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 */
299 #else /* i.e. 2440, 2410 and 2440 */
301 #ifndef CONFIG_MINI2440 /* cpu_init_crit is called right afterward */
302 #define LOCKTIME 0x4c000000
303 #define UPLLCON 0x4c000008
313 /* Page 7-19, seven nops between UPLL and MPLL */
323 str r1, [r0, #-4] /* MPLLCON */
333 ldr r0, =0x4c00000c /* clkcon */
334 ldr r1, =0x7fff0 /* all clocks on */
337 /* gpio UART0 init */
355 #endif /* ! CONFIG_MINI2440 */
357 #endif /* CONFIG_S3C2400 || CONFIG_S3C2410 || CONFIG_S3C2440 || CONFIG_S3C2442
360 #ifndef CONFIG_SKIP_LOWLEVEL_INIT
361 #ifndef CONFIG_LL_INIT_NAND_ONLY
365 #if defined(CONFIG_AT91RM9200) || defined(CONFIG_S3C2410) || \
366 defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442) || \
367 defined(CONFIG_S3C2443)
369 #ifndef CONFIG_SKIP_RELOCATE_UBOOT
370 adr r0, _start /* r0 <- current position of code */
372 #ifdef CONFIG_S3C2410_NAND_BOOT
373 /* are we running from NAND ? */
374 #define BWSCON 0x48000000
375 ldr r1, =BWSCON /* Z = CPU booted from NAND */
377 tst r1, #6 /* BWSCON[2:1] = OM[1:0] */
378 teqeq r0, #0 /* Z &= running at address 0 */
380 #endif /* CONFIG_S3C2410_NAND_BOOT */
382 relocate: /* relocate U-Boot to RAM */
383 teq r0, #0 /* running at address 0 ? */
384 bleq may_resume /* yes -> do low-level setup */
386 adr r0, _start /* the above may have clobbered r0 */
388 ldr r1, _TEXT_BASE /* test if we run from flash or RAM */
389 cmp r0, r1 /* don't reloc during debug */
392 ldr r2, _armboot_start
394 sub r2, r3, r2 /* r2 <- size of armboot */
395 add r2, r0, r2 /* r2 <- source end address */
398 ldmia r0!, {r3-r10} /* copy from source address [r0] */
399 stmia r1!, {r3-r10} /* copy to target address [r1] */
400 cmp r0, r2 /* until source end address [r2] */
404 ldr r0, _end_if_0 /* are we booting from NOR ? */
406 ldreq r0, _booted_from_nor /* remember that we've booted from */
407 moveq r1, #1 /* NOR */
409 #endif /* !CFG_NO_FLASH */
411 mov r0, #0 /* flush v3/v4 cache */
412 mcr p15, 0, r0, c7, c7, 0
413 ldr pc, _done_relocate /* jump to relocated code */
417 #ifdef CONFIG_S3C2410_NAND_BOOT
419 bl may_resume /* low-level setup and resume */
422 #if defined(CONFIG_S3C2410)
423 mov r1, #S3C2410_NAND_BASE
424 ldr r2, =0xf842 @ initial value enable tacls=3,rph0=6,rph1=0
425 str r2, [r1, #oNFCONF]
426 ldr r2, [r1, #oNFCONF]
427 bic r2, r2, #0x800 @ enable chip
428 str r2, [r1, #oNFCONF]
429 mov r2, #0xff @ RESET command
430 strb r2, [r1, #oNFCMD]
435 2: ldr r2, [r1, #oNFSTAT] @ wait ready
438 ldr r2, [r1, #oNFCONF]
439 orr r2, r2, #0x800 @ disable chip
440 str r2, [r1, #oNFCONF]
441 #elif defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442)
442 mov r1, #S3C2440_NAND_BASE
443 ldr r2, =0xfff0 @ initial value tacls=3,rph0=7,rph1=7
444 ldr r3, [r1, #oNFCONF]
446 str r3, [r1, #oNFCONF]
448 ldr r3, [r1, #oNFCONT]
449 orr r3, r3, #1 @ enable nand controller
450 str r3, [r1, #oNFCONT]
451 #endif /* CONFIG_S3C2440 || CONFIG_S3C2442 */
453 ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */
454 sub r0, r0, #CFG_MALLOC_LEN /* malloc area */
455 sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo */
456 #ifdef CONFIG_USE_IRQ
457 sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
459 sub sp, r0, #12 /* leave 3 words for abort-stack */
464 mov r2, #CFG_UBOOT_SIZE
469 #ifdef CONFIG_DEBUG_LL
474 1: b 1b @ infinite loop
478 #ifdef CONFIG_DEBUG_LL
488 mov r2, #0x400 @ 4 bytes * 1024 = 4K-bytes
498 #ifdef CONFIG_DEBUG_LL
508 ldr r0, _booted_from_nand
511 #endif /* CONFIG_S3C2410_NAND_BOOT */
514 #if defined(CONFIG_USE_IRQ) && (defined(CONFIG_S3C2410) || \
515 defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442))
516 /* In the case of the S3C2410, if we've somehow magically (JTAG, ...)
517 ended up in RAM, then that ram is mapped to 0x30000000 and not 0.
518 So we need to copy the interrupt vectors, etc. */
528 #endif /* CONFIG_USE_IRQ */
530 #endif /* CONFIG_SKIP_RELOCATE_UBOOT */
532 /* Set up the stack */
534 ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */
535 sub r0, r0, #CFG_MALLOC_LEN /* malloc area */
536 sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo */
537 #ifdef CONFIG_USE_IRQ
538 sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
540 sub sp, r0, #12 /* leave 3 words for abort-stack */
543 ldr r0, _bss_start /* find start of bss segment */
544 ldr r1, _bss_end /* stop here */
545 mov r2, #0x00000000 /* clear */
547 clbss_l:str r2, [r0] /* clear loop... */
552 ldr pc, _start_armboot
554 _start_armboot: .word start_armboot
558 *************************************************************************
560 * CPU_init_critical registers
562 * setup important registers
563 * setup memory timing
565 *************************************************************************
569 #ifndef CONFIG_SKIP_LOWLEVEL_INIT
572 * flush v4 I/D caches
575 mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache */
576 mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */
579 * disable MMU stuff and caches
581 mrc p15, 0, r0, c1, c0, 0
582 bic r0, r0, #0x00002300 @ clear bits 13, 9:8 (--V- --RS)
583 bic r0, r0, #0x00000087 @ clear bits 7, 2:0 (B--- -CAM)
584 orr r0, r0, #0x00000002 @ set bit 2 (A) Align
585 orr r0, r0, #0x00001000 @ set bit 12 (I) I-Cache
586 mcr p15, 0, r0, c1, c0, 0
589 * before relocating, we have to setup RAM timing
590 * because memory timing is board-dependend, you will
591 * find a lowlevel_init.S in your board directory.
594 #if defined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK) || defined(CONFIG_AT91RM9200DF)
601 #endif /* CONFIG_SKIP_LOWLEVEL_INIT */
605 *************************************************************************
609 * Bring up memory and check if we're coming out of suspend.
611 *************************************************************************
616 mov r10, lr /* we may call cpu_init_crit */
618 /* take sdram out of power down */
619 ldr r0, =0x56000080 /* misccr */
621 bic r1, r1, #(S3C2410_MISCCR_nEN_SCLK0 | S3C2410_MISCCR_nEN_SCLK1 | S3C2410_MISCCR_nEN_SCLKE)
624 /* ensure signals stabalise */
629 #if !defined(CONFIG_SKIP_LOWLEVEL_INIT) && defined(CONFIG_LL_INIT_NAND_ONLY)
632 #if defined(CONFIG_S3C2410) || defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442)
633 /* ensure some refresh has happened */
638 /* capture full EINT situation into gstatus 4 */
640 ldr r0, =0x4A000000 /* SRCPND */
644 ldr r0, =0x560000BC /* gstatus4 */
647 ldr r0, =0x560000A8 /* EINTPEND */
651 ldr r0, =0x560000BC /* gstatus4 */
654 ldr r0, =0x560000BC /* gstatus4 */
657 /* test for resume */
659 ldr r1, =0x560000B4 /* gstatus2 */
661 tst r0, #0x02 /* is this resume from power down */
662 /* well, if it was, we are going to jump to
663 * whatever address we stashed in gstatus3,
664 * and gstatus4 will hold the wake interrupt
665 * source for the OS to look at
668 #endif /* CONFIG_S3C2410 || CONFIG_S3C244 || CONFIG_S3C2442 */
669 #endif /* CONFIG_SKIP_LOWLEVEL_INIT */
674 *************************************************************************
678 *************************************************************************
684 #define S_FRAME_SIZE 72
706 #define MODE_SVC 0x13
710 * use bad_save_user_regs for abort/prefetch/undef/swi ...
711 * use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling
714 .macro bad_save_user_regs
715 sub sp, sp, #S_FRAME_SIZE
716 stmia sp, {r0 - r12} @ Calling r0-r12
717 ldr r2, _armboot_start
718 sub r2, r2, #(CONFIG_STACKSIZE+CFG_MALLOC_LEN)
719 sub r2, r2, #(CFG_GBL_DATA_SIZE+8) @ set base 2 words into abort stack
720 ldmia r2, {r2 - r3} @ get pc, cpsr
721 add r0, sp, #S_FRAME_SIZE @ restore sp_SVC
725 stmia r5, {r0 - r3} @ save sp_SVC, lr_SVC, pc, cpsr
729 .macro irq_save_user_regs
730 sub sp, sp, #S_FRAME_SIZE
731 stmia sp, {r0 - r12} @ Calling r0-r12
733 stmdb r7, {sp, lr}^ @ Calling SP, LR
734 str lr, [r7, #0] @ Save calling PC
736 str r6, [r7, #4] @ Save CPSR
737 str r0, [r7, #8] @ Save OLD_R0
741 .macro irq_restore_user_regs
742 ldmia sp, {r0 - lr}^ @ Calling r0 - lr
744 ldr lr, [sp, #S_PC] @ Get PC
745 add sp, sp, #S_FRAME_SIZE
746 subs pc, lr, #4 @ return & move spsr_svc into cpsr
750 ldr r13, _armboot_start @ setup our mode stack
751 sub r13, r13, #(CONFIG_STACKSIZE+CFG_MALLOC_LEN)
752 sub r13, r13, #(CFG_GBL_DATA_SIZE+8) @ reserved a couple spots in abort stack
754 str lr, [r13] @ save caller lr / spsr
758 mov r13, #MODE_SVC @ prepare SVC-Mode
765 .macro get_irq_stack @ setup IRQ stack
766 ldr sp, IRQ_STACK_START
769 .macro get_fiq_stack @ setup FIQ stack
770 ldr sp, FIQ_STACK_START
777 undefined_instruction:
780 bl do_undefined_instruction
786 bl do_software_interrupt
806 #ifdef CONFIG_USE_IRQ
813 irq_restore_user_regs
818 /* someone ought to write a more effiction fiq_save_user_regs */
821 irq_restore_user_regs