diff options
author | Mike Frysinger <vapier@gentoo.org> | 2009-11-09 19:44:04 -0500 |
---|---|---|
committer | Mike Frysinger <vapier@gentoo.org> | 2010-01-17 09:17:26 -0500 |
commit | dbda2c65e5fec92d0791367b53042983746ce95b (patch) | |
tree | 12572c9cd6e7eb4f4ef62c2199391a71462fe1e2 /cpu/blackfin | |
parent | f5402d4c27e471c333cb84a82a437e60c6182449 (diff) | |
download | u-boot-imx-dbda2c65e5fec92d0791367b53042983746ce95b.zip u-boot-imx-dbda2c65e5fec92d0791367b53042983746ce95b.tar.gz u-boot-imx-dbda2c65e5fec92d0791367b53042983746ce95b.tar.bz2 |
Blackfin: re-architect initcode
The single initcode function was growing unwieldy, so split it up the
distinct steps into their own function. This should making digesting the
result much easier on people.
Signed-off-by: Mike Frysinger <vapier@gentoo.org>
Diffstat (limited to 'cpu/blackfin')
-rw-r--r-- | cpu/blackfin/initcode.c | 221 |
1 files changed, 169 insertions, 52 deletions
diff --git a/cpu/blackfin/initcode.c b/cpu/blackfin/initcode.c index a039cbb..bb58898 100644 --- a/cpu/blackfin/initcode.c +++ b/cpu/blackfin/initcode.c @@ -9,6 +9,8 @@ * Licensed under the GPL-2 or later. */ +#define BFIN_IN_INITCODE + #include <config.h> #include <asm/blackfin.h> #include <asm/mach-common/bits/bootrom.h> @@ -17,7 +19,6 @@ #include <asm/mach-common/bits/pll.h> #include <asm/mach-common/bits/uart.h> -#define BFIN_IN_INITCODE #include "serial.h" __attribute__((always_inline)) @@ -213,6 +214,7 @@ static inline void serial_putc(char c) # define CONFIG_HAS_VR 1 #endif +#if CONFIG_MEM_SIZE #ifndef EBIU_RSTCTL /* Blackfin with SDRAM */ #ifndef CONFIG_EBIU_SDBCTL_VAL @@ -245,6 +247,7 @@ static inline void serial_putc(char c) # define CONFIG_EBIU_SDBCTL_VAL (CONFIG_EBCAW_VAL | CONFIG_EBSZ_VAL | EBE) #endif #endif +#endif /* Conflicting Column Address Widths Causes SDRAM Errors: * EB2CAW and EB3CAW must be the same @@ -255,28 +258,21 @@ static inline void serial_putc(char c) # endif #endif -BOOTROM_CALLED_FUNC_ATTR -void initcode(ADI_BOOT_DATA *bootstruct) +__attribute__((always_inline)) static inline void +program_early_devices(ADI_BOOT_DATA *bs, uint *sdivB, uint *divB, uint *vcoB) { - ADI_BOOT_DATA bootstruct_scratch; + serial_putc('a'); /* 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('b'); + *sdivB = bfin_read_PLL_DIV() & 0xf; + *vcoB = (bfin_read_PLL_CTL() >> 9) & 0x3f; + *divB = serial_early_get_div(); + serial_putc('c'); } - 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; + serial_putc('d'); #ifdef CONFIG_HW_WATCHDOG # ifndef CONFIG_HW_WATCHDOG_TIMEOUT_INITCODE @@ -289,41 +285,69 @@ void initcode(ADI_BOOT_DATA *bootstruct) * timeout, so don't clobber that. */ if (CONFIG_BFIN_BOOT_MODE != BFIN_BOOT_BYPASS) { + serial_putc('e'); bfin_write_WDOG_CNT(MSEC_TO_SCLK(CONFIG_HW_WATCHDOG_TIMEOUT_INITCODE)); bfin_write_WDOG_CTL(0); + serial_putc('f'); } #endif - serial_putc('B'); + serial_putc('g'); + + /* 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) { + serial_putc('h'); + if (BOOTROM_SUPPORTS_SPI_FAST_READ && CONFIG_SPI_BAUD_INITBLOCK < 4) + bs->dFlags |= BFLAG_FASTREAD; + bfin_write_SPI_BAUD(CONFIG_SPI_BAUD_INITBLOCK); + serial_putc('i'); + } + + serial_putc('j'); +} + +__attribute__((always_inline)) static inline bool +maybe_self_refresh(ADI_BOOT_DATA *bs) +{ + serial_putc('a'); + + if (!CONFIG_MEM_SIZE) + return false; /* 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) { + serial_putc('b'); bfin_write_EBIU_RSTCTL(bfin_read_EBIU_RSTCTL() | SRREQ); - put_into_srfs = true; + return true; } #else if (bfin_read_EBIU_SDBCTL() & EBE) { + serial_putc('b'); bfin_write_EBIU_SDGCTL(bfin_read_EBIU_SDGCTL() | SRFS); - put_into_srfs = true; + return true; } #endif - serial_putc('C'); + 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) { - if (BOOTROM_SUPPORTS_SPI_FAST_READ && CONFIG_SPI_BAUD_INITBLOCK < 4) - bootstruct->dFlags |= BFLAG_FASTREAD; - bfin_write_SPI_BAUD(CONFIG_SPI_BAUD_INITBLOCK); - } + return false; +} - serial_putc('D'); +__attribute__((always_inline)) static inline u16 +program_clocks(ADI_BOOT_DATA *bs, bool put_into_srfs) +{ + u16 vr_ctl; + + serial_putc('a'); + + vr_ctl = bfin_read_VR_CTL(); + + serial_putc('b'); /* If we're entering self refresh, make sure it has happened. */ if (put_into_srfs) @@ -334,15 +358,14 @@ void initcode(ADI_BOOT_DATA *bootstruct) #endif continue; - serial_putc('E'); + serial_putc('c'); /* 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'); + serial_putc('d'); /* Always programming PLL_LOCKCNT avoids Anomaly 05000430 */ ADI_SYSCTRL_VALUES memory_settings; @@ -362,7 +385,9 @@ void initcode(ADI_BOOT_DATA *bootstruct) #if ANOMALY_05000432 bfin_write_SIC_IWR1(0); #endif + serial_putc('e'); bfrom_SysControl(actions, &memory_settings, NULL); + serial_putc('f'); #if ANOMALY_05000432 bfin_write_SIC_IWR1(-1); #endif @@ -370,8 +395,9 @@ void initcode(ADI_BOOT_DATA *bootstruct) bfin_write_SICA_IWR0(-1); bfin_write_SICA_IWR1(-1); #endif + serial_putc('g'); } else { - serial_putc('G'); + serial_putc('h'); /* Disable all peripheral wakeups except for the PLL event. */ #ifdef SIC_IWR0 @@ -387,38 +413,40 @@ void initcode(ADI_BOOT_DATA *bootstruct) bfin_write_SIC_IWR(1); #endif - serial_putc('H'); + serial_putc('i'); /* Always programming PLL_LOCKCNT avoids Anomaly 05000430 */ bfin_write_PLL_LOCKCNT(CONFIG_PLL_LOCKCNT_VAL); - serial_putc('I'); + serial_putc('j'); /* Only reprogram when needed to avoid triggering unnecessary * PLL relock sequences. */ if (vr_ctl != CONFIG_VR_CTL_VAL) { - serial_putc('!'); + serial_putc('?'); bfin_write_VR_CTL(CONFIG_VR_CTL_VAL); asm("idle;"); + serial_putc('!'); } - serial_putc('J'); + serial_putc('k'); bfin_write_PLL_DIV(CONFIG_PLL_DIV_VAL); - serial_putc('K'); + serial_putc('l'); /* Only reprogram when needed to avoid triggering unnecessary * PLL relock sequences. */ if (ANOMALY_05000242 || bfin_read_PLL_CTL() != CONFIG_PLL_CTL_VAL) { - serial_putc('!'); + serial_putc('?'); bfin_write_PLL_CTL(CONFIG_PLL_CTL_VAL); asm("idle;"); + serial_putc('!'); } - serial_putc('L'); + serial_putc('m'); /* Restore all peripheral wakeups. */ #ifdef SIC_IWR0 @@ -433,9 +461,19 @@ void initcode(ADI_BOOT_DATA *bootstruct) #else bfin_write_SIC_IWR(-1); #endif + + serial_putc('n'); } - serial_putc('M'); + serial_putc('o'); + + return vr_ctl; +} + +__attribute__((always_inline)) static inline void +update_serial_clocks(ADI_BOOT_DATA *bs, uint sdivB, uint divB, uint vcoB) +{ + serial_putc('a'); /* Since we've changed the SCLK above, we may need to update * the UART divisors (UART baud rates are based on SCLK). @@ -443,6 +481,7 @@ void initcode(ADI_BOOT_DATA *bootstruct) * for dividing which means we'd generate a libgcc reference. */ if (CONFIG_BFIN_BOOT_MODE == BFIN_BOOT_UART) { + serial_putc('b'); unsigned int sdivR, vcoR; sdivR = bfin_read_PLL_DIV() & 0xf; vcoR = (bfin_read_PLL_CTL() >> 9) & 0x3f; @@ -452,20 +491,38 @@ void initcode(ADI_BOOT_DATA *bootstruct) for (quotient = 0; dividend > 0; ++quotient) dividend -= divisor; serial_early_put_div(quotient - ANOMALY_05000230); + serial_putc('c'); } - serial_putc('N'); + serial_putc('d'); +} + +__attribute__((always_inline)) static inline void +program_memory_controller(ADI_BOOT_DATA *bs, bool put_into_srfs) +{ + serial_putc('a'); + + if (!CONFIG_MEM_SIZE) + return; + + serial_putc('b'); /* Program the external memory controller before we come out of * self-refresh. This only works with our SDRAM controller. */ #ifndef EBIU_RSTCTL +# ifdef CONFIG_EBIU_SDRRC_VAL bfin_write_EBIU_SDRRC(CONFIG_EBIU_SDRRC_VAL); +# endif +# ifdef CONFIG_EBIU_SDBCTL_VAL bfin_write_EBIU_SDBCTL(CONFIG_EBIU_SDBCTL_VAL); +# endif +# ifdef CONFIG_EBIU_SDGCTL_VAL bfin_write_EBIU_SDGCTL(CONFIG_EBIU_SDGCTL_VAL); +# endif #endif - serial_putc('O'); + serial_putc('c'); /* Now that we've reprogrammed, take things out of self refresh. */ if (put_into_srfs) @@ -475,7 +532,7 @@ void initcode(ADI_BOOT_DATA *bootstruct) bfin_write_EBIU_SDGCTL(bfin_read_EBIU_SDGCTL() & ~(SRFS)); #endif - serial_putc('P'); + serial_putc('d'); /* Our DDR controller sucks and cannot be programmed while in * self-refresh. So we have to pull it out before programming. @@ -494,7 +551,18 @@ void initcode(ADI_BOOT_DATA *bootstruct) # endif #endif - serial_putc('Q'); + serial_putc('e'); +} + +__attribute__((always_inline)) static inline void +check_hibernation(ADI_BOOT_DATA *bs, u16 vr_ctl, bool put_into_srfs) +{ + serial_putc('a'); + + if (!CONFIG_MEM_SIZE) + return; + + serial_putc('b'); /* Are we coming out of hibernate (suspend to memory) ? * The memory layout is: @@ -508,7 +576,7 @@ void initcode(ADI_BOOT_DATA *bootstruct) uint32_t *hibernate_magic = 0; __builtin_bfin_ssync(); /* make sure memory controller is done */ if (hibernate_magic[0] == 0xDEADBEEF) { - serial_putc('R'); + serial_putc('c'); bfin_write_EVT15(hibernate_magic[1]); bfin_write_IMASK(EVT_IVG15); __asm__ __volatile__ ( @@ -525,15 +593,24 @@ void initcode(ADI_BOOT_DATA *bootstruct) : "p"(hibernate_magic), "d"(0x2000 /* jump.s 0 */) ); } + serial_putc('d'); } - serial_putc('S'); + serial_putc('e'); +} + +__attribute__((always_inline)) static inline void +program_async_controller(ADI_BOOT_DATA *bs) +{ + serial_putc('a'); /* 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); + serial_putc('b'); + #ifdef EBIU_MODE /* Not all parts have these additional MMRs. */ bfin_write_EBIU_MBSCTL(CONFIG_EBIU_MBSCTL_VAL); @@ -541,9 +618,49 @@ void initcode(ADI_BOOT_DATA *bootstruct) bfin_write_EBIU_FCTL(CONFIG_EBIU_FCTL_VAL); #endif - serial_putc('T'); + serial_putc('c'); +} + +BOOTROM_CALLED_FUNC_ATTR +void initcode(ADI_BOOT_DATA *bs) +{ + ADI_BOOT_DATA bootstruct_scratch; + + serial_init(); + + 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 (!bs) + bs = &bootstruct_scratch; + + serial_putc('B'); + bool put_into_srfs = maybe_self_refresh(bs); + + serial_putc('C'); + uint sdivB, divB, vcoB; + program_early_devices(bs, &sdivB, &divB, &vcoB); + + serial_putc('D'); + u16 vr_ctl = program_clocks(bs, put_into_srfs); + + serial_putc('E'); + update_serial_clocks(bs, sdivB, divB, vcoB); + + serial_putc('F'); + program_memory_controller(bs, put_into_srfs); + + serial_putc('G'); + check_hibernation(bs, vr_ctl, put_into_srfs); + + serial_putc('H'); + program_async_controller(bs); #ifdef CONFIG_BFIN_BOOTROM_USES_EVT1 + serial_putc('I'); /* tell the bootrom where our entry point is */ if (CONFIG_BFIN_BOOT_MODE != BFIN_BOOT_BYPASS) bfin_write_EVT1(CONFIG_SYS_MONITOR_BASE); |