[Uboot] (external) Uboot Drive model

Source: Internet
Author: User
Tags bind spl

[Uboot] uboot process series :
[Project X] tiny210 (s5pv210) power-on START process (BL0-BL2)
[Project X] tiny210 (s5pv210) load code from storage device to DDR
[Uboot] (chapter I) uboot process--Overview
[Uboot] (chapter II) uboot process--UBOOT-SPL compilation process
[Uboot] (chapter III) uboot process--UBOOT-SPL code flow
[Uboot] (fourth chapter) Uboot process--uboot compilation process
[Uboot] (fifth) Uboot process--uboot START process
[Uboot] (Foreign article) Global_data Introduction
[Uboot] (foreign article) uboot Relocation Introduction
[Uboot] (foreign article) Uboot FDT Introduction

It is recommended to look at "[Uboot] (foreign) Uboot FDT Introduction", to understand uboot FDT function, in the drive model will be used.

============================================================================================================== I. Description 1, Uboot Drive model Simple Introduction

Uboot introduces the driver model (driver models), which provides a unified approach to drive definition and access interfaces. Improved compatibility between drivers and standard types of access.
The Uboot drive model is similar to the device driver model in kernel, but it is different.
In the follow-up we will drive the model (driver models) referred to as DM, in fact, in Uboot is also the abbreviation.

Refer to the specific details./doc/driver-model/readme.txt 2, how to enable the Uboot DM function

(1) configuration config_dm
The following are defined in Configs/tiny210_defconfig:

Config_dm=y

(2) to enable the corresponding Uclass driver config.
DM and Uclass are closely related, if we want to introduce DM in a module, then we need to use the corresponding module Uclass driver to replace the old version of the general driver.
About Uclass We will continue to explain in a follow-up.
Taking serial as an example, in order to introduce DM in serial, I opened the Config_dm_serial macro in Configs/tiny210_defconfig0, as follows

Config_dm_serial=y

See Driver/serial/makefile

Ifdef config_dm_serial
Obj-y + = serial-uclass.o # # Introduction to DM's SERIAL core driver
Else
obj-y + = SERIAL.O # # Universal SERIAL Cor E-drive
endif
# # You can see that the compiled serial core driver code is not the same.

(3) the corresponding device driver should also introduce the function of DM
Its device driver mainly implements and the underlying interaction, provides the interface for the Uclass layer. Follow-up and detailed instructions.

The follow-up is serial-uclass to explain the second, uboot DM overall structure 1, DM four components

Uboot's DM mainly has four components Udevice
Simple refers to device objects, which can be understood as devices in kernel. Driver
Udevice Drive, can be understood as kernel in the device_driver. Communicates with the underlying hardware device and provides an upper-facing interface for the device. Uclass
Let's take a look at the description of Uclass in README.txt:

UCLASS-A Group of devices which operate in the same. A uclass provides
        a by accessing individual devices within the group, but always
        using the same interface. For example a GPIO Uclass provides
        operations for Get/set value. An i²c Uclass May has ten i²c ports,
        4 with one driver, and 6 with another.

Uclass, a group of device groups that use the same mode of action set. Equivalent is an abstraction. The Uclass provides a unified interface for devices that use the same interface.
For example, GPIO Uclass provides the Get/set interface. For example, an i²c uclass may have 10 i²c ports, 4 use one drive, and the other 6 use a different driver. Uclass_driver
Corresponds to the Uclass driver. Mainly provides uclass operations, such as binding udevice when some operations. 2. Call Relationship Framework Diagram

3, the relationship between each other

Combined with the above image, the upper interface is directly communicated with the Uclass interface. Uclass can be understood as some of the same properties of the Udevice external operation interface, Uclass driver is uclass_driver, mainly for the upper layer to provide interfaces. Udevice refers to the abstract of the specific device, the corresponding driver is Driver,driver is mainly responsible for and hardware communication, for the Uclass to provide a practical set of operations. Udevice the way to find the corresponding Uclass is mainly through: Udevice corresponding driver ID and uclass corresponding to the ID of uclass_driver is matched. Udevice will bind with Uclass. Driver will bind with Udevice. Uclass_driver will bind with Uclass.

Here's a quick introduction: Both Uclass and Udevice are dynamically generated. When parsing devices in Fdt, Udevice is generated dynamically.
Then find the udevice corresponding driver, get the Uclass_driver ID by uclass ID in driver. Find out whether the corresponding Uclass has been generated from the Uclass list and generates Uclass dynamically without generating it. 4. GD and DM related parts

typedef struct GLOBAL_DATA {
#ifdef config_dm
    struct udevice  *dm_root;   /* Root
device in instance for Driver Model///DM, also the first udevice created in Uboot, corresponds to the root node in DTS.
    struct Udevice  *dm_root_f;/* Pre-relocation Root instance *
///before relocation root device
    struct list_ in DM Head Uclass_root;   /* Head of Core tree *
//Uclass linked list, all uclass that are udevice matched will be mounted on this list
#endif
} gd_t;
third, DM Four main components of the detailed introduction

Description of the data structure, how to define it, where to store it, and how to get four parts. 0, Uclass ID

each type of Uclass has its own ID number. defined in its uclass_driver. The Uclass ID in the driver of its affiliated udevice must be consistent with it.
All Uclass IDs are defined in Include/dm/uclass-id.h
List partial IDs as follows

Enum UCLASS_ID {/
    * These is used internally by Driver Model */
    uclass_root = 0,
    uclass_demo,
    uclass_clk, /     * Clock source, e.g. used by peripherals *
    / Uclass_pinctrl,     /* Pinctrl (PIN muxing/configuration) device */
    uclass_serial,/      * SERIAL UART */
}
1, Uclass (1) Data structure
struct Uclass {
    void *priv;  Uclass private Data pointer
    struct uclass_driver *uc_drv;//corresponding uclass driver
    struct list_head dev_head;//list header, The connection belongs to all udevice
    struct list_head sibling_node;//list node, used to connect Uclass to the Uclass_root list
};

(2) How to define
Uclass is uboot automatically generated. And not all Uclass are generated, there are corresponding Uclass driver and uclass that have been matched to Udevice will be generated.
Refer to the following Uboot DM Initialization section for specific reference. or refer to the Uclass_add implementation.

(3) storage location
All generated uclass will be mounted on the gd->uclass_root linked list.

(4) How to obtain, API
Directly traverse the linked list Gd->uclass_root list and obtain the corresponding Uclass according to the Uclass ID.
Specific uclass_get-"Uclass_find realized this function.
There are the following APIs:

int Uclass_get (enum uclass_id key, struct uclass **UCP);
Get the corresponding uclass from the Gd->uclass_root list
2, Uclass_driver (1) Data structure
Include/dm/uclass.h
struct Uclass_driver {const char *name;//uclass_driver command enum UCLASS_ID ID;//corresponding Uclass ID//The following function pointers are mainly called timing difference */INT (*post_bind) (struct udevice *dev); an int (*pre_unbind) (struct Udevice *dev) is called after Udevice is bound to the Uclass; Call Int (*pre_probe) (struct Udevice *dev) before Udevice is unbound from the uclass; an int (*post_probe) (struct Udevice *dev) is called before a udevice of the Uclass is probe; an int (*pre_remove) (struct Udevice *dev) is called after a udevice of the Uclass is probe, or an int is called before a uclass of the Udevice is made (*ch Ild_post_bind) (struct udevice *dev); an int (*child_pre_probe) (struct Udevice *dev) is called after a udevice of the Uclass is bound to the Udevice; an int (*init) (struct Uclass *class) is called before probe of a udevice of the uclass; When installing the Uclass, call Int (*destroy) (struct uclass *class); When destroying the Uclass, call int priv_auto_alloc_size; How many private data int per_device_auto_alloc_size need to be allocated for the corresponding uclass; int per_device_platdata_auto_alloc_size; int per_child_auto_alloc_size; int PER_CHILD_PLATDATa_auto_alloc_size; const void *ops;   Operation set uint32_t flags; Identified as};
(2) How to define
define Uclass_driver with Uclass_driver.
Taking Serial-uclass as an example
Uclass_driver (serial) = {
    . id        = uclass_serial,
    . Name        = "Serial",
    . Flags        = Dm_uc_flag_seq_ ALIAS,   
    . Post_probe    = Serial_post_probe,
    . Pre_remove    = Serial_pre_remove,
    . Per_device_auto _alloc_size = sizeof (struct serial_dev_priv),
};

The Uclass_driver is implemented as follows:

#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)))
about Ll_entry_declare We are in the [ Uboot] (sixth) Uboot process-command-line mode and command handling introduction has been introduced.

Finally get a structure like this

struct Uclass_driver  _u_boot_list_2_uclass_2_serial = {
    . id        = uclass_serial,   //sets the corresponding Uclass ID
    . Name        = "Serial",
    . Flags        = Dm_uc_flag_seq_alias,   
    . Post_probe    = Serial_post_probe,
    . pre_ Remove    = Serial_pre_remove,
    . per_device_auto_alloc_size = sizeof (struct serial_dev_priv),
}

and stored in the. U_boot_list_2_uclass_2_serial segment. (3) storage location
Through the above, we know that the serial uclass_driver structure _u_boot_list_2_uclass_2_serial is stored in the. U_boot_list_2_uclass_2_serial segment.
By looking at U-boot.map get the following

.u_boot_list_2_uclass_1 0x23e368e0 0x0 drivers/built-in.o. U_boot_list_2_u Class_2_gpio 0x23e368e0 0x48 drivers/gpio/built-in.o 0x23e368e0 _u_bo Ot_list_2_uclass_2_gpio//Gpio uclass driver symbols. u_boot_list_2_uclass_2_root 0x23e36928 0x48 Drive RS/BUILT-IN.O 0x23e36928 _u_boot_list_2_uclass_2_root//root uclass drvier symbols. u_boot_list                _2_uclass_2_serial 0x23e36970 0x48 DRIVERS/SERIAL/BUILT-IN.O 0x23e36970        _u_boot_list_2_uclass_2_serial//serial Uclass driver symbols. U_boot_list_2_uclass_2_simple_bus 0X23E369B8 0x48 drivers/built-in.o 0x23e369b8 _u_boot_list_2_uclass_2_simple_bus. u_boot_list_2 _uclass_3 0x23e36a00 0x0 drivers/built-in.o 0x23e36a00. = ALIGN (0x4) 

Eventually, all UCLASS driver structures are placed in a list in the. U_boot_list_2_uclass_1 and. U_boot_list_2_uclass_3 intervals.
This list is referred to as Uclass_driver table. (4) How to obtain, API
To get uclass_driver, you need to get uclass_driver table first.
You can use the following macro to get Uclass_driver table

    struct Uclass_driver *uclass =
        ll_entry_start (struct uclass_driver, uclass); 
The address of the Uclass_driver table is obtained according to the segment address of the. u_boot_list_2_uclass_1.

    const int n_ents = Ll_entry_count (struct uclass_driver , uclass);
Get the length of the Uclass_driver table

Then, by traversing the Uclass_driver table, the corresponding Uclass_driver is obtained.
There are the following APIs

struct Uclass_driver *lists_uclass_lookup (enum uclass_id ID)
//Uclass with Uclass_driver ID as ID from uclass_driver table.
3, Udevice (1) Data structure
Include/dm/device.h
struct Udevice {
    const struct driver *driver;//Udevice corresponds to driver
    const char *name;//device name
    void *platdata;// The Udevice platform data is
    void *parent_platdata;//platform data that is provided to the parent device
    void *uclass_platdata;//platform data provided to the owning Uclass for use with
    int of _offset; The DTB node of the Udevice is offset, representing the node in the DTB nodes
    ulong driver_data;//drive data
    struct udevice *parent;//Parent device
    void *priv; Pointer to private data
    struct uclass *uclass;//belongs
    to Uclass void *uclass_priv;//private data pointer void Uclass used by the owning *parent_
    Priv The private data pointer that is provided to its parent device is
    struct list_head uclass_node;//used to connect to the list of Uclass on which the
    struct list_head child_head;//list header, Connect its sub
    -device struct list_head sibling_node;//On the linked list that is used to connect to its parent device
    uint32_t flags;//identity
    int req_seq;
    int seq;
#ifdef config_devres
    struct list_head devres_head;
#endif
};

(2) How to define
In the case of DTB existence, it is dynamically generated by Uboot parsing DTB, followed by the "Uboot DM initialization" section described in detail.

(3) The storage location is connected to the corresponding Uclass
That is, connect to the Uclass->dev_head in the child device linked list that is connected to the parent device
That is, it is connected to the Udevice->child_head, and the final root device is the root device of gd->dm_root.

(4) How to get, API get Udevice from Uclass
Traverse the uclass->dev_head to get the corresponding udevice. There are the following APIs

#define UCLASS_FOREACH_DEV (POS, UC) \ list_for_each_entry (POS, &uc->dev_head, Uclass_node) #define Uclass_fore Ach_dev_safe (POS, Next, UC) \ List_for_each_entry_safe (POS, Next, &uc->dev_head, uclass_node) int uclass_get_ Device (enum uclass_id ID, int index, struct udevice **DEVP);
                  Get Udevice int uclass_get_device_by_name (enum uclass_id ID, const char *name from Uclass by index,//Get Uclass from Udevice by device name
struct Udevice **DEVP);
int Uclass_get_device_by_seq (enum uclass_id ID, int seq, struct udevice **DEVP);
int Uclass_get_device_by_of_offset (enum uclass_id ID, int node, struct udevice **DEVP); int Uclass_get_device_by_phandle (enum uclass_id ID, struct udevice *parent, const char *name, struct UDEV
Ice **DEVP);
int Uclass_first_device (enum uclass_id ID, struct udevice **devp);
int Uclass_first_device_err (enum uclass_id ID, struct udevice **devp);
int Uclass_next_device (struct udevice **DEVP); int Uclass_resolve_seq (StruCT Udevice *dev); 
4, Driver

And the Uclass_driver way are similar. (1) Data structure
Include/dm/device.h

struct driver {char *name;  Drive name enum UCLASS_ID ID;    The corresponding Uclass ID const struct UDEVICE_ID *of_match;   A matching table of compatible strings that matches an int (*bind) (struct Udevice *dev) with the device node inside the devices tree;   Used to bind the target device to the driver int (*probe) (struct udevice *dev); For probe target device, activate Int (*remove) (struct udevice *dev); For the remove target device. disables int (*unbind) (struct udevice *dev); Used to unbind the target device into the driver int (*ofdata_to_platdata) (struct udevice *dev); Before probe, the DTS node corresponding to Udevice was parsed into Udevice's platform data int (*child_post_bind) (struct Udevice *dev). If a child device of the target device is bound, call Int (*child_pre_probe) (struct udevice *dev); Call Int (*child_post_remove) (struct Udevice *dev) before a child device of the target device is probe; After a sub-device of the target device is removed, the int priv_auto_alloc_size is called; How much space needs to be allocated as its udevice private data int platdata_auto_alloc_size;  How much space needs to be allocated as the platform data of its udevice int per_child_auto_alloc_size; For each child device of the target device, how much space needs to be allocated as the parent device's private data int per_child_platdata_auto_alloc_size;
   How much space will be allocated for each child device of the target device as the platform data for the parent device const void *ops; /* driver-specific Operations *//operation set of pointers, provided to uclass use, no specified action set format, determined by the specific Uclass uint32_t flags; some flag bits};
(2) How to define
define a driver by U_boot_driver.
Take s5pv210 as an example:
Driver/serial/serial_s5p.c
U_boot_driver (serial_s5p) = {
    . Name    = "serial_s5p",
    . ID    = uclass_serial,
    . Of_match = S5p_serial_ IDs,
    . Ofdata_to_platdata = S5p_serial_ofdata_to_platdata,
    . platdata_auto_alloc_size = sizeof (struct S5P_ Serial_platdata),
    . Probe = S5p_serial_probe,
    . ops    = &s5p_serial_ops,
    . Flags = Dm_flag_pre_ RELOC,
};

The U_boot_driver is implemented as follows:

#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)))
about Ll_entry_declare us in the [Uboot] (sixth) Uboot process-command-line mode and command handling introduction has been introduced.

Finally get the following structure

struct driver _u_boot_list_2_driver_2_serial_s5p= {
    . Name    = "serial_s5p",
    . ID    = uclass_serial,
    . Of_match = S5p_serial_ids,
    . Ofdata_to_platdata = S5p_serial_ofdata_to_platdata,
    . platdata_auto_ alloc_size = sizeof (struct s5p_serial_platdata),
    . Probe = S5p_serial_probe,
    . ops    = &s5p_serial_ OPS,
    . Flags = Dm_flag_pre_reloc,
};

and stored in the. u_boot_list_2_driver_2_serial_s5p segment (3) storage location
By the above, we know the driver structure of serial_s5p _u_boot_ The list_2_driver_2_serial_s5p is stored in the. u_boot_list_2_driver_2_serial_s5p segment.
by looking at U-boot.map get the following

 u_boot_list_2_driver_1 0x23e36754 0x0 DRIVERS/BUILT-IN.O. u_boot_list_2_                Driver_2_gpio_exynos 0x23e36754 0x44 DRIVERS/GPIO/BUILT-IN.O 0x23e36754 _u_boot_list_2_driver_2_gpio_exynos. U_boot_list_2_driver_2_root_driver 0x23e36798 0x44 drivers/b 
                UILT-IN.O 0x23e36798 _u_boot_list_2_driver_2_root_driver. u_boot_list_2_driver_2_serial_s5p 0X23E367DC 0x44 DRIVERS/SERIAL/BUILT-IN.O 0X23E367DC _u_boot_list_2_
                driver_2_serial_s5p. U_boot_list_2_driver_2_simple_bus_drv 0x23e36820 0x44 DRIVERS/BUILT-IN.O 0x23e36820 _u_boot_list_2_driver_2_simple_bus_drv. U_boot_list_2_driver_3 0x23e36 864 0x0 DRIVERS/BUILT-IN.O 

Eventually, all driver structures are placed in a list in the. u_boot_list_2_driver_1 and. U_boot_list_2_driver_3 intervals.
This list is referred to as driver table. (4) How to obtain, API
To get driver, you need to get driver table first.
You can use the following macro to get driver table

    struct Driver *drv =
        Ll_entry_start (struct driver, driver);
The address of the Uclass_driver table is obtained according to the segment address of the. u_boot_list_2_driver_1.

    const int n_ents = ll_entry_count (struct driver, driver );
Get the length of the driver table

Then, by traversing the driver table, the corresponding driver is obtained.

struct Driver *lists_driver_lookup_name (const char *name)
//Gets driver named name from driver table.
Iv. Some API collation of DM

Let's take a look at the previous section to understand. 1. Uclass Related API

int Uclass_get (enum uclass_id key, struct uclass **UCP);
Get the corresponding uclass from the Gd->uclass_root list

2. Uclass_driver Related API
struct Uclass_driver *lists_uclass_lookup (enum uclass_id ID)
//Uclass with Uclass_driver ID as ID from uclass_driver table.
3. Udevice Related API
 #define UCLASS_FOREACH_DEV (POS, UC) \ list_for_each_entry (POS, &uc->dev_head, Uclass _node) #define UCLASS_FOREACH_DEV_SAFE (POS, Next, UC) \ List_for_each_entry_safe (POS, Next, &uc->dev_head, UC lass_node) int device_bind (struct udevice *parent, const struct driver *drv, const char *name, void *platdata, I

NT Of_offset, struct Udevice **DEVP)//Initialize a udevice and bind it with its uclass, driver. int device_bind_by_name (struct udevice *parent, bool pre_reloc_only, const struct Driver_info *info, struct UD

Evice **DEVP)//Gets driver by name and calls Device_bind to Udevice initialization and binds it to uclass, driver.
    int Uclass_bind_device (struct udevice *dev)//bind Udevice to its corresponding Uclass device linked list {UC = dev->uclass;
List_add_tail (&dev->uclass_node, &uc->dev_head); } int Uclass_get_device (enum uclass_id ID, int index, struct udevice **DEVP); Get Udevice from Uclass by index, note that the device is probe int uclass_get_device_by_name (enum u 
) during acquisition.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.