[PATCH 07/20] mtd: pxa3xx_nand: mtd scan id process could be defined by driver itself
Lei Wen
adrian.wenl at gmail.com
Mon May 24 04:36:13 EDT 2010
On Mon, May 24, 2010 at 3:28 PM, Mike Rapoport <mike at compulab.co.il> wrote:
> Haojian Zhuang wrote:
>>
>> From f2010885a9d5cebfd3cca63b59fff941502f78b3 Mon Sep 17 00:00:00 2001
>> From: Lei Wen <leiwen at marvell.com>
>> Date: Thu, 6 May 2010 09:48:30 +0800
>> Subject: [PATCH] mtd: pxa3xx_nand: mtd scan id process could be
>> defined by driver itself
>>
>> Different NAND driver may require its unique detection. For pxa3xx_nand,
>> it use its self id database to get the necessary info.
>>
>> Signed-off-by: Lei Wen <leiwen at marvell.com>
>> Signed-off-by: Haojian Zhuang <haojian.zhuang at marvell.com>
>> ---
>> drivers/mtd/nand/pxa3xx_nand.c | 257
>> +++++++++++++++++++++++++++++-----------
>> 1 files changed, 185 insertions(+), 72 deletions(-)
>>
>> diff --git a/drivers/mtd/nand/pxa3xx_nand.c
>> b/drivers/mtd/nand/pxa3xx_nand.c
>> index 854adad..7a8ff38 100644
>> --- a/drivers/mtd/nand/pxa3xx_nand.c
>> +++ b/drivers/mtd/nand/pxa3xx_nand.c
>> @@ -255,6 +255,8 @@ static struct pxa3xx_nand_flash __devinitdata
>> builtin_flash_types[] = {
>> { 0xba20, 64, 2048, 16, 16, 2048, { 10, 35, 15, 25, 15, 25, 25000,
>> 60, 10, }, },
>> };
>>
>> +static const char *mtd_names[] = {"pxa3xx_nand-0", NULL};
>> +
>> #define NDTR0_tCH(c) (min((c), 7) << 19)
>> #define NDTR0_tCS(c) (min((c), 7) << 16)
>> #define NDTR0_tWH(c) (min((c), 7) << 11)
>> @@ -893,37 +895,6 @@ static int pxa3xx_nand_detect_config(struct
>> pxa3xx_nand_info *info)
>> return 0;
>> }
>>
>> -static int pxa3xx_nand_detect_flash(struct pxa3xx_nand_info *info,
>> - const struct pxa3xx_nand_platform_data
>> *pdata)
>> -{
>> - const struct pxa3xx_nand_flash *f;
>> - uint32_t id = -1;
>> - int i;
>> -
>> - if (pdata->keep_config)
>> - if (pxa3xx_nand_detect_config(info) == 0)
>> - return 0;
>
> NAK. You're breaking platforms that rely on this feature.
>
>> - f = &builtin_flash_types[0];
>> - pxa3xx_nand_config_flash(info, f);
>> - pxa3xx_nand_cmdfunc(info->mtd, NAND_CMD_READID, 0, 0);
>> - id = *((uint16_t *)(info->data_buff));
>> -
>> - for (i = 1; i < ARRAY_SIZE(builtin_flash_types); i++) {
>> - f = &builtin_flash_types[i];
>> - if (f->chip_id == id) {
>> - dev_info(&info->pdev->dev, "detect chip id:
>> 0x%x\n", id);
>> - pxa3xx_nand_config_flash(info, f);
>> - return 0;
>> - }
>> - }
>> -
>> - dev_warn(&info->pdev->dev,
>> - "failed to detect configured nand flash; found
>> %04x instead of\n",
>> - id);
>> - return -ENODEV;
>> -}
>> -
>> /* the maximum possible buffer size for large page with OOB data
>> * is: 2048 + 64 = 2112 bytes, allocate a page here for both the
>> * data buffer and the DMA descriptor
>> @@ -980,41 +951,174 @@ static struct nand_ecclayout hw_largepage_ecclayout
>> = {
>> .oobfree = { {2, 38} }
>> };
>>
>> -static void pxa3xx_nand_init_mtd(struct mtd_info *mtd,
>> - struct pxa3xx_nand_info *info)
>
> why are you removing the pxa3xx_nand_init_mtd? moving it's entire contents
> into alloc_nand_resource would make the latter overgrown....
>
>> +static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd,
>> + struct nand_chip *chip, uint8_t *buf, int page)
>> +{
>> + struct pxa3xx_nand_info *info = mtd->priv;
>> +
>> + chip->read_buf(mtd, buf, mtd->writesize);
>> + chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
>> +
>> + if (info->retcode == ERR_SBERR) {
>> + switch (info->use_ecc) {
>> + case 1:
>> + mtd->ecc_stats.corrected ++;
>> + break;
>> +
>> + case 0:
>> + default:
>> + break;
>> + }
>> + }
>> + else if (info->retcode == ERR_DBERR) {
>> + int buf_blank;
>> +
>> + buf_blank = is_buf_blank(buf, mtd->writesize);
>> + if (!buf_blank)
>> + mtd->ecc_stats.failed++;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static void pxa3xx_nand_write_page_hwecc(struct mtd_info *mtd,
>> + struct nand_chip *chip, const uint8_t *buf)
>> +{
>> + chip->write_buf(mtd, buf, mtd->writesize);
>> + chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
>> +}
>> +
>> +static void pxa3xx_nand_erase_cmd(struct mtd_info *mtd, int page)
>> {
>> - struct nand_chip *this = &info->nand_chip;
>> -
>> - this->options = (info->reg_ndcr & NDCR_DWIDTH_C) ?
>> NAND_BUSWIDTH_16: 0;
>> -
>> - this->waitfunc = pxa3xx_nand_waitfunc;
>> - this->select_chip = pxa3xx_nand_select_chip;
>> - this->dev_ready = pxa3xx_nand_dev_ready;
>> - this->cmdfunc = pxa3xx_nand_cmdfunc;
>> - this->read_word = pxa3xx_nand_read_word;
>> - this->read_byte = pxa3xx_nand_read_byte;
>> - this->read_buf = pxa3xx_nand_read_buf;
>> - this->write_buf = pxa3xx_nand_write_buf;
>> - this->verify_buf = pxa3xx_nand_verify_buf;
>> -
>> - this->ecc.mode = NAND_ECC_HW;
>> - this->ecc.hwctl = pxa3xx_nand_ecc_hwctl;
>> - this->ecc.calculate = pxa3xx_nand_ecc_calculate;
>> - this->ecc.correct = pxa3xx_nand_ecc_correct;
>> - this->ecc.size = info->page_size;
>> -
>> - if (info->page_size == 2048)
>> - this->ecc.layout = &hw_largepage_ecclayout;
>> + struct nand_chip *chip = mtd->priv;
>> + /* Send commands to erase a block */
>> + chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page);
>> +}
>> +
>> +static int pxa3xx_nand_sensing(struct pxa3xx_nand_info *info)
>> +{
>> + struct mtd_info *mtd = info->mtd;
>> + struct nand_chip *chip = mtd->priv;
>> +
>> + /* use the common timing to make a try */
>> + pxa3xx_nand_config_flash(info, &builtin_flash_types[0]);
>> + chip->cmdfunc(mtd, NAND_CMD_RESET, 0, 0);
>> + if (info->state & STATE_READY)
>> + return 1;
>> else
>> - this->ecc.layout = &hw_smallpage_ecclayout;
>> + return 0;
>> +}
>> +
>> +static int pxa3xx_nand_scan(struct mtd_info *mtd)
>> +{
>> + struct pxa3xx_nand_info *info = mtd->priv;
>> + struct pxa3xx_nand_flash *f;
>> + struct nand_chip *chip = mtd->priv;
>> + uint32_t id = -1;
>> + int i, ret;
>>
>> - this->chip_delay = 25;
>> + ret = pxa3xx_nand_sensing(info);
>> + if (!ret) {
>> + kfree(mtd);
>> + info->mtd = NULL;
>> + printk(KERN_INFO "There is no nand chip on cs 0!\n");
>> +
>> + return -EINVAL;
>> + }
>> +
>> + chip->cmdfunc(mtd, NAND_CMD_READID, 0, 0);
>> + id = *((uint16_t *)(info->data_buff));
>> + if (id != 0)
>> + printk(KERN_INFO "Detect a flash id %x\n", id);
>> + else {
>> + kfree(mtd);
>> + info->mtd = NULL;
>> + printk(KERN_WARNING "Read out ID 0, potential timing set
>> wrong!!\n");
>> +
>> + return -EINVAL;
>> + }
>> +
>> + for (i = 1; i < ARRAY_SIZE(builtin_flash_types); i++) {
>> +
>> + f = &builtin_flash_types[i];
>> +
>> + /* find the chip in default list */
>> + if (f->chip_id == id) {
>> + pxa3xx_nand_config_flash(info, f);
>> + chip->cellinfo = info->data_buff[2];
>> + mtd->writesize = f->page_size;
>> + mtd->writesize_shift = ffs(mtd->writesize) - 1;
>> + mtd->writesize_mask = (1 << mtd->writesize_shift)
>> - 1;
>> + mtd->oobsize = mtd->writesize / 32;
>> + mtd->erasesize = f->page_size * f->page_per_block;
>> + mtd->erasesize_shift = ffs(mtd->erasesize) - 1;
>> + mtd->erasesize_mask = (1 << mtd->erasesize_shift)
>> - 1;
>> +
>> + mtd->name = mtd_names[0];
>> + break;
>> + }
>> + }
>> +
>> + if (i == ARRAY_SIZE(builtin_flash_types)) {
>> + kfree(mtd);
>> + info->mtd = NULL;
>> + printk(KERN_ERR "ERROR!! flash not defined!!!\n");
>> +
>> + return -EINVAL;
>> + }
>> +
>> + chip->ecc.mode = NAND_ECC_HW;
>> + chip->ecc.size = f->page_size;
>> + if (f->page_size == 2048)
>> + chip->ecc.layout = &hw_largepage_ecclayout;
>> + else
>> + chip->ecc.layout = &hw_smallpage_ecclayout;
>> +
>> + chip->chipsize = (uint64_t)f->num_blocks * \
>> + f->page_per_block * \
>> + f->page_size;
>> +
>> + chip->chip_shift = ffs(chip->chipsize) - 1;
>> + mtd->size = chip->chipsize;
>> +
>> + /* Calculate the address shift from the page size */
>> + chip->page_shift = ffs(mtd->writesize) - 1;
>> + chip->pagemask = mtd_div_by_ws(chip->chipsize, mtd) - 1;
>> + chip->numchips = 1;
>> + chip->chip_delay = 25;
>> + chip->bbt_erase_shift = chip->phys_erase_shift =
>> ffs(mtd->erasesize) - 1;
>> +
>> + /* Set the bad block position */
>> + chip->badblockpos = mtd->writesize > 512 ?
>> + NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS;
>> +
>> + chip->options = (f->flash_width == 16) ? NAND_BUSWIDTH_16: 0;
>> + chip->options |= NAND_NO_AUTOINCR;
>> + chip->options |= NAND_NO_READRDY;
>> + chip->options |= NAND_USE_FLASH_BBT;
>> +
>> + return nand_scan_tail(mtd);
>> +}
>> +
>> +static int pxa3xx_nand_default_block_markbad(struct mtd_info *mtd, loff_t
>> ofs)
>> +{
>> + struct nand_chip *chip = mtd->priv;
>> + int block;
>> +
>> + block = (int)(ofs >> chip->bbt_erase_shift);
>> + chip->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);
>> + return nand_update_bbt(mtd, ofs);
>> +}
>> +
>> +static int pxa3xx_nand_block_bad(struct mtd_info *mtd, loff_t ofs, int
>> getchip)
>> +{
>> + return 0;
>> }
>>
>> static int alloc_nand_resource(struct platform_device *pdev)
>> {
>> - struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data;
>> struct pxa3xx_nand_info *info;
>> + struct nand_chip *chip;
>> struct mtd_info *mtd;
>> struct resource *r;
>> int ret, irq;
>> @@ -1027,12 +1131,31 @@ static int alloc_nand_resource(struct
>> platform_device *pdev)
>> }
>>
>> info = (struct pxa3xx_nand_info *)(&mtd[1]);
>> + chip = (struct nand_chip *)(&mtd[1]);
>> info->pdev = pdev;
>> -
>> - mtd->priv = info;
>> info->mtd = mtd;
>> + mtd->priv = info;
>> mtd->owner = THIS_MODULE;
>>
>> + chip->ecc.read_page = pxa3xx_nand_read_page_hwecc;
>> + chip->ecc.write_page = pxa3xx_nand_write_page_hwecc;
>> + chip->ecc.hwctl = pxa3xx_nand_ecc_hwctl;
>> + chip->ecc.calculate = pxa3xx_nand_ecc_calculate;
>> + chip->ecc.correct = pxa3xx_nand_ecc_correct;
>> + chip->waitfunc = pxa3xx_nand_waitfunc;
>> + chip->select_chip = pxa3xx_nand_select_chip;
>> + chip->dev_ready = pxa3xx_nand_dev_ready;
>> + chip->cmdfunc = pxa3xx_nand_cmdfunc;
>> + chip->read_word = pxa3xx_nand_read_word;
>> + chip->read_byte = pxa3xx_nand_read_byte;
>> + chip->read_buf = pxa3xx_nand_read_buf;
>> + chip->write_buf = pxa3xx_nand_write_buf;
>> + chip->verify_buf = pxa3xx_nand_verify_buf;
>> + chip->block_markbad = pxa3xx_nand_default_block_markbad;
>> + chip->block_bad = pxa3xx_nand_block_bad;
>> + chip->scan_bbt = nand_default_bbt;
>> + chip->erase_cmd = pxa3xx_nand_erase_cmd;
>> +
>
> this definitely has nothing to do with resource allocation.
>
This patch is just a code clean. In theory, alloc_nand_resource would
not overgrow for from whole code aspect, the most complex part is in
command handling.
Also we need know the status of nand chip in two chip select. Only by
this, than we can alloc proper resource.
Thanks,
Lei
More information about the linux-mtd
mailing list