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 */
112 .globl _armboot_start
117 * These are defined in the board-specific linker script.
127 #ifdef CONFIG_USE_IRQ
128 /* IRQ stack memory (calculated at run-time) */
129 .globl IRQ_STACK_START
133 /* IRQ stack memory (calculated at run-time) */
134 .globl FIQ_STACK_START
141 * the actual start code
146 * set the cpu to SVC32 mode
153 /* in case we run from the s3c24xx NAND stepping stone, the symbols
154 * for LED support are in lib_arm/board.o, i.e. outside of the
156 #ifndef CONFIG_S3C2410_NAND_BOOT
161 #if defined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK) || defined(CONFIG_AT91RM9200DF)
163 * relocate exception table
175 #if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410) || defined(CONFIG_S3C2440) || \
176 defined(CONFIG_S3C2442) || defined(CONFIG_S3C2443)
177 /* turn off the watchdog */
179 # if defined(CONFIG_S3C2400)
180 # define pWTCON 0x15300000
181 # define INTMSK 0x14400008 /* Interupt-Controller base addresses */
182 # define CLKDIVN 0x14800014 /* clock divisor register */
183 #elif defined(CONFIG_S3C2410) || defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442)
184 # define pWTCON 0x53000000
185 # define INTMSK 0x4A000008 /* Interupt-Controller base addresses */
186 # define INTSUBMSK 0x4A00001C
187 # define CLKDIVN 0x4C000014 /* clock divisor register */
190 #if defined(CONFIG_S3C2410)
191 # define INTSUBMSK_val 0x7ff
192 # define MPLLCON_val ((0x90 << 12) + (0x7 << 4) + 0x0) /* 202 MHz */
193 # define UPLLCON_val ((0x78 << 12) + (0x2 << 4) + 0x3)
194 # define CLKDIVN_val 3 /* FCLK:HCLK:PCLK = 1:2:4 */
195 #elif defined(CONFIG_S3C2440)
196 # define INTSUBMSK_val 0xffff
197 #if (CONFIG_SYS_CLK_FREQ == 16934400)
198 # define MPLLCON_val ((0x61 << 12) + (0x1 << 4) + 0x2) /* 296.35 MHz */
199 # define UPLLCON_val ((0x3c << 12) + (0x4 << 4) + 0x2) /* 47.98 MHz */
200 #else if (CONFIG_SYS_CLK_FREQ == 12000000)
201 # define MPLLCON_val ((0x44 << 12) + (0x1 << 4) + 0x1) /* 304.00 MHz */
202 # define UPLLCON_val ((0x38 << 12) + (0x2 << 4) + 0x2) /* 48.00 MHz */
204 # define CLKDIVN_val 7 /* FCLK:HCLK:PCLK = 1:3:6 */
205 # define CAMDIVN 0x4C000018
206 #elif defined(CONFIG_S3C2442)
207 # define INTSUBMSK_val 0xffff
208 # if (CONFIG_SYS_CLK_FREQ == 12000000)
209 # define MPLLCON_val ((142 << 12) + (7 << 4) + 1)
210 # define UPLLCON_val (( 88 << 12) + (8 << 4) + 2)
211 # elif (CONFIG_SYS_CLK_FREQ == 16934400)
212 # define MPLLCON_val ((181 << 12) + (14<< 4) + 1)
213 # define UPLLCON_val (( 26 << 12) + (4 << 4) + 1)
215 # define CLKDIVN_val 7 /* FCLK:HCLK:PCLK = 1:3:6 */
216 # define CAMDIVN 0x4C000018
217 #elif defined(CONFIG_S3C2443)
218 # define INTSUBMSK_val 0x1fffffff
219 # define EPLLCON_val ((40 << 16) | (1 << 8) | (1)) /* 96 MHz */
220 # define MPLLCON_val ((81 << 16) | (2 << 8) | (0)) /* 1068 MHz */
221 # define CLKDIV0_val ((8 << 9) | (1 << 4) | (1 << 3) | (1 << 2)
229 * mask all IRQs by setting all bits in the INTMR - default
234 # if defined(CONFIG_S3C2410) || defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442) || \
235 defined(CONFIG_S3C2443)
236 ldr r1, =INTSUBMSK_val
241 #if defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442)
242 /* Make sure we get FCLK:HCLK:PCLK = 1:3:6 */
248 /* Clock asynchronous mode */
249 mrc p15, 0, r1, c1, c0, 0
250 orr r1, r1, #0xc0000000
251 mcr p15, 0, r1, c1, c0, 0
254 #if defined(CONFIG_S3C2443)
255 #define LOCKCON0 0x4c000000
256 #define LOCKCON1 0x4c000004
257 #define MPLLCON 0x4c000010
258 #define EPLLCON 0x4c000018
264 /* set safe (way too long) locktime for both PLLs */
276 /* select MPLL clock out for SYSCLK */
290 #else /* i.e. 2440, 2410 and 2440 */
291 #define LOCKTIME 0x4c000000
292 #define UPLLCON 0x4c000008
302 /* Page 7-19, seven nops between UPLL and MPLL */
312 str r1, [r0, #-4] /* MPLLCON */
314 /* FCLK:HCLK:PCLK = 1:2:4 */
322 ldr r0, =0x4c00000c /* clkcon */
323 ldr r1, =0x7fff0 /* all clocks on */
326 /* gpio UART0 init */
345 #endif /* CONFIG_S3C2400 || CONFIG_S3C2410 || CONFIG_S3C2440 || CONFIG_S3C2442
348 #ifndef CONFIG_SKIP_LOWLEVEL_INIT
349 #ifndef CONFIG_LL_INIT_NAND_ONLY
353 #if defined(CONFIG_AT91RM9200) || defined(CONFIG_S3C2410) || \
354 defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442) || \
355 defined(CONFIG_S3C2443)
357 #ifndef CONFIG_SKIP_RELOCATE_UBOOT
358 adr r0, _start /* r0 <- current position of code */
360 #ifdef CONFIG_S3C2410_NAND_BOOT
361 /* are we running from NAND ? */
362 #define BWSCON 0x48000000
363 ldr r1, =BWSCON /* Z = CPU booted from NAND */
365 tst r1, #6 /* BWSCON[2:1] = OM[1:0] */
366 teqeq r0, #0 /* Z &= running at address 0 */
368 #endif /* CONFIG_S3C2410_NAND_BOOT */
370 relocate: /* relocate U-Boot to RAM */
371 teq r0, #0 /* running at address 0 ? */
372 bleq may_resume /* yes -> do low-level setup */
374 adr r0, _start /* the above may have clobbered r0 */
376 ldr r1, _TEXT_BASE /* test if we run from flash or RAM */
377 cmp r0, r1 /* don't reloc during debug */
380 ldr r2, _armboot_start
382 sub r2, r3, r2 /* r2 <- size of armboot */
383 add r2, r0, r2 /* r2 <- source end address */
386 ldmia r0!, {r3-r10} /* copy from source address [r0] */
387 stmia r1!, {r3-r10} /* copy to target address [r1] */
388 cmp r0, r2 /* until source end address [r2] */
390 mov r0, #0 /* flush v3/v4 cache */
391 mcr p15, 0, r0, c7, c7, 0
392 ldr pc, _done_relocate /* jump to relocated code */
396 #ifdef CONFIG_S3C2410_NAND_BOOT
398 bl may_resume /* low-level setup and resume */
401 #if defined(CONFIG_S3C2410)
402 mov r1, #S3C2410_NAND_BASE
403 ldr r2, =0xf842 @ initial value enable tacls=3,rph0=6,rph1=0
404 str r2, [r1, #oNFCONF]
405 ldr r2, [r1, #oNFCONF]
406 bic r2, r2, #0x800 @ enable chip
407 str r2, [r1, #oNFCONF]
408 mov r2, #0xff @ RESET command
409 strb r2, [r1, #oNFCMD]
414 2: ldr r2, [r1, #oNFSTAT] @ wait ready
417 ldr r2, [r1, #oNFCONF]
418 orr r2, r2, #0x800 @ disable chip
419 str r2, [r1, #oNFCONF]
420 #elif defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442)
421 mov r1, #S3C2440_NAND_BASE
422 ldr r2, =0xfff0 @ initial value tacls=3,rph0=7,rph1=7
423 ldr r3, [r1, #oNFCONF]
425 str r3, [r1, #oNFCONF]
427 ldr r3, [r1, #oNFCONT]
428 orr r3, r3, #1 @ enable nand controller
429 str r3, [r1, #oNFCONT]
430 #endif /* CONFIG_S3C2440 || CONFIG_S3C2442 */
432 ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */
433 sub r0, r0, #CFG_MALLOC_LEN /* malloc area */
434 sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo */
435 #ifdef CONFIG_USE_IRQ
436 sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
438 sub sp, r0, #12 /* leave 3 words for abort-stack */
443 mov r2, #CFG_UBOOT_SIZE
448 #ifdef CONFIG_DEBUG_LL
453 1: b 1b @ infinite loop
457 #ifdef CONFIG_DEBUG_LL
467 mov r2, #0x400 @ 4 bytes * 1024 = 4K-bytes
477 #ifdef CONFIG_DEBUG_LL
487 ldr r0, _booted_from_nand
490 #endif /* CONFIG_S3C2410_NAND_BOOT */
493 #if defined(CONFIG_USE_IRQ) && (defined(CONFIG_S3C2410) || \
494 defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442))
495 /* In the case of the S3C2410, if we've somehow magically (JTAG, ...)
496 ended up in RAM, then that ram is mapped to 0x30000000 and not 0.
497 So we need to copy the interrupt vectors, etc. */
507 #endif /* CONFIG_USE_IRQ */
509 #endif /* CONFIG_SKIP_RELOCATE_UBOOT */
511 /* Set up the stack */
513 ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */
514 sub r0, r0, #CFG_MALLOC_LEN /* malloc area */
515 sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo */
516 #ifdef CONFIG_USE_IRQ
517 sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
519 sub sp, r0, #12 /* leave 3 words for abort-stack */
522 ldr r0, _bss_start /* find start of bss segment */
523 ldr r1, _bss_end /* stop here */
524 mov r2, #0x00000000 /* clear */
526 clbss_l:str r2, [r0] /* clear loop... */
531 ldr pc, _start_armboot
533 _start_armboot: .word start_armboot
537 *************************************************************************
539 * CPU_init_critical registers
541 * setup important registers
542 * setup memory timing
544 *************************************************************************
548 #ifndef CONFIG_SKIP_LOWLEVEL_INIT
551 * flush v4 I/D caches
554 mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache */
555 mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */
558 * disable MMU stuff and caches
560 mrc p15, 0, r0, c1, c0, 0
561 bic r0, r0, #0x00002300 @ clear bits 13, 9:8 (--V- --RS)
562 bic r0, r0, #0x00000087 @ clear bits 7, 2:0 (B--- -CAM)
563 orr r0, r0, #0x00000002 @ set bit 2 (A) Align
564 orr r0, r0, #0x00001000 @ set bit 12 (I) I-Cache
565 mcr p15, 0, r0, c1, c0, 0
568 * before relocating, we have to setup RAM timing
569 * because memory timing is board-dependend, you will
570 * find a lowlevel_init.S in your board directory.
573 #if defined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK) || defined(CONFIG_AT91RM9200DF)
580 #endif /* CONFIG_SKIP_LOWLEVEL_INIT */
584 *************************************************************************
588 * Bring up memory and check if we're coming out of suspend.
590 *************************************************************************
595 mov r10, lr /* we may call cpu_init_crit */
597 /* take sdram out of power down */
598 ldr r0, =0x56000080 /* misccr */
600 bic r1, r1, #(S3C2410_MISCCR_nEN_SCLK0 | S3C2410_MISCCR_nEN_SCLK1 | S3C2410_MISCCR_nEN_SCLKE)
603 /* ensure signals stabalise */
608 #if !defined(CONFIG_SKIP_LOWLEVEL_INIT) && defined(CONFIG_LL_INIT_NAND_ONLY)
611 #if defined(CONFIG_S3C2410) || defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442)
612 /* ensure some refresh has happened */
617 /* test for resume */
618 ldr r1, =0x560000B4 /* gstatus2 */
620 tst r0, #0x02 /* is this resume from power down */
621 ldrne pc, [r1, #4] /* gstatus3 */
622 #endif /* CONFIG_S3C2410 || CONFIG_S3C244 || CONFIG_S3C2442 */
623 #endif /* CONFIG_SKIP_LOWLEVEL_INIT */
628 *************************************************************************
632 *************************************************************************
638 #define S_FRAME_SIZE 72
660 #define MODE_SVC 0x13
664 * use bad_save_user_regs for abort/prefetch/undef/swi ...
665 * use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling
668 .macro bad_save_user_regs
669 sub sp, sp, #S_FRAME_SIZE
670 stmia sp, {r0 - r12} @ Calling r0-r12
671 ldr r2, _armboot_start
672 sub r2, r2, #(CONFIG_STACKSIZE+CFG_MALLOC_LEN)
673 sub r2, r2, #(CFG_GBL_DATA_SIZE+8) @ set base 2 words into abort stack
674 ldmia r2, {r2 - r3} @ get pc, cpsr
675 add r0, sp, #S_FRAME_SIZE @ restore sp_SVC
679 stmia r5, {r0 - r3} @ save sp_SVC, lr_SVC, pc, cpsr
683 .macro irq_save_user_regs
684 sub sp, sp, #S_FRAME_SIZE
685 stmia sp, {r0 - r12} @ Calling r0-r12
687 stmdb r7, {sp, lr}^ @ Calling SP, LR
688 str lr, [r7, #0] @ Save calling PC
690 str r6, [r7, #4] @ Save CPSR
691 str r0, [r7, #8] @ Save OLD_R0
695 .macro irq_restore_user_regs
696 ldmia sp, {r0 - lr}^ @ Calling r0 - lr
698 ldr lr, [sp, #S_PC] @ Get PC
699 add sp, sp, #S_FRAME_SIZE
700 subs pc, lr, #4 @ return & move spsr_svc into cpsr
704 ldr r13, _armboot_start @ setup our mode stack
705 sub r13, r13, #(CONFIG_STACKSIZE+CFG_MALLOC_LEN)
706 sub r13, r13, #(CFG_GBL_DATA_SIZE+8) @ reserved a couple spots in abort stack
708 str lr, [r13] @ save caller lr / spsr
712 mov r13, #MODE_SVC @ prepare SVC-Mode
719 .macro get_irq_stack @ setup IRQ stack
720 ldr sp, IRQ_STACK_START
723 .macro get_fiq_stack @ setup FIQ stack
724 ldr sp, FIQ_STACK_START
731 undefined_instruction:
734 bl do_undefined_instruction
740 bl do_software_interrupt
760 #ifdef CONFIG_USE_IRQ
767 irq_restore_user_regs
772 /* someone ought to write a more effiction fiq_save_user_regs */
775 irq_restore_user_regs