You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在开机时启用所有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成功后立刻自动创建设备节点。确保内核配置开启:
    CONFIG_DEVTMPFS=y
    CONFIG_DEVTMPFS_MOUNT=y  // 让系统自动挂载/dev为devtmpfs
    
    开启后,UART驱动一初始化,/dev/ttymxc1就会自动出现,不需要额外操作。
  • 手动创建设备节点(备选):如果devtmpfs无法启用,可以在initramfs的启动脚本(比如rcS)里提前手动创建:
    mknod /dev/ttymxc1 c 207 1
    
    这里主设备号207是imx_serial对应的主设备号,次设备号1对应ttymxc1(ttymxc0是0,以此类推)。

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 10:03:34