Commit 511c41d9 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull MTD update from Brian Norris:
 "Sorry for delaying this a bit later than usual.  There's one mild
  regression from 3.16 that was noticed during the 3.17 cycle, and I
  meant to send a fix for it along with this pull request.  I'll
  probably try to queue it up for a later pull request once I've had a
  better look at it, hopefully by -rc2 at the latest.

  Summary for this pull:

  NAND
   - Cleanup for Denali driver
   - Atmel: add support for new page sizes
   - Atmel: fix up 'raw' mode support
   - Atmel: miscellaneous cleanups
   - New timing mode helpers for non-ONFI NAND
   - OMAP: allow driver to be (properly) built as a module
   - bcm47xx: RESET support and other cleanups

  SPI NOR
   - Miscellaneous cleanups, to prepare framework for wider use (some
     further work still pending)
   - Compile-time configuration to select 4K vs.  64K support for flash
     that support both (necessary for using UBIFS on some SPI NOR)

  A few scattered code quality fixes, detected by Coverity

  See the changesets for more"

* tag 'for-linus-20141015' of git://git.infradead.org/linux-mtd: (59 commits)
  mtd: nand: omap: Correct CONFIG_MTD_NAND_OMAP_BCH help message
  mtd: nand: Force omap_elm to be built as a module if omap2_nand is a module
  mtd: move support for struct flash_platform_data into m25p80
  mtd: spi-nor: add Kconfig option to disable 4K sectors
  mtd: nand: Move ELM driver and rename as omap_elm
  nand: omap2: Replace pr_err with dev_err
  nand: omap2: Remove horrible ifdefs to fix module probe
  mtd: nand: add Hynix's H27UCG8T2ATR-BC to nand_ids table
  mtd: nand: support ONFI timing mode retrieval for non-ONFI NANDs
  mtd: physmap_of: Add non-obsolete map_rom probe
  mtd: physmap_of: Fix ROM support via OF
  MAINTAINERS: add l2-mtd.git, 'next' tree for MTD
  mtd: denali: fix indents and other trivial things
  mtd: denali: remove unnecessary parentheses
  mtd: denali: remove another set-but-unused variable
  mtd: denali: fix include guard and license block of denali.h
  mtd: nand: don't break long print messages
  mtd: bcm47xxnflash: replace some magic numbers
  mtd: bcm47xxnflash: NAND_CMD_RESET support
  mtd: bcm47xxnflash: add cmd_ctrl handler
  ...
parents 88ed806a 8b3d58e5
...@@ -36,6 +36,7 @@ Optional properties: ...@@ -36,6 +36,7 @@ Optional properties:
- reg : should specify the address and size used for NFC command registers, - reg : should specify the address and size used for NFC command registers,
NFC registers and NFC Sram. NFC Sram address and size can be absent NFC registers and NFC Sram. NFC Sram address and size can be absent
if don't want to use it. if don't want to use it.
- clocks: phandle to the peripheral clock
- Optional properties: - Optional properties:
- atmel,write-by-sram: boolean to enable NFC write by sram. - atmel,write-by-sram: boolean to enable NFC write by sram.
...@@ -98,6 +99,7 @@ nand0: nand@40000000 { ...@@ -98,6 +99,7 @@ nand0: nand@40000000 {
compatible = "atmel,sama5d3-nfc"; compatible = "atmel,sama5d3-nfc";
#address-cells = <1>; #address-cells = <1>;
#size-cells = <1>; #size-cells = <1>;
clocks = <&hsmc_clk>
reg = < reg = <
0x70000000 0x10000000 /* NFC Command Registers */ 0x70000000 0x10000000 /* NFC Command Registers */
0xffffc000 0x00000070 /* NFC HSMC regs */ 0xffffc000 0x00000070 /* NFC HSMC regs */
......
...@@ -4,8 +4,8 @@ Flash chips (Memory Technology Devices) are often used for solid state ...@@ -4,8 +4,8 @@ Flash chips (Memory Technology Devices) are often used for solid state
file systems on embedded devices. file systems on embedded devices.
- compatible : should contain the specific model of mtd chip(s) - compatible : should contain the specific model of mtd chip(s)
used, if known, followed by either "cfi-flash", "jedec-flash" used, if known, followed by either "cfi-flash", "jedec-flash",
or "mtd-ram". "mtd-ram" or "mtd-rom".
- reg : Address range(s) of the mtd chip(s) - reg : Address range(s) of the mtd chip(s)
It's possible to (optionally) define multiple "reg" tuples so that It's possible to (optionally) define multiple "reg" tuples so that
non-identical chips can be described in one node. non-identical chips can be described in one node.
......
...@@ -5992,6 +5992,7 @@ L: linux-mtd@lists.infradead.org ...@@ -5992,6 +5992,7 @@ L: linux-mtd@lists.infradead.org
W: http://www.linux-mtd.infradead.org/ W: http://www.linux-mtd.infradead.org/
Q: http://patchwork.ozlabs.org/project/linux-mtd/list/ Q: http://patchwork.ozlabs.org/project/linux-mtd/list/
T: git git://git.infradead.org/linux-mtd.git T: git git://git.infradead.org/linux-mtd.git
T: git git://git.infradead.org/l2-mtd.git
S: Maintained S: Maintained
F: drivers/mtd/ F: drivers/mtd/
F: include/linux/mtd/ F: include/linux/mtd/
......
...@@ -1440,6 +1440,8 @@ static int gpmc_probe_nand_child(struct platform_device *pdev, ...@@ -1440,6 +1440,8 @@ static int gpmc_probe_nand_child(struct platform_device *pdev,
break; break;
} }
gpmc_nand_data->flash_bbt = of_get_nand_on_flash_bbt(child);
val = of_get_nand_bus_width(child); val = of_get_nand_bus_width(child);
if (val == 16) if (val == 16)
gpmc_nand_data->devsize = NAND_BUSWIDTH_16; gpmc_nand_data->devsize = NAND_BUSWIDTH_16;
......
...@@ -199,6 +199,17 @@ static int bcm47xxpart_parse(struct mtd_info *master, ...@@ -199,6 +199,17 @@ static int bcm47xxpart_parse(struct mtd_info *master,
continue; continue;
} }
/*
* New (ARM?) devices may have NVRAM in some middle block. Last
* block will be checked later, so skip it.
*/
if (offset != master->size - blocksize &&
buf[0x000 / 4] == NVRAM_HEADER) {
bcm47xxpart_add_part(&parts[curr_part++], "nvram",
offset, 0);
continue;
}
/* Read middle of the block */ /* Read middle of the block */
if (mtd_read(master, offset + 0x8000, 0x4, if (mtd_read(master, offset + 0x8000, 0x4,
&bytes_read, (uint8_t *)buf) < 0) { &bytes_read, (uint8_t *)buf) < 0) {
......
...@@ -2033,6 +2033,8 @@ static int cfi_amdstd_panic_wait(struct map_info *map, struct flchip *chip, ...@@ -2033,6 +2033,8 @@ static int cfi_amdstd_panic_wait(struct map_info *map, struct flchip *chip,
udelay(1); udelay(1);
} }
retries--;
} }
/* the chip never became ready */ /* the chip never became ready */
......
...@@ -12,7 +12,6 @@ obj-$(CONFIG_MTD_LART) += lart.o ...@@ -12,7 +12,6 @@ obj-$(CONFIG_MTD_LART) += lart.o
obj-$(CONFIG_MTD_BLOCK2MTD) += block2mtd.o obj-$(CONFIG_MTD_BLOCK2MTD) += block2mtd.o
obj-$(CONFIG_MTD_DATAFLASH) += mtd_dataflash.o obj-$(CONFIG_MTD_DATAFLASH) += mtd_dataflash.o
obj-$(CONFIG_MTD_M25P80) += m25p80.o obj-$(CONFIG_MTD_M25P80) += m25p80.o
obj-$(CONFIG_MTD_NAND_OMAP_BCH) += elm.o
obj-$(CONFIG_MTD_SPEAR_SMI) += spear_smi.o obj-$(CONFIG_MTD_SPEAR_SMI) += spear_smi.o
obj-$(CONFIG_MTD_SST25L) += sst25l.o obj-$(CONFIG_MTD_SST25L) += sst25l.o
obj-$(CONFIG_MTD_BCM47XXSFLASH) += bcm47xxsflash.o obj-$(CONFIG_MTD_BCM47XXSFLASH) += bcm47xxsflash.o
......
...@@ -1697,16 +1697,16 @@ static int dbg_asicmode_show(struct seq_file *s, void *p) ...@@ -1697,16 +1697,16 @@ static int dbg_asicmode_show(struct seq_file *s, void *p)
switch (mode) { switch (mode) {
case DOC_ASICMODE_RESET: case DOC_ASICMODE_RESET:
pos += seq_printf(s, "reset"); pos += seq_puts(s, "reset");
break; break;
case DOC_ASICMODE_NORMAL: case DOC_ASICMODE_NORMAL:
pos += seq_printf(s, "normal"); pos += seq_puts(s, "normal");
break; break;
case DOC_ASICMODE_POWERDOWN: case DOC_ASICMODE_POWERDOWN:
pos += seq_printf(s, "powerdown"); pos += seq_puts(s, "powerdown");
break; break;
} }
pos += seq_printf(s, ")\n"); pos += seq_puts(s, ")\n");
return pos; return pos;
} }
DEBUGFS_RO_ATTR(asic_mode, dbg_asicmode_show); DEBUGFS_RO_ATTR(asic_mode, dbg_asicmode_show);
...@@ -1745,22 +1745,22 @@ static int dbg_protection_show(struct seq_file *s, void *p) ...@@ -1745,22 +1745,22 @@ static int dbg_protection_show(struct seq_file *s, void *p)
pos += seq_printf(s, "Protection = 0x%02x (", pos += seq_printf(s, "Protection = 0x%02x (",
protect); protect);
if (protect & DOC_PROTECT_FOUNDRY_OTP_LOCK) if (protect & DOC_PROTECT_FOUNDRY_OTP_LOCK)
pos += seq_printf(s, "FOUNDRY_OTP_LOCK,"); pos += seq_puts(s, "FOUNDRY_OTP_LOCK,");
if (protect & DOC_PROTECT_CUSTOMER_OTP_LOCK) if (protect & DOC_PROTECT_CUSTOMER_OTP_LOCK)
pos += seq_printf(s, "CUSTOMER_OTP_LOCK,"); pos += seq_puts(s, "CUSTOMER_OTP_LOCK,");
if (protect & DOC_PROTECT_LOCK_INPUT) if (protect & DOC_PROTECT_LOCK_INPUT)
pos += seq_printf(s, "LOCK_INPUT,"); pos += seq_puts(s, "LOCK_INPUT,");
if (protect & DOC_PROTECT_STICKY_LOCK) if (protect & DOC_PROTECT_STICKY_LOCK)
pos += seq_printf(s, "STICKY_LOCK,"); pos += seq_puts(s, "STICKY_LOCK,");
if (protect & DOC_PROTECT_PROTECTION_ENABLED) if (protect & DOC_PROTECT_PROTECTION_ENABLED)
pos += seq_printf(s, "PROTECTION ON,"); pos += seq_puts(s, "PROTECTION ON,");
if (protect & DOC_PROTECT_IPL_DOWNLOAD_LOCK) if (protect & DOC_PROTECT_IPL_DOWNLOAD_LOCK)
pos += seq_printf(s, "IPL_DOWNLOAD_LOCK,"); pos += seq_puts(s, "IPL_DOWNLOAD_LOCK,");
if (protect & DOC_PROTECT_PROTECTION_ERROR) if (protect & DOC_PROTECT_PROTECTION_ERROR)
pos += seq_printf(s, "PROTECT_ERR,"); pos += seq_puts(s, "PROTECT_ERR,");
else else
pos += seq_printf(s, "NO_PROTECT_ERR"); pos += seq_puts(s, "NO_PROTECT_ERR");
pos += seq_printf(s, ")\n"); pos += seq_puts(s, ")\n");
pos += seq_printf(s, "DPS0 = 0x%02x : " pos += seq_printf(s, "DPS0 = 0x%02x : "
"Protected area [0x%x - 0x%x] : OTP=%d, READ=%d, " "Protected area [0x%x - 0x%x] : OTP=%d, READ=%d, "
......
...@@ -193,11 +193,14 @@ static int m25p_probe(struct spi_device *spi) ...@@ -193,11 +193,14 @@ static int m25p_probe(struct spi_device *spi)
{ {
struct mtd_part_parser_data ppdata; struct mtd_part_parser_data ppdata;
struct flash_platform_data *data; struct flash_platform_data *data;
const struct spi_device_id *id = NULL;
struct m25p *flash; struct m25p *flash;
struct spi_nor *nor; struct spi_nor *nor;
enum read_mode mode = SPI_NOR_NORMAL; enum read_mode mode = SPI_NOR_NORMAL;
int ret; int ret;
data = dev_get_platdata(&spi->dev);
flash = devm_kzalloc(&spi->dev, sizeof(*flash), GFP_KERNEL); flash = devm_kzalloc(&spi->dev, sizeof(*flash), GFP_KERNEL);
if (!flash) if (!flash)
return -ENOMEM; return -ENOMEM;
...@@ -223,11 +226,26 @@ static int m25p_probe(struct spi_device *spi) ...@@ -223,11 +226,26 @@ static int m25p_probe(struct spi_device *spi)
mode = SPI_NOR_QUAD; mode = SPI_NOR_QUAD;
else if (spi->mode & SPI_RX_DUAL) else if (spi->mode & SPI_RX_DUAL)
mode = SPI_NOR_DUAL; mode = SPI_NOR_DUAL;
ret = spi_nor_scan(nor, spi_get_device_id(spi), mode);
if (data && data->name)
flash->mtd.name = data->name;
/* For some (historical?) reason many platforms provide two different
* names in flash_platform_data: "name" and "type". Quite often name is
* set to "m25p80" and then "type" provides a real chip name.
* If that's the case, respect "type" and ignore a "name".
*/
if (data && data->type)
id = spi_nor_match_id(data->type);
/* If we didn't get name from platform, simply use "modalias". */
if (!id)
id = spi_get_device_id(spi);
ret = spi_nor_scan(nor, id, mode);
if (ret) if (ret)
return ret; return ret;
data = dev_get_platdata(&spi->dev);
ppdata.of_node = spi->dev.of_node; ppdata.of_node = spi->dev.of_node;
return mtd_device_parse_register(&flash->mtd, NULL, &ppdata, return mtd_device_parse_register(&flash->mtd, NULL, &ppdata,
......
...@@ -249,7 +249,7 @@ config MTD_CFI_FLAGADM ...@@ -249,7 +249,7 @@ config MTD_CFI_FLAGADM
config MTD_SOLUTIONENGINE config MTD_SOLUTIONENGINE
tristate "CFI Flash device mapped on Hitachi SolutionEngine" tristate "CFI Flash device mapped on Hitachi SolutionEngine"
depends on SUPERH && SOLUTION_ENGINE && MTD_CFI && MTD_REDBOOT_PARTS depends on SOLUTION_ENGINE && MTD_CFI && MTD_REDBOOT_PARTS
help help
This enables access to the flash chips on the Hitachi SolutionEngine and This enables access to the flash chips on the Hitachi SolutionEngine and
similar boards. Say 'Y' if you are building a kernel for such a board. similar boards. Say 'Y' if you are building a kernel for such a board.
......
...@@ -99,22 +99,28 @@ static map_word gf_read(struct map_info *map, unsigned long ofs) ...@@ -99,22 +99,28 @@ static map_word gf_read(struct map_info *map, unsigned long ofs)
* @from: flash offset to copy from * @from: flash offset to copy from
* @len: how much to copy * @len: how much to copy
* *
* We rely on the MTD layer to chunk up copies such that a single request here * The "from" region may straddle more than one window, so toggle the GPIOs for
* will not cross a window size. This allows us to only wiggle the GPIOs once * each window region before reading its data.
* before falling back to a normal memcpy. Reading the higher layer code shows
* that this is indeed the case, but add a BUG_ON() to future proof.
*/ */
static void gf_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) static void gf_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
{ {
struct async_state *state = gf_map_info_to_state(map); struct async_state *state = gf_map_info_to_state(map);
gf_set_gpios(state, from); int this_len;
/* BUG if operation crosses the win_size */ while (len) {
BUG_ON(!((from + len) % state->win_size <= (from + len))); if ((from % state->win_size) + len > state->win_size)
this_len = state->win_size - (from % state->win_size);
else
this_len = len;
/* operation does not cross the win_size, so one shot it */ gf_set_gpios(state, from);
memcpy_fromio(to, map->virt + (from % state->win_size), len); memcpy_fromio(to, map->virt + (from % state->win_size),
this_len);
len -= this_len;
from += this_len;
to += this_len;
}
} }
/** /**
...@@ -147,13 +153,21 @@ static void gf_copy_to(struct map_info *map, unsigned long to, ...@@ -147,13 +153,21 @@ static void gf_copy_to(struct map_info *map, unsigned long to,
{ {
struct async_state *state = gf_map_info_to_state(map); struct async_state *state = gf_map_info_to_state(map);
gf_set_gpios(state, to); int this_len;
/* BUG if operation crosses the win_size */ while (len) {
BUG_ON(!((to + len) % state->win_size <= (to + len))); if ((to % state->win_size) + len > state->win_size)
this_len = state->win_size - (to % state->win_size);
else
this_len = len;
/* operation does not cross the win_size, so one shot it */ gf_set_gpios(state, to);
memcpy_toio(map->virt + (to % state->win_size), from, len); memcpy_toio(map->virt + (to % state->win_size), from, len);
len -= this_len;
to += this_len;
from += this_len;
}
} }
static const char * const part_probe_types[] = { static const char * const part_probe_types[] = {
......
...@@ -89,7 +89,7 @@ static caddr_t remap_window(struct map_info *map, unsigned long to) ...@@ -89,7 +89,7 @@ static caddr_t remap_window(struct map_info *map, unsigned long to)
if (!pcmcia_dev_present(dev->p_dev)) { if (!pcmcia_dev_present(dev->p_dev)) {
pr_debug("device removed\n"); pr_debug("device removed\n");
return 0; return NULL;
} }
offset = to & ~(dev->win_size-1); offset = to & ~(dev->win_size-1);
......
...@@ -103,7 +103,7 @@ static struct mtd_info *obsolete_probe(struct platform_device *dev, ...@@ -103,7 +103,7 @@ static struct mtd_info *obsolete_probe(struct platform_device *dev,
if (strcmp(of_probe, "ROM") != 0) if (strcmp(of_probe, "ROM") != 0)
dev_warn(&dev->dev, "obsolete_probe: don't know probe " dev_warn(&dev->dev, "obsolete_probe: don't know probe "
"type '%s', mapping as rom\n", of_probe); "type '%s', mapping as rom\n", of_probe);
return do_map_probe("mtd_rom", map); return do_map_probe("map_rom", map);
} }
} }
...@@ -339,6 +339,10 @@ static struct of_device_id of_flash_match[] = { ...@@ -339,6 +339,10 @@ static struct of_device_id of_flash_match[] = {
.compatible = "mtd-ram", .compatible = "mtd-ram",
.data = (void *)"map_ram", .data = (void *)"map_ram",
}, },
{
.compatible = "mtd-rom",
.data = (void *)"map_rom",
},
{ {
.type = "rom", .type = "rom",
.compatible = "direct-mapped" .compatible = "direct-mapped"
......
...@@ -549,6 +549,9 @@ static int mtdchar_blkpg_ioctl(struct mtd_info *mtd, ...@@ -549,6 +549,9 @@ static int mtdchar_blkpg_ioctl(struct mtd_info *mtd,
if (mtd_is_partition(mtd)) if (mtd_is_partition(mtd))
return -EINVAL; return -EINVAL;
/* Sanitize user input */
p.devname[BLKPG_DEVNAMELTH - 1] = '\0';
return mtd_add_partition(mtd, p.devname, p.start, p.length); return mtd_add_partition(mtd, p.devname, p.start, p.length);
case BLKPG_DEL_PARTITION: case BLKPG_DEL_PARTITION:
......
...@@ -105,11 +105,10 @@ static LIST_HEAD(mtd_notifiers); ...@@ -105,11 +105,10 @@ static LIST_HEAD(mtd_notifiers);
*/ */
static void mtd_release(struct device *dev) static void mtd_release(struct device *dev)
{ {
struct mtd_info __maybe_unused *mtd = dev_get_drvdata(dev); struct mtd_info *mtd = dev_get_drvdata(dev);
dev_t index = MTD_DEVT(mtd->index); dev_t index = MTD_DEVT(mtd->index);
/* remove /dev/mtdXro node if needed */ /* remove /dev/mtdXro node */
if (index)
device_destroy(&mtd_class, index + 1); device_destroy(&mtd_class, index + 1);
} }
...@@ -442,10 +441,8 @@ int add_mtd_device(struct mtd_info *mtd) ...@@ -442,10 +441,8 @@ int add_mtd_device(struct mtd_info *mtd)
if (device_register(&mtd->dev) != 0) if (device_register(&mtd->dev) != 0)
goto fail_added; goto fail_added;
if (MTD_DEVT(i)) device_create(&mtd_class, mtd->dev.parent, MTD_DEVT(i) + 1, NULL,
device_create(&mtd_class, mtd->dev.parent, "mtd%dro", i);
MTD_DEVT(i) + 1,
NULL, "mtd%dro", i);
pr_debug("mtd: Giving out device %d to %s\n", i, mtd->name); pr_debug("mtd: Giving out device %d to %s\n", i, mtd->name);
/* No need to get a refcount on the module containing /* No need to get a refcount on the module containing
...@@ -778,7 +775,7 @@ EXPORT_SYMBOL_GPL(__put_mtd_device); ...@@ -778,7 +775,7 @@ EXPORT_SYMBOL_GPL(__put_mtd_device);
*/ */
int mtd_erase(struct mtd_info *mtd, struct erase_info *instr) int mtd_erase(struct mtd_info *mtd, struct erase_info *instr)
{ {
if (instr->addr > mtd->size || instr->len > mtd->size - instr->addr) if (instr->addr >= mtd->size || instr->len > mtd->size - instr->addr)
return -EINVAL; return -EINVAL;
if (!(mtd->flags & MTD_WRITEABLE)) if (!(mtd->flags & MTD_WRITEABLE))
return -EROFS; return -EROFS;
...@@ -804,7 +801,7 @@ int mtd_point(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, ...@@ -804,7 +801,7 @@ int mtd_point(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
*phys = 0; *phys = 0;
if (!mtd->_point) if (!mtd->_point)
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (from < 0 || from > mtd->size || len > mtd->size - from) if (from < 0 || from >= mtd->size || len > mtd->size - from)
return -EINVAL; return -EINVAL;
if (!len) if (!len)
return 0; return 0;
...@@ -817,7 +814,7 @@ int mtd_unpoint(struct mtd_info *mtd, loff_t from, size_t len) ...@@ -817,7 +814,7 @@ int mtd_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
{ {
if (!mtd->_point) if (!mtd->_point)
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (from < 0 || from > mtd->size || len > mtd->size - from) if (from < 0 || from >= mtd->size || len > mtd->size - from)
return -EINVAL; return -EINVAL;
if (!len) if (!len)
return 0; return 0;
...@@ -835,7 +832,7 @@ unsigned long mtd_get_unmapped_area(struct mtd_info *mtd, unsigned long len, ...@@ -835,7 +832,7 @@ unsigned long mtd_get_unmapped_area(struct mtd_info *mtd, unsigned long len,
{ {
if (!mtd->_get_unmapped_area) if (!mtd->_get_unmapped_area)
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (offset > mtd->size || len > mtd->size - offset) if (offset >= mtd->size || len > mtd->size - offset)
return -EINVAL; return -EINVAL;
return mtd->_get_unmapped_area(mtd, len, offset, flags); return mtd->_get_unmapped_area(mtd, len, offset, flags);
} }
...@@ -846,7 +843,7 @@ int mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, ...@@ -846,7 +843,7 @@ int mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
{ {
int ret_code; int ret_code;
*retlen = 0; *retlen = 0;
if (from < 0 || from > mtd->size || len > mtd->size - from) if (from < 0 || from >= mtd->size || len > mtd->size - from)
return -EINVAL; return -EINVAL;
if (!len) if (!len)
return 0; return 0;
...@@ -869,7 +866,7 @@ int mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, ...@@ -869,7 +866,7 @@ int mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
const u_char *buf) const u_char *buf)
{ {
*retlen = 0; *retlen = 0;
if (to < 0 || to > mtd->size || len > mtd->size - to) if (to < 0 || to >= mtd->size || len > mtd->size - to)
return -EINVAL; return -EINVAL;
if (!mtd->_write || !(mtd->flags & MTD_WRITEABLE)) if (!mtd->_write || !(mtd->flags & MTD_WRITEABLE))
return -EROFS; return -EROFS;
...@@ -892,7 +889,7 @@ int mtd_panic_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, ...@@ -892,7 +889,7 @@ int mtd_panic_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
*retlen = 0; *retlen = 0;
if (!mtd->_panic_write) if (!mtd->_panic_write)
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (to < 0 || to > mtd->size || len > mtd->size - to) if (to < 0 || to >= mtd->size || len > mtd->size - to)
return -EINVAL; return -EINVAL;
if (!(mtd->flags & MTD_WRITEABLE)) if (!(mtd->flags & MTD_WRITEABLE))
return -EROFS; return -EROFS;
...@@ -1011,7 +1008,7 @@ int mtd_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) ...@@ -1011,7 +1008,7 @@ int mtd_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
{ {
if (!mtd->_lock) if (!mtd->_lock)
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (ofs < 0 || ofs > mtd->size || len > mtd->size - ofs) if (ofs < 0 || ofs >= mtd->size || len > mtd->size - ofs)
return -EINVAL; return -EINVAL;
if (!len) if (!len)
return 0; return 0;
...@@ -1023,7 +1020,7 @@ int mtd_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) ...@@ -1023,7 +1020,7 @@ int mtd_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
{ {
if (!mtd->_unlock) if (!mtd->_unlock)
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (ofs < 0 || ofs > mtd->size || len > mtd->size - ofs) if (ofs < 0 || ofs >= mtd->size || len > mtd->size - ofs)
return -EINVAL; return -EINVAL;
if (!len) if (!len)
return 0; return 0;
...@@ -1035,7 +1032,7 @@ int mtd_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len) ...@@ -1035,7 +1032,7 @@ int mtd_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len)
{ {
if (!mtd->_is_locked) if (!mtd->_is_locked)
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (ofs < 0 || ofs > mtd->size || len > mtd->size - ofs) if (ofs < 0 || ofs >= mtd->size || len > mtd->size - ofs)
return -EINVAL; return -EINVAL;
if (!len) if (!len)
return 0; return 0;
...@@ -1045,7 +1042,7 @@ EXPORT_SYMBOL_GPL(mtd_is_locked); ...@@ -1045,7 +1042,7 @@ EXPORT_SYMBOL_GPL(mtd_is_locked);
int mtd_block_isreserved(struct mtd_info *mtd, loff_t ofs) int mtd_block_isreserved(struct mtd_info *mtd, loff_t ofs)
{ {
if (ofs < 0 || ofs > mtd->size) if (ofs < 0 || ofs >= mtd->size)
return -EINVAL; return -EINVAL;
if (!mtd->_block_isreserved) if (!mtd->_block_isreserved)
return 0; return 0;
...@@ -1055,7 +1052,7 @@ EXPORT_SYMBOL_GPL(mtd_block_isreserved); ...@@ -1055,7 +1052,7 @@ EXPORT_SYMBOL_GPL(mtd_block_isreserved);
int mtd_block_isbad(struct mtd_info *mtd, loff_t ofs) int mtd_block_isbad(struct mtd_info *mtd, loff_t ofs)
{ {
if (ofs < 0 || ofs > mtd->size) if (ofs < 0 || ofs >= mtd->size)
return -EINVAL; return -EINVAL;
if (!mtd->_block_isbad) if (!mtd->_block_isbad)
return 0; return 0;
...@@ -1067,7 +1064,7 @@ int mtd_block_markbad(struct mtd_info *mtd, loff_t ofs) ...@@ -1067,7 +1064,7 @@ int mtd_block_markbad(struct mtd_info *mtd, loff_t ofs)
{ {
if (!mtd->_block_markbad) if (!mtd->_block_markbad)
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (ofs < 0 || ofs > mtd->size) if (ofs < 0 || ofs >= mtd->size)
return -EINVAL; return -EINVAL;
if (!(mtd->flags & MTD_WRITEABLE)) if (!(mtd->flags & MTD_WRITEABLE))
return -EROFS; return -EROFS;
......
...@@ -145,7 +145,7 @@ struct mtdswap_dev { ...@@ -145,7 +145,7 @@ struct mtdswap_dev {
struct mtdswap_oobdata { struct mtdswap_oobdata {
__le16 magic; __le16 magic;
__le32 count; __le32 count;
} __attribute__((packed)); } __packed;
#define MTDSWAP_MAGIC_CLEAN 0x2095 #define MTDSWAP_MAGIC_CLEAN 0x2095
#define MTDSWAP_MAGIC_DIRTY (MTDSWAP_MAGIC_CLEAN + 1) #define MTDSWAP_MAGIC_DIRTY (MTDSWAP_MAGIC_CLEAN + 1)
...@@ -1287,7 +1287,7 @@ static int mtdswap_show(struct seq_file *s, void *data) ...@@ -1287,7 +1287,7 @@ static int mtdswap_show(struct seq_file *s, void *data)
seq_printf(s, "total erasures: %lu\n", sum); seq_printf(s, "total erasures: %lu\n", sum);
seq_printf(s, "\n"); seq_puts(s, "\n");
seq_printf(s, "mtdswap_readsect count: %llu\n", d->sect_read_count); seq_printf(s, "mtdswap_readsect count: %llu\n", d->sect_read_count);
seq_printf(s, "mtdswap_writesect count: %llu\n", d->sect_write_count); seq_printf(s, "mtdswap_writesect count: %llu\n", d->sect_write_count);
...@@ -1296,7 +1296,7 @@ static int mtdswap_show(struct seq_file *s, void *data) ...@@ -1296,7 +1296,7 @@ static int mtdswap_show(struct seq_file *s, void *data)
seq_printf(s, "mtd write count: %llu\n", d->mtd_write_count); seq_printf(s, "mtd write count: %llu\n", d->mtd_write_count);
seq_printf(s, "discarded pages count: %llu\n", d->discard_page_count); seq_printf(s, "discarded pages count: %llu\n", d->discard_page_count);
seq_printf(s, "\n"); seq_puts(s, "\n");
seq_printf(s, "total pages: %u\n", pages); seq_printf(s, "total pages: %u\n", pages);
seq_printf(s, "pages mapped: %u\n", mapped); seq_printf(s, "pages mapped: %u\n", mapped);
...@@ -1474,7 +1474,7 @@ static void mtdswap_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) ...@@ -1474,7 +1474,7 @@ static void mtdswap_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
} }
eblocks = mtd_div_by_eb(use_size, mtd); eblocks = mtd_div_by_eb(use_size, mtd);
use_size = eblocks * mtd->erasesize; use_size = (uint64_t)eblocks * mtd->erasesize;
bad_blocks = mtdswap_badblocks(mtd, use_size); bad_blocks = mtdswap_badblocks(mtd, use_size);
eavailable = eblocks - bad_blocks; eavailable = eblocks - bad_blocks;
......
...@@ -96,7 +96,7 @@ config MTD_NAND_OMAP2 ...@@ -96,7 +96,7 @@ config MTD_NAND_OMAP2
config MTD_NAND_OMAP_BCH config MTD_NAND_OMAP_BCH
depends on MTD_NAND_OMAP2 depends on MTD_NAND_OMAP2
tristate "Support hardware based BCH error correction" bool "Support hardware based BCH error correction"
default n default n
select BCH select BCH
help help
...@@ -104,7 +104,10 @@ config MTD_NAND_OMAP_BCH ...@@ -104,7 +104,10 @@ config MTD_NAND_OMAP_BCH
locate and correct errors when using BCH ECC scheme. This offloads locate and correct errors when using BCH ECC scheme. This offloads
the cpu from doing ECC error searching and correction. However some the cpu from doing ECC error searching and correction. However some
legacy OMAP families like OMAP2xxx, OMAP3xxx do not have ELM engine legacy OMAP families like OMAP2xxx, OMAP3xxx do not have ELM engine
so they should not enable this config symbol. so this is optional for them.
config MTD_NAND_OMAP_BCH_BUILD
def_tristate MTD_NAND_OMAP2 && MTD_NAND_OMAP_BCH
config MTD_NAND_IDS config MTD_NAND_IDS
tristate tristate
......
...@@ -27,6 +27,7 @@ obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o ...@@ -27,6 +27,7 @@ obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o
obj-$(CONFIG_MTD_NAND_ATMEL) += atmel_nand.o obj-$(CONFIG_MTD_NAND_ATMEL) += atmel_nand.o
obj-$(CONFIG_MTD_NAND_GPIO) += gpio.o obj-$(CONFIG_MTD_NAND_GPIO) += gpio.o
obj-$(CONFIG_MTD_NAND_OMAP2) += omap2.o obj-$(CONFIG_MTD_NAND_OMAP2) += omap2.o
obj-$(CONFIG_MTD_NAND_OMAP_BCH_BUILD) += omap_elm.o
obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o
obj-$(CONFIG_MTD_NAND_PXA3xx) += pxa3xx_nand.o obj-$(CONFIG_MTD_NAND_PXA3xx) += pxa3xx_nand.o
obj-$(CONFIG_MTD_NAND_TMIO) += tmio_nand.o obj-$(CONFIG_MTD_NAND_TMIO) += tmio_nand.o
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
* *
*/ */
#include <linux/clk.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -96,6 +97,8 @@ struct atmel_nfc { ...@@ -96,6 +97,8 @@ struct atmel_nfc {
bool use_nfc_sram; bool use_nfc_sram;
bool write_by_sram; bool write_by_sram;
struct clk *clk;
bool is_initialized; bool is_initialized;
struct completion comp_ready; struct completion comp_ready;
struct completion comp_cmd_done; struct completion comp_cmd_done;
...@@ -128,8 +131,6 @@ struct atmel_nand_host { ...@@ -128,8 +131,6 @@ struct atmel_nand_host {
u32 pmecc_lookup_table_offset_512; u32 pmecc_lookup_table_offset_512;
u32 pmecc_lookup_table_offset_1024; u32 pmecc_lookup_table_offset_1024;
int pmecc_bytes_per_sector;
int pmecc_sector_number;
int pmecc_degree; /* Degree of remainders */ int pmecc_degree; /* Degree of remainders */
int pmecc_cw_len; /* Length of codeword */ int pmecc_cw_len; /* Length of codeword */
...@@ -841,7 +842,7 @@ static void pmecc_correct_data(struct mtd_info *mtd, uint8_t *buf, uint8_t *ecc, ...@@ -841,7 +842,7 @@ static void pmecc_correct_data(struct mtd_info *mtd, uint8_t *buf, uint8_t *ecc,
pos, bit_pos, err_byte, *(buf + byte_pos)); pos, bit_pos, err_byte, *(buf + byte_pos));
} else { } else {
/* Bit flip in OOB area */ /* Bit flip in OOB area */
tmp = sector_num * host->pmecc_bytes_per_sector tmp = sector_num * nand_chip->ecc.bytes
+ (byte_pos - sector_size); + (byte_pos - sector_size);
err_byte = ecc[tmp]; err_byte = ecc[tmp];
ecc[tmp] ^= (1 << bit_pos); ecc[tmp] ^= (1 << bit_pos);
...@@ -874,7 +875,7 @@ static int pmecc_correction(struct mtd_info *mtd, u32 pmecc_stat, uint8_t *buf, ...@@ -874,7 +875,7 @@ static int pmecc_correction(struct mtd_info *mtd, u32 pmecc_stat, uint8_t *buf,
return 0; return 0;
normal_check: normal_check:
for (i = 0; i < host->pmecc_sector_number; i++) { for (i = 0; i < nand_chip->ecc.steps; i++) {
err_nbr = 0; err_nbr = 0;
if (pmecc_stat & 0x1) { if (pmecc_stat & 0x1) {
buf_pos = buf + i * host->pmecc_sector_size; buf_pos = buf + i * host->pmecc_sector_size;
...@@ -890,7 +891,7 @@ static int pmecc_correction(struct mtd_info *mtd, u32 pmecc_stat, uint8_t *buf, ...@@ -890,7 +891,7 @@ static int pmecc_correction(struct mtd_info *mtd, u32 pmecc_stat, uint8_t *buf,
return -EIO; return -EIO;
} else { } else {
pmecc_correct_data(mtd, buf_pos, ecc, i, pmecc_correct_data(mtd, buf_pos, ecc, i,
host->pmecc_bytes_per_sector, err_nbr); nand_chip->ecc.bytes, err_nbr);
mtd->ecc_stats.corrected += err_nbr; mtd->ecc_stats.corrected += err_nbr;
total_err += err_nbr; total_err += err_nbr;
} }
...@@ -984,11 +985,11 @@ static int atmel_nand_pmecc_write_page(struct mtd_info *mtd, ...@@ -984,11 +985,11 @@ static int atmel_nand_pmecc_write_page(struct mtd_info *mtd,
cpu_relax(); cpu_relax();
} }
for (i = 0; i < host->pmecc_sector_number; i++) { for (i = 0; i < chip->ecc.steps; i++) {
for (j = 0; j < host->pmecc_bytes_per_sector; j++) { for (j = 0; j < chip->ecc.bytes; j++) {
int pos; int pos;
pos = i * host->pmecc_bytes_per_sector + j; pos = i * chip->ecc.bytes + j;
chip->oob_poi[eccpos[pos]] = chip->oob_poi[eccpos[pos]] =
pmecc_readb_ecc_relaxed(host->ecc, i, j); pmecc_readb_ecc_relaxed(host->ecc, i, j);
} }
...@@ -1031,7 +1032,7 @@ static void atmel_pmecc_core_init(struct mtd_info *mtd) ...@@ -1031,7 +1032,7 @@ static void atmel_pmecc_core_init(struct mtd_info *mtd)
else if (host->pmecc_sector_size == 1024) else if (host->pmecc_sector_size == 1024)
val |= PMECC_CFG_SECTOR1024; val |= PMECC_CFG_SECTOR1024;
switch (host->pmecc_sector_number) { switch (nand_chip->ecc.steps) {
case 1: case 1:
val |= PMECC_CFG_PAGE_1SECTOR; val |= PMECC_CFG_PAGE_1SECTOR;
break; break;
...@@ -1148,7 +1149,6 @@ static int atmel_pmecc_nand_init_params(struct platform_device *pdev, ...@@ -1148,7 +1149,6 @@ static int atmel_pmecc_nand_init_params(struct platform_device *pdev,
host->ecc = devm_ioremap_resource(&pdev->dev, regs); host->ecc = devm_ioremap_resource(&pdev->dev, regs);
if (IS_ERR(host->ecc)) { if (IS_ERR(host->ecc)) {
dev_err(host->dev, "ioremap failed\n");
err_no = PTR_ERR(host->ecc); err_no = PTR_ERR(host->ecc);
goto err; goto err;
} }
...@@ -1156,8 +1156,6 @@ static int atmel_pmecc_nand_init_params(struct platform_device *pdev, ...@@ -1156,8 +1156,6 @@ static int atmel_pmecc_nand_init_params(struct platform_device *pdev,
regs_pmerr = platform_get_resource(pdev, IORESOURCE_MEM, 2); regs_pmerr = platform_get_resource(pdev, IORESOURCE_MEM, 2);
host->pmerrloc_base = devm_ioremap_resource(&pdev->dev, regs_pmerr); host->pmerrloc_base = devm_ioremap_resource(&pdev->dev, regs_pmerr);
if (IS_ERR(host->pmerrloc_base)) { if (IS_ERR(host->pmerrloc_base)) {
dev_err(host->dev,
"Can not get I/O resource for PMECC ERRLOC controller!\n");
err_no = PTR_ERR(host->pmerrloc_base); err_no = PTR_ERR(host->pmerrloc_base);
goto err; goto err;
} }
...@@ -1165,7 +1163,6 @@ static int atmel_pmecc_nand_init_params(struct platform_device *pdev, ...@@ -1165,7 +1163,6 @@ static int atmel_pmecc_nand_init_params(struct platform_device *pdev,
regs_rom = platform_get_resource(pdev, IORESOURCE_MEM, 3); regs_rom = platform_get_resource(pdev, IORESOURCE_MEM, 3);
host->pmecc_rom_base = devm_ioremap_resource(&pdev->dev, regs_rom); host->pmecc_rom_base = devm_ioremap_resource(&pdev->dev, regs_rom);
if (IS_ERR(host->pmecc_rom_base)) { if (IS_ERR(host->pmecc_rom_base)) {
dev_err(host->dev, "Can not get I/O resource for ROM!\n");
err_no = PTR_ERR(host->pmecc_rom_base); err_no = PTR_ERR(host->pmecc_rom_base);
goto err; goto err;
} }
...@@ -1174,22 +1171,29 @@ static int atmel_pmecc_nand_init_params(struct platform_device *pdev, ...@@ -1174,22 +1171,29 @@ static int atmel_pmecc_nand_init_params(struct platform_device *pdev,
/* set ECC page size and oob layout */ /* set ECC page size and oob layout */
switch (mtd->writesize) { switch (mtd->writesize) {
case 512:
case 1024:
case 2048: case 2048:
case 4096:
case 8192:
if (sector_size > mtd->writesize) {
dev_err(host->dev, "pmecc sector size is bigger than the page size!\n");
err_no = -EINVAL;
goto err;
}
host->pmecc_degree = (sector_size == 512) ? host->pmecc_degree = (sector_size == 512) ?
PMECC_GF_DIMENSION_13 : PMECC_GF_DIMENSION_14; PMECC_GF_DIMENSION_13 : PMECC_GF_DIMENSION_14;
host->pmecc_cw_len = (1 << host->pmecc_degree) - 1; host->pmecc_cw_len = (1 << host->pmecc_degree) - 1;
host->pmecc_sector_number = mtd->writesize / sector_size;
host->pmecc_bytes_per_sector = pmecc_get_ecc_bytes(
cap, sector_size);
host->pmecc_alpha_to = pmecc_get_alpha_to(host); host->pmecc_alpha_to = pmecc_get_alpha_to(host);
host->pmecc_index_of = host->pmecc_rom_base + host->pmecc_index_of = host->pmecc_rom_base +
host->pmecc_lookup_table_offset; host->pmecc_lookup_table_offset;
nand_chip->ecc.steps = host->pmecc_sector_number;
nand_chip->ecc.strength = cap; nand_chip->ecc.strength = cap;
nand_chip->ecc.bytes = host->pmecc_bytes_per_sector; nand_chip->ecc.bytes = pmecc_get_ecc_bytes(cap, sector_size);
nand_chip->ecc.total = host->pmecc_bytes_per_sector * nand_chip->ecc.steps = mtd->writesize / sector_size;
host->pmecc_sector_number; nand_chip->ecc.total = nand_chip->ecc.bytes *
nand_chip->ecc.steps;
if (nand_chip->ecc.total > mtd->oobsize - 2) { if (nand_chip->ecc.total > mtd->oobsize - 2) {
dev_err(host->dev, "No room for ECC bytes\n"); dev_err(host->dev, "No room for ECC bytes\n");
err_no = -EINVAL; err_no = -EINVAL;
...@@ -1201,13 +1205,9 @@ static int atmel_pmecc_nand_init_params(struct platform_device *pdev, ...@@ -1201,13 +1205,9 @@ static int atmel_pmecc_nand_init_params(struct platform_device *pdev,
nand_chip->ecc.layout = &atmel_pmecc_oobinfo; nand_chip->ecc.layout = &atmel_pmecc_oobinfo;
break; break;
case 512: default:
case 1024:
case 4096:
/* TODO */
dev_warn(host->dev, dev_warn(host->dev,
"Unsupported page size for PMECC, use Software ECC\n"); "Unsupported page size for PMECC, use Software ECC\n");
default:
/* page size not handled by HW ECC */ /* page size not handled by HW ECC */
/* switching back to soft ECC */ /* switching back to soft ECC */
nand_chip->ecc.mode = NAND_ECC_SOFT; nand_chip->ecc.mode = NAND_ECC_SOFT;
...@@ -1530,10 +1530,8 @@ static int atmel_hw_nand_init_params(struct platform_device *pdev, ...@@ -1530,10 +1530,8 @@ static int atmel_hw_nand_init_params(struct platform_device *pdev,
} }
host->ecc = devm_ioremap_resource(&pdev->dev, regs); host->ecc = devm_ioremap_resource(&pdev->dev, regs);
if (IS_ERR(host->ecc)) { if (IS_ERR(host->ecc))
dev_err(host->dev, "ioremap failed\n");
return PTR_ERR(host->ecc); return PTR_ERR(host->ecc);
}
/* ECC is calculated for the whole page (1 step) */ /* ECC is calculated for the whole page (1 step) */
nand_chip->ecc.size = mtd->writesize; nand_chip->ecc.size = mtd->writesize;
...@@ -1907,15 +1905,7 @@ static int nfc_sram_write_page(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -1907,15 +1905,7 @@ static int nfc_sram_write_page(struct mtd_info *mtd, struct nand_chip *chip,
if (offset || (data_len < mtd->writesize)) if (offset || (data_len < mtd->writesize))
return -EINVAL; return -EINVAL;
cfg = nfc_readl(host->nfc->hsmc_regs, CFG);
len = mtd->writesize; len = mtd->writesize;
if (unlikely(raw)) {
len += mtd->oobsize;
nfc_writel(host->nfc->hsmc_regs, CFG, cfg | NFC_CFG_WSPARE);
} else
nfc_writel(host->nfc->hsmc_regs, CFG, cfg & ~NFC_CFG_WSPARE);
/* Copy page data to sram that will write to nand via NFC */ /* Copy page data to sram that will write to nand via NFC */
if (use_dma) { if (use_dma) {
if (atmel_nand_dma_op(mtd, (void *)buf, len, 0) != 0) if (atmel_nand_dma_op(mtd, (void *)buf, len, 0) != 0)
...@@ -1925,6 +1915,15 @@ static int nfc_sram_write_page(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -1925,6 +1915,15 @@ static int nfc_sram_write_page(struct mtd_info *mtd, struct nand_chip *chip,
memcpy32_toio(sram, buf, len); memcpy32_toio(sram, buf, len);
} }
cfg = nfc_readl(host->nfc->hsmc_regs, CFG);
if (unlikely(raw) && oob_required) {
memcpy32_toio(sram + len, chip->oob_poi, mtd->oobsize);
len += mtd->oobsize;
nfc_writel(host->nfc->hsmc_regs, CFG, cfg | NFC_CFG_WSPARE);
} else {
nfc_writel(host->nfc->hsmc_regs, CFG, cfg & ~NFC_CFG_WSPARE);
}
if (chip->ecc.mode == NAND_ECC_HW && host->has_pmecc) if (chip->ecc.mode == NAND_ECC_HW && host->has_pmecc)
/* /*
* When use NFC sram, need set up PMECC before send * When use NFC sram, need set up PMECC before send
...@@ -2040,7 +2039,6 @@ static int atmel_nand_probe(struct platform_device *pdev) ...@@ -2040,7 +2039,6 @@ static int atmel_nand_probe(struct platform_device *pdev)
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
host->io_base = devm_ioremap_resource(&pdev->dev, mem); host->io_base = devm_ioremap_resource(&pdev->dev, mem);
if (IS_ERR(host->io_base)) { if (IS_ERR(host->io_base)) {
dev_err(&pdev->dev, "atmel_nand: ioremap resource failed\n");
res = PTR_ERR(host->io_base); res = PTR_ERR(host->io_base);
goto err_nand_ioremap; goto err_nand_ioremap;
} }
...@@ -2099,7 +2097,7 @@ static int atmel_nand_probe(struct platform_device *pdev) ...@@ -2099,7 +2097,7 @@ static int atmel_nand_probe(struct platform_device *pdev)
} }
nand_chip->ecc.mode = host->board.ecc_mode; nand_chip->ecc.mode = host->board.ecc_mode;
nand_chip->chip_delay = 20; /* 20us command delay time */ nand_chip->chip_delay = 40; /* 40us command delay time */
if (host->board.bus_width_16) /* 16-bit bus width */ if (host->board.bus_width_16) /* 16-bit bus width */
nand_chip->options |= NAND_BUSWIDTH_16; nand_chip->options |= NAND_BUSWIDTH_16;
...@@ -2248,6 +2246,7 @@ static int atmel_nand_nfc_probe(struct platform_device *pdev) ...@@ -2248,6 +2246,7 @@ static int atmel_nand_nfc_probe(struct platform_device *pdev)
{ {
struct atmel_nfc *nfc = &nand_nfc; struct atmel_nfc *nfc = &nand_nfc;
struct resource *nfc_cmd_regs, *nfc_hsmc_regs, *nfc_sram; struct resource *nfc_cmd_regs, *nfc_hsmc_regs, *nfc_sram;
int ret;
nfc_cmd_regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); nfc_cmd_regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
nfc->base_cmd_regs = devm_ioremap_resource(&pdev->dev, nfc_cmd_regs); nfc->base_cmd_regs = devm_ioremap_resource(&pdev->dev, nfc_cmd_regs);
...@@ -2279,8 +2278,28 @@ static int atmel_nand_nfc_probe(struct platform_device *pdev) ...@@ -2279,8 +2278,28 @@ static int atmel_nand_nfc_probe(struct platform_device *pdev)
nfc_writel(nfc->hsmc_regs, IDR, 0xffffffff); nfc_writel(nfc->hsmc_regs, IDR, 0xffffffff);
nfc_readl(nfc->hsmc_regs, SR); /* clear the NFC_SR */ nfc_readl(nfc->hsmc_regs, SR); /* clear the NFC_SR */
nfc->clk = devm_clk_get(&pdev->dev, NULL);
if (!IS_ERR(nfc->clk)) {
ret = clk_prepare_enable(nfc->clk);
if (ret)
return ret;
} else {
dev_warn(&pdev->dev, "NFC clock missing, update your Device Tree");
}
nfc->is_initialized = true; nfc->is_initialized = true;
dev_info(&pdev->dev, "NFC is probed.\n"); dev_info(&pdev->dev, "NFC is probed.\n");
return 0;
}
static int atmel_nand_nfc_remove(struct platform_device *pdev)
{
struct atmel_nfc *nfc = &nand_nfc;
if (!IS_ERR(nfc->clk))
clk_disable_unprepare(nfc->clk);
return 0; return 0;
} }
...@@ -2297,6 +2316,7 @@ static struct platform_driver atmel_nand_nfc_driver = { ...@@ -2297,6 +2316,7 @@ static struct platform_driver atmel_nand_nfc_driver = {
.of_match_table = of_match_ptr(atmel_nand_nfc_match), .of_match_table = of_match_ptr(atmel_nand_nfc_match),
}, },
.probe = atmel_nand_nfc_probe, .probe = atmel_nand_nfc_probe,
.remove = atmel_nand_nfc_remove,
}; };
static struct platform_driver atmel_nand_driver = { static struct platform_driver atmel_nand_driver = {
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/delay.h>
#include <linux/bcma/bcma.h> #include <linux/bcma/bcma.h>
/* Broadcom uses 1'000'000 but it seems to be too many. Tests on WNDR4500 has /* Broadcom uses 1'000'000 but it seems to be too many. Tests on WNDR4500 has
...@@ -23,6 +24,8 @@ ...@@ -23,6 +24,8 @@
#define NFLASH_SECTOR_SIZE 512 #define NFLASH_SECTOR_SIZE 512
#define NCTL_CMD0 0x00010000 #define NCTL_CMD0 0x00010000
#define NCTL_COL 0x00020000 /* Update column with value from BCMA_CC_NFLASH_COL_ADDR */
#define NCTL_ROW 0x00040000 /* Update row (page) with value from BCMA_CC_NFLASH_ROW_ADDR */
#define NCTL_CMD1W 0x00080000 #define NCTL_CMD1W 0x00080000
#define NCTL_READ 0x00100000 #define NCTL_READ 0x00100000
#define NCTL_WRITE 0x00200000 #define NCTL_WRITE 0x00200000
...@@ -109,7 +112,7 @@ static void bcm47xxnflash_ops_bcm4706_read(struct mtd_info *mtd, uint8_t *buf, ...@@ -109,7 +112,7 @@ static void bcm47xxnflash_ops_bcm4706_read(struct mtd_info *mtd, uint8_t *buf,
b47n->curr_page_addr); b47n->curr_page_addr);
/* Prepare to read */ /* Prepare to read */
ctlcode = NCTL_CSA | NCTL_CMD1W | 0x00040000 | 0x00020000 | ctlcode = NCTL_CSA | NCTL_CMD1W | NCTL_ROW | NCTL_COL |
NCTL_CMD0; NCTL_CMD0;
ctlcode |= NAND_CMD_READSTART << 8; ctlcode |= NAND_CMD_READSTART << 8;
if (bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc, ctlcode)) if (bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc, ctlcode))
...@@ -167,6 +170,26 @@ static void bcm47xxnflash_ops_bcm4706_write(struct mtd_info *mtd, ...@@ -167,6 +170,26 @@ static void bcm47xxnflash_ops_bcm4706_write(struct mtd_info *mtd,
* NAND chip ops * NAND chip ops
**************************************************/ **************************************************/
static void bcm47xxnflash_ops_bcm4706_cmd_ctrl(struct mtd_info *mtd, int cmd,
unsigned int ctrl)
{
struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv;
struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv;
u32 code = 0;
if (cmd == NAND_CMD_NONE)
return;
if (cmd & NAND_CTRL_CLE)
code = cmd | NCTL_CMD0;
/* nCS is not needed for reset command */
if (cmd != NAND_CMD_RESET)
code |= NCTL_CSA;
bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc, code);
}
/* Default nand_select_chip calls cmd_ctrl, which is not used in BCM4706 */ /* Default nand_select_chip calls cmd_ctrl, which is not used in BCM4706 */
static void bcm47xxnflash_ops_bcm4706_select_chip(struct mtd_info *mtd, static void bcm47xxnflash_ops_bcm4706_select_chip(struct mtd_info *mtd,
int chip) int chip)
...@@ -174,6 +197,14 @@ static void bcm47xxnflash_ops_bcm4706_select_chip(struct mtd_info *mtd, ...@@ -174,6 +197,14 @@ static void bcm47xxnflash_ops_bcm4706_select_chip(struct mtd_info *mtd,
return; return;
} }
static int bcm47xxnflash_ops_bcm4706_dev_ready(struct mtd_info *mtd)
{
struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv;
struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv;
return !!(bcma_cc_read32(b47n->cc, BCMA_CC_NFLASH_CTL) & NCTL_READY);
}
/* /*
* Default nand_command and nand_command_lp don't match BCM4706 hardware layout. * Default nand_command and nand_command_lp don't match BCM4706 hardware layout.
* For example, reading chip id is performed in a non-standard way. * For example, reading chip id is performed in a non-standard way.
...@@ -198,7 +229,10 @@ static void bcm47xxnflash_ops_bcm4706_cmdfunc(struct mtd_info *mtd, ...@@ -198,7 +229,10 @@ static void bcm47xxnflash_ops_bcm4706_cmdfunc(struct mtd_info *mtd,
switch (command) { switch (command) {
case NAND_CMD_RESET: case NAND_CMD_RESET:
pr_warn("Chip reset not implemented yet\n"); nand_chip->cmd_ctrl(mtd, command, NAND_CTRL_CLE);
ndelay(100);
nand_wait_ready(mtd);
break; break;
case NAND_CMD_READID: case NAND_CMD_READID:
ctlcode = NCTL_CSA | 0x01000000 | NCTL_CMD1W | NCTL_CMD0; ctlcode = NCTL_CSA | 0x01000000 | NCTL_CMD1W | NCTL_CMD0;
...@@ -242,7 +276,7 @@ static void bcm47xxnflash_ops_bcm4706_cmdfunc(struct mtd_info *mtd, ...@@ -242,7 +276,7 @@ static void bcm47xxnflash_ops_bcm4706_cmdfunc(struct mtd_info *mtd,
case NAND_CMD_ERASE1: case NAND_CMD_ERASE1:
bcma_cc_write32(cc, BCMA_CC_NFLASH_ROW_ADDR, bcma_cc_write32(cc, BCMA_CC_NFLASH_ROW_ADDR,
b47n->curr_page_addr); b47n->curr_page_addr);
ctlcode = 0x00040000 | NCTL_CMD1W | NCTL_CMD0 | ctlcode = NCTL_ROW | NCTL_CMD1W | NCTL_CMD0 |
NAND_CMD_ERASE1 | (NAND_CMD_ERASE2 << 8); NAND_CMD_ERASE1 | (NAND_CMD_ERASE2 << 8);
if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, ctlcode)) if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, ctlcode))
pr_err("ERASE1 failed\n"); pr_err("ERASE1 failed\n");
...@@ -257,13 +291,13 @@ static void bcm47xxnflash_ops_bcm4706_cmdfunc(struct mtd_info *mtd, ...@@ -257,13 +291,13 @@ static void bcm47xxnflash_ops_bcm4706_cmdfunc(struct mtd_info *mtd,
b47n->curr_page_addr); b47n->curr_page_addr);
/* Prepare to write */ /* Prepare to write */
ctlcode = 0x40000000 | 0x00040000 | 0x00020000 | 0x00010000; ctlcode = 0x40000000 | NCTL_ROW | NCTL_COL | NCTL_CMD0;
ctlcode |= NAND_CMD_SEQIN; ctlcode |= NAND_CMD_SEQIN;
if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, ctlcode)) if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, ctlcode))
pr_err("SEQIN failed\n"); pr_err("SEQIN failed\n");
break; break;
case NAND_CMD_PAGEPROG: case NAND_CMD_PAGEPROG:
if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, 0x00010000 | if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, NCTL_CMD0 |
NAND_CMD_PAGEPROG)) NAND_CMD_PAGEPROG))
pr_err("PAGEPROG failed\n"); pr_err("PAGEPROG failed\n");
if (bcm47xxnflash_ops_bcm4706_poll(cc)) if (bcm47xxnflash_ops_bcm4706_poll(cc))
...@@ -341,6 +375,7 @@ static void bcm47xxnflash_ops_bcm4706_write_buf(struct mtd_info *mtd, ...@@ -341,6 +375,7 @@ static void bcm47xxnflash_ops_bcm4706_write_buf(struct mtd_info *mtd,
int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n) int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n)
{ {
struct nand_chip *nand_chip = (struct nand_chip *)&b47n->nand_chip;
int err; int err;
u32 freq; u32 freq;
u16 clock; u16 clock;
...@@ -351,10 +386,14 @@ int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n) ...@@ -351,10 +386,14 @@ int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n)
u32 val; u32 val;
b47n->nand_chip.select_chip = bcm47xxnflash_ops_bcm4706_select_chip; b47n->nand_chip.select_chip = bcm47xxnflash_ops_bcm4706_select_chip;
nand_chip->cmd_ctrl = bcm47xxnflash_ops_bcm4706_cmd_ctrl;
nand_chip->dev_ready = bcm47xxnflash_ops_bcm4706_dev_ready;
b47n->nand_chip.cmdfunc = bcm47xxnflash_ops_bcm4706_cmdfunc; b47n->nand_chip.cmdfunc = bcm47xxnflash_ops_bcm4706_cmdfunc;
b47n->nand_chip.read_byte = bcm47xxnflash_ops_bcm4706_read_byte; b47n->nand_chip.read_byte = bcm47xxnflash_ops_bcm4706_read_byte;
b47n->nand_chip.read_buf = bcm47xxnflash_ops_bcm4706_read_buf; b47n->nand_chip.read_buf = bcm47xxnflash_ops_bcm4706_read_buf;
b47n->nand_chip.write_buf = bcm47xxnflash_ops_bcm4706_write_buf; b47n->nand_chip.write_buf = bcm47xxnflash_ops_bcm4706_write_buf;
nand_chip->chip_delay = 50;
b47n->nand_chip.bbt_options = NAND_BBT_USE_FLASH; b47n->nand_chip.bbt_options = NAND_BBT_USE_FLASH;
b47n->nand_chip.ecc.mode = NAND_ECC_NONE; /* TODO: implement ECC */ b47n->nand_chip.ecc.mode = NAND_ECC_NONE; /* TODO: implement ECC */
...@@ -364,11 +403,13 @@ int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n) ...@@ -364,11 +403,13 @@ int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n)
/* Configure wait counters */ /* Configure wait counters */
if (b47n->cc->status & BCMA_CC_CHIPST_4706_PKG_OPTION) { if (b47n->cc->status & BCMA_CC_CHIPST_4706_PKG_OPTION) {
freq = 100000000; /* 400 MHz */
freq = 400000000 / 4;
} else { } else {
freq = bcma_chipco_pll_read(b47n->cc, 4); freq = bcma_chipco_pll_read(b47n->cc, 4);
freq = (freq * 0xFFF) >> 3; freq = (freq & 0xFFF) >> 3;
freq = (freq * 25000000) >> 3; /* Fixed reference clock 25 MHz and m = 2 */
freq = (freq * 25000000 / 2) / 4;
} }
clock = freq / 1000000; clock = freq / 1000000;
w0 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(15, clock); w0 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(15, clock);
......
...@@ -29,20 +29,23 @@ ...@@ -29,20 +29,23 @@
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
/* We define a module parameter that allows the user to override /*
* We define a module parameter that allows the user to override
* the hardware and decide what timing mode should be used. * the hardware and decide what timing mode should be used.
*/ */
#define NAND_DEFAULT_TIMINGS -1 #define NAND_DEFAULT_TIMINGS -1
static int onfi_timing_mode = NAND_DEFAULT_TIMINGS; static int onfi_timing_mode = NAND_DEFAULT_TIMINGS;
module_param(onfi_timing_mode, int, S_IRUGO); module_param(onfi_timing_mode, int, S_IRUGO);
MODULE_PARM_DESC(onfi_timing_mode, "Overrides default ONFI setting." MODULE_PARM_DESC(onfi_timing_mode,
" -1 indicates use default timings"); "Overrides default ONFI setting. -1 indicates use default timings");
#define DENALI_NAND_NAME "denali-nand" #define DENALI_NAND_NAME "denali-nand"
/* We define a macro here that combines all interrupts this driver uses into /*
* a single constant value, for convenience. */ * We define a macro here that combines all interrupts this driver uses into
* a single constant value, for convenience.
*/
#define DENALI_IRQ_ALL (INTR_STATUS__DMA_CMD_COMP | \ #define DENALI_IRQ_ALL (INTR_STATUS__DMA_CMD_COMP | \
INTR_STATUS__ECC_TRANSACTION_DONE | \ INTR_STATUS__ECC_TRANSACTION_DONE | \
INTR_STATUS__ECC_ERR | \ INTR_STATUS__ECC_ERR | \
...@@ -54,26 +57,34 @@ MODULE_PARM_DESC(onfi_timing_mode, "Overrides default ONFI setting." ...@@ -54,26 +57,34 @@ MODULE_PARM_DESC(onfi_timing_mode, "Overrides default ONFI setting."
INTR_STATUS__RST_COMP | \ INTR_STATUS__RST_COMP | \
INTR_STATUS__ERASE_COMP) INTR_STATUS__ERASE_COMP)
/* indicates whether or not the internal value for the flash bank is /*
* valid or not */ * indicates whether or not the internal value for the flash bank is
* valid or not
*/
#define CHIP_SELECT_INVALID -1 #define CHIP_SELECT_INVALID -1
#define SUPPORT_8BITECC 1 #define SUPPORT_8BITECC 1
/* This macro divides two integers and rounds fractional values up /*
* to the nearest integer value. */ * This macro divides two integers and rounds fractional values up
* to the nearest integer value.
*/
#define CEIL_DIV(X, Y) (((X)%(Y)) ? ((X)/(Y)+1) : ((X)/(Y))) #define CEIL_DIV(X, Y) (((X)%(Y)) ? ((X)/(Y)+1) : ((X)/(Y)))
/* this macro allows us to convert from an MTD structure to our own /*
* this macro allows us to convert from an MTD structure to our own
* device context (denali) structure. * device context (denali) structure.
*/ */
#define mtd_to_denali(m) container_of(m, struct denali_nand_info, mtd) #define mtd_to_denali(m) container_of(m, struct denali_nand_info, mtd)
/* These constants are defined by the driver to enable common driver /*
* configuration options. */ * These constants are defined by the driver to enable common driver
* configuration options.
*/
#define SPARE_ACCESS 0x41 #define SPARE_ACCESS 0x41
#define MAIN_ACCESS 0x42 #define MAIN_ACCESS 0x42
#define MAIN_SPARE_ACCESS 0x43 #define MAIN_SPARE_ACCESS 0x43
#define PIPELINE_ACCESS 0x2000
#define DENALI_READ 0 #define DENALI_READ 0
#define DENALI_WRITE 0x100 #define DENALI_WRITE 0x100
...@@ -83,8 +94,10 @@ MODULE_PARM_DESC(onfi_timing_mode, "Overrides default ONFI setting." ...@@ -83,8 +94,10 @@ MODULE_PARM_DESC(onfi_timing_mode, "Overrides default ONFI setting."
#define ADDR_CYCLE 1 #define ADDR_CYCLE 1
#define STATUS_CYCLE 2 #define STATUS_CYCLE 2
/* this is a helper macro that allows us to /*
* format the bank into the proper bits for the controller */ * this is a helper macro that allows us to
* format the bank into the proper bits for the controller
*/
#define BANK(x) ((x) << 24) #define BANK(x) ((x) << 24)
/* forward declarations */ /* forward declarations */
...@@ -95,12 +108,12 @@ static void denali_irq_enable(struct denali_nand_info *denali, ...@@ -95,12 +108,12 @@ static void denali_irq_enable(struct denali_nand_info *denali,
uint32_t int_mask); uint32_t int_mask);
static uint32_t read_interrupt_status(struct denali_nand_info *denali); static uint32_t read_interrupt_status(struct denali_nand_info *denali);
/* Certain operations for the denali NAND controller use /*
* an indexed mode to read/write data. The operation is * Certain operations for the denali NAND controller use an indexed mode to
* performed by writing the address value of the command * read/write data. The operation is performed by writing the address value
* to the device memory followed by the data. This function * of the command to the device memory followed by the data. This function
* abstracts this common operation. * abstracts this common operation.
*/ */
static void index_addr(struct denali_nand_info *denali, static void index_addr(struct denali_nand_info *denali,
uint32_t address, uint32_t data) uint32_t address, uint32_t data)
{ {
...@@ -116,8 +129,10 @@ static void index_addr_read_data(struct denali_nand_info *denali, ...@@ -116,8 +129,10 @@ static void index_addr_read_data(struct denali_nand_info *denali,
*pdata = ioread32(denali->flash_mem + 0x10); *pdata = ioread32(denali->flash_mem + 0x10);
} }
/* We need to buffer some data for some of the NAND core routines. /*
* The operations manage buffering that data. */ * We need to buffer some data for some of the NAND core routines.
* The operations manage buffering that data.
*/
static void reset_buf(struct denali_nand_info *denali) static void reset_buf(struct denali_nand_info *denali)
{ {
denali->buf.head = denali->buf.tail = 0; denali->buf.head = denali->buf.tail = 0;
...@@ -131,7 +146,7 @@ static void write_byte_to_buf(struct denali_nand_info *denali, uint8_t byte) ...@@ -131,7 +146,7 @@ static void write_byte_to_buf(struct denali_nand_info *denali, uint8_t byte)
/* reads the status of the device */ /* reads the status of the device */
static void read_status(struct denali_nand_info *denali) static void read_status(struct denali_nand_info *denali)
{ {
uint32_t cmd = 0x0; uint32_t cmd;
/* initialize the data buffer to store status */ /* initialize the data buffer to store status */
reset_buf(denali); reset_buf(denali);
...@@ -146,9 +161,8 @@ static void read_status(struct denali_nand_info *denali) ...@@ -146,9 +161,8 @@ static void read_status(struct denali_nand_info *denali)
/* resets a specific device connected to the core */ /* resets a specific device connected to the core */
static void reset_bank(struct denali_nand_info *denali) static void reset_bank(struct denali_nand_info *denali)
{ {
uint32_t irq_status = 0; uint32_t irq_status;
uint32_t irq_mask = INTR_STATUS__RST_COMP | uint32_t irq_mask = INTR_STATUS__RST_COMP | INTR_STATUS__TIME_OUT;
INTR_STATUS__TIME_OUT;
clear_interrupts(denali); clear_interrupts(denali);
...@@ -163,19 +177,18 @@ static void reset_bank(struct denali_nand_info *denali) ...@@ -163,19 +177,18 @@ static void reset_bank(struct denali_nand_info *denali)
/* Reset the flash controller */ /* Reset the flash controller */
static uint16_t denali_nand_reset(struct denali_nand_info *denali) static uint16_t denali_nand_reset(struct denali_nand_info *denali)
{ {
uint32_t i; int i;
dev_dbg(denali->dev, "%s, Line %d, Function: %s\n", dev_dbg(denali->dev, "%s, Line %d, Function: %s\n",
__FILE__, __LINE__, __func__); __FILE__, __LINE__, __func__);
for (i = 0 ; i < denali->max_banks; i++) for (i = 0; i < denali->max_banks; i++)
iowrite32(INTR_STATUS__RST_COMP | INTR_STATUS__TIME_OUT, iowrite32(INTR_STATUS__RST_COMP | INTR_STATUS__TIME_OUT,
denali->flash_reg + INTR_STATUS(i)); denali->flash_reg + INTR_STATUS(i));
for (i = 0 ; i < denali->max_banks; i++) { for (i = 0; i < denali->max_banks; i++) {
iowrite32(1 << i, denali->flash_reg + DEVICE_RESET); iowrite32(1 << i, denali->flash_reg + DEVICE_RESET);
while (!(ioread32(denali->flash_reg + while (!(ioread32(denali->flash_reg + INTR_STATUS(i)) &
INTR_STATUS(i)) &
(INTR_STATUS__RST_COMP | INTR_STATUS__TIME_OUT))) (INTR_STATUS__RST_COMP | INTR_STATUS__TIME_OUT)))
cpu_relax(); cpu_relax();
if (ioread32(denali->flash_reg + INTR_STATUS(i)) & if (ioread32(denali->flash_reg + INTR_STATUS(i)) &
...@@ -191,7 +204,8 @@ static uint16_t denali_nand_reset(struct denali_nand_info *denali) ...@@ -191,7 +204,8 @@ static uint16_t denali_nand_reset(struct denali_nand_info *denali)
return PASS; return PASS;
} }
/* this routine calculates the ONFI timing values for a given mode and /*
* this routine calculates the ONFI timing values for a given mode and
* programs the clocking register accordingly. The mode is determined by * programs the clocking register accordingly. The mode is determined by
* the get_onfi_nand_para routine. * the get_onfi_nand_para routine.
*/ */
...@@ -239,9 +253,8 @@ static void nand_onfi_timing_set(struct denali_nand_info *denali, ...@@ -239,9 +253,8 @@ static void nand_onfi_timing_set(struct denali_nand_info *denali,
data_invalid_rloh = (en_lo + en_hi) * CLK_X + Trloh[mode]; data_invalid_rloh = (en_lo + en_hi) * CLK_X + Trloh[mode];
data_invalid = data_invalid = data_invalid_rhoh < data_invalid_rloh ?
data_invalid_rhoh < data_invalid_rhoh : data_invalid_rloh;
data_invalid_rloh ? data_invalid_rhoh : data_invalid_rloh;
dv_window = data_invalid - Trea[mode]; dv_window = data_invalid - Trea[mode];
...@@ -251,10 +264,10 @@ static void nand_onfi_timing_set(struct denali_nand_info *denali, ...@@ -251,10 +264,10 @@ static void nand_onfi_timing_set(struct denali_nand_info *denali,
acc_clks = CEIL_DIV(Trea[mode], CLK_X); acc_clks = CEIL_DIV(Trea[mode], CLK_X);
while (((acc_clks * CLK_X) - Trea[mode]) < 3) while (acc_clks * CLK_X - Trea[mode] < 3)
acc_clks++; acc_clks++;
if ((data_invalid - acc_clks * CLK_X) < 2) if (data_invalid - acc_clks * CLK_X < 2)
dev_warn(denali->dev, "%s, Line %d: Warning!\n", dev_warn(denali->dev, "%s, Line %d: Warning!\n",
__FILE__, __LINE__); __FILE__, __LINE__);
...@@ -269,7 +282,7 @@ static void nand_onfi_timing_set(struct denali_nand_info *denali, ...@@ -269,7 +282,7 @@ static void nand_onfi_timing_set(struct denali_nand_info *denali,
cs_cnt = 1; cs_cnt = 1;
if (Tcea[mode]) { if (Tcea[mode]) {
while (((cs_cnt * CLK_X) + Trea[mode]) < Tcea[mode]) while (cs_cnt * CLK_X + Trea[mode] < Tcea[mode])
cs_cnt++; cs_cnt++;
} }
...@@ -279,8 +292,8 @@ static void nand_onfi_timing_set(struct denali_nand_info *denali, ...@@ -279,8 +292,8 @@ static void nand_onfi_timing_set(struct denali_nand_info *denali,
#endif #endif
/* Sighting 3462430: Temporary hack for MT29F128G08CJABAWP:B */ /* Sighting 3462430: Temporary hack for MT29F128G08CJABAWP:B */
if ((ioread32(denali->flash_reg + MANUFACTURER_ID) == 0) && if (ioread32(denali->flash_reg + MANUFACTURER_ID) == 0 &&
(ioread32(denali->flash_reg + DEVICE_ID) == 0x88)) ioread32(denali->flash_reg + DEVICE_ID) == 0x88)
acc_clks = 6; acc_clks = 6;
iowrite32(acc_clks, denali->flash_reg + ACC_CLKS); iowrite32(acc_clks, denali->flash_reg + ACC_CLKS);
...@@ -297,9 +310,11 @@ static void nand_onfi_timing_set(struct denali_nand_info *denali, ...@@ -297,9 +310,11 @@ static void nand_onfi_timing_set(struct denali_nand_info *denali,
static uint16_t get_onfi_nand_para(struct denali_nand_info *denali) static uint16_t get_onfi_nand_para(struct denali_nand_info *denali)
{ {
int i; int i;
/* we needn't to do a reset here because driver has already
/*
* we needn't to do a reset here because driver has already
* reset all the banks before * reset all the banks before
* */ */
if (!(ioread32(denali->flash_reg + ONFI_TIMING_MODE) & if (!(ioread32(denali->flash_reg + ONFI_TIMING_MODE) &
ONFI_TIMING_MODE__VALUE)) ONFI_TIMING_MODE__VALUE))
return FAIL; return FAIL;
...@@ -312,8 +327,10 @@ static uint16_t get_onfi_nand_para(struct denali_nand_info *denali) ...@@ -312,8 +327,10 @@ static uint16_t get_onfi_nand_para(struct denali_nand_info *denali)
nand_onfi_timing_set(denali, i); nand_onfi_timing_set(denali, i);
/* By now, all the ONFI devices we know support the page cache */ /*
/* rw feature. So here we enable the pipeline_rw_ahead feature */ * By now, all the ONFI devices we know support the page cache
* rw feature. So here we enable the pipeline_rw_ahead feature
*/
/* iowrite32(1, denali->flash_reg + CACHE_WRITE_ENABLE); */ /* iowrite32(1, denali->flash_reg + CACHE_WRITE_ENABLE); */
/* iowrite32(1, denali->flash_reg + CACHE_READ_ENABLE); */ /* iowrite32(1, denali->flash_reg + CACHE_READ_ENABLE); */
...@@ -339,8 +356,10 @@ static void get_toshiba_nand_para(struct denali_nand_info *denali) ...@@ -339,8 +356,10 @@ static void get_toshiba_nand_para(struct denali_nand_info *denali)
{ {
uint32_t tmp; uint32_t tmp;
/* Workaround to fix a controller bug which reports a wrong */ /*
/* spare area size for some kind of Toshiba NAND device */ * Workaround to fix a controller bug which reports a wrong
* spare area size for some kind of Toshiba NAND device
*/
if ((ioread32(denali->flash_reg + DEVICE_MAIN_AREA_SIZE) == 4096) && if ((ioread32(denali->flash_reg + DEVICE_MAIN_AREA_SIZE) == 4096) &&
(ioread32(denali->flash_reg + DEVICE_SPARE_AREA_SIZE) == 64)) { (ioread32(denali->flash_reg + DEVICE_SPARE_AREA_SIZE) == 64)) {
iowrite32(216, denali->flash_reg + DEVICE_SPARE_AREA_SIZE); iowrite32(216, denali->flash_reg + DEVICE_SPARE_AREA_SIZE);
...@@ -384,13 +403,14 @@ static void get_hynix_nand_para(struct denali_nand_info *denali, ...@@ -384,13 +403,14 @@ static void get_hynix_nand_para(struct denali_nand_info *denali,
break; break;
default: default:
dev_warn(denali->dev, dev_warn(denali->dev,
"Spectra: Unknown Hynix NAND (Device ID: 0x%x)." "Spectra: Unknown Hynix NAND (Device ID: 0x%x).\n"
"Will use default parameter values instead.\n", "Will use default parameter values instead.\n",
device_id); device_id);
} }
} }
/* determines how many NAND chips are connected to the controller. Note for /*
* determines how many NAND chips are connected to the controller. Note for
* Intel CE4100 devices we don't support more than one device. * Intel CE4100 devices we don't support more than one device.
*/ */
static void find_valid_banks(struct denali_nand_info *denali) static void find_valid_banks(struct denali_nand_info *denali)
...@@ -400,10 +420,9 @@ static void find_valid_banks(struct denali_nand_info *denali) ...@@ -400,10 +420,9 @@ static void find_valid_banks(struct denali_nand_info *denali)
denali->total_used_banks = 1; denali->total_used_banks = 1;
for (i = 0; i < denali->max_banks; i++) { for (i = 0; i < denali->max_banks; i++) {
index_addr(denali, (uint32_t)(MODE_11 | (i << 24) | 0), 0x90); index_addr(denali, MODE_11 | (i << 24) | 0, 0x90);
index_addr(denali, (uint32_t)(MODE_11 | (i << 24) | 1), 0); index_addr(denali, MODE_11 | (i << 24) | 1, 0);
index_addr_read_data(denali, index_addr_read_data(denali, MODE_11 | (i << 24) | 2, &id[i]);
(uint32_t)(MODE_11 | (i << 24) | 2), &id[i]);
dev_dbg(denali->dev, dev_dbg(denali->dev,
"Return 1st ID for bank[%d]: %x\n", i, id[i]); "Return 1st ID for bank[%d]: %x\n", i, id[i]);
...@@ -420,14 +439,14 @@ static void find_valid_banks(struct denali_nand_info *denali) ...@@ -420,14 +439,14 @@ static void find_valid_banks(struct denali_nand_info *denali)
} }
if (denali->platform == INTEL_CE4100) { if (denali->platform == INTEL_CE4100) {
/* Platform limitations of the CE4100 device limit /*
* Platform limitations of the CE4100 device limit
* users to a single chip solution for NAND. * users to a single chip solution for NAND.
* Multichip support is not enabled. * Multichip support is not enabled.
*/ */
if (denali->total_used_banks != 1) { if (denali->total_used_banks != 1) {
dev_err(denali->dev, dev_err(denali->dev,
"Sorry, Intel CE4100 only supports " "Sorry, Intel CE4100 only supports a single NAND device.\n");
"a single NAND device.\n");
BUG(); BUG();
} }
} }
...@@ -448,12 +467,13 @@ static void detect_max_banks(struct denali_nand_info *denali) ...@@ -448,12 +467,13 @@ static void detect_max_banks(struct denali_nand_info *denali)
static void detect_partition_feature(struct denali_nand_info *denali) static void detect_partition_feature(struct denali_nand_info *denali)
{ {
/* For MRST platform, denali->fwblks represent the /*
* For MRST platform, denali->fwblks represent the
* number of blocks firmware is taken, * number of blocks firmware is taken,
* FW is in protect partition and MTD driver has no * FW is in protect partition and MTD driver has no
* permission to access it. So let driver know how many * permission to access it. So let driver know how many
* blocks it can't touch. * blocks it can't touch.
* */ */
if (ioread32(denali->flash_reg + FEATURES) & FEATURES__PARTITION) { if (ioread32(denali->flash_reg + FEATURES) & FEATURES__PARTITION) {
if ((ioread32(denali->flash_reg + PERM_SRC_ID(1)) & if ((ioread32(denali->flash_reg + PERM_SRC_ID(1)) &
PERM_SRC_ID__SRCID) == SPECTRA_PARTITION_ID) { PERM_SRC_ID__SRCID) == SPECTRA_PARTITION_ID) {
...@@ -464,30 +484,32 @@ static void detect_partition_feature(struct denali_nand_info *denali) ...@@ -464,30 +484,32 @@ static void detect_partition_feature(struct denali_nand_info *denali)
+ +
(ioread32(denali->flash_reg + MIN_BLK_ADDR(1)) & (ioread32(denali->flash_reg + MIN_BLK_ADDR(1)) &
MIN_BLK_ADDR__VALUE); MIN_BLK_ADDR__VALUE);
} else } else {
denali->fwblks = SPECTRA_START_BLOCK; denali->fwblks = SPECTRA_START_BLOCK;
} else }
} else {
denali->fwblks = SPECTRA_START_BLOCK; denali->fwblks = SPECTRA_START_BLOCK;
}
} }
static uint16_t denali_nand_timing_set(struct denali_nand_info *denali) static uint16_t denali_nand_timing_set(struct denali_nand_info *denali)
{ {
uint16_t status = PASS; uint16_t status = PASS;
uint32_t id_bytes[8], addr; uint32_t id_bytes[8], addr;
uint8_t i, maf_id, device_id; uint8_t maf_id, device_id;
int i;
dev_dbg(denali->dev, dev_dbg(denali->dev, "%s, Line %d, Function: %s\n",
"%s, Line %d, Function: %s\n",
__FILE__, __LINE__, __func__); __FILE__, __LINE__, __func__);
/* Use read id method to get device ID and other /*
* params. For some NAND chips, controller can't * Use read id method to get device ID and other params.
* report the correct device ID by reading from * For some NAND chips, controller can't report the correct
* DEVICE_ID register * device ID by reading from DEVICE_ID register
* */ */
addr = (uint32_t)MODE_11 | BANK(denali->flash_bank); addr = MODE_11 | BANK(denali->flash_bank);
index_addr(denali, (uint32_t)addr | 0, 0x90); index_addr(denali, addr | 0, 0x90);
index_addr(denali, (uint32_t)addr | 1, 0); index_addr(denali, addr | 1, 0);
for (i = 0; i < 8; i++) for (i = 0; i < 8; i++)
index_addr_read_data(denali, addr | 2, &id_bytes[i]); index_addr_read_data(denali, addr | 2, &id_bytes[i]);
maf_id = id_bytes[0]; maf_id = id_bytes[0];
...@@ -506,7 +528,7 @@ static uint16_t denali_nand_timing_set(struct denali_nand_info *denali) ...@@ -506,7 +528,7 @@ static uint16_t denali_nand_timing_set(struct denali_nand_info *denali)
} }
dev_info(denali->dev, dev_info(denali->dev,
"Dump timing register values:" "Dump timing register values:\n"
"acc_clks: %d, re_2_we: %d, re_2_re: %d\n" "acc_clks: %d, re_2_we: %d, re_2_re: %d\n"
"we_2_re: %d, addr_2_data: %d, rdwr_en_lo_cnt: %d\n" "we_2_re: %d, addr_2_data: %d, rdwr_en_lo_cnt: %d\n"
"rdwr_en_hi_cnt: %d, cs_setup_cnt: %d\n", "rdwr_en_hi_cnt: %d, cs_setup_cnt: %d\n",
...@@ -523,7 +545,8 @@ static uint16_t denali_nand_timing_set(struct denali_nand_info *denali) ...@@ -523,7 +545,8 @@ static uint16_t denali_nand_timing_set(struct denali_nand_info *denali)
detect_partition_feature(denali); detect_partition_feature(denali);
/* If the user specified to override the default timings /*
* If the user specified to override the default timings
* with a specific ONFI mode, we apply those changes here. * with a specific ONFI mode, we apply those changes here.
*/ */
if (onfi_timing_mode != NAND_DEFAULT_TIMINGS) if (onfi_timing_mode != NAND_DEFAULT_TIMINGS)
...@@ -544,17 +567,18 @@ static void denali_set_intr_modes(struct denali_nand_info *denali, ...@@ -544,17 +567,18 @@ static void denali_set_intr_modes(struct denali_nand_info *denali,
iowrite32(0, denali->flash_reg + GLOBAL_INT_ENABLE); iowrite32(0, denali->flash_reg + GLOBAL_INT_ENABLE);
} }
/* validation function to verify that the controlling software is making /*
* validation function to verify that the controlling software is making
* a valid request * a valid request
*/ */
static inline bool is_flash_bank_valid(int flash_bank) static inline bool is_flash_bank_valid(int flash_bank)
{ {
return (flash_bank >= 0 && flash_bank < 4); return flash_bank >= 0 && flash_bank < 4;
} }
static void denali_irq_init(struct denali_nand_info *denali) static void denali_irq_init(struct denali_nand_info *denali)
{ {
uint32_t int_mask = 0; uint32_t int_mask;
int i; int i;
/* Disable global interrupts */ /* Disable global interrupts */
...@@ -584,7 +608,8 @@ static void denali_irq_enable(struct denali_nand_info *denali, ...@@ -584,7 +608,8 @@ static void denali_irq_enable(struct denali_nand_info *denali,
iowrite32(int_mask, denali->flash_reg + INTR_EN(i)); iowrite32(int_mask, denali->flash_reg + INTR_EN(i));
} }
/* This function only returns when an interrupt that this driver cares about /*
* This function only returns when an interrupt that this driver cares about
* occurs. This is to reduce the overhead of servicing interrupts * occurs. This is to reduce the overhead of servicing interrupts
*/ */
static inline uint32_t denali_irq_detected(struct denali_nand_info *denali) static inline uint32_t denali_irq_detected(struct denali_nand_info *denali)
...@@ -596,7 +621,7 @@ static inline uint32_t denali_irq_detected(struct denali_nand_info *denali) ...@@ -596,7 +621,7 @@ static inline uint32_t denali_irq_detected(struct denali_nand_info *denali)
static inline void clear_interrupt(struct denali_nand_info *denali, static inline void clear_interrupt(struct denali_nand_info *denali,
uint32_t irq_mask) uint32_t irq_mask)
{ {
uint32_t intr_status_reg = 0; uint32_t intr_status_reg;
intr_status_reg = INTR_STATUS(denali->flash_bank); intr_status_reg = INTR_STATUS(denali->flash_bank);
...@@ -605,7 +630,8 @@ static inline void clear_interrupt(struct denali_nand_info *denali, ...@@ -605,7 +630,8 @@ static inline void clear_interrupt(struct denali_nand_info *denali,
static void clear_interrupts(struct denali_nand_info *denali) static void clear_interrupts(struct denali_nand_info *denali)
{ {
uint32_t status = 0x0; uint32_t status;
spin_lock_irq(&denali->irq_lock); spin_lock_irq(&denali->irq_lock);
status = read_interrupt_status(denali); status = read_interrupt_status(denali);
...@@ -617,38 +643,40 @@ static void clear_interrupts(struct denali_nand_info *denali) ...@@ -617,38 +643,40 @@ static void clear_interrupts(struct denali_nand_info *denali)
static uint32_t read_interrupt_status(struct denali_nand_info *denali) static uint32_t read_interrupt_status(struct denali_nand_info *denali)
{ {
uint32_t intr_status_reg = 0; uint32_t intr_status_reg;
intr_status_reg = INTR_STATUS(denali->flash_bank); intr_status_reg = INTR_STATUS(denali->flash_bank);
return ioread32(denali->flash_reg + intr_status_reg); return ioread32(denali->flash_reg + intr_status_reg);
} }
/* This is the interrupt service routine. It handles all interrupts /*
* sent to this device. Note that on CE4100, this is a shared * This is the interrupt service routine. It handles all interrupts
* interrupt. * sent to this device. Note that on CE4100, this is a shared interrupt.
*/ */
static irqreturn_t denali_isr(int irq, void *dev_id) static irqreturn_t denali_isr(int irq, void *dev_id)
{ {
struct denali_nand_info *denali = dev_id; struct denali_nand_info *denali = dev_id;
uint32_t irq_status = 0x0; uint32_t irq_status;
irqreturn_t result = IRQ_NONE; irqreturn_t result = IRQ_NONE;
spin_lock(&denali->irq_lock); spin_lock(&denali->irq_lock);
/* check to see if a valid NAND chip has /* check to see if a valid NAND chip has been selected. */
* been selected.
*/
if (is_flash_bank_valid(denali->flash_bank)) { if (is_flash_bank_valid(denali->flash_bank)) {
/* check to see if controller generated /*
* the interrupt, since this is a shared interrupt */ * check to see if controller generated the interrupt,
* since this is a shared interrupt
*/
irq_status = denali_irq_detected(denali); irq_status = denali_irq_detected(denali);
if (irq_status != 0) { if (irq_status != 0) {
/* handle interrupt */ /* handle interrupt */
/* first acknowledge it */ /* first acknowledge it */
clear_interrupt(denali, irq_status); clear_interrupt(denali, irq_status);
/* store the status in the device context for someone /*
to read */ * store the status in the device context for someone
* to read
*/
denali->irq_status |= irq_status; denali->irq_status |= irq_status;
/* notify anyone who cares that it happened */ /* notify anyone who cares that it happened */
complete(&denali->complete); complete(&denali->complete);
...@@ -663,9 +691,8 @@ static irqreturn_t denali_isr(int irq, void *dev_id) ...@@ -663,9 +691,8 @@ static irqreturn_t denali_isr(int irq, void *dev_id)
static uint32_t wait_for_irq(struct denali_nand_info *denali, uint32_t irq_mask) static uint32_t wait_for_irq(struct denali_nand_info *denali, uint32_t irq_mask)
{ {
unsigned long comp_res = 0; unsigned long comp_res;
uint32_t intr_status = 0; uint32_t intr_status;
bool retry = false;
unsigned long timeout = msecs_to_jiffies(1000); unsigned long timeout = msecs_to_jiffies(1000);
do { do {
...@@ -679,12 +706,13 @@ static uint32_t wait_for_irq(struct denali_nand_info *denali, uint32_t irq_mask) ...@@ -679,12 +706,13 @@ static uint32_t wait_for_irq(struct denali_nand_info *denali, uint32_t irq_mask)
spin_unlock_irq(&denali->irq_lock); spin_unlock_irq(&denali->irq_lock);
/* our interrupt was detected */ /* our interrupt was detected */
break; break;
} else {
/* these are not the interrupts you are looking for -
* need to wait again */
spin_unlock_irq(&denali->irq_lock);
retry = true;
} }
/*
* these are not the interrupts you are looking for -
* need to wait again
*/
spin_unlock_irq(&denali->irq_lock);
} while (comp_res != 0); } while (comp_res != 0);
if (comp_res == 0) { if (comp_res == 0) {
...@@ -697,12 +725,14 @@ static uint32_t wait_for_irq(struct denali_nand_info *denali, uint32_t irq_mask) ...@@ -697,12 +725,14 @@ static uint32_t wait_for_irq(struct denali_nand_info *denali, uint32_t irq_mask)
return intr_status; return intr_status;
} }
/* This helper function setups the registers for ECC and whether or not /*
* the spare area will be transferred. */ * This helper function setups the registers for ECC and whether or not
* the spare area will be transferred.
*/
static void setup_ecc_for_xfer(struct denali_nand_info *denali, bool ecc_en, static void setup_ecc_for_xfer(struct denali_nand_info *denali, bool ecc_en,
bool transfer_spare) bool transfer_spare)
{ {
int ecc_en_flag = 0, transfer_spare_flag = 0; int ecc_en_flag, transfer_spare_flag;
/* set ECC, transfer spare bits if needed */ /* set ECC, transfer spare bits if needed */
ecc_en_flag = ecc_en ? ECC_ENABLE__FLAG : 0; ecc_en_flag = ecc_en ? ECC_ENABLE__FLAG : 0;
...@@ -710,22 +740,20 @@ static void setup_ecc_for_xfer(struct denali_nand_info *denali, bool ecc_en, ...@@ -710,22 +740,20 @@ static void setup_ecc_for_xfer(struct denali_nand_info *denali, bool ecc_en,
/* Enable spare area/ECC per user's request. */ /* Enable spare area/ECC per user's request. */
iowrite32(ecc_en_flag, denali->flash_reg + ECC_ENABLE); iowrite32(ecc_en_flag, denali->flash_reg + ECC_ENABLE);
iowrite32(transfer_spare_flag, iowrite32(transfer_spare_flag, denali->flash_reg + TRANSFER_SPARE_REG);
denali->flash_reg + TRANSFER_SPARE_REG);
} }
/* sends a pipeline command operation to the controller. See the Denali NAND /*
* sends a pipeline command operation to the controller. See the Denali NAND
* controller's user guide for more information (section 4.2.3.6). * controller's user guide for more information (section 4.2.3.6).
*/ */
static int denali_send_pipeline_cmd(struct denali_nand_info *denali, static int denali_send_pipeline_cmd(struct denali_nand_info *denali,
bool ecc_en, bool ecc_en, bool transfer_spare,
bool transfer_spare, int access_type, int op)
int access_type,
int op)
{ {
int status = PASS; int status = PASS;
uint32_t addr = 0x0, cmd = 0x0, page_count = 1, irq_status = 0, uint32_t page_count = 1;
irq_mask = 0; uint32_t addr, cmd, irq_status, irq_mask;
if (op == DENALI_READ) if (op == DENALI_READ)
irq_mask = INTR_STATUS__LOAD_COMP; irq_mask = INTR_STATUS__LOAD_COMP;
...@@ -736,7 +764,6 @@ static int denali_send_pipeline_cmd(struct denali_nand_info *denali, ...@@ -736,7 +764,6 @@ static int denali_send_pipeline_cmd(struct denali_nand_info *denali,
setup_ecc_for_xfer(denali, ecc_en, transfer_spare); setup_ecc_for_xfer(denali, ecc_en, transfer_spare);
/* clear interrupts */
clear_interrupts(denali); clear_interrupts(denali);
addr = BANK(denali->flash_bank) | denali->page; addr = BANK(denali->flash_bank) | denali->page;
...@@ -747,36 +774,37 @@ static int denali_send_pipeline_cmd(struct denali_nand_info *denali, ...@@ -747,36 +774,37 @@ static int denali_send_pipeline_cmd(struct denali_nand_info *denali,
} else if (op == DENALI_WRITE && access_type == SPARE_ACCESS) { } else if (op == DENALI_WRITE && access_type == SPARE_ACCESS) {
/* read spare area */ /* read spare area */
cmd = MODE_10 | addr; cmd = MODE_10 | addr;
index_addr(denali, (uint32_t)cmd, access_type); index_addr(denali, cmd, access_type);
cmd = MODE_01 | addr; cmd = MODE_01 | addr;
iowrite32(cmd, denali->flash_mem); iowrite32(cmd, denali->flash_mem);
} else if (op == DENALI_READ) { } else if (op == DENALI_READ) {
/* setup page read request for access type */ /* setup page read request for access type */
cmd = MODE_10 | addr; cmd = MODE_10 | addr;
index_addr(denali, (uint32_t)cmd, access_type); index_addr(denali, cmd, access_type);
/* page 33 of the NAND controller spec indicates we should not /*
use the pipeline commands in Spare area only mode. So we * page 33 of the NAND controller spec indicates we should not
don't. * use the pipeline commands in Spare area only mode.
* So we don't.
*/ */
if (access_type == SPARE_ACCESS) { if (access_type == SPARE_ACCESS) {
cmd = MODE_01 | addr; cmd = MODE_01 | addr;
iowrite32(cmd, denali->flash_mem); iowrite32(cmd, denali->flash_mem);
} else { } else {
index_addr(denali, (uint32_t)cmd, index_addr(denali, cmd,
0x2000 | op | page_count); PIPELINE_ACCESS | op | page_count);
/* wait for command to be accepted /*
* wait for command to be accepted
* can always use status0 bit as the * can always use status0 bit as the
* mask is identical for each * mask is identical for each bank.
* bank. */ */
irq_status = wait_for_irq(denali, irq_mask); irq_status = wait_for_irq(denali, irq_mask);
if (irq_status == 0) { if (irq_status == 0) {
dev_err(denali->dev, dev_err(denali->dev,
"cmd, page, addr on timeout " "cmd, page, addr on timeout (0x%x, 0x%x, 0x%x)\n",
"(0x%x, 0x%x, 0x%x)\n",
cmd, denali->page, addr); cmd, denali->page, addr);
status = FAIL; status = FAIL;
} else { } else {
...@@ -790,51 +818,51 @@ static int denali_send_pipeline_cmd(struct denali_nand_info *denali, ...@@ -790,51 +818,51 @@ static int denali_send_pipeline_cmd(struct denali_nand_info *denali,
/* helper function that simply writes a buffer to the flash */ /* helper function that simply writes a buffer to the flash */
static int write_data_to_flash_mem(struct denali_nand_info *denali, static int write_data_to_flash_mem(struct denali_nand_info *denali,
const uint8_t *buf, const uint8_t *buf, int len)
int len)
{ {
uint32_t i = 0, *buf32; uint32_t *buf32;
int i;
/* verify that the len is a multiple of 4. see comment in /*
* read_data_from_flash_mem() */ * verify that the len is a multiple of 4.
* see comment in read_data_from_flash_mem()
*/
BUG_ON((len % 4) != 0); BUG_ON((len % 4) != 0);
/* write the data to the flash memory */ /* write the data to the flash memory */
buf32 = (uint32_t *)buf; buf32 = (uint32_t *)buf;
for (i = 0; i < len / 4; i++) for (i = 0; i < len / 4; i++)
iowrite32(*buf32++, denali->flash_mem + 0x10); iowrite32(*buf32++, denali->flash_mem + 0x10);
return i*4; /* intent is to return the number of bytes read */ return i * 4; /* intent is to return the number of bytes read */
} }
/* helper function that simply reads a buffer from the flash */ /* helper function that simply reads a buffer from the flash */
static int read_data_from_flash_mem(struct denali_nand_info *denali, static int read_data_from_flash_mem(struct denali_nand_info *denali,
uint8_t *buf, uint8_t *buf, int len)
int len)
{ {
uint32_t i = 0, *buf32; uint32_t *buf32;
int i;
/* we assume that len will be a multiple of 4, if not
* it would be nice to know about it ASAP rather than
* have random failures...
* This assumption is based on the fact that this
* function is designed to be used to read flash pages,
* which are typically multiples of 4...
*/
/*
* we assume that len will be a multiple of 4, if not it would be nice
* to know about it ASAP rather than have random failures...
* This assumption is based on the fact that this function is designed
* to be used to read flash pages, which are typically multiples of 4.
*/
BUG_ON((len % 4) != 0); BUG_ON((len % 4) != 0);
/* transfer the data from the flash */ /* transfer the data from the flash */
buf32 = (uint32_t *)buf; buf32 = (uint32_t *)buf;
for (i = 0; i < len / 4; i++) for (i = 0; i < len / 4; i++)
*buf32++ = ioread32(denali->flash_mem + 0x10); *buf32++ = ioread32(denali->flash_mem + 0x10);
return i*4; /* intent is to return the number of bytes read */ return i * 4; /* intent is to return the number of bytes read */
} }
/* writes OOB data to the device */ /* writes OOB data to the device */
static int write_oob_data(struct mtd_info *mtd, uint8_t *buf, int page) static int write_oob_data(struct mtd_info *mtd, uint8_t *buf, int page)
{ {
struct denali_nand_info *denali = mtd_to_denali(mtd); struct denali_nand_info *denali = mtd_to_denali(mtd);
uint32_t irq_status = 0; uint32_t irq_status;
uint32_t irq_mask = INTR_STATUS__PROGRAM_COMP | uint32_t irq_mask = INTR_STATUS__PROGRAM_COMP |
INTR_STATUS__PROGRAM_FAIL; INTR_STATUS__PROGRAM_FAIL;
int status = 0; int status = 0;
...@@ -863,8 +891,8 @@ static int write_oob_data(struct mtd_info *mtd, uint8_t *buf, int page) ...@@ -863,8 +891,8 @@ static int write_oob_data(struct mtd_info *mtd, uint8_t *buf, int page)
static void read_oob_data(struct mtd_info *mtd, uint8_t *buf, int page) static void read_oob_data(struct mtd_info *mtd, uint8_t *buf, int page)
{ {
struct denali_nand_info *denali = mtd_to_denali(mtd); struct denali_nand_info *denali = mtd_to_denali(mtd);
uint32_t irq_mask = INTR_STATUS__LOAD_COMP, uint32_t irq_mask = INTR_STATUS__LOAD_COMP;
irq_status = 0, addr = 0x0, cmd = 0x0; uint32_t irq_status, addr, cmd;
denali->page = page; denali->page = page;
...@@ -872,16 +900,19 @@ static void read_oob_data(struct mtd_info *mtd, uint8_t *buf, int page) ...@@ -872,16 +900,19 @@ static void read_oob_data(struct mtd_info *mtd, uint8_t *buf, int page)
DENALI_READ) == PASS) { DENALI_READ) == PASS) {
read_data_from_flash_mem(denali, buf, mtd->oobsize); read_data_from_flash_mem(denali, buf, mtd->oobsize);
/* wait for command to be accepted /*
* can always use status0 bit as the mask is identical for each * wait for command to be accepted
* bank. */ * can always use status0 bit as the
* mask is identical for each bank.
*/
irq_status = wait_for_irq(denali, irq_mask); irq_status = wait_for_irq(denali, irq_mask);
if (irq_status == 0) if (irq_status == 0)
dev_err(denali->dev, "page on OOB timeout %d\n", dev_err(denali->dev, "page on OOB timeout %d\n",
denali->page); denali->page);
/* We set the device back to MAIN_ACCESS here as I observed /*
* We set the device back to MAIN_ACCESS here as I observed
* instability with the controller if you do a block erase * instability with the controller if you do a block erase
* and the last transaction was a SPARE_ACCESS. Block erase * and the last transaction was a SPARE_ACCESS. Block erase
* is reliable (according to the MTD test infrastructure) * is reliable (according to the MTD test infrastructure)
...@@ -889,16 +920,18 @@ static void read_oob_data(struct mtd_info *mtd, uint8_t *buf, int page) ...@@ -889,16 +920,18 @@ static void read_oob_data(struct mtd_info *mtd, uint8_t *buf, int page)
*/ */
addr = BANK(denali->flash_bank) | denali->page; addr = BANK(denali->flash_bank) | denali->page;
cmd = MODE_10 | addr; cmd = MODE_10 | addr;
index_addr(denali, (uint32_t)cmd, MAIN_ACCESS); index_addr(denali, cmd, MAIN_ACCESS);
} }
} }
/* this function examines buffers to see if they contain data that /*
* this function examines buffers to see if they contain data that
* indicate that the buffer is part of an erased region of flash. * indicate that the buffer is part of an erased region of flash.
*/ */
static bool is_erased(uint8_t *buf, int len) static bool is_erased(uint8_t *buf, int len)
{ {
int i = 0; int i;
for (i = 0; i < len; i++) for (i = 0; i < len; i++)
if (buf[i] != 0xFF) if (buf[i] != 0xFF)
return false; return false;
...@@ -921,9 +954,8 @@ static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf, ...@@ -921,9 +954,8 @@ static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf,
if (irq_status & INTR_STATUS__ECC_ERR) { if (irq_status & INTR_STATUS__ECC_ERR) {
/* read the ECC errors. we'll ignore them for now */ /* read the ECC errors. we'll ignore them for now */
uint32_t err_address = 0, err_correction_info = 0; uint32_t err_address, err_correction_info, err_byte,
uint32_t err_byte = 0, err_sector = 0, err_device = 0; err_sector, err_device, err_correction_value;
uint32_t err_correction_value = 0;
denali_set_intr_modes(denali, false); denali_set_intr_modes(denali, false);
do { do {
...@@ -939,15 +971,17 @@ static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf, ...@@ -939,15 +971,17 @@ static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf,
err_device = ECC_ERR_DEVICE(err_correction_info); err_device = ECC_ERR_DEVICE(err_correction_info);
if (ECC_ERROR_CORRECTABLE(err_correction_info)) { if (ECC_ERROR_CORRECTABLE(err_correction_info)) {
/* If err_byte is larger than ECC_SECTOR_SIZE, /*
* If err_byte is larger than ECC_SECTOR_SIZE,
* means error happened in OOB, so we ignore * means error happened in OOB, so we ignore
* it. It's no need for us to correct it * it. It's no need for us to correct it
* err_device is represented the NAND error * err_device is represented the NAND error
* bits are happened in if there are more * bits are happened in if there are more
* than one NAND connected. * than one NAND connected.
* */ */
if (err_byte < ECC_SECTOR_SIZE) { if (err_byte < ECC_SECTOR_SIZE) {
int offset; int offset;
offset = (err_sector * offset = (err_sector *
ECC_SECTOR_SIZE + ECC_SECTOR_SIZE +
err_byte) * err_byte) *
...@@ -959,17 +993,19 @@ static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf, ...@@ -959,17 +993,19 @@ static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf,
bitflips++; bitflips++;
} }
} else { } else {
/* if the error is not correctable, need to /*
* if the error is not correctable, need to
* look at the page to see if it is an erased * look at the page to see if it is an erased
* page. if so, then it's not a real ECC error * page. if so, then it's not a real ECC error
* */ */
check_erased_page = true; check_erased_page = true;
} }
} while (!ECC_LAST_ERR(err_correction_info)); } while (!ECC_LAST_ERR(err_correction_info));
/* Once handle all ecc errors, controller will triger /*
* Once handle all ecc errors, controller will triger
* a ECC_TRANSACTION_DONE interrupt, so here just wait * a ECC_TRANSACTION_DONE interrupt, so here just wait
* for a while for this interrupt * for a while for this interrupt
* */ */
while (!(read_interrupt_status(denali) & while (!(read_interrupt_status(denali) &
INTR_STATUS__ECC_TRANSACTION_DONE)) INTR_STATUS__ECC_TRANSACTION_DONE))
cpu_relax(); cpu_relax();
...@@ -983,21 +1019,16 @@ static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf, ...@@ -983,21 +1019,16 @@ static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf,
/* programs the controller to either enable/disable DMA transfers */ /* programs the controller to either enable/disable DMA transfers */
static void denali_enable_dma(struct denali_nand_info *denali, bool en) static void denali_enable_dma(struct denali_nand_info *denali, bool en)
{ {
uint32_t reg_val = 0x0; iowrite32(en ? DMA_ENABLE__FLAG : 0, denali->flash_reg + DMA_ENABLE);
if (en)
reg_val = DMA_ENABLE__FLAG;
iowrite32(reg_val, denali->flash_reg + DMA_ENABLE);
ioread32(denali->flash_reg + DMA_ENABLE); ioread32(denali->flash_reg + DMA_ENABLE);
} }
/* setups the HW to perform the data DMA */ /* setups the HW to perform the data DMA */
static void denali_setup_dma(struct denali_nand_info *denali, int op) static void denali_setup_dma(struct denali_nand_info *denali, int op)
{ {
uint32_t mode = 0x0; uint32_t mode;
const int page_count = 1; const int page_count = 1;
dma_addr_t addr = denali->buf.dma_buf; uint32_t addr = denali->buf.dma_buf;
mode = MODE_10 | BANK(denali->flash_bank); mode = MODE_10 | BANK(denali->flash_bank);
...@@ -1007,31 +1038,31 @@ static void denali_setup_dma(struct denali_nand_info *denali, int op) ...@@ -1007,31 +1038,31 @@ static void denali_setup_dma(struct denali_nand_info *denali, int op)
index_addr(denali, mode | denali->page, 0x2000 | op | page_count); index_addr(denali, mode | denali->page, 0x2000 | op | page_count);
/* 2. set memory high address bits 23:8 */ /* 2. set memory high address bits 23:8 */
index_addr(denali, mode | ((uint16_t)(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 | ((uint16_t)addr << 8), 0x2300); index_addr(denali, mode | ((addr & 0xff) << 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);
} }
/* writes a page. user specifies type, and this function handles the /*
* configuration details. */ * writes a page. user specifies type, and this function handles the
* configuration details.
*/
static int write_page(struct mtd_info *mtd, struct nand_chip *chip, static int write_page(struct mtd_info *mtd, struct nand_chip *chip,
const uint8_t *buf, bool raw_xfer) const uint8_t *buf, bool raw_xfer)
{ {
struct denali_nand_info *denali = mtd_to_denali(mtd); struct denali_nand_info *denali = mtd_to_denali(mtd);
dma_addr_t addr = denali->buf.dma_buf; dma_addr_t addr = denali->buf.dma_buf;
size_t size = denali->mtd.writesize + denali->mtd.oobsize; size_t size = denali->mtd.writesize + denali->mtd.oobsize;
uint32_t irq_status;
uint32_t irq_status = 0;
uint32_t irq_mask = INTR_STATUS__DMA_CMD_COMP | uint32_t irq_mask = INTR_STATUS__DMA_CMD_COMP |
INTR_STATUS__PROGRAM_FAIL; INTR_STATUS__PROGRAM_FAIL;
/* if it is a raw xfer, we want to disable ecc, and send /*
* the spare area. * if it is a raw xfer, we want to disable ecc and send the spare area.
* !raw_xfer - enable ecc * !raw_xfer - enable ecc
* raw_xfer - transfer spare * raw_xfer - transfer spare
*/ */
...@@ -1058,12 +1089,9 @@ static int write_page(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -1058,12 +1089,9 @@ static int write_page(struct mtd_info *mtd, struct nand_chip *chip,
irq_status = wait_for_irq(denali, irq_mask); irq_status = wait_for_irq(denali, irq_mask);
if (irq_status == 0) { if (irq_status == 0) {
dev_err(denali->dev, dev_err(denali->dev, "timeout on write_page (type = %d)\n",
"timeout on write_page (type = %d)\n",
raw_xfer); raw_xfer);
denali->status = denali->status = NAND_STATUS_FAIL;
(irq_status & INTR_STATUS__PROGRAM_FAIL) ?
NAND_STATUS_FAIL : PASS;
} }
denali_enable_dma(denali, false); denali_enable_dma(denali, false);
...@@ -1074,27 +1102,33 @@ static int write_page(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -1074,27 +1102,33 @@ static int write_page(struct mtd_info *mtd, struct nand_chip *chip,
/* NAND core entry points */ /* NAND core entry points */
/* this is the callback that the NAND core calls to write a page. Since /*
* this is the callback that the NAND core calls to write a page. Since
* writing a page with ECC or without is similar, all the work is done * writing a page with ECC or without is similar, all the work is done
* by write_page above. * by write_page above.
* */ */
static int denali_write_page(struct mtd_info *mtd, struct nand_chip *chip, static int denali_write_page(struct mtd_info *mtd, struct nand_chip *chip,
const uint8_t *buf, int oob_required) const uint8_t *buf, int oob_required)
{ {
/* for regular page writes, we let HW handle all the ECC /*
* data written to the device. */ * for regular page writes, we let HW handle all the ECC
* data written to the device.
*/
return write_page(mtd, chip, buf, false); return write_page(mtd, chip, buf, false);
} }
/* This is the callback that the NAND core calls to write a page without ECC. /*
* This is the callback that the NAND core calls to write a page without ECC.
* raw access is similar to ECC page writes, so all the work is done in the * raw access is similar to ECC page writes, so all the work is done in the
* write_page() function above. * write_page() function above.
*/ */
static int denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, static int denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
const uint8_t *buf, int oob_required) const uint8_t *buf, int oob_required)
{ {
/* for raw page writes, we want to disable ECC and simply write /*
whatever data is in the buffer. */ * for raw page writes, we want to disable ECC and simply write
* whatever data is in the buffer.
*/
return write_page(mtd, chip, buf, true); return write_page(mtd, chip, buf, true);
} }
...@@ -1121,14 +1155,14 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -1121,14 +1155,14 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
dma_addr_t addr = denali->buf.dma_buf; dma_addr_t addr = denali->buf.dma_buf;
size_t size = denali->mtd.writesize + denali->mtd.oobsize; size_t size = denali->mtd.writesize + denali->mtd.oobsize;
uint32_t irq_status = 0; uint32_t irq_status;
uint32_t irq_mask = INTR_STATUS__ECC_TRANSACTION_DONE | uint32_t irq_mask = INTR_STATUS__ECC_TRANSACTION_DONE |
INTR_STATUS__ECC_ERR; INTR_STATUS__ECC_ERR;
bool check_erased_page = false; bool check_erased_page = false;
if (page != denali->page) { if (page != denali->page) {
dev_err(denali->dev, "IN %s: page %d is not" dev_err(denali->dev,
" equal to denali->page %d, investigate!!", "IN %s: page %d is not equal to denali->page %d",
__func__, page, denali->page); __func__, page, denali->page);
BUG(); BUG();
} }
...@@ -1169,16 +1203,13 @@ static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -1169,16 +1203,13 @@ static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int oob_required, int page) uint8_t *buf, int oob_required, int page)
{ {
struct denali_nand_info *denali = mtd_to_denali(mtd); struct denali_nand_info *denali = mtd_to_denali(mtd);
dma_addr_t addr = denali->buf.dma_buf; dma_addr_t addr = denali->buf.dma_buf;
size_t size = denali->mtd.writesize + denali->mtd.oobsize; size_t size = denali->mtd.writesize + denali->mtd.oobsize;
uint32_t irq_status = 0;
uint32_t irq_mask = INTR_STATUS__DMA_CMD_COMP; uint32_t irq_mask = INTR_STATUS__DMA_CMD_COMP;
if (page != denali->page) { if (page != denali->page) {
dev_err(denali->dev, "IN %s: page %d is not" dev_err(denali->dev,
" equal to denali->page %d, investigate!!", "IN %s: page %d is not equal to denali->page %d",
__func__, page, denali->page); __func__, page, denali->page);
BUG(); BUG();
} }
...@@ -1192,7 +1223,7 @@ static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -1192,7 +1223,7 @@ static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
denali_setup_dma(denali, DENALI_READ); denali_setup_dma(denali, DENALI_READ);
/* wait for operation to complete */ /* wait for operation to complete */
irq_status = wait_for_irq(denali, irq_mask); wait_for_irq(denali, irq_mask);
dma_sync_single_for_cpu(denali->dev, addr, size, DMA_FROM_DEVICE); dma_sync_single_for_cpu(denali->dev, addr, size, DMA_FROM_DEVICE);
...@@ -1228,6 +1259,7 @@ static int denali_waitfunc(struct mtd_info *mtd, struct nand_chip *chip) ...@@ -1228,6 +1259,7 @@ static int denali_waitfunc(struct mtd_info *mtd, struct nand_chip *chip)
{ {
struct denali_nand_info *denali = mtd_to_denali(mtd); struct denali_nand_info *denali = mtd_to_denali(mtd);
int status = denali->status; int status = denali->status;
denali->status = 0; denali->status = 0;
return status; return status;
...@@ -1237,20 +1269,19 @@ static int denali_erase(struct mtd_info *mtd, int page) ...@@ -1237,20 +1269,19 @@ static int denali_erase(struct mtd_info *mtd, int page)
{ {
struct denali_nand_info *denali = mtd_to_denali(mtd); struct denali_nand_info *denali = mtd_to_denali(mtd);
uint32_t cmd = 0x0, irq_status = 0; uint32_t cmd, irq_status;
/* clear interrupts */
clear_interrupts(denali); clear_interrupts(denali);
/* setup page read request for access type */ /* setup page read request for access type */
cmd = MODE_10 | BANK(denali->flash_bank) | page; cmd = MODE_10 | BANK(denali->flash_bank) | page;
index_addr(denali, (uint32_t)cmd, 0x1); index_addr(denali, cmd, 0x1);
/* wait for erase to complete or failure to occur */ /* wait for erase to complete or failure to occur */
irq_status = wait_for_irq(denali, INTR_STATUS__ERASE_COMP | irq_status = wait_for_irq(denali, INTR_STATUS__ERASE_COMP |
INTR_STATUS__ERASE_FAIL); INTR_STATUS__ERASE_FAIL);
return (irq_status & INTR_STATUS__ERASE_FAIL) ? NAND_STATUS_FAIL : PASS; return irq_status & INTR_STATUS__ERASE_FAIL ? NAND_STATUS_FAIL : PASS;
} }
static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col, static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col,
...@@ -1269,17 +1300,16 @@ static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col, ...@@ -1269,17 +1300,16 @@ static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col,
case NAND_CMD_READID: case NAND_CMD_READID:
case NAND_CMD_PARAM: case NAND_CMD_PARAM:
reset_buf(denali); reset_buf(denali);
/*sometimes ManufactureId read from register is not right /*
* sometimes ManufactureId read from register is not right
* e.g. some of Micron MT29F32G08QAA MLC NAND chips * e.g. some of Micron MT29F32G08QAA MLC NAND chips
* So here we send READID cmd to NAND insteand * So here we send READID cmd to NAND insteand
* */ */
addr = (uint32_t)MODE_11 | BANK(denali->flash_bank); addr = MODE_11 | BANK(denali->flash_bank);
index_addr(denali, (uint32_t)addr | 0, 0x90); index_addr(denali, addr | 0, 0x90);
index_addr(denali, (uint32_t)addr | 1, 0); index_addr(denali, addr | 1, 0);
for (i = 0; i < 8; i++) { for (i = 0; i < 8; i++) {
index_addr_read_data(denali, index_addr_read_data(denali, addr | 2, &id);
(uint32_t)addr | 2,
&id);
write_byte_to_buf(denali, id); write_byte_to_buf(denali, id);
} }
break; break;
...@@ -1304,8 +1334,8 @@ static int denali_ecc_calculate(struct mtd_info *mtd, const uint8_t *data, ...@@ -1304,8 +1334,8 @@ static int denali_ecc_calculate(struct mtd_info *mtd, const uint8_t *data,
uint8_t *ecc_code) uint8_t *ecc_code)
{ {
struct denali_nand_info *denali = mtd_to_denali(mtd); struct denali_nand_info *denali = mtd_to_denali(mtd);
dev_err(denali->dev,
"denali_ecc_calculate called unexpectedly\n"); dev_err(denali->dev, "denali_ecc_calculate called unexpectedly\n");
BUG(); BUG();
return -EIO; return -EIO;
} }
...@@ -1314,8 +1344,8 @@ static int denali_ecc_correct(struct mtd_info *mtd, uint8_t *data, ...@@ -1314,8 +1344,8 @@ static int denali_ecc_correct(struct mtd_info *mtd, uint8_t *data,
uint8_t *read_ecc, uint8_t *calc_ecc) uint8_t *read_ecc, uint8_t *calc_ecc)
{ {
struct denali_nand_info *denali = mtd_to_denali(mtd); struct denali_nand_info *denali = mtd_to_denali(mtd);
dev_err(denali->dev,
"denali_ecc_correct called unexpectedly\n"); dev_err(denali->dev, "denali_ecc_correct called unexpectedly\n");
BUG(); BUG();
return -EIO; return -EIO;
} }
...@@ -1323,8 +1353,8 @@ static int denali_ecc_correct(struct mtd_info *mtd, uint8_t *data, ...@@ -1323,8 +1353,8 @@ static int denali_ecc_correct(struct mtd_info *mtd, uint8_t *data,
static void denali_ecc_hwctl(struct mtd_info *mtd, int mode) static void denali_ecc_hwctl(struct mtd_info *mtd, int mode)
{ {
struct denali_nand_info *denali = mtd_to_denali(mtd); struct denali_nand_info *denali = mtd_to_denali(mtd);
dev_err(denali->dev,
"denali_ecc_hwctl called unexpectedly\n"); dev_err(denali->dev, "denali_ecc_hwctl called unexpectedly\n");
BUG(); BUG();
} }
/* end NAND core entry points */ /* end NAND core entry points */
...@@ -1332,11 +1362,12 @@ static void denali_ecc_hwctl(struct mtd_info *mtd, int mode) ...@@ -1332,11 +1362,12 @@ static void denali_ecc_hwctl(struct mtd_info *mtd, int mode)
/* Initialization code to bring the device up to a known good state */ /* Initialization code to bring the device up to a known good state */
static void denali_hw_init(struct denali_nand_info *denali) static void denali_hw_init(struct denali_nand_info *denali)
{ {
/* tell driver how many bit controller will skip before /*
* tell driver how many bit controller will skip before
* writing ECC code in OOB, this register may be already * writing ECC code in OOB, this register may be already
* set by firmware. So we read this value out. * set by firmware. So we read this value out.
* if this value is 0, just let it be. * if this value is 0, just let it be.
* */ */
denali->bbtskipbytes = ioread32(denali->flash_reg + denali->bbtskipbytes = ioread32(denali->flash_reg +
SPARE_AREA_SKIP_BYTES); SPARE_AREA_SKIP_BYTES);
detect_max_banks(denali); detect_max_banks(denali);
...@@ -1354,10 +1385,11 @@ static void denali_hw_init(struct denali_nand_info *denali) ...@@ -1354,10 +1385,11 @@ static void denali_hw_init(struct denali_nand_info *denali)
denali_irq_init(denali); denali_irq_init(denali);
} }
/* Althogh controller spec said SLC ECC is forceb to be 4bit, /*
* Althogh controller spec said SLC ECC is forceb to be 4bit,
* but denali controller in MRST only support 15bit and 8bit ECC * but denali controller in MRST only support 15bit and 8bit ECC
* correction * correction
* */ */
#define ECC_8BITS 14 #define ECC_8BITS 14
static struct nand_ecclayout nand_8bit_oob = { static struct nand_ecclayout nand_8bit_oob = {
.eccbytes = 14, .eccbytes = 14,
...@@ -1397,13 +1429,16 @@ static void denali_drv_init(struct denali_nand_info *denali) ...@@ -1397,13 +1429,16 @@ static void denali_drv_init(struct denali_nand_info *denali)
denali->idx = 0; denali->idx = 0;
/* setup interrupt handler */ /* setup interrupt handler */
/* the completion object will be used to notify /*
* the callee that the interrupt is done */ * the completion object will be used to notify
* the callee that the interrupt is done
*/
init_completion(&denali->complete); init_completion(&denali->complete);
/* the spinlock will be used to synchronize the ISR /*
* with any element that might be access shared * the spinlock will be used to synchronize the ISR with any
* data (interrupt status) */ * element that might be access shared data (interrupt status)
*/
spin_lock_init(&denali->irq_lock); spin_lock_init(&denali->irq_lock);
/* indicate that MTD has not selected a valid bank yet */ /* indicate that MTD has not selected a valid bank yet */
...@@ -1418,7 +1453,8 @@ int denali_init(struct denali_nand_info *denali) ...@@ -1418,7 +1453,8 @@ int denali_init(struct denali_nand_info *denali)
int ret; int ret;
if (denali->platform == INTEL_CE4100) { if (denali->platform == INTEL_CE4100) {
/* Due to a silicon limitation, we can only support /*
* Due to a silicon limitation, we can only support
* ONFI timing mode 1 and below. * ONFI timing mode 1 and below.
*/ */
if (onfi_timing_mode < -1 || onfi_timing_mode > 1) { if (onfi_timing_mode < -1 || onfi_timing_mode > 1) {
...@@ -1437,8 +1473,10 @@ int denali_init(struct denali_nand_info *denali) ...@@ -1437,8 +1473,10 @@ int denali_init(struct denali_nand_info *denali)
denali_hw_init(denali); denali_hw_init(denali);
denali_drv_init(denali); denali_drv_init(denali);
/* denali_isr register is done after all the hardware /*
* initilization is finished*/ * denali_isr register is done after all the hardware
* initilization is finished
*/
if (request_irq(denali->irq, denali_isr, IRQF_SHARED, if (request_irq(denali->irq, denali_isr, IRQF_SHARED,
DENALI_NAND_NAME, denali)) { DENALI_NAND_NAME, denali)) {
pr_err("Spectra: Unable to allocate IRQ\n"); pr_err("Spectra: Unable to allocate IRQ\n");
...@@ -1457,9 +1495,11 @@ int denali_init(struct denali_nand_info *denali) ...@@ -1457,9 +1495,11 @@ int denali_init(struct denali_nand_info *denali)
denali->nand.read_byte = denali_read_byte; denali->nand.read_byte = denali_read_byte;
denali->nand.waitfunc = denali_waitfunc; denali->nand.waitfunc = denali_waitfunc;
/* scan for NAND devices attached to the controller /*
* scan for NAND devices attached to the controller
* this is the first stage in a two step process to register * this is the first stage in a two step process to register
* with the nand subsystem */ * with the nand subsystem
*/
if (nand_scan_ident(&denali->mtd, denali->max_banks, NULL)) { if (nand_scan_ident(&denali->mtd, denali->max_banks, NULL)) {
ret = -ENXIO; ret = -ENXIO;
goto failed_req_irq; goto failed_req_irq;
...@@ -1491,10 +1531,10 @@ int denali_init(struct denali_nand_info *denali) ...@@ -1491,10 +1531,10 @@ int denali_init(struct denali_nand_info *denali)
goto failed_req_irq; goto failed_req_irq;
} }
/* support for multi nand /*
* MTD known nothing about multi nand, * support for multi nand
* so we should tell it the real pagesize * MTD known nothing about multi nand, so we should tell it
* and anything necessery * the real pagesize and anything necessery
*/ */
denali->devnum = ioread32(denali->flash_reg + DEVICES_CONNECTED); denali->devnum = ioread32(denali->flash_reg + DEVICES_CONNECTED);
denali->nand.chipsize <<= (denali->devnum - 1); denali->nand.chipsize <<= (denali->devnum - 1);
...@@ -1510,9 +1550,11 @@ int denali_init(struct denali_nand_info *denali) ...@@ -1510,9 +1550,11 @@ int denali_init(struct denali_nand_info *denali)
denali->mtd.size = denali->nand.numchips * denali->nand.chipsize; denali->mtd.size = denali->nand.numchips * denali->nand.chipsize;
denali->bbtskipbytes *= denali->devnum; denali->bbtskipbytes *= denali->devnum;
/* second stage of the NAND scan /*
* second stage of the NAND scan
* this stage requires information regarding ECC and * this stage requires information regarding ECC and
* bad block management. */ * bad block management.
*/
/* Bad block management */ /* Bad block management */
denali->nand.bbt_td = &bbt_main_descr; denali->nand.bbt_td = &bbt_main_descr;
...@@ -1523,7 +1565,8 @@ int denali_init(struct denali_nand_info *denali) ...@@ -1523,7 +1565,8 @@ int denali_init(struct denali_nand_info *denali)
denali->nand.options |= NAND_SKIP_BBTSCAN; denali->nand.options |= NAND_SKIP_BBTSCAN;
denali->nand.ecc.mode = NAND_ECC_HW_SYNDROME; denali->nand.ecc.mode = NAND_ECC_HW_SYNDROME;
/* Denali Controller only support 15bit and 8bit ECC in MRST, /*
* Denali Controller only support 15bit and 8bit ECC in MRST,
* so just let controller do 15bit ECC for MLC and 8bit ECC for * so just let controller do 15bit ECC for MLC and 8bit ECC for
* SLC if possible. * SLC if possible.
* */ * */
...@@ -1539,8 +1582,7 @@ int denali_init(struct denali_nand_info *denali) ...@@ -1539,8 +1582,7 @@ int denali_init(struct denali_nand_info *denali)
} else if (denali->mtd.oobsize < (denali->bbtskipbytes + } else if (denali->mtd.oobsize < (denali->bbtskipbytes +
ECC_8BITS * (denali->mtd.writesize / ECC_8BITS * (denali->mtd.writesize /
ECC_SECTOR_SIZE))) { ECC_SECTOR_SIZE))) {
pr_err("Your NAND chip OOB is not large enough to \ pr_err("Your NAND chip OOB is not large enough to contain 8bit ECC correction codes");
contain 8bit ECC correction codes");
goto failed_req_irq; goto failed_req_irq;
} else { } else {
denali->nand.ecc.strength = 8; denali->nand.ecc.strength = 8;
...@@ -1559,18 +1601,19 @@ int denali_init(struct denali_nand_info *denali) ...@@ -1559,18 +1601,19 @@ int denali_init(struct denali_nand_info *denali)
denali->mtd.oobsize - denali->nand.ecc.layout->eccbytes - denali->mtd.oobsize - denali->nand.ecc.layout->eccbytes -
denali->bbtskipbytes; denali->bbtskipbytes;
/* Let driver know the total blocks number and /*
* how many blocks contained by each nand chip. * Let driver know the total blocks number and how many blocks
* blksperchip will help driver to know how many * contained by each nand chip. blksperchip will help driver to
* blocks is taken by FW. * know how many blocks is taken by FW.
* */ */
denali->totalblks = denali->mtd.size >> denali->totalblks = denali->mtd.size >> denali->nand.phys_erase_shift;
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, /*
* 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 * the NAND core will assert. However, we don't need them, so we'll stub
* them out. */ * them out.
*/
denali->nand.ecc.calculate = denali_ecc_calculate; denali->nand.ecc.calculate = denali_ecc_calculate;
denali->nand.ecc.correct = denali_ecc_correct; denali->nand.ecc.correct = denali_ecc_correct;
denali->nand.ecc.hwctl = denali_ecc_hwctl; denali->nand.ecc.hwctl = denali_ecc_hwctl;
......
...@@ -17,6 +17,9 @@ ...@@ -17,6 +17,9 @@
* *
*/ */
#ifndef __DENALI_H__
#define __DENALI_H__
#include <linux/mtd/nand.h> #include <linux/mtd/nand.h>
#define DEVICE_RESET 0x0 #define DEVICE_RESET 0x0
...@@ -400,28 +403,6 @@ ...@@ -400,28 +403,6 @@
#define ONFI_BLOOM_TIME 1 #define ONFI_BLOOM_TIME 1
#define MODE5_WORKAROUND 0 #define MODE5_WORKAROUND 0
/* lld_nand.h */
/*
* NAND Flash Controller Device Driver
* Copyright (c) 2009, Intel Corporation and its suppliers.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#ifndef _LLD_NAND_
#define _LLD_NAND_
#define MODE_00 0x00000000 #define MODE_00 0x00000000
#define MODE_01 0x04000000 #define MODE_01 0x04000000
...@@ -499,4 +480,4 @@ struct denali_nand_info { ...@@ -499,4 +480,4 @@ struct denali_nand_info {
extern int denali_init(struct denali_nand_info *denali); extern int denali_init(struct denali_nand_info *denali);
extern void denali_remove(struct denali_nand_info *denali); extern void denali_remove(struct denali_nand_info *denali);
#endif /*_LLD_NAND_*/ #endif /* __DENALI_H__ */
...@@ -982,6 +982,15 @@ int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) ...@@ -982,6 +982,15 @@ int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
chip->select_chip(mtd, chipnr); chip->select_chip(mtd, chipnr);
/*
* Reset the chip.
* If we want to check the WP through READ STATUS and check the bit 7
* we must reset the chip
* some operation can also clear the bit 7 of status register
* eg. erase/program a locked block
*/
chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
/* Check, if it is write protected */ /* Check, if it is write protected */
if (nand_check_wp(mtd)) { if (nand_check_wp(mtd)) {
pr_debug("%s: device is write protected!\n", pr_debug("%s: device is write protected!\n",
...@@ -1032,6 +1041,15 @@ int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) ...@@ -1032,6 +1041,15 @@ int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
chip->select_chip(mtd, chipnr); chip->select_chip(mtd, chipnr);
/*
* Reset the chip.
* If we want to check the WP through READ STATUS and check the bit 7
* we must reset the chip
* some operation can also clear the bit 7 of status register
* eg. erase/program a locked block
*/
chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
/* Check, if it is write protected */ /* Check, if it is write protected */
if (nand_check_wp(mtd)) { if (nand_check_wp(mtd)) {
pr_debug("%s: device is write protected!\n", pr_debug("%s: device is write protected!\n",
...@@ -2391,8 +2409,8 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, ...@@ -2391,8 +2409,8 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
blockmask = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1; blockmask = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;
/* Invalidate the page cache, when we write to the cached page */ /* Invalidate the page cache, when we write to the cached page */
if (to <= (chip->pagebuf << chip->page_shift) && if (to <= ((loff_t)chip->pagebuf << chip->page_shift) &&
(chip->pagebuf << chip->page_shift) < (to + ops->len)) ((loff_t)chip->pagebuf << chip->page_shift) < (to + ops->len))
chip->pagebuf = -1; chip->pagebuf = -1;
/* Don't allow multipage oob writes with offset */ /* Don't allow multipage oob writes with offset */
...@@ -3576,6 +3594,8 @@ static bool find_full_id_nand(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -3576,6 +3594,8 @@ static bool find_full_id_nand(struct mtd_info *mtd, struct nand_chip *chip,
chip->options |= type->options; chip->options |= type->options;
chip->ecc_strength_ds = NAND_ECC_STRENGTH(type); chip->ecc_strength_ds = NAND_ECC_STRENGTH(type);
chip->ecc_step_ds = NAND_ECC_STEP(type); chip->ecc_step_ds = NAND_ECC_STEP(type);
chip->onfi_timing_mode_default =
type->onfi_timing_mode_default;
*busw = type->options & NAND_BUSWIDTH_16; *busw = type->options & NAND_BUSWIDTH_16;
...@@ -3918,8 +3938,7 @@ int nand_scan_tail(struct mtd_info *mtd) ...@@ -3918,8 +3938,7 @@ int nand_scan_tail(struct mtd_info *mtd)
case NAND_ECC_HW_OOB_FIRST: case NAND_ECC_HW_OOB_FIRST:
/* Similar to NAND_ECC_HW, but a separate read_page handle */ /* Similar to NAND_ECC_HW, but a separate read_page handle */
if (!ecc->calculate || !ecc->correct || !ecc->hwctl) { if (!ecc->calculate || !ecc->correct || !ecc->hwctl) {
pr_warn("No ECC functions supplied; " pr_warn("No ECC functions supplied; hardware ECC not possible\n");
"hardware ECC not possible\n");
BUG(); BUG();
} }
if (!ecc->read_page) if (!ecc->read_page)
...@@ -3950,8 +3969,7 @@ int nand_scan_tail(struct mtd_info *mtd) ...@@ -3950,8 +3969,7 @@ int nand_scan_tail(struct mtd_info *mtd)
ecc->read_page == nand_read_page_hwecc || ecc->read_page == nand_read_page_hwecc ||
!ecc->write_page || !ecc->write_page ||
ecc->write_page == nand_write_page_hwecc)) { ecc->write_page == nand_write_page_hwecc)) {
pr_warn("No ECC functions supplied; " pr_warn("No ECC functions supplied; hardware ECC not possible\n");
"hardware ECC not possible\n");
BUG(); BUG();
} }
/* Use standard syndrome read/write page function? */ /* Use standard syndrome read/write page function? */
...@@ -3975,8 +3993,7 @@ int nand_scan_tail(struct mtd_info *mtd) ...@@ -3975,8 +3993,7 @@ int nand_scan_tail(struct mtd_info *mtd)
} }
break; break;
} }
pr_warn("%d byte HW ECC not possible on " pr_warn("%d byte HW ECC not possible on %d byte page size, fallback to SW ECC\n",
"%d byte page size, fallback to SW ECC\n",
ecc->size, mtd->writesize); ecc->size, mtd->writesize);
ecc->mode = NAND_ECC_SOFT; ecc->mode = NAND_ECC_SOFT;
...@@ -4030,8 +4047,7 @@ int nand_scan_tail(struct mtd_info *mtd) ...@@ -4030,8 +4047,7 @@ int nand_scan_tail(struct mtd_info *mtd)
break; break;
case NAND_ECC_NONE: case NAND_ECC_NONE:
pr_warn("NAND_ECC_NONE selected by board driver. " pr_warn("NAND_ECC_NONE selected by board driver. This is not recommended!\n");
"This is not recommended!\n");
ecc->read_page = nand_read_page_raw; ecc->read_page = nand_read_page_raw;
ecc->write_page = nand_write_page_raw; ecc->write_page = nand_write_page_raw;
ecc->read_oob = nand_read_oob_std; ecc->read_oob = nand_read_oob_std;
......
...@@ -201,12 +201,12 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, ...@@ -201,12 +201,12 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
res = mtd_read(mtd, from, len, &retlen, buf); res = mtd_read(mtd, from, len, &retlen, buf);
if (res < 0) { if (res < 0) {
if (mtd_is_eccerr(res)) { if (mtd_is_eccerr(res)) {
pr_info("nand_bbt: ECC error in BBT at " pr_info("nand_bbt: ECC error in BBT at 0x%012llx\n",
"0x%012llx\n", from & ~mtd->writesize); from & ~mtd->writesize);
return res; return res;
} else if (mtd_is_bitflip(res)) { } else if (mtd_is_bitflip(res)) {
pr_info("nand_bbt: corrected error in BBT at " pr_info("nand_bbt: corrected error in BBT at 0x%012llx\n",
"0x%012llx\n", from & ~mtd->writesize); from & ~mtd->writesize);
ret = res; ret = res;
} else { } else {
pr_info("nand_bbt: error reading BBT\n"); pr_info("nand_bbt: error reading BBT\n");
...@@ -580,8 +580,8 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr ...@@ -580,8 +580,8 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
if (td->pages[i] == -1) if (td->pages[i] == -1)
pr_warn("Bad block table not found for chip %d\n", i); pr_warn("Bad block table not found for chip %d\n", i);
else else
pr_info("Bad block table found at page %d, version " pr_info("Bad block table found at page %d, version 0x%02X\n",
"0x%02X\n", td->pages[i], td->version[i]); td->pages[i], td->version[i]);
} }
return 0; return 0;
} }
...@@ -725,12 +725,10 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, ...@@ -725,12 +725,10 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
res = mtd_read(mtd, to, len, &retlen, buf); res = mtd_read(mtd, to, len, &retlen, buf);
if (res < 0) { if (res < 0) {
if (retlen != len) { if (retlen != len) {
pr_info("nand_bbt: error reading block " pr_info("nand_bbt: error reading block for writing the bad block table\n");
"for writing the bad block table\n");
return res; return res;
} }
pr_warn("nand_bbt: ECC error while reading " pr_warn("nand_bbt: ECC error while reading block for writing bad block table\n");
"block for writing bad block table\n");
} }
/* Read oob data */ /* Read oob data */
ops.ooblen = (len >> this->page_shift) * mtd->oobsize; ops.ooblen = (len >> this->page_shift) * mtd->oobsize;
...@@ -1338,8 +1336,7 @@ int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt) ...@@ -1338,8 +1336,7 @@ int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)
block = (int)(offs >> this->bbt_erase_shift); block = (int)(offs >> this->bbt_erase_shift);
res = bbt_get_entry(this, block); res = bbt_get_entry(this, block);
pr_debug("nand_isbad_bbt(): bbt info for offs 0x%08x: " pr_debug("nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n",
"(block %d) 0x%02x\n",
(unsigned int)offs, block, res); (unsigned int)offs, block, res);
switch (res) { switch (res) {
......
...@@ -46,6 +46,10 @@ struct nand_flash_dev nand_flash_ids[] = { ...@@ -46,6 +46,10 @@ struct nand_flash_dev nand_flash_ids[] = {
{"SDTNRGAMA 64G 3.3V 8-bit", {"SDTNRGAMA 64G 3.3V 8-bit",
{ .id = {0x45, 0xde, 0x94, 0x93, 0x76, 0x50} }, { .id = {0x45, 0xde, 0x94, 0x93, 0x76, 0x50} },
SZ_16K, SZ_8K, SZ_4M, 0, 6, 1280, NAND_ECC_INFO(40, SZ_1K) }, SZ_16K, SZ_8K, SZ_4M, 0, 6, 1280, NAND_ECC_INFO(40, SZ_1K) },
{"H27UCG8T2ATR-BC 64G 3.3V 8-bit",
{ .id = {0xad, 0xde, 0x94, 0xda, 0x74, 0xc4} },
SZ_8K, SZ_8K, SZ_2M, 0, 6, 640, NAND_ECC_INFO(40, SZ_1K),
4 },
LEGACY_ID_NAND("NAND 4MiB 5V 8-bit", 0x6B, 4, SZ_8K, SP_OPTIONS), LEGACY_ID_NAND("NAND 4MiB 5V 8-bit", 0x6B, 4, SZ_8K, SP_OPTIONS),
LEGACY_ID_NAND("NAND 4MiB 3,3V 8-bit", 0xE3, 4, SZ_8K, SP_OPTIONS), LEGACY_ID_NAND("NAND 4MiB 3,3V 8-bit", 0xE3, 4, SZ_8K, SP_OPTIONS),
......
...@@ -42,7 +42,7 @@ static const struct nand_sdr_timings onfi_sdr_timings[] = { ...@@ -42,7 +42,7 @@ static const struct nand_sdr_timings onfi_sdr_timings[] = {
.tRHZ_max = 200000, .tRHZ_max = 200000,
.tRLOH_min = 0, .tRLOH_min = 0,
.tRP_min = 50000, .tRP_min = 50000,
.tRST_max = 250000000000, .tRST_max = 250000000000ULL,
.tWB_max = 200000, .tWB_max = 200000,
.tRR_min = 40000, .tRR_min = 40000,
.tWC_min = 100000, .tWC_min = 100000,
......
...@@ -827,7 +827,7 @@ static int parse_badblocks(struct nandsim *ns, struct mtd_info *mtd) ...@@ -827,7 +827,7 @@ static int parse_badblocks(struct nandsim *ns, struct mtd_info *mtd)
NS_ERR("invalid badblocks.\n"); NS_ERR("invalid badblocks.\n");
return -EINVAL; return -EINVAL;
} }
offset = erase_block_no * ns->geom.secsz; offset = (loff_t)erase_block_no * ns->geom.secsz;
if (mtd_block_markbad(mtd, offset)) { if (mtd_block_markbad(mtd, offset)) {
NS_ERR("invalid badblocks.\n"); NS_ERR("invalid badblocks.\n");
return -EINVAL; return -EINVAL;
......
...@@ -203,7 +203,8 @@ static int ndfc_probe(struct platform_device *ofdev) ...@@ -203,7 +203,8 @@ static int ndfc_probe(struct platform_device *ofdev)
struct ndfc_controller *ndfc; struct ndfc_controller *ndfc;
const __be32 *reg; const __be32 *reg;
u32 ccr; u32 ccr;
int err, len, cs; u32 cs;
int err, len;
/* Read the reg property to get the chip select */ /* Read the reg property to get the chip select */
reg = of_get_property(ofdev->dev.of_node, "reg", &len); reg = of_get_property(ofdev->dev.of_node, "reg", &len);
......
...@@ -136,7 +136,6 @@ ...@@ -136,7 +136,6 @@
#define BADBLOCK_MARKER_LENGTH 2 #define BADBLOCK_MARKER_LENGTH 2
#ifdef CONFIG_MTD_NAND_OMAP_BCH
static u_char bch16_vector[] = {0xf5, 0x24, 0x1c, 0xd0, 0x61, 0xb3, 0xf1, 0x55, static u_char bch16_vector[] = {0xf5, 0x24, 0x1c, 0xd0, 0x61, 0xb3, 0xf1, 0x55,
0x2e, 0x2c, 0x86, 0xa3, 0xed, 0x36, 0x1b, 0x78, 0x2e, 0x2c, 0x86, 0xa3, 0xed, 0x36, 0x1b, 0x78,
0x48, 0x76, 0xa9, 0x3b, 0x97, 0xd1, 0x7a, 0x93, 0x48, 0x76, 0xa9, 0x3b, 0x97, 0xd1, 0x7a, 0x93,
...@@ -144,7 +143,6 @@ static u_char bch16_vector[] = {0xf5, 0x24, 0x1c, 0xd0, 0x61, 0xb3, 0xf1, 0x55, ...@@ -144,7 +143,6 @@ static u_char bch16_vector[] = {0xf5, 0x24, 0x1c, 0xd0, 0x61, 0xb3, 0xf1, 0x55,
static u_char bch8_vector[] = {0xf3, 0xdb, 0x14, 0x16, 0x8b, 0xd2, 0xbe, 0xcc, static u_char bch8_vector[] = {0xf3, 0xdb, 0x14, 0x16, 0x8b, 0xd2, 0xbe, 0xcc,
0xac, 0x6b, 0xff, 0x99, 0x7b}; 0xac, 0x6b, 0xff, 0x99, 0x7b};
static u_char bch4_vector[] = {0x00, 0x6b, 0x31, 0xdd, 0x41, 0xbc, 0x10}; static u_char bch4_vector[] = {0x00, 0x6b, 0x31, 0xdd, 0x41, 0xbc, 0x10};
#endif
/* oob info generated runtime depending on ecc algorithm and layout selected */ /* oob info generated runtime depending on ecc algorithm and layout selected */
static struct nand_ecclayout omap_oobinfo; static struct nand_ecclayout omap_oobinfo;
...@@ -1292,7 +1290,6 @@ static int __maybe_unused omap_calculate_ecc_bch(struct mtd_info *mtd, ...@@ -1292,7 +1290,6 @@ static int __maybe_unused omap_calculate_ecc_bch(struct mtd_info *mtd,
return 0; return 0;
} }
#ifdef CONFIG_MTD_NAND_OMAP_BCH
/** /**
* erased_sector_bitflips - count bit flips * erased_sector_bitflips - count bit flips
* @data: data sector buffer * @data: data sector buffer
...@@ -1378,7 +1375,7 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data, ...@@ -1378,7 +1375,7 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data,
erased_ecc_vec = bch16_vector; erased_ecc_vec = bch16_vector;
break; break;
default: default:
pr_err("invalid driver configuration\n"); dev_err(&info->pdev->dev, "invalid driver configuration\n");
return -EINVAL; return -EINVAL;
} }
...@@ -1449,7 +1446,8 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data, ...@@ -1449,7 +1446,8 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data,
err = 0; err = 0;
for (i = 0; i < eccsteps; i++) { for (i = 0; i < eccsteps; i++) {
if (err_vec[i].error_uncorrectable) { if (err_vec[i].error_uncorrectable) {
pr_err("nand: uncorrectable bit-flips found\n"); dev_err(&info->pdev->dev,
"uncorrectable bit-flips found\n");
err = -EBADMSG; err = -EBADMSG;
} else if (err_vec[i].error_reported) { } else if (err_vec[i].error_reported) {
for (j = 0; j < err_vec[i].error_count; j++) { for (j = 0; j < err_vec[i].error_count; j++) {
...@@ -1486,7 +1484,8 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data, ...@@ -1486,7 +1484,8 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data,
1 << bit_pos; 1 << bit_pos;
} }
} else { } else {
pr_err("invalid bit-flip @ %d:%d\n", dev_err(&info->pdev->dev,
"invalid bit-flip @ %d:%d\n",
byte_pos, bit_pos); byte_pos, bit_pos);
err = -EBADMSG; err = -EBADMSG;
} }
...@@ -1593,33 +1592,71 @@ static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -1593,33 +1592,71 @@ static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
/** /**
* is_elm_present - checks for presence of ELM module by scanning DT nodes * is_elm_present - checks for presence of ELM module by scanning DT nodes
* @omap_nand_info: NAND device structure containing platform data * @omap_nand_info: NAND device structure containing platform data
* @bch_type: 0x0=BCH4, 0x1=BCH8, 0x2=BCH16
*/ */
static int is_elm_present(struct omap_nand_info *info, static bool is_elm_present(struct omap_nand_info *info,
struct device_node *elm_node, enum bch_ecc bch_type) struct device_node *elm_node)
{ {
struct platform_device *pdev; struct platform_device *pdev;
struct nand_ecc_ctrl *ecc = &info->nand.ecc;
int err;
/* check whether elm-id is passed via DT */ /* check whether elm-id is passed via DT */
if (!elm_node) { if (!elm_node) {
pr_err("nand: error: ELM DT node not found\n"); dev_err(&info->pdev->dev, "ELM devicetree node not found\n");
return -ENODEV; return false;
} }
pdev = of_find_device_by_node(elm_node); pdev = of_find_device_by_node(elm_node);
/* check whether ELM device is registered */ /* check whether ELM device is registered */
if (!pdev) { if (!pdev) {
pr_err("nand: error: ELM device not found\n"); dev_err(&info->pdev->dev, "ELM device not found\n");
return -ENODEV; return false;
} }
/* ELM module available, now configure it */ /* ELM module available, now configure it */
info->elm_dev = &pdev->dev; info->elm_dev = &pdev->dev;
err = elm_config(info->elm_dev, bch_type, return true;
(info->mtd.writesize / ecc->size), ecc->size, ecc->bytes); }
return err; static bool omap2_nand_ecc_check(struct omap_nand_info *info,
struct omap_nand_platform_data *pdata)
{
bool ecc_needs_bch, ecc_needs_omap_bch, ecc_needs_elm;
switch (info->ecc_opt) {
case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW:
case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
ecc_needs_omap_bch = false;
ecc_needs_bch = true;
ecc_needs_elm = false;
break;
case OMAP_ECC_BCH4_CODE_HW:
case OMAP_ECC_BCH8_CODE_HW:
case OMAP_ECC_BCH16_CODE_HW:
ecc_needs_omap_bch = true;
ecc_needs_bch = false;
ecc_needs_elm = true;
break;
default:
ecc_needs_omap_bch = false;
ecc_needs_bch = false;
ecc_needs_elm = false;
break;
}
if (ecc_needs_bch && !IS_ENABLED(CONFIG_MTD_NAND_ECC_BCH)) {
dev_err(&info->pdev->dev,
"CONFIG_MTD_NAND_ECC_BCH not enabled\n");
return false;
}
if (ecc_needs_omap_bch && !IS_ENABLED(CONFIG_MTD_NAND_OMAP_BCH)) {
dev_err(&info->pdev->dev,
"CONFIG_MTD_NAND_OMAP_BCH not enabled\n");
return false;
}
if (ecc_needs_elm && !is_elm_present(info, pdata->elm_of_node)) {
dev_err(&info->pdev->dev, "ELM not available\n");
return false;
}
return true;
} }
#endif /* CONFIG_MTD_NAND_ECC_BCH */
static int omap_nand_probe(struct platform_device *pdev) static int omap_nand_probe(struct platform_device *pdev)
{ {
...@@ -1663,7 +1700,6 @@ static int omap_nand_probe(struct platform_device *pdev) ...@@ -1663,7 +1700,6 @@ static int omap_nand_probe(struct platform_device *pdev)
mtd->owner = THIS_MODULE; mtd->owner = THIS_MODULE;
nand_chip = &info->nand; nand_chip = &info->nand;
nand_chip->ecc.priv = NULL; nand_chip->ecc.priv = NULL;
nand_chip->options |= NAND_SKIP_BBTSCAN;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
nand_chip->IO_ADDR_R = devm_ioremap_resource(&pdev->dev, res); nand_chip->IO_ADDR_R = devm_ioremap_resource(&pdev->dev, res);
...@@ -1692,17 +1728,22 @@ static int omap_nand_probe(struct platform_device *pdev) ...@@ -1692,17 +1728,22 @@ static int omap_nand_probe(struct platform_device *pdev)
nand_chip->chip_delay = 50; nand_chip->chip_delay = 50;
} }
if (pdata->flash_bbt)
nand_chip->bbt_options |= NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB;
else
nand_chip->options |= NAND_SKIP_BBTSCAN;
/* scan NAND device connected to chip controller */ /* scan NAND device connected to chip controller */
nand_chip->options |= pdata->devsize & NAND_BUSWIDTH_16; nand_chip->options |= pdata->devsize & NAND_BUSWIDTH_16;
if (nand_scan_ident(mtd, 1, NULL)) { if (nand_scan_ident(mtd, 1, NULL)) {
pr_err("nand device scan failed, may be bus-width mismatch\n"); dev_err(&info->pdev->dev, "scan failed, may be bus-width mismatch\n");
err = -ENXIO; err = -ENXIO;
goto return_error; goto return_error;
} }
/* check for small page devices */ /* check for small page devices */
if ((mtd->oobsize < 64) && (pdata->ecc_opt != OMAP_ECC_HAM1_CODE_HW)) { if ((mtd->oobsize < 64) && (pdata->ecc_opt != OMAP_ECC_HAM1_CODE_HW)) {
pr_err("small page devices are not supported\n"); dev_err(&info->pdev->dev, "small page devices are not supported\n");
err = -EINVAL; err = -EINVAL;
goto return_error; goto return_error;
} }
...@@ -1793,6 +1834,11 @@ static int omap_nand_probe(struct platform_device *pdev) ...@@ -1793,6 +1834,11 @@ static int omap_nand_probe(struct platform_device *pdev)
goto return_error; goto return_error;
} }
if (!omap2_nand_ecc_check(info, pdata)) {
err = -EINVAL;
goto return_error;
}
/* populate MTD interface based on ECC scheme */ /* populate MTD interface based on ECC scheme */
ecclayout = &omap_oobinfo; ecclayout = &omap_oobinfo;
switch (info->ecc_opt) { switch (info->ecc_opt) {
...@@ -1825,7 +1871,6 @@ static int omap_nand_probe(struct platform_device *pdev) ...@@ -1825,7 +1871,6 @@ static int omap_nand_probe(struct platform_device *pdev)
break; break;
case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW: case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW:
#ifdef CONFIG_MTD_NAND_ECC_BCH
pr_info("nand: using OMAP_ECC_BCH4_CODE_HW_DETECTION_SW\n"); pr_info("nand: using OMAP_ECC_BCH4_CODE_HW_DETECTION_SW\n");
nand_chip->ecc.mode = NAND_ECC_HW; nand_chip->ecc.mode = NAND_ECC_HW;
nand_chip->ecc.size = 512; nand_chip->ecc.size = 512;
...@@ -1853,18 +1898,13 @@ static int omap_nand_probe(struct platform_device *pdev) ...@@ -1853,18 +1898,13 @@ static int omap_nand_probe(struct platform_device *pdev)
nand_chip->ecc.bytes, nand_chip->ecc.bytes,
&ecclayout); &ecclayout);
if (!nand_chip->ecc.priv) { if (!nand_chip->ecc.priv) {
pr_err("nand: error: unable to use s/w BCH library\n"); dev_err(&info->pdev->dev, "unable to use BCH library\n");
err = -EINVAL; err = -EINVAL;
goto return_error;
} }
break; break;
#else
pr_err("nand: error: CONFIG_MTD_NAND_ECC_BCH not enabled\n");
err = -EINVAL;
goto return_error;
#endif
case OMAP_ECC_BCH4_CODE_HW: case OMAP_ECC_BCH4_CODE_HW:
#ifdef CONFIG_MTD_NAND_OMAP_BCH
pr_info("nand: using OMAP_ECC_BCH4_CODE_HW ECC scheme\n"); pr_info("nand: using OMAP_ECC_BCH4_CODE_HW ECC scheme\n");
nand_chip->ecc.mode = NAND_ECC_HW; nand_chip->ecc.mode = NAND_ECC_HW;
nand_chip->ecc.size = 512; nand_chip->ecc.size = 512;
...@@ -1886,21 +1926,15 @@ static int omap_nand_probe(struct platform_device *pdev) ...@@ -1886,21 +1926,15 @@ static int omap_nand_probe(struct platform_device *pdev)
/* reserved marker already included in ecclayout->eccbytes */ /* reserved marker already included in ecclayout->eccbytes */
ecclayout->oobfree->offset = ecclayout->oobfree->offset =
ecclayout->eccpos[ecclayout->eccbytes - 1] + 1; ecclayout->eccpos[ecclayout->eccbytes - 1] + 1;
/* This ECC scheme requires ELM H/W block */
if (is_elm_present(info, pdata->elm_of_node, BCH4_ECC) < 0) { err = elm_config(info->elm_dev, BCH4_ECC,
pr_err("nand: error: could not initialize ELM\n"); info->mtd.writesize / nand_chip->ecc.size,
err = -ENODEV; nand_chip->ecc.size, nand_chip->ecc.bytes);
if (err < 0)
goto return_error; goto return_error;
}
break; break;
#else
pr_err("nand: error: CONFIG_MTD_NAND_OMAP_BCH not enabled\n");
err = -EINVAL;
goto return_error;
#endif
case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW: case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
#ifdef CONFIG_MTD_NAND_ECC_BCH
pr_info("nand: using OMAP_ECC_BCH8_CODE_HW_DETECTION_SW\n"); pr_info("nand: using OMAP_ECC_BCH8_CODE_HW_DETECTION_SW\n");
nand_chip->ecc.mode = NAND_ECC_HW; nand_chip->ecc.mode = NAND_ECC_HW;
nand_chip->ecc.size = 512; nand_chip->ecc.size = 512;
...@@ -1928,19 +1962,13 @@ static int omap_nand_probe(struct platform_device *pdev) ...@@ -1928,19 +1962,13 @@ static int omap_nand_probe(struct platform_device *pdev)
nand_chip->ecc.bytes, nand_chip->ecc.bytes,
&ecclayout); &ecclayout);
if (!nand_chip->ecc.priv) { if (!nand_chip->ecc.priv) {
pr_err("nand: error: unable to use s/w BCH library\n"); dev_err(&info->pdev->dev, "unable to use BCH library\n");
err = -EINVAL; err = -EINVAL;
goto return_error; goto return_error;
} }
break; break;
#else
pr_err("nand: error: CONFIG_MTD_NAND_ECC_BCH not enabled\n");
err = -EINVAL;
goto return_error;
#endif
case OMAP_ECC_BCH8_CODE_HW: case OMAP_ECC_BCH8_CODE_HW:
#ifdef CONFIG_MTD_NAND_OMAP_BCH
pr_info("nand: using OMAP_ECC_BCH8_CODE_HW ECC scheme\n"); pr_info("nand: using OMAP_ECC_BCH8_CODE_HW ECC scheme\n");
nand_chip->ecc.mode = NAND_ECC_HW; nand_chip->ecc.mode = NAND_ECC_HW;
nand_chip->ecc.size = 512; nand_chip->ecc.size = 512;
...@@ -1952,12 +1980,13 @@ static int omap_nand_probe(struct platform_device *pdev) ...@@ -1952,12 +1980,13 @@ static int omap_nand_probe(struct platform_device *pdev)
nand_chip->ecc.calculate = omap_calculate_ecc_bch; nand_chip->ecc.calculate = omap_calculate_ecc_bch;
nand_chip->ecc.read_page = omap_read_page_bch; nand_chip->ecc.read_page = omap_read_page_bch;
nand_chip->ecc.write_page = omap_write_page_bch; nand_chip->ecc.write_page = omap_write_page_bch;
/* This ECC scheme requires ELM H/W block */
err = is_elm_present(info, pdata->elm_of_node, BCH8_ECC); err = elm_config(info->elm_dev, BCH8_ECC,
if (err < 0) { info->mtd.writesize / nand_chip->ecc.size,
pr_err("nand: error: could not initialize ELM\n"); nand_chip->ecc.size, nand_chip->ecc.bytes);
if (err < 0)
goto return_error; goto return_error;
}
/* define ECC layout */ /* define ECC layout */
ecclayout->eccbytes = nand_chip->ecc.bytes * ecclayout->eccbytes = nand_chip->ecc.bytes *
(mtd->writesize / (mtd->writesize /
...@@ -1969,14 +1998,8 @@ static int omap_nand_probe(struct platform_device *pdev) ...@@ -1969,14 +1998,8 @@ static int omap_nand_probe(struct platform_device *pdev)
ecclayout->oobfree->offset = ecclayout->oobfree->offset =
ecclayout->eccpos[ecclayout->eccbytes - 1] + 1; ecclayout->eccpos[ecclayout->eccbytes - 1] + 1;
break; break;
#else
pr_err("nand: error: CONFIG_MTD_NAND_OMAP_BCH not enabled\n");
err = -EINVAL;
goto return_error;
#endif
case OMAP_ECC_BCH16_CODE_HW: case OMAP_ECC_BCH16_CODE_HW:
#ifdef CONFIG_MTD_NAND_OMAP_BCH
pr_info("using OMAP_ECC_BCH16_CODE_HW ECC scheme\n"); pr_info("using OMAP_ECC_BCH16_CODE_HW ECC scheme\n");
nand_chip->ecc.mode = NAND_ECC_HW; nand_chip->ecc.mode = NAND_ECC_HW;
nand_chip->ecc.size = 512; nand_chip->ecc.size = 512;
...@@ -1987,12 +2010,13 @@ static int omap_nand_probe(struct platform_device *pdev) ...@@ -1987,12 +2010,13 @@ static int omap_nand_probe(struct platform_device *pdev)
nand_chip->ecc.calculate = omap_calculate_ecc_bch; nand_chip->ecc.calculate = omap_calculate_ecc_bch;
nand_chip->ecc.read_page = omap_read_page_bch; nand_chip->ecc.read_page = omap_read_page_bch;
nand_chip->ecc.write_page = omap_write_page_bch; nand_chip->ecc.write_page = omap_write_page_bch;
/* This ECC scheme requires ELM H/W block */
err = is_elm_present(info, pdata->elm_of_node, BCH16_ECC); err = elm_config(info->elm_dev, BCH16_ECC,
if (err < 0) { info->mtd.writesize / nand_chip->ecc.size,
pr_err("ELM is required for this ECC scheme\n"); nand_chip->ecc.size, nand_chip->ecc.bytes);
if (err < 0)
goto return_error; goto return_error;
}
/* define ECC layout */ /* define ECC layout */
ecclayout->eccbytes = nand_chip->ecc.bytes * ecclayout->eccbytes = nand_chip->ecc.bytes *
(mtd->writesize / (mtd->writesize /
...@@ -2004,13 +2028,8 @@ static int omap_nand_probe(struct platform_device *pdev) ...@@ -2004,13 +2028,8 @@ static int omap_nand_probe(struct platform_device *pdev)
ecclayout->oobfree->offset = ecclayout->oobfree->offset =
ecclayout->eccpos[ecclayout->eccbytes - 1] + 1; ecclayout->eccpos[ecclayout->eccbytes - 1] + 1;
break; break;
#else
pr_err("nand: error: CONFIG_MTD_NAND_OMAP_BCH not enabled\n");
err = -EINVAL;
goto return_error;
#endif
default: default:
pr_err("nand: error: invalid or unsupported ECC scheme\n"); dev_err(&info->pdev->dev, "invalid or unsupported ECC scheme\n");
err = -EINVAL; err = -EINVAL;
goto return_error; goto return_error;
} }
...@@ -2022,7 +2041,8 @@ static int omap_nand_probe(struct platform_device *pdev) ...@@ -2022,7 +2041,8 @@ static int omap_nand_probe(struct platform_device *pdev)
ecclayout->oobfree->length = mtd->oobsize - ecclayout->oobfree->offset; ecclayout->oobfree->length = mtd->oobsize - ecclayout->oobfree->offset;
/* check if NAND device's OOB is enough to store ECC signatures */ /* check if NAND device's OOB is enough to store ECC signatures */
if (mtd->oobsize < (ecclayout->eccbytes + BADBLOCK_MARKER_LENGTH)) { if (mtd->oobsize < (ecclayout->eccbytes + BADBLOCK_MARKER_LENGTH)) {
pr_err("not enough OOB bytes required = %d, available=%d\n", dev_err(&info->pdev->dev,
"not enough OOB bytes required = %d, available=%d\n",
ecclayout->eccbytes, mtd->oobsize); ecclayout->eccbytes, mtd->oobsize);
err = -EINVAL; err = -EINVAL;
goto return_error; goto return_error;
......
...@@ -18,7 +18,7 @@ struct sm_oob { ...@@ -18,7 +18,7 @@ struct sm_oob {
uint8_t ecc2[3]; uint8_t ecc2[3];
uint8_t lba_copy2[2]; uint8_t lba_copy2[2];
uint8_t ecc1[3]; uint8_t ecc1[3];
} __attribute__((packed)); } __packed;
/* one sector is always 512 bytes, but it can consist of two nand pages */ /* one sector is always 512 bytes, but it can consist of two nand pages */
......
...@@ -1058,7 +1058,7 @@ static int sm_write(struct mtd_blktrans_dev *dev, ...@@ -1058,7 +1058,7 @@ static int sm_write(struct mtd_blktrans_dev *dev,
{ {
struct sm_ftl *ftl = dev->priv; struct sm_ftl *ftl = dev->priv;
struct ftl_zone *zone; struct ftl_zone *zone;
int error, zone_num, block, boffset; int error = 0, zone_num, block, boffset;
BUG_ON(ftl->readonly); BUG_ON(ftl->readonly);
sm_break_offset(ftl, sec_no << 9, &zone_num, &block, &boffset); sm_break_offset(ftl, sec_no << 9, &zone_num, &block, &boffset);
......
...@@ -7,6 +7,20 @@ menuconfig MTD_SPI_NOR ...@@ -7,6 +7,20 @@ menuconfig MTD_SPI_NOR
if MTD_SPI_NOR if MTD_SPI_NOR
config MTD_SPI_NOR_USE_4K_SECTORS
bool "Use small 4096 B erase sectors"
default y
help
Many flash memories support erasing small (4096 B) sectors. Depending
on the usage this feature may provide performance gain in comparison
to erasing whole blocks (32/64 KiB).
Changing a small part of the flash's contents is usually faster with
small sectors. On the other hand erasing should be faster when using
64 KiB block instead of 16 × 4 KiB sectors.
Please note that some tools/drivers/filesystems may not work with
4096 B erase size (e.g. UBIFS requires 15 KiB as a minimum).
config SPI_FSL_QUADSPI config SPI_FSL_QUADSPI
tristate "Freescale Quad SPI controller" tristate "Freescale Quad SPI controller"
depends on ARCH_MXC depends on ARCH_MXC
......
...@@ -611,6 +611,7 @@ const struct spi_device_id spi_nor_ids[] = { ...@@ -611,6 +611,7 @@ const struct spi_device_id spi_nor_ids[] = {
{ "m25px32-s0", INFO(0x207316, 0, 64 * 1024, 64, SECT_4K) }, { "m25px32-s0", INFO(0x207316, 0, 64 * 1024, 64, SECT_4K) },
{ "m25px32-s1", INFO(0x206316, 0, 64 * 1024, 64, SECT_4K) }, { "m25px32-s1", INFO(0x206316, 0, 64 * 1024, 64, SECT_4K) },
{ "m25px64", INFO(0x207117, 0, 64 * 1024, 128, 0) }, { "m25px64", INFO(0x207117, 0, 64 * 1024, 128, 0) },
{ "m25px80", INFO(0x207114, 0, 64 * 1024, 16, 0) },
/* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */ /* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */
{ "w25x10", INFO(0xef3011, 0, 64 * 1024, 2, SECT_4K) }, { "w25x10", INFO(0xef3011, 0, 64 * 1024, 2, SECT_4K) },
...@@ -623,7 +624,6 @@ const struct spi_device_id spi_nor_ids[] = { ...@@ -623,7 +624,6 @@ const struct spi_device_id spi_nor_ids[] = {
{ "w25q32dw", INFO(0xef6016, 0, 64 * 1024, 64, SECT_4K) }, { "w25q32dw", INFO(0xef6016, 0, 64 * 1024, 64, SECT_4K) },
{ "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) }, { "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) },
{ "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) }, { "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) },
{ "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) },
{ "w25q80", INFO(0xef5014, 0, 64 * 1024, 16, SECT_4K) }, { "w25q80", INFO(0xef5014, 0, 64 * 1024, 16, SECT_4K) },
{ "w25q80bl", INFO(0xef4014, 0, 64 * 1024, 16, SECT_4K) }, { "w25q80bl", INFO(0xef4014, 0, 64 * 1024, 16, SECT_4K) },
{ "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) }, { "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) },
...@@ -671,11 +671,6 @@ static const struct spi_device_id *spi_nor_read_id(struct spi_nor *nor) ...@@ -671,11 +671,6 @@ static const struct spi_device_id *spi_nor_read_id(struct spi_nor *nor)
return ERR_PTR(-ENODEV); return ERR_PTR(-ENODEV);
} }
static const struct spi_device_id *jedec_probe(struct spi_nor *nor)
{
return nor->read_id(nor);
}
static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len, static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf) size_t *retlen, u_char *buf)
{ {
...@@ -920,7 +915,6 @@ int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id, ...@@ -920,7 +915,6 @@ int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id,
enum read_mode mode) enum read_mode mode)
{ {
struct flash_info *info; struct flash_info *info;
struct flash_platform_data *data;
struct device *dev = nor->dev; struct device *dev = nor->dev;
struct mtd_info *mtd = nor->mtd; struct mtd_info *mtd = nor->mtd;
struct device_node *np = dev->of_node; struct device_node *np = dev->of_node;
...@@ -931,34 +925,12 @@ int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id, ...@@ -931,34 +925,12 @@ int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id,
if (ret) if (ret)
return ret; return ret;
/* Platform data helps sort out which chip type we have, as
* well as how this board partitions it. If we don't have
* a chip ID, try the JEDEC id commands; they'll work for most
* newer chips, even if we don't recognize the particular chip.
*/
data = dev_get_platdata(dev);
if (data && data->type) {
const struct spi_device_id *plat_id;
for (i = 0; i < ARRAY_SIZE(spi_nor_ids) - 1; i++) {
plat_id = &spi_nor_ids[i];
if (strcmp(data->type, plat_id->name))
continue;
break;
}
if (i < ARRAY_SIZE(spi_nor_ids) - 1)
id = plat_id;
else
dev_warn(dev, "unrecognized id %s\n", data->type);
}
info = (void *)id->driver_data; info = (void *)id->driver_data;
if (info->jedec_id) { if (info->jedec_id) {
const struct spi_device_id *jid; const struct spi_device_id *jid;
jid = jedec_probe(nor); jid = nor->read_id(nor);
if (IS_ERR(jid)) { if (IS_ERR(jid)) {
return PTR_ERR(jid); return PTR_ERR(jid);
} else if (jid != id) { } else if (jid != id) {
...@@ -990,11 +962,8 @@ int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id, ...@@ -990,11 +962,8 @@ int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id,
write_sr(nor, 0); write_sr(nor, 0);
} }
if (data && data->name) if (!mtd->name)
mtd->name = data->name;
else
mtd->name = dev_name(dev); mtd->name = dev_name(dev);
mtd->type = MTD_NORFLASH; mtd->type = MTD_NORFLASH;
mtd->writesize = 1; mtd->writesize = 1;
mtd->flags = MTD_CAP_NORFLASH; mtd->flags = MTD_CAP_NORFLASH;
...@@ -1018,6 +987,7 @@ int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id, ...@@ -1018,6 +987,7 @@ int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id,
nor->wait_till_ready == spi_nor_wait_till_ready) nor->wait_till_ready == spi_nor_wait_till_ready)
nor->wait_till_ready = spi_nor_wait_till_fsr_ready; nor->wait_till_ready = spi_nor_wait_till_fsr_ready;
#ifdef CONFIG_MTD_SPI_NOR_USE_4K_SECTORS
/* prefer "small sector" erase if possible */ /* prefer "small sector" erase if possible */
if (info->flags & SECT_4K) { if (info->flags & SECT_4K) {
nor->erase_opcode = SPINOR_OP_BE_4K; nor->erase_opcode = SPINOR_OP_BE_4K;
...@@ -1025,7 +995,9 @@ int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id, ...@@ -1025,7 +995,9 @@ int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id,
} else if (info->flags & SECT_4K_PMC) { } else if (info->flags & SECT_4K_PMC) {
nor->erase_opcode = SPINOR_OP_BE_4K_PMC; nor->erase_opcode = SPINOR_OP_BE_4K_PMC;
mtd->erasesize = 4096; mtd->erasesize = 4096;
} else { } else
#endif
{
nor->erase_opcode = SPINOR_OP_SE; nor->erase_opcode = SPINOR_OP_SE;
mtd->erasesize = info->sector_size; mtd->erasesize = info->sector_size;
} }
......
...@@ -10,7 +10,7 @@ int mtdtest_erase_eraseblock(struct mtd_info *mtd, unsigned int ebnum) ...@@ -10,7 +10,7 @@ int mtdtest_erase_eraseblock(struct mtd_info *mtd, unsigned int ebnum)
{ {
int err; int err;
struct erase_info ei; struct erase_info ei;
loff_t addr = ebnum * mtd->erasesize; loff_t addr = (loff_t)ebnum * mtd->erasesize;
memset(&ei, 0, sizeof(struct erase_info)); memset(&ei, 0, sizeof(struct erase_info));
ei.mtd = mtd; ei.mtd = mtd;
...@@ -33,7 +33,7 @@ int mtdtest_erase_eraseblock(struct mtd_info *mtd, unsigned int ebnum) ...@@ -33,7 +33,7 @@ int mtdtest_erase_eraseblock(struct mtd_info *mtd, unsigned int ebnum)
static int is_block_bad(struct mtd_info *mtd, unsigned int ebnum) static int is_block_bad(struct mtd_info *mtd, unsigned int ebnum)
{ {
int ret; int ret;
loff_t addr = ebnum * mtd->erasesize; loff_t addr = (loff_t)ebnum * mtd->erasesize;
ret = mtd_block_isbad(mtd, addr); ret = mtd_block_isbad(mtd, addr);
if (ret) if (ret)
......
...@@ -364,7 +364,7 @@ static int __init mtd_nandbiterrs_init(void) ...@@ -364,7 +364,7 @@ static int __init mtd_nandbiterrs_init(void)
pr_info("Device uses %d subpages of %d bytes\n", subcount, subsize); pr_info("Device uses %d subpages of %d bytes\n", subcount, subsize);
offset = page_offset * mtd->writesize; offset = (loff_t)page_offset * mtd->writesize;
eraseblock = mtd_div_by_eb(offset, mtd); eraseblock = mtd_div_by_eb(offset, mtd);
pr_info("Using page=%u, offset=%llu, eraseblock=%u\n", pr_info("Using page=%u, offset=%llu, eraseblock=%u\n",
......
...@@ -120,7 +120,7 @@ static int verify_eraseblock(int ebnum) ...@@ -120,7 +120,7 @@ static int verify_eraseblock(int ebnum)
int i; int i;
struct mtd_oob_ops ops; struct mtd_oob_ops ops;
int err = 0; int err = 0;
loff_t addr = ebnum * mtd->erasesize; loff_t addr = (loff_t)ebnum * mtd->erasesize;
prandom_bytes_state(&rnd_state, writebuf, use_len_max * pgcnt); prandom_bytes_state(&rnd_state, writebuf, use_len_max * pgcnt);
for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) { for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) {
...@@ -214,7 +214,7 @@ static int verify_eraseblock_in_one_go(int ebnum) ...@@ -214,7 +214,7 @@ static int verify_eraseblock_in_one_go(int ebnum)
{ {
struct mtd_oob_ops ops; struct mtd_oob_ops ops;
int err = 0; int err = 0;
loff_t addr = ebnum * mtd->erasesize; loff_t addr = (loff_t)ebnum * mtd->erasesize;
size_t len = mtd->ecclayout->oobavail * pgcnt; size_t len = mtd->ecclayout->oobavail * pgcnt;
prandom_bytes_state(&rnd_state, writebuf, len); prandom_bytes_state(&rnd_state, writebuf, len);
...@@ -568,7 +568,7 @@ static int __init mtd_oobtest_init(void) ...@@ -568,7 +568,7 @@ static int __init mtd_oobtest_init(void)
size_t sz = mtd->ecclayout->oobavail; size_t sz = mtd->ecclayout->oobavail;
if (bbt[i] || bbt[i + 1]) if (bbt[i] || bbt[i + 1])
continue; continue;
addr = (i + 1) * mtd->erasesize - mtd->writesize; addr = (loff_t)(i + 1) * mtd->erasesize - mtd->writesize;
prandom_bytes_state(&rnd_state, writebuf, sz * cnt); prandom_bytes_state(&rnd_state, writebuf, sz * cnt);
for (pg = 0; pg < cnt; ++pg) { for (pg = 0; pg < cnt; ++pg) {
ops.mode = MTD_OPS_AUTO_OOB; ops.mode = MTD_OPS_AUTO_OOB;
...@@ -598,7 +598,7 @@ static int __init mtd_oobtest_init(void) ...@@ -598,7 +598,7 @@ static int __init mtd_oobtest_init(void)
continue; continue;
prandom_bytes_state(&rnd_state, writebuf, prandom_bytes_state(&rnd_state, writebuf,
mtd->ecclayout->oobavail * 2); mtd->ecclayout->oobavail * 2);
addr = (i + 1) * mtd->erasesize - mtd->writesize; addr = (loff_t)(i + 1) * mtd->erasesize - mtd->writesize;
ops.mode = MTD_OPS_AUTO_OOB; ops.mode = MTD_OPS_AUTO_OOB;
ops.len = 0; ops.len = 0;
ops.retlen = 0; ops.retlen = 0;
......
...@@ -52,7 +52,7 @@ static struct rnd_state rnd_state; ...@@ -52,7 +52,7 @@ static struct rnd_state rnd_state;
static int write_eraseblock(int ebnum) static int write_eraseblock(int ebnum)
{ {
loff_t addr = ebnum * mtd->erasesize; loff_t addr = (loff_t)ebnum * mtd->erasesize;
prandom_bytes_state(&rnd_state, writebuf, mtd->erasesize); prandom_bytes_state(&rnd_state, writebuf, mtd->erasesize);
cond_resched(); cond_resched();
...@@ -64,7 +64,7 @@ static int verify_eraseblock(int ebnum) ...@@ -64,7 +64,7 @@ static int verify_eraseblock(int ebnum)
uint32_t j; uint32_t j;
int err = 0, i; int err = 0, i;
loff_t addr0, addrn; loff_t addr0, addrn;
loff_t addr = ebnum * mtd->erasesize; loff_t addr = (loff_t)ebnum * mtd->erasesize;
addr0 = 0; addr0 = 0;
for (i = 0; i < ebcnt && bbt[i]; ++i) for (i = 0; i < ebcnt && bbt[i]; ++i)
......
...@@ -47,7 +47,7 @@ static int pgcnt; ...@@ -47,7 +47,7 @@ static int pgcnt;
static int read_eraseblock_by_page(int ebnum) static int read_eraseblock_by_page(int ebnum)
{ {
int i, ret, err = 0; int i, ret, err = 0;
loff_t addr = ebnum * mtd->erasesize; loff_t addr = (loff_t)ebnum * mtd->erasesize;
void *buf = iobuf; void *buf = iobuf;
void *oobbuf = iobuf1; void *oobbuf = iobuf1;
......
...@@ -55,7 +55,7 @@ static int multiblock_erase(int ebnum, int blocks) ...@@ -55,7 +55,7 @@ static int multiblock_erase(int ebnum, int blocks)
{ {
int err; int err;
struct erase_info ei; struct erase_info ei;
loff_t addr = ebnum * mtd->erasesize; loff_t addr = (loff_t)ebnum * mtd->erasesize;
memset(&ei, 0, sizeof(struct erase_info)); memset(&ei, 0, sizeof(struct erase_info));
ei.mtd = mtd; ei.mtd = mtd;
...@@ -80,7 +80,7 @@ static int multiblock_erase(int ebnum, int blocks) ...@@ -80,7 +80,7 @@ static int multiblock_erase(int ebnum, int blocks)
static int write_eraseblock(int ebnum) static int write_eraseblock(int ebnum)
{ {
loff_t addr = ebnum * mtd->erasesize; loff_t addr = (loff_t)ebnum * mtd->erasesize;
return mtdtest_write(mtd, addr, mtd->erasesize, iobuf); return mtdtest_write(mtd, addr, mtd->erasesize, iobuf);
} }
...@@ -88,7 +88,7 @@ static int write_eraseblock(int ebnum) ...@@ -88,7 +88,7 @@ static int write_eraseblock(int ebnum)
static int write_eraseblock_by_page(int ebnum) static int write_eraseblock_by_page(int ebnum)
{ {
int i, err = 0; int i, err = 0;
loff_t addr = ebnum * mtd->erasesize; loff_t addr = (loff_t)ebnum * mtd->erasesize;
void *buf = iobuf; void *buf = iobuf;
for (i = 0; i < pgcnt; i++) { for (i = 0; i < pgcnt; i++) {
...@@ -106,7 +106,7 @@ static int write_eraseblock_by_2pages(int ebnum) ...@@ -106,7 +106,7 @@ static int write_eraseblock_by_2pages(int ebnum)
{ {
size_t sz = pgsize * 2; size_t sz = pgsize * 2;
int i, n = pgcnt / 2, err = 0; int i, n = pgcnt / 2, err = 0;
loff_t addr = ebnum * mtd->erasesize; loff_t addr = (loff_t)ebnum * mtd->erasesize;
void *buf = iobuf; void *buf = iobuf;
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
...@@ -124,7 +124,7 @@ static int write_eraseblock_by_2pages(int ebnum) ...@@ -124,7 +124,7 @@ static int write_eraseblock_by_2pages(int ebnum)
static int read_eraseblock(int ebnum) static int read_eraseblock(int ebnum)
{ {
loff_t addr = ebnum * mtd->erasesize; loff_t addr = (loff_t)ebnum * mtd->erasesize;
return mtdtest_read(mtd, addr, mtd->erasesize, iobuf); return mtdtest_read(mtd, addr, mtd->erasesize, iobuf);
} }
...@@ -132,7 +132,7 @@ static int read_eraseblock(int ebnum) ...@@ -132,7 +132,7 @@ static int read_eraseblock(int ebnum)
static int read_eraseblock_by_page(int ebnum) static int read_eraseblock_by_page(int ebnum)
{ {
int i, err = 0; int i, err = 0;
loff_t addr = ebnum * mtd->erasesize; loff_t addr = (loff_t)ebnum * mtd->erasesize;
void *buf = iobuf; void *buf = iobuf;
for (i = 0; i < pgcnt; i++) { for (i = 0; i < pgcnt; i++) {
...@@ -150,7 +150,7 @@ static int read_eraseblock_by_2pages(int ebnum) ...@@ -150,7 +150,7 @@ static int read_eraseblock_by_2pages(int ebnum)
{ {
size_t sz = pgsize * 2; size_t sz = pgsize * 2;
int i, n = pgcnt / 2, err = 0; int i, n = pgcnt / 2, err = 0;
loff_t addr = ebnum * mtd->erasesize; loff_t addr = (loff_t)ebnum * mtd->erasesize;
void *buf = iobuf; void *buf = iobuf;
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
......
...@@ -57,7 +57,7 @@ static int write_eraseblock(int ebnum) ...@@ -57,7 +57,7 @@ static int write_eraseblock(int ebnum)
{ {
size_t written; size_t written;
int err = 0; int err = 0;
loff_t addr = ebnum * mtd->erasesize; loff_t addr = (loff_t)ebnum * mtd->erasesize;
prandom_bytes_state(&rnd_state, writebuf, subpgsize); prandom_bytes_state(&rnd_state, writebuf, subpgsize);
err = mtd_write(mtd, addr, subpgsize, &written, writebuf); err = mtd_write(mtd, addr, subpgsize, &written, writebuf);
...@@ -92,7 +92,7 @@ static int write_eraseblock2(int ebnum) ...@@ -92,7 +92,7 @@ static int write_eraseblock2(int ebnum)
{ {
size_t written; size_t written;
int err = 0, k; int err = 0, k;
loff_t addr = ebnum * mtd->erasesize; loff_t addr = (loff_t)ebnum * mtd->erasesize;
for (k = 1; k < 33; ++k) { for (k = 1; k < 33; ++k) {
if (addr + (subpgsize * k) > (ebnum + 1) * mtd->erasesize) if (addr + (subpgsize * k) > (ebnum + 1) * mtd->erasesize)
...@@ -131,7 +131,7 @@ static int verify_eraseblock(int ebnum) ...@@ -131,7 +131,7 @@ static int verify_eraseblock(int ebnum)
{ {
size_t read; size_t read;
int err = 0; int err = 0;
loff_t addr = ebnum * mtd->erasesize; loff_t addr = (loff_t)ebnum * mtd->erasesize;
prandom_bytes_state(&rnd_state, writebuf, subpgsize); prandom_bytes_state(&rnd_state, writebuf, subpgsize);
clear_data(readbuf, subpgsize); clear_data(readbuf, subpgsize);
...@@ -192,7 +192,7 @@ static int verify_eraseblock2(int ebnum) ...@@ -192,7 +192,7 @@ static int verify_eraseblock2(int ebnum)
{ {
size_t read; size_t read;
int err = 0, k; int err = 0, k;
loff_t addr = ebnum * mtd->erasesize; loff_t addr = (loff_t)ebnum * mtd->erasesize;
for (k = 1; k < 33; ++k) { for (k = 1; k < 33; ++k) {
if (addr + (subpgsize * k) > (ebnum + 1) * mtd->erasesize) if (addr + (subpgsize * k) > (ebnum + 1) * mtd->erasesize)
...@@ -227,7 +227,7 @@ static int verify_eraseblock_ff(int ebnum) ...@@ -227,7 +227,7 @@ static int verify_eraseblock_ff(int ebnum)
uint32_t j; uint32_t j;
size_t read; size_t read;
int err = 0; int err = 0;
loff_t addr = ebnum * mtd->erasesize; loff_t addr = (loff_t)ebnum * mtd->erasesize;
memset(writebuf, 0xff, subpgsize); memset(writebuf, 0xff, subpgsize);
for (j = 0; j < mtd->erasesize / subpgsize; ++j) { for (j = 0; j < mtd->erasesize / subpgsize; ++j) {
......
...@@ -153,7 +153,7 @@ struct cfi_ident { ...@@ -153,7 +153,7 @@ struct cfi_ident {
uint16_t MaxBufWriteSize; uint16_t MaxBufWriteSize;
uint8_t NumEraseRegions; uint8_t NumEraseRegions;
uint32_t EraseRegionInfo[0]; /* Not host ordered */ uint32_t EraseRegionInfo[0]; /* Not host ordered */
} __attribute__((packed)); } __packed;
/* Extended Query Structure for both PRI and ALT */ /* Extended Query Structure for both PRI and ALT */
...@@ -161,7 +161,7 @@ struct cfi_extquery { ...@@ -161,7 +161,7 @@ struct cfi_extquery {
uint8_t pri[3]; uint8_t pri[3];
uint8_t MajorVersion; uint8_t MajorVersion;
uint8_t MinorVersion; uint8_t MinorVersion;
} __attribute__((packed)); } __packed;
/* Vendor-Specific PRI for Intel/Sharp Extended Command Set (0x0001) */ /* Vendor-Specific PRI for Intel/Sharp Extended Command Set (0x0001) */
...@@ -180,7 +180,7 @@ struct cfi_pri_intelext { ...@@ -180,7 +180,7 @@ struct cfi_pri_intelext {
uint8_t FactProtRegSize; uint8_t FactProtRegSize;
uint8_t UserProtRegSize; uint8_t UserProtRegSize;
uint8_t extra[0]; uint8_t extra[0];
} __attribute__((packed)); } __packed;
struct cfi_intelext_otpinfo { struct cfi_intelext_otpinfo {
uint32_t ProtRegAddr; uint32_t ProtRegAddr;
...@@ -188,7 +188,7 @@ struct cfi_intelext_otpinfo { ...@@ -188,7 +188,7 @@ struct cfi_intelext_otpinfo {
uint8_t FactProtRegSize; uint8_t FactProtRegSize;
uint16_t UserGroups; uint16_t UserGroups;
uint8_t UserProtRegSize; uint8_t UserProtRegSize;
} __attribute__((packed)); } __packed;
struct cfi_intelext_blockinfo { struct cfi_intelext_blockinfo {
uint16_t NumIdentBlocks; uint16_t NumIdentBlocks;
...@@ -196,7 +196,7 @@ struct cfi_intelext_blockinfo { ...@@ -196,7 +196,7 @@ struct cfi_intelext_blockinfo {
uint16_t MinBlockEraseCycles; uint16_t MinBlockEraseCycles;
uint8_t BitsPerCell; uint8_t BitsPerCell;
uint8_t BlockCap; uint8_t BlockCap;
} __attribute__((packed)); } __packed;
struct cfi_intelext_regioninfo { struct cfi_intelext_regioninfo {
uint16_t NumIdentPartitions; uint16_t NumIdentPartitions;
...@@ -205,7 +205,7 @@ struct cfi_intelext_regioninfo { ...@@ -205,7 +205,7 @@ struct cfi_intelext_regioninfo {
uint8_t NumOpAllowedSimEraMode; uint8_t NumOpAllowedSimEraMode;
uint8_t NumBlockTypes; uint8_t NumBlockTypes;
struct cfi_intelext_blockinfo BlockTypes[1]; struct cfi_intelext_blockinfo BlockTypes[1];
} __attribute__((packed)); } __packed;
struct cfi_intelext_programming_regioninfo { struct cfi_intelext_programming_regioninfo {
uint8_t ProgRegShift; uint8_t ProgRegShift;
...@@ -214,7 +214,7 @@ struct cfi_intelext_programming_regioninfo { ...@@ -214,7 +214,7 @@ struct cfi_intelext_programming_regioninfo {
uint8_t Reserved2; uint8_t Reserved2;
uint8_t ControlInvalid; uint8_t ControlInvalid;
uint8_t Reserved3; uint8_t Reserved3;
} __attribute__((packed)); } __packed;
/* Vendor-Specific PRI for AMD/Fujitsu Extended Command Set (0x0002) */ /* Vendor-Specific PRI for AMD/Fujitsu Extended Command Set (0x0002) */
...@@ -233,7 +233,7 @@ struct cfi_pri_amdstd { ...@@ -233,7 +233,7 @@ struct cfi_pri_amdstd {
uint8_t VppMin; uint8_t VppMin;
uint8_t VppMax; uint8_t VppMax;
uint8_t TopBottom; uint8_t TopBottom;
} __attribute__((packed)); } __packed;
/* Vendor-Specific PRI for Atmel chips (command set 0x0002) */ /* Vendor-Specific PRI for Atmel chips (command set 0x0002) */
...@@ -245,18 +245,18 @@ struct cfi_pri_atmel { ...@@ -245,18 +245,18 @@ struct cfi_pri_atmel {
uint8_t BottomBoot; uint8_t BottomBoot;
uint8_t BurstMode; uint8_t BurstMode;
uint8_t PageMode; uint8_t PageMode;
} __attribute__((packed)); } __packed;
struct cfi_pri_query { struct cfi_pri_query {
uint8_t NumFields; uint8_t NumFields;
uint32_t ProtField[1]; /* Not host ordered */ uint32_t ProtField[1]; /* Not host ordered */
} __attribute__((packed)); } __packed;
struct cfi_bri_query { struct cfi_bri_query {
uint8_t PageModeReadCap; uint8_t PageModeReadCap;
uint8_t NumFields; uint8_t NumFields;
uint32_t ConfField[1]; /* Not host ordered */ uint32_t ConfField[1]; /* Not host ordered */
} __attribute__((packed)); } __packed;
#define P_ID_NONE 0x0000 #define P_ID_NONE 0x0000
#define P_ID_INTEL_EXT 0x0001 #define P_ID_INTEL_EXT 0x0001
......
...@@ -587,6 +587,11 @@ struct nand_buffers { ...@@ -587,6 +587,11 @@ struct nand_buffers {
* @ecc_step_ds: [INTERN] ECC step required by the @ecc_strength_ds, * @ecc_step_ds: [INTERN] ECC step required by the @ecc_strength_ds,
* also from the datasheet. It is the recommended ECC step * also from the datasheet. It is the recommended ECC step
* size, if known; if unknown, set to zero. * size, if known; if unknown, set to zero.
* @onfi_timing_mode_default: [INTERN] default ONFI timing mode. This field is
* either deduced from the datasheet if the NAND
* chip is not ONFI compliant or set to 0 if it is
* (an ONFI chip is always configured in mode 0
* after a NAND reset)
* @numchips: [INTERN] number of physical chips * @numchips: [INTERN] number of physical chips
* @chipsize: [INTERN] the size of one chip for multichip arrays * @chipsize: [INTERN] the size of one chip for multichip arrays
* @pagemask: [INTERN] page number mask = number of (pages / chip) - 1 * @pagemask: [INTERN] page number mask = number of (pages / chip) - 1
...@@ -671,6 +676,7 @@ struct nand_chip { ...@@ -671,6 +676,7 @@ struct nand_chip {
uint8_t bits_per_cell; uint8_t bits_per_cell;
uint16_t ecc_strength_ds; uint16_t ecc_strength_ds;
uint16_t ecc_step_ds; uint16_t ecc_step_ds;
int onfi_timing_mode_default;
int badblockpos; int badblockpos;
int badblockbits; int badblockbits;
...@@ -766,12 +772,17 @@ struct nand_chip { ...@@ -766,12 +772,17 @@ struct nand_chip {
* @options: stores various chip bit options * @options: stores various chip bit options
* @id_len: The valid length of the @id. * @id_len: The valid length of the @id.
* @oobsize: OOB size * @oobsize: OOB size
* @ecc: ECC correctability and step information from the datasheet.
* @ecc.strength_ds: The ECC correctability from the datasheet, same as the * @ecc.strength_ds: The ECC correctability from the datasheet, same as the
* @ecc_strength_ds in nand_chip{}. * @ecc_strength_ds in nand_chip{}.
* @ecc.step_ds: The ECC step required by the @ecc.strength_ds, same as the * @ecc.step_ds: The ECC step required by the @ecc.strength_ds, same as the
* @ecc_step_ds in nand_chip{}, also from the datasheet. * @ecc_step_ds in nand_chip{}, also from the datasheet.
* For example, the "4bit ECC for each 512Byte" can be set with * For example, the "4bit ECC for each 512Byte" can be set with
* NAND_ECC_INFO(4, 512). * NAND_ECC_INFO(4, 512).
* @onfi_timing_mode_default: the default ONFI timing mode entered after a NAND
* reset. Should be deduced from timings described
* in the datasheet.
*
*/ */
struct nand_flash_dev { struct nand_flash_dev {
char *name; char *name;
...@@ -792,6 +803,7 @@ struct nand_flash_dev { ...@@ -792,6 +803,7 @@ struct nand_flash_dev {
uint16_t strength_ds; uint16_t strength_ds;
uint16_t step_ds; uint16_t step_ds;
} ecc; } ecc;
int onfi_timing_mode_default;
}; };
/** /**
......
...@@ -42,8 +42,24 @@ struct elm_errorvec { ...@@ -42,8 +42,24 @@ struct elm_errorvec {
int error_loc[16]; int error_loc[16];
}; };
#if IS_ENABLED(CONFIG_MTD_NAND_OMAP_BCH)
void elm_decode_bch_error_page(struct device *dev, u8 *ecc_calc, void elm_decode_bch_error_page(struct device *dev, u8 *ecc_calc,
struct elm_errorvec *err_vec); struct elm_errorvec *err_vec);
int elm_config(struct device *dev, enum bch_ecc bch_type, int elm_config(struct device *dev, enum bch_ecc bch_type,
int ecc_steps, int ecc_step_size, int ecc_syndrome_size); int ecc_steps, int ecc_step_size, int ecc_syndrome_size);
#else
static inline void
elm_decode_bch_error_page(struct device *dev, u8 *ecc_calc,
struct elm_errorvec *err_vec)
{
}
static inline int elm_config(struct device *dev, enum bch_ecc bch_type,
int ecc_steps, int ecc_step_size,
int ecc_syndrome_size)
{
return -ENOSYS;
}
#endif /* CONFIG_MTD_NAND_ECC_BCH */
#endif /* __ELM_H */ #endif /* __ELM_H */
...@@ -71,6 +71,7 @@ struct omap_nand_platform_data { ...@@ -71,6 +71,7 @@ struct omap_nand_platform_data {
struct mtd_partition *parts; struct mtd_partition *parts;
int nr_parts; int nr_parts;
bool dev_ready; bool dev_ready;
bool flash_bbt;
enum nand_io xfer_type; enum nand_io xfer_type;
int devsize; int devsize;
enum omap_ecc ecc_opt; enum omap_ecc ecc_opt;
......
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