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
This commit is contained in:
@@ -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/
|
|||||||
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
|
|||||||
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
|
|||||||
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,
|
|||||||
"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,
|
|||||||
/* 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)
|
|||||||
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)
|
|||||||
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 @@ err_clean_nand:
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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,
|
|||||||
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,
|
|||||||
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[] = {
|
|||||||
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[] = {
|
|||||||
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[] = {
|
|||||||
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[] = {
|
|||||||
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[] = {
|
|||||||
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[] = {
|
|||||||
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)),
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user