This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Reading environment variables from MLO

Is it possible to read u-boot environment variables from MLO? I want to set a flag and have the MLO see it on the next power up and then take a specific action. I tried this:

u-boot-[version]/common/spl/spl_nand.c

char *ep = NULL;
//
//...function stuff...
//
 /* Load u-boot */
 ep = getenv("upgrade");
 if(ep != NULL)
  puts(ep);
 else
  puts("upgrade not defined");
 nand_spl_load_image(CONFIG_SYS_NAND_U_BOOT_OFFS,

That built fine, and on the first time it ran I got back "upgrade not defined" in the boot log:

USB Host mode controller at 47401800 using PIO, IRQ 0
upgrade not defined

U-Boot 2013.01.01 (Apr 22 2014 - 08:59:59)

which I expected, then I saved a value for "upgrade":

U-Boot# setenv upgrade BOOYA
U-Boot# saveenv

On the next power up I again saw "upgrade not defined" in the boot log just as before, but when u-boot fully came up and I ran a printenv, I saw "upgrade" present and set as I expected:

U-Boot# printenv
...
stdout=serial
upgrade=BOOYA
usbnet_devaddr=00:18:31:8f:1b:7b
...

So I'm wondering why MLO failed to recognize the variable as set? Is it possible to read environment variables at all from MLO? If not, is there any way I can "set a flag" and have MLO trigger on it?

  • I did find one example of SPL based changes to environment variables:

    u-boot-[version]/common/spl/spl_net.c:

    void spl_net_load_image(const char *device)
    {
    	int rv;
    
    	env_init();
    	env_relocate();
    	setenv("autoload", "yes");

    In this case it's setting an environment variable, I notice that env_init() and env_relocate() are being called. I tossed those calls in before mine but there was no difference... I checked out what those functions are doing and it's strange, I guess it was supposed to be some validation of the memory but it doesn't seem to do much of anything.

    The env_init() (once you take the conditional compiles out of the picture) is just setting a default string of variables:

        gd->env_addr = (ulong)&default_environment[0];

    And marking them valid:

        gd->env_valid = 1;

    So obviously what is in there by default (when doing the make u-boot build) is not going to work.

    There appear to be other options here... (for example if ENV_IS_EMBEDDED or CONFIG_NAND_ENV_DST is defined) but I'm not sure what the consequences of enabling these is yet...

  • Hi Mike,

    The SPL reads the default environment and this is why you can't read the change you made to the variables back. Since the make system builds both the SPL and U-Boot using the same files, but different preprocessor #defines, the call to env_relocate_spec() results in different functions being called. In the case of U-Boot, the env_relocate_spec() function from common/env_nand.c is called, and in the case of SPL, the env_relocate_spec() function from common/env_nowhere.c (which is empty) is called.

    The env_relocate_spec() inside common/env_nand.c reads the environment variables from the NAND flash at offset CONFIG_ENV_OFFSET into a buffer and then imports it into a hash table using env_import(). This calls do_env_import() command from common/cmd_nvedit.c which finally marks the environment as "ready":

    gd->flags |= GD_FLG_ENV_READY;

    Every subsequent call to the getenv() command searches the populated hash table and extracts the needed environment data from it.

    However, doing this before U-Boot will require some modifications/hacks to the code, which I can't help you with.

    Best regards,
    Miroslav

  • Miroslav,

        Thanks for that information, I've been examining the code, it looks like the env_relocate_spec() for u-boot calls and allocate and then read function:

     ALLOC_CACHE_ALIGN_BUFFER(char, buf, CONFIG_ENV_SIZE);
     ret = readenv(CONFIG_ENV_OFFSET, (u_char *)buf);

    And this readenv function seems to use a nand_info variable. I found it in include/nand.h:

    extern nand_info_t nand_info[];

    but I'm having a hard time finding where this is actually initialized. Could you advise where this is set in the u-boot for the AM335x? I did find the drivers/mtd/nand/nand.c where there is the nand_init() function, but it then calls board_nand_init() (where I presume the actual select of the NAND chip is done).

    When I search the code for this I find a number of functions in bard/XXX/<somefile>.c but the only ti one that I see is:

    board/ti/tnetv107xevm/sdb_board.c. I was expecting something in board/ti/am335x/board.c, but that doesn't appear to be the case.

    So how does the NAND init procedure flow for the AM335x evm in u-boot?

    Thanks.

  • Mike, the nand_init() function calls the board_nand_init() function inside <u-boot_dir>/drivers/mtd/nand/omap_gpmc.c.

    Best regards,
    Miroslav