Coder
分类: 嵌入式
2010-03-13 21:26:05
第六步、从NAND Flash启动的支持
移植的重要关键部分是是代码的拷贝,从nand拷贝到sdram。从编程的角度看,nor flash是存储设备,而nand是I/O外设,对它们的底层操作有本质的不同。u-boot中对ARM的支持部分,没有支持nand启动的代码,而只有 nor flash的,重定位u-boot的那部分代码只适用于nor flash,而不适用于nand。整个启动代码参考了vivi的代码。因此,将vivi的nand_read.c(支持S
COBJS := nand_read.o
mini2440.o flash.o
Nand_read.c内容为:
/*
* nand_read.c: Simple NAND
read functions for booting from NAND
*
* This is used by
cpu/arm920/start.S assembler code,
* and the board-specific
linker script must make sure this
* file is linked within the
first 4kB of NAND flash.
*
* Taken from GPLv2 licensed
vivi bootloader,
* Copyright (C) 2002 MIZI
Research, Inc.
*
* Author: Hwang, Chideok
* Date : $Date: 2004/02/04 10:37:37 $
*
* u-boot integration and
bad-block skipping (C) 2006 by OpenMoko, Inc.
* Author: Harald Welte
*/
#include
#include
#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
#if defined(CONFIG_S
#define NFCONF __REGi(NF_BASE
+ 0x0)
#define NFCMD __REGb(NF_BASE
+ 0x4)
#define NFADDR __REGb(NF_BASE
+ 0x8)
#define NFDATA __REGb(NF_BASE
+ 0xc)
#define NFSTAT __REGb(NF_BASE
+ 0x10)
#define NFSTAT_BUSY 1
#define nand_select() (NFCONF
&= ~0x800)
#define nand_deselect() (NFCONF
|= 0x800)
#define nand_clear_RnB() do
{} while (0)
#elif defined(CONFIG_S
#define NFCONF __REGi(NF_BASE
+ 0x0)
#define NFCONT __REGi(NF_BASE
+ 0x4)
#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))
#endif
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;
// unsigned long size;
};
#if 0
#if defined(CONFIG_S
/* configuration for 2410 with 512byte sized flash */
#define NAND_PAGE_SIZE 512
#define BAD_BLOCK_OFFSET 5
#define NAND_BLOCK_MASK (NAND_PAGE_SIZE
- 1)
#define NAND_BLOCK_SIZE 0x4000
#else
/* configuration for 2440 with 2048byte sized flash */
#define NAND_5_ADDR_CYCLE
#define NAND_PAGE_SIZE 2048
#define BAD_BLOCK_OFFSET NAND_PAGE_SIZE
#define NAND_BLOCK_MASK (NAND_PAGE_SIZE - 1)
#define NAND_BLOCK_SIZE (NAND_PAGE_SIZE
* 64)
#endif
/* compile time failure in case of an invalid configuration */
#if defined(CONFIG_S
#error "S
#endif
#endif
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 ==
512) {
NFCMD =
NAND_CMD_READOOB; /* 0x50 */
NFADDR =
nand->bad_block_offset & 0xf;
NFADDR = (i >>
9) & 0xff;
NFADDR = (i >>
17) & 0xff;
NFADDR = (i >>
25) & 0xff;
} else if
(nand->page_size == 2048) {
page_num = i >>
11; /* addr / 2048 */
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 short *ptr16 =
(unsigned short *)buf;
unsigned int i, page_num;
nand_clear_RnB();
NFCMD = NAND_CMD_READ0;
if (nand->page_size ==
512) {
/* Write Address */
NFADDR = addr &
0xff;
NFADDR = (addr
>> 9) & 0xff;
NFADDR = (addr
>> 17) & 0xff;
NFADDR = (addr
>> 25) & 0xff;
} else if
(nand->page_size == 2048) {
page_num = addr >>
11; /* addr / 2048 */
/* Write Address */
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();
#if defined(CONFIG_S
for (i = 0; i <
nand->page_size; i++) {
*buf = (NFDATA &
0xff);
buf++;
}
#elif defined(CONFIG_S
for (i = 0; i <
(nand->page_size>>1); i++) {
*ptr16 = NFDATA16;
ptr16++;
}
#endif
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[];
/* low level nand read function */
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();
if (0) { /* dirty little
hack to detect if nand id is misread */
unsigned short * nid =
(unsigned short *)0x31fffff0;
*nid = nand_id;
}
if (nand_id == 0xec76
|| /* Samsung K91208 */
nand_id == 0xad76
) { /*Hynix HY27US
nand.page_size = 512;
nand.block_size = 16 *
1024;
nand.bad_block_offset
= 5;
// nand.size = 0x4000000;
} else if (nand_id ==
0xecf1 || /* Samsung K
nand_id == 0xecda || /* Samsung K
nand_id == 0xecd3 ) { /* Samsung K9K
nand.page_size = 2048;
nand.block_size = 128
* 1024;
nand.bad_block_offset
= nand.page_size;
// nand.size = 0x8000000;
} else {
return -1; // hang
}
if ((start_addr &
(nand.block_size-1)) || (size & ((nand.block_size-1))))
return -1; /* invalid alignment */
for (i=start_addr; i <
(start_addr + size);) {
#ifdef CONFIG_S
if (i &
(nand.block_size-1)== 0) {
if
(is_bad_block(&nand, i) ||
is_bad_block(&nand, i +
nand.page_size)) {
/* Bad block */
i +=
nand.block_size;
size +=
nand.block_size;
continue;
}
}
#endif
j =
nand_read_page_ll(&nand, buf, i);
i += j;
buf += j;
}
/* chip Disable */
nand_deselect();
return 0;
}
将/cpu/arm920t/start.s中之前阶段中为了从内存中启动而屏蔽掉的语句恢复。然后,删除或注释掉原来的 relocate 部分,用nand启动相关部分来替代。这段代码中调用的读取Nand函数nand_read_ll正是在nand_read.c中实现的。
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
bl cpu_init_crit
#endif
/*********************** CHECK_CODE_POSITION *************************/
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_BOOT ******************************/
#define LENGTH_UBOOT 0x40000
#define NAND_CTL_BASE 0x4E000000
#ifdef CONFIG_S
/* Offset */
#define oNFCONF 0x00
#define oNFCONT 0x04
#define oNFCMD 0x08
#define oNFSTAT 0x20
@ reset NAND
mov r1, #NAND_CTL_BASE
ldr r2, =(
(7<<12)|(7<<8)|(7<<4)|(0<<0) )
str r2, [r1, #oNFCONF]
ldr r2, [r1, #oNFCONF]
ldr r2, =( (1<<4)|(0<<1)|(1<<0) ) @ Active low CE Control
str r2, [r1, #oNFCONT]
ldr r2, [r1, #oNFCONT]
ldr r2, =(0x6) @
RnB Clear
str r2, [r1, #oNFSTAT]
ldr r2, [r1, #oNFSTAT]
mov r2, #0xff @
RESET command
strb r2, [r1, #oNFCMD]
mov r3, #0 @
wait
nand1:
add r3, r3, #0x1
cmp r3, #0xa
blt nand1
nand2:
ldr r2, [r1, #oNFSTAT] @ wait ready
tst r2, #0x4
beq nand2
ldr r2, [r1, #oNFCONT]
orr r2, r2, #0x2 @
Flash Memory Chip Disable
str r2, [r1, #oNFCONT]
@ get read to call C
functions (for nand_read())
ldr sp, DW_STACK_START @ setup stack pointer
mov fp, #0 @
no previous frame, so fp=0
@ copy U-Boot to RAM
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 @
infinite loop
ok_nand_read:
@ verify
mov r0, #0
ldr r1, =TEXT_BASE
mov r2, #0x400 @
4 bytes * 1024 = 4K-bytes
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 @
infinite loop
#endif
还要定义为了调用nand_read_ll而初始化的栈所用的变量DW_STACK_START。
_start_armboot: .word
start_armboot
#define STACK_BASE 0x
#define STACK_SIZE 0x10000
.align 2
DW_STACK_START: .word STACK_BASE+STACK_SIZE-4
同时,在/board/samsung/mini2440/lowlevel_init.s中,根据开发板电路,对内存相关的几个寄存器定义进行调整。
s
而通过查看编译后u-boot根目录下的u-boot.map文件可知,lowlevel_init.o并不在前4K的范围:
.text
0x
0x
所以我们要修改/cpu/arm920t/u-boot.lds文件,使lowlevel_init.o在前4K范围:
.text :
{
cpu/arm920t/start.o
(.text)
board/samsung/mini2440/lowlevel_init.o
(.text)
board/samsung/mini2440/nand_read.o
(.text)
*(.text)
}
修改后,重新编译,将u-boot烧入nand flash,能成功从nand启动了。
移植U-Boot-2008.10到友善之臂 mini2440
http://blog.chinaunix.net/u3/96581/showart_1934276.html
移植 u-boot2009.08到OK2440V3开发板(1)---方向与方法