📄 doc2001plus.c
字号:
} } /* If there are none at all that we recognise, bail */ if (!this->numchips) { printk("No flash chips recognised.\n"); return; } /* Allocate an array to hold the information for each chip */ this->chips = kmalloc(sizeof(struct Nand) * this->numchips, GFP_KERNEL); if (!this->chips){ printk("MTD: No memory for allocating chip info structures\n"); return; } /* Fill out the chip array with {floor, chipno} for each * detected chip in the device. */ for (floor = 0, ret = 0; floor < MAX_FLOORS_MPLUS; floor++) { for (chip = 0 ; chip < numchips[floor] ; chip++) { this->chips[ret].floor = floor; this->chips[ret].chip = chip; this->chips[ret].curadr = 0; this->chips[ret].curmode = 0x50; ret++; } } /* Calculate and print the total size of the device */ this->totlen = this->numchips * (1 << this->chipshift); printk(KERN_INFO "%d flash chips found. Total DiskOnChip size: %ld MiB\n", this->numchips ,this->totlen >> 20);}static int DoCMilPlus_is_alias(struct DiskOnChip *doc1, struct DiskOnChip *doc2){ int tmp1, tmp2, retval; if (doc1->physadr == doc2->physadr) return 1; /* Use the alias resolution register which was set aside for this * purpose. If it's value is the same on both chips, they might * be the same chip, and we write to one and check for a change in * the other. It's unclear if this register is usuable in the * DoC 2000 (it's in the Millennium docs), but it seems to work. */ tmp1 = ReadDOC(doc1->virtadr, Mplus_AliasResolution); tmp2 = ReadDOC(doc2->virtadr, Mplus_AliasResolution); if (tmp1 != tmp2) return 0; WriteDOC((tmp1+1) % 0xff, doc1->virtadr, Mplus_AliasResolution); tmp2 = ReadDOC(doc2->virtadr, Mplus_AliasResolution); if (tmp2 == (tmp1+1) % 0xff) retval = 1; else retval = 0; /* Restore register contents. May not be necessary, but do it just to * be safe. */ WriteDOC(tmp1, doc1->virtadr, Mplus_AliasResolution); return retval;}static const char im_name[] = "DoCMilPlus_init";/* This routine is made available to other mtd code via * inter_module_register. It must only be accessed through * inter_module_get which will bump the use count of this module. The * addresses passed back in mtd are valid as long as the use count of * this module is non-zero, i.e. between inter_module_get and * inter_module_put. Keith Owens <kaos@ocs.com.au> 29 Oct 2000. */static void DoCMilPlus_init(struct mtd_info *mtd){ struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv; struct DiskOnChip *old = NULL; /* We must avoid being called twice for the same device. */ if (docmilpluslist) old = (struct DiskOnChip *)docmilpluslist->priv; while (old) { if (DoCMilPlus_is_alias(this, old)) { printk(KERN_NOTICE "Ignoring DiskOnChip Millennium " "Plus at 0x%lX - already configured\n", this->physadr); iounmap((void *)this->virtadr); kfree(mtd); return; } if (old->nextdoc) old = (struct DiskOnChip *)old->nextdoc->priv; else old = NULL; } mtd->name = "DiskOnChip Millennium Plus"; printk(KERN_NOTICE "DiskOnChip Millennium Plus found at " "address 0x%lX\n", this->physadr); mtd->type = MTD_NANDFLASH; mtd->flags = MTD_CAP_NANDFLASH; mtd->ecctype = MTD_ECC_RS_DiskOnChip; mtd->size = 0; mtd->erasesize = 0; mtd->oobblock = 512; mtd->oobsize = 16; mtd->owner = THIS_MODULE; mtd->erase = doc_erase; mtd->point = NULL; mtd->unpoint = NULL; mtd->read = doc_read; mtd->write = doc_write; mtd->read_ecc = doc_read_ecc; mtd->write_ecc = doc_write_ecc; mtd->read_oob = doc_read_oob; mtd->write_oob = doc_write_oob; mtd->sync = NULL; this->totlen = 0; this->numchips = 0; this->curfloor = -1; this->curchip = -1; /* Ident all the chips present. */ DoC_ScanChips(this); if (!this->totlen) { kfree(mtd); iounmap((void *)this->virtadr); } else { this->nextdoc = docmilpluslist; docmilpluslist = mtd; mtd->size = this->totlen; mtd->erasesize = this->erasesize; add_mtd_device(mtd); return; }}#if 0static int doc_dumpblk(struct mtd_info *mtd, loff_t from){ int i; loff_t fofs; struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv; unsigned long docptr = this->virtadr; struct Nand *mychip = &this->chips[from >> (this->chipshift)]; unsigned char *bp, buf[1056]; char c[32]; from &= ~0x3ff; /* Don't allow read past end of device */ if (from >= this->totlen) return -EINVAL; DoC_CheckASIC(docptr); /* Find the chip which is to be used and select it */ if (this->curfloor != mychip->floor) { DoC_SelectFloor(docptr, mychip->floor); DoC_SelectChip(docptr, mychip->chip); } else if (this->curchip != mychip->chip) { DoC_SelectChip(docptr, mychip->chip); } this->curfloor = mychip->floor; this->curchip = mychip->chip; /* Millennium Plus bus cycle sequence as per figure 2, section 2.4 */ WriteDOC((DOC_FLASH_CE | DOC_FLASH_WP), docptr, Mplus_FlashSelect); /* Reset the chip, see Software Requirement 11.4 item 1. */ DoC_Command(docptr, NAND_CMD_RESET, 0); DoC_WaitReady(docptr); fofs = from; DoC_Command(docptr, DoC_GetDataOffset(mtd, &fofs), 0); DoC_Address(this, 3, fofs, 0, 0x00); WriteDOC(0, docptr, Mplus_FlashControl); DoC_WaitReady(docptr); /* disable the ECC engine */ WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf); ReadDOC(docptr, Mplus_ReadPipeInit); ReadDOC(docptr, Mplus_ReadPipeInit); /* Read the data via the internal pipeline through CDSN IO register, see Pipelined Read Operations 11.3 */ MemReadDOC(docptr, buf, 1054); buf[1054] = ReadDOC(docptr, Mplus_LastDataRead); buf[1055] = ReadDOC(docptr, Mplus_LastDataRead); memset(&c[0], 0, sizeof(c)); printk("DUMP OFFSET=%x:\n", (int)from); for (i = 0, bp = &buf[0]; (i < 1056); i++) { if ((i % 16) == 0) printk("%08x: ", i); printk(" %02x", *bp); c[(i & 0xf)] = ((*bp >= 0x20) && (*bp <= 0x7f)) ? *bp : '.'; bp++; if (((i + 1) % 16) == 0) printk(" %s\n", c); } printk("\n"); /* Disable flash internally */ WriteDOC(0, docptr, Mplus_FlashSelect); return 0;}#endifstatic int doc_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf){ /* Just a special case of doc_read_ecc */ return doc_read_ecc(mtd, from, len, retlen, buf, NULL, NULL);}static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel){ int ret, i; volatile char dummy; loff_t fofs; unsigned char syndrome[6]; struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv; unsigned long docptr = this->virtadr; struct Nand *mychip = &this->chips[from >> (this->chipshift)]; /* Don't allow read past end of device */ if (from >= this->totlen) return -EINVAL; /* Don't allow a single read to cross a 512-byte block boundary */ if (from + len > ((from | 0x1ff) + 1)) len = ((from | 0x1ff) + 1) - from; DoC_CheckASIC(docptr); /* Find the chip which is to be used and select it */ if (this->curfloor != mychip->floor) { DoC_SelectFloor(docptr, mychip->floor); DoC_SelectChip(docptr, mychip->chip); } else if (this->curchip != mychip->chip) { DoC_SelectChip(docptr, mychip->chip); } this->curfloor = mychip->floor; this->curchip = mychip->chip; /* Millennium Plus bus cycle sequence as per figure 2, section 2.4 */ WriteDOC((DOC_FLASH_CE | DOC_FLASH_WP), docptr, Mplus_FlashSelect); /* Reset the chip, see Software Requirement 11.4 item 1. */ DoC_Command(docptr, NAND_CMD_RESET, 0); DoC_WaitReady(docptr); fofs = from; DoC_Command(docptr, DoC_GetDataOffset(mtd, &fofs), 0); DoC_Address(this, 3, fofs, 0, 0x00); WriteDOC(0, docptr, Mplus_FlashControl); DoC_WaitReady(docptr); if (eccbuf) { /* init the ECC engine, see Reed-Solomon EDC/ECC 11.1 .*/ WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf); WriteDOC(DOC_ECC_EN, docptr, Mplus_ECCConf); } else { /* disable the ECC engine */ WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf); } /* Let the caller know we completed it */ *retlen = len; ret = 0; ReadDOC(docptr, Mplus_ReadPipeInit); ReadDOC(docptr, Mplus_ReadPipeInit); if (eccbuf) { /* Read the data via the internal pipeline through CDSN IO register, see Pipelined Read Operations 11.3 */ MemReadDOC(docptr, buf, len); /* Read the ECC data following raw data */ MemReadDOC(docptr, eccbuf, 4); eccbuf[4] = ReadDOC(docptr, Mplus_LastDataRead); eccbuf[5] = ReadDOC(docptr, Mplus_LastDataRead); /* Flush the pipeline */ dummy = ReadDOC(docptr, Mplus_ECCConf); dummy = ReadDOC(docptr, Mplus_ECCConf); /* Check the ECC Status */ if (ReadDOC(docptr, Mplus_ECCConf) & 0x80) { int nb_errors; /* There was an ECC error */#ifdef ECC_DEBUG printk("DiskOnChip ECC Error: Read at %lx\n", (long)from);#endif /* Read the ECC syndrom through the DiskOnChip ECC logic. These syndrome will be all ZERO when there is no error */ for (i = 0; i < 6; i++) syndrome[i] = ReadDOC(docptr, Mplus_ECCSyndrome0 + i); nb_errors = doc_decode_ecc(buf, syndrome);#ifdef ECC_DEBUG printk("ECC Errors corrected: %x\n", nb_errors);#endif if (nb_errors < 0) { /* We return error, but have actually done the read. Not that this can be told to user-space, via sys_read(), but at least MTD-aware stuff can know about it by checking *retlen */#ifdef ECC_DEBUG printk("%s(%d): Millennium Plus ECC error (from=0x%x:\n", __FILE__, __LINE__, (int)from); printk(" syndrome= %02x:%02x:%02x:%02x:%02x:" "%02x\n", syndrome[0], syndrome[1], syndrome[2], syndrome[3], syndrome[4], syndrome[5]); printk(" eccbuf= %02x:%02x:%02x:%02x:%02x:" "%02x\n", eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3], eccbuf[4], eccbuf[5]);#endif ret = -EIO; } }#ifdef PSYCHO_DEBUG printk("ECC DATA at %lx: %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n", (long)from, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3], eccbuf[4], eccbuf[5]);#endif /* disable the ECC engine */ WriteDOC(DOC_ECC_DIS, docptr , Mplus_ECCConf); } else { /* Read the data via the internal pipeline through CDSN IO register, see Pipelined Read Operations 11.3 */ MemReadDOC(docptr, buf, len-2); buf[len-2] = ReadDOC(docptr, Mplus_LastDataRead); buf[len-1] = ReadDOC(docptr, Mplus_LastDataRead); } /* Disable flash internally */ WriteDOC(0, docptr, Mplus_FlashSelect); return ret;}static int doc_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf){ char eccbuf[6]; return doc_write_ecc(mtd, to, len, retlen, buf, eccbuf, NULL);}static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel){ int i, before, ret = 0; loff_t fto; volatile char dummy; struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv; unsigned long docptr = this->virtadr; struct Nand *mychip = &this->chips[to >> (this->chipshift)]; /* Don't allow write past end of device */ if (to >= this->totlen) return -EINVAL; /* Don't allow writes which aren't exactly one block (512 bytes) */ if ((to & 0x1ff) || (len != 0x200)) return -EINVAL; /* Determine position of OOB flags, before or after data */ before = (this->interleave && (to & 0x200));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -