Browse Source

- factor out common code from MTD tests

- nand-gpio cleanup and portability to non-ARM
  - m25p80 support for 4-byte addressing chips, other new chips
  - pxa3xx cleanup and support for new platforms
  - remove obsolete alauda, octagon-5066 drivers
  - erase/write support for bcm47xxsflash
  - improve detection of ECC requirements for NAND, controller setup
  - NFC acceleration support for atmel-nand, read/write via SRAM
  - etc.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.14 (GNU/Linux)
 
 iEYEABECAAYFAlIt3VsACgkQdwG7hYl686NKBQCgqFzV1S+TiXZSjbqanK0374Hu
 lMIAoI2IOQb1bgQFSqaOzgSaBmVhLtMc
 =xWBt
 -----END PGP SIGNATURE-----

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

Pull mtd updates from David Woodhouse:
 - factor out common code from MTD tests
 - nand-gpio cleanup and portability to non-ARM
 - m25p80 support for 4-byte addressing chips, other new chips
 - pxa3xx cleanup and support for new platforms
 - remove obsolete alauda, octagon-5066 drivers
 - erase/write support for bcm47xxsflash
 - improve detection of ECC requirements for NAND, controller setup
 - NFC acceleration support for atmel-nand, read/write via SRAM
 - etc

* tag 'for-linus-20130909' of git://git.infradead.org/linux-mtd: (184 commits)
  mtd: chips: Add support for PMC SPI Flash chips in m25p80.c
  mtd: ofpart: use for_each_child_of_node() macro
  mtd: mtdswap: replace strict_strtoul() with kstrtoul()
  mtd cs553x_nand: use kzalloc() instead of memset
  mtd: atmel_nand: fix error return code in atmel_nand_probe()
  mtd: bcm47xxsflash: writing support
  mtd: bcm47xxsflash: implement erasing support
  mtd: bcm47xxsflash: convert to module_platform_driver instead of init/exit
  mtd: bcm47xxsflash: convert kzalloc to avoid invalid access
  mtd: remove alauda driver
  mtd: nand: mxc_nand: mark 'const' properly
  mtd: maps: cfi_flagadm: add missing __iomem annotation
  mtd: spear_smi: add missing __iomem annotation
  mtd: r852: Staticize local symbols
  mtd: nandsim: Staticize local symbols
  mtd: impa7: add missing __iomem annotation
  mtd: sm_ftl: Staticize local symbols
  mtd: m25p80: add support for mr25h10
  mtd: m25p80: make CONFIG_M25PXX_USE_FAST_READ safe to enable
  mtd: m25p80: Pass flags through CAT25_INFO macro
  ...
master
Linus Torvalds 8 years ago
parent
commit
ef9a61bef9
  1. 17
      Documentation/ABI/testing/sysfs-class-mtd
  2. 2
      Documentation/DocBook/mtdnand.tmpl
  3. 28
      Documentation/devicetree/bindings/mtd/atmel-nand.txt
  4. 25
      Documentation/devicetree/bindings/mtd/fsmc-nand.txt
  5. 1
      Documentation/devicetree/bindings/mtd/partition.txt
  6. 3
      arch/avr32/mach-at32ap/at32ap700x.c
  7. 11
      arch/mips/bcm63xx/nvram.c
  8. 2
      arch/mips/include/asm/mach-bcm63xx/bcm63xx_nvram.h
  9. 9
      drivers/mtd/bcm63xxpart.c
  10. 4
      drivers/mtd/chips/cfi_cmdset_0002.c
  11. 4
      drivers/mtd/chips/gen_probe.c
  12. 13
      drivers/mtd/chips/jedec_probe.c
  13. 55
      drivers/mtd/devices/Kconfig
  14. 275
      drivers/mtd/devices/bcm47xxsflash.c
  15. 2
      drivers/mtd/devices/bcm47xxsflash.h
  16. 58
      drivers/mtd/devices/block2mtd.c
  17. 129
      drivers/mtd/devices/elm.c
  18. 81
      drivers/mtd/devices/m25p80.c
  19. 10
      drivers/mtd/devices/mtd_dataflash.c
  20. 19
      drivers/mtd/devices/spear_smi.c
  21. 8
      drivers/mtd/devices/sst25l.c
  22. 18
      drivers/mtd/maps/Kconfig
  23. 2
      drivers/mtd/maps/Makefile
  24. 2
      drivers/mtd/maps/bfin-async-flash.c
  25. 10
      drivers/mtd/maps/cfi_flagadm.c
  26. 2
      drivers/mtd/maps/gpio-addr-flash.c
  27. 10
      drivers/mtd/maps/impa7.c
  28. 6
      drivers/mtd/maps/ixp4xx.c
  29. 5
      drivers/mtd/maps/latch-addr-flash.c
  30. 246
      drivers/mtd/maps/octagon-5066.c
  31. 7
      drivers/mtd/maps/physmap.c
  32. 6
      drivers/mtd/maps/plat-ram.c
  33. 4
      drivers/mtd/maps/pxa2xx-flash.c
  34. 5
      drivers/mtd/maps/rbtx4939-flash.c
  35. 5
      drivers/mtd/maps/sa1100-flash.c
  36. 196
      drivers/mtd/maps/vmax301.c
  37. 11
      drivers/mtd/mtdcore.c
  38. 1
      drivers/mtd/mtdpart.c
  39. 2
      drivers/mtd/mtdswap.c
  40. 12
      drivers/mtd/nand/Kconfig
  41. 1
      drivers/mtd/nand/Makefile
  42. 723
      drivers/mtd/nand/alauda.c
  43. 1
      drivers/mtd/nand/ams-delta.c
  44. 923
      drivers/mtd/nand/atmel_nand.c
  45. 98
      drivers/mtd/nand/atmel_nand_nfc.h
  46. 2
      drivers/mtd/nand/au1550nd.c
  47. 5
      drivers/mtd/nand/bf5xx_nand.c
  48. 6
      drivers/mtd/nand/cs553x_nand.c
  49. 19
      drivers/mtd/nand/davinci_nand.c
  50. 2
      drivers/mtd/nand/denali.c
  51. 4
      drivers/mtd/nand/diskonchip.c
  52. 8
      drivers/mtd/nand/docg4.c
  53. 3
      drivers/mtd/nand/fsl_ifc_nand.c
  54. 38
      drivers/mtd/nand/fsmc_nand.c
  55. 231
      drivers/mtd/nand/gpio.c
  56. 268
      drivers/mtd/nand/gpmi-nand/gpmi-nand.c
  57. 6
      drivers/mtd/nand/jz4740_nand.c
  58. 4
      drivers/mtd/nand/lpc32xx_mlc.c
  59. 4
      drivers/mtd/nand/lpc32xx_slc.c
  60. 12
      drivers/mtd/nand/mxc_nand.c
  61. 296
      drivers/mtd/nand/nand_base.c
  62. 194
      drivers/mtd/nand/nand_bbt.c
  63. 8
      drivers/mtd/nand/nand_ids.c
  64. 39
      drivers/mtd/nand/nandsim.c
  65. 2
      drivers/mtd/nand/nuc900_nand.c
  66. 5
      drivers/mtd/nand/omap2.c
  67. 6
      drivers/mtd/nand/orion_nand.c
  68. 5
      drivers/mtd/nand/plat_nand.c
  69. 384
      drivers/mtd/nand/pxa3xx_nand.c
  70. 49
      drivers/mtd/nand/r852.c
  71. 4
      drivers/mtd/nand/s3c2410.c
  72. 4
      drivers/mtd/nand/sh_flctl.c
  73. 5
      drivers/mtd/nand/sharpsl.c
  74. 9
      drivers/mtd/nand/sm_common.c
  75. 2
      drivers/mtd/nand/tmio_nand.c
  76. 13
      drivers/mtd/nand/txx9ndfmc.c
  77. 18
      drivers/mtd/ofpart.c
  78. 4
      drivers/mtd/onenand/generic.c
  79. 3
      drivers/mtd/onenand/omap2.c
  80. 1
      drivers/mtd/onenand/onenand_bbt.c
  81. 3
      drivers/mtd/onenand/samsung.c
  82. 26
      drivers/mtd/sm_ftl.c
  83. 9
      drivers/mtd/tests/Makefile
  84. 114
      drivers/mtd/tests/mtd_test.c
  85. 11
      drivers/mtd/tests/mtd_test.h
  86. 41
      drivers/mtd/tests/nandbiterrs.c
  87. 102
      drivers/mtd/tests/oobtest.c
  88. 271
      drivers/mtd/tests/pagetest.c
  89. 61
      drivers/mtd/tests/readtest.c
  90. 210
      drivers/mtd/tests/speedtest.c
  91. 101
      drivers/mtd/tests/stresstest.c
  92. 97
      drivers/mtd/tests/subpagetest.c
  93. 66
      drivers/mtd/tests/torturetest.c
  94. 2
      include/linux/mtd/bbm.h
  95. 1
      include/linux/mtd/fsmc.h
  96. 3
      include/linux/mtd/mtd.h
  97. 83
      include/linux/mtd/nand.h
  98. 4
      include/linux/platform_data/atmel.h
  99. 13
      include/linux/platform_data/mtd-nand-pxa3xx.h

17
Documentation/ABI/testing/sysfs-class-mtd

@ -128,9 +128,8 @@ KernelVersion: 3.4
Contact: linux-mtd@lists.infradead.org
Description:
Maximum number of bit errors that the device is capable of
correcting within each region covering an ecc step. This will
always be a non-negative integer. Note that some devices will
have multiple ecc steps within each writesize region.
correcting within each region covering an ECC step (see
ecc_step_size). This will always be a non-negative integer.
In the case of devices lacking any ECC capability, it is 0.
@ -173,3 +172,15 @@ Description:
This is generally applicable only to NAND flash devices with ECC
capability. It is ignored on devices lacking ECC capability;
i.e., devices for which ecc_strength is zero.
What: /sys/class/mtd/mtdX/ecc_step_size
Date: May 2013
KernelVersion: 3.10
Contact: linux-mtd@lists.infradead.org
Description:
The size of a single region covered by ECC, known as the ECC
step. Devices may have several equally sized ECC steps within
each writesize region.
It will always be a non-negative integer. In the case of
devices lacking any ECC capability, it is 0.

2
Documentation/DocBook/mtdnand.tmpl

@ -1224,8 +1224,6 @@ in this page</entry>
#define NAND_BBT_CREATE 0x00000200
/* Search good / bad pattern through all pages of a block */
#define NAND_BBT_SCANALLPAGES 0x00000400
/* Scan block empty during good / bad block scan */
#define NAND_BBT_SCANEMPTY 0x00000800
/* Write bbt if neccecary */
#define NAND_BBT_WRITE 0x00001000
/* Read and write back block contents when writing bbt */

28
Documentation/devicetree/bindings/mtd/atmel-nand.txt

@ -15,6 +15,7 @@ Required properties:
optional gpio and may be set to 0 if not present.
Optional properties:
- atmel,nand-has-dma : boolean to support dma transfer for nand read/write.
- nand-ecc-mode : String, operation mode of the NAND ecc mode, soft by default.
Supported values are: "none", "soft", "hw", "hw_syndrome", "hw_oob_first",
"soft_bch".
@ -29,6 +30,14 @@ Optional properties:
sector size 1024.
- nand-bus-width : 8 or 16 bus width if not present 8
- nand-on-flash-bbt: boolean to enable on flash bbt option if not present false
- Nand Flash Controller(NFC) is a slave driver under Atmel nand flash
- Required properties:
- compatible : "atmel,sama5d3-nfc".
- reg : should specify the address and size used for NFC command registers,
NFC registers and NFC Sram. NFC Sram address and size can be absent
if don't want to use it.
- Optional properties:
- atmel,write-by-sram: boolean to enable NFC write by sram.
Examples:
nand0: nand@40000000,0 {
@ -77,3 +86,22 @@ nand0: nand@40000000 {
...
};
};
/* for NFC supported chips */
nand0: nand@40000000 {
compatible = "atmel,at91rm9200-nand";
#address-cells = <1>;
#size-cells = <1>;
ranges;
...
nfc@70000000 {
compatible = "atmel,sama5d3-nfc";
#address-cells = <1>;
#size-cells = <1>;
reg = <
0x70000000 0x10000000 /* NFC Command Registers */
0xffffc000 0x00000070 /* NFC HSMC regs */
0x00200000 0x00100000 /* NFC SRAM banks */
>;
};
};

25
Documentation/devicetree/bindings/mtd/fsmc-nand.txt

@ -1,4 +1,5 @@
* FSMC NAND
ST Microelectronics Flexible Static Memory Controller (FSMC)
NAND Interface
Required properties:
- compatible : "st,spear600-fsmc-nand", "stericsson,fsmc-nand"
@ -9,6 +10,26 @@ Optional properties:
- bank-width : Width (in bytes) of the device. If not present, the width
defaults to 1 byte
- nand-skip-bbtscan: Indicates the the BBT scanning should be skipped
- timings: array of 6 bytes for NAND timings. The meanings of these bytes
are:
byte 0 TCLR : CLE to RE delay in number of AHB clock cycles, only 4 bits
are valid. Zero means one clockcycle, 15 means 16 clock
cycles.
byte 1 TAR : ALE to RE delay, 4 bits are valid. Same format as TCLR.
byte 2 THIZ : number of HCLK clock cycles during which the data bus is
kept in Hi-Z (tristate) after the start of a write access.
Only valid for write transactions. Zero means zero cycles,
255 means 255 cycles.
byte 3 THOLD : number of HCLK clock cycles to hold the address (and data
when writing) after the command deassertation. Zero means
one cycle, 255 means 256 cycles.
byte 4 TWAIT : number of HCLK clock cycles to assert the command to the
NAND flash in response to SMWAITn. Zero means 1 cycle,
255 means 256 cycles.
byte 5 TSET : number of HCLK clock cycles to assert the address before the
command is asserted. Zero means one cycle, 255 means 256
cycles.
- bank: default NAND bank to use (0-3 are valid, 0 is the default).
Example:
@ -24,6 +45,8 @@ Example:
bank-width = <1>;
nand-skip-bbtscan;
timings = /bits/ 8 <0 0 0 2 3 0>;
bank = <1>;
partition@0 {
...

1
Documentation/devicetree/bindings/mtd/partition.txt

@ -4,6 +4,7 @@ Partitions can be represented by sub-nodes of an mtd device. This can be used
on platforms which have strong conventions about which portions of a flash are
used for what purposes, but which don't use an on-flash partition table such
as RedBoot.
NOTE: if the sub-node has a compatible string, then it is not a partition.
#address-cells & #size-cells must both be present in the mtd device. There are
two valid values for both:

3
arch/avr32/mach-at32ap/at32ap700x.c

@ -1983,6 +1983,9 @@ at32_add_device_nand(unsigned int id, struct atmel_nand_data *data)
ARRAY_SIZE(smc_cs3_resource)))
goto fail;
/* For at32ap7000, we use the reset workaround for nand driver */
data->need_reset_workaround = true;
if (platform_device_add_data(pdev, data,
sizeof(struct atmel_nand_data)))
goto fail;

11
arch/mips/bcm63xx/nvram.c

@ -35,6 +35,8 @@ struct bcm963xx_nvram {
u32 checksum_high;
};
#define BCM63XX_DEFAULT_PSI_SIZE 64
static struct bcm963xx_nvram nvram;
static int mac_addr_used;
@ -114,3 +116,12 @@ int bcm63xx_nvram_get_mac_address(u8 *mac)
return 0;
}
EXPORT_SYMBOL(bcm63xx_nvram_get_mac_address);
int bcm63xx_nvram_get_psi_size(void)
{
if (nvram.psi_size > 0)
return nvram.psi_size;
return BCM63XX_DEFAULT_PSI_SIZE;
}
EXPORT_SYMBOL(bcm63xx_nvram_get_psi_size);

2
arch/mips/include/asm/mach-bcm63xx/bcm63xx_nvram.h

@ -30,4 +30,6 @@ u8 *bcm63xx_nvram_get_name(void);
*/
int bcm63xx_nvram_get_mac_address(u8 *mac);
int bcm63xx_nvram_get_psi_size(void);
#endif /* BCM63XX_NVRAM_H */

9
drivers/mtd/bcm63xxpart.c

@ -4,7 +4,7 @@
* Copyright © 2006-2008 Florian Fainelli <florian@openwrt.org>
* Mike Albon <malbon@openwrt.org>
* Copyright © 2009-2010 Daniel Dickinson <openwrt@cshore.neomailbox.net>
* Copyright © 2011-2012 Jonas Gorski <jonas.gorski@gmail.com>
* Copyright © 2011-2013 Jonas Gorski <jonas.gorski@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -27,17 +27,19 @@
#include <linux/crc32.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sizes.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <asm/mach-bcm63xx/bcm63xx_nvram.h>
#include <asm/mach-bcm63xx/bcm963xx_tag.h>
#include <asm/mach-bcm63xx/board_bcm963xx.h>
#define BCM63XX_EXTENDED_SIZE 0xBFC00000 /* Extended flash address */
#define BCM63XX_CFE_BLOCK_SIZE 0x10000 /* always at least 64KiB */
#define BCM63XX_CFE_BLOCK_SIZE SZ_64K /* always at least 64KiB */
#define BCM63XX_CFE_MAGIC_OFFSET 0x4e0
@ -90,7 +92,8 @@ static int bcm63xx_parse_cfe_partitions(struct mtd_info *master,
BCM63XX_CFE_BLOCK_SIZE);
cfelen = cfe_erasesize;
nvramlen = cfe_erasesize;
nvramlen = bcm63xx_nvram_get_psi_size() * SZ_1K;
nvramlen = roundup(nvramlen, cfe_erasesize);
/* Allocate memory for buffer */
buf = vmalloc(sizeof(struct bcm_tag));

4
drivers/mtd/chips/cfi_cmdset_0002.c

@ -1571,8 +1571,8 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
xip_enable(map, chip, adr);
/* FIXME - should have reset delay before continuing */
printk(KERN_WARNING "MTD %s(): software timeout\n",
__func__ );
printk(KERN_WARNING "MTD %s(): software timeout, address:0x%.8lx.\n",
__func__, adr);
ret = -EIO;
op_done:

4
drivers/mtd/chips/gen_probe.c

@ -211,9 +211,7 @@ static inline struct mtd_info *cfi_cmdset_unknown(struct map_info *map,
probe_function = __symbol_get(probename);
if (!probe_function) {
char modname[sizeof("cfi_cmdset_%4.4X")];
sprintf(modname, "cfi_cmdset_%4.4X", type);
request_module(modname);
request_module("cfi_cmdset_%4.4X", type);
probe_function = __symbol_get(probename);
}

13
drivers/mtd/chips/jedec_probe.c

@ -120,7 +120,7 @@
#define PM49FL008 0x006A
/* Sharp */
#define LH28F640BF 0x00b0
#define LH28F640BF 0x00B0
/* ST - www.st.com */
#define M29F800AB 0x0058
@ -1299,13 +1299,14 @@ static const struct amd_flash_info jedec_table[] = {
.mfr_id = CFI_MFR_SHARP,
.dev_id = LH28F640BF,
.name = "LH28F640BF",
.devtypes = CFI_DEVICETYPE_X8,
.devtypes = CFI_DEVICETYPE_X16,
.uaddr = MTD_UADDR_UNNECESSARY,
.dev_size = SIZE_4MiB,
.cmd_set = P_ID_INTEL_STD,
.nr_regions = 1,
.dev_size = SIZE_8MiB,
.cmd_set = P_ID_INTEL_EXT,
.nr_regions = 2,
.regions = {
ERASEINFO(0x40000,16),
ERASEINFO(0x10000, 127),
ERASEINFO(0x02000, 8),
}
}, {
.mfr_id = CFI_MFR_SST,

55
drivers/mtd/devices/Kconfig

@ -224,59 +224,4 @@ config BCH_CONST_T
default 4
endif
config MTD_DOCPROBE
tristate
select MTD_DOCECC
config MTD_DOCECC
tristate
config MTD_DOCPROBE_ADVANCED
bool "Advanced detection options for DiskOnChip"
depends on MTD_DOCPROBE
help
This option allows you to specify nonstandard address at which to
probe for a DiskOnChip, or to change the detection options. You
are unlikely to need any of this unless you are using LinuxBIOS.
Say 'N'.
config MTD_DOCPROBE_ADDRESS
hex "Physical address of DiskOnChip" if MTD_DOCPROBE_ADVANCED
depends on MTD_DOCPROBE
default "0x0"
---help---
By default, the probe for DiskOnChip devices will look for a
DiskOnChip at every multiple of 0x2000 between 0xC8000 and 0xEE000.
This option allows you to specify a single address at which to probe
for the device, which is useful if you have other devices in that
range which get upset when they are probed.
(Note that on PowerPC, the normal probe will only check at
0xE4000000.)
Normally, you should leave this set to zero, to allow the probe at
the normal addresses.
config MTD_DOCPROBE_HIGH
bool "Probe high addresses"
depends on MTD_DOCPROBE_ADVANCED
help
By default, the probe for DiskOnChip devices will look for a
DiskOnChip at every multiple of 0x2000 between 0xC8000 and 0xEE000.
This option changes to make it probe between 0xFFFC8000 and
0xFFFEE000. Unless you are using LinuxBIOS, this is unlikely to be
useful to you. Say 'N'.
config MTD_DOCPROBE_55AA
bool "Probe for 0x55 0xAA BIOS Extension Signature"
depends on MTD_DOCPROBE_ADVANCED
help
Check for the 0x55 0xAA signature of a DiskOnChip, and do not
continue with probing if it is absent. The signature will always be
present for a DiskOnChip 2000 or a normal DiskOnChip Millennium.
Only if you have overwritten the first block of a DiskOnChip
Millennium will it be absent. Enable this option if you are using
LinuxBIOS or if you need to recover a DiskOnChip Millennium on which
you have managed to wipe the first block.
endmenu

275
drivers/mtd/devices/bcm47xxsflash.c

@ -1,6 +1,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/mtd/mtd.h>
#include <linux/platform_device.h>
#include <linux/bcma/bcma.h>
@ -12,6 +13,93 @@ MODULE_DESCRIPTION("Serial flash driver for BCMA bus");
static const char * const probes[] = { "bcm47xxpart", NULL };
/**************************************************
* Various helpers
**************************************************/
static void bcm47xxsflash_cmd(struct bcm47xxsflash *b47s, u32 opcode)
{
int i;
b47s->cc_write(b47s, BCMA_CC_FLASHCTL, BCMA_CC_FLASHCTL_START | opcode);
for (i = 0; i < 1000; i++) {
if (!(b47s->cc_read(b47s, BCMA_CC_FLASHCTL) &
BCMA_CC_FLASHCTL_BUSY))
return;
cpu_relax();
}
pr_err("Control command failed (timeout)!\n");
}
static int bcm47xxsflash_poll(struct bcm47xxsflash *b47s, int timeout)
{
unsigned long deadline = jiffies + timeout;
do {
switch (b47s->type) {
case BCM47XXSFLASH_TYPE_ST:
bcm47xxsflash_cmd(b47s, OPCODE_ST_RDSR);
if (!(b47s->cc_read(b47s, BCMA_CC_FLASHDATA) &
SR_ST_WIP))
return 0;
break;
case BCM47XXSFLASH_TYPE_ATMEL:
bcm47xxsflash_cmd(b47s, OPCODE_AT_STATUS);
if (b47s->cc_read(b47s, BCMA_CC_FLASHDATA) &
SR_AT_READY)
return 0;
break;
}
cpu_relax();
udelay(1);
} while (!time_after_eq(jiffies, deadline));
pr_err("Timeout waiting for flash to be ready!\n");
return -EBUSY;
}
/**************************************************
* MTD ops
**************************************************/
static int bcm47xxsflash_erase(struct mtd_info *mtd, struct erase_info *erase)
{
struct bcm47xxsflash *b47s = mtd->priv;
int err;
switch (b47s->type) {
case BCM47XXSFLASH_TYPE_ST:
bcm47xxsflash_cmd(b47s, OPCODE_ST_WREN);
b47s->cc_write(b47s, BCMA_CC_FLASHADDR, erase->addr);
/* Newer flashes have "sub-sectors" which can be erased
* independently with a new command: ST_SSE. The ST_SE command
* erases 64KB just as before.
*/
if (b47s->blocksize < (64 * 1024))
bcm47xxsflash_cmd(b47s, OPCODE_ST_SSE);
else
bcm47xxsflash_cmd(b47s, OPCODE_ST_SE);
break;
case BCM47XXSFLASH_TYPE_ATMEL:
b47s->cc_write(b47s, BCMA_CC_FLASHADDR, erase->addr << 1);
bcm47xxsflash_cmd(b47s, OPCODE_AT_PAGE_ERASE);
break;
}
err = bcm47xxsflash_poll(b47s, HZ);
if (err)
erase->state = MTD_ERASE_FAILED;
else
erase->state = MTD_ERASE_DONE;
if (erase->callback)
erase->callback(erase);
return err;
}
static int bcm47xxsflash_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf)
{
@ -28,6 +116,127 @@ static int bcm47xxsflash_read(struct mtd_info *mtd, loff_t from, size_t len,
return len;
}
static int bcm47xxsflash_write_st(struct mtd_info *mtd, u32 offset, size_t len,
const u_char *buf)
{
struct bcm47xxsflash *b47s = mtd->priv;
int written = 0;
/* Enable writes */
bcm47xxsflash_cmd(b47s, OPCODE_ST_WREN);
/* Write first byte */
b47s->cc_write(b47s, BCMA_CC_FLASHADDR, offset);
b47s->cc_write(b47s, BCMA_CC_FLASHDATA, *buf++);
/* Program page */
if (b47s->bcma_cc->core->id.rev < 20) {
bcm47xxsflash_cmd(b47s, OPCODE_ST_PP);
return 1; /* 1B written */
}
/* Program page and set CSA (on newer chips we can continue writing) */
bcm47xxsflash_cmd(b47s, OPCODE_ST_CSA | OPCODE_ST_PP);
offset++;
len--;
written++;
while (len > 0) {
/* Page boundary, another function call is needed */
if ((offset & 0xFF) == 0)
break;
bcm47xxsflash_cmd(b47s, OPCODE_ST_CSA | *buf++);
offset++;
len--;
written++;
}
/* All done, drop CSA & poll */
b47s->cc_write(b47s, BCMA_CC_FLASHCTL, 0);
udelay(1);
if (bcm47xxsflash_poll(b47s, HZ / 10))
pr_err("Flash rejected dropping CSA\n");
return written;
}
static int bcm47xxsflash_write_at(struct mtd_info *mtd, u32 offset, size_t len,
const u_char *buf)
{
struct bcm47xxsflash *b47s = mtd->priv;
u32 mask = b47s->blocksize - 1;
u32 page = (offset & ~mask) << 1;
u32 byte = offset & mask;
int written = 0;
/* If we don't overwrite whole page, read it to the buffer first */
if (byte || (len < b47s->blocksize)) {
int err;
b47s->cc_write(b47s, BCMA_CC_FLASHADDR, page);
bcm47xxsflash_cmd(b47s, OPCODE_AT_BUF1_LOAD);
/* 250 us for AT45DB321B */
err = bcm47xxsflash_poll(b47s, HZ / 1000);
if (err) {
pr_err("Timeout reading page 0x%X info buffer\n", page);
return err;
}
}
/* Change buffer content with our data */
while (len > 0) {
/* Page boundary, another function call is needed */
if (byte == b47s->blocksize)
break;
b47s->cc_write(b47s, BCMA_CC_FLASHADDR, byte++);
b47s->cc_write(b47s, BCMA_CC_FLASHDATA, *buf++);
bcm47xxsflash_cmd(b47s, OPCODE_AT_BUF1_WRITE);
len--;
written++;
}
/* Program page with the buffer content */
b47s->cc_write(b47s, BCMA_CC_FLASHADDR, page);
bcm47xxsflash_cmd(b47s, OPCODE_AT_BUF1_PROGRAM);
return written;
}
static int bcm47xxsflash_write(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf)
{
struct bcm47xxsflash *b47s = mtd->priv;
int written;
/* Writing functions can return without writing all passed data, for
* example when the hardware is too old or when we git page boundary.
*/
while (len > 0) {
switch (b47s->type) {
case BCM47XXSFLASH_TYPE_ST:
written = bcm47xxsflash_write_st(mtd, to, len, buf);
break;
case BCM47XXSFLASH_TYPE_ATMEL:
written = bcm47xxsflash_write_at(mtd, to, len, buf);
break;
default:
BUG_ON(1);
}
if (written < 0) {
pr_err("Error writing at offset 0x%llX\n", to);
return written;
}
to += (loff_t)written;
len -= written;
*retlen += written;
buf += written;
}
return 0;
}
static void bcm47xxsflash_fill_mtd(struct bcm47xxsflash *b47s)
{
struct mtd_info *mtd = &b47s->mtd;
@ -35,33 +244,48 @@ static void bcm47xxsflash_fill_mtd(struct bcm47xxsflash *b47s)
mtd->priv = b47s;
mtd->name = "bcm47xxsflash";
mtd->owner = THIS_MODULE;
mtd->type = MTD_ROM;
mtd->type = MTD_NORFLASH;
mtd->flags = MTD_CAP_NORFLASH;
mtd->size = b47s->size;
mtd->_read = bcm47xxsflash_read;
mtd->erasesize = b47s->blocksize;
mtd->writesize = 1;
mtd->writebufsize = 1;
/* TODO: implement writing support and verify/change following code */
mtd->flags = MTD_CAP_ROM;
mtd->writebufsize = mtd->writesize = 1;
mtd->_erase = bcm47xxsflash_erase;
mtd->_read = bcm47xxsflash_read;
mtd->_write = bcm47xxsflash_write;
}
/**************************************************
* BCMA
**************************************************/
static int bcm47xxsflash_bcma_cc_read(struct bcm47xxsflash *b47s, u16 offset)
{
return bcma_cc_read32(b47s->bcma_cc, offset);
}
static void bcm47xxsflash_bcma_cc_write(struct bcm47xxsflash *b47s, u16 offset,
u32 value)
{
bcma_cc_write32(b47s->bcma_cc, offset, value);
}
static int bcm47xxsflash_bcma_probe(struct platform_device *pdev)
{
struct bcma_sflash *sflash = dev_get_platdata(&pdev->dev);
struct bcm47xxsflash *b47s;
int err;
b47s = kzalloc(sizeof(*b47s), GFP_KERNEL);
if (!b47s) {
err = -ENOMEM;
goto out;
}
b47s = devm_kzalloc(&pdev->dev, sizeof(*b47s), GFP_KERNEL);
if (!b47s)
return -ENOMEM;
sflash->priv = b47s;
b47s->bcma_cc = container_of(sflash, struct bcma_drv_cc, sflash);
b47s->cc_read = bcm47xxsflash_bcma_cc_read;
b47s->cc_write = bcm47xxsflash_bcma_cc_write;
switch (b47s->bcma_cc->capabilities & BCMA_CC_CAP_FLASHT) {
case BCMA_CC_FLASHT_STSER:
@ -81,15 +305,13 @@ static int bcm47xxsflash_bcma_probe(struct platform_device *pdev)
err = mtd_device_parse_register(&b47s->mtd, probes, NULL, NULL, 0);
if (err) {
pr_err("Failed to register MTD device: %d\n", err);
goto err_dev_reg;
return err;
}
return 0;
if (bcm47xxsflash_poll(b47s, HZ / 10))
pr_warn("Serial flash busy\n");
err_dev_reg:
kfree(&b47s->mtd);
out:
return err;
return 0;
}
static int bcm47xxsflash_bcma_remove(struct platform_device *pdev)
@ -98,7 +320,6 @@ static int bcm47xxsflash_bcma_remove(struct platform_device *pdev)
struct bcm47xxsflash *b47s = sflash->priv;
mtd_device_unregister(&b47s->mtd);
kfree(b47s);
return 0;
}
@ -116,22 +337,4 @@ static struct platform_driver bcma_sflash_driver = {
* Init
**************************************************/
static int __init bcm47xxsflash_init(void)
{
int err;
err = platform_driver_register(&bcma_sflash_driver);
if (err)
pr_err("Failed to register BCMA serial flash driver: %d\n",
err);
return err;
}
static void __exit bcm47xxsflash_exit(void)
{
platform_driver_unregister(&bcma_sflash_driver);
}
module_init(bcm47xxsflash_init);
module_exit(bcm47xxsflash_exit);
module_platform_driver(bcma_sflash_driver);

2
drivers/mtd/devices/bcm47xxsflash.h

@ -60,6 +60,8 @@ enum bcm47xxsflash_type {
struct bcm47xxsflash {
struct bcma_drv_cc *bcma_cc;
int (*cc_read)(struct bcm47xxsflash *b47s, u16 offset);
void (*cc_write)(struct bcm47xxsflash *b47s, u16 offset, u32 value);
enum bcm47xxsflash_type type;

58
drivers/mtd/devices/block2mtd.c

@ -6,6 +6,9 @@
*
* Licence: GPL
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/blkdev.h>
@ -18,10 +21,6 @@
#include <linux/mount.h>
#include <linux/slab.h>
#define ERROR(fmt, args...) printk(KERN_ERR "block2mtd: " fmt "\n" , ## args)
#define INFO(fmt, args...) printk(KERN_INFO "block2mtd: " fmt "\n" , ## args)
/* Info for the block device */
struct block2mtd_dev {
struct list_head list;
@ -84,7 +83,7 @@ static int block2mtd_erase(struct mtd_info *mtd, struct erase_info *instr)
err = _block2mtd_erase(dev, from, len);
mutex_unlock(&dev->write_mutex);
if (err) {
ERROR("erase failed err = %d", err);
pr_err("erase failed err = %d\n", err);
instr->state = MTD_ERASE_FAILED;
} else
instr->state = MTD_ERASE_DONE;
@ -239,13 +238,13 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size)
#endif
if (IS_ERR(bdev)) {
ERROR("error: cannot open device %s", devname);
pr_err("error: cannot open device %s\n", devname);
goto devinit_err;
}
dev->blkdev = bdev;
if (MAJOR(bdev->bd_dev) == MTD_BLOCK_MAJOR) {
ERROR("attempting to use an MTD device as a block device");
pr_err("attempting to use an MTD device as a block device\n");
goto devinit_err;
}
@ -277,9 +276,10 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size)
goto devinit_err;
}
list_add(&dev->list, &blkmtd_device_list);
INFO("mtd%d: [%s] erase_size = %dKiB [%d]", dev->mtd.index,
dev->mtd.name + strlen("block2mtd: "),
dev->mtd.erasesize >> 10, dev->mtd.erasesize);
pr_info("mtd%d: [%s] erase_size = %dKiB [%d]\n",
dev->mtd.index,
dev->mtd.name + strlen("block2mtd: "),
dev->mtd.erasesize >> 10, dev->mtd.erasesize);
return dev;
devinit_err:
@ -339,17 +339,11 @@ static inline void kill_final_newline(char *str)
}
#define parse_err(fmt, args...) do { \
ERROR(fmt, ## args); \
return 0; \
} while (0)
#ifndef MODULE
static int block2mtd_init_called = 0;
static char block2mtd_paramline[80 + 12]; /* 80 for device, 12 for erase size */
#endif
static int block2mtd_setup2(const char *val)
{
char buf[80 + 12]; /* 80 for device, 12 for erase size */
@ -359,8 +353,10 @@ static int block2mtd_setup2(const char *val)
size_t erase_size = PAGE_SIZE;
int i, ret;
if (strnlen(val, sizeof(buf)) >= sizeof(buf))
parse_err("parameter too long");
if (strnlen(val, sizeof(buf)) >= sizeof(buf)) {
pr_err("parameter too long\n");
return 0;
}
strcpy(str, val);
kill_final_newline(str);
@ -368,20 +364,27 @@ static int block2mtd_setup2(const char *val)
for (i = 0; i < 2; i++)
token[i] = strsep(&str, ",");
if (str)
parse_err("too many arguments");
if (str) {
pr_err("too many arguments\n");
return 0;
}
if (!token[0])
parse_err("no argument");
if (!token[0]) {
pr_err("no argument\n");
return 0;
}
name = token[0];
if (strlen(name) + 1 > 80)
parse_err("device name too long");
if (strlen(name) + 1 > 80) {
pr_err("device name too long\n");
return 0;
}
if (token[1]) {
ret = parse_num(&erase_size, token[1]);
if (ret) {
parse_err("illegal erase size");
pr_err("illegal erase size\n");
return 0;
}
}
@ -444,8 +447,9 @@ static void block2mtd_exit(void)
struct block2mtd_dev *dev = list_entry(pos, typeof(*dev), list);
block2mtd_sync(&dev->mtd);
mtd_device_unregister(&dev->mtd);
INFO("mtd%d: [%s] removed", dev->mtd.index,
dev->mtd.name + strlen("block2mtd: "));
pr_info("mtd%d: [%s] removed\n",
dev->mtd.index,
dev->mtd.name + strlen("block2mtd: "));
list_del(&dev->list);
block2mtd_free_device(dev);
}

129
drivers/mtd/devices/elm.c

@ -20,14 +20,21 @@
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/sched.h>
#include <linux/pm_runtime.h>
#include <linux/platform_data/elm.h>
#define ELM_SYSCONFIG 0x010
#define ELM_IRQSTATUS 0x018
#define ELM_IRQENABLE 0x01c
#define ELM_LOCATION_CONFIG 0x020
#define ELM_PAGE_CTRL 0x080
#define ELM_SYNDROME_FRAGMENT_0 0x400
#define ELM_SYNDROME_FRAGMENT_1 0x404
#define ELM_SYNDROME_FRAGMENT_2 0x408
#define ELM_SYNDROME_FRAGMENT_3 0x40c
#define ELM_SYNDROME_FRAGMENT_4 0x410
#define ELM_SYNDROME_FRAGMENT_5 0x414
#define ELM_SYNDROME_FRAGMENT_6 0x418
#define ELM_LOCATION_STATUS 0x800
#define ELM_ERROR_LOCATION_0 0x880
@ -56,12 +63,27 @@
#define SYNDROME_FRAGMENT_REG_SIZE 0x40
#define ERROR_LOCATION_SIZE 0x100
struct elm_registers {
u32 elm_irqenable;
u32 elm_sysconfig;
u32 elm_location_config;
u32 elm_page_ctrl;
u32 elm_syndrome_fragment_6[ERROR_VECTOR_MAX];
u32 elm_syndrome_fragment_5[ERROR_VECTOR_MAX];
u32 elm_syndrome_fragment_4[ERROR_VECTOR_MAX];
u32 elm_syndrome_fragment_3[ERROR_VECTOR_MAX];
u32 elm_syndrome_fragment_2[ERROR_VECTOR_MAX];
u32 elm_syndrome_fragment_1[ERROR_VECTOR_MAX];
u32 elm_syndrome_fragment_0[ERROR_VECTOR_MAX];
};
struct elm_info {
struct device *dev;
void __iomem *elm_base;
struct completion elm_completion;
struct list_head list;
enum bch_ecc bch_type;
struct elm_registers elm_regs;
};
static LIST_HEAD(elm_devices);
@ -346,14 +368,9 @@ static int elm_probe(struct platform_device *pdev)
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "no memory resource defined\n");
return -ENODEV;
}
info->elm_base = devm_request_and_ioremap(&pdev->dev, res);
if (!info->elm_base)
return -EADDRNOTAVAIL;
info->elm_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(info->elm_base))
return PTR_ERR(info->elm_base);
ret = devm_request_irq(&pdev->dev, irq->start, elm_isr, 0,
pdev->name, info);
@ -381,10 +398,103 @@ static int elm_remove(struct platform_device *pdev)
{
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
platform_set_drvdata(pdev, NULL);
return 0;
}
/**
* elm_context_save
* saves ELM configurations to preserve them across Hardware powered-down
*/
static int elm_context_save(struct elm_info *info)
{
struct elm_registers *regs = &info->elm_regs;
enum bch_ecc bch_type = info->bch_type;
u32 offset = 0, i;
regs->elm_irqenable = elm_read_reg(info, ELM_IRQENABLE);
regs->elm_sysconfig = elm_read_reg(info, ELM_SYSCONFIG);
regs->elm_location_config = elm_read_reg(info, ELM_LOCATION_CONFIG);
regs->elm_page_ctrl = elm_read_reg(info, ELM_PAGE_CTRL);
for (i = 0; i < ERROR_VECTOR_MAX; i++) {
offset = i * SYNDROME_FRAGMENT_REG_SIZE;
switch (bch_type) {
case BCH8_ECC:
regs->elm_syndrome_fragment_3[i] = elm_read_reg(info,
ELM_SYNDROME_FRAGMENT_3 + offset);
regs->elm_syndrome_fragment_2[i] = elm_read_reg(info,
ELM_SYNDROME_FRAGMENT_2 + offset);
case BCH4_ECC:
regs->elm_syndrome_fragment_1[i] = elm_read_reg(info,
ELM_SYNDROME_FRAGMENT_1 + offset);
regs->elm_syndrome_fragment_0[i] = elm_read_reg(info,
ELM_SYNDROME_FRAGMENT_0 + offset);
default:
return -EINVAL;
}
/* ELM SYNDROME_VALID bit in SYNDROME_FRAGMENT_6[] needs
* to be saved for all BCH schemes*/
regs->elm_syndrome_fragment_6[i] = elm_read_reg(info,
ELM_SYNDROME_FRAGMENT_6 + offset);
}
return 0;
}
/**
* elm_context_restore
* writes configurations saved duing power-down back into ELM registers
*/
static int elm_context_restore(struct elm_info *info)
{
struct elm_registers *regs = &info->elm_regs;
enum bch_ecc bch_type = info->bch_type;
u32 offset = 0, i;
elm_write_reg(info, ELM_IRQENABLE, regs->elm_irqenable);
elm_write_reg(info, ELM_SYSCONFIG, regs->elm_sysconfig);
elm_write_reg(info, ELM_LOCATION_CONFIG, regs->elm_location_config);
elm_write_reg(info, ELM_PAGE_CTRL, regs->elm_page_ctrl);
for (i = 0; i < ERROR_VECTOR_MAX; i++) {
offset = i * SYNDROME_FRAGMENT_REG_SIZE;
switch (bch_type) {
case BCH8_ECC:
elm_write_reg(info, ELM_SYNDROME_FRAGMENT_3 + offset,
regs->elm_syndrome_fragment_3[i]);
elm_write_reg(info, ELM_SYNDROME_FRAGMENT_2 + offset,
regs->elm_syndrome_fragment_2[i]);
case BCH4_ECC:
elm_write_reg(info, ELM_SYNDROME_FRAGMENT_1 + offset,
regs->elm_syndrome_fragment_1[i]);
elm_write_reg(info, ELM_SYNDROME_FRAGMENT_0 + offset,
regs->elm_syndrome_fragment_0[i]);
default:
return -EINVAL;
}
/* ELM_SYNDROME_VALID bit to be set in last to trigger FSM */
elm_write_reg(info, ELM_SYNDROME_FRAGMENT_6 + offset,
regs->elm_syndrome_fragment_6[i] &
ELM_SYNDROME_VALID);
}
return 0;
}
static int elm_suspend(struct device *dev)
{
struct elm_info *info = dev_get_drvdata(dev);
elm_context_save(info);
pm_runtime_put_sync(dev);
return 0;
}
static int elm_resume(struct device *dev)
{
struct elm_info *info = dev_get_drvdata(dev);
pm_runtime_get_sync(dev);
elm_context_restore(info);
return 0;
}
static SIMPLE_DEV_PM_OPS(elm_pm_ops, elm_suspend, elm_resume);
#ifdef CONFIG_OF
static const struct of_device_id elm_of_match[] = {
{ .compatible = "ti,am3352-elm" },
@ -398,6 +508,7 @@ static struct platform_driver elm_driver = {
.name = "elm",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(elm_of_match),
.pm = &elm_pm_ops,
},
.probe = elm_probe,
.remove = elm_remove,

81
drivers/mtd/devices/m25p80.c

@ -43,17 +43,24 @@
#define OPCODE_FAST_READ 0x0b /* Read data bytes (high frequency) */
#define OPCODE_PP 0x02 /* Page program (up to 256 bytes) */
#define OPCODE_BE_4K 0x20 /* Erase 4KiB block */
#define OPCODE_BE_4K_PMC 0xd7 /* Erase 4KiB block on PMC chips */
#define OPCODE_BE_32K 0x52 /* Erase 32KiB block */
#define OPCODE_CHIP_ERASE 0xc7 /* Erase whole flash chip */
#define OPCODE_SE 0xd8 /* Sector erase (usually 64KiB) */
#define OPCODE_RDID 0x9f /* Read JEDEC ID */
/* 4-byte address opcodes - used on Spansion and some Macronix flashes. */
#define OPCODE_NORM_READ_4B 0x13 /* Read data bytes (low frequency) */
#define OPCODE_FAST_READ_4B 0x0c /* Read data bytes (high frequency) */
#define OPCODE_PP_4B 0x12 /* Page program (up to 256 bytes) */
#define OPCODE_SE_4B 0xdc /* Sector erase (usually 64KiB) */
/* Used for SST flashes only. */
#define OPCODE_BP 0x02 /* Byte program */
#define OPCODE_WRDI 0x04 /* Write disable */
#define OPCODE_AAI_WP 0xad /* Auto address increment word program */
/* Used for Macronix flashes only. */
/* Used for Macronix and Winbond flashes. */
#define OPCODE_EN4B 0xb7 /* Enter 4-byte mode */
#define OPCODE_EX4B 0xe9 /* Exit 4-byte mode */
@ -84,6 +91,8 @@ struct m25p {
u16 page_size;
u16 addr_width;
u8 erase_opcode;
u8 read_opcode;
u8 program_opcode;
u8 *command;
bool fast_read;
};
@ -161,6 +170,7 @@ static inline int set_4byte(struct m25p *flash, u32 jedec_id, int enable)
{
switch (JEDEC_MFR(jedec_id)) {
case CFI_MFR_MACRONIX:
case CFI_MFR_ST: /* Micron, actually */
case 0xEF /* winbond */:
flash->command[0] = enable ? OPCODE_EN4B : OPCODE_EX4B;
return spi_write(flash->spi, flash->command, 1);
@ -371,7 +381,7 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len,
*/
/* Set up the write data buffer. */
opcode = flash->fast_read ? OPCODE_FAST_READ : OPCODE_NORM_READ;
opcode = flash->read_opcode;
flash->command[0] = opcode;
m25p_addr2cmd(flash, from, flash->command);
@ -422,7 +432,7 @@ static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len,
write_enable(flash);
/* Set up the opcode in the write buffer. */
flash->command[0] = OPCODE_PP;
flash->command[0] = flash->program_opcode;
m25p_addr2cmd(flash, to, flash->command);
page_offset = to & (flash->page_size - 1);
@ -682,6 +692,8 @@ struct flash_info {
#define SECT_4K 0x01 /* OPCODE_BE_4K works uniformly */
#define M25P_NO_ERASE 0x02 /* No erase command needed */
#define SST_WRITE 0x04 /* use SST byte programming */
#define M25P_NO_FR 0x08 /* Can't do fastread */
#define SECT_4K_PMC 0x10 /* OPCODE_BE_4K_PMC works uniformly */
};
#define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \
@ -694,13 +706,13 @@ struct flash_info {
.flags = (_flags), \
})
#define CAT25_INFO(_sector_size, _n_sectors, _page_size, _addr_width) \
#define CAT25_INFO(_sector_size, _n_sectors, _page_size, _addr_width, _flags) \
((kernel_ulong_t)&(struct flash_info) { \
.sector_size = (_sector_size), \
.n_sectors = (_n_sectors), \
.page_size = (_page_size), \
.addr_width = (_addr_width), \
.flags = M25P_NO_ERASE, \
.flags = (_flags), \
})
/* NOTE: double check command sets and memory organization when you add
@ -732,7 +744,8 @@ static const struct spi_device_id m25p_ids[] = {
{ "en25qh256", INFO(0x1c7019, 0, 64 * 1024, 512, 0) },
/* Everspin */
{ "mr25h256", CAT25_INFO( 32 * 1024, 1, 256, 2) },
{ "mr25h256", CAT25_INFO( 32 * 1024, 1, 256, 2, M25P_NO_ERASE | M25P_NO_FR) },
{ "mr25h10", CAT25_INFO(128 * 1024, 1, 256, 3, M25P_NO_ERASE | M25P_NO_FR) },
/* GigaDevice */
{ "gd25q32", INFO(0xc84016, 0, 64 * 1024, 64, SECT_4K) },
@ -762,6 +775,11 @@ static const struct spi_device_id m25p_ids[] = {
{ "n25q128a13", INFO(0x20ba18, 0, 64 * 1024, 256, 0) },
{ "n25q256a", INFO(0x20ba19, 0, 64 * 1024, 512, SECT_4K) },
/* PMC */
{ "pm25lv512", INFO(0, 0, 32 * 1024, 2, SECT_4K_PMC) },
{ "pm25lv010", INFO(0, 0, 32 * 1024, 4, SECT_4K_PMC) },
{ "pm25lq032", INFO(0x7f9d46, 0, 64 * 1024, 64, SECT_4K) },
/* Spansion -- single (large) sector size only, at least
* for the chips listed here (without boot sectors).
*/
@ -840,17 +858,18 @@ static const struct spi_device_id m25p_ids[] = {
{ "w25q32dw", INFO(0xef6016, 0, 64 * 1024, 64, SECT_4K) },
{ "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) },
{ "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) },
{ "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) },
{ "w25q80", INFO(0xef5014, 0, 64 * 1024, 16, SECT_4K) },
{ "w25q80bl", INFO(0xef4014, 0, 64 * 1024, 16, SECT_4K) },
{ "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) },
{ "w25q256", INFO(0xef4019, 0, 64 * 1024, 512, SECT_4K) },
/* Catalyst / On Semiconductor -- non-JEDEC */
{ "cat25c11", CAT25_INFO( 16, 8, 16, 1) },
{ "cat25c03", CAT25_INFO( 32, 8, 16, 2) },
{ "cat25c09", CAT25_INFO( 128, 8, 32, 2) },
{ "cat25c17", CAT25_INFO( 256, 8, 32, 2) },
{ "cat25128", CAT25_INFO(2048, 8, 64, 2) },
{ "cat25c11", CAT25_INFO( 16, 8, 16, 1, M25P_NO_ERASE | M25P_NO_FR) },
{ "cat25c03", CAT25_INFO( 32, 8, 16, 2, M25P_NO_ERASE | M25P_NO_FR) },
{ "cat25c09", CAT25_INFO( 128, 8, 32, 2, M25P_NO_ERASE | M25P_NO_FR) },
{ "cat25c17", CAT25_INFO( 256, 8, 32, 2, M25P_NO_ERASE | M25P_NO_FR) },
{ "cat25128", CAT25_INFO(2048, 8, 64, 2, M25P_NO_ERASE | M25P_NO_FR) },
{ },
};
MODULE_DEVICE_TABLE(spi, m25p_ids);
@ -920,7 +939,7 @@ static int m25p_probe(struct spi_device *spi)
* a chip ID, try the JEDEC id commands; they'll work for most
* newer chips, even if we don't recognize the particular chip.
*/
data = spi->dev.platform_data;
data = dev_get_platdata(&spi->dev);
if (data && data->type) {
const struct spi_device_id *plat_id;
@ -972,7 +991,7 @@ static int m25p_probe(struct spi_device *spi)
flash->spi = spi;
mutex_init(&flash->lock);
dev_set_drvdata(&spi->dev, flash);
spi_set_drvdata(spi, flash);
/*
* Atmel, SST and Intel/Numonyx serial flash tend to power
@ -1014,6 +1033,9 @@ static int m25p_probe(struct spi_device *spi)
if (info->flags & SECT_4K) {
flash->erase_opcode = OPCODE_BE_4K;
flash->mtd.erasesize = 4096;
} else if (info->flags & SECT_4K_PMC) {
flash->erase_opcode = OPCODE_BE_4K_PMC;
flash->mtd.erasesize = 4096;
} else {
flash->erase_opcode = OPCODE_SE;
flash->mtd.erasesize = info->sector_size;
@ -1028,24 +1050,41 @@ static int m25p_probe(struct spi_device *spi)
flash->mtd.writebufsize = flash->page_size;
flash->fast_read = false;
#ifdef CONFIG_OF
if (np && of_property_read_bool(np, "m25p,fast-read"))
flash->fast_read = true;
#endif
#ifdef CONFIG_M25PXX_USE_FAST_READ
flash->fast_read = true;
#endif
if (info->flags & M25P_NO_FR)
flash->fast_read = false;
/* Default commands */
if (flash->fast_read)
flash->read_opcode = OPCODE_FAST_READ;
else
flash->read_opcode = OPCODE_NORM_READ;
flash->program_opcode = OPCODE_PP;
if (info->addr_width)
flash->addr_width = info->addr_width;
else {
else if (flash->mtd.size > 0x1000000) {
/* enable 4-byte addressing if the device exceeds 16MiB */
if (flash->mtd.size > 0x1000000) {
flash->addr_width = 4;
set_4byte(flash, info->jedec_id, 1);
flash->addr_width = 4;
if (JEDEC_MFR(info->jedec_id) == CFI_MFR_AMD) {
/* Dedicated 4-byte command set */
flash->read_opcode = flash->fast_read ?
OPCODE_FAST_READ_4B :
OPCODE_NORM_READ_4B;
flash->program_opcode = OPCODE_PP_4B;
/* No small sector erase for 4-byte command set */
flash->erase_opcode = OPCODE_SE_4B;
flash->mtd.erasesize = info->sector_size;
} else
flash->addr_width = 3;
set_4byte(flash, info->jedec_id, 1);
} else {
flash->addr_width = 3;
}
dev_info(&spi->dev, "%s (%lld Kbytes)\n", id->name,
@ -1080,7 +1119,7 @@ static int m25p_probe(struct spi_device *spi)
static int m25p_remove(struct spi_device *spi)
{
struct m25p *flash = dev_get_drvdata(&spi->dev);
struct m25p *flash = spi_get_drvdata(spi);
int status;
/* Clean up MTD stuff. */

10
drivers/mtd/devices/mtd_dataflash.c

@ -622,7 +622,7 @@ static int add_dataflash_otp(struct spi_device *spi, char *name, int nr_pages,
struct dataflash *priv;
struct mtd_info *device;
struct mtd_part_parser_data ppdata;
struct flash_platform_data *pdata = spi->dev.platform_data;
struct flash_platform_data *pdata = dev_get_platdata(&spi->dev);
char *otp_tag = "";
int err = 0;
@ -661,7 +661,7 @@ static int add_dataflash_otp(struct spi_device *spi, char *name, int nr_pages,
dev_info(&spi->dev, "%s (%lld KBytes) pagesize %d bytes%s\n",
name, (long long)((device->size + 1023) >> 10),
pagesize, otp_tag);
dev_set_drvdata(&spi->dev, priv);
spi_set_drvdata(spi, priv);
ppdata.of_node = spi->dev.of_node;
err = mtd_device_parse_register(device, NULL, &ppdata,
@ -671,7 +671,7 @@ static int add_dataflash_otp(struct spi_device *spi, char *name, int nr_pages,
if (!err)
return 0;
dev_set_drvdata(&spi->dev, NULL);
spi_set_drvdata(spi, NULL);
kfree(priv);
return err;
}
@ -895,14 +895,14 @@ static int dataflash_probe(struct spi_device *spi)
static int dataflash_remove(struct spi_device *spi)
{
struct dataflash *flash = dev_get_drvdata(&spi->dev);
struct dataflash *flash = spi_get_drvdata(spi);
int status;
pr_debug("%s: remove\n", dev_name(&spi->dev));
status = mtd_device_unregister(&flash->mtd);
if (status == 0) {
dev_set_drvdata(&spi->dev, NULL);
spi_set_drvdata(spi, NULL);
kfree(flash);
}
return status;

19
drivers/mtd/devices/spear_smi.c

@ -550,7 +550,7 @@ static int spear_mtd_read(struct mtd_info *mtd, loff_t from, size_t len,
{
struct spear_snor_flash *flash = get_flash_data(mtd);
struct spear_smi *dev = mtd->priv;
void *src;
void __iomem *src;
u32 ctrlreg1, val;
int ret;
@ -583,7 +583,7 @@ static int spear_mtd_read(struct mtd_info *mtd, loff_t from, size_t len,
writel(val, dev->io_base + SMI_CR1);
memcpy_fromio(buf, (u8 *)src, len);
memcpy_fromio(buf, src, len);
/* restore ctrl reg1 */
writel(ctrlreg1, dev->io_base + SMI_CR1);
@ -596,7 +596,7 @@ static int spear_mtd_read(struct mtd_info *mtd, loff_t from, size_t len,
}
static inline int spear_smi_cpy_toio(struct spear_smi *dev, u32 bank,
void *dest, const void *src, size_t len)
void __iomem *dest, const void *src, size_t len)
{
int ret;
u32 ctrlreg1;
@ -643,7 +643,7 @@ static int spear_mtd_write(struct mtd_info *mtd, loff_t to, size_t len,
{
struct spear_snor_flash *flash = get_flash_data(mtd);
struct spear_smi *dev = mtd->priv;
void *dest;
void __iomem *dest;
u32 page_offset, page_size;
int ret;
@ -995,14 +995,12 @@ static int spear_smi_probe(struct platform_device *pdev)
ret = spear_smi_setup_banks(pdev, i, pdata->np[i]);
if (ret) {
dev_err(&dev->pdev->dev, "bank setup failed\n");
goto err_bank_setup;
goto err_irq;
}
}
return 0;
err_bank_setup:
platform_set_drvdata(pdev, NULL);
err_irq:
clk_disable_unprepare(dev->clk);
err:
@ -1040,12 +1038,11 @@ static int spear_smi_remove(struct platform_device *pdev)
}