ubootuboot 2020.04 DM驱动模式 -- Demo体验
Posted ZHONGCAI0901
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ubootuboot 2020.04 DM驱动模式 -- Demo体验相关的知识,希望对你有一定的参考价值。
文章目录
1. 前言
本篇文章是基于IMX6ULL平台uboot 2020.04源码分析DM驱动模式是如何使用的。IMX6ULL平台uboot源码下载可以参考这篇文章《【uboot】imx6ull uboot 2020.04源码下载和编译环境配置》。
2. uboot的驱动模型简介
uboot引入了驱动模型(driver model)简称为DM,这种驱动模型为驱动的定义和访问接口提供了统一的方法。提高了驱动之间的兼容性以及访问的标准型。
uboot官网有对DM的使用介绍,地址如下:
https://u-boot.readthedocs.io/en/latest/develop/driver-model/design.html
在uboot源码里面有一个DM驱动模型的Demo,我们可以使用它来了解分析DM驱动模型是如何工作的。下图是Demo DM驱动简单的框图,如下:
Demo DM驱动模型涉及到的文件如下:
成员 | 路径 | 描述 |
U_BOOT_CMD(do_demo) | ./cmd/demo.c | 定义了一个demo的命令,可以在uboot命令行进行操作。 |
UCLASS_DRIVER(demo) | ./drivers/demo/demo-uclass.c | 给UCLASS_DEMO类型的设备提供统一的接口。 |
U_BOOT_DRIVER(demo_imx6ull_drv) | ./drivers/demo/demo-imx6ull.c | 根据设备的定义操作对应的硬件。 |
uclass_id | ./include/dm/uclass-id.h | 定义UCLASS类的ID |
使能Demo DM驱动模型需要打开相关配置:
CONFIG_DM=y
CONFIG_CMD_DEMO=y
CONFIG_DM_DEMO=y
CONFIG_DM_DEMO_IMX6ULL=y
3. U_BOOT_CMD(do_demo)分析
通过U_BOOT_CMD定义了一个demo命令,该命令提供了4个功能:
- hello:打印设备的字符串
- light:操作硬件LED的开关
- status:查看设备的状态
- list:遍历UCLASS_DEMO绑定的所有设备
具体实现的代码如下:
// 定义命令参数对应的处理函数
static cmd_tbl_t demo_commands[] = {
U_BOOT_CMD_MKENT(list, 0, 1, do_demo_list, "", ""),
U_BOOT_CMD_MKENT(hello, 2, 1, do_demo_hello, "", ""),
U_BOOT_CMD_MKENT(light, 2, 1, do_demo_light, "", ""),
U_BOOT_CMD_MKENT(status, 1, 1, do_demo_status, "", ""),
};
static int do_demo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
// 通过命令行字符串获取对应的cmd的处理函数
demo_cmd = find_cmd_tbl(argv[1], demo_commands, ARRAY_SIZE(demo_commands));
devnum = simple_strtoul(argv[0], NULL, 10);
ret = uclass_get_device(UCLASS_DEMO, devnum, &demo_dev); // 通过设备号获取对应的设备实体struct udevice
ret = demo_cmd->cmd(demo_cmd, flag, argc, argv); //执行对应的处理函数
return cmd_process_error(demo_cmd, ret);
}
U_BOOT_CMD(
demo, 4, 1, do_demo,
"Driver model (dm) demo operations",
"list List available demo devices\\n"
"demo hello <num> [<char>] Say hello\\n"
"demo light [<num>] Set or get the lights\\n"
"demo status <num> Get demo device status\\n"
"demo list List available demo devices"
);
4. 执行命令demo list
执行命令demo list
命令时,会遍历所有的UCLASS_DEMO类型的设备。具体的代码如下:
int do_demo_list(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
struct udevice *dev;
int i, ret;
puts("Demo uclass entries:\\n");
for (i = 0, ret = uclass_first_device(UCLASS_DEMO, &dev);
dev;
ret = uclass_next_device(&dev)) {
printf("entry %d - instance %08x, ops %08x, platdata %08x\\n",
i++, (uint)map_to_sysmem(dev),
(uint)map_to_sysmem(dev->driver->ops),
(uint)map_to_sysmem(dev_get_platdata(dev)));
}
return cmd_process_error(cmdtp, ret);
}
运行结果如下:
通过以上的打印信息,我们可以了解到:
- UCLASS_DEMO有4个设备绑定,
- 4个不同instance地址对应4个不同的struct udevice设备实体地址。
- 4个设备对应不同的platdata(平台数据)。
- 4个设备使用同一个驱动,因为ops地址是同一地址。
这里的4个设备就是在device tree被定义的test_demo
:
/ {
test_demo@0 {
compatible = "fsl,imx6ull-demo";
colour = "red";
sides = <10>;
character = <82>;
led-gpios = <&gpio5 1 0>;
};
test_demo@1 {
compatible = "fsl,imx6ull-demo";
colour = "green";
sides = <11>;
character = <83>;
led-gpios = <&gpio5 2 0>;
};
test_demo@2 {
compatible = "fsl,imx6ull-demo";
colour = "blue";
sides = <12>;
character = <84>;
led-gpios = <&gpio5 3 0>;
};
test_demo@3 {
compatible = "fsl,imx6ull-demo";
colour = "yellow";
sides = <13>;
character = <85>;
led-gpios = <&gpio5 4 0>;
};
};
5. 执行命令demo hello
执行命令demo hello
时,会打印当前设备信息。具体代码如下:
static int imx6ull_hello(struct udevice *dev, int ch)
{
const struct dm_demo_pdata *pdata = dev_get_platdata(dev);
struct imx6ull_data *data = dev_get_priv(dev);
printf("Hello from %08x: %s %d\\n", (uint)map_to_sysmem(dev), pdata->colour,
pdata->sides);
data->num_chars = ch;
return 0;
}
执行结果如下:
demo hello
命令的参数0/1/2/3
代表设备编号,通过打印信息可以确定UCLASS_DEMO绑定的4个设备就是device tree里面的4个设备。
6. 执行命令demo light
执行命令demo light
时,会设置对应的GPIO的电压来控制LED开关。通过查看硬件LED连接到GPIO5_3,如下:
通过device tree定义的test_demo@2
配置,使其与GPIO5_3关联。然后,发送下面的命令开关LED:
=> demo light 2 0 // 设置GPIO5_3为低电平,打开LED
=> demo light 2 1 // 设置GPIO5_3为高电平,关闭LED
具体代码如下:
static int imx6ull_set_light(struct udevice *dev, int light)
{
struct imx6ull_data *priv = dev_get_priv(dev);
struct gpio_desc *desc;
int ret;
int i;
desc = priv->gpio_desc;
for (i = 0; i < priv->gpio_count; i++, desc++) {
uint mask = 1 << i;
ret = dm_gpio_set_value(desc, light & mask);
if (ret < 0)
return ret;
}
return 0;
}
运行效果如下:
7. U_BOOT_DRIVER和UCLASS_DRIVER分析
U_BOOT_DRIVER(demo_imx6ull_drv)
的定义解析如下:
UCLASS_DRIVER(demo)
的定义解析如下:
U_BOOT_DRIVER(demo_imx6ull_drv)
和UCLASS_DRIVER(demo)
都是被定义到固定的代码段,在DM模型初始化扫描时会进行遍历绑定。DM模型初始化流程:
在lists_bind_fdt()
函数中,主要设备树里面的compatible属性和driver里面属性匹配成功后,就将其绑定:
到此udevice、driver和uclass绑定完成,app可以通过uclass_driver提供的方法来操作硬件。
8. 参考资料
涉及的相关代码如下:
- imx6ull-14x14-evk-emmc-zc.dts是原始代码imx6ull-14x14-evk-emmc.dts基础上修改
- mx6ull_14x14_evk_emmc_zc_defconfig是原始代码mx6ull_14x14_evk_emmc_defconfig基础上修改
涉及到的代码下载路径如下:
https://download.csdn.net/download/ZHONGCAI0901/19405287
以上是关于ubootuboot 2020.04 DM驱动模式 -- Demo体验的主要内容,如果未能解决你的问题,请参考以下文章
ubootuboot 2020.04 Pinctrl子系统分析和使用
3DM速报:英伟达驱动更新 稳定RTX3080/90,育碧创立刺客信条“姐妹会”