dm: Initial import of design documents

This patch contains UDM-design.txt, which is document containing
general description of the driver model. The remaining files contains
descriptions of conversion process of particular subsystems.

Signed-off-by: Marek Vasut <marek.vasut@gmail.com>
This commit is contained in:
Marek Vasut 2012-08-08 01:42:17 +00:00 committed by Wolfgang Denk
parent c20dbf64a9
commit 15c6935b0c
8 changed files with 1075 additions and 0 deletions

View File

@ -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

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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

View File

@ -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.

View File

@ -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.

View File

@ -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.