X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=cpu%2Fblackfin%2Finitcode.c;h=a039cbbbce12d4969b5d9a3f9b2b2452da37f721;hb=f15f14e52879711be1d1bba2634dec684eda722e;hp=6091f8cef194a1b06fc7c248ccbf6fc995efac2f;hpb=9d8811c5bd2b7dd6307742cf22fbdb7953b6f816;p=oweals%2Fu-boot.git diff --git a/cpu/blackfin/initcode.c b/cpu/blackfin/initcode.c index 6091f8cef1..a039cbbbce 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) { @@ -124,7 +92,7 @@ static inline void serial_putc(char c) return; if (c == '\n') - *pUART_THR = '\r'; + serial_putc('\r'); *pUART_THR = 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 */ @@ -168,11 +146,18 @@ static inline void serial_putc(char c) #ifndef CONFIG_EBIU_RSTCTL_VAL # define CONFIG_EBIU_RSTCTL_VAL 0 /* only MDDRENABLE is useful */ #endif +#if ((CONFIG_EBIU_RSTCTL_VAL & 0xFFFFFFC4) != 0) +# error invalid EBIU_RSTCTL value: must not set reserved bits +#endif #ifndef CONFIG_EBIU_MBSCTL_VAL # define CONFIG_EBIU_MBSCTL_VAL 0 #endif +#if defined(CONFIG_EBIU_DDRQUE_VAL) && ((CONFIG_EBIU_DDRQUE_VAL & 0xFFFF8000) != 0) +# error invalid EBIU_DDRQUE value: must not set reserved bits +#endif + /* Make sure our voltage value is sane so we don't blow up! */ #ifndef CONFIG_VR_CTL_VAL # define BFIN_CCLK ((CONFIG_CLKIN_HZ * CONFIG_VCO_MULT) / CONFIG_CCLK_DIV) @@ -199,6 +184,9 @@ static inline void serial_putc(char c) # elif defined(__ADSPBF54x__) /* TBD; use default */ # undef CONFIG_VR_CTL_VLEV # define CONFIG_VR_CTL_VLEV VLEV_120 +# elif defined(__ADSPBF538__) || defined(__ADSPBF539__) /* TBD; use default */ +# undef CONFIG_VR_CTL_VLEV +# define CONFIG_VR_CTL_VLEV VLEV_125 # endif # ifdef CONFIG_BFIN_MAC @@ -216,10 +204,79 @@ 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 -__attribute__((saveall)) +/* 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 + +/* Conflicting Column Address Widths Causes SDRAM Errors: + * EB2CAW and EB3CAW must be the same + */ +#if ANOMALY_05000362 +# if ((CONFIG_EBIU_SDBCTL_VAL & 0x30000000) >> 8) != (CONFIG_EBIU_SDBCTL_VAL & 0x00300000) +# error "Anomaly 05000362: EB2CAW and EB3CAW must be the same" +# endif +#endif + +BOOTROM_CALLED_FUNC_ATTR void initcode(ADI_BOOT_DATA *bootstruct) { - uint32_t old_baud = serial_init(); + ADI_BOOT_DATA bootstruct_scratch; + + /* 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'); + + /* If the bootstruct is NULL, then it's because we're loading + * dynamically and not via LDR (bootrom). So set the struct to + * some scratch space. + */ + if (!bootstruct) + bootstruct = &bootstruct_scratch; #ifdef CONFIG_HW_WATCHDOG # ifndef CONFIG_HW_WATCHDOG_TIMEOUT_INITCODE @@ -237,88 +294,192 @@ 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); + } + + serial_putc('D'); + + /* 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 + while (!(bfin_read_EBIU_SDSTAT() & SDSRA)) #endif + continue; - serial_putc('B'); + serial_putc('E'); - /* Disable all peripheral wakeups except for the PLL event. */ + /* With newer bootroms, we use the helper function to set up + * the memory controller. Older bootroms lacks such helpers + * so we do it ourselves. + */ + uint16_t vr_ctl = bfin_read_VR_CTL(); + if (!ANOMALY_05000386) { + serial_putc('F'); + + /* Always programming PLL_LOCKCNT avoids Anomaly 05000430 */ + ADI_SYSCTRL_VALUES memory_settings; + 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; +#if ANOMALY_05000432 + bfin_write_SIC_IWR1(0); +#endif + bfrom_SysControl(actions, &memory_settings, NULL); +#if ANOMALY_05000432 + bfin_write_SIC_IWR1(-1); +#endif +#if ANOMALY_05000171 + bfin_write_SICA_IWR0(-1); + bfin_write_SICA_IWR1(-1); +#endif + } else { + 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); + bfin_write_SIC_IWR0(1); + bfin_write_SIC_IWR1(0); # ifdef SIC_IWR2 - bfin_write_SIC_IWR2(0); + bfin_write_SIC_IWR2(0); # endif #elif defined(SICA_IWR0) - bfin_write_SICA_IWR0(1); - bfin_write_SICA_IWR1(0); + bfin_write_SICA_IWR0(1); + bfin_write_SICA_IWR1(0); #else - bfin_write_SIC_IWR(1); + bfin_write_SIC_IWR(1); #endif - serial_putc('L'); + serial_putc('H'); - bfin_write_PLL_LOCKCNT(CONFIG_PLL_LOCKCNT_VAL); + /* Always programming PLL_LOCKCNT avoids Anomaly 05000430 */ + 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) { - serial_putc('!'); - bfin_write_VR_CTL(CONFIG_VR_CTL_VAL); - asm("idle;"); - } + /* Only reprogram when needed to avoid triggering unnecessary + * PLL relock sequences. + */ + 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); + bfin_write_PLL_DIV(CONFIG_PLL_DIV_VAL); - serial_putc('K'); + serial_putc('K'); - /* Only reprogram when needed to avoid triggering unnecessary - * PLL relock sequences. - */ - if (bfin_read_PLL_CTL() != CONFIG_PLL_CTL_VAL) { - serial_putc('!'); - bfin_write_PLL_CTL(CONFIG_PLL_CTL_VAL); - asm("idle;"); + /* Only reprogram when needed to avoid triggering unnecessary + * PLL relock sequences. + */ + if (ANOMALY_05000242 || bfin_read_PLL_CTL() != CONFIG_PLL_CTL_VAL) { + serial_putc('!'); + 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); @@ -328,26 +489,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'); + +#ifdef CONFIG_BFIN_BOOTROM_USES_EVT1 + /* tell the bootrom where our entry point is */ + if (CONFIG_BFIN_BOOT_MODE != BFIN_BOOT_BYPASS) + bfin_write_EVT1(CONFIG_SYS_MONITOR_BASE); #endif serial_putc('>');