summaryrefslogtreecommitdiff
path: root/doc/driver-model/UDM-design.txt
diff options
context:
space:
mode:
Diffstat (limited to 'doc/driver-model/UDM-design.txt')
-rw-r--r--doc/driver-model/UDM-design.txt315
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