diff options
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 b525f0d60..423b09d30 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); |