U-Boot Driver Model領域模型設計


需求分析

在2014年以前,uboot沒有一種類似於linux kernel的設備驅動模型,隨着uboot支持的設備越來越多,其一直受到如下問題困擾:

  • 設備初始化流程都獨立實現,而且為了集成到系統,需要修改核心公共代碼(如init_sequence)
  • 很多子系統只允許一個驅動,比如無法同時支持USB2.0和USB3.0
  • 子系統間的交互實現各異,開發難度大
  • 沒有個統一的設備視圖(如linux的/sys)

uboot driver model(U-Boot驅動模型,以下簡寫dm)的提出就是為了解決這些問題,它的設計目標包括:

  • 提供統一設備驅動框架,降低設備驅動的開發復雜度
  • 提供設備樹視圖
  • 支持設備組
  • 支持設備lazy init
  • 支持設備驅動沙盒測試
  • 較小的系統開銷(內存和CPU)

對象設計

對象的設計之所以區分靜態形式和運行態形式,考量的出發點是設計模塊化。
靜態表達形式的對象是離散的,和系統和其他對象隔離開,減小對象的復雜度,利於模塊化設計,遵循人類表達習慣。
運行態形式的對象是把所有對象組合成層次視圖,有着清晰的數據關聯視圖。方便系統運行時數據的流動。

靜態表達形式

device: FDT(設備樹文本描述) 或者 靜態數據結構U_BOOT_DEVICE(以數據段形式組織)
driver: 靜態數據結構U_BOOT_DRIVER(以數據段形式組織)

運行態形式

udevice: 設備對象(以鏈表形式組織)
driver: 驅動對象。作為udevice的一個屬性
uclass:設備組公共屬性對象(以鏈表形式組織),外部頂層對象,作為udevice的一個屬性
uclass_driver: 設備組公共行為對象,作為uclass的一個屬性

領域建模

uboot設備模型中udevice為核心對象,以樹型模型組織(如下),其為dm的頂層結構。

 

 

單個udevice建模如下,詳細對象定義參見《附:核心數據結構》小節。

所有對象可以按udevice或者uclass進行遍歷。

 

DM初始化流程

DM初始化流程包括:

  • 模型初始化
  • 靜態對象初始化
  • 運行態對象初始化
  • 設備組公共初始化
  • 設備初始化

DM初始化的總入口接口:dm_init_and_scan(),其主要由以下三塊組成:

dm_init():創建udevice和uclass空鏈表,創建根設備(root device)

dm_scan_platdata():掃描U_BOOT_DEVICE定義的設備,創建對應的udevice和uclass對象,查找並綁定相應driver,並調用probe流程。

dm_scan_fdt():掃描由FDT設備樹文件定義的設備,創建對應的udevice和uclass對象,查找並綁定相應driver,並調用probe流程。

附:核心數據結構

U_BOOT_DRIVER(demo_shape_drv) = {
    .name    = "demo_shape_drv",
    .of_match = demo_shape_id,
    .id    = UCLASS_DEMO,
    .ofdata_to_platdata = shape_ofdata_to_platdata,
    .ops    = &shape_ops,
    .probe = dm_shape_probe,
    .remove = dm_shape_remove,
    .priv_auto_alloc_size = sizeof(struct shape_data),
    .platdata_auto_alloc_size = sizeof(struct dm_demo_pdata),
};

#define U_BOOT_DRIVER(__name)                        \
    ll_entry_declare(struct driver, __name, driver)
    
#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)))

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

U_BOOT_DEVICE(demo0) = {
    .name = "demo_shape_drv",
    .platdata = &red_square,
};
#define U_BOOT_DEVICE(__name) \ ll_entry_declare(struct driver_info, __name, driver_info)
struct driver_info { const char *name; const void *platdata; #if CONFIG_IS_ENABLED(OF_PLATDATA) uint platdata_size; #endif }; struct uclass { void *priv; struct uclass_driver *uc_drv; struct list_head dev_head; struct list_head sibling_node; }; UCLASS_DRIVER(demo) = { .name = "demo", .id = UCLASS_DEMO, };
#define UCLASS_DRIVER(__name) \ ll_entry_declare(struct uclass_driver, __name, uclass)
struct uclass_driver { const char *name; enum uclass_id id; int (*post_bind)(struct udevice *dev); int (*pre_unbind)(struct udevice *dev); int (*pre_probe)(struct udevice *dev); int (*post_probe)(struct udevice *dev); int (*pre_remove)(struct udevice *dev); int (*child_post_bind)(struct udevice *dev); int (*child_pre_probe)(struct udevice *dev); int (*init)(struct uclass *class); int (*destroy)(struct uclass *class); int priv_auto_alloc_size; 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; }; struct udevice { const struct driver *driver; const char *name; void *platdata; void *parent_platdata; void *uclass_platdata; int of_offset; ulong driver_data; struct udevice *parent; void *priv; struct uclass *uclass; void *uclass_priv; void *parent_priv; struct list_head uclass_node; struct list_head child_head; struct list_head sibling_node; uint32_t flags; int req_seq; int seq; #ifdef CONFIG_DEVRES struct list_head devres_head; #endif };

 

--EOF--

 


免責聲明!

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



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