diff options
Diffstat (limited to 'cpu/blackfin')
-rw-r--r-- | cpu/blackfin/Makefile | 2 | ||||
-rw-r--r-- | cpu/blackfin/cpu.c | 11 | ||||
-rw-r--r-- | cpu/blackfin/initcode.c | 247 | ||||
-rw-r--r-- | cpu/blackfin/interrupt.S | 11 | ||||
-rw-r--r-- | cpu/blackfin/interrupts.c | 12 | ||||
-rw-r--r-- | cpu/blackfin/serial.c | 26 | ||||
-rw-r--r-- | cpu/blackfin/serial.h | 121 | ||||
-rw-r--r-- | cpu/blackfin/start.S | 24 | ||||
-rw-r--r-- | cpu/blackfin/traps.c | 9 | ||||
-rw-r--r-- | cpu/blackfin/watchdog.c | 4 |
10 files changed, 314 insertions, 153 deletions
diff --git a/cpu/blackfin/Makefile b/cpu/blackfin/Makefile index 5eef6a3..211b8d5 100644 --- a/cpu/blackfin/Makefile +++ b/cpu/blackfin/Makefile @@ -24,7 +24,7 @@ COBJS-y += os_log.o COBJS-y += reset.o COBJS-y += serial.o COBJS-y += traps.o -COBJS-y += watchdog.o +COBJS-$(CONFIG_HW_WATCHDOG) += watchdog.o ifeq ($(CONFIG_BFIN_BOOT_MODE),BFIN_BOOT_BYPASS) COBJS-y += initcode.o diff --git a/cpu/blackfin/cpu.c b/cpu/blackfin/cpu.c index 9bb6407..2c8fd86 100644 --- a/cpu/blackfin/cpu.c +++ b/cpu/blackfin/cpu.c @@ -25,13 +25,12 @@ ulong bfin_poweron_retx; __attribute__ ((__noreturn__)) void cpu_init_f(ulong bootflag, ulong loaded_from_ldr) { - extern char _stext_l1; #ifndef CONFIG_BFIN_BOOTROM_USES_EVT1 /* Build a NOP slide over the LDR jump block. Whee! */ char nops[0xC]; serial_early_puts("NOP Slide\n"); memset(nops, 0x00, sizeof(nops)); - memcpy(&_stext_l1 - sizeof(nops), nops, sizeof(nops)); + memcpy((void *)L1_INST_SRAM, nops, sizeof(nops)); #endif if (!loaded_from_ldr) { @@ -40,10 +39,10 @@ void cpu_init_f(ulong bootflag, ulong loaded_from_ldr) * checking at build time. */ serial_early_puts("L1 Relocate\n"); - extern char _stext_l1, _etext_l1, _stext_l1_lma; - memcpy(&_stext_l1, &_stext_l1_lma, (&_etext_l1 - &_stext_l1)); - extern char _sdata_l1, _edata_l1, _sdata_l1_lma; - memcpy(&_sdata_l1, &_sdata_l1_lma, (&_edata_l1 - &_sdata_l1)); + extern char _stext_l1[], _text_l1_lma[], _text_l1_len[]; + memcpy(&_stext_l1, &_text_l1_lma, (unsigned long)_text_l1_len); + extern char _sdata_l1[], _data_l1_lma[], _data_l1_len[]; + memcpy(&_sdata_l1, &_data_l1_lma, (unsigned long)_data_l1_len); } #if defined(__ADSPBF537__) || defined(__ADSPBF536__) || defined(__ADSPBF534__) /* The BF537 bootrom will reset the EBIU_AMGCTL register on us diff --git a/cpu/blackfin/initcode.c b/cpu/blackfin/initcode.c index a039cbb..5f80ad6 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)) @@ -33,7 +34,7 @@ static inline void serial_init(void) size_t i; /* force RTS rather than relying on auto RTS */ - bfin_write_UART1_MCR(bfin_read_UART1_MCR() | FCPOL); + bfin_write16(&pUART->mcr, bfin_read16(&pUART->mcr) | FCPOL); /* Wait for the line to clear up. We cannot rely on UART * registers as none of them reflect the status of the RSR. @@ -63,7 +64,7 @@ static inline void serial_init(void) #endif if (BFIN_DEBUG_EARLY_SERIAL) { - int ucen = *pUART_GCTL & UCEN; + int ucen = bfin_read16(&pUART->gctl) & UCEN; serial_early_init(); /* If the UART is off, that means we need to program @@ -80,7 +81,7 @@ static inline void serial_deinit(void) #ifdef __ADSPBF54x__ if (BFIN_UART_USE_RTS && CONFIG_BFIN_BOOT_MODE == BFIN_BOOT_UART) { /* clear forced RTS rather than relying on auto RTS */ - bfin_write_UART1_MCR(bfin_read_UART1_MCR() & ~FCPOL); + bfin_write16(&pUART->mcr, bfin_read16(&pUART->mcr) & ~FCPOL); } #endif } @@ -94,9 +95,9 @@ static inline void serial_putc(char c) if (c == '\n') serial_putc('\r'); - *pUART_THR = c; + bfin_write16(&pUART->thr, c); - while (!(*pUART_LSR & TEMT)) + while (!(bfin_read16(&pUART->lsr) & TEMT)) continue; } @@ -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,16 +532,24 @@ 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. */ #ifdef EBIU_RSTCTL +# ifdef CONFIG_EBIU_RSTCTL_VAL bfin_write_EBIU_RSTCTL(bfin_read_EBIU_RSTCTL() | 0x1 /*DDRSRESET*/ | CONFIG_EBIU_RSTCTL_VAL); +# endif +# ifdef CONFIG_EBIU_DDRCTL0_VAL bfin_write_EBIU_DDRCTL0(CONFIG_EBIU_DDRCTL0_VAL); +# endif +# ifdef CONFIG_EBIU_DDRCTL1_VAL bfin_write_EBIU_DDRCTL1(CONFIG_EBIU_DDRCTL1_VAL); +# endif +# ifdef CONFIG_EBIU_DDRCTL2_VAL bfin_write_EBIU_DDRCTL2(CONFIG_EBIU_DDRCTL2_VAL); +# endif # ifdef CONFIG_EBIU_DDRCTL3_VAL /* default is disable, so don't need to force this */ bfin_write_EBIU_DDRCTL3(CONFIG_EBIU_DDRCTL3_VAL); @@ -494,7 +559,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 +584,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,25 +601,80 @@ 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); -#ifdef EBIU_MODE + serial_putc('b'); + /* Not all parts have these additional MMRs. */ +#ifdef EBIU_MODE +# ifdef CONFIG_EBIU_MBSCTL_VAL bfin_write_EBIU_MBSCTL(CONFIG_EBIU_MBSCTL_VAL); +# endif +# ifdef CONFIG_EBIU_MODE_VAL bfin_write_EBIU_MODE(CONFIG_EBIU_MODE_VAL); +# endif +# ifdef CONFIG_EBIU_FCTL_VAL bfin_write_EBIU_FCTL(CONFIG_EBIU_FCTL_VAL); +# endif #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); diff --git a/cpu/blackfin/interrupt.S b/cpu/blackfin/interrupt.S index 71e0fc6..8c7a262 100644 --- a/cpu/blackfin/interrupt.S +++ b/cpu/blackfin/interrupt.S @@ -1,7 +1,7 @@ /* * interrupt.S - trampoline default exceptions/interrupts to C handlers * - * Copyright (c) 2005-2007 Analog Devices Inc. + * Copyright (c) 2005-2009 Analog Devices Inc. * Licensed under the GPL-2 or later. */ @@ -17,10 +17,19 @@ ENTRY(_trap) sp.l = LO(L1_SRAM_SCRATCH_END - 20); sp.h = HI(L1_SRAM_SCRATCH_END - 20); SAVE_ALL_SYS + r0 = sp; /* stack frame pt_regs pointer argument ==> r0 */ sp += -12; call _trap_c; sp += 12; + +#if ANOMALY_05000257 + R7 = LC0; + LC0 = R7; + R7 = LC1; + LC1 = R7; +#endif + RESTORE_ALL_SYS sp = CONFIG_BFIN_SCRATCH_REG; rtx; diff --git a/cpu/blackfin/interrupts.c b/cpu/blackfin/interrupts.c index 921bfe0..54a67b4 100644 --- a/cpu/blackfin/interrupts.c +++ b/cpu/blackfin/interrupts.c @@ -97,12 +97,12 @@ void __udelay(unsigned long usec) #define MAX_TIM_LOAD 0xFFFFFFFF int timer_init(void) { - *pTCNTL = 0x1; + bfin_write_TCNTL(0x1); CSYNC(); - *pTSCALE = 0x0; - *pTCOUNT = MAX_TIM_LOAD; - *pTPERIOD = MAX_TIM_LOAD; - *pTCNTL = 0x7; + bfin_write_TSCALE(0x0); + bfin_write_TCOUNT(MAX_TIM_LOAD); + bfin_write_TPERIOD(MAX_TIM_LOAD); + bfin_write_TCNTL(0x7); CSYNC(); timestamp = 0; @@ -130,7 +130,7 @@ ulong get_timer(ulong base) ulong milisec; /* Number of clocks elapsed */ - ulong clocks = (MAX_TIM_LOAD - (*pTCOUNT)); + ulong clocks = (MAX_TIM_LOAD - bfin_read_TCOUNT()); /* * Find if the TCOUNT is reset diff --git a/cpu/blackfin/serial.c b/cpu/blackfin/serial.c index 2abda18..901cb97 100644 --- a/cpu/blackfin/serial.c +++ b/cpu/blackfin/serial.c @@ -44,10 +44,6 @@ #ifdef CONFIG_UART_CONSOLE -#if defined(UART_LSR) && (CONFIG_UART_CONSOLE != 0) -# error CONFIG_UART_CONSOLE must be 0 on parts with only one UART -#endif - #include "serial.h" #ifdef CONFIG_DEBUG_SERIAL @@ -63,7 +59,7 @@ size_t cache_count; static uint16_t uart_lsr_save; static uint16_t uart_lsr_read(void) { - uint16_t lsr = *pUART_LSR; + uint16_t lsr = bfin_read16(&pUART->lsr); uart_lsr_save |= (lsr & (OE|PE|FE|BI)); return lsr | uart_lsr_save; } @@ -71,15 +67,21 @@ static uint16_t uart_lsr_read(void) static void uart_lsr_clear(void) { uart_lsr_save = 0; - *pUART_LSR |= -1; + bfin_write16(&pUART->lsr, bfin_read16(&pUART->lsr) | -1); } #else /* When debugging is disabled, we only care about the DR bit, so if other * bits get set/cleared, we don't really care since we don't read them * anyways (and thus anomaly 05000099 is irrelevant). */ -static inline uint16_t uart_lsr_read(void) { return *pUART_LSR; } -static inline void uart_lsr_clear(void) { *pUART_LSR = -1; } +static uint16_t uart_lsr_read(void) +{ + return bfin_read16(&pUART->lsr); +} +static void uart_lsr_clear(void) +{ + bfin_write16(&pUART->lsr, bfin_read16(&pUART->lsr) | -1); +} #endif /* Symbol for our assembly to call. */ @@ -130,7 +132,7 @@ void serial_putc(const char c) continue; /* queue the character for transmission */ - *pUART_THR = c; + bfin_write16(&pUART->thr, c); SSYNC(); WATCHDOG_RESET(); @@ -151,7 +153,7 @@ int serial_getc(void) continue; /* grab the new byte */ - uart_rbr_val = *pUART_RBR; + uart_rbr_val = bfin_read16(&pUART->rbr); #ifdef CONFIG_DEBUG_SERIAL /* grab & clear the LSR */ @@ -165,8 +167,8 @@ int serial_getc(void) uint16_t dll, dlh; printf("\n[SERIAL ERROR]\n"); ACCESS_LATCH(); - dll = *pUART_DLL; - dlh = *pUART_DLH; + dll = bfin_read16(&pUART->dll); + dlh = bfin_read16(&pUART->dlh); ACCESS_PORT_IER(); printf("\tDLL=0x%x DLH=0x%x\n", dll, dlh); do { diff --git a/cpu/blackfin/serial.h b/cpu/blackfin/serial.h index 6cbc564..5f9be86 100644 --- a/cpu/blackfin/serial.h +++ b/cpu/blackfin/serial.h @@ -24,71 +24,80 @@ # define BFIN_DEBUG_EARLY_SERIAL 0 #endif +#ifndef __ASSEMBLY__ + #define LOB(x) ((x) & 0xFF) #define HIB(x) (((x) >> 8) & 0xFF) +/* + * All Blackfin system MMRs are padded to 32bits even if the register + * itself is only 16bits. So use a helper macro to streamline this. + */ +#define __BFP(m) u16 m; u16 __pad_##m +struct bfin_mmr_serial { +#ifdef __ADSPBF54x__ + __BFP(dll); + __BFP(dlh); + __BFP(gctl); + __BFP(lcr); + __BFP(mcr); + __BFP(lsr); + __BFP(msr); + __BFP(scr); + __BFP(ier_set); + __BFP(ier_clear); + __BFP(thr); + __BFP(rbr); +#else + union { + u16 dll; + u16 thr; + const u16 rbr; + }; + const u16 __spad0; + union { + u16 dlh; + u16 ier; + }; + const u16 __spad1; + const __BFP(iir); + __BFP(lcr); + __BFP(mcr); + __BFP(lsr); + __BFP(msr); + __BFP(scr); + const u32 __spad2; + __BFP(gctl); +#endif +}; +#undef __BFP + #ifndef UART_LSR # if (CONFIG_UART_CONSOLE == 3) -# define pUART_DLH pUART3_DLH -# define pUART_DLL pUART3_DLL -# define pUART_GCTL pUART3_GCTL -# define pUART_IER pUART3_IER -# define pUART_IERC pUART3_IER_CLEAR -# define pUART_LCR pUART3_LCR -# define pUART_LSR pUART3_LSR -# define pUART_RBR pUART3_RBR -# define pUART_THR pUART3_THR -# define UART_THR UART3_THR -# define UART_LSR UART3_LSR +# define UART_BASE UART3_DLL # elif (CONFIG_UART_CONSOLE == 2) -# define pUART_DLH pUART2_DLH -# define pUART_DLL pUART2_DLL -# define pUART_GCTL pUART2_GCTL -# define pUART_IER pUART2_IER -# define pUART_IERC pUART2_IER_CLEAR -# define pUART_LCR pUART2_LCR -# define pUART_LSR pUART2_LSR -# define pUART_RBR pUART2_RBR -# define pUART_THR pUART2_THR -# define UART_THR UART2_THR -# define UART_LSR UART2_LSR +# define UART_BASE UART2_DLL # elif (CONFIG_UART_CONSOLE == 1) -# define pUART_DLH pUART1_DLH -# define pUART_DLL pUART1_DLL -# define pUART_GCTL pUART1_GCTL -# define pUART_IER pUART1_IER -# define pUART_IERC pUART1_IER_CLEAR -# define pUART_LCR pUART1_LCR -# define pUART_LSR pUART1_LSR -# define pUART_RBR pUART1_RBR -# define pUART_THR pUART1_THR -# define UART_THR UART1_THR -# define UART_LSR UART1_LSR +# define UART_BASE UART1_DLL # elif (CONFIG_UART_CONSOLE == 0) -# define pUART_DLH pUART0_DLH -# define pUART_DLL pUART0_DLL -# define pUART_GCTL pUART0_GCTL -# define pUART_IER pUART0_IER -# define pUART_IERC pUART0_IER_CLEAR -# define pUART_LCR pUART0_LCR -# define pUART_LSR pUART0_LSR -# define pUART_RBR pUART0_RBR -# define pUART_THR pUART0_THR -# define UART_THR UART0_THR -# define UART_LSR UART0_LSR +# define UART_BASE UART0_DLL +# endif +#else +# if CONFIG_UART_CONSOLE != 0 +# error CONFIG_UART_CONSOLE must be 0 on parts with only one UART # endif +# define UART_BASE UART_DLL #endif - -#ifndef __ASSEMBLY__ +#define pUART ((volatile struct bfin_mmr_serial *)UART_BASE) #ifdef __ADSPBF54x__ # define ACCESS_LATCH() # define ACCESS_PORT_IER() -# define CLEAR_IER() (*pUART_IERC = 0) #else -# define ACCESS_LATCH() (*pUART_LCR |= DLAB) -# define ACCESS_PORT_IER() (*pUART_LCR &= ~DLAB) -# define CLEAR_IER() (*pUART_IER = 0) +# define ACCESS_LATCH() \ + bfin_write16(&pUART->lcr, bfin_read16(&pUART->lcr) | DLAB) +# define ACCESS_PORT_IER() \ + bfin_write16(&pUART->lcr, bfin_read16(&pUART->lcr) & ~DLAB) #endif __attribute__((always_inline)) @@ -142,10 +151,10 @@ static inline void serial_early_init(void) serial_do_portmux(); /* always enable UART -- avoids anomalies 05000309 and 05000350 */ - *pUART_GCTL = UCEN; + bfin_write16(&pUART->gctl, UCEN); /* Set LCR to Word Lengh 8-bit word select */ - *pUART_LCR = WLS_8; + bfin_write16(&pUART->lcr, WLS_8); SSYNC(); } @@ -158,8 +167,8 @@ static inline void serial_early_put_div(uint16_t divisor) SSYNC(); /* Program the divisor to get the baud rate we want */ - *pUART_DLL = LOB(divisor); - *pUART_DLH = HIB(divisor); + bfin_write16(&pUART->dll, LOB(divisor)); + bfin_write16(&pUART->dlh, HIB(divisor)); SSYNC(); /* Clear DLAB in LCR to Access THR RBR IER */ @@ -174,8 +183,8 @@ static inline uint16_t serial_early_get_div(void) ACCESS_LATCH(); SSYNC(); - uint8_t dll = *pUART_DLL; - uint8_t dlh = *pUART_DLH; + uint8_t dll = bfin_read16(&pUART->dll); + uint8_t dlh = bfin_read16(&pUART->dlh); uint16_t divisor = (dlh << 8) | dll; /* Clear DLAB in LCR to Access THR RBR IER */ diff --git a/cpu/blackfin/start.S b/cpu/blackfin/start.S index 7cbd632..7a3abba 100644 --- a/cpu/blackfin/start.S +++ b/cpu/blackfin/start.S @@ -95,6 +95,7 @@ ENTRY(_start) /* Save RETX so we can pass it while booting Linux */ r7 = RETX; +#if CONFIG_MEM_SIZE /* Figure out where we are currently executing so that we can decide * how to best reprogram and relocate things. We'll pass below: * R4: load address of _start @@ -131,6 +132,9 @@ ENTRY(_start) r3.h = 0x2000; cc = r5 < r3 (iu); if cc jump .Ldma_and_reprogram; +#else + r6 = 1 (x); /* fake loaded_from_ldr = 1 */ +#endif r0 = 0 (x); /* set bootstruct to NULL */ call _initcode; jump .Lprogrammed; @@ -139,11 +143,10 @@ ENTRY(_start) .Ldma_and_reprogram: r0.l = LO(L1_INST_SRAM); r0.h = HI(L1_INST_SRAM); - r1.l = __initcode_start; - r1.h = __initcode_start; - r2.l = __initcode_end; - r2.h = __initcode_end; - r2 = r2 - r1; /* convert r2 into length of initcode */ + r1.l = __initcode_lma; + r1.h = __initcode_lma; + r2.l = __initcode_len; + r2.h = __initcode_len; r1 = r1 - r4; /* convert r1 from load address of initcode ... */ r1 = r1 + r5; /* ... to current (not load) address of initcode */ p3 = r0; @@ -155,6 +158,7 @@ ENTRY(_start) .Lprogrammed: serial_early_set_baud +#if CONFIG_MEM_SIZE /* Relocate from wherever we are (FLASH/RAM/etc...) to the hardcoded * monitor location in the end of RAM. We know that memcpy() only * uses registers, so it is safe to call here. Note that this only @@ -167,18 +171,18 @@ ENTRY(_start) r2.l = LO(CONFIG_SYS_MONITOR_LEN); r2.h = HI(CONFIG_SYS_MONITOR_LEN); call _memcpy_ASM; +#endif /* Initialize BSS section ... we know that memset() does not * use the BSS, so it is safe to call here. The bootrom LDR * takes care of clearing things for us. */ serial_early_puts("Zero BSS"); - r0.l = __bss_start; - r0.h = __bss_start; + r0.l = __bss_vma; + r0.h = __bss_vma; r1 = 0 (x); - r2.l = __bss_end; - r2.h = __bss_end; - r2 = r2 - r0; + r2.l = __bss_len; + r2.h = __bss_len; call _memset; .Lnorelocate: diff --git a/cpu/blackfin/traps.c b/cpu/blackfin/traps.c index 7e7c74c..becc36e 100644 --- a/cpu/blackfin/traps.c +++ b/cpu/blackfin/traps.c @@ -100,6 +100,14 @@ void trap_c(struct pt_regs *regs) uint32_t new_cplb_addr = 0, new_cplb_data = 0; static size_t last_evicted; size_t i; + unsigned long tflags; + + /* + * Keep the trace buffer so that a miss here points people + * to the right place (their code). Crashes here rarely + * happen. If they do, only the Blackfin maintainer cares. + */ + trace_buffer_save(tflags); new_cplb_addr = (data ? bfin_read_DCPLB_FAULT_ADDR() : bfin_read_ICPLB_FAULT_ADDR()) & ~(4 * 1024 * 1024 - 1); @@ -156,6 +164,7 @@ void trap_c(struct pt_regs *regs) for (i = 0; i < 16; ++i) debug("%2i 0x%p 0x%08X\n", i, *CPLB_ADDR++, *CPLB_DATA++); + trace_buffer_restore(tflags); break; } diff --git a/cpu/blackfin/watchdog.c b/cpu/blackfin/watchdog.c index b47c6b6..1886bda 100644 --- a/cpu/blackfin/watchdog.c +++ b/cpu/blackfin/watchdog.c @@ -1,7 +1,7 @@ /* * watchdog.c - driver for Blackfin on-chip watchdog * - * Copyright (c) 2007-2008 Analog Devices Inc. + * Copyright (c) 2007-2009 Analog Devices Inc. * * Licensed under the GPL-2 or later. */ @@ -10,7 +10,6 @@ #include <watchdog.h> #include <asm/blackfin.h> -#ifdef CONFIG_HW_WATCHDOG void hw_watchdog_reset(void) { bfin_write_WDOG_STAT(0); @@ -22,4 +21,3 @@ void hw_watchdog_init(void) hw_watchdog_reset(); bfin_write_WDOG_CTL(0x0); } -#endif |