diff options
Diffstat (limited to 'cpu')
105 files changed, 13710 insertions, 3001 deletions
diff --git a/cpu/74xx_7xx/cpu.c b/cpu/74xx_7xx/cpu.c index ca45e17..f4e5fc5 100644 --- a/cpu/74xx_7xx/cpu.c +++ b/cpu/74xx_7xx/cpu.c @@ -101,6 +101,10 @@ get_cpu_type(void) type = CPU_7457; break; + case 0x8004: + type = CPU_7448; + break; + default: break; } @@ -152,6 +156,10 @@ int checkcpu (void) str = "MPC7410"; break; + case CPU_7448: + str = "MPC7448"; + break; + case CPU_7450: str = "MPC7450"; break; @@ -221,7 +229,7 @@ soft_restart(unsigned long addr) void do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) { - ulong addr; + ulong addr; /* flush and disable I/D cache */ __asm__ __volatile__ ("mfspr 3, 1008" ::: "r3"); __asm__ __volatile__ ("ori 5, 5, 0xcc00" ::: "r5"); diff --git a/cpu/74xx_7xx/cpu_init.c b/cpu/74xx_7xx/cpu_init.c index 93f180f..e02a4cc 100644 --- a/cpu/74xx_7xx/cpu_init.c +++ b/cpu/74xx_7xx/cpu_init.c @@ -43,6 +43,7 @@ cpu_init_f (void) case CPU_7450: case CPU_7455: case CPU_7457: + case CPU_7448: /* enable the timebase bit in HID0 */ set_hid0(get_hid0() | 0x4000000); break; diff --git a/cpu/74xx_7xx/speed.c b/cpu/74xx_7xx/speed.c index 2dc5107..d1800ed 100644 --- a/cpu/74xx_7xx/speed.c +++ b/cpu/74xx_7xx/speed.c @@ -91,6 +91,7 @@ int get_clocks (void) /* calculate the clock frequency based upon the CPU type */ switch (get_cpu_type()) { + case CPU_7448: case CPU_7455: case CPU_7457: /* diff --git a/cpu/74xx_7xx/start.S b/cpu/74xx_7xx/start.S index 1fc0fe6..1143038 100644 --- a/cpu/74xx_7xx/start.S +++ b/cpu/74xx_7xx/start.S @@ -44,7 +44,8 @@ #if !defined(CONFIG_DB64360) && \ !defined(CONFIG_DB64460) && \ - !defined(CONFIG_CPCI750) + !defined(CONFIG_CPCI750) && \ + !defined(CONFIG_P3Mx) #include <galileo/gt64260R.h> #endif @@ -270,7 +271,7 @@ in_flash: * gt-regs BAT can be reused after board_init_f calls * board_early_init_f (EVB only). */ -#if !defined(CONFIG_BAB7xx) && !defined(CONFIG_ELPPC) +#if !defined(CONFIG_BAB7xx) && !defined(CONFIG_ELPPC) && !defined(CONFIG_P3Mx) /* enable address translation */ bl enable_addr_trans sync @@ -757,7 +758,8 @@ in_ram: defined(CONFIG_DB64360) || \ defined(CONFIG_DB64460) || \ defined(CONFIG_CPCI750) || \ - defined(CONFIG_PPMC7XX) + defined(CONFIG_PPMC7XX) || \ + defined(CONFIG_P3Mx) mr r4, r9 /* Use RAM copy of the global data */ #endif bl after_reloc diff --git a/cpu/arm720t/cpu.c b/cpu/arm720t/cpu.c index a5b6de7..60c1aa9 100644 --- a/cpu/arm720t/cpu.c +++ b/cpu/arm720t/cpu.c @@ -73,7 +73,7 @@ int cleanup_before_linux (void) /* go to high speed */ IO_SYSCON3 = (IO_SYSCON3 & ~CLKCTL) | CLKCTL_73; #endif -#elif defined(CONFIG_NETARM) || defined(CONFIG_S3C4510B) +#elif defined(CONFIG_NETARM) || defined(CONFIG_S3C4510B) || defined(CONFIG_LPC2292) disable_interrupts (); /* Nothing more needed */ #elif defined(CONFIG_INTEGRATOR) && defined(CONFIG_ARCH_INTEGRATOR) @@ -252,6 +252,7 @@ int dcache_status (void) void icache_enable (void) { } +#elif defined(CONFIG_LPC2292) /* just to satisfy the compiler */ #else #error No icache/dcache enable/disable functions defined for this CPU type #endif diff --git a/cpu/arm720t/interrupts.c b/cpu/arm720t/interrupts.c index da62502..8f32124 100644 --- a/cpu/arm720t/interrupts.c +++ b/cpu/arm720t/interrupts.c @@ -36,6 +36,12 @@ #define TIMER_LOAD_VAL 0xffff /* macro to read the 16 bit timer */ #define READ_TIMER (IO_TC1D & 0xffff) + +#ifdef CONFIG_LPC2292 +#undef READ_TIMER +#define READ_TIMER (0xFFFFFFFF - GET32(T0TC)) +#endif + #else #define IRQEN (*(volatile unsigned int *)(NETARM_GEN_MODULE_BASE + NETARM_GEN_INTR_ENABLE)) #define TM2CTRL (*(volatile unsigned int *)(NETARM_GEN_MODULE_BASE + NETARM_GEN_TIMER2_CONTROL)) @@ -195,6 +201,13 @@ void do_irq (struct pt_regs *pt_regs) } #elif defined(CONFIG_INTEGRATOR) && defined(CONFIG_ARCH_INTEGRATOR) /* No do_irq() for IntegratorAP/CM720T as yet */ +#elif defined(CONFIG_LPC2292) + + void (*pfnct)(void); + + pfnct = (void (*)(void))VICVectAddr; + + (*pfnct)(); #else #error do_irq() not defined for this CPU type #endif @@ -293,6 +306,13 @@ int interrupt_init (void) /* Start timer */ SET_REG( REG_TMOD, TM0_RUN); +#elif defined(CONFIG_LPC2292) + PUT32(T0IR, 0); /* disable all timer0 interrupts */ + PUT32(T0TCR, 0); /* disable timer0 */ + PUT32(T0PR, CFG_SYS_CLK_FREQ / CFG_HZ); + PUT32(T0MCR, 0); + PUT32(T0TC, 0); + PUT32(T0TCR, 1); /* enable timer0 */ #else #error No interrupt_init() defined for this CPU type @@ -309,7 +329,7 @@ int interrupt_init (void) */ -#if defined(CONFIG_IMPA7) || defined(CONFIG_EP7312) || defined(CONFIG_NETARM) || defined(CONFIG_ARMADILLO) +#if defined(CONFIG_IMPA7) || defined(CONFIG_EP7312) || defined(CONFIG_NETARM) || defined(CONFIG_ARMADILLO) || defined(CONFIG_LPC2292) void reset_timer (void) { @@ -337,7 +357,12 @@ void udelay (unsigned long usec) tmo += get_timer (0); while (get_timer_masked () < tmo) +#ifdef CONFIG_LPC2292 + /* GJ - not sure whether this is really needed or a misunderstanding */ + __asm__ __volatile__(" nop"); +#else /*NOP*/; +#endif } void reset_timer_masked (void) diff --git a/cpu/arm720t/serial.c b/cpu/arm720t/serial.c index 054bab9..15c54af 100644 --- a/cpu/arm720t/serial.c +++ b/cpu/arm720t/serial.c @@ -123,4 +123,80 @@ serial_puts (const char *s) } } -#endif /* defined(CONFIG_IMPA7) || defined(CONFIG_EP7312) */ +#elif defined(CONFIG_LPC2292) + +#include <asm/arch/hardware.h> + +void serial_setbrg (void) +{ + DECLARE_GLOBAL_DATA_PTR; + + unsigned short divisor = 0; + + switch (gd->baudrate) { + case 1200: divisor = 3072; break; + case 9600: divisor = 384; break; + case 19200: divisor = 192; break; + case 38400: divisor = 96; break; + case 57600: divisor = 64; break; + case 115200: divisor = 32; break; + default: hang (); break; + } + + /* init serial UART0 */ + PUT8(U0LCR, 0); + PUT8(U0IER, 0); + PUT8(U0LCR, 0x80); /* DLAB=1 */ + PUT8(U0DLL, (unsigned char)(divisor & 0x00FF)); + PUT8(U0DLM, (unsigned char)(divisor >> 8)); + PUT8(U0LCR, 0x03); /* 8N1, DLAB=0 */ + PUT8(U0FCR, 1); /* Enable RX and TX FIFOs */ +} + +int serial_init (void) +{ + unsigned long pinsel0; + + serial_setbrg (); + + pinsel0 = GET32(PINSEL0); + pinsel0 &= ~(0x00000003); + pinsel0 |= 5; + PUT32(PINSEL0, pinsel0); + + return (0); +} + +void serial_putc (const char c) +{ + if (c == '\n') + { + while((GET8(U0LSR) & (1<<5)) == 0); /* Wait for empty U0THR */ + PUT8(U0THR, '\r'); + } + + while((GET8(U0LSR) & (1<<5)) == 0); /* Wait for empty U0THR */ + PUT8(U0THR, c); +} + +int serial_getc (void) +{ + while((GET8(U0LSR) & 1) == 0); + return GET8(U0RBR); +} + +void +serial_puts (const char *s) +{ + while (*s) { + serial_putc (*s++); + } +} + +/* Test if there is a byte to read */ +int serial_tstc (void) +{ + return (GET8(U0LSR) & 1); +} + +#endif diff --git a/cpu/arm720t/start.S b/cpu/arm720t/start.S index e66d109..8423e4f 100644 --- a/cpu/arm720t/start.S +++ b/cpu/arm720t/start.S @@ -43,7 +43,11 @@ _start: b reset ldr pc, _software_interrupt ldr pc, _prefetch_abort ldr pc, _data_abort +#ifdef CONFIG_LPC2292 + .word 0xB4405F76 /* 2's complement of the checksum of the vectors */ +#else ldr pc, _not_used +#endif ldr pc, _irq ldr pc, _fiq @@ -123,6 +127,10 @@ reset: bl cpu_init_crit #endif +#ifdef CONFIG_LPC2292 + bl lowlevel_init +#endif + #ifndef CONFIG_SKIP_RELOCATE_UBOOT relocate: /* relocate U-Boot to RAM */ adr r0, _start /* r0 <- current position of code */ @@ -131,6 +139,7 @@ relocate: /* relocate U-Boot to RAM */ beq stack_setup #if TEXT_BASE +#ifndef CONFIG_LPC2292 /* already done in lowlevel_init */ ldr r2, =0x0 /* Relocate the exception vectors */ cmp r1, r2 /* and associated data to address */ ldmneia r0!, {r3-r10} /* 0x0. Do nothing if TEXT_BASE is */ @@ -138,6 +147,7 @@ relocate: /* relocate U-Boot to RAM */ ldmneia r0, {r3-r9} stmneia r2, {r3-r9} adrne r0, _start /* restore r0 */ +#endif /* !CONFIG_LPC2292 */ #endif ldr r2, _armboot_start @@ -206,6 +216,14 @@ SYSCON3: .word 0x80002200 #define CLKCTL_49 0x4 /* 49.152 MHz */ #define CLKCTL_73 0x6 /* 73.728 MHz */ +#elif defined(CONFIG_LPC2292) +PLLCFG_ADR: .word PLLCFG +PLLFEED_ADR: .word PLLFEED +PLLCON_ADR: .word PLLCON +PLLSTAT_ADR: .word PLLSTAT +VPBDIV_ADR: .word VPBDIV +MEMMAP_ADR: .word MEMMAP + #endif cpu_init_crit: @@ -306,6 +324,50 @@ cpu_init_crit: #elif defined(CONFIG_INTEGRATOR) && defined(CONFIG_ARCH_INTEGRATOR) /* No specific initialisation for IntegratorAP/CM720T as yet */ +#elif defined(CONFIG_LPC2292) + /* Set-up PLL */ + mov r3, #0xAA + mov r4, #0x55 + /* First disconnect and disable the PLL */ + ldr r0, PLLCON_ADR + mov r1, #0x00 + str r1, [r0] + ldr r0, PLLFEED_ADR /* start feed sequence */ + str r3, [r0] + str r4, [r0] /* feed sequence done */ + /* Set new M and P values */ + ldr r0, PLLCFG_ADR + mov r1, #0x23 /* M=4 and P=2 */ + str r1, [r0] + ldr r0, PLLFEED_ADR /* start feed sequence */ + str r3, [r0] + str r4, [r0] /* feed sequence done */ + /* Then enable the PLL */ + ldr r0, PLLCON_ADR + mov r1, #0x01 /* PLL enable bit */ + str r1, [r0] + ldr r0, PLLFEED_ADR /* start feed sequence */ + str r3, [r0] + str r4, [r0] /* feed sequence done */ + /* Wait for the lock */ + ldr r0, PLLSTAT_ADR + mov r1, #0x400 /* lock bit */ +lock_loop: + ldr r2, [r0] + and r2, r1, r2 + cmp r2, #0 + beq lock_loop + /* And finally connect the PLL */ + ldr r0, PLLCON_ADR + mov r1, #0x03 /* PLL enable bit and connect bit */ + str r1, [r0] + ldr r0, PLLFEED_ADR /* start feed sequence */ + str r3, [r0] + str r4, [r0] /* feed sequence done */ + /* Set-up VPBDIV register */ + ldr r0, VPBDIV_ADR + mov r1, #0x01 /* VPB clock is same as process clock */ + str r1, [r0] #else #error No cpu_init_crit() defined for current CPU type #endif @@ -321,6 +383,7 @@ cpu_init_crit: str r1, [r0] #endif +#ifndef CONFIG_LPC2292 mov ip, lr /* * before relocating, we have to setup RAM timing @@ -329,6 +392,7 @@ cpu_init_crit: */ bl lowlevel_init mov lr, ip +#endif mov pc, lr @@ -537,6 +601,11 @@ reset_cpu: * on external peripherals such as watchdog timers, etc. */ #elif defined(CONFIG_INTEGRATOR) && defined(CONFIG_ARCH_INTEGRATOR) /* No specific reset actions for IntegratorAP/CM720T as yet */ +#elif defined(CONFIG_LPC2292) + .align 5 +.globl reset_cpu +reset_cpu: + mov pc, r0 #else #error No reset_cpu() defined for current CPU type #endif diff --git a/cpu/bf533/Makefile b/cpu/bf533/Makefile index 9f4a0d8..90018f3 100644 --- a/cpu/bf533/Makefile +++ b/cpu/bf533/Makefile @@ -28,14 +28,16 @@ include $(TOPDIR)/config.mk LIB = $(obj)lib$(CPU).a -START = start.o start1.o interrupt.o cache.o cplbhdlr.o cplbmgr.o flush.o -COBJS = cpu.o traps.o ints.o serial.o interrupts.o +START = start.o start1.o interrupt.o cache.o flush.o init_sdram.o +COBJS = cpu.o traps.o ints.o serial.o interrupts.o video.o + +EXTRA = init_sdram_bootrom_initblock.o SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c) -OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS)) +OBJS := $(addprefix $(obj),$(COBJS) $(SOBJS)) START := $(addprefix $(obj),$(START)) -all: $(obj).depend $(START) $(LIB) +all: $(obj).depend $(START) $(LIB) $(obj).depend $(EXTRA) $(LIB): $(OBJS) $(AR) $(ARFLAGS) $@ $(OBJS) diff --git a/cpu/bf533/bf533_serial.h b/cpu/bf533/bf533_serial.h index d430e6c..0a04f3e 100644 --- a/cpu/bf533/bf533_serial.h +++ b/cpu/bf533/bf533_serial.h @@ -63,8 +63,7 @@ int serial_getc(void); void serial_puts(const char *s); static void local_put_char(char ch); -extern int get_clock(void); -int baud_table[5] = {9600, 19200, 38400, 57600, 115200}; +int baud_table[5] = { 9600, 19200, 38400, 57600, 115200 }; struct { unsigned char dl_high; diff --git a/cpu/bf533/cache.S b/cpu/bf533/cache.S index 8fac402..03aebe4 100644 --- a/cpu/bf533/cache.S +++ b/cpu/bf533/cache.S @@ -1,12 +1,11 @@ - - #define ASSEMBLY #include <asm/linkage.h> -#include <asm/cpu/def_LPBlackfin.h> +#include <config.h> +#include <asm/blackfin.h> .text .align 2 -ENTRY(blackfin_icache_flush_range) +ENTRY(_blackfin_icache_flush_range) R2 = -32; R2 = R0 & R2; P0 = R2; @@ -20,7 +19,7 @@ ENTRY(blackfin_icache_flush_range) SSYNC; RTS; -ENTRY(blackfin_dcache_flush_range) +ENTRY(_blackfin_dcache_flush_range) R2 = -32; R2 = R0 & R2; P0 = R2; @@ -35,19 +34,21 @@ ENTRY(blackfin_dcache_flush_range) RTS; ENTRY(_icache_invalidate) -ENTRY(invalidate_entire_icache) - [--SP] = ( R7:5); +ENTRY(_invalidate_entire_icache) + [--SP] = (R7:5); P0.L = (IMEM_CONTROL & 0xFFFF); P0.H = (IMEM_CONTROL >> 16); - R7 = [P0]; + R7 =[P0]; - /* Clear the IMC bit , All valid bits in the instruction + /* + * Clear the IMC bit , All valid bits in the instruction * cache are set to the invalid state */ - BITCLR(R7,IMC_P); + BITCLR(R7, IMC_P); CLI R6; - SSYNC; /* SSYNC required before invalidating cache. */ + /* SSYNC required before invalidating cache. */ + SSYNC; .align 8; [P0] = R7; SSYNC; @@ -58,54 +59,55 @@ ENTRY(invalidate_entire_icache) R7 = R7 | R6; CLI R6; - SSYNC; /* SSYNC required before writing to IMEM_CONTROL. */ + SSYNC; .align 8; [P0] = R7; SSYNC; STI R6; - ( R7:5) = [SP++]; + (R7:5) =[SP++]; RTS; -/* Invalidate the Entire Data cache by +/* + * Invalidate the Entire Data cache by * clearing DMC[1:0] bits */ -ENTRY(invalidate_entire_dcache) +ENTRY(_invalidate_entire_dcache) ENTRY(_dcache_invalidate) - [--SP] = ( R7:6); + [--SP] = (R7:6); P0.L = (DMEM_CONTROL & 0xFFFF); P0.H = (DMEM_CONTROL >> 16); - R7 = [P0]; + R7 =[P0]; - /* Clear the DMC[1:0] bits, All valid bits in the data + /* + * Clear the DMC[1:0] bits, All valid bits in the data * cache are set to the invalid state */ - BITCLR(R7,DMC0_P); - BITCLR(R7,DMC1_P); + BITCLR(R7, DMC0_P); + BITCLR(R7, DMC1_P); CLI R6; - SSYNC; /* SSYNC required before writing to DMEM_CONTROL. */ + SSYNC; .align 8; [P0] = R7; SSYNC; STI R6; - /* Configures the data cache again */ R6 = (ACACHE_BCACHE | ENDCPLB | PORT_PREF0); R7 = R7 | R6; CLI R6; - SSYNC; /* SSYNC required before writing to DMEM_CONTROL. */ + SSYNC; .align 8; [P0] = R7; SSYNC; STI R6; - ( R7:6) = [SP++]; + (R7:6) =[SP++]; RTS; -ENTRY(blackfin_dcache_invalidate_range) +ENTRY(_blackfin_dcache_invalidate_range) R2 = -32; R2 = R0 & R2; P0 = R2; @@ -113,13 +115,14 @@ ENTRY(blackfin_dcache_invalidate_range) CSYNC; 1: FLUSHINV[P0++]; - CC = P0 < P1 (iu); - IF CC JUMP 1b (bp); + CC = P0 < P1(iu); + IF CC JUMP 1b(bp); - /* If the data crosses a cache line, then we'll be pointing to - ** the last cache line, but won't have flushed/invalidated it yet, so do - ** one more. - */ + /* + * If the data crosses a cache line, then we'll be pointing to + * the last cache line, but won't have flushed/invalidated it yet, so do + * one more. + */ FLUSHINV[P0]; SSYNC; RTS; diff --git a/cpu/bf533/config.mk b/cpu/bf533/config.mk index a9d529e..10817d9 100644 --- a/cpu/bf533/config.mk +++ b/cpu/bf533/config.mk @@ -24,4 +24,4 @@ # MA 02111-1307 USA # -PLATFORM_RELFLAGS += -ffixed-P5 +PLATFORM_RELFLAGS += -mcpu=bf533 -ffixed-P5 diff --git a/cpu/bf533/cplbhdlr.S b/cpu/bf533/cplbhdlr.S deleted file mode 100644 index 61be5bb..0000000 --- a/cpu/bf533/cplbhdlr.S +++ /dev/null @@ -1,193 +0,0 @@ -/* Copyright (C) 2003 Analog Devices, Inc. All Rights Reserved. - * - * This file is subject to the terms and conditions of the GNU General Public - * License. - * - * Blackfin BF533/2.6 support : LG Soft India - */ - - -/* Include an exception handler to invoke the CPLB manager - */ - -#include <asm-blackfin/linkage.h> -#include <asm/cplb.h> -#include <asm/entry.h> - - -.text - -.globl _cplb_hdr; -.type _cplb_hdr, STT_FUNC; -.extern _cplb_mgr; -.type _cplb_mgr, STT_FUNC; -.extern __unknown_exception_occurred; -.type __unknown_exception_occurred, STT_FUNC; -.extern __cplb_miss_all_locked; -.type __cplb_miss_all_locked, STT_FUNC; -.extern __cplb_miss_without_replacement; -.type __cplb_miss_without_replacement, STT_FUNC; -.extern __cplb_protection_violation; -.type __cplb_protection_violation, STT_FUNC; -.extern panic_pv; - -.align 2; - -ENTRY(_cplb_hdr) - SSYNC; - [--SP] = ( R7:0, P5:0 ); - [--SP] = ASTAT; - [--SP] = SEQSTAT; - [--SP] = I0; - [--SP] = I1; - [--SP] = I2; - [--SP] = I3; - [--SP] = LT0; - [--SP] = LB0; - [--SP] = LC0; - [--SP] = LT1; - [--SP] = LB1; - [--SP] = LC1; - R2 = SEQSTAT; - - /*Mask the contents of SEQSTAT and leave only EXCAUSE in R2*/ - R2 <<= 26; - R2 >>= 26; - - R1 = 0x23; /* Data access CPLB protection violation */ - CC = R2 == R1; - IF !CC JUMP not_data_write; - R0 = 2; /* is a write to data space*/ - JUMP is_icplb_miss; - -not_data_write: - R1 = 0x2C; /* CPLB miss on an instruction fetch */ - CC = R2 == R1; - R0 = 0; /* is_data_miss == False*/ - IF CC JUMP is_icplb_miss; - - R1 = 0x26; - CC = R2 == R1; - IF !CC JUMP unknown; - - R0 = 1; /* is_data_miss == True*/ - -is_icplb_miss: - -#if ( defined (CONFIG_BLKFIN_CACHE) || defined (CONFIG_BLKFIN_DCACHE)) -#if ( defined (CONFIG_BLKFIN_CACHE) && !defined (CONFIG_BLKFIN_DCACHE)) - R1 = CPLB_ENABLE_ICACHE; -#endif -#if ( !defined (CONFIG_BLKFIN_CACHE) && defined (CONFIG_BLKFIN_DCACHE)) - R1 = CPLB_ENABLE_DCACHE; -#endif -#if ( defined (CONFIG_BLKFIN_CACHE) && defined (CONFIG_BLKFIN_DCACHE)) - R1 = CPLB_ENABLE_DCACHE | CPLB_ENABLE_ICACHE; -#endif -#else - R1 = 0; -#endif - - [--SP] = RETS; - CALL _cplb_mgr; - RETS = [SP++]; - CC = R0 == 0; - IF !CC JUMP not_replaced; - LC1 = [SP++]; - LB1 = [SP++]; - LT1 = [SP++]; - LC0 = [SP++]; - LB0 = [SP++]; - LT0 = [SP++]; - I3 = [SP++]; - I2 = [SP++]; - I1 = [SP++]; - I0 = [SP++]; - SEQSTAT = [SP++]; - ASTAT = [SP++]; - ( R7:0, P5:0 ) = [SP++]; - RTS; - -unknown: - [--SP] = RETS; - CALL __unknown_exception_occurred; - RETS = [SP++]; - JUMP unknown; -not_replaced: - CC = R0 == CPLB_NO_UNLOCKED; - IF !CC JUMP next_check; - [--SP] = RETS; - CALL __cplb_miss_all_locked; - RETS = [SP++]; -next_check: - CC = R0 == CPLB_NO_ADDR_MATCH; - IF !CC JUMP next_check2; - [--SP] = RETS; - CALL __cplb_miss_without_replacement; - RETS = [SP++]; - JUMP not_replaced; -next_check2: - CC = R0 == CPLB_PROT_VIOL; - IF !CC JUMP strange_return_from_cplb_mgr; - [--SP] = RETS; - CALL __cplb_protection_violation; - RETS = [SP++]; - JUMP not_replaced; -strange_return_from_cplb_mgr: - IDLE; - CSYNC; - JUMP strange_return_from_cplb_mgr; - -/************************************ - * Diagnostic exception handlers - */ - -__cplb_miss_all_locked: - sp += -12; - R0 = CPLB_NO_UNLOCKED; - call panic_bfin; - SP += 12; - RTS; - - __cplb_miss_without_replacement: - sp += -12; - R0 = CPLB_NO_ADDR_MATCH; - call panic_bfin; - SP += 12; - RTS; - -__cplb_protection_violation: - sp += -12; - R0 = CPLB_PROT_VIOL; - call panic_bfin; - SP += 12; - RTS; - -__unknown_exception_occurred: - - /* This function is invoked by the default exception - * handler, if it does not recognise the kind of - * exception that has occurred. In other words, the - * default handler only handles some of the system's - * exception types, and it does not expect any others - * to occur. If your application is going to be using - * other kinds of exceptions, you must replace the - * default handler with your own, that handles all the - * exceptions you will use. - * - * Since there's nothing we can do, we just loop here - * at what we hope is a suitably informative label. - */ - - IDLE; -do_not_know_what_to_do: - CSYNC; - JUMP __unknown_exception_occurred; - - RTS; -.__unknown_exception_occurred.end: -.global __unknown_exception_occurred; -.type __unknown_exception_occurred, STT_FUNC; - -panic_bfin: - RTS; diff --git a/cpu/bf533/cplbmgr.S b/cpu/bf533/cplbmgr.S deleted file mode 100644 index 7a0b048..0000000 --- a/cpu/bf533/cplbmgr.S +++ /dev/null @@ -1,601 +0,0 @@ -/*This file is subject to the terms and conditions of the GNU General Public - * License. - * - * Blackfin BF533/2.6 support : LG Soft India - * Modification: Dec 07 2004 - * 1. Correction in icheck_lock. Valid lock entries were - * geting victimized, for instruction cplb replacement. - * 2. Setup loop's are modified as now toolchain support's P Indexed - * addressing - * :LG Soft India - * - */ - -/* Usage: int _cplb_mgr(is_data_miss,int enable_cache) - * is_data_miss==2 => Mark as Dirty, write to the clean data page - * is_data_miss==1 => Replace a data CPLB. - * is_data_miss==0 => Replace an instruction CPLB. - * - * Returns: - * CPLB_RELOADED => Successfully updated CPLB table. - * CPLB_NO_UNLOCKED => All CPLBs are locked, so cannot be evicted.This indicates - * that the CPLBs in the configuration tablei are badly - * configured, as this should never occur. - * CPLB_NO_ADDR_MATCH => The address being accessed, that triggered the exception, - * is not covered by any of the CPLBs in the configuration - * table. The application isi presumably misbehaving. - * CPLB_PROT_VIOL => The address being accessed, that triggered thei exception, - * was not a first-write to a clean Write Back Data page, - * and so presumably is a genuine violation of the page's - * protection attributes. The application is misbehaving. - */ -#define ASSEMBLY - -#include <asm-blackfin/linkage.h> -#include <asm-blackfin/blackfin.h> -#include <asm-blackfin/cplbtab.h> -#include <asm-blackfin/cplb.h> - -.text - -.align 2; -ENTRY(_cplb_mgr) - - [--SP]=( R7:0,P5:0 ); - - CC = R0 == 2; - IF CC JUMP dcplb_write; - - CC = R0 == 0; - IF !CC JUMP dcplb_miss_compare; - - /* ICPLB Miss Exception. We need to choose one of the - * currently-installed CPLBs, and replace it with one - * from the configuration table. - */ - - P4.L = (ICPLB_FAULT_ADDR & 0xFFFF); - P4.H = (ICPLB_FAULT_ADDR >> 16); - - P1 = 16; - P5.L = page_size_table; - P5.H = page_size_table; - - P0.L = (ICPLB_DATA0 & 0xFFFF); - P0.H = (ICPLB_DATA0 >> 16); - R4 = [P4]; /* Get faulting address*/ - R6 = 64; /* Advance past the fault address, which*/ - R6 = R6 + R4; /* we'll use if we find a match*/ - R3 = ((16 << 8) | 2); /* Extract mask, bits 16 and 17.*/ - - R5 = 0; -isearch: - - R1 = [P0-0x100]; /* Address for this CPLB */ - - R0 = [P0++]; /* Info for this CPLB*/ - CC = BITTST(R0,0); /* Is the CPLB valid?*/ - IF !CC JUMP nomatch; /* Skip it, if not.*/ - CC = R4 < R1(IU); /* If fault address less than page start*/ - IF CC JUMP nomatch; /* then skip this one.*/ - R2 = EXTRACT(R0,R3.L) (Z); /* Get page size*/ - P1 = R2; - P1 = P5 + (P1<<2); /* index into page-size table*/ - R2 = [P1]; /* Get the page size*/ - R1 = R1 + R2; /* and add to page start, to get page end*/ - CC = R4 < R1(IU); /* and see whether fault addr is in page.*/ - IF !CC R4 = R6; /* If so, advance the address and finish loop.*/ - IF !CC JUMP isearch_done; -nomatch: - /* Go around again*/ - R5 += 1; - CC = BITTST(R5, 4); /* i.e CC = R5 >= 16*/ - IF !CC JUMP isearch; - -isearch_done: - I0 = R4; /* Fault address we'll search for*/ - - /* set up pointers */ - P0.L = (ICPLB_DATA0 & 0xFFFF); - P0.H = (ICPLB_DATA0 >> 16); - - /* The replacement procedure for ICPLBs */ - - P4.L = (IMEM_CONTROL & 0xFFFF); - P4.H = (IMEM_CONTROL >> 16); - - /* disable cplbs */ - R5 = [P4]; /* Control Register*/ - BITCLR(R5,ENICPLB_P); - CLI R1; - SSYNC; /* SSYNC required before writing to IMEM_CONTROL. */ - .align 8; - [P4] = R5; - SSYNC; - STI R1; - - R1 = -1; /* end point comparison */ - R3 = 16; /* counter */ - - /* Search through CPLBs for first non-locked entry */ - /* Overwrite it by moving everyone else up by 1 */ -icheck_lock: - R0 = [P0++]; - R3 = R3 + R1; - CC = R3 == R1; - IF CC JUMP all_locked; - CC = BITTST(R0, 0); /* an invalid entry is good */ - IF !CC JUMP ifound_victim; - CC = BITTST(R0,1); /* but a locked entry isn't */ - IF CC JUMP icheck_lock; - -ifound_victim: -#ifdef CONFIG_CPLB_INFO - R7 = [P0 - 0x104]; - P2.L = ipdt_table; - P2.H = ipdt_table; - P3.L = ipdt_swapcount_table; - P3.H = ipdt_swapcount_table; - P3 += -4; -icount: - R2 = [P2]; /* address from config table */ - P2 += 8; - P3 += 8; - CC = R2==-1; - IF CC JUMP icount_done; - CC = R7==R2; - IF !CC JUMP icount; - R7 = [P3]; - R7 += 1; - [P3] = R7; - CSYNC; -icount_done: -#endif - LC0=R3; - LSETUP(is_move,ie_move) LC0; -is_move: - R0 = [P0]; - [P0 - 4] = R0; - R0 = [P0 - 0x100]; - [P0-0x104] = R0; -ie_move:P0+=4; - - /* We've made space in the ICPLB table, so that ICPLB15 - * is now free to be overwritten. Next, we have to determine - * which CPLB we need to install, from the configuration - * table. This is a matter of getting the start-of-page - * addresses and page-lengths from the config table, and - * determining whether the fault address falls within that - * range. - */ - - P2.L = ipdt_table; - P2.H = ipdt_table; -#ifdef CONFIG_CPLB_INFO - P3.L = ipdt_swapcount_table; - P3.H = ipdt_swapcount_table; - P3 += -8; -#endif - P0.L = page_size_table; - P0.H = page_size_table; - - /* Retrieve our fault address (which may have been advanced - * because the faulting instruction crossed a page boundary). - */ - - R0 = I0; - - /* An extraction pattern, to get the page-size bits from - * the CPLB data entry. Bits 16-17, so two bits at posn 16. - */ - - R1 = ((16<<8)|2); -inext: R4 = [P2++]; /* address from config table */ - R2 = [P2++]; /* data from config table */ -#ifdef CONFIG_CPLB_INFO - P3 += 8; -#endif - - CC = R4 == -1; /* End of config table*/ - IF CC JUMP no_page_in_table; - - /* See if failed address > start address */ - CC = R4 <= R0(IU); - IF !CC JUMP inext; - - /* extract page size (17:16)*/ - R3 = EXTRACT(R2, R1.L) (Z); - - /* add page size to addr to get range */ - - P5 = R3; - P5 = P0 + (P5 << 2); /* scaled, for int access*/ - R3 = [P5]; - R3 = R3 + R4; - - /* See if failed address < (start address + page size) */ - CC = R0 < R3(IU); - IF !CC JUMP inext; - - /* We've found a CPLB in the config table that covers - * the faulting address, so install this CPLB into the - * last entry of the table. - */ - - P1.L = (ICPLB_DATA15 & 0xFFFF); /*ICPLB_DATA15*/ - P1.H = (ICPLB_DATA15 >> 16); - [P1] = R2; - [P1-0x100] = R4; -#ifdef CONFIG_CPLB_INFO - R3 = [P3]; - R3 += 1; - [P3] = R3; -#endif - - /* P4 points to IMEM_CONTROL, and R5 contains its old - * value, after we disabled ICPLBS. Re-enable them. - */ - - BITSET(R5,ENICPLB_P); - CLI R2; - SSYNC; /* SSYNC required before writing to IMEM_CONTROL. */ - .align 8; - [P4] = R5; - SSYNC; - STI R2; - - ( R7:0,P5:0 ) = [SP++]; - R0 = CPLB_RELOADED; - RTS; - -/* FAILED CASES*/ -no_page_in_table: - ( R7:0,P5:0 ) = [SP++]; - R0 = CPLB_NO_ADDR_MATCH; - RTS; -all_locked: - ( R7:0,P5:0 ) = [SP++]; - R0 = CPLB_NO_UNLOCKED; - RTS; -prot_violation: - ( R7:0,P5:0 ) = [SP++]; - R0 = CPLB_PROT_VIOL; - RTS; - -dcplb_write: - - /* if a DCPLB is marked as write-back (CPLB_WT==0), and - * it is clean (CPLB_DIRTY==0), then a write to the - * CPLB's page triggers a protection violation. We have to - * mark the CPLB as dirty, to indicate that there are - * pending writes associated with the CPLB. - */ - - P4.L = (DCPLB_STATUS & 0xFFFF); - P4.H = (DCPLB_STATUS >> 16); - P3.L = (DCPLB_DATA0 & 0xFFFF); - P3.H = (DCPLB_DATA0 >> 16); - R5 = [P4]; - - /* A protection violation can be caused by more than just writes - * to a clean WB page, so we have to ensure that: - * - It's a write - * - to a clean WB page - * - and is allowed in the mode the access occurred. - */ - - CC = BITTST(R5, 16); /* ensure it was a write*/ - IF !CC JUMP prot_violation; - - /* to check the rest, we have to retrieve the DCPLB.*/ - - /* The low half of DCPLB_STATUS is a bit mask*/ - - R2 = R5.L (Z); /* indicating which CPLB triggered the event.*/ - R3 = 30; /* so we can use this to determine the offset*/ - R2.L = SIGNBITS R2; - R2 = R2.L (Z); /* into the DCPLB table.*/ - R3 = R3 - R2; - P4 = R3; - P3 = P3 + (P4<<2); - R3 = [P3]; /* Retrieve the CPLB*/ - - /* Now we can check whether it's a clean WB page*/ - - CC = BITTST(R3, 14); /* 0==WB, 1==WT*/ - IF CC JUMP prot_violation; - CC = BITTST(R3, 7); /* 0 == clean, 1 == dirty*/ - IF CC JUMP prot_violation; - - /* Check whether the write is allowed in the mode that was active.*/ - - R2 = 1<<3; /* checking write in user mode*/ - CC = BITTST(R5, 17); /* 0==was user, 1==was super*/ - R5 = CC; - R2 <<= R5; /* if was super, check write in super mode*/ - R2 = R3 & R2; - CC = R2 == 0; - IF CC JUMP prot_violation; - - /* It's a genuine write-to-clean-page.*/ - - BITSET(R3, 7); /* mark as dirty*/ - [P3] = R3; /* and write back.*/ - CSYNC; - ( R7:0,P5:0 ) = [SP++]; - R0 = CPLB_RELOADED; - RTS; - -dcplb_miss_compare: - - /* Data CPLB Miss event. We need to choose a CPLB to - * evict, and then locate a new CPLB to install from the - * config table, that covers the faulting address. - */ - - P1.L = (DCPLB_DATA15 & 0xFFFF); - P1.H = (DCPLB_DATA15 >> 16); - - P4.L = (DCPLB_FAULT_ADDR & 0xFFFF); - P4.H = (DCPLB_FAULT_ADDR >> 16); - R4 = [P4]; - I0 = R4; - - /* The replacement procedure for DCPLBs*/ - - R6 = R1; /* Save for later*/ - - /* Turn off CPLBs while we work.*/ - P4.L = (DMEM_CONTROL & 0xFFFF); - P4.H = (DMEM_CONTROL >> 16); - R5 = [P4]; - BITCLR(R5,ENDCPLB_P); - CLI R0; - SSYNC; /* SSYNC required before writing to DMEM_CONTROL. */ - .align 8; - [P4] = R5; - SSYNC; - STI R0; - - /* Start looking for a CPLB to evict. Our order of preference - * is: invalid CPLBs, clean CPLBs, dirty CPLBs. Locked CPLBs - * are no good. - */ - - I1.L = (DCPLB_DATA0 & 0xFFFF); - I1.H = (DCPLB_DATA0 >> 16); - P1 = 3; - P2 = 16; - I2.L = dcplb_preference; - I2.H = dcplb_preference; - LSETUP(sdsearch1, edsearch1) LC0 = P1; -sdsearch1: - R0 = [I2++]; /* Get the bits we're interested in*/ - P0 = I1; /* Go back to start of table*/ - LSETUP (sdsearch2, edsearch2) LC1 = P2; -sdsearch2: - R1 = [P0++]; /* Fetch each installed CPLB in turn*/ - R2 = R1 & R0; /* and test for interesting bits.*/ - CC = R2 == 0; /* If none are set, it'll do.*/ - IF !CC JUMP skip_stack_check; - - R2 = [P0 - 0x104]; /* R2 - PageStart */ - P3.L = page_size_table; /* retrive end address */ - P3.H = page_size_table; /* retrive end address */ - R3 = 0x2; /* 0th - position, 2 bits -length */ - nop; /*Anamoly 05000209*/ - R7 = EXTRACT(R1,R3.l); - R7 = R7 << 2; /* Page size index offset */ - P5 = R7; - P3 = P3 + P5; - R7 = [P3]; /* page size in 1K bytes */ - - R7 = R7 << 0xA; /* in bytes * 1024*/ - R7 = R2 + R7; /* R7 - PageEnd */ - R4 = SP; /* Test SP is in range */ - - CC = R7 < R4; /* if PageEnd < SP */ - IF CC JUMP dfound_victim; - R3 = 0x284; /* stack length from start of trap till the point */ - /* 20 stack locations for future modifications */ - R4 = R4 + R3; - CC = R4 < R2; /* if SP + stacklen < PageStart */ - IF CC JUMP dfound_victim; -skip_stack_check: - -edsearch2: NOP; -edsearch1: NOP; - - /* If we got here, we didn't find a DCPLB we considered - * replacable, which means all of them were locked. - */ - - JUMP all_locked; -dfound_victim: - -#ifdef CONFIG_CPLB_INFO - R1 = [P0 - 0x104]; - P2.L = dpdt_table; - P2.H = dpdt_table; - P3.L = dpdt_swapcount_table; - P3.H = dpdt_swapcount_table; - P3 += -4; -dicount: - R2 = [P2]; - P2 += 8; - P3 += 8; - CC = R2==-1; - IF CC JUMP dicount_done; - CC = R1==R2; - IF !CC JUMP dicount; - R1 = [P3]; - R1 += 1; - [P3] = R1; - CSYNC; -dicount_done: -#endif - - /* Clean down the hardware loops*/ - R2 = 0; - LC1 = R2; - LC0 = R2; - - /* There's a suitable victim in [P0-4] (because we've - * advanced already). If it's a valid dirty write-back - * CPLB, we need to flush the pending writes first. - */ - - CC = BITTST(R1, 0); /* Is it valid?*/ - IF !CC JUMP Ddoverwrite;/* nope.*/ - CC = BITTST(R1, 7); /* Is it dirty?*/ - IF !CC JUMP Ddoverwrite (BP); /* Nope.*/ - CC = BITTST(R1, 14); /* Is it Write-Through?*/ - IF CC JUMP Ddoverwrite; /* Yep*/ - - /* This is a dirty page, so we need to flush all writes - * that are pending on the page. - */ - - /* Retrieve the page start address*/ - R0 = [P0 - 0x104]; - [--sp] = rets; - CALL dcplb_flush; /* R0==CPLB addr, R1==CPLB data*/ - rets = [sp++]; -Ddoverwrite: - - /* [P0-4] is a suitable victim CPLB, so we want to - * overwrite it by moving all the following CPLBs - * one space closer to the start. - */ - - R1.L = ((DCPLB_DATA15+4) & 0xFFFF); /*DCPLB_DATA15+4*/ - R1.H = ((DCPLB_DATA15+4) >> 16); - R0 = P0; - - /* If the victim happens to be in DCPLB15, - * we don't need to move anything. - */ - - CC = R1 == R0; - IF CC JUMP de_moved; - R1 = R1 - R0; - R1 >>= 2; - P1 = R1; - LSETUP(ds_move, de_move) LC0=P1; -ds_move: - R0 = [P0++]; /* move data */ - [P0 - 8] = R0; - R0 = [P0-0x104] /* move address */ -de_move: [P0-0x108] = R0; - - /* We've now made space in DCPLB15 for the new CPLB to be - * installed. The next stage is to locate a CPLB in the - * config table that covers the faulting address. - */ - -de_moved:NOP; - R0 = I0; /* Our faulting address */ - - P2.L = dpdt_table; - P2.H = dpdt_table; -#ifdef CONFIG_CPLB_INFO - P3.L = dpdt_swapcount_table; - P3.H = dpdt_swapcount_table; - P3 += -8; -#endif - - P1.L = page_size_table; - P1.H = page_size_table; - - /* An extraction pattern, to retrieve bits 17:16.*/ - - R1 = (16<<8)|2; -dnext: R4 = [P2++]; /* address */ - R2 = [P2++]; /* data */ -#ifdef CONFIG_CPLB_INFO - P3 += 8; -#endif - - CC = R4 == -1; - IF CC JUMP no_page_in_table; - - /* See if failed address > start address */ - CC = R4 <= R0(IU); - IF !CC JUMP dnext; - - /* extract page size (17:16)*/ - R3 = EXTRACT(R2, R1.L) (Z); - - /* add page size to addr to get range */ - - P5 = R3; - P5 = P1 + (P5 << 2); - R3 = [P5]; - R3 = R3 + R4; - - /* See if failed address < (start address + page size) */ - CC = R0 < R3(IU); - IF !CC JUMP dnext; - - /* We've found the CPLB that should be installed, so - * write it into CPLB15, masking off any caching bits - * if necessary. - */ - - P1.L = (DCPLB_DATA15 & 0xFFFF); - P1.H = (DCPLB_DATA15 >> 16); - - /* If the DCPLB has cache bits set, but caching hasn't - * been enabled, then we want to mask off the cache-in-L1 - * bit before installing. Moreover, if caching is off, we - * also want to ensure that the DCPLB has WT mode set, rather - * than WB, since WB pages still trigger first-write exceptions - * even when not caching is off, and the page isn't marked as - * cachable. Finally, we could mark the page as clean, not dirty, - * but we choose to leave that decision to the user; if the user - * chooses to have a CPLB pre-defined as dirty, then they always - * pay the cost of flushing during eviction, but don't pay the - * cost of first-write exceptions to mark the page as dirty. - */ - -#ifdef CONFIG_BLKFIN_WT - BITSET(R6, 14); /* Set WT*/ -#endif - - [P1] = R2; - [P1-0x100] = R4; -#ifdef CONFIG_CPLB_INFO - R3 = [P3]; - R3 += 1; - [P3] = R3; -#endif - - /* We've installed the CPLB, so re-enable CPLBs. P4 - * points to DMEM_CONTROL, and R5 is the value we - * last wrote to it, when we were disabling CPLBs. - */ - - BITSET(R5,ENDCPLB_P); - CLI R2; - .align 8; - [P4] = R5; - SSYNC; - STI R2; - - ( R7:0,P5:0 ) = [SP++]; - R0 = CPLB_RELOADED; - RTS; - -.data -.align 4; -page_size_table: -.byte4 0x00000400; /* 1K */ -.byte4 0x00001000; /* 4K */ -.byte4 0x00100000; /* 1M */ -.byte4 0x00400000; /* 4M */ - -.align 4; -dcplb_preference: -.byte4 0x00000001; /* valid bit */ -.byte4 0x00000082; /* dirty+lock bits */ -.byte4 0x00000002; /* lock bit */ diff --git a/cpu/bf533/cpu.c b/cpu/bf533/cpu.c index 78e2b96..ac8ec51 100644 --- a/cpu/bf533/cpu.c +++ b/cpu/bf533/cpu.c @@ -29,72 +29,19 @@ #include <asm/blackfin.h> #include <command.h> #include <asm/entry.h> +#include <asm/cplb.h> +#include <asm/io.h> -#define SSYNC() asm("ssync;") #define CACHE_ON 1 #define CACHE_OFF 0 -/* Data Attibutes*/ - -#define SDRAM_IGENERIC (PAGE_SIZE_4MB | CPLB_L1_CHBL | CPLB_USER_RD | CPLB_VALID) -#define SDRAM_IKERNEL (PAGE_SIZE_4MB | CPLB_L1_CHBL | CPLB_USER_RD | CPLB_VALID | CPLB_LOCK) -#define L1_IMEMORY (PAGE_SIZE_1MB | CPLB_L1_CHBL | CPLB_USER_RD | CPLB_VALID | CPLB_LOCK) -#define SDRAM_INON_CHBL (PAGE_SIZE_4MB | CPLB_USER_RD | CPLB_VALID) - -#define ANOMALY_05000158 0x200 -#define SDRAM_DGENERIC (PAGE_SIZE_4MB | CPLB_L1_CHBL | CPLB_WT | CPLB_L1_AOW | CPLB_SUPV_WR | CPLB_USER_RD | CPLB_USER_WR | CPLB_VALID | ANOMALY_05000158) -#define SDRAM_DNON_CHBL (PAGE_SIZE_4MB | CPLB_WT | CPLB_L1_AOW | CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID | ANOMALY_05000158) -#define SDRAM_DKERNEL (PAGE_SIZE_4MB | CPLB_L1_CHBL | CPLB_WT | CPLB_L1_AOW | CPLB_USER_RD | CPLB_SUPV_WR | CPLB_USER_WR | CPLB_VALID | CPLB_LOCK | ANOMALY_05000158) -#define L1_DMEMORY (PAGE_SIZE_4KB | CPLB_L1_CHBL | CPLB_L1_AOW | CPLB_WT | CPLB_SUPV_WR | CPLB_USER_WR | CPLB_VALID | ANOMALY_05000158) -#define SDRAM_EBIU (PAGE_SIZE_4MB | CPLB_WT | CPLB_L1_AOW | CPLB_USER_RD | CPLB_USER_WR | CPLB_SUPV_WR | CPLB_VALID | ANOMALY_05000158) - -static unsigned int icplb_table[16][2]={ - {0xFFA00000, L1_IMEMORY}, - {0x00000000, SDRAM_IKERNEL}, /*SDRAM_Page1*/ - {0x00400000, SDRAM_IKERNEL}, /*SDRAM_Page1*/ - {0x07C00000, SDRAM_IKERNEL}, /*SDRAM_Page14*/ - {0x00800000, SDRAM_IGENERIC}, /*SDRAM_Page2*/ - {0x00C00000, SDRAM_IGENERIC}, /*SDRAM_Page2*/ - {0x01000000, SDRAM_IGENERIC}, /*SDRAM_Page4*/ - {0x01400000, SDRAM_IGENERIC}, /*SDRAM_Page5*/ - {0x01800000, SDRAM_IGENERIC}, /*SDRAM_Page6*/ - {0x01C00000, SDRAM_IGENERIC}, /*SDRAM_Page7*/ - {0x02000000, SDRAM_IGENERIC}, /*SDRAM_Page8*/ - {0x02400000, SDRAM_IGENERIC}, /*SDRAM_Page9*/ - {0x02800000, SDRAM_IGENERIC}, /*SDRAM_Page10*/ - {0x02C00000, SDRAM_IGENERIC}, /*SDRAM_Page11*/ - {0x03000000, SDRAM_IGENERIC}, /*SDRAM_Page12*/ - {0x03400000, SDRAM_IGENERIC}, /*SDRAM_Page13*/ -}; - -static unsigned int dcplb_table[16][2]={ - {0xFFA00000,L1_DMEMORY}, - {0x00000000,SDRAM_DKERNEL}, /*SDRAM_Page1*/ - {0x00400000,SDRAM_DKERNEL}, /*SDRAM_Page1*/ - {0x07C00000,SDRAM_DKERNEL}, /*SDRAM_Page15*/ - {0x00800000,SDRAM_DGENERIC}, /*SDRAM_Page2*/ - {0x00C00000,SDRAM_DGENERIC}, /*SDRAM_Page3*/ - {0x01000000,SDRAM_DGENERIC}, /*SDRAM_Page4*/ - {0x01400000,SDRAM_DGENERIC}, /*SDRAM_Page5*/ - {0x01800000,SDRAM_DGENERIC}, /*SDRAM_Page6*/ - {0x01C00000,SDRAM_DGENERIC}, /*SDRAM_Page7*/ - {0x02000000,SDRAM_DGENERIC}, /*SDRAM_Page8*/ - {0x02400000,SDRAM_DGENERIC}, /*SDRAM_Page9*/ - {0x02800000,SDRAM_DGENERIC}, /*SDRAM_Page10*/ - {0x02C00000,SDRAM_DGENERIC}, /*SDRAM_Page11*/ - {0x03000000,SDRAM_DGENERIC}, /*SDRAM_Page12*/ - {0x20000000,SDRAM_EBIU}, /*For Network */ -}; - -int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +extern unsigned int icplb_table[page_descriptor_table_size][2]; +extern unsigned int dcplb_table[page_descriptor_table_size][2]; + +int do_reset(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) { - __asm__ __volatile__ - ("cli r3;" - "P0 = %0;" - "JUMP (P0);" - : - : "r" (L1_ISRAM) - ); + __asm__ __volatile__("cli r3;" "P0 = %0;" "JUMP (P0);"::"r"(L1_ISRAM) + ); return 0; } @@ -112,29 +59,62 @@ int cleanup_before_linux(void) void icache_enable(void) { - unsigned int *I0,*I1; - int i; + unsigned int *I0, *I1; + int i, j = 0; + /* Before enable icache, disable it first */ + icache_disable(); I0 = (unsigned int *)ICPLB_ADDR0; I1 = (unsigned int *)ICPLB_DATA0; - for(i=0;i<16;i++){ - *I0++ = icplb_table[i][0]; - *I1++ = icplb_table[i][1]; + /* make sure the locked ones go in first */ + for (i = 0; i < page_descriptor_table_size; i++) { + if (CPLB_LOCK & icplb_table[i][1]) { + debug("adding %02i %02i 0x%08x 0x%08x\n", i, j, + icplb_table[i][0], icplb_table[i][1]); + *I0++ = icplb_table[i][0]; + *I1++ = icplb_table[i][1]; + j++; + } + } + + for (i = 0; i < page_descriptor_table_size; i++) { + if (!(CPLB_LOCK & icplb_table[i][1])) { + debug("adding %02i %02i 0x%08x 0x%08x\n", i, j, + icplb_table[i][0], icplb_table[i][1]); + *I0++ = icplb_table[i][0]; + *I1++ = icplb_table[i][1]; + j++; + if (j == 16) { + break; + } + } + } + + /* Fill the rest with invalid entry */ + if (j <= 15) { + for (; j <= 16; j++) { + debug("filling %i with 0", j); + *I1++ = 0x0; } + + } + cli(); - SSYNC(); + sync(); + asm(" .align 8; "); *(unsigned int *)IMEM_CONTROL = IMC | ENICPLB; - SSYNC(); + sync(); sti(); } void icache_disable(void) { cli(); - SSYNC(); + sync(); + asm(" .align 8; "); *(unsigned int *)IMEM_CONTROL &= ~(IMC | ENICPLB); - SSYNC(); + sync(); sti(); } @@ -143,7 +123,7 @@ int icache_status(void) unsigned int value; value = *(unsigned int *)IMEM_CONTROL; - if( value & (IMC|ENICPLB) ) + if (value & (IMC | ENICPLB)) return CACHE_ON; else return CACHE_OFF; @@ -151,38 +131,90 @@ int icache_status(void) void dcache_enable(void) { - unsigned int *I0,*I1; + unsigned int *I0, *I1; unsigned int temp; - int i; + int i, j = 0; + + /* Before enable dcache, disable it first */ + dcache_disable(); I0 = (unsigned int *)DCPLB_ADDR0; I1 = (unsigned int *)DCPLB_DATA0; - for(i=0;i<16;i++){ - *I0++ = dcplb_table[i][0]; - *I1++ = dcplb_table[i][1]; + /* make sure the locked ones go in first */ + for (i = 0; i < page_descriptor_table_size; i++) { + if (CPLB_LOCK & dcplb_table[i][1]) { + debug("adding %02i %02i 0x%08x 0x%08x\n", i, j, + dcplb_table[i][0], dcplb_table[i][1]); + *I0++ = dcplb_table[i][0]; + *I1++ = dcplb_table[i][1]; + j++; + } else { + debug("skip %02i %02i 0x%08x 0x%08x\n", i, j, + dcplb_table[i][0], dcplb_table[i][1]); + } + } + + for (i = 0; i < page_descriptor_table_size; i++) { + if (!(CPLB_LOCK & dcplb_table[i][1])) { + debug("adding %02i %02i 0x%08x 0x%08x\n", i, j, + dcplb_table[i][0], dcplb_table[i][1]); + *I0++ = dcplb_table[i][0]; + *I1++ = dcplb_table[i][1]; + j++; + if (j == 16) { + break; + } } + } + + /* Fill the rest with invalid entry */ + if (j <= 15) { + for (; j <= 16; j++) { + debug("filling %i with 0", j); + *I1++ = 0x0; + } + } + cli(); temp = *(unsigned int *)DMEM_CONTROL; - SSYNC(); - *(unsigned int *)DMEM_CONTROL = ACACHE_BCACHE |ENDCPLB |PORT_PREF0|temp; - SSYNC(); + sync(); + asm(" .align 8; "); + *(unsigned int *)DMEM_CONTROL = + ACACHE_BCACHE | ENDCPLB | PORT_PREF0 | temp; + sync(); sti(); } void dcache_disable(void) { + unsigned int *I0, *I1; + int i; + cli(); - SSYNC(); - *(unsigned int *)DMEM_CONTROL &= ~(ACACHE_BCACHE |ENDCPLB |PORT_PREF0); - SSYNC(); + sync(); + asm(" .align 8; "); + *(unsigned int *)DMEM_CONTROL &= + ~(ACACHE_BCACHE | ENDCPLB | PORT_PREF0); + sync(); sti(); + + /* after disable dcache, + * clear it so we don't confuse the next application + */ + I0 = (unsigned int *)DCPLB_ADDR0; + I1 = (unsigned int *)DCPLB_DATA0; + + for (i = 0; i < 16; i++) { + *I0++ = 0x0; + *I1++ = 0x0; + } } int dcache_status(void) { unsigned int value; value = *(unsigned int *)DMEM_CONTROL; - if( value & (ENDCPLB)) + if (value & (ENDCPLB)) return CACHE_ON; else return CACHE_OFF; diff --git a/cpu/bf533/cpu.h b/cpu/bf533/cpu.h index 7ec3387..821363e 100644 --- a/cpu/bf533/cpu.h +++ b/cpu/bf533/cpu.h @@ -32,8 +32,8 @@ #define DEF_INTERRUPT_FLAGS 1 #define MAX_TIM_LOAD 0xFFFFFFFF -void blackfin_irq_panic(int reason, struct pt_regs * reg); -extern void dump(struct pt_regs * regs); +void blackfin_irq_panic(int reason, struct pt_regs *reg); +extern void dump(struct pt_regs *regs); void display_excp(void); asmlinkage void evt_nmi(void); asmlinkage void evt_exception(void); @@ -50,16 +50,17 @@ asmlinkage void evt_evt12(void); asmlinkage void evt_evt13(void); asmlinkage void evt_soft_int1(void); asmlinkage void evt_system_call(void); -void blackfin_irq_panic(int reason, struct pt_regs * regs); +void blackfin_irq_panic(int reason, struct pt_regs *regs); void blackfin_free_irq(unsigned int irq, void *dev_id); -void call_isr(int irq, struct pt_regs * fp); +void call_isr(int irq, struct pt_regs *fp); void blackfin_do_irq(int vec, struct pt_regs *fp); void blackfin_init_IRQ(void); void blackfin_enable_irq(unsigned int irq); void blackfin_disable_irq(unsigned int irq); -extern int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]); +extern int do_reset(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]); int blackfin_request_irq(unsigned int irq, - void (*handler)(int, void *, struct pt_regs *), - unsigned long flags,const char *devname,void *dev_id); + void (*handler) (int, void *, struct pt_regs *), + unsigned long flags, const char *devname, + void *dev_id); void timer_init(void); #endif diff --git a/cpu/bf533/flush.S b/cpu/bf533/flush.S index 9fbdefc..0512f3b 100644 --- a/cpu/bf533/flush.S +++ b/cpu/bf533/flush.S @@ -3,13 +3,12 @@ * * This file is subject to the terms and conditions of the GNU General Public * License. - * - * Blackfin BF533/2.6 support : LG Soft India */ #define ASSEMBLY #include <asm/linkage.h> #include <asm/cplb.h> +#include <config.h> #include <asm/blackfin.h> .text @@ -20,7 +19,7 @@ * in the instruction cache. */ -ENTRY(flush_instruction_cache) +ENTRY(_flush_instruction_cache) [--SP] = ( R7:6, P5:4 ); LINK 12; SP += -12; @@ -33,7 +32,7 @@ ENTRY(flush_instruction_cache) inext: R0 = [P5++]; R1 = [P4++]; [--SP] = RETS; - CALL icplb_flush; /* R0 = page, R1 = data*/ + CALL _icplb_flush; /* R0 = page, R1 = data*/ RETS = [SP++]; iskip: R6 += -1; CC = R6; @@ -52,7 +51,7 @@ iskip: R6 += -1; */ .align 2 -ENTRY(icplb_flush) +ENTRY(_icplb_flush) [--SP] = ( R7:0, P5:0 ); [--SP] = LC0; [--SP] = LT0; @@ -86,16 +85,17 @@ ENTRY(icplb_flush) */ R3 = ((12<<8)|2); /* Extraction pattern */ - nop; /*Anamoly 05000209*/ - R4 = EXTRACT(R0, R3.L) (Z); /* Extract bits*/ - R3.H = R4.L << 0 ; /* Save in extraction pattern for later deposit.*/ + nop; /* Anamoly 05000209 */ + R4 = EXTRACT(R0, R3.L) (Z); /* Extract bits */ + /* Save in extraction pattern for later deposit. */ + R3.H = R4.L << 0; /* So: * R0 = Page start * R1 = Page length (actually, offset into size/prefix tables) * R3 = sub-bank deposit values - * + * * The cache has 2 Ways, and 64 sets, so we iterate through * the sets, accessing the tag for each Way, for our Bank and * sub-bank, looking for dirty, valid tags that match our @@ -180,8 +180,10 @@ iflush_whole_page: SSYNC; IFLUSH [P0++]; /* because CSYNC can't end loops.*/ LSETUP (isall, ieall) LC0 = P1; -isall:IFLUSH [P0++]; -ieall: NOP; +isall: + IFLUSH [P0++]; +ieall: + NOP; SSYNC; JUMP ifinished; @@ -191,7 +193,7 @@ ieall: NOP; * in the data cache. */ -ENTRY(flush_data_cache) +ENTRY(_flush_data_cache) [--SP] = ( R7:6, P5:4 ); LINK 12; SP += -12; @@ -209,7 +211,7 @@ next: R0 = [P5++]; CC = R2; IF !CC JUMP skip; /* If not, ignore it.*/ [--SP] = RETS; - CALL dcplb_flush; /* R0 = page, R1 = data*/ + CALL _dcplb_flush; /* R0 = page, R1 = data*/ RETS = [SP++]; skip: R6 += -1; CC = R6; @@ -228,7 +230,7 @@ skip: R6 += -1; */ .align 2 -ENTRY(dcplb_flush) +ENTRY(_dcplb_flush) [--SP] = ( R7:0, P5:0 ); [--SP] = LC0; [--SP] = LT0; @@ -290,14 +292,15 @@ bank_chosen: R3 = ((12<<8)|2); /* Extraction pattern */ nop; /*Anamoly 05000209*/ R4 = EXTRACT(R0, R3.L) (Z); /* Extract bits*/ - R3.H = R4.L << 0 ; /* Save in extraction pattern for later deposit.*/ + /* Save in extraction pattern for later deposit.*/ + R3.H = R4.L << 0; /* So: * R0 = Page start * R1 = Page length (actually, offset into size/prefix tables) * R2 = Bank select mask * R3 = sub-bank deposit values - * + * * The cache has 2 Ways, and 64 sets, so we iterate through * the sets, accessing the tag for each Way, for our Bank and * sub-bank, looking for dirty, valid tags that match our @@ -386,7 +389,7 @@ dflush_whole_page: CC = BITTST(R1, 16); /* Whether 1K or 4K*/ IF CC P1 = P2; P1 += -1; /* Unroll one iteration*/ - SSYNC; + SSYNC; FLUSHINV [P0++]; /* because CSYNC can't end loops.*/ LSETUP (eall, eall) LC0 = P1; eall: FLUSHINV [P0++]; diff --git a/cpu/bf533/init_sdram.S b/cpu/bf533/init_sdram.S new file mode 100644 index 0000000..e1a8e2f --- /dev/null +++ b/cpu/bf533/init_sdram.S @@ -0,0 +1,179 @@ +#define ASSEMBLY + +#include <linux/config.h> +#include <config.h> +#include <asm/blackfin.h> +#include <asm/mem_init.h> +.global init_sdram; + +#if (CONFIG_CCLK_DIV == 1) +#define CONFIG_CCLK_ACT_DIV CCLK_DIV1 +#endif +#if (CONFIG_CCLK_DIV == 2) +#define CONFIG_CCLK_ACT_DIV CCLK_DIV2 +#endif +#if (CONFIG_CCLK_DIV == 4) +#define CONFIG_CCLK_ACT_DIV CCLK_DIV4 +#endif +#if (CONFIG_CCLK_DIV == 8) +#define CONFIG_CCLK_ACT_DIV CCLK_DIV8 +#endif +#ifndef CONFIG_CCLK_ACT_DIV +#define CONFIG_CCLK_ACT_DIV CONFIG_CCLK_DIV_not_defined_properly +#endif + +init_sdram: + [--SP] = ASTAT; + [--SP] = RETS; + [--SP] = (R7:0); + [--SP] = (P5:0); + +#if (BFIN_BOOT_MODE == BF533_SPI_BOOT) + p0.h = hi(SPI_BAUD); + p0.l = lo(SPI_BAUD); + r0.l = CONFIG_SPI_BAUD; + w[p0] = r0.l; + SSYNC; +#endif + + /* + * PLL_LOCKCNT - how many SCLK Cycles to delay while PLL becomes stable + */ + p0.h = hi(PLL_LOCKCNT); + p0.l = lo(PLL_LOCKCNT); + r0 = 0x300(Z); + w[p0] = r0.l; + ssync; + + /* + * Put SDRAM in self-refresh, incase anything is running + */ + P2.H = hi(EBIU_SDGCTL); + P2.L = lo(EBIU_SDGCTL); + R0 = [P2]; + BITSET (R0, 24); + [P2] = R0; + SSYNC; + + /* + * Set PLL_CTL with the value that we calculate in R0 + * - [14:09] = MSEL[5:0] : CLKIN / VCO multiplication factors + * - [8] = BYPASS : BYPASS the PLL, run CLKIN into CCLK/SCLK + * - [7] = output delay (add 200ps of delay to mem signals) + * - [6] = input delay (add 200ps of input delay to mem signals) + * - [5] = PDWN : 1=All Clocks off + * - [3] = STOPCK : 1=Core Clock off + * - [1] = PLL_OFF : 1=Disable Power to PLL + * - [0] = DF : 1=Pass CLKIN/2 to PLL / 0=Pass CLKIN to PLL + * all other bits set to zero + */ + + r0 = CONFIG_VCO_MULT & 63; /* Load the VCO multiplier */ + r0 = r0 << 9; /* Shift it over, */ + r1 = CONFIG_CLKIN_HALF; /* Do we need to divide CLKIN by 2?*/ + r0 = r1 | r0; + r1 = CONFIG_PLL_BYPASS; /* Bypass the PLL? */ + r1 = r1 << 8; /* Shift it over */ + r0 = r1 | r0; /* add them all together */ + + p0.h = hi(PLL_CTL); + p0.l = lo(PLL_CTL); /* Load the address */ + cli r2; /* Disable interrupts */ + ssync; + w[p0] = r0.l; /* Set the value */ + idle; /* Wait for the PLL to stablize */ + sti r2; /* Enable interrupts */ + +check_again: + p0.h = hi(PLL_STAT); + p0.l = lo(PLL_STAT); + R0 = W[P0](Z); + CC = BITTST(R0,5); + if ! CC jump check_again; + + /* Configure SCLK & CCLK Dividers */ + r0 = (CONFIG_CCLK_ACT_DIV | CONFIG_SCLK_DIV); + p0.h = hi(PLL_DIV); + p0.l = lo(PLL_DIV); + w[p0] = r0.l; + ssync; + + /* + * We now are running at speed, time to set the Async mem bank wait states + * This will speed up execution, since we are normally running from FLASH. + */ + + p2.h = (EBIU_AMBCTL1 >> 16); + p2.l = (EBIU_AMBCTL1 & 0xFFFF); + r0.h = (AMBCTL1VAL >> 16); + r0.l = (AMBCTL1VAL & 0xFFFF); + [p2] = r0; + ssync; + + p2.h = (EBIU_AMBCTL0 >> 16); + p2.l = (EBIU_AMBCTL0 & 0xFFFF); + r0.h = (AMBCTL0VAL >> 16); + r0.l = (AMBCTL0VAL & 0xFFFF); + [p2] = r0; + ssync; + + p2.h = (EBIU_AMGCTL >> 16); + p2.l = (EBIU_AMGCTL & 0xffff); + r0 = AMGCTLVAL; + w[p2] = r0; + ssync; + + /* + * Now, Initialize the SDRAM, + * start with the SDRAM Refresh Rate Control Register + */ + p0.l = lo(EBIU_SDRRC); + p0.h = hi(EBIU_SDRRC); + r0 = mem_SDRRC; + w[p0] = r0.l; + ssync; + + /* + * SDRAM Memory Bank Control Register - bank specific parameters + */ + p0.l = (EBIU_SDBCTL & 0xFFFF); + p0.h = (EBIU_SDBCTL >> 16); + r0 = mem_SDBCTL; + w[p0] = r0.l; + ssync; + + /* + * SDRAM Global Control Register - global programmable parameters + * Disable self-refresh + */ + P2.H = hi(EBIU_SDGCTL); + P2.L = lo(EBIU_SDGCTL); + R0 = [P2]; + BITCLR (R0, 24); + + /* + * Check if SDRAM is already powered up, if it is, enable self-refresh + */ + p0.h = hi(EBIU_SDSTAT); + p0.l = lo(EBIU_SDSTAT); + r2.l = w[p0]; + cc = bittst(r2,3); + if !cc jump skip; + NOP; + BITSET (R0, 23); +skip: + [P2] = R0; + SSYNC; + + /* Write in the new value in the register */ + R0.L = lo(mem_SDGCTL); + R0.H = hi(mem_SDGCTL); + [P2] = R0; + SSYNC; + nop; + + (P5:0) = [SP++]; + (R7:0) = [SP++]; + RETS = [SP++]; + ASTAT = [SP++]; + RTS; diff --git a/cpu/bf533/init_sdram_bootrom_initblock.S b/cpu/bf533/init_sdram_bootrom_initblock.S new file mode 100644 index 0000000..99ed920 --- /dev/null +++ b/cpu/bf533/init_sdram_bootrom_initblock.S @@ -0,0 +1,179 @@ +#define ASSEMBLY + +#include <linux/config.h> +#include <config.h> +#include <asm/blackfin.h> +#include <asm/mem_init.h> +.global init_sdram; + +#if (CONFIG_CCLK_DIV == 1) +#define CONFIG_CCLK_ACT_DIV CCLK_DIV1 +#endif +#if (CONFIG_CCLK_DIV == 2) +#define CONFIG_CCLK_ACT_DIV CCLK_DIV2 +#endif +#if (CONFIG_CCLK_DIV == 4) +#define CONFIG_CCLK_ACT_DIV CCLK_DIV4 +#endif +#if (CONFIG_CCLK_DIV == 8) +#define CONFIG_CCLK_ACT_DIV CCLK_DIV8 +#endif +#ifndef CONFIG_CCLK_ACT_DIV +#define CONFIG_CCLK_ACT_DIV CONFIG_CCLK_DIV_not_defined_properly +#endif + +init_sdram: + [--SP] = ASTAT; + [--SP] = RETS; + [--SP] = (R7:0); + [--SP] = (P5:0); + +#if (BFIN_BOOT_MODE == BF533_SPI_BOOT) + p0.h = hi(SPI_BAUD); + p0.l = lo(SPI_BAUD); + r0.l = CONFIG_SPI_BAUD_INITBLOCK; + w[p0] = r0.l; + SSYNC; +#endif + + /* + * PLL_LOCKCNT - how many SCLK Cycles to delay while PLL becomes stable + */ + p0.h = hi(PLL_LOCKCNT); + p0.l = lo(PLL_LOCKCNT); + r0 = 0x300(Z); + w[p0] = r0.l; + ssync; + + /* + * Put SDRAM in self-refresh, incase anything is running + */ + P2.H = hi(EBIU_SDGCTL); + P2.L = lo(EBIU_SDGCTL); + R0 = [P2]; + BITSET (R0, 24); + [P2] = R0; + SSYNC; + + /* + * Set PLL_CTL with the value that we calculate in R0 + * - [14:09] = MSEL[5:0] : CLKIN / VCO multiplication factors + * - [8] = BYPASS : BYPASS the PLL, run CLKIN into CCLK/SCLK + * - [7] = output delay (add 200ps of delay to mem signals) + * - [6] = input delay (add 200ps of input delay to mem signals) + * - [5] = PDWN : 1=All Clocks off + * - [3] = STOPCK : 1=Core Clock off + * - [1] = PLL_OFF : 1=Disable Power to PLL + * - [0] = DF : 1=Pass CLKIN/2 to PLL / 0=Pass CLKIN to PLL + * all other bits set to zero + */ + + r0 = CONFIG_VCO_MULT & 63; /* Load the VCO multiplier */ + r0 = r0 << 9; /* Shift it over, */ + r1 = CONFIG_CLKIN_HALF; /* Do we need to divide CLKIN by 2?*/ + r0 = r1 | r0; + r1 = CONFIG_PLL_BYPASS; /* Bypass the PLL? */ + r1 = r1 << 8; /* Shift it over */ + r0 = r1 | r0; /* add them all together */ + + p0.h = hi(PLL_CTL); + p0.l = lo(PLL_CTL); /* Load the address */ + cli r2; /* Disable interrupts */ + ssync; + w[p0] = r0.l; /* Set the value */ + idle; /* Wait for the PLL to stablize */ + sti r2; /* Enable interrupts */ + +check_again: + p0.h = hi(PLL_STAT); + p0.l = lo(PLL_STAT); + R0 = W[P0](Z); + CC = BITTST(R0,5); + if ! CC jump check_again; + + /* Configure SCLK & CCLK Dividers */ + r0 = (CONFIG_CCLK_ACT_DIV | CONFIG_SCLK_DIV); + p0.h = hi(PLL_DIV); + p0.l = lo(PLL_DIV); + w[p0] = r0.l; + ssync; + + /* + * We now are running at speed, time to set the Async mem bank wait states + * This will speed up execution, since we are normally running from FLASH. + */ + + p2.h = (EBIU_AMBCTL1 >> 16); + p2.l = (EBIU_AMBCTL1 & 0xFFFF); + r0.h = (AMBCTL1VAL >> 16); + r0.l = (AMBCTL1VAL & 0xFFFF); + [p2] = r0; + ssync; + + p2.h = (EBIU_AMBCTL0 >> 16); + p2.l = (EBIU_AMBCTL0 & 0xFFFF); + r0.h = (AMBCTL0VAL >> 16); + r0.l = (AMBCTL0VAL & 0xFFFF); + [p2] = r0; + ssync; + + p2.h = (EBIU_AMGCTL >> 16); + p2.l = (EBIU_AMGCTL & 0xffff); + r0 = AMGCTLVAL; + w[p2] = r0; + ssync; + + /* + * Now, Initialize the SDRAM, + * start with the SDRAM Refresh Rate Control Register + */ + p0.l = lo(EBIU_SDRRC); + p0.h = hi(EBIU_SDRRC); + r0 = mem_SDRRC; + w[p0] = r0.l; + ssync; + + /* + * SDRAM Memory Bank Control Register - bank specific parameters + */ + p0.l = (EBIU_SDBCTL & 0xFFFF); + p0.h = (EBIU_SDBCTL >> 16); + r0 = mem_SDBCTL; + w[p0] = r0.l; + ssync; + + /* + * SDRAM Global Control Register - global programmable parameters + * Disable self-refresh + */ + P2.H = hi(EBIU_SDGCTL); + P2.L = lo(EBIU_SDGCTL); + R0 = [P2]; + BITCLR (R0, 24); + + /* + * Check if SDRAM is already powered up, if it is, enable self-refresh + */ + p0.h = hi(EBIU_SDSTAT); + p0.l = lo(EBIU_SDSTAT); + r2.l = w[p0]; + cc = bittst(r2,3); + if !cc jump skip; + NOP; + BITSET (R0, 23); +skip: + [P2] = R0; + SSYNC; + + /* Write in the new value in the register */ + R0.L = lo(mem_SDGCTL); + R0.H = hi(mem_SDGCTL); + [P2] = R0; + SSYNC; + nop; + + (P5:0) = [SP++]; + (R7:0) = [SP++]; + RETS = [SP++]; + ASTAT = [SP++]; + RTS; diff --git a/cpu/bf533/interrupt.S b/cpu/bf533/interrupt.S index e780dc6..524da8f 100644 --- a/cpu/bf533/interrupt.S +++ b/cpu/bf533/interrupt.S @@ -40,203 +40,58 @@ */ #define ASSEMBLY - +#include <config.h> +#include <asm/blackfin.h> #include <asm/hw_irq.h> #include <asm/entry.h> #include <asm/blackfin_defs.h> -#include <asm/cpu/bf533_irq.h> -.global blackfin_irq_panic; +.global _blackfin_irq_panic; .text .align 2 #ifndef CONFIG_KGDB -.global evt_emulation -evt_emulation: +.global _evt_emulation +_evt_emulation: SAVE_CONTEXT r0 = IRQ_EMU; r1 = seqstat; sp += -12; - call blackfin_irq_panic; + call _blackfin_irq_panic; sp += 12; rte; #endif -.global evt_nmi -evt_nmi: +.global _evt_nmi +_evt_nmi: SAVE_CONTEXT r0 = IRQ_NMI; r1 = RETN; sp += -12; - call blackfin_irq_panic; + call _blackfin_irq_panic; sp += 12; _evt_nmi_exit: rtn; -.global trap -trap: - [--sp] = r0; - [--sp] = r1; - [--sp] = p0; - [--sp] = p1; - [--sp] = astat; - r0 = seqstat; - R0 <<= 26; - R0 >>= 26; - p0 = r0; - p1.l = EVTABLE; - p1.h = EVTABLE; - p0 = p1 + (p0 << 1); - r1 = W[p0] (Z); - p1 = r1; - jump (pc + p1); - -.global _EVENT1 -_EVENT1: - RAISE 14; - JUMP.S _EXIT; - -.global _EVENT2 -_EVENT2: - RAISE 14; - JUMP.S _EXIT; - -.global _EVENT3 -_EVENT3: - RAISE 14; - JUMP.S _EXIT; - -.global _EVENT4 -_EVENT4: - RAISE 14; - JUMP.S _EXIT; - -.global _EVENT5 -_EVENT5: - RAISE 14; - JUMP.S _EXIT; - -.global _EVENT6 -_EVENT6: - RAISE 14; - JUMP.S _EXIT; - -.global _EVENT7 -_EVENT7: - RAISE 15; - JUMP.S _EXIT; - -.global _EVENT8 -_EVENT8: - RAISE 14; - JUMP.S _EXIT; - -.global _EVENT9 -_EVENT9: - RAISE 14; - JUMP.S _EXIT; - -.global _EVENT10 -_EVENT10: - RAISE 14; - JUMP.S _EXIT; - -.global _EVENT11 -_EVENT11: - RAISE 14; - JUMP.S _EXIT; - -.global _EVENT12 -_EVENT12: - RAISE 14; - JUMP.S _EXIT; - -.global _EVENT13 -_EVENT13: - RAISE 14; - JUMP.S _EXIT; - -.global _EVENT14 -_EVENT14: -/* RAISE 14; */ - CALL _cplb_hdr; - JUMP.S _EXIT; - -.global _EVENT19 -_EVENT19: - RAISE 14; - JUMP.S _EXIT; - -.global _EVENT20 -_EVENT20: - RAISE 14; - JUMP.S _EXIT; - -.global _EVENT21 -_EVENT21: - RAISE 14; - JUMP.S _EXIT; - -.global _EXIT -_EXIT: - ASTAT = [sp++]; - p1 = [sp++]; - p0 = [sp++]; - r1 = [sp++]; - r0 = [sp++]; - RTX; - -EVTABLE: - .byte2 0x0000; - .byte2 0x0000; - .byte2 0x0000; - .byte2 0x0000; - .byte2 0x0000; - .byte2 0x0000; - .byte2 0x0000; - .byte2 0x0000; - .byte2 0x0000; - .byte2 0x0000; - .byte2 0x0000; - .byte2 0x0000; - .byte2 0x0000; - .byte2 0x0000; - .byte2 0x0000; - .byte2 0x0000; - .byte2 0x003E; - .byte2 0x0042; - .byte4 0x0000; - .byte4 0x0000; - .byte4 0x0000; - .byte4 0x0000; - .byte4 0x0000; - .byte4 0x0000; - .byte4 0x0000; - .byte2 0x0000; - .byte2 0x001E; - .byte2 0x0022; - .byte2 0x0032; - .byte2 0x002e; - .byte2 0x0002; - .byte2 0x0036; - .byte2 0x002A; - .byte2 0x001A; - .byte2 0x0016; - .byte2 0x000A; - .byte2 0x000E; - .byte2 0x0012; - .byte2 0x0006; - .byte2 0x0026; +.global _trap +_trap: + SAVE_ALL_SYS + r0 = sp; /* stack frame pt_regs pointer argument ==> r0 */ + sp += -12; + call _trap_c + sp += 12; + RESTORE_ALL_SYS + rtx; -.global evt_rst -evt_rst: +.global _evt_rst +_evt_rst: SAVE_CONTEXT r0 = IRQ_RST; r1 = RETN; sp += -12; - call do_reset; + call _do_reset; sp += 12; _evt_rst_exit: @@ -246,19 +101,19 @@ irq_panic: r0 = IRQ_EVX; r1 = sp; sp += -12; - call blackfin_irq_panic; + call _blackfin_irq_panic; sp += 12; -.global evt_ivhw -evt_ivhw: +.global _evt_ivhw +_evt_ivhw: SAVE_CONTEXT RAISE 14; _evt_ivhw_exit: rti; -.global evt_timer -evt_timer: +.global _evt_timer +_evt_timer: SAVE_CONTEXT r0 = IRQ_CORETMR; sp += -12; @@ -269,91 +124,91 @@ evt_timer: rti; nop; -.global evt_evt7 -evt_evt7: +.global _evt_evt7 +_evt_evt7: SAVE_CONTEXT r0 = 7; sp += -12; - call process_int; + call _process_int; sp += 12; evt_evt7_exit: RESTORE_CONTEXT rti; -.global evt_evt8 -evt_evt8: +.global _evt_evt8 +_evt_evt8: SAVE_CONTEXT r0 = 8; sp += -12; - call process_int; + call _process_int; sp += 12; evt_evt8_exit: RESTORE_CONTEXT rti; -.global evt_evt9 -evt_evt9: +.global _evt_evt9 +_evt_evt9: SAVE_CONTEXT r0 = 9; sp += -12; - call process_int; + call _process_int; sp += 12; evt_evt9_exit: RESTORE_CONTEXT rti; -.global evt_evt10 -evt_evt10: +.global _evt_evt10 +_evt_evt10: SAVE_CONTEXT r0 = 10; sp += -12; - call process_int; + call _process_int; sp += 12; evt_evt10_exit: RESTORE_CONTEXT rti; -.global evt_evt11 -evt_evt11: +.global _evt_evt11 +_evt_evt11: SAVE_CONTEXT r0 = 11; sp += -12; - call process_int; + call _process_int; sp += 12; evt_evt11_exit: RESTORE_CONTEXT rti; -.global evt_evt12 -evt_evt12: +.global _evt_evt12 +_evt_evt12: SAVE_CONTEXT r0 = 12; sp += -12; - call process_int; + call _process_int; sp += 12; evt_evt12_exit: RESTORE_CONTEXT rti; -.global evt_evt13 -evt_evt13: +.global _evt_evt13 +_evt_evt13: SAVE_CONTEXT r0 = 13; sp += -12; - call process_int; + call _process_int; sp += 12; evt_evt13_exit: RESTORE_CONTEXT rti; -.global evt_system_call -evt_system_call: +.global _evt_system_call +_evt_system_call: [--sp] = r0; [--SP] = RETI; r0 = [sp++]; @@ -363,7 +218,7 @@ evt_system_call: r0 = [SP++]; SAVE_CONTEXT sp += -12; - call display_excp; + call _exception_handle; sp += 12; RESTORE_CONTEXT RTI; @@ -371,8 +226,8 @@ evt_system_call: evt_system_call_exit: rti; -.global evt_soft_int1 -evt_soft_int1: +.global _evt_soft_int1 +_evt_soft_int1: [--sp] = r0; [--SP] = RETI; r0 = [sp++]; @@ -382,7 +237,7 @@ evt_soft_int1: r0 = [SP++]; SAVE_CONTEXT sp += -12; - call display_excp; + call _exception_handle; sp += 12; RESTORE_CONTEXT RTI; diff --git a/cpu/bf533/interrupts.c b/cpu/bf533/interrupts.c index df1a25e..9317f26 100644 --- a/cpu/bf533/interrupts.c +++ b/cpu/bf533/interrupts.c @@ -10,7 +10,7 @@ * Copyright 2002 Arcturus Networks Inc. MaTed <mated@sympatico.ca> * Copyright 2003 Metrowerks/Motorola * Copyright 2003 Bas Vermeulen <bas@buyways.nl>, - * BuyWays B.V. (www.buyways.nl) + * BuyWays B.V. (www.buyways.nl) * * (C) Copyright 2000-2004 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. @@ -37,14 +37,15 @@ #include <common.h> #include <asm/machdep.h> #include <asm/irq.h> -#include <asm/cpu/defBF533.h> +#include <config.h> +#include <asm/blackfin.h> #include "cpu.h" static ulong timestamp; static ulong last_time; static int int_flag; -int irq_flags; /* needed by asm-blackfin/system.h */ +int irq_flags; /* needed by asm-blackfin/system.h */ /* Functions just to satisfy the linker */ @@ -61,7 +62,7 @@ unsigned long long get_ticks(void) * This function is derived from PowerPC code (timebase clock frequency). * On BF533 it returns the number of timer ticks per second. */ -ulong get_tbclk (void) +ulong get_tbclk(void) { ulong tbclk; @@ -91,22 +92,22 @@ void udelay(unsigned long usec) unsigned long cclk; cclk = (CONFIG_CCLK_HZ); - while ( usec > 1 ) { - /* - * how many clock ticks to delay? - * - request(in useconds) * clock_ticks(Hz) / useconds/second - */ + while (usec > 1) { + /* + * how many clock ticks to delay? + * - request(in useconds) * clock_ticks(Hz) / useconds/second + */ if (usec < 1000) { - delay = (usec * (cclk/244)) >> 12 ; + delay = (usec * (cclk / 244)) >> 12; usec = 0; } else { - delay = (1000 * (cclk/244)) >> 12 ; + delay = (1000 * (cclk / 244)) >> 12; usec -= 1000; } - asm volatile (" %0 = CYCLES;": "=g"(start)); + asm volatile (" %0 = CYCLES;":"=r" (start)); do { - asm volatile (" %0 = CYCLES; ": "=g"(stop)); + asm volatile (" %0 = CYCLES; ":"=r" (stop)); } while (stop - start < delay); } @@ -117,7 +118,7 @@ void timer_init(void) { *pTCNTL = 0x1; *pTSCALE = 0x0; - *pTCOUNT = MAX_TIM_LOAD; + *pTCOUNT = MAX_TIM_LOAD; *pTPERIOD = MAX_TIM_LOAD; *pTCNTL = 0x7; asm("CSYNC;"); @@ -146,20 +147,23 @@ ulong get_timer(ulong base) /* Number of clocks elapsed */ ulong clocks = (MAX_TIM_LOAD - (*pTCOUNT)); - /* Find if the TCOUNT is reset - timestamp gives the number of times - TCOUNT got reset */ - if(clocks < last_time) + /** + * Find if the TCOUNT is reset + * timestamp gives the number of times + * TCOUNT got reset + */ + if (clocks < last_time) timestamp++; last_time = clocks; /* Get the number of milliseconds */ - milisec = clocks/(CONFIG_CCLK_HZ / 1000); + milisec = clocks / (CONFIG_CCLK_HZ / 1000); - /* Find the number of millisonds - that got elapsed before this TCOUNT - cycle */ - milisec += timestamp * (MAX_TIM_LOAD/(CONFIG_CCLK_HZ / 1000)); + /** + * Find the number of millisonds + * that got elapsed before this TCOUNT cycle + */ + milisec += timestamp * (MAX_TIM_LOAD / (CONFIG_CCLK_HZ / 1000)); return (milisec - base); } diff --git a/cpu/bf533/ints.c b/cpu/bf533/ints.c index 859f4b2..f476f14 100644 --- a/cpu/bf533/ints.c +++ b/cpu/bf533/ints.c @@ -51,9 +51,9 @@ void blackfin_irq_panic(int reason, struct pt_regs *regs) { printf("\n\nException: IRQ 0x%x entered\n", reason); - printf("code=[0x%x], ", (unsigned int) (regs->seqstat & 0x3f)); - printf("stack frame=0x%x, ", (unsigned int) regs); - printf("bad PC=0x%04x\n", (unsigned int) regs->pc); + printf("code=[0x%x], ", (unsigned int)(regs->seqstat & 0x3f)); + printf("stack frame=0x%x, ", (unsigned int)regs); + printf("bad PC=0x%04x\n", (unsigned int)regs->pc); dump(regs); printf("Unhandled IRQ or exceptions!\n"); printf("Please reset the board \n"); @@ -61,46 +61,56 @@ void blackfin_irq_panic(int reason, struct pt_regs *regs) void blackfin_init_IRQ(void) { - *(unsigned volatile long *) (SIC_IMASK) = SIC_UNMASK_ALL; + *(unsigned volatile long *)(SIC_IMASK) = SIC_UNMASK_ALL; cli(); #ifndef CONFIG_KGDB - *(unsigned volatile long *) (EVT_EMULATION_ADDR) = 0x0; + *(unsigned volatile long *)(EVT_EMULATION_ADDR) = 0x0; #endif - *(unsigned volatile long *) (EVT_NMI_ADDR) = - (unsigned volatile long) evt_nmi; - *(unsigned volatile long *) (EVT_EXCEPTION_ADDR) = - (unsigned volatile long) trap; - *(unsigned volatile long *) (EVT_HARDWARE_ERROR_ADDR) = - (unsigned volatile long) evt_ivhw; - *(unsigned volatile long *) (EVT_RESET_ADDR) = - (unsigned volatile long) evt_rst; - *(unsigned volatile long *) (EVT_TIMER_ADDR) = - (unsigned volatile long) evt_timer; - *(unsigned volatile long *) (EVT_IVG7_ADDR) = - (unsigned volatile long) evt_evt7; - *(unsigned volatile long *) (EVT_IVG8_ADDR) = - (unsigned volatile long) evt_evt8; - *(unsigned volatile long *) (EVT_IVG9_ADDR) = - (unsigned volatile long) evt_evt9; - *(unsigned volatile long *) (EVT_IVG10_ADDR) = - (unsigned volatile long) evt_evt10; - *(unsigned volatile long *) (EVT_IVG11_ADDR) = - (unsigned volatile long) evt_evt11; - *(unsigned volatile long *) (EVT_IVG12_ADDR) = - (unsigned volatile long) evt_evt12; - *(unsigned volatile long *) (EVT_IVG13_ADDR) = - (unsigned volatile long) evt_evt13; - *(unsigned volatile long *) (EVT_IVG14_ADDR) = - (unsigned volatile long) evt_system_call; - *(unsigned volatile long *) (EVT_IVG15_ADDR) = - (unsigned volatile long) evt_soft_int1; - *(volatile unsigned long *) ILAT = 0; + *(unsigned volatile long *)(EVT_NMI_ADDR) = + (unsigned volatile long)evt_nmi; + *(unsigned volatile long *)(EVT_EXCEPTION_ADDR) = + (unsigned volatile long)trap; + *(unsigned volatile long *)(EVT_HARDWARE_ERROR_ADDR) = + (unsigned volatile long)evt_ivhw; + *(unsigned volatile long *)(EVT_RESET_ADDR) = + (unsigned volatile long)evt_rst; + *(unsigned volatile long *)(EVT_TIMER_ADDR) = + (unsigned volatile long)evt_timer; + *(unsigned volatile long *)(EVT_IVG7_ADDR) = + (unsigned volatile long)evt_evt7; + *(unsigned volatile long *)(EVT_IVG8_ADDR) = + (unsigned volatile long)evt_evt8; + *(unsigned volatile long *)(EVT_IVG9_ADDR) = + (unsigned volatile long)evt_evt9; + *(unsigned volatile long *)(EVT_IVG10_ADDR) = + (unsigned volatile long)evt_evt10; + *(unsigned volatile long *)(EVT_IVG11_ADDR) = + (unsigned volatile long)evt_evt11; + *(unsigned volatile long *)(EVT_IVG12_ADDR) = + (unsigned volatile long)evt_evt12; + *(unsigned volatile long *)(EVT_IVG13_ADDR) = + (unsigned volatile long)evt_evt13; + *(unsigned volatile long *)(EVT_IVG14_ADDR) = + (unsigned volatile long)evt_system_call; + *(unsigned volatile long *)(EVT_IVG15_ADDR) = + (unsigned volatile long)evt_soft_int1; + *(volatile unsigned long *)ILAT = 0; asm("csync;"); sti(); - *(volatile unsigned long *) IMASK = 0xffbf; + *(volatile unsigned long *)IMASK = 0xffbf; asm("csync;"); } +void exception_handle(void) +{ +#if defined (CONFIG_PANIC_HANG) + display_excp(); +#else + udelay(100000); /* allow messages to go out */ + do_reset(NULL, 0, 0, NULL); +#endif +} + void display_excp(void) { printf("Exception!\n"); diff --git a/cpu/bf533/serial.c b/cpu/bf533/serial.c index 7b43ffd..11a46be 100644 --- a/cpu/bf533/serial.c +++ b/cpu/bf533/serial.c @@ -49,6 +49,7 @@ #include <asm/bitops.h> #include <asm/delay.h> #include <asm/uaccess.h> +#include <asm/io.h> #include "bf533_serial.h" DECLARE_GLOBAL_DATA_PTR; @@ -58,15 +59,16 @@ unsigned long pll_div_fact; void calc_baud(void) { unsigned char i; - int temp; + int temp; + u_long sclk = get_sclk(); - for(i = 0; i < sizeof(baud_table)/sizeof(int); i++) { - temp = CONFIG_SCLK_HZ/(baud_table[i]*8); - if ( temp && 0x1 == 1 ) { + for (i = 0; i < sizeof(baud_table) / sizeof(int); i++) { + temp = sclk / (baud_table[i] * 8); + if ((temp & 0x1) == 1) { temp++; } - temp = temp/2; - hw_baud_table[i].dl_high = (temp >> 8)& 0xFF; + temp = temp / 2; + hw_baud_table[i].dl_high = (temp >> 8) & 0xFF; hw_baud_table[i].dl_low = (temp) & 0xFF; } } @@ -74,6 +76,7 @@ void calc_baud(void) void serial_setbrg(void) { int i; + DECLARE_GLOBAL_DATA_PTR; calc_baud(); @@ -84,29 +87,29 @@ void serial_setbrg(void) /* Enable UART */ *pUART_GCTL |= UART_GCTL_UCEN; - asm("ssync;"); + sync(); /* Set DLAB in LCR to Access DLL and DLH */ ACCESS_LATCH; - asm("ssync;"); + sync(); *pUART_DLL = hw_baud_table[i].dl_low; - asm("ssync;"); + sync(); *pUART_DLH = hw_baud_table[i].dl_high; - asm("ssync;"); + sync(); /* Clear DLAB in LCR to Access THR RBR IER */ ACCESS_PORT_IER; - asm("ssync;"); + sync(); /* Enable ERBFI and ELSI interrupts - * to poll SIC_ISR register*/ + * to poll SIC_ISR register*/ *pUART_IER = UART_IER_ELSI | UART_IER_ERBFI | UART_IER_ETBEI; - asm("ssync;"); + sync(); /* Set LCR to Word Lengh 8-bit word select */ *pUART_LCR = UART_LCR_WLS8; - asm("ssync;"); + sync(); return; } @@ -119,8 +122,7 @@ int serial_init(void) void serial_putc(const char c) { - if ((*pUART_LSR) & UART_LSR_TEMT) - { + if ((*pUART_LSR) & UART_LSR_TEMT) { if (c == '\n') serial_putc('\r'); @@ -148,17 +150,16 @@ int serial_getc(void) int ret; /* Poll for RX Interrupt */ - while (!((isr_val = *(volatile unsigned long *)SIC_ISR) & IRQ_UART_RX_BIT)); + while (!((isr_val = + *(volatile unsigned long *)SIC_ISR) & IRQ_UART_RX_BIT)) ; asm("csync;"); uart_lsr_val = *pUART_LSR; /* Clear status bit */ uart_rbr_val = *pUART_RBR; /* getc() */ if (isr_val & IRQ_UART_ERROR_BIT) { - ret = -1; - } - else - { + ret = -1; + } else { ret = uart_rbr_val & 0xff; } @@ -180,10 +181,10 @@ static void local_put_char(char ch) save_and_cli(flags); /* Poll for TX Interruput */ - while (!((isr_val = *pSIC_ISR) & IRQ_UART_TX_BIT)); + while (!((isr_val = *pSIC_ISR) & IRQ_UART_TX_BIT)) ; asm("csync;"); - *pUART_THR = ch; /* putc() */ + *pUART_THR = ch; /* putc() */ if (isr_val & IRQ_UART_ERROR_BIT) { printf("?"); @@ -191,5 +192,5 @@ static void local_put_char(char ch) restore_flags(flags); - return ; + return; } diff --git a/cpu/bf533/start.S b/cpu/bf533/start.S index 6d58575..94556d6 100644 --- a/cpu/bf533/start.S +++ b/cpu/bf533/start.S @@ -1,5 +1,5 @@ /* - * U-boot - start.S Startup file of u-boot for BF533 + * U-boot - start.S Startup file of u-boot for BF533/BF561 * * Copyright (c) 2005 blackfin.uclinux.org * @@ -38,9 +38,23 @@ #define ASSEMBLY #include <linux/config.h> -#include <asm/blackfin.h> #include <config.h> -#include <asm/mem_init.h> +#include <asm/blackfin.h> + +.global _stext; +.global __bss_start; +.global start; +.global _start; +.global _rambase; +.global _ramstart; +.global _ramend; +.global _bf533_data_dest; +.global _bf533_data_size; +.global edata; +.global _initialize; +.global _exit; +.global flashdataend; +.global init_sdram; #if (CONFIG_CCLK_DIV == 1) #define CONFIG_CCLK_ACT_DIV CCLK_DIV1 @@ -58,26 +72,12 @@ #define CONFIG_CCLK_ACT_DIV CONFIG_CCLK_DIV_not_defined_properly #endif -.global _stext; -.global __bss_start; -.global start; -.global _start; -.global _rambase; -.global _ramstart; -.global _ramend; -.global _bf533_data_dest; -.global _bf533_data_size; -.global edata; -.global _initialize; -.global _exit; -.global flashdataend; - .text _start: start: _stext: - R0 = 0x30; + R0 = 0x32; SYSCFG = R0; SSYNC; @@ -120,8 +120,9 @@ _stext: /* Set loop counters to zero, to make sure that * hw loops are disabled. */ - lc0 = 0; - lc1 = 0; + r0 = 0; + lc0 = r0; + lc1 = r0; SSYNC; @@ -150,105 +151,40 @@ no_soft_reset: LSETUP(4,4) lc0 = p1; [ p0 ++ ] = r1; - /* - * Set PLL_CTL - * - [14:09] = MSEL[5:0] : CLKIN / VCO multiplication factors - * - [8] = BYPASS : BYPASS the PLL, run CLKIN into CCLK/SCLK - * - [7] = output delay (add 200ps of delay to mem signals) - * - [6] = input delay (add 200ps of input delay to mem signals) - * - [5] = PDWN : 1=All Clocks off - * - [3] = STOPCK : 1=Core Clock off - * - [1] = PLL_OFF : 1=Disable Power to PLL - * - [0] = DF : 1=Pass CLKIN/2 to PLL / 0=Pass CLKIN to PLL - * all other bits set to zero - */ - - r0 = CONFIG_VCO_MULT; /* Load the VCO multiplier */ - r0 = r0 << 9; /* Shift it over */ - r1 = CONFIG_CLKIN_HALF; /* Do we need to divide CLKIN by 2? */ - r0 = r1 | r0; - r1 = CONFIG_PLL_BYPASS; /* Bypass the PLL? */ - r1 = r1 << 8; /* Shift it over */ - r0 = r1 | r0; /* add them all together */ - - p0.h = (PLL_CTL >> 16); - p0.l = (PLL_CTL & 0xFFFF); /* Load the address */ - cli r2; /* Disable interrupts */ - w[p0] = r0; /* Set the value */ - idle; /* Wait for the PLL to stablize */ - sti r2; /* Enable interrupts */ - ssync; - - /* - * Turn on the CYCLES COUNTER - */ - r2 = SYSCFG; - BITSET (r2,1); - SYSCFG = r2; - - /* Configure SCLK & CCLK Dividers */ - r0 = CONFIG_CCLK_ACT_DIV | CONFIG_SCLK_DIV; - p0.h = (PLL_DIV >> 16); - p0.l = (PLL_DIV & 0xFFFF); - w[p0] = r0; - ssync; - -wait_for_pll_stab: - p0.h = (PLL_STAT >> 16); - p0.l = (PLL_STAT & 0xFFFF); - r0.l = w[p0]; - cc = bittst(r0,5); - if !cc jump wait_for_pll_stab; - - /* Configure SDRAM if SDRAM is already not enabled */ - p0.l = (EBIU_SDSTAT & 0xFFFF); - p0.h = (EBIU_SDSTAT >> 16); - r0.l = w[p0]; - cc = bittst(r0, 3); - if !cc jump skip_sdram_enable; - - /* SDRAM initialization */ - p0.l = (EBIU_SDGCTL & 0xFFFF); - p0.h = (EBIU_SDGCTL >> 16); /* SDRAM Memory Global Control Register */ - r0.h = (mem_SDGCTL >> 16); - r0.l = (mem_SDGCTL & 0xFFFF); - [p0] = r0; - ssync; - - p0.l = (EBIU_SDBCTL & 0xFFFF); - p0.h = (EBIU_SDBCTL >> 16); /* SDRAM Memory Bank Control Register */ - r0 = mem_SDBCTL; + p0.h = hi(SIC_IWR); + p0.l = lo(SIC_IWR); + r0.l = 0x1; w[p0] = r0.l; - ssync; + SSYNC; - p0.l = (EBIU_SDRRC & 0xFFFF); - p0.h = (EBIU_SDRRC >> 16); /* SDRAM Refresh Rate Control Register */ - r0 = mem_SDRRC; - w[p0] = r0.l; - ssync; + sp.l = (0xffb01000 & 0xFFFF); + sp.h = (0xffb01000 >> 16); -skip_sdram_enable: - nop; + call init_sdram; -#ifndef CFG_NO_FLASH /* relocate into to RAM */ - p1.l = (CFG_FLASH_BASE & 0xffff); - p1.h = (CFG_FLASH_BASE >> 16); + call get_pc; +offset: + r2.l = offset; + r2.h = offset; + r3.l = start; + r3.h = start; + r1 = r2 - r3; + + r0 = r0 - r1; + p1 = r0; + p2.l = (CFG_MONITOR_BASE & 0xffff); p2.h = (CFG_MONITOR_BASE >> 16); - r0.l = (CFG_MONITOR_LEN & 0xffff); - r0.h = (CFG_MONITOR_LEN >> 16); + + p3 = 0x04; + p4.l = ((CFG_MONITOR_BASE + CFG_MONITOR_LEN) & 0xffff); + p4.h = ((CFG_MONITOR_BASE + CFG_MONITOR_LEN) >> 16); loop1: - r1 = [p1]; - [p2] = r1; - p3=0x4; - p1=p1+p3; - p2=p2+p3; - r2=0x4; - r0=r0-r2; - cc=r0==0x0; + r1 = [p1 ++ p3]; + [p2 ++ p3] = r1; + cc=p2==p4; if !cc jump loop1; -#endif /* * configure STACK */ @@ -273,7 +209,8 @@ loop1: p0.l = (IMASK & 0xFFFF); p0.h = (IMASK >> 16); - r0 = IVG15_POS; + r0.l = LO(IVG15_POS); + r0.h = HI(IVG15_POS); [p0] = r0; raise 15; p0.l = WAIT_HERE; @@ -288,37 +225,10 @@ WAIT_HERE: _real_start: [ -- sp ] = reti; -#ifdef CONFIG_EZKIT533 - p0.l = (WDOG_CTL & 0xFFFF); - p0.h = (WDOG_CTL >> 16); - r0 = WATCHDOG_DISABLE(z); - w[p0] = r0; -#endif - - /* Code for initializing Async mem banks */ - p2.h = (EBIU_AMBCTL1 >> 16); - p2.l = (EBIU_AMBCTL1 & 0xFFFF); - r0.h = (AMBCTL1VAL >> 16); - r0.l = (AMBCTL1VAL & 0xFFFF); - [p2] = r0; - ssync; - - p2.h = (EBIU_AMBCTL0 >> 16); - p2.l = (EBIU_AMBCTL0 & 0xFFFF); - r0.h = (AMBCTL0VAL >> 16); - r0.l = (AMBCTL0VAL & 0xFFFF); - [p2] = r0; - ssync; - - p2.h = (EBIU_AMGCTL >> 16); - p2.l = (EBIU_AMGCTL & 0xffff); - r0 = AMGCTLVAL; - w[p2] = r0; - ssync; - /* DMA reset code to Hi of L1 SRAM */ copy: - P1.H = hi(SYSMMR_BASE); /* P1 Points to the beginning of SYSTEM MMR Space */ + /* P1 Points to the beginning of SYSTEM MMR Space */ + P1.H = hi(SYSMMR_BASE); P1.L = lo(SYSMMR_BASE); R0.H = reset_start; /* Source Address (high) */ @@ -329,7 +239,8 @@ copy: R1.H = hi(L1_ISRAM); /* Destination Address (high) */ R1.L = lo(L1_ISRAM); /* Destination Address (low) */ R3.L = DMAEN; /* Source DMAConfig Value (8-bit words) */ - R4.L = (DI_EN | WNR | DMAEN); /* Destination DMAConfig Value (8-bit words) */ + /* Destination DMAConfig Value (8-bit words) */ + R4.L = (DI_EN | WNR | DMAEN); DMA: R6 = 0x1 (Z); @@ -342,57 +253,24 @@ DMA: Memory Read, 8-Bit Transfers, 1-D DMA, Flow - Stop */ W[P1+OFFSET_(MDMA_S0_CONFIG)] = R3; - [P1+OFFSET_(MDMA_D0_START_ADDR)] = R1; /* Set Destination Base Address */ - W[P1+OFFSET_(MDMA_D0_X_COUNT)] = R2; /* Set Destination Count */ - /* Set Destination DMAConfig = DMA Enable, - Memory Write, 8-Bit Transfers, 1-D DMA, Flow - Stop, IOC */ - W[P1+OFFSET_(MDMA_D0_CONFIG)] = R4; - - IDLE; /* Wait for DMA to Complete */ - - R0 = 0x1; - W[P1+OFFSET_(MDMA_D0_IRQ_STATUS)] = R0; /* Write 1 to clear DMA interrupt */ - - /* DMA reset code to DATA BANK A which uses this port - * to avoid following problem - * " Data from a Data Cache fill can be corrupoted after or during - * instruction DMA if certain core stalls exist" - */ - -copy_as_data: - R0.H = reset_start; /* Source Address (high) */ - R0.L = reset_start; /* Source Address (low) */ - R1.H = reset_end; - R1.L = reset_end; - R2 = R1 - R0; /* Count */ - R1.H = hi(DATA_BANKA_SRAM); /* Destination Address (high) */ - R1.L = lo(DATA_BANKA_SRAM); /* Destination Address (low) */ - R3.L = DMAEN; /* Source DMAConfig Value (8-bit words) */ - R4.L = (DI_EN | WNR | DMAEN); /* Destination DMAConfig Value (8-bit words) */ - -DMA_DATA: - R6 = 0x1 (Z); - W[P1+OFFSET_(MDMA_S0_X_MODIFY)] = R6; /* Source Modify = 1 */ - W[P1+OFFSET_(MDMA_D0_X_MODIFY)] = R6; /* Destination Modify = 1 */ - - [P1+OFFSET_(MDMA_S0_START_ADDR)] = R0; /* Set Source Base Address */ - W[P1+OFFSET_(MDMA_S0_X_COUNT)] = R2; /* Set Source Count */ - /* Set Source DMAConfig = DMA Enable, - Memory Read, 8-Bit Transfers, 1-D DMA, Flow - Stop */ - W[P1+OFFSET_(MDMA_S0_CONFIG)] = R3; - - [P1+OFFSET_(MDMA_D0_START_ADDR)] = R1; /* Set Destination Base Address */ + /* Set Destination Base Address */ + [P1+OFFSET_(MDMA_D0_START_ADDR)] = R1; W[P1+OFFSET_(MDMA_D0_X_COUNT)] = R2; /* Set Destination Count */ /* Set Destination DMAConfig = DMA Enable, Memory Write, 8-Bit Transfers, 1-D DMA, Flow - Stop, IOC */ W[P1+OFFSET_(MDMA_D0_CONFIG)] = R4; - IDLE; /* Wait for DMA to Complete */ +WAIT_DMA_DONE: + p0.h = hi(MDMA_D0_IRQ_STATUS); + p0.l = lo(MDMA_D0_IRQ_STATUS); + R0 = W[P0](Z); + CC = BITTST(R0, 0); + if ! CC jump WAIT_DMA_DONE R0 = 0x1; - W[P1+OFFSET_(MDMA_D0_IRQ_STATUS)] = R0; /* Write 1 to clear DMA interrupt */ -copy_end: nop; + /* Write 1 to clear DMA interrupt */ + W[P1+OFFSET_(MDMA_D0_IRQ_STATUS)] = R0; /* Initialize BSS Section with 0 s */ p1.l = __bss_start; @@ -433,3 +311,6 @@ reset_end: nop; _exit: jump.s _exit; +get_pc: + r0 = rets; + rts; diff --git a/cpu/bf533/start1.S b/cpu/bf533/start1.S index 6f48124..72cfafb 100644 --- a/cpu/bf533/start1.S +++ b/cpu/bf533/start1.S @@ -24,8 +24,8 @@ #define ASSEMBLY #include <linux/config.h> -#include <asm/blackfin.h> #include <config.h> +#include <asm/blackfin.h> .global start1; .global _start1; @@ -34,5 +34,5 @@ _start1: start1: sp += -12; - call board_init_f; + call _board_init_f; sp += 12; diff --git a/cpu/bf533/traps.c b/cpu/bf533/traps.c index 37470d5..248e34f 100644 --- a/cpu/bf533/traps.c +++ b/cpu/bf533/traps.c @@ -42,6 +42,9 @@ #include <asm/page.h> #include <asm/machdep.h> #include "cpu.h" +#include <asm/arch/anomaly.h> +#include <asm/cplb.h> +#include <asm/io.h> void init_IRQ(void) { @@ -51,23 +54,187 @@ void init_IRQ(void) void process_int(unsigned long vec, struct pt_regs *fp) { + printf("interrupt\n"); return; } +extern unsigned int icplb_table[page_descriptor_table_size][2]; +extern unsigned int dcplb_table[page_descriptor_table_size][2]; + +unsigned long last_cplb_fault_retx; + +static unsigned int cplb_sizes[4] = + { 1024, 4 * 1024, 1024 * 1024, 4 * 1024 * 1024 }; + +void trap_c(struct pt_regs *regs) +{ + unsigned int addr; + unsigned long trapnr = (regs->seqstat) & SEQSTAT_EXCAUSE; + unsigned int i, j, size, *I0, *I1; + unsigned short data = 0; + + switch (trapnr) { + /* 0x26 - Data CPLB Miss */ + case VEC_CPLB_M: + +#ifdef ANOMALY_05000261 + /* + * Work around an anomaly: if we see a new DCPLB fault, + * return without doing anything. Then, + * if we get the same fault again, handle it. + */ + addr = last_cplb_fault_retx; + last_cplb_fault_retx = regs->retx; + printf("this time, curr = 0x%08x last = 0x%08x\n", + addr, last_cplb_fault_retx); + if (addr != last_cplb_fault_retx) + goto trap_c_return; +#endif + data = 1; + + case VEC_CPLB_I_M: + + if (data) { + addr = *(unsigned int *)pDCPLB_FAULT_ADDR; + } else { + addr = *(unsigned int *)pICPLB_FAULT_ADDR; + } + for (i = 0; i < page_descriptor_table_size; i++) { + if (data) { + size = cplb_sizes[dcplb_table[i][1] >> 16]; + j = dcplb_table[i][0]; + } else { + size = cplb_sizes[icplb_table[i][1] >> 16]; + j = icplb_table[i][0]; + } + if ((j <= addr) && ((j + size) > addr)) { + debug("found %i 0x%08x\n", i, j); + break; + } + } + if (i == page_descriptor_table_size) { + printf("something is really wrong\n"); + do_reset(NULL, 0, 0, NULL); + } + + /* Turn the cache off */ + if (data) { + sync(); + asm(" .align 8; "); + *(unsigned int *)DMEM_CONTROL &= + ~(ACACHE_BCACHE | ENDCPLB | PORT_PREF0); + sync(); + } else { + sync(); + asm(" .align 8; "); + *(unsigned int *)IMEM_CONTROL &= ~(IMC | ENICPLB); + sync(); + } + + if (data) { + I0 = (unsigned int *)DCPLB_ADDR0; + I1 = (unsigned int *)DCPLB_DATA0; + } else { + I0 = (unsigned int *)ICPLB_ADDR0; + I1 = (unsigned int *)ICPLB_DATA0; + } + + j = 0; + while (*I1 & CPLB_LOCK) { + debug("skipping %i %08p - %08x\n", j, I1, *I1); + *I0++; + *I1++; + j++; + } + + debug("remove %i 0x%08x 0x%08x\n", j, *I0, *I1); + + for (; j < 15; j++) { + debug("replace %i 0x%08x 0x%08x\n", j, I0, I0 + 1); + *I0++ = *(I0 + 1); + *I1++ = *(I1 + 1); + } + + if (data) { + *I0 = dcplb_table[i][0]; + *I1 = dcplb_table[i][1]; + I0 = (unsigned int *)DCPLB_ADDR0; + I1 = (unsigned int *)DCPLB_DATA0; + } else { + *I0 = icplb_table[i][0]; + *I1 = icplb_table[i][1]; + I0 = (unsigned int *)ICPLB_ADDR0; + I1 = (unsigned int *)ICPLB_DATA0; + } + + for (j = 0; j < 16; j++) { + debug("%i 0x%08x 0x%08x\n", j, *I0++, *I1++); + } + + /* Turn the cache back on */ + if (data) { + j = *(unsigned int *)DMEM_CONTROL; + sync(); + asm(" .align 8; "); + *(unsigned int *)DMEM_CONTROL = + ACACHE_BCACHE | ENDCPLB | PORT_PREF0 | j; + sync(); + } else { + sync(); + asm(" .align 8; "); + *(unsigned int *)IMEM_CONTROL = IMC | ENICPLB; + sync(); + } + + break; + default: + /* All traps come here */ + printf("code=[0x%x], ", (unsigned int)(regs->seqstat & 0x3f)); + printf("stack frame=0x%x, ", (unsigned int)regs); + printf("bad PC=0x%04x\n", (unsigned int)regs->pc); + dump(regs); + printf("\n\n"); + + printf("Unhandled IRQ or exceptions!\n"); + printf("Please reset the board \n"); + do_reset(NULL, 0, 0, NULL); + } + + return; + +} + void dump(struct pt_regs *fp) { - printf("PC: %08lx\n", fp->pc); - printf("SEQSTAT: %08lx SP: %08lx\n", (long) fp->seqstat, - (long) fp); - printf("R0: %08lx R1: %08lx R2: %08lx R3: %08lx\n", - fp->r0, fp->r1, fp->r2, fp->r3); - printf("R4: %08lx R5: %08lx R6: %08lx R7: %08lx\n", - fp->r4, fp->r5, fp->r6, fp->r7); - printf("P0: %08lx P1: %08lx P2: %08lx P3: %08lx\n", - fp->p0, fp->p1, fp->p2, fp->p3); - printf("P4: %08lx P5: %08lx FP: %08lx\n", fp->p4, fp->p5, - fp->fp); - printf("A0.w: %08lx A0.x: %08lx A1.w: %08lx A1.x: %08lx\n", - fp->a0w, fp->a0x, fp->a1w, fp->a1x); - printf("\n"); + debug("RETE: %08lx RETN: %08lx RETX: %08lx RETS: %08lx\n", + fp->rete, fp->retn, fp->retx, fp->rets); + debug("IPEND: %04lx SYSCFG: %04lx\n", fp->ipend, fp->syscfg); + debug("SEQSTAT: %08lx SP: %08lx\n", (long)fp->seqstat, (long)fp); + debug("R0: %08lx R1: %08lx R2: %08lx R3: %08lx\n", + fp->r0, fp->r1, fp->r2, fp->r3); + debug("R4: %08lx R5: %08lx R6: %08lx R7: %08lx\n", + fp->r4, fp->r5, fp->r6, fp->r7); + debug("P0: %08lx P1: %08lx P2: %08lx P3: %08lx\n", + fp->p0, fp->p1, fp->p2, fp->p3); + debug("P4: %08lx P5: %08lx FP: %08lx\n", + fp->p4, fp->p5, fp->fp); + debug("A0.w: %08lx A0.x: %08lx A1.w: %08lx A1.x: %08lx\n", + fp->a0w, fp->a0x, fp->a1w, fp->a1x); + + debug("LB0: %08lx LT0: %08lx LC0: %08lx\n", + fp->lb0, fp->lt0, fp->lc0); + debug("LB1: %08lx LT1: %08lx LC1: %08lx\n", + fp->lb1, fp->lt1, fp->lc1); + debug("B0: %08lx L0: %08lx M0: %08lx I0: %08lx\n", + fp->b0, fp->l0, fp->m0, fp->i0); + debug("B1: %08lx L1: %08lx M1: %08lx I1: %08lx\n", + fp->b1, fp->l1, fp->m1, fp->i1); + debug("B2: %08lx L2: %08lx M2: %08lx I2: %08lx\n", + fp->b2, fp->l2, fp->m2, fp->i2); + debug("B3: %08lx L3: %08lx M3: %08lx I3: %08lx\n", + fp->b3, fp->l3, fp->m3, fp->i3); + + debug("DCPLB_FAULT_ADDR=%p\n", *pDCPLB_FAULT_ADDR); + debug("ICPLB_FAULT_ADDR=%p\n", *pICPLB_FAULT_ADDR); + } diff --git a/cpu/bf533/video.c b/cpu/bf533/video.c new file mode 100644 index 0000000..3ff0151 --- /dev/null +++ b/cpu/bf533/video.c @@ -0,0 +1,194 @@ +/* + * (C) Copyright 2000 + * Paolo Scaffardi, AIRVENT SAM s.p.a - RIMINI(ITALY), arsenio@tin.it + * (C) Copyright 2002 + * Wolfgang Denk, wd@denx.de + * (C) Copyright 2006 + * Aubrey Li, aubrey.li@analog.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <stdarg.h> +#include <common.h> +#include <config.h> +#include <asm/blackfin.h> +#include <i2c.h> +#include <linux/types.h> +#include <devices.h> + +#ifdef CONFIG_VIDEO +#define NTSC_FRAME_ADDR 0x06000000 +#include "video.h" + +/* NTSC OUTPUT SIZE 720 * 240 */ +#define VERTICAL 2 +#define HORIZONTAL 4 + +int is_vblank_line(const int line) +{ + /* + * This array contains a single bit for each line in + * an NTSC frame. + */ + if ((line <= 18) || (line >= 264 && line <= 281) || (line == 528)) + return true; + + return false; +} + +int NTSC_framebuffer_init(char *base_address) +{ + const int NTSC_frames = 1; + const int NTSC_lines = 525; + char *dest = base_address; + int frame_num, line_num; + + for (frame_num = 0; frame_num < NTSC_frames; ++frame_num) { + for (line_num = 1; line_num <= NTSC_lines; ++line_num) { + unsigned int code; + int offset = 0; + int i; + + if (is_vblank_line(line_num)) + offset++; + + if (line_num > 266 || line_num < 3) + offset += 2; + + /* Output EAV code */ + code = SystemCodeMap[offset].EAV; + write_dest_byte((char)(code >> 24) & 0xff); + write_dest_byte((char)(code >> 16) & 0xff); + write_dest_byte((char)(code >> 8) & 0xff); + write_dest_byte((char)(code) & 0xff); + + /* Output horizontal blanking */ + for (i = 0; i < 67 * 2; ++i) { + write_dest_byte(0x80); + write_dest_byte(0x10); + } + + /* Output SAV */ + code = SystemCodeMap[offset].SAV; + write_dest_byte((char)(code >> 24) & 0xff); + write_dest_byte((char)(code >> 16) & 0xff); + write_dest_byte((char)(code >> 8) & 0xff); + write_dest_byte((char)(code) & 0xff); + + /* Output empty horizontal data */ + for (i = 0; i < 360 * 2; ++i) { + write_dest_byte(0x80); + write_dest_byte(0x10); + } + } + } + + return dest - base_address; +} + +void fill_frame(char *Frame, int Value) +{ + int *OddPtr32; + int OddLine; + int *EvenPtr32; + int EvenLine; + int i; + int *data; + int m, n; + + /* fill odd and even frames */ + for (OddLine = 22, EvenLine = 285; OddLine < 263; OddLine++, EvenLine++) { + OddPtr32 = (int *)((Frame + (OddLine * 1716)) + 276); + EvenPtr32 = (int *)((Frame + (EvenLine * 1716)) + 276); + for (i = 0; i < 360; i++, OddPtr32++, EvenPtr32++) { + *OddPtr32 = Value; + *EvenPtr32 = Value; + } + } + + for (m = 0; m < VERTICAL; m++) { + data = (int *)u_boot_logo.data; + for (OddLine = (22 + m), EvenLine = (285 + m); + OddLine < (u_boot_logo.height * VERTICAL) + (22 + m); + OddLine += VERTICAL, EvenLine += VERTICAL) { + OddPtr32 = (int *)((Frame + ((OddLine) * 1716)) + 276); + EvenPtr32 = + (int *)((Frame + ((EvenLine) * 1716)) + 276); + for (i = 0; i < u_boot_logo.width / 2; i++) { + /* enlarge one pixel to m x n */ + for (n = 0; n < HORIZONTAL; n++) { + *OddPtr32++ = *data; + *EvenPtr32++ = *data; + } + data++; + } + } + } +} + +void video_putc(const char c) +{ +} + +void video_puts(const char *s) +{ +} + +static int video_init(void) +{ + char *NTSCFrame; + NTSCFrame = (char *)NTSC_FRAME_ADDR; + NTSC_framebuffer_init(NTSCFrame); + fill_frame(NTSCFrame, BLUE); + + *pPPI_CONTROL = 0x0082; + *pPPI_FRAME = 0x020D; + + *pDMA0_START_ADDR = NTSCFrame; + *pDMA0_X_COUNT = 0x035A; + *pDMA0_X_MODIFY = 0x0002; + *pDMA0_Y_COUNT = 0x020D; + *pDMA0_Y_MODIFY = 0x0002; + *pDMA0_CONFIG = 0x1015; + *pPPI_CONTROL = 0x0083; + return 0; +} + +int drv_video_init(void) +{ + int error, devices = 1; + + device_t videodev; + + video_init(); /* Video initialization */ + + memset(&videodev, 0, sizeof(videodev)); + + strcpy(videodev.name, "video"); + videodev.ext = DEV_EXT_VIDEO; /* Video extensions */ + videodev.flags = DEV_FLAGS_OUTPUT; /* Output only */ + videodev.putc = video_putc; /* 'putc' function */ + videodev.puts = video_puts; /* 'puts' function */ + + error = device_register(&videodev); + + return (error == 0) ? devices : error; +} +#endif diff --git a/cpu/bf533/video.h b/cpu/bf533/video.h new file mode 100644 index 0000000..d237f6a --- /dev/null +++ b/cpu/bf533/video.h @@ -0,0 +1,25 @@ +#include <video_logo.h> +#define write_dest_byte(val) {*dest++=val;} +#define BLACK (0x01800180) /* black pixel pattern */ +#define BLUE (0x296E29F0) /* blue pixel pattern */ +#define RED (0x51F0515A) /* red pixel pattern */ +#define MAGENTA (0x6ADE6ACA) /* magenta pixel pattern */ +#define GREEN (0x91229136) /* green pixel pattern */ +#define CYAN (0xAA10AAA6) /* cyan pixel pattern */ +#define YELLOW (0xD292D210) /* yellow pixel pattern */ +#define WHITE (0xFE80FE80) /* white pixel pattern */ + +#define true 1 +#define false 0 + +typedef struct { + unsigned int SAV; + unsigned int EAV; +} SystemCodeType; + +const SystemCodeType SystemCodeMap[4] = { + {0xFF000080, 0xFF00009D}, + {0xFF0000AB, 0xFF0000B6}, + {0xFF0000C7, 0xFF0000DA}, + {0xFF0000EC, 0xFF0000F1} +}; diff --git a/cpu/bf537/Makefile b/cpu/bf537/Makefile new file mode 100644 index 0000000..61c7338 --- /dev/null +++ b/cpu/bf537/Makefile @@ -0,0 +1,52 @@ +# U-boot - Makefile +# +# Copyright (c) 2005 blackfin.uclinux.org +# +# (C) Copyright 2000-2004 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +include $(TOPDIR)/config.mk + +LIB = $(obj)lib$(CPU).a + +START = start.o start1.o interrupt.o cache.o flush.o init_sdram.o +COBJS = cpu.o traps.o ints.o serial.o interrupts.o video.o i2c.o + +EXTRA = init_sdram_bootrom_initblock.o + +SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS) $(SOBJS)) +START := $(addprefix $(obj),$(START)) + +all: $(obj).depend $(START) $(LIB) $(obj).depend $(EXTRA) + +$(LIB): $(OBJS) + $(AR) $(ARFLAGS) $@ $(OBJS) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/cpu/bf537/cache.S b/cpu/bf537/cache.S new file mode 100644 index 0000000..5bda5bf --- /dev/null +++ b/cpu/bf537/cache.S @@ -0,0 +1,128 @@ +#define ASSEMBLY +#include <asm/linkage.h> +#include <config.h> +#include <asm/blackfin.h> + +.text +.align 2 +ENTRY(_blackfin_icache_flush_range) + R2 = -32; + R2 = R0 & R2; + P0 = R2; + P1 = R1; + CSYNC; + 1: + IFLUSH[P0++]; + CC = P0 < P1(iu); + IF CC JUMP 1b(bp); + IFLUSH[P0]; + SSYNC; + RTS; + +ENTRY(_blackfin_dcache_flush_range) + R2 = -32; + R2 = R0 & R2; + P0 = R2; + P1 = R1; + CSYNC; +1: + FLUSH[P0++]; + CC = P0 < P1(iu); + IF CC JUMP 1b(bp); + FLUSH[P0]; + SSYNC; + RTS; + +ENTRY(_icache_invalidate) +ENTRY(_invalidate_entire_icache) + [--SP] = (R7:5); + + P0.L = (IMEM_CONTROL & 0xFFFF); + P0.H = (IMEM_CONTROL >> 16); + R7 =[P0]; + + /* + * Clear the IMC bit , All valid bits in the instruction + * cache are set to the invalid state + */ + BITCLR(R7, IMC_P); + CLI R6; + /* SSYNC required before invalidating cache. */ + SSYNC; + .align 8; + [P0] = R7; + SSYNC; + STI R6; + + /* Configures the instruction cache agian */ + R6 = (IMC | ENICPLB); + R7 = R7 | R6; + + CLI R6; + SSYNC; + .align 8; + [P0] = R7; + SSYNC; + STI R6; + + (R7:5) =[SP++]; + RTS; + +/* + * Invalidate the Entire Data cache by + * clearing DMC[1:0] bits + */ +ENTRY(_invalidate_entire_dcache) +ENTRY(_dcache_invalidate) + [--SP] = (R7:6); + + P0.L = (DMEM_CONTROL & 0xFFFF); + P0.H = (DMEM_CONTROL >> 16); + R7 =[P0]; + + /* + * Clear the DMC[1:0] bits, All valid bits in the data + * cache are set to the invalid state + */ + BITCLR(R7, DMC0_P); + BITCLR(R7, DMC1_P); + CLI R6; + SSYNC; + .align 8; + [P0] = R7; + SSYNC; + STI R6; + /* Configures the data cache again */ + + R6 = (ACACHE_BCACHE | ENDCPLB | PORT_PREF0); + R7 = R7 | R6; + + CLI R6; + SSYNC; + .align 8; + [P0] = R7; + SSYNC; + STI R6; + + (R7:6) =[SP++]; + RTS; + +ENTRY(_blackfin_dcache_invalidate_range) + R2 = -32; + R2 = R0 & R2; + P0 = R2; + P1 = R1; + CSYNC; +1: + FLUSHINV[P0++]; + CC = P0 < P1(iu); + IF CC JUMP 1b(bp); + + /* + * If the data crosses a cache line, then we'll be pointing to + * the last cache line, but won't have flushed/invalidated it yet, so do + * one more. + */ + FLUSHINV[P0]; + SSYNC; + RTS; diff --git a/cpu/bf537/config.mk b/cpu/bf537/config.mk new file mode 100644 index 0000000..4d57d9c --- /dev/null +++ b/cpu/bf537/config.mk @@ -0,0 +1,27 @@ +# U-boot - config.mk +# +# Copyright (c) 2005 blackfin.uclinux.org +# +# (C) Copyright 2000-2004 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +PLATFORM_RELFLAGS += -mcpu=bf537 -ffixed-P5 diff --git a/cpu/bf537/cpu.c b/cpu/bf537/cpu.c new file mode 100644 index 0000000..cb8dc3c --- /dev/null +++ b/cpu/bf537/cpu.c @@ -0,0 +1,227 @@ +/* + * U-boot - cpu.c CPU specific functions + * + * Copyright (c) 2005 blackfin.uclinux.org + * + * (C) Copyright 2000-2004 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <asm/blackfin.h> +#include <command.h> +#include <asm/entry.h> +#include <asm/cplb.h> +#include <asm/io.h> + +#define CACHE_ON 1 +#define CACHE_OFF 0 + +extern unsigned int icplb_table[page_descriptor_table_size][2]; +extern unsigned int dcplb_table[page_descriptor_table_size][2]; + +int do_reset(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) +{ + __asm__ __volatile__("cli r3;" "P0 = %0;" "JUMP (P0);"::"r"(L1_ISRAM) + ); + + return 0; +} + +/* These functions are just used to satisfy the linker */ +int cpu_init(void) +{ + return 0; +} + +int cleanup_before_linux(void) +{ + return 0; +} + +void icache_enable(void) +{ + unsigned int *I0, *I1; + int i, j = 0; + + if ((*pCHIPID >> 28) < 2) + return; + + /* Before enable icache, disable it first */ + icache_disable(); + I0 = (unsigned int *)ICPLB_ADDR0; + I1 = (unsigned int *)ICPLB_DATA0; + + /* make sure the locked ones go in first */ + for (i = 0; i < page_descriptor_table_size; i++) { + if (CPLB_LOCK & icplb_table[i][1]) { + debug("adding %02i %02i 0x%08x 0x%08x\n", i, j, + icplb_table[i][0], icplb_table[i][1]); + *I0++ = icplb_table[i][0]; + *I1++ = icplb_table[i][1]; + j++; + } + } + + for (i = 0; i < page_descriptor_table_size; i++) { + if (!(CPLB_LOCK & icplb_table[i][1])) { + debug("adding %02i %02i 0x%08x 0x%08x\n", i, j, + icplb_table[i][0], icplb_table[i][1]); + *I0++ = icplb_table[i][0]; + *I1++ = icplb_table[i][1]; + j++; + if (j == 16) { + break; + } + } + } + + /* Fill the rest with invalid entry */ + if (j <= 15) { + for (; j < 16; j++) { + debug("filling %i with 0", j); + *I1++ = 0x0; + } + + } + + cli(); + sync(); + asm(" .align 8; "); + *(unsigned int *)IMEM_CONTROL = IMC | ENICPLB; + sync(); + sti(); +} + +void icache_disable(void) +{ + if ((*pCHIPID >> 28) < 2) + return; + cli(); + sync(); + asm(" .align 8; "); + *(unsigned int *)IMEM_CONTROL &= ~(IMC | ENICPLB); + sync(); + sti(); +} + +int icache_status(void) +{ + unsigned int value; + value = *(unsigned int *)IMEM_CONTROL; + + if (value & (IMC | ENICPLB)) + return CACHE_ON; + else + return CACHE_OFF; +} + +void dcache_enable(void) +{ + unsigned int *I0, *I1; + unsigned int temp; + int i, j = 0; + + /* Before enable dcache, disable it first */ + dcache_disable(); + I0 = (unsigned int *)DCPLB_ADDR0; + I1 = (unsigned int *)DCPLB_DATA0; + + /* make sure the locked ones go in first */ + for (i = 0; i < page_descriptor_table_size; i++) { + if (CPLB_LOCK & dcplb_table[i][1]) { + debug("adding %02i %02i 0x%08x 0x%08x\n", i, j, + dcplb_table[i][0], dcplb_table[i][1]); + *I0++ = dcplb_table[i][0]; + *I1++ = dcplb_table[i][1]; + j++; + } else { + debug("skip %02i %02i 0x%08x 0x%08x\n", i, j, + dcplb_table[i][0], dcplb_table[i][1]); + } + } + + for (i = 0; i < page_descriptor_table_size; i++) { + if (!(CPLB_LOCK & dcplb_table[i][1])) { + debug("adding %02i %02i 0x%08x 0x%08x\n", i, j, + dcplb_table[i][0], dcplb_table[i][1]); + *I0++ = dcplb_table[i][0]; + *I1++ = dcplb_table[i][1]; + j++; + if (j == 16) { + break; + } + } + } + + /* Fill the rest with invalid entry */ + if (j <= 15) { + for (; j < 16; j++) { + debug("filling %i with 0", j); + *I1++ = 0x0; + } + } + + cli(); + temp = *(unsigned int *)DMEM_CONTROL; + sync(); + asm(" .align 8; "); + *(unsigned int *)DMEM_CONTROL = + ACACHE_BCACHE | ENDCPLB | PORT_PREF0 | temp; + sync(); + sti(); +} + +void dcache_disable(void) +{ + unsigned int *I0, *I1; + int i; + + cli(); + sync(); + asm(" .align 8; "); + *(unsigned int *)DMEM_CONTROL &= + ~(ACACHE_BCACHE | ENDCPLB | PORT_PREF0); + sync(); + sti(); + + /* after disable dcache, + * clear it so we don't confuse the next application + */ + I0 = (unsigned int *)DCPLB_ADDR0; + I1 = (unsigned int *)DCPLB_DATA0; + + for (i = 0; i < 16; i++) { + *I0++ = 0x0; + *I1++ = 0x0; + } +} + +int dcache_status(void) +{ + unsigned int value; + value = *(unsigned int *)DMEM_CONTROL; + + if (value & (ENDCPLB)) + return CACHE_ON; + else + return CACHE_OFF; +} diff --git a/cpu/bf537/cpu.h b/cpu/bf537/cpu.h new file mode 100644 index 0000000..821363e --- /dev/null +++ b/cpu/bf537/cpu.h @@ -0,0 +1,66 @@ +/* + * U-boot - cpu.h + * + * Copyright (c) 2005 blackfin.uclinux.org + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _CPU_H_ +#define _CPU_H_ + +#include <command.h> + +#define INTERNAL_IRQS (32) +#define NUM_IRQ_NODES 16 +#define DEF_INTERRUPT_FLAGS 1 +#define MAX_TIM_LOAD 0xFFFFFFFF + +void blackfin_irq_panic(int reason, struct pt_regs *reg); +extern void dump(struct pt_regs *regs); +void display_excp(void); +asmlinkage void evt_nmi(void); +asmlinkage void evt_exception(void); +asmlinkage void trap(void); +asmlinkage void evt_ivhw(void); +asmlinkage void evt_rst(void); +asmlinkage void evt_timer(void); +asmlinkage void evt_evt7(void); +asmlinkage void evt_evt8(void); +asmlinkage void evt_evt9(void); +asmlinkage void evt_evt10(void); +asmlinkage void evt_evt11(void); +asmlinkage void evt_evt12(void); +asmlinkage void evt_evt13(void); +asmlinkage void evt_soft_int1(void); +asmlinkage void evt_system_call(void); +void blackfin_irq_panic(int reason, struct pt_regs *regs); +void blackfin_free_irq(unsigned int irq, void *dev_id); +void call_isr(int irq, struct pt_regs *fp); +void blackfin_do_irq(int vec, struct pt_regs *fp); +void blackfin_init_IRQ(void); +void blackfin_enable_irq(unsigned int irq); +void blackfin_disable_irq(unsigned int irq); +extern int do_reset(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]); +int blackfin_request_irq(unsigned int irq, + void (*handler) (int, void *, struct pt_regs *), + unsigned long flags, const char *devname, + void *dev_id); +void timer_init(void); +#endif diff --git a/cpu/bf537/flush.S b/cpu/bf537/flush.S new file mode 100644 index 0000000..c260a8f --- /dev/null +++ b/cpu/bf537/flush.S @@ -0,0 +1,403 @@ +/* Copyright (C) 2003 Analog Devices, Inc. All Rights Reserved. + * Copyright (C) 2004 LG SOft India. All Rights Reserved. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. + */ +#define ASSEMBLY + +#include <asm/linkage.h> +#include <asm/cplb.h> +#include <config.h> +#include <asm/blackfin.h> + +.text + +/* This is an external function being called by the user + * application through __flush_cache_all. Currently this function + * serves the purpose of flushing all the pending writes in + * in the instruction cache. + */ + +ENTRY(_flush_instruction_cache) + [--SP] = ( R7:6, P5:4 ); + LINK 12; + SP += -12; + P5.H = (ICPLB_ADDR0 >> 16); + P5.L = (ICPLB_ADDR0 & 0xFFFF); + P4.H = (ICPLB_DATA0 >> 16); + P4.L = (ICPLB_DATA0 & 0xFFFF); + R7 = CPLB_VALID | CPLB_L1_CHBL; + R6 = 16; +inext: R0 = [P5++]; + R1 = [P4++]; + [--SP] = RETS; + CALL _icplb_flush; /* R0 = page, R1 = data*/ + RETS = [SP++]; +iskip: R6 += -1; + CC = R6; + IF CC JUMP inext; + SSYNC; + SP += 12; + UNLINK; + ( R7:6, P5:4 ) = [SP++]; + RTS; + +/* This is an internal function to flush all pending + * writes in the cache associated with a particular ICPLB. + * + * R0 - page's start address + * R1 - CPLB's data field. + */ + +.align 2 +ENTRY(_icplb_flush) + [--SP] = ( R7:0, P5:0 ); + [--SP] = LC0; + [--SP] = LT0; + [--SP] = LB0; + [--SP] = LC1; + [--SP] = LT1; + [--SP] = LB1; + + /* If it's a 1K or 4K page, then it's quickest to + * just systematically flush all the addresses in + * the page, regardless of whether they're in the + * cache, or dirty. If it's a 1M or 4M page, there + * are too many addresses, and we have to search the + * cache for lines corresponding to the page. + */ + + CC = BITTST(R1, 17); /* 1MB or 4MB */ + IF !CC JUMP iflush_whole_page; + + /* We're only interested in the page's size, so extract + * this from the CPLB (bits 17:16), and scale to give an + * offset into the page_size and page_prefix tables. + */ + + R1 <<= 14; + R1 >>= 30; + R1 <<= 2; + + /* We can also determine the sub-bank used, because this is + * taken from bits 13:12 of the address. + */ + + R3 = ((12<<8)|2); /* Extraction pattern */ + nop; /* Anamoly 05000209 */ + R4 = EXTRACT(R0, R3.L) (Z); /* Extract bits */ + + /* Save in extraction pattern for later deposit. */ + R3.H = R4.L << 0; + + /* So: + * R0 = Page start + * R1 = Page length (actually, offset into size/prefix tables) + * R3 = sub-bank deposit values + * + * The cache has 2 Ways, and 64 sets, so we iterate through + * the sets, accessing the tag for each Way, for our Bank and + * sub-bank, looking for dirty, valid tags that match our + * address prefix. + */ + + P5.L = (ITEST_COMMAND & 0xFFFF); + P5.H = (ITEST_COMMAND >> 16); + P4.L = (ITEST_DATA0 & 0xFFFF); + P4.H = (ITEST_DATA0 >> 16); + + P0.L = page_prefix_table; + P0.H = page_prefix_table; + P1 = R1; + R5 = 0; /* Set counter*/ + P0 = P1 + P0; + R4 = [P0]; /* This is the address prefix*/ + + /* We're reading (bit 1==0) the tag (bit 2==0), and we + * don't care about which double-word, since we're only + * fetching tags, so we only have to set Set, Bank, + * Sub-bank and Way. + */ + + P2 = 4; + LSETUP (ifs1, ife1) LC1 = P2; +ifs1: P0 = 32; /* iterate over all sets*/ + LSETUP (ifs0, ife0) LC0 = P0; +ifs0: R6 = R5 << 5; /* Combine set*/ + R6.H = R3.H << 0 ; /* and sub-bank*/ + [P5] = R6; /* Issue Command*/ + SSYNC; /* CSYNC will not work here :(*/ + R7 = [P4]; /* and read Tag.*/ + CC = BITTST(R7, 0); /* Check if valid*/ + IF !CC JUMP ifskip; /* and skip if not.*/ + + /* Compare against the page address. First, plant bits 13:12 + * into the tag, since those aren't part of the returned data. + */ + + R7 = DEPOSIT(R7, R3); /* set 13:12*/ + R1 = R7 & R4; /* Mask off lower bits*/ + CC = R1 == R0; /* Compare against page start.*/ + IF !CC JUMP ifskip; /* Skip it if it doesn't match.*/ + + /* Tag address matches against page, so this is an entry + * we must flush. + */ + + R7 >>= 10; /* Mask off the non-address bits*/ + R7 <<= 10; + P3 = R7; + IFLUSH [P3]; /* And flush the entry*/ +ifskip: +ife0: R5 += 1; /* Advance to next Set*/ +ife1: NOP; + +ifinished: + SSYNC; /* Ensure the data gets out to mem.*/ + + /*Finished. Restore context.*/ + LB1 = [SP++]; + LT1 = [SP++]; + LC1 = [SP++]; + LB0 = [SP++]; + LT0 = [SP++]; + LC0 = [SP++]; + ( R7:0, P5:0 ) = [SP++]; + RTS; + +iflush_whole_page: + /* It's a 1K or 4K page, so quicker to just flush the + * entire page. + */ + + P1 = 32; /* For 1K pages*/ + P2 = P1 << 2; /* For 4K pages*/ + P0 = R0; /* Start of page*/ + CC = BITTST(R1, 16); /* Whether 1K or 4K*/ + IF CC P1 = P2; + P1 += -1; /* Unroll one iteration*/ + SSYNC; + IFLUSH [P0++]; /* because CSYNC can't end loops.*/ + LSETUP (isall, ieall) LC0 = P1; +isall:IFLUSH [P0++]; +ieall: NOP; + SSYNC; + JUMP ifinished; + +/* This is an external function being called by the user + * application through __flush_cache_all. Currently this function + * serves the purpose of flushing all the pending writes in + * in the data cache. + */ + +ENTRY(_flush_data_cache) + [--SP] = ( R7:6, P5:4 ); + LINK 12; + SP += -12; + P5.H = (DCPLB_ADDR0 >> 16); + P5.L = (DCPLB_ADDR0 & 0xFFFF); + P4.H = (DCPLB_DATA0 >> 16); + P4.L = (DCPLB_DATA0 & 0xFFFF); + R7 = CPLB_VALID | CPLB_L1_CHBL | CPLB_DIRTY (Z); + R6 = 16; +next: R0 = [P5++]; + R1 = [P4++]; + CC = BITTST(R1, 14); /* Is it write-through?*/ + IF CC JUMP skip; /* If so, ignore it.*/ + R2 = R1 & R7; /* Is it a dirty, cached page?*/ + CC = R2; + IF !CC JUMP skip; /* If not, ignore it.*/ + [--SP] = RETS; + CALL _dcplb_flush; /* R0 = page, R1 = data*/ + RETS = [SP++]; +skip: R6 += -1; + CC = R6; + IF CC JUMP next; + SSYNC; + SP += 12; + UNLINK; + ( R7:6, P5:4 ) = [SP++]; + RTS; + +/* This is an internal function to flush all pending + * writes in the cache associated with a particular DCPLB. + * + * R0 - page's start address + * R1 - CPLB's data field. + */ + +.align 2 +ENTRY(_dcplb_flush) + [--SP] = ( R7:0, P5:0 ); + [--SP] = LC0; + [--SP] = LT0; + [--SP] = LB0; + [--SP] = LC1; + [--SP] = LT1; + [--SP] = LB1; + + /* If it's a 1K or 4K page, then it's quickest to + * just systematically flush all the addresses in + * the page, regardless of whether they're in the + * cache, or dirty. If it's a 1M or 4M page, there + * are too many addresses, and we have to search the + * cache for lines corresponding to the page. + */ + + CC = BITTST(R1, 17); /* 1MB or 4MB */ + IF !CC JUMP dflush_whole_page; + + /* We're only interested in the page's size, so extract + * this from the CPLB (bits 17:16), and scale to give an + * offset into the page_size and page_prefix tables. + */ + + R1 <<= 14; + R1 >>= 30; + R1 <<= 2; + + /* The page could be mapped into Bank A or Bank B, depending + * on (a) whether both banks are configured as cache, and + * (b) on whether address bit A[x] is set. x is determined + * by DCBS in DMEM_CONTROL + */ + + R2 = 0; /* Default to Bank A (Bank B would be 1)*/ + + P0.L = (DMEM_CONTROL & 0xFFFF); + P0.H = (DMEM_CONTROL >> 16); + + R3 = [P0]; /* If Bank B is not enabled as cache*/ + CC = BITTST(R3, 2); /* then Bank A is our only option.*/ + IF CC JUMP bank_chosen; + + R4 = 1<<14; /* If DCBS==0, use A[14].*/ + R5 = R4 << 7; /* If DCBS==1, use A[23];*/ + CC = BITTST(R3, 4); + IF CC R4 = R5; /* R4 now has either bit 14 or bit 23 set.*/ + R5 = R0 & R4; /* Use it to test the Page address*/ + CC = R5; /* and if that bit is set, we use Bank B,*/ + R2 = CC; /* else we use Bank A.*/ + R2 <<= 23; /* The Bank selection's at posn 23.*/ + +bank_chosen: + + /* We can also determine the sub-bank used, because this is + * taken from bits 13:12 of the address. + */ + + R3 = ((12<<8)|2); /* Extraction pattern */ + nop; /*Anamoly 05000209*/ + R4 = EXTRACT(R0, R3.L) (Z); /* Extract bits*/ + /* Save in extraction pattern for later deposit.*/ + R3.H = R4.L << 0; + + /* So: + * R0 = Page start + * R1 = Page length (actually, offset into size/prefix tables) + * R2 = Bank select mask + * R3 = sub-bank deposit values + * + * The cache has 2 Ways, and 64 sets, so we iterate through + * the sets, accessing the tag for each Way, for our Bank and + * sub-bank, looking for dirty, valid tags that match our + * address prefix. + */ + + P5.L = (DTEST_COMMAND & 0xFFFF); + P5.H = (DTEST_COMMAND >> 16); + P4.L = (DTEST_DATA0 & 0xFFFF); + P4.H = (DTEST_DATA0 >> 16); + + P0.L = page_prefix_table; + P0.H = page_prefix_table; + P1 = R1; + R5 = 0; /* Set counter*/ + P0 = P1 + P0; + R4 = [P0]; /* This is the address prefix*/ + + + /* We're reading (bit 1==0) the tag (bit 2==0), and we + * don't care about which double-word, since we're only + * fetching tags, so we only have to set Set, Bank, + * Sub-bank and Way. + */ + + P2 = 2; + LSETUP (fs1, fe1) LC1 = P2; +fs1: P0 = 64; /* iterate over all sets*/ + LSETUP (fs0, fe0) LC0 = P0; +fs0: R6 = R5 << 5; /* Combine set*/ + R6.H = R3.H << 0 ; /* and sub-bank*/ + R6 = R6 | R2; /* and Bank. Leave Way==0 at first.*/ + BITSET(R6,14); + [P5] = R6; /* Issue Command*/ + SSYNC; + R7 = [P4]; /* and read Tag.*/ + CC = BITTST(R7, 0); /* Check if valid*/ + IF !CC JUMP fskip; /* and skip if not.*/ + CC = BITTST(R7, 1); /* Check if dirty*/ + IF !CC JUMP fskip; /* and skip if not.*/ + + /* Compare against the page address. First, plant bits 13:12 + * into the tag, since those aren't part of the returned data. + */ + + R7 = DEPOSIT(R7, R3); /* set 13:12*/ + R1 = R7 & R4; /* Mask off lower bits*/ + CC = R1 == R0; /* Compare against page start.*/ + IF !CC JUMP fskip; /* Skip it if it doesn't match.*/ + + /* Tag address matches against page, so this is an entry + * we must flush. + */ + + R7 >>= 10; /* Mask off the non-address bits*/ + R7 <<= 10; + P3 = R7; + SSYNC; + FLUSHINV [P3]; /* And flush the entry*/ +fskip: +fe0: R5 += 1; /* Advance to next Set*/ +fe1: BITSET(R2, 26); /* Go to next Way.*/ + +dfinished: + SSYNC; /* Ensure the data gets out to mem.*/ + + /*Finished. Restore context.*/ + LB1 = [SP++]; + LT1 = [SP++]; + LC1 = [SP++]; + LB0 = [SP++]; + LT0 = [SP++]; + LC0 = [SP++]; + ( R7:0, P5:0 ) = [SP++]; + RTS; + +dflush_whole_page: + + /* It's a 1K or 4K page, so quicker to just flush the + * entire page. + */ + + P1 = 32; /* For 1K pages*/ + P2 = P1 << 2; /* For 4K pages*/ + P0 = R0; /* Start of page*/ + CC = BITTST(R1, 16); /* Whether 1K or 4K*/ + IF CC P1 = P2; + P1 += -1; /* Unroll one iteration*/ + SSYNC; + FLUSHINV [P0++]; /* because CSYNC can't end loops.*/ + LSETUP (eall, eall) LC0 = P1; +eall: FLUSHINV [P0++]; + SSYNC; + JUMP dfinished; + +.align 4; +page_prefix_table: +.byte4 0xFFFFFC00; /* 1K */ +.byte4 0xFFFFF000; /* 4K */ +.byte4 0xFFF00000; /* 1M */ +.byte4 0xFFC00000; /* 4M */ +.page_prefix_table.end: diff --git a/cpu/bf537/i2c.c b/cpu/bf537/i2c.c new file mode 100644 index 0000000..3b0d026 --- /dev/null +++ b/cpu/bf537/i2c.c @@ -0,0 +1,460 @@ +/**************************************************************** + * $ID: i2c.c 24 Oct 2006 12:00:00 +0800 $ * + * * + * Description: * + * * + * Maintainer: sonicz <sonic.zhang@analog.com> * + * * + * CopyRight (c) 2006 Analog Device * + * All rights reserved. * + * * + * This file is free software; * + * you are free to modify and/or redistribute it * + * under the terms of the GNU General Public Licence (GPL).* + * * + ****************************************************************/ + +#include <common.h> + +#ifdef CONFIG_HARD_I2C + +#include <asm/blackfin.h> +#include <i2c.h> +#include <asm/io.h> + +#define bfin_read16(addr) ({ unsigned __v; \ + __asm__ __volatile__ (\ + "%0 = w[%1] (z);\n\t"\ + : "=d"(__v) : "a"(addr)); (unsigned short)__v; }) + +#define bfin_write16(addr,val) ({\ + __asm__ __volatile__ (\ + "w[%0] = %1;\n\t"\ + : : "a"(addr) , "d"(val) : "memory");}) + +/* Two-Wire Interface (0xFFC01400 - 0xFFC014FF) */ +#define bfin_read_TWI_CLKDIV() bfin_read16(TWI_CLKDIV) +#define bfin_write_TWI_CLKDIV(val) bfin_write16(TWI_CLKDIV,val) +#define bfin_read_TWI_CONTROL() bfin_read16(TWI_CONTROL) +#define bfin_write_TWI_CONTROL(val) bfin_write16(TWI_CONTROL,val) +#define bfin_read_TWI_SLAVE_CTL() bfin_read16(TWI_SLAVE_CTL) +#define bfin_write_TWI_SLAVE_CTL(val) bfin_write16(TWI_SLAVE_CTL,val) +#define bfin_read_TWI_SLAVE_STAT() bfin_read16(TWI_SLAVE_STAT) +#define bfin_write_TWI_SLAVE_STAT(val) bfin_write16(TWI_SLAVE_STAT,val) +#define bfin_read_TWI_SLAVE_ADDR() bfin_read16(TWI_SLAVE_ADDR) +#define bfin_write_TWI_SLAVE_ADDR(val) bfin_write16(TWI_SLAVE_ADDR,val) +#define bfin_read_TWI_MASTER_CTL() bfin_read16(TWI_MASTER_CTL) +#define bfin_write_TWI_MASTER_CTL(val) bfin_write16(TWI_MASTER_CTL,val) +#define bfin_read_TWI_MASTER_STAT() bfin_read16(TWI_MASTER_STAT) +#define bfin_write_TWI_MASTER_STAT(val) bfin_write16(TWI_MASTER_STAT,val) +#define bfin_read_TWI_MASTER_ADDR() bfin_read16(TWI_MASTER_ADDR) +#define bfin_write_TWI_MASTER_ADDR(val) bfin_write16(TWI_MASTER_ADDR,val) +#define bfin_read_TWI_INT_STAT() bfin_read16(TWI_INT_STAT) +#define bfin_write_TWI_INT_STAT(val) bfin_write16(TWI_INT_STAT,val) +#define bfin_read_TWI_INT_MASK() bfin_read16(TWI_INT_MASK) +#define bfin_write_TWI_INT_MASK(val) bfin_write16(TWI_INT_MASK,val) +#define bfin_read_TWI_FIFO_CTL() bfin_read16(TWI_FIFO_CTL) +#define bfin_write_TWI_FIFO_CTL(val) bfin_write16(TWI_FIFO_CTL,val) +#define bfin_read_TWI_FIFO_STAT() bfin_read16(TWI_FIFO_STAT) +#define bfin_write_TWI_FIFO_STAT(val) bfin_write16(TWI_FIFO_STAT,val) +#define bfin_read_TWI_XMT_DATA8() bfin_read16(TWI_XMT_DATA8) +#define bfin_write_TWI_XMT_DATA8(val) bfin_write16(TWI_XMT_DATA8,val) +#define bfin_read_TWI_XMT_DATA16() bfin_read16(TWI_XMT_DATA16) +#define bfin_write_TWI_XMT_DATA16(val) bfin_write16(TWI_XMT_DATA16,val) +#define bfin_read_TWI_RCV_DATA8() bfin_read16(TWI_RCV_DATA8) +#define bfin_write_TWI_RCV_DATA8(val) bfin_write16(TWI_RCV_DATA8,val) +#define bfin_read_TWI_RCV_DATA16() bfin_read16(TWI_RCV_DATA16) +#define bfin_write_TWI_RCV_DATA16(val) bfin_write16(TWI_RCV_DATA16,val) + +#ifdef DEBUG_I2C +#define PRINTD(fmt,args...) do { \ + DECLARE_GLOBAL_DATA_PTR; \ + if (gd->have_console) \ + printf(fmt ,##args); \ + } while (0) +#else +#define PRINTD(fmt,args...) +#endif + +#ifndef CONFIG_TWICLK_KHZ +#define CONFIG_TWICLK_KHZ 50 +#endif + +/* All transfers are described by this data structure */ +struct i2c_msg { + u16 addr; /* slave address */ + u16 flags; +#define I2C_M_STOP 0x2 +#define I2C_M_RD 0x1 + u16 len; /* msg length */ + u8 *buf; /* pointer to msg data */ +}; + +/** + * i2c_reset: - reset the host controller + * + */ + +static void i2c_reset(void) +{ + /* Disable TWI */ + bfin_write_TWI_CONTROL(0); + sync(); + + /* Set TWI internal clock as 10MHz */ + bfin_write_TWI_CONTROL(((get_sclk() / 1024 / 1024 + 5) / 10) & 0x7F); + + /* Set Twi interface clock as specified */ + if (CONFIG_TWICLK_KHZ > 400) + bfin_write_TWI_CLKDIV(((5 * 1024 / 400) << 8) | ((5 * 1024 / + 400) & 0xFF)); + else + bfin_write_TWI_CLKDIV(((5 * 1024 / + CONFIG_TWICLK_KHZ) << 8) | ((5 * 1024 / + CONFIG_TWICLK_KHZ) + & 0xFF)); + + /* Enable TWI */ + bfin_write_TWI_CONTROL(bfin_read_TWI_CONTROL() | TWI_ENA); + sync(); +} + +int wait_for_completion(struct i2c_msg *msg, int timeout_count) +{ + unsigned short twi_int_stat; + unsigned short mast_stat; + int i; + + for (i = 0; i < timeout_count; i++) { + twi_int_stat = bfin_read_TWI_INT_STAT(); + mast_stat = bfin_read_TWI_MASTER_STAT(); + + if (XMTSERV & twi_int_stat) { + /* Transmit next data */ + if (msg->len > 0) { + bfin_write_TWI_XMT_DATA8(*(msg->buf++)); + msg->len--; + } else if (msg->flags & I2C_M_STOP) + bfin_write_TWI_MASTER_CTL + (bfin_read_TWI_MASTER_CTL() | STOP); + sync(); + /* Clear status */ + bfin_write_TWI_INT_STAT(XMTSERV); + sync(); + i = 0; + } + if (RCVSERV & twi_int_stat) { + if (msg->len > 0) { + /* Receive next data */ + *(msg->buf++) = bfin_read_TWI_RCV_DATA8(); + msg->len--; + } else if (msg->flags & I2C_M_STOP) { + bfin_write_TWI_MASTER_CTL + (bfin_read_TWI_MASTER_CTL() | STOP); + sync(); + } + /* Clear interrupt source */ + bfin_write_TWI_INT_STAT(RCVSERV); + sync(); + i = 0; + } + if (MERR & twi_int_stat) { + bfin_write_TWI_INT_STAT(MERR); + bfin_write_TWI_INT_MASK(0); + bfin_write_TWI_MASTER_STAT(0x3e); + bfin_write_TWI_MASTER_CTL(0); + sync(); + /* + * if both err and complete int stats are set, + * return proper results. + */ + if (MCOMP & twi_int_stat) { + bfin_write_TWI_INT_STAT(MCOMP); + bfin_write_TWI_INT_MASK(0); + bfin_write_TWI_MASTER_CTL(0); + sync(); + /* + * If it is a quick transfer, + * only address bug no data, not an err. + */ + if (msg->len == 0 && mast_stat & BUFRDERR) + return 0; + /* + * If address not acknowledged return -3, + * else return 0. + */ + else if (!(mast_stat & ANAK)) + return 0; + else + return -3; + } + return -1; + } + if (MCOMP & twi_int_stat) { + bfin_write_TWI_INT_STAT(MCOMP); + sync(); + bfin_write_TWI_INT_MASK(0); + bfin_write_TWI_MASTER_CTL(0); + sync(); + return 0; + } + } + if (msg->flags & I2C_M_RD) + return -4; + else + return -2; +} + +/** + * i2c_transfer: - Transfer one byte over the i2c bus + * + * This function can tranfer a byte over the i2c bus in both directions. + * It is used by the public API functions. + * + * @return: 0: transfer successful + * -1: transfer fail + * -2: transmit timeout + * -3: ACK missing + * -4: receive timeout + * -5: controller not ready + */ +int i2c_transfer(struct i2c_msg *msg) +{ + int ret = 0; + int timeout_count = 10000; + int len = msg->len; + + if (!(bfin_read_TWI_CONTROL() & TWI_ENA)) { + ret = -5; + goto transfer_error; + } + + while (bfin_read_TWI_MASTER_STAT() & BUSBUSY) ; + + /* Set Transmit device address */ + bfin_write_TWI_MASTER_ADDR(msg->addr); + + /* + * FIFO Initiation. + * Data in FIFO should be discarded before start a new operation. + */ + bfin_write_TWI_FIFO_CTL(0x3); + sync(); + bfin_write_TWI_FIFO_CTL(0); + sync(); + + if (!(msg->flags & I2C_M_RD)) { + /* Transmit first data */ + if (msg->len > 0) { + PRINTD("1 in i2c_transfer: buf=%d, len=%d\n", *msg->buf, + len); + bfin_write_TWI_XMT_DATA8(*(msg->buf++)); + msg->len--; + sync(); + } + } + + /* clear int stat */ + bfin_write_TWI_INT_STAT(MERR | MCOMP | XMTSERV | RCVSERV); + + /* Interrupt mask . Enable XMT, RCV interrupt */ + bfin_write_TWI_INT_MASK(MCOMP | MERR | + ((msg->flags & I2C_M_RD) ? RCVSERV : XMTSERV)); + sync(); + + if (len > 0 && len <= 255) + bfin_write_TWI_MASTER_CTL((len << 6)); + else if (msg->len > 255) { + bfin_write_TWI_MASTER_CTL((0xff << 6)); + msg->flags &= I2C_M_STOP; + } else + bfin_write_TWI_MASTER_CTL(0); + + /* Master enable */ + bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() | MEN | + ((msg->flags & I2C_M_RD) + ? MDIR : 0) | ((CONFIG_TWICLK_KHZ > + 100) ? FAST : 0)); + sync(); + + ret = wait_for_completion(msg, timeout_count); + PRINTD("3 in i2c_transfer: ret=%d\n", ret); + +transfer_error: + switch (ret) { + case 1: + PRINTD(("i2c_transfer: error: transfer fail\n")); + break; + case 2: + PRINTD(("i2c_transfer: error: transmit timeout\n")); + break; + case 3: + PRINTD(("i2c_transfer: error: ACK missing\n")); + break; + case 4: + PRINTD(("i2c_transfer: error: receive timeout\n")); + break; + case 5: + PRINTD(("i2c_transfer: error: controller not ready\n")); + i2c_reset(); + break; + default: + break; + } + return ret; + +} + +/* ---------------------------------------------------------------------*/ +/* API Functions */ +/* ---------------------------------------------------------------------*/ + +void i2c_init(int speed, int slaveaddr) +{ + i2c_reset(); +} + +/** + * i2c_probe: - Test if a chip answers for a given i2c address + * + * @chip: address of the chip which is searched for + * @return: 0 if a chip was found, -1 otherwhise + */ + +int i2c_probe(uchar chip) +{ + struct i2c_msg msg; + u8 probebuf; + + i2c_reset(); + + probebuf = 0; + msg.addr = chip; + msg.flags = 0; + msg.len = 1; + msg.buf = &probebuf; + if (i2c_transfer(&msg)) + return -1; + + msg.addr = chip; + msg.flags = I2C_M_RD; + msg.len = 1; + msg.buf = &probebuf; + if (i2c_transfer(&msg)) + return -1; + + return 0; +} + +/** + * i2c_read: - Read multiple bytes from an i2c device + * + * chip: I2C chip address, range 0..127 + * addr: Memory (register) address within the chip + * alen: Number of bytes to use for addr (typically 1, 2 for larger + * memories, 0 for register type devices with only one + * register) + * buffer: Where to read/write the data + * len: How many bytes to read/write + * + * Returns: 0 on success, not 0 on failure + */ + +int i2c_read(uchar chip, uint addr, int alen, uchar * buffer, int len) +{ + struct i2c_msg msg; + u8 addr_bytes[3]; /* lowest...highest byte of data address */ + + PRINTD("i2c_read: chip=0x%x, addr=0x%x, alen=0x%x, len=0x%x\n", chip, + addr, alen, len); + + if (alen > 0) { + addr_bytes[0] = (u8) ((addr >> 0) & 0x000000FF); + addr_bytes[1] = (u8) ((addr >> 8) & 0x000000FF); + addr_bytes[2] = (u8) ((addr >> 16) & 0x000000FF); + msg.addr = chip; + msg.flags = 0; + msg.len = alen; + msg.buf = addr_bytes; + if (i2c_transfer(&msg)) + return -1; + } + + /* start read sequence */ + PRINTD(("i2c_read: start read sequence\n")); + msg.addr = chip; + msg.flags = I2C_M_RD; + msg.len = len; + msg.buf = buffer; + if (i2c_transfer(&msg)) + return -1; + + return 0; +} + +/** + * i2c_write: - Write multiple bytes to an i2c device + * + * chip: I2C chip address, range 0..127 + * addr: Memory (register) address within the chip + * alen: Number of bytes to use for addr (typically 1, 2 for larger + * memories, 0 for register type devices with only one + * register) + * buffer: Where to read/write the data + * len: How many bytes to read/write + * + * Returns: 0 on success, not 0 on failure + */ + +int i2c_write(uchar chip, uint addr, int alen, uchar * buffer, int len) +{ + struct i2c_msg msg; + u8 addr_bytes[3]; /* lowest...highest byte of data address */ + + PRINTD + ("i2c_write: chip=0x%x, addr=0x%x, alen=0x%x, len=0x%x, buf0=0x%x\n", + chip, addr, alen, len, buffer[0]); + + /* chip address write */ + if (alen > 0) { + addr_bytes[0] = (u8) ((addr >> 0) & 0x000000FF); + addr_bytes[1] = (u8) ((addr >> 8) & 0x000000FF); + addr_bytes[2] = (u8) ((addr >> 16) & 0x000000FF); + msg.addr = chip; + msg.flags = 0; + msg.len = alen; + msg.buf = addr_bytes; + if (i2c_transfer(&msg)) + return -1; + } + + /* start read sequence */ + PRINTD(("i2c_write: start write sequence\n")); + msg.addr = chip; + msg.flags = 0; + msg.len = len; + msg.buf = buffer; + if (i2c_transfer(&msg)) + return -1; + + return 0; + +} + +uchar i2c_reg_read(uchar chip, uchar reg) +{ + uchar buf; + + PRINTD("i2c_reg_read: chip=0x%02x, reg=0x%02x\n", chip, reg); + i2c_read(chip, reg, 0, &buf, 1); + return (buf); +} + +void i2c_reg_write(uchar chip, uchar reg, uchar val) +{ + PRINTD("i2c_reg_write: chip=0x%02x, reg=0x%02x, val=0x%02x\n", chip, + reg, val); + i2c_write(chip, reg, 0, &val, 1); +} + +#endif /* CONFIG_HARD_I2C */ diff --git a/cpu/bf537/init_sdram.S b/cpu/bf537/init_sdram.S new file mode 100644 index 0000000..897a589 --- /dev/null +++ b/cpu/bf537/init_sdram.S @@ -0,0 +1,174 @@ +#define ASSEMBLY + +#include <linux/config.h> +#include <config.h> +#include <asm/blackfin.h> +#include <asm/mem_init.h> +.global init_sdram; + +#if (BFIN_BOOT_MODE != BF537_UART_BOOT) +#if (CONFIG_CCLK_DIV == 1) +#define CONFIG_CCLK_ACT_DIV CCLK_DIV1 +#endif +#if (CONFIG_CCLK_DIV == 2) +#define CONFIG_CCLK_ACT_DIV CCLK_DIV2 +#endif +#if (CONFIG_CCLK_DIV == 4) +#define CONFIG_CCLK_ACT_DIV CCLK_DIV4 +#endif +#if (CONFIG_CCLK_DIV == 8) +#define CONFIG_CCLK_ACT_DIV CCLK_DIV8 +#endif +#ifndef CONFIG_CCLK_ACT_DIV +#define CONFIG_CCLK_ACT_DIV CONFIG_CCLK_DIV_not_defined_properly +#endif +#endif + +init_sdram: + [--SP] = ASTAT; + [--SP] = RETS; + [--SP] = (R7:0); + [--SP] = (P5:0); + +#if (BFIN_BOOT_MODE == BF537_SPI_MASTER_BOOT) + p0.h = hi(SIC_IWR); + p0.l = lo(SIC_IWR); + r0.l = 0x1; + w[p0] = r0.l; + SSYNC; + + p0.h = hi(SPI_BAUD); + p0.l = lo(SPI_BAUD); + r0.l = CONFIG_SPI_BAUD; + w[p0] = r0.l; + SSYNC; +#endif + +#if (BFIN_BOOT_MODE != BF537_UART_BOOT) + +#ifdef CONFIG_BF537 + /* Enable PHY CLK buffer output */ + p0.h = hi(VR_CTL); + p0.l = lo(VR_CTL); + r0.l = w[p0]; + bitset(r0, 14); + w[p0] = r0.l; + ssync; +#endif + /* + * PLL_LOCKCNT - how many SCLK Cycles to delay while PLL becomes stable + */ + p0.h = hi(PLL_LOCKCNT); + p0.l = lo(PLL_LOCKCNT); + r0 = 0x300(Z); + w[p0] = r0.l; + ssync; + + /* + * Put SDRAM in self-refresh, incase anything is running + */ + P2.H = hi(EBIU_SDGCTL); + P2.L = lo(EBIU_SDGCTL); + R0 = [P2]; + BITSET (R0, 24); + [P2] = R0; + SSYNC; + + /* + * Set PLL_CTL with the value that we calculate in R0 + * - [14:09] = MSEL[5:0] : CLKIN / VCO multiplication factors + * - [8] = BYPASS : BYPASS the PLL, run CLKIN into CCLK/SCLK + * - [7] = output delay (add 200ps of delay to mem signals) + * - [6] = input delay (add 200ps of input delay to mem signals) + * - [5] = PDWN : 1=All Clocks off + * - [3] = STOPCK : 1=Core Clock off + * - [1] = PLL_OFF : 1=Disable Power to PLL + * - [0] = DF : 1=Pass CLKIN/2 to PLL / 0=Pass CLKIN to PLL + * all other bits set to zero + */ + + r0 = CONFIG_VCO_MULT & 63; /* Load the VCO multiplier */ + r0 = r0 << 9; /* Shift it over */ + r1 = CONFIG_CLKIN_HALF; /* Do we need to divide CLKIN by 2?*/ + r0 = r1 | r0; + r1 = CONFIG_PLL_BYPASS; /* Bypass the PLL? */ + r1 = r1 << 8; /* Shift it over */ + r0 = r1 | r0; /* add them all together */ + + p0.h = hi(PLL_CTL); + p0.l = lo(PLL_CTL); /* Load the address */ + cli r2; /* Disable interrupts */ + ssync; + w[p0] = r0.l; /* Set the value */ + idle; /* Wait for the PLL to stablize */ + sti r2; /* Enable interrupts */ + +check_again: + p0.h = hi(PLL_STAT); + p0.l = lo(PLL_STAT); + R0 = W[P0](Z); + CC = BITTST(R0,5); + if ! CC jump check_again; + + /* Configure SCLK & CCLK Dividers */ + r0 = (CONFIG_CCLK_ACT_DIV | CONFIG_SCLK_DIV); + p0.h = hi(PLL_DIV); + p0.l = lo(PLL_DIV); + w[p0] = r0.l; + ssync; +#endif + + /* + * Now, Initialize the SDRAM, + * start with the SDRAM Refresh Rate Control Register + */ + p0.l = lo(EBIU_SDRRC); + p0.h = hi(EBIU_SDRRC); + r0 = mem_SDRRC; + w[p0] = r0.l; + ssync; + + /* + * SDRAM Memory Bank Control Register - bank specific parameters + */ + p0.l = (EBIU_SDBCTL & 0xFFFF); + p0.h = (EBIU_SDBCTL >> 16); + r0 = mem_SDBCTL; + w[p0] = r0.l; + ssync; + + /* + * SDRAM Global Control Register - global programmable parameters + * Disable self-refresh + */ + P2.H = hi(EBIU_SDGCTL); + P2.L = lo(EBIU_SDGCTL); + R0 = [P2]; + BITCLR (R0, 24); + + /* + * Check if SDRAM is already powered up, if it is, enable self-refresh + */ + p0.h = hi(EBIU_SDSTAT); + p0.l = lo(EBIU_SDSTAT); + r2.l = w[p0]; + cc = bittst(r2,3); + if !cc jump skip; + NOP; + BITSET (R0, 23); +skip: + [P2] = R0; + SSYNC; + + /* Write in the new value in the register */ + R0.L = lo(mem_SDGCTL); + R0.H = hi(mem_SDGCTL); + [P2] = R0; + SSYNC; + nop; + + (P5:0) = [SP++]; + (R7:0) = [SP++]; + RETS = [SP++]; + ASTAT = [SP++]; + RTS; diff --git a/cpu/bf537/init_sdram_bootrom_initblock.S b/cpu/bf537/init_sdram_bootrom_initblock.S new file mode 100644 index 0000000..f9adbb9 --- /dev/null +++ b/cpu/bf537/init_sdram_bootrom_initblock.S @@ -0,0 +1,199 @@ +#define ASSEMBLY + +#include <linux/config.h> +#include <config.h> +#include <asm/blackfin.h> +#include <asm/mem_init.h> +.global init_sdram; + +#if (BFIN_BOOT_MODE != BF537_UART_BOOT) +#if (CONFIG_CCLK_DIV == 1) +#define CONFIG_CCLK_ACT_DIV CCLK_DIV1 +#endif +#if (CONFIG_CCLK_DIV == 2) +#define CONFIG_CCLK_ACT_DIV CCLK_DIV2 +#endif +#if (CONFIG_CCLK_DIV == 4) +#define CONFIG_CCLK_ACT_DIV CCLK_DIV4 +#endif +#if (CONFIG_CCLK_DIV == 8) +#define CONFIG_CCLK_ACT_DIV CCLK_DIV8 +#endif +#ifndef CONFIG_CCLK_ACT_DIV +#define CONFIG_CCLK_ACT_DIV CONFIG_CCLK_DIV_not_defined_properly +#endif +#endif + +init_sdram: + [--SP] = ASTAT; + [--SP] = RETS; + [--SP] = (R7:0); + [--SP] = (P5:0); + +#if (BFIN_BOOT_MODE == BF537_SPI_MASTER_BOOT) + p0.h = hi(SIC_IWR); + p0.l = lo(SIC_IWR); + r0.l = 0x1; + w[p0] = r0.l; + SSYNC; + + p0.h = hi(SPI_BAUD); + p0.l = lo(SPI_BAUD); + r0.l = CONFIG_SPI_BAUD_INITBLOCK; + w[p0] = r0.l; + SSYNC; +#endif + +#if (BFIN_BOOT_MODE != BF537_UART_BOOT) + +#ifdef CONFIG_BF537 + /* Enable PHY CLK buffer output */ + p0.h = hi(VR_CTL); + p0.l = lo(VR_CTL); + r0.l = w[p0]; + bitset(r0, 14); + w[p0] = r0.l; + ssync; +#endif + /* + * PLL_LOCKCNT - how many SCLK Cycles to delay while PLL becomes stable + */ + p0.h = hi(PLL_LOCKCNT); + p0.l = lo(PLL_LOCKCNT); + r0 = 0x300(Z); + w[p0] = r0.l; + ssync; + + /* + * Put SDRAM in self-refresh, incase anything is running + */ + P2.H = hi(EBIU_SDGCTL); + P2.L = lo(EBIU_SDGCTL); + R0 = [P2]; + BITSET (R0, 24); + [P2] = R0; + SSYNC; + + /* + * Set PLL_CTL with the value that we calculate in R0 + * - [14:09] = MSEL[5:0] : CLKIN / VCO multiplication factors + * - [8] = BYPASS : BYPASS the PLL, run CLKIN into CCLK/SCLK + * - [7] = output delay (add 200ps of delay to mem signals) + * - [6] = input delay (add 200ps of input delay to mem signals) + * - [5] = PDWN : 1=All Clocks off + * - [3] = STOPCK : 1=Core Clock off + * - [1] = PLL_OFF : 1=Disable Power to PLL + * - [0] = DF : 1=Pass CLKIN/2 to PLL / 0=Pass CLKIN to PLL + * all other bits set to zero + */ + + r0 = CONFIG_VCO_MULT & 63; /* Load the VCO multiplier */ + r0 = r0 << 9; /* Shift it over */ + r1 = CONFIG_CLKIN_HALF; /* Do we need to divide CLKIN by 2?*/ + r0 = r1 | r0; + r1 = CONFIG_PLL_BYPASS; /* Bypass the PLL? */ + r1 = r1 << 8; /* Shift it over */ + r0 = r1 | r0; /* add them all together */ + + p0.h = hi(PLL_CTL); + p0.l = lo(PLL_CTL); /* Load the address */ + cli r2; /* Disable interrupts */ + ssync; + w[p0] = r0.l; /* Set the value */ + idle; /* Wait for the PLL to stablize */ + sti r2; /* Enable interrupts */ + +check_again: + p0.h = hi(PLL_STAT); + p0.l = lo(PLL_STAT); + R0 = W[P0](Z); + CC = BITTST(R0,5); + if ! CC jump check_again; + + /* Configure SCLK & CCLK Dividers */ + r0 = (CONFIG_CCLK_ACT_DIV | CONFIG_SCLK_DIV); + p0.h = hi(PLL_DIV); + p0.l = lo(PLL_DIV); + w[p0] = r0.l; + ssync; +#endif + + /* + * We now are running at speed, time to set the Async mem bank wait states + * This will speed up execution, since we are normally running from FLASH. + */ + + p2.h = (EBIU_AMBCTL1 >> 16); + p2.l = (EBIU_AMBCTL1 & 0xFFFF); + r0.h = (AMBCTL1VAL >> 16); + r0.l = (AMBCTL1VAL & 0xFFFF); + [p2] = r0; + ssync; + + p2.h = (EBIU_AMBCTL0 >> 16); + p2.l = (EBIU_AMBCTL0 & 0xFFFF); + r0.h = (AMBCTL0VAL >> 16); + r0.l = (AMBCTL0VAL & 0xFFFF); + [p2] = r0; + ssync; + + p2.h = (EBIU_AMGCTL >> 16); + p2.l = (EBIU_AMGCTL & 0xffff); + r0 = AMGCTLVAL; + w[p2] = r0; + ssync; + + /* + * Now, Initialize the SDRAM, + * start with the SDRAM Refresh Rate Control Register + */ + p0.l = lo(EBIU_SDRRC); + p0.h = hi(EBIU_SDRRC); + r0 = mem_SDRRC; + w[p0] = r0.l; + ssync; + + /* + * SDRAM Memory Bank Control Register - bank specific parameters + */ + p0.l = (EBIU_SDBCTL & 0xFFFF); + p0.h = (EBIU_SDBCTL >> 16); + r0 = mem_SDBCTL; + w[p0] = r0.l; + ssync; + + /* + * SDRAM Global Control Register - global programmable parameters + * Disable self-refresh + */ + P2.H = hi(EBIU_SDGCTL); + P2.L = lo(EBIU_SDGCTL); + R0 = [P2]; + BITCLR (R0, 24); + + /* + * Check if SDRAM is already powered up, if it is, enable self-refresh + */ + p0.h = hi(EBIU_SDSTAT); + p0.l = lo(EBIU_SDSTAT); + r2.l = w[p0]; + cc = bittst(r2,3); + if !cc jump skip; + NOP; + BITSET (R0, 23); +skip: + [P2] = R0; + SSYNC; + + /* Write in the new value in the register */ + R0.L = lo(mem_SDGCTL); + R0.H = hi(mem_SDGCTL); + [P2] = R0; + SSYNC; + nop; + + (P5:0) = [SP++]; + (R7:0) = [SP++]; + RETS = [SP++]; + ASTAT = [SP++]; + RTS; diff --git a/cpu/bf537/interrupt.S b/cpu/bf537/interrupt.S new file mode 100644 index 0000000..a8be34f --- /dev/null +++ b/cpu/bf537/interrupt.S @@ -0,0 +1,246 @@ +/* + * U-boot - interrupt.S Processing of interrupts and exception handling + * + * Copyright (c) 2005 blackfin.uclinux.org + * + * (C) Copyright 2000-2004 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * This file is based on interrupt.S + * + * Copyright (C) 2003 Metrowerks, Inc. <mwaddel@metrowerks.com> + * Copyright (C) 2002 Arcturus Networks Ltd. Ted Ma <mated@sympatico.ca> + * Copyright (C) 1998 D. Jeff Dionne <jeff@ryeham.ee.ryerson.ca>, + * Kenneth Albanowski <kjahds@kjahds.com>, + * The Silver Hammer Group, Ltd. + * + * (c) 1995, Dionne & Associates + * (c) 1995, DKG Display Tech. + * + * This file is also based on exception.asm + * (C) Copyright 2001-2005 - Analog Devices, Inc. All rights reserved. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#define ASSEMBLY +#include <config.h> +#include <asm/blackfin.h> +#include <asm/hw_irq.h> +#include <asm/entry.h> +#include <asm/blackfin_defs.h> + +.global _blackfin_irq_panic; + +.text +.align 2 + +#ifndef CONFIG_KGDB +.global _evt_emulation +_evt_emulation: + SAVE_CONTEXT + r0 = IRQ_EMU; + r1 = seqstat; + sp += -12; + call _blackfin_irq_panic; + sp += 12; + rte; +#endif + +.global _evt_nmi +_evt_nmi: + SAVE_CONTEXT + r0 = IRQ_NMI; + r1 = RETN; + sp += -12; + call _blackfin_irq_panic; + sp += 12; + +_evt_nmi_exit: + rtn; + +.global _trap +_trap: + SAVE_ALL_SYS + r0 = sp; /* stack frame pt_regs pointer argument ==> r0 */ + sp += -12; + call _trap_c + sp += 12; + RESTORE_ALL_SYS + rtx; + +.global _evt_rst +_evt_rst: + SAVE_CONTEXT + r0 = IRQ_RST; + r1 = RETN; + sp += -12; + call _do_reset; + sp += 12; + +_evt_rst_exit: + rtn; + +irq_panic: + r0 = IRQ_EVX; + r1 = sp; + sp += -12; + call _blackfin_irq_panic; + sp += 12; + +.global _evt_ivhw +_evt_ivhw: + SAVE_CONTEXT + RAISE 14; + +_evt_ivhw_exit: + rti; + +.global _evt_timer +_evt_timer: + SAVE_CONTEXT + r0 = IRQ_CORETMR; + sp += -12; + /* Polling method used now. */ + /* call timer_int; */ + sp += 12; + RESTORE_CONTEXT + rti; + nop; + +.global _evt_evt7 +_evt_evt7: + SAVE_CONTEXT + r0 = 7; + sp += -12; + call _process_int; + sp += 12; + +evt_evt7_exit: + RESTORE_CONTEXT + rti; + +.global _evt_evt8 +_evt_evt8: + SAVE_CONTEXT + r0 = 8; + sp += -12; + call _process_int; + sp += 12; + +evt_evt8_exit: + RESTORE_CONTEXT + rti; + +.global _evt_evt9 +_evt_evt9: + SAVE_CONTEXT + r0 = 9; + sp += -12; + call _process_int; + sp += 12; + +evt_evt9_exit: + RESTORE_CONTEXT + rti; + +.global _evt_evt10 +_evt_evt10: + SAVE_CONTEXT + r0 = 10; + sp += -12; + call _process_int; + sp += 12; + +evt_evt10_exit: + RESTORE_CONTEXT + rti; + +.global _evt_evt11 +_evt_evt11: + SAVE_CONTEXT + r0 = 11; + sp += -12; + call _process_int; + sp += 12; + +evt_evt11_exit: + RESTORE_CONTEXT + rti; + +.global _evt_evt12 +_evt_evt12: + SAVE_CONTEXT + r0 = 12; + sp += -12; + call _process_int; + sp += 12; +evt_evt12_exit: + RESTORE_CONTEXT + rti; + +.global _evt_evt13 +_evt_evt13: + SAVE_CONTEXT + r0 = 13; + sp += -12; + call _process_int; + sp += 12; + +evt_evt13_exit: + RESTORE_CONTEXT + rti; + +.global _evt_system_call +_evt_system_call: + [--sp] = r0; + [--SP] = RETI; + r0 = [sp++]; + r0 += 2; + [--sp] = r0; + RETI = [SP++]; + r0 = [SP++]; + SAVE_CONTEXT + sp += -12; + call _exception_handle; + sp += 12; + RESTORE_CONTEXT + RTI; + +evt_system_call_exit: + rti; + +.global _evt_soft_int1 +_evt_soft_int1: + [--sp] = r0; + [--SP] = RETI; + r0 = [sp++]; + r0 += 2; + [--sp] = r0; + RETI = [SP++]; + r0 = [SP++]; + SAVE_CONTEXT + sp += -12; + call _exception_handle; + sp += 12; + RESTORE_CONTEXT + RTI; + +evt_soft_int1_exit: + rti; diff --git a/cpu/bf537/interrupts.c b/cpu/bf537/interrupts.c new file mode 100644 index 0000000..2ca76ec --- /dev/null +++ b/cpu/bf537/interrupts.c @@ -0,0 +1,174 @@ +/* + * U-boot - interrupts.c Interrupt related routines + * + * Copyright (c) 2005 blackfin.uclinux.org + * + * This file is based on interrupts.c + * Copyright 1996 Roman Zippel + * Copyright 1999 D. Jeff Dionne <jeff@uclinux.org> + * Copyright 2000-2001 Lineo, Inc. D. Jefff Dionne <jeff@lineo.ca> + * Copyright 2002 Arcturus Networks Inc. MaTed <mated@sympatico.ca> + * Copyright 2003 Metrowerks/Motorola + * Copyright 2003 Bas Vermeulen <bas@buyways.nl>, + * BuyWays B.V. (www.buyways.nl) + * + * (C) Copyright 2000-2004 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <asm/machdep.h> +#include <asm/irq.h> +#include <config.h> +#include <asm/blackfin.h> +#include "cpu.h" + +static ulong timestamp; +static ulong last_time; +static int int_flag; + +int irq_flags; /* needed by asm-blackfin/system.h */ + +/* Functions just to satisfy the linker */ + +/* + * This function is derived from PowerPC code (read timebase as long long). + * On BF533 it just returns the timer value. + */ +unsigned long long get_ticks(void) +{ + return get_timer(0); +} + +/* + * This function is derived from PowerPC code (timebase clock frequency). + * On BF533 it returns the number of timer ticks per second. + */ +ulong get_tbclk (void) +{ + ulong tbclk; + + tbclk = CFG_HZ; + return tbclk; +} + +void enable_interrupts(void) +{ + restore_flags(int_flag); +} + +int disable_interrupts(void) +{ + save_and_cli(int_flag); + return 1; +} + +int interrupt_init(void) +{ + return (0); +} + +void udelay(unsigned long usec) +{ + unsigned long delay, start, stop; + unsigned long cclk; + cclk = (CONFIG_CCLK_HZ); + + while (usec > 1) { + /* + * how many clock ticks to delay? + * - request(in useconds) * clock_ticks(Hz) / useconds/second + */ + if (usec < 1000) { + delay = (usec * (cclk / 244)) >> 12; + usec = 0; + } else { + delay = (1000 * (cclk / 244)) >> 12; + usec -= 1000; + } + + asm volatile (" %0 = CYCLES;":"=r" (start)); + do { + asm volatile (" %0 = CYCLES; ":"=r" (stop)); + } while (stop - start < delay); + } + + return; +} + +void timer_init(void) +{ + *pTCNTL = 0x1; + *pTSCALE = 0x0; + *pTCOUNT = MAX_TIM_LOAD; + *pTPERIOD = MAX_TIM_LOAD; + *pTCNTL = 0x7; + asm("CSYNC;"); + + timestamp = 0; + last_time = 0; +} + +/* Any network command or flash + * command is started get_timer shall + * be called before TCOUNT gets reset, + * to implement the accurate timeouts. + * + * How ever milliconds doesn't return + * the number that has been elapsed from + * the last reset. + * + * As get_timer is used in the u-boot + * only for timeouts this should be + * sufficient + */ +ulong get_timer(ulong base) +{ + ulong milisec; + + /* Number of clocks elapsed */ + ulong clocks = (MAX_TIM_LOAD - (*pTCOUNT)); + + /** + * Find if the TCOUNT is reset + * timestamp gives the number of times + * TCOUNT got reset + */ + if (clocks < last_time) + timestamp++; + last_time = clocks; + + /* Get the number of milliseconds */ + milisec = clocks / (CONFIG_CCLK_HZ / 1000); + + /** + * Find the number of millisonds + * that got elapsed before this TCOUNT cycle + */ + milisec += timestamp * (MAX_TIM_LOAD / (CONFIG_CCLK_HZ / 1000)); + + return (milisec - base); +} + +void reset_timer (void) +{ + timestamp = 0; +} diff --git a/cpu/bf537/ints.c b/cpu/bf537/ints.c new file mode 100644 index 0000000..f476f14 --- /dev/null +++ b/cpu/bf537/ints.c @@ -0,0 +1,117 @@ +/* + * U-boot - ints.c Interrupt related routines + * + * Copyright (c) 2005 blackfin.uclinux.org + * + * This file is based on ints.c + * + * Apr18 2003, Changed by HuTao to support interrupt cascading for Blackfin + * drivers + * + * Copyright 1996 Roman Zippel + * Copyright 1999 D. Jeff Dionne <jeff@uclinux.org> + * Copyright 2000-2001 Lineo, Inc. D. Jefff Dionne <jeff@lineo.ca> + * Copyright 2002 Arcturus Networks Inc. MaTed <mated@sympatico.ca> + * Copyright 2003 Metrowerks/Motorola + * + * (C) Copyright 2000-2004 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <linux/stddef.h> +#include <asm/system.h> +#include <asm/irq.h> +#include <asm/traps.h> +#include <asm/io.h> +#include <asm/errno.h> +#include <asm/machdep.h> +#include <asm/setup.h> +#include <asm/blackfin.h> +#include "cpu.h" + +void blackfin_irq_panic(int reason, struct pt_regs *regs) +{ + printf("\n\nException: IRQ 0x%x entered\n", reason); + printf("code=[0x%x], ", (unsigned int)(regs->seqstat & 0x3f)); + printf("stack frame=0x%x, ", (unsigned int)regs); + printf("bad PC=0x%04x\n", (unsigned int)regs->pc); + dump(regs); + printf("Unhandled IRQ or exceptions!\n"); + printf("Please reset the board \n"); +} + +void blackfin_init_IRQ(void) +{ + *(unsigned volatile long *)(SIC_IMASK) = SIC_UNMASK_ALL; + cli(); +#ifndef CONFIG_KGDB + *(unsigned volatile long *)(EVT_EMULATION_ADDR) = 0x0; +#endif + *(unsigned volatile long *)(EVT_NMI_ADDR) = + (unsigned volatile long)evt_nmi; + *(unsigned volatile long *)(EVT_EXCEPTION_ADDR) = + (unsigned volatile long)trap; + *(unsigned volatile long *)(EVT_HARDWARE_ERROR_ADDR) = + (unsigned volatile long)evt_ivhw; + *(unsigned volatile long *)(EVT_RESET_ADDR) = + (unsigned volatile long)evt_rst; + *(unsigned volatile long *)(EVT_TIMER_ADDR) = + (unsigned volatile long)evt_timer; + *(unsigned volatile long *)(EVT_IVG7_ADDR) = + (unsigned volatile long)evt_evt7; + *(unsigned volatile long *)(EVT_IVG8_ADDR) = + (unsigned volatile long)evt_evt8; + *(unsigned volatile long *)(EVT_IVG9_ADDR) = + (unsigned volatile long)evt_evt9; + *(unsigned volatile long *)(EVT_IVG10_ADDR) = + (unsigned volatile long)evt_evt10; + *(unsigned volatile long *)(EVT_IVG11_ADDR) = + (unsigned volatile long)evt_evt11; + *(unsigned volatile long *)(EVT_IVG12_ADDR) = + (unsigned volatile long)evt_evt12; + *(unsigned volatile long *)(EVT_IVG13_ADDR) = + (unsigned volatile long)evt_evt13; + *(unsigned volatile long *)(EVT_IVG14_ADDR) = + (unsigned volatile long)evt_system_call; + *(unsigned volatile long *)(EVT_IVG15_ADDR) = + (unsigned volatile long)evt_soft_int1; + *(volatile unsigned long *)ILAT = 0; + asm("csync;"); + sti(); + *(volatile unsigned long *)IMASK = 0xffbf; + asm("csync;"); +} + +void exception_handle(void) +{ +#if defined (CONFIG_PANIC_HANG) + display_excp(); +#else + udelay(100000); /* allow messages to go out */ + do_reset(NULL, 0, 0, NULL); +#endif +} + +void display_excp(void) +{ + printf("Exception!\n"); +} diff --git a/cpu/bf537/serial.c b/cpu/bf537/serial.c new file mode 100644 index 0000000..dd4f916 --- /dev/null +++ b/cpu/bf537/serial.c @@ -0,0 +1,194 @@ +/* + * U-boot - serial.c Serial driver for BF537 + * + * Copyright (c) 2005 blackfin.uclinux.org + * + * This file is based on + * bf537_serial.c: Serial driver for BlackFin BF537 internal UART. + * Copyright (c) 2003 Bas Vermeulen <bas@buyways.nl>, + * BuyWays B.V. (www.buyways.nl) + * + * Based heavily on blkfinserial.c + * blkfinserial.c: Serial driver for BlackFin DSP internal USRTs. + * Copyright(c) 2003 Metrowerks <mwaddel@metrowerks.com> + * Copyright(c) 2001 Tony Z. Kou <tonyko@arcturusnetworks.com> + * Copyright(c) 2001-2002 Arcturus Networks Inc. <www.arcturusnetworks.com> + * + * Based on code from 68328 version serial driver imlpementation which was: + * Copyright (C) 1995 David S. Miller <davem@caip.rutgers.edu> + * Copyright (C) 1998 Kenneth Albanowski <kjahds@kjahds.com> + * Copyright (C) 1998, 1999 D. Jeff Dionne <jeff@uclinux.org> + * Copyright (C) 1999 Vladimir Gurevich <vgurevic@cisco.com> + * + * (C) Copyright 2000-2004 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <asm/irq.h> +#include <asm/system.h> +#include <asm/segment.h> +#include <asm/bitops.h> +#include <asm/delay.h> +#include <asm/uaccess.h> +#include <asm/io.h> +#include "serial.h" + +unsigned long pll_div_fact; + +void calc_baud(void) +{ + unsigned char i; + int temp; + u_long sclk = get_sclk(); + + for (i = 0; i < sizeof(baud_table) / sizeof(int); i++) { + temp = sclk / (baud_table[i] * 8); + if ((temp & 0x1) == 1) { + temp++; + } + temp = temp / 2; + hw_baud_table[i].dl_high = (temp >> 8) & 0xFF; + hw_baud_table[i].dl_low = (temp) & 0xFF; + } +} + +void serial_setbrg(void) +{ + int i; + DECLARE_GLOBAL_DATA_PTR; + + calc_baud(); + + for (i = 0; i < sizeof(baud_table) / sizeof(int); i++) { + if (gd->baudrate == baud_table[i]) + break; + } + + /* Enable UART */ + *pUART_GCTL |= UART_GCTL_UCEN; + sync(); + + /* Set DLAB in LCR to Access DLL and DLH */ + ACCESS_LATCH; + sync(); + + *pUART_DLL = hw_baud_table[i].dl_low; + sync(); + *pUART_DLH = hw_baud_table[i].dl_high; + sync(); + + /* Clear DLAB in LCR to Access THR RBR IER */ + ACCESS_PORT_IER; + sync(); + + /* Enable ERBFI and ELSI interrupts + * to poll SIC_ISR register*/ + *pUART_IER = UART_IER_ELSI | UART_IER_ERBFI | UART_IER_ETBEI; + sync(); + + /* Set LCR to Word Lengh 8-bit word select */ + *pUART_LCR = UART_LCR_WLS8; + sync(); + + return; +} + +int serial_init(void) +{ + serial_setbrg(); + return (0); +} + +void serial_putc(const char c) +{ + if ((*pUART_LSR) & UART_LSR_TEMT) { + if (c == '\n') + serial_putc('\r'); + + local_put_char(c); + } + + while (!((*pUART_LSR) & UART_LSR_TEMT)) + SYNC_ALL; + + return; +} + +int serial_tstc(void) +{ + if (*pUART_LSR & UART_LSR_DR) + return 1; + else + return 0; +} + +int serial_getc(void) +{ + unsigned short uart_lsr_val, uart_rbr_val; + unsigned long isr_val; + int ret; + + /* Poll for RX Interrupt */ + while (!((isr_val = + *(volatile unsigned long *)SIC_ISR) & IRQ_UART_RX_BIT)) ; + asm("csync;"); + + uart_lsr_val = *pUART_LSR; /* Clear status bit */ + uart_rbr_val = *pUART_RBR; /* getc() */ + + if (isr_val & IRQ_UART_ERROR_BIT) { + ret = -1; + } else { + ret = uart_rbr_val & 0xff; + } + + return ret; +} + +void serial_puts(const char *s) +{ + while (*s) { + serial_putc(*s++); + } +} + +static void local_put_char(char ch) +{ + int flags = 0; + unsigned long isr_val; + + save_and_cli(flags); + + /* Poll for TX Interruput */ + while (!((isr_val = *pSIC_ISR) & IRQ_UART_TX_BIT)) ; + asm("csync;"); + + *pUART_THR = ch; /* putc() */ + + if (isr_val & IRQ_UART_ERROR_BIT) { + printf("?"); + } + + restore_flags(flags); + + return; +} diff --git a/cpu/bf537/serial.h b/cpu/bf537/serial.h new file mode 100644 index 0000000..c9ee3dc --- /dev/null +++ b/cpu/bf537/serial.h @@ -0,0 +1,77 @@ +/* + * U-boot - bf537_serial.h Serial Driver defines + * + * Copyright (c) 2005 blackfin.uclinux.org + * + * This file is based on + * bf533_serial.h: Definitions for the BlackFin BF533 DSP serial driver. + * Copyright (C) 2003 Bas Vermeulen <bas@buyways.nl> + * BuyWays B.V. (www.buyways.nl) + * + * Based heavily on: + * blkfinserial.h: Definitions for the BlackFin DSP serial driver. + * + * Copyright (C) 2001 Tony Z. Kou tonyko@arcturusnetworks.com + * Copyright (C) 2001 Arcturus Networks Inc. <www.arcturusnetworks.com> + * + * Based on code from 68328serial.c which was: + * Copyright (C) 1995 David S. Miller <davem@caip.rutgers.edu> + * Copyright (C) 1998 Kenneth Albanowski <kjahds@kjahds.com> + * Copyright (C) 1998, 1999 D. Jeff Dionne <jeff@uclinux.org> + * Copyright (C) 1999 Vladimir Gurevich <vgurevic@cisco.com> + * + * (C) Copyright 2000-2004 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _Bf537_SERIAL_H +#define _Bf537_SERIAL_H + +#include <linux/config.h> +#include <asm/blackfin.h> + +#define SYNC_ALL __asm__ __volatile__ ("ssync;\n") +#define ACCESS_LATCH *pUART_LCR |= UART_LCR_DLAB; +#define ACCESS_PORT_IER *pUART_LCR &= (~UART_LCR_DLAB); + +void serial_setbrg(void); +static void local_put_char(char ch); +void calc_baud(void); +void serial_setbrg(void); +int serial_init(void); +void serial_putc(const char c); +int serial_tstc(void); +int serial_getc(void); +void serial_puts(const char *s); +static void local_put_char(char ch); + +int baud_table[5] = { 9600, 19200, 38400, 57600, 115200 }; + +struct { + unsigned char dl_high; + unsigned char dl_low; +} hw_baud_table[5]; + +#ifdef CONFIG_STAMP +extern unsigned long pll_div_fact; +#endif + +#endif diff --git a/cpu/bf537/start.S b/cpu/bf537/start.S new file mode 100644 index 0000000..264e9b6 --- /dev/null +++ b/cpu/bf537/start.S @@ -0,0 +1,579 @@ +/* + * U-boot - start.S Startup file of u-boot for BF537 + * + * Copyright (c) 2005 blackfin.uclinux.org + * + * This file is based on head.S + * Copyright (c) 2003 Metrowerks/Motorola + * Copyright (C) 1998 D. Jeff Dionne <jeff@ryeham.ee.ryerson.ca>, + * Kenneth Albanowski <kjahds@kjahds.com>, + * The Silver Hammer Group, Ltd. + * (c) 1995, Dionne & Associates + * (c) 1995, DKG Display Tech. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * Note: A change in this file subsequently requires a change in + * board/$(board_name)/config.mk for a valid u-boot.bin + */ + +#define ASSEMBLY + +#include <linux/config.h> +#include <config.h> +#include <asm/blackfin.h> + +.global _stext; +.global __bss_start; +.global start; +.global _start; +.global _rambase; +.global _ramstart; +.global _ramend; +.global _bf533_data_dest; +.global _bf533_data_size; +.global edata; +.global _initialize; +.global _exit; +.global flashdataend; +.global init_sdram; +.global _icache_enable; +.global _dcache_enable; +#if defined(CONFIG_BF537)&&defined(CONFIG_POST) +.global _memory_post_test; +.global _post_flag; +#endif + +#if (BFIN_BOOT_MODE == BF537_UART_BOOT) +#if (CONFIG_CCLK_DIV == 1) +#define CONFIG_CCLK_ACT_DIV CCLK_DIV1 +#endif +#if (CONFIG_CCLK_DIV == 2) +#define CONFIG_CCLK_ACT_DIV CCLK_DIV2 +#endif +#if (CONFIG_CCLK_DIV == 4) +#define CONFIG_CCLK_ACT_DIV CCLK_DIV4 +#endif +#if (CONFIG_CCLK_DIV == 8) +#define CONFIG_CCLK_ACT_DIV CCLK_DIV8 +#endif +#ifndef CONFIG_CCLK_ACT_DIV +#define CONFIG_CCLK_ACT_DIV CONFIG_CCLK_DIV_not_defined_properly +#endif +#endif + +.text +_start: +start: +_stext: + + R0 = 0x32; + SYSCFG = R0; + SSYNC; + + /* As per HW reference manual DAG registers, + * DATA and Address resgister shall be zero'd + * in initialization, after a reset state + */ + r1 = 0; /* Data registers zero'd */ + r2 = 0; + r3 = 0; + r4 = 0; + r5 = 0; + r6 = 0; + r7 = 0; + + p0 = 0; /* Address registers zero'd */ + p1 = 0; + p2 = 0; + p3 = 0; + p4 = 0; + p5 = 0; + + i0 = 0; /* DAG Registers zero'd */ + i1 = 0; + i2 = 0; + i3 = 0; + m0 = 0; + m1 = 0; + m3 = 0; + m3 = 0; + l0 = 0; + l1 = 0; + l2 = 0; + l3 = 0; + b0 = 0; + b1 = 0; + b2 = 0; + b3 = 0; + + /* Set loop counters to zero, to make sure that + * hw loops are disabled. + */ + r0 = 0; + lc0 = r0; + lc1 = r0; + + SSYNC; + + /* Check soft reset status */ + p0.h = SWRST >> 16; + p0.l = SWRST & 0xFFFF; + r0.l = w[p0]; + + cc = bittst(r0, 15); + if !cc jump no_soft_reset; + + /* Clear Soft reset */ + r0 = 0x0000; + w[p0] = r0; + ssync; + +no_soft_reset: + nop; + + /* Clear EVT registers */ + p0.h = (EVT_EMULATION_ADDR >> 16); + p0.l = (EVT_EMULATION_ADDR & 0xFFFF); + p0 += 8; + p1 = 14; + r1 = 0; + LSETUP(4,4) lc0 = p1; + [ p0 ++ ] = r1; + +#if (BFIN_BOOT_MODE != BF537_SPI_MASTER_BOOT) + p0.h = hi(SIC_IWR); + p0.l = lo(SIC_IWR); + r0.l = 0x1; + w[p0] = r0.l; + SSYNC; +#endif + +#if (BFIN_BOOT_MODE == BF537_UART_BOOT) + + p0.h = hi(SIC_IWR); + p0.l = lo(SIC_IWR); + r0.l = 0x1; + w[p0] = r0.l; + SSYNC; + + /* + * PLL_LOCKCNT - how many SCLK Cycles to delay while PLL becomes stable + */ + p0.h = hi(PLL_LOCKCNT); + p0.l = lo(PLL_LOCKCNT); + r0 = 0x300(Z); + w[p0] = r0.l; + ssync; + + /* + * Put SDRAM in self-refresh, incase anything is running + */ + P2.H = hi(EBIU_SDGCTL); + P2.L = lo(EBIU_SDGCTL); + R0 = [P2]; + BITSET (R0, 24); + [P2] = R0; + SSYNC; + + /* + * Set PLL_CTL with the value that we calculate in R0 + * - [14:09] = MSEL[5:0] : CLKIN / VCO multiplication factors + * - [8] = BYPASS : BYPASS the PLL, run CLKIN into CCLK/SCLK + * - [7] = output delay (add 200ps of delay to mem signals) + * - [6] = input delay (add 200ps of input delay to mem signals) + * - [5] = PDWN : 1=All Clocks off + * - [3] = STOPCK : 1=Core Clock off + * - [1] = PLL_OFF : 1=Disable Power to PLL + * - [0] = DF : 1=Pass CLKIN/2 to PLL / 0=Pass CLKIN to PLL + * all other bits set to zero + */ + + r0 = CONFIG_VCO_MULT & 63; /* Load the VCO multiplier */ + r0 = r0 << 9; /* Shift it over, */ + r1 = CONFIG_CLKIN_HALF; /* Do we need to divide CLKIN by 2?*/ + r0 = r1 | r0; + r1 = CONFIG_PLL_BYPASS; /* Bypass the PLL? */ + r1 = r1 << 8; /* Shift it over */ + r0 = r1 | r0; /* add them all together */ + + p0.h = hi(PLL_CTL); + p0.l = lo(PLL_CTL); /* Load the address */ + cli r2; /* Disable interrupts */ + ssync; + w[p0] = r0.l; /* Set the value */ + idle; /* Wait for the PLL to stablize */ + sti r2; /* Enable interrupts */ + +check_again: + p0.h = hi(PLL_STAT); + p0.l = lo(PLL_STAT); + R0 = W[P0](Z); + CC = BITTST(R0,5); + if ! CC jump check_again; + + /* Configure SCLK & CCLK Dividers */ + r0 = (CONFIG_CCLK_ACT_DIV | CONFIG_SCLK_DIV); + p0.h = hi(PLL_DIV); + p0.l = lo(PLL_DIV); + w[p0] = r0.l; + ssync; +#endif + + /* + * We now are running at speed, time to set the Async mem bank wait states + * This will speed up execution, since we are normally running from FLASH. + * we need to read MAC address from FLASH + */ + p2.h = (EBIU_AMBCTL1 >> 16); + p2.l = (EBIU_AMBCTL1 & 0xFFFF); + r0.h = (AMBCTL1VAL >> 16); + r0.l = (AMBCTL1VAL & 0xFFFF); + [p2] = r0; + ssync; + + p2.h = (EBIU_AMBCTL0 >> 16); + p2.l = (EBIU_AMBCTL0 & 0xFFFF); + r0.h = (AMBCTL0VAL >> 16); + r0.l = (AMBCTL0VAL & 0xFFFF); + [p2] = r0; + ssync; + + p2.h = (EBIU_AMGCTL >> 16); + p2.l = (EBIU_AMGCTL & 0xffff); + r0 = AMGCTLVAL; + w[p2] = r0; + ssync; + +#if ((BFIN_BOOT_MODE != BF537_SPI_MASTER_BOOT) && (BFIN_BOOT_MODE != BF537_UART_BOOT)) + sp.l = (0xffb01000 & 0xFFFF); + sp.h = (0xffb01000 >> 16); + + call init_sdram; +#endif + + +#if defined(CONFIG_BF537)&&defined(CONFIG_POST) + /* DMA POST code to Hi of L1 SRAM */ +postcopy: + /* P1 Points to the beginning of SYSTEM MMR Space */ + P1.H = hi(SYSMMR_BASE); + P1.L = lo(SYSMMR_BASE); + + R0.H = _text_l1; + R0.L = _text_l1; + R1.H = _etext_l1; + R1.L = _etext_l1; + R2 = R1 - R0; /* Count */ + R0.H = _etext; + R0.L = _etext; + R1.H = (CFG_MONITOR_BASE >> 16); + R1.L = (CFG_MONITOR_BASE & 0xFFFF); + R0 = R0 - R1; + R1.H = (CFG_FLASH_BASE >> 16); + R1.L = (CFG_FLASH_BASE & 0xFFFF); + R0 = R0 + R1; /* Source Address */ + R1.H = hi(L1_ISRAM); /* Destination Address (high) */ + R1.L = lo(L1_ISRAM); /* Destination Address (low) */ + R3.L = DMAEN; /* Source DMAConfig Value (8-bit words) */ + /* Destination DMAConfig Value (8-bit words) */ + R4.L = (DI_EN | WNR | DMAEN); + + R6 = 0x1 (Z); + W[P1+OFFSET_(MDMA_S0_X_MODIFY)] = R6; /* Source Modify = 1 */ + W[P1+OFFSET_(MDMA_D0_X_MODIFY)] = R6; /* Destination Modify = 1 */ + + [P1+OFFSET_(MDMA_S0_START_ADDR)] = R0; /* Set Source Base Address */ + W[P1+OFFSET_(MDMA_S0_X_COUNT)] = R2; /* Set Source Count */ + /* Set Source DMAConfig = DMA Enable, + Memory Read, 8-Bit Transfers, 1-D DMA, Flow - Stop */ + W[P1+OFFSET_(MDMA_S0_CONFIG)] = R3; + + [P1+OFFSET_(MDMA_D0_START_ADDR)] = R1; /* Set Destination Base Address */ + W[P1+OFFSET_(MDMA_D0_X_COUNT)] = R2; /* Set Destination Count */ + /* Set Destination DMAConfig = DMA Enable, + Memory Write, 8-Bit Transfers, 1-D DMA, Flow - Stop, IOC */ + W[P1+OFFSET_(MDMA_D0_CONFIG)] = R4; + +POST_DMA_DONE: + p0.h = hi(MDMA_D0_IRQ_STATUS); + p0.l = lo(MDMA_D0_IRQ_STATUS); + R0 = W[P0](Z); + CC = BITTST(R0, 0); + if ! CC jump POST_DMA_DONE + + R0 = 0x1; + W[P1+OFFSET_(MDMA_D0_IRQ_STATUS)] = R0; /* Write 1 to clear DMA interrupt */ + + /* DMA POST data to Hi of L1 SRAM */ + R0.H = _rodata_l1; + R0.L = _rodata_l1; + R1.H = _erodata_l1; + R1.L = _erodata_l1; + R2 = R1 - R0; /* Count */ + R0.H = _erodata; + R0.L = _erodata; + R1.H = (CFG_MONITOR_BASE >> 16); + R1.L = (CFG_MONITOR_BASE & 0xFFFF); + R0 = R0 - R1; + R1.H = (CFG_FLASH_BASE >> 16); + R1.L = (CFG_FLASH_BASE & 0xFFFF); + R0 = R0 + R1; /* Source Address */ + R1.H = hi(DATA_BANKB_SRAM); /* Destination Address (high) */ + R1.L = lo(DATA_BANKB_SRAM); /* Destination Address (low) */ + R3.L = DMAEN; /* Source DMAConfig Value (8-bit words) */ + R4.L = (DI_EN | WNR | DMAEN); /* Destination DMAConfig Value (8-bit words) */ + + R6 = 0x1 (Z); + W[P1+OFFSET_(MDMA_S0_X_MODIFY)] = R6; /* Source Modify = 1 */ + W[P1+OFFSET_(MDMA_D0_X_MODIFY)] = R6; /* Destination Modify = 1 */ + + [P1+OFFSET_(MDMA_S0_START_ADDR)] = R0; /* Set Source Base Address */ + W[P1+OFFSET_(MDMA_S0_X_COUNT)] = R2; /* Set Source Count */ + /* Set Source DMAConfig = DMA Enable, + Memory Read, 8-Bit Transfers, 1-D DMA, Flow - Stop */ + W[P1+OFFSET_(MDMA_S0_CONFIG)] = R3; + + [P1+OFFSET_(MDMA_D0_START_ADDR)] = R1; /* Set Destination Base Address */ + W[P1+OFFSET_(MDMA_D0_X_COUNT)] = R2; /* Set Destination Count */ + /* Set Destination DMAConfig = DMA Enable, + Memory Write, 8-Bit Transfers, 1-D DMA, Flow - Stop, IOC */ + W[P1+OFFSET_(MDMA_D0_CONFIG)] = R4; + +POST_DATA_DMA_DONE: + p0.h = hi(MDMA_D0_IRQ_STATUS); + p0.l = lo(MDMA_D0_IRQ_STATUS); + R0 = W[P0](Z); + CC = BITTST(R0, 0); + if ! CC jump POST_DATA_DMA_DONE + + R0 = 0x1; + W[P1+OFFSET_(MDMA_D0_IRQ_STATUS)] = R0; /* Write 1 to clear DMA interrupt */ + + p0.l = _memory_post_test; + p0.h = _memory_post_test; + r0 = 0x0; + call (p0); + r7 = r0; /* save return value */ + + call init_sdram; +#endif + + /* relocate into to RAM */ + call get_pc; +offset: + r2.l = offset; + r2.h = offset; + r3.l = start; + r3.h = start; + r1 = r2 - r3; + + r0 = r0 - r1; + p1 = r0; + + p2.l = (CFG_MONITOR_BASE & 0xffff); + p2.h = (CFG_MONITOR_BASE >> 16); + + p3 = 0x04; + p4.l = ((CFG_MONITOR_BASE + CFG_MONITOR_LEN) & 0xffff); + p4.h = ((CFG_MONITOR_BASE + CFG_MONITOR_LEN) >> 16); +loop1: + r1 = [p1 ++ p3]; + [p2 ++ p3] = r1; + cc=p2==p4; + if !cc jump loop1; + /* + * configure STACK + */ + r0.h = (CONFIG_STACKBASE >> 16); + r0.l = (CONFIG_STACKBASE & 0xFFFF); + sp = r0; + fp = sp; + + /* + * This next section keeps the processor in supervisor mode + * during kernel boot. Switches to user mode at end of boot. + * See page 3-9 of Hardware Reference manual for documentation. + */ + + /* To keep ourselves in the supervisor mode */ + p0.l = (EVT_IVG15_ADDR & 0xFFFF); + p0.h = (EVT_IVG15_ADDR >> 16); + + p1.l = _real_start; + p1.h = _real_start; + [p0] = p1; + + p0.l = (IMASK & 0xFFFF); + p0.h = (IMASK >> 16); + r0.l = LO(IVG15_POS); + r0.h = HI(IVG15_POS); + [p0] = r0; + raise 15; + p0.l = WAIT_HERE; + p0.h = WAIT_HERE; + reti = p0; + rti; + +WAIT_HERE: + jump WAIT_HERE; + +.global _real_start; +_real_start: + [ -- sp ] = reti; + +#ifdef CONFIG_BF537 +/* Initialise General-Purpose I/O Modules on BF537 + * Rev 0.0 Anomaly 05000212 - PORTx_FER, + * PORT_MUX Registers Do Not accept "writes" correctly + */ + p0.h = hi(PORTF_FER); + p0.l = lo(PORTF_FER); + R0.L = W[P0]; /* Read */ + nop; + nop; + nop; + ssync; + R0 = 0x000F(Z); + W[P0] = R0.L; /* Write */ + nop; + nop; + nop; + ssync; + W[P0] = R0.L; /* Enable peripheral function of PORTF for UART0 and UART1 */ + nop; + nop; + nop; + ssync; + + p0.h = hi(PORTH_FER); + p0.l = lo(PORTH_FER); + R0.L = W[P0]; /* Read */ + nop; + nop; + nop; + ssync; + R0 = 0xFFFF(Z); + W[P0] = R0.L; /* Write */ + nop; + nop; + nop; + ssync; + W[P0] = R0.L; /* Enable peripheral function of PORTH for MAC */ + nop; + nop; + nop; + ssync; + +#endif + + /* DMA reset code to Hi of L1 SRAM */ +copy: + P1.H = hi(SYSMMR_BASE); /* P1 Points to the beginning of SYSTEM MMR Space */ + P1.L = lo(SYSMMR_BASE); + + R0.H = reset_start; /* Source Address (high) */ + R0.L = reset_start; /* Source Address (low) */ + R1.H = reset_end; + R1.L = reset_end; + R2 = R1 - R0; /* Count */ + R1.H = hi(L1_ISRAM); /* Destination Address (high) */ + R1.L = lo(L1_ISRAM); /* Destination Address (low) */ + R3.L = DMAEN; /* Source DMAConfig Value (8-bit words) */ + R4.L = (DI_EN | WNR | DMAEN); /* Destination DMAConfig Value (8-bit words) */ + +DMA: + R6 = 0x1 (Z); + W[P1+OFFSET_(MDMA_S0_X_MODIFY)] = R6; /* Source Modify = 1 */ + W[P1+OFFSET_(MDMA_D0_X_MODIFY)] = R6; /* Destination Modify = 1 */ + + [P1+OFFSET_(MDMA_S0_START_ADDR)] = R0; /* Set Source Base Address */ + W[P1+OFFSET_(MDMA_S0_X_COUNT)] = R2; /* Set Source Count */ + /* Set Source DMAConfig = DMA Enable, + Memory Read, 8-Bit Transfers, 1-D DMA, Flow - Stop */ + W[P1+OFFSET_(MDMA_S0_CONFIG)] = R3; + + [P1+OFFSET_(MDMA_D0_START_ADDR)] = R1; /* Set Destination Base Address */ + W[P1+OFFSET_(MDMA_D0_X_COUNT)] = R2; /* Set Destination Count */ + /* Set Destination DMAConfig = DMA Enable, + Memory Write, 8-Bit Transfers, 1-D DMA, Flow - Stop, IOC */ + W[P1+OFFSET_(MDMA_D0_CONFIG)] = R4; + +WAIT_DMA_DONE: + p0.h = hi(MDMA_D0_IRQ_STATUS); + p0.l = lo(MDMA_D0_IRQ_STATUS); + R0 = W[P0](Z); + CC = BITTST(R0, 0); + if ! CC jump WAIT_DMA_DONE + + R0 = 0x1; + W[P1+OFFSET_(MDMA_D0_IRQ_STATUS)] = R0; /* Write 1 to clear DMA interrupt */ + + /* Initialize BSS Section with 0 s */ + p1.l = __bss_start; + p1.h = __bss_start; + p2.l = _end; + p2.h = _end; + r1 = p1; + r2 = p2; + r3 = r2 - r1; + r3 = r3 >> 2; + p3 = r3; + lsetup (_clear_bss, _clear_bss_end ) lc1 = p3; + CC = p2<=p1; + if CC jump _clear_bss_skip; + r0 = 0; +_clear_bss: +_clear_bss_end: + [p1++] = r0; +_clear_bss_skip: + +#if defined(CONFIG_BF537)&&defined(CONFIG_POST) + p0.l = _post_flag; + p0.h = _post_flag; + r0 = r7; + [p0] = r0; +#endif + + p0.l = _start1; + p0.h = _start1; + jump (p0); + +reset_start: + p0.h = WDOG_CNT >> 16; + p0.l = WDOG_CNT & 0xffff; + r0 = 0x0010; + w[p0] = r0; + p0.h = WDOG_CTL >> 16; + p0.l = WDOG_CTL & 0xffff; + r0 = 0x0000; + w[p0] = r0; +reset_wait: + jump reset_wait; + +reset_end: + nop; + +_exit: + jump.s _exit; +get_pc: + r0 = rets; + rts; diff --git a/cpu/bf537/start1.S b/cpu/bf537/start1.S new file mode 100644 index 0000000..72cfafb --- /dev/null +++ b/cpu/bf537/start1.S @@ -0,0 +1,38 @@ +/* + * U-boot - start1.S Code running out of RAM after relocation + * + * Copyright (c) 2005 blackfin.uclinux.org + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#define ASSEMBLY +#include <linux/config.h> +#include <config.h> +#include <asm/blackfin.h> + +.global start1; +.global _start1; + +.text +_start1: +start1: + sp += -12; + call _board_init_f; + sp += 12; diff --git a/cpu/bf537/traps.c b/cpu/bf537/traps.c new file mode 100644 index 0000000..994ece8 --- /dev/null +++ b/cpu/bf537/traps.c @@ -0,0 +1,241 @@ +/* + * U-boot - traps.c Routines related to interrupts and exceptions + * + * Copyright (c) 2005 blackfin.uclinux.org + * + * This file is based on + * No original Copyright holder listed, + * Probabily original (C) Roman Zippel (assigned DJD, 1999) + * + * Copyright 2003 Metrowerks - for Blackfin + * Copyright 2000-2001 Lineo, Inc. D. Jeff Dionne <jeff@lineo.ca> + * Copyright 1999-2000 D. Jeff Dionne, <jeff@uclinux.org> + * + * (C) Copyright 2000-2004 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <linux/types.h> +#include <asm/errno.h> +#include <asm/irq.h> +#include <asm/system.h> +#include <asm/traps.h> +#include <asm/page.h> +#include <asm/machdep.h> +#include "cpu.h" +#include <asm/arch/anomaly.h> +#include <asm/cplb.h> +#include <asm/io.h> + +void init_IRQ(void) +{ + blackfin_init_IRQ(); + return; +} + +void process_int(unsigned long vec, struct pt_regs *fp) +{ + printf("interrupt\n"); + return; +} + +extern unsigned int icplb_table[page_descriptor_table_size][2]; +extern unsigned int dcplb_table[page_descriptor_table_size][2]; + +unsigned long last_cplb_fault_retx; + +static unsigned int cplb_sizes[4] = + { 1024, 4 * 1024, 1024 * 1024, 4 * 1024 * 1024 }; + +void trap_c(struct pt_regs *regs) +{ + unsigned int addr; + unsigned long trapnr = (regs->seqstat) & SEQSTAT_EXCAUSE; + unsigned int i, j, size, *I0, *I1; + unsigned short data = 0; + + switch (trapnr) { + /* 0x26 - Data CPLB Miss */ + case VEC_CPLB_M: + +#ifdef ANOMALY_05000261 + /* + * Work around an anomaly: if we see a new DCPLB fault, + * return without doing anything. Then, + * if we get the same fault again, handle it. + */ + addr = last_cplb_fault_retx; + last_cplb_fault_retx = regs->retx; + printf("this time, curr = 0x%08x last = 0x%08x\n", + addr, last_cplb_fault_retx); + if (addr != last_cplb_fault_retx) + goto trap_c_return; +#endif + data = 1; + + case VEC_CPLB_I_M: + + if (data) { + addr = *pDCPLB_FAULT_ADDR; + } else { + addr = *pICPLB_FAULT_ADDR; + } + for (i = 0; i < page_descriptor_table_size; i++) { + if (data) { + size = cplb_sizes[dcplb_table[i][1] >> 16]; + j = dcplb_table[i][0]; + } else { + size = cplb_sizes[icplb_table[i][1] >> 16]; + j = icplb_table[i][0]; + } + if ((j <= addr) && ((j + size) > addr)) { + debug("found %i 0x%08x\n", i, j); + break; + } + } + if (i == page_descriptor_table_size) { + printf("something is really wrong\n"); + do_reset(NULL, 0, 0, NULL); + } + + /* Turn the cache off */ + if (data) { + sync(); + asm(" .align 8; "); + *(unsigned int *)DMEM_CONTROL &= + ~(ACACHE_BCACHE | ENDCPLB | PORT_PREF0); + sync(); + } else { + sync(); + asm(" .align 8; "); + *(unsigned int *)IMEM_CONTROL &= ~(IMC | ENICPLB); + sync(); + } + + if (data) { + I0 = (unsigned int *)DCPLB_ADDR0; + I1 = (unsigned int *)DCPLB_DATA0; + } else { + I0 = (unsigned int *)ICPLB_ADDR0; + I1 = (unsigned int *)ICPLB_DATA0; + } + + j = 0; + while (*I1 & CPLB_LOCK) { + debug("skipping %i %08p - %08x\n", j, I1, *I1); + *I0++; + *I1++; + j++; + } + + debug("remove %i 0x%08x 0x%08x\n", j, *I0, *I1); + + for (; j < 15; j++) { + debug("replace %i 0x%08x 0x%08x\n", j, I0, I0 + 1); + *I0++ = *(I0 + 1); + *I1++ = *(I1 + 1); + } + + if (data) { + *I0 = dcplb_table[i][0]; + *I1 = dcplb_table[i][1]; + I0 = (unsigned int *)DCPLB_ADDR0; + I1 = (unsigned int *)DCPLB_DATA0; + } else { + *I0 = icplb_table[i][0]; + *I1 = icplb_table[i][1]; + I0 = (unsigned int *)ICPLB_ADDR0; + I1 = (unsigned int *)ICPLB_DATA0; + } + + for (j = 0; j < 16; j++) { + debug("%i 0x%08x 0x%08x\n", j, *I0++, *I1++); + } + + /* Turn the cache back on */ + if (data) { + j = *(unsigned int *)DMEM_CONTROL; + sync(); + asm(" .align 8; "); + *(unsigned int *)DMEM_CONTROL = + ACACHE_BCACHE | ENDCPLB | PORT_PREF0 | j; + sync(); + } else { + sync(); + asm(" .align 8; "); + *(unsigned int *)IMEM_CONTROL = IMC | ENICPLB; + sync(); + } + + break; + default: + /* All traps come here */ + printf("code=[0x%x], ", (unsigned int)(regs->seqstat & 0x3f)); + printf("stack frame=0x%x, ", (unsigned int)regs); + printf("bad PC=0x%04x\n", (unsigned int)regs->pc); + dump(regs); + printf("\n\n"); + + printf("Unhandled IRQ or exceptions!\n"); + printf("Please reset the board \n"); + do_reset(NULL, 0, 0, NULL); + } + +trap_c_return: + return; + +} + +void dump(struct pt_regs *fp) +{ + debug("RETE: %08lx RETN: %08lx RETX: %08lx RETS: %08lx\n", + fp->rete, fp->retn, fp->retx, fp->rets); + debug("IPEND: %04lx SYSCFG: %04lx\n", fp->ipend, fp->syscfg); + debug("SEQSTAT: %08lx SP: %08lx\n", (long)fp->seqstat, (long)fp); + debug("R0: %08lx R1: %08lx R2: %08lx R3: %08lx\n", + fp->r0, fp->r1, fp->r2, fp->r3); + debug("R4: %08lx R5: %08lx R6: %08lx R7: %08lx\n", + fp->r4, fp->r5, fp->r6, fp->r7); + debug("P0: %08lx P1: %08lx P2: %08lx P3: %08lx\n", + fp->p0, fp->p1, fp->p2, fp->p3); + debug("P4: %08lx P5: %08lx FP: %08lx\n", + fp->p4, fp->p5, fp->fp); + debug("A0.w: %08lx A0.x: %08lx A1.w: %08lx A1.x: %08lx\n", + fp->a0w, fp->a0x, fp->a1w, fp->a1x); + + debug("LB0: %08lx LT0: %08lx LC0: %08lx\n", + fp->lb0, fp->lt0, fp->lc0); + debug("LB1: %08lx LT1: %08lx LC1: %08lx\n", + fp->lb1, fp->lt1, fp->lc1); + debug("B0: %08lx L0: %08lx M0: %08lx I0: %08lx\n", + fp->b0, fp->l0, fp->m0, fp->i0); + debug("B1: %08lx L1: %08lx M1: %08lx I1: %08lx\n", + fp->b1, fp->l1, fp->m1, fp->i1); + debug("B2: %08lx L2: %08lx M2: %08lx I2: %08lx\n", + fp->b2, fp->l2, fp->m2, fp->i2); + debug("B3: %08lx L3: %08lx M3: %08lx I3: %08lx\n", + fp->b3, fp->l3, fp->m3, fp->i3); + + debug("DCPLB_FAULT_ADDR=%p\n", *pDCPLB_FAULT_ADDR); + debug("ICPLB_FAULT_ADDR=%p\n", *pICPLB_FAULT_ADDR); + +} diff --git a/cpu/bf537/video.c b/cpu/bf537/video.c new file mode 100644 index 0000000..3ff0151 --- /dev/null +++ b/cpu/bf537/video.c @@ -0,0 +1,194 @@ +/* + * (C) Copyright 2000 + * Paolo Scaffardi, AIRVENT SAM s.p.a - RIMINI(ITALY), arsenio@tin.it + * (C) Copyright 2002 + * Wolfgang Denk, wd@denx.de + * (C) Copyright 2006 + * Aubrey Li, aubrey.li@analog.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <stdarg.h> +#include <common.h> +#include <config.h> +#include <asm/blackfin.h> +#include <i2c.h> +#include <linux/types.h> +#include <devices.h> + +#ifdef CONFIG_VIDEO +#define NTSC_FRAME_ADDR 0x06000000 +#include "video.h" + +/* NTSC OUTPUT SIZE 720 * 240 */ +#define VERTICAL 2 +#define HORIZONTAL 4 + +int is_vblank_line(const int line) +{ + /* + * This array contains a single bit for each line in + * an NTSC frame. + */ + if ((line <= 18) || (line >= 264 && line <= 281) || (line == 528)) + return true; + + return false; +} + +int NTSC_framebuffer_init(char *base_address) +{ + const int NTSC_frames = 1; + const int NTSC_lines = 525; + char *dest = base_address; + int frame_num, line_num; + + for (frame_num = 0; frame_num < NTSC_frames; ++frame_num) { + for (line_num = 1; line_num <= NTSC_lines; ++line_num) { + unsigned int code; + int offset = 0; + int i; + + if (is_vblank_line(line_num)) + offset++; + + if (line_num > 266 || line_num < 3) + offset += 2; + + /* Output EAV code */ + code = SystemCodeMap[offset].EAV; + write_dest_byte((char)(code >> 24) & 0xff); + write_dest_byte((char)(code >> 16) & 0xff); + write_dest_byte((char)(code >> 8) & 0xff); + write_dest_byte((char)(code) & 0xff); + + /* Output horizontal blanking */ + for (i = 0; i < 67 * 2; ++i) { + write_dest_byte(0x80); + write_dest_byte(0x10); + } + + /* Output SAV */ + code = SystemCodeMap[offset].SAV; + write_dest_byte((char)(code >> 24) & 0xff); + write_dest_byte((char)(code >> 16) & 0xff); + write_dest_byte((char)(code >> 8) & 0xff); + write_dest_byte((char)(code) & 0xff); + + /* Output empty horizontal data */ + for (i = 0; i < 360 * 2; ++i) { + write_dest_byte(0x80); + write_dest_byte(0x10); + } + } + } + + return dest - base_address; +} + +void fill_frame(char *Frame, int Value) +{ + int *OddPtr32; + int OddLine; + int *EvenPtr32; + int EvenLine; + int i; + int *data; + int m, n; + + /* fill odd and even frames */ + for (OddLine = 22, EvenLine = 285; OddLine < 263; OddLine++, EvenLine++) { + OddPtr32 = (int *)((Frame + (OddLine * 1716)) + 276); + EvenPtr32 = (int *)((Frame + (EvenLine * 1716)) + 276); + for (i = 0; i < 360; i++, OddPtr32++, EvenPtr32++) { + *OddPtr32 = Value; + *EvenPtr32 = Value; + } + } + + for (m = 0; m < VERTICAL; m++) { + data = (int *)u_boot_logo.data; + for (OddLine = (22 + m), EvenLine = (285 + m); + OddLine < (u_boot_logo.height * VERTICAL) + (22 + m); + OddLine += VERTICAL, EvenLine += VERTICAL) { + OddPtr32 = (int *)((Frame + ((OddLine) * 1716)) + 276); + EvenPtr32 = + (int *)((Frame + ((EvenLine) * 1716)) + 276); + for (i = 0; i < u_boot_logo.width / 2; i++) { + /* enlarge one pixel to m x n */ + for (n = 0; n < HORIZONTAL; n++) { + *OddPtr32++ = *data; + *EvenPtr32++ = *data; + } + data++; + } + } + } +} + +void video_putc(const char c) +{ +} + +void video_puts(const char *s) +{ +} + +static int video_init(void) +{ + char *NTSCFrame; + NTSCFrame = (char *)NTSC_FRAME_ADDR; + NTSC_framebuffer_init(NTSCFrame); + fill_frame(NTSCFrame, BLUE); + + *pPPI_CONTROL = 0x0082; + *pPPI_FRAME = 0x020D; + + *pDMA0_START_ADDR = NTSCFrame; + *pDMA0_X_COUNT = 0x035A; + *pDMA0_X_MODIFY = 0x0002; + *pDMA0_Y_COUNT = 0x020D; + *pDMA0_Y_MODIFY = 0x0002; + *pDMA0_CONFIG = 0x1015; + *pPPI_CONTROL = 0x0083; + return 0; +} + +int drv_video_init(void) +{ + int error, devices = 1; + + device_t videodev; + + video_init(); /* Video initialization */ + + memset(&videodev, 0, sizeof(videodev)); + + strcpy(videodev.name, "video"); + videodev.ext = DEV_EXT_VIDEO; /* Video extensions */ + videodev.flags = DEV_FLAGS_OUTPUT; /* Output only */ + videodev.putc = video_putc; /* 'putc' function */ + videodev.puts = video_puts; /* 'puts' function */ + + error = device_register(&videodev); + + return (error == 0) ? devices : error; +} +#endif diff --git a/cpu/bf537/video.h b/cpu/bf537/video.h new file mode 100644 index 0000000..a43553f --- /dev/null +++ b/cpu/bf537/video.h @@ -0,0 +1,25 @@ +#include <video_logo.h> +#define write_dest_byte(val) {*dest++=val;} +#define BLACK (0x01800180) /* black pixel pattern */ +#define BLUE (0x296E29F0) /* blue pixel pattern */ +#define RED (0x51F0515A) /* red pixel pattern */ +#define MAGENTA (0x6ADE6ACA) /* magenta pixel pattern*/ +#define GREEN (0x91229136) /* green pixel pattern */ +#define CYAN (0xAA10AAA6) /* cyan pixel pattern */ +#define YELLOW (0xD292D210) /* yellow pixel pattern */ +#define WHITE (0xFE80FE80) /* white pixel pattern */ + +#define true 1 +#define false 0 + +typedef struct { + unsigned int SAV; + unsigned int EAV; +} SystemCodeType; + +const SystemCodeType SystemCodeMap[4] = { + {0xFF000080, 0xFF00009D}, + {0xFF0000AB, 0xFF0000B6}, + {0xFF0000C7, 0xFF0000DA}, + {0xFF0000EC, 0xFF0000F1} +}; diff --git a/cpu/bf561/Makefile b/cpu/bf561/Makefile new file mode 100644 index 0000000..ee7842a --- /dev/null +++ b/cpu/bf561/Makefile @@ -0,0 +1,52 @@ +# U-boot - Makefile +# +# Copyright (c) 2005 blackfin.uclinux.org +# +# (C) Copyright 2000-2004 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +include $(TOPDIR)/config.mk + +LIB = $(obj)lib$(CPU).a + +START = start.o start1.o interrupt.o cache.o flush.o init_sdram.o +COBJS = cpu.o traps.o ints.o serial.o interrupts.o video.o + +EXTRA = init_sdram_bootrom_initblock.o + +SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS) $(SOBJS)) +START := $(addprefix $(obj),$(START)) + +all: $(obj).depend $(START) $(LIB) $(obj).depend $(EXTRA) + +$(LIB): $(OBJS) + $(AR) $(ARFLAGS) $@ $(OBJS) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/cpu/bf561/cache.S b/cpu/bf561/cache.S new file mode 100644 index 0000000..5bda5bf --- /dev/null +++ b/cpu/bf561/cache.S @@ -0,0 +1,128 @@ +#define ASSEMBLY +#include <asm/linkage.h> +#include <config.h> +#include <asm/blackfin.h> + +.text +.align 2 +ENTRY(_blackfin_icache_flush_range) + R2 = -32; + R2 = R0 & R2; + P0 = R2; + P1 = R1; + CSYNC; + 1: + IFLUSH[P0++]; + CC = P0 < P1(iu); + IF CC JUMP 1b(bp); + IFLUSH[P0]; + SSYNC; + RTS; + +ENTRY(_blackfin_dcache_flush_range) + R2 = -32; + R2 = R0 & R2; + P0 = R2; + P1 = R1; + CSYNC; +1: + FLUSH[P0++]; + CC = P0 < P1(iu); + IF CC JUMP 1b(bp); + FLUSH[P0]; + SSYNC; + RTS; + +ENTRY(_icache_invalidate) +ENTRY(_invalidate_entire_icache) + [--SP] = (R7:5); + + P0.L = (IMEM_CONTROL & 0xFFFF); + P0.H = (IMEM_CONTROL >> 16); + R7 =[P0]; + + /* + * Clear the IMC bit , All valid bits in the instruction + * cache are set to the invalid state + */ + BITCLR(R7, IMC_P); + CLI R6; + /* SSYNC required before invalidating cache. */ + SSYNC; + .align 8; + [P0] = R7; + SSYNC; + STI R6; + + /* Configures the instruction cache agian */ + R6 = (IMC | ENICPLB); + R7 = R7 | R6; + + CLI R6; + SSYNC; + .align 8; + [P0] = R7; + SSYNC; + STI R6; + + (R7:5) =[SP++]; + RTS; + +/* + * Invalidate the Entire Data cache by + * clearing DMC[1:0] bits + */ +ENTRY(_invalidate_entire_dcache) +ENTRY(_dcache_invalidate) + [--SP] = (R7:6); + + P0.L = (DMEM_CONTROL & 0xFFFF); + P0.H = (DMEM_CONTROL >> 16); + R7 =[P0]; + + /* + * Clear the DMC[1:0] bits, All valid bits in the data + * cache are set to the invalid state + */ + BITCLR(R7, DMC0_P); + BITCLR(R7, DMC1_P); + CLI R6; + SSYNC; + .align 8; + [P0] = R7; + SSYNC; + STI R6; + /* Configures the data cache again */ + + R6 = (ACACHE_BCACHE | ENDCPLB | PORT_PREF0); + R7 = R7 | R6; + + CLI R6; + SSYNC; + .align 8; + [P0] = R7; + SSYNC; + STI R6; + + (R7:6) =[SP++]; + RTS; + +ENTRY(_blackfin_dcache_invalidate_range) + R2 = -32; + R2 = R0 & R2; + P0 = R2; + P1 = R1; + CSYNC; +1: + FLUSHINV[P0++]; + CC = P0 < P1(iu); + IF CC JUMP 1b(bp); + + /* + * If the data crosses a cache line, then we'll be pointing to + * the last cache line, but won't have flushed/invalidated it yet, so do + * one more. + */ + FLUSHINV[P0]; + SSYNC; + RTS; diff --git a/cpu/bf561/config.mk b/cpu/bf561/config.mk new file mode 100644 index 0000000..c49a0ba --- /dev/null +++ b/cpu/bf561/config.mk @@ -0,0 +1,27 @@ +# U-boot - config.mk +# +# Copyright (c) 2005 blackfin.uclinux.org +# +# (C) Copyright 2000-2004 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +PLATFORM_RELFLAGS += -mcpu=bf561 -ffixed-P5 diff --git a/cpu/bf561/cpu.c b/cpu/bf561/cpu.c new file mode 100644 index 0000000..a7b53d8 --- /dev/null +++ b/cpu/bf561/cpu.c @@ -0,0 +1,220 @@ +/* + * U-boot - cpu.c CPU specific functions + * + * Copyright (c) 2005 blackfin.uclinux.org + * + * (C) Copyright 2000-2004 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <asm/blackfin.h> +#include <command.h> +#include <asm/entry.h> +#include <asm/cplb.h> +#include <asm/io.h> + +#define CACHE_ON 1 +#define CACHE_OFF 0 + +extern unsigned int icplb_table[page_descriptor_table_size][2]; +extern unsigned int dcplb_table[page_descriptor_table_size][2]; + +int do_reset(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) +{ + __asm__ __volatile__("cli r3;" "P0 = %0;" "JUMP (P0);"::"r"(L1_ISRAM) + ); + + return 0; +} + +/* These functions are just used to satisfy the linker */ +int cpu_init(void) +{ + return 0; +} + +int cleanup_before_linux(void) +{ + return 0; +} + +void icache_enable(void) +{ + unsigned int *I0, *I1; + int i, j = 0; + + /* Before enable icache, disable it first */ + icache_disable(); + I0 = (unsigned int *)ICPLB_ADDR0; + I1 = (unsigned int *)ICPLB_DATA0; + + /* make sure the locked ones go in first */ + for (i = 0; i < page_descriptor_table_size; i++) { + if (CPLB_LOCK & icplb_table[i][1]) { + debug("adding %02i %02i 0x%08x 0x%08x\n", i, j, + icplb_table[i][0], icplb_table[i][1]); + *I0++ = icplb_table[i][0]; + *I1++ = icplb_table[i][1]; + j++; + } + } + + for (i = 0; i < page_descriptor_table_size; i++) { + if (!(CPLB_LOCK & icplb_table[i][1])) { + debug("adding %02i %02i 0x%08x 0x%08x\n", i, j, + icplb_table[i][0], icplb_table[i][1]); + *I0++ = icplb_table[i][0]; + *I1++ = icplb_table[i][1]; + j++; + if (j == 16) { + break; + } + } + } + + /* Fill the rest with invalid entry */ + if (j <= 15) { + for (; j < 16; j++) { + debug("filling %i with 0", j); + *I1++ = 0x0; + } + + } + + cli(); + sync(); + asm(" .align 8; "); + *(unsigned int *)IMEM_CONTROL = IMC | ENICPLB; + sync(); + sti(); +} + +void icache_disable(void) +{ + cli(); + sync(); + asm(" .align 8; "); + *(unsigned int *)IMEM_CONTROL &= ~(IMC | ENICPLB); + sync(); + sti(); +} + +int icache_status(void) +{ + unsigned int value; + value = *(unsigned int *)IMEM_CONTROL; + + if (value & (IMC | ENICPLB)) + return CACHE_ON; + else + return CACHE_OFF; +} + +void dcache_enable(void) +{ + unsigned int *I0, *I1; + unsigned int temp; + int i, j = 0; + + /* Before enable dcache, disable it first */ + dcache_disable(); + I0 = (unsigned int *)DCPLB_ADDR0; + I1 = (unsigned int *)DCPLB_DATA0; + + /* make sure the locked ones go in first */ + for (i = 0; i < page_descriptor_table_size; i++) { + if (CPLB_LOCK & dcplb_table[i][1]) { + debug("adding %02i %02i 0x%08x 0x%08x\n", i, j, + dcplb_table[i][0], dcplb_table[i][1]); + *I0++ = dcplb_table[i][0]; + *I1++ = dcplb_table[i][1]; + j++; + } else { + debug("skip %02i %02i 0x%08x 0x%08x\n", i, j, + dcplb_table[i][0], dcplb_table[i][1]); + } + } + + for (i = 0; i < page_descriptor_table_size; i++) { + if (!(CPLB_LOCK & dcplb_table[i][1])) { + debug("adding %02i %02i 0x%08x 0x%08x\n", i, j, + dcplb_table[i][0], dcplb_table[i][1]); + *I0++ = dcplb_table[i][0]; + *I1++ = dcplb_table[i][1]; + j++; + if (j == 16) { + break; + } + } + } + + /* Fill the rest with invalid entry */ + if (j <= 15) { + for (; j < 16; j++) { + debug("filling %i with 0", j); + *I1++ = 0x0; + } + } + + cli(); + temp = *(unsigned int *)DMEM_CONTROL; + sync(); + asm(" .align 8; "); + *(unsigned int *)DMEM_CONTROL = + ACACHE_BCACHE | ENDCPLB | PORT_PREF0 | temp; + sync(); + sti(); +} + +void dcache_disable(void) +{ + + unsigned int *I0, *I1; + int i; + + cli(); + sync(); + asm(" .align 8; "); + *(unsigned int *)DMEM_CONTROL &= + ~(ACACHE_BCACHE | ENDCPLB | PORT_PREF0); + sync(); + sti(); + + /* after disable dcache, clear it so we don't confuse the next application */ + I0 = (unsigned int *)DCPLB_ADDR0; + I1 = (unsigned int *)DCPLB_DATA0; + + for (i = 0; i < 16; i++) { + *I0++ = 0x0; + *I1++ = 0x0; + } +} + +int dcache_status(void) +{ + unsigned int value; + value = *(unsigned int *)DMEM_CONTROL; + if (value & (ENDCPLB)) + return CACHE_ON; + else + return CACHE_OFF; +} diff --git a/cpu/bf561/cpu.h b/cpu/bf561/cpu.h new file mode 100644 index 0000000..821363e --- /dev/null +++ b/cpu/bf561/cpu.h @@ -0,0 +1,66 @@ +/* + * U-boot - cpu.h + * + * Copyright (c) 2005 blackfin.uclinux.org + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _CPU_H_ +#define _CPU_H_ + +#include <command.h> + +#define INTERNAL_IRQS (32) +#define NUM_IRQ_NODES 16 +#define DEF_INTERRUPT_FLAGS 1 +#define MAX_TIM_LOAD 0xFFFFFFFF + +void blackfin_irq_panic(int reason, struct pt_regs *reg); +extern void dump(struct pt_regs *regs); +void display_excp(void); +asmlinkage void evt_nmi(void); +asmlinkage void evt_exception(void); +asmlinkage void trap(void); +asmlinkage void evt_ivhw(void); +asmlinkage void evt_rst(void); +asmlinkage void evt_timer(void); +asmlinkage void evt_evt7(void); +asmlinkage void evt_evt8(void); +asmlinkage void evt_evt9(void); +asmlinkage void evt_evt10(void); +asmlinkage void evt_evt11(void); +asmlinkage void evt_evt12(void); +asmlinkage void evt_evt13(void); +asmlinkage void evt_soft_int1(void); +asmlinkage void evt_system_call(void); +void blackfin_irq_panic(int reason, struct pt_regs *regs); +void blackfin_free_irq(unsigned int irq, void *dev_id); +void call_isr(int irq, struct pt_regs *fp); +void blackfin_do_irq(int vec, struct pt_regs *fp); +void blackfin_init_IRQ(void); +void blackfin_enable_irq(unsigned int irq); +void blackfin_disable_irq(unsigned int irq); +extern int do_reset(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]); +int blackfin_request_irq(unsigned int irq, + void (*handler) (int, void *, struct pt_regs *), + unsigned long flags, const char *devname, + void *dev_id); +void timer_init(void); +#endif diff --git a/cpu/bf561/flush.S b/cpu/bf561/flush.S new file mode 100644 index 0000000..7e12c83 --- /dev/null +++ b/cpu/bf561/flush.S @@ -0,0 +1,402 @@ +/* Copyright (C) 2003 Analog Devices, Inc. All Rights Reserved. + * Copyright (C) 2004 LG SOft India. All Rights Reserved. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. + */ +#define ASSEMBLY + +#include <asm/linkage.h> +#include <asm/cplb.h> +#include <config.h> +#include <asm/blackfin.h> + +.text + +/* This is an external function being called by the user + * application through __flush_cache_all. Currently this function + * serves the purpose of flushing all the pending writes in + * in the instruction cache. + */ + +ENTRY(_flush_instruction_cache) + [--SP] = ( R7:6, P5:4 ); + LINK 12; + SP += -12; + P5.H = (ICPLB_ADDR0 >> 16); + P5.L = (ICPLB_ADDR0 & 0xFFFF); + P4.H = (ICPLB_DATA0 >> 16); + P4.L = (ICPLB_DATA0 & 0xFFFF); + R7 = CPLB_VALID | CPLB_L1_CHBL; + R6 = 16; +inext: R0 = [P5++]; + R1 = [P4++]; + [--SP] = RETS; + CALL _icplb_flush; /* R0 = page, R1 = data*/ + RETS = [SP++]; +iskip: R6 += -1; + CC = R6; + IF CC JUMP inext; + SSYNC; + SP += 12; + UNLINK; + ( R7:6, P5:4 ) = [SP++]; + RTS; + +/* This is an internal function to flush all pending + * writes in the cache associated with a particular ICPLB. + * + * R0 - page's start address + * R1 - CPLB's data field. + */ + +.align 2 +ENTRY(_icplb_flush) + [--SP] = ( R7:0, P5:0 ); + [--SP] = LC0; + [--SP] = LT0; + [--SP] = LB0; + [--SP] = LC1; + [--SP] = LT1; + [--SP] = LB1; + + /* If it's a 1K or 4K page, then it's quickest to + * just systematically flush all the addresses in + * the page, regardless of whether they're in the + * cache, or dirty. If it's a 1M or 4M page, there + * are too many addresses, and we have to search the + * cache for lines corresponding to the page. + */ + + CC = BITTST(R1, 17); /* 1MB or 4MB */ + IF !CC JUMP iflush_whole_page; + + /* We're only interested in the page's size, so extract + * this from the CPLB (bits 17:16), and scale to give an + * offset into the page_size and page_prefix tables. + */ + + R1 <<= 14; + R1 >>= 30; + R1 <<= 2; + + /* We can also determine the sub-bank used, because this is + * taken from bits 13:12 of the address. + */ + + R3 = ((12<<8)|2); /* Extraction pattern */ + nop; /*Anamoly 05000209*/ + R4 = EXTRACT(R0, R3.L) (Z); /* Extract bits*/ + R3.H = R4.L << 0 ; /* Save in extraction pattern for later deposit.*/ + + + /* So: + * R0 = Page start + * R1 = Page length (actually, offset into size/prefix tables) + * R3 = sub-bank deposit values + * + * The cache has 2 Ways, and 64 sets, so we iterate through + * the sets, accessing the tag for each Way, for our Bank and + * sub-bank, looking for dirty, valid tags that match our + * address prefix. + */ + + P5.L = (ITEST_COMMAND & 0xFFFF); + P5.H = (ITEST_COMMAND >> 16); + P4.L = (ITEST_DATA0 & 0xFFFF); + P4.H = (ITEST_DATA0 >> 16); + + P0.L = page_prefix_table; + P0.H = page_prefix_table; + P1 = R1; + R5 = 0; /* Set counter*/ + P0 = P1 + P0; + R4 = [P0]; /* This is the address prefix*/ + + /* We're reading (bit 1==0) the tag (bit 2==0), and we + * don't care about which double-word, since we're only + * fetching tags, so we only have to set Set, Bank, + * Sub-bank and Way. + */ + + P2 = 4; + LSETUP (ifs1, ife1) LC1 = P2; +ifs1: P0 = 32; /* iterate over all sets*/ + LSETUP (ifs0, ife0) LC0 = P0; +ifs0: R6 = R5 << 5; /* Combine set*/ + R6.H = R3.H << 0 ; /* and sub-bank*/ + [P5] = R6; /* Issue Command*/ + SSYNC; /* CSYNC will not work here :(*/ + R7 = [P4]; /* and read Tag.*/ + CC = BITTST(R7, 0); /* Check if valid*/ + IF !CC JUMP ifskip; /* and skip if not.*/ + + /* Compare against the page address. First, plant bits 13:12 + * into the tag, since those aren't part of the returned data. + */ + + R7 = DEPOSIT(R7, R3); /* set 13:12*/ + R1 = R7 & R4; /* Mask off lower bits*/ + CC = R1 == R0; /* Compare against page start.*/ + IF !CC JUMP ifskip; /* Skip it if it doesn't match.*/ + + /* Tag address matches against page, so this is an entry + * we must flush. + */ + + R7 >>= 10; /* Mask off the non-address bits*/ + R7 <<= 10; + P3 = R7; + IFLUSH [P3]; /* And flush the entry*/ +ifskip: +ife0: R5 += 1; /* Advance to next Set*/ +ife1: NOP; + +ifinished: + SSYNC; /* Ensure the data gets out to mem.*/ + + /*Finished. Restore context.*/ + LB1 = [SP++]; + LT1 = [SP++]; + LC1 = [SP++]; + LB0 = [SP++]; + LT0 = [SP++]; + LC0 = [SP++]; + ( R7:0, P5:0 ) = [SP++]; + RTS; + +iflush_whole_page: + /* It's a 1K or 4K page, so quicker to just flush the + * entire page. + */ + + P1 = 32; /* For 1K pages*/ + P2 = P1 << 2; /* For 4K pages*/ + P0 = R0; /* Start of page*/ + CC = BITTST(R1, 16); /* Whether 1K or 4K*/ + IF CC P1 = P2; + P1 += -1; /* Unroll one iteration*/ + SSYNC; + IFLUSH [P0++]; /* because CSYNC can't end loops.*/ + LSETUP (isall, ieall) LC0 = P1; +isall:IFLUSH [P0++]; +ieall: NOP; + SSYNC; + JUMP ifinished; + +/* This is an external function being called by the user + * application through __flush_cache_all. Currently this function + * serves the purpose of flushing all the pending writes in + * in the data cache. + */ + +ENTRY(_flush_data_cache) + [--SP] = ( R7:6, P5:4 ); + LINK 12; + SP += -12; + P5.H = (DCPLB_ADDR0 >> 16); + P5.L = (DCPLB_ADDR0 & 0xFFFF); + P4.H = (DCPLB_DATA0 >> 16); + P4.L = (DCPLB_DATA0 & 0xFFFF); + R7 = CPLB_VALID | CPLB_L1_CHBL | CPLB_DIRTY (Z); + R6 = 16; +next: R0 = [P5++]; + R1 = [P4++]; + CC = BITTST(R1, 14); /* Is it write-through?*/ + IF CC JUMP skip; /* If so, ignore it.*/ + R2 = R1 & R7; /* Is it a dirty, cached page?*/ + CC = R2; + IF !CC JUMP skip; /* If not, ignore it.*/ + [--SP] = RETS; + CALL _dcplb_flush; /* R0 = page, R1 = data*/ + RETS = [SP++]; +skip: R6 += -1; + CC = R6; + IF CC JUMP next; + SSYNC; + SP += 12; + UNLINK; + ( R7:6, P5:4 ) = [SP++]; + RTS; + +/* This is an internal function to flush all pending + * writes in the cache associated with a particular DCPLB. + * + * R0 - page's start address + * R1 - CPLB's data field. + */ + +.align 2 +ENTRY(_dcplb_flush) + [--SP] = ( R7:0, P5:0 ); + [--SP] = LC0; + [--SP] = LT0; + [--SP] = LB0; + [--SP] = LC1; + [--SP] = LT1; + [--SP] = LB1; + + /* If it's a 1K or 4K page, then it's quickest to + * just systematically flush all the addresses in + * the page, regardless of whether they're in the + * cache, or dirty. If it's a 1M or 4M page, there + * are too many addresses, and we have to search the + * cache for lines corresponding to the page. + */ + + CC = BITTST(R1, 17); /* 1MB or 4MB */ + IF !CC JUMP dflush_whole_page; + + /* We're only interested in the page's size, so extract + * this from the CPLB (bits 17:16), and scale to give an + * offset into the page_size and page_prefix tables. + */ + + R1 <<= 14; + R1 >>= 30; + R1 <<= 2; + + /* The page could be mapped into Bank A or Bank B, depending + * on (a) whether both banks are configured as cache, and + * (b) on whether address bit A[x] is set. x is determined + * by DCBS in DMEM_CONTROL + */ + + R2 = 0; /* Default to Bank A (Bank B would be 1)*/ + + P0.L = (DMEM_CONTROL & 0xFFFF); + P0.H = (DMEM_CONTROL >> 16); + + R3 = [P0]; /* If Bank B is not enabled as cache*/ + CC = BITTST(R3, 2); /* then Bank A is our only option.*/ + IF CC JUMP bank_chosen; + + R4 = 1<<14; /* If DCBS==0, use A[14].*/ + R5 = R4 << 7; /* If DCBS==1, use A[23];*/ + CC = BITTST(R3, 4); + IF CC R4 = R5; /* R4 now has either bit 14 or bit 23 set.*/ + R5 = R0 & R4; /* Use it to test the Page address*/ + CC = R5; /* and if that bit is set, we use Bank B,*/ + R2 = CC; /* else we use Bank A.*/ + R2 <<= 23; /* The Bank selection's at posn 23.*/ + +bank_chosen: + + /* We can also determine the sub-bank used, because this is + * taken from bits 13:12 of the address. + */ + + R3 = ((12<<8)|2); /* Extraction pattern */ + nop; /*Anamoly 05000209*/ + R4 = EXTRACT(R0, R3.L) (Z); /* Extract bits*/ + /* Save in extraction pattern for later deposit.*/ + R3.H = R4.L << 0; + + /* So: + * R0 = Page start + * R1 = Page length (actually, offset into size/prefix tables) + * R2 = Bank select mask + * R3 = sub-bank deposit values + * + * The cache has 2 Ways, and 64 sets, so we iterate through + * the sets, accessing the tag for each Way, for our Bank and + * sub-bank, looking for dirty, valid tags that match our + * address prefix. + */ + + P5.L = (DTEST_COMMAND & 0xFFFF); + P5.H = (DTEST_COMMAND >> 16); + P4.L = (DTEST_DATA0 & 0xFFFF); + P4.H = (DTEST_DATA0 >> 16); + + P0.L = page_prefix_table; + P0.H = page_prefix_table; + P1 = R1; + R5 = 0; /* Set counter*/ + P0 = P1 + P0; + R4 = [P0]; /* This is the address prefix*/ + + + /* We're reading (bit 1==0) the tag (bit 2==0), and we + * don't care about which double-word, since we're only + * fetching tags, so we only have to set Set, Bank, + * Sub-bank and Way. + */ + + P2 = 2; + LSETUP (fs1, fe1) LC1 = P2; +fs1: P0 = 64; /* iterate over all sets*/ + LSETUP (fs0, fe0) LC0 = P0; +fs0: R6 = R5 << 5; /* Combine set*/ + R6.H = R3.H << 0 ; /* and sub-bank*/ + R6 = R6 | R2; /* and Bank. Leave Way==0 at first.*/ + BITSET(R6,14); + [P5] = R6; /* Issue Command*/ + SSYNC; + R7 = [P4]; /* and read Tag.*/ + CC = BITTST(R7, 0); /* Check if valid*/ + IF !CC JUMP fskip; /* and skip if not.*/ + CC = BITTST(R7, 1); /* Check if dirty*/ + IF !CC JUMP fskip; /* and skip if not.*/ + + /* Compare against the page address. First, plant bits 13:12 + * into the tag, since those aren't part of the returned data. + */ + + R7 = DEPOSIT(R7, R3); /* set 13:12*/ + R1 = R7 & R4; /* Mask off lower bits*/ + CC = R1 == R0; /* Compare against page start.*/ + IF !CC JUMP fskip; /* Skip it if it doesn't match.*/ + + /* Tag address matches against page, so this is an entry + * we must flush. + */ + + R7 >>= 10; /* Mask off the non-address bits*/ + R7 <<= 10; + P3 = R7; + SSYNC; + FLUSHINV [P3]; /* And flush the entry*/ +fskip: +fe0: R5 += 1; /* Advance to next Set*/ +fe1: BITSET(R2, 26); /* Go to next Way.*/ + +dfinished: + SSYNC; /* Ensure the data gets out to mem.*/ + + /*Finished. Restore context.*/ + LB1 = [SP++]; + LT1 = [SP++]; + LC1 = [SP++]; + LB0 = [SP++]; + LT0 = [SP++]; + LC0 = [SP++]; + ( R7:0, P5:0 ) = [SP++]; + RTS; + +dflush_whole_page: + + /* It's a 1K or 4K page, so quicker to just flush the + * entire page. + */ + + P1 = 32; /* For 1K pages*/ + P2 = P1 << 2; /* For 4K pages*/ + P0 = R0; /* Start of page*/ + CC = BITTST(R1, 16); /* Whether 1K or 4K*/ + IF CC P1 = P2; + P1 += -1; /* Unroll one iteration*/ + SSYNC; + FLUSHINV [P0++]; /* because CSYNC can't end loops.*/ + LSETUP (eall, eall) LC0 = P1; +eall: FLUSHINV [P0++]; + SSYNC; + JUMP dfinished; + +.align 4; +page_prefix_table: +.byte4 0xFFFFFC00; /* 1K */ +.byte4 0xFFFFF000; /* 4K */ +.byte4 0xFFF00000; /* 1M */ +.byte4 0xFFC00000; /* 4M */ +.page_prefix_table.end: diff --git a/cpu/bf561/init_sdram.S b/cpu/bf561/init_sdram.S new file mode 100644 index 0000000..d763f27 --- /dev/null +++ b/cpu/bf561/init_sdram.S @@ -0,0 +1,171 @@ +#define ASSEMBLY + +#include <linux/config.h> +#include <config.h> +#include <asm/blackfin.h> +#include <asm/mem_init.h> +.global init_sdram; + +#if (CONFIG_CCLK_DIV == 1) +#define CONFIG_CCLK_ACT_DIV CCLK_DIV1 +#endif +#if (CONFIG_CCLK_DIV == 2) +#define CONFIG_CCLK_ACT_DIV CCLK_DIV2 +#endif +#if (CONFIG_CCLK_DIV == 4) +#define CONFIG_CCLK_ACT_DIV CCLK_DIV4 +#endif +#if (CONFIG_CCLK_DIV == 8) +#define CONFIG_CCLK_ACT_DIV CCLK_DIV8 +#endif +#ifndef CONFIG_CCLK_ACT_DIV +#define CONFIG_CCLK_ACT_DIV CONFIG_CCLK_DIV_not_defined_properly +#endif + +init_sdram: + [--SP] = ASTAT; + [--SP] = RETS; + [--SP] = (R7:0); + [--SP] = (P5:0); + + /* + * PLL_LOCKCNT - how many SCLK Cycles to delay while PLL becomes stable + */ + p0.h = hi(PLL_LOCKCNT); + p0.l = lo(PLL_LOCKCNT); + r0 = 0x300(Z); + w[p0] = r0.l; + ssync; + + /* + * Put SDRAM in self-refresh, incase anything is running + */ + P2.H = hi(EBIU_SDGCTL); + P2.L = lo(EBIU_SDGCTL); + R0 = [P2]; + BITSET (R0, 24); + [P2] = R0; + SSYNC; + + /* + * Set PLL_CTL with the value that we calculate in R0 + * - [14:09] = MSEL[5:0] : CLKIN / VCO multiplication factors + * - [8] = BYPASS : BYPASS the PLL, run CLKIN into CCLK/SCLK + * - [7] = output delay (add 200ps of delay to mem signals) + * - [6] = input delay (add 200ps of input delay to mem signals) + * - [5] = PDWN : 1=All Clocks off + * - [3] = STOPCK : 1=Core Clock off + * - [1] = PLL_OFF : 1=Disable Power to PLL + * - [0] = DF : 1=Pass CLKIN/2 to PLL / 0=Pass CLKIN to PLL + * all other bits set to zero + */ + + r0 = CONFIG_VCO_MULT & 63; /* Load the VCO multiplier */ + r0 = r0 << 9; /* Shift it over, */ + r1 = CONFIG_CLKIN_HALF; /* Do we need to divide CLKIN by 2? */ + r0 = r1 | r0; + r1 = CONFIG_PLL_BYPASS; /* Bypass the PLL? */ + r1 = r1 << 8; /* Shift it over */ + r0 = r1 | r0; /* add them all together */ + + p0.h = hi(PLL_CTL); + p0.l = lo(PLL_CTL); /* Load the address */ + cli r2; /* Disable interrupts */ + ssync; + w[p0] = r0.l; /* Set the value */ + idle; /* Wait for the PLL to stablize */ + sti r2; /* Enable interrupts */ + +check_again: + p0.h = hi(PLL_STAT); + p0.l = lo(PLL_STAT); + R0 = W[P0](Z); + CC = BITTST(R0,5); + if ! CC jump check_again; + + /* Configure SCLK & CCLK Dividers */ + r0 = (CONFIG_CCLK_ACT_DIV | CONFIG_SCLK_DIV); + p0.h = hi(PLL_DIV); + p0.l = lo(PLL_DIV); + w[p0] = r0.l; + ssync; + + /* + * We now are running at speed, time to set the Async mem bank wait states + * This will speed up execution, since we are normally running from FLASH. + */ + + p2.h = (EBIU_AMBCTL1 >> 16); + p2.l = (EBIU_AMBCTL1 & 0xFFFF); + r0.h = (AMBCTL1VAL >> 16); + r0.l = (AMBCTL1VAL & 0xFFFF); + [p2] = r0; + ssync; + + p2.h = (EBIU_AMBCTL0 >> 16); + p2.l = (EBIU_AMBCTL0 & 0xFFFF); + r0.h = (AMBCTL0VAL >> 16); + r0.l = (AMBCTL0VAL & 0xFFFF); + [p2] = r0; + ssync; + + p2.h = (EBIU_AMGCTL >> 16); + p2.l = (EBIU_AMGCTL & 0xffff); + r0 = AMGCTLVAL; + w[p2] = r0; + ssync; + + /* + * Now, Initialize the SDRAM, + * start with the SDRAM Refresh Rate Control Register + */ + p0.l = lo(EBIU_SDRRC); + p0.h = hi(EBIU_SDRRC); + r0 = mem_SDRRC; + w[p0] = r0.l; + ssync; + + /* + * SDRAM Memory Bank Control Register - bank specific parameters + */ + p0.l = (EBIU_SDBCTL & 0xFFFF); + p0.h = (EBIU_SDBCTL >> 16); + r0 = mem_SDBCTL; + w[p0] = r0.l; + ssync; + + /* + * SDRAM Global Control Register - global programmable parameters + * Disable self-refresh + */ + P2.H = hi(EBIU_SDGCTL); + P2.L = lo(EBIU_SDGCTL); + R0 = [P2]; + BITCLR (R0, 24); + + /* + * Check if SDRAM is already powered up, if it is, enable self-refresh + */ + p0.h = hi(EBIU_SDSTAT); + p0.l = lo(EBIU_SDSTAT); + r2.l = w[p0]; + cc = bittst(r2,3); + if !cc jump skip; + NOP; + BITSET (R0, 23); +skip: + [P2] = R0; + SSYNC; + + /* Write in the new value in the register */ + R0.L = lo(mem_SDGCTL); + R0.H = hi(mem_SDGCTL); + [P2] = R0; + SSYNC; + nop; + + (P5:0) = [SP++]; + (R7:0) = [SP++]; + RETS = [SP++]; + ASTAT = [SP++]; + RTS; diff --git a/cpu/bf561/init_sdram_bootrom_initblock.S b/cpu/bf561/init_sdram_bootrom_initblock.S new file mode 100644 index 0000000..5e3c88a --- /dev/null +++ b/cpu/bf561/init_sdram_bootrom_initblock.S @@ -0,0 +1,185 @@ +#define ASSEMBLY + +#include <linux/config.h> +#include <config.h> +#include <asm/blackfin.h> +#include <asm/mem_init.h> +.global init_sdram; + +#if (CONFIG_CCLK_DIV == 1) +#define CONFIG_CCLK_ACT_DIV CCLK_DIV1 +#endif +#if (CONFIG_CCLK_DIV == 2) +#define CONFIG_CCLK_ACT_DIV CCLK_DIV2 +#endif +#if (CONFIG_CCLK_DIV == 4) +#define CONFIG_CCLK_ACT_DIV CCLK_DIV4 +#endif +#if (CONFIG_CCLK_DIV == 8) +#define CONFIG_CCLK_ACT_DIV CCLK_DIV8 +#endif +#ifndef CONFIG_CCLK_ACT_DIV +#define CONFIG_CCLK_ACT_DIV CONFIG_CCLK_DIV_not_defined_properly +#endif + +init_sdram: + [--SP] = ASTAT; + [--SP] = RETS; + [--SP] = (R7:0); + [--SP] = (P5:0); + + + p0.h = hi(SICA_IWR0); + p0.l = lo(SICA_IWR0); + r0.l = 0x1; + w[p0] = r0.l; + SSYNC; + + p0.h = hi(SPI_BAUD); + p0.l = lo(SPI_BAUD); + r0.l = CONFIG_SPI_BAUD_INITBLOCK; + w[p0] = r0.l; + SSYNC; + + /* + * PLL_LOCKCNT - how many SCLK Cycles to delay while PLL becomes stable + */ + p0.h = hi(PLL_LOCKCNT); + p0.l = lo(PLL_LOCKCNT); + r0 = 0x300(Z); + w[p0] = r0.l; + ssync; + + /* + * Put SDRAM in self-refresh, incase anything is running + */ + P2.H = hi(EBIU_SDGCTL); + P2.L = lo(EBIU_SDGCTL); + R0 = [P2]; + BITSET (R0, 24); + [P2] = R0; + SSYNC; + + /* + * Set PLL_CTL with the value that we calculate in R0 + * - [14:09] = MSEL[5:0] : CLKIN / VCO multiplication factors + * - [8] = BYPASS : BYPASS the PLL, run CLKIN into CCLK/SCLK + * - [7] = output delay (add 200ps of delay to mem signals) + * - [6] = input delay (add 200ps of input delay to mem signals) + * - [5] = PDWN : 1=All Clocks off + * - [3] = STOPCK : 1=Core Clock off + * - [1] = PLL_OFF : 1=Disable Power to PLL + * - [0] = DF : 1=Pass CLKIN/2 to PLL / 0=Pass CLKIN to PLL + * all other bits set to zero + */ + + r0 = CONFIG_VCO_MULT & 63; /* Load the VCO multiplier */ + r0 = r0 << 9; /* Shift it over, */ + r1 = CONFIG_CLKIN_HALF; /* Do we need to divide CLKIN by 2? */ + r0 = r1 | r0; + r1 = CONFIG_PLL_BYPASS; /* Bypass the PLL? */ + r1 = r1 << 8; /* Shift it over */ + r0 = r1 | r0; /* add them all together */ + + p0.h = hi(PLL_CTL); + p0.l = lo(PLL_CTL); /* Load the address */ + cli r2; /* Disable interrupts */ + ssync; + w[p0] = r0.l; /* Set the value */ + idle; /* Wait for the PLL to stablize */ + sti r2; /* Enable interrupts */ + +check_again: + p0.h = hi(PLL_STAT); + p0.l = lo(PLL_STAT); + R0 = W[P0](Z); + CC = BITTST(R0,5); + if ! CC jump check_again; + + /* Configure SCLK & CCLK Dividers */ + r0 = (CONFIG_CCLK_ACT_DIV | CONFIG_SCLK_DIV); + p0.h = hi(PLL_DIV); + p0.l = lo(PLL_DIV); + w[p0] = r0.l; + ssync; + + /* + * We now are running at speed, time to set the Async mem bank wait states + * This will speed up execution, since we are normally running from FLASH. + */ + + p2.h = (EBIU_AMBCTL1 >> 16); + p2.l = (EBIU_AMBCTL1 & 0xFFFF); + r0.h = (AMBCTL1VAL >> 16); + r0.l = (AMBCTL1VAL & 0xFFFF); + [p2] = r0; + ssync; + + p2.h = (EBIU_AMBCTL0 >> 16); + p2.l = (EBIU_AMBCTL0 & 0xFFFF); + r0.h = (AMBCTL0VAL >> 16); + r0.l = (AMBCTL0VAL & 0xFFFF); + [p2] = r0; + ssync; + + p2.h = (EBIU_AMGCTL >> 16); + p2.l = (EBIU_AMGCTL & 0xffff); + r0 = AMGCTLVAL; + w[p2] = r0; + ssync; + + /* + * Now, Initialize the SDRAM, + * start with the SDRAM Refresh Rate Control Register + */ + p0.l = lo(EBIU_SDRRC); + p0.h = hi(EBIU_SDRRC); + r0 = mem_SDRRC; + w[p0] = r0.l; + ssync; + + /* + * SDRAM Memory Bank Control Register - bank specific parameters + */ + p0.l = (EBIU_SDBCTL & 0xFFFF); + p0.h = (EBIU_SDBCTL >> 16); + r0 = mem_SDBCTL; + w[p0] = r0.l; + ssync; + + /* + * SDRAM Global Control Register - global programmable parameters + * Disable self-refresh + */ + P2.H = hi(EBIU_SDGCTL); + P2.L = lo(EBIU_SDGCTL); + R0 = [P2]; + BITCLR (R0, 24); + + /* + * Check if SDRAM is already powered up, if it is, enable self-refresh + */ + p0.h = hi(EBIU_SDSTAT); + p0.l = lo(EBIU_SDSTAT); + r2.l = w[p0]; + cc = bittst(r2,3); + if !cc jump skip; + NOP; + BITSET (R0, 23); +skip: + [P2] = R0; + SSYNC; + + /* Write in the new value in the register */ + R0.L = lo(mem_SDGCTL); + R0.H = hi(mem_SDGCTL); + [P2] = R0; + SSYNC; + nop; + + + (P5:0) = [SP++]; + (R7:0) = [SP++]; + RETS = [SP++]; + ASTAT = [SP++]; + RTS; diff --git a/cpu/bf561/interrupt.S b/cpu/bf561/interrupt.S new file mode 100644 index 0000000..f82fd9b --- /dev/null +++ b/cpu/bf561/interrupt.S @@ -0,0 +1,246 @@ +/* + * U-boot - interrupt.S Processing of interrupts and exception handling + * + * Copyright (c) 2005 blackfin.uclinux.org + * + * (C) Copyright 2000-2004 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * This file is based on interrupt.S + * + * Copyright (C) 2003 Metrowerks, Inc. <mwaddel@metrowerks.com> + * Copyright (C) 2002 Arcturus Networks Ltd. Ted Ma <mated@sympatico.ca> + * Copyright (C) 1998 D. Jeff Dionne <jeff@ryeham.ee.ryerson.ca>, + * Kenneth Albanowski <kjahds@kjahds.com>, + * The Silver Hammer Group, Ltd. + * + * (c) 1995, Dionne & Associates + * (c) 1995, DKG Display Tech. + * + * This file is also based on exception.asm + * (C) Copyright 2001-2005 - Analog Devices, Inc. All rights reserved. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#define ASSEMBLY +#include <config.h> +#include <asm/blackfin.h> +#include <asm/hw_irq.h> +#include <asm/entry.h> +#include <asm/blackfin_defs.h> + +.global _blackfin_irq_panic; + +.text +.align 2 + +#ifndef CONFIG_KGDB +.global _evt_emulation +_evt_emulation: + SAVE_CONTEXT + r0 = IRQ_EMU; + r1 = seqstat; + sp += -12; + call _blackfin_irq_panic; + sp += 12; + rte; +#endif + +.global _evt_nmi +_evt_nmi: + SAVE_CONTEXT + r0 = IRQ_NMI; + r1 = RETN; + sp += -12; + call _blackfin_irq_panic; + sp += 12; + +_evt_nmi_exit: + rtn; + +.global _trap +_trap: + SAVE_ALL_SYS + r0 = sp; /* stack frame pt_regs pointer argument ==> r0 */ + sp += -12; + call _trap_c + sp += 12; + RESTORE_ALL_SYS + rtx; + +.global _evt_rst +_evt_rst: + SAVE_CONTEXT + r0 = IRQ_RST; + r1 = RETN; + sp += -12; + call _do_reset; + sp += 12; + +_evt_rst_exit: + rtn; + +irq_panic: + r0 = IRQ_EVX; + r1 = sp; + sp += -12; + call _blackfin_irq_panic; + sp += 12; + +.global _evt_ivhw +_evt_ivhw: + SAVE_CONTEXT + RAISE 14; + +_evt_ivhw_exit: + rti; + +.global _evt_timer +_evt_timer: + SAVE_CONTEXT + r0 = IRQ_CORETMR; + sp += -12; + /* Polling method used now. */ + /* call timer_int; */ + sp += 12; + RESTORE_CONTEXT + rti; + nop; + +.global _evt_evt7 +_evt_evt7: + SAVE_CONTEXT + r0 = 7; + sp += -12; + call _process_int; + sp += 12; + +evt_evt7_exit: + RESTORE_CONTEXT + rti; + +.global _evt_evt8 +_evt_evt8: + SAVE_CONTEXT + r0 = 8; + sp += -12; + call _process_int; + sp += 12; + +evt_evt8_exit: + RESTORE_CONTEXT + rti; + +.global _evt_evt9 +_evt_evt9: + SAVE_CONTEXT + r0 = 9; + sp += -12; + call _process_int; + sp += 12; + +evt_evt9_exit: + RESTORE_CONTEXT + rti; + +.global _evt_evt10 +_evt_evt10: + SAVE_CONTEXT + r0 = 10; + sp += -12; + call _process_int; + sp += 12; + +evt_evt10_exit: + RESTORE_CONTEXT + rti; + +.global _evt_evt11 +_evt_evt11: + SAVE_CONTEXT + r0 = 11; + sp += -12; + call _process_int; + sp += 12; + +evt_evt11_exit: + RESTORE_CONTEXT + rti; + +.global _evt_evt12 +_evt_evt12: + SAVE_CONTEXT + r0 = 12; + sp += -12; + call _process_int; + sp += 12; +evt_evt12_exit: + RESTORE_CONTEXT + rti; + +.global _evt_evt13 +_evt_evt13: + SAVE_CONTEXT + r0 = 13; + sp += -12; + call _process_int; + sp += 12; + +evt_evt13_exit: + RESTORE_CONTEXT + rti; + +.global _evt_system_call +_evt_system_call: + [--sp] = r0; + [--SP] = RETI; + r0 = [sp++]; + r0 += 2; + [--sp] = r0; + RETI = [SP++]; + r0 = [SP++]; + SAVE_CONTEXT + sp += -12; + call _exception_handle; + sp += 12; + RESTORE_CONTEXT + RTI; + +evt_system_call_exit: + rti; + +.global _evt_soft_int1 +_evt_soft_int1: + [--sp] = r0; + [--SP] = RETI; + r0 = [sp++]; + r0 += 2; + [--sp] = r0; + RETI = [SP++]; + r0 = [SP++]; + SAVE_CONTEXT + sp += -12; + call _exception_handle; + sp += 12; + RESTORE_CONTEXT + RTI; + +evt_soft_int1_exit: + rti; diff --git a/cpu/bf561/interrupts.c b/cpu/bf561/interrupts.c new file mode 100644 index 0000000..e314f60 --- /dev/null +++ b/cpu/bf561/interrupts.c @@ -0,0 +1,171 @@ +/* + * U-boot - interrupts.c Interrupt related routines + * + * Copyright (c) 2005 blackfin.uclinux.org + * + * This file is based on interrupts.c + * Copyright 1996 Roman Zippel + * Copyright 1999 D. Jeff Dionne <jeff@uclinux.org> + * Copyright 2000-2001 Lineo, Inc. D. Jefff Dionne <jeff@lineo.ca> + * Copyright 2002 Arcturus Networks Inc. MaTed <mated@sympatico.ca> + * Copyright 2003 Metrowerks/Motorola + * Copyright 2003 Bas Vermeulen <bas@buyways.nl>, + * BuyWays B.V. (www.buyways.nl) + * + * (C) Copyright 2000-2004 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <asm/machdep.h> +#include <asm/irq.h> +#include <config.h> +#include <asm/blackfin.h> +#include "cpu.h" + +static ulong timestamp; +static ulong last_time; +static int int_flag; + +int irq_flags; /* needed by asm-blackfin/system.h */ + +/* Functions just to satisfy the linker */ + +/* + * This function is derived from PowerPC code (read timebase as long long). + * On BF561 it just returns the timer value. + */ +unsigned long long get_ticks(void) +{ + return get_timer(0); +} + +/* + * This function is derived from PowerPC code (timebase clock frequency). + * On BF561 it returns the number of timer ticks per second. + */ +ulong get_tbclk(void) +{ + ulong tbclk; + + tbclk = CFG_HZ; + return tbclk; +} + +void enable_interrupts(void) +{ + restore_flags(int_flag); +} + +int disable_interrupts(void) +{ + save_and_cli(int_flag); + return 1; +} + +int interrupt_init(void) +{ + return (0); +} + +void udelay(unsigned long usec) +{ + unsigned long delay, start, stop; + unsigned long cclk; + cclk = (CONFIG_CCLK_HZ); + + while (usec > 1) { + /* + * how many clock ticks to delay? + * - request(in useconds) * clock_ticks(Hz) / useconds/second + */ + if (usec < 1000) { + delay = (usec * (cclk / 244)) >> 12; + usec = 0; + } else { + delay = (1000 * (cclk / 244)) >> 12; + usec -= 1000; + } + + asm volatile (" %0 = CYCLES;":"=r" (start)); + do { + asm volatile (" %0 = CYCLES; ":"=r" (stop)); + } while (stop - start < delay); + } + + return; +} + +void timer_init(void) +{ + *pTCNTL = 0x1; + *pTSCALE = 0x0; + *pTCOUNT = MAX_TIM_LOAD; + *pTPERIOD = MAX_TIM_LOAD; + *pTCNTL = 0x7; + asm("CSYNC;"); + + timestamp = 0; + last_time = 0; +} + +/* + * Any network command or flash + * command is started get_timer shall + * be called before TCOUNT gets reset, + * to implement the accurate timeouts. + * + * How ever milliconds doesn't return + * the number that has been elapsed from + * the last reset. + * + * As get_timer is used in the u-boot + * only for timeouts this should be + * sufficient + */ +ulong get_timer(ulong base) +{ + ulong milisec; + + /* Number of clocks elapsed */ + ulong clocks = (MAX_TIM_LOAD - (*pTCOUNT)); + + /* + * Find if the TCOUNT is reset + * timestamp gives the number of times + * TCOUNT got reset + */ + if (clocks < last_time) + timestamp++; + last_time = clocks; + + /* Get the number of milliseconds */ + milisec = clocks / (CONFIG_CCLK_HZ / 1000); + + /* + * Find the number of millisonds + * that got elapsed before this TCOUNT + * cycle + */ + milisec += timestamp * (MAX_TIM_LOAD / (CONFIG_CCLK_HZ / 1000)); + + return (milisec - base); +} diff --git a/cpu/bf561/ints.c b/cpu/bf561/ints.c new file mode 100644 index 0000000..328e5d8 --- /dev/null +++ b/cpu/bf561/ints.c @@ -0,0 +1,117 @@ +/* + * U-boot - ints.c Interrupt related routines + * + * Copyright (c) 2005 blackfin.uclinux.org + * + * This file is based on ints.c + * + * Apr18 2003, Changed by HuTao to support interrupt cascading for Blackfin + * drivers + * + * Copyright 1996 Roman Zippel + * Copyright 1999 D. Jeff Dionne <jeff@uclinux.org> + * Copyright 2000-2001 Lineo, Inc. D. Jefff Dionne <jeff@lineo.ca> + * Copyright 2002 Arcturus Networks Inc. MaTed <mated@sympatico.ca> + * Copyright 2003 Metrowerks/Motorola + * + * (C) Copyright 2000-2004 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <linux/stddef.h> +#include <asm/system.h> +#include <asm/irq.h> +#include <asm/traps.h> +#include <asm/io.h> +#include <asm/errno.h> +#include <asm/machdep.h> +#include <asm/setup.h> +#include <asm/blackfin.h> +#include "cpu.h" + +void blackfin_irq_panic(int reason, struct pt_regs *regs) +{ + printf("\n\nException: IRQ 0x%x entered\n", reason); + printf("code=[0x%x], ", (unsigned int)(regs->seqstat & 0x3f)); + printf("stack frame=0x%x, ", (unsigned int)regs); + printf("bad PC=0x%04x\n", (unsigned int)regs->pc); + dump(regs); + printf("Unhandled IRQ or exceptions!\n"); + printf("Please reset the board \n"); +} + +void blackfin_init_IRQ(void) +{ + *(unsigned volatile long *)(SIC_IMASK) = SIC_UNMASK_ALL; + cli(); +#ifndef CONFIG_KGDB + *(unsigned volatile long *)(EVT_EMULATION_ADDR) = 0x0; +#endif + *(unsigned volatile long *)(EVT_NMI_ADDR) = + (unsigned volatile long)evt_nmi; + *(unsigned volatile long *)(EVT_EXCEPTION_ADDR) = + (unsigned volatile long)trap; + *(unsigned volatile long *)(EVT_HARDWARE_ERROR_ADDR) = + (unsigned volatile long)evt_ivhw; + *(unsigned volatile long *)(EVT_RESET_ADDR) = + (unsigned volatile long)evt_rst; + *(unsigned volatile long *)(EVT_TIMER_ADDR) = + (unsigned volatile long)evt_timer; + *(unsigned volatile long *)(EVT_IVG7_ADDR) = + (unsigned volatile long)evt_evt7; + *(unsigned volatile long *)(EVT_IVG8_ADDR) = + (unsigned volatile long)evt_evt8; + *(unsigned volatile long *)(EVT_IVG9_ADDR) = + (unsigned volatile long)evt_evt9; + *(unsigned volatile long *)(EVT_IVG10_ADDR) = + (unsigned volatile long)evt_evt10; + *(unsigned volatile long *)(EVT_IVG11_ADDR) = + (unsigned volatile long)evt_evt11; + *(unsigned volatile long *)(EVT_IVG12_ADDR) = + (unsigned volatile long)evt_evt12; + *(unsigned volatile long *)(EVT_IVG13_ADDR) = + (unsigned volatile long)evt_evt13; + *(unsigned volatile long *)(EVT_IVG14_ADDR) = + (unsigned volatile long)evt_system_call; + *(unsigned volatile long *)(EVT_IVG15_ADDR) = + (unsigned volatile long)evt_soft_int1; + *(volatile unsigned long *)ILAT = 0; + asm("csync;"); + sti(); + *(volatile unsigned long *)IMASK = 0xffbf; + asm("csync;"); +} + +void exception_handle(void) +{ +#if defined (CONFIG_PANIC_HANG) + display_excp(); +#else + udelay(100000); /* allow messages to go out */ + do_reset(NULL, 0, 0, NULL); +#endif +} + +void display_excp(void) +{ + printf("Exception!\n"); +} diff --git a/cpu/bf561/serial.c b/cpu/bf561/serial.c new file mode 100644 index 0000000..baec1d3 --- /dev/null +++ b/cpu/bf561/serial.c @@ -0,0 +1,196 @@ +/* + * U-boot - serial.c Serial driver for BF561 + * + * Copyright (c) 2005 blackfin.uclinux.org + * + * This file is based on + * bf533_serial.c: Serial driver for BlackFin BF533 DSP internal UART. + * Copyright (c) 2003 Bas Vermeulen <bas@buyways.nl>, + * BuyWays B.V. (www.buyways.nl) + * + * Based heavily on blkfinserial.c + * blkfinserial.c: Serial driver for BlackFin DSP internal USRTs. + * Copyright(c) 2003 Metrowerks <mwaddel@metrowerks.com> + * Copyright(c) 2001 Tony Z. Kou <tonyko@arcturusnetworks.com> + * Copyright(c) 2001-2002 Arcturus Networks Inc. <www.arcturusnetworks.com> + * + * Based on code from 68328 version serial driver imlpementation which was: + * Copyright (C) 1995 David S. Miller <davem@caip.rutgers.edu> + * Copyright (C) 1998 Kenneth Albanowski <kjahds@kjahds.com> + * Copyright (C) 1998, 1999 D. Jeff Dionne <jeff@uclinux.org> + * Copyright (C) 1999 Vladimir Gurevich <vgurevic@cisco.com> + * + * (C) Copyright 2000-2004 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <asm/irq.h> +#include <asm/system.h> +#include <asm/segment.h> +#include <asm/bitops.h> +#include <asm/delay.h> +#include <asm/uaccess.h> +#include "serial.h" +#include <asm/io.h> + +unsigned long pll_div_fact; + +void calc_baud(void) +{ + unsigned char i; + int temp; + u_long sclk = get_sclk(); + + for (i = 0; i < sizeof(baud_table) / sizeof(int); i++) { + temp = sclk / (baud_table[i] * 8); + if ((temp & 0x1) == 1) { + temp++; + } + temp = temp / 2; + hw_baud_table[i].dl_high = (temp >> 8) & 0xFF; + hw_baud_table[i].dl_low = (temp) & 0xFF; + } +} + +void serial_setbrg(void) +{ + int i; + DECLARE_GLOBAL_DATA_PTR; + + calc_baud(); + + for (i = 0; i < sizeof(baud_table) / sizeof(int); i++) { + if (gd->baudrate == baud_table[i]) + break; + } + + /* Enable UART */ + *pUART_GCTL |= UART_GCTL_UCEN; + sync(); + + /* Set DLAB in LCR to Access DLL and DLH */ + ACCESS_LATCH; + sync(); + + *pUART_DLL = hw_baud_table[i].dl_low; + sync(); + *pUART_DLH = hw_baud_table[i].dl_high; + sync(); + + /* Clear DLAB in LCR to Access THR RBR IER */ + ACCESS_PORT_IER; + sync(); + + /* + * Enable ERBFI and ELSI interrupts + * to poll SIC_ISR register + */ + *pUART_IER = UART_IER_ELSI | UART_IER_ERBFI | UART_IER_ETBEI; + sync(); + + /* Set LCR to Word Lengh 8-bit word select */ + *pUART_LCR = UART_LCR_WLS8; + sync(); + + return; +} + +int serial_init(void) +{ + serial_setbrg(); + return (0); +} + +void serial_putc(const char c) +{ + if ((*pUART_LSR) & UART_LSR_TEMT) { + if (c == '\n') + serial_putc('\r'); + + local_put_char(c); + } + + while (!((*pUART_LSR) & UART_LSR_TEMT)) + SYNC_ALL; + + return; +} + +int serial_tstc(void) +{ + if (*pUART_LSR & UART_LSR_DR) + return 1; + else + return 0; +} + +int serial_getc(void) +{ + unsigned short uart_lsr_val, uart_rbr_val; + unsigned long isr_val; + int ret; + + /* Poll for RX Interrupt */ + while (!((isr_val = + *(volatile unsigned long *)SIC_ISR) & IRQ_UART_RX_BIT)) ; + asm("csync;"); + + uart_lsr_val = *pUART_LSR; /* Clear status bit */ + uart_rbr_val = *pUART_RBR; /* getc() */ + + if (isr_val & IRQ_UART_ERROR_BIT) { + ret = -1; + } else { + ret = uart_rbr_val & 0xff; + } + + return ret; +} + +void serial_puts(const char *s) +{ + while (*s) { + serial_putc(*s++); + } +} + +static void local_put_char(char ch) +{ + int flags = 0; + unsigned long isr_val; + + save_and_cli(flags); + + /* Poll for TX Interruput */ + while (!((isr_val = *pSIC_ISR) & IRQ_UART_TX_BIT)) ; + asm("csync;"); + + *pUART_THR = ch; /* putc() */ + + if (isr_val & IRQ_UART_ERROR_BIT) { + printf("?"); + } + + restore_flags(flags); + + return; +} diff --git a/cpu/bf561/serial.h b/cpu/bf561/serial.h new file mode 100644 index 0000000..98c1242 --- /dev/null +++ b/cpu/bf561/serial.h @@ -0,0 +1,77 @@ +/* + * U-boot - bf561_serial.h Serial Driver defines + * + * Copyright (c) 2005 blackfin.uclinux.org + * + * This file is based on + * bf533_serial.h: Definitions for the BlackFin BF533 DSP serial driver. + * Copyright (C) 2003 Bas Vermeulen <bas@buyways.nl> + * BuyWays B.V. (www.buyways.nl) + * + * Based heavily on: + * blkfinserial.h: Definitions for the BlackFin DSP serial driver. + * + * Copyright (C) 2001 Tony Z. Kou tonyko@arcturusnetworks.com + * Copyright (C) 2001 Arcturus Networks Inc. <www.arcturusnetworks.com> + * + * Based on code from 68328serial.c which was: + * Copyright (C) 1995 David S. Miller <davem@caip.rutgers.edu> + * Copyright (C) 1998 Kenneth Albanowski <kjahds@kjahds.com> + * Copyright (C) 1998, 1999 D. Jeff Dionne <jeff@uclinux.org> + * Copyright (C) 1999 Vladimir Gurevich <vgurevic@cisco.com> + * + * (C) Copyright 2000-2004 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _Bf561_SERIAL_H +#define _Bf561_SERIAL_H + +#include <linux/config.h> +#include <asm/blackfin.h> + +#define SYNC_ALL __asm__ __volatile__ ("ssync;\n") +#define ACCESS_LATCH *pUART_LCR |= UART_LCR_DLAB; +#define ACCESS_PORT_IER *pUART_LCR &= (~UART_LCR_DLAB); + +void serial_setbrg(void); +static void local_put_char(char ch); +void calc_baud(void); +void serial_setbrg(void); +int serial_init(void); +void serial_putc(const char c); +int serial_tstc(void); +int serial_getc(void); +void serial_puts(const char *s); +static void local_put_char(char ch); + +int baud_table[5] = { 9600, 19200, 38400, 57600, 115200 }; + +struct { + unsigned char dl_high; + unsigned char dl_low; +} hw_baud_table[5]; + +#ifdef CONFIG_STAMP +extern unsigned long pll_div_fact; +#endif + +#endif diff --git a/cpu/bf561/start.S b/cpu/bf561/start.S new file mode 100644 index 0000000..9333648 --- /dev/null +++ b/cpu/bf561/start.S @@ -0,0 +1,311 @@ +/* + * U-boot - start.S Startup file of u-boot for BF533/BF561 + * + * Copyright (c) 2005 blackfin.uclinux.org + * + * This file is based on head.S + * Copyright (c) 2003 Metrowerks/Motorola + * Copyright (C) 1998 D. Jeff Dionne <jeff@ryeham.ee.ryerson.ca>, + * Kenneth Albanowski <kjahds@kjahds.com>, + * The Silver Hammer Group, Ltd. + * (c) 1995, Dionne & Associates + * (c) 1995, DKG Display Tech. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * Note: A change in this file subsequently requires a change in + * board/$(board_name)/config.mk for a valid u-boot.bin + */ + +#define ASSEMBLY + +#include <linux/config.h> +#include <config.h> +#include <asm/blackfin.h> + +.global _stext; +.global __bss_start; +.global start; +.global _start; +.global _rambase; +.global _ramstart; +.global _ramend; +.global edata; +.global _initialize; +.global _exit; +.global flashdataend; +.global init_sdram; + +.text +_start: +start: +_stext: + + R0 = 0x32; + SYSCFG = R0; + SSYNC; + + /* + * As per HW reference manual DAG registers, + * DATA and Address resgister shall be zero'd + * in initialization, after a reset state + */ + r1 = 0; /* Data registers zero'd */ + r2 = 0; + r3 = 0; + r4 = 0; + r5 = 0; + r6 = 0; + r7 = 0; + + p0 = 0; /* Address registers zero'd */ + p1 = 0; + p2 = 0; + p3 = 0; + p4 = 0; + p5 = 0; + + i0 = 0; /* DAG Registers zero'd */ + i1 = 0; + i2 = 0; + i3 = 0; + m0 = 0; + m1 = 0; + m3 = 0; + m3 = 0; + l0 = 0; + l1 = 0; + l2 = 0; + l3 = 0; + b0 = 0; + b1 = 0; + b2 = 0; + b3 = 0; + + /* + * Set loop counters to zero, to make sure that + * hw loops are disabled. + */ + r0 = 0; + lc0 = r0; + lc1 = r0; + + SSYNC; + + /* Check soft reset status */ + p0.h = SWRST >> 16; + p0.l = SWRST & 0xFFFF; + r0.l = w[p0]; + + cc = bittst(r0, 15); + if !cc jump no_soft_reset; + + /* Clear Soft reset */ + r0 = 0x0000; + w[p0] = r0; + ssync; + +no_soft_reset: + nop; + + /* Clear EVT registers */ + p0.h = (EVT_EMULATION_ADDR >> 16); + p0.l = (EVT_EMULATION_ADDR & 0xFFFF); + p0 += 8; + p1 = 14; + r1 = 0; + LSETUP(4,4) lc0 = p1; + [ p0 ++ ] = r1; + + p0.h = hi(SIC_IWR); + p0.l = lo(SIC_IWR); + r0.l = 0x1; + w[p0] = r0.l; + SSYNC; + + sp.l = (0xffb01000 & 0xFFFF); + sp.h = (0xffb01000 >> 16); + + /* + * Check if the code is in SDRAM + * If the code is in SDRAM, skip SDRAM initializaiton + */ + call get_pc; + r3.l = 0x0; + r3.h = 0x2000; + cc = r0 < r3 (iu); + if cc jump sdram_initialized; + call init_sdram; + /* relocate into to RAM */ +sdram_initialized: + call get_pc; +offset: + r2.l = offset; + r2.h = offset; + r3.l = start; + r3.h = start; + r1 = r2 - r3; + + r0 = r0 - r1; + p1 = r0; + + p2.l = (CFG_MONITOR_BASE & 0xffff); + p2.h = (CFG_MONITOR_BASE >> 16); + + p3 = 0x04; + p4.l = ((CFG_MONITOR_BASE + CFG_MONITOR_LEN) & 0xffff); + p4.h = ((CFG_MONITOR_BASE + CFG_MONITOR_LEN) >> 16); +loop1: + r1 = [p1 ++ p3]; + [p2 ++ p3] = r1; + cc=p2==p4; + if !cc jump loop1; + /* + * configure STACK + */ + r0.h = (CONFIG_STACKBASE >> 16); + r0.l = (CONFIG_STACKBASE & 0xFFFF); + sp = r0; + fp = sp; + + /* + * This next section keeps the processor in supervisor mode + * during kernel boot. Switches to user mode at end of boot. + * See page 3-9 of Hardware Reference manual for documentation. + */ + + /* To keep ourselves in the supervisor mode */ + p0.l = (EVT_IVG15_ADDR & 0xFFFF); + p0.h = (EVT_IVG15_ADDR >> 16); + + p1.l = _real_start; + p1.h = _real_start; + [p0] = p1; + + p0.l = (IMASK & 0xFFFF); + p0.h = (IMASK >> 16); + r0.l = LO(IVG15_POS); + r0.h = HI(IVG15_POS); + [p0] = r0; + raise 15; + p0.l = WAIT_HERE; + p0.h = WAIT_HERE; + reti = p0; + rti; + +WAIT_HERE: + jump WAIT_HERE; + +.global _real_start; +_real_start: + [ -- sp ] = reti; + +#ifdef CONFIG_EZKIT561 + p0.l = (WDOG_CTL & 0xFFFF); + p0.h = (WDOG_CTL >> 16); + r0 = WATCHDOG_DISABLE(z); + w[p0] = r0; +#endif + + /* DMA reset code to Hi of L1 SRAM */ +copy: + P1.H = hi(SYSMMR_BASE); /* P1 Points to the beginning of SYSTEM MMR Space */ + P1.L = lo(SYSMMR_BASE); + + R0.H = reset_start; /* Source Address (high) */ + R0.L = reset_start; /* Source Address (low) */ + R1.H = reset_end; + R1.L = reset_end; + R2 = R1 - R0; /* Count */ + R1.H = hi(L1_ISRAM); /* Destination Address (high) */ + R1.L = lo(L1_ISRAM); /* Destination Address (low) */ + R3.L = DMAEN; /* Source DMAConfig Value (8-bit words) */ + R4.L = (DI_EN | WNR | DMAEN); /* Destination DMAConfig Value (8-bit words) */ + +DMA: + R6 = 0x1 (Z); + W[P1+OFFSET_(MDMA_S0_X_MODIFY)] = R6; /* Source Modify = 1 */ + W[P1+OFFSET_(MDMA_D0_X_MODIFY)] = R6; /* Destination Modify = 1 */ + + [P1+OFFSET_(MDMA_S0_START_ADDR)] = R0; /* Set Source Base Address */ + W[P1+OFFSET_(MDMA_S0_X_COUNT)] = R2; /* Set Source Count */ + /* Set Source DMAConfig = DMA Enable, + Memory Read, 8-Bit Transfers, 1-D DMA, Flow - Stop */ + W[P1+OFFSET_(MDMA_S0_CONFIG)] = R3; + + [P1+OFFSET_(MDMA_D0_START_ADDR)] = R1; /* Set Destination Base Address */ + W[P1+OFFSET_(MDMA_D0_X_COUNT)] = R2; /* Set Destination Count */ + /* Set Destination DMAConfig = DMA Enable, + Memory Write, 8-Bit Transfers, 1-D DMA, Flow - Stop, IOC */ + W[P1+OFFSET_(MDMA_D0_CONFIG)] = R4; + +WAIT_DMA_DONE: + p0.h = hi(MDMA_D0_IRQ_STATUS); + p0.l = lo(MDMA_D0_IRQ_STATUS); + R0 = W[P0](Z); + CC = BITTST(R0, 0); + if ! CC jump WAIT_DMA_DONE + + R0 = 0x1; + W[P1+OFFSET_(MDMA_D0_IRQ_STATUS)] = R0; /* Write 1 to clear DMA interrupt */ + + /* Initialize BSS Section with 0 s */ + p1.l = __bss_start; + p1.h = __bss_start; + p2.l = _end; + p2.h = _end; + r1 = p1; + r2 = p2; + r3 = r2 - r1; + r3 = r3 >> 2; + p3 = r3; + lsetup (_clear_bss, _clear_bss_end ) lc1 = p3; + CC = p2<=p1; + if CC jump _clear_bss_skip; + r0 = 0; +_clear_bss: +_clear_bss_end: + [p1++] = r0; +_clear_bss_skip: + + p0.l = _start1; + p0.h = _start1; + jump (p0); + +reset_start: + p0.h = WDOG_CNT >> 16; + p0.l = WDOG_CNT & 0xffff; + r0 = 0x0010; + w[p0] = r0; + p0.h = WDOG_CTL >> 16; + p0.l = WDOG_CTL & 0xffff; + r0 = 0x0000; + w[p0] = r0; +reset_wait: + jump reset_wait; + +reset_end: nop; + +_exit: + jump.s _exit; +get_pc: + r0 = rets; + rts; diff --git a/cpu/bf561/start1.S b/cpu/bf561/start1.S new file mode 100644 index 0000000..72cfafb --- /dev/null +++ b/cpu/bf561/start1.S @@ -0,0 +1,38 @@ +/* + * U-boot - start1.S Code running out of RAM after relocation + * + * Copyright (c) 2005 blackfin.uclinux.org + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#define ASSEMBLY +#include <linux/config.h> +#include <config.h> +#include <asm/blackfin.h> + +.global start1; +.global _start1; + +.text +_start1: +start1: + sp += -12; + call _board_init_f; + sp += 12; diff --git a/cpu/bf561/traps.c b/cpu/bf561/traps.c new file mode 100644 index 0000000..f5ff3a8 --- /dev/null +++ b/cpu/bf561/traps.c @@ -0,0 +1,239 @@ +/* + * U-boot - traps.c Routines related to interrupts and exceptions + * + * Copyright (c) 2005 blackfin.uclinux.org + * + * This file is based on + * No original Copyright holder listed, + * Probabily original (C) Roman Zippel (assigned DJD, 1999) + * + * Copyright 2003 Metrowerks - for Blackfin + * Copyright 2000-2001 Lineo, Inc. D. Jeff Dionne <jeff@lineo.ca> + * Copyright 1999-2000 D. Jeff Dionne, <jeff@uclinux.org> + * + * (C) Copyright 2000-2004 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <linux/types.h> +#include <asm/errno.h> +#include <asm/irq.h> +#include <asm/system.h> +#include <asm/traps.h> +#include <asm/machdep.h> +#include "cpu.h" +#include <asm/arch/anomaly.h> +#include <asm/cplb.h> +#include <asm/io.h> + +void init_IRQ(void) +{ + blackfin_init_IRQ(); + return; +} + +void process_int(unsigned long vec, struct pt_regs *fp) +{ + printf("interrupt\n"); + return; +} + +extern unsigned int icplb_table[page_descriptor_table_size][2]; +extern unsigned int dcplb_table[page_descriptor_table_size][2]; + +unsigned long last_cplb_fault_retx; + +static unsigned int cplb_sizes[4] = + { 1024, 4 * 1024, 1024 * 1024, 4 * 1024 * 1024 }; + +void trap_c(struct pt_regs *regs) +{ + unsigned int addr; + unsigned long trapnr = (regs->seqstat) & SEQSTAT_EXCAUSE; + unsigned int i, j, size, *I0, *I1; + unsigned short data = 0; + + switch (trapnr) { + /* 0x26 - Data CPLB Miss */ + case VEC_CPLB_M: + +#ifdef ANOMALY_05000261 + /* + * Work around an anomaly: if we see a new DCPLB fault, return + * without doing anything. Then, if we get the same fault again, + * handle it. + */ + addr = last_cplb_fault_retx; + last_cplb_fault_retx = regs->retx; + printf("this time, curr = 0x%08x last = 0x%08x\n", addr, + last_cplb_fault_retx); + if (addr != last_cplb_fault_retx) + goto trap_c_return; +#endif + data = 1; + + case VEC_CPLB_I_M: + + if (data) + addr = *pDCPLB_FAULT_ADDR; + else + addr = *pICPLB_FAULT_ADDR; + + for (i = 0; i < page_descriptor_table_size; i++) { + if (data) { + size = cplb_sizes[dcplb_table[i][1] >> 16]; + j = dcplb_table[i][0]; + } else { + size = cplb_sizes[icplb_table[i][1] >> 16]; + j = icplb_table[i][0]; + } + if ((j <= addr) && ((j + size) > addr)) { + debug("found %i 0x%08x\n", i, j); + break; + } + } + if (i == page_descriptor_table_size) { + printf("something is really wrong\n"); + do_reset(NULL, 0, 0, NULL); + } + + /* Turn the cache off */ + if (data) { + sync(); + asm(" .align 8; "); + *(unsigned int *)DMEM_CONTROL &= + ~(ACACHE_BCACHE | ENDCPLB | PORT_PREF0); + sync(); + } else { + sync(); + asm(" .align 8; "); + *(unsigned int *)IMEM_CONTROL &= ~(IMC | ENICPLB); + sync(); + } + + if (data) { + I0 = (unsigned int *)DCPLB_ADDR0; + I1 = (unsigned int *)DCPLB_DATA0; + } else { + I0 = (unsigned int *)ICPLB_ADDR0; + I1 = (unsigned int *)ICPLB_DATA0; + } + + j = 0; + while (*I1 & CPLB_LOCK) { + debug("skipping %i %08p - %08x\n", j, I1, *I1); + *I0++; + *I1++; + j++; + } + + debug("remove %i 0x%08x 0x%08x\n", j, *I0, *I1); + + for (; j < 15; j++) { + debug("replace %i 0x%08x 0x%08x\n", j, I0, I0 + 1); + *I0++ = *(I0 + 1); + *I1++ = *(I1 + 1); + } + + if (data) { + *I0 = dcplb_table[i][0]; + *I1 = dcplb_table[i][1]; + I0 = (unsigned int *)DCPLB_ADDR0; + I1 = (unsigned int *)DCPLB_DATA0; + } else { + *I0 = icplb_table[i][0]; + *I1 = icplb_table[i][1]; + I0 = (unsigned int *)ICPLB_ADDR0; + I1 = (unsigned int *)ICPLB_DATA0; + } + + for (j = 0; j < 16; j++) { + debug("%i 0x%08x 0x%08x\n", j, *I0++, *I1++); + } + + /* Turn the cache back on */ + if (data) { + j = *(unsigned int *)DMEM_CONTROL; + sync(); + asm(" .align 8; "); + *(unsigned int *)DMEM_CONTROL = + ACACHE_BCACHE | ENDCPLB | PORT_PREF0 | j; + sync(); + } else { + sync(); + asm(" .align 8; "); + *(unsigned int *)IMEM_CONTROL = IMC | ENICPLB; + sync(); + } + + break; + default: + /* All traps come here */ + printf("code=[0x%x], ", (unsigned int)(regs->seqstat & 0x3f)); + printf("stack frame=0x%x, ", (unsigned int)regs); + printf("bad PC=0x%04x\n", (unsigned int)regs->pc); + dump(regs); + printf("\n\n"); + + printf("Unhandled IRQ or exceptions!\n"); + printf("Please reset the board \n"); + do_reset(NULL, 0, 0, NULL); + } + +trap_c_return: + return; + +} + +void dump(struct pt_regs *fp) +{ + debug("RETE: %08lx RETN: %08lx RETX: %08lx RETS: %08lx\n", fp->rete, + fp->retn, fp->retx, fp->rets); + debug("IPEND: %04lx SYSCFG: %04lx\n", fp->ipend, fp->syscfg); + debug("SEQSTAT: %08lx SP: %08lx\n", (long)fp->seqstat, (long)fp); + debug("R0: %08lx R1: %08lx R2: %08lx R3: %08lx\n", fp->r0, + fp->r1, fp->r2, fp->r3); + debug("R4: %08lx R5: %08lx R6: %08lx R7: %08lx\n", fp->r4, + fp->r5, fp->r6, fp->r7); + debug("P0: %08lx P1: %08lx P2: %08lx P3: %08lx\n", fp->p0, + fp->p1, fp->p2, fp->p3); + debug("P4: %08lx P5: %08lx FP: %08lx\n", fp->p4, fp->p5, fp->fp); + debug("A0.w: %08lx A0.x: %08lx A1.w: %08lx A1.x: %08lx\n", + fp->a0w, fp->a0x, fp->a1w, fp->a1x); + + debug("LB0: %08lx LT0: %08lx LC0: %08lx\n", fp->lb0, fp->lt0, + fp->lc0); + debug("LB1: %08lx LT1: %08lx LC1: %08lx\n", fp->lb1, fp->lt1, + fp->lc1); + debug("B0: %08lx L0: %08lx M0: %08lx I0: %08lx\n", fp->b0, fp->l0, + fp->m0, fp->i0); + debug("B1: %08lx L1: %08lx M1: %08lx I1: %08lx\n", fp->b1, fp->l1, + fp->m1, fp->i1); + debug("B2: %08lx L2: %08lx M2: %08lx I2: %08lx\n", fp->b2, fp->l2, + fp->m2, fp->i2); + debug("B3: %08lx L3: %08lx M3: %08lx I3: %08lx\n", fp->b3, fp->l3, + fp->m3, fp->i3); + + debug("DCPLB_FAULT_ADDR=%p\n", *pDCPLB_FAULT_ADDR); + debug("ICPLB_FAULT_ADDR=%p\n", *pICPLB_FAULT_ADDR); + +} diff --git a/cpu/bf561/video.c b/cpu/bf561/video.c new file mode 100644 index 0000000..3ff0151 --- /dev/null +++ b/cpu/bf561/video.c @@ -0,0 +1,194 @@ +/* + * (C) Copyright 2000 + * Paolo Scaffardi, AIRVENT SAM s.p.a - RIMINI(ITALY), arsenio@tin.it + * (C) Copyright 2002 + * Wolfgang Denk, wd@denx.de + * (C) Copyright 2006 + * Aubrey Li, aubrey.li@analog.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <stdarg.h> +#include <common.h> +#include <config.h> +#include <asm/blackfin.h> +#include <i2c.h> +#include <linux/types.h> +#include <devices.h> + +#ifdef CONFIG_VIDEO +#define NTSC_FRAME_ADDR 0x06000000 +#include "video.h" + +/* NTSC OUTPUT SIZE 720 * 240 */ +#define VERTICAL 2 +#define HORIZONTAL 4 + +int is_vblank_line(const int line) +{ + /* + * This array contains a single bit for each line in + * an NTSC frame. + */ + if ((line <= 18) || (line >= 264 && line <= 281) || (line == 528)) + return true; + + return false; +} + +int NTSC_framebuffer_init(char *base_address) +{ + const int NTSC_frames = 1; + const int NTSC_lines = 525; + char *dest = base_address; + int frame_num, line_num; + + for (frame_num = 0; frame_num < NTSC_frames; ++frame_num) { + for (line_num = 1; line_num <= NTSC_lines; ++line_num) { + unsigned int code; + int offset = 0; + int i; + + if (is_vblank_line(line_num)) + offset++; + + if (line_num > 266 || line_num < 3) + offset += 2; + + /* Output EAV code */ + code = SystemCodeMap[offset].EAV; + write_dest_byte((char)(code >> 24) & 0xff); + write_dest_byte((char)(code >> 16) & 0xff); + write_dest_byte((char)(code >> 8) & 0xff); + write_dest_byte((char)(code) & 0xff); + + /* Output horizontal blanking */ + for (i = 0; i < 67 * 2; ++i) { + write_dest_byte(0x80); + write_dest_byte(0x10); + } + + /* Output SAV */ + code = SystemCodeMap[offset].SAV; + write_dest_byte((char)(code >> 24) & 0xff); + write_dest_byte((char)(code >> 16) & 0xff); + write_dest_byte((char)(code >> 8) & 0xff); + write_dest_byte((char)(code) & 0xff); + + /* Output empty horizontal data */ + for (i = 0; i < 360 * 2; ++i) { + write_dest_byte(0x80); + write_dest_byte(0x10); + } + } + } + + return dest - base_address; +} + +void fill_frame(char *Frame, int Value) +{ + int *OddPtr32; + int OddLine; + int *EvenPtr32; + int EvenLine; + int i; + int *data; + int m, n; + + /* fill odd and even frames */ + for (OddLine = 22, EvenLine = 285; OddLine < 263; OddLine++, EvenLine++) { + OddPtr32 = (int *)((Frame + (OddLine * 1716)) + 276); + EvenPtr32 = (int *)((Frame + (EvenLine * 1716)) + 276); + for (i = 0; i < 360; i++, OddPtr32++, EvenPtr32++) { + *OddPtr32 = Value; + *EvenPtr32 = Value; + } + } + + for (m = 0; m < VERTICAL; m++) { + data = (int *)u_boot_logo.data; + for (OddLine = (22 + m), EvenLine = (285 + m); + OddLine < (u_boot_logo.height * VERTICAL) + (22 + m); + OddLine += VERTICAL, EvenLine += VERTICAL) { + OddPtr32 = (int *)((Frame + ((OddLine) * 1716)) + 276); + EvenPtr32 = + (int *)((Frame + ((EvenLine) * 1716)) + 276); + for (i = 0; i < u_boot_logo.width / 2; i++) { + /* enlarge one pixel to m x n */ + for (n = 0; n < HORIZONTAL; n++) { + *OddPtr32++ = *data; + *EvenPtr32++ = *data; + } + data++; + } + } + } +} + +void video_putc(const char c) +{ +} + +void video_puts(const char *s) +{ +} + +static int video_init(void) +{ + char *NTSCFrame; + NTSCFrame = (char *)NTSC_FRAME_ADDR; + NTSC_framebuffer_init(NTSCFrame); + fill_frame(NTSCFrame, BLUE); + + *pPPI_CONTROL = 0x0082; + *pPPI_FRAME = 0x020D; + + *pDMA0_START_ADDR = NTSCFrame; + *pDMA0_X_COUNT = 0x035A; + *pDMA0_X_MODIFY = 0x0002; + *pDMA0_Y_COUNT = 0x020D; + *pDMA0_Y_MODIFY = 0x0002; + *pDMA0_CONFIG = 0x1015; + *pPPI_CONTROL = 0x0083; + return 0; +} + +int drv_video_init(void) +{ + int error, devices = 1; + + device_t videodev; + + video_init(); /* Video initialization */ + + memset(&videodev, 0, sizeof(videodev)); + + strcpy(videodev.name, "video"); + videodev.ext = DEV_EXT_VIDEO; /* Video extensions */ + videodev.flags = DEV_FLAGS_OUTPUT; /* Output only */ + videodev.putc = video_putc; /* 'putc' function */ + videodev.puts = video_puts; /* 'puts' function */ + + error = device_register(&videodev); + + return (error == 0) ? devices : error; +} +#endif diff --git a/cpu/bf561/video.h b/cpu/bf561/video.h new file mode 100644 index 0000000..d237f6a --- /dev/null +++ b/cpu/bf561/video.h @@ -0,0 +1,25 @@ +#include <video_logo.h> +#define write_dest_byte(val) {*dest++=val;} +#define BLACK (0x01800180) /* black pixel pattern */ +#define BLUE (0x296E29F0) /* blue pixel pattern */ +#define RED (0x51F0515A) /* red pixel pattern */ +#define MAGENTA (0x6ADE6ACA) /* magenta pixel pattern */ +#define GREEN (0x91229136) /* green pixel pattern */ +#define CYAN (0xAA10AAA6) /* cyan pixel pattern */ +#define YELLOW (0xD292D210) /* yellow pixel pattern */ +#define WHITE (0xFE80FE80) /* white pixel pattern */ + +#define true 1 +#define false 0 + +typedef struct { + unsigned int SAV; + unsigned int EAV; +} SystemCodeType; + +const SystemCodeType SystemCodeMap[4] = { + {0xFF000080, 0xFF00009D}, + {0xFF0000AB, 0xFF0000B6}, + {0xFF0000C7, 0xFF0000DA}, + {0xFF0000EC, 0xFF0000F1} +}; diff --git a/cpu/mcf52x2/cpu.c b/cpu/mcf52x2/cpu.c index aa6b2bd..ce59d39 100644 --- a/cpu/mcf52x2/cpu.c +++ b/cpu/mcf52x2/cpu.c @@ -49,11 +49,43 @@ #endif #ifdef CONFIG_M5271 +/* + * Both MCF5270 and MCF5271 are members of the MPC5271 family. Try to + * determine which one we are running on, based on the Chip Identification + * Register (CIR). + */ int checkcpu (void) { char buf[32]; + unsigned short cir; /* Chip Identification Register */ + unsigned short pin; /* Part identification number */ + unsigned char prn; /* Part revision number */ + char *cpu_model; + + cir = mbar_readShort(MCF_CCM_CIR); + pin = cir >> MCF_CCM_CIR_PIN_LEN; + prn = cir & MCF_CCM_CIR_PRN_MASK; + + switch (pin) { + case MCF_CCM_CIR_PIN_MCF5270: + cpu_model = "5270"; + break; + case MCF_CCM_CIR_PIN_MCF5271: + cpu_model = "5271"; + break; + default: + cpu_model = NULL; + break; + } + + if (cpu_model) + printf("CPU: Freescale ColdFire MCF%s rev. %hu, at %s MHz\n", + cpu_model, prn, strmhz(buf, CFG_CLK)); + else + printf("CPU: Unknown - Freescale ColdFire MCF5271 family" + " (PIN: 0x%x) rev. %hu, at %s MHz\n", + pin, prn, strmhz(buf, CFG_CLK)); - printf ("CPU: Freescale Coldfire MCF5271 at %s MHz\n", strmhz(buf, CFG_CLK)); return 0; } diff --git a/cpu/mcf52x2/start.S b/cpu/mcf52x2/start.S index f1f4077..7c9a7d2 100644 --- a/cpu/mcf52x2/start.S +++ b/cpu/mcf52x2/start.S @@ -140,11 +140,11 @@ _start: move.l #(CFG_MBAR + 1), %d0 /* set IPSBAR address + valid flag */ move.l %d0, 0x40000000 -#if defined(CONFIG_M5282) /* Initialize RAMBAR1: locate SRAM and validate it */ move.l #(CFG_INIT_RAM_ADDR + 0x21), %d0 movec %d0, %RAMBAR1 +#if defined(CONFIG_M5282) #if (TEXT_BASE == CFG_INT_FLASH_BASE) /* Setup code in SRAM to initialize FLASHBAR, if start from internal Flash */ diff --git a/cpu/mpc5xxx/cpu.c b/cpu/mpc5xxx/cpu.c index 6b6f828..813aa79 100644 --- a/cpu/mpc5xxx/cpu.c +++ b/cpu/mpc5xxx/cpu.c @@ -31,6 +31,10 @@ #include <mpc5xxx.h> #include <asm/processor.h> +#if defined(CONFIG_OF_FLAT_TREE) +#include <ft_build.h> +#endif + DECLARE_GLOBAL_DATA_PTR; int checkcpu (void) @@ -102,3 +106,26 @@ unsigned long get_tbclk (void) } /* ------------------------------------------------------------------------- */ + +#ifdef CONFIG_OF_FLAT_TREE +void +ft_cpu_setup(void *blob, bd_t *bd) +{ + u32 *p; + int len; + + /* Core XLB bus frequency */ + p = ft_get_prop(blob, "/cpus/" OF_CPU "/bus-frequency", &len); + if (p != NULL) + *p = cpu_to_be32(bd->bi_busfreq); + + /* SOC peripherals use the IPB bus frequency */ + p = ft_get_prop(blob, "/" OF_SOC "/bus-frequency", &len); + if (p != NULL) + *p = cpu_to_be32(bd->bi_ipbfreq); + + p = ft_get_prop(blob, "/" OF_SOC "/ethernet@3000/mac-address", &len); + if (p != NULL) + memcpy(p, bd->bi_enetaddr, 6); +} +#endif diff --git a/cpu/mpc5xxx/cpu_init.c b/cpu/mpc5xxx/cpu_init.c index b7e00b3..7e65821 100644 --- a/cpu/mpc5xxx/cpu_init.c +++ b/cpu/mpc5xxx/cpu_init.c @@ -123,7 +123,7 @@ void cpu_init_f (void) #endif #if defined(CFG_CS7_START) && defined(CFG_CS7_SIZE) - *(vu_long *)MPC5XXX_CS7_START = START_REG(CFG_CS5_START); + *(vu_long *)MPC5XXX_CS7_START = START_REG(CFG_CS7_START); *(vu_long *)MPC5XXX_CS7_STOP = STOP_REG(CFG_CS7_START, CFG_CS7_SIZE); addecr |= (1 << 27); #endif diff --git a/cpu/mpc5xxx/fec.c b/cpu/mpc5xxx/fec.c index 37fe3e7..13a3870 100644 --- a/cpu/mpc5xxx/fec.c +++ b/cpu/mpc5xxx/fec.c @@ -376,7 +376,7 @@ static int mpc5xxx_fec_init(struct eth_device *dev, bd_t * bis) #if (DEBUG & 0x2) if (fec->xcv_type != SEVENWIRE) - mpc5xxx_fec_phydump (); + mpc5xxx_fec_phydump (dev->name); #endif /* @@ -575,7 +575,7 @@ static void mpc5xxx_fec_halt(struct eth_device *dev) #if (DEBUG & 0x2) if (fec->xcv_type != SEVENWIRE) - mpc5xxx_fec_phydump (); + mpc5xxx_fec_phydump (dev->name); #endif /* @@ -878,11 +878,13 @@ int mpc5xxx_fec_initialize(bd_t * bis) fec->eth = (ethernet_regs *)MPC5XXX_FEC; fec->tbdBase = (FEC_TBD *)FEC_BD_BASE; fec->rbdBase = (FEC_RBD *)(FEC_BD_BASE + FEC_TBD_NUM * sizeof(FEC_TBD)); -#if defined(CONFIG_CANMB) || defined(CONFIG_HMI1001) || \ - defined(CONFIG_ICECUBE) || defined(CONFIG_INKA4X0) || \ - defined(CONFIG_MCC200) || defined(CONFIG_O2DNT) || \ - defined(CONFIG_PM520) || defined(CONFIG_TOP5200) || \ - defined(CONFIG_TQM5200) || defined(CONFIG_V38B) +#if defined(CONFIG_CANMB) || defined(CONFIG_HMI1001) || \ + defined(CONFIG_ICECUBE) || defined(CONFIG_INKA4X0) || \ + defined(CONFIG_JUPITER) || defined(CONFIG_MCC200) || \ + defined(CONFIG_MOTIONPRO)|| defined(CONFIG_O2DNT) || \ + defined(CONFIG_PM520) || defined(CONFIG_TOP5200) || \ + defined(CONFIG_TQM5200) || defined(CONFIG_UC101) || \ + defined(CONFIG_V38B) # ifndef CONFIG_FEC_10MBIT fec->xcv_type = MII100; # else diff --git a/cpu/mpc8260/cpu.c b/cpu/mpc8260/cpu.c index 4f23012..94651dc 100644 --- a/cpu/mpc8260/cpu.c +++ b/cpu/mpc8260/cpu.c @@ -49,6 +49,10 @@ DECLARE_GLOBAL_DATA_PTR; +#if defined(CONFIG_GET_CPU_STR_F) +extern int get_cpu_str_f (char *buf); +#endif + int checkcpu (void) { volatile immap_t *immap = (immap_t *) CFG_IMMR; @@ -81,7 +85,12 @@ int checkcpu (void) if ((immr & IMMR_ISB_MSK) != CFG_IMMR) return -1; /* whoops! someone moved the IMMR */ +#if defined(CONFIG_GET_CPU_STR_F) + get_cpu_str_f (buf); + printf ("%s (HiP%d Rev %02x, Mask ", buf, k, rev); +#else printf (CPU_ID_STR " (HiP%d Rev %02x, Mask ", k, rev); +#endif /* * the bottom 16 bits of the immr are the Part Number and Mask Number diff --git a/cpu/mpc8260/cpu_init.c b/cpu/mpc8260/cpu_init.c index 640026b..380d7af 100644 --- a/cpu/mpc8260/cpu_init.c +++ b/cpu/mpc8260/cpu_init.c @@ -28,6 +28,10 @@ DECLARE_GLOBAL_DATA_PTR; +#if defined(CONFIG_BOARD_GET_CPU_CLK_F) +extern unsigned long board_get_cpu_clk_f (void); +#endif + static void config_8260_ioports (volatile immap_t * immr) { int portnum; @@ -90,6 +94,7 @@ static void config_8260_ioports (volatile immap_t * immr) } } +#define SET_VAL_MASK(a, b, mask) ((a & mask) | (b & ~mask)) /* * Breath some life into the CPU... * @@ -102,6 +107,9 @@ void cpu_init_f (volatile immap_t * immr) #if !defined(CONFIG_COGENT) /* done in start.S for the cogent */ uint sccr; #endif +#if defined(CONFIG_BOARD_GET_CPU_CLK_F) + unsigned long cpu_clk; +#endif volatile memctl8260_t *memctl = &immr->im_memctl; extern void m8260_cpm_reset (void); @@ -119,10 +127,27 @@ void cpu_init_f (volatile immap_t * immr) immr->im_clkrst.car_rmr = CFG_RMR; /* BCR - Bus Configuration Register (4-25) */ +#if defined(CFG_BCR_60x) && (CFG_BCR_SINGLE) + if (immr->im_siu_conf.sc_bcr & BCR_EBM) { + immr->im_siu_conf.sc_bcr = SET_VAL_MASK(immr->im_siu_conf.sc_bcr, CFG_BCR_60x, 0x80000010); + } else { + immr->im_siu_conf.sc_bcr = SET_VAL_MASK(immr->im_siu_conf.sc_bcr, CFG_BCR_SINGLE, 0x80000010); + } +#else immr->im_siu_conf.sc_bcr = CFG_BCR; +#endif /* SIUMCR - contains debug pin configuration (4-31) */ +#if defined(CFG_SIUMCR_LOW) && (CFG_SIUMCR_HIGH) + cpu_clk = board_get_cpu_clk_f (); + if (cpu_clk >= 100000000) { + immr->im_siu_conf.sc_siumcr = SET_VAL_MASK(immr->im_siu_conf.sc_siumcr, CFG_SIUMCR_HIGH, 0x9f3cc000); + } else { + immr->im_siu_conf.sc_siumcr = SET_VAL_MASK(immr->im_siu_conf.sc_siumcr, CFG_SIUMCR_LOW, 0x9f3cc000); + } +#else immr->im_siu_conf.sc_siumcr = CFG_SIUMCR; +#endif config_8260_ioports (immr); @@ -157,7 +182,8 @@ void cpu_init_f (volatile immap_t * immr) #endif /* now restrict to preliminary range */ - memctl->memc_br0 = CFG_BR0_PRELIM; + /* the PS came from the HRCW, don´t change it */ + memctl->memc_br0 = SET_VAL_MASK(memctl->memc_br0 , CFG_BR0_PRELIM, BRx_PS_MSK); memctl->memc_or0 = CFG_OR0_PRELIM; #if defined(CFG_BR1_PRELIM) && defined(CFG_OR1_PRELIM) diff --git a/cpu/mpc8260/pci.c b/cpu/mpc8260/pci.c index b14fc15..75c6ab2 100644 --- a/cpu/mpc8260/pci.c +++ b/cpu/mpc8260/pci.c @@ -274,7 +274,8 @@ void pci_mpc8250_init (struct pci_controller *hose) | SIUMCR_CS10PC00 | SIUMCR_BCTLC00 | SIUMCR_MMR11; - +#elif defined(CONFIG_TQM8272) +/* nothing to do for this Board here */ #else /* * Setting required to enable IRQ1-IRQ7 (SIUMCR [DPPC]), diff --git a/cpu/mpc8260/speed.c b/cpu/mpc8260/speed.c index 360404f..38cd0d9 100644 --- a/cpu/mpc8260/speed.c +++ b/cpu/mpc8260/speed.c @@ -25,6 +25,10 @@ #include <mpc8260.h> #include <asm/processor.h> +#if defined(CONFIG_BOARD_GET_CPU_CLK_F) +extern unsigned long board_get_cpu_clk_f (void); +#endif + DECLARE_GLOBAL_DATA_PTR; /* ------------------------------------------------------------------------- */ @@ -112,8 +116,12 @@ int get_clocks (void) #if !defined(CONFIG_8260_CLKIN) #error clock measuring not implemented yet - define CONFIG_8260_CLKIN #else +#if defined(CONFIG_BOARD_GET_CPU_CLK_F) + clkin = board_get_cpu_clk_f (); +#else clkin = CONFIG_8260_CLKIN; #endif +#endif sccr = immap->im_clkrst.car_sccr; dfbrg = (sccr & SCCR_DFBRG_MSK) >> SCCR_DFBRG_SHIFT; diff --git a/cpu/mpc83xx/Makefile b/cpu/mpc83xx/Makefile index b2a6b3e..4b9dcc8 100644 --- a/cpu/mpc83xx/Makefile +++ b/cpu/mpc83xx/Makefile @@ -27,9 +27,9 @@ include $(TOPDIR)/config.mk LIB = $(obj)lib$(CPU).a -START = start.o resetvec.o +START = start.o COBJS = traps.o cpu.o cpu_init.o speed.o interrupts.o \ - i2c.o spd_sdram.o + spd_sdram.o qe_io.o SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c) OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS)) diff --git a/cpu/mpc83xx/cpu.c b/cpu/mpc83xx/cpu.c index 20bba6c..e4bc405 100644 --- a/cpu/mpc83xx/cpu.c +++ b/cpu/mpc83xx/cpu.c @@ -1,5 +1,5 @@ /* - * Copyright 2004 Freescale Semiconductor, Inc. + * Copyright (C) 2004-2006 Freescale Semiconductor, Inc. * * See file CREDITS for list of people who contributed to this * project. @@ -18,11 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA - * - * Change log: - * - * 20050101: Eran Liberty (liberty@freescale.com) - * Initial file creating (porting from 85XX & 8260) */ /* @@ -43,35 +38,169 @@ DECLARE_GLOBAL_DATA_PTR; int checkcpu(void) { + volatile immap_t *immr; ulong clock = gd->cpu_clk; u32 pvr = get_pvr(); + u32 spridr; char buf[32]; + immr = (immap_t *)CFG_IMMR; + if ((pvr & 0xFFFF0000) != PVR_83xx) { puts("Not MPC83xx Family!!!\n"); return -1; } - puts("CPU: MPC83xx, "); - switch(pvr) { - case PVR_8349_REV10: + spridr = immr->sysconf.spridr; + puts("CPU: "); + switch(spridr) { + case SPR_8349E_REV10: + case SPR_8349E_REV11: + case SPR_8349E_REV31: + puts("MPC8349E, "); + break; + case SPR_8349_REV10: + case SPR_8349_REV11: + case SPR_8349_REV31: + puts("MPC8349, "); + break; + case SPR_8347E_REV10_TBGA: + case SPR_8347E_REV11_TBGA: + case SPR_8347E_REV31_TBGA: + case SPR_8347E_REV10_PBGA: + case SPR_8347E_REV11_PBGA: + case SPR_8347E_REV31_PBGA: + puts("MPC8347E, "); + break; + case SPR_8347_REV10_TBGA: + case SPR_8347_REV11_TBGA: + case SPR_8347_REV31_TBGA: + case SPR_8347_REV10_PBGA: + case SPR_8347_REV11_PBGA: + case SPR_8347_REV31_PBGA: + puts("MPC8347, "); + break; + case SPR_8343E_REV10: + case SPR_8343E_REV11: + case SPR_8343E_REV31: + puts("MPC8343E, "); + break; + case SPR_8343_REV10: + case SPR_8343_REV11: + case SPR_8343_REV31: + puts("MPC8343, "); + break; + case SPR_8360E_REV10: + case SPR_8360E_REV11: + case SPR_8360E_REV12: + case SPR_8360E_REV20: + puts("MPC8360E, "); break; - case PVR_8349_REV11: + case SPR_8360_REV10: + case SPR_8360_REV11: + case SPR_8360_REV12: + case SPR_8360_REV20: + puts("MPC8360, "); + break; + case SPR_8323E_REV10: + case SPR_8323E_REV11: + puts("MPC8323E, "); + break; + case SPR_8323_REV10: + case SPR_8323_REV11: + puts("MPC8323, "); + break; + case SPR_8321E_REV10: + case SPR_8321E_REV11: + puts("MPC8321E, "); + break; + case SPR_8321_REV10: + case SPR_8321_REV11: + puts("MPC8321, "); break; default: - puts("Rev: Unknown\n"); - return -1; /* Not sure what this is */ + puts("Rev: Unknown revision number.\nWarning: Unsupported cpu revision!\n"); + return 0; } - printf("Rev: %d.%d at %s MHz\n", (pvr & 0xf0) >> 4, - (pvr & 0x0f), strmhz(buf, clock)); +#if defined(CONFIG_MPC834X) + /* Multiple revisons of 834x processors may have the same SPRIDR value. + * So use PVR to identify the revision number. + */ + printf("Rev: %02x at %s MHz\n", PVR_MAJ(pvr)<<4 | PVR_MIN(pvr), strmhz(buf, clock)); +#else + printf("Rev: %02x at %s MHz\n", spridr & 0x0000FFFF, strmhz(buf, clock)); +#endif return 0; } +/* + * Program a UPM with the code supplied in the table. + * + * The 'dummy' variable is used to increment the MAD. 'dummy' is + * supposed to be a pointer to the memory of the device being + * programmed by the UPM. The data in the MDR is written into + * memory and the MAD is incremented every time there's a read + * from 'dummy'. Unfortunately, the current prototype for this + * function doesn't allow for passing the address of this + * device, and changing the prototype will break a number lots + * of other code, so we need to use a round-about way of finding + * the value for 'dummy'. + * + * The value can be extracted from the base address bits of the + * Base Register (BR) associated with the specific UPM. To find + * that BR, we need to scan all 8 BRs until we find the one that + * has its MSEL bits matching the UPM we want. Once we know the + * right BR, we can extract the base address bits from it. + * + * The MxMR and the BR and OR of the chosen bank should all be + * configured before calling this function. + * + * Parameters: + * upm: 0=UPMA, 1=UPMB, 2=UPMC + * table: Pointer to an array of values to program + * size: Number of elements in the array. Must be 64 or less. + */ void upmconfig (uint upm, uint *table, uint size) { - hang(); /* FIXME: upconfig() needed? */ +#if defined(CONFIG_MPC834X) + volatile immap_t *immap = (immap_t *) CFG_IMMR; + volatile lbus83xx_t *lbus = &immap->lbus; + volatile uchar *dummy = NULL; + const u32 msel = (upm + 4) << BR_MSEL_SHIFT; /* What the MSEL field in BRn should be */ + volatile u32 *mxmr = &lbus->mamr + upm; /* Pointer to mamr, mbmr, or mcmr */ + uint i; + + /* Scan all the banks to determine the base address of the device */ + for (i = 0; i < 8; i++) { + if ((lbus->bank[i].br & BR_MSEL) == msel) { + dummy = (uchar *) (lbus->bank[i].br & BR_BA); + break; + } + } + + if (!dummy) { + printf("Error: %s() could not find matching BR\n", __FUNCTION__); + hang(); + } + + /* Set the OP field in the MxMR to "write" and the MAD field to 000000 */ + *mxmr = (*mxmr & 0xCFFFFFC0) | 0x10000000; + + for (i = 0; i < size; i++) { + lbus->mdr = table[i]; + __asm__ __volatile__ ("sync"); + *dummy; /* Write the value to memory and increment MAD */ + __asm__ __volatile__ ("sync"); + } + + /* Set the OP field in the MxMR to "normal" and the MAD field to 000000 */ + *mxmr &= 0xCFFFFFC0; +#else + printf("Error: %s() not defined for this configuration.\n", __FUNCTION__); + hang(); +#endif } @@ -83,7 +212,7 @@ do_reset (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) ulong addr; #endif - volatile immap_t *immap = (immap_t *) CFG_IMMRBAR; + volatile immap_t *immap = (immap_t *) CFG_IMMR; #ifdef MPC83xx_RESET /* Interrupts and MMU off */ @@ -150,9 +279,17 @@ unsigned long get_tbclk(void) #if defined(CONFIG_WATCHDOG) void watchdog_reset (void) { - hang(); /* FIXME: implement watchdog_reset()? */ + int re_enable = disable_interrupts(); + + /* Reset the 83xx watchdog */ + volatile immap_t *immr = (immap_t *) CFG_IMMR; + immr->wdt.swsrr = 0x556c; + immr->wdt.swsrr = 0xaa39; + + if (re_enable) + enable_interrupts (); } -#endif /* CONFIG_WATCHDOG */ +#endif #if defined(CONFIG_OF_FLAT_TREE) void @@ -180,13 +317,63 @@ ft_cpu_setup(void *blob, bd_t *bd) *p = cpu_to_be32(clock); #ifdef CONFIG_MPC83XX_TSEC1 - p = ft_get_prop(blob, "/" OF_SOC "/ethernet@24000/address", &len); + p = ft_get_prop(blob, "/" OF_SOC "/ethernet@24000/mac-address", &len); + if (p != NULL) + memcpy(p, bd->bi_enetaddr, 6); + + p = ft_get_prop(blob, "/" OF_SOC "/ethernet@24000/local-mac-address", &len); + if (p != NULL) memcpy(p, bd->bi_enetaddr, 6); #endif #ifdef CONFIG_MPC83XX_TSEC2 - p = ft_get_prop(blob, "/" OF_SOC "/ethernet@25000/address", &len); + p = ft_get_prop(blob, "/" OF_SOC "/ethernet@25000/mac-address", &len); + if (p != NULL) memcpy(p, bd->bi_enet1addr, 6); + + p = ft_get_prop(blob, "/" OF_SOC "/ethernet@25000/local-mac-address", &len); + if (p != NULL) + memcpy(p, bd->bi_enet1addr, 6); +#endif + +#ifdef CONFIG_UEC_ETH1 +#if CFG_UEC1_UCC_NUM == 0 /* UCC1 */ + p = ft_get_prop(blob, "/" OF_QE "/ucc@2000/mac-address", &len); + if (p != NULL) + memcpy(p, bd->bi_enetaddr, 6); + + p = ft_get_prop(blob, "/" OF_QE "/ucc@2000/local-mac-address", &len); + if (p != NULL) + memcpy(p, bd->bi_enetaddr, 6); +#elif CFG_UEC1_UCC_NUM == 2 /* UCC3 */ + p = ft_get_prop(blob, "/" OF_QE "/ucc@2200/mac-address", &len); + if (p != NULL) + memcpy(p, bd->bi_enetaddr, 6); + + p = ft_get_prop(blob, "/" OF_QE "/ucc@2200/local-mac-address", &len); + if (p != NULL) + memcpy(p, bd->bi_enetaddr, 6); +#endif +#endif + +#ifdef CONFIG_UEC_ETH2 +#if CFG_UEC2_UCC_NUM == 1 /* UCC2 */ + p = ft_get_prop(blob, "/" OF_QE "/ucc@3000/mac-address", &len); + if (p != NULL) + memcpy(p, bd->bi_enet1addr, 6); + + p = ft_get_prop(blob, "/" OF_QE "/ucc@3000/local-mac-address", &len); + if (p != NULL) + memcpy(p, bd->bi_enet1addr, 6); +#elif CFG_UEC2_UCC_NUM == 3 /* UCC4 */ + p = ft_get_prop(blob, "/" OF_QE "/ucc@3200/mac-address", &len); + if (p != NULL) + memcpy(p, bd->bi_enet1addr, 6); + + p = ft_get_prop(blob, "/" OF_QE "/ucc@3200/local-mac-address", &len); + if (p != NULL) + memcpy(p, bd->bi_enet1addr, 6); +#endif #endif } #endif @@ -194,8 +381,8 @@ ft_cpu_setup(void *blob, bd_t *bd) #if defined(CONFIG_DDR_ECC) void dma_init(void) { - volatile immap_t *immap = (immap_t *)CFG_IMMRBAR; - volatile dma8349_t *dma = &immap->dma; + volatile immap_t *immap = (immap_t *)CFG_IMMR; + volatile dma83xx_t *dma = &immap->dma; volatile u32 status = swab32(dma->dmasr0); volatile u32 dmamr0 = swab32(dma->dmamr0); @@ -225,8 +412,8 @@ void dma_init(void) uint dma_check(void) { - volatile immap_t *immap = (immap_t *)CFG_IMMRBAR; - volatile dma8349_t *dma = &immap->dma; + volatile immap_t *immap = (immap_t *)CFG_IMMR; + volatile dma83xx_t *dma = &immap->dma; volatile u32 status = swab32(dma->dmasr0); volatile u32 byte_count = swab32(dma->dmabcr0); @@ -244,8 +431,8 @@ uint dma_check(void) int dma_xfer(void *dest, u32 count, void *src) { - volatile immap_t *immap = (immap_t *)CFG_IMMRBAR; - volatile dma8349_t *dma = &immap->dma; + volatile immap_t *immap = (immap_t *)CFG_IMMR; + volatile dma83xx_t *dma = &immap->dma; volatile u32 dmamr0; /* initialize DMASARn, DMADAR and DMAABCRn */ diff --git a/cpu/mpc83xx/cpu_init.c b/cpu/mpc83xx/cpu_init.c index 6ed0992..3ac9161 100644 --- a/cpu/mpc83xx/cpu_init.c +++ b/cpu/mpc83xx/cpu_init.c @@ -1,5 +1,5 @@ /* - * Copyright 2004 Freescale Semiconductor, Inc. + * Copyright (C) 2004-2006 Freescale Semiconductor, Inc. * * See file CREDITS for list of people who contributed to this * project. @@ -18,11 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA - * - * Change log: - * - * 20050101: Eran Liberty (liberty@freescale.com) - * Initial file creating (porting from 85XX & 8260) */ #include <common.h> @@ -31,6 +26,30 @@ DECLARE_GLOBAL_DATA_PTR; +#ifdef CONFIG_QE +extern qe_iop_conf_t qe_iop_conf_tab[]; +extern void qe_config_iopin(u8 port, u8 pin, int dir, + int open_drain, int assign); +extern void qe_init(uint qe_base); +extern void qe_reset(void); + +static void config_qe_ioports(void) +{ + u8 port, pin; + int dir, open_drain, assign; + int i; + + for (i = 0; qe_iop_conf_tab[i].assign != QE_IOP_TAB_END; i++) { + port = qe_iop_conf_tab[i].port; + pin = qe_iop_conf_tab[i].pin; + dir = qe_iop_conf_tab[i].dir; + open_drain = qe_iop_conf_tab[i].open_drain; + assign = qe_iop_conf_tab[i].assign; + qe_config_iopin(port, pin, dir, open_drain, assign); + } +} +#endif + /* * Breathe some life into the CPU... * @@ -46,6 +65,59 @@ void cpu_init_f (volatile immap_t * im) /* Clear initial global data */ memset ((void *) gd, 0, sizeof (gd_t)); + /* system performance tweaking */ + +#ifdef CFG_ACR_PIPE_DEP + /* Arbiter pipeline depth */ + im->arbiter.acr = (im->arbiter.acr & ~ACR_PIPE_DEP) | + (CFG_ACR_PIPE_DEP << ACR_PIPE_DEP_SHIFT); +#endif + +#ifdef CFG_SPCR_TSEC1EP + /* TSEC1 Emergency priority */ + im->sysconf.spcr = (im->sysconf.spcr & ~SPCR_TSEC1EP) | (CFG_SPCR_TSEC1EP << SPCR_TSEC1EP_SHIFT); +#endif + +#ifdef CFG_SPCR_TSEC2EP + /* TSEC2 Emergency priority */ + im->sysconf.spcr = (im->sysconf.spcr & ~SPCR_TSEC2EP) | (CFG_SPCR_TSEC2EP << SPCR_TSEC2EP_SHIFT); +#endif + +#ifdef CONFIG_MPC834X +#ifdef CFG_SCCR_TSEC1CM + /* TSEC1 clock mode */ + im->clk.sccr = (im->clk.sccr & ~SCCR_TSEC1CM) | (CFG_SCCR_TSEC1CM << SCCR_TSEC1CM_SHIFT); +#endif +#ifdef CFG_SCCR_TSEC2CM + /* TSEC2 & I2C1 clock mode */ + im->clk.sccr = (im->clk.sccr & ~SCCR_TSEC2CM) | (CFG_SCCR_TSEC2CM << SCCR_TSEC2CM_SHIFT); +#endif +#ifdef CFG_SCCR_USBMPHCM + /* USB MPH clock mode */ + im->clk.sccr = (im->clk.sccr & ~SCCR_USBMPHCM) | (CFG_SCCR_USBMPHCM << SCCR_USBMPHCM_SHIFT); +#endif +#endif /* CONFIG_MPC834X */ + +#ifdef CFG_SCCR_PCICM + /* PCI & DMA clock mode */ + im->clk.sccr = (im->clk.sccr & ~SCCR_PCICM) | (CFG_SCCR_PCICM << SCCR_PCICM_SHIFT); +#endif + +#ifdef CFG_SCCR_USBDRCM + /* USB DR clock mode */ + im->clk.sccr = (im->clk.sccr & ~SCCR_USBDRCM) | (CFG_SCCR_USBDRCM << SCCR_USBDRCM_SHIFT); +#endif + +#ifdef CFG_SCCR_ENCCM + /* Encryption clock mode */ + im->clk.sccr = (im->clk.sccr & ~SCCR_ENCCM) | (CFG_SCCR_ENCCM << SCCR_PCICM_SHIFT); +#endif + +#ifdef CFG_ACR_RPTCNT + /* Arbiter repeat count */ + im->arbiter.acr = ((im->arbiter.acr & ~(ACR_RPTCNT)) | (CFG_ACR_RPTCNT << ACR_RPTCNT_SHIFT)); +#endif + /* RSR - Reset Status Register - clear all status (4.6.1.3) */ gd->reset_status = im->reset.rsr; im->reset.rsr = ~(RSR_RES); @@ -69,6 +141,15 @@ void cpu_init_f (volatile immap_t * im) #ifdef CFG_SICRL im->sysconf.sicrl = CFG_SICRL; #endif + /* DDR control driver register */ +#ifdef CFG_DDRCDR + im->sysconf.ddrcdr = CFG_DDRCDR; +#endif + +#ifdef CONFIG_QE + /* Config QE ioports */ + config_qe_ioports(); +#endif /* * Memory Controller: @@ -148,21 +229,21 @@ void cpu_init_f (volatile immap_t * im) im->sysconf.lblaw[7].ar = CFG_LBLAWAR7_PRELIM; #endif #ifdef CFG_GPIO1_PRELIM - im->pgio[0].dir = CFG_GPIO1_DIR; - im->pgio[0].dat = CFG_GPIO1_DAT; + im->gpio[0].dir = CFG_GPIO1_DIR; + im->gpio[0].dat = CFG_GPIO1_DAT; #endif #ifdef CFG_GPIO2_PRELIM - im->pgio[1].dir = CFG_GPIO2_DIR; - im->pgio[1].dat = CFG_GPIO2_DAT; + im->gpio[1].dir = CFG_GPIO2_DIR; + im->gpio[1].dat = CFG_GPIO2_DAT; #endif } - -/* - * Initialize higher level parts of CPU like time base and timers. - */ - int cpu_init_r (void) { +#ifdef CONFIG_QE + uint qe_base = CFG_IMMR + 0x00100000; /* QE immr base */ + qe_init(qe_base); + qe_reset(); +#endif return 0; } diff --git a/cpu/mpc83xx/i2c.c b/cpu/mpc83xx/i2c.c deleted file mode 100644 index 70450f9..0000000 --- a/cpu/mpc83xx/i2c.c +++ /dev/null @@ -1,253 +0,0 @@ -/* - * (C) Copyright 2003,Motorola Inc. - * Xianghua Xiao <x.xiao@motorola.com> - * Adapted for Motorola 85xx chip. - * - * (C) Copyright 2003 - * Gleb Natapov <gnatapov@mrv.com> - * Some bits are taken from linux driver writen by adrian@humboldt.co.uk - * - * Hardware I2C driver for MPC107 PCI bridge. - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - * - * Change log: - * - * 20050101: Eran Liberty (liberty@freescale.com) - * Initial file creating (porting from 85XX & 8260) - */ - -#include <common.h> -#include <command.h> -#include <asm/io.h> - -#ifdef CONFIG_HARD_I2C -#include <i2c.h> -#include <asm/i2c.h> - -#if defined(CONFIG_MPC8349EMDS) || defined(CONFIG_TQM834X) -i2c_t * mpc8349_i2c = (i2c_t*)(CFG_IMMRBAR + CFG_I2C_OFFSET); -#endif - -void -i2c_init(int speed, int slaveadd) -{ - /* stop I2C controller */ - writeb(0x00 , &I2C->cr); - - /* set clock */ - writeb(0x3f, &I2C->fdr); - - /* set default filter */ - writeb(0x10,&I2C->dfsrr); - - /* write slave address */ - writeb(slaveadd, &I2C->adr); - - /* clear status register */ - writeb(0x00, &I2C->sr); - - /* start I2C controller */ - writeb(I2C_CR_MEN, &I2C->cr); -} - -static __inline__ int -i2c_wait4bus (void) -{ - ulong timeval = get_timer (0); - while (readb(&I2C->sr) & I2C_SR_MBB) { - if (get_timer (timeval) > I2C_TIMEOUT) { - return -1; - } - } - return 0; -} - -static __inline__ int -i2c_wait (int write) -{ - u32 csr; - ulong timeval = get_timer(0); - do { - csr = readb(&I2C->sr); - - if (!(csr & I2C_SR_MIF)) - continue; - - writeb(0x0, &I2C->sr); - - if (csr & I2C_SR_MAL) { - debug("i2c_wait: MAL\n"); - return -1; - } - - if (!(csr & I2C_SR_MCF)) { - debug("i2c_wait: unfinished\n"); - return -1; - } - - if (write == I2C_WRITE && (csr & I2C_SR_RXAK)) { - debug("i2c_wait: No RXACK\n"); - return -1; - } - - return 0; - } while (get_timer (timeval) < I2C_TIMEOUT); - - debug("i2c_wait: timed out\n"); - return -1; -} - -static __inline__ int -i2c_write_addr (u8 dev, u8 dir, int rsta) -{ - writeb(I2C_CR_MEN | I2C_CR_MSTA | I2C_CR_MTX | - (rsta?I2C_CR_RSTA:0), - &I2C->cr); - - writeb((dev << 1) | dir, &I2C->dr); - - if (i2c_wait (I2C_WRITE) < 0) - return 0; - return 1; -} - -static __inline__ int -__i2c_write (u8 *data, int length) -{ - int i; - - writeb(I2C_CR_MEN | I2C_CR_MSTA | I2C_CR_MTX, - &I2C->cr); - - for (i=0; i < length; i++) { - writeb(data[i], &I2C->dr); - - if (i2c_wait (I2C_WRITE) < 0) - break; - } - return i; -} - -static __inline__ int -__i2c_read (u8 *data, int length) -{ - int i; - - writeb(I2C_CR_MEN | I2C_CR_MSTA | - ((length == 1) ? I2C_CR_TXAK : 0), - &I2C->cr); - - /* dummy read */ - readb(&I2C->dr); - - for (i=0; i < length; i++) { - if (i2c_wait (I2C_READ) < 0) - break; - - /* Generate ack on last next to last byte */ - if (i == length - 2) - writeb(I2C_CR_MEN | I2C_CR_MSTA | - I2C_CR_TXAK, - &I2C->cr); - - /* Generate stop on last byte */ - if (i == length - 1) - writeb(I2C_CR_MEN | I2C_CR_TXAK, &I2C->cr); - - data[i] = readb(&I2C->dr); - } - return i; -} - -int -i2c_read (u8 dev, uint addr, int alen, u8 *data, int length) -{ - int i = 0; - u8 *a = (u8*)&addr; - - if (i2c_wait4bus () < 0) - goto exit; - - if (i2c_write_addr (dev, I2C_WRITE, 0) == 0) - goto exit; - - if (__i2c_write (&a[4 - alen], alen) != alen) - goto exit; - - if (i2c_write_addr (dev, I2C_READ, 1) == 0) - goto exit; - - i = __i2c_read (data, length); - - exit: - writeb(I2C_CR_MEN, &I2C->cr); - return !(i == length); -} - -int -i2c_write (u8 dev, uint addr, int alen, u8 *data, int length) -{ - int i = 0; - u8 *a = (u8*)&addr; - - if (i2c_wait4bus () < 0) - goto exit; - - if (i2c_write_addr (dev, I2C_WRITE, 0) == 0) - goto exit; - - if (__i2c_write (&a[4 - alen], alen) != alen) - goto exit; - - i = __i2c_write (data, length); - - exit: - writeb(I2C_CR_MEN, &I2C->cr); - return !(i == length); -} - -int i2c_probe (uchar chip) -{ - int tmp; - - /* - * Try to read the first location of the chip. The underlying - * driver doesn't appear to support sending just the chip address - * and looking for an <ACK> back. - */ - udelay(10000); - return i2c_read (chip, 0, 1, (uchar *)&tmp, 1); -} - -uchar i2c_reg_read (uchar i2c_addr, uchar reg) -{ - uchar buf[1]; - - i2c_read (i2c_addr, reg, 1, buf, 1); - - return (buf[0]); -} - -void i2c_reg_write (uchar i2c_addr, uchar reg, uchar val) -{ - i2c_write (i2c_addr, reg, 1, &val, 1); -} - -#endif /* CONFIG_HARD_I2C */ diff --git a/cpu/mpc83xx/interrupts.c b/cpu/mpc83xx/interrupts.c index 5a0babf..bb1fe1a 100644 --- a/cpu/mpc83xx/interrupts.c +++ b/cpu/mpc83xx/interrupts.c @@ -21,13 +21,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA - * - * Change log: - * - * Hacked for MPC8260 by Murray.Jensen@cmst.csiro.au, 22-Oct-00 - * - * 20050101: Eran Liberty (liberty@freescale.com) - * Initial file creating (porting from 85XX & 8260) */ #include <common.h> @@ -45,7 +38,7 @@ struct irq_action { int interrupt_init_cpu (unsigned *decrementer_count) { - volatile immap_t *immr = (immap_t *) CFG_IMMRBAR; + volatile immap_t *immr = (immap_t *) CFG_IMMR; *decrementer_count = (gd->bus_clk / 4) / CFG_HZ; diff --git a/cpu/mpc83xx/qe_io.c b/cpu/mpc83xx/qe_io.c new file mode 100644 index 0000000..8b3937a --- /dev/null +++ b/cpu/mpc83xx/qe_io.c @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2006 Freescale Semiconductor, Inc. + * + * Dave Liu <daveliu@freescale.com> + * based on source code of Shlomi Gridish + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include "common.h" +#include "asm/errno.h" +#include "asm/io.h" +#include "asm/immap_83xx.h" + +#if defined(CONFIG_QE) +#define NUM_OF_PINS 32 +void qe_config_iopin(u8 port, u8 pin, int dir, int open_drain, int assign) +{ + u32 pin_2bit_mask; + u32 pin_2bit_dir; + u32 pin_2bit_assign; + u32 pin_1bit_mask; + u32 tmp_val; + volatile immap_t *im = (volatile immap_t *)CFG_IMMR; + volatile qepio83xx_t *par_io = (volatile qepio83xx_t *)&im->qepio; + + /* Caculate pin location and 2bit mask and dir */ + pin_2bit_mask = (u32)(0x3 << (NUM_OF_PINS-(pin%(NUM_OF_PINS/2)+1)*2)); + pin_2bit_dir = (u32)(dir << (NUM_OF_PINS-(pin%(NUM_OF_PINS/2)+1)*2)); + + /* Setup the direction */ + tmp_val = (pin > (NUM_OF_PINS/2) - 1) ? \ + in_be32(&par_io->ioport[port].dir2) : + in_be32(&par_io->ioport[port].dir1); + + if (pin > (NUM_OF_PINS/2) -1) { + out_be32(&par_io->ioport[port].dir2, ~pin_2bit_mask & tmp_val); + out_be32(&par_io->ioport[port].dir2, pin_2bit_dir | tmp_val); + } else { + out_be32(&par_io->ioport[port].dir1, ~pin_2bit_mask & tmp_val); + out_be32(&par_io->ioport[port].dir1, pin_2bit_dir | tmp_val); + } + + /* Calculate pin location for 1bit mask */ + pin_1bit_mask = (u32)(1 << (NUM_OF_PINS - (pin+1))); + + /* Setup the open drain */ + tmp_val = in_be32(&par_io->ioport[port].podr); + if (open_drain) { + out_be32(&par_io->ioport[port].podr, pin_1bit_mask | tmp_val); + } else { + out_be32(&par_io->ioport[port].podr, ~pin_1bit_mask & tmp_val); + } + + /* Setup the assignment */ + tmp_val = (pin > (NUM_OF_PINS/2) - 1) ? + in_be32(&par_io->ioport[port].ppar2): + in_be32(&par_io->ioport[port].ppar1); + pin_2bit_assign = (u32)(assign + << (NUM_OF_PINS - (pin%(NUM_OF_PINS/2)+1)*2)); + + /* Clear and set 2 bits mask */ + if (pin > (NUM_OF_PINS/2) - 1) { + out_be32(&par_io->ioport[port].ppar2, ~pin_2bit_mask & tmp_val); + out_be32(&par_io->ioport[port].ppar2, pin_2bit_assign | tmp_val); + } else { + out_be32(&par_io->ioport[port].ppar1, ~pin_2bit_mask & tmp_val); + out_be32(&par_io->ioport[port].ppar1, pin_2bit_assign | tmp_val); + } +} + +#endif /* CONFIG_QE */ diff --git a/cpu/mpc83xx/resetvec.S b/cpu/mpc83xx/resetvec.S deleted file mode 100644 index 3dfcd0d..0000000 --- a/cpu/mpc83xx/resetvec.S +++ /dev/null @@ -1,6 +0,0 @@ - .section .resetvec,"ax" -#ifndef FIXME -#if 0 - b _start_e500 -#endif -#endif diff --git a/cpu/mpc83xx/spd_sdram.c b/cpu/mpc83xx/spd_sdram.c index 48624fe..d9b8753 100644 --- a/cpu/mpc83xx/spd_sdram.c +++ b/cpu/mpc83xx/spd_sdram.c @@ -1,8 +1,10 @@ /* + * (C) Copyright 2006 Freescale Semiconductor, Inc. + * * (C) Copyright 2006 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. * - * Copyright 2004 Freescale Semiconductor. + * Copyright (C) 2004-2006 Freescale Semiconductor, Inc. * (C) Copyright 2003 Motorola Inc. * Xianghua Xiao (X.Xiao@motorola.com) * @@ -23,11 +25,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA - * - * Change log: - * - * 20050101: Eran Liberty (liberty@freescale.com) - * Initial file creating (porting from 85XX & 8260) */ #include <common.h> @@ -39,7 +36,9 @@ #ifdef CONFIG_SPD_EEPROM -#if defined(CONFIG_DDR_ECC) +DECLARE_GLOBAL_DATA_PTR; + +#if defined(CONFIG_DDR_ECC) && !defined(CONFIG_ECC_INIT_VIA_DDRC) extern void dma_init(void); extern uint dma_check(void); extern int dma_xfer(void *dest, uint count, void *src); @@ -52,16 +51,16 @@ extern int dma_xfer(void *dest, uint count, void *src); /* * Convert picoseconds into clock cycles (rounding up if needed). */ - int picos_to_clk(int picos) { + unsigned int ddr_bus_clk; int clks; - clks = picos / (2000000000 / (get_bus_freq(0) / 1000)); - if (picos % (2000000000 / (get_bus_freq(0) / 1000)) != 0) { - clks++; - } + ddr_bus_clk = gd->ddr_clk >> 1; + clks = picos / ((1000000000 / ddr_bus_clk) * 1000); + if (picos % ((1000000000 / ddr_bus_clk) * 1000) != 0) + clks++; return clks; } @@ -103,60 +102,141 @@ static void spd_debug(spd_eeprom_t *spd) long int spd_sdram() { - volatile immap_t *immap = (immap_t *)CFG_IMMRBAR; - volatile ddr8349_t *ddr = &immap->ddr; - volatile law8349_t *ecm = &immap->sysconf.ddrlaw[0]; + volatile immap_t *immap = (immap_t *)CFG_IMMR; + volatile ddr83xx_t *ddr = &immap->ddr; + volatile law83xx_t *ecm = &immap->sysconf.ddrlaw[0]; spd_eeprom_t spd; - unsigned tmp, tmp1; + unsigned int n_ranks; + unsigned int odt_rd_cfg, odt_wr_cfg; + unsigned char twr_clk, twtr_clk; + unsigned char sdram_type; unsigned int memsize; unsigned int law_size; - unsigned char caslat; - unsigned int trfc, trfc_clk, trfc_low; - + unsigned char caslat, caslat_ctrl; + unsigned int trfc, trfc_clk, trfc_low, trfc_high; + unsigned int trcd_clk, trtp_clk; + unsigned char cke_min_clk; + unsigned char add_lat, wr_lat; + unsigned char wr_data_delay; + unsigned char four_act; + unsigned char cpo; + unsigned char burstlen; + unsigned char odt_cfg, mode_odt_enable; + unsigned int max_bus_clk; + unsigned int max_data_rate, effective_data_rate; + unsigned int ddrc_clk; + unsigned int refresh_clk; + unsigned int sdram_cfg; + unsigned int ddrc_ecc_enable; + unsigned int pvr = get_pvr(); + + /* Read SPD parameters with I2C */ CFG_READ_SPD(SPD_EEPROM_ADDRESS, 0, 1, (uchar *) & spd, sizeof (spd)); #ifdef SPD_DEBUG spd_debug(&spd); #endif - if (spd.nrows > 2) { - puts("DDR:Only two chip selects are supported on ADS.\n"); + /* Check the memory type */ + if (spd.mem_type != SPD_MEMTYPE_DDR && spd.mem_type != SPD_MEMTYPE_DDR2) { + printf("DDR: Module mem type is %02X\n", spd.mem_type); + return 0; + } + + /* Check the number of physical bank */ + if (spd.mem_type == SPD_MEMTYPE_DDR) { + n_ranks = spd.nrows; + } else { + n_ranks = (spd.nrows & 0x7) + 1; + } + + if (n_ranks > 2) { + printf("DDR: The number of physical bank is %02X\n", n_ranks); + return 0; + } + + /* Check if the number of row of the module is in the range of DDRC */ + if (spd.nrow_addr < 12 || spd.nrow_addr > 15) { + printf("DDR: Row number is out of range of DDRC, row=%02X\n", + spd.nrow_addr); return 0; } - if (spd.nrow_addr < 12 - || spd.nrow_addr > 14 - || spd.ncol_addr < 8 - || spd.ncol_addr > 11) { - puts("DDR:Row or Col number unsupported.\n"); + /* Check if the number of col of the module is in the range of DDRC */ + if (spd.ncol_addr < 8 || spd.ncol_addr > 11) { + printf("DDR: Col number is out of range of DDRC, col=%02X\n", + spd.ncol_addr); return 0; } +#ifdef CFG_DDRCDR_VALUE + /* + * Adjust DDR II IO voltage biasing. It just makes it work. + */ + if(spd.mem_type == SPD_MEMTYPE_DDR2) { + immap->sysconf.ddrcdr = CFG_DDRCDR_VALUE; + } +#endif + + /* + * ODT configuration recommendation from DDR Controller Chapter. + */ + odt_rd_cfg = 0; /* Never assert ODT */ + odt_wr_cfg = 0; /* Never assert ODT */ + if (spd.mem_type == SPD_MEMTYPE_DDR2) { + odt_wr_cfg = 1; /* Assert ODT on writes to CSn */ + } + + /* Setup DDR chip select register */ +#ifdef CFG_83XX_DDR_USES_CS0 + ddr->csbnds[0].csbnds = (banksize(spd.row_dens) >> 24) - 1; + ddr->cs_config[0] = ( 1 << 31 + | (odt_rd_cfg << 20) + | (odt_wr_cfg << 16) + | (spd.nrow_addr - 12) << 8 + | (spd.ncol_addr - 8) ); + debug("\n"); + debug("cs0_bnds = 0x%08x\n",ddr->csbnds[0].csbnds); + debug("cs0_config = 0x%08x\n",ddr->cs_config[0]); + + if (n_ranks == 2) { + ddr->csbnds[1].csbnds = ( (banksize(spd.row_dens) >> 8) + | ((banksize(spd.row_dens) >> 23) - 1) ); + ddr->cs_config[1] = ( 1<<31 + | (odt_rd_cfg << 20) + | (odt_wr_cfg << 16) + | (spd.nrow_addr-12) << 8 + | (spd.ncol_addr-8) ); + debug("cs1_bnds = 0x%08x\n",ddr->csbnds[1].csbnds); + debug("cs1_config = 0x%08x\n",ddr->cs_config[1]); + } + +#else ddr->csbnds[2].csbnds = (banksize(spd.row_dens) >> 24) - 1; ddr->cs_config[2] = ( 1 << 31 + | (odt_rd_cfg << 20) + | (odt_wr_cfg << 16) | (spd.nrow_addr - 12) << 8 | (spd.ncol_addr - 8) ); debug("\n"); debug("cs2_bnds = 0x%08x\n",ddr->csbnds[2].csbnds); debug("cs2_config = 0x%08x\n",ddr->cs_config[2]); - if (spd.nrows == 2) { + if (n_ranks == 2) { ddr->csbnds[3].csbnds = ( (banksize(spd.row_dens) >> 8) | ((banksize(spd.row_dens) >> 23) - 1) ); ddr->cs_config[3] = ( 1<<31 + | (odt_rd_cfg << 20) + | (odt_wr_cfg << 16) | (spd.nrow_addr-12) << 8 | (spd.ncol_addr-8) ); debug("cs3_bnds = 0x%08x\n",ddr->csbnds[3].csbnds); debug("cs3_config = 0x%08x\n",ddr->cs_config[3]); } - - if (spd.mem_type != 0x07) { - puts("No DDR module found!\n"); - return 0; - } +#endif /* * Figure out memory size in Megabytes. */ - memsize = spd.nrows * banksize(spd.row_dens) / 0x100000; + memsize = n_ranks * banksize(spd.row_dens) / 0x100000; /* * First supported LAW size is 16M, at LAWAR_SIZE_16M == 23. @@ -172,218 +252,520 @@ long int spd_sdram() debug("DDR:ar=0x%08x\n", ecm->ar); /* - * find the largest CAS + * Find the largest CAS by locating the highest 1 bit + * in the spd.cas_lat field. Translate it to a DDR + * controller field value: + * + * CAS Lat DDR I DDR II Ctrl + * Clocks SPD Bit SPD Bit Value + * ------- ------- ------- ----- + * 1.0 0 0001 + * 1.5 1 0010 + * 2.0 2 2 0011 + * 2.5 3 0100 + * 3.0 4 3 0101 + * 3.5 5 0110 + * 4.0 6 4 0111 + * 4.5 1000 + * 5.0 5 1001 */ - if(spd.cas_lat & 0x40) { - caslat = 7; - } else if (spd.cas_lat & 0x20) { - caslat = 6; - } else if (spd.cas_lat & 0x10) { - caslat = 5; - } else if (spd.cas_lat & 0x08) { - caslat = 4; - } else if (spd.cas_lat & 0x04) { - caslat = 3; - } else if (spd.cas_lat & 0x02) { - caslat = 2; - } else if (spd.cas_lat & 0x01) { - caslat = 1; - } else { - puts("DDR:no valid CAS Latency information.\n"); + caslat = __ilog2(spd.cas_lat); + if ((spd.mem_type == SPD_MEMTYPE_DDR) + && (caslat > 6)) { + printf("DDR I: Invalid SPD CAS Latency: 0x%x.\n", spd.cas_lat); + return 0; + } else if (spd.mem_type == SPD_MEMTYPE_DDR2 + && (caslat < 2 || caslat > 5)) { + printf("DDR II: Invalid SPD CAS Latency: 0x%x.\n", + spd.cas_lat); return 0; } + debug("DDR: caslat SPD bit is %d\n", caslat); + + max_bus_clk = 1000 *10 / (((spd.clk_cycle & 0xF0) >> 4) * 10 + + (spd.clk_cycle & 0x0f)); + max_data_rate = max_bus_clk * 2; + + debug("DDR:Module maximum data rate is: %dMhz\n", max_data_rate); + + ddrc_clk = gd->ddr_clk / 1000000; + effective_data_rate = 0; + + if (max_data_rate >= 390 && max_data_rate < 460) { /* it is DDR 400 */ + if (ddrc_clk <= 460 && ddrc_clk > 350) { + /* DDR controller clk at 350~460 */ + effective_data_rate = 400; /* 5ns */ + caslat = caslat; + } else if (ddrc_clk <= 350 && ddrc_clk > 280) { + /* DDR controller clk at 280~350 */ + effective_data_rate = 333; /* 6ns */ + if (spd.clk_cycle2 == 0x60) + caslat = caslat - 1; + else + caslat = caslat; + } else if (ddrc_clk <= 280 && ddrc_clk > 230) { + /* DDR controller clk at 230~280 */ + effective_data_rate = 266; /* 7.5ns */ + if (spd.clk_cycle3 == 0x75) + caslat = caslat - 2; + else if (spd.clk_cycle2 == 0x75) + caslat = caslat - 1; + else + caslat = caslat; + } else if (ddrc_clk <= 230 && ddrc_clk > 90) { + /* DDR controller clk at 90~230 */ + effective_data_rate = 200; /* 10ns */ + if (spd.clk_cycle3 == 0xa0) + caslat = caslat - 2; + else if (spd.clk_cycle2 == 0xa0) + caslat = caslat - 1; + else + caslat = caslat; + } + } else if (max_data_rate >= 323) { /* it is DDR 333 */ + if (ddrc_clk <= 350 && ddrc_clk > 280) { + /* DDR controller clk at 280~350 */ + effective_data_rate = 333; /* 6ns */ + caslat = caslat; + } else if (ddrc_clk <= 280 && ddrc_clk > 230) { + /* DDR controller clk at 230~280 */ + effective_data_rate = 266; /* 7.5ns */ + if (spd.clk_cycle2 == 0x75) + caslat = caslat - 1; + else + caslat = caslat; + } else if (ddrc_clk <= 230 && ddrc_clk > 90) { + /* DDR controller clk at 90~230 */ + effective_data_rate = 200; /* 10ns */ + if (spd.clk_cycle3 == 0xa0) + caslat = caslat - 2; + else if (spd.clk_cycle2 == 0xa0) + caslat = caslat - 1; + else + caslat = caslat; + } + } else if (max_data_rate >= 256) { /* it is DDR 266 */ + if (ddrc_clk <= 350 && ddrc_clk > 280) { + /* DDR controller clk at 280~350 */ + printf("DDR: DDR controller freq is more than " + "max data rate of the module\n"); + return 0; + } else if (ddrc_clk <= 280 && ddrc_clk > 230) { + /* DDR controller clk at 230~280 */ + effective_data_rate = 266; /* 7.5ns */ + caslat = caslat; + } else if (ddrc_clk <= 230 && ddrc_clk > 90) { + /* DDR controller clk at 90~230 */ + effective_data_rate = 200; /* 10ns */ + if (spd.clk_cycle2 == 0xa0) + caslat = caslat - 1; + } + } else if (max_data_rate >= 190) { /* it is DDR 200 */ + if (ddrc_clk <= 350 && ddrc_clk > 230) { + /* DDR controller clk at 230~350 */ + printf("DDR: DDR controller freq is more than " + "max data rate of the module\n"); + return 0; + } else if (ddrc_clk <= 230 && ddrc_clk > 90) { + /* DDR controller clk at 90~230 */ + effective_data_rate = 200; /* 10ns */ + caslat = caslat; + } + } - tmp = 20000 / (((spd.clk_cycle & 0xF0) >> 4) * 10 - + (spd.clk_cycle & 0x0f)); - debug("DDR:Module maximum data rate is: %dMhz\n", tmp); - - tmp1 = get_bus_freq(0) / 1000000; - if (tmp1 < 230 && tmp1 >= 90 && tmp >= 230) { - /* 90~230 range, treated as DDR 200 */ - if (spd.clk_cycle3 == 0xa0) - caslat -= 2; - else if(spd.clk_cycle2 == 0xa0) - caslat--; - } else if (tmp1 < 280 && tmp1 >= 230 && tmp >= 280) { - /* 230-280 range, treated as DDR 266 */ - if (spd.clk_cycle3 == 0x75) - caslat -= 2; - else if (spd.clk_cycle2 == 0x75) - caslat--; - } else if (tmp1 < 350 && tmp1 >= 280 && tmp >= 350) { - /* 280~350 range, treated as DDR 333 */ - if (spd.clk_cycle3 == 0x60) - caslat -= 2; - else if (spd.clk_cycle2 == 0x60) - caslat--; - } else if (tmp1 < 90 || tmp1 >= 350) { - /* DDR rate out-of-range */ - puts("DDR:platform frequency is not fit for DDR rate\n"); - return 0; + debug("DDR:Effective data rate is: %dMhz\n", effective_data_rate); + debug("DDR:The MSB 1 of CAS Latency is: %d\n", caslat); + + /* + * Errata DDR6 work around: input enable 2 cycles earlier. + * including MPC834x Rev1.0/1.1 and MPC8360 Rev1.1/1.2. + */ + if(PVR_MAJ(pvr) <= 1 && spd.mem_type == SPD_MEMTYPE_DDR){ + if (caslat == 2) + ddr->debug_reg = 0x201c0000; /* CL=2 */ + else if (caslat == 3) + ddr->debug_reg = 0x202c0000; /* CL=2.5 */ + else if (caslat == 4) + ddr->debug_reg = 0x202c0000; /* CL=3.0 */ + + __asm__ __volatile__ ("sync"); + + debug("Errata DDR6 (debug_reg=0x%08x)\n", ddr->debug_reg); } /* - * note: caslat must also be programmed into ddr->sdram_mode - * register. - * - * note: WRREC(Twr) and WRTORD(Twtr) are not in SPD, - * use conservative value here. + * Convert caslat clocks to DDR controller value. + * Force caslat_ctrl to be DDR Controller field-sized. + */ + if (spd.mem_type == SPD_MEMTYPE_DDR) { + caslat_ctrl = (caslat + 1) & 0x07; + } else { + caslat_ctrl = (2 * caslat - 1) & 0x0f; + } + + debug("DDR: effective data rate is %d MHz\n", effective_data_rate); + debug("DDR: caslat SPD bit is %d, controller field is 0x%x\n", + caslat, caslat_ctrl); + + /* + * Timing Config 0. + * Avoid writing for DDR I. + */ + if (spd.mem_type == SPD_MEMTYPE_DDR2) { + unsigned char taxpd_clk = 8; /* By the book. */ + unsigned char tmrd_clk = 2; /* By the book. */ + unsigned char act_pd_exit = 2; /* Empirical? */ + unsigned char pre_pd_exit = 6; /* Empirical? */ + + ddr->timing_cfg_0 = (0 + | ((act_pd_exit & 0x7) << 20) /* ACT_PD_EXIT */ + | ((pre_pd_exit & 0x7) << 16) /* PRE_PD_EXIT */ + | ((taxpd_clk & 0xf) << 8) /* ODT_PD_EXIT */ + | ((tmrd_clk & 0xf) << 0) /* MRS_CYC */ + ); + debug("DDR: timing_cfg_0 = 0x%08x\n", ddr->timing_cfg_0); + } + + /* + * For DDR I, WRREC(Twr) and WRTORD(Twtr) are not in SPD, + * use conservative value. + * For DDR II, they are bytes 36 and 37, in quarter nanos. */ - trfc = spd.trfc * 1000; /* up to ps */ + + if (spd.mem_type == SPD_MEMTYPE_DDR) { + twr_clk = 3; /* Clocks */ + twtr_clk = 1; /* Clocks */ + } else { + twr_clk = picos_to_clk(spd.twr * 250); + twtr_clk = picos_to_clk(spd.twtr * 250); + } + + /* + * Calculate Trfc, in picos. + * DDR I: Byte 42 straight up in ns. + * DDR II: Byte 40 and 42 swizzled some, in ns. + */ + if (spd.mem_type == SPD_MEMTYPE_DDR) { + trfc = spd.trfc * 1000; /* up to ps */ + } else { + unsigned int byte40_table_ps[8] = { + 0, + 250, + 330, + 500, + 660, + 750, + 0, + 0 + }; + + trfc = (((spd.trctrfc_ext & 0x1) * 256) + spd.trfc) * 1000 + + byte40_table_ps[(spd.trctrfc_ext >> 1) & 0x7]; + } trfc_clk = picos_to_clk(trfc); + + /* + * Trcd, Byte 29, from quarter nanos to ps and clocks. + */ + trcd_clk = picos_to_clk(spd.trcd * 250) & 0x7; + + /* + * Convert trfc_clk to DDR controller fields. DDR I should + * fit in the REFREC field (16-19) of TIMING_CFG_1, but the + * 83xx controller has an extended REFREC field of three bits. + * The controller automatically adds 8 clocks to this value, + * so preadjust it down 8 first before splitting it up. + */ trfc_low = (trfc_clk - 8) & 0xf; + trfc_high = ((trfc_clk - 8) >> 4) & 0x3; ddr->timing_cfg_1 = - (((picos_to_clk(spd.trp * 250) & 0x07) << 28 ) | - ((picos_to_clk(spd.tras * 1000) & 0x0f ) << 24 ) | - ((picos_to_clk(spd.trcd * 250) & 0x07) << 20 ) | - ((caslat & 0x07) << 16 ) | - (trfc_low << 12 ) | - ( 0x300 ) | - ((picos_to_clk(spd.trrd * 250) & 0x07) << 4) | 1); + (((picos_to_clk(spd.trp * 250) & 0x07) << 28 ) | /* PRETOACT */ + ((picos_to_clk(spd.tras * 1000) & 0x0f ) << 24 ) | /* ACTTOPRE */ + (trcd_clk << 20 ) | /* ACTTORW */ + (caslat_ctrl << 16 ) | /* CASLAT */ + (trfc_low << 12 ) | /* REFEC */ + ((twr_clk & 0x07) << 8) | /* WRRREC */ + ((picos_to_clk(spd.trrd * 250) & 0x07) << 4) | /* ACTTOACT */ + ((twtr_clk & 0x07) << 0) /* WRTORD */ + ); + + /* + * Additive Latency + * For DDR I, 0. + * For DDR II, with ODT enabled, use "a value" less than ACTTORW, + * which comes from Trcd, and also note that: + * add_lat + caslat must be >= 4 + */ + add_lat = 0; + if (spd.mem_type == SPD_MEMTYPE_DDR2 + && (odt_wr_cfg || odt_rd_cfg) + && (caslat < 4)) { + add_lat = trcd_clk - 1; + if ((add_lat + caslat) < 4) { + add_lat = 0; + } + } + + /* + * Write Data Delay + * Historically 0x2 == 4/8 clock delay. + * Empirically, 0x3 == 6/8 clock delay is suggested for DDR I 266. + */ + wr_data_delay = 2; + + /* + * Write Latency + * Read to Precharge + * Minimum CKE Pulse Width. + * Four Activate Window + */ + if (spd.mem_type == SPD_MEMTYPE_DDR) { + /* + * This is a lie. It should really be 1, but if it is + * set to 1, bits overlap into the old controller's + * otherwise unused ACSM field. If we leave it 0, then + * the HW will magically treat it as 1 for DDR 1. Oh Yea. + */ + wr_lat = 0; + + trtp_clk = 2; /* By the book. */ + cke_min_clk = 1; /* By the book. */ + four_act = 1; /* By the book. */ + + } else { + wr_lat = caslat - 1; + + /* Convert SPD value from quarter nanos to picos. */ + trtp_clk = picos_to_clk(spd.trtp * 250); + + cke_min_clk = 3; /* By the book. */ + four_act = picos_to_clk(37500); /* By the book. 1k pages? */ + } + + /* + * Empirically set ~MCAS-to-preamble override for DDR 2. + * Your milage will vary. + */ + cpo = 0; + if (spd.mem_type == SPD_MEMTYPE_DDR2) { + if (effective_data_rate == 266 || effective_data_rate == 333) { + cpo = 0x7; /* READ_LAT + 5/4 */ + } else if (effective_data_rate == 400) { + cpo = 0x9; /* READ_LAT + 7/4 */ + } else { + /* Automatic calibration */ + cpo = 0x1f; + } + } - ddr->timing_cfg_2 = 0x00000800; + ddr->timing_cfg_2 = (0 + | ((add_lat & 0x7) << 28) /* ADD_LAT */ + | ((cpo & 0x1f) << 23) /* CPO */ + | ((wr_lat & 0x7) << 19) /* WR_LAT */ + | ((trtp_clk & 0x7) << 13) /* RD_TO_PRE */ + | ((wr_data_delay & 0x7) << 10) /* WR_DATA_DELAY */ + | ((cke_min_clk & 0x7) << 6) /* CKE_PLS */ + | ((four_act & 0x1f) << 0) /* FOUR_ACT */ + ); debug("DDR:timing_cfg_1=0x%08x\n", ddr->timing_cfg_1); debug("DDR:timing_cfg_2=0x%08x\n", ddr->timing_cfg_2); - /* - * Only DDR I is supported - * DDR I and II have different mode-register-set definition + /* Check DIMM data bus width */ + if (spd.dataw_lsb == 0x20) { + burstlen = 0x03; /* 32 bit data bus, burst len is 8 */ + printf("\n DDR DIMM: data bus width is 32 bit"); + } else { + burstlen = 0x02; /* Others act as 64 bit bus, burst len is 4 */ + printf("\n DDR DIMM: data bus width is 64 bit"); + } + + /* Is this an ECC DDR chip? */ + if (spd.config == 0x02) + printf(" with ECC\n"); + else + printf(" without ECC\n"); + + /* Burst length is always 4 for 64 bit data bus, 8 for 32 bit data bus, + Burst type is sequential */ - switch(caslat) { - case 2: - tmp = 0x50; /* 1.5 */ - break; - case 3: - tmp = 0x20; /* 2.0 */ - break; - case 4: - tmp = 0x60; /* 2.5 */ - break; - case 5: - tmp = 0x30; /* 3.0 */ - break; - default: - puts("DDR:only CAS Latency 1.5, 2.0, 2.5, 3.0 is supported.\n"); - return 0; + if (spd.mem_type == SPD_MEMTYPE_DDR) { + switch (caslat) { + case 1: + ddr->sdram_mode = 0x50 | burstlen; /* CL=1.5 */ + break; + case 2: + ddr->sdram_mode = 0x20 | burstlen; /* CL=2.0 */ + break; + case 3: + ddr->sdram_mode = 0x60 | burstlen; /* CL=2.5 */ + break; + case 4: + ddr->sdram_mode = 0x30 | burstlen; /* CL=3.0 */ + break; + default: + printf("DDR:only CL 1.5, 2.0, 2.5, 3.0 is supported\n"); + return 0; + } + } else { + mode_odt_enable = 0x0; /* Default disabled */ + if (odt_wr_cfg || odt_rd_cfg) { + /* + * Bits 6 and 2 in Extended MRS(1) + * Bit 2 == 0x04 == 75 Ohm, with 2 DIMM modules. + * Bit 6 == 0x40 == 150 Ohm, with 1 DIMM module. + */ + mode_odt_enable = 0x40; /* 150 Ohm */ + } + + ddr->sdram_mode = + (0 + | (1 << (16 + 10)) /* DQS Differential disable */ + | (add_lat << (16 + 3)) /* Additive Latency in EMRS1 */ + | (mode_odt_enable << 16) /* ODT Enable in EMRS1 */ + | ((twr_clk >> 1) << 9) /* Write Recovery Autopre */ + | (caslat << 4) /* caslat */ + | (burstlen << 0) /* Burst length */ + ); } -#if defined (CONFIG_DDR_32BIT) - /* set burst length to 8 for 32-bit data path */ - tmp |= 0x03; -#else - /* set burst length to 4 - default for 64-bit data path */ - tmp |= 0x02; -#endif - ddr->sdram_mode = tmp; debug("DDR:sdram_mode=0x%08x\n", ddr->sdram_mode); - switch(spd.refresh) { - case 0x00: - case 0x80: - tmp = picos_to_clk(15625000); - break; - case 0x01: - case 0x81: - tmp = picos_to_clk(3900000); - break; - case 0x02: - case 0x82: - tmp = picos_to_clk(7800000); - break; - case 0x03: - case 0x83: - tmp = picos_to_clk(31300000); - break; - case 0x04: - case 0x84: - tmp = picos_to_clk(62500000); - break; - case 0x05: - case 0x85: - tmp = picos_to_clk(125000000); - break; - default: - tmp = 0x512; - break; + /* + * Clear EMRS2 and EMRS3. + */ + ddr->sdram_mode2 = 0; + debug("DDR: sdram_mode2 = 0x%08x\n", ddr->sdram_mode2); + + switch (spd.refresh) { + case 0x00: + case 0x80: + refresh_clk = picos_to_clk(15625000); + break; + case 0x01: + case 0x81: + refresh_clk = picos_to_clk(3900000); + break; + case 0x02: + case 0x82: + refresh_clk = picos_to_clk(7800000); + break; + case 0x03: + case 0x83: + refresh_clk = picos_to_clk(31300000); + break; + case 0x04: + case 0x84: + refresh_clk = picos_to_clk(62500000); + break; + case 0x05: + case 0x85: + refresh_clk = picos_to_clk(125000000); + break; + default: + refresh_clk = 0x512; + break; } /* * Set BSTOPRE to 0x100 for page mode * If auto-charge is used, set BSTOPRE = 0 */ - ddr->sdram_interval = ((tmp & 0x3fff) << 16) | 0x100; + ddr->sdram_interval = ((refresh_clk & 0x3fff) << 16) | 0x100; debug("DDR:sdram_interval=0x%08x\n", ddr->sdram_interval); /* - * Is this an ECC DDR chip? + * SDRAM Cfg 2 */ -#if defined(CONFIG_DDR_ECC) - if (spd.config == 0x02) { - /* disable error detection */ - ddr->err_disable = ~ECC_ERROR_ENABLE; - - /* set single bit error threshold to maximum value, - * reset counter to zero */ - ddr->err_sbe = (255 << ECC_ERROR_MAN_SBET_SHIFT) | - (0 << ECC_ERROR_MAN_SBEC_SHIFT); + odt_cfg = 0; + if (odt_rd_cfg | odt_wr_cfg) { + odt_cfg = 0x2; /* ODT to IOs during reads */ } - debug("DDR:err_disable=0x%08x\n", ddr->err_disable); - debug("DDR:err_sbe=0x%08x\n", ddr->err_sbe); + if (spd.mem_type == SPD_MEMTYPE_DDR2) { + ddr->sdram_cfg2 = (0 + | (0 << 26) /* True DQS */ + | (odt_cfg << 21) /* ODT only read */ + | (1 << 12) /* 1 refresh at a time */ + ); + + debug("DDR: sdram_cfg2 = 0x%08x\n", ddr->sdram_cfg2); + } + +#ifdef CFG_DDR_SDRAM_CLK_CNTL /* Optional platform specific value */ + ddr->sdram_clk_cntl = CFG_DDR_SDRAM_CLK_CNTL; +#else + /* SS_EN = 0, source synchronous disable + * CLK_ADJST = 0, MCK/MCK# is launched aligned with addr/cmd + */ + ddr->sdram_clk_cntl = 0x00000000; #endif - asm("sync;isync"); + debug("DDR:sdram_clk_cntl=0x%08x\n", ddr->sdram_clk_cntl); - udelay(500); + asm("sync;isync"); - /* - * SS_EN=1, - * CLK_ADJST = 2-MCK/MCK_B, is lauched 1/2 of one SDRAM - * clock cycle after address/command - */ - /*ddr->sdram_clk_cntl = 0x82000000;*/ - ddr->sdram_clk_cntl = (DDR_SDRAM_CLK_CNTL_SS_EN|DDR_SDRAM_CLK_CNTL_CLK_ADJUST_05); + udelay(600); /* - * Figure out the settings for the sdram_cfg register. Build up - * the entire register in 'tmp' before writing since the write into + * Figure out the settings for the sdram_cfg register. Build up + * the value in 'sdram_cfg' before writing since the write into * the register will actually enable the memory controller, and all * settings must be done before enabling. * * sdram_cfg[0] = 1 (ddr sdram logic enable) * sdram_cfg[1] = 1 (self-refresh-enable) - * sdram_cfg[6:7] = 2 (SDRAM type = DDR SDRAM) + * sdram_cfg[5:7] = (SDRAM type = DDR SDRAM) + * 010 DDR 1 SDRAM + * 011 DDR 2 SDRAM + * sdram_cfg[12] = 0 (32_BE =0 , 64 bit bus mode) + * sdram_cfg[13] = 0 (8_BE =0, 4-beat bursts) */ - tmp = 0xc2000000; + if (spd.mem_type == SPD_MEMTYPE_DDR) + sdram_type = 2; + else + sdram_type = 3; -#if defined (CONFIG_DDR_32BIT) - /* in 32-Bit mode burst len is 8 beats */ - tmp |= (SDRAM_CFG_32_BE | SDRAM_CFG_8_BE); -#endif - /* - * sdram_cfg[3] = RD_EN - registered DIMM enable - * A value of 0x26 indicates micron registered DIMMS (micron.com) - */ - if (spd.mod_attr == 0x26) { - tmp |= 0x10000000; - } + sdram_cfg = (0 + | (1 << 31) /* DDR enable */ + | (1 << 30) /* Self refresh */ + | (sdram_type << 24) /* SDRAM type */ + ); + + /* sdram_cfg[3] = RD_EN - registered DIMM enable */ + if (spd.mod_attr & 0x02) + sdram_cfg |= 0x10000000; + + /* The DIMM is 32bit width */ + if (spd.dataw_lsb == 0x20) + sdram_cfg |= 0x000C0000; + + ddrc_ecc_enable = 0; #if defined(CONFIG_DDR_ECC) - /* - * If the user wanted ECC (enabled via sdram_cfg[2]) - */ + /* Enable ECC with sdram_cfg[2] */ if (spd.config == 0x02) { - tmp |= SDRAM_CFG_ECC_EN; + sdram_cfg |= 0x20000000; + ddrc_ecc_enable = 1; + /* disable error detection */ + ddr->err_disable = ~ECC_ERROR_ENABLE; + /* set single bit error threshold to maximum value, + * reset counter to zero */ + ddr->err_sbe = (255 << ECC_ERROR_MAN_SBET_SHIFT) | + (0 << ECC_ERROR_MAN_SBEC_SHIFT); } + + debug("DDR:err_disable=0x%08x\n", ddr->err_disable); + debug("DDR:err_sbe=0x%08x\n", ddr->err_sbe); #endif + printf(" DDRC ECC mode: %s\n", ddrc_ecc_enable ? "ON":"OFF"); #if defined(CONFIG_DDR_2T_TIMING) /* * Enable 2T timing by setting sdram_cfg[16]. */ - tmp |= SDRAM_CFG_2T_EN; + sdram_cfg |= SDRAM_CFG_2T_EN; #endif - - ddr->sdram_cfg = tmp; + /* Enable controller, and GO! */ + ddr->sdram_cfg = sdram_cfg; asm("sync;isync"); udelay(500); @@ -392,8 +774,7 @@ long int spd_sdram() } #endif /* CONFIG_SPD_EEPROM */ - -#if defined(CONFIG_DDR_ECC) +#if defined(CONFIG_DDR_ECC) && !defined(CONFIG_ECC_INIT_VIA_DDRC) /* * Use timebase counter, get_timer() is not availabe * at this point of initialization yet. @@ -429,74 +810,48 @@ static __inline__ unsigned long get_tbms (void) /* #define CONFIG_DDR_ECC_INIT_VIA_DMA */ void ddr_enable_ecc(unsigned int dram_size) { - uint *p; - volatile immap_t *immap = (immap_t *)CFG_IMMRBAR; - volatile ddr8349_t *ddr = &immap->ddr; + volatile immap_t *immap = (immap_t *)CFG_IMMR; + volatile ddr83xx_t *ddr= &immap->ddr; unsigned long t_start, t_end; + register u64 *p; + register uint size; + unsigned int pattern[2]; #if defined(CONFIG_DDR_ECC_INIT_VIA_DMA) uint i; #endif - - debug("Initialize a Cachline in DRAM\n"); icache_enable(); - -#if defined(CONFIG_DDR_ECC_INIT_VIA_DMA) - /* Initialise DMA for direct Transfers */ - dma_init(); -#endif - t_start = get_tbms(); + pattern[0] = 0xdeadbeef; + pattern[1] = 0xdeadbeef; #if !defined(CONFIG_DDR_ECC_INIT_VIA_DMA) - debug("DDR init: Cache flush method\n"); - for (p = 0; p < (uint *)(dram_size); p++) { - if (((unsigned int)p & 0x1f) == 0) { - ppcDcbz((unsigned long) p); - } - - /* write pattern to cache and flush */ - *p = (unsigned int)0xdeadbeef; - - if (((unsigned int)p & 0x1c) == 0x1c) { - ppcDcbf((unsigned long) p); - } + debug("ddr init: CPU FP write method\n"); + size = dram_size; + for (p = 0; p < (u64*)(size); p++) { + ppcDWstore((u32*)p, pattern); } + __asm__ __volatile__ ("sync"); #else - printf("DDR init: DMA method\n"); - for (p = 0; p < (uint *)(8 * 1024); p++) { - /* zero one data cache line */ - if (((unsigned int)p & 0x1f) == 0) { - ppcDcbz((unsigned long)p); - } - - /* write pattern to it and flush */ - *p = (unsigned int)0xdeadbeef; - - if (((unsigned int)p & 0x1c) == 0x1c) { - ppcDcbf((unsigned long)p); - } + debug("ddr init: DMA method\n"); + size = 0x2000; + for (p = 0; p < (u64*)(size); p++) { + ppcDWstore((u32*)p, pattern); } + __asm__ __volatile__ ("sync"); - /* 8K */ - dma_xfer((uint *)0x2000, 0x2000, (uint *)0); - /* 16K */ - dma_xfer((uint *)0x4000, 0x4000, (uint *)0); - /* 32K */ - dma_xfer((uint *)0x8000, 0x8000, (uint *)0); - /* 64K */ - dma_xfer((uint *)0x10000, 0x10000, (uint *)0); - /* 128k */ - dma_xfer((uint *)0x20000, 0x20000, (uint *)0); - /* 256k */ - dma_xfer((uint *)0x40000, 0x40000, (uint *)0); - /* 512k */ - dma_xfer((uint *)0x80000, 0x80000, (uint *)0); - /* 1M */ - dma_xfer((uint *)0x100000, 0x100000, (uint *)0); - /* 2M */ - dma_xfer((uint *)0x200000, 0x200000, (uint *)0); - /* 4M */ - dma_xfer((uint *)0x400000, 0x400000, (uint *)0); + /* Initialise DMA for direct transfer */ + dma_init(); + /* Start DMA to transfer */ + dma_xfer((uint *)0x2000, 0x2000, (uint *)0); /* 8K */ + dma_xfer((uint *)0x4000, 0x4000, (uint *)0); /* 16K */ + dma_xfer((uint *)0x8000, 0x8000, (uint *)0); /* 32K */ + dma_xfer((uint *)0x10000, 0x10000, (uint *)0); /* 64K */ + dma_xfer((uint *)0x20000, 0x20000, (uint *)0); /* 128K */ + dma_xfer((uint *)0x40000, 0x40000, (uint *)0); /* 256K */ + dma_xfer((uint *)0x80000, 0x80000, (uint *)0); /* 512K */ + dma_xfer((uint *)0x100000, 0x100000, (uint *)0); /* 1M */ + dma_xfer((uint *)0x200000, 0x200000, (uint *)0); /* 2M */ + dma_xfer((uint *)0x400000, 0x400000, (uint *)0); /* 4M */ for (i = 1; i < dram_size / 0x800000; i++) { dma_xfer((uint *)(0x800000*i), 0x800000, (uint *)0); diff --git a/cpu/mpc83xx/speed.c b/cpu/mpc83xx/speed.c index ad6b3f6..c759930 100644 --- a/cpu/mpc83xx/speed.c +++ b/cpu/mpc83xx/speed.c @@ -2,7 +2,7 @@ * (C) Copyright 2000-2002 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. * - * Copyright 2004 Freescale Semiconductor, Inc. + * Copyright (C) 2004-2006 Freescale Semiconductor, Inc. * * See file CREDITS for list of people who contributed to this * project. @@ -21,11 +21,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA - * - * Change log: - * - * 20050101: Eran Liberty (liberty@freescale.com) - * Initial file creating (porting from 85XX & 8260) */ #include <common.h> @@ -53,38 +48,38 @@ typedef enum { typedef struct { mult_t core_csb_ratio; - mult_t vco_divider; + mult_t vco_divider; } corecnf_t; corecnf_t corecnf_tab[] = { - { _byp, _byp}, /* 0x00 */ - { _byp, _byp}, /* 0x01 */ - { _byp, _byp}, /* 0x02 */ - { _byp, _byp}, /* 0x03 */ - { _byp, _byp}, /* 0x04 */ - { _byp, _byp}, /* 0x05 */ - { _byp, _byp}, /* 0x06 */ - { _byp, _byp}, /* 0x07 */ - { _1x, _x2}, /* 0x08 */ - { _1x, _x4}, /* 0x09 */ - { _1x, _x8}, /* 0x0A */ - { _1x, _x8}, /* 0x0B */ - {_1_5x, _x2}, /* 0x0C */ - {_1_5x, _x4}, /* 0x0D */ - {_1_5x, _x8}, /* 0x0E */ - {_1_5x, _x8}, /* 0x0F */ - { _2x, _x2}, /* 0x10 */ - { _2x, _x4}, /* 0x11 */ - { _2x, _x8}, /* 0x12 */ - { _2x, _x8}, /* 0x13 */ - {_2_5x, _x2}, /* 0x14 */ - {_2_5x, _x4}, /* 0x15 */ - {_2_5x, _x8}, /* 0x16 */ - {_2_5x, _x8}, /* 0x17 */ - { _3x, _x2}, /* 0x18 */ - { _3x, _x4}, /* 0x19 */ - { _3x, _x8}, /* 0x1A */ - { _3x, _x8}, /* 0x1B */ + {_byp, _byp}, /* 0x00 */ + {_byp, _byp}, /* 0x01 */ + {_byp, _byp}, /* 0x02 */ + {_byp, _byp}, /* 0x03 */ + {_byp, _byp}, /* 0x04 */ + {_byp, _byp}, /* 0x05 */ + {_byp, _byp}, /* 0x06 */ + {_byp, _byp}, /* 0x07 */ + {_1x, _x2}, /* 0x08 */ + {_1x, _x4}, /* 0x09 */ + {_1x, _x8}, /* 0x0A */ + {_1x, _x8}, /* 0x0B */ + {_1_5x, _x2}, /* 0x0C */ + {_1_5x, _x4}, /* 0x0D */ + {_1_5x, _x8}, /* 0x0E */ + {_1_5x, _x8}, /* 0x0F */ + {_2x, _x2}, /* 0x10 */ + {_2x, _x4}, /* 0x11 */ + {_2x, _x8}, /* 0x12 */ + {_2x, _x8}, /* 0x13 */ + {_2_5x, _x2}, /* 0x14 */ + {_2_5x, _x4}, /* 0x15 */ + {_2_5x, _x8}, /* 0x16 */ + {_2_5x, _x8}, /* 0x17 */ + {_3x, _x2}, /* 0x18 */ + {_3x, _x4}, /* 0x19 */ + {_3x, _x8}, /* 0x1A */ + {_3x, _x8}, /* 0x1B */ }; /* ----------------------------------------------------------------- */ @@ -92,91 +87,68 @@ corecnf_t corecnf_tab[] = { /* * */ -int get_clocks (void) +int get_clocks(void) { - volatile immap_t *im = (immap_t *)CFG_IMMRBAR; + volatile immap_t *im = (immap_t *) CFG_IMMR; u32 pci_sync_in; - u8 spmf; - u8 clkin_div; + u8 spmf; + u8 clkin_div; u32 sccr; u32 corecnf_tab_index; - u8 corepll; + u8 corepll; u32 lcrr; u32 csb_clk; +#if defined(CONFIG_MPC834X) u32 tsec1_clk; u32 tsec2_clk; - u32 core_clk; u32 usbmph_clk; u32 usbdr_clk; - u32 i2c_clk; +#endif + u32 core_clk; + u32 i2c1_clk; +#if !defined(CONFIG_MPC832X) + u32 i2c2_clk; +#endif u32 enc_clk; u32 lbiu_clk; u32 lclk_clk; u32 ddr_clk; - - if ((im->sysconf.immrbar & IMMRBAR_BASE_ADDR) != (u32)im) +#if defined(CONFIG_MPC8360) + u32 ddr_sec_clk; +#endif +#if defined(CONFIG_MPC8360) || defined(CONFIG_MPC832X) + u32 qepmf; + u32 qepdf; + u32 qe_clk; + u32 brg_clk; +#endif + + if ((im->sysconf.immrbar & IMMRBAR_BASE_ADDR) != (u32) im) return -1; -#ifndef CFG_HRCW_HIGH -# error "CFG_HRCW_HIGH must be defined in board config file" -#endif /* CFG_HCWD_HIGH */ - -#if (CFG_HRCW_HIGH & HRCWH_PCI_HOST) - -# ifndef CONFIG_83XX_CLKIN -# error "In PCI Host Mode, CONFIG_83XX_CLKIN must be defined in board config file" -# endif /* CONFIG_83XX_CLKIN */ -# ifdef CONFIG_83XX_PCICLK -# warning "In PCI Host Mode, CONFIG_83XX_PCICLK in board config file is igonred" -# endif /* CONFIG_83XX_PCICLK */ - - /* PCI Host Mode */ - if (!(im->reset.rcwh & RCWH_PCIHOST)) { - /* though RCWH_PCIHOST is defined in CFG_HRCW_HIGH - * the im->reset.rcwhr PCI Host Mode is disabled - * FIXME: findout if there is a way to issue some warning */ - return -2; - } - if (im->clk.spmr & SPMR_CKID) { - /* PCI Clock is half CONFIG_83XX_CLKIN */ - pci_sync_in = CONFIG_83XX_CLKIN / 2; - } - else { - pci_sync_in = CONFIG_83XX_CLKIN; - } - -#else /* (CFG_HRCW_HIGH & HRCWH_PCI_HOST) */ - -# ifdef CONFIG_83XX_CLKIN -# warning "In PCI Agent Mode, CONFIG_83XX_CLKIN in board config file is igonred" -# endif /* CONFIG_83XX_CLKIN */ -# ifndef CONFIG_83XX_PCICLK -# error "In PCI Agent Mode, CONFIG_83XX_PCICLK must be defined in board config file" -# endif /* CONFIG_83XX_PCICLK */ - - /* PCI Agent Mode */ - if (im->reset.rcwh & RCWH_PCIHOST) { - /* though RCWH_PCIHOST is not defined in CFG_HRCW_HIGH - * the im->reset.rcwhr PCI Host Mode is enabled */ - return -3; - } - pci_sync_in = CONFIG_83XX_PCICLK; - -#endif /* (CFG_HRCW_HIGH | RCWH_PCIHOST) */ - - /* we have up to date pci_sync_in */ - spmf = ((im->reset.rcwl & RCWL_SPMF) >> RCWL_SPMF_SHIFT); clkin_div = ((im->clk.spmr & SPMR_CKID) >> SPMR_CKID_SHIFT); - if ((im->reset.rcwl & RCWL_LBIUCM) || (im->reset.rcwl & RCWL_DDRCM)) { - csb_clk = (pci_sync_in * spmf * (1 + clkin_div)) / 2; - } - else { - csb_clk = pci_sync_in * spmf * (1 + clkin_div); + if (im->reset.rcwh & HRCWH_PCI_HOST) { +#if defined(CONFIG_83XX_CLKIN) + pci_sync_in = CONFIG_83XX_CLKIN / (1 + clkin_div); +#else + pci_sync_in = 0xDEADBEEF; +#endif + } else { +#if defined(CONFIG_83XX_PCICLK) + pci_sync_in = CONFIG_83XX_PCICLK; +#else + pci_sync_in = 0xDEADBEEF; +#endif } + spmf = ((im->reset.rcwl & HRCWL_SPMF) >> HRCWL_SPMF_SHIFT); + csb_clk = pci_sync_in * (1 + clkin_div) * spmf; + sccr = im->clk.sccr; + +#if defined(CONFIG_MPC834X) switch ((sccr & SCCR_TSEC1CM) >> SCCR_TSEC1CM_SHIFT) { case 0: tsec1_clk = 0; @@ -212,25 +184,8 @@ int get_clocks (void) /* unkown SCCR_TSEC2CM value */ return -5; } - i2c_clk = tsec2_clk; - switch ((sccr & SCCR_ENCCM) >> SCCR_ENCCM_SHIFT) { - case 0: - enc_clk = 0; - break; - case 1: - enc_clk = csb_clk; - break; - case 2: - enc_clk = csb_clk / 2; - break; - case 3: - enc_clk = csb_clk / 3; - break; - default: - /* unkown SCCR_ENCCM value */ - return -6; - } + i2c1_clk = tsec2_clk; switch ((sccr & SCCR_USBMPHCM) >> SCCR_USBMPHCM_SHIFT) { case 0: @@ -268,14 +223,41 @@ int get_clocks (void) return -8; } - if (usbmph_clk != 0 - && usbdr_clk != 0 - && usbmph_clk != usbdr_clk ) { - /* if USB MPH clock is not disabled and USB DR clock is not disabled than USB MPH & USB DR must have the same rate */ + if (usbmph_clk != 0 && usbdr_clk != 0 && usbmph_clk != usbdr_clk) { + /* if USB MPH clock is not disabled and + * USB DR clock is not disabled then + * USB MPH & USB DR must have the same rate + */ return -9; } +#endif +#if defined(CONFIG_MPC8360) || defined(CONFIG_MPC832X) + i2c1_clk = csb_clk; +#endif +#if !defined(CONFIG_MPC832X) + i2c2_clk = csb_clk; /* i2c-2 clk is equal to csb clk */ +#endif - lbiu_clk = csb_clk * (1 + ((im->reset.rcwl & RCWL_LBIUCM) >> RCWL_LBIUCM_SHIFT)); + switch ((sccr & SCCR_ENCCM) >> SCCR_ENCCM_SHIFT) { + case 0: + enc_clk = 0; + break; + case 1: + enc_clk = csb_clk; + break; + case 2: + enc_clk = csb_clk / 2; + break; + case 3: + enc_clk = csb_clk / 3; + break; + default: + /* unkown SCCR_ENCCM value */ + return -6; + } + + lbiu_clk = csb_clk * + (1 + ((im->reset.rcwl & HRCWL_LBIUCM) >> HRCWL_LBIUCM_SHIFT)); lcrr = (im->lbus.lcrr & LCRR_CLKDIV) >> LCRR_CLKDIV_SHIFT; switch (lcrr) { case 2: @@ -288,11 +270,16 @@ int get_clocks (void) return -10; } - ddr_clk = csb_clk * (1 + ((im->reset.rcwl & RCWL_DDRCM) >> RCWL_DDRCM_SHIFT)); + ddr_clk = csb_clk * + (1 + ((im->reset.rcwl & HRCWL_DDRCM) >> HRCWL_DDRCM_SHIFT)); + corepll = (im->reset.rcwl & HRCWL_COREPLL) >> HRCWL_COREPLL_SHIFT; +#if defined(CONFIG_MPC8360) + ddr_sec_clk = csb_clk * (1 + + ((im->reset.rcwl & HRCWL_LBIUCM) >> HRCWL_LBIUCM_SHIFT)); +#endif - corepll = (im->reset.rcwl & RCWL_COREPLL) >> RCWL_COREPLL_SHIFT; corecnf_tab_index = ((corepll & 0x1F) << 2) | ((corepll & 0x60) >> 5); - if (corecnf_tab_index > (sizeof(corecnf_tab)/sizeof(corecnf_t)) ) { + if (corecnf_tab_index > (sizeof(corecnf_tab) / sizeof(corecnf_t))) { /* corecnf_tab_index is too high, possibly worng value */ return -11; } @@ -309,7 +296,7 @@ int get_clocks (void) core_clk = 2 * csb_clk; break; case _2_5x: - core_clk = ( 5 * csb_clk) / 2; + core_clk = (5 * csb_clk) / 2; break; case _3x: core_clk = 3 * csb_clk; @@ -319,46 +306,76 @@ int get_clocks (void) return -12; } - gd->csb_clk = csb_clk ; - gd->tsec1_clk = tsec1_clk ; - gd->tsec2_clk = tsec2_clk ; - gd->core_clk = core_clk ; +#if defined(CONFIG_MPC8360) || defined(CONFIG_MPC832X) + qepmf = (im->reset.rcwl & HRCWL_CEPMF) >> HRCWL_CEPMF_SHIFT; + qepdf = (im->reset.rcwl & HRCWL_CEPDF) >> HRCWL_CEPDF_SHIFT; + qe_clk = (pci_sync_in * qepmf) / (1 + qepdf); + brg_clk = qe_clk / 2; +#endif + + gd->csb_clk = csb_clk; +#if defined(CONFIG_MPC834X) + gd->tsec1_clk = tsec1_clk; + gd->tsec2_clk = tsec2_clk; gd->usbmph_clk = usbmph_clk; - gd->usbdr_clk = usbdr_clk ; - gd->i2c_clk = i2c_clk ; - gd->enc_clk = enc_clk ; - gd->lbiu_clk = lbiu_clk ; - gd->lclk_clk = lclk_clk ; - gd->ddr_clk = ddr_clk ; - gd->pci_clk = pci_sync_in; - + gd->usbdr_clk = usbdr_clk; +#endif + gd->core_clk = core_clk; + gd->i2c1_clk = i2c1_clk; +#if !defined(CONFIG_MPC832X) + gd->i2c2_clk = i2c2_clk; +#endif + gd->enc_clk = enc_clk; + gd->lbiu_clk = lbiu_clk; + gd->lclk_clk = lclk_clk; + gd->ddr_clk = ddr_clk; +#if defined(CONFIG_MPC8360) + gd->ddr_sec_clk = ddr_sec_clk; +#endif +#if defined(CONFIG_MPC8360) || defined(CONFIG_MPC832X) + gd->qe_clk = qe_clk; + gd->brg_clk = brg_clk; +#endif gd->cpu_clk = gd->core_clk; - gd->bus_clk = gd->lbiu_clk; + gd->bus_clk = gd->csb_clk; return 0; + } /******************************************** * get_bus_freq * return system bus freq in Hz *********************************************/ -ulong get_bus_freq (ulong dummy) +ulong get_bus_freq(ulong dummy) { return gd->csb_clk; } -int print_clock_conf (void) +int print_clock_conf(void) { printf("Clock configuration:\n"); - printf(" Coherent System Bus: %4d MHz\n",gd->csb_clk/1000000); - printf(" Core: %4d MHz\n",gd->core_clk/1000000); - debug(" Local Bus Controller:%4d MHz\n",gd->lbiu_clk/1000000); - printf(" Local Bus: %4d MHz\n",gd->lclk_clk/1000000); - debug(" DDR: %4d MHz\n",gd->ddr_clk/1000000); - debug(" I2C: %4d MHz\n",gd->i2c_clk/1000000); - debug(" TSEC1: %4d MHz\n",gd->tsec1_clk/1000000); - debug(" TSEC2: %4d MHz\n",gd->tsec2_clk/1000000); - debug(" USB MPH: %4d MHz\n",gd->usbmph_clk/1000000); - debug(" USB DR: %4d MHz\n",gd->usbdr_clk/1000000); - + printf(" Coherent System Bus: %4d MHz\n", gd->csb_clk / 1000000); + printf(" Core: %4d MHz\n", gd->core_clk / 1000000); +#if defined(CONFIG_MPC8360) || defined(CONFIG_MPC832X) + printf(" QE: %4d MHz\n", gd->qe_clk / 1000000); + printf(" BRG: %4d MHz\n", gd->brg_clk / 1000000); +#endif + printf(" Local Bus Controller:%4d MHz\n", gd->lbiu_clk / 1000000); + printf(" Local Bus: %4d MHz\n", gd->lclk_clk / 1000000); + printf(" DDR: %4d MHz\n", gd->ddr_clk / 1000000); +#if defined(CONFIG_MPC8360) + printf(" DDR Secondary: %4d MHz\n", gd->ddr_sec_clk / 1000000); +#endif + printf(" SEC: %4d MHz\n", gd->enc_clk / 1000000); + printf(" I2C1: %4d MHz\n", gd->i2c1_clk / 1000000); +#if !defined(CONFIG_MPC832X) + printf(" I2C2: %4d MHz\n", gd->i2c2_clk / 1000000); +#endif +#if defined(CONFIG_MPC834X) + printf(" TSEC1: %4d MHz\n", gd->tsec1_clk / 1000000); + printf(" TSEC2: %4d MHz\n", gd->tsec2_clk / 1000000); + printf(" USB MPH: %4d MHz\n", gd->usbmph_clk / 1000000); + printf(" USB DR: %4d MHz\n", gd->usbdr_clk / 1000000); +#endif return 0; } diff --git a/cpu/mpc83xx/start.S b/cpu/mpc83xx/start.S index 6e02cce..6ee9ec9 100644 --- a/cpu/mpc83xx/start.S +++ b/cpu/mpc83xx/start.S @@ -2,7 +2,7 @@ * Copyright (C) 1998 Dan Malek <dmalek@jlc.net> * Copyright (C) 1999 Magnus Damm <kieraypc01.p.y.kie.era.ericsson.se> * Copyright (C) 2000, 2001,2002 Wolfgang Denk <wd@denx.de> - * Copyright 2004 Freescale Semiconductor, Inc. + * Copyright Freescale Semiconductor, Inc. 2004, 2006. All rights reserved. * * See file CREDITS for list of people who contributed to this * project. @@ -77,19 +77,11 @@ END_GOT /* - * Version string - must be in data segment because MPC83xx uses the - * first 256 bytes for the Hard Reset Configuration Word table (see - * below). Similarly, can't have the U-Boot Magic Number as the first - * thing in the image - don't know how this will affect the image tools, - * but I guess I'll find out soon. + * The Hard Reset Configuration Word (HRCW) table is in the first 64 + * (0x40) bytes of flash. It has 8 bytes, but each byte is repeated 8 + * times so the processor can fetch it out of flash whether the flash + * is 8, 16, 32, or 64 bits wide (hardware trickery). */ - .data - .globl version_string -version_string: - .ascii U_BOOT_VERSION - .ascii " (", __DATE__, " - ", __TIME__, ")" - .ascii " ", CONFIG_IDENT_STRING, "\0" - .text #define _HRCW_TABLE_ENTRY(w) \ .fill 8,1,(((w)>>24)&0xff); \ @@ -100,13 +92,25 @@ version_string: _HRCW_TABLE_ENTRY(CFG_HRCW_LOW) _HRCW_TABLE_ENTRY(CFG_HRCW_HIGH) +/* + * Magic number and version string - put it after the HRCW since it + * cannot be first in flash like it is in many other processors. + */ + .long 0x27051956 /* U-Boot Magic Number */ + + .globl version_string +version_string: + .ascii U_BOOT_VERSION + .ascii " (", __DATE__, " - ", __TIME__, ")" + .ascii " ", CONFIG_IDENT_STRING, "\0" + #ifndef CONFIG_DEFAULT_IMMR #error CONFIG_DEFAULT_IMMR must be defined #endif /* CFG_DEFAULT_IMMR */ -#ifndef CFG_IMMRBAR -#define CFG_IMMRBAR CONFIG_DEFAULT_IMMR -#endif /* CFG_IMMRBAR */ +#ifndef CFG_IMMR +#define CFG_IMMR CONFIG_DEFAULT_IMMR +#endif /* CFG_IMMR */ /* * After configuration, a system reset exception is executed using the @@ -152,8 +156,8 @@ boot_cold: /* time t 3 */ nop boot_warm: /* time t 5 */ mfmsr r5 /* save msr contents */ - lis r3, CFG_IMMRBAR@h - ori r3, r3, CFG_IMMRBAR@l + lis r3, CFG_IMMR@h + ori r3, r3, CFG_IMMR@l stw r3, IMMRBAR(r4) /* Initialise the E300 processor core */ @@ -226,7 +230,7 @@ in_flash: GET_GOT /* initialize GOT access */ /* r3: IMMR */ - lis r3, CFG_IMMRBAR@h + lis r3, CFG_IMMR@h /* run low-level CPU init code (in Flash)*/ bl cpu_init_f @@ -446,7 +450,7 @@ init_e300_core: /* time t 10 */ mtspr SRR1, r3 /* Make SRR1 match MSR */ - lis r3, CFG_IMMRBAR@h + lis r3, CFG_IMMR@h #if defined(CONFIG_WATCHDOG) /* Initialise the Wathcdog values and reset it (if req) */ /*------------------------------------------------------*/ @@ -870,6 +874,18 @@ ppcDcbz: dcbz r0,r3 blr + .globl ppcDWstore +ppcDWstore: + lfd 1, 0(r4) + stfd 1, 0(r3) + blr + + .globl ppcDWload +ppcDWload: + lfd 1, 0(r3) + stfd 1, 0(r4) + blr + /*-------------------------------------------------------------------*/ /* @@ -1189,7 +1205,7 @@ map_flash_by_law1: /* When booting from ROM (Flash or EPROM), clear the */ /* Address Mask in OR0 so ROM appears everywhere */ /*----------------------------------------------------*/ - lis r3, (CFG_IMMRBAR)@h /* r3 <= CFG_IMMRBAR */ + lis r3, (CFG_IMMR)@h /* r3 <= CFG_IMMR */ lwz r4, OR0@l(r3) li r5, 0x7fff /* r5 <= 0x00007FFFF */ and r4, r4, r5 @@ -1214,8 +1230,15 @@ map_flash_by_law1: lis r4, (CFG_FLASH_BASE)@h ori r4, r4, (CFG_FLASH_BASE)@l stw r4, LBLAWBAR1(r3) /* LBLAWBAR1 <= CFG_FLASH_BASE */ - lis r4, (0x80000016)@h - ori r4, r4, (0x80000016)@l + + /* Store 0x80000012 + log2(CFG_FLASH_SIZE) into LBLAWAR1 */ + lis r4, (0x80000012)@h + ori r4, r4, (0x80000012)@l + li r5, CFG_FLASH_SIZE +1: srawi. r5, r5, 1 /* r5 = r5 >> 1 */ + addi r4, r4, 1 + bne 1b + stw r4, LBLAWAR1(r3) /* LBLAWAR1 <= 8MB Flash Size */ blr @@ -1234,17 +1257,23 @@ remap_flash_by_law0: stw r5, BR0(r3) /* r5 <= (CFG_FLASH_BASE & 0xFFFF8000) | (BR0 & 0x00007FFF) */ lwz r4, OR0(r3) - lis r5, 0xFF80 /* 8M */ + lis r5, ~((CFG_FLASH_SIZE << 4) - 1) or r4, r4, r5 - stw r4, OR0(r3) /* OR0 <= OR0 | 0xFF800000 */ + stw r4, OR0(r3) lis r4, (CFG_FLASH_BASE)@h ori r4, r4, (CFG_FLASH_BASE)@l stw r4, LBLAWBAR0(r3) /* LBLAWBAR0 <= CFG_FLASH_BASE */ - lis r4, (0x80000016)@h - ori r4, r4, (0x80000016)@l - stw r4, LBLAWAR0(r3) /* LBLAWAR0 <= 8MB Flash Size */ + /* Store 0x80000012 + log2(CFG_FLASH_SIZE) into LBLAWAR0 */ + lis r4, (0x80000012)@h + ori r4, r4, (0x80000012)@l + li r5, CFG_FLASH_SIZE +1: srawi. r5, r5, 1 /* r5 = r5 >> 1 */ + addi r4, r4, 1 + bne 1b + stw r4, LBLAWAR0(r3) /* LBLAWAR0 <= Flash Size */ + xor r4, r4, r4 stw r4, LBLAWBAR1(r3) diff --git a/cpu/mpc83xx/traps.c b/cpu/mpc83xx/traps.c index 44345af..152fa73 100644 --- a/cpu/mpc83xx/traps.c +++ b/cpu/mpc83xx/traps.c @@ -1,5 +1,8 @@ /* - * linux/arch/ppc/kernel/traps.c + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -15,19 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA - * - * Change log: - * - * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) - * - * Modified by Cort Dougan (cort@cs.nmt.edu) - * and Paul Mackerras (paulus@cs.anu.edu.au) - * - * (C) Copyright 2000 - * Wolfgang Denk, DENX Software Engineering, wd@denx.de. - * - * 20050101: Eran Liberty (liberty@freescale.com) - * Initial file creating (porting from 85XX & 8260) */ /* diff --git a/cpu/mpc8xx/serial.c b/cpu/mpc8xx/serial.c index 8ae584f..ffc898c 100644 --- a/cpu/mpc8xx/serial.c +++ b/cpu/mpc8xx/serial.c @@ -227,8 +227,16 @@ static int smc_init (void) sp->smc_smcm = 0; sp->smc_smce = 0xff; -#ifdef CFG_SPC1920_SMC1_CLK4 /* clock source is PLD */ - *((volatile uchar *) CFG_SPC1920_PLD_BASE+6) = 0xff; +#ifdef CFG_SPC1920_SMC1_CLK4 + /* clock source is PLD */ + + /* set freq to 19200 Baud */ + *((volatile uchar *) CFG_SPC1920_PLD_BASE+6) = 0x3; + /* configure clk4 as input */ + im->im_ioport.iop_pdpar |= 0x800; + im->im_ioport.iop_pddir &= ~0x800; + + cp->cp_simode = ((cp->cp_simode & ~0xf000) | 0x7000); #else /* Set up the baud rate generator */ smc_setbrg (); diff --git a/cpu/ppc4xx/405gp_pci.c b/cpu/ppc4xx/405gp_pci.c index 03128d3..7134355 100644 --- a/cpu/ppc4xx/405gp_pci.c +++ b/cpu/ppc4xx/405gp_pci.c @@ -380,7 +380,7 @@ void pci_405gp_setup_vga(struct pci_controller *hose, pci_dev_t dev, pci_hose_write_config_dword(hose, dev, PCI_COMMAND, cmdstat); } -#if !(defined(CONFIG_PIP405) || defined (CONFIG_MIP405)) +#if !(defined(CONFIG_PIP405) || defined (CONFIG_MIP405)) && !(defined (CONFIG_SOLIDCARD3)) /* *As is these functs get called out of flash Not a horrible @@ -475,7 +475,11 @@ void pci_440_init (struct pci_controller *hose) pci_set_region(hose->regions + reg_num++, CFG_PCI_TARGBASE, CFG_PCI_MEMBASE, +#ifdef CFG_PCI_MEMSIZE + CFG_PCI_MEMSIZE, +#else 0x10000000, +#endif PCI_REGION_MEM ); #if defined(CONFIG_PCI_SYS_MEM_BUS) && defined(CONFIG_PCI_SYS_MEM_PHYS) && \ diff --git a/cpu/ppc4xx/40x_spd_sdram.c b/cpu/ppc4xx/40x_spd_sdram.c new file mode 100644 index 0000000..19c4f76 --- /dev/null +++ b/cpu/ppc4xx/40x_spd_sdram.c @@ -0,0 +1,469 @@ +/* + * cpu/ppc4xx/40x_spd_sdram.c + * This SPD SDRAM detection code supports IBM/AMCC PPC44x cpu with a + * SDRAM controller. Those are all current 405 PPC's. + * + * (C) Copyright 2001 + * Bill Hunter, Wave 7 Optics, williamhunter@attbi.com + * + * Based on code by: + * + * Kenneth Johansson ,Ericsson AB. + * kenneth.johansson@etx.ericsson.se + * + * hacked up by bill hunter. fixed so we could run before + * serial_init and console_init. previous version avoided this by + * running out of cache memory during serial/console init, then running + * this code later. + * + * (C) Copyright 2002 + * Jun Gu, Artesyn Technology, jung@artesyncp.com + * Support for AMCC 440 based on OpenBIOS draminit.c from IBM. + * + * (C) Copyright 2005 + * Stefan Roese, DENX Software Engineering, sr@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <asm/processor.h> +#include <i2c.h> +#include <ppc4xx.h> + +#if defined(CONFIG_SPD_EEPROM) && !defined(CONFIG_440) + +/* + * Set default values + */ +#ifndef CFG_I2C_SPEED +#define CFG_I2C_SPEED 50000 +#endif + +#ifndef CFG_I2C_SLAVE +#define CFG_I2C_SLAVE 0xFE +#endif + +#define ONE_BILLION 1000000000 + +#define SDRAM0_CFG_DCE 0x80000000 +#define SDRAM0_CFG_SRE 0x40000000 +#define SDRAM0_CFG_PME 0x20000000 +#define SDRAM0_CFG_MEMCHK 0x10000000 +#define SDRAM0_CFG_REGEN 0x08000000 +#define SDRAM0_CFG_ECCDD 0x00400000 +#define SDRAM0_CFG_EMDULR 0x00200000 +#define SDRAM0_CFG_DRW_SHIFT (31-6) +#define SDRAM0_CFG_BRPF_SHIFT (31-8) + +#define SDRAM0_TR_CASL_SHIFT (31-8) +#define SDRAM0_TR_PTA_SHIFT (31-13) +#define SDRAM0_TR_CTP_SHIFT (31-15) +#define SDRAM0_TR_LDF_SHIFT (31-17) +#define SDRAM0_TR_RFTA_SHIFT (31-29) +#define SDRAM0_TR_RCD_SHIFT (31-31) + +#define SDRAM0_RTR_SHIFT (31-15) +#define SDRAM0_ECCCFG_SHIFT (31-11) + +/* SDRAM0_CFG enable macro */ +#define SDRAM0_CFG_BRPF(x) ( ( x & 0x3)<< SDRAM0_CFG_BRPF_SHIFT ) + +#define SDRAM0_BXCR_SZ_MASK 0x000e0000 +#define SDRAM0_BXCR_AM_MASK 0x0000e000 + +#define SDRAM0_BXCR_SZ_SHIFT (31-14) +#define SDRAM0_BXCR_AM_SHIFT (31-18) + +#define SDRAM0_BXCR_SZ(x) ( (( x << SDRAM0_BXCR_SZ_SHIFT) & SDRAM0_BXCR_SZ_MASK) ) +#define SDRAM0_BXCR_AM(x) ( (( x << SDRAM0_BXCR_AM_SHIFT) & SDRAM0_BXCR_AM_MASK) ) + +#ifdef CONFIG_SPDDRAM_SILENT +# define SPD_ERR(x) do { return 0; } while (0) +#else +# define SPD_ERR(x) do { printf(x); return(0); } while (0) +#endif + +#define sdram_HZ_to_ns(hertz) (1000000000/(hertz)) + +/* function prototypes */ +int spd_read(uint addr); + + +/* + * This function is reading data from the DIMM module EEPROM over the SPD bus + * and uses that to program the sdram controller. + * + * This works on boards that has the same schematics that the AMCC walnut has. + * + * Input: null for default I2C spd functions or a pointer to a custom function + * returning spd_data. + */ + +long int spd_sdram(int(read_spd)(uint addr)) +{ + int tmp,row,col; + int total_size,bank_size,bank_code; + int ecc_on; + int mode; + int bank_cnt; + + int sdram0_pmit=0x07c00000; +#ifndef CONFIG_405EP /* not on PPC405EP */ + int sdram0_besr0=-1; + int sdram0_besr1=-1; + int sdram0_eccesr=-1; +#endif + int sdram0_ecccfg; + + int sdram0_rtr=0; + int sdram0_tr=0; + + int sdram0_b0cr; + int sdram0_b1cr; + int sdram0_b2cr; + int sdram0_b3cr; + + int sdram0_cfg=0; + + int t_rp; + int t_rcd; + int t_ras; + int t_rc; + int min_cas; + + PPC405_SYS_INFO sys_info; + unsigned long bus_period_x_10; + + /* + * get the board info + */ + get_sys_info(&sys_info); + bus_period_x_10 = ONE_BILLION / (sys_info.freqPLB / 10); + + if (read_spd == 0){ + read_spd=spd_read; + /* + * Make sure I2C controller is initialized + * before continuing. + */ + i2c_init(CFG_I2C_SPEED, CFG_I2C_SLAVE); + } + + /* Make shure we are using SDRAM */ + if (read_spd(2) != 0x04) { + SPD_ERR("SDRAM - non SDRAM memory module found\n"); + } + + /* ------------------------------------------------------------------ + * configure memory timing register + * + * data from DIMM: + * 27 IN Row Precharge Time ( t RP) + * 29 MIN RAS to CAS Delay ( t RCD) + * 127 Component and Clock Detail ,clk0-clk3, junction temp, CAS + * -------------------------------------------------------------------*/ + + /* + * first figure out which cas latency mode to use + * use the min supported mode + */ + + tmp = read_spd(127) & 0x6; + if (tmp == 0x02) { /* only cas = 2 supported */ + min_cas = 2; +/* t_ck = read_spd(9); */ +/* t_ac = read_spd(10); */ + } else if (tmp == 0x04) { /* only cas = 3 supported */ + min_cas = 3; +/* t_ck = read_spd(9); */ +/* t_ac = read_spd(10); */ + } else if (tmp == 0x06) { /* 2,3 supported, so use 2 */ + min_cas = 2; +/* t_ck = read_spd(23); */ +/* t_ac = read_spd(24); */ + } else { + SPD_ERR("SDRAM - unsupported CAS latency \n"); + } + + /* get some timing values, t_rp,t_rcd,t_ras,t_rc + */ + t_rp = read_spd(27); + t_rcd = read_spd(29); + t_ras = read_spd(30); + t_rc = t_ras + t_rp; + + /* The following timing calcs subtract 1 before deviding. + * this has effect of using ceiling instead of floor rounding, + * and also subtracting 1 to convert number to reg value + */ + /* set up CASL */ + sdram0_tr = (min_cas - 1) << SDRAM0_TR_CASL_SHIFT; + /* set up PTA */ + sdram0_tr |= ((((t_rp - 1) * 10)/bus_period_x_10) & 0x3) << SDRAM0_TR_PTA_SHIFT; + /* set up CTP */ + tmp = (((t_rc - t_rcd - t_rp -1) * 10) / bus_period_x_10) & 0x3; + if (tmp < 1) + tmp = 1; + sdram0_tr |= tmp << SDRAM0_TR_CTP_SHIFT; + /* set LDF = 2 cycles, reg value = 1 */ + sdram0_tr |= 1 << SDRAM0_TR_LDF_SHIFT; + /* set RFTA = t_rfc/bus_period, use t_rfc = t_rc */ + tmp = (((t_rc - 1) * 10) / bus_period_x_10) - 3; + if (tmp < 0) + tmp = 0; + if (tmp > 6) + tmp = 6; + sdram0_tr |= tmp << SDRAM0_TR_RFTA_SHIFT; + /* set RCD = t_rcd/bus_period*/ + sdram0_tr |= ((((t_rcd - 1) * 10) / bus_period_x_10) &0x3) << SDRAM0_TR_RCD_SHIFT ; + + + /*------------------------------------------------------------------ + * configure RTR register + * -------------------------------------------------------------------*/ + row = read_spd(3); + col = read_spd(4); + tmp = read_spd(12) & 0x7f ; /* refresh type less self refresh bit */ + switch (tmp) { + case 0x00: + tmp = 15625; + break; + case 0x01: + tmp = 15625 / 4; + break; + case 0x02: + tmp = 15625 / 2; + break; + case 0x03: + tmp = 15625 * 2; + break; + case 0x04: + tmp = 15625 * 4; + break; + case 0x05: + tmp = 15625 * 8; + break; + default: + SPD_ERR("SDRAM - Bad refresh period \n"); + } + /* convert from nsec to bus cycles */ + tmp = (tmp * 10) / bus_period_x_10; + sdram0_rtr = (tmp & 0x3ff8) << SDRAM0_RTR_SHIFT; + + /*------------------------------------------------------------------ + * determine the number of banks used + * -------------------------------------------------------------------*/ + /* byte 7:6 is module data width */ + if (read_spd(7) != 0) + SPD_ERR("SDRAM - unsupported module width\n"); + tmp = read_spd(6); + if (tmp < 32) + SPD_ERR("SDRAM - unsupported module width\n"); + else if (tmp < 64) + bank_cnt = 1; /* one bank per sdram side */ + else if (tmp < 73) + bank_cnt = 2; /* need two banks per side */ + else if (tmp < 161) + bank_cnt = 4; /* need four banks per side */ + else + SPD_ERR("SDRAM - unsupported module width\n"); + + /* byte 5 is the module row count (refered to as dimm "sides") */ + tmp = read_spd(5); + if (tmp == 1) + ; + else if (tmp==2) + bank_cnt *= 2; + else if (tmp==4) + bank_cnt *= 4; + else + bank_cnt = 8; /* 8 is an error code */ + + if (bank_cnt > 4) /* we only have 4 banks to work with */ + SPD_ERR("SDRAM - unsupported module rows for this width\n"); + + /* now check for ECC ability of module. We only support ECC + * on 32 bit wide devices with 8 bit ECC. + */ + if ((read_spd(11)==2) && (read_spd(6)==40) && (read_spd(14)==8)) { + sdram0_ecccfg = 0xf << SDRAM0_ECCCFG_SHIFT; + ecc_on = 1; + } else { + sdram0_ecccfg = 0; + ecc_on = 0; + } + + /*------------------------------------------------------------------ + * calculate total size + * -------------------------------------------------------------------*/ + /* calculate total size and do sanity check */ + tmp = read_spd(31); + total_size = 1 << 22; /* total_size = 4MB */ + /* now multiply 4M by the smallest device row density */ + /* note that we don't support asymetric rows */ + while (((tmp & 0x0001) == 0) && (tmp != 0)) { + total_size = total_size << 1; + tmp = tmp >> 1; + } + total_size *= read_spd(5); /* mult by module rows (dimm sides) */ + + /*------------------------------------------------------------------ + * map rows * cols * banks to a mode + * -------------------------------------------------------------------*/ + + switch (row) { + case 11: + switch (col) { + case 8: + mode=4; /* mode 5 */ + break; + case 9: + case 10: + mode=0; /* mode 1 */ + break; + default: + SPD_ERR("SDRAM - unsupported mode\n"); + } + break; + case 12: + switch (col) { + case 8: + mode=3; /* mode 4 */ + break; + case 9: + case 10: + mode=1; /* mode 2 */ + break; + default: + SPD_ERR("SDRAM - unsupported mode\n"); + } + break; + case 13: + switch (col) { + case 8: + mode=5; /* mode 6 */ + break; + case 9: + case 10: + if (read_spd(17) == 2) + mode = 6; /* mode 7 */ + else + mode = 2; /* mode 3 */ + break; + case 11: + mode = 2; /* mode 3 */ + break; + default: + SPD_ERR("SDRAM - unsupported mode\n"); + } + break; + default: + SPD_ERR("SDRAM - unsupported mode\n"); + } + + /*------------------------------------------------------------------ + * using the calculated values, compute the bank + * config register values. + * -------------------------------------------------------------------*/ + sdram0_b1cr = 0; + sdram0_b2cr = 0; + sdram0_b3cr = 0; + + /* compute the size of each bank */ + bank_size = total_size / bank_cnt; + /* convert bank size to bank size code for ppc4xx + by takeing log2(bank_size) - 22 */ + tmp = bank_size; /* start with tmp = bank_size */ + bank_code = 0; /* and bank_code = 0 */ + while (tmp > 1) { /* this takes log2 of tmp */ + bank_code++; /* and stores result in bank_code */ + tmp = tmp >> 1; + } /* bank_code is now log2(bank_size) */ + bank_code -= 22; /* subtract 22 to get the code */ + + tmp = SDRAM0_BXCR_SZ(bank_code) | SDRAM0_BXCR_AM(mode) | 1; + sdram0_b0cr = (bank_size * 0) | tmp; +#ifndef CONFIG_405EP /* not on PPC405EP */ + if (bank_cnt > 1) + sdram0_b2cr = (bank_size * 1) | tmp; + if (bank_cnt > 2) + sdram0_b1cr = (bank_size * 2) | tmp; + if (bank_cnt > 3) + sdram0_b3cr = (bank_size * 3) | tmp; +#else + /* PPC405EP chip only supports two SDRAM banks */ + if (bank_cnt > 1) + sdram0_b1cr = (bank_size * 1) | tmp; + if (bank_cnt > 2) + total_size = 2 * bank_size; +#endif + + /* + * enable sdram controller DCE=1 + * enable burst read prefetch to 32 bytes BRPF=2 + * leave other functions off + */ + + /*------------------------------------------------------------------ + * now that we've done our calculations, we are ready to + * program all the registers. + * -------------------------------------------------------------------*/ + +#define mtsdram0(reg, data) mtdcr(memcfga,reg);mtdcr(memcfgd,data) + /* disable memcontroller so updates work */ + mtsdram0( mem_mcopt1, 0 ); + +#ifndef CONFIG_405EP /* not on PPC405EP */ + mtsdram0( mem_besra , sdram0_besr0 ); + mtsdram0( mem_besrb , sdram0_besr1 ); + mtsdram0( mem_ecccf , sdram0_ecccfg ); + mtsdram0( mem_eccerr, sdram0_eccesr ); +#endif + mtsdram0( mem_rtr , sdram0_rtr ); + mtsdram0( mem_pmit , sdram0_pmit ); + mtsdram0( mem_mb0cf , sdram0_b0cr ); + mtsdram0( mem_mb1cf , sdram0_b1cr ); +#ifndef CONFIG_405EP /* not on PPC405EP */ + mtsdram0( mem_mb2cf , sdram0_b2cr ); + mtsdram0( mem_mb3cf , sdram0_b3cr ); +#endif + mtsdram0( mem_sdtr1 , sdram0_tr ); + + /* SDRAM have a power on delay, 500 micro should do */ + udelay(500); + sdram0_cfg = SDRAM0_CFG_DCE | SDRAM0_CFG_BRPF(1) | SDRAM0_CFG_ECCDD | SDRAM0_CFG_EMDULR; + if (ecc_on) + sdram0_cfg |= SDRAM0_CFG_MEMCHK; + mtsdram0(mem_mcopt1, sdram0_cfg); + + return (total_size); +} + +int spd_read(uint addr) +{ + uchar data[2]; + + if (i2c_read(SPD_EEPROM_ADDRESS, addr, 1, data, 1) == 0) + return (int)data[0]; + else + return 0; +} + +#endif /* CONFIG_SPD_EEPROM */ diff --git a/cpu/ppc4xx/440spe_pcie.c b/cpu/ppc4xx/440spe_pcie.c index 6130cd2..d6c4be5 100644 --- a/cpu/ppc4xx/440spe_pcie.c +++ b/cpu/ppc4xx/440spe_pcie.c @@ -26,10 +26,9 @@ #include <common.h> #include <pci.h> -#include "440spe_pcie.h" +#if defined(CONFIG_440SPE) && defined(CONFIG_PCI) -#if defined(CONFIG_440SPE) -#if defined(CONFIG_PCI) +#include "440spe_pcie.h" enum { PTYPE_ENDPOINT = 0x0, @@ -958,5 +957,4 @@ int ppc440spe_setup_pcie_endpoint(struct pci_controller *hose, int port) return 0; } -#endif /* CONFIG_PCI */ -#endif /* CONFIG_440SPE */ +#endif /* CONFIG_440SPE && CONFIG_PCI */ diff --git a/cpu/ppc4xx/spd_sdram.c b/cpu/ppc4xx/44x_spd_ddr.c index c24456b..10b4c18 100644 --- a/cpu/ppc4xx/spd_sdram.c +++ b/cpu/ppc4xx/44x_spd_ddr.c @@ -1,4 +1,8 @@ /* + * cpu/ppc4xx/44x_spd_ddr.c + * This SPD DDR detection code supports IBM/AMCC PPC44x cpu with a + * DDR controller. Those are 440GP/GX/EP/GR. + * * (C) Copyright 2001 * Bill Hunter, Wave 7 Optics, williamhunter@attbi.com * @@ -42,8 +46,11 @@ #include <asm/processor.h> #include <i2c.h> #include <ppc4xx.h> +#include <asm/mmu.h> -#ifdef CONFIG_SPD_EEPROM +#if defined(CONFIG_SPD_EEPROM) && \ + (defined(CONFIG_440GP) || defined(CONFIG_440GX) || \ + defined(CONFIG_440EP) || defined(CONFIG_440GR)) /* * Set default values @@ -58,414 +65,6 @@ #define ONE_BILLION 1000000000 -#ifndef CONFIG_440 /* for 405 WALNUT/SYCAMORE/BUBINGA boards */ - -#define SDRAM0_CFG_DCE 0x80000000 -#define SDRAM0_CFG_SRE 0x40000000 -#define SDRAM0_CFG_PME 0x20000000 -#define SDRAM0_CFG_MEMCHK 0x10000000 -#define SDRAM0_CFG_REGEN 0x08000000 -#define SDRAM0_CFG_ECCDD 0x00400000 -#define SDRAM0_CFG_EMDULR 0x00200000 -#define SDRAM0_CFG_DRW_SHIFT (31-6) -#define SDRAM0_CFG_BRPF_SHIFT (31-8) - -#define SDRAM0_TR_CASL_SHIFT (31-8) -#define SDRAM0_TR_PTA_SHIFT (31-13) -#define SDRAM0_TR_CTP_SHIFT (31-15) -#define SDRAM0_TR_LDF_SHIFT (31-17) -#define SDRAM0_TR_RFTA_SHIFT (31-29) -#define SDRAM0_TR_RCD_SHIFT (31-31) - -#define SDRAM0_RTR_SHIFT (31-15) -#define SDRAM0_ECCCFG_SHIFT (31-11) - -/* SDRAM0_CFG enable macro */ -#define SDRAM0_CFG_BRPF(x) ( ( x & 0x3)<< SDRAM0_CFG_BRPF_SHIFT ) - -#define SDRAM0_BXCR_SZ_MASK 0x000e0000 -#define SDRAM0_BXCR_AM_MASK 0x0000e000 - -#define SDRAM0_BXCR_SZ_SHIFT (31-14) -#define SDRAM0_BXCR_AM_SHIFT (31-18) - -#define SDRAM0_BXCR_SZ(x) ( (( x << SDRAM0_BXCR_SZ_SHIFT) & SDRAM0_BXCR_SZ_MASK) ) -#define SDRAM0_BXCR_AM(x) ( (( x << SDRAM0_BXCR_AM_SHIFT) & SDRAM0_BXCR_AM_MASK) ) - -#ifdef CONFIG_SPDDRAM_SILENT -# define SPD_ERR(x) do { return 0; } while (0) -#else -# define SPD_ERR(x) do { printf(x); return(0); } while (0) -#endif - -#define sdram_HZ_to_ns(hertz) (1000000000/(hertz)) - -/* function prototypes */ -int spd_read(uint addr); - - -/* - * This function is reading data from the DIMM module EEPROM over the SPD bus - * and uses that to program the sdram controller. - * - * This works on boards that has the same schematics that the AMCC walnut has. - * - * Input: null for default I2C spd functions or a pointer to a custom function - * returning spd_data. - */ - -long int spd_sdram(int(read_spd)(uint addr)) -{ - int tmp,row,col; - int total_size,bank_size,bank_code; - int ecc_on; - int mode; - int bank_cnt; - - int sdram0_pmit=0x07c00000; -#ifndef CONFIG_405EP /* not on PPC405EP */ - int sdram0_besr0=-1; - int sdram0_besr1=-1; - int sdram0_eccesr=-1; -#endif - int sdram0_ecccfg; - - int sdram0_rtr=0; - int sdram0_tr=0; - - int sdram0_b0cr; - int sdram0_b1cr; - int sdram0_b2cr; - int sdram0_b3cr; - - int sdram0_cfg=0; - - int t_rp; - int t_rcd; - int t_ras; - int t_rc; - int min_cas; - - PPC405_SYS_INFO sys_info; - unsigned long bus_period_x_10; - - /* - * get the board info - */ - get_sys_info(&sys_info); - bus_period_x_10 = ONE_BILLION / (sys_info.freqPLB / 10); - - if (read_spd == 0){ - read_spd=spd_read; - /* - * Make sure I2C controller is initialized - * before continuing. - */ - i2c_init(CFG_I2C_SPEED, CFG_I2C_SLAVE); - } - - /* Make shure we are using SDRAM */ - if (read_spd(2) != 0x04) { - SPD_ERR("SDRAM - non SDRAM memory module found\n"); - } - - /* ------------------------------------------------------------------ - * configure memory timing register - * - * data from DIMM: - * 27 IN Row Precharge Time ( t RP) - * 29 MIN RAS to CAS Delay ( t RCD) - * 127 Component and Clock Detail ,clk0-clk3, junction temp, CAS - * -------------------------------------------------------------------*/ - - /* - * first figure out which cas latency mode to use - * use the min supported mode - */ - - tmp = read_spd(127) & 0x6; - if (tmp == 0x02) { /* only cas = 2 supported */ - min_cas = 2; -/* t_ck = read_spd(9); */ -/* t_ac = read_spd(10); */ - } else if (tmp == 0x04) { /* only cas = 3 supported */ - min_cas = 3; -/* t_ck = read_spd(9); */ -/* t_ac = read_spd(10); */ - } else if (tmp == 0x06) { /* 2,3 supported, so use 2 */ - min_cas = 2; -/* t_ck = read_spd(23); */ -/* t_ac = read_spd(24); */ - } else { - SPD_ERR("SDRAM - unsupported CAS latency \n"); - } - - /* get some timing values, t_rp,t_rcd,t_ras,t_rc - */ - t_rp = read_spd(27); - t_rcd = read_spd(29); - t_ras = read_spd(30); - t_rc = t_ras + t_rp; - - /* The following timing calcs subtract 1 before deviding. - * this has effect of using ceiling instead of floor rounding, - * and also subtracting 1 to convert number to reg value - */ - /* set up CASL */ - sdram0_tr = (min_cas - 1) << SDRAM0_TR_CASL_SHIFT; - /* set up PTA */ - sdram0_tr |= ((((t_rp - 1) * 10)/bus_period_x_10) & 0x3) << SDRAM0_TR_PTA_SHIFT; - /* set up CTP */ - tmp = (((t_rc - t_rcd - t_rp -1) * 10) / bus_period_x_10) & 0x3; - if (tmp < 1) - tmp = 1; - sdram0_tr |= tmp << SDRAM0_TR_CTP_SHIFT; - /* set LDF = 2 cycles, reg value = 1 */ - sdram0_tr |= 1 << SDRAM0_TR_LDF_SHIFT; - /* set RFTA = t_rfc/bus_period, use t_rfc = t_rc */ - tmp = (((t_rc - 1) * 10) / bus_period_x_10) - 3; - if (tmp < 0) - tmp = 0; - if (tmp > 6) - tmp = 6; - sdram0_tr |= tmp << SDRAM0_TR_RFTA_SHIFT; - /* set RCD = t_rcd/bus_period*/ - sdram0_tr |= ((((t_rcd - 1) * 10) / bus_period_x_10) &0x3) << SDRAM0_TR_RCD_SHIFT ; - - - /*------------------------------------------------------------------ - * configure RTR register - * -------------------------------------------------------------------*/ - row = read_spd(3); - col = read_spd(4); - tmp = read_spd(12) & 0x7f ; /* refresh type less self refresh bit */ - switch (tmp) { - case 0x00: - tmp = 15625; - break; - case 0x01: - tmp = 15625 / 4; - break; - case 0x02: - tmp = 15625 / 2; - break; - case 0x03: - tmp = 15625 * 2; - break; - case 0x04: - tmp = 15625 * 4; - break; - case 0x05: - tmp = 15625 * 8; - break; - default: - SPD_ERR("SDRAM - Bad refresh period \n"); - } - /* convert from nsec to bus cycles */ - tmp = (tmp * 10) / bus_period_x_10; - sdram0_rtr = (tmp & 0x3ff8) << SDRAM0_RTR_SHIFT; - - /*------------------------------------------------------------------ - * determine the number of banks used - * -------------------------------------------------------------------*/ - /* byte 7:6 is module data width */ - if (read_spd(7) != 0) - SPD_ERR("SDRAM - unsupported module width\n"); - tmp = read_spd(6); - if (tmp < 32) - SPD_ERR("SDRAM - unsupported module width\n"); - else if (tmp < 64) - bank_cnt = 1; /* one bank per sdram side */ - else if (tmp < 73) - bank_cnt = 2; /* need two banks per side */ - else if (tmp < 161) - bank_cnt = 4; /* need four banks per side */ - else - SPD_ERR("SDRAM - unsupported module width\n"); - - /* byte 5 is the module row count (refered to as dimm "sides") */ - tmp = read_spd(5); - if (tmp == 1) - ; - else if (tmp==2) - bank_cnt *= 2; - else if (tmp==4) - bank_cnt *= 4; - else - bank_cnt = 8; /* 8 is an error code */ - - if (bank_cnt > 4) /* we only have 4 banks to work with */ - SPD_ERR("SDRAM - unsupported module rows for this width\n"); - - /* now check for ECC ability of module. We only support ECC - * on 32 bit wide devices with 8 bit ECC. - */ - if ((read_spd(11)==2) && (read_spd(6)==40) && (read_spd(14)==8)) { - sdram0_ecccfg = 0xf << SDRAM0_ECCCFG_SHIFT; - ecc_on = 1; - } else { - sdram0_ecccfg = 0; - ecc_on = 0; - } - - /*------------------------------------------------------------------ - * calculate total size - * -------------------------------------------------------------------*/ - /* calculate total size and do sanity check */ - tmp = read_spd(31); - total_size = 1 << 22; /* total_size = 4MB */ - /* now multiply 4M by the smallest device row density */ - /* note that we don't support asymetric rows */ - while (((tmp & 0x0001) == 0) && (tmp != 0)) { - total_size = total_size << 1; - tmp = tmp >> 1; - } - total_size *= read_spd(5); /* mult by module rows (dimm sides) */ - - /*------------------------------------------------------------------ - * map rows * cols * banks to a mode - * -------------------------------------------------------------------*/ - - switch (row) { - case 11: - switch (col) { - case 8: - mode=4; /* mode 5 */ - break; - case 9: - case 10: - mode=0; /* mode 1 */ - break; - default: - SPD_ERR("SDRAM - unsupported mode\n"); - } - break; - case 12: - switch (col) { - case 8: - mode=3; /* mode 4 */ - break; - case 9: - case 10: - mode=1; /* mode 2 */ - break; - default: - SPD_ERR("SDRAM - unsupported mode\n"); - } - break; - case 13: - switch (col) { - case 8: - mode=5; /* mode 6 */ - break; - case 9: - case 10: - if (read_spd(17) == 2) - mode = 6; /* mode 7 */ - else - mode = 2; /* mode 3 */ - break; - case 11: - mode = 2; /* mode 3 */ - break; - default: - SPD_ERR("SDRAM - unsupported mode\n"); - } - break; - default: - SPD_ERR("SDRAM - unsupported mode\n"); - } - - /*------------------------------------------------------------------ - * using the calculated values, compute the bank - * config register values. - * -------------------------------------------------------------------*/ - sdram0_b1cr = 0; - sdram0_b2cr = 0; - sdram0_b3cr = 0; - - /* compute the size of each bank */ - bank_size = total_size / bank_cnt; - /* convert bank size to bank size code for ppc4xx - by takeing log2(bank_size) - 22 */ - tmp = bank_size; /* start with tmp = bank_size */ - bank_code = 0; /* and bank_code = 0 */ - while (tmp > 1) { /* this takes log2 of tmp */ - bank_code++; /* and stores result in bank_code */ - tmp = tmp >> 1; - } /* bank_code is now log2(bank_size) */ - bank_code -= 22; /* subtract 22 to get the code */ - - tmp = SDRAM0_BXCR_SZ(bank_code) | SDRAM0_BXCR_AM(mode) | 1; - sdram0_b0cr = (bank_size * 0) | tmp; -#ifndef CONFIG_405EP /* not on PPC405EP */ - if (bank_cnt > 1) - sdram0_b2cr = (bank_size * 1) | tmp; - if (bank_cnt > 2) - sdram0_b1cr = (bank_size * 2) | tmp; - if (bank_cnt > 3) - sdram0_b3cr = (bank_size * 3) | tmp; -#else - /* PPC405EP chip only supports two SDRAM banks */ - if (bank_cnt > 1) - sdram0_b1cr = (bank_size * 1) | tmp; - if (bank_cnt > 2) - total_size = 2 * bank_size; -#endif - - /* - * enable sdram controller DCE=1 - * enable burst read prefetch to 32 bytes BRPF=2 - * leave other functions off - */ - - /*------------------------------------------------------------------ - * now that we've done our calculations, we are ready to - * program all the registers. - * -------------------------------------------------------------------*/ - -#define mtsdram0(reg, data) mtdcr(memcfga,reg);mtdcr(memcfgd,data) - /* disable memcontroller so updates work */ - mtsdram0( mem_mcopt1, 0 ); - -#ifndef CONFIG_405EP /* not on PPC405EP */ - mtsdram0( mem_besra , sdram0_besr0 ); - mtsdram0( mem_besrb , sdram0_besr1 ); - mtsdram0( mem_ecccf , sdram0_ecccfg ); - mtsdram0( mem_eccerr, sdram0_eccesr ); -#endif - mtsdram0( mem_rtr , sdram0_rtr ); - mtsdram0( mem_pmit , sdram0_pmit ); - mtsdram0( mem_mb0cf , sdram0_b0cr ); - mtsdram0( mem_mb1cf , sdram0_b1cr ); -#ifndef CONFIG_405EP /* not on PPC405EP */ - mtsdram0( mem_mb2cf , sdram0_b2cr ); - mtsdram0( mem_mb3cf , sdram0_b3cr ); -#endif - mtsdram0( mem_sdtr1 , sdram0_tr ); - - /* SDRAM have a power on delay, 500 micro should do */ - udelay(500); - sdram0_cfg = SDRAM0_CFG_DCE | SDRAM0_CFG_BRPF(1) | SDRAM0_CFG_ECCDD | SDRAM0_CFG_EMDULR; - if (ecc_on) - sdram0_cfg |= SDRAM0_CFG_MEMCHK; - mtsdram0(mem_mcopt1, sdram0_cfg); - - return (total_size); -} - -int spd_read(uint addr) -{ - uchar data[2]; - - if (i2c_read(SPD_EEPROM_ADDRESS, addr, 1, data, 1) == 0) - return (int)data[0]; - else - return 0; -} - -#else /* CONFIG_440 */ - /*----------------------------------------------------------------------------- | Memory Controller Options 0 +-----------------------------------------------------------------------------*/ @@ -631,6 +230,22 @@ int spd_read(uint addr) #define TRUE 1 #define FALSE 0 +/* + * This DDR2 setup code can dynamically setup the TLB entries for the DDR2 memory + * region. Right now the cache should still be disabled in U-Boot because of the + * EMAC driver, that need it's buffer descriptor to be located in non cached + * memory. + * + * If at some time this restriction doesn't apply anymore, just define + * CFG_ENABLE_SDRAM_CACHE in the board config file and this code should setup + * everything correctly. + */ +#ifdef CFG_ENABLE_SDRAM_CACHE +#define MY_TLB_WORD2_I_ENABLE 0 /* enable caching on SDRAM */ +#else +#define MY_TLB_WORD2_I_ENABLE TLB_WORD2_I_ENABLE /* disable caching on SDRAM */ +#endif + const unsigned long test[NUMMEMTESTS][NUMMEMWORDS] = { {0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF}, @@ -661,6 +276,7 @@ typedef struct bank_param BANKPARMS; #ifdef CFG_SIMULATE_SPD_EEPROM extern unsigned char cfg_simulate_spd_eeprom[128]; #endif +void program_tlb(u32 start, u32 size, u32 tlb_word2_i_value); unsigned char spd_read(uchar chip, uint addr); @@ -779,6 +395,11 @@ long int spd_sdram(void) { total_size = program_bxcr(dimm_populated, iic0_dimm_addr, num_dimm_banks); +#ifdef CONFIG_PROG_SDRAM_TLB /* this define should eventually be removed */ + /* and program tlb entries for this size (dynamic) */ + program_tlb(0, total_size, MY_TLB_WORD2_I_ENABLE); +#endif + /* * program SDRAM Clock Timing Register (SDRAM0_CLKTR) */ @@ -1732,11 +1353,11 @@ unsigned long program_bxcr(unsigned long* dimm_populated, */ cr |= SDRAM_BXCR_SDBE; - for (i = 0; i < num_banks; i++) { - bank_parms[ctrl_bank_num[dimm_num]+i].bank_size_bytes = + for (i = 0; i < num_banks; i++) { + bank_parms[ctrl_bank_num[dimm_num]+i+dimm_num].bank_size_bytes = (4 * 1024 * 1024) * bank_size_id; - bank_parms[ctrl_bank_num[dimm_num]+i].cr = cr; - } + bank_parms[ctrl_bank_num[dimm_num]+i+dimm_num].cr = cr; + } } } @@ -1825,7 +1446,4 @@ void program_ecc (unsigned long num_bytes) SDRAM_CFG0_MCHK_CHK); } } - -#endif /* CONFIG_440 */ - #endif /* CONFIG_SPD_EEPROM */ diff --git a/cpu/ppc4xx/44x_spd_ddr2.c b/cpu/ppc4xx/44x_spd_ddr2.c new file mode 100644 index 0000000..83c9911 --- /dev/null +++ b/cpu/ppc4xx/44x_spd_ddr2.c @@ -0,0 +1,2954 @@ +/* + * cpu/ppc4xx/44x_spd_ddr2.c + * This SPD SDRAM detection code supports AMCC PPC44x cpu's with a + * DDR2 controller (non Denali Core). Those are 440SP/SPe. + * + * (C) Copyright 2007 + * Stefan Roese, DENX Software Engineering, sr@denx.de. + * + * COPYRIGHT AMCC CORPORATION 2004 + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +/* define DEBUG for debugging output (obviously ;-)) */ +#if 0 +#define DEBUG +#endif + +#include <common.h> +#include <command.h> +#include <ppc4xx.h> +#include <i2c.h> +#include <asm/io.h> +#include <asm/processor.h> +#include <asm/mmu.h> + +#if defined(CONFIG_SPD_EEPROM) && \ + (defined(CONFIG_440SP) || defined(CONFIG_440SPE)) + +/*-----------------------------------------------------------------------------+ + * Defines + *-----------------------------------------------------------------------------*/ +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif + +#define SDRAM_DDR1 1 +#define SDRAM_DDR2 2 +#define SDRAM_NONE 0 + +#define MAXDIMMS 2 +#define MAXRANKS 4 +#define MAXBXCF 4 +#define MAX_SPD_BYTES 256 /* Max number of bytes on the DIMM's SPD EEPROM */ + +#define ONE_BILLION 1000000000 + +#define MULDIV64(m1, m2, d) (u32)(((u64)(m1) * (u64)(m2)) / (u64)(d)) + +#define CMD_NOP (7 << 19) +#define CMD_PRECHARGE (2 << 19) +#define CMD_REFRESH (1 << 19) +#define CMD_EMR (0 << 19) +#define CMD_READ (5 << 19) +#define CMD_WRITE (4 << 19) + +#define SELECT_MR (0 << 16) +#define SELECT_EMR (1 << 16) +#define SELECT_EMR2 (2 << 16) +#define SELECT_EMR3 (3 << 16) + +/* MR */ +#define DLL_RESET 0x00000100 + +#define WRITE_RECOV_2 (1 << 9) +#define WRITE_RECOV_3 (2 << 9) +#define WRITE_RECOV_4 (3 << 9) +#define WRITE_RECOV_5 (4 << 9) +#define WRITE_RECOV_6 (5 << 9) + +#define BURST_LEN_4 0x00000002 + +/* EMR */ +#define ODT_0_OHM 0x00000000 +#define ODT_50_OHM 0x00000044 +#define ODT_75_OHM 0x00000004 +#define ODT_150_OHM 0x00000040 + +#define ODS_FULL 0x00000000 +#define ODS_REDUCED 0x00000002 + +/* defines for ODT (On Die Termination) of the 440SP(e) DDR2 controller */ +#define ODT_EB0R (0x80000000 >> 8) +#define ODT_EB0W (0x80000000 >> 7) +#define CALC_ODT_R(n) (ODT_EB0R << (n << 1)) +#define CALC_ODT_W(n) (ODT_EB0W << (n << 1)) +#define CALC_ODT_RW(n) (CALC_ODT_R(n) | CALC_ODT_W(n)) + +/* Defines for the Read Cycle Delay test */ +#define NUMMEMTESTS 8 +#define NUMMEMWORDS 8 + +#define CONFIG_ECC_ERROR_RESET /* test-only: see description below, at check_ecc() */ + +/* + * This DDR2 setup code can dynamically setup the TLB entries for the DDR2 memory + * region. Right now the cache should still be disabled in U-Boot because of the + * EMAC driver, that need it's buffer descriptor to be located in non cached + * memory. + * + * If at some time this restriction doesn't apply anymore, just define + * CFG_ENABLE_SDRAM_CACHE in the board config file and this code should setup + * everything correctly. + */ +#ifdef CFG_ENABLE_SDRAM_CACHE +#define MY_TLB_WORD2_I_ENABLE 0 /* enable caching on SDRAM */ +#else +#define MY_TLB_WORD2_I_ENABLE TLB_WORD2_I_ENABLE /* disable caching on SDRAM */ +#endif + +/* Private Structure Definitions */ + +/* enum only to ease code for cas latency setting */ +typedef enum ddr_cas_id { + DDR_CAS_2 = 20, + DDR_CAS_2_5 = 25, + DDR_CAS_3 = 30, + DDR_CAS_4 = 40, + DDR_CAS_5 = 50 +} ddr_cas_id_t; + +/*-----------------------------------------------------------------------------+ + * Prototypes + *-----------------------------------------------------------------------------*/ +static unsigned long sdram_memsize(void); +void program_tlb(u32 start, u32 size, u32 tlb_word2_i_value); +static void get_spd_info(unsigned long *dimm_populated, + unsigned char *iic0_dimm_addr, + unsigned long num_dimm_banks); +static void check_mem_type(unsigned long *dimm_populated, + unsigned char *iic0_dimm_addr, + unsigned long num_dimm_banks); +static void check_frequency(unsigned long *dimm_populated, + unsigned char *iic0_dimm_addr, + unsigned long num_dimm_banks); +static void check_rank_number(unsigned long *dimm_populated, + unsigned char *iic0_dimm_addr, + unsigned long num_dimm_banks); +static void check_voltage_type(unsigned long *dimm_populated, + unsigned char *iic0_dimm_addr, + unsigned long num_dimm_banks); +static void program_memory_queue(unsigned long *dimm_populated, + unsigned char *iic0_dimm_addr, + unsigned long num_dimm_banks); +static void program_codt(unsigned long *dimm_populated, + unsigned char *iic0_dimm_addr, + unsigned long num_dimm_banks); +static void program_mode(unsigned long *dimm_populated, + unsigned char *iic0_dimm_addr, + unsigned long num_dimm_banks, + ddr_cas_id_t *selected_cas, + int *write_recovery); +static void program_tr(unsigned long *dimm_populated, + unsigned char *iic0_dimm_addr, + unsigned long num_dimm_banks); +static void program_rtr(unsigned long *dimm_populated, + unsigned char *iic0_dimm_addr, + unsigned long num_dimm_banks); +static void program_bxcf(unsigned long *dimm_populated, + unsigned char *iic0_dimm_addr, + unsigned long num_dimm_banks); +static void program_copt1(unsigned long *dimm_populated, + unsigned char *iic0_dimm_addr, + unsigned long num_dimm_banks); +static void program_initplr(unsigned long *dimm_populated, + unsigned char *iic0_dimm_addr, + unsigned long num_dimm_banks, + ddr_cas_id_t selected_cas, + int write_recovery); +static unsigned long is_ecc_enabled(void); +#ifdef CONFIG_DDR_ECC +static void program_ecc(unsigned long *dimm_populated, + unsigned char *iic0_dimm_addr, + unsigned long num_dimm_banks, + unsigned long tlb_word2_i_value); +static void program_ecc_addr(unsigned long start_address, + unsigned long num_bytes, + unsigned long tlb_word2_i_value); +#endif +static void program_DQS_calibration(unsigned long *dimm_populated, + unsigned char *iic0_dimm_addr, + unsigned long num_dimm_banks); +#ifdef HARD_CODED_DQS /* calibration test with hardvalues */ +static void test(void); +#else +static void DQS_calibration_process(void); +#endif +#if defined(DEBUG) +static void ppc440sp_sdram_register_dump(void); +#endif +int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]); +void dcbz_area(u32 start_address, u32 num_bytes); +void dflush(void); + +static u32 mfdcr_any(u32 dcr) +{ + u32 val; + + switch (dcr) { + case SDRAM_R0BAS + 0: + val = mfdcr(SDRAM_R0BAS + 0); + break; + case SDRAM_R0BAS + 1: + val = mfdcr(SDRAM_R0BAS + 1); + break; + case SDRAM_R0BAS + 2: + val = mfdcr(SDRAM_R0BAS + 2); + break; + case SDRAM_R0BAS + 3: + val = mfdcr(SDRAM_R0BAS + 3); + break; + default: + printf("DCR %d not defined in case statement!!!\n", dcr); + val = 0; /* just to satisfy the compiler */ + } + + return val; +} + +static void mtdcr_any(u32 dcr, u32 val) +{ + switch (dcr) { + case SDRAM_R0BAS + 0: + mtdcr(SDRAM_R0BAS + 0, val); + break; + case SDRAM_R0BAS + 1: + mtdcr(SDRAM_R0BAS + 1, val); + break; + case SDRAM_R0BAS + 2: + mtdcr(SDRAM_R0BAS + 2, val); + break; + case SDRAM_R0BAS + 3: + mtdcr(SDRAM_R0BAS + 3, val); + break; + default: + printf("DCR %d not defined in case statement!!!\n", dcr); + } +} + +static unsigned char spd_read(uchar chip, uint addr) +{ + unsigned char data[2]; + + if (i2c_probe(chip) == 0) + if (i2c_read(chip, addr, 1, data, 1) == 0) + return data[0]; + + return 0; +} + +/*-----------------------------------------------------------------------------+ + * sdram_memsize + *-----------------------------------------------------------------------------*/ +static unsigned long sdram_memsize(void) +{ + unsigned long mem_size; + unsigned long mcopt2; + unsigned long mcstat; + unsigned long mb0cf; + unsigned long sdsz; + unsigned long i; + + mem_size = 0; + + mfsdram(SDRAM_MCOPT2, mcopt2); + mfsdram(SDRAM_MCSTAT, mcstat); + + /* DDR controller must be enabled and not in self-refresh. */ + /* Otherwise memsize is zero. */ + if (((mcopt2 & SDRAM_MCOPT2_DCEN_MASK) == SDRAM_MCOPT2_DCEN_ENABLE) + && ((mcopt2 & SDRAM_MCOPT2_SREN_MASK) == SDRAM_MCOPT2_SREN_EXIT) + && ((mcstat & (SDRAM_MCSTAT_MIC_MASK | SDRAM_MCSTAT_SRMS_MASK)) + == (SDRAM_MCSTAT_MIC_COMP | SDRAM_MCSTAT_SRMS_NOT_SF))) { + for (i = 0; i < MAXBXCF; i++) { + mfsdram(SDRAM_MB0CF + (i << 2), mb0cf); + /* Banks enabled */ + if ((mb0cf & SDRAM_BXCF_M_BE_MASK) == SDRAM_BXCF_M_BE_ENABLE) { + sdsz = mfdcr_any(SDRAM_R0BAS + i) & SDRAM_RXBAS_SDSZ_MASK; + + switch(sdsz) { + case SDRAM_RXBAS_SDSZ_8: + mem_size+=8; + break; + case SDRAM_RXBAS_SDSZ_16: + mem_size+=16; + break; + case SDRAM_RXBAS_SDSZ_32: + mem_size+=32; + break; + case SDRAM_RXBAS_SDSZ_64: + mem_size+=64; + break; + case SDRAM_RXBAS_SDSZ_128: + mem_size+=128; + break; + case SDRAM_RXBAS_SDSZ_256: + mem_size+=256; + break; + case SDRAM_RXBAS_SDSZ_512: + mem_size+=512; + break; + case SDRAM_RXBAS_SDSZ_1024: + mem_size+=1024; + break; + case SDRAM_RXBAS_SDSZ_2048: + mem_size+=2048; + break; + case SDRAM_RXBAS_SDSZ_4096: + mem_size+=4096; + break; + default: + mem_size=0; + break; + } + } + } + } + + mem_size *= 1024 * 1024; + return(mem_size); +} + +/*-----------------------------------------------------------------------------+ + * initdram. Initializes the 440SP Memory Queue and DDR SDRAM controller. + * Note: This routine runs from flash with a stack set up in the chip's + * sram space. It is important that the routine does not require .sbss, .bss or + * .data sections. It also cannot call routines that require these sections. + *-----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------- + * Function: initdram + * Description: Configures SDRAM memory banks for DDR operation. + * Auto Memory Configuration option reads the DDR SDRAM EEPROMs + * via the IIC bus and then configures the DDR SDRAM memory + * banks appropriately. If Auto Memory Configuration is + * not used, it is assumed that no DIMM is plugged + *-----------------------------------------------------------------------------*/ +long int initdram(int board_type) +{ + unsigned char iic0_dimm_addr[] = SPD_EEPROM_ADDRESS; + unsigned char spd0[MAX_SPD_BYTES]; + unsigned char spd1[MAX_SPD_BYTES]; + unsigned char *dimm_spd[MAXDIMMS]; + unsigned long dimm_populated[MAXDIMMS]; + unsigned long num_dimm_banks; /* on board dimm banks */ + unsigned long val; + ddr_cas_id_t selected_cas; + int write_recovery; + unsigned long dram_size = 0; + + num_dimm_banks = sizeof(iic0_dimm_addr); + + /*------------------------------------------------------------------ + * Set up an array of SPD matrixes. + *-----------------------------------------------------------------*/ + dimm_spd[0] = spd0; + dimm_spd[1] = spd1; + + /*------------------------------------------------------------------ + * Reset the DDR-SDRAM controller. + *-----------------------------------------------------------------*/ + mtsdr(SDR0_SRST, (0x80000000 >> 10)); + mtsdr(SDR0_SRST, 0x00000000); + + /* + * Make sure I2C controller is initialized + * before continuing. + */ + + /* switch to correct I2C bus */ + I2C_SET_BUS(CFG_SPD_BUS_NUM); + i2c_init(CFG_I2C_SPEED, CFG_I2C_SLAVE); + + /*------------------------------------------------------------------ + * Clear out the serial presence detect buffers. + * Perform IIC reads from the dimm. Fill in the spds. + * Check to see if the dimm slots are populated + *-----------------------------------------------------------------*/ + get_spd_info(dimm_populated, iic0_dimm_addr, num_dimm_banks); + + /*------------------------------------------------------------------ + * Check the memory type for the dimms plugged. + *-----------------------------------------------------------------*/ + check_mem_type(dimm_populated, iic0_dimm_addr, num_dimm_banks); + + /*------------------------------------------------------------------ + * Check the frequency supported for the dimms plugged. + *-----------------------------------------------------------------*/ + check_frequency(dimm_populated, iic0_dimm_addr, num_dimm_banks); + + /*------------------------------------------------------------------ + * Check the total rank number. + *-----------------------------------------------------------------*/ + check_rank_number(dimm_populated, iic0_dimm_addr, num_dimm_banks); + + /*------------------------------------------------------------------ + * Check the voltage type for the dimms plugged. + *-----------------------------------------------------------------*/ + check_voltage_type(dimm_populated, iic0_dimm_addr, num_dimm_banks); + + /*------------------------------------------------------------------ + * Program SDRAM controller options 2 register + * Except Enabling of the memory controller. + *-----------------------------------------------------------------*/ + mfsdram(SDRAM_MCOPT2, val); + mtsdram(SDRAM_MCOPT2, + (val & + ~(SDRAM_MCOPT2_SREN_MASK | SDRAM_MCOPT2_PMEN_MASK | + SDRAM_MCOPT2_IPTR_MASK | SDRAM_MCOPT2_XSRP_MASK | + SDRAM_MCOPT2_ISIE_MASK)) + | (SDRAM_MCOPT2_SREN_ENTER | SDRAM_MCOPT2_PMEN_DISABLE | + SDRAM_MCOPT2_IPTR_IDLE | SDRAM_MCOPT2_XSRP_ALLOW | + SDRAM_MCOPT2_ISIE_ENABLE)); + + /*------------------------------------------------------------------ + * Program SDRAM controller options 1 register + * Note: Does not enable the memory controller. + *-----------------------------------------------------------------*/ + program_copt1(dimm_populated, iic0_dimm_addr, num_dimm_banks); + + /*------------------------------------------------------------------ + * Set the SDRAM Controller On Die Termination Register + *-----------------------------------------------------------------*/ + program_codt(dimm_populated, iic0_dimm_addr, num_dimm_banks); + + /*------------------------------------------------------------------ + * Program SDRAM refresh register. + *-----------------------------------------------------------------*/ + program_rtr(dimm_populated, iic0_dimm_addr, num_dimm_banks); + + /*------------------------------------------------------------------ + * Program SDRAM mode register. + *-----------------------------------------------------------------*/ + program_mode(dimm_populated, iic0_dimm_addr, num_dimm_banks, + &selected_cas, &write_recovery); + + /*------------------------------------------------------------------ + * Set the SDRAM Write Data/DM/DQS Clock Timing Reg + *-----------------------------------------------------------------*/ + mfsdram(SDRAM_WRDTR, val); + mtsdram(SDRAM_WRDTR, (val & ~(SDRAM_WRDTR_LLWP_MASK | SDRAM_WRDTR_WTR_MASK)) | + (SDRAM_WRDTR_LLWP_1_CYC | SDRAM_WRDTR_WTR_90_DEG_ADV)); + + /*------------------------------------------------------------------ + * Set the SDRAM Clock Timing Register + *-----------------------------------------------------------------*/ + mfsdram(SDRAM_CLKTR, val); + mtsdram(SDRAM_CLKTR, (val & ~SDRAM_CLKTR_CLKP_MASK) | SDRAM_CLKTR_CLKP_0_DEG); + + /*------------------------------------------------------------------ + * Program the BxCF registers. + *-----------------------------------------------------------------*/ + program_bxcf(dimm_populated, iic0_dimm_addr, num_dimm_banks); + + /*------------------------------------------------------------------ + * Program SDRAM timing registers. + *-----------------------------------------------------------------*/ + program_tr(dimm_populated, iic0_dimm_addr, num_dimm_banks); + + /*------------------------------------------------------------------ + * Set the Extended Mode register + *-----------------------------------------------------------------*/ + mfsdram(SDRAM_MEMODE, val); + mtsdram(SDRAM_MEMODE, + (val & ~(SDRAM_MEMODE_DIC_MASK | SDRAM_MEMODE_DLL_MASK | + SDRAM_MEMODE_RTT_MASK | SDRAM_MEMODE_DQS_MASK)) | + (SDRAM_MEMODE_DIC_NORMAL | SDRAM_MEMODE_DLL_ENABLE + | SDRAM_MEMODE_RTT_150OHM | SDRAM_MEMODE_DQS_ENABLE)); + + /*------------------------------------------------------------------ + * Program Initialization preload registers. + *-----------------------------------------------------------------*/ + program_initplr(dimm_populated, iic0_dimm_addr, num_dimm_banks, + selected_cas, write_recovery); + + /*------------------------------------------------------------------ + * Delay to ensure 200usec have elapsed since reset. + *-----------------------------------------------------------------*/ + udelay(400); + + /*------------------------------------------------------------------ + * Set the memory queue core base addr. + *-----------------------------------------------------------------*/ + program_memory_queue(dimm_populated, iic0_dimm_addr, num_dimm_banks); + + /*------------------------------------------------------------------ + * Program SDRAM controller options 2 register + * Enable the memory controller. + *-----------------------------------------------------------------*/ + mfsdram(SDRAM_MCOPT2, val); + mtsdram(SDRAM_MCOPT2, + (val & ~(SDRAM_MCOPT2_SREN_MASK | SDRAM_MCOPT2_DCEN_MASK | + SDRAM_MCOPT2_IPTR_MASK | SDRAM_MCOPT2_ISIE_MASK)) | + (SDRAM_MCOPT2_DCEN_ENABLE | SDRAM_MCOPT2_IPTR_EXECUTE)); + + /*------------------------------------------------------------------ + * Wait for SDRAM_CFG0_DC_EN to complete. + *-----------------------------------------------------------------*/ + do { + mfsdram(SDRAM_MCSTAT, val); + } while ((val & SDRAM_MCSTAT_MIC_MASK) == SDRAM_MCSTAT_MIC_NOTCOMP); + + /* get installed memory size */ + dram_size = sdram_memsize(); + + /* and program tlb entries for this size (dynamic) */ + program_tlb(0, dram_size, MY_TLB_WORD2_I_ENABLE); + + /*------------------------------------------------------------------ + * DQS calibration. + *-----------------------------------------------------------------*/ + program_DQS_calibration(dimm_populated, iic0_dimm_addr, num_dimm_banks); + +#ifdef CONFIG_DDR_ECC + /*------------------------------------------------------------------ + * If ecc is enabled, initialize the parity bits. + *-----------------------------------------------------------------*/ + program_ecc(dimm_populated, iic0_dimm_addr, num_dimm_banks, MY_TLB_WORD2_I_ENABLE); +#endif + +#ifdef DEBUG + ppc440sp_sdram_register_dump(); +#endif + + return dram_size; +} + +static void get_spd_info(unsigned long *dimm_populated, + unsigned char *iic0_dimm_addr, + unsigned long num_dimm_banks) +{ + unsigned long dimm_num; + unsigned long dimm_found; + unsigned char num_of_bytes; + unsigned char total_size; + + dimm_found = FALSE; + for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) { + num_of_bytes = 0; + total_size = 0; + + num_of_bytes = spd_read(iic0_dimm_addr[dimm_num], 0); + debug("\nspd_read(0x%x) returned %d\n", + iic0_dimm_addr[dimm_num], num_of_bytes); + total_size = spd_read(iic0_dimm_addr[dimm_num], 1); + debug("spd_read(0x%x) returned %d\n", + iic0_dimm_addr[dimm_num], total_size); + + if ((num_of_bytes != 0) && (total_size != 0)) { + dimm_populated[dimm_num] = TRUE; + dimm_found = TRUE; + debug("DIMM slot %lu: populated\n", dimm_num); + } else { + dimm_populated[dimm_num] = FALSE; + debug("DIMM slot %lu: Not populated\n", dimm_num); + } + } + + if (dimm_found == FALSE) { + printf("ERROR - No memory installed. Install a DDR-SDRAM DIMM.\n\n"); + hang(); + } +} + +#ifdef CONFIG_ADD_RAM_INFO +void board_add_ram_info(int use_default) +{ + if (is_ecc_enabled()) + puts(" (ECC enabled)"); + else + puts(" (ECC not enabled)"); +} +#endif + +/*------------------------------------------------------------------ + * For the memory DIMMs installed, this routine verifies that they + * really are DDR specific DIMMs. + *-----------------------------------------------------------------*/ +static void check_mem_type(unsigned long *dimm_populated, + unsigned char *iic0_dimm_addr, + unsigned long num_dimm_banks) +{ + unsigned long dimm_num; + unsigned long dimm_type; + + for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) { + if (dimm_populated[dimm_num] == TRUE) { + dimm_type = spd_read(iic0_dimm_addr[dimm_num], 2); + switch (dimm_type) { + case 1: + printf("ERROR: Standard Fast Page Mode DRAM DIMM detected in " + "slot %d.\n", (unsigned int)dimm_num); + printf("Only DDR and DDR2 SDRAM DIMMs are supported.\n"); + printf("Replace the DIMM module with a supported DIMM.\n\n"); + hang(); + break; + case 2: + printf("ERROR: EDO DIMM detected in slot %d.\n", + (unsigned int)dimm_num); + printf("Only DDR and DDR2 SDRAM DIMMs are supported.\n"); + printf("Replace the DIMM module with a supported DIMM.\n\n"); + hang(); + break; + case 3: + printf("ERROR: Pipelined Nibble DIMM detected in slot %d.\n", + (unsigned int)dimm_num); + printf("Only DDR and DDR2 SDRAM DIMMs are supported.\n"); + printf("Replace the DIMM module with a supported DIMM.\n\n"); + hang(); + break; + case 4: + printf("ERROR: SDRAM DIMM detected in slot %d.\n", + (unsigned int)dimm_num); + printf("Only DDR and DDR2 SDRAM DIMMs are supported.\n"); + printf("Replace the DIMM module with a supported DIMM.\n\n"); + hang(); + break; + case 5: + printf("ERROR: Multiplexed ROM DIMM detected in slot %d.\n", + (unsigned int)dimm_num); + printf("Only DDR and DDR2 SDRAM DIMMs are supported.\n"); + printf("Replace the DIMM module with a supported DIMM.\n\n"); + hang(); + break; + case 6: + printf("ERROR: SGRAM DIMM detected in slot %d.\n", + (unsigned int)dimm_num); + printf("Only DDR and DDR2 SDRAM DIMMs are supported.\n"); + printf("Replace the DIMM module with a supported DIMM.\n\n"); + hang(); + break; + case 7: + debug("DIMM slot %d: DDR1 SDRAM detected\n", dimm_num); + dimm_populated[dimm_num] = SDRAM_DDR1; + break; + case 8: + debug("DIMM slot %d: DDR2 SDRAM detected\n", dimm_num); + dimm_populated[dimm_num] = SDRAM_DDR2; + break; + default: + printf("ERROR: Unknown DIMM detected in slot %d.\n", + (unsigned int)dimm_num); + printf("Only DDR1 and DDR2 SDRAM DIMMs are supported.\n"); + printf("Replace the DIMM module with a supported DIMM.\n\n"); + hang(); + break; + } + } + } + for (dimm_num = 1; dimm_num < num_dimm_banks; dimm_num++) { + if ((dimm_populated[dimm_num-1] != SDRAM_NONE) + && (dimm_populated[dimm_num] != SDRAM_NONE) + && (dimm_populated[dimm_num-1] != dimm_populated[dimm_num])) { + printf("ERROR: DIMM's DDR1 and DDR2 type can not be mixed.\n"); + hang(); + } + } +} + +/*------------------------------------------------------------------ + * For the memory DIMMs installed, this routine verifies that + * frequency previously calculated is supported. + *-----------------------------------------------------------------*/ +static void check_frequency(unsigned long *dimm_populated, + unsigned char *iic0_dimm_addr, + unsigned long num_dimm_banks) +{ + unsigned long dimm_num; + unsigned long tcyc_reg; + unsigned long cycle_time; + unsigned long calc_cycle_time; + unsigned long sdram_freq; + unsigned long sdr_ddrpll; + PPC440_SYS_INFO board_cfg; + + /*------------------------------------------------------------------ + * Get the board configuration info. + *-----------------------------------------------------------------*/ + get_sys_info(&board_cfg); + + mfsdr(SDR0_DDR0, sdr_ddrpll); + sdram_freq = ((board_cfg.freqPLB) * SDR0_DDR0_DDRM_DECODE(sdr_ddrpll)); + + /* + * calc_cycle_time is calculated from DDR frequency set by board/chip + * and is expressed in multiple of 10 picoseconds + * to match the way DIMM cycle time is calculated below. + */ + calc_cycle_time = MULDIV64(ONE_BILLION, 100, sdram_freq); + + for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) { + if (dimm_populated[dimm_num] != SDRAM_NONE) { + tcyc_reg = spd_read(iic0_dimm_addr[dimm_num], 9); + /* + * Byte 9, Cycle time for CAS Latency=X, is split into two nibbles: + * the higher order nibble (bits 4-7) designates the cycle time + * to a granularity of 1ns; + * the value presented by the lower order nibble (bits 0-3) + * has a granularity of .1ns and is added to the value designated + * by the higher nibble. In addition, four lines of the lower order + * nibble are assigned to support +.25,+.33, +.66 and +.75. + */ + /* Convert from hex to decimal */ + if ((tcyc_reg & 0x0F) == 0x0D) + cycle_time = (((tcyc_reg & 0xF0) >> 4) * 100) + 75; + else if ((tcyc_reg & 0x0F) == 0x0C) + cycle_time = (((tcyc_reg & 0xF0) >> 4) * 100) + 66; + else if ((tcyc_reg & 0x0F) == 0x0B) + cycle_time = (((tcyc_reg & 0xF0) >> 4) * 100) + 33; + else if ((tcyc_reg & 0x0F) == 0x0A) + cycle_time = (((tcyc_reg & 0xF0) >> 4) * 100) + 25; + else + cycle_time = (((tcyc_reg & 0xF0) >> 4) * 100) + + ((tcyc_reg & 0x0F)*10); + + if (cycle_time > (calc_cycle_time + 10)) { + /* + * the provided sdram cycle_time is too small + * for the available DIMM cycle_time. + * The additionnal 100ps is here to accept a small incertainty. + */ + printf("ERROR: DRAM DIMM detected with cycle_time %d ps in " + "slot %d \n while calculated cycle time is %d ps.\n", + (unsigned int)(cycle_time*10), + (unsigned int)dimm_num, + (unsigned int)(calc_cycle_time*10)); + printf("Replace the DIMM, or change DDR frequency via " + "strapping bits.\n\n"); + hang(); + } + } + } +} + +/*------------------------------------------------------------------ + * For the memory DIMMs installed, this routine verifies two + * ranks/banks maximum are availables. + *-----------------------------------------------------------------*/ +static void check_rank_number(unsigned long *dimm_populated, + unsigned char *iic0_dimm_addr, + unsigned long num_dimm_banks) +{ + unsigned long dimm_num; + unsigned long dimm_rank; + unsigned long total_rank = 0; + + for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) { + if (dimm_populated[dimm_num] != SDRAM_NONE) { + dimm_rank = spd_read(iic0_dimm_addr[dimm_num], 5); + if (((unsigned long)spd_read(iic0_dimm_addr[dimm_num], 2)) == 0x08) + dimm_rank = (dimm_rank & 0x0F) +1; + else + dimm_rank = dimm_rank & 0x0F; + + + if (dimm_rank > MAXRANKS) { + printf("ERROR: DRAM DIMM detected with %d ranks in " + "slot %d is not supported.\n", dimm_rank, dimm_num); + printf("Only %d ranks are supported for all DIMM.\n", MAXRANKS); + printf("Replace the DIMM module with a supported DIMM.\n\n"); + hang(); + } else + total_rank += dimm_rank; + } + if (total_rank > MAXRANKS) { + printf("ERROR: DRAM DIMM detected with a total of %d ranks " + "for all slots.\n", (unsigned int)total_rank); + printf("Only %d ranks are supported for all DIMM.\n", MAXRANKS); + printf("Remove one of the DIMM modules.\n\n"); + hang(); + } + } +} + +/*------------------------------------------------------------------ + * only support 2.5V modules. + * This routine verifies this. + *-----------------------------------------------------------------*/ +static void check_voltage_type(unsigned long *dimm_populated, + unsigned char *iic0_dimm_addr, + unsigned long num_dimm_banks) +{ + unsigned long dimm_num; + unsigned long voltage_type; + + for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) { + if (dimm_populated[dimm_num] != SDRAM_NONE) { + voltage_type = spd_read(iic0_dimm_addr[dimm_num], 8); + switch (voltage_type) { + case 0x00: + printf("ERROR: Only DIMMs DDR 2.5V or DDR2 1.8V are supported.\n"); + printf("This DIMM is 5.0 Volt/TTL.\n"); + printf("Replace the DIMM module in slot %d with a supported DIMM.\n\n", + (unsigned int)dimm_num); + hang(); + break; + case 0x01: + printf("ERROR: Only DIMMs DDR 2.5V or DDR2 1.8V are supported.\n"); + printf("This DIMM is LVTTL.\n"); + printf("Replace the DIMM module in slot %d with a supported DIMM.\n\n", + (unsigned int)dimm_num); + hang(); + break; + case 0x02: + printf("ERROR: Only DIMMs DDR 2.5V or DDR2 1.8V are supported.\n"); + printf("This DIMM is 1.5 Volt.\n"); + printf("Replace the DIMM module in slot %d with a supported DIMM.\n\n", + (unsigned int)dimm_num); + hang(); + break; + case 0x03: + printf("ERROR: Only DIMMs DDR 2.5V or DDR2 1.8V are supported.\n"); + printf("This DIMM is 3.3 Volt/TTL.\n"); + printf("Replace the DIMM module in slot %d with a supported DIMM.\n\n", + (unsigned int)dimm_num); + hang(); + break; + case 0x04: + /* 2.5 Voltage only for DDR1 */ + break; + case 0x05: + /* 1.8 Voltage only for DDR2 */ + break; + default: + printf("ERROR: Only DIMMs DDR 2.5V or DDR2 1.8V are supported.\n"); + printf("Replace the DIMM module in slot %d with a supported DIMM.\n\n", + (unsigned int)dimm_num); + hang(); + break; + } + } + } +} + +/*-----------------------------------------------------------------------------+ + * program_copt1. + *-----------------------------------------------------------------------------*/ +static void program_copt1(unsigned long *dimm_populated, + unsigned char *iic0_dimm_addr, + unsigned long num_dimm_banks) +{ + unsigned long dimm_num; + unsigned long mcopt1; + unsigned long ecc_enabled; + unsigned long ecc = 0; + unsigned long data_width = 0; + unsigned long dimm_32bit; + unsigned long dimm_64bit; + unsigned long registered = 0; + unsigned long attribute = 0; + unsigned long buf0, buf1; /* TODO: code to be changed for IOP1.6 to support 4 DIMMs */ + unsigned long bankcount; + unsigned long ddrtype; + unsigned long val; + +#ifdef CONFIG_DDR_ECC + ecc_enabled = TRUE; +#else + ecc_enabled = FALSE; +#endif + dimm_32bit = FALSE; + dimm_64bit = FALSE; + buf0 = FALSE; + buf1 = FALSE; + + /*------------------------------------------------------------------ + * Set memory controller options reg 1, SDRAM_MCOPT1. + *-----------------------------------------------------------------*/ + mfsdram(SDRAM_MCOPT1, val); + mcopt1 = val & ~(SDRAM_MCOPT1_MCHK_MASK | SDRAM_MCOPT1_RDEN_MASK | + SDRAM_MCOPT1_PMU_MASK | SDRAM_MCOPT1_DMWD_MASK | + SDRAM_MCOPT1_UIOS_MASK | SDRAM_MCOPT1_BCNT_MASK | + SDRAM_MCOPT1_DDR_TYPE_MASK | SDRAM_MCOPT1_RWOO_MASK | + SDRAM_MCOPT1_WOOO_MASK | SDRAM_MCOPT1_DCOO_MASK | + SDRAM_MCOPT1_DREF_MASK); + + mcopt1 |= SDRAM_MCOPT1_QDEP; + mcopt1 |= SDRAM_MCOPT1_PMU_OPEN; + mcopt1 |= SDRAM_MCOPT1_RWOO_DISABLED; + mcopt1 |= SDRAM_MCOPT1_WOOO_DISABLED; + mcopt1 |= SDRAM_MCOPT1_DCOO_DISABLED; + mcopt1 |= SDRAM_MCOPT1_DREF_NORMAL; + + for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) { + if (dimm_populated[dimm_num] != SDRAM_NONE) { + /* test ecc support */ + ecc = (unsigned long)spd_read(iic0_dimm_addr[dimm_num], 11); + if (ecc != 0x02) /* ecc not supported */ + ecc_enabled = FALSE; + + /* test bank count */ + bankcount = (unsigned long)spd_read(iic0_dimm_addr[dimm_num], 17); + if (bankcount == 0x04) /* bank count = 4 */ + mcopt1 |= SDRAM_MCOPT1_4_BANKS; + else /* bank count = 8 */ + mcopt1 |= SDRAM_MCOPT1_8_BANKS; + + /* test DDR type */ + ddrtype = (unsigned long)spd_read(iic0_dimm_addr[dimm_num], 2); + /* test for buffered/unbuffered, registered, differential clocks */ + registered = (unsigned long)spd_read(iic0_dimm_addr[dimm_num], 20); + attribute = (unsigned long)spd_read(iic0_dimm_addr[dimm_num], 21); + + /* TODO: code to be changed for IOP1.6 to support 4 DIMMs */ + if (dimm_num == 0) { + if (dimm_populated[dimm_num] == SDRAM_DDR1) /* DDR1 type */ + mcopt1 |= SDRAM_MCOPT1_DDR1_TYPE; + if (dimm_populated[dimm_num] == SDRAM_DDR2) /* DDR2 type */ + mcopt1 |= SDRAM_MCOPT1_DDR2_TYPE; + if (registered == 1) { /* DDR2 always buffered */ + /* TODO: what about above comments ? */ + mcopt1 |= SDRAM_MCOPT1_RDEN; + buf0 = TRUE; + } else { + /* TODO: the mask 0x02 doesn't match Samsung def for byte 21. */ + if ((attribute & 0x02) == 0x00) { + /* buffered not supported */ + buf0 = FALSE; + } else { + mcopt1 |= SDRAM_MCOPT1_RDEN; + buf0 = TRUE; + } + } + } + else if (dimm_num == 1) { + if (dimm_populated[dimm_num] == SDRAM_DDR1) /* DDR1 type */ + mcopt1 |= SDRAM_MCOPT1_DDR1_TYPE; + if (dimm_populated[dimm_num] == SDRAM_DDR2) /* DDR2 type */ + mcopt1 |= SDRAM_MCOPT1_DDR2_TYPE; + if (registered == 1) { + /* DDR2 always buffered */ + mcopt1 |= SDRAM_MCOPT1_RDEN; + buf1 = TRUE; + } else { + if ((attribute & 0x02) == 0x00) { + /* buffered not supported */ + buf1 = FALSE; + } else { + mcopt1 |= SDRAM_MCOPT1_RDEN; + buf1 = TRUE; + } + } + } + + /* Note that for DDR2 the byte 7 is reserved, but OK to keep code as is. */ + data_width = (unsigned long)spd_read(iic0_dimm_addr[dimm_num], 6) + + (((unsigned long)spd_read(iic0_dimm_addr[dimm_num], 7)) << 8); + + switch (data_width) { + case 72: + case 64: + dimm_64bit = TRUE; + break; + case 40: + case 32: + dimm_32bit = TRUE; + break; + default: + printf("WARNING: Detected a DIMM with a data width of %d bits.\n", + data_width); + printf("Only DIMMs with 32 or 64 bit DDR-SDRAM widths are supported.\n"); + break; + } + } + } + + /* verify matching properties */ + if ((dimm_populated[0] != SDRAM_NONE) && (dimm_populated[1] != SDRAM_NONE)) { + if (buf0 != buf1) { + printf("ERROR: DIMM's buffered/unbuffered, registered, clocking don't match.\n"); + hang(); + } + } + + if ((dimm_64bit == TRUE) && (dimm_32bit == TRUE)) { + printf("ERROR: Cannot mix 32 bit and 64 bit DDR-SDRAM DIMMs together.\n"); + hang(); + } + else if ((dimm_64bit == TRUE) && (dimm_32bit == FALSE)) { + mcopt1 |= SDRAM_MCOPT1_DMWD_64; + } else if ((dimm_64bit == FALSE) && (dimm_32bit == TRUE)) { + mcopt1 |= SDRAM_MCOPT1_DMWD_32; + } else { + printf("ERROR: Please install only 32 or 64 bit DDR-SDRAM DIMMs.\n\n"); + hang(); + } + + if (ecc_enabled == TRUE) + mcopt1 |= SDRAM_MCOPT1_MCHK_GEN; + else + mcopt1 |= SDRAM_MCOPT1_MCHK_NON; + + mtsdram(SDRAM_MCOPT1, mcopt1); +} + +/*-----------------------------------------------------------------------------+ + * program_codt. + *-----------------------------------------------------------------------------*/ +static void program_codt(unsigned long *dimm_populated, + unsigned char *iic0_dimm_addr, + unsigned long num_dimm_banks) +{ + unsigned long codt; + unsigned long modt0 = 0; + unsigned long modt1 = 0; + unsigned long modt2 = 0; + unsigned long modt3 = 0; + unsigned char dimm_num; + unsigned char dimm_rank; + unsigned char total_rank = 0; + unsigned char total_dimm = 0; + unsigned char dimm_type = 0; + unsigned char firstSlot = 0; + + /*------------------------------------------------------------------ + * Set the SDRAM Controller On Die Termination Register + *-----------------------------------------------------------------*/ + mfsdram(SDRAM_CODT, codt); + codt |= (SDRAM_CODT_IO_NMODE + & (~SDRAM_CODT_DQS_SINGLE_END + & ~SDRAM_CODT_CKSE_SINGLE_END + & ~SDRAM_CODT_FEEBBACK_RCV_SINGLE_END + & ~SDRAM_CODT_FEEBBACK_DRV_SINGLE_END)); + + for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) { + if (dimm_populated[dimm_num] != SDRAM_NONE) { + dimm_rank = (unsigned long)spd_read(iic0_dimm_addr[dimm_num], 5); + if (((unsigned long)spd_read(iic0_dimm_addr[dimm_num], 2)) == 0x08) { + dimm_rank = (dimm_rank & 0x0F) + 1; + dimm_type = SDRAM_DDR2; + } else { + dimm_rank = dimm_rank & 0x0F; + dimm_type = SDRAM_DDR1; + } + + total_rank += dimm_rank; + total_dimm++; + if ((dimm_num == 0) && (total_dimm == 1)) + firstSlot = TRUE; + else + firstSlot = FALSE; + } + } + if (dimm_type == SDRAM_DDR2) { + codt |= SDRAM_CODT_DQS_1_8_V_DDR2; + if ((total_dimm == 1) && (firstSlot == TRUE)) { + if (total_rank == 1) { + codt |= CALC_ODT_R(0); + modt0 = CALC_ODT_W(0); + modt1 = 0x00000000; + modt2 = 0x00000000; + modt3 = 0x00000000; + } + if (total_rank == 2) { + codt |= CALC_ODT_R(0) | CALC_ODT_R(1); + modt0 = CALC_ODT_W(0); + modt1 = CALC_ODT_W(0); + modt2 = 0x00000000; + modt3 = 0x00000000; + } + } else if ((total_dimm == 1) && (firstSlot != TRUE)) { + if (total_rank == 1) { + codt |= CALC_ODT_R(2); + modt0 = 0x00000000; + modt1 = 0x00000000; + modt2 = CALC_ODT_W(2); + modt3 = 0x00000000; + } + if (total_rank == 2) { + codt |= CALC_ODT_R(2) | CALC_ODT_R(3); + modt0 = 0x00000000; + modt1 = 0x00000000; + modt2 = CALC_ODT_W(2); + modt3 = CALC_ODT_W(2); + } + } + if (total_dimm == 2) { + if (total_rank == 2) { + codt |= CALC_ODT_R(0) | CALC_ODT_R(2); + modt0 = CALC_ODT_RW(2); + modt1 = 0x00000000; + modt2 = CALC_ODT_RW(0); + modt3 = 0x00000000; + } + if (total_rank == 4) { + codt |= CALC_ODT_R(0) | CALC_ODT_R(1) | CALC_ODT_R(2) | CALC_ODT_R(3); + modt0 = CALC_ODT_RW(2); + modt1 = 0x00000000; + modt2 = CALC_ODT_RW(0); + modt3 = 0x00000000; + } + } + } else { + codt |= SDRAM_CODT_DQS_2_5_V_DDR1; + modt0 = 0x00000000; + modt1 = 0x00000000; + modt2 = 0x00000000; + modt3 = 0x00000000; + + if (total_dimm == 1) { + if (total_rank == 1) + codt |= 0x00800000; + if (total_rank == 2) + codt |= 0x02800000; + } + if (total_dimm == 2) { + if (total_rank == 2) + codt |= 0x08800000; + if (total_rank == 4) + codt |= 0x2a800000; + } + } + + debug("nb of dimm %d\n", total_dimm); + debug("nb of rank %d\n", total_rank); + if (total_dimm == 1) + debug("dimm in slot %d\n", firstSlot); + + mtsdram(SDRAM_CODT, codt); + mtsdram(SDRAM_MODT0, modt0); + mtsdram(SDRAM_MODT1, modt1); + mtsdram(SDRAM_MODT2, modt2); + mtsdram(SDRAM_MODT3, modt3); +} + +/*-----------------------------------------------------------------------------+ + * program_initplr. + *-----------------------------------------------------------------------------*/ +static void program_initplr(unsigned long *dimm_populated, + unsigned char *iic0_dimm_addr, + unsigned long num_dimm_banks, + ddr_cas_id_t selected_cas, + int write_recovery) +{ + u32 cas = 0; + u32 odt = 0; + u32 ods = 0; + u32 mr; + u32 wr; + u32 emr; + u32 emr2; + u32 emr3; + int dimm_num; + int total_dimm = 0; + + /****************************************************** + ** Assumption: if more than one DIMM, all DIMMs are the same + ** as already checked in check_memory_type + ******************************************************/ + + if ((dimm_populated[0] == SDRAM_DDR1) || (dimm_populated[1] == SDRAM_DDR1)) { + mtsdram(SDRAM_INITPLR0, 0x81B80000); + mtsdram(SDRAM_INITPLR1, 0x81900400); + mtsdram(SDRAM_INITPLR2, 0x81810000); + mtsdram(SDRAM_INITPLR3, 0xff800162); + mtsdram(SDRAM_INITPLR4, 0x81900400); + mtsdram(SDRAM_INITPLR5, 0x86080000); + mtsdram(SDRAM_INITPLR6, 0x86080000); + mtsdram(SDRAM_INITPLR7, 0x81000062); + } else if ((dimm_populated[0] == SDRAM_DDR2) || (dimm_populated[1] == SDRAM_DDR2)) { + switch (selected_cas) { + case DDR_CAS_3: + cas = 3 << 4; + break; + case DDR_CAS_4: + cas = 4 << 4; + break; + case DDR_CAS_5: + cas = 5 << 4; + break; + default: + printf("ERROR: ucode error on selected_cas value %d", selected_cas); + hang(); + break; + } + +#if 0 + /* + * ToDo - Still a problem with the write recovery: + * On the Corsair CM2X512-5400C4 module, setting write recovery + * in the INITPLR reg to the value calculated in program_mode() + * results in not correctly working DDR2 memory (crash after + * relocation). + * + * So for now, set the write recovery to 3. This seems to work + * on the Corair module too. + * + * 2007-03-01, sr + */ + switch (write_recovery) { + case 3: + wr = WRITE_RECOV_3; + break; + case 4: + wr = WRITE_RECOV_4; + break; + case 5: + wr = WRITE_RECOV_5; + break; + case 6: + wr = WRITE_RECOV_6; + break; + default: + printf("ERROR: write recovery not support (%d)", write_recovery); + hang(); + break; + } +#else + wr = WRITE_RECOV_3; /* test-only, see description above */ +#endif + + for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) + if (dimm_populated[dimm_num] != SDRAM_NONE) + total_dimm++; + if (total_dimm == 1) { + odt = ODT_150_OHM; + ods = ODS_FULL; + } else if (total_dimm == 2) { + odt = ODT_75_OHM; + ods = ODS_REDUCED; + } else { + printf("ERROR: Unsupported number of DIMM's (%d)", total_dimm); + hang(); + } + + mr = CMD_EMR | SELECT_MR | BURST_LEN_4 | wr | cas; + emr = CMD_EMR | SELECT_EMR | odt | ods; + emr2 = CMD_EMR | SELECT_EMR2; + emr3 = CMD_EMR | SELECT_EMR3; + mtsdram(SDRAM_INITPLR0, 0xB5000000 | CMD_NOP); /* NOP */ + udelay(1000); + mtsdram(SDRAM_INITPLR1, 0x82000400 | CMD_PRECHARGE); /* precharge 8 DDR clock cycle */ + mtsdram(SDRAM_INITPLR2, 0x80800000 | emr2); /* EMR2 */ + mtsdram(SDRAM_INITPLR3, 0x80800000 | emr3); /* EMR3 */ + mtsdram(SDRAM_INITPLR4, 0x80800000 | emr); /* EMR DLL ENABLE */ + mtsdram(SDRAM_INITPLR5, 0x80800000 | mr | DLL_RESET); /* MR w/ DLL reset */ + udelay(1000); + mtsdram(SDRAM_INITPLR6, 0x82000400 | CMD_PRECHARGE); /* precharge 8 DDR clock cycle */ + mtsdram(SDRAM_INITPLR7, 0x8a000000 | CMD_REFRESH); /* Refresh 50 DDR clock cycle */ + mtsdram(SDRAM_INITPLR8, 0x8a000000 | CMD_REFRESH); /* Refresh 50 DDR clock cycle */ + mtsdram(SDRAM_INITPLR9, 0x8a000000 | CMD_REFRESH); /* Refresh 50 DDR clock cycle */ + mtsdram(SDRAM_INITPLR10, 0x8a000000 | CMD_REFRESH); /* Refresh 50 DDR clock cycle */ + mtsdram(SDRAM_INITPLR11, 0x80000000 | mr); /* MR w/o DLL reset */ + mtsdram(SDRAM_INITPLR12, 0x80800380 | emr); /* EMR OCD Default */ + mtsdram(SDRAM_INITPLR13, 0x80800000 | emr); /* EMR OCD Exit */ + } else { + printf("ERROR: ucode error as unknown DDR type in program_initplr"); + hang(); + } +} + +/*------------------------------------------------------------------ + * This routine programs the SDRAM_MMODE register. + * the selected_cas is an output parameter, that will be passed + * by caller to call the above program_initplr( ) + *-----------------------------------------------------------------*/ +static void program_mode(unsigned long *dimm_populated, + unsigned char *iic0_dimm_addr, + unsigned long num_dimm_banks, + ddr_cas_id_t *selected_cas, + int *write_recovery) +{ + unsigned long dimm_num; + unsigned long sdram_ddr1; + unsigned long t_wr_ns; + unsigned long t_wr_clk; + unsigned long cas_bit; + unsigned long cas_index; + unsigned long sdram_freq; + unsigned long ddr_check; + unsigned long mmode; + unsigned long tcyc_reg; + unsigned long cycle_2_0_clk; + unsigned long cycle_2_5_clk; + unsigned long cycle_3_0_clk; + unsigned long cycle_4_0_clk; + unsigned long cycle_5_0_clk; + unsigned long max_2_0_tcyc_ns_x_100; + unsigned long max_2_5_tcyc_ns_x_100; + unsigned long max_3_0_tcyc_ns_x_100; + unsigned long max_4_0_tcyc_ns_x_100; + unsigned long max_5_0_tcyc_ns_x_100; + unsigned long cycle_time_ns_x_100[3]; + PPC440_SYS_INFO board_cfg; + unsigned char cas_2_0_available; + unsigned char cas_2_5_available; + unsigned char cas_3_0_available; + unsigned char cas_4_0_available; + unsigned char cas_5_0_available; + unsigned long sdr_ddrpll; + + /*------------------------------------------------------------------ + * Get the board configuration info. + *-----------------------------------------------------------------*/ + get_sys_info(&board_cfg); + + mfsdr(SDR0_DDR0, sdr_ddrpll); + sdram_freq = MULDIV64((board_cfg.freqPLB), SDR0_DDR0_DDRM_DECODE(sdr_ddrpll), 1); + + /*------------------------------------------------------------------ + * Handle the timing. We need to find the worst case timing of all + * the dimm modules installed. + *-----------------------------------------------------------------*/ + t_wr_ns = 0; + cas_2_0_available = TRUE; + cas_2_5_available = TRUE; + cas_3_0_available = TRUE; + cas_4_0_available = TRUE; + cas_5_0_available = TRUE; + max_2_0_tcyc_ns_x_100 = 10; + max_2_5_tcyc_ns_x_100 = 10; + max_3_0_tcyc_ns_x_100 = 10; + max_4_0_tcyc_ns_x_100 = 10; + max_5_0_tcyc_ns_x_100 = 10; + sdram_ddr1 = TRUE; + + /* loop through all the DIMM slots on the board */ + for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) { + /* If a dimm is installed in a particular slot ... */ + if (dimm_populated[dimm_num] != SDRAM_NONE) { + if (dimm_populated[dimm_num] == SDRAM_DDR1) + sdram_ddr1 = TRUE; + else + sdram_ddr1 = FALSE; + + /* t_wr_ns = max(t_wr_ns, (unsigned long)dimm_spd[dimm_num][36] >> 2); */ /* not used in this loop. */ + cas_bit = spd_read(iic0_dimm_addr[dimm_num], 18); + + /* For a particular DIMM, grab the three CAS values it supports */ + for (cas_index = 0; cas_index < 3; cas_index++) { + switch (cas_index) { + case 0: + tcyc_reg = spd_read(iic0_dimm_addr[dimm_num], 9); + break; + case 1: + tcyc_reg = spd_read(iic0_dimm_addr[dimm_num], 23); + break; + default: + tcyc_reg = spd_read(iic0_dimm_addr[dimm_num], 25); + break; + } + + if ((tcyc_reg & 0x0F) >= 10) { + if ((tcyc_reg & 0x0F) == 0x0D) { + /* Convert from hex to decimal */ + cycle_time_ns_x_100[cas_index] = (((tcyc_reg & 0xF0) >> 4) * 100) + 75; + } else { + printf("ERROR: SPD reported Tcyc is incorrect for DIMM " + "in slot %d\n", (unsigned int)dimm_num); + hang(); + } + } else { + /* Convert from hex to decimal */ + cycle_time_ns_x_100[cas_index] = (((tcyc_reg & 0xF0) >> 4) * 100) + + ((tcyc_reg & 0x0F)*10); + } + } + + /* The rest of this routine determines if CAS 2.0, 2.5, 3.0, 4.0 and 5.0 are */ + /* supported for a particular DIMM. */ + cas_index = 0; + + if (sdram_ddr1) { + /* + * DDR devices use the following bitmask for CAS latency: + * Bit 7 6 5 4 3 2 1 0 + * TBD 4.0 3.5 3.0 2.5 2.0 1.5 1.0 + */ + if (((cas_bit & 0x40) == 0x40) && (cas_index < 3) && (cycle_time_ns_x_100[cas_index] != 0)) { + max_4_0_tcyc_ns_x_100 = max(max_4_0_tcyc_ns_x_100, cycle_time_ns_x_100[cas_index]); + cas_index++; + } else { + if (cas_index != 0) + cas_index++; + cas_4_0_available = FALSE; + } + + if (((cas_bit & 0x10) == 0x10) && (cas_index < 3) && (cycle_time_ns_x_100[cas_index] != 0)) { + max_3_0_tcyc_ns_x_100 = max(max_3_0_tcyc_ns_x_100, cycle_time_ns_x_100[cas_index]); + cas_index++; + } else { + if (cas_index != 0) + cas_index++; + cas_3_0_available = FALSE; + } + + if (((cas_bit & 0x08) == 0x08) && (cas_index < 3) && (cycle_time_ns_x_100[cas_index] != 0)) { + max_2_5_tcyc_ns_x_100 = max(max_2_5_tcyc_ns_x_100, cycle_time_ns_x_100[cas_index]); + cas_index++; + } else { + if (cas_index != 0) + cas_index++; + cas_2_5_available = FALSE; + } + + if (((cas_bit & 0x04) == 0x04) && (cas_index < 3) && (cycle_time_ns_x_100[cas_index] != 0)) { + max_2_0_tcyc_ns_x_100 = max(max_2_0_tcyc_ns_x_100, cycle_time_ns_x_100[cas_index]); + cas_index++; + } else { + if (cas_index != 0) + cas_index++; + cas_2_0_available = FALSE; + } + } else { + /* + * DDR2 devices use the following bitmask for CAS latency: + * Bit 7 6 5 4 3 2 1 0 + * TBD 6.0 5.0 4.0 3.0 2.0 TBD TBD + */ + if (((cas_bit & 0x20) == 0x20) && (cas_index < 3) && (cycle_time_ns_x_100[cas_index] != 0)) { + max_5_0_tcyc_ns_x_100 = max(max_5_0_tcyc_ns_x_100, cycle_time_ns_x_100[cas_index]); + cas_index++; + } else { + if (cas_index != 0) + cas_index++; + cas_5_0_available = FALSE; + } + + if (((cas_bit & 0x10) == 0x10) && (cas_index < 3) && (cycle_time_ns_x_100[cas_index] != 0)) { + max_4_0_tcyc_ns_x_100 = max(max_4_0_tcyc_ns_x_100, cycle_time_ns_x_100[cas_index]); + cas_index++; + } else { + if (cas_index != 0) + cas_index++; + cas_4_0_available = FALSE; + } + + if (((cas_bit & 0x08) == 0x08) && (cas_index < 3) && (cycle_time_ns_x_100[cas_index] != 0)) { + max_3_0_tcyc_ns_x_100 = max(max_3_0_tcyc_ns_x_100, cycle_time_ns_x_100[cas_index]); + cas_index++; + } else { + if (cas_index != 0) + cas_index++; + cas_3_0_available = FALSE; + } + } + } + } + + /*------------------------------------------------------------------ + * Set the SDRAM mode, SDRAM_MMODE + *-----------------------------------------------------------------*/ + mfsdram(SDRAM_MMODE, mmode); + mmode = mmode & ~(SDRAM_MMODE_WR_MASK | SDRAM_MMODE_DCL_MASK); + + /* add 10 here because of rounding problems */ + cycle_2_0_clk = MULDIV64(ONE_BILLION, 100, max_2_0_tcyc_ns_x_100) + 10; + cycle_2_5_clk = MULDIV64(ONE_BILLION, 100, max_2_5_tcyc_ns_x_100) + 10; + cycle_3_0_clk = MULDIV64(ONE_BILLION, 100, max_3_0_tcyc_ns_x_100) + 10; + cycle_4_0_clk = MULDIV64(ONE_BILLION, 100, max_4_0_tcyc_ns_x_100) + 10; + cycle_5_0_clk = MULDIV64(ONE_BILLION, 100, max_5_0_tcyc_ns_x_100) + 10; + + if (sdram_ddr1 == TRUE) { /* DDR1 */ + if ((cas_2_0_available == TRUE) && (sdram_freq <= cycle_2_0_clk)) { + mmode |= SDRAM_MMODE_DCL_DDR1_2_0_CLK; + *selected_cas = DDR_CAS_2; + } else if ((cas_2_5_available == TRUE) && (sdram_freq <= cycle_2_5_clk)) { + mmode |= SDRAM_MMODE_DCL_DDR1_2_5_CLK; + *selected_cas = DDR_CAS_2_5; + } else if ((cas_3_0_available == TRUE) && (sdram_freq <= cycle_3_0_clk)) { + mmode |= SDRAM_MMODE_DCL_DDR1_3_0_CLK; + *selected_cas = DDR_CAS_3; + } else { + printf("ERROR: Cannot find a supported CAS latency with the installed DIMMs.\n"); + printf("Only DIMMs DDR1 with CAS latencies of 2.0, 2.5, and 3.0 are supported.\n"); + printf("Make sure the PLB speed is within the supported range of the DIMMs.\n\n"); + hang(); + } + } else { /* DDR2 */ + if ((cas_3_0_available == TRUE) && (sdram_freq <= cycle_3_0_clk)) { + mmode |= SDRAM_MMODE_DCL_DDR2_3_0_CLK; + *selected_cas = DDR_CAS_3; + } else if ((cas_4_0_available == TRUE) && (sdram_freq <= cycle_4_0_clk)) { + mmode |= SDRAM_MMODE_DCL_DDR2_4_0_CLK; + *selected_cas = DDR_CAS_4; + } else if ((cas_5_0_available == TRUE) && (sdram_freq <= cycle_5_0_clk)) { + mmode |= SDRAM_MMODE_DCL_DDR2_5_0_CLK; + *selected_cas = DDR_CAS_5; + } else { + printf("ERROR: Cannot find a supported CAS latency with the installed DIMMs.\n"); + printf("Only DIMMs DDR2 with CAS latencies of 3.0, 4.0, and 5.0 are supported.\n"); + printf("Make sure the PLB speed is within the supported range of the DIMMs.\n"); + printf("cas3=%d cas4=%d cas5=%d\n", + cas_3_0_available, cas_4_0_available, cas_5_0_available); + printf("sdram_freq=%d cycle3=%d cycle4=%d cycle5=%d\n\n", + sdram_freq, cycle_3_0_clk, cycle_4_0_clk, cycle_5_0_clk); + hang(); + } + } + + if (sdram_ddr1 == TRUE) + mmode |= SDRAM_MMODE_WR_DDR1; + else { + + /* loop through all the DIMM slots on the board */ + for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) { + /* If a dimm is installed in a particular slot ... */ + if (dimm_populated[dimm_num] != SDRAM_NONE) + t_wr_ns = max(t_wr_ns, + spd_read(iic0_dimm_addr[dimm_num], 36) >> 2); + } + + /* + * convert from nanoseconds to ddr clocks + * round up if necessary + */ + t_wr_clk = MULDIV64(sdram_freq, t_wr_ns, ONE_BILLION); + ddr_check = MULDIV64(ONE_BILLION, t_wr_clk, t_wr_ns); + if (sdram_freq != ddr_check) + t_wr_clk++; + + switch (t_wr_clk) { + case 0: + case 1: + case 2: + case 3: + mmode |= SDRAM_MMODE_WR_DDR2_3_CYC; + break; + case 4: + mmode |= SDRAM_MMODE_WR_DDR2_4_CYC; + break; + case 5: + mmode |= SDRAM_MMODE_WR_DDR2_5_CYC; + break; + default: + mmode |= SDRAM_MMODE_WR_DDR2_6_CYC; + break; + } + *write_recovery = t_wr_clk; + } + + debug("CAS latency = %d\n", *selected_cas); + debug("Write recovery = %d\n", *write_recovery); + + mtsdram(SDRAM_MMODE, mmode); +} + +/*-----------------------------------------------------------------------------+ + * program_rtr. + *-----------------------------------------------------------------------------*/ +static void program_rtr(unsigned long *dimm_populated, + unsigned char *iic0_dimm_addr, + unsigned long num_dimm_banks) +{ + PPC440_SYS_INFO board_cfg; + unsigned long max_refresh_rate; + unsigned long dimm_num; + unsigned long refresh_rate_type; + unsigned long refresh_rate; + unsigned long rint; + unsigned long sdram_freq; + unsigned long sdr_ddrpll; + unsigned long val; + + /*------------------------------------------------------------------ + * Get the board configuration info. + *-----------------------------------------------------------------*/ + get_sys_info(&board_cfg); + + /*------------------------------------------------------------------ + * Set the SDRAM Refresh Timing Register, SDRAM_RTR + *-----------------------------------------------------------------*/ + mfsdr(SDR0_DDR0, sdr_ddrpll); + sdram_freq = ((board_cfg.freqPLB) * SDR0_DDR0_DDRM_DECODE(sdr_ddrpll)); + + max_refresh_rate = 0; + for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) { + if (dimm_populated[dimm_num] != SDRAM_NONE) { + + refresh_rate_type = spd_read(iic0_dimm_addr[dimm_num], 12); + refresh_rate_type &= 0x7F; + switch (refresh_rate_type) { + case 0: + refresh_rate = 15625; + break; + case 1: + refresh_rate = 3906; + break; + case 2: + refresh_rate = 7812; + break; + case 3: + refresh_rate = 31250; + break; + case 4: + refresh_rate = 62500; + break; + case 5: + refresh_rate = 125000; + break; + default: + refresh_rate = 0; + printf("ERROR: DIMM %d unsupported refresh rate/type.\n", + (unsigned int)dimm_num); + printf("Replace the DIMM module with a supported DIMM.\n\n"); + hang(); + break; + } + + max_refresh_rate = max(max_refresh_rate, refresh_rate); + } + } + + rint = MULDIV64(sdram_freq, max_refresh_rate, ONE_BILLION); + mfsdram(SDRAM_RTR, val); + mtsdram(SDRAM_RTR, (val & ~SDRAM_RTR_RINT_MASK) | + (SDRAM_RTR_RINT_ENCODE(rint))); +} + +/*------------------------------------------------------------------ + * This routine programs the SDRAM_TRx registers. + *-----------------------------------------------------------------*/ +static void program_tr(unsigned long *dimm_populated, + unsigned char *iic0_dimm_addr, + unsigned long num_dimm_banks) +{ + unsigned long dimm_num; + unsigned long sdram_ddr1; + unsigned long t_rp_ns; + unsigned long t_rcd_ns; + unsigned long t_rrd_ns; + unsigned long t_ras_ns; + unsigned long t_rc_ns; + unsigned long t_rfc_ns; + unsigned long t_wpc_ns; + unsigned long t_wtr_ns; + unsigned long t_rpc_ns; + unsigned long t_rp_clk; + unsigned long t_rcd_clk; + unsigned long t_rrd_clk; + unsigned long t_ras_clk; + unsigned long t_rc_clk; + unsigned long t_rfc_clk; + unsigned long t_wpc_clk; + unsigned long t_wtr_clk; + unsigned long t_rpc_clk; + unsigned long sdtr1, sdtr2, sdtr3; + unsigned long ddr_check; + unsigned long sdram_freq; + unsigned long sdr_ddrpll; + + PPC440_SYS_INFO board_cfg; + + /*------------------------------------------------------------------ + * Get the board configuration info. + *-----------------------------------------------------------------*/ + get_sys_info(&board_cfg); + + mfsdr(SDR0_DDR0, sdr_ddrpll); + sdram_freq = ((board_cfg.freqPLB) * SDR0_DDR0_DDRM_DECODE(sdr_ddrpll)); + + /*------------------------------------------------------------------ + * Handle the timing. We need to find the worst case timing of all + * the dimm modules installed. + *-----------------------------------------------------------------*/ + t_rp_ns = 0; + t_rrd_ns = 0; + t_rcd_ns = 0; + t_ras_ns = 0; + t_rc_ns = 0; + t_rfc_ns = 0; + t_wpc_ns = 0; + t_wtr_ns = 0; + t_rpc_ns = 0; + sdram_ddr1 = TRUE; + + /* loop through all the DIMM slots on the board */ + for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) { + /* If a dimm is installed in a particular slot ... */ + if (dimm_populated[dimm_num] != SDRAM_NONE) { + if (dimm_populated[dimm_num] == SDRAM_DDR2) + sdram_ddr1 = TRUE; + else + sdram_ddr1 = FALSE; + + t_rcd_ns = max(t_rcd_ns, spd_read(iic0_dimm_addr[dimm_num], 29) >> 2); + t_rrd_ns = max(t_rrd_ns, spd_read(iic0_dimm_addr[dimm_num], 28) >> 2); + t_rp_ns = max(t_rp_ns, spd_read(iic0_dimm_addr[dimm_num], 27) >> 2); + t_ras_ns = max(t_ras_ns, spd_read(iic0_dimm_addr[dimm_num], 30)); + t_rc_ns = max(t_rc_ns, spd_read(iic0_dimm_addr[dimm_num], 41)); + t_rfc_ns = max(t_rfc_ns, spd_read(iic0_dimm_addr[dimm_num], 42)); + } + } + + /*------------------------------------------------------------------ + * Set the SDRAM Timing Reg 1, SDRAM_TR1 + *-----------------------------------------------------------------*/ + mfsdram(SDRAM_SDTR1, sdtr1); + sdtr1 &= ~(SDRAM_SDTR1_LDOF_MASK | SDRAM_SDTR1_RTW_MASK | + SDRAM_SDTR1_WTWO_MASK | SDRAM_SDTR1_RTRO_MASK); + + /* default values */ + sdtr1 |= SDRAM_SDTR1_LDOF_2_CLK; + sdtr1 |= SDRAM_SDTR1_RTW_2_CLK; + + /* normal operations */ + sdtr1 |= SDRAM_SDTR1_WTWO_0_CLK; + sdtr1 |= SDRAM_SDTR1_RTRO_1_CLK; + + mtsdram(SDRAM_SDTR1, sdtr1); + + /*------------------------------------------------------------------ + * Set the SDRAM Timing Reg 2, SDRAM_TR2 + *-----------------------------------------------------------------*/ + mfsdram(SDRAM_SDTR2, sdtr2); + sdtr2 &= ~(SDRAM_SDTR2_RCD_MASK | SDRAM_SDTR2_WTR_MASK | + SDRAM_SDTR2_XSNR_MASK | SDRAM_SDTR2_WPC_MASK | + SDRAM_SDTR2_RPC_MASK | SDRAM_SDTR2_RP_MASK | + SDRAM_SDTR2_RRD_MASK); + + /* + * convert t_rcd from nanoseconds to ddr clocks + * round up if necessary + */ + t_rcd_clk = MULDIV64(sdram_freq, t_rcd_ns, ONE_BILLION); + ddr_check = MULDIV64(ONE_BILLION, t_rcd_clk, t_rcd_ns); + if (sdram_freq != ddr_check) + t_rcd_clk++; + + switch (t_rcd_clk) { + case 0: + case 1: + sdtr2 |= SDRAM_SDTR2_RCD_1_CLK; + break; + case 2: + sdtr2 |= SDRAM_SDTR2_RCD_2_CLK; + break; + case 3: + sdtr2 |= SDRAM_SDTR2_RCD_3_CLK; + break; + case 4: + sdtr2 |= SDRAM_SDTR2_RCD_4_CLK; + break; + default: + sdtr2 |= SDRAM_SDTR2_RCD_5_CLK; + break; + } + + if (sdram_ddr1 == TRUE) { /* DDR1 */ + if (sdram_freq < 200000000) { + sdtr2 |= SDRAM_SDTR2_WTR_1_CLK; + sdtr2 |= SDRAM_SDTR2_WPC_2_CLK; + sdtr2 |= SDRAM_SDTR2_RPC_2_CLK; + } else { + sdtr2 |= SDRAM_SDTR2_WTR_2_CLK; + sdtr2 |= SDRAM_SDTR2_WPC_3_CLK; + sdtr2 |= SDRAM_SDTR2_RPC_2_CLK; + } + } else { /* DDR2 */ + /* loop through all the DIMM slots on the board */ + for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) { + /* If a dimm is installed in a particular slot ... */ + if (dimm_populated[dimm_num] != SDRAM_NONE) { + t_wpc_ns = max(t_wtr_ns, spd_read(iic0_dimm_addr[dimm_num], 36) >> 2); + t_wtr_ns = max(t_wtr_ns, spd_read(iic0_dimm_addr[dimm_num], 37) >> 2); + t_rpc_ns = max(t_rpc_ns, spd_read(iic0_dimm_addr[dimm_num], 38) >> 2); + } + } + + /* + * convert from nanoseconds to ddr clocks + * round up if necessary + */ + t_wpc_clk = MULDIV64(sdram_freq, t_wpc_ns, ONE_BILLION); + ddr_check = MULDIV64(ONE_BILLION, t_wpc_clk, t_wpc_ns); + if (sdram_freq != ddr_check) + t_wpc_clk++; + + switch (t_wpc_clk) { + case 0: + case 1: + case 2: + sdtr2 |= SDRAM_SDTR2_WPC_2_CLK; + break; + case 3: + sdtr2 |= SDRAM_SDTR2_WPC_3_CLK; + break; + case 4: + sdtr2 |= SDRAM_SDTR2_WPC_4_CLK; + break; + case 5: + sdtr2 |= SDRAM_SDTR2_WPC_5_CLK; + break; + default: + sdtr2 |= SDRAM_SDTR2_WPC_6_CLK; + break; + } + + /* + * convert from nanoseconds to ddr clocks + * round up if necessary + */ + t_wtr_clk = MULDIV64(sdram_freq, t_wtr_ns, ONE_BILLION); + ddr_check = MULDIV64(ONE_BILLION, t_wtr_clk, t_wtr_ns); + if (sdram_freq != ddr_check) + t_wtr_clk++; + + switch (t_wtr_clk) { + case 0: + case 1: + sdtr2 |= SDRAM_SDTR2_WTR_1_CLK; + break; + case 2: + sdtr2 |= SDRAM_SDTR2_WTR_2_CLK; + break; + case 3: + sdtr2 |= SDRAM_SDTR2_WTR_3_CLK; + break; + default: + sdtr2 |= SDRAM_SDTR2_WTR_4_CLK; + break; + } + + /* + * convert from nanoseconds to ddr clocks + * round up if necessary + */ + t_rpc_clk = MULDIV64(sdram_freq, t_rpc_ns, ONE_BILLION); + ddr_check = MULDIV64(ONE_BILLION, t_rpc_clk, t_rpc_ns); + if (sdram_freq != ddr_check) + t_rpc_clk++; + + switch (t_rpc_clk) { + case 0: + case 1: + case 2: + sdtr2 |= SDRAM_SDTR2_RPC_2_CLK; + break; + case 3: + sdtr2 |= SDRAM_SDTR2_RPC_3_CLK; + break; + default: + sdtr2 |= SDRAM_SDTR2_RPC_4_CLK; + break; + } + } + + /* default value */ + sdtr2 |= SDRAM_SDTR2_XSNR_16_CLK; + + /* + * convert t_rrd from nanoseconds to ddr clocks + * round up if necessary + */ + t_rrd_clk = MULDIV64(sdram_freq, t_rrd_ns, ONE_BILLION); + ddr_check = MULDIV64(ONE_BILLION, t_rrd_clk, t_rrd_ns); + if (sdram_freq != ddr_check) + t_rrd_clk++; + + if (t_rrd_clk == 3) + sdtr2 |= SDRAM_SDTR2_RRD_3_CLK; + else + sdtr2 |= SDRAM_SDTR2_RRD_2_CLK; + + /* + * convert t_rp from nanoseconds to ddr clocks + * round up if necessary + */ + t_rp_clk = MULDIV64(sdram_freq, t_rp_ns, ONE_BILLION); + ddr_check = MULDIV64(ONE_BILLION, t_rp_clk, t_rp_ns); + if (sdram_freq != ddr_check) + t_rp_clk++; + + switch (t_rp_clk) { + case 0: + case 1: + case 2: + case 3: + sdtr2 |= SDRAM_SDTR2_RP_3_CLK; + break; + case 4: + sdtr2 |= SDRAM_SDTR2_RP_4_CLK; + break; + case 5: + sdtr2 |= SDRAM_SDTR2_RP_5_CLK; + break; + case 6: + sdtr2 |= SDRAM_SDTR2_RP_6_CLK; + break; + default: + sdtr2 |= SDRAM_SDTR2_RP_7_CLK; + break; + } + + mtsdram(SDRAM_SDTR2, sdtr2); + + /*------------------------------------------------------------------ + * Set the SDRAM Timing Reg 3, SDRAM_TR3 + *-----------------------------------------------------------------*/ + mfsdram(SDRAM_SDTR3, sdtr3); + sdtr3 &= ~(SDRAM_SDTR3_RAS_MASK | SDRAM_SDTR3_RC_MASK | + SDRAM_SDTR3_XCS_MASK | SDRAM_SDTR3_RFC_MASK); + + /* + * convert t_ras from nanoseconds to ddr clocks + * round up if necessary + */ + t_ras_clk = MULDIV64(sdram_freq, t_ras_ns, ONE_BILLION); + ddr_check = MULDIV64(ONE_BILLION, t_ras_clk, t_ras_ns); + if (sdram_freq != ddr_check) + t_ras_clk++; + + sdtr3 |= SDRAM_SDTR3_RAS_ENCODE(t_ras_clk); + + /* + * convert t_rc from nanoseconds to ddr clocks + * round up if necessary + */ + t_rc_clk = MULDIV64(sdram_freq, t_rc_ns, ONE_BILLION); + ddr_check = MULDIV64(ONE_BILLION, t_rc_clk, t_rc_ns); + if (sdram_freq != ddr_check) + t_rc_clk++; + + sdtr3 |= SDRAM_SDTR3_RC_ENCODE(t_rc_clk); + + /* default xcs value */ + sdtr3 |= SDRAM_SDTR3_XCS; + + /* + * convert t_rfc from nanoseconds to ddr clocks + * round up if necessary + */ + t_rfc_clk = MULDIV64(sdram_freq, t_rfc_ns, ONE_BILLION); + ddr_check = MULDIV64(ONE_BILLION, t_rfc_clk, t_rfc_ns); + if (sdram_freq != ddr_check) + t_rfc_clk++; + + sdtr3 |= SDRAM_SDTR3_RFC_ENCODE(t_rfc_clk); + + mtsdram(SDRAM_SDTR3, sdtr3); +} + +/*-----------------------------------------------------------------------------+ + * program_bxcf. + *-----------------------------------------------------------------------------*/ +static void program_bxcf(unsigned long *dimm_populated, + unsigned char *iic0_dimm_addr, + unsigned long num_dimm_banks) +{ + unsigned long dimm_num; + unsigned long num_col_addr; + unsigned long num_ranks; + unsigned long num_banks; + unsigned long mode; + unsigned long ind_rank; + unsigned long ind; + unsigned long ind_bank; + unsigned long bank_0_populated; + + /*------------------------------------------------------------------ + * Set the BxCF regs. First, wipe out the bank config registers. + *-----------------------------------------------------------------*/ + mtdcr(SDRAMC_CFGADDR, SDRAM_MB0CF); + mtdcr(SDRAMC_CFGDATA, 0x00000000); + mtdcr(SDRAMC_CFGADDR, SDRAM_MB1CF); + mtdcr(SDRAMC_CFGDATA, 0x00000000); + mtdcr(SDRAMC_CFGADDR, SDRAM_MB2CF); + mtdcr(SDRAMC_CFGDATA, 0x00000000); + mtdcr(SDRAMC_CFGADDR, SDRAM_MB3CF); + mtdcr(SDRAMC_CFGDATA, 0x00000000); + + mode = SDRAM_BXCF_M_BE_ENABLE; + + bank_0_populated = 0; + + for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) { + if (dimm_populated[dimm_num] != SDRAM_NONE) { + num_col_addr = spd_read(iic0_dimm_addr[dimm_num], 4); + num_ranks = spd_read(iic0_dimm_addr[dimm_num], 5); + if ((spd_read(iic0_dimm_addr[dimm_num], 2)) == 0x08) + num_ranks = (num_ranks & 0x0F) +1; + else + num_ranks = num_ranks & 0x0F; + + num_banks = spd_read(iic0_dimm_addr[dimm_num], 17); + + for (ind_bank = 0; ind_bank < 2; ind_bank++) { + if (num_banks == 4) + ind = 0; + else + ind = 5; + switch (num_col_addr) { + case 0x08: + mode |= (SDRAM_BXCF_M_AM_0 + ind); + break; + case 0x09: + mode |= (SDRAM_BXCF_M_AM_1 + ind); + break; + case 0x0A: + mode |= (SDRAM_BXCF_M_AM_2 + ind); + break; + case 0x0B: + mode |= (SDRAM_BXCF_M_AM_3 + ind); + break; + case 0x0C: + mode |= (SDRAM_BXCF_M_AM_4 + ind); + break; + default: + printf("DDR-SDRAM: DIMM %d BxCF configuration.\n", + (unsigned int)dimm_num); + printf("ERROR: Unsupported value for number of " + "column addresses: %d.\n", (unsigned int)num_col_addr); + printf("Replace the DIMM module with a supported DIMM.\n\n"); + hang(); + } + } + + if ((dimm_populated[dimm_num] != SDRAM_NONE)&& (dimm_num ==1)) + bank_0_populated = 1; + + for (ind_rank = 0; ind_rank < num_ranks; ind_rank++) { + mtdcr(SDRAMC_CFGADDR, SDRAM_MB0CF + ((dimm_num + bank_0_populated + ind_rank) << 2)); + mtdcr(SDRAMC_CFGDATA, mode); + } + } + } +} + +/*------------------------------------------------------------------ + * program memory queue. + *-----------------------------------------------------------------*/ +static void program_memory_queue(unsigned long *dimm_populated, + unsigned char *iic0_dimm_addr, + unsigned long num_dimm_banks) +{ + unsigned long dimm_num; + unsigned long rank_base_addr; + unsigned long rank_reg; + unsigned long rank_size_bytes; + unsigned long rank_size_id; + unsigned long num_ranks; + unsigned long baseadd_size; + unsigned long i; + unsigned long bank_0_populated = 0; + + /*------------------------------------------------------------------ + * Reset the rank_base_address. + *-----------------------------------------------------------------*/ + rank_reg = SDRAM_R0BAS; + + rank_base_addr = 0x00000000; + + for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) { + if (dimm_populated[dimm_num] != SDRAM_NONE) { + num_ranks = spd_read(iic0_dimm_addr[dimm_num], 5); + if ((spd_read(iic0_dimm_addr[dimm_num], 2)) == 0x08) + num_ranks = (num_ranks & 0x0F) + 1; + else + num_ranks = num_ranks & 0x0F; + + rank_size_id = spd_read(iic0_dimm_addr[dimm_num], 31); + + /*------------------------------------------------------------------ + * Set the sizes + *-----------------------------------------------------------------*/ + baseadd_size = 0; + rank_size_bytes = 4 * 1024 * 1024 * rank_size_id; + switch (rank_size_id) { + case 0x02: + baseadd_size |= SDRAM_RXBAS_SDSZ_8; + break; + case 0x04: + baseadd_size |= SDRAM_RXBAS_SDSZ_16; + break; + case 0x08: + baseadd_size |= SDRAM_RXBAS_SDSZ_32; + break; + case 0x10: + baseadd_size |= SDRAM_RXBAS_SDSZ_64; + break; + case 0x20: + baseadd_size |= SDRAM_RXBAS_SDSZ_128; + break; + case 0x40: + baseadd_size |= SDRAM_RXBAS_SDSZ_256; + break; + case 0x80: + baseadd_size |= SDRAM_RXBAS_SDSZ_512; + break; + default: + printf("DDR-SDRAM: DIMM %d memory queue configuration.\n", + (unsigned int)dimm_num); + printf("ERROR: Unsupported value for the banksize: %d.\n", + (unsigned int)rank_size_id); + printf("Replace the DIMM module with a supported DIMM.\n\n"); + hang(); + } + + if ((dimm_populated[dimm_num] != SDRAM_NONE) && (dimm_num == 1)) + bank_0_populated = 1; + + for (i = 0; i < num_ranks; i++) { + mtdcr_any(rank_reg+i+dimm_num+bank_0_populated, + (SDRAM_RXBAS_SDBA_ENCODE(rank_base_addr) | + baseadd_size)); + rank_base_addr += rank_size_bytes; + } + } + } +} + +/*-----------------------------------------------------------------------------+ + * is_ecc_enabled. + *-----------------------------------------------------------------------------*/ +static unsigned long is_ecc_enabled(void) +{ + unsigned long dimm_num; + unsigned long ecc; + unsigned long val; + + ecc = 0; + /* loop through all the DIMM slots on the board */ + for (dimm_num = 0; dimm_num < MAXDIMMS; dimm_num++) { + mfsdram(SDRAM_MCOPT1, val); + ecc = max(ecc, SDRAM_MCOPT1_MCHK_CHK_DECODE(val)); + } + + return ecc; +} + +#ifdef CONFIG_DDR_ECC +/*-----------------------------------------------------------------------------+ + * program_ecc. + *-----------------------------------------------------------------------------*/ +static void program_ecc(unsigned long *dimm_populated, + unsigned char *iic0_dimm_addr, + unsigned long num_dimm_banks, + unsigned long tlb_word2_i_value) +{ + unsigned long mcopt1; + unsigned long mcopt2; + unsigned long mcstat; + unsigned long dimm_num; + unsigned long ecc; + + ecc = 0; + /* loop through all the DIMM slots on the board */ + for (dimm_num = 0; dimm_num < MAXDIMMS; dimm_num++) { + /* If a dimm is installed in a particular slot ... */ + if (dimm_populated[dimm_num] != SDRAM_NONE) + ecc = max(ecc, spd_read(iic0_dimm_addr[dimm_num], 11)); + } + if (ecc == 0) + return; + + mfsdram(SDRAM_MCOPT1, mcopt1); + mfsdram(SDRAM_MCOPT2, mcopt2); + + if ((mcopt1 & SDRAM_MCOPT1_MCHK_MASK) != SDRAM_MCOPT1_MCHK_NON) { + /* DDR controller must be enabled and not in self-refresh. */ + mfsdram(SDRAM_MCSTAT, mcstat); + if (((mcopt2 & SDRAM_MCOPT2_DCEN_MASK) == SDRAM_MCOPT2_DCEN_ENABLE) + && ((mcopt2 & SDRAM_MCOPT2_SREN_MASK) == SDRAM_MCOPT2_SREN_EXIT) + && ((mcstat & (SDRAM_MCSTAT_MIC_MASK | SDRAM_MCSTAT_SRMS_MASK)) + == (SDRAM_MCSTAT_MIC_COMP | SDRAM_MCSTAT_SRMS_NOT_SF))) { + + program_ecc_addr(0, sdram_memsize(), tlb_word2_i_value); + } + } + + return; +} + +#ifdef CONFIG_ECC_ERROR_RESET +/* + * Check for ECC errors and reset board upon any error here + * + * On the Katmai 440SPe eval board, from time to time, the first + * lword write access after DDR2 initializazion with ECC checking + * enabled, leads to an ECC error. I couldn't find a configuration + * without this happening. On my board with the current setup it + * happens about 1 from 10 times. + * + * The ECC modules used for testing are: + * - Kingston ValueRAM KVR667D2E5/512 (tested with 1 and 2 DIMM's) + * + * This has to get fixed for the Katmai and tested for the other + * board (440SP/440SPe) that will eventually use this code in the + * future. + * + * 2007-03-01, sr + */ +static void check_ecc(void) +{ + u32 val; + + mfsdram(SDRAM_ECCCR, val); + if (val != 0) { + printf("\nECC error: MCIF0_ECCES=%08lx MQ0_ESL=%08lx address=%08lx\n", + val, mfdcr(0x4c), mfdcr(0x4e)); + printf("ECC error occured, resetting board...\n"); + do_reset(NULL, 0, 0, NULL); + } +} +#endif + +static void wait_ddr_idle(void) +{ + u32 val; + + do { + mfsdram(SDRAM_MCSTAT, val); + } while ((val & SDRAM_MCSTAT_IDLE_MASK) == SDRAM_MCSTAT_IDLE_NOT); +} + +/*-----------------------------------------------------------------------------+ + * program_ecc_addr. + *-----------------------------------------------------------------------------*/ +static void program_ecc_addr(unsigned long start_address, + unsigned long num_bytes, + unsigned long tlb_word2_i_value) +{ + unsigned long current_address; + unsigned long end_address; + unsigned long address_increment; + unsigned long mcopt1; + char str[] = "ECC generation..."; + int i; + + current_address = start_address; + mfsdram(SDRAM_MCOPT1, mcopt1); + if ((mcopt1 & SDRAM_MCOPT1_MCHK_MASK) != SDRAM_MCOPT1_MCHK_NON) { + mtsdram(SDRAM_MCOPT1, + (mcopt1 & ~SDRAM_MCOPT1_MCHK_MASK) | SDRAM_MCOPT1_MCHK_GEN); + sync(); + eieio(); + wait_ddr_idle(); + + puts(str); + if (tlb_word2_i_value == TLB_WORD2_I_ENABLE) { + /* ECC bit set method for non-cached memory */ + if ((mcopt1 & SDRAM_MCOPT1_DMWD_MASK) == SDRAM_MCOPT1_DMWD_32) + address_increment = 4; + else + address_increment = 8; + end_address = current_address + num_bytes; + + while (current_address < end_address) { + *((unsigned long *)current_address) = 0x00000000; + current_address += address_increment; + } + } else { + /* ECC bit set method for cached memory */ + dcbz_area(start_address, num_bytes); + dflush(); + } + for (i=0; i<strlen(str); i++) + putc('\b'); + + sync(); + eieio(); + wait_ddr_idle(); + + /* clear ECC error repoting registers */ + mtsdram(SDRAM_ECCCR, 0xffffffff); + mtdcr(0x4c, 0xffffffff); + + mtsdram(SDRAM_MCOPT1, + (mcopt1 & ~SDRAM_MCOPT1_MCHK_MASK) | SDRAM_MCOPT1_MCHK_CHK_REP); + sync(); + eieio(); + wait_ddr_idle(); + +#ifdef CONFIG_ECC_ERROR_RESET + /* + * One write to 0 is enough to trigger this ECC error + * (see description above) + */ + out_be32(0, 0x12345678); + check_ecc(); +#endif + } +} +#endif + +/*-----------------------------------------------------------------------------+ + * program_DQS_calibration. + *-----------------------------------------------------------------------------*/ +static void program_DQS_calibration(unsigned long *dimm_populated, + unsigned char *iic0_dimm_addr, + unsigned long num_dimm_banks) +{ + unsigned long val; + +#ifdef HARD_CODED_DQS /* calibration test with hardvalues */ + mtsdram(SDRAM_RQDC, 0x80000037); + mtsdram(SDRAM_RDCC, 0x40000000); + mtsdram(SDRAM_RFDC, 0x000001DF); + + test(); +#else + /*------------------------------------------------------------------ + * Program RDCC register + * Read sample cycle auto-update enable + *-----------------------------------------------------------------*/ + + /* + * Modified for the Katmai platform: with some DIMMs, the DDR2 + * controller automatically selects the T2 read cycle, but this + * proves unreliable. Go ahead and force the DDR2 controller + * to use the T4 sample and disable the automatic update of the + * RDSS field. + */ + mfsdram(SDRAM_RDCC, val); + mtsdram(SDRAM_RDCC, + (val & ~(SDRAM_RDCC_RDSS_MASK | SDRAM_RDCC_RSAE_MASK)) + | (SDRAM_RDCC_RDSS_T4 | SDRAM_RDCC_RSAE_DISABLE)); + + /*------------------------------------------------------------------ + * Program RQDC register + * Internal DQS delay mechanism enable + *-----------------------------------------------------------------*/ + mtsdram(SDRAM_RQDC, (SDRAM_RQDC_RQDE_ENABLE|SDRAM_RQDC_RQFD_ENCODE(0x38))); + + /*------------------------------------------------------------------ + * Program RFDC register + * Set Feedback Fractional Oversample + * Auto-detect read sample cycle enable + *-----------------------------------------------------------------*/ + mfsdram(SDRAM_RFDC, val); + mtsdram(SDRAM_RFDC, + (val & ~(SDRAM_RFDC_ARSE_MASK | SDRAM_RFDC_RFOS_MASK | + SDRAM_RFDC_RFFD_MASK)) + | (SDRAM_RFDC_ARSE_ENABLE | SDRAM_RFDC_RFOS_ENCODE(0) | + SDRAM_RFDC_RFFD_ENCODE(0))); + + DQS_calibration_process(); +#endif +} + +static u32 short_mem_test(void) +{ + u32 *membase; + u32 bxcr_num; + u32 bxcf; + int i; + int j; + u32 test[NUMMEMTESTS][NUMMEMWORDS] = { + {0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF}, + {0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000}, + {0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555, + 0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555}, + {0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA, + 0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA}, + {0xA5A5A5A5, 0xA5A5A5A5, 0x5A5A5A5A, 0x5A5A5A5A, + 0xA5A5A5A5, 0xA5A5A5A5, 0x5A5A5A5A, 0x5A5A5A5A}, + {0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5, + 0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5}, + {0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA, + 0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA}, + {0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55, + 0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55} }; + + for (bxcr_num = 0; bxcr_num < MAXBXCF; bxcr_num++) { + mfsdram(SDRAM_MB0CF + (bxcr_num << 2), bxcf); + + /* Banks enabled */ + if ((bxcf & SDRAM_BXCF_M_BE_MASK) == SDRAM_BXCF_M_BE_ENABLE) { + + /* Bank is enabled */ + membase = (u32 *)(SDRAM_RXBAS_SDBA_DECODE(mfdcr_any(SDRAM_R0BAS+bxcr_num))); + + /*------------------------------------------------------------------ + * Run the short memory test. + *-----------------------------------------------------------------*/ + for (i = 0; i < NUMMEMTESTS; i++) { + for (j = 0; j < NUMMEMWORDS; j++) { + membase[j] = test[i][j]; + ppcDcbf((u32)&(membase[j])); + } + sync(); + for (j = 0; j < NUMMEMWORDS; j++) { + if (membase[j] != test[i][j]) { + ppcDcbf((u32)&(membase[j])); + break; + } + ppcDcbf((u32)&(membase[j])); + } + sync(); + if (j < NUMMEMWORDS) + break; + } + if (i < NUMMEMTESTS) + break; + } /* if bank enabled */ + } /* for bxcf_num */ + + return bxcr_num; +} + +#ifndef HARD_CODED_DQS +/*-----------------------------------------------------------------------------+ + * DQS_calibration_process. + *-----------------------------------------------------------------------------*/ +static void DQS_calibration_process(void) +{ + unsigned long ecc_temp; + unsigned long rfdc_reg; + unsigned long rffd; + unsigned long rqdc_reg; + unsigned long rqfd; + unsigned long bxcr_num; + unsigned long val; + long rqfd_average; + long rffd_average; + long max_start; + long min_end; + unsigned long begin_rqfd[MAXRANKS]; + unsigned long begin_rffd[MAXRANKS]; + unsigned long end_rqfd[MAXRANKS]; + unsigned long end_rffd[MAXRANKS]; + char window_found; + unsigned long dlycal; + unsigned long dly_val; + unsigned long max_pass_length; + unsigned long current_pass_length; + unsigned long current_fail_length; + unsigned long current_start; + long max_end; + unsigned char fail_found; + unsigned char pass_found; + + /*------------------------------------------------------------------ + * Test to determine the best read clock delay tuning bits. + * + * Before the DDR controller can be used, the read clock delay needs to be + * set. This is SDRAM_RQDC[RQFD] and SDRAM_RFDC[RFFD]. + * This value cannot be hardcoded into the program because it changes + * depending on the board's setup and environment. + * To do this, all delay values are tested to see if they + * work or not. By doing this, you get groups of fails with groups of + * passing values. The idea is to find the start and end of a passing + * window and take the center of it to use as the read clock delay. + * + * A failure has to be seen first so that when we hit a pass, we know + * that it is truely the start of the window. If we get passing values + * to start off with, we don't know if we are at the start of the window. + * + * The code assumes that a failure will always be found. + * If a failure is not found, there is no easy way to get the middle + * of the passing window. I guess we can pretty much pick any value + * but some values will be better than others. Since the lowest speed + * we can clock the DDR interface at is 200 MHz (2x 100 MHz PLB speed), + * from experimentation it is safe to say you will always have a failure. + *-----------------------------------------------------------------*/ + mfsdram(SDRAM_MCOPT1, ecc_temp); + ecc_temp &= SDRAM_MCOPT1_MCHK_MASK; + mfsdram(SDRAM_MCOPT1, val); + mtsdram(SDRAM_MCOPT1, (val & ~SDRAM_MCOPT1_MCHK_MASK) | + SDRAM_MCOPT1_MCHK_NON); + + max_start = 0; + min_end = 0; + begin_rqfd[0] = 0; + begin_rffd[0] = 0; + begin_rqfd[1] = 0; + begin_rffd[1] = 0; + end_rqfd[0] = 0; + end_rffd[0] = 0; + end_rqfd[1] = 0; + end_rffd[1] = 0; + window_found = FALSE; + + max_pass_length = 0; + max_start = 0; + max_end = 0; + current_pass_length = 0; + current_fail_length = 0; + current_start = 0; + window_found = FALSE; + fail_found = FALSE; + pass_found = FALSE; + + /* first fix RQDC[RQFD] to an average of 80 degre phase shift to find RFDC[RFFD] */ + /* rqdc_reg = mfsdram(SDRAM_RQDC) & ~(SDRAM_RQDC_RQFD_MASK); */ + + /* + * get the delay line calibration register value + */ + mfsdram(SDRAM_DLCR, dlycal); + dly_val = SDRAM_DLYCAL_DLCV_DECODE(dlycal) << 2; + + for (rffd = 0; rffd <= SDRAM_RFDC_RFFD_MAX; rffd++) { + mfsdram(SDRAM_RFDC, rfdc_reg); + rfdc_reg &= ~(SDRAM_RFDC_RFFD_MASK); + + /*------------------------------------------------------------------ + * Set the timing reg for the test. + *-----------------------------------------------------------------*/ + mtsdram(SDRAM_RFDC, rfdc_reg | SDRAM_RFDC_RFFD_ENCODE(rffd)); + + /* do the small memory test */ + bxcr_num = short_mem_test(); + + /*------------------------------------------------------------------ + * See if the rffd value passed. + *-----------------------------------------------------------------*/ + if (bxcr_num == MAXBXCF) { + if (fail_found == TRUE) { + pass_found = TRUE; + if (current_pass_length == 0) + current_start = rffd; + + current_fail_length = 0; + current_pass_length++; + + if (current_pass_length > max_pass_length) { + max_pass_length = current_pass_length; + max_start = current_start; + max_end = rffd; + } + } + } else { + current_pass_length = 0; + current_fail_length++; + + if (current_fail_length >= (dly_val >> 2)) { + if (fail_found == FALSE) { + fail_found = TRUE; + } else if (pass_found == TRUE) { + window_found = TRUE; + break; + } + } + } + } /* for rffd */ + + /*------------------------------------------------------------------ + * Set the average RFFD value + *-----------------------------------------------------------------*/ + rffd_average = ((max_start + max_end) >> 1); + + if (rffd_average < 0) + rffd_average = 0; + + if (rffd_average > SDRAM_RFDC_RFFD_MAX) + rffd_average = SDRAM_RFDC_RFFD_MAX; + /* now fix RFDC[RFFD] found and find RQDC[RQFD] */ + mtsdram(SDRAM_RFDC, rfdc_reg | SDRAM_RFDC_RFFD_ENCODE(rffd_average)); + + max_pass_length = 0; + max_start = 0; + max_end = 0; + current_pass_length = 0; + current_fail_length = 0; + current_start = 0; + window_found = FALSE; + fail_found = FALSE; + pass_found = FALSE; + + for (rqfd = 0; rqfd <= SDRAM_RQDC_RQFD_MAX; rqfd++) { + mfsdram(SDRAM_RQDC, rqdc_reg); + rqdc_reg &= ~(SDRAM_RQDC_RQFD_MASK); + + /*------------------------------------------------------------------ + * Set the timing reg for the test. + *-----------------------------------------------------------------*/ + mtsdram(SDRAM_RQDC, rqdc_reg | SDRAM_RQDC_RQFD_ENCODE(rqfd)); + + /* do the small memory test */ + bxcr_num = short_mem_test(); + + /*------------------------------------------------------------------ + * See if the rffd value passed. + *-----------------------------------------------------------------*/ + if (bxcr_num == MAXBXCF) { + if (fail_found == TRUE) { + pass_found = TRUE; + if (current_pass_length == 0) + current_start = rqfd; + + current_fail_length = 0; + current_pass_length++; + + if (current_pass_length > max_pass_length) { + max_pass_length = current_pass_length; + max_start = current_start; + max_end = rqfd; + } + } + } else { + current_pass_length = 0; + current_fail_length++; + + if (fail_found == FALSE) { + fail_found = TRUE; + } else if (pass_found == TRUE) { + window_found = TRUE; + break; + } + } + } + + /*------------------------------------------------------------------ + * Make sure we found the valid read passing window. Halt if not + *-----------------------------------------------------------------*/ + if (window_found == FALSE) { + printf("ERROR: Cannot determine a common read delay for the " + "DIMM(s) installed.\n"); + debug("%s[%d] ERROR : \n", __FUNCTION__,__LINE__); + hang(); + } + + rqfd_average = ((max_start + max_end) >> 1); + + if (rqfd_average < 0) + rqfd_average = 0; + + if (rqfd_average > SDRAM_RQDC_RQFD_MAX) + rqfd_average = SDRAM_RQDC_RQFD_MAX; + + /*------------------------------------------------------------------ + * Restore the ECC variable to what it originally was + *-----------------------------------------------------------------*/ + mfsdram(SDRAM_MCOPT1, val); + mtsdram(SDRAM_MCOPT1, (val & ~SDRAM_MCOPT1_MCHK_MASK) | ecc_temp); + + mtsdram(SDRAM_RQDC, + (rqdc_reg & ~SDRAM_RQDC_RQFD_MASK) | + SDRAM_RQDC_RQFD_ENCODE(rqfd_average)); + + mfsdram(SDRAM_DLCR, val); + debug("%s[%d] DLCR: 0x%08X\n", __FUNCTION__, __LINE__, val); + mfsdram(SDRAM_RQDC, val); + debug("%s[%d] RQDC: 0x%08X\n", __FUNCTION__, __LINE__, val); + mfsdram(SDRAM_RFDC, val); + debug("%s[%d] RFDC: 0x%08X\n", __FUNCTION__, __LINE__, val); +} +#else /* calibration test with hardvalues */ +/*-----------------------------------------------------------------------------+ + * DQS_calibration_process. + *-----------------------------------------------------------------------------*/ +static void test(void) +{ + unsigned long dimm_num; + unsigned long ecc_temp; + unsigned long i, j; + unsigned long *membase; + unsigned long bxcf[MAXRANKS]; + unsigned long val; + char window_found; + char begin_found[MAXDIMMS]; + char end_found[MAXDIMMS]; + char search_end[MAXDIMMS]; + unsigned long test[NUMMEMTESTS][NUMMEMWORDS] = { + {0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF}, + {0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000}, + {0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555, + 0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555}, + {0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA, + 0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA}, + {0xA5A5A5A5, 0xA5A5A5A5, 0x5A5A5A5A, 0x5A5A5A5A, + 0xA5A5A5A5, 0xA5A5A5A5, 0x5A5A5A5A, 0x5A5A5A5A}, + {0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5, + 0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5}, + {0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA, + 0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA}, + {0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55, + 0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55} }; + + /*------------------------------------------------------------------ + * Test to determine the best read clock delay tuning bits. + * + * Before the DDR controller can be used, the read clock delay needs to be + * set. This is SDRAM_RQDC[RQFD] and SDRAM_RFDC[RFFD]. + * This value cannot be hardcoded into the program because it changes + * depending on the board's setup and environment. + * To do this, all delay values are tested to see if they + * work or not. By doing this, you get groups of fails with groups of + * passing values. The idea is to find the start and end of a passing + * window and take the center of it to use as the read clock delay. + * + * A failure has to be seen first so that when we hit a pass, we know + * that it is truely the start of the window. If we get passing values + * to start off with, we don't know if we are at the start of the window. + * + * The code assumes that a failure will always be found. + * If a failure is not found, there is no easy way to get the middle + * of the passing window. I guess we can pretty much pick any value + * but some values will be better than others. Since the lowest speed + * we can clock the DDR interface at is 200 MHz (2x 100 MHz PLB speed), + * from experimentation it is safe to say you will always have a failure. + *-----------------------------------------------------------------*/ + mfsdram(SDRAM_MCOPT1, ecc_temp); + ecc_temp &= SDRAM_MCOPT1_MCHK_MASK; + mfsdram(SDRAM_MCOPT1, val); + mtsdram(SDRAM_MCOPT1, (val & ~SDRAM_MCOPT1_MCHK_MASK) | + SDRAM_MCOPT1_MCHK_NON); + + window_found = FALSE; + begin_found[0] = FALSE; + end_found[0] = FALSE; + search_end[0] = FALSE; + begin_found[1] = FALSE; + end_found[1] = FALSE; + search_end[1] = FALSE; + + for (dimm_num = 0; dimm_num < MAXDIMMS; dimm_num++) { + mfsdram(SDRAM_MB0CF + (bxcr_num << 2), bxcf[bxcr_num]); + + /* Banks enabled */ + if ((bxcf[dimm_num] & SDRAM_BXCF_M_BE_MASK) == SDRAM_BXCF_M_BE_ENABLE) { + + /* Bank is enabled */ + membase = + (unsigned long*)(SDRAM_RXBAS_SDBA_DECODE(mfdcr_any(SDRAM_R0BAS+dimm_num))); + + /*------------------------------------------------------------------ + * Run the short memory test. + *-----------------------------------------------------------------*/ + for (i = 0; i < NUMMEMTESTS; i++) { + for (j = 0; j < NUMMEMWORDS; j++) { + membase[j] = test[i][j]; + ppcDcbf((u32)&(membase[j])); + } + sync(); + for (j = 0; j < NUMMEMWORDS; j++) { + if (membase[j] != test[i][j]) { + ppcDcbf((u32)&(membase[j])); + break; + } + ppcDcbf((u32)&(membase[j])); + } + sync(); + if (j < NUMMEMWORDS) + break; + } + + /*------------------------------------------------------------------ + * See if the rffd value passed. + *-----------------------------------------------------------------*/ + if (i < NUMMEMTESTS) { + if ((end_found[dimm_num] == FALSE) && + (search_end[dimm_num] == TRUE)) { + end_found[dimm_num] = TRUE; + } + if ((end_found[0] == TRUE) && + (end_found[1] == TRUE)) + break; + } else { + if (begin_found[dimm_num] == FALSE) { + begin_found[dimm_num] = TRUE; + search_end[dimm_num] = TRUE; + } + } + } else { + begin_found[dimm_num] = TRUE; + end_found[dimm_num] = TRUE; + } + } + + if ((begin_found[0] == TRUE) && (begin_found[1] == TRUE)) + window_found = TRUE; + + /*------------------------------------------------------------------ + * Make sure we found the valid read passing window. Halt if not + *-----------------------------------------------------------------*/ + if (window_found == FALSE) { + printf("ERROR: Cannot determine a common read delay for the " + "DIMM(s) installed.\n"); + hang(); + } + + /*------------------------------------------------------------------ + * Restore the ECC variable to what it originally was + *-----------------------------------------------------------------*/ + mtsdram(SDRAM_MCOPT1, + (ppcMfdcr_sdram(SDRAM_MCOPT1) & ~SDRAM_MCOPT1_MCHK_MASK) + | ecc_temp); +} +#endif + +#if defined(DEBUG) +static void ppc440sp_sdram_register_dump(void) +{ + unsigned int sdram_reg; + unsigned int sdram_data; + unsigned int dcr_data; + + printf("\n Register Dump:\n"); + sdram_reg = SDRAM_MCSTAT; + mfsdram(sdram_reg, sdram_data); + printf(" SDRAM_MCSTAT = 0x%08X", sdram_data); + sdram_reg = SDRAM_MCOPT1; + mfsdram(sdram_reg, sdram_data); + printf(" SDRAM_MCOPT1 = 0x%08X\n", sdram_data); + sdram_reg = SDRAM_MCOPT2; + mfsdram(sdram_reg, sdram_data); + printf(" SDRAM_MCOPT2 = 0x%08X", sdram_data); + sdram_reg = SDRAM_MODT0; + mfsdram(sdram_reg, sdram_data); + printf(" SDRAM_MODT0 = 0x%08X\n", sdram_data); + sdram_reg = SDRAM_MODT1; + mfsdram(sdram_reg, sdram_data); + printf(" SDRAM_MODT1 = 0x%08X", sdram_data); + sdram_reg = SDRAM_MODT2; + mfsdram(sdram_reg, sdram_data); + printf(" SDRAM_MODT2 = 0x%08X\n", sdram_data); + sdram_reg = SDRAM_MODT3; + mfsdram(sdram_reg, sdram_data); + printf(" SDRAM_MODT3 = 0x%08X", sdram_data); + sdram_reg = SDRAM_CODT; + mfsdram(sdram_reg, sdram_data); + printf(" SDRAM_CODT = 0x%08X\n", sdram_data); + sdram_reg = SDRAM_VVPR; + mfsdram(sdram_reg, sdram_data); + printf(" SDRAM_VVPR = 0x%08X", sdram_data); + sdram_reg = SDRAM_OPARS; + mfsdram(sdram_reg, sdram_data); + printf(" SDRAM_OPARS = 0x%08X\n", sdram_data); + /* + * OPAR2 is only used as a trigger register. + * No data is contained in this register, and reading or writing + * to is can cause bad things to happen (hangs). Just skip it + * and report NA + * sdram_reg = SDRAM_OPAR2; + * mfsdram(sdram_reg, sdram_data); + * printf(" SDRAM_OPAR2 = 0x%08X\n", sdram_data); + */ + printf(" SDRAM_OPART = N/A "); + sdram_reg = SDRAM_RTR; + mfsdram(sdram_reg, sdram_data); + printf(" SDRAM_RTR = 0x%08X\n", sdram_data); + sdram_reg = SDRAM_MB0CF; + mfsdram(sdram_reg, sdram_data); + printf(" SDRAM_MB0CF = 0x%08X", sdram_data); + sdram_reg = SDRAM_MB1CF; + mfsdram(sdram_reg, sdram_data); + printf(" SDRAM_MB1CF = 0x%08X\n", sdram_data); + sdram_reg = SDRAM_MB2CF; + mfsdram(sdram_reg, sdram_data); + printf(" SDRAM_MB2CF = 0x%08X", sdram_data); + sdram_reg = SDRAM_MB3CF; + mfsdram(sdram_reg, sdram_data); + printf(" SDRAM_MB3CF = 0x%08X\n", sdram_data); + sdram_reg = SDRAM_INITPLR0; + mfsdram(sdram_reg, sdram_data); + printf(" SDRAM_INITPLR0 = 0x%08X", sdram_data); + sdram_reg = SDRAM_INITPLR1; + mfsdram(sdram_reg, sdram_data); + printf(" SDRAM_INITPLR1 = 0x%08X\n", sdram_data); + sdram_reg = SDRAM_INITPLR2; + mfsdram(sdram_reg, sdram_data); + printf(" SDRAM_INITPLR2 = 0x%08X", sdram_data); + sdram_reg = SDRAM_INITPLR3; + mfsdram(sdram_reg, sdram_data); + printf(" SDRAM_INITPLR3 = 0x%08X\n", sdram_data); + sdram_reg = SDRAM_INITPLR4; + mfsdram(sdram_reg, sdram_data); + printf(" SDRAM_INITPLR4 = 0x%08X", sdram_data); + sdram_reg = SDRAM_INITPLR5; + mfsdram(sdram_reg, sdram_data); + printf(" SDRAM_INITPLR5 = 0x%08X\n", sdram_data); + sdram_reg = SDRAM_INITPLR6; + mfsdram(sdram_reg, sdram_data); + printf(" SDRAM_INITPLR6 = 0x%08X", sdram_data); + sdram_reg = SDRAM_INITPLR7; + mfsdram(sdram_reg, sdram_data); + printf(" SDRAM_INITPLR7 = 0x%08X\n", sdram_data); + sdram_reg = SDRAM_INITPLR8; + mfsdram(sdram_reg, sdram_data); + printf(" SDRAM_INITPLR8 = 0x%08X", sdram_data); + sdram_reg = SDRAM_INITPLR9; + mfsdram(sdram_reg, sdram_data); + printf(" SDRAM_INITPLR9 = 0x%08X\n", sdram_data); + sdram_reg = SDRAM_INITPLR10; + mfsdram(sdram_reg, sdram_data); + printf(" SDRAM_INITPLR10 = 0x%08X", sdram_data); + sdram_reg = SDRAM_INITPLR11; + mfsdram(sdram_reg, sdram_data); + printf(" SDRAM_INITPLR11 = 0x%08X\n", sdram_data); + sdram_reg = SDRAM_INITPLR12; + mfsdram(sdram_reg, sdram_data); + printf(" SDRAM_INITPLR12 = 0x%08X", sdram_data); + sdram_reg = SDRAM_INITPLR13; + mfsdram(sdram_reg, sdram_data); + printf(" SDRAM_INITPLR13 = 0x%08X\n", sdram_data); + sdram_reg = SDRAM_INITPLR14; + mfsdram(sdram_reg, sdram_data); + printf(" SDRAM_INITPLR14 = 0x%08X", sdram_data); + sdram_reg = SDRAM_INITPLR15; + mfsdram(sdram_reg, sdram_data); + printf(" SDRAM_INITPLR15 = 0x%08X\n", sdram_data); + sdram_reg = SDRAM_RQDC; + mfsdram(sdram_reg, sdram_data); + printf(" SDRAM_RQDC = 0x%08X", sdram_data); + sdram_reg = SDRAM_RFDC; + mfsdram(sdram_reg, sdram_data); + printf(" SDRAM_RFDC = 0x%08X\n", sdram_data); + sdram_reg = SDRAM_RDCC; + mfsdram(sdram_reg, sdram_data); + printf(" SDRAM_RDCC = 0x%08X", sdram_data); + sdram_reg = SDRAM_DLCR; + mfsdram(sdram_reg, sdram_data); + printf(" SDRAM_DLCR = 0x%08X\n", sdram_data); + sdram_reg = SDRAM_CLKTR; + mfsdram(sdram_reg, sdram_data); + printf(" SDRAM_CLKTR = 0x%08X", sdram_data); + sdram_reg = SDRAM_WRDTR; + mfsdram(sdram_reg, sdram_data); + printf(" SDRAM_WRDTR = 0x%08X\n", sdram_data); + sdram_reg = SDRAM_SDTR1; + mfsdram(sdram_reg, sdram_data); + printf(" SDRAM_SDTR1 = 0x%08X", sdram_data); + sdram_reg = SDRAM_SDTR2; + mfsdram(sdram_reg, sdram_data); + printf(" SDRAM_SDTR2 = 0x%08X\n", sdram_data); + sdram_reg = SDRAM_SDTR3; + mfsdram(sdram_reg, sdram_data); + printf(" SDRAM_SDTR3 = 0x%08X", sdram_data); + sdram_reg = SDRAM_MMODE; + mfsdram(sdram_reg, sdram_data); + printf(" SDRAM_MMODE = 0x%08X\n", sdram_data); + sdram_reg = SDRAM_MEMODE; + mfsdram(sdram_reg, sdram_data); + printf(" SDRAM_MEMODE = 0x%08X", sdram_data); + sdram_reg = SDRAM_ECCCR; + mfsdram(sdram_reg, sdram_data); + printf(" SDRAM_ECCCR = 0x%08X\n\n", sdram_data); + + dcr_data = mfdcr(SDRAM_R0BAS); + printf(" MQ0_B0BAS = 0x%08X", dcr_data); + dcr_data = mfdcr(SDRAM_R1BAS); + printf(" MQ1_B0BAS = 0x%08X\n", dcr_data); + dcr_data = mfdcr(SDRAM_R2BAS); + printf(" MQ2_B0BAS = 0x%08X", dcr_data); + dcr_data = mfdcr(SDRAM_R3BAS); + printf(" MQ3_B0BAS = 0x%08X\n", dcr_data); +} +#endif +#endif /* CONFIG_SPD_EEPROM */ diff --git a/cpu/ppc4xx/4xx_enet.c b/cpu/ppc4xx/4xx_enet.c index 81d49ff..cf56581 100644 --- a/cpu/ppc4xx/4xx_enet.c +++ b/cpu/ppc4xx/4xx_enet.c @@ -166,6 +166,11 @@ struct eth_device *emac0_dev = NULL; #define LAST_EMAC_NUM 1 #endif +/* normal boards start with EMAC0 */ +#if !defined(CONFIG_EMAC_NR_START) +#define CONFIG_EMAC_NR_START 0 +#endif + /*-----------------------------------------------------------------------------+ * Prototypes and externals. *-----------------------------------------------------------------------------*/ @@ -264,10 +269,10 @@ int ppc_4xx_eth_setup_bridge(int devnum, bd_t * bis) bis->bi_phymode[3] = BI_PHYMODE_ZMII; break; case 2: - zmiifer = ZMII_FER_SMII << ZMII_FER_V(0); - zmiifer = ZMII_FER_SMII << ZMII_FER_V(1); - zmiifer = ZMII_FER_SMII << ZMII_FER_V(2); - zmiifer = ZMII_FER_SMII << ZMII_FER_V(3); + zmiifer |= ZMII_FER_SMII << ZMII_FER_V(0); + zmiifer |= ZMII_FER_SMII << ZMII_FER_V(1); + zmiifer |= ZMII_FER_SMII << ZMII_FER_V(2); + zmiifer |= ZMII_FER_SMII << ZMII_FER_V(3); bis->bi_phymode[0] = BI_PHYMODE_ZMII; bis->bi_phymode[1] = BI_PHYMODE_ZMII; bis->bi_phymode[2] = BI_PHYMODE_ZMII; @@ -470,8 +475,7 @@ static int ppc_4xx_eth_init (struct eth_device *dev, bd_t * bis) #else if ((devnum == 0) || (devnum == 1)) { out32 (ZMII_FER, (ZMII_FER_SMII | ZMII_FER_MDI) << ZMII_FER_V (devnum)); - } - else { /* ((devnum == 2) || (devnum == 3)) */ + } else { /* ((devnum == 2) || (devnum == 3)) */ out32 (ZMII_FER, ZMII_FER_MDI << ZMII_FER_V (devnum)); out32 (RGMII_FER, ((RGMII_FER_RGMII << RGMII_FER_V (2)) | (RGMII_FER_RGMII << RGMII_FER_V (3)))); @@ -561,22 +565,7 @@ static int ppc_4xx_eth_init (struct eth_device *dev, bd_t * bis) * otherwise, just check the speeds & feeds */ if (hw_p->first_init == 0) { -#if defined(CONFIG_88E1111_CLK_DELAY) - /* - * On some boards (e.g. ALPR) the Marvell 88E1111 PHY needs - * the "RGMII transmit timing control" and "RGMII receive - * timing control" bits set, so that Gbit communication works - * without problems. - * Also set the "Transmitter disable" to 1 to enable the - * transmitter. - * After setting these bits a soft-reset must occur for this - * change to become active. - */ - miiphy_read (dev->name, reg, 0x14, ®_short); - reg_short |= (1 << 7) | (1 << 1) | (1 << 0); - miiphy_write (dev->name, reg, 0x14, reg_short); -#endif -#if defined(CONFIG_M88E1111_PHY) /* test-only: merge with CONFIG_88E1111_CLK_DELAY !!! */ +#if defined(CONFIG_M88E1111_PHY) miiphy_write (dev->name, reg, 0x14, 0x0ce3); miiphy_write (dev->name, reg, 0x18, 0x4101); miiphy_write (dev->name, reg, 0x09, 0x0e00); @@ -617,6 +606,26 @@ static int ppc_4xx_eth_init (struct eth_device *dev, bd_t * bis) /* end Vitesse/Cicada errata */ } #endif + +#if defined(CONFIG_ET1011C_PHY) + /* + * Agere ET1011c PHY needs to have an extended register whacked + * for RGMII mode. + */ + if (((devnum == 2) || (devnum ==3)) && (4 == ethgroup)) { + miiphy_read (dev->name, reg, 0x16, ®_short); + reg_short &= ~(0x7); + reg_short |= 0x6; /* RGMII DLL Delay*/ + miiphy_write (dev->name, reg, 0x16, reg_short); + + miiphy_read (dev->name, reg, 0x17, ®_short); + reg_short &= ~(0x40); + miiphy_write (dev->name, reg, 0x17, reg_short); + + miiphy_write(dev->name, reg, 0x1c, 0x74f0); + } +#endif + #endif /* Start/Restart autonegotiation */ phy_setup_aneg (dev->name, reg); @@ -659,8 +668,9 @@ static int ppc_4xx_eth_init (struct eth_device *dev, bd_t * bis) if (hw_p->print_speed) { hw_p->print_speed = 0; - printf ("ENET Speed is %d Mbps - %s duplex connection\n", - (int) speed, (duplex == HALF) ? "HALF" : "FULL"); + printf ("ENET Speed is %d Mbps - %s duplex connection (EMAC%d)\n", + (int) speed, (duplex == HALF) ? "HALF" : "FULL", + hw_p->devnum); } #if defined(CONFIG_440) && !defined(CONFIG_440SP) && !defined(CONFIG_440SPE) && \ @@ -808,7 +818,7 @@ static int ppc_4xx_eth_init (struct eth_device *dev, bd_t * bis) hw_p->rx[i].ctrl |= MAL_RX_CTRL_EMPTY | MAL_RX_CTRL_INTR; hw_p->rx_ready[i] = -1; #if 0 - printf ("RX_BUFF %d @ 0x%08lx\n", i, (ulong) rx[i].data_ptr); + printf ("RX_BUFF %d @ 0x%08lx\n", i, (ulong) hw_p->rx[i].data_ptr); #endif } @@ -1323,6 +1333,9 @@ int enetInt (struct eth_device *dev) } } mtdcr (uicsr, MAL_UIC_DEF|EMAC_UIC_DEF|EMAC_UIC_DEF1); /* Clear */ +#if defined(CONFIG_405EZ) + mtsdr (sdricintstat, SDR_ICRX_STAT | SDR_ICTX0_STAT | SDR_ICTX1_STAT); +#endif /* defined(CONFIG_405EZ) */ } while (serviced); @@ -1509,6 +1522,8 @@ int ppc_4xx_eth_initialize (bd_t * bis) struct eth_device *dev; int eth_num = 0; EMAC_4XX_HW_PST hw = NULL; + u8 ethaddr[4 + CONFIG_EMAC_NR_START][6]; + u32 hw_addr[4]; #if defined(CONFIG_440GX) unsigned long pfc1; @@ -1518,59 +1533,69 @@ int ppc_4xx_eth_initialize (bd_t * bis) pfc1 |= 0x01200000; mtsdr (sdr_pfc1, pfc1); #endif - /* set phy num and mode */ - bis->bi_phynum[0] = CONFIG_PHY_ADDR; - bis->bi_phymode[0] = 0; - -#if defined(CONFIG_PHY1_ADDR) - bis->bi_phynum[1] = CONFIG_PHY1_ADDR; - bis->bi_phymode[1] = 0; -#endif -#if defined(CONFIG_440GX) - bis->bi_phynum[2] = CONFIG_PHY2_ADDR; - bis->bi_phynum[3] = CONFIG_PHY3_ADDR; - bis->bi_phymode[2] = 2; - bis->bi_phymode[3] = 2; - ppc_4xx_eth_setup_bridge(0, bis); -#endif + /* first clear all mac-addresses */ + for (eth_num = 0; eth_num < LAST_EMAC_NUM; eth_num++) + memcpy(ethaddr[eth_num], "\0\0\0\0\0\0", 6); for (eth_num = 0; eth_num < LAST_EMAC_NUM; eth_num++) { - - /* See if we can actually bring up the interface, otherwise, skip it */ switch (eth_num) { default: /* fall through */ case 0: - if (memcmp (bis->bi_enetaddr, "\0\0\0\0\0\0", 6) == 0) { - bis->bi_phymode[eth_num] = BI_PHYMODE_NONE; - continue; - } + memcpy(ethaddr[eth_num + CONFIG_EMAC_NR_START], + bis->bi_enetaddr, 6); + hw_addr[eth_num] = 0x0; break; #ifdef CONFIG_HAS_ETH1 case 1: - if (memcmp (bis->bi_enet1addr, "\0\0\0\0\0\0", 6) == 0) { - bis->bi_phymode[eth_num] = BI_PHYMODE_NONE; - continue; - } + memcpy(ethaddr[eth_num + CONFIG_EMAC_NR_START], + bis->bi_enet1addr, 6); + hw_addr[eth_num] = 0x100; break; #endif #ifdef CONFIG_HAS_ETH2 case 2: - if (memcmp (bis->bi_enet2addr, "\0\0\0\0\0\0", 6) == 0) { - bis->bi_phymode[eth_num] = BI_PHYMODE_NONE; - continue; - } + memcpy(ethaddr[eth_num + CONFIG_EMAC_NR_START], + bis->bi_enet2addr, 6); + hw_addr[eth_num] = 0x400; break; #endif #ifdef CONFIG_HAS_ETH3 case 3: - if (memcmp (bis->bi_enet3addr, "\0\0\0\0\0\0", 6) == 0) { - bis->bi_phymode[eth_num] = BI_PHYMODE_NONE; - continue; - } + memcpy(ethaddr[eth_num + CONFIG_EMAC_NR_START], + bis->bi_enet3addr, 6); + hw_addr[eth_num] = 0x600; break; #endif } + } + + /* set phy num and mode */ + bis->bi_phynum[0] = CONFIG_PHY_ADDR; + bis->bi_phymode[0] = 0; + +#if defined(CONFIG_PHY1_ADDR) + bis->bi_phynum[1] = CONFIG_PHY1_ADDR; + bis->bi_phymode[1] = 0; +#endif +#if defined(CONFIG_440GX) + bis->bi_phynum[2] = CONFIG_PHY2_ADDR; + bis->bi_phynum[3] = CONFIG_PHY3_ADDR; + bis->bi_phymode[2] = 2; + bis->bi_phymode[3] = 2; + + ppc_4xx_eth_setup_bridge(0, bis); +#endif + + for (eth_num = 0; eth_num < LAST_EMAC_NUM; eth_num++) { + /* + * See if we can actually bring up the interface, + * otherwise, skip it + */ + if (memcmp (ethaddr[eth_num], "\0\0\0\0\0\0", 6) == 0) { + bis->bi_phymode[eth_num] = BI_PHYMODE_NONE; + continue; + } /* Allocate device structure */ dev = (struct eth_device *) malloc (sizeof (*dev)); @@ -1592,36 +1617,12 @@ int ppc_4xx_eth_initialize (bd_t * bis) } memset(hw, 0, sizeof(*hw)); - switch (eth_num) { - default: /* fall through */ - case 0: - hw->hw_addr = 0; - memcpy (dev->enetaddr, bis->bi_enetaddr, 6); - break; -#ifdef CONFIG_HAS_ETH1 - case 1: - hw->hw_addr = 0x100; - memcpy (dev->enetaddr, bis->bi_enet1addr, 6); - break; -#endif -#ifdef CONFIG_HAS_ETH2 - case 2: - hw->hw_addr = 0x400; - memcpy (dev->enetaddr, bis->bi_enet2addr, 6); - break; -#endif -#ifdef CONFIG_HAS_ETH3 - case 3: - hw->hw_addr = 0x600; - memcpy (dev->enetaddr, bis->bi_enet3addr, 6); - break; -#endif - } - + hw->hw_addr = hw_addr[eth_num]; + memcpy (dev->enetaddr, ethaddr[eth_num], 6); hw->devnum = eth_num; hw->print_speed = 1; - sprintf (dev->name, "ppc_4xx_eth%d", eth_num); + sprintf (dev->name, "ppc_4xx_eth%d", eth_num - CONFIG_EMAC_NR_START); dev->priv = (void *) hw; dev->init = ppc_4xx_eth_init; dev->halt = ppc_4xx_eth_halt; @@ -1679,7 +1680,6 @@ int ppc_4xx_eth_initialize (bd_t * bis) return (1); } - #if !defined(CONFIG_NET_MULTI) void eth_halt (void) { if (emac0_dev) { diff --git a/cpu/ppc4xx/Makefile b/cpu/ppc4xx/Makefile index 87c6230..1347e0f 100644 --- a/cpu/ppc4xx/Makefile +++ b/cpu/ppc4xx/Makefile @@ -31,7 +31,9 @@ COBJS = 405gp_pci.o 440spe_pcie.o 4xx_enet.o \ bedbug_405.o commproc.o \ cpu.o cpu_init.o i2c.o interrupts.o \ miiphy.o ndfc.o sdram.o serial.o \ - spd_sdram.o speed.o traps.o usb_ohci.o usbdev.o usb.o + 40x_spd_sdram.o 44x_spd_ddr.o 44x_spd_ddr2.o speed.o \ + tlb.o traps.o usb_ohci.o usbdev.o usb.o \ + 440spe_pcie.o SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c) OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS)) diff --git a/cpu/ppc4xx/cpu.c b/cpu/ppc4xx/cpu.c index f4a7208..2d8740c 100644 --- a/cpu/ppc4xx/cpu.c +++ b/cpu/ppc4xx/cpu.c @@ -41,8 +41,15 @@ DECLARE_GLOBAL_DATA_PTR; #endif +#if defined(CONFIG_BOARD_RESET) +void board_reset(void); +#endif + #if defined(CONFIG_440) #define FREQ_EBC (sys_info.freqEPB) +#elif defined(CONFIG_405EZ) +#define FREQ_EBC ((CONFIG_SYS_CLK_FREQ * sys_info.pllFbkDiv) / \ + sys_info.pllExtBusDiv) #else #define FREQ_EBC (sys_info.freqPLB / sys_info.pllExtBusDiv) #endif @@ -84,14 +91,18 @@ int pci_arbiter_enabled(void) return (mfdcr(cpc0_strp1) & CPC0_STRP1_PAE_MASK); #endif -#if defined(CONFIG_440GX) || \ - defined(CONFIG_440EP) || defined(CONFIG_440GR) || \ - defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \ - defined(CONFIG_440SP) || defined(CONFIG_440SPE) +#if defined(CONFIG_440GX) || defined(CONFIG_440SP) || defined(CONFIG_440SPE) unsigned long val; - mfsdr(sdr_sdstp1, val); - return (val & SDR0_SDSTP1_PAE_MASK); + mfsdr(sdr_xcr, val); + return (val & 0x80000000); +#endif +#if defined(CONFIG_440EP) || defined(CONFIG_440GR) || \ + defined(CONFIG_440EPX) || defined(CONFIG_440GRX) + unsigned long val; + + mfsdr(sdr_pci0, val); + return (val & 0x80000000); #endif } #endif @@ -201,7 +212,8 @@ int checkcpu (void) puts("AMCC PowerPC 4"); -#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || defined(CONFIG_405EP) +#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \ + defined(CONFIG_405EP) || defined(CONFIG_405EZ) puts("05"); #endif #if defined(CONFIG_440) @@ -249,6 +261,10 @@ int checkcpu (void) puts("EP Rev. B"); break; + case PVR_405EZ_RA: + puts("EZ Rev. A"); + break; + #if defined(CONFIG_440) case PVR_440GP_RB: puts("GP Rev. B"); @@ -308,40 +324,68 @@ int checkcpu (void) #endif /* CONFIG_440GR */ #endif /* CONFIG_440 */ - case PVR_440EPX1_RA: +#ifdef CONFIG_440EPX + case PVR_440EPX1_RA: /* 440EPx rev A and 440GRx rev A have same PVR */ puts("EPx Rev. A"); strcpy(addstr, "Security/Kasumi support"); break; - case PVR_440EPX2_RA: + case PVR_440EPX2_RA: /* 440EPx rev A and 440GRx rev A have same PVR */ puts("EPx Rev. A"); strcpy(addstr, "No Security/Kasumi support"); break; +#endif /* CONFIG_440EPX */ - case PVR_440GRX1_RA: +#ifdef CONFIG_440GRX + case PVR_440GRX1_RA: /* 440EPx rev A and 440GRx rev A have same PVR */ puts("GRx Rev. A"); strcpy(addstr, "Security/Kasumi support"); break; - case PVR_440GRX2_RA: + case PVR_440GRX2_RA: /* 440EPx rev A and 440GRx rev A have same PVR */ puts("GRx Rev. A"); strcpy(addstr, "No Security/Kasumi support"); break; +#endif /* CONFIG_440GRX */ + + case PVR_440SP_6_RAB: + puts("SP Rev. A/B"); + strcpy(addstr, "RAID 6 support"); + break; - case PVR_440SP_RA: - puts("SP Rev. A"); + case PVR_440SP_RAB: + puts("SP Rev. A/B"); + strcpy(addstr, "No RAID 6 support"); break; - case PVR_440SP_RB: - puts("SP Rev. B"); + case PVR_440SP_6_RC: + puts("SP Rev. C"); + strcpy(addstr, "RAID 6 support"); + break; + + case PVR_440SP_RC: + puts("SP Rev. C"); + strcpy(addstr, "No RAID 6 support"); + break; + + case PVR_440SPe_6_RA: + puts("SPe Rev. A"); + strcpy(addstr, "RAID 6 support"); break; case PVR_440SPe_RA: puts("SPe Rev. A"); + strcpy(addstr, "No RAID 6 support"); + break; + + case PVR_440SPe_6_RB: + puts("SPe Rev. B"); + strcpy(addstr, "RAID 6 support"); break; case PVR_440SPe_RB: puts("SPe Rev. B"); + strcpy(addstr, "No RAID 6 support"); break; default: @@ -350,9 +394,9 @@ int checkcpu (void) } printf (" at %s MHz (PLB=%lu, OPB=%lu, EBC=%lu MHz)\n", strmhz(buf, clock), - sys_info.freqPLB / 1000000, - sys_info.freqPLB / sys_info.pllOpbDiv / 1000000, - FREQ_EBC / 1000000); + sys_info.freqPLB / 1000000, + get_OPB_freq() / 1000000, + FREQ_EBC / 1000000); if (addstr[0] != 0) printf(" %s\n", addstr); @@ -382,7 +426,7 @@ int checkcpu (void) putc('\n'); #endif -#if defined(CONFIG_405EP) +#if defined(CONFIG_405EP) || defined(CONFIG_405EZ) printf (" 16 kB I-Cache 16 kB D-Cache"); #elif defined(CONFIG_440) printf (" 32 kB I-Cache 32 kB D-Cache"); @@ -411,7 +455,7 @@ int ppc440spe_revB() { unsigned int pvr; pvr = get_pvr(); - if (pvr == PVR_440SPe_RB) + if ((pvr == PVR_440SPe_6_RB) || (pvr == PVR_440SPe_RB)) return 1; else return 0; @@ -422,23 +466,19 @@ int ppc440spe_revB() { int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) { -#if defined(CONFIG_YOSEMITE) || defined(CONFIG_YELLOWSTONE) - /*give reset to BCSR*/ - *(unsigned char*)(CFG_BCSR_BASE | 0x06) = 0x09; - +#if defined(CONFIG_BOARD_RESET) + board_reset(); +#else +#if defined(CFG_4xx_RESET_TYPE) + mtspr(dbcr0, CFG_4xx_RESET_TYPE << 28); #else - /* * Initiate system reset in debug control register DBCR */ - __asm__ __volatile__("lis 3, 0x3000" ::: "r3"); -#if defined(CONFIG_440) - __asm__ __volatile__("mtspr 0x134, 3"); -#else - __asm__ __volatile__("mtspr 0x3f2, 3"); -#endif + mtspr(dbcr0, 0x30000000); +#endif /* defined(CFG_4xx_RESET_TYPE) */ +#endif /* defined(CONFIG_BOARD_RESET) */ -#endif/* defined(CONFIG_YOSEMITE) || defined(CONFIG_YELLOWSTONE)*/ return 1; } diff --git a/cpu/ppc4xx/cpu_init.c b/cpu/ppc4xx/cpu_init.c index def46f1..9d1cd13 100644 --- a/cpu/ppc4xx/cpu_init.c +++ b/cpu/ppc4xx/cpu_init.c @@ -31,9 +31,6 @@ DECLARE_GLOBAL_DATA_PTR; #endif - -#define mtebc(reg, data) mtdcr(ebccfga,reg);mtdcr(ebccfgd,data) - #ifdef CFG_INIT_DCACHE_CS # if (CFG_INIT_DCACHE_CS == 0) # define PBxAP pb0ap @@ -222,6 +219,10 @@ void set_chip_gpio_configuration(gpio_param_s (*gpio_tab)[GPIO_GROUP_MAX][GPIO_M void cpu_init_f (void) { +#if defined(CONFIG_WATCHDOG) + unsigned long val; +#endif + #if defined(CONFIG_405EP) /* * GPIO0 setup (select GPIO or alternate function) @@ -255,7 +256,8 @@ cpu_init_f (void) */ #if (defined(CFG_EBC_PB0AP) && defined(CFG_EBC_PB0CR)) #if (defined(CONFIG_405GP) || defined(CONFIG_405CR) || \ - defined(CONFIG_405EP) || defined(CONFIG_405)) + defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \ + defined(CONFIG_405)) /* * Move the next instructions into icache, since these modify the flash * we are running from! @@ -312,15 +314,21 @@ cpu_init_f (void) mtebc(pb7cr, CFG_EBC_PB7CR); #endif -#if defined(CONFIG_WATCHDOG) - unsigned long val; +#if defined (CFG_EBC_CFG) + mtebc(EBC0_CFG, CFG_EBC_CFG); +#endif +#if defined(CONFIG_WATCHDOG) val = mfspr(tcr); #if defined(CONFIG_440EP) || defined(CONFIG_440GR) val |= 0xb8000000; /* generate system reset after 1.34 seconds */ #else val |= 0xf0000000; /* generate system reset after 2.684 seconds */ #endif +#if defined(CFG_4xx_RESET_TYPE) + val &= ~0x30000000; /* clear WRC bits */ + val |= CFG_4xx_RESET_TYPE << 28; /* set board specific WRC type */ +#endif mtspr(tcr, val); val = mfspr(tsr); diff --git a/cpu/ppc4xx/i2c.c b/cpu/ppc4xx/i2c.c index 7db1cd8..8f4da86 100644 --- a/cpu/ppc4xx/i2c.c +++ b/cpu/ppc4xx/i2c.c @@ -1,91 +1,100 @@ -/*****************************************************************************/ -/* I2C Bus interface initialisation and I2C Commands */ -/* for PPC405GP */ -/* Author : AS HARNOIS */ -/* Date : 13.Dec.00 */ -/*****************************************************************************/ +/* + * (C) Copyright 2007 + * Stefan Roese, DENX Software Engineering, sr@denx.de. + * + * based on work by Anne Sophie Harnois <anne-sophie.harnois@nextream.fr> + * + * (C) Copyright 2001 + * Bill Hunter, Wave 7 Optics, williamhunter@mediaone.net + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ #include <common.h> #include <ppc4xx.h> -#if defined(CONFIG_440) -# include <440_i2c.h> -#else -# include <405gp_i2c.h> -#endif +#include <4xx_i2c.h> #include <i2c.h> +#include <asm-ppc/io.h> #ifdef CONFIG_HARD_I2C DECLARE_GLOBAL_DATA_PTR; -#define IIC_OK 0 -#define IIC_NOK 1 -#define IIC_NOK_LA 2 /* Lost arbitration */ -#define IIC_NOK_ICT 3 /* Incomplete transfer */ -#define IIC_NOK_XFRA 4 /* Transfer aborted */ -#define IIC_NOK_DATA 5 /* No data in buffer */ -#define IIC_NOK_TOUT 6 /* Transfer timeout */ - -#define IIC_TIMEOUT 1 /* 1 seconde */ - +#if defined(CONFIG_I2C_MULTI_BUS) +/* Initialize the bus pointer to whatever one the SPD EEPROM is on. + * Default is bus 0. This is necessary because the DDR initialization + * runs from ROM, and we can't switch buses because we can't modify + * the global variables. + */ +#ifdef CFG_SPD_BUS_NUM +static unsigned int i2c_bus_num __attribute__ ((section ("data"))) = CFG_SPD_BUS_NUM; +#else +static unsigned int i2c_bus_num __attribute__ ((section ("data"))) = 0; +#endif +#endif /* CONFIG_I2C_MULTI_BUS */ -static void _i2c_bus_reset (void) +static void _i2c_bus_reset(void) { - int i, status; + int i; + u8 dc; /* Reset status register */ /* write 1 in SCMP and IRQA to clear these fields */ - out8 (IIC_STS, 0x0A); + out_8((u8 *)IIC_STS, 0x0A); /* write 1 in IRQP IRQD LA ICT XFRA to clear these fields */ - out8 (IIC_EXTSTS, 0x8F); - __asm__ volatile ("eieio"); - - /* - * Get current state, reset bus - * only if no transfers are pending. - */ - i = 10; - do { - /* Get status */ - status = in8 (IIC_STS); - udelay (500); /* 500us */ - i--; - } while ((status & IIC_STS_PT) && (i > 0)); - /* Soft reset controller */ - status = in8 (IIC_XTCNTLSS); - out8 (IIC_XTCNTLSS, (status | IIC_XTCNTLSS_SRST)); - __asm__ volatile ("eieio"); - - /* make sure where in initial state, data hi, clock hi */ - out8 (IIC_DIRECTCNTL, 0xC); - for (i = 0; i < 10; i++) { - if ((in8 (IIC_DIRECTCNTL) & 0x3) != 0x3) { - /* clock until we get to known state */ - out8 (IIC_DIRECTCNTL, 0x8); /* clock lo */ - udelay (100); /* 100us */ - out8 (IIC_DIRECTCNTL, 0xC); /* clock hi */ - udelay (100); /* 100us */ - } else { - break; + out_8((u8 *)IIC_EXTSTS, 0x8F); + + /* Place chip in the reset state */ + out_8((u8 *)IIC_XTCNTLSS, IIC_XTCNTLSS_SRST); + + /* Check if bus is free */ + dc = in_8((u8 *)IIC_DIRECTCNTL); + if (!DIRCTNL_FREE(dc)){ + /* Try to set bus free state */ + out_8((u8 *)IIC_DIRECTCNTL, IIC_DIRCNTL_SDAC | IIC_DIRCNTL_SCC); + + /* Wait until we regain bus control */ + for (i = 0; i < 100; ++i) { + dc = in_8((u8 *)IIC_DIRECTCNTL); + if (DIRCTNL_FREE(dc)) + break; + + /* Toggle SCL line */ + dc ^= IIC_DIRCNTL_SCC; + out_8((u8 *)IIC_DIRECTCNTL, dc); + udelay(10); + dc ^= IIC_DIRCNTL_SCC; + out_8((u8 *)IIC_DIRECTCNTL, dc); } } - /* send start condition */ - out8 (IIC_DIRECTCNTL, 0x4); - udelay (1000); /* 1ms */ - /* send stop condition */ - out8 (IIC_DIRECTCNTL, 0xC); - udelay (1000); /* 1ms */ - /* Unreset controller */ - out8 (IIC_XTCNTLSS, (status & ~IIC_XTCNTLSS_SRST)); - udelay (1000); /* 1ms */ + + /* Remove reset */ + out_8((u8 *)IIC_XTCNTLSS, 0); } -void i2c_init (int speed, int slaveadd) +void i2c_init(int speed, int slaveadd) { sys_info_t sysInfo; unsigned long freqOPB; int val, divisor; + int bus; #ifdef CFG_I2C_INIT_BOARD /* call board specific i2c bus reset routine before accessing the */ @@ -94,101 +103,100 @@ void i2c_init (int speed, int slaveadd) i2c_init_board(); #endif - /* Handle possible failed I2C state */ - /* FIXME: put this into i2c_init_board()? */ - _i2c_bus_reset (); + for (bus = 0; bus < CFG_MAX_I2C_BUS; bus++) { + I2C_SET_BUS(bus); - /* clear lo master address */ - out8 (IIC_LMADR, 0); + /* Handle possible failed I2C state */ + /* FIXME: put this into i2c_init_board()? */ + _i2c_bus_reset(); - /* clear hi master address */ - out8 (IIC_HMADR, 0); + /* clear lo master address */ + out_8((u8 *)IIC_LMADR, 0); - /* clear lo slave address */ - out8 (IIC_LSADR, 0); + /* clear hi master address */ + out_8((u8 *)IIC_HMADR, 0); - /* clear hi slave address */ - out8 (IIC_HSADR, 0); + /* clear lo slave address */ + out_8((u8 *)IIC_LSADR, 0); - /* Clock divide Register */ - /* get OPB frequency */ - get_sys_info (&sysInfo); - freqOPB = sysInfo.freqPLB / sysInfo.pllOpbDiv; - /* set divisor according to freqOPB */ - divisor = (freqOPB - 1) / 10000000; - if (divisor == 0) - divisor = 1; - out8 (IIC_CLKDIV, divisor); + /* clear hi slave address */ + out_8((u8 *)IIC_HSADR, 0); - /* no interrupts */ - out8 (IIC_INTRMSK, 0); + /* Clock divide Register */ + /* get OPB frequency */ + get_sys_info(&sysInfo); + freqOPB = sysInfo.freqPLB / sysInfo.pllOpbDiv; + /* set divisor according to freqOPB */ + divisor = (freqOPB - 1) / 10000000; + if (divisor == 0) + divisor = 1; + out_8((u8 *)IIC_CLKDIV, divisor); - /* clear transfer count */ - out8 (IIC_XFRCNT, 0); + /* no interrupts */ + out_8((u8 *)IIC_INTRMSK, 0); - /* clear extended control & stat */ - /* write 1 in SRC SRS SWC SWS to clear these fields */ - out8 (IIC_XTCNTLSS, 0xF0); + /* clear transfer count */ + out_8((u8 *)IIC_XFRCNT, 0); - /* Mode Control Register - Flush Slave/Master data buffer */ - out8 (IIC_MDCNTL, IIC_MDCNTL_FSDB | IIC_MDCNTL_FMDB); - __asm__ volatile ("eieio"); + /* clear extended control & stat */ + /* write 1 in SRC SRS SWC SWS to clear these fields */ + out_8((u8 *)IIC_XTCNTLSS, 0xF0); + /* Mode Control Register + Flush Slave/Master data buffer */ + out_8((u8 *)IIC_MDCNTL, IIC_MDCNTL_FSDB | IIC_MDCNTL_FMDB); - val = in8(IIC_MDCNTL); - __asm__ volatile ("eieio"); + val = in_8((u8 *)IIC_MDCNTL); - /* Ignore General Call, slave transfers are ignored, - disable interrupts, exit unknown bus state, enable hold - SCL - 100kHz normaly or FastMode for 400kHz and above - */ + /* Ignore General Call, slave transfers are ignored, + * disable interrupts, exit unknown bus state, enable hold + * SCL 100kHz normaly or FastMode for 400kHz and above + */ - val |= IIC_MDCNTL_EUBS|IIC_MDCNTL_HSCL; - if( speed >= 400000 ){ - val |= IIC_MDCNTL_FSM; - } - out8 (IIC_MDCNTL, val); + val |= IIC_MDCNTL_EUBS|IIC_MDCNTL_HSCL; + if (speed >= 400000) + val |= IIC_MDCNTL_FSM; + out_8((u8 *)IIC_MDCNTL, val); - /* clear control reg */ - out8 (IIC_CNTL, 0x00); - __asm__ volatile ("eieio"); + /* clear control reg */ + out_8((u8 *)IIC_CNTL, 0x00); + } + /* set to SPD bus as default bus upon powerup */ + I2C_SET_BUS(CFG_SPD_BUS_NUM); } /* - This code tries to use the features of the 405GP i2c - controller. It will transfer up to 4 bytes in one pass - on the loop. It only does out8(lbz) to the buffer when it - is possible to do out16(lhz) transfers. - - cmd_type is 0 for write 1 for read. - - addr_len can take any value from 0-255, it is only limited - by the char, we could make it larger if needed. If it is - 0 we skip the address write cycle. - - Typical case is a Write of an addr followd by a Read. The - IBM FAQ does not cover this. On the last byte of the write - we don't set the creg CHT bit, and on the first bytes of the - read we set the RPST bit. - - It does not support address only transfers, there must be - a data part. If you want to write the address yourself, put - it in the data pointer. - - It does not support transfer to/from address 0. - - It does not check XFRCNT. -*/ -static -int i2c_transfer(unsigned char cmd_type, - unsigned char chip, - unsigned char addr[], - unsigned char addr_len, - unsigned char data[], - unsigned short data_len ) + * This code tries to use the features of the 405GP i2c + * controller. It will transfer up to 4 bytes in one pass + * on the loop. It only does out_8((u8 *)lbz) to the buffer when it + * is possible to do out16(lhz) transfers. + * + * cmd_type is 0 for write 1 for read. + * + * addr_len can take any value from 0-255, it is only limited + * by the char, we could make it larger if needed. If it is + * 0 we skip the address write cycle. + * + * Typical case is a Write of an addr followd by a Read. The + * IBM FAQ does not cover this. On the last byte of the write + * we don't set the creg CHT bit, and on the first bytes of the + * read we set the RPST bit. + * + * It does not support address only transfers, there must be + * a data part. If you want to write the address yourself, put + * it in the data pointer. + * + * It does not support transfer to/from address 0. + * + * It does not check XFRCNT. + */ +static int i2c_transfer(unsigned char cmd_type, + unsigned char chip, + unsigned char addr[], + unsigned char addr_len, + unsigned char data[], + unsigned short data_len) { unsigned char* ptr; int reading; @@ -198,97 +206,88 @@ int i2c_transfer(unsigned char cmd_type, int i; uchar creg; - if( data == 0 || data_len == 0 ){ - /*Don't support data transfer of no length or to address 0*/ + if (data == 0 || data_len == 0) { + /* Don't support data transfer of no length or to address 0 */ printf( "i2c_transfer: bad call\n" ); return IIC_NOK; } - if( addr && addr_len ){ + if (addr && addr_len) { ptr = addr; cnt = addr_len; reading = 0; - }else{ + } else { ptr = data; cnt = data_len; reading = cmd_type; } - /*Clear Stop Complete Bit*/ - out8(IIC_STS,IIC_STS_SCMP); + /* Clear Stop Complete Bit */ + out_8((u8 *)IIC_STS, IIC_STS_SCMP); /* Check init */ - i=10; + i = 10; do { /* Get status */ - status = in8(IIC_STS); - __asm__ volatile("eieio"); + status = in_8((u8 *)IIC_STS); i--; - } while ((status & IIC_STS_PT) && (i>0)); + } while ((status & IIC_STS_PT) && (i > 0)); if (status & IIC_STS_PT) { result = IIC_NOK_TOUT; return(result); } - /*flush the Master/Slave Databuffers*/ - out8(IIC_MDCNTL, ((in8(IIC_MDCNTL))|IIC_MDCNTL_FMDB|IIC_MDCNTL_FSDB)); - /*need to wait 4 OPB clocks? code below should take that long*/ + /* flush the Master/Slave Databuffers */ + out_8((u8 *)IIC_MDCNTL, ((in_8((u8 *)IIC_MDCNTL))|IIC_MDCNTL_FMDB|IIC_MDCNTL_FSDB)); + /* need to wait 4 OPB clocks? code below should take that long */ /* 7-bit adressing */ - out8(IIC_HMADR,0); - out8(IIC_LMADR, chip); - __asm__ volatile("eieio"); + out_8((u8 *)IIC_HMADR, 0); + out_8((u8 *)IIC_LMADR, chip); tran = 0; result = IIC_OK; creg = 0; - while ( tran != cnt && (result == IIC_OK)) { + while (tran != cnt && (result == IIC_OK)) { int bc,j; /* Control register = - Normal transfer, 7-bits adressing, Transfer up to bc bytes, Normal start, - Transfer is a sequence of transfers - */ + * Normal transfer, 7-bits adressing, Transfer up to bc bytes, Normal start, + * Transfer is a sequence of transfers + */ creg |= IIC_CNTL_PT; - bc = (cnt - tran) > 4 ? 4 : - cnt - tran; - creg |= (bc-1)<<4; - /* if the real cmd type is write continue trans*/ - if ( (!cmd_type && (ptr == addr)) || ((tran+bc) != cnt) ) + bc = (cnt - tran) > 4 ? 4 : cnt - tran; + creg |= (bc - 1) << 4; + /* if the real cmd type is write continue trans */ + if ((!cmd_type && (ptr == addr)) || ((tran + bc) != cnt)) creg |= IIC_CNTL_CHT; if (reading) creg |= IIC_CNTL_READ; - else { - for(j=0; j<bc; j++) { + else + for(j=0; j < bc; j++) /* Set buffer */ - out8(IIC_MDBUF,ptr[tran+j]); - __asm__ volatile("eieio"); - } - } - out8(IIC_CNTL, creg ); - __asm__ volatile("eieio"); + out_8((u8 *)IIC_MDBUF, ptr[tran+j]); + out_8((u8 *)IIC_CNTL, creg); /* Transfer is in progress - we have to wait for upto 5 bytes of data - 1 byte chip address+r/w bit then bc bytes - of data. - udelay(10) is 1 bit time at 100khz - Doubled for slop. 20 is too small. - */ - i=2*5*8; + * we have to wait for upto 5 bytes of data + * 1 byte chip address+r/w bit then bc bytes + * of data. + * udelay(10) is 1 bit time at 100khz + * Doubled for slop. 20 is too small. + */ + i = 2*5*8; do { /* Get status */ - status = in8(IIC_STS); - __asm__ volatile("eieio"); - udelay (10); + status = in_8((u8 *)IIC_STS); + udelay(10); i--; - } while ((status & IIC_STS_PT) && !(status & IIC_STS_ERR) - && (i>0)); + } while ((status & IIC_STS_PT) && !(status & IIC_STS_ERR) && (i > 0)); if (status & IIC_STS_ERR) { result = IIC_NOK; - status = in8 (IIC_EXTSTS); + status = in_8((u8 *)IIC_EXTSTS); /* Lost arbitration? */ if (status & IIC_EXTSTS_LA) result = IIC_NOK_LA; @@ -306,34 +305,32 @@ int i2c_transfer(unsigned char cmd_type, /* Are there data in buffer */ if (status & IIC_STS_MDBS) { /* - even if we have data we have to wait 4OPB clocks - for it to hit the front of the FIFO, after that - we can just read. We should check XFCNT here and - if the FIFO is full there is no need to wait. - */ - udelay (1); - for(j=0;j<bc;j++) { - ptr[tran+j] = in8(IIC_MDBUF); - __asm__ volatile("eieio"); - } + * even if we have data we have to wait 4OPB clocks + * for it to hit the front of the FIFO, after that + * we can just read. We should check XFCNT here and + * if the FIFO is full there is no need to wait. + */ + udelay(1); + for (j=0; j<bc; j++) + ptr[tran+j] = in_8((u8 *)IIC_MDBUF); } else result = IIC_NOK_DATA; } creg = 0; - tran+=bc; - if( ptr == addr && tran == cnt ) { + tran += bc; + if (ptr == addr && tran == cnt) { ptr = data; cnt = data_len; tran = 0; reading = cmd_type; - if( reading ) + if (reading) creg = IIC_CNTL_RPST; } } return (result); } -int i2c_probe (uchar chip) +int i2c_probe(uchar chip) { uchar buf[1]; @@ -344,21 +341,21 @@ int i2c_probe (uchar chip) * address was <ACK>ed (i.e. there was a chip at that address which * drove the data line low). */ - return(i2c_transfer (1, chip << 1, 0,0, buf, 1) != 0); + return (i2c_transfer(1, chip << 1, 0,0, buf, 1) != 0); } -int i2c_read (uchar chip, uint addr, int alen, uchar * buffer, int len) +int i2c_read(uchar chip, uint addr, int alen, uchar * buffer, int len) { uchar xaddr[4]; int ret; - if ( alen > 4 ) { + if (alen > 4) { printf ("I2C read: addr len %d not supported\n", alen); return 1; } - if ( alen > 0 ) { + if (alen > 0) { xaddr[0] = (addr >> 24) & 0xFF; xaddr[1] = (addr >> 16) & 0xFF; xaddr[2] = (addr >> 8) & 0xFF; @@ -378,10 +375,10 @@ int i2c_read (uchar chip, uint addr, int alen, uchar * buffer, int len) * still be one byte because the extra address bits are * hidden in the chip address. */ - if( alen > 0 ) + if (alen > 0) chip |= ((addr >> (alen * 8)) & CFG_I2C_EEPROM_ADDR_OVERFLOW); #endif - if( (ret = i2c_transfer( 1, chip<<1, &xaddr[4-alen], alen, buffer, len )) != 0) { + if ((ret = i2c_transfer(1, chip<<1, &xaddr[4-alen], alen, buffer, len)) != 0) { if (gd->have_console) printf( "I2c read: failed %d\n", ret); return 1; @@ -389,16 +386,17 @@ int i2c_read (uchar chip, uint addr, int alen, uchar * buffer, int len) return 0; } -int i2c_write (uchar chip, uint addr, int alen, uchar * buffer, int len) +int i2c_write(uchar chip, uint addr, int alen, uchar * buffer, int len) { uchar xaddr[4]; - if ( alen > 4 ) { + if (alen > 4) { printf ("I2C write: addr len %d not supported\n", alen); return 1; } - if ( alen > 0 ) { + + if (alen > 0) { xaddr[0] = (addr >> 24) & 0xFF; xaddr[1] = (addr >> 16) & 0xFF; xaddr[2] = (addr >> 8) & 0xFF; @@ -417,11 +415,11 @@ int i2c_write (uchar chip, uint addr, int alen, uchar * buffer, int len) * still be one byte because the extra address bits are * hidden in the chip address. */ - if( alen > 0 ) + if (alen > 0) chip |= ((addr >> (alen * 8)) & CFG_I2C_EEPROM_ADDR_OVERFLOW); #endif - return (i2c_transfer( 0, chip<<1, &xaddr[4-alen], alen, buffer, len ) != 0); + return (i2c_transfer(0, chip<<1, &xaddr[4-alen], alen, buffer, len ) != 0); } /*----------------------------------------------------------------------- @@ -433,7 +431,7 @@ uchar i2c_reg_read(uchar i2c_addr, uchar reg) i2c_read(i2c_addr, reg, 1, &buf, 1); - return(buf); + return (buf); } /*----------------------------------------------------------------------- @@ -443,4 +441,38 @@ void i2c_reg_write(uchar i2c_addr, uchar reg, uchar val) { i2c_write(i2c_addr, reg, 1, &val, 1); } + +#if defined(CONFIG_I2C_MULTI_BUS) +/* + * Functions for multiple I2C bus handling + */ +unsigned int i2c_get_bus_num(void) +{ + return i2c_bus_num; +} + +int i2c_set_bus_num(unsigned int bus) +{ + if (bus >= CFG_MAX_I2C_BUS) + return -1; + + i2c_bus_num = bus; + + return 0; +} +#endif /* CONFIG_I2C_MULTI_BUS */ + +/* TODO: add 100/400k switching */ +unsigned int i2c_get_bus_speed(void) +{ + return CFG_I2C_SPEED; +} + +int i2c_set_bus_speed(unsigned int speed) +{ + if (speed != CFG_I2C_SPEED) + return -1; + + return 0; +} #endif /* CONFIG_HARD_I2C */ diff --git a/cpu/ppc4xx/ndfc.c b/cpu/ppc4xx/ndfc.c index 3521731..b198ff4 100644 --- a/cpu/ppc4xx/ndfc.c +++ b/cpu/ppc4xx/ndfc.c @@ -156,7 +156,7 @@ void board_nand_select_device(struct nand_chip *nand, int chip) out32(base + NDFC_CCR, 0x00000000 | (cs << 24)); } -void board_nand_init(struct nand_chip *nand) +int board_nand_init(struct nand_chip *nand) { int cs = (ulong)nand->IO_ADDR_W & 0x00000003; ulong base = (ulong)nand->IO_ADDR_W & 0xfffffffc; @@ -188,6 +188,7 @@ void board_nand_init(struct nand_chip *nand) */ board_nand_select_device(nand, cs); out32(base + NDFC_BCFG0 + (cs << 2), 0x80002222); + return 0; } #endif diff --git a/cpu/ppc4xx/sdram.c b/cpu/ppc4xx/sdram.c index faeea5c..d520cd3 100644 --- a/cpu/ppc4xx/sdram.c +++ b/cpu/ppc4xx/sdram.c @@ -1,5 +1,5 @@ /* - * (C) Copyright 2005-2006 + * (C) Copyright 2005-2007 * Stefan Roese, DENX Software Engineering, sr@denx.de. * * (C) Copyright 2006 @@ -32,9 +32,9 @@ #include <asm/processor.h> #include "sdram.h" - #ifdef CONFIG_SDRAM_BANK0 +#ifndef CONFIG_440 #ifndef CFG_SDRAM_TABLE sdram_conf_t mb0cf[] = { @@ -50,9 +50,6 @@ sdram_conf_t mb0cf[] = CFG_SDRAM_TABLE; #define N_MB0CF (sizeof(mb0cf) / sizeof(mb0cf[0])) - -#ifndef CONFIG_440 - #ifdef CFG_SDRAM_CASL static ulong ns2clks(ulong ns) { @@ -221,6 +218,26 @@ void sdram_init(void) #else /* CONFIG_440 */ +/* + * Define some default values. Those can be overwritten in the + * board config file. + */ + +#ifndef CFG_SDRAM_TABLE +sdram_conf_t mb0cf[] = { + {(256 << 20), 13, 0x000C4001}, /* 256MB mode 3, 13x10(4) */ + {(64 << 20), 12, 0x00082001} /* 64MB mode 2, 12x9(4) */ +}; +#else +sdram_conf_t mb0cf[] = CFG_SDRAM_TABLE; +#endif + +#ifndef CFG_SDRAM0_TR0 +#define CFG_SDRAM0_TR0 0x41094012 +#endif + +#define N_MB0CF (sizeof(mb0cf) / sizeof(mb0cf[0])) + #define NUM_TRIES 64 #define NUM_READS 10 @@ -295,7 +312,6 @@ static void sdram_tr1_set(int ram_address, int* tr1_value) *tr1_value = (first_good + last_bad) / 2; } - #ifdef CONFIG_SDRAM_ECC static void ecc_init(ulong start, ulong size) { @@ -351,6 +367,15 @@ long int initdram(int board_type) int i; int tr1_bank1; +#if defined(CONFIG_440GX) || defined(CONFIG_440EP) || \ + defined(CONFIG_440GR) || defined(CONFIG_440SP) + /* + * Soft-reset SDRAM controller. + */ + mtsdr(sdr_srst, SDR0_SRST_DMC); + mtsdr(sdr_srst, 0x00000000); +#endif + for (i=0; i<N_MB0CF; i++) { /* * Disable memory controller. @@ -370,9 +395,9 @@ long int initdram(int board_type) * Following for CAS Latency = 2.5 @ 133 MHz PLB */ mtsdram(mem_b0cr, mb0cf[i].reg); - mtsdram(mem_tr0, 0x41094012); + mtsdram(mem_tr0, CFG_SDRAM0_TR0); mtsdram(mem_tr1, 0x80800800); /* SS=T2 SL=STAGE 3 CD=1 CT=0x00*/ - mtsdram(mem_rtr, 0x7e000000); /* Interval 15.20µs @ 133MHz PLB*/ + mtsdram(mem_rtr, 0x04100000); /* Interval 7.8µs @ 133MHz PLB */ mtsdram(mem_cfg1, 0x00000000); /* Self-refresh exit, disable PM*/ udelay(400); /* Delay 200 usecs (min) */ diff --git a/cpu/ppc4xx/serial.c b/cpu/ppc4xx/serial.c index fab0d95..e62dd9d 100644 --- a/cpu/ppc4xx/serial.c +++ b/cpu/ppc4xx/serial.c @@ -264,7 +264,8 @@ int serial_tstc () #endif /* CONFIG_IOP480 */ /*****************************************************************************/ -#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || defined(CONFIG_405EP) || \ +#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \ + defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \ defined(CONFIG_440) #if defined(CONFIG_440) @@ -309,7 +310,7 @@ int serial_tstc () #define MFREG(a, d) mfsdr(a, d) #define MTREG(a, d) mtsdr(a, d) #endif /* #if defined(CONFIG_440GP) */ -#elif defined(CONFIG_405EP) +#elif defined(CONFIG_405EP) || defined(CONFIG_405EZ) #define UART0_BASE 0xef600300 #define UART1_BASE 0xef600400 #define UCR0_MASK 0x0000007f @@ -392,47 +393,95 @@ volatile static serial_buffer_t buf_info; #if defined(CONFIG_440) && !defined(CFG_EXT_SERIAL_CLOCK) static void serial_divs (int baudrate, unsigned long *pudiv, - unsigned short *pbdiv ) + unsigned short *pbdiv) { - sys_info_t sysinfo; + sys_info_t sysinfo; unsigned long div; /* total divisor udiv * bdiv */ unsigned long umin; /* minimum udiv */ - unsigned short diff; /* smallest diff */ - unsigned long udiv; /* best udiv */ - - unsigned short idiff; /* current diff */ - unsigned short ibdiv; /* current bdiv */ + unsigned short diff; /* smallest diff */ + unsigned long udiv; /* best udiv */ + unsigned short idiff; /* current diff */ + unsigned short ibdiv; /* current bdiv */ unsigned long i; - unsigned long est; /* current estimate */ + unsigned long est; /* current estimate */ - get_sys_info( &sysinfo ); + get_sys_info(&sysinfo); - udiv = 32; /* Assume lowest possible serial clk */ - div = sysinfo.freqPLB/(16*baudrate); /* total divisor */ - umin = sysinfo.pllOpbDiv<<1; /* 2 x OPB divisor */ - diff = 32; /* highest possible */ + udiv = 32; /* Assume lowest possible serial clk */ + div = sysinfo.freqPLB / (16 * baudrate); /* total divisor */ + umin = sysinfo.pllOpbDiv << 1; /* 2 x OPB divisor */ + diff = 32; /* highest possible */ /* i is the test udiv value -- start with the largest * possible (32) to minimize serial clock and constrain * search to umin. */ - for( i = 32; i > umin; i-- ){ - ibdiv = div/i; + for (i = 32; i > umin; i--) { + ibdiv = div / i; est = i * ibdiv; idiff = (est > div) ? (est-div) : (div-est); - if( idiff == 0 ){ + if (idiff == 0) { udiv = i; break; /* can't do better */ - } - else if( idiff < diff ){ + } else if (idiff < diff) { udiv = i; /* best so far */ diff = idiff; /* update lowest diff*/ } } *pudiv = udiv; - *pbdiv = div/udiv; + *pbdiv = div / udiv; +} + +#elif defined(CONFIG_405EZ) + +static void serial_divs (int baudrate, unsigned long *pudiv, + unsigned short *pbdiv) +{ + sys_info_t sysinfo; + unsigned long div; /* total divisor udiv * bdiv */ + unsigned long umin; /* minimum udiv */ + unsigned short diff; /* smallest diff */ + unsigned long udiv; /* best udiv */ + unsigned short idiff; /* current diff */ + unsigned short ibdiv; /* current bdiv */ + unsigned long i; + unsigned long est; /* current estimate */ + unsigned long plloutb; + u32 reg; + + get_sys_info(&sysinfo); + plloutb = ((CONFIG_SYS_CLK_FREQ * sysinfo.pllFwdDiv * sysinfo.pllFbkDiv) + / sysinfo.pllFwdDivB); + udiv = 256; /* Assume lowest possible serial clk */ + div = plloutb / (16 * baudrate); /* total divisor */ + umin = (plloutb / get_OPB_freq()) << 1; /* 2 x OPB divisor */ + diff = 256; /* highest possible */ + + /* i is the test udiv value -- start with the largest + * possible (256) to minimize serial clock and constrain + * search to umin. + */ + for (i = 256; i > umin; i--) { + ibdiv = div / i; + est = i * ibdiv; + idiff = (est > div) ? (est-div) : (div-est); + if (idiff == 0) { + udiv = i; + break; /* can't do better */ + } else if (idiff < diff) { + udiv = i; /* best so far */ + diff = idiff; /* update lowest diff*/ + } + } + + *pudiv = udiv; + mfcpr(cprperd0, reg); + reg &= ~0x0000ffff; + reg |= ((udiv - 0) << 8) | (udiv - 0); + mtcpr(cprperd0, reg); + *pbdiv = div / udiv; } #endif /* defined(CONFIG_440) && !defined(CFG_EXT_SERIAL_CLK) */ @@ -518,6 +567,10 @@ int serial_init (void) unsigned short bdiv; volatile char val; +#if defined(CONFIG_405EZ) + serial_divs(gd->baudrate, &udiv, &bdiv); + clk = tmp = reg = 0; +#else #ifdef CONFIG_405EP reg = mfdcr(cpc0_ucr) & ~(UCR0_MASK | UCR1_MASK); clk = gd->cpu_clk; @@ -548,9 +601,9 @@ int serial_init (void) reg |= (udiv - 1) << CR0_UDIV_POS; /* set the UART divisor */ mtdcr (cntrl0, reg); #endif /* CONFIG_405EP */ - tmp = gd->baudrate * udiv * 16; bdiv = (clk + tmp / 2) / tmp; +#endif /* CONFIG_405EZ */ out8(UART_BASE + UART_LCR, 0x80); /* set DLAB bit */ out8(UART_BASE + UART_DLL, bdiv); /* set baudrate divisor */ diff --git a/cpu/ppc4xx/speed.c b/cpu/ppc4xx/speed.c index 2d16a83..028b11a 100644 --- a/cpu/ppc4xx/speed.c +++ b/cpu/ppc4xx/speed.c @@ -331,7 +331,7 @@ void get_sys_info (sys_info_t * sysInfo) unsigned long m; unsigned long prbdv0; -#if defined(CONFIG_440SPE) +#if defined(CONFIG_YUCCA) unsigned long sys_freq; unsigned long sys_per=0; unsigned long msr; @@ -348,7 +348,7 @@ void get_sys_info (sys_info_t * sysInfo) /*-------------------------------------------------------------------------+ | Calculate the system clock speed from the period. +-------------------------------------------------------------------------*/ - sys_freq=(ONE_BILLION/sys_per)*1000; + sys_freq = (ONE_BILLION / sys_per) * 1000; #endif /* Extract configured divisors */ @@ -385,17 +385,17 @@ void get_sys_info (sys_info_t * sysInfo) m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB; /* Now calculate the individual clocks */ -#if defined(CONFIG_440SPE) +#if defined(CONFIG_YUCCA) sysInfo->freqVCOMhz = (m * sys_freq) ; #else - sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m>>1); + sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m >> 1); #endif sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA; sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB/prbdv0; sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv; sysInfo->freqEPB = sysInfo->freqOPB/sysInfo->pllExtBusDiv; -#if defined(CONFIG_440SPE) +#if defined(CONFIG_YUCCA) /* Determine PCI Clock Period */ pci_clock_per = determine_pci_clock_per(); sysInfo->freqPCI = (ONE_BILLION/pci_clock_per) * 1000; @@ -408,7 +408,7 @@ void get_sys_info (sys_info_t * sysInfo) #endif -#if defined(CONFIG_440SPE) +#if defined(CONFIG_YUCCA) unsigned long determine_sysper(void) { unsigned int fpga_clocking_reg; @@ -583,7 +583,6 @@ unsigned long determine_sysper(void) } return(sys_per); - } /*-------------------------------------------------------------------------+ @@ -768,11 +767,119 @@ ulong get_PCI_freq (void) return val; } +#elif defined(CONFIG_405EZ) +void get_sys_info (PPC405_SYS_INFO * sysInfo) +{ + unsigned long cpr_plld; + unsigned long cpr_primad; + unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ/1000); + unsigned long primad_cpudv; + unsigned long m; + + /* + * Read PLL Mode registers + */ + mfcpr(cprplld, cpr_plld); + + /* + * Determine forward divider A + */ + sysInfo->pllFwdDiv = ((cpr_plld & PLLD_FWDVA_MASK) >> 16); + + /* + * Determine forward divider B (should be equal to A) + */ + sysInfo->pllFwdDivB = ((cpr_plld & PLLD_FWDVB_MASK) >> 8); + if (sysInfo->pllFwdDivB == 0) { + sysInfo->pllFwdDivB = 8; + } + + /* + * Determine FBK_DIV. + */ + sysInfo->pllFbkDiv = ((cpr_plld & PLLD_FBDV_MASK) >> 24); + if (sysInfo->pllFbkDiv == 0) { + sysInfo->pllFbkDiv = 256; + } + + /* + * Read CPR_PRIMAD register + */ + mfcpr(cprprimad, cpr_primad); + /* + * Determine PLB_DIV. + */ + sysInfo->pllPlbDiv = ((cpr_primad & PRIMAD_PLBDV_MASK) >> 16); + if (sysInfo->pllPlbDiv == 0) { + sysInfo->pllPlbDiv = 16; + } + + /* + * Determine EXTBUS_DIV. + */ + sysInfo->pllExtBusDiv = (cpr_primad & PRIMAD_EBCDV_MASK); + if (sysInfo->pllExtBusDiv == 0) { + sysInfo->pllExtBusDiv = 16; + } + + /* + * Determine OPB_DIV. + */ + sysInfo->pllOpbDiv = ((cpr_primad & PRIMAD_OPBDV_MASK) >> 8); + if (sysInfo->pllOpbDiv == 0) { + sysInfo->pllOpbDiv = 16; + } + + /* + * Determine the M factor + */ + m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB; + + /* + * Determine VCO clock frequency + */ + sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) / + (unsigned long long)sysClkPeriodPs; + + /* + * Determine CPU clock frequency + */ + primad_cpudv = ((cpr_primad & PRIMAD_CPUDV_MASK) >> 24); + if (primad_cpudv == 0) { + primad_cpudv = 16; + } + + sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) / primad_cpudv; + + /* + * Determine PLB clock frequency + */ + sysInfo->freqPLB = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) / sysInfo->pllPlbDiv; +} + +/******************************************** + * get_OPB_freq + * return OPB bus freq in Hz + *********************************************/ +ulong get_OPB_freq (void) +{ + ulong val = 0; + + PPC405_SYS_INFO sys_info; + + get_sys_info (&sys_info); + val = (CONFIG_SYS_CLK_FREQ * sys_info.pllFbkDiv) / sys_info.pllOpbDiv; + + return val; +} + #endif int get_clocks (void) { -#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || defined(CONFIG_440) || defined(CONFIG_405) || defined(CONFIG_405EP) +#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \ + defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \ + defined(CONFIG_440) || defined(CONFIG_405) sys_info_t sys_info; get_sys_info (&sys_info); @@ -797,7 +904,9 @@ ulong get_bus_freq (ulong dummy) { ulong val; -#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || defined(CONFIG_405) || defined(CONFIG_440) || defined(CONFIG_405EP) +#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \ + defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \ + defined(CONFIG_440) || defined(CONFIG_405) sys_info_t sys_info; get_sys_info (&sys_info); diff --git a/cpu/ppc4xx/start.S b/cpu/ppc4xx/start.S index 8e000d3..d918b3e 100644 --- a/cpu/ppc4xx/start.S +++ b/cpu/ppc4xx/start.S @@ -699,7 +699,9 @@ _start: #endif /* CONFIG_IOP480 */ /*****************************************************************************/ -#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || defined(CONFIG_405) || defined(CONFIG_405EP) +#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \ + defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \ + defined(CONFIG_405) /*----------------------------------------------------------------------- */ /* Clear and set up some registers. */ /*----------------------------------------------------------------------- */ @@ -727,13 +729,13 @@ _start: /*----------------------------------------------------------------------- */ /* Enable two 128MB cachable regions. */ /*----------------------------------------------------------------------- */ - addis r4,r0,0x8000 - addi r4,r4,0x0001 + lis r4,0x8000 + ori r4,r4,0x0001 mticcr r4 /* instruction cache */ isync - addis r4,r0,0x0000 - addi r4,r4,0x0000 + lis r4,0x0000 + ori r4,r4,0x0000 mtdccr r4 /* data cache */ #if !(defined(CFG_EBC_PB0AP) && defined(CFG_EBC_PB0CR)) @@ -755,6 +757,70 @@ _start: #endif /* CONFIG_405EP */ #if defined(CFG_OCM_DATA_ADDR) && defined(CFG_OCM_DATA_SIZE) +/* test-only... (clean up later when NAND booting is supported) */ +#if defined(CONFIG_405EZ) + /******************************************************************** + * Setup OCM - On Chip Memory - PPC405EZ uses OCM Controller V2 + *******************************************************************/ + /* + * We can map the OCM on the PLB3, so map it at + * CFG_OCM_DATA_ADDR + 0x8000 + */ + lis r3,CFG_OCM_DATA_ADDR@h /* OCM location */ + ori r3,r3,CFG_OCM_DATA_ADDR@l + ori r3,r3,0x8270 /* 32K Offset, 16K for Bank 1, R/W/Enable */ + mtdcr ocmplb3cr1,r3 /* Set PLB Access */ + ori r3,r3,0x4000 /* Add 0x4000 for bank 2 */ + mtdcr ocmplb3cr2,r3 /* Set PLB Access */ + isync + + lis r3,CFG_OCM_DATA_ADDR@h /* OCM location */ + ori r3,r3,CFG_OCM_DATA_ADDR@l + ori r3,r3,0x0270 /* 16K for Bank 1, R/W/Enable */ + mtdcr ocmdscr1, r3 /* Set Data Side */ + mtdcr ocmiscr1, r3 /* Set Instruction Side */ + ori r3,r3,0x4000 /* Add 0x4000 for bank 2 */ + mtdcr ocmdscr2, r3 /* Set Data Side */ + mtdcr ocmiscr2, r3 /* Set Instruction Side */ + addis r3,0,0x0800 /* OCM Data Parity Disable - 1 Wait State */ + mtdcr ocmdsisdpc,r4 + + isync + +#if defined(CONFIG_NAND_SPL) + /* + * 405EZ can boot from NAND Flash. + * If we are booting the SPL (Pre-loader), copy code from + * the mapped 4K NAND Flash to the OCM + */ + li r4,(CFG_NAND_BOOT_SPL_SIZE >> 2) - 1 + mtctr r4 + lis r2,CFG_NAND_BOOT_SPL_SRC@h + ori r2,r2,CFG_NAND_BOOT_SPL_SRC@l + lis r3,CFG_NAND_BOOT_SPL_DST@h + ori r3,r3,CFG_NAND_BOOT_SPL_DST@l +spl_loop: + lwzu r4,4(r2) + stwu r4,4(r3) + bdnz spl_loop + + /* + * Jump to code in OCM Ram + */ + bl 00f +00: mflr r10 + lis r3,(CFG_NAND_BOOT_SPL_SRC - CFG_NAND_BOOT_SPL_DST)@h + ori r3,r3,(CFG_NAND_BOOT_SPL_SRC - CFG_NAND_BOOT_SPL_DST)@l + sub r10,r10,r3 + addi r10,r10,28 + mtlr r10 + blr +start_ram: + sync + isync +#endif +#else +/* ...test-only */ /******************************************************************** * Setup OCM - On Chip Memory *******************************************************************/ @@ -774,6 +840,7 @@ _start: addis r4, 0, 0xC000 /* OCM data area enabled */ mtdcr ocmdscntl, r4 isync +#endif /* CONFIG_405EZ */ #endif /*----------------------------------------------------------------------- */ @@ -1361,7 +1428,7 @@ ppcSync: relocate_code: #if defined(CONFIG_440EP) || defined(CONFIG_440GR) || \ defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \ - defined(CONFIG_440SPE) + defined(CONFIG_440SP) || defined(CONFIG_440SPE) /* * On some 440er platforms the cache is enabled in the first TLB (Boot-CS) * to speed up the boot process. Now this cache needs to be disabled. @@ -1856,3 +1923,103 @@ pll_wait: /* execution will continue from the poweron */ /* vector of 0xfffffffc */ #endif /* CONFIG_405EP */ + +#if defined(CONFIG_440) +#define function_prolog(func_name) .text; \ + .align 2; \ + .globl func_name; \ + func_name: +#define function_epilog(func_name) .type func_name,@function; \ + .size func_name,.-func_name + +/*----------------------------------------------------------------------------+ +| mttlb3. ++----------------------------------------------------------------------------*/ + function_prolog(mttlb3) + TLBWE(4,3,2) + blr + function_epilog(mttlb3) + +/*----------------------------------------------------------------------------+ +| mftlb3. ++----------------------------------------------------------------------------*/ + function_prolog(mftlb3) + TLBRE(3,3,2) + blr + function_epilog(mftlb3) + +/*----------------------------------------------------------------------------+ +| mttlb2. ++----------------------------------------------------------------------------*/ + function_prolog(mttlb2) + TLBWE(4,3,1) + blr + function_epilog(mttlb2) + +/*----------------------------------------------------------------------------+ +| mftlb2. ++----------------------------------------------------------------------------*/ + function_prolog(mftlb2) + TLBRE(3,3,1) + blr + function_epilog(mftlb2) + +/*----------------------------------------------------------------------------+ +| mttlb1. ++----------------------------------------------------------------------------*/ + function_prolog(mttlb1) + TLBWE(4,3,0) + blr + function_epilog(mttlb1) + +/*----------------------------------------------------------------------------+ +| mftlb1. ++----------------------------------------------------------------------------*/ + function_prolog(mftlb1) + TLBRE(3,3,0) + blr + function_epilog(mftlb1) + +/*----------------------------------------------------------------------------+ +| dcbz_area. ++----------------------------------------------------------------------------*/ + function_prolog(dcbz_area) + rlwinm. r5,r4,0,27,31 + rlwinm r5,r4,27,5,31 + beq ..d_ra2 + addi r5,r5,0x0001 +..d_ra2:mtctr r5 +..d_ag2:dcbz r0,r3 + addi r3,r3,32 + bdnz ..d_ag2 + sync + blr + function_epilog(dcbz_area) + +/*----------------------------------------------------------------------------+ +| dflush. Assume 32K at vector address is cachable. ++----------------------------------------------------------------------------*/ + function_prolog(dflush) + mfmsr r9 + rlwinm r8,r9,0,15,13 + rlwinm r8,r8,0,17,15 + mtmsr r8 + addi r3,r0,0x0000 + mtspr dvlim,r3 + mfspr r3,ivpr + addi r4,r0,1024 + mtctr r4 +..dflush_loop: + lwz r6,0x0(r3) + addi r3,r3,32 + bdnz ..dflush_loop + addi r3,r3,-32 + mtctr r4 +..ag: dcbf r0,r3 + addi r3,r3,-32 + bdnz ..ag + sync + mtmsr r9 + blr + function_epilog(dflush) +#endif /* CONFIG_440 */ diff --git a/cpu/ppc4xx/tlb.c b/cpu/ppc4xx/tlb.c new file mode 100644 index 0000000..50344a4 --- /dev/null +++ b/cpu/ppc4xx/tlb.c @@ -0,0 +1,184 @@ +/* + * (C) Copyright 2007 + * Stefan Roese, DENX Software Engineering, sr@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> + +#if defined(CONFIG_440) + +#include <ppc4xx.h> +#include <ppc440.h> +#include <asm/io.h> +#include <asm/mmu.h> + +typedef struct region { + unsigned long base; + unsigned long size; + unsigned long tlb_word2_i_value; +} region_t; + +static int add_tlb_entry(unsigned long base_addr, + unsigned long tlb_word0_size_value, + unsigned long tlb_word2_i_value) +{ + int i; + unsigned long tlb_word0_value; + unsigned long tlb_word1_value; + unsigned long tlb_word2_value; + + /* First, find the index of a TLB entry not being used */ + for (i=0; i<PPC4XX_TLB_SIZE; i++) { + tlb_word0_value = mftlb1(i); + if ((tlb_word0_value & TLB_WORD0_V_MASK) == TLB_WORD0_V_DISABLE) + break; + } + if (i >= PPC4XX_TLB_SIZE) + return -1; + + /* Second, create the TLB entry */ + tlb_word0_value = TLB_WORD0_EPN_ENCODE(base_addr) | TLB_WORD0_V_ENABLE | + TLB_WORD0_TS_0 | tlb_word0_size_value; + tlb_word1_value = TLB_WORD1_RPN_ENCODE(base_addr) | TLB_WORD1_ERPN_ENCODE(0); + tlb_word2_value = TLB_WORD2_U0_DISABLE | TLB_WORD2_U1_DISABLE | + TLB_WORD2_U2_DISABLE | TLB_WORD2_U3_DISABLE | + TLB_WORD2_W_DISABLE | tlb_word2_i_value | + TLB_WORD2_M_DISABLE | TLB_WORD2_G_DISABLE | + TLB_WORD2_E_DISABLE | TLB_WORD2_UX_ENABLE | + TLB_WORD2_UW_ENABLE | TLB_WORD2_UR_ENABLE | + TLB_WORD2_SX_ENABLE | TLB_WORD2_SW_ENABLE | + TLB_WORD2_SR_ENABLE; + + /* Wait for all memory accesses to complete */ + sync(); + + /* Third, add the TLB entries */ + mttlb1(i, tlb_word0_value); + mttlb2(i, tlb_word1_value); + mttlb3(i, tlb_word2_value); + + /* Execute an ISYNC instruction so that the new TLB entry takes effect */ + asm("isync"); + + return 0; +} + +static void program_tlb_addr(unsigned long base_addr, unsigned long mem_size, + unsigned long tlb_word2_i_value) +{ + int rc; + int tlb_i; + + tlb_i = tlb_word2_i_value; + while (mem_size != 0) { + rc = 0; + /* Add the TLB entries in to map the region. */ + if (((base_addr & TLB_256MB_ALIGN_MASK) == base_addr) && + (mem_size >= TLB_256MB_SIZE)) { + /* Add a 256MB TLB entry */ + if ((rc = add_tlb_entry(base_addr, TLB_WORD0_SIZE_256MB, tlb_i)) == 0) { + mem_size -= TLB_256MB_SIZE; + base_addr += TLB_256MB_SIZE; + } + } else if (((base_addr & TLB_16MB_ALIGN_MASK) == base_addr) && + (mem_size >= TLB_16MB_SIZE)) { + /* Add a 16MB TLB entry */ + if ((rc = add_tlb_entry(base_addr, TLB_WORD0_SIZE_16MB, tlb_i)) == 0) { + mem_size -= TLB_16MB_SIZE; + base_addr += TLB_16MB_SIZE; + } + } else if (((base_addr & TLB_1MB_ALIGN_MASK) == base_addr) && + (mem_size >= TLB_1MB_SIZE)) { + /* Add a 1MB TLB entry */ + if ((rc = add_tlb_entry(base_addr, TLB_WORD0_SIZE_1MB, tlb_i)) == 0) { + mem_size -= TLB_1MB_SIZE; + base_addr += TLB_1MB_SIZE; + } + } else if (((base_addr & TLB_256KB_ALIGN_MASK) == base_addr) && + (mem_size >= TLB_256KB_SIZE)) { + /* Add a 256KB TLB entry */ + if ((rc = add_tlb_entry(base_addr, TLB_WORD0_SIZE_256KB, tlb_i)) == 0) { + mem_size -= TLB_256KB_SIZE; + base_addr += TLB_256KB_SIZE; + } + } else if (((base_addr & TLB_64KB_ALIGN_MASK) == base_addr) && + (mem_size >= TLB_64KB_SIZE)) { + /* Add a 64KB TLB entry */ + if ((rc = add_tlb_entry(base_addr, TLB_WORD0_SIZE_64KB, tlb_i)) == 0) { + mem_size -= TLB_64KB_SIZE; + base_addr += TLB_64KB_SIZE; + } + } else if (((base_addr & TLB_16KB_ALIGN_MASK) == base_addr) && + (mem_size >= TLB_16KB_SIZE)) { + /* Add a 16KB TLB entry */ + if ((rc = add_tlb_entry(base_addr, TLB_WORD0_SIZE_16KB, tlb_i)) == 0) { + mem_size -= TLB_16KB_SIZE; + base_addr += TLB_16KB_SIZE; + } + } else if (((base_addr & TLB_4KB_ALIGN_MASK) == base_addr) && + (mem_size >= TLB_4KB_SIZE)) { + /* Add a 4KB TLB entry */ + if ((rc = add_tlb_entry(base_addr, TLB_WORD0_SIZE_4KB, tlb_i)) == 0) { + mem_size -= TLB_4KB_SIZE; + base_addr += TLB_4KB_SIZE; + } + } else if (((base_addr & TLB_1KB_ALIGN_MASK) == base_addr) && + (mem_size >= TLB_1KB_SIZE)) { + /* Add a 1KB TLB entry */ + if ((rc = add_tlb_entry(base_addr, TLB_WORD0_SIZE_1KB, tlb_i)) == 0) { + mem_size -= TLB_1KB_SIZE; + base_addr += TLB_1KB_SIZE; + } + } else { + printf("ERROR: no TLB size exists for the base address 0x%0X.\n", + base_addr); + } + + if (rc != 0) + printf("ERROR: no TLB entries available for the base addr 0x%0X.\n", + base_addr); + } + + return; +} + +/* + * Program one (or multiple) TLB entries for one memory region + * + * Common usage for boards with SDRAM DIMM modules to dynamically + * configure the TLB's for the SDRAM + */ +void program_tlb(u32 start, u32 size, u32 tlb_word2_i_value) +{ + region_t region_array; + + region_array.base = start; + region_array.size = size; + region_array.tlb_word2_i_value = tlb_word2_i_value; /* en-/disable cache */ + + /* Call the routine to add in the tlb entries for the memory regions */ + program_tlb_addr(region_array.base, region_array.size, + region_array.tlb_word2_i_value); + + return; +} + +#endif /* CONFIG_440 */ diff --git a/cpu/ppc4xx/usb_ohci.c b/cpu/ppc4xx/usb_ohci.c index ab852c5..c71a6a9 100644 --- a/cpu/ppc4xx/usb_ohci.c +++ b/cpu/ppc4xx/usb_ohci.c @@ -76,7 +76,7 @@ #define m16_swap(x) swap_16(x) #define m32_swap(x) swap_32(x) -#if defined(CONFIG_440EP) || defined(CONFIG_440EPX) +#if defined(CONFIG_405EZ) || defined(CONFIG_440EP) || defined(CONFIG_440EPX) #define ohci_cpu_to_le16(x) (x) #define ohci_cpu_to_le32(x) (x) #else @@ -1601,7 +1601,7 @@ int usb_lowlevel_init(void) gohci.irq = -1; #if defined(CONFIG_440EP) gohci.regs = (struct ohci_regs *)(CFG_PERIPHERAL_BASE | 0x1000); -#elif defined(CONFIG_440EPX) +#elif defined(CONFIG_440EPX) || defined(CFG_USB_HOST) gohci.regs = (struct ohci_regs *)(CFG_USB_HOST); #endif @@ -1625,8 +1625,10 @@ int usb_lowlevel_init(void) ohci_inited = 1; urb_finished = 1; +#if defined(CONFIG_440EP) || defined(CONFIG_440EPX) /* init the device driver */ usb_dev_init(); +#endif return 0; } diff --git a/cpu/ppc4xx/vecnum.h b/cpu/ppc4xx/vecnum.h index 685d48b..bddf9e5 100644 --- a/cpu/ppc4xx/vecnum.h +++ b/cpu/ppc4xx/vecnum.h @@ -231,6 +231,47 @@ #else /* !defined(CONFIG_440) */ +#if defined(CONFIG_405EZ) +#define VECNUM_D0 0 /* DMA channel 0 */ +#define VECNUM_D1 1 /* DMA channel 1 */ +#define VECNUM_D2 2 /* DMA channel 2 */ +#define VECNUM_D3 3 /* DMA channel 3 */ +#define VECNUM_1588 4 /* IEEE 1588 network synchronization */ +#define VECNUM_U0 5 /* UART0 */ +#define VECNUM_U1 6 /* UART1 */ +#define VECNUM_CAN0 7 /* CAN 0 */ +#define VECNUM_CAN1 8 /* CAN 1 */ +#define VECNUM_SPI 9 /* SPI */ +#define VECNUM_IIC0 10 /* I2C */ +#define VECNUM_CHT0 11 /* Chameleon timer high pri interrupt */ +#define VECNUM_CHT1 12 /* Chameleon timer high pri interrupt */ +#define VECNUM_USBH1 13 /* USB Host 1 */ +#define VECNUM_USBH2 14 /* USB Host 2 */ +#define VECNUM_USBDEV 15 /* USB Device */ +#define VECNUM_ETH0 16 /* 10/100 Ethernet interrupt status */ +#define VECNUM_EWU0 17 /* Ethernet wakeup sequence detected */ + +#define VECNUM_MADMAL 18 /* Logical OR of following MadMAL int */ +#define VECNUM_MS 18 /* MAL_SERR_INT */ +#define VECNUM_TXDE 18 /* MAL_TXDE_INT */ +#define VECNUM_RXDE 18 /* MAL_RXDE_INT */ + +#define VECNUM_MTE 19 /* MAL TXEOB */ +#define VECNUM_MTE1 20 /* MAL TXEOB1 */ +#define VECNUM_MRE 21 /* MAL RXEOB */ +#define VECNUM_NAND 22 /* NAND Flash controller */ +#define VECNUM_ADC 23 /* ADC */ +#define VECNUM_DAC 24 /* DAC */ +#define VECNUM_OPB2PLB 25 /* OPB to PLB bridge interrupt */ +#define VECNUM_RESERVED0 26 /* Reserved */ +#define VECNUM_EIR0 27 /* External interrupt 0 */ +#define VECNUM_EIR1 28 /* External interrupt 1 */ +#define VECNUM_EIR2 29 /* External interrupt 2 */ +#define VECNUM_EIR3 30 /* External interrupt 3 */ +#define VECNUM_EIR4 31 /* External interrupt 4 */ + +#else /* !CONFIG_405EZ */ + #define VECNUM_U0 0 /* UART0 */ #define VECNUM_U1 1 /* UART1 */ #define VECNUM_D0 5 /* DMA channel 0 */ @@ -251,6 +292,7 @@ #define VECNUM_EIR4 29 /* External interrupt 4 */ #define VECNUM_EIR5 30 /* External interrupt 5 */ #define VECNUM_EIR6 31 /* External interrupt 6 */ +#endif /* defined(CONFIG_405EZ) */ #endif /* defined(CONFIG_440) */ diff --git a/cpu/pxa/mmc.c b/cpu/pxa/mmc.c index f7020ee..0fbaa16 100644 --- a/cpu/pxa/mmc.c +++ b/cpu/pxa/mmc.c @@ -37,7 +37,7 @@ static block_dev_desc_t mmc_dev; block_dev_desc_t * mmc_get_dev(int dev) { - return ((block_dev_desc_t *)&mmc_dev); + return (dev == 0) ? &mmc_dev : NULL; } /* @@ -363,7 +363,7 @@ mmc_write(uchar *src, ulong dst, int size) ulong /****************************************************/ -mmc_bread(int dev_num, ulong blknr, ulong blkcnt, ulong *dst) +mmc_bread(int dev_num, ulong blknr, ulong blkcnt, void *dst) /****************************************************/ { int mmc_block_size = MMC_BLOCK_SIZE; |