diff options
author | Sonic Zhang <sonic.zhang@analog.com> | 2012-08-16 11:56:14 +0800 |
---|---|---|
committer | sonic <sonic@sonic-linuxvm.(none)> | 2013-03-04 13:42:06 +0800 |
commit | a2979dcdbeb39a01dc888090d2c736c2ad3f548d (patch) | |
tree | a682537c30714af45a998e2c3cedbe495de05e52 /arch/blackfin/cpu/initcode.c | |
parent | 3ead92c571e7e17ca1c525c0fcd40e58901c5655 (diff) |
blackfin: bf60x: Port blackfin core architecture code to boot on bf60x.
Set up clocks, DDR controller, Nor flash controller, reboot,
serial port. Add new SPI boot modes.
Signed-off-by: Bob Liu <lliubbo@gmail.com>
Signed-off-by: Sonic Zhang <sonic.zhang@analog.com>
Signed-off-by: Sonic Zhang <sonic.adi@gmail.com>
Diffstat (limited to 'arch/blackfin/cpu/initcode.c')
-rw-r--r-- | arch/blackfin/cpu/initcode.c | 325 |
1 files changed, 306 insertions, 19 deletions
diff --git a/arch/blackfin/cpu/initcode.c b/arch/blackfin/cpu/initcode.c index fb3a101c79..a717148651 100644 --- a/arch/blackfin/cpu/initcode.c +++ b/arch/blackfin/cpu/initcode.c @@ -15,20 +15,141 @@ #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> #define BUG() while (1) { asm volatile("emuexcpt;"); } #include "serial.h" +#ifndef __ADSPBF60x__ +#include <asm/mach-common/bits/ebiu.h> +#include <asm/mach-common/bits/pll.h> +#else /* __ADSPBF60x__ */ +#include <asm/mach-common/bits/cgu.h> + +#define CONFIG_BFIN_GET_DCLK_M \ + ((CONFIG_CLKIN_HZ*CONFIG_VCO_MULT)/(CONFIG_DCLK_DIV*1000000)) + +#ifndef CONFIG_DMC_DDRCFG +#if ((CONFIG_BFIN_GET_DCLK_M != 125) && \ + (CONFIG_BFIN_GET_DCLK_M != 133) && \ + (CONFIG_BFIN_GET_DCLK_M != 150) && \ + (CONFIG_BFIN_GET_DCLK_M != 166) && \ + (CONFIG_BFIN_GET_DCLK_M != 200) && \ + (CONFIG_BFIN_GET_DCLK_M != 225) && \ + (CONFIG_BFIN_GET_DCLK_M != 250)) +#error "DDR2 CLK must be in (125, 133, 150, 166, 200, 225, 250)MHz" +#endif +#endif + +/* DMC control bits */ +#define SRREQ 0x8 + +/* DMC status bits */ +#define IDLE 0x1 +#define MEMINITDONE 0x4 +#define SRACK 0x8 +#define PDACK 0x10 +#define DPDACK 0x20 +#define DLLCALDONE 0x2000 +#define PENDREF 0xF0000 +#define PHYRDPHASE 0xF00000 +#define PHYRDPHASE_OFFSET 20 + +/* DMC DLL control bits */ +#define DLLCALRDCNT 0xFF +#define DATACYC_OFFSET 8 + +struct ddr_config { + u32 ddr_clk; + u32 dmc_ddrctl; + u32 dmc_ddrcfg; + u32 dmc_ddrtr0; + u32 dmc_ddrtr1; + u32 dmc_ddrtr2; + u32 dmc_ddrmr; + u32 dmc_ddrmr1; +}; + +static struct ddr_config ddr_config_table[] = { + [0] = { + .ddr_clk = 125, /* 125MHz */ + .dmc_ddrctl = 0x00000904, + .dmc_ddrcfg = 0x00000422, + .dmc_ddrtr0 = 0x20705212, + .dmc_ddrtr1 = 0x201003CF, + .dmc_ddrtr2 = 0x00320107, + .dmc_ddrmr = 0x00000422, + .dmc_ddrmr1 = 0x4, + }, + [1] = { + .ddr_clk = 133, /* 133MHz */ + .dmc_ddrctl = 0x00000904, + .dmc_ddrcfg = 0x00000422, + .dmc_ddrtr0 = 0x20806313, + .dmc_ddrtr1 = 0x2013040D, + .dmc_ddrtr2 = 0x00320108, + .dmc_ddrmr = 0x00000632, + .dmc_ddrmr1 = 0x4, + }, + [2] = { + .ddr_clk = 150, /* 150MHz */ + .dmc_ddrctl = 0x00000904, + .dmc_ddrcfg = 0x00000422, + .dmc_ddrtr0 = 0x20A07323, + .dmc_ddrtr1 = 0x20160492, + .dmc_ddrtr2 = 0x00320209, + .dmc_ddrmr = 0x00000632, + .dmc_ddrmr1 = 0x4, + }, + [3] = { + .ddr_clk = 166, /* 166MHz */ + .dmc_ddrctl = 0x00000904, + .dmc_ddrcfg = 0x00000422, + .dmc_ddrtr0 = 0x20A07323, + .dmc_ddrtr1 = 0x2016050E, + .dmc_ddrtr2 = 0x00320209, + .dmc_ddrmr = 0x00000632, + .dmc_ddrmr1 = 0x4, + }, + [4] = { + .ddr_clk = 200, /* 200MHz */ + .dmc_ddrctl = 0x00000904, + .dmc_ddrcfg = 0x00000422, + .dmc_ddrtr0 = 0x20a07323, + .dmc_ddrtr1 = 0x2016050f, + .dmc_ddrtr2 = 0x00320509, + .dmc_ddrmr = 0x00000632, + .dmc_ddrmr1 = 0x4, + }, + [5] = { + .ddr_clk = 225, /* 225MHz */ + .dmc_ddrctl = 0x00000904, + .dmc_ddrcfg = 0x00000422, + .dmc_ddrtr0 = 0x20E0A424, + .dmc_ddrtr1 = 0x302006DB, + .dmc_ddrtr2 = 0x0032020D, + .dmc_ddrmr = 0x00000842, + .dmc_ddrmr1 = 0x4, + }, + [6] = { + .ddr_clk = 250, /* 250MHz */ + .dmc_ddrctl = 0x00000904, + .dmc_ddrcfg = 0x00000422, + .dmc_ddrtr0 = 0x20E0A424, + .dmc_ddrtr1 = 0x3020079E, + .dmc_ddrtr2 = 0x0032050D, + .dmc_ddrmr = 0x00000842, + .dmc_ddrmr1 = 0x4, + }, +}; +#endif /* __ADSPBF60x__ */ + __attribute__((always_inline)) static inline void serial_init(void) { - uint32_t uart_base = UART_DLL; + uint32_t uart_base = UART_BASE; -#ifdef __ADSPBF54x__ +#if defined(__ADSPBF54x__) || defined(__ADSPBF60x__) # ifdef BFIN_BOOT_UART_USE_RTS # define BFIN_UART_USE_RTS 1 # else @@ -38,7 +159,12 @@ static inline void serial_init(void) size_t i; /* force RTS rather than relying on auto RTS */ +#if BFIN_UART_HW_VER < 4 bfin_write16(&pUART->mcr, bfin_read16(&pUART->mcr) | FCPOL); +#else + bfin_write32(&pUART->control, bfin_read32(&pUART->control) | + FCPOL); +#endif /* Wait for the line to clear up. We cannot rely on UART * registers as none of them reflect the status of the RSR. @@ -68,13 +194,14 @@ static inline void serial_init(void) #endif if (BFIN_DEBUG_EARLY_SERIAL) { - int ucen = bfin_read16(&pUART->gctl) & UCEN; + int enabled = serial_early_enabled(uart_base); + serial_early_init(uart_base); /* If the UART is off, that means we need to program * the baud rate ourselves initially. */ - if (ucen != UCEN) + if (!enabled) serial_early_set_baud(uart_base, CONFIG_BAUDRATE); } } @@ -82,12 +209,17 @@ static inline void serial_init(void) __attribute__((always_inline)) static inline void serial_deinit(void) { -#ifdef __ADSPBF54x__ - uint32_t uart_base = UART_DLL; +#if defined(__ADSPBF54x__) || defined(__ADSPBF60x__) + uint32_t uart_base = UART_BASE; if (BFIN_UART_USE_RTS && CONFIG_BFIN_BOOT_MODE == BFIN_BOOT_UART) { /* clear forced RTS rather than relying on auto RTS */ +#if BFIN_UART_HW_VER < 4 bfin_write16(&pUART->mcr, bfin_read16(&pUART->mcr) & ~FCPOL); +#else + bfin_write32(&pUART->control, bfin_read32(&pUART->control) & + ~FCPOL); +#endif } #endif } @@ -95,7 +227,7 @@ static inline void serial_deinit(void) __attribute__((always_inline)) static inline void serial_putc(char c) { - uint32_t uart_base = UART_DLL; + uint32_t uart_base = UART_BASE; if (!BFIN_DEBUG_EARLY_SERIAL) return; @@ -103,9 +235,9 @@ static inline void serial_putc(char c) if (c == '\n') serial_putc('\r'); - bfin_write16(&pUART->thr, c); + bfin_write(&pUART->thr, c); - while (!(bfin_read16(&pUART->lsr) & TEMT)) + while (!(_lsr_read(pUART) & TEMT)) continue; } @@ -152,6 +284,24 @@ program_nmi_handler(void) # define bfin_write_SPI_BAUD bfin_write_SPI0_BAUD #endif +#ifdef __ADSPBF60x__ + +#ifndef CONFIG_CGU_CTL_VAL +# define CONFIG_CGU_CTL_VAL ((CONFIG_VCO_MULT << 8) | CONFIG_CLKIN_HALF) +#endif + +#ifndef CONFIG_CGU_DIV_VAL +# define CONFIG_CGU_DIV_VAL \ + ((CONFIG_CCLK_DIV << CSEL_P) | \ + (CONFIG_SCLK0_DIV << S0SEL_P) | \ + (CONFIG_SCLK_DIV << SYSSEL_P) | \ + (CONFIG_SCLK1_DIV << S1SEL_P) | \ + (CONFIG_DCLK_DIV << DSEL_P) | \ + (CONFIG_OCLK_DIV << OSEL_P)) +#endif + +#else /* __ADSPBF60x__ */ + /* PLL_DIV defines */ #ifndef CONFIG_PLL_DIV_VAL # if (CONFIG_CCLK_DIV == 1) @@ -275,6 +425,8 @@ program_nmi_handler(void) # endif #endif +#endif /* __ADSPBF60x__ */ + __attribute__((always_inline)) static inline void program_early_devices(ADI_BOOT_DATA *bs, uint *sdivB, uint *divB, uint *vcoB) { @@ -283,8 +435,14 @@ program_early_devices(ADI_BOOT_DATA *bs, uint *sdivB, uint *divB, uint *vcoB) /* Save the clock pieces that are used in baud rate calculation */ if (BFIN_DEBUG_EARLY_SERIAL || CONFIG_BFIN_BOOT_MODE == BFIN_BOOT_UART) { serial_putc('b'); +#ifdef __ADSPBF60x__ + *sdivB = bfin_read_CGU_DIV(); + *sdivB = ((*sdivB >> 8) & 0x1f) * ((*sdivB >> 5) & 0x7); + *vcoB = (bfin_read_CGU_CTL() >> 8) & 0x7f; +#else *sdivB = bfin_read_PLL_DIV() & 0xf; *vcoB = (bfin_read_PLL_CTL() >> 9) & 0x3f; +#endif *divB = serial_early_get_div(); serial_putc('c'); } @@ -316,6 +474,7 @@ program_early_devices(ADI_BOOT_DATA *bs, uint *sdivB, uint *divB, uint *vcoB) * boot. Once we switch over to u-boot's SPI flash driver, we'll * increase the speed appropriately. */ +#ifdef SPI_BAUD if (CONFIG_BFIN_BOOT_MODE == BFIN_BOOT_SPI_MASTER) { serial_putc('h'); if (BOOTROM_SUPPORTS_SPI_FAST_READ && CONFIG_SPI_BAUD_INITBLOCK < 4) @@ -323,6 +482,7 @@ program_early_devices(ADI_BOOT_DATA *bs, uint *sdivB, uint *divB, uint *vcoB) bfin_write_SPI_BAUD(CONFIG_SPI_BAUD_INITBLOCK); serial_putc('i'); } +#endif serial_putc('j'); } @@ -335,6 +495,10 @@ maybe_self_refresh(ADI_BOOT_DATA *bs) if (!CONFIG_MEM_SIZE) return false; +#ifdef __ADSPBF60x__ + +#else /* __ADSPBF60x__ */ + /* If external memory is enabled, put it into self refresh first. */ #if defined(EBIU_RSTCTL) if (bfin_read_EBIU_RSTCTL() & DDR_SRESET) { @@ -350,6 +514,7 @@ maybe_self_refresh(ADI_BOOT_DATA *bs) } #endif +#endif /* __ADSPBF60x__ */ serial_putc('c'); return false; @@ -362,6 +527,37 @@ program_clocks(ADI_BOOT_DATA *bs, bool put_into_srfs) serial_putc('a'); +#ifdef __ADSPBF60x__ + if (bfin_read_DMC0_STAT() & MEMINITDONE) { + bfin_write_DMC0_CTL(bfin_read_DMC0_CTL() | SRREQ); + SSYNC(); + while (!(bfin_read_DMC0_STAT() & SRACK)) + continue; + } + + /* Don't set the same value of MSEL and DF to CGU_CTL */ + if ((bfin_read_CGU_CTL() & (MSEL_MASK | DF_MASK)) + != CONFIG_CGU_CTL_VAL) { + bfin_write_CGU_DIV(CONFIG_CGU_DIV_VAL); + bfin_write_CGU_CTL(CONFIG_CGU_CTL_VAL); + while ((bfin_read_CGU_STAT() & (CLKSALGN | PLLBP)) || + !(bfin_read_CGU_STAT() & PLLLK)) + continue; + } + + bfin_write_CGU_DIV(CONFIG_CGU_DIV_VAL | UPDT); + while (bfin_read_CGU_STAT() & CLKSALGN) + continue; + + if (bfin_read_DMC0_STAT() & MEMINITDONE) { + bfin_write_DMC0_CTL(bfin_read_DMC0_CTL() & ~SRREQ); + SSYNC(); + while (bfin_read_DMC0_STAT() & SRACK) + continue; + } + +#else /* __ADSPBF60x__ */ + vr_ctl = bfin_read_VR_CTL(); serial_putc('b'); @@ -433,7 +629,7 @@ program_clocks(ADI_BOOT_DATA *bs, bool put_into_srfs) #elif defined(SICA_IWR0) bfin_write_SICA_IWR0(1); bfin_write_SICA_IWR1(0); -#else +#elif defined(SIC_IWR) bfin_write_SIC_IWR(1); #endif @@ -482,13 +678,15 @@ program_clocks(ADI_BOOT_DATA *bs, bool put_into_srfs) #elif defined(SICA_IWR0) bfin_write_SICA_IWR0(-1); bfin_write_SICA_IWR1(-1); -#else +#elif defined(SIC_IWR) bfin_write_SIC_IWR(-1); #endif serial_putc('n'); } +#endif /* __ADSPBF60x__ */ + serial_putc('o'); return vr_ctl; @@ -505,16 +703,25 @@ update_serial_clocks(ADI_BOOT_DATA *bs, uint sdivB, uint divB, uint vcoB) * 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; int dividend = sdivB * divB * vcoR; int divisor = vcoB * sdivR; unsigned int quotient; + + serial_putc('b'); + +#ifdef __ADSPBF60x__ + sdivR = bfin_read_CGU_DIV(); + sdivR = ((sdivR >> 8) & 0x1f) * ((sdivR >> 5) & 0x7); + vcoR = (bfin_read_CGU_CTL() >> 8) & 0x7f; +#else + sdivR = bfin_read_PLL_DIV() & 0xf; + vcoR = (bfin_read_PLL_CTL() >> 9) & 0x3f; +#endif + for (quotient = 0; dividend > 0; ++quotient) dividend -= divisor; - serial_early_put_div(UART_DLL, quotient - ANOMALY_05000230); + serial_early_put_div(quotient - ANOMALY_05000230); serial_putc('c'); } @@ -531,6 +738,84 @@ program_memory_controller(ADI_BOOT_DATA *bs, bool put_into_srfs) serial_putc('b'); +#ifdef __ADSPBF60x__ + int dlldatacycle; + int dll_ctl; + int i = 0; + + if (CONFIG_BFIN_GET_DCLK_M == 125) + i = 0; + else if (CONFIG_BFIN_GET_DCLK_M == 133) + i = 1; + else if (CONFIG_BFIN_GET_DCLK_M == 150) + i = 2; + else if (CONFIG_BFIN_GET_DCLK_M == 166) + i = 3; + else if (CONFIG_BFIN_GET_DCLK_M == 200) + i = 4; + else if (CONFIG_BFIN_GET_DCLK_M == 225) + i = 5; + else if (CONFIG_BFIN_GET_DCLK_M == 250) + i = 6; + +#if 0 + for (i = 0; i < ARRAY_SIZE(ddr_config_table); i++) + if (CONFIG_BFIN_GET_DCLK_M == ddr_config_table[i].ddr_clk) + break; +#endif + +#ifndef CONFIG_DMC_DDRCFG + bfin_write_DMC0_CFG(ddr_config_table[i].dmc_ddrcfg); +#else + bfin_write_DMC0_CFG(CONFIG_DMC_DDRCFG); +#endif +#ifndef CONFIG_DMC_DDRTR0 + bfin_write_DMC0_TR0(ddr_config_table[i].dmc_ddrtr0); +#else + bfin_write_DMC0_TR0(CONFIG_DMC_DDRTR0); +#endif +#ifndef CONFIG_DMC_DDRTR1 + bfin_write_DMC0_TR1(ddr_config_table[i].dmc_ddrtr1); +#else + bfin_write_DMC0_TR1(CONFIG_DMC_DDRTR1); +#endif +#ifndef CONFIG_DMC_DDRTR2 + bfin_write_DMC0_TR2(ddr_config_table[i].dmc_ddrtr2); +#else + bfin_write_DMC0_TR2(CONFIG_DMC_DDRTR2); +#endif +#ifndef CONFIG_DMC_DDRMR + bfin_write_DMC0_MR(ddr_config_table[i].dmc_ddrmr); +#else + bfin_write_DMC0_MR(CONFIG_DMC_DDRMR); +#endif +#ifndef CONFIG_DMC_DDREMR1 + bfin_write_DMC0_EMR1(ddr_config_table[i].dmc_ddrmr1); +#else + bfin_write_DMC0_EMR1(CONFIG_DMC_DDREMR1); +#endif +#ifndef CONFIG_DMC_DDRCTL + bfin_write_DMC0_CTL(ddr_config_table[i].dmc_ddrctl); +#else + bfin_write_DMC0_CTL(CONFIG_DMC_DDRCTL); +#endif + + SSYNC(); + while (!(bfin_read_DMC0_STAT() & MEMINITDONE)) + continue; + + dlldatacycle = (bfin_read_DMC0_STAT() & PHYRDPHASE) >> + PHYRDPHASE_OFFSET; + dll_ctl = bfin_read_DMC0_DLLCTL(); + dll_ctl &= 0x0ff; + bfin_write_DMC0_DLLCTL(dll_ctl | (dlldatacycle << DATACYC_OFFSET)); + + SSYNC(); + while (!(bfin_read_DMC0_STAT() & DLLCALDONE)) + continue; + serial_putc('!'); +#else /* __ADSPBF60x__ */ + /* Program the external memory controller before we come out of * self-refresh. This only works with our SDRAM controller. */ @@ -583,6 +868,7 @@ program_memory_controller(ADI_BOOT_DATA *bs, bool put_into_srfs) # endif #endif +#endif /* __ADSPBF60x__ */ serial_putc('e'); } @@ -606,7 +892,8 @@ check_hibernation(ADI_BOOT_DATA *bs, u16 vr_ctl, bool put_into_srfs) */ if (ANOMALY_05000307 || vr_ctl & 0x8000) { uint32_t *hibernate_magic = 0; - __builtin_bfin_ssync(); /* make sure memory controller is done */ + + SSYNC(); if (hibernate_magic[0] == 0xDEADBEEF) { serial_putc('c'); bfin_write_EVT15(hibernate_magic[1]); |