tiny210(s5pv210)移植u-boot(基于 2014.4 版本)——NAND 8位硬件ECC

这节我们实现nand的ecc,保存环境变量到nand flash 中。然后把我们之前的led灯烧写到nand flash 中,开机启动,在 tiny210.h 中定义宏 CONFIG_S5PV210_NAND_HWECC、CONFIG_SYS_NAND_ECCSIZE、CONFIG_SYS_NAND_ECCBYTES


CONFIG_SYS_NAND_ECCSIZE 定义了消息长度,即每多少字节进行 1 次 ECC 校验
CONFIG_SYS_NAND_ECCBYTES 定义为 13Byte,将 drivers/mtd/nand/s5pv210_nand.c 中的 CONFIG_S3C2410_NAND_HWECC 替换为CONFIG_S5PV210_NAND_HWECC,
我们只进行 ECC 校验写,ECC 校验读使用三星提供的函数,我们必须按照三星手册规定的 ECC 校验码在 Spare Field  中的存储格式进行存储。


因此我们需要自定义 nand_ecclayout 结构体,这个结构体描述了如何存储 ECC 数据,同时将这个结构体赋值给 nand->ecc.layout



其他的代码请看源码:

[cpp]  view plain copy
  1. /* 
  2.  * (C) Copyright 2006 OpenMoko, Inc. 
  3.  * Author: Harald Welte <laforge@openmoko.org> 
  4.  * 
  5.  * SPDX-License-Identifier: GPL-2.0+ 
  6.  */  
  7.   
  8. #include <common.h>  
  9.   
  10. #include <nand.h>  
  11. #include <asm/arch/nand_reg.h>  
  12. #include <asm/io.h>  
  13.   
  14. #define MP0_1CON  (*(volatile u32 *)0xE02002E0)  
  15. #define MP0_3CON  (*(volatile u32 *)0xE0200320)  
  16. #define MP0_6CON  (*(volatile u32 *)0xE0200380)  
  17.   
  18. /* modied by shl */  
  19. static void s5pv210_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)  
  20. {  
  21.     struct nand_chip *chip = mtd->priv;  
  22.     struct s5pv210_nand *nand = (struct s5pv210_nand *)samsung_get_base_nand();  
  23.     debug("hwcontrol(): 0x%02x 0x%02x\n", cmd, ctrl);  
  24.     ulong IO_ADDR_W = (ulong)nand;  
  25.     if (ctrl & NAND_CTRL_CHANGE) {  
  26.           
  27.         if (ctrl & NAND_CLE)          
  28.             IO_ADDR_W = IO_ADDR_W | 0x8;    /* Command Register  */  
  29.         else if (ctrl & NAND_ALE)  
  30.             IO_ADDR_W = IO_ADDR_W | 0xC;    /* Address Register */  
  31.               
  32.         chip->IO_ADDR_W = (void *)IO_ADDR_W;  
  33.   
  34.         if (ctrl & NAND_NCE)    /* select */  
  35.             writel(readl(&nand->nfcont) & ~(1 << 1), &nand->nfcont);  
  36.         else                    /* deselect */  
  37.             writel(readl(&nand->nfcont) | (1 << 1), &nand->nfcont);  
  38.     }  
  39.   
  40.     if (cmd != NAND_CMD_NONE)  
  41.         writeb(cmd, chip->IO_ADDR_W);      
  42.     else  
  43.         chip->IO_ADDR_W = &nand->nfdata;  
  44.   
  45. }  
  46.   
  47. static int s5pv210_dev_ready(struct mtd_info *mtd)  
  48. {  
  49.     struct s5pv210_nand *nand = (struct s5pv210_nand *)samsung_get_base_nand();  
  50.     debug("dev_ready\n");  
  51.     return readl(&nand->nfstat) & 0x01;  
  52. }  
  53.   
  54. #ifdef CONFIG_S5PV210_NAND_HWECC  
  55. void s5pv210_nand_enable_hwecc(struct mtd_info *mtd, int mode)  
  56. {  
  57.     struct s5pv210_nand *nand = (struct s5pv210_nand *)samsung_get_base_nand();  
  58.     debug("s5pv210_nand_enable_hwecc(%p, %d)\n", mtd, mode);  
  59.       
  60.     writel(readl(&nand->nfconf) | (0x3 << 23), &nand->nfconf);  
  61.       
  62.     if (mode == NAND_ECC_READ)  
  63.     {  
  64.     }  
  65.     else if (mode == NAND_ECC_WRITE)  
  66.     {  
  67.         /* set 8/12/16bit Ecc direction to Encoding */  
  68.         writel(readl(&nand->nfecccont) | (0x1 << 16), &nand->nfecccont);  
  69.         /* clear 8/12/16bit ecc encode done */  
  70.         writel(readl(&nand->nfeccstat) | (0x1 << 25), &nand->nfeccstat);  
  71.     }  
  72.       
  73.     /* Initialize main area ECC decoder/encoder */  
  74.     writel(readl(&nand->nfcont) | (0x1 << 5), &nand->nfcont);  
  75.       
  76.     /* The ECC message size(For 512-byte message, you should set 511) 
  77.     * 8-bit ECC/512B */  
  78.     writel((511 << 16) | 0x3, &nand->nfeccconf);  
  79.       
  80.     writel(readl(&nand->nfstat) | (0x1 << 4) | (0x1 << 5), &nand->nfstat);  
  81.       
  82.     /* Initialize main area ECC decoder/ encoder */  
  83.     writel(readl(&nand->nfecccont) | (0x1 << 2), &nand->nfecccont);  
  84.       
  85.     /* Unlock Main area ECC   */  
  86.     writel(readl(&nand->nfcont) & ~(0x1 << 7), &nand->nfcont);  
  87. }  
  88.   
  89. /* modied by shl */  
  90. static int s5pv210_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,  
  91.                       u_char *ecc_code)  
  92. {  
  93.     struct s5pv210_nand *nand = (struct s5pv210_nand *)samsung_get_base_nand();  
  94.     u32 nfeccprgecc0 = 0, nfeccprgecc1 = 0, nfeccprgecc2 = 0, nfeccprgecc3 = 0;  
  95.   
  96.     /* Lock Main area ECC */  
  97.     writel(readl(&nand->nfcont) | (1 << 7), &nand->nfcont);  
  98.       
  99.     /* 读取13 Byte的Ecc Code */  
  100.     nfeccprgecc0 = readl(&nand->nfeccprgecc0);  
  101.     nfeccprgecc1 = readl(&nand->nfeccprgecc1);  
  102.     nfeccprgecc2 = readl(&nand->nfeccprgecc2);  
  103.     nfeccprgecc3 = readl(&nand->nfeccprgecc3);  
  104.   
  105.     ecc_code[0] = nfeccprgecc0 & 0xff;  
  106.     ecc_code[1] = (nfeccprgecc0 >> 8) & 0xff;  
  107.     ecc_code[2] = (nfeccprgecc0 >> 16) & 0xff;  
  108.     ecc_code[3] = (nfeccprgecc0 >> 24) & 0xff;  
  109.     ecc_code[4] = nfeccprgecc1 & 0xff;  
  110.     ecc_code[5] = (nfeccprgecc1 >> 8) & 0xff;  
  111.     ecc_code[6] = (nfeccprgecc1 >> 16) & 0xff;  
  112.     ecc_code[7] = (nfeccprgecc1 >> 24) & 0xff;  
  113.     ecc_code[8] = nfeccprgecc2 & 0xff;  
  114.     ecc_code[9] = (nfeccprgecc2 >> 8) & 0xff;  
  115.     ecc_code[10] = (nfeccprgecc2 >> 16) & 0xff;  
  116.     ecc_code[11] = (nfeccprgecc2 >> 24) & 0xff;  
  117.     ecc_code[12] = nfeccprgecc3 & 0xff;  
  118.       
  119.     debug("s5pv210_nand_calculate_hwecc(%p,):\n"  
  120.         "0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n"  
  121.         "0x%02x 0x%02x 0x%02x\n", mtd , ecc_code[0], ecc_code[1], ecc_code[2],   
  122.         ecc_code[3], ecc_code[4], ecc_code[5], ecc_code[6], ecc_code[7],   
  123.         ecc_code[8], ecc_code[9], ecc_code[10], ecc_code[11], ecc_code[12]);  
  124.   
  125.     return 0;  
  126. }  
  127.   
  128. /* add by shl */  
  129. #define NF8_ReadPage_Adv(a,b,c) (((int(*)(u32, u32, u8*))(*((u32 *)0xD0037F90)))(a,b,c))  
  130. static int s5pv210_nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,  
  131.                 uint8_t *buf, int oob_required, int page)  
  132. {  
  133.     /* tiny210使用的NAND FLASH一个块64页 */  
  134.     return NF8_ReadPage_Adv(page / 64, page % 64, buf);  
  135. }  
  136.   
  137. static int s5pv210_nand_correct_data(struct mtd_info *mtd, u_char *dat,  
  138.                      u_char *read_ecc, u_char *calc_ecc)  
  139. {  
  140.     if (read_ecc[0] == calc_ecc[0] &&  
  141.         read_ecc[1] == calc_ecc[1] &&  
  142.         read_ecc[2] == calc_ecc[2])  
  143.         return 0;  
  144.   
  145.     printf("s5pv210_nand_correct_data: not implemented\n");  
  146.     return -1;  
  147. }  
  148. #endif  
  149.   
  150. /* 
  151.  * add by shl 
  152.  * nand_select_chip 
  153.  * @mtd: MTD device structure 
  154.  * @ctl: 0 to select, -1 for deselect 
  155.  * 
  156.  * Default select function for 1 chip devices. 
  157.  */  
  158. static void s5pv210_nand_select_chip(struct mtd_info *mtd, int ctl)  
  159. {  
  160.     struct nand_chip *chip = mtd->priv;  
  161.   
  162.     switch (ctl) {  
  163.     case -1:    /* deselect the chip */  
  164.         chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE);  
  165.         break;  
  166.     case 0:     /* Select the chip */  
  167.         chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);  
  168.         break;  
  169.   
  170.     default:  
  171.         BUG();  
  172.     }  
  173. }  
  174.   
  175. /* add by shl */  
  176. static struct nand_ecclayout nand_oob_64 = {  
  177.     .eccbytes = 52,     /* 2048 / 512 * 13 */  
  178.     .eccpos = { 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,  
  179.                 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,  
  180.                 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,   
  181.                 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,  
  182.                 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,  
  183.                 62, 63},  
  184.     /* 0和1用于保存坏块标记,12~63保存ecc,剩余2~11为free */  
  185.     .oobfree = {  
  186.             {.offset = 2,  
  187.             .length = 10}  
  188.         }  
  189. };  
  190.   
  191. /* modied by shl */  
  192. int board_nand_init(struct nand_chip *nand)  
  193. {  
  194.     u32 cfg = 0;  
  195.     struct s5pv210_nand *nand_reg = (struct s5pv210_nand *)(struct s5pv210_nand *)samsung_get_base_nand();  
  196.   
  197.     debug("board_nand_init()\n");  
  198.   
  199.     /* initialize hardware */  
  200.     /* HCLK_PSYS=133MHz(7.5ns) */  
  201.     cfg =   (0x1 << 23) | /* Disable 1-bit and 4-bit ECC */  
  202.             /* 下面3个时间参数稍微比计算出的值大些(我这里依次加1),否则读写不稳定 */  
  203.             (0x3 << 12) | /* 7.5ns * 2 > 12ns tALS tCLS */  
  204.             (0x2 << 8) |  /* (1+1) * 7.5ns > 12ns (tWP) */  
  205.             (0x1 << 4) |  /* (0+1) * 7.5 > 5ns (tCLH/tALH) */  
  206.             (0x0 << 3) |  /* SLC NAND Flash */  
  207.             (0x0 << 2) |  /* 2KBytes/Page */  
  208.             (0x1 << 1);       /* 5 address cycle */  
  209.       
  210.     writel(cfg, &nand_reg->nfconf);  
  211.       
  212.     writel((0x1 << 1) | (0x1 << 0), &nand_reg->nfcont);  
  213.     /* Disable chip select and Enable NAND Flash Controller */  
  214.       
  215.     /* Config GPIO */  
  216.     MP0_1CON &= ~(0xFFFF << 8);  
  217.     MP0_1CON |= (0x3333 << 8);  
  218.     MP0_3CON = 0x22222222;  
  219.     MP0_6CON = 0x22222222;  
  220.       
  221.     /* initialize nand_chip data structure */  
  222.     nand->IO_ADDR_R = (void *)&nand_reg->nfdata;  
  223.     nand->IO_ADDR_W = (void *)&nand_reg->nfdata;  
  224.   
  225.     nand->select_chip = s5pv210_nand_select_chip;  
  226.   
  227.     /* read_buf and write_buf are default */  
  228.     /* read_byte and write_byte are default */  
  229.   
  230.     /* hwcontrol always must be implemented */  
  231.     nand->cmd_ctrl = s5pv210_hwcontrol;  
  232.   
  233.     nand->dev_ready = s5pv210_dev_ready;  
  234.   
  235. #ifdef CONFIG_S5PV210_NAND_HWECC  
  236.     nand->ecc.hwctl = s5pv210_nand_enable_hwecc;  
  237.     nand->ecc.calculate = s5pv210_nand_calculate_ecc;  
  238.     nand->ecc.correct = s5pv210_nand_correct_data;  
  239.     nand->ecc.mode = NAND_ECC_HW;  
  240.     nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE;  
  241.     nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES;  
  242.     nand->ecc.strength = 1;  
  243.     /* add by shl */  
  244.     nand->ecc.layout = &nand_oob_64;  
  245.     nand->ecc.read_page = s5pv210_nand_read_page_hwecc;  
  246. #else  
  247.     nand->ecc.mode = NAND_ECC_SOFT;  
  248. #endif  
  249.   
  250. #ifdef CONFIG_S3C2410_NAND_BBT  
  251.     nand->bbt_options |= NAND_BBT_USE_FLASH;  
  252. #endif  
  253.   
  254.     debug("end of nand_init\n");  
  255.       
  256.     return 0;  
  257. }  

重新编译,成功生成 u-boot.bin,将它烧写到 SD 卡的扇区 32,从 SD 卡启动开发板:


    下面进行 NAND 启动试验,将之前的led程序烧写到 NAND,然后从 NAND 启动,可以看到 LED 全亮的效果。首先我们先编译 led.c,生成 led.bin,然后 添加 16B 的头信息生成 210.bin,然后将 210.bin 拷贝到 tftp 服务器目录。


然后使用最新的 u-boot 将 210.bin 烧写到 NAND 的第 0 页,然后从 NAND 启动



   从 NAND 启动可以看到 4 个 LED 全亮。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值