diff options
author | Mike Frysinger <vapier@gentoo.org> | 2008-10-11 21:58:33 -0400 |
---|---|---|
committer | Mike Frysinger <vapier@gentoo.org> | 2009-03-23 15:14:55 -0400 |
commit | 74398b23f9c2ffdc137fd92910a46e3333fb93f9 (patch) | |
tree | 40b0cb30e95b29ab6866cea3d7754dc5ffb0732b /cpu/blackfin/initcode.c | |
parent | d347d572ab1f2d47bf257c9f7ca2e602038a136b (diff) | |
download | u-boot-imx-74398b23f9c2ffdc137fd92910a46e3333fb93f9.zip u-boot-imx-74398b23f9c2ffdc137fd92910a46e3333fb93f9.tar.gz u-boot-imx-74398b23f9c2ffdc137fd92910a46e3333fb93f9.tar.bz2 |
Blackfin: put memory into self-refresh before/after programming clocks
When initializing the core clocks, stick external memory into self-refresh.
This gains us a few cool things:
- support suspend-to-RAM with Linux
- reprogram clocks automatically when doing "go" on u-boot.bin in RAM
- make sure settings are stable before flashing new version
- finally fully unify initialize startup code path between LDR/non-LDR
Signed-off-by: Mike Frysinger <vapier@gentoo.org>
Diffstat (limited to 'cpu/blackfin/initcode.c')
-rw-r--r-- | cpu/blackfin/initcode.c | 189 |
1 files changed, 140 insertions, 49 deletions
diff --git a/cpu/blackfin/initcode.c b/cpu/blackfin/initcode.c index bbc2fa5..7bd4b22 100644 --- a/cpu/blackfin/initcode.c +++ b/cpu/blackfin/initcode.c @@ -12,6 +12,7 @@ #include <config.h> #include <asm/blackfin.h> #include <asm/mach-common/bits/bootrom.h> +#include <asm/mach-common/bits/core.h> #include <asm/mach-common/bits/ebiu.h> #include <asm/mach-common/bits/pll.h> #include <asm/mach-common/bits/uart.h> @@ -257,6 +258,8 @@ void initcode(ADI_BOOT_DATA *bootstruct) divB = serial_early_get_div(); } + serial_putc('A'); + #ifdef CONFIG_HW_WATCHDOG # ifndef CONFIG_HW_WATCHDOG_TIMEOUT_INITCODE # define CONFIG_HW_WATCHDOG_TIMEOUT_INITCODE 20000 @@ -273,7 +276,23 @@ 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 @@ -286,29 +305,26 @@ void initcode(ADI_BOOT_DATA *bootstruct) bfin_write_SPI_BAUD(CONFIG_SPI_BAUD_INITBLOCK); } - 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. */ -#define BOOTROM_CAPS_SYSCONTROL 0 - 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; uint32_t actions = SYSCTRL_WRITE | SYSCTRL_PLLCTL | SYSCTRL_PLLDIV | SYSCTRL_LOCKCNT; @@ -332,22 +348,38 @@ void initcode(ADI_BOOT_DATA *bootstruct) 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); @@ -361,8 +393,26 @@ 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 @@ -380,23 +430,32 @@ void initcode(ADI_BOOT_DATA *bootstruct) 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); @@ -406,28 +465,60 @@ 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); |