[TOC]
驱动初始化及绑定与探测流程
- 存储在段中的驱动设备信息
- 初始化驱动模型结构,初始化根节点
- 从FDT中扫描设备并绑定到根节点
- 绑定后分配设备私有数据大小,与注册设备数据
driver_data
- 绑定设备到父设备与uclass上
- 绑定后探测根节点下的子设备和子设备的子设备
- 总结如下:
- 扫描FDT的设备并与driver的compatible匹配后,进行绑定与挂载到父设备与根节点上
- 使用malloc分配设备使用的私有数据,并设置设备的driver_data
- 绑定后执行设备识别
device_probe
函数,顺序根据注册的顺序执行,注册顺序为FDT节点的顺序;1
- 设备绑定分为重定向之前绑定和重定向之后绑定,
- 重定向之前需要绑定的设备FDT节点中需要具有
bootph-all
或bootph-some-ram
,bootph-pre-ram
,bootph-pre-sram
属性,且设备驱动信息flag中需要有DM_FLAG_PRE_RELOC
标志 - 否则都是重定向之后绑定
- 重定向之前需要绑定的设备FDT节点中需要具有
dm_init_and_scan
dm_init 初始化驱动模型结构,初始化根节点
dm_scan 设备扫描并绑定到根节点
dm_scan_plat 绑定段中的driver_info
1 | U_BOOT_DRVINFOS(lpc32xx_uarts) = { |
dm_extended_scan 从FDT中扫描设备并绑定到根节点
dm_scan_fdt 从FDT的每个节点获取compatible信息并与段中的driver结构体的of_match信息匹配,进而绑定设备
- 调用
lists_bind_fdt
,进行绑定 - 扫描FDT中的节点并根据节点属性; 注意节点若具有
satus
属性,则值为ok
,则才会绑定设备 - 匹配FDT中的
compatible
字符串和段中的of_match
信息1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22//dts 匹配完全"st,stm32h743-rcc"
static const struct udevice_id stm32_rcc_ids[] = {
{.compatible = "st,stm32f42xx-rcc", .data = (ulong)&stm32_rcc_clk_f42x },
{.compatible = "st,stm32f469-rcc", .data = (ulong)&stm32_rcc_clk_f469 },
{.compatible = "st,stm32f746-rcc", .data = (ulong)&stm32_rcc_clk_f7 },
{.compatible = "st,stm32h743-rcc", .data = (ulong)&stm32_rcc_clk_h7 },
{.compatible = "st,stm32mp1-rcc", .data = (ulong)&stm32_rcc_clk_mp1 },
{.compatible = "st,stm32mp1-rcc-secure", .data = (ulong)&stm32_rcc_clk_mp1 },
{.compatible = "st,stm32mp13-rcc", .data = (ulong)&stm32_rcc_clk_mp13 },
{ }
};
reset-clock-controller@58024400 {
compatible = "st,stm32h743-rcc\0st,stm32-rcc";
reg = <0x58024400 0x400>;
clocks = <0x18 0x19 0x1a>;
st,syscfg = <0x17>;
bootph-all;
phandle = <0x02>;
}; - 与段中的driver结构体的of_match信息匹配,进而绑定设备
device_bind_with_driver_data
绑定设备到父节点并传入驱动数据driver_data
,分配设备私有数据的空间大小,绑定fdt的node信息- 并且与uclass,与父设备进行绑定
- 将初始化的name替换为FDT中的name
dm_scan_fdt_ofnode_path 扫描chosen
、clocks
、firmware
、reserved-memory
节点并绑定设备到根节点
dm_scan_other boot/bootstd-uclass.c ,用于bootmethod
dm_autoprobe 绑定后探测根节点下的子设备和子设备的子设备
device flag 说明
1 | // probe 后设置,表示设备已经激活 |
驱动卸载流程
bootm时跳转前执行
- arch/arm/lib/bootm.c -> announce_and_cleanup() -> dm_remove_devices_active
dm_remove_devices_active 移除所有激活的设备
device_remove
initf_dm
1 | static int initf_dm(void) |
root.c
root_driver & root
1 | /* This is the root driver - all drivers are children of this */ |
dm_init_and_scan
1 | /** |
dm_init 初始化驱动模型结构
1 | /** |
dm_scan 设备扫描
1 | static int dm_scan(bool pre_reloc_only) |
dm_scan_plat 扫描段中的设备,绑定driver_info
1 | int dm_scan_plat(bool pre_reloc_only) |
dm_autoprobe 绑定后探测根节点下的子设备和子设备的子设备
dm_probe_devices 绑定后探测节点下的子设备和子设备的子设备
1 | static int dm_probe_devices(struct udevice *dev) |
dm_extended_scan 从FDT中扫描设备并绑定到根节点
1 | int dm_extended_scan(bool pre_reloc_only) |
dm_scan_fdt 扫描FDT中的设备并绑定到根节点
dm_scan_fdt_node 扫描FDT中的节点并根据节点compatible信息匹配,绑定设备
- 注意节点若具有
satus
属性,则值为ok
,则才会绑定设备
1 | static int dm_scan_fdt_node(struct udevice *parent, ofnode parent_node, |
## dm_remove_devices_active 移除所有激活的设备
1 | void dm_remove_devices_active(void) |
device.c
udevice 驱动程序实例
- 函数包含有关设备的信息,该设备是绑定到特定端口或外围设备(本质上是一个驱动程序实例)
- 包含节点,序列号
driver 功能或外围设备的驱动程序
- 此字段包含设置新设备和删除新设备的方法。设备需要信息来设置自身
- 驱动程序都属于一个 uclass,代表相同类型。
device_bind_by_name 通过名字绑定设备
1 | int device_bind_by_name(struct udevice *parent, bool pre_reloc_only, |
device_bind_common 绑定设备
1 | static int device_bind_common(struct udevice *parent, const struct driver *drv, |
device_probe 探测设备
1 | int device_probe(struct udevice *dev) |
device_of_to_plat 识别设备并分配与设置平台内部的数据
1 | int device_of_to_plat(struct udevice *dev) |
device_alloc_priv 分配设备私有数据
1 | static int device_alloc_priv(struct udevice *dev) |
device_bind_with_driver_data 绑定设备到父节点并传入驱动数据,与fdt的node信息
1 | int device_bind_with_driver_data(struct udevice *parent, |
uclass.c
uclass_get
uclass_find 根据key查找uclass
1 | struct uclass *uclass_find(enum uclass_id key) |
uclass_find_device_by_ofnode 根据ofnode查找设备
1 | int uclass_find_device_by_ofnode(enum uclass_id id, ofnode node, |
dev_set_uclass_priv 设置设备私有数据
- 在device_alloc_priv时调用
- device_probe -> device_of_to_plat -> device_alloc_priv -> dev_set_uclass_priv -> uclass_priv_
dev_get_uclass_priv 获取设备私有数据
- dev_get_uclass_priv -> uclass_priv_
dev_set_ofnode 设置设备的ofnode
- device_bind_common-> dev_set_ofnode;//dev_set_ofnode(dev, node);
uclass_get_device_by_phandle 通过 phandle 获取 uclass 设备并执行探测
- 这将在 uclass 中搜索具有给定 phandle 的设备。探测设备以将其激活以供使用。
uclass_get_device_tail device_probe 该设备
uclass_find_device_by_phandle 通过 phandle 查找 uclass 设备
- 在当前FDT节点中根据name返回器phandle,并通过phandle id查找设备
1 | int uclass_find_device_by_phandle(enum uclass_id id, struct udevice *parent, |
uclass_find_device_by_phandle_id 通过 phandle id 查找 uclass 设备
1 | static int uclass_find_device_by_phandle_id(enum uclass_id id, |
uclass_get_device_by_seq 通过seq查找设备并执行探测
1 | int uclass_get_device_by_seq(enum uclass_id id, int seq, struct udevice **devp) |
uclass_find_device_by_seq 通过seq查找设备
- 遍历uclass链表,根据seq找到对应的设备
1 | int uclass_find_device_by_seq(enum uclass_id id, int seq, struct udevice **devp) |
lists.c
lists_bind_drivers 绑定段中的driver_info
- 由于设备之间可能存在依赖关系,因此可能需要多次绑定设备
- 必须先绑定父设备,然后再绑定子设备
- 所以尝试绑定设备10次,如果绑定失败,返回-EAGAIN
1 | int lists_bind_drivers(struct udevice *parent, bool pre_reloc_only) |
bind_drivers_pass 遍历段中的driver_info
1 | static int bind_drivers_pass(struct udevice *parent, bool pre_reloc_only) |
lists_bind_fdt 从FDT的每个节点获取compatible信息并与段中的driver结构体的of_match信息匹配,进而绑定设备
1 | int lists_bind_fdt(struct udevice *parent, ofnode node, struct udevice **devp, |
driver_check_compatible 检查设备是否与驱动程序兼容,每个字符串需要完全匹配
- 驱动有一个of_match数组,用于检查设备是否与驱动兼容
- 通过比较设备的compatible字符串,判断设备是否与驱动兼容
- 可以多个compatible字符串,只要有一个匹配即可
- of_idp返回匹配的驱动id和驱动数据
- 返回0表示匹配
1 | static int driver_check_compatible(const struct udevice_id *of_match, |
ofnode.c
- 配置了OF_LIVE,表示设备树是动态的,可以在运行时修改
- 否则直接从FDT中读取设备树
ofnode_first_subnode 获取第一个1子节点
- 用于遍历设备树
ofnode_parse_phandle_with_args 解析node的list索引到的phandle的args返回
1 | struct ofnode_phandle_args { |
ofnode_pre_reloc 判断节点是否需要在重定位之前绑定
- 具有
bootph-all
或bootph-pre-sram
1 | bool ofnode_pre_reloc(ofnode node) |
uclass_get_device_by_ofnode 根据ofnode获取uclass设备,并执行探测
fdtaddr.c
dev_read_addr
devfdt_get_addr
devfdt_get_addr_index
devfdt_get_addr_index_parent
fdtdec_get_addr_size_auto_parent FDT中获取节点获取reg的地址和大小
- 通过解析提供的父节点的
#address-cells
和#size-cells
属性,自动确定用于表示地址和大小的单元格数。 - 解析
reg
确定reg的地址和大小
device-remove.c
device_remove 移除设备
1 | int device_remove(struct udevice *dev, uint flags) |
device_chld_remove 移除设备下的子设备
1 | int device_chld_remove(struct udevice *dev, struct driver *drv, |
flags_remove 判断设备属性是否允许移除
- 具有
DM_REMOVE_NORMAL
标志的正常设备,允许进行卸载 - 具有活动 DMA 的设备(
DM_REMOVE_ACTIVE_DMA = DM_FLAG_ACTIVE_DMA
) 和跳转APP所需要的活动设备(DM_REMOVE_OS_PREPARE = DM_FLAG_OS_PREPARE
),不允许卸载;返回-EKEYREJECTED
- 具有标记为 Vital 的设备(
DM_REMOVE_NON_VITAL = DM_FLAG_VITAL,
),不允许卸载;返回-EPROBE_DEFER
1 | static int flags_remove(uint flags, uint drv_flags) |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 wdfk-prog的个人博客!
评论