* [PATCH v2 00/32] Allow dynamic allocations during NAND chip identification phase
@ 2018-07-03 21:59 Miquel Raynal
2018-07-03 21:59 ` [PATCH v2 01/32] mtd: rawnand: add hooks that may be called during nand_scan() Miquel Raynal
` (31 more replies)
0 siblings, 32 replies; 35+ messages in thread
From: Miquel Raynal @ 2018-07-03 21:59 UTC (permalink / raw)
To: linux-arm-kernel
Hello,
This series make a quite deep change in the NAND framework. Until now,
the NAND chip identification phase could be done in two manners from the
controller driver perspective:
1/ Call nand_scan()
or
1/ Call nand_scan_ident()
2/ Do some controller-dependent configuration
3/ Call nand_scan_tail().
The fact that the identifaction could be split in two operations
involved that in the NAND framework, it was not possible to do any
dynamic allocation without risking a memory leak. What if the core
allocates a structure, then the driver between nand_scan_ident() and
nand_scan_tail() decides it cannot handle the chip and errors out?
The structure allocated by the core is lost: it is a memory leak. One
solution could have been to add a nand_scan_ident_cleanup() function,
but that would mean patching all the drivers anyway to make them call
this function when something fails between nand_scan_ident() and
nand_scan_tail().
To avoid this situation, we migrate all drivers to use nand_scan(). But
because drivers need to do some configuration before nand_scan_tail(), a
first hook is offered, embedded in the nand_hw_ctrl structure, called
->attach_chip(). Drivers that need to tweak their configuration after
nand_scan_ident() should implement it. Any dynamically allocated space
in ->attach_chip() must be freed in the second hook: ->detach_chip().
The ->detach_chip() does not have to be called upon error in the
controller driver probe function. The nand_cleanup() helper already
exists for that and will do the call if needed. Of course, this helper
must be called on error after a successful nand_scan(), just like
before.
Once all drivers not using nand_scan() (yet) are migrated,
nand_scan_ident() and nand_scan_tail() are unexported and only available
internally.
A previous work [1] removed the ONFI/JEDEC parameter pages and instead
allocated a nand_parameters structure in nand_chip, embedding both
generic entries and ONFI-related ones. The deal was, once dynamic
allocation possible, allocate in nand_scan_ident() the ONFI strcuture
only if actually needed. This is done in the last patches.
All these changes have been tested with the GPMI driver and tested by
the 0-day robot. They apply now on top of another previous series that
cleaned the error path of all the drivers touched in this series.
Thank you,
Miqu?l
[1] http://lists.infradead.org/pipermail/linux-mtd/2018-March/079456.html
Changes since v1:
=================
* Rebased on top of nand/next.
* Light rewording of the cover letter about the possibility to have a
nand_scan_ident_cleanup() function (just as example of how this series
could have been done differently).
* Changed the hooks to reside in the nand_hw_ctrl structure instead of
being part of nand_ecc_ctrl as these hooks are more
controller-related.
Miquel Raynal (32):
mtd: rawnand: add hooks that may be called during nand_scan()
mtd: rawnand: brcmnand: convert driver to nand_scan()
mtd: rawnand: cafe: convert driver to nand_scan()
mtd: rawnand: davinci: convert driver to nand_scan()
mtd: rawnand: denali: convert to nand_scan()
mtd: rawnand: fsl_elbc: convert driver to nand_scan()
mtd: rawnand: fsl_ifc: convert driver to nand_scan()
mtd: rawnand: fsmc: convert driver to nand_scan()
mtd: rawnand: gpmi: convert driver to nand_scan()
mtd: rawnand: hisi504: convert driver to nand_scan()
mtd: rawnand: jz4780: convert driver to nand_scan()
mtd: rawnand: lpc32xx_mlc: convert driver to nand_scan()
mtd: rawnand: lpc32xx_slc: convert driver to nand_scan()
mtd: rawnand: marvell: convert driver to nand_scan()
mtd: rawnand: mtk: convert driver to nand_scan()
mtd: rawnand: mxc: convert driver to nand_scan()
mtd: rawnand: nandsim: convert driver to nand_scan()
mtd: rawnand: omap2: convert driver to nand_scan()
mtd: rawnand: s3c2410: convert driver to nand_scan()
mtd: rawnand: sh_flctl: move all NAND chip related setup in one
function
mtd: rawnand: sh_flctl: convert driver to nand_scan()
mtd: rawnand: sunxi: convert driver to nand_scan()
mtd: rawnand: tango: convert driver to nand_scan()
mtd: rawnand: txx9ndfmc: convert driver to nand_scan()
mtd: rawnand: vf610: convert driver to nand_scan()
mtd: rawnand: atmel: convert driver to nand_scan()
mtd: rawnand: sm_common: convert driver to nand_scan_with_ids()
mtd: rawnand: docg4: convert driver to nand_scan()
mtd: rawnand: qcom: convert driver to nand_scan()
mtd: rawnand: jz4740: convert driver to nand_scan()
mtd: rawnand: do not export nand_scan_[ident|tail]() anymore
mtd: rawnand: allocate dynamically ONFI parameters during detection
drivers/mtd/nand/raw/atmel/nand-controller.c | 70 ++--
drivers/mtd/nand/raw/brcmnand/brcmnand.c | 43 ++-
drivers/mtd/nand/raw/cafe_nand.c | 131 ++++---
drivers/mtd/nand/raw/davinci_nand.c | 186 +++++-----
drivers/mtd/nand/raw/denali.c | 134 +++----
drivers/mtd/nand/raw/docg4.c | 51 +--
drivers/mtd/nand/raw/fsl_elbc_nand.c | 15 +-
drivers/mtd/nand/raw/fsl_ifc_nand.c | 15 +-
drivers/mtd/nand/raw/fsmc_nand.c | 144 ++++----
drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c | 52 +--
drivers/mtd/nand/raw/hisi504_nand.c | 74 ++--
drivers/mtd/nand/raw/jz4740_nand.c | 42 ++-
drivers/mtd/nand/raw/jz4780_nand.c | 30 +-
drivers/mtd/nand/raw/lpc32xx_mlc.c | 105 +++---
drivers/mtd/nand/raw/lpc32xx_slc.c | 73 ++--
drivers/mtd/nand/raw/marvell_nand.c | 201 ++++++-----
drivers/mtd/nand/raw/mtk_nand.c | 71 ++--
drivers/mtd/nand/raw/mxc_nand.c | 132 +++----
drivers/mtd/nand/raw/nand_base.c | 132 +++++--
drivers/mtd/nand/raw/nand_micron.c | 6 +-
drivers/mtd/nand/raw/nand_timings.c | 12 +-
drivers/mtd/nand/raw/nandsim.c | 78 ++--
drivers/mtd/nand/raw/omap2.c | 517 +++++++++++++--------------
drivers/mtd/nand/raw/qcom_nandc.c | 67 ++--
drivers/mtd/nand/raw/s3c2410.c | 26 +-
drivers/mtd/nand/raw/sh_flctl.c | 53 ++-
drivers/mtd/nand/raw/sm_common.c | 35 +-
drivers/mtd/nand/raw/sunxi_nand.c | 38 +-
drivers/mtd/nand/raw/tango_nand.c | 36 +-
drivers/mtd/nand/raw/txx9ndfmc.c | 25 +-
drivers/mtd/nand/raw/vf610_nfc.c | 123 +++----
include/linux/mtd/rawnand.h | 23 +-
include/linux/mtd/sh_flctl.h | 1 +
33 files changed, 1414 insertions(+), 1327 deletions(-)
--
2.14.1
^ permalink raw reply [flat|nested] 35+ messages in thread
* [PATCH v2 01/32] mtd: rawnand: add hooks that may be called during nand_scan()
2018-07-03 21:59 [PATCH v2 00/32] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
@ 2018-07-03 21:59 ` Miquel Raynal
2018-07-04 7:09 ` Boris Brezillon
2018-07-03 21:59 ` [PATCH v2 02/32] mtd: rawnand: brcmnand: convert driver to nand_scan() Miquel Raynal
` (30 subsequent siblings)
31 siblings, 1 reply; 35+ messages in thread
From: Miquel Raynal @ 2018-07-03 21:59 UTC (permalink / raw)
To: linux-arm-kernel
In order to remove the limitation that forbids dynamic allocation in
nand_scan_ident(), we must create a path that will be the same for all
controller drivers. The idea is to use nand_scan() instead of the widely
implemented nand_scan_ident()/nand_scan_tail() couple. In order to
achieve this, controller drivers will need to adjust some parameters
between these two functions depending on the NAND chip wired on them.
For that, a hook called ->attach_chip() is created in the
nand_hw_control structure. This structure may be referenced by two ways:
1/ if the driver does not implement its own controller, the
chip->controller hook is not populated before nand_scan() so it
cannot be dereferenced: use chip->hwcontrol instead (which is
statically allocated and will be referenced later by chip->controller
anyway).
2/ through chip->controller if the driver implements its own controller.
Another hook, ->detach_chip() is also introduced in order to clean the
controller driver's potential allocations in case of failure of
nand_scan_tail(). There is no need for the controller driver to call the
->detach_chip() hook directly upon error after a successful nand_scan().
In this situation, calling nand_release() as before is enough.
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
drivers/mtd/nand/raw/nand_base.c | 21 +++++++++++++++++++--
include/linux/mtd/rawnand.h | 6 ++++++
2 files changed, 25 insertions(+), 2 deletions(-)
diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
index faac82b1e058..97a74d48b0cf 100644
--- a/drivers/mtd/nand/raw/nand_base.c
+++ b/drivers/mtd/nand/raw/nand_base.c
@@ -6712,11 +6712,23 @@ EXPORT_SYMBOL(nand_scan_tail);
int nand_scan_with_ids(struct mtd_info *mtd, int maxchips,
struct nand_flash_dev *ids)
{
+ struct nand_chip *chip = mtd_to_nand(mtd);
int ret;
ret = nand_scan_ident(mtd, maxchips, ids);
- if (!ret)
- ret = nand_scan_tail(mtd);
+ if (ret)
+ return ret;
+
+ if (chip->controller->attach_chip) {
+ ret = chip->controller->attach_chip(chip);
+ if (ret)
+ return ret;
+ }
+
+ ret = nand_scan_tail(mtd);
+ if (ret && chip->controller->detach_chip)
+ chip->controller->detach_chip(chip);
+
return ret;
}
EXPORT_SYMBOL(nand_scan_with_ids);
@@ -6744,7 +6756,12 @@ void nand_cleanup(struct nand_chip *chip)
/* Free manufacturer priv data. */
nand_manufacturer_cleanup(chip);
+
+ /* Free controller specific allocations after chip identification */
+ if (chip->controller->detach_chip)
+ chip->controller->detach_chip(chip);
}
+
EXPORT_SYMBOL_GPL(nand_cleanup);
/**
diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h
index 0c6fb316b409..81654211e520 100644
--- a/include/linux/mtd/rawnand.h
+++ b/include/linux/mtd/rawnand.h
@@ -517,11 +517,17 @@ struct nand_id {
* @wq: wait queue to sleep on if a NAND operation is in
* progress used instead of the per chip wait queue
* when a hw controller is available.
+ * @attach_chip: Callback that may be called between nand_detect() and
+ * nand_scan_tail() during nand_scan() (optional).
+ * @detach_chip: Callback that may be called if nand_scan_tail() fails
+ * (optional).
*/
struct nand_hw_control {
spinlock_t lock;
struct nand_chip *active;
wait_queue_head_t wq;
+ int (*attach_chip)(struct nand_chip *chip);
+ void (*detach_chip)(struct nand_chip *chip);
};
static inline void nand_hw_control_init(struct nand_hw_control *nfc)
--
2.14.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH v2 02/32] mtd: rawnand: brcmnand: convert driver to nand_scan()
2018-07-03 21:59 [PATCH v2 00/32] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
2018-07-03 21:59 ` [PATCH v2 01/32] mtd: rawnand: add hooks that may be called during nand_scan() Miquel Raynal
@ 2018-07-03 21:59 ` Miquel Raynal
2018-07-04 7:14 ` Boris Brezillon
2018-07-03 22:00 ` [PATCH v2 03/32] mtd: rawnand: cafe: " Miquel Raynal
` (29 subsequent siblings)
31 siblings, 1 reply; 35+ messages in thread
From: Miquel Raynal @ 2018-07-03 21:59 UTC (permalink / raw)
To: linux-arm-kernel
Two helpers have been added to the core to make ECC-related
configuration between the detection phase and the final NAND scan. Use
these hooks and convert the driver to just use nand_scan() instead of
both nand_scan_ident() and nand_scan_tail().
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
drivers/mtd/nand/raw/brcmnand/brcmnand.c | 43 ++++++++++++++++++--------------
1 file changed, 24 insertions(+), 19 deletions(-)
diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.c b/drivers/mtd/nand/raw/brcmnand/brcmnand.c
index 1306aaa7a8bf..99ab7b93756c 100644
--- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c
+++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c
@@ -2208,6 +2208,28 @@ static int brcmnand_setup_dev(struct brcmnand_host *host)
return 0;
}
+static int brcmnand_attach_chip(struct nand_chip *chip)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ struct brcmnand_host *host = nand_get_controller_data(chip);
+ int ret;
+
+ if (chip->bbt_options & NAND_BBT_USE_FLASH)
+ chip->bbt_options |= NAND_BBT_NO_OOB;
+
+ if (brcmnand_setup_dev(host))
+ return -ENXIO;
+
+ chip->ecc.size = host->hwcfg.sector_size_1k ? 1024 : 512;
+
+ /* only use our internal HW threshold */
+ mtd->bitflip_threshold = 1;
+
+ ret = brcmstb_choose_ecc_layout(host);
+
+ return ret;
+}
+
static int brcmnand_init_cs(struct brcmnand_host *host, struct device_node *dn)
{
struct brcmnand_controller *ctrl = host->ctrl;
@@ -2267,10 +2289,6 @@ static int brcmnand_init_cs(struct brcmnand_host *host, struct device_node *dn)
nand_writereg(ctrl, cfg_offs,
nand_readreg(ctrl, cfg_offs) & ~CFG_BUS_WIDTH);
- ret = nand_scan_ident(mtd, 1, NULL);
- if (ret)
- return ret;
-
chip->options |= NAND_NO_SUBPAGE_WRITE;
/*
* Avoid (for instance) kmap()'d buffers from JFFS2, which we can't DMA
@@ -2279,21 +2297,8 @@ static int brcmnand_init_cs(struct brcmnand_host *host, struct device_node *dn)
*/
chip->options |= NAND_USE_BOUNCE_BUFFER;
- if (chip->bbt_options & NAND_BBT_USE_FLASH)
- chip->bbt_options |= NAND_BBT_NO_OOB;
-
- if (brcmnand_setup_dev(host))
- return -ENXIO;
-
- chip->ecc.size = host->hwcfg.sector_size_1k ? 1024 : 512;
- /* only use our internal HW threshold */
- mtd->bitflip_threshold = 1;
-
- ret = brcmstb_choose_ecc_layout(host);
- if (ret)
- return ret;
-
- ret = nand_scan_tail(mtd);
+ chip->controller->attach_chip = brcmnand_attach_chip;
+ ret = nand_scan(mtd, 1);
if (ret)
return ret;
--
2.14.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH v2 03/32] mtd: rawnand: cafe: convert driver to nand_scan()
2018-07-03 21:59 [PATCH v2 00/32] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
2018-07-03 21:59 ` [PATCH v2 01/32] mtd: rawnand: add hooks that may be called during nand_scan() Miquel Raynal
2018-07-03 21:59 ` [PATCH v2 02/32] mtd: rawnand: brcmnand: convert driver to nand_scan() Miquel Raynal
@ 2018-07-03 22:00 ` Miquel Raynal
2018-07-03 22:00 ` [PATCH v2 04/32] mtd: rawnand: davinci: " Miquel Raynal
` (28 subsequent siblings)
31 siblings, 0 replies; 35+ messages in thread
From: Miquel Raynal @ 2018-07-03 22:00 UTC (permalink / raw)
To: linux-arm-kernel
Two helpers have been added to the core to make ECC-related
configuration between the detection phase and the final NAND scan. Use
these hooks and convert the driver to just use nand_scan() instead of
both nand_scan_ident() and nand_scan_tail().
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
drivers/mtd/nand/raw/cafe_nand.c | 131 ++++++++++++++++++++++-----------------
1 file changed, 75 insertions(+), 56 deletions(-)
diff --git a/drivers/mtd/nand/raw/cafe_nand.c b/drivers/mtd/nand/raw/cafe_nand.c
index d721f489b38b..035061606e39 100644
--- a/drivers/mtd/nand/raw/cafe_nand.c
+++ b/drivers/mtd/nand/raw/cafe_nand.c
@@ -71,7 +71,9 @@ struct cafe_priv {
unsigned char *dmabuf;
};
-static int usedma = 1;
+#define CAFE_DEFAULT_DMA 1
+
+static int usedma = CAFE_DEFAULT_DMA;
module_param(usedma, int, 0644);
static int skipbbt = 0;
@@ -598,6 +600,74 @@ static int cafe_mul(int x)
return gf4096_mul(x, 0xe01);
}
+static int cafe_nand_attach_chip(struct nand_chip *chip)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ struct cafe_priv *cafe = nand_get_controller_data(chip);
+ int err = 0;
+
+ cafe->dmabuf = dma_alloc_coherent(&cafe->pdev->dev, 2112,
+ &cafe->dmaaddr, GFP_KERNEL);
+ if (!cafe->dmabuf)
+ return -ENOMEM;
+
+ /* Set up DMA address */
+ cafe_writel(cafe, lower_32_bits(cafe->dmaaddr), NAND_DMA_ADDR0);
+ cafe_writel(cafe, upper_32_bits(cafe->dmaaddr), NAND_DMA_ADDR1);
+
+ cafe_dev_dbg(&cafe->pdev->dev, "Set DMA address to %x (virt %p)\n",
+ cafe_readl(cafe, NAND_DMA_ADDR0), cafe->dmabuf);
+
+ /* Restore the DMA flag */
+ usedma = CAFE_DEFAULT_DMA;
+
+ cafe->ctl2 = BIT(27); /* Reed-Solomon ECC */
+ if (mtd->writesize == 2048)
+ cafe->ctl2 |= BIT(29); /* 2KiB page size */
+
+ /* Set up ECC according to the type of chip we found */
+ mtd_set_ooblayout(mtd, &cafe_ooblayout_ops);
+ if (mtd->writesize == 2048) {
+ cafe->nand.bbt_td = &cafe_bbt_main_descr_2048;
+ cafe->nand.bbt_md = &cafe_bbt_mirror_descr_2048;
+ } else if (mtd->writesize == 512) {
+ cafe->nand.bbt_td = &cafe_bbt_main_descr_512;
+ cafe->nand.bbt_md = &cafe_bbt_mirror_descr_512;
+ } else {
+ dev_warn(&cafe->pdev->dev,
+ "Unexpected NAND flash writesize %d. Aborting\n",
+ mtd->writesize);
+ err = -ENOTSUPP;
+ goto out_free_dma;
+ }
+
+ cafe->nand.ecc.mode = NAND_ECC_HW_SYNDROME;
+ cafe->nand.ecc.size = mtd->writesize;
+ cafe->nand.ecc.bytes = 14;
+ cafe->nand.ecc.strength = 4;
+ cafe->nand.ecc.hwctl = (void *)cafe_nand_bug;
+ cafe->nand.ecc.calculate = (void *)cafe_nand_bug;
+ cafe->nand.ecc.correct = (void *)cafe_nand_bug;
+ cafe->nand.ecc.write_page = cafe_nand_write_page_lowlevel;
+ cafe->nand.ecc.write_oob = cafe_nand_write_oob;
+ cafe->nand.ecc.read_page = cafe_nand_read_page;
+ cafe->nand.ecc.read_oob = cafe_nand_read_oob;
+
+ return 0;
+
+ out_free_dma:
+ dma_free_coherent(&cafe->pdev->dev, 2112, cafe->dmabuf, cafe->dmaaddr);
+
+ return err;
+}
+
+static void cafe_nand_detach_chip(struct nand_chip *chip)
+{
+ struct cafe_priv *cafe = nand_get_controller_data(chip);
+
+ dma_free_coherent(&cafe->pdev->dev, 2112, cafe->dmabuf, cafe->dmaaddr);
+}
+
static int cafe_nand_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
@@ -713,65 +783,16 @@ static int cafe_nand_probe(struct pci_dev *pdev,
cafe_readl(cafe, GLOBAL_CTRL),
cafe_readl(cafe, GLOBAL_IRQ_MASK));
- /* Do not use the DMA for the nand_scan_ident() */
- old_dma = usedma;
+ /* Do not use the DMA during the NAND identification */
usedma = 0;
/* Scan to find existence of the device */
- err = nand_scan_ident(mtd, 2, NULL);
+ cafe->nand.hwcontrol.attach_chip = cafe_nand_attach_chip;
+ cafe->nand.hwcontrol.detach_chip = cafe_nand_detach_chip;
+ err = nand_scan(mtd, 2);
if (err)
goto out_irq;
- cafe->dmabuf = dma_alloc_coherent(&cafe->pdev->dev, 2112,
- &cafe->dmaaddr, GFP_KERNEL);
- if (!cafe->dmabuf) {
- err = -ENOMEM;
- goto out_irq;
- }
-
- /* Set up DMA address */
- cafe_writel(cafe, lower_32_bits(cafe->dmaaddr), NAND_DMA_ADDR0);
- cafe_writel(cafe, upper_32_bits(cafe->dmaaddr), NAND_DMA_ADDR1);
-
- cafe_dev_dbg(&cafe->pdev->dev, "Set DMA address to %x (virt %p)\n",
- cafe_readl(cafe, NAND_DMA_ADDR0), cafe->dmabuf);
-
- /* Restore the DMA flag */
- usedma = old_dma;
-
- cafe->ctl2 = 1<<27; /* Reed-Solomon ECC */
- if (mtd->writesize == 2048)
- cafe->ctl2 |= 1<<29; /* 2KiB page size */
-
- /* Set up ECC according to the type of chip we found */
- mtd_set_ooblayout(mtd, &cafe_ooblayout_ops);
- if (mtd->writesize == 2048) {
- cafe->nand.bbt_td = &cafe_bbt_main_descr_2048;
- cafe->nand.bbt_md = &cafe_bbt_mirror_descr_2048;
- } else if (mtd->writesize == 512) {
- cafe->nand.bbt_td = &cafe_bbt_main_descr_512;
- cafe->nand.bbt_md = &cafe_bbt_mirror_descr_512;
- } else {
- pr_warn("Unexpected NAND flash writesize %d. Aborting\n",
- mtd->writesize);
- goto out_free_dma;
- }
- cafe->nand.ecc.mode = NAND_ECC_HW_SYNDROME;
- cafe->nand.ecc.size = mtd->writesize;
- cafe->nand.ecc.bytes = 14;
- cafe->nand.ecc.strength = 4;
- cafe->nand.ecc.hwctl = (void *)cafe_nand_bug;
- cafe->nand.ecc.calculate = (void *)cafe_nand_bug;
- cafe->nand.ecc.correct = (void *)cafe_nand_bug;
- cafe->nand.ecc.write_page = cafe_nand_write_page_lowlevel;
- cafe->nand.ecc.write_oob = cafe_nand_write_oob;
- cafe->nand.ecc.read_page = cafe_nand_read_page;
- cafe->nand.ecc.read_oob = cafe_nand_read_oob;
-
- err = nand_scan_tail(mtd);
- if (err)
- goto out_free_dma;
-
pci_set_drvdata(pdev, mtd);
mtd->name = "cafe_nand";
@@ -783,8 +804,6 @@ static int cafe_nand_probe(struct pci_dev *pdev,
out_cleanup_nand:
nand_cleanup(&cafe->nand);
- out_free_dma:
- dma_free_coherent(&cafe->pdev->dev, 2112, cafe->dmabuf, cafe->dmaaddr);
out_irq:
/* Disable NAND IRQ in global IRQ mask register */
cafe_writel(cafe, ~1 & cafe_readl(cafe, GLOBAL_IRQ_MASK), GLOBAL_IRQ_MASK);
--
2.14.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH v2 04/32] mtd: rawnand: davinci: convert driver to nand_scan()
2018-07-03 21:59 [PATCH v2 00/32] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
` (2 preceding siblings ...)
2018-07-03 22:00 ` [PATCH v2 03/32] mtd: rawnand: cafe: " Miquel Raynal
@ 2018-07-03 22:00 ` Miquel Raynal
2018-07-03 22:00 ` [PATCH v2 05/32] mtd: rawnand: denali: convert " Miquel Raynal
` (27 subsequent siblings)
31 siblings, 0 replies; 35+ messages in thread
From: Miquel Raynal @ 2018-07-03 22:00 UTC (permalink / raw)
To: linux-arm-kernel
Two helpers have been added to the core to make ECC-related
configuration between the detection phase and the final NAND scan. Use
these hooks and convert the driver to just use nand_scan() instead of
both nand_scan_ident() and nand_scan_tail().
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>
---
drivers/mtd/nand/raw/davinci_nand.c | 186 +++++++++++++++++++-----------------
1 file changed, 98 insertions(+), 88 deletions(-)
diff --git a/drivers/mtd/nand/raw/davinci_nand.c b/drivers/mtd/nand/raw/davinci_nand.c
index cd12e5abafde..f27ce709f5b0 100644
--- a/drivers/mtd/nand/raw/davinci_nand.c
+++ b/drivers/mtd/nand/raw/davinci_nand.c
@@ -53,7 +53,7 @@
struct davinci_nand_info {
struct nand_chip chip;
- struct device *dev;
+ struct platform_device *pdev;
bool is_readmode;
@@ -606,6 +606,100 @@ 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 int nand_davinci_probe(struct platform_device *pdev)
{
struct davinci_nand_pdata *pdata;
@@ -659,7 +753,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;
@@ -711,97 +805,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.hwcontrol.attach_chip = davinci_nand_attach_chip;
+ 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_parse_register(mtd, NULL, NULL,
pdata->parts, pdata->nr_parts);
--
2.14.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH v2 05/32] mtd: rawnand: denali: convert to nand_scan()
2018-07-03 21:59 [PATCH v2 00/32] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
` (3 preceding siblings ...)
2018-07-03 22:00 ` [PATCH v2 04/32] mtd: rawnand: davinci: " Miquel Raynal
@ 2018-07-03 22:00 ` Miquel Raynal
2018-07-03 22:00 ` [PATCH v2 06/32] mtd: rawnand: fsl_elbc: convert driver " Miquel Raynal
` (26 subsequent siblings)
31 siblings, 0 replies; 35+ messages in thread
From: Miquel Raynal @ 2018-07-03 22:00 UTC (permalink / raw)
To: linux-arm-kernel
Two helpers have been added to the core to make ECC-related
configuration between the detection phase and the final NAND scan. Use
these hooks and convert the driver to just use nand_scan() instead of
both nand_scan_ident() and nand_scan_tail().
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
drivers/mtd/nand/raw/denali.c | 134 +++++++++++++++++++++++-------------------
1 file changed, 73 insertions(+), 61 deletions(-)
diff --git a/drivers/mtd/nand/raw/denali.c b/drivers/mtd/nand/raw/denali.c
index 4d53f41ada08..09b85d749552 100644
--- a/drivers/mtd/nand/raw/denali.c
+++ b/drivers/mtd/nand/raw/denali.c
@@ -1205,62 +1205,12 @@ static int denali_multidev_fixup(struct denali_nand_info *denali)
return 0;
}
-int denali_init(struct denali_nand_info *denali)
+static int denali_attach_chip(struct nand_chip *chip)
{
- struct nand_chip *chip = &denali->nand;
struct mtd_info *mtd = nand_to_mtd(chip);
- u32 features = ioread32(denali->reg + FEATURES);
+ struct denali_nand_info *denali = mtd_to_denali(mtd);
int ret;
- mtd->dev.parent = denali->dev;
- denali_hw_init(denali);
-
- init_completion(&denali->complete);
- spin_lock_init(&denali->irq_lock);
-
- denali_clear_irq_all(denali);
-
- ret = devm_request_irq(denali->dev, denali->irq, denali_isr,
- IRQF_SHARED, DENALI_NAND_NAME, denali);
- if (ret) {
- dev_err(denali->dev, "Unable to request IRQ\n");
- return ret;
- }
-
- denali_enable_irq(denali);
- denali_reset_banks(denali);
-
- denali->active_bank = DENALI_INVALID_BANK;
-
- nand_set_flash_node(chip, denali->dev->of_node);
- /* Fallback to the default name if DT did not give "label" property */
- if (!mtd->name)
- mtd->name = "denali-nand";
-
- chip->select_chip = denali_select_chip;
- chip->read_byte = denali_read_byte;
- chip->write_byte = denali_write_byte;
- chip->read_word = denali_read_word;
- chip->cmd_ctrl = denali_cmd_ctrl;
- chip->dev_ready = denali_dev_ready;
- chip->waitfunc = denali_waitfunc;
-
- if (features & FEATURES__INDEX_ADDR) {
- denali->host_read = denali_indexed_read;
- denali->host_write = denali_indexed_write;
- } else {
- denali->host_read = denali_direct_read;
- denali->host_write = denali_direct_write;
- }
-
- /* clk rate info is needed for setup_data_interface */
- if (denali->clk_rate && denali->clk_x_rate)
- chip->setup_data_interface = denali_setup_data_interface;
-
- ret = nand_scan_ident(mtd, denali->max_banks, NULL);
- if (ret)
- goto disable_irq;
-
if (ioread32(denali->reg + FEATURES) & FEATURES__DMA)
denali->dma_avail = 1;
@@ -1293,7 +1243,7 @@ int denali_init(struct denali_nand_info *denali)
mtd->oobsize - denali->oob_skip_bytes);
if (ret) {
dev_err(denali->dev, "Failed to setup ECC settings.\n");
- goto disable_irq;
+ return ret;
}
dev_dbg(denali->dev,
@@ -1337,7 +1287,7 @@ int denali_init(struct denali_nand_info *denali)
ret = denali_multidev_fixup(denali);
if (ret)
- goto disable_irq;
+ return ret;
/*
* This buffer is DMA-mapped by denali_{read,write}_page_raw. Do not
@@ -1345,26 +1295,88 @@ int denali_init(struct denali_nand_info *denali)
* guarantee DMA-safe alignment.
*/
denali->buf = kmalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL);
- if (!denali->buf) {
- ret = -ENOMEM;
- goto disable_irq;
+ if (!denali->buf)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static void denali_detach_chip(struct nand_chip *chip)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ struct denali_nand_info *denali = mtd_to_denali(mtd);
+
+ kfree(denali->buf);
+}
+
+int denali_init(struct denali_nand_info *denali)
+{
+ struct nand_chip *chip = &denali->nand;
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ u32 features = ioread32(denali->reg + FEATURES);
+ int ret;
+
+ mtd->dev.parent = denali->dev;
+ denali_hw_init(denali);
+
+ init_completion(&denali->complete);
+ spin_lock_init(&denali->irq_lock);
+
+ denali_clear_irq_all(denali);
+
+ ret = devm_request_irq(denali->dev, denali->irq, denali_isr,
+ IRQF_SHARED, DENALI_NAND_NAME, denali);
+ if (ret) {
+ dev_err(denali->dev, "Unable to request IRQ\n");
+ return ret;
}
- ret = nand_scan_tail(mtd);
+ denali_enable_irq(denali);
+ denali_reset_banks(denali);
+
+ denali->active_bank = DENALI_INVALID_BANK;
+
+ nand_set_flash_node(chip, denali->dev->of_node);
+ /* Fallback to the default name if DT did not give "label" property */
+ if (!mtd->name)
+ mtd->name = "denali-nand";
+
+ chip->select_chip = denali_select_chip;
+ chip->read_byte = denali_read_byte;
+ chip->write_byte = denali_write_byte;
+ chip->read_word = denali_read_word;
+ chip->cmd_ctrl = denali_cmd_ctrl;
+ chip->dev_ready = denali_dev_ready;
+ chip->waitfunc = denali_waitfunc;
+
+ if (features & FEATURES__INDEX_ADDR) {
+ denali->host_read = denali_indexed_read;
+ denali->host_write = denali_indexed_write;
+ } else {
+ denali->host_read = denali_direct_read;
+ denali->host_write = denali_direct_write;
+ }
+
+ /* clk rate info is needed for setup_data_interface */
+ if (denali->clk_rate && denali->clk_x_rate)
+ chip->setup_data_interface = denali_setup_data_interface;
+
+ chip->hwcontrol.attach_chip = denali_attach_chip;
+ chip->hwcontrol.detach_chip = denali_detach_chip;
+ ret = nand_scan(mtd, denali->max_banks);
if (ret)
- goto free_buf;
+ goto disable_irq;
ret = mtd_device_register(mtd, NULL, 0);
if (ret) {
dev_err(denali->dev, "Failed to register MTD: %d\n", ret);
goto cleanup_nand;
}
+
return 0;
cleanup_nand:
nand_cleanup(chip);
-free_buf:
- kfree(denali->buf);
disable_irq:
denali_disable_irq(denali);
--
2.14.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH v2 06/32] mtd: rawnand: fsl_elbc: convert driver to nand_scan()
2018-07-03 21:59 [PATCH v2 00/32] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
` (4 preceding siblings ...)
2018-07-03 22:00 ` [PATCH v2 05/32] mtd: rawnand: denali: convert " Miquel Raynal
@ 2018-07-03 22:00 ` Miquel Raynal
2018-07-03 22:00 ` [PATCH v2 07/32] mtd: rawnand: fsl_ifc: " Miquel Raynal
` (25 subsequent siblings)
31 siblings, 0 replies; 35+ messages in thread
From: Miquel Raynal @ 2018-07-03 22:00 UTC (permalink / raw)
To: linux-arm-kernel
Two helpers have been added to the core to make ECC-related
configuration between the detection phase and the final NAND scan. Use
these hooks and convert the driver to just use nand_scan() instead of
both nand_scan_ident() and nand_scan_tail().
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
drivers/mtd/nand/raw/fsl_elbc_nand.c | 15 ++++-----------
1 file changed, 4 insertions(+), 11 deletions(-)
diff --git a/drivers/mtd/nand/raw/fsl_elbc_nand.c b/drivers/mtd/nand/raw/fsl_elbc_nand.c
index 51f0b340bc0d..e535c8440f63 100644
--- a/drivers/mtd/nand/raw/fsl_elbc_nand.c
+++ b/drivers/mtd/nand/raw/fsl_elbc_nand.c
@@ -637,9 +637,9 @@ static int fsl_elbc_wait(struct mtd_info *mtd, struct nand_chip *chip)
return (elbc_fcm_ctrl->mdr & 0xff) | NAND_STATUS_WP;
}
-static int fsl_elbc_chip_init_tail(struct mtd_info *mtd)
+static int fsl_elbc_attach_chip(struct nand_chip *chip)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
struct fsl_lbc_ctrl *ctrl = priv->ctrl;
struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
@@ -910,15 +910,8 @@ static int fsl_elbc_nand_probe(struct platform_device *pdev)
if (ret)
goto err;
- ret = nand_scan_ident(mtd, 1, NULL);
- if (ret)
- goto err;
-
- ret = fsl_elbc_chip_init_tail(mtd);
- if (ret)
- goto err;
-
- ret = nand_scan_tail(mtd);
+ priv->chip->controller->attach_chip = fsl_elbc_attach_chip;
+ ret = nand_scan(mtd, 1);
if (ret)
goto err;
--
2.14.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH v2 07/32] mtd: rawnand: fsl_ifc: convert driver to nand_scan()
2018-07-03 21:59 [PATCH v2 00/32] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
` (5 preceding siblings ...)
2018-07-03 22:00 ` [PATCH v2 06/32] mtd: rawnand: fsl_elbc: convert driver " Miquel Raynal
@ 2018-07-03 22:00 ` Miquel Raynal
2018-07-03 22:00 ` [PATCH v2 08/32] mtd: rawnand: fsmc: " Miquel Raynal
` (24 subsequent siblings)
31 siblings, 0 replies; 35+ messages in thread
From: Miquel Raynal @ 2018-07-03 22:00 UTC (permalink / raw)
To: linux-arm-kernel
Two helpers have been added to the core to make ECC-related
configuration between the detection phase and the final NAND scan. Use
these hooks and convert the driver to just use nand_scan() instead of
both nand_scan_ident() and nand_scan_tail().
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
drivers/mtd/nand/raw/fsl_ifc_nand.c | 15 ++++-----------
1 file changed, 4 insertions(+), 11 deletions(-)
diff --git a/drivers/mtd/nand/raw/fsl_ifc_nand.c b/drivers/mtd/nand/raw/fsl_ifc_nand.c
index 382b67e97174..faefa186e9d3 100644
--- a/drivers/mtd/nand/raw/fsl_ifc_nand.c
+++ b/drivers/mtd/nand/raw/fsl_ifc_nand.c
@@ -714,9 +714,9 @@ static int fsl_ifc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
return nand_prog_page_end_op(chip);
}
-static int fsl_ifc_chip_init_tail(struct mtd_info *mtd)
+static int fsl_ifc_attach_chip(struct nand_chip *chip)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
dev_dbg(priv->dev, "%s: nand->numchips = %d\n", __func__,
@@ -1046,15 +1046,8 @@ static int fsl_ifc_nand_probe(struct platform_device *dev)
if (ret)
goto err;
- ret = nand_scan_ident(mtd, 1, NULL);
- if (ret)
- goto err;
-
- ret = fsl_ifc_chip_init_tail(mtd);
- if (ret)
- goto err;
-
- ret = nand_scan_tail(mtd);
+ priv->chip.controller->attach_chip = fsl_ifc_attach_chip;
+ ret = nand_scan(mtd, 1);
if (ret)
goto err;
--
2.14.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH v2 08/32] mtd: rawnand: fsmc: convert driver to nand_scan()
2018-07-03 21:59 [PATCH v2 00/32] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
` (6 preceding siblings ...)
2018-07-03 22:00 ` [PATCH v2 07/32] mtd: rawnand: fsl_ifc: " Miquel Raynal
@ 2018-07-03 22:00 ` Miquel Raynal
2018-07-03 22:00 ` [PATCH v2 09/32] mtd: rawnand: gpmi: " Miquel Raynal
` (23 subsequent siblings)
31 siblings, 0 replies; 35+ messages in thread
From: Miquel Raynal @ 2018-07-03 22:00 UTC (permalink / raw)
To: linux-arm-kernel
Two helpers have been added to the core to make ECC-related
configuration between the detection phase and the final NAND scan. Use
these hooks and convert the driver to just use nand_scan() instead of
both nand_scan_ident() and nand_scan_tail().
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
drivers/mtd/nand/raw/fsmc_nand.c | 144 ++++++++++++++++++++-------------------
1 file changed, 74 insertions(+), 70 deletions(-)
diff --git a/drivers/mtd/nand/raw/fsmc_nand.c b/drivers/mtd/nand/raw/fsmc_nand.c
index f4a5a317d4ae..f8b505ce7b98 100644
--- a/drivers/mtd/nand/raw/fsmc_nand.c
+++ b/drivers/mtd/nand/raw/fsmc_nand.c
@@ -918,6 +918,78 @@ static int fsmc_nand_probe_config_dt(struct platform_device *pdev,
return 0;
}
+static int fsmc_nand_attach_chip(struct nand_chip *nand)
+{
+ struct mtd_info *mtd = nand_to_mtd(nand);
+ struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
+
+ if (AMBA_REV_BITS(host->pid) >= 8) {
+ switch (mtd->oobsize) {
+ case 16:
+ case 64:
+ case 128:
+ case 224:
+ case 256:
+ break;
+ default:
+ dev_warn(host->dev,
+ "No oob scheme defined for oobsize %d\n",
+ mtd->oobsize);
+ return -EINVAL;
+ }
+
+ mtd_set_ooblayout(mtd, &fsmc_ecc4_ooblayout_ops);
+
+ return 0;
+ }
+
+ switch (nand->ecc.mode) {
+ case NAND_ECC_HW:
+ dev_info(host->dev, "Using 1-bit HW ECC scheme\n");
+ nand->ecc.calculate = fsmc_read_hwecc_ecc1;
+ nand->ecc.correct = nand_correct_data;
+ nand->ecc.bytes = 3;
+ nand->ecc.strength = 1;
+ break;
+
+ case NAND_ECC_SOFT:
+ if (nand->ecc.algo == NAND_ECC_BCH) {
+ dev_info(host->dev,
+ "Using 4-bit SW BCH ECC scheme\n");
+ break;
+ }
+
+ case NAND_ECC_ON_DIE:
+ break;
+
+ default:
+ dev_err(host->dev, "Unsupported ECC mode!\n");
+ return -ENOTSUPP;
+ }
+
+ /*
+ * Don't set layout for BCH4 SW ECC. This will be
+ * generated later in nand_bch_init() later.
+ */
+ if (nand->ecc.mode == NAND_ECC_HW) {
+ switch (mtd->oobsize) {
+ case 16:
+ case 64:
+ case 128:
+ mtd_set_ooblayout(mtd,
+ &fsmc_ecc1_ooblayout_ops);
+ break;
+ default:
+ dev_warn(host->dev,
+ "No oob scheme defined for oobsize %d\n",
+ mtd->oobsize);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
/*
* fsmc_nand_probe - Probe function
* @pdev: platform device structure
@@ -1047,76 +1119,8 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
/*
* Scan to find existence of the device
*/
- ret = nand_scan_ident(mtd, 1, NULL);
- if (ret) {
- dev_err(&pdev->dev, "No NAND Device found!\n");
- goto release_dma_write_chan;
- }
-
- if (AMBA_REV_BITS(host->pid) >= 8) {
- switch (mtd->oobsize) {
- case 16:
- case 64:
- case 128:
- case 224:
- case 256:
- break;
- default:
- dev_warn(&pdev->dev, "No oob scheme defined for oobsize %d\n",
- mtd->oobsize);
- ret = -EINVAL;
- goto release_dma_write_chan;
- }
-
- mtd_set_ooblayout(mtd, &fsmc_ecc4_ooblayout_ops);
- } else {
- switch (nand->ecc.mode) {
- case NAND_ECC_HW:
- dev_info(&pdev->dev, "Using 1-bit HW ECC scheme\n");
- nand->ecc.calculate = fsmc_read_hwecc_ecc1;
- nand->ecc.correct = nand_correct_data;
- nand->ecc.bytes = 3;
- nand->ecc.strength = 1;
- break;
-
- case NAND_ECC_SOFT:
- if (nand->ecc.algo == NAND_ECC_BCH) {
- dev_info(&pdev->dev, "Using 4-bit SW BCH ECC scheme\n");
- break;
- }
-
- case NAND_ECC_ON_DIE:
- break;
-
- default:
- dev_err(&pdev->dev, "Unsupported ECC mode!\n");
- goto release_dma_write_chan;
- }
-
- /*
- * Don't set layout for BCH4 SW ECC. This will be
- * generated later in nand_bch_init() later.
- */
- if (nand->ecc.mode == NAND_ECC_HW) {
- switch (mtd->oobsize) {
- case 16:
- case 64:
- case 128:
- mtd_set_ooblayout(mtd,
- &fsmc_ecc1_ooblayout_ops);
- break;
- default:
- dev_warn(&pdev->dev,
- "No oob scheme defined for oobsize %d\n",
- mtd->oobsize);
- ret = -EINVAL;
- goto release_dma_write_chan;
- }
- }
- }
-
- /* Second stage of scan to fill MTD data-structures */
- ret = nand_scan_tail(mtd);
+ nand->hwcontrol.attach_chip = fsmc_nand_attach_chip;
+ ret = nand_scan(mtd, 1);
if (ret)
goto release_dma_write_chan;
--
2.14.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH v2 09/32] mtd: rawnand: gpmi: convert driver to nand_scan()
2018-07-03 21:59 [PATCH v2 00/32] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
` (7 preceding siblings ...)
2018-07-03 22:00 ` [PATCH v2 08/32] mtd: rawnand: fsmc: " Miquel Raynal
@ 2018-07-03 22:00 ` Miquel Raynal
2018-07-03 22:00 ` [PATCH v2 10/32] mtd: rawnand: hisi504: " Miquel Raynal
` (22 subsequent siblings)
31 siblings, 0 replies; 35+ messages in thread
From: Miquel Raynal @ 2018-07-03 22:00 UTC (permalink / raw)
To: linux-arm-kernel
Two helpers have been added to the core to make ECC-related
configuration between the detection phase and the final NAND scan. Use
these hooks and convert the driver to just use nand_scan() instead of
both nand_scan_ident() and nand_scan_tail().
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c | 52 +++++++++++++++++-------------
1 file changed, 29 insertions(+), 23 deletions(-)
diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c
index f6aa358a3452..920f06aa40d7 100644
--- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c
+++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c
@@ -757,9 +757,9 @@ static int gpmi_alloc_dma_buffer(struct gpmi_nand_data *this)
* [2] Allocate a read/write data buffer.
* The gpmi_alloc_dma_buffer can be called twice.
* We allocate a PAGE_SIZE length buffer if gpmi_alloc_dma_buffer
- * is called before the nand_scan_ident; and we allocate a buffer
- * of the real NAND page size when the gpmi_alloc_dma_buffer is
- * called after the nand_scan_ident.
+ * is called before the NAND identification; and we allocate a
+ * buffer of the real NAND page size when the gpmi_alloc_dma_buffer
+ * is called after.
*/
this->data_buffer_dma = kzalloc(mtd->writesize ?: PAGE_SIZE,
GFP_DMA | GFP_KERNEL);
@@ -1881,6 +1881,30 @@ static int gpmi_init_last(struct gpmi_nand_data *this)
return 0;
}
+static int gpmi_nand_attach_chip(struct nand_chip *chip)
+{
+ struct gpmi_nand_data *this = nand_get_controller_data(chip);
+ int ret;
+
+ if (chip->bbt_options & NAND_BBT_USE_FLASH) {
+ chip->bbt_options |= NAND_BBT_NO_OOB;
+
+ if (of_property_read_bool(this->dev->of_node,
+ "fsl,no-blockmark-swap"))
+ this->swap_block_mark = false;
+ }
+ dev_dbg(this->dev, "Blockmark swapping %sabled\n",
+ this->swap_block_mark ? "en" : "dis");
+
+ ret = gpmi_init_last(this);
+ if (ret)
+ return ret;
+
+ chip->options |= NAND_SKIP_BBTSCAN;
+
+ return 0;
+}
+
static int gpmi_nand_init(struct gpmi_nand_data *this)
{
struct nand_chip *chip = &this->nand;
@@ -1921,26 +1945,8 @@ static int gpmi_nand_init(struct gpmi_nand_data *this)
if (ret)
goto err_out;
- ret = nand_scan_ident(mtd, GPMI_IS_MX6(this) ? 2 : 1, NULL);
- if (ret)
- goto err_out;
-
- if (chip->bbt_options & NAND_BBT_USE_FLASH) {
- chip->bbt_options |= NAND_BBT_NO_OOB;
-
- if (of_property_read_bool(this->dev->of_node,
- "fsl,no-blockmark-swap"))
- this->swap_block_mark = false;
- }
- dev_dbg(this->dev, "Blockmark swapping %sabled\n",
- this->swap_block_mark ? "en" : "dis");
-
- ret = gpmi_init_last(this);
- if (ret)
- goto err_out;
-
- chip->options |= NAND_SKIP_BBTSCAN;
- ret = nand_scan_tail(mtd);
+ chip->hwcontrol.attach_chip = gpmi_nand_attach_chip;
+ ret = nand_scan(mtd, GPMI_IS_MX6(this) ? 2 : 1);
if (ret)
goto err_out;
--
2.14.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH v2 10/32] mtd: rawnand: hisi504: convert driver to nand_scan()
2018-07-03 21:59 [PATCH v2 00/32] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
` (8 preceding siblings ...)
2018-07-03 22:00 ` [PATCH v2 09/32] mtd: rawnand: gpmi: " Miquel Raynal
@ 2018-07-03 22:00 ` Miquel Raynal
2018-07-03 22:00 ` [PATCH v2 11/32] mtd: rawnand: jz4780: " Miquel Raynal
` (21 subsequent siblings)
31 siblings, 0 replies; 35+ messages in thread
From: Miquel Raynal @ 2018-07-03 22:00 UTC (permalink / raw)
To: linux-arm-kernel
Two helpers have been added to the core to make ECC-related
configuration between the detection phase and the final NAND scan. Use
these hooks and convert the driver to just use nand_scan() instead of
both nand_scan_ident() and nand_scan_tail().
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
drivers/mtd/nand/raw/hisi504_nand.c | 74 ++++++++++++++++++++-----------------
1 file changed, 40 insertions(+), 34 deletions(-)
diff --git a/drivers/mtd/nand/raw/hisi504_nand.c b/drivers/mtd/nand/raw/hisi504_nand.c
index a1e009c8e556..d814a459b4d6 100644
--- a/drivers/mtd/nand/raw/hisi504_nand.c
+++ b/drivers/mtd/nand/raw/hisi504_nand.c
@@ -709,9 +709,46 @@ static int hisi_nfc_ecc_probe(struct hinfc_host *host)
return 0;
}
+static int hisi_nfc_attach_chip(struct nand_chip *chip)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ struct hinfc_host *host = nand_get_controller_data(chip);
+ int flag;
+
+ host->buffer = dmam_alloc_coherent(host->dev,
+ mtd->writesize + mtd->oobsize,
+ &host->dma_buffer, GFP_KERNEL);
+ if (!host->buffer)
+ return -ENOMEM;
+
+ host->dma_oob = host->dma_buffer + mtd->writesize;
+ memset(host->buffer, 0xff, mtd->writesize + mtd->oobsize);
+
+ flag = hinfc_read(host, HINFC504_CON);
+ flag &= ~(HINFC504_CON_PAGESIZE_MASK << HINFC504_CON_PAGEISZE_SHIFT);
+ switch (mtd->writesize) {
+ case 2048:
+ flag |= (0x001 << HINFC504_CON_PAGEISZE_SHIFT);
+ break;
+ /*
+ * TODO: add more pagesize support,
+ * default pagesize has been set in hisi_nfc_host_init
+ */
+ default:
+ dev_err(host->dev, "NON-2KB page size nand flash\n");
+ return -EINVAL;
+ }
+ hinfc_write(host, flag, HINFC504_CON);
+
+ if (chip->ecc.mode == NAND_ECC_HW)
+ hisi_nfc_ecc_probe(host);
+
+ return 0;
+}
+
static int hisi_nfc_probe(struct platform_device *pdev)
{
- int ret = 0, irq, flag, max_chips = HINFC504_MAX_CHIP;
+ int ret = 0, irq, max_chips = HINFC504_MAX_CHIP;
struct device *dev = &pdev->dev;
struct hinfc_host *host;
struct nand_chip *chip;
@@ -769,42 +806,11 @@ static int hisi_nfc_probe(struct platform_device *pdev)
return ret;
}
- ret = nand_scan_ident(mtd, max_chips, NULL);
+ chip->hwcontrol.attach_chip = hisi_nfc_attach_chip;
+ ret = nand_scan(mtd, max_chips);
if (ret)
return ret;
- host->buffer = dmam_alloc_coherent(dev, mtd->writesize + mtd->oobsize,
- &host->dma_buffer, GFP_KERNEL);
- if (!host->buffer)
- return -ENOMEM;
-
- host->dma_oob = host->dma_buffer + mtd->writesize;
- memset(host->buffer, 0xff, mtd->writesize + mtd->oobsize);
-
- flag = hinfc_read(host, HINFC504_CON);
- flag &= ~(HINFC504_CON_PAGESIZE_MASK << HINFC504_CON_PAGEISZE_SHIFT);
- switch (mtd->writesize) {
- case 2048:
- flag |= (0x001 << HINFC504_CON_PAGEISZE_SHIFT); break;
- /*
- * TODO: add more pagesize support,
- * default pagesize has been set in hisi_nfc_host_init
- */
- default:
- dev_err(dev, "NON-2KB page size nand flash\n");
- return -EINVAL;
- }
- hinfc_write(host, flag, HINFC504_CON);
-
- if (chip->ecc.mode == NAND_ECC_HW)
- hisi_nfc_ecc_probe(host);
-
- ret = nand_scan_tail(mtd);
- if (ret) {
- dev_err(dev, "nand_scan_tail failed: %d\n", ret);
- return ret;
- }
-
ret = mtd_device_register(mtd, NULL, 0);
if (ret) {
dev_err(dev, "Err MTD partition=%d\n", ret);
--
2.14.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH v2 11/32] mtd: rawnand: jz4780: convert driver to nand_scan()
2018-07-03 21:59 [PATCH v2 00/32] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
` (9 preceding siblings ...)
2018-07-03 22:00 ` [PATCH v2 10/32] mtd: rawnand: hisi504: " Miquel Raynal
@ 2018-07-03 22:00 ` Miquel Raynal
2018-07-03 22:00 ` [PATCH v2 12/32] mtd: rawnand: lpc32xx_mlc: " Miquel Raynal
` (20 subsequent siblings)
31 siblings, 0 replies; 35+ messages in thread
From: Miquel Raynal @ 2018-07-03 22:00 UTC (permalink / raw)
To: linux-arm-kernel
Two helpers have been added to the core to make ECC-related
configuration between the detection phase and the final NAND scan. Use
these hooks and convert the driver to just use nand_scan() instead of
both nand_scan_ident() and nand_scan_tail().
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Acked-by: Harvey Hunt <harveyhuntnexus@gmail.com>
---
drivers/mtd/nand/raw/jz4780_nand.c | 30 ++++++++++++------------------
1 file changed, 12 insertions(+), 18 deletions(-)
diff --git a/drivers/mtd/nand/raw/jz4780_nand.c b/drivers/mtd/nand/raw/jz4780_nand.c
index e69f6ae4c539..dd8c2facdef5 100644
--- a/drivers/mtd/nand/raw/jz4780_nand.c
+++ b/drivers/mtd/nand/raw/jz4780_nand.c
@@ -157,9 +157,8 @@ static int jz4780_nand_ecc_correct(struct mtd_info *mtd, u8 *dat,
return jz4780_bch_correct(nfc->bch, ¶ms, dat, read_ecc);
}
-static int jz4780_nand_init_ecc(struct jz4780_nand_chip *nand, struct device *dev)
+static int jz4780_nand_attach_chip(struct nand_chip *chip)
{
- struct nand_chip *chip = &nand->chip;
struct mtd_info *mtd = nand_to_mtd(chip);
struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(chip->controller);
int eccbytes;
@@ -170,7 +169,8 @@ static int jz4780_nand_init_ecc(struct jz4780_nand_chip *nand, struct device *de
switch (chip->ecc.mode) {
case NAND_ECC_HW:
if (!nfc->bch) {
- dev_err(dev, "HW BCH selected, but BCH controller not found\n");
+ dev_err(nfc->dev,
+ "HW BCH selected, but BCH controller not found\n");
return -ENODEV;
}
@@ -179,15 +179,16 @@ static int jz4780_nand_init_ecc(struct jz4780_nand_chip *nand, struct device *de
chip->ecc.correct = jz4780_nand_ecc_correct;
/* fall through */
case NAND_ECC_SOFT:
- dev_info(dev, "using %s (strength %d, size %d, bytes %d)\n",
- (nfc->bch) ? "hardware BCH" : "software ECC",
- chip->ecc.strength, chip->ecc.size, chip->ecc.bytes);
+ dev_info(nfc->dev, "using %s (strength %d, size %d, bytes %d)\n",
+ (nfc->bch) ? "hardware BCH" : "software ECC",
+ chip->ecc.strength, chip->ecc.size, chip->ecc.bytes);
break;
case NAND_ECC_NONE:
- dev_info(dev, "not using ECC\n");
+ dev_info(nfc->dev, "not using ECC\n");
break;
default:
- dev_err(dev, "ECC mode %d not supported\n", chip->ecc.mode);
+ dev_err(nfc->dev, "ECC mode %d not supported\n",
+ chip->ecc.mode);
return -EINVAL;
}
@@ -199,7 +200,7 @@ static int jz4780_nand_init_ecc(struct jz4780_nand_chip *nand, struct device *de
eccbytes = mtd->writesize / chip->ecc.size * chip->ecc.bytes;
if (eccbytes > mtd->oobsize - 2) {
- dev_err(dev,
+ dev_err(nfc->dev,
"invalid ECC config: required %d ECC bytes, but only %d are available",
eccbytes, mtd->oobsize - 2);
return -EINVAL;
@@ -279,15 +280,8 @@ static int jz4780_nand_init_chip(struct platform_device *pdev,
chip->controller = &nfc->controller;
nand_set_flash_node(chip, np);
- ret = nand_scan_ident(mtd, 1, NULL);
- if (ret)
- return ret;
-
- ret = jz4780_nand_init_ecc(nand, dev);
- if (ret)
- return ret;
-
- ret = nand_scan_tail(mtd);
+ chip->controller->attach_chip = jz4780_nand_attach_chip;
+ ret = nand_scan(mtd, 1);
if (ret)
return ret;
--
2.14.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH v2 12/32] mtd: rawnand: lpc32xx_mlc: convert driver to nand_scan()
2018-07-03 21:59 [PATCH v2 00/32] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
` (10 preceding siblings ...)
2018-07-03 22:00 ` [PATCH v2 11/32] mtd: rawnand: jz4780: " Miquel Raynal
@ 2018-07-03 22:00 ` Miquel Raynal
2018-07-03 22:00 ` [PATCH v2 13/32] mtd: rawnand: lpc32xx_slc: " Miquel Raynal
` (19 subsequent siblings)
31 siblings, 0 replies; 35+ messages in thread
From: Miquel Raynal @ 2018-07-03 22:00 UTC (permalink / raw)
To: linux-arm-kernel
Two helpers have been added to the core to make ECC-related
configuration between the detection phase and the final NAND scan. Use
these hooks and convert the driver to just use nand_scan() instead of
both nand_scan_ident() and nand_scan_tail().
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
drivers/mtd/nand/raw/lpc32xx_mlc.c | 105 +++++++++++++++++++------------------
1 file changed, 55 insertions(+), 50 deletions(-)
diff --git a/drivers/mtd/nand/raw/lpc32xx_mlc.c b/drivers/mtd/nand/raw/lpc32xx_mlc.c
index 052d123a8304..d650ed609ba7 100644
--- a/drivers/mtd/nand/raw/lpc32xx_mlc.c
+++ b/drivers/mtd/nand/raw/lpc32xx_mlc.c
@@ -184,6 +184,7 @@ static struct nand_bbt_descr lpc32xx_nand_bbt_mirror = {
};
struct lpc32xx_nand_host {
+ struct platform_device *pdev;
struct nand_chip nand_chip;
struct lpc32xx_mlc_platform_data *pdata;
struct clk *clk;
@@ -653,6 +654,53 @@ static struct lpc32xx_nand_cfg_mlc *lpc32xx_parse_dt(struct device *dev)
return ncfg;
}
+static int lpc32xx_nand_attach_chip(struct nand_chip *chip)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
+ struct device *dev = &host->pdev->dev;
+
+ host->dma_buf = devm_kzalloc(dev, mtd->writesize, GFP_KERNEL);
+ if (!host->dma_buf)
+ return -ENOMEM;
+
+ host->dummy_buf = devm_kzalloc(dev, mtd->writesize, GFP_KERNEL);
+ if (!host->dummy_buf)
+ return -ENOMEM;
+
+ chip->ecc.mode = NAND_ECC_HW;
+ chip->ecc.size = 512;
+ mtd_set_ooblayout(mtd, &lpc32xx_ooblayout_ops);
+ host->mlcsubpages = mtd->writesize / 512;
+
+ /* initially clear interrupt status */
+ readb(MLC_IRQ_SR(host->io_base));
+
+ init_completion(&host->comp_nand);
+ init_completion(&host->comp_controller);
+
+ host->irq = platform_get_irq(host->pdev, 0);
+ if (host->irq < 0) {
+ dev_err(dev, "failed to get platform irq\n");
+ return -EINVAL;
+ }
+
+ if (request_irq(host->irq, (irq_handler_t)&lpc3xxx_nand_irq,
+ IRQF_TRIGGER_HIGH, DRV_NAME, host)) {
+ dev_err(dev, "Error requesting NAND IRQ\n");
+ return -ENXIO;
+ }
+
+ return 0;
+}
+
+static void lpc32xx_nand_detach_chip(struct nand_chip *chip)
+{
+ struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
+
+ free_irq(host->irq, host);
+}
+
/*
* Probe for NAND controller
*/
@@ -669,6 +717,8 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
if (!host)
return -ENOMEM;
+ host->pdev = pdev;
+
rc = platform_get_resource(pdev, IORESOURCE_MEM, 0);
host->io_base = devm_ioremap_resource(&pdev->dev, rc);
if (IS_ERR(host->io_base))
@@ -749,58 +799,15 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
}
/*
- * Scan to find existance of the device and
- * Get the type of NAND device SMALL block or LARGE block
+ * Scan to find existence of the device and get the type of NAND device:
+ * SMALL block or LARGE block.
*/
- res = nand_scan_ident(mtd, 1, NULL);
+ nand_chip->hwcontrol.attach_chip = lpc32xx_nand_attach_chip;
+ nand_chip->hwcontrol.detach_chip = lpc32xx_nand_detach_chip;
+ res = nand_scan(mtd, 1);
if (res)
goto release_dma_chan;
- host->dma_buf = devm_kzalloc(&pdev->dev, mtd->writesize, GFP_KERNEL);
- if (!host->dma_buf) {
- res = -ENOMEM;
- goto release_dma_chan;
- }
-
- host->dummy_buf = devm_kzalloc(&pdev->dev, mtd->writesize, GFP_KERNEL);
- if (!host->dummy_buf) {
- res = -ENOMEM;
- goto release_dma_chan;
- }
-
- nand_chip->ecc.mode = NAND_ECC_HW;
- nand_chip->ecc.size = 512;
- mtd_set_ooblayout(mtd, &lpc32xx_ooblayout_ops);
- host->mlcsubpages = mtd->writesize / 512;
-
- /* initially clear interrupt status */
- readb(MLC_IRQ_SR(host->io_base));
-
- init_completion(&host->comp_nand);
- init_completion(&host->comp_controller);
-
- host->irq = platform_get_irq(pdev, 0);
- if (host->irq < 0) {
- dev_err(&pdev->dev, "failed to get platform irq\n");
- res = -EINVAL;
- goto release_dma_chan;
- }
-
- if (request_irq(host->irq, (irq_handler_t)&lpc3xxx_nand_irq,
- IRQF_TRIGGER_HIGH, DRV_NAME, host)) {
- dev_err(&pdev->dev, "Error requesting NAND IRQ\n");
- res = -ENXIO;
- goto release_dma_chan;
- }
-
- /*
- * Fills out all the uninitialized function pointers with the defaults
- * And scans for a bad block table if appropriate.
- */
- res = nand_scan_tail(mtd);
- if (res)
- goto free_irq;
-
mtd->name = DRV_NAME;
res = mtd_device_register(mtd, host->ncfg->parts,
@@ -812,8 +819,6 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
cleanup_nand:
nand_cleanup(nand_chip);
-free_irq:
- free_irq(host->irq, host);
release_dma_chan:
if (use_dma)
dma_release_channel(host->dma_chan);
--
2.14.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH v2 13/32] mtd: rawnand: lpc32xx_slc: convert driver to nand_scan()
2018-07-03 21:59 [PATCH v2 00/32] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
` (11 preceding siblings ...)
2018-07-03 22:00 ` [PATCH v2 12/32] mtd: rawnand: lpc32xx_mlc: " Miquel Raynal
@ 2018-07-03 22:00 ` Miquel Raynal
2018-07-03 22:00 ` [PATCH v2 14/32] mtd: rawnand: marvell: " Miquel Raynal
` (18 subsequent siblings)
31 siblings, 0 replies; 35+ messages in thread
From: Miquel Raynal @ 2018-07-03 22:00 UTC (permalink / raw)
To: linux-arm-kernel
Two helpers have been added to the core to make ECC-related
configuration between the detection phase and the final NAND scan. Use
these hooks and convert the driver to just use nand_scan() instead of
both nand_scan_ident() and nand_scan_tail().
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
drivers/mtd/nand/raw/lpc32xx_slc.c | 73 ++++++++++++++++++++------------------
1 file changed, 38 insertions(+), 35 deletions(-)
diff --git a/drivers/mtd/nand/raw/lpc32xx_slc.c b/drivers/mtd/nand/raw/lpc32xx_slc.c
index 42820aa1abab..c31efac1f9f5 100644
--- a/drivers/mtd/nand/raw/lpc32xx_slc.c
+++ b/drivers/mtd/nand/raw/lpc32xx_slc.c
@@ -779,6 +779,42 @@ static struct lpc32xx_nand_cfg_slc *lpc32xx_parse_dt(struct device *dev)
return ncfg;
}
+static int lpc32xx_nand_attach_chip(struct nand_chip *chip)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
+
+ /* OOB and ECC CPU and DMA work areas */
+ host->ecc_buf = (uint32_t *)(host->data_buf + LPC32XX_DMA_DATA_SIZE);
+
+ /*
+ * Small page FLASH has a unique OOB layout, but large and huge
+ * page FLASH use the standard layout. Small page FLASH uses a
+ * custom BBT marker layout.
+ */
+ if (mtd->writesize <= 512)
+ mtd_set_ooblayout(mtd, &lpc32xx_ooblayout_ops);
+
+ /* These sizes remain the same regardless of page size */
+ chip->ecc.size = 256;
+ chip->ecc.bytes = LPC32XX_SLC_DEV_ECC_BYTES;
+ chip->ecc.prepad = 0;
+ chip->ecc.postpad = 0;
+
+ /*
+ * Use a custom BBT marker setup for small page FLASH that
+ * won't interfere with the ECC layout. Large and huge page
+ * FLASH use the standard layout.
+ */
+ if ((chip->bbt_options & NAND_BBT_USE_FLASH) &&
+ mtd->writesize <= 512) {
+ chip->bbt_td = &bbt_smallpage_main_descr;
+ chip->bbt_md = &bbt_smallpage_mirror_descr;
+ }
+
+ return 0;
+}
+
/*
* Probe for NAND controller
*/
@@ -884,41 +920,8 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
}
/* Find NAND device */
- res = nand_scan_ident(mtd, 1, NULL);
- if (res)
- goto release_dma;
-
- /* OOB and ECC CPU and DMA work areas */
- host->ecc_buf = (uint32_t *)(host->data_buf + LPC32XX_DMA_DATA_SIZE);
-
- /*
- * Small page FLASH has a unique OOB layout, but large and huge
- * page FLASH use the standard layout. Small page FLASH uses a
- * custom BBT marker layout.
- */
- if (mtd->writesize <= 512)
- mtd_set_ooblayout(mtd, &lpc32xx_ooblayout_ops);
-
- /* These sizes remain the same regardless of page size */
- chip->ecc.size = 256;
- chip->ecc.bytes = LPC32XX_SLC_DEV_ECC_BYTES;
- chip->ecc.prepad = chip->ecc.postpad = 0;
-
- /*
- * Use a custom BBT marker setup for small page FLASH that
- * won't interfere with the ECC layout. Large and huge page
- * FLASH use the standard layout.
- */
- if ((chip->bbt_options & NAND_BBT_USE_FLASH) &&
- mtd->writesize <= 512) {
- chip->bbt_td = &bbt_smallpage_main_descr;
- chip->bbt_md = &bbt_smallpage_mirror_descr;
- }
-
- /*
- * Fills out all the uninitialized function pointers with the defaults
- */
- res = nand_scan_tail(mtd);
+ chip->hwcontrol.attach_chip = lpc32xx_nand_attach_chip;
+ res = nand_scan(mtd, 1);
if (res)
goto release_dma;
--
2.14.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH v2 14/32] mtd: rawnand: marvell: convert driver to nand_scan()
2018-07-03 21:59 [PATCH v2 00/32] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
` (12 preceding siblings ...)
2018-07-03 22:00 ` [PATCH v2 13/32] mtd: rawnand: lpc32xx_slc: " Miquel Raynal
@ 2018-07-03 22:00 ` Miquel Raynal
2018-07-03 22:00 ` [PATCH v2 15/32] mtd: rawnand: mtk: " Miquel Raynal
` (17 subsequent siblings)
31 siblings, 0 replies; 35+ messages in thread
From: Miquel Raynal @ 2018-07-03 22:00 UTC (permalink / raw)
To: linux-arm-kernel
Two helpers have been added to the core to make ECC-related
configuration between the detection phase and the final NAND scan. Use
these hooks and convert the driver to just use nand_scan() instead of
both nand_scan_ident() and nand_scan_tail().
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
drivers/mtd/nand/raw/marvell_nand.c | 201 +++++++++++++++++++-----------------
1 file changed, 104 insertions(+), 97 deletions(-)
diff --git a/drivers/mtd/nand/raw/marvell_nand.c b/drivers/mtd/nand/raw/marvell_nand.c
index ba6889bbe802..ed4a0419962a 100644
--- a/drivers/mtd/nand/raw/marvell_nand.c
+++ b/drivers/mtd/nand/raw/marvell_nand.c
@@ -2295,6 +2295,107 @@ static int marvell_nfc_setup_data_interface(struct mtd_info *mtd, int chipnr,
return 0;
}
+static int marvell_nand_attach_chip(struct nand_chip *chip)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ struct marvell_nand_chip *marvell_nand = to_marvell_nand(chip);
+ struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
+ struct pxa3xx_nand_platform_data *pdata = dev_get_platdata(nfc->dev);
+ int ret;
+
+ if (pdata && pdata->flash_bbt)
+ chip->bbt_options |= NAND_BBT_USE_FLASH;
+
+ if (chip->bbt_options & NAND_BBT_USE_FLASH) {
+ /*
+ * We'll use a bad block table stored in-flash and don't
+ * allow writing the bad block marker to the flash.
+ */
+ chip->bbt_options |= NAND_BBT_NO_OOB_BBM;
+ chip->bbt_td = &bbt_main_descr;
+ chip->bbt_md = &bbt_mirror_descr;
+ }
+
+ /* Save the chip-specific fields of NDCR */
+ marvell_nand->ndcr = NDCR_PAGE_SZ(mtd->writesize);
+ if (chip->options & NAND_BUSWIDTH_16)
+ marvell_nand->ndcr |= NDCR_DWIDTH_M | NDCR_DWIDTH_C;
+
+ /*
+ * On small page NANDs, only one cycle is needed to pass the
+ * column address.
+ */
+ if (mtd->writesize <= 512) {
+ marvell_nand->addr_cyc = 1;
+ } else {
+ marvell_nand->addr_cyc = 2;
+ marvell_nand->ndcr |= NDCR_RA_START;
+ }
+
+ /*
+ * Now add the number of cycles needed to pass the row
+ * address.
+ *
+ * Addressing a chip using CS 2 or 3 should also need the third row
+ * cycle but due to inconsistance in the documentation and lack of
+ * hardware to test this situation, this case is not supported.
+ */
+ if (chip->options & NAND_ROW_ADDR_3)
+ marvell_nand->addr_cyc += 3;
+ else
+ marvell_nand->addr_cyc += 2;
+
+ if (pdata) {
+ chip->ecc.size = pdata->ecc_step_size;
+ chip->ecc.strength = pdata->ecc_strength;
+ }
+
+ ret = marvell_nand_ecc_init(mtd, &chip->ecc);
+ if (ret) {
+ dev_err(nfc->dev, "ECC init failed: %d\n", ret);
+ return ret;
+ }
+
+ if (chip->ecc.mode == NAND_ECC_HW) {
+ /*
+ * Subpage write not available with hardware ECC, prohibit also
+ * subpage read as in userspace subpage access would still be
+ * allowed and subpage write, if used, would lead to numerous
+ * uncorrectable ECC errors.
+ */
+ chip->options |= NAND_NO_SUBPAGE_WRITE;
+ }
+
+ if (pdata || nfc->caps->legacy_of_bindings) {
+ /*
+ * We keep the MTD name unchanged to avoid breaking platforms
+ * where the MTD cmdline parser is used and the bootloader
+ * has not been updated to use the new naming scheme.
+ */
+ mtd->name = "pxa3xx_nand-0";
+ } else if (!mtd->name) {
+ /*
+ * If the new bindings are used and the bootloader has not been
+ * updated to pass a new mtdparts parameter on the cmdline, you
+ * should define the following property in your NAND node, ie:
+ *
+ * label = "main-storage";
+ *
+ * This way, mtd->name will be set by the core when
+ * nand_set_flash_node() is called.
+ */
+ mtd->name = devm_kasprintf(nfc->dev, GFP_KERNEL,
+ "%s:nand.%d", dev_name(nfc->dev),
+ marvell_nand->sels[0].cs);
+ if (!mtd->name) {
+ dev_err(nfc->dev, "Failed to allocate mtd->name\n");
+ return -ENOMEM;
+ }
+ }
+
+ return 0;
+}
+
static int marvell_nand_chip_init(struct device *dev, struct marvell_nfc *nfc,
struct device_node *np)
{
@@ -2437,105 +2538,11 @@ static int marvell_nand_chip_init(struct device *dev, struct marvell_nfc *nfc,
marvell_nand->ndtr1 = readl_relaxed(nfc->regs + NDTR1);
chip->options |= NAND_BUSWIDTH_AUTO;
- ret = nand_scan_ident(mtd, marvell_nand->nsels, NULL);
- if (ret) {
- dev_err(dev, "could not identify the nand chip\n");
- return ret;
- }
-
- if (pdata && pdata->flash_bbt)
- chip->bbt_options |= NAND_BBT_USE_FLASH;
-
- if (chip->bbt_options & NAND_BBT_USE_FLASH) {
- /*
- * We'll use a bad block table stored in-flash and don't
- * allow writing the bad block marker to the flash.
- */
- chip->bbt_options |= NAND_BBT_NO_OOB_BBM;
- chip->bbt_td = &bbt_main_descr;
- chip->bbt_md = &bbt_mirror_descr;
- }
-
- /* Save the chip-specific fields of NDCR */
- marvell_nand->ndcr = NDCR_PAGE_SZ(mtd->writesize);
- if (chip->options & NAND_BUSWIDTH_16)
- marvell_nand->ndcr |= NDCR_DWIDTH_M | NDCR_DWIDTH_C;
-
- /*
- * On small page NANDs, only one cycle is needed to pass the
- * column address.
- */
- if (mtd->writesize <= 512) {
- marvell_nand->addr_cyc = 1;
- } else {
- marvell_nand->addr_cyc = 2;
- marvell_nand->ndcr |= NDCR_RA_START;
- }
-
- /*
- * Now add the number of cycles needed to pass the row
- * address.
- *
- * Addressing a chip using CS 2 or 3 should also need the third row
- * cycle but due to inconsistance in the documentation and lack of
- * hardware to test this situation, this case is not supported.
- */
- if (chip->options & NAND_ROW_ADDR_3)
- marvell_nand->addr_cyc += 3;
- else
- marvell_nand->addr_cyc += 2;
-
- if (pdata) {
- chip->ecc.size = pdata->ecc_step_size;
- chip->ecc.strength = pdata->ecc_strength;
- }
-
- ret = marvell_nand_ecc_init(mtd, &chip->ecc);
- if (ret) {
- dev_err(dev, "ECC init failed: %d\n", ret);
- return ret;
- }
-
- if (chip->ecc.mode == NAND_ECC_HW) {
- /*
- * Subpage write not available with hardware ECC, prohibit also
- * subpage read as in userspace subpage access would still be
- * allowed and subpage write, if used, would lead to numerous
- * uncorrectable ECC errors.
- */
- chip->options |= NAND_NO_SUBPAGE_WRITE;
- }
-
- if (pdata || nfc->caps->legacy_of_bindings) {
- /*
- * We keep the MTD name unchanged to avoid breaking platforms
- * where the MTD cmdline parser is used and the bootloader
- * has not been updated to use the new naming scheme.
- */
- mtd->name = "pxa3xx_nand-0";
- } else if (!mtd->name) {
- /*
- * If the new bindings are used and the bootloader has not been
- * updated to pass a new mtdparts parameter on the cmdline, you
- * should define the following property in your NAND node, ie:
- *
- * label = "main-storage";
- *
- * This way, mtd->name will be set by the core when
- * nand_set_flash_node() is called.
- */
- mtd->name = devm_kasprintf(nfc->dev, GFP_KERNEL,
- "%s:nand.%d", dev_name(nfc->dev),
- marvell_nand->sels[0].cs);
- if (!mtd->name) {
- dev_err(nfc->dev, "Failed to allocate mtd->name\n");
- return -ENOMEM;
- }
- }
- ret = nand_scan_tail(mtd);
+ chip->controller->attach_chip = marvell_nand_attach_chip;
+ ret = nand_scan(mtd, marvell_nand->nsels);
if (ret) {
- dev_err(dev, "nand_scan_tail failed: %d\n", ret);
+ dev_err(dev, "could not scan the nand chip\n");
return ret;
}
--
2.14.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH v2 15/32] mtd: rawnand: mtk: convert driver to nand_scan()
2018-07-03 21:59 [PATCH v2 00/32] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
` (13 preceding siblings ...)
2018-07-03 22:00 ` [PATCH v2 14/32] mtd: rawnand: marvell: " Miquel Raynal
@ 2018-07-03 22:00 ` Miquel Raynal
2018-07-03 22:00 ` [PATCH v2 16/32] mtd: rawnand: mxc: " Miquel Raynal
` (16 subsequent siblings)
31 siblings, 0 replies; 35+ messages in thread
From: Miquel Raynal @ 2018-07-03 22:00 UTC (permalink / raw)
To: linux-arm-kernel
Two helpers have been added to the core to make ECC-related
configuration between the detection phase and the final NAND scan. Use
these hooks and convert the driver to just use nand_scan() instead of
both nand_scan_ident() and nand_scan_tail().
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
drivers/mtd/nand/raw/mtk_nand.c | 71 +++++++++++++++++++++++------------------
1 file changed, 40 insertions(+), 31 deletions(-)
diff --git a/drivers/mtd/nand/raw/mtk_nand.c b/drivers/mtd/nand/raw/mtk_nand.c
index 75c845adb050..a81cd36596e1 100644
--- a/drivers/mtd/nand/raw/mtk_nand.c
+++ b/drivers/mtd/nand/raw/mtk_nand.c
@@ -1250,13 +1250,50 @@ static int mtk_nfc_ecc_init(struct device *dev, struct mtd_info *mtd)
return 0;
}
+static int mtk_nfc_attach_chip(struct nand_chip *chip)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ struct device *dev = mtd->dev.parent;
+ struct mtk_nfc *nfc = nand_get_controller_data(chip);
+ struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+ int len;
+ int ret;
+
+ if (chip->options & NAND_BUSWIDTH_16) {
+ dev_err(dev, "16bits buswidth not supported");
+ return -EINVAL;
+ }
+
+ /* store bbt magic in page, cause OOB is not protected */
+ if (chip->bbt_options & NAND_BBT_USE_FLASH)
+ chip->bbt_options |= NAND_BBT_NO_OOB;
+
+ ret = mtk_nfc_ecc_init(dev, mtd);
+ if (ret)
+ return ret;
+
+ ret = mtk_nfc_set_spare_per_sector(&mtk_nand->spare_per_sector, mtd);
+ if (ret)
+ return ret;
+
+ mtk_nfc_set_fdm(&mtk_nand->fdm, mtd);
+ mtk_nfc_set_bad_mark_ctl(&mtk_nand->bad_mark, mtd);
+
+ len = mtd->writesize + mtd->oobsize;
+ nfc->buffer = devm_kzalloc(dev, len, GFP_KERNEL);
+ if (!nfc->buffer)
+ return -ENOMEM;
+
+ return 0;
+}
+
static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
struct device_node *np)
{
struct mtk_nfc_nand_chip *chip;
struct nand_chip *nand;
struct mtd_info *mtd;
- int nsels, len;
+ int nsels;
u32 tmp;
int ret;
int i;
@@ -1324,36 +1361,8 @@ static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
mtk_nfc_hw_init(nfc);
- ret = nand_scan_ident(mtd, nsels, NULL);
- if (ret)
- return ret;
-
- /* store bbt magic in page, cause OOB is not protected */
- if (nand->bbt_options & NAND_BBT_USE_FLASH)
- nand->bbt_options |= NAND_BBT_NO_OOB;
-
- ret = mtk_nfc_ecc_init(dev, mtd);
- if (ret)
- return -EINVAL;
-
- if (nand->options & NAND_BUSWIDTH_16) {
- dev_err(dev, "16bits buswidth not supported");
- return -EINVAL;
- }
-
- ret = mtk_nfc_set_spare_per_sector(&chip->spare_per_sector, mtd);
- if (ret)
- return ret;
-
- mtk_nfc_set_fdm(&chip->fdm, mtd);
- mtk_nfc_set_bad_mark_ctl(&chip->bad_mark, mtd);
-
- len = mtd->writesize + mtd->oobsize;
- nfc->buffer = devm_kzalloc(dev, len, GFP_KERNEL);
- if (!nfc->buffer)
- return -ENOMEM;
-
- ret = nand_scan_tail(mtd);
+ nand->controller->attach_chip = mtk_nfc_attach_chip;
+ ret = nand_scan(mtd, nsels);
if (ret)
return ret;
--
2.14.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH v2 16/32] mtd: rawnand: mxc: convert driver to nand_scan()
2018-07-03 21:59 [PATCH v2 00/32] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
` (14 preceding siblings ...)
2018-07-03 22:00 ` [PATCH v2 15/32] mtd: rawnand: mtk: " Miquel Raynal
@ 2018-07-03 22:00 ` Miquel Raynal
2018-07-03 22:00 ` [PATCH v2 17/32] mtd: rawnand: nandsim: " Miquel Raynal
` (15 subsequent siblings)
31 siblings, 0 replies; 35+ messages in thread
From: Miquel Raynal @ 2018-07-03 22:00 UTC (permalink / raw)
To: linux-arm-kernel
Two helpers have been added to the core to make ECC-related
configuration between the detection phase and the final NAND scan. Use
these hooks and convert the driver to just use nand_scan() instead of
both nand_scan_ident() and nand_scan_tail().
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
drivers/mtd/nand/raw/mxc_nand.c | 132 ++++++++++++++++++++--------------------
1 file changed, 67 insertions(+), 65 deletions(-)
diff --git a/drivers/mtd/nand/raw/mxc_nand.c b/drivers/mtd/nand/raw/mxc_nand.c
index 90cfb5e730aa..3c0451433247 100644
--- a/drivers/mtd/nand/raw/mxc_nand.c
+++ b/drivers/mtd/nand/raw/mxc_nand.c
@@ -1706,6 +1706,70 @@ static int mxcnd_probe_dt(struct mxc_nand_host *host)
}
#endif
+static int mxcnd_attach_chip(struct nand_chip *chip)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ struct mxc_nand_host *host = nand_get_controller_data(chip);
+ struct device *dev = mtd->dev.parent;
+
+ switch (chip->ecc.mode) {
+ case NAND_ECC_HW:
+ chip->ecc.read_page = mxc_nand_read_page;
+ chip->ecc.read_page_raw = mxc_nand_read_page_raw;
+ chip->ecc.read_oob = mxc_nand_read_oob;
+ chip->ecc.write_page = mxc_nand_write_page_ecc;
+ chip->ecc.write_page_raw = mxc_nand_write_page_raw;
+ chip->ecc.write_oob = mxc_nand_write_oob;
+ break;
+
+ case NAND_ECC_SOFT:
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ if (chip->bbt_options & NAND_BBT_USE_FLASH) {
+ chip->bbt_td = &bbt_main_descr;
+ chip->bbt_md = &bbt_mirror_descr;
+ }
+
+ /* Allocate the right size buffer now */
+ devm_kfree(dev, (void *)host->data_buf);
+ host->data_buf = devm_kzalloc(dev, mtd->writesize + mtd->oobsize,
+ GFP_KERNEL);
+ if (!host->data_buf)
+ return -ENOMEM;
+
+ /* Call preset again, with correct writesize chip time */
+ host->devtype_data->preset(mtd);
+
+ if (!chip->ecc.bytes) {
+ if (host->eccsize == 8)
+ chip->ecc.bytes = 18;
+ else if (host->eccsize == 4)
+ chip->ecc.bytes = 9;
+ }
+
+ /*
+ * Experimentation shows that i.MX NFC can only handle up to 218 oob
+ * bytes. Limit used_oobsize to 218 so as to not confuse copy_spare()
+ * into copying invalid data to/from the spare IO buffer, as this
+ * might cause ECC data corruption when doing sub-page write to a
+ * partially written page.
+ */
+ host->used_oobsize = min(mtd->oobsize, 218U);
+
+ if (chip->ecc.mode == NAND_ECC_HW) {
+ if (is_imx21_nfc(host) || is_imx27_nfc(host))
+ chip->ecc.strength = 1;
+ else
+ chip->ecc.strength = (host->eccsize == 4) ? 4 : 8;
+ }
+
+ return 0;
+}
+
static int mxcnd_probe(struct platform_device *pdev)
{
struct nand_chip *this;
@@ -1845,71 +1909,9 @@ static int mxcnd_probe(struct platform_device *pdev)
host->devtype_data->irq_control(host, 1);
}
- /* first scan to find the device and get the page size */
- err = nand_scan_ident(mtd, is_imx25_nfc(host) ? 4 : 1, NULL);
- if (err)
- goto escan;
-
- switch (this->ecc.mode) {
- case NAND_ECC_HW:
- this->ecc.read_page = mxc_nand_read_page;
- this->ecc.read_page_raw = mxc_nand_read_page_raw;
- this->ecc.read_oob = mxc_nand_read_oob;
- this->ecc.write_page = mxc_nand_write_page_ecc;
- this->ecc.write_page_raw = mxc_nand_write_page_raw;
- this->ecc.write_oob = mxc_nand_write_oob;
- break;
-
- case NAND_ECC_SOFT:
- break;
-
- default:
- err = -EINVAL;
- goto escan;
- }
-
- if (this->bbt_options & NAND_BBT_USE_FLASH) {
- this->bbt_td = &bbt_main_descr;
- this->bbt_md = &bbt_mirror_descr;
- }
-
- /* allocate the right size buffer now */
- devm_kfree(&pdev->dev, (void *)host->data_buf);
- host->data_buf = devm_kzalloc(&pdev->dev, mtd->writesize + mtd->oobsize,
- GFP_KERNEL);
- if (!host->data_buf) {
- err = -ENOMEM;
- goto escan;
- }
-
- /* Call preset again, with correct writesize this time */
- host->devtype_data->preset(mtd);
-
- if (!this->ecc.bytes) {
- if (host->eccsize == 8)
- this->ecc.bytes = 18;
- else if (host->eccsize == 4)
- this->ecc.bytes = 9;
- }
-
- /*
- * Experimentation shows that i.MX NFC can only handle up to 218 oob
- * bytes. Limit used_oobsize to 218 so as to not confuse copy_spare()
- * into copying invalid data to/from the spare IO buffer, as this
- * might cause ECC data corruption when doing sub-page write to a
- * partially written page.
- */
- host->used_oobsize = min(mtd->oobsize, 218U);
-
- if (this->ecc.mode == NAND_ECC_HW) {
- if (is_imx21_nfc(host) || is_imx27_nfc(host))
- this->ecc.strength = 1;
- else
- this->ecc.strength = (host->eccsize == 4) ? 4 : 8;
- }
-
- /* second phase scan */
- err = nand_scan_tail(mtd);
+ /* Scan the NAND device */
+ this->hwcontrol.attach_chip = mxcnd_attach_chip;
+ err = nand_scan(mtd, is_imx25_nfc(host) ? 4 : 1);
if (err)
goto escan;
--
2.14.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH v2 17/32] mtd: rawnand: nandsim: convert driver to nand_scan()
2018-07-03 21:59 [PATCH v2 00/32] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
` (15 preceding siblings ...)
2018-07-03 22:00 ` [PATCH v2 16/32] mtd: rawnand: mxc: " Miquel Raynal
@ 2018-07-03 22:00 ` Miquel Raynal
2018-07-03 22:00 ` [PATCH v2 18/32] mtd: rawnand: omap2: " Miquel Raynal
` (14 subsequent siblings)
31 siblings, 0 replies; 35+ messages in thread
From: Miquel Raynal @ 2018-07-03 22:00 UTC (permalink / raw)
To: linux-arm-kernel
Two helpers have been added to the core to make ECC-related
configuration between the detection phase and the final NAND scan. Use
these hooks and convert the driver to just use nand_scan() instead of
both nand_scan_ident() and nand_scan_tail().
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
drivers/mtd/nand/raw/nandsim.c | 78 ++++++++++++++++++++++--------------------
1 file changed, 41 insertions(+), 37 deletions(-)
diff --git a/drivers/mtd/nand/raw/nandsim.c b/drivers/mtd/nand/raw/nandsim.c
index f8edacde49ab..fa9d1c05fc45 100644
--- a/drivers/mtd/nand/raw/nandsim.c
+++ b/drivers/mtd/nand/raw/nandsim.c
@@ -2192,6 +2192,44 @@ static void ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
return;
}
+static int ns_attach_chip(struct nand_chip *chip)
+{
+ unsigned int eccsteps, eccbytes;
+
+ if (!bch)
+ return 0;
+
+ if (!mtd_nand_has_bch()) {
+ NS_ERR("BCH ECC support is disabled\n");
+ return -EINVAL;
+ }
+
+ /* Use 512-byte ecc blocks */
+ eccsteps = nsmtd->writesize / 512;
+ eccbytes = ((bch * 13) + 7) / 8;
+
+ /* Do not bother supporting small page devices */
+ if (nsmtd->oobsize < 64 || !eccsteps) {
+ NS_ERR("BCH not available on small page devices\n");
+ return -EINVAL;
+ }
+
+ if (((eccbytes * eccsteps) + 2) > nsmtd->oobsize) {
+ NS_ERR("Invalid BCH value %u\n", bch);
+ return -EINVAL;
+ }
+
+ chip->ecc.mode = NAND_ECC_SOFT;
+ chip->ecc.algo = NAND_ECC_BCH;
+ chip->ecc.size = 512;
+ chip->ecc.strength = bch;
+ chip->ecc.bytes = eccbytes;
+
+ NS_INFO("Using %u-bit/%u bytes BCH ECC\n", bch, chip->ecc.size);
+
+ return 0;
+}
+
/*
* Module initialization function
*/
@@ -2276,44 +2314,10 @@ static int __init ns_init_module(void)
if ((retval = parse_gravepages()) != 0)
goto error;
- retval = nand_scan_ident(nsmtd, 1, NULL);
+ chip->hwcontrol.attach_chip = ns_attach_chip;
+ retval = nand_scan(nsmtd, 1);
if (retval) {
- NS_ERR("cannot scan NAND Simulator device\n");
- goto error;
- }
-
- if (bch) {
- unsigned int eccsteps, eccbytes;
- if (!mtd_nand_has_bch()) {
- NS_ERR("BCH ECC support is disabled\n");
- retval = -EINVAL;
- goto error;
- }
- /* use 512-byte ecc blocks */
- eccsteps = nsmtd->writesize/512;
- eccbytes = (bch*13+7)/8;
- /* do not bother supporting small page devices */
- if ((nsmtd->oobsize < 64) || !eccsteps) {
- NS_ERR("bch not available on small page devices\n");
- retval = -EINVAL;
- goto error;
- }
- if ((eccbytes*eccsteps+2) > nsmtd->oobsize) {
- NS_ERR("invalid bch value %u\n", bch);
- retval = -EINVAL;
- goto error;
- }
- chip->ecc.mode = NAND_ECC_SOFT;
- chip->ecc.algo = NAND_ECC_BCH;
- chip->ecc.size = 512;
- chip->ecc.strength = bch;
- chip->ecc.bytes = eccbytes;
- NS_INFO("using %u-bit/%u bytes BCH ECC\n", bch, chip->ecc.size);
- }
-
- retval = nand_scan_tail(nsmtd);
- if (retval) {
- NS_ERR("can't register NAND Simulator\n");
+ NS_ERR("Could not scan NAND Simulator device\n");
goto error;
}
--
2.14.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH v2 18/32] mtd: rawnand: omap2: convert driver to nand_scan()
2018-07-03 21:59 [PATCH v2 00/32] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
` (16 preceding siblings ...)
2018-07-03 22:00 ` [PATCH v2 17/32] mtd: rawnand: nandsim: " Miquel Raynal
@ 2018-07-03 22:00 ` Miquel Raynal
2018-07-03 22:00 ` [PATCH v2 19/32] mtd: rawnand: s3c2410: " Miquel Raynal
` (13 subsequent siblings)
31 siblings, 0 replies; 35+ messages in thread
From: Miquel Raynal @ 2018-07-03 22:00 UTC (permalink / raw)
To: linux-arm-kernel
Two helpers have been added to the core to make ECC-related
configuration between the detection phase and the final NAND scan. Use
these hooks and convert the driver to just use nand_scan() instead of
both nand_scan_ident() and nand_scan_tail().
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
drivers/mtd/nand/raw/omap2.c | 517 +++++++++++++++++++++----------------------
1 file changed, 255 insertions(+), 262 deletions(-)
diff --git a/drivers/mtd/nand/raw/omap2.c b/drivers/mtd/nand/raw/omap2.c
index e50c64adc3c8..40799fd9b787 100644
--- a/drivers/mtd/nand/raw/omap2.c
+++ b/drivers/mtd/nand/raw/omap2.c
@@ -1915,17 +1915,267 @@ static const struct mtd_ooblayout_ops omap_sw_ooblayout_ops = {
.free = omap_sw_ooblayout_free,
};
+static int omap_nand_attach_chip(struct nand_chip *chip)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ struct omap_nand_info *info = mtd_to_omap(mtd);
+ struct device *dev = &info->pdev->dev;
+ int min_oobbytes = BADBLOCK_MARKER_LENGTH;
+ int oobbytes_per_step;
+ dma_cap_mask_t mask;
+ int err;
+
+ if (chip->bbt_options & NAND_BBT_USE_FLASH)
+ chip->bbt_options |= NAND_BBT_NO_OOB;
+ else
+ chip->options |= NAND_SKIP_BBTSCAN;
+
+ /* Re-populate low-level callbacks based on xfer modes */
+ switch (info->xfer_type) {
+ case NAND_OMAP_PREFETCH_POLLED:
+ chip->read_buf = omap_read_buf_pref;
+ chip->write_buf = omap_write_buf_pref;
+ break;
+
+ case NAND_OMAP_POLLED:
+ /* Use nand_base defaults for {read,write}_buf */
+ break;
+
+ case NAND_OMAP_PREFETCH_DMA:
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+ info->dma = dma_request_chan(dev, "rxtx");
+
+ if (IS_ERR(info->dma)) {
+ dev_err(dev, "DMA engine request failed\n");
+ return PTR_ERR(info->dma);
+ } else {
+ struct dma_slave_config cfg;
+
+ memset(&cfg, 0, sizeof(cfg));
+ cfg.src_addr = info->phys_base;
+ cfg.dst_addr = info->phys_base;
+ cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ cfg.src_maxburst = 16;
+ cfg.dst_maxburst = 16;
+ err = dmaengine_slave_config(info->dma, &cfg);
+ if (err) {
+ dev_err(dev,
+ "DMA engine slave config failed: %d\n",
+ err);
+ return err;
+ }
+ chip->read_buf = omap_read_buf_dma_pref;
+ chip->write_buf = omap_write_buf_dma_pref;
+ }
+ break;
+
+ case NAND_OMAP_PREFETCH_IRQ:
+ info->gpmc_irq_fifo = platform_get_irq(info->pdev, 0);
+ if (info->gpmc_irq_fifo <= 0) {
+ dev_err(dev, "Error getting fifo IRQ\n");
+ return -ENODEV;
+ }
+ err = devm_request_irq(dev, info->gpmc_irq_fifo,
+ omap_nand_irq, IRQF_SHARED,
+ "gpmc-nand-fifo", info);
+ if (err) {
+ dev_err(dev, "Requesting IRQ %d, error %d\n",
+ info->gpmc_irq_fifo, err);
+ info->gpmc_irq_fifo = 0;
+ return err;
+ }
+
+ info->gpmc_irq_count = platform_get_irq(info->pdev, 1);
+ if (info->gpmc_irq_count <= 0) {
+ dev_err(dev, "Error getting IRQ count\n");
+ return -ENODEV;
+ }
+ err = devm_request_irq(dev, info->gpmc_irq_count,
+ omap_nand_irq, IRQF_SHARED,
+ "gpmc-nand-count", info);
+ if (err) {
+ dev_err(dev, "Requesting IRQ %d, error %d\n",
+ info->gpmc_irq_count, err);
+ info->gpmc_irq_count = 0;
+ return err;
+ }
+
+ chip->read_buf = omap_read_buf_irq_pref;
+ chip->write_buf = omap_write_buf_irq_pref;
+
+ break;
+
+ default:
+ dev_err(dev, "xfer_type %d not supported!\n", info->xfer_type);
+ return -EINVAL;
+ }
+
+ if (!omap2_nand_ecc_check(info))
+ return -EINVAL;
+
+ /*
+ * Bail out earlier to let NAND_ECC_SOFT code create its own
+ * ooblayout instead of using ours.
+ */
+ if (info->ecc_opt == OMAP_ECC_HAM1_CODE_SW) {
+ chip->ecc.mode = NAND_ECC_SOFT;
+ chip->ecc.algo = NAND_ECC_HAMMING;
+ return 0;
+ }
+
+ /* Populate MTD interface based on ECC scheme */
+ switch (info->ecc_opt) {
+ case OMAP_ECC_HAM1_CODE_HW:
+ dev_info(dev, "nand: using OMAP_ECC_HAM1_CODE_HW\n");
+ chip->ecc.mode = NAND_ECC_HW;
+ chip->ecc.bytes = 3;
+ chip->ecc.size = 512;
+ chip->ecc.strength = 1;
+ chip->ecc.calculate = omap_calculate_ecc;
+ chip->ecc.hwctl = omap_enable_hwecc;
+ chip->ecc.correct = omap_correct_data;
+ mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
+ oobbytes_per_step = chip->ecc.bytes;
+
+ if (!(chip->options & NAND_BUSWIDTH_16))
+ min_oobbytes = 1;
+
+ break;
+
+ case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW:
+ pr_info("nand: using OMAP_ECC_BCH4_CODE_HW_DETECTION_SW\n");
+ chip->ecc.mode = NAND_ECC_HW;
+ chip->ecc.size = 512;
+ chip->ecc.bytes = 7;
+ chip->ecc.strength = 4;
+ chip->ecc.hwctl = omap_enable_hwecc_bch;
+ chip->ecc.correct = nand_bch_correct_data;
+ chip->ecc.calculate = omap_calculate_ecc_bch_sw;
+ mtd_set_ooblayout(mtd, &omap_sw_ooblayout_ops);
+ /* Reserve one byte for the OMAP marker */
+ oobbytes_per_step = chip->ecc.bytes + 1;
+ /* Software BCH library is used for locating errors */
+ chip->ecc.priv = nand_bch_init(mtd);
+ if (!chip->ecc.priv) {
+ dev_err(dev, "Unable to use BCH library\n");
+ return -EINVAL;
+ }
+ break;
+
+ case OMAP_ECC_BCH4_CODE_HW:
+ pr_info("nand: using OMAP_ECC_BCH4_CODE_HW ECC scheme\n");
+ chip->ecc.mode = NAND_ECC_HW;
+ chip->ecc.size = 512;
+ /* 14th bit is kept reserved for ROM-code compatibility */
+ chip->ecc.bytes = 7 + 1;
+ chip->ecc.strength = 4;
+ chip->ecc.hwctl = omap_enable_hwecc_bch;
+ chip->ecc.correct = omap_elm_correct_data;
+ chip->ecc.read_page = omap_read_page_bch;
+ chip->ecc.write_page = omap_write_page_bch;
+ chip->ecc.write_subpage = omap_write_subpage_bch;
+ mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
+ oobbytes_per_step = chip->ecc.bytes;
+
+ err = elm_config(info->elm_dev, BCH4_ECC,
+ mtd->writesize / chip->ecc.size,
+ chip->ecc.size, chip->ecc.bytes);
+ if (err < 0)
+ return err;
+ break;
+
+ case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
+ pr_info("nand: using OMAP_ECC_BCH8_CODE_HW_DETECTION_SW\n");
+ chip->ecc.mode = NAND_ECC_HW;
+ chip->ecc.size = 512;
+ chip->ecc.bytes = 13;
+ chip->ecc.strength = 8;
+ chip->ecc.hwctl = omap_enable_hwecc_bch;
+ chip->ecc.correct = nand_bch_correct_data;
+ chip->ecc.calculate = omap_calculate_ecc_bch_sw;
+ mtd_set_ooblayout(mtd, &omap_sw_ooblayout_ops);
+ /* Reserve one byte for the OMAP marker */
+ oobbytes_per_step = chip->ecc.bytes + 1;
+ /* Software BCH library is used for locating errors */
+ chip->ecc.priv = nand_bch_init(mtd);
+ if (!chip->ecc.priv) {
+ dev_err(dev, "unable to use BCH library\n");
+ return -EINVAL;
+ }
+ break;
+
+ case OMAP_ECC_BCH8_CODE_HW:
+ pr_info("nand: using OMAP_ECC_BCH8_CODE_HW ECC scheme\n");
+ chip->ecc.mode = NAND_ECC_HW;
+ chip->ecc.size = 512;
+ /* 14th bit is kept reserved for ROM-code compatibility */
+ chip->ecc.bytes = 13 + 1;
+ chip->ecc.strength = 8;
+ chip->ecc.hwctl = omap_enable_hwecc_bch;
+ chip->ecc.correct = omap_elm_correct_data;
+ chip->ecc.read_page = omap_read_page_bch;
+ chip->ecc.write_page = omap_write_page_bch;
+ chip->ecc.write_subpage = omap_write_subpage_bch;
+ mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
+ oobbytes_per_step = chip->ecc.bytes;
+
+ err = elm_config(info->elm_dev, BCH8_ECC,
+ mtd->writesize / chip->ecc.size,
+ chip->ecc.size, chip->ecc.bytes);
+ if (err < 0)
+ return err;
+
+ break;
+
+ case OMAP_ECC_BCH16_CODE_HW:
+ pr_info("Using OMAP_ECC_BCH16_CODE_HW ECC scheme\n");
+ chip->ecc.mode = NAND_ECC_HW;
+ chip->ecc.size = 512;
+ chip->ecc.bytes = 26;
+ chip->ecc.strength = 16;
+ chip->ecc.hwctl = omap_enable_hwecc_bch;
+ chip->ecc.correct = omap_elm_correct_data;
+ chip->ecc.read_page = omap_read_page_bch;
+ chip->ecc.write_page = omap_write_page_bch;
+ chip->ecc.write_subpage = omap_write_subpage_bch;
+ mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
+ oobbytes_per_step = chip->ecc.bytes;
+
+ err = elm_config(info->elm_dev, BCH16_ECC,
+ mtd->writesize / chip->ecc.size,
+ chip->ecc.size, chip->ecc.bytes);
+ if (err < 0)
+ return err;
+
+ break;
+ default:
+ dev_err(dev, "Invalid or unsupported ECC scheme\n");
+ return -EINVAL;
+ }
+
+ /* Check if NAND device's OOB is enough to store ECC signatures */
+ min_oobbytes += (oobbytes_per_step *
+ (mtd->writesize / chip->ecc.size));
+ if (mtd->oobsize < min_oobbytes) {
+ dev_err(dev,
+ "Not enough OOB bytes: required = %d, available=%d\n",
+ min_oobbytes, mtd->oobsize);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int omap_nand_probe(struct platform_device *pdev)
{
struct omap_nand_info *info;
struct mtd_info *mtd;
struct nand_chip *nand_chip;
int err;
- dma_cap_mask_t mask;
struct resource *res;
struct device *dev = &pdev->dev;
- int min_oobbytes = BADBLOCK_MARKER_LENGTH;
- int oobbytes_per_step;
info = devm_kzalloc(&pdev->dev, sizeof(struct omap_nand_info),
GFP_KERNEL);
@@ -1998,266 +2248,9 @@ static int omap_nand_probe(struct platform_device *pdev)
/* scan NAND device connected to chip controller */
nand_chip->options |= info->devsize & NAND_BUSWIDTH_16;
- err = nand_scan_ident(mtd, 1, NULL);
- if (err) {
- dev_err(&info->pdev->dev,
- "scan failed, may be bus-width mismatch\n");
- goto return_error;
- }
- if (nand_chip->bbt_options & NAND_BBT_USE_FLASH)
- nand_chip->bbt_options |= NAND_BBT_NO_OOB;
- else
- nand_chip->options |= NAND_SKIP_BBTSCAN;
-
- /* re-populate low-level callbacks based on xfer modes */
- switch (info->xfer_type) {
- case NAND_OMAP_PREFETCH_POLLED:
- nand_chip->read_buf = omap_read_buf_pref;
- nand_chip->write_buf = omap_write_buf_pref;
- break;
-
- case NAND_OMAP_POLLED:
- /* Use nand_base defaults for {read,write}_buf */
- break;
-
- case NAND_OMAP_PREFETCH_DMA:
- dma_cap_zero(mask);
- dma_cap_set(DMA_SLAVE, mask);
- info->dma = dma_request_chan(pdev->dev.parent, "rxtx");
-
- if (IS_ERR(info->dma)) {
- dev_err(&pdev->dev, "DMA engine request failed\n");
- err = PTR_ERR(info->dma);
- goto return_error;
- } else {
- struct dma_slave_config cfg;
-
- memset(&cfg, 0, sizeof(cfg));
- cfg.src_addr = info->phys_base;
- cfg.dst_addr = info->phys_base;
- cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
- cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
- cfg.src_maxburst = 16;
- cfg.dst_maxburst = 16;
- err = dmaengine_slave_config(info->dma, &cfg);
- if (err) {
- dev_err(&pdev->dev, "DMA engine slave config failed: %d\n",
- err);
- goto return_error;
- }
- nand_chip->read_buf = omap_read_buf_dma_pref;
- nand_chip->write_buf = omap_write_buf_dma_pref;
- }
- break;
-
- case NAND_OMAP_PREFETCH_IRQ:
- info->gpmc_irq_fifo = platform_get_irq(pdev, 0);
- if (info->gpmc_irq_fifo <= 0) {
- dev_err(&pdev->dev, "error getting fifo irq\n");
- err = -ENODEV;
- goto return_error;
- }
- err = devm_request_irq(&pdev->dev, info->gpmc_irq_fifo,
- omap_nand_irq, IRQF_SHARED,
- "gpmc-nand-fifo", info);
- if (err) {
- dev_err(&pdev->dev, "requesting irq(%d) error:%d",
- info->gpmc_irq_fifo, err);
- info->gpmc_irq_fifo = 0;
- goto return_error;
- }
-
- info->gpmc_irq_count = platform_get_irq(pdev, 1);
- if (info->gpmc_irq_count <= 0) {
- dev_err(&pdev->dev, "error getting count irq\n");
- err = -ENODEV;
- goto return_error;
- }
- err = devm_request_irq(&pdev->dev, info->gpmc_irq_count,
- omap_nand_irq, IRQF_SHARED,
- "gpmc-nand-count", info);
- if (err) {
- dev_err(&pdev->dev, "requesting irq(%d) error:%d",
- info->gpmc_irq_count, err);
- info->gpmc_irq_count = 0;
- goto return_error;
- }
-
- nand_chip->read_buf = omap_read_buf_irq_pref;
- nand_chip->write_buf = omap_write_buf_irq_pref;
-
- break;
-
- default:
- dev_err(&pdev->dev,
- "xfer_type(%d) not supported!\n", info->xfer_type);
- err = -EINVAL;
- goto return_error;
- }
-
- if (!omap2_nand_ecc_check(info)) {
- err = -EINVAL;
- goto return_error;
- }
-
- /*
- * Bail out earlier to let NAND_ECC_SOFT code create its own
- * ooblayout instead of using ours.
- */
- if (info->ecc_opt == OMAP_ECC_HAM1_CODE_SW) {
- nand_chip->ecc.mode = NAND_ECC_SOFT;
- nand_chip->ecc.algo = NAND_ECC_HAMMING;
- goto scan_tail;
- }
-
- /* populate MTD interface based on ECC scheme */
- switch (info->ecc_opt) {
- case OMAP_ECC_HAM1_CODE_HW:
- pr_info("nand: using OMAP_ECC_HAM1_CODE_HW\n");
- nand_chip->ecc.mode = NAND_ECC_HW;
- nand_chip->ecc.bytes = 3;
- nand_chip->ecc.size = 512;
- nand_chip->ecc.strength = 1;
- nand_chip->ecc.calculate = omap_calculate_ecc;
- nand_chip->ecc.hwctl = omap_enable_hwecc;
- nand_chip->ecc.correct = omap_correct_data;
- mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
- oobbytes_per_step = nand_chip->ecc.bytes;
-
- if (!(nand_chip->options & NAND_BUSWIDTH_16))
- min_oobbytes = 1;
-
- break;
-
- case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW:
- pr_info("nand: using OMAP_ECC_BCH4_CODE_HW_DETECTION_SW\n");
- nand_chip->ecc.mode = NAND_ECC_HW;
- nand_chip->ecc.size = 512;
- nand_chip->ecc.bytes = 7;
- nand_chip->ecc.strength = 4;
- nand_chip->ecc.hwctl = omap_enable_hwecc_bch;
- nand_chip->ecc.correct = nand_bch_correct_data;
- nand_chip->ecc.calculate = omap_calculate_ecc_bch_sw;
- mtd_set_ooblayout(mtd, &omap_sw_ooblayout_ops);
- /* Reserve one byte for the OMAP marker */
- oobbytes_per_step = nand_chip->ecc.bytes + 1;
- /* software bch library is used for locating errors */
- nand_chip->ecc.priv = nand_bch_init(mtd);
- if (!nand_chip->ecc.priv) {
- dev_err(&info->pdev->dev, "unable to use BCH library\n");
- err = -EINVAL;
- goto return_error;
- }
- break;
-
- case OMAP_ECC_BCH4_CODE_HW:
- pr_info("nand: using OMAP_ECC_BCH4_CODE_HW ECC scheme\n");
- nand_chip->ecc.mode = NAND_ECC_HW;
- nand_chip->ecc.size = 512;
- /* 14th bit is kept reserved for ROM-code compatibility */
- nand_chip->ecc.bytes = 7 + 1;
- nand_chip->ecc.strength = 4;
- nand_chip->ecc.hwctl = omap_enable_hwecc_bch;
- nand_chip->ecc.correct = omap_elm_correct_data;
- nand_chip->ecc.read_page = omap_read_page_bch;
- nand_chip->ecc.write_page = omap_write_page_bch;
- nand_chip->ecc.write_subpage = omap_write_subpage_bch;
- mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
- oobbytes_per_step = nand_chip->ecc.bytes;
-
- err = elm_config(info->elm_dev, BCH4_ECC,
- mtd->writesize / nand_chip->ecc.size,
- nand_chip->ecc.size, nand_chip->ecc.bytes);
- if (err < 0)
- goto return_error;
- break;
-
- case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
- pr_info("nand: using OMAP_ECC_BCH8_CODE_HW_DETECTION_SW\n");
- nand_chip->ecc.mode = NAND_ECC_HW;
- nand_chip->ecc.size = 512;
- nand_chip->ecc.bytes = 13;
- nand_chip->ecc.strength = 8;
- nand_chip->ecc.hwctl = omap_enable_hwecc_bch;
- nand_chip->ecc.correct = nand_bch_correct_data;
- nand_chip->ecc.calculate = omap_calculate_ecc_bch_sw;
- mtd_set_ooblayout(mtd, &omap_sw_ooblayout_ops);
- /* Reserve one byte for the OMAP marker */
- oobbytes_per_step = nand_chip->ecc.bytes + 1;
- /* software bch library is used for locating errors */
- nand_chip->ecc.priv = nand_bch_init(mtd);
- if (!nand_chip->ecc.priv) {
- dev_err(&info->pdev->dev, "unable to use BCH library\n");
- err = -EINVAL;
- goto return_error;
- }
- break;
-
- case OMAP_ECC_BCH8_CODE_HW:
- pr_info("nand: using OMAP_ECC_BCH8_CODE_HW ECC scheme\n");
- nand_chip->ecc.mode = NAND_ECC_HW;
- nand_chip->ecc.size = 512;
- /* 14th bit is kept reserved for ROM-code compatibility */
- nand_chip->ecc.bytes = 13 + 1;
- nand_chip->ecc.strength = 8;
- nand_chip->ecc.hwctl = omap_enable_hwecc_bch;
- nand_chip->ecc.correct = omap_elm_correct_data;
- nand_chip->ecc.read_page = omap_read_page_bch;
- nand_chip->ecc.write_page = omap_write_page_bch;
- nand_chip->ecc.write_subpage = omap_write_subpage_bch;
- mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
- oobbytes_per_step = nand_chip->ecc.bytes;
-
- err = elm_config(info->elm_dev, BCH8_ECC,
- mtd->writesize / nand_chip->ecc.size,
- nand_chip->ecc.size, nand_chip->ecc.bytes);
- if (err < 0)
- goto return_error;
-
- break;
-
- case OMAP_ECC_BCH16_CODE_HW:
- pr_info("using OMAP_ECC_BCH16_CODE_HW ECC scheme\n");
- nand_chip->ecc.mode = NAND_ECC_HW;
- nand_chip->ecc.size = 512;
- nand_chip->ecc.bytes = 26;
- nand_chip->ecc.strength = 16;
- nand_chip->ecc.hwctl = omap_enable_hwecc_bch;
- nand_chip->ecc.correct = omap_elm_correct_data;
- nand_chip->ecc.read_page = omap_read_page_bch;
- nand_chip->ecc.write_page = omap_write_page_bch;
- nand_chip->ecc.write_subpage = omap_write_subpage_bch;
- mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
- oobbytes_per_step = nand_chip->ecc.bytes;
-
- err = elm_config(info->elm_dev, BCH16_ECC,
- mtd->writesize / nand_chip->ecc.size,
- nand_chip->ecc.size, nand_chip->ecc.bytes);
- if (err < 0)
- goto return_error;
-
- break;
- default:
- dev_err(&info->pdev->dev, "invalid or unsupported ECC scheme\n");
- err = -EINVAL;
- goto return_error;
- }
-
- /* check if NAND device's OOB is enough to store ECC signatures */
- min_oobbytes += (oobbytes_per_step *
- (mtd->writesize / nand_chip->ecc.size));
- if (mtd->oobsize < min_oobbytes) {
- dev_err(&info->pdev->dev,
- "not enough OOB bytes required = %d, available=%d\n",
- min_oobbytes, mtd->oobsize);
- err = -EINVAL;
- goto return_error;
- }
-
-scan_tail:
- /* second phase scan */
- err = nand_scan_tail(mtd);
+ nand_chip->controller->attach_chip = omap_nand_attach_chip;
+ err = nand_scan(mtd, 1);
if (err)
goto return_error;
--
2.14.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH v2 19/32] mtd: rawnand: s3c2410: convert driver to nand_scan()
2018-07-03 21:59 [PATCH v2 00/32] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
` (17 preceding siblings ...)
2018-07-03 22:00 ` [PATCH v2 18/32] mtd: rawnand: omap2: " Miquel Raynal
@ 2018-07-03 22:00 ` Miquel Raynal
2018-07-03 22:00 ` [PATCH v2 20/32] mtd: rawnand: sh_flctl: move all NAND chip related setup in one function Miquel Raynal
` (12 subsequent siblings)
31 siblings, 0 replies; 35+ messages in thread
From: Miquel Raynal @ 2018-07-03 22:00 UTC (permalink / raw)
To: linux-arm-kernel
Two helpers have been added to the core to make ECC-related
configuration between the detection phase and the final NAND scan. Use
these hooks and convert the driver to just use nand_scan() instead of
both nand_scan_ident() and nand_scan_tail().
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
drivers/mtd/nand/raw/s3c2410.c | 26 +++++++++-----------------
1 file changed, 9 insertions(+), 17 deletions(-)
diff --git a/drivers/mtd/nand/raw/s3c2410.c b/drivers/mtd/nand/raw/s3c2410.c
index 19661c5d3220..d656ea3a9ffe 100644
--- a/drivers/mtd/nand/raw/s3c2410.c
+++ b/drivers/mtd/nand/raw/s3c2410.c
@@ -915,20 +915,19 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
}
/**
- * s3c2410_nand_update_chip - post probe update
- * @info: The controller instance.
- * @nmtd: The driver version of the MTD instance.
+ * s3c2410_nand_attach_chip - Init the ECC engine after NAND scan
+ * @chip: The NAND chip
*
- * This routine is called after the chip probe has successfully completed
- * and the relevant per-chip information updated. This call ensure that
+ * This hook is called by the core after the identification of the NAND chip,
+ * once the relevant per-chip information is up to date.. This call ensure that
* we update the internal state accordingly.
*
* The internal state is currently limited to the ECC state information.
*/
-static int s3c2410_nand_update_chip(struct s3c2410_nand_info *info,
- struct s3c2410_nand_mtd *nmtd)
+static int s3c2410_nand_attach_chip(struct nand_chip *chip)
{
- struct nand_chip *chip = &nmtd->chip;
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
switch (chip->ecc.mode) {
@@ -1161,15 +1160,8 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
mtd->dev.parent = &pdev->dev;
s3c2410_nand_init_chip(info, nmtd, sets);
- err = nand_scan_ident(mtd, (sets) ? sets->nr_chips : 1, NULL);
- if (err)
- goto exit_error;
-
- err = s3c2410_nand_update_chip(info, nmtd);
- if (err < 0)
- goto exit_error;
-
- err = nand_scan_tail(mtd);
+ nmtd->chip.controller->attach_chip = s3c2410_nand_attach_chip;
+ err = nand_scan(mtd, sets ? sets->nr_chips : 1);
if (err)
goto exit_error;
--
2.14.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH v2 20/32] mtd: rawnand: sh_flctl: move all NAND chip related setup in one function
2018-07-03 21:59 [PATCH v2 00/32] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
` (18 preceding siblings ...)
2018-07-03 22:00 ` [PATCH v2 19/32] mtd: rawnand: s3c2410: " Miquel Raynal
@ 2018-07-03 22:00 ` Miquel Raynal
2018-07-03 22:00 ` [PATCH v2 21/32] mtd: rawnand: sh_flctl: convert driver to nand_scan() Miquel Raynal
` (11 subsequent siblings)
31 siblings, 0 replies; 35+ messages in thread
From: Miquel Raynal @ 2018-07-03 22:00 UTC (permalink / raw)
To: linux-arm-kernel
Prepare the conversion of the sh_flctl driver to nand_scan() by moving
all the configuration that must be made after nand_scan_ident() in one
single function. Create a pdata entry in the controller structure for
that.
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
drivers/mtd/nand/raw/sh_flctl.c | 38 +++++++++++++++++++-------------------
include/linux/mtd/sh_flctl.h | 1 +
2 files changed, 20 insertions(+), 19 deletions(-)
diff --git a/drivers/mtd/nand/raw/sh_flctl.c b/drivers/mtd/nand/raw/sh_flctl.c
index c7abceffcc40..d37d1d3ccbf9 100644
--- a/drivers/mtd/nand/raw/sh_flctl.c
+++ b/drivers/mtd/nand/raw/sh_flctl.c
@@ -1007,6 +1007,16 @@ static int flctl_chip_init_tail(struct mtd_info *mtd)
struct sh_flctl *flctl = mtd_to_flctl(mtd);
struct nand_chip *chip = &flctl->chip;
+ if (chip->options & NAND_BUSWIDTH_16) {
+ /*
+ * NAND_BUSWIDTH_16 may have been set by nand_scan_ident().
+ * Add the SEL_16BIT flag in pdata->flcmncr_val and re-assign
+ * flctl->flcmncr_base to pdata->flcmncr_val.
+ */
+ flctl->pdata->flcmncr_val |= SEL_16BIT;
+ flctl->flcmncr_base = flctl->pdata->flcmncr_val;
+ }
+
if (mtd->writesize == 512) {
flctl->page_size = 0;
if (chip->chipsize > (32 << 20)) {
@@ -1122,7 +1132,6 @@ static int flctl_probe(struct platform_device *pdev)
struct sh_flctl *flctl;
struct mtd_info *flctl_mtd;
struct nand_chip *nand;
- struct sh_flctl_platform_data *pdata;
int ret;
int irq;
@@ -1150,11 +1159,11 @@ static int flctl_probe(struct platform_device *pdev)
}
if (pdev->dev.of_node)
- pdata = flctl_parse_dt(&pdev->dev);
+ flctl->pdata = flctl_parse_dt(&pdev->dev);
else
- pdata = dev_get_platdata(&pdev->dev);
+ flctl->pdata = dev_get_platdata(&pdev->dev);
- if (!pdata) {
+ if (!flctl->pdata) {
dev_err(&pdev->dev, "no setup data defined\n");
return -EINVAL;
}
@@ -1165,9 +1174,9 @@ static int flctl_probe(struct platform_device *pdev)
nand_set_flash_node(nand, pdev->dev.of_node);
flctl_mtd->dev.parent = &pdev->dev;
flctl->pdev = pdev;
- flctl->hwecc = pdata->has_hwecc;
- flctl->holden = pdata->use_holden;
- flctl->flcmncr_base = pdata->flcmncr_val;
+ flctl->hwecc = flctl->pdata->has_hwecc;
+ flctl->holden = flctl->pdata->use_holden;
+ flctl->flcmncr_base = flctl->pdata->flcmncr_val;
flctl->flintdmacr_base = flctl->hwecc ? (STERINTE | ECERB) : STERINTE;
/* Set address of hardware control function */
@@ -1183,7 +1192,7 @@ static int flctl_probe(struct platform_device *pdev)
nand->set_features = nand_get_set_features_notsupp;
nand->get_features = nand_get_set_features_notsupp;
- if (pdata->flcmncr_val & SEL_16BIT)
+ if (flctl->pdata->flcmncr_val & SEL_16BIT)
nand->options |= NAND_BUSWIDTH_16;
pm_runtime_enable(&pdev->dev);
@@ -1195,16 +1204,6 @@ static int flctl_probe(struct platform_device *pdev)
if (ret)
goto err_chip;
- if (nand->options & NAND_BUSWIDTH_16) {
- /*
- * NAND_BUSWIDTH_16 may have been set by nand_scan_ident().
- * Add the SEL_16BIT flag in pdata->flcmncr_val and re-assign
- * flctl->flcmncr_base to pdata->flcmncr_val.
- */
- pdata->flcmncr_val |= SEL_16BIT;
- flctl->flcmncr_base = pdata->flcmncr_val;
- }
-
ret = flctl_chip_init_tail(flctl_mtd);
if (ret)
goto err_chip;
@@ -1213,7 +1212,8 @@ static int flctl_probe(struct platform_device *pdev)
if (ret)
goto err_chip;
- ret = mtd_device_register(flctl_mtd, pdata->parts, pdata->nr_parts);
+ ret = mtd_device_register(flctl_mtd, flctl->pdata->parts,
+ flctl->pdata->nr_parts);
if (ret)
goto cleanup_nand;
diff --git a/include/linux/mtd/sh_flctl.h b/include/linux/mtd/sh_flctl.h
index c759d403cbc0..c9f486c6c019 100644
--- a/include/linux/mtd/sh_flctl.h
+++ b/include/linux/mtd/sh_flctl.h
@@ -148,6 +148,7 @@ struct sh_flctl {
struct dev_pm_qos_request pm_qos;
void __iomem *reg;
resource_size_t fifo;
+ struct sh_flctl_platform_data *pdata;
uint8_t done_buff[2048 + 64]; /* max size 2048 + 64 */
int read_bytes;
--
2.14.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH v2 21/32] mtd: rawnand: sh_flctl: convert driver to nand_scan()
2018-07-03 21:59 [PATCH v2 00/32] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
` (19 preceding siblings ...)
2018-07-03 22:00 ` [PATCH v2 20/32] mtd: rawnand: sh_flctl: move all NAND chip related setup in one function Miquel Raynal
@ 2018-07-03 22:00 ` Miquel Raynal
2018-07-03 22:00 ` [PATCH v2 22/32] mtd: rawnand: sunxi: " Miquel Raynal
` (10 subsequent siblings)
31 siblings, 0 replies; 35+ messages in thread
From: Miquel Raynal @ 2018-07-03 22:00 UTC (permalink / raw)
To: linux-arm-kernel
Two helpers have been added to the core to make ECC-related
configuration between the detection phase and the final NAND scan. Use
these hooks and convert the driver to just use nand_scan() instead of
both nand_scan_ident() and nand_scan_tail().
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
drivers/mtd/nand/raw/sh_flctl.c | 15 ++++-----------
1 file changed, 4 insertions(+), 11 deletions(-)
diff --git a/drivers/mtd/nand/raw/sh_flctl.c b/drivers/mtd/nand/raw/sh_flctl.c
index d37d1d3ccbf9..959eb6f5f269 100644
--- a/drivers/mtd/nand/raw/sh_flctl.c
+++ b/drivers/mtd/nand/raw/sh_flctl.c
@@ -1002,10 +1002,10 @@ static void flctl_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
flctl->index += len;
}
-static int flctl_chip_init_tail(struct mtd_info *mtd)
+static int flctl_chip_attach_chip(struct nand_chip *chip)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct sh_flctl *flctl = mtd_to_flctl(mtd);
- struct nand_chip *chip = &flctl->chip;
if (chip->options & NAND_BUSWIDTH_16) {
/*
@@ -1200,15 +1200,8 @@ static int flctl_probe(struct platform_device *pdev)
flctl_setup_dma(flctl);
- ret = nand_scan_ident(flctl_mtd, 1, NULL);
- if (ret)
- goto err_chip;
-
- ret = flctl_chip_init_tail(flctl_mtd);
- if (ret)
- goto err_chip;
-
- ret = nand_scan_tail(flctl_mtd);
+ nand->hwcontrol.attach_chip = flctl_chip_attach_chip;
+ ret = nand_scan(flctl_mtd, 1);
if (ret)
goto err_chip;
--
2.14.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH v2 22/32] mtd: rawnand: sunxi: convert driver to nand_scan()
2018-07-03 21:59 [PATCH v2 00/32] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
` (20 preceding siblings ...)
2018-07-03 22:00 ` [PATCH v2 21/32] mtd: rawnand: sh_flctl: convert driver to nand_scan() Miquel Raynal
@ 2018-07-03 22:00 ` Miquel Raynal
2018-07-03 22:00 ` [PATCH v2 23/32] mtd: rawnand: tango: " Miquel Raynal
` (9 subsequent siblings)
31 siblings, 0 replies; 35+ messages in thread
From: Miquel Raynal @ 2018-07-03 22:00 UTC (permalink / raw)
To: linux-arm-kernel
Two helpers have been added to the core to make ECC-related
configuration between the detection phase and the final NAND scan. Use
these hooks and convert the driver to just use nand_scan() instead of
both nand_scan_ident() and nand_scan_tail().
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
drivers/mtd/nand/raw/sunxi_nand.c | 38 ++++++++++++++------------------------
1 file changed, 14 insertions(+), 24 deletions(-)
diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi_nand.c
index d831a141a196..38bef2ad90a3 100644
--- a/drivers/mtd/nand/raw/sunxi_nand.c
+++ b/drivers/mtd/nand/raw/sunxi_nand.c
@@ -1816,12 +1816,21 @@ static void sunxi_nand_ecc_cleanup(struct nand_ecc_ctrl *ecc)
}
}
-static int sunxi_nand_ecc_init(struct mtd_info *mtd, struct nand_ecc_ctrl *ecc,
- struct device_node *np)
+static int sunxi_nand_attach_chip(struct nand_chip *nand)
{
- struct nand_chip *nand = mtd_to_nand(mtd);
+ struct mtd_info *mtd = nand_to_mtd(nand);
+ struct nand_ecc_ctrl *ecc = &nand->ecc;
+ struct device_node *np = nand_get_flash_node(nand);
int ret;
+ if (nand->bbt_options & NAND_BBT_USE_FLASH)
+ nand->bbt_options |= NAND_BBT_NO_OOB;
+
+ if (nand->options & NAND_NEED_SCRAMBLING)
+ nand->options |= NAND_NO_SUBPAGE_WRITE;
+
+ nand->options |= NAND_SUBPAGE_READ;
+
if (!ecc->size) {
ecc->size = nand->ecc_step_ds;
ecc->strength = nand->ecc_strength_ds;
@@ -1927,30 +1936,11 @@ static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
mtd = nand_to_mtd(nand);
mtd->dev.parent = dev;
- ret = nand_scan_ident(mtd, nsels, NULL);
+ nand->controller->attach_chip = sunxi_nand_attach_chip;
+ ret = nand_scan(mtd, nsels);
if (ret)
return ret;
- if (nand->bbt_options & NAND_BBT_USE_FLASH)
- nand->bbt_options |= NAND_BBT_NO_OOB;
-
- if (nand->options & NAND_NEED_SCRAMBLING)
- nand->options |= NAND_NO_SUBPAGE_WRITE;
-
- nand->options |= NAND_SUBPAGE_READ;
-
- ret = sunxi_nand_ecc_init(mtd, &nand->ecc, np);
- if (ret) {
- dev_err(dev, "ECC init failed: %d\n", ret);
- return ret;
- }
-
- ret = nand_scan_tail(mtd);
- if (ret) {
- dev_err(dev, "nand_scan_tail failed: %d\n", ret);
- return ret;
- }
-
ret = mtd_device_register(mtd, NULL, 0);
if (ret) {
dev_err(dev, "failed to register mtd device: %d\n", ret);
--
2.14.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH v2 23/32] mtd: rawnand: tango: convert driver to nand_scan()
2018-07-03 21:59 [PATCH v2 00/32] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
` (21 preceding siblings ...)
2018-07-03 22:00 ` [PATCH v2 22/32] mtd: rawnand: sunxi: " Miquel Raynal
@ 2018-07-03 22:00 ` Miquel Raynal
2018-07-03 22:00 ` [PATCH v2 24/32] mtd: rawnand: txx9ndfmc: " Miquel Raynal
` (8 subsequent siblings)
31 siblings, 0 replies; 35+ messages in thread
From: Miquel Raynal @ 2018-07-03 22:00 UTC (permalink / raw)
To: linux-arm-kernel
Two helpers have been added to the core to make ECC-related
configuration between the detection phase and the final NAND scan. Use
these hooks and convert the driver to just use nand_scan() instead of
both nand_scan_ident() and nand_scan_tail().
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
drivers/mtd/nand/raw/tango_nand.c | 36 ++++++++++++++++++++----------------
1 file changed, 20 insertions(+), 16 deletions(-)
diff --git a/drivers/mtd/nand/raw/tango_nand.c b/drivers/mtd/nand/raw/tango_nand.c
index f2052fae21c7..fb41e66e9b60 100644
--- a/drivers/mtd/nand/raw/tango_nand.c
+++ b/drivers/mtd/nand/raw/tango_nand.c
@@ -517,6 +517,24 @@ static int tango_set_timings(struct mtd_info *mtd, int csline,
return 0;
}
+static int tango_attach_chip(struct nand_chip *chip)
+{
+ struct nand_ecc_ctrl *ecc = &chip->ecc;
+
+ ecc->mode = NAND_ECC_HW;
+ ecc->algo = NAND_ECC_BCH;
+ ecc->bytes = DIV_ROUND_UP(ecc->strength * FIELD_ORDER, BITS_PER_BYTE);
+
+ ecc->read_page_raw = tango_read_page_raw;
+ ecc->write_page_raw = tango_write_page_raw;
+ ecc->read_page = tango_read_page;
+ ecc->write_page = tango_write_page;
+ ecc->read_oob = tango_read_oob;
+ ecc->write_oob = tango_write_oob;
+
+ return 0;
+}
+
static int chip_init(struct device *dev, struct device_node *np)
{
u32 cs;
@@ -566,22 +584,8 @@ static int chip_init(struct device *dev, struct device_node *np)
mtd_set_ooblayout(mtd, &tango_nand_ooblayout_ops);
mtd->dev.parent = dev;
- err = nand_scan_ident(mtd, 1, NULL);
- if (err)
- return err;
-
- ecc->mode = NAND_ECC_HW;
- ecc->algo = NAND_ECC_BCH;
- ecc->bytes = DIV_ROUND_UP(ecc->strength * FIELD_ORDER, BITS_PER_BYTE);
-
- ecc->read_page_raw = tango_read_page_raw;
- ecc->write_page_raw = tango_write_page_raw;
- ecc->read_page = tango_read_page;
- ecc->write_page = tango_write_page;
- ecc->read_oob = tango_read_oob;
- ecc->write_oob = tango_write_oob;
-
- err = nand_scan_tail(mtd);
+ chip->controller->attach_chip = tango_attach_chip;
+ err = nand_scan(mtd, 1);
if (err)
return err;
--
2.14.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH v2 24/32] mtd: rawnand: txx9ndfmc: convert driver to nand_scan()
2018-07-03 21:59 [PATCH v2 00/32] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
` (22 preceding siblings ...)
2018-07-03 22:00 ` [PATCH v2 23/32] mtd: rawnand: tango: " Miquel Raynal
@ 2018-07-03 22:00 ` Miquel Raynal
2018-07-03 22:00 ` [PATCH v2 25/32] mtd: rawnand: vf610: " Miquel Raynal
` (7 subsequent siblings)
31 siblings, 0 replies; 35+ messages in thread
From: Miquel Raynal @ 2018-07-03 22:00 UTC (permalink / raw)
To: linux-arm-kernel
Two helpers have been added to the core to make ECC-related
configuration between the detection phase and the final NAND scan. Use
these hooks and convert the driver to just use nand_scan() instead of
both nand_scan_ident() and nand_scan_tail().
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
drivers/mtd/nand/raw/txx9ndfmc.c | 25 +++++++++++--------------
1 file changed, 11 insertions(+), 14 deletions(-)
diff --git a/drivers/mtd/nand/raw/txx9ndfmc.c b/drivers/mtd/nand/raw/txx9ndfmc.c
index b567d212fe7d..cac22dda799e 100644
--- a/drivers/mtd/nand/raw/txx9ndfmc.c
+++ b/drivers/mtd/nand/raw/txx9ndfmc.c
@@ -254,21 +254,17 @@ static void txx9ndfmc_initialize(struct platform_device *dev)
#define TXX9NDFMC_NS_TO_CYC(gbusclk, ns) \
DIV_ROUND_UP((ns) * DIV_ROUND_UP(gbusclk, 1000), 1000000)
-static int txx9ndfmc_nand_scan(struct mtd_info *mtd)
+static int txx9ndfmc_attach_chip(struct nand_chip *chip)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
- int ret;
+ struct mtd_info *mtd = nand_to_mtd(chip);
- ret = nand_scan_ident(mtd, 1, NULL);
- if (!ret) {
- if (mtd->writesize >= 512) {
- /* Hardware ECC 6 byte ECC per 512 Byte data */
- chip->ecc.size = 512;
- chip->ecc.bytes = 6;
- }
- ret = nand_scan_tail(mtd);
+ if (mtd->writesize >= 512) {
+ /* Hardware ECC 6 byte ECC per 512 Byte data */
+ chip->ecc.size = 512;
+ chip->ecc.bytes = 6;
}
- return ret;
+
+ return 0;
}
static int __init txx9ndfmc_probe(struct platform_device *dev)
@@ -332,7 +328,7 @@ static int __init txx9ndfmc_probe(struct platform_device *dev)
chip->ecc.correct = txx9ndfmc_correct_data;
chip->ecc.hwctl = txx9ndfmc_enable_hwecc;
chip->ecc.mode = NAND_ECC_HW;
- /* txx9ndfmc_nand_scan will overwrite ecc.size and ecc.bytes */
+ /* nand_scan() will overwrite ecc.size and ecc.bytes */
chip->ecc.size = 256;
chip->ecc.bytes = 3;
chip->ecc.strength = 1;
@@ -359,7 +355,8 @@ static int __init txx9ndfmc_probe(struct platform_device *dev)
if (plat->wide_mask & (1 << i))
chip->options |= NAND_BUSWIDTH_16;
- if (txx9ndfmc_nand_scan(mtd)) {
+ chip->controller->attach_chip = txx9ndfmc_attach_chip;
+ if (nand_scan(mtd, 1)) {
kfree(txx9_priv->mtdname);
kfree(txx9_priv);
continue;
--
2.14.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH v2 25/32] mtd: rawnand: vf610: convert driver to nand_scan()
2018-07-03 21:59 [PATCH v2 00/32] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
` (23 preceding siblings ...)
2018-07-03 22:00 ` [PATCH v2 24/32] mtd: rawnand: txx9ndfmc: " Miquel Raynal
@ 2018-07-03 22:00 ` Miquel Raynal
2018-07-03 22:00 ` [PATCH v2 26/32] mtd: rawnand: atmel: " Miquel Raynal
` (6 subsequent siblings)
31 siblings, 0 replies; 35+ messages in thread
From: Miquel Raynal @ 2018-07-03 22:00 UTC (permalink / raw)
To: linux-arm-kernel
Two helpers have been added to the core to make ECC-related
configuration between the detection phase and the final NAND scan. Use
these hooks and convert the driver to just use nand_scan() instead of
both nand_scan_ident() and nand_scan_tail().
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
drivers/mtd/nand/raw/vf610_nfc.c | 123 ++++++++++++++++++++-------------------
1 file changed, 62 insertions(+), 61 deletions(-)
diff --git a/drivers/mtd/nand/raw/vf610_nfc.c b/drivers/mtd/nand/raw/vf610_nfc.c
index d5a22fc96878..150da1adbb8c 100644
--- a/drivers/mtd/nand/raw/vf610_nfc.c
+++ b/drivers/mtd/nand/raw/vf610_nfc.c
@@ -747,6 +747,65 @@ static void vf610_nfc_init_controller(struct vf610_nfc *nfc)
}
}
+static int vf610_nfc_attach_chip(struct nand_chip *chip)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ struct vf610_nfc *nfc = mtd_to_nfc(mtd);
+
+ vf610_nfc_init_controller(nfc);
+
+ /* Bad block options. */
+ if (chip->bbt_options & NAND_BBT_USE_FLASH)
+ chip->bbt_options |= NAND_BBT_NO_OOB;
+
+ /* Single buffer only, max 256 OOB minus ECC status */
+ if (mtd->writesize + mtd->oobsize > PAGE_2K + OOB_MAX - 8) {
+ dev_err(nfc->dev, "Unsupported flash page size\n");
+ return -ENXIO;
+ }
+
+ if (chip->ecc.mode != NAND_ECC_HW)
+ return 0;
+
+ if (mtd->writesize != PAGE_2K && mtd->oobsize < 64) {
+ dev_err(nfc->dev, "Unsupported flash with hwecc\n");
+ return -ENXIO;
+ }
+
+ if (chip->ecc.size != mtd->writesize) {
+ dev_err(nfc->dev, "Step size needs to be page size\n");
+ return -ENXIO;
+ }
+
+ /* Only 64 byte ECC layouts known */
+ if (mtd->oobsize > 64)
+ mtd->oobsize = 64;
+
+ /* Use default large page ECC layout defined in NAND core */
+ mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
+ if (chip->ecc.strength == 32) {
+ nfc->ecc_mode = ECC_60_BYTE;
+ chip->ecc.bytes = 60;
+ } else if (chip->ecc.strength == 24) {
+ nfc->ecc_mode = ECC_45_BYTE;
+ chip->ecc.bytes = 45;
+ } else {
+ dev_err(nfc->dev, "Unsupported ECC strength\n");
+ return -ENXIO;
+ }
+
+ chip->ecc.read_page = vf610_nfc_read_page;
+ chip->ecc.write_page = vf610_nfc_write_page;
+ chip->ecc.read_page_raw = vf610_nfc_read_page_raw;
+ chip->ecc.write_page_raw = vf610_nfc_write_page_raw;
+ chip->ecc.read_oob = vf610_nfc_read_oob;
+ chip->ecc.write_oob = vf610_nfc_write_oob;
+
+ chip->ecc.size = PAGE_2K;
+
+ return 0;
+}
+
static int vf610_nfc_probe(struct platform_device *pdev)
{
struct vf610_nfc *nfc;
@@ -827,67 +886,9 @@ static int vf610_nfc_probe(struct platform_device *pdev)
vf610_nfc_preinit_controller(nfc);
- /* first scan to find the device and get the page size */
- err = nand_scan_ident(mtd, 1, NULL);
- if (err)
- goto err_disable_clk;
-
- vf610_nfc_init_controller(nfc);
-
- /* Bad block options. */
- if (chip->bbt_options & NAND_BBT_USE_FLASH)
- chip->bbt_options |= NAND_BBT_NO_OOB;
-
- /* Single buffer only, max 256 OOB minus ECC status */
- if (mtd->writesize + mtd->oobsize > PAGE_2K + OOB_MAX - 8) {
- dev_err(nfc->dev, "Unsupported flash page size\n");
- err = -ENXIO;
- goto err_disable_clk;
- }
-
- if (chip->ecc.mode == NAND_ECC_HW) {
- if (mtd->writesize != PAGE_2K && mtd->oobsize < 64) {
- dev_err(nfc->dev, "Unsupported flash with hwecc\n");
- err = -ENXIO;
- goto err_disable_clk;
- }
-
- if (chip->ecc.size != mtd->writesize) {
- dev_err(nfc->dev, "Step size needs to be page size\n");
- err = -ENXIO;
- goto err_disable_clk;
- }
-
- /* Only 64 byte ECC layouts known */
- if (mtd->oobsize > 64)
- mtd->oobsize = 64;
-
- /* Use default large page ECC layout defined in NAND core */
- mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
- if (chip->ecc.strength == 32) {
- nfc->ecc_mode = ECC_60_BYTE;
- chip->ecc.bytes = 60;
- } else if (chip->ecc.strength == 24) {
- nfc->ecc_mode = ECC_45_BYTE;
- chip->ecc.bytes = 45;
- } else {
- dev_err(nfc->dev, "Unsupported ECC strength\n");
- err = -ENXIO;
- goto err_disable_clk;
- }
-
- chip->ecc.read_page = vf610_nfc_read_page;
- chip->ecc.write_page = vf610_nfc_write_page;
- chip->ecc.read_page_raw = vf610_nfc_read_page_raw;
- chip->ecc.write_page_raw = vf610_nfc_write_page_raw;
- chip->ecc.read_oob = vf610_nfc_read_oob;
- chip->ecc.write_oob = vf610_nfc_write_oob;
-
- chip->ecc.size = PAGE_2K;
- }
-
- /* second phase scan */
- err = nand_scan_tail(mtd);
+ /* Scan the NAND chip */
+ chip->hwcontrol.attach_chip = vf610_nfc_attach_chip;
+ err = nand_scan(mtd, 1);
if (err)
goto err_disable_clk;
--
2.14.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH v2 26/32] mtd: rawnand: atmel: convert driver to nand_scan()
2018-07-03 21:59 [PATCH v2 00/32] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
` (24 preceding siblings ...)
2018-07-03 22:00 ` [PATCH v2 25/32] mtd: rawnand: vf610: " Miquel Raynal
@ 2018-07-03 22:00 ` Miquel Raynal
2018-07-03 22:00 ` [PATCH v2 27/32] mtd: rawnand: sm_common: convert driver to nand_scan_with_ids() Miquel Raynal
` (5 subsequent siblings)
31 siblings, 0 replies; 35+ messages in thread
From: Miquel Raynal @ 2018-07-03 22:00 UTC (permalink / raw)
To: linux-arm-kernel
Two helpers have been added to the core to make ECC-related
configuration between the detection phase and the final NAND scan. Use
these hooks and convert the driver to just use nand_scan() instead of
both nand_scan_ident() and nand_scan_tail().
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
drivers/mtd/nand/raw/atmel/nand-controller.c | 70 +++++++++++-----------------
1 file changed, 27 insertions(+), 43 deletions(-)
diff --git a/drivers/mtd/nand/raw/atmel/nand-controller.c b/drivers/mtd/nand/raw/atmel/nand-controller.c
index e686fe73159e..0b5695b3c8c1 100644
--- a/drivers/mtd/nand/raw/atmel/nand-controller.c
+++ b/drivers/mtd/nand/raw/atmel/nand-controller.c
@@ -202,7 +202,7 @@ struct atmel_nand_controller_ops {
int (*remove)(struct atmel_nand_controller *nc);
void (*nand_init)(struct atmel_nand_controller *nc,
struct atmel_nand *nand);
- int (*ecc_init)(struct atmel_nand *nand);
+ int (*ecc_init)(struct nand_chip *chip);
int (*setup_data_interface)(struct atmel_nand *nand, int csline,
const struct nand_data_interface *conf);
};
@@ -1133,9 +1133,8 @@ static int atmel_nand_pmecc_init(struct nand_chip *chip)
return 0;
}
-static int atmel_nand_ecc_init(struct atmel_nand *nand)
+static int atmel_nand_ecc_init(struct nand_chip *chip)
{
- struct nand_chip *chip = &nand->base;
struct atmel_nand_controller *nc;
int ret;
@@ -1170,12 +1169,11 @@ static int atmel_nand_ecc_init(struct atmel_nand *nand)
return 0;
}
-static int atmel_hsmc_nand_ecc_init(struct atmel_nand *nand)
+static int atmel_hsmc_nand_ecc_init(struct nand_chip *chip)
{
- struct nand_chip *chip = &nand->base;
int ret;
- ret = atmel_nand_ecc_init(nand);
+ ret = atmel_nand_ecc_init(chip);
if (ret)
return ret;
@@ -1558,22 +1556,6 @@ static void atmel_hsmc_nand_init(struct atmel_nand_controller *nc,
chip->select_chip = atmel_hsmc_nand_select_chip;
}
-static int atmel_nand_detect(struct atmel_nand *nand)
-{
- struct nand_chip *chip = &nand->base;
- struct mtd_info *mtd = nand_to_mtd(chip);
- struct atmel_nand_controller *nc;
- int ret;
-
- nc = to_nand_controller(chip->controller);
-
- ret = nand_scan_ident(mtd, nand->numcs, NULL);
- if (ret)
- dev_err(nc->dev, "nand_scan_ident() failed: %d\n", ret);
-
- return ret;
-}
-
static int atmel_nand_unregister(struct atmel_nand *nand)
{
struct nand_chip *chip = &nand->base;
@@ -1595,7 +1577,6 @@ static int atmel_nand_register(struct atmel_nand *nand)
struct nand_chip *chip = &nand->base;
struct mtd_info *mtd = nand_to_mtd(chip);
struct atmel_nand_controller *nc;
- int ret;
nc = to_nand_controller(chip->controller);
@@ -1626,21 +1607,6 @@ static int atmel_nand_register(struct atmel_nand *nand)
}
}
- ret = nand_scan_tail(mtd);
- if (ret) {
- dev_err(nc->dev, "nand_scan_tail() failed: %d\n", ret);
- return ret;
- }
-
- ret = mtd_device_register(mtd, NULL, 0);
- if (ret) {
- dev_err(nc->dev, "Failed to register mtd device: %d\n", ret);
- nand_cleanup(chip);
- return ret;
- }
-
- list_add_tail(&nand->node, &nc->chips);
-
return 0;
}
@@ -1755,6 +1721,8 @@ static int
atmel_nand_controller_add_nand(struct atmel_nand_controller *nc,
struct atmel_nand *nand)
{
+ struct nand_chip *chip = &nand->base;
+ struct mtd_info *mtd = nand_to_mtd(chip);
int ret;
/* No card inserted, skip this NAND. */
@@ -1765,15 +1733,31 @@ atmel_nand_controller_add_nand(struct atmel_nand_controller *nc,
nc->caps->ops->nand_init(nc, nand);
- ret = atmel_nand_detect(nand);
- if (ret)
+ chip->controller->attach_chip = nc->caps->ops->ecc_init;
+ ret = nand_scan(mtd, nand->numcs);
+ if (ret) {
+ dev_err(nc->dev, "NAND scan failed: %d\n", ret);
return ret;
+ }
- ret = nc->caps->ops->ecc_init(nand);
+ ret = atmel_nand_register(nand);
if (ret)
- return ret;
+ goto cleanup_nand;
+
+ ret = mtd_device_register(mtd, NULL, 0);
+ if (ret) {
+ dev_err(nc->dev, "Failed to register mtd device: %d\n", ret);
+ goto cleanup_nand;
+ }
+
+ list_add_tail(&nand->node, &nc->chips);
+
+ return 0;
+
+cleanup_nand:
+ nand_cleanup(chip);
- return atmel_nand_register(nand);
+ return ret;
}
static int
--
2.14.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH v2 27/32] mtd: rawnand: sm_common: convert driver to nand_scan_with_ids()
2018-07-03 21:59 [PATCH v2 00/32] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
` (25 preceding siblings ...)
2018-07-03 22:00 ` [PATCH v2 26/32] mtd: rawnand: atmel: " Miquel Raynal
@ 2018-07-03 22:00 ` Miquel Raynal
2018-07-03 22:00 ` [PATCH v2 28/32] mtd: rawnand: docg4: convert driver to nand_scan() Miquel Raynal
` (4 subsequent siblings)
31 siblings, 0 replies; 35+ messages in thread
From: Miquel Raynal @ 2018-07-03 22:00 UTC (permalink / raw)
To: linux-arm-kernel
Two helpers have been added to the core to make ECC-related
configuration between the detection phase and the final NAND scan. Use
these hooks and convert the driver to just use nand_scan_with_ids()
(alternative to nand_scan() for passing a flash IDs table) instead of
both nand_scan_ident() and nand_scan_tail().
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
drivers/mtd/nand/raw/sm_common.c | 35 +++++++++++++++++++++--------------
1 file changed, 21 insertions(+), 14 deletions(-)
diff --git a/drivers/mtd/nand/raw/sm_common.c b/drivers/mtd/nand/raw/sm_common.c
index 7f5044a79f01..b8c9cc74b1c6 100644
--- a/drivers/mtd/nand/raw/sm_common.c
+++ b/drivers/mtd/nand/raw/sm_common.c
@@ -160,19 +160,9 @@ static struct nand_flash_dev nand_xd_flash_ids[] = {
{NULL}
};
-int sm_register_device(struct mtd_info *mtd, int smartmedia)
+static int sm_attach_chip(struct nand_chip *chip)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
- int ret;
-
- chip->options |= NAND_SKIP_BBTSCAN;
-
- /* Scan for card properties */
- ret = nand_scan_ident(mtd, 1, smartmedia ?
- nand_smartmedia_flash_ids : nand_xd_flash_ids);
-
- if (ret)
- return ret;
+ struct mtd_info *mtd = nand_to_mtd(chip);
/* Bad block marker position */
chip->badblockpos = 0x05;
@@ -187,12 +177,29 @@ int sm_register_device(struct mtd_info *mtd, int smartmedia)
else
return -ENODEV;
- ret = nand_scan_tail(mtd);
+ return 0;
+}
+int sm_register_device(struct mtd_info *mtd, int smartmedia)
+{
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct nand_flash_dev *flash_ids;
+ int ret;
+
+ chip->options |= NAND_SKIP_BBTSCAN;
+
+ /* Scan for card properties */
+ chip->hwcontrol.attach_chip = sm_attach_chip;
+ flash_ids = smartmedia ? nand_smartmedia_flash_ids : nand_xd_flash_ids;
+ ret = nand_scan_with_ids(mtd, 1, flash_ids);
if (ret)
return ret;
- return mtd_device_register(mtd, NULL, 0);
+ ret = mtd_device_register(mtd, NULL, 0);
+ if (ret)
+ nand_release(mtd);
+
+ return ret;
}
EXPORT_SYMBOL_GPL(sm_register_device);
--
2.14.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH v2 28/32] mtd: rawnand: docg4: convert driver to nand_scan()
2018-07-03 21:59 [PATCH v2 00/32] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
` (26 preceding siblings ...)
2018-07-03 22:00 ` [PATCH v2 27/32] mtd: rawnand: sm_common: convert driver to nand_scan_with_ids() Miquel Raynal
@ 2018-07-03 22:00 ` Miquel Raynal
2018-07-03 22:00 ` [PATCH v2 29/32] mtd: rawnand: qcom: " Miquel Raynal
` (3 subsequent siblings)
31 siblings, 0 replies; 35+ messages in thread
From: Miquel Raynal @ 2018-07-03 22:00 UTC (permalink / raw)
To: linux-arm-kernel
Two helpers have been added to the core to make ECC-related
configuration between the detection phase and the final NAND scan. Use
these hooks and convert the driver to just use nand_scan() instead of
both nand_scan_ident() and nand_scan_tail().
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
drivers/mtd/nand/raw/docg4.c | 51 ++++++++++++++++++++++++--------------------
1 file changed, 28 insertions(+), 23 deletions(-)
diff --git a/drivers/mtd/nand/raw/docg4.c b/drivers/mtd/nand/raw/docg4.c
index bb96cb33cd6b..50954c74e960 100644
--- a/drivers/mtd/nand/raw/docg4.c
+++ b/drivers/mtd/nand/raw/docg4.c
@@ -1227,10 +1227,9 @@ static void __init init_mtd_structs(struct mtd_info *mtd)
* required within a nand driver because they are performed by the nand
* infrastructure code as part of nand_scan(). In this case they need
* to be initialized here because we skip call to nand_scan_ident() (the
- * first half of nand_scan()). The call to nand_scan_ident() is skipped
- * because for this device the chip id is not read in the manner of a
- * standard nand device. Unfortunately, nand_scan_ident() does other
- * things as well, such as call nand_set_defaults().
+ * first half of nand_scan()). The call to nand_scan_ident() could be
+ * skipped because for this device the chip id is not read in the manner
+ * of a standard nand device.
*/
struct nand_chip *nand = mtd_to_nand(mtd);
@@ -1315,6 +1314,23 @@ static int __init read_id_reg(struct mtd_info *mtd)
static char const *part_probes[] = { "cmdlinepart", "saftlpart", NULL };
+static int docg4_attach_chip(struct nand_chip *chip)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ struct docg4_priv *doc = (struct docg4_priv *)(chip + 1);
+
+ init_mtd_structs(mtd);
+
+ /* Initialize kernel BCH algorithm */
+ doc->bch = init_bch(DOCG4_M, DOCG4_T, DOCG4_PRIMITIVE_POLY);
+ if (!doc->bch)
+ return -EINVAL;
+
+ reset(mtd);
+
+ return read_id_reg(mtd);
+}
+
static int __init probe_docg4(struct platform_device *pdev)
{
struct mtd_info *mtd;
@@ -1350,26 +1366,16 @@ static int __init probe_docg4(struct platform_device *pdev)
mtd->dev.parent = &pdev->dev;
doc->virtadr = virtadr;
doc->dev = dev;
-
- init_mtd_structs(mtd);
-
- /* initialize kernel bch algorithm */
- doc->bch = init_bch(DOCG4_M, DOCG4_T, DOCG4_PRIMITIVE_POLY);
- if (doc->bch == NULL) {
- retval = -EINVAL;
- goto free_nand;
- }
-
platform_set_drvdata(pdev, doc);
- reset(mtd);
- retval = read_id_reg(mtd);
- if (retval == -ENODEV) {
- dev_warn(dev, "No diskonchip G4 device found.\n");
- goto free_bch;
- }
-
- retval = nand_scan_tail(mtd);
+ /*
+ * Asking for 0 chips is useless here but it warns the user that the use
+ * of the nand_scan() function is a bit abused here because the
+ * initialization is actually a bit specific and re-handled again in the
+ * ->attach_chip() hook. It will probably leak some memory though.
+ */
+ nand->controller->attach_chip = docg4_attach_chip;
+ retval = nand_scan(mtd, 0);
if (retval)
goto free_bch;
@@ -1389,7 +1395,6 @@ static int __init probe_docg4(struct platform_device *pdev)
nand_cleanup(nand);
free_bch:
free_bch(doc->bch);
-free_nand:
kfree(nand);
unmap:
iounmap(virtadr);
--
2.14.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH v2 29/32] mtd: rawnand: qcom: convert driver to nand_scan()
2018-07-03 21:59 [PATCH v2 00/32] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
` (27 preceding siblings ...)
2018-07-03 22:00 ` [PATCH v2 28/32] mtd: rawnand: docg4: convert driver to nand_scan() Miquel Raynal
@ 2018-07-03 22:00 ` Miquel Raynal
2018-07-03 22:00 ` [PATCH v2 30/32] mtd: rawnand: jz4740: " Miquel Raynal
` (2 subsequent siblings)
31 siblings, 0 replies; 35+ messages in thread
From: Miquel Raynal @ 2018-07-03 22:00 UTC (permalink / raw)
To: linux-arm-kernel
Two helpers have been added to the core to make ECC-related
configuration between the detection phase and the final NAND scan. Use
these hooks and convert the driver to just use nand_scan() instead of
both nand_scan_ident() and nand_scan_tail().
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
drivers/mtd/nand/raw/qcom_nandc.c | 67 ++++++++++++---------------------------
1 file changed, 20 insertions(+), 47 deletions(-)
diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c
index 160acdff7d86..9407357ff77a 100644
--- a/drivers/mtd/nand/raw/qcom_nandc.c
+++ b/drivers/mtd/nand/raw/qcom_nandc.c
@@ -2423,10 +2423,10 @@ qcom_nandc_calc_ecc_bytes(int step_size, int strength)
NAND_ECC_CAPS_SINGLE(qcom_nandc_ecc_caps, qcom_nandc_calc_ecc_bytes,
NANDC_STEP_SIZE, 4, 8);
-static int qcom_nand_host_setup(struct qcom_nand_host *host)
+static int qcom_nand_attach_chip(struct nand_chip *chip)
{
- struct nand_chip *chip = &host->chip;
struct mtd_info *mtd = nand_to_mtd(chip);
+ struct qcom_nand_host *host = to_qcom_nand_host(chip);
struct nand_ecc_ctrl *ecc = &chip->ecc;
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
int cwperpage, bad_block_byte, ret;
@@ -2729,9 +2729,9 @@ static int qcom_nandc_setup(struct qcom_nand_controller *nandc)
return 0;
}
-static int qcom_nand_host_init(struct qcom_nand_controller *nandc,
- struct qcom_nand_host *host,
- struct device_node *dn)
+static int qcom_nand_host_init_and_register(struct qcom_nand_controller *nandc,
+ struct qcom_nand_host *host,
+ struct device_node *dn)
{
struct nand_chip *chip = &host->chip;
struct mtd_info *mtd = nand_to_mtd(chip);
@@ -2778,30 +2778,14 @@ static int qcom_nand_host_init(struct qcom_nand_controller *nandc,
/* set up initial status value */
host->status = NAND_STATUS_READY | NAND_STATUS_WP;
- ret = nand_scan_ident(mtd, 1, NULL);
- if (ret)
- return ret;
-
- ret = qcom_nand_host_setup(host);
-
- return ret;
-}
-
-static int qcom_nand_mtd_register(struct qcom_nand_controller *nandc,
- struct qcom_nand_host *host,
- struct device_node *dn)
-{
- struct nand_chip *chip = &host->chip;
- struct mtd_info *mtd = nand_to_mtd(chip);
- int ret;
-
- ret = nand_scan_tail(mtd);
+ chip->controller->attach_chip = qcom_nand_attach_chip;
+ ret = nand_scan(mtd, 1);
if (ret)
return ret;
ret = mtd_device_register(mtd, NULL, 0);
if (ret)
- nand_cleanup(mtd_to_nand(mtd));
+ nand_cleanup(chip);
return ret;
}
@@ -2810,9 +2794,19 @@ static int qcom_probe_nand_devices(struct qcom_nand_controller *nandc)
{
struct device *dev = nandc->dev;
struct device_node *dn = dev->of_node, *child;
- struct qcom_nand_host *host, *tmp;
+ struct qcom_nand_host *host;
int ret;
+ if (nandc->props->is_bam) {
+ free_bam_transaction(nandc);
+ nandc->bam_txn = alloc_bam_transaction(nandc);
+ if (!nandc->bam_txn) {
+ dev_err(nandc->dev,
+ "failed to allocate bam transaction\n");
+ return -ENOMEM;
+ }
+ }
+
for_each_available_child_of_node(dn, child) {
host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL);
if (!host) {
@@ -2820,7 +2814,7 @@ static int qcom_probe_nand_devices(struct qcom_nand_controller *nandc)
return -ENOMEM;
}
- ret = qcom_nand_host_init(nandc, host, child);
+ ret = qcom_nand_host_init_and_register(nandc, host, child);
if (ret) {
devm_kfree(dev, host);
continue;
@@ -2829,27 +2823,6 @@ static int qcom_probe_nand_devices(struct qcom_nand_controller *nandc)
list_add_tail(&host->node, &nandc->host_list);
}
- if (list_empty(&nandc->host_list))
- return -ENODEV;
-
- if (nandc->props->is_bam) {
- free_bam_transaction(nandc);
- nandc->bam_txn = alloc_bam_transaction(nandc);
- if (!nandc->bam_txn) {
- dev_err(nandc->dev,
- "failed to allocate bam transaction\n");
- return -ENOMEM;
- }
- }
-
- list_for_each_entry_safe(host, tmp, &nandc->host_list, node) {
- ret = qcom_nand_mtd_register(nandc, host, child);
- if (ret) {
- list_del(&host->node);
- devm_kfree(dev, host);
- }
- }
-
if (list_empty(&nandc->host_list))
return -ENODEV;
--
2.14.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH v2 30/32] mtd: rawnand: jz4740: convert driver to nand_scan()
2018-07-03 21:59 [PATCH v2 00/32] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
` (28 preceding siblings ...)
2018-07-03 22:00 ` [PATCH v2 29/32] mtd: rawnand: qcom: " Miquel Raynal
@ 2018-07-03 22:00 ` Miquel Raynal
2018-07-03 22:00 ` [PATCH v2 31/32] mtd: rawnand: do not export nand_scan_[ident|tail]() anymore Miquel Raynal
2018-07-03 22:00 ` [PATCH v2 32/32] mtd: rawnand: allocate dynamically ONFI parameters during detection Miquel Raynal
31 siblings, 0 replies; 35+ messages in thread
From: Miquel Raynal @ 2018-07-03 22:00 UTC (permalink / raw)
To: linux-arm-kernel
Two helpers have been added to the core to make ECC-related
configuration between the detection phase and the final NAND scan. Use
these hooks and convert the driver to just use nand_scan() instead of
both nand_scan_ident() and nand_scan_tail().
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
drivers/mtd/nand/raw/jz4740_nand.c | 42 +++++++++++++++++++++++---------------
1 file changed, 25 insertions(+), 17 deletions(-)
diff --git a/drivers/mtd/nand/raw/jz4740_nand.c b/drivers/mtd/nand/raw/jz4740_nand.c
index 613b00a9604b..2e95b618dc47 100644
--- a/drivers/mtd/nand/raw/jz4740_nand.c
+++ b/drivers/mtd/nand/raw/jz4740_nand.c
@@ -59,6 +59,7 @@
struct jz_nand {
struct nand_chip chip;
+ struct platform_device *pdev;
void __iomem *base;
struct resource *mem;
@@ -329,8 +330,8 @@ static int jz_nand_detect_bank(struct platform_device *pdev,
writel(ctrl, nand->base + JZ_REG_NAND_CTRL);
if (chipnr == 0) {
- /* Detect first chip. */
- ret = nand_scan_ident(mtd, 1, NULL);
+ /* Detect the first chip and register it */
+ ret = nand_scan(mtd, 1);
if (ret)
goto notfound_id;
@@ -367,6 +368,21 @@ static int jz_nand_detect_bank(struct platform_device *pdev,
return ret;
}
+static int jz_nand_attach_chip(struct nand_chip *chip)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ struct jz_nand *nand = mtd_to_jz_nand(mtd);
+ struct device *dev = mtd->dev.parent;
+ struct jz_nand_platform_data *pdata = dev_get_platdata(dev);
+
+ if (pdata && pdata->ident_callback) {
+ pdata->ident_callback(nand->pdev, mtd, &pdata->partitions,
+ &pdata->num_partitions);
+ }
+
+ return 0;
+}
+
static int jz_nand_probe(struct platform_device *pdev)
{
int ret;
@@ -397,6 +413,7 @@ static int jz_nand_probe(struct platform_device *pdev)
mtd = nand_to_mtd(chip);
mtd->dev.parent = &pdev->dev;
mtd->name = "jz4740-nand";
+ nand->pdev = pdev;
chip->ecc.hwctl = jz_nand_hwctl;
chip->ecc.calculate = jz_nand_calculate_ecc_rs;
@@ -410,6 +427,7 @@ static int jz_nand_probe(struct platform_device *pdev)
chip->chip_delay = 50;
chip->cmd_ctrl = jz_nand_cmd_ctrl;
chip->select_chip = jz_nand_select_chip;
+ chip->hwcontrol.attach_chip = jz_nand_attach_chip;
if (nand->busy_gpio)
chip->dev_ready = jz_nand_dev_ready;
@@ -450,20 +468,10 @@ static int jz_nand_probe(struct platform_device *pdev)
else
nand->banks[chipnr] = 0;
}
+
if (chipnr == 0) {
dev_err(&pdev->dev, "No NAND chips found\n");
- goto err_iounmap_mmio;
- }
-
- if (pdata && pdata->ident_callback) {
- pdata->ident_callback(pdev, mtd, &pdata->partitions,
- &pdata->num_partitions);
- }
-
- ret = nand_scan_tail(mtd);
- if (ret) {
- dev_err(&pdev->dev, "Failed to scan NAND\n");
- goto err_unclaim_banks;
+ goto err_nand_release;
}
ret = mtd_device_parse_register(mtd, NULL, NULL,
@@ -472,15 +480,13 @@ static int jz_nand_probe(struct platform_device *pdev)
if (ret) {
dev_err(&pdev->dev, "Failed to add mtd device\n");
- goto err_nand_release;
+ goto err_unclaim_banks;
}
dev_info(&pdev->dev, "Successfully registered JZ4740 NAND driver\n");
return 0;
-err_nand_release:
- nand_release(mtd);
err_unclaim_banks:
while (chipnr--) {
unsigned char bank = nand->banks[chipnr];
@@ -488,6 +494,8 @@ static int jz_nand_probe(struct platform_device *pdev)
nand->bank_base[bank - 1]);
}
writel(0, nand->base + JZ_REG_NAND_CTRL);
+err_nand_release:
+ nand_release(mtd);
err_iounmap_mmio:
jz_nand_iounmap_resource(nand->mem, nand->base);
err_free:
--
2.14.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH v2 31/32] mtd: rawnand: do not export nand_scan_[ident|tail]() anymore
2018-07-03 21:59 [PATCH v2 00/32] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
` (29 preceding siblings ...)
2018-07-03 22:00 ` [PATCH v2 30/32] mtd: rawnand: jz4740: " Miquel Raynal
@ 2018-07-03 22:00 ` Miquel Raynal
2018-07-03 22:00 ` [PATCH v2 32/32] mtd: rawnand: allocate dynamically ONFI parameters during detection Miquel Raynal
31 siblings, 0 replies; 35+ messages in thread
From: Miquel Raynal @ 2018-07-03 22:00 UTC (permalink / raw)
To: linux-arm-kernel
Both nand_scan_ident() and nand_scan_tail() helpers used to be called
directly from controller drivers that needed to tweak some ECC-related
parameters before nand_scan_tail(). This separation prevented dynamic
allocations during the phase of NAND identification, which was
inconvenient.
All controller drivers have been moved to use nand_scan(), in
conjunction with the chip->ecc.[attach|detach]_chip() hooks that
actually do the required tweaking sequence between both ident/tail
calls, allowing programmers to use dynamic allocation as they need all
across the scanning sequence.
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
drivers/mtd/nand/raw/nand_base.c | 59 ++++++++++++++++++++++++++++++++--------
include/linux/mtd/rawnand.h | 11 ++------
2 files changed, 50 insertions(+), 20 deletions(-)
diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
index 97a74d48b0cf..9b8777e325da 100644
--- a/drivers/mtd/nand/raw/nand_base.c
+++ b/drivers/mtd/nand/raw/nand_base.c
@@ -5120,6 +5120,7 @@ static int nand_flash_detect_onfi(struct nand_chip *chip)
{
struct mtd_info *mtd = nand_to_mtd(chip);
struct nand_onfi_params *p;
+ char *model;
char id[4];
int i, ret, val;
@@ -5194,8 +5195,15 @@ static int nand_flash_detect_onfi(struct nand_chip *chip)
sanitize_string(p->manufacturer, sizeof(p->manufacturer));
sanitize_string(p->model, sizeof(p->model));
- strncpy(chip->parameters.model, p->model,
- sizeof(chip->parameters.model) - 1);
+ model = kmemdup(p->model, sizeof(p->model), GFP_KERNEL);
+ if (!model) {
+ ret = -ENOMEM;
+ goto free_onfi_param_page;
+ }
+
+ chip->parameters.model = model;
+ if (!mtd->name)
+ mtd->name = chip->parameters.model;
mtd->writesize = le32_to_cpu(p->byte_per_page);
@@ -5275,6 +5283,7 @@ static int nand_flash_detect_jedec(struct nand_chip *chip)
struct nand_jedec_params *p;
struct jedec_ecc_info *ecc;
int jedec_version = 0;
+ char *model;
char id[5];
int i, val, ret;
@@ -5325,8 +5334,16 @@ static int nand_flash_detect_jedec(struct nand_chip *chip)
sanitize_string(p->manufacturer, sizeof(p->manufacturer));
sanitize_string(p->model, sizeof(p->model));
- strncpy(chip->parameters.model, p->model,
- sizeof(chip->parameters.model) - 1);
+ model = kzalloc(sizeof(p->model), GFP_KERNEL);
+ if (!p) {
+ ret = -ENOMEM;
+ goto free_jedec_param_page;
+ }
+
+ strncpy(model, p->model, sizeof(model) - 1);
+ chip->parameters.model = model;
+ if (!mtd->name)
+ mtd->name = chip->parameters.model;
mtd->writesize = le32_to_cpu(p->byte_per_page);
@@ -5893,7 +5910,7 @@ static int nand_dt_init(struct nand_chip *chip)
}
/**
- * nand_scan_ident - [NAND Interface] Scan for the NAND device
+ * nand_scan_ident - Scan for the NAND device
* @mtd: MTD device structure
* @maxchips: number of chips to scan for
* @table: alternative NAND ID table
@@ -5901,9 +5918,13 @@ static int nand_dt_init(struct nand_chip *chip)
* This is the first phase of the normal nand_scan() function. It reads the
* flash ID and sets up MTD fields accordingly.
*
+ * This helper used to be called directly from controller drivers that needed
+ * to tweak some ECC-related parameters before nand_scan_tail(). This separation
+ * prevented dynamic allocations during this phase which was unconvenient and
+ * as been banned for the benefit of the ->init_ecc()/cleanup_ecc() hooks.
*/
-int nand_scan_ident(struct mtd_info *mtd, int maxchips,
- struct nand_flash_dev *table)
+static int nand_scan_ident(struct mtd_info *mtd, int maxchips,
+ struct nand_flash_dev *table)
{
int i, nand_maf_id, nand_dev_id;
struct nand_chip *chip = mtd_to_nand(mtd);
@@ -5977,7 +5998,11 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
return 0;
}
-EXPORT_SYMBOL(nand_scan_ident);
+
+static void nand_scan_ident_cleanup(struct nand_chip *chip)
+{
+ kfree(chip->parameters.model);
+}
static int nand_set_ecc_soft_ops(struct mtd_info *mtd)
{
@@ -6354,14 +6379,14 @@ static bool nand_ecc_strength_good(struct mtd_info *mtd)
}
/**
- * nand_scan_tail - [NAND Interface] Scan for the NAND device
+ * nand_scan_tail - Scan for the NAND device
* @mtd: MTD device structure
*
* This is the second phase of the normal nand_scan() function. It fills out
* all the uninitialized function pointers with the defaults and scans for a
* bad block table if appropriate.
*/
-int nand_scan_tail(struct mtd_info *mtd)
+static int nand_scan_tail(struct mtd_info *mtd)
{
struct nand_chip *chip = mtd_to_nand(mtd);
struct nand_ecc_ctrl *ecc = &chip->ecc;
@@ -6685,7 +6710,6 @@ int nand_scan_tail(struct mtd_info *mtd)
return ret;
}
-EXPORT_SYMBOL(nand_scan_tail);
/*
* is_module_text_address() isn't exported, and it's mostly a pointless
@@ -6722,12 +6746,20 @@ int nand_scan_with_ids(struct mtd_info *mtd, int maxchips,
if (chip->controller->attach_chip) {
ret = chip->controller->attach_chip(chip);
if (ret)
- return ret;
+ goto cleanup_ident;
}
ret = nand_scan_tail(mtd);
+ if (ret)
+ goto detach_chip;
+
+ return 0;
+
+detach_chip:
if (ret && chip->controller->detach_chip)
chip->controller->detach_chip(chip);
+cleanup_ident:
+ nand_scan_ident_cleanup(chip);
return ret;
}
@@ -6760,6 +6792,9 @@ void nand_cleanup(struct nand_chip *chip)
/* Free controller specific allocations after chip identification */
if (chip->controller->detach_chip)
chip->controller->detach_chip(chip);
+
+ /* Free identification phase allocations */
+ nand_scan_ident_cleanup(chip);
}
EXPORT_SYMBOL_GPL(nand_cleanup);
diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h
index 81654211e520..61b8e9a7e870 100644
--- a/include/linux/mtd/rawnand.h
+++ b/include/linux/mtd/rawnand.h
@@ -37,14 +37,9 @@ static inline int nand_scan(struct mtd_info *mtd, int max_chips)
}
/*
- * Separate phases of nand_scan(), allowing board driver to intervene
- * and override command or ECC setup according to flash type.
+ * Unregister the MTD device and free resources held by the NAND device, must be
+ * called on error after a successful nand_scan().
*/
-int nand_scan_ident(struct mtd_info *mtd, int max_chips,
- struct nand_flash_dev *table);
-int nand_scan_tail(struct mtd_info *mtd);
-
-/* Unregister the MTD device and free resources held by the NAND device */
void nand_release(struct mtd_info *mtd);
/* Internal helper for board drivers which need to override command function */
@@ -488,7 +483,7 @@ struct onfi_params {
*/
struct nand_parameters {
/* Generic parameters */
- char model[100];
+ const char *model;
bool supports_set_get_features;
DECLARE_BITMAP(set_feature_list, ONFI_FEATURE_NUMBER);
DECLARE_BITMAP(get_feature_list, ONFI_FEATURE_NUMBER);
--
2.14.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH v2 32/32] mtd: rawnand: allocate dynamically ONFI parameters during detection
2018-07-03 21:59 [PATCH v2 00/32] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
` (30 preceding siblings ...)
2018-07-03 22:00 ` [PATCH v2 31/32] mtd: rawnand: do not export nand_scan_[ident|tail]() anymore Miquel Raynal
@ 2018-07-03 22:00 ` Miquel Raynal
31 siblings, 0 replies; 35+ messages in thread
From: Miquel Raynal @ 2018-07-03 22:00 UTC (permalink / raw)
To: linux-arm-kernel
Now that it is possible to do dynamic allocations during the
identification phase, convert the onfi_params structure (which is only
needed with ONFI compliant chips) into a pointer that will be allocated
only if needed.
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
drivers/mtd/nand/raw/nand_base.c | 54 +++++++++++++++++++++++--------------
drivers/mtd/nand/raw/nand_micron.c | 6 ++---
drivers/mtd/nand/raw/nand_timings.c | 12 ++++-----
include/linux/mtd/rawnand.h | 6 ++---
4 files changed, 46 insertions(+), 32 deletions(-)
diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
index 9b8777e325da..8fb1b74abb68 100644
--- a/drivers/mtd/nand/raw/nand_base.c
+++ b/drivers/mtd/nand/raw/nand_base.c
@@ -5120,6 +5120,8 @@ static int nand_flash_detect_onfi(struct nand_chip *chip)
{
struct mtd_info *mtd = nand_to_mtd(chip);
struct nand_onfi_params *p;
+ struct onfi_params *onfi;
+ int onfi_version = 0;
char *model;
char id[4];
int i, ret, val;
@@ -5176,21 +5178,19 @@ static int nand_flash_detect_onfi(struct nand_chip *chip)
/* Check version */
val = le16_to_cpu(p->revision);
if (val & ONFI_VERSION_2_3)
- chip->parameters.onfi.version = 23;
+ onfi_version = 23;
else if (val & ONFI_VERSION_2_2)
- chip->parameters.onfi.version = 22;
+ onfi_version = 22;
else if (val & ONFI_VERSION_2_1)
- chip->parameters.onfi.version = 21;
+ onfi_version = 21;
else if (val & ONFI_VERSION_2_0)
- chip->parameters.onfi.version = 20;
+ onfi_version = 20;
else if (val & ONFI_VERSION_1_0)
- chip->parameters.onfi.version = 10;
+ onfi_version = 10;
- if (!chip->parameters.onfi.version) {
+ if (!onfi_version) {
pr_info("unsupported ONFI version: %d\n", val);
goto free_onfi_param_page;
- } else {
- ret = 1;
}
sanitize_string(p->manufacturer, sizeof(p->manufacturer));
@@ -5231,7 +5231,7 @@ static int nand_flash_detect_onfi(struct nand_chip *chip)
if (p->ecc_bits != 0xff) {
chip->ecc_strength_ds = p->ecc_bits;
chip->ecc_step_ds = 512;
- } else if (chip->parameters.onfi.version >= 21 &&
+ } else if (onfi_version >= 21 &&
(le16_to_cpu(p->features) & ONFI_FEATURE_EXT_PARAM_PAGE)) {
/*
@@ -5258,19 +5258,32 @@ static int nand_flash_detect_onfi(struct nand_chip *chip)
bitmap_set(chip->parameters.set_feature_list,
ONFI_FEATURE_ADDR_TIMING_MODE, 1);
}
- chip->parameters.onfi.tPROG = le16_to_cpu(p->t_prog);
- chip->parameters.onfi.tBERS = le16_to_cpu(p->t_bers);
- chip->parameters.onfi.tR = le16_to_cpu(p->t_r);
- chip->parameters.onfi.tCCS = le16_to_cpu(p->t_ccs);
- chip->parameters.onfi.async_timing_mode =
- le16_to_cpu(p->async_timing_mode);
- chip->parameters.onfi.vendor_revision =
- le16_to_cpu(p->vendor_revision);
- memcpy(chip->parameters.onfi.vendor, p->vendor,
- sizeof(p->vendor));
+ onfi = kzalloc(sizeof(*onfi), GFP_KERNEL);
+ if (!onfi) {
+ ret = -ENOMEM;
+ goto free_model;
+ }
+ onfi->version = onfi_version;
+ onfi->tPROG = le16_to_cpu(p->t_prog);
+ onfi->tBERS = le16_to_cpu(p->t_bers);
+ onfi->tR = le16_to_cpu(p->t_r);
+ onfi->tCCS = le16_to_cpu(p->t_ccs);
+ onfi->async_timing_mode = le16_to_cpu(p->async_timing_mode);
+ onfi->vendor_revision = le16_to_cpu(p->vendor_revision);
+ memcpy(onfi->vendor, p->vendor, sizeof(p->vendor));
+ chip->parameters.onfi = onfi;
+
+ /* Identification done, free the full ONFI parameter page and exit */
+ kfree(p);
+
+ return 1;
+
+free_model:
+ kfree(model);
free_onfi_param_page:
kfree(p);
+
return ret;
}
@@ -5672,7 +5685,6 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type)
}
}
- chip->parameters.onfi.version = 0;
if (!type->name || !type->pagesize) {
/* Check if the chip is ONFI compliant */
ret = nand_flash_detect_onfi(chip);
@@ -6002,6 +6014,8 @@ static int nand_scan_ident(struct mtd_info *mtd, int maxchips,
static void nand_scan_ident_cleanup(struct nand_chip *chip)
{
kfree(chip->parameters.model);
+ kfree(chip->parameters.onfi);
+
}
static int nand_set_ecc_soft_ops(struct mtd_info *mtd)
diff --git a/drivers/mtd/nand/raw/nand_micron.c b/drivers/mtd/nand/raw/nand_micron.c
index 35fa6880a799..df92dd1f0427 100644
--- a/drivers/mtd/nand/raw/nand_micron.c
+++ b/drivers/mtd/nand/raw/nand_micron.c
@@ -77,9 +77,9 @@ static int micron_nand_setup_read_retry(struct mtd_info *mtd, int retry_mode)
static int micron_nand_onfi_init(struct nand_chip *chip)
{
struct nand_parameters *p = &chip->parameters;
- struct nand_onfi_vendor_micron *micron = (void *)p->onfi.vendor;
+ struct nand_onfi_vendor_micron *micron = (void *)p->onfi->vendor;
- if (chip->parameters.onfi.version && p->onfi.vendor_revision) {
+ if (p->onfi && p->onfi->vendor_revision) {
chip->read_retries = micron->read_retry_options;
chip->setup_read_retry = micron_nand_setup_read_retry;
}
@@ -283,7 +283,7 @@ static int micron_supports_on_die_ecc(struct nand_chip *chip)
if (chip->id.data[1] == micron_on_die_ecc[i])
return MICRON_ON_DIE_MANDATORY;
- if (!chip->parameters.onfi.version)
+ if (!chip->parameters.onfi)
return MICRON_ON_DIE_UNSUPPORTED;
if (chip->bits_per_cell != 1)
diff --git a/drivers/mtd/nand/raw/nand_timings.c b/drivers/mtd/nand/raw/nand_timings.c
index 7c4e4a371bbc..d113c05c26f9 100644
--- a/drivers/mtd/nand/raw/nand_timings.c
+++ b/drivers/mtd/nand/raw/nand_timings.c
@@ -292,6 +292,7 @@ int onfi_fill_data_interface(struct nand_chip *chip,
int timing_mode)
{
struct nand_data_interface *iface = &chip->data_interface;
+ struct onfi_params *onfi = chip->parameters.onfi;
if (type != NAND_SDR_IFACE)
return -EINVAL;
@@ -306,17 +307,16 @@ int onfi_fill_data_interface(struct nand_chip *chip,
* tR, tPROG, tCCS, ...
* These information are part of the ONFI parameter page.
*/
- if (chip->parameters.onfi.version) {
- struct nand_parameters *params = &chip->parameters;
+ if (onfi) {
struct nand_sdr_timings *timings = &iface->timings.sdr;
/* microseconds -> picoseconds */
- timings->tPROG_max = 1000000ULL * params->onfi.tPROG;
- timings->tBERS_max = 1000000ULL * params->onfi.tBERS;
- timings->tR_max = 1000000ULL * params->onfi.tR;
+ timings->tPROG_max = 1000000ULL * onfi->tPROG;
+ timings->tBERS_max = 1000000ULL * onfi->tBERS;
+ timings->tR_max = 1000000ULL * onfi->tR;
/* nanoseconds -> picoseconds */
- timings->tCCS_min = 1000UL * params->onfi.tCCS;
+ timings->tCCS_min = 1000UL * onfi->tCCS;
}
return 0;
diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h
index 61b8e9a7e870..bbbe26be5fd2 100644
--- a/include/linux/mtd/rawnand.h
+++ b/include/linux/mtd/rawnand.h
@@ -489,7 +489,7 @@ struct nand_parameters {
DECLARE_BITMAP(get_feature_list, ONFI_FEATURE_NUMBER);
/* ONFI parameters */
- struct onfi_params onfi;
+ struct onfi_params *onfi;
};
/* The maximum expected count of bytes in the NAND ID sequence */
@@ -1616,10 +1616,10 @@ struct platform_nand_data {
/* return the supported asynchronous timing mode. */
static inline int onfi_get_async_timing_mode(struct nand_chip *chip)
{
- if (!chip->parameters.onfi.version)
+ if (!chip->parameters.onfi)
return ONFI_TIMING_MODE_UNKNOWN;
- return chip->parameters.onfi.async_timing_mode;
+ return chip->parameters.onfi->async_timing_mode;
}
int onfi_fill_data_interface(struct nand_chip *chip,
--
2.14.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH v2 01/32] mtd: rawnand: add hooks that may be called during nand_scan()
2018-07-03 21:59 ` [PATCH v2 01/32] mtd: rawnand: add hooks that may be called during nand_scan() Miquel Raynal
@ 2018-07-04 7:09 ` Boris Brezillon
0 siblings, 0 replies; 35+ messages in thread
From: Boris Brezillon @ 2018-07-04 7:09 UTC (permalink / raw)
To: linux-arm-kernel
Hi Miquel,
On Tue, 3 Jul 2018 23:59:58 +0200
Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> In order to remove the limitation that forbids dynamic allocation in
> nand_scan_ident(), we must create a path that will be the same for all
> controller drivers. The idea is to use nand_scan() instead of the widely
> implemented nand_scan_ident()/nand_scan_tail() couple. In order to
> achieve this, controller drivers will need to adjust some parameters
> between these two functions depending on the NAND chip wired on them.
>
> For that, a hook called ->attach_chip() is created in the
> nand_hw_control structure. This structure may be referenced by two ways:
> 1/ if the driver does not implement its own controller, the
> chip->controller hook is not populated before nand_scan() so it
> cannot be dereferenced: use chip->hwcontrol instead (which is
> statically allocated and will be referenced later by chip->controller
> anyway).
> 2/ through chip->controller if the driver implements its own controller.
>
> Another hook, ->detach_chip() is also introduced in order to clean the
> controller driver's potential allocations in case of failure of
> nand_scan_tail(). There is no need for the controller driver to call the
> ->detach_chip() hook directly upon error after a successful nand_scan().
> In this situation, calling nand_release() as before is enough.
>
> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> ---
> drivers/mtd/nand/raw/nand_base.c | 21 +++++++++++++++++++--
> include/linux/mtd/rawnand.h | 6 ++++++
> 2 files changed, 25 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
> index faac82b1e058..97a74d48b0cf 100644
> --- a/drivers/mtd/nand/raw/nand_base.c
> +++ b/drivers/mtd/nand/raw/nand_base.c
> @@ -6712,11 +6712,23 @@ EXPORT_SYMBOL(nand_scan_tail);
> int nand_scan_with_ids(struct mtd_info *mtd, int maxchips,
> struct nand_flash_dev *ids)
> {
> + struct nand_chip *chip = mtd_to_nand(mtd);
> int ret;
>
> ret = nand_scan_ident(mtd, maxchips, ids);
> - if (!ret)
> - ret = nand_scan_tail(mtd);
> + if (ret)
> + return ret;
> +
> + if (chip->controller->attach_chip) {
> + ret = chip->controller->attach_chip(chip);
> + if (ret)
> + return ret;
> + }
> +
> + ret = nand_scan_tail(mtd);
> + if (ret && chip->controller->detach_chip)
> + chip->controller->detach_chip(chip);
> +
> return ret;
> }
> EXPORT_SYMBOL(nand_scan_with_ids);
> @@ -6744,7 +6756,12 @@ void nand_cleanup(struct nand_chip *chip)
>
> /* Free manufacturer priv data. */
> nand_manufacturer_cleanup(chip);
> +
> + /* Free controller specific allocations after chip identification */
> + if (chip->controller->detach_chip)
> + chip->controller->detach_chip(chip);
> }
> +
> EXPORT_SYMBOL_GPL(nand_cleanup);
>
> /**
> diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h
> index 0c6fb316b409..81654211e520 100644
> --- a/include/linux/mtd/rawnand.h
> +++ b/include/linux/mtd/rawnand.h
> @@ -517,11 +517,17 @@ struct nand_id {
> * @wq: wait queue to sleep on if a NAND operation is in
> * progress used instead of the per chip wait queue
> * when a hw controller is available.
> + * @attach_chip: Callback that may be called between nand_detect() and
> + * nand_scan_tail() during nand_scan() (optional).
> + * @detach_chip: Callback that may be called if nand_scan_tail() fails
> + * (optional).
> */
> struct nand_hw_control {
> spinlock_t lock;
> struct nand_chip *active;
> wait_queue_head_t wq;
> + int (*attach_chip)(struct nand_chip *chip);
> + void (*detach_chip)(struct nand_chip *chip);
> };
Can we instead declare a nand_controller_ops struct and then have
nand_hw_control point to it. Something like:
struct nand_controller_ops {
int (*attach_chip)(struct nand_chip *chip);
void (*detach_chip)(struct nand_chip *chip);
};
struct nand_hw_control {
...
const struct nand_controller_ops *ops;
};
>
> static inline void nand_hw_control_init(struct nand_hw_control *nfc)
Regards,
Boris
^ permalink raw reply [flat|nested] 35+ messages in thread
* [PATCH v2 02/32] mtd: rawnand: brcmnand: convert driver to nand_scan()
2018-07-03 21:59 ` [PATCH v2 02/32] mtd: rawnand: brcmnand: convert driver to nand_scan() Miquel Raynal
@ 2018-07-04 7:14 ` Boris Brezillon
0 siblings, 0 replies; 35+ messages in thread
From: Boris Brezillon @ 2018-07-04 7:14 UTC (permalink / raw)
To: linux-arm-kernel
On Tue, 3 Jul 2018 23:59:59 +0200
Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> Two helpers have been added to the core to make ECC-related
> configuration between the detection phase and the final NAND scan. Use
> these hooks and convert the driver to just use nand_scan() instead of
> both nand_scan_ident() and nand_scan_tail().
>
> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> ---
> drivers/mtd/nand/raw/brcmnand/brcmnand.c | 43 ++++++++++++++++++--------------
> 1 file changed, 24 insertions(+), 19 deletions(-)
>
> diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.c b/drivers/mtd/nand/raw/brcmnand/brcmnand.c
> index 1306aaa7a8bf..99ab7b93756c 100644
> --- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c
> +++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c
> @@ -2208,6 +2208,28 @@ static int brcmnand_setup_dev(struct brcmnand_host *host)
> return 0;
> }
>
> +static int brcmnand_attach_chip(struct nand_chip *chip)
> +{
> + struct mtd_info *mtd = nand_to_mtd(chip);
> + struct brcmnand_host *host = nand_get_controller_data(chip);
> + int ret;
> +
> + if (chip->bbt_options & NAND_BBT_USE_FLASH)
> + chip->bbt_options |= NAND_BBT_NO_OOB;
> +
> + if (brcmnand_setup_dev(host))
> + return -ENXIO;
> +
> + chip->ecc.size = host->hwcfg.sector_size_1k ? 1024 : 512;
> +
> + /* only use our internal HW threshold */
> + mtd->bitflip_threshold = 1;
> +
> + ret = brcmstb_choose_ecc_layout(host);
> +
> + return ret;
> +}
> +
> static int brcmnand_init_cs(struct brcmnand_host *host, struct device_node *dn)
> {
> struct brcmnand_controller *ctrl = host->ctrl;
> @@ -2267,10 +2289,6 @@ static int brcmnand_init_cs(struct brcmnand_host *host, struct device_node *dn)
> nand_writereg(ctrl, cfg_offs,
> nand_readreg(ctrl, cfg_offs) & ~CFG_BUS_WIDTH);
>
> - ret = nand_scan_ident(mtd, 1, NULL);
> - if (ret)
> - return ret;
> -
> chip->options |= NAND_NO_SUBPAGE_WRITE;
> /*
> * Avoid (for instance) kmap()'d buffers from JFFS2, which we can't DMA
> @@ -2279,21 +2297,8 @@ static int brcmnand_init_cs(struct brcmnand_host *host, struct device_node *dn)
> */
> chip->options |= NAND_USE_BOUNCE_BUFFER;
>
> - if (chip->bbt_options & NAND_BBT_USE_FLASH)
> - chip->bbt_options |= NAND_BBT_NO_OOB;
> -
> - if (brcmnand_setup_dev(host))
> - return -ENXIO;
> -
> - chip->ecc.size = host->hwcfg.sector_size_1k ? 1024 : 512;
> - /* only use our internal HW threshold */
> - mtd->bitflip_threshold = 1;
> -
> - ret = brcmstb_choose_ecc_layout(host);
> - if (ret)
> - return ret;
> -
> - ret = nand_scan_tail(mtd);
> + chip->controller->attach_chip = brcmnand_attach_chip;
Hm, this assignment should be done once, when initializing the
controller (in brcmnand_probe()), not every time you add a NAND chip.
> + ret = nand_scan(mtd, 1);
> if (ret)
> return ret;
>
^ permalink raw reply [flat|nested] 35+ messages in thread
end of thread, other threads:[~2018-07-04 7:14 UTC | newest]
Thread overview: 35+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2018-07-03 21:59 [PATCH v2 00/32] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
2018-07-03 21:59 ` [PATCH v2 01/32] mtd: rawnand: add hooks that may be called during nand_scan() Miquel Raynal
2018-07-04 7:09 ` Boris Brezillon
2018-07-03 21:59 ` [PATCH v2 02/32] mtd: rawnand: brcmnand: convert driver to nand_scan() Miquel Raynal
2018-07-04 7:14 ` Boris Brezillon
2018-07-03 22:00 ` [PATCH v2 03/32] mtd: rawnand: cafe: " Miquel Raynal
2018-07-03 22:00 ` [PATCH v2 04/32] mtd: rawnand: davinci: " Miquel Raynal
2018-07-03 22:00 ` [PATCH v2 05/32] mtd: rawnand: denali: convert " Miquel Raynal
2018-07-03 22:00 ` [PATCH v2 06/32] mtd: rawnand: fsl_elbc: convert driver " Miquel Raynal
2018-07-03 22:00 ` [PATCH v2 07/32] mtd: rawnand: fsl_ifc: " Miquel Raynal
2018-07-03 22:00 ` [PATCH v2 08/32] mtd: rawnand: fsmc: " Miquel Raynal
2018-07-03 22:00 ` [PATCH v2 09/32] mtd: rawnand: gpmi: " Miquel Raynal
2018-07-03 22:00 ` [PATCH v2 10/32] mtd: rawnand: hisi504: " Miquel Raynal
2018-07-03 22:00 ` [PATCH v2 11/32] mtd: rawnand: jz4780: " Miquel Raynal
2018-07-03 22:00 ` [PATCH v2 12/32] mtd: rawnand: lpc32xx_mlc: " Miquel Raynal
2018-07-03 22:00 ` [PATCH v2 13/32] mtd: rawnand: lpc32xx_slc: " Miquel Raynal
2018-07-03 22:00 ` [PATCH v2 14/32] mtd: rawnand: marvell: " Miquel Raynal
2018-07-03 22:00 ` [PATCH v2 15/32] mtd: rawnand: mtk: " Miquel Raynal
2018-07-03 22:00 ` [PATCH v2 16/32] mtd: rawnand: mxc: " Miquel Raynal
2018-07-03 22:00 ` [PATCH v2 17/32] mtd: rawnand: nandsim: " Miquel Raynal
2018-07-03 22:00 ` [PATCH v2 18/32] mtd: rawnand: omap2: " Miquel Raynal
2018-07-03 22:00 ` [PATCH v2 19/32] mtd: rawnand: s3c2410: " Miquel Raynal
2018-07-03 22:00 ` [PATCH v2 20/32] mtd: rawnand: sh_flctl: move all NAND chip related setup in one function Miquel Raynal
2018-07-03 22:00 ` [PATCH v2 21/32] mtd: rawnand: sh_flctl: convert driver to nand_scan() Miquel Raynal
2018-07-03 22:00 ` [PATCH v2 22/32] mtd: rawnand: sunxi: " Miquel Raynal
2018-07-03 22:00 ` [PATCH v2 23/32] mtd: rawnand: tango: " Miquel Raynal
2018-07-03 22:00 ` [PATCH v2 24/32] mtd: rawnand: txx9ndfmc: " Miquel Raynal
2018-07-03 22:00 ` [PATCH v2 25/32] mtd: rawnand: vf610: " Miquel Raynal
2018-07-03 22:00 ` [PATCH v2 26/32] mtd: rawnand: atmel: " Miquel Raynal
2018-07-03 22:00 ` [PATCH v2 27/32] mtd: rawnand: sm_common: convert driver to nand_scan_with_ids() Miquel Raynal
2018-07-03 22:00 ` [PATCH v2 28/32] mtd: rawnand: docg4: convert driver to nand_scan() Miquel Raynal
2018-07-03 22:00 ` [PATCH v2 29/32] mtd: rawnand: qcom: " Miquel Raynal
2018-07-03 22:00 ` [PATCH v2 30/32] mtd: rawnand: jz4740: " Miquel Raynal
2018-07-03 22:00 ` [PATCH v2 31/32] mtd: rawnand: do not export nand_scan_[ident|tail]() anymore Miquel Raynal
2018-07-03 22:00 ` [PATCH v2 32/32] mtd: rawnand: allocate dynamically ONFI parameters during detection Miquel Raynal
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).