文章目录
一、综述
本文通过如何通过编写特定板子的spi master驱动从而识别到spi norflash设备,完成norflash设备的读写。
二、UCLASS架构解析
2.1 uclass
uclass可以理解为一些具有相同属性的udevice对外操作的接口,uclass的驱动是uclass_driver,主要为上层提供接口。
udevice的是指具体设备的抽象,对应驱动是driver,driver主要负责和硬件通信,为uclass提供实际的操作集。
udevice找到对应的uclass的方式主要是通过:udevice对应的driver的id和uclass对应的uclass_driver的id是否匹配。
udevice会和uclass绑定。driver会和udevice绑定。uclass_driver会和uclass绑定。

uclass和udevice都是动态生成的。在解析fdt中的设备的时候,会动态生成udevice。
然后找到udevice对应的driver,通过driver中的uclass id得到uclass_driver id。从uclass链表中查找对应的uclass是否已经生成,没有生成的话则动态生成uclass。
2.2 udevice
连接到对应uclass中
也就是会连接到uclass->dev_head中
连接到父设备的子设备链表中
也就是会连接到udevice->child_head中,并且最终的根设备是gd->dm_root这个根设备。
struct uclass {
void *priv; //uclass的私有数据
struct uclass_driver *uc_drv; //uclass类的操作函数集合
struct list_head dev_head; //该uclass的所有设备
struct list_head sibling_node; //下一个uclass的节点
};
2.3 uclass driver
主要函数:
struct uclass_driver {
const char *name; // 该uclass_driver的命令
enum uclass_id id; // 对应的uclass id
/* 以下函数指针主要是调用时机的区别 */
int (*post_bind)(struct udevice *dev); // 在udevice被绑定到该uclass之后调用
int (*pre_unbind)(struct udevice *dev); // 在udevice被解绑出该uclass之前调用
int (*pre_probe)(struct udevice *dev); // 在该uclass的一个udevice进行probe之前调用
int (*post_probe)(struct udevice *dev); // 在该uclass的一个udevice进行probe之后调用
int (*pre_remove)(struct udevice *dev);// 在该uclass的一个udevice进行remove之前调用
int (*child_post_bind)(struct udevice *dev); // 在该uclass的一个udevice的一个子设备被绑定到该udevice之后调用
int (*child_pre_probe)(struct udevice *dev); // 在该uclass的一个udevice的一个子设备进行probe之前调用
int (*init)(struct uclass *class); // 安装该uclass的时候调用
int (*destroy)(struct uclass *class); // 销毁该uclass的时候调用
int priv_auto_alloc_size; // 需要为对应的uclass分配多少私有数据
int per_device_auto_alloc_size; //
int per_device_platdata_auto_alloc_size; //
int per_child_auto_alloc_size; //
int per_child_platdata_auto_alloc_size; //
const void *ops; //操作集合
uint32_t flags; // 标识为
};
spi-uclass驱动:
UCLASS_DRIVER(spi) = {
.id = UCLASS_SPI,
.name = "spi",
.flags = DM_UC_FLAG_SEQ_ALIAS,
#if CONFIG_IS_ENABLED(OF_REAL)
.post_bind = dm_scan_fdt_dev,
#endif
.post_probe = spi_post_probe,
.child_pre_probe = spi_child_pre_probe,
.per_device_auto = sizeof(struct dm_spi_bus),
.per_child_auto = sizeof(struct spi_slave),
.per_child_plat_auto = sizeof(struct dm_spi_slave_plat),
#if CONFIG_IS_ENABLED(OF_REAL)
.child_post_bind = spi_child_post_bind,
#endif
};
//存放在段._u_boot_list_2_uclass_2_spi中,也就是section段的内容可以在uboot.map可以查看

想要获取uclass_driver需要先获取uclass_driver table。
struct uclass_driver *uclass =
ll_entry_start(struct uclass_driver, uclass);
// 会根据.u_boot_list_2_uclass_1的段地址来得到uclass_driver table的地址
const int n_ents = ll_entry_count(struct uclass_driver, uclass);
// 获得uclass_driver table的长度
struct uclass_driver *lists_uclass_lookup(enum uclass_id id)
// 从uclass_driver table中获取uclass id为id的uclass_driver。
2.4 driver
主要函数:
struct driver {
char *name; // 驱动名
enum uclass_id id; // 对应的uclass id
const struct udevice_id *of_match; // compatible字符串的匹配表,用于和device tree里面的设备节点匹配
int (*bind)(struct udevice *dev); // 用于绑定目标设备到该driver中
int (*probe)(struct udevice *dev); // 用于probe目标设备,激活
int (*remove)(struct udevice *dev); // 用于remove目标设备。禁用
int (*unbind)(struct udevice *dev); // 用于解绑目标设备到该driver中
int (*ofdata_to_platdata)(struct udevice *dev); // 在probe之前,解析对应udevice的dts节点,转化成udevice的平台数据
int (*child_post_bind)(struct udevice *dev); // 如果目标设备的一个子设备被绑定之后,调用
int (*child_pre_probe)(struct udevice *dev); // 在目标设备的一个子设备被probe之前,调用
int (*child_post_remove)(struct udevice *dev); // 在目标设备的一个子设备被remove之后,调用
int priv_auto_alloc_size; //需要分配多少空间作为其udevice的私有数据
int platdata_auto_alloc_size; //需要分配多少空间作为其udevice的平台数据
int per_child_auto_alloc_size; // 对于目标设备的每个

本文详细介绍了U-Boot中的设备模型(DeviceModel,DM)架构,特别是针对UCLASS、udevice、uclass_driver和driver的概念及关系。文章讲解了如何通过编写spimaster驱动来识别spinorflash设备,完成norflash的读写操作。此外,还涵盖了uboot代码的解析,包括DM的初始化、spinorflash设备的识别、设备树内容以及配置选项。最后,提供了SPI协议、SPI网卡驱动移植和设备树内容的相关链接。

1470

被折叠的 条评论
为什么被折叠?



