tq210 nand硬件校验

前几天匆忙间发了一篇关于S5PV210的8位HWECC驱动的文章,但是后来发现存在严重的Bug,就将原来那篇文章删除了,这里先说声抱歉,但是,HWECC能有效的节省CPU占用量,我仔细调试了S5PV210的HWECC部分,现在刚调好1位的HWECC,为了表示误发原来那篇文章的歉意,现在将代码放在这里,与大家分享:

[plain]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. #include <linux/module.h>  
  2. #include <linux/platform_device.h>  
  3. #include <linux/clk.h>  
  4. #include <linux/io.h>  
  5. #include <linux/slab.h>  
  6. #include <linux/mtd/mtd.h>  
  7. #include <linux/mtd/nand.h>  
  8. #include <linux/mtd/partitions.h>  
  9.   
  10. #define NFCONT_MECCLOCK         (1<<7)  
  11. #define NFCONT_SECCLOCK         (1<<6)  
  12. #define NFCONT_INITMECC         (1<<5)  
  13. #define NFCONT_INITSECC         (1<<4)  
  14. #define NFCONT_INITECC          (NFCONT_INITMECC | NFCONT_INITSECC)  
  15.   
  16. struct s5p_nand_regs{  
  17.     unsigned long nfconf;  
  18.     unsigned long nfcont;  
  19.     unsigned long nfcmmd;  
  20.     unsigned long nfaddr;  
  21.     unsigned long nfdata;  
  22.     unsigned long nfmeccd0;  
  23.     unsigned long nfmeccd1;  
  24.     unsigned long nfseccd;  
  25.     unsigned long nfsblk;  
  26.     unsigned long nfeblk;  
  27.     unsigned long nfstat;  
  28.     unsigned long nfeccerr0;  
  29.     unsigned long nfeccerr1;  
  30.     unsigned long nfmecc0;  
  31.     unsigned long nfmecc1;  
  32.     unsigned long nfsecc;  
  33.     unsigned long nfmlcbitpt;  
  34. };  
  35.   
  36. static volatile struct s5p_nand_regs *s5p_nand_regs;  
  37. static struct nand_chip *nand_chip;  
  38. static struct mtd_info *s5p_mtd_info;  
  39. static struct clk *s5p_nand_clk;  
  40. static int eccmode;  
  41.   
  42. static struct nand_ecclayout s5p_nand_oob_64 = {  
  43.     .eccbytes = 16,  
  44.     .eccpos = {  
  45.         40, 41, 42, 43, 44, 45, 46, 47,  
  46.         48, 49, 50, 51, 52, 53, 54, 55  
  47.     },  
  48.     .oobfree = {  
  49.         {  
  50.         .offset = 2,  
  51.         .length = 38  
  52.         }  
  53.     }  
  54. };  
  55.   
  56. static struct mtd_partition s5p_nand_partions[] = {  
  57.     [0] = {  
  58.         .name   = "bootloader",  
  59.         .offset = 0,  
  60.         .size   = SZ_1M,  
  61.     },  
  62.   
  63.     [1] = {  
  64.         .name   = "kernel",  
  65.         .offset = MTDPART_OFS_APPEND,  
  66.         .size   = 5*SZ_1M,  
  67.     },  
  68.   
  69.     [2] = {  
  70.         .name   = "rootfs",  
  71.         .offset = MTDPART_OFS_APPEND,  
  72.         .size   = MTDPART_SIZ_FULL,  
  73.     },  
  74. };  
  75.   
  76. static void s5p_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)  
  77. {  
  78.     if (ctrl & NAND_CTRL_CHANGE) {  
  79.         if (ctrl & NAND_NCE) {  
  80.             if (cmd != NAND_CMD_NONE) {  
  81.                 s5p_nand_regs->nfcont &= ~(1<<1);  
  82.             }  
  83.         } else {  
  84.             s5p_nand_regs->nfcont |= (1<<1);  
  85.         }  
  86.     }  
  87.   
  88.     if (cmd != NAND_CMD_NONE) {  
  89.         if (ctrl & NAND_CLE)  
  90.             s5p_nand_regs->nfcmmd = cmd;  
  91.         else if (ctrl & NAND_ALE)  
  92.             s5p_nand_regs->nfaddr = cmd;  
  93.     }  
  94. }  
  95.   
  96. static int s5p_nand_ready(struct mtd_info *mtd){  
  97.     return (s5p_nand_regs->nfstat & 0x1);  
  98. }  
  99.   
  100. static void s5p_ecc_hwctl(struct mtd_info *mtd, int mode){  
  101.   
  102.     eccmode = mode;  
  103.   
  104.     s5p_nand_regs->nfconf &= ~(0x3 << 23);  
  105.   
  106.     /* Init main ECC & unlock */  
  107.     s5p_nand_regs->nfcont |= NFCONT_INITMECC;  
  108.     s5p_nand_regs->nfcont &= ~NFCONT_MECCLOCK;  
  109. }  
  110.   
  111. static int s5p_ecc_calculate(struct mtd_info *mtd, const uint8_t *dat,  
  112.             uint8_t *ecc_code){  
  113.               
  114.     unsigned long nfmecc0 = s5p_nand_regs->nfmecc0;  
  115.   
  116.     /* Lock */  
  117.     s5p_nand_regs->nfcont |= NFCONT_MECCLOCK;  
  118.   
  119.     ecc_code[0] = (nfmecc0)&0xff;  
  120.     ecc_code[1] = (nfmecc0>>8)&0xff;  
  121.     ecc_code[2] = (nfmecc0>>16)&0xff;  
  122.     ecc_code[3] = (nfmecc0>>24)&0xff;  
  123.       
  124.     return 0;  
  125. }  
  126.   
  127. static int s5p_ecc_correct(struct mtd_info *mtd, uint8_t *dat, uint8_t *read_ecc, uint8_t *calc_ecc){  
  128.     unsigned nfmeccd0, nfmeccd1;  
  129.     unsigned long nfeccerr0;  
  130.   
  131.     nfmeccd0 = (read_ecc[1]<<16)|read_ecc[0];  
  132.     nfmeccd1 = (read_ecc[3]<<16)|read_ecc[2];  
  133.   
  134.     s5p_nand_regs->nfmeccd0 = nfmeccd0;  
  135.     s5p_nand_regs->nfmeccd1 = nfmeccd1;  
  136.   
  137.     nfeccerr0 = s5p_nand_regs->nfeccerr0;  
  138.   
  139.     switch(nfeccerr0&0x3){  
  140.         case 0:  
  141.             return 0;  
  142.         case 1:  
  143.             printk("s5p-nand: detected one bit error\n");  
  144.             dat[(nfeccerr0>>7)&0x7ff] ^= 1<<((nfeccerr0>>4)&0x3);  
  145.             return 1;  
  146.         case 2:  
  147.         case 3:  
  148.             printk("s5p-nand: detected uncorrected error\n");  
  149.             return 3;  
  150.   
  151.         default:  
  152.             return -EIO;  
  153.     }  
  154. }  
  155.   
  156. static int s5p_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,  
  157.                 uint8_t *buf, int oob_required, int page)  
  158. {  
  159.     int i, stat, eccsize = chip->ecc.size;  
  160.     int eccbytes = chip->ecc.bytes;  
  161.     int eccsteps = chip->ecc.steps;  
  162.     int secc_start = mtd->oobsize - eccbytes;  
  163.     int col = 0;  
  164.     uint8_t *p = buf;  
  165.     uint32_t *mecc_pos = chip->ecc.layout->eccpos;  
  166.     uint8_t *ecc_calc = chip->buffers->ecccalc;  
  167.       
  168.     col = mtd->writesize;  
  169.     chip->cmdfunc(mtd, NAND_CMD_RNDOUT, col, -1);  
  170.   
  171.     /* spare area */  
  172.     chip->ecc.hwctl(mtd, NAND_ECC_READ);  
  173.     chip->read_buf(mtd, chip->oob_poi, secc_start);  
  174.     chip->ecc.calculate(mtd, p, &ecc_calc[chip->ecc.total]);  
  175.     chip->read_buf(mtd, chip->oob_poi + secc_start, eccbytes);  
  176.   
  177.     col = 0;  
  178.   
  179.     /* main area */  
  180.     for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {  
  181.         chip->cmdfunc(mtd, NAND_CMD_RNDOUT, col, -1);  
  182.         chip->ecc.hwctl(mtd, NAND_ECC_READ);  
  183.         chip->read_buf(mtd, p, eccsize);  
  184.         chip->ecc.calculate(mtd, p, &ecc_calc[i]);  
  185.   
  186.         stat = chip->ecc.correct(mtd, p, chip->oob_poi + mecc_pos[0] +  
  187.                 ((chip->ecc.steps - eccsteps) * eccbytes), 0);  
  188.         if (stat == -1)  
  189.             mtd->ecc_stats.failed++;  
  190.   
  191.         col = eccsize * (chip->ecc.steps + 1 - eccsteps);  
  192.     }  
  193.       
  194.     return 0;  
  195. }  
  196.   
  197. static int s5p_nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,  
  198.                   const uint8_t *buf, int oob_required)  
  199. {  
  200.     int i, eccsize = chip->ecc.size;  
  201.     int eccbytes = chip->ecc.bytes;  
  202.     int eccsteps = chip->ecc.steps;  
  203.     int secc_start = mtd->oobsize - eccbytes;  
  204.     uint8_t *ecc_calc = chip->buffers->ecccalc;  
  205.     const uint8_t *p = buf;  
  206.   
  207.     uint32_t *eccpos = chip->ecc.layout->eccpos;  
  208.   
  209.     /* main area */  
  210.     for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {  
  211.         chip->ecc.hwctl(mtd, NAND_ECC_WRITE);  
  212.         chip->write_buf(mtd, p, eccsize);  
  213.         chip->ecc.calculate(mtd, p, &ecc_calc[i]);  
  214.     }  
  215.   
  216.     for (i = 0; i < chip->ecc.total; i++)  
  217.         chip->oob_poi[eccpos[i]] = ecc_calc[i];  
  218.   
  219.     /* spare area */  
  220.     chip->ecc.hwctl(mtd, NAND_ECC_WRITE);  
  221.     chip->write_buf(mtd, chip->oob_poi, secc_start);  
  222.     chip->ecc.calculate(mtd, p, &ecc_calc[chip->ecc.total]);  
  223.   
  224.     for (i = 0; i < eccbytes; i++)  
  225.         chip->oob_poi[secc_start + i] = ecc_calc[chip->ecc.total + i];  
  226.   
  227.     chip->write_buf(mtd, chip->oob_poi + secc_start, eccbytes);  
  228.   
  229.     return 0;  
  230. }  
  231.   
  232. static int s5p_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,  
  233.                  int page)  
  234. {  
  235.     uint8_t *ecc_calc = chip->buffers->ecccalc;  
  236.     int eccbytes = chip->ecc.bytes;  
  237.     int secc_start = mtd->oobsize - eccbytes;  
  238.       
  239.     chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);  
  240.     chip->ecc.hwctl(mtd, NAND_ECC_READ);  
  241.     chip->read_buf(mtd, chip->oob_poi, secc_start);  
  242.     chip->ecc.calculate(mtd, 0, &ecc_calc[chip->ecc.total]);  
  243.     chip->read_buf(mtd, chip->oob_poi + secc_start, eccbytes);  
  244.       
  245.     return 0;  
  246. }  
  247.   
  248. static int s5p_nand_write_oob(struct mtd_info *mtd, struct nand_chip *chip,  
  249.                   int page)  
  250. {  
  251.     int status = 0;  
  252.     int eccbytes = chip->ecc.bytes;  
  253.     int secc_start = mtd->oobsize - eccbytes;  
  254.     uint8_t *ecc_calc = chip->buffers->ecccalc;  
  255.     int i;  
  256.   
  257.     chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page);  
  258.   
  259.     /* spare area */  
  260.     chip->ecc.hwctl(mtd, NAND_ECC_WRITE);  
  261.     chip->write_buf(mtd, chip->oob_poi, secc_start);  
  262.     chip->ecc.calculate(mtd, 0, &ecc_calc[chip->ecc.total]);  
  263.   
  264.     for (i = 0; i < eccbytes; i++)  
  265.         chip->oob_poi[secc_start + i] = ecc_calc[chip->ecc.total + i];  
  266.   
  267.     chip->write_buf(mtd, chip->oob_poi + secc_start, eccbytes);  
  268.       
  269.     /* Send command to program the OOB data */  
  270.     chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);  
  271.   
  272.     status = chip->waitfunc(mtd, chip);  
  273.   
  274.     return status & NAND_STATUS_FAIL ? -EIO : 0;  
  275. }  
  276.   
  277.   
  278. static int s5p_nand_probe(struct platform_device *pdev){  
  279.     int ret = 0;  
  280.     struct resource *mem;  
  281.     //硬件部分初始化  
  282.     mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);  
  283.     if (!mem) {  
  284.         dev_err(&pdev->dev, "can't get I/O resource mem\n");  
  285.         return -ENXIO;  
  286.     }  
  287.       
  288.     s5p_nand_regs = (volatile struct s5p_nand_regs *)ioremap(mem->start, resource_size(mem));  
  289.     if (s5p_nand_regs == NULL) {  
  290.         dev_err(&pdev->dev, "ioremap failed\n");  
  291.         ret = -EIO;  
  292.         goto err_exit;  
  293.     }  
  294.       
  295.     s5p_nand_clk = clk_get(&pdev->dev, "nand");  
  296.     if(s5p_nand_clk == NULL){  
  297.         dev_dbg(&pdev->dev, "get clk failed\n");  
  298.         ret = -ENODEV;  
  299.         goto err_iounmap;  
  300.     }  
  301.   
  302.     clk_enable(s5p_nand_clk);  
  303.   
  304.     //s5p_nand_regs->nfconf &= ~(0xfff<<4);  
  305.     //s5p_nand_regs->nfconf |= (3<<12)|(5<<8)|(3<<4);  
  306.     //s5p_nand_regs->nfcont |= 3;  
  307.   
  308.     //分配驱动相关结构体  
  309.     nand_chip = (struct nand_chip *)kzalloc(sizeof(struct nand_chip), GFP_KERNEL);  
  310.     if(nand_chip == NULL){  
  311.         dev_err(&pdev->dev, "failed to allocate nand_chip structure\n");  
  312.         ret = -ENOMEM;  
  313.         goto err_clk_put;  
  314.     }  
  315.   
  316.     s5p_mtd_info = (struct mtd_info *)kzalloc(sizeof(struct mtd_info), GFP_KERNEL);  
  317.     if(s5p_mtd_info == NULL){  
  318.         dev_err(&pdev->dev, "failed to allocate mtd_info structure\n");  
  319.         ret = -ENOMEM;  
  320.         goto err_free_chip;  
  321.     }  
  322.   
  323.     //设置驱动相关结构体  
  324.     nand_chip->IO_ADDR_R   = (unsigned char*)&s5p_nand_regs->nfdata;  
  325.     nand_chip->IO_ADDR_W   = (unsigned char*)&s5p_nand_regs->nfdata;  
  326.       
  327.     nand_chip->cmd_ctrl    = s5p_nand_cmd_ctrl;  
  328.     nand_chip->dev_ready   = s5p_nand_ready;  
  329.       
  330.     nand_chip->ecc.mode    = NAND_ECC_HW;  
  331.     nand_chip->ecc.hwctl   = s5p_ecc_hwctl;  
  332.     nand_chip->ecc.calculate = s5p_ecc_calculate;  
  333.     nand_chip->ecc.correct   = s5p_ecc_correct;  
  334.       
  335.     nand_chip->ecc.read_oob   = s5p_nand_read_oob;  
  336.     nand_chip->ecc.write_oob  = s5p_nand_write_oob;  
  337.     nand_chip->ecc.read_page  = s5p_nand_read_page;  
  338.     nand_chip->ecc.write_page = s5p_nand_write_page;  
  339.     nand_chip->ecc.size       = 512;  
  340.     nand_chip->ecc.bytes      = 4;  
  341.     nand_chip->ecc.strength   = 1;  
  342.     nand_chip->ecc.layout = &s5p_nand_oob_64;  
  343.   
  344.     s5p_mtd_info->priv = nand_chip;  
  345.     s5p_mtd_info->owner = THIS_MODULE;  
  346.   
  347.     //扫描Nand flash 设备  
  348.     if(nand_scan(s5p_mtd_info, 1)){  
  349.         dev_dbg(&pdev->dev, "nand scan error\n");  
  350.         goto err_free_info;  
  351.     }  
  352.   
  353.     //添加分区信息  
  354.     ret = mtd_device_parse_register(s5p_mtd_info, NULL, NULL, s5p_nand_partions, ARRAY_SIZE(s5p_nand_partions));  
  355.     if(!ret)  
  356.         return 0;  
  357.   
  358. err_free_info:  
  359.     kfree(s5p_mtd_info);  
  360. err_free_chip:  
  361.     kfree(nand_chip);  
  362. err_clk_put:  
  363.     clk_disable(s5p_nand_clk);  
  364.     clk_put(s5p_nand_clk);  
  365. err_iounmap:  
  366.     iounmap(s5p_nand_regs);  
  367. err_exit:  
  368.     return ret;  
  369. }  
  370.   
  371. static int s5p_nand_remove(struct platform_device *pdev){  
  372.     nand_release(s5p_mtd_info);  
  373.     kfree(s5p_mtd_info);  
  374.     kfree(nand_chip);  
  375.   
  376.     clk_disable(s5p_nand_clk);  
  377.     clk_put(s5p_nand_clk);  
  378.   
  379.     iounmap(s5p_nand_regs);  
  380.     return 0;  
  381. }  
  382.   
  383. static struct platform_driver s5p_nand_drv = {  
  384.     .driver = {  
  385.         .owner = THIS_MODULE,  
  386.         .name = "s5p-nand",  
  387.     },  
  388.     .probe = s5p_nand_probe,  
  389.     .remove = s5p_nand_remove,  
  390. };  
  391.   
  392. module_platform_driver(s5p_nand_drv);  
  393. MODULE_LICENSE("GPL");  

接下来的几天我会继续调试一下8位HWECC,不知道能不能调好,从天嵌技术支持那里获悉,天嵌技术人员当时也调试过8位HWECC,他们从三星的某个资料中发现S5PV210的HWECC模块只能使用1位HWECC,不知道是不是真的,我要自己来验证一下。

如果有什么问题欢迎留言讨论,转载原来那篇HWECC文章的朋友请自己修正一下吧。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值