U-Boot2010.06移植(2440)-----移植NandFlash驱动

来源:互联网 发布:天猫的网络教育真的吗 编辑:程序博客网 时间:2024/06/08 00:55

1、修改include/configs/smdk2440.h

(1)添加Nand的定义:
/*NAND flash settings*/ 
#define CONFIG_CMD_NAND
#if defined(CONFIG_CMD_NAND)
#define CONFIG_NAND_S3C2440
#define CONFIG_SYS_NAND_BASE 0x4E000000 //Nand配置寄存器基地址,nand.c要用到
#define CONFIG_SYS_MAX_NAND_DEVICE 1 //nand个数,nand.c要用到
#endif



2、修改arch/arm/include/asm/arch-s3c24x0/s3c24x0.h(CPU寄存器声明)

(1)添加2440Nand控制器寄存器声明
struct s3c2440_nand { 
u32 NFCONF; 
u32 NFCONT; 
u32 NFCMMD; 
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; 
};



3、在arch/arm/include/asm/arch-s3c24x0/目录中复制s3c2410.h为s3c2440.h,替换内容中s3c2410为s3c2440,替换内容中S3C2410为S3C2440(注意大小写)


4、修改arch/arm/include/asm/arch-s3c24x0/s3c24x0_cpu.h

(1)添加s3c2440.h头文件
#ifdef CONFIG_S3C2400
#include <asm/arch/s3c2400.h>
#elif defined CONFIG_S3C2410
#include <asm/arch/s3c2410.h>
#elif defined CONFIG_S3C2440
#include <asm/arch/s3c2440.h>

#else



5、在drivers/mtd/nand目录中新增s3c2440_nand.c(参照s3c2410_nand.c修改)

(1)文件内容如下:
#include <common.h>#include <nand.h>#include <asm/arch/s3c24x0_cpu.h>#include <asm/io.h>//NFCONF和NFCONT寄存器配置宏#define S3C2440_NFCONF_TACLS(x)    ((x)<<12)#define S3C2440_NFCONF_TWRPH0(x)   ((x)<<8)#define S3C2440_NFCONF_TWRPH1(x)   ((x)<<4)#define S3C2440_NFCONT_SECCL (1<<6)#define S3C2440_NFCONT_MECCL (1<<5)#define S3C2440_NFCONT_INITECC (1<<4)#define S3C2440_NFCONT_nCE (1<<1)#define S3C2440_NFCONT_MODE (1<<0)#define S3C2440_ADDR_NALE 0x08#define S3C2440_ADDR_NCLE 0x0c#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);}#endifstatic void s3c2440_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl){struct nand_chip *chip = mtd->priv;struct s3c2440_nand *nand = s3c2440_get_base_nand();   //获取Nand控制器的寄存器结构体debugX(1, "hwcontrol(): 0x%02x 0x%02x\n", cmd, ctrl);if (ctrl & NAND_CTRL_CHANGE) {ulong IO_ADDR_W = (ulong)nand;    //NAND控制寄存器基地址if (!(ctrl & NAND_CLE))   //要写的是地址IO_ADDR_W |= S3C2440_ADDR_NCLE;  if (!(ctrl & NAND_ALE))//要写的是命令IO_ADDR_W |= S3C2440_ADDR_NALE;if (cmd == NAND_CMD_NONE)IO_ADDR_W = &nand->NFDATA;//在写完命令和地址后,一定还要把IO端口的地址重新设置为寄存器NFDATAchip->IO_ADDR_W = (void *)IO_ADDR_W;if (ctrl & NAND_NCE)writel(readl(&nand->NFCONF) & ~S3C2440_NFCONT_nCE,      &nand->NFCONF);     //使能nand flashelsewritel(readl(&nand->NFCONF) | S3C2440_NFCONT_nCE,      &nand->NFCONF);     //禁止nand flash}if (cmd != NAND_CMD_NONE)writeb(cmd, chip->IO_ADDR_W);}static int s3c2440_dev_ready(struct mtd_info *mtd){struct s3c2440_nand *nand = s3c2440_get_base_nand();debugX(1, "dev_ready\n");return readl(&nand->NFSTAT) & 0x01;}#ifdef CONFIG_S3C2440_NAND_HWECCvoid s3c2410_nand_enable_hwecc(struct mtd_info *mtd, int mode){struct s3c2440_nand *nand = s3c2440_get_base_nand();debugX(1, "s3c2440_nand_enable_hwecc(%p, %d)\n", mtd, mode);writel(readl(&nand->NFCONT) | S3C2440_NFCONT_INITECC, &nand->NFCONT);}static int s3c2440_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,     u_char *ecc_code){struct s3c2440_nand *nand = s3c2440_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, "s3c2440_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 s3c2440_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("s3c2440_nand_correct_data: not implemented\n");return -1;}#endifint 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 s3c2440_nand *nand_reg = s3c2440_get_base_nand();debugX(1, "board_nand_init()\n");writel(readl(&clk_power->CLKCON) | (1 << 4), &clk_power->CLKCON);/* initialize hardware */twrph0 = 2;twrph1 = 1;tacls = 0;cfg = 0;cfg |= S3C2440_NFCONF_TACLS(tacls);cfg |= S3C2440_NFCONF_TWRPH0(twrph0);cfg |= S3C2440_NFCONF_TWRPH1(twrph1);writel(cfg, &nand_reg->NFCONF);  //配置NFCONFcfg = S3C2440_NFCONT_SECCL;cfg |= S3C2440_NFCONT_MECCL;cfg |= S3C2440_NFCONT_INITECC;cfg |= S3C2440_NFCONT_MODE;writel(cfg, &nand_reg->NFCONT);  //配置NFCONT/* initialize nand_chip data structure */nand->IO_ADDR_R = nand->IO_ADDR_W = (void *)&nand_reg->NFDATA;nand->select_chip = NULL;/* read_buf and write_buf are default *//* read_byte and write_byte are default */#ifdef CONFIG_NAND_SPLnand->read_buf = nand_read_buf;#endif/* hwcontrol always must be implemented */nand->cmd_ctrl = s3c2440_hwcontrol;nand->dev_ready = s3c2440_dev_ready;#ifdef CONFIG_S3C2410_NAND_HWECCnand->ecc.hwctl = s3c2440_nand_enable_hwecc;nand->ecc.calculate = s3c2440_nand_calculate_ecc;nand->ecc.correct = s3c2440_nand_correct_data;nand->ecc.mode = NAND_ECC_HW;nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE;nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES;#elsenand->ecc.mode = NAND_ECC_SOFT;#endif#ifdef CONFIG_S3C2440_NAND_BBTnand->options = NAND_USE_FLASH_BBT;#elsenand->options = 0;#endifdebugX(1, "end of nand_init\n");return 0;}



6、修改drivers/mtd/nand/目录下Makefile

(1)添加编译选项:
COBJS-$(CONFIG_NAND_S3C2410) += s3c2410_nand.o
COBJS-$(CONFIG_NAND_S3C2440) += s3c2440_nand.o
COBJS-$(CONFIG_NAND_S3C64XX) += s3c64xx.o



7、修改include/configs/smdk2440.h

(1)定义环境变量存放位置的宏
#define CONFIG_ENV_IS_IN_NAND 1    //common目录Makefile,连接时要用

8、修改arch/arm/cpu/arm920t/start.S

(1)判断是Nor启动还是Nand启动,在relocate:/*relocate U-Boot to RAM*/后面添加:

/***************** CHECK_BOOT_FLASH **************************************/ldr r1, =0x4000003C/* address of Internal SRAM 0x4000003C*/mov r0, #0 /* r0 = 0 */str r0, [r1]mov r1, #0x3c /* address of 0x0000003C*/ldr r0, [r1]cmp r0, #0 /*判断0x0000003C所指向的4个字节是否被清0*/bne norboot /*没有被清0,就是在Nor Flash中启动,则跳到Nor Flash的启动代码处norboot*//***************** CHECK_BOOT_FLASH *********************************//***************** NAND_BOOT *************************************************/nandboot:/* recovery */ldr r0, =0xdeadbeef /*被清0,就是在Nand Flash中启动*/ldr r1, =0x4000003C /*恢复0x4000003C指向的4字节的数据0xdeadbeef*/str r0, [r1]#define LENGTH_UBOOT 0x100000#define NAND_CTL_BASE 0x4E000000#ifdef CONFIG_S3C2440/* Offset */#define oNFCONF 0x00#define oNFCONT 0x04#define oNFCMD 0x08#define oNFSTAT 0x20@ reset NANDmov r1, #NAND_CTL_BASEldr r2, =( (2<<12)|(1<<8)|(0<<4)|(0<<0) )str r2, [r1, #oNFCONF]ldr r2, [r1, #oNFCONF]ldr r2, =( (1<<4)|(0<<1)|(1<<0) ) @ Active low CE Controlstr r2, [r1, #oNFCONT]ldr r2, [r1, #oNFCONT]ldr r2, =(0x6) @ RnB Clearstr r2, [r1, #oNFSTAT]ldr r2, [r1, #oNFSTAT]mov r2, #0xff @ RESET commandstrb r2, [r1, #oNFCMD]mov r3, #0 @ waitnand1:add r3, r3, #0x1cmp r3, #0xablt nand1nand2:ldr r2, [r1, #oNFSTAT] @ wait readytst r2, #0x4beq nand2ldr r2, [r1, #oNFCONT]orr r2, r2, #0x2 @ Flash Memory Chip Disablestr r2, [r1, #oNFCONT]@ get read to call C functions (for nand_read())ldr sp, DW_STACK_START @ setup stack pointermov fp, #0 @ no previous frame, so fp=0@ copy U-Boot to RAMldr r0, =TEXT_BASEmov r1, #0x0mov r2, #LENGTH_UBOOTbl nand_read_lltst r0, #0x0beq ok_nand_readbad_nand_read:loop2:b loop2 @ infinite loopok_nand_read:@ verifymov r0, #0ldr r1, =TEXT_BASEmov r2, #0x400 @ 4 bytes * 1024 = 4K-bytesgo_next:ldr r3, [r0], #4ldr r4, [r1], #4teq r3, r4bne notmatchsubs r2, r2, #4beq stack_setupbne go_nextnotmatch:loop3:b loop3 @ infinite loop#endif/***************** NAND_BOOT *************************************************//***************** NOR_BOOT *************************************************/norboot: /*********** CHECK_FOR_MAGIC_NUMBER***************/ldr r1, =0xdeadbeefcmp r0, r1bne loop3/*********** CHECK_FOR_MAGIC_NUMBER***************/
(2)添加nandboot中DW_STACK_START的定义:
_start_armboot: .word start_armboot
#define STACK_BASE 0x33f00000
#define STACK_SIZE 0x10000
.align 2
DW_STACK_START: .wordSTACK_BASE+STACK_SIZE-4


9、在board/samsung/smdk2440文件夹中创建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 <hwang@mizi.com>*Date : $Date: 2004/02/04 10:37:37 $**u-boot integration and bad-block skipping (C) 2006 by OpenMoko, Inc.*Author: Harald Welte <laforge@openmoko.org>*/#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 + 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))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;};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();for (i = 0; i < (nand->page_size>>1); i++) {*ptr16 = NFDATA16;ptr16++;}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_BADif (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;}}#endifj = nand_read_page_ll(&nand, buf, i);i += j;buf += j;}/* chip Disable */nand_deselect();return 0;}

10、修改board/samsung/smdk2440目录下Makefile文件,加入对它的编译选项支持

COBJS :=smdk2440.o flash.o nand_read.o


11、修改arch/arm/cpu/arm920t/u-boot.lds文件

(1)添加nand_read.o到4K地址之内
arch/arm/cpu/arm920t/start.o (.text) 
board/samsung/smdk2440/lowlevel_init.o (.text)
board/samsung/smdk2440/nand_read.o (.text)
0 0