in nand/onenand/onenand_base.c [3813:3979]
int onenand_scan(struct mtd_info *mtd, int maxchips)
{
int i, ret;
struct onenand_chip *this = mtd->priv;
if (!this->read_word)
this->read_word = onenand_readw;
if (!this->write_word)
this->write_word = onenand_writew;
if (!this->command)
this->command = onenand_command;
if (!this->wait)
onenand_setup_wait(mtd);
if (!this->bbt_wait)
this->bbt_wait = onenand_bbt_wait;
if (!this->unlock_all)
this->unlock_all = onenand_unlock_all;
if (!this->chip_probe)
this->chip_probe = onenand_chip_probe;
if (!this->read_bufferram)
this->read_bufferram = onenand_read_bufferram;
if (!this->write_bufferram)
this->write_bufferram = onenand_write_bufferram;
if (!this->block_markbad)
this->block_markbad = onenand_default_block_markbad;
if (!this->scan_bbt)
this->scan_bbt = onenand_default_bbt;
if (onenand_probe(mtd))
return -ENXIO;
/* Set Sync. Burst Read after probing */
if (this->mmcontrol) {
printk(KERN_INFO "OneNAND Sync. Burst Read support\n");
this->read_bufferram = onenand_sync_read_bufferram;
}
/* Allocate buffers, if necessary */
if (!this->page_buf) {
this->page_buf = kzalloc(mtd->writesize, GFP_KERNEL);
if (!this->page_buf)
return -ENOMEM;
#ifdef CONFIG_MTD_ONENAND_VERIFY_WRITE
this->verify_buf = kzalloc(mtd->writesize, GFP_KERNEL);
if (!this->verify_buf) {
kfree(this->page_buf);
return -ENOMEM;
}
#endif
this->options |= ONENAND_PAGEBUF_ALLOC;
}
if (!this->oob_buf) {
this->oob_buf = kzalloc(mtd->oobsize, GFP_KERNEL);
if (!this->oob_buf) {
if (this->options & ONENAND_PAGEBUF_ALLOC) {
this->options &= ~ONENAND_PAGEBUF_ALLOC;
#ifdef CONFIG_MTD_ONENAND_VERIFY_WRITE
kfree(this->verify_buf);
#endif
kfree(this->page_buf);
}
return -ENOMEM;
}
this->options |= ONENAND_OOBBUF_ALLOC;
}
this->state = FL_READY;
init_waitqueue_head(&this->wq);
spin_lock_init(&this->chip_lock);
/*
* Allow subpage writes up to oobsize.
*/
switch (mtd->oobsize) {
case 128:
if (FLEXONENAND(this)) {
mtd_set_ooblayout(mtd, &flexonenand_ooblayout_ops);
mtd->subpage_sft = 0;
} else {
mtd_set_ooblayout(mtd, &onenand_oob_128_ooblayout_ops);
mtd->subpage_sft = 2;
}
if (ONENAND_IS_NOP_1(this))
mtd->subpage_sft = 0;
break;
case 64:
mtd_set_ooblayout(mtd, &onenand_oob_32_64_ooblayout_ops);
mtd->subpage_sft = 2;
break;
case 32:
mtd_set_ooblayout(mtd, &onenand_oob_32_64_ooblayout_ops);
mtd->subpage_sft = 1;
break;
default:
printk(KERN_WARNING "%s: No OOB scheme defined for oobsize %d\n",
__func__, mtd->oobsize);
mtd->subpage_sft = 0;
/* To prevent kernel oops */
mtd_set_ooblayout(mtd, &onenand_oob_32_64_ooblayout_ops);
break;
}
this->subpagesize = mtd->writesize >> mtd->subpage_sft;
/*
* The number of bytes available for a client to place data into
* the out of band area
*/
ret = mtd_ooblayout_count_freebytes(mtd);
if (ret < 0)
ret = 0;
mtd->oobavail = ret;
mtd->ecc_strength = 1;
/* Fill in remaining MTD driver data */
mtd->type = ONENAND_IS_MLC(this) ? MTD_MLCNANDFLASH : MTD_NANDFLASH;
mtd->flags = MTD_CAP_NANDFLASH;
mtd->_erase = onenand_erase;
mtd->_point = NULL;
mtd->_unpoint = NULL;
mtd->_read_oob = onenand_read_oob;
mtd->_write_oob = onenand_write_oob;
mtd->_panic_write = onenand_panic_write;
#ifdef CONFIG_MTD_ONENAND_OTP
mtd->_get_fact_prot_info = onenand_get_fact_prot_info;
mtd->_read_fact_prot_reg = onenand_read_fact_prot_reg;
mtd->_get_user_prot_info = onenand_get_user_prot_info;
mtd->_read_user_prot_reg = onenand_read_user_prot_reg;
mtd->_write_user_prot_reg = onenand_write_user_prot_reg;
mtd->_lock_user_prot_reg = onenand_lock_user_prot_reg;
#endif
mtd->_sync = onenand_sync;
mtd->_lock = onenand_lock;
mtd->_unlock = onenand_unlock;
mtd->_suspend = onenand_suspend;
mtd->_resume = onenand_resume;
mtd->_block_isbad = onenand_block_isbad;
mtd->_block_markbad = onenand_block_markbad;
mtd->owner = THIS_MODULE;
mtd->writebufsize = mtd->writesize;
/* Unlock whole block */
if (!(this->options & ONENAND_SKIP_INITIAL_UNLOCKING))
this->unlock_all(mtd);
/* Set the bad block marker position */
this->badblockpos = ONENAND_BADBLOCK_POS;
ret = this->scan_bbt(mtd);
if ((!FLEXONENAND(this)) || ret)
return ret;
/* Change Flex-OneNAND boundaries if required */
for (i = 0; i < MAX_DIES; i++)
flexonenand_set_boundary(mtd, i, flex_bdry[2 * i],
flex_bdry[(2 * i) + 1]);
return 0;
}