[U-Boot] Selectable / delayed initialization

Graeme Russ graeme.russ at gmail.com
Wed Aug 17 08:42:40 CEST 2011


Hi Simon,

On Wed, Aug 17, 2011 at 1:25 PM, Simon Glass <sjg at chromium.org> wrote:
> Hi,
>
> When U-Boot starts up it initializes all the peripherals which are
> enabled  This might include USB, I2C, SD/MMC, LCD, Ethernet, UARTs,
> etc.
>
> To save time, reduce the amount of code executed and thereby improve
> security, we are wanting to initialize only some peripherals at the
> start. For example we might start up I2C and SC/MMC.
>
> Later when it becomes clear that USB and Ethernet are needed we want
> to init those also. I suppose the easiest way of describing this is
> that we want to have some 'level 0' init, then perhaps move to level 1
> and init peripherals at that level, then perhaps to level 2, etc.
> Quite often we will only get to level 1 before jumping to the kernel.

Well technically, the device init should only be done either

a) U-Boot core code needs to access the device (to read the environment
   for example)
b) When a U-Boot command first uses the device
b) When doing final init ready for the OS kernel

> At the moment the U-Boot init code is spread around a bit - there are
> files called board.c within arch/xx/cpu/, board/xx/ and arch/xx/lib/.
> So it is hard to make this change just within a board file. Some other
> files have big lists of init calls like stdio.c and serial.c.

Yes, it is a mess

> I am thinking of creating a way of specifying a list of peripherals
> which should be inited in each level, then moving all init code into a
> function which knows how to init each peripheral. Then we can call
> init_level(2) for example, to start up peripherals in that level.
> Perhaps level 0 would be reserved for pre-relocation init.
>
> I am interested in any thoughts that people have about this and
> whether it might be implemented in a generally useful way. I am
> assuming that a driver registration / initcall approach would be a
> bridge too far for U-Boot at the moment, so I am thinking of a
> function with a big 'switch' statement.

I would prefer a device level 'start' and 'stop' hooks so when a command
or the U-Boot core needs to use a particular device it calls
device->start(), uses the device then calls device->stop(). Devices that
are in use permanently (timers and console ports are prime examples),
device->stop() is never called (or maybe called proir to entering the
OS kernel). This would be a massive architectural change for U-Boot and
leads into a 'driver framework'

> The other related issue is that I notice that the arch/xxx/lib/board.c
> files are different but have a lot of common code. Is there some scope
> for starting a common/board.c file which slowly builds up common
> functionality so that over time we end up with only the
> architecture-specific code in the arch/lib/xxx/board.c? If so these
> these two goals could perhaps be progressed together.

Now that relocation has settled down and looks to be working in a much
more platform independent manner, board_init_f() and board_init_r() should
be able to be moved into /lib/ with any arch or board specific
functionality carved out into init functions. Have a look at x86 and
you'll see that board_init_f() and board_init_r() work in a very simlar
manner to each other. I don't think this is going to be particularly
difficult to implement. I am, however, still scratching my head trying to
figure out how to create a simple mechanism for dynamic init sequence
building (even if it is done at compile time). By this I mean a standard
arch level init sequence and a way of allowing boards to insert init
functions at arbitrary points in the init sequence without a mass of
#ifdef's in /lib/board.c and without have each and every board having to
define the whole init sequence in /board/init.c. At the moment it's done
by reserving some specific points in the init sequence where U-Boot calls
into the board-specific init functions. If the board has no need for such
a call, it still needs to implement a do nothing stub function. I'm sure
someone can come up with some clever pre-processor macro-foo to do
something like this:

In board/foo.c:

int init_board_gpio()
{
	/* Do Stuff */
}
BOARD_INIT(init_board_leds, 214);

int init_board_leds()
{
	/* Do Stuff */
}
/* Init board LEDs after the boards GPIO has been initialised */
BOARD_INIT(init_board_leds, 215);

In arch/xxx/sdram.c

int init_sdram()
{
	/* Do Stuff */
}
/* SDRAM gets intialised really early (but not before timers) */
BOARD_INIT(init_sdram, 10);

In arch/xxx/<soc>/timer.c

int init_timers()
{
	/* Do Stuff */
}
/* Timers are needed early */
BOARD_INITinit_timers, 9);


You could even #define some of the steps with nice gaps between:

#define INIT_STEP_CPU		1	
#define INIT_STEP_TIMERS	INIT_STEP_CPU + 10
#define INIT_STEP_SDARM		INIT_STEP_TIMERS + 10

But maybe it's all wishful thinking

Regards,

Graeme


More information about the U-Boot mailing list