diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-09-02 15:16:24 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-09-02 15:16:24 -0400 |
commit | 91a247d7d3694a161092931ea4e0b13c11b8e9a0 (patch) | |
tree | e7b7f1cf30ba702e533a95e7ae1939efee3c9e8f | |
parent | 8bdc69b764013a9b5ebeef7df8f314f1066c5d79 (diff) | |
parent | 718e38b4d96085b4dab08d3d32e5e033aa1ba6e9 (diff) |
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
...
-rw-r--r-- | Documentation/devicetree/bindings/mtd/fsl-quadspi.txt | 3 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/mtd/nxp-spifi.txt | 58 | ||||
-rw-r--r-- | drivers/mtd/devices/m25p80.c | 18 | ||||
-rw-r--r-- | drivers/mtd/devices/mtd_dataflash.c | 1 | ||||
-rw-r--r-- | drivers/mtd/maps/nettel.c | 13 | ||||
-rw-r--r-- | drivers/mtd/maps/physmap_of.c | 6 | ||||
-rw-r--r-- | drivers/mtd/mtd_blkdevs.c | 8 | ||||
-rw-r--r-- | drivers/mtd/nand/Kconfig | 13 | ||||
-rw-r--r-- | drivers/mtd/nand/brcmnand/brcmnand.h | 4 | ||||
-rw-r--r-- | drivers/mtd/nand/davinci_nand.c | 42 | ||||
-rw-r--r-- | drivers/mtd/nand/denali_pci.c | 43 | ||||
-rw-r--r-- | drivers/mtd/nand/nand_ids.c | 4 | ||||
-rw-r--r-- | drivers/mtd/nand/nandsim.c | 28 | ||||
-rw-r--r-- | drivers/mtd/nand/omap_elm.c | 2 | ||||
-rw-r--r-- | drivers/mtd/nand/pxa3xx_nand.c | 61 | ||||
-rw-r--r-- | drivers/mtd/nand/r852.c | 2 | ||||
-rw-r--r-- | drivers/mtd/nand/sunxi_nand.c | 88 | ||||
-rw-r--r-- | drivers/mtd/spi-nor/Kconfig | 14 | ||||
-rw-r--r-- | drivers/mtd/spi-nor/Makefile | 1 | ||||
-rw-r--r-- | drivers/mtd/spi-nor/fsl-quadspi.c | 265 | ||||
-rw-r--r-- | drivers/mtd/spi-nor/nxp-spifi.c | 482 | ||||
-rw-r--r-- | drivers/mtd/spi-nor/spi-nor.c | 69 | ||||
-rw-r--r-- | drivers/mtd/tests/oobtest.c | 18 |
23 files changed, 1010 insertions, 233 deletions
diff --git a/Documentation/devicetree/bindings/mtd/fsl-quadspi.txt b/Documentation/devicetree/bindings/mtd/fsl-quadspi.txt index 4461dc71cb10..862aa2f8837a 100644 --- a/Documentation/devicetree/bindings/mtd/fsl-quadspi.txt +++ b/Documentation/devicetree/bindings/mtd/fsl-quadspi.txt | |||
@@ -1,7 +1,8 @@ | |||
1 | * Freescale Quad Serial Peripheral Interface(QuadSPI) | 1 | * Freescale Quad Serial Peripheral Interface(QuadSPI) |
2 | 2 | ||
3 | Required properties: | 3 | Required properties: |
4 | - compatible : Should be "fsl,vf610-qspi" or "fsl,imx6sx-qspi" | 4 | - compatible : Should be "fsl,vf610-qspi", "fsl,imx6sx-qspi", |
5 | "fsl,imx7d-qspi", "fsl,imx6ul-qspi" | ||
5 | - reg : the first contains the register location and length, | 6 | - reg : the first contains the register location and length, |
6 | the second contains the memory mapping address and length | 7 | the second contains the memory mapping address and length |
7 | - reg-names: Should contain the reg names "QuadSPI" and "QuadSPI-memory" | 8 | - reg-names: Should contain the reg names "QuadSPI" and "QuadSPI-memory" |
diff --git a/Documentation/devicetree/bindings/mtd/nxp-spifi.txt b/Documentation/devicetree/bindings/mtd/nxp-spifi.txt new file mode 100644 index 000000000000..f8b6b250654e --- /dev/null +++ b/Documentation/devicetree/bindings/mtd/nxp-spifi.txt | |||
@@ -0,0 +1,58 @@ | |||
1 | * NXP SPI Flash Interface (SPIFI) | ||
2 | |||
3 | NXP SPIFI is a specialized SPI interface for serial Flash devices. | ||
4 | It supports one Flash device with 1-, 2- and 4-bits width in SPI | ||
5 | mode 0 or 3. The controller operates in either command or memory | ||
6 | mode. In memory mode the Flash is accessible from the CPU as | ||
7 | normal memory. | ||
8 | |||
9 | Required properties: | ||
10 | - compatible : Should be "nxp,lpc1773-spifi" | ||
11 | - reg : the first contains the register location and length, | ||
12 | the second contains the memory mapping address and length | ||
13 | - reg-names: Should contain the reg names "spifi" and "flash" | ||
14 | - interrupts : Should contain the interrupt for the device | ||
15 | - clocks : The clocks needed by the SPIFI controller | ||
16 | - clock-names : Should contain the clock names "spifi" and "reg" | ||
17 | |||
18 | Optional properties: | ||
19 | - resets : phandle + reset specifier | ||
20 | |||
21 | The SPI Flash must be a child of the SPIFI node and must have a | ||
22 | compatible property as specified in bindings/mtd/jedec,spi-nor.txt | ||
23 | |||
24 | Optionally it can also contain the following properties. | ||
25 | - spi-cpol : Controller only supports mode 0 and 3 so either | ||
26 | both spi-cpol and spi-cpha should be present or | ||
27 | none of them | ||
28 | - spi-cpha : See above | ||
29 | - spi-rx-bus-width : Used to select how many pins that are used | ||
30 | for input on the controller | ||
31 | |||
32 | See bindings/spi/spi-bus.txt for more information. | ||
33 | |||
34 | Example: | ||
35 | spifi: spifi@40003000 { | ||
36 | compatible = "nxp,lpc1773-spifi"; | ||
37 | reg = <0x40003000 0x1000>, <0x14000000 0x4000000>; | ||
38 | reg-names = "spifi", "flash"; | ||
39 | interrupts = <30>; | ||
40 | clocks = <&ccu1 CLK_SPIFI>, <&ccu1 CLK_CPU_SPIFI>; | ||
41 | clock-names = "spifi", "reg"; | ||
42 | resets = <&rgu 53>; | ||
43 | |||
44 | flash@0 { | ||
45 | compatible = "jedec,spi-nor"; | ||
46 | spi-cpol; | ||
47 | spi-cpha; | ||
48 | spi-rx-bus-width = <4>; | ||
49 | #address-cells = <1>; | ||
50 | #size-cells = <1>; | ||
51 | |||
52 | partition@0 { | ||
53 | label = "data"; | ||
54 | reg = <0 0x200000>; | ||
55 | }; | ||
56 | }; | ||
57 | }; | ||
58 | |||
diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index d313f948b96c..9cd3631170ef 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c | |||
@@ -223,8 +223,6 @@ static int m25p_probe(struct spi_device *spi) | |||
223 | */ | 223 | */ |
224 | if (data && data->type) | 224 | if (data && data->type) |
225 | flash_name = data->type; | 225 | flash_name = data->type; |
226 | else if (!strcmp(spi->modalias, "spi-nor")) | ||
227 | flash_name = NULL; /* auto-detect */ | ||
228 | else | 226 | else |
229 | flash_name = spi->modalias; | 227 | flash_name = spi->modalias; |
230 | 228 | ||
@@ -289,19 +287,25 @@ static const struct spi_device_id m25p_ids[] = { | |||
289 | {"m25p40-nonjedec"}, {"m25p80-nonjedec"}, {"m25p16-nonjedec"}, | 287 | {"m25p40-nonjedec"}, {"m25p80-nonjedec"}, {"m25p16-nonjedec"}, |
290 | {"m25p32-nonjedec"}, {"m25p64-nonjedec"}, {"m25p128-nonjedec"}, | 288 | {"m25p32-nonjedec"}, {"m25p64-nonjedec"}, {"m25p128-nonjedec"}, |
291 | 289 | ||
292 | /* | ||
293 | * Generic support for SPI NOR that can be identified by the JEDEC READ | ||
294 | * ID opcode (0x9F). Use this, if possible. | ||
295 | */ | ||
296 | {"spi-nor"}, | ||
297 | { }, | 290 | { }, |
298 | }; | 291 | }; |
299 | MODULE_DEVICE_TABLE(spi, m25p_ids); | 292 | MODULE_DEVICE_TABLE(spi, m25p_ids); |
300 | 293 | ||
294 | static const struct of_device_id m25p_of_table[] = { | ||
295 | /* | ||
296 | * Generic compatibility for SPI NOR that can be identified by the | ||
297 | * JEDEC READ ID opcode (0x9F). Use this, if possible. | ||
298 | */ | ||
299 | { .compatible = "jedec,spi-nor" }, | ||
300 | {} | ||
301 | }; | ||
302 | MODULE_DEVICE_TABLE(of, m25p_of_table); | ||
303 | |||
301 | static struct spi_driver m25p80_driver = { | 304 | static struct spi_driver m25p80_driver = { |
302 | .driver = { | 305 | .driver = { |
303 | .name = "m25p80", | 306 | .name = "m25p80", |
304 | .owner = THIS_MODULE, | 307 | .owner = THIS_MODULE, |
308 | .of_match_table = m25p_of_table, | ||
305 | }, | 309 | }, |
306 | .id_table = m25p_ids, | 310 | .id_table = m25p_ids, |
307 | .probe = m25p_probe, | 311 | .probe = m25p_probe, |
diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c index 0099aba72a8b..df6f61137376 100644 --- a/drivers/mtd/devices/mtd_dataflash.c +++ b/drivers/mtd/devices/mtd_dataflash.c | |||
@@ -102,6 +102,7 @@ static const struct of_device_id dataflash_dt_ids[] = { | |||
102 | { .compatible = "atmel,dataflash", }, | 102 | { .compatible = "atmel,dataflash", }, |
103 | { /* sentinel */ } | 103 | { /* sentinel */ } |
104 | }; | 104 | }; |
105 | MODULE_DEVICE_TABLE(of, dataflash_dt_ids); | ||
105 | #endif | 106 | #endif |
106 | 107 | ||
107 | /* ......................................................................... */ | 108 | /* ......................................................................... */ |
diff --git a/drivers/mtd/maps/nettel.c b/drivers/mtd/maps/nettel.c index eadcfffc4f9c..a577ef8553d0 100644 --- a/drivers/mtd/maps/nettel.c +++ b/drivers/mtd/maps/nettel.c | |||
@@ -385,20 +385,28 @@ static int __init nettel_init(void) | |||
385 | } | 385 | } |
386 | rc = mtd_device_register(intel_mtd, nettel_intel_partitions, | 386 | rc = mtd_device_register(intel_mtd, nettel_intel_partitions, |
387 | num_intel_partitions); | 387 | num_intel_partitions); |
388 | if (rc) | ||
389 | goto out_map_destroy; | ||
388 | #endif | 390 | #endif |
389 | 391 | ||
390 | if (amd_mtd) { | 392 | if (amd_mtd) { |
391 | rc = mtd_device_register(amd_mtd, nettel_amd_partitions, | 393 | rc = mtd_device_register(amd_mtd, nettel_amd_partitions, |
392 | num_amd_partitions); | 394 | num_amd_partitions); |
395 | if (rc) | ||
396 | goto out_mtd_unreg; | ||
393 | } | 397 | } |
394 | 398 | ||
395 | #ifdef CONFIG_MTD_CFI_INTELEXT | 399 | #ifdef CONFIG_MTD_CFI_INTELEXT |
396 | register_reboot_notifier(&nettel_notifier_block); | 400 | register_reboot_notifier(&nettel_notifier_block); |
397 | #endif | 401 | #endif |
398 | 402 | ||
399 | return(rc); | 403 | return rc; |
400 | 404 | ||
405 | out_mtd_unreg: | ||
401 | #ifdef CONFIG_MTD_CFI_INTELEXT | 406 | #ifdef CONFIG_MTD_CFI_INTELEXT |
407 | mtd_device_unregister(intel_mtd); | ||
408 | out_map_destroy: | ||
409 | map_destroy(intel_mtd); | ||
402 | out_unmap1: | 410 | out_unmap1: |
403 | iounmap(nettel_intel_map.virt); | 411 | iounmap(nettel_intel_map.virt); |
404 | #endif | 412 | #endif |
@@ -407,8 +415,7 @@ out_unmap2: | |||
407 | iounmap(nettel_mmcrp); | 415 | iounmap(nettel_mmcrp); |
408 | iounmap(nettel_amd_map.virt); | 416 | iounmap(nettel_amd_map.virt); |
409 | 417 | ||
410 | return(rc); | 418 | return rc; |
411 | |||
412 | } | 419 | } |
413 | 420 | ||
414 | /****************************************************************************/ | 421 | /****************************************************************************/ |
diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c index 774b32fd29e6..3e614e9119d5 100644 --- a/drivers/mtd/maps/physmap_of.c +++ b/drivers/mtd/maps/physmap_of.c | |||
@@ -130,6 +130,8 @@ static const char * const *of_get_probes(struct device_node *dp) | |||
130 | count++; | 130 | count++; |
131 | 131 | ||
132 | res = kzalloc((count + 1)*sizeof(*res), GFP_KERNEL); | 132 | res = kzalloc((count + 1)*sizeof(*res), GFP_KERNEL); |
133 | if (!res) | ||
134 | return NULL; | ||
133 | count = 0; | 135 | count = 0; |
134 | while (cplen > 0) { | 136 | while (cplen > 0) { |
135 | res[count] = cp; | 137 | res[count] = cp; |
@@ -311,6 +313,10 @@ static int of_flash_probe(struct platform_device *dev) | |||
311 | 313 | ||
312 | ppdata.of_node = dp; | 314 | ppdata.of_node = dp; |
313 | part_probe_types = of_get_probes(dp); | 315 | part_probe_types = of_get_probes(dp); |
316 | if (!part_probe_types) { | ||
317 | err = -ENOMEM; | ||
318 | goto err_out; | ||
319 | } | ||
314 | mtd_device_parse_register(info->cmtd, part_probe_types, &ppdata, | 320 | mtd_device_parse_register(info->cmtd, part_probe_types, &ppdata, |
315 | NULL, 0); | 321 | NULL, 0); |
316 | of_free_probes(part_probe_types); | 322 | of_free_probes(part_probe_types); |
diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c index 41acc507b22e..88304751eb8a 100644 --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c | |||
@@ -97,14 +97,13 @@ static int do_blktrans_request(struct mtd_blktrans_ops *tr, | |||
97 | if (req->cmd_flags & REQ_DISCARD) | 97 | if (req->cmd_flags & REQ_DISCARD) |
98 | return tr->discard(dev, block, nsect); | 98 | return tr->discard(dev, block, nsect); |
99 | 99 | ||
100 | switch(rq_data_dir(req)) { | 100 | if (rq_data_dir(req) == READ) { |
101 | case READ: | ||
102 | for (; nsect > 0; nsect--, block++, buf += tr->blksize) | 101 | for (; nsect > 0; nsect--, block++, buf += tr->blksize) |
103 | if (tr->readsect(dev, block, buf)) | 102 | if (tr->readsect(dev, block, buf)) |
104 | return -EIO; | 103 | return -EIO; |
105 | rq_flush_dcache_pages(req); | 104 | rq_flush_dcache_pages(req); |
106 | return 0; | 105 | return 0; |
107 | case WRITE: | 106 | } else { |
108 | if (!tr->writesect) | 107 | if (!tr->writesect) |
109 | return -EIO; | 108 | return -EIO; |
110 | 109 | ||
@@ -113,9 +112,6 @@ static int do_blktrans_request(struct mtd_blktrans_ops *tr, | |||
113 | if (tr->writesect(dev, block, buf)) | 112 | if (tr->writesect(dev, block, buf)) |
114 | return -EIO; | 113 | return -EIO; |
115 | return 0; | 114 | return 0; |
116 | default: | ||
117 | printk(KERN_NOTICE "Unknown request %u\n", rq_data_dir(req)); | ||
118 | return -EIO; | ||
119 | } | 115 | } |
120 | } | 116 | } |
121 | 117 | ||
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 5b2806a7e5f7..3324281d1f53 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig | |||
@@ -42,23 +42,20 @@ config MTD_SM_COMMON | |||
42 | default n | 42 | default n |
43 | 43 | ||
44 | config MTD_NAND_DENALI | 44 | config MTD_NAND_DENALI |
45 | tristate "Support Denali NAND controller" | 45 | tristate |
46 | depends on HAS_DMA | ||
47 | help | ||
48 | Enable support for the Denali NAND controller. This should be | ||
49 | combined with either the PCI or platform drivers to provide device | ||
50 | registration. | ||
51 | 46 | ||
52 | config MTD_NAND_DENALI_PCI | 47 | config MTD_NAND_DENALI_PCI |
53 | tristate "Support Denali NAND controller on Intel Moorestown" | 48 | tristate "Support Denali NAND controller on Intel Moorestown" |
54 | depends on PCI && MTD_NAND_DENALI | 49 | select MTD_NAND_DENALI |
50 | depends on HAS_DMA && PCI | ||
55 | help | 51 | help |
56 | Enable the driver for NAND flash on Intel Moorestown, using the | 52 | Enable the driver for NAND flash on Intel Moorestown, using the |
57 | Denali NAND controller core. | 53 | Denali NAND controller core. |
58 | 54 | ||
59 | config MTD_NAND_DENALI_DT | 55 | config MTD_NAND_DENALI_DT |
60 | tristate "Support Denali NAND controller as a DT device" | 56 | tristate "Support Denali NAND controller as a DT device" |
61 | depends on HAVE_CLK && MTD_NAND_DENALI | 57 | select MTD_NAND_DENALI |
58 | depends on HAS_DMA && HAVE_CLK | ||
62 | help | 59 | help |
63 | Enable the driver for NAND flash on platforms using a Denali NAND | 60 | Enable the driver for NAND flash on platforms using a Denali NAND |
64 | controller as a DT device. | 61 | controller as a DT device. |
diff --git a/drivers/mtd/nand/brcmnand/brcmnand.h b/drivers/mtd/nand/brcmnand/brcmnand.h index a20c73630b7b..169f99e38a26 100644 --- a/drivers/mtd/nand/brcmnand/brcmnand.h +++ b/drivers/mtd/nand/brcmnand/brcmnand.h | |||
@@ -50,7 +50,7 @@ static inline u32 brcmnand_readl(void __iomem *addr) | |||
50 | * Other architectures (e.g., ARM) either do not support big endian, or | 50 | * Other architectures (e.g., ARM) either do not support big endian, or |
51 | * else leave I/O in little endian mode. | 51 | * else leave I/O in little endian mode. |
52 | */ | 52 | */ |
53 | if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(__BIG_ENDIAN)) | 53 | if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) |
54 | return __raw_readl(addr); | 54 | return __raw_readl(addr); |
55 | else | 55 | else |
56 | return readl_relaxed(addr); | 56 | return readl_relaxed(addr); |
@@ -59,7 +59,7 @@ static inline u32 brcmnand_readl(void __iomem *addr) | |||
59 | static inline void brcmnand_writel(u32 val, void __iomem *addr) | 59 | static inline void brcmnand_writel(u32 val, void __iomem *addr) |
60 | { | 60 | { |
61 | /* See brcmnand_readl() comments */ | 61 | /* See brcmnand_readl() comments */ |
62 | if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(__BIG_ENDIAN)) | 62 | if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) |
63 | __raw_writel(val, addr); | 63 | __raw_writel(val, addr); |
64 | else | 64 | else |
65 | writel_relaxed(val, addr); | 65 | writel_relaxed(val, addr); |
diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c index feb6d18de78d..b90801302df4 100644 --- a/drivers/mtd/nand/davinci_nand.c +++ b/drivers/mtd/nand/davinci_nand.c | |||
@@ -520,6 +520,32 @@ static struct nand_ecclayout hwecc4_2048 = { | |||
520 | }, | 520 | }, |
521 | }; | 521 | }; |
522 | 522 | ||
523 | /* | ||
524 | * An ECC layout for using 4-bit ECC with large-page (4096bytes) flash, | ||
525 | * storing ten ECC bytes plus the manufacturer's bad block marker byte, | ||
526 | * and not overlapping the default BBT markers. | ||
527 | */ | ||
528 | static struct nand_ecclayout hwecc4_4096 = { | ||
529 | .eccbytes = 80, | ||
530 | .eccpos = { | ||
531 | /* at the end of spare sector */ | ||
532 | 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, | ||
533 | 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, | ||
534 | 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, | ||
535 | 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, | ||
536 | 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, | ||
537 | 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, | ||
538 | 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, | ||
539 | 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, | ||
540 | }, | ||
541 | .oobfree = { | ||
542 | /* 2 bytes at offset 0 hold manufacturer badblock markers */ | ||
543 | {.offset = 2, .length = 46, }, | ||
544 | /* 5 bytes at offset 8 hold BBT markers */ | ||
545 | /* 8 bytes at offset 16 hold JFFS2 clean markers */ | ||
546 | }, | ||
547 | }; | ||
548 | |||
523 | #if defined(CONFIG_OF) | 549 | #if defined(CONFIG_OF) |
524 | static const struct of_device_id davinci_nand_of_match[] = { | 550 | static const struct of_device_id davinci_nand_of_match[] = { |
525 | {.compatible = "ti,davinci-nand", }, | 551 | {.compatible = "ti,davinci-nand", }, |
@@ -796,18 +822,12 @@ static int nand_davinci_probe(struct platform_device *pdev) | |||
796 | info->chip.ecc.mode = NAND_ECC_HW_OOB_FIRST; | 822 | info->chip.ecc.mode = NAND_ECC_HW_OOB_FIRST; |
797 | goto syndrome_done; | 823 | goto syndrome_done; |
798 | } | 824 | } |
825 | if (chunks == 8) { | ||
826 | info->ecclayout = hwecc4_4096; | ||
827 | info->chip.ecc.mode = NAND_ECC_HW_OOB_FIRST; | ||
828 | goto syndrome_done; | ||
829 | } | ||
799 | 830 | ||
800 | /* 4KiB page chips are not yet supported. The eccpos from | ||
801 | * nand_ecclayout cannot hold 80 bytes and change to eccpos[] | ||
802 | * breaks userspace ioctl interface with mtd-utils. Once we | ||
803 | * resolve this issue, NAND_ECC_HW_OOB_FIRST mode can be used | ||
804 | * for the 4KiB page chips. | ||
805 | * | ||
806 | * TODO: Note that nand_ecclayout has now been expanded and can | ||
807 | * hold plenty of OOB entries. | ||
808 | */ | ||
809 | dev_warn(&pdev->dev, "no 4-bit ECC support yet " | ||
810 | "for 4KiB-page NAND\n"); | ||
811 | ret = -EIO; | 831 | ret = -EIO; |
812 | goto err; | 832 | goto err; |
813 | 833 | ||
diff --git a/drivers/mtd/nand/denali_pci.c b/drivers/mtd/nand/denali_pci.c index 6e2f387b823f..de31514df282 100644 --- a/drivers/mtd/nand/denali_pci.c +++ b/drivers/mtd/nand/denali_pci.c | |||
@@ -30,19 +30,19 @@ MODULE_DEVICE_TABLE(pci, denali_pci_ids); | |||
30 | 30 | ||
31 | static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) | 31 | static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) |
32 | { | 32 | { |
33 | int ret = -ENODEV; | 33 | int ret; |
34 | resource_size_t csr_base, mem_base; | 34 | resource_size_t csr_base, mem_base; |
35 | unsigned long csr_len, mem_len; | 35 | unsigned long csr_len, mem_len; |
36 | struct denali_nand_info *denali; | 36 | struct denali_nand_info *denali; |
37 | 37 | ||
38 | denali = kzalloc(sizeof(*denali), GFP_KERNEL); | 38 | denali = devm_kzalloc(&dev->dev, sizeof(*denali), GFP_KERNEL); |
39 | if (!denali) | 39 | if (!denali) |
40 | return -ENOMEM; | 40 | return -ENOMEM; |
41 | 41 | ||
42 | ret = pci_enable_device(dev); | 42 | ret = pcim_enable_device(dev); |
43 | if (ret) { | 43 | if (ret) { |
44 | pr_err("Spectra: pci_enable_device failed.\n"); | 44 | dev_err(&dev->dev, "Spectra: pci_enable_device failed.\n"); |
45 | goto failed_alloc_memery; | 45 | return ret; |
46 | } | 46 | } |
47 | 47 | ||
48 | if (id->driver_data == INTEL_CE4100) { | 48 | 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 | 69 | ||
70 | ret = pci_request_regions(dev, DENALI_NAND_NAME); | 70 | ret = pci_request_regions(dev, DENALI_NAND_NAME); |
71 | if (ret) { | 71 | if (ret) { |
72 | pr_err("Spectra: Unable to request memory regions\n"); | 72 | dev_err(&dev->dev, "Spectra: Unable to request memory regions\n"); |
73 | goto failed_enable_dev; | 73 | return ret; |
74 | } | 74 | } |
75 | 75 | ||
76 | denali->flash_reg = ioremap_nocache(csr_base, csr_len); | 76 | denali->flash_reg = ioremap_nocache(csr_base, csr_len); |
77 | if (!denali->flash_reg) { | 77 | if (!denali->flash_reg) { |
78 | pr_err("Spectra: Unable to remap memory region\n"); | 78 | dev_err(&dev->dev, "Spectra: Unable to remap memory region\n"); |
79 | ret = -ENOMEM; | 79 | return -ENOMEM; |
80 | goto failed_req_regions; | ||
81 | } | 80 | } |
82 | 81 | ||
83 | denali->flash_mem = ioremap_nocache(mem_base, mem_len); | 82 | denali->flash_mem = ioremap_nocache(mem_base, mem_len); |
84 | if (!denali->flash_mem) { | 83 | if (!denali->flash_mem) { |
85 | pr_err("Spectra: ioremap_nocache failed!"); | 84 | dev_err(&dev->dev, "Spectra: ioremap_nocache failed!"); |
86 | ret = -ENOMEM; | 85 | ret = -ENOMEM; |
87 | goto failed_remap_reg; | 86 | goto failed_remap_reg; |
88 | } | 87 | } |
@@ -99,13 +98,6 @@ failed_remap_mem: | |||
99 | iounmap(denali->flash_mem); | 98 | iounmap(denali->flash_mem); |
100 | failed_remap_reg: | 99 | failed_remap_reg: |
101 | iounmap(denali->flash_reg); | 100 | iounmap(denali->flash_reg); |
102 | failed_req_regions: | ||
103 | pci_release_regions(dev); | ||
104 | failed_enable_dev: | ||
105 | pci_disable_device(dev); | ||
106 | failed_alloc_memery: | ||
107 | kfree(denali); | ||
108 | |||
109 | return ret; | 101 | return ret; |
110 | } | 102 | } |
111 | 103 | ||
@@ -117,9 +109,6 @@ static void denali_pci_remove(struct pci_dev *dev) | |||
117 | denali_remove(denali); | 109 | denali_remove(denali); |
118 | iounmap(denali->flash_reg); | 110 | iounmap(denali->flash_reg); |
119 | iounmap(denali->flash_mem); | 111 | iounmap(denali->flash_mem); |
120 | pci_release_regions(dev); | ||
121 | pci_disable_device(dev); | ||
122 | kfree(denali); | ||
123 | } | 112 | } |
124 | 113 | ||
125 | static struct pci_driver denali_pci_driver = { | 114 | static struct pci_driver denali_pci_driver = { |
@@ -129,14 +118,4 @@ static struct pci_driver denali_pci_driver = { | |||
129 | .remove = denali_pci_remove, | 118 | .remove = denali_pci_remove, |
130 | }; | 119 | }; |
131 | 120 | ||
132 | static int denali_init_pci(void) | 121 | module_pci_driver(denali_pci_driver); |
133 | { | ||
134 | return pci_register_driver(&denali_pci_driver); | ||
135 | } | ||
136 | module_init(denali_init_pci); | ||
137 | |||
138 | static void denali_exit_pci(void) | ||
139 | { | ||
140 | pci_unregister_driver(&denali_pci_driver); | ||
141 | } | ||
142 | module_exit(denali_exit_pci); | ||
diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c index 7124400d903b..a8804a3da076 100644 --- a/drivers/mtd/nand/nand_ids.c +++ b/drivers/mtd/nand/nand_ids.c | |||
@@ -29,6 +29,10 @@ struct nand_flash_dev nand_flash_ids[] = { | |||
29 | * listed by full ID. We list them first so that we can easily identify | 29 | * listed by full ID. We list them first so that we can easily identify |
30 | * the most specific match. | 30 | * the most specific match. |
31 | */ | 31 | */ |
32 | {"TC58NVG0S3E 1G 3.3V 8-bit", | ||
33 | { .id = {0x98, 0xd1, 0x90, 0x15, 0x76, 0x14, 0x01, 0x00} }, | ||
34 | SZ_2K, SZ_128, SZ_128K, 0, 8, 64, NAND_ECC_INFO(1, SZ_512), | ||
35 | 2 }, | ||
32 | {"TC58NVG2S0F 4G 3.3V 8-bit", | 36 | {"TC58NVG2S0F 4G 3.3V 8-bit", |
33 | { .id = {0x98, 0xdc, 0x90, 0x26, 0x76, 0x15, 0x01, 0x08} }, | 37 | { .id = {0x98, 0xdc, 0x90, 0x26, 0x76, 0x15, 0x01, 0x08} }, |
34 | SZ_4K, SZ_512, SZ_256K, 0, 8, 224, NAND_ECC_INFO(4, SZ_512) }, | 38 | SZ_4K, SZ_512, SZ_256K, 0, 8, 224, NAND_ECC_INFO(4, SZ_512) }, |
diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index 52c0c1a3899c..95d0cc49cfc2 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c | |||
@@ -649,7 +649,8 @@ static void free_device(struct nandsim *ns) | |||
649 | kmem_cache_free(ns->nand_pages_slab, | 649 | kmem_cache_free(ns->nand_pages_slab, |
650 | ns->pages[i].byte); | 650 | ns->pages[i].byte); |
651 | } | 651 | } |
652 | kmem_cache_destroy(ns->nand_pages_slab); | 652 | if (ns->nand_pages_slab) |
653 | kmem_cache_destroy(ns->nand_pages_slab); | ||
653 | vfree(ns->pages); | 654 | vfree(ns->pages); |
654 | } | 655 | } |
655 | } | 656 | } |
@@ -729,8 +730,7 @@ static int init_nandsim(struct mtd_info *mtd) | |||
729 | /* Fill the partition_info structure */ | 730 | /* Fill the partition_info structure */ |
730 | if (parts_num > ARRAY_SIZE(ns->partitions)) { | 731 | if (parts_num > ARRAY_SIZE(ns->partitions)) { |
731 | NS_ERR("too many partitions.\n"); | 732 | NS_ERR("too many partitions.\n"); |
732 | ret = -EINVAL; | 733 | return -EINVAL; |
733 | goto error; | ||
734 | } | 734 | } |
735 | remains = ns->geom.totsz; | 735 | remains = ns->geom.totsz; |
736 | next_offset = 0; | 736 | next_offset = 0; |
@@ -739,14 +739,12 @@ static int init_nandsim(struct mtd_info *mtd) | |||
739 | 739 | ||
740 | if (!part_sz || part_sz > remains) { | 740 | if (!part_sz || part_sz > remains) { |
741 | NS_ERR("bad partition size.\n"); | 741 | NS_ERR("bad partition size.\n"); |
742 | ret = -EINVAL; | 742 | return -EINVAL; |
743 | goto error; | ||
744 | } | 743 | } |
745 | ns->partitions[i].name = get_partition_name(i); | 744 | ns->partitions[i].name = get_partition_name(i); |
746 | if (!ns->partitions[i].name) { | 745 | if (!ns->partitions[i].name) { |
747 | NS_ERR("unable to allocate memory.\n"); | 746 | NS_ERR("unable to allocate memory.\n"); |
748 | ret = -ENOMEM; | 747 | return -ENOMEM; |
749 | goto error; | ||
750 | } | 748 | } |
751 | ns->partitions[i].offset = next_offset; | 749 | ns->partitions[i].offset = next_offset; |
752 | ns->partitions[i].size = part_sz; | 750 | ns->partitions[i].size = part_sz; |
@@ -757,14 +755,12 @@ static int init_nandsim(struct mtd_info *mtd) | |||
757 | if (remains) { | 755 | if (remains) { |
758 | if (parts_num + 1 > ARRAY_SIZE(ns->partitions)) { | 756 | if (parts_num + 1 > ARRAY_SIZE(ns->partitions)) { |
759 | NS_ERR("too many partitions.\n"); | 757 | NS_ERR("too many partitions.\n"); |
760 | ret = -EINVAL; | 758 | return -EINVAL; |
761 | goto error; | ||
762 | } | 759 | } |
763 | ns->partitions[i].name = get_partition_name(i); | 760 | ns->partitions[i].name = get_partition_name(i); |
764 | if (!ns->partitions[i].name) { | 761 | if (!ns->partitions[i].name) { |
765 | NS_ERR("unable to allocate memory.\n"); | 762 | NS_ERR("unable to allocate memory.\n"); |
766 | ret = -ENOMEM; | 763 | return -ENOMEM; |
767 | goto error; | ||
768 | } | 764 | } |
769 | ns->partitions[i].offset = next_offset; | 765 | ns->partitions[i].offset = next_offset; |
770 | ns->partitions[i].size = remains; | 766 | ns->partitions[i].size = remains; |
@@ -792,24 +788,18 @@ static int init_nandsim(struct mtd_info *mtd) | |||
792 | printk("options: %#x\n", ns->options); | 788 | printk("options: %#x\n", ns->options); |
793 | 789 | ||
794 | if ((ret = alloc_device(ns)) != 0) | 790 | if ((ret = alloc_device(ns)) != 0) |
795 | goto error; | 791 | return ret; |
796 | 792 | ||
797 | /* Allocate / initialize the internal buffer */ | 793 | /* Allocate / initialize the internal buffer */ |
798 | ns->buf.byte = kmalloc(ns->geom.pgszoob, GFP_KERNEL); | 794 | ns->buf.byte = kmalloc(ns->geom.pgszoob, GFP_KERNEL); |
799 | if (!ns->buf.byte) { | 795 | if (!ns->buf.byte) { |
800 | NS_ERR("init_nandsim: unable to allocate %u bytes for the internal buffer\n", | 796 | NS_ERR("init_nandsim: unable to allocate %u bytes for the internal buffer\n", |
801 | ns->geom.pgszoob); | 797 | ns->geom.pgszoob); |
802 | ret = -ENOMEM; | 798 | return -ENOMEM; |
803 | goto error; | ||
804 | } | 799 | } |
805 | memset(ns->buf.byte, 0xFF, ns->geom.pgszoob); | 800 | memset(ns->buf.byte, 0xFF, ns->geom.pgszoob); |
806 | 801 | ||
807 | return 0; | 802 | return 0; |
808 | |||
809 | error: | ||
810 | free_device(ns); | ||
811 | |||
812 | return ret; | ||
813 | } | 803 | } |
814 | 804 | ||
815 | /* | 805 | /* |
diff --git a/drivers/mtd/nand/omap_elm.c b/drivers/mtd/nand/omap_elm.c index 376bfe19104f..235ec7992b4c 100644 --- a/drivers/mtd/nand/omap_elm.c +++ b/drivers/mtd/nand/omap_elm.c | |||
@@ -574,5 +574,5 @@ module_platform_driver(elm_driver); | |||
574 | 574 | ||
575 | MODULE_DESCRIPTION("ELM driver for BCH error correction"); | 575 | MODULE_DESCRIPTION("ELM driver for BCH error correction"); |
576 | MODULE_AUTHOR("Texas Instruments"); | 576 | MODULE_AUTHOR("Texas Instruments"); |
577 | MODULE_ALIAS("platform: elm"); | 577 | MODULE_ALIAS("platform:" DRIVER_NAME); |
578 | MODULE_LICENSE("GPL v2"); | 578 | MODULE_LICENSE("GPL v2"); |
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 1259cc558ce9..740983a34626 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c | |||
@@ -45,10 +45,13 @@ | |||
45 | 45 | ||
46 | /* | 46 | /* |
47 | * Define a buffer size for the initial command that detects the flash device: | 47 | * Define a buffer size for the initial command that detects the flash device: |
48 | * STATUS, READID and PARAM. The largest of these is the PARAM command, | 48 | * STATUS, READID and PARAM. |
49 | * needing 256 bytes. | 49 | * ONFI param page is 256 bytes, and there are three redundant copies |
50 | * to be read. JEDEC param page is 512 bytes, and there are also three | ||
51 | * redundant copies to be read. | ||
52 | * Hence this buffer should be at least 512 x 3. Let's pick 2048. | ||
50 | */ | 53 | */ |
51 | #define INIT_BUFFER_SIZE 256 | 54 | #define INIT_BUFFER_SIZE 2048 |
52 | 55 | ||
53 | /* registers and bit definitions */ | 56 | /* registers and bit definitions */ |
54 | #define NDCR (0x00) /* Control register */ | 57 | #define NDCR (0x00) /* Control register */ |
@@ -126,6 +129,13 @@ | |||
126 | #define EXT_CMD_TYPE_LAST_RW 1 /* Last naked read/write */ | 129 | #define EXT_CMD_TYPE_LAST_RW 1 /* Last naked read/write */ |
127 | #define EXT_CMD_TYPE_MONO 0 /* Monolithic read/write */ | 130 | #define EXT_CMD_TYPE_MONO 0 /* Monolithic read/write */ |
128 | 131 | ||
132 | /* | ||
133 | * This should be large enough to read 'ONFI' and 'JEDEC'. | ||
134 | * Let's use 7 bytes, which is the maximum ID count supported | ||
135 | * by the controller (see NDCR_RD_ID_CNT_MASK). | ||
136 | */ | ||
137 | #define READ_ID_BYTES 7 | ||
138 | |||
129 | /* macros for registers read/write */ | 139 | /* macros for registers read/write */ |
130 | #define nand_writel(info, off, val) \ | 140 | #define nand_writel(info, off, val) \ |
131 | writel_relaxed((val), (info)->mmio_base + (off)) | 141 | writel_relaxed((val), (info)->mmio_base + (off)) |
@@ -173,8 +183,6 @@ struct pxa3xx_nand_host { | |||
173 | /* calculated from pxa3xx_nand_flash data */ | 183 | /* calculated from pxa3xx_nand_flash data */ |
174 | unsigned int col_addr_cycles; | 184 | unsigned int col_addr_cycles; |
175 | unsigned int row_addr_cycles; | 185 | unsigned int row_addr_cycles; |
176 | size_t read_id_bytes; | ||
177 | |||
178 | }; | 186 | }; |
179 | 187 | ||
180 | struct pxa3xx_nand_info { | 188 | struct pxa3xx_nand_info { |
@@ -439,8 +447,8 @@ static void pxa3xx_nand_start(struct pxa3xx_nand_info *info) | |||
439 | ndcr |= NDCR_ND_RUN; | 447 | ndcr |= NDCR_ND_RUN; |
440 | 448 | ||
441 | /* clear status bits and run */ | 449 | /* clear status bits and run */ |
442 | nand_writel(info, NDCR, 0); | ||
443 | nand_writel(info, NDSR, NDSR_MASK); | 450 | nand_writel(info, NDSR, NDSR_MASK); |
451 | nand_writel(info, NDCR, 0); | ||
444 | nand_writel(info, NDCR, ndcr); | 452 | nand_writel(info, NDCR, ndcr); |
445 | } | 453 | } |
446 | 454 | ||
@@ -675,8 +683,14 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid) | |||
675 | is_ready = 1; | 683 | is_ready = 1; |
676 | } | 684 | } |
677 | 685 | ||
686 | /* | ||
687 | * Clear all status bit before issuing the next command, which | ||
688 | * can and will alter the status bits and will deserve a new | ||
689 | * interrupt on its own. This lets the controller exit the IRQ | ||
690 | */ | ||
691 | nand_writel(info, NDSR, status); | ||
692 | |||
678 | if (status & NDSR_WRCMDREQ) { | 693 | if (status & NDSR_WRCMDREQ) { |
679 | nand_writel(info, NDSR, NDSR_WRCMDREQ); | ||
680 | status &= ~NDSR_WRCMDREQ; | 694 | status &= ~NDSR_WRCMDREQ; |
681 | info->state = STATE_CMD_HANDLE; | 695 | info->state = STATE_CMD_HANDLE; |
682 | 696 | ||
@@ -697,8 +711,6 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid) | |||
697 | nand_writel(info, NDCB0, info->ndcb3); | 711 | nand_writel(info, NDCB0, info->ndcb3); |
698 | } | 712 | } |
699 | 713 | ||
700 | /* clear NDSR to let the controller exit the IRQ */ | ||
701 | nand_writel(info, NDSR, status); | ||
702 | if (is_completed) | 714 | if (is_completed) |
703 | complete(&info->cmd_complete); | 715 | complete(&info->cmd_complete); |
704 | if (is_ready) | 716 | if (is_ready) |
@@ -899,18 +911,18 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command, | |||
899 | break; | 911 | break; |
900 | 912 | ||
901 | case NAND_CMD_PARAM: | 913 | case NAND_CMD_PARAM: |
902 | info->buf_count = 256; | 914 | info->buf_count = INIT_BUFFER_SIZE; |
903 | info->ndcb0 |= NDCB0_CMD_TYPE(0) | 915 | info->ndcb0 |= NDCB0_CMD_TYPE(0) |
904 | | NDCB0_ADDR_CYC(1) | 916 | | NDCB0_ADDR_CYC(1) |
905 | | NDCB0_LEN_OVRD | 917 | | NDCB0_LEN_OVRD |
906 | | command; | 918 | | command; |
907 | info->ndcb1 = (column & 0xFF); | 919 | info->ndcb1 = (column & 0xFF); |
908 | info->ndcb3 = 256; | 920 | info->ndcb3 = INIT_BUFFER_SIZE; |
909 | info->data_size = 256; | 921 | info->data_size = INIT_BUFFER_SIZE; |
910 | break; | 922 | break; |
911 | 923 | ||
912 | case NAND_CMD_READID: | 924 | case NAND_CMD_READID: |
913 | info->buf_count = host->read_id_bytes; | 925 | info->buf_count = READ_ID_BYTES; |
914 | info->ndcb0 |= NDCB0_CMD_TYPE(3) | 926 | info->ndcb0 |= NDCB0_CMD_TYPE(3) |
915 | | NDCB0_ADDR_CYC(1) | 927 | | NDCB0_ADDR_CYC(1) |
916 | | command; | 928 | | command; |
@@ -1247,9 +1259,6 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, | |||
1247 | return -EINVAL; | 1259 | return -EINVAL; |
1248 | } | 1260 | } |
1249 | 1261 | ||
1250 | /* calculate flash information */ | ||
1251 | host->read_id_bytes = (f->page_size == 2048) ? 4 : 2; | ||
1252 | |||
1253 | /* calculate addressing information */ | 1262 | /* calculate addressing information */ |
1254 | host->col_addr_cycles = (f->page_size == 2048) ? 2 : 1; | 1263 | host->col_addr_cycles = (f->page_size == 2048) ? 2 : 1; |
1255 | 1264 | ||
@@ -1265,7 +1274,7 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, | |||
1265 | ndcr |= (f->flash_width == 16) ? NDCR_DWIDTH_M : 0; | 1274 | ndcr |= (f->flash_width == 16) ? NDCR_DWIDTH_M : 0; |
1266 | ndcr |= (f->dfc_width == 16) ? NDCR_DWIDTH_C : 0; | 1275 | ndcr |= (f->dfc_width == 16) ? NDCR_DWIDTH_C : 0; |
1267 | 1276 | ||
1268 | ndcr |= NDCR_RD_ID_CNT(host->read_id_bytes); | 1277 | ndcr |= NDCR_RD_ID_CNT(READ_ID_BYTES); |
1269 | ndcr |= NDCR_SPARE_EN; /* enable spare by default */ | 1278 | ndcr |= NDCR_SPARE_EN; /* enable spare by default */ |
1270 | 1279 | ||
1271 | info->reg_ndcr = ndcr; | 1280 | info->reg_ndcr = ndcr; |
@@ -1276,23 +1285,10 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, | |||
1276 | 1285 | ||
1277 | static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info) | 1286 | static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info) |
1278 | { | 1287 | { |
1279 | /* | ||
1280 | * We set 0 by hard coding here, for we don't support keep_config | ||
1281 | * when there is more than one chip attached to the controller | ||
1282 | */ | ||
1283 | struct pxa3xx_nand_host *host = info->host[0]; | ||
1284 | uint32_t ndcr = nand_readl(info, NDCR); | 1288 | uint32_t ndcr = nand_readl(info, NDCR); |
1285 | 1289 | ||
1286 | if (ndcr & NDCR_PAGE_SZ) { | ||
1287 | /* Controller's FIFO size */ | ||
1288 | info->chunk_size = 2048; | ||
1289 | host->read_id_bytes = 4; | ||
1290 | } else { | ||
1291 | info->chunk_size = 512; | ||
1292 | host->read_id_bytes = 2; | ||
1293 | } | ||
1294 | |||
1295 | /* Set an initial chunk size */ | 1290 | /* Set an initial chunk size */ |
1291 | info->chunk_size = ndcr & NDCR_PAGE_SZ ? 2048 : 512; | ||
1296 | info->reg_ndcr = ndcr & ~NDCR_INT_MASK; | 1292 | info->reg_ndcr = ndcr & ~NDCR_INT_MASK; |
1297 | info->ndtr0cs0 = nand_readl(info, NDTR0CS0); | 1293 | info->ndtr0cs0 = nand_readl(info, NDTR0CS0); |
1298 | info->ndtr1cs0 = nand_readl(info, NDTR1CS0); | 1294 | info->ndtr1cs0 = nand_readl(info, NDTR1CS0); |
@@ -1473,6 +1469,9 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) | |||
1473 | if (pdata->keep_config && !pxa3xx_nand_detect_config(info)) | 1469 | if (pdata->keep_config && !pxa3xx_nand_detect_config(info)) |
1474 | goto KEEP_CONFIG; | 1470 | goto KEEP_CONFIG; |
1475 | 1471 | ||
1472 | /* Set a default chunk size */ | ||
1473 | info->chunk_size = 512; | ||
1474 | |||
1476 | ret = pxa3xx_nand_sensing(info); | 1475 | ret = pxa3xx_nand_sensing(info); |
1477 | if (ret) { | 1476 | if (ret) { |
1478 | dev_info(&info->pdev->dev, "There is no chip on cs %d!\n", | 1477 | dev_info(&info->pdev->dev, "There is no chip on cs %d!\n", |
diff --git a/drivers/mtd/nand/r852.c b/drivers/mtd/nand/r852.c index 77e96d2df96c..cc6bac537f5a 100644 --- a/drivers/mtd/nand/r852.c +++ b/drivers/mtd/nand/r852.c | |||
@@ -466,7 +466,7 @@ static int r852_ecc_calculate(struct mtd_info *mtd, const uint8_t *dat, | |||
466 | static int r852_ecc_correct(struct mtd_info *mtd, uint8_t *dat, | 466 | static int r852_ecc_correct(struct mtd_info *mtd, uint8_t *dat, |
467 | uint8_t *read_ecc, uint8_t *calc_ecc) | 467 | uint8_t *read_ecc, uint8_t *calc_ecc) |
468 | { | 468 | { |
469 | uint16_t ecc_reg; | 469 | uint32_t ecc_reg; |
470 | uint8_t ecc_status, err_byte; | 470 | uint8_t ecc_status, err_byte; |
471 | int i, error = 0; | 471 | int i, error = 0; |
472 | 472 | ||
diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c index 6f93b2990d25..f97a58d6aae1 100644 --- a/drivers/mtd/nand/sunxi_nand.c +++ b/drivers/mtd/nand/sunxi_nand.c | |||
@@ -99,6 +99,15 @@ | |||
99 | NFC_CMD_INT_ENABLE | \ | 99 | NFC_CMD_INT_ENABLE | \ |
100 | NFC_DMA_INT_ENABLE) | 100 | NFC_DMA_INT_ENABLE) |
101 | 101 | ||
102 | /* define bit use in NFC_TIMING_CTL */ | ||
103 | #define NFC_TIMING_CTL_EDO BIT(8) | ||
104 | |||
105 | /* define NFC_TIMING_CFG register layout */ | ||
106 | #define NFC_TIMING_CFG(tWB, tADL, tWHR, tRHW, tCAD) \ | ||
107 | (((tWB) & 0x3) | (((tADL) & 0x3) << 2) | \ | ||
108 | (((tWHR) & 0x3) << 4) | (((tRHW) & 0x3) << 6) | \ | ||
109 | (((tCAD) & 0x7) << 8)) | ||
110 | |||
102 | /* define bit use in NFC_CMD */ | 111 | /* define bit use in NFC_CMD */ |
103 | #define NFC_CMD_LOW_BYTE GENMASK(7, 0) | 112 | #define NFC_CMD_LOW_BYTE GENMASK(7, 0) |
104 | #define NFC_CMD_HIGH_BYTE GENMASK(15, 8) | 113 | #define NFC_CMD_HIGH_BYTE GENMASK(15, 8) |
@@ -208,6 +217,7 @@ struct sunxi_nand_hw_ecc { | |||
208 | * @nand: base NAND chip structure | 217 | * @nand: base NAND chip structure |
209 | * @mtd: base MTD structure | 218 | * @mtd: base MTD structure |
210 | * @clk_rate: clk_rate required for this NAND chip | 219 | * @clk_rate: clk_rate required for this NAND chip |
220 | * @timing_cfg TIMING_CFG register value for this NAND chip | ||
211 | * @selected: current active CS | 221 | * @selected: current active CS |
212 | * @nsels: number of CS lines required by the NAND chip | 222 | * @nsels: number of CS lines required by the NAND chip |
213 | * @sels: array of CS lines descriptions | 223 | * @sels: array of CS lines descriptions |
@@ -217,6 +227,8 @@ struct sunxi_nand_chip { | |||
217 | struct nand_chip nand; | 227 | struct nand_chip nand; |
218 | struct mtd_info mtd; | 228 | struct mtd_info mtd; |
219 | unsigned long clk_rate; | 229 | unsigned long clk_rate; |
230 | u32 timing_cfg; | ||
231 | u32 timing_ctl; | ||
220 | int selected; | 232 | int selected; |
221 | int nsels; | 233 | int nsels; |
222 | struct sunxi_nand_chip_sel sels[0]; | 234 | struct sunxi_nand_chip_sel sels[0]; |
@@ -403,6 +415,8 @@ static void sunxi_nfc_select_chip(struct mtd_info *mtd, int chip) | |||
403 | } | 415 | } |
404 | } | 416 | } |
405 | 417 | ||
418 | writel(sunxi_nand->timing_ctl, nfc->regs + NFC_REG_TIMING_CTL); | ||
419 | writel(sunxi_nand->timing_cfg, nfc->regs + NFC_REG_TIMING_CFG); | ||
406 | writel(ctl, nfc->regs + NFC_REG_CTL); | 420 | writel(ctl, nfc->regs + NFC_REG_CTL); |
407 | 421 | ||
408 | sunxi_nand->selected = chip; | 422 | sunxi_nand->selected = chip; |
@@ -807,10 +821,33 @@ static int sunxi_nfc_hw_syndrome_ecc_write_page(struct mtd_info *mtd, | |||
807 | return 0; | 821 | return 0; |
808 | } | 822 | } |
809 | 823 | ||
824 | static const s32 tWB_lut[] = {6, 12, 16, 20}; | ||
825 | static const s32 tRHW_lut[] = {4, 8, 12, 20}; | ||
826 | |||
827 | static int _sunxi_nand_lookup_timing(const s32 *lut, int lut_size, u32 duration, | ||
828 | u32 clk_period) | ||
829 | { | ||
830 | u32 clk_cycles = DIV_ROUND_UP(duration, clk_period); | ||
831 | int i; | ||
832 | |||
833 | for (i = 0; i < lut_size; i++) { | ||
834 | if (clk_cycles <= lut[i]) | ||
835 | return i; | ||
836 | } | ||
837 | |||
838 | /* Doesn't fit */ | ||
839 | return -EINVAL; | ||
840 | } | ||
841 | |||
842 | #define sunxi_nand_lookup_timing(l, p, c) \ | ||
843 | _sunxi_nand_lookup_timing(l, ARRAY_SIZE(l), p, c) | ||
844 | |||
810 | static int sunxi_nand_chip_set_timings(struct sunxi_nand_chip *chip, | 845 | static int sunxi_nand_chip_set_timings(struct sunxi_nand_chip *chip, |
811 | const struct nand_sdr_timings *timings) | 846 | const struct nand_sdr_timings *timings) |
812 | { | 847 | { |
848 | struct sunxi_nfc *nfc = to_sunxi_nfc(chip->nand.controller); | ||
813 | u32 min_clk_period = 0; | 849 | u32 min_clk_period = 0; |
850 | s32 tWB, tADL, tWHR, tRHW, tCAD; | ||
814 | 851 | ||
815 | /* T1 <=> tCLS */ | 852 | /* T1 <=> tCLS */ |
816 | if (timings->tCLS_min > min_clk_period) | 853 | if (timings->tCLS_min > min_clk_period) |
@@ -872,6 +909,48 @@ static int sunxi_nand_chip_set_timings(struct sunxi_nand_chip *chip, | |||
872 | if (timings->tWC_min > (min_clk_period * 2)) | 909 | if (timings->tWC_min > (min_clk_period * 2)) |
873 | min_clk_period = DIV_ROUND_UP(timings->tWC_min, 2); | 910 | min_clk_period = DIV_ROUND_UP(timings->tWC_min, 2); |
874 | 911 | ||
912 | /* T16 - T19 + tCAD */ | ||
913 | tWB = sunxi_nand_lookup_timing(tWB_lut, timings->tWB_max, | ||
914 | min_clk_period); | ||
915 | if (tWB < 0) { | ||
916 | dev_err(nfc->dev, "unsupported tWB\n"); | ||
917 | return tWB; | ||
918 | } | ||
919 | |||
920 | tADL = DIV_ROUND_UP(timings->tADL_min, min_clk_period) >> 3; | ||
921 | if (tADL > 3) { | ||
922 | dev_err(nfc->dev, "unsupported tADL\n"); | ||
923 | return -EINVAL; | ||
924 | } | ||
925 | |||
926 | tWHR = DIV_ROUND_UP(timings->tWHR_min, min_clk_period) >> 3; | ||
927 | if (tWHR > 3) { | ||
928 | dev_err(nfc->dev, "unsupported tWHR\n"); | ||
929 | return -EINVAL; | ||
930 | } | ||
931 | |||
932 | tRHW = sunxi_nand_lookup_timing(tRHW_lut, timings->tRHW_min, | ||
933 | min_clk_period); | ||
934 | if (tRHW < 0) { | ||
935 | dev_err(nfc->dev, "unsupported tRHW\n"); | ||
936 | return tRHW; | ||
937 | } | ||
938 | |||
939 | /* | ||
940 | * TODO: according to ONFI specs this value only applies for DDR NAND, | ||
941 | * but Allwinner seems to set this to 0x7. Mimic them for now. | ||
942 | */ | ||
943 | tCAD = 0x7; | ||
944 | |||
945 | /* TODO: A83 has some more bits for CDQSS, CS, CLHZ, CCS, WC */ | ||
946 | chip->timing_cfg = NFC_TIMING_CFG(tWB, tADL, tWHR, tRHW, tCAD); | ||
947 | |||
948 | /* | ||
949 | * ONFI specification 3.1, paragraph 4.15.2 dictates that EDO data | ||
950 | * output cycle timings shall be used if the host drives tRC less than | ||
951 | * 30 ns. | ||
952 | */ | ||
953 | chip->timing_ctl = (timings->tRC_min < 30000) ? NFC_TIMING_CTL_EDO : 0; | ||
875 | 954 | ||
876 | /* Convert min_clk_period from picoseconds to nanoseconds */ | 955 | /* Convert min_clk_period from picoseconds to nanoseconds */ |
877 | min_clk_period = DIV_ROUND_UP(min_clk_period, 1000); | 956 | 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 | */ | 963 | */ |
885 | chip->clk_rate = (2 * NSEC_PER_SEC) / min_clk_period; | 964 | chip->clk_rate = (2 * NSEC_PER_SEC) / min_clk_period; |
886 | 965 | ||
887 | /* TODO: configure T16-T19 */ | ||
888 | |||
889 | return 0; | 966 | return 0; |
890 | } | 967 | } |
891 | 968 | ||
@@ -1376,13 +1453,6 @@ static int sunxi_nfc_probe(struct platform_device *pdev) | |||
1376 | 1453 | ||
1377 | platform_set_drvdata(pdev, nfc); | 1454 | platform_set_drvdata(pdev, nfc); |
1378 | 1455 | ||
1379 | /* | ||
1380 | * TODO: replace these magic values with proper flags as soon as we | ||
1381 | * know what they are encoding. | ||
1382 | */ | ||
1383 | writel(0x100, nfc->regs + NFC_REG_TIMING_CTL); | ||
1384 | writel(0x7ff, nfc->regs + NFC_REG_TIMING_CFG); | ||
1385 | |||
1386 | ret = sunxi_nand_chips_init(dev, nfc); | 1456 | ret = sunxi_nand_chips_init(dev, nfc); |
1387 | if (ret) { | 1457 | if (ret) { |
1388 | dev_err(dev, "failed to init nand chips\n"); | 1458 | dev_err(dev, "failed to init nand chips\n"); |
diff --git a/drivers/mtd/spi-nor/Kconfig b/drivers/mtd/spi-nor/Kconfig index 64a4f0edabc7..89bf4c1faa2b 100644 --- a/drivers/mtd/spi-nor/Kconfig +++ b/drivers/mtd/spi-nor/Kconfig | |||
@@ -26,6 +26,18 @@ config SPI_FSL_QUADSPI | |||
26 | depends on ARCH_MXC | 26 | depends on ARCH_MXC |
27 | help | 27 | help |
28 | This enables support for the Quad SPI controller in master mode. | 28 | This enables support for the Quad SPI controller in master mode. |
29 | We only connect the NOR to this controller now. | 29 | This controller does not support generic SPI. It only supports |
30 | SPI NOR. | ||
31 | |||
32 | config SPI_NXP_SPIFI | ||
33 | tristate "NXP SPI Flash Interface (SPIFI)" | ||
34 | depends on OF && (ARCH_LPC18XX || COMPILE_TEST) | ||
35 | depends on HAS_IOMEM | ||
36 | help | ||
37 | Enable support for the NXP LPC SPI Flash Interface controller. | ||
38 | |||
39 | SPIFI is a specialized controller for connecting serial SPI | ||
40 | Flash. Enable this option if you have a device with a SPIFI | ||
41 | controller and want to access the Flash as a mtd device. | ||
30 | 42 | ||
31 | endif # MTD_SPI_NOR | 43 | endif # MTD_SPI_NOR |
diff --git a/drivers/mtd/spi-nor/Makefile b/drivers/mtd/spi-nor/Makefile index 6a7ce1462247..e53333ef8582 100644 --- a/drivers/mtd/spi-nor/Makefile +++ b/drivers/mtd/spi-nor/Makefile | |||
@@ -1,2 +1,3 @@ | |||
1 | obj-$(CONFIG_MTD_SPI_NOR) += spi-nor.o | 1 | obj-$(CONFIG_MTD_SPI_NOR) += spi-nor.o |
2 | obj-$(CONFIG_SPI_FSL_QUADSPI) += fsl-quadspi.o | 2 | obj-$(CONFIG_SPI_FSL_QUADSPI) += fsl-quadspi.o |
3 | obj-$(CONFIG_SPI_NXP_SPIFI) += nxp-spifi.o | ||
diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c index 52a872fa1b6e..d32b7e04ccca 100644 --- a/drivers/mtd/spi-nor/fsl-quadspi.c +++ b/drivers/mtd/spi-nor/fsl-quadspi.c | |||
@@ -26,6 +26,20 @@ | |||
26 | #include <linux/mtd/mtd.h> | 26 | #include <linux/mtd/mtd.h> |
27 | #include <linux/mtd/partitions.h> | 27 | #include <linux/mtd/partitions.h> |
28 | #include <linux/mtd/spi-nor.h> | 28 | #include <linux/mtd/spi-nor.h> |
29 | #include <linux/mutex.h> | ||
30 | #include <linux/pm_qos.h> | ||
31 | |||
32 | /* Controller needs driver to swap endian */ | ||
33 | #define QUADSPI_QUIRK_SWAP_ENDIAN (1 << 0) | ||
34 | /* Controller needs 4x internal clock */ | ||
35 | #define QUADSPI_QUIRK_4X_INT_CLK (1 << 1) | ||
36 | /* | ||
37 | * TKT253890, Controller needs driver to fill txfifo till 16 byte to | ||
38 | * trigger data transfer even though extern data will not transferred. | ||
39 | */ | ||
40 | #define QUADSPI_QUIRK_TKT253890 (1 << 2) | ||
41 | /* Controller cannot wake up from wait mode, TKT245618 */ | ||
42 | #define QUADSPI_QUIRK_TKT245618 (1 << 3) | ||
29 | 43 | ||
30 | /* The registers */ | 44 | /* The registers */ |
31 | #define QUADSPI_MCR 0x00 | 45 | #define QUADSPI_MCR 0x00 |
@@ -191,9 +205,13 @@ | |||
191 | #define SEQID_EN4B 10 | 205 | #define SEQID_EN4B 10 |
192 | #define SEQID_BRWR 11 | 206 | #define SEQID_BRWR 11 |
193 | 207 | ||
208 | #define QUADSPI_MIN_IOMAP SZ_4M | ||
209 | |||
194 | enum fsl_qspi_devtype { | 210 | enum fsl_qspi_devtype { |
195 | FSL_QUADSPI_VYBRID, | 211 | FSL_QUADSPI_VYBRID, |
196 | FSL_QUADSPI_IMX6SX, | 212 | FSL_QUADSPI_IMX6SX, |
213 | FSL_QUADSPI_IMX7D, | ||
214 | FSL_QUADSPI_IMX6UL, | ||
197 | }; | 215 | }; |
198 | 216 | ||
199 | struct fsl_qspi_devtype_data { | 217 | struct fsl_qspi_devtype_data { |
@@ -201,20 +219,42 @@ struct fsl_qspi_devtype_data { | |||
201 | int rxfifo; | 219 | int rxfifo; |
202 | int txfifo; | 220 | int txfifo; |
203 | int ahb_buf_size; | 221 | int ahb_buf_size; |
222 | int driver_data; | ||
204 | }; | 223 | }; |
205 | 224 | ||
206 | static struct fsl_qspi_devtype_data vybrid_data = { | 225 | static struct fsl_qspi_devtype_data vybrid_data = { |
207 | .devtype = FSL_QUADSPI_VYBRID, | 226 | .devtype = FSL_QUADSPI_VYBRID, |
208 | .rxfifo = 128, | 227 | .rxfifo = 128, |
209 | .txfifo = 64, | 228 | .txfifo = 64, |
210 | .ahb_buf_size = 1024 | 229 | .ahb_buf_size = 1024, |
230 | .driver_data = QUADSPI_QUIRK_SWAP_ENDIAN, | ||
211 | }; | 231 | }; |
212 | 232 | ||
213 | static struct fsl_qspi_devtype_data imx6sx_data = { | 233 | static struct fsl_qspi_devtype_data imx6sx_data = { |
214 | .devtype = FSL_QUADSPI_IMX6SX, | 234 | .devtype = FSL_QUADSPI_IMX6SX, |
215 | .rxfifo = 128, | 235 | .rxfifo = 128, |
216 | .txfifo = 512, | 236 | .txfifo = 512, |
217 | .ahb_buf_size = 1024 | 237 | .ahb_buf_size = 1024, |
238 | .driver_data = QUADSPI_QUIRK_4X_INT_CLK | ||
239 | | QUADSPI_QUIRK_TKT245618, | ||
240 | }; | ||
241 | |||
242 | static struct fsl_qspi_devtype_data imx7d_data = { | ||
243 | .devtype = FSL_QUADSPI_IMX7D, | ||
244 | .rxfifo = 512, | ||
245 | .txfifo = 512, | ||
246 | .ahb_buf_size = 1024, | ||
247 | .driver_data = QUADSPI_QUIRK_TKT253890 | ||
248 | | QUADSPI_QUIRK_4X_INT_CLK, | ||
249 | }; | ||
250 | |||
251 | static struct fsl_qspi_devtype_data imx6ul_data = { | ||
252 | .devtype = FSL_QUADSPI_IMX6UL, | ||
253 | .rxfifo = 128, | ||
254 | .txfifo = 512, | ||
255 | .ahb_buf_size = 1024, | ||
256 | .driver_data = QUADSPI_QUIRK_TKT253890 | ||
257 | | QUADSPI_QUIRK_4X_INT_CLK, | ||
218 | }; | 258 | }; |
219 | 259 | ||
220 | #define FSL_QSPI_MAX_CHIP 4 | 260 | #define FSL_QSPI_MAX_CHIP 4 |
@@ -222,8 +262,10 @@ struct fsl_qspi { | |||
222 | struct mtd_info mtd[FSL_QSPI_MAX_CHIP]; | 262 | struct mtd_info mtd[FSL_QSPI_MAX_CHIP]; |
223 | struct spi_nor nor[FSL_QSPI_MAX_CHIP]; | 263 | struct spi_nor nor[FSL_QSPI_MAX_CHIP]; |
224 | void __iomem *iobase; | 264 | void __iomem *iobase; |
225 | void __iomem *ahb_base; /* Used when read from AHB bus */ | 265 | void __iomem *ahb_addr; |
226 | u32 memmap_phy; | 266 | u32 memmap_phy; |
267 | u32 memmap_offs; | ||
268 | u32 memmap_len; | ||
227 | struct clk *clk, *clk_en; | 269 | struct clk *clk, *clk_en; |
228 | struct device *dev; | 270 | struct device *dev; |
229 | struct completion c; | 271 | struct completion c; |
@@ -233,16 +275,28 @@ struct fsl_qspi { | |||
233 | u32 clk_rate; | 275 | u32 clk_rate; |
234 | unsigned int chip_base_addr; /* We may support two chips. */ | 276 | unsigned int chip_base_addr; /* We may support two chips. */ |
235 | bool has_second_chip; | 277 | bool has_second_chip; |
278 | struct mutex lock; | ||
279 | struct pm_qos_request pm_qos_req; | ||
236 | }; | 280 | }; |
237 | 281 | ||
238 | static inline int is_vybrid_qspi(struct fsl_qspi *q) | 282 | static inline int needs_swap_endian(struct fsl_qspi *q) |
283 | { | ||
284 | return q->devtype_data->driver_data & QUADSPI_QUIRK_SWAP_ENDIAN; | ||
285 | } | ||
286 | |||
287 | static inline int needs_4x_clock(struct fsl_qspi *q) | ||
288 | { | ||
289 | return q->devtype_data->driver_data & QUADSPI_QUIRK_4X_INT_CLK; | ||
290 | } | ||
291 | |||
292 | static inline int needs_fill_txfifo(struct fsl_qspi *q) | ||
239 | { | 293 | { |
240 | return q->devtype_data->devtype == FSL_QUADSPI_VYBRID; | 294 | return q->devtype_data->driver_data & QUADSPI_QUIRK_TKT253890; |
241 | } | 295 | } |
242 | 296 | ||
243 | static inline int is_imx6sx_qspi(struct fsl_qspi *q) | 297 | static inline int needs_wakeup_wait_mode(struct fsl_qspi *q) |
244 | { | 298 | { |
245 | return q->devtype_data->devtype == FSL_QUADSPI_IMX6SX; | 299 | return q->devtype_data->driver_data & QUADSPI_QUIRK_TKT245618; |
246 | } | 300 | } |
247 | 301 | ||
248 | /* | 302 | /* |
@@ -251,7 +305,7 @@ static inline int is_imx6sx_qspi(struct fsl_qspi *q) | |||
251 | */ | 305 | */ |
252 | static inline u32 fsl_qspi_endian_xchg(struct fsl_qspi *q, u32 a) | 306 | static inline u32 fsl_qspi_endian_xchg(struct fsl_qspi *q, u32 a) |
253 | { | 307 | { |
254 | return is_vybrid_qspi(q) ? __swab32(a) : a; | 308 | return needs_swap_endian(q) ? __swab32(a) : a; |
255 | } | 309 | } |
256 | 310 | ||
257 | static inline void fsl_qspi_unlock_lut(struct fsl_qspi *q) | 311 | static inline void fsl_qspi_unlock_lut(struct fsl_qspi *q) |
@@ -343,14 +397,8 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q) | |||
343 | /* Erase a sector */ | 397 | /* Erase a sector */ |
344 | lut_base = SEQID_SE * 4; | 398 | lut_base = SEQID_SE * 4; |
345 | 399 | ||
346 | if (q->nor_size <= SZ_16M) { | 400 | cmd = q->nor[0].erase_opcode; |
347 | cmd = SPINOR_OP_SE; | 401 | addrlen = q->nor_size <= SZ_16M ? ADDR24BIT : ADDR32BIT; |
348 | addrlen = ADDR24BIT; | ||
349 | } else { | ||
350 | /* use the 4-byte address */ | ||
351 | cmd = SPINOR_OP_SE; | ||
352 | addrlen = ADDR32BIT; | ||
353 | } | ||
354 | 402 | ||
355 | writel(LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen), | 403 | writel(LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen), |
356 | base + QUADSPI_LUT(lut_base)); | 404 | base + QUADSPI_LUT(lut_base)); |
@@ -419,6 +467,8 @@ static int fsl_qspi_get_seqid(struct fsl_qspi *q, u8 cmd) | |||
419 | case SPINOR_OP_BRWR: | 467 | case SPINOR_OP_BRWR: |
420 | return SEQID_BRWR; | 468 | return SEQID_BRWR; |
421 | default: | 469 | default: |
470 | if (cmd == q->nor[0].erase_opcode) | ||
471 | return SEQID_SE; | ||
422 | dev_err(q->dev, "Unsupported cmd 0x%.2x\n", cmd); | 472 | dev_err(q->dev, "Unsupported cmd 0x%.2x\n", cmd); |
423 | break; | 473 | break; |
424 | } | 474 | } |
@@ -537,7 +587,7 @@ static int fsl_qspi_nor_write(struct fsl_qspi *q, struct spi_nor *nor, | |||
537 | 587 | ||
538 | /* clear the TX FIFO. */ | 588 | /* clear the TX FIFO. */ |
539 | tmp = readl(q->iobase + QUADSPI_MCR); | 589 | tmp = readl(q->iobase + QUADSPI_MCR); |
540 | writel(tmp | QUADSPI_MCR_CLR_RXF_MASK, q->iobase + QUADSPI_MCR); | 590 | writel(tmp | QUADSPI_MCR_CLR_TXF_MASK, q->iobase + QUADSPI_MCR); |
541 | 591 | ||
542 | /* fill the TX data to the FIFO */ | 592 | /* fill the TX data to the FIFO */ |
543 | for (j = 0, i = ((count + 3) / 4); j < i; j++) { | 593 | for (j = 0, i = ((count + 3) / 4); j < i; j++) { |
@@ -546,6 +596,11 @@ static int fsl_qspi_nor_write(struct fsl_qspi *q, struct spi_nor *nor, | |||
546 | txbuf++; | 596 | txbuf++; |
547 | } | 597 | } |
548 | 598 | ||
599 | /* fill the TXFIFO upto 16 bytes for i.MX7d */ | ||
600 | if (needs_fill_txfifo(q)) | ||
601 | for (; i < 4; i++) | ||
602 | writel(tmp, q->iobase + QUADSPI_TBDR); | ||
603 | |||
549 | /* Trigger it */ | 604 | /* Trigger it */ |
550 | ret = fsl_qspi_runcmd(q, opcode, to, count); | 605 | ret = fsl_qspi_runcmd(q, opcode, to, count); |
551 | 606 | ||
@@ -606,6 +661,38 @@ static void fsl_qspi_init_abh_read(struct fsl_qspi *q) | |||
606 | q->iobase + QUADSPI_BFGENCR); | 661 | q->iobase + QUADSPI_BFGENCR); |
607 | } | 662 | } |
608 | 663 | ||
664 | /* This function was used to prepare and enable QSPI clock */ | ||
665 | static int fsl_qspi_clk_prep_enable(struct fsl_qspi *q) | ||
666 | { | ||
667 | int ret; | ||
668 | |||
669 | ret = clk_prepare_enable(q->clk_en); | ||
670 | if (ret) | ||
671 | return ret; | ||
672 | |||
673 | ret = clk_prepare_enable(q->clk); | ||
674 | if (ret) { | ||
675 | clk_disable_unprepare(q->clk_en); | ||
676 | return ret; | ||
677 | } | ||
678 | |||
679 | if (needs_wakeup_wait_mode(q)) | ||
680 | pm_qos_add_request(&q->pm_qos_req, PM_QOS_CPU_DMA_LATENCY, 0); | ||
681 | |||
682 | return 0; | ||
683 | } | ||
684 | |||
685 | /* This function was used to disable and unprepare QSPI clock */ | ||
686 | static void fsl_qspi_clk_disable_unprep(struct fsl_qspi *q) | ||
687 | { | ||
688 | if (needs_wakeup_wait_mode(q)) | ||
689 | pm_qos_remove_request(&q->pm_qos_req); | ||
690 | |||
691 | clk_disable_unprepare(q->clk); | ||
692 | clk_disable_unprepare(q->clk_en); | ||
693 | |||
694 | } | ||
695 | |||
609 | /* We use this function to do some basic init for spi_nor_scan(). */ | 696 | /* We use this function to do some basic init for spi_nor_scan(). */ |
610 | static int fsl_qspi_nor_setup(struct fsl_qspi *q) | 697 | static int fsl_qspi_nor_setup(struct fsl_qspi *q) |
611 | { | 698 | { |
@@ -613,11 +700,23 @@ static int fsl_qspi_nor_setup(struct fsl_qspi *q) | |||
613 | u32 reg; | 700 | u32 reg; |
614 | int ret; | 701 | int ret; |
615 | 702 | ||
616 | /* the default frequency, we will change it in the future.*/ | 703 | /* disable and unprepare clock to avoid glitch pass to controller */ |
704 | fsl_qspi_clk_disable_unprep(q); | ||
705 | |||
706 | /* the default frequency, we will change it in the future. */ | ||
617 | ret = clk_set_rate(q->clk, 66000000); | 707 | ret = clk_set_rate(q->clk, 66000000); |
618 | if (ret) | 708 | if (ret) |
619 | return ret; | 709 | return ret; |
620 | 710 | ||
711 | ret = fsl_qspi_clk_prep_enable(q); | ||
712 | if (ret) | ||
713 | return ret; | ||
714 | |||
715 | /* Reset the module */ | ||
716 | writel(QUADSPI_MCR_SWRSTSD_MASK | QUADSPI_MCR_SWRSTHD_MASK, | ||
717 | base + QUADSPI_MCR); | ||
718 | udelay(1); | ||
719 | |||
621 | /* Init the LUT table. */ | 720 | /* Init the LUT table. */ |
622 | fsl_qspi_init_lut(q); | 721 | fsl_qspi_init_lut(q); |
623 | 722 | ||
@@ -635,6 +734,9 @@ static int fsl_qspi_nor_setup(struct fsl_qspi *q) | |||
635 | writel(QUADSPI_MCR_RESERVED_MASK | QUADSPI_MCR_END_CFG_MASK, | 734 | writel(QUADSPI_MCR_RESERVED_MASK | QUADSPI_MCR_END_CFG_MASK, |
636 | base + QUADSPI_MCR); | 735 | base + QUADSPI_MCR); |
637 | 736 | ||
737 | /* clear all interrupt status */ | ||
738 | writel(0xffffffff, q->iobase + QUADSPI_FR); | ||
739 | |||
638 | /* enable the interrupt */ | 740 | /* enable the interrupt */ |
639 | writel(QUADSPI_RSER_TFIE, q->iobase + QUADSPI_RSER); | 741 | writel(QUADSPI_RSER_TFIE, q->iobase + QUADSPI_RSER); |
640 | 742 | ||
@@ -646,13 +748,20 @@ static int fsl_qspi_nor_setup_last(struct fsl_qspi *q) | |||
646 | unsigned long rate = q->clk_rate; | 748 | unsigned long rate = q->clk_rate; |
647 | int ret; | 749 | int ret; |
648 | 750 | ||
649 | if (is_imx6sx_qspi(q)) | 751 | if (needs_4x_clock(q)) |
650 | rate *= 4; | 752 | rate *= 4; |
651 | 753 | ||
754 | /* disable and unprepare clock to avoid glitch pass to controller */ | ||
755 | fsl_qspi_clk_disable_unprep(q); | ||
756 | |||
652 | ret = clk_set_rate(q->clk, rate); | 757 | ret = clk_set_rate(q->clk, rate); |
653 | if (ret) | 758 | if (ret) |
654 | return ret; | 759 | return ret; |
655 | 760 | ||
761 | ret = fsl_qspi_clk_prep_enable(q); | ||
762 | if (ret) | ||
763 | return ret; | ||
764 | |||
656 | /* Init the LUT table again. */ | 765 | /* Init the LUT table again. */ |
657 | fsl_qspi_init_lut(q); | 766 | fsl_qspi_init_lut(q); |
658 | 767 | ||
@@ -665,6 +774,8 @@ static int fsl_qspi_nor_setup_last(struct fsl_qspi *q) | |||
665 | static const struct of_device_id fsl_qspi_dt_ids[] = { | 774 | static const struct of_device_id fsl_qspi_dt_ids[] = { |
666 | { .compatible = "fsl,vf610-qspi", .data = (void *)&vybrid_data, }, | 775 | { .compatible = "fsl,vf610-qspi", .data = (void *)&vybrid_data, }, |
667 | { .compatible = "fsl,imx6sx-qspi", .data = (void *)&imx6sx_data, }, | 776 | { .compatible = "fsl,imx6sx-qspi", .data = (void *)&imx6sx_data, }, |
777 | { .compatible = "fsl,imx7d-qspi", .data = (void *)&imx7d_data, }, | ||
778 | { .compatible = "fsl,imx6ul-qspi", .data = (void *)&imx6ul_data, }, | ||
668 | { /* sentinel */ } | 779 | { /* sentinel */ } |
669 | }; | 780 | }; |
670 | MODULE_DEVICE_TABLE(of, fsl_qspi_dt_ids); | 781 | MODULE_DEVICE_TABLE(of, fsl_qspi_dt_ids); |
@@ -730,11 +841,42 @@ static int fsl_qspi_read(struct spi_nor *nor, loff_t from, | |||
730 | struct fsl_qspi *q = nor->priv; | 841 | struct fsl_qspi *q = nor->priv; |
731 | u8 cmd = nor->read_opcode; | 842 | u8 cmd = nor->read_opcode; |
732 | 843 | ||
733 | dev_dbg(q->dev, "cmd [%x],read from (0x%p, 0x%.8x, 0x%.8x),len:%d\n", | 844 | /* if necessary,ioremap buffer before AHB read, */ |
734 | cmd, q->ahb_base, q->chip_base_addr, (unsigned int)from, len); | 845 | if (!q->ahb_addr) { |
846 | q->memmap_offs = q->chip_base_addr + from; | ||
847 | q->memmap_len = len > QUADSPI_MIN_IOMAP ? len : QUADSPI_MIN_IOMAP; | ||
848 | |||
849 | q->ahb_addr = ioremap_nocache( | ||
850 | q->memmap_phy + q->memmap_offs, | ||
851 | q->memmap_len); | ||
852 | if (!q->ahb_addr) { | ||
853 | dev_err(q->dev, "ioremap failed\n"); | ||
854 | return -ENOMEM; | ||
855 | } | ||
856 | /* ioremap if the data requested is out of range */ | ||
857 | } else if (q->chip_base_addr + from < q->memmap_offs | ||
858 | || q->chip_base_addr + from + len > | ||
859 | q->memmap_offs + q->memmap_len) { | ||
860 | iounmap(q->ahb_addr); | ||
861 | |||
862 | q->memmap_offs = q->chip_base_addr + from; | ||
863 | q->memmap_len = len > QUADSPI_MIN_IOMAP ? len : QUADSPI_MIN_IOMAP; | ||
864 | q->ahb_addr = ioremap_nocache( | ||
865 | q->memmap_phy + q->memmap_offs, | ||
866 | q->memmap_len); | ||
867 | if (!q->ahb_addr) { | ||
868 | dev_err(q->dev, "ioremap failed\n"); | ||
869 | return -ENOMEM; | ||
870 | } | ||
871 | } | ||
872 | |||
873 | dev_dbg(q->dev, "cmd [%x],read from 0x%p, len:%d\n", | ||
874 | cmd, q->ahb_addr + q->chip_base_addr + from - q->memmap_offs, | ||
875 | len); | ||
735 | 876 | ||
736 | /* Read out the data directly from the AHB buffer.*/ | 877 | /* Read out the data directly from the AHB buffer.*/ |
737 | memcpy(buf, q->ahb_base + q->chip_base_addr + from, len); | 878 | memcpy(buf, q->ahb_addr + q->chip_base_addr + from - q->memmap_offs, |
879 | len); | ||
738 | 880 | ||
739 | *retlen += len; | 881 | *retlen += len; |
740 | return 0; | 882 | return 0; |
@@ -761,26 +903,26 @@ static int fsl_qspi_prep(struct spi_nor *nor, enum spi_nor_ops ops) | |||
761 | struct fsl_qspi *q = nor->priv; | 903 | struct fsl_qspi *q = nor->priv; |
762 | int ret; | 904 | int ret; |
763 | 905 | ||
764 | ret = clk_enable(q->clk_en); | 906 | mutex_lock(&q->lock); |
765 | if (ret) | ||
766 | return ret; | ||
767 | 907 | ||
768 | ret = clk_enable(q->clk); | 908 | ret = fsl_qspi_clk_prep_enable(q); |
769 | if (ret) { | 909 | if (ret) |
770 | clk_disable(q->clk_en); | 910 | goto err_mutex; |
771 | return ret; | ||
772 | } | ||
773 | 911 | ||
774 | fsl_qspi_set_base_addr(q, nor); | 912 | fsl_qspi_set_base_addr(q, nor); |
775 | return 0; | 913 | return 0; |
914 | |||
915 | err_mutex: | ||
916 | mutex_unlock(&q->lock); | ||
917 | return ret; | ||
776 | } | 918 | } |
777 | 919 | ||
778 | static void fsl_qspi_unprep(struct spi_nor *nor, enum spi_nor_ops ops) | 920 | static void fsl_qspi_unprep(struct spi_nor *nor, enum spi_nor_ops ops) |
779 | { | 921 | { |
780 | struct fsl_qspi *q = nor->priv; | 922 | struct fsl_qspi *q = nor->priv; |
781 | 923 | ||
782 | clk_disable(q->clk); | 924 | fsl_qspi_clk_disable_unprep(q); |
783 | clk_disable(q->clk_en); | 925 | mutex_unlock(&q->lock); |
784 | } | 926 | } |
785 | 927 | ||
786 | static int fsl_qspi_probe(struct platform_device *pdev) | 928 | static int fsl_qspi_probe(struct platform_device *pdev) |
@@ -804,6 +946,10 @@ static int fsl_qspi_probe(struct platform_device *pdev) | |||
804 | if (!q->nor_num || q->nor_num > FSL_QSPI_MAX_CHIP) | 946 | if (!q->nor_num || q->nor_num > FSL_QSPI_MAX_CHIP) |
805 | return -ENODEV; | 947 | return -ENODEV; |
806 | 948 | ||
949 | q->dev = dev; | ||
950 | q->devtype_data = (struct fsl_qspi_devtype_data *)of_id->data; | ||
951 | platform_set_drvdata(pdev, q); | ||
952 | |||
807 | /* find the resources */ | 953 | /* find the resources */ |
808 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "QuadSPI"); | 954 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "QuadSPI"); |
809 | q->iobase = devm_ioremap_resource(dev, res); | 955 | q->iobase = devm_ioremap_resource(dev, res); |
@@ -812,9 +958,11 @@ static int fsl_qspi_probe(struct platform_device *pdev) | |||
812 | 958 | ||
813 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, | 959 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, |
814 | "QuadSPI-memory"); | 960 | "QuadSPI-memory"); |
815 | q->ahb_base = devm_ioremap_resource(dev, res); | 961 | if (!devm_request_mem_region(dev, res->start, resource_size(res), |
816 | if (IS_ERR(q->ahb_base)) | 962 | res->name)) { |
817 | return PTR_ERR(q->ahb_base); | 963 | dev_err(dev, "can't request region for resource %pR\n", res); |
964 | return -EBUSY; | ||
965 | } | ||
818 | 966 | ||
819 | q->memmap_phy = res->start; | 967 | q->memmap_phy = res->start; |
820 | 968 | ||
@@ -827,15 +975,9 @@ static int fsl_qspi_probe(struct platform_device *pdev) | |||
827 | if (IS_ERR(q->clk)) | 975 | if (IS_ERR(q->clk)) |
828 | return PTR_ERR(q->clk); | 976 | return PTR_ERR(q->clk); |
829 | 977 | ||
830 | ret = clk_prepare_enable(q->clk_en); | 978 | ret = fsl_qspi_clk_prep_enable(q); |
831 | if (ret) { | ||
832 | dev_err(dev, "cannot enable the qspi_en clock: %d\n", ret); | ||
833 | return ret; | ||
834 | } | ||
835 | |||
836 | ret = clk_prepare_enable(q->clk); | ||
837 | if (ret) { | 979 | if (ret) { |
838 | dev_err(dev, "cannot enable the qspi clock: %d\n", ret); | 980 | dev_err(dev, "can not enable the clock\n"); |
839 | goto clk_failed; | 981 | goto clk_failed; |
840 | } | 982 | } |
841 | 983 | ||
@@ -853,10 +995,6 @@ static int fsl_qspi_probe(struct platform_device *pdev) | |||
853 | goto irq_failed; | 995 | goto irq_failed; |
854 | } | 996 | } |
855 | 997 | ||
856 | q->dev = dev; | ||
857 | q->devtype_data = (struct fsl_qspi_devtype_data *)of_id->data; | ||
858 | platform_set_drvdata(pdev, q); | ||
859 | |||
860 | ret = fsl_qspi_nor_setup(q); | 998 | ret = fsl_qspi_nor_setup(q); |
861 | if (ret) | 999 | if (ret) |
862 | goto irq_failed; | 1000 | goto irq_failed; |
@@ -864,6 +1002,8 @@ static int fsl_qspi_probe(struct platform_device *pdev) | |||
864 | if (of_get_property(np, "fsl,qspi-has-second-chip", NULL)) | 1002 | if (of_get_property(np, "fsl,qspi-has-second-chip", NULL)) |
865 | q->has_second_chip = true; | 1003 | q->has_second_chip = true; |
866 | 1004 | ||
1005 | mutex_init(&q->lock); | ||
1006 | |||
867 | /* iterate the subnodes. */ | 1007 | /* iterate the subnodes. */ |
868 | for_each_available_child_of_node(dev->of_node, np) { | 1008 | for_each_available_child_of_node(dev->of_node, np) { |
869 | char modalias[40]; | 1009 | char modalias[40]; |
@@ -892,24 +1032,24 @@ static int fsl_qspi_probe(struct platform_device *pdev) | |||
892 | 1032 | ||
893 | ret = of_modalias_node(np, modalias, sizeof(modalias)); | 1033 | ret = of_modalias_node(np, modalias, sizeof(modalias)); |
894 | if (ret < 0) | 1034 | if (ret < 0) |
895 | goto irq_failed; | 1035 | goto mutex_failed; |
896 | 1036 | ||
897 | ret = of_property_read_u32(np, "spi-max-frequency", | 1037 | ret = of_property_read_u32(np, "spi-max-frequency", |
898 | &q->clk_rate); | 1038 | &q->clk_rate); |
899 | if (ret < 0) | 1039 | if (ret < 0) |
900 | goto irq_failed; | 1040 | goto mutex_failed; |
901 | 1041 | ||
902 | /* set the chip address for READID */ | 1042 | /* set the chip address for READID */ |
903 | fsl_qspi_set_base_addr(q, nor); | 1043 | fsl_qspi_set_base_addr(q, nor); |
904 | 1044 | ||
905 | ret = spi_nor_scan(nor, modalias, SPI_NOR_QUAD); | 1045 | ret = spi_nor_scan(nor, modalias, SPI_NOR_QUAD); |
906 | if (ret) | 1046 | if (ret) |
907 | goto irq_failed; | 1047 | goto mutex_failed; |
908 | 1048 | ||
909 | ppdata.of_node = np; | 1049 | ppdata.of_node = np; |
910 | ret = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0); | 1050 | ret = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0); |
911 | if (ret) | 1051 | if (ret) |
912 | goto irq_failed; | 1052 | goto mutex_failed; |
913 | 1053 | ||
914 | /* Set the correct NOR size now. */ | 1054 | /* Set the correct NOR size now. */ |
915 | if (q->nor_size == 0) { | 1055 | if (q->nor_size == 0) { |
@@ -939,8 +1079,7 @@ static int fsl_qspi_probe(struct platform_device *pdev) | |||
939 | if (ret) | 1079 | if (ret) |
940 | goto last_init_failed; | 1080 | goto last_init_failed; |
941 | 1081 | ||
942 | clk_disable(q->clk); | 1082 | fsl_qspi_clk_disable_unprep(q); |
943 | clk_disable(q->clk_en); | ||
944 | return 0; | 1083 | return 0; |
945 | 1084 | ||
946 | last_init_failed: | 1085 | last_init_failed: |
@@ -950,10 +1089,12 @@ last_init_failed: | |||
950 | i *= 2; | 1089 | i *= 2; |
951 | mtd_device_unregister(&q->mtd[i]); | 1090 | mtd_device_unregister(&q->mtd[i]); |
952 | } | 1091 | } |
1092 | mutex_failed: | ||
1093 | mutex_destroy(&q->lock); | ||
953 | irq_failed: | 1094 | irq_failed: |
954 | clk_disable_unprepare(q->clk); | 1095 | fsl_qspi_clk_disable_unprep(q); |
955 | clk_failed: | 1096 | clk_failed: |
956 | clk_disable_unprepare(q->clk_en); | 1097 | dev_err(dev, "Freescale QuadSPI probe failed\n"); |
957 | return ret; | 1098 | return ret; |
958 | } | 1099 | } |
959 | 1100 | ||
@@ -973,8 +1114,11 @@ static int fsl_qspi_remove(struct platform_device *pdev) | |||
973 | writel(QUADSPI_MCR_MDIS_MASK, q->iobase + QUADSPI_MCR); | 1114 | writel(QUADSPI_MCR_MDIS_MASK, q->iobase + QUADSPI_MCR); |
974 | writel(0x0, q->iobase + QUADSPI_RSER); | 1115 | writel(0x0, q->iobase + QUADSPI_RSER); |
975 | 1116 | ||
976 | clk_unprepare(q->clk); | 1117 | mutex_destroy(&q->lock); |
977 | clk_unprepare(q->clk_en); | 1118 | |
1119 | if (q->ahb_addr) | ||
1120 | iounmap(q->ahb_addr); | ||
1121 | |||
978 | return 0; | 1122 | return 0; |
979 | } | 1123 | } |
980 | 1124 | ||
@@ -985,12 +1129,19 @@ static int fsl_qspi_suspend(struct platform_device *pdev, pm_message_t state) | |||
985 | 1129 | ||
986 | static int fsl_qspi_resume(struct platform_device *pdev) | 1130 | static int fsl_qspi_resume(struct platform_device *pdev) |
987 | { | 1131 | { |
1132 | int ret; | ||
988 | struct fsl_qspi *q = platform_get_drvdata(pdev); | 1133 | struct fsl_qspi *q = platform_get_drvdata(pdev); |
989 | 1134 | ||
1135 | ret = fsl_qspi_clk_prep_enable(q); | ||
1136 | if (ret) | ||
1137 | return ret; | ||
1138 | |||
990 | fsl_qspi_nor_setup(q); | 1139 | fsl_qspi_nor_setup(q); |
991 | fsl_qspi_set_map_addr(q); | 1140 | fsl_qspi_set_map_addr(q); |
992 | fsl_qspi_nor_setup_last(q); | 1141 | fsl_qspi_nor_setup_last(q); |
993 | 1142 | ||
1143 | fsl_qspi_clk_disable_unprep(q); | ||
1144 | |||
994 | return 0; | 1145 | return 0; |
995 | } | 1146 | } |
996 | 1147 | ||
diff --git a/drivers/mtd/spi-nor/nxp-spifi.c b/drivers/mtd/spi-nor/nxp-spifi.c new file mode 100644 index 000000000000..9ad1dd0896c0 --- /dev/null +++ b/drivers/mtd/spi-nor/nxp-spifi.c | |||
@@ -0,0 +1,482 @@ | |||
1 | /* | ||
2 | * SPI-NOR driver for NXP SPI Flash Interface (SPIFI) | ||
3 | * | ||
4 | * Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com> | ||
5 | * | ||
6 | * Based on Freescale QuadSPI driver: | ||
7 | * Copyright (C) 2013 Freescale Semiconductor, Inc. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #include <linux/clk.h> | ||
16 | #include <linux/err.h> | ||
17 | #include <linux/io.h> | ||
18 | #include <linux/iopoll.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/mtd/mtd.h> | ||
21 | #include <linux/mtd/partitions.h> | ||
22 | #include <linux/mtd/spi-nor.h> | ||
23 | #include <linux/of.h> | ||
24 | #include <linux/of_device.h> | ||
25 | #include <linux/platform_device.h> | ||
26 | #include <linux/spi/spi.h> | ||
27 | |||
28 | /* NXP SPIFI registers, bits and macros */ | ||
29 | #define SPIFI_CTRL 0x000 | ||
30 | #define SPIFI_CTRL_TIMEOUT(timeout) (timeout) | ||
31 | #define SPIFI_CTRL_CSHIGH(cshigh) ((cshigh) << 16) | ||
32 | #define SPIFI_CTRL_MODE3 BIT(23) | ||
33 | #define SPIFI_CTRL_DUAL BIT(28) | ||
34 | #define SPIFI_CTRL_FBCLK BIT(30) | ||
35 | #define SPIFI_CMD 0x004 | ||
36 | #define SPIFI_CMD_DATALEN(dlen) ((dlen) & 0x3fff) | ||
37 | #define SPIFI_CMD_DOUT BIT(15) | ||
38 | #define SPIFI_CMD_INTLEN(ilen) ((ilen) << 16) | ||
39 | #define SPIFI_CMD_FIELDFORM(field) ((field) << 19) | ||
40 | #define SPIFI_CMD_FIELDFORM_ALL_SERIAL SPIFI_CMD_FIELDFORM(0x0) | ||
41 | #define SPIFI_CMD_FIELDFORM_QUAD_DUAL_DATA SPIFI_CMD_FIELDFORM(0x1) | ||
42 | #define SPIFI_CMD_FRAMEFORM(frame) ((frame) << 21) | ||
43 | #define SPIFI_CMD_FRAMEFORM_OPCODE_ONLY SPIFI_CMD_FRAMEFORM(0x1) | ||
44 | #define SPIFI_CMD_OPCODE(op) ((op) << 24) | ||
45 | #define SPIFI_ADDR 0x008 | ||
46 | #define SPIFI_IDATA 0x00c | ||
47 | #define SPIFI_CLIMIT 0x010 | ||
48 | #define SPIFI_DATA 0x014 | ||
49 | #define SPIFI_MCMD 0x018 | ||
50 | #define SPIFI_STAT 0x01c | ||
51 | #define SPIFI_STAT_MCINIT BIT(0) | ||
52 | #define SPIFI_STAT_CMD BIT(1) | ||
53 | #define SPIFI_STAT_RESET BIT(4) | ||
54 | |||
55 | #define SPI_NOR_MAX_ID_LEN 6 | ||
56 | |||
57 | struct nxp_spifi { | ||
58 | struct device *dev; | ||
59 | struct clk *clk_spifi; | ||
60 | struct clk *clk_reg; | ||
61 | void __iomem *io_base; | ||
62 | void __iomem *flash_base; | ||
63 | struct mtd_info mtd; | ||
64 | struct spi_nor nor; | ||
65 | bool memory_mode; | ||
66 | u32 mcmd; | ||
67 | }; | ||
68 | |||
69 | static int nxp_spifi_wait_for_cmd(struct nxp_spifi *spifi) | ||
70 | { | ||
71 | u8 stat; | ||
72 | int ret; | ||
73 | |||
74 | ret = readb_poll_timeout(spifi->io_base + SPIFI_STAT, stat, | ||
75 | !(stat & SPIFI_STAT_CMD), 10, 30); | ||
76 | if (ret) | ||
77 | dev_warn(spifi->dev, "command timed out\n"); | ||
78 | |||
79 | return ret; | ||
80 | } | ||
81 | |||
82 | static int nxp_spifi_reset(struct nxp_spifi *spifi) | ||
83 | { | ||
84 | u8 stat; | ||
85 | int ret; | ||
86 | |||
87 | writel(SPIFI_STAT_RESET, spifi->io_base + SPIFI_STAT); | ||
88 | ret = readb_poll_timeout(spifi->io_base + SPIFI_STAT, stat, | ||
89 | !(stat & SPIFI_STAT_RESET), 10, 30); | ||
90 | if (ret) | ||
91 | dev_warn(spifi->dev, "state reset timed out\n"); | ||
92 | |||
93 | return ret; | ||
94 | } | ||
95 | |||
96 | static int nxp_spifi_set_memory_mode_off(struct nxp_spifi *spifi) | ||
97 | { | ||
98 | int ret; | ||
99 | |||
100 | if (!spifi->memory_mode) | ||
101 | return 0; | ||
102 | |||
103 | ret = nxp_spifi_reset(spifi); | ||
104 | if (ret) | ||
105 | dev_err(spifi->dev, "unable to enter command mode\n"); | ||
106 | else | ||
107 | spifi->memory_mode = false; | ||
108 | |||
109 | return ret; | ||
110 | } | ||
111 | |||
112 | static int nxp_spifi_set_memory_mode_on(struct nxp_spifi *spifi) | ||
113 | { | ||
114 | u8 stat; | ||
115 | int ret; | ||
116 | |||
117 | if (spifi->memory_mode) | ||
118 | return 0; | ||
119 | |||
120 | writel(spifi->mcmd, spifi->io_base + SPIFI_MCMD); | ||
121 | ret = readb_poll_timeout(spifi->io_base + SPIFI_STAT, stat, | ||
122 | stat & SPIFI_STAT_MCINIT, 10, 30); | ||
123 | if (ret) | ||
124 | dev_err(spifi->dev, "unable to enter memory mode\n"); | ||
125 | else | ||
126 | spifi->memory_mode = true; | ||
127 | |||
128 | return ret; | ||
129 | } | ||
130 | |||
131 | static int nxp_spifi_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len) | ||
132 | { | ||
133 | struct nxp_spifi *spifi = nor->priv; | ||
134 | u32 cmd; | ||
135 | int ret; | ||
136 | |||
137 | ret = nxp_spifi_set_memory_mode_off(spifi); | ||
138 | if (ret) | ||
139 | return ret; | ||
140 | |||
141 | cmd = SPIFI_CMD_DATALEN(len) | | ||
142 | SPIFI_CMD_OPCODE(opcode) | | ||
143 | SPIFI_CMD_FIELDFORM_ALL_SERIAL | | ||
144 | SPIFI_CMD_FRAMEFORM_OPCODE_ONLY; | ||
145 | writel(cmd, spifi->io_base + SPIFI_CMD); | ||
146 | |||
147 | while (len--) | ||
148 | *buf++ = readb(spifi->io_base + SPIFI_DATA); | ||
149 | |||
150 | return nxp_spifi_wait_for_cmd(spifi); | ||
151 | } | ||
152 | |||
153 | static int nxp_spifi_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, | ||
154 | int len, int write_enable) | ||
155 | { | ||
156 | struct nxp_spifi *spifi = nor->priv; | ||
157 | u32 cmd; | ||
158 | int ret; | ||
159 | |||
160 | ret = nxp_spifi_set_memory_mode_off(spifi); | ||
161 | if (ret) | ||
162 | return ret; | ||
163 | |||
164 | cmd = SPIFI_CMD_DOUT | | ||
165 | SPIFI_CMD_DATALEN(len) | | ||
166 | SPIFI_CMD_OPCODE(opcode) | | ||
167 | SPIFI_CMD_FIELDFORM_ALL_SERIAL | | ||
168 | SPIFI_CMD_FRAMEFORM_OPCODE_ONLY; | ||
169 | writel(cmd, spifi->io_base + SPIFI_CMD); | ||
170 | |||
171 | while (len--) | ||
172 | writeb(*buf++, spifi->io_base + SPIFI_DATA); | ||
173 | |||
174 | return nxp_spifi_wait_for_cmd(spifi); | ||
175 | } | ||
176 | |||
177 | static int nxp_spifi_read(struct spi_nor *nor, loff_t from, size_t len, | ||
178 | size_t *retlen, u_char *buf) | ||
179 | { | ||
180 | struct nxp_spifi *spifi = nor->priv; | ||
181 | int ret; | ||
182 | |||
183 | ret = nxp_spifi_set_memory_mode_on(spifi); | ||
184 | if (ret) | ||
185 | return ret; | ||
186 | |||
187 | memcpy_fromio(buf, spifi->flash_base + from, len); | ||
188 | *retlen += len; | ||
189 | |||
190 | return 0; | ||
191 | } | ||
192 | |||
193 | static void nxp_spifi_write(struct spi_nor *nor, loff_t to, size_t len, | ||
194 | size_t *retlen, const u_char *buf) | ||
195 | { | ||
196 | struct nxp_spifi *spifi = nor->priv; | ||
197 | u32 cmd; | ||
198 | int ret; | ||
199 | |||
200 | ret = nxp_spifi_set_memory_mode_off(spifi); | ||
201 | if (ret) | ||
202 | return; | ||
203 | |||
204 | writel(to, spifi->io_base + SPIFI_ADDR); | ||
205 | *retlen += len; | ||
206 | |||
207 | cmd = SPIFI_CMD_DOUT | | ||
208 | SPIFI_CMD_DATALEN(len) | | ||
209 | SPIFI_CMD_FIELDFORM_ALL_SERIAL | | ||
210 | SPIFI_CMD_OPCODE(nor->program_opcode) | | ||
211 | SPIFI_CMD_FRAMEFORM(spifi->nor.addr_width + 1); | ||
212 | writel(cmd, spifi->io_base + SPIFI_CMD); | ||
213 | |||
214 | while (len--) | ||
215 | writeb(*buf++, spifi->io_base + SPIFI_DATA); | ||
216 | |||
217 | nxp_spifi_wait_for_cmd(spifi); | ||
218 | } | ||
219 | |||
220 | static int nxp_spifi_erase(struct spi_nor *nor, loff_t offs) | ||
221 | { | ||
222 | struct nxp_spifi *spifi = nor->priv; | ||
223 | u32 cmd; | ||
224 | int ret; | ||
225 | |||
226 | ret = nxp_spifi_set_memory_mode_off(spifi); | ||
227 | if (ret) | ||
228 | return ret; | ||
229 | |||
230 | writel(offs, spifi->io_base + SPIFI_ADDR); | ||
231 | |||
232 | cmd = SPIFI_CMD_FIELDFORM_ALL_SERIAL | | ||
233 | SPIFI_CMD_OPCODE(nor->erase_opcode) | | ||
234 | SPIFI_CMD_FRAMEFORM(spifi->nor.addr_width + 1); | ||
235 | writel(cmd, spifi->io_base + SPIFI_CMD); | ||
236 | |||
237 | return nxp_spifi_wait_for_cmd(spifi); | ||
238 | } | ||
239 | |||
240 | static int nxp_spifi_setup_memory_cmd(struct nxp_spifi *spifi) | ||
241 | { | ||
242 | switch (spifi->nor.flash_read) { | ||
243 | case SPI_NOR_NORMAL: | ||
244 | case SPI_NOR_FAST: | ||
245 | spifi->mcmd = SPIFI_CMD_FIELDFORM_ALL_SERIAL; | ||
246 | break; | ||
247 | case SPI_NOR_DUAL: | ||
248 | case SPI_NOR_QUAD: | ||
249 | spifi->mcmd = SPIFI_CMD_FIELDFORM_QUAD_DUAL_DATA; | ||
250 | break; | ||
251 | default: | ||
252 | dev_err(spifi->dev, "unsupported SPI read mode\n"); | ||
253 | return -EINVAL; | ||
254 | } | ||
255 | |||
256 | /* Memory mode supports address length between 1 and 4 */ | ||
257 | if (spifi->nor.addr_width < 1 || spifi->nor.addr_width > 4) | ||
258 | return -EINVAL; | ||
259 | |||
260 | spifi->mcmd |= SPIFI_CMD_OPCODE(spifi->nor.read_opcode) | | ||
261 | SPIFI_CMD_INTLEN(spifi->nor.read_dummy / 8) | | ||
262 | SPIFI_CMD_FRAMEFORM(spifi->nor.addr_width + 1); | ||
263 | |||
264 | return 0; | ||
265 | } | ||
266 | |||
267 | static void nxp_spifi_dummy_id_read(struct spi_nor *nor) | ||
268 | { | ||
269 | u8 id[SPI_NOR_MAX_ID_LEN]; | ||
270 | nor->read_reg(nor, SPINOR_OP_RDID, id, SPI_NOR_MAX_ID_LEN); | ||
271 | } | ||
272 | |||
273 | static int nxp_spifi_setup_flash(struct nxp_spifi *spifi, | ||
274 | struct device_node *np) | ||
275 | { | ||
276 | struct mtd_part_parser_data ppdata; | ||
277 | enum read_mode flash_read; | ||
278 | u32 ctrl, property; | ||
279 | u16 mode = 0; | ||
280 | int ret; | ||
281 | |||
282 | if (!of_property_read_u32(np, "spi-rx-bus-width", &property)) { | ||
283 | switch (property) { | ||
284 | case 1: | ||
285 | break; | ||
286 | case 2: | ||
287 | mode |= SPI_RX_DUAL; | ||
288 | break; | ||
289 | case 4: | ||
290 | mode |= SPI_RX_QUAD; | ||
291 | break; | ||
292 | default: | ||
293 | dev_err(spifi->dev, "unsupported rx-bus-width\n"); | ||
294 | return -EINVAL; | ||
295 | } | ||
296 | } | ||
297 | |||
298 | if (of_find_property(np, "spi-cpha", NULL)) | ||
299 | mode |= SPI_CPHA; | ||
300 | |||
301 | if (of_find_property(np, "spi-cpol", NULL)) | ||
302 | mode |= SPI_CPOL; | ||
303 | |||
304 | /* Setup control register defaults */ | ||
305 | ctrl = SPIFI_CTRL_TIMEOUT(1000) | | ||
306 | SPIFI_CTRL_CSHIGH(15) | | ||
307 | SPIFI_CTRL_FBCLK; | ||
308 | |||
309 | if (mode & SPI_RX_DUAL) { | ||
310 | ctrl |= SPIFI_CTRL_DUAL; | ||
311 | flash_read = SPI_NOR_DUAL; | ||
312 | } else if (mode & SPI_RX_QUAD) { | ||
313 | ctrl &= ~SPIFI_CTRL_DUAL; | ||
314 | flash_read = SPI_NOR_QUAD; | ||
315 | } else { | ||
316 | ctrl |= SPIFI_CTRL_DUAL; | ||
317 | flash_read = SPI_NOR_NORMAL; | ||
318 | } | ||
319 | |||
320 | switch (mode & (SPI_CPHA | SPI_CPOL)) { | ||
321 | case SPI_MODE_0: | ||
322 | ctrl &= ~SPIFI_CTRL_MODE3; | ||
323 | break; | ||
324 | case SPI_MODE_3: | ||
325 | ctrl |= SPIFI_CTRL_MODE3; | ||
326 | break; | ||
327 | default: | ||
328 | dev_err(spifi->dev, "only mode 0 and 3 supported\n"); | ||
329 | return -EINVAL; | ||
330 | } | ||
331 | |||
332 | writel(ctrl, spifi->io_base + SPIFI_CTRL); | ||
333 | |||
334 | spifi->mtd.priv = &spifi->nor; | ||
335 | spifi->nor.mtd = &spifi->mtd; | ||
336 | spifi->nor.dev = spifi->dev; | ||
337 | spifi->nor.priv = spifi; | ||
338 | spifi->nor.read = nxp_spifi_read; | ||
339 | spifi->nor.write = nxp_spifi_write; | ||
340 | spifi->nor.erase = nxp_spifi_erase; | ||
341 | spifi->nor.read_reg = nxp_spifi_read_reg; | ||
342 | spifi->nor.write_reg = nxp_spifi_write_reg; | ||
343 | |||
344 | /* | ||
345 | * The first read on a hard reset isn't reliable so do a | ||
346 | * dummy read of the id before calling spi_nor_scan(). | ||
347 | * The reason for this problem is unknown. | ||
348 | * | ||
349 | * The official NXP spifilib uses more or less the same | ||
350 | * workaround that is applied here by reading the device | ||
351 | * id multiple times. | ||
352 | */ | ||
353 | nxp_spifi_dummy_id_read(&spifi->nor); | ||
354 | |||
355 | ret = spi_nor_scan(&spifi->nor, NULL, flash_read); | ||
356 | if (ret) { | ||
357 | dev_err(spifi->dev, "device scan failed\n"); | ||
358 | return ret; | ||
359 | } | ||
360 | |||
361 | ret = nxp_spifi_setup_memory_cmd(spifi); | ||
362 | if (ret) { | ||
363 | dev_err(spifi->dev, "memory command setup failed\n"); | ||
364 | return ret; | ||
365 | } | ||
366 | |||
367 | ppdata.of_node = np; | ||
368 | ret = mtd_device_parse_register(&spifi->mtd, NULL, &ppdata, NULL, 0); | ||
369 | if (ret) { | ||
370 | dev_err(spifi->dev, "mtd device parse failed\n"); | ||
371 | return ret; | ||
372 | } | ||
373 | |||
374 | return 0; | ||
375 | } | ||
376 | |||
377 | static int nxp_spifi_probe(struct platform_device *pdev) | ||
378 | { | ||
379 | struct device_node *flash_np; | ||
380 | struct nxp_spifi *spifi; | ||
381 | struct resource *res; | ||
382 | int ret; | ||
383 | |||
384 | spifi = devm_kzalloc(&pdev->dev, sizeof(*spifi), GFP_KERNEL); | ||
385 | if (!spifi) | ||
386 | return -ENOMEM; | ||
387 | |||
388 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "spifi"); | ||
389 | spifi->io_base = devm_ioremap_resource(&pdev->dev, res); | ||
390 | if (IS_ERR(spifi->io_base)) | ||
391 | return PTR_ERR(spifi->io_base); | ||
392 | |||
393 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "flash"); | ||
394 | spifi->flash_base = devm_ioremap_resource(&pdev->dev, res); | ||
395 | if (IS_ERR(spifi->flash_base)) | ||
396 | return PTR_ERR(spifi->flash_base); | ||
397 | |||
398 | spifi->clk_spifi = devm_clk_get(&pdev->dev, "spifi"); | ||
399 | if (IS_ERR(spifi->clk_spifi)) { | ||
400 | dev_err(&pdev->dev, "spifi clock not found\n"); | ||
401 | return PTR_ERR(spifi->clk_spifi); | ||
402 | } | ||
403 | |||
404 | spifi->clk_reg = devm_clk_get(&pdev->dev, "reg"); | ||
405 | if (IS_ERR(spifi->clk_reg)) { | ||
406 | dev_err(&pdev->dev, "reg clock not found\n"); | ||
407 | return PTR_ERR(spifi->clk_reg); | ||
408 | } | ||
409 | |||
410 | ret = clk_prepare_enable(spifi->clk_reg); | ||
411 | if (ret) { | ||
412 | dev_err(&pdev->dev, "unable to enable reg clock\n"); | ||
413 | return ret; | ||
414 | } | ||
415 | |||
416 | ret = clk_prepare_enable(spifi->clk_spifi); | ||
417 | if (ret) { | ||
418 | dev_err(&pdev->dev, "unable to enable spifi clock\n"); | ||
419 | goto dis_clk_reg; | ||
420 | } | ||
421 | |||
422 | spifi->dev = &pdev->dev; | ||
423 | platform_set_drvdata(pdev, spifi); | ||
424 | |||
425 | /* Initialize and reset device */ | ||
426 | nxp_spifi_reset(spifi); | ||
427 | writel(0, spifi->io_base + SPIFI_IDATA); | ||
428 | writel(0, spifi->io_base + SPIFI_MCMD); | ||
429 | nxp_spifi_reset(spifi); | ||
430 | |||
431 | flash_np = of_get_next_available_child(pdev->dev.of_node, NULL); | ||
432 | if (!flash_np) { | ||
433 | dev_err(&pdev->dev, "no SPI flash device to configure\n"); | ||
434 | ret = -ENODEV; | ||
435 | goto dis_clks; | ||
436 | } | ||
437 | |||
438 | ret = nxp_spifi_setup_flash(spifi, flash_np); | ||
439 | if (ret) { | ||
440 | dev_err(&pdev->dev, "unable to setup flash chip\n"); | ||
441 | goto dis_clks; | ||
442 | } | ||
443 | |||
444 | return 0; | ||
445 | |||
446 | dis_clks: | ||
447 | clk_disable_unprepare(spifi->clk_spifi); | ||
448 | dis_clk_reg: | ||
449 | clk_disable_unprepare(spifi->clk_reg); | ||
450 | return ret; | ||
451 | } | ||
452 | |||
453 | static int nxp_spifi_remove(struct platform_device *pdev) | ||
454 | { | ||
455 | struct nxp_spifi *spifi = platform_get_drvdata(pdev); | ||
456 | |||
457 | mtd_device_unregister(&spifi->mtd); | ||
458 | clk_disable_unprepare(spifi->clk_spifi); | ||
459 | clk_disable_unprepare(spifi->clk_reg); | ||
460 | |||
461 | return 0; | ||
462 | } | ||
463 | |||
464 | static const struct of_device_id nxp_spifi_match[] = { | ||
465 | {.compatible = "nxp,lpc1773-spifi"}, | ||
466 | { /* sentinel */ } | ||
467 | }; | ||
468 | MODULE_DEVICE_TABLE(of, nxp_spifi_match); | ||
469 | |||
470 | static struct platform_driver nxp_spifi_driver = { | ||
471 | .probe = nxp_spifi_probe, | ||
472 | .remove = nxp_spifi_remove, | ||
473 | .driver = { | ||
474 | .name = "nxp-spifi", | ||
475 | .of_match_table = nxp_spifi_match, | ||
476 | }, | ||
477 | }; | ||
478 | module_platform_driver(nxp_spifi_driver); | ||
479 | |||
480 | MODULE_DESCRIPTION("NXP SPI Flash Interface driver"); | ||
481 | MODULE_AUTHOR("Joachim Eastwood <manabian@gmail.com>"); | ||
482 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index d78831b4422b..c27d427fead4 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c | |||
@@ -29,6 +29,8 @@ | |||
29 | #define SPI_NOR_MAX_ID_LEN 6 | 29 | #define SPI_NOR_MAX_ID_LEN 6 |
30 | 30 | ||
31 | struct flash_info { | 31 | struct flash_info { |
32 | char *name; | ||
33 | |||
32 | /* | 34 | /* |
33 | * This array stores the ID bytes. | 35 | * This array stores the ID bytes. |
34 | * The first three bytes are the JEDIC ID. | 36 | * The first three bytes are the JEDIC ID. |
@@ -59,7 +61,7 @@ struct flash_info { | |||
59 | 61 | ||
60 | #define JEDEC_MFR(info) ((info)->id[0]) | 62 | #define JEDEC_MFR(info) ((info)->id[0]) |
61 | 63 | ||
62 | static const struct spi_device_id *spi_nor_match_id(const char *name); | 64 | static const struct flash_info *spi_nor_match_id(const char *name); |
63 | 65 | ||
64 | /* | 66 | /* |
65 | * Read the status register, returning its value in the location | 67 | * 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 | } | 171 | } |
170 | 172 | ||
171 | /* Enable/disable 4-byte addressing mode. */ | 173 | /* Enable/disable 4-byte addressing mode. */ |
172 | static inline int set_4byte(struct spi_nor *nor, struct flash_info *info, | 174 | static inline int set_4byte(struct spi_nor *nor, const struct flash_info *info, |
173 | int enable) | 175 | int enable) |
174 | { | 176 | { |
175 | int status; | 177 | int status; |
@@ -469,7 +471,6 @@ static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) | |||
469 | 471 | ||
470 | /* Used when the "_ext_id" is two bytes at most */ | 472 | /* Used when the "_ext_id" is two bytes at most */ |
471 | #define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \ | 473 | #define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \ |
472 | ((kernel_ulong_t)&(struct flash_info) { \ | ||
473 | .id = { \ | 474 | .id = { \ |
474 | ((_jedec_id) >> 16) & 0xff, \ | 475 | ((_jedec_id) >> 16) & 0xff, \ |
475 | ((_jedec_id) >> 8) & 0xff, \ | 476 | ((_jedec_id) >> 8) & 0xff, \ |
@@ -481,11 +482,9 @@ static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) | |||
481 | .sector_size = (_sector_size), \ | 482 | .sector_size = (_sector_size), \ |
482 | .n_sectors = (_n_sectors), \ | 483 | .n_sectors = (_n_sectors), \ |
483 | .page_size = 256, \ | 484 | .page_size = 256, \ |
484 | .flags = (_flags), \ | 485 | .flags = (_flags), |
485 | }) | ||
486 | 486 | ||
487 | #define INFO6(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \ | 487 | #define INFO6(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \ |
488 | ((kernel_ulong_t)&(struct flash_info) { \ | ||
489 | .id = { \ | 488 | .id = { \ |
490 | ((_jedec_id) >> 16) & 0xff, \ | 489 | ((_jedec_id) >> 16) & 0xff, \ |
491 | ((_jedec_id) >> 8) & 0xff, \ | 490 | ((_jedec_id) >> 8) & 0xff, \ |
@@ -498,17 +497,14 @@ static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) | |||
498 | .sector_size = (_sector_size), \ | 497 | .sector_size = (_sector_size), \ |
499 | .n_sectors = (_n_sectors), \ | 498 | .n_sectors = (_n_sectors), \ |
500 | .page_size = 256, \ | 499 | .page_size = 256, \ |
501 | .flags = (_flags), \ | 500 | .flags = (_flags), |
502 | }) | ||
503 | 501 | ||
504 | #define CAT25_INFO(_sector_size, _n_sectors, _page_size, _addr_width, _flags) \ | 502 | #define CAT25_INFO(_sector_size, _n_sectors, _page_size, _addr_width, _flags) \ |
505 | ((kernel_ulong_t)&(struct flash_info) { \ | ||
506 | .sector_size = (_sector_size), \ | 503 | .sector_size = (_sector_size), \ |
507 | .n_sectors = (_n_sectors), \ | 504 | .n_sectors = (_n_sectors), \ |
508 | .page_size = (_page_size), \ | 505 | .page_size = (_page_size), \ |
509 | .addr_width = (_addr_width), \ | 506 | .addr_width = (_addr_width), \ |
510 | .flags = (_flags), \ | 507 | .flags = (_flags), |
511 | }) | ||
512 | 508 | ||
513 | /* NOTE: double check command sets and memory organization when you add | 509 | /* NOTE: double check command sets and memory organization when you add |
514 | * more nor chips. This current list focusses on newer chips, which | 510 | * 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 | * For historical (and compatibility) reasons (before we got above config) some | 517 | * For historical (and compatibility) reasons (before we got above config) some |
522 | * old entries may be missing 4K flag. | 518 | * old entries may be missing 4K flag. |
523 | */ | 519 | */ |
524 | static const struct spi_device_id spi_nor_ids[] = { | 520 | static const struct flash_info spi_nor_ids[] = { |
525 | /* Atmel -- some are (confusingly) marketed as "DataFlash" */ | 521 | /* Atmel -- some are (confusingly) marketed as "DataFlash" */ |
526 | { "at25fs010", INFO(0x1f6601, 0, 32 * 1024, 4, SECT_4K) }, | 522 | { "at25fs010", INFO(0x1f6601, 0, 32 * 1024, 4, SECT_4K) }, |
527 | { "at25fs040", INFO(0x1f6604, 0, 64 * 1024, 8, SECT_4K) }, | 523 | { "at25fs040", INFO(0x1f6604, 0, 64 * 1024, 8, SECT_4K) }, |
@@ -589,7 +585,7 @@ static const struct spi_device_id spi_nor_ids[] = { | |||
589 | 585 | ||
590 | /* Micron */ | 586 | /* Micron */ |
591 | { "n25q032", INFO(0x20ba16, 0, 64 * 1024, 64, SPI_NOR_QUAD_READ) }, | 587 | { "n25q032", INFO(0x20ba16, 0, 64 * 1024, 64, SPI_NOR_QUAD_READ) }, |
592 | { "n25q064", INFO(0x20ba17, 0, 64 * 1024, 128, SPI_NOR_QUAD_READ) }, | 588 | { "n25q064", INFO(0x20ba17, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_QUAD_READ) }, |
593 | { "n25q128a11", INFO(0x20bb18, 0, 64 * 1024, 256, SPI_NOR_QUAD_READ) }, | 589 | { "n25q128a11", INFO(0x20bb18, 0, 64 * 1024, 256, SPI_NOR_QUAD_READ) }, |
594 | { "n25q128a13", INFO(0x20ba18, 0, 64 * 1024, 256, SPI_NOR_QUAD_READ) }, | 590 | { "n25q128a13", INFO(0x20ba18, 0, 64 * 1024, 256, SPI_NOR_QUAD_READ) }, |
595 | { "n25q256a", INFO(0x20ba19, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_QUAD_READ) }, | 591 | { "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 | { "s25fl064k", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) }, | 622 | { "s25fl064k", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) }, |
627 | { "s25fl132k", INFO(0x014016, 0, 64 * 1024, 64, SECT_4K) }, | 623 | { "s25fl132k", INFO(0x014016, 0, 64 * 1024, 64, SECT_4K) }, |
628 | { "s25fl164k", INFO(0x014017, 0, 64 * 1024, 128, SECT_4K) }, | 624 | { "s25fl164k", INFO(0x014017, 0, 64 * 1024, 128, SECT_4K) }, |
625 | { "s25fl204k", INFO(0x014013, 0, 64 * 1024, 8, SECT_4K) }, | ||
629 | 626 | ||
630 | /* SST -- large erase sizes are "overlays", "sectors" are 4K */ | 627 | /* SST -- large erase sizes are "overlays", "sectors" are 4K */ |
631 | { "sst25vf040b", INFO(0xbf258d, 0, 64 * 1024, 8, SECT_4K | SST_WRITE) }, | 628 | { "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 | { }, | 699 | { }, |
703 | }; | 700 | }; |
704 | 701 | ||
705 | static const struct spi_device_id *spi_nor_read_id(struct spi_nor *nor) | 702 | static const struct flash_info *spi_nor_read_id(struct spi_nor *nor) |
706 | { | 703 | { |
707 | int tmp; | 704 | int tmp; |
708 | u8 id[SPI_NOR_MAX_ID_LEN]; | 705 | u8 id[SPI_NOR_MAX_ID_LEN]; |
709 | struct flash_info *info; | 706 | const struct flash_info *info; |
710 | 707 | ||
711 | tmp = nor->read_reg(nor, SPINOR_OP_RDID, id, SPI_NOR_MAX_ID_LEN); | 708 | tmp = nor->read_reg(nor, SPINOR_OP_RDID, id, SPI_NOR_MAX_ID_LEN); |
712 | if (tmp < 0) { | 709 | if (tmp < 0) { |
@@ -715,7 +712,7 @@ static const struct spi_device_id *spi_nor_read_id(struct spi_nor *nor) | |||
715 | } | 712 | } |
716 | 713 | ||
717 | for (tmp = 0; tmp < ARRAY_SIZE(spi_nor_ids) - 1; tmp++) { | 714 | for (tmp = 0; tmp < ARRAY_SIZE(spi_nor_ids) - 1; tmp++) { |
718 | info = (void *)spi_nor_ids[tmp].driver_data; | 715 | info = &spi_nor_ids[tmp]; |
719 | if (info->id_len) { | 716 | if (info->id_len) { |
720 | if (!memcmp(info->id, id, info->id_len)) | 717 | if (!memcmp(info->id, id, info->id_len)) |
721 | return &spi_nor_ids[tmp]; | 718 | return &spi_nor_ids[tmp]; |
@@ -961,7 +958,7 @@ static int micron_quad_enable(struct spi_nor *nor) | |||
961 | return 0; | 958 | return 0; |
962 | } | 959 | } |
963 | 960 | ||
964 | static int set_quad_mode(struct spi_nor *nor, struct flash_info *info) | 961 | static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info) |
965 | { | 962 | { |
966 | int status; | 963 | int status; |
967 | 964 | ||
@@ -1003,8 +1000,7 @@ static int spi_nor_check(struct spi_nor *nor) | |||
1003 | 1000 | ||
1004 | int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode) | 1001 | int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode) |
1005 | { | 1002 | { |
1006 | const struct spi_device_id *id = NULL; | 1003 | const struct flash_info *info = NULL; |
1007 | struct flash_info *info; | ||
1008 | struct device *dev = nor->dev; | 1004 | struct device *dev = nor->dev; |
1009 | struct mtd_info *mtd = nor->mtd; | 1005 | struct mtd_info *mtd = nor->mtd; |
1010 | struct device_node *np = dev->of_node; | 1006 | 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 | if (ret) | 1011 | if (ret) |
1016 | return ret; | 1012 | return ret; |
1017 | 1013 | ||
1018 | /* Try to auto-detect if chip name wasn't specified */ | 1014 | if (name) |
1019 | if (!name) | 1015 | info = spi_nor_match_id(name); |
1020 | id = spi_nor_read_id(nor); | 1016 | /* Try to auto-detect if chip name wasn't specified or not found */ |
1021 | else | 1017 | if (!info) |
1022 | id = spi_nor_match_id(name); | 1018 | info = spi_nor_read_id(nor); |
1023 | if (IS_ERR_OR_NULL(id)) | 1019 | if (IS_ERR_OR_NULL(info)) |
1024 | return -ENOENT; | 1020 | return -ENOENT; |
1025 | 1021 | ||
1026 | info = (void *)id->driver_data; | ||
1027 | |||
1028 | /* | 1022 | /* |
1029 | * If caller has specified name of flash model that can normally be | 1023 | * If caller has specified name of flash model that can normally be |
1030 | * detected using JEDEC, let's verify it. | 1024 | * detected using JEDEC, let's verify it. |
1031 | */ | 1025 | */ |
1032 | if (name && info->id_len) { | 1026 | if (name && info->id_len) { |
1033 | const struct spi_device_id *jid; | 1027 | const struct flash_info *jinfo; |
1034 | 1028 | ||
1035 | jid = spi_nor_read_id(nor); | 1029 | jinfo = spi_nor_read_id(nor); |
1036 | if (IS_ERR(jid)) { | 1030 | if (IS_ERR(jinfo)) { |
1037 | return PTR_ERR(jid); | 1031 | return PTR_ERR(jinfo); |
1038 | } else if (jid != id) { | 1032 | } else if (jinfo != info) { |
1039 | /* | 1033 | /* |
1040 | * JEDEC knows better, so overwrite platform ID. We | 1034 | * JEDEC knows better, so overwrite platform ID. We |
1041 | * can't trust partitions any longer, but we'll let | 1035 | * 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 | * information, even if it's not 100% accurate. | 1038 | * information, even if it's not 100% accurate. |
1045 | */ | 1039 | */ |
1046 | dev_warn(dev, "found %s, expected %s\n", | 1040 | dev_warn(dev, "found %s, expected %s\n", |
1047 | jid->name, id->name); | 1041 | jinfo->name, info->name); |
1048 | id = jid; | 1042 | info = jinfo; |
1049 | info = (void *)jid->driver_data; | ||
1050 | } | 1043 | } |
1051 | } | 1044 | } |
1052 | 1045 | ||
@@ -1196,7 +1189,7 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode) | |||
1196 | 1189 | ||
1197 | nor->read_dummy = spi_nor_read_dummy_cycles(nor); | 1190 | nor->read_dummy = spi_nor_read_dummy_cycles(nor); |
1198 | 1191 | ||
1199 | dev_info(dev, "%s (%lld Kbytes)\n", id->name, | 1192 | dev_info(dev, "%s (%lld Kbytes)\n", info->name, |
1200 | (long long)mtd->size >> 10); | 1193 | (long long)mtd->size >> 10); |
1201 | 1194 | ||
1202 | dev_dbg(dev, | 1195 | dev_dbg(dev, |
@@ -1219,9 +1212,9 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode) | |||
1219 | } | 1212 | } |
1220 | EXPORT_SYMBOL_GPL(spi_nor_scan); | 1213 | EXPORT_SYMBOL_GPL(spi_nor_scan); |
1221 | 1214 | ||
1222 | static const struct spi_device_id *spi_nor_match_id(const char *name) | 1215 | static const struct flash_info *spi_nor_match_id(const char *name) |
1223 | { | 1216 | { |
1224 | const struct spi_device_id *id = spi_nor_ids; | 1217 | const struct flash_info *id = spi_nor_ids; |
1225 | 1218 | ||
1226 | while (id->name[0]) { | 1219 | while (id->name[0]) { |
1227 | if (!strcmp(name, id->name)) | 1220 | if (!strcmp(name, id->name)) |
diff --git a/drivers/mtd/tests/oobtest.c b/drivers/mtd/tests/oobtest.c index 8e8525f0202f..31762120eb56 100644 --- a/drivers/mtd/tests/oobtest.c +++ b/drivers/mtd/tests/oobtest.c | |||
@@ -125,7 +125,8 @@ static int write_whole_device(void) | |||
125 | * Display the address, offset and data bytes at comparison failure. | 125 | * Display the address, offset and data bytes at comparison failure. |
126 | * Return number of bitflips encountered. | 126 | * Return number of bitflips encountered. |
127 | */ | 127 | */ |
128 | static size_t memcmpshow(loff_t addr, const void *cs, const void *ct, size_t count) | 128 | static size_t memcmpshowoffset(loff_t addr, loff_t offset, const void *cs, |
129 | const void *ct, size_t count) | ||
129 | { | 130 | { |
130 | const unsigned char *su1, *su2; | 131 | const unsigned char *su1, *su2; |
131 | int res; | 132 | int res; |
@@ -135,8 +136,9 @@ static size_t memcmpshow(loff_t addr, const void *cs, const void *ct, size_t cou | |||
135 | for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--, i++) { | 136 | for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--, i++) { |
136 | res = *su1 ^ *su2; | 137 | res = *su1 ^ *su2; |
137 | if (res) { | 138 | if (res) { |
138 | pr_info("error @addr[0x%lx:0x%zx] 0x%x -> 0x%x diff 0x%x\n", | 139 | pr_info("error @addr[0x%lx:0x%lx] 0x%x -> 0x%x diff 0x%x\n", |
139 | (unsigned long)addr, i, *su1, *su2, res); | 140 | (unsigned long)addr, (unsigned long)offset + i, |
141 | *su1, *su2, res); | ||
140 | bitflips += hweight8(res); | 142 | bitflips += hweight8(res); |
141 | } | 143 | } |
142 | } | 144 | } |
@@ -144,6 +146,9 @@ static size_t memcmpshow(loff_t addr, const void *cs, const void *ct, size_t cou | |||
144 | return bitflips; | 146 | return bitflips; |
145 | } | 147 | } |
146 | 148 | ||
149 | #define memcmpshow(addr, cs, ct, count) memcmpshowoffset((addr), 0, (cs), (ct),\ | ||
150 | (count)) | ||
151 | |||
147 | /* | 152 | /* |
148 | * Compare with 0xff and show the address, offset and data bytes at | 153 | * Compare with 0xff and show the address, offset and data bytes at |
149 | * comparison failure. Return number of bitflips encountered. | 154 | * comparison failure. Return number of bitflips encountered. |
@@ -228,9 +233,10 @@ static int verify_eraseblock(int ebnum) | |||
228 | errcnt += 1; | 233 | errcnt += 1; |
229 | return err ? err : -1; | 234 | return err ? err : -1; |
230 | } | 235 | } |
231 | bitflips = memcmpshow(addr, readbuf + use_offset, | 236 | bitflips = memcmpshowoffset(addr, use_offset, |
232 | writebuf + (use_len_max * i) + use_offset, | 237 | readbuf + use_offset, |
233 | use_len); | 238 | writebuf + (use_len_max * i) + use_offset, |
239 | use_len); | ||
234 | 240 | ||
235 | /* verify pre-offset area for 0xff */ | 241 | /* verify pre-offset area for 0xff */ |
236 | bitflips += memffshow(addr, 0, readbuf, use_offset); | 242 | bitflips += memffshow(addr, 0, readbuf, use_offset); |