OK6410A 开发板 (三) 19 u-boot-2021.01 boot 解析 U-boot 镜像运行部分 driver model

发布者:捡漏来了最新更新时间:2022-09-21 来源: csdn关键字:OK6410A  开发板  u-boo  镜像  driver  model 手机看文章 扫描二维码
随时随地手机看文章

总体简述

在 u-boot 中, DM 是 uclass device driver 以及三者相关函数的总体


uclass device driver 相关结构体

driver 在定义的时候就根据 其 自身的id成员被 分为了 XXX uclass

device 在定义的时候就根据 其 自身的name成员 暗含了 与 driver 绑定的条件


函数

初始化

在(initf_dm/initr_dm)的时候,为每一个设备(设备树中的节点/U_BOOT_DEVICE声明的结构体)做以下动作

1. 初始化了 device 结构体

2. device_bind_common 实现driver 、uclass 与该 device 绑定(即三者绑定)

3. 调用了 driver 中的 bind 函数 为该设备类做初始化

在 例如 serial_init/mmc_initialize的时候

1. 调用 driver 中的 probe 函数 为设备做初始化

使用设备

1. 通过 uclass_get_device_xxx 获取 device 句柄

2. 通过 uclass 提供的函数 yyy 来控制设备


对driver mode 来一次感官认识

文档查阅

doc/driver-model/design.rst


u-boot 将 驱动和 设备 做了分离 ,分成了三部分(这里没涉及 uclass 的core 部分) 

Uclass Driver Device


假设 我用 cmdline 去访问 ,那么涉及的代码就是 4部分(这里没涉及 uclass 的core 部分) 

cmd

cmd/demo.c

Uclass

drivers/demo/demo_uclass.c

include/dm-demo.h

Driver

demo-shape.c  demo-simple.c(一个文件对应一个驱动)

Device

demo-pdata.c(虽然是一个文件,但是这里有5个设备)


运行感知

make sandbox_defconfig

make

./u-boot -d u-boot.dtb

=> demo list  // 查看 已经注册的 且 属于 UCLASS_DEMO 类的 设备有多少个 (5个)

Demo uclass entries:

entry 0 - instance 05292d40, ops 08000001, platdata 08000000

entry 1 - instance 05292e00, ops 08000002, platdata 08000000

entry 2 - instance 05292ec0, ops 08000001, platdata 08000003

entry 3 - instance 05292f80, ops 08000002, platdata 08000004

entry 4 - instance 05293040, ops 08000001, platdata 08000004


=> demo hello 0

r@@@@@@@

e@@@@@@@

d@@@@@@@

r@@@@@@@

e@@@@@@@

d@@@@@@@

=> demo hello 2

g       

r@      

e@@     

e@@@    

n@@@@   

g@@@@@  

=> demo hello 4

  y@@@  

 e@@@@@ 

l@@@@@@@

l@@@@@@@

 o@@@@@ 

  w@@@  

// 看起来 设备 0 2 4 用的是同一个驱动 , 实际证明也是如此 , 用的是 demo_shape_drv


=> demo hello 1

Hello from 05292e00: red 4

=> demo hello 3

Hello from 05292f80: yellow 6

// 看起来 设备 1 3 用的是同一个驱动 , 实际证明也是如此 , 用的是 demo_simple_drv


代码流程分析

// 如果是 demo hello 1

cmd(cmd/demo.c)

do_demo

uclass_get_device(UCLASS_DEMO, devnum, &demo_dev);

demo_hello(demo_dev, ch);

uclass(drivers/demo/demo_uclass.c)

demo_hello

struct demo_ops *ops = device_get_ops(dev);

ops->hello(dev, ch);

Driver(demo-simple.c)

simple_hello

const struct dm_demo_pdata *pdata = dev_get_platdata(dev);

printf("Hello from %08x: %s %dn", (uint)map_to_sysmem(dev), pdata->colour, pdata->sides);

Device(demo-pdata.c)

static const struct dm_demo_pdata red_square = {                                 

    .colour = "red",                                                             

    .sides = 4.                                                                  

};

U_BOOT_DEVICE(demo1) = {                                                         

    .name = "demo_simple_drv",                                                      

    .platdata = &red_square,                                                        

};


代码功能分析

uclass(drivers/demo/demo_uclass.c)

通过 UCLASS_DRIVER(demo) 注册 UCLASS_DEMO 类

Driver(demo-simple.c)

通过 U_BOOT_DRIVER(demo_simple_drv) 注册 驱动, 并绑定 到 UCLASS_DEMO

Device(demo-pdata.c)

通过 U_BOOT_DEVICE(demo0) 注册设备,并绑定到 特定的driver

消费者(例如cmd)

通过 uclass_get_device(UCLASS_DEMO, devnum, &demo_dev); 获取到设备

通过 设备类 提供的 操作函数  demo_hello(demo_dev, ch); 来控制设备


u-boot 引入 driver model以前

消费者想要操作一个设备,需要知道以下信息

A. 设备的物理地址是什么

B. 设备的驱动是什么,以及提供了什么API

u-boot 引入 driver model之后

消费者想要操作一个设备,不需要知道A和B,只需要知道下面的就行了

1. 该设备属于哪个类

2. 该类的操作函数


以上都是从消费者角度考虑的,但是没考虑 driver model 的核心实现(即 uclass的核心实现)


而我认为 initf_dm 和 initr_dm 就是 核心实现的初始化


driver mode 的初始化

看了一些博客

先来个总体感觉

1. initf_dm 和 initr_dm 的过程是类似的,下面以initf_dm 为例讲述

2. initf_dm 目的在于 初始化一个 树型 数据结构 ,里面存储的是 Device,并初始化 gd->dm_root

3. Device 是 从 U_BOOT_DEVICE 和 fdt 中找的

4. 在 对 Device 进行 树型 排列的过程中,还要 针对  每一个 Device 做一些 recipe

5. recipe 包括 为 Device 找到 Driver , 为 Device 找到 UCLASS

6. 因为 Device 是 树型结构,操作一个Device 的时候还可能对 parents 做一些动作


u-boot 运行过程中

board_init_f 

initf_dm

bootstage_start(BOOTSTAGE_ID_ACCUM_DM_F, "dm_f");

ret = dm_init_and_scan(1);

// 主要是负责 root driver和root device 的bind 和 probe

// core/root.c 中的 U_BOOT_DRIVER(root_driver)

// core/root.c 中的 UCLASS_DRIVER(root)

// drivers/core/device.c 中的 device_bind_common 动态创建了 U_BOOT_DEVICE(root)

dm_init

INIT_LIST_HEAD(&DM_UCLASS_ROOT_NON_CONST);

device_bind_by_name(NULL, false, &root_info, &DM_ROOT_NON_CONST);

drv = lists_driver_lookup_name(info->name);

device_bind_common(parent, drv, info->name, (void *)info->platdata, 0, ofnode_null(), platdata_size, devp);

uclass_bind_device

没有 drv->bind


(((gd_t *)gd)->dm_root)->node = offset_to_ofnode(0);

device_probe((((gd_t *)gd)->dm_root))

device_ofdata_to_platdata

没有dev->parent

uclass_pre_probe_device

clk_set_defaults(dev, 0);

没有drv->probe

uclass_post_probe_device

// 主要是负责 U_BOOT_DEVICE 声明的 device 和 对应的 driver  bind/probe

dm_scan_platdata(1)

lists_bind_drivers((((gd_t *)gd)->dm_root), pre_reloc_only);

bind_drivers_pass

const int n_ents = ll_entry_count(struct driver_info, driver_info) = 0;

return 0

// 主要是负责 fdt 声明的 device 和 对应的 driver  bind/probe

// 设备树预处理文件 : output/arch/arm/dts/.s3c64xx-ok6410a.dtb.dts.tmp

dm_extended_scan_fdt(gd->fdt_blob,1);

dm_scan_fdt(blob, pre_reloc_only);

dm_scan_fdt_node(gd->dm_root, blob, 0, pre_reloc_only);

查看节点有没有enable ,没有的话(sdhci@7C300000,sdhci@7C400000)什么都不做,返回.有的话继续


for_each_node

lists_bind_fdt

// 没有 compatible string 的 node 

什么都不做 (chosen,aliases,memory,config,)

// 有 compatible 且没有子节点

对每个节点(interrupt-controller@10490000,clock@1800000,serial0@7F005000,sdhci@7C200000)

driver_check_compatible

device_bind_with_driver_data

device_bind_common

uclass_bind_device

有 drv->bind则执行bind,没 drv->bind则不执行

// 有 compatible 且有 子节点

对每个节点(包括该节点pinctrl@7f008000和所有子节点gpa-gpq)

device_bind_with_driver_data

device_bind_common

uclass_bind_device

有 drv->bind

dm_scan_other(1);

bootstage_accum(BOOTSTAGE_ID_ACCUM_DM_F);

board_init_r

initr_dm

gd->dm_root_f = gd->dm_root;

gd->dm_root = ((void *)0);

bootstage_start(BOOTSTAGE_ID_ACCUM_DM_R, "dm_r");

ret = dm_init_and_scan(0);

dm_init(0)

dm_scan_platdata(0)

dm_extended_scan_fdt(gd->fdt_blob,0);

dm_scan_other(0);

bootstage_accum(BOOTSTAGE_ID_ACCUM_DM_R);

initr_dm_devices

// null


initf_dm initr_dm两者的区别

初始化流程

initf_dm

dm_init_and_scan(true) // pre_reloc_only = 1

// device_bind_by_name

// if (pre_reloc_only && !(drv->flags & DM_FLAG_PRE_RELOC)) return; // return表示不做下面的初始化动作

// 也就是说 该设备 需要在 重定位之前初始化 ,则 drv->flags & DM_FLAG_PRE_RELOC != 0

// 这里初始化的设备就是 drv->flags & DM_FLAG_PRE_RELOC != 0 的设备

// 哪些驱动 是 DM_FLAG_PRE_RELOC 

// pinctrl@7f008000以及子节点

// clock@1800000

// serial0@7F005000

initr_dm

dm_init_and_scan(false) // pre_reloc_only = 0

消费者(其实这个消费者也是DM架构的一部分,只不过是核心部分的较外层部分)

initf_dm

initf_dm 之后 initr_dm 之前的消费者(serial_init)

调用device_probe次数:2


serial_init // 主要作用是调用drv->probe 完成硬件的初始化

serial_find_console_or_panic

serial_check_stdout

uclass_get_device_by_of_offset

uclass_get_device_tail

device_probe(dev);

if (dev->parent) device_probe(dev->parent);

if (drv->probe) drv->probe(dev);


initr_dm 

initr_dm 之后的消费者

调用device_probe次数:(18+104)


driver mode 的初始化和 Uclass Driver Device

Uclass Driver Device 的展开

uclass UCLASS_DRIVER(gpio)

struct uclass_driver _u_boot_list_2_uclass_2_gpio __attribute__((__aligned__(4))) __attribute__((unused, section(".u_boot_list_2_""uclass""_2_""gpio"))) = {

 .id = UCLASS_GPIO,

 .name = "gpio",

 .flags = (1 << 0),

 .post_probe = gpio_post_probe,

 .post_bind = gpio_post_bind,

 .pre_remove = gpio_pre_remove,

 .per_device_auto_alloc_size = sizeof(struct gpio_dev_priv),

};


Driver U_BOOT_DRIVER(s3c64xx_gpio)

struct driver _u_boot_list_2_driver_2_s3c64xx_gpio __attribute__((__aligned__(4))) __attribute__((unused, section(".u_boot_list_2_""driver""_2_""s3c64xx_gpio"))) = {

 .name = "s3c64xx_gpio",

 .id = UCLASS_GPIO,

 .of_match = s3c64xx_gpio_ids,

 .bind = s3c64xx_gpio_bind,

 .probe = s3c64xx_gpio_probe,


 .ops = &gpio_s3c_ops,

 .flags = (1 << 2),

};


Device U_BOOT_DEVICE(demo0)

设备树


初始化中对三个结构体群组的遍历

uclass

遍历:

struct uclass_driver *uclass = ll_entry_start(struct uclass_driver, uclass);

const int n_ents = ll_entry_count(struct uclass_driver, uclass);

struct uclass_driver *entry;

for (entry = uclass; entry != uclass + n_ents; entry++)

遍历的应用:

lists_uclass_lookup

Driver 

遍历:

struct driver *drv = ll_entry_start(struct driver, driver);

const int n_ents = ll_entry_count(struct driver, driver);

struct driver *entry;

for (entry = drv; entry != drv + n_ents; entry++)

遍历的应用:

lists_driver_lookup_name

Device 

遍历: for (offset = fdt_first_subnode(blob, offset); offset > 0; offset = fdt_next_subnode(blob, offset))

遍历2:

gpio_bank_t *base = (gpio_bank_t *)devfdt_get_addr(parent);

[1] [2]
关键字:OK6410A  开发板  u-boo  镜像  driver  model 引用地址:OK6410A 开发板 (三) 19 u-boot-2021.01 boot 解析 U-boot 镜像运行部分 driver model

上一篇:OK6410A 开发板 (三) 20 u-boot-2021.01 boot 解析 U-boot 镜像运行部分 system clock
下一篇:OK6410A 开发板 (三) 18 u-boot-2021.01 boot 解析 U-boot 镜像运行部分 env

推荐阅读最新更新时间:2024-11-11 20:23

紫光展锐虎贲T710开发板问市,内置NPU,拥有超强AI算力
10月10日,紫光展锐发布虎贲T710开发板。产品是八核高性能人工智能主板,搭载紫光展锐AI处理器虎贲T710,内置神经网络处理器NPU,具有强悍的AI算力性能,高达3.2TOPS。 据介绍,除了在智慧医疗这个典型的场景,虎贲T710开发板还可运用在多种场景,并满足其计算性能需求,包括智能零售、智能医疗、智慧教育、智慧农业、智能辅助驾驶等领域。 紫光展锐虎贲搭载T710八核处理器,处理器采用四大核Cortex-A75+四小核Cortex-A55构架,主频2.0GHz。系统集成AI神经网络处理器NPU,支持INT8/INT16/FP16多种神经网络量化方式,综合算力达4.2TOPS,具有超过2.5TOPS/W的能效比。
[嵌入式]
紫光展锐虎贲T710<font color='red'>开发板</font>问市,内置NPU,拥有超强AI算力
Linux驱动之按键驱动编写(查询方式)
1、查看原理图,确定需要控制的IO端口 打开原理图,确定需要控制的IO端口为GPF0、GPF2、GPG3、GPG11 2、查看芯片手册,确定IO端口的寄存器地址,可以看到因为用了两组GPIO端口,所以它的基地址分别为0x56000050、0x56000060 3、编写驱动代码,编写驱动代码的步骤如下: 1)、编写出口、入口函数。代码如下,具体说明参考Linux驱动之LED驱动编写 static int second_drv_init(void) { Secondmajor = register_chrdev(0, buttons , &second_drv_ops);//注册驱动程序 if(Second
[单片机]
Linux<font color='red'>驱动</font>之按键<font color='red'>驱动</font>编写(查询方式)
LED灯驱动电源的几条实战经验
  近年来LED灯封装技术和散热技术的不断发展,LED灯的稳定性已经达到比较好的水平,发生光衰和色漂移的主要是些山寨厂家的产品,主要原因是散热设计的不合理。相对来说LED灯驱动电源的问题要严重的多,是导致死灯或者闪烁的主要原因,也就是说,LED灯驱动电源已经成为LED灯质量的短板,根据木桶理论,LED灯驱动电源的寿命就是LED灯的寿命。   常规照明路灯是灯头与电源分开的,通常发生故障的是灯头--高压钠灯,高压钠灯国家标准规定质保期一年,路灯管理单位都会存库一定数量的钠灯,高压钠灯具有成熟的国家标准,其主要配件尺寸、功率等主要参数都是统一的,具备互换性。   而当前LED灯的故障主要在电源,所以主要就是要解决电源问题。由于目前le
[电源管理]
当工业物联网成为半导体产业的最大驱动力将赚大钱
IHS最近推出了2016年应用市场预测报告,预测了未来五年内半导体领域具有最高增长率的细分市场,可以看到,曾经一度黯淡的市场再次焕发生机,即下图的右上角:工业市场,其增长潜力预计会超过目前风头正劲的汽车市场。   这对新的芯片设计意味着什么呢?嵌入式类应用之前已经走过了若干个发展周期,曾经引发广泛关注的移动和消费电子市场一度非常火热,然后慢慢从白热化阶段进入平稳发展阶段,同时,像航空、国防、汽车、医疗和工业等被认为枯燥乏味的板块也一直不温不火。不过这次,情况有所不同,人们每说起一次物联网,总会有新的不同认识。     实在讲,物联网并不是一个真正的应用领域,它更多地是指将大规模的设备、用户和数据连接在一起的一系
[嵌入式]
iTOP-4412开发板-使用PartitionManager分区之后tf卡无法识别
本文档介绍的iTOP-4412开发板丨iTOP-4418开发板丨IMX6开发板丨使用PartitionManager分区之后tf卡无法识别 tf卡使用 PartitionManager 软件分区后,在Windows上可能出现无法识别的情况。 tf卡分区之后,Windows下无法识别,并不影响系统的烧写,用户可以按照手册上的方 法在 Ubuntu 上正常使用,按照正常的烧写流程即可。 说到定位和导航,大家容易有几个误区,请务必理解以下知识点。 下面介绍一下,在烧写完毕之后,如何使 tf 卡在 Windows 上可以识别。 pc 上打开磁盘管理,计算机→管理→磁盘管理,如下图所示。 如上图所示,上方两个是不显示的盘
[单片机]
iTOP-4412<font color='red'>开发板</font>-使用PartitionManager分区之后tf卡无法识别
“秒懂”不同LED驱动电源在不同应用中的区别
LED具有很强的应用灵活性,在不懂的驱动电源中当然也会有所区别。如果处理不当,将会严重影响LED的使用寿命和照明情况,下面给大家介绍LED驱动电源在不同应用中的区别,看看就知道!   1 分布式恒流驱动原理介绍   在以往的白炽灯和节能灯市场,大公司所形成的规格有限的主流灯具型号,LED很难再继续遵守。LED有它的应用灵活性,在日后的设计中会带来较多的电源规格。   分布式恒流的原理在于,在各并联支路点均设立独立恒流源,以管理、维持、控制支路与支路、支路与整体线路的稳定。分布式恒流电路在使用上可视为一个完整的线路结构,而实际应用是分布在线路各节点的,是一个可以通过恒流控制并能相互通讯的电路结构。   在当前,LED产品宣称与实际
[电源管理]
Anritsu与dSPACE合作开发支持5G的虚拟测试驱动
Anritsu和dSPACE将共同展示集成在硬件在环(HIL)系统中的5G网络仿真器,以开发汽车连接应用程序。 在2020年世界移动通信大会期间,Anritsu展位将展示虚拟测试驱动器,测试车辆到基础设施(V2I)应用,从而进行流量优化和传感器数据共享。方案将通过智能基础设施以及真实的5G通信来模拟车辆和环境。 5G和边缘云的结合保证了高数据吞吐量和低延迟,它允许与车辆和基础设施共享原始传感器数据。这可以进一步实现协作感知,基于共享AI的人工智能或实时流量优化。如果没有合适的5G测试平台基础架构,相关应用程序的开发将面临挑战。 展示将Anritsu无线电通信测试站MT8000A,5G射频,功能和协议测试解决方案与dSACE Sca
[汽车电子]
在GD32F310G-START开发板上读取三轴加速度计
我拿到的开发板实际板载的 MCU 是 GD32F310G8,QFN28pin 封装,基于 ARM CORTEX M4 内核,主频 72MHz, 芯片内置 64KB flash,8KB SRAM, 两路 I2C 外设。 整体概述 首先感谢极术社区给我试用GD32开发板的机会,让我体验一下近几年国产MCU开发体验。该芯片是基于arm cortex-M4内核,主频72Mhz,flash 64k,ram 8k,以及丰富的外设。 本次试用是一个读取三轴加速度计的实验,主要使用的是硬件iic。 硬件连接 传感器介绍 SC7A20 是一款高精度 12bit 数字三轴加速度传感器芯片,内置功能 更丰富,功耗更低,体积更小,测量更精确。 芯片通
[单片机]
在GD32F310G-START<font color='red'>开发板</font>上读取三轴加速度计
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
随便看看

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved