Board support framework
Introduction
In the past, there's been a confusion, or merging, of support for the SoC and for the board. This resulted from the developers making for a single board. While this worked for the initial development, it acts as a barrier to entry for additional boards for the same SoC. In addition, there's a number of interrelated CPU families that make up a number of different SoC implementations as vendors glue their CPU core technology together with many different configurations.
Proposed Solution
The AT91 subport has moved to using the proposed solution. In this table, we're porting to board foo.
File Name |
Change |
Contents |
arm/at91/kb920x_machdep.c |
Rename to at91_machdep.c |
Contains arminit(), support routines and variables, as well as new at91_ramsize() (more generally, any common routines needed by the board routines) |
arm/conf/FOO |
New |
Sample config file for a foo board. This lists the devices that are on the board, as well as the optional parts of FreeBSD that are used by the author of this config file for their application. Constants that are the same for all versions of the foo board aren't listed here. |
arm/at91/std.foo |
New |
Lists all the constants needed for the board. Also brings the board into the build with the line 'device at91_board_foo'. As of this writing, only one board is compiled at a time. |
arm/at91/files.at91 |
Change |
Add a line mapping at91_board_foo into the system. 'arm/at91/board_foo.c optional at91_board_foo' is the typical way. |
arm/at91/board_foo.c |
New |
Contains the board_init() routine for this board. This routine is responsible for tweaking the enabled devices/GPIO pints for this board. Typically, the boot loader will configure these, but often times it is necessary to do that here when the boot loader doesn't. It is rare that NO tweaks will be needed at all. In addition to tweaking the configured devices, this routine would be responsible for communicating things like the MAC address, if the SD connector has all 4 wires, what the GPIO lines are for this or that function to the common SoC init code. |
arm/at91/at91boards.h |
New |
Contains a list of common routines defined in at91_machdep.c that board init routines can use, as well as a list of functions that a board must implement. Currently, it is only board_init() that must be defined by the board routines. |
std.foo
#$FreeBSD: head/sys/arm/at91/std.foo 185307 2008-11-25 19:05:46Z imp $ include "../at91/std.at91" options STARTUP_PAGETABLE_ADDR=0x20800000 makeoptions KERNPHYSADDR=0x20000000 options KERNPHYSADDR=0x20000000 makeoptions KERNVIRTADDR=0xc0000000 options KERNVIRTADDR=0xc0000000 device at91_board_foo
board_foo.c
long board_init(void) { /* Boot loader configures everything we need */ return (at91_ramsize()); }
Future Ideas
MultiBoard support
In the future, I'd like to modify at91boards.h such that it can build one board, or support for multiple boards. There's a boot-loader supplied thing that will allow the early boot code to select the right one.
Reorg of arminit and how we drive initialization
In the future, I'd like there to be more sharing between the arminit routines.
I'm also thinking that we need to have each board provide its own init routine that drives the configuration process:
long board_init(void) { /* Setup data structures for SoC code to do its thing */ at91rm9200_soc_init(<params>); /* Tweak the peripheral lines, etc */ }
In this scenario, arminit would be per boot loader. The boot loader would pass in the board type, somehow, and would then establish the board_init routine to call. Chances are there'd be a table of function pointers here (since kobj doesn't work too well in the extreme early boot process) and board_init would be but one thing. There's also a desire to have broad ranges of boards be supported by one board_init() function, with the differences between them being spelled out via hints (see below for one way to beef up hints to help out). Ideally, everybody would use /boot/loader, but that's not really possible in the embedded space, since the logistics of reading in a kernel w/o support from uboot/redboot may prove to be too difficult to overcome. Having a different arminit per boot loader (or maybe one uber one that would be able to know which boot loader was used) would simplify porting as well. Of course, then arminit would just devolve into a simple routine that figured out the meta data from the bootloader, and made the appropriate calls to do the initialization.
The down side of moving all initialization into a board specific routine is that we'd still be duplicating a bunch of code. The code is rock simple, however, so maybe that won't be a big deal. Time will tell if we run into these issues.
Flattened Device Tree
There's also a desire to have some way to specify most of the hardware via a config file that's interpreted at run time. The flattened device tree that Linux's PowerPC port uses has a number of very desirable traits. First, uboot supports passing in a compiled version of this file into the tree for boards that don't support full OpenFirmware. Second, it represents a number of overlaid relationships between different nodes in a device tree. Third, most board vendors that support linux have started producing these files. Our barrier to entry would also be lowered if we could use them.
The interesting thing about the FDTs is that they encode non-heirarchical relationships between devices, as are often found when GPIOs are used for interrupts, when interrupt controllers are wired externally to the bus hierarchy, etc. They also can encode things like the wiring of the different elements of a sound/video subsystem, which might have different relationships still than the bus hierarchy.
Multiple Boot Loader Support
We need to support multiple boot loaders for the at91 family. Linux defines a standard boot environment for the ARM. We should just use that, since that's what all boot loaders for arm on Linux do. Not sure what other arm subports use, or what the /boot/loader interface is... If they all were the same, we could use the same support code everywhere.
Multiple CPU Families
When we go to add support for another CPU family, some additional reorg is likely needed.
Newer members of the AT91 family share much in common with the AT91RM9200. The AT91SAM926x family shares many of the same devices as the AT91RM9200. but adds a number of new devices. Many of the devices are the same, but some are slightly different and others are radically different/new.
The common devices should remain in sys/arm/at91. We should create subdirectories for each subfamily, at91rm9200 and at91sam9. We then move the few devices specific the the rm9200 to that directory, and create new devices in the at91sam9 directory. In addition, we should move the board specific files to the directory appropriate for that board. Most boards support only one CPU. Those that support multiple CPUs would remain in the at91 directory (I'm not aware of any on the market today).
There's some suggestions that there be a separate "boards" directory. I'm not sure that I like it.