| /* | 
 |  * U-boot - ldrinfo | 
 |  * | 
 |  * Copyright (c) 2010 Analog Devices Inc. | 
 |  * | 
 |  * See file CREDITS for list of people who contributed to this | 
 |  * project. | 
 |  * | 
 |  * Licensed under the GPL-2 or later. | 
 |  */ | 
 |  | 
 | #include <config.h> | 
 | #include <common.h> | 
 | #include <command.h> | 
 |  | 
 | #include <asm/blackfin.h> | 
 | #include <asm/mach-common/bits/bootrom.h> | 
 |  | 
 | static uint32_t ldrinfo_header(const void *addr) | 
 | { | 
 | 	uint32_t skip = 0; | 
 |  | 
 | #if defined(__ADSPBF561__) | 
 | 	/* BF56x has a 4 byte global header */ | 
 | 	uint32_t header, sign; | 
 | 	static const char * const spi_speed[] = { | 
 | 		"500K", "1M", "2M", "??", | 
 | 	}; | 
 |  | 
 | 	memcpy(&header, addr, sizeof(header)); | 
 |  | 
 | 	sign = (header & GFLAG_56X_SIGN_MASK) >> GFLAG_56X_SIGN_SHIFT; | 
 | 	printf("Header: %08X ( %s-bit-flash wait:%i hold:%i spi:%s %s)\n", | 
 | 		header, | 
 | 		(header & GFLAG_56X_16BIT_FLASH) ? "16" : "8", | 
 | 		(header & GFLAG_56X_WAIT_MASK) >> GFLAG_56X_WAIT_SHIFT, | 
 | 		(header & GFLAG_56X_HOLD_MASK) >> GFLAG_56X_HOLD_SHIFT, | 
 | 		spi_speed[(header & GFLAG_56X_SPI_MASK) >> GFLAG_56X_SPI_SHIFT], | 
 | 		sign == GFLAG_56X_SIGN_MAGIC ? "" : "!!hdrsign!! "); | 
 |  | 
 | 	skip = 4; | 
 | #endif | 
 |  | 
 | 	    /* |Block @ 12345678: 12345678 12345678 12345678 12345678 | */ | 
 | #if defined(__ADSPBF531__) || defined(__ADSPBF532__) || defined(__ADSPBF533__) || \ | 
 |     defined(__ADSPBF534__) || defined(__ADSPBF536__) || defined(__ADSPBF537__) || \ | 
 |     defined(__ADSPBF538__) || defined(__ADSPBF539__) || defined(__ADSPBF561__) | 
 | 	printf("                  Address  Count    Flags\n"); | 
 | #else | 
 | 	printf("                  BCode    Address  Count    Argument\n"); | 
 | #endif | 
 |  | 
 | 	return skip; | 
 | } | 
 |  | 
 | struct ldr_flag { | 
 | 	uint16_t flag; | 
 | 	const char *desc; | 
 | }; | 
 |  | 
 | static uint32_t ldrinfo_block(const void *base_addr) | 
 | { | 
 | 	uint32_t count; | 
 |  | 
 | 	printf("Block @ %08X: ", (uint32_t)base_addr); | 
 |  | 
 | #if defined(__ADSPBF531__) || defined(__ADSPBF532__) || defined(__ADSPBF533__) || \ | 
 |     defined(__ADSPBF534__) || defined(__ADSPBF536__) || defined(__ADSPBF537__) || \ | 
 |     defined(__ADSPBF538__) || defined(__ADSPBF539__) || defined(__ADSPBF561__) | 
 |  | 
 | 	uint32_t addr, pval; | 
 | 	uint16_t flags; | 
 | 	int i; | 
 | 	static const struct ldr_flag ldr_flags[] = { | 
 | 		{ BFLAG_53X_ZEROFILL,    "zerofill"  }, | 
 | 		{ BFLAG_53X_RESVECT,     "resvect"   }, | 
 | 		{ BFLAG_53X_INIT,        "init"      }, | 
 | 		{ BFLAG_53X_IGNORE,      "ignore"    }, | 
 | 		{ BFLAG_53X_COMPRESSED,  "compressed"}, | 
 | 		{ BFLAG_53X_FINAL,       "final"     }, | 
 | 	}; | 
 |  | 
 | 	memcpy(&addr, base_addr, sizeof(addr)); | 
 | 	memcpy(&count, base_addr+4, sizeof(count)); | 
 | 	memcpy(&flags, base_addr+8, sizeof(flags)); | 
 |  | 
 | 	printf("%08X %08X %04X ( ", addr, count, flags); | 
 |  | 
 | 	for (i = 0; i < ARRAY_SIZE(ldr_flags); ++i) | 
 | 		if (flags & ldr_flags[i].flag) | 
 | 			printf("%s ", ldr_flags[i].desc); | 
 |  | 
 | 	pval = (flags & BFLAG_53X_PFLAG_MASK) >> BFLAG_53X_PFLAG_SHIFT; | 
 | 	if (pval) | 
 | 		printf("gpio%i ", pval); | 
 | 	pval = (flags & BFLAG_53X_PPORT_MASK) >> BFLAG_53X_PPORT_SHIFT; | 
 | 	if (pval) | 
 | 		printf("port%c ", 'e' + pval); | 
 |  | 
 | 	if (flags & BFLAG_53X_ZEROFILL) | 
 | 		count = 0; | 
 | 	if (flags & BFLAG_53X_FINAL) | 
 | 		count = 0; | 
 | 	else | 
 | 		count += sizeof(addr) + sizeof(count) + sizeof(flags); | 
 |  | 
 | #else | 
 |  | 
 | 	const uint8_t *raw8 = base_addr; | 
 | 	uint32_t bcode, addr, arg, sign, chk; | 
 | 	int i; | 
 | 	static const struct ldr_flag ldr_flags[] = { | 
 | 		{ BFLAG_SAFE,        "safe"      }, | 
 | 		{ BFLAG_AUX,         "aux"       }, | 
 | 		{ BFLAG_FILL,        "fill"      }, | 
 | 		{ BFLAG_QUICKBOOT,   "quickboot" }, | 
 | 		{ BFLAG_CALLBACK,    "callback"  }, | 
 | 		{ BFLAG_INIT,        "init"      }, | 
 | 		{ BFLAG_IGNORE,      "ignore"    }, | 
 | 		{ BFLAG_INDIRECT,    "indirect"  }, | 
 | 		{ BFLAG_FIRST,       "first"     }, | 
 | 		{ BFLAG_FINAL,       "final"     }, | 
 | 	}; | 
 |  | 
 | 	memcpy(&bcode, base_addr, sizeof(bcode)); | 
 | 	memcpy(&addr, base_addr+4, sizeof(addr)); | 
 | 	memcpy(&count, base_addr+8, sizeof(count)); | 
 | 	memcpy(&arg, base_addr+12, sizeof(arg)); | 
 |  | 
 | 	printf("%08X %08X %08X %08X ( ", bcode, addr, count, arg); | 
 |  | 
 | 	if (addr % 4) | 
 | 		printf("!!addralgn!! "); | 
 | 	if (count % 4) | 
 | 		printf("!!cntalgn!! "); | 
 |  | 
 | 	sign = (bcode & BFLAG_HDRSIGN_MASK) >> BFLAG_HDRSIGN_SHIFT; | 
 | 	if (sign != BFLAG_HDRSIGN_MAGIC) | 
 | 		printf("!!hdrsign!! "); | 
 |  | 
 | 	chk = 0; | 
 | 	for (i = 0; i < 16; ++i) | 
 | 		chk ^= raw8[i]; | 
 | 	if (chk) | 
 | 		printf("!!hdrchk!! "); | 
 |  | 
 | 	printf("dma:%i ", bcode & BFLAG_DMACODE_MASK); | 
 |  | 
 | 	for (i = 0; i < ARRAY_SIZE(ldr_flags); ++i) | 
 | 		if (bcode & ldr_flags[i].flag) | 
 | 			printf("%s ", ldr_flags[i].desc); | 
 |  | 
 | 	if (bcode & BFLAG_FILL) | 
 | 		count = 0; | 
 | 	if (bcode & BFLAG_FINAL) | 
 | 		count = 0; | 
 | 	else | 
 | 		count += sizeof(bcode) + sizeof(addr) + sizeof(count) + sizeof(arg); | 
 |  | 
 | #endif | 
 |  | 
 | 	printf(")\n"); | 
 |  | 
 | 	return count; | 
 | } | 
 |  | 
 | static int do_ldrinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) | 
 | { | 
 | 	const void *addr; | 
 | 	uint32_t skip; | 
 |  | 
 | 	/* Get the address */ | 
 | 	if (argc < 2) | 
 | 		addr = (void *)load_addr; | 
 | 	else | 
 | 		addr = (void *)simple_strtoul(argv[1], NULL, 16); | 
 |  | 
 | 	/* Walk the LDR */ | 
 | 	addr += ldrinfo_header(addr); | 
 | 	do { | 
 | 		skip = ldrinfo_block(addr); | 
 | 		addr += skip; | 
 | 	} while (skip); | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | U_BOOT_CMD( | 
 | 	ldrinfo, 2, 0, do_ldrinfo, | 
 | 	"validate ldr image in memory", | 
 | 	"[addr]\n" | 
 | ); |