判断当前位置
判断当前位置是否在SDRAM
# < cpu\arm920t\start.S >
relocate1: /* relocate U-Boot to RAM */
adr r0, _start /* r0 <- current position of code */
ldr r1, _TEXT_BASE /* test if we run from flash or RAM */
cmp r0, r1 /* don't reloc during debug */
beq stack_setup
判断当前位置为Nand还是Nor Flash
# < cpu\arm920t\start.S >
ldr r1, =0x4000003c
mov r0, #0
str r0, [r1]
// mov r1, #0x3c
ldr r1, =0x4000003c
ldr r0, [r1]
cmp r0, #0
bne relocate2
/**/
ldr r0, =0xdeadbeef
ldr r1, =0x4000003c
str r0, [r1]
说明:
从地址总线可以看出,Nor和Nand启动的区别为BootSRAM位置,所以判断0x40000000-0x40000FFFF是否可以存储数据,就可以知道是不是Nor启动
Nand Boot
# < cpu\arm920t\start.S >
/***************************NAND BOOT*****************************/
#define LENGTH_UBOOT 0x40000
#define NAND_CTL_BASE 0x4e000000
#define oNFCONF 0x00
#define oNFCONT 0x04
#define oNFCMD 0x08
#define oNFSTAT 0x20
/*reset NAND*/
mov r1, #NAND_CTL_BASE
ldr r2, =((2<<12)|(1<<8)|(1<<4)|(0<<0))
str r2, [r1, #oNFCONF]
ldr r2, =((1<<4)|(0<<1)|(1<<0))
str r2, [r1, #oNFCONT]
ldr r2, =0x6
str r2, [r1, #oNFSTAT]
mov r2, #0xff
strb r2, [r1, #oNFCMD]
mov r3, #0
nand1:
add r3, r3, #0x01
cmp r3, #0xa
blt nand1
nand2:
ldr r2, [r1, #oNFSTAT]
tst r2, #0x4
beq nand2
ldr r2, [r1, #oNFCONT]
orr r2, r2, #0x02
str r2, [r1, #oNFCONT]
ldr sp, DW_STACK_START
mov fp, #0
ldr r0, =TEXT_BASE
mov r1, #0x0
mov r2, #LENGTH_UBOOT
bl nand_read_ll
tst r0, #0x0
beq ok_nand_read
bad_nand_read:
loop2:
b loop2
ok_nand_read:
mov r0, #0
ldr r1, =TEXT_BASE
mov r2, #0x400
go_next:
ldr r3, [r0], #4
ldr r4, [r1], #4
teq r3, r4
bne notmatch
subs r2, r2, #4
beq stack_setup
bne go_next
notmatch:
loop3:
b loop3
/* Set up the stack */
stack_setup:
ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */
sub r0, r0, #CONFIG_SYS_MALLOC_LEN /* malloc area */
sub r0, r0, #CONFIG_SYS_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
ldr pc, _start_armboot
_start_armboot: .word start_armboot
NFCONF(指令周期)
mov r1, #NAND_CTL_BASE
ldr r2, =((2<<12)|(1<<8)|(1<<4))
str r2, [r1, #oNFCONF]
周期(HCLK: 100M)
TACLS = 2*HCLK=20ns > 0 ns
TWRPH0 = (1+1)*HCLK=20ns > 12 ns
TWRPH1 = (1+1)*HCLK=20ns > 5 ns
NFCONT(配置使能Nand Flash)
ldr r2, =((1<<4)|(0<<1)|(1<<0))
str r2, [r1, #oNFCONT]
初始化ECC(错误校验)
使能片选
Nand Flash控制器使能
NFSTAT(Nand Flash状态)
ldr r2, =0x6
str r2, [r1, #oNFSTAT]
清除RnB
NFCMD(Nand Flash命令)
mov r2, #0xff
strb r2, [r1, #oNFCMD]
复位
片选、设置栈底、跳转c代码拷贝第二阶段
nand2:
// 判断状态
ldr r2, [r1, #oNFSTAT]
tst r2, #0x4
beq nand2
// 片选
ldr r2, [r1, #oNFCONT]
orr r2, r2, #0x02
str r2, [r1, #oNFCONT]
// 设置栈顶
ldr sp, DW_STACK_START
mov fp, #0
设置参数,跳转c代码
ldr r0, =TEXT_BASE
mov r1, #0x0
mov r2, #LENGTH_UBOOT
bl nand_read_ll
c代码拷贝第二阶段
# < board\vbird\mini2440\nand_read.c >
#include <common.h>
#include <linux/mtd/nand.h>
#define _REGb(x) (*(volatile unsigned char *)(x))
#define _REGw(x) (*(volatile unsigned short *)(x))
#define _REGi(x) (*(volatile unsigned int *)(x))
#define NF_BASE 0x4e000000
#define NFCONF _REGi(NF_BASE+0x0)
#define NFCONT _REGi(NF_BASE+0x04)
#define NFCMD _REGb(NF_BASE+0x8)
#define NFADDR _REGb(NF_BASE+0xc)
#define NFDATA _REGb(NF_BASE+0X10)
#define NFDATA16 _REGw(NF_BASE+0x10)
#define NFSTAT _REGb(NF_BASE+0x20)
#define NFSTAT_BUSY 1
#define nand_select() (NFCONT &= ~(1<<1))
#define nand_deselect() (NFCONT |= (1<<1))
#define nand_clear_RnB() (NFSTAT |= (1<<2))
static inline void nand_wait(void)
{
int i;
while (!(NFSTAT & NFSTAT_BUSY))
for (i=0; i<10; i++);
}
struct boot_nand_t{
int page_size;
int block_size;
int bad_block_offset;
};
static int is_bad_block(struct boot_nand_t *nand, unsigned long i)
{
unsigned char data;
unsigned long page_num;
nand_clear_RnB();
if (nand->page_size == 2048)
{
page_num=i>>11;
NFCMD = NAND_CMD_READ0;
NFADDR = nand->bad_block_offset&0xff;
NFADDR = (nand->bad_block_offset>>8)&0xff;
NFADDR = page_num & 0xff;
NFADDR = (page_num>>8)&0xff;
NFADDR = (page_num>>16)&0xff;
NFCMD = NAND_CMD_READSTART;
}
else
{
return -1;
}
nand_wait();
data = (NFDATA & 0xff);
if (data != 0xff)
return 1;
return 0;
}
static int nand_read_page_ll(struct boot_nand_t *nand,
unsigned char *buf,
unsigned long addr)
{
unsigned char *ptr = (unsigned char *)buf;
unsigned int i, page_num;
nand_clear_RnB();
NFCMD = NAND_CMD_READ0;
if (nand->page_size == 2048)
{
page_num = addr>>11;
NFADDR = 0;
NFADDR = 0;
NFADDR = page_num & 0xff;
NFADDR = (page_num>>8) & 0xff;
NFADDR = (page_num>>16) & 0xff;
NFCMD = NAND_CMD_READSTART;
}
else
{
return -1;
}
nand_wait();
for (i=0; i<(nand->page_size); i++)
{
*ptr = NFDATA;
ptr++;
}
return nand->page_size;
}
static unsigned short nand_read_id()
{
unsigned short res = 0;
NFCMD = NAND_CMD_READID;
NFADDR = 0;
res = NFDATA;
res = (res<<8) | NFDATA;
return res;
}
extern unsigned int dynpart_size[];
int nand_read_ll(unsigned char *buf, unsigned long start_addr, int size)
{
int i, j;
unsigned short nand_id;
struct boot_nand_t nand;
/*chip Enable*/
nand_select();
nand_clear_RnB();
for (i=0; i<10; i++);
nand_id=nand_read_id();
nand.page_size = 2048;
nand.block_size = 128*1024;
nand.bad_block_offset = nand.page_size;
if ((start_addr&(nand.block_size-1)) || (size&(nand.block_size-1)))
return -1;
for (i=start_addr; i<(start_addr+size);)
{
j = nand_read_page_ll(&nand, buf, i);
i += j;
buf += j;
}
nand_deselect();
return 0;
}
设置栈、bss段、跳转第二阶段
# < cpu\arm920t\start.S >
stack_setup:
ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */
sub r0, r0, #CONFIG_SYS_MALLOC_LEN /* malloc area */
sub r0, r0, #CONFIG_SYS_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
ldr pc, _start_armboot
_start_armboot: .word start_armboot
Nor Boot
# < cpu\arm920t\start.S >
/*****************************CHECK_CODE_POSITION***************/
ldr r1, =0x4000003c
mov r0, #0
str r0, [r1]
mov r1, #0x3c
ldr r0, [r1]
cmp r0, #0
bne relocate2
/**/
ldr r0, =0xdeadbeef
ldr r1, =0x4000003c
str r0, [r1]
loop3:
b loop3
/*******************nor boot*********************/
relocate2:
ldr r1, =0xdeadbeef
cmp r0, r1
bne loop3
adr r0, _start
ldr r1, _TEXT_BASE
ldr r2, _armboot_start
ldr r3, _bss_start
sub r2, r3, r2
// stmia r1!, {r3-r10}
cmp r0, r2
ble copy_loop
ldr r2, _armboot_start
ldr r3, _bss_start
sub r2, r3, r2 /* r2 <- size of armboot */
add r2, r0, r2 /* r2 <- source end address */
copy_loop:
ldmia r0!, {r3-r10} /* copy from source address [r0] */
stmia r1!, {r3-r10} /* copy to target address [r1] */
cmp r0, r2 /* until source end addreee [r2] */
ble copy_loop
#endif /* CONFIG_SKIP_RELOCATE_UBOOT */
_armboot_start = _start 代码起始
_bss_start 代码结尾
_bss_start - _armboot_start 代码大小
拷贝:从_start,拷贝(_bss_start - _armboot_start )整个代码
copy_loop:
ldmia r0!, {r3-r10} /* copy from source address [r0] */
stmia r1!, {r3-r10} /* copy to target address [r1] */
cmp r0, r2 /* until source end addreee [r2] */
ble copy_loop