summaryrefslogtreecommitdiff
path: root/drivers/mtd
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd')
-rw-r--r--drivers/mtd/devices/m25p80.c49
-rw-r--r--drivers/mtd/maps/gpio-addr-flash.c146
-rw-r--r--drivers/mtd/maps/physmap_of_core.c27
-rw-r--r--drivers/mtd/maps/physmap_of_gemini.c5
-rw-r--r--drivers/mtd/mtd_blkdevs.c102
-rw-r--r--drivers/mtd/mtdpart.c5
-rw-r--r--drivers/mtd/nand/raw/Kconfig20
-rw-r--r--drivers/mtd/nand/raw/Makefile6
-rw-r--r--drivers/mtd/nand/raw/ams-delta.c249
-rw-r--r--drivers/mtd/nand/raw/atmel/nand-controller.c111
-rw-r--r--drivers/mtd/nand/raw/au1550nd.c124
-rw-r--r--drivers/mtd/nand/raw/bcm47xxnflash/main.c2
-rw-r--r--drivers/mtd/nand/raw/bcm47xxnflash/ops_bcm4706.c58
-rw-r--r--drivers/mtd/nand/raw/brcmnand/brcmnand.c93
-rw-r--r--drivers/mtd/nand/raw/cafe_nand.c74
-rw-r--r--drivers/mtd/nand/raw/cmx270_nand.c48
-rw-r--r--drivers/mtd/nand/raw/cs553x_nand.c75
-rw-r--r--drivers/mtd/nand/raw/davinci_nand.c93
-rw-r--r--drivers/mtd/nand/raw/denali.c162
-rw-r--r--drivers/mtd/nand/raw/denali.h10
-rw-r--r--drivers/mtd/nand/raw/denali_dt.c12
-rw-r--r--drivers/mtd/nand/raw/denali_pci.c10
-rw-r--r--drivers/mtd/nand/raw/diskonchip.c156
-rw-r--r--drivers/mtd/nand/raw/docg4.c1442
-rw-r--r--drivers/mtd/nand/raw/fsl_elbc_nand.c70
-rw-r--r--drivers/mtd/nand/raw/fsl_ifc_nand.c106
-rw-r--r--drivers/mtd/nand/raw/fsl_upm.c66
-rw-r--r--drivers/mtd/nand/raw/fsmc_nand.c44
-rw-r--r--drivers/mtd/nand/raw/gpio.c29
-rw-r--r--drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c3
-rw-r--r--drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c111
-rw-r--r--drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h2
-rw-r--r--drivers/mtd/nand/raw/hisi504_nand.c68
-rw-r--r--drivers/mtd/nand/raw/internals.h115
-rw-r--r--drivers/mtd/nand/raw/jz4740_nand.c53
-rw-r--r--drivers/mtd/nand/raw/jz4780_nand.c42
-rw-r--r--drivers/mtd/nand/raw/lpc32xx_mlc.c59
-rw-r--r--drivers/mtd/nand/raw/lpc32xx_slc.c83
-rw-r--r--drivers/mtd/nand/raw/marvell_nand.c279
-rw-r--r--drivers/mtd/nand/raw/mpc5121_nfc.c65
-rw-r--r--drivers/mtd/nand/raw/mtk_nand.c93
-rw-r--r--drivers/mtd/nand/raw/mxc_nand.c114
-rw-r--r--drivers/mtd/nand/raw/nand_amd.c2
-rw-r--r--drivers/mtd/nand/raw/nand_base.c1721
-rw-r--r--drivers/mtd/nand/raw/nand_bbt.c24
-rw-r--r--drivers/mtd/nand/raw/nand_bch.c10
-rw-r--r--drivers/mtd/nand/raw/nand_ecc.c99
-rw-r--r--drivers/mtd/nand/raw/nand_esmt.c47
-rw-r--r--drivers/mtd/nand/raw/nand_hynix.c15
-rw-r--r--drivers/mtd/nand/raw/nand_ids.c26
-rw-r--r--drivers/mtd/nand/raw/nand_jedec.c113
-rw-r--r--drivers/mtd/nand/raw/nand_legacy.c642
-rw-r--r--drivers/mtd/nand/raw/nand_macronix.c2
-rw-r--r--drivers/mtd/nand/raw/nand_micron.c19
-rw-r--r--drivers/mtd/nand/raw/nand_onfi.c305
-rw-r--r--drivers/mtd/nand/raw/nand_samsung.c2
-rw-r--r--drivers/mtd/nand/raw/nand_timings.c18
-rw-r--r--drivers/mtd/nand/raw/nand_toshiba.c88
-rw-r--r--drivers/mtd/nand/raw/nandsim.c50
-rw-r--r--drivers/mtd/nand/raw/ndfc.c43
-rw-r--r--drivers/mtd/nand/raw/nuc900_nand.c47
-rw-r--r--drivers/mtd/nand/raw/omap2.c200
-rw-r--r--drivers/mtd/nand/raw/orion_nand.c26
-rw-r--r--drivers/mtd/nand/raw/oxnas_nand.c29
-rw-r--r--drivers/mtd/nand/raw/pasemi_nand.c51
-rw-r--r--drivers/mtd/nand/raw/plat_nand.c23
-rw-r--r--drivers/mtd/nand/raw/qcom_nandc.c92
-rw-r--r--drivers/mtd/nand/raw/r852.c80
-rw-r--r--drivers/mtd/nand/raw/r852.h2
-rw-r--r--drivers/mtd/nand/raw/s3c2410.c106
-rw-r--r--drivers/mtd/nand/raw/sh_flctl.c68
-rw-r--r--drivers/mtd/nand/raw/sharpsl.c36
-rw-r--r--drivers/mtd/nand/raw/sm_common.c7
-rw-r--r--drivers/mtd/nand/raw/socrates_nand.c60
-rw-r--r--drivers/mtd/nand/raw/sunxi_nand.c96
-rw-r--r--drivers/mtd/nand/raw/tango_nand.c77
-rw-r--r--drivers/mtd/nand/raw/tegra_nand.c36
-rw-r--r--drivers/mtd/nand/raw/tmio_nand.c78
-rw-r--r--drivers/mtd/nand/raw/txx9ndfmc.c53
-rw-r--r--drivers/mtd/nand/raw/vf610_nfc.c43
-rw-r--r--drivers/mtd/nand/raw/xway_nand.c39
-rw-r--r--drivers/mtd/sm_ftl.c20
-rw-r--r--drivers/mtd/spi-nor/cadence-quadspi.c4
-rw-r--r--drivers/mtd/spi-nor/fsl-quadspi.c15
-rw-r--r--drivers/mtd/spi-nor/intel-spi-pci.c1
-rw-r--r--drivers/mtd/spi-nor/spi-nor.c925
-rw-r--r--drivers/mtd/tests/mtd_nandecctest.c21
87 files changed, 4749 insertions, 5193 deletions
diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
index cbfafc453274..c4a1d04b8c80 100644
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
@@ -39,13 +39,23 @@ static int m25p80_read_reg(struct spi_nor *nor, u8 code, u8 *val, int len)
struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(code, 1),
SPI_MEM_OP_NO_ADDR,
SPI_MEM_OP_NO_DUMMY,
- SPI_MEM_OP_DATA_IN(len, val, 1));
+ SPI_MEM_OP_DATA_IN(len, NULL, 1));
+ void *scratchbuf;
int ret;
+ scratchbuf = kmalloc(len, GFP_KERNEL);
+ if (!scratchbuf)
+ return -ENOMEM;
+
+ op.data.buf.in = scratchbuf;
ret = spi_mem_exec_op(flash->spimem, &op);
if (ret < 0)
dev_err(&flash->spimem->spi->dev, "error %d reading %x\n", ret,
code);
+ else
+ memcpy(val, scratchbuf, len);
+
+ kfree(scratchbuf);
return ret;
}
@@ -56,9 +66,19 @@ static int m25p80_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(opcode, 1),
SPI_MEM_OP_NO_ADDR,
SPI_MEM_OP_NO_DUMMY,
- SPI_MEM_OP_DATA_OUT(len, buf, 1));
+ SPI_MEM_OP_DATA_OUT(len, NULL, 1));
+ void *scratchbuf;
+ int ret;
+
+ scratchbuf = kmemdup(buf, len, GFP_KERNEL);
+ if (!scratchbuf)
+ return -ENOMEM;
- return spi_mem_exec_op(flash->spimem, &op);
+ op.data.buf.out = scratchbuf;
+ ret = spi_mem_exec_op(flash->spimem, &op);
+ kfree(scratchbuf);
+
+ return ret;
}
static ssize_t m25p80_write(struct spi_nor *nor, loff_t to, size_t len,
@@ -70,7 +90,6 @@ static ssize_t m25p80_write(struct spi_nor *nor, loff_t to, size_t len,
SPI_MEM_OP_ADDR(nor->addr_width, to, 1),
SPI_MEM_OP_NO_DUMMY,
SPI_MEM_OP_DATA_OUT(len, buf, 1));
- size_t remaining = len;
int ret;
/* get transfer protocols. */
@@ -81,22 +100,16 @@ static ssize_t m25p80_write(struct spi_nor *nor, loff_t to, size_t len,
if (nor->program_opcode == SPINOR_OP_AAI_WP && nor->sst_write_second)
op.addr.nbytes = 0;
- while (remaining) {
- op.data.nbytes = remaining < UINT_MAX ? remaining : UINT_MAX;
- ret = spi_mem_adjust_op_size(flash->spimem, &op);
- if (ret)
- return ret;
-
- ret = spi_mem_exec_op(flash->spimem, &op);
- if (ret)
- return ret;
+ ret = spi_mem_adjust_op_size(flash->spimem, &op);
+ if (ret)
+ return ret;
+ op.data.nbytes = len < op.data.nbytes ? len : op.data.nbytes;
- op.addr.val += op.data.nbytes;
- remaining -= op.data.nbytes;
- op.data.buf.out += op.data.nbytes;
- }
+ ret = spi_mem_exec_op(flash->spimem, &op);
+ if (ret)
+ return ret;
- return len;
+ return op.data.nbytes;
}
/*
diff --git a/drivers/mtd/maps/gpio-addr-flash.c b/drivers/mtd/maps/gpio-addr-flash.c
index 9d9723693217..a20e85aa770e 100644
--- a/drivers/mtd/maps/gpio-addr-flash.c
+++ b/drivers/mtd/maps/gpio-addr-flash.c
@@ -14,6 +14,7 @@
*/
#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
@@ -25,28 +26,24 @@
#include <linux/slab.h>
#include <linux/types.h>
-#define pr_devinit(fmt, args...) \
- ({ static const char __fmt[] = fmt; printk(__fmt, ## args); })
+#define win_mask(x) ((BIT(x)) - 1)
#define DRIVER_NAME "gpio-addr-flash"
-#define PFX DRIVER_NAME ": "
/**
* struct async_state - keep GPIO flash state
* @mtd: MTD state for this mapping
* @map: MTD map state for this flash
- * @gpio_count: number of GPIOs used to address
- * @gpio_addrs: array of GPIOs to twiddle
+ * @gpios: Struct containing the array of GPIO descriptors
* @gpio_values: cached GPIO values
- * @win_size: dedicated memory size (if no GPIOs)
+ * @win_order: dedicated memory size (if no GPIOs)
*/
struct async_state {
struct mtd_info *mtd;
struct map_info map;
- size_t gpio_count;
- unsigned *gpio_addrs;
- int *gpio_values;
- unsigned long win_size;
+ struct gpio_descs *gpios;
+ unsigned int gpio_values;
+ unsigned int win_order;
};
#define gf_map_info_to_state(mi) ((struct async_state *)(mi)->map_priv_1)
@@ -57,21 +54,25 @@ struct async_state {
*
* Rather than call the GPIO framework every time, cache the last-programmed
* value. This speeds up sequential accesses (which are by far the most common
- * type). We rely on the GPIO framework to treat non-zero value as high so
- * that we don't have to normalize the bits.
+ * type).
*/
static void gf_set_gpios(struct async_state *state, unsigned long ofs)
{
- size_t i = 0;
- int value;
- ofs /= state->win_size;
- do {
- value = ofs & (1 << i);
- if (state->gpio_values[i] != value) {
- gpio_set_value(state->gpio_addrs[i], value);
- state->gpio_values[i] = value;
- }
- } while (++i < state->gpio_count);
+ int i;
+
+ ofs >>= state->win_order;
+
+ if (ofs == state->gpio_values)
+ return;
+
+ for (i = 0; i < state->gpios->ndescs; i++) {
+ if ((ofs & BIT(i)) == (state->gpio_values & BIT(i)))
+ continue;
+
+ gpiod_set_value(state->gpios->desc[i], !!(ofs & BIT(i)));
+ }
+
+ state->gpio_values = ofs;
}
/**
@@ -87,7 +88,7 @@ static map_word gf_read(struct map_info *map, unsigned long ofs)
gf_set_gpios(state, ofs);
- word = readw(map->virt + (ofs % state->win_size));
+ word = readw(map->virt + (ofs & win_mask(state->win_order)));
test.x[0] = word;
return test;
}
@@ -109,14 +110,14 @@ static void gf_copy_from(struct map_info *map, void *to, unsigned long from, ssi
int this_len;
while (len) {
- if ((from % state->win_size) + len > state->win_size)
- this_len = state->win_size - (from % state->win_size);
- else
- this_len = len;
+ this_len = from & win_mask(state->win_order);
+ this_len = BIT(state->win_order) - this_len;
+ this_len = min_t(int, len, this_len);
gf_set_gpios(state, from);
- memcpy_fromio(to, map->virt + (from % state->win_size),
- this_len);
+ memcpy_fromio(to,
+ map->virt + (from & win_mask(state->win_order)),
+ this_len);
len -= this_len;
from += this_len;
to += this_len;
@@ -136,7 +137,7 @@ static void gf_write(struct map_info *map, map_word d1, unsigned long ofs)
gf_set_gpios(state, ofs);
d = d1.x[0];
- writew(d, map->virt + (ofs % state->win_size));
+ writew(d, map->virt + (ofs & win_mask(state->win_order)));
}
/**
@@ -156,13 +157,13 @@ static void gf_copy_to(struct map_info *map, unsigned long to,
int this_len;
while (len) {
- if ((to % state->win_size) + len > state->win_size)
- this_len = state->win_size - (to % state->win_size);
- else
- this_len = len;
+ this_len = to & win_mask(state->win_order);
+ this_len = BIT(state->win_order) - this_len;
+ this_len = min_t(int, len, this_len);
gf_set_gpios(state, to);
- memcpy_toio(map->virt + (to % state->win_size), from, len);
+ memcpy_toio(map->virt + (to & win_mask(state->win_order)),
+ from, len);
len -= this_len;
to += this_len;
@@ -180,18 +181,22 @@ static const char * const part_probe_types[] = {
* The platform resource layout expected looks something like:
* struct mtd_partition partitions[] = { ... };
* struct physmap_flash_data flash_data = { ... };
- * unsigned flash_gpios[] = { GPIO_XX, GPIO_XX, ... };
+ * static struct gpiod_lookup_table addr_flash_gpios = {
+ * .dev_id = "gpio-addr-flash.0",
+ * .table = {
+ * GPIO_LOOKUP_IDX("gpio.0", 15, "addr", 0, GPIO_ACTIVE_HIGH),
+ * GPIO_LOOKUP_IDX("gpio.0", 16, "addr", 1, GPIO_ACTIVE_HIGH),
+ * );
+ * };
+ * gpiod_add_lookup_table(&addr_flash_gpios);
+ *
* struct resource flash_resource[] = {
* {
* .name = "cfi_probe",
* .start = 0x20000000,
* .end = 0x201fffff,
* .flags = IORESOURCE_MEM,
- * }, {
- * .start = (unsigned long)flash_gpios,
- * .end = ARRAY_SIZE(flash_gpios),
- * .flags = IORESOURCE_IRQ,
- * }
+ * },
* };
* struct platform_device flash_device = {
* .name = "gpio-addr-flash",
@@ -203,33 +208,25 @@ static const char * const part_probe_types[] = {
*/
static int gpio_flash_probe(struct platform_device *pdev)
{
- size_t i, arr_size;
struct physmap_flash_data *pdata;
struct resource *memory;
- struct resource *gpios;
struct async_state *state;
pdata = dev_get_platdata(&pdev->dev);
memory = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- gpios = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (!memory || !gpios || !gpios->end)
+ if (!memory)
return -EINVAL;
- arr_size = sizeof(int) * gpios->end;
- state = kzalloc(sizeof(*state) + arr_size, GFP_KERNEL);
+ state = devm_kzalloc(&pdev->dev, sizeof(*state), GFP_KERNEL);
if (!state)
return -ENOMEM;
- /*
- * We cast start/end to known types in the boards file, so cast
- * away their pointer types here to the known types (gpios->xxx).
- */
- state->gpio_count = gpios->end;
- state->gpio_addrs = (void *)(unsigned long)gpios->start;
- state->gpio_values = (void *)(state + 1);
- state->win_size = resource_size(memory);
- memset(state->gpio_values, 0xff, arr_size);
+ state->gpios = devm_gpiod_get_array(&pdev->dev, "addr", GPIOD_OUT_LOW);
+ if (IS_ERR(state->gpios))
+ return PTR_ERR(state->gpios);
+
+ state->win_order = get_bitmask_order(resource_size(memory)) - 1;
state->map.name = DRIVER_NAME;
state->map.read = gf_read;
@@ -237,38 +234,21 @@ static int gpio_flash_probe(struct platform_device *pdev)
state->map.write = gf_write;
state->map.copy_to = gf_copy_to;
state->map.bankwidth = pdata->width;
- state->map.size = state->win_size * (1 << state->gpio_count);
- state->map.virt = ioremap_nocache(memory->start, state->map.size);
- if (!state->map.virt)
- return -ENOMEM;
+ state->map.size = BIT(state->win_order + state->gpios->ndescs);
+ state->map.virt = devm_ioremap_resource(&pdev->dev, memory);
+ if (IS_ERR(state->map.virt))
+ return PTR_ERR(state->map.virt);
state->map.phys = NO_XIP;
state->map.map_priv_1 = (unsigned long)state;
platform_set_drvdata(pdev, state);
- i = 0;
- do {
- if (gpio_request(state->gpio_addrs[i], DRIVER_NAME)) {
- pr_devinit(KERN_ERR PFX "failed to request gpio %d\n",
- state->gpio_addrs[i]);
- while (i--)
- gpio_free(state->gpio_addrs[i]);
- kfree(state);
- return -EBUSY;
- }
- gpio_direction_output(state->gpio_addrs[i], 0);
- } while (++i < state->gpio_count);
-
- pr_devinit(KERN_NOTICE PFX "probing %d-bit flash bus\n",
- state->map.bankwidth * 8);
+ dev_notice(&pdev->dev, "probing %d-bit flash bus\n",
+ state->map.bankwidth * 8);
state->mtd = do_map_probe(memory->name, &state->map);
- if (!state->mtd) {
- for (i = 0; i < state->gpio_count; ++i)
- gpio_free(state->gpio_addrs[i]);
- kfree(state);
+ if (!state->mtd)
return -ENXIO;
- }
state->mtd->dev.parent = &pdev->dev;
mtd_device_parse_register(state->mtd, part_probe_types, NULL,
@@ -280,13 +260,9 @@ static int gpio_flash_probe(struct platform_device *pdev)
static int gpio_flash_remove(struct platform_device *pdev)
{
struct async_state *state = platform_get_drvdata(pdev);
- size_t i = 0;
- do {
- gpio_free(state->gpio_addrs[i]);
- } while (++i < state->gpio_count);
+
mtd_device_unregister(state->mtd);
map_destroy(state->mtd);
- kfree(state);
return 0;
}
diff --git a/drivers/mtd/maps/physmap_of_core.c b/drivers/mtd/maps/physmap_of_core.c
index 4129535b8e46..ece605d78c21 100644
--- a/drivers/mtd/maps/physmap_of_core.c
+++ b/drivers/mtd/maps/physmap_of_core.c
@@ -31,7 +31,6 @@
struct of_flash_list {
struct mtd_info *mtd;
struct map_info map;
- struct resource *res;
};
struct of_flash {
@@ -56,18 +55,10 @@ static int of_flash_remove(struct platform_device *dev)
mtd_concat_destroy(info->cmtd);
}
- for (i = 0; i < info->list_size; i++) {
+ for (i = 0; i < info->list_size; i++)
if (info->list[i].mtd)
map_destroy(info->list[i].mtd);
- if (info->list[i].map.virt)
- iounmap(info->list[i].map.virt);
-
- if (info->list[i].res) {
- release_resource(info->list[i].res);
- kfree(info->list[i].res);
- }
- }
return 0;
}
@@ -215,10 +206,11 @@ static int of_flash_probe(struct platform_device *dev)
err = -EBUSY;
res_size = resource_size(&res);
- info->list[i].res = request_mem_region(res.start, res_size,
- dev_name(&dev->dev));
- if (!info->list[i].res)
+ info->list[i].map.virt = devm_ioremap_resource(&dev->dev, &res);
+ if (IS_ERR(info->list[i].map.virt)) {
+ err = PTR_ERR(info->list[i].map.virt);
goto err_out;
+ }
err = -ENXIO;
width = of_get_property(dp, "bank-width", NULL);
@@ -246,15 +238,6 @@ static int of_flash_probe(struct platform_device *dev)
if (err)
goto err_out;
- err = -ENOMEM;
- info->list[i].map.virt = ioremap(info->list[i].map.phys,
- info->list[i].map.size);
- if (!info->list[i].map.virt) {
- dev_err(&dev->dev, "Failed to ioremap() flash"
- " region\n");
- goto err_out;
- }
-
simple_map_init(&info->list[i].map);
/*
diff --git a/drivers/mtd/maps/physmap_of_gemini.c b/drivers/mtd/maps/physmap_of_gemini.c
index 830b1b7e702b..9df62ca721d5 100644
--- a/drivers/mtd/maps/physmap_of_gemini.c
+++ b/drivers/mtd/maps/physmap_of_gemini.c
@@ -44,11 +44,6 @@
#define FLASH_PARALLEL_HIGH_PIN_CNT (1 << 20) /* else low pin cnt */
-static const struct of_device_id syscon_match[] = {
- { .compatible = "cortina,gemini-syscon" },
- { },
-};
-
int of_flash_probe_gemini(struct platform_device *pdev,
struct device_node *np,
struct map_info *map)
diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c
index 29c0bfd74e8a..b0d44f9214b0 100644
--- a/drivers/mtd/mtd_blkdevs.c
+++ b/drivers/mtd/mtd_blkdevs.c
@@ -27,6 +27,7 @@
#include <linux/mtd/blktrans.h>
#include <linux/mtd/mtd.h>
#include <linux/blkdev.h>
+#include <linux/blk-mq.h>
#include <linux/blkpg.h>
#include <linux/spinlock.h>
#include <linux/hdreg.h>
@@ -45,6 +46,8 @@ static void blktrans_dev_release(struct kref *kref)
dev->disk->private_data = NULL;
blk_cleanup_queue(dev->rq);
+ blk_mq_free_tag_set(dev->tag_set);
+ kfree(dev->tag_set);
put_disk(dev->disk);
list_del(&dev->list);
kfree(dev);
@@ -134,28 +137,39 @@ int mtd_blktrans_cease_background(struct mtd_blktrans_dev *dev)
}
EXPORT_SYMBOL_GPL(mtd_blktrans_cease_background);
-static void mtd_blktrans_work(struct work_struct *work)
+static struct request *mtd_next_request(struct mtd_blktrans_dev *dev)
+{
+ struct request *rq;
+
+ rq = list_first_entry_or_null(&dev->rq_list, struct request, queuelist);
+ if (rq) {
+ list_del_init(&rq->queuelist);
+ blk_mq_start_request(rq);
+ return rq;
+ }
+
+ return NULL;
+}
+
+static void mtd_blktrans_work(struct mtd_blktrans_dev *dev)
+ __releases(&dev->queue_lock)
+ __acquires(&dev->queue_lock)
{
- struct mtd_blktrans_dev *dev =
- container_of(work, struct mtd_blktrans_dev, work);
struct mtd_blktrans_ops *tr = dev->tr;
- struct request_queue *rq = dev->rq;
struct request *req = NULL;
int background_done = 0;
- spin_lock_irq(rq->queue_lock);
-
while (1) {
blk_status_t res;
dev->bg_stop = false;
- if (!req && !(req = blk_fetch_request(rq))) {
+ if (!req && !(req = mtd_next_request(dev))) {
if (tr->background && !background_done) {
- spin_unlock_irq(rq->queue_lock);
+ spin_unlock_irq(&dev->queue_lock);
mutex_lock(&dev->lock);
tr->background(dev);
mutex_unlock(&dev->lock);
- spin_lock_irq(rq->queue_lock);
+ spin_lock_irq(&dev->queue_lock);
/*
* Do background processing just once per idle
* period.
@@ -166,35 +180,39 @@ static void mtd_blktrans_work(struct work_struct *work)
break;
}
- spin_unlock_irq(rq->queue_lock);
+ spin_unlock_irq(&dev->queue_lock);
mutex_lock(&dev->lock);
res = do_blktrans_request(dev->tr, dev, req);
mutex_unlock(&dev->lock);
- spin_lock_irq(rq->queue_lock);
-
- if (!__blk_end_request_cur(req, res))
+ if (!blk_update_request(req, res, blk_rq_cur_bytes(req))) {
+ __blk_mq_end_request(req, res);
req = NULL;
+ }
background_done = 0;
+ spin_lock_irq(&dev->queue_lock);
}
-
- spin_unlock_irq(rq->queue_lock);
}
-static void mtd_blktrans_request(struct request_queue *rq)
+static blk_status_t mtd_queue_rq(struct blk_mq_hw_ctx *hctx,
+ const struct blk_mq_queue_data *bd)
{
struct mtd_blktrans_dev *dev;
- struct request *req = NULL;
- dev = rq->queuedata;
+ dev = hctx->queue->queuedata;
+ if (!dev) {
+ blk_mq_start_request(bd->rq);
+ return BLK_STS_IOERR;
+ }
+
+ spin_lock_irq(&dev->queue_lock);
+ list_add_tail(&bd->rq->queuelist, &dev->rq_list);
+ mtd_blktrans_work(dev);
+ spin_unlock_irq(&dev->queue_lock);
- if (!dev)
- while ((req = blk_fetch_request(rq)) != NULL)
- __blk_end_request_all(req, BLK_STS_IOERR);
- else
- queue_work(dev->wq, &dev->work);
+ return BLK_STS_OK;
}
static int blktrans_open(struct block_device *bdev, fmode_t mode)
@@ -329,6 +347,10 @@ static const struct block_device_operations mtd_block_ops = {
.getgeo = blktrans_getgeo,
};
+static const struct blk_mq_ops mtd_mq_ops = {
+ .queue_rq = mtd_queue_rq,
+};
+
int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
{
struct mtd_blktrans_ops *tr = new->tr;
@@ -416,11 +438,20 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
/* Create the request queue */
spin_lock_init(&new->queue_lock);
- new->rq = blk_init_queue(mtd_blktrans_request, &new->queue_lock);
+ INIT_LIST_HEAD(&new->rq_list);
- if (!new->rq)
+ new->tag_set = kzalloc(sizeof(*new->tag_set), GFP_KERNEL);
+ if (!new->tag_set)
goto error3;
+ new->rq = blk_mq_init_sq_queue(new->tag_set, &mtd_mq_ops, 2,
+ BLK_MQ_F_SHOULD_MERGE | BLK_MQ_F_BLOCKING);
+ if (IS_ERR(new->rq)) {
+ ret = PTR_ERR(new->rq);
+ new->rq = NULL;
+ goto error4;
+ }
+
if (tr->flush)
blk_queue_write_cache(new->rq, true, false);
@@ -437,17 +468,10 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
gd->queue = new->rq;
- /* Create processing workqueue */
- new->wq = alloc_workqueue("%s%d", 0, 0,
- tr->name, new->mtd->index);
- if (!new->wq)
- goto error4;
- INIT_WORK(&new->work, mtd_blktrans_work);
-
if (new->readonly)
set_disk_ro(gd, 1);
- device_add_disk(&new->mtd->dev, gd);
+ device_add_disk(&new->mtd->dev, gd, NULL);
if (new->disk_attributes) {
ret = sysfs_create_group(&disk_to_dev(gd)->kobj,
@@ -456,7 +480,7 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
}
return 0;
error4:
- blk_cleanup_queue(new->rq);
+ kfree(new->tag_set);
error3:
put_disk(new->disk);
error2:
@@ -481,15 +505,17 @@ int del_mtd_blktrans_dev(struct mtd_blktrans_dev *old)
/* Stop new requests to arrive */
del_gendisk(old->disk);
- /* Stop workqueue. This will perform any pending request. */
- destroy_workqueue(old->wq);
-
/* Kill current requests */
spin_lock_irqsave(&old->queue_lock, flags);
old->rq->queuedata = NULL;
- blk_start_queue(old->rq);
spin_unlock_irqrestore(&old->queue_lock, flags);
+ /* freeze+quiesce queue to ensure all requests are flushed */
+ blk_mq_freeze_queue(old->rq);
+ blk_mq_quiesce_queue(old->rq);
+ blk_mq_unquiesce_queue(old->rq);
+ blk_mq_unfreeze_queue(old->rq);
+
/* If the device is currently open, tell trans driver to close it,
then put mtd device, and don't touch it again */
mutex_lock(&old->lock);
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index 52e2cb35fc79..99c460facd5e 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -873,8 +873,11 @@ static int mtd_part_of_parse(struct mtd_info *master,
int ret, err = 0;
np = mtd_get_of_node(master);
- if (!mtd_is_partition(master))
+ if (mtd_is_partition(master))
+ of_node_get(np);
+ else
np = of_get_child_by_name(np, "partitions");
+
of_property_for_each_string(np, "compatible", prop, compat) {
parser = mtd_part_get_compatible_parser(compat);
if (!parser)
diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig
index 5fc9a1bde4ac..c7efc31384d5 100644
--- a/drivers/mtd/nand/raw/Kconfig
+++ b/drivers/mtd/nand/raw/Kconfig
@@ -227,26 +227,6 @@ config MTD_NAND_DISKONCHIP_BBTWRITE
load time (assuming you build diskonchip as a module) with the module
parameter "inftl_bbt_write=1".
-config MTD_NAND_DOCG4
- tristate "Support for DiskOnChip G4"
- depends on HAS_IOMEM
- select BCH
- select BITREVERSE
- help
- Support for diskonchip G4 nand flash, found in various smartphones and
- PDAs, among them the Palm Treo680, HTC Prophet and Wizard, Toshiba
- Portege G900, Asus P526, and O2 XDA Zinc.
-
- With this driver you will be able to use UBI and create a ubifs on the
- device, so you may wish to consider enabling UBI and UBIFS as well.
-
- These devices ship with the Mys/Sandisk SAFTL formatting, for which
- there is currently no mtd parser, so you may want to use command line
- partitioning to segregate write-protected blocks. On the Treo680, the
- first five erase blocks (256KiB each) are write-protected, followed
- by the block containing the saftl partition table. This is probably
- typical.
-
config MTD_NAND_SHARPSL
tristate "Support for NAND Flash on Sharp SL Series (C7xx + others)"
depends on ARCH_PXA || COMPILE_TEST
diff --git a/drivers/mtd/nand/raw/Makefile b/drivers/mtd/nand/raw/Makefile
index d5a5f9832b88..57159b349054 100644
--- a/drivers/mtd/nand/raw/Makefile
+++ b/drivers/mtd/nand/raw/Makefile
@@ -15,7 +15,6 @@ obj-$(CONFIG_MTD_NAND_S3C2410) += s3c2410.o
obj-$(CONFIG_MTD_NAND_TANGO) += tango_nand.o
obj-$(CONFIG_MTD_NAND_DAVINCI) += davinci_nand.o
obj-$(CONFIG_MTD_NAND_DISKONCHIP) += diskonchip.o
-obj-$(CONFIG_MTD_NAND_DOCG4) += docg4.o
obj-$(CONFIG_MTD_NAND_FSMC) += fsmc_nand.o
obj-$(CONFIG_MTD_NAND_SHARPSL) += sharpsl.o
obj-$(CONFIG_MTD_NAND_NANDSIM) += nandsim.o
@@ -58,8 +57,11 @@ obj-$(CONFIG_MTD_NAND_QCOM) += qcom_nandc.o
obj-$(CONFIG_MTD_NAND_MTK) += mtk_ecc.o mtk_nand.o
obj-$(CONFIG_MTD_NAND_TEGRA) += tegra_nand.o
-nand-objs := nand_base.o nand_bbt.o nand_timings.o nand_ids.o
+nand-objs := nand_base.o nand_legacy.o nand_bbt.o nand_timings.o nand_ids.o
+nand-objs += nand_onfi.o
+nand-objs += nand_jedec.o
nand-objs += nand_amd.o
+nand-objs += nand_esmt.o
nand-objs += nand_hynix.o
nand-objs += nand_macronix.o
nand-objs += nand_micron.o
diff --git a/drivers/mtd/nand/raw/ams-delta.c b/drivers/mtd/nand/raw/ams-delta.c
index 37a3cc21c7bc..5ba180a291eb 100644
--- a/drivers/mtd/nand/raw/ams-delta.c
+++ b/drivers/mtd/nand/raw/ams-delta.c
@@ -20,23 +20,33 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/rawnand.h>
#include <linux/mtd/partitions.h>
-#include <linux/gpio.h>
#include <linux/platform_data/gpio-omap.h>
#include <asm/io.h>
#include <asm/sizes.h>
-#include <mach/board-ams-delta.h>
-
#include <mach/hardware.h>
/*
* MTD structure for E3 (Delta)
*/
-static struct mtd_info *ams_delta_mtd = NULL;
+
+struct ams_delta_nand {
+ struct nand_chip nand_chip;
+ struct gpio_desc *gpiod_rdy;
+ struct gpio_desc *gpiod_nce;
+ struct gpio_desc *gpiod_nre;
+ struct gpio_desc *gpiod_nwp;
+ struct gpio_desc *gpiod_nwe;
+ struct gpio_desc *gpiod_ale;
+ struct gpio_desc *gpiod_cle;
+ void __iomem *io_base;
+ bool data_in;
+};
/*
* Define partitions for flash devices
@@ -63,48 +73,64 @@ static const struct mtd_partition partition_info[] = {
.size = 3 * SZ_256K },
};
-static void ams_delta_write_byte(struct mtd_info *mtd, u_char byte)
+static void ams_delta_io_write(struct ams_delta_nand *priv, u_char byte)
{
- struct nand_chip *this = mtd_to_nand(mtd);
- void __iomem *io_base = (void __iomem *)nand_get_controller_data(this);
-
- writew(0, io_base + OMAP_MPUIO_IO_CNTL);
- writew(byte, this->IO_ADDR_W);
- gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_NWE, 0);
+ writew(byte, priv->nand_chip.legacy.IO_ADDR_W);
+ gpiod_set_value(priv->gpiod_nwe, 0);
ndelay(40);
- gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_NWE, 1);
+ gpiod_set_value(priv->gpiod_nwe, 1);
}
-static u_char ams_delta_read_byte(struct mtd_info *mtd)
+static u_char ams_delta_io_read(struct ams_delta_nand *priv)
{
u_char res;
- struct nand_chip *this = mtd_to_nand(mtd);
- void __iomem *io_base = (void __iomem *)nand_get_controller_data(this);
- gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_NRE, 0);
+ gpiod_set_value(priv->gpiod_nre, 0);
ndelay(40);
- writew(~0, io_base + OMAP_MPUIO_IO_CNTL);
- res = readw(this->IO_ADDR_R);
- gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_NRE, 1);
+ res = readw(priv->nand_chip.legacy.IO_ADDR_R);
+ gpiod_set_value(priv->gpiod_nre, 1);
return res;
}
-static void ams_delta_write_buf(struct mtd_info *mtd, const u_char *buf,
+static void ams_delta_dir_input(struct ams_delta_nand *priv, bool in)
+{
+ writew(in ? ~0 : 0, priv->io_base + OMAP_MPUIO_IO_CNTL);
+ priv->data_in = in;
+}
+
+static void ams_delta_write_buf(struct nand_chip *this, const u_char *buf,
int len)
{
+ struct ams_delta_nand *priv = nand_get_controller_data(this);
int i;
- for (i=0; i<len; i++)
- ams_delta_write_byte(mtd, buf[i]);
+ if (priv->data_in)
+ ams_delta_dir_input(priv, false);
+
+ for (i = 0; i < len; i++)
+ ams_delta_io_write(priv, buf[i]);
}
-static void ams_delta_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+static void ams_delta_read_buf(struct nand_chip *this, u_char *buf, int len)
{
+ struct ams_delta_nand *priv = nand_get_controller_data(this);
int i;
- for (i=0; i<len; i++)
- buf[i] = ams_delta_read_byte(mtd);
+ if (!priv->data_in)
+ ams_delta_dir_input(priv, true);
+
+ for (i = 0; i < len; i++)
+ buf[i] = ams_delta_io_read(priv);
+}
+
+static u_char ams_delta_read_byte(struct nand_chip *this)
+{
+ u_char res;
+
+ ams_delta_read_buf(this, &res, 1);
+
+ return res;
}
/*
@@ -115,67 +141,40 @@ static void ams_delta_read_buf(struct mtd_info *mtd, u_char *buf, int len)
* NAND_CLE: bit 1 -> bit 7
* NAND_ALE: bit 2 -> bit 6
*/
-static void ams_delta_hwcontrol(struct mtd_info *mtd, int cmd,
+static void ams_delta_hwcontrol(struct nand_chip *this, int cmd,
unsigned int ctrl)
{
+ struct ams_delta_nand *priv = nand_get_controller_data(this);
if (ctrl & NAND_CTRL_CHANGE) {
- gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_NCE,
- (ctrl & NAND_NCE) == 0);
- gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_CLE,
- (ctrl & NAND_CLE) != 0);
- gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_ALE,
- (ctrl & NAND_ALE) != 0);
+ gpiod_set_value(priv->gpiod_nce, !(ctrl & NAND_NCE));
+ gpiod_set_value(priv->gpiod_cle, !!(ctrl & NAND_CLE));
+ gpiod_set_value(priv->gpiod_ale, !!(ctrl & NAND_ALE));
}
- if (cmd != NAND_CMD_NONE)
- ams_delta_write_byte(mtd, cmd);
+ if (cmd != NAND_CMD_NONE) {
+ u_char byte = cmd;
+
+ ams_delta_write_buf(this, &byte, 1);
+ }
}
-static int ams_delta_nand_ready(struct mtd_info *mtd)
+static int ams_delta_nand_ready(struct nand_chip *this)
{
- return gpio_get_value(AMS_DELTA_GPIO_PIN_NAND_RB);
+ struct ams_delta_nand *priv = nand_get_controller_data(this);
+
+ return gpiod_get_value(priv->gpiod_rdy);
}
-static const struct gpio _mandatory_gpio[] = {
- {
- .gpio = AMS_DELTA_GPIO_PIN_NAND_NCE,
- .flags = GPIOF_OUT_INIT_HIGH,
- .label = "nand_nce",
- },
- {
- .gpio = AMS_DELTA_GPIO_PIN_NAND_NRE,
- .flags = GPIOF_OUT_INIT_HIGH,
- .label = "nand_nre",
- },
- {
- .gpio = AMS_DELTA_GPIO_PIN_NAND_NWP,
- .flags = GPIOF_OUT_INIT_HIGH,
- .label = "nand_nwp",
- },
- {
- .gpio = AMS_DELTA_GPIO_PIN_NAND_NWE,
- .flags = GPIOF_OUT_INIT_HIGH,
- .label = "nand_nwe",
- },
- {
- .gpio = AMS_DELTA_GPIO_PIN_NAND_ALE,
- .flags = GPIOF_OUT_INIT_LOW,
- .label = "nand_ale",
- },
- {
- .gpio = AMS_DELTA_GPIO_PIN_NAND_CLE,
- .flags = GPIOF_OUT_INIT_LOW,
- .label = "nand_cle",
- },
-};
/*
* Main initialization routine
*/
static int ams_delta_init(struct platform_device *pdev)
{
+ struct ams_delta_nand *priv;
struct nand_chip *this;
+ struct mtd_info *mtd;
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
void __iomem *io_base;
int err = 0;
@@ -184,15 +183,16 @@ static int ams_delta_init(struct platform_device *pdev)
return -ENXIO;
/* Allocate memory for MTD device structure and private data */
- this = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);
- if (!this) {
+ priv = devm_kzalloc(&pdev->dev, sizeof(struct ams_delta_nand),
+ GFP_KERNEL);
+ if (!priv) {
pr_warn("Unable to allocate E3 NAND MTD device structure.\n");
- err = -ENOMEM;
- goto out;
+ return -ENOMEM;
}
+ this = &priv->nand_chip;
- ams_delta_mtd = nand_to_mtd(this);
- ams_delta_mtd->owner = THIS_MODULE;
+ mtd = nand_to_mtd(this);
+ mtd->dev.parent = &pdev->dev;
/*
* Don't try to request the memory region from here,
@@ -207,51 +207,93 @@ static int ams_delta_init(struct platform_device *pdev)
goto out_free;
}
- nand_set_controller_data(this, (void *)io_base);
+ priv->io_base = io_base;
+ nand_set_controller_data(this, priv);
/* Set address of NAND IO lines */
- this->IO_ADDR_R = io_base + OMAP_MPUIO_INPUT_LATCH;
- this->IO_ADDR_W = io_base + OMAP_MPUIO_OUTPUT;
- this->read_byte = ams_delta_read_byte;
- this->write_buf = ams_delta_write_buf;
- this->read_buf = ams_delta_read_buf;
- this->cmd_ctrl = ams_delta_hwcontrol;
- if (gpio_request(AMS_DELTA_GPIO_PIN_NAND_RB, "nand_rdy") == 0) {
- this->dev_ready = ams_delta_nand_ready;
- } else {
- this->dev_ready = NULL;
- pr_notice("Couldn't request gpio for Delta NAND ready.\n");
+ this->legacy.IO_ADDR_R = io_base + OMAP_MPUIO_INPUT_LATCH;
+ this->legacy.IO_ADDR_W = io_base + OMAP_MPUIO_OUTPUT;
+ this->legacy.read_byte = ams_delta_read_byte;
+ this->legacy.write_buf = ams_delta_write_buf;
+ this->legacy.read_buf = ams_delta_read_buf;
+ this->legacy.cmd_ctrl = ams_delta_hwcontrol;
+
+ priv->gpiod_rdy = devm_gpiod_get_optional(&pdev->dev, "rdy", GPIOD_IN);
+ if (IS_ERR(priv->gpiod_rdy)) {
+ err = PTR_ERR(priv->gpiod_rdy);
+ dev_warn(&pdev->dev, "RDY GPIO request failed (%d)\n", err);
+ goto out_mtd;
}
+
+ if (priv->gpiod_rdy)
+ this->legacy.dev_ready = ams_delta_nand_ready;
+
/* 25 us command delay time */
- this->chip_delay = 30;
+ this->legacy.chip_delay = 30;
this->ecc.mode = NAND_ECC_SOFT;
this->ecc.algo = NAND_ECC_HAMMING;
- platform_set_drvdata(pdev, io_base);
+ platform_set_drvdata(pdev, priv);
/* Set chip enabled, but */
- err = gpio_request_array(_mandatory_gpio, ARRAY_SIZE(_mandatory_gpio));
- if (err)
- goto out_gpio;
+ priv->gpiod_nwp = devm_gpiod_get(&pdev->dev, "nwp", GPIOD_OUT_HIGH);
+ if (IS_ERR(priv->gpiod_nwp)) {
+ err = PTR_ERR(priv->gpiod_nwp);
+ dev_err(&pdev->dev, "NWP GPIO request failed (%d)\n", err);
+ goto out_mtd;
+ }
+
+ priv->gpiod_nce = devm_gpiod_get(&pdev->dev, "nce", GPIOD_OUT_HIGH);
+ if (IS_ERR(priv->gpiod_nce)) {
+ err = PTR_ERR(priv->gpiod_nce);
+ dev_err(&pdev->dev, "NCE GPIO request failed (%d)\n", err);
+ goto out_mtd;
+ }
+
+ priv->gpiod_nre = devm_gpiod_get(&pdev->dev, "nre", GPIOD_OUT_HIGH);
+ if (IS_ERR(priv->gpiod_nre)) {
+ err = PTR_ERR(priv->gpiod_nre);
+ dev_err(&pdev->dev, "NRE GPIO request failed (%d)\n", err);
+ goto out_mtd;
+ }
+
+ priv->gpiod_nwe = devm_gpiod_get(&pdev->dev, "nwe", GPIOD_OUT_HIGH);
+ if (IS_ERR(priv->gpiod_nwe)) {
+ err = PTR_ERR(priv->gpiod_nwe);
+ dev_err(&pdev->dev, "NWE GPIO request failed (%d)\n", err);
+ goto out_mtd;
+ }
+
+ priv->gpiod_ale = devm_gpiod_get(&pdev->dev, "ale", GPIOD_OUT_LOW);
+ if (IS_ERR(priv->gpiod_ale)) {
+ err = PTR_ERR(priv->gpiod_ale);
+ dev_err(&pdev->dev, "ALE GPIO request failed (%d)\n", err);
+ goto out_mtd;
+ }
+
+ priv->gpiod_cle = devm_gpiod_get(&pdev->dev, "cle", GPIOD_OUT_LOW);
+ if (IS_ERR(priv->gpiod_cle)) {
+ err = PTR_ERR(priv->gpiod_cle);
+ dev_err(&pdev->dev, "CLE GPIO request failed (%d)\n", err);
+ goto out_mtd;
+ }
+
+ /* Initialize data port direction to a known state */
+ ams_delta_dir_input(priv, true);
/* Scan to find existence of the device */
- err = nand_scan(ams_delta_mtd, 1);
+ err = nand_scan(this, 1);
if (err)
goto out_mtd;
/* Register the partitions */
- mtd_device_register(ams_delta_mtd, partition_info,
- ARRAY_SIZE(partition_info));
+ mtd_device_register(mtd, partition_info, ARRAY_SIZE(partition_info));
goto out;
out_mtd:
- gpio_free_array(_mandatory_gpio, ARRAY_SIZE(_mandatory_gpio));
-out_gpio:
- gpio_free(AMS_DELTA_GPIO_PIN_NAND_RB);
iounmap(io_base);
out_free:
- kfree(this);
out:
return err;
}
@@ -261,18 +303,15 @@ out_free:
*/
static int ams_delta_cleanup(struct platform_device *pdev)
{
- void __iomem *io_base = platform_get_drvdata(pdev);
+ struct ams_delta_nand *priv = platform_get_drvdata(pdev);
+ struct mtd_info *mtd = nand_to_mtd(&priv->nand_chip);
+ void __iomem *io_base = priv->io_base;
/* Release resources, unregister device */
- nand_release(ams_delta_mtd);
+ nand_release(mtd_to_nand(mtd));
- gpio_free_array(_mandatory_gpio, ARRAY_SIZE(_mandatory_gpio));
- gpio_free(AMS_DELTA_GPIO_PIN_NAND_RB);
iounmap(io_base);
- /* Free the MTD device structure */
- kfree(mtd_to_nand(ams_delta_mtd));
-
return 0;
}
diff --git a/drivers/mtd/nand/raw/atmel/nand-controller.c b/drivers/mtd/nand/raw/atmel/nand-controller.c
index a068b214ebaa..fb33f6be7c4f 100644
--- a/drivers/mtd/nand/raw/atmel/nand-controller.c
+++ b/drivers/mtd/nand/raw/atmel/nand-controller.c
@@ -410,25 +410,15 @@ err:
return -EIO;
}
-static u8 atmel_nand_read_byte(struct mtd_info *mtd)
+static u8 atmel_nand_read_byte(struct nand_chip *chip)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct atmel_nand *nand = to_atmel_nand(chip);
return ioread8(nand->activecs->io.virt);
}
-static u16 atmel_nand_read_word(struct mtd_info *mtd)
+static void atmel_nand_write_byte(struct nand_chip *chip, u8 byte)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
- struct atmel_nand *nand = to_atmel_nand(chip);
-
- return ioread16(nand->activecs->io.virt);
-}
-
-static void atmel_nand_write_byte(struct mtd_info *mtd, u8 byte)
-{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct atmel_nand *nand = to_atmel_nand(chip);
if (chip->options & NAND_BUSWIDTH_16)
@@ -437,9 +427,8 @@ static void atmel_nand_write_byte(struct mtd_info *mtd, u8 byte)
iowrite8(byte, nand->activecs->io.virt);
}
-static void atmel_nand_read_buf(struct mtd_info *mtd, u8 *buf, int len)
+static void atmel_nand_read_buf(struct nand_chip *chip, u8 *buf, int len)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct atmel_nand *nand = to_atmel_nand(chip);
struct atmel_nand_controller *nc;
@@ -462,9 +451,8 @@ static void atmel_nand_read_buf(struct mtd_info *mtd, u8 *buf, int len)
ioread8_rep(nand->activecs->io.virt, buf, len);
}
-static void atmel_nand_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
+static void atmel_nand_write_buf(struct nand_chip *chip, const u8 *buf, int len)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct atmel_nand *nand = to_atmel_nand(chip);
struct atmel_nand_controller *nc;
@@ -487,34 +475,31 @@ static void atmel_nand_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
iowrite8_rep(nand->activecs->io.virt, buf, len);
}
-static int atmel_nand_dev_ready(struct mtd_info *mtd)
+static int atmel_nand_dev_ready(struct nand_chip *chip)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct atmel_nand *nand = to_atmel_nand(chip);
return gpiod_get_value(nand->activecs->rb.gpio);
}
-static void atmel_nand_select_chip(struct mtd_info *mtd, int cs)
+static void atmel_nand_select_chip(struct nand_chip *chip, int cs)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct atmel_nand *nand = to_atmel_nand(chip);
if (cs < 0 || cs >= nand->numcs) {
nand->activecs = NULL;
- chip->dev_ready = NULL;
+ chip->legacy.dev_ready = NULL;
return;
}
nand->activecs = &nand->cs[cs];
if (nand->activecs->rb.type == ATMEL_NAND_GPIO_RB)
- chip->dev_ready = atmel_nand_dev_ready;
+ chip->legacy.dev_ready = atmel_nand_dev_ready;
}
-static int atmel_hsmc_nand_dev_ready(struct mtd_info *mtd)
+static int atmel_hsmc_nand_dev_ready(struct nand_chip *chip)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct atmel_nand *nand = to_atmel_nand(chip);
struct atmel_hsmc_nand_controller *nc;
u32 status;
@@ -526,15 +511,15 @@ static int atmel_hsmc_nand_dev_ready(struct mtd_info *mtd)
return status & ATMEL_HSMC_NFC_SR_RBEDGE(nand->activecs->rb.id);
}
-static void atmel_hsmc_nand_select_chip(struct mtd_info *mtd, int cs)
+static void atmel_hsmc_nand_select_chip(struct nand_chip *chip, int cs)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct atmel_nand *nand = to_atmel_nand(chip);
struct atmel_hsmc_nand_controller *nc;
nc = to_hsmc_nand_controller(chip->controller);
- atmel_nand_select_chip(mtd, cs);
+ atmel_nand_select_chip(chip, cs);
if (!nand->activecs) {
regmap_write(nc->base.smc, ATMEL_HSMC_NFC_CTRL,
@@ -543,7 +528,7 @@ static void atmel_hsmc_nand_select_chip(struct mtd_info *mtd, int cs)
}
if (nand->activecs->rb.type == ATMEL_NAND_NATIVE_RB)
- chip->dev_ready = atmel_hsmc_nand_dev_ready;
+ chip->legacy.dev_ready = atmel_hsmc_nand_dev_ready;
regmap_update_bits(nc->base.smc, ATMEL_HSMC_NFC_CFG,
ATMEL_HSMC_NFC_CFG_PAGESIZE_MASK |
@@ -607,10 +592,9 @@ static int atmel_nfc_exec_op(struct atmel_hsmc_nand_controller *nc, bool poll)
return ret;
}
-static void atmel_hsmc_nand_cmd_ctrl(struct mtd_info *mtd, int dat,
+static void atmel_hsmc_nand_cmd_ctrl(struct nand_chip *chip, int dat,
unsigned int ctrl)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct atmel_nand *nand = to_atmel_nand(chip);
struct atmel_hsmc_nand_controller *nc;
@@ -634,10 +618,9 @@ static void atmel_hsmc_nand_cmd_ctrl(struct mtd_info *mtd, int dat,
}
}
-static void atmel_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
+static void atmel_nand_cmd_ctrl(struct nand_chip *chip, int cmd,
unsigned int ctrl)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct atmel_nand *nand = to_atmel_nand(chip);
struct atmel_nand_controller *nc;
@@ -851,7 +834,7 @@ static int atmel_nand_pmecc_write_pg(struct nand_chip *chip, const u8 *buf,
if (ret)
return ret;
- atmel_nand_write_buf(mtd, buf, mtd->writesize);
+ atmel_nand_write_buf(chip, buf, mtd->writesize);
ret = atmel_nand_pmecc_generate_eccbytes(chip, raw);
if (ret) {
@@ -861,20 +844,18 @@ static int atmel_nand_pmecc_write_pg(struct nand_chip *chip, const u8 *buf,
atmel_nand_pmecc_disable(chip, raw);
- atmel_nand_write_buf(mtd, chip->oob_poi, mtd->oobsize);
+ atmel_nand_write_buf(chip, chip->oob_poi, mtd->oobsize);
return nand_prog_page_end_op(chip);
}
-static int atmel_nand_pmecc_write_page(struct mtd_info *mtd,
- struct nand_chip *chip, const u8 *buf,
+static int atmel_nand_pmecc_write_page(struct nand_chip *chip, const u8 *buf,
int oob_required, int page)
{
return atmel_nand_pmecc_write_pg(chip, buf, oob_required, page, false);
}
-static int atmel_nand_pmecc_write_page_raw(struct mtd_info *mtd,
- struct nand_chip *chip,
+static int atmel_nand_pmecc_write_page_raw(struct nand_chip *chip,
const u8 *buf, int oob_required,
int page)
{
@@ -893,8 +874,8 @@ static int atmel_nand_pmecc_read_pg(struct nand_chip *chip, u8 *buf,
if (ret)
return ret;
- atmel_nand_read_buf(mtd, buf, mtd->writesize);
- atmel_nand_read_buf(mtd, chip->oob_poi, mtd->oobsize);
+ atmel_nand_read_buf(chip, buf, mtd->writesize);
+ atmel_nand_read_buf(chip, chip->oob_poi, mtd->oobsize);
ret = atmel_nand_pmecc_correct_data(chip, buf, raw);
@@ -903,15 +884,13 @@ static int atmel_nand_pmecc_read_pg(struct nand_chip *chip, u8 *buf,
return ret;
}
-static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
- struct nand_chip *chip, u8 *buf,
+static int atmel_nand_pmecc_read_page(struct nand_chip *chip, u8 *buf,
int oob_required, int page)
{
return atmel_nand_pmecc_read_pg(chip, buf, oob_required, page, false);
}
-static int atmel_nand_pmecc_read_page_raw(struct mtd_info *mtd,
- struct nand_chip *chip, u8 *buf,
+static int atmel_nand_pmecc_read_page_raw(struct nand_chip *chip, u8 *buf,
int oob_required, int page)
{
return atmel_nand_pmecc_read_pg(chip, buf, oob_required, page, true);
@@ -956,7 +935,7 @@ static int atmel_hsmc_nand_pmecc_write_pg(struct nand_chip *chip,
if (ret)
return ret;
- atmel_nand_write_buf(mtd, chip->oob_poi, mtd->oobsize);
+ atmel_nand_write_buf(chip, chip->oob_poi, mtd->oobsize);
nc->op.cmds[0] = NAND_CMD_PAGEPROG;
nc->op.ncmds = 1;
@@ -966,15 +945,14 @@ static int atmel_hsmc_nand_pmecc_write_pg(struct nand_chip *chip,
dev_err(nc->base.dev, "Failed to program NAND page (err = %d)\n",
ret);
- status = chip->waitfunc(mtd, chip);
+ status = chip->legacy.waitfunc(chip);
if (status & NAND_STATUS_FAIL)
return -EIO;
return ret;
}
-static int atmel_hsmc_nand_pmecc_write_page(struct mtd_info *mtd,
- struct nand_chip *chip,
+static int atmel_hsmc_nand_pmecc_write_page(struct nand_chip *chip,
const u8 *buf, int oob_required,
int page)
{
@@ -982,8 +960,7 @@ static int atmel_hsmc_nand_pmecc_write_page(struct mtd_info *mtd,
false);
}
-static int atmel_hsmc_nand_pmecc_write_page_raw(struct mtd_info *mtd,
- struct nand_chip *chip,
+static int atmel_hsmc_nand_pmecc_write_page_raw(struct nand_chip *chip,
const u8 *buf,
int oob_required, int page)
{
@@ -1045,16 +1022,14 @@ static int atmel_hsmc_nand_pmecc_read_pg(struct nand_chip *chip, u8 *buf,
return ret;
}
-static int atmel_hsmc_nand_pmecc_read_page(struct mtd_info *mtd,
- struct nand_chip *chip, u8 *buf,
+static int atmel_hsmc_nand_pmecc_read_page(struct nand_chip *chip, u8 *buf,
int oob_required, int page)
{
return atmel_hsmc_nand_pmecc_read_pg(chip, buf, oob_required, page,
false);
}
-static int atmel_hsmc_nand_pmecc_read_page_raw(struct mtd_info *mtd,
- struct nand_chip *chip,
+static int atmel_hsmc_nand_pmecc_read_page_raw(struct nand_chip *chip,
u8 *buf, int oob_required,
int page)
{
@@ -1473,10 +1448,9 @@ static int atmel_hsmc_nand_setup_data_interface(struct atmel_nand *nand,
return 0;
}
-static int atmel_nand_setup_data_interface(struct mtd_info *mtd, int csline,
+static int atmel_nand_setup_data_interface(struct nand_chip *chip, int csline,
const struct nand_data_interface *conf)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct atmel_nand *nand = to_atmel_nand(chip);
struct atmel_nand_controller *nc;
@@ -1498,19 +1472,18 @@ static void atmel_nand_init(struct atmel_nand_controller *nc,
mtd->dev.parent = nc->dev;
nand->base.controller = &nc->base;
- chip->cmd_ctrl = atmel_nand_cmd_ctrl;
- chip->read_byte = atmel_nand_read_byte;
- chip->read_word = atmel_nand_read_word;
- chip->write_byte = atmel_nand_write_byte;
- chip->read_buf = atmel_nand_read_buf;
- chip->write_buf = atmel_nand_write_buf;
+ chip->legacy.cmd_ctrl = atmel_nand_cmd_ctrl;
+ chip->legacy.read_byte = atmel_nand_read_byte;
+ chip->legacy.write_byte = atmel_nand_write_byte;
+ chip->legacy.read_buf = atmel_nand_read_buf;
+ chip->legacy.write_buf = atmel_nand_write_buf;
chip->select_chip = atmel_nand_select_chip;
if (nc->mck && nc->caps->ops->setup_data_interface)
chip->setup_data_interface = atmel_nand_setup_data_interface;
/* Some NANDs require a longer delay than the default one (20us). */
- chip->chip_delay = 40;
+ chip->legacy.chip_delay = 40;
/*
* Use a bounce buffer when the buffer passed by the MTD user is not
@@ -1551,7 +1524,7 @@ static void atmel_hsmc_nand_init(struct atmel_nand_controller *nc,
atmel_nand_init(nc, nand);
/* Overload some methods for the HSMC controller. */
- chip->cmd_ctrl = atmel_hsmc_nand_cmd_ctrl;
+ chip->legacy.cmd_ctrl = atmel_hsmc_nand_cmd_ctrl;
chip->select_chip = atmel_hsmc_nand_select_chip;
}
@@ -1586,9 +1559,7 @@ static struct atmel_nand *atmel_nand_create(struct atmel_nand_controller *nc,
return ERR_PTR(-EINVAL);
}
- nand = devm_kzalloc(nc->dev,
- sizeof(*nand) + (numcs * sizeof(*nand->cs)),
- GFP_KERNEL);
+ nand = devm_kzalloc(nc->dev, struct_size(nand, cs, numcs), GFP_KERNEL);
if (!nand) {
dev_err(nc->dev, "Failed to allocate NAND object\n");
return ERR_PTR(-ENOMEM);
@@ -1694,7 +1665,7 @@ atmel_nand_controller_add_nand(struct atmel_nand_controller *nc,
nc->caps->ops->nand_init(nc, nand);
- ret = nand_scan(mtd, nand->numcs);
+ ret = nand_scan(chip, nand->numcs);
if (ret) {
dev_err(nc->dev, "NAND scan failed: %d\n", ret);
return ret;
@@ -2063,6 +2034,10 @@ atmel_hsmc_nand_controller_legacy_init(struct atmel_hsmc_nand_controller *nc)
nand_np = dev->of_node;
nfc_np = of_find_compatible_node(dev->of_node, NULL,
"atmel,sama5d3-nfc");
+ if (!nfc_np) {
+ dev_err(dev, "Could not find device node for sama5d3-nfc\n");
+ return -ENODEV;
+ }
nc->clk = of_clk_get(nfc_np, 0);
if (IS_ERR(nc->clk)) {
diff --git a/drivers/mtd/nand/raw/au1550nd.c b/drivers/mtd/nand/raw/au1550nd.c
index 35f5c84cd331..9731c1c487f6 100644
--- a/drivers/mtd/nand/raw/au1550nd.c
+++ b/drivers/mtd/nand/raw/au1550nd.c
@@ -24,134 +24,113 @@ struct au1550nd_ctx {
int cs;
void __iomem *base;
- void (*write_byte)(struct mtd_info *, u_char);
+ void (*write_byte)(struct nand_chip *, u_char);
};
/**
* au_read_byte - read one byte from the chip
- * @mtd: MTD device structure
+ * @this: NAND chip object
*
* read function for 8bit buswidth
*/
-static u_char au_read_byte(struct mtd_info *mtd)
+static u_char au_read_byte(struct nand_chip *this)
{
- struct nand_chip *this = mtd_to_nand(mtd);
- u_char ret = readb(this->IO_ADDR_R);
+ u_char ret = readb(this->legacy.IO_ADDR_R);
wmb(); /* drain writebuffer */
return ret;
}
/**
* au_write_byte - write one byte to the chip
- * @mtd: MTD device structure
+ * @this: NAND chip object
* @byte: pointer to data byte to write
*
* write function for 8it buswidth
*/
-static void au_write_byte(struct mtd_info *mtd, u_char byte)
+static void au_write_byte(struct nand_chip *this, u_char byte)
{
- struct nand_chip *this = mtd_to_nand(mtd);
- writeb(byte, this->IO_ADDR_W);
+ writeb(byte, this->legacy.IO_ADDR_W);
wmb(); /* drain writebuffer */
}
/**
* au_read_byte16 - read one byte endianness aware from the chip
- * @mtd: MTD device structure
+ * @this: NAND chip object
*
* read function for 16bit buswidth with endianness conversion
*/
-static u_char au_read_byte16(struct mtd_info *mtd)
+static u_char au_read_byte16(struct nand_chip *this)
{
- struct nand_chip *this = mtd_to_nand(mtd);
- u_char ret = (u_char) cpu_to_le16(readw(this->IO_ADDR_R));
+ u_char ret = (u_char) cpu_to_le16(readw(this->legacy.IO_ADDR_R));
wmb(); /* drain writebuffer */
return ret;
}
/**
* au_write_byte16 - write one byte endianness aware to the chip
- * @mtd: MTD device structure
+ * @this: NAND chip object
* @byte: pointer to data byte to write
*
* write function for 16bit buswidth with endianness conversion
*/
-static void au_write_byte16(struct mtd_info *mtd, u_char byte)
+static void au_write_byte16(struct nand_chip *this, u_char byte)
{
- struct nand_chip *this = mtd_to_nand(mtd);
- writew(le16_to_cpu((u16) byte), this->IO_ADDR_W);
+ writew(le16_to_cpu((u16) byte), this->legacy.IO_ADDR_W);
wmb(); /* drain writebuffer */
}
/**
- * au_read_word - read one word from the chip
- * @mtd: MTD device structure
- *
- * read function for 16bit buswidth without endianness conversion
- */
-static u16 au_read_word(struct mtd_info *mtd)
-{
- struct nand_chip *this = mtd_to_nand(mtd);
- u16 ret = readw(this->IO_ADDR_R);
- wmb(); /* drain writebuffer */
- return ret;
-}
-
-/**
* au_write_buf - write buffer to chip
- * @mtd: MTD device structure
+ * @this: NAND chip object
* @buf: data buffer
* @len: number of bytes to write
*
* write function for 8bit buswidth
*/
-static void au_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
+static void au_write_buf(struct nand_chip *this, const u_char *buf, int len)
{
int i;
- struct nand_chip *this = mtd_to_nand(mtd);
for (i = 0; i < len; i++) {
- writeb(buf[i], this->IO_ADDR_W);
+ writeb(buf[i], this->legacy.IO_ADDR_W);
wmb(); /* drain writebuffer */
}
}
/**
* au_read_buf - read chip data into buffer
- * @mtd: MTD device structure
+ * @this: NAND chip object
* @buf: buffer to store date
* @len: number of bytes to read
*
* read function for 8bit buswidth
*/
-static void au_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+static void au_read_buf(struct nand_chip *this, u_char *buf, int len)
{
int i;
- struct nand_chip *this = mtd_to_nand(mtd);
for (i = 0; i < len; i++) {
- buf[i] = readb(this->IO_ADDR_R);
+ buf[i] = readb(this->legacy.IO_ADDR_R);
wmb(); /* drain writebuffer */
}
}
/**
* au_write_buf16 - write buffer to chip
- * @mtd: MTD device structure
+ * @this: NAND chip object
* @buf: data buffer
* @len: number of bytes to write
*
* write function for 16bit buswidth
*/
-static void au_write_buf16(struct mtd_info *mtd, const u_char *buf, int len)
+static void au_write_buf16(struct nand_chip *this, const u_char *buf, int len)
{
int i;
- struct nand_chip *this = mtd_to_nand(mtd);
u16 *p = (u16 *) buf;
len >>= 1;
for (i = 0; i < len; i++) {
- writew(p[i], this->IO_ADDR_W);
+ writew(p[i], this->legacy.IO_ADDR_W);
wmb(); /* drain writebuffer */
}
@@ -173,7 +152,7 @@ static void au_read_buf16(struct mtd_info *mtd, u_char *buf, int len)
len >>= 1;
for (i = 0; i < len; i++) {
- p[i] = readw(this->IO_ADDR_R);
+ p[i] = readw(this->legacy.IO_ADDR_R);
wmb(); /* drain writebuffer */
}
}
@@ -200,19 +179,19 @@ static void au1550_hwcontrol(struct mtd_info *mtd, int cmd)
switch (cmd) {
case NAND_CTL_SETCLE:
- this->IO_ADDR_W = ctx->base + MEM_STNAND_CMD;
+ this->legacy.IO_ADDR_W = ctx->base + MEM_STNAND_CMD;
break;
case NAND_CTL_CLRCLE:
- this->IO_ADDR_W = ctx->base + MEM_STNAND_DATA;
+ this->legacy.IO_ADDR_W = ctx->base + MEM_STNAND_DATA;
break;
case NAND_CTL_SETALE:
- this->IO_ADDR_W = ctx->base + MEM_STNAND_ADDR;
+ this->legacy.IO_ADDR_W = ctx->base + MEM_STNAND_ADDR;
break;
case NAND_CTL_CLRALE:
- this->IO_ADDR_W = ctx->base + MEM_STNAND_DATA;
+ this->legacy.IO_ADDR_W = ctx->base + MEM_STNAND_DATA;
/* FIXME: Nobody knows why this is necessary,
* but it works only that way */
udelay(1);
@@ -229,12 +208,12 @@ static void au1550_hwcontrol(struct mtd_info *mtd, int cmd)
break;
}
- this->IO_ADDR_R = this->IO_ADDR_W;
+ this->legacy.IO_ADDR_R = this->legacy.IO_ADDR_W;
wmb(); /* Drain the writebuffer */
}
-int au1550_device_ready(struct mtd_info *mtd)
+int au1550_device_ready(struct nand_chip *this)
{
return (alchemy_rdsmem(AU1000_MEM_STSTAT) & 0x1) ? 1 : 0;
}
@@ -248,23 +227,24 @@ int au1550_device_ready(struct mtd_info *mtd)
* chip needs it to be asserted during chip not ready time but the NAND
* controller keeps it released.
*
- * @mtd: MTD device structure
+ * @this: NAND chip object
* @chip: chipnumber to select, -1 for deselect
*/
-static void au1550_select_chip(struct mtd_info *mtd, int chip)
+static void au1550_select_chip(struct nand_chip *this, int chip)
{
}
/**
* au1550_command - Send command to NAND device
- * @mtd: MTD device structure
+ * @this: NAND chip object
* @command: the command to be sent
* @column: the column address for this command, -1 if none
* @page_addr: the page address for this command, -1 if none
*/
-static void au1550_command(struct mtd_info *mtd, unsigned command, int column, int page_addr)
+static void au1550_command(struct nand_chip *this, unsigned command,
+ int column, int page_addr)
{
- struct nand_chip *this = mtd_to_nand(mtd);
+ struct mtd_info *mtd = nand_to_mtd(this);
struct au1550nd_ctx *ctx = container_of(this, struct au1550nd_ctx,
chip);
int ce_override = 0, i;
@@ -289,9 +269,9 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i
column -= 256;
readcmd = NAND_CMD_READ1;
}
- ctx->write_byte(mtd, readcmd);
+ ctx->write_byte(this, readcmd);
}
- ctx->write_byte(mtd, command);
+ ctx->write_byte(this, command);
/* Set ALE and clear CLE to start address cycle */
au1550_hwcontrol(mtd, NAND_CTL_CLRCLE);
@@ -305,10 +285,10 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i
if (this->options & NAND_BUSWIDTH_16 &&
!nand_opcode_8bits(command))
column >>= 1;
- ctx->write_byte(mtd, column);
+ ctx->write_byte(this, column);
}
if (page_addr != -1) {
- ctx->write_byte(mtd, (u8)(page_addr & 0xff));
+ ctx->write_byte(this, (u8)(page_addr & 0xff));
if (command == NAND_CMD_READ0 ||
command == NAND_CMD_READ1 ||
@@ -326,10 +306,10 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i
au1550_hwcontrol(mtd, NAND_CTL_SETNCE);
}
- ctx->write_byte(mtd, (u8)(page_addr >> 8));
+ ctx->write_byte(this, (u8)(page_addr >> 8));
if (this->options & NAND_ROW_ADDR_3)
- ctx->write_byte(mtd,
+ ctx->write_byte(this,
((page_addr >> 16) & 0x0f));
}
/* Latch in address */
@@ -362,7 +342,8 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i
/* Apply a short delay always to ensure that we do wait tWB. */
ndelay(100);
/* Wait for a chip to become ready... */
- for (i = this->chip_delay; !this->dev_ready(mtd) && i > 0; --i)
+ for (i = this->legacy.chip_delay;
+ !this->legacy.dev_ready(this) && i > 0; --i)
udelay(1);
/* Release -CE and re-enable interrupts. */
@@ -373,7 +354,7 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i
/* Apply this short delay always to ensure that we do wait tWB. */
ndelay(100);
- while(!this->dev_ready(mtd));
+ while(!this->legacy.dev_ready(this));
}
static int find_nand_cs(unsigned long nand_base)
@@ -448,25 +429,24 @@ static int au1550nd_probe(struct platform_device *pdev)
}
ctx->cs = cs;
- this->dev_ready = au1550_device_ready;
+ this->legacy.dev_ready = au1550_device_ready;
this->select_chip = au1550_select_chip;
- this->cmdfunc = au1550_command;
+ this->legacy.cmdfunc = au1550_command;
/* 30 us command delay time */
- this->chip_delay = 30;
+ this->legacy.chip_delay = 30;
this->ecc.mode = NAND_ECC_SOFT;
this->ecc.algo = NAND_ECC_HAMMING;
if (pd->devwidth)
this->options |= NAND_BUSWIDTH_16;
- this->read_byte = (pd->devwidth) ? au_read_byte16 : au_read_byte;
+ this->legacy.read_byte = (pd->devwidth) ? au_read_byte16 : au_read_byte;
ctx->write_byte = (pd->devwidth) ? au_write_byte16 : au_write_byte;
- this->read_word = au_read_word;
- this->write_buf = (pd->devwidth) ? au_write_buf16 : au_write_buf;
- this->read_buf = (pd->devwidth) ? au_read_buf16 : au_read_buf;
+ this->legacy.write_buf = (pd->devwidth) ? au_write_buf16 : au_write_buf;
+ this->legacy.read_buf = (pd->devwidth) ? au_read_buf16 : au_read_buf;
- ret = nand_scan(mtd, 1);
+ ret = nand_scan(this, 1);
if (ret) {
dev_err(&pdev->dev, "NAND scan failed with %d\n", ret);
goto out3;
@@ -492,7 +472,7 @@ static int au1550nd_remove(struct platform_device *pdev)
struct au1550nd_ctx *ctx = platform_get_drvdata(pdev);
struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- nand_release(nand_to_mtd(&ctx->chip));
+ nand_release(&ctx->chip);
iounmap(ctx->base);
release_mem_region(r->start, 0x1000);
kfree(ctx);
diff --git a/drivers/mtd/nand/raw/bcm47xxnflash/main.c b/drivers/mtd/nand/raw/bcm47xxnflash/main.c
index fb31429b70a9..d79694160845 100644
--- a/drivers/mtd/nand/raw/bcm47xxnflash/main.c
+++ b/drivers/mtd/nand/raw/bcm47xxnflash/main.c
@@ -65,7 +65,7 @@ static int bcm47xxnflash_remove(struct platform_device *pdev)
{
struct bcm47xxnflash *nflash = platform_get_drvdata(pdev);
- nand_release(nand_to_mtd(&nflash->nand_chip));
+ nand_release(&nflash->nand_chip);
return 0;
}
diff --git a/drivers/mtd/nand/raw/bcm47xxnflash/ops_bcm4706.c b/drivers/mtd/nand/raw/bcm47xxnflash/ops_bcm4706.c
index 60874de430eb..9095a79ebc7d 100644
--- a/drivers/mtd/nand/raw/bcm47xxnflash/ops_bcm4706.c
+++ b/drivers/mtd/nand/raw/bcm47xxnflash/ops_bcm4706.c
@@ -170,10 +170,9 @@ static void bcm47xxnflash_ops_bcm4706_write(struct mtd_info *mtd,
* NAND chip ops
**************************************************/
-static void bcm47xxnflash_ops_bcm4706_cmd_ctrl(struct mtd_info *mtd, int cmd,
- unsigned int ctrl)
+static void bcm47xxnflash_ops_bcm4706_cmd_ctrl(struct nand_chip *nand_chip,
+ int cmd, unsigned int ctrl)
{
- struct nand_chip *nand_chip = mtd_to_nand(mtd);
struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
u32 code = 0;
@@ -191,15 +190,14 @@ static void bcm47xxnflash_ops_bcm4706_cmd_ctrl(struct mtd_info *mtd, int cmd,
}
/* Default nand_select_chip calls cmd_ctrl, which is not used in BCM4706 */
-static void bcm47xxnflash_ops_bcm4706_select_chip(struct mtd_info *mtd,
- int chip)
+static void bcm47xxnflash_ops_bcm4706_select_chip(struct nand_chip *chip,
+ int cs)
{
return;
}
-static int bcm47xxnflash_ops_bcm4706_dev_ready(struct mtd_info *mtd)
+static int bcm47xxnflash_ops_bcm4706_dev_ready(struct nand_chip *nand_chip)
{
- struct nand_chip *nand_chip = mtd_to_nand(mtd);
struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
return !!(bcma_cc_read32(b47n->cc, BCMA_CC_NFLASH_CTL) & NCTL_READY);
@@ -212,11 +210,11 @@ static int bcm47xxnflash_ops_bcm4706_dev_ready(struct mtd_info *mtd)
* registers of ChipCommon core. Hacking cmd_ctrl to understand and convert
* standard commands would be much more complicated.
*/
-static void bcm47xxnflash_ops_bcm4706_cmdfunc(struct mtd_info *mtd,
+static void bcm47xxnflash_ops_bcm4706_cmdfunc(struct nand_chip *nand_chip,
unsigned command, int column,
int page_addr)
{
- struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct mtd_info *mtd = nand_to_mtd(nand_chip);
struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
struct bcma_drv_cc *cc = b47n->cc;
u32 ctlcode;
@@ -229,10 +227,10 @@ static void bcm47xxnflash_ops_bcm4706_cmdfunc(struct mtd_info *mtd,
switch (command) {
case NAND_CMD_RESET:
- nand_chip->cmd_ctrl(mtd, command, NAND_CTRL_CLE);
+ nand_chip->legacy.cmd_ctrl(nand_chip, command, NAND_CTRL_CLE);
ndelay(100);
- nand_wait_ready(mtd);
+ nand_wait_ready(nand_chip);
break;
case NAND_CMD_READID:
ctlcode = NCTL_CSA | 0x01000000 | NCTL_CMD1W | NCTL_CMD0;
@@ -310,9 +308,9 @@ static void bcm47xxnflash_ops_bcm4706_cmdfunc(struct mtd_info *mtd,
b47n->curr_command = command;
}
-static u8 bcm47xxnflash_ops_bcm4706_read_byte(struct mtd_info *mtd)
+static u8 bcm47xxnflash_ops_bcm4706_read_byte(struct nand_chip *nand_chip)
{
- struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct mtd_info *mtd = nand_to_mtd(nand_chip);
struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
struct bcma_drv_cc *cc = b47n->cc;
u32 tmp = 0;
@@ -338,31 +336,31 @@ static u8 bcm47xxnflash_ops_bcm4706_read_byte(struct mtd_info *mtd)
return 0;
}
-static void bcm47xxnflash_ops_bcm4706_read_buf(struct mtd_info *mtd,
+static void bcm47xxnflash_ops_bcm4706_read_buf(struct nand_chip *nand_chip,
uint8_t *buf, int len)
{
- struct nand_chip *nand_chip = mtd_to_nand(mtd);
struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
switch (b47n->curr_command) {
case NAND_CMD_READ0:
case NAND_CMD_READOOB:
- bcm47xxnflash_ops_bcm4706_read(mtd, buf, len);
+ bcm47xxnflash_ops_bcm4706_read(nand_to_mtd(nand_chip), buf,
+ len);
return;
}
pr_err("Invalid command for buf read: 0x%X\n", b47n->curr_command);
}
-static void bcm47xxnflash_ops_bcm4706_write_buf(struct mtd_info *mtd,
+static void bcm47xxnflash_ops_bcm4706_write_buf(struct nand_chip *nand_chip,
const uint8_t *buf, int len)
{
- struct nand_chip *nand_chip = mtd_to_nand(mtd);
struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
switch (b47n->curr_command) {
case NAND_CMD_SEQIN:
- bcm47xxnflash_ops_bcm4706_write(mtd, buf, len);
+ bcm47xxnflash_ops_bcm4706_write(nand_to_mtd(nand_chip), buf,
+ len);
return;
}
@@ -386,16 +384,16 @@ int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n)
u32 val;
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.read_byte = bcm47xxnflash_ops_bcm4706_read_byte;
- b47n->nand_chip.read_buf = bcm47xxnflash_ops_bcm4706_read_buf;
- b47n->nand_chip.write_buf = bcm47xxnflash_ops_bcm4706_write_buf;
- b47n->nand_chip.set_features = nand_get_set_features_notsupp;
- b47n->nand_chip.get_features = nand_get_set_features_notsupp;
-
- nand_chip->chip_delay = 50;
+ nand_chip->legacy.cmd_ctrl = bcm47xxnflash_ops_bcm4706_cmd_ctrl;
+ nand_chip->legacy.dev_ready = bcm47xxnflash_ops_bcm4706_dev_ready;
+ b47n->nand_chip.legacy.cmdfunc = bcm47xxnflash_ops_bcm4706_cmdfunc;
+ b47n->nand_chip.legacy.read_byte = bcm47xxnflash_ops_bcm4706_read_byte;
+ b47n->nand_chip.legacy.read_buf = bcm47xxnflash_ops_bcm4706_read_buf;
+ b47n->nand_chip.legacy.write_buf = bcm47xxnflash_ops_bcm4706_write_buf;
+ b47n->nand_chip.legacy.set_features = nand_get_set_features_notsupp;
+ b47n->nand_chip.legacy.get_features = nand_get_set_features_notsupp;
+
+ nand_chip->legacy.chip_delay = 50;
b47n->nand_chip.bbt_options = NAND_BBT_USE_FLASH;
b47n->nand_chip.ecc.mode = NAND_ECC_NONE; /* TODO: implement ECC */
@@ -423,7 +421,7 @@ int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n)
(w4 << 24 | w3 << 18 | w2 << 12 | w1 << 6 | w0));
/* Scan NAND */
- err = nand_scan(nand_to_mtd(&b47n->nand_chip), 1);
+ err = nand_scan(&b47n->nand_chip, 1);
if (err) {
pr_err("Could not scan NAND flash: %d\n", err);
goto exit;
diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.c b/drivers/mtd/nand/raw/brcmnand/brcmnand.c
index 4b90d5b380c2..482c6f093f99 100644
--- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c
+++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c
@@ -1231,15 +1231,14 @@ static void brcmnand_send_cmd(struct brcmnand_host *host, int cmd)
* NAND MTD API: read/program/erase
***********************************************************************/
-static void brcmnand_cmd_ctrl(struct mtd_info *mtd, int dat,
- unsigned int ctrl)
+static void brcmnand_cmd_ctrl(struct nand_chip *chip, int dat,
+ unsigned int ctrl)
{
/* intentionally left blank */
}
-static int brcmnand_waitfunc(struct mtd_info *mtd, struct nand_chip *this)
+static int brcmnand_waitfunc(struct nand_chip *chip)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct brcmnand_host *host = nand_get_controller_data(chip);
struct brcmnand_controller *ctrl = host->ctrl;
unsigned long timeo = msecs_to_jiffies(100);
@@ -1274,7 +1273,6 @@ static int brcmnand_low_level_op(struct brcmnand_host *host,
enum brcmnand_llop_type type, u32 data,
bool last_op)
{
- struct mtd_info *mtd = nand_to_mtd(&host->chip);
struct nand_chip *chip = &host->chip;
struct brcmnand_controller *ctrl = host->ctrl;
u32 tmp;
@@ -1307,13 +1305,13 @@ static int brcmnand_low_level_op(struct brcmnand_host *host,
(void)brcmnand_read_reg(ctrl, BRCMNAND_LL_OP);
brcmnand_send_cmd(host, CMD_LOW_LEVEL_OP);
- return brcmnand_waitfunc(mtd, chip);
+ return brcmnand_waitfunc(chip);
}
-static void brcmnand_cmdfunc(struct mtd_info *mtd, unsigned command,
+static void brcmnand_cmdfunc(struct nand_chip *chip, unsigned command,
int column, int page_addr)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct brcmnand_host *host = nand_get_controller_data(chip);
struct brcmnand_controller *ctrl = host->ctrl;
u64 addr = (u64)page_addr << chip->page_shift;
@@ -1383,7 +1381,7 @@ static void brcmnand_cmdfunc(struct mtd_info *mtd, unsigned command,
(void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS);
brcmnand_send_cmd(host, native_cmd);
- brcmnand_waitfunc(mtd, chip);
+ brcmnand_waitfunc(chip);
if (native_cmd == CMD_PARAMETER_READ ||
native_cmd == CMD_PARAMETER_CHANGE_COL) {
@@ -1417,9 +1415,8 @@ static void brcmnand_cmdfunc(struct mtd_info *mtd, unsigned command,
brcmnand_wp(mtd, 1);
}
-static uint8_t brcmnand_read_byte(struct mtd_info *mtd)
+static uint8_t brcmnand_read_byte(struct nand_chip *chip)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct brcmnand_host *host = nand_get_controller_data(chip);
struct brcmnand_controller *ctrl = host->ctrl;
uint8_t ret = 0;
@@ -1474,19 +1471,18 @@ static uint8_t brcmnand_read_byte(struct mtd_info *mtd)
return ret;
}
-static void brcmnand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+static void brcmnand_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
{
int i;
for (i = 0; i < len; i++, buf++)
- *buf = brcmnand_read_byte(mtd);
+ *buf = brcmnand_read_byte(chip);
}
-static void brcmnand_write_buf(struct mtd_info *mtd, const uint8_t *buf,
- int len)
+static void brcmnand_write_buf(struct nand_chip *chip, const uint8_t *buf,
+ int len)
{
int i;
- struct nand_chip *chip = mtd_to_nand(mtd);
struct brcmnand_host *host = nand_get_controller_data(chip);
switch (host->last_cmd) {
@@ -1617,7 +1613,7 @@ static int brcmnand_read_by_pio(struct mtd_info *mtd, struct nand_chip *chip,
(void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS);
/* SPARE_AREA_READ does not use ECC, so just use PAGE_READ */
brcmnand_send_cmd(host, CMD_PAGE_READ);
- brcmnand_waitfunc(mtd, chip);
+ brcmnand_waitfunc(chip);
if (likely(buf)) {
brcmnand_soc_data_bus_prepare(ctrl->soc, false);
@@ -1689,7 +1685,7 @@ static int brcmstb_nand_verify_erased_page(struct mtd_info *mtd,
sas = mtd->oobsize / chip->ecc.steps;
/* read without ecc for verification */
- ret = chip->ecc.read_page_raw(mtd, chip, buf, true, page);
+ ret = chip->ecc.read_page_raw(chip, buf, true, page);
if (ret)
return ret;
@@ -1786,9 +1782,10 @@ try_dmaread:
return 0;
}
-static int brcmnand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
- uint8_t *buf, int oob_required, int page)
+static int brcmnand_read_page(struct nand_chip *chip, uint8_t *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct brcmnand_host *host = nand_get_controller_data(chip);
u8 *oob = oob_required ? (u8 *)chip->oob_poi : NULL;
@@ -1798,10 +1795,11 @@ static int brcmnand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
mtd->writesize >> FC_SHIFT, (u32 *)buf, oob);
}
-static int brcmnand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
- uint8_t *buf, int oob_required, int page)
+static int brcmnand_read_page_raw(struct nand_chip *chip, uint8_t *buf,
+ int oob_required, int page)
{
struct brcmnand_host *host = nand_get_controller_data(chip);
+ struct mtd_info *mtd = nand_to_mtd(chip);
u8 *oob = oob_required ? (u8 *)chip->oob_poi : NULL;
int ret;
@@ -1814,17 +1812,18 @@ static int brcmnand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
return ret;
}
-static int brcmnand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
- int page)
+static int brcmnand_read_oob(struct nand_chip *chip, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
return brcmnand_read(mtd, chip, (u64)page << chip->page_shift,
mtd->writesize >> FC_SHIFT,
NULL, (u8 *)chip->oob_poi);
}
-static int brcmnand_read_oob_raw(struct mtd_info *mtd, struct nand_chip *chip,
- int page)
+static int brcmnand_read_oob_raw(struct nand_chip *chip, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct brcmnand_host *host = nand_get_controller_data(chip);
brcmnand_set_ecc_enabled(host, 0);
@@ -1892,7 +1891,7 @@ static int brcmnand_write(struct mtd_info *mtd, struct nand_chip *chip,
/* we cannot use SPARE_AREA_PROGRAM when PARTIAL_PAGE_EN=0 */
brcmnand_send_cmd(host, CMD_PROGRAM_PAGE);
- status = brcmnand_waitfunc(mtd, chip);
+ status = brcmnand_waitfunc(chip);
if (status & NAND_STATUS_FAIL) {
dev_info(ctrl->dev, "program failed at %llx\n",
@@ -1906,9 +1905,10 @@ out:
return ret;
}
-static int brcmnand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
- const uint8_t *buf, int oob_required, int page)
+static int brcmnand_write_page(struct nand_chip *chip, const uint8_t *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct brcmnand_host *host = nand_get_controller_data(chip);
void *oob = oob_required ? chip->oob_poi : NULL;
@@ -1918,10 +1918,10 @@ static int brcmnand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
return nand_prog_page_end_op(chip);
}
-static int brcmnand_write_page_raw(struct mtd_info *mtd,
- struct nand_chip *chip, const uint8_t *buf,
+static int brcmnand_write_page_raw(struct nand_chip *chip, const uint8_t *buf,
int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct brcmnand_host *host = nand_get_controller_data(chip);
void *oob = oob_required ? chip->oob_poi : NULL;
@@ -1933,16 +1933,16 @@ static int brcmnand_write_page_raw(struct mtd_info *mtd,
return nand_prog_page_end_op(chip);
}
-static int brcmnand_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
- int page)
+static int brcmnand_write_oob(struct nand_chip *chip, int page)
{
- return brcmnand_write(mtd, chip, (u64)page << chip->page_shift,
- NULL, chip->oob_poi);
+ return brcmnand_write(nand_to_mtd(chip), chip,
+ (u64)page << chip->page_shift, NULL,
+ chip->oob_poi);
}
-static int brcmnand_write_oob_raw(struct mtd_info *mtd, struct nand_chip *chip,
- int page)
+static int brcmnand_write_oob_raw(struct nand_chip *chip, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct brcmnand_host *host = nand_get_controller_data(chip);
int ret;
@@ -2270,15 +2270,12 @@ static int brcmnand_init_cs(struct brcmnand_host *host, struct device_node *dn)
mtd->owner = THIS_MODULE;
mtd->dev.parent = &pdev->dev;
- chip->IO_ADDR_R = (void __iomem *)0xdeadbeef;
- chip->IO_ADDR_W = (void __iomem *)0xdeadbeef;
-
- chip->cmd_ctrl = brcmnand_cmd_ctrl;
- chip->cmdfunc = brcmnand_cmdfunc;
- chip->waitfunc = brcmnand_waitfunc;
- chip->read_byte = brcmnand_read_byte;
- chip->read_buf = brcmnand_read_buf;
- chip->write_buf = brcmnand_write_buf;
+ chip->legacy.cmd_ctrl = brcmnand_cmd_ctrl;
+ chip->legacy.cmdfunc = brcmnand_cmdfunc;
+ chip->legacy.waitfunc = brcmnand_waitfunc;
+ chip->legacy.read_byte = brcmnand_read_byte;
+ chip->legacy.read_buf = brcmnand_read_buf;
+ chip->legacy.write_buf = brcmnand_write_buf;
chip->ecc.mode = NAND_ECC_HW;
chip->ecc.read_page = brcmnand_read_page;
@@ -2301,7 +2298,7 @@ static int brcmnand_init_cs(struct brcmnand_host *host, struct device_node *dn)
nand_writereg(ctrl, cfg_offs,
nand_readreg(ctrl, cfg_offs) & ~CFG_BUS_WIDTH);
- ret = nand_scan(mtd, 1);
+ ret = nand_scan(chip, 1);
if (ret)
return ret;
@@ -2616,7 +2613,7 @@ int brcmnand_remove(struct platform_device *pdev)
struct brcmnand_host *host;
list_for_each_entry(host, &ctrl->host_list, node)
- nand_release(nand_to_mtd(&host->chip));
+ nand_release(&host->chip);
clk_disable_unprepare(ctrl->clk);
diff --git a/drivers/mtd/nand/raw/cafe_nand.c b/drivers/mtd/nand/raw/cafe_nand.c
index 1dbe43adcfe7..c1a745940d12 100644
--- a/drivers/mtd/nand/raw/cafe_nand.c
+++ b/drivers/mtd/nand/raw/cafe_nand.c
@@ -100,9 +100,8 @@ static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL };
#define cafe_readl(cafe, addr) readl((cafe)->mmio + CAFE_##addr)
#define cafe_writel(cafe, datum, addr) writel(datum, (cafe)->mmio + CAFE_##addr)
-static int cafe_device_ready(struct mtd_info *mtd)
+static int cafe_device_ready(struct nand_chip *chip)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct cafe_priv *cafe = nand_get_controller_data(chip);
int result = !!(cafe_readl(cafe, NAND_STATUS) & 0x40000000);
uint32_t irqs = cafe_readl(cafe, NAND_IRQ);
@@ -117,9 +116,8 @@ static int cafe_device_ready(struct mtd_info *mtd)
}
-static void cafe_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+static void cafe_write_buf(struct nand_chip *chip, const uint8_t *buf, int len)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct cafe_priv *cafe = nand_get_controller_data(chip);
if (cafe->usedma)
@@ -133,9 +131,8 @@ static void cafe_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
len, cafe->datalen);
}
-static void cafe_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+static void cafe_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct cafe_priv *cafe = nand_get_controller_data(chip);
if (cafe->usedma)
@@ -148,22 +145,21 @@ static void cafe_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
cafe->datalen += len;
}
-static uint8_t cafe_read_byte(struct mtd_info *mtd)
+static uint8_t cafe_read_byte(struct nand_chip *chip)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct cafe_priv *cafe = nand_get_controller_data(chip);
uint8_t d;
- cafe_read_buf(mtd, &d, 1);
+ cafe_read_buf(chip, &d, 1);
cafe_dev_dbg(&cafe->pdev->dev, "Read %02x\n", d);
return d;
}
-static void cafe_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
+static void cafe_nand_cmdfunc(struct nand_chip *chip, unsigned command,
int column, int page_addr)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct cafe_priv *cafe = nand_get_controller_data(chip);
int adrbytes = 0;
uint32_t ctl1;
@@ -313,13 +309,12 @@ static void cafe_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
cafe_writel(cafe, cafe->ctl2, NAND_CTRL2);
return;
}
- nand_wait_ready(mtd);
+ nand_wait_ready(chip);
cafe_writel(cafe, cafe->ctl2, NAND_CTRL2);
}
-static void cafe_select_chip(struct mtd_info *mtd, int chipnr)
+static void cafe_select_chip(struct nand_chip *chip, int chipnr)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct cafe_priv *cafe = nand_get_controller_data(chip);
cafe_dev_dbg(&cafe->pdev->dev, "select_chip %d\n", chipnr);
@@ -346,17 +341,19 @@ static irqreturn_t cafe_nand_interrupt(int irq, void *id)
return IRQ_HANDLED;
}
-static int cafe_nand_write_oob(struct mtd_info *mtd,
- struct nand_chip *chip, int page)
+static int cafe_nand_write_oob(struct nand_chip *chip, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
return nand_prog_page_op(chip, page, mtd->writesize, chip->oob_poi,
mtd->oobsize);
}
/* Don't use -- use nand_read_oob_std for now */
-static int cafe_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
- int page)
+static int cafe_nand_read_oob(struct nand_chip *chip, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
return nand_read_oob_op(chip, page, 0, chip->oob_poi, mtd->oobsize);
}
/**
@@ -369,9 +366,10 @@ static int cafe_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
* The hw generator calculates the error syndrome automatically. Therefore
* we need a special oob layout and handling.
*/
-static int cafe_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
- uint8_t *buf, int oob_required, int page)
+static int cafe_nand_read_page(struct nand_chip *chip, uint8_t *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct cafe_priv *cafe = nand_get_controller_data(chip);
unsigned int max_bitflips = 0;
@@ -380,7 +378,7 @@ static int cafe_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
cafe_readl(cafe, NAND_ECC_SYN01));
nand_read_page_op(chip, page, 0, buf, mtd->writesize);
- chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+ chip->legacy.read_buf(chip, chip->oob_poi, mtd->oobsize);
if (checkecc && cafe_readl(cafe, NAND_ECC_RESULT) & (1<<18)) {
unsigned short syn[8], pat[4];
@@ -531,15 +529,15 @@ static struct nand_bbt_descr cafe_bbt_mirror_descr_512 = {
};
-static int cafe_nand_write_page_lowlevel(struct mtd_info *mtd,
- struct nand_chip *chip,
- const uint8_t *buf, int oob_required,
- int page)
+static int cafe_nand_write_page_lowlevel(struct nand_chip *chip,
+ const uint8_t *buf, int oob_required,
+ int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct cafe_priv *cafe = nand_get_controller_data(chip);
nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize);
- chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+ chip->legacy.write_buf(chip, chip->oob_poi, mtd->oobsize);
/* Set up ECC autogeneration */
cafe->ctl2 |= (1<<30);
@@ -547,7 +545,7 @@ static int cafe_nand_write_page_lowlevel(struct mtd_info *mtd,
return nand_prog_page_end_op(chip);
}
-static int cafe_nand_block_bad(struct mtd_info *mtd, loff_t ofs)
+static int cafe_nand_block_bad(struct nand_chip *chip, loff_t ofs)
{
return 0;
}
@@ -705,23 +703,23 @@ static int cafe_nand_probe(struct pci_dev *pdev,
goto out_ior;
}
- cafe->nand.cmdfunc = cafe_nand_cmdfunc;
- cafe->nand.dev_ready = cafe_device_ready;
- cafe->nand.read_byte = cafe_read_byte;
- cafe->nand.read_buf = cafe_read_buf;
- cafe->nand.write_buf = cafe_write_buf;
+ cafe->nand.legacy.cmdfunc = cafe_nand_cmdfunc;
+ cafe->nand.legacy.dev_ready = cafe_device_ready;
+ cafe->nand.legacy.read_byte = cafe_read_byte;
+ cafe->nand.legacy.read_buf = cafe_read_buf;
+ cafe->nand.legacy.write_buf = cafe_write_buf;
cafe->nand.select_chip = cafe_select_chip;
- cafe->nand.set_features = nand_get_set_features_notsupp;
- cafe->nand.get_features = nand_get_set_features_notsupp;
+ cafe->nand.legacy.set_features = nand_get_set_features_notsupp;
+ cafe->nand.legacy.get_features = nand_get_set_features_notsupp;
- cafe->nand.chip_delay = 0;
+ cafe->nand.legacy.chip_delay = 0;
/* Enable the following for a flash based bad block table */
cafe->nand.bbt_options = NAND_BBT_USE_FLASH;
if (skipbbt) {
cafe->nand.options |= NAND_SKIP_BBTSCAN;
- cafe->nand.block_bad = cafe_nand_block_bad;
+ cafe->nand.legacy.block_bad = cafe_nand_block_bad;
}
if (numtimings && numtimings != 3) {
@@ -783,7 +781,7 @@ static int cafe_nand_probe(struct pci_dev *pdev,
/* Scan to find existence of the device */
cafe->nand.dummy_controller.ops = &cafe_nand_controller_ops;
- err = nand_scan(mtd, 2);
+ err = nand_scan(&cafe->nand, 2);
if (err)
goto out_irq;
@@ -819,7 +817,7 @@ static void cafe_nand_remove(struct pci_dev *pdev)
/* Disable NAND IRQ in global IRQ mask register */
cafe_writel(cafe, ~1 & cafe_readl(cafe, GLOBAL_IRQ_MASK), GLOBAL_IRQ_MASK);
free_irq(pdev->irq, mtd);
- nand_release(mtd);
+ nand_release(chip);
free_rs(cafe->rs);
pci_iounmap(pdev, cafe->mmio);
dma_free_coherent(&cafe->pdev->dev, 2112, cafe->dmabuf, cafe->dmaaddr);
diff --git a/drivers/mtd/nand/raw/cmx270_nand.c b/drivers/mtd/nand/raw/cmx270_nand.c
index b66e254b6802..143e4acacaae 100644
--- a/drivers/mtd/nand/raw/cmx270_nand.c
+++ b/drivers/mtd/nand/raw/cmx270_nand.c
@@ -49,29 +49,26 @@ static const struct mtd_partition partition_info[] = {
};
#define NUM_PARTITIONS (ARRAY_SIZE(partition_info))
-static u_char cmx270_read_byte(struct mtd_info *mtd)
+static u_char cmx270_read_byte(struct nand_chip *this)
{
- struct nand_chip *this = mtd_to_nand(mtd);
-
- return (readl(this->IO_ADDR_R) >> 16);
+ return (readl(this->legacy.IO_ADDR_R) >> 16);
}
-static void cmx270_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
+static void cmx270_write_buf(struct nand_chip *this, const u_char *buf,
+ int len)
{
int i;
- struct nand_chip *this = mtd_to_nand(mtd);
for (i=0; i<len; i++)
- writel((*buf++ << 16), this->IO_ADDR_W);
+ writel((*buf++ << 16), this->legacy.IO_ADDR_W);
}
-static void cmx270_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+static void cmx270_read_buf(struct nand_chip *this, u_char *buf, int len)
{
int i;
- struct nand_chip *this = mtd_to_nand(mtd);
for (i=0; i<len; i++)
- *buf++ = readl(this->IO_ADDR_R) >> 16;
+ *buf++ = readl(this->legacy.IO_ADDR_R) >> 16;
}
static inline void nand_cs_on(void)
@@ -89,11 +86,10 @@ static void nand_cs_off(void)
/*
* hardware specific access to control-lines
*/
-static void cmx270_hwcontrol(struct mtd_info *mtd, int dat,
+static void cmx270_hwcontrol(struct nand_chip *this, int dat,
unsigned int ctrl)
{
- struct nand_chip *this = mtd_to_nand(mtd);
- unsigned int nandaddr = (unsigned int)this->IO_ADDR_W;
+ unsigned int nandaddr = (unsigned int)this->legacy.IO_ADDR_W;
dsb();
@@ -113,9 +109,9 @@ static void cmx270_hwcontrol(struct mtd_info *mtd, int dat,
}
dsb();
- this->IO_ADDR_W = (void __iomem*)nandaddr;
+ this->legacy.IO_ADDR_W = (void __iomem*)nandaddr;
if (dat != NAND_CMD_NONE)
- writel((dat << 16), this->IO_ADDR_W);
+ writel((dat << 16), this->legacy.IO_ADDR_W);
dsb();
}
@@ -123,7 +119,7 @@ static void cmx270_hwcontrol(struct mtd_info *mtd, int dat,
/*
* read device ready pin
*/
-static int cmx270_device_ready(struct mtd_info *mtd)
+static int cmx270_device_ready(struct nand_chip *this)
{
dsb();
@@ -177,23 +173,23 @@ static int __init cmx270_init(void)
cmx270_nand_mtd->owner = THIS_MODULE;
/* insert callbacks */
- this->IO_ADDR_R = cmx270_nand_io;
- this->IO_ADDR_W = cmx270_nand_io;
- this->cmd_ctrl = cmx270_hwcontrol;
- this->dev_ready = cmx270_device_ready;
+ this->legacy.IO_ADDR_R = cmx270_nand_io;
+ this->legacy.IO_ADDR_W = cmx270_nand_io;
+ this->legacy.cmd_ctrl = cmx270_hwcontrol;
+ this->legacy.dev_ready = cmx270_device_ready;
/* 15 us command delay time */
- this->chip_delay = 20;
+ this->legacy.chip_delay = 20;
this->ecc.mode = NAND_ECC_SOFT;
this->ecc.algo = NAND_ECC_HAMMING;
/* read/write functions */
- this->read_byte = cmx270_read_byte;
- this->read_buf = cmx270_read_buf;
- this->write_buf = cmx270_write_buf;
+ this->legacy.read_byte = cmx270_read_byte;
+ this->legacy.read_buf = cmx270_read_buf;
+ this->legacy.write_buf = cmx270_write_buf;
/* Scan to find existence of the device */
- ret = nand_scan(cmx270_nand_mtd, 1);
+ ret = nand_scan(this, 1);
if (ret) {
pr_notice("No NAND device\n");
goto err_scan;
@@ -228,7 +224,7 @@ module_init(cmx270_init);
static void __exit cmx270_cleanup(void)
{
/* Release resources, unregister device */
- nand_release(cmx270_nand_mtd);
+ nand_release(mtd_to_nand(cmx270_nand_mtd));
gpio_free(GPIO_NAND_RB);
gpio_free(GPIO_NAND_CS);
diff --git a/drivers/mtd/nand/raw/cs553x_nand.c b/drivers/mtd/nand/raw/cs553x_nand.c
index beafad62e7d5..c6f578aff5d9 100644
--- a/drivers/mtd/nand/raw/cs553x_nand.c
+++ b/drivers/mtd/nand/raw/cs553x_nand.c
@@ -93,83 +93,74 @@
#define CS_NAND_ECC_CLRECC (1<<1)
#define CS_NAND_ECC_ENECC (1<<0)
-static void cs553x_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+static void cs553x_read_buf(struct nand_chip *this, u_char *buf, int len)
{
- struct nand_chip *this = mtd_to_nand(mtd);
-
while (unlikely(len > 0x800)) {
- memcpy_fromio(buf, this->IO_ADDR_R, 0x800);
+ memcpy_fromio(buf, this->legacy.IO_ADDR_R, 0x800);
buf += 0x800;
len -= 0x800;
}
- memcpy_fromio(buf, this->IO_ADDR_R, len);
+ memcpy_fromio(buf, this->legacy.IO_ADDR_R, len);
}
-static void cs553x_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
+static void cs553x_write_buf(struct nand_chip *this, const u_char *buf, int len)
{
- struct nand_chip *this = mtd_to_nand(mtd);
-
while (unlikely(len > 0x800)) {
- memcpy_toio(this->IO_ADDR_R, buf, 0x800);
+ memcpy_toio(this->legacy.IO_ADDR_R, buf, 0x800);
buf += 0x800;
len -= 0x800;
}
- memcpy_toio(this->IO_ADDR_R, buf, len);
+ memcpy_toio(this->legacy.IO_ADDR_R, buf, len);
}
-static unsigned char cs553x_read_byte(struct mtd_info *mtd)
+static unsigned char cs553x_read_byte(struct nand_chip *this)
{
- struct nand_chip *this = mtd_to_nand(mtd);
- return readb(this->IO_ADDR_R);
+ return readb(this->legacy.IO_ADDR_R);
}
-static void cs553x_write_byte(struct mtd_info *mtd, u_char byte)
+static void cs553x_write_byte(struct nand_chip *this, u_char byte)
{
- struct nand_chip *this = mtd_to_nand(mtd);
int i = 100000;
- while (i && readb(this->IO_ADDR_R + MM_NAND_STS) & CS_NAND_CTLR_BUSY) {
+ while (i && readb(this->legacy.IO_ADDR_R + MM_NAND_STS) & CS_NAND_CTLR_BUSY) {
udelay(1);
i--;
}
- writeb(byte, this->IO_ADDR_W + 0x801);
+ writeb(byte, this->legacy.IO_ADDR_W + 0x801);
}
-static void cs553x_hwcontrol(struct mtd_info *mtd, int cmd,
+static void cs553x_hwcontrol(struct nand_chip *this, int cmd,
unsigned int ctrl)
{
- struct nand_chip *this = mtd_to_nand(mtd);
- void __iomem *mmio_base = this->IO_ADDR_R;
+ void __iomem *mmio_base = this->legacy.IO_ADDR_R;
if (ctrl & NAND_CTRL_CHANGE) {
unsigned char ctl = (ctrl & ~NAND_CTRL_CHANGE ) ^ 0x01;
writeb(ctl, mmio_base + MM_NAND_CTL);
}
if (cmd != NAND_CMD_NONE)
- cs553x_write_byte(mtd, cmd);
+ cs553x_write_byte(this, cmd);
}
-static int cs553x_device_ready(struct mtd_info *mtd)
+static int cs553x_device_ready(struct nand_chip *this)
{
- struct nand_chip *this = mtd_to_nand(mtd);
- void __iomem *mmio_base = this->IO_ADDR_R;
+ void __iomem *mmio_base = this->legacy.IO_ADDR_R;
unsigned char foo = readb(mmio_base + MM_NAND_STS);
return (foo & CS_NAND_STS_FLASH_RDY) && !(foo & CS_NAND_CTLR_BUSY);
}
-static void cs_enable_hwecc(struct mtd_info *mtd, int mode)
+static void cs_enable_hwecc(struct nand_chip *this, int mode)
{
- struct nand_chip *this = mtd_to_nand(mtd);
- void __iomem *mmio_base = this->IO_ADDR_R;
+ void __iomem *mmio_base = this->legacy.IO_ADDR_R;
writeb(0x07, mmio_base + MM_NAND_ECC_CTL);
}
-static int cs_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code)
+static int cs_calculate_ecc(struct nand_chip *this, const u_char *dat,
+ u_char *ecc_code)
{
uint32_t ecc;
- struct nand_chip *this = mtd_to_nand(mtd);
- void __iomem *mmio_base = this->IO_ADDR_R;
+ void __iomem *mmio_base = this->legacy.IO_ADDR_R;
ecc = readl(mmio_base + MM_NAND_STS);
@@ -208,20 +199,20 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr)
new_mtd->owner = THIS_MODULE;
/* map physical address */
- this->IO_ADDR_R = this->IO_ADDR_W = ioremap(adr, 4096);
- if (!this->IO_ADDR_R) {
+ this->legacy.IO_ADDR_R = this->legacy.IO_ADDR_W = ioremap(adr, 4096);
+ if (!this->legacy.IO_ADDR_R) {
pr_warn("ioremap cs553x NAND @0x%08lx failed\n", adr);
err = -EIO;
goto out_mtd;
}
- this->cmd_ctrl = cs553x_hwcontrol;
- this->dev_ready = cs553x_device_ready;
- this->read_byte = cs553x_read_byte;
- this->read_buf = cs553x_read_buf;
- this->write_buf = cs553x_write_buf;
+ this->legacy.cmd_ctrl = cs553x_hwcontrol;
+ this->legacy.dev_ready = cs553x_device_ready;
+ this->legacy.read_byte = cs553x_read_byte;
+ this->legacy.read_buf = cs553x_read_buf;
+ this->legacy.write_buf = cs553x_write_buf;
- this->chip_delay = 0;
+ this->legacy.chip_delay = 0;
this->ecc.mode = NAND_ECC_HW;
this->ecc.size = 256;
@@ -241,7 +232,7 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr)
}
/* Scan to find existence of the device */
- err = nand_scan(new_mtd, 1);
+ err = nand_scan(this, 1);
if (err)
goto out_free;
@@ -251,7 +242,7 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr)
out_free:
kfree(new_mtd->name);
out_ior:
- iounmap(this->IO_ADDR_R);
+ iounmap(this->legacy.IO_ADDR_R);
out_mtd:
kfree(this);
out:
@@ -333,10 +324,10 @@ static void __exit cs553x_cleanup(void)
continue;
this = mtd_to_nand(mtd);
- mmio_base = this->IO_ADDR_R;
+ mmio_base = this->legacy.IO_ADDR_R;
/* Release resources, unregister device */
- nand_release(mtd);
+ nand_release(this);
kfree(mtd->name);
cs553x_mtd[i] = NULL;
diff --git a/drivers/mtd/nand/raw/davinci_nand.c b/drivers/mtd/nand/raw/davinci_nand.c
index 40145e206a6b..80f228d23cd2 100644
--- a/drivers/mtd/nand/raw/davinci_nand.c
+++ b/drivers/mtd/nand/raw/davinci_nand.c
@@ -97,12 +97,11 @@ static inline void davinci_nand_writel(struct davinci_nand_info *info,
* Access to hardware control lines: ALE, CLE, secondary chipselect.
*/
-static void nand_davinci_hwcontrol(struct mtd_info *mtd, int cmd,
+static void nand_davinci_hwcontrol(struct nand_chip *nand, int cmd,
unsigned int ctrl)
{
- struct davinci_nand_info *info = to_davinci_nand(mtd);
+ struct davinci_nand_info *info = to_davinci_nand(nand_to_mtd(nand));
void __iomem *addr = info->current_cs;
- struct nand_chip *nand = mtd_to_nand(mtd);
/* Did the control lines change? */
if (ctrl & NAND_CTRL_CHANGE) {
@@ -111,16 +110,16 @@ static void nand_davinci_hwcontrol(struct mtd_info *mtd, int cmd,
else if ((ctrl & NAND_CTRL_ALE) == NAND_CTRL_ALE)
addr += info->mask_ale;
- nand->IO_ADDR_W = addr;
+ nand->legacy.IO_ADDR_W = addr;
}
if (cmd != NAND_CMD_NONE)
- iowrite8(cmd, nand->IO_ADDR_W);
+ iowrite8(cmd, nand->legacy.IO_ADDR_W);
}
-static void nand_davinci_select_chip(struct mtd_info *mtd, int chip)
+static void nand_davinci_select_chip(struct nand_chip *nand, int chip)
{
- struct davinci_nand_info *info = to_davinci_nand(mtd);
+ struct davinci_nand_info *info = to_davinci_nand(nand_to_mtd(nand));
info->current_cs = info->vaddr;
@@ -128,8 +127,8 @@ static void nand_davinci_select_chip(struct mtd_info *mtd, int chip)
if (chip > 0)
info->current_cs += info->mask_chipsel;
- info->chip.IO_ADDR_W = info->current_cs;
- info->chip.IO_ADDR_R = info->chip.IO_ADDR_W;
+ info->chip.legacy.IO_ADDR_W = info->current_cs;
+ info->chip.legacy.IO_ADDR_R = info->chip.legacy.IO_ADDR_W;
}
/*----------------------------------------------------------------------*/
@@ -146,16 +145,16 @@ static inline uint32_t nand_davinci_readecc_1bit(struct mtd_info *mtd)
+ 4 * info->core_chipsel);
}
-static void nand_davinci_hwctl_1bit(struct mtd_info *mtd, int mode)
+static void nand_davinci_hwctl_1bit(struct nand_chip *chip, int mode)
{
struct davinci_nand_info *info;
uint32_t nandcfr;
unsigned long flags;
- info = to_davinci_nand(mtd);
+ info = to_davinci_nand(nand_to_mtd(chip));
/* Reset ECC hardware */
- nand_davinci_readecc_1bit(mtd);
+ nand_davinci_readecc_1bit(nand_to_mtd(chip));
spin_lock_irqsave(&davinci_nand_lock, flags);
@@ -170,10 +169,10 @@ static void nand_davinci_hwctl_1bit(struct mtd_info *mtd, int mode)
/*
* Read hardware ECC value and pack into three bytes
*/
-static int nand_davinci_calculate_1bit(struct mtd_info *mtd,
- const u_char *dat, u_char *ecc_code)
+static int nand_davinci_calculate_1bit(struct nand_chip *chip,
+ const u_char *dat, u_char *ecc_code)
{
- unsigned int ecc_val = nand_davinci_readecc_1bit(mtd);
+ unsigned int ecc_val = nand_davinci_readecc_1bit(nand_to_mtd(chip));
unsigned int ecc24 = (ecc_val & 0x0fff) | ((ecc_val & 0x0fff0000) >> 4);
/* invert so that erased block ecc is correct */
@@ -185,10 +184,9 @@ static int nand_davinci_calculate_1bit(struct mtd_info *mtd,
return 0;
}
-static int nand_davinci_correct_1bit(struct mtd_info *mtd, u_char *dat,
+static int nand_davinci_correct_1bit(struct nand_chip *chip, u_char *dat,
u_char *read_ecc, u_char *calc_ecc)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
uint32_t eccNand = read_ecc[0] | (read_ecc[1] << 8) |
(read_ecc[2] << 16);
uint32_t eccCalc = calc_ecc[0] | (calc_ecc[1] << 8) |
@@ -231,9 +229,9 @@ static int nand_davinci_correct_1bit(struct mtd_info *mtd, u_char *dat,
* OOB without recomputing ECC.
*/
-static void nand_davinci_hwctl_4bit(struct mtd_info *mtd, int mode)
+static void nand_davinci_hwctl_4bit(struct nand_chip *chip, int mode)
{
- struct davinci_nand_info *info = to_davinci_nand(mtd);
+ struct davinci_nand_info *info = to_davinci_nand(nand_to_mtd(chip));
unsigned long flags;
u32 val;
@@ -266,10 +264,10 @@ nand_davinci_readecc_4bit(struct davinci_nand_info *info, u32 code[4])
}
/* Terminate read ECC; or return ECC (as bytes) of data written to NAND. */
-static int nand_davinci_calculate_4bit(struct mtd_info *mtd,
- const u_char *dat, u_char *ecc_code)
+static int nand_davinci_calculate_4bit(struct nand_chip *chip,
+ const u_char *dat, u_char *ecc_code)
{
- struct davinci_nand_info *info = to_davinci_nand(mtd);
+ struct davinci_nand_info *info = to_davinci_nand(nand_to_mtd(chip));
u32 raw_ecc[4], *p;
unsigned i;
@@ -303,11 +301,11 @@ static int nand_davinci_calculate_4bit(struct mtd_info *mtd,
/* Correct up to 4 bits in data we just read, using state left in the
* hardware plus the ecc_code computed when it was first written.
*/
-static int nand_davinci_correct_4bit(struct mtd_info *mtd,
- u_char *data, u_char *ecc_code, u_char *null)
+static int nand_davinci_correct_4bit(struct nand_chip *chip, u_char *data,
+ u_char *ecc_code, u_char *null)
{
int i;
- struct davinci_nand_info *info = to_davinci_nand(mtd);
+ struct davinci_nand_info *info = to_davinci_nand(nand_to_mtd(chip));
unsigned short ecc10[8];
unsigned short *ecc16;
u32 syndrome[4];
@@ -436,38 +434,35 @@ correct:
* the two LSBs for NAND access ... so we can issue 32-bit reads/writes
* and have that transparently morphed into multiple NAND operations.
*/
-static void nand_davinci_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+static void nand_davinci_read_buf(struct nand_chip *chip, uint8_t *buf,
+ int len)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
-
if ((0x03 & ((uintptr_t)buf)) == 0 && (0x03 & len) == 0)
- ioread32_rep(chip->IO_ADDR_R, buf, len >> 2);
+ ioread32_rep(chip->legacy.IO_ADDR_R, buf, len >> 2);
else if ((0x01 & ((uintptr_t)buf)) == 0 && (0x01 & len) == 0)
- ioread16_rep(chip->IO_ADDR_R, buf, len >> 1);
+ ioread16_rep(chip->legacy.IO_ADDR_R, buf, len >> 1);
else
- ioread8_rep(chip->IO_ADDR_R, buf, len);
+ ioread8_rep(chip->legacy.IO_ADDR_R, buf, len);
}
-static void nand_davinci_write_buf(struct mtd_info *mtd,
- const uint8_t *buf, int len)
+static void nand_davinci_write_buf(struct nand_chip *chip, const uint8_t *buf,
+ int len)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
-
if ((0x03 & ((uintptr_t)buf)) == 0 && (0x03 & len) == 0)
- iowrite32_rep(chip->IO_ADDR_R, buf, len >> 2);
+ iowrite32_rep(chip->legacy.IO_ADDR_R, buf, len >> 2);
else if ((0x01 & ((uintptr_t)buf)) == 0 && (0x01 & len) == 0)
- iowrite16_rep(chip->IO_ADDR_R, buf, len >> 1);
+ iowrite16_rep(chip->legacy.IO_ADDR_R, buf, len >> 1);
else
- iowrite8_rep(chip->IO_ADDR_R, buf, len);
+ iowrite8_rep(chip->legacy.IO_ADDR_R, buf, len);
}
/*
* Check hardware register for wait status. Returns 1 if device is ready,
* 0 if it is still busy.
*/
-static int nand_davinci_dev_ready(struct mtd_info *mtd)
+static int nand_davinci_dev_ready(struct nand_chip *chip)
{
- struct davinci_nand_info *info = to_davinci_nand(mtd);
+ struct davinci_nand_info *info = to_davinci_nand(nand_to_mtd(chip));
return davinci_nand_readl(info, NANDFSR_OFFSET) & BIT(0);
}
@@ -764,9 +759,9 @@ static int nand_davinci_probe(struct platform_device *pdev)
mtd->dev.parent = &pdev->dev;
nand_set_flash_node(&info->chip, pdev->dev.of_node);
- info->chip.IO_ADDR_R = vaddr;
- info->chip.IO_ADDR_W = vaddr;
- info->chip.chip_delay = 0;
+ info->chip.legacy.IO_ADDR_R = vaddr;
+ info->chip.legacy.IO_ADDR_W = vaddr;
+ info->chip.legacy.chip_delay = 0;
info->chip.select_chip = nand_davinci_select_chip;
/* options such as NAND_BBT_USE_FLASH */
@@ -786,12 +781,12 @@ static int nand_davinci_probe(struct platform_device *pdev)
info->mask_cle = pdata->mask_cle ? : MASK_CLE;
/* Set address of hardware control function */
- info->chip.cmd_ctrl = nand_davinci_hwcontrol;
- info->chip.dev_ready = nand_davinci_dev_ready;
+ info->chip.legacy.cmd_ctrl = nand_davinci_hwcontrol;
+ info->chip.legacy.dev_ready = nand_davinci_dev_ready;
/* Speed up buffer I/O */
- info->chip.read_buf = nand_davinci_read_buf;
- info->chip.write_buf = nand_davinci_write_buf;
+ info->chip.legacy.read_buf = nand_davinci_read_buf;
+ info->chip.legacy.write_buf = nand_davinci_write_buf;
/* Use board-specific ECC config */
info->chip.ecc.mode = pdata->ecc_mode;
@@ -807,7 +802,7 @@ static int nand_davinci_probe(struct platform_device *pdev)
/* Scan to find existence of the device(s) */
info->chip.dummy_controller.ops = &davinci_nand_controller_ops;
- ret = nand_scan(mtd, pdata->mask_chipsel ? 2 : 1);
+ ret = nand_scan(&info->chip, pdata->mask_chipsel ? 2 : 1);
if (ret < 0) {
dev_dbg(&pdev->dev, "no NAND chip(s) found\n");
return ret;
@@ -841,7 +836,7 @@ static int nand_davinci_remove(struct platform_device *pdev)
ecc4_busy = false;
spin_unlock_irq(&davinci_nand_lock);
- nand_release(nand_to_mtd(&info->chip));
+ nand_release(&info->chip);
return 0;
}
diff --git a/drivers/mtd/nand/raw/denali.c b/drivers/mtd/nand/raw/denali.c
index ca18612c4201..830ea247277b 100644
--- a/drivers/mtd/nand/raw/denali.c
+++ b/drivers/mtd/nand/raw/denali.c
@@ -1,15 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* NAND Flash Controller Device Driver
* Copyright © 2009-2010, 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.
+ * Copyright (c) 2017 Socionext Inc.
+ * Reworked by Masahiro Yamada <yamada.masahiro@socionext.com>
*/
#include <linux/bitfield.h>
@@ -25,9 +20,8 @@
#include "denali.h"
-MODULE_LICENSE("GPL");
-
#define DENALI_NAND_NAME "denali-nand"
+#define DENALI_DEFAULT_OOB_SKIP_BYTES 8
/* for Indexed Addressing */
#define DENALI_INDEXED_CTRL 0x00
@@ -222,8 +216,9 @@ static uint32_t denali_check_irq(struct denali_nand_info *denali)
return irq_status;
}
-static void denali_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+static void denali_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct denali_nand_info *denali = mtd_to_denali(mtd);
u32 addr = DENALI_MAP11_DATA | DENALI_BANK(denali);
int i;
@@ -232,9 +227,10 @@ static void denali_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
buf[i] = denali->host_read(denali, addr);
}
-static void denali_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+static void denali_write_buf(struct nand_chip *chip, const uint8_t *buf,
+ int len)
{
- struct denali_nand_info *denali = mtd_to_denali(mtd);
+ struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip));
u32 addr = DENALI_MAP11_DATA | DENALI_BANK(denali);
int i;
@@ -242,9 +238,9 @@ static void denali_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
denali->host_write(denali, addr, buf[i]);
}
-static void denali_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
+static void denali_read_buf16(struct nand_chip *chip, uint8_t *buf, int len)
{
- struct denali_nand_info *denali = mtd_to_denali(mtd);
+ struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip));
u32 addr = DENALI_MAP11_DATA | DENALI_BANK(denali);
uint16_t *buf16 = (uint16_t *)buf;
int i;
@@ -253,10 +249,10 @@ static void denali_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
buf16[i] = denali->host_read(denali, addr);
}
-static void denali_write_buf16(struct mtd_info *mtd, const uint8_t *buf,
+static void denali_write_buf16(struct nand_chip *chip, const uint8_t *buf,
int len)
{
- struct denali_nand_info *denali = mtd_to_denali(mtd);
+ struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip));
u32 addr = DENALI_MAP11_DATA | DENALI_BANK(denali);
const uint16_t *buf16 = (const uint16_t *)buf;
int i;
@@ -265,32 +261,23 @@ static void denali_write_buf16(struct mtd_info *mtd, const uint8_t *buf,
denali->host_write(denali, addr, buf16[i]);
}
-static uint8_t denali_read_byte(struct mtd_info *mtd)
+static uint8_t denali_read_byte(struct nand_chip *chip)
{
uint8_t byte;
- denali_read_buf(mtd, &byte, 1);
+ denali_read_buf(chip, &byte, 1);
return byte;
}
-static void denali_write_byte(struct mtd_info *mtd, uint8_t byte)
-{
- denali_write_buf(mtd, &byte, 1);
-}
-
-static uint16_t denali_read_word(struct mtd_info *mtd)
+static void denali_write_byte(struct nand_chip *chip, uint8_t byte)
{
- uint16_t word;
-
- denali_read_buf16(mtd, (uint8_t *)&word, 2);
-
- return word;
+ denali_write_buf(chip, &byte, 1);
}
-static void denali_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
+static void denali_cmd_ctrl(struct nand_chip *chip, int dat, unsigned int ctrl)
{
- struct denali_nand_info *denali = mtd_to_denali(mtd);
+ struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip));
uint32_t type;
if (ctrl & NAND_CLE)
@@ -301,7 +288,8 @@ static void denali_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
return;
/*
- * Some commands are followed by chip->dev_ready or chip->waitfunc.
+ * Some commands are followed by chip->legacy.dev_ready or
+ * chip->legacy.waitfunc.
* irq_status must be cleared here to catch the R/B# interrupt later.
*/
if (ctrl & NAND_CTRL_CHANGE)
@@ -310,9 +298,9 @@ static void denali_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
denali->host_write(denali, DENALI_BANK(denali) | type, dat);
}
-static int denali_dev_ready(struct mtd_info *mtd)
+static int denali_dev_ready(struct nand_chip *chip)
{
- struct denali_nand_info *denali = mtd_to_denali(mtd);
+ struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip));
return !!(denali_check_irq(denali) & INTR__INT_ACT);
}
@@ -596,6 +584,12 @@ static int denali_dma_xfer(struct denali_nand_info *denali, void *buf,
}
iowrite32(DMA_ENABLE__FLAG, denali->reg + DMA_ENABLE);
+ /*
+ * The ->setup_dma() hook kicks DMA by using the data/command
+ * interface, which belongs to a different AXI port from the
+ * register interface. Read back the register to avoid a race.
+ */
+ ioread32(denali->reg + DMA_ENABLE);
denali_reset_irq(denali);
denali->setup_dma(denali, dma_addr, page, write);
@@ -692,9 +686,10 @@ static void denali_oob_xfer(struct mtd_info *mtd, struct nand_chip *chip,
false);
}
-static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
- uint8_t *buf, int oob_required, int page)
+static int denali_read_page_raw(struct nand_chip *chip, uint8_t *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct denali_nand_info *denali = mtd_to_denali(mtd);
int writesize = mtd->writesize;
int oobsize = mtd->oobsize;
@@ -767,17 +762,18 @@ static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
return 0;
}
-static int denali_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
- int page)
+static int denali_read_oob(struct nand_chip *chip, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
denali_oob_xfer(mtd, chip, page, 0);
return 0;
}
-static int denali_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
- int page)
+static int denali_write_oob(struct nand_chip *chip, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct denali_nand_info *denali = mtd_to_denali(mtd);
denali_reset_irq(denali);
@@ -787,9 +783,10 @@ static int denali_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
return nand_prog_page_end_op(chip);
}
-static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
- uint8_t *buf, int oob_required, int page)
+static int denali_read_page(struct nand_chip *chip, uint8_t *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct denali_nand_info *denali = mtd_to_denali(mtd);
unsigned long uncor_ecc_flags = 0;
int stat = 0;
@@ -808,7 +805,7 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
return stat;
if (uncor_ecc_flags) {
- ret = denali_read_oob(mtd, chip, page);
+ ret = denali_read_oob(chip, page);
if (ret)
return ret;
@@ -819,9 +816,10 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
return stat;
}
-static int denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
- const uint8_t *buf, int oob_required, int page)
+static int denali_write_page_raw(struct nand_chip *chip, const uint8_t *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct denali_nand_info *denali = mtd_to_denali(mtd);
int writesize = mtd->writesize;
int oobsize = mtd->oobsize;
@@ -897,25 +895,26 @@ static int denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
return denali_data_xfer(denali, tmp_buf, size, page, 1, 1);
}
-static int denali_write_page(struct mtd_info *mtd, struct nand_chip *chip,
- const uint8_t *buf, int oob_required, int page)
+static int denali_write_page(struct nand_chip *chip, const uint8_t *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct denali_nand_info *denali = mtd_to_denali(mtd);
return denali_data_xfer(denali, (void *)buf, mtd->writesize,
page, 0, 1);
}
-static void denali_select_chip(struct mtd_info *mtd, int chip)
+static void denali_select_chip(struct nand_chip *chip, int cs)
{
- struct denali_nand_info *denali = mtd_to_denali(mtd);
+ struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip));
- denali->active_bank = chip;
+ denali->active_bank = cs;
}
-static int denali_waitfunc(struct mtd_info *mtd, struct nand_chip *chip)
+static int denali_waitfunc(struct nand_chip *chip)
{
- struct denali_nand_info *denali = mtd_to_denali(mtd);
+ struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip));
uint32_t irq_status;
/* R/B# pin transitioned from low to high? */
@@ -924,9 +923,9 @@ static int denali_waitfunc(struct mtd_info *mtd, struct nand_chip *chip)
return irq_status & INTR__INT_ACT ? 0 : NAND_STATUS_FAIL;
}
-static int denali_erase(struct mtd_info *mtd, int page)
+static int denali_erase(struct nand_chip *chip, int page)
{
- struct denali_nand_info *denali = mtd_to_denali(mtd);
+ struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip));
uint32_t irq_status;
denali_reset_irq(denali);
@@ -941,10 +940,10 @@ static int denali_erase(struct mtd_info *mtd, int page)
return irq_status & INTR__ERASE_COMP ? 0 : -EIO;
}
-static int denali_setup_data_interface(struct mtd_info *mtd, int chipnr,
+static int denali_setup_data_interface(struct nand_chip *chip, int chipnr,
const struct nand_data_interface *conf)
{
- struct denali_nand_info *denali = mtd_to_denali(mtd);
+ struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip));
const struct nand_sdr_timings *timings;
unsigned long t_x, mult_x;
int acc_clks, re_2_we, re_2_re, we_2_re, addr_2_data;
@@ -1099,12 +1098,17 @@ static void denali_hw_init(struct denali_nand_info *denali)
denali->revision = swab16(ioread32(denali->reg + REVISION));
/*
- * tell driver how many bit controller will skip before
- * writing ECC code in OOB, this register may be already
- * set by firmware. So we read this value out.
- * if this value is 0, just let it be.
+ * Set how many bytes should be skipped before writing data in OOB.
+ * If a non-zero value has already been set (by firmware or something),
+ * just use it. Otherwise, set the driver default.
*/
denali->oob_skip_bytes = ioread32(denali->reg + SPARE_AREA_SKIP_BYTES);
+ if (!denali->oob_skip_bytes) {
+ denali->oob_skip_bytes = DENALI_DEFAULT_OOB_SKIP_BYTES;
+ iowrite32(denali->oob_skip_bytes,
+ denali->reg + SPARE_AREA_SKIP_BYTES);
+ }
+
denali_detect_max_banks(denali);
iowrite32(0x0F, denali->reg + RB_PIN_ENABLED);
iowrite32(CHIP_EN_DONT_CARE__FLAG, denali->reg + CHIP_ENABLE_DONT_CARE);
@@ -1271,11 +1275,11 @@ static int denali_attach_chip(struct nand_chip *chip)
mtd_set_ooblayout(mtd, &denali_ooblayout_ops);
if (chip->options & NAND_BUSWIDTH_16) {
- chip->read_buf = denali_read_buf16;
- chip->write_buf = denali_write_buf16;
+ chip->legacy.read_buf = denali_read_buf16;
+ chip->legacy.write_buf = denali_write_buf16;
} else {
- chip->read_buf = denali_read_buf;
- chip->write_buf = denali_write_buf;
+ chip->legacy.read_buf = denali_read_buf;
+ chip->legacy.write_buf = denali_write_buf;
}
chip->ecc.read_page = denali_read_page;
chip->ecc.read_page_raw = denali_read_page_raw;
@@ -1283,7 +1287,7 @@ static int denali_attach_chip(struct nand_chip *chip)
chip->ecc.write_page_raw = denali_write_page_raw;
chip->ecc.read_oob = denali_read_oob;
chip->ecc.write_oob = denali_write_oob;
- chip->erase = denali_erase;
+ chip->legacy.erase = denali_erase;
ret = denali_multidev_fixup(denali);
if (ret)
@@ -1338,6 +1342,11 @@ int denali_init(struct denali_nand_info *denali)
denali_enable_irq(denali);
denali_reset_banks(denali);
+ if (!denali->max_banks) {
+ /* Error out earlier if no chip is found for some reasons. */
+ ret = -ENODEV;
+ goto disable_irq;
+ }
denali->active_bank = DENALI_INVALID_BANK;
@@ -1347,12 +1356,11 @@ int denali_init(struct denali_nand_info *denali)
mtd->name = "denali-nand";
chip->select_chip = denali_select_chip;
- chip->read_byte = denali_read_byte;
- chip->write_byte = denali_write_byte;
- chip->read_word = denali_read_word;
- chip->cmd_ctrl = denali_cmd_ctrl;
- chip->dev_ready = denali_dev_ready;
- chip->waitfunc = denali_waitfunc;
+ chip->legacy.read_byte = denali_read_byte;
+ chip->legacy.write_byte = denali_write_byte;
+ chip->legacy.cmd_ctrl = denali_cmd_ctrl;
+ chip->legacy.dev_ready = denali_dev_ready;
+ chip->legacy.waitfunc = denali_waitfunc;
if (features & FEATURES__INDEX_ADDR) {
denali->host_read = denali_indexed_read;
@@ -1367,7 +1375,7 @@ int denali_init(struct denali_nand_info *denali)
chip->setup_data_interface = denali_setup_data_interface;
chip->dummy_controller.ops = &denali_controller_ops;
- ret = nand_scan(mtd, denali->max_banks);
+ ret = nand_scan(chip, denali->max_banks);
if (ret)
goto disable_irq;
@@ -1390,9 +1398,11 @@ EXPORT_SYMBOL(denali_init);
void denali_remove(struct denali_nand_info *denali)
{
- struct mtd_info *mtd = nand_to_mtd(&denali->nand);
-
- nand_release(mtd);
+ nand_release(&denali->nand);
denali_disable_irq(denali);
}
EXPORT_SYMBOL(denali_remove);
+
+MODULE_DESCRIPTION("Driver core for Denali NAND controller");
+MODULE_AUTHOR("Intel Corporation and its suppliers");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mtd/nand/raw/denali.h b/drivers/mtd/nand/raw/denali.h
index 1f8feaf924eb..57a5498f58bb 100644
--- a/drivers/mtd/nand/raw/denali.h
+++ b/drivers/mtd/nand/raw/denali.h
@@ -1,15 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* NAND Flash Controller Device Driver
* Copyright (c) 2009 - 2010, 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.
*/
#ifndef __DENALI_H__
diff --git a/drivers/mtd/nand/raw/denali_dt.c b/drivers/mtd/nand/raw/denali_dt.c
index 0faaad032e5f..7c6a8a426606 100644
--- a/drivers/mtd/nand/raw/denali_dt.c
+++ b/drivers/mtd/nand/raw/denali_dt.c
@@ -1,16 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* NAND Flash Controller Device Driver for DT
*
* Copyright © 2011, Picochip.
- *
- * 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.
*/
#include <linux/clk.h>
@@ -202,6 +194,6 @@ static struct platform_driver denali_dt_driver = {
};
module_platform_driver(denali_dt_driver);
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Jamie Iles");
MODULE_DESCRIPTION("DT driver for Denali NAND controller");
diff --git a/drivers/mtd/nand/raw/denali_pci.c b/drivers/mtd/nand/raw/denali_pci.c
index 7c8efc4c7bdf..48e9ac54ad53 100644
--- a/drivers/mtd/nand/raw/denali_pci.c
+++ b/drivers/mtd/nand/raw/denali_pci.c
@@ -1,15 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* NAND Flash Controller Device Driver
* Copyright © 2009-2010, 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.
*/
#include <linux/errno.h>
diff --git a/drivers/mtd/nand/raw/diskonchip.c b/drivers/mtd/nand/raw/diskonchip.c
index 3c46188dd6d2..3a4c373affab 100644
--- a/drivers/mtd/nand/raw/diskonchip.c
+++ b/drivers/mtd/nand/raw/diskonchip.c
@@ -83,9 +83,9 @@ static u_char empty_write_ecc[6] = { 0x4b, 0x00, 0xe2, 0x0e, 0x93, 0xf7 };
#define DoC_is_Millennium(doc) ((doc)->ChipID == DOC_ChipID_DocMil)
#define DoC_is_2000(doc) ((doc)->ChipID == DOC_ChipID_Doc2k)
-static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd,
+static void doc200x_hwcontrol(struct nand_chip *this, int cmd,
unsigned int bitmask);
-static void doc200x_select_chip(struct mtd_info *mtd, int chip);
+static void doc200x_select_chip(struct nand_chip *this, int chip);
static int debug = 0;
module_param(debug, int, 0);
@@ -290,9 +290,8 @@ static inline int DoC_WaitReady(struct doc_priv *doc)
return ret;
}
-static void doc2000_write_byte(struct mtd_info *mtd, u_char datum)
+static void doc2000_write_byte(struct nand_chip *this, u_char datum)
{
- struct nand_chip *this = mtd_to_nand(mtd);
struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
@@ -302,9 +301,8 @@ static void doc2000_write_byte(struct mtd_info *mtd, u_char datum)
WriteDOC(datum, docptr, 2k_CDSN_IO);
}
-static u_char doc2000_read_byte(struct mtd_info *mtd)
+static u_char doc2000_read_byte(struct nand_chip *this)
{
- struct nand_chip *this = mtd_to_nand(mtd);
struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
u_char ret;
@@ -317,9 +315,9 @@ static u_char doc2000_read_byte(struct mtd_info *mtd)
return ret;
}
-static void doc2000_writebuf(struct mtd_info *mtd, const u_char *buf, int len)
+static void doc2000_writebuf(struct nand_chip *this, const u_char *buf,
+ int len)
{
- struct nand_chip *this = mtd_to_nand(mtd);
struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
int i;
@@ -334,9 +332,8 @@ static void doc2000_writebuf(struct mtd_info *mtd, const u_char *buf, int len)
printk("\n");
}
-static void doc2000_readbuf(struct mtd_info *mtd, u_char *buf, int len)
+static void doc2000_readbuf(struct nand_chip *this, u_char *buf, int len)
{
- struct nand_chip *this = mtd_to_nand(mtd);
struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
int i;
@@ -344,14 +341,12 @@ static void doc2000_readbuf(struct mtd_info *mtd, u_char *buf, int len)
if (debug)
printk("readbuf of %d bytes: ", len);
- for (i = 0; i < len; i++) {
+ for (i = 0; i < len; i++)
buf[i] = ReadDOC(docptr, 2k_CDSN_IO + i);
- }
}
-static void doc2000_readbuf_dword(struct mtd_info *mtd, u_char *buf, int len)
+static void doc2000_readbuf_dword(struct nand_chip *this, u_char *buf, int len)
{
- struct nand_chip *this = mtd_to_nand(mtd);
struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
int i;
@@ -376,19 +371,19 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr)
struct doc_priv *doc = nand_get_controller_data(this);
uint16_t ret;
- doc200x_select_chip(mtd, nr);
- doc200x_hwcontrol(mtd, NAND_CMD_READID,
+ doc200x_select_chip(this, nr);
+ doc200x_hwcontrol(this, NAND_CMD_READID,
NAND_CTRL_CLE | NAND_CTRL_CHANGE);
- doc200x_hwcontrol(mtd, 0, NAND_CTRL_ALE | NAND_CTRL_CHANGE);
- doc200x_hwcontrol(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
+ doc200x_hwcontrol(this, 0, NAND_CTRL_ALE | NAND_CTRL_CHANGE);
+ doc200x_hwcontrol(this, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
/* We can't use dev_ready here, but at least we wait for the
* command to complete
*/
udelay(50);
- ret = this->read_byte(mtd) << 8;
- ret |= this->read_byte(mtd);
+ ret = this->legacy.read_byte(this) << 8;
+ ret |= this->legacy.read_byte(this);
if (doc->ChipID == DOC_ChipID_Doc2k && try_dword && !nr) {
/* First chip probe. See if we get same results by 32-bit access */
@@ -398,10 +393,10 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr)
} ident;
void __iomem *docptr = doc->virtadr;
- doc200x_hwcontrol(mtd, NAND_CMD_READID,
+ doc200x_hwcontrol(this, NAND_CMD_READID,
NAND_CTRL_CLE | NAND_CTRL_CHANGE);
- doc200x_hwcontrol(mtd, 0, NAND_CTRL_ALE | NAND_CTRL_CHANGE);
- doc200x_hwcontrol(mtd, NAND_CMD_NONE,
+ doc200x_hwcontrol(this, 0, NAND_CTRL_ALE | NAND_CTRL_CHANGE);
+ doc200x_hwcontrol(this, NAND_CMD_NONE,
NAND_NCE | NAND_CTRL_CHANGE);
udelay(50);
@@ -409,7 +404,7 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr)
ident.dword = readl(docptr + DoC_2k_CDSN_IO);
if (((ident.byte[0] << 8) | ident.byte[1]) == ret) {
pr_info("DiskOnChip 2000 responds to DWORD access\n");
- this->read_buf = &doc2000_readbuf_dword;
+ this->legacy.read_buf = &doc2000_readbuf_dword;
}
}
@@ -438,7 +433,7 @@ static void __init doc2000_count_chips(struct mtd_info *mtd)
pr_debug("Detected %d chips per floor.\n", i);
}
-static int doc200x_wait(struct mtd_info *mtd, struct nand_chip *this)
+static int doc200x_wait(struct nand_chip *this)
{
struct doc_priv *doc = nand_get_controller_data(this);
@@ -447,14 +442,13 @@ static int doc200x_wait(struct mtd_info *mtd, struct nand_chip *this)
DoC_WaitReady(doc);
nand_status_op(this, NULL);
DoC_WaitReady(doc);
- status = (int)this->read_byte(mtd);
+ status = (int)this->legacy.read_byte(this);
return status;
}
-static void doc2001_write_byte(struct mtd_info *mtd, u_char datum)
+static void doc2001_write_byte(struct nand_chip *this, u_char datum)
{
- struct nand_chip *this = mtd_to_nand(mtd);
struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
@@ -463,9 +457,8 @@ static void doc2001_write_byte(struct mtd_info *mtd, u_char datum)
WriteDOC(datum, docptr, WritePipeTerm);
}
-static u_char doc2001_read_byte(struct mtd_info *mtd)
+static u_char doc2001_read_byte(struct nand_chip *this)
{
- struct nand_chip *this = mtd_to_nand(mtd);
struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
@@ -477,9 +470,8 @@ static u_char doc2001_read_byte(struct mtd_info *mtd)
return ReadDOC(docptr, LastDataRead);
}
-static void doc2001_writebuf(struct mtd_info *mtd, const u_char *buf, int len)
+static void doc2001_writebuf(struct nand_chip *this, const u_char *buf, int len)
{
- struct nand_chip *this = mtd_to_nand(mtd);
struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
int i;
@@ -490,9 +482,8 @@ static void doc2001_writebuf(struct mtd_info *mtd, const u_char *buf, int len)
WriteDOC(0x00, docptr, WritePipeTerm);
}
-static void doc2001_readbuf(struct mtd_info *mtd, u_char *buf, int len)
+static void doc2001_readbuf(struct nand_chip *this, u_char *buf, int len)
{
- struct nand_chip *this = mtd_to_nand(mtd);
struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
int i;
@@ -507,9 +498,8 @@ static void doc2001_readbuf(struct mtd_info *mtd, u_char *buf, int len)
buf[i] = ReadDOC(docptr, LastDataRead);
}
-static u_char doc2001plus_read_byte(struct mtd_info *mtd)
+static u_char doc2001plus_read_byte(struct nand_chip *this)
{
- struct nand_chip *this = mtd_to_nand(mtd);
struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
u_char ret;
@@ -522,9 +512,8 @@ static u_char doc2001plus_read_byte(struct mtd_info *mtd)
return ret;
}
-static void doc2001plus_writebuf(struct mtd_info *mtd, const u_char *buf, int len)
+static void doc2001plus_writebuf(struct nand_chip *this, const u_char *buf, int len)
{
- struct nand_chip *this = mtd_to_nand(mtd);
struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
int i;
@@ -540,9 +529,8 @@ static void doc2001plus_writebuf(struct mtd_info *mtd, const u_char *buf, int le
printk("\n");
}
-static void doc2001plus_readbuf(struct mtd_info *mtd, u_char *buf, int len)
+static void doc2001plus_readbuf(struct nand_chip *this, u_char *buf, int len)
{
- struct nand_chip *this = mtd_to_nand(mtd);
struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
int i;
@@ -571,9 +559,8 @@ static void doc2001plus_readbuf(struct mtd_info *mtd, u_char *buf, int len)
printk("\n");
}
-static void doc2001plus_select_chip(struct mtd_info *mtd, int chip)
+static void doc2001plus_select_chip(struct nand_chip *this, int chip)
{
- struct nand_chip *this = mtd_to_nand(mtd);
struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
int floor = 0;
@@ -598,9 +585,8 @@ static void doc2001plus_select_chip(struct mtd_info *mtd, int chip)
doc->curfloor = floor;
}
-static void doc200x_select_chip(struct mtd_info *mtd, int chip)
+static void doc200x_select_chip(struct nand_chip *this, int chip)
{
- struct nand_chip *this = mtd_to_nand(mtd);
struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
int floor = 0;
@@ -615,12 +601,12 @@ static void doc200x_select_chip(struct mtd_info *mtd, int chip)
chip -= (floor * doc->chips_per_floor);
/* 11.4.4 -- deassert CE before changing chip */
- doc200x_hwcontrol(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE);
+ doc200x_hwcontrol(this, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE);
WriteDOC(floor, docptr, FloorSelect);
WriteDOC(chip, docptr, CDSNDeviceSelect);
- doc200x_hwcontrol(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
+ doc200x_hwcontrol(this, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
doc->curchip = chip;
doc->curfloor = floor;
@@ -628,10 +614,9 @@ static void doc200x_select_chip(struct mtd_info *mtd, int chip)
#define CDSN_CTRL_MSK (CDSN_CTRL_CE | CDSN_CTRL_CLE | CDSN_CTRL_ALE)
-static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd,
+static void doc200x_hwcontrol(struct nand_chip *this, int cmd,
unsigned int ctrl)
{
- struct nand_chip *this = mtd_to_nand(mtd);
struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
@@ -646,15 +631,16 @@ static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd,
}
if (cmd != NAND_CMD_NONE) {
if (DoC_is_2000(doc))
- doc2000_write_byte(mtd, cmd);
+ doc2000_write_byte(this, cmd);
else
- doc2001_write_byte(mtd, cmd);
+ doc2001_write_byte(this, cmd);
}
}
-static void doc2001plus_command(struct mtd_info *mtd, unsigned command, int column, int page_addr)
+static void doc2001plus_command(struct nand_chip *this, unsigned command,
+ int column, int page_addr)
{
- struct nand_chip *this = mtd_to_nand(mtd);
+ struct mtd_info *mtd = nand_to_mtd(this);
struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
@@ -729,13 +715,13 @@ static void doc2001plus_command(struct mtd_info *mtd, unsigned command, int colu
return;
case NAND_CMD_RESET:
- if (this->dev_ready)
+ if (this->legacy.dev_ready)
break;
- udelay(this->chip_delay);
+ udelay(this->legacy.chip_delay);
WriteDOC(NAND_CMD_STATUS, docptr, Mplus_FlashCmd);
WriteDOC(0, docptr, Mplus_WritePipeTerm);
WriteDOC(0, docptr, Mplus_WritePipeTerm);
- while (!(this->read_byte(mtd) & 0x40)) ;
+ while (!(this->legacy.read_byte(this) & 0x40)) ;
return;
/* This applies to read commands */
@@ -744,8 +730,8 @@ static void doc2001plus_command(struct mtd_info *mtd, unsigned command, int colu
* If we don't have access to the busy pin, we apply the given
* command delay
*/
- if (!this->dev_ready) {
- udelay(this->chip_delay);
+ if (!this->legacy.dev_ready) {
+ udelay(this->legacy.chip_delay);
return;
}
}
@@ -754,12 +740,11 @@ static void doc2001plus_command(struct mtd_info *mtd, unsigned command, int colu
* any case on any machine. */
ndelay(100);
/* wait until command is processed */
- while (!this->dev_ready(mtd)) ;
+ while (!this->legacy.dev_ready(this)) ;
}
-static int doc200x_dev_ready(struct mtd_info *mtd)
+static int doc200x_dev_ready(struct nand_chip *this)
{
- struct nand_chip *this = mtd_to_nand(mtd);
struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
@@ -790,16 +775,15 @@ static int doc200x_dev_ready(struct mtd_info *mtd)
}
}
-static int doc200x_block_bad(struct mtd_info *mtd, loff_t ofs)
+static int doc200x_block_bad(struct nand_chip *this, loff_t ofs)
{
/* This is our last resort if we couldn't find or create a BBT. Just
pretend all blocks are good. */
return 0;
}
-static void doc200x_enable_hwecc(struct mtd_info *mtd, int mode)
+static void doc200x_enable_hwecc(struct nand_chip *this, int mode)
{
- struct nand_chip *this = mtd_to_nand(mtd);
struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
@@ -816,9 +800,8 @@ static void doc200x_enable_hwecc(struct mtd_info *mtd, int mode)
}
}
-static void doc2001plus_enable_hwecc(struct mtd_info *mtd, int mode)
+static void doc2001plus_enable_hwecc(struct nand_chip *this, int mode)
{
- struct nand_chip *this = mtd_to_nand(mtd);
struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
@@ -836,9 +819,9 @@ static void doc2001plus_enable_hwecc(struct mtd_info *mtd, int mode)
}
/* This code is only called on write */
-static int doc200x_calculate_ecc(struct mtd_info *mtd, const u_char *dat, unsigned char *ecc_code)
+static int doc200x_calculate_ecc(struct nand_chip *this, const u_char *dat,
+ unsigned char *ecc_code)
{
- struct nand_chip *this = mtd_to_nand(mtd);
struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
int i;
@@ -895,11 +878,10 @@ static int doc200x_calculate_ecc(struct mtd_info *mtd, const u_char *dat, unsign
return 0;
}
-static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat,
+static int doc200x_correct_data(struct nand_chip *this, u_char *dat,
u_char *read_ecc, u_char *isnull)
{
int i, ret = 0;
- struct nand_chip *this = mtd_to_nand(mtd);
struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
uint8_t calc_ecc[6];
@@ -1357,9 +1339,9 @@ static inline int __init doc2000_init(struct mtd_info *mtd)
struct nand_chip *this = mtd_to_nand(mtd);
struct doc_priv *doc = nand_get_controller_data(this);
- this->read_byte = doc2000_read_byte;
- this->write_buf = doc2000_writebuf;
- this->read_buf = doc2000_readbuf;
+ this->legacy.read_byte = doc2000_read_byte;
+ this->legacy.write_buf = doc2000_writebuf;
+ this->legacy.read_buf = doc2000_readbuf;
doc->late_init = nftl_scan_bbt;
doc->CDSNControl = CDSN_CTRL_FLASH_IO | CDSN_CTRL_ECC_IO;
@@ -1373,9 +1355,9 @@ static inline int __init doc2001_init(struct mtd_info *mtd)
struct nand_chip *this = mtd_to_nand(mtd);
struct doc_priv *doc = nand_get_controller_data(this);
- this->read_byte = doc2001_read_byte;
- this->write_buf = doc2001_writebuf;
- this->read_buf = doc2001_readbuf;
+ this->legacy.read_byte = doc2001_read_byte;
+ this->legacy.write_buf = doc2001_writebuf;
+ this->legacy.read_buf = doc2001_readbuf;
ReadDOC(doc->virtadr, ChipID);
ReadDOC(doc->virtadr, ChipID);
@@ -1403,13 +1385,13 @@ static inline int __init doc2001plus_init(struct mtd_info *mtd)
struct nand_chip *this = mtd_to_nand(mtd);
struct doc_priv *doc = nand_get_controller_data(this);
- this->read_byte = doc2001plus_read_byte;
- this->write_buf = doc2001plus_writebuf;
- this->read_buf = doc2001plus_readbuf;
+ this->legacy.read_byte = doc2001plus_read_byte;
+ this->legacy.write_buf = doc2001plus_writebuf;
+ this->legacy.read_buf = doc2001plus_readbuf;
doc->late_init = inftl_scan_bbt;
- this->cmd_ctrl = NULL;
+ this->legacy.cmd_ctrl = NULL;
this->select_chip = doc2001plus_select_chip;
- this->cmdfunc = doc2001plus_command;
+ this->legacy.cmdfunc = doc2001plus_command;
this->ecc.hwctl = doc2001plus_enable_hwecc;
doc->chips_per_floor = 1;
@@ -1587,10 +1569,10 @@ static int __init doc_probe(unsigned long physadr)
nand_set_controller_data(nand, doc);
nand->select_chip = doc200x_select_chip;
- nand->cmd_ctrl = doc200x_hwcontrol;
- nand->dev_ready = doc200x_dev_ready;
- nand->waitfunc = doc200x_wait;
- nand->block_bad = doc200x_block_bad;
+ nand->legacy.cmd_ctrl = doc200x_hwcontrol;
+ nand->legacy.dev_ready = doc200x_dev_ready;
+ nand->legacy.waitfunc = doc200x_wait;
+ nand->legacy.block_bad = doc200x_block_bad;
nand->ecc.hwctl = doc200x_enable_hwecc;
nand->ecc.calculate = doc200x_calculate_ecc;
nand->ecc.correct = doc200x_correct_data;
@@ -1620,14 +1602,14 @@ static int __init doc_probe(unsigned long physadr)
else
numchips = doc2001_init(mtd);
- if ((ret = nand_scan(mtd, numchips)) || (ret = doc->late_init(mtd))) {
+ if ((ret = nand_scan(nand, numchips)) || (ret = doc->late_init(mtd))) {
/* DBB note: i believe nand_release is necessary here, as
buffers may have been allocated in nand_base. Check with
Thomas. FIX ME! */
/* nand_release will call mtd_device_unregister, but we
haven't yet added it. This is handled without incident by
mtd_device_unregister, as far as I can tell. */
- nand_release(mtd);
+ nand_release(nand);
goto fail;
}
@@ -1662,7 +1644,7 @@ static void release_nanddoc(void)
doc = nand_get_controller_data(nand);
nextmtd = doc->nextdoc;
- nand_release(mtd);
+ nand_release(nand);
iounmap(doc->virtadr);
release_mem_region(doc->physadr, DOC_IOREMAP_LEN);
free_rs(doc->rs_decoder);
diff --git a/drivers/mtd/nand/raw/docg4.c b/drivers/mtd/nand/raw/docg4.c
deleted file mode 100644
index a3f04315c05c..000000000000
--- a/drivers/mtd/nand/raw/docg4.c
+++ /dev/null
@@ -1,1442 +0,0 @@
-/*
- * Copyright © 2012 Mike Dunn <mikedunn@newsguy.com>
- *
- * mtd nand driver for M-Systems DiskOnChip G4
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * Tested on the Palm Treo 680. The G4 is also present on Toshiba Portege, Asus
- * P526, some HTC smartphones (Wizard, Prophet, ...), O2 XDA Zinc, maybe others.
- * Should work on these as well. Let me know!
- *
- * TODO:
- *
- * Mechanism for management of password-protected areas
- *
- * Hamming ecc when reading oob only
- *
- * According to the M-Sys documentation, this device is also available in a
- * "dual-die" configuration having a 256MB capacity, but no mechanism for
- * detecting this variant is documented. Currently this driver assumes 128MB
- * capacity.
- *
- * Support for multiple cascaded devices ("floors"). Not sure which gadgets
- * contain multiple G4s in a cascaded configuration, if any.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/string.h>
-#include <linux/sched.h>
-#include <linux/delay.h>
-#include <linux/module.h>
-#include <linux/export.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-#include <linux/bitops.h>
-#include <linux/mtd/partitions.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/bch.h>
-#include <linux/bitrev.h>
-#include <linux/jiffies.h>
-
-/*
- * In "reliable mode" consecutive 2k pages are used in parallel (in some
- * fashion) to store the same data. The data can be read back from the
- * even-numbered pages in the normal manner; odd-numbered pages will appear to
- * contain junk. Systems that boot from the docg4 typically write the secondary
- * program loader (SPL) code in this mode. The SPL is loaded by the initial
- * program loader (IPL, stored in the docg4's 2k NOR-like region that is mapped
- * to the reset vector address). This module parameter enables you to use this
- * driver to write the SPL. When in this mode, no more than 2k of data can be
- * written at a time, because the addresses do not increment in the normal
- * manner, and the starting offset must be within an even-numbered 2k region;
- * i.e., invalid starting offsets are 0x800, 0xa00, 0xc00, 0xe00, 0x1800,
- * 0x1a00, ... Reliable mode is a special case and should not be used unless
- * you know what you're doing.
- */
-static bool reliable_mode;
-module_param(reliable_mode, bool, 0);
-MODULE_PARM_DESC(reliable_mode, "pages are programmed in reliable mode");
-
-/*
- * You'll want to ignore badblocks if you're reading a partition that contains
- * data written by the TrueFFS library (i.e., by PalmOS, Windows, etc), since
- * it does not use mtd nand's method for marking bad blocks (using oob area).
- * This will also skip the check of the "page written" flag.
- */
-static bool ignore_badblocks;
-module_param(ignore_badblocks, bool, 0);
-MODULE_PARM_DESC(ignore_badblocks, "no badblock checking performed");
-
-struct docg4_priv {
- struct mtd_info *mtd;
- struct device *dev;
- void __iomem *virtadr;
- int status;
- struct {
- unsigned int command;
- int column;
- int page;
- } last_command;
- uint8_t oob_buf[16];
- uint8_t ecc_buf[7];
- int oob_page;
- struct bch_control *bch;
-};
-
-/*
- * Defines prefixed with DOCG4 are unique to the diskonchip G4. All others are
- * shared with other diskonchip devices (P3, G3 at least).
- *
- * Functions with names prefixed with docg4_ are mtd / nand interface functions
- * (though they may also be called internally). All others are internal.
- */
-
-#define DOC_IOSPACE_DATA 0x0800
-
-/* register offsets */
-#define DOC_CHIPID 0x1000
-#define DOC_DEVICESELECT 0x100a
-#define DOC_ASICMODE 0x100c
-#define DOC_DATAEND 0x101e
-#define DOC_NOP 0x103e
-
-#define DOC_FLASHSEQUENCE 0x1032
-#define DOC_FLASHCOMMAND 0x1034
-#define DOC_FLASHADDRESS 0x1036
-#define DOC_FLASHCONTROL 0x1038
-#define DOC_ECCCONF0 0x1040
-#define DOC_ECCCONF1 0x1042
-#define DOC_HAMMINGPARITY 0x1046
-#define DOC_BCH_SYNDROM(idx) (0x1048 + idx)
-
-#define DOC_ASICMODECONFIRM 0x1072
-#define DOC_CHIPID_INV 0x1074
-#define DOC_POWERMODE 0x107c
-
-#define DOCG4_MYSTERY_REG 0x1050
-
-/* apparently used only to write oob bytes 6 and 7 */
-#define DOCG4_OOB_6_7 0x1052
-
-/* DOC_FLASHSEQUENCE register commands */
-#define DOC_SEQ_RESET 0x00
-#define DOCG4_SEQ_PAGE_READ 0x03
-#define DOCG4_SEQ_FLUSH 0x29
-#define DOCG4_SEQ_PAGEWRITE 0x16
-#define DOCG4_SEQ_PAGEPROG 0x1e
-#define DOCG4_SEQ_BLOCKERASE 0x24
-#define DOCG4_SEQ_SETMODE 0x45
-
-/* DOC_FLASHCOMMAND register commands */
-#define DOCG4_CMD_PAGE_READ 0x00
-#define DOC_CMD_ERASECYCLE2 0xd0
-#define DOCG4_CMD_FLUSH 0x70
-#define DOCG4_CMD_READ2 0x30
-#define DOC_CMD_PROG_BLOCK_ADDR 0x60
-#define DOCG4_CMD_PAGEWRITE 0x80
-#define DOC_CMD_PROG_CYCLE2 0x10
-#define DOCG4_CMD_FAST_MODE 0xa3 /* functionality guessed */
-#define DOC_CMD_RELIABLE_MODE 0x22
-#define DOC_CMD_RESET 0xff
-
-/* DOC_POWERMODE register bits */
-#define DOC_POWERDOWN_READY 0x80
-
-/* DOC_FLASHCONTROL register bits */
-#define DOC_CTRL_CE 0x10
-#define DOC_CTRL_UNKNOWN 0x40
-#define DOC_CTRL_FLASHREADY 0x01
-
-/* DOC_ECCCONF0 register bits */
-#define DOC_ECCCONF0_READ_MODE 0x8000
-#define DOC_ECCCONF0_UNKNOWN 0x2000
-#define DOC_ECCCONF0_ECC_ENABLE 0x1000
-#define DOC_ECCCONF0_DATA_BYTES_MASK 0x07ff
-
-/* DOC_ECCCONF1 register bits */
-#define DOC_ECCCONF1_BCH_SYNDROM_ERR 0x80
-#define DOC_ECCCONF1_ECC_ENABLE 0x07
-#define DOC_ECCCONF1_PAGE_IS_WRITTEN 0x20
-
-/* DOC_ASICMODE register bits */
-#define DOC_ASICMODE_RESET 0x00
-#define DOC_ASICMODE_NORMAL 0x01
-#define DOC_ASICMODE_POWERDOWN 0x02
-#define DOC_ASICMODE_MDWREN 0x04
-#define DOC_ASICMODE_BDETCT_RESET 0x08
-#define DOC_ASICMODE_RSTIN_RESET 0x10
-#define DOC_ASICMODE_RAM_WE 0x20
-
-/* good status values read after read/write/erase operations */
-#define DOCG4_PROGSTATUS_GOOD 0x51
-#define DOCG4_PROGSTATUS_GOOD_2 0xe0
-
-/*
- * On read operations (page and oob-only), the first byte read from I/O reg is a
- * status. On error, it reads 0x73; otherwise, it reads either 0x71 (first read
- * after reset only) or 0x51, so bit 1 is presumed to be an error indicator.
- */
-#define DOCG4_READ_ERROR 0x02 /* bit 1 indicates read error */
-
-/* anatomy of the device */
-#define DOCG4_CHIP_SIZE 0x8000000
-#define DOCG4_PAGE_SIZE 0x200
-#define DOCG4_PAGES_PER_BLOCK 0x200
-#define DOCG4_BLOCK_SIZE (DOCG4_PAGES_PER_BLOCK * DOCG4_PAGE_SIZE)
-#define DOCG4_NUMBLOCKS (DOCG4_CHIP_SIZE / DOCG4_BLOCK_SIZE)
-#define DOCG4_OOB_SIZE 0x10
-#define DOCG4_CHIP_SHIFT 27 /* log_2(DOCG4_CHIP_SIZE) */
-#define DOCG4_PAGE_SHIFT 9 /* log_2(DOCG4_PAGE_SIZE) */
-#define DOCG4_ERASE_SHIFT 18 /* log_2(DOCG4_BLOCK_SIZE) */
-
-/* all but the last byte is included in ecc calculation */
-#define DOCG4_BCH_SIZE (DOCG4_PAGE_SIZE + DOCG4_OOB_SIZE - 1)
-
-#define DOCG4_USERDATA_LEN 520 /* 512 byte page plus 8 oob avail to user */
-
-/* expected values from the ID registers */
-#define DOCG4_IDREG1_VALUE 0x0400
-#define DOCG4_IDREG2_VALUE 0xfbff
-
-/* primitive polynomial used to build the Galois field used by hw ecc gen */
-#define DOCG4_PRIMITIVE_POLY 0x4443
-
-#define DOCG4_M 14 /* Galois field is of order 2^14 */
-#define DOCG4_T 4 /* BCH alg corrects up to 4 bit errors */
-
-#define DOCG4_FACTORY_BBT_PAGE 16 /* page where read-only factory bbt lives */
-#define DOCG4_REDUNDANT_BBT_PAGE 24 /* page where redundant factory bbt lives */
-
-/*
- * Bytes 0, 1 are used as badblock marker.
- * Bytes 2 - 6 are available to the user.
- * Byte 7 is hamming ecc for first 7 oob bytes only.
- * Bytes 8 - 14 are hw-generated ecc covering entire page + oob bytes 0 - 14.
- * Byte 15 (the last) is used by the driver as a "page written" flag.
- */
-static int docg4_ooblayout_ecc(struct mtd_info *mtd, int section,
- struct mtd_oob_region *oobregion)
-{
- if (section)
- return -ERANGE;
-
- oobregion->offset = 7;
- oobregion->length = 9;
-
- return 0;
-}
-
-static int docg4_ooblayout_free(struct mtd_info *mtd, int section,
- struct mtd_oob_region *oobregion)
-{
- if (section)
- return -ERANGE;
-
- oobregion->offset = 2;
- oobregion->length = 5;
-
- return 0;
-}
-
-static const struct mtd_ooblayout_ops docg4_ooblayout_ops = {
- .ecc = docg4_ooblayout_ecc,
- .free = docg4_ooblayout_free,
-};
-
-/*
- * The device has a nop register which M-Sys claims is for the purpose of
- * inserting precise delays. But beware; at least some operations fail if the
- * nop writes are replaced with a generic delay!
- */
-static inline void write_nop(void __iomem *docptr)
-{
- writew(0, docptr + DOC_NOP);
-}
-
-static void docg4_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
-{
- int i;
- struct nand_chip *nand = mtd_to_nand(mtd);
- uint16_t *p = (uint16_t *) buf;
- len >>= 1;
-
- for (i = 0; i < len; i++)
- p[i] = readw(nand->IO_ADDR_R);
-}
-
-static void docg4_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
-{
- int i;
- struct nand_chip *nand = mtd_to_nand(mtd);
- uint16_t *p = (uint16_t *) buf;
- len >>= 1;
-
- for (i = 0; i < len; i++)
- writew(p[i], nand->IO_ADDR_W);
-}
-
-static int poll_status(struct docg4_priv *doc)
-{
- /*
- * Busy-wait for the FLASHREADY bit to be set in the FLASHCONTROL
- * register. Operations known to take a long time (e.g., block erase)
- * should sleep for a while before calling this.
- */
-
- uint16_t flash_status;
- unsigned long timeo;
- void __iomem *docptr = doc->virtadr;
-
- dev_dbg(doc->dev, "%s...\n", __func__);
-
- /* hardware quirk requires reading twice initially */
- flash_status = readw(docptr + DOC_FLASHCONTROL);
-
- timeo = jiffies + msecs_to_jiffies(200); /* generous timeout */
- do {
- cpu_relax();
- flash_status = readb(docptr + DOC_FLASHCONTROL);
- } while (!(flash_status & DOC_CTRL_FLASHREADY) &&
- time_before(jiffies, timeo));
-
- if (unlikely(!(flash_status & DOC_CTRL_FLASHREADY))) {
- dev_err(doc->dev, "%s: timed out!\n", __func__);
- return NAND_STATUS_FAIL;
- }
-
- return 0;
-}
-
-
-static int docg4_wait(struct mtd_info *mtd, struct nand_chip *nand)
-{
-
- struct docg4_priv *doc = nand_get_controller_data(nand);
- int status = NAND_STATUS_WP; /* inverse logic?? */
- dev_dbg(doc->dev, "%s...\n", __func__);
-
- /* report any previously unreported error */
- if (doc->status) {
- status |= doc->status;
- doc->status = 0;
- return status;
- }
-
- status |= poll_status(doc);
- return status;
-}
-
-static void docg4_select_chip(struct mtd_info *mtd, int chip)
-{
- /*
- * Select among multiple cascaded chips ("floors"). Multiple floors are
- * not yet supported, so the only valid non-negative value is 0.
- */
- struct nand_chip *nand = mtd_to_nand(mtd);
- struct docg4_priv *doc = nand_get_controller_data(nand);
- void __iomem *docptr = doc->virtadr;
-
- dev_dbg(doc->dev, "%s: chip %d\n", __func__, chip);
-
- if (chip < 0)
- return; /* deselected */
-
- if (chip > 0)
- dev_warn(doc->dev, "multiple floors currently unsupported\n");
-
- writew(0, docptr + DOC_DEVICESELECT);
-}
-
-static void reset(struct mtd_info *mtd)
-{
- /* full device reset */
-
- struct nand_chip *nand = mtd_to_nand(mtd);
- struct docg4_priv *doc = nand_get_controller_data(nand);
- void __iomem *docptr = doc->virtadr;
-
- writew(DOC_ASICMODE_RESET | DOC_ASICMODE_MDWREN,
- docptr + DOC_ASICMODE);
- writew(~(DOC_ASICMODE_RESET | DOC_ASICMODE_MDWREN),
- docptr + DOC_ASICMODECONFIRM);
- write_nop(docptr);
-
- writew(DOC_ASICMODE_NORMAL | DOC_ASICMODE_MDWREN,
- docptr + DOC_ASICMODE);
- writew(~(DOC_ASICMODE_NORMAL | DOC_ASICMODE_MDWREN),
- docptr + DOC_ASICMODECONFIRM);
-
- writew(DOC_ECCCONF1_ECC_ENABLE, docptr + DOC_ECCCONF1);
-
- poll_status(doc);
-}
-
-static void read_hw_ecc(void __iomem *docptr, uint8_t *ecc_buf)
-{
- /* read the 7 hw-generated ecc bytes */
-
- int i;
- for (i = 0; i < 7; i++) { /* hw quirk; read twice */
- ecc_buf[i] = readb(docptr + DOC_BCH_SYNDROM(i));
- ecc_buf[i] = readb(docptr + DOC_BCH_SYNDROM(i));
- }
-}
-
-static int correct_data(struct mtd_info *mtd, uint8_t *buf, int page)
-{
- /*
- * Called after a page read when hardware reports bitflips.
- * Up to four bitflips can be corrected.
- */
-
- struct nand_chip *nand = mtd_to_nand(mtd);
- struct docg4_priv *doc = nand_get_controller_data(nand);
- void __iomem *docptr = doc->virtadr;
- int i, numerrs, errpos[4];
- const uint8_t blank_read_hwecc[8] = {
- 0xcf, 0x72, 0xfc, 0x1b, 0xa9, 0xc7, 0xb9, 0 };
-
- read_hw_ecc(docptr, doc->ecc_buf); /* read 7 hw-generated ecc bytes */
-
- /* check if read error is due to a blank page */
- if (!memcmp(doc->ecc_buf, blank_read_hwecc, 7))
- return 0; /* yes */
-
- /* skip additional check of "written flag" if ignore_badblocks */
- if (ignore_badblocks == false) {
-
- /*
- * If the hw ecc bytes are not those of a blank page, there's
- * still a chance that the page is blank, but was read with
- * errors. Check the "written flag" in last oob byte, which
- * is set to zero when a page is written. If more than half
- * the bits are set, assume a blank page. Unfortunately, the
- * bit flips(s) are not reported in stats.
- */
-
- if (nand->oob_poi[15]) {
- int bit, numsetbits = 0;
- unsigned long written_flag = nand->oob_poi[15];
- for_each_set_bit(bit, &written_flag, 8)
- numsetbits++;
- if (numsetbits > 4) { /* assume blank */
- dev_warn(doc->dev,
- "error(s) in blank page "
- "at offset %08x\n",
- page * DOCG4_PAGE_SIZE);
- return 0;
- }
- }
- }
-
- /*
- * The hardware ecc unit produces oob_ecc ^ calc_ecc. The kernel's bch
- * algorithm is used to decode this. However the hw operates on page
- * data in a bit order that is the reverse of that of the bch alg,
- * requiring that the bits be reversed on the result. Thanks to Ivan
- * Djelic for his analysis!
- */
- for (i = 0; i < 7; i++)
- doc->ecc_buf[i] = bitrev8(doc->ecc_buf[i]);
-
- numerrs = decode_bch(doc->bch, NULL, DOCG4_USERDATA_LEN, NULL,
- doc->ecc_buf, NULL, errpos);
-
- if (numerrs == -EBADMSG) {
- dev_warn(doc->dev, "uncorrectable errors at offset %08x\n",
- page * DOCG4_PAGE_SIZE);
- return -EBADMSG;
- }
-
- BUG_ON(numerrs < 0); /* -EINVAL, or anything other than -EBADMSG */
-
- /* undo last step in BCH alg (modulo mirroring not needed) */
- for (i = 0; i < numerrs; i++)
- errpos[i] = (errpos[i] & ~7)|(7-(errpos[i] & 7));
-
- /* fix the errors */
- for (i = 0; i < numerrs; i++) {
-
- /* ignore if error within oob ecc bytes */
- if (errpos[i] > DOCG4_USERDATA_LEN * 8)
- continue;
-
- /* if error within oob area preceeding ecc bytes... */
- if (errpos[i] > DOCG4_PAGE_SIZE * 8)
- change_bit(errpos[i] - DOCG4_PAGE_SIZE * 8,
- (unsigned long *)nand->oob_poi);
-
- else /* error in page data */
- change_bit(errpos[i], (unsigned long *)buf);
- }
-
- dev_notice(doc->dev, "%d error(s) corrected at offset %08x\n",
- numerrs, page * DOCG4_PAGE_SIZE);
-
- return numerrs;
-}
-
-static uint8_t docg4_read_byte(struct mtd_info *mtd)
-{
- struct nand_chip *nand = mtd_to_nand(mtd);
- struct docg4_priv *doc = nand_get_controller_data(nand);
-
- dev_dbg(doc->dev, "%s\n", __func__);
-
- if (doc->last_command.command == NAND_CMD_STATUS) {
- int status;
-
- /*
- * Previous nand command was status request, so nand
- * infrastructure code expects to read the status here. If an
- * error occurred in a previous operation, report it.
- */
- doc->last_command.command = 0;
-
- if (doc->status) {
- status = doc->status;
- doc->status = 0;
- }
-
- /* why is NAND_STATUS_WP inverse logic?? */
- else
- status = NAND_STATUS_WP | NAND_STATUS_READY;
-
- return status;
- }
-
- dev_warn(doc->dev, "unexpected call to read_byte()\n");
-
- return 0;
-}
-
-static void write_addr(struct docg4_priv *doc, uint32_t docg4_addr)
-{
- /* write the four address bytes packed in docg4_addr to the device */
-
- void __iomem *docptr = doc->virtadr;
- writeb(docg4_addr & 0xff, docptr + DOC_FLASHADDRESS);
- docg4_addr >>= 8;
- writeb(docg4_addr & 0xff, docptr + DOC_FLASHADDRESS);
- docg4_addr >>= 8;
- writeb(docg4_addr & 0xff, docptr + DOC_FLASHADDRESS);
- docg4_addr >>= 8;
- writeb(docg4_addr & 0xff, docptr + DOC_FLASHADDRESS);
-}
-
-static int read_progstatus(struct docg4_priv *doc)
-{
- /*
- * This apparently checks the status of programming. Done after an
- * erasure, and after page data is written. On error, the status is
- * saved, to be later retrieved by the nand infrastructure code.
- */
- void __iomem *docptr = doc->virtadr;
-
- /* status is read from the I/O reg */
- uint16_t status1 = readw(docptr + DOC_IOSPACE_DATA);
- uint16_t status2 = readw(docptr + DOC_IOSPACE_DATA);
- uint16_t status3 = readw(docptr + DOCG4_MYSTERY_REG);
-
- dev_dbg(doc->dev, "docg4: %s: %02x %02x %02x\n",
- __func__, status1, status2, status3);
-
- if (status1 != DOCG4_PROGSTATUS_GOOD
- || status2 != DOCG4_PROGSTATUS_GOOD_2
- || status3 != DOCG4_PROGSTATUS_GOOD_2) {
- doc->status = NAND_STATUS_FAIL;
- dev_warn(doc->dev, "read_progstatus failed: "
- "%02x, %02x, %02x\n", status1, status2, status3);
- return -EIO;
- }
- return 0;
-}
-
-static int pageprog(struct mtd_info *mtd)
-{
- /*
- * Final step in writing a page. Writes the contents of its
- * internal buffer out to the flash array, or some such.
- */
-
- struct nand_chip *nand = mtd_to_nand(mtd);
- struct docg4_priv *doc = nand_get_controller_data(nand);
- void __iomem *docptr = doc->virtadr;
- int retval = 0;
-
- dev_dbg(doc->dev, "docg4: %s\n", __func__);
-
- writew(DOCG4_SEQ_PAGEPROG, docptr + DOC_FLASHSEQUENCE);
- writew(DOC_CMD_PROG_CYCLE2, docptr + DOC_FLASHCOMMAND);
- write_nop(docptr);
- write_nop(docptr);
-
- /* Just busy-wait; usleep_range() slows things down noticeably. */
- poll_status(doc);
-
- writew(DOCG4_SEQ_FLUSH, docptr + DOC_FLASHSEQUENCE);
- writew(DOCG4_CMD_FLUSH, docptr + DOC_FLASHCOMMAND);
- writew(DOC_ECCCONF0_READ_MODE | 4, docptr + DOC_ECCCONF0);
- write_nop(docptr);
- write_nop(docptr);
- write_nop(docptr);
- write_nop(docptr);
- write_nop(docptr);
-
- retval = read_progstatus(doc);
- writew(0, docptr + DOC_DATAEND);
- write_nop(docptr);
- poll_status(doc);
- write_nop(docptr);
-
- return retval;
-}
-
-static void sequence_reset(struct mtd_info *mtd)
-{
- /* common starting sequence for all operations */
-
- struct nand_chip *nand = mtd_to_nand(mtd);
- struct docg4_priv *doc = nand_get_controller_data(nand);
- void __iomem *docptr = doc->virtadr;
-
- writew(DOC_CTRL_UNKNOWN | DOC_CTRL_CE, docptr + DOC_FLASHCONTROL);
- writew(DOC_SEQ_RESET, docptr + DOC_FLASHSEQUENCE);
- writew(DOC_CMD_RESET, docptr + DOC_FLASHCOMMAND);
- write_nop(docptr);
- write_nop(docptr);
- poll_status(doc);
- write_nop(docptr);
-}
-
-static void read_page_prologue(struct mtd_info *mtd, uint32_t docg4_addr)
-{
- /* first step in reading a page */
-
- struct nand_chip *nand = mtd_to_nand(mtd);
- struct docg4_priv *doc = nand_get_controller_data(nand);
- void __iomem *docptr = doc->virtadr;
-
- dev_dbg(doc->dev,
- "docg4: %s: g4 page %08x\n", __func__, docg4_addr);
-
- sequence_reset(mtd);
-
- writew(DOCG4_SEQ_PAGE_READ, docptr + DOC_FLASHSEQUENCE);
- writew(DOCG4_CMD_PAGE_READ, docptr + DOC_FLASHCOMMAND);
- write_nop(docptr);
-
- write_addr(doc, docg4_addr);
-
- write_nop(docptr);
- writew(DOCG4_CMD_READ2, docptr + DOC_FLASHCOMMAND);
- write_nop(docptr);
- write_nop(docptr);
-
- poll_status(doc);
-}
-
-static void write_page_prologue(struct mtd_info *mtd, uint32_t docg4_addr)
-{
- /* first step in writing a page */
-
- struct nand_chip *nand = mtd_to_nand(mtd);
- struct docg4_priv *doc = nand_get_controller_data(nand);
- void __iomem *docptr = doc->virtadr;
-
- dev_dbg(doc->dev,
- "docg4: %s: g4 addr: %x\n", __func__, docg4_addr);
- sequence_reset(mtd);
-
- if (unlikely(reliable_mode)) {
- writew(DOCG4_SEQ_SETMODE, docptr + DOC_FLASHSEQUENCE);
- writew(DOCG4_CMD_FAST_MODE, docptr + DOC_FLASHCOMMAND);
- writew(DOC_CMD_RELIABLE_MODE, docptr + DOC_FLASHCOMMAND);
- write_nop(docptr);
- }
-
- writew(DOCG4_SEQ_PAGEWRITE, docptr + DOC_FLASHSEQUENCE);
- writew(DOCG4_CMD_PAGEWRITE, docptr + DOC_FLASHCOMMAND);
- write_nop(docptr);
- write_addr(doc, docg4_addr);
- write_nop(docptr);
- write_nop(docptr);
- poll_status(doc);
-}
-
-static uint32_t mtd_to_docg4_address(int page, int column)
-{
- /*
- * Convert mtd address to format used by the device, 32 bit packed.
- *
- * Some notes on G4 addressing... The M-Sys documentation on this device
- * claims that pages are 2K in length, and indeed, the format of the
- * address used by the device reflects that. But within each page are
- * four 512 byte "sub-pages", each with its own oob data that is
- * read/written immediately after the 512 bytes of page data. This oob
- * data contains the ecc bytes for the preceeding 512 bytes.
- *
- * Rather than tell the mtd nand infrastructure that page size is 2k,
- * with four sub-pages each, we engage in a little subterfuge and tell
- * the infrastructure code that pages are 512 bytes in size. This is
- * done because during the course of reverse-engineering the device, I
- * never observed an instance where an entire 2K "page" was read or
- * written as a unit. Each "sub-page" is always addressed individually,
- * its data read/written, and ecc handled before the next "sub-page" is
- * addressed.
- *
- * This requires us to convert addresses passed by the mtd nand
- * infrastructure code to those used by the device.
- *
- * The address that is written to the device consists of four bytes: the
- * first two are the 2k page number, and the second is the index into
- * the page. The index is in terms of 16-bit half-words and includes
- * the preceeding oob data, so e.g., the index into the second
- * "sub-page" is 0x108, and the full device address of the start of mtd
- * page 0x201 is 0x00800108.
- */
- int g4_page = page / 4; /* device's 2K page */
- int g4_index = (page % 4) * 0x108 + column/2; /* offset into page */
- return (g4_page << 16) | g4_index; /* pack */
-}
-
-static void docg4_command(struct mtd_info *mtd, unsigned command, int column,
- int page_addr)
-{
- /* handle standard nand commands */
-
- struct nand_chip *nand = mtd_to_nand(mtd);
- struct docg4_priv *doc = nand_get_controller_data(nand);
- uint32_t g4_addr = mtd_to_docg4_address(page_addr, column);
-
- dev_dbg(doc->dev, "%s %x, page_addr=%x, column=%x\n",
- __func__, command, page_addr, column);
-
- /*
- * Save the command and its arguments. This enables emulation of
- * standard flash devices, and also some optimizations.
- */
- doc->last_command.command = command;
- doc->last_command.column = column;
- doc->last_command.page = page_addr;
-
- switch (command) {
-
- case NAND_CMD_RESET:
- reset(mtd);
- break;
-
- case NAND_CMD_READ0:
- read_page_prologue(mtd, g4_addr);
- break;
-
- case NAND_CMD_STATUS:
- /* next call to read_byte() will expect a status */
- break;
-
- case NAND_CMD_SEQIN:
- if (unlikely(reliable_mode)) {
- uint16_t g4_page = g4_addr >> 16;
-
- /* writes to odd-numbered 2k pages are invalid */
- if (g4_page & 0x01)
- dev_warn(doc->dev,
- "invalid reliable mode address\n");
- }
-
- write_page_prologue(mtd, g4_addr);
-
- /* hack for deferred write of oob bytes */
- if (doc->oob_page == page_addr)
- memcpy(nand->oob_poi, doc->oob_buf, 16);
- break;
-
- case NAND_CMD_PAGEPROG:
- pageprog(mtd);
- break;
-
- /* we don't expect these, based on review of nand_base.c */
- case NAND_CMD_READOOB:
- case NAND_CMD_READID:
- case NAND_CMD_ERASE1:
- case NAND_CMD_ERASE2:
- dev_warn(doc->dev, "docg4_command: "
- "unexpected nand command 0x%x\n", command);
- break;
-
- }
-}
-
-static int read_page(struct mtd_info *mtd, struct nand_chip *nand,
- uint8_t *buf, int page, bool use_ecc)
-{
- struct docg4_priv *doc = nand_get_controller_data(nand);
- void __iomem *docptr = doc->virtadr;
- uint16_t status, edc_err, *buf16;
- int bits_corrected = 0;
-
- dev_dbg(doc->dev, "%s: page %08x\n", __func__, page);
-
- nand_read_page_op(nand, page, 0, NULL, 0);
-
- writew(DOC_ECCCONF0_READ_MODE |
- DOC_ECCCONF0_ECC_ENABLE |
- DOC_ECCCONF0_UNKNOWN |
- DOCG4_BCH_SIZE,
- docptr + DOC_ECCCONF0);
- write_nop(docptr);
- write_nop(docptr);
- write_nop(docptr);
- write_nop(docptr);
- write_nop(docptr);
-
- /* the 1st byte from the I/O reg is a status; the rest is page data */
- status = readw(docptr + DOC_IOSPACE_DATA);
- if (status & DOCG4_READ_ERROR) {
- dev_err(doc->dev,
- "docg4_read_page: bad status: 0x%02x\n", status);
- writew(0, docptr + DOC_DATAEND);
- return -EIO;
- }
-
- dev_dbg(doc->dev, "%s: status = 0x%x\n", __func__, status);
-
- docg4_read_buf(mtd, buf, DOCG4_PAGE_SIZE); /* read the page data */
-
- /* this device always reads oob after page data */
- /* first 14 oob bytes read from I/O reg */
- docg4_read_buf(mtd, nand->oob_poi, 14);
-
- /* last 2 read from another reg */
- buf16 = (uint16_t *)(nand->oob_poi + 14);
- *buf16 = readw(docptr + DOCG4_MYSTERY_REG);
-
- write_nop(docptr);
-
- if (likely(use_ecc == true)) {
-
- /* read the register that tells us if bitflip(s) detected */
- edc_err = readw(docptr + DOC_ECCCONF1);
- edc_err = readw(docptr + DOC_ECCCONF1);
- dev_dbg(doc->dev, "%s: edc_err = 0x%02x\n", __func__, edc_err);
-
- /* If bitflips are reported, attempt to correct with ecc */
- if (edc_err & DOC_ECCCONF1_BCH_SYNDROM_ERR) {
- bits_corrected = correct_data(mtd, buf, page);
- if (bits_corrected == -EBADMSG)
- mtd->ecc_stats.failed++;
- else
- mtd->ecc_stats.corrected += bits_corrected;
- }
- }
-
- writew(0, docptr + DOC_DATAEND);
- if (bits_corrected == -EBADMSG) /* uncorrectable errors */
- return 0;
- return bits_corrected;
-}
-
-
-static int docg4_read_page_raw(struct mtd_info *mtd, struct nand_chip *nand,
- uint8_t *buf, int oob_required, int page)
-{
- return read_page(mtd, nand, buf, page, false);
-}
-
-static int docg4_read_page(struct mtd_info *mtd, struct nand_chip *nand,
- uint8_t *buf, int oob_required, int page)
-{
- return read_page(mtd, nand, buf, page, true);
-}
-
-static int docg4_read_oob(struct mtd_info *mtd, struct nand_chip *nand,
- int page)
-{
- struct docg4_priv *doc = nand_get_controller_data(nand);
- void __iomem *docptr = doc->virtadr;
- uint16_t status;
-
- dev_dbg(doc->dev, "%s: page %x\n", __func__, page);
-
- nand_read_page_op(nand, page, nand->ecc.size, NULL, 0);
-
- writew(DOC_ECCCONF0_READ_MODE | DOCG4_OOB_SIZE, docptr + DOC_ECCCONF0);
- write_nop(docptr);
- write_nop(docptr);
- write_nop(docptr);
- write_nop(docptr);
- write_nop(docptr);
-
- /* the 1st byte from the I/O reg is a status; the rest is oob data */
- status = readw(docptr + DOC_IOSPACE_DATA);
- if (status & DOCG4_READ_ERROR) {
- dev_warn(doc->dev,
- "docg4_read_oob failed: status = 0x%02x\n", status);
- return -EIO;
- }
-
- dev_dbg(doc->dev, "%s: status = 0x%x\n", __func__, status);
-
- docg4_read_buf(mtd, nand->oob_poi, 16);
-
- write_nop(docptr);
- write_nop(docptr);
- write_nop(docptr);
- writew(0, docptr + DOC_DATAEND);
- write_nop(docptr);
-
- return 0;
-}
-
-static int docg4_erase_block(struct mtd_info *mtd, int page)
-{
- struct nand_chip *nand = mtd_to_nand(mtd);
- struct docg4_priv *doc = nand_get_controller_data(nand);
- void __iomem *docptr = doc->virtadr;
- uint16_t g4_page;
- int status;
-
- dev_dbg(doc->dev, "%s: page %04x\n", __func__, page);
-
- sequence_reset(mtd);
-
- writew(DOCG4_SEQ_BLOCKERASE, docptr + DOC_FLASHSEQUENCE);
- writew(DOC_CMD_PROG_BLOCK_ADDR, docptr + DOC_FLASHCOMMAND);
- write_nop(docptr);
-
- /* only 2 bytes of address are written to specify erase block */
- g4_page = (uint16_t)(page / 4); /* to g4's 2k page addressing */
- writeb(g4_page & 0xff, docptr + DOC_FLASHADDRESS);
- g4_page >>= 8;
- writeb(g4_page & 0xff, docptr + DOC_FLASHADDRESS);
- write_nop(docptr);
-
- /* start the erasure */
- writew(DOC_CMD_ERASECYCLE2, docptr + DOC_FLASHCOMMAND);
- write_nop(docptr);
- write_nop(docptr);
-
- usleep_range(500, 1000); /* erasure is long; take a snooze */
- poll_status(doc);
- writew(DOCG4_SEQ_FLUSH, docptr + DOC_FLASHSEQUENCE);
- writew(DOCG4_CMD_FLUSH, docptr + DOC_FLASHCOMMAND);
- writew(DOC_ECCCONF0_READ_MODE | 4, docptr + DOC_ECCCONF0);
- write_nop(docptr);
- write_nop(docptr);
- write_nop(docptr);
- write_nop(docptr);
- write_nop(docptr);
-
- read_progstatus(doc);
-
- writew(0, docptr + DOC_DATAEND);
- write_nop(docptr);
- poll_status(doc);
- write_nop(docptr);
-
- status = nand->waitfunc(mtd, nand);
- if (status < 0)
- return status;
-
- return status & NAND_STATUS_FAIL ? -EIO : 0;
-}
-
-static int write_page(struct mtd_info *mtd, struct nand_chip *nand,
- const uint8_t *buf, int page, bool use_ecc)
-{
- struct docg4_priv *doc = nand_get_controller_data(nand);
- void __iomem *docptr = doc->virtadr;
- uint8_t ecc_buf[8];
-
- dev_dbg(doc->dev, "%s...\n", __func__);
-
- nand_prog_page_begin_op(nand, page, 0, NULL, 0);
-
- writew(DOC_ECCCONF0_ECC_ENABLE |
- DOC_ECCCONF0_UNKNOWN |
- DOCG4_BCH_SIZE,
- docptr + DOC_ECCCONF0);
- write_nop(docptr);
-
- /* write the page data */
- docg4_write_buf16(mtd, buf, DOCG4_PAGE_SIZE);
-
- /* oob bytes 0 through 5 are written to I/O reg */
- docg4_write_buf16(mtd, nand->oob_poi, 6);
-
- /* oob byte 6 written to a separate reg */
- writew(nand->oob_poi[6], docptr + DOCG4_OOB_6_7);
-
- write_nop(docptr);
- write_nop(docptr);
-
- /* write hw-generated ecc bytes to oob */
- if (likely(use_ecc == true)) {
- /* oob byte 7 is hamming code */
- uint8_t hamming = readb(docptr + DOC_HAMMINGPARITY);
- hamming = readb(docptr + DOC_HAMMINGPARITY); /* 2nd read */
- writew(hamming, docptr + DOCG4_OOB_6_7);
- write_nop(docptr);
-
- /* read the 7 bch bytes from ecc regs */
- read_hw_ecc(docptr, ecc_buf);
- ecc_buf[7] = 0; /* clear the "page written" flag */
- }
-
- /* write user-supplied bytes to oob */
- else {
- writew(nand->oob_poi[7], docptr + DOCG4_OOB_6_7);
- write_nop(docptr);
- memcpy(ecc_buf, &nand->oob_poi[8], 8);
- }
-
- docg4_write_buf16(mtd, ecc_buf, 8);
- write_nop(docptr);
- write_nop(docptr);
- writew(0, docptr + DOC_DATAEND);
- write_nop(docptr);
-
- return nand_prog_page_end_op(nand);
-}
-
-static int docg4_write_page_raw(struct mtd_info *mtd, struct nand_chip *nand,
- const uint8_t *buf, int oob_required, int page)
-{
- return write_page(mtd, nand, buf, page, false);
-}
-
-static int docg4_write_page(struct mtd_info *mtd, struct nand_chip *nand,
- const uint8_t *buf, int oob_required, int page)
-{
- return write_page(mtd, nand, buf, page, true);
-}
-
-static int docg4_write_oob(struct mtd_info *mtd, struct nand_chip *nand,
- int page)
-{
- /*
- * Writing oob-only is not really supported, because MLC nand must write
- * oob bytes at the same time as page data. Nonetheless, we save the
- * oob buffer contents here, and then write it along with the page data
- * if the same page is subsequently written. This allows user space
- * utilities that write the oob data prior to the page data to work
- * (e.g., nandwrite). The disdvantage is that, if the intention was to
- * write oob only, the operation is quietly ignored. Also, oob can get
- * corrupted if two concurrent processes are running nandwrite.
- */
-
- /* note that bytes 7..14 are hw generated hamming/ecc and overwritten */
- struct docg4_priv *doc = nand_get_controller_data(nand);
- doc->oob_page = page;
- memcpy(doc->oob_buf, nand->oob_poi, 16);
- return 0;
-}
-
-static int __init read_factory_bbt(struct mtd_info *mtd)
-{
- /*
- * The device contains a read-only factory bad block table. Read it and
- * update the memory-based bbt accordingly.
- */
-
- struct nand_chip *nand = mtd_to_nand(mtd);
- struct docg4_priv *doc = nand_get_controller_data(nand);
- uint32_t g4_addr = mtd_to_docg4_address(DOCG4_FACTORY_BBT_PAGE, 0);
- uint8_t *buf;
- int i, block;
- __u32 eccfailed_stats = mtd->ecc_stats.failed;
-
- buf = kzalloc(DOCG4_PAGE_SIZE, GFP_KERNEL);
- if (buf == NULL)
- return -ENOMEM;
-
- read_page_prologue(mtd, g4_addr);
- docg4_read_page(mtd, nand, buf, 0, DOCG4_FACTORY_BBT_PAGE);
-
- /*
- * If no memory-based bbt was created, exit. This will happen if module
- * parameter ignore_badblocks is set. Then why even call this function?
- * For an unknown reason, block erase always fails if it's the first
- * operation after device power-up. The above read ensures it never is.
- * Ugly, I know.
- */
- if (nand->bbt == NULL) /* no memory-based bbt */
- goto exit;
-
- if (mtd->ecc_stats.failed > eccfailed_stats) {
- /*
- * Whoops, an ecc failure ocurred reading the factory bbt.
- * It is stored redundantly, so we get another chance.
- */
- eccfailed_stats = mtd->ecc_stats.failed;
- docg4_read_page(mtd, nand, buf, 0, DOCG4_REDUNDANT_BBT_PAGE);
- if (mtd->ecc_stats.failed > eccfailed_stats) {
- dev_warn(doc->dev,
- "The factory bbt could not be read!\n");
- goto exit;
- }
- }
-
- /*
- * Parse factory bbt and update memory-based bbt. Factory bbt format is
- * simple: one bit per block, block numbers increase left to right (msb
- * to lsb). Bit clear means bad block.
- */
- for (i = block = 0; block < DOCG4_NUMBLOCKS; block += 8, i++) {
- int bitnum;
- unsigned long bits = ~buf[i];
- for_each_set_bit(bitnum, &bits, 8) {
- int badblock = block + 7 - bitnum;
- nand->bbt[badblock / 4] |=
- 0x03 << ((badblock % 4) * 2);
- mtd->ecc_stats.badblocks++;
- dev_notice(doc->dev, "factory-marked bad block: %d\n",
- badblock);
- }
- }
- exit:
- kfree(buf);
- return 0;
-}
-
-static int docg4_block_markbad(struct mtd_info *mtd, loff_t ofs)
-{
- /*
- * Mark a block as bad. Bad blocks are marked in the oob area of the
- * first page of the block. The default scan_bbt() in the nand
- * infrastructure code works fine for building the memory-based bbt
- * during initialization, as does the nand infrastructure function that
- * checks if a block is bad by reading the bbt. This function replaces
- * the nand default because writes to oob-only are not supported.
- */
-
- int ret, i;
- uint8_t *buf;
- struct nand_chip *nand = mtd_to_nand(mtd);
- struct docg4_priv *doc = nand_get_controller_data(nand);
- struct nand_bbt_descr *bbtd = nand->badblock_pattern;
- int page = (int)(ofs >> nand->page_shift);
- uint32_t g4_addr = mtd_to_docg4_address(page, 0);
-
- dev_dbg(doc->dev, "%s: %08llx\n", __func__, ofs);
-
- if (unlikely(ofs & (DOCG4_BLOCK_SIZE - 1)))
- dev_warn(doc->dev, "%s: ofs %llx not start of block!\n",
- __func__, ofs);
-
- /* allocate blank buffer for page data */
- buf = kzalloc(DOCG4_PAGE_SIZE, GFP_KERNEL);
- if (buf == NULL)
- return -ENOMEM;
-
- /* write bit-wise negation of pattern to oob buffer */
- memset(nand->oob_poi, 0xff, mtd->oobsize);
- for (i = 0; i < bbtd->len; i++)
- nand->oob_poi[bbtd->offs + i] = ~bbtd->pattern[i];
-
- /* write first page of block */
- write_page_prologue(mtd, g4_addr);
- docg4_write_page(mtd, nand, buf, 1, page);
- ret = pageprog(mtd);
-
- kfree(buf);
-
- return ret;
-}
-
-static int docg4_block_neverbad(struct mtd_info *mtd, loff_t ofs)
-{
- /* only called when module_param ignore_badblocks is set */
- return 0;
-}
-
-static int docg4_suspend(struct platform_device *pdev, pm_message_t state)
-{
- /*
- * Put the device into "deep power-down" mode. Note that CE# must be
- * deasserted for this to take effect. The xscale, e.g., can be
- * configured to float this signal when the processor enters power-down,
- * and a suitable pull-up ensures its deassertion.
- */
-
- int i;
- uint8_t pwr_down;
- struct docg4_priv *doc = platform_get_drvdata(pdev);
- void __iomem *docptr = doc->virtadr;
-
- dev_dbg(doc->dev, "%s...\n", __func__);
-
- /* poll the register that tells us we're ready to go to sleep */
- for (i = 0; i < 10; i++) {
- pwr_down = readb(docptr + DOC_POWERMODE);
- if (pwr_down & DOC_POWERDOWN_READY)
- break;
- usleep_range(1000, 4000);
- }
-
- if (pwr_down & DOC_POWERDOWN_READY) {
- dev_err(doc->dev, "suspend failed; "
- "timeout polling DOC_POWERDOWN_READY\n");
- return -EIO;
- }
-
- writew(DOC_ASICMODE_POWERDOWN | DOC_ASICMODE_MDWREN,
- docptr + DOC_ASICMODE);
- writew(~(DOC_ASICMODE_POWERDOWN | DOC_ASICMODE_MDWREN),
- docptr + DOC_ASICMODECONFIRM);
-
- write_nop(docptr);
-
- return 0;
-}
-
-static int docg4_resume(struct platform_device *pdev)
-{
-
- /*
- * Exit power-down. Twelve consecutive reads of the address below
- * accomplishes this, assuming CE# has been asserted.
- */
-
- struct docg4_priv *doc = platform_get_drvdata(pdev);
- void __iomem *docptr = doc->virtadr;
- int i;
-
- dev_dbg(doc->dev, "%s...\n", __func__);
-
- for (i = 0; i < 12; i++)
- readb(docptr + 0x1fff);
-
- return 0;
-}
-
-static void __init init_mtd_structs(struct mtd_info *mtd)
-{
- /* initialize mtd and nand data structures */
-
- /*
- * Note that some of the following initializations are not usually
- * required within a nand driver because they are performed by the nand
- * infrastructure code as part of nand_scan(). In this case they need
- * to be initialized here because we skip call to nand_scan_ident() (the
- * first half of nand_scan()). The call to nand_scan_ident() could be
- * skipped because for this device the chip id is not read in the manner
- * of a standard nand device.
- */
-
- struct nand_chip *nand = mtd_to_nand(mtd);
- struct docg4_priv *doc = nand_get_controller_data(nand);
-
- mtd->size = DOCG4_CHIP_SIZE;
- mtd->name = "Msys_Diskonchip_G4";
- mtd->writesize = DOCG4_PAGE_SIZE;
- mtd->erasesize = DOCG4_BLOCK_SIZE;
- mtd->oobsize = DOCG4_OOB_SIZE;
- mtd_set_ooblayout(mtd, &docg4_ooblayout_ops);
- nand->chipsize = DOCG4_CHIP_SIZE;
- nand->chip_shift = DOCG4_CHIP_SHIFT;
- nand->bbt_erase_shift = nand->phys_erase_shift = DOCG4_ERASE_SHIFT;
- nand->chip_delay = 20;
- nand->page_shift = DOCG4_PAGE_SHIFT;
- nand->pagemask = 0x3ffff;
- nand->badblockpos = NAND_LARGE_BADBLOCK_POS;
- nand->badblockbits = 8;
- nand->ecc.mode = NAND_ECC_HW_SYNDROME;
- nand->ecc.size = DOCG4_PAGE_SIZE;
- nand->ecc.prepad = 8;
- nand->ecc.bytes = 8;
- nand->ecc.strength = DOCG4_T;
- nand->options = NAND_BUSWIDTH_16 | NAND_NO_SUBPAGE_WRITE;
- nand->IO_ADDR_R = nand->IO_ADDR_W = doc->virtadr + DOC_IOSPACE_DATA;
- nand->controller = &nand->dummy_controller;
- nand_controller_init(nand->controller);
-
- /* methods */
- nand->cmdfunc = docg4_command;
- nand->waitfunc = docg4_wait;
- nand->select_chip = docg4_select_chip;
- nand->read_byte = docg4_read_byte;
- nand->block_markbad = docg4_block_markbad;
- nand->read_buf = docg4_read_buf;
- nand->write_buf = docg4_write_buf16;
- nand->erase = docg4_erase_block;
- nand->set_features = nand_get_set_features_notsupp;
- nand->get_features = nand_get_set_features_notsupp;
- nand->ecc.read_page = docg4_read_page;
- nand->ecc.write_page = docg4_write_page;
- nand->ecc.read_page_raw = docg4_read_page_raw;
- nand->ecc.write_page_raw = docg4_write_page_raw;
- nand->ecc.read_oob = docg4_read_oob;
- nand->ecc.write_oob = docg4_write_oob;
-
- /*
- * The way the nand infrastructure code is written, a memory-based bbt
- * is not created if NAND_SKIP_BBTSCAN is set. With no memory bbt,
- * nand->block_bad() is used. So when ignoring bad blocks, we skip the
- * scan and define a dummy block_bad() which always returns 0.
- */
- if (ignore_badblocks) {
- nand->options |= NAND_SKIP_BBTSCAN;
- nand->block_bad = docg4_block_neverbad;
- }
-
-}
-
-static int __init read_id_reg(struct mtd_info *mtd)
-{
- struct nand_chip *nand = mtd_to_nand(mtd);
- struct docg4_priv *doc = nand_get_controller_data(nand);
- void __iomem *docptr = doc->virtadr;
- uint16_t id1, id2;
-
- /* check for presence of g4 chip by reading id registers */
- id1 = readw(docptr + DOC_CHIPID);
- id1 = readw(docptr + DOCG4_MYSTERY_REG);
- id2 = readw(docptr + DOC_CHIPID_INV);
- id2 = readw(docptr + DOCG4_MYSTERY_REG);
-
- if (id1 == DOCG4_IDREG1_VALUE && id2 == DOCG4_IDREG2_VALUE) {
- dev_info(doc->dev,
- "NAND device: 128MiB Diskonchip G4 detected\n");
- return 0;
- }
-
- return -ENODEV;
-}
-
-static char const *part_probes[] = { "cmdlinepart", "saftlpart", NULL };
-
-static int docg4_attach_chip(struct nand_chip *chip)
-{
- struct mtd_info *mtd = nand_to_mtd(chip);
- struct docg4_priv *doc = (struct docg4_priv *)(chip + 1);
- int ret;
-
- init_mtd_structs(mtd);
-
- /* Initialize kernel BCH algorithm */
- doc->bch = init_bch(DOCG4_M, DOCG4_T, DOCG4_PRIMITIVE_POLY);
- if (!doc->bch)
- return -EINVAL;
-
- reset(mtd);
-
- ret = read_id_reg(mtd);
- if (ret)
- free_bch(doc->bch);
-
- return ret;
-}
-
-static void docg4_detach_chip(struct nand_chip *chip)
-{
- struct docg4_priv *doc = (struct docg4_priv *)(chip + 1);
-
- free_bch(doc->bch);
-}
-
-static const struct nand_controller_ops docg4_controller_ops = {
- .attach_chip = docg4_attach_chip,
- .detach_chip = docg4_detach_chip,
-};
-
-static int __init probe_docg4(struct platform_device *pdev)
-{
- struct mtd_info *mtd;
- struct nand_chip *nand;
- void __iomem *virtadr;
- struct docg4_priv *doc;
- int len, retval;
- struct resource *r;
- struct device *dev = &pdev->dev;
-
- r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (r == NULL) {
- dev_err(dev, "no io memory resource defined!\n");
- return -ENODEV;
- }
-
- virtadr = ioremap(r->start, resource_size(r));
- if (!virtadr) {
- dev_err(dev, "Diskonchip ioremap failed: %pR\n", r);
- return -EIO;
- }
-
- len = sizeof(struct nand_chip) + sizeof(struct docg4_priv);
- nand = kzalloc(len, GFP_KERNEL);
- if (nand == NULL) {
- retval = -ENOMEM;
- goto unmap;
- }
-
- mtd = nand_to_mtd(nand);
- doc = (struct docg4_priv *) (nand + 1);
- nand_set_controller_data(nand, doc);
- mtd->dev.parent = &pdev->dev;
- doc->virtadr = virtadr;
- doc->dev = dev;
- platform_set_drvdata(pdev, doc);
-
- /*
- * Running nand_scan() with maxchips == 0 will skip nand_scan_ident(),
- * which is a specific operation with this driver and done in the
- * ->attach_chip callback.
- */
- nand->dummy_controller.ops = &docg4_controller_ops;
- retval = nand_scan(mtd, 0);
- if (retval)
- goto free_nand;
-
- retval = read_factory_bbt(mtd);
- if (retval)
- goto cleanup_nand;
-
- retval = mtd_device_parse_register(mtd, part_probes, NULL, NULL, 0);
- if (retval)
- goto cleanup_nand;
-
- doc->mtd = mtd;
-
- return 0;
-
-cleanup_nand:
- nand_cleanup(nand);
-free_nand:
- kfree(nand);
-unmap:
- iounmap(virtadr);
-
- return retval;
-}
-
-static int __exit cleanup_docg4(struct platform_device *pdev)
-{
- struct docg4_priv *doc = platform_get_drvdata(pdev);
- nand_release(doc->mtd);
- kfree(mtd_to_nand(doc->mtd));
- iounmap(doc->virtadr);
- return 0;
-}
-
-static struct platform_driver docg4_driver = {
- .driver = {
- .name = "docg4",
- },
- .suspend = docg4_suspend,
- .resume = docg4_resume,
- .remove = __exit_p(cleanup_docg4),
-};
-
-module_platform_driver_probe(docg4_driver, probe_docg4);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mike Dunn");
-MODULE_DESCRIPTION("M-Systems DiskOnChip G4 device driver");
diff --git a/drivers/mtd/nand/raw/fsl_elbc_nand.c b/drivers/mtd/nand/raw/fsl_elbc_nand.c
index 55f449b711fd..d6ed697fcfe6 100644
--- a/drivers/mtd/nand/raw/fsl_elbc_nand.c
+++ b/drivers/mtd/nand/raw/fsl_elbc_nand.c
@@ -317,10 +317,10 @@ static void fsl_elbc_do_read(struct nand_chip *chip, int oob)
}
/* cmdfunc send commands to the FCM */
-static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
+static void fsl_elbc_cmdfunc(struct nand_chip *chip, unsigned int command,
int column, int page_addr)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
struct fsl_lbc_ctrl *ctrl = priv->ctrl;
struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand;
@@ -533,7 +533,7 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
}
}
-static void fsl_elbc_select_chip(struct mtd_info *mtd, int chip)
+static void fsl_elbc_select_chip(struct nand_chip *chip, int cs)
{
/* The hardware does not seem to support multiple
* chips per bank.
@@ -543,9 +543,9 @@ static void fsl_elbc_select_chip(struct mtd_info *mtd, int chip)
/*
* Write buf to the FCM Controller Data Buffer
*/
-static void fsl_elbc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
+static void fsl_elbc_write_buf(struct nand_chip *chip, const u8 *buf, int len)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
unsigned int bufsize = mtd->writesize + mtd->oobsize;
@@ -581,9 +581,8 @@ static void fsl_elbc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
* read a byte from either the FCM hardware buffer if it has any data left
* otherwise issue a command to read a single byte.
*/
-static u8 fsl_elbc_read_byte(struct mtd_info *mtd)
+static u8 fsl_elbc_read_byte(struct nand_chip *chip)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
@@ -598,9 +597,8 @@ static u8 fsl_elbc_read_byte(struct mtd_info *mtd)
/*
* Read from the FCM Controller Data Buffer
*/
-static void fsl_elbc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
+static void fsl_elbc_read_buf(struct nand_chip *chip, u8 *buf, int len)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
int avail;
@@ -623,7 +621,7 @@ static void fsl_elbc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
/* This function is called after Program and Erase Operations to
* check for success or failure.
*/
-static int fsl_elbc_wait(struct mtd_info *mtd, struct nand_chip *chip)
+static int fsl_elbc_wait(struct nand_chip *chip)
{
struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
@@ -660,8 +658,8 @@ static int fsl_elbc_attach_chip(struct nand_chip *chip)
chip->chipsize);
dev_dbg(priv->dev, "fsl_elbc_init: nand->pagemask = %8x\n",
chip->pagemask);
- dev_dbg(priv->dev, "fsl_elbc_init: nand->chip_delay = %d\n",
- chip->chip_delay);
+ dev_dbg(priv->dev, "fsl_elbc_init: nand->legacy.chip_delay = %d\n",
+ chip->legacy.chip_delay);
dev_dbg(priv->dev, "fsl_elbc_init: nand->badblockpos = %d\n",
chip->badblockpos);
dev_dbg(priv->dev, "fsl_elbc_init: nand->chip_shift = %d\n",
@@ -710,18 +708,19 @@ static const struct nand_controller_ops fsl_elbc_controller_ops = {
.attach_chip = fsl_elbc_attach_chip,
};
-static int fsl_elbc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
- uint8_t *buf, int oob_required, int page)
+static int fsl_elbc_read_page(struct nand_chip *chip, uint8_t *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
struct fsl_lbc_ctrl *ctrl = priv->ctrl;
struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand;
nand_read_page_op(chip, page, 0, buf, mtd->writesize);
if (oob_required)
- fsl_elbc_read_buf(mtd, chip->oob_poi, mtd->oobsize);
+ fsl_elbc_read_buf(chip, chip->oob_poi, mtd->oobsize);
- if (fsl_elbc_wait(mtd, chip) & NAND_STATUS_FAIL)
+ if (fsl_elbc_wait(chip) & NAND_STATUS_FAIL)
mtd->ecc_stats.failed++;
return elbc_fcm_ctrl->max_bitflips;
@@ -730,11 +729,13 @@ static int fsl_elbc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
/* ECC will be calculated automatically, and errors will be detected in
* waitfunc.
*/
-static int fsl_elbc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
- const uint8_t *buf, int oob_required, int page)
+static int fsl_elbc_write_page(struct nand_chip *chip, const uint8_t *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize);
- fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
+ fsl_elbc_write_buf(chip, chip->oob_poi, mtd->oobsize);
return nand_prog_page_end_op(chip);
}
@@ -742,13 +743,15 @@ static int fsl_elbc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
/* ECC will be calculated automatically, and errors will be detected in
* waitfunc.
*/
-static int fsl_elbc_write_subpage(struct mtd_info *mtd, struct nand_chip *chip,
- uint32_t offset, uint32_t data_len,
- const uint8_t *buf, int oob_required, int page)
+static int fsl_elbc_write_subpage(struct nand_chip *chip, uint32_t offset,
+ uint32_t data_len, const uint8_t *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
nand_prog_page_begin_op(chip, page, 0, NULL, 0);
- fsl_elbc_write_buf(mtd, buf, mtd->writesize);
- fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
+ fsl_elbc_write_buf(chip, buf, mtd->writesize);
+ fsl_elbc_write_buf(chip, chip->oob_poi, mtd->oobsize);
return nand_prog_page_end_op(chip);
}
@@ -773,14 +776,14 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv)
/* fill in nand_chip structure */
/* set up function call table */
- chip->read_byte = fsl_elbc_read_byte;
- chip->write_buf = fsl_elbc_write_buf;
- chip->read_buf = fsl_elbc_read_buf;
+ chip->legacy.read_byte = fsl_elbc_read_byte;
+ chip->legacy.write_buf = fsl_elbc_write_buf;
+ chip->legacy.read_buf = fsl_elbc_read_buf;
chip->select_chip = fsl_elbc_select_chip;
- chip->cmdfunc = fsl_elbc_cmdfunc;
- chip->waitfunc = fsl_elbc_wait;
- chip->set_features = nand_get_set_features_notsupp;
- chip->get_features = nand_get_set_features_notsupp;
+ chip->legacy.cmdfunc = fsl_elbc_cmdfunc;
+ chip->legacy.waitfunc = fsl_elbc_wait;
+ chip->legacy.set_features = nand_get_set_features_notsupp;
+ chip->legacy.get_features = nand_get_set_features_notsupp;
chip->bbt_td = &bbt_main_descr;
chip->bbt_md = &bbt_mirror_descr;
@@ -915,7 +918,7 @@ static int fsl_elbc_nand_probe(struct platform_device *pdev)
goto err;
priv->chip.controller->ops = &fsl_elbc_controller_ops;
- ret = nand_scan(mtd, 1);
+ ret = nand_scan(&priv->chip, 1);
if (ret)
goto err;
@@ -942,9 +945,8 @@ static int fsl_elbc_nand_remove(struct platform_device *pdev)
{
struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = fsl_lbc_ctrl_dev->nand;
struct fsl_elbc_mtd *priv = dev_get_drvdata(&pdev->dev);
- struct mtd_info *mtd = nand_to_mtd(&priv->chip);
- nand_release(mtd);
+ nand_release(&priv->chip);
fsl_elbc_chip_remove(priv);
mutex_lock(&fsl_elbc_nand_mutex);
diff --git a/drivers/mtd/nand/raw/fsl_ifc_nand.c b/drivers/mtd/nand/raw/fsl_ifc_nand.c
index 24f59d0066af..6f4afc44381a 100644
--- a/drivers/mtd/nand/raw/fsl_ifc_nand.c
+++ b/drivers/mtd/nand/raw/fsl_ifc_nand.c
@@ -30,6 +30,7 @@
#include <linux/mtd/partitions.h>
#include <linux/mtd/nand_ecc.h>
#include <linux/fsl_ifc.h>
+#include <linux/iopoll.h>
#define ERR_BYTE 0xFF /* Value returned for read
bytes when read failed */
@@ -300,9 +301,9 @@ static void fsl_ifc_do_read(struct nand_chip *chip,
}
/* cmdfunc send commands to the IFC NAND Machine */
-static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command,
- int column, int page_addr) {
- struct nand_chip *chip = mtd_to_nand(mtd);
+static void fsl_ifc_cmdfunc(struct nand_chip *chip, unsigned int command,
+ int column, int page_addr) {
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
struct fsl_ifc_ctrl *ctrl = priv->ctrl;
struct fsl_ifc_runtime __iomem *ifc = ctrl->rregs;
@@ -508,7 +509,7 @@ static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command,
}
}
-static void fsl_ifc_select_chip(struct mtd_info *mtd, int chip)
+static void fsl_ifc_select_chip(struct nand_chip *chip, int cs)
{
/* The hardware does not seem to support multiple
* chips per bank.
@@ -518,9 +519,9 @@ static void fsl_ifc_select_chip(struct mtd_info *mtd, int chip)
/*
* Write buf to the IFC NAND Controller Data Buffer
*/
-static void fsl_ifc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
+static void fsl_ifc_write_buf(struct nand_chip *chip, const u8 *buf, int len)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
unsigned int bufsize = mtd->writesize + mtd->oobsize;
@@ -544,9 +545,8 @@ static void fsl_ifc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
* Read a byte from either the IFC hardware buffer
* read function for 8-bit buswidth
*/
-static uint8_t fsl_ifc_read_byte(struct mtd_info *mtd)
+static uint8_t fsl_ifc_read_byte(struct nand_chip *chip)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
unsigned int offset;
@@ -567,9 +567,8 @@ static uint8_t fsl_ifc_read_byte(struct mtd_info *mtd)
* Read two bytes from the IFC hardware buffer
* read function for 16-bit buswith
*/
-static uint8_t fsl_ifc_read_byte16(struct mtd_info *mtd)
+static uint8_t fsl_ifc_read_byte16(struct nand_chip *chip)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
uint16_t data;
@@ -590,9 +589,8 @@ static uint8_t fsl_ifc_read_byte16(struct mtd_info *mtd)
/*
* Read from the IFC Controller Data Buffer
*/
-static void fsl_ifc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
+static void fsl_ifc_read_buf(struct nand_chip *chip, u8 *buf, int len)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
int avail;
@@ -616,8 +614,9 @@ static void fsl_ifc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
* This function is called after Program and Erase Operations to
* check for success or failure.
*/
-static int fsl_ifc_wait(struct mtd_info *mtd, struct nand_chip *chip)
+static int fsl_ifc_wait(struct nand_chip *chip)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
struct fsl_ifc_ctrl *ctrl = priv->ctrl;
struct fsl_ifc_runtime __iomem *ifc = ctrl->rregs;
@@ -678,20 +677,21 @@ static int check_erased_page(struct nand_chip *chip, u8 *buf)
return bitflips;
}
-static int fsl_ifc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
- uint8_t *buf, int oob_required, int page)
+static int fsl_ifc_read_page(struct nand_chip *chip, uint8_t *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
struct fsl_ifc_ctrl *ctrl = priv->ctrl;
struct fsl_ifc_nand_ctrl *nctrl = ifc_nand_ctrl;
nand_read_page_op(chip, page, 0, buf, mtd->writesize);
if (oob_required)
- fsl_ifc_read_buf(mtd, chip->oob_poi, mtd->oobsize);
+ fsl_ifc_read_buf(chip, chip->oob_poi, mtd->oobsize);
if (ctrl->nand_stat & IFC_NAND_EVTER_STAT_ECCER) {
if (!oob_required)
- fsl_ifc_read_buf(mtd, chip->oob_poi, mtd->oobsize);
+ fsl_ifc_read_buf(chip, chip->oob_poi, mtd->oobsize);
return check_erased_page(chip, buf);
}
@@ -705,11 +705,13 @@ static int fsl_ifc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
/* ECC will be calculated automatically, and errors will be detected in
* waitfunc.
*/
-static int fsl_ifc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
- const uint8_t *buf, int oob_required, int page)
+static int fsl_ifc_write_page(struct nand_chip *chip, const uint8_t *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize);
- fsl_ifc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
+ fsl_ifc_write_buf(chip, chip->oob_poi, mtd->oobsize);
return nand_prog_page_end_op(chip);
}
@@ -725,8 +727,8 @@ static int fsl_ifc_attach_chip(struct nand_chip *chip)
chip->chipsize);
dev_dbg(priv->dev, "%s: nand->pagemask = %8x\n", __func__,
chip->pagemask);
- dev_dbg(priv->dev, "%s: nand->chip_delay = %d\n", __func__,
- chip->chip_delay);
+ dev_dbg(priv->dev, "%s: nand->legacy.chip_delay = %d\n", __func__,
+ chip->legacy.chip_delay);
dev_dbg(priv->dev, "%s: nand->badblockpos = %d\n", __func__,
chip->badblockpos);
dev_dbg(priv->dev, "%s: nand->chip_shift = %d\n", __func__,
@@ -761,7 +763,7 @@ static const struct nand_controller_ops fsl_ifc_controller_ops = {
.attach_chip = fsl_ifc_attach_chip,
};
-static void fsl_ifc_sram_init(struct fsl_ifc_mtd *priv)
+static int fsl_ifc_sram_init(struct fsl_ifc_mtd *priv)
{
struct fsl_ifc_ctrl *ctrl = priv->ctrl;
struct fsl_ifc_runtime __iomem *ifc_runtime = ctrl->rregs;
@@ -769,6 +771,27 @@ static void fsl_ifc_sram_init(struct fsl_ifc_mtd *priv)
uint32_t csor = 0, csor_8k = 0, csor_ext = 0;
uint32_t cs = priv->bank;
+ if (ctrl->version < FSL_IFC_VERSION_1_1_0)
+ return 0;
+
+ if (ctrl->version > FSL_IFC_VERSION_1_1_0) {
+ u32 ncfgr, status;
+ int ret;
+
+ /* Trigger auto initialization */
+ ncfgr = ifc_in32(&ifc_runtime->ifc_nand.ncfgr);
+ ifc_out32(ncfgr | IFC_NAND_NCFGR_SRAM_INIT_EN, &ifc_runtime->ifc_nand.ncfgr);
+
+ /* Wait until done */
+ ret = readx_poll_timeout(ifc_in32, &ifc_runtime->ifc_nand.ncfgr,
+ status, !(status & IFC_NAND_NCFGR_SRAM_INIT_EN),
+ 10, IFC_TIMEOUT_MSECS * 1000);
+ if (ret)
+ dev_err(priv->dev, "Failed to initialize SRAM!\n");
+
+ return ret;
+ }
+
/* Save CSOR and CSOR_ext */
csor = ifc_in32(&ifc_global->csor_cs[cs].csor);
csor_ext = ifc_in32(&ifc_global->csor_cs[cs].csor_ext);
@@ -805,12 +828,16 @@ static void fsl_ifc_sram_init(struct fsl_ifc_mtd *priv)
wait_event_timeout(ctrl->nand_wait, ctrl->nand_stat,
msecs_to_jiffies(IFC_TIMEOUT_MSECS));
- if (ctrl->nand_stat != IFC_NAND_EVTER_STAT_OPC)
+ if (ctrl->nand_stat != IFC_NAND_EVTER_STAT_OPC) {
pr_err("fsl-ifc: Failed to Initialise SRAM\n");
+ return -ETIMEDOUT;
+ }
/* Restore CSOR and CSOR_ext */
ifc_out32(csor, &ifc_global->csor_cs[cs].csor);
ifc_out32(csor_ext, &ifc_global->csor_cs[cs].csor_ext);
+
+ return 0;
}
static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
@@ -821,6 +848,7 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
struct nand_chip *chip = &priv->chip;
struct mtd_info *mtd = nand_to_mtd(&priv->chip);
u32 csor;
+ int ret;
/* Fill in fsl_ifc_mtd structure */
mtd->dev.parent = priv->dev;
@@ -830,17 +858,17 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
/* set up function call table */
if ((ifc_in32(&ifc_global->cspr_cs[priv->bank].cspr))
& CSPR_PORT_SIZE_16)
- chip->read_byte = fsl_ifc_read_byte16;
+ chip->legacy.read_byte = fsl_ifc_read_byte16;
else
- chip->read_byte = fsl_ifc_read_byte;
+ chip->legacy.read_byte = fsl_ifc_read_byte;
- chip->write_buf = fsl_ifc_write_buf;
- chip->read_buf = fsl_ifc_read_buf;
+ chip->legacy.write_buf = fsl_ifc_write_buf;
+ chip->legacy.read_buf = fsl_ifc_read_buf;
chip->select_chip = fsl_ifc_select_chip;
- chip->cmdfunc = fsl_ifc_cmdfunc;
- chip->waitfunc = fsl_ifc_wait;
- chip->set_features = nand_get_set_features_notsupp;
- chip->get_features = nand_get_set_features_notsupp;
+ chip->legacy.cmdfunc = fsl_ifc_cmdfunc;
+ chip->legacy.waitfunc = fsl_ifc_wait;
+ chip->legacy.set_features = nand_get_set_features_notsupp;
+ chip->legacy.get_features = nand_get_set_features_notsupp;
chip->bbt_td = &bbt_main_descr;
chip->bbt_md = &bbt_mirror_descr;
@@ -853,10 +881,10 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
if (ifc_in32(&ifc_global->cspr_cs[priv->bank].cspr)
& CSPR_PORT_SIZE_16) {
- chip->read_byte = fsl_ifc_read_byte16;
+ chip->legacy.read_byte = fsl_ifc_read_byte16;
chip->options |= NAND_BUSWIDTH_16;
} else {
- chip->read_byte = fsl_ifc_read_byte;
+ chip->legacy.read_byte = fsl_ifc_read_byte;
}
chip->controller = &ifc_nand_ctrl->controller;
@@ -914,8 +942,9 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
chip->ecc.algo = NAND_ECC_HAMMING;
}
- if (ctrl->version >= FSL_IFC_VERSION_1_1_0)
- fsl_ifc_sram_init(priv);
+ ret = fsl_ifc_sram_init(priv);
+ if (ret)
+ return ret;
/*
* As IFC version 2.0.0 has 16KB of internal SRAM as compared to older
@@ -1051,7 +1080,7 @@ static int fsl_ifc_nand_probe(struct platform_device *dev)
goto err;
priv->chip.controller->ops = &fsl_ifc_controller_ops;
- ret = nand_scan(mtd, 1);
+ ret = nand_scan(&priv->chip, 1);
if (ret)
goto err;
@@ -1077,9 +1106,8 @@ err:
static int fsl_ifc_nand_remove(struct platform_device *dev)
{
struct fsl_ifc_mtd *priv = dev_get_drvdata(&dev->dev);
- struct mtd_info *mtd = nand_to_mtd(&priv->chip);
- nand_release(mtd);
+ nand_release(&priv->chip);
fsl_ifc_chip_remove(priv);
mutex_lock(&fsl_ifc_nand_mutex);
diff --git a/drivers/mtd/nand/raw/fsl_upm.c b/drivers/mtd/nand/raw/fsl_upm.c
index a88e2cf66e0f..673c5a0c9345 100644
--- a/drivers/mtd/nand/raw/fsl_upm.c
+++ b/drivers/mtd/nand/raw/fsl_upm.c
@@ -52,9 +52,9 @@ static inline struct fsl_upm_nand *to_fsl_upm_nand(struct mtd_info *mtdinfo)
chip);
}
-static int fun_chip_ready(struct mtd_info *mtd)
+static int fun_chip_ready(struct nand_chip *chip)
{
- struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd);
+ struct fsl_upm_nand *fun = to_fsl_upm_nand(nand_to_mtd(chip));
if (gpio_get_value(fun->rnb_gpio[fun->mchip_number]))
return 1;
@@ -69,7 +69,7 @@ static void fun_wait_rnb(struct fsl_upm_nand *fun)
struct mtd_info *mtd = nand_to_mtd(&fun->chip);
int cnt = 1000000;
- while (--cnt && !fun_chip_ready(mtd))
+ while (--cnt && !fun_chip_ready(&fun->chip))
cpu_relax();
if (!cnt)
dev_err(fun->dev, "tired waiting for RNB\n");
@@ -78,10 +78,9 @@ static void fun_wait_rnb(struct fsl_upm_nand *fun)
}
}
-static void fun_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+static void fun_cmd_ctrl(struct nand_chip *chip, int cmd, unsigned int ctrl)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
- struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd);
+ struct fsl_upm_nand *fun = to_fsl_upm_nand(nand_to_mtd(chip));
u32 mar;
if (!(ctrl & fun->last_ctrl)) {
@@ -102,51 +101,50 @@ static void fun_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
mar = (cmd << (32 - fun->upm.width)) |
fun->mchip_offsets[fun->mchip_number];
- fsl_upm_run_pattern(&fun->upm, chip->IO_ADDR_R, mar);
+ fsl_upm_run_pattern(&fun->upm, chip->legacy.IO_ADDR_R, mar);
if (fun->wait_flags & FSL_UPM_WAIT_RUN_PATTERN)
fun_wait_rnb(fun);
}
-static void fun_select_chip(struct mtd_info *mtd, int mchip_nr)
+static void fun_select_chip(struct nand_chip *chip, int mchip_nr)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
- struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd);
+ struct fsl_upm_nand *fun = to_fsl_upm_nand(nand_to_mtd(chip));
if (mchip_nr == -1) {
- chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE);
+ chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE);
} else if (mchip_nr >= 0 && mchip_nr < NAND_MAX_CHIPS) {
fun->mchip_number = mchip_nr;
- chip->IO_ADDR_R = fun->io_base + fun->mchip_offsets[mchip_nr];
- chip->IO_ADDR_W = chip->IO_ADDR_R;
+ chip->legacy.IO_ADDR_R = fun->io_base + fun->mchip_offsets[mchip_nr];
+ chip->legacy.IO_ADDR_W = chip->legacy.IO_ADDR_R;
} else {
BUG();
}
}
-static uint8_t fun_read_byte(struct mtd_info *mtd)
+static uint8_t fun_read_byte(struct nand_chip *chip)
{
- struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd);
+ struct fsl_upm_nand *fun = to_fsl_upm_nand(nand_to_mtd(chip));
- return in_8(fun->chip.IO_ADDR_R);
+ return in_8(fun->chip.legacy.IO_ADDR_R);
}
-static void fun_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+static void fun_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
{
- struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd);
+ struct fsl_upm_nand *fun = to_fsl_upm_nand(nand_to_mtd(chip));
int i;
for (i = 0; i < len; i++)
- buf[i] = in_8(fun->chip.IO_ADDR_R);
+ buf[i] = in_8(fun->chip.legacy.IO_ADDR_R);
}
-static void fun_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+static void fun_write_buf(struct nand_chip *chip, const uint8_t *buf, int len)
{
- struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd);
+ struct fsl_upm_nand *fun = to_fsl_upm_nand(nand_to_mtd(chip));
int i;
for (i = 0; i < len; i++) {
- out_8(fun->chip.IO_ADDR_W, buf[i]);
+ out_8(fun->chip.legacy.IO_ADDR_W, buf[i]);
if (fun->wait_flags & FSL_UPM_WAIT_WRITE_BYTE)
fun_wait_rnb(fun);
}
@@ -162,20 +160,20 @@ static int fun_chip_init(struct fsl_upm_nand *fun,
int ret;
struct device_node *flash_np;
- fun->chip.IO_ADDR_R = fun->io_base;
- fun->chip.IO_ADDR_W = fun->io_base;
- fun->chip.cmd_ctrl = fun_cmd_ctrl;
- fun->chip.chip_delay = fun->chip_delay;
- fun->chip.read_byte = fun_read_byte;
- fun->chip.read_buf = fun_read_buf;
- fun->chip.write_buf = fun_write_buf;
+ fun->chip.legacy.IO_ADDR_R = fun->io_base;
+ fun->chip.legacy.IO_ADDR_W = fun->io_base;
+ fun->chip.legacy.cmd_ctrl = fun_cmd_ctrl;
+ fun->chip.legacy.chip_delay = fun->chip_delay;
+ fun->chip.legacy.read_byte = fun_read_byte;
+ fun->chip.legacy.read_buf = fun_read_buf;
+ fun->chip.legacy.write_buf = fun_write_buf;
fun->chip.ecc.mode = NAND_ECC_SOFT;
fun->chip.ecc.algo = NAND_ECC_HAMMING;
if (fun->mchip_count > 1)
fun->chip.select_chip = fun_select_chip;
if (fun->rnb_gpio[0] >= 0)
- fun->chip.dev_ready = fun_chip_ready;
+ fun->chip.legacy.dev_ready = fun_chip_ready;
mtd->dev.parent = fun->dev;
@@ -184,14 +182,14 @@ static int fun_chip_init(struct fsl_upm_nand *fun,
return -ENODEV;
nand_set_flash_node(&fun->chip, flash_np);
- mtd->name = kasprintf(GFP_KERNEL, "0x%llx.%s", (u64)io_res->start,
- flash_np->name);
+ mtd->name = kasprintf(GFP_KERNEL, "0x%llx.%pOFn", (u64)io_res->start,
+ flash_np);
if (!mtd->name) {
ret = -ENOMEM;
goto err;
}
- ret = nand_scan(mtd, fun->mchip_count);
+ ret = nand_scan(&fun->chip, fun->mchip_count);
if (ret)
goto err;
@@ -326,7 +324,7 @@ static int fun_remove(struct platform_device *ofdev)
struct mtd_info *mtd = nand_to_mtd(&fun->chip);
int i;
- nand_release(mtd);
+ nand_release(&fun->chip);
kfree(mtd->name);
for (i = 0; i < fun->mchip_count; i++) {
diff --git a/drivers/mtd/nand/raw/fsmc_nand.c b/drivers/mtd/nand/raw/fsmc_nand.c
index f418236fa020..70ac8d875218 100644
--- a/drivers/mtd/nand/raw/fsmc_nand.c
+++ b/drivers/mtd/nand/raw/fsmc_nand.c
@@ -340,10 +340,9 @@ static int fsmc_calc_timings(struct fsmc_nand_data *host,
return 0;
}
-static int fsmc_setup_data_interface(struct mtd_info *mtd, int csline,
+static int fsmc_setup_data_interface(struct nand_chip *nand, int csline,
const struct nand_data_interface *conf)
{
- struct nand_chip *nand = mtd_to_nand(mtd);
struct fsmc_nand_data *host = nand_get_controller_data(nand);
struct fsmc_nand_timings tims;
const struct nand_sdr_timings *sdrt;
@@ -368,9 +367,9 @@ static int fsmc_setup_data_interface(struct mtd_info *mtd, int csline,
/*
* fsmc_enable_hwecc - Enables Hardware ECC through FSMC registers
*/
-static void fsmc_enable_hwecc(struct mtd_info *mtd, int mode)
+static void fsmc_enable_hwecc(struct nand_chip *chip, int mode)
{
- struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
+ struct fsmc_nand_data *host = mtd_to_fsmc(nand_to_mtd(chip));
writel_relaxed(readl(host->regs_va + FSMC_PC) & ~FSMC_ECCPLEN_256,
host->regs_va + FSMC_PC);
@@ -385,10 +384,10 @@ static void fsmc_enable_hwecc(struct mtd_info *mtd, int mode)
* FSMC. ECC is 13 bytes for 512 bytes of data (supports error correction up to
* max of 8-bits)
*/
-static int fsmc_read_hwecc_ecc4(struct mtd_info *mtd, const uint8_t *data,
+static int fsmc_read_hwecc_ecc4(struct nand_chip *chip, const uint8_t *data,
uint8_t *ecc)
{
- struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
+ struct fsmc_nand_data *host = mtd_to_fsmc(nand_to_mtd(chip));
uint32_t ecc_tmp;
unsigned long deadline = jiffies + FSMC_BUSY_WAIT_TIMEOUT;
@@ -433,10 +432,10 @@ static int fsmc_read_hwecc_ecc4(struct mtd_info *mtd, const uint8_t *data,
* FSMC. ECC is 3 bytes for 512 bytes of data (supports error correction up to
* max of 1-bit)
*/
-static int fsmc_read_hwecc_ecc1(struct mtd_info *mtd, const uint8_t *data,
+static int fsmc_read_hwecc_ecc1(struct nand_chip *chip, const uint8_t *data,
uint8_t *ecc)
{
- struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
+ struct fsmc_nand_data *host = mtd_to_fsmc(nand_to_mtd(chip));
uint32_t ecc_tmp;
ecc_tmp = readl_relaxed(host->regs_va + ECC1);
@@ -610,9 +609,9 @@ static void fsmc_write_buf_dma(struct mtd_info *mtd, const uint8_t *buf,
}
/* fsmc_select_chip - assert or deassert nCE */
-static void fsmc_select_chip(struct mtd_info *mtd, int chipnr)
+static void fsmc_select_chip(struct nand_chip *chip, int chipnr)
{
- struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
+ struct fsmc_nand_data *host = mtd_to_fsmc(nand_to_mtd(chip));
u32 pc;
/* Support only one CS */
@@ -707,7 +706,6 @@ static int fsmc_exec_op(struct nand_chip *chip, const struct nand_operation *op,
/*
* fsmc_read_page_hwecc
- * @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: buffer to store read data
* @oob_required: caller expects OOB data read to chip->oob_poi
@@ -719,9 +717,10 @@ static int fsmc_exec_op(struct nand_chip *chip, const struct nand_operation *op,
* After this read, fsmc hardware generates and reports error data bits(up to a
* max of 8 bits)
*/
-static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
- uint8_t *buf, int oob_required, int page)
+static int fsmc_read_page_hwecc(struct nand_chip *chip, uint8_t *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
int i, j, s, stat, eccsize = chip->ecc.size;
int eccbytes = chip->ecc.bytes;
int eccsteps = chip->ecc.steps;
@@ -740,7 +739,7 @@ static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
for (i = 0, s = 0; s < eccsteps; s++, i += eccbytes, p += eccsize) {
nand_read_page_op(chip, page, s * eccsize, NULL, 0);
- chip->ecc.hwctl(mtd, NAND_ECC_READ);
+ chip->ecc.hwctl(chip, NAND_ECC_READ);
nand_read_data_op(chip, p, eccsize, false);
for (j = 0; j < eccbytes;) {
@@ -767,9 +766,9 @@ static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
}
memcpy(&ecc_code[i], oob, chip->ecc.bytes);
- chip->ecc.calculate(mtd, p, &ecc_calc[i]);
+ chip->ecc.calculate(chip, p, &ecc_calc[i]);
- stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
+ stat = chip->ecc.correct(chip, p, &ecc_code[i], &ecc_calc[i]);
if (stat < 0) {
mtd->ecc_stats.failed++;
} else {
@@ -791,11 +790,10 @@ static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
* calc_ecc is a 104 bit information containing maximum of 8 error
* offset informations of 13 bits each in 512 bytes of read data.
*/
-static int fsmc_bch8_correct_data(struct mtd_info *mtd, uint8_t *dat,
- uint8_t *read_ecc, uint8_t *calc_ecc)
+static int fsmc_bch8_correct_data(struct nand_chip *chip, uint8_t *dat,
+ uint8_t *read_ecc, uint8_t *calc_ecc)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
- struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
+ struct fsmc_nand_data *host = mtd_to_fsmc(nand_to_mtd(chip));
uint32_t err_idx[8];
uint32_t num_err, i;
uint32_t ecc1, ecc2, ecc3, ecc4;
@@ -951,6 +949,7 @@ static int fsmc_nand_attach_chip(struct nand_chip *nand)
nand->ecc.correct = nand_correct_data;
nand->ecc.bytes = 3;
nand->ecc.strength = 1;
+ nand->ecc.options |= NAND_ECC_SOFT_HAMMING_SM_ORDER;
break;
case NAND_ECC_SOFT:
@@ -1082,7 +1081,6 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
mtd->dev.parent = &pdev->dev;
nand->exec_op = fsmc_exec_op;
nand->select_chip = fsmc_select_chip;
- nand->chip_delay = 30;
/*
* Setup default ECC mode. nand_dt_init() called from nand_scan_ident()
@@ -1125,7 +1123,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
* Scan to find existence of the device
*/
nand->dummy_controller.ops = &fsmc_nand_controller_ops;
- ret = nand_scan(mtd, 1);
+ ret = nand_scan(nand, 1);
if (ret)
goto release_dma_write_chan;
@@ -1161,7 +1159,7 @@ static int fsmc_nand_remove(struct platform_device *pdev)
struct fsmc_nand_data *host = platform_get_drvdata(pdev);
if (host) {
- nand_release(nand_to_mtd(&host->nand));
+ nand_release(&host->nand);
if (host->mode == USE_DMA_ACCESS) {
dma_release_channel(host->write_dma_chan);
diff --git a/drivers/mtd/nand/raw/gpio.c b/drivers/mtd/nand/raw/gpio.c
index 2780af26d9ab..a6c9a824a7d4 100644
--- a/drivers/mtd/nand/raw/gpio.c
+++ b/drivers/mtd/nand/raw/gpio.c
@@ -73,9 +73,10 @@ static void gpio_nand_dosync(struct gpiomtd *gpiomtd)
static inline void gpio_nand_dosync(struct gpiomtd *gpiomtd) {}
#endif
-static void gpio_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+static void gpio_nand_cmd_ctrl(struct nand_chip *chip, int cmd,
+ unsigned int ctrl)
{
- struct gpiomtd *gpiomtd = gpio_nand_getpriv(mtd);
+ struct gpiomtd *gpiomtd = gpio_nand_getpriv(nand_to_mtd(chip));
gpio_nand_dosync(gpiomtd);
@@ -89,13 +90,13 @@ static void gpio_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
if (cmd == NAND_CMD_NONE)
return;
- writeb(cmd, gpiomtd->nand_chip.IO_ADDR_W);
+ writeb(cmd, gpiomtd->nand_chip.legacy.IO_ADDR_W);
gpio_nand_dosync(gpiomtd);
}
-static int gpio_nand_devready(struct mtd_info *mtd)
+static int gpio_nand_devready(struct nand_chip *chip)
{
- struct gpiomtd *gpiomtd = gpio_nand_getpriv(mtd);
+ struct gpiomtd *gpiomtd = gpio_nand_getpriv(nand_to_mtd(chip));
return gpiod_get_value(gpiomtd->rdy);
}
@@ -194,7 +195,7 @@ static int gpio_nand_remove(struct platform_device *pdev)
{
struct gpiomtd *gpiomtd = platform_get_drvdata(pdev);
- nand_release(nand_to_mtd(&gpiomtd->nand_chip));
+ nand_release(&gpiomtd->nand_chip);
/* Enable write protection and disable the chip */
if (gpiomtd->nwp && !IS_ERR(gpiomtd->nwp))
@@ -224,9 +225,9 @@ static int gpio_nand_probe(struct platform_device *pdev)
chip = &gpiomtd->nand_chip;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- chip->IO_ADDR_R = devm_ioremap_resource(dev, res);
- if (IS_ERR(chip->IO_ADDR_R))
- return PTR_ERR(chip->IO_ADDR_R);
+ chip->legacy.IO_ADDR_R = devm_ioremap_resource(dev, res);
+ if (IS_ERR(chip->legacy.IO_ADDR_R))
+ return PTR_ERR(chip->legacy.IO_ADDR_R);
res = gpio_nand_get_io_sync(pdev);
if (res) {
@@ -270,15 +271,15 @@ static int gpio_nand_probe(struct platform_device *pdev)
}
/* Using RDY pin */
if (gpiomtd->rdy)
- chip->dev_ready = gpio_nand_devready;
+ chip->legacy.dev_ready = gpio_nand_devready;
nand_set_flash_node(chip, pdev->dev.of_node);
- chip->IO_ADDR_W = chip->IO_ADDR_R;
+ chip->legacy.IO_ADDR_W = chip->legacy.IO_ADDR_R;
chip->ecc.mode = NAND_ECC_SOFT;
chip->ecc.algo = NAND_ECC_HAMMING;
chip->options = gpiomtd->plat.options;
- chip->chip_delay = gpiomtd->plat.chip_delay;
- chip->cmd_ctrl = gpio_nand_cmd_ctrl;
+ chip->legacy.chip_delay = gpiomtd->plat.chip_delay;
+ chip->legacy.cmd_ctrl = gpio_nand_cmd_ctrl;
mtd = nand_to_mtd(chip);
mtd->dev.parent = dev;
@@ -289,7 +290,7 @@ static int gpio_nand_probe(struct platform_device *pdev)
if (gpiomtd->nwp && !IS_ERR(gpiomtd->nwp))
gpiod_direction_output(gpiomtd->nwp, 1);
- ret = nand_scan(mtd, 1);
+ ret = nand_scan(chip, 1);
if (ret)
goto err_wp;
diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c
index 88ea2203e263..bd4cfac6b5aa 100644
--- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c
+++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c
@@ -471,10 +471,9 @@ void gpmi_nfc_apply_timings(struct gpmi_nand_data *this)
udelay(dll_wait_time_us);
}
-int gpmi_setup_data_interface(struct mtd_info *mtd, int chipnr,
+int gpmi_setup_data_interface(struct nand_chip *chip, int chipnr,
const struct nand_data_interface *conf)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct gpmi_nand_data *this = nand_get_controller_data(chip);
const struct nand_sdr_timings *sdr;
diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c
index 1c1ebbc82824..94c2b7525c85 100644
--- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c
+++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c
@@ -783,9 +783,8 @@ error_alloc:
return -ENOMEM;
}
-static void gpmi_cmd_ctrl(struct mtd_info *mtd, int data, unsigned int ctrl)
+static void gpmi_cmd_ctrl(struct nand_chip *chip, int data, unsigned int ctrl)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct gpmi_nand_data *this = nand_get_controller_data(chip);
int ret;
@@ -817,17 +816,15 @@ static void gpmi_cmd_ctrl(struct mtd_info *mtd, int data, unsigned int ctrl)
this->command_length = 0;
}
-static int gpmi_dev_ready(struct mtd_info *mtd)
+static int gpmi_dev_ready(struct nand_chip *chip)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct gpmi_nand_data *this = nand_get_controller_data(chip);
return gpmi_is_ready(this, this->current_chip);
}
-static void gpmi_select_chip(struct mtd_info *mtd, int chipnr)
+static void gpmi_select_chip(struct nand_chip *chip, int chipnr)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct gpmi_nand_data *this = nand_get_controller_data(chip);
int ret;
@@ -859,9 +856,8 @@ static void gpmi_select_chip(struct mtd_info *mtd, int chipnr)
this->current_chip = chipnr;
}
-static void gpmi_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+static void gpmi_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct gpmi_nand_data *this = nand_get_controller_data(chip);
dev_dbg(this->dev, "len is %d\n", len);
@@ -869,9 +865,8 @@ static void gpmi_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
gpmi_read_data(this, buf, len);
}
-static void gpmi_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+static void gpmi_write_buf(struct nand_chip *chip, const uint8_t *buf, int len)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct gpmi_nand_data *this = nand_get_controller_data(chip);
dev_dbg(this->dev, "len is %d\n", len);
@@ -879,13 +874,12 @@ static void gpmi_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
gpmi_send_data(this, buf, len);
}
-static uint8_t gpmi_read_byte(struct mtd_info *mtd)
+static uint8_t gpmi_read_byte(struct nand_chip *chip)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct gpmi_nand_data *this = nand_get_controller_data(chip);
uint8_t *buf = this->data_buffer_dma;
- gpmi_read_buf(mtd, buf, 1);
+ gpmi_read_buf(chip, buf, 1);
return buf[0];
}
@@ -1085,8 +1079,8 @@ static int gpmi_ecc_read_page_data(struct nand_chip *chip,
return max_bitflips;
}
-static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
- uint8_t *buf, int oob_required, int page)
+static int gpmi_ecc_read_page(struct nand_chip *chip, uint8_t *buf,
+ int oob_required, int page)
{
nand_read_page_op(chip, page, 0, NULL, 0);
@@ -1094,8 +1088,8 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
}
/* Fake a virtual small page for the subpage read */
-static int gpmi_ecc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
- uint32_t offs, uint32_t len, uint8_t *buf, int page)
+static int gpmi_ecc_read_subpage(struct nand_chip *chip, uint32_t offs,
+ uint32_t len, uint8_t *buf, int page)
{
struct gpmi_nand_data *this = nand_get_controller_data(chip);
void __iomem *bch_regs = this->resources.bch_regs;
@@ -1130,7 +1124,7 @@ static int gpmi_ecc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
dev_dbg(this->dev,
"page:%d, first:%d, last:%d, marker at:%d\n",
page, first, last, marker_pos);
- return gpmi_ecc_read_page(mtd, chip, buf, 0, page);
+ return gpmi_ecc_read_page(chip, buf, 0, page);
}
}
@@ -1182,9 +1176,10 @@ static int gpmi_ecc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
return max_bitflips;
}
-static int gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
- const uint8_t *buf, int oob_required, int page)
+static int gpmi_ecc_write_page(struct nand_chip *chip, const uint8_t *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct gpmi_nand_data *this = nand_get_controller_data(chip);
struct bch_geometry *nfc_geo = &this->bch_geometry;
const void *payload_virt;
@@ -1324,9 +1319,9 @@ exit_auxiliary:
* ECC-based or raw view of the page is implicit in which function it calls
* (there is a similar pair of ECC-based/raw functions for writing).
*/
-static int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
- int page)
+static int gpmi_ecc_read_oob(struct nand_chip *chip, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct gpmi_nand_data *this = nand_get_controller_data(chip);
dev_dbg(this->dev, "page number is %d\n", page);
@@ -1335,7 +1330,7 @@ static int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
/* Read out the conventional OOB. */
nand_read_page_op(chip, page, mtd->writesize, NULL, 0);
- chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+ chip->legacy.read_buf(chip, chip->oob_poi, mtd->oobsize);
/*
* Now, we want to make sure the block mark is correct. In the
@@ -1345,15 +1340,15 @@ static int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
if (GPMI_IS_MX23(this)) {
/* Read the block mark into the first byte of the OOB buffer. */
nand_read_page_op(chip, page, 0, NULL, 0);
- chip->oob_poi[0] = chip->read_byte(mtd);
+ chip->oob_poi[0] = chip->legacy.read_byte(chip);
}
return 0;
}
-static int
-gpmi_ecc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, int page)
+static int gpmi_ecc_write_oob(struct nand_chip *chip, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct mtd_oob_region of = { };
/* Do we have available oob area? */
@@ -1380,10 +1375,10 @@ gpmi_ecc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, int page)
* See set_geometry_by_ecc_info inline comments to have a full description
* of the layout used by the GPMI controller.
*/
-static int gpmi_ecc_read_page_raw(struct mtd_info *mtd,
- struct nand_chip *chip, uint8_t *buf,
+static int gpmi_ecc_read_page_raw(struct nand_chip *chip, uint8_t *buf,
int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct gpmi_nand_data *this = nand_get_controller_data(chip);
struct bch_geometry *nfc_geo = &this->bch_geometry;
int eccsize = nfc_geo->ecc_chunk_size;
@@ -1464,11 +1459,10 @@ static int gpmi_ecc_read_page_raw(struct mtd_info *mtd,
* See set_geometry_by_ecc_info inline comments to have a full description
* of the layout used by the GPMI controller.
*/
-static int gpmi_ecc_write_page_raw(struct mtd_info *mtd,
- struct nand_chip *chip,
- const uint8_t *buf,
+static int gpmi_ecc_write_page_raw(struct nand_chip *chip, const uint8_t *buf,
int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct gpmi_nand_data *this = nand_get_controller_data(chip);
struct bch_geometry *nfc_geo = &this->bch_geometry;
int eccsize = nfc_geo->ecc_chunk_size;
@@ -1536,28 +1530,26 @@ static int gpmi_ecc_write_page_raw(struct mtd_info *mtd,
mtd->writesize + mtd->oobsize);
}
-static int gpmi_ecc_read_oob_raw(struct mtd_info *mtd, struct nand_chip *chip,
- int page)
+static int gpmi_ecc_read_oob_raw(struct nand_chip *chip, int page)
{
- return gpmi_ecc_read_page_raw(mtd, chip, NULL, 1, page);
+ return gpmi_ecc_read_page_raw(chip, NULL, 1, page);
}
-static int gpmi_ecc_write_oob_raw(struct mtd_info *mtd, struct nand_chip *chip,
- int page)
+static int gpmi_ecc_write_oob_raw(struct nand_chip *chip, int page)
{
- return gpmi_ecc_write_page_raw(mtd, chip, NULL, 1, page);
+ return gpmi_ecc_write_page_raw(chip, NULL, 1, page);
}
-static int gpmi_block_markbad(struct mtd_info *mtd, loff_t ofs)
+static int gpmi_block_markbad(struct nand_chip *chip, loff_t ofs)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct gpmi_nand_data *this = nand_get_controller_data(chip);
int ret = 0;
uint8_t *block_mark;
int column, page, chipnr;
chipnr = (int)(ofs >> chip->chip_shift);
- chip->select_chip(mtd, chipnr);
+ chip->select_chip(chip, chipnr);
column = !GPMI_IS_MX23(this) ? mtd->writesize : 0;
@@ -1570,7 +1562,7 @@ static int gpmi_block_markbad(struct mtd_info *mtd, loff_t ofs)
ret = nand_prog_page_op(chip, page, column, block_mark, 1);
- chip->select_chip(mtd, -1);
+ chip->select_chip(chip, -1);
return ret;
}
@@ -1607,7 +1599,6 @@ static int mx23_check_transcription_stamp(struct gpmi_nand_data *this)
struct boot_rom_geometry *rom_geo = &this->rom_geometry;
struct device *dev = this->dev;
struct nand_chip *chip = &this->nand;
- struct mtd_info *mtd = nand_to_mtd(chip);
unsigned int search_area_size_in_strides;
unsigned int stride;
unsigned int page;
@@ -1619,7 +1610,7 @@ static int mx23_check_transcription_stamp(struct gpmi_nand_data *this)
search_area_size_in_strides = 1 << rom_geo->search_area_stride_exponent;
saved_chip_number = this->current_chip;
- chip->select_chip(mtd, 0);
+ chip->select_chip(chip, 0);
/*
* Loop through the first search area, looking for the NCB fingerprint.
@@ -1637,7 +1628,7 @@ static int mx23_check_transcription_stamp(struct gpmi_nand_data *this)
* and starts in the 12th byte of the page.
*/
nand_read_page_op(chip, page, 12, NULL, 0);
- chip->read_buf(mtd, buffer, strlen(fingerprint));
+ chip->legacy.read_buf(chip, buffer, strlen(fingerprint));
/* Look for the fingerprint. */
if (!memcmp(buffer, fingerprint, strlen(fingerprint))) {
@@ -1647,7 +1638,7 @@ static int mx23_check_transcription_stamp(struct gpmi_nand_data *this)
}
- chip->select_chip(mtd, saved_chip_number);
+ chip->select_chip(chip, saved_chip_number);
if (found_an_ncb_fingerprint)
dev_dbg(dev, "\tFound a fingerprint\n");
@@ -1690,7 +1681,7 @@ static int mx23_write_transcription_stamp(struct gpmi_nand_data *this)
/* Select chip 0. */
saved_chip_number = this->current_chip;
- chip->select_chip(mtd, 0);
+ chip->select_chip(chip, 0);
/* Loop over blocks in the first search area, erasing them. */
dev_dbg(dev, "Erasing the search area...\n");
@@ -1716,13 +1707,13 @@ static int mx23_write_transcription_stamp(struct gpmi_nand_data *this)
/* Write the first page of the current stride. */
dev_dbg(dev, "Writing an NCB fingerprint in page 0x%x\n", page);
- status = chip->ecc.write_page_raw(mtd, chip, buffer, 0, page);
+ status = chip->ecc.write_page_raw(chip, buffer, 0, page);
if (status)
dev_err(dev, "[%s] Write failed.\n", __func__);
}
/* Deselect chip 0. */
- chip->select_chip(mtd, saved_chip_number);
+ chip->select_chip(chip, saved_chip_number);
return 0;
}
@@ -1771,10 +1762,10 @@ static int mx23_boot_init(struct gpmi_nand_data *this)
byte = block << chip->phys_erase_shift;
/* Send the command to read the conventional block mark. */
- chip->select_chip(mtd, chipnr);
+ chip->select_chip(chip, chipnr);
nand_read_page_op(chip, page, mtd->writesize, NULL, 0);
- block_mark = chip->read_byte(mtd);
- chip->select_chip(mtd, -1);
+ block_mark = chip->legacy.read_byte(chip);
+ chip->select_chip(chip, -1);
/*
* Check if the block is marked bad. If so, we need to mark it
@@ -1783,7 +1774,7 @@ static int mx23_boot_init(struct gpmi_nand_data *this)
*/
if (block_mark != 0xff) {
dev_dbg(dev, "Transcribing mark in block %u\n", block);
- ret = chip->block_markbad(mtd, byte);
+ ret = chip->legacy.block_markbad(chip, byte);
if (ret)
dev_err(dev,
"Failed to mark block bad with ret %d\n",
@@ -1911,13 +1902,13 @@ static int gpmi_nand_init(struct gpmi_nand_data *this)
nand_set_flash_node(chip, this->pdev->dev.of_node);
chip->select_chip = gpmi_select_chip;
chip->setup_data_interface = gpmi_setup_data_interface;
- chip->cmd_ctrl = gpmi_cmd_ctrl;
- chip->dev_ready = gpmi_dev_ready;
- chip->read_byte = gpmi_read_byte;
- chip->read_buf = gpmi_read_buf;
- chip->write_buf = gpmi_write_buf;
+ chip->legacy.cmd_ctrl = gpmi_cmd_ctrl;
+ chip->legacy.dev_ready = gpmi_dev_ready;
+ chip->legacy.read_byte = gpmi_read_byte;
+ chip->legacy.read_buf = gpmi_read_buf;
+ chip->legacy.write_buf = gpmi_write_buf;
chip->badblock_pattern = &gpmi_bbt_descr;
- chip->block_markbad = gpmi_block_markbad;
+ chip->legacy.block_markbad = gpmi_block_markbad;
chip->options |= NAND_NO_SUBPAGE_WRITE;
/* Set up swap_block_mark, must be set before the gpmi_set_geometry() */
@@ -1934,7 +1925,7 @@ static int gpmi_nand_init(struct gpmi_nand_data *this)
goto err_out;
chip->dummy_controller.ops = &gpmi_nand_controller_ops;
- ret = nand_scan(mtd, GPMI_IS_MX6(this) ? 2 : 1);
+ ret = nand_scan(chip, GPMI_IS_MX6(this) ? 2 : 1);
if (ret)
goto err_out;
@@ -2026,7 +2017,7 @@ static int gpmi_nand_remove(struct platform_device *pdev)
{
struct gpmi_nand_data *this = platform_get_drvdata(pdev);
- nand_release(nand_to_mtd(&this->nand));
+ nand_release(&this->nand);
gpmi_free_dma_buffer(this);
release_resources(this);
return 0;
diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h
index 69cd0cbde4f2..d0b79bac2728 100644
--- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h
+++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h
@@ -178,7 +178,7 @@ int gpmi_is_ready(struct gpmi_nand_data *, unsigned chip);
int gpmi_send_command(struct gpmi_nand_data *);
int gpmi_enable_clk(struct gpmi_nand_data *this);
int gpmi_disable_clk(struct gpmi_nand_data *this);
-int gpmi_setup_data_interface(struct mtd_info *mtd, int chipnr,
+int gpmi_setup_data_interface(struct nand_chip *chip, int chipnr,
const struct nand_data_interface *conf);
void gpmi_nfc_apply_timings(struct gpmi_nand_data *this);
int gpmi_read_data(struct gpmi_nand_data *, void *buf, int len);
diff --git a/drivers/mtd/nand/raw/hisi504_nand.c b/drivers/mtd/nand/raw/hisi504_nand.c
index 950dc7789296..f043938ee36b 100644
--- a/drivers/mtd/nand/raw/hisi504_nand.c
+++ b/drivers/mtd/nand/raw/hisi504_nand.c
@@ -353,9 +353,8 @@ static int hisi_nfc_send_cmd_reset(struct hinfc_host *host, int chipselect)
return 0;
}
-static void hisi_nfc_select_chip(struct mtd_info *mtd, int chipselect)
+static void hisi_nfc_select_chip(struct nand_chip *chip, int chipselect)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct hinfc_host *host = nand_get_controller_data(chip);
if (chipselect < 0)
@@ -364,9 +363,8 @@ static void hisi_nfc_select_chip(struct mtd_info *mtd, int chipselect)
host->chipselect = chipselect;
}
-static uint8_t hisi_nfc_read_byte(struct mtd_info *mtd)
+static uint8_t hisi_nfc_read_byte(struct nand_chip *chip)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct hinfc_host *host = nand_get_controller_data(chip);
if (host->command == NAND_CMD_STATUS)
@@ -380,28 +378,17 @@ static uint8_t hisi_nfc_read_byte(struct mtd_info *mtd)
return *(uint8_t *)(host->buffer + host->offset - 1);
}
-static u16 hisi_nfc_read_word(struct mtd_info *mtd)
-{
- struct nand_chip *chip = mtd_to_nand(mtd);
- struct hinfc_host *host = nand_get_controller_data(chip);
-
- host->offset += 2;
- return *(u16 *)(host->buffer + host->offset - 2);
-}
-
static void
-hisi_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+hisi_nfc_write_buf(struct nand_chip *chip, const uint8_t *buf, int len)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct hinfc_host *host = nand_get_controller_data(chip);
memcpy(host->buffer + host->offset, buf, len);
host->offset += len;
}
-static void hisi_nfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+static void hisi_nfc_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct hinfc_host *host = nand_get_controller_data(chip);
memcpy(buf, host->buffer + host->offset, len);
@@ -442,10 +429,10 @@ static void set_addr(struct mtd_info *mtd, int column, int page_addr)
}
}
-static void hisi_nfc_cmdfunc(struct mtd_info *mtd, unsigned command, int column,
- int page_addr)
+static void hisi_nfc_cmdfunc(struct nand_chip *chip, unsigned command,
+ int column, int page_addr)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct hinfc_host *host = nand_get_controller_data(chip);
int is_cache_invalid = 1;
unsigned int flag = 0;
@@ -537,15 +524,16 @@ static irqreturn_t hinfc_irq_handle(int irq, void *devid)
return IRQ_HANDLED;
}
-static int hisi_nand_read_page_hwecc(struct mtd_info *mtd,
- struct nand_chip *chip, uint8_t *buf, int oob_required, int page)
+static int hisi_nand_read_page_hwecc(struct nand_chip *chip, uint8_t *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct hinfc_host *host = nand_get_controller_data(chip);
int max_bitflips = 0, stat = 0, stat_max = 0, status_ecc;
int stat_1, stat_2;
nand_read_page_op(chip, page, 0, buf, mtd->writesize);
- chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+ chip->legacy.read_buf(chip, chip->oob_poi, mtd->oobsize);
/* errors which can not be corrected by ECC */
if (host->irq_status & HINFC504_INTS_UE) {
@@ -569,9 +557,9 @@ static int hisi_nand_read_page_hwecc(struct mtd_info *mtd,
return max_bitflips;
}
-static int hisi_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
- int page)
+static int hisi_nand_read_oob(struct nand_chip *chip, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct hinfc_host *host = nand_get_controller_data(chip);
nand_read_oob_op(chip, page, 0, chip->oob_poi, mtd->oobsize);
@@ -585,13 +573,15 @@ static int hisi_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
return 0;
}
-static int hisi_nand_write_page_hwecc(struct mtd_info *mtd,
- struct nand_chip *chip, const uint8_t *buf, int oob_required,
- int page)
+static int hisi_nand_write_page_hwecc(struct nand_chip *chip,
+ const uint8_t *buf, int oob_required,
+ int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize);
if (oob_required)
- chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+ chip->legacy.write_buf(chip, chip->oob_poi, mtd->oobsize);
return nand_prog_page_end_op(chip);
}
@@ -792,15 +782,14 @@ static int hisi_nfc_probe(struct platform_device *pdev)
nand_set_controller_data(chip, host);
nand_set_flash_node(chip, np);
- chip->cmdfunc = hisi_nfc_cmdfunc;
+ chip->legacy.cmdfunc = hisi_nfc_cmdfunc;
chip->select_chip = hisi_nfc_select_chip;
- chip->read_byte = hisi_nfc_read_byte;
- chip->read_word = hisi_nfc_read_word;
- chip->write_buf = hisi_nfc_write_buf;
- chip->read_buf = hisi_nfc_read_buf;
- chip->chip_delay = HINFC504_CHIP_DELAY;
- chip->set_features = nand_get_set_features_notsupp;
- chip->get_features = nand_get_set_features_notsupp;
+ chip->legacy.read_byte = hisi_nfc_read_byte;
+ chip->legacy.write_buf = hisi_nfc_write_buf;
+ chip->legacy.read_buf = hisi_nfc_read_buf;
+ chip->legacy.chip_delay = HINFC504_CHIP_DELAY;
+ chip->legacy.set_features = nand_get_set_features_notsupp;
+ chip->legacy.get_features = nand_get_set_features_notsupp;
hisi_nfc_host_init(host);
@@ -811,7 +800,7 @@ static int hisi_nfc_probe(struct platform_device *pdev)
}
chip->dummy_controller.ops = &hisi_nfc_controller_ops;
- ret = nand_scan(mtd, max_chips);
+ ret = nand_scan(chip, max_chips);
if (ret)
return ret;
@@ -828,9 +817,8 @@ static int hisi_nfc_probe(struct platform_device *pdev)
static int hisi_nfc_remove(struct platform_device *pdev)
{
struct hinfc_host *host = platform_get_drvdata(pdev);
- struct mtd_info *mtd = nand_to_mtd(&host->chip);
- nand_release(mtd);
+ nand_release(&host->chip);
return 0;
}
diff --git a/drivers/mtd/nand/raw/internals.h b/drivers/mtd/nand/raw/internals.h
new file mode 100644
index 000000000000..04c2cf74eff3
--- /dev/null
+++ b/drivers/mtd/nand/raw/internals.h
@@ -0,0 +1,115 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2018 - Bootlin
+ *
+ * Author: Boris Brezillon <boris.brezillon@bootlin.com>
+ *
+ * Header containing internal definitions to be used only by core files.
+ * NAND controller drivers should not include this file.
+ */
+
+#ifndef __LINUX_RAWNAND_INTERNALS
+#define __LINUX_RAWNAND_INTERNALS
+
+#include <linux/mtd/rawnand.h>
+
+/*
+ * NAND Flash Manufacturer ID Codes
+ */
+#define NAND_MFR_AMD 0x01
+#define NAND_MFR_ATO 0x9b
+#define NAND_MFR_EON 0x92
+#define NAND_MFR_ESMT 0xc8
+#define NAND_MFR_FUJITSU 0x04
+#define NAND_MFR_HYNIX 0xad
+#define NAND_MFR_INTEL 0x89
+#define NAND_MFR_MACRONIX 0xc2
+#define NAND_MFR_MICRON 0x2c
+#define NAND_MFR_NATIONAL 0x8f
+#define NAND_MFR_RENESAS 0x07
+#define NAND_MFR_SAMSUNG 0xec
+#define NAND_MFR_SANDISK 0x45
+#define NAND_MFR_STMICRO 0x20
+#define NAND_MFR_TOSHIBA 0x98
+#define NAND_MFR_WINBOND 0xef
+
+/**
+ * struct nand_manufacturer_ops - NAND Manufacturer operations
+ * @detect: detect the NAND memory organization and capabilities
+ * @init: initialize all vendor specific fields (like the ->read_retry()
+ * implementation) if any.
+ * @cleanup: the ->init() function may have allocated resources, ->cleanup()
+ * is here to let vendor specific code release those resources.
+ * @fixup_onfi_param_page: apply vendor specific fixups to the ONFI parameter
+ * page. This is called after the checksum is verified.
+ */
+struct nand_manufacturer_ops {
+ void (*detect)(struct nand_chip *chip);
+ int (*init)(struct nand_chip *chip);
+ void (*cleanup)(struct nand_chip *chip);
+ void (*fixup_onfi_param_page)(struct nand_chip *chip,
+ struct nand_onfi_params *p);
+};
+
+/**
+ * struct nand_manufacturer - NAND Flash Manufacturer structure
+ * @name: Manufacturer name
+ * @id: manufacturer ID code of device.
+ * @ops: manufacturer operations
+ */
+struct nand_manufacturer {
+ int id;
+ char *name;
+ const struct nand_manufacturer_ops *ops;
+};
+
+
+extern struct nand_flash_dev nand_flash_ids[];
+
+extern const struct nand_manufacturer_ops amd_nand_manuf_ops;
+extern const struct nand_manufacturer_ops esmt_nand_manuf_ops;
+extern const struct nand_manufacturer_ops hynix_nand_manuf_ops;
+extern const struct nand_manufacturer_ops macronix_nand_manuf_ops;
+extern const struct nand_manufacturer_ops micron_nand_manuf_ops;
+extern const struct nand_manufacturer_ops samsung_nand_manuf_ops;
+extern const struct nand_manufacturer_ops toshiba_nand_manuf_ops;
+
+/* Core functions */
+const struct nand_manufacturer *nand_get_manufacturer(u8 id);
+int nand_markbad_bbm(struct nand_chip *chip, loff_t ofs);
+int nand_erase_nand(struct nand_chip *chip, struct erase_info *instr,
+ int allowbbt);
+int onfi_fill_data_interface(struct nand_chip *chip,
+ enum nand_data_interface_type type,
+ int timing_mode);
+int nand_get_features(struct nand_chip *chip, int addr, u8 *subfeature_param);
+int nand_set_features(struct nand_chip *chip, int addr, u8 *subfeature_param);
+int nand_read_page_raw_notsupp(struct nand_chip *chip, u8 *buf,
+ int oob_required, int page);
+int nand_write_page_raw_notsupp(struct nand_chip *chip, const u8 *buf,
+ int oob_required, int page);
+int nand_exit_status_op(struct nand_chip *chip);
+int nand_read_param_page_op(struct nand_chip *chip, u8 page, void *buf,
+ unsigned int len);
+void nand_decode_ext_id(struct nand_chip *chip);
+void panic_nand_wait(struct nand_chip *chip, unsigned long timeo);
+void sanitize_string(uint8_t *s, size_t len);
+
+/* BBT functions */
+int nand_markbad_bbt(struct nand_chip *chip, loff_t offs);
+int nand_isreserved_bbt(struct nand_chip *chip, loff_t offs);
+int nand_isbad_bbt(struct nand_chip *chip, loff_t offs, int allowbbt);
+
+/* Legacy */
+void nand_legacy_set_defaults(struct nand_chip *chip);
+void nand_legacy_adjust_cmdfunc(struct nand_chip *chip);
+int nand_legacy_check_hooks(struct nand_chip *chip);
+
+/* ONFI functions */
+u16 onfi_crc16(u16 crc, u8 const *p, size_t len);
+int nand_onfi_detect(struct nand_chip *chip);
+
+/* JEDEC functions */
+int nand_jedec_detect(struct nand_chip *chip);
+
+#endif /* __LINUX_RAWNAND_INTERNALS */
diff --git a/drivers/mtd/nand/raw/jz4740_nand.c b/drivers/mtd/nand/raw/jz4740_nand.c
index a7515452bc59..fb59cfca11a7 100644
--- a/drivers/mtd/nand/raw/jz4740_nand.c
+++ b/drivers/mtd/nand/raw/jz4740_nand.c
@@ -78,10 +78,9 @@ static inline struct jz_nand *mtd_to_jz_nand(struct mtd_info *mtd)
return container_of(mtd_to_nand(mtd), struct jz_nand, chip);
}
-static void jz_nand_select_chip(struct mtd_info *mtd, int chipnr)
+static void jz_nand_select_chip(struct nand_chip *chip, int chipnr)
{
- struct jz_nand *nand = mtd_to_jz_nand(mtd);
- struct nand_chip *chip = mtd_to_nand(mtd);
+ struct jz_nand *nand = mtd_to_jz_nand(nand_to_mtd(chip));
uint32_t ctrl;
int banknr;
@@ -92,18 +91,18 @@ static void jz_nand_select_chip(struct mtd_info *mtd, int chipnr)
banknr = -1;
} else {
banknr = nand->banks[chipnr] - 1;
- chip->IO_ADDR_R = nand->bank_base[banknr];
- chip->IO_ADDR_W = nand->bank_base[banknr];
+ chip->legacy.IO_ADDR_R = nand->bank_base[banknr];
+ chip->legacy.IO_ADDR_W = nand->bank_base[banknr];
}
writel(ctrl, nand->base + JZ_REG_NAND_CTRL);
nand->selected_bank = banknr;
}
-static void jz_nand_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
+static void jz_nand_cmd_ctrl(struct nand_chip *chip, int dat,
+ unsigned int ctrl)
{
- struct jz_nand *nand = mtd_to_jz_nand(mtd);
- struct nand_chip *chip = mtd_to_nand(mtd);
+ struct jz_nand *nand = mtd_to_jz_nand(nand_to_mtd(chip));
uint32_t reg;
void __iomem *bank_base = nand->bank_base[nand->selected_bank];
@@ -115,7 +114,7 @@ static void jz_nand_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
bank_base += JZ_NAND_MEM_ADDR_OFFSET;
else if (ctrl & NAND_CLE)
bank_base += JZ_NAND_MEM_CMD_OFFSET;
- chip->IO_ADDR_W = bank_base;
+ chip->legacy.IO_ADDR_W = bank_base;
reg = readl(nand->base + JZ_REG_NAND_CTRL);
if (ctrl & NAND_NCE)
@@ -125,18 +124,18 @@ static void jz_nand_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
writel(reg, nand->base + JZ_REG_NAND_CTRL);
}
if (dat != NAND_CMD_NONE)
- writeb(dat, chip->IO_ADDR_W);
+ writeb(dat, chip->legacy.IO_ADDR_W);
}
-static int jz_nand_dev_ready(struct mtd_info *mtd)
+static int jz_nand_dev_ready(struct nand_chip *chip)
{
- struct jz_nand *nand = mtd_to_jz_nand(mtd);
+ struct jz_nand *nand = mtd_to_jz_nand(nand_to_mtd(chip));
return gpiod_get_value_cansleep(nand->busy_gpio);
}
-static void jz_nand_hwctl(struct mtd_info *mtd, int mode)
+static void jz_nand_hwctl(struct nand_chip *chip, int mode)
{
- struct jz_nand *nand = mtd_to_jz_nand(mtd);
+ struct jz_nand *nand = mtd_to_jz_nand(nand_to_mtd(chip));
uint32_t reg;
writel(0, nand->base + JZ_REG_NAND_IRQ_STAT);
@@ -162,10 +161,10 @@ static void jz_nand_hwctl(struct mtd_info *mtd, int mode)
writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL);
}
-static int jz_nand_calculate_ecc_rs(struct mtd_info *mtd, const uint8_t *dat,
- uint8_t *ecc_code)
+static int jz_nand_calculate_ecc_rs(struct nand_chip *chip, const uint8_t *dat,
+ uint8_t *ecc_code)
{
- struct jz_nand *nand = mtd_to_jz_nand(mtd);
+ struct jz_nand *nand = mtd_to_jz_nand(nand_to_mtd(chip));
uint32_t reg, status;
int i;
unsigned int timeout = 1000;
@@ -215,10 +214,10 @@ static void jz_nand_correct_data(uint8_t *dat, int index, int mask)
dat[index+1] = (data >> 8) & 0xff;
}
-static int jz_nand_correct_ecc_rs(struct mtd_info *mtd, uint8_t *dat,
- uint8_t *read_ecc, uint8_t *calc_ecc)
+static int jz_nand_correct_ecc_rs(struct nand_chip *chip, uint8_t *dat,
+ uint8_t *read_ecc, uint8_t *calc_ecc)
{
- struct jz_nand *nand = mtd_to_jz_nand(mtd);
+ struct jz_nand *nand = mtd_to_jz_nand(nand_to_mtd(chip));
int i, error_count, index;
uint32_t reg, status, error;
unsigned int timeout = 1000;
@@ -331,19 +330,19 @@ static int jz_nand_detect_bank(struct platform_device *pdev,
if (chipnr == 0) {
/* Detect first chip. */
- ret = nand_scan(mtd, 1);
+ ret = nand_scan(chip, 1);
if (ret)
goto notfound_id;
/* Retrieve the IDs from the first chip. */
- chip->select_chip(mtd, 0);
+ chip->select_chip(chip, 0);
nand_reset_op(chip);
nand_readid_op(chip, 0, id, sizeof(id));
*nand_maf_id = id[0];
*nand_dev_id = id[1];
} else {
/* Detect additional chip. */
- chip->select_chip(mtd, chipnr);
+ chip->select_chip(chip, chipnr);
nand_reset_op(chip);
nand_readid_op(chip, 0, id, sizeof(id));
if (*nand_maf_id != id[0] || *nand_dev_id != id[1]) {
@@ -426,13 +425,13 @@ static int jz_nand_probe(struct platform_device *pdev)
chip->ecc.strength = 4;
chip->ecc.options = NAND_ECC_GENERIC_ERASED_CHECK;
- chip->chip_delay = 50;
- chip->cmd_ctrl = jz_nand_cmd_ctrl;
+ chip->legacy.chip_delay = 50;
+ chip->legacy.cmd_ctrl = jz_nand_cmd_ctrl;
chip->select_chip = jz_nand_select_chip;
chip->dummy_controller.ops = &jz_nand_controller_ops;
if (nand->busy_gpio)
- chip->dev_ready = jz_nand_dev_ready;
+ chip->legacy.dev_ready = jz_nand_dev_ready;
platform_set_drvdata(pdev, nand);
@@ -507,7 +506,7 @@ static int jz_nand_remove(struct platform_device *pdev)
struct jz_nand *nand = platform_get_drvdata(pdev);
size_t i;
- nand_release(nand_to_mtd(&nand->chip));
+ nand_release(&nand->chip);
/* Deassert and disable all chips */
writel(0, nand->base + JZ_REG_NAND_CTRL);
diff --git a/drivers/mtd/nand/raw/jz4780_nand.c b/drivers/mtd/nand/raw/jz4780_nand.c
index db4fa60bd52a..cdf22100ab77 100644
--- a/drivers/mtd/nand/raw/jz4780_nand.c
+++ b/drivers/mtd/nand/raw/jz4780_nand.c
@@ -71,9 +71,9 @@ static inline struct jz4780_nand_controller
return container_of(ctrl, struct jz4780_nand_controller, controller);
}
-static void jz4780_nand_select_chip(struct mtd_info *mtd, int chipnr)
+static void jz4780_nand_select_chip(struct nand_chip *chip, int chipnr)
{
- struct jz4780_nand_chip *nand = to_jz4780_nand_chip(mtd);
+ struct jz4780_nand_chip *nand = to_jz4780_nand_chip(nand_to_mtd(chip));
struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(nand->chip.controller);
struct jz4780_nand_cs *cs;
@@ -86,10 +86,10 @@ static void jz4780_nand_select_chip(struct mtd_info *mtd, int chipnr)
nfc->selected = chipnr;
}
-static void jz4780_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
+static void jz4780_nand_cmd_ctrl(struct nand_chip *chip, int cmd,
unsigned int ctrl)
{
- struct jz4780_nand_chip *nand = to_jz4780_nand_chip(mtd);
+ struct jz4780_nand_chip *nand = to_jz4780_nand_chip(nand_to_mtd(chip));
struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(nand->chip.controller);
struct jz4780_nand_cs *cs;
@@ -109,24 +109,24 @@ static void jz4780_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
writeb(cmd, cs->base + OFFSET_CMD);
}
-static int jz4780_nand_dev_ready(struct mtd_info *mtd)
+static int jz4780_nand_dev_ready(struct nand_chip *chip)
{
- struct jz4780_nand_chip *nand = to_jz4780_nand_chip(mtd);
+ struct jz4780_nand_chip *nand = to_jz4780_nand_chip(nand_to_mtd(chip));
return !gpiod_get_value_cansleep(nand->busy_gpio);
}
-static void jz4780_nand_ecc_hwctl(struct mtd_info *mtd, int mode)
+static void jz4780_nand_ecc_hwctl(struct nand_chip *chip, int mode)
{
- struct jz4780_nand_chip *nand = to_jz4780_nand_chip(mtd);
+ struct jz4780_nand_chip *nand = to_jz4780_nand_chip(nand_to_mtd(chip));
nand->reading = (mode == NAND_ECC_READ);
}
-static int jz4780_nand_ecc_calculate(struct mtd_info *mtd, const u8 *dat,
+static int jz4780_nand_ecc_calculate(struct nand_chip *chip, const u8 *dat,
u8 *ecc_code)
{
- struct jz4780_nand_chip *nand = to_jz4780_nand_chip(mtd);
+ struct jz4780_nand_chip *nand = to_jz4780_nand_chip(nand_to_mtd(chip));
struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(nand->chip.controller);
struct jz4780_bch_params params;
@@ -144,10 +144,10 @@ static int jz4780_nand_ecc_calculate(struct mtd_info *mtd, const u8 *dat,
return jz4780_bch_calculate(nfc->bch, &params, dat, ecc_code);
}
-static int jz4780_nand_ecc_correct(struct mtd_info *mtd, u8 *dat,
+static int jz4780_nand_ecc_correct(struct nand_chip *chip, u8 *dat,
u8 *read_ecc, u8 *calc_ecc)
{
- struct jz4780_nand_chip *nand = to_jz4780_nand_chip(mtd);
+ struct jz4780_nand_chip *nand = to_jz4780_nand_chip(nand_to_mtd(chip));
struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(nand->chip.controller);
struct jz4780_bch_params params;
@@ -256,7 +256,7 @@ static int jz4780_nand_init_chip(struct platform_device *pdev,
dev_err(dev, "failed to request busy GPIO: %d\n", ret);
return ret;
} else if (nand->busy_gpio) {
- nand->chip.dev_ready = jz4780_nand_dev_ready;
+ nand->chip.legacy.dev_ready = jz4780_nand_dev_ready;
}
nand->wp_gpio = devm_gpiod_get_optional(dev, "wp", GPIOD_OUT_LOW);
@@ -275,24 +275,24 @@ static int jz4780_nand_init_chip(struct platform_device *pdev,
return -ENOMEM;
mtd->dev.parent = dev;
- chip->IO_ADDR_R = cs->base + OFFSET_DATA;
- chip->IO_ADDR_W = cs->base + OFFSET_DATA;
- chip->chip_delay = RB_DELAY_US;
+ chip->legacy.IO_ADDR_R = cs->base + OFFSET_DATA;
+ chip->legacy.IO_ADDR_W = cs->base + OFFSET_DATA;
+ chip->legacy.chip_delay = RB_DELAY_US;
chip->options = NAND_NO_SUBPAGE_WRITE;
chip->select_chip = jz4780_nand_select_chip;
- chip->cmd_ctrl = jz4780_nand_cmd_ctrl;
+ chip->legacy.cmd_ctrl = jz4780_nand_cmd_ctrl;
chip->ecc.mode = NAND_ECC_HW;
chip->controller = &nfc->controller;
nand_set_flash_node(chip, np);
chip->controller->ops = &jz4780_nand_controller_ops;
- ret = nand_scan(mtd, 1);
+ ret = nand_scan(chip, 1);
if (ret)
return ret;
ret = mtd_device_register(mtd, NULL, 0);
if (ret) {
- nand_release(mtd);
+ nand_release(chip);
return ret;
}
@@ -307,7 +307,7 @@ static void jz4780_nand_cleanup_chips(struct jz4780_nand_controller *nfc)
while (!list_empty(&nfc->chips)) {
chip = list_first_entry(&nfc->chips, struct jz4780_nand_chip, chip_list);
- nand_release(nand_to_mtd(&chip->chip));
+ nand_release(&chip->chip);
list_del(&chip->chip_list);
}
}
@@ -352,7 +352,7 @@ static int jz4780_nand_probe(struct platform_device *pdev)
return -ENODEV;
}
- nfc = devm_kzalloc(dev, sizeof(*nfc) + (sizeof(nfc->cs[0]) * num_banks), GFP_KERNEL);
+ nfc = devm_kzalloc(dev, struct_size(nfc, cs, num_banks), GFP_KERNEL);
if (!nfc)
return -ENOMEM;
diff --git a/drivers/mtd/nand/raw/lpc32xx_mlc.c b/drivers/mtd/nand/raw/lpc32xx_mlc.c
index e82abada130a..abbb655fe154 100644
--- a/drivers/mtd/nand/raw/lpc32xx_mlc.c
+++ b/drivers/mtd/nand/raw/lpc32xx_mlc.c
@@ -286,10 +286,9 @@ static void lpc32xx_nand_setup(struct lpc32xx_nand_host *host)
/*
* Hardware specific access to control lines
*/
-static void lpc32xx_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
+static void lpc32xx_nand_cmd_ctrl(struct nand_chip *nand_chip, int cmd,
unsigned int ctrl)
{
- struct nand_chip *nand_chip = mtd_to_nand(mtd);
struct lpc32xx_nand_host *host = nand_get_controller_data(nand_chip);
if (cmd != NAND_CMD_NONE) {
@@ -303,9 +302,8 @@ static void lpc32xx_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
/*
* Read Device Ready (NAND device _and_ controller ready)
*/
-static int lpc32xx_nand_device_ready(struct mtd_info *mtd)
+static int lpc32xx_nand_device_ready(struct nand_chip *nand_chip)
{
- struct nand_chip *nand_chip = mtd_to_nand(mtd);
struct lpc32xx_nand_host *host = nand_get_controller_data(nand_chip);
if ((readb(MLC_ISR(host->io_base)) &
@@ -330,8 +328,9 @@ static irqreturn_t lpc3xxx_nand_irq(int irq, struct lpc32xx_nand_host *host)
return IRQ_HANDLED;
}
-static int lpc32xx_waitfunc_nand(struct mtd_info *mtd, struct nand_chip *chip)
+static int lpc32xx_waitfunc_nand(struct nand_chip *chip)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
if (readb(MLC_ISR(host->io_base)) & MLCISR_NAND_READY)
@@ -349,9 +348,9 @@ exit:
return NAND_STATUS_READY;
}
-static int lpc32xx_waitfunc_controller(struct mtd_info *mtd,
- struct nand_chip *chip)
+static int lpc32xx_waitfunc_controller(struct nand_chip *chip)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
if (readb(MLC_ISR(host->io_base)) & MLCISR_CONTROLLER_READY)
@@ -369,10 +368,10 @@ exit:
return NAND_STATUS_READY;
}
-static int lpc32xx_waitfunc(struct mtd_info *mtd, struct nand_chip *chip)
+static int lpc32xx_waitfunc(struct nand_chip *chip)
{
- lpc32xx_waitfunc_nand(mtd, chip);
- lpc32xx_waitfunc_controller(mtd, chip);
+ lpc32xx_waitfunc_nand(chip);
+ lpc32xx_waitfunc_controller(chip);
return NAND_STATUS_READY;
}
@@ -442,9 +441,10 @@ out1:
return -ENXIO;
}
-static int lpc32xx_read_page(struct mtd_info *mtd, struct nand_chip *chip,
- uint8_t *buf, int oob_required, int page)
+static int lpc32xx_read_page(struct nand_chip *chip, uint8_t *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
int i, j;
uint8_t *oobbuf = chip->oob_poi;
@@ -470,7 +470,7 @@ static int lpc32xx_read_page(struct mtd_info *mtd, struct nand_chip *chip,
writeb(0x00, MLC_ECC_AUTO_DEC_REG(host->io_base));
/* Wait for Controller Ready */
- lpc32xx_waitfunc_controller(mtd, chip);
+ lpc32xx_waitfunc_controller(chip);
/* Check ECC Error status */
mlc_isr = readl(MLC_ISR(host->io_base));
@@ -507,11 +507,11 @@ static int lpc32xx_read_page(struct mtd_info *mtd, struct nand_chip *chip,
return 0;
}
-static int lpc32xx_write_page_lowlevel(struct mtd_info *mtd,
- struct nand_chip *chip,
+static int lpc32xx_write_page_lowlevel(struct nand_chip *chip,
const uint8_t *buf, int oob_required,
int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
const uint8_t *oobbuf = chip->oob_poi;
uint8_t *dma_buf = (uint8_t *)buf;
@@ -551,32 +551,30 @@ static int lpc32xx_write_page_lowlevel(struct mtd_info *mtd,
writeb(0x00, MLC_ECC_AUTO_ENC_REG(host->io_base));
/* Wait for Controller Ready */
- lpc32xx_waitfunc_controller(mtd, chip);
+ lpc32xx_waitfunc_controller(chip);
}
return nand_prog_page_end_op(chip);
}
-static int lpc32xx_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
- int page)
+static int lpc32xx_read_oob(struct nand_chip *chip, int page)
{
struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
/* Read whole page - necessary with MLC controller! */
- lpc32xx_read_page(mtd, chip, host->dummy_buf, 1, page);
+ lpc32xx_read_page(chip, host->dummy_buf, 1, page);
return 0;
}
-static int lpc32xx_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
- int page)
+static int lpc32xx_write_oob(struct nand_chip *chip, int page)
{
/* None, write_oob conflicts with the automatic LPC MLC ECC decoder! */
return 0;
}
/* Prepares MLC for transfers with H/W ECC enabled: always enabled anyway */
-static void lpc32xx_ecc_enable(struct mtd_info *mtd, int mode)
+static void lpc32xx_ecc_enable(struct nand_chip *chip, int mode)
{
/* Always enabled! */
}
@@ -741,11 +739,11 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
if (res)
goto put_clk;
- nand_chip->cmd_ctrl = lpc32xx_nand_cmd_ctrl;
- nand_chip->dev_ready = lpc32xx_nand_device_ready;
- nand_chip->chip_delay = 25; /* us */
- nand_chip->IO_ADDR_R = MLC_DATA(host->io_base);
- nand_chip->IO_ADDR_W = MLC_DATA(host->io_base);
+ nand_chip->legacy.cmd_ctrl = lpc32xx_nand_cmd_ctrl;
+ nand_chip->legacy.dev_ready = lpc32xx_nand_device_ready;
+ nand_chip->legacy.chip_delay = 25; /* us */
+ nand_chip->legacy.IO_ADDR_R = MLC_DATA(host->io_base);
+ nand_chip->legacy.IO_ADDR_W = MLC_DATA(host->io_base);
/* Init NAND controller */
lpc32xx_nand_setup(host);
@@ -762,7 +760,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
nand_chip->ecc.read_oob = lpc32xx_read_oob;
nand_chip->ecc.strength = 4;
nand_chip->ecc.bytes = 10;
- nand_chip->waitfunc = lpc32xx_waitfunc;
+ nand_chip->legacy.waitfunc = lpc32xx_waitfunc;
nand_chip->options = NAND_NO_SUBPAGE_WRITE;
nand_chip->bbt_options = NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB;
@@ -802,7 +800,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
* SMALL block or LARGE block.
*/
nand_chip->dummy_controller.ops = &lpc32xx_nand_controller_ops;
- res = nand_scan(mtd, 1);
+ res = nand_scan(nand_chip, 1);
if (res)
goto free_irq;
@@ -839,9 +837,8 @@ free_gpio:
static int lpc32xx_nand_remove(struct platform_device *pdev)
{
struct lpc32xx_nand_host *host = platform_get_drvdata(pdev);
- struct mtd_info *mtd = nand_to_mtd(&host->nand_chip);
- nand_release(mtd);
+ nand_release(&host->nand_chip);
free_irq(host->irq, host);
if (use_dma)
dma_release_channel(host->dma_chan);
diff --git a/drivers/mtd/nand/raw/lpc32xx_slc.c b/drivers/mtd/nand/raw/lpc32xx_slc.c
index a4e8b7e75135..f2f2cdbb9d04 100644
--- a/drivers/mtd/nand/raw/lpc32xx_slc.c
+++ b/drivers/mtd/nand/raw/lpc32xx_slc.c
@@ -278,11 +278,10 @@ static void lpc32xx_nand_setup(struct lpc32xx_nand_host *host)
/*
* Hardware specific access to control lines
*/
-static void lpc32xx_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
- unsigned int ctrl)
+static void lpc32xx_nand_cmd_ctrl(struct nand_chip *chip, int cmd,
+ unsigned int ctrl)
{
uint32_t tmp;
- struct nand_chip *chip = mtd_to_nand(mtd);
struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
/* Does CE state need to be changed? */
@@ -304,9 +303,8 @@ static void lpc32xx_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
/*
* Read the Device Ready pin
*/
-static int lpc32xx_nand_device_ready(struct mtd_info *mtd)
+static int lpc32xx_nand_device_ready(struct nand_chip *chip)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
int rdy = 0;
@@ -337,7 +335,7 @@ static void lpc32xx_wp_disable(struct lpc32xx_nand_host *host)
/*
* Prepares SLC for transfers with H/W ECC enabled
*/
-static void lpc32xx_nand_ecc_enable(struct mtd_info *mtd, int mode)
+static void lpc32xx_nand_ecc_enable(struct nand_chip *chip, int mode)
{
/* Hardware ECC is enabled automatically in hardware as needed */
}
@@ -345,7 +343,7 @@ static void lpc32xx_nand_ecc_enable(struct mtd_info *mtd, int mode)
/*
* Calculates the ECC for the data
*/
-static int lpc32xx_nand_ecc_calculate(struct mtd_info *mtd,
+static int lpc32xx_nand_ecc_calculate(struct nand_chip *chip,
const unsigned char *buf,
unsigned char *code)
{
@@ -359,9 +357,8 @@ static int lpc32xx_nand_ecc_calculate(struct mtd_info *mtd,
/*
* Read a single byte from NAND device
*/
-static uint8_t lpc32xx_nand_read_byte(struct mtd_info *mtd)
+static uint8_t lpc32xx_nand_read_byte(struct nand_chip *chip)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
return (uint8_t)readl(SLC_DATA(host->io_base));
@@ -370,9 +367,8 @@ static uint8_t lpc32xx_nand_read_byte(struct mtd_info *mtd)
/*
* Simple device read without ECC
*/
-static void lpc32xx_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+static void lpc32xx_nand_read_buf(struct nand_chip *chip, u_char *buf, int len)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
/* Direct device read with no ECC */
@@ -383,9 +379,9 @@ static void lpc32xx_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
/*
* Simple device write without ECC
*/
-static void lpc32xx_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+static void lpc32xx_nand_write_buf(struct nand_chip *chip, const uint8_t *buf,
+ int len)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
/* Direct device write with no ECC */
@@ -396,18 +392,20 @@ static void lpc32xx_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int
/*
* Read the OOB data from the device without ECC using FIFO method
*/
-static int lpc32xx_nand_read_oob_syndrome(struct mtd_info *mtd,
- struct nand_chip *chip, int page)
+static int lpc32xx_nand_read_oob_syndrome(struct nand_chip *chip, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
return nand_read_oob_op(chip, page, 0, chip->oob_poi, mtd->oobsize);
}
/*
* Write the OOB data to the device without ECC using FIFO method
*/
-static int lpc32xx_nand_write_oob_syndrome(struct mtd_info *mtd,
- struct nand_chip *chip, int page)
+static int lpc32xx_nand_write_oob_syndrome(struct nand_chip *chip, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
return nand_prog_page_op(chip, page, mtd->writesize, chip->oob_poi,
mtd->oobsize);
}
@@ -610,10 +608,10 @@ static int lpc32xx_xfer(struct mtd_info *mtd, uint8_t *buf, int eccsubpages,
* Read the data and OOB data from the device, use ECC correction with the
* data, disable ECC for the OOB data
*/
-static int lpc32xx_nand_read_page_syndrome(struct mtd_info *mtd,
- struct nand_chip *chip, uint8_t *buf,
+static int lpc32xx_nand_read_page_syndrome(struct nand_chip *chip, uint8_t *buf,
int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
struct mtd_oob_region oobregion = { };
int stat, i, status, error;
@@ -626,7 +624,7 @@ static int lpc32xx_nand_read_page_syndrome(struct mtd_info *mtd,
status = lpc32xx_xfer(mtd, buf, chip->ecc.steps, 1);
/* Get OOB data */
- chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+ chip->legacy.read_buf(chip, chip->oob_poi, mtd->oobsize);
/* Convert to stored ECC format */
lpc32xx_slc_ecc_copy(tmpecc, (uint32_t *) host->ecc_buf, chip->ecc.steps);
@@ -639,7 +637,7 @@ static int lpc32xx_nand_read_page_syndrome(struct mtd_info *mtd,
oobecc = chip->oob_poi + oobregion.offset;
for (i = 0; i < chip->ecc.steps; i++) {
- stat = chip->ecc.correct(mtd, buf, oobecc,
+ stat = chip->ecc.correct(chip, buf, oobecc,
&tmpecc[i * chip->ecc.bytes]);
if (stat < 0)
mtd->ecc_stats.failed++;
@@ -657,17 +655,18 @@ static int lpc32xx_nand_read_page_syndrome(struct mtd_info *mtd,
* Read the data and OOB data from the device, no ECC correction with the
* data or OOB data
*/
-static int lpc32xx_nand_read_page_raw_syndrome(struct mtd_info *mtd,
- struct nand_chip *chip,
+static int lpc32xx_nand_read_page_raw_syndrome(struct nand_chip *chip,
uint8_t *buf, int oob_required,
int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
/* Issue read command */
nand_read_page_op(chip, page, 0, NULL, 0);
/* Raw reads can just use the FIFO interface */
- chip->read_buf(mtd, buf, chip->ecc.size * chip->ecc.steps);
- chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+ chip->legacy.read_buf(chip, buf, chip->ecc.size * chip->ecc.steps);
+ chip->legacy.read_buf(chip, chip->oob_poi, mtd->oobsize);
return 0;
}
@@ -676,11 +675,11 @@ static int lpc32xx_nand_read_page_raw_syndrome(struct mtd_info *mtd,
* Write the data and OOB data to the device, use ECC with the data,
* disable ECC for the OOB data
*/
-static int lpc32xx_nand_write_page_syndrome(struct mtd_info *mtd,
- struct nand_chip *chip,
+static int lpc32xx_nand_write_page_syndrome(struct nand_chip *chip,
const uint8_t *buf,
int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
struct mtd_oob_region oobregion = { };
uint8_t *pb;
@@ -705,7 +704,7 @@ static int lpc32xx_nand_write_page_syndrome(struct mtd_info *mtd,
lpc32xx_slc_ecc_copy(pb, (uint32_t *)host->ecc_buf, chip->ecc.steps);
/* Write ECC data to device */
- chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+ chip->legacy.write_buf(chip, chip->oob_poi, mtd->oobsize);
return nand_prog_page_end_op(chip);
}
@@ -714,15 +713,16 @@ static int lpc32xx_nand_write_page_syndrome(struct mtd_info *mtd,
* Write the data and OOB data to the device, no ECC correction with the
* data or OOB data
*/
-static int lpc32xx_nand_write_page_raw_syndrome(struct mtd_info *mtd,
- struct nand_chip *chip,
+static int lpc32xx_nand_write_page_raw_syndrome(struct nand_chip *chip,
const uint8_t *buf,
int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
/* Raw writes can just use the FIFO interface */
nand_prog_page_begin_op(chip, page, 0, buf,
chip->ecc.size * chip->ecc.steps);
- chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+ chip->legacy.write_buf(chip, chip->oob_poi, mtd->oobsize);
return nand_prog_page_end_op(chip);
}
@@ -878,11 +878,11 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
goto enable_wp;
/* Set NAND IO addresses and command/ready functions */
- chip->IO_ADDR_R = SLC_DATA(host->io_base);
- chip->IO_ADDR_W = SLC_DATA(host->io_base);
- chip->cmd_ctrl = lpc32xx_nand_cmd_ctrl;
- chip->dev_ready = lpc32xx_nand_device_ready;
- chip->chip_delay = 20; /* 20us command delay time */
+ chip->legacy.IO_ADDR_R = SLC_DATA(host->io_base);
+ chip->legacy.IO_ADDR_W = SLC_DATA(host->io_base);
+ chip->legacy.cmd_ctrl = lpc32xx_nand_cmd_ctrl;
+ chip->legacy.dev_ready = lpc32xx_nand_device_ready;
+ chip->legacy.chip_delay = 20; /* 20us command delay time */
/* Init NAND controller */
lpc32xx_nand_setup(host);
@@ -891,9 +891,9 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
/* NAND callbacks for LPC32xx SLC hardware */
chip->ecc.mode = NAND_ECC_HW_SYNDROME;
- chip->read_byte = lpc32xx_nand_read_byte;
- chip->read_buf = lpc32xx_nand_read_buf;
- chip->write_buf = lpc32xx_nand_write_buf;
+ chip->legacy.read_byte = lpc32xx_nand_read_byte;
+ chip->legacy.read_buf = lpc32xx_nand_read_buf;
+ chip->legacy.write_buf = lpc32xx_nand_write_buf;
chip->ecc.read_page_raw = lpc32xx_nand_read_page_raw_syndrome;
chip->ecc.read_page = lpc32xx_nand_read_page_syndrome;
chip->ecc.write_page_raw = lpc32xx_nand_write_page_raw_syndrome;
@@ -925,7 +925,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
/* Find NAND device */
chip->dummy_controller.ops = &lpc32xx_nand_controller_ops;
- res = nand_scan(mtd, 1);
+ res = nand_scan(chip, 1);
if (res)
goto release_dma;
@@ -956,9 +956,8 @@ static int lpc32xx_nand_remove(struct platform_device *pdev)
{
uint32_t tmp;
struct lpc32xx_nand_host *host = platform_get_drvdata(pdev);
- struct mtd_info *mtd = nand_to_mtd(&host->nand_chip);
- nand_release(mtd);
+ nand_release(&host->nand_chip);
dma_release_channel(host->dma_chan);
/* Force CE high */
diff --git a/drivers/mtd/nand/raw/marvell_nand.c b/drivers/mtd/nand/raw/marvell_nand.c
index 7af4d6213ee5..650f2b490a05 100644
--- a/drivers/mtd/nand/raw/marvell_nand.c
+++ b/drivers/mtd/nand/raw/marvell_nand.c
@@ -5,6 +5,73 @@
* Copyright (C) 2017 Marvell
* Author: Miquel RAYNAL <miquel.raynal@free-electrons.com>
*
+ *
+ * This NAND controller driver handles two versions of the hardware,
+ * one is called NFCv1 and is available on PXA SoCs and the other is
+ * called NFCv2 and is available on Armada SoCs.
+ *
+ * The main visible difference is that NFCv1 only has Hamming ECC
+ * capabilities, while NFCv2 also embeds a BCH ECC engine. Also, DMA
+ * is not used with NFCv2.
+ *
+ * The ECC layouts are depicted in details in Marvell AN-379, but here
+ * is a brief description.
+ *
+ * When using Hamming, the data is split in 512B chunks (either 1, 2
+ * or 4) and each chunk will have its own ECC "digest" of 6B at the
+ * beginning of the OOB area and eventually the remaining free OOB
+ * bytes (also called "spare" bytes in the driver). This engine
+ * corrects up to 1 bit per chunk and detects reliably an error if
+ * there are at most 2 bitflips. Here is the page layout used by the
+ * controller when Hamming is chosen:
+ *
+ * +-------------------------------------------------------------+
+ * | Data 1 | ... | Data N | ECC 1 | ... | ECCN | Free OOB bytes |
+ * +-------------------------------------------------------------+
+ *
+ * When using the BCH engine, there are N identical (data + free OOB +
+ * ECC) sections and potentially an extra one to deal with
+ * configurations where the chosen (data + free OOB + ECC) sizes do
+ * not align with the page (data + OOB) size. ECC bytes are always
+ * 30B per ECC chunk. Here is the page layout used by the controller
+ * when BCH is chosen:
+ *
+ * +-----------------------------------------
+ * | Data 1 | Free OOB bytes 1 | ECC 1 | ...
+ * +-----------------------------------------
+ *
+ * -------------------------------------------
+ * ... | Data N | Free OOB bytes N | ECC N |
+ * -------------------------------------------
+ *
+ * --------------------------------------------+
+ * Last Data | Last Free OOB bytes | Last ECC |
+ * --------------------------------------------+
+ *
+ * In both cases, the layout seen by the user is always: all data
+ * first, then all free OOB bytes and finally all ECC bytes. With BCH,
+ * ECC bytes are 30B long and are padded with 0xFF to align on 32
+ * bytes.
+ *
+ * The controller has certain limitations that are handled by the
+ * driver:
+ * - It can only read 2k at a time. To overcome this limitation, the
+ * driver issues data cycles on the bus, without issuing new
+ * CMD + ADDR cycles. The Marvell term is "naked" operations.
+ * - The ECC strength in BCH mode cannot be tuned. It is fixed 16
+ * bits. What can be tuned is the ECC block size as long as it
+ * stays between 512B and 2kiB. It's usually chosen based on the
+ * chip ECC requirements. For instance, using 2kiB ECC chunks
+ * provides 4b/512B correctability.
+ * - The controller will always treat data bytes, free OOB bytes
+ * and ECC bytes in that order, no matter what the real layout is
+ * (which is usually all data then all OOB bytes). The
+ * marvell_nfc_layouts array below contains the currently
+ * supported layouts.
+ * - Because of these weird layouts, the Bad Block Markers can be
+ * located in data section. In this case, the NAND_BBT_NO_OOB_BBM
+ * option must be set to prevent scanning/writing bad block
+ * markers.
*/
#include <linux/module.h>
@@ -217,8 +284,11 @@ static const struct marvell_hw_ecc_layout marvell_nfc_layouts[] = {
MARVELL_LAYOUT( 512, 512, 1, 1, 1, 512, 8, 8, 0, 0, 0),
MARVELL_LAYOUT( 2048, 512, 1, 1, 1, 2048, 40, 24, 0, 0, 0),
MARVELL_LAYOUT( 2048, 512, 4, 1, 1, 2048, 32, 30, 0, 0, 0),
+ MARVELL_LAYOUT( 2048, 512, 8, 2, 1, 1024, 0, 30,1024,32, 30),
MARVELL_LAYOUT( 4096, 512, 4, 2, 2, 2048, 32, 30, 0, 0, 0),
MARVELL_LAYOUT( 4096, 512, 8, 5, 4, 1024, 0, 30, 0, 64, 30),
+ MARVELL_LAYOUT( 8192, 512, 4, 4, 4, 2048, 0, 30, 0, 0, 0),
+ MARVELL_LAYOUT( 8192, 512, 8, 9, 8, 1024, 0, 30, 0, 160, 30),
};
/**
@@ -634,9 +704,8 @@ static int marvell_nfc_wait_op(struct nand_chip *chip, unsigned int timeout_ms)
return 0;
}
-static void marvell_nfc_select_chip(struct mtd_info *mtd, int die_nr)
+static void marvell_nfc_select_chip(struct nand_chip *chip, int die_nr)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct marvell_nand_chip *marvell_nand = to_marvell_nand(chip);
struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
u32 ndcr_generic;
@@ -686,7 +755,7 @@ static irqreturn_t marvell_nfc_isr(int irq, void *dev_id)
marvell_nfc_disable_int(nfc, st & NDCR_ALL_INT);
- if (!(st & (NDSR_RDDREQ | NDSR_WRDREQ | NDSR_WRCMDREQ)))
+ if (st & (NDSR_RDY(0) | NDSR_RDY(1)))
complete(&nfc->complete);
return IRQ_HANDLED;
@@ -959,18 +1028,15 @@ static int marvell_nfc_hw_ecc_hmg_do_read_page(struct nand_chip *chip,
return ret;
}
-static int marvell_nfc_hw_ecc_hmg_read_page_raw(struct mtd_info *mtd,
- struct nand_chip *chip, u8 *buf,
+static int marvell_nfc_hw_ecc_hmg_read_page_raw(struct nand_chip *chip, u8 *buf,
int oob_required, int page)
{
return marvell_nfc_hw_ecc_hmg_do_read_page(chip, buf, chip->oob_poi,
true, page);
}
-static int marvell_nfc_hw_ecc_hmg_read_page(struct mtd_info *mtd,
- struct nand_chip *chip,
- u8 *buf, int oob_required,
- int page)
+static int marvell_nfc_hw_ecc_hmg_read_page(struct nand_chip *chip, u8 *buf,
+ int oob_required, int page)
{
const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
unsigned int full_sz = lt->data_bytes + lt->spare_bytes + lt->ecc_bytes;
@@ -1008,8 +1074,7 @@ static int marvell_nfc_hw_ecc_hmg_read_page(struct mtd_info *mtd,
* it appears before the ECC bytes when reading), the ->read_oob_raw() function
* also stands for ->read_oob().
*/
-static int marvell_nfc_hw_ecc_hmg_read_oob_raw(struct mtd_info *mtd,
- struct nand_chip *chip, int page)
+static int marvell_nfc_hw_ecc_hmg_read_oob_raw(struct nand_chip *chip, int page)
{
/* Invalidate page cache */
chip->pagebuf = -1;
@@ -1073,8 +1138,7 @@ static int marvell_nfc_hw_ecc_hmg_do_write_page(struct nand_chip *chip,
return ret;
}
-static int marvell_nfc_hw_ecc_hmg_write_page_raw(struct mtd_info *mtd,
- struct nand_chip *chip,
+static int marvell_nfc_hw_ecc_hmg_write_page_raw(struct nand_chip *chip,
const u8 *buf,
int oob_required, int page)
{
@@ -1082,8 +1146,7 @@ static int marvell_nfc_hw_ecc_hmg_write_page_raw(struct mtd_info *mtd,
true, page);
}
-static int marvell_nfc_hw_ecc_hmg_write_page(struct mtd_info *mtd,
- struct nand_chip *chip,
+static int marvell_nfc_hw_ecc_hmg_write_page(struct nand_chip *chip,
const u8 *buf,
int oob_required, int page)
{
@@ -1102,10 +1165,11 @@ static int marvell_nfc_hw_ecc_hmg_write_page(struct mtd_info *mtd,
* it appears before the ECC bytes when reading), the ->write_oob_raw() function
* also stands for ->write_oob().
*/
-static int marvell_nfc_hw_ecc_hmg_write_oob_raw(struct mtd_info *mtd,
- struct nand_chip *chip,
+static int marvell_nfc_hw_ecc_hmg_write_oob_raw(struct nand_chip *chip,
int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
/* Invalidate page cache */
chip->pagebuf = -1;
@@ -1116,10 +1180,10 @@ static int marvell_nfc_hw_ecc_hmg_write_oob_raw(struct mtd_info *mtd,
}
/* BCH read helpers */
-static int marvell_nfc_hw_ecc_bch_read_page_raw(struct mtd_info *mtd,
- struct nand_chip *chip, u8 *buf,
+static int marvell_nfc_hw_ecc_bch_read_page_raw(struct nand_chip *chip, u8 *buf,
int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
u8 *oob = chip->oob_poi;
int chunk_size = lt->data_bytes + lt->spare_bytes + lt->ecc_bytes;
@@ -1228,17 +1292,17 @@ static void marvell_nfc_hw_ecc_bch_read_chunk(struct nand_chip *chip, int chunk,
}
}
-static int marvell_nfc_hw_ecc_bch_read_page(struct mtd_info *mtd,
- struct nand_chip *chip,
+static int marvell_nfc_hw_ecc_bch_read_page(struct nand_chip *chip,
u8 *buf, int oob_required,
int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
- int data_len = lt->data_bytes, spare_len = lt->spare_bytes, ecc_len;
- u8 *data = buf, *spare = chip->oob_poi, *ecc;
+ int data_len = lt->data_bytes, spare_len = lt->spare_bytes;
+ u8 *data = buf, *spare = chip->oob_poi;
int max_bitflips = 0;
u32 failure_mask = 0;
- int chunk, ecc_offset_in_page, ret;
+ int chunk, ret;
/*
* With BCH, OOB is not fully used (and thus not read entirely), not
@@ -1279,73 +1343,98 @@ static int marvell_nfc_hw_ecc_bch_read_page(struct mtd_info *mtd,
* the controller in normal mode and must be re-read in raw mode. To
* avoid dropping the performances, we prefer not to include them. The
* user should re-read the page in raw mode if ECC bytes are required.
+ */
+
+ /*
+ * In case there is any subpage read error reported by ->correct(), we
+ * usually re-read only ECC bytes in raw mode and check if the whole
+ * page is empty. In this case, it is normal that the ECC check failed
+ * and we just ignore the error.
*
- * However, for any subpage read error reported by ->correct(), the ECC
- * bytes must be read in raw mode and the full subpage must be checked
- * to see if it is entirely empty of if there was an actual error.
+ * However, it has been empirically observed that for some layouts (e.g
+ * 2k page, 8b strength per 512B chunk), the controller tries to correct
+ * bits and may create itself bitflips in the erased area. To overcome
+ * this strange behavior, the whole page is re-read in raw mode, not
+ * only the ECC bytes.
*/
for (chunk = 0; chunk < lt->nchunks; chunk++) {
+ int data_off_in_page, spare_off_in_page, ecc_off_in_page;
+ int data_off, spare_off, ecc_off;
+ int data_len, spare_len, ecc_len;
+
/* No failure reported for this chunk, move to the next one */
if (!(failure_mask & BIT(chunk)))
continue;
- /* Derive ECC bytes positions (in page/buffer) and length */
- ecc = chip->oob_poi +
- (lt->full_chunk_cnt * lt->spare_bytes) +
- lt->last_spare_bytes +
- (chunk * ALIGN(lt->ecc_bytes, 32));
- ecc_offset_in_page =
- (chunk * (lt->data_bytes + lt->spare_bytes +
- lt->ecc_bytes)) +
- (chunk < lt->full_chunk_cnt ?
- lt->data_bytes + lt->spare_bytes :
- lt->last_data_bytes + lt->last_spare_bytes);
- ecc_len = chunk < lt->full_chunk_cnt ?
- lt->ecc_bytes : lt->last_ecc_bytes;
-
- /* Do the actual raw read of the ECC bytes */
- nand_change_read_column_op(chip, ecc_offset_in_page,
- ecc, ecc_len, false);
-
- /* Derive data/spare bytes positions (in buffer) and length */
- data = buf + (chunk * lt->data_bytes);
- data_len = chunk < lt->full_chunk_cnt ?
- lt->data_bytes : lt->last_data_bytes;
- spare = chip->oob_poi + (chunk * (lt->spare_bytes +
- lt->ecc_bytes));
- spare_len = chunk < lt->full_chunk_cnt ?
- lt->spare_bytes : lt->last_spare_bytes;
+ data_off_in_page = chunk * (lt->data_bytes + lt->spare_bytes +
+ lt->ecc_bytes);
+ spare_off_in_page = data_off_in_page +
+ (chunk < lt->full_chunk_cnt ? lt->data_bytes :
+ lt->last_data_bytes);
+ ecc_off_in_page = spare_off_in_page +
+ (chunk < lt->full_chunk_cnt ? lt->spare_bytes :
+ lt->last_spare_bytes);
+
+ data_off = chunk * lt->data_bytes;
+ spare_off = chunk * lt->spare_bytes;
+ ecc_off = (lt->full_chunk_cnt * lt->spare_bytes) +
+ lt->last_spare_bytes +
+ (chunk * (lt->ecc_bytes + 2));
+
+ data_len = chunk < lt->full_chunk_cnt ? lt->data_bytes :
+ lt->last_data_bytes;
+ spare_len = chunk < lt->full_chunk_cnt ? lt->spare_bytes :
+ lt->last_spare_bytes;
+ ecc_len = chunk < lt->full_chunk_cnt ? lt->ecc_bytes :
+ lt->last_ecc_bytes;
+
+ /*
+ * Only re-read the ECC bytes, unless we are using the 2k/8b
+ * layout which is buggy in the sense that the ECC engine will
+ * try to correct data bytes anyway, creating bitflips. In this
+ * case, re-read the entire page.
+ */
+ if (lt->writesize == 2048 && lt->strength == 8) {
+ nand_change_read_column_op(chip, data_off_in_page,
+ buf + data_off, data_len,
+ false);
+ nand_change_read_column_op(chip, spare_off_in_page,
+ chip->oob_poi + spare_off, spare_len,
+ false);
+ }
+
+ nand_change_read_column_op(chip, ecc_off_in_page,
+ chip->oob_poi + ecc_off, ecc_len,
+ false);
/* Check the entire chunk (data + spare + ecc) for emptyness */
- marvell_nfc_check_empty_chunk(chip, data, data_len, spare,
- spare_len, ecc, ecc_len,
+ marvell_nfc_check_empty_chunk(chip, buf + data_off, data_len,
+ chip->oob_poi + spare_off, spare_len,
+ chip->oob_poi + ecc_off, ecc_len,
&max_bitflips);
}
return max_bitflips;
}
-static int marvell_nfc_hw_ecc_bch_read_oob_raw(struct mtd_info *mtd,
- struct nand_chip *chip, int page)
+static int marvell_nfc_hw_ecc_bch_read_oob_raw(struct nand_chip *chip, int page)
{
/* Invalidate page cache */
chip->pagebuf = -1;
- return chip->ecc.read_page_raw(mtd, chip, chip->data_buf, true, page);
+ return chip->ecc.read_page_raw(chip, chip->data_buf, true, page);
}
-static int marvell_nfc_hw_ecc_bch_read_oob(struct mtd_info *mtd,
- struct nand_chip *chip, int page)
+static int marvell_nfc_hw_ecc_bch_read_oob(struct nand_chip *chip, int page)
{
/* Invalidate page cache */
chip->pagebuf = -1;
- return chip->ecc.read_page(mtd, chip, chip->data_buf, true, page);
+ return chip->ecc.read_page(chip, chip->data_buf, true, page);
}
/* BCH write helpers */
-static int marvell_nfc_hw_ecc_bch_write_page_raw(struct mtd_info *mtd,
- struct nand_chip *chip,
+static int marvell_nfc_hw_ecc_bch_write_page_raw(struct nand_chip *chip,
const u8 *buf,
int oob_required, int page)
{
@@ -1458,11 +1547,11 @@ marvell_nfc_hw_ecc_bch_write_chunk(struct nand_chip *chip, int chunk,
return 0;
}
-static int marvell_nfc_hw_ecc_bch_write_page(struct mtd_info *mtd,
- struct nand_chip *chip,
+static int marvell_nfc_hw_ecc_bch_write_page(struct nand_chip *chip,
const u8 *buf,
int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
const u8 *data = buf;
const u8 *spare = chip->oob_poi;
@@ -1507,27 +1596,29 @@ static int marvell_nfc_hw_ecc_bch_write_page(struct mtd_info *mtd,
return 0;
}
-static int marvell_nfc_hw_ecc_bch_write_oob_raw(struct mtd_info *mtd,
- struct nand_chip *chip,
+static int marvell_nfc_hw_ecc_bch_write_oob_raw(struct nand_chip *chip,
int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
/* Invalidate page cache */
chip->pagebuf = -1;
memset(chip->data_buf, 0xFF, mtd->writesize);
- return chip->ecc.write_page_raw(mtd, chip, chip->data_buf, true, page);
+ return chip->ecc.write_page_raw(chip, chip->data_buf, true, page);
}
-static int marvell_nfc_hw_ecc_bch_write_oob(struct mtd_info *mtd,
- struct nand_chip *chip, int page)
+static int marvell_nfc_hw_ecc_bch_write_oob(struct nand_chip *chip, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
/* Invalidate page cache */
chip->pagebuf = -1;
memset(chip->data_buf, 0xFF, mtd->writesize);
- return chip->ecc.write_page(mtd, chip, chip->data_buf, true, page);
+ return chip->ecc.write_page(chip, chip->data_buf, true, page);
}
/* NAND framework ->exec_op() hooks and related helpers */
@@ -1547,7 +1638,7 @@ static void marvell_nfc_parse_instructions(struct nand_chip *chip,
for (op_id = 0; op_id < subop->ninstrs; op_id++) {
unsigned int offset, naddrs;
const u8 *addrs;
- int len = nand_subop_get_data_len(subop, op_id);
+ int len;
instr = &subop->instrs[op_id];
@@ -1593,6 +1684,7 @@ static void marvell_nfc_parse_instructions(struct nand_chip *chip,
nfc_op->ndcb[0] |=
NDCB0_CMD_XTYPE(XTYPE_MONOLITHIC_RW) |
NDCB0_LEN_OVRD;
+ len = nand_subop_get_data_len(subop, op_id);
nfc_op->ndcb[3] |= round_up(len, FIFO_DEPTH);
}
nfc_op->data_delay_ns = instr->delay_ns;
@@ -1606,6 +1698,7 @@ static void marvell_nfc_parse_instructions(struct nand_chip *chip,
nfc_op->ndcb[0] |=
NDCB0_CMD_XTYPE(XTYPE_MONOLITHIC_RW) |
NDCB0_LEN_OVRD;
+ len = nand_subop_get_data_len(subop, op_id);
nfc_op->ndcb[3] |= round_up(len, FIFO_DEPTH);
}
nfc_op->data_delay_ns = instr->delay_ns;
@@ -2095,6 +2188,16 @@ static int marvell_nand_hw_ecc_ctrl_init(struct mtd_info *mtd,
return -ENOTSUPP;
}
+ /* Special care for the layout 2k/8-bit/512B */
+ if (l->writesize == 2048 && l->strength == 8) {
+ if (mtd->oobsize < 128) {
+ dev_err(nfc->dev, "Requested layout needs at least 128 OOB bytes\n");
+ return -ENOTSUPP;
+ } else {
+ chip->bbt_options |= NAND_BBT_NO_OOB_BBM;
+ }
+ }
+
mtd_set_ooblayout(mtd, &marvell_nand_ooblayout_ops);
ecc->steps = l->nchunks;
ecc->size = l->data_bytes;
@@ -2190,11 +2293,10 @@ static struct nand_bbt_descr bbt_mirror_descr = {
.pattern = bbt_mirror_pattern
};
-static int marvell_nfc_setup_data_interface(struct mtd_info *mtd, int chipnr,
+static int marvell_nfc_setup_data_interface(struct nand_chip *chip, int chipnr,
const struct nand_data_interface
*conf)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct marvell_nand_chip *marvell_nand = to_marvell_nand(chip);
struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
unsigned int period_ns = 1000000000 / clk_get_rate(nfc->core_clk) * 2;
@@ -2538,7 +2640,7 @@ static int marvell_nand_chip_init(struct device *dev, struct marvell_nfc *nfc,
chip->options |= NAND_BUSWIDTH_AUTO;
- ret = nand_scan(mtd, marvell_nand->nsels);
+ ret = nand_scan(chip, marvell_nand->nsels);
if (ret) {
dev_err(dev, "could not scan the nand chip\n");
return ret;
@@ -2551,7 +2653,7 @@ static int marvell_nand_chip_init(struct device *dev, struct marvell_nfc *nfc,
ret = mtd_device_register(mtd, NULL, 0);
if (ret) {
dev_err(dev, "failed to register mtd device: %d\n", ret);
- nand_release(mtd);
+ nand_release(chip);
return ret;
}
@@ -2606,7 +2708,7 @@ static void marvell_nand_chips_cleanup(struct marvell_nfc *nfc)
struct marvell_nand_chip *entry, *temp;
list_for_each_entry_safe(entry, temp, &nfc->chips, node) {
- nand_release(nand_to_mtd(&entry->chip));
+ nand_release(&entry->chip);
list_del(&entry->node);
}
}
@@ -2697,24 +2799,23 @@ static int marvell_nfc_init(struct marvell_nfc *nfc)
struct regmap *sysctrl_base =
syscon_regmap_lookup_by_phandle(np,
"marvell,system-controller");
- u32 reg;
if (IS_ERR(sysctrl_base))
return PTR_ERR(sysctrl_base);
- reg = GENCONF_SOC_DEVICE_MUX_NFC_EN |
- GENCONF_SOC_DEVICE_MUX_ECC_CLK_RST |
- GENCONF_SOC_DEVICE_MUX_ECC_CORE_RST |
- GENCONF_SOC_DEVICE_MUX_NFC_INT_EN;
- regmap_write(sysctrl_base, GENCONF_SOC_DEVICE_MUX, reg);
+ regmap_write(sysctrl_base, GENCONF_SOC_DEVICE_MUX,
+ GENCONF_SOC_DEVICE_MUX_NFC_EN |
+ GENCONF_SOC_DEVICE_MUX_ECC_CLK_RST |
+ GENCONF_SOC_DEVICE_MUX_ECC_CORE_RST |
+ GENCONF_SOC_DEVICE_MUX_NFC_INT_EN);
- regmap_read(sysctrl_base, GENCONF_CLK_GATING_CTRL, &reg);
- reg |= GENCONF_CLK_GATING_CTRL_ND_GATE;
- regmap_write(sysctrl_base, GENCONF_CLK_GATING_CTRL, reg);
+ regmap_update_bits(sysctrl_base, GENCONF_CLK_GATING_CTRL,
+ GENCONF_CLK_GATING_CTRL_ND_GATE,
+ GENCONF_CLK_GATING_CTRL_ND_GATE);
- regmap_read(sysctrl_base, GENCONF_ND_CLK_CTRL, &reg);
- reg |= GENCONF_ND_CLK_CTRL_EN;
- regmap_write(sysctrl_base, GENCONF_ND_CLK_CTRL, reg);
+ regmap_update_bits(sysctrl_base, GENCONF_ND_CLK_CTRL,
+ GENCONF_ND_CLK_CTRL_EN,
+ GENCONF_ND_CLK_CTRL_EN);
}
/* Configure the DMA if appropriate */
diff --git a/drivers/mtd/nand/raw/mpc5121_nfc.c b/drivers/mtd/nand/raw/mpc5121_nfc.c
index 6d1740d54e0d..86a0aabe08df 100644
--- a/drivers/mtd/nand/raw/mpc5121_nfc.c
+++ b/drivers/mtd/nand/raw/mpc5121_nfc.c
@@ -263,8 +263,10 @@ static void mpc5121_nfc_addr_cycle(struct mtd_info *mtd, int column, int page)
}
/* Control chip select signals */
-static void mpc5121_nfc_select_chip(struct mtd_info *mtd, int chip)
+static void mpc5121_nfc_select_chip(struct nand_chip *nand, int chip)
{
+ struct mtd_info *mtd = nand_to_mtd(nand);
+
if (chip < 0) {
nfc_clear(mtd, NFC_CONFIG1, NFC_CE);
return;
@@ -299,9 +301,9 @@ static int ads5121_chipselect_init(struct mtd_info *mtd)
}
/* Control chips select signal on ADS5121 board */
-static void ads5121_select_chip(struct mtd_info *mtd, int chip)
+static void ads5121_select_chip(struct nand_chip *nand, int chip)
{
- struct nand_chip *nand = mtd_to_nand(mtd);
+ struct mtd_info *mtd = nand_to_mtd(nand);
struct mpc5121_nfc_prv *prv = nand_get_controller_data(nand);
u8 v;
@@ -309,16 +311,16 @@ static void ads5121_select_chip(struct mtd_info *mtd, int chip)
v |= 0x0F;
if (chip >= 0) {
- mpc5121_nfc_select_chip(mtd, 0);
+ mpc5121_nfc_select_chip(nand, 0);
v &= ~(1 << chip);
} else
- mpc5121_nfc_select_chip(mtd, -1);
+ mpc5121_nfc_select_chip(nand, -1);
out_8(prv->csreg, v);
}
/* Read NAND Ready/Busy signal */
-static int mpc5121_nfc_dev_ready(struct mtd_info *mtd)
+static int mpc5121_nfc_dev_ready(struct nand_chip *nand)
{
/*
* NFC handles ready/busy signal internally. Therefore, this function
@@ -328,10 +330,10 @@ static int mpc5121_nfc_dev_ready(struct mtd_info *mtd)
}
/* Write command to NAND flash */
-static void mpc5121_nfc_command(struct mtd_info *mtd, unsigned command,
- int column, int page)
+static void mpc5121_nfc_command(struct nand_chip *chip, unsigned command,
+ int column, int page)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip);
prv->column = (column >= 0) ? column : 0;
@@ -362,7 +364,7 @@ static void mpc5121_nfc_command(struct mtd_info *mtd, unsigned command,
break;
case NAND_CMD_SEQIN:
- mpc5121_nfc_command(mtd, NAND_CMD_READ0, column, page);
+ mpc5121_nfc_command(chip, NAND_CMD_READ0, column, page);
column = 0;
break;
@@ -493,34 +495,24 @@ static void mpc5121_nfc_buf_copy(struct mtd_info *mtd, u_char *buf, int len,
}
/* Read data from NFC buffers */
-static void mpc5121_nfc_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+static void mpc5121_nfc_read_buf(struct nand_chip *chip, u_char *buf, int len)
{
- mpc5121_nfc_buf_copy(mtd, buf, len, 0);
+ mpc5121_nfc_buf_copy(nand_to_mtd(chip), buf, len, 0);
}
/* Write data to NFC buffers */
-static void mpc5121_nfc_write_buf(struct mtd_info *mtd,
- const u_char *buf, int len)
+static void mpc5121_nfc_write_buf(struct nand_chip *chip, const u_char *buf,
+ int len)
{
- mpc5121_nfc_buf_copy(mtd, (u_char *)buf, len, 1);
+ mpc5121_nfc_buf_copy(nand_to_mtd(chip), (u_char *)buf, len, 1);
}
/* Read byte from NFC buffers */
-static u8 mpc5121_nfc_read_byte(struct mtd_info *mtd)
+static u8 mpc5121_nfc_read_byte(struct nand_chip *chip)
{
u8 tmp;
- mpc5121_nfc_read_buf(mtd, &tmp, sizeof(tmp));
-
- return tmp;
-}
-
-/* Read word from NFC buffers */
-static u16 mpc5121_nfc_read_word(struct mtd_info *mtd)
-{
- u16 tmp;
-
- mpc5121_nfc_read_buf(mtd, (u_char *)&tmp, sizeof(tmp));
+ mpc5121_nfc_read_buf(chip, &tmp, sizeof(tmp));
return tmp;
}
@@ -700,15 +692,14 @@ static int mpc5121_nfc_probe(struct platform_device *op)
}
mtd->name = "MPC5121 NAND";
- chip->dev_ready = mpc5121_nfc_dev_ready;
- chip->cmdfunc = mpc5121_nfc_command;
- chip->read_byte = mpc5121_nfc_read_byte;
- chip->read_word = mpc5121_nfc_read_word;
- chip->read_buf = mpc5121_nfc_read_buf;
- chip->write_buf = mpc5121_nfc_write_buf;
+ chip->legacy.dev_ready = mpc5121_nfc_dev_ready;
+ chip->legacy.cmdfunc = mpc5121_nfc_command;
+ chip->legacy.read_byte = mpc5121_nfc_read_byte;
+ chip->legacy.read_buf = mpc5121_nfc_read_buf;
+ chip->legacy.write_buf = mpc5121_nfc_write_buf;
chip->select_chip = mpc5121_nfc_select_chip;
- chip->set_features = nand_get_set_features_notsupp;
- chip->get_features = nand_get_set_features_notsupp;
+ chip->legacy.set_features = nand_get_set_features_notsupp;
+ chip->legacy.get_features = nand_get_set_features_notsupp;
chip->bbt_options = NAND_BBT_USE_FLASH;
chip->ecc.mode = NAND_ECC_SOFT;
chip->ecc.algo = NAND_ECC_HAMMING;
@@ -778,7 +769,7 @@ static int mpc5121_nfc_probe(struct platform_device *op)
}
/* Detect NAND chips */
- retval = nand_scan(mtd, be32_to_cpup(chips_no));
+ retval = nand_scan(chip, be32_to_cpup(chips_no));
if (retval) {
dev_err(dev, "NAND Flash not found !\n");
goto error;
@@ -828,7 +819,7 @@ static int mpc5121_nfc_remove(struct platform_device *op)
struct device *dev = &op->dev;
struct mtd_info *mtd = dev_get_drvdata(dev);
- nand_release(mtd);
+ nand_release(mtd_to_nand(mtd));
mpc5121_nfc_free(dev, mtd);
return 0;
diff --git a/drivers/mtd/nand/raw/mtk_nand.c b/drivers/mtd/nand/raw/mtk_nand.c
index 57b5ed1699e3..2bb0df1b7244 100644
--- a/drivers/mtd/nand/raw/mtk_nand.c
+++ b/drivers/mtd/nand/raw/mtk_nand.c
@@ -389,23 +389,22 @@ static int mtk_nfc_hw_runtime_config(struct mtd_info *mtd)
return 0;
}
-static void mtk_nfc_select_chip(struct mtd_info *mtd, int chip)
+static void mtk_nfc_select_chip(struct nand_chip *nand, int chip)
{
- struct nand_chip *nand = mtd_to_nand(mtd);
struct mtk_nfc *nfc = nand_get_controller_data(nand);
struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(nand);
if (chip < 0)
return;
- mtk_nfc_hw_runtime_config(mtd);
+ mtk_nfc_hw_runtime_config(nand_to_mtd(nand));
nfi_writel(nfc, mtk_nand->sels[chip], NFI_CSEL);
}
-static int mtk_nfc_dev_ready(struct mtd_info *mtd)
+static int mtk_nfc_dev_ready(struct nand_chip *nand)
{
- struct mtk_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd));
+ struct mtk_nfc *nfc = nand_get_controller_data(nand);
if (nfi_readl(nfc, NFI_STA) & STA_BUSY)
return 0;
@@ -413,9 +412,10 @@ static int mtk_nfc_dev_ready(struct mtd_info *mtd)
return 1;
}
-static void mtk_nfc_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
+static void mtk_nfc_cmd_ctrl(struct nand_chip *chip, int dat,
+ unsigned int ctrl)
{
- struct mtk_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd));
+ struct mtk_nfc *nfc = nand_get_controller_data(chip);
if (ctrl & NAND_ALE) {
mtk_nfc_send_address(nfc, dat);
@@ -438,9 +438,8 @@ static inline void mtk_nfc_wait_ioready(struct mtk_nfc *nfc)
dev_err(nfc->dev, "data not ready\n");
}
-static inline u8 mtk_nfc_read_byte(struct mtd_info *mtd)
+static inline u8 mtk_nfc_read_byte(struct nand_chip *chip)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct mtk_nfc *nfc = nand_get_controller_data(chip);
u32 reg;
@@ -467,17 +466,17 @@ static inline u8 mtk_nfc_read_byte(struct mtd_info *mtd)
return nfi_readb(nfc, NFI_DATAR);
}
-static void mtk_nfc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
+static void mtk_nfc_read_buf(struct nand_chip *chip, u8 *buf, int len)
{
int i;
for (i = 0; i < len; i++)
- buf[i] = mtk_nfc_read_byte(mtd);
+ buf[i] = mtk_nfc_read_byte(chip);
}
-static void mtk_nfc_write_byte(struct mtd_info *mtd, u8 byte)
+static void mtk_nfc_write_byte(struct nand_chip *chip, u8 byte)
{
- struct mtk_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd));
+ struct mtk_nfc *nfc = nand_get_controller_data(chip);
u32 reg;
reg = nfi_readl(nfc, NFI_STA) & NFI_FSM_MASK;
@@ -496,18 +495,18 @@ static void mtk_nfc_write_byte(struct mtd_info *mtd, u8 byte)
nfi_writeb(nfc, byte, NFI_DATAW);
}
-static void mtk_nfc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
+static void mtk_nfc_write_buf(struct nand_chip *chip, const u8 *buf, int len)
{
int i;
for (i = 0; i < len; i++)
- mtk_nfc_write_byte(mtd, buf[i]);
+ mtk_nfc_write_byte(chip, buf[i]);
}
-static int mtk_nfc_setup_data_interface(struct mtd_info *mtd, int csline,
+static int mtk_nfc_setup_data_interface(struct nand_chip *chip, int csline,
const struct nand_data_interface *conf)
{
- struct mtk_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd));
+ struct mtk_nfc *nfc = nand_get_controller_data(chip);
const struct nand_sdr_timings *timings;
u32 rate, tpoecs, tprecs, tc2r, tw2r, twh, twst, trlt;
@@ -807,27 +806,27 @@ static int mtk_nfc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
return nand_prog_page_end_op(chip);
}
-static int mtk_nfc_write_page_hwecc(struct mtd_info *mtd,
- struct nand_chip *chip, const u8 *buf,
+static int mtk_nfc_write_page_hwecc(struct nand_chip *chip, const u8 *buf,
int oob_on, int page)
{
- return mtk_nfc_write_page(mtd, chip, buf, page, 0);
+ return mtk_nfc_write_page(nand_to_mtd(chip), chip, buf, page, 0);
}
-static int mtk_nfc_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
- const u8 *buf, int oob_on, int pg)
+static int mtk_nfc_write_page_raw(struct nand_chip *chip, const u8 *buf,
+ int oob_on, int pg)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct mtk_nfc *nfc = nand_get_controller_data(chip);
mtk_nfc_format_page(mtd, buf);
return mtk_nfc_write_page(mtd, chip, nfc->buffer, pg, 1);
}
-static int mtk_nfc_write_subpage_hwecc(struct mtd_info *mtd,
- struct nand_chip *chip, u32 offset,
+static int mtk_nfc_write_subpage_hwecc(struct nand_chip *chip, u32 offset,
u32 data_len, const u8 *buf,
int oob_on, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct mtk_nfc *nfc = nand_get_controller_data(chip);
int ret;
@@ -839,10 +838,9 @@ static int mtk_nfc_write_subpage_hwecc(struct mtd_info *mtd,
return mtk_nfc_write_page(mtd, chip, nfc->buffer, page, 1);
}
-static int mtk_nfc_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
- int page)
+static int mtk_nfc_write_oob_std(struct nand_chip *chip, int page)
{
- return mtk_nfc_write_page_raw(mtd, chip, NULL, 1, page);
+ return mtk_nfc_write_page_raw(chip, NULL, 1, page);
}
static int mtk_nfc_update_ecc_stats(struct mtd_info *mtd, u8 *buf, u32 sectors)
@@ -969,23 +967,25 @@ done:
return bitflips;
}
-static int mtk_nfc_read_subpage_hwecc(struct mtd_info *mtd,
- struct nand_chip *chip, u32 off,
+static int mtk_nfc_read_subpage_hwecc(struct nand_chip *chip, u32 off,
u32 len, u8 *p, int pg)
{
- return mtk_nfc_read_subpage(mtd, chip, off, len, p, pg, 0);
+ return mtk_nfc_read_subpage(nand_to_mtd(chip), chip, off, len, p, pg,
+ 0);
}
-static int mtk_nfc_read_page_hwecc(struct mtd_info *mtd,
- struct nand_chip *chip, u8 *p,
- int oob_on, int pg)
+static int mtk_nfc_read_page_hwecc(struct nand_chip *chip, u8 *p, int oob_on,
+ int pg)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
return mtk_nfc_read_subpage(mtd, chip, 0, mtd->writesize, p, pg, 0);
}
-static int mtk_nfc_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
- u8 *buf, int oob_on, int page)
+static int mtk_nfc_read_page_raw(struct nand_chip *chip, u8 *buf, int oob_on,
+ int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
struct mtk_nfc *nfc = nand_get_controller_data(chip);
struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
@@ -1011,10 +1011,9 @@ static int mtk_nfc_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
return ret;
}
-static int mtk_nfc_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
- int page)
+static int mtk_nfc_read_oob_std(struct nand_chip *chip, int page)
{
- return mtk_nfc_read_page_raw(mtd, chip, NULL, 1, page);
+ return mtk_nfc_read_page_raw(chip, NULL, 1, page);
}
static inline void mtk_nfc_hw_init(struct mtk_nfc *nfc)
@@ -1333,13 +1332,13 @@ static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
nand_set_controller_data(nand, nfc);
nand->options |= NAND_USE_BOUNCE_BUFFER | NAND_SUBPAGE_READ;
- nand->dev_ready = mtk_nfc_dev_ready;
+ nand->legacy.dev_ready = mtk_nfc_dev_ready;
nand->select_chip = mtk_nfc_select_chip;
- nand->write_byte = mtk_nfc_write_byte;
- nand->write_buf = mtk_nfc_write_buf;
- nand->read_byte = mtk_nfc_read_byte;
- nand->read_buf = mtk_nfc_read_buf;
- nand->cmd_ctrl = mtk_nfc_cmd_ctrl;
+ nand->legacy.write_byte = mtk_nfc_write_byte;
+ nand->legacy.write_buf = mtk_nfc_write_buf;
+ nand->legacy.read_byte = mtk_nfc_read_byte;
+ nand->legacy.read_buf = mtk_nfc_read_buf;
+ nand->legacy.cmd_ctrl = mtk_nfc_cmd_ctrl;
nand->setup_data_interface = mtk_nfc_setup_data_interface;
/* set default mode in case dt entry is missing */
@@ -1365,14 +1364,14 @@ static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
mtk_nfc_hw_init(nfc);
- ret = nand_scan(mtd, nsels);
+ ret = nand_scan(nand, nsels);
if (ret)
return ret;
ret = mtd_device_register(mtd, NULL, 0);
if (ret) {
dev_err(dev, "mtd parse partition error\n");
- nand_release(mtd);
+ nand_release(nand);
return ret;
}
@@ -1538,7 +1537,7 @@ static int mtk_nfc_remove(struct platform_device *pdev)
while (!list_empty(&nfc->chips)) {
chip = list_first_entry(&nfc->chips, struct mtk_nfc_nand_chip,
node);
- nand_release(nand_to_mtd(&chip->nand));
+ nand_release(&chip->nand);
list_del(&chip->node);
}
diff --git a/drivers/mtd/nand/raw/mxc_nand.c b/drivers/mtd/nand/raw/mxc_nand.c
index 4c9214dea424..88bd3f6a499c 100644
--- a/drivers/mtd/nand/raw/mxc_nand.c
+++ b/drivers/mtd/nand/raw/mxc_nand.c
@@ -136,8 +136,8 @@ struct mxc_nand_devtype_data {
void (*irq_control)(struct mxc_nand_host *, int);
u32 (*get_ecc_status)(struct mxc_nand_host *);
const struct mtd_ooblayout_ops *ooblayout;
- void (*select_chip)(struct mtd_info *mtd, int chip);
- int (*setup_data_interface)(struct mtd_info *mtd, int csline,
+ void (*select_chip)(struct nand_chip *chip, int cs);
+ int (*setup_data_interface)(struct nand_chip *chip, int csline,
const struct nand_data_interface *conf);
void (*enable_hwecc)(struct nand_chip *chip, bool enable);
@@ -701,7 +701,7 @@ static void mxc_nand_enable_hwecc_v3(struct nand_chip *chip, bool enable)
}
/* This functions is used by upper layer to checks if device is ready */
-static int mxc_nand_dev_ready(struct mtd_info *mtd)
+static int mxc_nand_dev_ready(struct nand_chip *chip)
{
/*
* NFC handles R/B internally. Therefore, this function
@@ -816,8 +816,8 @@ static int mxc_nand_read_page_v2_v3(struct nand_chip *chip, void *buf,
return max_bitflips;
}
-static int mxc_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
- uint8_t *buf, int oob_required, int page)
+static int mxc_nand_read_page(struct nand_chip *chip, uint8_t *buf,
+ int oob_required, int page)
{
struct mxc_nand_host *host = nand_get_controller_data(chip);
void *oob_buf;
@@ -830,8 +830,8 @@ static int mxc_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
return host->devtype_data->read_page(chip, buf, oob_buf, 1, page);
}
-static int mxc_nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
- uint8_t *buf, int oob_required, int page)
+static int mxc_nand_read_page_raw(struct nand_chip *chip, uint8_t *buf,
+ int oob_required, int page)
{
struct mxc_nand_host *host = nand_get_controller_data(chip);
void *oob_buf;
@@ -844,8 +844,7 @@ static int mxc_nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
return host->devtype_data->read_page(chip, buf, oob_buf, 0, page);
}
-static int mxc_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
- int page)
+static int mxc_nand_read_oob(struct nand_chip *chip, int page)
{
struct mxc_nand_host *host = nand_get_controller_data(chip);
@@ -874,22 +873,21 @@ static int mxc_nand_write_page(struct nand_chip *chip, const uint8_t *buf,
return 0;
}
-static int mxc_nand_write_page_ecc(struct mtd_info *mtd, struct nand_chip *chip,
- const uint8_t *buf, int oob_required,
- int page)
+static int mxc_nand_write_page_ecc(struct nand_chip *chip, const uint8_t *buf,
+ int oob_required, int page)
{
return mxc_nand_write_page(chip, buf, true, page);
}
-static int mxc_nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
- const uint8_t *buf, int oob_required, int page)
+static int mxc_nand_write_page_raw(struct nand_chip *chip, const uint8_t *buf,
+ int oob_required, int page)
{
return mxc_nand_write_page(chip, buf, false, page);
}
-static int mxc_nand_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
- int page)
+static int mxc_nand_write_oob(struct nand_chip *chip, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct mxc_nand_host *host = nand_get_controller_data(chip);
memset(host->data_buf, 0xff, mtd->writesize);
@@ -897,9 +895,8 @@ static int mxc_nand_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
return mxc_nand_write_page(chip, host->data_buf, false, page);
}
-static u_char mxc_nand_read_byte(struct mtd_info *mtd)
+static u_char mxc_nand_read_byte(struct nand_chip *nand_chip)
{
- struct nand_chip *nand_chip = mtd_to_nand(mtd);
struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
uint8_t ret;
@@ -921,25 +918,13 @@ static u_char mxc_nand_read_byte(struct mtd_info *mtd)
return ret;
}
-static uint16_t mxc_nand_read_word(struct mtd_info *mtd)
-{
- struct nand_chip *nand_chip = mtd_to_nand(mtd);
- struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
- uint16_t ret;
-
- ret = *(uint16_t *)(host->data_buf + host->buf_start);
- host->buf_start += 2;
-
- return ret;
-}
-
/* Write data of length len to buffer buf. The data to be
* written on NAND Flash is first copied to RAMbuffer. After the Data Input
* Operation by the NFC, the data is written to NAND Flash */
-static void mxc_nand_write_buf(struct mtd_info *mtd,
- const u_char *buf, int len)
+static void mxc_nand_write_buf(struct nand_chip *nand_chip, const u_char *buf,
+ int len)
{
- struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct mtd_info *mtd = nand_to_mtd(nand_chip);
struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
u16 col = host->buf_start;
int n = mtd->oobsize + mtd->writesize - col;
@@ -955,9 +940,10 @@ static void mxc_nand_write_buf(struct mtd_info *mtd,
* Flash first the data output cycle is initiated by the NFC, which copies
* the data to RAMbuffer. This data of length len is then copied to buffer buf.
*/
-static void mxc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+static void mxc_nand_read_buf(struct nand_chip *nand_chip, u_char *buf,
+ int len)
{
- struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct mtd_info *mtd = nand_to_mtd(nand_chip);
struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
u16 col = host->buf_start;
int n = mtd->oobsize + mtd->writesize - col;
@@ -971,9 +957,8 @@ static void mxc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
/* This function is used by upper layer for select and
* deselect of the NAND chip */
-static void mxc_nand_select_chip_v1_v3(struct mtd_info *mtd, int chip)
+static void mxc_nand_select_chip_v1_v3(struct nand_chip *nand_chip, int chip)
{
- struct nand_chip *nand_chip = mtd_to_nand(mtd);
struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
if (chip == -1) {
@@ -992,9 +977,8 @@ static void mxc_nand_select_chip_v1_v3(struct mtd_info *mtd, int chip)
}
}
-static void mxc_nand_select_chip_v2(struct mtd_info *mtd, int chip)
+static void mxc_nand_select_chip_v2(struct nand_chip *nand_chip, int chip)
{
- struct nand_chip *nand_chip = mtd_to_nand(mtd);
struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
if (chip == -1) {
@@ -1155,11 +1139,10 @@ static void preset_v1(struct mtd_info *mtd)
writew(0x4, NFC_V1_V2_WRPROT);
}
-static int mxc_nand_v2_setup_data_interface(struct mtd_info *mtd, int csline,
+static int mxc_nand_v2_setup_data_interface(struct nand_chip *chip, int csline,
const struct nand_data_interface *conf)
{
- struct nand_chip *nand_chip = mtd_to_nand(mtd);
- struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
+ struct mxc_nand_host *host = nand_get_controller_data(chip);
int tRC_min_ns, tRC_ps, ret;
unsigned long rate, rate_round;
const struct nand_sdr_timings *timings;
@@ -1349,10 +1332,10 @@ static void preset_v3(struct mtd_info *mtd)
/* Used by the upper layer to write command to NAND Flash for
* different operations to be carried out on NAND Flash */
-static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
- int column, int page_addr)
+static void mxc_nand_command(struct nand_chip *nand_chip, unsigned command,
+ int column, int page_addr)
{
- struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct mtd_info *mtd = nand_to_mtd(nand_chip);
struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
dev_dbg(host->dev, "mxc_nand_command (cmd = 0x%x, col = 0x%x, page = 0x%x)\n",
@@ -1409,17 +1392,17 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
}
}
-static int mxc_nand_set_features(struct mtd_info *mtd, struct nand_chip *chip,
- int addr, u8 *subfeature_param)
+static int mxc_nand_set_features(struct nand_chip *chip, int addr,
+ u8 *subfeature_param)
{
- struct nand_chip *nand_chip = mtd_to_nand(mtd);
- struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ struct mxc_nand_host *host = nand_get_controller_data(chip);
int i;
host->buf_start = 0;
for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
- chip->write_byte(mtd, subfeature_param[i]);
+ chip->legacy.write_byte(chip, subfeature_param[i]);
memcpy32_toio(host->main_area0, host->data_buf, mtd->writesize);
host->devtype_data->send_cmd(host, NAND_CMD_SET_FEATURES, false);
@@ -1429,11 +1412,11 @@ static int mxc_nand_set_features(struct mtd_info *mtd, struct nand_chip *chip,
return 0;
}
-static int mxc_nand_get_features(struct mtd_info *mtd, struct nand_chip *chip,
- int addr, u8 *subfeature_param)
+static int mxc_nand_get_features(struct nand_chip *chip, int addr,
+ u8 *subfeature_param)
{
- struct nand_chip *nand_chip = mtd_to_nand(mtd);
- struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ struct mxc_nand_host *host = nand_get_controller_data(chip);
int i;
host->devtype_data->send_cmd(host, NAND_CMD_GET_FEATURES, false);
@@ -1443,7 +1426,7 @@ static int mxc_nand_get_features(struct mtd_info *mtd, struct nand_chip *chip,
host->buf_start = 0;
for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
- *subfeature_param++ = chip->read_byte(mtd);
+ *subfeature_param++ = chip->legacy.read_byte(chip);
return 0;
}
@@ -1786,18 +1769,17 @@ static int mxcnd_probe(struct platform_device *pdev)
mtd->name = DRIVER_NAME;
/* 50 us command delay time */
- this->chip_delay = 5;
+ this->legacy.chip_delay = 5;
nand_set_controller_data(this, host);
nand_set_flash_node(this, pdev->dev.of_node),
- this->dev_ready = mxc_nand_dev_ready;
- this->cmdfunc = mxc_nand_command;
- this->read_byte = mxc_nand_read_byte;
- this->read_word = mxc_nand_read_word;
- this->write_buf = mxc_nand_write_buf;
- this->read_buf = mxc_nand_read_buf;
- this->set_features = mxc_nand_set_features;
- this->get_features = mxc_nand_get_features;
+ this->legacy.dev_ready = mxc_nand_dev_ready;
+ this->legacy.cmdfunc = mxc_nand_command;
+ this->legacy.read_byte = mxc_nand_read_byte;
+ this->legacy.write_buf = mxc_nand_write_buf;
+ this->legacy.read_buf = mxc_nand_read_buf;
+ this->legacy.set_features = mxc_nand_set_features;
+ this->legacy.get_features = mxc_nand_get_features;
host->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(host->clk))
@@ -1900,7 +1882,7 @@ static int mxcnd_probe(struct platform_device *pdev)
/* Scan the NAND device */
this->dummy_controller.ops = &mxcnd_controller_ops;
- err = nand_scan(mtd, is_imx25_nfc(host) ? 4 : 1);
+ err = nand_scan(this, is_imx25_nfc(host) ? 4 : 1);
if (err)
goto escan;
@@ -1928,7 +1910,7 @@ static int mxcnd_remove(struct platform_device *pdev)
{
struct mxc_nand_host *host = platform_get_drvdata(pdev);
- nand_release(nand_to_mtd(&host->nand));
+ nand_release(&host->nand);
if (host->clk_act)
clk_disable_unprepare(host->clk);
diff --git a/drivers/mtd/nand/raw/nand_amd.c b/drivers/mtd/nand/raw/nand_amd.c
index 22f060f38123..890c5b43e03c 100644
--- a/drivers/mtd/nand/raw/nand_amd.c
+++ b/drivers/mtd/nand/raw/nand_amd.c
@@ -15,7 +15,7 @@
* GNU General Public License for more details.
*/
-#include <linux/mtd/rawnand.h>
+#include "internals.h"
static void amd_nand_decode_id(struct nand_chip *chip)
{
diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
index d527e448ce19..05bd0779fe9b 100644
--- a/drivers/mtd/nand/raw/nand_base.c
+++ b/drivers/mtd/nand/raw/nand_base.c
@@ -36,10 +36,8 @@
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/mm.h>
-#include <linux/nmi.h>
#include <linux/types.h>
#include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
#include <linux/mtd/nand_ecc.h>
#include <linux/mtd/nand_bch.h>
#include <linux/interrupt.h>
@@ -48,6 +46,8 @@
#include <linux/mtd/partitions.h>
#include <linux/of.h>
+#include "internals.h"
+
static int nand_get_device(struct mtd_info *mtd, int new_state);
static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
@@ -253,183 +253,16 @@ static void nand_release_device(struct mtd_info *mtd)
}
/**
- * nand_read_byte - [DEFAULT] read one byte from the chip
- * @mtd: MTD device structure
- *
- * Default read function for 8bit buswidth
- */
-static uint8_t nand_read_byte(struct mtd_info *mtd)
-{
- struct nand_chip *chip = mtd_to_nand(mtd);
- return readb(chip->IO_ADDR_R);
-}
-
-/**
- * nand_read_byte16 - [DEFAULT] read one byte endianness aware from the chip
- * @mtd: MTD device structure
- *
- * Default read function for 16bit buswidth with endianness conversion.
- *
- */
-static uint8_t nand_read_byte16(struct mtd_info *mtd)
-{
- struct nand_chip *chip = mtd_to_nand(mtd);
- return (uint8_t) cpu_to_le16(readw(chip->IO_ADDR_R));
-}
-
-/**
- * nand_read_word - [DEFAULT] read one word from the chip
- * @mtd: MTD device structure
- *
- * Default read function for 16bit buswidth without endianness conversion.
- */
-static u16 nand_read_word(struct mtd_info *mtd)
-{
- struct nand_chip *chip = mtd_to_nand(mtd);
- return readw(chip->IO_ADDR_R);
-}
-
-/**
- * nand_select_chip - [DEFAULT] control CE line
- * @mtd: MTD device structure
- * @chipnr: chipnumber to select, -1 for deselect
- *
- * Default select function for 1 chip devices.
- */
-static void nand_select_chip(struct mtd_info *mtd, int chipnr)
-{
- struct nand_chip *chip = mtd_to_nand(mtd);
-
- switch (chipnr) {
- case -1:
- chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE);
- break;
- case 0:
- break;
-
- default:
- BUG();
- }
-}
-
-/**
- * nand_write_byte - [DEFAULT] write single byte to chip
- * @mtd: MTD device structure
- * @byte: value to write
- *
- * Default function to write a byte to I/O[7:0]
- */
-static void nand_write_byte(struct mtd_info *mtd, uint8_t byte)
-{
- struct nand_chip *chip = mtd_to_nand(mtd);
-
- chip->write_buf(mtd, &byte, 1);
-}
-
-/**
- * nand_write_byte16 - [DEFAULT] write single byte to a chip with width 16
- * @mtd: MTD device structure
- * @byte: value to write
- *
- * Default function to write a byte to I/O[7:0] on a 16-bit wide chip.
- */
-static void nand_write_byte16(struct mtd_info *mtd, uint8_t byte)
-{
- struct nand_chip *chip = mtd_to_nand(mtd);
- uint16_t word = byte;
-
- /*
- * It's not entirely clear what should happen to I/O[15:8] when writing
- * a byte. The ONFi spec (Revision 3.1; 2012-09-19, Section 2.16) reads:
- *
- * When the host supports a 16-bit bus width, only data is
- * transferred at the 16-bit width. All address and command line
- * transfers shall use only the lower 8-bits of the data bus. During
- * command transfers, the host may place any value on the upper
- * 8-bits of the data bus. During address transfers, the host shall
- * set the upper 8-bits of the data bus to 00h.
- *
- * One user of the write_byte callback is nand_set_features. The
- * four parameters are specified to be written to I/O[7:0], but this is
- * neither an address nor a command transfer. Let's assume a 0 on the
- * upper I/O lines is OK.
- */
- chip->write_buf(mtd, (uint8_t *)&word, 2);
-}
-
-/**
- * nand_write_buf - [DEFAULT] write buffer to chip
- * @mtd: MTD device structure
- * @buf: data buffer
- * @len: number of bytes to write
- *
- * Default write function for 8bit buswidth.
- */
-static void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
-{
- struct nand_chip *chip = mtd_to_nand(mtd);
-
- iowrite8_rep(chip->IO_ADDR_W, buf, len);
-}
-
-/**
- * nand_read_buf - [DEFAULT] read chip data into buffer
- * @mtd: MTD device structure
- * @buf: buffer to store date
- * @len: number of bytes to read
- *
- * Default read function for 8bit buswidth.
- */
-static void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
-{
- struct nand_chip *chip = mtd_to_nand(mtd);
-
- ioread8_rep(chip->IO_ADDR_R, buf, len);
-}
-
-/**
- * nand_write_buf16 - [DEFAULT] write buffer to chip
- * @mtd: MTD device structure
- * @buf: data buffer
- * @len: number of bytes to write
- *
- * Default write function for 16bit buswidth.
- */
-static void nand_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
-{
- struct nand_chip *chip = mtd_to_nand(mtd);
- u16 *p = (u16 *) buf;
-
- iowrite16_rep(chip->IO_ADDR_W, p, len >> 1);
-}
-
-/**
- * nand_read_buf16 - [DEFAULT] read chip data into buffer
- * @mtd: MTD device structure
- * @buf: buffer to store date
- * @len: number of bytes to read
- *
- * Default read function for 16bit buswidth.
- */
-static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
-{
- struct nand_chip *chip = mtd_to_nand(mtd);
- u16 *p = (u16 *) buf;
-
- ioread16_rep(chip->IO_ADDR_R, p, len >> 1);
-}
-
-/**
* nand_block_bad - [DEFAULT] Read bad block marker from the chip
- * @mtd: MTD device structure
+ * @chip: NAND chip object
* @ofs: offset from device start
*
* Check, if the block is bad.
*/
-static int nand_block_bad(struct mtd_info *mtd, loff_t ofs)
+static int nand_block_bad(struct nand_chip *chip, loff_t ofs)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
int page, page_end, res;
- struct nand_chip *chip = mtd_to_nand(mtd);
u8 bad;
if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)
@@ -439,7 +272,7 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs)
page_end = page + (chip->bbt_options & NAND_BBT_SCAN2NDPAGE ? 2 : 1);
for (; page < page_end; page++) {
- res = chip->ecc.read_oob(mtd, chip, page);
+ res = chip->ecc.read_oob(chip, page);
if (res < 0)
return res;
@@ -458,16 +291,16 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs)
/**
* nand_default_block_markbad - [DEFAULT] mark a block bad via bad block marker
- * @mtd: MTD device structure
+ * @chip: NAND chip object
* @ofs: offset from device start
*
* This is the default implementation, which can be overridden by a hardware
* specific driver. It provides the details for writing a bad block marker to a
* block.
*/
-static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
+static int nand_default_block_markbad(struct nand_chip *chip, loff_t ofs)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct mtd_oob_ops ops;
uint8_t buf[2] = { 0, 0 };
int ret = 0, res, i = 0;
@@ -499,13 +332,34 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
}
/**
+ * nand_markbad_bbm - mark a block by updating the BBM
+ * @chip: NAND chip object
+ * @ofs: offset of the block to mark bad
+ */
+int nand_markbad_bbm(struct nand_chip *chip, loff_t ofs)
+{
+ if (chip->legacy.block_markbad)
+ return chip->legacy.block_markbad(chip, ofs);
+
+ return nand_default_block_markbad(chip, ofs);
+}
+
+static int nand_isbad_bbm(struct nand_chip *chip, loff_t ofs)
+{
+ if (chip->legacy.block_bad)
+ return chip->legacy.block_bad(chip, ofs);
+
+ return nand_block_bad(chip, ofs);
+}
+
+/**
* nand_block_markbad_lowlevel - mark a block bad
* @mtd: MTD device structure
* @ofs: offset from device start
*
* This function performs the generic NAND bad block marking steps (i.e., bad
* block table(s) and/or marker(s)). We only allow the hardware driver to
- * specify how to write bad block markers to OOB (chip->block_markbad).
+ * specify how to write bad block markers to OOB (chip->legacy.block_markbad).
*
* We try operations in the following order:
*
@@ -529,17 +383,17 @@ static int nand_block_markbad_lowlevel(struct mtd_info *mtd, loff_t ofs)
memset(&einfo, 0, sizeof(einfo));
einfo.addr = ofs;
einfo.len = 1ULL << chip->phys_erase_shift;
- nand_erase_nand(mtd, &einfo, 0);
+ nand_erase_nand(chip, &einfo, 0);
/* Write bad block marker to OOB */
nand_get_device(mtd, FL_WRITING);
- ret = chip->block_markbad(mtd, ofs);
+ ret = nand_markbad_bbm(chip, ofs);
nand_release_device(mtd);
}
/* Mark block bad in BBT */
if (chip->bbt) {
- res = nand_markbad_bbt(mtd, ofs);
+ res = nand_markbad_bbt(chip, ofs);
if (!ret)
ret = res;
}
@@ -589,7 +443,7 @@ static int nand_block_isreserved(struct mtd_info *mtd, loff_t ofs)
if (!chip->bbt)
return 0;
/* Return info from the table */
- return nand_isreserved_bbt(mtd, ofs);
+ return nand_isreserved_bbt(chip, ofs);
}
/**
@@ -605,89 +459,14 @@ static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int allowbbt)
{
struct nand_chip *chip = mtd_to_nand(mtd);
- if (!chip->bbt)
- return chip->block_bad(mtd, ofs);
-
/* Return info from the table */
- return nand_isbad_bbt(mtd, ofs, allowbbt);
-}
+ if (chip->bbt)
+ return nand_isbad_bbt(chip, ofs, allowbbt);
-/**
- * panic_nand_wait_ready - [GENERIC] Wait for the ready pin after commands.
- * @mtd: MTD device structure
- * @timeo: Timeout
- *
- * Helper function for nand_wait_ready used when needing to wait in interrupt
- * context.
- */
-static void panic_nand_wait_ready(struct mtd_info *mtd, unsigned long timeo)
-{
- struct nand_chip *chip = mtd_to_nand(mtd);
- int i;
-
- /* Wait for the device to get ready */
- for (i = 0; i < timeo; i++) {
- if (chip->dev_ready(mtd))
- break;
- touch_softlockup_watchdog();
- mdelay(1);
- }
+ return nand_isbad_bbm(chip, ofs);
}
/**
- * nand_wait_ready - [GENERIC] Wait for the ready pin after commands.
- * @mtd: MTD device structure
- *
- * Wait for the ready pin after a command, and warn if a timeout occurs.
- */
-void nand_wait_ready(struct mtd_info *mtd)
-{
- struct nand_chip *chip = mtd_to_nand(mtd);
- unsigned long timeo = 400;
-
- if (in_interrupt() || oops_in_progress)
- return panic_nand_wait_ready(mtd, timeo);
-
- /* Wait until command is processed or timeout occurs */
- timeo = jiffies + msecs_to_jiffies(timeo);
- do {
- if (chip->dev_ready(mtd))
- return;
- cond_resched();
- } while (time_before(jiffies, timeo));
-
- if (!chip->dev_ready(mtd))
- pr_warn_ratelimited("timeout while waiting for chip to become ready\n");
-}
-EXPORT_SYMBOL_GPL(nand_wait_ready);
-
-/**
- * nand_wait_status_ready - [GENERIC] Wait for the ready status after commands.
- * @mtd: MTD device structure
- * @timeo: Timeout in ms
- *
- * Wait for status ready (i.e. command done) or timeout.
- */
-static void nand_wait_status_ready(struct mtd_info *mtd, unsigned long timeo)
-{
- register struct nand_chip *chip = mtd_to_nand(mtd);
- int ret;
-
- timeo = jiffies + msecs_to_jiffies(timeo);
- do {
- u8 status;
-
- ret = nand_read_data_op(chip, &status, sizeof(status), true);
- if (ret)
- return;
-
- if (status & NAND_STATUS_READY)
- break;
- touch_softlockup_watchdog();
- } while (time_before(jiffies, timeo));
-};
-
-/**
* nand_soft_waitrdy - Poll STATUS reg until RDY bit is set to 1
* @chip: NAND chip structure
* @timeout_ms: Timeout in ms
@@ -753,273 +532,6 @@ int nand_soft_waitrdy(struct nand_chip *chip, unsigned long timeout_ms)
EXPORT_SYMBOL_GPL(nand_soft_waitrdy);
/**
- * nand_command - [DEFAULT] Send command to NAND device
- * @mtd: MTD device structure
- * @command: the command to be sent
- * @column: the column address for this command, -1 if none
- * @page_addr: the page address for this command, -1 if none
- *
- * Send command to NAND device. This function is used for small page devices
- * (512 Bytes per page).
- */
-static void nand_command(struct mtd_info *mtd, unsigned int command,
- int column, int page_addr)
-{
- register struct nand_chip *chip = mtd_to_nand(mtd);
- int ctrl = NAND_CTRL_CLE | NAND_CTRL_CHANGE;
-
- /* Write out the command to the device */
- if (command == NAND_CMD_SEQIN) {
- int readcmd;
-
- if (column >= mtd->writesize) {
- /* OOB area */
- column -= mtd->writesize;
- readcmd = NAND_CMD_READOOB;
- } else if (column < 256) {
- /* First 256 bytes --> READ0 */
- readcmd = NAND_CMD_READ0;
- } else {
- column -= 256;
- readcmd = NAND_CMD_READ1;
- }
- chip->cmd_ctrl(mtd, readcmd, ctrl);
- ctrl &= ~NAND_CTRL_CHANGE;
- }
- if (command != NAND_CMD_NONE)
- chip->cmd_ctrl(mtd, command, ctrl);
-
- /* Address cycle, when necessary */
- ctrl = NAND_CTRL_ALE | NAND_CTRL_CHANGE;
- /* Serially input address */
- if (column != -1) {
- /* Adjust columns for 16 bit buswidth */
- if (chip->options & NAND_BUSWIDTH_16 &&
- !nand_opcode_8bits(command))
- column >>= 1;
- chip->cmd_ctrl(mtd, column, ctrl);
- ctrl &= ~NAND_CTRL_CHANGE;
- }
- if (page_addr != -1) {
- chip->cmd_ctrl(mtd, page_addr, ctrl);
- ctrl &= ~NAND_CTRL_CHANGE;
- chip->cmd_ctrl(mtd, page_addr >> 8, ctrl);
- if (chip->options & NAND_ROW_ADDR_3)
- chip->cmd_ctrl(mtd, page_addr >> 16, ctrl);
- }
- chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
-
- /*
- * Program and erase have their own busy handlers status and sequential
- * in needs no delay
- */
- switch (command) {
-
- case NAND_CMD_NONE:
- case NAND_CMD_PAGEPROG:
- case NAND_CMD_ERASE1:
- case NAND_CMD_ERASE2:
- case NAND_CMD_SEQIN:
- case NAND_CMD_STATUS:
- case NAND_CMD_READID:
- case NAND_CMD_SET_FEATURES:
- return;
-
- case NAND_CMD_RESET:
- if (chip->dev_ready)
- break;
- udelay(chip->chip_delay);
- chip->cmd_ctrl(mtd, NAND_CMD_STATUS,
- NAND_CTRL_CLE | NAND_CTRL_CHANGE);
- chip->cmd_ctrl(mtd,
- NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
- /* EZ-NAND can take upto 250ms as per ONFi v4.0 */
- nand_wait_status_ready(mtd, 250);
- return;
-
- /* This applies to read commands */
- case NAND_CMD_READ0:
- /*
- * READ0 is sometimes used to exit GET STATUS mode. When this
- * is the case no address cycles are requested, and we can use
- * this information to detect that we should not wait for the
- * device to be ready.
- */
- if (column == -1 && page_addr == -1)
- return;
-
- default:
- /*
- * If we don't have access to the busy pin, we apply the given
- * command delay
- */
- if (!chip->dev_ready) {
- udelay(chip->chip_delay);
- return;
- }
- }
- /*
- * Apply this short delay always to ensure that we do wait tWB in
- * any case on any machine.
- */
- ndelay(100);
-
- nand_wait_ready(mtd);
-}
-
-static void nand_ccs_delay(struct nand_chip *chip)
-{
- /*
- * The controller already takes care of waiting for tCCS when the RNDIN
- * or RNDOUT command is sent, return directly.
- */
- if (!(chip->options & NAND_WAIT_TCCS))
- return;
-
- /*
- * Wait tCCS_min if it is correctly defined, otherwise wait 500ns
- * (which should be safe for all NANDs).
- */
- if (chip->setup_data_interface)
- ndelay(chip->data_interface.timings.sdr.tCCS_min / 1000);
- else
- ndelay(500);
-}
-
-/**
- * nand_command_lp - [DEFAULT] Send command to NAND large page device
- * @mtd: MTD device structure
- * @command: the command to be sent
- * @column: the column address for this command, -1 if none
- * @page_addr: the page address for this command, -1 if none
- *
- * Send command to NAND device. This is the version for the new large page
- * devices. We don't have the separate regions as we have in the small page
- * devices. We must emulate NAND_CMD_READOOB to keep the code compatible.
- */
-static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
- int column, int page_addr)
-{
- register struct nand_chip *chip = mtd_to_nand(mtd);
-
- /* Emulate NAND_CMD_READOOB */
- if (command == NAND_CMD_READOOB) {
- column += mtd->writesize;
- command = NAND_CMD_READ0;
- }
-
- /* Command latch cycle */
- if (command != NAND_CMD_NONE)
- chip->cmd_ctrl(mtd, command,
- NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
-
- if (column != -1 || page_addr != -1) {
- int ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE;
-
- /* Serially input address */
- if (column != -1) {
- /* Adjust columns for 16 bit buswidth */
- if (chip->options & NAND_BUSWIDTH_16 &&
- !nand_opcode_8bits(command))
- column >>= 1;
- chip->cmd_ctrl(mtd, column, ctrl);
- ctrl &= ~NAND_CTRL_CHANGE;
-
- /* Only output a single addr cycle for 8bits opcodes. */
- if (!nand_opcode_8bits(command))
- chip->cmd_ctrl(mtd, column >> 8, ctrl);
- }
- if (page_addr != -1) {
- chip->cmd_ctrl(mtd, page_addr, ctrl);
- chip->cmd_ctrl(mtd, page_addr >> 8,
- NAND_NCE | NAND_ALE);
- if (chip->options & NAND_ROW_ADDR_3)
- chip->cmd_ctrl(mtd, page_addr >> 16,
- NAND_NCE | NAND_ALE);
- }
- }
- chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
-
- /*
- * Program and erase have their own busy handlers status, sequential
- * in and status need no delay.
- */
- switch (command) {
-
- case NAND_CMD_NONE:
- case NAND_CMD_CACHEDPROG:
- case NAND_CMD_PAGEPROG:
- case NAND_CMD_ERASE1:
- case NAND_CMD_ERASE2:
- case NAND_CMD_SEQIN:
- case NAND_CMD_STATUS:
- case NAND_CMD_READID:
- case NAND_CMD_SET_FEATURES:
- return;
-
- case NAND_CMD_RNDIN:
- nand_ccs_delay(chip);
- return;
-
- case NAND_CMD_RESET:
- if (chip->dev_ready)
- break;
- udelay(chip->chip_delay);
- chip->cmd_ctrl(mtd, NAND_CMD_STATUS,
- NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
- chip->cmd_ctrl(mtd, NAND_CMD_NONE,
- NAND_NCE | NAND_CTRL_CHANGE);
- /* EZ-NAND can take upto 250ms as per ONFi v4.0 */
- nand_wait_status_ready(mtd, 250);
- return;
-
- case NAND_CMD_RNDOUT:
- /* No ready / busy check necessary */
- chip->cmd_ctrl(mtd, NAND_CMD_RNDOUTSTART,
- NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
- chip->cmd_ctrl(mtd, NAND_CMD_NONE,
- NAND_NCE | NAND_CTRL_CHANGE);
-
- nand_ccs_delay(chip);
- return;
-
- case NAND_CMD_READ0:
- /*
- * READ0 is sometimes used to exit GET STATUS mode. When this
- * is the case no address cycles are requested, and we can use
- * this information to detect that READSTART should not be
- * issued.
- */
- if (column == -1 && page_addr == -1)
- return;
-
- chip->cmd_ctrl(mtd, NAND_CMD_READSTART,
- NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
- chip->cmd_ctrl(mtd, NAND_CMD_NONE,
- NAND_NCE | NAND_CTRL_CHANGE);
-
- /* This applies to read commands */
- default:
- /*
- * If we don't have access to the busy pin, we apply the given
- * command delay.
- */
- if (!chip->dev_ready) {
- udelay(chip->chip_delay);
- return;
- }
- }
-
- /*
- * Apply this short delay always to ensure that we do wait tWB in
- * any case on any machine.
- */
- ndelay(100);
-
- nand_wait_ready(mtd);
-}
-
-/**
* panic_nand_get_device - [GENERIC] Get chip for selected access
* @chip: the nand chip descriptor
* @mtd: MTD device structure
@@ -1086,13 +598,12 @@ retry:
* we are in interrupt context. May happen when in panic and trying to write
* an oops through mtdoops.
*/
-static void panic_nand_wait(struct mtd_info *mtd, struct nand_chip *chip,
- unsigned long timeo)
+void panic_nand_wait(struct nand_chip *chip, unsigned long timeo)
{
int i;
for (i = 0; i < timeo; i++) {
- if (chip->dev_ready) {
- if (chip->dev_ready(mtd))
+ if (chip->legacy.dev_ready) {
+ if (chip->legacy.dev_ready(chip))
break;
} else {
int ret;
@@ -1110,60 +621,6 @@ static void panic_nand_wait(struct mtd_info *mtd, struct nand_chip *chip,
}
}
-/**
- * nand_wait - [DEFAULT] wait until the command is done
- * @mtd: MTD device structure
- * @chip: NAND chip structure
- *
- * Wait for command done. This applies to erase and program only.
- */
-static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
-{
-
- unsigned long timeo = 400;
- u8 status;
- int ret;
-
- /*
- * Apply this short delay always to ensure that we do wait tWB in any
- * case on any machine.
- */
- ndelay(100);
-
- ret = nand_status_op(chip, NULL);
- if (ret)
- return ret;
-
- if (in_interrupt() || oops_in_progress)
- panic_nand_wait(mtd, chip, timeo);
- else {
- timeo = jiffies + msecs_to_jiffies(timeo);
- do {
- if (chip->dev_ready) {
- if (chip->dev_ready(mtd))
- break;
- } else {
- ret = nand_read_data_op(chip, &status,
- sizeof(status), true);
- if (ret)
- return ret;
-
- if (status & NAND_STATUS_READY)
- break;
- }
- cond_resched();
- } while (time_before(jiffies, timeo));
- }
-
- ret = nand_read_data_op(chip, &status, sizeof(status), true);
- if (ret)
- return ret;
-
- /* This can happen if in case of timeout or buggy dev_ready */
- WARN_ON(!(status & NAND_STATUS_READY));
- return status;
-}
-
static bool nand_supports_get_features(struct nand_chip *chip, int addr)
{
return (chip->parameters.supports_set_get_features &&
@@ -1177,48 +634,6 @@ static bool nand_supports_set_features(struct nand_chip *chip, int addr)
}
/**
- * nand_get_features - wrapper to perform a GET_FEATURE
- * @chip: NAND chip info structure
- * @addr: feature address
- * @subfeature_param: the subfeature parameters, a four bytes array
- *
- * Returns 0 for success, a negative error otherwise. Returns -ENOTSUPP if the
- * operation cannot be handled.
- */
-int nand_get_features(struct nand_chip *chip, int addr,
- u8 *subfeature_param)
-{
- struct mtd_info *mtd = nand_to_mtd(chip);
-
- if (!nand_supports_get_features(chip, addr))
- return -ENOTSUPP;
-
- return chip->get_features(mtd, chip, addr, subfeature_param);
-}
-EXPORT_SYMBOL_GPL(nand_get_features);
-
-/**
- * nand_set_features - wrapper to perform a SET_FEATURE
- * @chip: NAND chip info structure
- * @addr: feature address
- * @subfeature_param: the subfeature parameters, a four bytes array
- *
- * Returns 0 for success, a negative error otherwise. Returns -ENOTSUPP if the
- * operation cannot be handled.
- */
-int nand_set_features(struct nand_chip *chip, int addr,
- u8 *subfeature_param)
-{
- struct mtd_info *mtd = nand_to_mtd(chip);
-
- if (!nand_supports_set_features(chip, addr))
- return -ENOTSUPP;
-
- return chip->set_features(mtd, chip, addr, subfeature_param);
-}
-EXPORT_SYMBOL_GPL(nand_set_features);
-
-/**
* nand_reset_data_interface - Reset data interface and timings
* @chip: The NAND chip
* @chipnr: Internal die id
@@ -1229,7 +644,6 @@ EXPORT_SYMBOL_GPL(nand_set_features);
*/
static int nand_reset_data_interface(struct nand_chip *chip, int chipnr)
{
- struct mtd_info *mtd = nand_to_mtd(chip);
int ret;
if (!chip->setup_data_interface)
@@ -1250,7 +664,7 @@ static int nand_reset_data_interface(struct nand_chip *chip, int chipnr)
*/
onfi_fill_data_interface(chip, NAND_SDR_IFACE, 0);
- ret = chip->setup_data_interface(mtd, chipnr, &chip->data_interface);
+ ret = chip->setup_data_interface(chip, chipnr, &chip->data_interface);
if (ret)
pr_err("Failed to configure data interface to SDR timing mode 0\n");
@@ -1272,7 +686,6 @@ static int nand_reset_data_interface(struct nand_chip *chip, int chipnr)
*/
static int nand_setup_data_interface(struct nand_chip *chip, int chipnr)
{
- struct mtd_info *mtd = nand_to_mtd(chip);
u8 tmode_param[ONFI_SUBFEATURE_PARAM_LEN] = {
chip->onfi_timing_mode_default,
};
@@ -1283,16 +696,16 @@ static int nand_setup_data_interface(struct nand_chip *chip, int chipnr)
/* Change the mode on the chip side (if supported by the NAND chip) */
if (nand_supports_set_features(chip, ONFI_FEATURE_ADDR_TIMING_MODE)) {
- chip->select_chip(mtd, chipnr);
+ chip->select_chip(chip, chipnr);
ret = nand_set_features(chip, ONFI_FEATURE_ADDR_TIMING_MODE,
tmode_param);
- chip->select_chip(mtd, -1);
+ chip->select_chip(chip, -1);
if (ret)
return ret;
}
/* Change the mode on the controller side */
- ret = chip->setup_data_interface(mtd, chipnr, &chip->data_interface);
+ ret = chip->setup_data_interface(chip, chipnr, &chip->data_interface);
if (ret)
return ret;
@@ -1301,10 +714,10 @@ static int nand_setup_data_interface(struct nand_chip *chip, int chipnr)
return 0;
memset(tmode_param, 0, ONFI_SUBFEATURE_PARAM_LEN);
- chip->select_chip(mtd, chipnr);
+ chip->select_chip(chip, chipnr);
ret = nand_get_features(chip, ONFI_FEATURE_ADDR_TIMING_MODE,
tmode_param);
- chip->select_chip(mtd, -1);
+ chip->select_chip(chip, -1);
if (ret)
goto err_reset_chip;
@@ -1322,9 +735,9 @@ err_reset_chip:
* timing mode.
*/
nand_reset_data_interface(chip, chipnr);
- chip->select_chip(mtd, chipnr);
+ chip->select_chip(chip, chipnr);
nand_reset_op(chip);
- chip->select_chip(mtd, -1);
+ chip->select_chip(chip, -1);
return ret;
}
@@ -1345,7 +758,6 @@ err_reset_chip:
*/
static int nand_init_data_interface(struct nand_chip *chip)
{
- struct mtd_info *mtd = nand_to_mtd(chip);
int modes, mode, ret;
if (!chip->setup_data_interface)
@@ -1356,15 +768,15 @@ static int nand_init_data_interface(struct nand_chip *chip)
* if the NAND does not support ONFI, fallback to the default ONFI
* timing mode.
*/
- modes = onfi_get_async_timing_mode(chip);
- if (modes == ONFI_TIMING_MODE_UNKNOWN) {
+ if (chip->parameters.onfi) {
+ modes = chip->parameters.onfi->async_timing_mode;
+ } else {
if (!chip->onfi_timing_mode_default)
return 0;
modes = GENMASK(chip->onfi_timing_mode_default, 0);
}
-
for (mode = fls(modes) - 1; mode >= 0; mode--) {
ret = onfi_fill_data_interface(chip, NAND_SDR_IFACE, mode);
if (ret)
@@ -1374,7 +786,7 @@ static int nand_init_data_interface(struct nand_chip *chip)
* Pass NAND_DATA_IFACE_CHECK_ONLY to only check if the
* controller supports the requested timings.
*/
- ret = chip->setup_data_interface(mtd,
+ ret = chip->setup_data_interface(chip,
NAND_DATA_IFACE_CHECK_ONLY,
&chip->data_interface);
if (!ret) {
@@ -1554,9 +966,9 @@ int nand_read_page_op(struct nand_chip *chip, unsigned int page,
buf, len);
}
- chip->cmdfunc(mtd, NAND_CMD_READ0, offset_in_page, page);
+ chip->legacy.cmdfunc(chip, NAND_CMD_READ0, offset_in_page, page);
if (len)
- chip->read_buf(mtd, buf, len);
+ chip->legacy.read_buf(chip, buf, len);
return 0;
}
@@ -1574,10 +986,9 @@ EXPORT_SYMBOL_GPL(nand_read_page_op);
*
* Returns 0 on success, a negative error code otherwise.
*/
-static int nand_read_param_page_op(struct nand_chip *chip, u8 page, void *buf,
- unsigned int len)
+int nand_read_param_page_op(struct nand_chip *chip, u8 page, void *buf,
+ unsigned int len)
{
- struct mtd_info *mtd = nand_to_mtd(chip);
unsigned int i;
u8 *p = buf;
@@ -1603,9 +1014,9 @@ static int nand_read_param_page_op(struct nand_chip *chip, u8 page, void *buf,
return nand_exec_op(chip, &op);
}
- chip->cmdfunc(mtd, NAND_CMD_PARAM, page, -1);
+ chip->legacy.cmdfunc(chip, NAND_CMD_PARAM, page, -1);
for (i = 0; i < len; i++)
- p[i] = chip->read_byte(mtd);
+ p[i] = chip->legacy.read_byte(chip);
return 0;
}
@@ -1666,9 +1077,9 @@ int nand_change_read_column_op(struct nand_chip *chip,
return nand_exec_op(chip, &op);
}
- chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset_in_page, -1);
+ chip->legacy.cmdfunc(chip, NAND_CMD_RNDOUT, offset_in_page, -1);
if (len)
- chip->read_buf(mtd, buf, len);
+ chip->legacy.read_buf(chip, buf, len);
return 0;
}
@@ -1703,9 +1114,9 @@ int nand_read_oob_op(struct nand_chip *chip, unsigned int page,
mtd->writesize + offset_in_oob,
buf, len);
- chip->cmdfunc(mtd, NAND_CMD_READOOB, offset_in_oob, page);
+ chip->legacy.cmdfunc(chip, NAND_CMD_READOOB, offset_in_oob, page);
if (len)
- chip->read_buf(mtd, buf, len);
+ chip->legacy.read_buf(chip, buf, len);
return 0;
}
@@ -1815,10 +1226,10 @@ int nand_prog_page_begin_op(struct nand_chip *chip, unsigned int page,
return nand_exec_prog_page_op(chip, page, offset_in_page, buf,
len, false);
- chip->cmdfunc(mtd, NAND_CMD_SEQIN, offset_in_page, page);
+ chip->legacy.cmdfunc(chip, NAND_CMD_SEQIN, offset_in_page, page);
if (buf)
- chip->write_buf(mtd, buf, len);
+ chip->legacy.write_buf(chip, buf, len);
return 0;
}
@@ -1835,7 +1246,6 @@ EXPORT_SYMBOL_GPL(nand_prog_page_begin_op);
*/
int nand_prog_page_end_op(struct nand_chip *chip)
{
- struct mtd_info *mtd = nand_to_mtd(chip);
int ret;
u8 status;
@@ -1857,8 +1267,8 @@ int nand_prog_page_end_op(struct nand_chip *chip)
if (ret)
return ret;
} else {
- chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
- ret = chip->waitfunc(mtd, chip);
+ chip->legacy.cmdfunc(chip, NAND_CMD_PAGEPROG, -1, -1);
+ ret = chip->legacy.waitfunc(chip);
if (ret < 0)
return ret;
@@ -1902,10 +1312,11 @@ int nand_prog_page_op(struct nand_chip *chip, unsigned int page,
status = nand_exec_prog_page_op(chip, page, offset_in_page, buf,
len, true);
} else {
- chip->cmdfunc(mtd, NAND_CMD_SEQIN, offset_in_page, page);
- chip->write_buf(mtd, buf, len);
- chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
- status = chip->waitfunc(mtd, chip);
+ chip->legacy.cmdfunc(chip, NAND_CMD_SEQIN, offset_in_page,
+ page);
+ chip->legacy.write_buf(chip, buf, len);
+ chip->legacy.cmdfunc(chip, NAND_CMD_PAGEPROG, -1, -1);
+ status = chip->legacy.waitfunc(chip);
}
if (status & NAND_STATUS_FAIL)
@@ -1970,9 +1381,9 @@ int nand_change_write_column_op(struct nand_chip *chip,
return nand_exec_op(chip, &op);
}
- chip->cmdfunc(mtd, NAND_CMD_RNDIN, offset_in_page, -1);
+ chip->legacy.cmdfunc(chip, NAND_CMD_RNDIN, offset_in_page, -1);
if (len)
- chip->write_buf(mtd, buf, len);
+ chip->legacy.write_buf(chip, buf, len);
return 0;
}
@@ -1994,7 +1405,6 @@ EXPORT_SYMBOL_GPL(nand_change_write_column_op);
int nand_readid_op(struct nand_chip *chip, u8 addr, void *buf,
unsigned int len)
{
- struct mtd_info *mtd = nand_to_mtd(chip);
unsigned int i;
u8 *id = buf;
@@ -2018,10 +1428,10 @@ int nand_readid_op(struct nand_chip *chip, u8 addr, void *buf,
return nand_exec_op(chip, &op);
}
- chip->cmdfunc(mtd, NAND_CMD_READID, addr, -1);
+ chip->legacy.cmdfunc(chip, NAND_CMD_READID, addr, -1);
for (i = 0; i < len; i++)
- id[i] = chip->read_byte(mtd);
+ id[i] = chip->legacy.read_byte(chip);
return 0;
}
@@ -2040,8 +1450,6 @@ EXPORT_SYMBOL_GPL(nand_readid_op);
*/
int nand_status_op(struct nand_chip *chip, u8 *status)
{
- struct mtd_info *mtd = nand_to_mtd(chip);
-
if (chip->exec_op) {
const struct nand_sdr_timings *sdr =
nand_get_sdr_timings(&chip->data_interface);
@@ -2058,9 +1466,9 @@ int nand_status_op(struct nand_chip *chip, u8 *status)
return nand_exec_op(chip, &op);
}
- chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
+ chip->legacy.cmdfunc(chip, NAND_CMD_STATUS, -1, -1);
if (status)
- *status = chip->read_byte(mtd);
+ *status = chip->legacy.read_byte(chip);
return 0;
}
@@ -2079,8 +1487,6 @@ EXPORT_SYMBOL_GPL(nand_status_op);
*/
int nand_exit_status_op(struct nand_chip *chip)
{
- struct mtd_info *mtd = nand_to_mtd(chip);
-
if (chip->exec_op) {
struct nand_op_instr instrs[] = {
NAND_OP_CMD(NAND_CMD_READ0, 0),
@@ -2090,11 +1496,10 @@ int nand_exit_status_op(struct nand_chip *chip)
return nand_exec_op(chip, &op);
}
- chip->cmdfunc(mtd, NAND_CMD_READ0, -1, -1);
+ chip->legacy.cmdfunc(chip, NAND_CMD_READ0, -1, -1);
return 0;
}
-EXPORT_SYMBOL_GPL(nand_exit_status_op);
/**
* nand_erase_op - Do an erase operation
@@ -2109,7 +1514,6 @@ EXPORT_SYMBOL_GPL(nand_exit_status_op);
*/
int nand_erase_op(struct nand_chip *chip, unsigned int eraseblock)
{
- struct mtd_info *mtd = nand_to_mtd(chip);
unsigned int page = eraseblock <<
(chip->phys_erase_shift - chip->page_shift);
int ret;
@@ -2139,10 +1543,10 @@ int nand_erase_op(struct nand_chip *chip, unsigned int eraseblock)
if (ret)
return ret;
} else {
- chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page);
- chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1);
+ chip->legacy.cmdfunc(chip, NAND_CMD_ERASE1, -1, page);
+ chip->legacy.cmdfunc(chip, NAND_CMD_ERASE2, -1, -1);
- ret = chip->waitfunc(mtd, chip);
+ ret = chip->legacy.waitfunc(chip);
if (ret < 0)
return ret;
@@ -2171,7 +1575,6 @@ EXPORT_SYMBOL_GPL(nand_erase_op);
static int nand_set_features_op(struct nand_chip *chip, u8 feature,
const void *data)
{
- struct mtd_info *mtd = nand_to_mtd(chip);
const u8 *params = data;
int i, ret;
@@ -2190,11 +1593,11 @@ static int nand_set_features_op(struct nand_chip *chip, u8 feature,
return nand_exec_op(chip, &op);
}
- chip->cmdfunc(mtd, NAND_CMD_SET_FEATURES, feature, -1);
+ chip->legacy.cmdfunc(chip, NAND_CMD_SET_FEATURES, feature, -1);
for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
- chip->write_byte(mtd, params[i]);
+ chip->legacy.write_byte(chip, params[i]);
- ret = chip->waitfunc(mtd, chip);
+ ret = chip->legacy.waitfunc(chip);
if (ret < 0)
return ret;
@@ -2219,7 +1622,6 @@ static int nand_set_features_op(struct nand_chip *chip, u8 feature,
static int nand_get_features_op(struct nand_chip *chip, u8 feature,
void *data)
{
- struct mtd_info *mtd = nand_to_mtd(chip);
u8 *params = data;
int i;
@@ -2239,9 +1641,31 @@ static int nand_get_features_op(struct nand_chip *chip, u8 feature,
return nand_exec_op(chip, &op);
}
- chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES, feature, -1);
+ chip->legacy.cmdfunc(chip, NAND_CMD_GET_FEATURES, feature, -1);
for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
- params[i] = chip->read_byte(mtd);
+ params[i] = chip->legacy.read_byte(chip);
+
+ return 0;
+}
+
+static int nand_wait_rdy_op(struct nand_chip *chip, unsigned int timeout_ms,
+ unsigned int delay_ns)
+{
+ if (chip->exec_op) {
+ struct nand_op_instr instrs[] = {
+ NAND_OP_WAIT_RDY(PSEC_TO_MSEC(timeout_ms),
+ PSEC_TO_NSEC(delay_ns)),
+ };
+ struct nand_operation op = NAND_OPERATION(instrs);
+
+ return nand_exec_op(chip, &op);
+ }
+
+ /* Apply delay or wait for ready/busy pin */
+ if (!chip->legacy.dev_ready)
+ udelay(chip->legacy.chip_delay);
+ else
+ nand_wait_ready(chip);
return 0;
}
@@ -2258,8 +1682,6 @@ static int nand_get_features_op(struct nand_chip *chip, u8 feature,
*/
int nand_reset_op(struct nand_chip *chip)
{
- struct mtd_info *mtd = nand_to_mtd(chip);
-
if (chip->exec_op) {
const struct nand_sdr_timings *sdr =
nand_get_sdr_timings(&chip->data_interface);
@@ -2272,7 +1694,7 @@ int nand_reset_op(struct nand_chip *chip)
return nand_exec_op(chip, &op);
}
- chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
+ chip->legacy.cmdfunc(chip, NAND_CMD_RESET, -1, -1);
return 0;
}
@@ -2294,8 +1716,6 @@ EXPORT_SYMBOL_GPL(nand_reset_op);
int nand_read_data_op(struct nand_chip *chip, void *buf, unsigned int len,
bool force_8bit)
{
- struct mtd_info *mtd = nand_to_mtd(chip);
-
if (!len || !buf)
return -EINVAL;
@@ -2315,9 +1735,9 @@ int nand_read_data_op(struct nand_chip *chip, void *buf, unsigned int len,
unsigned int i;
for (i = 0; i < len; i++)
- p[i] = chip->read_byte(mtd);
+ p[i] = chip->legacy.read_byte(chip);
} else {
- chip->read_buf(mtd, buf, len);
+ chip->legacy.read_buf(chip, buf, len);
}
return 0;
@@ -2340,8 +1760,6 @@ EXPORT_SYMBOL_GPL(nand_read_data_op);
int nand_write_data_op(struct nand_chip *chip, const void *buf,
unsigned int len, bool force_8bit)
{
- struct mtd_info *mtd = nand_to_mtd(chip);
-
if (!len || !buf)
return -EINVAL;
@@ -2361,9 +1779,9 @@ int nand_write_data_op(struct nand_chip *chip, const void *buf,
unsigned int i;
for (i = 0; i < len; i++)
- chip->write_byte(mtd, p[i]);
+ chip->legacy.write_byte(chip, p[i]);
} else {
- chip->write_buf(mtd, buf, len);
+ chip->legacy.write_buf(chip, buf, len);
}
return 0;
@@ -2798,7 +2216,6 @@ EXPORT_SYMBOL_GPL(nand_subop_get_data_len);
*/
int nand_reset(struct nand_chip *chip, int chipnr)
{
- struct mtd_info *mtd = nand_to_mtd(chip);
struct nand_data_interface saved_data_intf = chip->data_interface;
int ret;
@@ -2810,9 +2227,9 @@ int nand_reset(struct nand_chip *chip, int chipnr)
* The CS line has to be released before we can apply the new NAND
* interface settings, hence this weird ->select_chip() dance.
*/
- chip->select_chip(mtd, chipnr);
+ chip->select_chip(chip, chipnr);
ret = nand_reset_op(chip);
- chip->select_chip(mtd, -1);
+ chip->select_chip(chip, -1);
if (ret)
return ret;
@@ -2836,6 +2253,48 @@ int nand_reset(struct nand_chip *chip, int chipnr)
EXPORT_SYMBOL_GPL(nand_reset);
/**
+ * nand_get_features - wrapper to perform a GET_FEATURE
+ * @chip: NAND chip info structure
+ * @addr: feature address
+ * @subfeature_param: the subfeature parameters, a four bytes array
+ *
+ * Returns 0 for success, a negative error otherwise. Returns -ENOTSUPP if the
+ * operation cannot be handled.
+ */
+int nand_get_features(struct nand_chip *chip, int addr,
+ u8 *subfeature_param)
+{
+ if (!nand_supports_get_features(chip, addr))
+ return -ENOTSUPP;
+
+ if (chip->legacy.get_features)
+ return chip->legacy.get_features(chip, addr, subfeature_param);
+
+ return nand_get_features_op(chip, addr, subfeature_param);
+}
+
+/**
+ * nand_set_features - wrapper to perform a SET_FEATURE
+ * @chip: NAND chip info structure
+ * @addr: feature address
+ * @subfeature_param: the subfeature parameters, a four bytes array
+ *
+ * Returns 0 for success, a negative error otherwise. Returns -ENOTSUPP if the
+ * operation cannot be handled.
+ */
+int nand_set_features(struct nand_chip *chip, int addr,
+ u8 *subfeature_param)
+{
+ if (!nand_supports_set_features(chip, addr))
+ return -ENOTSUPP;
+
+ if (chip->legacy.set_features)
+ return chip->legacy.set_features(chip, addr, subfeature_param);
+
+ return nand_set_features_op(chip, addr, subfeature_param);
+}
+
+/**
* nand_check_erased_buf - check if a buffer contains (almost) only 0xff data
* @buf: buffer to test
* @len: buffer length
@@ -2968,7 +2427,6 @@ EXPORT_SYMBOL(nand_check_erased_ecc_chunk);
/**
* nand_read_page_raw_notsupp - dummy read raw page function
- * @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: buffer to store read data
* @oob_required: caller requires OOB data read to chip->oob_poi
@@ -2976,16 +2434,14 @@ EXPORT_SYMBOL(nand_check_erased_ecc_chunk);
*
* Returns -ENOTSUPP unconditionally.
*/
-int nand_read_page_raw_notsupp(struct mtd_info *mtd, struct nand_chip *chip,
- u8 *buf, int oob_required, int page)
+int nand_read_page_raw_notsupp(struct nand_chip *chip, u8 *buf,
+ int oob_required, int page)
{
return -ENOTSUPP;
}
-EXPORT_SYMBOL(nand_read_page_raw_notsupp);
/**
* nand_read_page_raw - [INTERN] read raw page data without ecc
- * @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: buffer to store read data
* @oob_required: caller requires OOB data read to chip->oob_poi
@@ -2993,9 +2449,10 @@ EXPORT_SYMBOL(nand_read_page_raw_notsupp);
*
* Not for syndrome calculating ECC controllers, which use a special oob layout.
*/
-int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
- uint8_t *buf, int oob_required, int page)
+int nand_read_page_raw(struct nand_chip *chip, uint8_t *buf, int oob_required,
+ int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
int ret;
ret = nand_read_page_op(chip, page, 0, buf, mtd->writesize);
@@ -3015,7 +2472,6 @@ EXPORT_SYMBOL(nand_read_page_raw);
/**
* nand_read_page_raw_syndrome - [INTERN] read raw page data without ecc
- * @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: buffer to store read data
* @oob_required: caller requires OOB data read to chip->oob_poi
@@ -3023,10 +2479,10 @@ EXPORT_SYMBOL(nand_read_page_raw);
*
* We need a special oob layout and handling even when OOB isn't used.
*/
-static int nand_read_page_raw_syndrome(struct mtd_info *mtd,
- struct nand_chip *chip, uint8_t *buf,
+static int nand_read_page_raw_syndrome(struct nand_chip *chip, uint8_t *buf,
int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
int eccsize = chip->ecc.size;
int eccbytes = chip->ecc.bytes;
uint8_t *oob = chip->oob_poi;
@@ -3080,15 +2536,15 @@ static int nand_read_page_raw_syndrome(struct mtd_info *mtd,
/**
* nand_read_page_swecc - [REPLACEABLE] software ECC based page read function
- * @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: buffer to store read data
* @oob_required: caller requires OOB data read to chip->oob_poi
* @page: page number to read
*/
-static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
- uint8_t *buf, int oob_required, int page)
+static int nand_read_page_swecc(struct nand_chip *chip, uint8_t *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
int i, eccsize = chip->ecc.size, ret;
int eccbytes = chip->ecc.bytes;
int eccsteps = chip->ecc.steps;
@@ -3097,10 +2553,10 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *ecc_code = chip->ecc.code_buf;
unsigned int max_bitflips = 0;
- chip->ecc.read_page_raw(mtd, chip, buf, 1, page);
+ chip->ecc.read_page_raw(chip, buf, 1, page);
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
- chip->ecc.calculate(mtd, p, &ecc_calc[i]);
+ chip->ecc.calculate(chip, p, &ecc_calc[i]);
ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0,
chip->ecc.total);
@@ -3113,7 +2569,7 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
int stat;
- stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
+ stat = chip->ecc.correct(chip, p, &ecc_code[i], &ecc_calc[i]);
if (stat < 0) {
mtd->ecc_stats.failed++;
} else {
@@ -3126,17 +2582,16 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
/**
* nand_read_subpage - [REPLACEABLE] ECC based sub-page read function
- * @mtd: mtd info structure
* @chip: nand chip info structure
* @data_offs: offset of requested data within the page
* @readlen: data length
* @bufpoi: buffer to store read data
* @page: page number to read
*/
-static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
- uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi,
- int page)
+static int nand_read_subpage(struct nand_chip *chip, uint32_t data_offs,
+ uint32_t readlen, uint8_t *bufpoi, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
int start_step, end_step, num_steps, ret;
uint8_t *p;
int data_col_addr, i, gaps = 0;
@@ -3165,7 +2620,7 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
/* Calculate ECC */
for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size)
- chip->ecc.calculate(mtd, p, &chip->ecc.calc_buf[i]);
+ chip->ecc.calculate(chip, p, &chip->ecc.calc_buf[i]);
/*
* The performance is faster if we position offsets according to
@@ -3214,7 +2669,7 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size) {
int stat;
- stat = chip->ecc.correct(mtd, p, &chip->ecc.code_buf[i],
+ stat = chip->ecc.correct(chip, p, &chip->ecc.code_buf[i],
&chip->ecc.calc_buf[i]);
if (stat == -EBADMSG &&
(chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) {
@@ -3238,7 +2693,6 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
/**
* nand_read_page_hwecc - [REPLACEABLE] hardware ECC based page read function
- * @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: buffer to store read data
* @oob_required: caller requires OOB data read to chip->oob_poi
@@ -3246,9 +2700,10 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
*
* Not for syndrome calculating ECC controllers which need a special oob layout.
*/
-static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
- uint8_t *buf, int oob_required, int page)
+static int nand_read_page_hwecc(struct nand_chip *chip, uint8_t *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
int i, eccsize = chip->ecc.size, ret;
int eccbytes = chip->ecc.bytes;
int eccsteps = chip->ecc.steps;
@@ -3262,13 +2717,13 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
return ret;
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
- chip->ecc.hwctl(mtd, NAND_ECC_READ);
+ chip->ecc.hwctl(chip, NAND_ECC_READ);
ret = nand_read_data_op(chip, p, eccsize, false);
if (ret)
return ret;
- chip->ecc.calculate(mtd, p, &ecc_calc[i]);
+ chip->ecc.calculate(chip, p, &ecc_calc[i]);
}
ret = nand_read_data_op(chip, chip->oob_poi, mtd->oobsize, false);
@@ -3286,7 +2741,7 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
int stat;
- stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
+ stat = chip->ecc.correct(chip, p, &ecc_code[i], &ecc_calc[i]);
if (stat == -EBADMSG &&
(chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) {
/* check for empty pages with bitflips */
@@ -3308,7 +2763,6 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
/**
* nand_read_page_hwecc_oob_first - [REPLACEABLE] hw ecc, read oob first
- * @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: buffer to store read data
* @oob_required: caller requires OOB data read to chip->oob_poi
@@ -3320,9 +2774,10 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
* multiple ECC steps, follows the "infix ECC" scheme and reads/writes ECC from
* the data area, by overwriting the NAND manufacturer bad block markings.
*/
-static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,
- struct nand_chip *chip, uint8_t *buf, int oob_required, int page)
+static int nand_read_page_hwecc_oob_first(struct nand_chip *chip, uint8_t *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
int i, eccsize = chip->ecc.size, ret;
int eccbytes = chip->ecc.bytes;
int eccsteps = chip->ecc.steps;
@@ -3348,15 +2803,15 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
int stat;
- chip->ecc.hwctl(mtd, NAND_ECC_READ);
+ chip->ecc.hwctl(chip, NAND_ECC_READ);
ret = nand_read_data_op(chip, p, eccsize, false);
if (ret)
return ret;
- chip->ecc.calculate(mtd, p, &ecc_calc[i]);
+ chip->ecc.calculate(chip, p, &ecc_calc[i]);
- stat = chip->ecc.correct(mtd, p, &ecc_code[i], NULL);
+ stat = chip->ecc.correct(chip, p, &ecc_code[i], NULL);
if (stat == -EBADMSG &&
(chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) {
/* check for empty pages with bitflips */
@@ -3378,7 +2833,6 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,
/**
* nand_read_page_syndrome - [REPLACEABLE] hardware ECC syndrome based page read
- * @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: buffer to store read data
* @oob_required: caller requires OOB data read to chip->oob_poi
@@ -3387,9 +2841,10 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,
* The hw generator calculates the error syndrome automatically. Therefore we
* need a special oob layout and handling.
*/
-static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
- uint8_t *buf, int oob_required, int page)
+static int nand_read_page_syndrome(struct nand_chip *chip, uint8_t *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
int ret, i, eccsize = chip->ecc.size;
int eccbytes = chip->ecc.bytes;
int eccsteps = chip->ecc.steps;
@@ -3405,7 +2860,7 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
int stat;
- chip->ecc.hwctl(mtd, NAND_ECC_READ);
+ chip->ecc.hwctl(chip, NAND_ECC_READ);
ret = nand_read_data_op(chip, p, eccsize, false);
if (ret)
@@ -3420,13 +2875,13 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
oob += chip->ecc.prepad;
}
- chip->ecc.hwctl(mtd, NAND_ECC_READSYN);
+ chip->ecc.hwctl(chip, NAND_ECC_READSYN);
ret = nand_read_data_op(chip, oob, eccbytes, false);
if (ret)
return ret;
- stat = chip->ecc.correct(mtd, p, oob, NULL);
+ stat = chip->ecc.correct(chip, p, oob, NULL);
oob += eccbytes;
@@ -3502,17 +2957,15 @@ static uint8_t *nand_transfer_oob(struct mtd_info *mtd, uint8_t *oob,
/**
* nand_setup_read_retry - [INTERN] Set the READ RETRY mode
- * @mtd: MTD device structure
+ * @chip: NAND chip object
* @retry_mode: the retry mode to use
*
* Some vendors supply a special command to shift the Vt threshold, to be used
* when there are too many bitflips in a page (i.e., ECC error). After setting
* a new threshold, the host should retry reading the page.
*/
-static int nand_setup_read_retry(struct mtd_info *mtd, int retry_mode)
+static int nand_setup_read_retry(struct nand_chip *chip, int retry_mode)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
-
pr_debug("setting READ RETRY mode %d\n", retry_mode);
if (retry_mode >= chip->read_retries)
@@ -3521,7 +2974,18 @@ static int nand_setup_read_retry(struct mtd_info *mtd, int retry_mode)
if (!chip->setup_read_retry)
return -EOPNOTSUPP;
- return chip->setup_read_retry(mtd, retry_mode);
+ return chip->setup_read_retry(chip, retry_mode);
+}
+
+static void nand_wait_readrdy(struct nand_chip *chip)
+{
+ const struct nand_sdr_timings *sdr;
+
+ if (!(chip->options & NAND_NEED_READRDY))
+ return;
+
+ sdr = nand_get_sdr_timings(&chip->data_interface);
+ WARN_ON(nand_wait_rdy_op(chip, PSEC_TO_MSEC(sdr->tR_max), 0));
}
/**
@@ -3549,7 +3013,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
bool ecc_fail = false;
chipnr = (int)(from >> chip->chip_shift);
- chip->select_chip(mtd, chipnr);
+ chip->select_chip(chip, chipnr);
realpage = (int)(from >> chip->page_shift);
page = realpage & chip->pagemask;
@@ -3589,16 +3053,15 @@ read_retry:
* the read methods return max bitflips per ecc step.
*/
if (unlikely(ops->mode == MTD_OPS_RAW))
- ret = chip->ecc.read_page_raw(mtd, chip, bufpoi,
+ ret = chip->ecc.read_page_raw(chip, bufpoi,
oob_required,
page);
else if (!aligned && NAND_HAS_SUBPAGE_READ(chip) &&
!oob)
- ret = chip->ecc.read_subpage(mtd, chip,
- col, bytes, bufpoi,
- page);
+ ret = chip->ecc.read_subpage(chip, col, bytes,
+ bufpoi, page);
else
- ret = chip->ecc.read_page(mtd, chip, bufpoi,
+ ret = chip->ecc.read_page(chip, bufpoi,
oob_required, page);
if (ret < 0) {
if (use_bufpoi)
@@ -3631,18 +3094,12 @@ read_retry:
}
}
- if (chip->options & NAND_NEED_READRDY) {
- /* Apply delay or wait for ready/busy pin */
- if (!chip->dev_ready)
- udelay(chip->chip_delay);
- else
- nand_wait_ready(mtd);
- }
+ nand_wait_readrdy(chip);
if (mtd->ecc_stats.failed - ecc_failures) {
if (retry_mode + 1 < chip->read_retries) {
retry_mode++;
- ret = nand_setup_read_retry(mtd,
+ ret = nand_setup_read_retry(chip,
retry_mode);
if (ret < 0)
break;
@@ -3669,7 +3126,7 @@ read_retry:
/* Reset to retry mode 0 */
if (retry_mode) {
- ret = nand_setup_read_retry(mtd, 0);
+ ret = nand_setup_read_retry(chip, 0);
if (ret < 0)
break;
retry_mode = 0;
@@ -3687,11 +3144,11 @@ read_retry:
/* Check, if we cross a chip boundary */
if (!page) {
chipnr++;
- chip->select_chip(mtd, -1);
- chip->select_chip(mtd, chipnr);
+ chip->select_chip(chip, -1);
+ chip->select_chip(chip, chipnr);
}
}
- chip->select_chip(mtd, -1);
+ chip->select_chip(chip, -1);
ops->retlen = ops->len - (size_t) readlen;
if (oob)
@@ -3708,12 +3165,13 @@ read_retry:
/**
* nand_read_oob_std - [REPLACEABLE] the most common OOB data read function
- * @mtd: mtd info structure
* @chip: nand chip info structure
* @page: page number to read
*/
-int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page)
+int nand_read_oob_std(struct nand_chip *chip, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
return nand_read_oob_op(chip, page, 0, chip->oob_poi, mtd->oobsize);
}
EXPORT_SYMBOL(nand_read_oob_std);
@@ -3721,13 +3179,12 @@ EXPORT_SYMBOL(nand_read_oob_std);
/**
* nand_read_oob_syndrome - [REPLACEABLE] OOB data read function for HW ECC
* with syndromes
- * @mtd: mtd info structure
* @chip: nand chip info structure
* @page: page number to read
*/
-int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
- int page)
+static int nand_read_oob_syndrome(struct nand_chip *chip, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
int length = mtd->oobsize;
int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad;
int eccsize = chip->ecc.size;
@@ -3772,16 +3229,16 @@ int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
return 0;
}
-EXPORT_SYMBOL(nand_read_oob_syndrome);
/**
* nand_write_oob_std - [REPLACEABLE] the most common OOB data write function
- * @mtd: mtd info structure
* @chip: nand chip info structure
* @page: page number to write
*/
-int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page)
+int nand_write_oob_std(struct nand_chip *chip, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
return nand_prog_page_op(chip, page, mtd->writesize, chip->oob_poi,
mtd->oobsize);
}
@@ -3790,13 +3247,12 @@ EXPORT_SYMBOL(nand_write_oob_std);
/**
* nand_write_oob_syndrome - [REPLACEABLE] OOB data write function for HW ECC
* with syndrome - only for large page flash
- * @mtd: mtd info structure
* @chip: nand chip info structure
* @page: page number to write
*/
-int nand_write_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
- int page)
+static int nand_write_oob_syndrome(struct nand_chip *chip, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad;
int eccsize = chip->ecc.size, length = mtd->oobsize;
int ret, i, len, pos, sndcmd = 0, steps = chip->ecc.steps;
@@ -3860,7 +3316,6 @@ int nand_write_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
return nand_prog_page_end_op(chip);
}
-EXPORT_SYMBOL(nand_write_oob_syndrome);
/**
* nand_do_read_oob - [INTERN] NAND read out-of-band
@@ -3890,7 +3345,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
len = mtd_oobavail(mtd, ops);
chipnr = (int)(from >> chip->chip_shift);
- chip->select_chip(mtd, chipnr);
+ chip->select_chip(chip, chipnr);
/* Shift to get page */
realpage = (int)(from >> chip->page_shift);
@@ -3898,9 +3353,9 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
while (1) {
if (ops->mode == MTD_OPS_RAW)
- ret = chip->ecc.read_oob_raw(mtd, chip, page);
+ ret = chip->ecc.read_oob_raw(chip, page);
else
- ret = chip->ecc.read_oob(mtd, chip, page);
+ ret = chip->ecc.read_oob(chip, page);
if (ret < 0)
break;
@@ -3908,13 +3363,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
len = min(len, readlen);
buf = nand_transfer_oob(mtd, buf, ops, len);
- if (chip->options & NAND_NEED_READRDY) {
- /* Apply delay or wait for ready/busy pin */
- if (!chip->dev_ready)
- udelay(chip->chip_delay);
- else
- nand_wait_ready(mtd);
- }
+ nand_wait_readrdy(chip);
max_bitflips = max_t(unsigned int, max_bitflips, ret);
@@ -3929,11 +3378,11 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
/* Check, if we cross a chip boundary */
if (!page) {
chipnr++;
- chip->select_chip(mtd, -1);
- chip->select_chip(mtd, chipnr);
+ chip->select_chip(chip, -1);
+ chip->select_chip(chip, chipnr);
}
}
- chip->select_chip(mtd, -1);
+ chip->select_chip(chip, -1);
ops->oobretlen = ops->ooblen - readlen;
@@ -3979,7 +3428,6 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from,
/**
* nand_write_page_raw_notsupp - dummy raw page write function
- * @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: data buffer
* @oob_required: must write chip->oob_poi to OOB
@@ -3987,16 +3435,14 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from,
*
* Returns -ENOTSUPP unconditionally.
*/
-int nand_write_page_raw_notsupp(struct mtd_info *mtd, struct nand_chip *chip,
- const u8 *buf, int oob_required, int page)
+int nand_write_page_raw_notsupp(struct nand_chip *chip, const u8 *buf,
+ int oob_required, int page)
{
return -ENOTSUPP;
}
-EXPORT_SYMBOL(nand_write_page_raw_notsupp);
/**
* nand_write_page_raw - [INTERN] raw page write function
- * @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: data buffer
* @oob_required: must write chip->oob_poi to OOB
@@ -4004,9 +3450,10 @@ EXPORT_SYMBOL(nand_write_page_raw_notsupp);
*
* Not for syndrome calculating ECC controllers, which use a special oob layout.
*/
-int nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
- const uint8_t *buf, int oob_required, int page)
+int nand_write_page_raw(struct nand_chip *chip, const uint8_t *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
int ret;
ret = nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize);
@@ -4026,7 +3473,6 @@ EXPORT_SYMBOL(nand_write_page_raw);
/**
* nand_write_page_raw_syndrome - [INTERN] raw page write function
- * @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: data buffer
* @oob_required: must write chip->oob_poi to OOB
@@ -4034,11 +3480,11 @@ EXPORT_SYMBOL(nand_write_page_raw);
*
* We need a special oob layout and handling even when ECC isn't checked.
*/
-static int nand_write_page_raw_syndrome(struct mtd_info *mtd,
- struct nand_chip *chip,
+static int nand_write_page_raw_syndrome(struct nand_chip *chip,
const uint8_t *buf, int oob_required,
int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
int eccsize = chip->ecc.size;
int eccbytes = chip->ecc.bytes;
uint8_t *oob = chip->oob_poi;
@@ -4091,16 +3537,15 @@ static int nand_write_page_raw_syndrome(struct mtd_info *mtd,
}
/**
* nand_write_page_swecc - [REPLACEABLE] software ECC based page write function
- * @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: data buffer
* @oob_required: must write chip->oob_poi to OOB
* @page: page number to write
*/
-static int nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
- const uint8_t *buf, int oob_required,
- int page)
+static int nand_write_page_swecc(struct nand_chip *chip, const uint8_t *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
int i, eccsize = chip->ecc.size, ret;
int eccbytes = chip->ecc.bytes;
int eccsteps = chip->ecc.steps;
@@ -4109,28 +3554,27 @@ static int nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
/* Software ECC calculation */
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
- chip->ecc.calculate(mtd, p, &ecc_calc[i]);
+ chip->ecc.calculate(chip, p, &ecc_calc[i]);
ret = mtd_ooblayout_set_eccbytes(mtd, ecc_calc, chip->oob_poi, 0,
chip->ecc.total);
if (ret)
return ret;
- return chip->ecc.write_page_raw(mtd, chip, buf, 1, page);
+ return chip->ecc.write_page_raw(chip, buf, 1, page);
}
/**
* nand_write_page_hwecc - [REPLACEABLE] hardware ECC based page write function
- * @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: data buffer
* @oob_required: must write chip->oob_poi to OOB
* @page: page number to write
*/
-static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
- const uint8_t *buf, int oob_required,
- int page)
+static int nand_write_page_hwecc(struct nand_chip *chip, const uint8_t *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
int i, eccsize = chip->ecc.size, ret;
int eccbytes = chip->ecc.bytes;
int eccsteps = chip->ecc.steps;
@@ -4142,13 +3586,13 @@ static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
return ret;
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
- chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
+ chip->ecc.hwctl(chip, NAND_ECC_WRITE);
ret = nand_write_data_op(chip, p, eccsize, false);
if (ret)
return ret;
- chip->ecc.calculate(mtd, p, &ecc_calc[i]);
+ chip->ecc.calculate(chip, p, &ecc_calc[i]);
}
ret = mtd_ooblayout_set_eccbytes(mtd, ecc_calc, chip->oob_poi, 0,
@@ -4166,7 +3610,6 @@ static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
/**
* nand_write_subpage_hwecc - [REPLACEABLE] hardware ECC based subpage write
- * @mtd: mtd info structure
* @chip: nand chip info structure
* @offset: column address of subpage within the page
* @data_len: data length
@@ -4174,11 +3617,11 @@ static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
* @oob_required: must write chip->oob_poi to OOB
* @page: page number to write
*/
-static int nand_write_subpage_hwecc(struct mtd_info *mtd,
- struct nand_chip *chip, uint32_t offset,
- uint32_t data_len, const uint8_t *buf,
- int oob_required, int page)
+static int nand_write_subpage_hwecc(struct nand_chip *chip, uint32_t offset,
+ uint32_t data_len, const uint8_t *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
uint8_t *oob_buf = chip->oob_poi;
uint8_t *ecc_calc = chip->ecc.calc_buf;
int ecc_size = chip->ecc.size;
@@ -4195,7 +3638,7 @@ static int nand_write_subpage_hwecc(struct mtd_info *mtd,
for (step = 0; step < ecc_steps; step++) {
/* configure controller for WRITE access */
- chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
+ chip->ecc.hwctl(chip, NAND_ECC_WRITE);
/* write data (untouched subpages already masked by 0xFF) */
ret = nand_write_data_op(chip, buf, ecc_size, false);
@@ -4206,7 +3649,7 @@ static int nand_write_subpage_hwecc(struct mtd_info *mtd,
if ((step < start_step) || (step > end_step))
memset(ecc_calc, 0xff, ecc_bytes);
else
- chip->ecc.calculate(mtd, buf, ecc_calc);
+ chip->ecc.calculate(chip, buf, ecc_calc);
/* mask OOB of un-touched subpages by padding 0xFF */
/* if oob_required, preserve OOB metadata of written subpage */
@@ -4237,7 +3680,6 @@ static int nand_write_subpage_hwecc(struct mtd_info *mtd,
/**
* nand_write_page_syndrome - [REPLACEABLE] hardware ECC syndrome based page write
- * @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: data buffer
* @oob_required: must write chip->oob_poi to OOB
@@ -4246,11 +3688,10 @@ static int nand_write_subpage_hwecc(struct mtd_info *mtd,
* The hw generator calculates the error syndrome automatically. Therefore we
* need a special oob layout and handling.
*/
-static int nand_write_page_syndrome(struct mtd_info *mtd,
- struct nand_chip *chip,
- const uint8_t *buf, int oob_required,
- int page)
+static int nand_write_page_syndrome(struct nand_chip *chip, const uint8_t *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
int i, eccsize = chip->ecc.size;
int eccbytes = chip->ecc.bytes;
int eccsteps = chip->ecc.steps;
@@ -4263,7 +3704,7 @@ static int nand_write_page_syndrome(struct mtd_info *mtd,
return ret;
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
- chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
+ chip->ecc.hwctl(chip, NAND_ECC_WRITE);
ret = nand_write_data_op(chip, p, eccsize, false);
if (ret)
@@ -4278,7 +3719,7 @@ static int nand_write_page_syndrome(struct mtd_info *mtd,
oob += chip->ecc.prepad;
}
- chip->ecc.calculate(mtd, p, oob);
+ chip->ecc.calculate(chip, p, oob);
ret = nand_write_data_op(chip, oob, eccbytes, false);
if (ret)
@@ -4331,14 +3772,13 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
subpage = 0;
if (unlikely(raw))
- status = chip->ecc.write_page_raw(mtd, chip, buf,
- oob_required, page);
+ status = chip->ecc.write_page_raw(chip, buf, oob_required,
+ page);
else if (subpage)
- status = chip->ecc.write_subpage(mtd, chip, offset, data_len,
- buf, oob_required, page);
+ status = chip->ecc.write_subpage(chip, offset, data_len, buf,
+ oob_required, page);
else
- status = chip->ecc.write_page(mtd, chip, buf, oob_required,
- page);
+ status = chip->ecc.write_page(chip, buf, oob_required, page);
if (status < 0)
return status;
@@ -4423,7 +3863,7 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
column = to & (mtd->writesize - 1);
chipnr = (int)(to >> chip->chip_shift);
- chip->select_chip(mtd, chipnr);
+ chip->select_chip(chip, chipnr);
/* Check, if it is write protected */
if (nand_check_wp(mtd)) {
@@ -4499,8 +3939,8 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
/* Check, if we cross a chip boundary */
if (!page) {
chipnr++;
- chip->select_chip(mtd, -1);
- chip->select_chip(mtd, chipnr);
+ chip->select_chip(chip, -1);
+ chip->select_chip(chip, chipnr);
}
}
@@ -4509,7 +3949,7 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
ops->oobretlen = ops->ooblen;
err_out:
- chip->select_chip(mtd, -1);
+ chip->select_chip(chip, -1);
return ret;
}
@@ -4535,10 +3975,10 @@ static int panic_nand_write(struct mtd_info *mtd, loff_t to, size_t len,
/* Grab the device */
panic_nand_get_device(chip, mtd, FL_WRITING);
- chip->select_chip(mtd, chipnr);
+ chip->select_chip(chip, chipnr);
/* Wait for the device to get ready */
- panic_nand_wait(mtd, chip, 400);
+ panic_nand_wait(chip, 400);
memset(&ops, 0, sizeof(ops));
ops.len = len;
@@ -4587,14 +4027,14 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
*/
nand_reset(chip, chipnr);
- chip->select_chip(mtd, chipnr);
+ chip->select_chip(chip, chipnr);
/* Shift to get page */
page = (int)(to >> chip->page_shift);
/* Check, if it is write protected */
if (nand_check_wp(mtd)) {
- chip->select_chip(mtd, -1);
+ chip->select_chip(chip, -1);
return -EROFS;
}
@@ -4605,11 +4045,11 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
nand_fill_oob(mtd, ops->oobbuf, ops->ooblen, ops);
if (ops->mode == MTD_OPS_RAW)
- status = chip->ecc.write_oob_raw(mtd, chip, page & chip->pagemask);
+ status = chip->ecc.write_oob_raw(chip, page & chip->pagemask);
else
- status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask);
+ status = chip->ecc.write_oob(chip, page & chip->pagemask);
- chip->select_chip(mtd, -1);
+ chip->select_chip(chip, -1);
if (status)
return status;
@@ -4656,14 +4096,13 @@ out:
/**
* single_erase - [GENERIC] NAND standard block erase command function
- * @mtd: MTD device structure
+ * @chip: NAND chip object
* @page: the page address of the block which will be erased
*
* Standard erase command for NAND chips. Returns NAND status.
*/
-static int single_erase(struct mtd_info *mtd, int page)
+static int single_erase(struct nand_chip *chip, int page)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
unsigned int eraseblock;
/* Send commands to erase a block */
@@ -4681,22 +4120,22 @@ static int single_erase(struct mtd_info *mtd, int page)
*/
static int nand_erase(struct mtd_info *mtd, struct erase_info *instr)
{
- return nand_erase_nand(mtd, instr, 0);
+ return nand_erase_nand(mtd_to_nand(mtd), instr, 0);
}
/**
* nand_erase_nand - [INTERN] erase block(s)
- * @mtd: MTD device structure
+ * @chip: NAND chip object
* @instr: erase instruction
* @allowbbt: allow erasing the bbt area
*
* Erase one ore more blocks.
*/
-int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
+int nand_erase_nand(struct nand_chip *chip, struct erase_info *instr,
int allowbbt)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
int page, status, pages_per_block, ret, chipnr;
- struct nand_chip *chip = mtd_to_nand(mtd);
loff_t len;
pr_debug("%s: start = 0x%012llx, len = %llu\n",
@@ -4717,7 +4156,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
pages_per_block = 1 << (chip->phys_erase_shift - chip->page_shift);
/* Select the NAND device */
- chip->select_chip(mtd, chipnr);
+ chip->select_chip(chip, chipnr);
/* Check, if it is write protected */
if (nand_check_wp(mtd)) {
@@ -4748,7 +4187,11 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
(page + pages_per_block))
chip->pagebuf = -1;
- status = chip->erase(mtd, page & chip->pagemask);
+ if (chip->legacy.erase)
+ status = chip->legacy.erase(chip,
+ page & chip->pagemask);
+ else
+ status = single_erase(chip, page & chip->pagemask);
/* See if block erase succeeded */
if (status) {
@@ -4767,8 +4210,8 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
/* Check, if we cross a chip boundary */
if (len && !(page & chip->pagemask)) {
chipnr++;
- chip->select_chip(mtd, -1);
- chip->select_chip(mtd, chipnr);
+ chip->select_chip(chip, -1);
+ chip->select_chip(chip, chipnr);
}
}
@@ -4776,7 +4219,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
erase_exit:
/* Deselect and wake up anyone waiting on the device */
- chip->select_chip(mtd, -1);
+ chip->select_chip(chip, -1);
nand_release_device(mtd);
/* Return more or less happy */
@@ -4812,11 +4255,11 @@ static int nand_block_isbad(struct mtd_info *mtd, loff_t offs)
/* Select the NAND device */
nand_get_device(mtd, FL_READING);
- chip->select_chip(mtd, chipnr);
+ chip->select_chip(chip, chipnr);
ret = nand_block_checkbad(mtd, offs, 0);
- chip->select_chip(mtd, -1);
+ chip->select_chip(chip, -1);
nand_release_device(mtd);
return ret;
@@ -4879,51 +4322,6 @@ static int nand_max_bad_blocks(struct mtd_info *mtd, loff_t ofs, size_t len)
}
/**
- * nand_default_set_features- [REPLACEABLE] set NAND chip features
- * @mtd: MTD device structure
- * @chip: nand chip info structure
- * @addr: feature address.
- * @subfeature_param: the subfeature parameters, a four bytes array.
- */
-static int nand_default_set_features(struct mtd_info *mtd,
- struct nand_chip *chip, int addr,
- uint8_t *subfeature_param)
-{
- return nand_set_features_op(chip, addr, subfeature_param);
-}
-
-/**
- * nand_default_get_features- [REPLACEABLE] get NAND chip features
- * @mtd: MTD device structure
- * @chip: nand chip info structure
- * @addr: feature address.
- * @subfeature_param: the subfeature parameters, a four bytes array.
- */
-static int nand_default_get_features(struct mtd_info *mtd,
- struct nand_chip *chip, int addr,
- uint8_t *subfeature_param)
-{
- return nand_get_features_op(chip, addr, subfeature_param);
-}
-
-/**
- * nand_get_set_features_notsupp - set/get features stub returning -ENOTSUPP
- * @mtd: MTD device structure
- * @chip: nand chip info structure
- * @addr: feature address.
- * @subfeature_param: the subfeature parameters, a four bytes array.
- *
- * Should be used by NAND controller drivers that do not support the SET/GET
- * FEATURES operations.
- */
-int nand_get_set_features_notsupp(struct mtd_info *mtd, struct nand_chip *chip,
- int addr, u8 *subfeature_param)
-{
- return -ENOTSUPP;
-}
-EXPORT_SYMBOL(nand_get_set_features_notsupp);
-
-/**
* nand_suspend - [MTD Interface] Suspend the NAND flash
* @mtd: MTD device structure
*/
@@ -4960,44 +4358,7 @@ static void nand_shutdown(struct mtd_info *mtd)
/* Set default functions */
static void nand_set_defaults(struct nand_chip *chip)
{
- unsigned int busw = chip->options & NAND_BUSWIDTH_16;
-
- /* check for proper chip_delay setup, set 20us if not */
- if (!chip->chip_delay)
- chip->chip_delay = 20;
-
- /* check, if a user supplied command function given */
- if (!chip->cmdfunc && !chip->exec_op)
- chip->cmdfunc = nand_command;
-
- /* check, if a user supplied wait function given */
- if (chip->waitfunc == NULL)
- chip->waitfunc = nand_wait;
-
- if (!chip->select_chip)
- chip->select_chip = nand_select_chip;
-
- /* set for ONFI nand */
- if (!chip->set_features)
- chip->set_features = nand_default_set_features;
- if (!chip->get_features)
- chip->get_features = nand_default_get_features;
-
- /* If called twice, pointers that depend on busw may need to be reset */
- if (!chip->read_byte || chip->read_byte == nand_read_byte)
- chip->read_byte = busw ? nand_read_byte16 : nand_read_byte;
- if (!chip->read_word)
- chip->read_word = nand_read_word;
- if (!chip->block_bad)
- chip->block_bad = nand_block_bad;
- if (!chip->block_markbad)
- chip->block_markbad = nand_default_block_markbad;
- if (!chip->write_buf || chip->write_buf == nand_write_buf)
- chip->write_buf = busw ? nand_write_buf16 : nand_write_buf;
- if (!chip->write_byte || chip->write_byte == nand_write_byte)
- chip->write_byte = busw ? nand_write_byte16 : nand_write_byte;
- if (!chip->read_buf || chip->read_buf == nand_read_buf)
- chip->read_buf = busw ? nand_read_buf16 : nand_read_buf;
+ nand_legacy_set_defaults(chip);
if (!chip->controller) {
chip->controller = &chip->dummy_controller;
@@ -5009,7 +4370,7 @@ static void nand_set_defaults(struct nand_chip *chip)
}
/* Sanitize ONFI strings so we can safely print them */
-static void sanitize_string(uint8_t *s, size_t len)
+void sanitize_string(uint8_t *s, size_t len)
{
ssize_t i;
@@ -5026,390 +4387,6 @@ static void sanitize_string(uint8_t *s, size_t len)
strim(s);
}
-static u16 onfi_crc16(u16 crc, u8 const *p, size_t len)
-{
- int i;
- while (len--) {
- crc ^= *p++ << 8;
- for (i = 0; i < 8; i++)
- crc = (crc << 1) ^ ((crc & 0x8000) ? 0x8005 : 0);
- }
-
- return crc;
-}
-
-/* Parse the Extended Parameter Page. */
-static int nand_flash_detect_ext_param_page(struct nand_chip *chip,
- struct nand_onfi_params *p)
-{
- struct onfi_ext_param_page *ep;
- struct onfi_ext_section *s;
- struct onfi_ext_ecc_info *ecc;
- uint8_t *cursor;
- int ret;
- int len;
- int i;
-
- len = le16_to_cpu(p->ext_param_page_length) * 16;
- ep = kmalloc(len, GFP_KERNEL);
- if (!ep)
- return -ENOMEM;
-
- /* Send our own NAND_CMD_PARAM. */
- ret = nand_read_param_page_op(chip, 0, NULL, 0);
- if (ret)
- goto ext_out;
-
- /* Use the Change Read Column command to skip the ONFI param pages. */
- ret = nand_change_read_column_op(chip,
- sizeof(*p) * p->num_of_param_pages,
- ep, len, true);
- if (ret)
- goto ext_out;
-
- ret = -EINVAL;
- if ((onfi_crc16(ONFI_CRC_BASE, ((uint8_t *)ep) + 2, len - 2)
- != le16_to_cpu(ep->crc))) {
- pr_debug("fail in the CRC.\n");
- goto ext_out;
- }
-
- /*
- * Check the signature.
- * Do not strictly follow the ONFI spec, maybe changed in future.
- */
- if (strncmp(ep->sig, "EPPS", 4)) {
- pr_debug("The signature is invalid.\n");
- goto ext_out;
- }
-
- /* find the ECC section. */
- cursor = (uint8_t *)(ep + 1);
- for (i = 0; i < ONFI_EXT_SECTION_MAX; i++) {
- s = ep->sections + i;
- if (s->type == ONFI_SECTION_TYPE_2)
- break;
- cursor += s->length * 16;
- }
- if (i == ONFI_EXT_SECTION_MAX) {
- pr_debug("We can not find the ECC section.\n");
- goto ext_out;
- }
-
- /* get the info we want. */
- ecc = (struct onfi_ext_ecc_info *)cursor;
-
- if (!ecc->codeword_size) {
- pr_debug("Invalid codeword size\n");
- goto ext_out;
- }
-
- chip->ecc_strength_ds = ecc->ecc_bits;
- chip->ecc_step_ds = 1 << ecc->codeword_size;
- ret = 0;
-
-ext_out:
- kfree(ep);
- return ret;
-}
-
-/*
- * Recover data with bit-wise majority
- */
-static void nand_bit_wise_majority(const void **srcbufs,
- unsigned int nsrcbufs,
- void *dstbuf,
- unsigned int bufsize)
-{
- int i, j, k;
-
- for (i = 0; i < bufsize; i++) {
- u8 val = 0;
-
- for (j = 0; j < 8; j++) {
- unsigned int cnt = 0;
-
- for (k = 0; k < nsrcbufs; k++) {
- const u8 *srcbuf = srcbufs[k];
-
- if (srcbuf[i] & BIT(j))
- cnt++;
- }
-
- if (cnt > nsrcbufs / 2)
- val |= BIT(j);
- }
-
- ((u8 *)dstbuf)[i] = val;
- }
-}
-
-/*
- * Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise.
- */
-static int nand_flash_detect_onfi(struct nand_chip *chip)
-{
- struct mtd_info *mtd = nand_to_mtd(chip);
- struct nand_onfi_params *p;
- struct onfi_params *onfi;
- int onfi_version = 0;
- char id[4];
- int i, ret, val;
-
- /* Try ONFI for unknown chip or LP */
- ret = nand_readid_op(chip, 0x20, id, sizeof(id));
- if (ret || strncmp(id, "ONFI", 4))
- return 0;
-
- /* ONFI chip: allocate a buffer to hold its parameter page */
- p = kzalloc((sizeof(*p) * 3), GFP_KERNEL);
- if (!p)
- return -ENOMEM;
-
- ret = nand_read_param_page_op(chip, 0, NULL, 0);
- if (ret) {
- ret = 0;
- goto free_onfi_param_page;
- }
-
- for (i = 0; i < 3; i++) {
- ret = nand_read_data_op(chip, &p[i], sizeof(*p), true);
- if (ret) {
- ret = 0;
- goto free_onfi_param_page;
- }
-
- if (onfi_crc16(ONFI_CRC_BASE, (u8 *)&p[i], 254) ==
- le16_to_cpu(p->crc)) {
- if (i)
- memcpy(p, &p[i], sizeof(*p));
- break;
- }
- }
-
- if (i == 3) {
- const void *srcbufs[3] = {p, p + 1, p + 2};
-
- pr_warn("Could not find a valid ONFI parameter page, trying bit-wise majority to recover it\n");
- nand_bit_wise_majority(srcbufs, ARRAY_SIZE(srcbufs), p,
- sizeof(*p));
-
- if (onfi_crc16(ONFI_CRC_BASE, (u8 *)p, 254) !=
- le16_to_cpu(p->crc)) {
- pr_err("ONFI parameter recovery failed, aborting\n");
- goto free_onfi_param_page;
- }
- }
-
- if (chip->manufacturer.desc && chip->manufacturer.desc->ops &&
- chip->manufacturer.desc->ops->fixup_onfi_param_page)
- chip->manufacturer.desc->ops->fixup_onfi_param_page(chip, p);
-
- /* Check version */
- val = le16_to_cpu(p->revision);
- if (val & ONFI_VERSION_2_3)
- onfi_version = 23;
- else if (val & ONFI_VERSION_2_2)
- onfi_version = 22;
- else if (val & ONFI_VERSION_2_1)
- onfi_version = 21;
- else if (val & ONFI_VERSION_2_0)
- onfi_version = 20;
- else if (val & ONFI_VERSION_1_0)
- onfi_version = 10;
-
- if (!onfi_version) {
- pr_info("unsupported ONFI version: %d\n", val);
- goto free_onfi_param_page;
- }
-
- sanitize_string(p->manufacturer, sizeof(p->manufacturer));
- sanitize_string(p->model, sizeof(p->model));
- chip->parameters.model = kstrdup(p->model, GFP_KERNEL);
- if (!chip->parameters.model) {
- ret = -ENOMEM;
- goto free_onfi_param_page;
- }
-
- mtd->writesize = le32_to_cpu(p->byte_per_page);
-
- /*
- * pages_per_block and blocks_per_lun may not be a power-of-2 size
- * (don't ask me who thought of this...). MTD assumes that these
- * dimensions will be power-of-2, so just truncate the remaining area.
- */
- mtd->erasesize = 1 << (fls(le32_to_cpu(p->pages_per_block)) - 1);
- mtd->erasesize *= mtd->writesize;
-
- mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page);
-
- /* See erasesize comment */
- chip->chipsize = 1 << (fls(le32_to_cpu(p->blocks_per_lun)) - 1);
- chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count;
- chip->bits_per_cell = p->bits_per_cell;
-
- chip->max_bb_per_die = le16_to_cpu(p->bb_per_lun);
- chip->blocks_per_die = le32_to_cpu(p->blocks_per_lun);
-
- if (le16_to_cpu(p->features) & ONFI_FEATURE_16_BIT_BUS)
- chip->options |= NAND_BUSWIDTH_16;
-
- if (p->ecc_bits != 0xff) {
- chip->ecc_strength_ds = p->ecc_bits;
- chip->ecc_step_ds = 512;
- } else if (onfi_version >= 21 &&
- (le16_to_cpu(p->features) & ONFI_FEATURE_EXT_PARAM_PAGE)) {
-
- /*
- * The nand_flash_detect_ext_param_page() uses the
- * Change Read Column command which maybe not supported
- * by the chip->cmdfunc. So try to update the chip->cmdfunc
- * now. We do not replace user supplied command function.
- */
- if (mtd->writesize > 512 && chip->cmdfunc == nand_command)
- chip->cmdfunc = nand_command_lp;
-
- /* The Extended Parameter Page is supported since ONFI 2.1. */
- if (nand_flash_detect_ext_param_page(chip, p))
- pr_warn("Failed to detect ONFI extended param page\n");
- } else {
- pr_warn("Could not retrieve ONFI ECC requirements\n");
- }
-
- /* Save some parameters from the parameter page for future use */
- if (le16_to_cpu(p->opt_cmd) & ONFI_OPT_CMD_SET_GET_FEATURES) {
- chip->parameters.supports_set_get_features = true;
- bitmap_set(chip->parameters.get_feature_list,
- ONFI_FEATURE_ADDR_TIMING_MODE, 1);
- bitmap_set(chip->parameters.set_feature_list,
- ONFI_FEATURE_ADDR_TIMING_MODE, 1);
- }
-
- onfi = kzalloc(sizeof(*onfi), GFP_KERNEL);
- if (!onfi) {
- ret = -ENOMEM;
- goto free_model;
- }
-
- onfi->version = onfi_version;
- onfi->tPROG = le16_to_cpu(p->t_prog);
- onfi->tBERS = le16_to_cpu(p->t_bers);
- onfi->tR = le16_to_cpu(p->t_r);
- onfi->tCCS = le16_to_cpu(p->t_ccs);
- onfi->async_timing_mode = le16_to_cpu(p->async_timing_mode);
- onfi->vendor_revision = le16_to_cpu(p->vendor_revision);
- memcpy(onfi->vendor, p->vendor, sizeof(p->vendor));
- chip->parameters.onfi = onfi;
-
- /* Identification done, free the full ONFI parameter page and exit */
- kfree(p);
-
- return 1;
-
-free_model:
- kfree(chip->parameters.model);
-free_onfi_param_page:
- kfree(p);
-
- return ret;
-}
-
-/*
- * Check if the NAND chip is JEDEC compliant, returns 1 if it is, 0 otherwise.
- */
-static int nand_flash_detect_jedec(struct nand_chip *chip)
-{
- struct mtd_info *mtd = nand_to_mtd(chip);
- struct nand_jedec_params *p;
- struct jedec_ecc_info *ecc;
- int jedec_version = 0;
- char id[5];
- int i, val, ret;
-
- /* Try JEDEC for unknown chip or LP */
- ret = nand_readid_op(chip, 0x40, id, sizeof(id));
- if (ret || strncmp(id, "JEDEC", sizeof(id)))
- return 0;
-
- /* JEDEC chip: allocate a buffer to hold its parameter page */
- p = kzalloc(sizeof(*p), GFP_KERNEL);
- if (!p)
- return -ENOMEM;
-
- ret = nand_read_param_page_op(chip, 0x40, NULL, 0);
- if (ret) {
- ret = 0;
- goto free_jedec_param_page;
- }
-
- for (i = 0; i < 3; i++) {
- ret = nand_read_data_op(chip, p, sizeof(*p), true);
- if (ret) {
- ret = 0;
- goto free_jedec_param_page;
- }
-
- if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 510) ==
- le16_to_cpu(p->crc))
- break;
- }
-
- if (i == 3) {
- pr_err("Could not find valid JEDEC parameter page; aborting\n");
- goto free_jedec_param_page;
- }
-
- /* Check version */
- val = le16_to_cpu(p->revision);
- if (val & (1 << 2))
- jedec_version = 10;
- else if (val & (1 << 1))
- jedec_version = 1; /* vendor specific version */
-
- if (!jedec_version) {
- pr_info("unsupported JEDEC version: %d\n", val);
- goto free_jedec_param_page;
- }
-
- sanitize_string(p->manufacturer, sizeof(p->manufacturer));
- sanitize_string(p->model, sizeof(p->model));
- chip->parameters.model = kstrdup(p->model, GFP_KERNEL);
- if (!chip->parameters.model) {
- ret = -ENOMEM;
- goto free_jedec_param_page;
- }
-
- mtd->writesize = le32_to_cpu(p->byte_per_page);
-
- /* Please reference to the comment for nand_flash_detect_onfi. */
- mtd->erasesize = 1 << (fls(le32_to_cpu(p->pages_per_block)) - 1);
- mtd->erasesize *= mtd->writesize;
-
- mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page);
-
- /* Please reference to the comment for nand_flash_detect_onfi. */
- chip->chipsize = 1 << (fls(le32_to_cpu(p->blocks_per_lun)) - 1);
- chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count;
- chip->bits_per_cell = p->bits_per_cell;
-
- if (le16_to_cpu(p->features) & JEDEC_FEATURE_16_BIT_BUS)
- chip->options |= NAND_BUSWIDTH_16;
-
- /* ECC info */
- ecc = &p->ecc_info[0];
-
- if (ecc->codeword_size >= 9) {
- chip->ecc_strength_ds = ecc->ecc_bits;
- chip->ecc_step_ds = 1 << ecc->codeword_size;
- } else {
- pr_warn("Invalid codeword size\n");
- }
-
-free_jedec_param_page:
- kfree(p);
- return ret;
-}
-
/*
* nand_id_has_period - Check if an ID string has a given wraparound period
* @id_data: the ID string
@@ -5625,6 +4602,12 @@ static void nand_manufacturer_cleanup(struct nand_chip *chip)
chip->manufacturer.desc->ops->cleanup(chip);
}
+static const char *
+nand_manufacturer_name(const struct nand_manufacturer *manufacturer)
+{
+ return manufacturer ? manufacturer->name : "Unknown";
+}
+
/*
* Get the flash and manufacturer id and lookup if the type is supported.
*/
@@ -5645,7 +4628,7 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type)
return ret;
/* Select the device */
- chip->select_chip(mtd, 0);
+ chip->select_chip(chip, 0);
/* Send the command for reading device ID */
ret = nand_readid_op(chip, 0, id_data, 2);
@@ -5709,14 +4692,14 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type)
if (!type->name || !type->pagesize) {
/* Check if the chip is ONFI compliant */
- ret = nand_flash_detect_onfi(chip);
+ ret = nand_onfi_detect(chip);
if (ret < 0)
return ret;
else if (ret)
goto ident_done;
/* Check if the chip is JEDEC compliant */
- ret = nand_flash_detect_jedec(chip);
+ ret = nand_jedec_detect(chip);
if (ret < 0)
return ret;
else if (ret)
@@ -5783,11 +4766,8 @@ ident_done:
chip->options |= NAND_ROW_ADDR_3;
chip->badblockbits = 8;
- chip->erase = single_erase;
- /* Do not replace user supplied command function! */
- if (mtd->writesize > 512 && chip->cmdfunc == nand_command)
- chip->cmdfunc = nand_command_lp;
+ nand_legacy_adjust_cmdfunc(chip);
pr_info("device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n",
maf_id, dev_id);
@@ -5953,7 +4933,7 @@ static int nand_dt_init(struct nand_chip *chip)
/**
* nand_scan_ident - Scan for the NAND device
- * @mtd: MTD device structure
+ * @chip: NAND chip object
* @maxchips: number of chips to scan for
* @table: alternative NAND ID table
*
@@ -5965,11 +4945,12 @@ static int nand_dt_init(struct nand_chip *chip)
* prevented dynamic allocations during this phase which was unconvenient and
* as been banned for the benefit of the ->init_ecc()/cleanup_ecc() hooks.
*/
-static int nand_scan_ident(struct mtd_info *mtd, int maxchips,
+static int nand_scan_ident(struct nand_chip *chip, unsigned int maxchips,
struct nand_flash_dev *table)
{
- int i, nand_maf_id, nand_dev_id;
- struct nand_chip *chip = mtd_to_nand(mtd);
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ int nand_maf_id, nand_dev_id;
+ unsigned int i;
int ret;
/* Enforce the right timings for reset/detection */
@@ -5982,21 +4963,15 @@ static int nand_scan_ident(struct mtd_info *mtd, int maxchips,
if (!mtd->name && mtd->dev.parent)
mtd->name = dev_name(mtd->dev.parent);
- /*
- * ->cmdfunc() is legacy and will only be used if ->exec_op() is not
- * populated.
- */
- if (!chip->exec_op) {
- /*
- * Default functions assigned for ->cmdfunc() and
- * ->select_chip() both expect ->cmd_ctrl() to be populated.
- */
- if ((!chip->cmdfunc || !chip->select_chip) && !chip->cmd_ctrl) {
- pr_err("->cmd_ctrl() should be provided\n");
- return -EINVAL;
- }
+ if (chip->exec_op && !chip->select_chip) {
+ pr_err("->select_chip() is mandatory when implementing ->exec_op()\n");
+ return -EINVAL;
}
+ ret = nand_legacy_check_hooks(chip);
+ if (ret)
+ return ret;
+
/* Set the default functions */
nand_set_defaults(chip);
@@ -6005,14 +4980,14 @@ static int nand_scan_ident(struct mtd_info *mtd, int maxchips,
if (ret) {
if (!(chip->options & NAND_SCAN_SILENT_NODEV))
pr_warn("No NAND device found\n");
- chip->select_chip(mtd, -1);
+ chip->select_chip(chip, -1);
return ret;
}
nand_maf_id = chip->id.data[0];
nand_dev_id = chip->id.data[1];
- chip->select_chip(mtd, -1);
+ chip->select_chip(chip, -1);
/* Check for a chip array */
for (i = 1; i < maxchips; i++) {
@@ -6021,15 +4996,15 @@ static int nand_scan_ident(struct mtd_info *mtd, int maxchips,
/* See comment in nand_get_flash_type for reset */
nand_reset(chip, i);
- chip->select_chip(mtd, i);
+ chip->select_chip(chip, i);
/* Send the command for reading device ID */
nand_readid_op(chip, 0, id, sizeof(id));
/* Read manufacturer and device IDs */
if (nand_maf_id != id[0] || nand_dev_id != id[1]) {
- chip->select_chip(mtd, -1);
+ chip->select_chip(chip, -1);
break;
}
- chip->select_chip(mtd, -1);
+ chip->select_chip(chip, -1);
}
if (i > 1)
pr_info("%d chips detected\n", i);
@@ -6070,6 +5045,10 @@ static int nand_set_ecc_soft_ops(struct mtd_info *mtd)
ecc->size = 256;
ecc->bytes = 3;
ecc->strength = 1;
+
+ if (IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC))
+ ecc->options |= NAND_ECC_SOFT_HAMMING_SM_ORDER;
+
return 0;
case NAND_ECC_BCH:
if (!mtd_nand_has_bch()) {
@@ -6423,15 +5402,15 @@ static bool nand_ecc_strength_good(struct mtd_info *mtd)
/**
* nand_scan_tail - Scan for the NAND device
- * @mtd: MTD device structure
+ * @chip: NAND chip object
*
* This is the second phase of the normal nand_scan() function. It fills out
* all the uninitialized function pointers with the defaults and scans for a
* bad block table if appropriate.
*/
-static int nand_scan_tail(struct mtd_info *mtd)
+static int nand_scan_tail(struct nand_chip *chip)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct nand_ecc_ctrl *ecc = &chip->ecc;
int ret, i;
@@ -6451,9 +5430,9 @@ static int nand_scan_tail(struct mtd_info *mtd)
* to explictly select the relevant die when interacting with the NAND
* chip.
*/
- chip->select_chip(mtd, 0);
+ chip->select_chip(chip, 0);
ret = nand_manufacturer_init(chip);
- chip->select_chip(mtd, -1);
+ chip->select_chip(chip, -1);
if (ret)
goto err_free_buf;
@@ -6770,33 +5749,31 @@ static void nand_detach(struct nand_chip *chip)
/**
* nand_scan_with_ids - [NAND Interface] Scan for the NAND device
- * @mtd: MTD device structure
- * @maxchips: number of chips to scan for. @nand_scan_ident() will not be run if
- * this parameter is zero (useful for specific drivers that must
- * handle this part of the process themselves, e.g docg4).
+ * @chip: NAND chip object
+ * @maxchips: number of chips to scan for.
* @ids: optional flash IDs table
*
* This fills out all the uninitialized function pointers with the defaults.
* The flash ID is read and the mtd/chip structures are filled with the
* appropriate values.
*/
-int nand_scan_with_ids(struct mtd_info *mtd, int maxchips,
+int nand_scan_with_ids(struct nand_chip *chip, unsigned int maxchips,
struct nand_flash_dev *ids)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
int ret;
- if (maxchips) {
- ret = nand_scan_ident(mtd, maxchips, ids);
- if (ret)
- return ret;
- }
+ if (!maxchips)
+ return -EINVAL;
+
+ ret = nand_scan_ident(chip, maxchips, ids);
+ if (ret)
+ return ret;
ret = nand_attach(chip);
if (ret)
goto cleanup_ident;
- ret = nand_scan_tail(mtd);
+ ret = nand_scan_tail(chip);
if (ret)
goto detach_chip;
@@ -6847,12 +5824,12 @@ EXPORT_SYMBOL_GPL(nand_cleanup);
/**
* nand_release - [NAND Interface] Unregister the MTD device and free resources
* held by the NAND device
- * @mtd: MTD device structure
+ * @chip: NAND chip object
*/
-void nand_release(struct mtd_info *mtd)
+void nand_release(struct nand_chip *chip)
{
- mtd_device_unregister(mtd);
- nand_cleanup(mtd_to_nand(mtd));
+ mtd_device_unregister(nand_to_mtd(chip));
+ nand_cleanup(chip);
}
EXPORT_SYMBOL_GPL(nand_release);
diff --git a/drivers/mtd/nand/raw/nand_bbt.c b/drivers/mtd/nand/raw/nand_bbt.c
index 39db352f8757..98a826838b60 100644
--- a/drivers/mtd/nand/raw/nand_bbt.c
+++ b/drivers/mtd/nand/raw/nand_bbt.c
@@ -61,13 +61,14 @@
#include <linux/types.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/bbm.h>
-#include <linux/mtd/rawnand.h>
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/vmalloc.h>
#include <linux/export.h>
#include <linux/string.h>
+#include "internals.h"
+
#define BBT_BLOCK_GOOD 0x00
#define BBT_BLOCK_WORN 0x01
#define BBT_BLOCK_RESERVED 0x02
@@ -683,14 +684,13 @@ static void mark_bbt_block_bad(struct nand_chip *this,
struct nand_bbt_descr *td,
int chip, int block)
{
- struct mtd_info *mtd = nand_to_mtd(this);
loff_t to;
int res;
bbt_mark_entry(this, block, BBT_BLOCK_WORN);
to = (loff_t)block << this->bbt_erase_shift;
- res = this->block_markbad(mtd, to);
+ res = nand_markbad_bbm(this, to);
if (res)
pr_warn("nand_bbt: error %d while marking block %d bad\n",
res, block);
@@ -854,7 +854,7 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
memset(&einfo, 0, sizeof(einfo));
einfo.addr = to;
einfo.len = 1 << this->bbt_erase_shift;
- res = nand_erase_nand(mtd, &einfo, 1);
+ res = nand_erase_nand(this, &einfo, 1);
if (res < 0) {
pr_warn("nand_bbt: error while erasing BBT block %d\n",
res);
@@ -1388,12 +1388,11 @@ EXPORT_SYMBOL(nand_create_bbt);
/**
* nand_isreserved_bbt - [NAND Interface] Check if a block is reserved
- * @mtd: MTD device structure
+ * @this: NAND chip object
* @offs: offset in the device
*/
-int nand_isreserved_bbt(struct mtd_info *mtd, loff_t offs)
+int nand_isreserved_bbt(struct nand_chip *this, loff_t offs)
{
- struct nand_chip *this = mtd_to_nand(mtd);
int block;
block = (int)(offs >> this->bbt_erase_shift);
@@ -1402,13 +1401,12 @@ int nand_isreserved_bbt(struct mtd_info *mtd, loff_t offs)
/**
* nand_isbad_bbt - [NAND Interface] Check if a block is bad
- * @mtd: MTD device structure
+ * @this: NAND chip object
* @offs: offset in the device
* @allowbbt: allow access to bad block table region
*/
-int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)
+int nand_isbad_bbt(struct nand_chip *this, loff_t offs, int allowbbt)
{
- struct nand_chip *this = mtd_to_nand(mtd);
int block, res;
block = (int)(offs >> this->bbt_erase_shift);
@@ -1430,12 +1428,12 @@ int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)
/**
* nand_markbad_bbt - [NAND Interface] Mark a block bad in the BBT
- * @mtd: MTD device structure
+ * @this: NAND chip object
* @offs: offset of the bad block
*/
-int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs)
+int nand_markbad_bbt(struct nand_chip *this, loff_t offs)
{
- struct nand_chip *this = mtd_to_nand(mtd);
+ struct mtd_info *mtd = nand_to_mtd(this);
int block, ret = 0;
block = (int)(offs >> this->bbt_erase_shift);
diff --git a/drivers/mtd/nand/raw/nand_bch.c b/drivers/mtd/nand/raw/nand_bch.c
index b7387ace567a..574c0ca16160 100644
--- a/drivers/mtd/nand/raw/nand_bch.c
+++ b/drivers/mtd/nand/raw/nand_bch.c
@@ -43,14 +43,13 @@ struct nand_bch_control {
/**
* nand_bch_calculate_ecc - [NAND Interface] Calculate ECC for data block
- * @mtd: MTD block structure
+ * @chip: NAND chip object
* @buf: input buffer with raw data
* @code: output buffer with ECC
*/
-int nand_bch_calculate_ecc(struct mtd_info *mtd, const unsigned char *buf,
+int nand_bch_calculate_ecc(struct nand_chip *chip, const unsigned char *buf,
unsigned char *code)
{
- const struct nand_chip *chip = mtd_to_nand(mtd);
struct nand_bch_control *nbc = chip->ecc.priv;
unsigned int i;
@@ -67,17 +66,16 @@ EXPORT_SYMBOL(nand_bch_calculate_ecc);
/**
* nand_bch_correct_data - [NAND Interface] Detect and correct bit error(s)
- * @mtd: MTD block structure
+ * @chip: NAND chip object
* @buf: raw data read from the chip
* @read_ecc: ECC from the chip
* @calc_ecc: the ECC calculated from raw data
*
* Detect and correct bit errors for a data byte block
*/
-int nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf,
+int nand_bch_correct_data(struct nand_chip *chip, unsigned char *buf,
unsigned char *read_ecc, unsigned char *calc_ecc)
{
- const struct nand_chip *chip = mtd_to_nand(mtd);
struct nand_bch_control *nbc = chip->ecc.priv;
unsigned int *errloc = nbc->errloc;
int i, count;
diff --git a/drivers/mtd/nand/raw/nand_ecc.c b/drivers/mtd/nand/raw/nand_ecc.c
index 8e132edbc5ce..4f4347533058 100644
--- a/drivers/mtd/nand/raw/nand_ecc.c
+++ b/drivers/mtd/nand/raw/nand_ecc.c
@@ -132,9 +132,10 @@ static const char addressbits[256] = {
* @buf: input buffer with raw data
* @eccsize: data bytes per ECC step (256 or 512)
* @code: output buffer with ECC
+ * @sm_order: Smart Media byte ordering
*/
void __nand_calculate_ecc(const unsigned char *buf, unsigned int eccsize,
- unsigned char *code)
+ unsigned char *code, bool sm_order)
{
int i;
const uint32_t *bp = (uint32_t *)buf;
@@ -330,45 +331,26 @@ void __nand_calculate_ecc(const unsigned char *buf, unsigned int eccsize,
* possible, but benchmarks showed that on the system this is developed
* the code below is the fastest
*/
-#ifdef CONFIG_MTD_NAND_ECC_SMC
- code[0] =
- (invparity[rp7] << 7) |
- (invparity[rp6] << 6) |
- (invparity[rp5] << 5) |
- (invparity[rp4] << 4) |
- (invparity[rp3] << 3) |
- (invparity[rp2] << 2) |
- (invparity[rp1] << 1) |
- (invparity[rp0]);
- code[1] =
- (invparity[rp15] << 7) |
- (invparity[rp14] << 6) |
- (invparity[rp13] << 5) |
- (invparity[rp12] << 4) |
- (invparity[rp11] << 3) |
- (invparity[rp10] << 2) |
- (invparity[rp9] << 1) |
- (invparity[rp8]);
-#else
- code[1] =
- (invparity[rp7] << 7) |
- (invparity[rp6] << 6) |
- (invparity[rp5] << 5) |
- (invparity[rp4] << 4) |
- (invparity[rp3] << 3) |
- (invparity[rp2] << 2) |
- (invparity[rp1] << 1) |
- (invparity[rp0]);
- code[0] =
- (invparity[rp15] << 7) |
- (invparity[rp14] << 6) |
- (invparity[rp13] << 5) |
- (invparity[rp12] << 4) |
- (invparity[rp11] << 3) |
- (invparity[rp10] << 2) |
- (invparity[rp9] << 1) |
- (invparity[rp8]);
-#endif
+ if (sm_order) {
+ code[0] = (invparity[rp7] << 7) | (invparity[rp6] << 6) |
+ (invparity[rp5] << 5) | (invparity[rp4] << 4) |
+ (invparity[rp3] << 3) | (invparity[rp2] << 2) |
+ (invparity[rp1] << 1) | (invparity[rp0]);
+ code[1] = (invparity[rp15] << 7) | (invparity[rp14] << 6) |
+ (invparity[rp13] << 5) | (invparity[rp12] << 4) |
+ (invparity[rp11] << 3) | (invparity[rp10] << 2) |
+ (invparity[rp9] << 1) | (invparity[rp8]);
+ } else {
+ code[1] = (invparity[rp7] << 7) | (invparity[rp6] << 6) |
+ (invparity[rp5] << 5) | (invparity[rp4] << 4) |
+ (invparity[rp3] << 3) | (invparity[rp2] << 2) |
+ (invparity[rp1] << 1) | (invparity[rp0]);
+ code[0] = (invparity[rp15] << 7) | (invparity[rp14] << 6) |
+ (invparity[rp13] << 5) | (invparity[rp12] << 4) |
+ (invparity[rp11] << 3) | (invparity[rp10] << 2) |
+ (invparity[rp9] << 1) | (invparity[rp8]);
+ }
+
if (eccsize_mult == 1)
code[2] =
(invparity[par & 0xf0] << 7) |
@@ -394,15 +376,16 @@ EXPORT_SYMBOL(__nand_calculate_ecc);
/**
* nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256/512-byte
* block
- * @mtd: MTD block structure
+ * @chip: NAND chip object
* @buf: input buffer with raw data
* @code: output buffer with ECC
*/
-int nand_calculate_ecc(struct mtd_info *mtd, const unsigned char *buf,
+int nand_calculate_ecc(struct nand_chip *chip, const unsigned char *buf,
unsigned char *code)
{
- __nand_calculate_ecc(buf,
- mtd_to_nand(mtd)->ecc.size, code);
+ bool sm_order = chip->ecc.options & NAND_ECC_SOFT_HAMMING_SM_ORDER;
+
+ __nand_calculate_ecc(buf, chip->ecc.size, code, sm_order);
return 0;
}
@@ -414,12 +397,13 @@ EXPORT_SYMBOL(nand_calculate_ecc);
* @read_ecc: ECC from the chip
* @calc_ecc: the ECC calculated from raw data
* @eccsize: data bytes per ECC step (256 or 512)
+ * @sm_order: Smart Media byte order
*
* Detect and correct a 1 bit error for eccsize byte block
*/
int __nand_correct_data(unsigned char *buf,
unsigned char *read_ecc, unsigned char *calc_ecc,
- unsigned int eccsize)
+ unsigned int eccsize, bool sm_order)
{
unsigned char b0, b1, b2, bit_addr;
unsigned int byte_addr;
@@ -431,13 +415,14 @@ int __nand_correct_data(unsigned char *buf,
* we might need the xor result more than once,
* so keep them in a local var
*/
-#ifdef CONFIG_MTD_NAND_ECC_SMC
- b0 = read_ecc[0] ^ calc_ecc[0];
- b1 = read_ecc[1] ^ calc_ecc[1];
-#else
- b0 = read_ecc[1] ^ calc_ecc[1];
- b1 = read_ecc[0] ^ calc_ecc[0];
-#endif
+ if (sm_order) {
+ b0 = read_ecc[0] ^ calc_ecc[0];
+ b1 = read_ecc[1] ^ calc_ecc[1];
+ } else {
+ b0 = read_ecc[1] ^ calc_ecc[1];
+ b1 = read_ecc[0] ^ calc_ecc[0];
+ }
+
b2 = read_ecc[2] ^ calc_ecc[2];
/* check if there are any bitfaults */
@@ -491,18 +476,20 @@ EXPORT_SYMBOL(__nand_correct_data);
/**
* nand_correct_data - [NAND Interface] Detect and correct bit error(s)
- * @mtd: MTD block structure
+ * @chip: NAND chip object
* @buf: raw data read from the chip
* @read_ecc: ECC from the chip
* @calc_ecc: the ECC calculated from raw data
*
* Detect and correct a 1 bit error for 256/512 byte block
*/
-int nand_correct_data(struct mtd_info *mtd, unsigned char *buf,
+int nand_correct_data(struct nand_chip *chip, unsigned char *buf,
unsigned char *read_ecc, unsigned char *calc_ecc)
{
- return __nand_correct_data(buf, read_ecc, calc_ecc,
- mtd_to_nand(mtd)->ecc.size);
+ bool sm_order = chip->ecc.options & NAND_ECC_SOFT_HAMMING_SM_ORDER;
+
+ return __nand_correct_data(buf, read_ecc, calc_ecc, chip->ecc.size,
+ sm_order);
}
EXPORT_SYMBOL(nand_correct_data);
diff --git a/drivers/mtd/nand/raw/nand_esmt.c b/drivers/mtd/nand/raw/nand_esmt.c
new file mode 100644
index 000000000000..96f039a83bc8
--- /dev/null
+++ b/drivers/mtd/nand/raw/nand_esmt.c
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 Toradex AG
+ *
+ * Author: Marcel Ziswiler <marcel.ziswiler@toradex.com>
+ */
+
+#include <linux/mtd/rawnand.h>
+#include "internals.h"
+
+static void esmt_nand_decode_id(struct nand_chip *chip)
+{
+ nand_decode_ext_id(chip);
+
+ /* Extract ECC requirements from 5th id byte. */
+ if (chip->id.len >= 5 && nand_is_slc(chip)) {
+ chip->ecc_step_ds = 512;
+ switch (chip->id.data[4] & 0x3) {
+ case 0x0:
+ chip->ecc_strength_ds = 4;
+ break;
+ case 0x1:
+ chip->ecc_strength_ds = 2;
+ break;
+ case 0x2:
+ chip->ecc_strength_ds = 1;
+ break;
+ default:
+ WARN(1, "Could not get ECC info");
+ chip->ecc_step_ds = 0;
+ break;
+ }
+ }
+}
+
+static int esmt_nand_init(struct nand_chip *chip)
+{
+ if (nand_is_slc(chip))
+ chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
+
+ return 0;
+}
+
+const struct nand_manufacturer_ops esmt_nand_manuf_ops = {
+ .detect = esmt_nand_decode_id,
+ .init = esmt_nand_init,
+};
diff --git a/drivers/mtd/nand/raw/nand_hynix.c b/drivers/mtd/nand/raw/nand_hynix.c
index 4ffbb26e76d6..ac1b5c103968 100644
--- a/drivers/mtd/nand/raw/nand_hynix.c
+++ b/drivers/mtd/nand/raw/nand_hynix.c
@@ -15,10 +15,11 @@
* GNU General Public License for more details.
*/
-#include <linux/mtd/rawnand.h>
#include <linux/sizes.h>
#include <linux/slab.h>
+#include "internals.h"
+
#define NAND_HYNIX_CMD_SET_PARAMS 0x36
#define NAND_HYNIX_CMD_APPLY_PARAMS 0x16
@@ -79,8 +80,6 @@ static bool hynix_nand_has_valid_jedecid(struct nand_chip *chip)
static int hynix_nand_cmd_op(struct nand_chip *chip, u8 cmd)
{
- struct mtd_info *mtd = nand_to_mtd(chip);
-
if (chip->exec_op) {
struct nand_op_instr instrs[] = {
NAND_OP_CMD(cmd, 0),
@@ -90,14 +89,13 @@ static int hynix_nand_cmd_op(struct nand_chip *chip, u8 cmd)
return nand_exec_op(chip, &op);
}
- chip->cmdfunc(mtd, cmd, -1, -1);
+ chip->legacy.cmdfunc(chip, cmd, -1, -1);
return 0;
}
static int hynix_nand_reg_write_op(struct nand_chip *chip, u8 addr, u8 val)
{
- struct mtd_info *mtd = nand_to_mtd(chip);
u16 column = ((u16)addr << 8) | addr;
if (chip->exec_op) {
@@ -110,15 +108,14 @@ static int hynix_nand_reg_write_op(struct nand_chip *chip, u8 addr, u8 val)
return nand_exec_op(chip, &op);
}
- chip->cmdfunc(mtd, NAND_CMD_NONE, column, -1);
- chip->write_byte(mtd, val);
+ chip->legacy.cmdfunc(chip, NAND_CMD_NONE, column, -1);
+ chip->legacy.write_byte(chip, val);
return 0;
}
-static int hynix_nand_setup_read_retry(struct mtd_info *mtd, int retry_mode)
+static int hynix_nand_setup_read_retry(struct nand_chip *chip, int retry_mode)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct hynix_nand *hynix = nand_get_manufacturer_data(chip);
const u8 *values;
int i, ret;
diff --git a/drivers/mtd/nand/raw/nand_ids.c b/drivers/mtd/nand/raw/nand_ids.c
index 5423c3bb388e..ea5a342cd91e 100644
--- a/drivers/mtd/nand/raw/nand_ids.c
+++ b/drivers/mtd/nand/raw/nand_ids.c
@@ -6,9 +6,11 @@
* published by the Free Software Foundation.
*
*/
-#include <linux/mtd/rawnand.h>
+
#include <linux/sizes.h>
+#include "internals.h"
+
#define LP_OPTIONS 0
#define LP_OPTIONS16 (LP_OPTIONS | NAND_BUSWIDTH_16)
@@ -169,21 +171,21 @@ struct nand_flash_dev nand_flash_ids[] = {
/* Manufacturer IDs */
static const struct nand_manufacturer nand_manufacturers[] = {
- {NAND_MFR_TOSHIBA, "Toshiba", &toshiba_nand_manuf_ops},
- {NAND_MFR_ESMT, "ESMT"},
- {NAND_MFR_SAMSUNG, "Samsung", &samsung_nand_manuf_ops},
+ {NAND_MFR_AMD, "AMD/Spansion", &amd_nand_manuf_ops},
+ {NAND_MFR_ATO, "ATO"},
+ {NAND_MFR_EON, "Eon"},
+ {NAND_MFR_ESMT, "ESMT", &esmt_nand_manuf_ops},
{NAND_MFR_FUJITSU, "Fujitsu"},
- {NAND_MFR_NATIONAL, "National"},
- {NAND_MFR_RENESAS, "Renesas"},
- {NAND_MFR_STMICRO, "ST Micro"},
{NAND_MFR_HYNIX, "Hynix", &hynix_nand_manuf_ops},
- {NAND_MFR_MICRON, "Micron", &micron_nand_manuf_ops},
- {NAND_MFR_AMD, "AMD/Spansion", &amd_nand_manuf_ops},
+ {NAND_MFR_INTEL, "Intel"},
{NAND_MFR_MACRONIX, "Macronix", &macronix_nand_manuf_ops},
- {NAND_MFR_EON, "Eon"},
+ {NAND_MFR_MICRON, "Micron", &micron_nand_manuf_ops},
+ {NAND_MFR_NATIONAL, "National"},
+ {NAND_MFR_RENESAS, "Renesas"},
+ {NAND_MFR_SAMSUNG, "Samsung", &samsung_nand_manuf_ops},
{NAND_MFR_SANDISK, "SanDisk"},
- {NAND_MFR_INTEL, "Intel"},
- {NAND_MFR_ATO, "ATO"},
+ {NAND_MFR_STMICRO, "ST Micro"},
+ {NAND_MFR_TOSHIBA, "Toshiba", &toshiba_nand_manuf_ops},
{NAND_MFR_WINBOND, "Winbond"},
};
diff --git a/drivers/mtd/nand/raw/nand_jedec.c b/drivers/mtd/nand/raw/nand_jedec.c
new file mode 100644
index 000000000000..5c26492c841d
--- /dev/null
+++ b/drivers/mtd/nand/raw/nand_jedec.c
@@ -0,0 +1,113 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
+ * 2002-2006 Thomas Gleixner (tglx@linutronix.de)
+ *
+ * Credits:
+ * David Woodhouse for adding multichip support
+ *
+ * Aleph One Ltd. and Toby Churchill Ltd. for supporting the
+ * rework for 2K page size chips
+ *
+ * This file contains all ONFI helpers.
+ */
+
+#include <linux/slab.h>
+
+#include "internals.h"
+
+/*
+ * Check if the NAND chip is JEDEC compliant, returns 1 if it is, 0 otherwise.
+ */
+int nand_jedec_detect(struct nand_chip *chip)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ struct nand_jedec_params *p;
+ struct jedec_ecc_info *ecc;
+ int jedec_version = 0;
+ char id[5];
+ int i, val, ret;
+
+ /* Try JEDEC for unknown chip or LP */
+ ret = nand_readid_op(chip, 0x40, id, sizeof(id));
+ if (ret || strncmp(id, "JEDEC", sizeof(id)))
+ return 0;
+
+ /* JEDEC chip: allocate a buffer to hold its parameter page */
+ p = kzalloc(sizeof(*p), GFP_KERNEL);
+ if (!p)
+ return -ENOMEM;
+
+ ret = nand_read_param_page_op(chip, 0x40, NULL, 0);
+ if (ret) {
+ ret = 0;
+ goto free_jedec_param_page;
+ }
+
+ for (i = 0; i < 3; i++) {
+ ret = nand_read_data_op(chip, p, sizeof(*p), true);
+ if (ret) {
+ ret = 0;
+ goto free_jedec_param_page;
+ }
+
+ if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 510) ==
+ le16_to_cpu(p->crc))
+ break;
+ }
+
+ if (i == 3) {
+ pr_err("Could not find valid JEDEC parameter page; aborting\n");
+ goto free_jedec_param_page;
+ }
+
+ /* Check version */
+ val = le16_to_cpu(p->revision);
+ if (val & (1 << 2))
+ jedec_version = 10;
+ else if (val & (1 << 1))
+ jedec_version = 1; /* vendor specific version */
+
+ if (!jedec_version) {
+ pr_info("unsupported JEDEC version: %d\n", val);
+ goto free_jedec_param_page;
+ }
+
+ sanitize_string(p->manufacturer, sizeof(p->manufacturer));
+ sanitize_string(p->model, sizeof(p->model));
+ chip->parameters.model = kstrdup(p->model, GFP_KERNEL);
+ if (!chip->parameters.model) {
+ ret = -ENOMEM;
+ goto free_jedec_param_page;
+ }
+
+ mtd->writesize = le32_to_cpu(p->byte_per_page);
+
+ /* Please reference to the comment for nand_flash_detect_onfi. */
+ mtd->erasesize = 1 << (fls(le32_to_cpu(p->pages_per_block)) - 1);
+ mtd->erasesize *= mtd->writesize;
+
+ mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page);
+
+ /* Please reference to the comment for nand_flash_detect_onfi. */
+ chip->chipsize = 1 << (fls(le32_to_cpu(p->blocks_per_lun)) - 1);
+ chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count;
+ chip->bits_per_cell = p->bits_per_cell;
+
+ if (le16_to_cpu(p->features) & JEDEC_FEATURE_16_BIT_BUS)
+ chip->options |= NAND_BUSWIDTH_16;
+
+ /* ECC info */
+ ecc = &p->ecc_info[0];
+
+ if (ecc->codeword_size >= 9) {
+ chip->ecc_strength_ds = ecc->ecc_bits;
+ chip->ecc_step_ds = 1 << ecc->codeword_size;
+ } else {
+ pr_warn("Invalid codeword size\n");
+ }
+
+free_jedec_param_page:
+ kfree(p);
+ return ret;
+}
diff --git a/drivers/mtd/nand/raw/nand_legacy.c b/drivers/mtd/nand/raw/nand_legacy.c
new file mode 100644
index 000000000000..c5ddc86cd98c
--- /dev/null
+++ b/drivers/mtd/nand/raw/nand_legacy.c
@@ -0,0 +1,642 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
+ * 2002-2006 Thomas Gleixner (tglx@linutronix.de)
+ *
+ * Credits:
+ * David Woodhouse for adding multichip support
+ *
+ * Aleph One Ltd. and Toby Churchill Ltd. for supporting the
+ * rework for 2K page size chips
+ *
+ * This file contains all legacy helpers/code that should be removed
+ * at some point.
+ */
+
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/nmi.h>
+
+#include "internals.h"
+
+/**
+ * nand_read_byte - [DEFAULT] read one byte from the chip
+ * @chip: NAND chip object
+ *
+ * Default read function for 8bit buswidth
+ */
+static uint8_t nand_read_byte(struct nand_chip *chip)
+{
+ return readb(chip->legacy.IO_ADDR_R);
+}
+
+/**
+ * nand_read_byte16 - [DEFAULT] read one byte endianness aware from the chip
+ * @chip: NAND chip object
+ *
+ * Default read function for 16bit buswidth with endianness conversion.
+ *
+ */
+static uint8_t nand_read_byte16(struct nand_chip *chip)
+{
+ return (uint8_t) cpu_to_le16(readw(chip->legacy.IO_ADDR_R));
+}
+
+/**
+ * nand_select_chip - [DEFAULT] control CE line
+ * @chip: NAND chip object
+ * @chipnr: chipnumber to select, -1 for deselect
+ *
+ * Default select function for 1 chip devices.
+ */
+static void nand_select_chip(struct nand_chip *chip, int chipnr)
+{
+ switch (chipnr) {
+ case -1:
+ chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE,
+ 0 | NAND_CTRL_CHANGE);
+ break;
+ case 0:
+ break;
+
+ default:
+ BUG();
+ }
+}
+
+/**
+ * nand_write_byte - [DEFAULT] write single byte to chip
+ * @chip: NAND chip object
+ * @byte: value to write
+ *
+ * Default function to write a byte to I/O[7:0]
+ */
+static void nand_write_byte(struct nand_chip *chip, uint8_t byte)
+{
+ chip->legacy.write_buf(chip, &byte, 1);
+}
+
+/**
+ * nand_write_byte16 - [DEFAULT] write single byte to a chip with width 16
+ * @chip: NAND chip object
+ * @byte: value to write
+ *
+ * Default function to write a byte to I/O[7:0] on a 16-bit wide chip.
+ */
+static void nand_write_byte16(struct nand_chip *chip, uint8_t byte)
+{
+ uint16_t word = byte;
+
+ /*
+ * It's not entirely clear what should happen to I/O[15:8] when writing
+ * a byte. The ONFi spec (Revision 3.1; 2012-09-19, Section 2.16) reads:
+ *
+ * When the host supports a 16-bit bus width, only data is
+ * transferred at the 16-bit width. All address and command line
+ * transfers shall use only the lower 8-bits of the data bus. During
+ * command transfers, the host may place any value on the upper
+ * 8-bits of the data bus. During address transfers, the host shall
+ * set the upper 8-bits of the data bus to 00h.
+ *
+ * One user of the write_byte callback is nand_set_features. The
+ * four parameters are specified to be written to I/O[7:0], but this is
+ * neither an address nor a command transfer. Let's assume a 0 on the
+ * upper I/O lines is OK.
+ */
+ chip->legacy.write_buf(chip, (uint8_t *)&word, 2);
+}
+
+/**
+ * nand_write_buf - [DEFAULT] write buffer to chip
+ * @chip: NAND chip object
+ * @buf: data buffer
+ * @len: number of bytes to write
+ *
+ * Default write function for 8bit buswidth.
+ */
+static void nand_write_buf(struct nand_chip *chip, const uint8_t *buf, int len)
+{
+ iowrite8_rep(chip->legacy.IO_ADDR_W, buf, len);
+}
+
+/**
+ * nand_read_buf - [DEFAULT] read chip data into buffer
+ * @chip: NAND chip object
+ * @buf: buffer to store date
+ * @len: number of bytes to read
+ *
+ * Default read function for 8bit buswidth.
+ */
+static void nand_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
+{
+ ioread8_rep(chip->legacy.IO_ADDR_R, buf, len);
+}
+
+/**
+ * nand_write_buf16 - [DEFAULT] write buffer to chip
+ * @chip: NAND chip object
+ * @buf: data buffer
+ * @len: number of bytes to write
+ *
+ * Default write function for 16bit buswidth.
+ */
+static void nand_write_buf16(struct nand_chip *chip, const uint8_t *buf,
+ int len)
+{
+ u16 *p = (u16 *) buf;
+
+ iowrite16_rep(chip->legacy.IO_ADDR_W, p, len >> 1);
+}
+
+/**
+ * nand_read_buf16 - [DEFAULT] read chip data into buffer
+ * @chip: NAND chip object
+ * @buf: buffer to store date
+ * @len: number of bytes to read
+ *
+ * Default read function for 16bit buswidth.
+ */
+static void nand_read_buf16(struct nand_chip *chip, uint8_t *buf, int len)
+{
+ u16 *p = (u16 *) buf;
+
+ ioread16_rep(chip->legacy.IO_ADDR_R, p, len >> 1);
+}
+
+/**
+ * panic_nand_wait_ready - [GENERIC] Wait for the ready pin after commands.
+ * @mtd: MTD device structure
+ * @timeo: Timeout
+ *
+ * Helper function for nand_wait_ready used when needing to wait in interrupt
+ * context.
+ */
+static void panic_nand_wait_ready(struct mtd_info *mtd, unsigned long timeo)
+{
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ int i;
+
+ /* Wait for the device to get ready */
+ for (i = 0; i < timeo; i++) {
+ if (chip->legacy.dev_ready(chip))
+ break;
+ touch_softlockup_watchdog();
+ mdelay(1);
+ }
+}
+
+/**
+ * nand_wait_ready - [GENERIC] Wait for the ready pin after commands.
+ * @chip: NAND chip object
+ *
+ * Wait for the ready pin after a command, and warn if a timeout occurs.
+ */
+void nand_wait_ready(struct nand_chip *chip)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ unsigned long timeo = 400;
+
+ if (in_interrupt() || oops_in_progress)
+ return panic_nand_wait_ready(mtd, timeo);
+
+ /* Wait until command is processed or timeout occurs */
+ timeo = jiffies + msecs_to_jiffies(timeo);
+ do {
+ if (chip->legacy.dev_ready(chip))
+ return;
+ cond_resched();
+ } while (time_before(jiffies, timeo));
+
+ if (!chip->legacy.dev_ready(chip))
+ pr_warn_ratelimited("timeout while waiting for chip to become ready\n");
+}
+EXPORT_SYMBOL_GPL(nand_wait_ready);
+
+/**
+ * nand_wait_status_ready - [GENERIC] Wait for the ready status after commands.
+ * @mtd: MTD device structure
+ * @timeo: Timeout in ms
+ *
+ * Wait for status ready (i.e. command done) or timeout.
+ */
+static void nand_wait_status_ready(struct mtd_info *mtd, unsigned long timeo)
+{
+ register struct nand_chip *chip = mtd_to_nand(mtd);
+ int ret;
+
+ timeo = jiffies + msecs_to_jiffies(timeo);
+ do {
+ u8 status;
+
+ ret = nand_read_data_op(chip, &status, sizeof(status), true);
+ if (ret)
+ return;
+
+ if (status & NAND_STATUS_READY)
+ break;
+ touch_softlockup_watchdog();
+ } while (time_before(jiffies, timeo));
+};
+
+/**
+ * nand_command - [DEFAULT] Send command to NAND device
+ * @chip: NAND chip object
+ * @command: the command to be sent
+ * @column: the column address for this command, -1 if none
+ * @page_addr: the page address for this command, -1 if none
+ *
+ * Send command to NAND device. This function is used for small page devices
+ * (512 Bytes per page).
+ */
+static void nand_command(struct nand_chip *chip, unsigned int command,
+ int column, int page_addr)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ int ctrl = NAND_CTRL_CLE | NAND_CTRL_CHANGE;
+
+ /* Write out the command to the device */
+ if (command == NAND_CMD_SEQIN) {
+ int readcmd;
+
+ if (column >= mtd->writesize) {
+ /* OOB area */
+ column -= mtd->writesize;
+ readcmd = NAND_CMD_READOOB;
+ } else if (column < 256) {
+ /* First 256 bytes --> READ0 */
+ readcmd = NAND_CMD_READ0;
+ } else {
+ column -= 256;
+ readcmd = NAND_CMD_READ1;
+ }
+ chip->legacy.cmd_ctrl(chip, readcmd, ctrl);
+ ctrl &= ~NAND_CTRL_CHANGE;
+ }
+ if (command != NAND_CMD_NONE)
+ chip->legacy.cmd_ctrl(chip, command, ctrl);
+
+ /* Address cycle, when necessary */
+ ctrl = NAND_CTRL_ALE | NAND_CTRL_CHANGE;
+ /* Serially input address */
+ if (column != -1) {
+ /* Adjust columns for 16 bit buswidth */
+ if (chip->options & NAND_BUSWIDTH_16 &&
+ !nand_opcode_8bits(command))
+ column >>= 1;
+ chip->legacy.cmd_ctrl(chip, column, ctrl);
+ ctrl &= ~NAND_CTRL_CHANGE;
+ }
+ if (page_addr != -1) {
+ chip->legacy.cmd_ctrl(chip, page_addr, ctrl);
+ ctrl &= ~NAND_CTRL_CHANGE;
+ chip->legacy.cmd_ctrl(chip, page_addr >> 8, ctrl);
+ if (chip->options & NAND_ROW_ADDR_3)
+ chip->legacy.cmd_ctrl(chip, page_addr >> 16, ctrl);
+ }
+ chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE,
+ NAND_NCE | NAND_CTRL_CHANGE);
+
+ /*
+ * Program and erase have their own busy handlers status and sequential
+ * in needs no delay
+ */
+ switch (command) {
+
+ case NAND_CMD_NONE:
+ case NAND_CMD_PAGEPROG:
+ case NAND_CMD_ERASE1:
+ case NAND_CMD_ERASE2:
+ case NAND_CMD_SEQIN:
+ case NAND_CMD_STATUS:
+ case NAND_CMD_READID:
+ case NAND_CMD_SET_FEATURES:
+ return;
+
+ case NAND_CMD_RESET:
+ if (chip->legacy.dev_ready)
+ break;
+ udelay(chip->legacy.chip_delay);
+ chip->legacy.cmd_ctrl(chip, NAND_CMD_STATUS,
+ NAND_CTRL_CLE | NAND_CTRL_CHANGE);
+ chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE,
+ NAND_NCE | NAND_CTRL_CHANGE);
+ /* EZ-NAND can take upto 250ms as per ONFi v4.0 */
+ nand_wait_status_ready(mtd, 250);
+ return;
+
+ /* This applies to read commands */
+ case NAND_CMD_READ0:
+ /*
+ * READ0 is sometimes used to exit GET STATUS mode. When this
+ * is the case no address cycles are requested, and we can use
+ * this information to detect that we should not wait for the
+ * device to be ready.
+ */
+ if (column == -1 && page_addr == -1)
+ return;
+
+ default:
+ /*
+ * If we don't have access to the busy pin, we apply the given
+ * command delay
+ */
+ if (!chip->legacy.dev_ready) {
+ udelay(chip->legacy.chip_delay);
+ return;
+ }
+ }
+ /*
+ * Apply this short delay always to ensure that we do wait tWB in
+ * any case on any machine.
+ */
+ ndelay(100);
+
+ nand_wait_ready(chip);
+}
+
+static void nand_ccs_delay(struct nand_chip *chip)
+{
+ /*
+ * The controller already takes care of waiting for tCCS when the RNDIN
+ * or RNDOUT command is sent, return directly.
+ */
+ if (!(chip->options & NAND_WAIT_TCCS))
+ return;
+
+ /*
+ * Wait tCCS_min if it is correctly defined, otherwise wait 500ns
+ * (which should be safe for all NANDs).
+ */
+ if (chip->setup_data_interface)
+ ndelay(chip->data_interface.timings.sdr.tCCS_min / 1000);
+ else
+ ndelay(500);
+}
+
+/**
+ * nand_command_lp - [DEFAULT] Send command to NAND large page device
+ * @chip: NAND chip object
+ * @command: the command to be sent
+ * @column: the column address for this command, -1 if none
+ * @page_addr: the page address for this command, -1 if none
+ *
+ * Send command to NAND device. This is the version for the new large page
+ * devices. We don't have the separate regions as we have in the small page
+ * devices. We must emulate NAND_CMD_READOOB to keep the code compatible.
+ */
+static void nand_command_lp(struct nand_chip *chip, unsigned int command,
+ int column, int page_addr)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
+ /* Emulate NAND_CMD_READOOB */
+ if (command == NAND_CMD_READOOB) {
+ column += mtd->writesize;
+ command = NAND_CMD_READ0;
+ }
+
+ /* Command latch cycle */
+ if (command != NAND_CMD_NONE)
+ chip->legacy.cmd_ctrl(chip, command,
+ NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
+
+ if (column != -1 || page_addr != -1) {
+ int ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE;
+
+ /* Serially input address */
+ if (column != -1) {
+ /* Adjust columns for 16 bit buswidth */
+ if (chip->options & NAND_BUSWIDTH_16 &&
+ !nand_opcode_8bits(command))
+ column >>= 1;
+ chip->legacy.cmd_ctrl(chip, column, ctrl);
+ ctrl &= ~NAND_CTRL_CHANGE;
+
+ /* Only output a single addr cycle for 8bits opcodes. */
+ if (!nand_opcode_8bits(command))
+ chip->legacy.cmd_ctrl(chip, column >> 8, ctrl);
+ }
+ if (page_addr != -1) {
+ chip->legacy.cmd_ctrl(chip, page_addr, ctrl);
+ chip->legacy.cmd_ctrl(chip, page_addr >> 8,
+ NAND_NCE | NAND_ALE);
+ if (chip->options & NAND_ROW_ADDR_3)
+ chip->legacy.cmd_ctrl(chip, page_addr >> 16,
+ NAND_NCE | NAND_ALE);
+ }
+ }
+ chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE,
+ NAND_NCE | NAND_CTRL_CHANGE);
+
+ /*
+ * Program and erase have their own busy handlers status, sequential
+ * in and status need no delay.
+ */
+ switch (command) {
+
+ case NAND_CMD_NONE:
+ case NAND_CMD_CACHEDPROG:
+ case NAND_CMD_PAGEPROG:
+ case NAND_CMD_ERASE1:
+ case NAND_CMD_ERASE2:
+ case NAND_CMD_SEQIN:
+ case NAND_CMD_STATUS:
+ case NAND_CMD_READID:
+ case NAND_CMD_SET_FEATURES:
+ return;
+
+ case NAND_CMD_RNDIN:
+ nand_ccs_delay(chip);
+ return;
+
+ case NAND_CMD_RESET:
+ if (chip->legacy.dev_ready)
+ break;
+ udelay(chip->legacy.chip_delay);
+ chip->legacy.cmd_ctrl(chip, NAND_CMD_STATUS,
+ NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
+ chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE,
+ NAND_NCE | NAND_CTRL_CHANGE);
+ /* EZ-NAND can take upto 250ms as per ONFi v4.0 */
+ nand_wait_status_ready(mtd, 250);
+ return;
+
+ case NAND_CMD_RNDOUT:
+ /* No ready / busy check necessary */
+ chip->legacy.cmd_ctrl(chip, NAND_CMD_RNDOUTSTART,
+ NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
+ chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE,
+ NAND_NCE | NAND_CTRL_CHANGE);
+
+ nand_ccs_delay(chip);
+ return;
+
+ case NAND_CMD_READ0:
+ /*
+ * READ0 is sometimes used to exit GET STATUS mode. When this
+ * is the case no address cycles are requested, and we can use
+ * this information to detect that READSTART should not be
+ * issued.
+ */
+ if (column == -1 && page_addr == -1)
+ return;
+
+ chip->legacy.cmd_ctrl(chip, NAND_CMD_READSTART,
+ NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
+ chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE,
+ NAND_NCE | NAND_CTRL_CHANGE);
+
+ /* This applies to read commands */
+ default:
+ /*
+ * If we don't have access to the busy pin, we apply the given
+ * command delay.
+ */
+ if (!chip->legacy.dev_ready) {
+ udelay(chip->legacy.chip_delay);
+ return;
+ }
+ }
+
+ /*
+ * Apply this short delay always to ensure that we do wait tWB in
+ * any case on any machine.
+ */
+ ndelay(100);
+
+ nand_wait_ready(chip);
+}
+
+/**
+ * nand_get_set_features_notsupp - set/get features stub returning -ENOTSUPP
+ * @chip: nand chip info structure
+ * @addr: feature address.
+ * @subfeature_param: the subfeature parameters, a four bytes array.
+ *
+ * Should be used by NAND controller drivers that do not support the SET/GET
+ * FEATURES operations.
+ */
+int nand_get_set_features_notsupp(struct nand_chip *chip, int addr,
+ u8 *subfeature_param)
+{
+ return -ENOTSUPP;
+}
+EXPORT_SYMBOL(nand_get_set_features_notsupp);
+
+/**
+ * nand_wait - [DEFAULT] wait until the command is done
+ * @mtd: MTD device structure
+ * @chip: NAND chip structure
+ *
+ * Wait for command done. This applies to erase and program only.
+ */
+static int nand_wait(struct nand_chip *chip)
+{
+
+ unsigned long timeo = 400;
+ u8 status;
+ int ret;
+
+ /*
+ * Apply this short delay always to ensure that we do wait tWB in any
+ * case on any machine.
+ */
+ ndelay(100);
+
+ ret = nand_status_op(chip, NULL);
+ if (ret)
+ return ret;
+
+ if (in_interrupt() || oops_in_progress)
+ panic_nand_wait(chip, timeo);
+ else {
+ timeo = jiffies + msecs_to_jiffies(timeo);
+ do {
+ if (chip->legacy.dev_ready) {
+ if (chip->legacy.dev_ready(chip))
+ break;
+ } else {
+ ret = nand_read_data_op(chip, &status,
+ sizeof(status), true);
+ if (ret)
+ return ret;
+
+ if (status & NAND_STATUS_READY)
+ break;
+ }
+ cond_resched();
+ } while (time_before(jiffies, timeo));
+ }
+
+ ret = nand_read_data_op(chip, &status, sizeof(status), true);
+ if (ret)
+ return ret;
+
+ /* This can happen if in case of timeout or buggy dev_ready */
+ WARN_ON(!(status & NAND_STATUS_READY));
+ return status;
+}
+
+void nand_legacy_set_defaults(struct nand_chip *chip)
+{
+ unsigned int busw = chip->options & NAND_BUSWIDTH_16;
+
+ if (chip->exec_op)
+ return;
+
+ /* check for proper chip_delay setup, set 20us if not */
+ if (!chip->legacy.chip_delay)
+ chip->legacy.chip_delay = 20;
+
+ /* check, if a user supplied command function given */
+ if (!chip->legacy.cmdfunc && !chip->exec_op)
+ chip->legacy.cmdfunc = nand_command;
+
+ /* check, if a user supplied wait function given */
+ if (chip->legacy.waitfunc == NULL)
+ chip->legacy.waitfunc = nand_wait;
+
+ if (!chip->select_chip)
+ chip->select_chip = nand_select_chip;
+
+ /* If called twice, pointers that depend on busw may need to be reset */
+ if (!chip->legacy.read_byte || chip->legacy.read_byte == nand_read_byte)
+ chip->legacy.read_byte = busw ? nand_read_byte16 : nand_read_byte;
+ if (!chip->legacy.write_buf || chip->legacy.write_buf == nand_write_buf)
+ chip->legacy.write_buf = busw ? nand_write_buf16 : nand_write_buf;
+ if (!chip->legacy.write_byte || chip->legacy.write_byte == nand_write_byte)
+ chip->legacy.write_byte = busw ? nand_write_byte16 : nand_write_byte;
+ if (!chip->legacy.read_buf || chip->legacy.read_buf == nand_read_buf)
+ chip->legacy.read_buf = busw ? nand_read_buf16 : nand_read_buf;
+}
+
+void nand_legacy_adjust_cmdfunc(struct nand_chip *chip)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
+ /* Do not replace user supplied command function! */
+ if (mtd->writesize > 512 && chip->legacy.cmdfunc == nand_command)
+ chip->legacy.cmdfunc = nand_command_lp;
+}
+
+int nand_legacy_check_hooks(struct nand_chip *chip)
+{
+ /*
+ * ->legacy.cmdfunc() is legacy and will only be used if ->exec_op() is
+ * not populated.
+ */
+ if (chip->exec_op)
+ return 0;
+
+ /*
+ * Default functions assigned for ->legacy.cmdfunc() and
+ * ->select_chip() both expect ->legacy.cmd_ctrl() to be populated.
+ */
+ if ((!chip->legacy.cmdfunc || !chip->select_chip) &&
+ !chip->legacy.cmd_ctrl) {
+ pr_err("->legacy.cmd_ctrl() should be provided\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
diff --git a/drivers/mtd/nand/raw/nand_macronix.c b/drivers/mtd/nand/raw/nand_macronix.c
index 49c546c97c6f..358dcc957bb2 100644
--- a/drivers/mtd/nand/raw/nand_macronix.c
+++ b/drivers/mtd/nand/raw/nand_macronix.c
@@ -15,7 +15,7 @@
* GNU General Public License for more details.
*/
-#include <linux/mtd/rawnand.h>
+#include "internals.h"
/*
* Macronix AC series does not support using SET/GET_FEATURES to change
diff --git a/drivers/mtd/nand/raw/nand_micron.c b/drivers/mtd/nand/raw/nand_micron.c
index f5dc0a7a2456..b85e1c13b79e 100644
--- a/drivers/mtd/nand/raw/nand_micron.c
+++ b/drivers/mtd/nand/raw/nand_micron.c
@@ -15,9 +15,10 @@
* GNU General Public License for more details.
*/
-#include <linux/mtd/rawnand.h>
#include <linux/slab.h>
+#include "internals.h"
+
/*
* Special Micron status bit 3 indicates that the block has been
* corrected by on-die ECC and should be rewritten.
@@ -74,9 +75,8 @@ struct micron_nand {
struct micron_on_die_ecc ecc;
};
-static int micron_nand_setup_read_retry(struct mtd_info *mtd, int retry_mode)
+static int micron_nand_setup_read_retry(struct nand_chip *chip, int retry_mode)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
u8 feature[ONFI_SUBFEATURE_PARAM_LEN] = {retry_mode};
return nand_set_features(chip, ONFI_FEATURE_ADDR_READ_RETRY, feature);
@@ -290,10 +290,10 @@ static int micron_nand_on_die_ecc_status_8(struct nand_chip *chip, u8 status)
}
static int
-micron_nand_read_page_on_die_ecc(struct mtd_info *mtd, struct nand_chip *chip,
- uint8_t *buf, int oob_required,
- int page)
+micron_nand_read_page_on_die_ecc(struct nand_chip *chip, uint8_t *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
u8 status;
int ret, max_bitflips = 0;
@@ -332,9 +332,8 @@ out:
}
static int
-micron_nand_write_page_on_die_ecc(struct mtd_info *mtd, struct nand_chip *chip,
- const uint8_t *buf, int oob_required,
- int page)
+micron_nand_write_page_on_die_ecc(struct nand_chip *chip, const uint8_t *buf,
+ int oob_required, int page)
{
int ret;
@@ -342,7 +341,7 @@ micron_nand_write_page_on_die_ecc(struct mtd_info *mtd, struct nand_chip *chip,
if (ret)
return ret;
- ret = nand_write_page_raw(mtd, chip, buf, oob_required, page);
+ ret = nand_write_page_raw(chip, buf, oob_required, page);
micron_nand_on_die_ecc_setup(chip, false);
return ret;
diff --git a/drivers/mtd/nand/raw/nand_onfi.c b/drivers/mtd/nand/raw/nand_onfi.c
new file mode 100644
index 000000000000..d8184cf591ad
--- /dev/null
+++ b/drivers/mtd/nand/raw/nand_onfi.c
@@ -0,0 +1,305 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
+ * 2002-2006 Thomas Gleixner (tglx@linutronix.de)
+ *
+ * Credits:
+ * David Woodhouse for adding multichip support
+ *
+ * Aleph One Ltd. and Toby Churchill Ltd. for supporting the
+ * rework for 2K page size chips
+ *
+ * This file contains all ONFI helpers.
+ */
+
+#include <linux/slab.h>
+
+#include "internals.h"
+
+u16 onfi_crc16(u16 crc, u8 const *p, size_t len)
+{
+ int i;
+ while (len--) {
+ crc ^= *p++ << 8;
+ for (i = 0; i < 8; i++)
+ crc = (crc << 1) ^ ((crc & 0x8000) ? 0x8005 : 0);
+ }
+
+ return crc;
+}
+
+/* Parse the Extended Parameter Page. */
+static int nand_flash_detect_ext_param_page(struct nand_chip *chip,
+ struct nand_onfi_params *p)
+{
+ struct onfi_ext_param_page *ep;
+ struct onfi_ext_section *s;
+ struct onfi_ext_ecc_info *ecc;
+ uint8_t *cursor;
+ int ret;
+ int len;
+ int i;
+
+ len = le16_to_cpu(p->ext_param_page_length) * 16;
+ ep = kmalloc(len, GFP_KERNEL);
+ if (!ep)
+ return -ENOMEM;
+
+ /* Send our own NAND_CMD_PARAM. */
+ ret = nand_read_param_page_op(chip, 0, NULL, 0);
+ if (ret)
+ goto ext_out;
+
+ /* Use the Change Read Column command to skip the ONFI param pages. */
+ ret = nand_change_read_column_op(chip,
+ sizeof(*p) * p->num_of_param_pages,
+ ep, len, true);
+ if (ret)
+ goto ext_out;
+
+ ret = -EINVAL;
+ if ((onfi_crc16(ONFI_CRC_BASE, ((uint8_t *)ep) + 2, len - 2)
+ != le16_to_cpu(ep->crc))) {
+ pr_debug("fail in the CRC.\n");
+ goto ext_out;
+ }
+
+ /*
+ * Check the signature.
+ * Do not strictly follow the ONFI spec, maybe changed in future.
+ */
+ if (strncmp(ep->sig, "EPPS", 4)) {
+ pr_debug("The signature is invalid.\n");
+ goto ext_out;
+ }
+
+ /* find the ECC section. */
+ cursor = (uint8_t *)(ep + 1);
+ for (i = 0; i < ONFI_EXT_SECTION_MAX; i++) {
+ s = ep->sections + i;
+ if (s->type == ONFI_SECTION_TYPE_2)
+ break;
+ cursor += s->length * 16;
+ }
+ if (i == ONFI_EXT_SECTION_MAX) {
+ pr_debug("We can not find the ECC section.\n");
+ goto ext_out;
+ }
+
+ /* get the info we want. */
+ ecc = (struct onfi_ext_ecc_info *)cursor;
+
+ if (!ecc->codeword_size) {
+ pr_debug("Invalid codeword size\n");
+ goto ext_out;
+ }
+
+ chip->ecc_strength_ds = ecc->ecc_bits;
+ chip->ecc_step_ds = 1 << ecc->codeword_size;
+ ret = 0;
+
+ext_out:
+ kfree(ep);
+ return ret;
+}
+
+/*
+ * Recover data with bit-wise majority
+ */
+static void nand_bit_wise_majority(const void **srcbufs,
+ unsigned int nsrcbufs,
+ void *dstbuf,
+ unsigned int bufsize)
+{
+ int i, j, k;
+
+ for (i = 0; i < bufsize; i++) {
+ u8 val = 0;
+
+ for (j = 0; j < 8; j++) {
+ unsigned int cnt = 0;
+
+ for (k = 0; k < nsrcbufs; k++) {
+ const u8 *srcbuf = srcbufs[k];
+
+ if (srcbuf[i] & BIT(j))
+ cnt++;
+ }
+
+ if (cnt > nsrcbufs / 2)
+ val |= BIT(j);
+ }
+
+ ((u8 *)dstbuf)[i] = val;
+ }
+}
+
+/*
+ * Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise.
+ */
+int nand_onfi_detect(struct nand_chip *chip)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ struct nand_onfi_params *p;
+ struct onfi_params *onfi;
+ int onfi_version = 0;
+ char id[4];
+ int i, ret, val;
+
+ /* Try ONFI for unknown chip or LP */
+ ret = nand_readid_op(chip, 0x20, id, sizeof(id));
+ if (ret || strncmp(id, "ONFI", 4))
+ return 0;
+
+ /* ONFI chip: allocate a buffer to hold its parameter page */
+ p = kzalloc((sizeof(*p) * 3), GFP_KERNEL);
+ if (!p)
+ return -ENOMEM;
+
+ ret = nand_read_param_page_op(chip, 0, NULL, 0);
+ if (ret) {
+ ret = 0;
+ goto free_onfi_param_page;
+ }
+
+ for (i = 0; i < 3; i++) {
+ ret = nand_read_data_op(chip, &p[i], sizeof(*p), true);
+ if (ret) {
+ ret = 0;
+ goto free_onfi_param_page;
+ }
+
+ if (onfi_crc16(ONFI_CRC_BASE, (u8 *)&p[i], 254) ==
+ le16_to_cpu(p->crc)) {
+ if (i)
+ memcpy(p, &p[i], sizeof(*p));
+ break;
+ }
+ }
+
+ if (i == 3) {
+ const void *srcbufs[3] = {p, p + 1, p + 2};
+
+ pr_warn("Could not find a valid ONFI parameter page, trying bit-wise majority to recover it\n");
+ nand_bit_wise_majority(srcbufs, ARRAY_SIZE(srcbufs), p,
+ sizeof(*p));
+
+ if (onfi_crc16(ONFI_CRC_BASE, (u8 *)p, 254) !=
+ le16_to_cpu(p->crc)) {
+ pr_err("ONFI parameter recovery failed, aborting\n");
+ goto free_onfi_param_page;
+ }
+ }
+
+ if (chip->manufacturer.desc && chip->manufacturer.desc->ops &&
+ chip->manufacturer.desc->ops->fixup_onfi_param_page)
+ chip->manufacturer.desc->ops->fixup_onfi_param_page(chip, p);
+
+ /* Check version */
+ val = le16_to_cpu(p->revision);
+ if (val & ONFI_VERSION_2_3)
+ onfi_version = 23;
+ else if (val & ONFI_VERSION_2_2)
+ onfi_version = 22;
+ else if (val & ONFI_VERSION_2_1)
+ onfi_version = 21;
+ else if (val & ONFI_VERSION_2_0)
+ onfi_version = 20;
+ else if (val & ONFI_VERSION_1_0)
+ onfi_version = 10;
+
+ if (!onfi_version) {
+ pr_info("unsupported ONFI version: %d\n", val);
+ goto free_onfi_param_page;
+ }
+
+ sanitize_string(p->manufacturer, sizeof(p->manufacturer));
+ sanitize_string(p->model, sizeof(p->model));
+ chip->parameters.model = kstrdup(p->model, GFP_KERNEL);
+ if (!chip->parameters.model) {
+ ret = -ENOMEM;
+ goto free_onfi_param_page;
+ }
+
+ mtd->writesize = le32_to_cpu(p->byte_per_page);
+
+ /*
+ * pages_per_block and blocks_per_lun may not be a power-of-2 size
+ * (don't ask me who thought of this...). MTD assumes that these
+ * dimensions will be power-of-2, so just truncate the remaining area.
+ */
+ mtd->erasesize = 1 << (fls(le32_to_cpu(p->pages_per_block)) - 1);
+ mtd->erasesize *= mtd->writesize;
+
+ mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page);
+
+ /* See erasesize comment */
+ chip->chipsize = 1 << (fls(le32_to_cpu(p->blocks_per_lun)) - 1);
+ chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count;
+ chip->bits_per_cell = p->bits_per_cell;
+
+ chip->max_bb_per_die = le16_to_cpu(p->bb_per_lun);
+ chip->blocks_per_die = le32_to_cpu(p->blocks_per_lun);
+
+ if (le16_to_cpu(p->features) & ONFI_FEATURE_16_BIT_BUS)
+ chip->options |= NAND_BUSWIDTH_16;
+
+ if (p->ecc_bits != 0xff) {
+ chip->ecc_strength_ds = p->ecc_bits;
+ chip->ecc_step_ds = 512;
+ } else if (onfi_version >= 21 &&
+ (le16_to_cpu(p->features) & ONFI_FEATURE_EXT_PARAM_PAGE)) {
+
+ /*
+ * The nand_flash_detect_ext_param_page() uses the
+ * Change Read Column command which maybe not supported
+ * by the chip->legacy.cmdfunc. So try to update the
+ * chip->legacy.cmdfunc now. We do not replace user supplied
+ * command function.
+ */
+ nand_legacy_adjust_cmdfunc(chip);
+
+ /* The Extended Parameter Page is supported since ONFI 2.1. */
+ if (nand_flash_detect_ext_param_page(chip, p))
+ pr_warn("Failed to detect ONFI extended param page\n");
+ } else {
+ pr_warn("Could not retrieve ONFI ECC requirements\n");
+ }
+
+ /* Save some parameters from the parameter page for future use */
+ if (le16_to_cpu(p->opt_cmd) & ONFI_OPT_CMD_SET_GET_FEATURES) {
+ chip->parameters.supports_set_get_features = true;
+ bitmap_set(chip->parameters.get_feature_list,
+ ONFI_FEATURE_ADDR_TIMING_MODE, 1);
+ bitmap_set(chip->parameters.set_feature_list,
+ ONFI_FEATURE_ADDR_TIMING_MODE, 1);
+ }
+
+ onfi = kzalloc(sizeof(*onfi), GFP_KERNEL);
+ if (!onfi) {
+ ret = -ENOMEM;
+ goto free_model;
+ }
+
+ onfi->version = onfi_version;
+ onfi->tPROG = le16_to_cpu(p->t_prog);
+ onfi->tBERS = le16_to_cpu(p->t_bers);
+ onfi->tR = le16_to_cpu(p->t_r);
+ onfi->tCCS = le16_to_cpu(p->t_ccs);
+ onfi->async_timing_mode = le16_to_cpu(p->async_timing_mode);
+ onfi->vendor_revision = le16_to_cpu(p->vendor_revision);
+ memcpy(onfi->vendor, p->vendor, sizeof(p->vendor));
+ chip->parameters.onfi = onfi;
+
+ /* Identification done, free the full ONFI parameter page and exit */
+ kfree(p);
+
+ return 1;
+
+free_model:
+ kfree(chip->parameters.model);
+free_onfi_param_page:
+ kfree(p);
+
+ return ret;
+}
diff --git a/drivers/mtd/nand/raw/nand_samsung.c b/drivers/mtd/nand/raw/nand_samsung.c
index ef022f62f74c..e46d4c492ad8 100644
--- a/drivers/mtd/nand/raw/nand_samsung.c
+++ b/drivers/mtd/nand/raw/nand_samsung.c
@@ -15,7 +15,7 @@
* GNU General Public License for more details.
*/
-#include <linux/mtd/rawnand.h>
+#include "internals.h"
static void samsung_nand_decode_id(struct nand_chip *chip)
{
diff --git a/drivers/mtd/nand/raw/nand_timings.c b/drivers/mtd/nand/raw/nand_timings.c
index ebc7b5f76f77..bea3062d71d6 100644
--- a/drivers/mtd/nand/raw/nand_timings.c
+++ b/drivers/mtd/nand/raw/nand_timings.c
@@ -11,7 +11,8 @@
#include <linux/kernel.h>
#include <linux/err.h>
#include <linux/export.h>
-#include <linux/mtd/rawnand.h>
+
+#include "internals.h"
#define ONFI_DYN_TIMING_MAX U16_MAX
@@ -271,20 +272,6 @@ static const struct nand_data_interface onfi_sdr_timings[] = {
};
/**
- * onfi_async_timing_mode_to_sdr_timings - [NAND Interface] Retrieve NAND
- * timings according to the given ONFI timing mode
- * @mode: ONFI timing mode
- */
-const struct nand_sdr_timings *onfi_async_timing_mode_to_sdr_timings(int mode)
-{
- if (mode < 0 || mode >= ARRAY_SIZE(onfi_sdr_timings))
- return ERR_PTR(-EINVAL);
-
- return &onfi_sdr_timings[mode].timings.sdr;
-}
-EXPORT_SYMBOL(onfi_async_timing_mode_to_sdr_timings);
-
-/**
* onfi_fill_data_interface - [NAND Interface] Initialize a data interface from
* given ONFI mode
* @mode: The ONFI timing mode
@@ -339,4 +326,3 @@ int onfi_fill_data_interface(struct nand_chip *chip,
return 0;
}
-EXPORT_SYMBOL(onfi_fill_data_interface);
diff --git a/drivers/mtd/nand/raw/nand_toshiba.c b/drivers/mtd/nand/raw/nand_toshiba.c
index ab43f027cd23..d068163b64b3 100644
--- a/drivers/mtd/nand/raw/nand_toshiba.c
+++ b/drivers/mtd/nand/raw/nand_toshiba.c
@@ -15,7 +15,88 @@
* GNU General Public License for more details.
*/
-#include <linux/mtd/rawnand.h>
+#include "internals.h"
+
+/* Bit for detecting BENAND */
+#define TOSHIBA_NAND_ID4_IS_BENAND BIT(7)
+
+/* Recommended to rewrite for BENAND */
+#define TOSHIBA_NAND_STATUS_REWRITE_RECOMMENDED BIT(3)
+
+static int toshiba_nand_benand_eccstatus(struct nand_chip *chip)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ int ret;
+ unsigned int max_bitflips = 0;
+ u8 status;
+
+ /* Check Status */
+ ret = nand_status_op(chip, &status);
+ if (ret)
+ return ret;
+
+ if (status & NAND_STATUS_FAIL) {
+ /* uncorrected */
+ mtd->ecc_stats.failed++;
+ } else if (status & TOSHIBA_NAND_STATUS_REWRITE_RECOMMENDED) {
+ /* corrected */
+ max_bitflips = mtd->bitflip_threshold;
+ mtd->ecc_stats.corrected += max_bitflips;
+ }
+
+ return max_bitflips;
+}
+
+static int
+toshiba_nand_read_page_benand(struct nand_chip *chip, uint8_t *buf,
+ int oob_required, int page)
+{
+ int ret;
+
+ ret = nand_read_page_raw(chip, buf, oob_required, page);
+ if (ret)
+ return ret;
+
+ return toshiba_nand_benand_eccstatus(chip);
+}
+
+static int
+toshiba_nand_read_subpage_benand(struct nand_chip *chip, uint32_t data_offs,
+ uint32_t readlen, uint8_t *bufpoi, int page)
+{
+ int ret;
+
+ ret = nand_read_page_op(chip, page, data_offs,
+ bufpoi + data_offs, readlen);
+ if (ret)
+ return ret;
+
+ return toshiba_nand_benand_eccstatus(chip);
+}
+
+static void toshiba_nand_benand_init(struct nand_chip *chip)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
+ /*
+ * On BENAND, the entire OOB region can be used by the MTD user.
+ * The calculated ECC bytes are stored into other isolated
+ * area which is not accessible to users.
+ * This is why chip->ecc.bytes = 0.
+ */
+ chip->ecc.bytes = 0;
+ chip->ecc.size = 512;
+ chip->ecc.strength = 8;
+ chip->ecc.read_page = toshiba_nand_read_page_benand;
+ chip->ecc.read_subpage = toshiba_nand_read_subpage_benand;
+ chip->ecc.write_page = nand_write_page_raw;
+ chip->ecc.read_page_raw = nand_read_page_raw_notsupp;
+ chip->ecc.write_page_raw = nand_write_page_raw_notsupp;
+
+ chip->options |= NAND_SUBPAGE_READ;
+
+ mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
+}
static void toshiba_nand_decode_id(struct nand_chip *chip)
{
@@ -68,6 +149,11 @@ static int toshiba_nand_init(struct nand_chip *chip)
if (nand_is_slc(chip))
chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
+ /* Check that chip is BENAND and ECC mode is on-die */
+ if (nand_is_slc(chip) && chip->ecc.mode == NAND_ECC_ON_DIE &&
+ chip->id.data[4] & TOSHIBA_NAND_ID4_IS_BENAND)
+ toshiba_nand_benand_init(chip);
+
return 0;
}
diff --git a/drivers/mtd/nand/raw/nandsim.c b/drivers/mtd/nand/raw/nandsim.c
index 71ac034aee9c..c452819f6123 100644
--- a/drivers/mtd/nand/raw/nandsim.c
+++ b/drivers/mtd/nand/raw/nandsim.c
@@ -656,7 +656,7 @@ static int __init init_nandsim(struct mtd_info *mtd)
}
/* Force mtd to not do delays */
- chip->chip_delay = 0;
+ chip->legacy.chip_delay = 0;
/* Initialize the NAND flash parameters */
ns->busw = chip->options & NAND_BUSWIDTH_16 ? 16 : 8;
@@ -1872,9 +1872,8 @@ static void switch_state(struct nandsim *ns)
}
}
-static u_char ns_nand_read_byte(struct mtd_info *mtd)
+static u_char ns_nand_read_byte(struct nand_chip *chip)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct nandsim *ns = nand_get_controller_data(chip);
u_char outb = 0x00;
@@ -1934,9 +1933,8 @@ static u_char ns_nand_read_byte(struct mtd_info *mtd)
return outb;
}
-static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
+static void ns_nand_write_byte(struct nand_chip *chip, u_char byte)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct nandsim *ns = nand_get_controller_data(chip);
/* Sanity and correctness checks */
@@ -2089,9 +2087,8 @@ static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
return;
}
-static void ns_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int bitmask)
+static void ns_hwcontrol(struct nand_chip *chip, int cmd, unsigned int bitmask)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct nandsim *ns = nand_get_controller_data(chip);
ns->lines.cle = bitmask & NAND_CLE ? 1 : 0;
@@ -2099,27 +2096,18 @@ static void ns_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int bitmask)
ns->lines.ce = bitmask & NAND_NCE ? 1 : 0;
if (cmd != NAND_CMD_NONE)
- ns_nand_write_byte(mtd, cmd);
+ ns_nand_write_byte(chip, cmd);
}
-static int ns_device_ready(struct mtd_info *mtd)
+static int ns_device_ready(struct nand_chip *chip)
{
NS_DBG("device_ready\n");
return 1;
}
-static uint16_t ns_nand_read_word(struct mtd_info *mtd)
+static void ns_nand_write_buf(struct nand_chip *chip, const u_char *buf,
+ int len)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
-
- NS_DBG("read_word\n");
-
- return chip->read_byte(mtd) | (chip->read_byte(mtd) << 8);
-}
-
-static void ns_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
-{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct nandsim *ns = nand_get_controller_data(chip);
/* Check that chip is expecting data input */
@@ -2145,9 +2133,8 @@ static void ns_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
}
}
-static void ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+static void ns_nand_read_buf(struct nand_chip *chip, u_char *buf, int len)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct nandsim *ns = nand_get_controller_data(chip);
/* Sanity and correctness checks */
@@ -2169,7 +2156,7 @@ static void ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
int i;
for (i = 0; i < len; i++)
- buf[i] = mtd_to_nand(mtd)->read_byte(mtd);
+ buf[i] = chip->legacy.read_byte(chip);
return;
}
@@ -2262,12 +2249,11 @@ static int __init ns_init_module(void)
/*
* Register simulator's callbacks.
*/
- chip->cmd_ctrl = ns_hwcontrol;
- chip->read_byte = ns_nand_read_byte;
- chip->dev_ready = ns_device_ready;
- chip->write_buf = ns_nand_write_buf;
- chip->read_buf = ns_nand_read_buf;
- chip->read_word = ns_nand_read_word;
+ chip->legacy.cmd_ctrl = ns_hwcontrol;
+ chip->legacy.read_byte = ns_nand_read_byte;
+ chip->legacy.dev_ready = ns_device_ready;
+ chip->legacy.write_buf = ns_nand_write_buf;
+ chip->legacy.read_buf = ns_nand_read_buf;
chip->ecc.mode = NAND_ECC_SOFT;
chip->ecc.algo = NAND_ECC_HAMMING;
/* The NAND_SKIP_BBTSCAN option is necessary for 'overridesize' */
@@ -2319,7 +2305,7 @@ static int __init ns_init_module(void)
goto error;
chip->dummy_controller.ops = &ns_controller_ops;
- retval = nand_scan(nsmtd, 1);
+ retval = nand_scan(chip, 1);
if (retval) {
NS_ERR("Could not scan NAND Simulator device\n");
goto error;
@@ -2364,7 +2350,7 @@ static int __init ns_init_module(void)
err_exit:
free_nandsim(nand);
- nand_release(nsmtd);
+ nand_release(chip);
for (i = 0;i < ARRAY_SIZE(nand->partitions); ++i)
kfree(nand->partitions[i].name);
error:
@@ -2386,7 +2372,7 @@ static void __exit ns_cleanup_module(void)
int i;
free_nandsim(ns); /* Free nandsim private resources */
- nand_release(nsmtd); /* Unregister driver */
+ nand_release(chip); /* Unregister driver */
for (i = 0;i < ARRAY_SIZE(ns->partitions); ++i)
kfree(ns->partitions[i].name);
kfree(mtd_to_nand(nsmtd)); /* Free other structures */
diff --git a/drivers/mtd/nand/raw/ndfc.c b/drivers/mtd/nand/raw/ndfc.c
index 540fa1a0ea24..d49a7a17146c 100644
--- a/drivers/mtd/nand/raw/ndfc.c
+++ b/drivers/mtd/nand/raw/ndfc.c
@@ -44,10 +44,9 @@ struct ndfc_controller {
static struct ndfc_controller ndfc_ctrl[NDFC_MAX_CS];
-static void ndfc_select_chip(struct mtd_info *mtd, int chip)
+static void ndfc_select_chip(struct nand_chip *nchip, int chip)
{
uint32_t ccr;
- struct nand_chip *nchip = mtd_to_nand(mtd);
struct ndfc_controller *ndfc = nand_get_controller_data(nchip);
ccr = in_be32(ndfc->ndfcbase + NDFC_CCR);
@@ -59,9 +58,8 @@ static void ndfc_select_chip(struct mtd_info *mtd, int chip)
out_be32(ndfc->ndfcbase + NDFC_CCR, ccr);
}
-static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+static void ndfc_hwcontrol(struct nand_chip *chip, int cmd, unsigned int ctrl)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct ndfc_controller *ndfc = nand_get_controller_data(chip);
if (cmd == NAND_CMD_NONE)
@@ -73,18 +71,16 @@ static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
writel(cmd & 0xFF, ndfc->ndfcbase + NDFC_ALE);
}
-static int ndfc_ready(struct mtd_info *mtd)
+static int ndfc_ready(struct nand_chip *chip)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct ndfc_controller *ndfc = nand_get_controller_data(chip);
return in_be32(ndfc->ndfcbase + NDFC_STAT) & NDFC_STAT_IS_READY;
}
-static void ndfc_enable_hwecc(struct mtd_info *mtd, int mode)
+static void ndfc_enable_hwecc(struct nand_chip *chip, int mode)
{
uint32_t ccr;
- struct nand_chip *chip = mtd_to_nand(mtd);
struct ndfc_controller *ndfc = nand_get_controller_data(chip);
ccr = in_be32(ndfc->ndfcbase + NDFC_CCR);
@@ -93,10 +89,9 @@ static void ndfc_enable_hwecc(struct mtd_info *mtd, int mode)
wmb();
}
-static int ndfc_calculate_ecc(struct mtd_info *mtd,
+static int ndfc_calculate_ecc(struct nand_chip *chip,
const u_char *dat, u_char *ecc_code)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct ndfc_controller *ndfc = nand_get_controller_data(chip);
uint32_t ecc;
uint8_t *p = (uint8_t *)&ecc;
@@ -118,9 +113,8 @@ static int ndfc_calculate_ecc(struct mtd_info *mtd,
* functions. No further checking, as nand_base will always read/write
* page aligned.
*/
-static void ndfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+static void ndfc_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct ndfc_controller *ndfc = nand_get_controller_data(chip);
uint32_t *p = (uint32_t *) buf;
@@ -128,9 +122,8 @@ static void ndfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
*p++ = in_be32(ndfc->ndfcbase + NDFC_DATA);
}
-static void ndfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+static void ndfc_write_buf(struct nand_chip *chip, const uint8_t *buf, int len)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct ndfc_controller *ndfc = nand_get_controller_data(chip);
uint32_t *p = (uint32_t *) buf;
@@ -149,15 +142,15 @@ static int ndfc_chip_init(struct ndfc_controller *ndfc,
struct mtd_info *mtd = nand_to_mtd(chip);
int ret;
- chip->IO_ADDR_R = ndfc->ndfcbase + NDFC_DATA;
- chip->IO_ADDR_W = ndfc->ndfcbase + NDFC_DATA;
- chip->cmd_ctrl = ndfc_hwcontrol;
- chip->dev_ready = ndfc_ready;
+ chip->legacy.IO_ADDR_R = ndfc->ndfcbase + NDFC_DATA;
+ chip->legacy.IO_ADDR_W = ndfc->ndfcbase + NDFC_DATA;
+ chip->legacy.cmd_ctrl = ndfc_hwcontrol;
+ chip->legacy.dev_ready = ndfc_ready;
chip->select_chip = ndfc_select_chip;
- chip->chip_delay = 50;
+ chip->legacy.chip_delay = 50;
chip->controller = &ndfc->ndfc_control;
- chip->read_buf = ndfc_read_buf;
- chip->write_buf = ndfc_write_buf;
+ chip->legacy.read_buf = ndfc_read_buf;
+ chip->legacy.write_buf = ndfc_write_buf;
chip->ecc.correct = nand_correct_data;
chip->ecc.hwctl = ndfc_enable_hwecc;
chip->ecc.calculate = ndfc_calculate_ecc;
@@ -174,14 +167,14 @@ static int ndfc_chip_init(struct ndfc_controller *ndfc,
return -ENODEV;
nand_set_flash_node(chip, flash_np);
- mtd->name = kasprintf(GFP_KERNEL, "%s.%s", dev_name(&ndfc->ofdev->dev),
- flash_np->name);
+ mtd->name = kasprintf(GFP_KERNEL, "%s.%pOFn", dev_name(&ndfc->ofdev->dev),
+ flash_np);
if (!mtd->name) {
ret = -ENOMEM;
goto err;
}
- ret = nand_scan(mtd, 1);
+ ret = nand_scan(chip, 1);
if (ret)
goto err;
@@ -258,7 +251,7 @@ static int ndfc_remove(struct platform_device *ofdev)
struct ndfc_controller *ndfc = dev_get_drvdata(&ofdev->dev);
struct mtd_info *mtd = nand_to_mtd(&ndfc->chip);
- nand_release(mtd);
+ nand_release(&ndfc->chip);
kfree(mtd->name);
return 0;
diff --git a/drivers/mtd/nand/raw/nuc900_nand.c b/drivers/mtd/nand/raw/nuc900_nand.c
index af5b32c9a791..38b1994e7ed3 100644
--- a/drivers/mtd/nand/raw/nuc900_nand.c
+++ b/drivers/mtd/nand/raw/nuc900_nand.c
@@ -79,31 +79,31 @@ static const struct mtd_partition partitions[] = {
}
};
-static unsigned char nuc900_nand_read_byte(struct mtd_info *mtd)
+static unsigned char nuc900_nand_read_byte(struct nand_chip *chip)
{
unsigned char ret;
- struct nuc900_nand *nand = mtd_to_nuc900(mtd);
+ struct nuc900_nand *nand = mtd_to_nuc900(nand_to_mtd(chip));
ret = (unsigned char)read_data_reg(nand);
return ret;
}
-static void nuc900_nand_read_buf(struct mtd_info *mtd,
+static void nuc900_nand_read_buf(struct nand_chip *chip,
unsigned char *buf, int len)
{
int i;
- struct nuc900_nand *nand = mtd_to_nuc900(mtd);
+ struct nuc900_nand *nand = mtd_to_nuc900(nand_to_mtd(chip));
for (i = 0; i < len; i++)
buf[i] = (unsigned char)read_data_reg(nand);
}
-static void nuc900_nand_write_buf(struct mtd_info *mtd,
+static void nuc900_nand_write_buf(struct nand_chip *chip,
const unsigned char *buf, int len)
{
int i;
- struct nuc900_nand *nand = mtd_to_nuc900(mtd);
+ struct nuc900_nand *nand = mtd_to_nuc900(nand_to_mtd(chip));
for (i = 0; i < len; i++)
write_data_reg(nand, buf[i]);
@@ -120,19 +120,20 @@ static int nuc900_check_rb(struct nuc900_nand *nand)
return val;
}
-static int nuc900_nand_devready(struct mtd_info *mtd)
+static int nuc900_nand_devready(struct nand_chip *chip)
{
- struct nuc900_nand *nand = mtd_to_nuc900(mtd);
+ struct nuc900_nand *nand = mtd_to_nuc900(nand_to_mtd(chip));
int ready;
ready = (nuc900_check_rb(nand)) ? 1 : 0;
return ready;
}
-static void nuc900_nand_command_lp(struct mtd_info *mtd, unsigned int command,
+static void nuc900_nand_command_lp(struct nand_chip *chip,
+ unsigned int command,
int column, int page_addr)
{
- register struct nand_chip *chip = mtd_to_nand(mtd);
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct nuc900_nand *nand = mtd_to_nuc900(mtd);
if (command == NAND_CMD_READOOB) {
@@ -174,9 +175,9 @@ static void nuc900_nand_command_lp(struct mtd_info *mtd, unsigned int command,
return;
case NAND_CMD_RESET:
- if (chip->dev_ready)
+ if (chip->legacy.dev_ready)
break;
- udelay(chip->chip_delay);
+ udelay(chip->legacy.chip_delay);
write_cmd_reg(nand, NAND_CMD_STATUS);
write_cmd_reg(nand, command);
@@ -195,8 +196,8 @@ static void nuc900_nand_command_lp(struct mtd_info *mtd, unsigned int command,
write_cmd_reg(nand, NAND_CMD_READSTART);
default:
- if (!chip->dev_ready) {
- udelay(chip->chip_delay);
+ if (!chip->legacy.dev_ready) {
+ udelay(chip->legacy.chip_delay);
return;
}
}
@@ -205,7 +206,7 @@ static void nuc900_nand_command_lp(struct mtd_info *mtd, unsigned int command,
* any case on any machine. */
ndelay(100);
- while (!chip->dev_ready(mtd))
+ while (!chip->legacy.dev_ready(chip))
;
}
@@ -253,12 +254,12 @@ static int nuc900_nand_probe(struct platform_device *pdev)
return -ENOENT;
clk_enable(nuc900_nand->clk);
- chip->cmdfunc = nuc900_nand_command_lp;
- chip->dev_ready = nuc900_nand_devready;
- chip->read_byte = nuc900_nand_read_byte;
- chip->write_buf = nuc900_nand_write_buf;
- chip->read_buf = nuc900_nand_read_buf;
- chip->chip_delay = 50;
+ chip->legacy.cmdfunc = nuc900_nand_command_lp;
+ chip->legacy.dev_ready = nuc900_nand_devready;
+ chip->legacy.read_byte = nuc900_nand_read_byte;
+ chip->legacy.write_buf = nuc900_nand_write_buf;
+ chip->legacy.read_buf = nuc900_nand_read_buf;
+ chip->legacy.chip_delay = 50;
chip->options = 0;
chip->ecc.mode = NAND_ECC_SOFT;
chip->ecc.algo = NAND_ECC_HAMMING;
@@ -270,7 +271,7 @@ static int nuc900_nand_probe(struct platform_device *pdev)
nuc900_nand_enable(nuc900_nand);
- if (nand_scan(mtd, 1))
+ if (nand_scan(chip, 1))
return -ENXIO;
mtd_device_register(mtd, partitions, ARRAY_SIZE(partitions));
@@ -284,7 +285,7 @@ static int nuc900_nand_remove(struct platform_device *pdev)
{
struct nuc900_nand *nuc900_nand = platform_get_drvdata(pdev);
- nand_release(nand_to_mtd(&nuc900_nand->chip));
+ nand_release(&nuc900_nand->chip);
clk_disable(nuc900_nand->clk);
return 0;
diff --git a/drivers/mtd/nand/raw/omap2.c b/drivers/mtd/nand/raw/omap2.c
index 4546ac0bed4a..886d05c391ef 100644
--- a/drivers/mtd/nand/raw/omap2.c
+++ b/drivers/mtd/nand/raw/omap2.c
@@ -240,7 +240,7 @@ static int omap_prefetch_reset(int cs, struct omap_nand_info *info)
/**
* omap_hwcontrol - hardware specific access to control-lines
- * @mtd: MTD device structure
+ * @chip: NAND chip object
* @cmd: command to device
* @ctrl:
* NAND_NCE: bit 0 -> don't care
@@ -249,9 +249,9 @@ static int omap_prefetch_reset(int cs, struct omap_nand_info *info)
*
* NOTE: boards may use different bits for these!!
*/
-static void omap_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+static void omap_hwcontrol(struct nand_chip *chip, int cmd, unsigned int ctrl)
{
- struct omap_nand_info *info = mtd_to_omap(mtd);
+ struct omap_nand_info *info = mtd_to_omap(nand_to_mtd(chip));
if (cmd != NAND_CMD_NONE) {
if (ctrl & NAND_CLE)
@@ -275,7 +275,7 @@ static void omap_read_buf8(struct mtd_info *mtd, u_char *buf, int len)
{
struct nand_chip *nand = mtd_to_nand(mtd);
- ioread8_rep(nand->IO_ADDR_R, buf, len);
+ ioread8_rep(nand->legacy.IO_ADDR_R, buf, len);
}
/**
@@ -291,7 +291,7 @@ static void omap_write_buf8(struct mtd_info *mtd, const u_char *buf, int len)
bool status;
while (len--) {
- iowrite8(*p++, info->nand.IO_ADDR_W);
+ iowrite8(*p++, info->nand.legacy.IO_ADDR_W);
/* wait until buffer is available for write */
do {
status = info->ops->nand_writebuffer_empty();
@@ -309,7 +309,7 @@ static void omap_read_buf16(struct mtd_info *mtd, u_char *buf, int len)
{
struct nand_chip *nand = mtd_to_nand(mtd);
- ioread16_rep(nand->IO_ADDR_R, buf, len / 2);
+ ioread16_rep(nand->legacy.IO_ADDR_R, buf, len / 2);
}
/**
@@ -327,7 +327,7 @@ static void omap_write_buf16(struct mtd_info *mtd, const u_char * buf, int len)
len >>= 1;
while (len--) {
- iowrite16(*p++, info->nand.IO_ADDR_W);
+ iowrite16(*p++, info->nand.legacy.IO_ADDR_W);
/* wait until buffer is available for write */
do {
status = info->ops->nand_writebuffer_empty();
@@ -337,12 +337,13 @@ static void omap_write_buf16(struct mtd_info *mtd, const u_char * buf, int len)
/**
* omap_read_buf_pref - read data from NAND controller into buffer
- * @mtd: MTD device structure
+ * @chip: NAND chip object
* @buf: buffer to store date
* @len: number of bytes to read
*/
-static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len)
+static void omap_read_buf_pref(struct nand_chip *chip, u_char *buf, int len)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct omap_nand_info *info = mtd_to_omap(mtd);
uint32_t r_count = 0;
int ret = 0;
@@ -372,7 +373,7 @@ static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len)
r_count = readl(info->reg.gpmc_prefetch_status);
r_count = PREFETCH_STATUS_FIFO_CNT(r_count);
r_count = r_count >> 2;
- ioread32_rep(info->nand.IO_ADDR_R, p, r_count);
+ ioread32_rep(info->nand.legacy.IO_ADDR_R, p, r_count);
p += r_count;
len -= r_count << 2;
} while (len);
@@ -383,13 +384,14 @@ static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len)
/**
* omap_write_buf_pref - write buffer to NAND controller
- * @mtd: MTD device structure
+ * @chip: NAND chip object
* @buf: data buffer
* @len: number of bytes to write
*/
-static void omap_write_buf_pref(struct mtd_info *mtd,
- const u_char *buf, int len)
+static void omap_write_buf_pref(struct nand_chip *chip, const u_char *buf,
+ int len)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct omap_nand_info *info = mtd_to_omap(mtd);
uint32_t w_count = 0;
int i = 0, ret = 0;
@@ -399,7 +401,7 @@ static void omap_write_buf_pref(struct mtd_info *mtd,
/* take care of subpage writes */
if (len % 2 != 0) {
- writeb(*buf, info->nand.IO_ADDR_W);
+ writeb(*buf, info->nand.legacy.IO_ADDR_W);
p = (u16 *)(buf + 1);
len--;
}
@@ -419,7 +421,7 @@ static void omap_write_buf_pref(struct mtd_info *mtd,
w_count = PREFETCH_STATUS_FIFO_CNT(w_count);
w_count = w_count >> 1;
for (i = 0; (i < w_count) && len; i++, len -= 2)
- iowrite16(*p++, info->nand.IO_ADDR_W);
+ iowrite16(*p++, info->nand.legacy.IO_ADDR_W);
}
/* wait for data to flushed-out before reset the prefetch */
tim = 0;
@@ -528,14 +530,17 @@ out_copy:
/**
* omap_read_buf_dma_pref - read data from NAND controller into buffer
- * @mtd: MTD device structure
+ * @chip: NAND chip object
* @buf: buffer to store date
* @len: number of bytes to read
*/
-static void omap_read_buf_dma_pref(struct mtd_info *mtd, u_char *buf, int len)
+static void omap_read_buf_dma_pref(struct nand_chip *chip, u_char *buf,
+ int len)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
if (len <= mtd->oobsize)
- omap_read_buf_pref(mtd, buf, len);
+ omap_read_buf_pref(chip, buf, len);
else
/* start transfer in DMA mode */
omap_nand_dma_transfer(mtd, buf, len, 0x0);
@@ -543,18 +548,20 @@ static void omap_read_buf_dma_pref(struct mtd_info *mtd, u_char *buf, int len)
/**
* omap_write_buf_dma_pref - write buffer to NAND controller
- * @mtd: MTD device structure
+ * @chip: NAND chip object
* @buf: data buffer
* @len: number of bytes to write
*/
-static void omap_write_buf_dma_pref(struct mtd_info *mtd,
- const u_char *buf, int len)
+static void omap_write_buf_dma_pref(struct nand_chip *chip, const u_char *buf,
+ int len)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
if (len <= mtd->oobsize)
- omap_write_buf_pref(mtd, buf, len);
+ omap_write_buf_pref(chip, buf, len);
else
/* start transfer in DMA mode */
- omap_nand_dma_transfer(mtd, (u_char *) buf, len, 0x1);
+ omap_nand_dma_transfer(mtd, (u_char *)buf, len, 0x1);
}
/*
@@ -578,14 +585,14 @@ static irqreturn_t omap_nand_irq(int this_irq, void *dev)
bytes = info->buf_len;
else if (!info->buf_len)
bytes = 0;
- iowrite32_rep(info->nand.IO_ADDR_W,
- (u32 *)info->buf, bytes >> 2);
+ iowrite32_rep(info->nand.legacy.IO_ADDR_W, (u32 *)info->buf,
+ bytes >> 2);
info->buf = info->buf + bytes;
info->buf_len -= bytes;
} else {
- ioread32_rep(info->nand.IO_ADDR_R,
- (u32 *)info->buf, bytes >> 2);
+ ioread32_rep(info->nand.legacy.IO_ADDR_R, (u32 *)info->buf,
+ bytes >> 2);
info->buf = info->buf + bytes;
if (this_irq == info->gpmc_irq_count)
@@ -605,17 +612,19 @@ done:
/*
* omap_read_buf_irq_pref - read data from NAND controller into buffer
- * @mtd: MTD device structure
+ * @chip: NAND chip object
* @buf: buffer to store date
* @len: number of bytes to read
*/
-static void omap_read_buf_irq_pref(struct mtd_info *mtd, u_char *buf, int len)
+static void omap_read_buf_irq_pref(struct nand_chip *chip, u_char *buf,
+ int len)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct omap_nand_info *info = mtd_to_omap(mtd);
int ret = 0;
if (len <= mtd->oobsize) {
- omap_read_buf_pref(mtd, buf, len);
+ omap_read_buf_pref(chip, buf, len);
return;
}
@@ -651,20 +660,21 @@ out_copy:
/*
* omap_write_buf_irq_pref - write buffer to NAND controller
- * @mtd: MTD device structure
+ * @chip: NAND chip object
* @buf: data buffer
* @len: number of bytes to write
*/
-static void omap_write_buf_irq_pref(struct mtd_info *mtd,
- const u_char *buf, int len)
+static void omap_write_buf_irq_pref(struct nand_chip *chip, const u_char *buf,
+ int len)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct omap_nand_info *info = mtd_to_omap(mtd);
int ret = 0;
unsigned long tim, limit;
u32 val;
if (len <= mtd->oobsize) {
- omap_write_buf_pref(mtd, buf, len);
+ omap_write_buf_pref(chip, buf, len);
return;
}
@@ -857,7 +867,7 @@ static int omap_compare_ecc(u8 *ecc_data1, /* read from NAND memory */
/**
* omap_correct_data - Compares the ECC read with HW generated ECC
- * @mtd: MTD device structure
+ * @chip: NAND chip object
* @dat: page data
* @read_ecc: ecc read from nand flash
* @calc_ecc: ecc read from HW ECC registers
@@ -869,10 +879,10 @@ static int omap_compare_ecc(u8 *ecc_data1, /* read from NAND memory */
* corrected errors is returned. If uncorrectable errors exist, %-1 is
* returned.
*/
-static int omap_correct_data(struct mtd_info *mtd, u_char *dat,
- u_char *read_ecc, u_char *calc_ecc)
+static int omap_correct_data(struct nand_chip *chip, u_char *dat,
+ u_char *read_ecc, u_char *calc_ecc)
{
- struct omap_nand_info *info = mtd_to_omap(mtd);
+ struct omap_nand_info *info = mtd_to_omap(nand_to_mtd(chip));
int blockCnt = 0, i = 0, ret = 0;
int stat = 0;
@@ -900,7 +910,7 @@ static int omap_correct_data(struct mtd_info *mtd, u_char *dat,
/**
* omap_calcuate_ecc - Generate non-inverted ECC bytes.
- * @mtd: MTD device structure
+ * @chip: NAND chip object
* @dat: The pointer to data on which ecc is computed
* @ecc_code: The ecc_code buffer
*
@@ -910,10 +920,10 @@ static int omap_correct_data(struct mtd_info *mtd, u_char *dat,
* an erased page will produce an ECC mismatch between generated and read
* ECC bytes that has to be dealt with separately.
*/
-static int omap_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
- u_char *ecc_code)
+static int omap_calculate_ecc(struct nand_chip *chip, const u_char *dat,
+ u_char *ecc_code)
{
- struct omap_nand_info *info = mtd_to_omap(mtd);
+ struct omap_nand_info *info = mtd_to_omap(nand_to_mtd(chip));
u32 val;
val = readl(info->reg.gpmc_ecc_config);
@@ -935,10 +945,9 @@ static int omap_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
* @mtd: MTD device structure
* @mode: Read/Write mode
*/
-static void omap_enable_hwecc(struct mtd_info *mtd, int mode)
+static void omap_enable_hwecc(struct nand_chip *chip, int mode)
{
- struct omap_nand_info *info = mtd_to_omap(mtd);
- struct nand_chip *chip = mtd_to_nand(mtd);
+ struct omap_nand_info *info = mtd_to_omap(nand_to_mtd(chip));
unsigned int dev_width = (chip->options & NAND_BUSWIDTH_16) ? 1 : 0;
u32 val;
@@ -972,8 +981,7 @@ static void omap_enable_hwecc(struct mtd_info *mtd, int mode)
/**
* omap_wait - wait until the command is done
- * @mtd: MTD device structure
- * @chip: NAND Chip structure
+ * @this: NAND Chip structure
*
* Wait function is called during Program and erase operations and
* the way it is called from MTD layer, we should wait till the NAND
@@ -982,10 +990,9 @@ static void omap_enable_hwecc(struct mtd_info *mtd, int mode)
* Erase can take up to 400ms and program up to 20ms according to
* general NAND and SmartMedia specs
*/
-static int omap_wait(struct mtd_info *mtd, struct nand_chip *chip)
+static int omap_wait(struct nand_chip *this)
{
- struct nand_chip *this = mtd_to_nand(mtd);
- struct omap_nand_info *info = mtd_to_omap(mtd);
+ struct omap_nand_info *info = mtd_to_omap(nand_to_mtd(this));
unsigned long timeo = jiffies;
int status, state = this->state;
@@ -1012,9 +1019,9 @@ static int omap_wait(struct mtd_info *mtd, struct nand_chip *chip)
*
* Returns true if ready and false if busy.
*/
-static int omap_dev_ready(struct mtd_info *mtd)
+static int omap_dev_ready(struct nand_chip *chip)
{
- struct omap_nand_info *info = mtd_to_omap(mtd);
+ struct omap_nand_info *info = mtd_to_omap(nand_to_mtd(chip));
return gpiod_get_value(info->ready_gpiod);
}
@@ -1030,13 +1037,13 @@ static int omap_dev_ready(struct mtd_info *mtd)
* eccsize0 = 0 (no additional protected byte in spare area)
* eccsize1 = 32 (skip 32 nibbles = 16 bytes per sector in spare area)
*/
-static void __maybe_unused omap_enable_hwecc_bch(struct mtd_info *mtd, int mode)
+static void __maybe_unused omap_enable_hwecc_bch(struct nand_chip *chip,
+ int mode)
{
unsigned int bch_type;
unsigned int dev_width, nsectors;
- struct omap_nand_info *info = mtd_to_omap(mtd);
+ struct omap_nand_info *info = mtd_to_omap(nand_to_mtd(chip));
enum omap_ecc ecc_opt = info->ecc_opt;
- struct nand_chip *chip = mtd_to_nand(mtd);
u32 val, wr_mode;
unsigned int ecc_size1, ecc_size0;
@@ -1256,7 +1263,7 @@ static int _omap_calculate_ecc_bch(struct mtd_info *mtd,
/**
* omap_calculate_ecc_bch_sw - ECC generator for sector for SW based correction
- * @mtd: MTD device structure
+ * @chip: NAND chip object
* @dat: The pointer to data on which ecc is computed
* @ecc_code: The ecc_code buffer
*
@@ -1264,10 +1271,10 @@ static int _omap_calculate_ecc_bch(struct mtd_info *mtd,
* when SW based correction is required as ECC is required for one sector
* at a time.
*/
-static int omap_calculate_ecc_bch_sw(struct mtd_info *mtd,
+static int omap_calculate_ecc_bch_sw(struct nand_chip *chip,
const u_char *dat, u_char *ecc_calc)
{
- return _omap_calculate_ecc_bch(mtd, dat, ecc_calc, 0);
+ return _omap_calculate_ecc_bch(nand_to_mtd(chip), dat, ecc_calc, 0);
}
/**
@@ -1339,7 +1346,7 @@ static int erased_sector_bitflips(u_char *data, u_char *oob,
/**
* omap_elm_correct_data - corrects page data area in case error reported
- * @mtd: MTD device structure
+ * @chip: NAND chip object
* @data: page data
* @read_ecc: ecc read from nand flash
* @calc_ecc: ecc read from HW ECC registers
@@ -1348,10 +1355,10 @@ static int erased_sector_bitflips(u_char *data, u_char *oob,
* In case of non-zero ecc vector, first filter out erased-pages, and
* then process data via ELM to detect bit-flips.
*/
-static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data,
- u_char *read_ecc, u_char *calc_ecc)
+static int omap_elm_correct_data(struct nand_chip *chip, u_char *data,
+ u_char *read_ecc, u_char *calc_ecc)
{
- struct omap_nand_info *info = mtd_to_omap(mtd);
+ struct omap_nand_info *info = mtd_to_omap(nand_to_mtd(chip));
struct nand_ecc_ctrl *ecc = &info->nand.ecc;
int eccsteps = info->nand.ecc.steps;
int i , j, stat = 0;
@@ -1512,7 +1519,6 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data,
/**
* omap_write_page_bch - BCH ecc based write page function for entire page
- * @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: data buffer
* @oob_required: must write chip->oob_poi to OOB
@@ -1520,19 +1526,20 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data,
*
* Custom write page method evolved to support multi sector writing in one shot
*/
-static int omap_write_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
- const uint8_t *buf, int oob_required, int page)
+static int omap_write_page_bch(struct nand_chip *chip, const uint8_t *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
int ret;
uint8_t *ecc_calc = chip->ecc.calc_buf;
nand_prog_page_begin_op(chip, page, 0, NULL, 0);
/* Enable GPMC ecc engine */
- chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
+ chip->ecc.hwctl(chip, NAND_ECC_WRITE);
/* Write data */
- chip->write_buf(mtd, buf, mtd->writesize);
+ chip->legacy.write_buf(chip, buf, mtd->writesize);
/* Update ecc vector from GPMC result registers */
omap_calculate_ecc_bch_multi(mtd, buf, &ecc_calc[0]);
@@ -1543,14 +1550,13 @@ static int omap_write_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
return ret;
/* Write ecc vector to OOB area */
- chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+ chip->legacy.write_buf(chip, chip->oob_poi, mtd->oobsize);
return nand_prog_page_end_op(chip);
}
/**
* omap_write_subpage_bch - BCH hardware ECC based subpage write
- * @mtd: mtd info structure
* @chip: nand chip info structure
* @offset: column address of subpage within the page
* @data_len: data length
@@ -1560,11 +1566,11 @@ static int omap_write_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
*
* OMAP optimized subpage write method.
*/
-static int omap_write_subpage_bch(struct mtd_info *mtd,
- struct nand_chip *chip, u32 offset,
+static int omap_write_subpage_bch(struct nand_chip *chip, u32 offset,
u32 data_len, const u8 *buf,
int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
u8 *ecc_calc = chip->ecc.calc_buf;
int ecc_size = chip->ecc.size;
int ecc_bytes = chip->ecc.bytes;
@@ -1582,10 +1588,10 @@ static int omap_write_subpage_bch(struct mtd_info *mtd,
nand_prog_page_begin_op(chip, page, 0, NULL, 0);
/* Enable GPMC ECC engine */
- chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
+ chip->ecc.hwctl(chip, NAND_ECC_WRITE);
/* Write data */
- chip->write_buf(mtd, buf, mtd->writesize);
+ chip->legacy.write_buf(chip, buf, mtd->writesize);
for (step = 0; step < ecc_steps; step++) {
/* mask ECC of un-touched subpages by padding 0xFF */
@@ -1610,14 +1616,13 @@ static int omap_write_subpage_bch(struct mtd_info *mtd,
return ret;
/* write OOB buffer to NAND device */
- chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+ chip->legacy.write_buf(chip, chip->oob_poi, mtd->oobsize);
return nand_prog_page_end_op(chip);
}
/**
* omap_read_page_bch - BCH ecc based page read function for entire page
- * @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: buffer to store read data
* @oob_required: caller requires OOB data read to chip->oob_poi
@@ -1630,9 +1635,10 @@ static int omap_write_subpage_bch(struct mtd_info *mtd,
* ecc engine enabled. ecc vector updated after read of OOB data.
* For non error pages ecc vector reported as zero.
*/
-static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
- uint8_t *buf, int oob_required, int page)
+static int omap_read_page_bch(struct nand_chip *chip, uint8_t *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
uint8_t *ecc_calc = chip->ecc.calc_buf;
uint8_t *ecc_code = chip->ecc.code_buf;
int stat, ret;
@@ -1641,10 +1647,10 @@ static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
nand_read_page_op(chip, page, 0, NULL, 0);
/* Enable GPMC ecc engine */
- chip->ecc.hwctl(mtd, NAND_ECC_READ);
+ chip->ecc.hwctl(chip, NAND_ECC_READ);
/* Read data */
- chip->read_buf(mtd, buf, mtd->writesize);
+ chip->legacy.read_buf(chip, buf, mtd->writesize);
/* Read oob bytes */
nand_change_read_column_op(chip,
@@ -1660,7 +1666,7 @@ static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
if (ret)
return ret;
- stat = chip->ecc.correct(mtd, buf, ecc_code, ecc_calc);
+ stat = chip->ecc.correct(chip, buf, ecc_code, ecc_calc);
if (stat < 0) {
mtd->ecc_stats.failed++;
@@ -1927,8 +1933,8 @@ static int omap_nand_attach_chip(struct nand_chip *chip)
/* Re-populate low-level callbacks based on xfer modes */
switch (info->xfer_type) {
case NAND_OMAP_PREFETCH_POLLED:
- chip->read_buf = omap_read_buf_pref;
- chip->write_buf = omap_write_buf_pref;
+ chip->legacy.read_buf = omap_read_buf_pref;
+ chip->legacy.write_buf = omap_write_buf_pref;
break;
case NAND_OMAP_POLLED:
@@ -1960,8 +1966,8 @@ static int omap_nand_attach_chip(struct nand_chip *chip)
err);
return err;
}
- chip->read_buf = omap_read_buf_dma_pref;
- chip->write_buf = omap_write_buf_dma_pref;
+ chip->legacy.read_buf = omap_read_buf_dma_pref;
+ chip->legacy.write_buf = omap_write_buf_dma_pref;
}
break;
@@ -1996,8 +2002,8 @@ static int omap_nand_attach_chip(struct nand_chip *chip)
return err;
}
- chip->read_buf = omap_read_buf_irq_pref;
- chip->write_buf = omap_write_buf_irq_pref;
+ chip->legacy.read_buf = omap_read_buf_irq_pref;
+ chip->legacy.write_buf = omap_write_buf_irq_pref;
break;
@@ -2215,16 +2221,16 @@ static int omap_nand_probe(struct platform_device *pdev)
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- nand_chip->IO_ADDR_R = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(nand_chip->IO_ADDR_R))
- return PTR_ERR(nand_chip->IO_ADDR_R);
+ nand_chip->legacy.IO_ADDR_R = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(nand_chip->legacy.IO_ADDR_R))
+ return PTR_ERR(nand_chip->legacy.IO_ADDR_R);
info->phys_base = res->start;
nand_chip->controller = &omap_gpmc_controller;
- nand_chip->IO_ADDR_W = nand_chip->IO_ADDR_R;
- nand_chip->cmd_ctrl = omap_hwcontrol;
+ nand_chip->legacy.IO_ADDR_W = nand_chip->legacy.IO_ADDR_R;
+ nand_chip->legacy.cmd_ctrl = omap_hwcontrol;
info->ready_gpiod = devm_gpiod_get_optional(&pdev->dev, "rb",
GPIOD_IN);
@@ -2241,11 +2247,11 @@ static int omap_nand_probe(struct platform_device *pdev)
* device and read status register until you get a failure or success
*/
if (info->ready_gpiod) {
- nand_chip->dev_ready = omap_dev_ready;
- nand_chip->chip_delay = 0;
+ nand_chip->legacy.dev_ready = omap_dev_ready;
+ nand_chip->legacy.chip_delay = 0;
} else {
- nand_chip->waitfunc = omap_wait;
- nand_chip->chip_delay = 50;
+ nand_chip->legacy.waitfunc = omap_wait;
+ nand_chip->legacy.chip_delay = 50;
}
if (info->flash_bbt)
@@ -2254,7 +2260,7 @@ static int omap_nand_probe(struct platform_device *pdev)
/* scan NAND device connected to chip controller */
nand_chip->options |= info->devsize & NAND_BUSWIDTH_16;
- err = nand_scan(mtd, 1);
+ err = nand_scan(nand_chip, 1);
if (err)
goto return_error;
@@ -2290,7 +2296,7 @@ static int omap_nand_remove(struct platform_device *pdev)
}
if (info->dma)
dma_release_channel(info->dma);
- nand_release(mtd);
+ nand_release(nand_chip);
return 0;
}
diff --git a/drivers/mtd/nand/raw/orion_nand.c b/drivers/mtd/nand/raw/orion_nand.c
index 52d435285a3f..d27b39a7223c 100644
--- a/drivers/mtd/nand/raw/orion_nand.c
+++ b/drivers/mtd/nand/raw/orion_nand.c
@@ -26,9 +26,9 @@ struct orion_nand_info {
struct clk *clk;
};
-static void orion_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+static void orion_nand_cmd_ctrl(struct nand_chip *nc, int cmd,
+ unsigned int ctrl)
{
- struct nand_chip *nc = mtd_to_nand(mtd);
struct orion_nand_data *board = nand_get_controller_data(nc);
u32 offs;
@@ -45,13 +45,12 @@ static void orion_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl
if (nc->options & NAND_BUSWIDTH_16)
offs <<= 1;
- writeb(cmd, nc->IO_ADDR_W + offs);
+ writeb(cmd, nc->legacy.IO_ADDR_W + offs);
}
-static void orion_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+static void orion_nand_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
- void __iomem *io_base = chip->IO_ADDR_R;
+ void __iomem *io_base = chip->legacy.IO_ADDR_R;
#if defined(__LINUX_ARM_ARCH__) && __LINUX_ARM_ARCH__ >= 5
uint64_t *buf64;
#endif
@@ -137,14 +136,14 @@ static int __init orion_nand_probe(struct platform_device *pdev)
nand_set_controller_data(nc, board);
nand_set_flash_node(nc, pdev->dev.of_node);
- nc->IO_ADDR_R = nc->IO_ADDR_W = io_base;
- nc->cmd_ctrl = orion_nand_cmd_ctrl;
- nc->read_buf = orion_nand_read_buf;
+ nc->legacy.IO_ADDR_R = nc->legacy.IO_ADDR_W = io_base;
+ nc->legacy.cmd_ctrl = orion_nand_cmd_ctrl;
+ nc->legacy.read_buf = orion_nand_read_buf;
nc->ecc.mode = NAND_ECC_SOFT;
nc->ecc.algo = NAND_ECC_HAMMING;
if (board->chip_delay)
- nc->chip_delay = board->chip_delay;
+ nc->legacy.chip_delay = board->chip_delay;
WARN(board->width > 16,
"%d bit bus width out of range",
@@ -174,14 +173,14 @@ static int __init orion_nand_probe(struct platform_device *pdev)
return ret;
}
- ret = nand_scan(mtd, 1);
+ ret = nand_scan(nc, 1);
if (ret)
goto no_dev;
mtd->name = "orion_nand";
ret = mtd_device_register(mtd, board->parts, board->nr_parts);
if (ret) {
- nand_release(mtd);
+ nand_release(nc);
goto no_dev;
}
@@ -196,9 +195,8 @@ static int orion_nand_remove(struct platform_device *pdev)
{
struct orion_nand_info *info = platform_get_drvdata(pdev);
struct nand_chip *chip = &info->chip;
- struct mtd_info *mtd = nand_to_mtd(chip);
- nand_release(mtd);
+ nand_release(chip);
clk_disable_unprepare(info->clk);
diff --git a/drivers/mtd/nand/raw/oxnas_nand.c b/drivers/mtd/nand/raw/oxnas_nand.c
index 01b00bb69c1e..0e52dc29141c 100644
--- a/drivers/mtd/nand/raw/oxnas_nand.c
+++ b/drivers/mtd/nand/raw/oxnas_nand.c
@@ -38,35 +38,32 @@ struct oxnas_nand_ctrl {
struct nand_chip *chips[OXNAS_NAND_MAX_CHIPS];
};
-static uint8_t oxnas_nand_read_byte(struct mtd_info *mtd)
+static uint8_t oxnas_nand_read_byte(struct nand_chip *chip)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip);
return readb(oxnas->io_base);
}
-static void oxnas_nand_read_buf(struct mtd_info *mtd, u8 *buf, int len)
+static void oxnas_nand_read_buf(struct nand_chip *chip, u8 *buf, int len)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip);
ioread8_rep(oxnas->io_base, buf, len);
}
-static void oxnas_nand_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
+static void oxnas_nand_write_buf(struct nand_chip *chip, const u8 *buf,
+ int len)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip);
iowrite8_rep(oxnas->io_base, buf, len);
}
/* Single CS command control */
-static void oxnas_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
+static void oxnas_nand_cmd_ctrl(struct nand_chip *chip, int cmd,
unsigned int ctrl)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip);
if (ctrl & NAND_CLE)
@@ -135,20 +132,20 @@ static int oxnas_nand_probe(struct platform_device *pdev)
mtd->dev.parent = &pdev->dev;
mtd->priv = chip;
- chip->cmd_ctrl = oxnas_nand_cmd_ctrl;
- chip->read_buf = oxnas_nand_read_buf;
- chip->read_byte = oxnas_nand_read_byte;
- chip->write_buf = oxnas_nand_write_buf;
- chip->chip_delay = 30;
+ chip->legacy.cmd_ctrl = oxnas_nand_cmd_ctrl;
+ chip->legacy.read_buf = oxnas_nand_read_buf;
+ chip->legacy.read_byte = oxnas_nand_read_byte;
+ chip->legacy.write_buf = oxnas_nand_write_buf;
+ chip->legacy.chip_delay = 30;
/* Scan to find existence of the device */
- err = nand_scan(mtd, 1);
+ err = nand_scan(chip, 1);
if (err)
goto err_clk_unprepare;
err = mtd_device_register(mtd, NULL, 0);
if (err) {
- nand_release(mtd);
+ nand_release(chip);
goto err_clk_unprepare;
}
@@ -176,7 +173,7 @@ static int oxnas_nand_remove(struct platform_device *pdev)
struct oxnas_nand_ctrl *oxnas = platform_get_drvdata(pdev);
if (oxnas->chips[0])
- nand_release(nand_to_mtd(oxnas->chips[0]));
+ nand_release(oxnas->chips[0]);
clk_disable_unprepare(oxnas->clk);
diff --git a/drivers/mtd/nand/raw/pasemi_nand.c b/drivers/mtd/nand/raw/pasemi_nand.c
index a47a7e4bd25a..643cd22af009 100644
--- a/drivers/mtd/nand/raw/pasemi_nand.c
+++ b/drivers/mtd/nand/raw/pasemi_nand.c
@@ -43,49 +43,44 @@ static unsigned int lpcctl;
static struct mtd_info *pasemi_nand_mtd;
static const char driver_name[] = "pasemi-nand";
-static void pasemi_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+static void pasemi_read_buf(struct nand_chip *chip, u_char *buf, int len)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
-
while (len > 0x800) {
- memcpy_fromio(buf, chip->IO_ADDR_R, 0x800);
+ memcpy_fromio(buf, chip->legacy.IO_ADDR_R, 0x800);
buf += 0x800;
len -= 0x800;
}
- memcpy_fromio(buf, chip->IO_ADDR_R, len);
+ memcpy_fromio(buf, chip->legacy.IO_ADDR_R, len);
}
-static void pasemi_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
+static void pasemi_write_buf(struct nand_chip *chip, const u_char *buf,
+ int len)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
-
while (len > 0x800) {
- memcpy_toio(chip->IO_ADDR_R, buf, 0x800);
+ memcpy_toio(chip->legacy.IO_ADDR_R, buf, 0x800);
buf += 0x800;
len -= 0x800;
}
- memcpy_toio(chip->IO_ADDR_R, buf, len);
+ memcpy_toio(chip->legacy.IO_ADDR_R, buf, len);
}
-static void pasemi_hwcontrol(struct mtd_info *mtd, int cmd,
+static void pasemi_hwcontrol(struct nand_chip *chip, int cmd,
unsigned int ctrl)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
-
if (cmd == NAND_CMD_NONE)
return;
if (ctrl & NAND_CLE)
- out_8(chip->IO_ADDR_W + (1 << CLE_PIN_CTL), cmd);
+ out_8(chip->legacy.IO_ADDR_W + (1 << CLE_PIN_CTL), cmd);
else
- out_8(chip->IO_ADDR_W + (1 << ALE_PIN_CTL), cmd);
+ out_8(chip->legacy.IO_ADDR_W + (1 << ALE_PIN_CTL), cmd);
/* Push out posted writes */
eieio();
inl(lpcctl);
}
-int pasemi_device_ready(struct mtd_info *mtd)
+int pasemi_device_ready(struct nand_chip *chip)
{
return !!(inl(lpcctl) & LBICTRL_LPCCTL_NR);
}
@@ -122,10 +117,10 @@ static int pasemi_nand_probe(struct platform_device *ofdev)
/* Link the private data with the MTD structure */
pasemi_nand_mtd->dev.parent = dev;
- chip->IO_ADDR_R = of_iomap(np, 0);
- chip->IO_ADDR_W = chip->IO_ADDR_R;
+ chip->legacy.IO_ADDR_R = of_iomap(np, 0);
+ chip->legacy.IO_ADDR_W = chip->legacy.IO_ADDR_R;
- if (!chip->IO_ADDR_R) {
+ if (!chip->legacy.IO_ADDR_R) {
err = -EIO;
goto out_mtd;
}
@@ -144,11 +139,11 @@ static int pasemi_nand_probe(struct platform_device *ofdev)
goto out_ior;
}
- chip->cmd_ctrl = pasemi_hwcontrol;
- chip->dev_ready = pasemi_device_ready;
- chip->read_buf = pasemi_read_buf;
- chip->write_buf = pasemi_write_buf;
- chip->chip_delay = 0;
+ chip->legacy.cmd_ctrl = pasemi_hwcontrol;
+ chip->legacy.dev_ready = pasemi_device_ready;
+ chip->legacy.read_buf = pasemi_read_buf;
+ chip->legacy.write_buf = pasemi_write_buf;
+ chip->legacy.chip_delay = 0;
chip->ecc.mode = NAND_ECC_SOFT;
chip->ecc.algo = NAND_ECC_HAMMING;
@@ -156,7 +151,7 @@ static int pasemi_nand_probe(struct platform_device *ofdev)
chip->bbt_options = NAND_BBT_USE_FLASH;
/* Scan to find existence of the device */
- err = nand_scan(pasemi_nand_mtd, 1);
+ err = nand_scan(chip, 1);
if (err)
goto out_lpc;
@@ -174,7 +169,7 @@ static int pasemi_nand_probe(struct platform_device *ofdev)
out_lpc:
release_region(lpcctl, 4);
out_ior:
- iounmap(chip->IO_ADDR_R);
+ iounmap(chip->legacy.IO_ADDR_R);
out_mtd:
kfree(chip);
out:
@@ -191,11 +186,11 @@ static int pasemi_nand_remove(struct platform_device *ofdev)
chip = mtd_to_nand(pasemi_nand_mtd);
/* Release resources, unregister device */
- nand_release(pasemi_nand_mtd);
+ nand_release(chip);
release_region(lpcctl, 4);
- iounmap(chip->IO_ADDR_R);
+ iounmap(chip->legacy.IO_ADDR_R);
/* Free the MTD device structure */
kfree(chip);
diff --git a/drivers/mtd/nand/raw/plat_nand.c b/drivers/mtd/nand/raw/plat_nand.c
index 222626df4b96..86c536ddaf24 100644
--- a/drivers/mtd/nand/raw/plat_nand.c
+++ b/drivers/mtd/nand/raw/plat_nand.c
@@ -15,8 +15,7 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/partitions.h>
+#include <linux/mtd/platnand.h>
struct plat_nand_data {
struct nand_chip chip;
@@ -60,14 +59,14 @@ static int plat_nand_probe(struct platform_device *pdev)
mtd = nand_to_mtd(&data->chip);
mtd->dev.parent = &pdev->dev;
- data->chip.IO_ADDR_R = data->io_base;
- data->chip.IO_ADDR_W = data->io_base;
- data->chip.cmd_ctrl = pdata->ctrl.cmd_ctrl;
- data->chip.dev_ready = pdata->ctrl.dev_ready;
+ data->chip.legacy.IO_ADDR_R = data->io_base;
+ data->chip.legacy.IO_ADDR_W = data->io_base;
+ data->chip.legacy.cmd_ctrl = pdata->ctrl.cmd_ctrl;
+ data->chip.legacy.dev_ready = pdata->ctrl.dev_ready;
data->chip.select_chip = pdata->ctrl.select_chip;
- data->chip.write_buf = pdata->ctrl.write_buf;
- data->chip.read_buf = pdata->ctrl.read_buf;
- data->chip.chip_delay = pdata->chip.chip_delay;
+ data->chip.legacy.write_buf = pdata->ctrl.write_buf;
+ data->chip.legacy.read_buf = pdata->ctrl.read_buf;
+ data->chip.legacy.chip_delay = pdata->chip.chip_delay;
data->chip.options |= pdata->chip.options;
data->chip.bbt_options |= pdata->chip.bbt_options;
@@ -84,7 +83,7 @@ static int plat_nand_probe(struct platform_device *pdev)
}
/* Scan to find existence of the device */
- err = nand_scan(mtd, pdata->chip.nr_chips);
+ err = nand_scan(&data->chip, pdata->chip.nr_chips);
if (err)
goto out;
@@ -97,7 +96,7 @@ static int plat_nand_probe(struct platform_device *pdev)
if (!err)
return err;
- nand_release(mtd);
+ nand_release(&data->chip);
out:
if (pdata->ctrl.remove)
pdata->ctrl.remove(pdev);
@@ -112,7 +111,7 @@ static int plat_nand_remove(struct platform_device *pdev)
struct plat_nand_data *data = platform_get_drvdata(pdev);
struct platform_nand_data *pdata = dev_get_platdata(&pdev->dev);
- nand_release(nand_to_mtd(&data->chip));
+ nand_release(&data->chip);
if (pdata->ctrl.remove)
pdata->ctrl.remove(pdev);
diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c
index d1d470bb32e4..ef75dfa62a4f 100644
--- a/drivers/mtd/nand/raw/qcom_nandc.c
+++ b/drivers/mtd/nand/raw/qcom_nandc.c
@@ -23,7 +23,6 @@
#include <linux/of_device.h>
#include <linux/delay.h>
#include <linux/dma/qcom_bam_dma.h>
-#include <linux/dma-direct.h> /* XXX: drivers shall never use this directly! */
/* NANDc reg offsets */
#define NAND_FLASH_CMD 0x00
@@ -350,7 +349,8 @@ struct nandc_regs {
* @data_buffer: our local DMA buffer for page read/writes,
* used when we can't use the buffer provided
* by upper layers directly
- * @buf_size/count/start: markers for chip->read_buf/write_buf functions
+ * @buf_size/count/start: markers for chip->legacy.read_buf/write_buf
+ * functions
* @reg_read_buf: local buffer for reading back registers via DMA
* @reg_read_dma: contains dma address for register read buffer
* @reg_read_pos: marker for data read in reg_read_buf
@@ -1155,8 +1155,8 @@ static void config_nand_cw_write(struct qcom_nand_controller *nandc)
}
/*
- * the following functions are used within chip->cmdfunc() to perform different
- * NAND_CMD_* commands
+ * the following functions are used within chip->legacy.cmdfunc() to
+ * perform different NAND_CMD_* commands
*/
/* sets up descriptors for NAND_CMD_PARAM */
@@ -1436,15 +1436,14 @@ static void post_command(struct qcom_nand_host *host, int command)
}
/*
- * Implements chip->cmdfunc. It's only used for a limited set of commands.
- * The rest of the commands wouldn't be called by upper layers. For example,
- * NAND_CMD_READOOB would never be called because we have our own versions
- * of read_oob ops for nand_ecc_ctrl.
+ * Implements chip->legacy.cmdfunc. It's only used for a limited set of
+ * commands. The rest of the commands wouldn't be called by upper layers.
+ * For example, NAND_CMD_READOOB would never be called because we have our own
+ * versions of read_oob ops for nand_ecc_ctrl.
*/
-static void qcom_nandc_command(struct mtd_info *mtd, unsigned int command,
+static void qcom_nandc_command(struct nand_chip *chip, unsigned int command,
int column, int page_addr)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct qcom_nand_host *host = to_qcom_nand_host(chip);
struct nand_ecc_ctrl *ecc = &chip->ecc;
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
@@ -1949,8 +1948,8 @@ static int copy_last_cw(struct qcom_nand_host *host, int page)
}
/* implements ecc->read_page() */
-static int qcom_nandc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
- uint8_t *buf, int oob_required, int page)
+static int qcom_nandc_read_page(struct nand_chip *chip, uint8_t *buf,
+ int oob_required, int page)
{
struct qcom_nand_host *host = to_qcom_nand_host(chip);
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
@@ -1966,10 +1965,10 @@ static int qcom_nandc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
}
/* implements ecc->read_page_raw() */
-static int qcom_nandc_read_page_raw(struct mtd_info *mtd,
- struct nand_chip *chip, uint8_t *buf,
+static int qcom_nandc_read_page_raw(struct nand_chip *chip, uint8_t *buf,
int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct qcom_nand_host *host = to_qcom_nand_host(chip);
struct nand_ecc_ctrl *ecc = &chip->ecc;
int cw, ret;
@@ -1989,8 +1988,7 @@ static int qcom_nandc_read_page_raw(struct mtd_info *mtd,
}
/* implements ecc->read_oob() */
-static int qcom_nandc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
- int page)
+static int qcom_nandc_read_oob(struct nand_chip *chip, int page)
{
struct qcom_nand_host *host = to_qcom_nand_host(chip);
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
@@ -2007,8 +2005,8 @@ static int qcom_nandc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
}
/* implements ecc->write_page() */
-static int qcom_nandc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
- const uint8_t *buf, int oob_required, int page)
+static int qcom_nandc_write_page(struct nand_chip *chip, const uint8_t *buf,
+ int oob_required, int page)
{
struct qcom_nand_host *host = to_qcom_nand_host(chip);
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
@@ -2077,10 +2075,11 @@ static int qcom_nandc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
}
/* implements ecc->write_page_raw() */
-static int qcom_nandc_write_page_raw(struct mtd_info *mtd,
- struct nand_chip *chip, const uint8_t *buf,
- int oob_required, int page)
+static int qcom_nandc_write_page_raw(struct nand_chip *chip,
+ const uint8_t *buf, int oob_required,
+ int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct qcom_nand_host *host = to_qcom_nand_host(chip);
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
struct nand_ecc_ctrl *ecc = &chip->ecc;
@@ -2155,9 +2154,9 @@ static int qcom_nandc_write_page_raw(struct mtd_info *mtd,
* since ECC is calculated for the combined codeword. So update the OOB from
* chip->oob_poi, and pad the data area with OxFF before writing.
*/
-static int qcom_nandc_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
- int page)
+static int qcom_nandc_write_oob(struct nand_chip *chip, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct qcom_nand_host *host = to_qcom_nand_host(chip);
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
struct nand_ecc_ctrl *ecc = &chip->ecc;
@@ -2197,9 +2196,9 @@ static int qcom_nandc_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
return nand_prog_page_end_op(chip);
}
-static int qcom_nandc_block_bad(struct mtd_info *mtd, loff_t ofs)
+static int qcom_nandc_block_bad(struct nand_chip *chip, loff_t ofs)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct qcom_nand_host *host = to_qcom_nand_host(chip);
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
struct nand_ecc_ctrl *ecc = &chip->ecc;
@@ -2235,9 +2234,8 @@ err:
return bad;
}
-static int qcom_nandc_block_markbad(struct mtd_info *mtd, loff_t ofs)
+static int qcom_nandc_block_markbad(struct nand_chip *chip, loff_t ofs)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct qcom_nand_host *host = to_qcom_nand_host(chip);
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
struct nand_ecc_ctrl *ecc = &chip->ecc;
@@ -2278,14 +2276,13 @@ static int qcom_nandc_block_markbad(struct mtd_info *mtd, loff_t ofs)
}
/*
- * the three functions below implement chip->read_byte(), chip->read_buf()
- * and chip->write_buf() respectively. these aren't used for
- * reading/writing page data, they are used for smaller data like reading
- * id, status etc
+ * the three functions below implement chip->legacy.read_byte(),
+ * chip->legacy.read_buf() and chip->legacy.write_buf() respectively. these
+ * aren't used for reading/writing page data, they are used for smaller data
+ * like reading id, status etc
*/
-static uint8_t qcom_nandc_read_byte(struct mtd_info *mtd)
+static uint8_t qcom_nandc_read_byte(struct nand_chip *chip)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct qcom_nand_host *host = to_qcom_nand_host(chip);
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
u8 *buf = nandc->data_buffer;
@@ -2305,9 +2302,8 @@ static uint8_t qcom_nandc_read_byte(struct mtd_info *mtd)
return ret;
}
-static void qcom_nandc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+static void qcom_nandc_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
int real_len = min_t(size_t, len, nandc->buf_count - nandc->buf_start);
@@ -2315,10 +2311,9 @@ static void qcom_nandc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
nandc->buf_start += real_len;
}
-static void qcom_nandc_write_buf(struct mtd_info *mtd, const uint8_t *buf,
+static void qcom_nandc_write_buf(struct nand_chip *chip, const uint8_t *buf,
int len)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
int real_len = min_t(size_t, len, nandc->buf_count - nandc->buf_start);
@@ -2328,9 +2323,8 @@ static void qcom_nandc_write_buf(struct mtd_info *mtd, const uint8_t *buf,
}
/* we support only one external chip for now */
-static void qcom_nandc_select_chip(struct mtd_info *mtd, int chipnr)
+static void qcom_nandc_select_chip(struct nand_chip *chip, int chipnr)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
if (chipnr <= 0)
@@ -2809,13 +2803,13 @@ static int qcom_nand_host_init_and_register(struct qcom_nand_controller *nandc,
mtd->owner = THIS_MODULE;
mtd->dev.parent = dev;
- chip->cmdfunc = qcom_nandc_command;
+ chip->legacy.cmdfunc = qcom_nandc_command;
chip->select_chip = qcom_nandc_select_chip;
- chip->read_byte = qcom_nandc_read_byte;
- chip->read_buf = qcom_nandc_read_buf;
- chip->write_buf = qcom_nandc_write_buf;
- chip->set_features = nand_get_set_features_notsupp;
- chip->get_features = nand_get_set_features_notsupp;
+ chip->legacy.read_byte = qcom_nandc_read_byte;
+ chip->legacy.read_buf = qcom_nandc_read_buf;
+ chip->legacy.write_buf = qcom_nandc_write_buf;
+ chip->legacy.set_features = nand_get_set_features_notsupp;
+ chip->legacy.get_features = nand_get_set_features_notsupp;
/*
* the bad block marker is readable only when we read the last codeword
@@ -2825,8 +2819,8 @@ static int qcom_nand_host_init_and_register(struct qcom_nand_controller *nandc,
* and block_markbad helpers until we permanently switch to using
* MTD_OPS_RAW for all drivers (with the help of badblockbits)
*/
- chip->block_bad = qcom_nandc_block_bad;
- chip->block_markbad = qcom_nandc_block_markbad;
+ chip->legacy.block_bad = qcom_nandc_block_bad;
+ chip->legacy.block_markbad = qcom_nandc_block_markbad;
chip->controller = &nandc->controller;
chip->options |= NAND_NO_SUBPAGE_WRITE | NAND_USE_BOUNCE_BUFFER |
@@ -2835,7 +2829,7 @@ static int qcom_nand_host_init_and_register(struct qcom_nand_controller *nandc,
/* set up initial status value */
host->status = NAND_STATUS_READY | NAND_STATUS_WP;
- ret = nand_scan(mtd, 1);
+ ret = nand_scan(chip, 1);
if (ret)
return ret;
@@ -3000,7 +2994,7 @@ static int qcom_nandc_remove(struct platform_device *pdev)
struct qcom_nand_host *host;
list_for_each_entry(host, &nandc->host_list, node)
- nand_release(nand_to_mtd(&host->chip));
+ nand_release(&host->chip);
qcom_nandc_unalloc(nandc);
diff --git a/drivers/mtd/nand/raw/r852.c b/drivers/mtd/nand/raw/r852.c
index dcdeb0660e5e..39be65b35ac2 100644
--- a/drivers/mtd/nand/raw/r852.c
+++ b/drivers/mtd/nand/raw/r852.c
@@ -232,9 +232,9 @@ static void r852_do_dma(struct r852_device *dev, uint8_t *buf, int do_read)
/*
* Program data lines of the nand chip to send data to it
*/
-static void r852_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+static void r852_write_buf(struct nand_chip *chip, const uint8_t *buf, int len)
{
- struct r852_device *dev = r852_get_dev(mtd);
+ struct r852_device *dev = r852_get_dev(nand_to_mtd(chip));
uint32_t reg;
/* Don't allow any access to hardware if we suspect card removal */
@@ -266,9 +266,9 @@ static void r852_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
/*
* Read data lines of the nand chip to retrieve data
*/
-static void r852_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+static void r852_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
{
- struct r852_device *dev = r852_get_dev(mtd);
+ struct r852_device *dev = r852_get_dev(nand_to_mtd(chip));
uint32_t reg;
if (dev->card_unstable) {
@@ -303,9 +303,9 @@ static void r852_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
/*
* Read one byte from nand chip
*/
-static uint8_t r852_read_byte(struct mtd_info *mtd)
+static uint8_t r852_read_byte(struct nand_chip *chip)
{
- struct r852_device *dev = r852_get_dev(mtd);
+ struct r852_device *dev = r852_get_dev(nand_to_mtd(chip));
/* Same problem as in r852_read_buf.... */
if (dev->card_unstable)
@@ -317,9 +317,9 @@ static uint8_t r852_read_byte(struct mtd_info *mtd)
/*
* Control several chip lines & send commands
*/
-static void r852_cmdctl(struct mtd_info *mtd, int dat, unsigned int ctrl)
+static void r852_cmdctl(struct nand_chip *chip, int dat, unsigned int ctrl)
{
- struct r852_device *dev = r852_get_dev(mtd);
+ struct r852_device *dev = r852_get_dev(nand_to_mtd(chip));
if (dev->card_unstable)
return;
@@ -362,7 +362,7 @@ static void r852_cmdctl(struct mtd_info *mtd, int dat, unsigned int ctrl)
* Wait till card is ready.
* based on nand_wait, but returns errors on DMA error
*/
-static int r852_wait(struct mtd_info *mtd, struct nand_chip *chip)
+static int r852_wait(struct nand_chip *chip)
{
struct r852_device *dev = nand_get_controller_data(chip);
@@ -373,7 +373,7 @@ static int r852_wait(struct mtd_info *mtd, struct nand_chip *chip)
msecs_to_jiffies(400) : msecs_to_jiffies(20));
while (time_before(jiffies, timeout))
- if (chip->dev_ready(mtd))
+ if (chip->legacy.dev_ready(chip))
break;
nand_status_op(chip, &status);
@@ -390,9 +390,9 @@ static int r852_wait(struct mtd_info *mtd, struct nand_chip *chip)
* Check if card is ready
*/
-static int r852_ready(struct mtd_info *mtd)
+static int r852_ready(struct nand_chip *chip)
{
- struct r852_device *dev = r852_get_dev(mtd);
+ struct r852_device *dev = r852_get_dev(nand_to_mtd(chip));
return !(r852_read_reg(dev, R852_CARD_STA) & R852_CARD_STA_BUSY);
}
@@ -401,9 +401,9 @@ static int r852_ready(struct mtd_info *mtd)
* Set ECC engine mode
*/
-static void r852_ecc_hwctl(struct mtd_info *mtd, int mode)
+static void r852_ecc_hwctl(struct nand_chip *chip, int mode)
{
- struct r852_device *dev = r852_get_dev(mtd);
+ struct r852_device *dev = r852_get_dev(nand_to_mtd(chip));
if (dev->card_unstable)
return;
@@ -433,10 +433,10 @@ static void r852_ecc_hwctl(struct mtd_info *mtd, int mode)
* Calculate ECC, only used for writes
*/
-static int r852_ecc_calculate(struct mtd_info *mtd, const uint8_t *dat,
- uint8_t *ecc_code)
+static int r852_ecc_calculate(struct nand_chip *chip, const uint8_t *dat,
+ uint8_t *ecc_code)
{
- struct r852_device *dev = r852_get_dev(mtd);
+ struct r852_device *dev = r852_get_dev(nand_to_mtd(chip));
struct sm_oob *oob = (struct sm_oob *)ecc_code;
uint32_t ecc1, ecc2;
@@ -465,14 +465,14 @@ static int r852_ecc_calculate(struct mtd_info *mtd, const uint8_t *dat,
* Correct the data using ECC, hw did almost everything for us
*/
-static int r852_ecc_correct(struct mtd_info *mtd, uint8_t *dat,
- uint8_t *read_ecc, uint8_t *calc_ecc)
+static int r852_ecc_correct(struct nand_chip *chip, uint8_t *dat,
+ uint8_t *read_ecc, uint8_t *calc_ecc)
{
uint32_t ecc_reg;
uint8_t ecc_status, err_byte;
int i, error = 0;
- struct r852_device *dev = r852_get_dev(mtd);
+ struct r852_device *dev = r852_get_dev(nand_to_mtd(chip));
if (dev->card_unstable)
return 0;
@@ -521,9 +521,10 @@ exit:
* This is copy of nand_read_oob_std
* nand_read_oob_syndrome assumes we can send column address - we can't
*/
-static int r852_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
- int page)
+static int r852_read_oob(struct nand_chip *chip, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
return nand_read_oob_op(chip, page, 0, chip->oob_poi, mtd->oobsize);
}
@@ -636,7 +637,7 @@ static int r852_register_nand_device(struct r852_device *dev)
{
struct mtd_info *mtd = nand_to_mtd(dev->chip);
- WARN_ON(dev->card_registred);
+ WARN_ON(dev->card_registered);
mtd->dev.parent = &dev->pci_dev->dev;
@@ -653,10 +654,10 @@ static int r852_register_nand_device(struct r852_device *dev)
goto error3;
}
- dev->card_registred = 1;
+ dev->card_registered = 1;
return 0;
error3:
- nand_release(mtd);
+ nand_release(dev->chip);
error1:
/* Force card redetect */
dev->card_detected = 0;
@@ -671,13 +672,13 @@ static void r852_unregister_nand_device(struct r852_device *dev)
{
struct mtd_info *mtd = nand_to_mtd(dev->chip);
- if (!dev->card_registred)
+ if (!dev->card_registered)
return;
device_remove_file(&mtd->dev, &dev_attr_media_type);
- nand_release(mtd);
+ nand_release(dev->chip);
r852_engine_disable(dev);
- dev->card_registred = 0;
+ dev->card_registered = 0;
}
/* Card state updater */
@@ -691,7 +692,7 @@ static void r852_card_detect_work(struct work_struct *work)
dev->card_unstable = 0;
/* False alarm */
- if (dev->card_detected == dev->card_registred)
+ if (dev->card_detected == dev->card_registered)
goto exit;
/* Read media properties */
@@ -852,14 +853,14 @@ static int r852_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
goto error4;
/* commands */
- chip->cmd_ctrl = r852_cmdctl;
- chip->waitfunc = r852_wait;
- chip->dev_ready = r852_ready;
+ chip->legacy.cmd_ctrl = r852_cmdctl;
+ chip->legacy.waitfunc = r852_wait;
+ chip->legacy.dev_ready = r852_ready;
/* I/O */
- chip->read_byte = r852_read_byte;
- chip->read_buf = r852_read_buf;
- chip->write_buf = r852_write_buf;
+ chip->legacy.read_byte = r852_read_byte;
+ chip->legacy.read_buf = r852_read_buf;
+ chip->legacy.write_buf = r852_write_buf;
/* ecc */
chip->ecc.mode = NAND_ECC_HW_SYNDROME;
@@ -1025,7 +1026,6 @@ static int r852_suspend(struct device *device)
static int r852_resume(struct device *device)
{
struct r852_device *dev = pci_get_drvdata(to_pci_dev(device));
- struct mtd_info *mtd = nand_to_mtd(dev->chip);
r852_disable_irqs(dev);
r852_card_update_present(dev);
@@ -1033,7 +1033,7 @@ static int r852_resume(struct device *device)
/* If card status changed, just do the work */
- if (dev->card_detected != dev->card_registred) {
+ if (dev->card_detected != dev->card_registered) {
dbg("card was %s during low power state",
dev->card_detected ? "added" : "removed");
@@ -1043,11 +1043,11 @@ static int r852_resume(struct device *device)
}
/* Otherwise, initialize the card */
- if (dev->card_registred) {
+ if (dev->card_registered) {
r852_engine_enable(dev);
- dev->chip->select_chip(mtd, 0);
+ dev->chip->select_chip(dev->chip, 0);
nand_reset_op(dev->chip);
- dev->chip->select_chip(mtd, -1);
+ dev->chip->select_chip(dev->chip, -1);
}
/* Program card detection IRQ */
diff --git a/drivers/mtd/nand/raw/r852.h b/drivers/mtd/nand/raw/r852.h
index 1eed2fc2fa42..bc67f5bf67e8 100644
--- a/drivers/mtd/nand/raw/r852.h
+++ b/drivers/mtd/nand/raw/r852.h
@@ -129,7 +129,7 @@ struct r852_device {
/* card status area */
struct delayed_work card_detect_work;
struct workqueue_struct *card_workqueue;
- int card_registred; /* card registered with mtd */
+ int card_registered; /* card registered with mtd */
int card_detected; /* card detected in slot */
int card_unstable; /* whenever the card is inserted,
is not known yet */
diff --git a/drivers/mtd/nand/raw/s3c2410.c b/drivers/mtd/nand/raw/s3c2410.c
index c21e8892394a..d2e42e9d0e8c 100644
--- a/drivers/mtd/nand/raw/s3c2410.c
+++ b/drivers/mtd/nand/raw/s3c2410.c
@@ -404,7 +404,7 @@ static int s3c2410_nand_inithw(struct s3c2410_nand_info *info)
/**
* s3c2410_nand_select_chip - select the given nand chip
- * @mtd: The MTD instance for this chip.
+ * @this: NAND chip object.
* @chip: The chip number.
*
* This is called by the MTD layer to either select a given chip for the
@@ -415,11 +415,10 @@ static int s3c2410_nand_inithw(struct s3c2410_nand_info *info)
* platform specific selection code is called to route nFCE to the specific
* chip.
*/
-static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip)
+static void s3c2410_nand_select_chip(struct nand_chip *this, int chip)
{
struct s3c2410_nand_info *info;
struct s3c2410_nand_mtd *nmtd;
- struct nand_chip *this = mtd_to_nand(mtd);
unsigned long cur;
nmtd = nand_get_controller_data(this);
@@ -457,9 +456,10 @@ static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip)
* Issue command and address cycles to the chip
*/
-static void s3c2410_nand_hwcontrol(struct mtd_info *mtd, int cmd,
+static void s3c2410_nand_hwcontrol(struct nand_chip *chip, int cmd,
unsigned int ctrl)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
if (cmd == NAND_CMD_NONE)
@@ -473,9 +473,10 @@ static void s3c2410_nand_hwcontrol(struct mtd_info *mtd, int cmd,
/* command and control functions */
-static void s3c2440_nand_hwcontrol(struct mtd_info *mtd, int cmd,
+static void s3c2440_nand_hwcontrol(struct nand_chip *chip, int cmd,
unsigned int ctrl)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
if (cmd == NAND_CMD_NONE)
@@ -492,29 +493,33 @@ static void s3c2440_nand_hwcontrol(struct mtd_info *mtd, int cmd,
* returns 0 if the nand is busy, 1 if it is ready
*/
-static int s3c2410_nand_devready(struct mtd_info *mtd)
+static int s3c2410_nand_devready(struct nand_chip *chip)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
return readb(info->regs + S3C2410_NFSTAT) & S3C2410_NFSTAT_BUSY;
}
-static int s3c2440_nand_devready(struct mtd_info *mtd)
+static int s3c2440_nand_devready(struct nand_chip *chip)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
return readb(info->regs + S3C2440_NFSTAT) & S3C2440_NFSTAT_READY;
}
-static int s3c2412_nand_devready(struct mtd_info *mtd)
+static int s3c2412_nand_devready(struct nand_chip *chip)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
return readb(info->regs + S3C2412_NFSTAT) & S3C2412_NFSTAT_READY;
}
/* ECC handling functions */
-static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat,
+static int s3c2410_nand_correct_data(struct nand_chip *chip, u_char *dat,
u_char *read_ecc, u_char *calc_ecc)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
unsigned int diff0, diff1, diff2;
unsigned int bit, byte;
@@ -591,38 +596,42 @@ static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat,
* generator block to ECC the data as it passes through]
*/
-static void s3c2410_nand_enable_hwecc(struct mtd_info *mtd, int mode)
+static void s3c2410_nand_enable_hwecc(struct nand_chip *chip, int mode)
{
- struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+ struct s3c2410_nand_info *info;
unsigned long ctrl;
+ info = s3c2410_nand_mtd_toinfo(nand_to_mtd(chip));
ctrl = readl(info->regs + S3C2410_NFCONF);
ctrl |= S3C2410_NFCONF_INITECC;
writel(ctrl, info->regs + S3C2410_NFCONF);
}
-static void s3c2412_nand_enable_hwecc(struct mtd_info *mtd, int mode)
+static void s3c2412_nand_enable_hwecc(struct nand_chip *chip, int mode)
{
- struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+ struct s3c2410_nand_info *info;
unsigned long ctrl;
+ info = s3c2410_nand_mtd_toinfo(nand_to_mtd(chip));
ctrl = readl(info->regs + S3C2440_NFCONT);
writel(ctrl | S3C2412_NFCONT_INIT_MAIN_ECC,
info->regs + S3C2440_NFCONT);
}
-static void s3c2440_nand_enable_hwecc(struct mtd_info *mtd, int mode)
+static void s3c2440_nand_enable_hwecc(struct nand_chip *chip, int mode)
{
- struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+ struct s3c2410_nand_info *info;
unsigned long ctrl;
+ info = s3c2410_nand_mtd_toinfo(nand_to_mtd(chip));
ctrl = readl(info->regs + S3C2440_NFCONT);
writel(ctrl | S3C2440_NFCONT_INITECC, info->regs + S3C2440_NFCONT);
}
-static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
- u_char *ecc_code)
+static int s3c2410_nand_calculate_ecc(struct nand_chip *chip,
+ const u_char *dat, u_char *ecc_code)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
ecc_code[0] = readb(info->regs + S3C2410_NFECC + 0);
@@ -634,9 +643,10 @@ static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
return 0;
}
-static int s3c2412_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
- u_char *ecc_code)
+static int s3c2412_nand_calculate_ecc(struct nand_chip *chip,
+ const u_char *dat, u_char *ecc_code)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
unsigned long ecc = readl(info->regs + S3C2412_NFMECC0);
@@ -649,9 +659,10 @@ static int s3c2412_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
return 0;
}
-static int s3c2440_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
- u_char *ecc_code)
+static int s3c2440_nand_calculate_ecc(struct nand_chip *chip,
+ const u_char *dat, u_char *ecc_code)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
unsigned long ecc = readl(info->regs + S3C2440_NFMECC0);
@@ -668,14 +679,14 @@ static int s3c2440_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
* use read/write block to move the data buffers to/from the controller
*/
-static void s3c2410_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+static void s3c2410_nand_read_buf(struct nand_chip *this, u_char *buf, int len)
{
- struct nand_chip *this = mtd_to_nand(mtd);
- readsb(this->IO_ADDR_R, buf, len);
+ readsb(this->legacy.IO_ADDR_R, buf, len);
}
-static void s3c2440_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+static void s3c2440_nand_read_buf(struct nand_chip *this, u_char *buf, int len)
{
+ struct mtd_info *mtd = nand_to_mtd(this);
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
readsl(info->regs + S3C2440_NFDATA, buf, len >> 2);
@@ -689,16 +700,16 @@ static void s3c2440_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
}
}
-static void s3c2410_nand_write_buf(struct mtd_info *mtd, const u_char *buf,
+static void s3c2410_nand_write_buf(struct nand_chip *this, const u_char *buf,
int len)
{
- struct nand_chip *this = mtd_to_nand(mtd);
- writesb(this->IO_ADDR_W, buf, len);
+ writesb(this->legacy.IO_ADDR_W, buf, len);
}
-static void s3c2440_nand_write_buf(struct mtd_info *mtd, const u_char *buf,
+static void s3c2440_nand_write_buf(struct nand_chip *this, const u_char *buf,
int len)
{
+ struct mtd_info *mtd = nand_to_mtd(this);
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
writesl(info->regs + S3C2440_NFDATA, buf, len >> 2);
@@ -781,7 +792,7 @@ static int s3c24xx_nand_remove(struct platform_device *pdev)
for (mtdno = 0; mtdno < info->mtd_count; mtdno++, ptr++) {
pr_debug("releasing mtd %d (%p)\n", mtdno, ptr);
- nand_release(nand_to_mtd(&ptr->chip));
+ nand_release(&ptr->chip);
}
}
@@ -809,9 +820,10 @@ static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info,
return -ENODEV;
}
-static int s3c2410_nand_setup_data_interface(struct mtd_info *mtd, int csline,
+static int s3c2410_nand_setup_data_interface(struct nand_chip *chip, int csline,
const struct nand_data_interface *conf)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
struct s3c2410_platform_nand *pdata = info->platform;
const struct nand_sdr_timings *timings;
@@ -852,10 +864,10 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
nand_set_flash_node(chip, set->of_node);
- chip->write_buf = s3c2410_nand_write_buf;
- chip->read_buf = s3c2410_nand_read_buf;
+ chip->legacy.write_buf = s3c2410_nand_write_buf;
+ chip->legacy.read_buf = s3c2410_nand_read_buf;
chip->select_chip = s3c2410_nand_select_chip;
- chip->chip_delay = 50;
+ chip->legacy.chip_delay = 50;
nand_set_controller_data(chip, nmtd);
chip->options = set->options;
chip->controller = &info->controller;
@@ -869,29 +881,29 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
switch (info->cpu_type) {
case TYPE_S3C2410:
- chip->IO_ADDR_W = regs + S3C2410_NFDATA;
+ chip->legacy.IO_ADDR_W = regs + S3C2410_NFDATA;
info->sel_reg = regs + S3C2410_NFCONF;
info->sel_bit = S3C2410_NFCONF_nFCE;
- chip->cmd_ctrl = s3c2410_nand_hwcontrol;
- chip->dev_ready = s3c2410_nand_devready;
+ chip->legacy.cmd_ctrl = s3c2410_nand_hwcontrol;
+ chip->legacy.dev_ready = s3c2410_nand_devready;
break;
case TYPE_S3C2440:
- chip->IO_ADDR_W = regs + S3C2440_NFDATA;
+ chip->legacy.IO_ADDR_W = regs + S3C2440_NFDATA;
info->sel_reg = regs + S3C2440_NFCONT;
info->sel_bit = S3C2440_NFCONT_nFCE;
- chip->cmd_ctrl = s3c2440_nand_hwcontrol;
- chip->dev_ready = s3c2440_nand_devready;
- chip->read_buf = s3c2440_nand_read_buf;
- chip->write_buf = s3c2440_nand_write_buf;
+ chip->legacy.cmd_ctrl = s3c2440_nand_hwcontrol;
+ chip->legacy.dev_ready = s3c2440_nand_devready;
+ chip->legacy.read_buf = s3c2440_nand_read_buf;
+ chip->legacy.write_buf = s3c2440_nand_write_buf;
break;
case TYPE_S3C2412:
- chip->IO_ADDR_W = regs + S3C2440_NFDATA;
+ chip->legacy.IO_ADDR_W = regs + S3C2440_NFDATA;
info->sel_reg = regs + S3C2440_NFCONT;
info->sel_bit = S3C2412_NFCONT_nFCE0;
- chip->cmd_ctrl = s3c2440_nand_hwcontrol;
- chip->dev_ready = s3c2412_nand_devready;
+ chip->legacy.cmd_ctrl = s3c2440_nand_hwcontrol;
+ chip->legacy.dev_ready = s3c2412_nand_devready;
if (readl(regs + S3C2410_NFCONF) & S3C2412_NFCONF_NANDBOOT)
dev_info(info->device, "System booted from NAND\n");
@@ -899,7 +911,7 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
break;
}
- chip->IO_ADDR_R = chip->IO_ADDR_W;
+ chip->legacy.IO_ADDR_R = chip->legacy.IO_ADDR_W;
nmtd->info = info;
nmtd->set = set;
@@ -1170,7 +1182,7 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
mtd->dev.parent = &pdev->dev;
s3c2410_nand_init_chip(info, nmtd, sets);
- err = nand_scan(mtd, sets ? sets->nr_chips : 1);
+ err = nand_scan(&nmtd->chip, sets ? sets->nr_chips : 1);
if (err)
goto exit_error;
diff --git a/drivers/mtd/nand/raw/sh_flctl.c b/drivers/mtd/nand/raw/sh_flctl.c
index bb8866e05ff7..4d20d033de7b 100644
--- a/drivers/mtd/nand/raw/sh_flctl.c
+++ b/drivers/mtd/nand/raw/sh_flctl.c
@@ -480,7 +480,7 @@ static void read_fiforeg(struct sh_flctl *flctl, int rlen, int offset)
/* initiate DMA transfer */
if (flctl->chan_fifo0_rx && rlen >= 32 &&
- flctl_dma_fifo0_transfer(flctl, buf, rlen, DMA_DEV_TO_MEM) > 0)
+ flctl_dma_fifo0_transfer(flctl, buf, rlen, DMA_FROM_DEVICE) > 0)
goto convert; /* DMA success */
/* do polling transfer */
@@ -539,7 +539,7 @@ static void write_ec_fiforeg(struct sh_flctl *flctl, int rlen,
/* initiate DMA transfer */
if (flctl->chan_fifo0_tx && rlen >= 32 &&
- flctl_dma_fifo0_transfer(flctl, buf, rlen, DMA_MEM_TO_DEV) > 0)
+ flctl_dma_fifo0_transfer(flctl, buf, rlen, DMA_TO_DEVICE) > 0)
return; /* DMA success */
/* do polling transfer */
@@ -611,21 +611,24 @@ static void set_cmd_regs(struct mtd_info *mtd, uint32_t cmd, uint32_t flcmcdr_va
writel(flcmcdr_val, FLCMCDR(flctl));
}
-static int flctl_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
- uint8_t *buf, int oob_required, int page)
+static int flctl_read_page_hwecc(struct nand_chip *chip, uint8_t *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
nand_read_page_op(chip, page, 0, buf, mtd->writesize);
if (oob_required)
- chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+ chip->legacy.read_buf(chip, chip->oob_poi, mtd->oobsize);
return 0;
}
-static int flctl_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
- const uint8_t *buf, int oob_required,
- int page)
+static int flctl_write_page_hwecc(struct nand_chip *chip, const uint8_t *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize);
- chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+ chip->legacy.write_buf(chip, chip->oob_poi, mtd->oobsize);
return nand_prog_page_end_op(chip);
}
@@ -747,9 +750,10 @@ static void execmd_write_oob(struct mtd_info *mtd)
}
}
-static void flctl_cmdfunc(struct mtd_info *mtd, unsigned int command,
+static void flctl_cmdfunc(struct nand_chip *chip, unsigned int command,
int column, int page_addr)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct sh_flctl *flctl = mtd_to_flctl(mtd);
uint32_t read_cmd = 0;
@@ -923,9 +927,9 @@ runtime_exit:
return;
}
-static void flctl_select_chip(struct mtd_info *mtd, int chipnr)
+static void flctl_select_chip(struct nand_chip *chip, int chipnr)
{
- struct sh_flctl *flctl = mtd_to_flctl(mtd);
+ struct sh_flctl *flctl = mtd_to_flctl(nand_to_mtd(chip));
int ret;
switch (chipnr) {
@@ -967,17 +971,17 @@ static void flctl_select_chip(struct mtd_info *mtd, int chipnr)
}
}
-static void flctl_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+static void flctl_write_buf(struct nand_chip *chip, const uint8_t *buf, int len)
{
- struct sh_flctl *flctl = mtd_to_flctl(mtd);
+ struct sh_flctl *flctl = mtd_to_flctl(nand_to_mtd(chip));
memcpy(&flctl->done_buff[flctl->index], buf, len);
flctl->index += len;
}
-static uint8_t flctl_read_byte(struct mtd_info *mtd)
+static uint8_t flctl_read_byte(struct nand_chip *chip)
{
- struct sh_flctl *flctl = mtd_to_flctl(mtd);
+ struct sh_flctl *flctl = mtd_to_flctl(nand_to_mtd(chip));
uint8_t data;
data = flctl->done_buff[flctl->index];
@@ -985,18 +989,9 @@ static uint8_t flctl_read_byte(struct mtd_info *mtd)
return data;
}
-static uint16_t flctl_read_word(struct mtd_info *mtd)
+static void flctl_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
{
- struct sh_flctl *flctl = mtd_to_flctl(mtd);
- uint16_t *buf = (uint16_t *)&flctl->done_buff[flctl->index];
-
- flctl->index += 2;
- return *buf;
-}
-
-static void flctl_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
-{
- struct sh_flctl *flctl = mtd_to_flctl(mtd);
+ struct sh_flctl *flctl = mtd_to_flctl(nand_to_mtd(chip));
memcpy(buf, &flctl->done_buff[flctl->index], len);
flctl->index += len;
@@ -1183,16 +1178,15 @@ static int flctl_probe(struct platform_device *pdev)
/* Set address of hardware control function */
/* 20 us command delay time */
- nand->chip_delay = 20;
+ nand->legacy.chip_delay = 20;
- nand->read_byte = flctl_read_byte;
- nand->read_word = flctl_read_word;
- nand->write_buf = flctl_write_buf;
- nand->read_buf = flctl_read_buf;
+ nand->legacy.read_byte = flctl_read_byte;
+ nand->legacy.write_buf = flctl_write_buf;
+ nand->legacy.read_buf = flctl_read_buf;
nand->select_chip = flctl_select_chip;
- nand->cmdfunc = flctl_cmdfunc;
- nand->set_features = nand_get_set_features_notsupp;
- nand->get_features = nand_get_set_features_notsupp;
+ nand->legacy.cmdfunc = flctl_cmdfunc;
+ nand->legacy.set_features = nand_get_set_features_notsupp;
+ nand->legacy.get_features = nand_get_set_features_notsupp;
if (pdata->flcmncr_val & SEL_16BIT)
nand->options |= NAND_BUSWIDTH_16;
@@ -1203,7 +1197,7 @@ static int flctl_probe(struct platform_device *pdev)
flctl_setup_dma(flctl);
nand->dummy_controller.ops = &flctl_nand_controller_ops;
- ret = nand_scan(flctl_mtd, 1);
+ ret = nand_scan(nand, 1);
if (ret)
goto err_chip;
@@ -1226,7 +1220,7 @@ static int flctl_remove(struct platform_device *pdev)
struct sh_flctl *flctl = platform_get_drvdata(pdev);
flctl_release_dma(flctl);
- nand_release(nand_to_mtd(&flctl->chip));
+ nand_release(&flctl->chip);
pm_runtime_disable(&pdev->dev);
return 0;
diff --git a/drivers/mtd/nand/raw/sharpsl.c b/drivers/mtd/nand/raw/sharpsl.c
index fc171b17a39b..c82f26c8b58c 100644
--- a/drivers/mtd/nand/raw/sharpsl.c
+++ b/drivers/mtd/nand/raw/sharpsl.c
@@ -59,11 +59,10 @@ static inline struct sharpsl_nand *mtd_to_sharpsl(struct mtd_info *mtd)
* NAND_ALE: bit 2 -> bit 2
*
*/
-static void sharpsl_nand_hwcontrol(struct mtd_info *mtd, int cmd,
+static void sharpsl_nand_hwcontrol(struct nand_chip *chip, int cmd,
unsigned int ctrl)
{
- struct sharpsl_nand *sharpsl = mtd_to_sharpsl(mtd);
- struct nand_chip *chip = mtd_to_nand(mtd);
+ struct sharpsl_nand *sharpsl = mtd_to_sharpsl(nand_to_mtd(chip));
if (ctrl & NAND_CTRL_CHANGE) {
unsigned char bits = ctrl & 0x07;
@@ -76,24 +75,25 @@ static void sharpsl_nand_hwcontrol(struct mtd_info *mtd, int cmd,
}
if (cmd != NAND_CMD_NONE)
- writeb(cmd, chip->IO_ADDR_W);
+ writeb(cmd, chip->legacy.IO_ADDR_W);
}
-static int sharpsl_nand_dev_ready(struct mtd_info *mtd)
+static int sharpsl_nand_dev_ready(struct nand_chip *chip)
{
- struct sharpsl_nand *sharpsl = mtd_to_sharpsl(mtd);
+ struct sharpsl_nand *sharpsl = mtd_to_sharpsl(nand_to_mtd(chip));
return !((readb(sharpsl->io + FLASHCTL) & FLRYBY) == 0);
}
-static void sharpsl_nand_enable_hwecc(struct mtd_info *mtd, int mode)
+static void sharpsl_nand_enable_hwecc(struct nand_chip *chip, int mode)
{
- struct sharpsl_nand *sharpsl = mtd_to_sharpsl(mtd);
+ struct sharpsl_nand *sharpsl = mtd_to_sharpsl(nand_to_mtd(chip));
writeb(0, sharpsl->io + ECCCLRR);
}
-static int sharpsl_nand_calculate_ecc(struct mtd_info *mtd, const u_char * dat, u_char * ecc_code)
+static int sharpsl_nand_calculate_ecc(struct nand_chip *chip,
+ const u_char * dat, u_char * ecc_code)
{
- struct sharpsl_nand *sharpsl = mtd_to_sharpsl(mtd);
+ struct sharpsl_nand *sharpsl = mtd_to_sharpsl(nand_to_mtd(chip));
ecc_code[0] = ~readb(sharpsl->io + ECCLPUB);
ecc_code[1] = ~readb(sharpsl->io + ECCLPLB);
ecc_code[2] = (~readb(sharpsl->io + ECCCP) << 2) | 0x03;
@@ -153,13 +153,13 @@ static int sharpsl_nand_probe(struct platform_device *pdev)
writeb(readb(sharpsl->io + FLASHCTL) | FLWP, sharpsl->io + FLASHCTL);
/* Set address of NAND IO lines */
- this->IO_ADDR_R = sharpsl->io + FLASHIO;
- this->IO_ADDR_W = sharpsl->io + FLASHIO;
+ this->legacy.IO_ADDR_R = sharpsl->io + FLASHIO;
+ this->legacy.IO_ADDR_W = sharpsl->io + FLASHIO;
/* Set address of hardware control function */
- this->cmd_ctrl = sharpsl_nand_hwcontrol;
- this->dev_ready = sharpsl_nand_dev_ready;
+ this->legacy.cmd_ctrl = sharpsl_nand_hwcontrol;
+ this->legacy.dev_ready = sharpsl_nand_dev_ready;
/* 15 us command delay time */
- this->chip_delay = 15;
+ this->legacy.chip_delay = 15;
/* set eccmode using hardware ECC */
this->ecc.mode = NAND_ECC_HW;
this->ecc.size = 256;
@@ -171,7 +171,7 @@ static int sharpsl_nand_probe(struct platform_device *pdev)
this->ecc.correct = nand_correct_data;
/* Scan to find existence of the device */
- err = nand_scan(mtd, 1);
+ err = nand_scan(this, 1);
if (err)
goto err_scan;
@@ -187,7 +187,7 @@ static int sharpsl_nand_probe(struct platform_device *pdev)
return 0;
err_add:
- nand_release(mtd);
+ nand_release(this);
err_scan:
iounmap(sharpsl->io);
@@ -205,7 +205,7 @@ static int sharpsl_nand_remove(struct platform_device *pdev)
struct sharpsl_nand *sharpsl = platform_get_drvdata(pdev);
/* Release resources, unregister device */
- nand_release(nand_to_mtd(&sharpsl->chip));
+ nand_release(&sharpsl->chip);
iounmap(sharpsl->io);
diff --git a/drivers/mtd/nand/raw/sm_common.c b/drivers/mtd/nand/raw/sm_common.c
index 73aafe8c3ef3..6f063ef57640 100644
--- a/drivers/mtd/nand/raw/sm_common.c
+++ b/drivers/mtd/nand/raw/sm_common.c
@@ -99,8 +99,9 @@ static const struct mtd_ooblayout_ops oob_sm_small_ops = {
.free = oob_sm_small_ooblayout_free,
};
-static int sm_block_markbad(struct mtd_info *mtd, loff_t ofs)
+static int sm_block_markbad(struct nand_chip *chip, loff_t ofs)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct mtd_oob_ops ops;
struct sm_oob oob;
int ret;
@@ -167,7 +168,7 @@ static int sm_attach_chip(struct nand_chip *chip)
/* Bad block marker position */
chip->badblockpos = 0x05;
chip->badblockbits = 7;
- chip->block_markbad = sm_block_markbad;
+ chip->legacy.block_markbad = sm_block_markbad;
/* ECC layout */
if (mtd->writesize == SM_SECTOR_SIZE)
@@ -195,7 +196,7 @@ int sm_register_device(struct mtd_info *mtd, int smartmedia)
/* Scan for card properties */
chip->dummy_controller.ops = &sm_controller_ops;
flash_ids = smartmedia ? nand_smartmedia_flash_ids : nand_xd_flash_ids;
- ret = nand_scan_with_ids(mtd, 1, flash_ids);
+ ret = nand_scan_with_ids(chip, 1, flash_ids);
if (ret)
return ret;
diff --git a/drivers/mtd/nand/raw/socrates_nand.c b/drivers/mtd/nand/raw/socrates_nand.c
index 9824a9923583..8be9a50c7880 100644
--- a/drivers/mtd/nand/raw/socrates_nand.c
+++ b/drivers/mtd/nand/raw/socrates_nand.c
@@ -34,15 +34,14 @@ struct socrates_nand_host {
/**
* socrates_nand_write_buf - write buffer to chip
- * @mtd: MTD device structure
+ * @this: NAND chip object
* @buf: data buffer
* @len: number of bytes to write
*/
-static void socrates_nand_write_buf(struct mtd_info *mtd,
- const uint8_t *buf, int len)
+static void socrates_nand_write_buf(struct nand_chip *this, const uint8_t *buf,
+ int len)
{
int i;
- struct nand_chip *this = mtd_to_nand(mtd);
struct socrates_nand_host *host = nand_get_controller_data(this);
for (i = 0; i < len; i++) {
@@ -54,14 +53,14 @@ static void socrates_nand_write_buf(struct mtd_info *mtd,
/**
* socrates_nand_read_buf - read chip data into buffer
- * @mtd: MTD device structure
+ * @this: NAND chip object
* @buf: buffer to store date
* @len: number of bytes to read
*/
-static void socrates_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+static void socrates_nand_read_buf(struct nand_chip *this, uint8_t *buf,
+ int len)
{
int i;
- struct nand_chip *this = mtd_to_nand(mtd);
struct socrates_nand_host *host = nand_get_controller_data(this);
uint32_t val;
@@ -78,31 +77,19 @@ static void socrates_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
* socrates_nand_read_byte - read one byte from the chip
* @mtd: MTD device structure
*/
-static uint8_t socrates_nand_read_byte(struct mtd_info *mtd)
+static uint8_t socrates_nand_read_byte(struct nand_chip *this)
{
uint8_t byte;
- socrates_nand_read_buf(mtd, &byte, sizeof(byte));
+ socrates_nand_read_buf(this, &byte, sizeof(byte));
return byte;
}
-/**
- * socrates_nand_read_word - read one word from the chip
- * @mtd: MTD device structure
- */
-static uint16_t socrates_nand_read_word(struct mtd_info *mtd)
-{
- uint16_t word;
- socrates_nand_read_buf(mtd, (uint8_t *)&word, sizeof(word));
- return word;
-}
-
/*
* Hardware specific access to control-lines
*/
-static void socrates_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
- unsigned int ctrl)
+static void socrates_nand_cmd_ctrl(struct nand_chip *nand_chip, int cmd,
+ unsigned int ctrl)
{
- struct nand_chip *nand_chip = mtd_to_nand(mtd);
struct socrates_nand_host *host = nand_get_controller_data(nand_chip);
uint32_t val;
@@ -125,9 +112,8 @@ static void socrates_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
/*
* Read the Device Ready pin.
*/
-static int socrates_nand_device_ready(struct mtd_info *mtd)
+static int socrates_nand_device_ready(struct nand_chip *nand_chip)
{
- struct nand_chip *nand_chip = mtd_to_nand(mtd);
struct socrates_nand_host *host = nand_get_controller_data(nand_chip);
if (in_be32(host->io_base) & FPGA_NAND_BUSY)
@@ -166,26 +152,21 @@ static int socrates_nand_probe(struct platform_device *ofdev)
mtd->name = "socrates_nand";
mtd->dev.parent = &ofdev->dev;
- /*should never be accessed directly */
- nand_chip->IO_ADDR_R = (void *)0xdeadbeef;
- nand_chip->IO_ADDR_W = (void *)0xdeadbeef;
-
- nand_chip->cmd_ctrl = socrates_nand_cmd_ctrl;
- nand_chip->read_byte = socrates_nand_read_byte;
- nand_chip->read_word = socrates_nand_read_word;
- nand_chip->write_buf = socrates_nand_write_buf;
- nand_chip->read_buf = socrates_nand_read_buf;
- nand_chip->dev_ready = socrates_nand_device_ready;
+ nand_chip->legacy.cmd_ctrl = socrates_nand_cmd_ctrl;
+ nand_chip->legacy.read_byte = socrates_nand_read_byte;
+ nand_chip->legacy.write_buf = socrates_nand_write_buf;
+ nand_chip->legacy.read_buf = socrates_nand_read_buf;
+ nand_chip->legacy.dev_ready = socrates_nand_device_ready;
nand_chip->ecc.mode = NAND_ECC_SOFT; /* enable ECC */
nand_chip->ecc.algo = NAND_ECC_HAMMING;
/* TODO: I have no idea what real delay is. */
- nand_chip->chip_delay = 20; /* 20us command delay time */
+ nand_chip->legacy.chip_delay = 20; /* 20us command delay time */
dev_set_drvdata(&ofdev->dev, host);
- res = nand_scan(mtd, 1);
+ res = nand_scan(nand_chip, 1);
if (res)
goto out;
@@ -193,7 +174,7 @@ static int socrates_nand_probe(struct platform_device *ofdev)
if (!res)
return res;
- nand_release(mtd);
+ nand_release(nand_chip);
out:
iounmap(host->io_base);
@@ -206,9 +187,8 @@ out:
static int socrates_nand_remove(struct platform_device *ofdev)
{
struct socrates_nand_host *host = dev_get_drvdata(&ofdev->dev);
- struct mtd_info *mtd = nand_to_mtd(&host->nand_chip);
- nand_release(mtd);
+ nand_release(&host->nand_chip);
iounmap(host->io_base);
diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi_nand.c
index 1f0b7ee38df5..51b1a548064b 100644
--- a/drivers/mtd/nand/raw/sunxi_nand.c
+++ b/drivers/mtd/nand/raw/sunxi_nand.c
@@ -400,9 +400,8 @@ static void sunxi_nfc_dma_op_cleanup(struct mtd_info *mtd,
nfc->regs + NFC_REG_CTL);
}
-static int sunxi_nfc_dev_ready(struct mtd_info *mtd)
+static int sunxi_nfc_dev_ready(struct nand_chip *nand)
{
- struct nand_chip *nand = mtd_to_nand(mtd);
struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
u32 mask;
@@ -420,9 +419,9 @@ static int sunxi_nfc_dev_ready(struct mtd_info *mtd)
return !!(readl(nfc->regs + NFC_REG_ST) & mask);
}
-static void sunxi_nfc_select_chip(struct mtd_info *mtd, int chip)
+static void sunxi_nfc_select_chip(struct nand_chip *nand, int chip)
{
- struct nand_chip *nand = mtd_to_nand(mtd);
+ struct mtd_info *mtd = nand_to_mtd(nand);
struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
struct sunxi_nand_chip_sel *sel;
@@ -443,9 +442,9 @@ static void sunxi_nfc_select_chip(struct mtd_info *mtd, int chip)
ctl |= NFC_CE_SEL(sel->cs) | NFC_EN |
NFC_PAGE_SHIFT(nand->page_shift);
if (sel->rb < 0) {
- nand->dev_ready = NULL;
+ nand->legacy.dev_ready = NULL;
} else {
- nand->dev_ready = sunxi_nfc_dev_ready;
+ nand->legacy.dev_ready = sunxi_nfc_dev_ready;
ctl |= NFC_RB_SEL(sel->rb);
}
@@ -464,9 +463,8 @@ static void sunxi_nfc_select_chip(struct mtd_info *mtd, int chip)
sunxi_nand->selected = chip;
}
-static void sunxi_nfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+static void sunxi_nfc_read_buf(struct nand_chip *nand, uint8_t *buf, int len)
{
- struct nand_chip *nand = mtd_to_nand(mtd);
struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
int ret;
@@ -502,10 +500,9 @@ static void sunxi_nfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
}
}
-static void sunxi_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf,
+static void sunxi_nfc_write_buf(struct nand_chip *nand, const uint8_t *buf,
int len)
{
- struct nand_chip *nand = mtd_to_nand(mtd);
struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
int ret;
@@ -540,19 +537,18 @@ static void sunxi_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf,
}
}
-static uint8_t sunxi_nfc_read_byte(struct mtd_info *mtd)
+static uint8_t sunxi_nfc_read_byte(struct nand_chip *nand)
{
uint8_t ret = 0;
- sunxi_nfc_read_buf(mtd, &ret, 1);
+ sunxi_nfc_read_buf(nand, &ret, 1);
return ret;
}
-static void sunxi_nfc_cmd_ctrl(struct mtd_info *mtd, int dat,
+static void sunxi_nfc_cmd_ctrl(struct nand_chip *nand, int dat,
unsigned int ctrl)
{
- struct nand_chip *nand = mtd_to_nand(mtd);
struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
int ret;
@@ -761,7 +757,7 @@ static void sunxi_nfc_randomizer_write_buf(struct mtd_info *mtd,
{
sunxi_nfc_randomizer_config(mtd, page, ecc);
sunxi_nfc_randomizer_enable(mtd);
- sunxi_nfc_write_buf(mtd, buf, len);
+ sunxi_nfc_write_buf(mtd_to_nand(mtd), buf, len);
sunxi_nfc_randomizer_disable(mtd);
}
@@ -770,7 +766,7 @@ static void sunxi_nfc_randomizer_read_buf(struct mtd_info *mtd, uint8_t *buf,
{
sunxi_nfc_randomizer_config(mtd, page, ecc);
sunxi_nfc_randomizer_enable(mtd);
- sunxi_nfc_read_buf(mtd, buf, len);
+ sunxi_nfc_read_buf(mtd_to_nand(mtd), buf, len);
sunxi_nfc_randomizer_disable(mtd);
}
@@ -995,7 +991,7 @@ static void sunxi_nfc_hw_ecc_read_extra_oob(struct mtd_info *mtd,
false);
if (!randomize)
- sunxi_nfc_read_buf(mtd, oob + offset, len);
+ sunxi_nfc_read_buf(nand, oob + offset, len);
else
sunxi_nfc_randomizer_read_buf(mtd, oob + offset, len,
false, page);
@@ -1189,10 +1185,10 @@ static void sunxi_nfc_hw_ecc_write_extra_oob(struct mtd_info *mtd,
*cur_off = mtd->oobsize + mtd->writesize;
}
-static int sunxi_nfc_hw_ecc_read_page(struct mtd_info *mtd,
- struct nand_chip *chip, uint8_t *buf,
+static int sunxi_nfc_hw_ecc_read_page(struct nand_chip *chip, uint8_t *buf,
int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct nand_ecc_ctrl *ecc = &chip->ecc;
unsigned int max_bitflips = 0;
int ret, i, cur_off = 0;
@@ -1227,10 +1223,10 @@ static int sunxi_nfc_hw_ecc_read_page(struct mtd_info *mtd,
return max_bitflips;
}
-static int sunxi_nfc_hw_ecc_read_page_dma(struct mtd_info *mtd,
- struct nand_chip *chip, u8 *buf,
+static int sunxi_nfc_hw_ecc_read_page_dma(struct nand_chip *chip, u8 *buf,
int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
int ret;
nand_read_page_op(chip, page, 0, NULL, 0);
@@ -1241,14 +1237,14 @@ static int sunxi_nfc_hw_ecc_read_page_dma(struct mtd_info *mtd,
return ret;
/* Fallback to PIO mode */
- return sunxi_nfc_hw_ecc_read_page(mtd, chip, buf, oob_required, page);
+ return sunxi_nfc_hw_ecc_read_page(chip, buf, oob_required, page);
}
-static int sunxi_nfc_hw_ecc_read_subpage(struct mtd_info *mtd,
- struct nand_chip *chip,
+static int sunxi_nfc_hw_ecc_read_subpage(struct nand_chip *chip,
u32 data_offs, u32 readlen,
u8 *bufpoi, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct nand_ecc_ctrl *ecc = &chip->ecc;
int ret, i, cur_off = 0;
unsigned int max_bitflips = 0;
@@ -1278,11 +1274,11 @@ static int sunxi_nfc_hw_ecc_read_subpage(struct mtd_info *mtd,
return max_bitflips;
}
-static int sunxi_nfc_hw_ecc_read_subpage_dma(struct mtd_info *mtd,
- struct nand_chip *chip,
+static int sunxi_nfc_hw_ecc_read_subpage_dma(struct nand_chip *chip,
u32 data_offs, u32 readlen,
u8 *buf, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
int nchunks = DIV_ROUND_UP(data_offs + readlen, chip->ecc.size);
int ret;
@@ -1293,15 +1289,15 @@ static int sunxi_nfc_hw_ecc_read_subpage_dma(struct mtd_info *mtd,
return ret;
/* Fallback to PIO mode */
- return sunxi_nfc_hw_ecc_read_subpage(mtd, chip, data_offs, readlen,
+ return sunxi_nfc_hw_ecc_read_subpage(chip, data_offs, readlen,
buf, page);
}
-static int sunxi_nfc_hw_ecc_write_page(struct mtd_info *mtd,
- struct nand_chip *chip,
+static int sunxi_nfc_hw_ecc_write_page(struct nand_chip *chip,
const uint8_t *buf, int oob_required,
int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct nand_ecc_ctrl *ecc = &chip->ecc;
int ret, i, cur_off = 0;
@@ -1331,12 +1327,12 @@ static int sunxi_nfc_hw_ecc_write_page(struct mtd_info *mtd,
return nand_prog_page_end_op(chip);
}
-static int sunxi_nfc_hw_ecc_write_subpage(struct mtd_info *mtd,
- struct nand_chip *chip,
+static int sunxi_nfc_hw_ecc_write_subpage(struct nand_chip *chip,
u32 data_offs, u32 data_len,
const u8 *buf, int oob_required,
int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct nand_ecc_ctrl *ecc = &chip->ecc;
int ret, i, cur_off = 0;
@@ -1363,12 +1359,12 @@ static int sunxi_nfc_hw_ecc_write_subpage(struct mtd_info *mtd,
return nand_prog_page_end_op(chip);
}
-static int sunxi_nfc_hw_ecc_write_page_dma(struct mtd_info *mtd,
- struct nand_chip *chip,
+static int sunxi_nfc_hw_ecc_write_page_dma(struct nand_chip *chip,
const u8 *buf,
int oob_required,
int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct nand_chip *nand = mtd_to_nand(mtd);
struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
struct nand_ecc_ctrl *ecc = &nand->ecc;
@@ -1425,28 +1421,25 @@ static int sunxi_nfc_hw_ecc_write_page_dma(struct mtd_info *mtd,
return nand_prog_page_end_op(chip);
pio_fallback:
- return sunxi_nfc_hw_ecc_write_page(mtd, chip, buf, oob_required, page);
+ return sunxi_nfc_hw_ecc_write_page(chip, buf, oob_required, page);
}
-static int sunxi_nfc_hw_ecc_read_oob(struct mtd_info *mtd,
- struct nand_chip *chip,
- int page)
+static int sunxi_nfc_hw_ecc_read_oob(struct nand_chip *chip, int page)
{
chip->pagebuf = -1;
- return chip->ecc.read_page(mtd, chip, chip->data_buf, 1, page);
+ return chip->ecc.read_page(chip, chip->data_buf, 1, page);
}
-static int sunxi_nfc_hw_ecc_write_oob(struct mtd_info *mtd,
- struct nand_chip *chip,
- int page)
+static int sunxi_nfc_hw_ecc_write_oob(struct nand_chip *chip, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
int ret;
chip->pagebuf = -1;
memset(chip->data_buf, 0xff, mtd->writesize);
- ret = chip->ecc.write_page(mtd, chip, chip->data_buf, 1, page);
+ ret = chip->ecc.write_page(chip, chip->data_buf, 1, page);
if (ret)
return ret;
@@ -1475,10 +1468,9 @@ static int _sunxi_nand_lookup_timing(const s32 *lut, int lut_size, u32 duration,
#define sunxi_nand_lookup_timing(l, p, c) \
_sunxi_nand_lookup_timing(l, ARRAY_SIZE(l), p, c)
-static int sunxi_nfc_setup_data_interface(struct mtd_info *mtd, int csline,
+static int sunxi_nfc_setup_data_interface(struct nand_chip *nand, int csline,
const struct nand_data_interface *conf)
{
- struct nand_chip *nand = mtd_to_nand(mtd);
struct sunxi_nand_chip *chip = to_sunxi_nand(nand);
struct sunxi_nfc *nfc = to_sunxi_nfc(chip->nand.controller);
const struct nand_sdr_timings *timings;
@@ -1920,7 +1912,7 @@ static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
nand = &chip->nand;
/* Default tR value specified in the ONFI spec (chapter 4.15.1) */
- nand->chip_delay = 200;
+ nand->legacy.chip_delay = 200;
nand->controller = &nfc->controller;
nand->controller->ops = &sunxi_nand_controller_ops;
@@ -1931,23 +1923,23 @@ static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
nand->ecc.mode = NAND_ECC_HW;
nand_set_flash_node(nand, np);
nand->select_chip = sunxi_nfc_select_chip;
- nand->cmd_ctrl = sunxi_nfc_cmd_ctrl;
- nand->read_buf = sunxi_nfc_read_buf;
- nand->write_buf = sunxi_nfc_write_buf;
- nand->read_byte = sunxi_nfc_read_byte;
+ nand->legacy.cmd_ctrl = sunxi_nfc_cmd_ctrl;
+ nand->legacy.read_buf = sunxi_nfc_read_buf;
+ nand->legacy.write_buf = sunxi_nfc_write_buf;
+ nand->legacy.read_byte = sunxi_nfc_read_byte;
nand->setup_data_interface = sunxi_nfc_setup_data_interface;
mtd = nand_to_mtd(nand);
mtd->dev.parent = dev;
- ret = nand_scan(mtd, nsels);
+ ret = nand_scan(nand, nsels);
if (ret)
return ret;
ret = mtd_device_register(mtd, NULL, 0);
if (ret) {
dev_err(dev, "failed to register mtd device: %d\n", ret);
- nand_release(mtd);
+ nand_release(nand);
return ret;
}
@@ -1986,7 +1978,7 @@ static void sunxi_nand_chips_cleanup(struct sunxi_nfc *nfc)
while (!list_empty(&nfc->chips)) {
chip = list_first_entry(&nfc->chips, struct sunxi_nand_chip,
node);
- nand_release(nand_to_mtd(&chip->nand));
+ nand_release(&chip->nand);
sunxi_nand_ecc_cleanup(&chip->nand.ecc);
list_del(&chip->node);
}
diff --git a/drivers/mtd/nand/raw/tango_nand.c b/drivers/mtd/nand/raw/tango_nand.c
index 72698691727d..8818f893f300 100644
--- a/drivers/mtd/nand/raw/tango_nand.c
+++ b/drivers/mtd/nand/raw/tango_nand.c
@@ -116,9 +116,9 @@ struct tango_chip {
#define TIMING(t0, t1, t2, t3) ((t0) << 24 | (t1) << 16 | (t2) << 8 | (t3))
-static void tango_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
+static void tango_cmd_ctrl(struct nand_chip *chip, int dat, unsigned int ctrl)
{
- struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd));
+ struct tango_chip *tchip = to_tango_chip(chip);
if (ctrl & NAND_CLE)
writeb_relaxed(dat, tchip->base + PBUS_CMD);
@@ -127,38 +127,36 @@ static void tango_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
writeb_relaxed(dat, tchip->base + PBUS_ADDR);
}
-static int tango_dev_ready(struct mtd_info *mtd)
+static int tango_dev_ready(struct nand_chip *chip)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct tango_nfc *nfc = to_tango_nfc(chip->controller);
return readl_relaxed(nfc->pbus_base + PBUS_CS_CTRL) & PBUS_IORDY;
}
-static u8 tango_read_byte(struct mtd_info *mtd)
+static u8 tango_read_byte(struct nand_chip *chip)
{
- struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd));
+ struct tango_chip *tchip = to_tango_chip(chip);
return readb_relaxed(tchip->base + PBUS_DATA);
}
-static void tango_read_buf(struct mtd_info *mtd, u8 *buf, int len)
+static void tango_read_buf(struct nand_chip *chip, u8 *buf, int len)
{
- struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd));
+ struct tango_chip *tchip = to_tango_chip(chip);
ioread8_rep(tchip->base + PBUS_DATA, buf, len);
}
-static void tango_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
+static void tango_write_buf(struct nand_chip *chip, const u8 *buf, int len)
{
- struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd));
+ struct tango_chip *tchip = to_tango_chip(chip);
iowrite8_rep(tchip->base + PBUS_DATA, buf, len);
}
-static void tango_select_chip(struct mtd_info *mtd, int idx)
+static void tango_select_chip(struct nand_chip *chip, int idx)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct tango_nfc *nfc = to_tango_nfc(chip->controller);
struct tango_chip *tchip = to_tango_chip(chip);
@@ -277,14 +275,15 @@ dma_unmap:
return err;
}
-static int tango_read_page(struct mtd_info *mtd, struct nand_chip *chip,
- u8 *buf, int oob_required, int page)
+static int tango_read_page(struct nand_chip *chip, u8 *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct tango_nfc *nfc = to_tango_nfc(chip->controller);
int err, res, len = mtd->writesize;
if (oob_required)
- chip->ecc.read_oob(mtd, chip, page);
+ chip->ecc.read_oob(chip, page);
err = do_dma(nfc, DMA_FROM_DEVICE, NFC_READ, buf, len, page);
if (err)
@@ -292,16 +291,17 @@ static int tango_read_page(struct mtd_info *mtd, struct nand_chip *chip,
res = decode_error_report(chip);
if (res < 0) {
- chip->ecc.read_oob_raw(mtd, chip, page);
+ chip->ecc.read_oob_raw(chip, page);
res = check_erased_page(chip, buf);
}
return res;
}
-static int tango_write_page(struct mtd_info *mtd, struct nand_chip *chip,
- const u8 *buf, int oob_required, int page)
+static int tango_write_page(struct nand_chip *chip, const u8 *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct tango_nfc *nfc = to_tango_nfc(chip->controller);
int err, status, len = mtd->writesize;
@@ -314,7 +314,7 @@ static int tango_write_page(struct mtd_info *mtd, struct nand_chip *chip,
if (err)
return err;
- status = chip->waitfunc(mtd, chip);
+ status = chip->legacy.waitfunc(chip);
if (status & NAND_STATUS_FAIL)
return -EIO;
@@ -323,30 +323,26 @@ static int tango_write_page(struct mtd_info *mtd, struct nand_chip *chip,
static void aux_read(struct nand_chip *chip, u8 **buf, int len, int *pos)
{
- struct mtd_info *mtd = nand_to_mtd(chip);
-
*pos += len;
if (!*buf) {
/* skip over "len" bytes */
nand_change_read_column_op(chip, *pos, NULL, 0, false);
} else {
- tango_read_buf(mtd, *buf, len);
+ tango_read_buf(chip, *buf, len);
*buf += len;
}
}
static void aux_write(struct nand_chip *chip, const u8 **buf, int len, int *pos)
{
- struct mtd_info *mtd = nand_to_mtd(chip);
-
*pos += len;
if (!*buf) {
/* skip over "len" bytes */
nand_change_write_column_op(chip, *pos, NULL, 0, false);
} else {
- tango_write_buf(mtd, *buf, len);
+ tango_write_buf(chip, *buf, len);
*buf += len;
}
}
@@ -424,32 +420,30 @@ static void raw_write(struct nand_chip *chip, const u8 *buf, const u8 *oob)
aux_write(chip, &oob, ecc_size, &pos);
}
-static int tango_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
- u8 *buf, int oob_required, int page)
+static int tango_read_page_raw(struct nand_chip *chip, u8 *buf,
+ int oob_required, int page)
{
nand_read_page_op(chip, page, 0, NULL, 0);
raw_read(chip, buf, chip->oob_poi);
return 0;
}
-static int tango_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
- const u8 *buf, int oob_required, int page)
+static int tango_write_page_raw(struct nand_chip *chip, const u8 *buf,
+ int oob_required, int page)
{
nand_prog_page_begin_op(chip, page, 0, NULL, 0);
raw_write(chip, buf, chip->oob_poi);
return nand_prog_page_end_op(chip);
}
-static int tango_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
- int page)
+static int tango_read_oob(struct nand_chip *chip, int page)
{
nand_read_page_op(chip, page, 0, NULL, 0);
raw_read(chip, NULL, chip->oob_poi);
return 0;
}
-static int tango_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
- int page)
+static int tango_write_oob(struct nand_chip *chip, int page)
{
nand_prog_page_begin_op(chip, page, 0, NULL, 0);
raw_write(chip, NULL, chip->oob_poi);
@@ -485,11 +479,10 @@ static u32 to_ticks(int kHz, int ps)
return DIV_ROUND_UP_ULL((u64)kHz * ps, NSEC_PER_SEC);
}
-static int tango_set_timings(struct mtd_info *mtd, int csline,
+static int tango_set_timings(struct nand_chip *chip, int csline,
const struct nand_data_interface *conf)
{
const struct nand_sdr_timings *sdr = nand_get_sdr_timings(conf);
- struct nand_chip *chip = mtd_to_nand(mtd);
struct tango_nfc *nfc = to_tango_nfc(chip->controller);
struct tango_chip *tchip = to_tango_chip(chip);
u32 Trdy, Textw, Twc, Twpw, Tacc, Thold, Trpw, Textr;
@@ -571,12 +564,12 @@ static int chip_init(struct device *dev, struct device_node *np)
ecc = &chip->ecc;
mtd = nand_to_mtd(chip);
- chip->read_byte = tango_read_byte;
- chip->write_buf = tango_write_buf;
- chip->read_buf = tango_read_buf;
+ chip->legacy.read_byte = tango_read_byte;
+ chip->legacy.write_buf = tango_write_buf;
+ chip->legacy.read_buf = tango_read_buf;
chip->select_chip = tango_select_chip;
- chip->cmd_ctrl = tango_cmd_ctrl;
- chip->dev_ready = tango_dev_ready;
+ chip->legacy.cmd_ctrl = tango_cmd_ctrl;
+ chip->legacy.dev_ready = tango_dev_ready;
chip->setup_data_interface = tango_set_timings;
chip->options = NAND_USE_BOUNCE_BUFFER |
NAND_NO_SUBPAGE_WRITE |
@@ -588,7 +581,7 @@ static int chip_init(struct device *dev, struct device_node *np)
mtd_set_ooblayout(mtd, &tango_nand_ooblayout_ops);
mtd->dev.parent = dev;
- err = nand_scan(mtd, 1);
+ err = nand_scan(chip, 1);
if (err)
return err;
@@ -617,7 +610,7 @@ static int tango_nand_remove(struct platform_device *pdev)
for (cs = 0; cs < MAX_CS; ++cs) {
if (nfc->chips[cs])
- nand_release(nand_to_mtd(&nfc->chips[cs]->nand_chip));
+ nand_release(&nfc->chips[cs]->nand_chip);
}
return 0;
diff --git a/drivers/mtd/nand/raw/tegra_nand.c b/drivers/mtd/nand/raw/tegra_nand.c
index 79da1efc88d1..9767e29d74e2 100644
--- a/drivers/mtd/nand/raw/tegra_nand.c
+++ b/drivers/mtd/nand/raw/tegra_nand.c
@@ -462,9 +462,8 @@ static int tegra_nand_exec_op(struct nand_chip *chip,
check_only);
}
-static void tegra_nand_select_chip(struct mtd_info *mtd, int die_nr)
+static void tegra_nand_select_chip(struct nand_chip *chip, int die_nr)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct tegra_nand_chip *nand = to_tegra_chip(chip);
struct tegra_nand_controller *ctrl = to_tegra_ctrl(chip->controller);
@@ -615,44 +614,46 @@ err_unmap_dma_page:
return ret;
}
-static int tegra_nand_read_page_raw(struct mtd_info *mtd,
- struct nand_chip *chip, u8 *buf,
+static int tegra_nand_read_page_raw(struct nand_chip *chip, u8 *buf,
int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
void *oob_buf = oob_required ? chip->oob_poi : NULL;
return tegra_nand_page_xfer(mtd, chip, buf, oob_buf,
mtd->oobsize, page, true);
}
-static int tegra_nand_write_page_raw(struct mtd_info *mtd,
- struct nand_chip *chip, const u8 *buf,
+static int tegra_nand_write_page_raw(struct nand_chip *chip, const u8 *buf,
int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
void *oob_buf = oob_required ? chip->oob_poi : NULL;
return tegra_nand_page_xfer(mtd, chip, (void *)buf, oob_buf,
mtd->oobsize, page, false);
}
-static int tegra_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
- int page)
+static int tegra_nand_read_oob(struct nand_chip *chip, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
return tegra_nand_page_xfer(mtd, chip, NULL, chip->oob_poi,
mtd->oobsize, page, true);
}
-static int tegra_nand_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
- int page)
+static int tegra_nand_write_oob(struct nand_chip *chip, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
return tegra_nand_page_xfer(mtd, chip, NULL, chip->oob_poi,
mtd->oobsize, page, false);
}
-static int tegra_nand_read_page_hwecc(struct mtd_info *mtd,
- struct nand_chip *chip, u8 *buf,
+static int tegra_nand_read_page_hwecc(struct nand_chip *chip, u8 *buf,
int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct tegra_nand_controller *ctrl = to_tegra_ctrl(chip->controller);
struct tegra_nand_chip *nand = to_tegra_chip(chip);
void *oob_buf = oob_required ? chip->oob_poi : NULL;
@@ -716,7 +717,7 @@ static int tegra_nand_read_page_hwecc(struct mtd_info *mtd,
* erased or if error correction just failed for all sub-
* pages.
*/
- ret = tegra_nand_read_oob(mtd, chip, page);
+ ret = tegra_nand_read_oob(chip, page);
if (ret < 0)
return ret;
@@ -759,10 +760,10 @@ static int tegra_nand_read_page_hwecc(struct mtd_info *mtd,
}
}
-static int tegra_nand_write_page_hwecc(struct mtd_info *mtd,
- struct nand_chip *chip, const u8 *buf,
+static int tegra_nand_write_page_hwecc(struct nand_chip *chip, const u8 *buf,
int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct tegra_nand_controller *ctrl = to_tegra_ctrl(chip->controller);
void *oob_buf = oob_required ? chip->oob_poi : NULL;
int ret;
@@ -813,10 +814,9 @@ static void tegra_nand_setup_timing(struct tegra_nand_controller *ctrl,
writel_relaxed(reg, ctrl->regs + TIMING_2);
}
-static int tegra_nand_setup_data_interface(struct mtd_info *mtd, int csline,
+static int tegra_nand_setup_data_interface(struct nand_chip *chip, int csline,
const struct nand_data_interface *conf)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct tegra_nand_controller *ctrl = to_tegra_ctrl(chip->controller);
const struct nand_sdr_timings *timings;
@@ -1119,7 +1119,7 @@ static int tegra_nand_chips_init(struct device *dev,
chip->select_chip = tegra_nand_select_chip;
chip->setup_data_interface = tegra_nand_setup_data_interface;
- ret = nand_scan(mtd, 1);
+ ret = nand_scan(chip, 1);
if (ret)
return ret;
diff --git a/drivers/mtd/nand/raw/tmio_nand.c b/drivers/mtd/nand/raw/tmio_nand.c
index dcaa924502de..f3b59e649b7d 100644
--- a/drivers/mtd/nand/raw/tmio_nand.c
+++ b/drivers/mtd/nand/raw/tmio_nand.c
@@ -126,11 +126,10 @@ static inline struct tmio_nand *mtd_to_tmio(struct mtd_info *mtd)
/*--------------------------------------------------------------------------*/
-static void tmio_nand_hwcontrol(struct mtd_info *mtd, int cmd,
- unsigned int ctrl)
+static void tmio_nand_hwcontrol(struct nand_chip *chip, int cmd,
+ unsigned int ctrl)
{
- struct tmio_nand *tmio = mtd_to_tmio(mtd);
- struct nand_chip *chip = mtd_to_nand(mtd);
+ struct tmio_nand *tmio = mtd_to_tmio(nand_to_mtd(chip));
if (ctrl & NAND_CTRL_CHANGE) {
u8 mode;
@@ -156,12 +155,12 @@ static void tmio_nand_hwcontrol(struct mtd_info *mtd, int cmd,
}
if (cmd != NAND_CMD_NONE)
- tmio_iowrite8(cmd, chip->IO_ADDR_W);
+ tmio_iowrite8(cmd, chip->legacy.IO_ADDR_W);
}
-static int tmio_nand_dev_ready(struct mtd_info *mtd)
+static int tmio_nand_dev_ready(struct nand_chip *chip)
{
- struct tmio_nand *tmio = mtd_to_tmio(mtd);
+ struct tmio_nand *tmio = mtd_to_tmio(nand_to_mtd(chip));
return !(tmio_ioread8(tmio->fcr + FCR_STATUS) & FCR_STATUS_BUSY);
}
@@ -187,10 +186,9 @@ static irqreturn_t tmio_irq(int irq, void *__tmio)
*erase and write, we enable it to wake us up. The irq handler
*disables the interrupt.
*/
-static int
-tmio_nand_wait(struct mtd_info *mtd, struct nand_chip *nand_chip)
+static int tmio_nand_wait(struct nand_chip *nand_chip)
{
- struct tmio_nand *tmio = mtd_to_tmio(mtd);
+ struct tmio_nand *tmio = mtd_to_tmio(nand_to_mtd(nand_chip));
long timeout;
u8 status;
@@ -199,10 +197,10 @@ tmio_nand_wait(struct mtd_info *mtd, struct nand_chip *nand_chip)
tmio_iowrite8(0x81, tmio->fcr + FCR_IMR);
timeout = wait_event_timeout(nand_chip->controller->wq,
- tmio_nand_dev_ready(mtd),
+ tmio_nand_dev_ready(nand_chip),
msecs_to_jiffies(nand_chip->state == FL_ERASING ? 400 : 20));
- if (unlikely(!tmio_nand_dev_ready(mtd))) {
+ if (unlikely(!tmio_nand_dev_ready(nand_chip))) {
tmio_iowrite8(0x00, tmio->fcr + FCR_IMR);
dev_warn(&tmio->dev->dev, "still busy with %s after %d ms\n",
nand_chip->state == FL_ERASING ? "erase" : "program",
@@ -225,9 +223,9 @@ tmio_nand_wait(struct mtd_info *mtd, struct nand_chip *nand_chip)
*To prevent stale data from being read, tmio_nand_hwcontrol() clears
*tmio->read_good.
*/
-static u_char tmio_nand_read_byte(struct mtd_info *mtd)
+static u_char tmio_nand_read_byte(struct nand_chip *chip)
{
- struct tmio_nand *tmio = mtd_to_tmio(mtd);
+ struct tmio_nand *tmio = mtd_to_tmio(nand_to_mtd(chip));
unsigned int data;
if (tmio->read_good--)
@@ -245,33 +243,33 @@ static u_char tmio_nand_read_byte(struct mtd_info *mtd)
*buffer functions.
*/
static void
-tmio_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
+tmio_nand_write_buf(struct nand_chip *chip, const u_char *buf, int len)
{
- struct tmio_nand *tmio = mtd_to_tmio(mtd);
+ struct tmio_nand *tmio = mtd_to_tmio(nand_to_mtd(chip));
tmio_iowrite16_rep(tmio->fcr + FCR_DATA, buf, len >> 1);
}
-static void tmio_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+static void tmio_nand_read_buf(struct nand_chip *chip, u_char *buf, int len)
{
- struct tmio_nand *tmio = mtd_to_tmio(mtd);
+ struct tmio_nand *tmio = mtd_to_tmio(nand_to_mtd(chip));
tmio_ioread16_rep(tmio->fcr + FCR_DATA, buf, len >> 1);
}
-static void tmio_nand_enable_hwecc(struct mtd_info *mtd, int mode)
+static void tmio_nand_enable_hwecc(struct nand_chip *chip, int mode)
{
- struct tmio_nand *tmio = mtd_to_tmio(mtd);
+ struct tmio_nand *tmio = mtd_to_tmio(nand_to_mtd(chip));
tmio_iowrite8(FCR_MODE_HWECC_RESET, tmio->fcr + FCR_MODE);
tmio_ioread8(tmio->fcr + FCR_DATA); /* dummy read */
tmio_iowrite8(FCR_MODE_HWECC_CALC, tmio->fcr + FCR_MODE);
}
-static int tmio_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
- u_char *ecc_code)
+static int tmio_nand_calculate_ecc(struct nand_chip *chip, const u_char *dat,
+ u_char *ecc_code)
{
- struct tmio_nand *tmio = mtd_to_tmio(mtd);
+ struct tmio_nand *tmio = mtd_to_tmio(nand_to_mtd(chip));
unsigned int ecc;
tmio_iowrite8(FCR_MODE_HWECC_RESULT, tmio->fcr + FCR_MODE);
@@ -290,16 +288,18 @@ static int tmio_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
return 0;
}
-static int tmio_nand_correct_data(struct mtd_info *mtd, unsigned char *buf,
- unsigned char *read_ecc, unsigned char *calc_ecc)
+static int tmio_nand_correct_data(struct nand_chip *chip, unsigned char *buf,
+ unsigned char *read_ecc,
+ unsigned char *calc_ecc)
{
int r0, r1;
/* assume ecc.size = 512 and ecc.bytes = 6 */
- r0 = __nand_correct_data(buf, read_ecc, calc_ecc, 256);
+ r0 = __nand_correct_data(buf, read_ecc, calc_ecc, 256, false);
if (r0 < 0)
return r0;
- r1 = __nand_correct_data(buf + 256, read_ecc + 3, calc_ecc + 3, 256);
+ r1 = __nand_correct_data(buf + 256, read_ecc + 3, calc_ecc + 3, 256,
+ false);
if (r1 < 0)
return r1;
return r0 + r1;
@@ -400,15 +400,15 @@ static int tmio_probe(struct platform_device *dev)
return retval;
/* Set address of NAND IO lines */
- nand_chip->IO_ADDR_R = tmio->fcr;
- nand_chip->IO_ADDR_W = tmio->fcr;
+ nand_chip->legacy.IO_ADDR_R = tmio->fcr;
+ nand_chip->legacy.IO_ADDR_W = tmio->fcr;
/* Set address of hardware control function */
- nand_chip->cmd_ctrl = tmio_nand_hwcontrol;
- nand_chip->dev_ready = tmio_nand_dev_ready;
- nand_chip->read_byte = tmio_nand_read_byte;
- nand_chip->write_buf = tmio_nand_write_buf;
- nand_chip->read_buf = tmio_nand_read_buf;
+ nand_chip->legacy.cmd_ctrl = tmio_nand_hwcontrol;
+ nand_chip->legacy.dev_ready = tmio_nand_dev_ready;
+ nand_chip->legacy.read_byte = tmio_nand_read_byte;
+ nand_chip->legacy.write_buf = tmio_nand_write_buf;
+ nand_chip->legacy.read_buf = tmio_nand_read_buf;
/* set eccmode using hardware ECC */
nand_chip->ecc.mode = NAND_ECC_HW;
@@ -423,7 +423,7 @@ static int tmio_probe(struct platform_device *dev)
nand_chip->badblock_pattern = data->badblock_pattern;
/* 15 us command delay time */
- nand_chip->chip_delay = 15;
+ nand_chip->legacy.chip_delay = 15;
retval = devm_request_irq(&dev->dev, irq, &tmio_irq, 0,
dev_name(&dev->dev), tmio);
@@ -433,10 +433,10 @@ static int tmio_probe(struct platform_device *dev)
}
tmio->irq = irq;
- nand_chip->waitfunc = tmio_nand_wait;
+ nand_chip->legacy.waitfunc = tmio_nand_wait;
/* Scan to find existence of the device */
- retval = nand_scan(mtd, 1);
+ retval = nand_scan(nand_chip, 1);
if (retval)
goto err_irq;
@@ -449,7 +449,7 @@ static int tmio_probe(struct platform_device *dev)
if (!retval)
return retval;
- nand_release(mtd);
+ nand_release(nand_chip);
err_irq:
tmio_hw_stop(dev, tmio);
@@ -460,7 +460,7 @@ static int tmio_remove(struct platform_device *dev)
{
struct tmio_nand *tmio = platform_get_drvdata(dev);
- nand_release(nand_to_mtd(&tmio->chip));
+ nand_release(&tmio->chip);
tmio_hw_stop(dev, tmio);
return 0;
}
diff --git a/drivers/mtd/nand/raw/txx9ndfmc.c b/drivers/mtd/nand/raw/txx9ndfmc.c
index 4d61a14fcb65..ddf0420c0997 100644
--- a/drivers/mtd/nand/raw/txx9ndfmc.c
+++ b/drivers/mtd/nand/raw/txx9ndfmc.c
@@ -102,17 +102,17 @@ static void txx9ndfmc_write(struct platform_device *dev,
__raw_writel(val, ndregaddr(dev, reg));
}
-static uint8_t txx9ndfmc_read_byte(struct mtd_info *mtd)
+static uint8_t txx9ndfmc_read_byte(struct nand_chip *chip)
{
- struct platform_device *dev = mtd_to_platdev(mtd);
+ struct platform_device *dev = mtd_to_platdev(nand_to_mtd(chip));
return txx9ndfmc_read(dev, TXX9_NDFDTR);
}
-static void txx9ndfmc_write_buf(struct mtd_info *mtd, const uint8_t *buf,
+static void txx9ndfmc_write_buf(struct nand_chip *chip, const uint8_t *buf,
int len)
{
- struct platform_device *dev = mtd_to_platdev(mtd);
+ struct platform_device *dev = mtd_to_platdev(nand_to_mtd(chip));
void __iomem *ndfdtr = ndregaddr(dev, TXX9_NDFDTR);
u32 mcr = txx9ndfmc_read(dev, TXX9_NDFMCR);
@@ -122,19 +122,18 @@ static void txx9ndfmc_write_buf(struct mtd_info *mtd, const uint8_t *buf,
txx9ndfmc_write(dev, mcr, TXX9_NDFMCR);
}
-static void txx9ndfmc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+static void txx9ndfmc_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
{
- struct platform_device *dev = mtd_to_platdev(mtd);
+ struct platform_device *dev = mtd_to_platdev(nand_to_mtd(chip));
void __iomem *ndfdtr = ndregaddr(dev, TXX9_NDFDTR);
while (len--)
*buf++ = __raw_readl(ndfdtr);
}
-static void txx9ndfmc_cmd_ctrl(struct mtd_info *mtd, int cmd,
+static void txx9ndfmc_cmd_ctrl(struct nand_chip *chip, int cmd,
unsigned int ctrl)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct txx9ndfmc_priv *txx9_priv = nand_get_controller_data(chip);
struct platform_device *dev = txx9_priv->dev;
struct txx9ndfmc_platform_data *plat = dev_get_platdata(&dev->dev);
@@ -163,18 +162,17 @@ static void txx9ndfmc_cmd_ctrl(struct mtd_info *mtd, int cmd,
mmiowb();
}
-static int txx9ndfmc_dev_ready(struct mtd_info *mtd)
+static int txx9ndfmc_dev_ready(struct nand_chip *chip)
{
- struct platform_device *dev = mtd_to_platdev(mtd);
+ struct platform_device *dev = mtd_to_platdev(nand_to_mtd(chip));
return !(txx9ndfmc_read(dev, TXX9_NDFSR) & TXX9_NDFSR_BUSY);
}
-static int txx9ndfmc_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat,
+static int txx9ndfmc_calculate_ecc(struct nand_chip *chip, const uint8_t *dat,
uint8_t *ecc_code)
{
- struct platform_device *dev = mtd_to_platdev(mtd);
- struct nand_chip *chip = mtd_to_nand(mtd);
+ struct platform_device *dev = mtd_to_platdev(nand_to_mtd(chip));
int eccbytes;
u32 mcr = txx9ndfmc_read(dev, TXX9_NDFMCR);
@@ -191,16 +189,17 @@ static int txx9ndfmc_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat,
return 0;
}
-static int txx9ndfmc_correct_data(struct mtd_info *mtd, unsigned char *buf,
- unsigned char *read_ecc, unsigned char *calc_ecc)
+static int txx9ndfmc_correct_data(struct nand_chip *chip, unsigned char *buf,
+ unsigned char *read_ecc,
+ unsigned char *calc_ecc)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
int eccsize;
int corrected = 0;
int stat;
for (eccsize = chip->ecc.size; eccsize > 0; eccsize -= 256) {
- stat = __nand_correct_data(buf, read_ecc, calc_ecc, 256);
+ stat = __nand_correct_data(buf, read_ecc, calc_ecc, 256,
+ false);
if (stat < 0)
return stat;
corrected += stat;
@@ -211,9 +210,9 @@ static int txx9ndfmc_correct_data(struct mtd_info *mtd, unsigned char *buf,
return corrected;
}
-static void txx9ndfmc_enable_hwecc(struct mtd_info *mtd, int mode)
+static void txx9ndfmc_enable_hwecc(struct nand_chip *chip, int mode)
{
- struct platform_device *dev = mtd_to_platdev(mtd);
+ struct platform_device *dev = mtd_to_platdev(nand_to_mtd(chip));
u32 mcr = txx9ndfmc_read(dev, TXX9_NDFMCR);
mcr &= ~TXX9_NDFMCR_ECC_ALL;
@@ -326,17 +325,17 @@ static int __init txx9ndfmc_probe(struct platform_device *dev)
mtd = nand_to_mtd(chip);
mtd->dev.parent = &dev->dev;
- chip->read_byte = txx9ndfmc_read_byte;
- chip->read_buf = txx9ndfmc_read_buf;
- chip->write_buf = txx9ndfmc_write_buf;
- chip->cmd_ctrl = txx9ndfmc_cmd_ctrl;
- chip->dev_ready = txx9ndfmc_dev_ready;
+ chip->legacy.read_byte = txx9ndfmc_read_byte;
+ chip->legacy.read_buf = txx9ndfmc_read_buf;
+ chip->legacy.write_buf = txx9ndfmc_write_buf;
+ chip->legacy.cmd_ctrl = txx9ndfmc_cmd_ctrl;
+ chip->legacy.dev_ready = txx9ndfmc_dev_ready;
chip->ecc.calculate = txx9ndfmc_calculate_ecc;
chip->ecc.correct = txx9ndfmc_correct_data;
chip->ecc.hwctl = txx9ndfmc_enable_hwecc;
chip->ecc.mode = NAND_ECC_HW;
chip->ecc.strength = 1;
- chip->chip_delay = 100;
+ chip->legacy.chip_delay = 100;
chip->controller = &drvdata->controller;
nand_set_controller_data(chip, txx9_priv);
@@ -359,7 +358,7 @@ static int __init txx9ndfmc_probe(struct platform_device *dev)
if (plat->wide_mask & (1 << i))
chip->options |= NAND_BUSWIDTH_16;
- if (nand_scan(mtd, 1)) {
+ if (nand_scan(chip, 1)) {
kfree(txx9_priv->mtdname);
kfree(txx9_priv);
continue;
@@ -390,7 +389,7 @@ static int __exit txx9ndfmc_remove(struct platform_device *dev)
chip = mtd_to_nand(mtd);
txx9_priv = nand_get_controller_data(chip);
- nand_release(mtd);
+ nand_release(chip);
kfree(txx9_priv->mtdname);
kfree(txx9_priv);
}
diff --git a/drivers/mtd/nand/raw/vf610_nfc.c b/drivers/mtd/nand/raw/vf610_nfc.c
index 6f6dcbf9095b..9814fd4a84cf 100644
--- a/drivers/mtd/nand/raw/vf610_nfc.c
+++ b/drivers/mtd/nand/raw/vf610_nfc.c
@@ -498,9 +498,9 @@ static int vf610_nfc_exec_op(struct nand_chip *chip,
/*
* This function supports Vybrid only (MPC5125 would have full RB and four CS)
*/
-static void vf610_nfc_select_chip(struct mtd_info *mtd, int chip)
+static void vf610_nfc_select_chip(struct nand_chip *chip, int cs)
{
- struct vf610_nfc *nfc = mtd_to_nfc(mtd);
+ struct vf610_nfc *nfc = mtd_to_nfc(nand_to_mtd(chip));
u32 tmp = vf610_nfc_read(nfc, NFC_ROW_ADDR);
/* Vybrid only (MPC5125 would have full RB and four CS) */
@@ -509,9 +509,9 @@ static void vf610_nfc_select_chip(struct mtd_info *mtd, int chip)
tmp &= ~(ROW_ADDR_CHIP_SEL_RB_MASK | ROW_ADDR_CHIP_SEL_MASK);
- if (chip >= 0) {
+ if (cs >= 0) {
tmp |= 1 << ROW_ADDR_CHIP_SEL_RB_SHIFT;
- tmp |= BIT(chip) << ROW_ADDR_CHIP_SEL_SHIFT;
+ tmp |= BIT(cs) << ROW_ADDR_CHIP_SEL_SHIFT;
}
vf610_nfc_write(nfc, NFC_ROW_ADDR, tmp);
@@ -557,9 +557,10 @@ static void vf610_nfc_fill_row(struct nand_chip *chip, int page, u32 *code,
}
}
-static int vf610_nfc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
- uint8_t *buf, int oob_required, int page)
+static int vf610_nfc_read_page(struct nand_chip *chip, uint8_t *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct vf610_nfc *nfc = mtd_to_nfc(mtd);
int trfr_sz = mtd->writesize + mtd->oobsize;
u32 row = 0, cmd1 = 0, cmd2 = 0, code = 0;
@@ -602,9 +603,10 @@ static int vf610_nfc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
}
}
-static int vf610_nfc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
- const uint8_t *buf, int oob_required, int page)
+static int vf610_nfc_write_page(struct nand_chip *chip, const uint8_t *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct vf610_nfc *nfc = mtd_to_nfc(mtd);
int trfr_sz = mtd->writesize + mtd->oobsize;
u32 row = 0, cmd1 = 0, cmd2 = 0, code = 0;
@@ -643,24 +645,24 @@ static int vf610_nfc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
return 0;
}
-static int vf610_nfc_read_page_raw(struct mtd_info *mtd,
- struct nand_chip *chip, u8 *buf,
+static int vf610_nfc_read_page_raw(struct nand_chip *chip, u8 *buf,
int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct vf610_nfc *nfc = mtd_to_nfc(mtd);
int ret;
nfc->data_access = true;
- ret = nand_read_page_raw(mtd, chip, buf, oob_required, page);
+ ret = nand_read_page_raw(chip, buf, oob_required, page);
nfc->data_access = false;
return ret;
}
-static int vf610_nfc_write_page_raw(struct mtd_info *mtd,
- struct nand_chip *chip, const u8 *buf,
+static int vf610_nfc_write_page_raw(struct nand_chip *chip, const u8 *buf,
int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct vf610_nfc *nfc = mtd_to_nfc(mtd);
int ret;
@@ -677,22 +679,21 @@ static int vf610_nfc_write_page_raw(struct mtd_info *mtd,
return nand_prog_page_end_op(chip);
}
-static int vf610_nfc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
- int page)
+static int vf610_nfc_read_oob(struct nand_chip *chip, int page)
{
- struct vf610_nfc *nfc = mtd_to_nfc(mtd);
+ struct vf610_nfc *nfc = mtd_to_nfc(nand_to_mtd(chip));
int ret;
nfc->data_access = true;
- ret = nand_read_oob_std(mtd, chip, page);
+ ret = nand_read_oob_std(chip, page);
nfc->data_access = false;
return ret;
}
-static int vf610_nfc_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
- int page)
+static int vf610_nfc_write_oob(struct nand_chip *chip, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct vf610_nfc *nfc = mtd_to_nfc(mtd);
int ret;
@@ -892,7 +893,7 @@ static int vf610_nfc_probe(struct platform_device *pdev)
/* Scan the NAND chip */
chip->dummy_controller.ops = &vf610_nfc_controller_ops;
- err = nand_scan(mtd, 1);
+ err = nand_scan(chip, 1);
if (err)
goto err_disable_clk;
@@ -916,7 +917,7 @@ static int vf610_nfc_remove(struct platform_device *pdev)
struct mtd_info *mtd = platform_get_drvdata(pdev);
struct vf610_nfc *nfc = mtd_to_nfc(mtd);
- nand_release(mtd);
+ nand_release(mtd_to_nand(mtd));
clk_disable_unprepare(nfc->clk);
return 0;
}
diff --git a/drivers/mtd/nand/raw/xway_nand.c b/drivers/mtd/nand/raw/xway_nand.c
index 9926b4e3d69d..a234a5cb4868 100644
--- a/drivers/mtd/nand/raw/xway_nand.c
+++ b/drivers/mtd/nand/raw/xway_nand.c
@@ -85,9 +85,8 @@ static void xway_writeb(struct mtd_info *mtd, int op, u8 value)
writeb(value, data->nandaddr + op);
}
-static void xway_select_chip(struct mtd_info *mtd, int select)
+static void xway_select_chip(struct nand_chip *chip, int select)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct xway_nand_data *data = nand_get_controller_data(chip);
switch (select) {
@@ -106,8 +105,10 @@ static void xway_select_chip(struct mtd_info *mtd, int select)
}
}
-static void xway_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+static void xway_cmd_ctrl(struct nand_chip *chip, int cmd, unsigned int ctrl)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
if (cmd == NAND_CMD_NONE)
return;
@@ -120,30 +121,30 @@ static void xway_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
;
}
-static int xway_dev_ready(struct mtd_info *mtd)
+static int xway_dev_ready(struct nand_chip *chip)
{
return ltq_ebu_r32(EBU_NAND_WAIT) & NAND_WAIT_RD;
}
-static unsigned char xway_read_byte(struct mtd_info *mtd)
+static unsigned char xway_read_byte(struct nand_chip *chip)
{
- return xway_readb(mtd, NAND_READ_DATA);
+ return xway_readb(nand_to_mtd(chip), NAND_READ_DATA);
}
-static void xway_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+static void xway_read_buf(struct nand_chip *chip, u_char *buf, int len)
{
int i;
for (i = 0; i < len; i++)
- buf[i] = xway_readb(mtd, NAND_WRITE_DATA);
+ buf[i] = xway_readb(nand_to_mtd(chip), NAND_WRITE_DATA);
}
-static void xway_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
+static void xway_write_buf(struct nand_chip *chip, const u_char *buf, int len)
{
int i;
for (i = 0; i < len; i++)
- xway_writeb(mtd, NAND_WRITE_DATA, buf[i]);
+ xway_writeb(nand_to_mtd(chip), NAND_WRITE_DATA, buf[i]);
}
/*
@@ -173,13 +174,13 @@ static int xway_nand_probe(struct platform_device *pdev)
mtd = nand_to_mtd(&data->chip);
mtd->dev.parent = &pdev->dev;
- data->chip.cmd_ctrl = xway_cmd_ctrl;
- data->chip.dev_ready = xway_dev_ready;
+ data->chip.legacy.cmd_ctrl = xway_cmd_ctrl;
+ data->chip.legacy.dev_ready = xway_dev_ready;
data->chip.select_chip = xway_select_chip;
- data->chip.write_buf = xway_write_buf;
- data->chip.read_buf = xway_read_buf;
- data->chip.read_byte = xway_read_byte;
- data->chip.chip_delay = 30;
+ data->chip.legacy.write_buf = xway_write_buf;
+ data->chip.legacy.read_buf = xway_read_buf;
+ data->chip.legacy.read_byte = xway_read_byte;
+ data->chip.legacy.chip_delay = 30;
data->chip.ecc.mode = NAND_ECC_SOFT;
data->chip.ecc.algo = NAND_ECC_HAMMING;
@@ -205,13 +206,13 @@ static int xway_nand_probe(struct platform_device *pdev)
| cs_flag, EBU_NAND_CON);
/* Scan to find existence of the device */
- err = nand_scan(mtd, 1);
+ err = nand_scan(&data->chip, 1);
if (err)
return err;
err = mtd_device_register(mtd, NULL, 0);
if (err)
- nand_release(mtd);
+ nand_release(&data->chip);
return err;
}
@@ -223,7 +224,7 @@ static int xway_nand_remove(struct platform_device *pdev)
{
struct xway_nand_data *data = platform_get_drvdata(pdev);
- nand_release(nand_to_mtd(&data->chip));
+ nand_release(&data->chip);
return 0;
}
diff --git a/drivers/mtd/sm_ftl.c b/drivers/mtd/sm_ftl.c
index f3bd86e13603..89227b1d036a 100644
--- a/drivers/mtd/sm_ftl.c
+++ b/drivers/mtd/sm_ftl.c
@@ -221,14 +221,18 @@ static int sm_correct_sector(uint8_t *buffer, struct sm_oob *oob)
{
uint8_t ecc[3];
- __nand_calculate_ecc(buffer, SM_SMALL_PAGE, ecc);
- if (__nand_correct_data(buffer, ecc, oob->ecc1, SM_SMALL_PAGE) < 0)
+ __nand_calculate_ecc(buffer, SM_SMALL_PAGE, ecc,
+ IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC));
+ if (__nand_correct_data(buffer, ecc, oob->ecc1, SM_SMALL_PAGE,
+ IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC)) < 0)
return -EIO;
buffer += SM_SMALL_PAGE;
- __nand_calculate_ecc(buffer, SM_SMALL_PAGE, ecc);
- if (__nand_correct_data(buffer, ecc, oob->ecc2, SM_SMALL_PAGE) < 0)
+ __nand_calculate_ecc(buffer, SM_SMALL_PAGE, ecc,
+ IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC));
+ if (__nand_correct_data(buffer, ecc, oob->ecc2, SM_SMALL_PAGE,
+ IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC)) < 0)
return -EIO;
return 0;
}
@@ -393,11 +397,13 @@ restart:
}
if (ftl->smallpagenand) {
- __nand_calculate_ecc(buf + boffset,
- SM_SMALL_PAGE, oob.ecc1);
+ __nand_calculate_ecc(buf + boffset, SM_SMALL_PAGE,
+ oob.ecc1,
+ IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC));
__nand_calculate_ecc(buf + boffset + SM_SMALL_PAGE,
- SM_SMALL_PAGE, oob.ecc2);
+ SM_SMALL_PAGE, oob.ecc2,
+ IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC));
}
if (!sm_write_sector(ftl, zone, block, boffset,
buf + boffset, &oob))
diff --git a/drivers/mtd/spi-nor/cadence-quadspi.c b/drivers/mtd/spi-nor/cadence-quadspi.c
index 8e714fbfa521..e24db817154e 100644
--- a/drivers/mtd/spi-nor/cadence-quadspi.c
+++ b/drivers/mtd/spi-nor/cadence-quadspi.c
@@ -959,7 +959,7 @@ static int cqspi_direct_read_execute(struct spi_nor *nor, u_char *buf,
return 0;
}
- dma_dst = dma_map_single(nor->dev, buf, len, DMA_DEV_TO_MEM);
+ dma_dst = dma_map_single(nor->dev, buf, len, DMA_FROM_DEVICE);
if (dma_mapping_error(nor->dev, dma_dst)) {
dev_err(nor->dev, "dma mapping failed\n");
return -ENOMEM;
@@ -994,7 +994,7 @@ static int cqspi_direct_read_execute(struct spi_nor *nor, u_char *buf,
}
err_unmap:
- dma_unmap_single(nor->dev, dma_dst, len, DMA_DEV_TO_MEM);
+ dma_unmap_single(nor->dev, dma_dst, len, DMA_FROM_DEVICE);
return 0;
}
diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c
index 7d9620c7ff6c..1ff3430f82c8 100644
--- a/drivers/mtd/spi-nor/fsl-quadspi.c
+++ b/drivers/mtd/spi-nor/fsl-quadspi.c
@@ -478,6 +478,7 @@ static int fsl_qspi_get_seqid(struct fsl_qspi *q, u8 cmd)
{
switch (cmd) {
case SPINOR_OP_READ_1_1_4:
+ case SPINOR_OP_READ_1_1_4_4B:
return SEQID_READ;
case SPINOR_OP_WREN:
return SEQID_WREN;
@@ -543,6 +544,9 @@ fsl_qspi_runcmd(struct fsl_qspi *q, u8 cmd, unsigned int addr, int len)
/* trigger the LUT now */
seqid = fsl_qspi_get_seqid(q, cmd);
+ if (seqid < 0)
+ return seqid;
+
qspi_writel(q, (seqid << QUADSPI_IPCR_SEQID_SHIFT) | len,
base + QUADSPI_IPCR);
@@ -671,7 +675,7 @@ static void fsl_qspi_set_map_addr(struct fsl_qspi *q)
* causes the controller to clear the buffer, and use the sequence pointed
* by the QUADSPI_BFGENCR[SEQID] to initiate a read from the flash.
*/
-static void fsl_qspi_init_ahb_read(struct fsl_qspi *q)
+static int fsl_qspi_init_ahb_read(struct fsl_qspi *q)
{
void __iomem *base = q->iobase;
int seqid;
@@ -696,8 +700,13 @@ static void fsl_qspi_init_ahb_read(struct fsl_qspi *q)
/* Set the default lut sequence for AHB Read. */
seqid = fsl_qspi_get_seqid(q, q->nor[0].read_opcode);
+ if (seqid < 0)
+ return seqid;
+
qspi_writel(q, seqid << QUADSPI_BFGENCR_SEQID_SHIFT,
q->iobase + QUADSPI_BFGENCR);
+
+ return 0;
}
/* This function was used to prepare and enable QSPI clock */
@@ -805,9 +814,7 @@ static int fsl_qspi_nor_setup_last(struct fsl_qspi *q)
fsl_qspi_init_lut(q);
/* Init for AHB read */
- fsl_qspi_init_ahb_read(q);
-
- return 0;
+ return fsl_qspi_init_ahb_read(q);
}
static const struct of_device_id fsl_qspi_dt_ids[] = {
diff --git a/drivers/mtd/spi-nor/intel-spi-pci.c b/drivers/mtd/spi-nor/intel-spi-pci.c
index c0976f2e3dd1..872b40922608 100644
--- a/drivers/mtd/spi-nor/intel-spi-pci.c
+++ b/drivers/mtd/spi-nor/intel-spi-pci.c
@@ -65,6 +65,7 @@ static void intel_spi_pci_remove(struct pci_dev *pdev)
static const struct pci_device_id intel_spi_pci_ids[] = {
{ PCI_VDEVICE(INTEL, 0x18e0), (unsigned long)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x19e0), (unsigned long)&bxt_info },
+ { PCI_VDEVICE(INTEL, 0x34a4), (unsigned long)&bxt_info },
{ PCI_VDEVICE(INTEL, 0xa1a4), (unsigned long)&bxt_info },
{ PCI_VDEVICE(INTEL, 0xa224), (unsigned long)&bxt_info },
{ },
diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index f028277fb1ce..9407ca5f9443 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -18,6 +18,7 @@
#include <linux/math64.h>
#include <linux/sizes.h>
#include <linux/slab.h>
+#include <linux/sort.h>
#include <linux/mtd/mtd.h>
#include <linux/of_platform.h>
@@ -260,6 +261,18 @@ static void spi_nor_set_4byte_opcodes(struct spi_nor *nor,
nor->read_opcode = spi_nor_convert_3to4_read(nor->read_opcode);
nor->program_opcode = spi_nor_convert_3to4_program(nor->program_opcode);
nor->erase_opcode = spi_nor_convert_3to4_erase(nor->erase_opcode);
+
+ if (!spi_nor_has_uniform_erase(nor)) {
+ struct spi_nor_erase_map *map = &nor->erase_map;
+ struct spi_nor_erase_type *erase;
+ int i;
+
+ for (i = 0; i < SNOR_ERASE_TYPE_MAX; i++) {
+ erase = &map->erase_type[i];
+ erase->opcode =
+ spi_nor_convert_3to4_erase(erase->opcode);
+ }
+ }
}
/* Enable/disable 4-byte addressing mode. */
@@ -497,6 +510,277 @@ static int spi_nor_erase_sector(struct spi_nor *nor, u32 addr)
return nor->write_reg(nor, nor->erase_opcode, buf, nor->addr_width);
}
+/**
+ * spi_nor_div_by_erase_size() - calculate remainder and update new dividend
+ * @erase: pointer to a structure that describes a SPI NOR erase type
+ * @dividend: dividend value
+ * @remainder: pointer to u32 remainder (will be updated)
+ *
+ * Return: the result of the division
+ */
+static u64 spi_nor_div_by_erase_size(const struct spi_nor_erase_type *erase,
+ u64 dividend, u32 *remainder)
+{
+ /* JEDEC JESD216B Standard imposes erase sizes to be power of 2. */
+ *remainder = (u32)dividend & erase->size_mask;
+ return dividend >> erase->size_shift;
+}
+
+/**
+ * spi_nor_find_best_erase_type() - find the best erase type for the given
+ * offset in the serial flash memory and the
+ * number of bytes to erase. The region in
+ * which the address fits is expected to be
+ * provided.
+ * @map: the erase map of the SPI NOR
+ * @region: pointer to a structure that describes a SPI NOR erase region
+ * @addr: offset in the serial flash memory
+ * @len: number of bytes to erase
+ *
+ * Return: a pointer to the best fitted erase type, NULL otherwise.
+ */
+static const struct spi_nor_erase_type *
+spi_nor_find_best_erase_type(const struct spi_nor_erase_map *map,
+ const struct spi_nor_erase_region *region,
+ u64 addr, u32 len)
+{
+ const struct spi_nor_erase_type *erase;
+ u32 rem;
+ int i;
+ u8 erase_mask = region->offset & SNOR_ERASE_TYPE_MASK;
+
+ /*
+ * Erase types are ordered by size, with the biggest erase type at
+ * index 0.
+ */
+ for (i = SNOR_ERASE_TYPE_MAX - 1; i >= 0; i--) {
+ /* Does the erase region support the tested erase type? */
+ if (!(erase_mask & BIT(i)))
+ continue;
+
+ erase = &map->erase_type[i];
+
+ /* Don't erase more than what the user has asked for. */
+ if (erase->size > len)
+ continue;
+
+ /* Alignment is not mandatory for overlaid regions */
+ if (region->offset & SNOR_OVERLAID_REGION)
+ return erase;
+
+ spi_nor_div_by_erase_size(erase, addr, &rem);
+ if (rem)
+ continue;
+ else
+ return erase;
+ }
+
+ return NULL;
+}
+
+/**
+ * spi_nor_region_next() - get the next spi nor region
+ * @region: pointer to a structure that describes a SPI NOR erase region
+ *
+ * Return: the next spi nor region or NULL if last region.
+ */
+static struct spi_nor_erase_region *
+spi_nor_region_next(struct spi_nor_erase_region *region)
+{
+ if (spi_nor_region_is_last(region))
+ return NULL;
+ region++;
+ return region;
+}
+
+/**
+ * spi_nor_find_erase_region() - find the region of the serial flash memory in
+ * which the offset fits
+ * @map: the erase map of the SPI NOR
+ * @addr: offset in the serial flash memory
+ *
+ * Return: a pointer to the spi_nor_erase_region struct, ERR_PTR(-errno)
+ * otherwise.
+ */
+static struct spi_nor_erase_region *
+spi_nor_find_erase_region(const struct spi_nor_erase_map *map, u64 addr)
+{
+ struct spi_nor_erase_region *region = map->regions;
+ u64 region_start = region->offset & ~SNOR_ERASE_FLAGS_MASK;
+ u64 region_end = region_start + region->size;
+
+ while (addr < region_start || addr >= region_end) {
+ region = spi_nor_region_next(region);
+ if (!region)
+ return ERR_PTR(-EINVAL);
+
+ region_start = region->offset & ~SNOR_ERASE_FLAGS_MASK;
+ region_end = region_start + region->size;
+ }
+
+ return region;
+}
+
+/**
+ * spi_nor_init_erase_cmd() - initialize an erase command
+ * @region: pointer to a structure that describes a SPI NOR erase region
+ * @erase: pointer to a structure that describes a SPI NOR erase type
+ *
+ * Return: the pointer to the allocated erase command, ERR_PTR(-errno)
+ * otherwise.
+ */
+static struct spi_nor_erase_command *
+spi_nor_init_erase_cmd(const struct spi_nor_erase_region *region,
+ const struct spi_nor_erase_type *erase)
+{
+ struct spi_nor_erase_command *cmd;
+
+ cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd)
+ return ERR_PTR(-ENOMEM);
+
+ INIT_LIST_HEAD(&cmd->list);
+ cmd->opcode = erase->opcode;
+ cmd->count = 1;
+
+ if (region->offset & SNOR_OVERLAID_REGION)
+ cmd->size = region->size;
+ else
+ cmd->size = erase->size;
+
+ return cmd;
+}
+
+/**
+ * spi_nor_destroy_erase_cmd_list() - destroy erase command list
+ * @erase_list: list of erase commands
+ */
+static void spi_nor_destroy_erase_cmd_list(struct list_head *erase_list)
+{
+ struct spi_nor_erase_command *cmd, *next;
+
+ list_for_each_entry_safe(cmd, next, erase_list, list) {
+ list_del(&cmd->list);
+ kfree(cmd);
+ }
+}
+
+/**
+ * spi_nor_init_erase_cmd_list() - initialize erase command list
+ * @nor: pointer to a 'struct spi_nor'
+ * @erase_list: list of erase commands to be executed once we validate that the
+ * erase can be performed
+ * @addr: offset in the serial flash memory
+ * @len: number of bytes to erase
+ *
+ * Builds the list of best fitted erase commands and verifies if the erase can
+ * be performed.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int spi_nor_init_erase_cmd_list(struct spi_nor *nor,
+ struct list_head *erase_list,
+ u64 addr, u32 len)
+{
+ const struct spi_nor_erase_map *map = &nor->erase_map;
+ const struct spi_nor_erase_type *erase, *prev_erase = NULL;
+ struct spi_nor_erase_region *region;
+ struct spi_nor_erase_command *cmd = NULL;
+ u64 region_end;
+ int ret = -EINVAL;
+
+ region = spi_nor_find_erase_region(map, addr);
+ if (IS_ERR(region))
+ return PTR_ERR(region);
+
+ region_end = spi_nor_region_end(region);
+
+ while (len) {
+ erase = spi_nor_find_best_erase_type(map, region, addr, len);
+ if (!erase)
+ goto destroy_erase_cmd_list;
+
+ if (prev_erase != erase ||
+ region->offset & SNOR_OVERLAID_REGION) {
+ cmd = spi_nor_init_erase_cmd(region, erase);
+ if (IS_ERR(cmd)) {
+ ret = PTR_ERR(cmd);
+ goto destroy_erase_cmd_list;
+ }
+
+ list_add_tail(&cmd->list, erase_list);
+ } else {
+ cmd->count++;
+ }
+
+ addr += cmd->size;
+ len -= cmd->size;
+
+ if (len && addr >= region_end) {
+ region = spi_nor_region_next(region);
+ if (!region)
+ goto destroy_erase_cmd_list;
+ region_end = spi_nor_region_end(region);
+ }
+
+ prev_erase = erase;
+ }
+
+ return 0;
+
+destroy_erase_cmd_list:
+ spi_nor_destroy_erase_cmd_list(erase_list);
+ return ret;
+}
+
+/**
+ * spi_nor_erase_multi_sectors() - perform a non-uniform erase
+ * @nor: pointer to a 'struct spi_nor'
+ * @addr: offset in the serial flash memory
+ * @len: number of bytes to erase
+ *
+ * Build a list of best fitted erase commands and execute it once we validate
+ * that the erase can be performed.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int spi_nor_erase_multi_sectors(struct spi_nor *nor, u64 addr, u32 len)
+{
+ LIST_HEAD(erase_list);
+ struct spi_nor_erase_command *cmd, *next;
+ int ret;
+
+ ret = spi_nor_init_erase_cmd_list(nor, &erase_list, addr, len);
+ if (ret)
+ return ret;
+
+ list_for_each_entry_safe(cmd, next, &erase_list, list) {
+ nor->erase_opcode = cmd->opcode;
+ while (cmd->count) {
+ write_enable(nor);
+
+ ret = spi_nor_erase_sector(nor, addr);
+ if (ret)
+ goto destroy_erase_cmd_list;
+
+ addr += cmd->size;
+ cmd->count--;
+
+ ret = spi_nor_wait_till_ready(nor);
+ if (ret)
+ goto destroy_erase_cmd_list;
+ }
+ list_del(&cmd->list);
+ kfree(cmd);
+ }
+
+ return 0;
+
+destroy_erase_cmd_list:
+ spi_nor_destroy_erase_cmd_list(&erase_list);
+ return ret;
+}
+
/*
* Erase an address range on the nor chip. The address range may extend
* one or more erase sectors. Return an error is there is a problem erasing.
@@ -511,9 +795,11 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
dev_dbg(nor->dev, "at 0x%llx, len %lld\n", (long long)instr->addr,
(long long)instr->len);
- div_u64_rem(instr->len, mtd->erasesize, &rem);
- if (rem)
- return -EINVAL;
+ if (spi_nor_has_uniform_erase(nor)) {
+ div_u64_rem(instr->len, mtd->erasesize, &rem);
+ if (rem)
+ return -EINVAL;
+ }
addr = instr->addr;
len = instr->len;
@@ -552,7 +838,7 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
*/
/* "sector"-at-a-time erase */
- } else {
+ } else if (spi_nor_has_uniform_erase(nor)) {
while (len) {
write_enable(nor);
@@ -567,6 +853,12 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
if (ret)
goto erase_err;
}
+
+ /* erase multiple sectors */
+ } else {
+ ret = spi_nor_erase_multi_sectors(nor, addr, len);
+ if (ret)
+ goto erase_err;
}
write_disable(nor);
@@ -1464,13 +1756,6 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
goto write_err;
*retlen += written;
i += written;
- if (written != page_remain) {
- dev_err(nor->dev,
- "While writing %zu bytes written %zd bytes\n",
- page_remain, written);
- ret = -EIO;
- goto write_err;
- }
}
write_err:
@@ -1864,6 +2149,36 @@ spi_nor_set_pp_settings(struct spi_nor_pp_command *pp,
*/
/**
+ * spi_nor_read_raw() - raw read of serial flash memory. read_opcode,
+ * addr_width and read_dummy members of the struct spi_nor
+ * should be previously
+ * set.
+ * @nor: pointer to a 'struct spi_nor'
+ * @addr: offset in the serial flash memory
+ * @len: number of bytes to read
+ * @buf: buffer where the data is copied into
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int spi_nor_read_raw(struct spi_nor *nor, u32 addr, size_t len, u8 *buf)
+{
+ int ret;
+
+ while (len) {
+ ret = nor->read(nor, addr, len, buf);
+ if (!ret || ret > len)
+ return -EIO;
+ if (ret < 0)
+ return ret;
+
+ buf += ret;
+ addr += ret;
+ len -= ret;
+ }
+ return 0;
+}
+
+/**
* spi_nor_read_sfdp() - read Serial Flash Discoverable Parameters.
* @nor: pointer to a 'struct spi_nor'
* @addr: offset in the SFDP area to start reading data from
@@ -1890,22 +2205,8 @@ static int spi_nor_read_sfdp(struct spi_nor *nor, u32 addr,
nor->addr_width = 3;
nor->read_dummy = 8;
- while (len) {
- ret = nor->read(nor, addr, len, (u8 *)buf);
- if (!ret || ret > len) {
- ret = -EIO;
- goto read_err;
- }
- if (ret < 0)
- goto read_err;
-
- buf += ret;
- addr += ret;
- len -= ret;
- }
- ret = 0;
+ ret = spi_nor_read_raw(nor, addr, len, buf);
-read_err:
nor->read_opcode = read_opcode;
nor->addr_width = addr_width;
nor->read_dummy = read_dummy;
@@ -2166,6 +2467,116 @@ static const struct sfdp_bfpt_erase sfdp_bfpt_erases[] = {
static int spi_nor_hwcaps_read2cmd(u32 hwcaps);
/**
+ * spi_nor_set_erase_type() - set a SPI NOR erase type
+ * @erase: pointer to a structure that describes a SPI NOR erase type
+ * @size: the size of the sector/block erased by the erase type
+ * @opcode: the SPI command op code to erase the sector/block
+ */
+static void spi_nor_set_erase_type(struct spi_nor_erase_type *erase,
+ u32 size, u8 opcode)
+{
+ erase->size = size;
+ erase->opcode = opcode;
+ /* JEDEC JESD216B Standard imposes erase sizes to be power of 2. */
+ erase->size_shift = ffs(erase->size) - 1;
+ erase->size_mask = (1 << erase->size_shift) - 1;
+}
+
+/**
+ * spi_nor_set_erase_settings_from_bfpt() - set erase type settings from BFPT
+ * @erase: pointer to a structure that describes a SPI NOR erase type
+ * @size: the size of the sector/block erased by the erase type
+ * @opcode: the SPI command op code to erase the sector/block
+ * @i: erase type index as sorted in the Basic Flash Parameter Table
+ *
+ * The supported Erase Types will be sorted at init in ascending order, with
+ * the smallest Erase Type size being the first member in the erase_type array
+ * of the spi_nor_erase_map structure. Save the Erase Type index as sorted in
+ * the Basic Flash Parameter Table since it will be used later on to
+ * synchronize with the supported Erase Types defined in SFDP optional tables.
+ */
+static void
+spi_nor_set_erase_settings_from_bfpt(struct spi_nor_erase_type *erase,
+ u32 size, u8 opcode, u8 i)
+{
+ erase->idx = i;
+ spi_nor_set_erase_type(erase, size, opcode);
+}
+
+/**
+ * spi_nor_map_cmp_erase_type() - compare the map's erase types by size
+ * @l: member in the left half of the map's erase_type array
+ * @r: member in the right half of the map's erase_type array
+ *
+ * Comparison function used in the sort() call to sort in ascending order the
+ * map's erase types, the smallest erase type size being the first member in the
+ * sorted erase_type array.
+ *
+ * Return: the result of @l->size - @r->size
+ */
+static int spi_nor_map_cmp_erase_type(const void *l, const void *r)
+{
+ const struct spi_nor_erase_type *left = l, *right = r;
+
+ return left->size - right->size;
+}
+
+/**
+ * spi_nor_regions_sort_erase_types() - sort erase types in each region
+ * @map: the erase map of the SPI NOR
+ *
+ * Function assumes that the erase types defined in the erase map are already
+ * sorted in ascending order, with the smallest erase type size being the first
+ * member in the erase_type array. It replicates the sort done for the map's
+ * erase types. Each region's erase bitmask will indicate which erase types are
+ * supported from the sorted erase types defined in the erase map.
+ * Sort the all region's erase type at init in order to speed up the process of
+ * finding the best erase command at runtime.
+ */
+static void spi_nor_regions_sort_erase_types(struct spi_nor_erase_map *map)
+{
+ struct spi_nor_erase_region *region = map->regions;
+ struct spi_nor_erase_type *erase_type = map->erase_type;
+ int i;
+ u8 region_erase_mask, sorted_erase_mask;
+
+ while (region) {
+ region_erase_mask = region->offset & SNOR_ERASE_TYPE_MASK;
+
+ /* Replicate the sort done for the map's erase types. */
+ sorted_erase_mask = 0;
+ for (i = 0; i < SNOR_ERASE_TYPE_MAX; i++)
+ if (erase_type[i].size &&
+ region_erase_mask & BIT(erase_type[i].idx))
+ sorted_erase_mask |= BIT(i);
+
+ /* Overwrite erase mask. */
+ region->offset = (region->offset & ~SNOR_ERASE_TYPE_MASK) |
+ sorted_erase_mask;
+
+ region = spi_nor_region_next(region);
+ }
+}
+
+/**
+ * spi_nor_init_uniform_erase_map() - Initialize uniform erase map
+ * @map: the erase map of the SPI NOR
+ * @erase_mask: bitmask encoding erase types that can erase the entire
+ * flash memory
+ * @flash_size: the spi nor flash memory size
+ */
+static void spi_nor_init_uniform_erase_map(struct spi_nor_erase_map *map,
+ u8 erase_mask, u64 flash_size)
+{
+ /* Offset 0 with erase_mask and SNOR_LAST_REGION bit set */
+ map->uniform_region.offset = (erase_mask & SNOR_ERASE_TYPE_MASK) |
+ SNOR_LAST_REGION;
+ map->uniform_region.size = flash_size;
+ map->regions = &map->uniform_region;
+ map->uniform_erase_type = erase_mask;
+}
+
+/**
* spi_nor_parse_bfpt() - read and parse the Basic Flash Parameter Table.
* @nor: pointer to a 'struct spi_nor'
* @bfpt_header: pointer to the 'struct sfdp_parameter_header' describing
@@ -2199,12 +2610,14 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
const struct sfdp_parameter_header *bfpt_header,
struct spi_nor_flash_parameter *params)
{
- struct mtd_info *mtd = &nor->mtd;
+ struct spi_nor_erase_map *map = &nor->erase_map;
+ struct spi_nor_erase_type *erase_type = map->erase_type;
struct sfdp_bfpt bfpt;
size_t len;
int i, cmd, err;
u32 addr;
u16 half;
+ u8 erase_mask;
/* JESD216 Basic Flash Parameter Table length is at least 9 DWORDs. */
if (bfpt_header->length < BFPT_DWORD_MAX_JESD216)
@@ -2273,7 +2686,12 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
spi_nor_set_read_settings_from_bfpt(read, half, rd->proto);
}
- /* Sector Erase settings. */
+ /*
+ * Sector Erase settings. Reinitialize the uniform erase map using the
+ * Erase Types defined in the bfpt table.
+ */
+ erase_mask = 0;
+ memset(&nor->erase_map, 0, sizeof(nor->erase_map));
for (i = 0; i < ARRAY_SIZE(sfdp_bfpt_erases); i++) {
const struct sfdp_bfpt_erase *er = &sfdp_bfpt_erases[i];
u32 erasesize;
@@ -2288,18 +2706,25 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
erasesize = 1U << erasesize;
opcode = (half >> 8) & 0xff;
-#ifdef CONFIG_MTD_SPI_NOR_USE_4K_SECTORS
- if (erasesize == SZ_4K) {
- nor->erase_opcode = opcode;
- mtd->erasesize = erasesize;
- break;
- }
-#endif
- if (!mtd->erasesize || mtd->erasesize < erasesize) {
- nor->erase_opcode = opcode;
- mtd->erasesize = erasesize;
- }
+ erase_mask |= BIT(i);
+ spi_nor_set_erase_settings_from_bfpt(&erase_type[i], erasesize,
+ opcode, i);
}
+ spi_nor_init_uniform_erase_map(map, erase_mask, params->size);
+ /*
+ * Sort all the map's Erase Types in ascending order with the smallest
+ * erase size being the first member in the erase_type array.
+ */
+ sort(erase_type, SNOR_ERASE_TYPE_MAX, sizeof(erase_type[0]),
+ spi_nor_map_cmp_erase_type, NULL);
+ /*
+ * Sort the erase types in the uniform region in order to update the
+ * uniform_erase_type bitmask. The bitmask will be used later on when
+ * selecting the uniform erase.
+ */
+ spi_nor_regions_sort_erase_types(map);
+ map->uniform_erase_type = map->uniform_region.offset &
+ SNOR_ERASE_TYPE_MASK;
/* Stop here if not JESD216 rev A or later. */
if (bfpt_header->length < BFPT_DWORD_MAX)
@@ -2341,6 +2766,277 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
return 0;
}
+#define SMPT_CMD_ADDRESS_LEN_MASK GENMASK(23, 22)
+#define SMPT_CMD_ADDRESS_LEN_0 (0x0UL << 22)
+#define SMPT_CMD_ADDRESS_LEN_3 (0x1UL << 22)
+#define SMPT_CMD_ADDRESS_LEN_4 (0x2UL << 22)
+#define SMPT_CMD_ADDRESS_LEN_USE_CURRENT (0x3UL << 22)
+
+#define SMPT_CMD_READ_DUMMY_MASK GENMASK(19, 16)
+#define SMPT_CMD_READ_DUMMY_SHIFT 16
+#define SMPT_CMD_READ_DUMMY(_cmd) \
+ (((_cmd) & SMPT_CMD_READ_DUMMY_MASK) >> SMPT_CMD_READ_DUMMY_SHIFT)
+#define SMPT_CMD_READ_DUMMY_IS_VARIABLE 0xfUL
+
+#define SMPT_CMD_READ_DATA_MASK GENMASK(31, 24)
+#define SMPT_CMD_READ_DATA_SHIFT 24
+#define SMPT_CMD_READ_DATA(_cmd) \
+ (((_cmd) & SMPT_CMD_READ_DATA_MASK) >> SMPT_CMD_READ_DATA_SHIFT)
+
+#define SMPT_CMD_OPCODE_MASK GENMASK(15, 8)
+#define SMPT_CMD_OPCODE_SHIFT 8
+#define SMPT_CMD_OPCODE(_cmd) \
+ (((_cmd) & SMPT_CMD_OPCODE_MASK) >> SMPT_CMD_OPCODE_SHIFT)
+
+#define SMPT_MAP_REGION_COUNT_MASK GENMASK(23, 16)
+#define SMPT_MAP_REGION_COUNT_SHIFT 16
+#define SMPT_MAP_REGION_COUNT(_header) \
+ ((((_header) & SMPT_MAP_REGION_COUNT_MASK) >> \
+ SMPT_MAP_REGION_COUNT_SHIFT) + 1)
+
+#define SMPT_MAP_ID_MASK GENMASK(15, 8)
+#define SMPT_MAP_ID_SHIFT 8
+#define SMPT_MAP_ID(_header) \
+ (((_header) & SMPT_MAP_ID_MASK) >> SMPT_MAP_ID_SHIFT)
+
+#define SMPT_MAP_REGION_SIZE_MASK GENMASK(31, 8)
+#define SMPT_MAP_REGION_SIZE_SHIFT 8
+#define SMPT_MAP_REGION_SIZE(_region) \
+ (((((_region) & SMPT_MAP_REGION_SIZE_MASK) >> \
+ SMPT_MAP_REGION_SIZE_SHIFT) + 1) * 256)
+
+#define SMPT_MAP_REGION_ERASE_TYPE_MASK GENMASK(3, 0)
+#define SMPT_MAP_REGION_ERASE_TYPE(_region) \
+ ((_region) & SMPT_MAP_REGION_ERASE_TYPE_MASK)
+
+#define SMPT_DESC_TYPE_MAP BIT(1)
+#define SMPT_DESC_END BIT(0)
+
+/**
+ * spi_nor_smpt_addr_width() - return the address width used in the
+ * configuration detection command.
+ * @nor: pointer to a 'struct spi_nor'
+ * @settings: configuration detection command descriptor, dword1
+ */
+static u8 spi_nor_smpt_addr_width(const struct spi_nor *nor, const u32 settings)
+{
+ switch (settings & SMPT_CMD_ADDRESS_LEN_MASK) {
+ case SMPT_CMD_ADDRESS_LEN_0:
+ return 0;
+ case SMPT_CMD_ADDRESS_LEN_3:
+ return 3;
+ case SMPT_CMD_ADDRESS_LEN_4:
+ return 4;
+ case SMPT_CMD_ADDRESS_LEN_USE_CURRENT:
+ /* fall through */
+ default:
+ return nor->addr_width;
+ }
+}
+
+/**
+ * spi_nor_smpt_read_dummy() - return the configuration detection command read
+ * latency, in clock cycles.
+ * @nor: pointer to a 'struct spi_nor'
+ * @settings: configuration detection command descriptor, dword1
+ *
+ * Return: the number of dummy cycles for an SMPT read
+ */
+static u8 spi_nor_smpt_read_dummy(const struct spi_nor *nor, const u32 settings)
+{
+ u8 read_dummy = SMPT_CMD_READ_DUMMY(settings);
+
+ if (read_dummy == SMPT_CMD_READ_DUMMY_IS_VARIABLE)
+ return nor->read_dummy;
+ return read_dummy;
+}
+
+/**
+ * spi_nor_get_map_in_use() - get the configuration map in use
+ * @nor: pointer to a 'struct spi_nor'
+ * @smpt: pointer to the sector map parameter table
+ */
+static const u32 *spi_nor_get_map_in_use(struct spi_nor *nor, const u32 *smpt)
+{
+ const u32 *ret = NULL;
+ u32 i, addr;
+ int err;
+ u8 addr_width, read_opcode, read_dummy;
+ u8 read_data_mask, data_byte, map_id;
+
+ addr_width = nor->addr_width;
+ read_dummy = nor->read_dummy;
+ read_opcode = nor->read_opcode;
+
+ map_id = 0;
+ i = 0;
+ /* Determine if there are any optional Detection Command Descriptors */
+ while (!(smpt[i] & SMPT_DESC_TYPE_MAP)) {
+ read_data_mask = SMPT_CMD_READ_DATA(smpt[i]);
+ nor->addr_width = spi_nor_smpt_addr_width(nor, smpt[i]);
+ nor->read_dummy = spi_nor_smpt_read_dummy(nor, smpt[i]);
+ nor->read_opcode = SMPT_CMD_OPCODE(smpt[i]);
+ addr = smpt[i + 1];
+
+ err = spi_nor_read_raw(nor, addr, 1, &data_byte);
+ if (err)
+ goto out;
+
+ /*
+ * Build an index value that is used to select the Sector Map
+ * Configuration that is currently in use.
+ */
+ map_id = map_id << 1 | !!(data_byte & read_data_mask);
+ i = i + 2;
+ }
+
+ /* Find the matching configuration map */
+ while (SMPT_MAP_ID(smpt[i]) != map_id) {
+ if (smpt[i] & SMPT_DESC_END)
+ goto out;
+ /* increment the table index to the next map */
+ i += SMPT_MAP_REGION_COUNT(smpt[i]) + 1;
+ }
+
+ ret = smpt + i;
+ /* fall through */
+out:
+ nor->addr_width = addr_width;
+ nor->read_dummy = read_dummy;
+ nor->read_opcode = read_opcode;
+ return ret;
+}
+
+/**
+ * spi_nor_region_check_overlay() - set overlay bit when the region is overlaid
+ * @region: pointer to a structure that describes a SPI NOR erase region
+ * @erase: pointer to a structure that describes a SPI NOR erase type
+ * @erase_type: erase type bitmask
+ */
+static void
+spi_nor_region_check_overlay(struct spi_nor_erase_region *region,
+ const struct spi_nor_erase_type *erase,
+ const u8 erase_type)
+{
+ int i;
+
+ for (i = 0; i < SNOR_ERASE_TYPE_MAX; i++) {
+ if (!(erase_type & BIT(i)))
+ continue;
+ if (region->size & erase[i].size_mask) {
+ spi_nor_region_mark_overlay(region);
+ return;
+ }
+ }
+}
+
+/**
+ * spi_nor_init_non_uniform_erase_map() - initialize the non-uniform erase map
+ * @nor: pointer to a 'struct spi_nor'
+ * @smpt: pointer to the sector map parameter table
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int spi_nor_init_non_uniform_erase_map(struct spi_nor *nor,
+ const u32 *smpt)
+{
+ struct spi_nor_erase_map *map = &nor->erase_map;
+ const struct spi_nor_erase_type *erase = map->erase_type;
+ struct spi_nor_erase_region *region;
+ u64 offset;
+ u32 region_count;
+ int i, j;
+ u8 erase_type;
+
+ region_count = SMPT_MAP_REGION_COUNT(*smpt);
+ /*
+ * The regions will be freed when the driver detaches from the
+ * device.
+ */
+ region = devm_kcalloc(nor->dev, region_count, sizeof(*region),
+ GFP_KERNEL);
+ if (!region)
+ return -ENOMEM;
+ map->regions = region;
+
+ map->uniform_erase_type = 0xff;
+ offset = 0;
+ /* Populate regions. */
+ for (i = 0; i < region_count; i++) {
+ j = i + 1; /* index for the region dword */
+ region[i].size = SMPT_MAP_REGION_SIZE(smpt[j]);
+ erase_type = SMPT_MAP_REGION_ERASE_TYPE(smpt[j]);
+ region[i].offset = offset | erase_type;
+
+ spi_nor_region_check_overlay(&region[i], erase, erase_type);
+
+ /*
+ * Save the erase types that are supported in all regions and
+ * can erase the entire flash memory.
+ */
+ map->uniform_erase_type &= erase_type;
+
+ offset = (region[i].offset & ~SNOR_ERASE_FLAGS_MASK) +
+ region[i].size;
+ }
+
+ spi_nor_region_mark_end(&region[i - 1]);
+
+ return 0;
+}
+
+/**
+ * spi_nor_parse_smpt() - parse Sector Map Parameter Table
+ * @nor: pointer to a 'struct spi_nor'
+ * @smpt_header: sector map parameter table header
+ *
+ * This table is optional, but when available, we parse it to identify the
+ * location and size of sectors within the main data array of the flash memory
+ * device and to identify which Erase Types are supported by each sector.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int spi_nor_parse_smpt(struct spi_nor *nor,
+ const struct sfdp_parameter_header *smpt_header)
+{
+ const u32 *sector_map;
+ u32 *smpt;
+ size_t len;
+ u32 addr;
+ int i, ret;
+
+ /* Read the Sector Map Parameter Table. */
+ len = smpt_header->length * sizeof(*smpt);
+ smpt = kzalloc(len, GFP_KERNEL);
+ if (!smpt)
+ return -ENOMEM;
+
+ addr = SFDP_PARAM_HEADER_PTP(smpt_header);
+ ret = spi_nor_read_sfdp(nor, addr, len, smpt);
+ if (ret)
+ goto out;
+
+ /* Fix endianness of the SMPT DWORDs. */
+ for (i = 0; i < smpt_header->length; i++)
+ smpt[i] = le32_to_cpu(smpt[i]);
+
+ sector_map = spi_nor_get_map_in_use(nor, smpt);
+ if (!sector_map) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = spi_nor_init_non_uniform_erase_map(nor, sector_map);
+ if (ret)
+ goto out;
+
+ spi_nor_regions_sort_erase_types(&nor->erase_map);
+ /* fall through */
+out:
+ kfree(smpt);
+ return ret;
+}
+
/**
* spi_nor_parse_sfdp() - parse the Serial Flash Discoverable Parameters.
* @nor: pointer to a 'struct spi_nor'
@@ -2435,7 +3131,7 @@ static int spi_nor_parse_sfdp(struct spi_nor *nor,
switch (SFDP_PARAM_HEADER_ID(param_header)) {
case SFDP_SECTOR_MAP_ID:
- dev_info(dev, "non-uniform erase sector maps are not supported yet.\n");
+ err = spi_nor_parse_smpt(nor, param_header);
break;
default:
@@ -2455,6 +3151,9 @@ static int spi_nor_init_params(struct spi_nor *nor,
const struct flash_info *info,
struct spi_nor_flash_parameter *params)
{
+ struct spi_nor_erase_map *map = &nor->erase_map;
+ u8 i, erase_mask;
+
/* Set legacy flash parameters as default. */
memset(params, 0, sizeof(*params));
@@ -2494,6 +3193,28 @@ static int spi_nor_init_params(struct spi_nor *nor,
spi_nor_set_pp_settings(&params->page_programs[SNOR_CMD_PP],
SPINOR_OP_PP, SNOR_PROTO_1_1_1);
+ /*
+ * Sector Erase settings. Sort Erase Types in ascending order, with the
+ * smallest erase size starting at BIT(0).
+ */
+ erase_mask = 0;
+ i = 0;
+ if (info->flags & SECT_4K_PMC) {
+ erase_mask |= BIT(i);
+ spi_nor_set_erase_type(&map->erase_type[i], 4096u,
+ SPINOR_OP_BE_4K_PMC);
+ i++;
+ } else if (info->flags & SECT_4K) {
+ erase_mask |= BIT(i);
+ spi_nor_set_erase_type(&map->erase_type[i], 4096u,
+ SPINOR_OP_BE_4K);
+ i++;
+ }
+ erase_mask |= BIT(i);
+ spi_nor_set_erase_type(&map->erase_type[i], info->sector_size,
+ SPINOR_OP_SE);
+ spi_nor_init_uniform_erase_map(map, erase_mask, params->size);
+
/* Select the procedure to set the Quad Enable bit. */
if (params->hwcaps.mask & (SNOR_HWCAPS_READ_QUAD |
SNOR_HWCAPS_PP_QUAD)) {
@@ -2521,20 +3242,20 @@ static int spi_nor_init_params(struct spi_nor *nor,
params->quad_enable = info->quad_enable;
}
- /* Override the parameters with data read from SFDP tables. */
- nor->addr_width = 0;
- nor->mtd.erasesize = 0;
if ((info->flags & (SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)) &&
!(info->flags & SPI_NOR_SKIP_SFDP)) {
struct spi_nor_flash_parameter sfdp_params;
+ struct spi_nor_erase_map prev_map;
memcpy(&sfdp_params, params, sizeof(sfdp_params));
- if (spi_nor_parse_sfdp(nor, &sfdp_params)) {
- nor->addr_width = 0;
- nor->mtd.erasesize = 0;
- } else {
+ memcpy(&prev_map, &nor->erase_map, sizeof(prev_map));
+
+ if (spi_nor_parse_sfdp(nor, &sfdp_params))
+ /* restore previous erase map */
+ memcpy(&nor->erase_map, &prev_map,
+ sizeof(nor->erase_map));
+ else
memcpy(params, &sfdp_params, sizeof(*params));
- }
}
return 0;
@@ -2643,29 +3364,103 @@ static int spi_nor_select_pp(struct spi_nor *nor,
return 0;
}
-static int spi_nor_select_erase(struct spi_nor *nor,
- const struct flash_info *info)
+/**
+ * spi_nor_select_uniform_erase() - select optimum uniform erase type
+ * @map: the erase map of the SPI NOR
+ * @wanted_size: the erase type size to search for. Contains the value of
+ * info->sector_size or of the "small sector" size in case
+ * CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is defined.
+ *
+ * Once the optimum uniform sector erase command is found, disable all the
+ * other.
+ *
+ * Return: pointer to erase type on success, NULL otherwise.
+ */
+static const struct spi_nor_erase_type *
+spi_nor_select_uniform_erase(struct spi_nor_erase_map *map,
+ const u32 wanted_size)
{
- struct mtd_info *mtd = &nor->mtd;
+ const struct spi_nor_erase_type *tested_erase, *erase = NULL;
+ int i;
+ u8 uniform_erase_type = map->uniform_erase_type;
- /* Do nothing if already configured from SFDP. */
- if (mtd->erasesize)
- return 0;
+ for (i = SNOR_ERASE_TYPE_MAX - 1; i >= 0; i--) {
+ if (!(uniform_erase_type & BIT(i)))
+ continue;
+
+ tested_erase = &map->erase_type[i];
+
+ /*
+ * If the current erase size is the one, stop here:
+ * we have found the right uniform Sector Erase command.
+ */
+ if (tested_erase->size == wanted_size) {
+ erase = tested_erase;
+ break;
+ }
+
+ /*
+ * Otherwise, the current erase size is still a valid canditate.
+ * Select the biggest valid candidate.
+ */
+ if (!erase && tested_erase->size)
+ erase = tested_erase;
+ /* keep iterating to find the wanted_size */
+ }
+
+ if (!erase)
+ return NULL;
+ /* Disable all other Sector Erase commands. */
+ map->uniform_erase_type &= ~SNOR_ERASE_TYPE_MASK;
+ map->uniform_erase_type |= BIT(erase - map->erase_type);
+ return erase;
+}
+
+static int spi_nor_select_erase(struct spi_nor *nor, u32 wanted_size)
+{
+ struct spi_nor_erase_map *map = &nor->erase_map;
+ const struct spi_nor_erase_type *erase = NULL;
+ struct mtd_info *mtd = &nor->mtd;
+ int i;
+
+ /*
+ * The previous implementation handling Sector Erase commands assumed
+ * that the SPI flash memory has an uniform layout then used only one
+ * of the supported erase sizes for all Sector Erase commands.
+ * So to be backward compatible, the new implementation also tries to
+ * manage the SPI flash memory as uniform with a single erase sector
+ * size, when possible.
+ */
#ifdef CONFIG_MTD_SPI_NOR_USE_4K_SECTORS
/* prefer "small sector" erase if possible */
- if (info->flags & SECT_4K) {
- nor->erase_opcode = SPINOR_OP_BE_4K;
- mtd->erasesize = 4096;
- } else if (info->flags & SECT_4K_PMC) {
- nor->erase_opcode = SPINOR_OP_BE_4K_PMC;
- mtd->erasesize = 4096;
- } else
+ wanted_size = 4096u;
#endif
- {
- nor->erase_opcode = SPINOR_OP_SE;
- mtd->erasesize = info->sector_size;
+
+ if (spi_nor_has_uniform_erase(nor)) {
+ erase = spi_nor_select_uniform_erase(map, wanted_size);
+ if (!erase)
+ return -EINVAL;
+ nor->erase_opcode = erase->opcode;
+ mtd->erasesize = erase->size;
+ return 0;
}
+
+ /*
+ * For non-uniform SPI flash memory, set mtd->erasesize to the
+ * maximum erase sector size. No need to set nor->erase_opcode.
+ */
+ for (i = SNOR_ERASE_TYPE_MAX - 1; i >= 0; i--) {
+ if (map->erase_type[i].size) {
+ erase = &map->erase_type[i];
+ break;
+ }
+ }
+
+ if (!erase)
+ return -EINVAL;
+
+ mtd->erasesize = erase->size;
return 0;
}
@@ -2712,7 +3507,7 @@ static int spi_nor_setup(struct spi_nor *nor, const struct flash_info *info,
}
/* Select the Sector Erase command. */
- err = spi_nor_select_erase(nor, info);
+ err = spi_nor_select_erase(nor, info->sector_size);
if (err) {
dev_err(nor->dev,
"can't select erase settings supported by both the SPI controller and memory.\n");
diff --git a/drivers/mtd/tests/mtd_nandecctest.c b/drivers/mtd/tests/mtd_nandecctest.c
index 88b6c81cebbe..c71523e94580 100644
--- a/drivers/mtd/tests/mtd_nandecctest.c
+++ b/drivers/mtd/tests/mtd_nandecctest.c
@@ -121,8 +121,10 @@ static int no_bit_error_verify(void *error_data, void *error_ecc,
unsigned char calc_ecc[3];
int ret;
- __nand_calculate_ecc(error_data, size, calc_ecc);
- ret = __nand_correct_data(error_data, error_ecc, calc_ecc, size);
+ __nand_calculate_ecc(error_data, size, calc_ecc,
+ IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC));
+ ret = __nand_correct_data(error_data, error_ecc, calc_ecc, size,
+ IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC));
if (ret == 0 && !memcmp(correct_data, error_data, size))
return 0;
@@ -149,8 +151,10 @@ static int single_bit_error_correct(void *error_data, void *error_ecc,
unsigned char calc_ecc[3];
int ret;
- __nand_calculate_ecc(error_data, size, calc_ecc);
- ret = __nand_correct_data(error_data, error_ecc, calc_ecc, size);
+ __nand_calculate_ecc(error_data, size, calc_ecc,
+ IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC));
+ ret = __nand_correct_data(error_data, error_ecc, calc_ecc, size,
+ IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC));
if (ret == 1 && !memcmp(correct_data, error_data, size))
return 0;
@@ -184,8 +188,10 @@ static int double_bit_error_detect(void *error_data, void *error_ecc,
unsigned char calc_ecc[3];
int ret;
- __nand_calculate_ecc(error_data, size, calc_ecc);
- ret = __nand_correct_data(error_data, error_ecc, calc_ecc, size);
+ __nand_calculate_ecc(error_data, size, calc_ecc,
+ IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC));
+ ret = __nand_correct_data(error_data, error_ecc, calc_ecc, size,
+ IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC));
return (ret == -EBADMSG) ? 0 : -EINVAL;
}
@@ -259,7 +265,8 @@ static int nand_ecc_test_run(const size_t size)
}
prandom_bytes(correct_data, size);
- __nand_calculate_ecc(correct_data, size, correct_ecc);
+ __nand_calculate_ecc(correct_data, size, correct_ecc,
+ IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC));
for (i = 0; i < ARRAY_SIZE(nand_ecc_test); i++) {
nand_ecc_test[i].prepare(error_data, error_ecc,