diff options
Diffstat (limited to 'doc/driver-model/UDM-design.txt')
-rw-r--r-- | doc/driver-model/UDM-design.txt | 315 |
1 files changed, 0 insertions, 315 deletions
diff --git a/doc/driver-model/UDM-design.txt b/doc/driver-model/UDM-design.txt deleted file mode 100644 index 9f03bba..0000000 --- a/doc/driver-model/UDM-design.txt +++ /dev/null @@ -1,315 +0,0 @@ -The U-Boot Driver Model Project -=============================== -Design document -=============== -Marek Vasut <marek.vasut@gmail.com> -Pavel Herrmann <morpheus.ibis@gmail.com> -2012-05-17 - -I) The modular concept ----------------------- - -The driver core design is done with modularity in mind. The long-term plan is to -extend this modularity to allow loading not only drivers, but various other -objects into U-Boot at runtime -- like commands, support for other boards etc. - -II) Driver core initialization stages -------------------------------------- - -The drivers have to be initialized in two stages, since the U-Boot bootloader -runs in two stages itself. The first stage is the one which is executed before -the bootloader itself is relocated. The second stage then happens after -relocation. - - 1) First stage - -------------- - - The first stage runs after the bootloader did very basic hardware init. This - means the stack pointer was configured, caches disabled and that's about it. - The problem with this part is the memory management isn't running at all. To - make things even worse, at this point, the RAM is still likely uninitialized - and therefore unavailable. - - 2) Second stage - --------------- - - At this stage, the bootloader has initialized RAM and is running from it's - final location. Dynamic memory allocations are working at this point. Most of - the driver initialization is executed here. - -III) The drivers ----------------- - - 1) The structure of a driver - ---------------------------- - - The driver will contain a structure located in a separate section, which - will allow linker to create a list of compiled-in drivers at compile time. - Let's call this list "driver_list". - - struct driver __attribute__((section(driver_list))) { - /* The name of the driver */ - char name[STATIC_CONFIG_DRIVER_NAME_LENGTH]; - - /* - * This function should connect this driver with cores it depends on and - * with other drivers, likely bus drivers - */ - int (*bind)(struct instance *i); - - /* This function actually initializes the hardware. */ - int (*probe)(struct instance *i); - - /* - * The function of the driver called when U-Boot finished relocation. - * This is particularly important to eg. move pointers to DMA buffers - * and such from the location before relocation to their final location. - */ - int (*reloc)(struct instance *i); - - /* - * This is called when the driver is shuting down, to deinitialize the - * hardware. - */ - int (*remove)(struct instance *i); - - /* This is called to remove the driver from the driver tree */ - int (*unbind)(struct instance *i); - - /* This is a list of cores this driver depends on */ - struct driver *cores[]; - }; - - The cores[] array in here is very important. It allows u-boot to figure out, - in compile-time, which possible cores can be activated at runtime. Therefore - if there are cores that won't be ever activated, GCC LTO might remove them - from the final binary. Actually, this information might be used to drive build - of the cores. - - FIXME: Should *cores[] be really struct driver, pointing to drivers that - represent the cores? Shouldn't it be core instance pointer? - - 2) Instantiation of a driver - ---------------------------- - - The driver is instantiated by calling: - - driver_bind(struct instance *bus, const struct driver_info *di) - - The "struct instance *bus" is a pointer to a bus with which this driver should - be registered with. The "root" bus pointer is supplied to the board init - functions. - - FIXME: We need some functions that will return list of busses of certain type - registered with the system so the user can find proper instance even if - he has no bus pointer (this will come handy if the user isn't - registering the driver from board init function, but somewhere else). - - The "const struct driver_info *di" pointer points to a structure defining the - driver to be registered. The structure is defined as follows: - - struct driver_info { - char name[STATIC_CONFIG_DRIVER_NAME_LENGTH]; - void *platform_data; - } - - The instantiation of a driver by calling driver_bind() creates an instance - of the driver by allocating "struct driver_instance". Note that only struct - instance is passed to the driver. The wrapping struct driver_instance is there - for purposes of the driver core: - - struct driver_instance { - uint32_t flags; - struct instance i; - }; - - struct instance { - /* Pointer to a driver information passed by driver_register() */ - const struct driver_info *info; - /* Pointer to a bus this driver is bound with */ - struct instance *bus; - /* Pointer to this driver's own private data */ - void *private_data; - /* Pointer to the first block of successor nodes (optional) */ - struct successor_block *succ; - } - - The instantiation of a driver does not mean the hardware is initialized. The - driver_bind() call only creates the instance of the driver, fills in the "bus" - pointer and calls the drivers' .bind() function. The .bind() function of the - driver should hook the driver with the remaining cores and/or drivers it - depends on. - - It's important to note here, that in case the driver instance has multiple - parents, such parent can be connected with this instance by calling: - - driver_link(struct instance *parent, struct instance *dev); - - This will connect the other parent driver with the newly instantiated driver. - Note that this must be called after driver_bind() and before driver_acticate() - (driver_activate() will be explained below). To allow struct instance to have - multiple parent pointer, the struct instance *bus will utilize it's last bit - to indicate if this is a pointer to struct instance or to an array if - instances, struct successor block. The approach is similar as the approach to - *succ in struct instance, described in the following paragraph. - - The last pointer of the struct instance, the pointer to successor nodes, is - used only in case of a bus driver. Otherwise the pointer contains NULL value. - The last bit of this field indicates if this is a bus having a single child - node (so the last bit is 0) or if this bus has multiple child nodes (the last - bit is 1). In the former case, the driver core should clear the last bit and - this pointer points directly to the child node. In the later case of a bus - driver, the pointer points to an instance of structure: - - struct successor_block { - /* Array of pointers to instances of devices attached to this bus */ - struct instance *dev[BLOCKING_FACTOR]; - /* Pointer to next block of successors */ - struct successor_block *next; - } - - Some of the *dev[] array members might be NULL in case there are no more - devices attached. The *next is NULL in case the list of attached devices - doesn't continue anymore. The BLOCKING_FACTOR is used to allocate multiple - slots for successor devices at once to avoid fragmentation of memory. - - 3) The bind() function of a driver - ---------------------------------- - - The bind function of a driver connects the driver with various cores the - driver provides functions for. The driver model related part will look like - the following example for a bus driver: - - int driver_bind(struct instance *in) - { - ... - core_bind(&core_i2c_static_instance, in, i2c_bus_funcs); - ... - } - - FIXME: What if we need to run-time determine, depending on some hardware - register, what kind of i2c_bus_funcs to pass? - - This makes the i2c core aware of a new bus. The i2c_bus_funcs is a constant - structure of functions any i2c bus driver must provide to work. This will - allow the i2c command operate with the bus. The core_i2c_static_instance is - the pointer to the instance of a core this driver provides function to. - - FIXME: Maybe replace "core-i2c" with CORE_I2C global pointer to an instance of - the core? - - 4) The instantiation of a core driver - ------------------------------------- - - The core driver is special in the way that it's single-instance driver. It is - always present in the system, though it might not be activated. The fact that - it's single instance allows it to be instantiated at compile time. - - Therefore, all possible structures of this driver can be in read-only memory, - especially struct driver and struct driver_instance. But the successor list, - which needs special treatment. - - To solve the problem with a successor list and the core driver flags, a new - entry in struct gd (global data) will be introduced. This entry will point to - runtime allocated array of struct driver_instance. It will be possible to - allocate the exact amount of struct driver_instance necessary, as the number - of cores that might be activated will be known at compile time. The cores will - then behave like any usual driver. - - Pointers to the struct instance of cores can be computed at compile time, - therefore allowing the resulting u-boot binary to save some overhead. - - 5) The probe() function of a driver - ----------------------------------- - - The probe function of a driver allocates necessary resources and does required - initialization of the hardware itself. This is usually called only when the - driver is needed, as a part of the defered probe mechanism. - - The driver core should implement a function called - - int driver_activate(struct instance *in); - - which should call the .probe() function of the driver and then configure the - state of the driver instance to "ACTIVATED". This state of a driver instance - should be stored in a wrap-around structure for the structure instance, the - struct driver_instance. - - 6) The command side interface to a driver - ----------------------------------------- - - The U-Boot command shall communicate only with the specific driver core. The - driver core in turn exports necessary API towards the command. - - 7) Demonstration imaginary board - -------------------------------- - - Consider the following computer: - - * - | - +-- System power management logic - | - +-- CPU clock controlling logc - | - +-- NAND controller - | | - | +-- NAND flash chip - | - +-- 128MB of DDR DRAM - | - +-- I2C bus #0 - | | - | +-- RTC - | | - | +-- EEPROM #0 - | | - | +-- EEPROM #1 - | - +-- USB host-only IP core - | | - | +-- USB storage device - | - +-- USB OTG-capable IP core - | | - | +-- connection to the host PC - | - +-- GPIO - | | - | +-- User LED #0 - | | - | +-- User LED #1 - | - +-- UART0 - | - +-- UART1 - | - +-- Ethernet controller #0 - | - +-- Ethernet controller #1 - | - +-- Audio codec - | - +-- PCI bridge - | | - | +-- Ethernet controller #2 - | | - | +-- SPI host card - | | | - | | +-- Audio amplifier (must be operational before codec) - | | - | +-- GPIO host card - | | - | +-- User LED #2 - | - +-- LCD controller - | - +-- PWM controller (must be enabled after LCD controller) - | - +-- SPI host controller - | | - | +-- SD/MMC connected via SPI - | | - | +-- SPI flash - | - +-- CPLD/FPGA with stored configuration of the board |