U-Boot驱动模型(DM)分析

在U-boot中引入驱动模型(driver model),为驱动的定义和范文接口提供统一的方法,提高驱动间的兼容性以及访问的标准性,u-boot中的驱动模型(DM)和kernel中的设备驱动模型类似,但是也有所区别
通过宏定义CONFIG_DM使能驱动模型,对应的实际驱动设备则需要通过使能CONFIG_DM_SERIAL来使能;后面以serial驱动为例
 
 
关于dm的三个概念:
uclass:一组同类型的devices,uclass为同一个group的device,提供一个相同的接口。比如:I2C、GPIO等
driver:上层的接口,英文原文解释是“some code which talks to a peripheral and presents a higher-level  interface to it.”
device:driver的一个实例,绑定到一个具体的端口或者外设。(driver和device是不是可以类比于程序与进程,进程是程序的一个实例)

 

uclass/udevice/drivers三者之间的关联

uclass可以理解为具有相同属性的device对外操作的接口, 它与上层接口直接通讯,其驱动为uclass_driver,给上层提供接口
udevice对具体设备的抽象,对应的驱动是driver; driver负责和硬件通讯,为uclass提供实际的操作集
udevice如何和uclass绑定:udevice对应的driver_id和uclass对应的uclass_driver_id是否匹配
hardware对应的driver绑定对应的udevice,udevice绑定uclass,uclass有其对应的uclass_driver

uclass和udevice是动态生成的

    1. udevice在解析fdt中的设备的时候自动生成,然后udevice找到对应的driver
    2. driver中保存了uclass_id, 根据它找到uclass_driver_id
    3. 从uclass链表中查找对应的uclass是否已经生成,若没有生成,则动态生成
    4. 重点是解析设备树,生成udevice, 并找到对应的driver

 

 

要分析uclass之前,首先得搞清楚两个宏U_BOOT_DRIVER及U_BOOT_DEVICE的作用:

1.U_BOOT_DRIVER及U_BOOT_DEVICE宏定义如下:

 

#define U_BOOT_DRIVER(__name) \
ll_entry_declare(struct driver, __name, driver)

#define U_BOOT_DEVICE(__name) \
ll_entry_declare(struct driver_info, __name, driver_info)

#define ll_entry_declare(_type, _name, _list) \
_type _u_boot_list_2_##_list##_2_##_name __aligned(4) \
__attribute__((unused, \
section(".u_boot_list_2_"#_list"_2_"#_name)))

 

全局数据GD中和DM相关部分

typedef struct global_data {
   // dts中的根节点,第一个创建的udevice
   struct udevice  *dm_root;

   // relocation之前的根设备
   struct udevice  *dm_root_f;

  // uclass的链表, 挂的是有udevice的uclass
   struct list_head uclass_root;  
} gd_t;

 

 

 

2。通过对宏定义UCLASS_DRIVER的展开

/* Declare a new uclass_driver */
#define UCLASS_DRIVER(__name) \
ll_entry_declare(struct uclass_driver, __name, uclass)

#define ll_entry_declare(_type, _name, _list) \
_type _u_boot_list_2_##_list##_2_##_name __aligned(4) \
__attribute__((unused, \
section(".u_boot_list_2_"#_list"_2_"#_name)))

 2-1

int dm_init_and_scan(bool pre_reloc_only)
{
  int ret;

/*创建udevice和uclass空链表,创建根设备(root device)*/
  ret = dm_init();
  if (ret) {
    debug("dm_init() failed: %d\n", ret);
    return ret;
  }
/*扫描U_BOOT_DEVICE定义的设备,与U_BOOT_DRIVER定义的driver进行查找,并绑定相应driver*/
  ret = dm_scan_platdata(pre_reloc_only);
  if (ret) {
    debug("dm_scan_platdata() failed: %d\n", ret);
    return ret;
  }

  if (CONFIG_IS_ENABLED(OF_CONTROL)) {
/*扫描由FDT设备树文件定义的设备,与U_BOOT_DRIVER定义的driver进行查找,并绑定相应driver*/
  ret = dm_scan_fdt(gd->fdt_blob, pre_reloc_only);
  if (ret) {
    debug("dm_scan_fdt() failed: %d\n", ret);
    return ret;
   }
  }
  ret = dm_scan_other(pre_reloc_only);
  if (ret)
    return ret;

  return 0;
}

dm_init():创建udevice和uclass空链表,创建根设备(root device)

dm_scan_platdata():调用函数lists_bind_drivers,扫描U_BOOT_DEVICE定义的设备,与U_BOOT_DRIVER定义的driver进行查找,创建udevice,并绑定相应driver。
dm_scan_fdt():扫描由FDT设备树文件定义的设备,与U_BOOT_DRIVER定义的driver进行查找,创建udevice,并绑定相应driver。

2-2

 

int dm_init(bool of_live)
{
    int ret;

    if (gd->dm_root) {
        dm_warn("Virtual root driver already exists!\n");
        return -EINVAL;
    }
//#define DM_UCLASS_ROOT_NON_CONST (((gd_t *)gd)->uclass_root) 创建头结点gd->uclass_root
    INIT_LIST_HEAD(&DM_UCLASS_ROOT_NON_CONST);

    if (IS_ENABLED(CONFIG_NEEDS_MANUAL_RELOC)) {
        fix_drivers();
        fix_uclass();
        fix_devices();
    }

    ret = device_bind_by_name(NULL, false, &root_info, &DM_ROOT_NON_CONST);
    if (ret)
        return ret;
#if CONFIG_IS_ENABLED(OF_CONTROL)
    if (CONFIG_IS_ENABLED(OF_LIVE) && of_live)
        DM_ROOT_NON_CONST->node = np_to_ofnode(gd_of_root());
    else
        DM_ROOT_NON_CONST->node = offset_to_ofnode(0);
#endif
    ret = device_probe(DM_ROOT_NON_CONST);
    if (ret)
        return ret;

    return 0;
}
 

[root.c]dm_init(); // 主要是初始化driver model的root实例(gd->dm_root和gd->uclass_root)
  [device.c]device_bind_by_name(NULL, false, &root_info, &DM_ROOT_NON_CONST);// 创建一个device并将其绑定到driver,这是一个帮助器函数,用于绑定不使用设备树的设备。
    [list.c]lists_driver_lookup_name(“root_driver”); // 通过driver name “root_driver”遍历整个driver list,找到U_BOOT_DRIVER(root_driver)定义的driver地址
    [device.c]device_bind_common(NULL, drv, “root_driver”, NULL, driver_data, node, 0, devp); // 创建udevice dm_root和uclass root,并将driver root_driver、udevice dm_root和uclass root三者进行绑定。
      [uclass.c]uclass_get(drv->id, &uc); // 根据ID UCLASS_ROOT获取对应的uclass,第一次运行它不存在,所以创建它。
        [uclass.c]uclass_find(); // 第一次运行无法找到对应的uclass UCLASS_ROOT。
        [uclass.c]uclass_add(); //在未找到的情况下,就会在列表中创建一个新的root uclass。
      [device.c]calloc(1, size); // 创建第一个udevice dm_root并初始化;
      [uclass.c]uclass_bind_device(dev); // 将udevice dm_root与root uclass进行绑定,设备udevice dm_root连接到root uclass的uc->dev_head设备链表中。
  [device.c]device_probe(gd->dm_root); // 探测设备udevice dm_root并激活它

/* Cast away any volatile pointer */
#define DM_ROOT_NON_CONST       (((gd_t *)gd)->dm_root)
#define DM_UCLASS_ROOT_NON_CONST    (((gd_t *)gd)->uclass_root)
 
 
int device_bind_by_name(struct udevice *parent, bool pre_reloc_only,
            const struct driver_info *info, struct udevice **devp)
{
    struct driver *drv;
    uint platdata_size = 0;
    int ret;
 
//lists_driver_lookup_name("root_driver")
/*从driver list中查找info的名字*/

    drv = lists_driver_lookup_name(info->name);
    if (!drv)
        return -ENOENT;
    if (pre_reloc_only && !(drv->flags & DM_FLAG_PRE_RELOC))
        return -EPERM;

#if CONFIG_IS_ENABLED(OF_PLATDATA)
    platdata_size = info->platdata_size;
#endif
/*创建udevice,绑定*/
    ret = device_bind_common(parent, drv, info->name,
                 (void *)info->platdata, 0, ofnode_null(),
                 platdata_size, devp);
    if (ret)
        return ret;

    return ret;
}
 
 
struct driver {
    char *name;
    enum uclass_id id;
    const struct udevice_id *of_match;
    int (*bind)(struct udevice *dev);
    int (*probe)(struct udevice *dev);
    int (*remove)(struct udevice *dev);
    int (*unbind)(struct udevice *dev);
    int (*ofdata_to_platdata)(struct udevice *dev);
    int (*child_post_bind)(struct udevice *dev);
    int (*child_pre_probe)(struct udevice *dev);
    int (*child_post_remove)(struct udevice *dev);
    int priv_auto_alloc_size;
    int platdata_auto_alloc_size;
    int per_child_auto_alloc_size;
    int per_child_platdata_auto_alloc_size;
    const void *ops;    /* driver-specific operations */
    uint32_t flags;
#if CONFIG_IS_ENABLED(ACPIGEN)
    struct acpi_ops *acpi_ops;
#endif
};
posted @ 2022-02-23 21:10  liujunhuasd  阅读(1226)  评论(0编辑  收藏  举报