diff options
Diffstat (limited to 'cfe/cfe/arch/mips/board/bcm63xx_rom/src/bcm6368_rom_boot.S')
-rwxr-xr-x | cfe/cfe/arch/mips/board/bcm63xx_rom/src/bcm6368_rom_boot.S | 548 |
1 files changed, 548 insertions, 0 deletions
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) |