/*****************************************************************************
 * 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. *
 *****************************************************************************/

#define APMC_CGMR_OFFSET 0x20
#define APMC_SR_OFFSET   0x30

#define APMC_CGMR_MOSCBYP (1 << 0)
#define APMC_CGMR_MOSCEN  (1 << 1)
#define APMC_CGMR_MOSODS  (1 << 2)
#define APMC_CGMR_PRES_SHIFT 4
#define APMC_CGMR_MUL_SHIFT 8
#define APMC_CGMR_CSS_SHIFT 14
#define APMC_CGMR_OSCOUNT_SHIFT 16
#define APMC_CGMR_PLLCOUNT_SHIFT 24

#define APMC_CGMR_CSS_LF 0
#define APMC_CGMR_CSS_MOSC 1
#define APMC_CGMR_CSS_PLL 2

#define APMC_SR_MOSCS (1 << 0)
#define APMC_SR_LOCK  (1 << 1)

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

#ifdef __FLASH_BUILD

/*****************************************************************************
 * Exception Vectors (Prior to remap)                                        *
 *****************************************************************************/
_pre_remap_vectors:
  b configure_and_start 
  b undef_handler
  b swi_handler
  b pabort_handler
  b dabort_handler
  .word 0 
  b irq_handler
  b fiq_handler

#endif

/*****************************************************************************
 * Exception Vectors (Post remap)                                            *
 *****************************************************************************/
_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] /* irq */
  ldr pc, [pc, #fiq_handler_address - . - 8] /* fiq */

_exception_entrypoints:
reset_handler_address:
  .word _start
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

#ifdef __FLASH_BUILD
/*****************************************************************************
 * Function    : configure_and_start                                         *
 * Description : Configure memory and jump to the _start entrypoint.         *
 *****************************************************************************/
configure_and_start:
  mov r0, #0xA0000000
  mov r0, r0, asr #0xF /* APMC_BASE (0xFFFF4000) */

  /* Only configure clock source if it has not already been configured */
  ldr r1, [r0, #APMC_CGMR_OFFSET]
  cmp r1, #0
  bne clock_config_end

  /* Enable main oscillator */
  mov r1, #APMC_CGMR_MOSCEN
  orr r1, r1, #0x2F << APMC_CGMR_OSCOUNT_SHIFT
  str r1, [r0, #APMC_CGMR_OFFSET]

  /* Wait for main oscillator to stabilize */
1:
  ldr r2, [r0, #APMC_SR_OFFSET]
  tst r2, #APMC_SR_MOSCS
  beq 1b

  /* Set main oscillator as clock source */
  orr r1, r1, #APMC_CGMR_CSS_MOSC << APMC_CGMR_CSS_SHIFT
  str r1, [r0, #APMC_CGMR_OFFSET]

  /* Enable the PLL */
  orr r1, r1, #1 << APMC_CGMR_MUL_SHIFT
  orr r1, r1, #3 << APMC_CGMR_PLLCOUNT_SHIFT
  str r1, [r0, #APMC_CGMR_OFFSET]

  /* Wait for PLL to stabilize */
1:
  ldr r2, [r0, #APMC_SR_OFFSET]
  tst r2, #APMC_SR_LOCK
  beq 1b

  /* Set PLL as clock source */
  bic r1, r1, #APMC_CGMR_CSS_MOSC << APMC_CGMR_CSS_SHIFT
  orr r1, r1, #APMC_CGMR_CSS_PLL << APMC_CGMR_CSS_SHIFT
  str r1, [r0, #APMC_CGMR_OFFSET]
clock_config_end:

  /* Copy exception vectors */
  mov r8, #0x00300000 /* Address of SRAM prior to remap */
  mov r9, #(_vectors - _pre_remap_vectors) /* Address of _vectors in FLASH prior 
                                              to remap (FLASH at 0x00000000) */
  ldmia r9!, {r0-r7}
  stmia r8!, {r0-r7}
  ldmia r9!, {r0-r6}
  stmia r8!, {r0-r6}
          
  /* Configure memory */
configure_memory:
  sub r10, pc, #(+.-memory_configuration+8)
  ldr r12, =_start
  ldmia r10!, {r0-r9, r11}
  stmia r11, {r0-r9}

  /* Leap to the main entry point */
  mov pc, r12

/******************************************************************************
 * System configuration registers for the following memory layout:            *
 *                                                                            *
 *     ------------------                                                     *
 *    |  External SRAM   | 0x02000000 - 0x02001FFF                            *
 *    |------------------|                                                    *
 *    |      FLASH       | 0x01000000 - 0x011FFFFF                            *
 *    |------------------|                                                    *
 *    |  Internal SRAM   | 0x00000000 - 0x0003FFFF                            *
 *     ------------------                                                     *
 *                                                                            *
 ******************************************************************************/
memory_configuration:
.word 0x01002529 // EBI_CSR0
.word 0x02002121 // EBI_CSR1
.word 0x20000000 // EBI_CSR2
.word 0x30000000 // EBI_CSR3
.word 0x40000000 // EBI_CSR4
.word 0x50000000 // EBI_CSR5
.word 0x60000000 // EBI_CSR6
.word 0x70000000 // EBI_CSR7
.word 0x00000001 // EBI_RCR (remap command)
.word 0x00000006 // EBI_MCR (6 memory regions, standard read)
.word 0xFFE00000 // EBI Base Address

#endif

/******************************************************************************
 *                                                                            *
 * 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
