问题描述
在对比原理图后,发现打印日志的串口是UART2(GPIO3_A2 & GPIO3_A3),但设备树中只开启了UART0(GPIO1_C2&GPIO1_C3)
/* 以下设备树内容来自多个设备树描述文件*/
dts
&uart0 {
pinctrl-names = "default";
pinctrl-0 = <&uart0_xfer &uart0_ctsn>;
status = "okay";
};
uart0: serial@ff560000 {
compatible = "rockchip,rv1126-uart", "snps,dw-apb-uart";
reg = <0xff560000 0x100>;
interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>;
reg-shift = <2>;
reg-io-width = <4>;
dmas = <&dmac 5>, <&dmac 4>;
clock-frequency = <24000000>;
clocks = <&cru SCLK_UART0>, <&cru PCLK_UART0>;
clock-names = "baudclk", "apb_pclk";
pinctrl-names = "default";
pinctrl-0 = <&uart0_xfer &uart0_ctsn &uart0_rtsn>;
status = "disabled";
};
uart0_xfer: uart0-xfer {
rockchip,pins =
/* uart0_rx */
<1 RK_PC2 1 &pcfg_pull_up>,
/* uart0_tx */
<1 RK_PC3 1 &pcfg_pull_up>;
};
uart2: serial@ff570000 {
compatible = "rockchip,rv1126-uart", "snps,dw-apb-uart";
reg = <0xff570000 0x100>;
interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
reg-shift = <2>;
reg-io-width = <4>;
dmas = <&dmac 9>, <&dmac 8>;
clock-frequency = <24000000>;
clocks = <&cru SCLK_UART2>, <&cru PCLK_UART2>;
clock-names = "baudclk", "apb_pclk";
pinctrl-names = "default";
pinctrl-0 = <&uart2m1_xfer>;
status = "disabled";
};
uart2m1_xfer: uart2m1-xfer {
rockchip,pins =
/* uart2_rx_m1 */
<3 RK_PA3 1 &pcfg_pull_up>,
/* uart2_tx_m1 */
<3 RK_PA2 1 &pcfg_pull_up>;
};
问题分析
无论是硬件原理图还是实际结果都表示启动日志是从UART2打印出来的,所以我们就要尽量往UART2去拓展。
由设备树可以得到内核启动参数 bootargs
:
dts
chosen {
bootargs = "earlycon=uart8250,mmio32,0xff570000 console=ttyFIQ0 root=PARTUUID=614e0000-0000 rootfstype=ext4 rootwait snd_aloop.index=7";
};
earlycon阶段(内核初始化早期)
首先可以看到earlycon=uart8250,mmio32,0xff570000
,earlycon
直接在设备树解析前初始化硬件,不依赖设备树中的status
属性。在内核初始化早期,直接向地址0xff570000
输出日志,对比之前提到的设备树配置,我们可以看到这个地址就是UART2串口。
标准console阶段(内核初始化后期)
在bootargs
中设置了console=ttyFIQ0
- 由于UART2在设备树中被标记为
disabled
,内核不会注册标准UART驱动(如ttyS2) - 后续日志会通过
ttyFIQ0
输出(通常是 Rockchip 的 FIQ 调试串口)
就像一个知道结果的解谜游戏,我们现在大可以猜测是不是ttyFIQ0
配置了UART2,接过了日志输出的任务并继续向UART2输出(通过FIQ驱动,绕过标准UART状态),接下来我们继续分析设备树:
dts
&fiq_debugger {
status = "okay";
};
fiq_debugger
是启用的,我们继续向上层设备树文件找,目前来到了rv1126.dtsi
dts
fiq_debugger: fiq-debugger {
compatible = "rockchip,fiq-debugger";
rockchip,serial-id = <2>; // 绑定到 UART2
rockchip,wake-irq = <0>;
rockchip,irq-mode-enable = <0>;
rockchip,baudrate = <1500000>; /* Only 115200 and 1500000 */
interrupts = <GIC_SPI 127 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
};
出现了!rockchip,serial-id = <2>
,我们可以看到fiq_debugger
节点绑定到了UART2,由此完成了内核启动早期与后期的日志输出的衔接。
总结
本篇文章是由一个status
为disable
但却被作为日志输出的UART2引出,核心是围绕着bootargs
中的earlycon
与console
参数展开。earlycon
直接通过UART2的地址,在设备树解析前输出早期日志;console
通过FIQ调试串口,复用了UART2的端口,实际上是使用了FIQ的驱动输出后续日志。完成了整个内核初始化及后续过程中的日志输出不同阶段的衔接。