📄 doc2001.c
字号:
DoC_WaitReady(docptr); if (eccbuf) { /* init the ECC engine, see Reed-Solomon EDC/ECC 11.1 .*/ WriteDOC (DOC_ECC_RESET, docptr, ECCConf); WriteDOC (DOC_ECC_EN, docptr, ECCConf); } else { /* disable the ECC engine */ WriteDOC (DOC_ECC_RESET, docptr, ECCConf); WriteDOC (DOC_ECC_DIS, docptr, ECCConf); } /* Read the data via the internal pipeline through CDSN IO register, see Pipelined Read Operations 11.3 */ dummy = ReadDOC(docptr, ReadPipeInit);#ifndef USE_MEMCPY for (i = 0; i < len-1; i++) { /* N.B. you have to increase the source address in this way or the ECC logic will not work properly */ buf[i] = ReadDOC(docptr, Mil_CDSN_IO + (i & 0xff)); }#else memcpy_fromio(buf, docptr + DoC_Mil_CDSN_IO, len - 1);#endif buf[len - 1] = ReadDOC(docptr, LastDataRead); /* Let the caller know we completed it */ *retlen = len; ret = 0; if (eccbuf) { /* Read the ECC data from Spare Data Area, see Reed-Solomon EDC/ECC 11.1 */ dummy = ReadDOC(docptr, ReadPipeInit);#ifndef USE_MEMCPY for (i = 0; i < 5; i++) { /* N.B. you have to increase the source address in this way or the ECC logic will not work properly */ eccbuf[i] = ReadDOC(docptr, Mil_CDSN_IO + i); }#else memcpy_fromio(eccbuf, docptr + DoC_Mil_CDSN_IO, 5);#endif eccbuf[5] = ReadDOC(docptr, LastDataRead); /* Flush the pipeline */ dummy = ReadDOC(docptr, ECCConf); dummy = ReadDOC(docptr, ECCConf); /* Check the ECC Status */ if (ReadDOC(docptr, 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, 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 */ 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 , ECCConf); } 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,ret = 0; 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;#if 0 /* Don't allow a single write to cross a 512-byte block boundary */ if (to + len > ( (to | 0x1ff) + 1)) len = ((to | 0x1ff) + 1) - to;#else /* Don't allow writes which aren't exactly one block */ if (to & 0x1ff || len != 0x200) return -EINVAL;#endif /* 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; /* Reset the chip, see Software Requirement 11.4 item 1. */ DoC_Command(docptr, NAND_CMD_RESET, 0x00); DoC_WaitReady(docptr); /* Set device to main plane of flash */ DoC_Command(docptr, NAND_CMD_READ0, 0x00); /* issue the Serial Data In command to initial the Page Program process */ DoC_Command(docptr, NAND_CMD_SEQIN, 0x00); DoC_Address(docptr, 3, to, 0x00, 0x00); DoC_WaitReady(docptr); if (eccbuf) { /* init the ECC engine, see Reed-Solomon EDC/ECC 11.1 .*/ WriteDOC (DOC_ECC_RESET, docptr, ECCConf); WriteDOC (DOC_ECC_EN | DOC_ECC_RW, docptr, ECCConf); } else { /* disable the ECC engine */ WriteDOC (DOC_ECC_RESET, docptr, ECCConf); WriteDOC (DOC_ECC_DIS, docptr, ECCConf); } /* Write the data via the internal pipeline through CDSN IO register, see Pipelined Write Operations 11.2 */#ifndef USE_MEMCPY for (i = 0; i < len; i++) { /* N.B. you have to increase the source address in this way or the ECC logic will not work properly */ WriteDOC(buf[i], docptr, Mil_CDSN_IO + i); }#else memcpy_toio(docptr + DoC_Mil_CDSN_IO, buf, len);#endif WriteDOC(0x00, docptr, WritePipeTerm); if (eccbuf) { /* Write ECC data to flash, the ECC info is generated by the DiskOnChip ECC logic see Reed-Solomon EDC/ECC 11.1 */ WriteDOC(0, docptr, NOP); WriteDOC(0, docptr, NOP); WriteDOC(0, docptr, NOP); /* Read the ECC data through the DiskOnChip ECC logic */ for (i = 0; i < 6; i++) { eccbuf[i] = ReadDOC(docptr, ECCSyndrome0 + i); } /* ignore the ECC engine */ WriteDOC(DOC_ECC_DIS, docptr , ECCConf);#ifndef USE_MEMCPY /* Write the ECC data to flash */ for (i = 0; i < 6; i++) { /* N.B. you have to increase the source address in this way or the ECC logic will not work properly */ WriteDOC(eccbuf[i], docptr, Mil_CDSN_IO + i); }#else memcpy_toio(docptr + DoC_Mil_CDSN_IO, eccbuf, 6);#endif /* write the block status BLOCK_USED (0x5555) at the end of ECC data FIXME: this is only a hack for programming the IPL area for LinuxBIOS and should be replace with proper codes in user space utilities */ WriteDOC(0x55, docptr, Mil_CDSN_IO); WriteDOC(0x55, docptr, Mil_CDSN_IO + 1); WriteDOC(0x00, docptr, WritePipeTerm);#ifdef PSYCHO_DEBUG printk("OOB data at %lx is %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n", (long) to, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3], eccbuf[4], eccbuf[5]);#endif } /* Commit the Page Program command and wait for ready see Software Requirement 11.4 item 1.*/ DoC_Command(docptr, NAND_CMD_PAGEPROG, 0x00); DoC_WaitReady(docptr); /* Read the status of the flash device through CDSN IO register see Software Requirement 11.4 item 5.*/ DoC_Command(docptr, NAND_CMD_STATUS, CDSN_CTRL_WP); dummy = ReadDOC(docptr, ReadPipeInit); DoC_Delay(docptr, 2); if (ReadDOC(docptr, Mil_CDSN_IO) & 1) { printk("Error programming flash\n"); /* Error in programming FIXME: implement Bad Block Replacement (in nftl.c ??) */ *retlen = 0; ret = -EIO; } dummy = ReadDOC(docptr, LastDataRead); /* Let the caller know we completed it */ *retlen = len; return ret;}static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len, size_t *retlen, u_char *buf){#ifndef USE_MEMCPY int i;#endif volatile char dummy; struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv; unsigned long docptr = this->virtadr; struct Nand *mychip = &this->chips[ofs >> this->chipshift]; /* 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; /* disable the ECC engine */ WriteDOC (DOC_ECC_RESET, docptr, ECCConf); WriteDOC (DOC_ECC_DIS, docptr, ECCConf); /* issue the Read2 command to set the pointer to the Spare Data Area. Polling the Flash Ready bit after issue 3 bytes address in Sequence Read Mode, see Software Requirement 11.4 item 1.*/ DoC_Command(docptr, NAND_CMD_READOOB, CDSN_CTRL_WP); DoC_Address(docptr, 3, ofs, CDSN_CTRL_WP, 0x00); DoC_WaitReady(docptr); /* Read the data out via the internal pipeline through CDSN IO register, see Pipelined Read Operations 11.3 */ dummy = ReadDOC(docptr, ReadPipeInit);#ifndef USE_MEMCPY for (i = 0; i < len-1; i++) { /* N.B. you have to increase the source address in this way or the ECC logic will not work properly */ buf[i] = ReadDOC(docptr, Mil_CDSN_IO + i); }#else memcpy_fromio(buf, docptr + DoC_Mil_CDSN_IO, len - 1);#endif buf[len - 1] = ReadDOC(docptr, LastDataRead); *retlen = len; return 0;}static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len, size_t *retlen, const u_char *buf){#ifndef USE_MEMCPY int i;#endif volatile char dummy; int ret = 0; struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv; unsigned long docptr = this->virtadr; struct Nand *mychip = &this->chips[ofs >> this->chipshift]; /* 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; /* disable the ECC engine */ WriteDOC (DOC_ECC_RESET, docptr, ECCConf); WriteDOC (DOC_ECC_DIS, docptr, ECCConf); /* Reset the chip, see Software Requirement 11.4 item 1. */ DoC_Command(docptr, NAND_CMD_RESET, CDSN_CTRL_WP); DoC_WaitReady(docptr); /* issue the Read2 command to set the pointer to the Spare Data Area. */ DoC_Command(docptr, NAND_CMD_READOOB, CDSN_CTRL_WP); /* issue the Serial Data In command to initial the Page Program process */ DoC_Command(docptr, NAND_CMD_SEQIN, 0x00); DoC_Address(docptr, 3, ofs, 0x00, 0x00); /* Write the data via the internal pipeline through CDSN IO register, see Pipelined Write Operations 11.2 */#ifndef USE_MEMCPY for (i = 0; i < len; i++) { /* N.B. you have to increase the source address in this way or the ECC logic will not work properly */ WriteDOC(buf[i], docptr, Mil_CDSN_IO + i); }#else memcpy_toio(docptr + DoC_Mil_CDSN_IO, buf, len);#endif WriteDOC(0x00, docptr, WritePipeTerm); /* Commit the Page Program command and wait for ready see Software Requirement 11.4 item 1.*/ DoC_Command(docptr, NAND_CMD_PAGEPROG, 0x00); DoC_WaitReady(docptr); /* Read the status of the flash device through CDSN IO register see Software Requirement 11.4 item 5.*/ DoC_Command(docptr, NAND_CMD_STATUS, 0x00); dummy = ReadDOC(docptr, ReadPipeInit); DoC_Delay(docptr, 2); if (ReadDOC(docptr, Mil_CDSN_IO) & 1) { printk("Error programming oob data\n"); /* FIXME: implement Bad Block Replacement (in nftl.c ??) */ *retlen = 0; ret = -EIO; } dummy = ReadDOC(docptr, LastDataRead); *retlen = len; return ret;}int doc_erase (struct mtd_info *mtd, struct erase_info *instr){ volatile char dummy; struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv; __u32 ofs = instr->addr; __u32 len = instr->len; unsigned long docptr = this->virtadr; struct Nand *mychip = &this->chips[ofs >> this->chipshift]; if (len != mtd->erasesize) printk(KERN_WARNING "Erase not right size (%x != %x)n", len, mtd->erasesize); /* 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; instr->state = MTD_ERASE_PENDING; /* issue the Erase Setup command */ DoC_Command(docptr, NAND_CMD_ERASE1, 0x00); DoC_Address(docptr, 2, ofs, 0x00, 0x00); /* Commit the Erase Start command and wait for ready see Software Requirement 11.4 item 1.*/ DoC_Command(docptr, NAND_CMD_ERASE2, 0x00); DoC_WaitReady(docptr); instr->state = MTD_ERASING; /* Read the status of the flash device through CDSN IO register see Software Requirement 11.4 item 5. FIXME: it seems that we are not wait long enough, some blocks are not erased fully */ DoC_Command(docptr, NAND_CMD_STATUS, CDSN_CTRL_WP); dummy = ReadDOC(docptr, ReadPipeInit); DoC_Delay(docptr, 2); if (ReadDOC(docptr, Mil_CDSN_IO) & 1) { printk("Error Erasing at 0x%x\n", ofs); /* There was an error FIXME: implement Bad Block Replacement (in nftl.c ??) */ instr->state = MTD_ERASE_FAILED; } else instr->state = MTD_ERASE_DONE; dummy = ReadDOC(docptr, LastDataRead); mtd_erase_callback(instr); return 0;}/**************************************************************************** * * Module stuff * ****************************************************************************/int __init init_doc2001(void){ inter_module_register(im_name, THIS_MODULE, &DoCMil_init); return 0;}static void __exit cleanup_doc2001(void){ struct mtd_info *mtd; struct DiskOnChip *this; while ((mtd=docmillist)) { this = (struct DiskOnChip *)mtd->priv; docmillist = this->nextdoc; del_mtd_device(mtd); iounmap((void *)this->virtadr); kfree(this->chips); kfree(mtd); } inter_module_unregister(im_name);}module_exit(cleanup_doc2001);module_init(init_doc2001);MODULE_LICENSE("GPL");MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org> et al.");MODULE_DESCRIPTION("Alternative driver for DiskOnChip Millennium");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -