Commit 402521b8 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull MTD updates from Brian Norris:
 "NAND:

   - Add new Hisilicon NAND driver for Hip04
   - Add default reboot handler, to ensure all outstanding erase
     transactions complete in time
   - jz4740: convert to use GPIO descriptor API
   - Atmel: add support for sama5d4
   - Change default bitflip threshold to 75% of correction strength
   - Miscellaneous cleanups and bugfixes

  SPI NOR:

   - Freescale QuadSPI:
   - Fix a few probe() and remove() issues
   - Add a MAINTAINERS entry for this driver
   - Tweak transfer size to increase read performance
   - Add suspend/resume support
   - Add Micron quad I/O support
   - ST FSM SPI: miscellaneous fixes

  JFFS2:

   - gracefully handle corrupted 'offset' field found on flash

  Other:

   - bcm47xxpart: add tweaks for a few new devices
   - mtdconcat: set return lengths properly for mtd_write_oob()
   - map_ram: enable use with mtdoops
   - maps: support fallback to ROM/UBI for write-protected NOR flash"

* tag 'for-linus-20150216' of git://git.infradead.org/linux-mtd: (46 commits)
  mtd: hisilicon: && vs & typo
  jffs2: fix handling of corrupted summary length
  mtd: hisilicon: add device tree binding documentation
  mtd: hisilicon: add a new NAND controller driver for hisilicon hip04 Soc
  mtd: avoid registering reboot notifier twice
  mtd: concat: set the return lengths properly
  mtd: kconfig: replace PPC_OF with PPC
  mtd: denali: remove unnecessary stubs
  mtd: nand: remove redundant local variable
  MAINTAINERS: add maintainer entry for FREESCALE QUAD SPI driver
  mtd: fsl-quadspi: improve read performance by increase AHB transfer size
  mtd: fsl-quadspi: Remove unnecessary 'map_failed' label
  mtd: fsl-quadspi: Remove unneeded success/error messages
  mtd: fsl-quadspi: Fix the error paths
  mtd: nand: omap: drop condition with no effect
  mtd: nand: jz4740: Convert to GPIO descriptor API
  mtd: nand: Request strength instead of bytes for soft BCH
  mtd: nand: default bitflip-reporting threshold to 75% of correction strength
  mtd: atmel_nand: introduce a new compatible string for sama5d4 chip
  mtd: atmel_nand: return max bitflips in all sectors in pmecc_correction()
  ...
parents f5af19d1 eb928d40
Atmel NAND flash Atmel NAND flash
Required properties: Required properties:
- compatible : "atmel,at91rm9200-nand". - compatible : should be "atmel,at91rm9200-nand" or "atmel,sama5d4-nand".
- reg : should specify localbus address and size used for the chip, - reg : should specify localbus address and size used for the chip,
and hardware ECC controller if available. and hardware ECC controller if available.
If the hardware ECC is PMECC, it should contain address and size for If the hardware ECC is PMECC, it should contain address and size for
......
* Freescale Quad Serial Peripheral Interface(QuadSPI) * Freescale Quad Serial Peripheral Interface(QuadSPI)
Required properties: Required properties:
- compatible : Should be "fsl,vf610-qspi" - compatible : Should be "fsl,vf610-qspi" or "fsl,imx6sx-qspi"
- reg : the first contains the register location and length, - reg : the first contains the register location and length,
the second contains the memory mapping address and length the second contains the memory mapping address and length
- reg-names: Should contain the reg names "QuadSPI" and "QuadSPI-memory" - reg-names: Should contain the reg names "QuadSPI" and "QuadSPI-memory"
......
* Freescale General-Purpose Media Interface (GPMI) * Freescale General-Purpose Media Interface (GPMI)
The GPMI nand controller provides an interface to control the The GPMI nand controller provides an interface to control the
NAND flash chips. We support only one NAND chip now. NAND flash chips.
Required properties: Required properties:
- compatible : should be "fsl,<chip>-gpmi-nand" - compatible : should be "fsl,<chip>-gpmi-nand"
......
Hisilicon Hip04 Soc NAND controller DT binding
Required properties:
- compatible: Should be "hisilicon,504-nfc".
- reg: The first contains base physical address and size of
NAND controller's registers. The second contains base
physical address and size of NAND controller's buffer.
- interrupts: Interrupt number for nfc.
- nand-bus-width: See nand.txt.
- nand-ecc-mode: Support none and hw ecc mode.
- #address-cells: Partition address, should be set 1.
- #size-cells: Partition size, should be set 1.
Optional properties:
- nand-ecc-strength: Number of bits to correct per ECC step.
- nand-ecc-step-size: Number of data bytes covered by a single ECC step.
The following ECC strength and step size are currently supported:
- nand-ecc-strength = <16>, nand-ecc-step-size = <1024>
Flash chip may optionally contain additional sub-nodes describing partitions of
the address space. See partition.txt for more detail.
Example:
nand: nand@4020000 {
compatible = "hisilicon,504-nfc";
reg = <0x4020000 0x10000>, <0x5000000 0x1000>;
interrupts = <0 379 4>;
nand-bus-width = <8>;
nand-ecc-mode = "hw";
nand-ecc-strength = <16>;
nand-ecc-step-size = <1024>;
#address-cells = <1>;
#size-cells = <1>;
partition@0 {
label = "nand_text";
reg = <0x00000000 0x00400000>;
};
...
};
...@@ -36,6 +36,11 @@ are defined: ...@@ -36,6 +36,11 @@ are defined:
- vendor-id : Contains the flash chip's vendor id (1 byte). - vendor-id : Contains the flash chip's vendor id (1 byte).
- device-id : Contains the flash chip's device id (1 byte). - device-id : Contains the flash chip's device id (1 byte).
For ROM compatible devices (and ROM fallback from cfi-flash), the following
additional (optional) property is defined:
- erase-size : The chip's physical erase block size in bytes.
The device tree may optionally contain sub-nodes describing partitions of the The device tree may optionally contain sub-nodes describing partitions of the
address space. See partition.txt for more detail. address space. See partition.txt for more detail.
......
...@@ -4092,6 +4092,12 @@ S: Maintained ...@@ -4092,6 +4092,12 @@ S: Maintained
F: include/linux/platform_data/video-imxfb.h F: include/linux/platform_data/video-imxfb.h
F: drivers/video/fbdev/imxfb.c F: drivers/video/fbdev/imxfb.c
FREESCALE QUAD SPI DRIVER
M: Han Xu <han.xu@freescale.com>
L: linux-mtd@lists.infradead.org
S: Maintained
F: drivers/mtd/spi-nor/fsl-quadspi.c
FREESCALE SOC FS_ENET DRIVER FREESCALE SOC FS_ENET DRIVER
M: Pantelis Antoniou <pantelis.antoniou@gmail.com> M: Pantelis Antoniou <pantelis.antoniou@gmail.com>
M: Vitaly Bordug <vbordug@ru.mvista.com> M: Vitaly Bordug <vbordug@ru.mvista.com>
......
...@@ -27,8 +27,6 @@ struct jz_nand_platform_data { ...@@ -27,8 +27,6 @@ struct jz_nand_platform_data {
struct nand_ecclayout *ecc_layout; struct nand_ecclayout *ecc_layout;
unsigned int busy_gpio;
unsigned char banks[JZ_NAND_NUM_BANKS]; unsigned char banks[JZ_NAND_NUM_BANKS];
void (*ident_callback)(struct platform_device *, struct nand_chip *, void (*ident_callback)(struct platform_device *, struct nand_chip *,
......
...@@ -140,10 +140,18 @@ static void qi_lb60_nand_ident(struct platform_device *pdev, ...@@ -140,10 +140,18 @@ static void qi_lb60_nand_ident(struct platform_device *pdev,
static struct jz_nand_platform_data qi_lb60_nand_pdata = { static struct jz_nand_platform_data qi_lb60_nand_pdata = {
.ident_callback = qi_lb60_nand_ident, .ident_callback = qi_lb60_nand_ident,
.busy_gpio = 94,
.banks = { 1 }, .banks = { 1 },
}; };
static struct gpiod_lookup_table qi_lb60_nand_gpio_table = {
.dev_id = "jz4740-nand.0",
.table = {
GPIO_LOOKUP("Bank C", 30, "busy", 0),
{ },
},
};
/* Keyboard*/ /* Keyboard*/
#define KEY_QI_QI KEY_F13 #define KEY_QI_QI KEY_F13
...@@ -472,6 +480,7 @@ static int __init qi_lb60_init_platform_devices(void) ...@@ -472,6 +480,7 @@ static int __init qi_lb60_init_platform_devices(void)
jz4740_mmc_device.dev.platform_data = &qi_lb60_mmc_pdata; jz4740_mmc_device.dev.platform_data = &qi_lb60_mmc_pdata;
gpiod_add_lookup_table(&qi_lb60_audio_gpio_table); gpiod_add_lookup_table(&qi_lb60_audio_gpio_table);
gpiod_add_lookup_table(&qi_lb60_nand_gpio_table);
jz4740_serial_device_register(); jz4740_serial_device_register();
......
...@@ -15,6 +15,8 @@ ...@@ -15,6 +15,8 @@
#include <linux/mtd/mtd.h> #include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h> #include <linux/mtd/partitions.h>
#include <uapi/linux/magic.h>
/* /*
* NAND flash on Netgear R6250 was verified to contain 15 partitions. * NAND flash on Netgear R6250 was verified to contain 15 partitions.
* This will result in allocating too big array for some old devices, but the * This will result in allocating too big array for some old devices, but the
...@@ -39,7 +41,8 @@ ...@@ -39,7 +41,8 @@
#define ML_MAGIC1 0x39685a42 #define ML_MAGIC1 0x39685a42
#define ML_MAGIC2 0x26594131 #define ML_MAGIC2 0x26594131
#define TRX_MAGIC 0x30524448 #define TRX_MAGIC 0x30524448
#define SQSH_MAGIC 0x71736873 /* shsq */ #define SHSQ_MAGIC 0x71736873 /* shsq (weird ZTE H218N endianness) */
#define UBI_EC_MAGIC 0x23494255 /* UBI# */
struct trx_header { struct trx_header {
uint32_t magic; uint32_t magic;
...@@ -50,7 +53,7 @@ struct trx_header { ...@@ -50,7 +53,7 @@ struct trx_header {
uint32_t offset[3]; uint32_t offset[3];
} __packed; } __packed;
static void bcm47xxpart_add_part(struct mtd_partition *part, char *name, static void bcm47xxpart_add_part(struct mtd_partition *part, const char *name,
u64 offset, uint32_t mask_flags) u64 offset, uint32_t mask_flags)
{ {
part->name = name; part->name = name;
...@@ -58,6 +61,26 @@ static void bcm47xxpart_add_part(struct mtd_partition *part, char *name, ...@@ -58,6 +61,26 @@ static void bcm47xxpart_add_part(struct mtd_partition *part, char *name,
part->mask_flags = mask_flags; part->mask_flags = mask_flags;
} }
static const char *bcm47xxpart_trx_data_part_name(struct mtd_info *master,
size_t offset)
{
uint32_t buf;
size_t bytes_read;
if (mtd_read(master, offset, sizeof(buf), &bytes_read,
(uint8_t *)&buf) < 0) {
pr_err("mtd_read error while parsing (offset: 0x%X)!\n",
offset);
goto out_default;
}
if (buf == UBI_EC_MAGIC)
return "ubi";
out_default:
return "rootfs";
}
static int bcm47xxpart_parse(struct mtd_info *master, static int bcm47xxpart_parse(struct mtd_info *master,
struct mtd_partition **pparts, struct mtd_partition **pparts,
struct mtd_part_parser_data *data) struct mtd_part_parser_data *data)
...@@ -73,8 +96,12 @@ static int bcm47xxpart_parse(struct mtd_info *master, ...@@ -73,8 +96,12 @@ static int bcm47xxpart_parse(struct mtd_info *master,
int last_trx_part = -1; int last_trx_part = -1;
int possible_nvram_sizes[] = { 0x8000, 0xF000, 0x10000, }; int possible_nvram_sizes[] = { 0x8000, 0xF000, 0x10000, };
if (blocksize <= 0x10000) /*
blocksize = 0x10000; * Some really old flashes (like AT45DB*) had smaller erasesize-s, but
* partitions were aligned to at least 0x1000 anyway.
*/
if (blocksize < 0x1000)
blocksize = 0x1000;
/* Alloc */ /* Alloc */
parts = kzalloc(sizeof(struct mtd_partition) * BCM47XXPART_MAX_PARTS, parts = kzalloc(sizeof(struct mtd_partition) * BCM47XXPART_MAX_PARTS,
...@@ -186,8 +213,11 @@ static int bcm47xxpart_parse(struct mtd_info *master, ...@@ -186,8 +213,11 @@ static int bcm47xxpart_parse(struct mtd_info *master,
* we want to have jffs2 (overlay) in the same mtd. * we want to have jffs2 (overlay) in the same mtd.
*/ */
if (trx->offset[i]) { if (trx->offset[i]) {
const char *name;
name = bcm47xxpart_trx_data_part_name(master, offset + trx->offset[i]);
bcm47xxpart_add_part(&parts[curr_part++], bcm47xxpart_add_part(&parts[curr_part++],
"rootfs", name,
offset + trx->offset[i], offset + trx->offset[i],
0); 0);
i++; i++;
...@@ -205,7 +235,8 @@ static int bcm47xxpart_parse(struct mtd_info *master, ...@@ -205,7 +235,8 @@ static int bcm47xxpart_parse(struct mtd_info *master,
} }
/* Squashfs on devices not using TRX */ /* Squashfs on devices not using TRX */
if (buf[0x000 / 4] == SQSH_MAGIC) { if (le32_to_cpu(buf[0x000 / 4]) == SQUASHFS_MAGIC ||
buf[0x000 / 4] == SHSQ_MAGIC) {
bcm47xxpart_add_part(&parts[curr_part++], "rootfs", bcm47xxpart_add_part(&parts[curr_part++], "rootfs",
offset, 0); offset, 0);
continue; continue;
......
...@@ -68,6 +68,7 @@ static struct mtd_info *map_ram_probe(struct map_info *map) ...@@ -68,6 +68,7 @@ static struct mtd_info *map_ram_probe(struct map_info *map)
mtd->_get_unmapped_area = mapram_unmapped_area; mtd->_get_unmapped_area = mapram_unmapped_area;
mtd->_read = mapram_read; mtd->_read = mapram_read;
mtd->_write = mapram_write; mtd->_write = mapram_write;
mtd->_panic_write = mapram_write;
mtd->_sync = mapram_nop; mtd->_sync = mapram_nop;
mtd->flags = MTD_CAP_RAM; mtd->flags = MTD_CAP_RAM;
mtd->writesize = 1; mtd->writesize = 1;
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/of.h>
#include <linux/mtd/mtd.h> #include <linux/mtd/mtd.h>
#include <linux/mtd/map.h> #include <linux/mtd/map.h>
...@@ -28,6 +29,15 @@ static struct mtd_chip_driver maprom_chipdrv = { ...@@ -28,6 +29,15 @@ static struct mtd_chip_driver maprom_chipdrv = {
.module = THIS_MODULE .module = THIS_MODULE
}; };
static unsigned int default_erasesize(struct map_info *map)
{
const __be32 *erase_size = NULL;
erase_size = of_get_property(map->device_node, "erase-size", NULL);
return !erase_size ? map->size : be32_to_cpu(*erase_size);
}
static struct mtd_info *map_rom_probe(struct map_info *map) static struct mtd_info *map_rom_probe(struct map_info *map)
{ {
struct mtd_info *mtd; struct mtd_info *mtd;
...@@ -47,8 +57,9 @@ static struct mtd_info *map_rom_probe(struct map_info *map) ...@@ -47,8 +57,9 @@ static struct mtd_info *map_rom_probe(struct map_info *map)
mtd->_sync = maprom_nop; mtd->_sync = maprom_nop;
mtd->_erase = maprom_erase; mtd->_erase = maprom_erase;
mtd->flags = MTD_CAP_ROM; mtd->flags = MTD_CAP_ROM;
mtd->erasesize = map->size; mtd->erasesize = default_erasesize(map);
mtd->writesize = 1; mtd->writesize = 1;
mtd->writebufsize = 1;
__module_get(THIS_MODULE); __module_get(THIS_MODULE);
return mtd; return mtd;
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/clk.h>
#include "serial_flash_cmds.h" #include "serial_flash_cmds.h"
...@@ -262,6 +263,7 @@ struct stfsm { ...@@ -262,6 +263,7 @@ struct stfsm {
struct mtd_info mtd; struct mtd_info mtd;
struct mutex lock; struct mutex lock;
struct flash_info *info; struct flash_info *info;
struct clk *clk;
uint32_t configuration; uint32_t configuration;
uint32_t fifo_dir_delay; uint32_t fifo_dir_delay;
...@@ -663,6 +665,23 @@ static struct stfsm_seq stfsm_seq_write_status = { ...@@ -663,6 +665,23 @@ static struct stfsm_seq stfsm_seq_write_status = {
SEQ_CFG_STARTSEQ), SEQ_CFG_STARTSEQ),
}; };
/* Dummy sequence to read one byte of data from flash into the FIFO */
static const struct stfsm_seq stfsm_seq_load_fifo_byte = {
.data_size = TRANSFER_SIZE(1),
.seq_opc[0] = (SEQ_OPC_PADS_1 |
SEQ_OPC_CYCLES(8) |
SEQ_OPC_OPCODE(SPINOR_OP_RDID)),
.seq = {
STFSM_INST_CMD1,
STFSM_INST_DATA_READ,
STFSM_INST_STOP,
},
.seq_cfg = (SEQ_CFG_PADS_1 |
SEQ_CFG_READNOTWRITE |
SEQ_CFG_CSDEASSERT |
SEQ_CFG_STARTSEQ),
};
static int stfsm_n25q_en_32bit_addr_seq(struct stfsm_seq *seq) static int stfsm_n25q_en_32bit_addr_seq(struct stfsm_seq *seq)
{ {
seq->seq_opc[0] = (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) | seq->seq_opc[0] = (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) |
...@@ -695,22 +714,6 @@ static inline uint32_t stfsm_fifo_available(struct stfsm *fsm) ...@@ -695,22 +714,6 @@ static inline uint32_t stfsm_fifo_available(struct stfsm *fsm)
return (readl(fsm->base + SPI_FAST_SEQ_STA) >> 5) & 0x7f; return (readl(fsm->base + SPI_FAST_SEQ_STA) >> 5) & 0x7f;
} }
static void stfsm_clear_fifo(struct stfsm *fsm)
{
uint32_t avail;
for (;;) {
avail = stfsm_fifo_available(fsm);
if (!avail)
break;
while (avail) {
readl(fsm->base + SPI_FAST_SEQ_DATA_REG);
avail--;
}
}
}
static inline void stfsm_load_seq(struct stfsm *fsm, static inline void stfsm_load_seq(struct stfsm *fsm,
const struct stfsm_seq *seq) const struct stfsm_seq *seq)
{ {
...@@ -772,6 +775,68 @@ static void stfsm_read_fifo(struct stfsm *fsm, uint32_t *buf, uint32_t size) ...@@ -772,6 +775,68 @@ static void stfsm_read_fifo(struct stfsm *fsm, uint32_t *buf, uint32_t size)
} }
} }
/*
* Clear the data FIFO
*
* Typically, this is only required during driver initialisation, where no
* assumptions can be made regarding the state of the FIFO.
*
* The process of clearing the FIFO is complicated by fact that while it is
* possible for the FIFO to contain an arbitrary number of bytes [1], the
* SPI_FAST_SEQ_STA register only reports the number of complete 32-bit words
* present. Furthermore, data can only be drained from the FIFO by reading
* complete 32-bit words.
*
* With this in mind, a two stage process is used to the clear the FIFO:
*
* 1. Read any complete 32-bit words from the FIFO, as reported by the
* SPI_FAST_SEQ_STA register.
*
* 2. Mop up any remaining bytes. At this point, it is not known if there
* are 0, 1, 2, or 3 bytes in the FIFO. To handle all cases, a dummy FSM
* sequence is used to load one byte at a time, until a complete 32-bit
* word is formed; at most, 4 bytes will need to be loaded.
*
* [1] It is theoretically possible for the FIFO to contain an arbitrary number
* of bits. However, since there are no known use-cases that leave
* incomplete bytes in the FIFO, only words and bytes are considered here.
*/
static void stfsm_clear_fifo(struct stfsm *fsm)
{
const struct stfsm_seq *seq = &stfsm_seq_load_fifo_byte;
uint32_t words, i;
/* 1. Clear any 32-bit words */
words = stfsm_fifo_available(fsm);
if (words) {
for (i = 0; i < words; i++)
readl(fsm->base + SPI_FAST_SEQ_DATA_REG);
dev_dbg(fsm->dev, "cleared %d words from FIFO\n", words);
}
/*
* 2. Clear any remaining bytes
* - Load the FIFO, one byte at a time, until a complete 32-bit word
* is available.
*/
for (i = 0, words = 0; i < 4 && !words; i++) {
stfsm_load_seq(fsm, seq);
stfsm_wait_seq(fsm);
words = stfsm_fifo_available(fsm);
}
/* - A single word must be available now */
if (words != 1) {
dev_err(fsm->dev, "failed to clear bytes from the data FIFO\n");
return;
}
/* - Read the 32-bit word */
readl(fsm->base + SPI_FAST_SEQ_DATA_REG);
dev_dbg(fsm->dev, "cleared %d byte(s) from the data FIFO\n", 4 - i);
}
static int stfsm_write_fifo(struct stfsm *fsm, const uint32_t *buf, static int stfsm_write_fifo(struct stfsm *fsm, const uint32_t *buf,
uint32_t size) uint32_t size)
{ {
...@@ -1521,11 +1586,11 @@ static int stfsm_write(struct stfsm *fsm, const uint8_t *buf, ...@@ -1521,11 +1586,11 @@ static int stfsm_write(struct stfsm *fsm, const uint8_t *buf,
uint32_t size_lb; uint32_t size_lb;
uint32_t size_mop; uint32_t size_mop;
uint32_t tmp[4]; uint32_t tmp[4];
uint32_t i;
uint32_t page_buf[FLASH_PAGESIZE_32]; uint32_t page_buf[FLASH_PAGESIZE_32];
uint8_t *t = (uint8_t *)&tmp; uint8_t *t = (uint8_t *)&tmp;
const uint8_t *p; const uint8_t *p;
int ret; int ret;
int i;
dev_dbg(fsm->dev, "writing %d bytes to 0x%08x\n", size, offset); dev_dbg(fsm->dev, "writing %d bytes to 0x%08x\n", size, offset);
...@@ -1843,8 +1908,7 @@ static void stfsm_set_freq(struct stfsm *fsm, uint32_t spi_freq) ...@@ -1843,8 +1908,7 @@ static void stfsm_set_freq(struct stfsm *fsm, uint32_t spi_freq)
uint32_t emi_freq; uint32_t emi_freq;
uint32_t clk_div; uint32_t clk_div;
/* TODO: Make this dynamic */ emi_freq = clk_get_rate(fsm->clk);
emi_freq = STFSM_DEFAULT_EMI_FREQ;
/* /*
* Calculate clk_div - values between 2 and 128 * Calculate clk_div - values between 2 and 128
...@@ -1994,6 +2058,18 @@ static int stfsm_probe(struct platform_device *pdev) ...@@ -1994,6 +2058,18 @@ static int stfsm_probe(struct platform_device *pdev)
return PTR_ERR(fsm->base); return PTR_ERR(fsm->base);
} }
fsm->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(fsm->clk)) {
dev_err(fsm->dev, "Couldn't find EMI clock.\n");
return PTR_ERR(fsm->clk);
}
ret = clk_prepare_enable(fsm->clk);
if (ret) {
dev_err(fsm->dev, "Failed to enable EMI clock.\n");
return ret;
}
mutex_init(&fsm->lock); mutex_init(&fsm->lock);
ret = stfsm_init(fsm); ret = stfsm_init(fsm);
...@@ -2058,6 +2134,28 @@ static int stfsm_remove(struct platform_device *pdev) ...@@ -2058,6 +2134,28 @@ static int stfsm_remove(struct platform_device *pdev)
return mtd_device_unregister(&fsm->mtd); return mtd_device_unregister(&fsm->mtd);
} }
#ifdef CONFIG_PM_SLEEP
static int stfsmfsm_suspend(struct device *dev)
{
struct stfsm *fsm = dev_get_drvdata(dev);
clk_disable_unprepare(fsm->clk);
return 0;
}
static int stfsmfsm_resume(struct device *dev)
{
struct stfsm *fsm = dev_get_drvdata(dev);
clk_prepare_enable(fsm->clk);
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(stfsm_pm_ops, stfsmfsm_suspend, stfsmfsm_resume);
static const struct of_device_id stfsm_match[] = { static const struct of_device_id stfsm_match[] = {
{ .compatible = "st,spi-fsm", }, { .compatible = "st,spi-fsm", },
{}, {},
...@@ -2070,6 +2168,7 @@ static struct platform_driver stfsm_driver = { ...@@ -2070,6 +2168,7 @@ static struct platform_driver stfsm_driver = {
.driver = { .driver = {
.name = "st-spi-fsm", .name = "st-spi-fsm",
.of_match_table = stfsm_match, .of_match_table = stfsm_match,
.pm = &stfsm_pm_ops,
}, },
}; };
module_platform_driver(stfsm_driver); module_platform_driver(stfsm_driver);
......
...@@ -269,6 +269,16 @@ static int of_flash_probe(struct platform_device *dev) ...@@ -269,6 +269,16 @@ static int of_flash_probe(struct platform_device *dev)
info->list[i].mtd = obsolete_probe(dev, info->list[i].mtd = obsolete_probe(dev,
&info->list[i].map); &info->list[i].map);
} }
/* Fall back to mapping region as ROM */
if (!info->list[i].mtd) {
dev_warn(&dev->dev,
"do_map_probe() failed for type %s\n",
probe_type);
info->list[i].mtd = do_map_probe("map_rom",
&info->list[i].map);
}
mtd_list[i] = info->list[i].mtd; mtd_list[i] = info->list[i].mtd;
err = -ENXIO; err = -ENXIO;
......
...@@ -45,8 +45,6 @@ struct mtdblk_dev { ...@@ -45,8 +45,6 @@ struct mtdblk_dev {
enum { STATE_EMPTY, STATE_CLEAN, STATE_DIRTY } cache_state; enum { STATE_EMPTY, STATE_CLEAN, STATE_DIRTY } cache_state;
}; };
static DEFINE_MUTEX(mtdblks_lock);
/* /*
* Cache stuff... * Cache stuff...
* *
...@@ -286,10 +284,8 @@ static int mtdblock_open(struct mtd_blktrans_dev *mbd) ...@@ -286,10 +284,8 @@ static int mtdblock_open(struct mtd_blktrans_dev *mbd)
pr_debug("mtdblock_open\n"); pr_debug("mtdblock_open\n");
mutex_lock(&mtdblks_lock);
if (mtdblk->count) { if (mtdblk->count) {
mtdblk->count++; mtdblk->count++;
mutex_unlock(&mtdblks_lock);
return 0; return 0;
} }
...@@ -302,8 +298,6 @@ static int mtdblock_open(struct mtd_blktrans_dev *mbd) ...@@ -302,8 +298,6 @@ static int mtdblock_open(struct mtd_blktrans_dev *mbd)
mtdblk->cache_data = NULL; mtdblk->cache_data = NULL;
} }
mutex_unlock(&mtdblks_lock);
pr_debug("ok\n"); pr_debug("ok\n");
return 0; return 0;
...@@ -315,8 +309,6 @@ static void mtdblock_release(struct mtd_blktrans_dev *mbd) ...@@ -315,8 +309,6 @@ static void mtdblock_release(struct mtd_blktrans_dev *mbd)
pr_debug("mtdblock_release\n"); pr_debug("mtdblock_release\n");
mutex_lock(&mtdblks_lock);
mutex_lock(&mtdblk->cache_mutex); mutex_lock(&mtdblk->cache_mutex);
write_cached_data(mtdblk); write_cached_data(mtdblk);
mutex_unlock(&mtdblk->cache_mutex); mutex_unlock(&mtdblk->cache_mutex);
...@@ -331,8 +323,6 @@ static void mtdblock_release(struct mtd_blktrans_dev *mbd) ...@@ -331,8 +323,6 @@ static void mtdblock_release(struct mtd_blktrans_dev *mbd)
vfree(mtdblk->cache_data); vfree(mtdblk->cache_data);
} }
mutex_unlock(&mtdblks_lock);
pr_debug("ok\n"); pr_debug("ok\n");
} }
......
...@@ -311,7 +311,8 @@ concat_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops) ...@@ -311,7 +311,8 @@ concat_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops)
devops.len = subdev->size - to; devops.len = subdev->size - to;
err = mtd_write_oob(subdev, to, &devops); err = mtd_write_oob(subdev, to, &devops);
ops->retlen += devops.oobretlen; ops->retlen += devops.retlen;
ops->oobretlen += devops.oobretlen;
if (err) if (err)
return err; return err;
......
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include <linux/backing-dev.h> #include <linux/backing-dev.h>
#include <linux/gfp.h> #include <linux/gfp.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/reboot.h>
#include <linux/mtd/mtd.h> #include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h> #include <linux/mtd/partitions.h>
...@@ -356,6 +357,17 @@ unsigned mtd_mmap_capabilities(struct mtd_info *mtd) ...@@ -356,6 +357,17 @@ unsigned mtd_mmap_capabilities(struct mtd_info *mtd)
EXPORT_SYMBOL_GPL(mtd_mmap_capabilities); EXPORT_SYMBOL_GPL(mtd_mmap_capabilities);
#endif #endif
static int mtd_reboot_notifier(struct notifier_block *n, unsigned long state,
void *cmd)
{
struct mtd_info *mtd;
mtd = container_of(n, struct mtd_info, reboot_notifier);
mtd->_reboot(mtd);
return NOTIFY_DONE;
}
/** /**
* add_mtd_device - register an MTD device * add_mtd_device - register an MTD device
* @mtd: pointer to new MTD device info structure * @mtd: pointer to new MTD device info structure
...@@ -544,6 +556,19 @@ int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types, ...@@ -544,6 +556,19 @@ int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types,
err = -ENODEV; err = -ENODEV;
} }
/*
* FIXME: some drivers unfortunately call this function more than once.
* So we have to check if we've already assigned the reboot notifier.
*
* Generally, we can make multiple calls work for most cases, but it
* does cause problems with parse_mtd_partitions() above (e.g.,
* cmdlineparts will register partitions more than once).
*/
if (mtd->_reboot && !mtd->reboot_notifier.notifier_call) {
mtd->reboot_notifier.notifier_call = mtd_reboot_notifier;
register_reboot_notifier(&mtd->reboot_notifier);
}
return err; return err;
} }
EXPORT_SYMBOL_GPL(mtd_device_parse_register); EXPORT_SYMBOL_GPL(mtd_device_parse_register);
...@@ -558,6 +583,9 @@ int mtd_device_unregister(struct mtd_info *master) ...@@ -558,6 +583,9 @@ int mtd_device_unregister(struct mtd_info *master)
{ {
int err; int err;
if (master->_reboot)
unregister_reboot_notifier(&master->reboot_notifier);
err = del_mtd_partitions(master); err = del_mtd_partitions(master);
if (err) if (err)
return err; return err;
......
...@@ -421,7 +421,7 @@ config MTD_NAND_ORION ...@@ -421,7 +421,7 @@ config MTD_NAND_ORION
config MTD_NAND_FSL_ELBC config MTD_NAND_FSL_ELBC
tristate "NAND support for Freescale eLBC controllers" tristate "NAND support for Freescale eLBC controllers"
depends on PPC_OF depends on PPC
select FSL_LBC select FSL_LBC
help help
Various Freescale chips, including the 8313, include a NAND Flash Various Freescale chips, including the 8313, include a NAND Flash
...@@ -524,4 +524,9 @@ config MTD_NAND_SUNXI ...@@ -524,4 +524,9 @@ config MTD_NAND_SUNXI
help help
Enables support for NAND Flash chips on Allwinner SoCs. Enables support for NAND Flash chips on Allwinner SoCs.
config MTD_NAND_HISI504
tristate "Support for NAND controller on Hisilicon SoC Hip04"
help
Enables support for NAND controller on Hisilicon SoC Hip04.
endif # MTD_NAND endif # MTD_NAND
...@@ -51,5 +51,6 @@ obj-$(CONFIG_MTD_NAND_GPMI_NAND) += gpmi-nand/ ...@@ -51,5 +51,6 @@ obj-$(CONFIG_MTD_NAND_GPMI_NAND) += gpmi-nand/
obj-$(CONFIG_MTD_NAND_XWAY) += xway_nand.o obj-$(CONFIG_MTD_NAND_XWAY) += xway_nand.o
obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH) += bcm47xxnflash/ obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH) += bcm47xxnflash/
obj-$(CONFIG_MTD_NAND_SUNXI) += sunxi_nand.o obj-$(CONFIG_MTD_NAND_SUNXI) += sunxi_nand.o
obj-$(CONFIG_MTD_NAND_HISI504) += hisi504_nand.o
nand-objs := nand_base.o nand_bbt.o nand_timings.o nand-objs := nand_base.o nand_bbt.o nand_timings.o
...@@ -183,7 +183,7 @@ static int ams_delta_init(struct platform_device *pdev) ...@@ -183,7 +183,7 @@ static int ams_delta_init(struct platform_device *pdev)
return -ENXIO; return -ENXIO;
/* Allocate memory for MTD device structure and private data */ /* Allocate memory for MTD device structure and private data */
ams_delta_mtd = kmalloc(sizeof(struct mtd_info) + ams_delta_mtd = kzalloc(sizeof(struct mtd_info) +
sizeof(struct nand_chip), GFP_KERNEL); sizeof(struct nand_chip), GFP_KERNEL);
if (!ams_delta_mtd) { if (!ams_delta_mtd) {
printk (KERN_WARNING "Unable to allocate E3 NAND MTD device structure.\n"); printk (KERN_WARNING "Unable to allocate E3 NAND MTD device structure.\n");
...@@ -196,10 +196,6 @@ static int ams_delta_init(struct platform_device *pdev) ...@@ -196,10 +196,6 @@ static int ams_delta_init(struct platform_device *pdev)
/* Get pointer to private data */ /* Get pointer to private data */
this = (struct nand_chip *) (&ams_delta_mtd[1]); this = (struct nand_chip *) (&ams_delta_mtd[1]);
/* Initialize structures */
memset(ams_delta_mtd, 0, sizeof(struct mtd_info));
memset(this, 0, sizeof(struct nand_chip));
/* Link the private data with the MTD structure */ /* Link the private data with the MTD structure */
ams_delta_mtd->priv = this; ams_delta_mtd->priv = this;
......
...@@ -63,6 +63,10 @@ module_param(on_flash_bbt, int, 0); ...@@ -63,6 +63,10 @@ module_param(on_flash_bbt, int, 0);
#include "atmel_nand_ecc.h" /* Hardware ECC registers */ #include "atmel_nand_ecc.h" /* Hardware ECC registers */
#include "atmel_nand_nfc.h" /* Nand Flash Controller definition */ #include "atmel_nand_nfc.h" /* Nand Flash Controller definition */
struct atmel_nand_caps {
bool pmecc_correct_erase_page;
};
/* oob layout for large page size /* oob layout for large page size
* bad block info is on bytes 0 and 1 * bad block info is on bytes 0 and 1
* the bytes have to be consecutives to avoid * the bytes have to be consecutives to avoid
...@@ -124,6 +128,7 @@ struct atmel_nand_host { ...@@ -124,6 +128,7 @@ struct atmel_nand_host {
struct atmel_nfc *nfc; struct atmel_nfc *nfc;
struct atmel_nand_caps *caps;
bool has_pmecc; bool has_pmecc;
u8 pmecc_corr_cap; u8 pmecc_corr_cap;
u16 pmecc_sector_size; u16 pmecc_sector_size;
...@@ -847,7 +852,11 @@ static int pmecc_correction(struct mtd_info *mtd, u32 pmecc_stat, uint8_t *buf, ...@@ -847,7 +852,11 @@ static int pmecc_correction(struct mtd_info *mtd, u32 pmecc_stat, uint8_t *buf,
struct atmel_nand_host *host = nand_chip->priv; struct atmel_nand_host *host = nand_chip->priv;
int i, err_nbr; int i, err_nbr;
uint8_t *buf_pos; uint8_t *buf_pos;
int total_err = 0; int max_bitflips = 0;
/* If can correct bitfilps from erased page, do the normal check */
if (host->caps->pmecc_correct_erase_page)
goto normal_check;
for (i = 0; i < nand_chip->ecc.total; i++) for (i = 0; i < nand_chip->ecc.total; i++)
if (ecc[i] != 0xff) if (ecc[i] != 0xff)
...@@ -874,13 +883,13 @@ static int pmecc_correction(struct mtd_info *mtd, u32 pmecc_stat, uint8_t *buf, ...@@ -874,13 +883,13 @@ static int pmecc_correction(struct mtd_info *mtd, u32 pmecc_stat, uint8_t *buf,
pmecc_correct_data(mtd, buf_pos, ecc, i, pmecc_correct_data(mtd, buf_pos, ecc, i,
nand_chip->ecc.bytes, err_nbr); nand_chip->ecc.bytes, err_nbr);
mtd->ecc_stats.corrected += err_nbr; mtd->ecc_stats.corrected += err_nbr;
total_err += err_nbr; max_bitflips = max_t(int, max_bitflips, err_nbr);
} }
} }
pmecc_stat >>= 1; pmecc_stat >>= 1;
} }
return total_err; return max_bitflips;
} }
static void pmecc_enable(struct atmel_nand_host *host, int ecc_op) static void pmecc_enable(struct atmel_nand_host *host, int ecc_op)
...@@ -1474,6 +1483,8 @@ static void atmel_nand_hwctl(struct mtd_info *mtd, int mode) ...@@ -1474,6 +1483,8 @@ static void atmel_nand_hwctl(struct mtd_info *mtd, int mode)
ecc_writel(host->ecc, CR, ATMEL_ECC_RST); ecc_writel(host->ecc, CR, ATMEL_ECC_RST);
} }
static const struct of_device_id atmel_nand_dt_ids[];
static int atmel_of_init_port(struct atmel_nand_host *host, static int atmel_of_init_port(struct atmel_nand_host *host,
struct device_node *np) struct device_node *np)
{ {
...@@ -1483,6 +1494,9 @@ static int atmel_of_init_port(struct atmel_nand_host *host, ...@@ -1483,6 +1494,9 @@ static int atmel_of_init_port(struct atmel_nand_host *host,
struct atmel_nand_data *board = &host->board; struct atmel_nand_data *board = &host->board;
enum of_gpio_flags flags = 0; enum of_gpio_flags flags = 0;
host->caps = (struct atmel_nand_caps *)
of_match_device(atmel_nand_dt_ids, host->dev)->data;
if (of_property_read_u32(np, "atmel,nand-addr-offset", &val) == 0) { if (of_property_read_u32(np, "atmel,nand-addr-offset", &val) == 0) {
if (val >= 32) { if (val >= 32) {
dev_err(host->dev, "invalid addr-offset %u\n", val); dev_err(host->dev, "invalid addr-offset %u\n", val);
...@@ -2288,8 +2302,17 @@ static int atmel_nand_remove(struct platform_device *pdev) ...@@ -2288,8 +2302,17 @@ static int atmel_nand_remove(struct platform_device *pdev)
return 0; return 0;
} }
static struct atmel_nand_caps at91rm9200_caps = {
.pmecc_correct_erase_page = false,
};
static struct atmel_nand_caps sama5d4_caps = {
.pmecc_correct_erase_page = true,
};
static const struct of_device_id atmel_nand_dt_ids[] = { static const struct of_device_id atmel_nand_dt_ids[] = {
{ .compatible = "atmel,at91rm9200-nand" }, { .compatible = "atmel,at91rm9200-nand", .data = &at91rm9200_caps },
{ .compatible = "atmel,sama5d4-nand", .data = &sama5d4_caps },
{ /* sentinel */ } { /* sentinel */ }
}; };
......
...@@ -1041,7 +1041,7 @@ static void denali_setup_dma(struct denali_nand_info *denali, int op) ...@@ -1041,7 +1041,7 @@ static void denali_setup_dma(struct denali_nand_info *denali, int op)
index_addr(denali, mode | ((addr >> 16) << 8), 0x2200); index_addr(denali, mode | ((addr >> 16) << 8), 0x2200);
/* 3. set memory low address bits 23:8 */ /* 3. set memory low address bits 23:8 */
index_addr(denali, mode | ((addr & 0xff) << 8), 0x2300); index_addr(denali, mode | ((addr & 0xffff) << 8), 0x2300);
/* 4. interrupt when complete, burst len = 64 bytes */ /* 4. interrupt when complete, burst len = 64 bytes */
index_addr(denali, mode | 0x14000, 0x2400); index_addr(denali, mode | 0x14000, 0x2400);
...@@ -1328,35 +1328,6 @@ static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col, ...@@ -1328,35 +1328,6 @@ static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col,
break; break;
} }
} }
/* stubs for ECC functions not used by the NAND core */
static int denali_ecc_calculate(struct mtd_info *mtd, const uint8_t *data,
uint8_t *ecc_code)
{
struct denali_nand_info *denali = mtd_to_denali(mtd);
dev_err(denali->dev, "denali_ecc_calculate called unexpectedly\n");
BUG();
return -EIO;
}
static int denali_ecc_correct(struct mtd_info *mtd, uint8_t *data,
uint8_t *read_ecc, uint8_t *calc_ecc)
{
struct denali_nand_info *denali = mtd_to_denali(mtd);
dev_err(denali->dev, "denali_ecc_correct called unexpectedly\n");
BUG();
return -EIO;
}
static void denali_ecc_hwctl(struct mtd_info *mtd, int mode)
{
struct denali_nand_info *denali = mtd_to_denali(mtd);
dev_err(denali->dev, "denali_ecc_hwctl called unexpectedly\n");
BUG();
}
/* end NAND core entry points */ /* end NAND core entry points */
/* Initialization code to bring the device up to a known good state */ /* Initialization code to bring the device up to a known good state */
...@@ -1609,15 +1580,6 @@ int denali_init(struct denali_nand_info *denali) ...@@ -1609,15 +1580,6 @@ int denali_init(struct denali_nand_info *denali)
denali->totalblks = denali->mtd.size >> denali->nand.phys_erase_shift; denali->totalblks = denali->mtd.size >> denali->nand.phys_erase_shift;
denali->blksperchip = denali->totalblks / denali->nand.numchips; denali->blksperchip = denali->totalblks / denali->nand.numchips;
/*
* These functions are required by the NAND core framework, otherwise,
* the NAND core will assert. However, we don't need them, so we'll stub
* them out.
*/
denali->nand.ecc.calculate = denali_ecc_calculate;
denali->nand.ecc.correct = denali_ecc_correct;
denali->nand.ecc.hwctl = denali_ecc_hwctl;
/* override the default read operations */ /* override the default read operations */
denali->nand.ecc.size = ECC_SECTOR_SIZE * denali->devnum; denali->nand.ecc.size = ECC_SECTOR_SIZE * denali->devnum;
denali->nand.ecc.read_page = denali_read_page; denali->nand.ecc.read_page = denali_read_page;
......
...@@ -1294,14 +1294,6 @@ static int gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -1294,14 +1294,6 @@ static int gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
* ecc.read_page or ecc.read_page_raw function. Thus, the fact that MTD wants an * ecc.read_page or ecc.read_page_raw function. Thus, the fact that MTD wants an
* ECC-based or raw view of the page is implicit in which function it calls * ECC-based or raw view of the page is implicit in which function it calls
* (there is a similar pair of ECC-based/raw functions for writing). * (there is a similar pair of ECC-based/raw functions for writing).
*
* FIXME: The following paragraph is incorrect, now that there exist
* ecc.read_oob_raw and ecc.write_oob_raw functions.
*
* Since MTD assumes the OOB is not covered by ECC, there is no pair of
* ECC-based/raw functions for reading or or writing the OOB. The fact that the
* caller wants an ECC-based or raw view of the page is not propagated down to
* this driver.
*/ */
static int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip, static int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
int page) int page)
...@@ -2029,7 +2021,6 @@ static int gpmi_nand_probe(struct platform_device *pdev) ...@@ -2029,7 +2021,6 @@ static int gpmi_nand_probe(struct platform_device *pdev)
exit_nfc_init: exit_nfc_init:
release_resources(this); release_resources(this);
exit_acquire_resources: exit_acquire_resources:
dev_err(this->dev, "driver registration failed: %d\n", ret);
return ret; return ret;
} }
......
This diff is collapsed.
...@@ -69,7 +69,7 @@ struct jz_nand { ...@@ -69,7 +69,7 @@ struct jz_nand {
int selected_bank; int selected_bank;
struct jz_nand_platform_data *pdata; struct gpio_desc *busy_gpio;
bool is_reading; bool is_reading;
}; };
...@@ -131,7 +131,7 @@ static void jz_nand_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl) ...@@ -131,7 +131,7 @@ static void jz_nand_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
static int jz_nand_dev_ready(struct mtd_info *mtd) static int jz_nand_dev_ready(struct mtd_info *mtd)
{ {
struct jz_nand *nand = mtd_to_jz_nand(mtd); struct jz_nand *nand = mtd_to_jz_nand(mtd);
return gpio_get_value_cansleep(nand->pdata->busy_gpio); return gpiod_get_value_cansleep(nand->busy_gpio);
} }
static void jz_nand_hwctl(struct mtd_info *mtd, int mode) static void jz_nand_hwctl(struct mtd_info *mtd, int mode)
...@@ -423,14 +423,12 @@ static int jz_nand_probe(struct platform_device *pdev) ...@@ -423,14 +423,12 @@ static int jz_nand_probe(struct platform_device *pdev)
if (ret) if (ret)
goto err_free; goto err_free;
if (pdata && gpio_is_valid(pdata->busy_gpio)) { nand->busy_gpio = devm_gpiod_get_optional(&pdev->dev, "busy", GPIOD_IN);
ret = gpio_request(pdata->busy_gpio, "NAND busy pin"); if (IS_ERR(nand->busy_gpio)) {
if (ret) { ret = PTR_ERR(nand->busy_gpio);
dev_err(&pdev->dev, dev_err(&pdev->dev, "Failed to request busy gpio %d\n",
"Failed to request busy gpio %d: %d\n", ret);
pdata->busy_gpio, ret); goto err_iounmap_mmio;
goto err_iounmap_mmio;
}
} }
mtd = &nand->mtd; mtd = &nand->mtd;
...@@ -454,10 +452,9 @@ static int jz_nand_probe(struct platform_device *pdev) ...@@ -454,10 +452,9 @@ static int jz_nand_probe(struct platform_device *pdev)
chip->cmd_ctrl = jz_nand_cmd_ctrl; chip->cmd_ctrl = jz_nand_cmd_ctrl;
chip->select_chip = jz_nand_select_chip; chip->select_chip = jz_nand_select_chip;
if (pdata && gpio_is_valid(pdata->busy_gpio)) if (nand->busy_gpio)
chip->dev_ready = jz_nand_dev_ready; chip->dev_ready = jz_nand_dev_ready;
nand->pdata = pdata;
platform_set_drvdata(pdev, nand); platform_set_drvdata(pdev, nand);
/* We are going to autodetect NAND chips in the banks specified in the /* We are going to autodetect NAND chips in the banks specified in the
...@@ -496,7 +493,7 @@ static int jz_nand_probe(struct platform_device *pdev) ...@@ -496,7 +493,7 @@ static int jz_nand_probe(struct platform_device *pdev)
} }
if (chipnr == 0) { if (chipnr == 0) {
dev_err(&pdev->dev, "No NAND chips found\n"); dev_err(&pdev->dev, "No NAND chips found\n");
goto err_gpio_busy; goto err_iounmap_mmio;
} }
if (pdata && pdata->ident_callback) { if (pdata && pdata->ident_callback) {
...@@ -533,9 +530,6 @@ static int jz_nand_probe(struct platform_device *pdev) ...@@ -533,9 +530,6 @@ static int jz_nand_probe(struct platform_device *pdev)
nand->bank_base[bank - 1]); nand->bank_base[bank - 1]);
} }
writel(0, nand->base + JZ_REG_NAND_CTRL); writel(0, nand->base + JZ_REG_NAND_CTRL);
err_gpio_busy:
if (pdata && gpio_is_valid(pdata->busy_gpio))
gpio_free(pdata->busy_gpio);
err_iounmap_mmio: err_iounmap_mmio:
jz_nand_iounmap_resource(nand->mem, nand->base); jz_nand_iounmap_resource(nand->mem, nand->base);
err_free: err_free:
...@@ -546,7 +540,6 @@ static int jz_nand_probe(struct platform_device *pdev) ...@@ -546,7 +540,6 @@ static int jz_nand_probe(struct platform_device *pdev)
static int jz_nand_remove(struct platform_device *pdev) static int jz_nand_remove(struct platform_device *pdev)
{ {
struct jz_nand *nand = platform_get_drvdata(pdev); struct jz_nand *nand = platform_get_drvdata(pdev);
struct jz_nand_platform_data *pdata = dev_get_platdata(&pdev->dev);
size_t i; size_t i;
nand_release(&nand->mtd); nand_release(&nand->mtd);
...@@ -562,8 +555,6 @@ static int jz_nand_remove(struct platform_device *pdev) ...@@ -562,8 +555,6 @@ static int jz_nand_remove(struct platform_device *pdev)
gpio_free(JZ_GPIO_MEM_CS0 + bank - 1); gpio_free(JZ_GPIO_MEM_CS0 + bank - 1);
} }
} }
if (pdata && gpio_is_valid(pdata->busy_gpio))
gpio_free(pdata->busy_gpio);
jz_nand_iounmap_resource(nand->mem, nand->base); jz_nand_iounmap_resource(nand->mem, nand->base);
......
...@@ -156,7 +156,6 @@ static uint8_t nand_read_byte(struct mtd_info *mtd) ...@@ -156,7 +156,6 @@ static uint8_t nand_read_byte(struct mtd_info *mtd)
} }
/** /**
* nand_read_byte16 - [DEFAULT] read one byte endianness aware from the chip
* nand_read_byte16 - [DEFAULT] read one byte endianness aware from the chip * nand_read_byte16 - [DEFAULT] read one byte endianness aware from the chip
* @mtd: MTD device structure * @mtd: MTD device structure
* *
...@@ -1751,11 +1750,10 @@ static int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -1751,11 +1750,10 @@ static int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
static int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip, static int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
int page) int page)
{ {
uint8_t *buf = chip->oob_poi;
int length = mtd->oobsize; int length = mtd->oobsize;
int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad; int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad;
int eccsize = chip->ecc.size; int eccsize = chip->ecc.size;
uint8_t *bufpoi = buf; uint8_t *bufpoi = chip->oob_poi;
int i, toread, sndrnd = 0, pos; int i, toread, sndrnd = 0, pos;
chip->cmdfunc(mtd, NAND_CMD_READ0, chip->ecc.size, page); chip->cmdfunc(mtd, NAND_CMD_READ0, chip->ecc.size, page);
...@@ -2944,6 +2942,16 @@ static void nand_resume(struct mtd_info *mtd) ...@@ -2944,6 +2942,16 @@ static void nand_resume(struct mtd_info *mtd)
__func__); __func__);
} }
/**
* nand_shutdown - [MTD Interface] Finish the current NAND operation and
* prevent further operations
* @mtd: MTD device structure
*/
static void nand_shutdown(struct mtd_info *mtd)
{
nand_get_device(mtd, FL_SHUTDOWN);
}
/* Set default functions */ /* Set default functions */
static void nand_set_defaults(struct nand_chip *chip, int busw) static void nand_set_defaults(struct nand_chip *chip, int busw)
{ {
...@@ -4028,22 +4036,24 @@ int nand_scan_tail(struct mtd_info *mtd) ...@@ -4028,22 +4036,24 @@ int nand_scan_tail(struct mtd_info *mtd)
ecc->read_oob = nand_read_oob_std; ecc->read_oob = nand_read_oob_std;
ecc->write_oob = nand_write_oob_std; ecc->write_oob = nand_write_oob_std;
/* /*
* Board driver should supply ecc.size and ecc.bytes values to * Board driver should supply ecc.size and ecc.strength values
* select how many bits are correctable; see nand_bch_init() * to select how many bits are correctable. Otherwise, default
* for details. Otherwise, default to 4 bits for large page * to 4 bits for large page devices.
* devices.
*/ */
if (!ecc->size && (mtd->oobsize >= 64)) { if (!ecc->size && (mtd->oobsize >= 64)) {
ecc->size = 512; ecc->size = 512;
ecc->bytes = DIV_ROUND_UP(13 * ecc->strength, 8); ecc->strength = 4;
} }
/* See nand_bch_init() for details. */
ecc->bytes = DIV_ROUND_UP(
ecc->strength * fls(8 * ecc->size), 8);
ecc->priv = nand_bch_init(mtd, ecc->size, ecc->bytes, ecc->priv = nand_bch_init(mtd, ecc->size, ecc->bytes,
&ecc->layout); &ecc->layout);
if (!ecc->priv) { if (!ecc->priv) {
pr_warn("BCH ECC initialization failed!\n"); pr_warn("BCH ECC initialization failed!\n");
BUG(); BUG();
} }
ecc->strength = ecc->bytes * 8 / fls(8 * ecc->size);
break; break;
case NAND_ECC_NONE: case NAND_ECC_NONE:
...@@ -4146,6 +4156,7 @@ int nand_scan_tail(struct mtd_info *mtd) ...@@ -4146,6 +4156,7 @@ int nand_scan_tail(struct mtd_info *mtd)
mtd->_unlock = NULL; mtd->_unlock = NULL;
mtd->_suspend = nand_suspend; mtd->_suspend = nand_suspend;
mtd->_resume = nand_resume; mtd->_resume = nand_resume;
mtd->_reboot = nand_shutdown;
mtd->_block_isreserved = nand_block_isreserved; mtd->_block_isreserved = nand_block_isreserved;
mtd->_block_isbad = nand_block_isbad; mtd->_block_isbad = nand_block_isbad;
mtd->_block_markbad = nand_block_markbad; mtd->_block_markbad = nand_block_markbad;
...@@ -4161,7 +4172,7 @@ int nand_scan_tail(struct mtd_info *mtd) ...@@ -4161,7 +4172,7 @@ int nand_scan_tail(struct mtd_info *mtd)
* properly set. * properly set.
*/ */
if (!mtd->bitflip_threshold) if (!mtd->bitflip_threshold)
mtd->bitflip_threshold = mtd->ecc_strength; mtd->bitflip_threshold = DIV_ROUND_UP(mtd->ecc_strength * 3, 4);
/* Check, if we should skip the bad block table scan */ /* Check, if we should skip the bad block table scan */
if (chip->options & NAND_SKIP_BBTSCAN) if (chip->options & NAND_SKIP_BBTSCAN)
......
...@@ -245,7 +245,6 @@ MODULE_PARM_DESC(bch, "Enable BCH ecc and set how many bits should " ...@@ -245,7 +245,6 @@ MODULE_PARM_DESC(bch, "Enable BCH ecc and set how many bits should "
#define STATE_DATAOUT 0x00001000 /* waiting for page data output */ #define STATE_DATAOUT 0x00001000 /* waiting for page data output */
#define STATE_DATAOUT_ID 0x00002000 /* waiting for ID bytes output */ #define STATE_DATAOUT_ID 0x00002000 /* waiting for ID bytes output */
#define STATE_DATAOUT_STATUS 0x00003000 /* waiting for status output */ #define STATE_DATAOUT_STATUS 0x00003000 /* waiting for status output */
#define STATE_DATAOUT_STATUS_M 0x00004000 /* waiting for multi-plane status output */
#define STATE_DATAOUT_MASK 0x00007000 /* data output states mask */ #define STATE_DATAOUT_MASK 0x00007000 /* data output states mask */
/* Previous operation is done, ready to accept new requests */ /* Previous operation is done, ready to accept new requests */
...@@ -269,7 +268,6 @@ MODULE_PARM_DESC(bch, "Enable BCH ecc and set how many bits should " ...@@ -269,7 +268,6 @@ MODULE_PARM_DESC(bch, "Enable BCH ecc and set how many bits should "
#define OPT_ANY 0xFFFFFFFF /* any chip supports this operation */ #define OPT_ANY 0xFFFFFFFF /* any chip supports this operation */
#define OPT_PAGE512 0x00000002 /* 512-byte page chips */ #define OPT_PAGE512 0x00000002 /* 512-byte page chips */
#define OPT_PAGE2048 0x00000008 /* 2048-byte page chips */ #define OPT_PAGE2048 0x00000008 /* 2048-byte page chips */
#define OPT_SMARTMEDIA 0x00000010 /* SmartMedia technology chips */
#define OPT_PAGE512_8BIT 0x00000040 /* 512-byte page chips with 8-bit bus width */ #define OPT_PAGE512_8BIT 0x00000040 /* 512-byte page chips with 8-bit bus width */
#define OPT_PAGE4096 0x00000080 /* 4096-byte page chips */ #define OPT_PAGE4096 0x00000080 /* 4096-byte page chips */
#define OPT_LARGEPAGE (OPT_PAGE2048 | OPT_PAGE4096) /* 2048 & 4096-byte page chips */ #define OPT_LARGEPAGE (OPT_PAGE2048 | OPT_PAGE4096) /* 2048 & 4096-byte page chips */
...@@ -1096,8 +1094,6 @@ static char *get_state_name(uint32_t state) ...@@ -1096,8 +1094,6 @@ static char *get_state_name(uint32_t state)
return "STATE_DATAOUT_ID"; return "STATE_DATAOUT_ID";
case STATE_DATAOUT_STATUS: case STATE_DATAOUT_STATUS:
return "STATE_DATAOUT_STATUS"; return "STATE_DATAOUT_STATUS";
case STATE_DATAOUT_STATUS_M:
return "STATE_DATAOUT_STATUS_M";
case STATE_READY: case STATE_READY:
return "STATE_READY"; return "STATE_READY";
case STATE_UNKNOWN: case STATE_UNKNOWN:
...@@ -1865,7 +1861,6 @@ static void switch_state(struct nandsim *ns) ...@@ -1865,7 +1861,6 @@ static void switch_state(struct nandsim *ns)
break; break;
case STATE_DATAOUT_STATUS: case STATE_DATAOUT_STATUS:
case STATE_DATAOUT_STATUS_M:
ns->regs.count = ns->regs.num = 0; ns->regs.count = ns->regs.num = 0;
break; break;
...@@ -2005,7 +2000,6 @@ static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte) ...@@ -2005,7 +2000,6 @@ static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
} }
if (NS_STATE(ns->state) == STATE_DATAOUT_STATUS if (NS_STATE(ns->state) == STATE_DATAOUT_STATUS
|| NS_STATE(ns->state) == STATE_DATAOUT_STATUS_M
|| NS_STATE(ns->state) == STATE_DATAOUT) { || NS_STATE(ns->state) == STATE_DATAOUT) {
int row = ns->regs.row; int row = ns->regs.row;
...@@ -2343,6 +2337,7 @@ static int __init ns_init_module(void) ...@@ -2343,6 +2337,7 @@ static int __init ns_init_module(void)
} }
chip->ecc.mode = NAND_ECC_SOFT_BCH; chip->ecc.mode = NAND_ECC_SOFT_BCH;
chip->ecc.size = 512; chip->ecc.size = 512;
chip->ecc.strength = bch;
chip->ecc.bytes = eccbytes; chip->ecc.bytes = eccbytes;
NS_INFO("using %u-bit/%u bytes BCH ECC\n", bch, chip->ecc.size); NS_INFO("using %u-bit/%u bytes BCH ECC\n", bch, chip->ecc.size);
} }
......
...@@ -1048,10 +1048,9 @@ static int omap_dev_ready(struct mtd_info *mtd) ...@@ -1048,10 +1048,9 @@ static int omap_dev_ready(struct mtd_info *mtd)
* @mtd: MTD device structure * @mtd: MTD device structure
* @mode: Read/Write mode * @mode: Read/Write mode
* *
* When using BCH, sector size is hardcoded to 512 bytes. * When using BCH with SW correction (i.e. no ELM), sector size is set
* Using wrapping mode 6 both for reading and writing if ELM module not uses * to 512 bytes and we use BCH_WRAPMODE_6 wrapping mode
* for error correction. * for both reading and writing with:
* On writing,
* eccsize0 = 0 (no additional protected byte in spare area) * eccsize0 = 0 (no additional protected byte in spare area)
* eccsize1 = 32 (skip 32 nibbles = 16 bytes per sector in spare area) * eccsize1 = 32 (skip 32 nibbles = 16 bytes per sector in spare area)
*/ */
...@@ -1071,15 +1070,9 @@ static void __maybe_unused omap_enable_hwecc_bch(struct mtd_info *mtd, int mode) ...@@ -1071,15 +1070,9 @@ static void __maybe_unused omap_enable_hwecc_bch(struct mtd_info *mtd, int mode)
case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW: case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW:
bch_type = 0; bch_type = 0;
nsectors = 1; nsectors = 1;
if (mode == NAND_ECC_READ) { wr_mode = BCH_WRAPMODE_6;
wr_mode = BCH_WRAPMODE_6; ecc_size0 = BCH_ECC_SIZE0;
ecc_size0 = BCH_ECC_SIZE0; ecc_size1 = BCH_ECC_SIZE1;
ecc_size1 = BCH_ECC_SIZE1;
} else {
wr_mode = BCH_WRAPMODE_6;
ecc_size0 = BCH_ECC_SIZE0;
ecc_size1 = BCH_ECC_SIZE1;
}
break; break;
case OMAP_ECC_BCH4_CODE_HW: case OMAP_ECC_BCH4_CODE_HW:
bch_type = 0; bch_type = 0;
...@@ -1097,15 +1090,9 @@ static void __maybe_unused omap_enable_hwecc_bch(struct mtd_info *mtd, int mode) ...@@ -1097,15 +1090,9 @@ static void __maybe_unused omap_enable_hwecc_bch(struct mtd_info *mtd, int mode)
case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW: case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
bch_type = 1; bch_type = 1;
nsectors = 1; nsectors = 1;
if (mode == NAND_ECC_READ) { wr_mode = BCH_WRAPMODE_6;
wr_mode = BCH_WRAPMODE_6; ecc_size0 = BCH_ECC_SIZE0;
ecc_size0 = BCH_ECC_SIZE0; ecc_size1 = BCH_ECC_SIZE1;
ecc_size1 = BCH_ECC_SIZE1;
} else {
wr_mode = BCH_WRAPMODE_6;
ecc_size0 = BCH_ECC_SIZE0;
ecc_size1 = BCH_ECC_SIZE1;
}
break; break;
case OMAP_ECC_BCH8_CODE_HW: case OMAP_ECC_BCH8_CODE_HW:
bch_type = 1; bch_type = 1;
......
...@@ -1110,8 +1110,6 @@ static int sunxi_nand_ecc_init(struct mtd_info *mtd, struct nand_ecc_ctrl *ecc, ...@@ -1110,8 +1110,6 @@ static int sunxi_nand_ecc_init(struct mtd_info *mtd, struct nand_ecc_ctrl *ecc,
switch (ecc->mode) { switch (ecc->mode) {
case NAND_ECC_SOFT_BCH: case NAND_ECC_SOFT_BCH:
ecc->bytes = DIV_ROUND_UP(ecc->strength * fls(8 * ecc->size),
8);
break; break;
case NAND_ECC_HW: case NAND_ECC_HW:
ret = sunxi_nand_hw_ecc_ctrl_init(mtd, ecc, np); ret = sunxi_nand_hw_ecc_ctrl_init(mtd, ecc, np);
......
...@@ -89,9 +89,10 @@ static int find_boot_record(struct NFTLrecord *nftl) ...@@ -89,9 +89,10 @@ static int find_boot_record(struct NFTLrecord *nftl)
} }
/* To be safer with BIOS, also use erase mark as discriminant */ /* To be safer with BIOS, also use erase mark as discriminant */
if ((ret = nftl_read_oob(mtd, block * nftl->EraseSize + ret = nftl_read_oob(mtd, block * nftl->EraseSize +
SECTORSIZE + 8, 8, &retlen, SECTORSIZE + 8, 8, &retlen,
(char *)&h1) < 0)) { (char *)&h1);
if (ret < 0) {
printk(KERN_WARNING "ANAND header found at 0x%x in mtd%d, but OOB data read failed (err %d)\n", printk(KERN_WARNING "ANAND header found at 0x%x in mtd%d, but OOB data read failed (err %d)\n",
block * nftl->EraseSize, nftl->mbd.mtd->index, ret); block * nftl->EraseSize, nftl->mbd.mtd->index, ret);
continue; continue;
...@@ -109,8 +110,9 @@ static int find_boot_record(struct NFTLrecord *nftl) ...@@ -109,8 +110,9 @@ static int find_boot_record(struct NFTLrecord *nftl)
} }
/* Finally reread to check ECC */ /* Finally reread to check ECC */
if ((ret = mtd->read(mtd, block * nftl->EraseSize, SECTORSIZE, ret = mtd->read(mtd, block * nftl->EraseSize, SECTORSIZE,
&retlen, buf) < 0)) { &retlen, buf);
if (ret < 0) {
printk(KERN_NOTICE "ANAND header found at 0x%x in mtd%d, but ECC read failed (err %d)\n", printk(KERN_NOTICE "ANAND header found at 0x%x in mtd%d, but ECC read failed (err %d)\n",
block * nftl->EraseSize, nftl->mbd.mtd->index, ret); block * nftl->EraseSize, nftl->mbd.mtd->index, ret);
continue; continue;
...@@ -228,9 +230,11 @@ device is already correct. ...@@ -228,9 +230,11 @@ device is already correct.
The new DiskOnChip driver already scanned the bad block table. Just query it. The new DiskOnChip driver already scanned the bad block table. Just query it.
if ((i & (SECTORSIZE - 1)) == 0) { if ((i & (SECTORSIZE - 1)) == 0) {
/* read one sector for every SECTORSIZE of blocks */ /* read one sector for every SECTORSIZE of blocks */
if ((ret = mtd->read(nftl->mbd.mtd, block * nftl->EraseSize + ret = mtd->read(nftl->mbd.mtd,
i + SECTORSIZE, SECTORSIZE, &retlen, block * nftl->EraseSize + i +
buf)) < 0) { SECTORSIZE, SECTORSIZE,
&retlen, buf);
if (ret < 0) {
printk(KERN_NOTICE "Read of bad sector table failed (err %d)\n", printk(KERN_NOTICE "Read of bad sector table failed (err %d)\n",
ret); ret);
kfree(nftl->ReplUnitTable); kfree(nftl->ReplUnitTable);
......
...@@ -57,7 +57,9 @@ ...@@ -57,7 +57,9 @@
#define QUADSPI_BUF3CR 0x1c #define QUADSPI_BUF3CR 0x1c
#define QUADSPI_BUF3CR_ALLMST_SHIFT 31 #define QUADSPI_BUF3CR_ALLMST_SHIFT 31
#define QUADSPI_BUF3CR_ALLMST (1 << QUADSPI_BUF3CR_ALLMST_SHIFT) #define QUADSPI_BUF3CR_ALLMST_MASK (1 << QUADSPI_BUF3CR_ALLMST_SHIFT)
#define QUADSPI_BUF3CR_ADATSZ_SHIFT 8
#define QUADSPI_BUF3CR_ADATSZ_MASK (0xFF << QUADSPI_BUF3CR_ADATSZ_SHIFT)
#define QUADSPI_BFGENCR 0x20 #define QUADSPI_BFGENCR 0x20
#define QUADSPI_BFGENCR_PAR_EN_SHIFT 16 #define QUADSPI_BFGENCR_PAR_EN_SHIFT 16
...@@ -198,18 +200,21 @@ struct fsl_qspi_devtype_data { ...@@ -198,18 +200,21 @@ struct fsl_qspi_devtype_data {
enum fsl_qspi_devtype devtype; enum fsl_qspi_devtype devtype;
int rxfifo; int rxfifo;
int txfifo; int txfifo;
int ahb_buf_size;
}; };
static struct fsl_qspi_devtype_data vybrid_data = { static struct fsl_qspi_devtype_data vybrid_data = {
.devtype = FSL_QUADSPI_VYBRID, .devtype = FSL_QUADSPI_VYBRID,
.rxfifo = 128, .rxfifo = 128,
.txfifo = 64 .txfifo = 64,
.ahb_buf_size = 1024
}; };
static struct fsl_qspi_devtype_data imx6sx_data = { static struct fsl_qspi_devtype_data imx6sx_data = {
.devtype = FSL_QUADSPI_IMX6SX, .devtype = FSL_QUADSPI_IMX6SX,
.rxfifo = 128, .rxfifo = 128,
.txfifo = 512 .txfifo = 512,
.ahb_buf_size = 1024
}; };
#define FSL_QSPI_MAX_CHIP 4 #define FSL_QSPI_MAX_CHIP 4
...@@ -227,6 +232,7 @@ struct fsl_qspi { ...@@ -227,6 +232,7 @@ struct fsl_qspi {
u32 nor_num; u32 nor_num;
u32 clk_rate; u32 clk_rate;
unsigned int chip_base_addr; /* We may support two chips. */ unsigned int chip_base_addr; /* We may support two chips. */
bool has_second_chip;
}; };
static inline int is_vybrid_qspi(struct fsl_qspi *q) static inline int is_vybrid_qspi(struct fsl_qspi *q)
...@@ -583,7 +589,12 @@ static void fsl_qspi_init_abh_read(struct fsl_qspi *q) ...@@ -583,7 +589,12 @@ static void fsl_qspi_init_abh_read(struct fsl_qspi *q)
writel(QUADSPI_BUFXCR_INVALID_MSTRID, base + QUADSPI_BUF0CR); writel(QUADSPI_BUFXCR_INVALID_MSTRID, base + QUADSPI_BUF0CR);
writel(QUADSPI_BUFXCR_INVALID_MSTRID, base + QUADSPI_BUF1CR); writel(QUADSPI_BUFXCR_INVALID_MSTRID, base + QUADSPI_BUF1CR);
writel(QUADSPI_BUFXCR_INVALID_MSTRID, base + QUADSPI_BUF2CR); writel(QUADSPI_BUFXCR_INVALID_MSTRID, base + QUADSPI_BUF2CR);
writel(QUADSPI_BUF3CR_ALLMST, base + QUADSPI_BUF3CR); /*
* Set ADATSZ with the maximum AHB buffer size to improve the
* read performance.
*/
writel(QUADSPI_BUF3CR_ALLMST_MASK | ((q->devtype_data->ahb_buf_size / 8)
<< QUADSPI_BUF3CR_ADATSZ_SHIFT), base + QUADSPI_BUF3CR);
/* We only use the buffer3 */ /* We only use the buffer3 */
writel(0, base + QUADSPI_BUF0IND); writel(0, base + QUADSPI_BUF0IND);
...@@ -783,7 +794,6 @@ static int fsl_qspi_probe(struct platform_device *pdev) ...@@ -783,7 +794,6 @@ static int fsl_qspi_probe(struct platform_device *pdev)
struct spi_nor *nor; struct spi_nor *nor;
struct mtd_info *mtd; struct mtd_info *mtd;
int ret, i = 0; int ret, i = 0;
bool has_second_chip = false;
const struct of_device_id *of_id = const struct of_device_id *of_id =
of_match_device(fsl_qspi_dt_ids, &pdev->dev); of_match_device(fsl_qspi_dt_ids, &pdev->dev);
...@@ -798,37 +808,30 @@ static int fsl_qspi_probe(struct platform_device *pdev) ...@@ -798,37 +808,30 @@ static int fsl_qspi_probe(struct platform_device *pdev)
/* find the resources */ /* find the resources */
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "QuadSPI"); res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "QuadSPI");
q->iobase = devm_ioremap_resource(dev, res); q->iobase = devm_ioremap_resource(dev, res);
if (IS_ERR(q->iobase)) { if (IS_ERR(q->iobase))
ret = PTR_ERR(q->iobase); return PTR_ERR(q->iobase);
goto map_failed;
}
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"QuadSPI-memory"); "QuadSPI-memory");
q->ahb_base = devm_ioremap_resource(dev, res); q->ahb_base = devm_ioremap_resource(dev, res);
if (IS_ERR(q->ahb_base)) { if (IS_ERR(q->ahb_base))
ret = PTR_ERR(q->ahb_base); return PTR_ERR(q->ahb_base);
goto map_failed;
}
q->memmap_phy = res->start; q->memmap_phy = res->start;
/* find the clocks */ /* find the clocks */
q->clk_en = devm_clk_get(dev, "qspi_en"); q->clk_en = devm_clk_get(dev, "qspi_en");
if (IS_ERR(q->clk_en)) { if (IS_ERR(q->clk_en))
ret = PTR_ERR(q->clk_en); return PTR_ERR(q->clk_en);
goto map_failed;
}
q->clk = devm_clk_get(dev, "qspi"); q->clk = devm_clk_get(dev, "qspi");
if (IS_ERR(q->clk)) { if (IS_ERR(q->clk))
ret = PTR_ERR(q->clk); return PTR_ERR(q->clk);
goto map_failed;
}
ret = clk_prepare_enable(q->clk_en); ret = clk_prepare_enable(q->clk_en);
if (ret) { if (ret) {
dev_err(dev, "can not enable the qspi_en clock\n"); dev_err(dev, "can not enable the qspi_en clock\n");
goto map_failed; return ret;
} }
ret = clk_prepare_enable(q->clk); ret = clk_prepare_enable(q->clk);
...@@ -860,14 +863,14 @@ static int fsl_qspi_probe(struct platform_device *pdev) ...@@ -860,14 +863,14 @@ static int fsl_qspi_probe(struct platform_device *pdev)
goto irq_failed; goto irq_failed;
if (of_get_property(np, "fsl,qspi-has-second-chip", NULL)) if (of_get_property(np, "fsl,qspi-has-second-chip", NULL))
has_second_chip = true; q->has_second_chip = true;
/* iterate the subnodes. */ /* iterate the subnodes. */
for_each_available_child_of_node(dev->of_node, np) { for_each_available_child_of_node(dev->of_node, np) {
char modalias[40]; char modalias[40];
/* skip the holes */ /* skip the holes */
if (!has_second_chip) if (!q->has_second_chip)
i *= 2; i *= 2;
nor = &q->nor[i]; nor = &q->nor[i];
...@@ -890,24 +893,24 @@ static int fsl_qspi_probe(struct platform_device *pdev) ...@@ -890,24 +893,24 @@ static int fsl_qspi_probe(struct platform_device *pdev)
ret = of_modalias_node(np, modalias, sizeof(modalias)); ret = of_modalias_node(np, modalias, sizeof(modalias));
if (ret < 0) if (ret < 0)
goto map_failed; goto irq_failed;
ret = of_property_read_u32(np, "spi-max-frequency", ret = of_property_read_u32(np, "spi-max-frequency",
&q->clk_rate); &q->clk_rate);
if (ret < 0) if (ret < 0)
goto map_failed; goto irq_failed;
/* set the chip address for READID */ /* set the chip address for READID */
fsl_qspi_set_base_addr(q, nor); fsl_qspi_set_base_addr(q, nor);
ret = spi_nor_scan(nor, modalias, SPI_NOR_QUAD); ret = spi_nor_scan(nor, modalias, SPI_NOR_QUAD);
if (ret) if (ret)
goto map_failed; goto irq_failed;
ppdata.of_node = np; ppdata.of_node = np;
ret = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0); ret = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0);
if (ret) if (ret)
goto map_failed; goto irq_failed;
/* Set the correct NOR size now. */ /* Set the correct NOR size now. */
if (q->nor_size == 0) { if (q->nor_size == 0) {
...@@ -939,19 +942,19 @@ static int fsl_qspi_probe(struct platform_device *pdev) ...@@ -939,19 +942,19 @@ static int fsl_qspi_probe(struct platform_device *pdev)
clk_disable(q->clk); clk_disable(q->clk);
clk_disable(q->clk_en); clk_disable(q->clk_en);
dev_info(dev, "QuadSPI SPI NOR flash driver\n");
return 0; return 0;
last_init_failed: last_init_failed:
for (i = 0; i < q->nor_num; i++) for (i = 0; i < q->nor_num; i++) {
/* skip the holes */
if (!q->has_second_chip)
i *= 2;
mtd_device_unregister(&q->mtd[i]); mtd_device_unregister(&q->mtd[i]);
}
irq_failed: irq_failed:
clk_disable_unprepare(q->clk); clk_disable_unprepare(q->clk);
clk_failed: clk_failed:
clk_disable_unprepare(q->clk_en); clk_disable_unprepare(q->clk_en);
map_failed:
dev_err(dev, "Freescale QuadSPI probe failed\n");
return ret; return ret;
} }
...@@ -960,8 +963,12 @@ static int fsl_qspi_remove(struct platform_device *pdev) ...@@ -960,8 +963,12 @@ static int fsl_qspi_remove(struct platform_device *pdev)
struct fsl_qspi *q = platform_get_drvdata(pdev); struct fsl_qspi *q = platform_get_drvdata(pdev);
int i; int i;
for (i = 0; i < q->nor_num; i++) for (i = 0; i < q->nor_num; i++) {
/* skip the holes */
if (!q->has_second_chip)
i *= 2;
mtd_device_unregister(&q->mtd[i]); mtd_device_unregister(&q->mtd[i]);
}
/* disable the hardware */ /* disable the hardware */
writel(QUADSPI_MCR_MDIS_MASK, q->iobase + QUADSPI_MCR); writel(QUADSPI_MCR_MDIS_MASK, q->iobase + QUADSPI_MCR);
...@@ -972,6 +979,22 @@ static int fsl_qspi_remove(struct platform_device *pdev) ...@@ -972,6 +979,22 @@ static int fsl_qspi_remove(struct platform_device *pdev)
return 0; return 0;
} }
static int fsl_qspi_suspend(struct platform_device *pdev, pm_message_t state)
{
return 0;
}
static int fsl_qspi_resume(struct platform_device *pdev)
{
struct fsl_qspi *q = platform_get_drvdata(pdev);
fsl_qspi_nor_setup(q);
fsl_qspi_set_map_addr(q);
fsl_qspi_nor_setup_last(q);
return 0;
}
static struct platform_driver fsl_qspi_driver = { static struct platform_driver fsl_qspi_driver = {
.driver = { .driver = {
.name = "fsl-quadspi", .name = "fsl-quadspi",
...@@ -980,6 +1003,8 @@ static struct platform_driver fsl_qspi_driver = { ...@@ -980,6 +1003,8 @@ static struct platform_driver fsl_qspi_driver = {
}, },
.probe = fsl_qspi_probe, .probe = fsl_qspi_probe,
.remove = fsl_qspi_remove, .remove = fsl_qspi_remove,
.suspend = fsl_qspi_suspend,
.resume = fsl_qspi_resume,
}; };
module_platform_driver(fsl_qspi_driver); module_platform_driver(fsl_qspi_driver);
......
...@@ -538,6 +538,7 @@ static const struct spi_device_id spi_nor_ids[] = { ...@@ -538,6 +538,7 @@ static const struct spi_device_id spi_nor_ids[] = {
/* GigaDevice */ /* GigaDevice */
{ "gd25q32", INFO(0xc84016, 0, 64 * 1024, 64, SECT_4K) }, { "gd25q32", INFO(0xc84016, 0, 64 * 1024, 64, SECT_4K) },
{ "gd25q64", INFO(0xc84017, 0, 64 * 1024, 128, SECT_4K) }, { "gd25q64", INFO(0xc84017, 0, 64 * 1024, 128, SECT_4K) },
{ "gd25q128", INFO(0xc84018, 0, 64 * 1024, 256, SECT_4K) },
/* Intel/Numonyx -- xxxs33b */ /* Intel/Numonyx -- xxxs33b */
{ "160s33b", INFO(0x898911, 0, 64 * 1024, 32, 0) }, { "160s33b", INFO(0x898911, 0, 64 * 1024, 32, 0) },
...@@ -560,14 +561,14 @@ static const struct spi_device_id spi_nor_ids[] = { ...@@ -560,14 +561,14 @@ static const struct spi_device_id spi_nor_ids[] = {
{ "mx66l1g55g", INFO(0xc2261b, 0, 64 * 1024, 2048, SPI_NOR_QUAD_READ) }, { "mx66l1g55g", INFO(0xc2261b, 0, 64 * 1024, 2048, SPI_NOR_QUAD_READ) },
/* Micron */ /* Micron */
{ "n25q032", INFO(0x20ba16, 0, 64 * 1024, 64, 0) }, { "n25q032", INFO(0x20ba16, 0, 64 * 1024, 64, SPI_NOR_QUAD_READ) },
{ "n25q064", INFO(0x20ba17, 0, 64 * 1024, 128, 0) }, { "n25q064", INFO(0x20ba17, 0, 64 * 1024, 128, SPI_NOR_QUAD_READ) },
{ "n25q128a11", INFO(0x20bb18, 0, 64 * 1024, 256, 0) }, { "n25q128a11", INFO(0x20bb18, 0, 64 * 1024, 256, SPI_NOR_QUAD_READ) },
{ "n25q128a13", INFO(0x20ba18, 0, 64 * 1024, 256, 0) }, { "n25q128a13", INFO(0x20ba18, 0, 64 * 1024, 256, SPI_NOR_QUAD_READ) },
{ "n25q256a", INFO(0x20ba19, 0, 64 * 1024, 512, SECT_4K) }, { "n25q256a", INFO(0x20ba19, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_QUAD_READ) },
{ "n25q512a", INFO(0x20bb20, 0, 64 * 1024, 1024, SECT_4K) }, { "n25q512a", INFO(0x20bb20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) },
{ "n25q512ax3", INFO(0x20ba20, 0, 64 * 1024, 1024, USE_FSR) }, { "n25q512ax3", INFO(0x20ba20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) },
{ "n25q00", INFO(0x20ba21, 0, 64 * 1024, 2048, USE_FSR) }, { "n25q00", INFO(0x20ba21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) },
/* PMC */ /* PMC */
{ "pm25lv512", INFO(0, 0, 32 * 1024, 2, SECT_4K_PMC) }, { "pm25lv512", INFO(0, 0, 32 * 1024, 2, SECT_4K_PMC) },
...@@ -891,6 +892,45 @@ static int spansion_quad_enable(struct spi_nor *nor) ...@@ -891,6 +892,45 @@ static int spansion_quad_enable(struct spi_nor *nor)
return 0; return 0;
} }
static int micron_quad_enable(struct spi_nor *nor)
{
int ret;
u8 val;
ret = nor->read_reg(nor, SPINOR_OP_RD_EVCR, &val, 1);
if (ret < 0) {
dev_err(nor->dev, "error %d reading EVCR\n", ret);
return ret;
}
write_enable(nor);
/* set EVCR, enable quad I/O */
nor->cmd_buf[0] = val & ~EVCR_QUAD_EN_MICRON;
ret = nor->write_reg(nor, SPINOR_OP_WD_EVCR, nor->cmd_buf, 1, 0);
if (ret < 0) {
dev_err(nor->dev, "error while writing EVCR register\n");
return ret;
}
ret = spi_nor_wait_till_ready(nor);
if (ret)
return ret;
/* read EVCR and check it */
ret = nor->read_reg(nor, SPINOR_OP_RD_EVCR, &val, 1);
if (ret < 0) {
dev_err(nor->dev, "error %d reading EVCR\n", ret);
return ret;
}
if (val & EVCR_QUAD_EN_MICRON) {
dev_err(nor->dev, "Micron EVCR Quad bit not clear\n");
return -EINVAL;
}
return 0;
}
static int set_quad_mode(struct spi_nor *nor, struct flash_info *info) static int set_quad_mode(struct spi_nor *nor, struct flash_info *info)
{ {
int status; int status;
...@@ -903,6 +943,13 @@ static int set_quad_mode(struct spi_nor *nor, struct flash_info *info) ...@@ -903,6 +943,13 @@ static int set_quad_mode(struct spi_nor *nor, struct flash_info *info)
return -EINVAL; return -EINVAL;
} }
return status; return status;
case CFI_MFR_ST:
status = micron_quad_enable(nor);
if (status) {
dev_err(nor->dev, "Micron quad-read not enabled\n");
return -EINVAL;
}
return status;
default: default:
status = spansion_quad_enable(nor); status = spansion_quad_enable(nor);
if (status) { if (status) {
......
...@@ -84,11 +84,6 @@ static inline int pullbit(struct pushpull *pp) ...@@ -84,11 +84,6 @@ static inline int pullbit(struct pushpull *pp)
return bit; return bit;
} }
static inline int pulledbits(struct pushpull *pp)
{
return pp->ofs;
}
static void init_rubin(struct rubin_state *rs, int div, int *bits) static void init_rubin(struct rubin_state *rs, int div, int *bits)
{ {
......
...@@ -510,6 +510,10 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo ...@@ -510,6 +510,10 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
sumlen = c->sector_size - je32_to_cpu(sm->offset); sumlen = c->sector_size - je32_to_cpu(sm->offset);
sumptr = buf + buf_size - sumlen; sumptr = buf + buf_size - sumlen;
/* sm->offset maybe wrong but MAGIC maybe right */
if (sumlen > c->sector_size)
goto full_scan;
/* Now, make sure the summary itself is available */ /* Now, make sure the summary itself is available */
if (sumlen > buf_size) { if (sumlen > buf_size) {
/* Need to kmalloc for this. */ /* Need to kmalloc for this. */
...@@ -544,6 +548,7 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo ...@@ -544,6 +548,7 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
} }
} }
full_scan:
buf_ofs = jeb->offset; buf_ofs = jeb->offset;
if (!buf_size) { if (!buf_size) {
......
...@@ -227,6 +227,7 @@ struct mtd_info { ...@@ -227,6 +227,7 @@ struct mtd_info {
int (*_block_markbad) (struct mtd_info *mtd, loff_t ofs); int (*_block_markbad) (struct mtd_info *mtd, loff_t ofs);
int (*_suspend) (struct mtd_info *mtd); int (*_suspend) (struct mtd_info *mtd);
void (*_resume) (struct mtd_info *mtd); void (*_resume) (struct mtd_info *mtd);
void (*_reboot) (struct mtd_info *mtd);
/* /*
* If the driver is something smart, like UBI, it may need to maintain * If the driver is something smart, like UBI, it may need to maintain
* its own reference counting. The below functions are only for driver. * its own reference counting. The below functions are only for driver.
......
...@@ -56,6 +56,10 @@ ...@@ -56,6 +56,10 @@
/* Used for Spansion flashes only. */ /* Used for Spansion flashes only. */
#define SPINOR_OP_BRWR 0x17 /* Bank register write */ #define SPINOR_OP_BRWR 0x17 /* Bank register write */
/* Used for Micron flashes only. */
#define SPINOR_OP_RD_EVCR 0x65 /* Read EVCR register */
#define SPINOR_OP_WD_EVCR 0x61 /* Write EVCR register */
/* Status Register bits. */ /* Status Register bits. */
#define SR_WIP 1 /* Write in progress */ #define SR_WIP 1 /* Write in progress */
#define SR_WEL 2 /* Write enable latch */ #define SR_WEL 2 /* Write enable latch */
...@@ -67,6 +71,9 @@ ...@@ -67,6 +71,9 @@
#define SR_QUAD_EN_MX 0x40 /* Macronix Quad I/O */ #define SR_QUAD_EN_MX 0x40 /* Macronix Quad I/O */
/* Enhanced Volatile Configuration Register bits */
#define EVCR_QUAD_EN_MICRON 0x80 /* Micron Quad I/O */
/* Flag Status Register bits */ /* Flag Status Register bits */
#define FSR_READY 0x80 #define FSR_READY 0x80
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment