您的位置:首页 > 其它

u-boot-2010-06在mini2440上的移植(四)

2011-03-17 09:02 435 查看
四.添加对Nand Flash的支持4.1 支持u-boot从Nand flash启动目前u-boot中还没有对2440上Nand Flash的支持,也就是说要想u-boot从Nand Flash上启动得自己去实现了。首先,在include/configs/mini2440.h头文件中定义Nand要用到的宏和寄存器,如下:
#gedit include/configs/my2440.h //在文件末尾加入以下Nand Flash相关定义
/* * Nand flash register and envionment variables */#define CONFIG_S3C2440_NAND_BOOT 1#define NAND_CTL_BASE 0x4E000000 //Nand Flash配置寄存器基地址,查2440手册可得知#define bINT_CTL(Nb) __REG(INT_CTL_BASE+(Nb))#define UBOOT_RAM_BASE 0x33f80000#define STACK_BASE 0x33F00000 //定义堆栈的地址#define STACK_SIZE 0x8000 //堆栈的长度大小
其次,修改cpu/arm920t/start.S这个文件,使u-boot从Nand Flash启动,在上一节中提过,u-boot默认是从Nor Flash启动的。修改部分如下:
#gedit cpu/arm920t/start.S
/*注意:在上一篇Nor Flash启动中,我们为了把u-boot用supervivi下载到内存中运行而屏蔽掉这段有关CPU初始化的代码。而现在我们要把u-boot下载到Nand Flash中,从Nand Flash启动,所以现在要恢复这段代码。*/#ifndef CONFIG_SKIP_LOWLEVEL_INIT bl cpu_init_crit#endif #if 0 //屏蔽掉u-boot中的从Nor Flash启动部分#ifndef CONFIG_SKIP_RELOCATE_UBOOTrelocate: /* 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 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 */#endif //下面添加2440中u-boot从Nand Flash启动 #ifdef CONFIG_S3C2440_NAND_BOOT#define oNFCONF 0x00#define oNFCONT 0x04#define oNFCMD 0x08#define oNFSTAT 0x20#define LENGTH_UBOOT 0x60000 mov r1, #NAND_CTL_BASE //复位Nand Flash ldr r2, =( (7<<12)|(7<<8)|(7<<4)|(0<<0) ) str r2, [r1, #oNFCONF] //设置配置寄存器的初始值,参考s3c2440手册 ldr r2, [r1, #oNFCONF] ldr r2, =( (1<<4)|(0<<1)|(1<<0) ) str r2, [r1, #oNFCONT] //设置控制寄存器 ldr r2, [r1, #oNFCONT] ldr r2, =(0x6) //RnB Clear str r2, [r1, #oNFSTAT]ldr r2, [r1, #oNFSTAT] mov r2, #0xff //复位command strb r2, [r1, #oNFCMD] mov r3, #0 //等待nand1: add r3, r3, #0x1 cmp r3, #0xa blt nand1nand2: ldr r2, [r1, #oNFSTAT] //等待就绪 tst r2, #0x4 beq nand2 ldr r2, [r1, #oNFCONT] orr r2, r2, #0x2 //取消片选 str r2, [r1, #oNFCONT] //get read to call C functions (for nand_read()) ldr sp, DW_STACK_START //为C代码准备堆栈,DW_STACK_START定义在下面 mov fp, #0 //copy U-Boot to RAM ldr r0, =TEXT_BASE//传递给C代码的第一个参数:u-boot在RAM中的起始地址 mov r1, #0x0 //传递给C代码的第二个参数:Nand Flash的起始地址 mov r2, # LENGTH_UBOOT //传递给C代码的第三个参数:u-boot的长度大小(128k) bl nand_read_ll //此处调用C代码中读Nand的函数,现在还没有要自己编写实现 tst r0, #0x0 beq ok_nand_readbad_nand_read: loop2: b loop2 //infinite loopok_nand_read: //检查搬移后的数据,如果前4k完全相同,表示搬移成功 mov r0, #0 ldr r1, =TEXT_BASE mov r2, #0x400 //4 bytes * 1024 = 4K-bytesgo_next: ldr r3, [r0], #4 ldr r4, [r1], #4 teq r3, r4 bne notmatch subs r2, r2, #4 beq stack_setup bne go_nextnotmatch: loop3: b loop3 //infinite loop#endif //CONFIG_S3C2440_NAND_BOOT _start_armboot: .word start_armboot //在这一句的下面加上DW_STACK_START的定义 .align 2DW_STACK_START: .word STACK_BASE+STACK_SIZE-4
再次,在board/samsung/mini2440/目录下新建一个nand_read.c文件,在该文件中来实现上面汇编中要调用的nand_read_ll函数,代码如下:
#gedit board/samsung/mini2440/nand_read.c //新建一个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#if defined(CONFIG_S3C2410) && !define (CONFIG_S3C2440)#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_S3C2440) || defined(CONFIG_S3C2442)#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))#endifstatic 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;};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_S3C2410)&& !define (CONFIG_S3C2440) for (i = 0; i < nand->page_size; i++) { *buf = (NFDATA & 0xff); buf++; }#elif defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442) 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 HY27US08121A*/ nand.page_size = 512; nand.block_size = 16 * 1024; nand.bad_block_offset = 5; // nand.size = 0x4000000; } else if (nand_id == 0xecf1 || /* Samsung K9F1G08U0B */ nand_id == 0xecda || /* Samsung K9F2G08U0B */ nand_id == 0xecd3 ) { /* Samsung K9K8G08 */ 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_S3C2410_NAND_SKIP_BAD 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;}
然后,在board/samsung/mini2440/Makefile中添加nand_read.c的编译选项,使他编译到u-boot中,如下:
COBJS := mini2440.o flash.o nand_read.o
还有一个重要的地方要修改,在cpu/arm920t/u-boot.lds中,这个u-boot启动连接脚本文件决定了u-boot运行的入口地址,以及各个段的存储位置,这也是链接定位的作用。添加下面两行代码的主要目的是防止编译器把我们自己添加的用于nandboot的子函数放到4K之后,否则是无法启动的。如下:
.text :{ cpu/arm920t/start.o (.text) board/samsung/mini2440/lowlevel_init.o (.text) board/samsung/mini440/nand_read.o (.text) *(.text)}
最后编译u-boot,生成u-boot.bin文件。然后先将mini2440开发板调到Nor启动档,利用supervivi的a命令将u-boot.bin下载到开发板的Nand Flash中,再把开发板调到Nand启动档,打开电源就从Nand Flash启动了。 4.2 添加Nand Flash(K9F2g08U0C)的有关操作支持在上一节中我们说过,通常在嵌入式bootloader中,有两种方式来引导启动内核:从Nor Flash启动和从Nand Flash启动,但不管是从Nor启动或者从Nand启动,进入第二阶段以后,两者的执行流程是相同的。现在的u-boot-2010-06版本对Nand的初始化、读写实现是基于最近的Linux内核的MTD架构,删除了以前传统的执行方法,使移植没有以前那样复杂了,实现Nand的操作和基本命令都直接在drivers/mtd/nand目录下(在doc/README.nand中讲得很清楚)。下面我们结合代码来分析一下u-boot在第二阶段的执行流程:
1.lib_arm/board.c文件中的start_armboot函数调用了drivers/mtd/nand/nand.c文件中的nand_init函数,如下: #if defined(CONFIG_CMD_NAND) //可以看到CONFIG_CMD_NAND宏决定了Nand的初始化 puts ("NAND: "); nand_init(); #endif2.nand_init调用了同文件下的nand_init_chip函数;3.nand_init_chip函数调用drivers/mtd/nand/s3c2410_nand.c文件下的board_nand_init函数,然后再调用drivers/mtd/nand/nand_base.c函数中的nand_scan函数;4.nand_scan函数调用了同文件下的nand_scan_ident函数等。
我们在u-boot提供的关于S3C2410的nand_flash驱动文件的基础上添加相关代码以支持S3C2440.
#gedit driver/mtd/nand/s3c2410_nand.c
#include <common.h>#include <nand.h>#include <asm/arch-s3c24x0/s3c24x0_cpu.h> #include <asm/io.h>#define NF_BASE 0x4e000000 #if defined(CONFIG_S3C2410)&&!define(CONFIG_S3C2440)#define S3C2410_NFCONF_EN (1<<15)#define S3C2410_NFCONF_512BYTE (1<<14)#define S3C2410_NFCONF_4STEP (1<<13)#define S3C2410_NFCONF_INITECC (1<<12)#define S3C2410_NFCONF_nFCE (1<<11)#define S3C2410_NFCONF_TACLS(x) ((x)<<8)#define S3C2410_NFCONF_TWRPH0(x) ((x)<<4)#define S3C2410_NFCONF_TWRPH1(x) ((x)<<0) #define S3C2410_ADDR_NALE 4#define S3C2410_ADDR_NCLE 8#endif #if defined(CONFIG_S3C2440)#define S3C2410_NFCONT_EN (1<<0)#define S3C2410_NFCONT_INITECC (1<<4)#define S3C2410_NFCONT_nFCE (1<<1)#define S3C2410_NFCONT_MAINECCLOCK (1<<5)#define S3C2410_NFCONF_TACLS(x) ((x)<<12)#define S3C2410_NFCONF_TWRPH0(x) ((x)<<8)#define S3C2410_NFCONF_TWRPH1(x) ((x)<<4)#define S3C2410_ADDR_NALE 0x08#define S3C2410_ADDR_NCLE 0x0c#endifulong IO_ADDR_W = NF_BASE;#ifdef CONFIG_NAND_SPL/* in the early stage of NAND flash booting, printf() is not available */#define printf(fmt, args...)static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len){ int i; struct nand_chip *this = mtd->priv; for (i = 0; i < len; i++) buf[i] = readb(this->IO_ADDR_R);}#endif static void s3c2410_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl){// struct nand_chip *chip = mtd->priv; struct s3c2410_nand *nand = s3c2410_get_base_nand(); debugX(1, "hwcontrol(): 0x%02x 0x%02x/n", cmd, ctrl); if (ctrl & NAND_CTRL_CHANGE) { // ulong IO_ADDR_W = (ulong) nand; IO_ADDR_W = (ulong)nand; if (!(ctrl & NAND_CLE)) IO_ADDR_W |= S3C2410_ADDR_NCLE; if (!(ctrl & NAND_ALE)) IO_ADDR_W |= S3C2410_ADDR_NALE; // chip->IO_ADDR_W = (void *)IO_ADDR_W; #if defined(CONFIG_S3C2410)&& !define(CONFIG_S3C2440) if (ctrl & NAND_NCE) writel(readl(&nand->NFCONF) & ~S3C2410_NFCONF_nFCE, &nand->NFCONF); else writel(readl(&nand->NFCONF) | S3C2410_NFCONF_nFCE, &nand->NFCONF); }#endif#if defined(CONFIG_S3C2440) if (ctrl & NAND_NCE) writel(readl(&nand->NFCONT) & ~S3C2410_NFCONT_nFCE, &nand->NFCONT); else writel(readl(&nand->NFCONT) | S3C2410_NFCONT_nFCE, &nand->NFCONT); }#endif if (cmd != NAND_CMD_NONE) // writeb(cmd, chip->IO_ADDR_W); writeb(cmd, (void *)IO_ADDR_W);}static int s3c2410_dev_ready(struct mtd_info *mtd){ struct s3c2410_nand *nand = s3c2410_get_base_nand(); debugX(1, "dev_ready/n"); return readl(&nand->NFSTAT) & 0x01;} #ifdef CONFIG_S3C2410_NAND_HWECCvoid s3c2410_nand_enable_hwecc(struct mtd_info *mtd, int mode){ struct s3c2410_nand *nand = s3c2410_get_base_nand(); debugX(1, "s3c2410_nand_enable_hwecc(%p, %d)/n", mtd, mode);#if defined(CONFIG_S3C2410)&& !define(CONFIG_S3C2440) writel(readl(&nand->NFCONF) | S3C2410_NFCONF_INITECC, &nand->NFCONF);#endif #if defined(CONFIG_S3C2440) writel(readl(&nand->NFCONT) | S3C2410_NFCONT_INITECC, &nand->NFCONT);#endif} static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code){ struct s3c2410_nand *nand = s3c2410_get_base_nand(); ecc_code[0] = readb(&nand->NFECC); ecc_code[1] = readb(&nand->NFECC + 1); ecc_code[2] = readb(&nand->NFECC + 2); debugX(1, "s3c2410_nand_calculate_hwecc(%p,): 0x%02x 0x%02x 0x%02x/n", mtd , ecc_code[0], ecc_code[1], ecc_code[2]); return 0;} static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc){ if (read_ecc[0] == calc_ecc[0] && read_ecc[1] == calc_ecc[1] && read_ecc[2] == calc_ecc[2]) return 0; printf("s3c2410_nand_correct_data: not implemented/n"); return -1;}#endif int board_nand_init(struct nand_chip *nand){ u_int32_t cfg; u_int8_t tacls, twrph0, twrph1; struct s3c24x0_clock_power *clk_power = s3c24x0_get_base_clock_power(); struct s3c2410_nand *nand_reg = s3c2410_get_base_nand(); debugX(1, "board_nand_init()/n"); writel(readl(&clk_power->CLKCON) | (1 << 4), &clk_power->CLKCON); #if defined(CONFIG_S3C2410)&& !define(CONFIG_S3C2440) /* initialize hardware */ twrph0 = 3; twrph1 = 0; tacls = 0; cfg = S3C2410_NFCONF_EN; cfg |= S3C2410_NFCONF_TACLS(tacls - 1); cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1); cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1); writel(cfg, &nand_reg->NFCONF); /* initialize nand_chip data structure */ nand->IO_ADDR_R = nand->IO_ADDR_W = (void *)&nand_reg->NFDATA;#endif#if defined(CONFIG_S3C2440) twrph0 = 4; twrph1 = 2; tacls = 0; cfg = 0; cfg |= S3C2410_NFCONF_TACLS(tacls - 1); cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1); cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1); writel(cfg, &nand_reg->NFCONF); cfg = (0<<13)|(0<<12)|(0<<10)|(0<<9)|(0<<8)|(0<<6)|(0<<5)|(1<<4)|(0<<1)|(1<<0); writel(cfg, &nand_reg->NFCONT); /* initialize nand_chip data structure */ nand->IO_ADDR_R = nand->IO_ADDR_W = (void *)&nand_reg->NFDATA;#endif nand->select_chip = NULL; /* read_buf and write_buf are default */ /* read_byte and write_byte are default */#ifdef CONFIG_NAND_SPL nand->read_buf = nand_read_buf;#endif /* hwcontrol always must be implemented */ nand->cmd_ctrl = s3c2410_hwcontrol; nand->dev_ready = s3c2410_dev_ready; #ifdef CONFIG_S3C2410_NAND_HWECC nand->ecc.hwctl = s3c2410_nand_enable_hwecc; nand->ecc.calculate = s3c2410_nand_calculate_ecc; nand->ecc.correct = s3c2410_nand_correct_data; nand->ecc.mode = NAND_ECC_HW; nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE; nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES;#else nand->ecc.mode = NAND_ECC_SOFT;#endif #ifdef CONFIG_S3C2410_NAND_BBT nand->options = NAND_USE_FLASH_BBT;#else nand->options = 0;#endif debugX(1, "end of nand_init/n"); return 0;}
在s3c24x0.h里添加S3C2440相关nand_flash的结构体,修改代码如下:
#gedit include/asm/arch-s3c24x0/s3c24x0.h
#if defined(CONFIG_S3C2440)struct s3c2410_nand { u32 NFCONF; u32 NFCONT; u32 NFCMD; u32 NFADDR; u32 NFDATA; u32 NFMECCD0; u32 NFMECCD1; u32 NFSECCD; u32 NFSTAT; u32 NFESTAT0; u32 NFESTAT1; u32 NFMECC0; u32 NFMECC1; u32 NFSECC; u32 NFSBLK; u32 NFEBLK; };#endif#if defined(CONFIG_S3C2410)&& !define(CONFIG_S3C2440)/* NAND FLASH (see S3C2410 manual chapter 6) */struct s3c2410_nand { u32 NFCONF; u32 NFCMD; u32 NFADDR; u32 NFDATA; u32 NFSTAT; u32 NFECC;};#endif
在mini2440.h里添加nand_flash相关宏定义
#gedit include/configs/mini2440.h
#define CONFIG_CMD_NAND/* NAND flash settings */ #if defined(CONFIG_CMD_NAND) #define CONFIG_NAND_S3C2410#define CONFIG_SYS_NAND_BASE 0x4E000000 //Nand配置寄存器基地址 #define CONFIG_SYS_MAX_NAND_DEVICE 1 #define CONFIG_MTD_NAND_VERIFY_WRITE 1 //#define NAND_SAMSUNG_LP_OPTIONS 1 //注意:我们这里是M的Nand Flash,所以不、//用,如果是M的大块Nand Flash,则需加上 #endif
在mini2440.h里添加saveenv命令的支持
#gedit include/configs/mini2440.h
//#define CONFIG_ENV_IS_IN_FLASH 1 /*屏蔽Nor Flash saveenv相关宏定义*///#define CONFIG_ENV_SIZE 0x10000 /* Total Size of Environment Sector */#define CONFIG_ENV_IS_IN_NAND 1#define CONFIG_ENV_OFFSET 0x60000#define CONFIG_ENV_SIZE 0x20000#define CONFIG_CMD_SAVEENV
编译下载,从Nand Flash启动,从出现的信息看出,此时已经支持Nand Flash了:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  2010 flash struct c cmd structure