diff options
author | Mike Frysinger <vapier@gentoo.org> | 2008-10-11 22:08:42 -0400 |
---|---|---|
committer | Mike Frysinger <vapier@gentoo.org> | 2009-01-28 13:27:09 -0500 |
commit | 29d4ea0a9073c82469184331010136f52edf8db6 (patch) | |
tree | fe768d0cf86a6b9ca9ffce134cb19ab575d57c59 /common/cmd_bootldr.c | |
parent | 8b35e3aeff6c2d747c37697997b3f8a808432329 (diff) |
Blackfin: bootldr: implement BF53x/BF56x LDR loader
The BF53x/BF56x parts do not have an on-chip ROM to boot LDRs out of
arbitrary memory locations, so implement a basic one in software.
Signed-off-by: Mike Frysinger <vapier@gentoo.org>
Diffstat (limited to 'common/cmd_bootldr.c')
-rw-r--r-- | common/cmd_bootldr.c | 137 |
1 files changed, 124 insertions, 13 deletions
diff --git a/common/cmd_bootldr.c b/common/cmd_bootldr.c index b525f0d602d..423b09d307b 100644 --- a/common/cmd_bootldr.c +++ b/common/cmd_bootldr.c @@ -16,6 +16,127 @@ #include <asm/blackfin.h> #include <asm/mach-common/bits/bootrom.h> +/* Simple sanity check on the specified address to make sure it contains + * an LDR image of some sort. + */ +static bool ldr_valid_signature(uint8_t *data) +{ +#if defined(__ADSPBF561__) + + /* BF56x has a 4 byte global header */ + if (data[3] == 0xA0) + return true; + +#elif defined(__ADSPBF531__) || defined(__ADSPBF532__) || defined(__ADSPBF533__) || \ + defined(__ADSPBF534__) || defined(__ADSPBF536__) || defined(__ADSPBF537__) || \ + defined(__ADSPBF538__) || defined(__ADSPBF539__) + + /* all the BF53x should start at this address mask */ + uint32_t addr; + memmove(&addr, data, sizeof(addr)); + if ((addr & 0xFF0FFF0F) == 0xFF000000) + return true; +#else + + /* everything newer has a magic byte */ + uint32_t count; + memmove(&count, data + 8, sizeof(count)); + if (data[3] == 0xAD && count == 0) + return true; + +#endif + + return false; +} + +/* If the Blackfin is new enough, the Blackfin on-chip ROM supports loading + * LDRs from random memory addresses. So whenever possible, use that. In + * the older cases (BF53x/BF561), parse the LDR format ourselves. + */ +#define ZEROFILL 0x0001 +#define RESVECT 0x0002 +#define INIT 0x0008 +#define IGNORE 0x0010 +#define FINAL 0x8000 +static void ldr_load(uint8_t *base_addr) +{ +#if defined(__ADSPBF531__) || defined(__ADSPBF532__) || defined(__ADSPBF533__) || \ + /*defined(__ADSPBF534__) || defined(__ADSPBF536__) || defined(__ADSPBF537__) ||*/\ + defined(__ADSPBF538__) || defined(__ADSPBF539__) || defined(__ADSPBF561__) + + void *ret; + + uint32_t addr; + uint32_t count; + uint16_t flags; + + /* the bf56x has a 4 byte global header ... but it is useless to + * us when booting an LDR from a memory address, so skip it + */ +# ifdef __ADSPBF561__ + base_addr += 4; +# endif + + memmove(&flags, base_addr + 8, sizeof(flags)); + bfin_write_EVT1(flags & RESVECT ? 0xFFA00000 : 0xFFA08000); + + do { + /* block header may not be aligned */ + memmove(&addr, base_addr, sizeof(addr)); + memmove(&count, base_addr+4, sizeof(count)); + memmove(&flags, base_addr+8, sizeof(flags)); + base_addr += sizeof(addr) + sizeof(count) + sizeof(flags); + + printf("loading to 0x%08x (0x%x bytes) flags: 0x%04x\n", + addr, count, flags); + + if (!(flags & IGNORE)) { + if (flags & ZEROFILL) + memset((void *)addr, 0x00, count); + else + memcpy((void *)addr, base_addr, count); + + if (flags & INIT) { + void (*init)(void) = (void *)addr; + init(); + } + } + + if (!(flags & ZEROFILL)) + base_addr += count; + } while (!(flags & FINAL)); + +#endif +} + +/* For BF537, we use the _BOOTROM_BOOT_DXE_FLASH funky ROM function. + * For all other BF53x/BF56x, we just call the entry point. + * For everything else (newer), we use _BOOTROM_MEMBOOT ROM function. + */ +static void ldr_exec(void *addr) +{ +#if defined(__ADSPBF534__) || defined(__ADSPBF536__) || defined(__ADSPBF537__) + + /* restore EVT1 to reset value as this is what the bootrom uses as + * the default entry point when booting the final block of LDRs + */ + bfin_write_EVT1(L1_INST_SRAM); + __asm__("call (%0);" : : "a"(_BOOTROM_MEMBOOT), "q7"(addr) : "RETS", "memory"); + +#elif defined(__ADSPBF531__) || defined(__ADSPBF532__) || defined(__ADSPBF533__) || \ + defined(__ADSPBF538__) || defined(__ADSPBF539__) || defined(__ADSPBF561__) + + void (*ldr_entry)(void) = bfin_read_EVT1(); + ldr_entry(); + +#else + + int32_t (*BOOTROM_MEM)(void *, int32_t, int32_t, void *) = (void *)_BOOTROM_MEMBOOT; + BOOTROM_MEM(addr, 0, 0, NULL); + +#endif +} + /* * the bootldr command loads an address, checks to see if there * is a Boot stream that the on-chip BOOTROM can understand, @@ -23,11 +144,9 @@ * to also add booting from SPI, or TWI, but this function does * not currently support that. */ - int do_bootldr(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) { void *addr; - uint32_t *data; /* Get the address */ if (argc < 2) @@ -36,22 +155,14 @@ int do_bootldr(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) addr = (void *)simple_strtoul(argv[1], NULL, 16); /* Check if it is a LDR file */ - data = addr; -#if defined(__ADSPBF54x__) || defined(__ADSPBF52x__) - if ((*data & 0xFF000000) == 0xAD000000 && data[2] == 0x00000000) { -#else - if (*data == 0xFF800060 || *data == 0xFF800040 || *data == 0xFF800020) { -#endif - /* We want to boot from FLASH or SDRAM */ + if (ldr_valid_signature(addr)) { printf("## Booting ldr image at 0x%p ...\n", addr); + ldr_load(addr); icache_disable(); dcache_disable(); - __asm__( - "jump (%1);" - : - : "q7" (addr), "a" (_BOOTROM_MEMBOOT)); + ldr_exec(addr); } else printf("## No ldr image at address 0x%p\n", addr); |