2 * armboot - Startup Code for ARM920 CPU-core
4 * Copyright (c) 2001 Marius Gröger <mag@sysgo.de>
5 * Copyright (c) 2002 Alex Züpke <azu@sysgo.de>
6 * Copyright (c) 2002 Gary Jennejohn <gj@denx.de>
8 * S3C2410 NAND portions
9 * Copyright (c) 2001 MIZI Research, Inc.
10 * Copyright (c) 2006 OpenMoko, Inc. (Harald Welte <laforge@openmmoko.org>
12 * See file CREDITS for list of people who contributed to this
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License as
17 * published by the Free Software Foundation; either version 2 of
18 * the License, or (at your option) any later version.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
34 #if defined(CONFIG_S3C2410)
36 #elif defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442)
38 #elif defined(CONFIG_S3C2443)
41 #include <status_led.h>
44 *************************************************************************
46 * Jump vector table as in table 3.1 in [1]
48 *************************************************************************
54 ldr pc, _undefined_instruction
55 ldr pc, _software_interrupt
56 ldr pc, _prefetch_abort
62 _undefined_instruction: .word undefined_instruction
63 _software_interrupt: .word software_interrupt
64 _prefetch_abort: .word prefetch_abort
65 _data_abort: .word data_abort
66 _not_used: .word not_used
70 .balignl 16,0xdeadbeef
74 *************************************************************************
76 * Startup Code (called from the ARM reset exception vector)
78 * do important init only if we don't start from memory!
79 * relocate armboot to ram
81 * jump to second stage
83 *************************************************************************
87 /* Must follow the .balign above, so we get a well-known address ! */
88 #ifdef CFG_PREBOOT_OVERRIDE
89 .globl preboot_override
94 /* Must follow preboot_override , so we get a well-known address ! */
95 #ifdef CFG_ENV_OVERRIDE
101 #ifdef CONFIG_S3C2410_NAND_BOOT
102 .globl booted_from_nand
106 .word booted_from_nand
107 #endif /* CONFIG_S3C2410_NAND_BOOT */
110 .globl booted_from_nor
114 .word booted_from_nor
116 .word __bss_start-_start
117 #endif /* !CFG_NO_FLASH */
122 .globl _armboot_start
127 * These are defined in the board-specific linker script.
137 #ifdef CONFIG_USE_IRQ
138 /* IRQ stack memory (calculated at run-time) */
139 .globl IRQ_STACK_START
143 /* IRQ stack memory (calculated at run-time) */
144 .globl FIQ_STACK_START
151 * the actual start code
156 * set the cpu to SVC32 mode
163 /* in case we run from the s3c24xx NAND stepping stone, the symbols
164 * for LED support are in lib_arm/board.o, i.e. outside of the
166 #ifndef CONFIG_S3C2410_NAND_BOOT
171 #if defined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK) || defined(CONFIG_AT91RM9200DF)
173 * relocate exception table
185 #if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410) || defined(CONFIG_S3C2440) || \
186 defined(CONFIG_S3C2442) || defined(CONFIG_S3C2443)
187 /* turn off the watchdog */
189 # if defined(CONFIG_S3C2400)
190 # define pWTCON 0x15300000
191 # define INTMSK 0x14400008 /* Interupt-Controller base addresses */
192 # define CLKDIVN 0x14800014 /* clock divisor register */
193 #elif defined(CONFIG_S3C2410) || defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442)
194 # define pWTCON 0x53000000
195 # define INTMSK 0x4A000008 /* Interupt-Controller base addresses */
196 # define INTSUBMSK 0x4A00001C
197 # define CLKDIVN 0x4C000014 /* clock divisor register */
200 #if defined(CONFIG_S3C2410)
201 # define INTSUBMSK_val 0x7ff
202 # define MPLLCON_val ((0x90 << 12) + (0x7 << 4) + 0x0) /* 202 MHz */
203 # define UPLLCON_val ((0x78 << 12) + (0x2 << 4) + 0x3)
204 # define CLKDIVN_val 3 /* FCLK:HCLK:PCLK = 1:2:4 */
205 #elif defined(CONFIG_S3C2440)
206 # define INTSUBMSK_val 0xffff
207 #if (CONFIG_SYS_CLK_FREQ == 16934400)
208 # define MPLLCON_val ((0x61 << 12) + (0x1 << 4) + 0x2) /* 296.35 MHz */
209 # define UPLLCON_val ((0x3c << 12) + (0x4 << 4) + 0x2) /* 47.98 MHz */
210 #elif (CONFIG_SYS_CLK_FREQ == 12000000)
211 # define MPLLCON_val ((0x44 << 12) + (0x1 << 4) + 0x1) /* 304.00 MHz */
212 # define UPLLCON_val ((0x38 << 12) + (0x2 << 4) + 0x2) /* 48.00 MHz */
214 # define CLKDIVN_val 7 /* FCLK:HCLK:PCLK = 1:3:6 */
215 # define CAMDIVN 0x4C000018
216 #elif defined(CONFIG_S3C2442)
217 # define INTSUBMSK_val 0xffff
218 # if (CONFIG_SYS_CLK_FREQ == 12000000)
219 # define MPLLCON_val ((142 << 12) + (7 << 4) + 1)
220 # define UPLLCON_val (( 88 << 12) + (4 << 4) + 2)
221 # elif (CONFIG_SYS_CLK_FREQ == 16934400)
222 # define MPLLCON_val ((181 << 12) + (14<< 4) + 1)
223 # define UPLLCON_val (( 26 << 12) + (4 << 4) + 1)
225 # define CLKDIVN_val 7 /* FCLK:HCLK:PCLK = 1:3:6 */
226 # define CAMDIVN 0x4C000018
227 #elif defined(CONFIG_S3C2443)
228 # define INTSUBMSK_val 0x1fffffff
229 # define EPLLCON_val ((40 << 16) | (1 << 8) | (1)) /* 96 MHz */
230 # define MPLLCON_val ((81 << 16) | (2 << 8) | (0)) /* 1068 MHz */
231 # define CLKDIV0_val ((8 << 9) | (1 << 4) | (1 << 3) | (1 << 2)
239 * mask all IRQs by setting all bits in the INTMR - default
244 # if defined(CONFIG_S3C2410) || defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442) || \
245 defined(CONFIG_S3C2443)
246 ldr r1, =INTSUBMSK_val
251 #if defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442)
252 /* Make sure we get FCLK:HCLK:PCLK */
258 /* Clock asynchronous mode */
259 mrc p15, 0, r1, c1, c0, 0
260 orr r1, r1, #0xc0000000
261 mcr p15, 0, r1, c1, c0, 0
264 #if defined(CONFIG_S3C2443)
265 #define LOCKCON0 0x4c000000
266 #define LOCKCON1 0x4c000004
267 #define MPLLCON 0x4c000010
268 #define EPLLCON 0x4c000018
274 /* set safe (way too long) locktime for both PLLs */
286 /* select MPLL clock out for SYSCLK */
300 #else /* i.e. 2440, 2410 and 2440 */
301 #define LOCKTIME 0x4c000000
302 #define UPLLCON 0x4c000008
312 /* Page 7-19, seven nops between UPLL and MPLL */
322 str r1, [r0, #-4] /* MPLLCON */
332 ldr r0, =0x4c00000c /* clkcon */
333 ldr r1, =0x7fff0 /* all clocks on */
336 /* gpio UART0 init */
355 #endif /* CONFIG_S3C2400 || CONFIG_S3C2410 || CONFIG_S3C2440 || CONFIG_S3C2442
358 #ifndef CONFIG_SKIP_LOWLEVEL_INIT
359 #ifndef CONFIG_LL_INIT_NAND_ONLY
363 #if defined(CONFIG_AT91RM9200) || defined(CONFIG_S3C2410) || \
364 defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442) || \
365 defined(CONFIG_S3C2443)
367 #ifndef CONFIG_SKIP_RELOCATE_UBOOT
368 adr r0, _start /* r0 <- current position of code */
370 #ifdef CONFIG_S3C2410_NAND_BOOT
371 /* are we running from NAND ? */
372 #define BWSCON 0x48000000
373 ldr r1, =BWSCON /* Z = CPU booted from NAND */
375 tst r1, #6 /* BWSCON[2:1] = OM[1:0] */
376 teqeq r0, #0 /* Z &= running at address 0 */
378 #endif /* CONFIG_S3C2410_NAND_BOOT */
380 relocate: /* relocate U-Boot to RAM */
381 teq r0, #0 /* running at address 0 ? */
382 bleq may_resume /* yes -> do low-level setup */
384 adr r0, _start /* the above may have clobbered r0 */
386 ldr r1, _TEXT_BASE /* test if we run from flash or RAM */
387 cmp r0, r1 /* don't reloc during debug */
390 ldr r2, _armboot_start
392 sub r2, r3, r2 /* r2 <- size of armboot */
393 add r2, r0, r2 /* r2 <- source end address */
396 ldmia r0!, {r3-r10} /* copy from source address [r0] */
397 stmia r1!, {r3-r10} /* copy to target address [r1] */
398 cmp r0, r2 /* until source end address [r2] */
402 ldr r0, _end_if_0 /* are we booting from NOR ? */
404 ldreq r0, _booted_from_nor /* remember that we've booted from */
405 moveq r1, #1 /* NOR */
407 #endif /* !CFG_NO_FLASH */
409 mov r0, #0 /* flush v3/v4 cache */
410 mcr p15, 0, r0, c7, c7, 0
411 ldr pc, _done_relocate /* jump to relocated code */
415 #ifdef CONFIG_S3C2410_NAND_BOOT
417 bl may_resume /* low-level setup and resume */
420 #if defined(CONFIG_S3C2410)
421 mov r1, #S3C2410_NAND_BASE
422 ldr r2, =0xf842 @ initial value enable tacls=3,rph0=6,rph1=0
423 str r2, [r1, #oNFCONF]
424 ldr r2, [r1, #oNFCONF]
425 bic r2, r2, #0x800 @ enable chip
426 str r2, [r1, #oNFCONF]
427 mov r2, #0xff @ RESET command
428 strb r2, [r1, #oNFCMD]
433 2: ldr r2, [r1, #oNFSTAT] @ wait ready
436 ldr r2, [r1, #oNFCONF]
437 orr r2, r2, #0x800 @ disable chip
438 str r2, [r1, #oNFCONF]
439 #elif defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442)
440 mov r1, #S3C2440_NAND_BASE
441 ldr r2, =0xfff0 @ initial value tacls=3,rph0=7,rph1=7
442 ldr r3, [r1, #oNFCONF]
444 str r3, [r1, #oNFCONF]
446 ldr r3, [r1, #oNFCONT]
447 orr r3, r3, #1 @ enable nand controller
448 str r3, [r1, #oNFCONT]
449 #endif /* CONFIG_S3C2440 || CONFIG_S3C2442 */
451 ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */
452 sub r0, r0, #CFG_MALLOC_LEN /* malloc area */
453 sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo */
454 #ifdef CONFIG_USE_IRQ
455 sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
457 sub sp, r0, #12 /* leave 3 words for abort-stack */
462 mov r2, #CFG_UBOOT_SIZE
467 #ifdef CONFIG_DEBUG_LL
472 1: b 1b @ infinite loop
476 #ifdef CONFIG_DEBUG_LL
486 mov r2, #0x400 @ 4 bytes * 1024 = 4K-bytes
496 #ifdef CONFIG_DEBUG_LL
506 ldr r0, _booted_from_nand
509 #endif /* CONFIG_S3C2410_NAND_BOOT */
512 #if defined(CONFIG_USE_IRQ) && (defined(CONFIG_S3C2410) || \
513 defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442))
514 /* In the case of the S3C2410, if we've somehow magically (JTAG, ...)
515 ended up in RAM, then that ram is mapped to 0x30000000 and not 0.
516 So we need to copy the interrupt vectors, etc. */
526 #endif /* CONFIG_USE_IRQ */
528 #endif /* CONFIG_SKIP_RELOCATE_UBOOT */
530 /* Set up the stack */
532 ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */
533 sub r0, r0, #CFG_MALLOC_LEN /* malloc area */
534 sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo */
535 #ifdef CONFIG_USE_IRQ
536 sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
538 sub sp, r0, #12 /* leave 3 words for abort-stack */
541 ldr r0, _bss_start /* find start of bss segment */
542 ldr r1, _bss_end /* stop here */
543 mov r2, #0x00000000 /* clear */
545 clbss_l:str r2, [r0] /* clear loop... */
550 ldr pc, _start_armboot
552 _start_armboot: .word start_armboot
556 *************************************************************************
558 * CPU_init_critical registers
560 * setup important registers
561 * setup memory timing
563 *************************************************************************
567 #ifndef CONFIG_SKIP_LOWLEVEL_INIT
570 * flush v4 I/D caches
573 mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache */
574 mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */
577 * disable MMU stuff and caches
579 mrc p15, 0, r0, c1, c0, 0
580 bic r0, r0, #0x00002300 @ clear bits 13, 9:8 (--V- --RS)
581 bic r0, r0, #0x00000087 @ clear bits 7, 2:0 (B--- -CAM)
582 orr r0, r0, #0x00000002 @ set bit 2 (A) Align
583 orr r0, r0, #0x00001000 @ set bit 12 (I) I-Cache
584 mcr p15, 0, r0, c1, c0, 0
587 * before relocating, we have to setup RAM timing
588 * because memory timing is board-dependend, you will
589 * find a lowlevel_init.S in your board directory.
592 #if defined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK) || defined(CONFIG_AT91RM9200DF)
599 #endif /* CONFIG_SKIP_LOWLEVEL_INIT */
603 *************************************************************************
607 * Bring up memory and check if we're coming out of suspend.
609 *************************************************************************
614 mov r10, lr /* we may call cpu_init_crit */
616 /* take sdram out of power down */
617 ldr r0, =0x56000080 /* misccr */
619 bic r1, r1, #(S3C2410_MISCCR_nEN_SCLK0 | S3C2410_MISCCR_nEN_SCLK1 | S3C2410_MISCCR_nEN_SCLKE)
622 /* ensure signals stabalise */
627 #if !defined(CONFIG_SKIP_LOWLEVEL_INIT) && defined(CONFIG_LL_INIT_NAND_ONLY)
630 #if defined(CONFIG_S3C2410) || defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442)
631 /* ensure some refresh has happened */
636 /* capture full EINT situation into gstatus 4 */
638 ldr r0, =0x4A000000 /* SRCPND */
642 ldr r0, =0x560000BC /* gstatus4 */
645 ldr r0, =0x560000A8 /* EINTPEND */
649 ldr r0, =0x560000BC /* gstatus4 */
652 ldr r0, =0x560000BC /* gstatus4 */
655 /* test for resume */
657 ldr r1, =0x560000B4 /* gstatus2 */
659 tst r0, #0x02 /* is this resume from power down */
660 /* well, if it was, we are going to jump to
661 * whatever address we stashed in gstatus3,
662 * and gstatus4 will hold the wake interrupt
663 * source for the OS to look at
666 #endif /* CONFIG_S3C2410 || CONFIG_S3C244 || CONFIG_S3C2442 */
667 #endif /* CONFIG_SKIP_LOWLEVEL_INIT */
672 *************************************************************************
676 *************************************************************************
682 #define S_FRAME_SIZE 72
704 #define MODE_SVC 0x13
708 * use bad_save_user_regs for abort/prefetch/undef/swi ...
709 * use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling
712 .macro bad_save_user_regs
713 sub sp, sp, #S_FRAME_SIZE
714 stmia sp, {r0 - r12} @ Calling r0-r12
715 ldr r2, _armboot_start
716 sub r2, r2, #(CONFIG_STACKSIZE+CFG_MALLOC_LEN)
717 sub r2, r2, #(CFG_GBL_DATA_SIZE+8) @ set base 2 words into abort stack
718 ldmia r2, {r2 - r3} @ get pc, cpsr
719 add r0, sp, #S_FRAME_SIZE @ restore sp_SVC
723 stmia r5, {r0 - r3} @ save sp_SVC, lr_SVC, pc, cpsr
727 .macro irq_save_user_regs
728 sub sp, sp, #S_FRAME_SIZE
729 stmia sp, {r0 - r12} @ Calling r0-r12
731 stmdb r7, {sp, lr}^ @ Calling SP, LR
732 str lr, [r7, #0] @ Save calling PC
734 str r6, [r7, #4] @ Save CPSR
735 str r0, [r7, #8] @ Save OLD_R0
739 .macro irq_restore_user_regs
740 ldmia sp, {r0 - lr}^ @ Calling r0 - lr
742 ldr lr, [sp, #S_PC] @ Get PC
743 add sp, sp, #S_FRAME_SIZE
744 subs pc, lr, #4 @ return & move spsr_svc into cpsr
748 ldr r13, _armboot_start @ setup our mode stack
749 sub r13, r13, #(CONFIG_STACKSIZE+CFG_MALLOC_LEN)
750 sub r13, r13, #(CFG_GBL_DATA_SIZE+8) @ reserved a couple spots in abort stack
752 str lr, [r13] @ save caller lr / spsr
756 mov r13, #MODE_SVC @ prepare SVC-Mode
763 .macro get_irq_stack @ setup IRQ stack
764 ldr sp, IRQ_STACK_START
767 .macro get_fiq_stack @ setup FIQ stack
768 ldr sp, FIQ_STACK_START
775 undefined_instruction:
778 bl do_undefined_instruction
784 bl do_software_interrupt
804 #ifdef CONFIG_USE_IRQ
811 irq_restore_user_regs
816 /* someone ought to write a more effiction fiq_save_user_regs */
819 irq_restore_user_regs