diff options
Diffstat (limited to 'cfe/cfe/arch/mips/board/bcm63xx_rom')
-rwxr-xr-x | cfe/cfe/arch/mips/board/bcm63xx_rom/src/Makefile | 23 | ||||
-rwxr-xr-x | cfe/cfe/arch/mips/board/bcm63xx_rom/src/bcm6368_rom_boot.S | 548 | ||||
-rwxr-xr-x | cfe/cfe/arch/mips/board/bcm63xx_rom/src/bcm6368_sdramDqs.c | 439 | ||||
-rwxr-xr-x | cfe/cfe/arch/mips/board/bcm63xx_rom/src/bcm63xx_impl1_rom_boot.S | 1818 | ||||
-rwxr-xr-x | cfe/cfe/arch/mips/board/bcm63xx_rom/src/bcm63xx_main.c | 649 | ||||
-rwxr-xr-x | cfe/cfe/arch/mips/board/bcm63xx_rom/src/memtest.c | 1031 | ||||
-rwxr-xr-x | cfe/cfe/arch/mips/board/bcm63xx_rom/src/rom_cfe.mk | 370 |
7 files changed, 4878 insertions, 0 deletions
diff --git a/cfe/cfe/arch/mips/board/bcm63xx_rom/src/Makefile b/cfe/cfe/arch/mips/board/bcm63xx_rom/src/Makefile new file mode 100755 index 0000000..808ddc2 --- /dev/null +++ b/cfe/cfe/arch/mips/board/bcm63xx_rom/src/Makefile @@ -0,0 +1,23 @@ +ifeq ($(strip ${CFG_BOARDNAME}),"BCM96328") +BSPOBJS += \ + bcm63xx_impl1_rom_boot.o +endif +ifeq ($(strip ${CFG_BOARDNAME}),"BCM96362") +BSPOBJS += \ + bcm63xx_impl1_rom_boot.o +endif +ifeq ($(strip ${CFG_BOARDNAME}),"BCM96368") +BSPOBJS += \ + bcm6368_rom_boot.o \ + bcm6368_sdramDqs.o +endif +ifeq ($(strip ${CFG_BOARDNAME}),"BCM96816") +BSPOBJS += \ + bcm63xx_impl1_rom_boot.o +endif +ifeq ($(strip ${INC_NAND_FLASH_DRIVER}),1) +BSPOBJS += \ + nandflash.o +endif +BSPOBJS += \ + bcm63xx_main.o diff --git a/cfe/cfe/arch/mips/board/bcm63xx_rom/src/bcm6368_rom_boot.S b/cfe/cfe/arch/mips/board/bcm63xx_rom/src/bcm6368_rom_boot.S new file mode 100755 index 0000000..f1cba19 --- /dev/null +++ b/cfe/cfe/arch/mips/board/bcm63xx_rom/src/bcm6368_rom_boot.S @@ -0,0 +1,548 @@ +#include "sbmips.h" +#include "bsp_config.h" + +#include "6368_cpu.h" +#include "6368_common.h" +#include "bcm_hwdefs.h" +#include "boardparms.h" +#include "mipsmacros.h" + +#define SETLEDS1(a,b,c,d) \ + li a0,(((a)<<24)|((b)<<16)|((c)<<8)|(d)) ; \ + bal board_setleds + +/* ********************************************************************* + * BOARD_EARLYINIT() + * + * Initialize board registers. This is the earliest + * time the BSP gets control. This routine cannot assume that + * memory is operational, and therefore all code in this routine + * must run from registers only. The $ra register must not + * be modified, as it contains the return address. + * + * This routine will be called from uncached space, before + * the caches are initialized. If you want to make + * subroutine calls from here, you must use the CALLKSEG1 macro. + * + * Among other things, this is where the GPIO registers get + * programmed to make on-board LEDs function, or other startup + * that has to be done before anything will work. + * + * Input parameters: + * a0 - Flash base address (address of MIPS reset) + * + * Return value: + * nothing + ********************************************************************* */ + +LEAF(board_earlyinit) + + .set noreorder + + mfc0 t1, C0_BCM_CONFIG, 3 + li t2, CP0_CMT_TPID + and t1, t2 + bnez t1, 2f # if we are running on thread 1, skip init + nop + +#if 0 + /* wait for a while to allow catch by jtag debugger */ + li t8, -(200000000*3) /* we will count up to 0 to delay a couple of seconds */ + /* and give the emulator a chance to catch us */ + mtc0 t8, C0_COUNT +catchloop: + bltz t8, catchloop + mfc0 t8, C0_COUNT +#endif + + /**--------------------------------------------------------------**/ + /** platform specific code **/ + /**--------------------------------------------------------------**/ + /**----- Enable I Cache -----------------------------------------**/ + mfc0 t1, C0_BCM_CONFIG + or t1, (CP0_BCM_CFG_ICSHEN | CP0_BCM_CFG_DCSHEN) + mtc0 t1, C0_BCM_CONFIG # Enable I Cache + + // In the begining MIPS core registers are mapped to 0xbfax_xxxx + li t1, 0x1FA0000C # Set up CBR to 1FAx_xxxx + mtc0 t1, C0_BCM_CONFIG, 6 + + li t1, MIPS_BASE_BOOT + lw t2, MIPS_LMB_CR(t1) + or t2, 0xC0000000 # enable ffxx_xxxx space + sw t2, MIPS_LMB_CR(t1) + li t2, 0xFFF80001 # SBR FFF8_xxxx and enable + sw t2, MIPS_SBR(t1) + + // Now map MIPS core registers to 0xFF4x_xxxx space + li t1, 0xFF40000C # CBR FF4x_xxxx (and reserved bits 0xc). + mtc0 t1, C0_BCM_CONFIG, 6 + + /**----- Initialize EBI -----------------------------------------**/ + li t1, MPI_BASE + li t2, EBI_SIZE_32M + or t2, a0 + sw t2, CS0BASE(t1) # CS[0] Base + li t2, THREEWT|EBI_WORD_WIDE|EBI_ENABLE + sw t2, CS0CNTL(t1) # CS[0] Control + + /**----- Initialize Serial --------------------------------------**/ + li t3, ((FPERIPH / 115200) / 16) + /* + # Baudword = (FPeriph)/Baud/32-1. We have to perform rounding + # and subtraction. Above we divided by 16 (instead of 32). If + # bit0 is set, we round up. However, we then subtract 1, so final + # result should be t3/2. If bit0 is 0, then we truncate and subtract + # 1, t3=t3/2-1. + */ + andi t0, t3, 0x1 + bne t0,zero,1f # do shift only (in delay slot) + # and jump to apply + srl t3,1 # do divide by 2 + addiu t3, -1 # subtract 1 +1: + + # t3 contains the UART BAUDWORD + li t0, UART_BASE + sw t3, UART0BAUD(t0) # Store BaudRate + li t1, BITS8SYM|ONESTOP + sb t1, UART0CONFIG(t0) # 8 Bits/1 Stop + li t1, TXEN|RXEN|BRGEN + sb t1, UART0CONTROL(t0) # Enable, No Parity + move t1, zero + sh t1, UART0INTMASK(t0) + + .set reorder +2: + j ra +END(board_earlyinit) + +/* ********************************************************************* + * BOARD_DRAMINFO + * + * Return the address of the DRAM information table + * + * Input parameters: + * nothing + * + * Return value: + * v0 - DRAM info table, return 0 to use default table + ********************************************************************* */ +LEAF(board_draminfo) + j ra +END(board_draminfo) + +/* ********************************************************************* + * BOARD_DRAMINIT + * + * This routine should activate memory. + * + * Input parameters: + * None + * + * Return value: + * None + * + * Registers used: + * can use all registers. + ********************************************************************* */ +LEAF(board_draminit) + .set noreorder + + li t0, MEMC_BASE + li t1, DDR_BASE + + li t4, (7 << 28) | (7 << 24) | (1 << 20) | (7 << 16) # UBUS_CNTR_CYCLES = 7, LLMB_CNTR_CYCLES = 7, PH_CNTR_EN = 1, PH_CNTR_CYCLES = 7 + sw t4, DDR_MIPS_PHASE_CNTL(t1) + + # Calculate a value for a 90 degree phase shift. + + lw t2, DDR_MIPSDDR_PLL_MDIV(t1) + srl t2, 8 # Shift and mask off DDR_MDIV + and t2, 0xff + sll t2, 2 # PI_steps = (90deg * 16 * MBUS(t2) + 2)/360 ~= MBUS * 4 + or t2, (1 << 14) # set the count direction + + lw t3, DDR_DDR3_4_PHASE_CNTL(t1) # Get current DDR3/4 value. + ori t3, 0x7fff # Clear low 15 bits (DDR3 value). + xori t3, 0x7fff + or t3, t2 # Set new DDR3 value, preserving existing DDR4 value. + sw t3, DDR_DDR3_4_PHASE_CNTL(t1) + + li t4, (1 << 28) | (7 << 24) | (1 << 23) | (1 << 20) | (7 << 16) # UBUS_CNTR_CYCLES = 1, LLMB_CNTR_CYCLES = 7, UBUS_CNTR_EN = 1, PH_CNTR_EN = 1, PH_CNTR_CYCLES = 7 + sw t4, DDR_MIPS_PHASE_CNTL(t1) + + li t4, 0x103e + sw t4, DDR_UBUS_PI_DSK1(t1) + li t4, 0x40000000 + sw t4, DDR_UBUS_PI_DSK0(t1) + + ## Set PI mask, and frequnecy of updates + # bit[5:0] 1 to 31, controls how often feedback is send back to PI + # bit[7] update register in sampling logic to take the new value in bit[5:0] + # bit[14:8] masking bits for the sampling result + + li t2, 0x00000010 # 0x8 for 8 DDR cycles, 0x10 for 16 DDR cycles, 0x4 for 4 DDR cycles, can take values from 1 to 31 + sw t2, DDR_UBUS_PI_DSK0(t1) # set PI update to 16 ddr cycles + li t2, 0x00000090 # update value + sw t2, DDR_UBUS_PI_DSK0(t1) + li t2, 0x00000c90 # set mask to 0001100; 0x1890 will set mask to 0011000 + sw t2, DDR_UBUS_PI_DSK0(t1) + + ###### Check to see if we found the edge... + ###### Ideally we want to loop here until we find an edge.... + + li t3, 0 + li t2, 10000 + +1: + # Looking for a rising edge. + lw t4, DDR_UBUS_PI_DSK0(t1) # Read a sample value. + srl t4, 16 # The sample is in the upper 16 bits. + andi t4, 0x41 # Look at the 2 outermost bits; if the LSB is 0 and the MSB is 1, + beq t4, 0x40, 2f # then there is an edge somewhere in the sample. + + addi t3, 1 + bne t2, t3, 1b + nop + +2: + + /**----- Configure DDR controller ------------------------------------**/ + li v0, 16 + li t2, ((MEMC_12BIT_ROW << MEMC_ROW_SHFT) | (MEMC_9BIT_COL << MEMC_COL_SHFT)) + or t2, (MEMC_16BIT_BUS << MEMC_WIDTH_SHFT) + or t2, (MEMC_SEL_PRIORITY) + or t2, (2 << MEMC_EARLY_HDR_CNT_SHFT) + or t2, (MEMC_USE_HDR_CNT) +// or t2, (MEMC_EN_FAST_REPLY) + or t2, (MEMC_RR_ARB) + or t2, (MEMC_DQS_GATE_EN | MEMC_MEMTYPE_DDR) + sw t2, MEMC_CONFIG(t0) # Enable DDR Mem & SEQ EN, 16MB + + li t2, 0x7 # Reduce drive strength for command pins (per John Lorek) + sw t2, DDR_CMD_PAD_CNTL(t1) + + li t2, 0x00A778DD + sw t2, MEMC_DRAM_TIM(t0) # DDR Timing Set Latency 2.5 Latency,tRAS period =7,tRFC period=12, tWR=3 + li t2, 0x00000003 + sw t2, MEMC_CONTROL(t0) # Turn on CKE + li t2, 0x0000000B + sw t2, MEMC_CONTROL(t0) # PreCharge + li t2, 0x00004002 + sw t2, MEMC_M_EM_BUF(t0) # Value for Extended Mode Register, DDR Reduced Drive Strength On + li t2, 0x00000013 + sw t2, MEMC_CONTROL(t0) # MRS command + li t2, 0x00000163 + sw t2, MEMC_M_EM_BUF(t0) # Reset DLL, Burst Length = 8, Burst Type Sequential 2.5 Latency + li t2, 0x00000013 + sw t2, MEMC_CONTROL(t0) # MRS command + nop # Delay 200 DDR clock cycles (~1.5 uS) + nop + nop + li t2, 0x0000000B + sw t2, MEMC_CONTROL(t0) # Precharge + li t2, 0x0000840f + sw t2, MEMC_REF_PD_CONTROL(t0) # Enable auto refresh + li t2, 0x00000007 + sw t2, MEMC_CONTROL(t0) # Set Auto Refresh Mode + li t2, 0x00000007 + sw t2, MEMC_CONTROL(t0) # Set Auto Refresh Mode + li t2, 0x00000063 + sw t2, MEMC_M_EM_BUF(t0) # Reset DLL, Burst Length = 8, Burst Type Sequential 2.5 Latency + li t2, 0x00000013 + sw t2, MEMC_CONTROL(t0) # MRS + + .set reorder + + li sp, 0x80001000 + sub sp, 8 + sw ra, 0(sp) + sw v0, 4(sp) + bal sdramDqsPhaseSet + lw v0, 4(sp) + lw ra, 0(sp) + add sp, 8 + + /**----- switch to sync -----------------------------------------**/ + li t0, 0xff410000 + li t1, DDR_BASE + li t2, 4048 + li t3, 1 + +1: + lw t4, 0x40(t0) # Read a sample value. + srl t4, 16 # The sample is in the upper 16 bits. + + andi t4, t4, 0x41 # Look at the 2 outermost bits; if the LSB is 0 and the MSB is 1, + beq t4, 0x40, 2f # then there is an edge somewhere in the sample. + + lw t5, DDR_MIPS_PHASE_CNTL(t1) + and t5, 0xffff0000 + or t5, t3 + or t5, (1<<14) + sw t5, DDR_MIPS_PHASE_CNTL(t1) + + lw t5, 0x40(t0) # Delay before reading another sample. + add t3, 1 + bne t2, t3, 1b + b 3f + +2: + # Success + lw t2, DDR_MIPS_PHASE_CNTL(t1) # Turn on auto-PI mode. + and t2, 0xf0ffffff + or t2, (1 << 24) | (1 << 21) # LLMB_CNTR_CYCLES_CNTL = 1, LLMB_CNTR_EN = 1 + sw t2, DDR_MIPS_PHASE_CNTL(t1) + + li t2, 0x0010 # Set PI mask to 0000110, and check new value every 16 MIPS cycles. + sw t2, 0x40(t0) # set PI update to 16 ddr cycles + li t2, 0x80000090 # Enable MIPS auto-PI | Enable update period | Set 16 clock update + sw t2, 0x40(t0) + li t2, 0x80000c90 # Enable MIPS auto-PI | Enable comparator | Enable update period | Set 16 clock update + sw t2, 0x40(t0) + + lw t2, 0x40(t0) # Do a few reads to wait till the edge is stable... + lw t2, 0x40(t0) + lw t2, 0x40(t0) + lw t2, 0x40(t0) + lw t2, 0x40(t0) + + mfc0 t1, C0_BCM_CONFIG, 5 + and t1, ~(0x1 << 28) + mtc0 t1, C0_BCM_CONFIG, 5 + + /**----- Enable RAC and LMB -------------------------------------**/ + li t1, MIPS_BASE + lw t2, MIPS_LMB_CR(t1) + or t2, LMB_EN # Enable LMB + sw t2, MIPS_LMB_CR(t1) + + li t2, 0xFFF << RAC_UPB_SHFT # Enable prefetch for RAM address range up to 256MB + sw t2, MIPS_RAC_ARR(t1) + + lw t2, MIPS_RAC_CR0(t1) + or t2, (RAC_C_INV | RAC_I | RAC_PF_I) + sw t2, MIPS_RAC_CR0(t1) + + lw t2, MIPS_RAC_CR1(t1) + or t2, (RAC_C_INV | RAC_I | RAC_PF_I) + sw t2, MIPS_RAC_CR1(t1) + +3: + /**----- Enable branch prediction and non-blocking data cache ---**/ + mfc0 t1, C0_BCM_CONFIG + and t1, ~CP0_BCM_CFG_BTHD + or t1, CP0_BCM_CFG_NBK + or t1, CP0_BCM_CFG_CLF + mtc0 t1, C0_BCM_CONFIG + + /* Test whether memory is 16 or 32 bit wide */ + li t0, MEMC_BASE + lw t2, MEMC_CONFIG(t0) + and t2, ~MEMC_WIDTH_MASK + or t2, (MEMC_32BIT_BUS << MEMC_WIDTH_SHFT) + sw t2, MEMC_CONFIG(t0) + + li t3, DRAM_BASE_NOCACHE + li t4, 0x12345678 + sw t4, 0(t3) + li t4, 0x87654321 + sw t4, 4(t3) + nop + nop + nop + nop + nop + nop + li t4, 0x12345678 + lw t5, 0(t3) + beq t4, t5, 4f + + /* 16 bit wide memory */ + lw t2, MEMC_CONFIG(t0) + and t2, ~MEMC_WIDTH_MASK + or t2, (MEMC_16BIT_BUS << MEMC_WIDTH_SHFT) + sw t2, MEMC_CONFIG(t0) +4: + j ra + +END(board_draminit) + +/* ********************************************************************* + * BOARD_SETLEDS(x) + * + * Set LEDs for boot-time progress indication. Not used if + * the board does not have progress LEDs. This routine + * must not call any other routines, since it may be invoked + * either from KSEG0 or KSEG1 and it may be invoked + * whether or not the icache is operational. + * + * Input parameters: + * a0 - LED value (8 bits per character, 4 characters) + * + * Return value: + * nothing + * + * Registers used: + * t0,t1,t2,t3 + ********************************************************************* */ +LEAF(board_setleds) +#if 0 + li t0, UART_BASE + li t2, TXFIFOEMT + +1: lh t1, UART0INTSTAT(t0) + and t1, t2 + bne t1, t2, 1b + + srl t3, a0, 24 + sb t3, UART0DATA(t0) + srl t3, a0, 16 + sb t3, UART0DATA(t0) + srl t3, a0, 8 + sb t3, UART0DATA(t0) + sb a0, UART0DATA(t0) + li a0, '\r' + sb a0, UART0DATA(t0) + li a0, '\n' + sb a0, UART0DATA(t0) +#endif + j ra +END(board_setleds) + +/* ********************************************************************* + * BCMCORE_TP1_SWITCH() + * + * Check if the thread switch is required. If we are already + * running on thread 1 this function will do nothing and just return + * If we are running on thread 0 this function will take thread 1 + * out of reset and put thread 0 to sleep waiting for singnal from + * thread 1. + * + * Input parameters: + * nothing + * + * Return value: + * nothing + ********************************************************************* */ +LEAF(bcmcore_tp1_switch) + + mfc0 t1, C0_BCM_CONFIG, 3 + li t2, CP0_CMT_TPID + and t1, t2 + bnez t1, tp1 # Already running on thread 1 + +# Start TP1 +# Set boot address for TP1 + li t1, MIPS_BASE + li t2, 0x98000000 | ENABLE_ALT_BV + sw t2, MIPS_TP1_ALT_BV(t1) + +# Set a flag so we can wait for TP1 to catch up + li t1, 0x0 + mtc0 t1, $31 # CO_DESAVE + +# Take TP1 out of reset + mfc0 t1, C0_BCM_CONFIG, 2 + or t1, CP0_CMT_RSTSE + mtc0 t1, C0_BCM_CONFIG, 2 + + /* wait until second thread catches up with the first */ +waittp1: + mfc0 t0, $31 # CO_DESAVE + beqz t0, waittp1 + + li t0, THREAD_NUM_ADDRESS + FIXUP(t0) + lw t0, 0(t0) + li t1, 1 + bne t0, t1, return # Linux will run on TP0, continue running bootloader + +# Voice will run on TP0. Set it up and put it to sleep + + # enable interrupts and enable SW IRQ 0 + li t0, M_SR_IE | M_SR_IBIT1 + mtc0 t0, C0_SR + + # Set up to use alternate exception vector 0x80000200 + li t0, M_CAUSE_IV + mtc0 t0, C0_CAUSE + + mfc0 t1, C0_BCM_CONFIG, 1 + # set all ints except IRQ1 to TP1 and cross over SW IRQ 0 + or t1, (CP0_CMT_XIR_4 | CP0_CMT_XIR_3 | CP0_CMT_XIR_2 | CP0_CMT_XIR_0 | CP0_CMT_SIR_0 | CP0_CMT_NMIR_TP1) + mtc0 t1, C0_BCM_CONFIG, 1 + + mfc0 t1, C0_BCM_CONFIG, 2 + # Set debug on TP1, give priority to TP0, and + # set TLB exception serialization to ignore SCNT value in CP0 reg22 sel 4 + and t1, ~CP0_CMT_TPS_MASK; + or t1, (CP0_CMT_DSU_TP1 | CP0_CMT_PRIO_TP0 | (1 << CP0_CMT_TPS_SHFT)) + mtc0 t1, C0_BCM_CONFIG, 2 + + # Enable Data RAC on TP0 + li t1, MIPS_BASE + lw t2, MIPS_RAC_CR0(t1) + or t2, (RAC_D | RAC_PF_D) + sw t2, MIPS_RAC_CR0(t1) + +2: + li t8, 0 + b wait_for_wake + +tp1: +# Running on TP1.... +# First signal to TP0 that TP1 is up + li t1, 0x1 + mtc0 t1, $31 # CO_DESAVE + + li t0, THREAD_NUM_ADDRESS + FIXUP(t0) + lw t0, 0(t0) + li t1, 1 + beq t0, t1, return # Linux will run on TP1, continue running bootloader + +# Voice will run on TP1. Set it up and put it to sleep + + # enable interrupts and enable SW IRQ 0 + li t0, M_SR_IE | M_SR_IBIT1 + mtc0 t0, C0_SR + + # Set up to use alternate exception vector 0x80000200 + li t0, M_CAUSE_IV + mtc0 t0, C0_CAUSE + + mfc0 t1, C0_BCM_CONFIG, 1 + # set IRQ1 to TP1 and cross over SW IRQ 0 + or t1, (CP0_CMT_XIR_1 | CP0_CMT_SIR_0 | CP0_CMT_NMIR_TP0) + mtc0 t1, C0_BCM_CONFIG, 1 + + mfc0 t1, C0_BCM_CONFIG, 2 + # Set debug on TP0, give priority to TP1, and + # set TLB exception serialization to ignore SCNT value in CP0 reg22 sel 4 + and t1, ~CP0_CMT_TPS_MASK; + or t1, (CP0_CMT_PRIO_TP1 | (1 << CP0_CMT_TPS_SHFT)) + mtc0 t1, C0_BCM_CONFIG, 2 + + # Enable Data RAC on TP1 + li t1, MIPS_BASE + lw t2, MIPS_RAC_CR1(t1) + or t2, (RAC_D | RAC_PF_D) + sw t2, MIPS_RAC_CR1(t1) + b 2b + +return: + j ra + +END(bcmcore_tp1_switch) + +# align this code to cache line. NAND flash is not memory mapped after system boots +# so when we are signaling to the second TP to wake we need +# jal instruction to be in cache + .align 4 +LEAF(wait_for_wake) + sync + wait # wait for interrupt + jal t8 # jump to entry point +END(wait_for_wake) diff --git a/cfe/cfe/arch/mips/board/bcm63xx_rom/src/bcm6368_sdramDqs.c b/cfe/cfe/arch/mips/board/bcm63xx_rom/src/bcm6368_sdramDqs.c new file mode 100755 index 0000000..96d5000 --- /dev/null +++ b/cfe/cfe/arch/mips/board/bcm63xx_rom/src/bcm6368_sdramDqs.c @@ -0,0 +1,439 @@ +/*************************************************************************** +* +* Copyright (c) 2004 Broadcom Corporation, All Rights Reserved. +* Contains proprietary and confidential information. +* +* No portions of this material may be reproduced in any form without the +* written permission of: +* +* Broadcom Corporation +* 16215 Alton Parkway +* P.O. Box 57013 +* Irvine, California 92619-7013 +* +* All information contained in this document is Broadcom Corporation +* company private, proprietary, and trade secret. +* +****************************************************************************/ +#include "lib_types.h" +#include "bcm_map.h" + +// Uncomment out the below line to use MemoryTestSuite() +// #define EXTENDED_MEMORY_TESTS + +/* ---- Private Constants and Types -------------------------------------- */ +#define VCDL_PHASE_DEFAULT 16 +#define VCDL_PHASE_MAX 47 /* 154.69 degree */ +#define VCDL_PHASE_MIN 0 /* 22.5 degree */ + +typedef unsigned long u; + +#define N 32*1024 // Size of the copy operation + // Must be at least equal to the L2 cache size +#define S (1*sizeof(u)) + +/* ---- Private Function Prototypes -------------------------------------- */ +inline static int MemoryTest(void) __attribute__((always_inline)); +inline static void PI_upper_set(volatile uint32 *, int bitOffset, int shift) __attribute__((always_inline)); +inline static void PI_shmoo(volatile uint32 *PI_reg, int bitOffset, int minValue, int maxValue, int increment) __attribute__((always_inline)); +inline static void shmooVcdl(int minValue, int maxValue, int increment) __attribute__((always_inline)); + +// #define DEBUG_SHMOO 1 +#if DEBUG_SHMOO +inline static void dumpChar(uint8 c) __attribute__((always_inline)); +inline static void dumpChar(uint8 c) +{ + //wait till tx fifo below threshold + while (UART->txf_levl > 14); + UART->Data = c; +} + +#else +#define dumpChar(c) +#endif + +#if defined(EXTENDED_MEMORY_TESTS) +#include "memtest.c"/* Suite memory tests SCAN, MARCH, SLIDING, SHIFT ADDRESS */ +inline static int MemoryTestSuite(void) __attribute__((always_inline)); +#endif + +/* ==== Public Functions ================================================= */ +void sdramDqsPhaseSet(void); +void vcdlCalibration(void); + +/*******************************************************************************/ +void sdramDqsPhaseSet(void) +{ + int dqOutPhaseMax; + int delay; + int ubusPhase, mipsPhase; + int equalCount = 0; + + // Reset VCDL + DDR->Spare1 |= 0x1; + delay = 1000; + while(delay--); + DDR->Spare1 &= ~0x1; + + // Calculate max phase offset from PLL config register. + dqOutPhaseMax = ((DDR->MIPSDDRPLLMDiv & DDR_MDIV_MASK) >> DDR_MDIV_SHFT) * 8; + + dumpChar('\n'); + dumpChar('\r'); + + // Start by setting VCDL to the default. This almost always works. + // Enable squelch + DDR->WSliceCntl |= (0x1<<20) | (0x1<<4); + DDR->VCDLPhaseCntl0 = (VCDL_PHASE_DEFAULT << 22) | (VCDL_PHASE_DEFAULT << 16) | (VCDL_PHASE_DEFAULT << 6) | VCDL_PHASE_DEFAULT; + DDR->VCDLPhaseCntl1 = (VCDL_PHASE_DEFAULT << 22) | (VCDL_PHASE_DEFAULT << 16) | (VCDL_PHASE_DEFAULT << 6) | VCDL_PHASE_DEFAULT; + DDR->WSliceCntl &= ~((0x1<<20) | (0x1<<4)); + + // Now shmoo over DQ phase to find an optimum value. + dumpChar('D');dumpChar('D');dumpChar('R');dumpChar('2'); + dumpChar('\n'); + dumpChar('\r'); + PI_shmoo(&DDR->DDR1_2PhaseCntl0, 16, -dqOutPhaseMax, dqOutPhaseMax, 1); + + dumpChar('V');dumpChar('C');dumpChar('D');dumpChar('L'); + dumpChar('\n'); + dumpChar('\r'); + shmooVcdl(VCDL_PHASE_MIN, VCDL_PHASE_MAX, 1); + + // Now setup the UBUS clock + dumpChar('U');dumpChar('B');dumpChar('U');dumpChar('S'); + dumpChar('\n'); + dumpChar('\r'); + + MEMC->RefreshPdControl &= ~MEMC_REFRESH_ENABLE; // Turn off refresh while messing with UBus clock + + DDR->MIPSPhaseCntl &= ~(0x1<<23); // turn off ubus PI auto mode + + mipsPhase = DDR->MIPSPhaseCntl; + do { + if (DDR->MIPSPhaseCntl == mipsPhase) + equalCount++; + else { + equalCount = 0; + mipsPhase = DDR->MIPSPhaseCntl; + } + } while (equalCount < 3); + + ubusPhase = ((DDR->UBUSPhaseCntl) & 0x3ffe); // make it even and decrease count + DDR->UBUSPhaseCntl = ubusPhase; + + // Wait until we match several times in a row, to be sure we wait long enough + do { + if (DDR->UBUSPhaseCntl == ubusPhase) + equalCount++; + else + equalCount = 0; + } while (equalCount < 3); + + MEMC->RefreshPdControl |= MEMC_REFRESH_ENABLE; +} + + +/* ==== Private Functions ================================================ */ + +inline static void PI_upper_set(volatile uint32 *PI_reg, int bitOffset, int shift) +{ + uint32 oldVal; + uint32 newVal; + int32 oldPhase; + int32 newPhase; + int equalCount = 0; + + oldVal = *PI_reg; // get the phase config (may have other controls in other 16 bits) + + oldPhase = ( oldVal >> bitOffset ) & 0x3fff; + if ( oldPhase & (0x1<<13) ) { + oldPhase |= ~0x3fff; // sign extend + } + + newPhase = shift & 0x3fff; // set up phase shift value[13:0] + if (shift > oldPhase) { // set up up/down [14], shift is signed value + newPhase |= 0x1<<14; + } + + newPhase = newPhase << bitOffset; + oldVal = oldVal & (0xffff << (16-bitOffset)); // Keep the other control bits + newVal = newPhase | oldVal; + *PI_reg = newVal; + + // Wait until we match several times in a row, to be sure we wait long enough + do { + if (*PI_reg == newVal) + equalCount++; + else + equalCount = 0; + } while (equalCount < 3); +} + + +inline static void PI_shmoo(volatile uint32 *PI_reg, int bitOffset, int minValue, int maxValue, int increment) +{ + int piPhase, piPhaseCnt, passStatus; + int pass1Start, pass1Fail, pass2Start, pass2Fail; + int pass1Cnt, pass2Cnt; + + PI_upper_set(PI_reg, bitOffset, minValue); + + passStatus = 0; + pass1Start = maxValue; + pass1Fail = minValue; + pass2Start = minValue; + pass2Fail = minValue; + + for (piPhase = minValue; piPhase <= maxValue; piPhase += increment) { + + // if (MemoryTestSuite()) + if (MemoryTest()) + { + if (passStatus == 0x0) { // first_pass start + passStatus = 0x1; + pass1Start = piPhase; + } + else if (passStatus == 0x2) { // second_pass start + passStatus = 0x3; + pass2Start = piPhase; + } + dumpChar('p'); + } + else { + if (passStatus == 0x1) { // fisrt_pass end + passStatus = 0x2; + pass1Fail = piPhase; + } + else if (passStatus == 0x3) { // second_pass end + passStatus = 0x4; + pass2Fail = piPhase; + } + dumpChar('.'); + } + + piPhaseCnt = ( piPhase + 0x01) & 0x3fff; + if (increment) { + piPhaseCnt |= (0x01<<14); + } + + *PI_reg = (*PI_reg & (0xffff << (16-bitOffset))) | (piPhaseCnt<<bitOffset); + + } + + // Figure out the middle point of the pass window + // valid window 1 -- .......PPPPPPPPPPPPPP....... + // valid window 2 -- PPPPPPP........PPPPPPPPPPPPP + + if ((pass1Start != maxValue) && (pass2Start == minValue)) { // valid window 1 + if (pass1Fail == minValue) { + piPhaseCnt = (pass1Start + maxValue) >> 1; // mid-point of the pass window + } else { + piPhaseCnt = (pass1Start + pass1Fail - 0x1) >> 1; // mid-point of the pass window + } + } + else if ((pass1Start == minValue) && (pass2Start != minValue) && (pass2Fail == minValue)) { // valid window 2 + pass1Cnt = pass1Fail - minValue; + pass2Cnt = maxValue - pass2Start + 1; + passStatus= (pass1Cnt + pass2Cnt) >> 1; + if (passStatus < pass1Cnt) { // mid-point of the overall pass window is in sub-window 1 + piPhaseCnt = minValue + ( pass1Cnt - passStatus ); + } + else { + piPhaseCnt = pass2Start - 0x1 + passStatus; + } + } + else { + piPhaseCnt = 0x0; // shmoo failed. + } + + piPhaseCnt &= ~0x01; // make it even number + + PI_upper_set(PI_reg, bitOffset, piPhaseCnt); // set the final phase value + + dumpChar('\n'); + dumpChar('\r'); +} + + +inline static void shmooVcdl(int minValue, int maxValue, int increment) +{ + UINT32 dqsInPhase; + UINT32 dqsInSum = 0; + UINT32 passCnt = 0; + volatile int delay; + + for (dqsInPhase = minValue; dqsInPhase <= maxValue; dqsInPhase += increment) { + delay = 1000; + while(delay--); + // Enable squelch + DDR->WSliceCntl |= (0x1<<20) | (0x1<<4); + DDR->VCDLPhaseCntl0 = (dqsInPhase << 22) | (dqsInPhase << 16) | (dqsInPhase << 6) | dqsInPhase; + DDR->VCDLPhaseCntl1 = (dqsInPhase << 22) | (dqsInPhase << 16) | (dqsInPhase << 6) | dqsInPhase; + DDR->WSliceCntl &= ~((0x1<<20) | (0x1<<4)); + + delay = 1000; + while(delay--); + +#if defined(EXTENDED_MEMORY_TESTS) + if (MemoryTestSuite() == MEMTEST_SUCCESS ) +#else + if (MemoryTest()) +#endif + { + dqsInSum += dqsInPhase; + passCnt++; + dumpChar('p'); + } + else { + dumpChar('.'); + } + } + delay = 1000; + while(delay--); + // Enable squelch + DDR->WSliceCntl |= (0x1<<20) | (0x1<<4); + if (passCnt > 0) { + dqsInPhase = dqsInSum / passCnt; + DDR->VCDLPhaseCntl0 = (dqsInPhase << 22) | (dqsInPhase << 16) | (dqsInPhase << 6) | dqsInPhase; + DDR->VCDLPhaseCntl1 = (dqsInPhase << 22) | (dqsInPhase << 16) | (dqsInPhase << 6) | dqsInPhase; + } + else { + DDR->VCDLPhaseCntl0 = (VCDL_PHASE_DEFAULT << 22) | (VCDL_PHASE_DEFAULT << 16) | (VCDL_PHASE_DEFAULT << 6) | VCDL_PHASE_DEFAULT; + DDR->VCDLPhaseCntl1 = (VCDL_PHASE_DEFAULT << 22) | (VCDL_PHASE_DEFAULT << 16) | (VCDL_PHASE_DEFAULT << 6) | VCDL_PHASE_DEFAULT; + } + DDR->WSliceCntl &= ~((0x1<<20) | (0x1<<4)); + dumpChar('\n'); + dumpChar('\r'); +} + +#if defined(EXTENDED_MEMORY_TESTS) + +// Define the memory size for use by the memory test suite +#define MEMORY_SIZE (2 * 1024) + +int MemoryTestSuite(void) +{ + int test = 1; + uint32_t * memory = (uint32_t*) (0xa0000000); + Pattern_t pat32, patIx; + + for (patIx = PATTERN_0x00000000; patIx < PATTERN_MAX; patIx++ ) + { + pat32 = pattern[ patIx ]; + + fill_memory( memory, MEMORY_SIZE, 0x0 ); + if ( scanWordValue( memory, MEMORY_SIZE, pat32 ) == MEMTEST_FAILURE ) + goto exit_tests; + + test++; + + fill_memory( memory, MEMORY_SIZE, 0x0 ); + if ( scanBulkValue( memory, MEMORY_SIZE, pat32 ) == MEMTEST_FAILURE ) + goto exit_tests; + + test++; + + fill_memory( memory, MEMORY_SIZE, 0x0 ); + if ( scanBulkAltInv( memory, MEMORY_SIZE, pat32 ) == MEMTEST_FAILURE ) + goto exit_tests; + + test++; + + fill_memory( memory, MEMORY_SIZE, 0x0 ); + if ( slidingAltInv( memory, MEMORY_SIZE, pat32 ) == MEMTEST_FAILURE ) + goto exit_tests; + + test++; + + fill_memory( memory, MEMORY_SIZE, 0x0 ); + if ( slidingDiag( memory, MEMORY_SIZE, pat32 ) == MEMTEST_FAILURE ) + goto exit_tests; + + test++; + } + + fill_memory( memory, MEMORY_SIZE, 0x0 ); + if ( scanWordSelf( memory, MEMORY_SIZE ) == MEMTEST_FAILURE ) + goto exit_tests; + + test++; + + fill_memory( memory, MEMORY_SIZE, 0x0 ); + if ( scanBulkSelf( memory, MEMORY_SIZE ) == MEMTEST_FAILURE ) + goto exit_tests; + + test++; + + fill_alt_memory( memory, MEMORY_SIZE, 0XAAAAAAAA, 0x55555555 ); + if ( memoryBulkCopy( memory, (memory + ((MEMORY_SIZE/2)/sizeof(uint32_t))), + MEMORY_SIZE/2 ) == MEMTEST_FAILURE ) + goto exit_tests; + + // return tests; + return MEMTEST_SUCCESS; + +exit_tests: + return MEMTEST_FAILURE; + +} +#endif /* defined(EXTENDED_MEMORY_TESTS) */ + +// +// Returns: 0=FAILURE, 1=SUCCESS +inline static int MemoryTest(void) +{ + // Test 32-bit write/read + volatile uint32 *memAddr; + uint32 memBase; + uint32 testValue; + int i; + int j; + int k; + + memBase = 0xa0000000; + for (i = 2; i < 24; i++) { + memAddr = (void *) (memBase + (1 << i)); + for (k = 0; k < 2; k++) { + /* walking one */ + testValue = 1; + for (j = 0; j < 32; j++) { + *memAddr = testValue; + if (*memAddr != testValue) + return 0; + + testValue <<= 1; + } + /* walking zero */ + testValue = ~1; + for (j = 0; j < 32; j++) { + *memAddr = testValue; + if (*memAddr != testValue) + return 0; + + testValue = (testValue << 1) | 1; + } + /* shift in zeroes */ + testValue = -1; + for (j = 0; j < 32; j++) { + *memAddr = testValue; + *(uint32*)memBase = 0; + if (*memAddr != testValue) + return 0; + + testValue <<= 1; + } + /* shift in ones */ + testValue = 1; + for (j = 0; j < 32; j++) { + *memAddr = testValue; + *(uint32*)memBase = 0; + if (*memAddr != testValue) + return 0; + + testValue = (testValue << 1) | 1; + } + } + } + return 1; +} + diff --git a/cfe/cfe/arch/mips/board/bcm63xx_rom/src/bcm63xx_impl1_rom_boot.S b/cfe/cfe/arch/mips/board/bcm63xx_rom/src/bcm63xx_impl1_rom_boot.S new file mode 100755 index 0000000..b3986ed --- /dev/null +++ b/cfe/cfe/arch/mips/board/bcm63xx_rom/src/bcm63xx_impl1_rom_boot.S @@ -0,0 +1,1818 @@ +#include "sbmips.h" +#include "bsp_config.h" + +#include "bcm_cpu.h" +#include "bcm_common.h" + +#include "bcm_hwdefs.h" +#include "boardparms.h" +#include "mipsmacros.h" + +#define DDR_TEST 1 +#define UBUS_SYNC_ENABLE 1 +#define LMB_SYNC_ENABLE 1 +#define MIPS_SYNC_ENABLE 1 +#define LMB_ENABLE 1 + +/* Memory mapping table for different size DRAMs (256Mb, 512Mb, 1Gb, 2Gb) */ + .globl dram_map_table_x8 +dram_map_table_x8: + // 128Mb 64B Interleaving (x8 Mode) 32MB + // This is just a place holder. This memory does not exist + _LONG_ 0x0F0E0D0C, 0x13121110, 0x17161514, 0x00000018 // Row00_0 Row00_1 Row01_0 Row01_1 + _LONG_ 0x04000000, 0x0A090805, 0x0000000B, 0x00000000 // Col00_0 Col00_1 Col01_0 Col01_1 + _LONG_ 0x00080706, 0x00000002, 0x00000055 // Bank CS_End Dramsize + + // 256Mb 64B Interleaving (x8 Mode) 64MB + _LONG_ 0x100F0E0D, 0x14131211, 0x18171615, 0x00000019 // Row00_0 Row00_1 Row01_0 Row01_1 + _LONG_ 0x04000000, 0x0A090805, 0x00000C0B, 0x00000000 // Col00_0 Col00_1 Col01_0 Col01_1 + _LONG_ 0x00000706, 0x00000004, 0x00000066 // Bank CS_End Dramsize + + // 512Mb 64B Interleaving (x8 Mode) 128MB + _LONG_ 0x100F0E0D, 0x14131211, 0x18171615, 0x00001A19 // Row00_0 Row00_1 Row01_0 Row01_1 + _LONG_ 0x04000000, 0x0A090805, 0x00000C0B, 0x00000000 // Col00_0 Col00_1 Col01_0 Col01_1 + _LONG_ 0x00000706, 0x00000008, 0x00000077 // Bank CS_End Dramsize + + // 1Gb 64B Interleaving (x8 Mode) 256MB + _LONG_ 0x11100F0E, 0x15141312, 0x19181716, 0x00001B1A // Row00_0 Row00_1 Row01_0 Row01_1 + _LONG_ 0x04000000, 0x0B0A0905, 0x00000D0C, 0x00000000 // Col00_0 Col00_1 Col01_0 Col01_1 + _LONG_ 0x00080706, 0x00000010, 0x00000088 // Bank CS_End Dramsize + + .globl dram_map_table_x16 +dram_map_table_x16: + // 256Mb 64B Interleaving (x16 Mode) 32MB + _LONG_ 0x0F0E0D0C, 0x13121110, 0x17161514, 0x00000018 // Row00_0 Row00_1 Row01_0 Row01_1 + _LONG_ 0x04000000, 0x0A090805, 0x0000000B, 0x00000000 // Col00_0 Col00_1 Col01_0 Col01_1 + _LONG_ 0x00000706, 0x00000002, 0x00000055 // Bank CS_End Dramsize + + // 512Mb 64B Interleaving (x16 Mode) 64MB + _LONG_ 0x100F0E0D, 0x14131211, 0x18171615, 0x00000019 // Row00_0 Row00_1 Row01_0 Row01_1 + _LONG_ 0x04000000, 0x0A090805, 0x00000C0B, 0x00000000 // Col00_0 Col00_1 Col01_0 Col01_1 + _LONG_ 0x00000706, 0x00000004, 0x00000066 // Bank CS_End Dramsize + + // 1Gb 64B Interleaving (x16 Mode) 128MB + _LONG_ 0x11100F0E, 0x15141312, 0x19181716, 0x0000001A // Row00_0 Row00_1 Row01_0 Row01_1 + _LONG_ 0x04000000, 0x0B0A0905, 0x00000D0C, 0x00000000 // Col00_0 Col00_1 Col01_0 Col01_1 + _LONG_ 0x00080706, 0x00000008, 0x00000077 // Bank CS_End Dramsize + + // 2Gb 64B Interleaving (x16 Mode) 256MB + _LONG_ 0x11100F0E, 0x15141312, 0x19181716, 0x00001B1A // Row00_0 Row00_1 Row01_0 Row01_1 + _LONG_ 0x04000000, 0x0B0A0905, 0x00000D0C, 0x00000000 // Col00_0 Col00_1 Col01_0 Col01_1 + _LONG_ 0x00080706, 0x00000010, 0x00000088 // Bank CS_End Dramsize + + .globl dram_tRefi_table +dram_tRefi_table: /* Refresh Interval table for different Speed DRAMs (100-200, 300-333, 400) */ + _LONG_ 0x16, 0x49, 0x5D // 100-200 300-333 400 (MHz) + + .globl dram_tRFC_table +dram_tRFC_table: /* tRFC table for different size & Speed DRAMs (256Mb, 512Mb, 1Gb)/(200, 333, 400) */ +// 200 333 400 (MHz) + _LONG_ 0xF, 0x19, 0x1E // 256Mb + _LONG_ 0x15, 0x23, 0x2A // 512Mb + _LONG_ 0x1A, 0x2B, 0x33 // 1Gb + _LONG_ 0x28, 0x42, 0x4F // 2Gb + + .globl dram_timing_table +dram_timing_table: /* */ +// tRCD tCL tWR tWL tRP tRRD tRC tFAW tW2R tR2W tR2R tAL tRTP tW2W +// --------------------------------------------------------------------- + .byte 0x03,0x04,0x03,0x03,0x03,0x02,0x11,0x00,0x01,0x01,0x00,0x02,0x02,0x00,0x00,0x00 // 200MHz + .byte 0x05,0x05,0x05,0x04,0x05,0x04,0x13,0x00,0x02,0x01,0x00,0x04,0x03,0x00,0x00,0x00 // 300MHz + .byte 0x05,0x05,0x06,0x04,0x06,0x05,0x18,0x00,0x02,0x01,0x00,0x04,0x03,0x00,0x00,0x00 // 400MHz + + .globl dram_sync_table +dram_sync_table: /* Bit vector table for Ubus sync modes and Lmb sync modes */ +#if defined(_BCM96328_) + _LONG_ 0x8E10FFFF, 0x8A10FFFF, 0xEDC2FFFF // UBUS Sync , LMB Sync, Mips Sync +#elif defined(_BCM96362_) + _LONG_ 0xFFBFBFBF, 0x6341C101, 0xE7E5E5E5 // UBUS Sync , LMB Sync, Mips Sync +#elif defined(_BCM96816_) + _LONG_ 0xC03033B5, 0x80303095, 0xFF90FFFF // UBUS Sync , LMB Sync, Mips Sync +#endif + .globl dram_speed_table +dram_speed_table: /* Memory Speed Table for different clock strap values */ + /* 0=200Mhz 1=333MHz 2=400MHz */ +#if defined(_BCM96328_) + .byte 0 // 0x0 + .byte 0 // 0x1 + .byte 0 // 0x2 + .byte 0 // 0x3 + .byte 0 // 0x4 + .byte 0 // 0x5 + .byte 0 // 0x6 + .byte 0 // 0x7 + .byte 0 // 0x8 + .byte 0 // 0x9 + .byte 0 // 0xa + .byte 0 // 0xb + .byte 0 // 0xc + .byte 0 // 0xd + .byte 0 // 0xe + .byte 0 // 0xf + .byte 0 // 0x10 + .byte 0 // 0x11 + .byte 0 // 0x12 + .byte 0 // 0x13 + .byte 0 // 0x14 + .byte 0 // 0x15 + .byte 2 // 0x16 + .byte 2 // 0x17 + .byte 0 // 0x18 + .byte 0 // 0x19 + .byte 0 // 0x1a + .byte 0 // 0x1b + .byte 0 // 0x1c + .byte 0 // 0x1d + .byte 0 // 0x1e + .byte 1 // 0x1f +#elif defined(_BCM96362_) + .byte 1 // 0x0 + .byte 2 // 0x1 + .byte 0 // 0x2 + .byte 1 // 0x3 + .byte 0 // 0x4 + .byte 2 // 0x5 + .byte 2 // 0x6 + .byte 1 // 0x7 + .byte 1 // 0x8 + .byte 2 // 0x9 + .byte 0 // 0xa + .byte 1 // 0xb + .byte 0 // 0xc + .byte 2 // 0xd + .byte 2 // 0xe + .byte 1 // 0xf + .byte 1 // 0x10 + .byte 2 // 0x11 + .byte 0 // 0x12 + .byte 1 // 0x13 + .byte 0 // 0x14 + .byte 1 // 0x15 // 267MHz. Need to change tREFI if this is used. + .byte 2 // 0x16 + .byte 1 // 0x17 + .byte 1 // 0x18 + .byte 1 // 0x19 + .byte 0 // 0x1a + .byte 1 // 0x1b + .byte 0 // 0x1c + .byte 0 // 0x1d + .byte 2 // 0x1e + .byte 1 // 0x1f +#elif defined(_BCM96816_) + .byte 0 // 0x0 + .byte 1 // 0x1 + .byte 0 // 0x2 + .byte 0 // 0x3 + .byte 0 // 0x4 + .byte 1 // 0x5 + .byte 1 // 0x6 + .byte 1 // 0x7 + .byte 1 // 0x8 + .byte 1 // 0x9 + .byte 1 // 0xa + .byte 2 // 0xb + .byte 2 // 0xc + .byte 2 // 0xd + .byte 2 // 0xe + .byte 2 // 0xf + .byte 2 // 0x10 + .byte 2 // 0x11 + .byte 2 // 0x12 + .byte 2 // 0x13 + .byte 2 // 0x14 + .byte 0 // 0x15 + .byte 0 // 0x16 + .byte 1 // 0x17 + .byte 1 // 0x18 + .byte 1 // 0x19 + .byte 1 // 0x1a + .byte 1 // 0x1b + .byte 2 // 0x1c + .byte 2 // 0x1d + .byte 2 // 0x1e + .byte 2 // 0x1f +#endif + + .globl memc_ubus_ratio_table +memc_ubus_ratio_table: /* Memory Speed Table for different clock strap values */ +#if defined(_BCM96328_) +// 6328 Clock Speed Table + .byte 3 // 0x0 + .byte 3 // 0x1 + .byte 3 // 0x2 + .byte 3 // 0x3 + .byte 3 // 0x4 + .byte 3 // 0x5 + .byte 3 // 0x6 + .byte 3 // 0x7 + .byte 3 // 0x8 + .byte 3 // 0x9 + .byte 3 // 0xa + .byte 3 // 0xb + .byte 3 // 0xc + .byte 3 // 0xd + .byte 3 // 0xe + .byte 3 // 0xf + .byte 3 // 0x10 + .byte 3 // 0x11 + .byte 0xf // 0x12 + .byte 0xf // 0x13 + .byte 3 // 0x14 + .byte 9 // 0x15 + .byte 9 // 0x16 + .byte 9 // 0x17 + .byte 3 // 0x18 + .byte 3 // 0x19 + .byte 3 // 0x1a + .byte 3 // 0x1b + .byte 0xb // 0x1c + .byte 0xb // 0x1d + .byte 0xb // 0x1e + .byte 3 // 0x1f +#elif defined(_BCM96362_) +// 6362 Clock Speed Table + .byte 3 // 0x0 + .byte 3 // 0x1 + .byte 3 // 0x2 + .byte 3 // 0x3 + .byte 3 // 0x4 + .byte 3 // 0x5 + .byte 3 // 0x6 + .byte 3 // 0x7 + .byte 3 // 0x8 + .byte 3 // 0x9 + .byte 3 // 0xa + .byte 3 // 0xb + .byte 3 // 0xc + .byte 3 // 0xd + .byte 3 // 0xe + .byte 3 // 0xf + .byte 3 // 0x10 + .byte 3 // 0x11 + .byte 3 // 0x12 + .byte 3 // 0x13 + .byte 4 // 0x14 + .byte 4 // 0x15 + .byte 15 // 0x16 + .byte 3 // 0x17 + .byte 3 // 0x18 + .byte 3 // 0x19 + .byte 3 // 0x1a + .byte 3 // 0x1b + .byte 3 // 0x1c + .byte 3 // 0x1d + .byte 3 // 0x1e + .byte 3 // 0x1f +#elif defined(_BCM96816_) +// 6816 Clock Speed Table + .byte 3 // 0x0 + .byte 9 // 0x1 + .byte 3 // 0x2 + .byte 4 // 0x3 + .byte 3 // 0x4 + .byte 3 // 0x5 + .byte 9 // 0x6 + .byte 3 // 0x7 + .byte 3 // 0x8 + .byte 3 // 0x9 + .byte 2 // 0xa + .byte 4 // 0xb + .byte 2 // 0xc + .byte 3 // 0xd + .byte 4 // 0xe + .byte 9 // 0xf + .byte 1 // 0x10 + .byte 1 // 0x11 + .byte 1 // 0x12 + .byte 1 // 0x13 + .byte 3 // 0x14 + .byte 3 // 0x15 + .byte 4 // 0x16 + .byte 9 // 0x17 + .byte 6 // 0x18 + .byte 2 // 0x19 + .byte 6 // 0x1a + .byte 2 // 0x1b + .byte 4 // 0x1c + .byte 3 // 0x1d + .byte 4 // 0x1e + .byte 3 // 0x1f +#endif + +#if defined(_BCM96816_) + .globl periph_fix_table +periph_fix_table: // Periph Clock fix vector for different clock strap values + _LONG_ 0xAA30A047 +#endif + +#define SETLEDS1(a,b,c,d) \ + li a0,(((a)<<24)|((b)<<16)|((c)<<8)|(d)) ; \ + bal board_setleds; \ + nop + +/* ********************************************************************* + * BOARD_EARLYINIT() + * + * Initialize board registers. This is the earliest + * time the BSP gets control. This routine cannot assume that + * memory is operational, and therefore all code in this routine + * must run from registers only. The $ra register must not + * be modified, as it contains the return address. + * + * This routine will be called from uncached space, before + * the caches are initialized. If you want to make + * subroutine calls from here, you must use the CALLKSEG1 macro. + * + * Among other things, this is where the GPIO registers get + * programmed to make on-board LEDs function, or other startup + * that has to be done before anything will work. + * + * Input parameters: + * a0 - Flash base address (address of MIPS reset) + * + * Return value: + * nothing + ********************************************************************* */ + +LEAF(board_earlyinit) + + .set noreorder + + mfc0 t1, C0_BCM_CONFIG, 3 + li t2, CP0_CMT_TPID + and t1, t2 + bnez t1, 3f # if we are running on thread 1, skip init + nop + + /**-------------------------------------------------------------**/ + /** platform specific code **/ + /**-------------------------------------------------------------**/ + +#if defined(_BCM96816_) + /**----- Offset UBUS Clock 180 degrees -------------------------**/ + li t2, MISC_BASE + lw t1, MISC_STRAP_BUS(t2) + + srl t1, MISC_STRAP_BUS_MIPS_PLL_FVCO_SHIFT + andi t1, 0x1f // Mask out strap bits + + move s0,ra + LOADREL(t2, periph_fix_table) + lw t2, 0(t2) + srl t2, t1 + andi t2, 1 + move ra,s0 + + beq t2, zero, 2f + nop + + li t0, DDR_BASE + li t1, 0x00070000 // send new phase value to PLL every 8 cycles + sw t1, DDR_CTL_PI_UBUS_CTL(t0) + ori t1, 0x4080 // shift 128 steps in the positive direction to be 180 degree's offset VCO 1.6GHz + sw t1, DDR_CTL_PI_UBUS_CTL(t0) + li t1, 0x00000001 + sw t1, DDR_CTL_PI_GCF(t0) + + li t1, 0x10000 // delay +1: + bnez t1, 1b + addi t1, -1 + +2: + /**----- Set 1.2V and 2.5V Voltage regulators ------------------**/ + li t1, GPIO_BASE + lw t2, GPIO_SWREG_CONFIG(t1) + and t2, ~GPIO_SW_VREG_SEL_MASK + or t2, (0x0 << GPIO_SW_VREG_SEL_SHIFT) + and t2, ~GPIO_LIN_VREG_ADJ_MASK + or t2, (0x0 << GPIO_LIN_VREG_ADJ_SHIFT) + sw t2, GPIO_SWREG_CONFIG(t1) + + li t1, 0x10000 +1: + bnez t1, 1b + addi t1, -1 +#endif + +#if defined (_BCM96328_) || defined (_BCM96362_) + /* slow down mips clk (div 4) to unlock memory */ + mfc0 t1, C0_BCM_CONFIG, 5 + or t2, t1, 0x40000000 + mtc0 t2, C0_BCM_CONFIG, 5 + nop + + mtc0 t1, C0_BCM_CONFIG, 5 + nop +#endif + +#if defined (_BCM96362_) + /* Adjust VREG frequency up by 50% to improve DSL performance */ + li t2, MISC_BASE + + /* First set ramp control */ + lw t1, MISC_VREG_CONTROL0(t2) + or t1, (0x2 << MISC_VREG_CONTROL0_VREG_RAMP1P8_SHIFT) | (0x2 << MISC_VREG_CONTROL0_VREG_RAMP1P2_SHIFT) + sw t1, MISC_VREG_CONTROL0(t2) + + /* wait 10ms for the setting to take effect */ + li t8, -2000000 + mtc0 t8, C0_COUNT +1: + bltz t8, 1b + mfc0 t8, C0_COUNT + + and t1, ~((0x7 << MISC_VREG_CONTROL0_VREG_RAMP1P8_SHIFT) | (0x7 << MISC_VREG_CONTROL0_VREG_RAMP1P2_SHIFT)) + or t1, (0x3 << MISC_VREG_CONTROL0_VREG_ADJ_SHIFT) + sw t1, MISC_VREG_CONTROL0(t2) + + /* Increase 2.5V regulator to provide increased range for 1.8V */ + lw t1, MISC_VREG_CONTROL1(t2) + and t1, ~MISC_VREG_CONTROL1_VREG_ISEL2P5_MASK + or t1, (MISC_VREG_LDO_2P61 << MISC_VREG_CONTROL1_VREG_ISEL2P5_SHIFT) + sw t1, MISC_VREG_CONTROL1(t2) +#endif + +#if 0 + /* wait for a while to allow catch by jtag debugger */ + li t8, -(200000000*3) /* we will count up to 0 to delay a couple of seconds */ + /* and give the emulator a chance to catch us */ + mtc0 t8, C0_COUNT +catchloop: + bltz t8, catchloop + mfc0 t8, C0_COUNT +#endif + + /**----- Enable I Cache -----------------------------------------**/ + mfc0 t1, C0_BCM_CONFIG + or t1, (CP0_BCM_CFG_ICSHEN | CP0_BCM_CFG_DCSHEN) + mtc0 t1, C0_BCM_CONFIG # Enable I Cache + + // In the begining MIPS core registers are mapped to 0xbfax_xxxx + li t1, 0x1FA0000C # Set up CBR to 1FAx_xxxx + mtc0 t1, C0_BCM_CONFIG, 6 + + li t1, MIPS_BASE_BOOT + lw t2, MIPS_LMB_CR(t1) + or t2, 0xC0000000 # enable ffxx_xxxx space + sw t2, MIPS_LMB_CR(t1) + li t2, 0xFFF80001 # SBR FFF8_xxxx and enable + sw t2, MIPS_SBR(t1) + + // Now map MIPS core registers to 0xFF4x_xxxx space + li t1, 0xFF40000C # CBR FF4x_xxxx (and reserved bits 0xc). + mtc0 t1, C0_BCM_CONFIG, 6 + +#if defined(_BCM96816_) + /**----- Initialize EBI -----------------------------------------**/ + li t1, MPI_BASE + li t2, EBI_SIZE_32M + or t2, a0 + sw t2, CS0BASE(t1) # CS[0] Base + li t2, THREEWT|EBI_WORD_WIDE|EBI_ENABLE + sw t2, CS0CNTL(t1) # CS[0] Control +#endif + + /**----- Initialize Serial --------------------------------------**/ + li t3, ((FPERIPH / 115200) / 16) + /* + # Baudword = (FPeriph)/Baud/32-1. We have to perform rounding + # and subtraction. Above we divided by 16 (instead of 32). If + # bit0 is set, we round up. However, we then subtract 1, so final + # result should be t3/2. If bit0 is 0, then we truncate and subtract + # 1, t3=t3/2-1. + */ + andi t0, t3, 0x1 + bne t0,zero,1f # do shift only (in delay slot) + # and jump to apply + srl t3,1 # do divide by 2 + addiu t3, -1 # subtract 1 +1: + + // t3 contains the UART BAUDWORD + li t0, UART_BASE + sw t3, UART0BAUD(t0) # Store BaudRate + li t1, BITS8SYM|ONESTOP + sb t1, UART0CONFIG(t0) # 8 Bits/1 Stop + li t1, TXEN|RXEN|BRGEN + sb t1, UART0CONTROL(t0) # Enable, No Parity + move t1, zero + sh t1, UART0INTMASK(t0) + + .set reorder +3: + j ra +END(board_earlyinit) + +/* ********************************************************************* + * BOARD_DRAMINFO + * + * Return the address of the DRAM information table + * + * Input parameters: + * nothing + * + * Return value: + * v0 - DRAM info table, return 0 to use default table + ********************************************************************* */ +LEAF(board_draminfo) + j ra +END(board_draminfo) + +/* ********************************************************************* + * BOARD_DRAMINIT + * + * This routine should activate memory. + * + * Input parameters: + * None + * + * Return value: + * None + * + * Registers used: + * can use all registers. + ********************************************************************* */ +LEAF(board_draminit) + .set noreorder + + move s0,ra + +/***** Load DDR Base *************************************/ + li t0, DDR_BASE + +/***** Disable Auto refresh ******************************/ + li t1, 0x10000 + sw t1, DDR_CTL_CLKS(t0) + SETLEDS1('-','-','-', '-') + SETLEDS1('P','H','Y','S') + + li t1, 0x10 // Loop count value + li t3, 1 + +zq_loop: + sub t1, t3 // Decrement count by 1 + beq t1, zero, zq_error + nop + + sw zero, PHY_CONTROL_REGS_ZQ_PVT_COMP_CTL(t0) // Reset the calibration engine + li t4, (1 << 26) + sw t4, PHY_CONTROL_REGS_ZQ_PVT_COMP_CTL(t0) // Start the calibration + + li t2, 0x100 // Timeout value + +wait_zq1: + beq t2, zero, zq_timeout + nop + + lw t4, PHY_CONTROL_REGS_ZQ_PVT_COMP_CTL(t0) // Read the calibration result + move t5, t4 // Save calibration result1 + and t4, (1 << 28) + beq t4, zero, wait_zq1 + sub t2, t3 + + sw zero, PHY_CONTROL_REGS_ZQ_PVT_COMP_CTL(t0) // Reset the calibration engine + li t4, (1 << 26) + sw t4, PHY_CONTROL_REGS_ZQ_PVT_COMP_CTL(t0) // Start the calibration + + li t2, 0x100 // Timeout value + +wait_zq2: + beq t2, zero, zq_timeout + nop + + lw t4, PHY_CONTROL_REGS_ZQ_PVT_COMP_CTL(t0) // Read the calibration result + move t6, t4 // Save calibration result1 + and t4, (1 << 28) + beq t4, zero, wait_zq2 + sub t2, t3 + + sw zero, PHY_CONTROL_REGS_ZQ_PVT_COMP_CTL(t0) // Reset the calibration engine + li t4, (1 << 26) + sw t4, PHY_CONTROL_REGS_ZQ_PVT_COMP_CTL(t0) // Start the calibration + + li t2, 0x100 // Timeout value + +wait_zq3: + beq t2, zero, zq_timeout + nop + + lw t4, PHY_CONTROL_REGS_ZQ_PVT_COMP_CTL(t0) // Read the calibration result + move t7, t4 // Save calibration result1 + and t4, (1 << 28) + beq t4, zero, wait_zq3 + sub t2, t3 + + bne t5, t6, zq_loop + nop + bne t5, t7, zq_loop + nop + bne t6, t7, zq_loop + nop + + b zq_done; + nop + +zq_error: + SETLEDS1('Z','Q','E','R') + b zq_done + nop + +zq_timeout: + SETLEDS1('Z','Q','T','O') + nop +zq_done: + sw zero, PHY_CONTROL_REGS_ZQ_PVT_COMP_CTL(t0) // Reset the calibration engine + + SETLEDS1('Z','Q','D','N') + nop + +/****** Set control pad strength to half ********/ + lw t2, PHY_CONTROL_REGS_DRIVE_PAD_CTL(t0) + or t2, 0x4 + sw t2, PHY_CONTROL_REGS_DRIVE_PAD_CTL(t0) + +#if defined(_BCM96816_) +/****** Disable byte lanes 2 and 3 ********/ + li t1, 0x800fffff + sw t1, PHY_BYTE_LANE_2_IDLE_PAD_CONTROL(t0) + sw t1, PHY_BYTE_LANE_3_IDLE_PAD_CONTROL(t0) +#endif + +/****** Disable byte lane 1 clock ********/ + li t1, 1 + sw t1, PHY_BYTE_LANE_1_CLOCK_PAD_DISABLE(t0) + +ddr_x8: + +/****** Change the slew and receiver power to full strength in the byte lanes ********/ + li t1, 0xFFFFFFFC + lw t2, PHY_BYTE_LANE_0_DRIVE_PAD_CTL(t0) + and t2, t2, t1 + sw t2, PHY_BYTE_LANE_0_DRIVE_PAD_CTL(t0) + lw t2, PHY_BYTE_LANE_1_DRIVE_PAD_CTL(t0) + and t2, t2, t1 + sw t2, PHY_BYTE_LANE_1_DRIVE_PAD_CTL(t0) + +/****** Hardware calibrate VDL *******/ + li t1, 3 + sw t1, PHY_BYTE_LANE_0_VDL_CALIBRATE(t0) + sw t1, PHY_BYTE_LANE_1_VDL_CALIBRATE(t0) + + li t1, 0x1000 +1: + bnez t1, 1b + addi t1, -1 + +/****** Check strap value to figure out 400MHz or 200Mhz DDR ******/ + li t2, MISC_BASE + lw t1, MISC_STRAP_BUS(t2) + + srl t1, MISC_STRAP_BUS_MIPS_PLL_FVCO_SHIFT + andi t1, 0x1f // Mask out strap bits + + LOADREL(t2, dram_speed_table) + + add t2, t1 + lb t1, 0x00(t2) + beq t1, zero, ddr_clk_200 + li t2, 1 + beq t1, t2, ddr_clk_300 + nop + +/****** Software override rd_en VDL and ADDRESS VDL ********/ +ddr_clk_450: +ddr_clk_400: + li a1, 2 // Set speed to 400MHz (2) + b 1f + nop +ddr_clk_300: + li a1, 1 // Set speed to 300MHz (1) + +/* At higher frequencies set Read_en VDL value to calibrated VDL value + 10 */ +1: li t2, 0x10000 + lw t1, PHY_BYTE_LANE_0_VDL_STATUS(t0) + srl t1, 8 + addi t1, 0xA + or t1, t1, t2 + sw t1, PHY_BYTE_LANE_0_VDL_OVERRIDE_2(t0) + lw t1, PHY_BYTE_LANE_1_VDL_STATUS(t0) + srl t1, 8 + addi t1, 0xA + or t1, t1, t2 + sw t1, PHY_BYTE_LANE_1_VDL_OVERRIDE_2(t0) + b vdl_override_cont + nop + +ddr_clk_200: + li a1, 0 // Set speed to 200MHz (0) + li t3, 0x1f // Set maximum VDL step size for 200MHz + b 1f + nop + +vdl_override_cont: + lw t2, PHY_BYTE_LANE_0_VDL_STATUS(t0) + andi t3, t2, 0x1f00 + srl t3, 8 + addi t3, t3, 0x4 // Add Stepsize 4 + +1: li t1, 0x110000 // Enable & Force Override + or t1, t3 // Fine rise and fine fall are set to 0 + + sw t1, PHY_CONTROL_REGS_STATIC_VDL_OVERRIDE(t0) + li t1, 0x0c + sw t1, DDR_CTL_DCMD(t0) // Set VDL + + SETLEDS1('P','H','Y','E') + +/* Program MC Timing Registers + + Read each timing parameter based on the speed and then create the + timing registers and program them. +*/ + LOADREL(t2, dram_timing_table) + + li t1, 0x10 // size of dram_timing_table element + mult t1, a1 + mflo t1 // dram_timing_table offset + add t2, t1 + + move t3, zero + lb t1, 0x00(t2) // tRCD + andi t1, 0xf + move t3, t1 + lb t1, 0x01(t2) // tCL + andi t1, 0xf + + move t4, t1 + and t4, 0x7 // Make sure that only 3 bits are written to DRAM's tCL field + sll t4, 20 + sw t4, DDR_CTL_DMODE_0 (t0) // Write tCL to the MRS register holder + + sll t1, 4 + or t3, t1 + lb t1, 0x02(t2) // tWR + andi t1, 0xf + + // Here we create the MRS register values + move t4, t1 + li t5, 1 + subu t4, t5 // tWR written to DRAM is 1 less than real tWR value + andi t4, 0x7 + sll t4, 25 + li t5, 0x01030000 // Sequential burst mode, burst of 8, reset DLL + or t4, t5 + lw t5, DDR_CTL_DMODE_0 (t0) + or t5, t4 + sw t5, DDR_CTL_DMODE_0 (t0) // Add tWR to the MRS register holder + + sll t1, 9 + or t3, t1 + lb t1, 0x03(t2) // tWL + andi t1, 0xf + sll t1, 12 + or t3, t1 + lb t1, 0x04(t2) // tRP + andi t1, 0xf + sll t1, 16 + or t3, t1 + lb t1, 0x05(t2) // tRRD + andi t1, 0xf + sll t1, 20 + or t3, t1 + lb t1, 0x06(t2) // tRC + andi t1, 0x1f + sll t1, 24 // tRCw + or t3, t1 + sw t3, DDR_CTL_TIM1_0(t0) // Program TIM1_0 register + + move t3, zero + lb t1, 0x06(t2) // tRC + andi t1, 0x1f + or t3, t1 // tRCr + lb t1, 0x07(t2) // tFAW + andi t1, 0x3f + sll t1, 8 + or t3, t1 + li t1, 0xff // tRFC = 0xff (Set to max value first. + sll t1, 16 // We'll fix it after we determine dram size) + or t3, t1 + + // We skip tFIFO since it needs to be 0 + + lb t1, 0x08(t2) // tW2R + andi t1, 0x3 + sll t1, 26 + or t3, t1 + lb t1, 0x09(t2) // tR2W + andi t1, 0x3 + sll t1, 28 + or t3, t1 + lb t1, 0x0a(t2) // tR2R + andi t1, 0x1 + sll t1, 30 + or t3, t1 + sw t3, DDR_CTL_TIM1_1(t0) // Program TIM1_1 register + + move t3, zero + lb t1, 0x0b(t2) // tAL + andi t1, 0xf + + // Here we create the EMRS register values + move t4, t1 + andi t4, 0x7 + sll t4, 3 + li t5, 0x384 // RTT=75ohm, OCD Enter + or t4, t5 + lw t5, DDR_CTL_DMODE_0 (t0) + or t5, t4 + sw t5, DDR_CTL_DMODE_0 (t0) // Store required values in EMRS holding register + + or t3, t1 + lb t1, 0x0c(t2) // tRTP + andi t1, 0x7 + sll t1, 4 + or t3, t1 + lb t1, 0x0d(t2) // tW2W + andi t1, 0x3 + sll t1, 8 + or t3, t1 + sw t3, DDR_CTL_TIM2(t0) // Program TIM2 register + +/* +// (tRRD is incremented by 1 due to tFAW bug for >=1Gb devices) + li t1, 0x18564c55 // tRCD=5,tWR=6,tCL=5,tWL=4,tRP=6,tRRD=5,tRCw=0x18 +// li t1, 0x13554a55 // tRCD=5,tWR=5,tCL=5,tWL=4,tRP=5,tRRD=5,tRCw=0x13 + sw t1, DDR_CTL_TIM1_0(t0) + li t1, 0x18330018 // tR2W=1,tR2R=0,tW2R=2,tFIFO=0,tRFC=0x33,tFAW=0,tRCr=0x18 +// li t1, 0x182b0013 // tR2W=1,tR2R=0,tW2R=2,tFIFO=0,tRFC=0x2b,tFAW=0,tRCr=0x13 + sw t1, DDR_CTL_TIM1_1(t0) + li t1, 0x00000034 // tAL=4 (tRCD-1), tRTP=3, tW2W=0 + sw t1, DDR_CTL_TIM2(t0) +*/ + +// Set x16 mode and Page policy + li t1, 0x100 + sw t1, DDR_CTL_DMODE_1(t0) + +// Enable ODT for writes + li t1, 0x104 + sw t1, DDR_CTL_ODT(t0) + +/***** Turn on CKE ***************/ + li t1, 0x35 + sw t1, DDR_CTL_DCMD(t0) + + li t1, 0x200 +2: + bnez t1, 2b + addi t1, -1 + +/***** Set arbitor for Burst Round Robin Mode ***/ + lw t1, DDR_CTL_ARB(t0) + or t1, 4 << 16 + sw t1, DDR_CTL_ARB(t0) + +/***** Issue Precharge All Banks Command ***/ + li t1, 0x32 + sw t1, DDR_CTL_DCMD(t0) + +/***** Issue EMRS2 Command ***/ + li t1, 0x0 + lw t2, DDR_CTL_DMODE_0 (t0) // Load previous value to t2 to preserve it + nop + sw t1, DDR_CTL_DMODE_0 (t0) + li t1, 0x38 + sw t1, DDR_CTL_DCMD(t0) + +/***** Issue EMRS3 Command***/ + li t1, 0x0 + sw t1, DDR_CTL_DMODE_0 (t0) + li t1, 0x39 + sw t1, DDR_CTL_DCMD(t0) + +// Enable DLL by issuing EMRS Command +// li t1, 0x0 +// sw t1, DDR_CTL_DMODE_0 (t0) + sw t2, DDR_CTL_DMODE_0 (t0) // Use the saved value back to DMODE_0 register + li t1, 0x30 + sw t1, DDR_CTL_DCMD(t0) + +/* +// Issue MRS Command tCL=5 tWL=4 + li t1, 0x0b530000 +// li t1, 0x07530000 // tCL=5 tWR=5, Reset DLL, Sequential Mode, Burst Length = 8 + sw t1, DDR_CTL_DMODE_0 (t0) + li t1, 0x31 + sw t1, DDR_CTL_DCMD(t0) +*/ +// Issue MRS Command. Set Reset DLL bit + li t1, 0x31 + sw t1, DDR_CTL_DCMD(t0) + +// Issue Precharge All Banks Command + li t1, 0x32 + sw t1, DDR_CTL_DCMD(t0) + +// Issue Autorefresh Command + li t1, 0x33 + sw t1, DDR_CTL_DCMD(t0) + li t1, 0x33 + sw t1, DDR_CTL_DCMD(t0) + + li t1, 0x200 +3: + bnez t1, 3b + addi t1, -1 + +/* +// Clear DLL Reset by Issuing MRS Command, tCL=5 tWL=4 + li t1, 0x0a530000 + sw t1, DDR_CTL_DMODE_0 (t0) + li t1, 0x31 + sw t1, DDR_CTL_DCMD(t0) +*/ + +// Issue MRS Command w/ DLL Reset bit set to 0 + lw t1, DDR_CTL_DMODE_0 (t0) + li t2, 0xFEFFFFFF // Reset DLL reset bit + and t1, t2 + sw t1, DDR_CTL_DMODE_0 (t0) + li t1, 0x31 + sw t1, DDR_CTL_DCMD(t0) + +/* +// Issue EMRS Command (Enter OCD Calibration) + li t1, 0x380 + sw t1, DDR_CTL_DMODE_0 (t0) + li t1, 0x30 + sw t1, DDR_CTL_DCMD(t0) +*/ + +// Issue EMRS Command (Enter OCD Calibration) 75 Ohm, Full strength Drive, tAL=tRCD-1 + li t1, 0x30 + sw t1, DDR_CTL_DCMD(t0) + +// Issue EMRS Command (Exit OCD Calibration) + lw t1, DDR_CTL_DMODE_0 (t0) + li t2, 0xFC7F // Reset OCD field for exit mode + and t1, t2 + sw t1, DDR_CTL_DMODE_0 (t0) + li t1, 0x30 + sw t1, DDR_CTL_DCMD(t0) + +// Check x8 or x16 DDR + li t1, 0x12345678 + li t3, 0xA0000000 + sw zero, 0(t3) + sw t1, 0(t3) + lw t2, 0(t3) + bne t1, t2, 3f // Failed + nop +// Do the test twice. Just in case random values match... + li t1, 0x87654321 + sw t1, 0(t3) + lw t2, 0(t3) + beq t1, t2, 1f // Clock lines are enabled as needed + nop + +3: +// Memory test failed. Need to re-enable byte lane 1 clock + sw zero, PHY_BYTE_LANE_1_CLOCK_PAD_DISABLE(t0) + li t1, 0x200 +2: + bnez t1, 2b // Delay after enabling clocks + addi t1, -1 + b ddr_x8 + nop + +1: +// Find memory size. a3 keeps the size: 0=256Mb, 1=512Mb, 2=1Gb, 3=2Gb +// Start from 2Gb device + LOADREL(t7, dram_map_table_x8) + lw t1, PHY_BYTE_LANE_1_CLOCK_PAD_DISABLE(t0) + beqz t1, 1f + nop + LOADREL(t7, dram_map_table_x16) + +1: + li a3, 4 +ddr_size: + addi a3, -1 + + li t1, 0x2c // size of dram_map_table element + mult t1, a3 + mflo t2 // dram_map_table offset + add t2, t7 + + lw t1, 0x00(t2) // Row00_0 + sw t1, DDR_CTL_ROW00_0(t0) + + lw t1, 0x04(t2) // Row00_1 + sw t1, DDR_CTL_ROW00_1(t0) + + lw t1, 0x08(t2) // Row01_0 + sw t1, DDR_CTL_ROW01_0(t0) + + lw t1, 0x0C(t2) // Row01_1 + sw t1, DDR_CTL_ROW01_1(t0) + + lw t1, 0x10(t2) // Col00_0 + sw t1, DDR_CTL_COL00_0(t0) + + lw t1, 0x14(t2) // Col00_1 + sw t1, DDR_CTL_COL00_1(t0) + + lw t1, 0x18(t2) // Col01_0 + sw t1, DDR_CTL_COL01_0(t0) + + lw t1, 0x1C(t2) // Col01_1 + sw t1, DDR_CTL_COL01_1(t0) + + lw t1, 0x20(t2) // Bank + sw t1, DDR_CTL_BNK10(t0) + + li t1, 0x0 // CS_Start + sw t1, DDR_CTL_CSST(t0) + + lw t1, 0x24(t2) // CS_End + sw t1, DDR_CTL_CSEND(t0) + + li t1, 0x0 // CS Interleaving CFG + sw t1, DDR_CTL_CNFG(t0) + + lw t3, 0x28(t2) // Dram Size + lw t1, DDR_CTL_GCFG(t0) // GCFG + li t2, 0xFFFFFF00 + and t1, t1, t2 // Mask out Dram Size Fields + or t1, t3, t1 // insert new DRAM Size value + sw t1, DDR_CTL_GCFG(t0) + beqz a3, ddr_speed + nop + +// Check for memory aliasing +// This assumes that the bank interleaving is below address bits 8. + li t1, 8 + li t2, 24 + add t2, a3 // Scan up to maximum memory size + li t3, 0xA0000000 + +check_alias: + li t4, 1 + sll t4, t1 + add t4, t3 + + sw zero, 0(t3) + li t5, -1 + sw t5, 0(t4) + lw t6, 0(t3) + + beq t5, t6, ddr_size + nop + + bne t1, t2, check_alias + addi t1, 1 + +ddr_speed: + li t1, 3 + lw t2, PHY_BYTE_LANE_1_CLOCK_PAD_DISABLE(t0) + beqz t2, 1f + nop + li t1, 2 +1: + blt a3, t1, tRefi_update // If smaller than 1Gb device, keep tRRD same + nop + + lw t1, DDR_CTL_TIM1_0(t0) // Load DDR_CTL_TIM1_0 register + move t2, t1 + srl t2, 20 + andi t2, 0xf + addi t2, 1 // Increment ttRRD by one (software work around for a bug) + sll t2, 20 + li t3, 0xFF0FFFFF + and t1, t3 // Clear tRRD field + or t1, t2 // Insert the new tRRD value + sw t1, DDR_CTL_TIM1_0(t0) // Store DDR_CTL_TIM1_0 register + nop + +tRefi_update: + LOADREL(t2, dram_tRefi_table) + + li t1, 0x4 // size of dram_tRefi_table entry + mult t1, a1 + mflo t1 // dram_tRefi_table offset + add t2, t1 + + lw t1, 0x0(t2) // tRefi + sll t1, 8 + sw t1, DDR_CTL_CLKS(t0) + + LOADREL(t2, dram_tRFC_table) + + li t1, 0x4 // size of dram_tRFC_table entry + mult t1, a1 + mflo t1 // dram_tRefi_table offset + add t2, t1 // Calculate address in the row + + li t1, 0xc // size of dram_tRFC_table row + mult t1, a3 + mflo t1 // dram_tRefi_table offset + add t2, t1 // Calculate address in the column + + lw t3, 0x0(t2) // Load tRFC value + andi t3, 0xFF // Mask tRFC to 8-bits + sll t3, 16 // Move it to bit location [23:16] + + lw t1, DDR_CTL_TIM1_1(t0) // Load DDR_CTL_TIM1_1 register + li t2, 0xFF00FFFF + and t1, t1, t2 // Mask out tRFC Field + or t1, t3, t1 // insert new tRFC value + sw t1, DDR_CTL_TIM1_1(t0) // Write to TIM1_1 register + + SETLEDS1('D','I','N','T') + +/***** UBUS align to MEMC *****/ +align_memc: + +/*** check MEMC clk ratio to set sampling freq *****/ + li t2, MISC_BASE + lw t1, MISC_STRAP_BUS(t2) + + srl t1, MISC_STRAP_BUS_MIPS_PLL_FVCO_SHIFT + andi t1, 0x1f // Mask out strap bits + +#if defined(_BCM96816_) + LOADREL(t2, periph_fix_table) + lw t2, 0(t2) + srl t2, t1 + andi t2, 1 + bne t2, zero, 2f +#endif + + LOADREL(t2, memc_ubus_ratio_table) + + add t2, t1 + lb t1, 0x00(t2) + sll t4,t1,28 // Update Sampling Period Field + +pi_ubus: + li t2, 4048 + li t3, 1 + + sw zero, DDR_CTL_PI_GCF(t0) + li t1, 0x00001c0b // send feedback command every 11 cycles + or t1, t1, t4 + sw t1, DDR_CTL_PI_UBUS_SMPL(t0) + ori t1, 0x80 // trigger stoke signal to latch in new counter value + sw t1, DDR_CTL_PI_UBUS_SMPL(t0) + li t1, 0x00040000 // send new phase value to PLL every 5 cycles + sw t1, DDR_CTL_PI_UBUS_CTL(t0) + li t1, 0x00000001 // enable enable counter that change PLL phase + sw t1, DDR_CTL_PI_GCF(t0) + nop + +#if defined (_BCM96328_) || defined(_BCM96362_) +// Enable PHY MIPS PI + li t1, 0x00130000 + sw t1, DDR_CTL_PI_DSL_MIPS_CTL(t0) + nop +#endif + +1: + lw t4, DDR_CTL_PI_UBUS_SMPL(t0) // Read a sample value. + srl t4, 16 // The sample is in the upper 16 bits. + + andi t4, t4, 0x22 // Look at the 2 outermost bits; if the LSB is 0 and the MSB is 1, + beq t4, 0x20, 2f // then there is an edge somewhere in the sample. + nop + lw t5, DDR_CTL_PI_UBUS_CTL(t0) + and t5, 0xffff0000 + or t5, t3 + or t5, (1<<14) // move phase in positive direction + sw t5, DDR_CTL_PI_UBUS_CTL(t0) + nop + lw t5, DDR_CTL_PI_UBUS_CTL(t0) // Delay before reading another sample. + add t3, 1 + bne t2, t3, 1b + nop + + SETLEDS1('U','A','S','Y') + SETLEDS1('L','A','S','Y') + SETLEDS1('M','A','S','Y') + b run_async // failed to set sync mode + nop + +2: +/*** check MIPS clk ratio *****/ + li t4, 0xff410010 + li t2, MISC_BASE + lw t1, MISC_STRAP_BUS(t2) + + srl t1, MISC_STRAP_BUS_MIPS_PLL_FVCO_SHIFT + andi t1, 0x1f // Mask out strap bits + + b _mips_align_2_ubus // none of the above means it is either 1/1 or 2/1 + nop + + +_mips_align_2_ubus: + +/***** MIPS align to UBUS *****/ + li t1, 0xff410000 + + li t2, 0x00040000 // update PLL phase value every 5 MC cycles + sw t2, DDR_CTL_PI_MIPS_CTL(t0) + + li t2, 0xc0001c03 // force update on mclk_period + sw t2, 0x40(t1) + li t2, 0x80001c83 + sw t2, 0x40(t1) + + lw t2, DDR_CTL_PI_MIPS_CTL(t0) // add delay + li t3, 1 + +1: lw t4, 0x40(t1) // Read a sample value. + srl t4, 16 // The sample is in the upper 16 bits. + + andi t4, t4, 0x22 // Look at the 2 outermost bits, if the LSB is 0 and the MSB is 1, + beq t4, 0x20, 2f // then there is an edge somewhere in the sample. + nop + lw t5, DDR_CTL_PI_MIPS_CTL(t0) + and t5, 0xffff0000 + or t5, t3 + or t5, (1<<14) // move phase in positive direction + sw t5, DDR_CTL_PI_MIPS_CTL(t0) + nop + lw t5, DDR_CTL_PI_MIPS_CTL(t0) // Delay before reading another sample. + add t3, 1 + bne t2, t3, 1b + nop + + SETLEDS1('U','A','S','Y') + SETLEDS1('L','A','S','Y') + SETLEDS1('M','A','S','Y') + b run_async // failed to set sync mode + nop +2: + // Success + lw t2, DDR_CTL_PI_MIPS_CTL(t0) // Turn on auto-PI mode. + or t2, (1 << 20) // PI_UBUS_CTL_Hw_Cntr_En = 1 + sw t2, DDR_CTL_PI_MIPS_CTL(t0) + + /**----- Enable DDR/UBUS and DDR/LMB sync mode ------------------**/ + /*** only MIPS in sync mode for these strap options */ + + li t2, MISC_BASE + lw t1, MISC_STRAP_BUS(t2) + + srl t1, MISC_STRAP_BUS_MIPS_PLL_FVCO_SHIFT + andi t1, 0x1f // Mask out strap bits + + li t3, 0 // Used to keep MC/MIPS and MC/UBUS sync/async mode + + LOADREL(t2, dram_sync_table) + + lw t4, 0x0(t2) // Ubus Sync vector + lw t5, 0x4(t2) // Lmb Sync vector + +#if defined (_96816_) + move t4, t6 +#endif + lw t6, 0x8(t2) // Mips Sync vector + + srl t4, t1 // Get the ubus sync flag + srl t5, t1 // Get the lmb sync flag + srl t6, t1 // Get the mips sync flag + andi t4, 1 // Mask out other bits + andi t5, 1 // Mask out other bits + andi t6, 1 // Mask out other bits + + li t2, 1 + bne t4, t2, ubus_async // 1f below. If ubus is not sync, lmb can't be in sync + nop // Go to ubus_async (1f) + + // Ubus Sync Mode. Turn on Ubus Clock tracking + lw t2, DDR_CTL_PI_UBUS_CTL(t0) // Turn on auto-PI mode. + or t2, (1 << 20) // PI_UBUS_CTL_Hw_Cntr_En = 1 + sw t2, DDR_CTL_PI_UBUS_CTL(t0) + + // Is LMB Sync as well? + li t2, 1 + beq t5, t2, memc_all_sync // If both ubus and lmb are sync, go to memc_all_sync + nop + +memc_ubus_sync: +#if UBUS_SYNC_ENABLE +// set MC/UBUS to SYNC + li t3, 0x4 + SETLEDS1('L','A','S','Y') + SETLEDS1('U','S','Y','N') +#else +// set MC/UBUS to ASYNC + li t3, 0xc + SETLEDS1('L','A','S','Y') + SETLEDS1('U','A','S','Y') +#endif + + b update_sync_mode + nop + +memc_all_sync: +#if LMB_SYNC_ENABLE +// set MC/MIPS to SYNC + nop + SETLEDS1('L','S','Y','N') +#else +// set MC/MIPS to ASYNC + li t1, 0x4 + or t3, t1 + SETLEDS1('L','A','S','Y') +#endif +#if UBUS_SYNC_ENABLE +// set MC/UBUS to SYNC + nop + SETLEDS1('U','S','Y','N') +#else +// set MC/UBUS to ASYNC + li t1, 0x8 + or t3, t1 + SETLEDS1('U','A','S','Y') +#endif + +update_sync_mode: + li t1, MISC_BASE + sw t3, MISC_MEMC_CONTROL(t1) + b 2f + nop +1: +ubus_async: + SETLEDS1('L','A','S','Y') + SETLEDS1('U','A','S','Y') + +2: + // Can Mips run in sync mode? If not, skip all below + beq t6, zero, run_async + nop + +#if MIPS_SYNC_ENABLE + /**----- Clear MIPS Async mode bit ------------------------------**/ + mfc0 t1, C0_BCM_CONFIG, 5 + and t1, ~(0x1 << 28) + mtc0 t1, C0_BCM_CONFIG, 5 + + SETLEDS1('M','S','Y','N') +#else + SETLEDS1('M','A','S','Y') +#endif + +3: + /**----- Enable RAC and LMB -------------------------------------**/ + li t0, MIPS_BASE + lw t2, MIPS_LMB_CR(t0) +#if LMB_ENABLE + or t2, LMB_EN // Enable LMB + SETLEDS1('L','M','B','E') +#else + SETLEDS1('L','M','B','D') +#endif + sw t2, MIPS_LMB_CR(t0) + + li t2, 0xFFF << RAC_UPB_SHFT // Enable prefetch for RAM address range up to 256MB + sw t2, MIPS_RAC_ARR(t0) + + lw t2, MIPS_RAC_CR0(t0) + or t2, (RAC_C_INV | RAC_I | RAC_PF_I) + sw t2, MIPS_RAC_CR0(t0) + + lw t2, MIPS_RAC_CR1(t0) + or t2, (RAC_C_INV | RAC_I | RAC_PF_I) + sw t2, MIPS_RAC_CR1(t0) + +run_async: + /**----- Enable branch prediction and non-blocking data cache ---**/ + mfc0 t1, C0_BCM_CONFIG + and t1, ~CP0_BCM_CFG_BTHD + or t1, CP0_BCM_CFG_NBK + or t1, CP0_BCM_CFG_CLF + mtc0 t1, C0_BCM_CONFIG + +#if DDR_TEST +####################################### +# Run test on DRAM using Test Engine # +####################################### +#define BACKGND_MODE_DATA 0x0 +#define BACKGND_MODE_LFSR 0x400 +#define BACKGND_MODE_PRBS 0x800 +#define BACKGND_MODE_NOT_PRBS 0xc00 +#define BACKGND_MODE_PAT 0x1000 +#define BACKGND_MODE_NOT_PAT 0x1400 + +#define VICT_MODE_PRBS 0 +#define VICT_MODE_NOT_PRBS 0x100 +#define VICT_MODE_PAT 0x200 +#define VICT_MODE_NOT_PAT 0x300 + +#define VICT_ENABLE 0x8000 +#define VICT_SWEEP_ENABLE 0x10000 +#define VICT_COUNT 0x0 + +#define PRBS_ORDER(x) ((x & 0x3) << 13) + +#define TEST_COUNT 0x1000 +#define TEST_ADDR 0x0 +#define TEST_ADDR_UPDT 0x1 +#define TEST_PATTERN0 0x5555 +#define TEST_PATTERN1 0xaaaa +#define TEST_PATTERN (TEST_PATTERN1 << 16 | TEST_PATTERN0) + +#define TEST_ENABLE 0x1 +#define TEST_DONE 0x2 +#define TEST_ERROR 0x4 +#define TEST_WRITE 0x10 +#define TEST_READ 0x0 + +#define BACKGND_DATA0 0xa5a5a5a5 +#define BACKGND_DATA1 0x5a5a5a5a +#define BACKGND_DATA2 0xa5a5a5a5 +#define BACKGND_DATA3 0x5a5a5a5a + +#define TEST_DATA0 0x02468ace +#define TEST_DATA1 0x13579bdf +#define TEST_DATA2 0x33cccc33 +#define TEST_DATA3 0x55aaaa55 + +/***** Load DDR Base *************************************/ + li t0, DDR_BASE + li t1, BACKGND_DATA0 + sw t1, DDR_CTL_TEST_DATA0(t0) + li t1, BACKGND_DATA1 + sw t1, DDR_CTL_TEST_DATA1(t0) + li t1, BACKGND_DATA2 + sw t1, DDR_CTL_TEST_DATA2(t0) + li t1, BACKGND_DATA3 + sw t1, DDR_CTL_TEST_DATA3(t0) + li t1, TEST_COUNT + li t2, VICT_COUNT + or t1, t2 # add victim count value + sw t1, DDR_CTL_TEST_COUNT(t0) + li t1, TEST_ADDR + sw t1, DDR_CTL_TEST_ADDR(t0) + li t1, TEST_ADDR_UPDT + sw t1, DDR_CTL_TEST_ADDR_UPDT(t0) + li t1, TEST_PATTERN + sw t1, DDR_CTL_TEST_PAT(t0) + +# Write a background pattern first + li t1, BACKGND_MODE_DATA + li t2, TEST_WRITE + or t1, t2 + li t2, TEST_ENABLE + or t1, t2 + sw t1, DDR_CTL_TEST_CFG1(t0) + + li t2, 0x2 + li t3, MISC_BASE + + li t5, 0x10000 +2: li t1, 0x100 +1: addiu t1, -1 + bnez t1, 1b + nop + + lw t4, MISC_MEMC_CONTROL(t3) + and t4, 0x2 + beq t4, t2, backgnd_write_done + nop + addiu t5, -1 + bnez t5, 2b + nop + +# Background write operation is finished + +backgnd_write_done: + li t1, TEST_DATA0 + sw t1, DDR_CTL_TEST_DATA0(t0) + li t1, TEST_DATA1 + sw t1, DDR_CTL_TEST_DATA1(t0) + li t1, TEST_DATA2 + sw t1, DDR_CTL_TEST_DATA2(t0) + li t1, TEST_DATA3 + sw t1, DDR_CTL_TEST_DATA3(t0) + li t1, TEST_COUNT + li t2, VICT_COUNT + or t1, t2 # add victim count value + sw t1, DDR_CTL_TEST_COUNT(t0) + li t1, TEST_ADDR + sw t1, DDR_CTL_TEST_ADDR(t0) + li t1, TEST_ADDR_UPDT + sw t1, DDR_CTL_TEST_ADDR_UPDT(t0) + li t1, TEST_PATTERN + sw t1, DDR_CTL_TEST_PAT(t0) + +# li t1, BACKGND_MODE_DATA +# li t1, BACKGND_MODE_PAT +# li t2, VICT_MODE_NOT_PAT + li t1, BACKGND_MODE_PRBS + li t2, VICT_MODE_NOT_PRBS + + or t1, t2 + li t2, VICT_ENABLE + or t1, t2 + li t2, VICT_SWEEP_ENABLE + or t1, t2 + li t2, PRBS_ORDER(0) + or t1, t2 + li t2, TEST_WRITE + or t1, t2 + li t2, TEST_ENABLE + or t1, t2 + sw t1, DDR_CTL_TEST_CFG1(t0) + + li t2, 0x2 + li t3, MISC_BASE + + li t5, 0x10000 +2: li t1, 0x100 +1: addiu t1, -1 + bnez t1, 1b + nop + + lw t4, MISC_MEMC_CONTROL(t3) + and t4, 0x2 + beq t4, t2, test_write_done + nop + addiu t5, -1 + bnez t5, 2b + nop + +# Test write operation is finished + +test_write_done: + li t1, TEST_DATA0 + sw t1, DDR_CTL_TEST_DATA0(t0) + li t1, TEST_DATA1 + sw t1, DDR_CTL_TEST_DATA1(t0) + li t1, TEST_DATA2 + sw t1, DDR_CTL_TEST_DATA2(t0) + li t1, TEST_DATA3 + sw t1, DDR_CTL_TEST_DATA3(t0) + li t1, TEST_COUNT + li t2, VICT_COUNT + or t1, t2 # add victim count value + sw t1, DDR_CTL_TEST_COUNT(t0) + li t1, TEST_ADDR + sw t1, DDR_CTL_TEST_ADDR(t0) + li t1, TEST_ADDR_UPDT + sw t1, DDR_CTL_TEST_ADDR_UPDT(t0) + li t1, TEST_PATTERN + sw t1, DDR_CTL_TEST_PAT(t0) + +# li t1, BACKGND_MODE_DATA +# li t1, BACKGND_MODE_PAT +# li t2, VICT_MODE_NOT_PAT + li t1, BACKGND_MODE_PRBS + li t2, VICT_MODE_NOT_PRBS + + or t1, t2 + li t2, VICT_ENABLE + or t1, t2 + li t2, VICT_SWEEP_ENABLE + or t1, t2 + li t2, PRBS_ORDER(0) + or t1, t2 + li t2, TEST_READ + or t1, t2 + li t2, TEST_ENABLE + or t1, t2 + sw t1, DDR_CTL_TEST_CFG1(t0) + + li t3, MISC_BASE + li t2, 0x2 + + li t5, 0x10000 +2: li t1, 0x100 +1: addiu t1, -1 + bnez t1, 1b + nop + + lw t4, MISC_MEMC_CONTROL(t3) + and t4, 0x2 + beq t4, t2, test_read_done + nop + addiu t5, -1 + bnez t5, 2b + nop + +# Test read operation is finished + +test_read_done: + lw t1, DDR_CTL_TEST_CFG1(t0) + srl t1, 2 + and t1, 1 + beq t1, zero, test_passed + nop + +test_failed: + SETLEDS1('F','A','I','L') + b 1f + nop +test_passed: + SETLEDS1('P','A','S','S') +1: + SETLEDS1('-','-','-', '-') +#endif + + move ra,s0 + j ra + nop + + .set reorder + +END(board_draminit) + +/* ********************************************************************* + * BOARD_SETLEDS(x) + * + * Set LEDs for boot-time progress indication. Not used if + * the board does not have progress LEDs. This routine + * must not call any other routines, since it may be invoked + * either from KSEG0 or KSEG1 and it may be invoked + * whether or not the icache is operational. + * + * Input parameters: + * a0 - LED value (8 bits per character, 4 characters) + * + * Return value: + * nothing + * + * Registers used: + * t7,t8,t9 + ********************************************************************* */ +LEAF(board_setleds) +#if 1 + li t7, UART_BASE + li t8, TXFIFOEMT + +1: lh t9, UART0INTSTAT(t7) + and t9, t8 + bne t9, t8, 1b + + srl t8, a0, 24 + sb t8, UART0DATA(t7) + srl t8, a0, 16 + sb t8, UART0DATA(t7) + srl t8, a0, 8 + sb t8, UART0DATA(t7) + sb a0, UART0DATA(t7) + li a0, '\r' + sb a0, UART0DATA(t7) + li a0, '\n' + sb a0, UART0DATA(t7) +#endif + j ra +END(board_setleds) + +/* ********************************************************************* + * BCMCORE_TP1_SWITCH() + * + * Check if the thread switch is required. If we are already + * running on thread 1 this function will do nothing and just return + * If we are running on thread 0 this function will take thread 1 + * out of reset and put thread 0 to sleep waiting for singnal from + * thread 1. + * + * Input parameters: + * nothing + * + * Return value: + * nothing + ********************************************************************* */ +LEAF(bcmcore_tp1_switch) + +#if defined(_BCM96328_) + li t1, OTP_BASE + addi t1, OTP_USER_BITS + addi t1, 0xc - ((OTP_TP1_DISABLE_BIT / 8) & ~3) + lw t0, 0(t1) + andi t0, 1 << (OTP_TP1_DISABLE_BIT % 32) + beqz t0, 1f + j ra +1: +#endif + mfc0 t1, C0_BCM_CONFIG, 3 + li t2, CP0_CMT_TPID + and t1, t2 + bnez t1, tp1 # Already running on thread 1 + +# Start TP1 +# Set boot address for TP1 + li t1, MIPS_BASE + li t2, 0x98000000 | ENABLE_ALT_BV + sw t2, MIPS_TP1_ALT_BV(t1) + +# Set a flag so we can wait for TP1 to catch up + li t1, 0x0 + mtc0 t1, $31 # CO_DESAVE + +# Take TP1 out of reset + mfc0 t1, C0_BCM_CONFIG, 2 + or t1, CP0_CMT_RSTSE + mtc0 t1, C0_BCM_CONFIG, 2 + + /* wait until second thread catches up with the first */ +waittp1: + mfc0 t0, $31 # CO_DESAVE + beqz t0, waittp1 + + li t0, THREAD_NUM_ADDRESS + FIXUP(t0) + lw t0, 0(t0) + li t1, 1 + bne t0, t1, return # Linux will run on TP0, continue running bootloader + +# Voice will run on TP0. Set it up and put it to sleep + + # enable interrupts and enable SW IRQ 0 + li t0, M_SR_IE | M_SR_IBIT1 + mtc0 t0, C0_SR + + # Set up to use alternate exception vector 0x80000200 + li t0, M_CAUSE_IV + mtc0 t0, C0_CAUSE + + mfc0 t1, C0_BCM_CONFIG, 1 + # set all ints except IRQ1 to TP1 and cross over SW IRQ 0 + or t1, (CP0_CMT_XIR_4 | CP0_CMT_XIR_3 | CP0_CMT_XIR_2 | CP0_CMT_XIR_0 | CP0_CMT_SIR_0 | CP0_CMT_NMIR_TP1) + mtc0 t1, C0_BCM_CONFIG, 1 + + mfc0 t1, C0_BCM_CONFIG, 2 + # Set debug on TP1, give priority to TP0, and + # set TLB exception serialization to ignore SCNT value in CP0 reg22 sel 4 + and t1, ~CP0_CMT_TPS_MASK; + or t1, (CP0_CMT_DSU_TP1 | CP0_CMT_PRIO_TP0 | (1 << CP0_CMT_TPS_SHFT)) + mtc0 t1, C0_BCM_CONFIG, 2 + + # Enable Data RAC on TP0 + li t1, MIPS_BASE + lw t2, MIPS_RAC_CR0(t1) + or t2, (RAC_D | RAC_PF_D) + sw t2, MIPS_RAC_CR0(t1) + +2: + b wait_for_wake + +tp1: +# Running on TP1.... +# First signal to TP0 that TP1 is up + li t1, 0x1 + mtc0 t1, $31 # CO_DESAVE + + li t0, THREAD_NUM_ADDRESS + FIXUP(t0) + lw t0, 0(t0) + li t1, 1 + beq t0, t1, return # Linux will run on TP1, continue running bootloader + +# Voice will run on TP1. Set it up and put it to sleep + + # enable interrupts and enable SW IRQ 0 + li t0, M_SR_IE | M_SR_IBIT1 + mtc0 t0, C0_SR + + # Set up to use alternate exception vector 0x80000200 + li t0, M_CAUSE_IV + mtc0 t0, C0_CAUSE + + mfc0 t1, C0_BCM_CONFIG, 1 + # set IRQ1 to TP1 and cross over SW IRQ 0 + or t1, (CP0_CMT_XIR_1 | CP0_CMT_SIR_0 | CP0_CMT_NMIR_TP0) + mtc0 t1, C0_BCM_CONFIG, 1 + + mfc0 t1, C0_BCM_CONFIG, 2 + # Set debug on TP0, give priority to TP1, and + # set TLB exception serialization to ignore SCNT value in CP0 reg22 sel 4 + and t1, ~CP0_CMT_TPS_MASK; + or t1, (CP0_CMT_PRIO_TP1 | (1 << CP0_CMT_TPS_SHFT)) + mtc0 t1, C0_BCM_CONFIG, 2 + + # Enable Data RAC on TP1 + li t1, MIPS_BASE + lw t2, MIPS_RAC_CR1(t1) + or t2, (RAC_D | RAC_PF_D) + sw t2, MIPS_RAC_CR1(t1) + b 2b + +return: + j ra + +END(bcmcore_tp1_switch) + +# align this code to cache line. NAND flash is not memory mapped after system boots +# so when we are signaling to the second TP to wake we need +# jal instruction to be in cache + .align 4 +LEAF(wait_for_wake) + sync + wait # wait for interrupt + jal t8 # jump to entry point +END(wait_for_wake) diff --git a/cfe/cfe/arch/mips/board/bcm63xx_rom/src/bcm63xx_main.c b/cfe/cfe/arch/mips/board/bcm63xx_rom/src/bcm63xx_main.c new file mode 100755 index 0000000..201d6d8 --- /dev/null +++ b/cfe/cfe/arch/mips/board/bcm63xx_rom/src/bcm63xx_main.c @@ -0,0 +1,649 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Main Module File: bcm63xxBoot_main.c + * + * This module contains the main "C" routine for CFE bootstrap loader + * and decompressor to decompress the real CFE to ram and jump over. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * Revised: seanl + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_iocb.h" +#include "cfe_device.h" +#include "cfe_console.h" +#include "cfe_timer.h" + +#include "env_subr.h" +#include "ui_command.h" +#include "cfe_mem.h" +#include "cfe.h" + +#include "bsp_config.h" +#include "bcm_hwdefs.h" +#include "bcm_map.h" + +#include "exception.h" + +#include "segtable.h" + +#include "initdata.h" + +#if defined(_BCM96368_) || defined(_BCM96362_) || defined(_BCM96328_) || defined(_BCM96816_) +#include "flash_api.h" +#include "jffs2.h" +#endif + +#if CFG_PCI +#include "pcivar.h" +#endif + + + +int cfe_size_ram(void); +inline static int is_aliased(int max_bits) __attribute__((always_inline)); + +/* ********************************************************************* + * Constants + ********************************************************************* */ + +#ifndef CFG_STACK_SIZE +#define STACK_SIZE 8192 +#else +#define STACK_SIZE ((CFG_STACK_SIZE+1023) & ~1023) +#endif + +inline static int is_aliased(int max_bits) +{ + volatile uint32 *mem_base; + volatile uint32 *test_ptr; + uint32 tmp; + int bit; + int res = 0; + + mem_base = (uint32*)DRAM_BASE_NOCACHE; + + *mem_base = 0; + + for (bit = 8; bit < max_bits; bit++) { + test_ptr = (uint32*)((uint32)mem_base | 1 << bit); + /* ram may contain useful data, save location before modifying */ + tmp = *test_ptr; + *test_ptr = -1; + if (*mem_base == *test_ptr) { + *test_ptr = tmp; + res = 1; + break; + } + *test_ptr = tmp; + } + return res; +} + +#define MEMC_MAX_ROWS 14 + +int cfe_size_ram(void) +{ +#if !(defined(_BCM96328_) || defined (_BCM96362_) || defined(_BCM96816_)) + uint32 col_bits, row_bits, bus_bits, bank_bits; + uint32 size; + + /* Bus width is configured during early boot */ + if (((MEMC->Config & MEMC_WIDTH_MASK) >> MEMC_WIDTH_SHFT) == MEMC_32BIT_BUS) + bus_bits = 2; + else + bus_bits = 1; + + bank_bits = 2; + /* Start from setting to the lowest possible configuration */ + col_bits = 8; + row_bits = 11; + + MEMC->Config &= ~MEMC_COL_MASK; + MEMC->Config |= ((col_bits - 8) << MEMC_COL_SHFT); + + MEMC->Config &= ~MEMC_ROW_MASK; + MEMC->Config |= ((row_bits - 11) << MEMC_ROW_SHFT); + + /* Determine number of rows */ + for (row_bits = 12; row_bits <= MEMC_MAX_ROWS; row_bits++) { + MEMC->Config &= ~MEMC_ROW_MASK; + MEMC->Config |= ((row_bits - 11) << MEMC_ROW_SHFT); + /* check if this address bit is valid */ + if (is_aliased (col_bits + row_bits + bus_bits + bank_bits)) + break; + } + row_bits -= 1; + MEMC->Config &= ~MEMC_ROW_MASK; + MEMC->Config |= ((row_bits - 11) << MEMC_ROW_SHFT); + + /* Determine number of columns */ + for (col_bits = 9; col_bits <= 11; col_bits++) { + MEMC->Config &= ~MEMC_COL_MASK; + MEMC->Config |= ((col_bits - 8) << MEMC_COL_SHFT); + /* check if this address bit is valid */ + if (is_aliased (col_bits + row_bits + bus_bits + bank_bits)) + break; + } + col_bits -= 1; + MEMC->Config &= ~MEMC_COL_MASK; + MEMC->Config |= ((col_bits - 8) << MEMC_COL_SHFT); + + /* Compute memory size in MB */ + size = 1 << (bus_bits + col_bits + row_bits + bank_bits - 20); + + return size; +#else + return (DDR->CSEND << 24); +#endif +} + +// fake functions for not to modifying init_mips.S +void _exc_entry(void); +void cfe_command_restart(void); +void cfe_doxreq(void); + +void _exc_entry(void) +{ +} + +void cfe_command_restart(void) +{ +} +void cfe_doxreq(void) +{ +} + +/* ********************************************************************* + * Externs + ********************************************************************* */ + +void cfe_main(int,int); + +/* ********************************************************************* + * Globals + ********************************************************************* */ + +void cfe_ledstr(const char *leds) +{ +} + +#if !defined(CONFIG_BRCM_IKOS) +extern void _binArrayStart(void); +extern void _binArrayEnd(void); +extern int decompressLZMA(unsigned char *in, unsigned insize, unsigned char *out, unsigned outsize); + +#if (INC_NAND_FLASH_DRIVER==1) || (INC_SPI_PROG_NAND==1) +#define je16_to_cpu(x) ((x).v16) +#define je32_to_cpu(x) ((x).v32) +extern void rom_nand_flash_init(void); +extern int nand_flash_get_sector_size(unsigned short sector); +extern int nand_flash_get_numsectors(void); +extern int nand_flash_read_buf(unsigned short blk, int offset, + unsigned char *buffer, int len); +extern void board_setleds(unsigned long); + +void *lib_memcpy(void *dest,const void *src,size_t cnt) +{ + unsigned char *d; + const unsigned char *s; + + d = (unsigned char *) dest; + s = (const unsigned char *) src; + + while (cnt) { + *d++ = *s++; + cnt--; + } + + return dest; +} + +int lib_memcmp(const void *dest,const void *src,size_t cnt) +{ + const unsigned char *d; + const unsigned char *s; + + d = (const unsigned char *) dest; + s = (const unsigned char *) src; + + while (cnt) { + if (*d < *s) return -1; + if (*d > *s) return 1; + d++; s++; cnt--; + } + + return 0; +} + +#if (INC_NAND_FLASH_DRIVER==1) +/* Find uncompressed file cferam.bin on the JFFS2 file system, load it into + * memory and jump to its entry point function. + */ +char g_fname[] = NAND_CFE_RAM_NAME; +int g_fname_actual_len = sizeof(g_fname) - 1; +int g_fname_cmp_len = sizeof(g_fname) - 4; /* last three are digits */ +static void bootImageFromNand(void) +{ + const unsigned long bv_invalid = 0xfffffff; + const int max_not_jffs2 = 10; + + struct rootfs_info + { + int rootfs; + int start_blk; + int end_blk; + unsigned long boot_val; + unsigned long ino; + } rfs_info[2], *prfs_info[2], *rfsi; + + unsigned char *buf = (unsigned char *) mem_heapstart; + unsigned long version = 0; + struct jffs2_raw_dirent *pdir; + struct jffs2_raw_inode *pino; + unsigned char *p; + int i, j, k, done, not_jffs2; + int num_blks; + int len; + int boot_prev; + PNVRAM_DATA nd; + static int err0=0, err1=1; + + rom_nand_flash_init(); + num_blks = nand_flash_get_numsectors(); + len = nand_flash_get_sector_size(0); + nd = (PNVRAM_DATA) (buf + len); + + NAND->NandNandBootConfig = NBC_AUTO_DEV_ID_CFG | 0x101; + NAND->NandCsNandXor = 1; + + memcpy((unsigned char *) nd, (unsigned char *) + FLASH_BASE + NVRAM_DATA_OFFSET, sizeof(NVRAM_DATA)); + + NAND->NandNandBootConfig = NBC_AUTO_DEV_ID_CFG | 0x2; + NAND->NandCsNandXor = 0; + + /* Look at config to determine whether to boot current or previous image.*/ + for( i = 0, p = (unsigned char *) nd->szBootline, boot_prev = 0; + i < NVRAM_BOOTLINE_LEN; i++, p++ ) + { + if( p[0] == ' ' && p[1] == 'p' && p[2] == '=' ) + { + boot_prev = p[3] - '0'; + if( boot_prev != 0 && boot_prev != 1 ) + boot_prev = '0'; + break; + } + } + + /* Find the CFE ram inode entry point for both root file systems. */ + board_setleds((boot_prev == 0) ? 0x4e414e30 : 0x4e414e31); + for( k = 0, rfsi = rfs_info; k < 2; k++, rfsi++ ) + { + version = 0; + not_jffs2 = 0; + rfsi->rootfs = k + NP_ROOTFS_1; + rfsi->boot_val = bv_invalid; + if( nd->ulNandPartOfsKb[rfsi->rootfs] > 0 && + nd->ulNandPartOfsKb[rfsi->rootfs] < ((num_blks * len) / 1024)) + { + rfsi->start_blk = nd->ulNandPartOfsKb[rfsi->rootfs] / (len/1024); + rfsi->end_blk = rfsi->start_blk + + (nd->ulNandPartSizeKb[rfsi->rootfs] / (len / 1024)); + } + else + rfsi->start_blk = rfsi->end_blk = 0; + + if( rfsi->start_blk == 0 || rfsi->start_blk >= rfsi->end_blk || + rfsi->start_blk >= num_blks || rfsi->end_blk >= num_blks ) + { + /* NVRAM_DATA fields for this rootfs are not valid. */ + if( k == 0 ) + { + /* Skip this rootfs. */ + board_setleds(0x4e414e36); + continue; + } + + if( rfs_info[0].boot_val == bv_invalid ) + { + /* File system info cannot be found for either rootfs. + * NVRAM_DATA may not be set. Use default values. + */ + board_setleds(0x4e414e37); + rfsi = rfs_info; + rfsi->start_blk = 1; + rfsi->end_blk = num_blks; + } + } + + /* Find the directory entry. */ + for( i = rfsi->start_blk, done = 0; i < rfsi->end_blk && done == 0; i++ ) + { + /* This loop sequentially reads a NAND flash block into memory and + * processes it. + */ + if( nand_flash_read_buf(i, 0, buf, len) > 0 ) + { + /* This loop reads inodes in a block. */ + p = buf; + while( p < buf + len ) + { + pdir = (struct jffs2_raw_dirent *) p; + if( je16_to_cpu(pdir->magic) == JFFS2_MAGIC_BITMASK ) + { + if( je16_to_cpu(pdir->nodetype) == + JFFS2_NODETYPE_DIRENT && + g_fname_actual_len == pdir->nsize && + !memcmp(g_fname, pdir->name, g_fname_cmp_len) ) + { + /* The desired directory was found. */ + if( je32_to_cpu(pdir->version) > version ) + { + if( (rfsi->ino = je32_to_cpu(pdir->ino)) != 0 ) + { + unsigned char *fname = + pdir->name + g_fname_cmp_len; + rfsi->boot_val = + ((fname[0] - '0') * 100) + + ((fname[1] - '0') * 10) + + ((fname[2] - '0') * 1); + version = je32_to_cpu(pdir->version); + + board_setleds(0x42540000 + + ((unsigned long) fname[1] << 8) + + (unsigned long) fname[2]); + + /* Setting 'done = 1' assumes there is only + * one version of the directory entry. This + * may not be correct if the file is + * updated after it was initially flashed. + * + * TBD. Look for a higher version of the + * directory entry without searching the + * entire flash part. + */ + done = 1; + break; + } + } + } + + p += (je32_to_cpu(pdir->totlen) + 0x03) & ~0x03; + not_jffs2 = 0; + } + else + { + if( not_jffs2++ > max_not_jffs2 ) + { + /* No JFFS2 magic bitmask for consecutive blocks. + * Assume this partion does not have a file system + * on it. + */ + board_setleds(0x53544F50); + done = 1; + } + break; + } + } + } + else + { + if(!err0) + { + err0=1; + board_setleds(0x45525230); + } + } + } + board_setleds(0x4e414e39); + } + + /* Set the rfs_info to the index to boot from. */ + if( (boot_prev == 0 && rfs_info[0].boot_val > rfs_info[1].boot_val) || + (boot_prev == 1 && rfs_info[0].boot_val < rfs_info[1].boot_val) || + rfs_info[1].boot_val == bv_invalid ) + { + /* Boot from the most recent image. */ + prfs_info[0] = &rfs_info[0]; + prfs_info[1] = &rfs_info[1]; + } + else + { + /* Boot from the previous image. */ + prfs_info[0] = &rfs_info[1]; + prfs_info[1] = &rfs_info[0]; + } + + /* If the directory entry for the desired file, which is the CFE RAM image, + * is found, read it into memory and jump to its entry point function. + * This loop checks for CFE RAM image in two possible rootfs file sytems. + */ + for( k = 0; k < 2; k++ ) + { + unsigned char *pucDest = NULL; + unsigned char *pucEntry = NULL; + long isize = 0; + + board_setleds(0x4e414e33); + rfsi = prfs_info[k]; + if( rfsi->boot_val == bv_invalid ) + continue; + + /* When j == 0, get the first inode to find the entry point address. + * When j == 1, read the file contents into memory. + */ + for( j = 0; j < 2; j++ ) + { + /* This loop sequentially reads a NAND flash block into memory and + * processes it. + */ + for(i = rfsi->start_blk, done = 0; i<rfsi->end_blk && done==0; i++) + { + if( nand_flash_read_buf(i, 0, buf, len) > 0 ) + { + /* This loop reads inodes in a block. */ + p = buf; + while( p < buf + len ) + { + /* Verify the first short word is the JFFS2 magic + * number. + */ + pino = (struct jffs2_raw_inode *) p; + if( je16_to_cpu(pino->magic) == JFFS2_MAGIC_BITMASK ) + { + if( je16_to_cpu(pino->nodetype) == + JFFS2_NODETYPE_INODE && + je32_to_cpu(pino->ino) == rfsi->ino ) + { + unsigned long size = je32_to_cpu(pino->dsize); + unsigned long ofs = je32_to_cpu(pino->offset); + + if( size ) + { + /* A node of the CFE RAM file was found + * with data. */ + if( pucDest == NULL ) + { + /* The entry point and copy destination + * addresses have not been obtained. + * If this is the first node of the CFE + * RAM file, obtain this information. + */ + if( ofs == 0 ) + { + /* The first 12 bytes contain a + * header. The first word is the + * entry point address. + */ + pucEntry = (unsigned char *) + *(unsigned long *) pino->data; + pucDest = pucEntry - 12; + isize = je32_to_cpu(pino->isize); + done = 1; + board_setleds(0x52465330 | + rfsi->rootfs); + break; + } + } + else + { + /* Copy the image to memory. Stop when + * the entire image has been copied. + */ + memcpy(pucDest+ofs, pino->data, size); + if( (isize -= size) <= 0 ) + { + done = 1; + break; + } + } + } + } + + /* Skip to the next inode entry. */ + p += (je32_to_cpu(pino->totlen) + 0x03) & ~0x03; + } + else + break; + } + } + else + { + if(!err1) + { + err1=1; + board_setleds(0x45525231); + } + } + } + } + + if( pucEntry && isize <= 0 ) + { + board_setleds(0x4e414e35); + + /* Save the rootfs partition that the CFE RAM image boots from + * at the memory location before the CFE RAM load address. The + * CFE RAM image uses this value to determine the partition to + * flash a new rootfs to. + */ + *(pucEntry - 1) = (unsigned char) rfsi->rootfs; + + cfe_launch((unsigned long) pucEntry); // never return... + } + board_setleds(0x4e414e38); + } + + /* Error occurred. */ + board_setleds(0x44494530); + while(1); +} +#endif +#endif + +/* ********************************************************************* + * cfe_main(a,b) + * + * It's gotta start somewhere. + * Input parameters: + * a,b - not used + * + * Return value: + * does not return + ********************************************************************* */ + +void cfe_main(int a,int b) +{ + unsigned char *pucSrc; + unsigned char *pucDst; + unsigned int *entryPoint; + unsigned int binArrayStart = (unsigned int) _binArrayStart; + unsigned int binArrayEnd = (unsigned int) _binArrayEnd; + unsigned int dataLen = binArrayEnd - binArrayStart - 4; + int ret; + + KMEMINIT((unsigned char *) (uint32_t) mem_heapstart, + ((CFG_HEAP_SIZE)*1024)); + +#if (INC_NAND_FLASH_DRIVER==1) && (defined(_BCM96816_) || defined(_BCM96362_) || defined(_BCM96328_)) + if( ((MISC->miscStrapBus & MISC_STRAP_BUS_BOOT_SEL_MASK) >> + MISC_STRAP_BUS_BOOT_SEL_SHIFT) == MISC_STRAP_BUS_BOOT_NAND ) + { + bootImageFromNand(); /* Will not return. */ + } +#elif (INC_NAND_FLASH_DRIVER==1) && defined(_BCM96368_) + if( ((GPIO->StrapBus & MISC_STRAP_BUS_BOOT_SEL_MASK) >> + MISC_STRAP_BUS_BOOT_SEL_SHIFT) == MISC_STRAP_BUS_BOOT_NAND ) + { + bootImageFromNand(); /* Will not return. */ + } +#endif + + entryPoint = (unsigned int*) binArrayStart; + pucSrc = (unsigned char *) (binArrayStart + 4); + + pucDst = (unsigned char *) *entryPoint; + ret = decompressLZMA((unsigned char*)pucSrc, + (unsigned int)dataLen, + (unsigned char *) pucDst, + 23*1024*1024); + + if (ret != 0) + while (1); // if not decompressed ok, loop for EJTAG + + cfe_launch((unsigned long) pucDst); // never return... +} +#else +/* 0x694b6f31 (iKo1) is replaced with actual address during the build process.*/ +unsigned long cfeRamStartAddr=0x694b6f31; +void cfe_main(int a,int b) +{ + cfe_size_ram(); + cfe_launch(cfeRamStartAddr); // never return... +} +#endif + diff --git a/cfe/cfe/arch/mips/board/bcm63xx_rom/src/memtest.c b/cfe/cfe/arch/mips/board/bcm63xx_rom/src/memtest.c new file mode 100755 index 0000000..310fb40 --- /dev/null +++ b/cfe/cfe/arch/mips/board/bcm63xx_rom/src/memtest.c @@ -0,0 +1,1031 @@ +/* + *----------------------------------------------------------------------------* + * Collection of Memory Tests. + *----------------------------------------------------------------------------* + */ + +// +// NOTE: Blatant inlining ... (not sure whether caller supports EABI calls). +// WARNING CFE: Must NOT use function calls !!! +// +#define _ALWAYS_INLINE_ __attribute__((always_inline)) +#define _INLINE_ inline static + +typedef enum memTestResult { + MEMTEST_FAILURE = 0, + MEMTEST_SUCCESS, + MEMTEST_ERROR, +} MemTestResult_t; + +/* ------------------------------------------------------------------------- */ + +#undef PATTERN +#define PATTERN(x) PATTERN_##x, + +/* + * For each pattern listed, the inverse pattern is also automatically used. + * E.g. 0x55555555, the inverse of defined 0xAAAAAAAA is covered. + */ +typedef enum pattern { + PATTERN(0x00000000) + PATTERN(0xAAAAAAAA) + PATTERN(0xCCCCCCCC) + PATTERN(0x77777777) + PATTERN(0xF0F0F0F0) + PATTERN(0xFF00FF00) + PATTERN(0xFFFF0000) + PATTERN(0x01234567) + PATTERN(0x89ABCDEF) + PATTERN_MAX, +} Pattern_t; + +#undef PATTERN +#define PATTERN(x) x, +const uint32_t pattern[] = { + PATTERN(0x00000000) + PATTERN(0xAAAAAAAA) + PATTERN(0xCCCCCCCC) + PATTERN(0x77777777) + PATTERN(0xF0F0F0F0) + PATTERN(0xFF00FF00) + PATTERN(0xFFFF0000) + PATTERN(0x01234567) + PATTERN(0x89ABCDEF) + PATTERN_MAX, +}; + +/* ------------------------------------------------------------------------- */ + +#ifndef NBBY +#define NBBY 8 /* FreeBSD style: Number Bits per BYte */ +#endif + +/* ------------------------------------------------------------------------- */ + +#define NBITS(type) (sizeof(type) * NBBY) +#define NBITVAL(nbits) (1 << (nbits)) +#define MAXBITVAL(nbits) ( NBITVAL(nbits) - 1) +#define NBITMASK(nbits) MAXBITVAL(nbits) +#define MAXNBVAL(nbyte) MAXBITVAL((nbyte) * NBBY) + +#define DIVBY(val32,by) ((val32)>>(by)) +#define MODBY(val32,by) ((val32) & ((1 <<(by)) - 1) ) + +#define IS_POWEROF2(val32) ( (((val32)-1) & (val32)) == 0 ) + +#define ROUNDDN(addr, align) ( (addr) & ~((align) - 1) ) +#define ROUNDUP(addr, align) ( ((addr) + (align) - 1) & ~((align) - 1) ) +//#define ROUNDUP(x,y) ((((x)+((y)-1))/(y))*(y)) +#define ALIGN_ADDR(addr, bytes) (void *)( ((uint32_t *)(addr) + (bytes) - 1) \ + & ~((bytes) - 1) ) +#define IS_ALIGNED(addr, bytes) (((uint32_t)(addr) & ((bytes)-1)) == 0) + +#define OFFSET_OF(stype,member) ((uint32_t) &((struct stype *)0)->member) +#define RELOC(base,stype,member) ((base) + OFFSET_OF(stype, member)) + +#define RROTATE32(val32) (((val32) << 31) | ((val32) >> 1)) +#define LROTATE32(val32) (((val32) << 1) | ((val32) >> 31)) + +/* ------------------------------------------------------------------------- */ + +/* Aligned (32bit register) read/write access */ +#define RD16(addr16) (*(volatile uint32_t *)(addr16)) +#define WR16(addr16,val16) (*(volatile uint32_t *)(addr16))=(val16) +#define RD32(addr32) (*(volatile uint32_t *)(addr32)) +#define WR32(addr32,val32) (*(volatile uint32_t *)(addr32))=(val32) + +/*---------------------------------------------------------------------------*/ + +/* Forward declaration */ +_INLINE_ void fill_memory( uint32_t * addr, uint32_t bytes, uint32_t fill32) + _ALWAYS_INLINE_; +_INLINE_ void fill_alt_memory(uint32_t * addr, uint32_t bytes, + uint32_t fillA32, uint32_t fillB32) _ALWAYS_INLINE_; + +void fill_memory( uint32_t * addr, uint32_t bytes, uint32_t fill32) +{ + uint32_t * at, * end_p; + uint32_t words; + words = bytes / sizeof(uint32_t); + if ( words == 0 ) return; + + end_p = addr + words; + for ( at = addr; at < end_p; at++ ) + WR32( at, fill32 ); +} + +void fill_alt_memory( uint32_t * addr, uint32_t bytes, + uint32_t fillA32, uint32_t fillB32) +{ + uint32_t * at, * end_p; + uint32_t words; + words = bytes / sizeof(uint32_t); + words = ROUNDDN( words, 2 ); + if ( words == 0 ) return; + + end_p = addr + words; + for ( at = addr; at < end_p; at+=2 ) + { + WR32( at+0, fillA32 ); + WR32( at+1, fillB32 ); + } +} + +/* Forward declaration */ +_INLINE_ MemTestResult_t scanWordValue( uint32_t * addr, uint32_t bytes, + uint32_t pat32 ) _ALWAYS_INLINE_; +_INLINE_ MemTestResult_t scanBulkValue( uint32_t * addr, uint32_t bytes, + uint32_t pat32 ) _ALWAYS_INLINE_; +_INLINE_ MemTestResult_t scanBulkAltInv( uint32_t * addr, uint32_t bytes, + uint32_t pat32 ) _ALWAYS_INLINE_; +_INLINE_ MemTestResult_t scanWordSelf( uint32_t * addr, uint32_t bytes ) + _ALWAYS_INLINE_; +_INLINE_ MemTestResult_t scanBulkSelf( uint32_t * addr, uint32_t bytes ) + _ALWAYS_INLINE_; +_INLINE_ MemTestResult_t slidingAltInv( uint32_t * addr, uint32_t bytes, + uint32_t pat32 ) _ALWAYS_INLINE_; +_INLINE_ MemTestResult_t slidingDiag( uint32_t * addr, uint32_t bytes, + uint32_t pat32 ) _ALWAYS_INLINE_; +_INLINE_ MemTestResult_t memoryBulkCopy( uint32_t * saddr, uint32_t * daddr, + uint32_t bytes ) _ALWAYS_INLINE_; + +/* + *----------------------------------------------------------------------------- + * Function: scanWordValue + * + * Description: + * 4 Passes are conducted on the memory region. + * Pass 1. In INcreasing memory address, write a word with value and verify. + * Pass 2. In DEcreasing memory address, write a word with value and verify. + * Pass 3. In INcreasing memory address, write a word with INVERSE and verify. + * Pass 4. In DEcreasing memory address, write a word with INVERSE and verify. + * Pass 5. In INcreasing shifted memory address, write word with value verify. + * Pass 6. In INcreasing shifted memory address, write word with INVERSE verify. + * + * Parameters: + * addr: word aligned pointer to memory region + * bytes: size in bytes of memory region to test + * pat32: 32bit pattern, e.g. 0x0U, 0xAAAAAAAA, 0xFF00FF00, 0xFFFF0000, + * 0xF0F0F0F0, 0xC3C3C3C3, 0x87878787 + *----------------------------------------------------------------------------- + */ +MemTestResult_t scanWordValue( uint32_t * addr, uint32_t bytes, uint32_t pat32 ) +{ + volatile uint32_t * at, * end_p; + uint32_t expected, read, words; + uint32_t shift; + + if ( ! IS_ALIGNED(addr,4) ) return MEMTEST_ERROR; + + words = bytes / sizeof(uint32_t); /* in whole words (4byte multiple) */ + if ( words == 0 ) + return MEMTEST_ERROR; + + expected = pat32; /* ORIGINAL value */ + + /* INCREASING traversal */ + end_p = addr + words; + for ( at = addr; at < end_p; at++ ) + { + WR32( at, expected ); + read = RD32(at); + if ( read != expected ) + { + return MEMTEST_FAILURE; + } + } + + /* DECREASING traversal */ + end_p = addr; + for ( at = addr + words - 1; at >= end_p; at-- ) + { + WR32( at, expected ); + read = RD32(at); + if ( read != expected ) + { + return MEMTEST_FAILURE; + } + } + + expected = ~pat32; /* INVERSE value */ + + /* INCREASING traversal */ + end_p = addr + words; + for ( at = addr; at < end_p; at++ ) + { + WR32( at, expected ); + read = RD32(at); + if ( read != expected ) + { + return MEMTEST_FAILURE; + } + } + + /* DECREASING traversal */ + end_p = addr; + for ( at = addr + words - 1; at >= end_p; at-- ) + { + WR32( at, expected ); + read = RD32(at); + if ( read != expected ) + { + return MEMTEST_FAILURE; + } + } + + /* PASS 5: Shifting address walk, ORIGINAL */ + expected = pat32; /* ORIGINAL value */ + + end_p = addr + words; + shift = sizeof(uint32_t); + for ( at = addr + shift; at < end_p; shift <<= 1, at = addr + shift ) + { + WR32( at, expected ); + WR32( addr, ~expected ); /* noise at base addr */ + read = RD32(at); + if ( read != expected ) + { + return MEMTEST_FAILURE; + } + } + + expected = ~pat32; /* INVERSE value */ + + /* PASS 6: Shifting address walk, INVERSE */ + end_p = addr + words; + shift = sizeof(uint32_t); + for ( at = addr + shift; at < end_p; shift <<= 1, at = addr + shift ) + { + WR32( at, expected ); + WR32( addr, ~expected ); /* noise at base addr */ + read = RD32(at); + if ( read != expected ) + { + return MEMTEST_FAILURE; + } + } + + return MEMTEST_SUCCESS; +} + +/* + *----------------------------------------------------------------------------- + * Function: scanBulkValue + * + * Description: + * Pass 1. Fill entire memory in INcreasing memory address with value + * then in INcreasing memory address read and verify. + * Pass 2. Fill entire memory in DEcreasing memory address with value + * then in DEcreasing memory address read and verify. + * Pass 3. Fill entire memory in INcreasing memory address with inverse value + * then in INcreasing memory address read and verify. + * Pass 4. Fill entire memory in DEcreasing memory address with inverse value + * then in DEcreasing memory address read and verify. + * Pass 5. INcreasing shifted, ORIGINAL + * Pass 6. INcreasing shifted, INVERSE + * + * Parameters: + * addr: word aligned pointer to memory region + * bytes: size in bytes of memory region to test + * pat32: 32bit pattern, e.g. 0x0U, 0xAAAAAAAA, 0xFF00FF00, 0xFFFF0000, + * 0xF0F0F0F0, 0xC3C3C3C3, 0x87878787 + *----------------------------------------------------------------------------- + */ +MemTestResult_t scanBulkValue( uint32_t * addr, uint32_t bytes, uint32_t pat32 ) +{ + volatile uint32_t * at, * end_p; + uint32_t expected, read, words; + uint32_t shift; + + if ( ! IS_ALIGNED(addr,4) ) return MEMTEST_ERROR; + + words = bytes / sizeof(uint32_t); /* in whole words (4byte multiple) */ + if ( words == 0 ) return MEMTEST_ERROR; + + expected = pat32; /* ORIGINAL value */ + + /* INCREASING traversal */ + end_p = addr + words; + for ( at = addr; at < end_p; at++ ) + { + WR32( at, expected ); + } + for ( at = addr; at < end_p; at++ ) + { + read = RD32(at); + if ( read != expected ) + { + return MEMTEST_FAILURE; + } + } + + /* DECREASING traversal */ + end_p = addr; + for ( at = addr + words - 1; at >= end_p; at-- ) + { + WR32( at, expected ); + } + for ( at = addr + words - 1; at >= end_p; at-- ) + { + read = RD32(at); + if ( read != expected ) + { + return MEMTEST_FAILURE; + } + } + + expected = ~pat32; /* INVERSE value */ + + /* INCREASING traversal */ + end_p = addr + words; + for ( at = addr; at < end_p; at++ ) + { + WR32( at, expected ); + } + for ( at = addr; at < end_p; at++ ) + { + read = RD32(at); + if ( read != expected ) + { + return MEMTEST_FAILURE; + } + } + + /* DECREASING traversal */ + end_p = addr; + for ( at = addr + words - 1; at >= end_p; at-- ) + { + WR32( at, expected ); + } + for ( at = addr + words - 1; at >= end_p; at-- ) + { + read = RD32(at); + if ( read != expected ) + { + return MEMTEST_FAILURE; + } + } + + /* Pass 5. INCREASING Shifted traversal */ + expected = pat32; /* ORIGINAL value */ + end_p = addr + words; + shift = sizeof(uint32_t); + for ( at = addr + shift; at < end_p; shift <<= 1, at = addr + shift ) + { + WR32( at, expected ); + WR32( addr, ~expected ); /* noise at base addr */ + } + shift = sizeof(uint32_t); + for ( at = addr + shift; at < end_p; shift <<= 1, at = addr + shift ) + { + read = RD32(at); + if ( read != expected ) + { + return MEMTEST_FAILURE; + } + } + + expected = ~pat32; /* INVERSE value */ + end_p = addr + words; + shift = sizeof(uint32_t); + for ( at = addr + shift; at < end_p; shift <<= 1, at = addr + shift ) + { + WR32( at, expected ); + WR32( addr, ~expected ); /* noise at base addr */ + } + shift = sizeof(uint32_t); + for ( at = addr + shift; at < end_p; shift <<= 1, at = addr + shift ) + { + read = RD32(at); + if ( read != expected ) + { + return MEMTEST_FAILURE; + } + } + + return MEMTEST_SUCCESS; +} + +/* + *----------------------------------------------------------------------------- + * Function: scanBulkAltInv + * + * Description: + * Pass 1. Fill entire memory in INcreasing memory address with alternating + * value, then in INcreasing memory address read and verify. + * Pass 2. Fill entire memory in DEcreasing memory address with alternating + * value, then in DEcreasing memory address read and verify. + * Pass 3. Same as one but with shifted address. + * + * Parameters: + * addr: word aligned pointer to memory region + * bytes: size in bytes of memory region to test + * pat32: 32bit pattern, e.g. 0x0U, 0xAAAAAAAA, 0xFF00FF00, 0xFFFF0000, + * 0xF0F0F0F0, 0xC3C3C3C3, 0x87878787 + *----------------------------------------------------------------------------- + */ +MemTestResult_t scanBulkAltInv( uint32_t * addr, uint32_t bytes, uint32_t pat32 ) +{ + volatile uint32_t * at, * end_p; + uint32_t read, words; + uint32_t shift; + + if ( ! IS_ALIGNED(addr,4) ) return MEMTEST_ERROR; + + words = bytes / sizeof(uint32_t); /* in whole words (4byte multiple) */ + words = ROUNDDN( words, 2 ); + if ( words == 0 ) return MEMTEST_ERROR; + + /* INCREASING traversal */ + end_p = addr + words; + for ( at = addr; at < end_p; at+=2 ) + { + WR32( at+0, pat32 ); + WR32( at+1, ~pat32 ); + } + for ( at = addr; at < end_p; at+=2 ) + { + read = RD32( at+0 ); + if ( read != pat32 ) + { + return MEMTEST_FAILURE; + } + read = RD32( at+1 ); + if ( read != ~pat32 ) + { + return MEMTEST_FAILURE; + } + } + + /* DECREASING traversal */ + end_p = addr; + for ( at = addr + words - 1; at >= end_p; at-=2 ) + { + WR32( at+0, pat32 ); + WR32( at+1, ~pat32 ); + } + for ( at = addr + words - 1; at >= end_p; at-=2 ) + { + read = RD32( at+0 ); + if ( read != pat32 ) + { + return MEMTEST_FAILURE; + } + read = RD32( at+1 ); + if ( read != ~pat32 ) + { + return MEMTEST_FAILURE; + } + } + + /* INCREASING SHIFTED traversal */ + end_p = addr + words; + shift = sizeof(uint32_t); + for ( at = addr + shift; at < end_p; shift <<= 1, at = addr + shift ) + { + WR32( at+0, pat32 ); + WR32( addr, 0 ); + WR32( at+1, ~pat32 ); + WR32( addr, 0 ); + } + shift = sizeof(uint32_t); + for ( at = addr + shift; at < end_p; shift <<= 1, at = addr + shift ) + { + read = RD32( at+0 ); + if ( read != pat32 ) + { + return MEMTEST_FAILURE; + } + read = RD32( at+1 ); + if ( read != ~pat32 ) + { + return MEMTEST_FAILURE; + } + } + + return MEMTEST_SUCCESS; +} + + +/* + *----------------------------------------------------------------------------- + * Function: scanWordSelf + * + * Description: + * 4 Passes are conducted on the memory region. + * Pass 1. In INcreasing memory address, write a word with selfaddr and verify. + * Pass 2. In DEcreasing memory address, write a word with INVERSE and verify. + * Pass 3. In INcreasing memory address, write a word with INVERSE and verify. + * Pass 4. In DEcreasing memory address, write a word with selfaddr and verify. + * Pass 5. value = ORIGINAL address, INCREASING SHIFTED traversal. + * Pass 6. value = INVERSE address, INCREASING SHIFTED traversal. + * + * In Pass 2 Read+Modify+Write, and in Pass 3, Read+Write is used + * + * Parameters: + * addr: word aligned pointer to memory region + * bytes: size in bytes of memory region to test + * + *----------------------------------------------------------------------------- + */ +MemTestResult_t scanWordSelf( uint32_t * addr, uint32_t bytes ) +{ + volatile uint32_t * at, * end_p; + uint32_t expected, read, words; + uint32_t shift; + + if ( ! IS_ALIGNED(addr,4) ) return MEMTEST_FAILURE; + + words = bytes / sizeof(uint32_t); /* in whole words (4byte multiple) */ + if ( words == 0 ) return MEMTEST_ERROR; + + /* ORIGINAL value */ + + /* INCREASING traversal */ + end_p = addr + words; + for ( at = addr; at < end_p; at++ ) + { + expected = (uint32_t)at; + WR32( at, expected ); + read = RD32(at); + if ( read != expected ) + { + return MEMTEST_FAILURE; + } + } + + /* DECREASING traversal */ + end_p = addr; + for ( at = addr + words - 1; at >= end_p; at-- ) + { + expected = ~( (uint32_t)RD32(at) ); + WR32( at, expected ); + read = RD32(at); + if ( read != expected ) + { + return MEMTEST_FAILURE; + } + } + + /* INCREASING traversal */ + end_p = addr + words; + for ( at = addr; at < end_p; at++ ) + { + expected = ((uint32_t)RD32(at)); + WR32( at, expected ); + read = RD32(at); + if ( read != expected ) + { + return MEMTEST_FAILURE; + } + } + + /* DECREASING traversal */ + end_p = addr; + for ( at = addr + words - 1; at >= end_p; at-- ) + { + expected = ~((uint32_t)at); + WR32( at, expected ); + read = RD32(at); + if ( read != expected ) + { + return MEMTEST_FAILURE; + } + } + + /* value = ORIGINAL address, INCREASING SHIFTED traversal */ + end_p = addr + words; + shift = sizeof(uint32_t); + for ( at = addr + shift; at < end_p; shift <<= 1, at = addr + shift ) + { + expected = (uint32_t)at; /* Not read modify write */ + WR32( at, expected ); + WR32( addr, ~expected ); + read = RD32(at); + if ( read != expected ) + { + return MEMTEST_FAILURE; + } + } + + /* value = INVERSE address, INCREASING SHIFTED traversal */ + end_p = addr + words; + shift = sizeof(uint32_t); + for ( at = addr + shift; at < end_p; shift <<= 1, at = addr + shift ) + { + expected = ~(uint32_t)(at); /* Not read modify write */ + WR32( at, expected ); + WR32( addr, ~expected ); + read = RD32(at); + if ( read != expected ) + { + return MEMTEST_FAILURE; + } + } + + return MEMTEST_SUCCESS; +} + +/* + *----------------------------------------------------------------------------- + * Function: scanBulkSelf + * + * Description: + * Pass 1. Fill entire memory in INcreasing memory address with self address + * then in INcreasing memory address read and verify. + * Pass 2. Fill entire memory in DEcreasing memory address with self address + * then in DEcreasing memory address read and verify. + * Pass 3. Fill entire memory in INcreasing memory address with inverse addr + * then in INcreasing memory address read and verify. + * Pass 4. Fill entire memory in DEcreasing memory address with inverse addr + * then in DEcreasing memory address read and verify. + * Pass 5. Same as Pass 1 but with shifted address + * Pass 6. Same as Pass 3 but with shifted address + * + * Parameters: + * addr: word aligned pointer to memory region + * bytes: size in bytes of memory region to test + *----------------------------------------------------------------------------- + */ +MemTestResult_t scanBulkSelf( uint32_t * addr, uint32_t bytes ) +{ + volatile uint32_t * at, * end_p; + uint32_t read, words; + uint32_t shift; + + if ( ! IS_ALIGNED(addr,4) ) return MEMTEST_ERROR; + + words = bytes / sizeof(uint32_t); /* in whole words (4byte multiple) */ + if ( words == 0 ) return MEMTEST_ERROR; + + /* INCREASING traversal */ + end_p = addr + words; + for ( at = addr; at < end_p; at++ ) + { + WR32( at, (uint32_t)at ); + } + for ( at = addr; at < end_p; at++ ) + { + read = RD32(at); + if ( read != (uint32_t)at ) + { + return MEMTEST_FAILURE; + } + } + + /* DECREASING traversal */ + end_p = addr; + for ( at = addr + words - 1; at >= end_p; at-- ) + { + WR32( at, (uint32_t)at ); + } + for ( at = addr + words - 1; at >= end_p; at-- ) + { + read = RD32(at); + if ( read != (uint32_t)at ) + { + return MEMTEST_FAILURE; + } + } + + /* INCREASING traversal */ + end_p = addr + words; + for ( at = addr; at < end_p; at++ ) + { + WR32( at, ~((uint32_t)at) ); + } + for ( at = addr; at < end_p; at++ ) + { + read = RD32(at); + if ( read != ~((uint32_t)at) ) + { + return MEMTEST_FAILURE; + } + } + + /* DECREASING traversal */ + end_p = addr; + for ( at = addr + words - 1; at >= end_p; at-- ) + { + WR32( at, ~((uint32_t)at) ); + } + for ( at = addr + words - 1; at >= end_p; at-- ) + { + read = RD32(at); + if ( read != ~((uint32_t)at) ) + { + return MEMTEST_FAILURE; + } + } + + /* INCREASING traversal */ + end_p = addr + words; + shift = sizeof(uint32_t); + for ( at = addr + shift; at < end_p; shift <<= 1, at = addr + shift ) + { + WR32( at, (uint32_t)at ); + WR32( addr, ~((uint32_t)at) ); + } + shift = sizeof(uint32_t); + for ( at = addr + shift; at < end_p; shift <<= 1, at = addr + shift ) + { + read = RD32(at); + if ( read != (uint32_t)at ) + { + return MEMTEST_FAILURE; + } + } + + /* INCREASING traversal */ + end_p = addr + words; + shift = sizeof(uint32_t); + for ( at = addr + shift; at < end_p; shift <<= 1, at = addr + shift ) + { + WR32( at, ~((uint32_t)at) ); + WR32( addr, ((uint32_t)at) ); + } + shift = sizeof(uint32_t); + for ( at = addr + shift; at < end_p; shift <<= 1, at = addr + shift ) + { + read = RD32(at); + if ( read != ~((uint32_t)at) ) + { + return MEMTEST_FAILURE; + } + } + + return MEMTEST_SUCCESS; +} + + +/* + *----------------------------------------------------------------------------- + * Function: slidingAltInv + * + * Description: + * This is the same as scanBulkAltInv, where in each invocation the value is + * rotated to the right. The starting value is usedefined. + * + * Parameters: + * addr: word aligned pointer to memory region + * bytes: size in bytes of memory region to test + * pat32: pattern to slide per pass + *----------------------------------------------------------------------------- + */ +MemTestResult_t slidingAltInv( uint32_t * addr, uint32_t bytes, uint32_t pat32 ) +{ + uint32_t sliding_pat32, i; + + if ( pat32 == 0x0 ) pat32 = 0x80000000; + if ( pat32 == ~0x0 ) pat32 = 0x7FFFFFFF; + + sliding_pat32 = pat32; + + for ( i=0; i<32; i++ ) + { + if ( scanBulkAltInv( addr, bytes, sliding_pat32 ) + == MEMTEST_FAILURE ) + { + return MEMTEST_FAILURE; + } + + sliding_pat32 = RROTATE32( sliding_pat32 ); + } + + sliding_pat32 = pat32; + for (i=0; i<32; i++) + { + if ( scanBulkAltInv( addr, bytes, sliding_pat32 ) + == MEMTEST_FAILURE ) + { + return MEMTEST_FAILURE; + } + + sliding_pat32 = LROTATE32( sliding_pat32 ); + } + + return MEMTEST_SUCCESS; +} + +/* + *----------------------------------------------------------------------------- + * Function: slidingDiag + * + * Description: + * Pass 1. Fill entire memory in INcreasing memory address with pattern right + * shifted. Then read in INcreasing order and verify. + * Pass 2. Fill entire memory in DEcreasing memory address with inverse of + * read value. Then read in DEcreasing order and verify. + * Pass 3. Fill entire memory in DEcreasing memory address with pattern right + * shifted. Then read in DEcreasing order and verify. + * Pass 4. Fill entire memory in INcreasing memory address with inverse of + * read value. Then read in INcreasing order and verify. + * + * Parameters: + * addr: word aligned pointer to memory region + * bytes: size in bytes of memory region to test + * pat32: pattern to be filled shifted each write + *----------------------------------------------------------------------------- + */ +MemTestResult_t slidingDiag( uint32_t * addr, uint32_t bytes, uint32_t pat32 ) +{ + volatile uint32_t * at, * end_p; + uint32_t expected, read = 0, words, last; + + if ( ! IS_ALIGNED(addr,4) ) return MEMTEST_ERROR; + + words = bytes / sizeof(uint32_t); /* in whole words (4byte multiple) */ + if ( words == 0 ) return MEMTEST_ERROR; + + + /* INCREASING traversal */ + expected = pat32; /* ORIGINAL value */ + end_p = addr + words; + for ( at = addr; at < end_p; at++ ) + { + WR32( at, expected ); + expected = RROTATE32( expected ); /* next expected */ + } + expected = pat32; /* ORIGINAL value */ + for ( at = addr; at < end_p; at++ ) + { + read = RD32(at); + if ( read != expected ) + { + return MEMTEST_FAILURE; + } + expected = RROTATE32( expected ); /* next expected */ + } + + last = ~( read ); /* Starting value for decreasing traversal, next */ + + /* DECREASING traversal */ + end_p = addr; + for ( at = addr + words - 1; at >= end_p; at-- ) + { + expected = ~( RD32(at) ); + WR32( at, expected ); + } + expected = last; + for ( at = addr + words - 1; at >= end_p; at-- ) + { + read = RD32(at); + if ( read != expected ) + { + return MEMTEST_FAILURE; + } + expected = LROTATE32( expected ); + } + + /* DECREASING traversal */ + expected = pat32; /* ORIGINAL value */ + end_p = addr; + for ( at = addr + words - 1; at >= end_p; at-- ) + { + WR32( at, expected ); + expected = RROTATE32( expected ); /* next expected */ + } + expected = pat32; /* ORIGINAL value */ + for ( at = addr + words - 1; at >= end_p; at-- ) + { + read = RD32(at); + if ( read != expected ) + { + return MEMTEST_FAILURE; + } + expected = RROTATE32( expected ); /* next expected */ + } + + last = ~( read ); + + /* INCREASING traversal */ + end_p = addr + words; + for ( at = addr; at < end_p; at++ ) + { + expected = ~( RD32(at) ); + WR32( at, expected ); + } + expected = last; + for ( at = addr; at < end_p; at++ ) + { + read = RD32(at); + if ( read != expected ) + { + return MEMTEST_FAILURE; + } + expected = LROTATE32( expected ); + } + + return MEMTEST_SUCCESS; +} + +/* + *----------------------------------------------------------------------------- + * Function: memoryBulkCopy + * + * Description: + * Pass 1. Copy entire ORIGINAL memory in INcreasing memory address, then verify + * Pass 2. Copy entire ORIGINAL memory in DEcreasing memory address, then verify + * Pass 3. Copy entire INVERSE memory in INcreasing memory address, then verify + * Pass 4. Copy entire INVERSE memory in DEcreasing memory address, then verify + *----------------------------------------------------------------------------- + */ +MemTestResult_t memoryBulkCopy( uint32_t * saddr, uint32_t * daddr, + uint32_t bytes ) +{ + volatile uint32_t * src_p, * dst_p, * end_p; + uint32_t expected, read, words; + + if ( ! IS_ALIGNED(saddr,4) ) return MEMTEST_ERROR; + if ( ! IS_ALIGNED(daddr,4) ) return MEMTEST_ERROR; + + words = bytes / sizeof(uint32_t); /* in whole words (4byte multiple) */ + if ( words == 0 ) return MEMTEST_ERROR; + + if ( (uint32_t)saddr < (uint32_t)daddr ) + { + if ( (uint32_t)(saddr + words) > (uint32_t)daddr ) + return MEMTEST_ERROR; + } + else if ( (uint32_t)daddr < (uint32_t)saddr ) + { + if ( (uint32_t)(daddr + words) > (uint32_t)saddr ) + return MEMTEST_ERROR; + } + + /* INCREASING traversal ORIGINAL */ + end_p = saddr + words; + for ( src_p = saddr, dst_p = daddr; src_p < end_p; src_p++, dst_p++ ) + { + expected = RD32( dst_p ); + WR32( src_p, expected ); + } + for ( src_p = saddr, dst_p = daddr; src_p < end_p; src_p++, dst_p++ ) + { + expected = RD32( dst_p ); + read = RD32( src_p ); + if ( read != expected ) + { + return MEMTEST_FAILURE; + } + } + + /* DECREASING traversal ORIGINAL */ + end_p = saddr; + for ( src_p = saddr + words - 1, dst_p = daddr + words - 1; + src_p >= end_p; src_p--, dst_p-- ) + { + expected = RD32( dst_p ); + WR32( src_p, expected ); + } + for ( src_p = saddr + words - 1, dst_p = daddr + words - 1; + src_p >= end_p; src_p--, dst_p-- ) + { + expected = RD32( dst_p ); + read = RD32( src_p ); + if ( read != expected ) + { + return MEMTEST_FAILURE; + } + } + + /* INCREASING traversal INVERSE */ + end_p = saddr + words; + for ( src_p = saddr, dst_p = daddr; src_p < end_p; src_p++, dst_p++ ) + { + expected = ~( RD32( dst_p ) ); + WR32( src_p, expected ); + } + for ( src_p = saddr, dst_p = daddr; src_p < end_p; src_p++, dst_p++ ) + { + expected = ~( RD32( dst_p ) ); + read = RD32( src_p ); + if ( read != expected ) + { + return MEMTEST_FAILURE; + } + } + + /* DECREASING traversal INVERSE */ + end_p = saddr; + for ( src_p = saddr + words - 1, dst_p = daddr + words - 1; + src_p >= end_p; src_p--, dst_p-- ) + { + expected = ~( RD32( dst_p ) ); + WR32( src_p, expected ); + } + for ( src_p = saddr + words - 1, dst_p = daddr + words - 1; + src_p >= end_p; src_p--, dst_p-- ) + { + expected = ~( RD32( dst_p ) ); + read = RD32( src_p ); + if ( read != expected ) + { + return MEMTEST_FAILURE; + } + } + + return MEMTEST_SUCCESS; +} + +/*---------------------------------------------------------------------------*/ diff --git a/cfe/cfe/arch/mips/board/bcm63xx_rom/src/rom_cfe.mk b/cfe/cfe/arch/mips/board/bcm63xx_rom/src/rom_cfe.mk new file mode 100755 index 0000000..c45aea7 --- /dev/null +++ b/cfe/cfe/arch/mips/board/bcm63xx_rom/src/rom_cfe.mk @@ -0,0 +1,370 @@ + +# +# CFE's version number +# + +include ${TOP}/main/cfe_version.mk + +# +# Default values for certain parameters +# + +CFG_MLONG64 ?= 0 +CFG_LITTLE ?= 0 +CFG_RELOC ?= 0 +CFG_UNCACHED ?= 0 +CFG_NEWRELOC ?= 0 +CFG_BOOTRAM ?= 0 +CFG_VGACONSOLE ?= 0 +CFG_PCI ?= 1 +CFG_LDT_REV_017 ?= 0 +CFG_ZLIB ?= 0 +CFG_BIENDIAN ?= 0 +CFG_DOWNLOAD ?= 0 +CFG_RAMAPP ?= 0 +CFG_USB ?= 0 + +# +# Paths to other parts of the firmware. Everything's relative to ${TOP} +# so that you can actually do a build anywhere you want. +# + +ARCH_TOP = ${TOP}/arch/${ARCH} +ARCH_SRC = ${ARCH_TOP}/common/src +ARCH_INC = ${ARCH_TOP}/common/include +CPU_SRC = ${ARCH_TOP}/cpu/${CPU}/src +CPU_INC = ${ARCH_TOP}/cpu/${CPU}/include +# +# It's actually optional to have a 'board' +# directory. If you don't specify BOARD, +# don't include the files. +# + +ifneq ("$(strip ${BOARD})","") +BOARD_SRC = ${ARCH_TOP}/board/${BOARD}/src +BOARD_INC = ${ARCH_TOP}/board/${BOARD}/include +endif + +# +# Preprocessor defines for CFE's version number +# + +VDEF = -DCFE_VER_MAJ=${CFE_VER_MAJ} -DCFE_VER_MIN=${CFE_VER_MIN} -DCFE_VER_ECO=${CFE_VER_ECO} + +# +# Construct the list of paths that will eventually become the include +# paths and VPATH +# + +SRCDIRS = ${ARCH_SRC} ${CPU_SRC} ${BOARD_SRC} ${TOP}/main ${TOP}/vendor ${TOP}/include ${TOP}/net ${TOP}/dev ${TOP}/pci ${TOP}/ui ${TOP}/lib ${TOP}/common ${TOP}/verif ${TOP}/lzma + +CFE_INC = ${TOP}/include ${TOP}/pci ${TOP}/net + +ifeq ($(strip ${CFG_VGACONSOLE}),1) +SRCDIRS += ${TOP}/x86emu ${TOP}/pccons +CFE_INC += ${TOP}/x86emu ${TOP}/pccons +endif + +ifeq ($(strip ${CFG_VAPI}),1) +SRCDIRS += ${TOP}/verif +CFE_INC += ${TOP}/verif +endif + +ifeq ($(strip ${CFG_ZLIB}),1) +SRCDIRS += ${TOP}/zlib +CFE_INC += ${TOP}/zlib +endif + + +INCDIRS = $(patsubst %,-I%,$(subst :, ,$(ARCH_INC) $(CPU_INC) $(BOARD_INC) $(CFE_INC))) + +VPATH = $(SRCDIRS) + +# +# Bi-endian support: If we're building the little-endian +# version, use a different linker script so we can locate the +# ROM at a higher address. You'd think we could do this with +# normal linker command line switches, but there appears to be no +# command-line way to override the 'AT' qualifier in the linker script. +# + +CFG_TEXTAT1MB=0 +ifeq ($(strip ${CFG_BIENDIAN}),1) + ifeq ($(strip ${CFG_LITTLE}),1) + CFG_TEXTAT1MB=1 + endif +endif + + +# +# Configure tools and basic tools flags. This include sets up +# macros for calling the C compiler, basic flags, +# and linker scripts. +# + +include ${ARCH_SRC}/tools.mk + +# +# Add some common flags that are used on any architecture. +# + +CFLAGS += -I. $(INCDIRS) +CFLAGS += -D_CFE_ ${VDEF} -DCFG_BOARDNAME=\"${CFG_BOARDNAME}\" + +# +# Gross - allow more options to be supplied from command line +# + +ifdef CFG_OPTIONS +OPTFLAGS = $(patsubst %,-D%,$(subst :, ,$(CFG_OPTIONS))) +CFLAGS += ${OPTFLAGS} +endif + +ifeq ($(strip $(BRCM_IKOS)),y) +CFLAGS += -DCONFIG_BRCM_IKOS +endif + +# +# Add flash driver support. +# + +ifeq ($(strip $(BLD_NAND)),1) +# BUILD NAND flash boot loader +ifeq ($(strip $(BRCM_CHIP)),6328) +INC_CFI_FLASH_DRIVER=0 +INC_SPI_FLASH_DRIVER=0 +INC_NAND_FLASH_DRIVER=1 +endif +ifeq ($(strip $(BRCM_CHIP)),6362) +INC_CFI_FLASH_DRIVER=0 +INC_SPI_FLASH_DRIVER=0 +INC_NAND_FLASH_DRIVER=1 +endif +ifeq ($(strip $(BRCM_CHIP)),6368) +INC_CFI_FLASH_DRIVER=0 +INC_SPI_FLASH_DRIVER=0 +INC_NAND_FLASH_DRIVER=1 +endif +ifeq ($(strip $(BRCM_CHIP)),6816) +INC_CFI_FLASH_DRIVER=0 +INC_SPI_FLASH_DRIVER=0 +INC_NAND_FLASH_DRIVER=1 +endif + +else +# BUILD NOR flash boot loader +ifeq ($(strip $(BRCM_CHIP)),6328) +INC_CFI_FLASH_DRIVER=0 +INC_SPI_FLASH_DRIVER=1 +INC_NAND_FLASH_DRIVER=0 +endif +ifeq ($(strip $(BRCM_CHIP)),6362) +INC_CFI_FLASH_DRIVER=0 +INC_SPI_FLASH_DRIVER=1 +INC_NAND_FLASH_DRIVER=0 +endif +ifeq ($(strip $(BRCM_CHIP)),6368) +INC_CFI_FLASH_DRIVER=1 +INC_SPI_FLASH_DRIVER=1 +INC_NAND_FLASH_DRIVER=0 +endif +ifeq ($(strip $(BRCM_CHIP)),6816) +INC_CFI_FLASH_DRIVER=1 +INC_SPI_FLASH_DRIVER=1 +INC_NAND_FLASH_DRIVER=0 +endif +endif + +ifeq ($(strip $(BLD_SPI_NAND)),1) +INC_CFI_FLASH_DRIVER=0 +INC_SPI_FLASH_DRIVER=1 +INC_NAND_FLASH_DRIVER=0 +INC_SPI_PROG_NAND=1 +else +INC_SPI_PROG_NAND=0 +endif + +CFLAGS += -DINC_CFI_FLASH_DRIVER=$(INC_CFI_FLASH_DRIVER) +CFLAGS += -DINC_SPI_FLASH_DRIVER=$(INC_SPI_FLASH_DRIVER) +CFLAGS += -DINC_NAND_FLASH_DRIVER=$(INC_NAND_FLASH_DRIVER) +CFLAGS += -DINC_SPI_PROG_NAND=$(INC_SPI_PROG_NAND) + +# +# This is the makefile's main target. Note that we actually +# do most of the work in 'ALL' not 'all', since we include +# other makefiles after this point. +# + +all : build_date.c ALL + +# +# Macros that expand to the list of arch-independent files +# + +LZMAOBJS = LzmaDecode.o dcapi.o +DEVOBJS = lib_malloc.o +## dev_newflash.o dev_null.o dev_promice.o dev_ide_common.o dev_ns16550.o dev_ds17887clock.o dev_flash.o + +##lib_hssubr.o lib_physio.o lib_printf.o lib_misc.o \ lib_arena.o lib_queue.o +## lib_qsort.o lib_string.o lib_string2.o + +NETOBJS = +## net_tcp.o net_tcpbuf.o dev_tcpconsole.o net_dhcp.o net_icmp.o net_ether.o net_tftp.o net_ip.o net_udp.o net_dns.o net_arp.o net_api.o + +CFEOBJS = +## cfe_iocb_dispatch.o cfe_devfuncs.o \ cfe_console.o cfe_timer.o cfe_attach.o cfe_background.o cfe_zlibfs.o +## cfe_mem.o +## cfe_error.o build_date.o \ +## cfe_rawfs.o cfe_xreq.o cfe_filesys.o +## cfe_fatfs.o cfe_httpfs.o cfe_ldr_srec.o cfe_autoboot.o cfe_boot.o cfe_ldr_elf.o cfe_ldr_raw.o cfe_loader.o +## cfe_main.o nvram_subr.o url.o cfe_savedata.o env_subr.o +UIOBJS = +##ui_command.o ui_cmddisp.o +## ui_pcicmds.o \ui_tcpcmds.o ui_memcmds.o ui_loadcmds.o ui_flash.o ui_netcmds.o ui_envcmds.o ui_devcmds.o +## ui_examcmds.o ui_misccmds.o \ +## ui_test_disk.o ui_test_ether.o ui_test_flash.o ui_test_uart.o + +# +# Add more object files if we're supporting PCI +# + +ifeq ($(strip ${CFG_PCI}),1) +PCIOBJS = pciconf.o ldtinit.o pci_subr.o +PCIOBJS += pci_devs.o +DEVOBJS += dev_sp1011.o dev_ht7520.o +DEVOBJS += dev_ide_pci.o dev_ns16550_pci.o +DEVOBJS += dev_tulip.o dev_dp83815.o +CFLAGS += -DCFG_PCI=1 +ifeq ($(strip ${CFG_LDT_REV_017}),1) +CFLAGS += -DCFG_LDT_REV_017=1 +endif +ifeq ($(strip ${CFG_DOWNLOAD}),1) +DEVOBJS += dev_bcm1250.o download.data +CFLAGS += -DCFG_DOWNLOAD=1 +endif +endif + +# +# If doing bi-endian, add the compiler switch to change +# the way the vectors are generated. These switches are +# only added to the big-endian portion of the ROM, +# which is located at the real boot vector. +# + +ifeq ($(strip ${CFG_BIENDIAN}),1) + ifeq ($(strip ${CFG_LITTLE}),0) + CFLAGS += -DCFG_BIENDIAN=1 + endif +endif + +# +# Include the makefiles for the architecture-common, cpu-specific, +# and board-specific directories. Each of these will supply +# some files to "ALLOBJS". The BOARD directory is optional +# as some ports are so simple they don't need boad-specific stuff. +# + +include ${ARCH_SRC}/Makefile +include ${CPU_SRC}/Makefile + +ifneq ("$(strip ${BOARD})","") +include ${BOARD_SRC}/Makefile +endif + +# +# Add the common object files here. +# + +ALLOBJS += $(LIBOBJS) $(DEVOBJS) $(CFEOBJS) $(VENOBJS) $(UIOBJS) $(NETOBJS) +#$(PCIOBJS) + +# +# VAPI continues to be a special case. +# + +ifeq ($(strip ${CFG_VAPI}),1) +include ${TOP}/verif/Makefile +endif + +# +# USB support +# + +ifeq ($(strip ${CFG_USB}),1) +SRCDIRS += ${TOP}/usb +CFE_INC += ${TOP}/usb +include ${TOP}/usb/Makefile +endif + +# +# If we're doing the VGA console thing, pull in the x86 emulator +# and the pcconsole subsystem +# + +ifeq ($(strip ${CFG_VGACONSOLE}),1) +include ${TOP}/x86emu/Makefile +include ${TOP}/pccons/Makefile +endif + +# +# If we're including ZLIB, then add its makefile. +# + +##ifeq ($(strip ${CFG_ZLIB}),1) +##include ${TOP}/zlib/Makefile +CFLAGS += -DCFG_ZLIB=1 -DMY_ZCALLOC -DNO_MEMCPY +##endif + +.PHONY : all +.PHONY : ALL +.PHONY : build_date.c + +# +# Build the local tools that we use to construct other source files +# + +mkpcidb : ${TOP}/hosttools/mkpcidb.c + gcc -o mkpcidb ${TOP}/hosttools/mkpcidb.c + +memconfig : ${TOP}/hosttools/memconfig.c + gcc -o memconfig -D_MCSTANDALONE_ -D_MCSTANDALONE_NOISY_ -I${TOP}/arch/mips/cpu/sb1250/include ${TOP}/hosttools/memconfig.c ${TOP}/arch/${ARCH}/cpu/${CPU}/src/sb1250_draminit.c + +pcidevs_data2.h : mkpcidb ${TOP}/pci/pcidevs_data.h + ./mkpcidb > pcidevs_data2.h + +mkflashimage : ${TOP}/hosttools/mkflashimage.c + gcc -o mkflashimage -I${TOP}/include ${TOP}/hosttools/mkflashimage.c + +pci_subr.o : ${TOP}/pci/pci_subr.c pcidevs_data2.h + +##build_date.c : +## echo "const char *builddate = \"`date`\";" > build_date.c +## echo "const char *builduser = \"`whoami`@`hostname`\";" >> build_date.c + +# +# Make a define for the board name +# + +CFLAGS += -D_$(patsubst "%",%,${CFG_BOARDNAME})_ + +LIBCFE = libcfe.a + +%.o : %.c + $(GCC) $(CFLAGS) -o $@ $< + +%.o : %.S + $(GCC) $(CFLAGS) -o $@ $< + +# +# This rule constructs "libcfe.a" which contains most of the object +# files. +# + +$(LIBCFE) : $(ALLOBJS) + rm -f $(LIBCFE) + $(AR) cr $(LIBCFE) $(ALLOBJS) + $(RANLIB) $(LIBCFE) + + + + |