X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=cpu%2Fblackfin%2Finitcode.c;h=7bd4b227e6d3b71c07a5338e80ba2d77fad4b103;hb=aaa0e0812ffdf861993129f41936eb175a2eaa5f;hp=71f33759e00a49a2774aec033f34673bfe9c2e12;hpb=67619982bfc5cd62710a48e3cbffc304cb78c341;p=u-boot diff --git a/cpu/blackfin/initcode.c b/cpu/blackfin/initcode.c index 71f33759e0..7bd4b227e6 100644 --- a/cpu/blackfin/initcode.c +++ b/cpu/blackfin/initcode.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -20,7 +21,7 @@ #include "serial.h" __attribute__((always_inline)) -static inline uint32_t serial_init(void) +static inline void serial_init(void) { #ifdef __ADSPBF54x__ # ifdef BFIN_BOOT_UART_USE_RTS @@ -61,25 +62,16 @@ static inline uint32_t serial_init(void) } #endif - uint32_t old_baud; - if (BFIN_DEBUG_EARLY_SERIAL || CONFIG_BFIN_BOOT_MODE == BFIN_BOOT_UART) - old_baud = serial_early_get_baud(); - else - old_baud = CONFIG_BAUDRATE; - if (BFIN_DEBUG_EARLY_SERIAL) { + int ucen = *pUART_GCTL & UCEN; serial_early_init(); /* If the UART is off, that means we need to program * the baud rate ourselves initially. */ - if (!old_baud) { - old_baud = CONFIG_BAUDRATE; + if (ucen != UCEN) serial_early_set_baud(CONFIG_BAUDRATE); - } } - - return old_baud; } __attribute__((always_inline)) @@ -93,30 +85,6 @@ static inline void serial_deinit(void) #endif } -/* We need to reset the baud rate when we have early debug turned on - * or when we are booting over the UART. - * XXX: we should fix this to calc the old baud and restore it rather - * than hardcoding it via CONFIG_LDR_LOAD_BAUD ... but we have - * to figure out how to avoid the division in the baud calc ... - */ -__attribute__((always_inline)) -static inline void serial_reset_baud(uint32_t baud) -{ - if (!BFIN_DEBUG_EARLY_SERIAL && CONFIG_BFIN_BOOT_MODE != BFIN_BOOT_UART) - return; - -#ifndef CONFIG_LDR_LOAD_BAUD -# define CONFIG_LDR_LOAD_BAUD 115200 -#endif - - if (CONFIG_BFIN_BOOT_MODE == BFIN_BOOT_BYPASS) - serial_early_set_baud(baud); - else if (CONFIG_BFIN_BOOT_MODE == BFIN_BOOT_UART) - serial_early_set_baud(CONFIG_LDR_LOAD_BAUD); - else - serial_early_set_baud(CONFIG_BAUDRATE); -} - __attribute__((always_inline)) static inline void serial_putc(char c) { @@ -133,12 +101,22 @@ static inline void serial_putc(char c) } -/* Max SCLK can be 133MHz ... dividing that by 4 gives - * us a freq of 33MHz for SPI which should generally be +/* Max SCLK can be 133MHz ... dividing that by (2*4) gives + * us a freq of 16MHz for SPI which should generally be * slow enough for the slow reads the bootrom uses. */ +#if !defined(CONFIG_SPI_FLASH_SLOW_READ) && \ + ((defined(__ADSPBF52x__) && __SILICON_REVISION__ >= 2) || \ + (defined(__ADSPBF54x__) && __SILICON_REVISION__ >= 1)) +# define BOOTROM_SUPPORTS_SPI_FAST_READ 1 +#else +# define BOOTROM_SUPPORTS_SPI_FAST_READ 0 +#endif #ifndef CONFIG_SPI_BAUD_INITBLOCK -# define CONFIG_SPI_BAUD_INITBLOCK 4 +# define CONFIG_SPI_BAUD_INITBLOCK (BOOTROM_SUPPORTS_SPI_FAST_READ ? 2 : 4) +#endif +#ifdef SPI0_BAUD +# define bfin_write_SPI_BAUD bfin_write_SPI0_BAUD #endif /* PLL_DIV defines */ @@ -226,10 +204,61 @@ static inline void serial_putc(char c) # define CONFIG_VR_CTL_VAL (CONFIG_VR_CTL_CLKBUF | CONFIG_VR_CTL_VLEV | CONFIG_VR_CTL_FREQ) #endif +/* some parts do not have an on-chip voltage regulator */ +#if defined(__ADSPBF51x__) +# define CONFIG_HAS_VR 0 +# undef CONFIG_VR_CTL_VAL +# define CONFIG_VR_CTL_VAL 0 +#else +# define CONFIG_HAS_VR 1 +#endif + +#ifndef EBIU_RSTCTL +/* Blackfin with SDRAM */ +#ifndef CONFIG_EBIU_SDBCTL_VAL +# if CONFIG_MEM_SIZE == 16 +# define CONFIG_EBSZ_VAL EBSZ_16 +# elif CONFIG_MEM_SIZE == 32 +# define CONFIG_EBSZ_VAL EBSZ_32 +# elif CONFIG_MEM_SIZE == 64 +# define CONFIG_EBSZ_VAL EBSZ_64 +# elif CONFIG_MEM_SIZE == 128 +# define CONFIG_EBSZ_VAL EBSZ_128 +# elif CONFIG_MEM_SIZE == 256 +# define CONFIG_EBSZ_VAL EBSZ_256 +# elif CONFIG_MEM_SIZE == 512 +# define CONFIG_EBSZ_VAL EBSZ_512 +# else +# error You need to define CONFIG_EBIU_SDBCTL_VAL or CONFIG_MEM_SIZE +# endif +# if CONFIG_MEM_ADD_WDTH == 8 +# define CONFIG_EBCAW_VAL EBCAW_8 +# elif CONFIG_MEM_ADD_WDTH == 9 +# define CONFIG_EBCAW_VAL EBCAW_9 +# elif CONFIG_MEM_ADD_WDTH == 10 +# define CONFIG_EBCAW_VAL EBCAW_10 +# elif CONFIG_MEM_ADD_WDTH == 11 +# define CONFIG_EBCAW_VAL EBCAW_11 +# else +# error You need to define CONFIG_EBIU_SDBCTL_VAL or CONFIG_MEM_ADD_WDTH +# endif +# define CONFIG_EBIU_SDBCTL_VAL (CONFIG_EBCAW_VAL | CONFIG_EBSZ_VAL | EBE) +#endif +#endif + BOOTROM_CALLED_FUNC_ATTR void initcode(ADI_BOOT_DATA *bootstruct) { - uint32_t old_baud = serial_init(); + /* Save the clock pieces that are used in baud rate calculation */ + unsigned int sdivB, divB, vcoB; + serial_init(); + if (BFIN_DEBUG_EARLY_SERIAL || CONFIG_BFIN_BOOT_MODE == BFIN_BOOT_UART) { + sdivB = bfin_read_PLL_DIV() & 0xf; + vcoB = (bfin_read_PLL_CTL() >> 9) & 0x3f; + divB = serial_early_get_div(); + } + + serial_putc('A'); #ifdef CONFIG_HW_WATCHDOG # ifndef CONFIG_HW_WATCHDOG_TIMEOUT_INITCODE @@ -247,67 +276,110 @@ void initcode(ADI_BOOT_DATA *bootstruct) } #endif - serial_putc('S'); + serial_putc('B'); + + /* If external memory is enabled, put it into self refresh first. */ + bool put_into_srfs = false; +#ifdef EBIU_RSTCTL + if (bfin_read_EBIU_RSTCTL() & DDR_SRESET) { + bfin_write_EBIU_RSTCTL(bfin_read_EBIU_RSTCTL() | SRREQ); + put_into_srfs = true; + } +#else + if (bfin_read_EBIU_SDBCTL() & EBE) { + bfin_write_EBIU_SDGCTL(bfin_read_EBIU_SDGCTL() | SRFS); + put_into_srfs = true; + } +#endif + + serial_putc('C'); /* Blackfin bootroms use the SPI slow read opcode instead of the SPI * fast read, so we need to slow down the SPI clock a lot more during * boot. Once we switch over to u-boot's SPI flash driver, we'll * increase the speed appropriately. */ - if (CONFIG_BFIN_BOOT_MODE == BFIN_BOOT_SPI_MASTER) -#ifdef SPI0_BAUD - bfin_write_SPI0_BAUD(CONFIG_SPI_BAUD_INITBLOCK); -#else + if (CONFIG_BFIN_BOOT_MODE == BFIN_BOOT_SPI_MASTER) { + if (BOOTROM_SUPPORTS_SPI_FAST_READ && CONFIG_SPI_BAUD_INITBLOCK < 4) + bootstruct->dFlags |= BFLAG_FASTREAD; bfin_write_SPI_BAUD(CONFIG_SPI_BAUD_INITBLOCK); -#endif + } - serial_putc('B'); + serial_putc('D'); - /* Disable all peripheral wakeups except for the PLL event. */ -#ifdef SIC_IWR0 - bfin_write_SIC_IWR0(1); - bfin_write_SIC_IWR1(0); -# ifdef SIC_IWR2 - bfin_write_SIC_IWR2(0); -# endif -#elif defined(SICA_IWR0) - bfin_write_SICA_IWR0(1); - bfin_write_SICA_IWR1(0); + /* If we're entering self refresh, make sure it has happened. */ + if (put_into_srfs) +#ifdef EBIU_RSTCTL + while (!(bfin_read_EBIU_RSTCTL() & SRACK)) #else - bfin_write_SIC_IWR(1); + while (!(bfin_read_EBIU_SDSTAT() & SDSRA)) #endif + continue; + + serial_putc('E'); /* With newer bootroms, we use the helper function to set up * the memory controller. Older bootroms lacks such helpers * so we do it ourselves. */ - if (BOOTROM_CAPS_SYSCONTROL) { - serial_putc('S'); + uint16_t vr_ctl = bfin_read_VR_CTL(); + if (!ANOMALY_05000386) { + serial_putc('F'); ADI_SYSCTRL_VALUES memory_settings; - memory_settings.uwVrCtl = CONFIG_VR_CTL_VAL; + uint32_t actions = SYSCTRL_WRITE | SYSCTRL_PLLCTL | SYSCTRL_PLLDIV | SYSCTRL_LOCKCNT; + if (CONFIG_HAS_VR) { + actions |= SYSCTRL_VRCTL; + if (CONFIG_VR_CTL_VAL & FREQ_MASK) + actions |= SYSCTRL_INTVOLTAGE; + else + actions |= SYSCTRL_EXTVOLTAGE; + memory_settings.uwVrCtl = CONFIG_VR_CTL_VAL; + } else + actions |= SYSCTRL_EXTVOLTAGE; memory_settings.uwPllCtl = CONFIG_PLL_CTL_VAL; memory_settings.uwPllDiv = CONFIG_PLL_DIV_VAL; memory_settings.uwPllLockCnt = CONFIG_PLL_LOCKCNT_VAL; - syscontrol(SYSCTRL_WRITE | SYSCTRL_VRCTL | SYSCTRL_PLLCTL | SYSCTRL_PLLDIV | SYSCTRL_LOCKCNT | - (CONFIG_VR_CTL_VAL & FREQ_MASK ? SYSCTRL_INTVOLTAGE : SYSCTRL_EXTVOLTAGE), &memory_settings, NULL); +#if ANOMALY_05000432 + bfin_write_SIC_IWR1(0); +#endif + bfrom_SysControl(actions, &memory_settings, NULL); +#if ANOMALY_05000432 + bfin_write_SIC_IWR1(-1); +#endif } else { - serial_putc('L'); + serial_putc('G'); + + /* Disable all peripheral wakeups except for the PLL event. */ +#ifdef SIC_IWR0 + bfin_write_SIC_IWR0(1); + bfin_write_SIC_IWR1(0); +# ifdef SIC_IWR2 + bfin_write_SIC_IWR2(0); +# endif +#elif defined(SICA_IWR0) + bfin_write_SICA_IWR0(1); + bfin_write_SICA_IWR1(0); +#else + bfin_write_SIC_IWR(1); +#endif + + serial_putc('H'); bfin_write_PLL_LOCKCNT(CONFIG_PLL_LOCKCNT_VAL); - serial_putc('A'); + serial_putc('I'); /* Only reprogram when needed to avoid triggering unnecessary * PLL relock sequences. */ - if (bfin_read_VR_CTL() != CONFIG_VR_CTL_VAL) { + if (vr_ctl != CONFIG_VR_CTL_VAL) { serial_putc('!'); bfin_write_VR_CTL(CONFIG_VR_CTL_VAL); asm("idle;"); } - serial_putc('C'); + serial_putc('J'); bfin_write_PLL_DIV(CONFIG_PLL_DIV_VAL); @@ -321,30 +393,69 @@ void initcode(ADI_BOOT_DATA *bootstruct) bfin_write_PLL_CTL(CONFIG_PLL_CTL_VAL); asm("idle;"); } + + serial_putc('L'); + + /* Restore all peripheral wakeups. */ +#ifdef SIC_IWR0 + bfin_write_SIC_IWR0(-1); + bfin_write_SIC_IWR1(-1); +# ifdef SIC_IWR2 + bfin_write_SIC_IWR2(-1); +# endif +#elif defined(SICA_IWR0) + bfin_write_SICA_IWR0(-1); + bfin_write_SICA_IWR1(-1); +#else + bfin_write_SIC_IWR(-1); +#endif } + serial_putc('M'); + /* Since we've changed the SCLK above, we may need to update * the UART divisors (UART baud rates are based on SCLK). + * Do the division by hand as there are no native instructions + * for dividing which means we'd generate a libgcc reference. */ - serial_reset_baud(old_baud); + if (CONFIG_BFIN_BOOT_MODE == BFIN_BOOT_UART) { + unsigned int sdivR, vcoR; + sdivR = bfin_read_PLL_DIV() & 0xf; + vcoR = (bfin_read_PLL_CTL() >> 9) & 0x3f; + int dividend = sdivB * divB * vcoR; + int divisor = vcoB * sdivR; + unsigned int quotient; + for (quotient = 0; dividend > 0; ++quotient) + dividend -= divisor; + serial_early_put_div(quotient - ANOMALY_05000230); + } - serial_putc('F'); + serial_putc('N'); - /* Program the async banks controller. */ - bfin_write_EBIU_AMBCTL0(CONFIG_EBIU_AMBCTL0_VAL); - bfin_write_EBIU_AMBCTL1(CONFIG_EBIU_AMBCTL1_VAL); - bfin_write_EBIU_AMGCTL(CONFIG_EBIU_AMGCTL_VAL); + /* Program the external memory controller before we come out of + * self-refresh. This only works with our SDRAM controller. + */ +#ifndef EBIU_RSTCTL + bfin_write_EBIU_SDRRC(CONFIG_EBIU_SDRRC_VAL); + bfin_write_EBIU_SDBCTL(CONFIG_EBIU_SDBCTL_VAL); + bfin_write_EBIU_SDGCTL(CONFIG_EBIU_SDGCTL_VAL); +#endif -#ifdef EBIU_MODE - /* Not all parts have these additional MMRs. */ - bfin_write_EBIU_MBSCTL(CONFIG_EBIU_MBSCTL_VAL); - bfin_write_EBIU_MODE(CONFIG_EBIU_MODE_VAL); - bfin_write_EBIU_FCTL(CONFIG_EBIU_FCTL_VAL); + serial_putc('O'); + + /* Now that we've reprogrammed, take things out of self refresh. */ + if (put_into_srfs) +#ifdef EBIU_RSTCTL + bfin_write_EBIU_RSTCTL(bfin_read_EBIU_RSTCTL() & ~(SRREQ)); +#else + bfin_write_EBIU_SDGCTL(bfin_read_EBIU_SDGCTL() & ~(SRFS)); #endif - serial_putc('I'); + serial_putc('P'); - /* Program the external memory controller. */ + /* Our DDR controller sucks and cannot be programmed while in + * self-refresh. So we have to pull it out before programming. + */ #ifdef EBIU_RSTCTL bfin_write_EBIU_RSTCTL(bfin_read_EBIU_RSTCTL() | 0x1 /*DDRSRESET*/ | CONFIG_EBIU_RSTCTL_VAL); bfin_write_EBIU_DDRCTL0(CONFIG_EBIU_DDRCTL0_VAL); @@ -354,28 +465,64 @@ void initcode(ADI_BOOT_DATA *bootstruct) /* default is disable, so don't need to force this */ bfin_write_EBIU_DDRCTL3(CONFIG_EBIU_DDRCTL3_VAL); # endif -#else - bfin_write_EBIU_SDRRC(CONFIG_EBIU_SDRRC_VAL); - bfin_write_EBIU_SDBCTL(CONFIG_EBIU_SDBCTL_VAL); - bfin_write_EBIU_SDGCTL(CONFIG_EBIU_SDGCTL_VAL); +# ifdef CONFIG_EBIU_DDRQUE_VAL + bfin_write_EBIU_DDRQUE(bfin_read_EBIU_DDRQUE() | CONFIG_EBIU_DDRQUE_VAL); +# endif #endif - serial_putc('N'); + serial_putc('Q'); - /* Restore all peripheral wakeups. */ -#ifdef SIC_IWR0 - bfin_write_SIC_IWR0(-1); - bfin_write_SIC_IWR1(-1); -# ifdef SIC_IWR2 - bfin_write_SIC_IWR2(-1); -# endif -#elif defined(SICA_IWR0) - bfin_write_SICA_IWR0(-1); - bfin_write_SICA_IWR1(-1); -#else - bfin_write_SIC_IWR(-1); + /* Are we coming out of hibernate (suspend to memory) ? + * The memory layout is: + * 0x0: hibernate magic for anomaly 307 (0xDEADBEEF) + * 0x4: return address + * 0x8: stack pointer + * + * SCKELOW is unreliable on older parts (anomaly 307) + */ + if (ANOMALY_05000307 || vr_ctl & 0x8000) { + uint32_t *hibernate_magic = 0; + __builtin_bfin_ssync(); /* make sure memory controller is done */ + if (hibernate_magic[0] == 0xDEADBEEF) { + serial_putc('R'); + bfin_write_EVT15(hibernate_magic[1]); + bfin_write_IMASK(EVT_IVG15); + __asm__ __volatile__ ( + /* load reti early to avoid anomaly 281 */ + "reti = %0;" + /* clear hibernate magic */ + "[%0] = %1;" + /* load stack pointer */ + "SP = [%0 + 8];" + /* lower ourselves from reset ivg to ivg15 */ + "raise 15;" + "rti;" + : + : "p"(hibernate_magic), "d"(0x2000 /* jump.s 0 */) + ); + } + } + + serial_putc('S'); + + /* Program the async banks controller. */ + bfin_write_EBIU_AMBCTL0(CONFIG_EBIU_AMBCTL0_VAL); + bfin_write_EBIU_AMBCTL1(CONFIG_EBIU_AMBCTL1_VAL); + bfin_write_EBIU_AMGCTL(CONFIG_EBIU_AMGCTL_VAL); + +#ifdef EBIU_MODE + /* Not all parts have these additional MMRs. */ + bfin_write_EBIU_MBSCTL(CONFIG_EBIU_MBSCTL_VAL); + bfin_write_EBIU_MODE(CONFIG_EBIU_MODE_VAL); + bfin_write_EBIU_FCTL(CONFIG_EBIU_FCTL_VAL); #endif + serial_putc('T'); + + /* tell the bootrom where our entry point is */ + if (CONFIG_BFIN_BOOT_MODE != BFIN_BOOT_BYPASS) + bfin_write_EVT1(CONFIG_SYS_MONITOR_BASE); + serial_putc('>'); serial_putc('\n');