diff options
Diffstat (limited to 'doc/driver-model')
| -rw-r--r-- | doc/driver-model/UDM-design.txt | 315 | ||||
| -rw-r--r-- | doc/driver-model/UDM-fpga.txt | 115 | ||||
| -rw-r--r-- | doc/driver-model/UDM-keyboard.txt | 47 | ||||
| -rw-r--r-- | doc/driver-model/UDM-serial.txt | 191 | ||||
| -rw-r--r-- | doc/driver-model/UDM-stdio.txt | 191 | ||||
| -rw-r--r-- | doc/driver-model/UDM-tpm.txt | 48 | ||||
| -rw-r--r-- | doc/driver-model/UDM-usb.txt | 94 | ||||
| -rw-r--r-- | doc/driver-model/UDM-video.txt | 74 | 
8 files changed, 1075 insertions, 0 deletions
| diff --git a/doc/driver-model/UDM-design.txt b/doc/driver-model/UDM-design.txt new file mode 100644 index 000000000..185f477b0 --- /dev/null +++ b/doc/driver-model/UDM-design.txt @@ -0,0 +1,315 @@ +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 diff --git a/doc/driver-model/UDM-fpga.txt b/doc/driver-model/UDM-fpga.txt new file mode 100644 index 000000000..4f9df940e --- /dev/null +++ b/doc/driver-model/UDM-fpga.txt @@ -0,0 +1,115 @@ +The U-Boot Driver Model Project +=============================== +I/O system analysis +=================== +Marek Vasut <marek.vasut@gmail.com> +2012-02-21 + +I) Overview +----------- + +The current FPGA implementation is handled by command "fpga". This command in +turn calls the following functions: + +fpga_info() +fpga_load() +fpga_dump() + +These functions are implemented by what appears to be FPGA multiplexer, located +in drivers/fpga/fpga.c . This code determines which device to operate with +depending on the device ID. + +The fpga_info() function is multiplexer of the functions providing information +about the particular FPGA device. These functions are implemented in the drivers +for the particular FPGA device: + +xilinx_info() +altera_info() +lattice_info() + +Similar approach is used for fpga_load(), which multiplexes "xilinx_load()", +"altera_load()" and "lattice_load()" and is used to load firmware into the FPGA +device. + +The fpga_dump() function, which prints the contents of the FPGA device, is no +different either, by multiplexing "xilinx_dump()", "altera_dump()" and +"lattice_dump()" functions. + +Finally, each new FPGA device is registered by calling "fpga_add()" function. +This function takes two arguments, the second one being particularly important, +because it's basically what will become platform_data. Currently, it's data that +are passed to the driver from the board/platform code. + +II) Approach +------------ + +The path to conversion of the FPGA subsystem will be very straightforward, since +the FPGA subsystem is already quite dynamic. Multiple things will need to be +modified though. + +First is the registration of the new FPGA device towards the FPGA core. This +will be achieved by calling: + +  fpga_device_register(struct instance *i, const struct fpga_ops *ops); + +The particularly interesting part is the struct fpga_ops, which contains +operations supported by the FPGA device. These are basically the already used +calls in the current implementation: + +struct fpga_ops { +  int info(struct instance *i); +  int load(struct instance *i, const char *buf, size_t size); +  int dump(struct instance *i, const char *buf, size_t size); +} + +The other piece that'll have to be modified is how the devices are tracked. +It'll be necessary to introduce a linked list of devices within the FPGA core +instead of tracking them by ID number. + +Next, the "Xilinx_desc", "Lattice_desc" and "Altera_desc" structures will have +to be moved to driver's private_data. Finally, structures passed from the board +and/or platform files, like "Xilinx_Virtex2_Slave_SelectMap_fns" would be passed +via platform_data to the driver. + +III) Analysis of in-tree drivers +-------------------------------- + +  1) Altera driver +  ---------------- +  The driver is realized using the following files: + +    drivers/fpga/altera.c +    drivers/fpga/ACEX1K.c +    drivers/fpga/cyclon2.c +    drivers/fpga/stratixII.c + +  All of the sub-drivers implement basically the same info-load-dump interface +  and there's no expected problem during the conversion. The driver itself will +  be realised by altera.c and all the sub-drivers will be linked in. The +  distinction will be done by passing different platform data. + +  2) Lattice driver +  ----------------- +  The driver is realized using the following files: + +    drivers/fpga/lattice.c +    drivers/fpga/ivm_core.c + +  This driver also implements the standard interface, but to realise the +  operations with the FPGA device, uses functions from "ivm_core.c" file. This +  file implements the main communications logic and has to be linked in together +  with "lattice.c". No problem converting is expected here. + +  3) Xilinx driver +  ---------------- +  The driver is realized using the following files: + +    drivers/fpga/xilinx.c +    drivers/fpga/spartan2.c +    drivers/fpga/spartan3.c +    drivers/fpga/virtex2.c + +  This set of sub-drivers is special by defining a big set of macros in +  "include/spartan3.h" and similar files. These macros would need to be either +  rewritten or replaced. Otherwise, there are no problems expected during the +  conversion process. diff --git a/doc/driver-model/UDM-keyboard.txt b/doc/driver-model/UDM-keyboard.txt new file mode 100644 index 000000000..ef3761dc2 --- /dev/null +++ b/doc/driver-model/UDM-keyboard.txt @@ -0,0 +1,47 @@ +The U-Boot Driver Model Project +=============================== +Keyboard input analysis +======================= +Marek Vasut <marek.vasut@gmail.com> +2012-02-20 + +I) Overview +----------- + +The keyboard drivers are most often registered with STDIO subsystem. There are +components of the keyboard drivers though, which operate in severe ad-hoc +manner, often being related to interrupt-driven keypress reception. This +components will require the most sanitization of all parts of keyboard input +subsystem. + +Otherwise, the keyboard is no different from other standard input but with the +necessity to decode scancodes. These are decoded using tables provided by +keyboard drivers. These tables are often driver specific. + +II) Approach +------------ + +The most problematic part is the interrupt driven keypress reception. For this, +the buffers that are currently shared throughout the whole U-Boot would need to +be converted into driver's private data. + +III) Analysis of in-tree drivers +-------------------------------- + +  1) board/mpl/common/kbd.c +  ------------------------- +  This driver is a classic STDIO driver, no problem with conversion is expected. +  Only necessary change will be to move this driver to a proper location. + +  2) board/rbc823/kbd.c +  --------------------- +  This driver is a classic STDIO driver, no problem with conversion is expected. +  Only necessary change will be to move this driver to a proper location. + +  3) drivers/input/keyboard.c +  --------------------------- +  This driver is special in many ways. Firstly because this is a universal stub +  driver for converting scancodes from i8042 and the likes. Secondly because the +  buffer is filled by various other ad-hoc implementations of keyboard input by +  using this buffer as an extern. This will need to be fixed by allowing drivers +  to pass certain routines to this driver via platform data. diff --git a/doc/driver-model/UDM-serial.txt b/doc/driver-model/UDM-serial.txt new file mode 100644 index 000000000..e9c274d45 --- /dev/null +++ b/doc/driver-model/UDM-serial.txt @@ -0,0 +1,191 @@ +The U-Boot Driver Model Project +=============================== +Serial I/O analysis +=================== +Marek Vasut <marek.vasut@gmail.com> +2012-02-20 + +I) Overview +----------- + +The serial port support currently requires the driver to export the following +functions: + +  serial_putc() ...... Output a character +  serial_puts() ...... Output string, often done using serial_putc() +  serial_tstc() ...... Test if incoming character is in a buffer +  serial_getc() ...... Retrieve incoming character +  serial_setbrg() .... Configure port options +  serial_init() ...... Initialize the hardware + +The simpliest implementation, supporting only one port, simply defines these six +functions and calls them. Such calls are scattered all around U-Boot, especiall +serial_putc(), serial_puts(), serial_tstc() and serial_getc(). The serial_init() +and serial_setbrg() are often called from platform-dependent places. + +It's important to consider current implementation of CONFIG_SERIAL_MULTI though. +This resides in common/serial.c and behaves as a multiplexer for serial ports. +This, by calling serial_assign(), allows user to switch I/O from one serial port +to another. Though the environmental variables "stdin", "stdout", "stderr" +remain set to "serial". + +These variables are managed by the IOMUX. This resides in common/iomux.c and +manages all console input/output from U-Boot. For serial port, only one IOMUX is +always registered, called "serial" and the switching of different serial ports +is done by code in common/serial.c. + +On a final note, it's important to mention function default_serial_console(), +which is platform specific and reports the default serial console for the +platform, unless proper environment variable overrides this. + +II) Approach +------------ + +Drivers not using CONFIG_SERIAL_MULTI already will have to be converted to +similar approach. The probe() function of a driver will call a function +registering the driver with a STDIO subsystem core, stdio_device_register(). + +The serial_init() function will now be replaced by probe() function of the +driver, the rest of the components of the driver will be converted to standard +STDIO driver calls. See [ UDM-stdio.txt ] for details. + +The serial_setbrg() function depends on global data pointer. This is wrong, +since there is likely to be user willing to configure different baudrate on two +different serial ports. The function will be replaced with STDIO's "conf()" +call, with STDIO_CONFIG_SERIAL_BAUDRATE argument. + +III) Analysis of in-tree drivers +-------------------------------- + +  1) altera_jtag_uart.c +  --------------------- +  No support for CONFIG_SERIAL_MULTI. Simple conversion possible. + +  2) altera_uart.c +  ---------------- +  No support for CONFIG_SERIAL_MULTI. Simple conversion possible. + +  3) arm_dcc.c +  ------------ +  No support for CONFIG_SERIAL_MULTI. Simple conversion possible, unless used +  with CONFIG_ARM_DCC_MULTI. Then it registers another separate IOMUX. + +  4) atmel_usart.c +  ---------------- +  No support for CONFIG_SERIAL_MULTI. Simple conversion possible. + +  5) mcfuart.c +  ------------ +  No support for CONFIG_SERIAL_MULTI. Simple conversion possible. + +  6) ns16550.c +  ------------ +  This driver seems complicated and certain consideration will need to be made +  during conversion. This driver is implemented in very universal manner, +  therefore it'll be necessary to properly design it's platform_data. + +  7) ns9750_serial.c +  ------------------ +  No support for CONFIG_SERIAL_MULTI. Simple conversion possible. + +  8) opencores_yanu.c +  ------------------- +  No support for CONFIG_SERIAL_MULTI. Simple conversion possible. + +  9) s3c4510b_uart.c +  ------------------ +  No support for CONFIG_SERIAL_MULTI. Simple conversion possible. + +  10) s3c64xx.c +  ------------- +  No support for CONFIG_SERIAL_MULTI. Simple conversion possible. + +  11) sandbox.c +  ------------- +  No support for CONFIG_SERIAL_MULTI. Simple conversion possible. + +  12) serial.c +  ------------ +  This is a complementary part of NS16550 UART driver, see above. + +  13) serial_clps7111.c +  --------------------- +  No support for CONFIG_SERIAL_MULTI. Simple conversion possible. + +  14) serial_imx.c +  ---------------- +  No support for CONFIG_SERIAL_MULTI. Simple conversion possible. This driver +  might be removed in favor of serial_mxc.c . + +  15) serial_ixp.c +  ---------------- +  No support for CONFIG_SERIAL_MULTI. Simple conversion possible. + +  16) serial_ks8695.c +  ------------------- +  No support for CONFIG_SERIAL_MULTI. Simple conversion possible. + +  17) serial_lh7a40x.c +  -------------------- +  No support for CONFIG_SERIAL_MULTI. Simple conversion possible. + +  18) serial_lpc2292.c +  -------------------- +  No support for CONFIG_SERIAL_MULTI. Simple conversion possible. + +  19) serial_max3100.c +  -------------------- +  No support for CONFIG_SERIAL_MULTI. Simple conversion possible. + +  20) serial_mxc.c +  ---------------- +  No support for CONFIG_SERIAL_MULTI. Simple conversion possible. + +  21) serial_netarm.c +  ------------------- +  No support for CONFIG_SERIAL_MULTI. Simple conversion possible. + +  22) serial_pl01x.c +  ------------------ +  No support for CONFIG_SERIAL_MULTI. Simple conversion possible, though this +  driver in fact contains two drivers in total. + +  23) serial_pxa.c +  ---------------- +  This driver is a bit complicated, but due to clean support for +  CONFIG_SERIAL_MULTI, there are no expected obstructions throughout the +  conversion process. + +  24) serial_s3c24x0.c +  -------------------- +  This driver, being quite ad-hoc might need some work to bring back to shape. + +  25) serial_s3c44b0.c +  -------------------- +  No support for CONFIG_SERIAL_MULTI. Simple conversion possible. + +  26) serial_s5p.c +  ---------------- +  No support for CONFIG_SERIAL_MULTI. Simple conversion possible. + +  27) serial_sa1100.c +  ------------------- +  No support for CONFIG_SERIAL_MULTI. Simple conversion possible. + +  28) serial_sh.c +  --------------- +  No support for CONFIG_SERIAL_MULTI. Simple conversion possible. + +  29) serial_xuartlite.c +  ---------------------- +  No support for CONFIG_SERIAL_MULTI. Simple conversion possible. + +  30) usbtty.c +  ------------ +  This driver seems very complicated and entangled with USB framework. The +  conversion might be complicated here. + +  31) arch/powerpc/cpu/mpc512x/serial.c +  ------------------------------------- +  This driver supports CONFIG_SERIAL_MULTI. This driver will need to be moved to +  proper place. diff --git a/doc/driver-model/UDM-stdio.txt b/doc/driver-model/UDM-stdio.txt new file mode 100644 index 000000000..a6c484f37 --- /dev/null +++ b/doc/driver-model/UDM-stdio.txt @@ -0,0 +1,191 @@ +The U-Boot Driver Model Project +=============================== +I/O system analysis +=================== +Marek Vasut <marek.vasut@gmail.com> +2012-02-20 + +I) Overview +----------- + +The console input and output is currently done using the STDIO subsystem in +U-Boot. The design of this subsystem is already flexible enough to be easily +converted to new driver model approach. Minor changes will need to be done +though. + +Each device that wants to register with STDIO subsystem has to define struct +stdio_dev, defined in include/stdio_dev.h and containing the following fields: + +struct stdio_dev { +        int     flags;                  /* Device flags: input/output/system */ +        int     ext;                    /* Supported extensions              */ +        char    name[16];               /* Device name                       */ + +/* GENERAL functions */ + +        int (*start) (void);            /* To start the device               */ +        int (*stop) (void);             /* To stop the device                */ + +/* OUTPUT functions */ + +        void (*putc) (const char c);    /* To put a char                     */ +        void (*puts) (const char *s);   /* To put a string (accelerator)     */ + +/* INPUT functions */ + +        int (*tstc) (void);             /* To test if a char is ready...     */ +        int (*getc) (void);             /* To get that char                  */ + +/* Other functions */ + +        void *priv;                     /* Private extensions                */ +        struct list_head list; +}; + +Currently used flags are DEV_FLAGS_INPUT, DEV_FLAGS_OUTPUT and DEV_FLAGS_SYSTEM, +extensions being only one, the DEV_EXT_VIDEO. + +The private extensions are now used as a per-device carrier of private data and +finally list allows this structure to be a member of linked list of STDIO +devices. + +The STDIN, STDOUT and STDERR routing is handled by environment variables +"stdin", "stdout" and "stderr". By configuring the variable to the name of a +driver, functions of such driver are called to execute that particular +operation. + +II) Approach +------------ + +  1) Similarity of serial, video and keyboard drivers +  --------------------------------------------------- + +  All of these drivers can be unified under the STDIO subsystem if modified +  slightly. The serial drivers basically define both input and output functions +  and need function to configure baudrate. The keyboard drivers provide only +  input. On the other hand, video drivers provide output, but need to be +  configured in certain way. This configuration might be dynamic, therefore the +  STDIO has to be modified to provide such flexibility. + +  2) Unification of serial, video and keyboard drivers +  ---------------------------------------------------- + +  Every STDIO device would register a structure containing operation it supports +  with the STDIO core by calling: + +    int stdio_device_register(struct instance *i, struct stdio_device_ops *o); + +  The structure being defined as follows: + +  struct stdio_device_ops { +    void (*putc)(struct instance *i, const char c); +    void (*puts)(struct instance *i, const char *s);    /* OPTIONAL */ + +    int  (*tstc)(struct instance *i); +    int  (*getc)(struct instance *i); + +    int  (*init)(struct instance *i); +    int  (*exit)(struct instance *i); +    int  (*conf)(struct instance *i, enum stdio_config c, const void *data); +  }; + +  The "putc()" function will emit a character, the "puts()" function will emit a +  string. If both of these are set to NULL, the device is considered STDIN only, +  aka input only device. + +  The "getc()" retrieves a character from a STDIN device, while "tstc()" tests +  if there is a character in the buffer of STDIN device. In case these two are +  set to NULL, this device is STDOUT / STDERR device. + +  Setting all "putc()", "puts()", "getc()" and "tstc()" calls to NULL isn't an +  error condition, though such device does nothing. By instroducing tests for +  these functions being NULL, the "flags" and "ext" fields from original struct +  stdio_dev can be eliminated. + +  The "init()" and "exit()" calls are replacement for "start()" and "exit()" +  calls in the old approach. The "priv" part of the old struct stdio_dev will be +  replaced by common private data in the driver model and the struct list_head +  list will be eliminated by introducing common STDIO core, that tracks all the +  STDIO devices. + +  Lastly, the "conf()" call will allow the user to configure various options of +  the driver. The enum stdio_config contains all possible configuration options +  available to the STDIO devices, const void *data being the argument to be +  configured. Currently, the enum stdio_config will contain at least the +  following options: + +  enum stdio_config { +    STDIO_CONFIG_SERIAL_BAUDRATE, +  }; + +  3) Transformation of stdio routing +  ---------------------------------- + +  By allowing multiple instances of drivers, the environment variables "stdin", +  "stdout" and "stderr" can no longer be set to the name of the driver. +  Therefore the STDIO core, tracking all of the STDIO devices in the system will +  need to have a small amount of internal data for each device: + +  struct stdio_device_node { +    struct instance          *i; +    struct stdio_device_ops  *ops; +    uint8_t                  id; +    uint8_t                  flags; +    struct list_head         list; +  } + +  The "id" is the order of the instance of the same driver. The "flags" variable +  allows multiple drivers to be used at the same time and even for different +  purpose. The following flags will be defined: + +    STDIO_FLG_STDIN ..... This device will be used as an input device. All input +                          from all devices with this flag set will be received +			  and passed to the upper layers. +    STDIO_FLG_STDOUT .... This device will be used as an output device. All +                          output sent to stdout will be routed to all devices +			  with this flag set. +    STDIO_FLG_STDERR .... This device will be used as an standard error output +                          device. All output sent to stderr will be routed to +			  all devices with this flag set. + +  The "list" member of this structure allows to have a linked list of all +  registered STDIO devices. + +III) Analysis of in-tree drivers +-------------------------------- + +For in-depth analysis of serial port drivers, refer to [ UDM-serial.txt ]. +For in-depth analysis of keyboard drivers, refer to [ UDM-keyboard.txt ]. +For in-depth analysis of video drivers, refer to [ UDM-video.txt ]. + +  1) arch/blackfin/cpu/jtag-console.c +  ----------------------------------- +  This driver is a classic STDIO driver, no problem with conversion is expected. + +  2) board/mpl/pati/pati.c +  ------------------------ +  This driver registers with the STDIO framework, though it uses a lot of ad-hoc +  stuff which will need to be sorted out. + +  3) board/netphone/phone_console.c +  --------------------------------- +  This driver is a classic STDIO driver, no problem with conversion is expected. + +  4) drivers/net/netconsole.c +  --------------------------- +  This driver is a classic STDIO driver, no problem with conversion is expected. + +IV) Other involved files (To be removed) +---------------------------------------- + +common/cmd_console.c +common/cmd_log.c +common/cmd_terminal.c +common/console.c +common/fdt_support.c +common/iomux.c +common/lcd.c +common/serial.c +common/stdio.c +common/usb_kbd.c +doc/README.iomux diff --git a/doc/driver-model/UDM-tpm.txt b/doc/driver-model/UDM-tpm.txt new file mode 100644 index 000000000..91a953a72 --- /dev/null +++ b/doc/driver-model/UDM-tpm.txt @@ -0,0 +1,48 @@ +The U-Boot Driver Model Project +=============================== +TPM system analysis +=================== +Marek Vasut <marek.vasut@gmail.com> +2012-02-23 + +I) Overview +----------- + +There is currently only one TPM chip driver available and therefore the API +controlling it is very much based on this. The API is very simple: + +  int tis_open(void); +  int tis_close(void); +  int tis_sendrecv(const u8 *sendbuf, size_t send_size, +                         u8 *recvbuf, size_t *recv_len); + +The command operating the TPM chip only provides operations to send and receive +bytes from the chip. + +II) Approach +------------ + +The API can't be generalised too much considering there's only one TPM chip +supported. But it's a good idea to split the tis_sendrecv() function in two +functions. Therefore the new API will use register the TPM chip by calling: + +  tpm_device_register(struct instance *i, const struct tpm_ops *ops); + +And the struct tpm_ops will contain the following members: + +  struct tpm_ops { +    int (*tpm_open)(struct instance *i); +    int (*tpm_close)(struct instance *i); +    int (*tpm_send)(const uint8_t *buf, const size_t size); +    int (*tpm_recv)(uint8_t *buf, size_t *size); +  }; + +The behaviour of "tpm_open()" and "tpm_close()" will basically copy the +behaviour of "tis_open()" and "tis_close()". The "tpm_send()" will be based on +the "tis_senddata()" and "tis_recv()" will be based on "tis_readresponse()". + +III) Analysis of in-tree drivers +-------------------------------- + +There is only one in-tree driver present, the "drivers/tpm/generic_lpc_tpm.c", +which will be simply converted as outlined in previous chapter. diff --git a/doc/driver-model/UDM-usb.txt b/doc/driver-model/UDM-usb.txt new file mode 100644 index 000000000..5ce85b5d6 --- /dev/null +++ b/doc/driver-model/UDM-usb.txt @@ -0,0 +1,94 @@ +The U-Boot Driver Model Project +=============================== +USB analysis +============ +Marek Vasut <marek.vasut@gmail.com> +2012-02-16 + +I) Overview +----------- + +  1) The USB Host driver +  ---------------------- +  There are basically four or five USB host drivers. All such drivers currently +  provide at least the following fuctions: + +    usb_lowlevel_init() ... Do the initialization of the USB controller hardware +    usb_lowlevel_stop() ... Do the shutdown of the USB controller hardware + +    usb_event_poll() ...... Poll interrupt from USB device, often used by KBD + +    submit_control_msg() .. Submit message via Control endpoint +    submit_int_msg() ...... Submit message via Interrupt endpoint +    submit_bulk_msg() ..... Submit message via Bulk endpoint + + +    This allows for the host driver to be easily abstracted. + +  2) The USB hierarchy +  -------------------- + +  In the current implementation, the USB Host driver provides operations to +  communicate via the USB bus. This is realised by providing access to a USB +  root port to which an USB root hub is attached. The USB bus is scanned and for +  each newly found device, a struct usb_device is allocated. See common/usb.c +  and include/usb.h for details. + +II) Approach +------------ + +  1) The USB Host driver +  ---------------------- + +  Converting the host driver will follow the classic driver model consideration. +  Though, the host driver will have to call a function that registers a root +  port with the USB core in it's probe() function, let's call this function + +    usb_register_root_port(&ops); + +  This will allow the USB core to track all available root ports. The ops +  parameter will contain structure describing operations supported by the root +  port: + +  struct usb_port_ops { +    void   (*usb_event_poll)(); +    int    (*submit_control_msg)(); +    int    (*submit_int_msg)(); +    int    (*submit_bulk_msg)(); +  } + +  2) The USB hierarchy and hub drivers +  ------------------------------------ + +  Converting the USB heirarchy should be fairy simple, considering the already +  dynamic nature of the implementation. The current usb_hub_device structure +  will have to be converted to a struct instance. Every such instance will +  contain components of struct usb_device and struct usb_hub_device in it's +  private data, providing only accessors in order to properly encapsulate the +  driver. + +  By registering the root port, the USB framework will instantiate a USB hub +  driver, which is always present, the root hub. The root hub and any subsequent +  hub instance is represented by struct instance and it's private data contain +  amongst others common bits from struct usb_device. + +  Note the USB hub driver is partly defying the usual method of registering a +  set of callbacks to a particular core driver. Instead, a static set of +  functions is defined and the USB hub instance is passed to those. This creates +  certain restrictions as of how the USB hub driver looks, but considering the +  specification for USB hub is given and a different type of USB hub won't ever +  exist, this approach is ok: + +  - Report how many ports does this hub have: +      uint get_nr_ports(struct instance *hub); +  - Get pointer to device connected to a port: +      struct instance *(*get_child)(struct instance *hub, int port); +  - Instantiate and configure device on port: +      struct instance *(*enum_dev_on_port)(struct instance *hub, int port); + +  3) USB device drivers +  --------------------- + +  The USB device driver, in turn, will have to register various ops structures +  with certain cores. For example, USB disc driver will have to register it's +  ops with core handling USB discs etc. diff --git a/doc/driver-model/UDM-video.txt b/doc/driver-model/UDM-video.txt new file mode 100644 index 000000000..342aeee48 --- /dev/null +++ b/doc/driver-model/UDM-video.txt @@ -0,0 +1,74 @@ +The U-Boot Driver Model Project +=============================== +Video output analysis +===================== +Marek Vasut <marek.vasut@gmail.com> +2012-02-20 + +I) Overview +----------- + +The video drivers are most often registered with video subsystem. This subsystem +often expects to be allowed access to framebuffer of certain parameters. This +subsystem also provides calls for STDIO subsystem to allow it to output +characters on the screen. For this part, see [ UDM-stdio.txt ]. + +Therefore the API has two parts, the video driver part and the part where the +video driver core registers with STDIO API. + +The video driver part will follow the current cfb_console approach, though +allowing it to be more dynamic. + +II) Approach +------------ + +Registering the video driver into the video driver core is done by calling the +following function from the driver probe() function: + +  video_device_register(struct instance *i, GraphicDevice *gd); + +Because the video driver core is in charge or rendering characters as well as +bitmaps on the screen, it will in turn call stdio_device_register(i, so), where +"i" is the same instance as the video driver's one. But "so" will be special +static struct stdio_device_ops handling the character output. + + +III) Analysis of in-tree drivers +-------------------------------- + +  1) arch/powerpc/cpu/mpc8xx/video.c +  ---------------------------------- +  This driver copies the cfb_console [ see drivers/video/cfb_console.c ] +  approach and acts only as a STDIO device. Therefore there are currently two +  possible approaches, first being the conversion of this driver to usual STDIO +  device and second, long-term one, being conversion of this driver to video +  driver that provides console. + +  2) arch/x86/lib/video.c +  ----------------------- +  This driver registers two separate STDIO devices and should be therefore +  converted as such. + +  3) board/bf527-ezkit/video.c +  ---------------------------- +  This driver seems bogus as it behaves as STDIO device, but provides no input +  or output capabilities. It relies on DEV_EXT_VIDEO, which is no longer in use +  or present otherwise than as a dead code/define. + +  4) board/bf533-stamp/video.c +  ---------------------------- +  This driver seems bogus as it behaves as STDIO device, but provides no input +  or output capabilities. It relies on DEV_EXT_VIDEO, which is no longer in use +  or present otherwise than as a dead code/define. + +  5) board/bf548-ezkit/video.c +  ---------------------------- +  This driver seems bogus as it behaves as STDIO device, but provides no input +  or output capabilities. It relies on DEV_EXT_VIDEO, which is no longer in use +  or present otherwise than as a dead code/define. + +  6) board/cm-bf548/video.c +  ---------------------------- +  This driver seems bogus as it behaves as STDIO device, but provides no input +  or output capabilities. It relies on DEV_EXT_VIDEO, which is no longer in use +  or present otherwise than as a dead code/define. |