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.

Let MLO/Bootloader erad from eMMC first?

Genius 5820 points

Hi,


the community-driven variant of StarterWare from https://sourceforge.net/projects/starterwarefree/

  • Since my postign was trashed I'll try again:

    the community-driven variant of StarterWare from sourceforge.net/.../ contains not only a lot of bugfixes but also eMMC support for BeagleBone. So I wonder if anybody already used it to upgrade MLO application to first try to read "APP" from eMMC and try from external SD-card only if this fails?
  • I have been trying and failing spectacularly. if someone does get it figured out, it would be greatly appreciated.
  • I was able to get it working with the help of some other posts here.  This was for the AM335x/Beaglebone.  The code needs a bunch of cleanup and I'm cherry-picking it from a larger project I was working on, so there may be some references to include files that don't exist.  But here's what I did and files are in the links below.

    ---------------

    First, you need to modify the mmcsdlib library in the starterware folder and recompile it with your changes.  Download my changes (source and precompiled .lib file also) here:  http://uiproductions.com/emmc/mmcsdlib.zip

    1.  In hs_mmcsdlib.c, I modified the this line to support the eMMC's higher voltage spec.

    HSMMCSDSupportedVoltSet(ctrl->memBase, HS_MMCSD_SUPPORT_VOLT_1P8 |HS_MMCSD_SUPPORT_VOLT_3P3);

    2.  Also in hs_mmcsdlib.c, Set bus width to 4 bits and voltage to 3P3, and modify the BusWidthConfig functions to support other bus widths.

    ---------------

    Then I made my own version of the beaglebone read/write example code with some modifications.  Files here:  http://uiproductions.com/emmc/dremmc.zip

    The key changes from the sample to here are as follows.  First, I made some new setup functions to initialize the proper GPIOs and clock module.  These are assuming your eMMC is connected to MMC1, as is the Beaglebone's.  

    void MMC1PinPuxSetup(void) {
    
    HWREG(SOC_CONTROL_REGS + CONTROL_CONF_GPMC_AD(7)) = CONTROL_CONF_MUXMODE(1) | CONTROL_CONF_RXACTIVE | CONTROL_CONF_PULLUPSEL;
    HWREG(SOC_CONTROL_REGS + CONTROL_CONF_GPMC_AD(6)) = CONTROL_CONF_MUXMODE(1) | CONTROL_CONF_RXACTIVE | CONTROL_CONF_PULLUPSEL;
    HWREG(SOC_CONTROL_REGS + CONTROL_CONF_GPMC_AD(5)) = CONTROL_CONF_MUXMODE(1) | CONTROL_CONF_RXACTIVE | CONTROL_CONF_PULLUPSEL;
    HWREG(SOC_CONTROL_REGS + CONTROL_CONF_GPMC_AD(4)) = CONTROL_CONF_MUXMODE(1) | CONTROL_CONF_RXACTIVE | CONTROL_CONF_PULLUPSEL;
    HWREG(SOC_CONTROL_REGS + CONTROL_CONF_GPMC_AD(3)) = CONTROL_CONF_MUXMODE(1) | CONTROL_CONF_RXACTIVE | CONTROL_CONF_PULLUPSEL;
    HWREG(SOC_CONTROL_REGS + CONTROL_CONF_GPMC_AD(2)) = CONTROL_CONF_MUXMODE(1) | CONTROL_CONF_RXACTIVE | CONTROL_CONF_PULLUPSEL;
    HWREG(SOC_CONTROL_REGS + CONTROL_CONF_GPMC_AD(1)) = CONTROL_CONF_MUXMODE(1) | CONTROL_CONF_RXACTIVE | CONTROL_CONF_PULLUPSEL;
    HWREG(SOC_CONTROL_REGS + CONTROL_CONF_GPMC_AD(0)) = CONTROL_CONF_MUXMODE(1) | CONTROL_CONF_RXACTIVE | CONTROL_CONF_PULLUPSEL;
    HWREG(SOC_CONTROL_REGS + CONTROL_CONF_GPMC_CSN(1)) = CONTROL_CONF_MUXMODE(2) | CONTROL_CONF_RXACTIVE | CONTROL_CONF_PULLUPSEL;
    HWREG(SOC_CONTROL_REGS + CONTROL_CONF_GPMC_CSN(2)) = CONTROL_CONF_MUXMODE(2) | CONTROL_CONF_RXACTIVE | CONTROL_CONF_PULLUPSEL;
    HWREG(SOC_CONTROL_REGS + CONTROL_CONF_GPMC_CSN(0)) = CONTROL_CONF_MUXMODE(7) | CONTROL_CONF_RXACTIVE | CONTROL_CONF_PULLUPSEL;
    HWREG(SOC_CONTROL_REGS + CONTROL_CONF_GPMC_ADVN_ALE) = CONTROL_CONF_MUXMODE(7) | CONTROL_CONF_RXACTIVE | CONTROL_CONF_PULLUPSEL;
    }
    
    void MMC1ModuleClkConfig(void)
    {
    HWREG(SOC_PRCM_REGS + CM_PER_MMC1_CLKCTRL) |=
    CM_PER_MMC1_CLKCTRL_MODULEMODE_ENABLE;
    
    while((HWREG(SOC_PRCM_REGS + CM_PER_MMC1_CLKCTRL) &
    CM_PER_MMC1_CLKCTRL_MODULEMODE) != CM_PER_MMC1_CLKCTRL_MODULEMODE_ENABLE);
    }

    I also needed to initialize the EDMA module, since the MMC library uses DMA to read/write to eMMC.  That's done in the setup in DReMMC.c.

    -----------------

    Now, to use everything, you just include DReMMC.h, the H files from the library, and the library itself into your project.  Then to setup, first make sure you have the MMU configured, cache enabled, and then call DReMMC_setup().

        MMUConfigAndEnable();
        CacheEnable(CACHE_DCACHE);
        DReMMC_setup();
    

    To write to flash, call:

    		unsigned int status = DReMMC_write(firmwareBuffer, 0x300, numberOfBlocks);
    

    Where firmwareBuffer is an unsigned char array containing the bytes to write, 0x300 is the eMMC block to write to, and numberOfBlocks is the number of blocks to write.  1 block is 4096 bytes, so make sure your buffer has the correct amount of data.  Status will be non-zero if it was a success.

    Reading flash is just as easy:

    status = DReMMC_read(dataBuffer, 0x300, 0x220);

    Where dataBuffer is an unsigned char array with enough space for what you're reading, 0x300 is the block address to read, and 0x220 is the number of blocks to read.  Status will be non-zero if it was a success.

    ------------------------

    Some other misc things to be mindful of:

    It took me forever to figure this out, so it's worth mentioning.  0x300 is the block address where uBoot jumps to when booting from eMMC.  I wrote a bootloader using my eMMC functions to overwrite the firmware at 0x300 on my device over a USB bulk endpoint, then soft reboot.

    Since the read/write functions use DMA with interrupts to talk to the eMMC, you need to call the read/write functions from the main loop, not within another interrupt.  You might be able to get around this by doing some sort of interrupt priority tweaking.

    Since it uses caching, I find that I need to declare the read/write buffers in global scope.  I guess it has something to do with keeping the memory allocated while the read/write action occurs?

    I'm not sure if this matters, but because of some caching thing you may have to align your buffers when declaring them.  Not sure what this does, or if you need it.  

    #define SOC_CACHELINE_SIZE 64
    #pragma DATA_ALIGN(dataBuffer, SOC_CACHELINE_SIZE);
    static unsigned char dataBuffer[512];