如何在开机时启用所有UART端口?开机阶段RTC驱动打开串口设备失败
解决开机阶段启用UART端口并访问/dev/ttymxc1的问题
看起来你碰到的核心问题是开机早期阶段/dev/ttymxc1设备节点还没创建完成,导致你的RTC驱动调用filp_open()返回ENOENT(-2)。咱一步步来拆解和解决这个问题:
1. 确保UART2在开机早期被内核初始化
首先得确认UART2(对应ttymxc1)的硬件和驱动在开机阶段就已经就绪:
- 检查设备树配置:打开你的DTS/DTSI文件,找到UART2的节点,确保它没有被禁用:
&uart2 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_uart2>; status = "okay"; // 必须是"okay"而不是"disabled" }; - 确认UART驱动编译进内核:imx_serial驱动必须是内置的(不是模块),因为开机早期内核模块加载机制还未就绪。检查内核配置:
CONFIG_SERIAL_IMX=y // 不能是=m
2. 让/dev/ttymxc1在开机早期自动创建
/dev节点通常由devtmpfs或udev/mdev管理,要让它在开机早期出现:
- 启用devtmpfs(推荐):现代Linux内核默认支持devtmpfs,它会在驱动probe成功后立刻自动创建设备节点。确保内核配置开启:
开启后,UART驱动一初始化,/dev/ttymxc1就会自动出现,不需要额外操作。CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y // 让系统自动挂载/dev为devtmpfs - 手动创建设备节点(备选):如果devtmpfs无法启用,可以在initramfs的启动脚本(比如rcS)里提前手动创建:
这里主设备号207是imx_serial对应的主设备号,次设备号1对应ttymxc1(ttymxc0是0,以此类推)。mknod /dev/ttymxc1 c 207 1
3. 调整RTC驱动的加载时机
你的RTC驱动可能比UART驱动更早启动,导致UART设备还没准备好:
- 调整驱动加载顺序:如果RTC驱动是模块,把它的加载放在UART驱动之后(比如在rc.local里执行
insmod your_rtc_driver.ko)。如果必须在内核启动阶段运行,那可以在设备树里给RTC节点添加依赖:your_rtc_node { // ... 其他配置 depends-on = <&uart2>; // 让RTC驱动在UART2初始化后再probe }; - 使用内核初始化优先级:如果是内置驱动,可以用
late_initcall()代替module_init(),让RTC驱动在大部分设备初始化后再启动。
4. 更可靠的替代方案:直接操作UART寄存器
既然你已经知道UART2的MMIO地址是0x21e8000,完全可以在RTC驱动里直接读写硬件寄存器,绕过/dev节点。这样就不需要依赖用户空间的设备节点,适合开机早期的场景:
- 参考imx_serial驱动的代码逻辑,初始化UART的波特率、数据位、停止位等参数;
- 用
ioremap()映射MMIO地址,然后直接读写寄存器和RTC通信。
这种方式更底层,也彻底避免了设备节点创建时机的问题。
调试小技巧
- 查看内核启动日志(
dmesg),对比UART驱动初始化日志(21e8000.serial: ttymxc1 at MMIO 0x21e8000...)和你的RTC驱动报错的时机,确认是不是UART驱动启动太晚; - 在initramfs的启动脚本里添加
ls /dev命令,查看开机阶段/dev目录下的设备节点情况。
内容的提问来源于stack exchange,提问作者schustercp
相关产品推荐
相关产品推荐

