rockbox/firmware/target/arm/s3c2440/crt0.S
Rafaël Carré 0ea7905395 ARM: use BX when branch to an address in register
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@26432 a1c6a512-1295-4272-9138-f99709370657
2010-05-31 15:14:26 +00:00

752 lines
20 KiB
ArmAsm

/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2008 by Karl Kurbjun
*
* 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>
*
* 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"
#define CACHE_NONE 0
#define CACHE_ALL 0x0C
#define BUFFERED 0x04
/****************************************************************************/
#ifdef TOSHIBA_GIGABEAT_F
/* Clock and Power Management setup values */
#define VAL_CLKDIV 0x7
#define VAL_UPLLCON 0x0003C042
#define VAL_MPLLCON 0x000C9042
/* Memory Controller setup */
/* Memory setup (taken from 0x5070) */
/* BWSCON
* Reserved 0
* Bank 0:
* Bus width 01 (16 bit)
* Bank 1:
* Buswidth 00 (8 bit)
* Disable wait 0
* Not using UB/LB 0
* Bank 2:
* Buswidth 10 (32 bit)
* Disable wait 0
* Not using UB/LB 0
* Bank 3:
* Buswidth 10 (32 bit)
* Disable wait 0
* Use UB/LB 1
* Bank 4:
* Buswidth 10 (32 bit)
* Disable wait 0
* Use UB/LB 1
* Bank 5:
* Buswidth 00 (8 bit)
* Disable wait 0
* Not using UB/LB 0
* Bank 6:
* Buswidth 10 (32 bit)
* Disable wait 0
* Not using UB/LB 0
* Bank 7:
* Buswidth 00 (8 bit)
* Disable wait 0
* Not using UB/LB 0
*/
#define VAL_BWSCON 0x01055102
/* BANKCON0
* Pagemode: normal (1 data) 00
* Pagemode access cycle: 2 clocks 00
* Address hold: 2 clocks 10
* Chip selection hold time: 1 clock 10
* Access cycle: 8 clocks 101
* Chip select setup time: 1 clock 01
* Address setup time: 0 clock 00
*/
#define VAL_BANKCON0 0x00000D60
/* BANKCON1
* Pagemode: normal (1 data) 00
* Pagemode access cycle: 2 clocks 00
* Address hold: 0 clocks 00
* Chip selection hold time: 0 clock 00
* Access cycle: 1 clocks 000
* Chip select setup time: 0 clocks 00
* Address setup time: 0 clocks 00
*/
#define VAL_BANKCON1 0x00000000
/* BANKCON2
* Pagemode: normal (1 data) 00
* Pagemode access cycle: 2 clocks 00
* Address hold: 2 clocks 10
* Chip selection hold time: 2 clocks 10
* Access cycle: 14 clocks 111
* Chip select setup time: 4 clocks 11
* Address setup time: 0 clocks 00
*/
#define VAL_BANKCON2 0x00001FA0
#define VAL_BANKCON3 0x00001D80
#define VAL_BANKCON4 0x00001D80
#define VAL_BANKCON5 0x00000000
/* BANKCON6/7
* SCAN: 9 bit 01
* Trcd: 3 clocks 01
* Tcah: 0 clock 00
* Tcoh: 0 clock 00
* Tacc: 1 clock 000
* Tcos: 0 clock 00
* Tacs: 0 clock 00
* MT: Sync DRAM 11
*/
#define VAL_BANKCON6 0x00018005
#define VAL_BANKCON7 0x00018005
#define VAL_REFRESH 0x00980501
/* BANKSIZE
* BK76MAP: 32M/32M 000
* Reserved: 0 0 (was 1)
* SCLK_EN: always 1 (was 0)
* SCKE_EN: disable 0
* Reserved: 0 0
* BURST_EN: enabled 1
*/
#define VAL_BANKSIZE 0x00000090
#define VAL_MRSRB6 0x00000030
#define VAL_MRSRB7 0x00000030
#define VAL_GPACON 0x00FFFFFF
/****************************************************************************/
#elif defined (MINI2440)
/* For Mini2440 board or compatible */
/* Clock and Power Management setup values */
/* NB: clock settings must match values in s3c2440/system-target.h */
#define VAL_CLKDIV 0x5 /* HCLK = FCLK/4, PCLK = HCLK/2 */
#define VAL_UPLLCON 0x00038022 /* UCLK = 48 MHz */
#define VAL_MPLLCON 0x000C3041 /* FCLK = 406 MHz */
/* Memory Controller setup */
#define VAL_BWSCON 0x22111112
#define VAL_BANKCON0 0x00002F50
#define VAL_BANKCON1 0x00000700
#define VAL_BANKCON2 0x00000700
#define VAL_BANKCON3 0x00000700
#define VAL_BANKCON4 0x00000700
#define VAL_BANKCON5 0x0007FFFC
#define VAL_BANKCON6 0x00018009
#define VAL_BANKCON7 0x00018009
#define VAL_REFRESH 0x008E04EB
#define VAL_BANKSIZE 0x000000B2
#define VAL_MRSRB6 0x00000030
#define VAL_MRSRB7 0x00000030
#define VAL_GPACON 0x00FFFFFF
#define VAL_GPFCON 0x000055AA
#define VAL_GPGCON 0xAA2A0128
#define VAL_GPGDAT 0x0000
#else
#error Unknown target
#endif
/****************************************************************************/
/* Exception Handlers */
.section .vectors,"ax",%progbits
.code 32
.global vectors
vectors:
b start
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
/* This branch is used to make sure that we know where the shutdown routine
* is located in flash (0x040A0020)
*/
b rom_shutdown
/* Add some strings to detect the bootloader in flash and give it a version
* number. (0x040A0028, 0x040A002C)
*/
.string "ROCKBOX\0"
.string "R 03.00\0"
/*
* Function: word_copy
* Variables:
* r0 = from
* r1 = to
* r2 = length
*/
.section .init.text, "ax", %progbits
.align 0x04
.global word_copy
.type word_copy, %function
word_copy:
subs r2, r2, #0x04
ldrge r3, [r0], #4
strge r3, [r1], #4
bgt word_copy
bx lr
.ltorg
.size word_copy, .-word_copy
/*
* Entry: start
* Variables:
* none
*/
.section .init.text,"ax",%progbits
.code 32
.align 0x04
.global start
start:
/* Get the execute address; R0 is used to store the address and it should
* not be written to till the rest of the execution checks are done below.
* This is done first thing since we have to check if the code was started
* with the old rockbox bootloader that offset the image by 100 bytes.
*/
ldr r0, =0xffffff00
and r0, pc, r0
/************************** DO NOT WRITE TO R0 ***************************/
#ifdef TOSHIBA_GIGABEAT_F
/* Check if the code is running from flash. If not skip all these checks */
cmp r0, #0xA0000
bne poweron
/* Point LCDSADDR1 to the boot logo for lcd_init_device in lcd-meg-fx.c */
mov r2, #0x4D000000
ldr r1, =0x020200A8
str r1, [r2, #0x14]
/* Did an RTC event wake the player up? */
mov r2, #0x4A000000
ldr r1, [r2]
ands r1, r1, #0x40000000
/* Store a flag in GSTATUS3 to indicate that the bootloader is flashed */
ldr r2, =0x560000b8
mov r1, #0x02
/* Woke up with the alarm? - store a flag in GSTATUS3 */
orrne r1, r1, #0x01
str r1, [r2]
bne poweron
/* Set GPG up to read power and menu status */
ldr r2, =0x56000050
ldr r1, [r2, #0x18]
orr r1, r1, #0x03
str r1, [r2, #0x18]
/* Check if menu is held down */
ldr r1, [r2, #0x14]
ands r3, r1, #0x02
bne bootOF
/* Check if power is held down */
ands r3, r1, #0x01
bne poweron
/* Set GPF up to read charger connection if power is not held down */
ldr r1, [r2, #0x08]
orr r1, r1, #0x10
str r1, [r2, #0x08]
/* Check if charger is connected */
ldr r1, [r2, #0x04]
ands r1, r1, #0x10
beq poweron
bootOF:
/* power is not down || menu is held || the charger is not connected */
mov pc, #0x70
#endif
poweron:
/* enter supervisor mode, disable IRQ */
msr cpsr, #0xd3
/* Disable the watchdog */
ldr r2, =0x00000000
mov r1, #0x53000000
str r2, [r1]
/* Mask all Interupts to be safe */
ldr r2, =0xFFFFFFFF
mov r1, #0x4A000000
str r2, [r1, #0x08]
/* Submask too */
ldr r2, =0x00003FFF
str r2, [r1, #0x1C]
#ifdef TOSHIBA_GIGABEAT_F
/* Check if loaded by the old bootloader or by the OF. This copy routine
* cannot run/copy properly until the memory has been initialized, so the
* copy routine later is still necessary. The old bootloader/OF will
* initialize the memory.
*/
/* Calculate the length of the code needed to run/copy */
ldr r1, = _vectorstart
ldr r2, = _initdata_end
sub r2, r2, r1
add r3, r2, #0x30000000
/* Is there enough space to copy without overwriting? */
cmp r0, r3
/* There's enough space, skip copying */
bgt skipreset
/* Is this code running from 0xA0000? If so skip copy. */
cmplt r0, #0xA0000
beq skipreset
/****************************** OK TO USE R0 *****************************/
/* There's not enough space to copy without overwriting, copy to safe
* spot and reset
*/
mov r1, #0x31000000 /* copy location */
bl word_copy
mov pc, #0x31000000
#endif
skipreset:
/* Initial Clock Setup */
/* set Bus to Asynchronous mode (full speed) */
mov r0, #0
mrc p15, 0, r0, c1, c0, 0
ldr r1, =0xC0000000
orr r0, r0, r1
mcr p15, 0, r0, c1, c0, 0
mov r2, #VAL_CLKDIV
mov r1, #0x4C000000
str r2, [r1, #0x14]
mov r2, #0x0
str r2, [r1, #0x18]
ldr r2, =0xFFFFFFFF
str r2, [r1]
ldr r2, =VAL_UPLLCON
str r2, [r1, #0x08]
nop
nop
nop
nop
nop
nop
nop
nop
ldr r2, =VAL_MPLLCON
str r2, [r1, #0x04]
nop
nop
nop
nop
nop
nop
nop
nop
/* Setup MISCCR */
ldr r2, =0x00613020
mov r1, #0x56000000
str r2, [r1, #0x80]
/* Memory setup */
ldr r2, =VAL_BWSCON
mov r1, #0x48000000
str r2, [r1]
/* BANKCON0 */
ldr r2, =VAL_BANKCON0
str r2, [r1, #0x04]
/* BANKCON1 */
ldr r2, =VAL_BANKCON1
str r2, [r1, #0x08]
/* BANKCON2 */
ldr r2, =VAL_BANKCON2
str r2, [r1, #0xC]
/* BANKCON3 */
ldr r2, =VAL_BANKCON3
str r2, [r1, #0x10]
/* BANKCON4 */
str r2, [r1, #0x14]
/* BANKCON5 */
ldr r2, =VAL_BANKCON5
str r2, [r1, #0x18]
/* BANKCON6/7 */
ldr r2, =VAL_BANKCON6
str r2, [r1, #0x1C]
/* BANKCON7 */
str r2, [r1, #0x20]
/* REFRESH */
ldr r2, =VAL_REFRESH
str r2, [r1, #0x24]
/* BANKSIZE */
ldr r2, =VAL_BANKSIZE
str r2, [r1, #0x28]
/* MRSRB6 */
ldr r2, =VAL_MRSRB6
str r2, [r1, #0x2C]
/* MRSRB7 */
str r2, [r1, #0x30]
/* RMC: I guess this is some notes about Gigabeat */
/*
0x56000000 0x1FFFCFF
4 0x1FFFEFF
0X4800002C 0X0
0X560000
*/
/* GPACON */
mov r1, #0x56000000
ldr r2, =VAL_GPACON
str r2, [r1]
#if 0
/* GPGCON */
ldr r2, =VAL_GPGCON
str r2, [r1, #0x60]
ldr r2, =VAL_GPGDAT
str r2, [r1, #0x64]
#endif
/* Copy from current location (from NOR Flash if bootloader, load buffer if
firmware) to RAM */
/* Gigabeat: The builds have two potential load addresses, one being from flash,
* and the other from some "unknown" location right now the assumption
* is that the code is not at 0x3000000.
*/
/* get the high part of our execute address (where am I) */
ldr r0, =0xfffff000
and r0, pc, r0 /* copy from address */
/* SDRAM starts at 0x30000000 (physical address) */
ldr r1, =0x30000000 /* copy To address */
ldr r2, = _vectorstart
ldr r3, = _initdata_end
sub r2, r3, r2 /* length of loader */
bl word_copy
ldr r1, =donecopy
ldr r2, =0x30000000
add r1, r1, r2
bx r1 /* The code is located where we want it so jump */
donecopy:
/* Setup the MMU, start by disabling */
mrc p15, 0, r0, c1, c0, 0
bic r0, r0, #0x5 /* disable mmu and dcache */
bic r0, r0, #0x1000 /* disable icache */
mcr p15, 0, r0, c1, c0, 0
bl ttb_init
ldr r0, =0x0
ldr r1, =0x0
ldr r2, =0x1000
mov r3, #CACHE_NONE
bl map_section
ldr r0, =0x30000000
ldr r1, =0x0
mov r2, #MEMORYSIZE
mov r3, #CACHE_ALL
bl map_section
ldr r0, =LCD_FRAME_ADDR /* LCD Frame buffer */
mov r1, r0
mov r2, #1
mov r3, #BUFFERED
bl map_section
bl enable_mmu
/* Initialise bss section to zero */
ldr r2, =_edata
ldr r3, =_end
mov r4, #0
bsszero:
cmp r3, r2
strhi r4, [r2], #4
bhi bsszero
/* Set up some stack and munge it with 0xdeadbeef */
ldr sp, =stackend
mov r3, sp
ldr r2, =stackbegin
ldr r4, =0xdeadbeef
stackmunge:
cmp r3, r2
strhi r4, [r2], #4
bhi stackmunge
/* 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 to supervisor mode */
msr cpsr_c, #0xd3
ldr sp, =stackend
/* Start the main function */
ldr lr, =vectors
ldr pc, =main
/* Should never get here, but let's restart in case (also needed for
* linking)
*/
b vectors
/* 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:
sub r0, lr, #4
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
#if defined(BOOTLOADER)
fiq_handler:
b UIE
#endif
UIE:
b UIE
/* TODO: Review this function - is it target dependent? */
/*
* Function: rom_shutdown
* Variables:
* none
*/
.section .init.text, "ax", %progbits
.align 0x04
.global rom_shutdown
.type rom_shutdown, %function
rom_shutdown:
/* Turn off the MMU */
mrc p15, 0, r1, c1, c0, 0
bic r1, r1, #0x0001
mcr p15, 0, r1, c1, c0, 0
/* Taken from 0x10010 */
ldr r2, =0x56000014 //GPBDAT
ldr r1, =0x56000010 //GPBCON
ldr r3, =0x00015450
ldr r8, =0x56000024 //GPCDAT
ldr r10, =0x56000020 //GPCCON
ldr r5, =0xAAA054A8
ldr r6, =0x56000024 //GPDDAT
ldr r7, =0x56000030 //GPDCON
ldr r12, =0x56000044 //GPEDAT
ldr lr, =0x56000040 //GPECON
ldr r0, =0x56000054 //GPFDAT
mov r4, #0
str r4, [r2]
str r3, [r1]
ldr r1, =0xAAA0AAA5
ldr r2, =0xAA8002AA
mov r3, #0x80
str r3, [r8]
add r3, r3, #0x980
str r5, [r10]
mov r5, #4
str r4, [r6]
str r1, [r7]
str r4, [r12]
str r2, [lr]
str r4, [r0],#(0x56000064-0x56000054) //(GPGDAT - GPFDAT)
add r12, r12, #(0x56000060-0x56000044)//(GPGCON - GPEDAT)
ldr r1, =0x56000050 //GPFCON
ldr r2, =0x01401002
mov lr, #0xFFFFFFFF
str r3, [r1],#(0x56000074-0x56000050)// (GPHDAT - GPFCON)
str r4, [r0],#(0x56000060-0x56000054)// (GPGCON - GPFDAT)
// str r2, [r12]
ldr r2, =0x140A5
mov r3, #0x81
str r3, [r1]
ldr r12, =0x4A000008 //INTMSK
// mov r3, #0x200000 // disable EINT13
ldr r3, =0xFFFFFECF
str r2, [r0] // GPFDAT=0x140A5
ldr r2, =0x56000088 //EXTINT0
ldr r0, =0x4A000010 //INTPND
add r1, r1, #(0x56000068 - 0x56000050) // (GPGUP - GPFCON) (0x18)
str lr, [r12] /* INTMSK = 0xFFFFFFFF */
str r3, [r2],#(0x560000A4 - 0x56000088) // (EINTMASK - EXTINT0) disable EINT13 (0x1C)
// mov r3, #0xFFFFFECF
mov r3, #0xFFFFFEFF
str r5, [r1],#(0x56000074-0x56000058) //(GPHDAT - GPFUP) (0x1C) DCLKCON
str r3, [r2]
ldr r11, =0x56000060
ldr r6, =0x01401002
str r6, [r11]
// add r3, r3, #0x00000100
ldr r3, =0xFFFFFFDF;
str r3, [r12] // disable INT_TICK
mov r3, #0x4A000000
add r2, r2, #(0x560000B0-0x56000088) //(GSTATUS1 - EXTINT0) //; 0x600 (0x28)
str lr, [r1]
str lr, [r3]
mov r3, #0x600
str lr, [r0]
str r3, [r2] // GSTATUS1 = 0x600 /* what for ??? */
ldr r12, =0x56000080 //MISCCr
mov r2, #0x58000000 //ADCCON
str r5, [r2]
add r2, r2, #(0x4D000000-0x58000000) //(LCDCON1 - ADCCON) // LCDCON1 (0xF5000000)
ldr r3, [r12]
ldr r0, =0x48000024 // REFRESH
bic r3, r3, #0x700000
bic r3, r3, #0x3000
orr r3, r3, #0x600000
orr r3, r3, #0x3000
str r3, [r12] // MISCCR = (MISCCR & ~0x100000) | 0x603000;
/* clear [20] BATTFLT_FUNC - BATT_FLT function On/Off.
* 0, Battery fault function will be turned on.
* set [21] BATTFLT_INTR - BATT_FLT Interrupt On/Off.
* 1, Battery fault interrupt will be masked by hardware.
* set [13] SEL_SUSPND1 - USB Port 1 Suspend mode
* 1= suspend mode
* set [12] SEL_SUSPND0 - USB Port 0 Suspend mode
* 1= suspend mode
*/
mov r3, #0x4C000000 // LOCKTIME
str r4, [r2]
str lr, [r3]
ldr r1, [r0]
ldr lr, =0x4C00000C // CLKCON
// str r1, [r11,#-0x28]
ldr r2, [lr]
// str r2, [r11,#-0x28]
ldr r3, [r0]
orr r3, r3, #0x00C00000
/* REFRESH
* [22] TREFMD - SDRAM Refresh Mode
*/
str r3, [r0]
ldr r2, [r12]
ldr r3, =0x00004018
/* [3] SLEEP - Control SLEEP mode of S3C2440X.
* [4] NAND - Control HCLK into NAND Flash Controller block.
* [14] RTC - Control PCLK into RTC control block.
*/
orr r2, r2, #0x000E0000
/* [17] nEN_SCLK0 - SCLK0 output enable (1: SCLK 0 = 0)
* [18] nEN_SCLK1 - SCLK1 output enable (1: SCLK 1 = 0)
* [19] OFFREFRESH - Self refresh retain enable after wake-up from sleep
*/
str r2, [r12]
str r3, [lr]
1:
b 1b
.ltorg
.size rom_shutdown, .-rom_shutdown
.section .text
/* 256 words of IRQ stack */
.space 256*4
irq_stack:
/* 256 words of FIQ stack */
.space 256*4
fiq_stack: