S5PV210(TQ210)學(xué)習(xí)筆記——Nand驅(qū)動(dòng)之HWECC
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #defineNFCONT_MECCLOCK(1<<7)
- #defineNFCONT_SECCLOCK(1<<6)
- #defineNFCONT_INITMECC(1<<5)
- #defineNFCONT_INITSECC(1<<4)
- #defineNFCONT_INITECC(NFCONT_INITMECC|NFCONT_INITSECC)
- structs5p_nand_regs{
- unsignedlongnfconf;
- unsignedlongnfcont;
- unsignedlongnfcmmd;
- unsignedlongnfaddr;
- unsignedlongnfdata;
- unsignedlongnfmeccd0;
- unsignedlongnfmeccd1;
- unsignedlongnfseccd;
- unsignedlongnfsblk;
- unsignedlongnfeblk;
- unsignedlongnfstat;
- unsignedlongnfeccerr0;
- unsignedlongnfeccerr1;
- unsignedlongnfmecc0;
- unsignedlongnfmecc1;
- unsignedlongnfsecc;
- unsignedlongnfmlcbitpt;
- };
- staticvolatilestructs5p_nand_regs*s5p_nand_regs;
- staticstructnand_chip*nand_chip;
- staticstructmtd_info*s5p_mtd_info;
- staticstructclk*s5p_nand_clk;
- staticinteccmode;
- staticstructnand_ecclayouts5p_nand_oob_64={
- .eccbytes=16,
- .eccpos={
- 40,41,42,43,44,45,46,47,
- 48,49,50,51,52,53,54,55
- },
- .oobfree={
- {
- .offset=2,
- .length=38
- }
- }
- };
- staticstructmtd_partitions5p_nand_partions[]={
- [0]={
- .name="bootloader",
- .offset=0,
- .size=SZ_1M,
- },
- [1]={
- .name="kernel",
- .offset=MTDPART_OFS_APPEND,
- .size=5*SZ_1M,
- },
- [2]={
- .name="rootfs",
- .offset=MTDPART_OFS_APPEND,
- .size=MTDPART_SIZ_FULL,
- },
- };
- staticvoids5p_nand_cmd_ctrl(structmtd_info*mtd,intcmd,unsignedintctrl)
- {
- if(ctrl&NAND_CTRL_CHANGE){
- if(ctrl&NAND_NCE){
- if(cmd!=NAND_CMD_NONE){
- s5p_nand_regs->nfcont&=~(1<<1);
- }
- }else{
- s5p_nand_regs->nfcont|=(1<<1);
- }
- }
- if(cmd!=NAND_CMD_NONE){
- if(ctrl&NAND_CLE)
- s5p_nand_regs->nfcmmd=cmd;
- elseif(ctrl&NAND_ALE)
- s5p_nand_regs->nfaddr=cmd;
- }
- }
- staticints5p_nand_ready(structmtd_info*mtd){
- return(s5p_nand_regs->nfstat&0x1);
- }
- staticvoids5p_ecc_hwctl(structmtd_info*mtd,intmode){
- eccmode=mode;
- s5p_nand_regs->nfconf&=~(0x3<<23);
- /*InitmainECC&unlock*/
- s5p_nand_regs->nfcont|=NFCONT_INITMECC;
- s5p_nand_regs->nfcont&=~NFCONT_MECCLOCK;
- }
- staticints5p_ecc_calculate(structmtd_info*mtd,constuint8_t*dat,
- uint8_t*ecc_code){
- unsignedlongnfmecc0=s5p_nand_regs->nfmecc0;
- /*Lock*/
- s5p_nand_regs->nfcont|=NFCONT_MECCLOCK;
- ecc_code[0]=(nfmecc0)&0xff;
- ecc_code[1]=(nfmecc0>>8)&0xff;
- ecc_code[2]=(nfmecc0>>16)&0xff;
- ecc_code[3]=(nfmecc0>>24)&0xff;
- return0;
- }
- staticints5p_ecc_correct(structmtd_info*mtd,uint8_t*dat,uint8_t*read_ecc,uint8_t*calc_ecc){
- unsignednfmeccd0,nfmeccd1;
- unsignedlongnfeccerr0;
- nfmeccd0=(read_ecc[1]<<16)|read_ecc[0];
- nfmeccd1=(read_ecc[3]<<16)|read_ecc[2];
- s5p_nand_regs->nfmeccd0=nfmeccd0;
- s5p_nand_regs->nfmeccd1=nfmeccd1;
- nfeccerr0=s5p_nand_regs->nfeccerr0;
- switch(nfeccerr0&0x3){
- case0:
- return0;
- case1:
- printk("s5p-nand:detectedonebiterror");
- dat[(nfeccerr0>>7)&0x7ff]^=1<<((nfeccerr0>>4)&0x3);
- return1;
- case2:
- case3:
- printk("s5p-nand:detecteduncorrectederror");
- return3;
- default:
- return-EIO;
- }
- }
- staticints5p_nand_read_page(structmtd_info*mtd,structnand_chip*chip,
- uint8_t*buf,intoob_required,intpage)
- {
- inti,stat,eccsize=chip->ecc.size;
- inteccbytes=chip->ecc.bytes;
- inteccsteps=chip->ecc.steps;
- intsecc_start=mtd->oobsize-eccbytes;
- intcol=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);
- /*sparearea*/
- 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);
- col=0;
- /*mainarea*/
- 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);
- }
- return0;
- }
- staticints5p_nand_write_page(structmtd_info*mtd,structnand_chip*chip,
- constuint8_t*buf,intoob_required)
- {
- inti,eccsize=chip->ecc.size;
- inteccbytes=chip->ecc.bytes;
- inteccsteps=chip->ecc.steps;
- intsecc_start=mtd->oobsize-eccbytes;
- uint8_t*ecc_calc=chip->buffers->ecccalc;
- constuint8_t*p=buf;
- uint32_t*eccpos=chip->ecc.layout->eccpos;
- /*mainarea*/
- 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
ecc.total;i++) - chip->oob_poi[eccpos[i]]=ecc_calc[i];
- /*sparearea*/
- 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
- chip->oob_poi[secc_start+i]=ecc_calc[chip->ecc.total+i];
- chip->write_buf(mtd,chip->oob_poi+secc_start,eccbytes);
- return0;
- }
- staticints5p_nand_read_oob(structmtd_info*mtd,structnand_chip*chip,
- intpage)
- {
- uint8_t*ecc_calc=chip->buffers->ecccalc;
- inteccbytes=chip->ecc.bytes;
- intsecc_start=mtd->oobsize-eccbytes;
- chip->cmdfunc(mtd,NAND_CMD_READOOB,0,page);
- 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);
- return0;
- }
- staticints5p_nand_write_oob(structmtd_info*mtd,structnand_chip*chip,
- intpage)
- {
- intstatus=0;
- inteccbytes=chip->ecc.bytes;
- intsecc_start=mtd->oobsize-eccbytes;
- uint8_t*ecc_calc=chip->buffers->ecccalc;
- inti;
- chip->cmdfunc(mtd,NAND_CMD_SEQIN,mtd->writesize,page);
- /*sparearea*/
- 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
- chip->oob_poi[secc_start+i]=ecc_calc[chip->ecc.total+i];
- chip->write_buf(mtd,chip->oob_poi+secc_start,eccbytes);
- /*SendcommandtoprogramtheOOBdata*/
- chip->cmdfunc(mtd,NAND_CMD_PAGEPROG,-1,-1);
- status=chip->waitfunc(mtd,chip);
- returnstatus&NAND_STATUS_FAIL?-EIO:0;
- }
- staticints5p_nand_probe(structplatform_device*pdev){
- intret=0;
- structresource*mem;
- //硬件部分初始化
- mem=platform_get_resource(pdev,IORESOURCE_MEM,0);
- if(!mem){
- dev_err(&pdev->dev,"cantgetI/Oresourcemem");
- return-ENXIO;
- }
- s5p_nand_regs=(volatilestructs5p_nand_regs*)ioremap(mem->start,resource_size(mem));
- if(s5p_nand_regs==NULL){
- dev_err(&pdev->dev,"ioremapfailed");
- ret=-EIO;
- gotoerr_exit;
- }
- s5p_nand_clk=clk_get(&pdev->dev,"nand");
- if(s5p_nand_clk==NULL){
- dev_dbg(&pdev->dev,"getclkfailed");
- ret=-ENODEV;
- gotoerr_iounmap;
- }
- clk_enable(s5p_nand_clk);
- //s5p_nand_regs->nfconf&=~(0xfff<<4);
- //s5p_nand_regs->nfconf|=(3<<12)|(5<<8)|(3<<4);
- //s5p_nand_regs->nfcont|=3;
- //分配驅(qū)動(dòng)相關(guān)結(jié)構(gòu)體
- nand_chip=(structnand_chip*)kzalloc(sizeof(structnand_chip),GFP_KERNEL);
- if(nand_chip==NULL){
- dev_err(&pdev->dev,"failedtoallocatenand_chipstructure");
- ret=-ENOMEM;
- gotoerr_clk_put;
- }
- s5p_mtd_info=(structmtd_info*)kzalloc(sizeof(structmtd_info),GFP_KERNEL);
- if(s5p_mtd_info==NULL){
- dev_err(&pdev->dev,"failedtoallocatemtd_infostructure");
- ret=-ENOMEM;
- gotoerr_free_chip;
- }
- //設(shè)置驅(qū)動(dòng)相關(guān)結(jié)構(gòu)體
- nand_chip->IO_ADDR_R=(unsignedchar*)&s5p_nand_regs->nfdata;
- nand_chip->IO_ADDR_W=(unsignedchar*)&s5p_nand_regs->nfdata;
- nand_chip->cmd_ctrl=s5p_nand_cmd_ctrl;
- nand_chip->dev_ready=s5p_nand_ready;
- nand_chip->ecc.mode=NAND_ECC_HW;
- nand_chip->ecc.hwctl=s5p_ecc_hwctl;
- nand_chip->ecc.calculate=s5p_ecc_calculate;
- nand_chip->ecc.correct=s5p_ecc_correct;
- nand_chip->ecc.read_oob=s5p_nand_read_oob;
- nand_chip->ecc.write_oob=s5p_nand_write_oob;
- nand_chip->ecc.read_page=s5p_nand_read_page;
- nand_chip->ecc.write_page=s5p_nand_write_page;
- nand_chip->ecc.size=512;
- nand_chip->ecc.bytes=4;
- nand_chip->ecc.strength=1;
- nand_chip->ecc.layout=&s5p_nand_oob_64;
- s5p_mtd_info->priv=nand_chip;
- s5p_mtd_info->owner=THIS_MODULE;
- //掃描Nandflash設(shè)備
- if(nand_scan(s5p_mtd_info,1)){
- dev_dbg(&pdev->dev,"nandscanerror");
- gotoerr_free_info;
- }
- //添加分區(qū)信息
- ret=mtd_device_parse_register(s5p_mtd_info,NULL,NULL,s5p_nand_partions,ARRAY_SIZE(s5p_nand_partions));
- if(!ret)
- return0;
- err_free_info:
- kfree(s5p_mtd_info);
- err_free_chip:
- kfree(nand_chip);
- err_clk_put:
- clk_disable(s5p_nand_clk);
- clk_put(s5p_nand_clk);
- err_iounmap:
- iounmap(s5p_nand_regs);
- err_exit:
- returnret;
- }
- staticints5p_nand_remove(structplatform_device*pdev){
- nand_release(s5p_mtd_info);
- kfree(s5p_mtd_info);
- kfree(nand_chip);
- clk_disable(s5p_nand_clk);
- clk_put(s5p_nand_clk);
- iounmap(s5p_nand_regs);
- return0;
- }
- staticstructplatform_drivers5p_nand_drv={
- .driver={
- .owner=THIS_MODULE,
- .name="s5p-nand",
- },
- .probe=s5p_nand_probe,
- .remove=s5p_nand_remove,
- };
- module_platform_driver(s5p_nand_drv);
- MODULE_LICENSE("GPL");
接下來的幾天我會(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文章的朋友請自己修正一下吧。
評論