Message ID | 20180725133152.30898-5-miquel.raynal@bootlin.com |
---|---|
State | Accepted |
Headers | show |
Series | Allow dynamic allocations during NAND chip identification phase | expand |
On Wed, 25 Jul 2018 15:31:39 +0200 Miquel Raynal <miquel.raynal@bootlin.com> wrote: > Two helpers have been added to the core to do all kind of controller > side configuration/initialization between the detection phase and the > final NAND scan. Implement these hooks so that we can convert the driver > to just use nand_scan() instead of the nand_scan_ident() + > nand_scan_tail() pair. > > Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com> Reviewed-by: Boris Brezillon <boris.brezillon@bootlin.com> > --- > drivers/mtd/nand/raw/omap2.c | 533 +++++++++++++++++++++---------------------- > 1 file changed, 265 insertions(+), 268 deletions(-) > > diff --git a/drivers/mtd/nand/raw/omap2.c b/drivers/mtd/nand/raw/omap2.c > index e943b2e5a5e2..4546ac0bed4a 100644 > --- a/drivers/mtd/nand/raw/omap2.c > +++ b/drivers/mtd/nand/raw/omap2.c > @@ -144,12 +144,6 @@ static u_char bch8_vector[] = {0xf3, 0xdb, 0x14, 0x16, 0x8b, 0xd2, 0xbe, 0xcc, > 0xac, 0x6b, 0xff, 0x99, 0x7b}; > static u_char bch4_vector[] = {0x00, 0x6b, 0x31, 0xdd, 0x41, 0xbc, 0x10}; > > -/* Shared among all NAND instances to synchronize access to the ECC Engine */ > -static struct nand_controller omap_gpmc_controller = { > - .lock = __SPIN_LOCK_UNLOCKED(omap_gpmc_controller.lock), > - .wq = __WAIT_QUEUE_HEAD_INITIALIZER(omap_gpmc_controller.wq), > -}; > - > struct omap_nand_info { > struct nand_chip nand; > struct platform_device *pdev; > @@ -1915,17 +1909,278 @@ 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 const struct nand_controller_ops omap_nand_controller_ops = { > + .attach_chip = omap_nand_attach_chip, > +}; > + > +/* Shared among all NAND instances to synchronize access to the ECC Engine */ > +static struct nand_controller omap_gpmc_controller = { > + .lock = __SPIN_LOCK_UNLOCKED(omap_gpmc_controller.lock), > + .wq = __WAIT_QUEUE_HEAD_INITIALIZER(omap_gpmc_controller.wq), > + .ops = &omap_nand_controller_ops, > +}; > + > 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 +2253,8 @@ 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); > + err = nand_scan(mtd, 1); > if (err) > goto return_error; >
Hello Miquel, Boris, On Wed, 25 Jul 2018 15:31:39 +0200 Miquel Raynal <miquel.raynal@bootlin.com> wrote: > Two helpers have been added to the core to do all kind of controller > side configuration/initialization between the detection phase and the > final NAND scan. Implement these hooks so that we can convert the driver > to just use nand_scan() instead of the nand_scan_ident() + > nand_scan_tail() pair. > > Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com> > Reviewed-by: Boris Brezillon <boris.brezillon@bootlin.com> I've bisected this patch to brake Beagle Bone Black boot (from NAND, at least in DMA mode): [ 0.243337] edma 49000000.edma: TI EDMA DMA engine driver ... skipped... [ 1.888170] omap-gpmc 50000000.gpmc: GPMC revision 6.0 [ 1.893597] gpmc_mem_init: disabling cs 0 mapped at 0x0-0x1000000 [ 1.901776] nand: device found, Manufacturer ID: 0x2c, Chip ID: 0xda [ 1.908589] nand: Micron MT29F2G08ABAEAWP [ 1.912807] nand: 256 MiB, SLC, erase size: 128 KiB, page size: 2048, OOB size: 64 [ 1.920802] omap2-nand 8000000.nand: DMA engine request failed ... unrelated... [ 1.985544] UBI error: cannot open mtd NAND.root-squashfs2, error -2 [ 1.992432] UBI error: cannot open mtd NAND.root-ubifs, error -2 [ 1.998897] UBI: block: can't open volume on ubi0_0, err=-19 ... unrelated... [ 2.025751] VFS: Cannot open root device "ubiblock0_0" or unknown-block(0,0): error -6 [ 2.034168] Please append a correct "root=" boot option; here are the available partitions: [ 2.042997] Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0) EDMA driver is here, yet the channel cannot be obtained after commit e1e6255c31. > --- > drivers/mtd/nand/raw/omap2.c | 533 +++++++++++++++++++++---------------------- > 1 file changed, 265 insertions(+), 268 deletions(-) > > diff --git a/drivers/mtd/nand/raw/omap2.c b/drivers/mtd/nand/raw/omap2.c > index e943b2e5a5e2..4546ac0bed4a 100644 > --- a/drivers/mtd/nand/raw/omap2.c > +++ b/drivers/mtd/nand/raw/omap2.c > @@ -144,12 +144,6 @@ static u_char bch8_vector[] = {0xf3, 0xdb, 0x14, 0x16, 0x8b, 0xd2, 0xbe, 0xcc, > 0xac, 0x6b, 0xff, 0x99, 0x7b}; > static u_char bch4_vector[] = {0x00, 0x6b, 0x31, 0xdd, 0x41, 0xbc, 0x10}; > > -/* Shared among all NAND instances to synchronize access to the ECC Engine */ > -static struct nand_controller omap_gpmc_controller = { > - .lock = __SPIN_LOCK_UNLOCKED(omap_gpmc_controller.lock), > - .wq = __WAIT_QUEUE_HEAD_INITIALIZER(omap_gpmc_controller.wq), > -}; > - > struct omap_nand_info { > struct nand_chip nand; > struct platform_device *pdev; > @@ -1915,17 +1909,278 @@ 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 const struct nand_controller_ops omap_nand_controller_ops = { > + .attach_chip = omap_nand_attach_chip, > +}; > + > +/* Shared among all NAND instances to synchronize access to the ECC Engine */ > +static struct nand_controller omap_gpmc_controller = { > + .lock = __SPIN_LOCK_UNLOCKED(omap_gpmc_controller.lock), > + .wq = __WAIT_QUEUE_HEAD_INITIALIZER(omap_gpmc_controller.wq), > + .ops = &omap_nand_controller_ops, > +}; > + > 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 +2253,8 @@ 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); > + err = nand_scan(mtd, 1); > if (err) > goto return_error; >
On Thu, 13 Dec 2018 19:01:11 +0100 Alexander Sverdlin <alexander.sverdlin@gmail.com> wrote: > Hello Miquel, Boris, > > On Wed, 25 Jul 2018 15:31:39 +0200 > Miquel Raynal <miquel.raynal@bootlin.com> wrote: > > > Two helpers have been added to the core to do all kind of controller > > side configuration/initialization between the detection phase and the > > final NAND scan. Implement these hooks so that we can convert the driver > > to just use nand_scan() instead of the nand_scan_ident() + > > nand_scan_tail() pair. > > > > Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com> > > Reviewed-by: Boris Brezillon <boris.brezillon@bootlin.com> > > I've bisected this patch to brake Beagle Bone Black boot > (from NAND, at least in DMA mode): > > [ 0.243337] edma 49000000.edma: TI EDMA DMA engine driver > > ... skipped... > > [ 1.888170] omap-gpmc 50000000.gpmc: GPMC revision 6.0 > [ 1.893597] gpmc_mem_init: disabling cs 0 mapped at 0x0-0x1000000 > [ 1.901776] nand: device found, Manufacturer ID: 0x2c, Chip ID: 0xda > [ 1.908589] nand: Micron MT29F2G08ABAEAWP > [ 1.912807] nand: 256 MiB, SLC, erase size: 128 KiB, page size: 2048, OOB size: 64 > [ 1.920802] omap2-nand 8000000.nand: DMA engine request failed > > ... unrelated... > > [ 1.985544] UBI error: cannot open mtd NAND.root-squashfs2, error -2 > [ 1.992432] UBI error: cannot open mtd NAND.root-ubifs, error -2 > [ 1.998897] UBI: block: can't open volume on ubi0_0, err=-19 > > ... unrelated... > > [ 2.025751] VFS: Cannot open root device "ubiblock0_0" or unknown-block(0,0): error -6 > [ 2.034168] Please append a correct "root=" boot option; here are the available partitions: > [ 2.042997] Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0) > > EDMA driver is here, yet the channel cannot be obtained after > commit e1e6255c31. Can you provide the full logs before and after this commit?
On Thu, 13 Dec 2018 19:01:11 +0100 Alexander Sverdlin <alexander.sverdlin@gmail.com> wrote: > > + /* 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"); Can you print the error code here?
On Thu, 13 Dec 2018 19:01:11 +0100 Alexander Sverdlin <alexander.sverdlin@gmail.com> wrote: > > +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"); > > + Can you try with info->dma = dma_request_chan(dev->parent, "rxtx"); ?
diff --git a/drivers/mtd/nand/raw/omap2.c b/drivers/mtd/nand/raw/omap2.c index e943b2e5a5e2..4546ac0bed4a 100644 --- a/drivers/mtd/nand/raw/omap2.c +++ b/drivers/mtd/nand/raw/omap2.c @@ -144,12 +144,6 @@ static u_char bch8_vector[] = {0xf3, 0xdb, 0x14, 0x16, 0x8b, 0xd2, 0xbe, 0xcc, 0xac, 0x6b, 0xff, 0x99, 0x7b}; static u_char bch4_vector[] = {0x00, 0x6b, 0x31, 0xdd, 0x41, 0xbc, 0x10}; -/* Shared among all NAND instances to synchronize access to the ECC Engine */ -static struct nand_controller omap_gpmc_controller = { - .lock = __SPIN_LOCK_UNLOCKED(omap_gpmc_controller.lock), - .wq = __WAIT_QUEUE_HEAD_INITIALIZER(omap_gpmc_controller.wq), -}; - struct omap_nand_info { struct nand_chip nand; struct platform_device *pdev; @@ -1915,17 +1909,278 @@ 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 const struct nand_controller_ops omap_nand_controller_ops = { + .attach_chip = omap_nand_attach_chip, +}; + +/* Shared among all NAND instances to synchronize access to the ECC Engine */ +static struct nand_controller omap_gpmc_controller = { + .lock = __SPIN_LOCK_UNLOCKED(omap_gpmc_controller.lock), + .wq = __WAIT_QUEUE_HEAD_INITIALIZER(omap_gpmc_controller.wq), + .ops = &omap_nand_controller_ops, +}; + 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 +2253,8 @@ 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); + err = nand_scan(mtd, 1); if (err) goto return_error;
Two helpers have been added to the core to do all kind of controller side configuration/initialization between the detection phase and the final NAND scan. Implement these hooks so that we can convert the driver to just use nand_scan() instead of the nand_scan_ident() + nand_scan_tail() pair. Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com> --- drivers/mtd/nand/raw/omap2.c | 533 +++++++++++++++++++++---------------------- 1 file changed, 265 insertions(+), 268 deletions(-)