会痛的十七岁中间插曲:u-boot-1.1.4 (实现了从Nand Flash 启动)(基于优龙FS2410\S3C2410平台)

来源:百度文库 编辑:偶看新闻 时间:2024/04/30 15:12:41
 2009-10-06 15:48

       如何从Nand Flash启动u-boot?从网上找了很多文章,结果很令我失望,不是描述不完全,就是方法不可行,最后只能自己研究。经过几天的奋战,终于把这个问题解决了,现在把最终可运行的代码贴在这里,以免忘却。

/*
* armboot - Startup Code for ARM920 CPU-core
*
* Copyright (c) 2001 Marius Gr鰃er
* Copyright (c) 2002 Alex Z黳ke
* Copyright (c) 2002 Gary Jennejohn
*
* See file CREDITS for list of people who contributed to this
* project.
*
* 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 program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/


#include
#include


/*
*************************************************************************
*
* Jump vector table as in table 3.1 in [1]
*
*************************************************************************
*/


.globl _start
_start: b       reset
ldr pc, _undefined_instruction
ldr pc, _software_interrupt
ldr pc, _prefetch_abort
ldr pc, _data_abort
ldr pc, _not_used
ldr pc, _irq
ldr pc, _fiq

_undefined_instruction: .word undefined_instruction
_software_interrupt: .word software_interrupt
_prefetch_abort: .word prefetch_abort
_data_abort:   .word data_abort
_not_used:   .word not_used
_irq:    .word irq
_fiq:    .word fiq

.balignl 16,0xdeadbeef


/*
*************************************************************************
*
* Startup Code (reset vector)
*
* do important init only if we don't start from memory!
* relocate armboot to ram
* setup stack
* jump to second stage
*
*************************************************************************
*/

_TEXT_BASE:
.word TEXT_BASE

.globl _armboot_start
_armboot_start:
.word _start

/*
* These are defined in the board-specific linker script.
*/
.globl _bss_start
_bss_start:
.word __bss_start

.globl _bss_end
_bss_end:
.word _end

#ifdef CONFIG_USE_IRQ
/* IRQ stack memory (calculated at run-time) */
.globl IRQ_STACK_START
IRQ_STACK_START:
.word 0x0badc0de

/* IRQ stack memory (calculated at run-time) */
.globl FIQ_STACK_START
FIQ_STACK_START:
.word 0x0badc0de
#endif


/*
* the actual reset code
*/

reset:
/*
* set the cpu to SVC32 mode
*/
mrs r0,cpsr
bic r0,r0,#0x1f
orr r0,r0,#0xd3
msr cpsr,r0

/* turn off the watchdog */

# define pWTCON   0x53000000
# define INTMSK   0x4A000008 /* Interupt-Controller base addresses */
# define INTSUBMSK 0x4A00001C
# define CLKDIVN 0x4C000014 /* clock divisor register */

ldr     r0, =pWTCON
mov     r1, #0x0
str     r1, [r0]

/*
* mask all IRQs by setting all bits in the INTMR - default
*/
mov r1, #0xffffffff
ldr r0, =INTMSK
str r1, [r0]

ldr r1, =0x3ff
ldr r0, =INTSUBMSK
str r1, [r0]


/* FCLK:HCLK:PCLK = 1:2:4 */
/* default FCLK is 120 MHz ! */
ldr r0, =CLKDIVN
mov r1, #3
str r1, [r0]


/*
* we do sys-critical inits only at reboot,
* not when booting from ram!
*/
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
bl cpu_init_crit
#endif

#ifndef CONFIG_SKIP_RELOCATE_UBOOT

mov r5, #0x4e000000
ldr r0,=(1<<15)|(1<<12)|(1<<11)|(7<<8)|(7<<4)|(7)
str r0,[r5]
bl ReadNandID
mov r6, #0
ldr r0, =0xec73
cmp r5,r0
beq 1f
ldr r0,=0xec75
cmp r5,r0
beq 1f
mov r6,#1
1:
bl ReadNandStatus

mov r8, #0 @
ldr r9, _TEXT_BASE @拷贝到由标号ResetEntry确定的绝对地址(内存绝对地址)中,而不是拷贝到SRAM中。
cmp     r8, r9                  /* don't reloc during debug         */
beq     stack_setup
            @ResetEntry的地址在链接(Link)时才能确定
            @注意,与系统自动拷贝4K到SRAM不同。
2:
ands r0, r8, #0x1f @取页号,如果页号为0,则标志位Z=1,否则Z=0
bne 3f       @如果是第0页,则顺序执行,否则跳转。如果标志位Z=0,则跳转;第一次循环Z=1,不跳转
mov r0, r8     @
bl CheckBadBlk   @通过第0页判断此块是否为坏块
cmp r0, #0     @如果r0为0,则标志位Z=1,说明该块为好块;否则Z=0,该块为坏块
addne r8, r8, #32   @如果该块为坏块,则不读取该块,直接跳转
bne 4f
3:
mov r0, r8    @r8为要读取的页地址
mov r1, r9    @r9为要写入的内存地址
bl ReadNandPage   @跳转入读取函数,读取一块
add r9, r9, #512   @
add r8, r8, #1   
4:
cmp r8, #256
bcc 2b

mov r5, #0x4e000000    @DsNandFlash
ldr r0, [r5]
and r0, r0, #~0x8000
str r0, [r5]
/*ldr pc, =copy_proc_beg@跳转入内存中执行,地址为BaseOfROM*/


#endif /* CONFIG_SKIP_RELOCATE_UBOOT */

/* Set up the stack          */
stack_setup:
ldr r0, _TEXT_BASE   /* upper 128 KiB: relocated uboot   */
sub r0, r0, #CFG_MALLOC_LEN /* malloc area                      */
sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo                        */
#ifdef CONFIG_USE_IRQ
sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
#endif
sub sp, r0, #12   /* leave 3 words for abort-stack    */

clear_bss:
ldr r0, _bss_start   /* find start of bss segment        */
ldr r1, _bss_end   /* stop here                        */
mov r2, #0x00000000   /* clear                            */

clbss_l:str r2, [r0]   /* clear loop...                    */
add r0, r0, #4
cmp r0, r1
ble clbss_l

#if 0
/* try doing this stuff after the relocation */
ldr     r0, =pWTCON
mov     r1, #0x0
str     r1, [r0]

/*
* mask all IRQs by setting all bits in the INTMR - default
*/
mov r1, #0xffffffff
ldr r0, =INTMR
str r1, [r0]

/* FCLK:HCLK:PCLK = 1:2:4 */
/* default FCLK is 120 MHz ! */
ldr r0, =CLKDIVN
mov r1, #3
str r1, [r0]
/* END stuff after relocation */
#endif
#ifdef CONFIG_S3C2410_NAND_BOOT    /* CONFIG_S3C2410_NAND_BOOT=y */

#endif

ldr pc, _start_armboot

_start_armboot: .word start_armboot

/********************************************
* sub function
********************************************/
#ifdef CONFIG_S3C2410_NAND_BOOT
ReadNandID:
mov r7,#0x4e000000
ldr r0,[r7,#0]   @NFChipEn();
bic r0,r0,#0x800
str r0,[r7,#0]
mov r0,#0x90   @WrNFCmd(RdIDCMD);
strb r0,[r7,#4]
mov r4,#0    @WrNFAddr(0);
strb r4,[r7,#8]
1:        @while(NFIsBusy());
ldr r0,[r7,#0x10]
tst r0,#1
beq 1b
ldrb r0,[r7,#0xc] @id = RdNFDat()<<8;
mov r0,r0,lsl #8
ldrb r1,[r7,#0xc] @id |= RdNFDat();
orr r5,r1,r0
ldr r0,[r7,#0]   @NFChipDs();
orr r0,r0,#0x800
str r0,[r7,#0]
mov pc,lr

ReadNandStatus:
mov r7,#0x4e000000
ldr r0,[r7,#0]   @NFChipEn();
bic r0,r0,#0x800
str r0,[r7,#0]
mov r0,#0x70   @WrNFCmd(QUERYCMD);
strb r0,[r7,#4]
ldrb r1,[r7,#0xc] @r1 = RdNFDat();
ldr r0,[r7,#0]   @NFChipDs();
orr r0,r0,#0x800
str r0,[r7,#0]
mov pc,lr

WaitNandBusy:
mov r0,#0x70   @WrNFCmd(QUERYCMD);
mov r1,#0x4e000000
strb r0,[r1,#4]
1:        @while(!(RdNFDat()&0x40));
ldrb r0,[r1,#0xc]
tst r0,#0x40
beq 1b
mov r0,#0    @WrNFCmd(READCMD0);
strb r0,[r1,#4]
mov pc,lr

CheckBadBlk:
mov r7, lr
mov r5, #0x4e000000

bic r0, r0, #0x1f @addr &= ~0x1f;
ldr r1,[r5,#0]   @NFChipEn()
bic r1,r1,#0x800
str r1,[r5,#0]

mov r1,#0x50   @WrNFCmd(READCMD2)
strb r1,[r5,#4]
mov r1, #5
strb r1,[r5,#8]   @WrNFAddr(5)
strb r0,[r5,#8]   @WrNFAddr(addr)
mov r1,r0,lsr #8 @WrNFAddr(addr>>8)
strb r1,[r5,#8]
cmp r6,#0    @if(NandAddr)  
movne r0,r0,lsr #16 @WrNFAddr(addr>>16)
strneb r0,[r5,#8]

bl WaitNandBusy @WaitNFBusy()

ldrb r0, [r5,#0xc] @RdNFDat()
sub r0, r0, #0xff

mov r1,#0    @WrNFCmd(READCMD0)
strb r1,[r5,#4]

ldr r1,[r5,#0]   @NFChipDs()
orr r1,r1,#0x800
str r1,[r5,#0]

mov pc, r7

ReadNandPage:
mov r7,lr
mov r4,r1
mov r5,#0x4e000000

ldr r1,[r5,#0]   @NFChipEn()
bic r1,r1,#0x800
str r1,[r5,#0]

mov r1,#0    @WrNFCmd(READCMD0)
strb r1,[r5,#4]
strb r1,[r5,#8]   @WrNFAddr(0)
strb r0,[r5,#8]   @WrNFAddr(addr)
mov r1,r0,lsr #8 @WrNFAddr(addr>>8)
strb r1,[r5,#8]
cmp r6,#0    @if(NandAddr)  
movne r0,r0,lsr #16 @WrNFAddr(addr>>16)
strneb r0,[r5,#8]

ldr r0,[r5,#0]   @InitEcc()
orr r0,r0,#0x1000
str r0,[r5,#0]

bl WaitNandBusy @WaitNFBusy()

mov r0,#0    @for(i=0; i<512; i++)
1:
ldrb r1,[r5,#0xc] @buf[i] = RdNFDat()
strb r1,[r4,r0]
add r0,r0,#1
bic r0,r0,#0x10000
cmp r0,#0x200
bcc 1b

ldr r0,[r5,#0]   @NFChipDs()
orr r0,r0,#0x800
str r0,[r5,#0]
  
mov pc,r7
#endif @ CONFIG_S3C2410_NAND_BOOT

/*
*************************************************************************
*
* CPU_init_critical registers
*
* setup important registers
* setup memory timing
*
*************************************************************************
*/


cpu_init_crit:
/*
* flush v4 I/D caches
*/
mov r0, #0
mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache */
mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */

/*
* disable MMU stuff and caches
*/
mrc p15, 0, r0, c1, c0, 0
bic r0, r0, #0x00002300 @ clear bits 13, 9:8 (--V- --RS)
bic r0, r0, #0x00000087 @ clear bits 7, 2:0 (B--- -CAM)
orr r0, r0, #0x00000002 @ set bit 2 (A) Align
orr r0, r0, #0x00001000 @ set bit 12 (I) I-Cache
mcr p15, 0, r0, c1, c0, 0

/*
* before relocating, we have to setup RAM timing
* because memory timing is board-dependend, you will
* find a lowlevel_init.S in your board directory.
*/
mov ip, lr
bl lowlevel_init
mov lr, ip
mov pc, lr

/*
*************************************************************************
*
* Interrupt handling
*
*************************************************************************
*/

@
@ IRQ stack frame.
@
#define S_FRAME_SIZE 72

#define S_OLD_R0 68
#define S_PSR   64
#define S_PC   60
#define S_LR   56
#define S_SP   52

#define S_IP   48
#define S_FP   44
#define S_R10   40
#define S_R9   36
#define S_R8   32
#define S_R7   28
#define S_R6   24
#define S_R5   20
#define S_R4   16
#define S_R3   12
#define S_R2   8
#define S_R1   4
#define S_R0   0

#define MODE_SVC 0x13
#define I_BIT 0x80

/*
* use bad_save_user_regs for abort/prefetch/undef/swi ...
* use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling
*/

.macro bad_save_user_regs
sub sp, sp, #S_FRAME_SIZE
stmia sp, {r0 - r12}    @ Calling r0-r12
ldr r2, _armboot_start
sub r2, r2, #(CONFIG_STACKSIZE+CFG_MALLOC_LEN)
sub r2, r2, #(CFG_GBL_DATA_SIZE+8) @ set base 2 words into abort stack
ldmia r2, {r2 - r3}    @ get pc, cpsr
add r0, sp, #S_FRAME_SIZE   @ restore sp_SVC

add r5, sp, #S_SP
mov r1, lr
stmia r5, {r0 - r3}    @ save sp_SVC, lr_SVC, pc, cpsr
mov r0, sp
.endm

.macro irq_save_user_regs
sub sp, sp, #S_FRAME_SIZE
stmia sp, {r0 - r12}    @ Calling r0-r12
add     r8, sp, #S_PC
stmdb   r8, {sp, lr}^                   @ Calling SP, LR
str     lr, [r8, #0]                    @ Save calling PC
mrs     r6, spsr
str     r6, [r8, #4]                    @ Save CPSR
str     r0, [r8, #8]                    @ Save OLD_R0
mov r0, sp
.endm

.macro irq_restore_user_regs
ldmia sp, {r0 - lr}^    @ Calling r0 - lr
mov r0, r0
ldr lr, [sp, #S_PC]    @ Get PC
add sp, sp, #S_FRAME_SIZE
subs pc, lr, #4    @ return & move spsr_svc into cpsr
.endm

.macro get_bad_stack
ldr r13, _armboot_start   @ setup our mode stack
sub r13, r13, #(CONFIG_STACKSIZE+CFG_MALLOC_LEN)
sub r13, r13, #(CFG_GBL_DATA_SIZE+8) @ reserved a couple spots in abort stack

str lr, [r13]    @ save caller lr / spsr
mrs lr, spsr
str     lr, [r13, #4]

mov r13, #MODE_SVC    @ prepare SVC-Mode
@ msr spsr_c, r13
msr spsr, r13
mov lr, pc
movs pc, lr
.endm

.macro get_irq_stack    @ setup IRQ stack
ldr sp, IRQ_STACK_START
.endm

.macro get_fiq_stack    @ setup FIQ stack
ldr sp, FIQ_STACK_START
.endm

/*
* exception handlers
*/
.align 5
undefined_instruction:
get_bad_stack
bad_save_user_regs
bl do_undefined_instruction

.align 5
software_interrupt:
get_bad_stack
bad_save_user_regs
bl do_software_interrupt

.align 5
prefetch_abort:
get_bad_stack
bad_save_user_regs
bl do_prefetch_abort

.align 5
data_abort:
get_bad_stack
bad_save_user_regs
bl do_data_abort

.align 5
not_used:
get_bad_stack
bad_save_user_regs
bl do_not_used

#ifdef CONFIG_USE_IRQ

.align 5
irq:
get_irq_stack
irq_save_user_regs
bl do_irq
irq_restore_user_regs

.align 5
fiq:
get_fiq_stack
/* someone ought to write a more effiction fiq_save_user_regs */
irq_save_user_regs
bl do_fiq
irq_restore_user_regs

#else

.align 5
irq:
get_bad_stack
bad_save_user_regs
bl do_irq

.align 5
fiq:
get_bad_stack
bad_save_user_regs
bl do_fiq

#endif
   .align    2
DW_STACK_START:
    .word    STACK_BASE+STACK_SIZE-4