mtd: rawnand: davinci: convert driver to nand_scan()
Two helpers have been added to the core to do all kind of controller side configuration/initialization between the detection phase and the final NAND scan. Implement these hooks so that we can convert the driver to just use nand_scan() instead of the nand_scan_ident() + nand_scan_tail() pair. Also change the unused "struct device *dev" parameter of the driver structure into a platform device to reuse it in the ->attach_chip() hook. Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com> Reviewed-by: Boris Brezillon <boris.brezillon@bootlin.com>
This commit is contained in:
parent
c1070db383
commit
b2342c1c80
|
@ -53,7 +53,7 @@
|
|||
struct davinci_nand_info {
|
||||
struct nand_chip chip;
|
||||
|
||||
struct device *dev;
|
||||
struct platform_device *pdev;
|
||||
|
||||
bool is_readmode;
|
||||
|
||||
|
@ -605,6 +605,104 @@ static struct davinci_nand_pdata
|
|||
}
|
||||
#endif
|
||||
|
||||
static int davinci_nand_attach_chip(struct nand_chip *chip)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct davinci_nand_info *info = to_davinci_nand(mtd);
|
||||
struct davinci_nand_pdata *pdata = nand_davinci_get_pdata(info->pdev);
|
||||
int ret = 0;
|
||||
|
||||
if (IS_ERR(pdata))
|
||||
return PTR_ERR(pdata);
|
||||
|
||||
switch (info->chip.ecc.mode) {
|
||||
case NAND_ECC_NONE:
|
||||
pdata->ecc_bits = 0;
|
||||
break;
|
||||
case NAND_ECC_SOFT:
|
||||
pdata->ecc_bits = 0;
|
||||
/*
|
||||
* This driver expects Hamming based ECC when ecc_mode is set
|
||||
* to NAND_ECC_SOFT. Force ecc.algo to NAND_ECC_HAMMING to
|
||||
* avoid adding an extra ->ecc_algo field to
|
||||
* davinci_nand_pdata.
|
||||
*/
|
||||
info->chip.ecc.algo = NAND_ECC_HAMMING;
|
||||
break;
|
||||
case NAND_ECC_HW:
|
||||
if (pdata->ecc_bits == 4) {
|
||||
/*
|
||||
* No sanity checks: CPUs must support this,
|
||||
* and the chips may not use NAND_BUSWIDTH_16.
|
||||
*/
|
||||
|
||||
/* No sharing 4-bit hardware between chipselects yet */
|
||||
spin_lock_irq(&davinci_nand_lock);
|
||||
if (ecc4_busy)
|
||||
ret = -EBUSY;
|
||||
else
|
||||
ecc4_busy = true;
|
||||
spin_unlock_irq(&davinci_nand_lock);
|
||||
|
||||
if (ret == -EBUSY)
|
||||
return ret;
|
||||
|
||||
info->chip.ecc.calculate = nand_davinci_calculate_4bit;
|
||||
info->chip.ecc.correct = nand_davinci_correct_4bit;
|
||||
info->chip.ecc.hwctl = nand_davinci_hwctl_4bit;
|
||||
info->chip.ecc.bytes = 10;
|
||||
info->chip.ecc.options = NAND_ECC_GENERIC_ERASED_CHECK;
|
||||
info->chip.ecc.algo = NAND_ECC_BCH;
|
||||
} else {
|
||||
/* 1bit ecc hamming */
|
||||
info->chip.ecc.calculate = nand_davinci_calculate_1bit;
|
||||
info->chip.ecc.correct = nand_davinci_correct_1bit;
|
||||
info->chip.ecc.hwctl = nand_davinci_hwctl_1bit;
|
||||
info->chip.ecc.bytes = 3;
|
||||
info->chip.ecc.algo = NAND_ECC_HAMMING;
|
||||
}
|
||||
info->chip.ecc.size = 512;
|
||||
info->chip.ecc.strength = pdata->ecc_bits;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update ECC layout if needed ... for 1-bit HW ECC, the default
|
||||
* is OK, but it allocates 6 bytes when only 3 are needed (for
|
||||
* each 512 bytes). For the 4-bit HW ECC, that default is not
|
||||
* usable: 10 bytes are needed, not 6.
|
||||
*/
|
||||
if (pdata->ecc_bits == 4) {
|
||||
int chunks = mtd->writesize / 512;
|
||||
|
||||
if (!chunks || mtd->oobsize < 16) {
|
||||
dev_dbg(&info->pdev->dev, "too small\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* For small page chips, preserve the manufacturer's
|
||||
* badblock marking data ... and make sure a flash BBT
|
||||
* table marker fits in the free bytes.
|
||||
*/
|
||||
if (chunks == 1) {
|
||||
mtd_set_ooblayout(mtd, &hwecc4_small_ooblayout_ops);
|
||||
} else if (chunks == 4 || chunks == 8) {
|
||||
mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
|
||||
info->chip.ecc.mode = NAND_ECC_HW_OOB_FIRST;
|
||||
} else {
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct nand_controller_ops davinci_nand_controller_ops = {
|
||||
.attach_chip = davinci_nand_attach_chip,
|
||||
};
|
||||
|
||||
static int nand_davinci_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct davinci_nand_pdata *pdata;
|
||||
|
@ -658,7 +756,7 @@ static int nand_davinci_probe(struct platform_device *pdev)
|
|||
return -EADDRNOTAVAIL;
|
||||
}
|
||||
|
||||
info->dev = &pdev->dev;
|
||||
info->pdev = pdev;
|
||||
info->base = base;
|
||||
info->vaddr = vaddr;
|
||||
|
||||
|
@ -708,97 +806,13 @@ static int nand_davinci_probe(struct platform_device *pdev)
|
|||
spin_unlock_irq(&davinci_nand_lock);
|
||||
|
||||
/* Scan to find existence of the device(s) */
|
||||
ret = nand_scan_ident(mtd, pdata->mask_chipsel ? 2 : 1, NULL);
|
||||
info->chip.dummy_controller.ops = &davinci_nand_controller_ops;
|
||||
ret = nand_scan(mtd, pdata->mask_chipsel ? 2 : 1);
|
||||
if (ret < 0) {
|
||||
dev_dbg(&pdev->dev, "no NAND chip(s) found\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
switch (info->chip.ecc.mode) {
|
||||
case NAND_ECC_NONE:
|
||||
pdata->ecc_bits = 0;
|
||||
break;
|
||||
case NAND_ECC_SOFT:
|
||||
pdata->ecc_bits = 0;
|
||||
/*
|
||||
* This driver expects Hamming based ECC when ecc_mode is set
|
||||
* to NAND_ECC_SOFT. Force ecc.algo to NAND_ECC_HAMMING to
|
||||
* avoid adding an extra ->ecc_algo field to
|
||||
* davinci_nand_pdata.
|
||||
*/
|
||||
info->chip.ecc.algo = NAND_ECC_HAMMING;
|
||||
break;
|
||||
case NAND_ECC_HW:
|
||||
if (pdata->ecc_bits == 4) {
|
||||
/* No sanity checks: CPUs must support this,
|
||||
* and the chips may not use NAND_BUSWIDTH_16.
|
||||
*/
|
||||
|
||||
/* No sharing 4-bit hardware between chipselects yet */
|
||||
spin_lock_irq(&davinci_nand_lock);
|
||||
if (ecc4_busy)
|
||||
ret = -EBUSY;
|
||||
else
|
||||
ecc4_busy = true;
|
||||
spin_unlock_irq(&davinci_nand_lock);
|
||||
|
||||
if (ret == -EBUSY)
|
||||
return ret;
|
||||
|
||||
info->chip.ecc.calculate = nand_davinci_calculate_4bit;
|
||||
info->chip.ecc.correct = nand_davinci_correct_4bit;
|
||||
info->chip.ecc.hwctl = nand_davinci_hwctl_4bit;
|
||||
info->chip.ecc.bytes = 10;
|
||||
info->chip.ecc.options = NAND_ECC_GENERIC_ERASED_CHECK;
|
||||
info->chip.ecc.algo = NAND_ECC_BCH;
|
||||
} else {
|
||||
/* 1bit ecc hamming */
|
||||
info->chip.ecc.calculate = nand_davinci_calculate_1bit;
|
||||
info->chip.ecc.correct = nand_davinci_correct_1bit;
|
||||
info->chip.ecc.hwctl = nand_davinci_hwctl_1bit;
|
||||
info->chip.ecc.bytes = 3;
|
||||
info->chip.ecc.algo = NAND_ECC_HAMMING;
|
||||
}
|
||||
info->chip.ecc.size = 512;
|
||||
info->chip.ecc.strength = pdata->ecc_bits;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Update ECC layout if needed ... for 1-bit HW ECC, the default
|
||||
* is OK, but it allocates 6 bytes when only 3 are needed (for
|
||||
* each 512 bytes). For the 4-bit HW ECC, that default is not
|
||||
* usable: 10 bytes are needed, not 6.
|
||||
*/
|
||||
if (pdata->ecc_bits == 4) {
|
||||
int chunks = mtd->writesize / 512;
|
||||
|
||||
if (!chunks || mtd->oobsize < 16) {
|
||||
dev_dbg(&pdev->dev, "too small\n");
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* For small page chips, preserve the manufacturer's
|
||||
* badblock marking data ... and make sure a flash BBT
|
||||
* table marker fits in the free bytes.
|
||||
*/
|
||||
if (chunks == 1) {
|
||||
mtd_set_ooblayout(mtd, &hwecc4_small_ooblayout_ops);
|
||||
} else if (chunks == 4 || chunks == 8) {
|
||||
mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
|
||||
info->chip.ecc.mode = NAND_ECC_HW_OOB_FIRST;
|
||||
} else {
|
||||
ret = -EIO;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
ret = nand_scan_tail(mtd);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
if (pdata->parts)
|
||||
ret = mtd_device_register(mtd, pdata->parts, pdata->nr_parts);
|
||||
else
|
||||
|
@ -815,11 +829,6 @@ static int nand_davinci_probe(struct platform_device *pdev)
|
|||
err_cleanup_nand:
|
||||
nand_cleanup(&info->chip);
|
||||
|
||||
err:
|
||||
spin_lock_irq(&davinci_nand_lock);
|
||||
if (info->chip.ecc.mode == NAND_ECC_HW_SYNDROME)
|
||||
ecc4_busy = false;
|
||||
spin_unlock_irq(&davinci_nand_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue