diff options
Diffstat (limited to 'drivers')
43 files changed, 3348 insertions, 522 deletions
diff --git a/drivers/memory/fsl_ifc.c b/drivers/memory/fsl_ifc.c index acd1460cf787..2a691da8c1c7 100644 --- a/drivers/memory/fsl_ifc.c +++ b/drivers/memory/fsl_ifc.c @@ -260,7 +260,7 @@ static int fsl_ifc_ctrl_probe(struct platform_device *dev) /* get the Controller level irq */ fsl_ifc_ctrl_dev->irq = irq_of_parse_and_map(dev->dev.of_node, 0); - if (fsl_ifc_ctrl_dev->irq == NO_IRQ) { + if (fsl_ifc_ctrl_dev->irq == 0) { dev_err(&dev->dev, "failed to get irq resource " "for IFC\n"); ret = -ENODEV; diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index 42cc953309f1..e83a279f1217 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig @@ -142,7 +142,7 @@ config MTD_AR7_PARTS config MTD_BCM63XX_PARTS tristate "BCM63XX CFE partitioning support" - depends on BCM63XX + depends on BCM63XX || BMIPS_GENERIC || COMPILE_TEST select CRC32 help This provides partions parsing for BCM63xx devices with CFE diff --git a/drivers/mtd/bcm47xxpart.c b/drivers/mtd/bcm47xxpart.c index 8282f47bcf5d..845dd27d9f41 100644 --- a/drivers/mtd/bcm47xxpart.c +++ b/drivers/mtd/bcm47xxpart.c @@ -66,11 +66,13 @@ static const char *bcm47xxpart_trx_data_part_name(struct mtd_info *master, { uint32_t buf; size_t bytes_read; + int err; - if (mtd_read(master, offset, sizeof(buf), &bytes_read, - (uint8_t *)&buf) < 0) { - pr_err("mtd_read error while parsing (offset: 0x%X)!\n", - offset); + err = mtd_read(master, offset, sizeof(buf), &bytes_read, + (uint8_t *)&buf); + if (err && !mtd_is_bitflip(err)) { + pr_err("mtd_read error while parsing (offset: 0x%X): %d\n", + offset, err); goto out_default; } @@ -95,6 +97,7 @@ static int bcm47xxpart_parse(struct mtd_info *master, int trx_part = -1; int last_trx_part = -1; int possible_nvram_sizes[] = { 0x8000, 0xF000, 0x10000, }; + int err; /* * Some really old flashes (like AT45DB*) had smaller erasesize-s, but @@ -118,8 +121,8 @@ static int bcm47xxpart_parse(struct mtd_info *master, /* Parse block by block looking for magics */ for (offset = 0; offset <= master->size - blocksize; offset += blocksize) { - /* Nothing more in higher memory */ - if (offset >= 0x2000000) + /* Nothing more in higher memory on BCM47XX (MIPS) */ + if (config_enabled(CONFIG_BCM47XX) && offset >= 0x2000000) break; if (curr_part >= BCM47XXPART_MAX_PARTS) { @@ -128,10 +131,11 @@ static int bcm47xxpart_parse(struct mtd_info *master, } /* Read beginning of the block */ - if (mtd_read(master, offset, BCM47XXPART_BYTES_TO_READ, - &bytes_read, (uint8_t *)buf) < 0) { - pr_err("mtd_read error while parsing (offset: 0x%X)!\n", - offset); + err = mtd_read(master, offset, BCM47XXPART_BYTES_TO_READ, + &bytes_read, (uint8_t *)buf); + if (err && !mtd_is_bitflip(err)) { + pr_err("mtd_read error while parsing (offset: 0x%X): %d\n", + offset, err); continue; } @@ -254,10 +258,11 @@ static int bcm47xxpart_parse(struct mtd_info *master, } /* Read middle of the block */ - if (mtd_read(master, offset + 0x8000, 0x4, - &bytes_read, (uint8_t *)buf) < 0) { - pr_err("mtd_read error while parsing (offset: 0x%X)!\n", - offset); + err = mtd_read(master, offset + 0x8000, 0x4, &bytes_read, + (uint8_t *)buf); + if (err && !mtd_is_bitflip(err)) { + pr_err("mtd_read error while parsing (offset: 0x%X): %d\n", + offset, err); continue; } @@ -277,10 +282,11 @@ static int bcm47xxpart_parse(struct mtd_info *master, } offset = master->size - possible_nvram_sizes[i]; - if (mtd_read(master, offset, 0x4, &bytes_read, - (uint8_t *)buf) < 0) { - pr_err("mtd_read error while reading at offset 0x%X!\n", - offset); + err = mtd_read(master, offset, 0x4, &bytes_read, + (uint8_t *)buf); + if (err && !mtd_is_bitflip(err)) { + pr_err("mtd_read error while reading (offset 0x%X): %d\n", + offset, err); continue; } diff --git a/drivers/mtd/bcm63xxpart.c b/drivers/mtd/bcm63xxpart.c index cec3188a170d..41d1d3149c61 100644 --- a/drivers/mtd/bcm63xxpart.c +++ b/drivers/mtd/bcm63xxpart.c @@ -24,6 +24,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include <linux/bcm963xx_nvram.h> #include <linux/bcm963xx_tag.h> #include <linux/crc32.h> #include <linux/module.h> @@ -34,12 +35,15 @@ #include <linux/mtd/mtd.h> #include <linux/mtd/partitions.h> -#include <asm/mach-bcm63xx/bcm63xx_nvram.h> -#include <asm/mach-bcm63xx/board_bcm963xx.h> +#define BCM963XX_CFE_BLOCK_SIZE SZ_64K /* always at least 64KiB */ -#define BCM63XX_CFE_BLOCK_SIZE SZ_64K /* always at least 64KiB */ +#define BCM963XX_CFE_MAGIC_OFFSET 0x4e0 +#define BCM963XX_CFE_VERSION_OFFSET 0x570 +#define BCM963XX_NVRAM_OFFSET 0x580 -#define BCM63XX_CFE_MAGIC_OFFSET 0x4e0 +/* Ensure strings read from flash structs are null terminated */ +#define STR_NULL_TERMINATE(x) \ + do { char *_str = (x); _str[sizeof(x) - 1] = 0; } while (0) static int bcm63xx_detect_cfe(struct mtd_info *master) { @@ -58,68 +62,130 @@ static int bcm63xx_detect_cfe(struct mtd_info *master) return 0; /* very old CFE's do not have the cfe-v string, so check for magic */ - ret = mtd_read(master, BCM63XX_CFE_MAGIC_OFFSET, 8, &retlen, + ret = mtd_read(master, BCM963XX_CFE_MAGIC_OFFSET, 8, &retlen, (void *)buf); buf[retlen] = 0; return strncmp("CFE1CFE1", buf, 8); } -static int bcm63xx_parse_cfe_partitions(struct mtd_info *master, - const struct mtd_partition **pparts, - struct mtd_part_parser_data *data) +static int bcm63xx_read_nvram(struct mtd_info *master, + struct bcm963xx_nvram *nvram) +{ + u32 actual_crc, expected_crc; + size_t retlen; + int ret; + + /* extract nvram data */ + ret = mtd_read(master, BCM963XX_NVRAM_OFFSET, BCM963XX_NVRAM_V5_SIZE, + &retlen, (void *)nvram); + if (ret) + return ret; + + ret = bcm963xx_nvram_checksum(nvram, &expected_crc, &actual_crc); + if (ret) + pr_warn("nvram checksum failed, contents may be invalid (expected %08x, got %08x)\n", + expected_crc, actual_crc); + + if (!nvram->psi_size) + nvram->psi_size = BCM963XX_DEFAULT_PSI_SIZE; + + return 0; +} + +static int bcm63xx_read_image_tag(struct mtd_info *master, const char *name, + loff_t tag_offset, struct bcm_tag *buf) +{ + int ret; + size_t retlen; + u32 computed_crc; + + ret = mtd_read(master, tag_offset, sizeof(*buf), &retlen, (void *)buf); + if (ret) + return ret; + + if (retlen != sizeof(*buf)) + return -EIO; + + computed_crc = crc32_le(IMAGETAG_CRC_START, (u8 *)buf, + offsetof(struct bcm_tag, header_crc)); + if (computed_crc == buf->header_crc) { + STR_NULL_TERMINATE(buf->board_id); + STR_NULL_TERMINATE(buf->tag_version); + + pr_info("%s: CFE image tag found at 0x%llx with version %s, board type %s\n", + name, tag_offset, buf->tag_version, buf->board_id); + + return 0; + } + + pr_warn("%s: CFE image tag at 0x%llx CRC invalid (expected %08x, actual %08x)\n", + name, tag_offset, buf->header_crc, computed_crc); + return 1; +} + +static int bcm63xx_parse_cfe_nor_partitions(struct mtd_info *master, + const struct mtd_partition **pparts, struct bcm963xx_nvram *nvram) { /* CFE, NVRAM and global Linux are always present */ int nrparts = 3, curpart = 0; - struct bcm_tag *buf; + struct bcm_tag *buf = NULL; struct mtd_partition *parts; int ret; - size_t retlen; unsigned int rootfsaddr, kerneladdr, spareaddr; unsigned int rootfslen, kernellen, sparelen, totallen; unsigned int cfelen, nvramlen; unsigned int cfe_erasesize; int i; - u32 computed_crc; bool rootfs_first = false; - if (bcm63xx_detect_cfe(master)) - return -EINVAL; - cfe_erasesize = max_t(uint32_t, master->erasesize, - BCM63XX_CFE_BLOCK_SIZE); + BCM963XX_CFE_BLOCK_SIZE); cfelen = cfe_erasesize; - nvramlen = bcm63xx_nvram_get_psi_size() * SZ_1K; + nvramlen = nvram->psi_size * SZ_1K; nvramlen = roundup(nvramlen, cfe_erasesize); - /* Allocate memory for buffer */ buf = vmalloc(sizeof(struct bcm_tag)); if (!buf) return -ENOMEM; /* Get the tag */ - ret = mtd_read(master, cfelen, sizeof(struct bcm_tag), &retlen, - (void *)buf); - - if (retlen != sizeof(struct bcm_tag)) { - vfree(buf); - return -EIO; - } + ret = bcm63xx_read_image_tag(master, "rootfs", cfelen, buf); + if (!ret) { + STR_NULL_TERMINATE(buf->flash_image_start); + if (kstrtouint(buf->flash_image_start, 10, &rootfsaddr) || + rootfsaddr < BCM963XX_EXTENDED_SIZE) { + pr_err("invalid rootfs address: %*ph\n", + (int)sizeof(buf->flash_image_start), + buf->flash_image_start); + goto invalid_tag; + } - computed_crc = crc32_le(IMAGETAG_CRC_START, (u8 *)buf, - offsetof(struct bcm_tag, header_crc)); - if (computed_crc == buf->header_crc) { - char *boardid = &(buf->board_id[0]); - char *tagversion = &(buf->tag_version[0]); + STR_NULL_TERMINATE(buf->kernel_address); + if (kstrtouint(buf->kernel_address, 10, &kerneladdr) || + kerneladdr < BCM963XX_EXTENDED_SIZE) { + pr_err("invalid kernel address: %*ph\n", + (int)sizeof(buf->kernel_address), + buf->kernel_address); + goto invalid_tag; + } - sscanf(buf->flash_image_start, "%u", &rootfsaddr); - sscanf(buf->kernel_address, "%u", &kerneladdr); - sscanf(buf->kernel_length, "%u", &kernellen); - sscanf(buf->total_length, "%u", &totallen); + STR_NULL_TERMINATE(buf->kernel_length); + if (kstrtouint(buf->kernel_length, 10, &kernellen)) { + pr_err("invalid kernel length: %*ph\n", + (int)sizeof(buf->kernel_length), + buf->kernel_length); + goto invalid_tag; + } - pr_info("CFE boot tag found with version %s and board type %s\n", - tagversion, boardid); + STR_NULL_TERMINATE(buf->total_length); + if (kstrtouint(buf->total_length, 10, &totallen)) { + pr_err("invalid total length: %*ph\n", + (int)sizeof(buf->total_length), + buf->total_length); + goto invalid_tag; + } kerneladdr = kerneladdr - BCM963XX_EXTENDED_SIZE; rootfsaddr = rootfsaddr - BCM963XX_EXTENDED_SIZE; @@ -134,13 +200,14 @@ static int bcm63xx_parse_cfe_partitions(struct mtd_info *master, rootfsaddr = kerneladdr + kernellen; rootfslen = spareaddr - rootfsaddr; } - } else { - pr_warn("CFE boot tag CRC invalid (expected %08x, actual %08x)\n", - buf->header_crc, computed_crc); + } else if (ret > 0) { +invalid_tag: kernellen = 0; rootfslen = 0; rootfsaddr = 0; spareaddr = cfelen; + } else { + goto out; } sparelen = master->size - spareaddr - nvramlen; @@ -151,11 +218,10 @@ static int bcm63xx_parse_cfe_partitions(struct mtd_info *master, if (kernellen > 0) nrparts++; - /* Ask kernel for more memory */ parts = kzalloc(sizeof(*parts) * nrparts + 10 * nrparts, GFP_KERNEL); if (!parts) { - vfree(buf); - return -ENOMEM; + ret = -ENOMEM; + goto out; } /* Start building partition list */ @@ -206,9 +272,43 @@ static int bcm63xx_parse_cfe_partitions(struct mtd_info *master, sparelen); *pparts = parts; + ret = 0; + +out: vfree(buf); + if (ret) + return ret; + return nrparts; +} + +static int bcm63xx_parse_cfe_partitions(struct mtd_info *master, + const struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + struct bcm963xx_nvram *nvram = NULL; + int ret; + + if (bcm63xx_detect_cfe(master)) + return -EINVAL; + + nvram = vzalloc(sizeof(*nvram)); + if (!nvram) + return -ENOMEM; + + ret = bcm63xx_read_nvram(master, nvram); + if (ret) + goto out; + + if (!mtd_type_is_nand(master)) + ret = bcm63xx_parse_cfe_nor_partitions(master, pparts, nvram); + else + ret = -EINVAL; + +out: + vfree(nvram); + return ret; }; static struct mtd_part_parser bcm63xx_cfe_parser = { diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c index c3a2695a4420..e7b2e439696c 100644 --- a/drivers/mtd/devices/docg3.c +++ b/drivers/mtd/devices/docg3.c @@ -72,13 +72,11 @@ MODULE_PARM_DESC(reliable_mode, "Set the docg3 mode (0=normal MLC, 1=fast, " * @eccbytes: 8 bytes are used (1 for Hamming ECC, 7 for BCH ECC) * @eccpos: ecc positions (byte 7 is Hamming ECC, byte 8-14 are BCH ECC) * @oobfree: free pageinfo bytes (byte 0 until byte 6, byte 15 - * @oobavail: 8 available bytes remaining after ECC toll */ static struct nand_ecclayout docg3_oobinfo = { .eccbytes = 8, .eccpos = {7, 8, 9, 10, 11, 12, 13, 14}, .oobfree = {{0, 7}, {15, 1} }, - .oobavail = 8, }; static inline u8 doc_readb(struct docg3 *docg3, u16 reg) @@ -1438,7 +1436,7 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, oobdelta = mtd->oobsize; break; case MTD_OPS_AUTO_OOB: - oobdelta = mtd->ecclayout->oobavail; + oobdelta = mtd->oobavail; break; default: return -EINVAL; @@ -1860,6 +1858,7 @@ static int __init doc_set_driver_info(int chip_id, struct mtd_info *mtd) mtd->_write_oob = doc_write_oob; mtd->_block_isbad = doc_block_isbad; mtd->ecclayout = &docg3_oobinfo; + mtd->oobavail = 8; mtd->ecc_strength = DOC_ECC_BCH_T; return 0; diff --git a/drivers/mtd/devices/mtdram.c b/drivers/mtd/devices/mtdram.c index 627a9bc37679..cbd8547d7aad 100644 --- a/drivers/mtd/devices/mtdram.c +++ b/drivers/mtd/devices/mtdram.c @@ -19,6 +19,7 @@ static unsigned long total_size = CONFIG_MTDRAM_TOTAL_SIZE; static unsigned long erase_size = CONFIG_MTDRAM_ERASE_SIZE; +static unsigned long writebuf_size = 64; #define MTDRAM_TOTAL_SIZE (total_size * 1024) #define MTDRAM_ERASE_SIZE (erase_size * 1024) @@ -27,6 +28,8 @@ module_param(total_size, ulong, 0); MODULE_PARM_DESC(total_size, "Total device size in KiB"); module_param(erase_size, ulong, 0); MODULE_PARM_DESC(erase_size, "Device erase block size in KiB"); +module_param(writebuf_size, ulong, 0); +MODULE_PARM_DESC(writebuf_size, "Device write buf size in Bytes (Default: 64)"); #endif // We could store these in the mtd structure, but we only support 1 device.. @@ -123,7 +126,7 @@ int mtdram_init_device(struct mtd_info *mtd, void *mapped_address, mtd->flags = MTD_CAP_RAM; mtd->size = size; mtd->writesize = 1; - mtd->writebufsize = 64; /* Mimic CFI NOR flashes */ + mtd->writebufsize = writebuf_size; mtd->erasesize = MTDRAM_ERASE_SIZE; mtd->priv = mapped_address; diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 10bf304027dd..08de4b2cf0f5 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -126,10 +126,7 @@ static int part_read_oob(struct mtd_info *mtd, loff_t from, if (ops->oobbuf) { size_t len, pages; - if (ops->mode == MTD_OPS_AUTO_OOB) - len = mtd->oobavail; - else - len = mtd->oobsize; + len = mtd_oobavail(mtd, ops); pages = mtd_div_by_ws(mtd->size, mtd); pages -= mtd_div_by_ws(from, mtd); if (ops->ooboffs + ops->ooblen > pages * len) diff --git a/drivers/mtd/mtdswap.c b/drivers/mtd/mtdswap.c index fc8b3d16cce7..cb06bdd21a1b 100644 --- a/drivers/mtd/mtdswap.c +++ b/drivers/mtd/mtdswap.c @@ -346,7 +346,7 @@ static int mtdswap_read_markers(struct mtdswap_dev *d, struct swap_eb *eb) if (mtd_can_have_bb(d->mtd) && mtd_block_isbad(d->mtd, offset)) return MTDSWAP_SCANNED_BAD; - ops.ooblen = 2 * d->mtd->ecclayout->oobavail; + ops.ooblen = 2 * d->mtd->oobavail; ops.oobbuf = d->oob_buf; ops.ooboffs = 0; ops.datbuf = NULL; @@ -359,7 +359,7 @@ static int mtdswap_read_markers(struct mtdswap_dev *d, struct swap_eb *eb) data = (struct mtdswap_oobdata *)d->oob_buf; data2 = (struct mtdswap_oobdata *) - (d->oob_buf + d->mtd->ecclayout->oobavail); + (d->oob_buf + d->mtd->oobavail); if (le16_to_cpu(data->magic) == MTDSWAP_MAGIC_CLEAN) { eb->erase_count = le32_to_cpu(data->count); @@ -933,7 +933,7 @@ static unsigned int mtdswap_eblk_passes(struct mtdswap_dev *d, ops.mode = MTD_OPS_AUTO_OOB; ops.len = mtd->writesize; - ops.ooblen = mtd->ecclayout->oobavail; + ops.ooblen = mtd->oobavail; ops.ooboffs = 0; ops.datbuf = d->page_buf; ops.oobbuf = d->oob_buf; @@ -945,7 +945,7 @@ static unsigned int mtdswap_eblk_passes(struct mtdswap_dev *d, for (i = 0; i < mtd_pages; i++) { patt = mtdswap_test_patt(test + i); memset(d->page_buf, patt, mtd->writesize); - memset(d->oob_buf, patt, mtd->ecclayout->oobavail); + memset(d->oob_buf, patt, mtd->oobavail); ret = mtd_write_oob(mtd, pos, &ops); if (ret) goto error; @@ -964,7 +964,7 @@ static unsigned int mtdswap_eblk_passes(struct mtdswap_dev *d, if (p1[j] != patt) goto error; - for (j = 0; j < mtd->ecclayout->oobavail; j++) + for (j = 0; j < mtd->oobavail; j++) if (p2[j] != (unsigned char)patt) goto error; @@ -1387,7 +1387,7 @@ static int mtdswap_init(struct mtdswap_dev *d, unsigned int eblocks, if (!d->page_buf) goto page_buf_fail; - d->oob_buf = kmalloc(2 * mtd->ecclayout->oobavail, GFP_KERNEL); + d->oob_buf = kmalloc(2 * mtd->oobavail, GFP_KERNEL); if (!d->oob_buf) goto oob_buf_fail; @@ -1417,7 +1417,6 @@ static void mtdswap_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) unsigned long part; unsigned int eblocks, eavailable, bad_blocks, spare_cnt; uint64_t swap_size, use_size, size_limit; - struct nand_ecclayout *oinfo; int ret; parts = &partitions[0]; @@ -1447,17 +1446,10 @@ static void mtdswap_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) return; } - oinfo = mtd->ecclayout; - if (!oinfo) { - printk(KERN_ERR "%s: mtd%d does not have OOB\n", - MTDSWAP_PREFIX, mtd->index); - return; - } - - if (!mtd->oobsize || oinfo->oobavail < MTDSWAP_OOBSIZE) { + if (!mtd->oobsize || mtd->oobavail < MTDSWAP_OOBSIZE) { printk(KERN_ERR "%s: Not enough free bytes in OOB, " "%d available, %zu needed.\n", - MTDSWAP_PREFIX, oinfo->oobavail, MTDSWAP_OOBSIZE); + MTDSWAP_PREFIX, mtd->oobavail, MTDSWAP_OOBSIZE); return; } diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 20f01b3ec23d..f05e0e9eb2f7 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -74,6 +74,7 @@ config MTD_NAND_DENALI_SCRATCH_REG_ADDR config MTD_NAND_GPIO tristate "GPIO assisted NAND Flash driver" depends on GPIOLIB || COMPILE_TEST + depends on HAS_IOMEM help This enables a NAND flash driver where control signals are connected to GPIO pins, and commands and data are communicated @@ -310,6 +311,7 @@ config MTD_NAND_CAFE config MTD_NAND_CS553X tristate "NAND support for CS5535/CS5536 (AMD Geode companion chip)" depends on X86_32 + depends on !UML && HAS_IOMEM help The CS553x companion chips for the AMD Geode processor include NAND flash controllers with built-in hardware ECC @@ -463,6 +465,7 @@ config MTD_NAND_MPC5121_NFC config MTD_NAND_VF610_NFC tristate "Support for Freescale NFC for VF610/MPC5125" depends on (SOC_VF610 || COMPILE_TEST) + depends on HAS_IOMEM help Enables support for NAND Flash Controller on some Freescale processors like the VF610, MPC5125, MCF54418 or Kinetis K70. @@ -553,4 +556,11 @@ config MTD_NAND_HISI504 help Enables support for NAND controller on Hisilicon SoC Hip04. +config MTD_NAND_QCOM + tristate "Support for NAND on QCOM SoCs" + depends on ARCH_QCOM + help + Enables support for NAND flash chips on SoCs containing the EBI2 NAND + controller. This controller is found on IPQ806x SoC. + endif # MTD_NAND diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 9e3623308509..f55335373f7c 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -56,5 +56,6 @@ obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH) += bcm47xxnflash/ obj-$(CONFIG_MTD_NAND_SUNXI) += sunxi_nand.o obj-$(CONFIG_MTD_NAND_HISI504) += hisi504_nand.o obj-$(CONFIG_MTD_NAND_BRCMNAND) += brcmnand/ +obj-$(CONFIG_MTD_NAND_QCOM) += qcom_nandc.o nand-objs := nand_base.o nand_bbt.o nand_timings.o diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index bddcf83d6859..20cbaabb2959 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -65,6 +65,11 @@ module_param(on_flash_bbt, int, 0); struct atmel_nand_caps { bool pmecc_correct_erase_page; + uint8_t pmecc_max_correction; +}; + +struct atmel_nand_nfc_caps { + uint32_t rb_mask; }; /* oob layout for large page size @@ -111,6 +116,7 @@ struct atmel_nfc { /* Point to the sram bank which include readed data via NFC */ void *data_in_sram; bool will_write_sram; + const struct atmel_nand_nfc_caps *caps; }; static struct atmel_nfc nand_nfc; @@ -140,6 +146,7 @@ struct atmel_nand_host { int pmecc_cw_len; /* Length of codeword */ void __iomem *pmerrloc_base; + void __iomem *pmerrloc_el_base; void __iomem *pmecc_rom_base; /* lookup table for alpha_to and index_of */ @@ -468,6 +475,7 @@ static void atmel_write_buf(struct mtd_info *mtd, const u8 *buf, int len) * 8-bits 13-bytes 14-bytes * 12-bits 20-bytes 21-bytes * 24-bits 39-bytes 42-bytes + * 32-bits 52-bytes 56-bytes */ static int pmecc_get_ecc_bytes(int cap, int sector_size) { @@ -813,7 +821,7 @@ static void pmecc_correct_data(struct mtd_info *mtd, uint8_t *buf, uint8_t *ecc, sector_size = host->pmecc_sector_size; while (err_nbr) { - tmp = pmerrloc_readl_el_relaxed(host->pmerrloc_base, i) - 1; + tmp = pmerrloc_readl_el_relaxed(host->pmerrloc_el_base, i) - 1; byte_pos = tmp / 8; bit_pos = tmp % 8; @@ -825,7 +833,7 @@ static void pmecc_correct_data(struct mtd_info *mtd, uint8_t *buf, uint8_t *ecc, *(buf + byte_pos) ^= (1 << bit_pos); pos = sector_num * host->pmecc_sector_size + byte_pos; - dev_info(host->dev, "Bit flip in data area, byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n", + dev_dbg(host->dev, "Bit flip in data area, byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n", pos, bit_pos, err_byte, *(buf + byte_pos)); } else { /* Bit flip in OOB area */ @@ -835,7 +843,7 @@ static void pmecc_correct_data(struct mtd_info *mtd, uint8_t *buf, uint8_t *ecc, ecc[tmp] ^= (1 << bit_pos); pos = tmp + nand_chip->ecc.layout->eccpos[0]; - dev_info(host->dev, "Bit flip in OOB, oob_byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n", + dev_dbg(host->dev, "Bit flip in OOB, oob_byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n", pos, bit_pos, err_byte, ecc[tmp]); } @@ -1017,6 +1025,9 @@ static void atmel_pmecc_core_init(struct mtd_info *mtd) case 24: val = PMECC_CFG_BCH_ERR24; break; + case 32: + val = PMECC_CFG_BCH_ERR32; + break; } if (host->pmecc_sector_size == 512) @@ -1078,6 +1089,9 @@ static int pmecc_choose_ecc(struct atmel_nand_host *host, /* If device tree doesn't specify, use NAND's minimum ECC parameters */ if (host->pmecc_corr_cap == 0) { + if (*cap > host->caps->pmecc_max_correction) + return -EINVAL; + /* use the most fitable ecc bits (the near bigger one ) */ if (*cap <= 2) host->pmecc_corr_cap = 2; @@ -1089,6 +1103,8 @@ static int pmecc_choose_ecc(struct atmel_nand_host *host, host->pmecc_corr_cap = 12; else if (*cap <= 24) host->pmecc_corr_cap = 24; + else if (*cap <= 32) + host->pmecc_corr_cap = 32; else return -EINVAL; } @@ -1205,6 +1221,8 @@ static int atmel_pmecc_nand_init_params(struct platform_device *pdev, err_no = PTR_ERR(host->pmerrloc_base); goto err; } + host->pmerrloc_el_base = host->pmerrloc_base + ATMEL_PMERRLOC_SIGMAx + + (host->caps->pmecc_max_correction + 1) * 4; if (!host->has_no_lookup_table) { regs_rom = platform_get_resource(pdev, IORESOURCE_MEM, 3); @@ -1486,8 +1504,6 @@ static void atmel_nand_hwctl(struct mtd_info *mtd, int mode) ecc_writel(host->ecc, CR, ATMEL_ECC_RST); } -static const struct of_device_id atmel_nand_dt_ids[]; - static int atmel_of_init_port(struct atmel_nand_host *host, struct device_node *np) { @@ -1498,7 +1514,7 @@ static int atmel_of_init_port(struct atmel_nand_host *host, enum of_gpio_flags flags = 0; host->caps = (struct atmel_nand_caps *) - of_match_device(atmel_nand_dt_ids, host->dev)->data; + of_device_get_match_data(host->dev); if (of_property_read_u32(np, "atmel,nand-addr-offset", &val) == 0) { if (val >= 32) { @@ -1547,10 +1563,16 @@ static int atmel_of_init_port(struct atmel_nand_host *host, * them from NAND ONFI parameters. */ if (of_property_read_u32(np, "atmel,pmecc-cap", &val) == 0) { - if ((val != 2) && (val != 4) && (val != 8) && (val != 12) && - (val != 24)) { + if (val > host->caps->pmecc_max_correction) { dev_err(host->dev, - "Unsupported PMECC correction capability: %d; should be 2, 4, 8, 12 |