【注意】
本程序只能用于读取2K/页的Nand。本人的Micro2440上的Nand Flash为256M,型号为K9F2G08
[408@WZC u-boot-2011.06]$ touch board/samsung/micro2440/nand_read.c
[408@WZC u-boot-2011.06]$ cat> board/samsung/micro2440/nand_read.c
#define rNFCONF (*(volatile unsigned *)0x4E000000)
#define rNFCONT (*(volatile unsigned *)0x4E000004)
#define rNFCMD (*(volatile unsigned *)0x4E000008)
#define rNFADDR (*(volatile unsigned *)0x4E00000C)
#define rNFDATA8 (*(volatile unsigned char*)0x4E000010)
#define rNFSTAT (*(volatile unsigned *)0x4E000020)
#define CMD_READ1 0x00 /* 页读命令周期1 */
#define CMD_READ2 0x30 /* 页读命令周期2 */
#define CMD_RESET 0xFF /* 复位 */
#define NF_CMD(cmd) {rNFCMD=(cmd);} /* 写命令 */
#define NF_ADDR(addr) {rNFADDR=(addr);} /* 写地址 */
#define NF_RDDATA8() (rNFDATA8) /* 读8位数据 */
#define NF_nFCE_L() {rNFCONT&=~(1<<1);} /* 片选使能 */
#define NF_nFCE_H() {rNFCONT|=(1<<1);} /* 片选禁用 */
#define NF_WAITRB() {while(!(rNFSTAT&(1<<1)));} /* 等待就绪 */
#define NF_CLEAR_RB() {rNFSTAT |= (1<<2);} /* 清除就绪/忙位 */
#define NF_DETECT_RB() {while(!(rNFSTAT&(1<<2)));} /* 等待就绪 */
#define TACLS 1
#define TWRPH0 2
#define TWRPH1 1
void delay(int i)
{
while(i-->0);
}
void Nand_Init(void)
{
rNFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4)|(0<<0);
rNFCONT = (1<<4)|(1<<1)|(1<<0);
}
static void Nand_Reset(void)
{
NF_nFCE_L(); /* 片选使能 */
NF_CLEAR_RB(); /* 清除就绪/忙位 */
NF_CMD(CMD_RESET); /* 写复位命令 */
NF_DETECT_RB(); /* 等待就绪 */
NF_nFCE_H(); /* 片选禁用 */
}
unsigned char Nand_ReadPage(const int page, unsigned char * const buffer)
{
int i;
Nand_Reset();
NF_nFCE_L();
NF_CLEAR_RB();
NF_CMD(CMD_READ1);
NF_ADDR(0x0);
NF_ADDR(0x0);
NF_ADDR(page&0xff);
NF_ADDR((page>>8)&0xff);
NF_ADDR((page>>16)&0xff);
NF_CMD(CMD_READ2);
NF_DETECT_RB();
for (i = 0; i < 2048; i++)
{
buffer[i] = NF_RDDATA8();
}
NF_nFCE_H();
}
int nand_read(int start_page, int read_pages, unsigned char *buffer)
{
int i;
Nand_Init();
for(i=0; i<read_pages; i++)
{
Nand_ReadPage(start_page, buffer + 2048*i);
start_page++;
}
return 0;
}
COBJS := micro2440.o flash.o nand_read.o
.text :
{
arch/arm/cpu/arm920t/start.o (.text)
board/samsung/micro2440/libmicro2440.o (.text)
*(.text)
}
【说明】
如果是在RAM中运行,一定要删去board/samsung/micro2440/libmicro2440.o (.text),否则在RAM中也不能运行。原因尚不理解,需要阅读代码。
下面红色部分是添加的部分,黑色的代码用于定位。
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
bl cpu_init_crit
#endif
#ifdef CONFIG_S3C2440_NAND_BOOT
ldr sp, =0x30008000
ldr r0, =0x0;
ldr r1, _end_ofs
mov r1, r1, LSR #11
add r1, r1, #1
ldr r2, =(CONFIG_SYS_TEXT_BASE)
bl nand_read
ldr pc, =relocations
#endif
......
......
copy_loop:
ldmia r0!, {r9-r10} /* copy from source address [r0] */
stmia r1!, {r9-r10} /* copy to target address [r1] */
cmp r0, r2 /* until source end address [r2] */
blo copy_loop
#ifdef CONFIG_S3C2440_NAND_BOOT
relocations:
ldr r6, =CONFIG_SYS_TEXT_BASE
#endif
#ifndef CONFIG_PRELOADER
/*
* fix .rel.dyn relocations
*/
......
......
clbss_l:str r2, [r0] /* clear loop... */
add r0, r0, #4
cmp r0, r1
bne clbss_l
bl coloured_LED_init
bl red_LED_on
#endif
#ifdef CONFIG_S3C2440_NAND_BOOT
ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)
bic sp, sp, #7 /* 8-byte alignment for ABI compliance */
ldr r0,=0x00000000
ldr pc, =board_init_f
#endif
/*
* We are done. Do not return, instead branch to second part of board
* initialization, now running from RAM.
*/
#ifdef CONFIG_NAND_SPL
#define CONFIG_S3C2440_NAND_BOOT /* #define CONFIG_SKIP_LOWLEVEL_INIT */
【说明】
由于要在Nand Flash中运行,所以需要注释掉#define CONFIG_SKIP_LOWLEVEL_INIT
void board_init_f (ulong bootflag)
{
......
gd->mon_len = _bss_end_ofs + 0x100000; /* why */
......
这里的修改参考了bscbem的日志:http://my.chinaunix.net/space.php?uid=24319701&do=blog&id=136249 如果有读者想了解原理请参考这个日志。
/* relocate_code (addr_sp, id, addr); */ #ifdef CONFIG_S3C2440_NAND_BOOT /*add by wzc*/ __asm__ __volatile__("mov sp,%0"::"r"(addr_sp):"sp");/*add by wzc*/ board_init_r(id, addr); #else relocate_code (addr_sp, id, addr); /* NOTREACHED - relocate_code() does not return */ #endif }【说明】至于gd->mon_len = _bss_end_ofs + 0x100000;我也不理解,需要阅读源代码才能解释。
到这里应该就可以从Nand Flash启动了。