Commit 91a247d7 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'for-linus-20150901' of git://git.infradead.org/linux-mtd

Pull MTD updates from Brian Norris:
 "SPI NOR:
   - reduce virtual address space requirements for fsl-quadspi memory map
   - new fsl-quadspi IP support: imx6ul-qspi and imx7d-qspi
   - add new NOR flash device support
   - add new driver for NXP SPI Flash Interface (SPIFI)
   - stop abusing SPI API structs for non-SPI framework
   - fixup DT table matching for new "jedec,spi-nor" string

  NAND:
   - brcmnand: fix big endian MIPS macro usage
   - denali: refactor to use devres, dev_*() printing, etc.
   - OMAP ELM: change the module alias to actually be usable
   - pxa3xx_nand: fixup a few command sequencing issues -- both new and old
      - race conditions in the IRQ handler status clearing
      - problems when a bootloader left interrupts pending
      - config issues when overriding the bootloader configuration
   - new flash device support
   - sunxi_nand:
      - optimize timing configuration by calculation, rather than fixed
        fail-safe values
      - use EDO setting from ONFI
   - r852: fix compiler warnings
   - davinci: add 4KB page support

  Core:
   - oobtest: correct debug print information"

* tag 'for-linus-20150901' of git://git.infradead.org/linux-mtd: (42 commits)
  mtd: mtd_oobtest: Fix the address offset with vary_offset case
  mtd: blkdevs: fix switch-bool compilation warning
  mtd: spi-nor: stop (ab)using struct spi_device_id
  mtd: nand: add Toshiba TC58NVG0S3E to nand_ids table
  mtd: dataflash: Export OF module alias information
  nand: pxa3xx: Increase READ_ID buffer and make the size static
  mtd: nand: pxa3xx-nand: fix random command timeouts
  mtd: nand: pxa3xx_nand: fix early spurious interrupt
  mtd: pxa3xx_nand: add a default chunk size
  mtd: omap_elm: Fix module alias
  mtd: physmap_of: fix null pointer deference when kzalloc returns null
  mtd: nettel: do not ignore mtd_device_register() failure in nettel_init()
  mtd: denali_pci: switch to dev_err()
  mtd: denali_pci: refactor driver using devres API
  mtd: denali_pci: use module_pci_driver() macro
  mtd: denali: hide core part from user in Kconfig
  mtd: spi-nor: add Spansion S25FL204K support
  mtd: spi-nor: Improve Kconfig help text for SPI_FSL_QUADSPI
  mtd: spi-nor: add driver for NXP SPI Flash Interface (SPIFI)
  doc: dt: add documentation for nxp,lpc1773-spifi
  ...
parents 8bdc69b7 718e38b4
* Freescale Quad Serial Peripheral Interface(QuadSPI) * Freescale Quad Serial Peripheral Interface(QuadSPI)
Required properties: Required properties:
- compatible : Should be "fsl,vf610-qspi" or "fsl,imx6sx-qspi" - compatible : Should be "fsl,vf610-qspi", "fsl,imx6sx-qspi",
"fsl,imx7d-qspi", "fsl,imx6ul-qspi"
- reg : the first contains the register location and length, - reg : the first contains the register location and length,
the second contains the memory mapping address and length the second contains the memory mapping address and length
- reg-names: Should contain the reg names "QuadSPI" and "QuadSPI-memory" - reg-names: Should contain the reg names "QuadSPI" and "QuadSPI-memory"
......
* NXP SPI Flash Interface (SPIFI)
NXP SPIFI is a specialized SPI interface for serial Flash devices.
It supports one Flash device with 1-, 2- and 4-bits width in SPI
mode 0 or 3. The controller operates in either command or memory
mode. In memory mode the Flash is accessible from the CPU as
normal memory.
Required properties:
- compatible : Should be "nxp,lpc1773-spifi"
- reg : the first contains the register location and length,
the second contains the memory mapping address and length
- reg-names: Should contain the reg names "spifi" and "flash"
- interrupts : Should contain the interrupt for the device
- clocks : The clocks needed by the SPIFI controller
- clock-names : Should contain the clock names "spifi" and "reg"
Optional properties:
- resets : phandle + reset specifier
The SPI Flash must be a child of the SPIFI node and must have a
compatible property as specified in bindings/mtd/jedec,spi-nor.txt
Optionally it can also contain the following properties.
- spi-cpol : Controller only supports mode 0 and 3 so either
both spi-cpol and spi-cpha should be present or
none of them
- spi-cpha : See above
- spi-rx-bus-width : Used to select how many pins that are used
for input on the controller
See bindings/spi/spi-bus.txt for more information.
Example:
spifi: spifi@40003000 {
compatible = "nxp,lpc1773-spifi";
reg = <0x40003000 0x1000>, <0x14000000 0x4000000>;
reg-names = "spifi", "flash";
interrupts = <30>;
clocks = <&ccu1 CLK_SPIFI>, <&ccu1 CLK_CPU_SPIFI>;
clock-names = "spifi", "reg";
resets = <&rgu 53>;
flash@0 {
compatible = "jedec,spi-nor";
spi-cpol;
spi-cpha;
spi-rx-bus-width = <4>;
#address-cells = <1>;
#size-cells = <1>;
partition@0 {
label = "data";
reg = <0 0x200000>;
};
};
};
...@@ -223,8 +223,6 @@ static int m25p_probe(struct spi_device *spi) ...@@ -223,8 +223,6 @@ static int m25p_probe(struct spi_device *spi)
*/ */
if (data && data->type) if (data && data->type)
flash_name = data->type; flash_name = data->type;
else if (!strcmp(spi->modalias, "spi-nor"))
flash_name = NULL; /* auto-detect */
else else
flash_name = spi->modalias; flash_name = spi->modalias;
...@@ -289,19 +287,25 @@ static const struct spi_device_id m25p_ids[] = { ...@@ -289,19 +287,25 @@ static const struct spi_device_id m25p_ids[] = {
{"m25p40-nonjedec"}, {"m25p80-nonjedec"}, {"m25p16-nonjedec"}, {"m25p40-nonjedec"}, {"m25p80-nonjedec"}, {"m25p16-nonjedec"},
{"m25p32-nonjedec"}, {"m25p64-nonjedec"}, {"m25p128-nonjedec"}, {"m25p32-nonjedec"}, {"m25p64-nonjedec"}, {"m25p128-nonjedec"},
/*
* Generic support for SPI NOR that can be identified by the JEDEC READ
* ID opcode (0x9F). Use this, if possible.
*/
{"spi-nor"},
{ }, { },
}; };
MODULE_DEVICE_TABLE(spi, m25p_ids); MODULE_DEVICE_TABLE(spi, m25p_ids);
static const struct of_device_id m25p_of_table[] = {
/*
* Generic compatibility for SPI NOR that can be identified by the
* JEDEC READ ID opcode (0x9F). Use this, if possible.
*/
{ .compatible = "jedec,spi-nor" },
{}
};
MODULE_DEVICE_TABLE(of, m25p_of_table);
static struct spi_driver m25p80_driver = { static struct spi_driver m25p80_driver = {
.driver = { .driver = {
.name = "m25p80", .name = "m25p80",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.of_match_table = m25p_of_table,
}, },
.id_table = m25p_ids, .id_table = m25p_ids,
.probe = m25p_probe, .probe = m25p_probe,
......
...@@ -102,6 +102,7 @@ static const struct of_device_id dataflash_dt_ids[] = { ...@@ -102,6 +102,7 @@ static const struct of_device_id dataflash_dt_ids[] = {
{ .compatible = "atmel,dataflash", }, { .compatible = "atmel,dataflash", },
{ /* sentinel */ } { /* sentinel */ }
}; };
MODULE_DEVICE_TABLE(of, dataflash_dt_ids);
#endif #endif
/* ......................................................................... */ /* ......................................................................... */
......
...@@ -385,20 +385,28 @@ static int __init nettel_init(void) ...@@ -385,20 +385,28 @@ static int __init nettel_init(void)
} }
rc = mtd_device_register(intel_mtd, nettel_intel_partitions, rc = mtd_device_register(intel_mtd, nettel_intel_partitions,
num_intel_partitions); num_intel_partitions);
if (rc)
goto out_map_destroy;
#endif #endif
if (amd_mtd) { if (amd_mtd) {
rc = mtd_device_register(amd_mtd, nettel_amd_partitions, rc = mtd_device_register(amd_mtd, nettel_amd_partitions,
num_amd_partitions); num_amd_partitions);
if (rc)
goto out_mtd_unreg;
} }
#ifdef CONFIG_MTD_CFI_INTELEXT #ifdef CONFIG_MTD_CFI_INTELEXT
register_reboot_notifier(&nettel_notifier_block); register_reboot_notifier(&nettel_notifier_block);
#endif #endif
return(rc); return rc;
out_mtd_unreg:
#ifdef CONFIG_MTD_CFI_INTELEXT #ifdef CONFIG_MTD_CFI_INTELEXT
mtd_device_unregister(intel_mtd);
out_map_destroy:
map_destroy(intel_mtd);
out_unmap1: out_unmap1:
iounmap(nettel_intel_map.virt); iounmap(nettel_intel_map.virt);
#endif #endif
...@@ -407,8 +415,7 @@ static int __init nettel_init(void) ...@@ -407,8 +415,7 @@ static int __init nettel_init(void)
iounmap(nettel_mmcrp); iounmap(nettel_mmcrp);
iounmap(nettel_amd_map.virt); iounmap(nettel_amd_map.virt);
return(rc); return rc;
} }
/****************************************************************************/ /****************************************************************************/
......
...@@ -130,6 +130,8 @@ static const char * const *of_get_probes(struct device_node *dp) ...@@ -130,6 +130,8 @@ static const char * const *of_get_probes(struct device_node *dp)
count++; count++;
res = kzalloc((count + 1)*sizeof(*res), GFP_KERNEL); res = kzalloc((count + 1)*sizeof(*res), GFP_KERNEL);
if (!res)
return NULL;
count = 0; count = 0;
while (cplen > 0) { while (cplen > 0) {
res[count] = cp; res[count] = cp;
...@@ -311,6 +313,10 @@ static int of_flash_probe(struct platform_device *dev) ...@@ -311,6 +313,10 @@ static int of_flash_probe(struct platform_device *dev)
ppdata.of_node = dp; ppdata.of_node = dp;
part_probe_types = of_get_probes(dp); part_probe_types = of_get_probes(dp);
if (!part_probe_types) {
err = -ENOMEM;
goto err_out;
}
mtd_device_parse_register(info->cmtd, part_probe_types, &ppdata, mtd_device_parse_register(info->cmtd, part_probe_types, &ppdata,
NULL, 0); NULL, 0);
of_free_probes(part_probe_types); of_free_probes(part_probe_types);
......
...@@ -97,14 +97,13 @@ static int do_blktrans_request(struct mtd_blktrans_ops *tr, ...@@ -97,14 +97,13 @@ static int do_blktrans_request(struct mtd_blktrans_ops *tr,
if (req->cmd_flags & REQ_DISCARD) if (req->cmd_flags & REQ_DISCARD)
return tr->discard(dev, block, nsect); return tr->discard(dev, block, nsect);
switch(rq_data_dir(req)) { if (rq_data_dir(req) == READ) {
case READ:
for (; nsect > 0; nsect--, block++, buf += tr->blksize) for (; nsect > 0; nsect--, block++, buf += tr->blksize)
if (tr->readsect(dev, block, buf)) if (tr->readsect(dev, block, buf))
return -EIO; return -EIO;
rq_flush_dcache_pages(req); rq_flush_dcache_pages(req);
return 0; return 0;
case WRITE: } else {
if (!tr->writesect) if (!tr->writesect)
return -EIO; return -EIO;
...@@ -113,9 +112,6 @@ static int do_blktrans_request(struct mtd_blktrans_ops *tr, ...@@ -113,9 +112,6 @@ static int do_blktrans_request(struct mtd_blktrans_ops *tr,
if (tr->writesect(dev, block, buf)) if (tr->writesect(dev, block, buf))
return -EIO; return -EIO;
return 0; return 0;
default:
printk(KERN_NOTICE "Unknown request %u\n", rq_data_dir(req));
return -EIO;
} }
} }
......
...@@ -42,23 +42,20 @@ config MTD_SM_COMMON ...@@ -42,23 +42,20 @@ config MTD_SM_COMMON
default n default n
config MTD_NAND_DENALI config MTD_NAND_DENALI
tristate "Support Denali NAND controller" tristate
depends on HAS_DMA
help
Enable support for the Denali NAND controller. This should be
combined with either the PCI or platform drivers to provide device
registration.
config MTD_NAND_DENALI_PCI config MTD_NAND_DENALI_PCI
tristate "Support Denali NAND controller on Intel Moorestown" tristate "Support Denali NAND controller on Intel Moorestown"
depends on PCI && MTD_NAND_DENALI select MTD_NAND_DENALI
depends on HAS_DMA && PCI
help help
Enable the driver for NAND flash on Intel Moorestown, using the Enable the driver for NAND flash on Intel Moorestown, using the
Denali NAND controller core. Denali NAND controller core.
config MTD_NAND_DENALI_DT config MTD_NAND_DENALI_DT
tristate "Support Denali NAND controller as a DT device" tristate "Support Denali NAND controller as a DT device"
depends on HAVE_CLK && MTD_NAND_DENALI select MTD_NAND_DENALI
depends on HAS_DMA && HAVE_CLK
help help
Enable the driver for NAND flash on platforms using a Denali NAND Enable the driver for NAND flash on platforms using a Denali NAND
controller as a DT device. controller as a DT device.
......
...@@ -50,7 +50,7 @@ static inline u32 brcmnand_readl(void __iomem *addr) ...@@ -50,7 +50,7 @@ static inline u32 brcmnand_readl(void __iomem *addr)
* Other architectures (e.g., ARM) either do not support big endian, or * Other architectures (e.g., ARM) either do not support big endian, or
* else leave I/O in little endian mode. * else leave I/O in little endian mode.
*/ */
if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(__BIG_ENDIAN)) if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
return __raw_readl(addr); return __raw_readl(addr);
else else
return readl_relaxed(addr); return readl_relaxed(addr);
...@@ -59,7 +59,7 @@ static inline u32 brcmnand_readl(void __iomem *addr) ...@@ -59,7 +59,7 @@ static inline u32 brcmnand_readl(void __iomem *addr)
static inline void brcmnand_writel(u32 val, void __iomem *addr) static inline void brcmnand_writel(u32 val, void __iomem *addr)
{ {
/* See brcmnand_readl() comments */ /* See brcmnand_readl() comments */
if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(__BIG_ENDIAN)) if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
__raw_writel(val, addr); __raw_writel(val, addr);
else else
writel_relaxed(val, addr); writel_relaxed(val, addr);
......
...@@ -520,6 +520,32 @@ static struct nand_ecclayout hwecc4_2048 = { ...@@ -520,6 +520,32 @@ static struct nand_ecclayout hwecc4_2048 = {
}, },
}; };
/*
* An ECC layout for using 4-bit ECC with large-page (4096bytes) flash,
* storing ten ECC bytes plus the manufacturer's bad block marker byte,
* and not overlapping the default BBT markers.
*/
static struct nand_ecclayout hwecc4_4096 = {
.eccbytes = 80,
.eccpos = {
/* at the end of spare sector */
48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
58, 59, 60, 61, 62, 63, 64, 65, 66, 67,
68, 69, 70, 71, 72, 73, 74, 75, 76, 77,
78, 79, 80, 81, 82, 83, 84, 85, 86, 87,
88, 89, 90, 91, 92, 93, 94, 95, 96, 97,
98, 99, 100, 101, 102, 103, 104, 105, 106, 107,
108, 109, 110, 111, 112, 113, 114, 115, 116, 117,
118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
},
.oobfree = {
/* 2 bytes at offset 0 hold manufacturer badblock markers */
{.offset = 2, .length = 46, },
/* 5 bytes at offset 8 hold BBT markers */
/* 8 bytes at offset 16 hold JFFS2 clean markers */
},
};
#if defined(CONFIG_OF) #if defined(CONFIG_OF)
static const struct of_device_id davinci_nand_of_match[] = { static const struct of_device_id davinci_nand_of_match[] = {
{.compatible = "ti,davinci-nand", }, {.compatible = "ti,davinci-nand", },
...@@ -796,18 +822,12 @@ static int nand_davinci_probe(struct platform_device *pdev) ...@@ -796,18 +822,12 @@ static int nand_davinci_probe(struct platform_device *pdev)
info->chip.ecc.mode = NAND_ECC_HW_OOB_FIRST; info->chip.ecc.mode = NAND_ECC_HW_OOB_FIRST;
goto syndrome_done; goto syndrome_done;
} }
if (chunks == 8) {
info->ecclayout = hwecc4_4096;
info->chip.ecc.mode = NAND_ECC_HW_OOB_FIRST;
goto syndrome_done;
}
/* 4KiB page chips are not yet supported. The eccpos from
* nand_ecclayout cannot hold 80 bytes and change to eccpos[]
* breaks userspace ioctl interface with mtd-utils. Once we
* resolve this issue, NAND_ECC_HW_OOB_FIRST mode can be used
* for the 4KiB page chips.
*
* TODO: Note that nand_ecclayout has now been expanded and can
* hold plenty of OOB entries.
*/
dev_warn(&pdev->dev, "no 4-bit ECC support yet "
"for 4KiB-page NAND\n");
ret = -EIO; ret = -EIO;
goto err; goto err;
......
...@@ -30,19 +30,19 @@ MODULE_DEVICE_TABLE(pci, denali_pci_ids); ...@@ -30,19 +30,19 @@ MODULE_DEVICE_TABLE(pci, denali_pci_ids);
static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
{ {
int ret = -ENODEV; int ret;
resource_size_t csr_base, mem_base; resource_size_t csr_base, mem_base;
unsigned long csr_len, mem_len; unsigned long csr_len, mem_len;
struct denali_nand_info *denali; struct denali_nand_info *denali;
denali = kzalloc(sizeof(*denali), GFP_KERNEL); denali = devm_kzalloc(&dev->dev, sizeof(*denali), GFP_KERNEL);
if (!denali) if (!denali)
return -ENOMEM; return -ENOMEM;
ret = pci_enable_device(dev); ret = pcim_enable_device(dev);
if (ret) { if (ret) {
pr_err("Spectra: pci_enable_device failed.\n"); dev_err(&dev->dev, "Spectra: pci_enable_device failed.\n");
goto failed_alloc_memery; return ret;
} }
if (id->driver_data == INTEL_CE4100) { if (id->driver_data == INTEL_CE4100) {
...@@ -69,20 +69,19 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) ...@@ -69,20 +69,19 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
ret = pci_request_regions(dev, DENALI_NAND_NAME); ret = pci_request_regions(dev, DENALI_NAND_NAME);
if (ret) { if (ret) {
pr_err("Spectra: Unable to request memory regions\n"); dev_err(&dev->dev, "Spectra: Unable to request memory regions\n");
goto failed_enable_dev; return ret;
} }
denali->flash_reg = ioremap_nocache(csr_base, csr_len); denali->flash_reg = ioremap_nocache(csr_base, csr_len);
if (!denali->flash_reg) { if (!denali->flash_reg) {
pr_err("Spectra: Unable to remap memory region\n"); dev_err(&dev->dev, "Spectra: Unable to remap memory region\n");
ret = -ENOMEM; return -ENOMEM;
goto failed_req_regions;
} }
denali->flash_mem = ioremap_nocache(mem_base, mem_len); denali->flash_mem = ioremap_nocache(mem_base, mem_len);
if (!denali->flash_mem) { if (!denali->flash_mem) {
pr_err("Spectra: ioremap_nocache failed!"); dev_err(&dev->dev, "Spectra: ioremap_nocache failed!");
ret = -ENOMEM; ret = -ENOMEM;
goto failed_remap_reg; goto failed_remap_reg;
} }
...@@ -99,13 +98,6 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) ...@@ -99,13 +98,6 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
iounmap(denali->flash_mem); iounmap(denali->flash_mem);
failed_remap_reg: failed_remap_reg:
iounmap(denali->flash_reg); iounmap(denali->flash_reg);
failed_req_regions:
pci_release_regions(dev);
failed_enable_dev:
pci_disable_device(dev);
failed_alloc_memery:
kfree(denali);
return ret; return ret;
} }
...@@ -117,9 +109,6 @@ static void denali_pci_remove(struct pci_dev *dev) ...@@ -117,9 +109,6 @@ static void denali_pci_remove(struct pci_dev *dev)
denali_remove(denali); denali_remove(denali);
iounmap(denali->flash_reg); iounmap(denali->flash_reg);
iounmap(denali->flash_mem); iounmap(denali->flash_mem);
pci_release_regions(dev);
pci_disable_device(dev);
kfree(denali);
} }
static struct pci_driver denali_pci_driver = { static struct pci_driver denali_pci_driver = {
...@@ -129,14 +118,4 @@ static struct pci_driver denali_pci_driver = { ...@@ -129,14 +118,4 @@ static struct pci_driver denali_pci_driver = {
.remove = denali_pci_remove, .remove = denali_pci_remove,
}; };
static int denali_init_pci(void) module_pci_driver(denali_pci_driver);
{
return pci_register_driver(&denali_pci_driver);
}
module_init(denali_init_pci);
static void denali_exit_pci(void)
{
pci_unregister_driver(&denali_pci_driver);
}
module_exit(denali_exit_pci);
...@@ -29,6 +29,10 @@ struct nand_flash_dev nand_flash_ids[] = { ...@@ -29,6 +29,10 @@ struct nand_flash_dev nand_flash_ids[] = {
* listed by full ID. We list them first so that we can easily identify * listed by full ID. We list them first so that we can easily identify
* the most specific match. * the most specific match.
*/ */
{"TC58NVG0S3E 1G 3.3V 8-bit",
{ .id = {0x98, 0xd1, 0x90, 0x15, 0x76, 0x14, 0x01, 0x00} },
SZ_2K, SZ_128, SZ_128K, 0, 8, 64, NAND_ECC_INFO(1, SZ_512),
2 },
{"TC58NVG2S0F 4G 3.3V 8-bit", {"TC58NVG2S0F 4G 3.3V 8-bit",
{ .id = {0x98, 0xdc, 0x90, 0x26, 0x76, 0x15, 0x01, 0x08} }, { .id = {0x98, 0xdc, 0x90, 0x26, 0x76, 0x15, 0x01, 0x08} },
SZ_4K, SZ_512, SZ_256K, 0, 8, 224, NAND_ECC_INFO(4, SZ_512) }, SZ_4K, SZ_512, SZ_256K, 0, 8, 224, NAND_ECC_INFO(4, SZ_512) },
......
...@@ -649,7 +649,8 @@ static void free_device(struct nandsim *ns) ...@@ -649,7 +649,8 @@ static void free_device(struct nandsim *ns)
kmem_cache_free(ns->nand_pages_slab, kmem_cache_free(ns->nand_pages_slab,
ns->pages[i].byte); ns->pages[i].byte);
} }
kmem_cache_destroy(ns->nand_pages_slab); if (ns->nand_pages_slab)
kmem_cache_destroy(ns->nand_pages_slab);
vfree(ns->pages); vfree(ns->pages);
} }
} }
...@@ -729,8 +730,7 @@ static int init_nandsim(struct mtd_info *mtd) ...@@ -729,8 +730,7 @@ static int init_nandsim(struct mtd_info *mtd)
/* Fill the partition_info structure */ /* Fill the partition_info structure */
if (parts_num > ARRAY_SIZE(ns->partitions)) { if (parts_num > ARRAY_SIZE(ns->partitions)) {
NS_ERR("too many partitions.\n"); NS_ERR("too many partitions.\n");
ret = -EINVAL; return -EINVAL;
goto error;
} }
remains = ns->geom.totsz; remains = ns->geom.totsz;
next_offset = 0; next_offset = 0;
...@@ -739,14 +739,12 @@ static int init_nandsim(struct mtd_info *mtd) ...@@ -739,14 +739,12 @@ static int init_nandsim(struct mtd_info *mtd)
if (!part_sz || part_sz > remains) { if (!part_sz || part_sz > remains) {
NS_ERR("bad partition size.\n"); NS_ERR("bad partition size.\n");
ret = -EINVAL; return -EINVAL;
goto error;
} }
ns->partitions[i].name = get_partition_name(i); ns->partitions[i].name = get_partition_name(i);
if (!ns->partitions[i].name) { if (!ns->partitions[i].name) {
NS_ERR("unable to allocate memory.\n"); NS_ERR("unable to allocate memory.\n");
ret = -ENOMEM; return -ENOMEM;
goto error;
} }
ns->partitions[i].offset = next_offset; ns->partitions[i].offset = next_offset;
ns->partitions[i].size = part_sz; ns->partitions[i].size = part_sz;
...@@ -757,14 +755,12 @@ static int init_nandsim(struct mtd_info *mtd) ...@@ -757,14 +755,12 @@ static int init_nandsim(struct mtd_info *mtd)
if (remains) { if (remains) {
if (parts_num + 1 > ARRAY_SIZE(ns->partitions)) { if (parts_num + 1 > ARRAY_SIZE(ns->partitions)) {
NS_ERR("too many partitions.\n"); NS_ERR("too many partitions.\n");
ret = -EINVAL; return -EINVAL;
goto error;
} }
ns->partitions[i].name = get_partition_name(i); ns->partitions[i].name = get_partition_name(i);
if (!ns->partitions[i].name) { if (!ns->partitions[i].name) {
NS_ERR("unable to allocate memory.\n"); NS_ERR("unable to allocate memory.\n");
ret = -ENOMEM; return -ENOMEM;
goto error;
} }
ns->partitions[i].offset = next_offset; ns->partitions[i].offset = next_offset;
ns->partitions[i].size = remains; ns->partitions[i].size = remains;
...@@ -792,24 +788,18 @@ static int init_nandsim(struct mtd_info *mtd) ...@@ -792,24 +788,18 @@ static int init_nandsim(struct mtd_info *mtd)
printk("options: %#x\n", ns->options); printk("options: %#x\n", ns->options);
if ((ret = alloc_device(ns)) != 0) if ((ret = alloc_device(ns)) != 0)
goto error; return ret;
/* Allocate / initialize the internal buffer */ /* Allocate / initialize the internal buffer */
ns->buf.byte = kmalloc(ns->geom.pgszoob, GFP_KERNEL); ns->buf.byte = kmalloc(ns->geom.pgszoob, GFP_KERNEL);
if (!ns->buf.byte) { if (!ns->buf.byte) {
NS_ERR("init_nandsim: unable to allocate %u bytes for the internal buffer\n", NS_ERR("init_nandsim: unable to allocate %u bytes for the internal buffer\n",
ns->geom.pgszoob); ns->geom.pgszoob);
ret = -ENOMEM; return -ENOMEM;
goto error;
} }
memset(ns->buf.byte, 0xFF, ns->geom.pgszoob); memset(ns->buf.byte, 0xFF, ns->geom.pgszoob);
return 0; return 0;
error:
free_device(ns);
return ret;
} }
/* /*
......
...@@ -574,5 +574,5 @@ module_platform_driver(elm_driver); ...@@ -574,5 +574,5 @@ module_platform_driver(elm_driver);
MODULE_DESCRIPTION("ELM driver for BCH error correction"); MODULE_DESCRIPTION("ELM driver for BCH error correction");
MODULE_AUTHOR("Texas Instruments"); MODULE_AUTHOR("Texas Instruments");
MODULE_ALIAS("platform: elm"); MODULE_ALIAS("platform:" DRIVER_NAME);
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
...@@ -45,10 +45,13 @@ ...@@ -45,10 +45,13 @@
/* /*
* Define a buffer size for the initial command that detects the flash device: * Define a buffer size for the initial command that detects the flash device:
* STATUS, READID and PARAM. The largest of these is the PARAM command, * STATUS, READID and PARAM.
* needing 256 bytes. * ONFI param page is 256 bytes, and there are three redundant copies
* to be read. JEDEC param page is 512 bytes, and there are also three
* redundant copies to be read.
* Hence this buffer should be at least 512 x 3. Let's pick 2048.
*/ */
#define INIT_BUFFER_SIZE 256 #define INIT_BUFFER_SIZE 2048
/* registers and bit definitions */ /* registers and bit definitions */
#define NDCR (0x00) /* Control register */ #define NDCR (0x00) /* Control register */
...@@ -126,6 +129,13 @@ ...@@ -126,6 +129,13 @@
#define EXT_CMD_TYPE_LAST_RW 1 /* Last naked read/write */ #define EXT_CMD_TYPE_LAST_RW 1 /* Last naked read/write */
#define EXT_CMD_TYPE_MONO 0 /* Monolithic read/write */ #define EXT_CMD_TYPE_MONO 0 /* Monolithic read/write */
/*
* This should be large enough to read 'ONFI' and 'JEDEC'.
* Let's use 7 bytes, which is the maximum ID count supported
* by the controller (see NDCR_RD_ID_CNT_MASK).
*/
#define READ_ID_BYTES 7
/* macros for registers read/write */ /* macros for registers read/write */
#define nand_writel(info, off, val) \ #define nand_writel(info, off, val) \
writel_relaxed((val), (info)->mmio_base + (off)) writel_relaxed((val), (info)->mmio_base + (off))
...@@ -173,8 +183,6 @@ struct pxa3xx_nand_host { ...@@ -173,8 +183,6 @@ struct pxa3xx_nand_host {
/* calculated from pxa3xx_nand_flash data */ /* calculated from pxa3xx_nand_flash data */
unsigned int col_addr_cycles; unsigned int col_addr_cycles;
unsigned int row_addr_cycles; unsigned int row_addr_cycles;
size_t read_id_bytes;
}; };
struct pxa3xx_nand_info { struct pxa3xx_nand_info {
...@@ -439,8 +447,8 @@ static void pxa3xx_nand_start(struct pxa3xx_nand_info *info) ...@@ -439,8 +447,8 @@ static void pxa3xx_nand_start(struct pxa3xx_nand_info *info)
ndcr |= NDCR_ND_RUN; ndcr |= NDCR_ND_RUN;
/* clear status bits and run */ /* clear status bits and run */
nand_writel(info, NDCR, 0);
nand_writel(info, NDSR, NDSR_MASK); nand_writel(info, NDSR, NDSR_MASK);
nand_writel(info, NDCR, 0);
nand_writel(info, NDCR, ndcr); nand_writel(info, NDCR, ndcr);
} }
...@@ -675,8 +683,14 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid) ...@@ -675,8 +683,14 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid)
is_ready = 1; is_ready = 1;
} }
/*
* Clear all status bit before issuing the next command, which
* can and will alter the status bits and will deserve a new
* interrupt on its own. This lets the controller exit the IRQ
*/
nand_writel(info, NDSR, status);
if (status & NDSR_WRCMDREQ) { if (status & NDSR_WRCMDREQ) {
nand_writel(info, NDSR, NDSR_WRCMDREQ);
status &= ~NDSR_WRCMDREQ; status &= ~NDSR_WRCMDREQ;
info->state = STATE_CMD_HANDLE; info->state = STATE_CMD_HANDLE;
...@@ -697,8 +711,6 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid) ...@@ -697,8 +711,6 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid)
nand_writel(info, NDCB0, info->ndcb3); nand_writel(info, NDCB0, info->ndcb3);
} }
/* clear NDSR to let the controller exit the IRQ */
nand_writel(info, NDSR, status);
if (is_completed) if (is_completed)
complete(&info->cmd_complete); complete(&info->cmd_complete);
if (is_ready) if (is_ready)
...@@ -899,18 +911,18 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command, ...@@ -899,18 +911,18 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command,
break; break;
case NAND_CMD_PARAM: case NAND_CMD_PARAM:
info->buf_count = 256; info->buf_count = INIT_BUFFER_SIZE;
info->ndcb0 |= NDCB0_CMD_TYPE(0) info->ndcb0 |= NDCB0_CMD_TYPE(0)
| NDCB0_ADDR_CYC(1) | NDCB0_ADDR_CYC(1)
| NDCB0_LEN_OVRD | NDCB0_LEN_OVRD
| command; | command;
info->ndcb1 = (column & 0xFF); info->ndcb1 = (column & 0xFF);
info->ndcb3 = 256; info->ndcb3 = INIT_BUFFER_SIZE;
info->data_size = 256; info->data_size = INIT_BUFFER_SIZE;
break; break;
case NAND_CMD_READID: case NAND_CMD_READID:
info->buf_count = host->read_id_bytes; info->buf_count = READ_ID_BYTES;
info->ndcb0 |= NDCB0_CMD_TYPE(3) info->ndcb0 |= NDCB0_CMD_TYPE(3)
| NDCB0_ADDR_CYC(1) | NDCB0_ADDR_CYC(1)
| command; | command;
...@@ -1247,9 +1259,6 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, ...@@ -1247,9 +1259,6 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info,
return -EINVAL; return -EINVAL;
} }
/* calculate flash information */
host->read_id_bytes = (f->page_size == 2048) ? 4 : 2;
/* calculate addressing information */ /* calculate addressing information */
host->col_addr_cycles = (f->page_size == 2048) ? 2 : 1; host->col_addr_cycles = (f->page_size == 2048) ? 2 : 1;
...@@ -1265,7 +1274,7 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, ...@@ -1265,7 +1274,7 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info,
ndcr |= (f->flash_width == 16) ? NDCR_DWIDTH_M : 0; ndcr |= (f->flash_width == 16) ? NDCR_DWIDTH_M : 0;
ndcr |= (f->dfc_width == 16) ? NDCR_DWIDTH_C : 0; ndcr |= (f->dfc_width == 16) ? NDCR_DWIDTH_C : 0;
ndcr |= NDCR_RD_ID_CNT(host->read_id_bytes); ndcr |= NDCR_RD_ID_CNT(READ_ID_BYTES);
ndcr |= NDCR_SPARE_EN; /* enable spare by default */ ndcr |= NDCR_SPARE_EN; /* enable spare by default */
info->reg_ndcr = ndcr; info->reg_ndcr = ndcr;
...@@ -1276,23 +1285,10 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, ...@@ -1276,23 +1285,10 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info,
static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info) static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info)
{ {
/*
* We set 0 by hard coding here, for we don't support keep_config
* when there is more than one chip attached to the controller
*/
struct pxa3xx_nand_host *host = info->host[0];
uint32_t ndcr = nand_readl(info, NDCR); uint32_t ndcr = nand_readl(info, NDCR);
if (ndcr & NDCR_PAGE_SZ) {
/* Controller's FIFO size */
info->chunk_size = 2048;
host->read_id_bytes = 4;
} else {
info->chunk_size = 512;
host->read_id_bytes = 2;
}
/* Set an initial chunk size */ /* Set an initial chunk size */
info->chunk_size = ndcr & NDCR_PAGE_SZ ? 2048 : 512;
info->reg_ndcr = ndcr & ~NDCR_INT_MASK; info->reg_ndcr = ndcr & ~NDCR_INT_MASK;
info->ndtr0cs0 = nand_readl(info, NDTR0CS0); info->ndtr0cs0 = nand_readl(info, NDTR0CS0);
info->ndtr1cs0 = nand_readl(info, NDTR1CS0); info->ndtr1cs0 = nand_readl(info, NDTR1CS0);
...@@ -1473,6 +1469,9 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) ...@@ -1473,6 +1469,9 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd)
if (pdata->keep_config && !pxa3xx_nand_detect_config(info)) if (pdata->keep_config && !pxa3xx_nand_detect_config(info))
goto KEEP_CONFIG; goto KEEP_CONFIG;
/* Set a default chunk size */
info->chunk_size = 512;
ret = pxa3xx_nand_sensing(info); ret = pxa3xx_nand_sensing(info);
if (ret) { if (ret) {
dev_info(&info->pdev->dev, "There is no chip on cs %d!\n", dev_info(&info->pdev->dev, "There is no chip on cs %d!\n",
......
...@@ -466,7 +466,7 @@ static int r852_ecc_calculate(struct mtd_info *mtd, const uint8_t *dat, ...@@ -466,7 +466,7 @@ static int r852_ecc_calculate(struct mtd_info *mtd, const uint8_t *dat,
static int r852_ecc_correct(struct mtd_info *mtd, uint8_t *dat, static int r852_ecc_correct(struct mtd_info *mtd, uint8_t *dat,
uint8_t *read_ecc, uint8_t *calc_ecc) uint8_t *read_ecc, uint8_t *calc_ecc)
{ {
uint16_t ecc_reg; uint32_t ecc_reg;
uint8_t ecc_status, err_byte; uint8_t ecc_status, err_byte;
int i, error = 0; int i, error = 0;
......
...@@ -99,6 +99,15 @@ ...@@ -99,6 +99,15 @@
NFC_CMD_INT_ENABLE | \ NFC_CMD_INT_ENABLE | \
NFC_DMA_INT_ENABLE) NFC_DMA_INT_ENABLE)
/* define bit use in NFC_TIMING_CTL */
#define NFC_TIMING_CTL_EDO BIT(8)
/* define NFC_TIMING_CFG register layout */
#define NFC_TIMING_CFG(tWB, tADL, tWHR, tRHW, tCAD) \
(((tWB) & 0x3) | (((tADL) & 0x3) << 2) | \
(((tWHR) & 0x3) << 4) | (((tRHW) & 0x3) << 6) | \
(((tCAD) & 0x7) << 8))
/* define bit use in NFC_CMD */ /* define bit use in NFC_CMD */
#define NFC_CMD_LOW_BYTE GENMASK(7, 0) #define NFC_CMD_LOW_BYTE GENMASK(7, 0)
#define NFC_CMD_HIGH_BYTE GENMASK(15, 8) #define NFC_CMD_HIGH_BYTE GENMASK(15, 8)
...@@ -208,6 +217,7 @@ struct sunxi_nand_hw_ecc { ...@@ -208,6 +217,7 @@ struct sunxi_nand_hw_ecc {
* @nand: base NAND chip structure * @nand: base NAND chip structure
* @mtd: base MTD structure * @mtd: base MTD structure
* @clk_rate: clk_rate required for this NAND chip * @clk_rate: clk_rate required for this NAND chip
* @timing_cfg TIMING_CFG register value for this NAND chip
* @selected: current active CS * @selected: current active CS
* @nsels: number of CS lines required by the NAND chip * @nsels: number of CS lines required by the NAND chip
* @sels: array of CS lines descriptions * @sels: array of CS lines descriptions
...@@ -217,6 +227,8 @@ struct sunxi_nand_chip { ...@@ -217,6 +227,8 @@ struct sunxi_nand_chip {
struct nand_chip nand; struct nand_chip nand;
struct mtd_info mtd; struct mtd_info mtd;
unsigned long clk_rate; unsigned long clk_rate;
u32 timing_cfg;
u32 timing_ctl;
int selected; int selected;
int nsels; int nsels;
struct sunxi_nand_chip_sel sels[0]; struct sunxi_nand_chip_sel sels[0];
...@@ -403,6 +415,8 @@ static void sunxi_nfc_select_chip(struct mtd_info *mtd, int chip) ...@@ -403,6 +415,8 @@ static void sunxi_nfc_select_chip(struct mtd_info *mtd, int chip)
} }
} }
writel(sunxi_nand->timing_ctl, nfc->regs + NFC_REG_TIMING_CTL);
writel(sunxi_nand->timing_cfg, nfc->regs + NFC_REG_TIMING_CFG);
writel(ctl, nfc->regs + NFC_REG_CTL); writel(ctl, nfc->regs + NFC_REG_CTL);
sunxi_nand->selected = chip; sunxi_nand->selected = chip;
...@@ -807,10 +821,33 @@ static int sunxi_nfc_hw_syndrome_ecc_write_page(struct mtd_info *mtd, ...@@ -807,10 +821,33 @@ static int sunxi_nfc_hw_syndrome_ecc_write_page(struct mtd_info *mtd,
return 0; return 0;
} }
static const s32 tWB_lut[] = {6, 12, 16, 20};
static const s32 tRHW_lut[] = {4, 8, 12, 20};
static int _sunxi_nand_lookup_timing(const s32 *lut, int lut_size, u32 duration,
u32 clk_period)
{
u32 clk_cycles = DIV_ROUND_UP(duration, clk_period);
int i;
for (i = 0; i < lut_size; i++) {
if (clk_cycles <= lut[i])
return i;
}
/* Doesn't fit */
return -EINVAL;
}
#define sunxi_nand_lookup_timing(l, p, c) \
_sunxi_nand_lookup_timing(l, ARRAY_SIZE(l), p, c)
static int sunxi_nand_chip_set_timings(struct sunxi_nand_chip *chip, static int sunxi_nand_chip_set_timings(struct sunxi_nand_chip *chip,
const struct nand_sdr_timings *timings) const struct nand_sdr_timings *timings)
{ {
struct sunxi_nfc *nfc = to_sunxi_nfc(chip->nand.controller);
u32 min_clk_period = 0; u32 min_clk_period = 0;
s32 tWB, tADL, tWHR, tRHW, tCAD;
/* T1 <=> tCLS */ /* T1 <=> tCLS */
if (timings->tCLS_min > min_clk_period) if (timings->tCLS_min > min_clk_period)
...@@ -872,6 +909,48 @@ static int sunxi_nand_chip_set_timings(struct sunxi_nand_chip *chip, ...@@ -872,6 +909,48 @@ static int sunxi_nand_chip_set_timings(struct sunxi_nand_chip *chip,
if (timings->tWC_min > (min_clk_period * 2)) if (timings->tWC_min > (min_clk_period * 2))
min_clk_period = DIV_ROUND_UP(timings->tWC_min, 2); min_clk_period = DIV_ROUND_UP(timings->tWC_min, 2);
/* T16 - T19 + tCAD */
tWB = sunxi_nand_lookup_timing(tWB_lut, timings->tWB_max,
min_clk_period);
if (tWB < 0) {
dev_err(nfc->dev, "unsupported tWB\n");
return tWB;
}
tADL = DIV_ROUND_UP(timings->tADL_min, min_clk_period) >> 3;
if (tADL > 3) {
dev_err(nfc->dev, "unsupported tADL\n");
return -EINVAL;
}
tWHR = DIV_ROUND_UP(timings->tWHR_min, min_clk_period) >> 3;
if (tWHR > 3) {
dev_err(nfc->dev, "unsupported tWHR\n");
return -EINVAL;
}
tRHW = sunxi_nand_lookup_timing(tRHW_lut, timings->tRHW_min,
min_clk_period);
if (tRHW < 0) {
dev_err(nfc->dev, "unsupported tRHW\n");
return tRHW;
}
/*
* TODO: according to ONFI specs this value only applies for DDR NAND,
* but Allwinner seems to set this to 0x7. Mimic them for now.
*/
tCAD = 0x7;
/* TODO: A83 has some more bits for CDQSS, CS, CLHZ, CCS, WC */
chip->timing_cfg = NFC_TIMING_CFG(tWB, tADL, tWHR, tRHW, tCAD);
/*
* ONFI specification 3.1, paragraph 4.15.2 dictates that EDO data
* output cycle timings shall be used if the host drives tRC less than
* 30 ns.
*/
chip->timing_ctl = (timings->tRC_min < 30000) ? NFC_TIMING_CTL_EDO : 0;
/* Convert min_clk_period from picoseconds to nanoseconds */ /* Convert min_clk_period from picoseconds to nanoseconds */
min_clk_period = DIV_ROUND_UP(min_clk_period, 1000); min_clk_period = DIV_ROUND_UP(min_clk_period, 1000);
...@@ -884,8 +963,6 @@ static int sunxi_nand_chip_set_timings(struct sunxi_nand_chip *chip, ...@@ -884,8 +963,6 @@ static int sunxi_nand_chip_set_timings(struct sunxi_nand_chip *chip,
*/ */
chip->clk_rate = (2 * NSEC_PER_SEC) / min_clk_period; chip->clk_rate = (2 * NSEC_PER_SEC) / min_clk_period;
/* TODO: configure T16-T19 */
return 0; return 0;
} }
...@@ -1376,13 +1453,6 @@ static int sunxi_nfc_probe(struct platform_device *pdev) ...@@ -1376,13 +1453,6 @@ static int sunxi_nfc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, nfc); platform_set_drvdata(pdev, nfc);
/*
* TODO: replace these magic values with proper flags as soon as we
* know what they are encoding.
*/
writel(0x100, nfc->regs + NFC_REG_TIMING_CTL);
writel(0x7ff, nfc->regs + NFC_REG_TIMING_CFG);
ret = sunxi_nand_chips_init(dev, nfc); ret = sunxi_nand_chips_init(dev, nfc);
if (ret) { if (ret) {
dev_err(dev, "failed to init nand chips\n"); dev_err(dev, "failed to init nand chips\n");
......
...@@ -26,6 +26,18 @@ config SPI_FSL_QUADSPI ...@@ -26,6 +26,18 @@ config SPI_FSL_QUADSPI
depends on ARCH_MXC depends on ARCH_MXC
help help
This enables support for the Quad SPI controller in master mode. This enables support for the Quad SPI controller in master mode.
We only connect the NOR to this controller now. This controller does not support generic SPI. It only supports
SPI NOR.
config SPI_NXP_SPIFI
tristate "NXP SPI Flash Interface (SPIFI)"
depends on OF && (ARCH_LPC18XX || COMPILE_TEST)
depends on HAS_IOMEM
help
Enable support for the NXP LPC SPI Flash Interface controller.
SPIFI is a specialized controller for connecting serial SPI
Flash. Enable this option if you have a device with a SPIFI
controller and want to access the Flash as a mtd device.
endif # MTD_SPI_NOR endif # MTD_SPI_NOR
obj-$(CONFIG_MTD_SPI_NOR) += spi-nor.o obj-$(CONFIG_MTD_SPI_NOR) += spi-nor.o
obj-$(CONFIG_SPI_FSL_QUADSPI) += fsl-quadspi.o obj-$(CONFIG_SPI_FSL_QUADSPI) += fsl-quadspi.o
obj-$(CONFIG_SPI_NXP_SPIFI) += nxp-spifi.o
This diff is collapsed.
This diff is collapsed.
...@@ -29,6 +29,8 @@ ...@@ -29,6 +29,8 @@
#define SPI_NOR_MAX_ID_LEN 6 #define SPI_NOR_MAX_ID_LEN 6
struct flash_info { struct flash_info {
char *name;
/* /*
* This array stores the ID bytes. * This array stores the ID bytes.
* The first three bytes are the JEDIC ID. * The first three bytes are the JEDIC ID.
...@@ -59,7 +61,7 @@ struct flash_info { ...@@ -59,7 +61,7 @@ struct flash_info {
#define JEDEC_MFR(info) ((info)->id[0]) #define JEDEC_MFR(info) ((info)->id[0])
static const struct spi_device_id *spi_nor_match_id(const char *name); static const struct flash_info *spi_nor_match_id(const char *name);
/* /*
* Read the status register, returning its value in the location * Read the status register, returning its value in the location
...@@ -169,7 +171,7 @@ static inline struct spi_nor *mtd_to_spi_nor(struct mtd_info *mtd) ...@@ -169,7 +171,7 @@ static inline struct spi_nor *mtd_to_spi_nor(struct mtd_info *mtd)
} }
/* Enable/disable 4-byte addressing mode. */ /* Enable/disable 4-byte addressing mode. */
static inline int set_4byte(struct spi_nor *nor, struct flash_info *info, static inline int set_4byte(struct spi_nor *nor, const struct flash_info *info,
int enable) int enable)
{ {
int status; int status;
...@@ -469,7 +471,6 @@ static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) ...@@ -469,7 +471,6 @@ static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
/* Used when the "_ext_id" is two bytes at most */ /* Used when the "_ext_id" is two bytes at most */
#define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \ #define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \
((kernel_ulong_t)&(struct flash_info) { \
.id = { \ .id = { \
((_jedec_id) >> 16) & 0xff, \ ((_jedec_id) >> 16) & 0xff, \
((_jedec_id) >> 8) & 0xff, \ ((_jedec_id) >> 8) & 0xff, \
...@@ -481,11 +482,9 @@ static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) ...@@ -481,11 +482,9 @@ static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
.sector_size = (_sector_size), \ .sector_size = (_sector_size), \
.n_sectors = (_n_sectors), \ .n_sectors = (_n_sectors), \
.page_size = 256, \ .page_size = 256, \
.flags = (_flags), \ .flags = (_flags),
})
#define INFO6(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \ #define INFO6(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \
((kernel_ulong_t)&(struct flash_info) { \
.id = { \ .id = { \
((_jedec_id) >> 16) & 0xff, \ ((_jedec_id) >> 16) & 0xff, \
((_jedec_id) >> 8) & 0xff, \ ((_jedec_id) >> 8) & 0xff, \
...@@ -498,17 +497,14 @@ static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) ...@@ -498,17 +497,14 @@ static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
.sector_size = (_sector_size), \ .sector_size = (_sector_size), \
.n_sectors = (_n_sectors), \ .n_sectors = (_n_sectors), \
.page_size = 256, \ .page_size = 256, \
.flags = (_flags), \ .flags = (_flags),
})
#define CAT25_INFO(_sector_size, _n_sectors, _page_size, _addr_width, _flags) \ #define CAT25_INFO(_sector_size, _n_sectors, _page_size, _addr_width, _flags) \
((kernel_ulong_t)&(struct flash_info) { \
.sector_size = (_sector_size), \ .sector_size = (_sector_size), \
.n_sectors = (_n_sectors), \ .n_sectors = (_n_sectors), \
.page_size = (_page_size), \ .page_size = (_page_size), \
.addr_width = (_addr_width), \ .addr_width = (_addr_width), \
.flags = (_flags), \ .flags = (_flags),
})
/* NOTE: double check command sets and memory organization when you add /* NOTE: double check command sets and memory organization when you add
* more nor chips. This current list focusses on newer chips, which * more nor chips. This current list focusses on newer chips, which
...@@ -521,7 +517,7 @@ static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) ...@@ -521,7 +517,7 @@ static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
* For historical (and compatibility) reasons (before we got above config) some * For historical (and compatibility) reasons (before we got above config) some
* old entries may be missing 4K flag. * old entries may be missing 4K flag.
*/ */
static const struct spi_device_id spi_nor_ids[] = { static const struct flash_info spi_nor_ids[] = {
/* Atmel -- some are (confusingly) marketed as "DataFlash" */ /* Atmel -- some are (confusingly) marketed as "DataFlash" */
{ "at25fs010", INFO(0x1f6601, 0, 32 * 1024, 4, SECT_4K) }, { "at25fs010", INFO(0x1f6601, 0, 32 * 1024, 4, SECT_4K) },
{ "at25fs040", INFO(0x1f6604, 0, 64 * 1024, 8, SECT_4K) }, { "at25fs040", INFO(0x1f6604, 0, 64 * 1024, 8, SECT_4K) },
...@@ -589,7 +585,7 @@ static const struct spi_device_id spi_nor_ids[] = { ...@@ -589,7 +585,7 @@ static const struct spi_device_id spi_nor_ids[] = {
/* Micron */ /* Micron */
{ "n25q032", INFO(0x20ba16, 0, 64 * 1024, 64, SPI_NOR_QUAD_READ) }, { "n25q032", INFO(0x20ba16, 0, 64 * 1024, 64, SPI_NOR_QUAD_READ) },
{ "n25q064", INFO(0x20ba17, 0, 64 * 1024, 128, SPI_NOR_QUAD_READ) }, { "n25q064", INFO(0x20ba17, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_QUAD_READ) },
{ "n25q128a11", INFO(0x20bb18, 0, 64 * 1024, 256, SPI_NOR_QUAD_READ) }, { "n25q128a11", INFO(0x20bb18, 0, 64 * 1024, 256, SPI_NOR_QUAD_READ) },
{ "n25q128a13", INFO(0x20ba18, 0, 64 * 1024, 256, SPI_NOR_QUAD_READ) }, { "n25q128a13", INFO(0x20ba18, 0, 64 * 1024, 256, SPI_NOR_QUAD_READ) },
{ "n25q256a", INFO(0x20ba19, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_QUAD_READ) }, { "n25q256a", INFO(0x20ba19, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_QUAD_READ) },
...@@ -626,6 +622,7 @@ static const struct spi_device_id spi_nor_ids[] = { ...@@ -626,6 +622,7 @@ static const struct spi_device_id spi_nor_ids[] = {
{ "s25fl064k", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) }, { "s25fl064k", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) },
{ "s25fl132k", INFO(0x014016, 0, 64 * 1024, 64, SECT_4K) }, { "s25fl132k", INFO(0x014016, 0, 64 * 1024, 64, SECT_4K) },
{ "s25fl164k", INFO(0x014017, 0, 64 * 1024, 128, SECT_4K) }, { "s25fl164k", INFO(0x014017, 0, 64 * 1024, 128, SECT_4K) },
{ "s25fl204k", INFO(0x014013, 0, 64 * 1024, 8, SECT_4K) },
/* SST -- large erase sizes are "overlays", "sectors" are 4K */ /* SST -- large erase sizes are "overlays", "sectors" are 4K */
{ "sst25vf040b", INFO(0xbf258d, 0, 64 * 1024, 8, SECT_4K | SST_WRITE) }, { "sst25vf040b", INFO(0xbf258d, 0, 64 * 1024, 8, SECT_4K | SST_WRITE) },
...@@ -702,11 +699,11 @@ static const struct spi_device_id spi_nor_ids[] = { ...@@ -702,11 +699,11 @@ static const struct spi_device_id spi_nor_ids[] = {
{ }, { },
}; };
static const struct spi_device_id *spi_nor_read_id(struct spi_nor *nor) static const struct flash_info *spi_nor_read_id(struct spi_nor *nor)
{ {
int tmp; int tmp;
u8 id[SPI_NOR_MAX_ID_LEN]; u8 id[SPI_NOR_MAX_ID_LEN];
struct flash_info *info; const struct flash_info *info;
tmp = nor->read_reg(nor, SPINOR_OP_RDID, id, SPI_NOR_MAX_ID_LEN); tmp = nor->read_reg(nor, SPINOR_OP_RDID, id, SPI_NOR_MAX_ID_LEN);
if (tmp < 0) { if (tmp < 0) {
...@@ -715,7 +712,7 @@ static const struct spi_device_id *spi_nor_read_id(struct spi_nor *nor) ...@@ -715,7 +712,7 @@ static const struct spi_device_id *spi_nor_read_id(struct spi_nor *nor)
} }
for (tmp = 0; tmp < ARRAY_SIZE(spi_nor_ids) - 1; tmp++) { for (tmp = 0; tmp < ARRAY_SIZE(spi_nor_ids) - 1; tmp++) {
info = (void *)spi_nor_ids[tmp].driver_data; info = &spi_nor_ids[tmp];
if (info->id_len) { if (info->id_len) {
if (!memcmp(info->id, id, info->id_len)) if (!memcmp(info->id, id, info->id_len))
return &spi_nor_ids[tmp]; return &spi_nor_ids[tmp];
...@@ -961,7 +958,7 @@ static int micron_quad_enable(struct spi_nor *nor) ...@@ -961,7 +958,7 @@ static int micron_quad_enable(struct spi_nor *nor)
return 0; return 0;
} }
static int set_quad_mode(struct spi_nor *nor, struct flash_info *info) static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info)
{ {
int status; int status;
...@@ -1003,8 +1000,7 @@ static int spi_nor_check(struct spi_nor *nor) ...@@ -1003,8 +1000,7 @@ static int spi_nor_check(struct spi_nor *nor)
int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode) int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
{ {
const struct spi_device_id *id = NULL; const struct flash_info *info = NULL;
struct flash_info *info;
struct device *dev = nor->dev; struct device *dev = nor->dev;
struct mtd_info *mtd = nor->mtd; struct mtd_info *mtd = nor->mtd;
struct device_node *np = dev->of_node; struct device_node *np = dev->of_node;
...@@ -1015,27 +1011,25 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode) ...@@ -1015,27 +1011,25 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
if (ret) if (ret)
return ret; return ret;
/* Try to auto-detect if chip name wasn't specified */ if (name)
if (!name) info = spi_nor_match_id(name);
id = spi_nor_read_id(nor); /* Try to auto-detect if chip name wasn't specified or not found */
else if (!info)
id = spi_nor_match_id(name); info = spi_nor_read_id(nor);
if (IS_ERR_OR_NULL(id)) if (IS_ERR_OR_NULL(info))
return -ENOENT; return -ENOENT;
info = (void *)id->driver_data;
/* /*
* If caller has specified name of flash model that can normally be * If caller has specified name of flash model that can normally be
* detected using JEDEC, let's verify it. * detected using JEDEC, let's verify it.
*/ */
if (name && info->id_len) { if (name && info->id_len) {
const struct spi_device_id *jid; const struct flash_info *jinfo;
jid = spi_nor_read_id(nor); jinfo = spi_nor_read_id(nor);
if (IS_ERR(jid)) { if (IS_ERR(jinfo)) {
return PTR_ERR(jid); return PTR_ERR(jinfo);
} else if (jid != id) { } else if (jinfo != info) {
/* /*
* JEDEC knows better, so overwrite platform ID. We * JEDEC knows better, so overwrite platform ID. We
* can't trust partitions any longer, but we'll let * can't trust partitions any longer, but we'll let
...@@ -1044,9 +1038,8 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode) ...@@ -1044,9 +1038,8 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
* information, even if it's not 100% accurate. * information, even if it's not 100% accurate.
*/ */
dev_warn(dev, "found %s, expected %s\n", dev_warn(dev, "found %s, expected %s\n",
jid->name, id->name); jinfo->name, info->name);
id = jid; info = jinfo;
info = (void *)jid->driver_data;
} }
} }
...@@ -1196,7 +1189,7 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode) ...@@ -1196,7 +1189,7 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
nor->read_dummy = spi_nor_read_dummy_cycles(nor); nor->read_dummy = spi_nor_read_dummy_cycles(nor);
dev_info(dev, "%s (%lld Kbytes)\n", id->name, dev_info(dev, "%s (%lld Kbytes)\n", info->name,
(long long)mtd->size >> 10); (long long)mtd->size >> 10);
dev_dbg(dev, dev_dbg(dev,
...@@ -1219,9 +1212,9 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode) ...@@ -1219,9 +1212,9 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
} }
EXPORT_SYMBOL_GPL(spi_nor_scan); EXPORT_SYMBOL_GPL(spi_nor_scan);
static const struct spi_device_id *spi_nor_match_id(const char *name) static const struct flash_info *spi_nor_match_id(const char *name)
{ {
const struct spi_device_id *id = spi_nor_ids; const struct flash_info *id = spi_nor_ids;
while (id->name[0]) { while (id->name[0]) {
if (!strcmp(name, id->name)) if (!strcmp(name, id->name))
......
...@@ -125,7 +125,8 @@ static int write_whole_device(void) ...@@ -125,7 +125,8 @@ static int write_whole_device(void)
* Display the address, offset and data bytes at comparison failure. * Display the address, offset and data bytes at comparison failure.
* Return number of bitflips encountered. * Return number of bitflips encountered.
*/ */
static size_t memcmpshow(loff_t addr, const void *cs, const void *ct, size_t count) static size_t memcmpshowoffset(loff_t addr, loff_t offset, const void *cs,
const void *ct, size_t count)
{ {
const unsigned char *su1, *su2; const unsigned char *su1, *su2;
int res; int res;
...@@ -135,8 +136,9 @@ static size_t memcmpshow(loff_t addr, const void *cs, const void *ct, size_t cou ...@@ -135,8 +136,9 @@ static size_t memcmpshow(loff_t addr, const void *cs, const void *ct, size_t cou
for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--, i++) { for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--, i++) {
res = *su1 ^ *su2; res = *su1 ^ *su2;
if (res) { if (res) {
pr_info("error @addr[0x%lx:0x%zx] 0x%x -> 0x%x diff 0x%x\n", pr_info("error @addr[0x%lx:0x%lx] 0x%x -> 0x%x diff 0x%x\n",
(unsigned long)addr, i, *su1, *su2, res); (unsigned long)addr, (unsigned long)offset + i,
*su1, *su2, res);
bitflips += hweight8(res); bitflips += hweight8(res);
} }
} }
...@@ -144,6 +146,9 @@ static size_t memcmpshow(loff_t addr, const void *cs, const void *ct, size_t cou ...@@ -144,6 +146,9 @@ static size_t memcmpshow(loff_t addr, const void *cs, const void *ct, size_t cou
return bitflips; return bitflips;
} }
#define memcmpshow(addr, cs, ct, count) memcmpshowoffset((addr), 0, (cs), (ct),\
(count))
/* /*
* Compare with 0xff and show the address, offset and data bytes at * Compare with 0xff and show the address, offset and data bytes at
* comparison failure. Return number of bitflips encountered. * comparison failure. Return number of bitflips encountered.
...@@ -228,9 +233,10 @@ static int verify_eraseblock(int ebnum) ...@@ -228,9 +233,10 @@ static int verify_eraseblock(int ebnum)
errcnt += 1; errcnt += 1;
return err ? err : -1; return err ? err : -1;
} }
bitflips = memcmpshow(addr, readbuf + use_offset, bitflips = memcmpshowoffset(addr, use_offset,
writebuf + (use_len_max * i) + use_offset, readbuf + use_offset,
use_len); writebuf + (use_len_max * i) + use_offset,
use_len);
/* verify pre-offset area for 0xff */ /* verify pre-offset area for 0xff */
bitflips += memffshow(addr, 0, readbuf, use_offset); bitflips += memffshow(addr, 0, readbuf, use_offset);
......
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