MTD updates for 3.20-rc1

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
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABAgAGBQJU4qf2AAoJEFySrpd9RFgtmo4P/i7KD+Xx12SgBbO+ZUCqBJhh
 X+gorTFr0YpItdn53i1PA8t+WnnXi4BHY07Y8fCj/JL+lxzS+00156o+hsYAFWIl
 TVvjlFHxUYS/rh7plshd5kbEZunlXBOpWw2Qr4dSoIIuOChaRDm9eGNHJ75D/ImO
 Cr+83cyYAm0F+fCHavZKHUq/iFmpDcrt3vbPx/Rv51W+rs/HqPPUcKxt4iaL5Thk
 R0pkcaZHfJ+pkXfjkgRu/L35RLRVxRkycYvLlVSOyE/KqnzE1RRgFeHUYUiPeCem
 xUEoI0OqIYlR5LuKTt/NsBtz1W0Kcm3AcQDC5QliKnbGCwm9nbHAjqfraaZ4Ks2Z
 4YL/2pJCyJFT6NPjsiwiYkJOzJHvN8tLCSIQrXCtAKAkMn8YMHvWIEC/bVsAkpVq
 V3ke3gmZ8bY7sXyY+Fi5WVW4uxKCwSVtGiAw3i74v3z5hZZ818hkbtPc1J0CANiE
 iqbkLMJ5pvWuVT9V2qGlDqK1MDqNXNLXZgBfT9tJx/q5Ptitva79Ift4teRwery2
 5pD3uSaA3vJE2AGHKPfIyTDFqdDDUDCOWJIGbIKsYoKXSAmuOxuWKEhRMWeZMmjo
 o0ZOrhJqBNp4ZqvAxUddUOsGhRKNa3btPoB+IhAQG4+OBwxknsAY39BzPcBjKrkG
 iEKHgRDXXMe8W2wCalLw
 =+nRk
 -----END PGP SIGNATURE-----

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()
  ...
This commit is contained in:
Linus Torvalds 2015-02-18 08:01:44 -08:00
commit 402521b8f7
35 changed files with 1385 additions and 214 deletions

View file

@ -1,7 +1,7 @@
Atmel NAND flash
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,
and hardware ECC controller if available.
If the hardware ECC is PMECC, it should contain address and size for

View file

@ -1,7 +1,7 @@
* Freescale Quad Serial Peripheral Interface(QuadSPI)
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,
the second contains the memory mapping address and length
- reg-names: Should contain the reg names "QuadSPI" and "QuadSPI-memory"

View file

@ -1,7 +1,7 @@
* Freescale General-Purpose Media Interface (GPMI)
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:
- compatible : should be "fsl,<chip>-gpmi-nand"

View file

@ -0,0 +1,47 @@
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>;
};
...
};

View file

@ -36,6 +36,11 @@ are defined:
- vendor-id : Contains the flash chip's vendor 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
address space. See partition.txt for more detail.

View file

@ -4092,6 +4092,12 @@ S: Maintained
F: include/linux/platform_data/video-imxfb.h
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
M: Pantelis Antoniou <pantelis.antoniou@gmail.com>
M: Vitaly Bordug <vbordug@ru.mvista.com>

View file

@ -27,8 +27,6 @@ struct jz_nand_platform_data {
struct nand_ecclayout *ecc_layout;
unsigned int busy_gpio;
unsigned char banks[JZ_NAND_NUM_BANKS];
void (*ident_callback)(struct platform_device *, struct nand_chip *,

View file

@ -140,10 +140,18 @@ static void qi_lb60_nand_ident(struct platform_device *pdev,
static struct jz_nand_platform_data qi_lb60_nand_pdata = {
.ident_callback = qi_lb60_nand_ident,
.busy_gpio = 94,
.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*/
#define KEY_QI_QI KEY_F13
@ -472,6 +480,7 @@ static int __init qi_lb60_init_platform_devices(void)
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_nand_gpio_table);
jz4740_serial_device_register();

View file

@ -15,6 +15,8 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <uapi/linux/magic.h>
/*
* 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
@ -39,7 +41,8 @@
#define ML_MAGIC1 0x39685a42
#define ML_MAGIC2 0x26594131
#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 {
uint32_t magic;
@ -50,7 +53,7 @@ struct trx_header {
uint32_t offset[3];
} __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)
{
part->name = name;
@ -58,6 +61,26 @@ static void bcm47xxpart_add_part(struct mtd_partition *part, char *name,
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,
struct mtd_partition **pparts,
struct mtd_part_parser_data *data)
@ -73,8 +96,12 @@ static int bcm47xxpart_parse(struct mtd_info *master,
int last_trx_part = -1;
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 */
parts = kzalloc(sizeof(struct mtd_partition) * BCM47XXPART_MAX_PARTS,
@ -186,8 +213,11 @@ static int bcm47xxpart_parse(struct mtd_info *master,
* we want to have jffs2 (overlay) in the same mtd.
*/
if (trx->offset[i]) {
const char *name;
name = bcm47xxpart_trx_data_part_name(master, offset + trx->offset[i]);
bcm47xxpart_add_part(&parts[curr_part++],
"rootfs",
name,
offset + trx->offset[i],
0);
i++;
@ -205,7 +235,8 @@ static int bcm47xxpart_parse(struct mtd_info *master,
}
/* 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",
offset, 0);
continue;

View file

@ -68,6 +68,7 @@ static struct mtd_info *map_ram_probe(struct map_info *map)
mtd->_get_unmapped_area = mapram_unmapped_area;
mtd->_read = mapram_read;
mtd->_write = mapram_write;
mtd->_panic_write = mapram_write;
mtd->_sync = mapram_nop;
mtd->flags = MTD_CAP_RAM;
mtd->writesize = 1;

View file

@ -11,6 +11,7 @@
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/of.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
@ -28,6 +29,15 @@ static struct mtd_chip_driver maprom_chipdrv = {
.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)
{
struct mtd_info *mtd;
@ -47,8 +57,9 @@ static struct mtd_info *map_rom_probe(struct map_info *map)
mtd->_sync = maprom_nop;
mtd->_erase = maprom_erase;
mtd->flags = MTD_CAP_ROM;
mtd->erasesize = map->size;
mtd->erasesize = default_erasesize(map);
mtd->writesize = 1;
mtd->writebufsize = 1;
__module_get(THIS_MODULE);
return mtd;

View file

@ -24,6 +24,7 @@
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/clk.h>
#include "serial_flash_cmds.h"
@ -262,6 +263,7 @@ struct stfsm {
struct mtd_info mtd;
struct mutex lock;
struct flash_info *info;
struct clk *clk;
uint32_t configuration;
uint32_t fifo_dir_delay;
@ -663,6 +665,23 @@ static struct stfsm_seq stfsm_seq_write_status = {
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)
{
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)
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,
const struct stfsm_seq *seq)
{
@ -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,
uint32_t size)
{
@ -1521,11 +1586,11 @@ static int stfsm_write(struct stfsm *fsm, const uint8_t *buf,
uint32_t size_lb;
uint32_t size_mop;
uint32_t tmp[4];
uint32_t i;
uint32_t page_buf[FLASH_PAGESIZE_32];
uint8_t *t = (uint8_t *)&tmp;
const uint8_t *p;
int ret;
int i;
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)
uint32_t emi_freq;
uint32_t clk_div;
/* TODO: Make this dynamic */
emi_freq = STFSM_DEFAULT_EMI_FREQ;
emi_freq = clk_get_rate(fsm->clk);
/*
* Calculate clk_div - values between 2 and 128
@ -1994,6 +2058,18 @@ static int stfsm_probe(struct platform_device *pdev)
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);
ret = stfsm_init(fsm);
@ -2058,6 +2134,28 @@ static int stfsm_remove(struct platform_device *pdev)
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[] = {
{ .compatible = "st,spi-fsm", },
{},
@ -2070,6 +2168,7 @@ static struct platform_driver stfsm_driver = {
.driver = {
.name = "st-spi-fsm",
.of_match_table = stfsm_match,
.pm = &stfsm_pm_ops,
},
};
module_platform_driver(stfsm_driver);

View file

@ -269,6 +269,16 @@ static int of_flash_probe(struct platform_device *dev)
info->list[i].mtd = obsolete_probe(dev,
&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;
err = -ENXIO;

View file

@ -45,8 +45,6 @@ struct mtdblk_dev {
enum { STATE_EMPTY, STATE_CLEAN, STATE_DIRTY } cache_state;
};
static DEFINE_MUTEX(mtdblks_lock);
/*
* Cache stuff...
*
@ -286,10 +284,8 @@ static int mtdblock_open(struct mtd_blktrans_dev *mbd)
pr_debug("mtdblock_open\n");
mutex_lock(&mtdblks_lock);
if (mtdblk->count) {
mtdblk->count++;
mutex_unlock(&mtdblks_lock);
return 0;
}
@ -302,8 +298,6 @@ static int mtdblock_open(struct mtd_blktrans_dev *mbd)
mtdblk->cache_data = NULL;
}
mutex_unlock(&mtdblks_lock);
pr_debug("ok\n");
return 0;
@ -315,8 +309,6 @@ static void mtdblock_release(struct mtd_blktrans_dev *mbd)
pr_debug("mtdblock_release\n");
mutex_lock(&mtdblks_lock);
mutex_lock(&mtdblk->cache_mutex);
write_cached_data(mtdblk);
mutex_unlock(&mtdblk->cache_mutex);
@ -331,8 +323,6 @@ static void mtdblock_release(struct mtd_blktrans_dev *mbd)
vfree(mtdblk->cache_data);
}
mutex_unlock(&mtdblks_lock);
pr_debug("ok\n");
}

View file

@ -311,7 +311,8 @@ concat_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops)
devops.len = subdev->size - to;
err = mtd_write_oob(subdev, to, &devops);
ops->retlen += devops.oobretlen;
ops->retlen += devops.retlen;
ops->oobretlen += devops.oobretlen;
if (err)
return err;

View file

@ -37,6 +37,7 @@
#include <linux/backing-dev.h>
#include <linux/gfp.h>
#include <linux/slab.h>
#include <linux/reboot.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
@ -356,6 +357,17 @@ unsigned mtd_mmap_capabilities(struct mtd_info *mtd)
EXPORT_SYMBOL_GPL(mtd_mmap_capabilities);
#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
* @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,
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;
}
EXPORT_SYMBOL_GPL(mtd_device_parse_register);
@ -558,6 +583,9 @@ int mtd_device_unregister(struct mtd_info *master)
{
int err;
if (master->_reboot)
unregister_reboot_notifier(&master->reboot_notifier);
err = del_mtd_partitions(master);
if (err)
return err;

View file

@ -421,7 +421,7 @@ config MTD_NAND_ORION
config MTD_NAND_FSL_ELBC
tristate "NAND support for Freescale eLBC controllers"
depends on PPC_OF
depends on PPC
select FSL_LBC
help
Various Freescale chips, including the 8313, include a NAND Flash
@ -524,4 +524,9 @@ config MTD_NAND_SUNXI
help
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

View file

@ -51,5 +51,6 @@ obj-$(CONFIG_MTD_NAND_GPMI_NAND) += gpmi-nand/
obj-$(CONFIG_MTD_NAND_XWAY) += xway_nand.o
obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH) += bcm47xxnflash/
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

View file

@ -183,7 +183,7 @@ static int ams_delta_init(struct platform_device *pdev)
return -ENXIO;
/* 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);
if (!ams_delta_mtd) {
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)
/* Get pointer to private data */
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 */
ams_delta_mtd->priv = this;

View file

@ -63,6 +63,10 @@ module_param(on_flash_bbt, int, 0);
#include "atmel_nand_ecc.h" /* Hardware ECC registers */
#include "atmel_nand_nfc.h" /* Nand Flash Controller definition */
struct atmel_nand_caps {
bool pmecc_correct_erase_page;
};
/* oob layout for large page size
* bad block info is on bytes 0 and 1
* the bytes have to be consecutives to avoid
@ -124,6 +128,7 @@ struct atmel_nand_host {
struct atmel_nfc *nfc;
struct atmel_nand_caps *caps;
bool has_pmecc;
u8 pmecc_corr_cap;
u16 pmecc_sector_size;
@ -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;
int i, err_nbr;
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++)
if (ecc[i] != 0xff)
@ -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,
nand_chip->ecc.bytes, err_nbr);
mtd->ecc_stats.corrected += err_nbr;
total_err += err_nbr;
max_bitflips = max_t(int, max_bitflips, err_nbr);
}
}
pmecc_stat >>= 1;
}
return total_err;
return max_bitflips;
}
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)
ecc_writel(host->ecc, CR, ATMEL_ECC_RST);
}
static const struct of_device_id atmel_nand_dt_ids[];
static int atmel_of_init_port(struct atmel_nand_host *host,
struct device_node *np)
{
@ -1483,6 +1494,9 @@ static int atmel_of_init_port(struct atmel_nand_host *host,
struct atmel_nand_data *board = &host->board;
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 (val >= 32) {
dev_err(host->dev, "invalid addr-offset %u\n", val);
@ -2288,8 +2302,17 @@ static int atmel_nand_remove(struct platform_device *pdev)
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[] = {
{ .compatible = "atmel,at91rm9200-nand" },
{ .compatible = "atmel,at91rm9200-nand", .data = &at91rm9200_caps },
{ .compatible = "atmel,sama5d4-nand", .data = &sama5d4_caps },
{ /* sentinel */ }
};

View file

@ -1041,7 +1041,7 @@ static void denali_setup_dma(struct denali_nand_info *denali, int op)
index_addr(denali, mode | ((addr >> 16) << 8), 0x2200);
/* 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 */
index_addr(denali, mode | 0x14000, 0x2400);
@ -1328,35 +1328,6 @@ static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col,
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 */
/* Initialization code to bring the device up to a known good state */
@ -1609,15 +1580,6 @@ int denali_init(struct denali_nand_info *denali)
denali->totalblks = denali->mtd.size >> denali->nand.phys_erase_shift;
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 */
denali->nand.ecc.size = ECC_SECTOR_SIZE * denali->devnum;
denali->nand.ecc.read_page = denali_read_page;

View file

@ -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-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).
*
* 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,
int page)
@ -2029,7 +2021,6 @@ static int gpmi_nand_probe(struct platform_device *pdev)
exit_nfc_init:
release_resources(this);
exit_acquire_resources:
dev_err(this->dev, "driver registration failed: %d\n", ret);
return ret;
}

View file

@ -0,0 +1,891 @@
/*
* Hisilicon NAND Flash controller driver
*
* Copyright © 2012-2014 HiSilicon Technologies Co., Ltd.
* http://www.hisilicon.com
*
* Author: Zhou Wang <wangzhou.bry@gmail.com>
* The initial developer of the original code is Zhiyong Cai
* <caizhiyong@huawei.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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/of.h>
#include <linux/of_mtd.h>
#include <linux/mtd/mtd.h>
#include <linux/sizes.h>
#include <linux/clk.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/mtd/nand.h>
#include <linux/dma-mapping.h>
#include <linux/platform_device.h>
#include <linux/mtd/partitions.h>
#define HINFC504_MAX_CHIP (4)
#define HINFC504_W_LATCH (5)
#define HINFC504_R_LATCH (7)
#define HINFC504_RW_LATCH (3)
#define HINFC504_NFC_TIMEOUT (2 * HZ)
#define HINFC504_NFC_PM_TIMEOUT (1 * HZ)
#define HINFC504_NFC_DMA_TIMEOUT (5 * HZ)
#define HINFC504_CHIP_DELAY (25)
#define HINFC504_REG_BASE_ADDRESS_LEN (0x100)
#define HINFC504_BUFFER_BASE_ADDRESS_LEN (2048 + 128)
#define HINFC504_ADDR_CYCLE_MASK 0x4
#define HINFC504_CON 0x00
#define HINFC504_CON_OP_MODE_NORMAL BIT(0)
#define HINFC504_CON_PAGEISZE_SHIFT (1)
#define HINFC504_CON_PAGESIZE_MASK (0x07)
#define HINFC504_CON_BUS_WIDTH BIT(4)
#define HINFC504_CON_READY_BUSY_SEL BIT(8)
#define HINFC504_CON_ECCTYPE_SHIFT (9)
#define HINFC504_CON_ECCTYPE_MASK (0x07)
#define HINFC504_PWIDTH 0x04
#define SET_HINFC504_PWIDTH(_w_lcnt, _r_lcnt, _rw_hcnt) \
((_w_lcnt) | (((_r_lcnt) & 0x0F) << 4) | (((_rw_hcnt) & 0x0F) << 8))
#define HINFC504_CMD 0x0C
#define HINFC504_ADDRL 0x10
#define HINFC504_ADDRH 0x14
#define HINFC504_DATA_NUM 0x18
#define HINFC504_OP 0x1C
#define HINFC504_OP_READ_DATA_EN BIT(1)
#define HINFC504_OP_WAIT_READY_EN BIT(2)
#define HINFC504_OP_CMD2_EN BIT(3)
#define HINFC504_OP_WRITE_DATA_EN BIT(4)
#define HINFC504_OP_ADDR_EN BIT(5)
#define HINFC504_OP_CMD1_EN BIT(6)
#define HINFC504_OP_NF_CS_SHIFT (7)
#define HINFC504_OP_NF_CS_MASK (3)
#define HINFC504_OP_ADDR_CYCLE_SHIFT (9)
#define HINFC504_OP_ADDR_CYCLE_MASK (7)
#define HINFC504_STATUS 0x20
#define HINFC504_READY BIT(0)
#define HINFC504_INTEN 0x24
#define HINFC504_INTEN_DMA BIT(9)
#define HINFC504_INTEN_UE BIT(6)
#define HINFC504_INTEN_CE BIT(5)
#define HINFC504_INTS 0x28
#define HINFC504_INTS_DMA BIT(9)
#define HINFC504_INTS_UE BIT(6)
#define HINFC504_INTS_CE BIT(5)
#define HINFC504_INTCLR 0x2C
#define HINFC504_INTCLR_DMA BIT(9)
#define HINFC504_INTCLR_UE BIT(6)
#define HINFC504_INTCLR_CE BIT(5)
#define HINFC504_ECC_STATUS 0x5C
#define HINFC504_ECC_16_BIT_SHIFT 12
#define HINFC504_DMA_CTRL 0x60
#define HINFC504_DMA_CTRL_DMA_START BIT(0)
#define HINFC504_DMA_CTRL_WE BIT(1)
#define HINFC504_DMA_CTRL_DATA_AREA_EN BIT(2)
#define HINFC504_DMA_CTRL_OOB_AREA_EN BIT(3)
#define HINFC504_DMA_CTRL_BURST4_EN BIT(4)
#define HINFC504_DMA_CTRL_BURST8_EN BIT(5)
#define HINFC504_DMA_CTRL_BURST16_EN BIT(6)
#define HINFC504_DMA_CTRL_ADDR_NUM_SHIFT (7)
#define HINFC504_DMA_CTRL_ADDR_NUM_MASK (1)
#define HINFC504_DMA_CTRL_CS_SHIFT (8)
#define HINFC504_DMA_CTRL_CS_MASK (0x03)
#define HINFC504_DMA_ADDR_DATA 0x64
#define HINFC504_DMA_ADDR_OOB 0x68
#define HINFC504_DMA_LEN 0x6C
#define HINFC504_DMA_LEN_OOB_SHIFT (16)
#define HINFC504_DMA_LEN_OOB_MASK (0xFFF)
#define HINFC504_DMA_PARA 0x70
#define HINFC504_DMA_PARA_DATA_RW_EN BIT(0)
#define HINFC504_DMA_PARA_OOB_RW_EN BIT(1)
#define HINFC504_DMA_PARA_DATA_EDC_EN BIT(2)
#define HINFC504_DMA_PARA_OOB_EDC_EN BIT(3)
#define HINFC504_DMA_PARA_DATA_ECC_EN BIT(4)
#define HINFC504_DMA_PARA_OOB_ECC_EN BIT(5)
#define HINFC_VERSION 0x74
#define HINFC504_LOG_READ_ADDR 0x7C
#define HINFC504_LOG_READ_LEN 0x80
#define HINFC504_NANDINFO_LEN 0x10
struct hinfc_host {
struct nand_chip chip;
struct mtd_info mtd;
struct device *dev;
void __iomem *iobase;
void __iomem *mmio;
struct completion cmd_complete;
unsigned int offset;
unsigned int command;
int chipselect;
unsigned int addr_cycle;
u32 addr_value[2];
u32 cache_addr_value[2];
char *buffer;
dma_addr_t dma_buffer;
dma_addr_t dma_oob;
int version;
unsigned int irq_status; /* interrupt status */
};
static inline unsigned int hinfc_read(struct hinfc_host *host, unsigned int reg)
{
return readl(host->iobase + reg);
}
static inline void hinfc_write(struct hinfc_host *host, unsigned int value,
unsigned int reg)
{
writel(value, host->iobase + reg);
}
static void wait_controller_finished(struct hinfc_host *host)
{
unsigned long timeout = jiffies + HINFC504_NFC_TIMEOUT;
int val;
while (time_before(jiffies, timeout)) {
val = hinfc_read(host, HINFC504_STATUS);
if (host->command == NAND_CMD_ERASE2) {
/* nfc is ready */
while (!(val & HINFC504_READY)) {
usleep_range(500, 1000);
val = hinfc_read(host, HINFC504_STATUS);
}
return;
}
if (val & HINFC504_READY)
return;
}
/* wait cmd timeout */
dev_err(host->dev, "Wait NAND controller exec cmd timeout.\n");
}
static void hisi_nfc_dma_transfer(struct hinfc_host *host, int todev)
{
struct mtd_info *mtd = &host->mtd;
struct nand_chip *chip = mtd->priv;
unsigned long val;
int ret;
hinfc_write(host, host->dma_buffer, HINFC504_DMA_ADDR_DATA);
hinfc_write(host, host->dma_oob, HINFC504_DMA_ADDR_OOB);
if (chip->ecc.mode == NAND_ECC_NONE) {
hinfc_write(host, ((mtd->oobsize & HINFC504_DMA_LEN_OOB_MASK)
<< HINFC504_DMA_LEN_OOB_SHIFT), HINFC504_DMA_LEN);
hinfc_write(host, HINFC504_DMA_PARA_DATA_RW_EN
| HINFC504_DMA_PARA_OOB_RW_EN, HINFC504_DMA_PARA);
} else {
if (host->command == NAND_CMD_READOOB)
hinfc_write(host, HINFC504_DMA_PARA_OOB_RW_EN
| HINFC504_DMA_PARA_OOB_EDC_EN
| HINFC504_DMA_PARA_OOB_ECC_EN, HINFC504_DMA_PARA);
else
hinfc_write(host, HINFC504_DMA_PARA_DATA_RW_EN
| HINFC504_DMA_PARA_OOB_RW_EN
| HINFC504_DMA_PARA_DATA_EDC_EN
| HINFC504_DMA_PARA_OOB_EDC_EN
| HINFC504_DMA_PARA_DATA_ECC_EN
| HINFC504_DMA_PARA_OOB_ECC_EN, HINFC504_DMA_PARA);
}
val = (HINFC504_DMA_CTRL_DMA_START | HINFC504_DMA_CTRL_BURST4_EN
| HINFC504_DMA_CTRL_BURST8_EN | HINFC504_DMA_CTRL_BURST16_EN
| HINFC504_DMA_CTRL_DATA_AREA_EN | HINFC504_DMA_CTRL_OOB_AREA_EN
| ((host->addr_cycle == 4 ? 1 : 0)
<< HINFC504_DMA_CTRL_ADDR_NUM_SHIFT)
| ((host->chipselect & HINFC504_DMA_CTRL_CS_MASK)
<< HINFC504_DMA_CTRL_CS_SHIFT));
if (todev)
val |= HINFC504_DMA_CTRL_WE;
init_completion(&host->cmd_complete);
hinfc_write(host, val, HINFC504_DMA_CTRL);
ret = wait_for_completion_timeout(&host->cmd_complete,
HINFC504_NFC_DMA_TIMEOUT);
if (!ret) {
dev_err(host->dev, "DMA operation(irq) timeout!\n");
/* sanity check */
val = hinfc_read(host, HINFC504_DMA_CTRL);
if (!(val & HINFC504_DMA_CTRL_DMA_START))
dev_err(host->dev, "DMA is already done but without irq ACK!\n");
else
dev_err(host->dev, "DMA is really timeout!\n");
}
}
static int hisi_nfc_send_cmd_pageprog(struct hinfc_host *host)
{
host->addr_value[0] &= 0xffff0000;
hinfc_write(host, host->addr_value[0], HINFC504_ADDRL);
hinfc_write(host, host->addr_value[1], HINFC504_ADDRH);
hinfc_write(host, NAND_CMD_PAGEPROG << 8 | NAND_CMD_SEQIN,
HINFC504_CMD);
hisi_nfc_dma_transfer(host, 1);
return 0;
}
static int hisi_nfc_send_cmd_readstart(struct hinfc_host *host)
{
struct mtd_info *mtd = &host->mtd;
if ((host->addr_value[0] == host->cache_addr_value[0]) &&
(host->addr_value[1] == host->cache_addr_value[1]))
return 0;
host->addr_value[0] &= 0xffff0000;
hinfc_write(host, host->addr_value[0], HINFC504_ADDRL);
hinfc_write(host, host->addr_value[1], HINFC504_ADDRH);
hinfc_write(host, NAND_CMD_READSTART << 8 | NAND_CMD_READ0,
HINFC504_CMD);
hinfc_write(host, 0, HINFC504_LOG_READ_ADDR);
hinfc_write(host, mtd->writesize + mtd->oobsize,
HINFC504_LOG_READ_LEN);
hisi_nfc_dma_transfer(host, 0);
host->cache_addr_value[0] = host->addr_value[0];
host->cache_addr_value[1] = host->addr_value[1];
return 0;
}
static int hisi_nfc_send_cmd_erase(struct hinfc_host *host)
{
hinfc_write(host, host->addr_value[0], HINFC504_ADDRL);
hinfc_write(host, (NAND_CMD_ERASE2 << 8) | NAND_CMD_ERASE1,
HINFC504_CMD);
hinfc_write(host, HINFC504_OP_WAIT_READY_EN
| HINFC504_OP_CMD2_EN
| HINFC504_OP_CMD1_EN
| HINFC504_OP_ADDR_EN
| ((host->chipselect & HINFC504_OP_NF_CS_MASK)
<< HINFC504_OP_NF_CS_SHIFT)
| ((host->addr_cycle & HINFC504_OP_ADDR_CYCLE_MASK)
<< HINFC504_OP_ADDR_CYCLE_SHIFT),
HINFC504_OP);
wait_controller_finished(host);
return 0;
}
static int hisi_nfc_send_cmd_readid(struct hinfc_host *host)
{
hinfc_write(host, HINFC504_NANDINFO_LEN, HINFC504_DATA_NUM);
hinfc_write(host, NAND_CMD_READID, HINFC504_CMD);
hinfc_write(host, 0, HINFC504_ADDRL);
hinfc_write(host, HINFC504_OP_CMD1_EN | HINFC504_OP_ADDR_EN
| HINFC504_OP_READ_DATA_EN
| ((host->chipselect & HINFC504_OP_NF_CS_MASK)
<< HINFC504_OP_NF_CS_SHIFT)
| 1 << HINFC504_OP_ADDR_CYCLE_SHIFT, HINFC504_OP);
wait_controller_finished(host);
return 0;
}
static int hisi_nfc_send_cmd_status(struct hinfc_host *host)
{
hinfc_write(host, HINFC504_NANDINFO_LEN, HINFC504_DATA_NUM);
hinfc_write(host, NAND_CMD_STATUS, HINFC504_CMD);
hinfc_write(host, HINFC504_OP_CMD1_EN
| HINFC504_OP_READ_DATA_EN
| ((host->chipselect & HINFC504_OP_NF_CS_MASK)
<< HINFC504_OP_NF_CS_SHIFT),
HINFC504_OP);
wait_controller_finished(host);
return 0;
}
static int hisi_nfc_send_cmd_reset(struct hinfc_host *host, int chipselect)
{
hinfc_write(host, NAND_CMD_RESET, HINFC504_CMD);
hinfc_write(host, HINFC504_OP_CMD1_EN
| ((chipselect & HINFC504_OP_NF_CS_MASK)
<< HINFC504_OP_NF_CS_SHIFT)
| HINFC504_OP_WAIT_READY_EN,
HINFC504_OP);
wait_controller_finished(host);
return 0;
}
static void hisi_nfc_select_chip(struct mtd_info *mtd, int chipselect)
{
struct nand_chip *chip = mtd->priv;
struct hinfc_host *host = chip->priv;
if (chipselect < 0)
return;
host->chipselect = chipselect;
}
static uint8_t hisi_nfc_read_byte(struct mtd_info *mtd)
{
struct nand_chip *chip = mtd->priv;
struct hinfc_host *host = chip->priv;
if (host->command == NAND_CMD_STATUS)
return *(uint8_t *)(host->mmio);
host->offset++;
if (host->command == NAND_CMD_READID)
return *(uint8_t *)(host->mmio + host->offset - 1);
return *(uint8_t *)(host->buffer + host->offset - 1);
}
static u16 hisi_nfc_read_word(struct mtd_info *mtd)
{
struct nand_chip *chip = mtd->priv;
struct hinfc_host *host = chip->priv;
host->offset += 2;
return *(u16 *)(host->buffer + host->offset - 2);
}
static void
hisi_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
{
struct nand_chip *chip = mtd->priv;
struct hinfc_host *host = chip->priv;
memcpy(host->buffer + host->offset, buf, len);
host->offset += len;
}
static void hisi_nfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
{
struct nand_chip *chip = mtd->priv;
struct hinfc_host *host = chip->priv;
memcpy(buf, host->buffer + host->offset, len);
host->offset += len;
}
static void set_addr(struct mtd_info *mtd, int column, int page_addr)
{
struct nand_chip *chip = mtd->priv;
struct hinfc_host *host = chip->priv;
unsigned int command = host->command;
host->addr_cycle = 0;
host->addr_value[0] = 0;
host->addr_value[1] = 0;
/* Serially input address */
if (column != -1) {
/* Adjust columns for 16 bit buswidth */
if (chip->options & NAND_BUSWIDTH_16 &&
!nand_opcode_8bits(command))
column >>= 1;
host->addr_value[0] = column & 0xffff;
host->addr_cycle = 2;
}
if (page_addr != -1) {
host->addr_value[0] |= (page_addr & 0xffff)
<< (host->addr_cycle * 8);
host->addr_cycle += 2;
/* One more address cycle for devices > 128MiB */
if (chip->chipsize > (128 << 20)) {
host->addr_cycle += 1;
if (host->command == NAND_CMD_ERASE1)
host->addr_value[0] |= ((page_addr >> 16) & 0xff) << 16;
else
host->addr_value[1] |= ((page_addr >> 16) & 0xff);
}
}
}
static void hisi_nfc_cmdfunc(struct mtd_info *mtd, unsigned command, int column,
int page_addr)
{
struct nand_chip *chip = mtd->priv;
struct hinfc_host *host = chip->priv;
int is_cache_invalid = 1;
unsigned int flag = 0;
host->command = command;
switch (command) {
case NAND_CMD_READ0:
case NAND_CMD_READOOB:
if (command == NAND_CMD_READ0)
host->offset = column;
else
host->offset = column + mtd->writesize;
is_cache_invalid = 0;
set_addr(mtd, column, page_addr);
hisi_nfc_send_cmd_readstart(host);
break;
case NAND_CMD_SEQIN:
host->offset = column;
set_addr(mtd, column, page_addr);
break;
case NAND_CMD_ERASE1:
set_addr(mtd, column, page_addr);
break;
case NAND_CMD_PAGEPROG:
hisi_nfc_send_cmd_pageprog(host);
break;
case NAND_CMD_ERASE2:
hisi_nfc_send_cmd_erase(host);
break;
case NAND_CMD_READID:
host->offset = column;
memset(host->mmio, 0, 0x10);
hisi_nfc_send_cmd_readid(host);
break;
case NAND_CMD_STATUS:
flag = hinfc_read(host, HINFC504_CON);
if (chip->ecc.mode == NAND_ECC_HW)
hinfc_write(host,
flag & ~(HINFC504_CON_ECCTYPE_MASK <<
HINFC504_CON_ECCTYPE_SHIFT), HINFC504_CON);
host->offset = 0;
memset(host->mmio, 0, 0x10);
hisi_nfc_send_cmd_status(host);
hinfc_write(host, flag, HINFC504_CON);
break;
case NAND_CMD_RESET:
hisi_nfc_send_cmd_reset(host, host->chipselect);
break;
default:
dev_err(host->dev, "Error: unsupported cmd(cmd=%x, col=%x, page=%x)\n",
command, column, page_addr);
}
if (is_cache_invalid) {
host->cache_addr_value[0] = ~0;
host->cache_addr_value[1] = ~0;
}
}
static irqreturn_t hinfc_irq_handle(int irq, void *devid)
{
struct hinfc_host *host = devid;
unsigned int flag;
flag = hinfc_read(host, HINFC504_INTS);
/* store interrupts state */
host->irq_status |= flag;
if (flag & HINFC504_INTS_DMA) {
hinfc_write(host, HINFC504_INTCLR_DMA, HINFC504_INTCLR);
complete(&host->cmd_complete);
} else if (flag & HINFC504_INTS_CE) {
hinfc_write(host, HINFC504_INTCLR_CE, HINFC504_INTCLR);
} else if (flag & HINFC504_INTS_UE) {
hinfc_write(host, HINFC504_INTCLR_UE, HINFC504_INTCLR);
}
return IRQ_HANDLED;
}
static int hisi_nand_read_page_hwecc(struct mtd_info *mtd,
struct nand_chip *chip, uint8_t *buf, int oob_required, int page)
{
struct hinfc_host *host = chip->priv;
int max_bitflips = 0, stat = 0, stat_max = 0, status_ecc;
int stat_1, stat_2;
chip->read_buf(mtd, buf, mtd->writesize);
chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
/* errors which can not be corrected by ECC */
if (host->irq_status & HINFC504_INTS_UE) {
mtd->ecc_stats.failed++;
} else if (host->irq_status & HINFC504_INTS_CE) {
/* TODO: need add other ECC modes! */
switch (chip->ecc.strength) {
case 16:
status_ecc = hinfc_read(host, HINFC504_ECC_STATUS) >>
HINFC504_ECC_16_BIT_SHIFT & 0x0fff;
stat_2 = status_ecc & 0x3f;
stat_1 = status_ecc >> 6 & 0x3f;
stat = stat_1 + stat_2;
stat_max = max_t(int, stat_1, stat_2);
}
mtd->ecc_stats.corrected += stat;
max_bitflips = max_t(int, max_bitflips, stat_max);
}
host->irq_status = 0;
return max_bitflips;
}
static int hisi_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
int page)
{
struct hinfc_host *host = chip->priv;
chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
if (host->irq_status & HINFC504_INTS_UE) {
host->irq_status = 0;
return -EBADMSG;
}
host->irq_status = 0;
return 0;
}
static int hisi_nand_write_page_hwecc(struct mtd_info *mtd,
struct nand_chip *chip, const uint8_t *buf, int oob_required)
{
chip->write_buf(mtd, buf, mtd->writesize);
if (oob_required)
chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
return 0;
}
static void hisi_nfc_host_init(struct hinfc_host *host)
{
struct nand_chip *chip = &host->chip;
unsigned int flag = 0;
host->version = hinfc_read(host, HINFC_VERSION);
host->addr_cycle = 0;
host->addr_value[0] = 0;
host->addr_value[1] = 0;
host->cache_addr_value[0] = ~0;
host->cache_addr_value[1] = ~0;
host->chipselect = 0;
/* default page size: 2K, ecc_none. need modify */
flag = HINFC504_CON_OP_MODE_NORMAL | HINFC504_CON_READY_BUSY_SEL
| ((0x001 & HINFC504_CON_PAGESIZE_MASK)
<< HINFC504_CON_PAGEISZE_SHIFT)
| ((0x0 & HINFC504_CON_ECCTYPE_MASK)
<< HINFC504_CON_ECCTYPE_SHIFT)
| ((chip->options & NAND_BUSWIDTH_16) ?
HINFC504_CON_BUS_WIDTH : 0);
hinfc_write(host, flag, HINFC504_CON);
memset(host->mmio, 0xff, HINFC504_BUFFER_BASE_ADDRESS_LEN);
hinfc_write(host, SET_HINFC504_PWIDTH(HINFC504_W_LATCH,
HINFC504_R_LATCH, HINFC504_RW_LATCH), HINFC504_PWIDTH);
/* enable DMA irq */
hinfc_write(host, HINFC504_INTEN_DMA, HINFC504_INTEN);
}
static struct nand_ecclayout nand_ecc_2K_16bits = {
.oobavail = 6,
.oobfree = { {2, 6} },
};
static int hisi_nfc_ecc_probe(struct hinfc_host *host)
{
unsigned int flag;
int size, strength, ecc_bits;
struct device *dev = host->dev;
struct nand_chip *chip = &host->chip;
struct mtd_info *mtd = &host->mtd;
struct device_node *np = host->dev->of_node;
size = of_get_nand_ecc_step_size(np);
strength = of_get_nand_ecc_strength(np);
if (size != 1024) {
dev_err(dev, "error ecc size: %d\n", size);
return -EINVAL;
}
if ((size == 1024) && ((strength != 8) && (strength != 16) &&
(strength != 24) && (strength != 40))) {
dev_err(dev, "ecc size and strength do not match\n");
return -EINVAL;
}
chip->ecc.size = size;
chip->ecc.strength = strength;
chip->ecc.read_page = hisi_nand_read_page_hwecc;
chip->ecc.read_oob = hisi_nand_read_oob;
chip->ecc.write_page = hisi_nand_write_page_hwecc;
switch (chip->ecc.strength) {
case 16:
ecc_bits = 6;
if (mtd->writesize == 2048)
chip->ecc.layout = &nand_ecc_2K_16bits;
/* TODO: add more page size support */
break;
/* TODO: add more ecc strength support */
default:
dev_err(dev, "not support strength: %d\n", chip->ecc.strength);
return -EINVAL;
}
flag = hinfc_read(host, HINFC504_CON);
/* add ecc type configure */
flag |= ((ecc_bits & HINFC504_CON_ECCTYPE_MASK)
<< HINFC504_CON_ECCTYPE_SHIFT);
hinfc_write(host, flag, HINFC504_CON);
/* enable ecc irq */
flag = hinfc_read(host, HINFC504_INTEN) & 0xfff;
hinfc_write(host, flag | HINFC504_INTEN_UE | HINFC504_INTEN_CE,
HINFC504_INTEN);
return 0;
}
static int hisi_nfc_probe(struct platform_device *pdev)
{
int ret = 0, irq, buswidth, flag, max_chips = HINFC504_MAX_CHIP;
struct device *dev = &pdev->dev;
struct hinfc_host *host;
struct nand_chip *chip;
struct mtd_info *mtd;
struct resource *res;
struct device_node *np = dev->of_node;
struct mtd_part_parser_data ppdata;
host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL);
if (!host)
return -ENOMEM;
host->dev = dev;
platform_set_drvdata(pdev, host);
chip = &host->chip;
mtd = &host->mtd;
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(dev, "no IRQ resource defined\n");
ret = -ENXIO;
goto err_res;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
host->iobase = devm_ioremap_resource(dev, res);
if (IS_ERR(host->iobase)) {
ret = PTR_ERR(host->iobase);
goto err_res;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
host->mmio = devm_ioremap_resource(dev, res);
if (IS_ERR(host->mmio)) {
ret = PTR_ERR(host->mmio);
dev_err(dev, "devm_ioremap_resource[1] fail\n");
goto err_res;
}
mtd->priv = chip;
mtd->owner = THIS_MODULE;
mtd->name = "hisi_nand";
mtd->dev.parent = &pdev->dev;
chip->priv = host;
chip->cmdfunc = hisi_nfc_cmdfunc;
chip->select_chip = hisi_nfc_select_chip;
chip->read_byte = hisi_nfc_read_byte;
chip->read_word = hisi_nfc_read_word;
chip->write_buf = hisi_nfc_write_buf;
chip->read_buf = hisi_nfc_read_buf;
chip->chip_delay = HINFC504_CHIP_DELAY;
chip->ecc.mode = of_get_nand_ecc_mode(np);
buswidth = of_get_nand_bus_width(np);
if (buswidth == 16)
chip->options |= NAND_BUSWIDTH_16;
hisi_nfc_host_init(host);
ret = devm_request_irq(dev, irq, hinfc_irq_handle, IRQF_DISABLED,
"nandc", host);
if (ret) {
dev_err(dev, "failed to request IRQ\n");
goto err_res;
}
ret = nand_scan_ident(mtd, max_chips, NULL);
if (ret) {
ret = -ENODEV;
goto err_res;
}
host->buffer = dmam_alloc_coherent(dev, mtd->writesize + mtd->oobsize,
&host->dma_buffer, GFP_KERNEL);
if (!host->buffer) {
ret = -ENOMEM;
goto err_res;
}
host->dma_oob = host->dma_buffer + mtd->writesize;
memset(host->buffer, 0xff, mtd->writesize + mtd->oobsize);
flag = hinfc_read(host, HINFC504_CON);
flag &= ~(HINFC504_CON_PAGESIZE_MASK << HINFC504_CON_PAGEISZE_SHIFT);
switch (mtd->writesize) {
case 2048:
flag |= (0x001 << HINFC504_CON_PAGEISZE_SHIFT); break;
/*
* TODO: add more pagesize support,
* default pagesize has been set in hisi_nfc_host_init
*/
default:
dev_err(dev, "NON-2KB page size nand flash\n");
ret = -EINVAL;
goto err_res;
}
hinfc_write(host, flag, HINFC504_CON);
if (chip->ecc.mode == NAND_ECC_HW)
hisi_nfc_ecc_probe(host);
ret = nand_scan_tail(mtd);
if (ret) {
dev_err(dev, "nand_scan_tail failed: %d\n", ret);
goto err_res;
}
ppdata.of_node = np;
ret = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0);
if (ret) {
dev_err(dev, "Err MTD partition=%d\n", ret);
goto err_mtd;
}
return 0;
err_mtd:
nand_release(mtd);
err_res:
return ret;
}
static int hisi_nfc_remove(struct platform_device *pdev)
{
struct hinfc_host *host = platform_get_drvdata(pdev);
struct mtd_info *mtd = &host->mtd;
nand_release(mtd);
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int hisi_nfc_suspend(struct device *dev)
{
struct hinfc_host *host = dev_get_drvdata(dev);
unsigned long timeout = jiffies + HINFC504_NFC_PM_TIMEOUT;
while (time_before(jiffies, timeout)) {
if (((hinfc_read(host, HINFC504_STATUS) & 0x1) == 0x0) &&
(hinfc_read(host, HINFC504_DMA_CTRL) &
HINFC504_DMA_CTRL_DMA_START)) {
cond_resched();
return 0;
}
}
dev_err(host->dev, "nand controller suspend timeout.\n");
return -EAGAIN;
}
static int hisi_nfc_resume(struct device *dev)
{
int cs;
struct hinfc_host *host = dev_get_drvdata(dev);
struct nand_chip *chip = &host->chip;
for (cs = 0; cs < chip->numchips; cs++)
hisi_nfc_send_cmd_reset(host, cs);
hinfc_write(host, SET_HINFC504_PWIDTH(HINFC504_W_LATCH,
HINFC504_R_LATCH, HINFC504_RW_LATCH), HINFC504_PWIDTH);
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(hisi_nfc_pm_ops, hisi_nfc_suspend, hisi_nfc_resume);
static const struct of_device_id nfc_id_table[] = {
{ .compatible = "hisilicon,504-nfc" },
{}
};
MODULE_DEVICE_TABLE(of, nfc_id_table);
static struct platform_driver hisi_nfc_driver = {
.driver = {
.name = "hisi_nand",
.of_match_table = nfc_id_table,
.pm = &hisi_nfc_pm_ops,
},
.probe = hisi_nfc_probe,
.remove = hisi_nfc_remove,
};
module_platform_driver(hisi_nfc_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Zhou Wang");
MODULE_AUTHOR("Zhiyong Cai");
MODULE_DESCRIPTION("Hisilicon Nand Flash Controller Driver");

View file

@ -69,7 +69,7 @@ struct jz_nand {
int selected_bank;
struct jz_nand_platform_data *pdata;
struct gpio_desc *busy_gpio;
bool is_reading;
};
@ -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)
{
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)
@ -423,14 +423,12 @@ static int jz_nand_probe(struct platform_device *pdev)
if (ret)
goto err_free;
if (pdata && gpio_is_valid(pdata->busy_gpio)) {
ret = gpio_request(pdata->busy_gpio, "NAND busy pin");
if (ret) {
dev_err(&pdev->dev,
"Failed to request busy gpio %d: %d\n",
pdata->busy_gpio, ret);
goto err_iounmap_mmio;
}
nand->busy_gpio = devm_gpiod_get_optional(&pdev->dev, "busy", GPIOD_IN);
if (IS_ERR(nand->busy_gpio)) {
ret = PTR_ERR(nand->busy_gpio);
dev_err(&pdev->dev, "Failed to request busy gpio %d\n",
ret);
goto err_iounmap_mmio;
}
mtd = &nand->mtd;
@ -454,10 +452,9 @@ static int jz_nand_probe(struct platform_device *pdev)
chip->cmd_ctrl = jz_nand_cmd_ctrl;
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;
nand->pdata = pdata;
platform_set_drvdata(pdev, nand);
/* 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)
}
if (chipnr == 0) {
dev_err(&pdev->dev, "No NAND chips found\n");
goto err_gpio_busy;
goto err_iounmap_mmio;
}
if (pdata && pdata->ident_callback) {
@ -533,9 +530,6 @@ static int jz_nand_probe(struct platform_device *pdev)
nand->bank_base[bank - 1]);
}
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:
jz_nand_iounmap_resource(nand->mem, nand->base);
err_free:
@ -546,7 +540,6 @@ static int jz_nand_probe(struct platform_device *pdev)
static int jz_nand_remove(struct platform_device *pdev)
{
struct jz_nand *nand = platform_get_drvdata(pdev);
struct jz_nand_platform_data *pdata = dev_get_platdata(&pdev->dev);
size_t i;
nand_release(&nand->mtd);
@ -562,8 +555,6 @@ static int jz_nand_remove(struct platform_device *pdev)
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);

View file

@ -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
* @mtd: MTD device structure
*
@ -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,
int page)
{
uint8_t *buf = chip->oob_poi;
int length = mtd->oobsize;
int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad;
int eccsize = chip->ecc.size;
uint8_t *bufpoi = buf;
uint8_t *bufpoi = chip->oob_poi;
int i, toread, sndrnd = 0, pos;
chip->cmdfunc(mtd, NAND_CMD_READ0, chip->ecc.size, page);
@ -2944,6 +2942,16 @@ static void nand_resume(struct mtd_info *mtd)
__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 */
static void nand_set_defaults(struct nand_chip *chip, int busw)
{
@ -4028,22 +4036,24 @@ int nand_scan_tail(struct mtd_info *mtd)
ecc->read_oob = nand_read_oob_std;
ecc->write_oob = nand_write_oob_std;
/*
* Board driver should supply ecc.size and ecc.bytes values to
* select how many bits are correctable; see nand_bch_init()
* for details. Otherwise, default to 4 bits for large page
* devices.
* Board driver should supply ecc.size and ecc.strength values
* to select how many bits are correctable. Otherwise, default
* to 4 bits for large page devices.
*/
if (!ecc->size && (mtd->oobsize >= 64)) {
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->layout);
if (!ecc->priv) {
pr_warn("BCH ECC initialization failed!\n");
BUG();
}
ecc->strength = ecc->bytes * 8 / fls(8 * ecc->size);
break;
case NAND_ECC_NONE:
@ -4146,6 +4156,7 @@ int nand_scan_tail(struct mtd_info *mtd)
mtd->_unlock = NULL;
mtd->_suspend = nand_suspend;
mtd->_resume = nand_resume;
mtd->_reboot = nand_shutdown;
mtd->_block_isreserved = nand_block_isreserved;
mtd->_block_isbad = nand_block_isbad;
mtd->_block_markbad = nand_block_markbad;
@ -4161,7 +4172,7 @@ int nand_scan_tail(struct mtd_info *mtd)
* properly set.
*/
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 */
if (chip->options & NAND_SKIP_BBTSCAN)

View file

@ -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_ID 0x00002000 /* waiting for ID bytes 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 */
/* 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 "
#define OPT_ANY 0xFFFFFFFF /* any chip supports this operation */
#define OPT_PAGE512 0x00000002 /* 512-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_PAGE4096 0x00000080 /* 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)
return "STATE_DATAOUT_ID";
case STATE_DATAOUT_STATUS:
return "STATE_DATAOUT_STATUS";
case STATE_DATAOUT_STATUS_M:
return "STATE_DATAOUT_STATUS_M";
case STATE_READY:
return "STATE_READY";
case STATE_UNKNOWN:
@ -1865,7 +1861,6 @@ static void switch_state(struct nandsim *ns)
break;
case STATE_DATAOUT_STATUS:
case STATE_DATAOUT_STATUS_M:
ns->regs.count = ns->regs.num = 0;
break;
@ -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
|| NS_STATE(ns->state) == STATE_DATAOUT_STATUS_M
|| NS_STATE(ns->state) == STATE_DATAOUT) {
int row = ns->regs.row;
@ -2343,6 +2337,7 @@ static int __init ns_init_module(void)
}
chip->ecc.mode = NAND_ECC_SOFT_BCH;
chip->ecc.size = 512;
chip->ecc.strength = bch;
chip->ecc.bytes = eccbytes;
NS_INFO("using %u-bit/%u bytes BCH ECC\n", bch, chip->ecc.size);
}

View file

@ -1048,10 +1048,9 @@ static int omap_dev_ready(struct mtd_info *mtd)
* @mtd: MTD device structure
* @mode: Read/Write mode
*
* When using BCH, sector size is hardcoded to 512 bytes.
* Using wrapping mode 6 both for reading and writing if ELM module not uses
* for error correction.
* On writing,
* When using BCH with SW correction (i.e. no ELM), sector size is set
* to 512 bytes and we use BCH_WRAPMODE_6 wrapping mode
* for both reading and writing with:
* eccsize0 = 0 (no additional protected byte 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)
case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW:
bch_type = 0;
nsectors = 1;
if (mode == NAND_ECC_READ) {
wr_mode = BCH_WRAPMODE_6;
ecc_size0 = BCH_ECC_SIZE0;
ecc_size1 = BCH_ECC_SIZE1;
} else {
wr_mode = BCH_WRAPMODE_6;
ecc_size0 = BCH_ECC_SIZE0;
ecc_size1 = BCH_ECC_SIZE1;
}
wr_mode = BCH_WRAPMODE_6;
ecc_size0 = BCH_ECC_SIZE0;
ecc_size1 = BCH_ECC_SIZE1;
break;
case OMAP_ECC_BCH4_CODE_HW:
bch_type = 0;
@ -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:
bch_type = 1;
nsectors = 1;
if (mode == NAND_ECC_READ) {
wr_mode = BCH_WRAPMODE_6;
ecc_size0 = BCH_ECC_SIZE0;
ecc_size1 = BCH_ECC_SIZE1;
} else {
wr_mode = BCH_WRAPMODE_6;
ecc_size0 = BCH_ECC_SIZE0;
ecc_size1 = BCH_ECC_SIZE1;
}
wr_mode = BCH_WRAPMODE_6;
ecc_size0 = BCH_ECC_SIZE0;
ecc_size1 = BCH_ECC_SIZE1;
break;
case OMAP_ECC_BCH8_CODE_HW:
bch_type = 1;

View file

@ -1110,8 +1110,6 @@ static int sunxi_nand_ecc_init(struct mtd_info *mtd, struct nand_ecc_ctrl *ecc,
switch (ecc->mode) {
case NAND_ECC_SOFT_BCH:
ecc->bytes = DIV_ROUND_UP(ecc->strength * fls(8 * ecc->size),
8);
break;
case NAND_ECC_HW:
ret = sunxi_nand_hw_ecc_ctrl_init(mtd, ecc, np);

View file

@ -89,9 +89,10 @@ static int find_boot_record(struct NFTLrecord *nftl)
}
/* 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,
(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",
block * nftl->EraseSize, nftl->mbd.mtd->index, ret);
continue;
@ -109,8 +110,9 @@ static int find_boot_record(struct NFTLrecord *nftl)
}
/* Finally reread to check ECC */
if ((ret = mtd->read(mtd, block * nftl->EraseSize, SECTORSIZE,
&retlen, buf) < 0)) {
ret = mtd->read(mtd, block * nftl->EraseSize, SECTORSIZE,
&retlen, buf);
if (ret < 0) {
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);
continue;
@ -228,9 +230,11 @@ device is already correct.
The new DiskOnChip driver already scanned the bad block table. Just query it.
if ((i & (SECTORSIZE - 1)) == 0) {
/* read one sector for every SECTORSIZE of blocks */
if ((ret = mtd->read(nftl->mbd.mtd, block * nftl->EraseSize +
i + SECTORSIZE, SECTORSIZE, &retlen,
buf)) < 0) {
ret = mtd->read(nftl->mbd.mtd,
block * nftl->EraseSize + i +
SECTORSIZE, SECTORSIZE,
&retlen, buf);
if (ret < 0) {
printk(KERN_NOTICE "Read of bad sector table failed (err %d)\n",
ret);
kfree(nftl->ReplUnitTable);

View file

@ -57,7 +57,9 @@
#define QUADSPI_BUF3CR 0x1c
#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_PAR_EN_SHIFT 16
@ -198,18 +200,21 @@ struct fsl_qspi_devtype_data {
enum fsl_qspi_devtype devtype;
int rxfifo;
int txfifo;
int ahb_buf_size;
};
static struct fsl_qspi_devtype_data vybrid_data = {
.devtype = FSL_QUADSPI_VYBRID,
.rxfifo = 128,
.txfifo = 64
.txfifo = 64,
.ahb_buf_size = 1024
};
static struct fsl_qspi_devtype_data imx6sx_data = {
.devtype = FSL_QUADSPI_IMX6SX,
.rxfifo = 128,
.txfifo = 512
.txfifo = 512,
.ahb_buf_size = 1024
};
#define FSL_QSPI_MAX_CHIP 4
@ -227,6 +232,7 @@ struct fsl_qspi {
u32 nor_num;
u32 clk_rate;
unsigned int chip_base_addr; /* We may support two chips. */
bool has_second_chip;
};
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)
writel(QUADSPI_BUFXCR_INVALID_MSTRID, base + QUADSPI_BUF0CR);
writel(QUADSPI_BUFXCR_INVALID_MSTRID, base + QUADSPI_BUF1CR);
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 */
writel(0, base + QUADSPI_BUF0IND);
@ -783,7 +794,6 @@ static int fsl_qspi_probe(struct platform_device *pdev)
struct spi_nor *nor;
struct mtd_info *mtd;
int ret, i = 0;
bool has_second_chip = false;
const struct of_device_id *of_id =
of_match_device(fsl_qspi_dt_ids, &pdev->dev);
@ -798,37 +808,30 @@ static int fsl_qspi_probe(struct platform_device *pdev)
/* find the resources */
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "QuadSPI");
q->iobase = devm_ioremap_resource(dev, res);
if (IS_ERR(q->iobase)) {
ret = PTR_ERR(q->iobase);
goto map_failed;
}
if (IS_ERR(q->iobase))
return PTR_ERR(q->iobase);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"QuadSPI-memory");
q->ahb_base = devm_ioremap_resource(dev, res);
if (IS_ERR(q->ahb_base)) {
ret = PTR_ERR(q->ahb_base);
goto map_failed;
}
if (IS_ERR(q->ahb_base))
return PTR_ERR(q->ahb_base);
q->memmap_phy = res->start;
/* find the clocks */
q->clk_en = devm_clk_get(dev, "qspi_en");
if (IS_ERR(q->clk_en)) {
ret = PTR_ERR(q->clk_en);
goto map_failed;
}
if (IS_ERR(q->clk_en))
return PTR_ERR(q->clk_en);
q->clk = devm_clk_get(dev, "qspi");
if (IS_ERR(q->clk)) {
ret = PTR_ERR(q->clk);
goto map_failed;
}
if (IS_ERR(q->clk))
return PTR_ERR(q->clk);
ret = clk_prepare_enable(q->clk_en);
if (ret) {
dev_err(dev, "can not enable the qspi_en clock\n");
goto map_failed;
return ret;
}
ret = clk_prepare_enable(q->clk);
@ -860,14 +863,14 @@ static int fsl_qspi_probe(struct platform_device *pdev)
goto irq_failed;
if (of_get_property(np, "fsl,qspi-has-second-chip", NULL))
has_second_chip = true;
q->has_second_chip = true;
/* iterate the subnodes. */
for_each_available_child_of_node(dev->of_node, np) {
char modalias[40];
/* skip the holes */
if (!has_second_chip)
if (!q->has_second_chip)
i *= 2;
nor = &q->nor[i];
@ -890,24 +893,24 @@ static int fsl_qspi_probe(struct platform_device *pdev)
ret = of_modalias_node(np, modalias, sizeof(modalias));
if (ret < 0)
goto map_failed;
goto irq_failed;
ret = of_property_read_u32(np, "spi-max-frequency",
&q->clk_rate);
if (ret < 0)
goto map_failed;
goto irq_failed;
/* set the chip address for READID */
fsl_qspi_set_base_addr(q, nor);
ret = spi_nor_scan(nor, modalias, SPI_NOR_QUAD);
if (ret)
goto map_failed;
goto irq_failed;
ppdata.of_node = np;
ret = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0);
if (ret)
goto map_failed;
goto irq_failed;
/* Set the correct NOR size now. */
if (q->nor_size == 0) {
@ -939,19 +942,19 @@ static int fsl_qspi_probe(struct platform_device *pdev)
clk_disable(q->clk);
clk_disable(q->clk_en);
dev_info(dev, "QuadSPI SPI NOR flash driver\n");
return 0;
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]);
}
irq_failed:
clk_disable_unprepare(q->clk);
clk_failed:
clk_disable_unprepare(q->clk_en);
map_failed:
dev_err(dev, "Freescale QuadSPI probe failed\n");
return ret;
}
@ -960,8 +963,12 @@ static int fsl_qspi_remove(struct platform_device *pdev)
struct fsl_qspi *q = platform_get_drvdata(pdev);
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]);
}
/* disable the hardware */
writel(QUADSPI_MCR_MDIS_MASK, q->iobase + QUADSPI_MCR);
@ -972,6 +979,22 @@ static int fsl_qspi_remove(struct platform_device *pdev)
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 = {
.driver = {
.name = "fsl-quadspi",
@ -980,6 +1003,8 @@ static struct platform_driver fsl_qspi_driver = {
},
.probe = fsl_qspi_probe,
.remove = fsl_qspi_remove,
.suspend = fsl_qspi_suspend,
.resume = fsl_qspi_resume,
};
module_platform_driver(fsl_qspi_driver);

View file

@ -538,6 +538,7 @@ static const struct spi_device_id spi_nor_ids[] = {
/* GigaDevice */
{ "gd25q32", INFO(0xc84016, 0, 64 * 1024, 64, SECT_4K) },
{ "gd25q64", INFO(0xc84017, 0, 64 * 1024, 128, SECT_4K) },
{ "gd25q128", INFO(0xc84018, 0, 64 * 1024, 256, SECT_4K) },
/* Intel/Numonyx -- xxxs33b */
{ "160s33b", INFO(0x898911, 0, 64 * 1024, 32, 0) },
@ -560,14 +561,14 @@ static const struct spi_device_id spi_nor_ids[] = {
{ "mx66l1g55g", INFO(0xc2261b, 0, 64 * 1024, 2048, SPI_NOR_QUAD_READ) },
/* Micron */
{ "n25q032", INFO(0x20ba16, 0, 64 * 1024, 64, 0) },
{ "n25q064", INFO(0x20ba17, 0, 64 * 1024, 128, 0) },
{ "n25q128a11", INFO(0x20bb18, 0, 64 * 1024, 256, 0) },
{ "n25q128a13", INFO(0x20ba18, 0, 64 * 1024, 256, 0) },
{ "n25q256a", INFO(0x20ba19, 0, 64 * 1024, 512, SECT_4K) },
{ "n25q512a", INFO(0x20bb20, 0, 64 * 1024, 1024, SECT_4K) },
{ "n25q512ax3", INFO(0x20ba20, 0, 64 * 1024, 1024, USE_FSR) },
{ "n25q00", INFO(0x20ba21, 0, 64 * 1024, 2048, USE_FSR) },
{ "n25q032", INFO(0x20ba16, 0, 64 * 1024, 64, SPI_NOR_QUAD_READ) },
{ "n25q064", INFO(0x20ba17, 0, 64 * 1024, 128, SPI_NOR_QUAD_READ) },
{ "n25q128a11", INFO(0x20bb18, 0, 64 * 1024, 256, SPI_NOR_QUAD_READ) },
{ "n25q128a13", INFO(0x20ba18, 0, 64 * 1024, 256, SPI_NOR_QUAD_READ) },
{ "n25q256a", INFO(0x20ba19, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_QUAD_READ) },
{ "n25q512a", INFO(0x20bb20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) },
{ "n25q512ax3", INFO(0x20ba20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) },
{ "n25q00", INFO(0x20ba21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) },
/* PMC */
{ "pm25lv512", INFO(0, 0, 32 * 1024, 2, SECT_4K_PMC) },
@ -891,6 +892,45 @@ static int spansion_quad_enable(struct spi_nor *nor)
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)
{
int status;
@ -903,6 +943,13 @@ static int set_quad_mode(struct spi_nor *nor, struct flash_info *info)
return -EINVAL;
}
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:
status = spansion_quad_enable(nor);
if (status) {

View file

@ -84,11 +84,6 @@ static inline int pullbit(struct pushpull *pp)
return bit;
}
static inline int pulledbits(struct pushpull *pp)
{
return pp->ofs;
}
static void init_rubin(struct rubin_state *rs, int div, int *bits)
{

View file

@ -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);
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 */
if (sumlen > buf_size) {
/* Need to kmalloc for this. */
@ -544,6 +548,7 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
}
}
full_scan:
buf_ofs = jeb->offset;
if (!buf_size) {

View file

@ -227,6 +227,7 @@ struct mtd_info {
int (*_block_markbad) (struct mtd_info *mtd, loff_t ofs);
int (*_suspend) (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
* its own reference counting. The below functions are only for driver.

View file

@ -56,6 +56,10 @@
/* Used for Spansion flashes only. */
#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. */
#define SR_WIP 1 /* Write in progress */
#define SR_WEL 2 /* Write enable latch */
@ -67,6 +71,9 @@
#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 */
#define FSR_READY 0x80