| /**************************************************************************** |
| * arch/arm/src/str71x/str71x_head.S |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. The |
| * ASF licenses this file to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance with the |
| * License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| * License for the specific language governing permissions and limitations |
| * under the License. |
| * |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Included Files |
| ****************************************************************************/ |
| |
| #include <nuttx/config.h> /* NuttX configuration settings */ |
| |
| #include "arm.h" /* ARM-specific settings */ |
| #include "chip.h" /* Chip-specific settings */ |
| |
| /**************************************************************************** |
| * Pre-processor Definitions |
| ****************************************************************************/ |
| |
| /* This file holds the NuttX start logic that runs when the STR711 |
| * is reset. This logic must be located at address 0x4000:0000 in |
| * flash. It will also be mapped to address zero when the STR711 is |
| * reset. |
| */ |
| |
| /**************************************************************************** |
| * External references |
| ****************************************************************************/ |
| |
| .globl str71x_prccuinit /* Clock initialization */ |
| .globl up_lowsetup /* Early initialization of UART */ |
| #ifdef USE_EARLYSERIALINIT |
| .globl arm_earlyserialinit /* Early initialization of serial driver */ |
| #endif |
| #ifdef CONFIG_ARCH_LEDS |
| .globl board_autoled_initialize /* Boot LED setup */ |
| #endif |
| #ifdef CONFIG_DEBUG_FEATURES |
| .globl arm_lowputc /* Low-level debug output */ |
| #endif |
| .globl nx_start /* NuttX entry point */ |
| |
| /**************************************************************************** |
| * Macros |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Name: showprogress |
| * |
| * Description: |
| * Print a character on the UART to show boot status. This macro will |
| * modify r0, r1, r2 and r14 |
| * |
| ****************************************************************************/ |
| |
| .macro showprogress, code |
| #ifdef CONFIG_DEBUG_FEATURES |
| mov r0, #\code |
| bl arm_lowputc |
| #endif |
| .endm |
| |
| /**************************************************************************** |
| * Name: emiinit |
| * |
| * Description: |
| * Initialize external memory banks 0-3 as configured |
| * |
| ****************************************************************************/ |
| |
| .macro emiinit, base, value |
| #if defined(CONFIG_STR71X_BANK0) || defined(CONFIG_STR71X_BANK1) || \ |
| defined(CONFIG_STR71X_BANK2) || defined(CONFIG_STR71X_BANK3) |
| |
| /* In order to use the external memory, certain GPIO pins must be |
| * configured in the alternate function: |
| * |
| * GPIO ALT Description |
| * P2.0-3 CS.0-3 External memory chip select for banks 0,1,3,4 |
| * P2.4-7 A.20-23 External memory extended address bus (needed for |
| * address space > 1Mb) |
| */ |
| |
| #ifdef CONFIG_STR71X_BIGEXTMEM |
| # define EXTMEM_GPIO_BITSET 0x000000ff /* P2.0-7 */ |
| #else |
| # define EXTMEM_GPIO_BITSET 0x0000000f /* P2.0-3 */ |
| #endif |
| |
| ldr \base, =STR71X_GPIO_BASE /* Configure P2.0 to P2.3/7 in AF_PP mode */ |
| ldr \value, [\base, #STR71X_GPIO_PC0_OFFSET] |
| orr \value, \value, #EXTMEM_GPIO_BITSET |
| str \value, [\base, #STR71X_GPIO_PC0_OFFSET] |
| ldr \value, [\base, #STR71X_GPIO_PC1_OFFSET] |
| orr \value, \value, #EXTMEM_GPIO_BITSET |
| str \value, [\base, #STR71X_GPIO_PC1_OFFSET] |
| ldr \value, [\base, #STR71X_GPIO_PC2_OFFSET] |
| orr \value, \value, #EXTMEM_GPIO_BITSET |
| str \value, [\base, #STR71X_GPIO_PC2_OFFSET] |
| |
| /* Enable bank 0 */ |
| |
| ldr \base, =STR71X_EMI_BASE |
| |
| #ifdef CONFIG_STR71X_BANK0 |
| |
| /* Get the bank 0 size */ |
| |
| # if CONFIG_STR71X_BANK0_SIZE == 8 |
| # define EXTMEM_BANK0_SIZE STR71X_EMIBCON_BSIZE8 |
| # elif CONFIG_STR71X_BANK0_SIZE == 16 |
| # define EXTMEM_BANK0_SIZE STR71X_EMIBCON_BSIZE16 |
| # else |
| # error "CONFIG_STR71X_BANK0_SIZE invalid" |
| # endif |
| |
| /* Get the bank 0 waitstates */ |
| |
| # if !defined(CONFIG_STR71X_BANK0_WAITSTATES) || \ |
| CONFIG_STR71X_BANK0_WAITSTATES < 0 || CONFIG_STR71X_BANK0_WAITSTATES > 15 |
| # error "CONFIG_STR71X_BANK0_WAITSTATES invalid" |
| # else |
| /* Bits 2-5: wait states */ |
| # define EXTMEM_BANK0_WAITSTATES (CONFIG_STR71X_BANK0_WAITSTATES << 2) |
| # endif |
| |
| ldr \value, =(STR71X_EMIBCON_ENABLE|EXTMEM_BANK0_WAITSTATES|EXTMEM_BANK0_SIZE) |
| #else |
| mov \value, #0 |
| #endif |
| str \value, [\base, #STR71X_EMI_BCON0_OFFSET] |
| |
| /* Enable bank 1 */ |
| |
| #ifdef CONFIG_STR71X_BANK1 |
| |
| /* Get the bank 1 size */ |
| |
| # if CONFIG_STR71X_BANK1_SIZE == 8 |
| # define EXTMEM_BANK1_SIZE STR71X_EMIBCON_BSIZE8 |
| # elif CONFIG_STR71X_BANK1_SIZE == 16 |
| # define EXTMEM_BANK1_SIZE STR71X_EMIBCON_BSIZE16 |
| # else |
| # error "CONFIG_STR71X_BANK1_SIZE invalid" |
| # endif |
| |
| /* Get the bank 1 waitstates */ |
| |
| # if !defined(CONFIG_STR71X_BANK1_WAITSTATES) || \ |
| CONFIG_STR71X_BANK1_WAITSTATES < 0 || CONFIG_STR71X_BANK1_WAITSTATES > 15 |
| # error "CONFIG_STR71X_BANK1_WAITSTATES invalid" |
| # else |
| /* Bits 2-5: wait states */ |
| # define EXTMEM_BANK1_WAITSTATES (CONFIG_STR71X_BANK1_WAITSTATES << 2) |
| # endif |
| |
| ldr \value, =(STR71X_EMIBCON_ENABLE|EXTMEM_BANK1_WAITSTATES|EXTMEM_BANK1_SIZE) |
| #else |
| mov \value, #0 |
| #endif |
| str \value, [\base, #STR71X_EMI_BCON1_OFFSET] |
| |
| /* Enable bank 2 */ |
| |
| #ifdef CONFIG_STR71X_BANK2 |
| |
| /* Get the bank 2 size */ |
| |
| # if CONFIG_STR71X_BANK2_SIZE == 8 |
| # define EXTMEM_BANK2_SIZE STR71X_EMIBCON_BSIZE8 |
| # elif CONFIG_STR71X_BANK2_SIZE == 16 |
| # define EXTMEM_BANK2_SIZE STR71X_EMIBCON_BSIZE16 |
| # else |
| # error "CONFIG_STR71X_BANK2_SIZE invalid" |
| # endif |
| |
| /* Get the bank 2 waitstates */ |
| |
| # if !defined(CONFIG_STR71X_BANK2_WAITSTATES) || \ |
| CONFIG_STR71X_BANK2_WAITSTATES < 2 || CONFIG_STR71X_BANK2_WAITSTATES > 15 |
| # error "CONFIG_STR71X_BANK2_WAITSTATES invalid" |
| # else |
| /* Bits 2-5: wait states */ |
| # define EXTMEM_BANK2_WAITSTATES (CONFIG_STR71X_BANK2_WAITSTATES << 2) |
| # endif |
| |
| ldr \value, =(STR71X_EMIBCON_ENABLE|EXTMEM_BANK2_WAITSTATES|EXTMEM_BANK2_SIZE) |
| #else |
| mov \value, #0 |
| #endif |
| str \value, [\base, #STR71X_EMI_BCON2_OFFSET] |
| |
| /* Enable bank 3 */ |
| |
| #ifdef CONFIG_STR71X_BANK3 |
| |
| /* Get the bank 3 size */ |
| |
| # if CONFIG_STR71X_BANK3_SIZE == 8 |
| # define EXTMEM_BANK3_SIZE STR71X_EMIBCON_BSIZE8 |
| # elif CONFIG_STR71X_BANK3_SIZE == 16 |
| # define EXTMEM_BANK3_SIZE STR71X_EMIBCON_BSIZE16 |
| # else |
| # error "CONFIG_STR71X_BANK3_SIZE invalid" |
| # endif |
| |
| /* Get the bank 3 waitstates */ |
| |
| # if !defined(CONFIG_STR71X_BANK3_WAITSTATES) || \ |
| CONFIG_STR71X_BANK3_WAITSTATES < 3 || CONFIG_STR71X_BANK3_WAITSTATES > 15 |
| # error "CONFIG_STR71X_BANK3_WAITSTATES invalid" |
| # else |
| /* Bits 2-5: wait states */ |
| # define EXTMEM_BANK3_WAITSTATES (CONFIG_STR71X_BANK3_WAITSTATES << 2) |
| # endif |
| |
| ldr \value, =(STR71X_EMIBCON_ENABLE|EXTMEM_BANK3_WAITSTATES|EXTMEM_BANK3_SIZE) |
| #else |
| mov \value, #0 |
| #endif |
| str \value, [\base, #STR71X_EMI_BCON3_OFFSET] |
| #endif |
| .endm |
| |
| /**************************************************************************** |
| * Name: eicinit |
| * |
| * Description: |
| * The EIC is initialized for use with NuttX. This initialization does not |
| * take advantage of the high performance capabilities of the EIC. Instead, |
| * The EIC is only used to provide NuttX IRQ numbers. Here is what is |
| * done: |
| * |
| * IRQs and FIQs are disabled |
| * IVR set to zero |
| * All channels are disabled |
| * Channels set to priority 0 |
| * All SIR[n] registers contain the NuttX IRQ number in the MS 16-bits |
| * |
| * At the time of IRQ processing, the IVR will contain the decoded IRQ |
| * number needed by NuttX. |
| * |
| ****************************************************************************/ |
| |
| .macro eicinit, eicbase, value, irqno, offset |
| /* Disable and clear all interrupts */ |
| |
| ldr \eicbase, =STR71X_EIC_BASE |
| |
| /* Disable FIQ and IRQ */ |
| |
| mov \value, #0 |
| str \value, [\eicbase, #STR71X_EIC_ICR_OFFSET] |
| |
| /* Disable all channel interrupts */ |
| |
| str \value, [\eicbase, #STR71X_EIC_IER_OFFSET] |
| |
| /* Clear all pending IRQs */ |
| |
| ldr \value, =0xffffffff |
| str \value, [\eicbase, #STR71X_EIC_IPR_OFFSET] |
| |
| /* Disable FIQ channels/clear pending FIQs */ |
| |
| mov \value, #0x0c |
| str \value, [\eicbase, #STR71X_EIC_FIR_OFFSET] |
| |
| /* Reset the current priority register */ |
| |
| mov \value, #0 |
| str \value, [\eicbase, #STR71X_EIC_CIPR_OFFSET] |
| |
| /* Zero IVR 31:16 */ |
| |
| str \value, [\eicbase, #STR71X_EIC_IVR_OFFSET] |
| |
| /* Set up the loop to initialize each SIR register. Start |
| * with IRQ number 0 and SIR0 |
| */ |
| |
| mov \irqno, #0 |
| ldr \offset, =STR71X_EIC_SIR_OFFSET |
| |
| /* Then loop for each EIC channel */ |
| eicloop: |
| /* Shift the IRQ number to bits 16-31 and save the shifted IRQ |
| * number as SIR[irqno]. This will appear as bits 0:15 in the |
| * IVR during IRQ processing. |
| * |
| * NOTE that the initial priority is set to zero -- the current |
| * interrupt priority (CIP) is always zero, so these interrupts |
| * are all disabled. |
| */ |
| |
| mov \value, \irqno, lsl #16 |
| str \value, [\eicbase, \offset] |
| |
| /* Increment the offset to the next SIR register and inrement |
| * the IRQ number. |
| */ |
| |
| add \offset, \offset, #4 |
| add \irqno, \irqno, #1 |
| |
| /* Continue to loop until all of the SIR registers have been |
| * initializeed. |
| */ |
| |
| cmp \irqno, #STR71X_EIC_NCHANNELS |
| blt eicloop |
| .endm |
| |
| /**************************************************************************** |
| * Name: periphinit |
| * |
| * Description: |
| * Disable all perfipherals (except EIC) |
| * |
| ****************************************************************************/ |
| |
| .macro periphinit, value, base1, base2 |
| #ifndef CONFIG_STR71X_DISABLE_PERIPHINIT |
| /* Set up APB1 and APB2 addresses */ |
| |
| ldr \base1, =STR71X_APB1_BASE |
| ldr \base2, =STR71X_APB2_BASE |
| |
| /* Disable all APB1 peripherals */ |
| |
| ldr \value, =STR71X_APB1_APB1ALL |
| strh \value, [\base1, #STR71X_APB_CKDIS_OFFSET] |
| |
| /* Disable all(or most) APB2 peripherals */ |
| |
| ldr \value, =(STR71X_APB2_APB2ALL & ~STR71X_APB2_EIC) |
| strh \value, [\base2, #STR71X_APB_CKDIS_OFFSET] |
| |
| /* Allow EMI and USB */ |
| |
| ldr \base1, =STR71X_RCCU_BASE |
| #ifdef CONFIG_STR71X_USB |
| ldr \value, =(STR71X_RCCUPER_EMI|STR71X_RCCUPER_USBKERNEL) |
| #else |
| ldr \value, =STR71X_RCCUPER_EMI |
| #endif |
| strh \value, [\base1, #STR71X_RCCU_PER_OFFSET] |
| #endif |
| .endm |
| |
| /**************************************************************************** |
| * Name: remap |
| * |
| * Description: |
| * Remap memory at address 0x0000000 to either FLASH. The system always |
| * boots at Bank0, sector 0 of FLASH. Part of the initial setup will be to |
| * map the memory appropriately for the execution configuration. Various |
| * options are possible, but only boot from FLASH is currently supported. |
| * |
| ****************************************************************************/ |
| |
| .macro remap, base, value |
| |
| /* Read the PCU BOOTCR register */ |
| |
| ldr \base, =STR71X_PCU_BASE |
| ldrh \value, [\base, #STR71X_PCU_BOOTCR_OFFSET] |
| |
| /* Mask out the old boot mode bits and set the boot mode to FLASH */ |
| |
| bic \value, \value, #STR71X_PCUBOOTCR_BOOTMASK |
| orr \value, \value, #STR71X_PCUBOOTCR_BMFLASH |
| |
| /* Save the modified BOOTCR register */ |
| |
| strh \value, [\base, #STR71X_PCU_BOOTCR_OFFSET] |
| .endm |
| |
| /**************************************************************************** |
| * Text |
| ****************************************************************************/ |
| |
| .text |
| |
| /**************************************************************************** |
| * Name: _vector_table |
| * |
| * Description: |
| * Interrupt vector table. This must be located at the beginning |
| * of the memory space (at the beginning FLASH which will be mapped to |
| * address 0x00000000). The first entry in the vector table is the reset |
| * vector and this is the code that will execute when the processor is reset. |
| * |
| ****************************************************************************/ |
| |
| .globl _vector_table |
| .type _vector_table, %function |
| _vector_table: |
| ldr pc, .Lresethandler /* 0x00: Reset */ |
| ldr pc, .Lundefinedhandler /* 0x04: Undefined instruction */ |
| ldr pc, .Lswihandler /* 0x08: Software interrupt */ |
| ldr pc, .Lprefetchaborthandler /* 0x0c: Prefetch abort */ |
| ldr pc, .Ldataaborthandler /* 0x10: Data abort */ |
| .long 0 /* 0x14: Reserved vector */ |
| ldr pc, .Lirqhandler /* 0x18: IRQ */ |
| ldr pc, .Lfiqhandler /* 0x1c: FIQ */ |
| |
| .globl __start |
| .globl arm_vectorundefinsn |
| .globl arm_vectorsvc |
| .globl arm_vectorprefetch |
| .globl arm_vectordata |
| .globl arm_vectorirq |
| .globl arm_vectorfiq |
| |
| .Lresethandler: |
| .long __start |
| .Lundefinedhandler: |
| .long arm_vectorundefinsn |
| .Lswihandler: |
| .long arm_vectorsvc |
| .Lprefetchaborthandler: |
| .long arm_vectorprefetch |
| .Ldataaborthandler: |
| .long arm_vectordata |
| .Lirqhandler: |
| .long arm_vectorirq |
| .Lfiqhandler: |
| .long arm_vectorfiq |
| .size _vector_table, . - _vector_table |
| |
| /**************************************************************************** |
| * Name: __start |
| * |
| * Description: |
| * Reset entry point. This is the first function to execute when |
| * the processor is reset. It initializes hardware and then gives |
| * control to NuttX. |
| * |
| ****************************************************************************/ |
| |
| .global __start |
| .type __start, #function |
| |
| __start: |
| /* On reset, an aliased copy of FLASH is mapped to address 0x00000000. |
| * Continue execution in the 'real' FLASH address space rather than |
| * the aliased copy |
| */ |
| |
| ldr pc, =__flashstart |
| __flashstart: |
| .rept 9 |
| nop /* Wait for OSC stabilization */ |
| .endr |
| |
| /* Setup the initial processor mode */ |
| |
| mov r0, #(PSR_MODE_SYS | PSR_I_BIT | PSR_F_BIT ) |
| msr cpsr, r0 |
| |
| /* Initialize the external memory interface (EMI) */ |
| |
| emiinit r0, r1 |
| |
| /* Initialize the enhanced interrupt controller (EIC) */ |
| |
| eicinit r0, r1, r2, r3 |
| |
| /* Disable all peripherals except EIC */ |
| |
| periphinit r0, r1, r2 |
| |
| /* Map memory appropriately for configuration */ |
| |
| remap r0, r1 |
| |
| /* Setup system stack (and get the BSS range) */ |
| |
| adr r0, LC0 |
| ldmia r0, {r4, r5, sp} |
| |
| /* Clear system BSS section */ |
| |
| mov r0, #0 |
| 1: cmp r4, r5 |
| strcc r0, [r4], #4 |
| bcc 1b |
| |
| /* Copy system .data sections from FLASH to new home in RAM. */ |
| |
| adr r3, LC2 |
| ldmia r3, {r0, r1, r2} |
| |
| 2: ldmia r0!, {r3 - r10} |
| stmia r1!, {r3 - r10} |
| cmp r1, r2 |
| blt 2b |
| |
| /* Initialize clocking */ |
| |
| bl str71x_prccuinit |
| |
| /* Configure the uart so that we can get debug output as soon |
| * as possible. |
| */ |
| |
| bl up_lowsetup |
| showprogress 'A' |
| |
| /* Perform early serial initialization */ |
| |
| mov fp, #0 |
| #ifdef USE_EARLYSERIALINIT |
| bl arm_earlyserialinit |
| #endif |
| |
| showprogress 'B' |
| |
| /* Call C++ constructors */ |
| |
| #ifdef CONFIG_CPLUSPLUS |
| ldr r0, =__ctors_start__ |
| ldr r1, =__ctors_end__ |
| ctor_loop: |
| cmp r0, r1 |
| beq ctor_end |
| ldr r2, [r0], #4 |
| stmfd sp!, {r0-r1} |
| mov lr, pc |
| mov pc, r2 |
| ldmfd sp!, {r0-r1} |
| b ctor_loop |
| ctor_end: |
| |
| showprogress 'C' |
| #endif |
| showprogress '\n' |
| |
| /* Initialize onboard LEDs */ |
| |
| #ifdef CONFIG_ARCH_LEDS |
| bl board_autoled_initialize |
| #endif |
| |
| /* Then jump to OS entry */ |
| |
| b nx_start |
| |
| /* Call destructors -- never get here */ |
| |
| #if 0 /* CONFIG_CPLUSPLUS */ |
| ldr r0, =__dtors_start__ |
| ldr r1, =__dtors_end__ |
| dtor_loop: |
| cmp r0, r1 |
| beq dtor_end |
| ldr r2, [r0], #4 |
| stmfd sp!, {r0-r1} |
| mov lr, pc |
| mov pc, r2 |
| ldmfd sp!, {r0-r1} |
| b dtor_loop |
| dtor_end: |
| #endif |
| |
| /* Variables: |
| * _sbss is the start of the BSS region (see ld.script) |
| * _ebss is the end of the BSS region (see ld.script) |
| * The idle task stack starts at the end of BSS and is |
| * of size CONFIG_IDLETHREAD_STACKSIZE. The heap continues |
| * from there until the end of memory. See g_idle_topstack |
| * below. |
| */ |
| |
| LC0: .long _sbss |
| .long _ebss |
| .long _ebss+CONFIG_IDLETHREAD_STACKSIZE |
| |
| LC2: .long _eronly /* Where .data defaults are stored in FLASH */ |
| .long _sdata /* Where .data needs to reside in SDRAM */ |
| .long _edata |
| .size __start, .-__start |
| |
| /* This global variable is unsigned long g_idle_topstack and is |
| * exported from here only because of its coupling to LCO |
| * above. |
| */ |
| |
| .data |
| .align 4 |
| .globl g_idle_topstack |
| .type g_idle_topstack, object |
| g_idle_topstack: |
| .long _ebss+CONFIG_IDLETHREAD_STACKSIZE |
| .size g_idle_topstack, .-g_idle_topstack |
| |
| .end |