?? diskonchip.c
字號:
WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, ECCConf); break; }}static void doc2001plus_enable_hwecc(struct mtd_info *mtd, int mode){ struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; void __iomem *docptr = doc->virtadr; /* Prime the ECC engine */ switch(mode) { case NAND_ECC_READ: WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf); WriteDOC(DOC_ECC_EN, docptr, Mplus_ECCConf); break; case NAND_ECC_WRITE: WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf); WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, Mplus_ECCConf); break; }}/* This code is only called on write */static int doc200x_calculate_ecc(struct mtd_info *mtd, const u_char *dat, unsigned char *ecc_code){ struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; void __iomem *docptr = doc->virtadr; int i; int emptymatch = 1; /* flush the pipeline */ if (DoC_is_2000(doc)) { WriteDOC(doc->CDSNControl & ~CDSN_CTRL_FLASH_IO, docptr, CDSNControl); WriteDOC(0, docptr, 2k_CDSN_IO); WriteDOC(0, docptr, 2k_CDSN_IO); WriteDOC(0, docptr, 2k_CDSN_IO); WriteDOC(doc->CDSNControl, docptr, CDSNControl); } else if (DoC_is_MillenniumPlus(doc)) { WriteDOC(0, docptr, Mplus_NOP); WriteDOC(0, docptr, Mplus_NOP); WriteDOC(0, docptr, Mplus_NOP); } else { WriteDOC(0, docptr, NOP); WriteDOC(0, docptr, NOP); WriteDOC(0, docptr, NOP); } for (i = 0; i < 6; i++) { if (DoC_is_MillenniumPlus(doc)) ecc_code[i] = ReadDOC_(docptr, DoC_Mplus_ECCSyndrome0 + i); else ecc_code[i] = ReadDOC_(docptr, DoC_ECCSyndrome0 + i); if (ecc_code[i] != empty_write_ecc[i]) emptymatch = 0; } if (DoC_is_MillenniumPlus(doc)) WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf); else WriteDOC(DOC_ECC_DIS, docptr, ECCConf);#if 0 /* If emptymatch=1, we might have an all-0xff data buffer. Check. */ if (emptymatch) { /* Note: this somewhat expensive test should not be triggered often. It could be optimized away by examining the data in the writebuf routine, and remembering the result. */ for (i = 0; i < 512; i++) { if (dat[i] == 0xff) continue; emptymatch = 0; break; } } /* If emptymatch still =1, we do have an all-0xff data buffer. Return all-0xff ecc value instead of the computed one, so it'll look just like a freshly-erased page. */ if (emptymatch) memset(ecc_code, 0xff, 6);#endif return 0;}static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc){ int i, ret = 0; struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; void __iomem *docptr = doc->virtadr; volatile u_char dummy; int emptymatch = 1; /* flush the pipeline */ if (DoC_is_2000(doc)) { dummy = ReadDOC(docptr, 2k_ECCStatus); dummy = ReadDOC(docptr, 2k_ECCStatus); dummy = ReadDOC(docptr, 2k_ECCStatus); } else if (DoC_is_MillenniumPlus(doc)) { dummy = ReadDOC(docptr, Mplus_ECCConf); dummy = ReadDOC(docptr, Mplus_ECCConf); dummy = ReadDOC(docptr, Mplus_ECCConf); } else { dummy = ReadDOC(docptr, ECCConf); dummy = ReadDOC(docptr, ECCConf); dummy = ReadDOC(docptr, ECCConf); } /* Error occured ? */ if (dummy & 0x80) { for (i = 0; i < 6; i++) { if (DoC_is_MillenniumPlus(doc)) calc_ecc[i] = ReadDOC_(docptr, DoC_Mplus_ECCSyndrome0 + i); else calc_ecc[i] = ReadDOC_(docptr, DoC_ECCSyndrome0 + i); if (calc_ecc[i] != empty_read_syndrome[i]) emptymatch = 0; } /* If emptymatch=1, the read syndrome is consistent with an all-0xff data and stored ecc block. Check the stored ecc. */ if (emptymatch) { for (i = 0; i < 6; i++) { if (read_ecc[i] == 0xff) continue; emptymatch = 0; break; } } /* If emptymatch still =1, check the data block. */ if (emptymatch) { /* Note: this somewhat expensive test should not be triggered often. It could be optimized away by examining the data in the readbuf routine, and remembering the result. */ for (i = 0; i < 512; i++) { if (dat[i] == 0xff) continue; emptymatch = 0; break; } } /* If emptymatch still =1, this is almost certainly a freshly- erased block, in which case the ECC will not come out right. We'll suppress the error and tell the caller everything's OK. Because it is. */ if (!emptymatch) ret = doc_ecc_decode (rs_decoder, dat, calc_ecc); if (ret > 0) printk(KERN_ERR "doc200x_correct_data corrected %d errors\n", ret); } if (DoC_is_MillenniumPlus(doc)) WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf); else WriteDOC(DOC_ECC_DIS, docptr, ECCConf); if (no_ecc_failures && (ret == -1)) { printk(KERN_ERR "suppressing ECC failure\n"); ret = 0; } return ret;}/*u_char mydatabuf[528]; */static struct nand_oobinfo doc200x_oobinfo = { .useecc = MTD_NANDECC_AUTOPLACE, .eccbytes = 6, .eccpos = {0, 1, 2, 3, 4, 5}, .oobfree = { {8, 8} }};/* Find the (I)NFTL Media Header, and optionally also the mirror media header. On sucessful return, buf will contain a copy of the media header for further processing. id is the string to scan for, and will presumably be either "ANAND" or "BNAND". If findmirror=1, also look for the mirror media header. The page #s of the found media headers are placed in mh0_page and mh1_page in the DOC private structure. */static int __init find_media_headers(struct mtd_info *mtd, u_char *buf, const char *id, int findmirror){ struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; unsigned offs, end = (MAX_MEDIAHEADER_SCAN << this->phys_erase_shift); int ret; size_t retlen; end = min(end, mtd->size); /* paranoia */ for (offs = 0; offs < end; offs += mtd->erasesize) { ret = mtd->read(mtd, offs, mtd->oobblock, &retlen, buf); if (retlen != mtd->oobblock) continue; if (ret) { printk(KERN_WARNING "ECC error scanning DOC at 0x%x\n", offs); } if (memcmp(buf, id, 6)) continue; printk(KERN_INFO "Found DiskOnChip %s Media Header at 0x%x\n", id, offs); if (doc->mh0_page == -1) { doc->mh0_page = offs >> this->page_shift; if (!findmirror) return 1; continue; } doc->mh1_page = offs >> this->page_shift; return 2; } if (doc->mh0_page == -1) { printk(KERN_WARNING "DiskOnChip %s Media Header not found.\n", id); return 0; } /* Only one mediaheader was found. We want buf to contain a mediaheader on return, so we'll have to re-read the one we found. */ offs = doc->mh0_page << this->page_shift; ret = mtd->read(mtd, offs, mtd->oobblock, &retlen, buf); if (retlen != mtd->oobblock) { /* Insanity. Give up. */ printk(KERN_ERR "Read DiskOnChip Media Header once, but can't reread it???\n"); return 0; } return 1;}static inline int __init nftl_partscan(struct mtd_info *mtd, struct mtd_partition *parts){ struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; int ret = 0; u_char *buf; struct NFTLMediaHeader *mh; const unsigned psize = 1 << this->page_shift; unsigned blocks, maxblocks; int offs, numheaders; buf = kmalloc(mtd->oobblock, GFP_KERNEL); if (!buf) { printk(KERN_ERR "DiskOnChip mediaheader kmalloc failed!\n"); return 0; } if (!(numheaders=find_media_headers(mtd, buf, "ANAND", 1))) goto out; mh = (struct NFTLMediaHeader *) buf;/*#ifdef CONFIG_MTD_DEBUG_VERBOSE *//* if (CONFIG_MTD_DEBUG_VERBOSE >= 2) */ printk(KERN_INFO " DataOrgID = %s\n" " NumEraseUnits = %d\n" " FirstPhysicalEUN = %d\n" " FormattedSize = %d\n" " UnitSizeFactor = %d\n", mh->DataOrgID, mh->NumEraseUnits, mh->FirstPhysicalEUN, mh->FormattedSize, mh->UnitSizeFactor);/*#endif */ blocks = mtd->size >> this->phys_erase_shift; maxblocks = min(32768U, mtd->erasesize - psize); if (mh->UnitSizeFactor == 0x00) { /* Auto-determine UnitSizeFactor. The constraints are: - There can be at most 32768 virtual blocks. - There can be at most (virtual block size - page size) virtual blocks (because MediaHeader+BBT must fit in 1). */ mh->UnitSizeFactor = 0xff; while (blocks > maxblocks) { blocks >>= 1; maxblocks = min(32768U, (maxblocks << 1) + psize); mh->UnitSizeFactor--; } printk(KERN_WARNING "UnitSizeFactor=0x00 detected. Correct value is assumed to be 0x%02x.\n", mh->UnitSizeFactor); } /* NOTE: The lines below modify internal variables of the NAND and MTD layers; variables with have already been configured by nand_scan. Unfortunately, we didn't know before this point what these values should be. Thus, this code is somewhat dependant on the exact implementation of the NAND layer. */ if (mh->UnitSizeFactor != 0xff) { this->bbt_erase_shift += (0xff - mh->UnitSizeFactor); mtd->erasesize <<= (0xff - mh->UnitSizeFactor); printk(KERN_INFO "Setting virtual erase size to %d\n", mtd->erasesize); blocks = mtd->size >> this->bbt_erase_shift; maxblocks = min(32768U, mtd->erasesize - psize); } if (blocks > maxblocks) { printk(KERN_ERR "UnitSizeFactor of 0x%02x is inconsistent with device size. Aborting.\n", mh->UnitSizeFactor); goto out; } /* Skip past the media headers. */ offs = max(doc->mh0_page, doc->mh1_page); offs <<= this->page_shift; offs += mtd->erasesize; /*parts[0].name = " DiskOnChip Boot / Media Header partition"; */ /*parts[0].offset = 0; */ /*parts[0].size = offs; */ parts[0].name = " DiskOnChip BDTL partition"; parts[0].offset = offs; parts[0].size = (mh->NumEraseUnits - numheaders) << this->bbt_erase_shift; offs += parts[0].size; if (offs < mtd->size) { parts[1].name = " DiskOnChip Remainder partition"; parts[1].offset = offs; parts[1].size = mtd->size - offs; ret = 2; goto out; } ret = 1;out: kfree(buf); return ret;}/* This is a stripped-down copy of the code in inftlmount.c */static inline int __init inftl_partscan(struct mtd_info *mtd, struct mtd_partition *parts){ struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; int ret = 0; u_char *buf; struct INFTLMediaHeader *mh; struct INFTLPartition *ip; int numparts = 0; int blocks; int vshift, lastvunit = 0; int i; int end = mtd->size; if (inftl_bbt_write) end -= (INFTL_BBT_RESERVED_BLOCKS << this->phys_erase_shift); buf = kmalloc(mtd->oobblock, GFP_KERNEL); if (!buf) { printk(KERN_ERR "DiskOnChip mediaheader kmalloc failed!\n"); return 0; } if (!find_media_headers(mtd, buf, "BNAND", 0)) goto out; doc->mh1_page = doc->mh0_page + (4096 >> this->page_shift); mh = (struct INFTLMediaHeader *) buf; mh->NoOfBootImageBlocks = le32_to_cpu(mh->NoOfBootImageBlocks); mh->NoOfBinaryPartitions = le32_to_cpu(mh->NoOfBinaryPartitions); mh->NoOfBDTLPartitions = le32_to_cpu(mh->NoOfBDTLPartitions); mh->BlockMultiplierBits = le32_to_cpu(mh->BlockMultiplierBits); mh->FormatFlags = le32_to_cpu(mh->FormatFlags); mh->PercentUsed = le32_to_cpu(mh->PercentUsed);/*#ifdef CONFIG_MTD_DEBUG_VERBOSE *//* if (CONFIG_MTD_DEBUG_VERBOSE >= 2) */ printk(KERN_INFO " bootRecordID = %s\n" " NoOfBootImageBlocks = %d\n" " NoOfBinaryPartitions = %d\n" " NoOfBDTLPartitions = %d\n" " BlockMultiplerBits = %d\n" " FormatFlgs = %d\n" " OsakVersion = %d.%d.%d.%d\n" " PercentUsed = %d\n", mh->bootRecordID, mh->NoOfBootImageBlocks, mh->NoOfBinaryPartitions, mh->NoOfBDTLPartitions, mh->BlockMultiplierBits, mh->FormatFlags, ((unsigned char *) &mh->OsakVersion)[0] & 0xf, ((unsigned char *) &mh->OsakVersion)[1] & 0xf, ((unsigned char *) &mh->OsakVersion)[2] & 0xf, ((unsigned char *) &mh->OsakVersion)[3] & 0xf, mh->PercentUsed);/*#endif */ vshift = this->phys_erase_shift + mh->BlockMultiplierBits; blocks = mtd->size >> vshift; if (blocks > 32768) { printk(KERN_ERR "BlockMultiplierBits=%d is inconsistent with device size. Aborting.\n", mh->BlockMultiplierBits); goto out; } blocks = doc->chips_per_floor << (this->chip_shift - this->phys_erase_shift); if (inftl_bbt_write && (blocks > mtd->erasesize)) { printk(KERN_ERR "Writeable BBTs spanning more than one erase block are not yet supported. FIX ME!\n"); goto out; } /* Scan the partitions */ for (i = 0; (i < 4); i++) { ip = &(mh->Partitions[i]); ip->virtualUnits = le32_to_cpu(ip->virtualUnits); ip->firstUnit = le32_to_cpu(ip->firstUnit); ip->lastUnit = le32_to_cpu(ip->lastUnit); ip->flags = le32_to_cpu(ip->flags); ip->spareUnits = le32_to_cpu(ip->spareUnits); ip->Reserved0 = le32_to_cpu(ip->Reserved0);/*#ifdef CONFIG_MTD_DEBUG_VERBOSE *//* if (CONFIG_MTD_DEBUG_VERBOSE >= 2) */ printk(KERN_INFO " PARTITION[%d] ->\n" " virtualUnits = %d\n" " firstUnit = %d\n" " lastUnit = %d\n" " flags = 0x%x\n" " spareUnits = %d\n", i, ip->virtualUnits, ip->firstUnit, ip->lastUnit, ip->flags, ip->spareUnits);/*#endif *//* if ((i == 0) && (ip->firstUnit > 0)) { parts[0].name = " DiskOnChip IPL / Media Header partition"; parts[0].offset = 0; parts[0].size = mtd->erasesize * ip->firstUnit; numparts = 1; }*/ if (ip->flags & INFTL_BINARY) parts[numparts].name = " DiskOnChip BDK partition"; else parts[numparts].name = " DiskOnChip BDTL partition"; parts[numparts].offset = ip->firstUnit << vshift; parts[numparts].size = (1 + ip->lastUnit - ip->firstUnit) << vshift; numparts++; if (ip->lastUnit > lastvunit) lastvunit = ip->lastUnit; if (ip->flags & INFTL_LAST) break; } lastvunit++; if ((lastvunit << vshift) < end) { parts[numparts].name = " DiskOnChip Remainder partition"; parts[numparts].offset = lastvunit << vshift; parts[numparts].size = end - parts[numparts].offset; numparts++; } ret = numparts;out: kfree(buf); return ret;}static int __init nftl_scan_bbt(struct mtd_info *mtd){ int ret, numparts; struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; struct mtd_partition parts[2]; memset((char *) parts, 0, sizeof(parts)); /* On NFTL, we have to find the media headers before we can read the BBTs, since they're stored in the media header eraseblocks. */ numparts = nftl_partscan(mtd, parts); if (!numparts) return -EIO;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -