📄 doc2000.c
字号:
DoC_Command(this, (!this->page256 && (to & 0x100)) ? NAND_CMD_READ1 : NAND_CMD_READ0, CDSN_CTRL_WP); DoC_Command(this, NAND_CMD_SEQIN, 0); DoC_Address(this, ADDR_COLUMN_PAGE, to, 0, CDSN_CTRL_ECC_IO); /* Prime the ECC engine */ WriteDOC(DOC_ECC_RESET, docptr, ECCConf); WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, ECCConf); /* treat crossing 256-byte sector for 2M x 8bits devices */ if (this->page256 && to + len > (to | 0xff) + 1) { len256 = (to | 0xff) + 1 - to; DoC_WriteBuf(this, buf, len256); DoC_Command(this, NAND_CMD_PAGEPROG, 0); DoC_Command(this, NAND_CMD_STATUS, CDSN_CTRL_WP); /* There's an implicit DoC_WaitReady() in DoC_Command */ dummy = ReadDOC(docptr, CDSNSlowIO); DoC_Delay(this, 2); if (ReadDOC_(docptr, this->ioreg) & 1) { printk(KERN_ERR "Error programming flash\n"); /* Error in programming */ *retlen = 0; mutex_unlock(&this->lock); return -EIO; } DoC_Command(this, NAND_CMD_SEQIN, 0); DoC_Address(this, ADDR_COLUMN_PAGE, to + len256, 0, CDSN_CTRL_ECC_IO); } DoC_WriteBuf(this, &buf[len256], len - len256); WriteDOC(CDSN_CTRL_ECC_IO | CDSN_CTRL_CE, docptr, CDSNControl); if (DoC_is_Millennium(this)) { WriteDOC(0, docptr, NOP); WriteDOC(0, docptr, NOP); WriteDOC(0, docptr, NOP); } else { WriteDOC_(0, docptr, this->ioreg); WriteDOC_(0, docptr, this->ioreg); WriteDOC_(0, docptr, this->ioreg); } WriteDOC(CDSN_CTRL_ECC_IO | CDSN_CTRL_FLASH_IO | CDSN_CTRL_CE, docptr, CDSNControl); /* Read the ECC data through the DiskOnChip ECC logic */ for (di = 0; di < 6; di++) { eccbuf[di] = ReadDOC(docptr, ECCSyndrome0 + di); } /* Reset the ECC engine */ WriteDOC(DOC_ECC_DIS, docptr, ECCConf);#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 DoC_Command(this, NAND_CMD_PAGEPROG, 0); DoC_Command(this, NAND_CMD_STATUS, CDSN_CTRL_WP); /* There's an implicit DoC_WaitReady() in DoC_Command */ if (DoC_is_Millennium(this)) { ReadDOC(docptr, ReadPipeInit); status = ReadDOC(docptr, LastDataRead); } else { dummy = ReadDOC(docptr, CDSNSlowIO); DoC_Delay(this, 2); status = ReadDOC_(docptr, this->ioreg); } if (status & 1) { printk(KERN_ERR "Error programming flash\n"); /* Error in programming */ *retlen = 0; mutex_unlock(&this->lock); return -EIO; } /* Let the caller know we completed it */ *retlen += len; { unsigned char x[8]; size_t dummy; int ret; /* Write the ECC data to flash */ for (di=0; di<6; di++) x[di] = eccbuf[di]; x[6]=0x55; x[7]=0x55; ret = doc_write_oob_nolock(mtd, to, 8, &dummy, x); if (ret) { mutex_unlock(&this->lock); return ret; } } to += len; left -= len; buf += len; } mutex_unlock(&this->lock); return 0;}static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, struct mtd_oob_ops *ops){ struct DiskOnChip *this = mtd->priv; int len256 = 0, ret; struct Nand *mychip; uint8_t *buf = ops->oobbuf; size_t len = ops->len; BUG_ON(ops->mode != MTD_OOB_PLACE); ofs += ops->ooboffs; mutex_lock(&this->lock); mychip = &this->chips[ofs >> this->chipshift]; if (this->curfloor != mychip->floor) { DoC_SelectFloor(this, mychip->floor); DoC_SelectChip(this, mychip->chip); } else if (this->curchip != mychip->chip) { DoC_SelectChip(this, mychip->chip); } this->curfloor = mychip->floor; this->curchip = mychip->chip; /* update address for 2M x 8bit devices. OOB starts on the second */ /* page to maintain compatibility with doc_read_ecc. */ if (this->page256) { if (!(ofs & 0x8)) ofs += 0x100; else ofs -= 0x8; } DoC_Command(this, NAND_CMD_READOOB, CDSN_CTRL_WP); DoC_Address(this, ADDR_COLUMN_PAGE, ofs, CDSN_CTRL_WP, 0); /* treat crossing 8-byte OOB data for 2M x 8bit devices */ /* Note: datasheet says it should automaticaly wrap to the */ /* next OOB block, but it didn't work here. mf. */ if (this->page256 && ofs + len > (ofs | 0x7) + 1) { len256 = (ofs | 0x7) + 1 - ofs; DoC_ReadBuf(this, buf, len256); DoC_Command(this, NAND_CMD_READOOB, CDSN_CTRL_WP); DoC_Address(this, ADDR_COLUMN_PAGE, ofs & (~0x1ff), CDSN_CTRL_WP, 0); } DoC_ReadBuf(this, &buf[len256], len - len256); ops->retlen = len; /* Reading the full OOB data drops us off of the end of the page, * causing the flash device to go into busy mode, so we need * to wait until ready 11.4.1 and Toshiba TC58256FT docs */ ret = DoC_WaitReady(this); mutex_unlock(&this->lock); return ret;}static int doc_write_oob_nolock(struct mtd_info *mtd, loff_t ofs, size_t len, size_t * retlen, const u_char * buf){ struct DiskOnChip *this = mtd->priv; int len256 = 0; void __iomem *docptr = this->virtadr; struct Nand *mychip = &this->chips[ofs >> this->chipshift]; volatile int dummy; int status; // printk("doc_write_oob(%lx, %d): %2.2X %2.2X %2.2X %2.2X ... %2.2X %2.2X .. %2.2X %2.2X\n",(long)ofs, len, // buf[0], buf[1], buf[2], buf[3], buf[8], buf[9], buf[14],buf[15]); /* Find the chip which is to be used and select it */ if (this->curfloor != mychip->floor) { DoC_SelectFloor(this, mychip->floor); DoC_SelectChip(this, mychip->chip); } else if (this->curchip != mychip->chip) { DoC_SelectChip(this, 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(this, NAND_CMD_RESET, CDSN_CTRL_WP); /* issue the Read2 command to set the pointer to the Spare Data Area. */ DoC_Command(this, NAND_CMD_READOOB, CDSN_CTRL_WP); /* update address for 2M x 8bit devices. OOB starts on the second */ /* page to maintain compatibility with doc_read_ecc. */ if (this->page256) { if (!(ofs & 0x8)) ofs += 0x100; else ofs -= 0x8; } /* issue the Serial Data In command to initial the Page Program process */ DoC_Command(this, NAND_CMD_SEQIN, 0); DoC_Address(this, ADDR_COLUMN_PAGE, ofs, 0, 0); /* treat crossing 8-byte OOB data for 2M x 8bit devices */ /* Note: datasheet says it should automaticaly wrap to the */ /* next OOB block, but it didn't work here. mf. */ if (this->page256 && ofs + len > (ofs | 0x7) + 1) { len256 = (ofs | 0x7) + 1 - ofs; DoC_WriteBuf(this, buf, len256); DoC_Command(this, NAND_CMD_PAGEPROG, 0); DoC_Command(this, NAND_CMD_STATUS, 0); /* DoC_WaitReady() is implicit in DoC_Command */ if (DoC_is_Millennium(this)) { ReadDOC(docptr, ReadPipeInit); status = ReadDOC(docptr, LastDataRead); } else { dummy = ReadDOC(docptr, CDSNSlowIO); DoC_Delay(this, 2); status = ReadDOC_(docptr, this->ioreg); } if (status & 1) { printk(KERN_ERR "Error programming oob data\n"); /* There was an error */ *retlen = 0; return -EIO; } DoC_Command(this, NAND_CMD_SEQIN, 0); DoC_Address(this, ADDR_COLUMN_PAGE, ofs & (~0x1ff), 0, 0); } DoC_WriteBuf(this, &buf[len256], len - len256); DoC_Command(this, NAND_CMD_PAGEPROG, 0); DoC_Command(this, NAND_CMD_STATUS, 0); /* DoC_WaitReady() is implicit in DoC_Command */ if (DoC_is_Millennium(this)) { ReadDOC(docptr, ReadPipeInit); status = ReadDOC(docptr, LastDataRead); } else { dummy = ReadDOC(docptr, CDSNSlowIO); DoC_Delay(this, 2); status = ReadDOC_(docptr, this->ioreg); } if (status & 1) { printk(KERN_ERR "Error programming oob data\n"); /* There was an error */ *retlen = 0; return -EIO; } *retlen = len; return 0;}static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, struct mtd_oob_ops *ops){ struct DiskOnChip *this = mtd->priv; int ret; BUG_ON(ops->mode != MTD_OOB_PLACE); mutex_lock(&this->lock); ret = doc_write_oob_nolock(mtd, ofs + ops->ooboffs, ops->len, &ops->retlen, ops->oobbuf); mutex_unlock(&this->lock); return ret;}static int doc_erase(struct mtd_info *mtd, struct erase_info *instr){ struct DiskOnChip *this = mtd->priv; __u32 ofs = instr->addr; __u32 len = instr->len; volatile int dummy; void __iomem *docptr = this->virtadr; struct Nand *mychip; int status; mutex_lock(&this->lock); if (ofs & (mtd->erasesize-1) || len & (mtd->erasesize-1)) { mutex_unlock(&this->lock); return -EINVAL; } instr->state = MTD_ERASING; /* FIXME: Do this in the background. Use timers or schedule_task() */ while(len) { mychip = &this->chips[ofs >> this->chipshift]; if (this->curfloor != mychip->floor) { DoC_SelectFloor(this, mychip->floor); DoC_SelectChip(this, mychip->chip); } else if (this->curchip != mychip->chip) { DoC_SelectChip(this, mychip->chip); } this->curfloor = mychip->floor; this->curchip = mychip->chip; DoC_Command(this, NAND_CMD_ERASE1, 0); DoC_Address(this, ADDR_PAGE, ofs, 0, 0); DoC_Command(this, NAND_CMD_ERASE2, 0); DoC_Command(this, NAND_CMD_STATUS, CDSN_CTRL_WP); if (DoC_is_Millennium(this)) { ReadDOC(docptr, ReadPipeInit); status = ReadDOC(docptr, LastDataRead); } else { dummy = ReadDOC(docptr, CDSNSlowIO); DoC_Delay(this, 2); status = ReadDOC_(docptr, this->ioreg); } if (status & 1) { printk(KERN_ERR "Error erasing at 0x%x\n", ofs); /* There was an error */ instr->state = MTD_ERASE_FAILED; goto callback; } ofs += mtd->erasesize; len -= mtd->erasesize; } instr->state = MTD_ERASE_DONE; callback: mtd_erase_callback(instr); mutex_unlock(&this->lock); return 0;}/**************************************************************************** * * Module stuff * ****************************************************************************/static void __exit cleanup_doc2000(void){ struct mtd_info *mtd; struct DiskOnChip *this; while ((mtd = doc2klist)) { this = mtd->priv; doc2klist = this->nextdoc; del_mtd_device(mtd); iounmap(this->virtadr); kfree(this->chips); kfree(mtd); }}module_exit(cleanup_doc2000);MODULE_LICENSE("GPL");MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org> et al.");MODULE_DESCRIPTION("MTD driver for DiskOnChip 2000 and Millennium");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -