struct doc_priv { struct nand_controller base; void __iomem *virtadr; unsignedlong physadr;
u_char ChipID;
u_char CDSNControl; int chips_per_floor; /* The number of chips detected on each floor */ int curfloor; int curchip; int mh0_page; int mh1_page; struct rs_control *rs_decoder; struct mtd_info *nextdoc; bool supports_32b_reads;
/* Handle the last stage of initialization (BBT scan, partitioning) */ int (*late_init)(struct mtd_info *mtd);
};
/* This is the ecc value computed by the HW ecc generator upon writing an empty
page, one with all 0xff for data. */ static u_char empty_write_ecc[6] = { 0x4b, 0x00, 0xe2, 0x0e, 0x93, 0xf7 };
staticunsignedlong doc_config_location = CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS;
module_param(doc_config_location, ulong, 0);
MODULE_PARM_DESC(doc_config_location, "Physical memory address at which to probe for DiskOnChip");
/* Sector size for HW ECC */ #define SECTOR_SIZE 512 /* The sector bytes are packed into NB_DATA 10 bit words */ #define NB_DATA (((SECTOR_SIZE + 1) * 8 + 6) / 10) /* Number of roots */ #define NROOTS 4 /* First consective root */ #define FCR 510 /* Number of symbols */ #define NN 1023
if (doc->ChipID == DOC_ChipID_Doc2k && try_dword && !nr) { /* First chip probe. See if we get same results by 32-bit access */ union {
uint32_t dword;
uint8_t byte[4];
} ident; void __iomem *docptr = doc->virtadr;
/* Max 4 chips per floor on DiskOnChip 2000 */
doc->chips_per_floor = 4;
/* Find out what the first chip is */
mfrid = doc200x_ident_chip(mtd, 0);
/* Find how many chips in each floor. */ for (i = 1; i < 4; i++) { if (doc200x_ident_chip(mtd, i) != mfrid) break;
}
doc->chips_per_floor = i;
pr_debug("Detected %d chips per floor.\n", i);
}
if (debug)
printk("writebuf of %d bytes: ", len); for (i = 0; i < len; i++) {
WriteDOC_(buf[i], docptr, DoC_Mil_CDSN_IO + i); if (debug && i < 16)
printk("%02x ", buf[i]);
} if (debug)
printk("\n");
}
case NAND_OP_ADDR_INSTR:
doc200x_write_control(doc, CDSN_CTRL_CE | CDSN_CTRL_ALE); for (i = 0; i < instr->ctx.addr.naddrs; i++) {
u8 addr = instr->ctx.addr.addrs[i];
if (DoC_is_2000(doc))
doc2000_write_byte(this, addr); else
doc2001_write_byte(this, addr);
} break;
case NAND_OP_DATA_IN_INSTR:
doc200x_write_control(doc, CDSN_CTRL_CE); if (DoC_is_2000(doc))
doc2000_readbuf(this, instr->ctx.data.buf.in,
instr->ctx.data.len); else
doc2001_readbuf(this, instr->ctx.data.buf.in,
instr->ctx.data.len); break;
case NAND_OP_DATA_OUT_INSTR:
doc200x_write_control(doc, CDSN_CTRL_CE); if (DoC_is_2000(doc))
doc2000_writebuf(this, instr->ctx.data.buf.out,
instr->ctx.data.len); else
doc2001_writebuf(this, instr->ctx.data.buf.out,
instr->ctx.data.len); break;
case NAND_OP_WAITRDY_INSTR:
DoC_WaitReady(doc); break;
}
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); #if0 /* If emptymatch=1, we might have an all-0xff data buffer. Check. */ if (emptymatch) { /* Note: this somewhat expensive test should not be triggered often.Itcouldbeoptimizedawaybyexaminingthedatain
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. Returnall-0xffeccvalueinsteadofthecomputedone,so
it'll look just like a freshly-erased page. */ if (emptymatch)
memset(ecc_code, 0xff, 6); #endif return0;
}
/* Find the (I)NFTL Media Header, and optionally also the mirror media header. Onsuccessfulreturn,bufwillcontainacopyofthemediaheaderfor furtherprocessing.idisthestringtoscanfor,andwillpresumablybe either"ANAND"or"BNAND".Iffindmirror=1,alsolookforthemirrormedia header.Thepage#softhefoundmediaheadersareplacedinmh0_pageand
mh1_page in the DOC private structure. */ staticint __init find_media_headers(struct mtd_info *mtd, u_char *buf, constchar *id, intfindmirror)
{ struct nand_chip *this = mtd_to_nand(mtd); struct doc_priv *doc = nand_get_controller_data(this); unsigned offs; int ret;
size_t retlen;
for (offs = 0; offs < mtd->size; offs += mtd->erasesize) {
ret = mtd_read(mtd, offs, mtd->writesize, &retlen, buf); if (retlen != mtd->writesize) continue; if (ret) {
pr_warn("ECC error scanning DOC at 0x%x\n", offs);
} if (memcmp(buf, id, 6)) continue;
pr_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) return1; continue;
}
doc->mh1_page = offs >> this->page_shift; return2;
} if (doc->mh0_page == -1) {
pr_warn("DiskOnChip %s Media Header not found.\n", id); return0;
} /* 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->writesize, &retlen, buf); if (retlen != mtd->writesize) { /* Insanity. Give up. */
pr_err("Read DiskOnChip Media Header once, but can't reread it???\n"); return0;
} return1;
}
/* This is a stripped-down copy of the code in inftlmount.c */ staticinlineint __init inftl_partscan(struct mtd_info *mtd, struct mtd_partition *parts)
{ struct nand_chip *this = mtd_to_nand(mtd); struct doc_priv *doc = nand_get_controller_data(this); 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->writesize, GFP_KERNEL); if (!buf) { return0;
}
blocks = mtd->size >> vshift; if (blocks > 32768) {
pr_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)) {
pr_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]);
le32_to_cpus(&ip->virtualUnits);
le32_to_cpus(&ip->firstUnit);
le32_to_cpus(&ip->lastUnit);
le32_to_cpus(&ip->flags);
le32_to_cpus(&ip->spareUnits);
le32_to_cpus(&ip->Reserved0);
memset((char *)parts, 0, sizeof(parts));
numparts = inftl_partscan(mtd, parts); /* At least for now, require the INFTL Media Header. We could probably dowithoutitfornon-INFTLuse,sinceallitgivesusis
autopartitioning, but I want to give it more thought. */ if (!numparts) return -EIO; return mtd_device_register(mtd, parts, no_autopart ? 0 : numparts);
}
if (!request_mem_region(physadr, DOC_IOREMAP_LEN, "DiskOnChip")) return -EBUSY;
virtadr = ioremap(physadr, DOC_IOREMAP_LEN); if (!virtadr) {
pr_err("Diskonchip ioremap failed: 0x%x bytes at 0x%lx\n",
DOC_IOREMAP_LEN, physadr);
ret = -EIO; goto error_ioremap;
}
/* It's not possible to cleanly detect the DiskOnChip - the *bootupprocedurewillputthedeviceintoresetmode,and *it'snotpossibletotalktoitwithoutactuallywriting *totheDOCControlregister.Sowestorethecurrentcontents *oftheDOCControlregister'slocation,incasewelaterdecide *thatit'snotaDiskOnChip,andwanttoputitbackhowwe *foundit.
*/
save_control = ReadDOC(virtadr, DOCControl);
switch (ChipID) { case DOC_ChipID_Doc2k:
reg = DoC_2k_ECCStatus; break; case DOC_ChipID_DocMil:
reg = DoC_ECCConf; break; case DOC_ChipID_DocMilPlus16: case DOC_ChipID_DocMilPlus32: case0: /* Possible Millennium Plus, need to do more checks */ /* Possibly release from power down mode */ for (tmp = 0; (tmp < 4); tmp++)
ReadDOC(virtadr, Mplus_Power);
switch (ChipID) { case DOC_ChipID_DocMilPlus16:
reg = DoC_Mplus_Toggle; break; case DOC_ChipID_DocMilPlus32:
pr_err("DiskOnChip Millennium Plus 32MB is not supported, ignoring.\n");
fallthrough; default:
ret = -ENODEV; goto notfound;
} break;
default:
ret = -ENODEV; goto notfound;
} /* Check the TOGGLE bit in the ECC register */
tmp = ReadDOC_(virtadr, reg) & DOC_TOGGLE_BIT;
tmpb = ReadDOC_(virtadr, reg) & DOC_TOGGLE_BIT;
tmpc = ReadDOC_(virtadr, reg) & DOC_TOGGLE_BIT; if ((tmp == tmpb) || (tmp != tmpc)) {
pr_warn("Possible DiskOnChip at 0x%lx failed TOGGLE test, dropping.\n", physadr);
ret = -ENODEV; goto notfound;
}
for (mtd = doclist; mtd; mtd = doc->nextdoc) { unsignedchar oldval; unsignedchar newval;
nand = mtd_to_nand(mtd);
doc = nand_get_controller_data(nand); /* Use the alias resolution register to determine if this is infactthesameDOCaliasedtoanewaddress.Ifwrites toonechip'saliasresolutionregisterchangethevalueon
the other chip, they're the same chip. */ if (ChipID == DOC_ChipID_DocMilPlus16) {
oldval = ReadDOC(doc->virtadr, Mplus_AliasResolution);
newval = ReadDOC(virtadr, Mplus_AliasResolution);
} else {
oldval = ReadDOC(doc->virtadr, AliasResolution);
newval = ReadDOC(virtadr, AliasResolution);
} if (oldval != newval) continue; if (ChipID == DOC_ChipID_DocMilPlus16) {
WriteDOC(~newval, virtadr, Mplus_AliasResolution);
oldval = ReadDOC(doc->virtadr, Mplus_AliasResolution);
WriteDOC(newval, virtadr, Mplus_AliasResolution); // restore it
} else {
WriteDOC(~newval, virtadr, AliasResolution);
oldval = ReadDOC(doc->virtadr, AliasResolution);
WriteDOC(newval, virtadr, AliasResolution); // restore it
}
newval = ~newval; if (oldval == newval) {
pr_debug("Found alias of DOC at 0x%lx to 0x%lx\n",
doc->physadr, physadr); goto notfound;
}
}
pr_notice("DiskOnChip found at 0x%lx\n", physadr);
len = sizeof(struct nand_chip) + sizeof(struct doc_priv) +
(2 * sizeof(struct nand_bbt_descr));
nand = kzalloc(len, GFP_KERNEL); if (!nand) {
ret = -ENOMEM; goto fail;
}
/* *AllocateaRScodecinstance * *Symbolsizeis10(bits) *Primitvepolynomialisx^10+x^3+1 *Firstconsecutiverootis510 *Primitveelementtogenerateroots=1 *Generatorpolinomialdegree=4
*/
doc = (struct doc_priv *) (nand + 1);
doc->rs_decoder = init_rs(10, 0x409, FCR, 1, NROOTS); if (!doc->rs_decoder) {
pr_err("DiskOnChip: Could not create a RS codec\n");
ret = -ENOMEM; goto fail;
}
nand->controller = &doc->base;
nand_set_controller_data(nand, doc);
nand->bbt_options = NAND_BBT_USE_FLASH; /* Skip the automatic BBT scan so we can run it manually */
nand->options |= NAND_SKIP_BBTSCAN | NAND_NO_BBM_QUIRK;
ret = nand_scan(nand, numchips); if (ret) goto fail;
ret = doc->late_init(mtd); if (ret) {
nand_cleanup(nand); goto fail;
}
/* Success! */
doclist = mtd; return0;
notfound: /* Put back the contents of the DOCControl register, in case it's not
actually a DiskOnChip. */
WriteDOC(save_control, virtadr, DOCControl);
fail: if (doc)
free_rs(doc->rs_decoder);
kfree(nand);
iounmap(virtadr);
staticint __init init_nanddoc(void)
{ int i, ret = 0;
if (doc_config_location) {
pr_info("Using configured DiskOnChip probe address 0x%lx\n",
doc_config_location);
ret = doc_probe(doc_config_location); if (ret < 0) return ret;
} else { for (i = 0; i < ARRAY_SIZE(doc_locations); i++) {
doc_probe(doc_locations[i]);
}
} /* No banner message any more. Print a message if no DiskOnChip
found, so the user knows we at least tried. */ if (!doclist) {
pr_info("No valid DiskOnChip devices found\n");
ret = -ENODEV;
} return ret;
}
MODULE_LICENSE("GPL");
MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
MODULE_DESCRIPTION("M-Systems DiskOnChip 2000, Millennium and Millennium Plus device driver");
Messung V0.5 in Prozent
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.28Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-09-29)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.