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
};


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM