[uboot] (番外篇)uboot串口&console&stdio设备工作流程

本文深入探讨了UBoot中的串口框架,包括串口驱动模型、调试和printf的输出流程,以及stdio模块。详细分析了serial core接口、default baudrate设置和初始化时机。此外,还介绍了stdio设备的结构体、存储位置和初始化过程,以及fputs的输出流程。最后,简述了s5pv210串口驱动的实现步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

[uboot] uboot流程系列
[project X] tiny210(s5pv210)上电启动流程(BL0-BL2)
[project X] tiny210(s5pv210)从存储设备加载代码到DDR
[uboot] (第一章)uboot流程——概述
[uboot] (第二章)uboot流程——uboot-spl编译流程
[uboot] (第三章)uboot流程——uboot-spl代码流程
[uboot] (第四章)uboot流程——uboot编译流程
[uboot] (第五章)uboot流程——uboot启动流程
[uboot] (番外篇)global_data介绍
[uboot] (番外篇)uboot relocation介绍
[uboot] (番外篇)uboot 驱动模型

建议先看《[uboot] (番外篇)uboot 驱动模型

=============================================================================================================

一、uboot serial框架

1、serial模块驱动模型

在《[uboot] (番外篇)uboot 驱动模型》中我们已经介绍uboot的驱动模型,uboot DM。
在uboot中,serial模块也使用了对应的驱动模型。
其框架图如下:
这里写图片描述
我们在《[uboot] (番外篇)uboot 驱动模型》已经说明过了,这里再简单解释一下:

  • serial core为serial模块向外提供接口,但是也是在serial-uclass中实现
  • serial uclass是serial设备的集合抽象,为serial设备提供统一的操作接口,serial uclass driver则是其对应的驱动
  • serial udevice是serial设备的具体抽象,代表了一个serial设备对象,serial driver则是其对应的驱动

2、serial DM实现

在《[uboot] (番外篇)uboot 驱动模型》中,我们已经知道了uclass和udevice由uboot动态生成,但是我们需要在dtsi中添加相应的设备信息,以及添加相应的uclass driver和udevice driver.
以tiny210为例,如下:

  • dts中的设备信息
/{
    aliases {
        console = "/serial@e2900000";
    };

    serial@e2900000 {
        compatible = "samsung,exynos4210-uart";
        reg = <0xe2900000 0x100>;
        interrupts = <0 51 0>;
        id = <0>;
    };
};

这里,有些人或许会有疑问,在relocate之前就需要打印串口数据,就需要使用到这个节点了,为什么不需要加上“u-boot,dm-pre-reloc”属性?
确实是可以加,但是不加也没事,因为console中已经指定了串口节点的路径,在relocate之前的串口初始化过程中,在设备链表上找不到对应串口设备的话,会强制绑定console指定的串口节点的设备。

  • uclass driver
    driver/serial/serial-uclass.c
UCLASS_DRIVER(serial) = {
    .id     = UCLASS_SERIAL,
    .name       = "serial",
    .flags      = DM_UC_FLAG_SEQ_ALIAS,
    .post_probe = serial_post_probe,
    .pre_remove = serial_pre_remove,
    .per_device_auto_alloc_size = sizeof(struct serial_dev_priv),
};
  • udevice driver
    driver/serial/serial_s5p.c
static const struct udevice_id s5p_serial_ids[] = {
    { .compatible = "samsung,exynos4210-uart" },  // 必须和dts匹配
    { }
};

// s5p serial driver 提供了如下操作集 
static const struct dm_serial_ops s5p_serial_ops = {
    .putc = s5p_serial_putc,
    .pending = s5p_serial_pending,
    .getc = s5p_serial_getc,
    .setbrg = s5p_serial_setbrg,
};

U_BOOT_DRIVER(serial_s5p) = {
    .name   = "serial_s5p",
    .id = UCLASS_SERIAL,
    .of_match = s5p_serial_ids,
    .ofdata_to_platdata = s5p_serial_ofdata_to_platdata,
    .platdata_auto_alloc_size = sizeof(struct s5p_serial_platdata),
    .probe = s5p_serial_probe,
    .ops    = &s5p_serial_ops,
    .flags = DM_FLAG_PRE_RELOC,
};

注意,serial uclass driver的id和serial driver的id是一致的,都是UCLASS_SERIAL。
具体也在《[uboot] (番外篇)uboot 驱动模型》分析过了,这里也不多说了。
关于tiny210的串口驱动的实现,在第四节中再学习。

3、serial core提供的接口

serial core会利用serial uclass找到对应的设备及其操作集,向上层提供接口。
如下:
driver/serial/serial-uclass.c

  • void serial_putc(char ch)
    往gd->cur_serial_dev指定的串口设备输出一个字符。
void serial_putc(char ch)
{
    if (gd->cur_serial_dev)
        _serial_putc(gd->cur_serial_dev, ch); // 将gd->cur_serial_dev指定的udevice作为参数传入
}

static void _serial_putc(struct udevice *dev, char ch)
{
    struct dm_serial_ops *ops = serial_get_ops(dev); // 获取对应udevice的操作集(driver->ops)
    int err;

    if (ch == '\n')
        _serial_putc(dev, '\r');

    do {
        err = ops->putc(dev, ch); // 调用udevice的操作集(driver->ops)中的putc函数,这里真正向硬件串口设备进行输出。
    } while (err == -EAGAIN);
}
  • void serial_puts(const char *str)
    往gd->cur_serial_dev指定的串口设备输出字符串。其方法与serial_putc类似,自己参考代码。

  • int serial_getc(void)
    从gd->cur_serial_dev指定的串口设备获取一个字符。其方法与serial_putc类似,自己参考代码。

  • int serial_tstc(void)
    判断gd->cur_serial_dev指定的串口设备是否有数据在等待。其方法与serial_putc类似,自己参考代码。

  • void serial_setbrg(void)
    设置gd->cur_serial_dev指定的串口设备的波特率。其方法与serial_putc类似,自己参考代码。

  • void serial_initialize(void) & int serial_init(void)
    串口初始化。这里重点说明

void serial_initialize(void)
{
    serial_init();
}
// 可以看出serial_initialize和serial_init是一样的。

int serial_init(void)
{
    serial_find_console_or_panic(); //调用serial_find_console_or_panic来查找console指定的设备
    gd->flags |= GD_FLG_SERIAL_READY;

    return 0;
}

static 
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值