Commit c1fe77e4 authored by Miquel Raynal's avatar Miquel Raynal

Merge tag 'nand/for-5.15' into mtd/next

NAND core changes:
* Repair Miquel Raynal's email address in MAINTAINERS
* Fix a couple of spelling mistakes in Kconfig
* bbt: Skip bad blocks when searching for the BBT in NAND
* Remove never changed ret variable

Raw NAND changes:
* cafe: Fix a resource leak in the error handling path of 'cafe_nand_probe()'
* intel: Fix error handling in probe
* omap: Fix kernel doc warning on 'calcuate' typo
* gpmc: Fix the ECC bytes vs. OOB bytes equation

SPI-NAND core changes:
* Properly fill the OOB area.
* Fix comment

SPI-NAND drivers changes:
* macronix: Add Quad support for serial NAND flash
parents ee28b420 6b430c75
...@@ -122,7 +122,7 @@ on various other factors also like; ...@@ -122,7 +122,7 @@ on various other factors also like;
so the device should have enough free bytes available its OOB/Spare so the device should have enough free bytes available its OOB/Spare
area to accommodate ECC for entire page. In general following expression area to accommodate ECC for entire page. In general following expression
helps in determining if given device can accommodate ECC syndrome: helps in determining if given device can accommodate ECC syndrome:
"2 + (PAGESIZE / 512) * ECC_BYTES" >= OOBSIZE" "2 + (PAGESIZE / 512) * ECC_BYTES" <= OOBSIZE"
where where
OOBSIZE number of bytes in OOB/spare area OOBSIZE number of bytes in OOB/spare area
PAGESIZE number of bytes in main-area of device page PAGESIZE number of bytes in main-area of device page
......
...@@ -1475,7 +1475,7 @@ F: drivers/amba/ ...@@ -1475,7 +1475,7 @@ F: drivers/amba/
F: include/linux/amba/bus.h F: include/linux/amba/bus.h
ARM PRIMECELL PL35X NAND CONTROLLER DRIVER ARM PRIMECELL PL35X NAND CONTROLLER DRIVER
M: Miquel Raynal <miquel.raynal@bootlin.com@bootlin.com> M: Miquel Raynal <miquel.raynal@bootlin.com>
M: Naga Sureshkumar Relli <nagasure@xilinx.com> M: Naga Sureshkumar Relli <nagasure@xilinx.com>
L: linux-mtd@lists.infradead.org L: linux-mtd@lists.infradead.org
S: Maintained S: Maintained
...@@ -1483,7 +1483,7 @@ F: Documentation/devicetree/bindings/mtd/arm,pl353-nand-r2p1.yaml ...@@ -1483,7 +1483,7 @@ F: Documentation/devicetree/bindings/mtd/arm,pl353-nand-r2p1.yaml
F: drivers/mtd/nand/raw/pl35x-nand-controller.c F: drivers/mtd/nand/raw/pl35x-nand-controller.c
ARM PRIMECELL PL35X SMC DRIVER ARM PRIMECELL PL35X SMC DRIVER
M: Miquel Raynal <miquel.raynal@bootlin.com@bootlin.com> M: Miquel Raynal <miquel.raynal@bootlin.com>
M: Naga Sureshkumar Relli <nagasure@xilinx.com> M: Naga Sureshkumar Relli <nagasure@xilinx.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained S: Maintained
......
...@@ -480,9 +480,9 @@ config MTD_NAND_RICOH ...@@ -480,9 +480,9 @@ config MTD_NAND_RICOH
select MTD_SM_COMMON select MTD_SM_COMMON
help help
Enable support for Ricoh R5C852 xD card reader Enable support for Ricoh R5C852 xD card reader
You also need to enable ether You also need to enable either
NAND SSFDC (SmartMedia) read only translation layer' or new NAND SSFDC (SmartMedia) read only translation layer' or new
expermental, readwrite experimental, readwrite
'SmartMedia/xD new translation layer' 'SmartMedia/xD new translation layer'
config MTD_NAND_DISKONCHIP config MTD_NAND_DISKONCHIP
......
...@@ -751,7 +751,7 @@ static int cafe_nand_probe(struct pci_dev *pdev, ...@@ -751,7 +751,7 @@ static int cafe_nand_probe(struct pci_dev *pdev,
"CAFE NAND", mtd); "CAFE NAND", mtd);
if (err) { if (err) {
dev_warn(&pdev->dev, "Could not register IRQ %d\n", pdev->irq); dev_warn(&pdev->dev, "Could not register IRQ %d\n", pdev->irq);
goto out_ior; goto out_free_rs;
} }
/* Disable master reset, enable NAND clock */ /* Disable master reset, enable NAND clock */
...@@ -795,6 +795,8 @@ static int cafe_nand_probe(struct pci_dev *pdev, ...@@ -795,6 +795,8 @@ static int cafe_nand_probe(struct pci_dev *pdev,
/* Disable NAND IRQ in global IRQ mask register */ /* Disable NAND IRQ in global IRQ mask register */
cafe_writel(cafe, ~1 & cafe_readl(cafe, GLOBAL_IRQ_MASK), GLOBAL_IRQ_MASK); cafe_writel(cafe, ~1 & cafe_readl(cafe, GLOBAL_IRQ_MASK), GLOBAL_IRQ_MASK);
free_irq(pdev->irq, mtd); free_irq(pdev->irq, mtd);
out_free_rs:
free_rs(cafe->rs);
out_ior: out_ior:
pci_iounmap(pdev, cafe->mmio); pci_iounmap(pdev, cafe->mmio);
out_free_mtd: out_free_mtd:
......
...@@ -631,19 +631,26 @@ static int ebu_nand_probe(struct platform_device *pdev) ...@@ -631,19 +631,26 @@ static int ebu_nand_probe(struct platform_device *pdev)
ebu_host->clk_rate = clk_get_rate(ebu_host->clk); ebu_host->clk_rate = clk_get_rate(ebu_host->clk);
ebu_host->dma_tx = dma_request_chan(dev, "tx"); ebu_host->dma_tx = dma_request_chan(dev, "tx");
if (IS_ERR(ebu_host->dma_tx)) if (IS_ERR(ebu_host->dma_tx)) {
return dev_err_probe(dev, PTR_ERR(ebu_host->dma_tx), ret = dev_err_probe(dev, PTR_ERR(ebu_host->dma_tx),
"failed to request DMA tx chan!.\n"); "failed to request DMA tx chan!.\n");
goto err_disable_unprepare_clk;
}
ebu_host->dma_rx = dma_request_chan(dev, "rx"); ebu_host->dma_rx = dma_request_chan(dev, "rx");
if (IS_ERR(ebu_host->dma_rx)) if (IS_ERR(ebu_host->dma_rx)) {
return dev_err_probe(dev, PTR_ERR(ebu_host->dma_rx), ret = dev_err_probe(dev, PTR_ERR(ebu_host->dma_rx),
"failed to request DMA rx chan!.\n"); "failed to request DMA rx chan!.\n");
ebu_host->dma_rx = NULL;
goto err_cleanup_dma;
}
resname = devm_kasprintf(dev, GFP_KERNEL, "addr_sel%d", cs); resname = devm_kasprintf(dev, GFP_KERNEL, "addr_sel%d", cs);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, resname); res = platform_get_resource_byname(pdev, IORESOURCE_MEM, resname);
if (!res) if (!res) {
return -EINVAL; ret = -EINVAL;
goto err_cleanup_dma;
}
ebu_host->cs[cs].addr_sel = res->start; ebu_host->cs[cs].addr_sel = res->start;
writel(ebu_host->cs[cs].addr_sel | EBU_ADDR_MASK(5) | EBU_ADDR_SEL_REGEN, writel(ebu_host->cs[cs].addr_sel | EBU_ADDR_MASK(5) | EBU_ADDR_SEL_REGEN,
ebu_host->ebu + EBU_ADDR_SEL(cs)); ebu_host->ebu + EBU_ADDR_SEL(cs));
...@@ -653,7 +660,8 @@ static int ebu_nand_probe(struct platform_device *pdev) ...@@ -653,7 +660,8 @@ static int ebu_nand_probe(struct platform_device *pdev)
mtd = nand_to_mtd(&ebu_host->chip); mtd = nand_to_mtd(&ebu_host->chip);
if (!mtd->name) { if (!mtd->name) {
dev_err(ebu_host->dev, "NAND label property is mandatory\n"); dev_err(ebu_host->dev, "NAND label property is mandatory\n");
return -EINVAL; ret = -EINVAL;
goto err_cleanup_dma;
} }
mtd->dev.parent = dev; mtd->dev.parent = dev;
...@@ -681,6 +689,7 @@ static int ebu_nand_probe(struct platform_device *pdev) ...@@ -681,6 +689,7 @@ static int ebu_nand_probe(struct platform_device *pdev)
nand_cleanup(&ebu_host->chip); nand_cleanup(&ebu_host->chip);
err_cleanup_dma: err_cleanup_dma:
ebu_dma_cleanup(ebu_host); ebu_dma_cleanup(ebu_host);
err_disable_unprepare_clk:
clk_disable_unprepare(ebu_host->clk); clk_disable_unprepare(ebu_host->clk);
return ret; return ret;
......
...@@ -580,7 +580,7 @@ static int meson_nfc_rw_cmd_prepare_and_execute(struct nand_chip *nand, ...@@ -580,7 +580,7 @@ static int meson_nfc_rw_cmd_prepare_and_execute(struct nand_chip *nand,
u32 *addrs = nfc->cmdfifo.rw.addrs; u32 *addrs = nfc->cmdfifo.rw.addrs;
u32 cs = nfc->param.chip_select; u32 cs = nfc->param.chip_select;
u32 cmd0, cmd_num, row_start; u32 cmd0, cmd_num, row_start;
int ret = 0, i; int i;
cmd_num = sizeof(struct nand_rw_cmd) / sizeof(int); cmd_num = sizeof(struct nand_rw_cmd) / sizeof(int);
...@@ -620,7 +620,7 @@ static int meson_nfc_rw_cmd_prepare_and_execute(struct nand_chip *nand, ...@@ -620,7 +620,7 @@ static int meson_nfc_rw_cmd_prepare_and_execute(struct nand_chip *nand,
meson_nfc_cmd_idle(nfc, nfc->timing.tadl); meson_nfc_cmd_idle(nfc, nfc->timing.tadl);
} }
return ret; return 0;
} }
static int meson_nfc_write_page_sub(struct nand_chip *nand, static int meson_nfc_write_page_sub(struct nand_chip *nand,
......
...@@ -447,6 +447,35 @@ static int scan_block_fast(struct nand_chip *this, struct nand_bbt_descr *bd, ...@@ -447,6 +447,35 @@ static int scan_block_fast(struct nand_chip *this, struct nand_bbt_descr *bd,
return 0; return 0;
} }
/* Check if a potential BBT block is marked as bad */
static int bbt_block_checkbad(struct nand_chip *this, struct nand_bbt_descr *td,
loff_t offs, uint8_t *buf)
{
struct nand_bbt_descr *bd = this->badblock_pattern;
/*
* No need to check for a bad BBT block if the BBM area overlaps with
* the bad block table marker area in OOB since writing a BBM here
* invalidates the bad block table marker anyway.
*/
if (!(td->options & NAND_BBT_NO_OOB) &&
td->offs >= bd->offs && td->offs < bd->offs + bd->len)
return 0;
/*
* There is no point in checking for a bad block marker if writing
* such marker is not supported
*/
if (this->bbt_options & NAND_BBT_NO_OOB_BBM ||
this->options & NAND_NO_BBM_QUIRK)
return 0;
if (scan_block_fast(this, bd, offs, buf) > 0)
return 1;
return 0;
}
/** /**
* create_bbt - [GENERIC] Create a bad block table by scanning the device * create_bbt - [GENERIC] Create a bad block table by scanning the device
* @this: NAND chip object * @this: NAND chip object
...@@ -560,6 +589,10 @@ static int search_bbt(struct nand_chip *this, uint8_t *buf, ...@@ -560,6 +589,10 @@ static int search_bbt(struct nand_chip *this, uint8_t *buf,
int actblock = startblock + dir * block; int actblock = startblock + dir * block;
loff_t offs = (loff_t)actblock << this->bbt_erase_shift; loff_t offs = (loff_t)actblock << this->bbt_erase_shift;
/* Check if block is marked bad */
if (bbt_block_checkbad(this, td, offs, buf))
continue;
/* Read first page */ /* Read first page */
scan_read(this, buf, offs, mtd->writesize, td); scan_read(this, buf, offs, mtd->writesize, td);
if (!check_pattern(buf, scanlen, mtd->writesize, td)) { if (!check_pattern(buf, scanlen, mtd->writesize, td)) {
......
...@@ -911,7 +911,7 @@ static int omap_correct_data(struct nand_chip *chip, u_char *dat, ...@@ -911,7 +911,7 @@ static int omap_correct_data(struct nand_chip *chip, u_char *dat,
} }
/** /**
* omap_calcuate_ecc - Generate non-inverted ECC bytes. * omap_calculate_ecc - Generate non-inverted ECC bytes.
* @chip: NAND chip object * @chip: NAND chip object
* @dat: The pointer to data on which ecc is computed * @dat: The pointer to data on which ecc is computed
* @ecc_code: The ecc_code buffer * @ecc_code: The ecc_code buffer
......
...@@ -288,6 +288,8 @@ static int spinand_ondie_ecc_prepare_io_req(struct nand_device *nand, ...@@ -288,6 +288,8 @@ static int spinand_ondie_ecc_prepare_io_req(struct nand_device *nand,
struct spinand_device *spinand = nand_to_spinand(nand); struct spinand_device *spinand = nand_to_spinand(nand);
bool enable = (req->mode != MTD_OPS_RAW); bool enable = (req->mode != MTD_OPS_RAW);
memset(spinand->oobbuf, 0xff, nanddev_per_page_oobsize(nand));
/* Only enable or disable the engine */ /* Only enable or disable the engine */
return spinand_ecc_enable(spinand, enable); return spinand_ecc_enable(spinand, enable);
} }
...@@ -307,7 +309,7 @@ static int spinand_ondie_ecc_finish_io_req(struct nand_device *nand, ...@@ -307,7 +309,7 @@ static int spinand_ondie_ecc_finish_io_req(struct nand_device *nand,
if (req->type == NAND_PAGE_WRITE) if (req->type == NAND_PAGE_WRITE)
return 0; return 0;
/* Finish a page write: check the status, report errors/bitflips */ /* Finish a page read: check the status, report errors/bitflips */
ret = spinand_check_ecc_status(spinand, engine_conf->status); ret = spinand_check_ecc_status(spinand, engine_conf->status);
if (ret == -EBADMSG) if (ret == -EBADMSG)
mtd->ecc_stats.failed++; mtd->ecc_stats.failed++;
......
...@@ -126,7 +126,7 @@ static const struct spinand_info macronix_spinand_table[] = { ...@@ -126,7 +126,7 @@ static const struct spinand_info macronix_spinand_table[] = {
SPINAND_INFO_OP_VARIANTS(&read_cache_variants, SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants, &write_cache_variants,
&update_cache_variants), &update_cache_variants),
0, SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
mx35lf1ge4ab_ecc_get_status)), mx35lf1ge4ab_ecc_get_status)),
SPINAND_INFO("MX35LF4GE4AD", SPINAND_INFO("MX35LF4GE4AD",
...@@ -136,7 +136,7 @@ static const struct spinand_info macronix_spinand_table[] = { ...@@ -136,7 +136,7 @@ static const struct spinand_info macronix_spinand_table[] = {
SPINAND_INFO_OP_VARIANTS(&read_cache_variants, SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants, &write_cache_variants,
&update_cache_variants), &update_cache_variants),
0, SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
mx35lf1ge4ab_ecc_get_status)), mx35lf1ge4ab_ecc_get_status)),
SPINAND_INFO("MX35LF1G24AD", SPINAND_INFO("MX35LF1G24AD",
...@@ -146,16 +146,16 @@ static const struct spinand_info macronix_spinand_table[] = { ...@@ -146,16 +146,16 @@ static const struct spinand_info macronix_spinand_table[] = {
SPINAND_INFO_OP_VARIANTS(&read_cache_variants, SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants, &write_cache_variants,
&update_cache_variants), &update_cache_variants),
0, SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)), SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)),
SPINAND_INFO("MX35LF2G24AD", SPINAND_INFO("MX35LF2G24AD",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x24), SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x24),
NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 2, 1, 1),
NAND_ECCREQ(8, 512), NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants, SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants, &write_cache_variants,
&update_cache_variants), &update_cache_variants),
0, SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)), SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)),
SPINAND_INFO("MX35LF4G24AD", SPINAND_INFO("MX35LF4G24AD",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x35), SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x35),
...@@ -164,7 +164,7 @@ static const struct spinand_info macronix_spinand_table[] = { ...@@ -164,7 +164,7 @@ static const struct spinand_info macronix_spinand_table[] = {
SPINAND_INFO_OP_VARIANTS(&read_cache_variants, SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants, &write_cache_variants,
&update_cache_variants), &update_cache_variants),
0, SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)), SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)),
SPINAND_INFO("MX31LF1GE4BC", SPINAND_INFO("MX31LF1GE4BC",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x1e), SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x1e),
...@@ -173,7 +173,7 @@ static const struct spinand_info macronix_spinand_table[] = { ...@@ -173,7 +173,7 @@ static const struct spinand_info macronix_spinand_table[] = {
SPINAND_INFO_OP_VARIANTS(&read_cache_variants, SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants, &write_cache_variants,
&update_cache_variants), &update_cache_variants),
0 /*SPINAND_HAS_QE_BIT*/, SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
mx35lf1ge4ab_ecc_get_status)), mx35lf1ge4ab_ecc_get_status)),
SPINAND_INFO("MX31UF1GE4BC", SPINAND_INFO("MX31UF1GE4BC",
...@@ -183,7 +183,7 @@ static const struct spinand_info macronix_spinand_table[] = { ...@@ -183,7 +183,7 @@ static const struct spinand_info macronix_spinand_table[] = {
SPINAND_INFO_OP_VARIANTS(&read_cache_variants, SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants, &write_cache_variants,
&update_cache_variants), &update_cache_variants),
0 /*SPINAND_HAS_QE_BIT*/, SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
mx35lf1ge4ab_ecc_get_status)), mx35lf1ge4ab_ecc_get_status)),
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment