u-boot for tiny210 ver2.2(by liukun321咕唧咕唧)
前三个版本都不支持nandflash的读写,这次更新(ver2.2)添加了nandflash驱动及yaffs文件系统的烧写功能。在kasim的建议下我从ver2.2开始用git源代码仓库管理我的源码。并发布上一版本的补丁文件。 Git source u-boot for tiny210 ver2.2 下面的提供了在CSDN资源库的下载链接: ver2.2源码下载:? u-boot for tiny210 ver2.2 下面的提供了补丁包的下载链接: ver2.2补丁下载:?u-boot-for-tiny210-patch-ver2.2 下面的链接提供了前几次修改的源码: ver1.0源码下载:u-boot for tiny210 ver1.0 你还可以参考下三篇blog从头构建自己的u-boot for tiny210 ver1.0?? ver2.0? ?ver2.1? ? ver2.2的基本功能: 1. SD boot,基于linaro u-boot的SPL功能实现 2. 从SD卡的FAT分区上加载文件到SDRAM 3. 将环境变量保存至SD卡 4. 添加DM9000网卡驱动,开启网络功能(例如:tftp,nfs等) 5. 添加TAB键命令自动补全功能 6.修复bug: 修复bug 1:SD卡保存环境变量出现Writing to MMC(0)... mmc_send_cmd: error during transfer: 0x00208001 mmc write failed。 修复bug 2:每次启动只能保存一次环境变量。 +7.添加NandFlash驱动,开启所有Nand cmd。 +8.添加Yaffs文件系统烧写支持。 ? ? 参照本文后面内容修改完后:
编译u-boot
$make ARCH=arm CROSS_COMPILE=/opt/FriendlyARM/toolschain/4.5.1/bin/arm-none-linux-gnueabi- tiny210_config $make ARCH=arm CROSS_COMPILE=/opt/FriendlyARM/toolschain/4.5.1/bin/arm-none-linux-gnueabi- all spl 由于我的系统下装有两套交叉工具链,所以没有把 ?/opt/FriendlyARM/toolschain/4.5.1/bin/?添加到环境变量,在使用工具链时要指明路径。
将u-boot镜像写入SD卡
将SD卡通过读卡器接上电脑(或直接插入笔记本卡槽),通过"cat /proc/partitions"找出SD卡对应的设备,我的设备节点是/dev/sdb. 执行下面的命令 $sudo dd iflag=dsync oflag=dsync if=spl/tiny210-spl.bin of=/dev/sdb seek=1 $sudo dd iflag=dsync oflag=dsync if=u-boot.bin of=/dev/sdb??seek=49
?
?
将SD卡插入开发板启动:
? ? 启动: ? 部分NAND CMD测试: ? ? 下面简要介绍ver2.2的修改步骤: 左边的数字为旧行号,右边的数字为新行号,大家可以对应行号阅读修改部分的源码,或自己从ver2.1修改至ver2.2 1.tiny210-u-boot-version2.1/board/samsung/tiny210/Makefile 在此目录下修改Makefile
(
4 /
0)
?
?
2.??tiny210-u-boot-version2.1/drivers/mtd/nand/nand.c
?
?
3.tiny210-u-boot-version2.1/include/configs/tiny210.h
修改此目录下的tiny210.h?(33 /0)
?
?
4.tiny210-u-boot-version2.1/include/linux/mtd/mtd-abi.h
修改此目录下的mtd-abi.h(2 /0)
?
5.在
tiny210-u-boot-version2.1/board/samsung/tiny210/
?目录下添加nand.c nand_cp.c(本版本未启用nand_cp.c文件)。nand.c文件内容如下:
#include <common.h> #if defined(CONFIG_CMD_NAND) #include <nand.h> #include <bedbug/regs.h> #include <s5pc110.h> #include <asm/io.h> #include <asm/errno.h> /* Nand flash definition values by jsgood */ #define S3C_NAND_TYPE_UNKNOWN 0x0 #define S3C_NAND_TYPE_SLC 0x1 #define S3C_NAND_TYPE_MLC 0x2 #undef S3C_NAND_DEBUG /* Nand flash global values by jsgood */ int cur_ecc_mode = 0; int nand_type = S3C_NAND_TYPE_UNKNOWN; /* Nand flash oob definition for SLC 512b page size by jsgood */ static struct nand_ecclayout s3c_nand_oob_16 = { .useecc = MTD_NANDECC_AUTOPLACE,/* Only for U-Boot */ .eccbytes = 4,.eccpos = {1,2,3,4},.oobfree = { {.offset = 6,. length = 10}} }; /* Nand flash oob definition for SLC 2k page size by jsgood */ static struct nand_ecclayout s3c_nand_oob_64 = { .useecc = MTD_NANDECC_AUTOPLACE,/* Only for U-Boot */ .eccbytes = 16,.eccpos = {40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55},.oobfree = { {.offset = 2,.length = 38}} }; /* Nand flash oob definition for MLC 2k page size by jsgood */ static struct nand_ecclayout s3c_nand_oob_mlc_64 = { .useecc = MTD_NANDECC_AUTOPLACE,/* Only for U-Boot */ .eccbytes = 32,.eccpos = { 32,33,34,35,36,37,38,39,40,55,56,57,58,59,60,61,62,63},.length = 28}} }; /* Nand flash oob definition for 4Kb page size with 8_bit ECC */ static struct nand_ecclayout s3c_nand_oob_128 = { .useecc = MTD_NANDECC_AUTOPLACE,.eccbytes = 104,.eccpos = { 24,25,26,27,28,29,30,31,32,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127},.oobfree = { {.offset = 2,.length = 22}} }; #if defined(S3C_NAND_DEBUG) /* * Function to print out oob buffer for debugging * Written by jsgood */ static void print_oob(const char *header,struct mtd_info *mtd) { int i; struct nand_chip *chip = mtd->priv; printk("%s:t",header); for(i = 0; i < 64; i++) printk("%02x ",chip->oob_poi[i]); printk("n"); } #endif /* * Hardware specific access to control-lines function * Written by jsgood */ static void s3c_nand_hwcontrol(struct mtd_info *mtd,int dat,unsigned int ctrl) { unsigned int cur; #if 1 if (ctrl & NAND_CTRL_CHANGE) { if (ctrl & NAND_NCE) { if (dat != NAND_CMD_NONE) { cur = readl(NFCONT); /* Forced Enable CS */ cur &= ~NFCONT_CS; writel(cur,NFCONT); } } else { cur = readl(NFCONT); /* Forced Enable CS */ cur |= NFCONT_CS; writel(cur,NFCONT); } } if (dat != NAND_CMD_NONE) { if (ctrl & NAND_CLE) writeb(dat,NFCMMD); else if (ctrl & NAND_ALE) writeb(dat,NFADDR); } #endif } /* * Function for checking device ready pin * Written by jsgood */ static int s3c_nand_device_ready(struct mtd_info *mtdinfo) { while (!(readl(NFSTAT) & NFSTAT_RnB)) {} return 1; } /* * We don't use bad block table */ static int s3c_nand_scan_bbt(struct mtd_info *mtdinfo) { return nand_default_bbt(mtdinfo); } #if defined(CFG_NAND_HWECC) /* * Function for checking ECCEncDone in NFSTAT * Written by jsgood */ static void s3c_nand_wait_enc(void) { while (!(readl(NFECCSTAT) & NFSTAT_ECCENCDONE)) {} } /* * Function for checking ECCDecDone in NFSTAT * Written by jsgood */ static void s3c_nand_wait_dec(void) { while (!(readl(NFECCSTAT) & NFSTAT_ECCDECDONE)) {} } /* * Function for checking ECC Busy * Written by jsgood */ static void s3c_nand_wait_ecc_busy(void) { while (readl(NFECCSTAT) & NFESTAT0_ECCBUSY) {} } /* * This function is called before encoding ecc codes to ready ecc engine. * Written by jsgood */ static void s3c_nand_enable_hwecc(struct mtd_info *mtd,int mode) { u_long nfcont,nfconf; cur_ecc_mode = mode; nfconf = readl(NFCONF); if (nand_type == S3C_NAND_TYPE_SLC) nfconf &= ~NFCONF_ECC_MLC; /* SLC */ else nfconf |= NFCONF_ECC_MLC; /* MLC */ writel(nfconf,NFCONF); printf("NFCONF = %xn",nfconf); /* Initialize & unlock */ nfcont = readl(NFCONT); nfcont |= NFCONT_INITMECC; nfcont &= ~NFCONT_MECCLOCK; if (nand_type == S3C_NAND_TYPE_MLC) { if (mode == NAND_ECC_WRITE) nfcont |= NFCONT_ECC_ENC; else if (mode == NAND_ECC_READ) nfcont &= ~NFCONT_ECC_ENC; } writel(nfcont,NFCONT); } /* * This function is called immediately after encoding ecc codes. * This function returns encoded ecc codes. * Written by jsgood */ static int s3c_nand_calculate_ecc(struct mtd_info *mtd,const u_char *dat,u_char *ecc_code) { u_long nfcont,nfmecc0,nfmecc1; /* Lock */ nfcont = readl(NFCONT); nfcont |= NFCONT_MECCLOCK; writel(nfcont,NFCONT); if (nand_type == S3C_NAND_TYPE_SLC) { nfmecc0 = readl(NFMECC0); ecc_code[0] = nfmecc0 & 0xff; ecc_code[1] = (nfmecc0 >> 8) & 0xff; ecc_code[2] = (nfmecc0 >> 16) & 0xff; ecc_code[3] = (nfmecc0 >> 24) & 0xff; } else { if (cur_ecc_mode == NAND_ECC_READ) s3c_nand_wait_dec(); else { s3c_nand_wait_enc(); nfmecc0 = readl(NFMECC0); nfmecc1 = readl(NFMECC1); ecc_code[0] = nfmecc0 & 0xff; ecc_code[1] = (nfmecc0 >> 8) & 0xff; ecc_code[2] = (nfmecc0 >> 16) & 0xff; ecc_code[3] = (nfmecc0 >> 24) & 0xff; ecc_code[4] = nfmecc1 & 0xff; ecc_code[5] = (nfmecc1 >> 8) & 0xff; ecc_code[6] = (nfmecc1 >> 16) & 0xff; ecc_code[7] = (nfmecc1 >> 24) & 0xff; } } return 0; } /* * This function determines whether read data is good or not. * If SLC,must write ecc codes to controller before reading status bit. * If MLC,status bit is already set,so only reading is needed. * If status bit is good,return 0. * If correctable errors occured,do that. * If uncorrectable errors occured,return -1. * Written by jsgood */ static int s3c_nand_correct_data(struct mtd_info *mtd,u_char *dat,u_char *read_ecc,u_char *calc_ecc) { int ret = -1; u_long nfestat0,nfestat1,nfmeccdata0,nfmeccdata1,nfmlcbitpt; u_char err_type; if (nand_type == S3C_NAND_TYPE_SLC) { /* SLC: Write ecc to compare */ nfmeccdata0 = (read_ecc[1] << 16) | read_ecc[0]; nfmeccdata1 = (read_ecc[3] << 16) | read_ecc[2]; writel(nfmeccdata0,NFMECCDATA0); writel(nfmeccdata1,NFMECCDATA1); /* Read ecc status */ nfestat0 = readl(NFESTAT0); err_type = nfestat0 & 0x3; switch (err_type) { case 0: /* No error */ ret = 0; break; case 1: /* 1 bit error (Correctable) (nfestat0 >> 7) & 0x7ff :error byte number (nfestat0 >> 4) & 0x7 :error bit number */ printk("s3c-nand: 1 bit error detected at byte %ld,correcting from " "0x%02x ",(nfestat0 >> 7) & 0x7ff,dat[(nfestat0 >> 7) & 0x7ff]); dat[(nfestat0 >> 7) & 0x7ff] ^= (1 << ((nfestat0 >> 4) & 0x7)); printk("to 0x%02x...OKn",dat[(nfestat0 >> 7) & 0x7ff]); ret = 1; break; case 2: /* Multiple error */ case 3: /* ECC area error */ printk("s3c-nand: ECC uncorrectable error detectedn"); ret = -1; break; } } else { /* MLC: */ s3c_nand_wait_ecc_busy(); nfestat0 = readl(NFESTAT0); nfestat1 = readl(NFESTAT1); nfmlcbitpt = readl(NFMLCBITPT); err_type = (nfestat0 >> 26) & 0x7; /* No error,If free page (all 0xff) */ if ((nfestat0 >> 29) & 0x1) { err_type = 0; } else { /* No error,If all 0xff from 17th byte in oob (in case of JFFS2 format) */ if (dat) { if (dat[17] == 0xff && dat[26] == 0xff && dat[35] == 0xff && dat[44] == 0xff && dat[54] == 0xff) err_type = 0; } } switch (err_type) { case 5: /* Uncorrectable */ printk("s3c-nand: ECC uncorrectable error detectedn"); ret = -1; break; case 4: /* 4 bit error (Correctable) */ dat[(nfestat1 >> 16) & 0x3ff] ^= ((nfmlcbitpt >> 24) & 0xff); case 3: /* 3 bit error (Correctable) */ dat[nfestat1 & 0x3ff] ^= ((nfmlcbitpt >> 16) & 0xff); case 2: /* 2 bit error (Correctable) */ dat[(nfestat0 >> 16) & 0x3ff] ^= ((nfmlcbitpt >> 8) & 0xff); case 1: /* 1 bit error (Correctable) */ printk("s3c-nand: %d bit(s) error detected,corrected successfullyn",err_type); dat[nfestat0 & 0x3ff] ^= (nfmlcbitpt & 0xff); ret = err_type; break; case 0: /* No error */ ret = 0; break; } } return ret; } #if defined(CONFIG_NAND_BL1_8BIT_ECC) && defined(CONFIG_S5PC110) /*************************************************************** * jsgood: Temporary 8 Bit H/W ECC supports for BL1 (6410/6430 only) ***************************************************************/ static void s3c_nand_wait_ecc_busy_8bit(void) { while (readl(NFECCSTAT) & NFESTAT0_ECCBUSY) { } } void s3c_nand_enable_hwecc_8bit(struct mtd_info *mtd,int mode) { u_long nfreg; cur_ecc_mode = mode; if(cur_ecc_mode == NAND_ECC_WRITE){ /* 8 bit selection */ nfreg = readl(NFCONF); nfreg &= ~(0x3 << 23); nfreg |= (0x3<< 23); writel(nfreg,NFCONF); /* Set ECC type */ nfreg = readl(NFECCCONF); nfreg &= 0xf; nfreg |= 0x3; writel(nfreg,NFECCCONF); /* set 8/12/16bit Ecc direction to Encoding */ nfreg = readl(NFECCCONT); nfreg &= ~(0x1 << 16); nfreg |= (0x1 << 16); writel(nfreg,NFECCCONT); /* set 8/12/16bit ECC message length to msg */ nfreg = readl(NFECCCONF); nfreg &= ~((0x3ff<<16)); nfreg |= (0x1ff << 16); writel(nfreg,NFECCCONF); /* write '1' to clear this bit. */ /* clear illegal access status bit */ nfreg = readl(NFSTAT); nfreg |= (0x1 << 4); nfreg |= (0x1 << 5); writel(nfreg,NFSTAT); /* clear 8/12/16bit ecc encode done */ nfreg = readl(NFECCSTAT); nfreg |= (0x1 << 25); writel(nfreg,NFECCSTAT); nfreg = readl(NFCONT); nfreg &= ~(0x1 << 1); writel(nfreg,NFCONT); /* Initialize & unlock */ nfreg = readl(NFCONT); nfreg &= ~NFCONT_MECCLOCK; nfreg |= NFCONT_INITECC; writel(nfreg,NFCONT); /* Reset ECC value. */ nfreg = readl(NFECCCONT); nfreg |= (0x1 << 2); writel(nfreg,NFECCCONT); }else{ /* set 8/12/16bit ECC message length to msg */ nfreg = readl(NFECCCONF); nfreg &= ~((0x3ff<<16)); nfreg |= (0x1ff << 16); writel(nfreg,NFECCCONF); /* set 8/12/16bit Ecc direction to Decoding */ nfreg = readl(NFECCCONT); nfreg &= ~(0x1 << 16); writel(nfreg,NFECCCONT); /* write '1' to clear this bit. */ /* clear illegal access status bit */ nfreg = readl(NFSTAT); nfreg |= (0x1 << 4); nfreg |= (0x1 << 5); writel(nfreg,NFSTAT); /* Lock */ nfreg = readl(NFCONT); nfreg |= NFCONT_MECCLOCK; writel(nfreg,NFCONT); nfreg = readl(NFCONT); nfreg &= ~(0x1 << 1); writel(nfreg,NFCONT); /* clear 8/12/16bit ecc decode done */ nfreg = readl(NFECCSTAT); nfreg |= (0x1 << 24); writel(nfreg,NFECCSTAT); /* Initialize & lock */ nfreg = readl(NFCONT); nfreg &= ~NFCONT_MECCLOCK; nfreg |= NFCONT_MECCLOCK; writel(nfreg,NFCONT); /* write '1' to clear this bit. */ nfreg = readl(NFSTAT); nfreg &= ~(1<<4); nfreg |= (1<<4); writel(nfreg,NFSTAT); while(!(nfreg &(1<<4))){ nfreg = readl(NFSTAT); } /* write '1' to clear this bit. */ nfreg = readl(NFSTAT); nfreg &= ~(1<<4); nfreg |= (1<<4); writel(nfreg,NFSTAT); /* Initialize & unlock */ nfreg = readl(NFCONT); nfreg &= ~NFCONT_MECCLOCK; nfreg |= NFCONT_INITECC; writel(nfreg,NFECCCONT); } } int s3c_nand_calculate_ecc_8bit(struct mtd_info *mtd,nfeccprgecc0,nfeccprgecc1,nfeccprgecc2,nfeccprgecc3; if (cur_ecc_mode == NAND_ECC_READ) { /* Lock */ nfcont = readl(NFCONT); nfcont |= NFCONT_MECCLOCK; writel(nfcont,NFCONT); s3c_nand_wait_dec(); /* clear 8/12/16bit ecc decode done */ nfcont = readl(NFECCSTAT); nfcont |= (1<<24); writel(nfcont,NFECCSTAT); s3c_nand_wait_ecc_busy_8bit(); if(readl(NFSTAT)&(1<<5)) { /* clear illegal access status bit */ nfcont = readl(NFSTAT); nfcont |= (1<<5); writel(nfcont,NFSTAT); printf("n Accessed locked area!! n"); nfcont = readl(NFCONT); nfcont |= (1<<1); writel(nfcont,NFCONT); return -1; } nfcont = readl(NFCONT); nfcont |= (1<<1); writel(nfcont,NFCONT); } else { /* Lock */ nfcont = readl(NFCONT); nfcont |= NFCONT_MECCLOCK; writel(nfcont,NFCONT); s3c_nand_wait_enc(); /* clear 8/12/16bit ecc encode done */ nfcont = readl(NFECCSTAT); nfcont |= (1<<25); writel(nfcont,NFECCSTAT); nfeccprgecc0 = readl(NFECCPRGECC0); nfeccprgecc1 = readl(NFECCPRGECC1); nfeccprgecc2 = readl(NFECCPRGECC2); nfeccprgecc3 = readl(NFECCPRGECC3); ecc_code[0] = nfeccprgecc0 & 0xff; ecc_code[1] = (nfeccprgecc0 >> 8) & 0xff; ecc_code[2] = (nfeccprgecc0 >> 16) & 0xff; ecc_code[3] = (nfeccprgecc0 >> 24) & 0xff; ecc_code[4] = nfeccprgecc1 & 0xff; ecc_code[5] = (nfeccprgecc1 >> 8) & 0xff; ecc_code[6] = (nfeccprgecc1 >> 16) & 0xff; ecc_code[7] = (nfeccprgecc1 >> 24) & 0xff; ecc_code[8] = nfeccprgecc2 & 0xff; ecc_code[9] = (nfeccprgecc2 >> 8) & 0xff; ecc_code[10] = (nfeccprgecc2 >> 16) & 0xff; ecc_code[11] = (nfeccprgecc2 >> 24) & 0xff; ecc_code[12] = nfeccprgecc3 & 0xff; } return 0; } int s3c_nand_correct_data_8bit(struct mtd_info *mtd,u_char *dat) { int ret = -1; u_long nf8eccerr0,nf8eccerr1,nf8eccerr2,nf8eccerr3,nf8eccerr4,nfmlc8bitpt0,nfmlc8bitpt1; u_char err_type; s3c_nand_wait_ecc_busy_8bit(); nf8eccerr0 = readl(NFECCSECSTAT); nf8eccerr1 = readl(NFECCERL0); nf8eccerr2 = readl(NFECCERL1); nf8eccerr3 = readl(NFECCERL2); nf8eccerr4 = readl(NFECCERL3); nfmlc8bitpt0 = readl(NFECCERP0); nfmlc8bitpt1 = readl(NFECCERP1); err_type = (nf8eccerr0) & 0xf; /* No error,If free page (all 0xff) */ if ((nf8eccerr0 >> 29) & 0x1) err_type = 0; switch (err_type) { case 9: /* Uncorrectable */ printk("s3c-nand: ECC uncorrectable error detectedn"); ret = -1; break; case 8: /* 8 bit error (Correctable) */ dat[(nf8eccerr4 >> 16) & 0x3ff] ^= ((nfmlc8bitpt1 >> 24) & 0xff); case 7: /* 7 bit error (Correctable) */ dat[(nf8eccerr4) & 0x3ff] ^= ((nfmlc8bitpt1 >> 16) & 0xff); case 6: /* 6 bit error (Correctable) */ dat[(nf8eccerr3 >> 16) & 0x3ff] ^= ((nfmlc8bitpt1 >> 8) & 0xff); case 5: /* 5 bit error (Correctable) */ dat[(nf8eccerr3) & 0x3ff] ^= ((nfmlc8bitpt1) & 0xff); case 4: /* 8 bit error (Correctable) */ dat[(nf8eccerr2 >> 16) & 0x3ff] ^= ((nfmlc8bitpt0 >> 24) & 0xff); case 3: /* 7 bit error (Correctable) */ dat[(nf8eccerr2) & 0x3ff] ^= ((nfmlc8bitpt0>> 16) & 0xff); case 2: /* 6 bit error (Correctable) */ dat[(nf8eccerr1 >> 16) & 0x3ff] ^= ((nfmlc8bitpt0>> 8) & 0xff); case 1: /* 1 bit error (Correctable) */ printk("s3c-nand: %d bit(s) error detected,err_type); dat[(nf8eccerr1) & 0x3ff] ^= ((nfmlc8bitpt0) & 0xff); ret = err_type; break; case 0: /* No error */ ret = 0; break; } return ret; } void s3c_nand_write_page_8bit(struct mtd_info *mtd,struct nand_chip *chip,const uint8_t *buf) { u_long nfreg; int i,eccsize = 512; int eccbytes = 13; int eccsteps = mtd->writesize / eccsize; int badoffs = mtd->writesize == 512 ? NAND_SMALL_BADBLOCK_POS : NAND_LARGE_BADBLOCK_POS; uint8_t *ecc_calc = chip->buffers->ecccalc; uint8_t *p = buf; for (i = 0; eccsteps; eccsteps--,i += eccbytes,p += eccsize) { s3c_nand_enable_hwecc_8bit(mtd,NAND_ECC_WRITE); chip->write_buf(mtd,p,eccsize); s3c_nand_calculate_ecc_8bit(mtd,&ecc_calc[i]); } chip->oob_poi[badoffs] = 0xff; for (i = 0; i <= eccbytes * (mtd->writesize / eccsize); i++) { #if defined(CONFIG_EVT1) chip->oob_poi[i+12] = ecc_calc[i]; #else chip->oob_poi[i] = ecc_calc[i]; #endif } chip->write_buf(mtd,chip->oob_poi,mtd->oobsize); } int s3c_nand_read_page_8bit(struct mtd_info *mtd,uint8_t *buf) { u_long nfreg; int i,stat,eccsize = 512; int eccbytes = 13; int eccsteps = mtd->writesize / eccsize; int col = 0; uint8_t *p = buf; /* Step1: read whole oob */ col = mtd->writesize; #if defined(CONFIG_EVT1) chip->cmdfunc(mtd,NAND_CMD_RNDOUT,col+12,-1); #else chip->cmdfunc(mtd,col,-1); #endif chip->read_buf(mtd,mtd->oobsize); col = 0; for (i = 0; eccsteps; eccsteps--,p += eccsize) { chip->cmdfunc(mtd,-1); s3c_nand_enable_hwecc_8bit(mtd,NAND_ECC_READ); chip->read_buf(mtd,eccsize); chip->write_buf(mtd,chip->oob_poi + (((mtd->writesize / eccsize) - eccsteps) * eccbytes),eccbytes); s3c_nand_calculate_ecc_8bit(mtd,0); stat = s3c_nand_correct_data_8bit(mtd,p); if (stat == -1) mtd->ecc_stats.failed++; col = eccsize * ((mtd->writesize / eccsize) + 1 - eccsteps); } return 0; } int s3c_nand_read_oob_8bit(struct mtd_info *mtd,int page,int sndcmd) { int eccbytes = chip->ecc.bytes; int secc_start = mtd->oobsize - eccbytes; if (sndcmd) { chip->cmdfunc(mtd,NAND_CMD_READOOB,page); sndcmd = 0; } chip->read_buf(mtd,0); //secc_start); return sndcmd; } int s3c_nand_write_oob_8bit(struct mtd_info *mtd,int page) { int status = 0; int eccbytes = chip->ecc.bytes; int secc_start = mtd->oobsize - eccbytes; chip->cmdfunc(mtd,NAND_CMD_SEQIN,mtd->writesize,page); /* spare area */ chip->write_buf(mtd,0); //secc_start); /* Send command to program the OOB data */ chip->cmdfunc(mtd,NAND_CMD_PAGEPROG,-1,-1); status = chip->waitfunc(mtd,chip); return status & NAND_STATUS_FAIL ? -EIO : 0; } /********************************************************/ #endif static int s3c_nand_write_oob_1bit(struct mtd_info *mtd,int page) { uint8_t *ecc_calc = chip->buffers->ecccalc; int status = 0; int eccbytes = chip->ecc.bytes; int secc_start = mtd->oobsize - eccbytes; int i; chip->cmdfunc(mtd,page); /* spare area */ chip->ecc.hwctl(mtd,NAND_ECC_WRITE); chip->write_buf(mtd,secc_start); chip->ecc.calculate(mtd,&ecc_calc[chip->ecc.total]); for (i = 0; i < eccbytes; i++) chip->oob_poi[secc_start + i] = ecc_calc[chip->ecc.total + i]; chip->write_buf(mtd,chip->oob_poi + secc_start,eccbytes); /* Send command to program the OOB data */ chip->cmdfunc(mtd,-1); status = chip->waitfunc(mtd,chip); return status & NAND_STATUS_FAIL ? -EIO : 0; } static int s3c_nand_read_oob_1bit(struct mtd_info *mtd,int sndcmd) { uint8_t *ecc_calc = chip->buffers->ecccalc; int eccbytes = chip->ecc.bytes; int secc_start = mtd->oobsize - eccbytes; if (sndcmd) { chip->cmdfunc(mtd,page); sndcmd = 0; } chip->ecc.hwctl(mtd,NAND_ECC_READ); chip->read_buf(mtd,&ecc_calc[chip->ecc.total]); chip->read_buf(mtd,eccbytes); /* jffs2 special case */ if (!(chip->oob_poi[2] == 0x85 && chip->oob_poi[3] == 0x19)) chip->ecc.correct(mtd,0); return sndcmd; } static void s3c_nand_write_page_1bit(struct mtd_info *mtd,const uint8_t *buf) { int i,eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; int eccsteps = chip->ecc.steps; int secc_start = mtd->oobsize - eccbytes; uint8_t *ecc_calc = chip->buffers->ecccalc; const uint8_t *p = buf; uint32_t *eccpos = chip->ecc.layout->eccpos; /* main area */ for (i = 0; eccsteps; eccsteps--,p += eccsize) { chip->ecc.hwctl(mtd,eccsize); chip->ecc.calculate(mtd,&ecc_calc[i]); } for (i = 0; i < chip->ecc.total; i++) chip->oob_poi[eccpos[i]] = ecc_calc[i]; /* spare area */ chip->ecc.hwctl(mtd,eccbytes); } static int s3c_nand_read_page_1bit(struct mtd_info *mtd,uint8_t *buf) { int i,eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; int eccsteps = chip->ecc.steps; int secc_start = mtd->oobsize - eccbytes; int col = 0; uint8_t *p = buf; uint32_t *mecc_pos = chip->ecc.layout->eccpos; uint8_t *ecc_calc = chip->buffers->ecccalc; col = mtd->writesize; chip->cmdfunc(mtd,-1); /* spare area */ chip->ecc.hwctl(mtd,0); col = 0; /* main area */ for (i = 0; eccsteps; eccsteps--,p += eccsize) { chip->cmdfunc(mtd,-1); chip->ecc.hwctl(mtd,&ecc_calc[i]); stat = chip->ecc.correct(mtd,chip->oob_poi + mecc_pos[0] + ((chip->ecc.steps - eccsteps) * eccbytes),0); if (stat == -1) mtd->ecc_stats.failed++; col = eccsize * (chip->ecc.steps + 1 - eccsteps); } return 0; } /* * Hardware specific page read function for MLC. * Written by jsgood */ static int s3c_nand_read_page_4bit(struct mtd_info *mtd,eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; int eccsteps = chip->ecc.steps; int col = 0; uint8_t *p = buf; uint32_t *mecc_pos = chip->ecc.layout->eccpos; /* Step1: read whole oob */ col = mtd->writesize; chip->cmdfunc(mtd,-1); chip->read_buf(mtd,mtd->oobsize); col = 0; for (i = 0; eccsteps; eccsteps--,eccbytes); chip->ecc.calculate(mtd,0); stat = chip->ecc.correct(mtd,0); if (stat == -1) mtd->ecc_stats.failed++; col = eccsize * (chip->ecc.steps + 1 - eccsteps); } return 0; } /* * Hardware specific page write function for MLC. * Written by jsgood */ static void s3c_nand_write_page_4bit(struct mtd_info *mtd,eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; int eccsteps = chip->ecc.steps; const uint8_t *p = buf; uint8_t *ecc_calc = chip->buffers->ecccalc; uint32_t *mecc_pos = chip->ecc.layout->eccpos; /* Step1: write main data and encode mecc */ for (i = 0; eccsteps; eccsteps--,&ecc_calc[i]); } /* Step2: save encoded mecc */ for (i = 0; i < chip->ecc.total; i++) chip->oob_poi[mecc_pos[i]] = ecc_calc[i]; chip->write_buf(mtd,mtd->oobsize); } #endif /* * Board-specific NAND initialization. The following members of the * argument are board-specific (per include/linux/mtd/nand.h): * - IO_ADDR_R?: address to read the 8 I/O lines of the flash device * - IO_ADDR_W?: address to write the 8 I/O lines of the flash device * - hwcontrol: hardwarespecific function for accesing control-lines * - dev_ready: hardwarespecific function for accesing device ready/busy line * - enable_hwecc?: function to enable (reset) hardware ecc generator. Must * only be provided if a hardware ECC is available * - eccmode: mode of ecc,see defines * - chip_delay: chip dependent delay for transfering data from array to * read regs (tR) * - options: various chip options. They can partly be set to inform * nand_scan about special functionality. See the defines for further * explanation * Members with a "?" were not set in the merged testing-NAND branch,* so they are not set here either. */ int board_nand_init(struct nand_chip *nand) { unsigned int cur; #if defined(CFG_NAND_HWECC) int i; u_char tmp; struct nand_flash_dev *type = NULL; #endif /*Modified by lk*/ cur = MP01CON_REG; cur = (0x3<<12)|(0x3<<8)|(cur&(~(0xff<<8))); MP01CON_REG = cur; cur = MP03CON_REG; cur = (cur&(~(0xfff<<0))); cur = (cur&(~(0xf<<16))); cur |= (0x2<<16)|(0x2<<8)|(0x2<<4)|(0x2<<0); MP03CON_REG = cur; NFCONF_REG |= (7<<12)|(7<<8)|(7<<4)|(2<<23)|(1<<1);//NFCONF_VAL; NFCONT_REG |= (3<<4)|(1<<0);//NFCONT_VAL; NFCONT_REG &= ~((0x1<<16)|(0x1<<6)|(0x1<<7)); /*Modified by lk*/ nand->IO_ADDR_R = (void __iomem *)(NFDATA); nand->IO_ADDR_W = (void __iomem *)(NFDATA); nand->cmd_ctrl = s3c_nand_hwcontrol; nand->dev_ready = s3c_nand_device_ready; nand->scan_bbt = s3c_nand_scan_bbt; nand->options = 0; #if defined(CFG_NAND_FLASH_BBT) nand->options |= NAND_USE_FLASH_BBT; #else nand->options |= NAND_SKIP_BBTSCAN; #endif #if defined(CFG_NAND_HWECC) nand->ecc.mode = NAND_ECC_HW; nand->ecc.hwctl = s3c_nand_enable_hwecc; nand->ecc.calculate = s3c_nand_calculate_ecc; nand->ecc.correct = s3c_nand_correct_data; s3c_nand_hwcontrol(0,NAND_CMD_READID,NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); s3c_nand_hwcontrol(0,0x00,NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE); s3c_nand_hwcontrol(0,NAND_NCE | NAND_ALE); s3c_nand_hwcontrol(0,NAND_CMD_NONE,NAND_NCE | NAND_CTRL_CHANGE); s3c_nand_device_ready(0); tmp = readb(nand->IO_ADDR_R); /* Maf. ID */ tmp = readb(nand->IO_ADDR_R); /* Device ID */ for (i = 0; nand_flash_ids[i].name != NULL; i++) { if (tmp == nand_flash_ids[i].id) { type = &nand_flash_ids[i]; break; } } printf("id = %xn",nand_flash_ids[i].id); nand->cellinfo = readb(nand->IO_ADDR_R); /* 3rd byte */ tmp = readb(nand->IO_ADDR_R); /* 4th byte */ if (!type->pagesize) { if (((nand->cellinfo >> 2) & 0x3) == 0) { nand_type = S3C_NAND_TYPE_SLC; nand->ecc.size = 512; nand->ecc.bytes = 4; if ((1024 << (tmp & 0x3)) > 512) { nand->ecc.read_page = s3c_nand_read_page_1bit; nand->ecc.write_page = s3c_nand_write_page_1bit; nand->ecc.read_oob = s3c_nand_read_oob_1bit; nand->ecc.write_oob = s3c_nand_write_oob_1bit; nand->ecc.layout = &s3c_nand_oob_64; nand->ecc.hwctl = s3c_nand_enable_hwecc; nand->ecc.calculate = s3c_nand_calculate_ecc; nand->ecc.correct = s3c_nand_correct_data; nand->options |= NAND_NO_SUBPAGE_WRITE; } else { nand->ecc.layout = &s3c_nand_oob_16; } } else { nand_type = S3C_NAND_TYPE_MLC; nand->options |= NAND_NO_SUBPAGE_WRITE; /* NOP = 1 if MLC */ nand->ecc.read_page = s3c_nand_read_page_4bit; nand->ecc.write_page = s3c_nand_write_page_4bit; nand->ecc.size = 512; nand->ecc.bytes = 8; /* really 7 bytes */ nand->ecc.layout = &s3c_nand_oob_mlc_64; } } else { nand_type = S3C_NAND_TYPE_SLC; nand->ecc.size = 512; nand->cellinfo = 0; nand->ecc.bytes = 4; nand->ecc.layout = &s3c_nand_oob_16; } #else nand->ecc.mode = NAND_ECC_SOFT; #endif return 0; } #endif /* (CONFIG_CMD_NAND) */
?
?
添加nand_cp.c
/* * $Id: nand_cp.c,v 1.1 2008/11/20 01:08:36 boyko Exp $ * * (C) Copyright 2006 Samsung Electronics * * See file CREDITS for list of people who contributed to this * project. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License,or (at your option) any later version. * * This program is distributed in the hope that it will be useful,* but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not,write to the Free Software * Foundation,Inc.,59 Temple Place,Suite 330,Boston,* MA 02111-1307 USA */ /* * You must make sure that all functions in this file are designed * to load only U-Boot image. * * So,DO NOT USE in common read. * * By scsuh. */ #include <common.h> #ifdef CONFIG_S5PC11X #include <asm/io.h> #include <linux/mtd/nand.h> #include <regs.h> #define NAND_CONTROL_ENABLE() (NFCONT_REG |= (1 << 0)) /* * address format * 17 16 9 8 0 * -------------------------------------------- * | block(12bit) | page(5bit) | offset(9bit) | * -------------------------------------------- */ static int nandll_read_page (uchar *buf,ulong addr,int large_block) { int i; int page_size = 512; if (large_block) page_size = 2048; NAND_ENABLE_CE(); NFCMD_REG = NAND_CMD_READ0; /* Write Address */ NFADDR_REG = 0; if (large_block) NFADDR_REG = 0; NFADDR_REG = (addr) & 0xff; NFADDR_REG = (addr >> 8) & 0xff; NFADDR_REG = (addr >> 16) & 0xff; if (large_block) NFCMD_REG = NAND_CMD_READSTART; NF_TRANSRnB(); /* for compatibility(2460). u32 cannot be used. by scsuh */ for(i=0; i < page_size; i++) { *buf++ = NFDATA8_REG; } NAND_DISABLE_CE(); return 0; } /* * Read data from NAND. */ static int nandll_read_blocks (ulong dst_addr,ulong size,int large_block) { uchar *buf = (uchar *)dst_addr; int i; uint page_shift = 9; if (large_block) page_shift = 11; /* Read pages */ for (i = 0; i < (size>>page_shift); i++,buf+=(1<<page_shift)) { nandll_read_page(buf,i,large_block); } return 0; } int copy_uboot_to_ram (void) { int large_block = 0; int i; vu_char id; NAND_CONTROL_ENABLE(); NAND_ENABLE_CE(); NFCMD_REG = NAND_CMD_READID; NFADDR_REG = 0x00; /* wait for a while */ for (i=0; i<200; i++); id = NFDATA8_REG; id = NFDATA8_REG; if (id > 0x80) large_block = 1; /* read NAND Block. * 128KB ->240KB because of U-Boot size increase. by scsuh * So,read 0x3c000 bytes not 0x20000(128KB). */ return nandll_read_blocks(CFG_PHY_UBOOT_BASE,COPY_BL2_SIZE,large_block); } #endif (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |