新聞中心

EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > S5PV210(TQ210)學(xué)習(xí)筆記——Nand驅(qū)動(dòng)之HWECC

S5PV210(TQ210)學(xué)習(xí)筆記——Nand驅(qū)動(dòng)之HWECC

作者: 時(shí)間:2016-11-28 來源:網(wǎng)絡(luò) 收藏
前幾天匆忙間發(fā)了一篇關(guān)于S5PV210的8位HWECC驅(qū)動(dòng)的文章,但是后來發(fā)現(xiàn)存在嚴(yán)重的Bug,就將原來那篇文章刪除了,這里先說聲抱歉,但是,HWECC能有效的節(jié)省CPU占用量,我仔細(xì)調(diào)試了S5PV210的HWECC部分,現(xiàn)在剛調(diào)好1位的HWECC,為了表示誤發(fā)原來那篇文章的歉意,現(xiàn)在將代碼放在這里,與大家分享:
  1. #include
  2. #include
  3. #include
  4. #include
  5. #include
  6. #include
  7. #include
  8. #include
  9. #defineNFCONT_MECCLOCK(1<<7)
  10. #defineNFCONT_SECCLOCK(1<<6)
  11. #defineNFCONT_INITMECC(1<<5)
  12. #defineNFCONT_INITSECC(1<<4)
  13. #defineNFCONT_INITECC(NFCONT_INITMECC|NFCONT_INITSECC)
  14. structs5p_nand_regs{
  15. unsignedlongnfconf;
  16. unsignedlongnfcont;
  17. unsignedlongnfcmmd;
  18. unsignedlongnfaddr;
  19. unsignedlongnfdata;
  20. unsignedlongnfmeccd0;
  21. unsignedlongnfmeccd1;
  22. unsignedlongnfseccd;
  23. unsignedlongnfsblk;
  24. unsignedlongnfeblk;
  25. unsignedlongnfstat;
  26. unsignedlongnfeccerr0;
  27. unsignedlongnfeccerr1;
  28. unsignedlongnfmecc0;
  29. unsignedlongnfmecc1;
  30. unsignedlongnfsecc;
  31. unsignedlongnfmlcbitpt;
  32. };
  33. staticvolatilestructs5p_nand_regs*s5p_nand_regs;
  34. staticstructnand_chip*nand_chip;
  35. staticstructmtd_info*s5p_mtd_info;
  36. staticstructclk*s5p_nand_clk;
  37. staticinteccmode;
  38. staticstructnand_ecclayouts5p_nand_oob_64={
  39. .eccbytes=16,
  40. .eccpos={
  41. 40,41,42,43,44,45,46,47,
  42. 48,49,50,51,52,53,54,55
  43. },
  44. .oobfree={
  45. {
  46. .offset=2,
  47. .length=38
  48. }
  49. }
  50. };
  51. staticstructmtd_partitions5p_nand_partions[]={
  52. [0]={
  53. .name="bootloader",
  54. .offset=0,
  55. .size=SZ_1M,
  56. },
  57. [1]={
  58. .name="kernel",
  59. .offset=MTDPART_OFS_APPEND,
  60. .size=5*SZ_1M,
  61. },
  62. [2]={
  63. .name="rootfs",
  64. .offset=MTDPART_OFS_APPEND,
  65. .size=MTDPART_SIZ_FULL,
  66. },
  67. };
  68. staticvoids5p_nand_cmd_ctrl(structmtd_info*mtd,intcmd,unsignedintctrl)
  69. {
  70. if(ctrl&NAND_CTRL_CHANGE){
  71. if(ctrl&NAND_NCE){
  72. if(cmd!=NAND_CMD_NONE){
  73. s5p_nand_regs->nfcont&=~(1<<1);
  74. }
  75. }else{
  76. s5p_nand_regs->nfcont|=(1<<1);
  77. }
  78. }
  79. if(cmd!=NAND_CMD_NONE){
  80. if(ctrl&NAND_CLE)
  81. s5p_nand_regs->nfcmmd=cmd;
  82. elseif(ctrl&NAND_ALE)
  83. s5p_nand_regs->nfaddr=cmd;
  84. }
  85. }
  86. staticints5p_nand_ready(structmtd_info*mtd){
  87. return(s5p_nand_regs->nfstat&0x1);
  88. }
  89. staticvoids5p_ecc_hwctl(structmtd_info*mtd,intmode){
  90. eccmode=mode;
  91. s5p_nand_regs->nfconf&=~(0x3<<23);
  92. /*InitmainECC&unlock*/
  93. s5p_nand_regs->nfcont|=NFCONT_INITMECC;
  94. s5p_nand_regs->nfcont&=~NFCONT_MECCLOCK;
  95. }
  96. staticints5p_ecc_calculate(structmtd_info*mtd,constuint8_t*dat,
  97. uint8_t*ecc_code){
  98. unsignedlongnfmecc0=s5p_nand_regs->nfmecc0;
  99. /*Lock*/
  100. s5p_nand_regs->nfcont|=NFCONT_MECCLOCK;
  101. ecc_code[0]=(nfmecc0)&0xff;
  102. ecc_code[1]=(nfmecc0>>8)&0xff;
  103. ecc_code[2]=(nfmecc0>>16)&0xff;
  104. ecc_code[3]=(nfmecc0>>24)&0xff;
  105. return0;
  106. }
  107. staticints5p_ecc_correct(structmtd_info*mtd,uint8_t*dat,uint8_t*read_ecc,uint8_t*calc_ecc){
  108. unsignednfmeccd0,nfmeccd1;
  109. unsignedlongnfeccerr0;
  110. nfmeccd0=(read_ecc[1]<<16)|read_ecc[0];
  111. nfmeccd1=(read_ecc[3]<<16)|read_ecc[2];
  112. s5p_nand_regs->nfmeccd0=nfmeccd0;
  113. s5p_nand_regs->nfmeccd1=nfmeccd1;
  114. nfeccerr0=s5p_nand_regs->nfeccerr0;
  115. switch(nfeccerr0&0x3){
  116. case0:
  117. return0;
  118. case1:
  119. printk("s5p-nand:detectedonebiterror");
  120. dat[(nfeccerr0>>7)&0x7ff]^=1<<((nfeccerr0>>4)&0x3);
  121. return1;
  122. case2:
  123. case3:
  124. printk("s5p-nand:detecteduncorrectederror");
  125. return3;
  126. default:
  127. return-EIO;
  128. }
  129. }
  130. staticints5p_nand_read_page(structmtd_info*mtd,structnand_chip*chip,
  131. uint8_t*buf,intoob_required,intpage)
  132. {
  133. inti,stat,eccsize=chip->ecc.size;
  134. inteccbytes=chip->ecc.bytes;
  135. inteccsteps=chip->ecc.steps;
  136. intsecc_start=mtd->oobsize-eccbytes;
  137. intcol=0;
  138. uint8_t*p=buf;
  139. uint32_t*mecc_pos=chip->ecc.layout->eccpos;
  140. uint8_t*ecc_calc=chip->buffers->ecccalc;
  141. col=mtd->writesize;
  142. chip->cmdfunc(mtd,NAND_CMD_RNDOUT,col,-1);
  143. /*sparearea*/
  144. chip->ecc.hwctl(mtd,NAND_ECC_READ);
  145. chip->read_buf(mtd,chip->oob_poi,secc_start);
  146. chip->ecc.calculate(mtd,p,&ecc_calc[chip->ecc.total]);
  147. chip->read_buf(mtd,chip->oob_poi+secc_start,eccbytes);
  148. col=0;
  149. /*mainarea*/
  150. for(i=0;eccsteps;eccsteps--,i+=eccbytes,p+=eccsize){
  151. chip->cmdfunc(mtd,NAND_CMD_RNDOUT,col,-1);
  152. chip->ecc.hwctl(mtd,NAND_ECC_READ);
  153. chip->read_buf(mtd,p,eccsize);
  154. chip->ecc.calculate(mtd,p,&ecc_calc[i]);
  155. stat=chip->ecc.correct(mtd,p,chip->oob_poi+mecc_pos[0]+
  156. ((chip->ecc.steps-eccsteps)*eccbytes),0);
  157. if(stat==-1)
  158. mtd->ecc_stats.failed++;
  159. col=eccsize*(chip->ecc.steps+1-eccsteps);
  160. }
  161. return0;
  162. }
  163. staticints5p_nand_write_page(structmtd_info*mtd,structnand_chip*chip,
  164. constuint8_t*buf,intoob_required)
  165. {
  166. inti,eccsize=chip->ecc.size;
  167. inteccbytes=chip->ecc.bytes;
  168. inteccsteps=chip->ecc.steps;
  169. intsecc_start=mtd->oobsize-eccbytes;
  170. uint8_t*ecc_calc=chip->buffers->ecccalc;
  171. constuint8_t*p=buf;
  172. uint32_t*eccpos=chip->ecc.layout->eccpos;
  173. /*mainarea*/
  174. for(i=0;eccsteps;eccsteps--,i+=eccbytes,p+=eccsize){
  175. chip->ecc.hwctl(mtd,NAND_ECC_WRITE);
  176. chip->write_buf(mtd,p,eccsize);
  177. chip->ecc.calculate(mtd,p,&ecc_calc[i]);
  178. }
  179. for(i=0;iecc.total;i++)
  180. chip->oob_poi[eccpos[i]]=ecc_calc[i];
  181. /*sparearea*/
  182. chip->ecc.hwctl(mtd,NAND_ECC_WRITE);
  183. chip->write_buf(mtd,chip->oob_poi,secc_start);
  184. chip->ecc.calculate(mtd,p,&ecc_calc[chip->ecc.total]);
  185. for(i=0;i
  186. chip->oob_poi[secc_start+i]=ecc_calc[chip->ecc.total+i];
  187. chip->write_buf(mtd,chip->oob_poi+secc_start,eccbytes);
  188. return0;
  189. }
  190. staticints5p_nand_read_oob(structmtd_info*mtd,structnand_chip*chip,
  191. intpage)
  192. {
  193. uint8_t*ecc_calc=chip->buffers->ecccalc;
  194. inteccbytes=chip->ecc.bytes;
  195. intsecc_start=mtd->oobsize-eccbytes;
  196. chip->cmdfunc(mtd,NAND_CMD_READOOB,0,page);
  197. chip->ecc.hwctl(mtd,NAND_ECC_READ);
  198. chip->read_buf(mtd,chip->oob_poi,secc_start);
  199. chip->ecc.calculate(mtd,0,&ecc_calc[chip->ecc.total]);
  200. chip->read_buf(mtd,chip->oob_poi+secc_start,eccbytes);
  201. return0;
  202. }
  203. staticints5p_nand_write_oob(structmtd_info*mtd,structnand_chip*chip,
  204. intpage)
  205. {
  206. intstatus=0;
  207. inteccbytes=chip->ecc.bytes;
  208. intsecc_start=mtd->oobsize-eccbytes;
  209. uint8_t*ecc_calc=chip->buffers->ecccalc;
  210. inti;
  211. chip->cmdfunc(mtd,NAND_CMD_SEQIN,mtd->writesize,page);
  212. /*sparearea*/
  213. chip->ecc.hwctl(mtd,NAND_ECC_WRITE);
  214. chip->write_buf(mtd,chip->oob_poi,secc_start);
  215. chip->ecc.calculate(mtd,0,&ecc_calc[chip->ecc.total]);
  216. for(i=0;i
  217. chip->oob_poi[secc_start+i]=ecc_calc[chip->ecc.total+i];
  218. chip->write_buf(mtd,chip->oob_poi+secc_start,eccbytes);
  219. /*SendcommandtoprogramtheOOBdata*/
  220. chip->cmdfunc(mtd,NAND_CMD_PAGEPROG,-1,-1);
  221. status=chip->waitfunc(mtd,chip);
  222. returnstatus&NAND_STATUS_FAIL?-EIO:0;
  223. }
  224. staticints5p_nand_probe(structplatform_device*pdev){
  225. intret=0;
  226. structresource*mem;
  227. //硬件部分初始化
  228. mem=platform_get_resource(pdev,IORESOURCE_MEM,0);
  229. if(!mem){
  230. dev_err(&pdev->dev,"cantgetI/Oresourcemem");
  231. return-ENXIO;
  232. }
  233. s5p_nand_regs=(volatilestructs5p_nand_regs*)ioremap(mem->start,resource_size(mem));
  234. if(s5p_nand_regs==NULL){
  235. dev_err(&pdev->dev,"ioremapfailed");
  236. ret=-EIO;
  237. gotoerr_exit;
  238. }
  239. s5p_nand_clk=clk_get(&pdev->dev,"nand");
  240. if(s5p_nand_clk==NULL){
  241. dev_dbg(&pdev->dev,"getclkfailed");
  242. ret=-ENODEV;
  243. gotoerr_iounmap;
  244. }
  245. clk_enable(s5p_nand_clk);
  246. //s5p_nand_regs->nfconf&=~(0xfff<<4);
  247. //s5p_nand_regs->nfconf|=(3<<12)|(5<<8)|(3<<4);
  248. //s5p_nand_regs->nfcont|=3;
  249. //分配驅(qū)動(dòng)相關(guān)結(jié)構(gòu)體
  250. nand_chip=(structnand_chip*)kzalloc(sizeof(structnand_chip),GFP_KERNEL);
  251. if(nand_chip==NULL){
  252. dev_err(&pdev->dev,"failedtoallocatenand_chipstructure");
  253. ret=-ENOMEM;
  254. gotoerr_clk_put;
  255. }
  256. s5p_mtd_info=(structmtd_info*)kzalloc(sizeof(structmtd_info),GFP_KERNEL);
  257. if(s5p_mtd_info==NULL){
  258. dev_err(&pdev->dev,"failedtoallocatemtd_infostructure");
  259. ret=-ENOMEM;
  260. gotoerr_free_chip;
  261. }
  262. //設(shè)置驅(qū)動(dòng)相關(guān)結(jié)構(gòu)體
  263. nand_chip->IO_ADDR_R=(unsignedchar*)&s5p_nand_regs->nfdata;
  264. nand_chip->IO_ADDR_W=(unsignedchar*)&s5p_nand_regs->nfdata;
  265. nand_chip->cmd_ctrl=s5p_nand_cmd_ctrl;
  266. nand_chip->dev_ready=s5p_nand_ready;
  267. nand_chip->ecc.mode=NAND_ECC_HW;
  268. nand_chip->ecc.hwctl=s5p_ecc_hwctl;
  269. nand_chip->ecc.calculate=s5p_ecc_calculate;
  270. nand_chip->ecc.correct=s5p_ecc_correct;
  271. nand_chip->ecc.read_oob=s5p_nand_read_oob;
  272. nand_chip->ecc.write_oob=s5p_nand_write_oob;
  273. nand_chip->ecc.read_page=s5p_nand_read_page;
  274. nand_chip->ecc.write_page=s5p_nand_write_page;
  275. nand_chip->ecc.size=512;
  276. nand_chip->ecc.bytes=4;
  277. nand_chip->ecc.strength=1;
  278. nand_chip->ecc.layout=&s5p_nand_oob_64;
  279. s5p_mtd_info->priv=nand_chip;
  280. s5p_mtd_info->owner=THIS_MODULE;
  281. //掃描Nandflash設(shè)備
  282. if(nand_scan(s5p_mtd_info,1)){
  283. dev_dbg(&pdev->dev,"nandscanerror");
  284. gotoerr_free_info;
  285. }
  286. //添加分區(qū)信息
  287. ret=mtd_device_parse_register(s5p_mtd_info,NULL,NULL,s5p_nand_partions,ARRAY_SIZE(s5p_nand_partions));
  288. if(!ret)
  289. return0;
  290. err_free_info:
  291. kfree(s5p_mtd_info);
  292. err_free_chip:
  293. kfree(nand_chip);
  294. err_clk_put:
  295. clk_disable(s5p_nand_clk);
  296. clk_put(s5p_nand_clk);
  297. err_iounmap:
  298. iounmap(s5p_nand_regs);
  299. err_exit:
  300. returnret;
  301. }
  302. staticints5p_nand_remove(structplatform_device*pdev){
  303. nand_release(s5p_mtd_info);
  304. kfree(s5p_mtd_info);
  305. kfree(nand_chip);
  306. clk_disable(s5p_nand_clk);
  307. clk_put(s5p_nand_clk);
  308. iounmap(s5p_nand_regs);
  309. return0;
  310. }
  311. staticstructplatform_drivers5p_nand_drv={
  312. .driver={
  313. .owner=THIS_MODULE,
  314. .name="s5p-nand",
  315. },
  316. .probe=s5p_nand_probe,
  317. .remove=s5p_nand_remove,
  318. };
  319. module_platform_driver(s5p_nand_drv);
  320. MODULE_LICENSE("GPL");

本文引用地址:http://m.butianyuan.cn/article/201611/322813.htm

接下來的幾天我會(huì)繼續(xù)調(diào)試一下8位HWECC,不知道能不能調(diào)好,從天嵌技術(shù)支持那里獲悉,天嵌技術(shù)人員當(dāng)時(shí)也調(diào)試過8位HWECC,他們從三星的某個(gè)資料中發(fā)現(xiàn)S5PV210的HWECC模塊只能使用1位HWECC,不知道是不是真的,我要自己來驗(yàn)證一下。

如果有什么問題歡迎留言討論,轉(zhuǎn)載原來那篇HWECC文章的朋友請自己修正一下吧。



評論


技術(shù)專區(qū)

關(guān)閉