[U-Boot] Selectable / delayed initialization
Simon Glass
sjg at chromium.org
Thu Aug 18 17:46:12 CEST 2011
Hi Graeme,
On Tue, Aug 16, 2011 at 11:42 PM, Graeme Russ <graeme.russ at gmail.com> wrote:
> 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.
Well given your recent patch it seems this isn't a bridge too far :-)
I would very much like init to be done via a registration macro as
your patch does (and U-Boot commands already do). If we are going down
that path I would even argue for a way to configure it at start-up
(add/remove things).
>
> 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'
That's great as far as it goes. But many devices have one-time
initialization also. So perhaps
device->init()
device->start()
device->stop()
device->start()
device->stop()
device->uninit()
although some might argue for open/close instead of start/stop.
As an example, USB typically requires some clock/pinmux setup after
which it is ready for use. This happens at the beginning, often
regardless of whether 'usb start' is ever used. While this might be
against the grain, forcing all the init into the start() function then
means that this code needs to check if the init was done in a previous
start() call, and skip it if so. That seems wrong to me.
>
>> 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
Well let's hope not. Going back to my original request, I can see how
your patch can be fairly easily modified to do what I require - simply
by adding a tag to each init call indicating what it refers to (usb,
mmc, uart, etc.) and then providing a list of tags we want to init
for.
Regards
Simon
>
> Regards,
>
> Graeme
>
More information about the U-Boot
mailing list