ok6410 u-boot-2012.04.01移植四增加MLC NAND支持

2024-05-09 04:48

本文主要是介绍ok6410 u-boot-2012.04.01移植四增加MLC NAND支持,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

继ok6410 u-boot-2012.04.01移植三后,单板已具备下载程序,只需一根串口线就能下载程序。其实u-boot基本上已可以使用,在以后一步步完善u-boot。查看NAND型号,发现是MLC NAND,就又痛了,市场上一般开发板都是SCL NAND,并且MLC NAND操作起来复杂些,查看了很多资料,最终移植成功,放在这里与大家分享。

开发环境:
系统:ubuntu 10.04.4
单板:ok6410
NAND FLASH:K9GAG08U0D 2048MB
DDR:K4X1G163PCX2 256MB
NET:DM9000AEP
编译器:arm-linux-gcc-4.3.2
搭建开发环境详见ubuntu 10.04.4开发环境配置。
目标:
1.板级初始化,支持单板ok6410
2.修改u-boot,支持NAND启动
3.增加菜单update功能
4.增加MLC NAND支持
5.支持DM9000,网卡下载程序
6.修改环境变量以及mtdpart分区
7.u-boot裁剪及制作补丁

一、简单分析NAND部分源码

根据开发板启动串口输出信息,找到arch/arm/lib/board.c: board_init_r函数537:puts("NAND:  ");,我是从这里开始分析的,进入nand_init,接着就一直往下一层一层分析。

nand_init->nand_init_chip->board_nand_init ......例如分析nand read

SMDK6410# nand read 52000000 0 100000
 data abort
 reseting.......
/common/cmd_nand.c:
nand->ecc.mode = NAND_ECC_SOFT;
int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
 if (strncmp(cmd, "read", 4) == 0 || strncmp(cmd, "write", 5) == 0)
 ret = nand_read_skip_bad(nand, off, &rwsize,(u_char *)addr);
  need_skip = check_skip_len(nand, offset, *length);//nand_util.c
  rval = nand_read (nand, offset, length, buffer);//nand_base.c
   nand_get_device(chip, mtd, FL_READING);
   ret = nand_do_read_ops(mtd, from, &chip->ops);
    uint32_t readlen = ops->len;
    realpage = (int)(from >> chip->page_shift);
    page = realpage & chip->pagemask;
    while(1)
    {
    bytes = min(mtd->writesize - col, readlen);
    aligned = (bytes == mtd->writesize);
    if (realpage != chip->pagebuf || oob)
    {
    //chip->ecc.read_page = nand_read_page_swecc;
    etc = chip->ecc.read_page(mtd, chip, bufpoi,page);
     //chip->ecc.read_page_raw = nand_read_page_raw;
     chip->ecc.read_page_raw(mtd, chip, buf, page);
      chip->read_buf(mtd, buf, mtd->writesize);
      chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
     for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
      //chip->ecc.calculate = nand_calculate_ecc; nand_ecc.c
      chip->ecc.calculate(mtd, p, &ecc_calc[i]);
     for (i = 0; i < chip->ecc.total; i++)
     {
     ecc_code[i] = chip->oob_poi[eccpos[i]];
     //eccpos[6] = -442503148 ecc_code[6] = 0 
     //data abort pc : [<57e19768>]          lr : [<57e19780>]
     printf("eccpos[%d] = %ld\n",i,eccpos[i]);  
     printf("ecc_code[%d] = %d\n",i,ecc_code[i]);  
     }
     for (i = 0 ; eccsteps; eccsteps--, i += eccbytes,p +=eccsize)
      //chip->ecc.correct = nand_correct_data
      stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
    buf += bytes;
    }
    readlen -= bytes;
    if (!readlen)
     break;
    col = 0;
    realpage++;
    page = realpage & chip->pagemask;
    }
   return  mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0;
  nand_release_device(mtd);
 return 0;

solution:
 nand->ecc.mode = NAND_ECC_NONE;// instead of NAND_ECC_SOFT; then the nand become normal
problem:
 nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
 for (i = 0; i < len; i++)
  buf[i] = readb(chip->IO_ADDR_R);//there is no pagesize
int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
 if (strncmp(cmd, "read", 4) == 0 || strncmp(cmd, "write", 5) == 0)
 ret = nand_read_skip_bad(nand, off, &rwsize,(u_char *)addr);
  need_skip = check_skip_len(nand, offset, *length);//nand_util.c
  rval = nand_read (nand, offset, length, buffer);//nand_base.c
   nand_get_device(chip, mtd, FL_READING);
   ret = nand_do_read_ops(mtd, from, &chip->ops); 
    uint32_t readlen = ops->len;
    realpage = (int)(from >> chip->page_shift);
    page = realpage & chip->pagemask;
    while(1){
     bytes = min(mtd->writesize - col, readlen);
     aligned = (bytes == mtd->writesize);
     if (realpage != chip->pagebuf || oob)
     {
     //chip->ecc.read_page = nand_read_page_raw; nand_base.c
     ret = chip->ecc.read_page(mtd, chip, bufpoi,page);
      //chip->read_buf = busw ? nand_read_buf16 : nand_read_buf;
      chip->read_buf(mtd, buf, mtd->writesize);
      chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
     buf += bytes;
     }
     readlen -= bytes;
     if (!readlen)
      break;
     col = 0;
     realpage++;
     page = realpage & chip->pagemask;
     }
    return  mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0;
   nand_release_device(mtd);
 return 0;

就类似这样分析,一层一层往下看,总会找到问题所在。下面直接修改代码

二、修改代码支持MLC NAND

nand_init->nand_init_chip->board_nand_init,在drivers/mtd/nand/s3c64xx.c:

 board_nand_init,修改后的代码如下

int board_nand_init(struct nand_chip *nand)
{
#if defined(CFG_NAND_HWECC)
int i;
u_char tmp;
u_char dev_id;
struct nand_flash_dev *type = NULL;
#endif
static int chip_n;
if (chip_n >= MAX_CHIPS)
return -ENODEV;
if (NFCONF_REG & 0x80000000)
boot_nand = 1;
else
boot_nand = 0;
/*time parmmter*/
#define TACLS     0
#define TWRPH0    2
#define TWRPH1    1
NFCONF_REG &= ~((1<<30) | (7<<12) | (7<<8) | (7<<4));
NFCONF_REG |= ((TACLS<<12) | (TWRPH0<<8) | (TWRPH1<<4));
/*enable flash control*/	
NFCONT_REG |= NFCONT_ENABLE ;
NFCONT_REG &= ~NFCONT_WP;
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->select_chip	= s3c_nand_select_chip;
nand->scan_bbt		= s3c_nand_scan_bbt;
nand->options		= 0;
#ifdef CONFIG_NAND_SPL
nand->read_byte		= nand_read_byte;
nand->write_buf		= nand_write_buf;
nand->read_buf		= nand_read_buf;
#endif
#ifdef CONFIG_SYS_S3C_NAND_HWECC
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, 0x00, 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 */
dev_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;
}
}
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;
} 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;
//jkeqiang			
if((1024 << (tmp & 0x3)) > 2048)
{
printf("select s3c_nand_oob_mlc_128\n");
nand->ecc.layout = &s3c_nand_oob_mlc_128;
}
}
} 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;
*/
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;
//jkeqiang			
//		if((1024 << (tmp & 0x3)) > 2048)
if(dev_id == 0xd5)
{
printf("select s3c_nand_oob_mlc_128\n");
nand->ecc.layout = &s3c_nand_oob_mlc_128;
}
else
{
printf("select s3c_nand_oob_mlc_64\n");
}
}
/*
* If you get more than 1 NAND-chip with different page-sizes on the
* board one day, it will get more complicated...
*/
//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_NONE;//NAND_ECC_SOFT;
#endif /* ! CONFIG_SYS_S3C_NAND_HWECC */
//nand->priv		= nand_cs + chip_n++;
return 0;
}

同时在include/configs/smdk6410.h增加宏定义#define CFG_NAND_HWECC

在drivers/mtd/nand/s3c64xx.c头文件后38:增加

/* When NAND is used as boot device, below is set to 1. */
int boot_nand = 0;

/* 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}}
};

#if 1
/* 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}}
};
#else
/* 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 = 4,
 .eccpos = {56, 57, 58, 59},
 .oobfree = {
  {2, 6}, {13, 3}, {18, 6}, {29, 3},
  {34, 6}, {45, 3}, {50, 6}, {61, 3}}
};
#endif

/* 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, 41, 42, 43, 44, 45, 46, 47,
      48, 49, 50, 51, 52, 53, 54, 55,
        56, 57, 58, 59, 60, 61, 62, 63},
 .oobfree = {
  {.offset = 2,
   .length = 28}}
};

static struct nand_ecclayout s3c_nand_oob_mlc_128 = {
 .useecc = MTD_NANDECC_AUTOPLACE, /* Only for U-Boot */
 .eccbytes = 64,
 .eccpos = {
     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 = 60}}
};

修改166:s3c_nand_hwcontrol,修改后如下:

static void s3c_nand_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
struct nand_chip *this = mtd->priv;
if (ctrl & NAND_CLE)
{
// **send command
writeb(cmd, NFCMMD);
}
else if (ctrl & NAND_ALE)
{
//**send address
writeb(cmd, NFADDR);
}
/*if (ctrl & NAND_CTRL_CHANGE) {
if (ctrl & NAND_CLE)
this->IO_ADDR_W = (void __iomem *)NFCMMD;
else if (ctrl & NAND_ALE)
this->IO_ADDR_W = (void __iomem *)NFADDR;
else
this->IO_ADDR_W = (void __iomem *)NFDATA;
if (ctrl & NAND_NCE)
s3c_nand_select_chip(mtd, *(int *)this->priv);
else
s3c_nand_select_chip(mtd, -1);
}
if (cmd != NAND_CMD_NONE)
writeb(cmd, this->IO_ADDR_W);
*/
}

199增加s3c_nand_scan_bbt

/*
* We don't use bad block table
*/
static int s3c_nand_scan_bbt(struct mtd_info *mtdinfo)
{
return nand_default_bbt(mtdinfo);
}

207:接着增加ECC部分代码,替换掉下面的宏定义部分

#ifdef CONFIG_SYS_S3C_NAND_HWECC

.................

#endif /* CONFIG_SYS_S3C_NAND_HWECC */

/*
* Function for checking ECCEncDone in NFSTAT
* Written by jsgood
*/
static void s3c_nand_wait_enc(void)
{
while (!(readl(NFSTAT) & NFSTAT_ECCENCDONE)) {}
}
/*
* Function for checking ECCDecDone in NFSTAT
* Written by jsgood
*/
static void s3c_nand_wait_dec(void)
{
while (!(readl(NFSTAT) & NFSTAT_ECCDECDONE)) {}
}
/*
* Function for checking ECC Busy
* Written by jsgood
*/
static void s3c_nand_wait_ecc_busy(void)
{
while (readl(NFESTAT0) & 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 defined(CONFIG_S3C6410)
nfconf &= ~(0x3 << 23);
if (nand_type == S3C_NAND_TYPE_SLC)
nfconf |= NFCONF_ECC_1BIT;
else
nfconf |= NFCONF_ECC_4BIT;
#else
if (nand_type == S3C_NAND_TYPE_SLC)
nfconf &= ~NFCONF_ECC_MLC;	/* SLC */
else
nfconf |= NFCONF_ECC_MLC;	/* MLC */
#endif
writel(nfconf, 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) {
//printf("nand type =S3C_NAND_TYPE_SLC.\n");
/* 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...OK\n", dat[(nfestat0 >> 7) & 0x7ff]);
ret = 1;
break;
case 2: /* Multiple error */
case 3: /* ECC area error */
printk("s3c-nand: ECC uncorrectable error detected\n");
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 detected\n");
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 successfully\n", err_type);
dat[nfestat0 & 0x3ff] ^= (nfmlcbitpt & 0xff);
ret = err_type;
break;
case 0: /* No error */
ret = 0;
break;
}
}
return ret;
}
/***************************************************************
* jsgood: Temporary 8 Bit H/W ECC supports for BL1 (6410/6430 only)
***************************************************************/
static void s3c_nand_wait_ecc_busy_8bit(void)
{
while (readl(NF8ECCERR0) & NFESTAT0_ECCBUSY) {}
}
void s3c_nand_enable_hwecc_8bit(struct mtd_info *mtd, int mode)
{
u_long nfcont, nfconf;
cur_ecc_mode = mode;
/* 8 bit selection */
nfconf = readl(NFCONF);
nfconf &= ~(0x3 << 23);
nfconf |= (0x1 << 23);
writel(nfconf, NFCONF);
/* Initialize & unlock */
nfcont = readl(NFCONT);
nfcont |= NFCONT_INITECC;
nfcont &= ~NFCONT_MECCLOCK;
if (mode == NAND_ECC_WRITE)
nfcont |= NFCONT_ECC_ENC;
else if (mode == NAND_ECC_READ)
nfcont &= ~NFCONT_ECC_ENC;
writel(nfcont, NFCONT);
}
int s3c_nand_calculate_ecc_8bit(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code)
{
u_long nfcont, nfm8ecc0, nfm8ecc1, nfm8ecc2, nfm8ecc3;
/* Lock */
nfcont = readl(NFCONT);
nfcont |= NFCONT_MECCLOCK;
writel(nfcont, NFCONT);
if (cur_ecc_mode == NAND_ECC_READ)
s3c_nand_wait_dec();
else {
s3c_nand_wait_enc();
nfm8ecc0 = readl(NFM8ECC0);
nfm8ecc1 = readl(NFM8ECC1);
nfm8ecc2 = readl(NFM8ECC2);
nfm8ecc3 = readl(NFM8ECC3);
ecc_code[0] = nfm8ecc0 & 0xff;
ecc_code[1] = (nfm8ecc0 >> 8) & 0xff;
ecc_code[2] = (nfm8ecc0 >> 16) & 0xff;
ecc_code[3] = (nfm8ecc0 >> 24) & 0xff;			
ecc_code[4] = nfm8ecc1 & 0xff;
ecc_code[5] = (nfm8ecc1 >> 8) & 0xff;
ecc_code[6] = (nfm8ecc1 >> 16) & 0xff;
ecc_code[7] = (nfm8ecc1 >> 24) & 0xff;
ecc_code[8] = nfm8ecc2 & 0xff;
ecc_code[9] = (nfm8ecc2 >> 8) & 0xff;
ecc_code[10] = (nfm8ecc2 >> 16) & 0xff;
ecc_code[11] = (nfm8ecc2 >> 24) & 0xff;
ecc_code[12] = nfm8ecc3 & 0xff;
}
return 0;
}
int s3c_nand_correct_data_8bit(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc)
{
int ret = -1;
u_long nf8eccerr0, nf8eccerr1, nf8eccerr2, nfmlc8bitpt0, nfmlc8bitpt1;
u_char err_type;
s3c_nand_wait_ecc_busy_8bit();
nf8eccerr0 = readl(NF8ECCERR0);
nf8eccerr1 = readl(NF8ECCERR1);
nf8eccerr2 = readl(NF8ECCERR2);
nfmlc8bitpt0 = readl(NFMLC8BITPT0);
nfmlc8bitpt1 = readl(NFMLC8BITPT1);
err_type = (nf8eccerr0 >> 25) & 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 detected\n");
ret = -1;
break;
case 8: /* 8 bit error (Correctable) */
dat[(nf8eccerr2 >> 22) & 0x3ff] ^= ((nfmlc8bitpt1 >> 24) & 0xff);
case 7: /* 7 bit error (Correctable) */
dat[(nf8eccerr2 >> 11) & 0x3ff] ^= ((nfmlc8bitpt1 >> 16) & 0xff);
case 6: /* 6 bit error (Correctable) */
dat[nf8eccerr2 & 0x3ff] ^= ((nfmlc8bitpt1 >> 8) & 0xff);
case 5: /* 5 bit error (Correctable) */
dat[(nf8eccerr1 >> 22) & 0x3ff] ^= (nfmlc8bitpt1 & 0xff);
case 4: /* 4 bit error (Correctable) */
dat[(nf8eccerr1 >> 11) & 0x3ff] ^= ((nfmlc8bitpt0 >> 24) & 0xff);
case 3: /* 3 bit error (Correctable) */
dat[nf8eccerr1 & 0x3ff] ^= ((nfmlc8bitpt0 >> 16) & 0xff);
case 2: /* 2 bit error (Correctable) */
dat[(nf8eccerr0 >> 15) & 0x3ff] ^= ((nfmlc8bitpt0 >> 8) & 0xff);
case 1: /* 1 bit error (Correctable) */
printk("s3c-nand: %d bit(s) error detected, corrected successfully\n", err_type);
dat[nf8eccerr0 & 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)
{
int i, eccsize = 512;
int eccbytes = 13;
int eccsteps = mtd->writesize / eccsize;
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, p, &ecc_calc[i]);
}
for (i = 0; i < eccbytes * (mtd->writesize / eccsize); i++)
chip->oob_poi[i] = ecc_calc[i];
chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
}
int s3c_nand_read_page_8bit(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf)
{
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;
chip->cmdfunc(mtd, NAND_CMD_RNDOUT, col, -1);
chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
col = 0;
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
chip->cmdfunc(mtd, NAND_CMD_RNDOUT, col, -1);
s3c_nand_enable_hwecc_8bit(mtd, NAND_ECC_READ);
chip->read_buf(mtd, p, eccsize);
chip->write_buf(mtd, chip->oob_poi + (((mtd->writesize / eccsize) - eccsteps) * eccbytes), eccbytes);
s3c_nand_calculate_ecc_8bit(mtd, 0, 0);
stat = s3c_nand_correct_data_8bit(mtd, p, 0, 0);
if (stat == -1)
mtd->ecc_stats.failed++;
col = eccsize * ((mtd->writesize / eccsize) + 1 - eccsteps);
}
return 0;
}
static int s3c_nand_write_oob_1bit(struct mtd_info *mtd, struct nand_chip *chip,
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, NAND_CMD_SEQIN, mtd->writesize, page);
/* spare area */
chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
chip->write_buf(mtd, chip->oob_poi, secc_start);
chip->ecc.calculate(mtd, 0, &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, NAND_CMD_PAGEPROG, -1, -1);
status = chip->waitfunc(mtd, chip);
return status & NAND_STATUS_FAIL ? -EIO : 0;
}
static int s3c_nand_read_oob_1bit(struct mtd_info *mtd, struct nand_chip *chip,
int page, 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, NAND_CMD_READOOB, 0, page);
sndcmd = 0;
}
chip->ecc.hwctl(mtd, NAND_ECC_READ);
chip->read_buf(mtd, chip->oob_poi, secc_start);
chip->ecc.calculate(mtd, 0, &ecc_calc[chip->ecc.total]);
chip->read_buf(mtd, chip->oob_poi + secc_start, eccbytes);
/* jffs2 special case */
if (!(chip->oob_poi[2] == 0x85 && chip->oob_poi[3] == 0x19))
chip->ecc.correct(mtd, chip->oob_poi, chip->oob_poi + secc_start, 0);
return sndcmd;
}
static void s3c_nand_write_page_1bit(struct mtd_info *mtd, struct nand_chip *chip,
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--, i += eccbytes, p += eccsize) {
chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
chip->write_buf(mtd, p, eccsize);
chip->ecc.calculate(mtd, p, &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, NAND_ECC_WRITE);
chip->write_buf(mtd, chip->oob_poi, secc_start);
chip->ecc.calculate(mtd, p, &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);
}
static int s3c_nand_read_page_1bit(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf)
{
int i, stat, 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, NAND_CMD_RNDOUT, col, -1);
/* spare area */
chip->ecc.hwctl(mtd, NAND_ECC_READ);
chip->read_buf(mtd, chip->oob_poi, secc_start);
chip->ecc.calculate(mtd, p, &ecc_calc[chip->ecc.total]);
chip->read_buf(mtd, chip->oob_poi + secc_start, eccbytes);
/* jffs2 special case */
if (!(chip->oob_poi[2] == 0x85 && chip->oob_poi[3] == 0x19))
chip->ecc.correct(mtd, chip->oob_poi, chip->oob_poi + secc_start, 0);
col = 0;
/* main area */
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
chip->cmdfunc(mtd, NAND_CMD_RNDOUT, col, -1);
chip->ecc.hwctl(mtd, NAND_ECC_READ);
chip->read_buf(mtd, p, eccsize);
chip->ecc.calculate(mtd, p, &ecc_calc[i]);
stat = chip->ecc.correct(mtd, p, 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, struct nand_chip *chip,
uint8_t *buf)
{
int i, stat, 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, NAND_CMD_RNDOUT, col, -1);
chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
col = 0;
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
chip->cmdfunc(mtd, NAND_CMD_RNDOUT, col, -1);
chip->ecc.hwctl(mtd, NAND_ECC_READ);
chip->read_buf(mtd, p, eccsize);
chip->write_buf(mtd, chip->oob_poi + mecc_pos[0] + ((chip->ecc.steps - eccsteps) * eccbytes), eccbytes);
chip->ecc.calculate(mtd, 0, 0);
stat = chip->ecc.correct(mtd, p, 0, 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, struct nand_chip *chip,
const uint8_t *buf)
{
int i, 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--, i += eccbytes, p += eccsize) {
chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
chip->write_buf(mtd, p, eccsize);
chip->ecc.calculate(mtd, p, &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, chip->oob_poi, mtd->oobsize);
}

drivers/mtd/nand/s3c64xx.c 基本修改完毕,现在的NAND以支持MLC NAND,但想要用u-boot自带的nand命令读写nand,还需要修改

修改的地方太多了,先编译再说,遇到问题再解决

change@change:/si/OK6410/u-boot-2012.04.01$ make

s3c64xx.c:53: error: unknown field 'useecc' specified in initializer
s3c64xx.c:64: error: unknown field 'useecc' specified in initializer
s3c64xx.c:86: error: unknown field 'useecc' specified in initializer
s3c64xx.c:99: error: unknown field 'useecc' specified in initializer
s3c64xx.c: In function 's3c_nand_hwcontrol':
s3c64xx.c:168: warning: unused variable 'this'
s3c64xx.c: In function 's3c_nand_enable_hwecc':
s3c64xx.c:255: error: 'NFCONF_ECC_MLC' undeclared (first use in this function)
s3c64xx.c:255: error: (Each undeclared identifier is reported only once
s3c64xx.c:255: error: for each function it appears in.)
s3c64xx.c: In function 's3c_nand_wait_ecc_busy_8bit':
s3c64xx.c:425: error: 'NF8ECCERR0' undeclared (first use in this function)
s3c64xx.c: In function 's3c_nand_calculate_ecc_8bit':
s3c64xx.c:469: error: 'NFM8ECC0' undeclared (first use in this function)
s3c64xx.c:470: error: 'NFM8ECC1' undeclared (first use in this function)
s3c64xx.c:471: error: 'NFM8ECC2' undeclared (first use in this function)
s3c64xx.c:472: error: 'NFM8ECC3' undeclared (first use in this function)
s3c64xx.c: In function 's3c_nand_correct_data_8bit':
s3c64xx.c:501: error: 'NF8ECCERR0' undeclared (first use in this function)
s3c64xx.c:502: error: 'NF8ECCERR1' undeclared (first use in this function)
s3c64xx.c:503: error: 'NF8ECCERR2' undeclared (first use in this function)
s3c64xx.c:504: error: 'NFMLC8BITPT0' undeclared (first use in this function)
s3c64xx.c:505: error: 'NFMLC8BITPT1' undeclared (first use in this function)
s3c64xx.c: In function 's3c_nand_write_page_8bit':
s3c64xx.c:561: warning: initialization discards qualifiers from pointer target type
s3c64xx.c: In function 'board_nand_init':
s3c64xx.c:887: warning: assignment discards qualifiers from pointer target type
s3c64xx.c:902: warning: assignment from incompatible pointer type
s3c64xx.c:913: warning: assignment from incompatible pointer type
s3c64xx.c:937: warning: assignment from incompatible pointer type
make[1]: *** [s3c64xx.o] Error 1
make[1]: Leaving directory `/si/OK6410/u-boot-2012.04.01/drivers/mtd/nand'
make: *** [drivers/mtd/nand/libnand.o] Error 2
change@change:/si/OK6410/u-boot-2012.04.01$ 

先解决第一个问题,没有就定义

进去定位到include/linux/mtd/mtd-abi.h 在nand_ecclayout增加成员

 uint32_t useecc;
 uint32_t reserved;

接着在include/asm/arch-s3c64xx/s3c6400.h 614:增加下面宏定义,覆盖掉#define NFCONF_ECC_4BIT  (2<<23)

#define NF8ECCERR0  (ELFIN_NAND_BASE+NF8ECCERR0_OFFSET)
#define NF8ECCERR1  (ELFIN_NAND_BASE+NF8ECCERR1_OFFSET)
#define NF8ECCERR2  (ELFIN_NAND_BASE+NF8ECCERR2_OFFSET)
#define NFM8ECC0  (ELFIN_NAND_BASE+NFM8ECC0_OFFSET)
#define NFM8ECC1  (ELFIN_NAND_BASE+NFM8ECC1_OFFSET)
#define NFM8ECC2  (ELFIN_NAND_BASE+NFM8ECC2_OFFSET)
#define NFM8ECC3  (ELFIN_NAND_BASE+NFM8ECC3_OFFSET)
#define NFMLC8BITPT0  (ELFIN_NAND_BASE+NFMLC8BITPT0_OFFSET)
#define NFMLC8BITPT1  (ELFIN_NAND_BASE+NFMLC8BITPT1_OFFSET)

#define NFCONF_ECC_MLC  (1<<24)

#define NFCONF_ECC_1BIT  (0<<23)
#define NFCONF_ECC_4BIT  (2<<23)
#define NFCONF_ECC_8BIT  (1<<23)

577:增加

#define NF8ECCERR0_OFFSET 0x44
#define NF8ECCERR1_OFFSET 0x48
#define NF8ECCERR2_OFFSET 0x4c
#define NFM8ECC0_OFFSET  0x50
#define NFM8ECC1_OFFSET  0x54
#define NFM8ECC2_OFFSET  0x58
#define NFM8ECC3_OFFSET  0x5c
#define NFMLC8BITPT0_OFFSET 0x60
#define NFMLC8BITPT1_OFFSET 0x64

再编译看看,OK编译通过,肯定还有问题,等测试的时候就知道了,改的地方很多,先写到这,下一篇测试再修改

 

 

 

 

 

 

 

 

 

 

 

 

 

 

这篇关于ok6410 u-boot-2012.04.01移植四增加MLC NAND支持的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/972430

相关文章

hdu 2602 and poj 3624(01背包)

01背包的模板题。 hdu2602代码: #include<stdio.h>#include<string.h>const int MaxN = 1001;int max(int a, int b){return a > b ? a : b;}int w[MaxN];int v[MaxN];int dp[MaxN];int main(){int T;int N, V;s

EMLOG程序单页友链和标签增加美化

单页友联效果图: 标签页面效果图: 源码介绍 EMLOG单页友情链接和TAG标签,友链单页文件代码main{width: 58%;是设置宽度 自己把设置成与您的网站宽度一样,如果自适应就填写100%,TAG文件不用修改 安装方法:把Links.php和tag.php上传到网站根目录即可,访问 域名/Links.php、域名/tag.php 所有模板适用,代码就不粘贴出来,已经打

集中式版本控制与分布式版本控制——Git 学习笔记01

什么是版本控制 如果你用 Microsoft Word 写过东西,那你八成会有这样的经历: 想删除一段文字,又怕将来这段文字有用,怎么办呢?有一个办法,先把当前文件“另存为”一个文件,然后继续改,改到某个程度,再“另存为”一个文件。就这样改着、存着……最后你的 Word 文档变成了这样: 过了几天,你想找回被删除的文字,但是已经记不清保存在哪个文件了,只能挨个去找。真麻烦,眼睛都花了。看

FreeRTOS-基本介绍和移植STM32

FreeRTOS-基本介绍和STM32移植 一、裸机开发和操作系统开发介绍二、任务调度和任务状态介绍2.1 任务调度2.1.1 抢占式调度2.1.2 时间片调度 2.2 任务状态 三、FreeRTOS源码和移植STM323.1 FreeRTOS源码3.2 FreeRTOS移植STM323.2.1 代码移植3.2.2 时钟中断配置 一、裸机开发和操作系统开发介绍 裸机:前后台系

RabbitMQ使用及与spring boot整合

1.MQ   消息队列(Message Queue,简称MQ)——应用程序和应用程序之间的通信方法   应用:不同进程Process/线程Thread之间通信   比较流行的中间件:     ActiveMQ     RabbitMQ(非常重量级,更适合于企业级的开发)     Kafka(高吞吐量的分布式发布订阅消息系统)     RocketMQ   在高并发、可靠性、成熟度等

Spring Boot 入门篇

一、简介 Spring Boot是一款开源的Java Web应用框架,旨在简化Spring应用的初始搭建以及开发过程。它整合了Spring技术栈中的诸多关键组件,为开发者提供了一种快速、简便的Spring应用开发方式。Spring Boot遵循“约定优于配置”的原则,通过自动配置、起步依赖和内置的Servlet容器,极大地简化了传统Spring应用的配置和部署过程。 二、Spring Boot

Spring Boot集成Tess4J实现OCR

1.什么是Tess4j? Tesseract是一个开源的光学字符识别(OCR)引擎,它可以将图像中的文字转换为计算机可读的文本。支持多种语言和书面语言,并且可以在命令行中执行。它是一个流行的开源OCR工具,可以在许多不同的操作系统上运行。Tess4J是一个基于Tesseract OCR引擎的Java接口,可以用来识别图像中的文本,说白了,就是封装了它的API,让Java可以直接调用。 Tess

部署若依Spring boot项目

nohup和& nohup命令解释 nohup命令:nohup 是 no hang up 的缩写,就是不挂断的意思,但没有后台运行,终端不能标准输入。nohup :不挂断的运行,注意并没有后台运行的功能,就是指,用nohup运行命令可以使命令永久的执行下去,和用户终端没有关系,注意了nohup没有后台运行的意思;&才是后台运行在缺省情况下该作业的所有输出都被重定向到一个名为nohup.o

使用Spring Boot集成Spring Data JPA和单例模式构建库存管理系统

引言 在企业级应用开发中,数据库操作是非常重要的一环。Spring Data JPA提供了一种简化的方式来进行数据库交互,它使得开发者无需编写复杂的JPA代码就可以完成常见的CRUD操作。此外,设计模式如单例模式可以帮助我们更好地管理和控制对象的创建过程,从而提高系统的性能和可维护性。本文将展示如何结合Spring Boot、Spring Data JPA以及单例模式来构建一个基本的库存管理系统

Spring Boot集成PDFBox实现电子签章

概述 随着无纸化办公的普及,电子文档的使用越来越广泛。电子签章作为一种有效的身份验证方式,在很多场景下替代了传统的纸质文件签名。Apache PDFBox 是一个开源的Java库,可以用来渲染、生成、填写PDF文档等操作。本文将介绍如何使用Spring Boot框架结合PDFBox来实现电子签章功能。 准备工作 环境搭建:确保你的开发环境中安装了JDK 8或更高版本,并且配置好了Maven或