| /*************************************************************************** |
| * __________ __ ___. |
| * Open \______ \ ____ ____ | | _\_ |__ _______ ___ |
| * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / |
| * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < |
| * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ |
| * \/ \/ \/ \/ \/ |
| * $Id$ |
| * |
| * Copyright (C) 2002 by Linus Nielsen Feltzing |
| * |
| * This program is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU General Public License |
| * as published by the Free Software Foundation; either version 2 |
| * of the License, or (at your option) any later version. |
| * |
| * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY |
| * KIND, either express or implied. |
| * |
| ****************************************************************************/ |
| #include "config.h" |
| #include "cpu.h" |
| |
| .section .init.text,"ax",%progbits |
| |
| .global start |
| start: |
| /* Exception vectors */ |
| b newstart |
| b undef_instr_handler |
| b software_int_handler |
| b prefetch_abort_handler |
| b data_abort_handler |
| b reserved_handler |
| b irq_handler |
| b fiq_handler |
| .balign 0x40, 0x6B |
| |
| /* Arm bootloader and startup code based on startup.s from the iPodLinux loader |
| * |
| * Copyright (c) 2003, Daniel Palffy (dpalffy (at) rainstorm.org) |
| * Copyright (c) 2005, Bernard Leach <leachbj@bouncycastle.org> |
| * |
| */ |
| |
| /* Initially this code is running at VA 0x8a000000 (PA 0x82000000). |
| * The mapping stub is copied to IRAM (0x1fffc000) and jumps to the final |
| * VA remapping starting at 0x01f00000 because the 1MB section containing |
| * the framebuffer at PA 0x81000000 is skipped in the remapping giving 63MB |
| * of contiguous RAM for the firmware. The TTB is placed at the end of said |
| * section. |
| * |
| * For now this will be done in bootloader, especially if usb will be needed |
| * within the bootloader to load the main firmware file. Interrupts will be |
| * needed for this (whether they be swi or irq). |
| */ |
| newstart: |
| msr cpsr_c, #0xd3 /* enter supervisor mode, disable IRQ/FIQ */ |
| |
| #ifdef BOOTLOADER |
| adr r2, remap_start /* Load PC-relative labels */ |
| adr r3, remap_end |
| ldr r5, =TTB_BASE_ADDR /* TTB pointer */ |
| ldr r6, =IRAM_BASE_ADDR |
| mov r1, r6 |
| |
| 1: /* Copy remapping stub to IRAM */ |
| cmp r3, r2 |
| ldrhi r4, [r2], #4 |
| strhi r4, [r1], #4 |
| bhi 1b |
| |
| mov pc, r6 |
| |
| /* Remapping stub. No absolute addresses may be used until after the |
| * remapping is complete. */ |
| remap_start: |
| mrc p15, 0, r3, c1, c0, 0 /* perform writeback if D cache is enabled */ |
| tst r3, #(1 << 2) /* dcache? */ |
| tsteq r3, #(1 << 12) /* or icache? */ |
| mov r0, #0 |
| mcrne p15, 0, r0, c7, c10, 0 /* clean dcache */ |
| mcrne p15, 0, r0, c7, c7, 0 /* invalidate I cache and D cache */ |
| mcr p15, 0, r0, c8, c7, 0 /* invalidate TLBs */ |
| mcr p15, 0, r0, c7, c10, 4 /* Drain the write buffer */ |
| |
| mcr p15, 0, r0, c13, c0, 0 |
| mcr p15, 0, r0, c13, c0, 1 |
| |
| /* Also setup the Peripheral Port Remap register inside the core */ |
| mov r0, #0x40000000 /* start from AIPS 2GB region */ |
| add r0, r0, #0x15 |
| mcr p15, 0, r0, c15, c2, 4 |
| |
| /*** L2 Cache setup/invalidation/disable ***/ |
| /* Disable L2 cache first */ |
| mov r0, #L2CC_BASE_ADDR |
| mov r1, #0 |
| str r1, [r0, #L2_CACHE_CTL_REG] |
| |
| /* Disble L1 caches and memory manager */ |
| bic r3, r3, #(1 << 12) /* L1 I-cache disabled */ |
| bic r3, r3, #((1 << 2) | /* L1 D-cache disabled */ \ |
| (1 << 0)) /* MMU disabled */ |
| mcr p15, 0, r3, c1, c0, 0 |
| |
| /* |
| * Configure L2 Cache: |
| * - 128k size(16k way) |
| * - 8-way associativity |
| * - 0 ws TAG/VALID/DIRTY |
| * - 4 ws DATA R/W |
| */ |
| mov r1, #0x00130000 |
| orr r1, r1, #0x24 |
| str r1, [r0, #L2_CACHE_AUX_CTL_REG] |
| |
| /* Invalidate L2 */ |
| mov r1, #0x000000FF |
| str r1, [r0, #L2_CACHE_INV_WAY_REG] |
| 1: |
| /* Poll Invalidate By Way register */ |
| ldr r1, [r0, #L2_CACHE_INV_WAY_REG] |
| cmp r1, #0 |
| bne 1b |
| |
| /*** End of L2 operations ***/ |
| |
| /* TTB Initialisation */ |
| mov r2, r5 |
| add r3, r5, #TTB_SIZE |
| mov r1, #0 |
| 1: |
| str r1, [r2], #4 |
| cmp r2, r3 |
| blo 1b |
| |
| /* Set TTB base address */ |
| mcr p15, 0, r5, c2, c0, 0 |
| |
| /* Set all domains to manager status */ |
| mvn r0, #0 |
| mcr p15, 0, r0, c3, c0, 0 |
| |
| /* Set page tables */ |
| |
| /* Map each memory loc to itself, no cache */ |
| /* Physical address = 0x0 */ |
| mov r1, #(1 << 10) /* superuser - r/w, user - no access */ |
| orr r1, r1, #((0 << 5) | /* domain 0th */ \ |
| (1 << 4) | /* should be "1" */ \ |
| (1 << 1)) /* Section signature */ |
| mov r2, r5 |
| add r3, r5, #TTB_SIZE /* End position */ |
| 1: |
| str r1, [r2], #4 |
| add r1, r1, #(1 << 20) /* Next MB */ |
| cmp r2, r3 |
| blo 1b |
| sub r1, r1, #TTB_SIZE/4*(1 << 20) /* Back up */ |
| |
| /* Map 0x80000000 -> 0x0, cached */ |
| mov r2, r5 /* TTB pointer */ |
| add r3, r5, #63*4 /* End position */ |
| orr r1, r1, #0x80000000 /* Physical address */ |
| orr r1, r1, #((1 << 3) | /* cache flag */ \ |
| (1 << 2)) /* buffer flag */ |
| 1: |
| str r1, [r2], #4 |
| add r1, r1, #(1 << 20) |
| and r4, r1, #0x0ff00000 |
| cmp r4, #0x00100000 /* Skip framebuffer */ |
| addeq r1, r1, #(1 << 20) |
| cmp r2, r3 |
| blo 1b |
| |
| /* Map device section 0x80100000 to 0x03f00000 - buffered, not cached */ |
| bic r1, r1, #0x0ff00000 |
| orr r1, r1, #0x00100000 |
| bic r1, r1, #(1 << 3) |
| add r2, r5, #63*4 |
| str r1, [r2] |
| |
| /* Enable MMU */ |
| |
| mov r0, #0 |
| mcr p15, 0, r0, c8, c7, 0 /* Invalidate TLB */ |
| mcr p15, 0, r0, c7, c7, 0 /* Invalidate icache and dcache */ |
| |
| /* Auxilliary control register */ |
| mrc p15, 0, r0, c1, c0, 1 |
| bic r0, r0, #((1 << 6) | /* Restrict cache size OFF */ \ |
| (1 << 5) | /* Enable block tranfer cache operations */ \ |
| (1 << 4) | /* Clean+Invalidate cache operation ON */ \ |
| (1 << 3)) /* Round-robin micro TLB replacement */ |
| orr r0, r0, #((1 << 2) | /* Static branch prediction ON */ \ |
| (1 << 1) | /* Dynamic branch prediction ON */ \ |
| (1 << 0)) /* Return stack enabled */ |
| mcr p15, 0, r0, c1, c0, 1 |
| |
| /* Control register */ |
| mrc p15, 0, r0, c1, c0, 0 |
| bic r0, r0, #((1 << 29) | /* AF by AP disabled */ \ |
| (1 << 28) | /* TEX remap disabled */ \ |
| (1 << 23)) /* Sub AP bits enabled (compatible) */ |
| bic r0, r0, #((1 << 21) | /* All performance features enabled */ \ |
| (1 << 15)) /* Loads to PC set T bit */ |
| bic r0, r0, #((1 << 13)) /* Low vectors */ |
| bic r0, r0, #((1 << 1)) /* Strict alignment disabled */ |
| orr r0, r0, #((1 << 24) | /* Vectored interrupt ON */ \ |
| (1 << 22)) /* Unaligned access support enabled */ |
| orr r0, r0, #((1 << 14) | /* Round-robin replacement for I/D caches */ \ |
| (1 << 12) | /* L1 I-cache enabled */ \ |
| (1 << 11) | /* Program flow prediction enabled */ \ |
| (1 << 9) | /* ROM protection enabled */ \ |
| (1 << 8)) /* MMU protection enabled */ |
| orr r0, r0, #((1 << 2) | /* L1 D-cache enabled */ \ |
| (1 << 0)) /* MMU enabled */ |
| mcr p15, 0, r0, c1, c0, 0 |
| nop |
| nop |
| nop |
| nop |
| nop |
| nop |
| nop |
| nop |
| ldr pc, L_post_remap |
| L_post_remap: |
| .word remap_end |
| remap_end: |
| |
| #endif /* BOOTLOADER */ |
| |
| #ifdef BOOTLOADER |
| /* Copy bootloader exception handler code to address 0 */ |
| ldr r2, =_vectorsstart |
| ldr r3, =_vectorsend |
| ldr r4, =_vectorscopy |
| 1: |
| cmp r3, r2 |
| ldrhi r5, [r4], #4 |
| strhi r5, [r2], #4 |
| bhi 1b |
| #endif /* BOOTLOADER */ |
| |
| /* Initialise bss section to zero */ |
| ldr r2, =_edata |
| ldr r3, =_end |
| mov r4, #0 |
| 1: |
| cmp r3, r2 |
| strhi r4, [r2], #4 |
| bhi 1b |
| |
| /* Initialise the device bss section to zero */ |
| ldr r2, =_devbssdata |
| ldr r3, =_devbssend |
| mov r4, #0 |
| 1: |
| cmp r3, r2 |
| strhi r4, [r2], #4 |
| bhi 1b |
| |
| /* Set up some stack and munge it with 0xdeadbeef */ |
| ldr sp, =stackend |
| ldr r2, =stackbegin |
| ldr r3, =0xdeadbeef |
| 1: |
| cmp sp, r2 |
| strhi r3, [r2], #4 |
| bhi 1b |
| |
| /* Set up stack for IRQ mode */ |
| msr cpsr_c, #0xd2 |
| ldr sp, =irq_stack |
| |
| /* Set up stack for FIQ mode */ |
| msr cpsr_c, #0xd1 |
| ldr sp, =fiq_stack |
| |
| /* Let abort and undefined modes use IRQ stack */ |
| msr cpsr_c, #0xd7 |
| ldr sp, =irq_stack |
| msr cpsr_c, #0xdb |
| ldr sp, =irq_stack |
| |
| /* Switch back to supervisor mode */ |
| msr cpsr_c, #0xd3 |
| bl main |
| |
| #ifdef BOOTLOADER |
| /* Exception vectors with absolute jumps for bootloader */ |
| .section .vectors,"aw" |
| ldr pc, [pc, #24] |
| ldr pc, [pc, #24] |
| ldr pc, [pc, #24] |
| ldr pc, [pc, #24] |
| ldr pc, [pc, #24] |
| ldr pc, [pc, #24] |
| ldr pc, [pc, #24] |
| ldr pc, [pc, #24] |
| .word newstart |
| .word undef_instr_handler |
| .word software_int_handler |
| .word prefetch_abort_handler |
| .word data_abort_handler |
| .word reserved_handler |
| .word irq_handler |
| .word fiq_handler |
| #endif /* BOOTLOADER */ |
| |
| .text |
| |
| /* All illegal exceptions call into UIE with exception address as first |
| * parameter. This is calculated differently depending on which exception |
| * we're in. Second parameter is exception number, used for a string lookup |
| * in UIE. */ |
| undef_instr_handler: |
| mov r0, lr |
| mov r1, #0 |
| b UIE |
| |
| /* We run supervisor mode most of the time, and should never see a software |
| * exception being thrown. Perhaps make it illegal and call UIE? */ |
| software_int_handler: |
| reserved_handler: |
| movs pc, lr |
| |
| prefetch_abort_handler: |
| sub r0, lr, #4 |
| mov r1, #1 |
| b UIE |
| |
| data_abort_handler: |
| sub r0, lr, #8 |
| mov r1, #2 |
| b UIE |
| |
| /* 256 words of IRQ stack */ |
| .space 256*4 |
| irq_stack: |
| |
| /* 256 words of FIQ stack */ |
| .space 256*4 |
| fiq_stack: |