/*****************************************************************************
 * Copyright (c) 2004 Rowley Associates Limited.                             *
 *                                                                           *
 * This file may be distributed under the terms of the License Agreement     *
 * provided with this software.                                              *
 *                                                                           *
 * THIS FILE IS PROVIDED AS IS WITH NO WARRANTY OF ANY KIND, INCLUDING THE   *
 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. *
 *****************************************************************************/

  .section .vectors, "ax"
  .code 32
  .align 0

/*
 * Enable copying and re-mapping of interrupt vectors from FLASH to
 * SDRAM. If undefined, interrupt vectors will be mapped in SRAM.
 *
 * #define SDRAM_EXCEPTIONS
 *
 */

#define SDRAM_INIT_NOP  0x03
#define SDRAM_INIT_MODE 0x02
#define SDRAM_INIT_PALL 0x01
#define SDRAM_INIT_NORMAL 0x0c

/*****************************************************************************
 * Exception Vectors                                                         *
 *****************************************************************************/
_vectors:
  ldr pc, [pc, #reset_handler_address - . - 8] /* reset */
  ldr pc, [pc, #undef_handler_address - . - 8] /* undefined instruction */
  ldr pc, [pc, #swi_handler_address - . - 8] /* swi handler */
  ldr pc, [pc, #pabort_handler_address - . - 8] /* abort prefetch */
  ldr pc, [pc, #dabort_handler_address - . - 8] /* abort data */
  nop
  ldr pc, [pc, #irq_handler_address - . - 8]
  ldr pc, [pc, #fiq_handler_address - . - 8]

reset_handler_address:
  .word reset_handler
undef_handler_address:
  .word undef_handler
swi_handler_address:
  .word swi_handler
pabort_handler_address:
  .word pabort_handler
dabort_handler_address:
  .word dabort_handler
irq_handler_address:
  .word irq_handler
fiq_handler_address:
  .word fiq_handler

  .section .init, "ax"
  .code 32
  .align 0

/******************************************************************************
 *                                                                            *
 * Default exception handlers                                                 *
 *                                                                            *
 ******************************************************************************/
reset_handler:
#ifdef __FLASH_BUILD
  /* r10 = 0xfffe2000 */
  mov r10, #0x88000000
  mov r10, r10, asr #0xe 

  /* Set up clocks */
  mov r0, #3
  str r0, [r10, #0x1c] /* CpuClkPrescale: divider= 6 (50Mhz) */
  str r0, [r10, #0x18] /* HCLKPrescale: divider = 6 (50Mhz) */
  mov r0, #0x260
  add r0, r0, #0x3
  str r0, [r10, #0x00] /* RCPCCtrl: Start PLL */

  /* r1 = 0xFFFF1000 */
  mov r1, #0x88000000
  mov r1, r1, asr #0xf 

  /* SMCBCR0: Configure FLASH SMC for normal operation */
  mov r0, #0x10000000
  add r0, r0, #0x34c0
  str r0, [r1, #0] 

  /* r1 = 0xFFFE5000 */
  mov r1, #0x94000000
  mov r1, r1, asr #0xe 

  /* MemMux |= 0xFF: Assign necessary I/Os to SDRC */
  ldr r0, [r1, #0] 
  orr r0, r0, #0xFF
  str r0, [r1, #0]

  /* AHBClkCtrl &= 0xfffffffd: Enable HCLK feed to SDRC */
  ldr r0, [r10, #0x2c]
  bic r0, r0, #2
  str r0, [r10, #0x2c]

  /* Configure SDRAM */
  mov r0, #200
  bl delay

  /* r11 = 0xFFFF2000 */
  mov r11, #0x90000000
  mov r11, r11, asr #0xf 

  mov r0, #SDRAM_INIT_NOP
  str r0, [r11, #0x04] /* SDRCCONFIG1 = SDRAM_INIT_NOP */
  str r0, [r11, #0x04] /* SDRCCONFIG1 = SDRAM_INIT_NOP */

  /* DELAY to allow sdram clocks to settle */
  mov r0, #200 
  bl delay

  /* SDRCCONFIG1: Issue a "pre-charge all" command */
  mov r0, #SDRAM_INIT_PALL
  str r0, [r11, #0x4] 
  mov r0, #250
  bl delay

  /* SDRCRefTimer: Refresh every 16 clock cycles */
  mov r0, #16
  str r0, [r11, #0x8] 
  mov r0, #250
  bl delay

  /* SDRCRefTimer: Assumes 52 MHz default clock and 16us refresh period */
  mov r0, #800
  str r0, [r11, #0x8] 
  mov r0, #250
  bl delay

  /* SDRCCONFIG1: Select mode register update mode */
  mov r0, #SDRAM_INIT_MODE
  str r0, [r11, #0x4] 
  mov r1, #0x20000000 /* SDRAM BASE */
  add r1, r1, #0x22000
  ldr r0, [r1]
  bl sdram_wait_for_idle

  /* SDRCCONFIG0: Latency = 2, 32 bits, 4 banks */
  mov r0, #0x1a40000
  add r0, r0, #0x88
  str r0, [r11, #0x0]
  bl sdram_wait_for_idle

  /* SDRCCONFIG1: Select normal operating mode */
  mov r0, #SDRAM_INIT_NORMAL
  str r0, [r11, #0x04] /* SDRCCONFIG1 = SDRAM_INIT_NOP */
  bl sdram_wait_for_idle
  mov r0, #128
  bl delay

#ifdef SDRAM_EXCEPTIONS
  /* Copy exception vectors into SRAM */
  mov r8, #0x20000000
  ldr r9, =_vectors
  ldmia r9!, {r0-r7}
  stmia r8!, {r0-r7}
  ldmia r9!, {r0-r6}
  stmia r8!, {r0-r6}

  /* Remap External SDRAM to 0x00000000 */
  mov r0, #0x1
  str r0, [r10, #8]
#else
  /* Copy exception vectors into SRAM */
  mov r8, #0x60000000
  ldr r9, =_vectors
  ldmia r9!, {r0-r7}
  stmia r8!, {r0-r7}
  ldmia r9!, {r0-r6}
  stmia r8!, {r0-r6}

  /* Remap Internal SRAM to 0x00000000 */
  mov r0, #0x2
  str r0, [r10, #8]
#endif
#endif

  /* Jump to the default C runtime startup code. */
  b _start

/* Wait for SDRAM idle status
 * NOTE: Assumes R11 = 0xFFFF2000
 */
sdram_wait_for_idle:
  ldr r1, [r11, #0x4]
  tst r1, #0x20
  bne sdram_wait_for_idle
  mov pc, lr

delay:
  subs r0, r0, #1
  bne delay
  mov pc, lr

/******************************************************************************
 *                                                                            *
 * Default exception handlers                                                 *
 * These are declared weak symbols so they can be redefined in user code.     * 
 *                                                                            *
 ******************************************************************************/

undef_handler:
  b undef_handler
  
swi_handler:
  b swi_handler
  
pabort_handler:
  b pabort_handler
  
dabort_handler:
  b dabort_handler
  
irq_handler:
  b irq_handler
  
fiq_handler:
  b fiq_handler

  .weak undef_handler, swi_handler, pabort_handler, dabort_handler, irq_handler, fiq_handler

