diff --git a/Documentation/devices_drivers.txt b/Documentation/devices_drivers.txt new file mode 100644 index 0000000..5a95c91 --- /dev/null +++ b/Documentation/devices_drivers.txt @@ -0,0 +1,79 @@ + +---------- Devices and drivers in U-Boot -------------- + +We follow a rather simplistic driver model here. There is a struct device which +describes a particular device present in the system. A struct driver represents +a driver present in the system. Both structs find together via the members +'type' (int) and 'name' (char *). If both members match, the driver's probe +function is called with the struct device as argument. People familiar with +the Linux platform bus will recognize this behaviour and in fact many things were +stolen from there. Some selected members of the structs will be described in this +document. +Currently all devices and drivers are handled in simple linked lists. When it comes +to USB or PCI it may be desirable to have a tree structure, but this may also be +unnecessary overhead. + +struct device +------------- + +char name[MAX_DRIVER_NAME]; + +This member (and 'type' described below) is used to match with a driver. This is +a descriptive name and could be MPC5XXX_ether or imx_serial. + +char id[MAX_DRIVER_NAME]; + +The id is used to uniquely identify a device in the system. The id will show up +under /dev/ as the device's name. Usually this is something like eth0 or nor0. + +unsigned long type; + +This describes the type (or class) of this device. Have a look at include/driver.h +to see a list of known device types. Currently this includes DEVICE_TYPE_ETHER, +DEVICE_TYPE_CONSOLE and others. + +void *type_data; + +Devices of a particular class normaly need to store more information than struct +device holds. This entry holds a pointer to the type specific struct, so a +a device of type DEVICE_TYPE_ETHER sets this to a struct eth_device. + +void *priv; + +Used by the device driver to store private information. + +void *platform_data; + +This is used to carry information of board specific data from the board code to the +device driver. + +struct param_d *param; + +The parameters for this device. See Documentation/parameters.txt for more info. + +struct driver_d +--------------- + +char name[MAX_DRIVER_NAME]; +unsigned long type; + +See above. + +int (*probe) (struct device_d *); +int (*remove)(struct device_d *); + +These are called if a instance of a device is found or gone. + +ssize_t (*read) (struct device_d*, void* buf, size_t count, ulong offset, ulong flags); +ssize_t (*write) (struct device_d*, const void* buf, size_t count, ulong offset, ulong flags); + +The standard read/write functions. These are called as a response to the read/write +system calls. No driver needs to implement these. + +void *type_data; + +This is somewhat redundant with the type data in struct device. Currently the +filesystem implementation uses this field while ethernet drivers use the same +field in struct device. Probably one of both should be removed. + + diff --git a/Documentation/parameters.txt b/Documentation/parameters.txt new file mode 100644 index 0000000..219440b --- /dev/null +++ b/Documentation/parameters.txt @@ -0,0 +1,52 @@ +---------- Device parameters -------------- + +Devices have several parameters. In case of a network device this may be the +ip address, networking mask or similar and users need access to these +parameters. in U-Boot this is solved with device paramters. Device parameters +are always strings, although there are functions to interpret them as +something else. hush users can access parameters as a local variable which +have a dot (.) in them. So setting the ip address of the first ethernet +device is a matter of typing 'eth0.ip=192.168.0.7' on the console and can +then be read back with 'echo $eth0.ip'. The devinfo command shows a summary +about all devices currently present. If called with a device id as parameter +it shows the parameters available for a device. + +Device parameters programming API +--------------------------------- + +struct param_d { + char* (*get)(struct device_d *, struct param_d *param); + int (*set)(struct device_d *, struct param_d *param, const char *val); + ulong flags; + char *name; + struct param_d *next; + char *value; +}; + +int dev_add_param(struct device_d *dev, struct param_d *par); + +This function adds a new parameter to a device. At least the name field in +the new parameter struct has to be initialized. The 'get' and 'set' fields +can be set to NULL in which case the framework handles them. It is also +allowed to implement only one of the get/set functions. Care must be taken +with the initial value of the parameter. If the framework handles the set +function it will try to free the value of the parameter. If this is a +static array bad things will happen. A parameter can have the flag +PARAM_FLAG_RO which means that the parameter is readonly. It is perfectly ok +then to point value to a static array. + +const char *dev_get_param(struct device_d *dev, const char *name); + +This function returns a pointer to the value of the parameter specified +with dev and name. +If the framework handles the get/set functions the parameter value strings +are alloceted with malloc and freed with free when another value is set for +this parameter. Drivers implementing set/get themselves are allowed to +return values in static arrays. This means that the pointers returned from +dev_get_param() are only valid until the next call to dev_get_param. If this +is not long enough strdup() or similar must be used. + +int dev_set_param(struct device_d *dev, const char *name, const char *val); + +Set the value of a parameter. + diff --git a/Documentation/porting.txt b/Documentation/porting.txt new file mode 100644 index 0000000..167a11c --- /dev/null +++ b/Documentation/porting.txt @@ -0,0 +1,106 @@ + +When porting from old U-Boot the follwing steps must be taken (please complain +if there's something missing here ;) + + +- Most of the macros in include/configs/yourboard.h can be removed, espacially + the CONFIG_COMMANDS section. The goal is to remove this file entirely, but + for now some values are still needed here. If you think some things are better + configured with the Kconfig system feel free to add them there. + +- The linker script needs a new section for the initcalls. The handling of the + U-Boot command table has changed also (The commands are now sorted by the + linker instead in runtime). To change it you need an entry like the following + in your linker script: + +#include + + __u_boot_cmd_start = .; + .u_boot_cmd : { U_BOOT_CMDS } + __u_boot_cmd_end = .; + + __u_boot_initcalls_start = .; + .u_boot_initcalls : { INITCALLS } + __u_boot_initcalls_end = .; + +- Rename your linker script to u-boot.lds.S and add the following entry to the + Makefile to make sure the linker script is generated: + +extra-y += u-boot.lds + +- Register the devices present in your system in the board specific .c file. + To see anything you at least have to register a console. In scb9328.c this + looks like this: + +static struct device_d scb9328_serial_device = { + .name = "imx_serial", + .id = "cs0", + .map_base = IMX_UART1_BASE, + .size = 4096, + .type = DEVICE_TYPE_CONSOLE, +}; + +static int scb9328_console_init(void) +{ + register_device(&scb9328_serial_device); + return 0; +} + +- For most boards you will have to register a cfi_flash device. NAND flash + is not ported yet. + +- Call dev_add_partition() to add an environment partition for your device: + dev_add_partition(&cfi_dev, 0x40000, 0x20000, "env"); + This will add an area starting at 0x40000 of size 0x20000 of the device + cfi_dev as env0. + +console_initcall(scb9328_console_init); + +- Port missing drivers. Depending on the driver this can a be rather simple + process: + + Serial drivers + - Declare all functions static. + - register a device of type DEVICE_TYPE_CONSOLE + - in your probe function fill in a struct console_device and register it + with console_register() + + Ethernet drivers + - Basically do the same as with serial drivers. + - Identify the parts of the driver which handle the MAC address. There are + now two fields in struct eth_device. get_mac_address() shall retrieve the + MAC address from the EEPROM if one is connected. If you don't have an + EEPROM just return -1. set_mac_address() shall set the MAC address in + the device. All magic previously done with getenv/setenv(ethaddr) must be + removed. + +- Add a clocksource for your system. PowerPCs have a generic decrementer + counter, so if you have a PowerPC aou have nothing to do here. on ARM + this is SoC dependend. See Documentation/timekeeping.txt for further + information. + +- Adjust start.S. These files share a lot of common code, so they should be + reworked in general. On Arm you have to fix CFG_MALLOC_LEN. Most start.S + under cpu/arm* do a "sub r0, r0, #CFG_MALLOC_LEN". If you increase + the malloc space the value CFG_MALLOC_LEN does not fit into the instruction. + See cpu/arm920t/start.S how it is done. + On PowerpC there is at least the Problem that the relocation offset is + defined at compile time. It is easily possible to determine the address + U-Boot is currently starting from at runtime and thus allowing it U-Boot + to be started at any address. Look at the relocation code and replace + TEXT_BASE with the following calculation of the runtime address: + + bl calc_source /* Calculate Source Address */ +calc_source: + mfspr r4, LR + subi r4, r4, (calc_source - _start) + subi r4, r4, 0x100 + + (I'm almost sure that PowerPC has a dedicated instruction for this, un- + fortunately I know next to nothing of PowerPC assembler) + + U-Boot runs now from the address it was linked to, so on PowerPC you have + to adjust TEXT_BASE to be in RAM. This makes the various fixup functions + unnecessary. It also simplifies debugging because you will see the + correct addresses in the objdump. + diff --git a/Documentation/timekeeping.txt b/Documentation/timekeeping.txt new file mode 100644 index 0000000..9d77811 --- /dev/null +++ b/Documentation/timekeeping.txt @@ -0,0 +1,13 @@ +------------ U-Boot timekeeping ------------- + +In U-Boot we use the clocksource mechanism from the Linux Kernel. This makes +it fairly easy to add timer functionality for a new board or architecture. +Apart from initialization there is only one function required: +clocksource_read(). This function returns the current value of a free running +counter. Other functions like udelay() and get_time_ns() are derived from this +function. The only thing you have to implement is a clocksource driver. See +cpu/arm920t/imx/interrupts.c for an example. clocksource drivers from the +Linux Kernel can be used nearly 1:1, except for the register accesses. + +for clocksources the __lshrdi3 symbol is needed. You can find the function for +your architecture in the Linux Kernel or a libc of your choice.