diff options
Diffstat (limited to 'common')
-rw-r--r-- | common/cmd_bootldr.c | 135 | ||||
-rw-r--r-- | common/cmd_cplbinfo.c | 4 | ||||
-rw-r--r-- | common/cmd_otp.c | 163 | ||||
-rw-r--r-- | common/devices.c | 3 |
4 files changed, 245 insertions, 60 deletions
diff --git a/common/cmd_bootldr.c b/common/cmd_bootldr.c index b525f0d..48d113f 100644 --- a/common/cmd_bootldr.c +++ b/common/cmd_bootldr.c @@ -16,6 +16,125 @@ #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__) + + 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) = (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 +142,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 +153,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); diff --git a/common/cmd_cplbinfo.c b/common/cmd_cplbinfo.c index 629e6a9..56e70d6 100644 --- a/common/cmd_cplbinfo.c +++ b/common/cmd_cplbinfo.c @@ -26,11 +26,11 @@ static const char *cplb_page_size(uint32_t data) */ static void show_cplb_table(uint32_t *addr, uint32_t *data) { - size_t i; + int i; printf(" Address Data Size Valid Locked\n"); for (i = 1; i <= 16; ++i) { printf(" %2i 0x%p 0x%05X %s %c %c\n", - i, *addr, *data, + i, (void *)*addr, *data, cplb_page_size(*data), (*data & CPLB_VALID ? 'Y' : 'N'), (*data & CPLB_LOCK ? 'Y' : 'N')); diff --git a/common/cmd_otp.c b/common/cmd_otp.c index e27bb29..6523290 100644 --- a/common/cmd_otp.c +++ b/common/cmd_otp.c @@ -6,7 +6,7 @@ * Licensed under the GPL-2 or later. */ -/* There are 512 128-bit "pages" (0x000 to 0x1FF). +/* There are 512 128-bit "pages" (0x000 through 0x1FF). * The pages are accessable as 64-bit "halfpages" (an upper and lower half). * The pages are not part of the memory map. There is an OTP controller which * handles scanning in/out of bits. While access is done through OTP MMRs, @@ -17,8 +17,6 @@ #include <common.h> #include <command.h> -#ifdef CONFIG_CMD_OTP - #include <asm/blackfin.h> #include <asm/mach-common/bits/otp.h> @@ -40,30 +38,87 @@ static const char *otp_strerror(uint32_t err) #define lowup(x) ((x) % 2 ? "upper" : "lower") -int do_otp(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +static int check_voltage(void) +{ + /* Make sure voltage limits are within datasheet spec */ + uint16_t vr_ctl = bfin_read_VR_CTL(); + +#ifdef __ADSPBF54x__ + /* 0.9V <= VDDINT <= 1.1V */ + if ((vr_ctl & 0xc) && (vr_ctl & 0xc0) == 0xc0) + return 1; +#else + /* for the parts w/out qualification yet */ + (void)vr_ctl; +#endif + + return 0; +} + +static void set_otp_timing(bool write) { - bool force = false; - if (!strcmp(argv[1], "--force")) { - force = true; - argv[1] = argv[0]; - argv++; - --argc; + static uint32_t timing; + if (!timing) { + uint32_t tp1, tp2, tp3; + /* OTP_TP1 = 1000 / sclk_period (in nanoseconds) + * OTP_TP1 = 1000 / (1 / get_sclk() * 10^9) + * OTP_TP1 = (1000 * get_sclk()) / 10^9 + * OTP_TP1 = get_sclk() / 10^6 + */ + tp1 = get_sclk() / 1000000; + /* OTP_TP2 = 400 / (2 * sclk_period) + * OTP_TP2 = 400 / (2 * 1 / get_sclk() * 10^9) + * OTP_TP2 = (400 * get_sclk()) / (2 * 10^9) + * OTP_TP2 = (2 * get_sclk()) / 10^7 + */ + tp2 = (2 * get_sclk() / 10000000) << 8; + /* OTP_TP3 = magic constant */ + tp3 = (0x1401) << 15; + timing = tp1 | tp2 | tp3; } + bfrom_OtpCommand(OTP_INIT, write ? timing : timing & ~(-1 << 15)); +} + +int do_otp(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + uint32_t ret, base_flags; + bool prompt_user, force_read; uint32_t (*otp_func)(uint32_t page, uint32_t flags, uint64_t *page_content); - if (!strcmp(argv[1], "read")) - otp_func = otp_read; - else if (!strcmp(argv[1], "write")) - otp_func = otp_write; - else { + + if (argc < 4) { usage: cmd_usage(cmdtp); return 1; } + prompt_user = false; + base_flags = 0; + if (!strcmp(argv[1], "read")) + otp_func = bfrom_OtpRead; + else if (!strcmp(argv[1], "dump")) { + otp_func = bfrom_OtpRead; + force_read = true; + } else if (!strcmp(argv[1], "write")) { + otp_func = bfrom_OtpWrite; + base_flags = OTP_CHECK_FOR_PREV_WRITE; + if (!strcmp(argv[2], "--force")) { + argv[2] = argv[1]; + argv++; + --argc; + } else + prompt_user = false; + } else if (!strcmp(argv[1], "lock")) { + if (argc != 4) + goto usage; + otp_func = bfrom_OtpWrite; + base_flags = OTP_LOCK; + } else + goto usage; + uint64_t *addr = (uint64_t *)simple_strtoul(argv[2], NULL, 16); uint32_t page = simple_strtoul(argv[3], NULL, 16); - uint32_t flags, ret; + uint32_t flags; size_t i, count; ulong half; @@ -81,14 +136,21 @@ int do_otp(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) } else half = 0; + /* "otp lock" has slightly different semantics */ + if (base_flags & OTP_LOCK) { + count = page; + page = (uint32_t)addr; + addr = NULL; + } + /* do to the nature of OTP, make sure users are sure */ - if (!force && otp_func == otp_write) { + if (prompt_user) { printf( "Writing one time programmable memory\n" "Make sure your operating voltages and temperature are within spec\n" " source address: 0x%p\n" - " OTP destination: %s page 0x%03X - %s page 0x%03X\n" - " number to write: %ld halfpages\n" + " OTP destination: %s page 0x%03X - %s page 0x%03lX\n" + " number to write: %lu halfpages\n" " type \"YES\" (no quotes) to confirm: ", addr, lowup(half), page, @@ -111,30 +173,42 @@ int do_otp(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) } } } - - /* Only supported in newer silicon ... enable writing */ -#if (0) - otp_command(OTP_INIT, ...); -#else - *pOTP_TIMING = 0x32149485; -#endif } - printf("OTP memory %s: addr 0x%08lx page 0x%03X count %ld ... ", + printf("OTP memory %s: addr 0x%p page 0x%03X count %zu ... ", argv[1], addr, page, count); + set_otp_timing(otp_func == bfrom_OtpWrite); + if (otp_func == bfrom_OtpWrite && check_voltage()) { + puts("ERROR: VDDINT voltage is out of spec for writing\n"); + return -1; + } + + /* Do the actual reading/writing stuff */ ret = 0; for (i = half; i < count + half; ++i) { - flags = (i % 2) ? OTP_UPPER_HALF : OTP_LOWER_HALF; + flags = base_flags | (i % 2 ? OTP_UPPER_HALF : OTP_LOWER_HALF); + try_again: ret = otp_func(page, flags, addr); - if (ret & 0x1) - break; - else if (ret) + if (ret & OTP_MASTER_ERROR) { + if (force_read) { + if (flags & OTP_NO_ECC) + break; + else + flags |= OTP_NO_ECC; + puts("E"); + goto try_again; + } else + break; + } else if (ret) puts("W"); else puts("."); - ++addr; - if (i % 2) + if (!(base_flags & OTP_LOCK)) { + ++addr; + if (i % 2) + ++page; + } else ++page; } if (ret & 0x1) @@ -143,21 +217,20 @@ int do_otp(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) else puts(" done\n"); - if (otp_func == otp_write) - /* Only supported in newer silicon ... disable writing */ -#if (0) - otp_command(OTP_INIT, ...); -#else - *pOTP_TIMING = 0x1485; -#endif + /* Make sure we disable writing */ + set_otp_timing(false); + bfrom_OtpCommand(OTP_CLOSE, 0); return ret; } -U_BOOT_CMD(otp, 6, 0, do_otp, - "One-Time-Programmable sub-system", +U_BOOT_CMD(otp, 7, 0, do_otp, + "One-Time-Programmable sub-system\n", "read <addr> <page> [count] [half]\n" + " - read 'count' half-pages starting at 'page' (offset 'half') to 'addr'\n" + "otp dump <addr> <page> [count] [half]\n" + " - like 'otp read', but skip read errors\n" "otp write [--force] <addr> <page> [count] [half]\n" - " - read/write 'count' half-pages starting at page 'page' (offset 'half')\n"); - -#endif + " - write 'count' half-pages starting at 'page' (offset 'half') from 'addr'\n" + "otp lock <page> <count>\n" + " - lock 'count' pages starting at 'page'\n"); diff --git a/common/devices.c b/common/devices.c index ce3b7a0..38f1bbc 100644 --- a/common/devices.c +++ b/common/devices.c @@ -240,6 +240,9 @@ int devices_init (void) #ifdef CONFIG_NETCONSOLE drv_nc_init (); #endif +#ifdef CONFIG_JTAG_CONSOLE + drv_jtag_console_init (); +#endif return (0); } |