mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 22:21:40 +00:00
MTD updates for 3.18
NAND * Cleanup for Denali driver * Atmel: add support for new page sizes * Atmel: fix up 'raw' mode support * Atmel: miscellaneous cleanups * New timing mode helpers for non-ONFI NAND * OMAP: allow driver to be (properly) built as a module * bcm47xx: RESET support and other cleanups SPI NOR * Miscellaneous cleanups, to prepare framework for wider use (some further work still pending) * Compile-time configuration to select 4K vs. 64K support for flash that support both (necessary for using UBIFS on some SPI NOR) A few scattered code quality fixes, detected by Coverity See the changesets for more. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJUP2dfAAoJEFySrpd9RFgtiUYQAKHmzTw4UR5lZNwBHLPIk5mV d11If+kGwY5wVTG0f7+d0RxXWQLP11LnWn7S9JK3ttvuc5L8ev4jCjtbR6aRQZgy 6vdqqvOv/kqP+Q4FclVIdEPzEgLurg4zCuVoDaMkhIKkdmrcw3inWSt7F+/2dJYb OAPRoOSv8hnmQheH85v8zpHrovcYLY9tGoSlv0Yu8pKapyp7LT2E/wPaXh16VjZG A8Qr6NsSZR/5UY5RZmMewkKkB/T25miPwwdiXvdwbWoKRn8pPlg/NJ9ae8BXcyFg GsOuQWnjdDJE+Orud5IBWEARpW98SbtksQSVtoZPLE4iK9gglsUgiXAI2W8/MQkP cvmGDz1q80jNF4m/RJSY9frGXRCK3ICOue6g24JDmgioQYZ/Weqo0gtpYQnYiWPb lYsNgNrOM2clLVnVbUMD5LwFf7oEspgZkyqirwaqJ+lP3Elyc6VTr3BvClQpdpyb tZ7g5PC/zlU+IcFbiGCgsvkoFsWQ7aT0thchNn4RmP8QbNNL/OJ1gIMat0at2Aon nqYfkJVi/a7lHCYmhP9rdEWqhOSljtvyjeE7A5XSPVlYxP+xSOyyEKDCcIbh8chH pC11WASnbDRP/ldAuZf67s2ot62u1sD3Az4fdYgf04wFpq7s52MLkeThUrSsm2L0 ljLrSCV/8l2XYqvyYBQm =/jCH -----END PGP SIGNATURE----- Merge tag 'for-linus-20141015' of git://git.infradead.org/linux-mtd Pull MTD update from Brian Norris: "Sorry for delaying this a bit later than usual. There's one mild regression from 3.16 that was noticed during the 3.17 cycle, and I meant to send a fix for it along with this pull request. I'll probably try to queue it up for a later pull request once I've had a better look at it, hopefully by -rc2 at the latest. Summary for this pull: NAND - Cleanup for Denali driver - Atmel: add support for new page sizes - Atmel: fix up 'raw' mode support - Atmel: miscellaneous cleanups - New timing mode helpers for non-ONFI NAND - OMAP: allow driver to be (properly) built as a module - bcm47xx: RESET support and other cleanups SPI NOR - Miscellaneous cleanups, to prepare framework for wider use (some further work still pending) - Compile-time configuration to select 4K vs. 64K support for flash that support both (necessary for using UBIFS on some SPI NOR) A few scattered code quality fixes, detected by Coverity See the changesets for more" * tag 'for-linus-20141015' of git://git.infradead.org/linux-mtd: (59 commits) mtd: nand: omap: Correct CONFIG_MTD_NAND_OMAP_BCH help message mtd: nand: Force omap_elm to be built as a module if omap2_nand is a module mtd: move support for struct flash_platform_data into m25p80 mtd: spi-nor: add Kconfig option to disable 4K sectors mtd: nand: Move ELM driver and rename as omap_elm nand: omap2: Replace pr_err with dev_err nand: omap2: Remove horrible ifdefs to fix module probe mtd: nand: add Hynix's H27UCG8T2ATR-BC to nand_ids table mtd: nand: support ONFI timing mode retrieval for non-ONFI NANDs mtd: physmap_of: Add non-obsolete map_rom probe mtd: physmap_of: Fix ROM support via OF MAINTAINERS: add l2-mtd.git, 'next' tree for MTD mtd: denali: fix indents and other trivial things mtd: denali: remove unnecessary parentheses mtd: denali: remove another set-but-unused variable mtd: denali: fix include guard and license block of denali.h mtd: nand: don't break long print messages mtd: bcm47xxnflash: replace some magic numbers mtd: bcm47xxnflash: NAND_CMD_RESET support mtd: bcm47xxnflash: add cmd_ctrl handler ...
This commit is contained in:
commit
511c41d9e6
@ -36,6 +36,7 @@ Optional properties:
|
||||
- reg : should specify the address and size used for NFC command registers,
|
||||
NFC registers and NFC Sram. NFC Sram address and size can be absent
|
||||
if don't want to use it.
|
||||
- clocks: phandle to the peripheral clock
|
||||
- Optional properties:
|
||||
- atmel,write-by-sram: boolean to enable NFC write by sram.
|
||||
|
||||
@ -98,6 +99,7 @@ nand0: nand@40000000 {
|
||||
compatible = "atmel,sama5d3-nfc";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
clocks = <&hsmc_clk>
|
||||
reg = <
|
||||
0x70000000 0x10000000 /* NFC Command Registers */
|
||||
0xffffc000 0x00000070 /* NFC HSMC regs */
|
||||
|
@ -4,8 +4,8 @@ Flash chips (Memory Technology Devices) are often used for solid state
|
||||
file systems on embedded devices.
|
||||
|
||||
- compatible : should contain the specific model of mtd chip(s)
|
||||
used, if known, followed by either "cfi-flash", "jedec-flash"
|
||||
or "mtd-ram".
|
||||
used, if known, followed by either "cfi-flash", "jedec-flash",
|
||||
"mtd-ram" or "mtd-rom".
|
||||
- reg : Address range(s) of the mtd chip(s)
|
||||
It's possible to (optionally) define multiple "reg" tuples so that
|
||||
non-identical chips can be described in one node.
|
||||
|
@ -5992,6 +5992,7 @@ L: linux-mtd@lists.infradead.org
|
||||
W: http://www.linux-mtd.infradead.org/
|
||||
Q: http://patchwork.ozlabs.org/project/linux-mtd/list/
|
||||
T: git git://git.infradead.org/linux-mtd.git
|
||||
T: git git://git.infradead.org/l2-mtd.git
|
||||
S: Maintained
|
||||
F: drivers/mtd/
|
||||
F: include/linux/mtd/
|
||||
|
@ -1440,6 +1440,8 @@ static int gpmc_probe_nand_child(struct platform_device *pdev,
|
||||
break;
|
||||
}
|
||||
|
||||
gpmc_nand_data->flash_bbt = of_get_nand_on_flash_bbt(child);
|
||||
|
||||
val = of_get_nand_bus_width(child);
|
||||
if (val == 16)
|
||||
gpmc_nand_data->devsize = NAND_BUSWIDTH_16;
|
||||
|
@ -199,6 +199,17 @@ static int bcm47xxpart_parse(struct mtd_info *master,
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* New (ARM?) devices may have NVRAM in some middle block. Last
|
||||
* block will be checked later, so skip it.
|
||||
*/
|
||||
if (offset != master->size - blocksize &&
|
||||
buf[0x000 / 4] == NVRAM_HEADER) {
|
||||
bcm47xxpart_add_part(&parts[curr_part++], "nvram",
|
||||
offset, 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Read middle of the block */
|
||||
if (mtd_read(master, offset + 0x8000, 0x4,
|
||||
&bytes_read, (uint8_t *)buf) < 0) {
|
||||
|
@ -2033,6 +2033,8 @@ static int cfi_amdstd_panic_wait(struct map_info *map, struct flchip *chip,
|
||||
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
retries--;
|
||||
}
|
||||
|
||||
/* the chip never became ready */
|
||||
|
@ -12,7 +12,6 @@ obj-$(CONFIG_MTD_LART) += lart.o
|
||||
obj-$(CONFIG_MTD_BLOCK2MTD) += block2mtd.o
|
||||
obj-$(CONFIG_MTD_DATAFLASH) += mtd_dataflash.o
|
||||
obj-$(CONFIG_MTD_M25P80) += m25p80.o
|
||||
obj-$(CONFIG_MTD_NAND_OMAP_BCH) += elm.o
|
||||
obj-$(CONFIG_MTD_SPEAR_SMI) += spear_smi.o
|
||||
obj-$(CONFIG_MTD_SST25L) += sst25l.o
|
||||
obj-$(CONFIG_MTD_BCM47XXSFLASH) += bcm47xxsflash.o
|
||||
|
@ -1697,16 +1697,16 @@ static int dbg_asicmode_show(struct seq_file *s, void *p)
|
||||
|
||||
switch (mode) {
|
||||
case DOC_ASICMODE_RESET:
|
||||
pos += seq_printf(s, "reset");
|
||||
pos += seq_puts(s, "reset");
|
||||
break;
|
||||
case DOC_ASICMODE_NORMAL:
|
||||
pos += seq_printf(s, "normal");
|
||||
pos += seq_puts(s, "normal");
|
||||
break;
|
||||
case DOC_ASICMODE_POWERDOWN:
|
||||
pos += seq_printf(s, "powerdown");
|
||||
pos += seq_puts(s, "powerdown");
|
||||
break;
|
||||
}
|
||||
pos += seq_printf(s, ")\n");
|
||||
pos += seq_puts(s, ")\n");
|
||||
return pos;
|
||||
}
|
||||
DEBUGFS_RO_ATTR(asic_mode, dbg_asicmode_show);
|
||||
@ -1745,22 +1745,22 @@ static int dbg_protection_show(struct seq_file *s, void *p)
|
||||
pos += seq_printf(s, "Protection = 0x%02x (",
|
||||
protect);
|
||||
if (protect & DOC_PROTECT_FOUNDRY_OTP_LOCK)
|
||||
pos += seq_printf(s, "FOUNDRY_OTP_LOCK,");
|
||||
pos += seq_puts(s, "FOUNDRY_OTP_LOCK,");
|
||||
if (protect & DOC_PROTECT_CUSTOMER_OTP_LOCK)
|
||||
pos += seq_printf(s, "CUSTOMER_OTP_LOCK,");
|
||||
pos += seq_puts(s, "CUSTOMER_OTP_LOCK,");
|
||||
if (protect & DOC_PROTECT_LOCK_INPUT)
|
||||
pos += seq_printf(s, "LOCK_INPUT,");
|
||||
pos += seq_puts(s, "LOCK_INPUT,");
|
||||
if (protect & DOC_PROTECT_STICKY_LOCK)
|
||||
pos += seq_printf(s, "STICKY_LOCK,");
|
||||
pos += seq_puts(s, "STICKY_LOCK,");
|
||||
if (protect & DOC_PROTECT_PROTECTION_ENABLED)
|
||||
pos += seq_printf(s, "PROTECTION ON,");
|
||||
pos += seq_puts(s, "PROTECTION ON,");
|
||||
if (protect & DOC_PROTECT_IPL_DOWNLOAD_LOCK)
|
||||
pos += seq_printf(s, "IPL_DOWNLOAD_LOCK,");
|
||||
pos += seq_puts(s, "IPL_DOWNLOAD_LOCK,");
|
||||
if (protect & DOC_PROTECT_PROTECTION_ERROR)
|
||||
pos += seq_printf(s, "PROTECT_ERR,");
|
||||
pos += seq_puts(s, "PROTECT_ERR,");
|
||||
else
|
||||
pos += seq_printf(s, "NO_PROTECT_ERR");
|
||||
pos += seq_printf(s, ")\n");
|
||||
pos += seq_puts(s, "NO_PROTECT_ERR");
|
||||
pos += seq_puts(s, ")\n");
|
||||
|
||||
pos += seq_printf(s, "DPS0 = 0x%02x : "
|
||||
"Protected area [0x%x - 0x%x] : OTP=%d, READ=%d, "
|
||||
|
@ -193,11 +193,14 @@ static int m25p_probe(struct spi_device *spi)
|
||||
{
|
||||
struct mtd_part_parser_data ppdata;
|
||||
struct flash_platform_data *data;
|
||||
const struct spi_device_id *id = NULL;
|
||||
struct m25p *flash;
|
||||
struct spi_nor *nor;
|
||||
enum read_mode mode = SPI_NOR_NORMAL;
|
||||
int ret;
|
||||
|
||||
data = dev_get_platdata(&spi->dev);
|
||||
|
||||
flash = devm_kzalloc(&spi->dev, sizeof(*flash), GFP_KERNEL);
|
||||
if (!flash)
|
||||
return -ENOMEM;
|
||||
@ -223,11 +226,26 @@ static int m25p_probe(struct spi_device *spi)
|
||||
mode = SPI_NOR_QUAD;
|
||||
else if (spi->mode & SPI_RX_DUAL)
|
||||
mode = SPI_NOR_DUAL;
|
||||
ret = spi_nor_scan(nor, spi_get_device_id(spi), mode);
|
||||
|
||||
if (data && data->name)
|
||||
flash->mtd.name = data->name;
|
||||
|
||||
/* For some (historical?) reason many platforms provide two different
|
||||
* names in flash_platform_data: "name" and "type". Quite often name is
|
||||
* set to "m25p80" and then "type" provides a real chip name.
|
||||
* If that's the case, respect "type" and ignore a "name".
|
||||
*/
|
||||
if (data && data->type)
|
||||
id = spi_nor_match_id(data->type);
|
||||
|
||||
/* If we didn't get name from platform, simply use "modalias". */
|
||||
if (!id)
|
||||
id = spi_get_device_id(spi);
|
||||
|
||||
ret = spi_nor_scan(nor, id, mode);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
data = dev_get_platdata(&spi->dev);
|
||||
ppdata.of_node = spi->dev.of_node;
|
||||
|
||||
return mtd_device_parse_register(&flash->mtd, NULL, &ppdata,
|
||||
|
@ -249,7 +249,7 @@ config MTD_CFI_FLAGADM
|
||||
|
||||
config MTD_SOLUTIONENGINE
|
||||
tristate "CFI Flash device mapped on Hitachi SolutionEngine"
|
||||
depends on SUPERH && SOLUTION_ENGINE && MTD_CFI && MTD_REDBOOT_PARTS
|
||||
depends on SOLUTION_ENGINE && MTD_CFI && MTD_REDBOOT_PARTS
|
||||
help
|
||||
This enables access to the flash chips on the Hitachi SolutionEngine and
|
||||
similar boards. Say 'Y' if you are building a kernel for such a board.
|
||||
|
@ -99,22 +99,28 @@ static map_word gf_read(struct map_info *map, unsigned long ofs)
|
||||
* @from: flash offset to copy from
|
||||
* @len: how much to copy
|
||||
*
|
||||
* We rely on the MTD layer to chunk up copies such that a single request here
|
||||
* will not cross a window size. This allows us to only wiggle the GPIOs once
|
||||
* before falling back to a normal memcpy. Reading the higher layer code shows
|
||||
* that this is indeed the case, but add a BUG_ON() to future proof.
|
||||
* The "from" region may straddle more than one window, so toggle the GPIOs for
|
||||
* each window region before reading its data.
|
||||
*/
|
||||
static void gf_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
|
||||
{
|
||||
struct async_state *state = gf_map_info_to_state(map);
|
||||
|
||||
gf_set_gpios(state, from);
|
||||
int this_len;
|
||||
|
||||
/* BUG if operation crosses the win_size */
|
||||
BUG_ON(!((from + len) % state->win_size <= (from + 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;
|
||||
|
||||
/* operation does not cross the win_size, so one shot it */
|
||||
memcpy_fromio(to, map->virt + (from % state->win_size), len);
|
||||
gf_set_gpios(state, from);
|
||||
memcpy_fromio(to, map->virt + (from % state->win_size),
|
||||
this_len);
|
||||
len -= this_len;
|
||||
from += this_len;
|
||||
to += this_len;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -147,13 +153,21 @@ static void gf_copy_to(struct map_info *map, unsigned long to,
|
||||
{
|
||||
struct async_state *state = gf_map_info_to_state(map);
|
||||
|
||||
gf_set_gpios(state, to);
|
||||
int this_len;
|
||||
|
||||
/* BUG if operation crosses the win_size */
|
||||
BUG_ON(!((to + len) % state->win_size <= (to + 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;
|
||||
|
||||
/* operation does not cross the win_size, so one shot it */
|
||||
memcpy_toio(map->virt + (to % state->win_size), from, len);
|
||||
gf_set_gpios(state, to);
|
||||
memcpy_toio(map->virt + (to % state->win_size), from, len);
|
||||
|
||||
len -= this_len;
|
||||
to += this_len;
|
||||
from += this_len;
|
||||
}
|
||||
}
|
||||
|
||||
static const char * const part_probe_types[] = {
|
||||
|
@ -89,7 +89,7 @@ static caddr_t remap_window(struct map_info *map, unsigned long to)
|
||||
|
||||
if (!pcmcia_dev_present(dev->p_dev)) {
|
||||
pr_debug("device removed\n");
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
offset = to & ~(dev->win_size-1);
|
||||
|
@ -103,7 +103,7 @@ static struct mtd_info *obsolete_probe(struct platform_device *dev,
|
||||
if (strcmp(of_probe, "ROM") != 0)
|
||||
dev_warn(&dev->dev, "obsolete_probe: don't know probe "
|
||||
"type '%s', mapping as rom\n", of_probe);
|
||||
return do_map_probe("mtd_rom", map);
|
||||
return do_map_probe("map_rom", map);
|
||||
}
|
||||
}
|
||||
|
||||
@ -339,6 +339,10 @@ static struct of_device_id of_flash_match[] = {
|
||||
.compatible = "mtd-ram",
|
||||
.data = (void *)"map_ram",
|
||||
},
|
||||
{
|
||||
.compatible = "mtd-rom",
|
||||
.data = (void *)"map_rom",
|
||||
},
|
||||
{
|
||||
.type = "rom",
|
||||
.compatible = "direct-mapped"
|
||||
|
@ -549,6 +549,9 @@ static int mtdchar_blkpg_ioctl(struct mtd_info *mtd,
|
||||
if (mtd_is_partition(mtd))
|
||||
return -EINVAL;
|
||||
|
||||
/* Sanitize user input */
|
||||
p.devname[BLKPG_DEVNAMELTH - 1] = '\0';
|
||||
|
||||
return mtd_add_partition(mtd, p.devname, p.start, p.length);
|
||||
|
||||
case BLKPG_DEL_PARTITION:
|
||||
|
@ -105,12 +105,11 @@ static LIST_HEAD(mtd_notifiers);
|
||||
*/
|
||||
static void mtd_release(struct device *dev)
|
||||
{
|
||||
struct mtd_info __maybe_unused *mtd = dev_get_drvdata(dev);
|
||||
struct mtd_info *mtd = dev_get_drvdata(dev);
|
||||
dev_t index = MTD_DEVT(mtd->index);
|
||||
|
||||
/* remove /dev/mtdXro node if needed */
|
||||
if (index)
|
||||
device_destroy(&mtd_class, index + 1);
|
||||
/* remove /dev/mtdXro node */
|
||||
device_destroy(&mtd_class, index + 1);
|
||||
}
|
||||
|
||||
static int mtd_cls_suspend(struct device *dev, pm_message_t state)
|
||||
@ -442,10 +441,8 @@ int add_mtd_device(struct mtd_info *mtd)
|
||||
if (device_register(&mtd->dev) != 0)
|
||||
goto fail_added;
|
||||
|
||||
if (MTD_DEVT(i))
|
||||
device_create(&mtd_class, mtd->dev.parent,
|
||||
MTD_DEVT(i) + 1,
|
||||
NULL, "mtd%dro", i);
|
||||
device_create(&mtd_class, mtd->dev.parent, MTD_DEVT(i) + 1, NULL,
|
||||
"mtd%dro", i);
|
||||
|
||||
pr_debug("mtd: Giving out device %d to %s\n", i, mtd->name);
|
||||
/* No need to get a refcount on the module containing
|
||||
@ -778,7 +775,7 @@ EXPORT_SYMBOL_GPL(__put_mtd_device);
|
||||
*/
|
||||
int mtd_erase(struct mtd_info *mtd, struct erase_info *instr)
|
||||
{
|
||||
if (instr->addr > mtd->size || instr->len > mtd->size - instr->addr)
|
||||
if (instr->addr >= mtd->size || instr->len > mtd->size - instr->addr)
|
||||
return -EINVAL;
|
||||
if (!(mtd->flags & MTD_WRITEABLE))
|
||||
return -EROFS;
|
||||
@ -804,7 +801,7 @@ int mtd_point(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
|
||||
*phys = 0;
|
||||
if (!mtd->_point)
|
||||
return -EOPNOTSUPP;
|
||||
if (from < 0 || from > mtd->size || len > mtd->size - from)
|
||||
if (from < 0 || from >= mtd->size || len > mtd->size - from)
|
||||
return -EINVAL;
|
||||
if (!len)
|
||||
return 0;
|
||||
@ -817,7 +814,7 @@ int mtd_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
|
||||
{
|
||||
if (!mtd->_point)
|
||||
return -EOPNOTSUPP;
|
||||
if (from < 0 || from > mtd->size || len > mtd->size - from)
|
||||
if (from < 0 || from >= mtd->size || len > mtd->size - from)
|
||||
return -EINVAL;
|
||||
if (!len)
|
||||
return 0;
|
||||
@ -835,7 +832,7 @@ unsigned long mtd_get_unmapped_area(struct mtd_info *mtd, unsigned long len,
|
||||
{
|
||||
if (!mtd->_get_unmapped_area)
|
||||
return -EOPNOTSUPP;
|
||||
if (offset > mtd->size || len > mtd->size - offset)
|
||||
if (offset >= mtd->size || len > mtd->size - offset)
|
||||
return -EINVAL;
|
||||
return mtd->_get_unmapped_area(mtd, len, offset, flags);
|
||||
}
|
||||
@ -846,7 +843,7 @@ int mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
|
||||
{
|
||||
int ret_code;
|
||||
*retlen = 0;
|
||||
if (from < 0 || from > mtd->size || len > mtd->size - from)
|
||||
if (from < 0 || from >= mtd->size || len > mtd->size - from)
|
||||
return -EINVAL;
|
||||
if (!len)
|
||||
return 0;
|
||||
@ -869,7 +866,7 @@ int mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
|
||||
const u_char *buf)
|
||||
{
|
||||
*retlen = 0;
|
||||
if (to < 0 || to > mtd->size || len > mtd->size - to)
|
||||
if (to < 0 || to >= mtd->size || len > mtd->size - to)
|
||||
return -EINVAL;
|
||||
if (!mtd->_write || !(mtd->flags & MTD_WRITEABLE))
|
||||
return -EROFS;
|
||||
@ -892,7 +889,7 @@ int mtd_panic_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
|
||||
*retlen = 0;
|
||||
if (!mtd->_panic_write)
|
||||
return -EOPNOTSUPP;
|
||||
if (to < 0 || to > mtd->size || len > mtd->size - to)
|
||||
if (to < 0 || to >= mtd->size || len > mtd->size - to)
|
||||
return -EINVAL;
|
||||
if (!(mtd->flags & MTD_WRITEABLE))
|
||||
return -EROFS;
|
||||
@ -1011,7 +1008,7 @@ int mtd_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
|
||||
{
|
||||
if (!mtd->_lock)
|
||||
return -EOPNOTSUPP;
|
||||
if (ofs < 0 || ofs > mtd->size || len > mtd->size - ofs)
|
||||
if (ofs < 0 || ofs >= mtd->size || len > mtd->size - ofs)
|
||||
return -EINVAL;
|
||||
if (!len)
|
||||
return 0;
|
||||
@ -1023,7 +1020,7 @@ int mtd_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
|
||||
{
|
||||
if (!mtd->_unlock)
|
||||
return -EOPNOTSUPP;
|
||||
if (ofs < 0 || ofs > mtd->size || len > mtd->size - ofs)
|
||||
if (ofs < 0 || ofs >= mtd->size || len > mtd->size - ofs)
|
||||
return -EINVAL;
|
||||
if (!len)
|
||||
return 0;
|
||||
@ -1035,7 +1032,7 @@ int mtd_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len)
|
||||
{
|
||||
if (!mtd->_is_locked)
|
||||
return -EOPNOTSUPP;
|
||||
if (ofs < 0 || ofs > mtd->size || len > mtd->size - ofs)
|
||||
if (ofs < 0 || ofs >= mtd->size || len > mtd->size - ofs)
|
||||
return -EINVAL;
|
||||
if (!len)
|
||||
return 0;
|
||||
@ -1045,7 +1042,7 @@ EXPORT_SYMBOL_GPL(mtd_is_locked);
|
||||
|
||||
int mtd_block_isreserved(struct mtd_info *mtd, loff_t ofs)
|
||||
{
|
||||
if (ofs < 0 || ofs > mtd->size)
|
||||
if (ofs < 0 || ofs >= mtd->size)
|
||||
return -EINVAL;
|
||||
if (!mtd->_block_isreserved)
|
||||
return 0;
|
||||
@ -1055,7 +1052,7 @@ EXPORT_SYMBOL_GPL(mtd_block_isreserved);
|
||||
|
||||
int mtd_block_isbad(struct mtd_info *mtd, loff_t ofs)
|
||||
{
|
||||
if (ofs < 0 || ofs > mtd->size)
|
||||
if (ofs < 0 || ofs >= mtd->size)
|
||||
return -EINVAL;
|
||||
if (!mtd->_block_isbad)
|
||||
return 0;
|
||||
@ -1067,7 +1064,7 @@ int mtd_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
||||
{
|
||||
if (!mtd->_block_markbad)
|
||||
return -EOPNOTSUPP;
|
||||
if (ofs < 0 || ofs > mtd->size)
|
||||
if (ofs < 0 || ofs >= mtd->size)
|
||||
return -EINVAL;
|
||||
if (!(mtd->flags & MTD_WRITEABLE))
|
||||
return -EROFS;
|
||||
|
@ -145,7 +145,7 @@ struct mtdswap_dev {
|
||||
struct mtdswap_oobdata {
|
||||
__le16 magic;
|
||||
__le32 count;
|
||||
} __attribute__((packed));
|
||||
} __packed;
|
||||
|
||||
#define MTDSWAP_MAGIC_CLEAN 0x2095
|
||||
#define MTDSWAP_MAGIC_DIRTY (MTDSWAP_MAGIC_CLEAN + 1)
|
||||
@ -1287,7 +1287,7 @@ static int mtdswap_show(struct seq_file *s, void *data)
|
||||
|
||||
seq_printf(s, "total erasures: %lu\n", sum);
|
||||
|
||||
seq_printf(s, "\n");
|
||||
seq_puts(s, "\n");
|
||||
|
||||
seq_printf(s, "mtdswap_readsect count: %llu\n", d->sect_read_count);
|
||||
seq_printf(s, "mtdswap_writesect count: %llu\n", d->sect_write_count);
|
||||
@ -1296,7 +1296,7 @@ static int mtdswap_show(struct seq_file *s, void *data)
|
||||
seq_printf(s, "mtd write count: %llu\n", d->mtd_write_count);
|
||||
seq_printf(s, "discarded pages count: %llu\n", d->discard_page_count);
|
||||
|
||||
seq_printf(s, "\n");
|
||||
seq_puts(s, "\n");
|
||||
seq_printf(s, "total pages: %u\n", pages);
|
||||
seq_printf(s, "pages mapped: %u\n", mapped);
|
||||
|
||||
@ -1474,7 +1474,7 @@ static void mtdswap_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
|
||||
}
|
||||
|
||||
eblocks = mtd_div_by_eb(use_size, mtd);
|
||||
use_size = eblocks * mtd->erasesize;
|
||||
use_size = (uint64_t)eblocks * mtd->erasesize;
|
||||
bad_blocks = mtdswap_badblocks(mtd, use_size);
|
||||
eavailable = eblocks - bad_blocks;
|
||||
|
||||
|
@ -96,7 +96,7 @@ config MTD_NAND_OMAP2
|
||||
|
||||
config MTD_NAND_OMAP_BCH
|
||||
depends on MTD_NAND_OMAP2
|
||||
tristate "Support hardware based BCH error correction"
|
||||
bool "Support hardware based BCH error correction"
|
||||
default n
|
||||
select BCH
|
||||
help
|
||||
@ -104,7 +104,10 @@ config MTD_NAND_OMAP_BCH
|
||||
locate and correct errors when using BCH ECC scheme. This offloads
|
||||
the cpu from doing ECC error searching and correction. However some
|
||||
legacy OMAP families like OMAP2xxx, OMAP3xxx do not have ELM engine
|
||||
so they should not enable this config symbol.
|
||||
so this is optional for them.
|
||||
|
||||
config MTD_NAND_OMAP_BCH_BUILD
|
||||
def_tristate MTD_NAND_OMAP2 && MTD_NAND_OMAP_BCH
|
||||
|
||||
config MTD_NAND_IDS
|
||||
tristate
|
||||
|
@ -27,6 +27,7 @@ obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o
|
||||
obj-$(CONFIG_MTD_NAND_ATMEL) += atmel_nand.o
|
||||
obj-$(CONFIG_MTD_NAND_GPIO) += gpio.o
|
||||
obj-$(CONFIG_MTD_NAND_OMAP2) += omap2.o
|
||||
obj-$(CONFIG_MTD_NAND_OMAP_BCH_BUILD) += omap_elm.o
|
||||
obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o
|
||||
obj-$(CONFIG_MTD_NAND_PXA3xx) += pxa3xx_nand.o
|
||||
obj-$(CONFIG_MTD_NAND_TMIO) += tmio_nand.o
|
||||
|
@ -27,6 +27,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
@ -96,6 +97,8 @@ struct atmel_nfc {
|
||||
bool use_nfc_sram;
|
||||
bool write_by_sram;
|
||||
|
||||
struct clk *clk;
|
||||
|
||||
bool is_initialized;
|
||||
struct completion comp_ready;
|
||||
struct completion comp_cmd_done;
|
||||
@ -128,8 +131,6 @@ struct atmel_nand_host {
|
||||
u32 pmecc_lookup_table_offset_512;
|
||||
u32 pmecc_lookup_table_offset_1024;
|
||||
|
||||
int pmecc_bytes_per_sector;
|
||||
int pmecc_sector_number;
|
||||
int pmecc_degree; /* Degree of remainders */
|
||||
int pmecc_cw_len; /* Length of codeword */
|
||||
|
||||
@ -841,7 +842,7 @@ static void pmecc_correct_data(struct mtd_info *mtd, uint8_t *buf, uint8_t *ecc,
|
||||
pos, bit_pos, err_byte, *(buf + byte_pos));
|
||||
} else {
|
||||
/* Bit flip in OOB area */
|
||||
tmp = sector_num * host->pmecc_bytes_per_sector
|
||||
tmp = sector_num * nand_chip->ecc.bytes
|
||||
+ (byte_pos - sector_size);
|
||||
err_byte = ecc[tmp];
|
||||
ecc[tmp] ^= (1 << bit_pos);
|
||||
@ -874,7 +875,7 @@ static int pmecc_correction(struct mtd_info *mtd, u32 pmecc_stat, uint8_t *buf,
|
||||
return 0;
|
||||
|
||||
normal_check:
|
||||
for (i = 0; i < host->pmecc_sector_number; i++) {
|
||||
for (i = 0; i < nand_chip->ecc.steps; i++) {
|
||||
err_nbr = 0;
|
||||
if (pmecc_stat & 0x1) {
|
||||
buf_pos = buf + i * host->pmecc_sector_size;
|
||||
@ -890,7 +891,7 @@ normal_check:
|
||||
return -EIO;
|
||||
} else {
|
||||
pmecc_correct_data(mtd, buf_pos, ecc, i,
|
||||
host->pmecc_bytes_per_sector, err_nbr);
|
||||
nand_chip->ecc.bytes, err_nbr);
|
||||
mtd->ecc_stats.corrected += err_nbr;
|
||||
total_err += err_nbr;
|
||||
}
|
||||
@ -984,11 +985,11 @@ static int atmel_nand_pmecc_write_page(struct mtd_info *mtd,
|
||||
cpu_relax();
|
||||
}
|
||||
|
||||
for (i = 0; i < host->pmecc_sector_number; i++) {
|
||||
for (j = 0; j < host->pmecc_bytes_per_sector; j++) {
|
||||
for (i = 0; i < chip->ecc.steps; i++) {
|
||||
for (j = 0; j < chip->ecc.bytes; j++) {
|
||||
int pos;
|
||||
|
||||
pos = i * host->pmecc_bytes_per_sector + j;
|
||||
pos = i * chip->ecc.bytes + j;
|
||||
chip->oob_poi[eccpos[pos]] =
|
||||
pmecc_readb_ecc_relaxed(host->ecc, i, j);
|
||||
}
|
||||
@ -1031,7 +1032,7 @@ static void atmel_pmecc_core_init(struct mtd_info *mtd)
|
||||
else if (host->pmecc_sector_size == 1024)
|
||||
val |= PMECC_CFG_SECTOR1024;
|
||||
|
||||
switch (host->pmecc_sector_number) {
|
||||
switch (nand_chip->ecc.steps) {
|
||||
case 1:
|
||||
val |= PMECC_CFG_PAGE_1SECTOR;
|
||||
break;
|
||||
@ -1148,7 +1149,6 @@ static int atmel_pmecc_nand_init_params(struct platform_device *pdev,
|
||||
|
||||
host->ecc = devm_ioremap_resource(&pdev->dev, regs);
|
||||
if (IS_ERR(host->ecc)) {
|
||||
dev_err(host->dev, "ioremap failed\n");
|
||||
err_no = PTR_ERR(host->ecc);
|
||||
goto err;
|
||||
}
|
||||
@ -1156,8 +1156,6 @@ static int atmel_pmecc_nand_init_params(struct platform_device *pdev,
|
||||
regs_pmerr = platform_get_resource(pdev, IORESOURCE_MEM, 2);
|
||||
host->pmerrloc_base = devm_ioremap_resource(&pdev->dev, regs_pmerr);
|
||||
if (IS_ERR(host->pmerrloc_base)) {
|
||||
dev_err(host->dev,
|
||||
"Can not get I/O resource for PMECC ERRLOC controller!\n");
|
||||
err_no = PTR_ERR(host->pmerrloc_base);
|
||||
goto err;
|
||||
}
|
||||
@ -1165,7 +1163,6 @@ static int atmel_pmecc_nand_init_params(struct platform_device *pdev,
|
||||
regs_rom = platform_get_resource(pdev, IORESOURCE_MEM, 3);
|
||||
host->pmecc_rom_base = devm_ioremap_resource(&pdev->dev, regs_rom);
|
||||
if (IS_ERR(host->pmecc_rom_base)) {
|
||||
dev_err(host->dev, "Can not get I/O resource for ROM!\n");
|
||||
err_no = PTR_ERR(host->pmecc_rom_base);
|
||||
goto err;
|
||||
}
|
||||
@ -1174,22 +1171,29 @@ static int atmel_pmecc_nand_init_params(struct platform_device *pdev,
|
||||
|
||||
/* set ECC page size and oob layout */
|
||||
switch (mtd->writesize) {
|
||||
case 512:
|
||||
case 1024:
|
||||
case 2048:
|
||||
case 4096:
|
||||
case 8192:
|
||||
if (sector_size > mtd->writesize) {
|
||||
dev_err(host->dev, "pmecc sector size is bigger than the page size!\n");
|
||||
err_no = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
host->pmecc_degree = (sector_size == 512) ?
|
||||
PMECC_GF_DIMENSION_13 : PMECC_GF_DIMENSION_14;
|
||||
host->pmecc_cw_len = (1 << host->pmecc_degree) - 1;
|
||||
host->pmecc_sector_number = mtd->writesize / sector_size;
|
||||
host->pmecc_bytes_per_sector = pmecc_get_ecc_bytes(
|
||||
cap, sector_size);
|
||||
host->pmecc_alpha_to = pmecc_get_alpha_to(host);
|
||||
host->pmecc_index_of = host->pmecc_rom_base +
|
||||
host->pmecc_lookup_table_offset;
|
||||
|
||||
nand_chip->ecc.steps = host->pmecc_sector_number;
|
||||
nand_chip->ecc.strength = cap;
|
||||
nand_chip->ecc.bytes = host->pmecc_bytes_per_sector;
|
||||
nand_chip->ecc.total = host->pmecc_bytes_per_sector *
|
||||
host->pmecc_sector_number;
|
||||
nand_chip->ecc.bytes = pmecc_get_ecc_bytes(cap, sector_size);
|
||||
nand_chip->ecc.steps = mtd->writesize / sector_size;
|
||||
nand_chip->ecc.total = nand_chip->ecc.bytes *
|
||||
nand_chip->ecc.steps;
|
||||
if (nand_chip->ecc.total > mtd->oobsize - 2) {
|
||||
dev_err(host->dev, "No room for ECC bytes\n");
|
||||
err_no = -EINVAL;
|
||||
@ -1201,13 +1205,9 @@ static int atmel_pmecc_nand_init_params(struct platform_device *pdev,
|
||||
|
||||
nand_chip->ecc.layout = &atmel_pmecc_oobinfo;
|
||||
break;
|
||||
case 512:
|
||||
case 1024:
|
||||
case 4096:
|
||||
/* TODO */
|
||||
default:
|
||||
dev_warn(host->dev,
|
||||
"Unsupported page size for PMECC, use Software ECC\n");
|
||||
default:
|
||||
/* page size not handled by HW ECC */
|
||||
/* switching back to soft ECC */
|
||||
nand_chip->ecc.mode = NAND_ECC_SOFT;
|
||||
@ -1530,10 +1530,8 @@ static int atmel_hw_nand_init_params(struct platform_device *pdev,
|
||||
}
|
||||
|
||||
host->ecc = devm_ioremap_resource(&pdev->dev, regs);
|
||||
if (IS_ERR(host->ecc)) {
|
||||
dev_err(host->dev, "ioremap failed\n");
|
||||
if (IS_ERR(host->ecc))
|
||||
return PTR_ERR(host->ecc);
|
||||
}
|
||||
|
||||
/* ECC is calculated for the whole page (1 step) */
|
||||
nand_chip->ecc.size = mtd->writesize;
|
||||
@ -1907,15 +1905,7 @@ static int nfc_sram_write_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
if (offset || (data_len < mtd->writesize))
|
||||
return -EINVAL;
|
||||
|
||||
cfg = nfc_readl(host->nfc->hsmc_regs, CFG);
|
||||
len = mtd->writesize;
|
||||
|
||||
if (unlikely(raw)) {
|
||||
len += mtd->oobsize;
|
||||
nfc_writel(host->nfc->hsmc_regs, CFG, cfg | NFC_CFG_WSPARE);
|
||||
} else
|
||||
nfc_writel(host->nfc->hsmc_regs, CFG, cfg & ~NFC_CFG_WSPARE);
|
||||
|
||||
/* Copy page data to sram that will write to nand via NFC */
|
||||
if (use_dma) {
|
||||
if (atmel_nand_dma_op(mtd, (void *)buf, len, 0) != 0)
|
||||
@ -1925,6 +1915,15 @@ static int nfc_sram_write_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
memcpy32_toio(sram, buf, len);
|
||||
}
|
||||
|
||||
cfg = nfc_readl(host->nfc->hsmc_regs, CFG);
|
||||
if (unlikely(raw) && oob_required) {
|
||||
memcpy32_toio(sram + len, chip->oob_poi, mtd->oobsize);
|
||||
len += mtd->oobsize;
|
||||
nfc_writel(host->nfc->hsmc_regs, CFG, cfg | NFC_CFG_WSPARE);
|
||||
} else {
|
||||
nfc_writel(host->nfc->hsmc_regs, CFG, cfg & ~NFC_CFG_WSPARE);
|
||||
}
|
||||
|
||||
if (chip->ecc.mode == NAND_ECC_HW && host->has_pmecc)
|
||||
/*
|
||||
* When use NFC sram, need set up PMECC before send
|
||||
@ -2040,7 +2039,6 @@ static int atmel_nand_probe(struct platform_device *pdev)
|
||||
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
host->io_base = devm_ioremap_resource(&pdev->dev, mem);
|
||||
if (IS_ERR(host->io_base)) {
|
||||
dev_err(&pdev->dev, "atmel_nand: ioremap resource failed\n");
|
||||
res = PTR_ERR(host->io_base);
|
||||
goto err_nand_ioremap;
|
||||
}
|
||||
@ -2099,7 +2097,7 @@ static int atmel_nand_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
nand_chip->ecc.mode = host->board.ecc_mode;
|
||||
nand_chip->chip_delay = 20; /* 20us command delay time */
|
||||
nand_chip->chip_delay = 40; /* 40us command delay time */
|
||||
|
||||
if (host->board.bus_width_16) /* 16-bit bus width */
|
||||
nand_chip->options |= NAND_BUSWIDTH_16;
|
||||
@ -2248,6 +2246,7 @@ static int atmel_nand_nfc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct atmel_nfc *nfc = &nand_nfc;
|
||||
struct resource *nfc_cmd_regs, *nfc_hsmc_regs, *nfc_sram;
|
||||
int ret;
|
||||
|
||||
nfc_cmd_regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
nfc->base_cmd_regs = devm_ioremap_resource(&pdev->dev, nfc_cmd_regs);
|
||||
@ -2279,8 +2278,28 @@ static int atmel_nand_nfc_probe(struct platform_device *pdev)
|
||||
nfc_writel(nfc->hsmc_regs, IDR, 0xffffffff);
|
||||
nfc_readl(nfc->hsmc_regs, SR); /* clear the NFC_SR */
|
||||
|
||||
nfc->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (!IS_ERR(nfc->clk)) {
|
||||
ret = clk_prepare_enable(nfc->clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else {
|
||||
dev_warn(&pdev->dev, "NFC clock missing, update your Device Tree");
|
||||
}
|
||||
|
||||
nfc->is_initialized = true;
|
||||
dev_info(&pdev->dev, "NFC is probed.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int atmel_nand_nfc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct atmel_nfc *nfc = &nand_nfc;
|
||||
|
||||
if (!IS_ERR(nfc->clk))
|
||||
clk_disable_unprepare(nfc->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2297,6 +2316,7 @@ static struct platform_driver atmel_nand_nfc_driver = {
|
||||
.of_match_table = of_match_ptr(atmel_nand_nfc_match),
|
||||
},
|
||||
.probe = atmel_nand_nfc_probe,
|
||||
.remove = atmel_nand_nfc_remove,
|
||||
};
|
||||
|
||||
static struct platform_driver atmel_nand_driver = {
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/bcma/bcma.h>
|
||||
|
||||
/* Broadcom uses 1'000'000 but it seems to be too many. Tests on WNDR4500 has
|
||||
@ -23,6 +24,8 @@
|
||||
#define NFLASH_SECTOR_SIZE 512
|
||||
|
||||
#define NCTL_CMD0 0x00010000
|
||||
#define NCTL_COL 0x00020000 /* Update column with value from BCMA_CC_NFLASH_COL_ADDR */
|
||||
#define NCTL_ROW 0x00040000 /* Update row (page) with value from BCMA_CC_NFLASH_ROW_ADDR */
|
||||
#define NCTL_CMD1W 0x00080000
|
||||
#define NCTL_READ 0x00100000
|
||||
#define NCTL_WRITE 0x00200000
|
||||
@ -109,7 +112,7 @@ static void bcm47xxnflash_ops_bcm4706_read(struct mtd_info *mtd, uint8_t *buf,
|
||||
b47n->curr_page_addr);
|
||||
|
||||
/* Prepare to read */
|
||||
ctlcode = NCTL_CSA | NCTL_CMD1W | 0x00040000 | 0x00020000 |
|
||||
ctlcode = NCTL_CSA | NCTL_CMD1W | NCTL_ROW | NCTL_COL |
|
||||
NCTL_CMD0;
|
||||
ctlcode |= NAND_CMD_READSTART << 8;
|
||||
if (bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc, ctlcode))
|
||||
@ -167,6 +170,26 @@ 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)
|
||||
{
|
||||
struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv;
|
||||
struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv;
|
||||
u32 code = 0;
|
||||
|
||||
if (cmd == NAND_CMD_NONE)
|
||||
return;
|
||||
|
||||
if (cmd & NAND_CTRL_CLE)
|
||||
code = cmd | NCTL_CMD0;
|
||||
|
||||
/* nCS is not needed for reset command */
|
||||
if (cmd != NAND_CMD_RESET)
|
||||
code |= NCTL_CSA;
|
||||
|
||||
bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc, code);
|
||||
}
|
||||
|
||||
/* Default nand_select_chip calls cmd_ctrl, which is not used in BCM4706 */
|
||||
static void bcm47xxnflash_ops_bcm4706_select_chip(struct mtd_info *mtd,
|
||||
int chip)
|
||||
@ -174,6 +197,14 @@ static void bcm47xxnflash_ops_bcm4706_select_chip(struct mtd_info *mtd,
|
||||
return;
|
||||
}
|
||||
|
||||
static int bcm47xxnflash_ops_bcm4706_dev_ready(struct mtd_info *mtd)
|
||||
{
|
||||
struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv;
|
||||
struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv;
|
||||
|
||||
return !!(bcma_cc_read32(b47n->cc, BCMA_CC_NFLASH_CTL) & NCTL_READY);
|
||||
}
|
||||
|
||||
/*
|
||||
* Default nand_command and nand_command_lp don't match BCM4706 hardware layout.
|
||||
* For example, reading chip id is performed in a non-standard way.
|
||||
@ -198,7 +229,10 @@ static void bcm47xxnflash_ops_bcm4706_cmdfunc(struct mtd_info *mtd,
|
||||
|
||||
switch (command) {
|
||||
case NAND_CMD_RESET:
|
||||
pr_warn("Chip reset not implemented yet\n");
|
||||
nand_chip->cmd_ctrl(mtd, command, NAND_CTRL_CLE);
|
||||
|
||||
ndelay(100);
|
||||
nand_wait_ready(mtd);
|
||||
break;
|
||||
case NAND_CMD_READID:
|
||||
ctlcode = NCTL_CSA | 0x01000000 | NCTL_CMD1W | NCTL_CMD0;
|
||||
@ -242,7 +276,7 @@ static void bcm47xxnflash_ops_bcm4706_cmdfunc(struct mtd_info *mtd,
|
||||
case NAND_CMD_ERASE1:
|
||||
bcma_cc_write32(cc, BCMA_CC_NFLASH_ROW_ADDR,
|
||||
b47n->curr_page_addr);
|
||||
ctlcode = 0x00040000 | NCTL_CMD1W | NCTL_CMD0 |
|
||||
ctlcode = NCTL_ROW | NCTL_CMD1W | NCTL_CMD0 |
|
||||
NAND_CMD_ERASE1 | (NAND_CMD_ERASE2 << 8);
|
||||
if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, ctlcode))
|
||||
pr_err("ERASE1 failed\n");
|
||||
@ -257,13 +291,13 @@ static void bcm47xxnflash_ops_bcm4706_cmdfunc(struct mtd_info *mtd,
|
||||
b47n->curr_page_addr);
|
||||
|
||||
/* Prepare to write */
|
||||
ctlcode = 0x40000000 | 0x00040000 | 0x00020000 | 0x00010000;
|
||||
ctlcode = 0x40000000 | NCTL_ROW | NCTL_COL | NCTL_CMD0;
|
||||
ctlcode |= NAND_CMD_SEQIN;
|
||||
if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, ctlcode))
|
||||
pr_err("SEQIN failed\n");
|
||||
break;
|
||||
case NAND_CMD_PAGEPROG:
|
||||
if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, 0x00010000 |
|
||||
if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, NCTL_CMD0 |
|
||||
NAND_CMD_PAGEPROG))
|
||||
pr_err("PAGEPROG failed\n");
|
||||
if (bcm47xxnflash_ops_bcm4706_poll(cc))
|
||||
@ -341,6 +375,7 @@ static void bcm47xxnflash_ops_bcm4706_write_buf(struct mtd_info *mtd,
|
||||
|
||||
int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n)
|
||||
{
|
||||
struct nand_chip *nand_chip = (struct nand_chip *)&b47n->nand_chip;
|
||||
int err;
|
||||
u32 freq;
|
||||
u16 clock;
|
||||
@ -351,10 +386,14 @@ 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;
|
||||
|
||||
nand_chip->chip_delay = 50;
|
||||
b47n->nand_chip.bbt_options = NAND_BBT_USE_FLASH;
|
||||
b47n->nand_chip.ecc.mode = NAND_ECC_NONE; /* TODO: implement ECC */
|
||||
|
||||
@ -364,11 +403,13 @@ int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n)
|
||||
|
||||
/* Configure wait counters */
|
||||
if (b47n->cc->status & BCMA_CC_CHIPST_4706_PKG_OPTION) {
|
||||
freq = 100000000;
|
||||
/* 400 MHz */
|
||||
freq = 400000000 / 4;
|
||||
} else {
|
||||
freq = bcma_chipco_pll_read(b47n->cc, 4);
|
||||
freq = (freq * 0xFFF) >> 3;
|
||||
freq = (freq * 25000000) >> 3;
|
||||
freq = (freq & 0xFFF) >> 3;
|
||||
/* Fixed reference clock 25 MHz and m = 2 */
|
||||
freq = (freq * 25000000 / 2) / 4;
|
||||
}
|
||||
clock = freq / 1000000;
|
||||
w0 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(15, clock);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -17,6 +17,9 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __DENALI_H__
|
||||
#define __DENALI_H__
|
||||
|
||||
#include <linux/mtd/nand.h>
|
||||
|
||||
#define DEVICE_RESET 0x0
|
||||
@ -400,28 +403,6 @@
|
||||
#define ONFI_BLOOM_TIME 1
|
||||
#define MODE5_WORKAROUND 0
|
||||
|
||||
/* lld_nand.h */
|
||||
/*
|
||||
* NAND Flash Controller Device Driver
|
||||
* Copyright (c) 2009, Intel Corporation and its suppliers.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _LLD_NAND_
|
||||
#define _LLD_NAND_
|
||||
|
||||
#define MODE_00 0x00000000
|
||||
#define MODE_01 0x04000000
|
||||
@ -499,4 +480,4 @@ struct denali_nand_info {
|
||||
extern int denali_init(struct denali_nand_info *denali);
|
||||
extern void denali_remove(struct denali_nand_info *denali);
|
||||
|
||||
#endif /*_LLD_NAND_*/
|
||||
#endif /* __DENALI_H__ */
|
||||
|
@ -982,6 +982,15 @@ int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
|
||||
|
||||
chip->select_chip(mtd, chipnr);
|
||||
|
||||
/*
|
||||
* Reset the chip.
|
||||
* If we want to check the WP through READ STATUS and check the bit 7
|
||||
* we must reset the chip
|
||||
* some operation can also clear the bit 7 of status register
|
||||
* eg. erase/program a locked block
|
||||
*/
|
||||
chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
|
||||
|
||||
/* Check, if it is write protected */
|
||||
if (nand_check_wp(mtd)) {
|
||||
pr_debug("%s: device is write protected!\n",
|
||||
@ -1032,6 +1041,15 @@ int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
|
||||
|
||||
chip->select_chip(mtd, chipnr);
|
||||
|
||||
/*
|
||||
* Reset the chip.
|
||||
* If we want to check the WP through READ STATUS and check the bit 7
|
||||
* we must reset the chip
|
||||
* some operation can also clear the bit 7 of status register
|
||||
* eg. erase/program a locked block
|
||||
*/
|
||||
chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
|
||||
|
||||
/* Check, if it is write protected */
|
||||
if (nand_check_wp(mtd)) {
|
||||
pr_debug("%s: device is write protected!\n",
|
||||
@ -2391,8 +2409,8 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
|
||||
blockmask = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;
|
||||
|
||||
/* Invalidate the page cache, when we write to the cached page */
|
||||
if (to <= (chip->pagebuf << chip->page_shift) &&
|
||||
(chip->pagebuf << chip->page_shift) < (to + ops->len))
|
||||
if (to <= ((loff_t)chip->pagebuf << chip->page_shift) &&
|
||||
((loff_t)chip->pagebuf << chip->page_shift) < (to + ops->len))
|
||||
chip->pagebuf = -1;
|
||||
|
||||
/* Don't allow multipage oob writes with offset */
|
||||
@ -3576,6 +3594,8 @@ static bool find_full_id_nand(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
chip->options |= type->options;
|
||||
chip->ecc_strength_ds = NAND_ECC_STRENGTH(type);
|
||||
chip->ecc_step_ds = NAND_ECC_STEP(type);
|
||||
chip->onfi_timing_mode_default =
|
||||
type->onfi_timing_mode_default;
|
||||
|
||||
*busw = type->options & NAND_BUSWIDTH_16;
|
||||
|
||||
@ -3918,8 +3938,7 @@ int nand_scan_tail(struct mtd_info *mtd)
|
||||
case NAND_ECC_HW_OOB_FIRST:
|
||||
/* Similar to NAND_ECC_HW, but a separate read_page handle */
|
||||
if (!ecc->calculate || !ecc->correct || !ecc->hwctl) {
|
||||
pr_warn("No ECC functions supplied; "
|
||||
"hardware ECC not possible\n");
|
||||
pr_warn("No ECC functions supplied; hardware ECC not possible\n");
|
||||
BUG();
|
||||
}
|
||||
if (!ecc->read_page)
|
||||
@ -3950,8 +3969,7 @@ int nand_scan_tail(struct mtd_info *mtd)
|
||||
ecc->read_page == nand_read_page_hwecc ||
|
||||
!ecc->write_page ||
|
||||
ecc->write_page == nand_write_page_hwecc)) {
|
||||
pr_warn("No ECC functions supplied; "
|
||||
"hardware ECC not possible\n");
|
||||
pr_warn("No ECC functions supplied; hardware ECC not possible\n");
|
||||
BUG();
|
||||
}
|
||||
/* Use standard syndrome read/write page function? */
|
||||
@ -3975,9 +3993,8 @@ int nand_scan_tail(struct mtd_info *mtd)
|
||||
}
|
||||
break;
|
||||
}
|
||||
pr_warn("%d byte HW ECC not possible on "
|
||||
"%d byte page size, fallback to SW ECC\n",
|
||||
ecc->size, mtd->writesize);
|
||||
pr_warn("%d byte HW ECC not possible on %d byte page size, fallback to SW ECC\n",
|
||||
ecc->size, mtd->writesize);
|
||||
ecc->mode = NAND_ECC_SOFT;
|
||||
|
||||
case NAND_ECC_SOFT:
|
||||
@ -4030,8 +4047,7 @@ int nand_scan_tail(struct mtd_info *mtd)
|
||||
break;
|
||||
|
||||
case NAND_ECC_NONE:
|
||||
pr_warn("NAND_ECC_NONE selected by board driver. "
|
||||
"This is not recommended!\n");
|
||||
pr_warn("NAND_ECC_NONE selected by board driver. This is not recommended!\n");
|
||||
ecc->read_page = nand_read_page_raw;
|
||||
ecc->write_page = nand_write_page_raw;
|
||||
ecc->read_oob = nand_read_oob_std;
|
||||
|
@ -201,12 +201,12 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
|
||||
res = mtd_read(mtd, from, len, &retlen, buf);
|
||||
if (res < 0) {
|
||||
if (mtd_is_eccerr(res)) {
|
||||
pr_info("nand_bbt: ECC error in BBT at "
|
||||
"0x%012llx\n", from & ~mtd->writesize);
|
||||
pr_info("nand_bbt: ECC error in BBT at 0x%012llx\n",
|
||||
from & ~mtd->writesize);
|
||||
return res;
|
||||
} else if (mtd_is_bitflip(res)) {
|
||||
pr_info("nand_bbt: corrected error in BBT at "
|
||||
"0x%012llx\n", from & ~mtd->writesize);
|
||||
pr_info("nand_bbt: corrected error in BBT at 0x%012llx\n",
|
||||
from & ~mtd->writesize);
|
||||
ret = res;
|
||||
} else {
|
||||
pr_info("nand_bbt: error reading BBT\n");
|
||||
@ -580,8 +580,8 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
|
||||
if (td->pages[i] == -1)
|
||||
pr_warn("Bad block table not found for chip %d\n", i);
|
||||
else
|
||||
pr_info("Bad block table found at page %d, version "
|
||||
"0x%02X\n", td->pages[i], td->version[i]);
|
||||
pr_info("Bad block table found at page %d, version 0x%02X\n",
|
||||
td->pages[i], td->version[i]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -725,12 +725,10 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
|
||||
res = mtd_read(mtd, to, len, &retlen, buf);
|
||||
if (res < 0) {
|
||||
if (retlen != len) {
|
||||
pr_info("nand_bbt: error reading block "
|
||||
"for writing the bad block table\n");
|
||||
pr_info("nand_bbt: error reading block for writing the bad block table\n");
|
||||
return res;
|
||||
}
|
||||
pr_warn("nand_bbt: ECC error while reading "
|
||||
"block for writing bad block table\n");
|
||||
pr_warn("nand_bbt: ECC error while reading block for writing bad block table\n");
|
||||
}
|
||||
/* Read oob data */
|
||||
ops.ooblen = (len >> this->page_shift) * mtd->oobsize;
|
||||
@ -1338,9 +1336,8 @@ int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)
|
||||
block = (int)(offs >> this->bbt_erase_shift);
|
||||
res = bbt_get_entry(this, block);
|
||||
|
||||
pr_debug("nand_isbad_bbt(): bbt info for offs 0x%08x: "
|
||||
"(block %d) 0x%02x\n",
|
||||
(unsigned int)offs, block, res);
|
||||
pr_debug("nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n",
|
||||
(unsigned int)offs, block, res);
|
||||
|
||||
switch (res) {
|
||||
case BBT_BLOCK_GOOD:
|
||||
|
@ -46,6 +46,10 @@ struct nand_flash_dev nand_flash_ids[] = {
|
||||
{"SDTNRGAMA 64G 3.3V 8-bit",
|
||||
{ .id = {0x45, 0xde, 0x94, 0x93, 0x76, 0x50} },
|
||||
SZ_16K, SZ_8K, SZ_4M, 0, 6, 1280, NAND_ECC_INFO(40, SZ_1K) },
|
||||
{"H27UCG8T2ATR-BC 64G 3.3V 8-bit",
|
||||
{ .id = {0xad, 0xde, 0x94, 0xda, 0x74, 0xc4} },
|
||||
SZ_8K, SZ_8K, SZ_2M, 0, 6, 640, NAND_ECC_INFO(40, SZ_1K),
|
||||
4 },
|
||||
|
||||
LEGACY_ID_NAND("NAND 4MiB 5V 8-bit", 0x6B, 4, SZ_8K, SP_OPTIONS),
|
||||
LEGACY_ID_NAND("NAND 4MiB 3,3V 8-bit", 0xE3, 4, SZ_8K, SP_OPTIONS),
|
||||
|
@ -42,7 +42,7 @@ static const struct nand_sdr_timings onfi_sdr_timings[] = {
|
||||
.tRHZ_max = 200000,
|
||||
.tRLOH_min = 0,
|
||||
.tRP_min = 50000,
|
||||
.tRST_max = 250000000000,
|
||||
.tRST_max = 250000000000ULL,
|
||||
.tWB_max = 200000,
|
||||
.tRR_min = 40000,
|
||||
.tWC_min = 100000,
|
||||
|
@ -827,7 +827,7 @@ static int parse_badblocks(struct nandsim *ns, struct mtd_info *mtd)
|
||||
NS_ERR("invalid badblocks.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
offset = erase_block_no * ns->geom.secsz;
|
||||
offset = (loff_t)erase_block_no * ns->geom.secsz;
|
||||
if (mtd_block_markbad(mtd, offset)) {
|
||||
NS_ERR("invalid badblocks.\n");
|
||||
return -EINVAL;
|
||||
|
@ -203,7 +203,8 @@ static int ndfc_probe(struct platform_device *ofdev)
|
||||
struct ndfc_controller *ndfc;
|
||||
const __be32 *reg;
|
||||
u32 ccr;
|
||||
int err, len, cs;
|
||||
u32 cs;
|
||||
int err, len;
|
||||
|
||||
/* Read the reg property to get the chip select */
|
||||
reg = of_get_property(ofdev->dev.of_node, "reg", &len);
|
||||
|
@ -136,7 +136,6 @@
|
||||
|
||||
#define BADBLOCK_MARKER_LENGTH 2
|
||||
|
||||
#ifdef CONFIG_MTD_NAND_OMAP_BCH
|
||||
static u_char bch16_vector[] = {0xf5, 0x24, 0x1c, 0xd0, 0x61, 0xb3, 0xf1, 0x55,
|
||||
0x2e, 0x2c, 0x86, 0xa3, 0xed, 0x36, 0x1b, 0x78,
|
||||
0x48, 0x76, 0xa9, 0x3b, 0x97, 0xd1, 0x7a, 0x93,
|
||||
@ -144,7 +143,6 @@ static u_char bch16_vector[] = {0xf5, 0x24, 0x1c, 0xd0, 0x61, 0xb3, 0xf1, 0x55,
|
||||
static u_char bch8_vector[] = {0xf3, 0xdb, 0x14, 0x16, 0x8b, 0xd2, 0xbe, 0xcc,
|
||||
0xac, 0x6b, 0xff, 0x99, 0x7b};
|
||||
static u_char bch4_vector[] = {0x00, 0x6b, 0x31, 0xdd, 0x41, 0xbc, 0x10};
|
||||
#endif
|
||||
|
||||
/* oob info generated runtime depending on ecc algorithm and layout selected */
|
||||
static struct nand_ecclayout omap_oobinfo;
|
||||
@ -1292,7 +1290,6 @@ static int __maybe_unused omap_calculate_ecc_bch(struct mtd_info *mtd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MTD_NAND_OMAP_BCH
|
||||
/**
|
||||
* erased_sector_bitflips - count bit flips
|
||||
* @data: data sector buffer
|
||||
@ -1378,7 +1375,7 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data,
|
||||
erased_ecc_vec = bch16_vector;
|
||||
break;
|
||||
default:
|
||||
pr_err("invalid driver configuration\n");
|
||||
dev_err(&info->pdev->dev, "invalid driver configuration\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -1449,7 +1446,8 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data,
|
||||
err = 0;
|
||||
for (i = 0; i < eccsteps; i++) {
|
||||
if (err_vec[i].error_uncorrectable) {
|
||||
pr_err("nand: uncorrectable bit-flips found\n");
|
||||
dev_err(&info->pdev->dev,
|
||||
"uncorrectable bit-flips found\n");
|
||||
err = -EBADMSG;
|
||||
} else if (err_vec[i].error_reported) {
|
||||
for (j = 0; j < err_vec[i].error_count; j++) {
|
||||
@ -1486,8 +1484,9 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data,
|
||||
1 << bit_pos;
|
||||
}
|
||||
} else {
|
||||
pr_err("invalid bit-flip @ %d:%d\n",
|
||||
byte_pos, bit_pos);
|
||||
dev_err(&info->pdev->dev,
|
||||
"invalid bit-flip @ %d:%d\n",
|
||||
byte_pos, bit_pos);
|
||||
err = -EBADMSG;
|
||||
}
|
||||
}
|
||||
@ -1593,33 +1592,71 @@ static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
/**
|
||||
* is_elm_present - checks for presence of ELM module by scanning DT nodes
|
||||
* @omap_nand_info: NAND device structure containing platform data
|
||||
* @bch_type: 0x0=BCH4, 0x1=BCH8, 0x2=BCH16
|
||||
*/
|
||||
static int is_elm_present(struct omap_nand_info *info,
|
||||
struct device_node *elm_node, enum bch_ecc bch_type)
|
||||
static bool is_elm_present(struct omap_nand_info *info,
|
||||
struct device_node *elm_node)
|
||||
{
|
||||
struct platform_device *pdev;
|
||||
struct nand_ecc_ctrl *ecc = &info->nand.ecc;
|
||||
int err;
|
||||
|
||||
/* check whether elm-id is passed via DT */
|
||||
if (!elm_node) {
|
||||
pr_err("nand: error: ELM DT node not found\n");
|
||||
return -ENODEV;
|
||||
dev_err(&info->pdev->dev, "ELM devicetree node not found\n");
|
||||
return false;
|
||||
}
|
||||
pdev = of_find_device_by_node(elm_node);
|
||||
/* check whether ELM device is registered */
|
||||
if (!pdev) {
|
||||
pr_err("nand: error: ELM device not found\n");
|
||||
return -ENODEV;
|
||||
dev_err(&info->pdev->dev, "ELM device not found\n");
|
||||
return false;
|
||||
}
|
||||
/* ELM module available, now configure it */
|
||||
info->elm_dev = &pdev->dev;
|
||||
err = elm_config(info->elm_dev, bch_type,
|
||||
(info->mtd.writesize / ecc->size), ecc->size, ecc->bytes);
|
||||
|
||||
return err;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool omap2_nand_ecc_check(struct omap_nand_info *info,
|
||||
struct omap_nand_platform_data *pdata)
|
||||
{
|
||||
bool ecc_needs_bch, ecc_needs_omap_bch, ecc_needs_elm;
|
||||
|
||||
switch (info->ecc_opt) {
|
||||
case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW:
|
||||
case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
|
||||
ecc_needs_omap_bch = false;
|
||||
ecc_needs_bch = true;
|
||||
ecc_needs_elm = false;
|
||||
break;
|
||||
case OMAP_ECC_BCH4_CODE_HW:
|
||||
case OMAP_ECC_BCH8_CODE_HW:
|
||||
case OMAP_ECC_BCH16_CODE_HW:
|
||||
ecc_needs_omap_bch = true;
|
||||
ecc_needs_bch = false;
|
||||
ecc_needs_elm = true;
|
||||
break;
|
||||
default:
|
||||
ecc_needs_omap_bch = false;
|
||||
ecc_needs_bch = false;
|
||||
ecc_needs_elm = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ecc_needs_bch && !IS_ENABLED(CONFIG_MTD_NAND_ECC_BCH)) {
|
||||
dev_err(&info->pdev->dev,
|
||||
"CONFIG_MTD_NAND_ECC_BCH not enabled\n");
|
||||
return false;
|
||||
}
|
||||
if (ecc_needs_omap_bch && !IS_ENABLED(CONFIG_MTD_NAND_OMAP_BCH)) {
|
||||
dev_err(&info->pdev->dev,
|
||||
"CONFIG_MTD_NAND_OMAP_BCH not enabled\n");
|
||||
return false;
|
||||
}
|
||||
if (ecc_needs_elm && !is_elm_present(info, pdata->elm_of_node)) {
|
||||
dev_err(&info->pdev->dev, "ELM not available\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif /* CONFIG_MTD_NAND_ECC_BCH */
|
||||
|
||||
static int omap_nand_probe(struct platform_device *pdev)
|
||||
{
|
||||
@ -1663,7 +1700,6 @@ static int omap_nand_probe(struct platform_device *pdev)
|
||||
mtd->owner = THIS_MODULE;
|
||||
nand_chip = &info->nand;
|
||||
nand_chip->ecc.priv = NULL;
|
||||
nand_chip->options |= NAND_SKIP_BBTSCAN;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
nand_chip->IO_ADDR_R = devm_ioremap_resource(&pdev->dev, res);
|
||||
@ -1692,17 +1728,22 @@ static int omap_nand_probe(struct platform_device *pdev)
|
||||
nand_chip->chip_delay = 50;
|
||||
}
|
||||
|
||||
if (pdata->flash_bbt)
|
||||
nand_chip->bbt_options |= NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB;
|
||||
else
|
||||
nand_chip->options |= NAND_SKIP_BBTSCAN;
|
||||
|
||||
/* scan NAND device connected to chip controller */
|
||||
nand_chip->options |= pdata->devsize & NAND_BUSWIDTH_16;
|
||||
if (nand_scan_ident(mtd, 1, NULL)) {
|
||||
pr_err("nand device scan failed, may be bus-width mismatch\n");
|
||||
dev_err(&info->pdev->dev, "scan failed, may be bus-width mismatch\n");
|
||||
err = -ENXIO;
|
||||
goto return_error;
|
||||
}
|
||||
|
||||
/* check for small page devices */
|
||||
if ((mtd->oobsize < 64) && (pdata->ecc_opt != OMAP_ECC_HAM1_CODE_HW)) {
|
||||
pr_err("small page devices are not supported\n");
|
||||
dev_err(&info->pdev->dev, "small page devices are not supported\n");
|
||||
err = -EINVAL;
|
||||
goto return_error;
|
||||
}
|
||||
@ -1793,6 +1834,11 @@ static int omap_nand_probe(struct platform_device *pdev)
|
||||
goto return_error;
|
||||
}
|
||||
|
||||
if (!omap2_nand_ecc_check(info, pdata)) {
|
||||
err = -EINVAL;
|
||||
goto return_error;
|
||||
}
|
||||
|
||||
/* populate MTD interface based on ECC scheme */
|
||||
ecclayout = &omap_oobinfo;
|
||||
switch (info->ecc_opt) {
|
||||
@ -1825,7 +1871,6 @@ static int omap_nand_probe(struct platform_device *pdev)
|
||||
break;
|
||||
|
||||
case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW:
|
||||
#ifdef CONFIG_MTD_NAND_ECC_BCH
|
||||
pr_info("nand: using OMAP_ECC_BCH4_CODE_HW_DETECTION_SW\n");
|
||||
nand_chip->ecc.mode = NAND_ECC_HW;
|
||||
nand_chip->ecc.size = 512;
|
||||
@ -1853,18 +1898,13 @@ static int omap_nand_probe(struct platform_device *pdev)
|
||||
nand_chip->ecc.bytes,
|
||||
&ecclayout);
|
||||
if (!nand_chip->ecc.priv) {
|
||||
pr_err("nand: error: unable to use s/w BCH library\n");
|
||||
dev_err(&info->pdev->dev, "unable to use BCH library\n");
|
||||
err = -EINVAL;
|
||||
goto return_error;
|
||||
}
|
||||
break;
|
||||
#else
|
||||
pr_err("nand: error: CONFIG_MTD_NAND_ECC_BCH not enabled\n");
|
||||
err = -EINVAL;
|
||||
goto return_error;
|
||||
#endif
|
||||
|
||||
case OMAP_ECC_BCH4_CODE_HW:
|
||||
#ifdef CONFIG_MTD_NAND_OMAP_BCH
|
||||
pr_info("nand: using OMAP_ECC_BCH4_CODE_HW ECC scheme\n");
|
||||
nand_chip->ecc.mode = NAND_ECC_HW;
|
||||
nand_chip->ecc.size = 512;
|
||||
@ -1886,21 +1926,15 @@ static int omap_nand_probe(struct platform_device *pdev)
|
||||
/* reserved marker already included in ecclayout->eccbytes */
|
||||
ecclayout->oobfree->offset =
|
||||
ecclayout->eccpos[ecclayout->eccbytes - 1] + 1;
|
||||
/* This ECC scheme requires ELM H/W block */
|
||||
if (is_elm_present(info, pdata->elm_of_node, BCH4_ECC) < 0) {
|
||||
pr_err("nand: error: could not initialize ELM\n");
|
||||
err = -ENODEV;
|
||||
|
||||
err = elm_config(info->elm_dev, BCH4_ECC,
|
||||
info->mtd.writesize / nand_chip->ecc.size,
|
||||
nand_chip->ecc.size, nand_chip->ecc.bytes);
|
||||
if (err < 0)
|
||||
goto return_error;
|
||||
}
|
||||
break;
|
||||
#else
|
||||
pr_err("nand: error: CONFIG_MTD_NAND_OMAP_BCH not enabled\n");
|
||||
err = -EINVAL;
|
||||
goto return_error;
|
||||
#endif
|
||||
|
||||
case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
|
||||
#ifdef CONFIG_MTD_NAND_ECC_BCH
|
||||
pr_info("nand: using OMAP_ECC_BCH8_CODE_HW_DETECTION_SW\n");
|
||||
nand_chip->ecc.mode = NAND_ECC_HW;
|
||||
nand_chip->ecc.size = 512;
|
||||
@ -1928,19 +1962,13 @@ static int omap_nand_probe(struct platform_device *pdev)
|
||||
nand_chip->ecc.bytes,
|
||||
&ecclayout);
|
||||
if (!nand_chip->ecc.priv) {
|
||||
pr_err("nand: error: unable to use s/w BCH library\n");
|
||||
dev_err(&info->pdev->dev, "unable to use BCH library\n");
|
||||
err = -EINVAL;
|
||||
goto return_error;
|
||||
}
|
||||
break;
|
||||
#else
|
||||
pr_err("nand: error: CONFIG_MTD_NAND_ECC_BCH not enabled\n");
|
||||
err = -EINVAL;
|
||||
goto return_error;
|
||||
#endif
|
||||
|
||||
case OMAP_ECC_BCH8_CODE_HW:
|
||||
#ifdef CONFIG_MTD_NAND_OMAP_BCH
|
||||
pr_info("nand: using OMAP_ECC_BCH8_CODE_HW ECC scheme\n");
|
||||
nand_chip->ecc.mode = NAND_ECC_HW;
|
||||
nand_chip->ecc.size = 512;
|
||||
@ -1952,12 +1980,13 @@ static int omap_nand_probe(struct platform_device *pdev)
|
||||
nand_chip->ecc.calculate = omap_calculate_ecc_bch;
|
||||
nand_chip->ecc.read_page = omap_read_page_bch;
|
||||
nand_chip->ecc.write_page = omap_write_page_bch;
|
||||
/* This ECC scheme requires ELM H/W block */
|
||||
err = is_elm_present(info, pdata->elm_of_node, BCH8_ECC);
|
||||
if (err < 0) {
|
||||
pr_err("nand: error: could not initialize ELM\n");
|
||||
|
||||
err = elm_config(info->elm_dev, BCH8_ECC,
|
||||
info->mtd.writesize / nand_chip->ecc.size,
|
||||
nand_chip->ecc.size, nand_chip->ecc.bytes);
|
||||
if (err < 0)
|
||||
goto return_error;
|
||||
}
|
||||
|
||||
/* define ECC layout */
|
||||
ecclayout->eccbytes = nand_chip->ecc.bytes *
|
||||
(mtd->writesize /
|
||||
@ -1969,14 +1998,8 @@ static int omap_nand_probe(struct platform_device *pdev)
|
||||
ecclayout->oobfree->offset =
|
||||
ecclayout->eccpos[ecclayout->eccbytes - 1] + 1;
|
||||
break;
|
||||
#else
|
||||
pr_err("nand: error: CONFIG_MTD_NAND_OMAP_BCH not enabled\n");
|
||||
err = -EINVAL;
|
||||
goto return_error;
|
||||
#endif
|
||||
|
||||
case OMAP_ECC_BCH16_CODE_HW:
|
||||
#ifdef CONFIG_MTD_NAND_OMAP_BCH
|
||||
pr_info("using OMAP_ECC_BCH16_CODE_HW ECC scheme\n");
|
||||
nand_chip->ecc.mode = NAND_ECC_HW;
|
||||
nand_chip->ecc.size = 512;
|
||||
@ -1987,12 +2010,13 @@ static int omap_nand_probe(struct platform_device *pdev)
|
||||
nand_chip->ecc.calculate = omap_calculate_ecc_bch;
|
||||
nand_chip->ecc.read_page = omap_read_page_bch;
|
||||
nand_chip->ecc.write_page = omap_write_page_bch;
|
||||
/* This ECC scheme requires ELM H/W block */
|
||||
err = is_elm_present(info, pdata->elm_of_node, BCH16_ECC);
|
||||
if (err < 0) {
|
||||
pr_err("ELM is required for this ECC scheme\n");
|
||||
|
||||
err = elm_config(info->elm_dev, BCH16_ECC,
|
||||
info->mtd.writesize / nand_chip->ecc.size,
|
||||
nand_chip->ecc.size, nand_chip->ecc.bytes);
|
||||
if (err < 0)
|
||||
goto return_error;
|
||||
}
|
||||
|
||||
/* define ECC layout */
|
||||
ecclayout->eccbytes = nand_chip->ecc.bytes *
|
||||
(mtd->writesize /
|
||||
@ -2004,13 +2028,8 @@ static int omap_nand_probe(struct platform_device *pdev)
|
||||
ecclayout->oobfree->offset =
|
||||
ecclayout->eccpos[ecclayout->eccbytes - 1] + 1;
|
||||
break;
|
||||
#else
|
||||
pr_err("nand: error: CONFIG_MTD_NAND_OMAP_BCH not enabled\n");
|
||||
err = -EINVAL;
|
||||
goto return_error;
|
||||
#endif
|
||||
default:
|
||||
pr_err("nand: error: invalid or unsupported ECC scheme\n");
|
||||
dev_err(&info->pdev->dev, "invalid or unsupported ECC scheme\n");
|
||||
err = -EINVAL;
|
||||
goto return_error;
|
||||
}
|
||||
@ -2022,8 +2041,9 @@ static int omap_nand_probe(struct platform_device *pdev)
|
||||
ecclayout->oobfree->length = mtd->oobsize - ecclayout->oobfree->offset;
|
||||
/* check if NAND device's OOB is enough to store ECC signatures */
|
||||
if (mtd->oobsize < (ecclayout->eccbytes + BADBLOCK_MARKER_LENGTH)) {
|
||||
pr_err("not enough OOB bytes required = %d, available=%d\n",
|
||||
ecclayout->eccbytes, mtd->oobsize);
|
||||
dev_err(&info->pdev->dev,
|
||||
"not enough OOB bytes required = %d, available=%d\n",
|
||||
ecclayout->eccbytes, mtd->oobsize);
|
||||
err = -EINVAL;
|
||||
goto return_error;
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ struct sm_oob {
|
||||
uint8_t ecc2[3];
|
||||
uint8_t lba_copy2[2];
|
||||
uint8_t ecc1[3];
|
||||
} __attribute__((packed));
|
||||
} __packed;
|
||||
|
||||
|
||||
/* one sector is always 512 bytes, but it can consist of two nand pages */
|
||||
|
@ -1058,7 +1058,7 @@ static int sm_write(struct mtd_blktrans_dev *dev,
|
||||
{
|
||||
struct sm_ftl *ftl = dev->priv;
|
||||
struct ftl_zone *zone;
|
||||
int error, zone_num, block, boffset;
|
||||
int error = 0, zone_num, block, boffset;
|
||||
|
||||
BUG_ON(ftl->readonly);
|
||||
sm_break_offset(ftl, sec_no << 9, &zone_num, &block, &boffset);
|
||||
|
@ -7,6 +7,20 @@ menuconfig MTD_SPI_NOR
|
||||
|
||||
if MTD_SPI_NOR
|
||||
|
||||
config MTD_SPI_NOR_USE_4K_SECTORS
|
||||
bool "Use small 4096 B erase sectors"
|
||||
default y
|
||||
help
|
||||
Many flash memories support erasing small (4096 B) sectors. Depending
|
||||
on the usage this feature may provide performance gain in comparison
|
||||
to erasing whole blocks (32/64 KiB).
|
||||
Changing a small part of the flash's contents is usually faster with
|
||||
small sectors. On the other hand erasing should be faster when using
|
||||
64 KiB block instead of 16 × 4 KiB sectors.
|
||||
|
||||
Please note that some tools/drivers/filesystems may not work with
|
||||
4096 B erase size (e.g. UBIFS requires 15 KiB as a minimum).
|
||||
|
||||
config SPI_FSL_QUADSPI
|
||||
tristate "Freescale Quad SPI controller"
|
||||
depends on ARCH_MXC
|
||||
|
@ -611,6 +611,7 @@ const struct spi_device_id spi_nor_ids[] = {
|
||||
{ "m25px32-s0", INFO(0x207316, 0, 64 * 1024, 64, SECT_4K) },
|
||||
{ "m25px32-s1", INFO(0x206316, 0, 64 * 1024, 64, SECT_4K) },
|
||||
{ "m25px64", INFO(0x207117, 0, 64 * 1024, 128, 0) },
|
||||
{ "m25px80", INFO(0x207114, 0, 64 * 1024, 16, 0) },
|
||||
|
||||
/* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */
|
||||
{ "w25x10", INFO(0xef3011, 0, 64 * 1024, 2, SECT_4K) },
|
||||
@ -623,7 +624,6 @@ const struct spi_device_id spi_nor_ids[] = {
|
||||
{ "w25q32dw", INFO(0xef6016, 0, 64 * 1024, 64, SECT_4K) },
|
||||
{ "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) },
|
||||
{ "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) },
|
||||
{ "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) },
|
||||
{ "w25q80", INFO(0xef5014, 0, 64 * 1024, 16, SECT_4K) },
|
||||
{ "w25q80bl", INFO(0xef4014, 0, 64 * 1024, 16, SECT_4K) },
|
||||
{ "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) },
|
||||
@ -671,11 +671,6 @@ static const struct spi_device_id *spi_nor_read_id(struct spi_nor *nor)
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
static const struct spi_device_id *jedec_probe(struct spi_nor *nor)
|
||||
{
|
||||
return nor->read_id(nor);
|
||||
}
|
||||
|
||||
static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len,
|
||||
size_t *retlen, u_char *buf)
|
||||
{
|
||||
@ -920,7 +915,6 @@ int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id,
|
||||
enum read_mode mode)
|
||||
{
|
||||
struct flash_info *info;
|
||||
struct flash_platform_data *data;
|
||||
struct device *dev = nor->dev;
|
||||
struct mtd_info *mtd = nor->mtd;
|
||||
struct device_node *np = dev->of_node;
|
||||
@ -931,34 +925,12 @@ int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Platform data helps sort out which chip type we have, as
|
||||
* well as how this board partitions it. If we don't have
|
||||
* a chip ID, try the JEDEC id commands; they'll work for most
|
||||
* newer chips, even if we don't recognize the particular chip.
|
||||
*/
|
||||
data = dev_get_platdata(dev);
|
||||
if (data && data->type) {
|
||||
const struct spi_device_id *plat_id;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(spi_nor_ids) - 1; i++) {
|
||||
plat_id = &spi_nor_ids[i];
|
||||
if (strcmp(data->type, plat_id->name))
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
|
||||
if (i < ARRAY_SIZE(spi_nor_ids) - 1)
|
||||
id = plat_id;
|
||||
else
|
||||
dev_warn(dev, "unrecognized id %s\n", data->type);
|
||||
}
|
||||
|
||||
info = (void *)id->driver_data;
|
||||
|
||||
if (info->jedec_id) {
|
||||
const struct spi_device_id *jid;
|
||||
|
||||
jid = jedec_probe(nor);
|
||||
jid = nor->read_id(nor);
|
||||
if (IS_ERR(jid)) {
|
||||
return PTR_ERR(jid);
|
||||
} else if (jid != id) {
|
||||
@ -990,11 +962,8 @@ int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id,
|
||||
write_sr(nor, 0);
|
||||
}
|
||||
|
||||
if (data && data->name)
|
||||
mtd->name = data->name;
|
||||
else
|
||||
if (!mtd->name)
|
||||
mtd->name = dev_name(dev);
|
||||
|
||||
mtd->type = MTD_NORFLASH;
|
||||
mtd->writesize = 1;
|
||||
mtd->flags = MTD_CAP_NORFLASH;
|
||||
@ -1018,6 +987,7 @@ int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id,
|
||||
nor->wait_till_ready == spi_nor_wait_till_ready)
|
||||
nor->wait_till_ready = spi_nor_wait_till_fsr_ready;
|
||||
|
||||
#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;
|
||||
@ -1025,7 +995,9 @@ int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id,
|
||||
} else if (info->flags & SECT_4K_PMC) {
|
||||
nor->erase_opcode = SPINOR_OP_BE_4K_PMC;
|
||||
mtd->erasesize = 4096;
|
||||
} else {
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
nor->erase_opcode = SPINOR_OP_SE;
|
||||
mtd->erasesize = info->sector_size;
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ int mtdtest_erase_eraseblock(struct mtd_info *mtd, unsigned int ebnum)
|
||||
{
|
||||
int err;
|
||||
struct erase_info ei;
|
||||
loff_t addr = ebnum * mtd->erasesize;
|
||||
loff_t addr = (loff_t)ebnum * mtd->erasesize;
|
||||
|
||||
memset(&ei, 0, sizeof(struct erase_info));
|
||||
ei.mtd = mtd;
|
||||
@ -33,7 +33,7 @@ int mtdtest_erase_eraseblock(struct mtd_info *mtd, unsigned int ebnum)
|
||||
static int is_block_bad(struct mtd_info *mtd, unsigned int ebnum)
|
||||
{
|
||||
int ret;
|
||||
loff_t addr = ebnum * mtd->erasesize;
|
||||
loff_t addr = (loff_t)ebnum * mtd->erasesize;
|
||||
|
||||
ret = mtd_block_isbad(mtd, addr);
|
||||
if (ret)
|
||||
|
@ -364,7 +364,7 @@ static int __init mtd_nandbiterrs_init(void)
|
||||
|
||||
pr_info("Device uses %d subpages of %d bytes\n", subcount, subsize);
|
||||
|
||||
offset = page_offset * mtd->writesize;
|
||||
offset = (loff_t)page_offset * mtd->writesize;
|
||||
eraseblock = mtd_div_by_eb(offset, mtd);
|
||||
|
||||
pr_info("Using page=%u, offset=%llu, eraseblock=%u\n",
|
||||
|
@ -120,7 +120,7 @@ static int verify_eraseblock(int ebnum)
|
||||
int i;
|
||||
struct mtd_oob_ops ops;
|
||||
int err = 0;
|
||||
loff_t addr = ebnum * mtd->erasesize;
|
||||
loff_t addr = (loff_t)ebnum * mtd->erasesize;
|
||||
|
||||
prandom_bytes_state(&rnd_state, writebuf, use_len_max * pgcnt);
|
||||
for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) {
|
||||
@ -214,7 +214,7 @@ static int verify_eraseblock_in_one_go(int ebnum)
|
||||
{
|
||||
struct mtd_oob_ops ops;
|
||||
int err = 0;
|
||||
loff_t addr = ebnum * mtd->erasesize;
|
||||
loff_t addr = (loff_t)ebnum * mtd->erasesize;
|
||||
size_t len = mtd->ecclayout->oobavail * pgcnt;
|
||||
|
||||
prandom_bytes_state(&rnd_state, writebuf, len);
|
||||
@ -568,7 +568,7 @@ static int __init mtd_oobtest_init(void)
|
||||
size_t sz = mtd->ecclayout->oobavail;
|
||||
if (bbt[i] || bbt[i + 1])
|
||||
continue;
|
||||
addr = (i + 1) * mtd->erasesize - mtd->writesize;
|
||||
addr = (loff_t)(i + 1) * mtd->erasesize - mtd->writesize;
|
||||
prandom_bytes_state(&rnd_state, writebuf, sz * cnt);
|
||||
for (pg = 0; pg < cnt; ++pg) {
|
||||
ops.mode = MTD_OPS_AUTO_OOB;
|
||||
@ -598,7 +598,7 @@ static int __init mtd_oobtest_init(void)
|
||||
continue;
|
||||
prandom_bytes_state(&rnd_state, writebuf,
|
||||
mtd->ecclayout->oobavail * 2);
|
||||
addr = (i + 1) * mtd->erasesize - mtd->writesize;
|
||||
addr = (loff_t)(i + 1) * mtd->erasesize - mtd->writesize;
|
||||
ops.mode = MTD_OPS_AUTO_OOB;
|
||||
ops.len = 0;
|
||||
ops.retlen = 0;
|
||||
|
@ -52,7 +52,7 @@ static struct rnd_state rnd_state;
|
||||
|
||||
static int write_eraseblock(int ebnum)
|
||||
{
|
||||
loff_t addr = ebnum * mtd->erasesize;
|
||||
loff_t addr = (loff_t)ebnum * mtd->erasesize;
|
||||
|
||||
prandom_bytes_state(&rnd_state, writebuf, mtd->erasesize);
|
||||
cond_resched();
|
||||
@ -64,7 +64,7 @@ static int verify_eraseblock(int ebnum)
|
||||
uint32_t j;
|
||||
int err = 0, i;
|
||||
loff_t addr0, addrn;
|
||||
loff_t addr = ebnum * mtd->erasesize;
|
||||
loff_t addr = (loff_t)ebnum * mtd->erasesize;
|
||||
|
||||
addr0 = 0;
|
||||
for (i = 0; i < ebcnt && bbt[i]; ++i)
|
||||
|
@ -47,7 +47,7 @@ static int pgcnt;
|
||||
static int read_eraseblock_by_page(int ebnum)
|
||||
{
|
||||
int i, ret, err = 0;
|
||||
loff_t addr = ebnum * mtd->erasesize;
|
||||
loff_t addr = (loff_t)ebnum * mtd->erasesize;
|
||||
void *buf = iobuf;
|
||||
void *oobbuf = iobuf1;
|
||||
|
||||
|
@ -55,7 +55,7 @@ static int multiblock_erase(int ebnum, int blocks)
|
||||
{
|
||||
int err;
|
||||
struct erase_info ei;
|
||||
loff_t addr = ebnum * mtd->erasesize;
|
||||
loff_t addr = (loff_t)ebnum * mtd->erasesize;
|
||||
|
||||
memset(&ei, 0, sizeof(struct erase_info));
|
||||
ei.mtd = mtd;
|
||||
@ -80,7 +80,7 @@ static int multiblock_erase(int ebnum, int blocks)
|
||||
|
||||
static int write_eraseblock(int ebnum)
|
||||
{
|
||||
loff_t addr = ebnum * mtd->erasesize;
|
||||
loff_t addr = (loff_t)ebnum * mtd->erasesize;
|
||||
|
||||
return mtdtest_write(mtd, addr, mtd->erasesize, iobuf);
|
||||
}
|
||||
@ -88,7 +88,7 @@ static int write_eraseblock(int ebnum)
|
||||
static int write_eraseblock_by_page(int ebnum)
|
||||
{
|
||||
int i, err = 0;
|
||||
loff_t addr = ebnum * mtd->erasesize;
|
||||
loff_t addr = (loff_t)ebnum * mtd->erasesize;
|
||||
void *buf = iobuf;
|
||||
|
||||
for (i = 0; i < pgcnt; i++) {
|
||||
@ -106,7 +106,7 @@ static int write_eraseblock_by_2pages(int ebnum)
|
||||
{
|
||||
size_t sz = pgsize * 2;
|
||||
int i, n = pgcnt / 2, err = 0;
|
||||
loff_t addr = ebnum * mtd->erasesize;
|
||||
loff_t addr = (loff_t)ebnum * mtd->erasesize;
|
||||
void *buf = iobuf;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
@ -124,7 +124,7 @@ static int write_eraseblock_by_2pages(int ebnum)
|
||||
|
||||
static int read_eraseblock(int ebnum)
|
||||
{
|
||||
loff_t addr = ebnum * mtd->erasesize;
|
||||
loff_t addr = (loff_t)ebnum * mtd->erasesize;
|
||||
|
||||
return mtdtest_read(mtd, addr, mtd->erasesize, iobuf);
|
||||
}
|
||||
@ -132,7 +132,7 @@ static int read_eraseblock(int ebnum)
|
||||
static int read_eraseblock_by_page(int ebnum)
|
||||
{
|
||||
int i, err = 0;
|
||||
loff_t addr = ebnum * mtd->erasesize;
|
||||
loff_t addr = (loff_t)ebnum * mtd->erasesize;
|
||||
void *buf = iobuf;
|
||||
|
||||
for (i = 0; i < pgcnt; i++) {
|
||||
@ -150,7 +150,7 @@ static int read_eraseblock_by_2pages(int ebnum)
|
||||
{
|
||||
size_t sz = pgsize * 2;
|
||||
int i, n = pgcnt / 2, err = 0;
|
||||
loff_t addr = ebnum * mtd->erasesize;
|
||||
loff_t addr = (loff_t)ebnum * mtd->erasesize;
|
||||
void *buf = iobuf;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
|
@ -57,7 +57,7 @@ static int write_eraseblock(int ebnum)
|
||||
{
|
||||
size_t written;
|
||||
int err = 0;
|
||||
loff_t addr = ebnum * mtd->erasesize;
|
||||
loff_t addr = (loff_t)ebnum * mtd->erasesize;
|
||||
|
||||
prandom_bytes_state(&rnd_state, writebuf, subpgsize);
|
||||
err = mtd_write(mtd, addr, subpgsize, &written, writebuf);
|
||||
@ -92,7 +92,7 @@ static int write_eraseblock2(int ebnum)
|
||||
{
|
||||
size_t written;
|
||||
int err = 0, k;
|
||||
loff_t addr = ebnum * mtd->erasesize;
|
||||
loff_t addr = (loff_t)ebnum * mtd->erasesize;
|
||||
|
||||
for (k = 1; k < 33; ++k) {
|
||||
if (addr + (subpgsize * k) > (ebnum + 1) * mtd->erasesize)
|
||||
@ -131,7 +131,7 @@ static int verify_eraseblock(int ebnum)
|
||||
{
|
||||
size_t read;
|
||||
int err = 0;
|
||||
loff_t addr = ebnum * mtd->erasesize;
|
||||
loff_t addr = (loff_t)ebnum * mtd->erasesize;
|
||||
|
||||
prandom_bytes_state(&rnd_state, writebuf, subpgsize);
|
||||
clear_data(readbuf, subpgsize);
|
||||
@ -192,7 +192,7 @@ static int verify_eraseblock2(int ebnum)
|
||||
{
|
||||
size_t read;
|
||||
int err = 0, k;
|
||||
loff_t addr = ebnum * mtd->erasesize;
|
||||
loff_t addr = (loff_t)ebnum * mtd->erasesize;
|
||||
|
||||
for (k = 1; k < 33; ++k) {
|
||||
if (addr + (subpgsize * k) > (ebnum + 1) * mtd->erasesize)
|
||||
@ -227,7 +227,7 @@ static int verify_eraseblock_ff(int ebnum)
|
||||
uint32_t j;
|
||||
size_t read;
|
||||
int err = 0;
|
||||
loff_t addr = ebnum * mtd->erasesize;
|
||||
loff_t addr = (loff_t)ebnum * mtd->erasesize;
|
||||
|
||||
memset(writebuf, 0xff, subpgsize);
|
||||
for (j = 0; j < mtd->erasesize / subpgsize; ++j) {
|
||||
|
@ -153,7 +153,7 @@ struct cfi_ident {
|
||||
uint16_t MaxBufWriteSize;
|
||||
uint8_t NumEraseRegions;
|
||||
uint32_t EraseRegionInfo[0]; /* Not host ordered */
|
||||
} __attribute__((packed));
|
||||
} __packed;
|
||||
|
||||
/* Extended Query Structure for both PRI and ALT */
|
||||
|
||||
@ -161,7 +161,7 @@ struct cfi_extquery {
|
||||
uint8_t pri[3];
|
||||
uint8_t MajorVersion;
|
||||
uint8_t MinorVersion;
|
||||
} __attribute__((packed));
|
||||
} __packed;
|
||||
|
||||
/* Vendor-Specific PRI for Intel/Sharp Extended Command Set (0x0001) */
|
||||
|
||||
@ -180,7 +180,7 @@ struct cfi_pri_intelext {
|
||||
uint8_t FactProtRegSize;
|
||||
uint8_t UserProtRegSize;
|
||||
uint8_t extra[0];
|
||||
} __attribute__((packed));
|
||||
} __packed;
|
||||
|
||||
struct cfi_intelext_otpinfo {
|
||||
uint32_t ProtRegAddr;
|
||||
@ -188,7 +188,7 @@ struct cfi_intelext_otpinfo {
|
||||
uint8_t FactProtRegSize;
|
||||
uint16_t UserGroups;
|
||||
uint8_t UserProtRegSize;
|
||||
} __attribute__((packed));
|
||||
} __packed;
|
||||
|
||||
struct cfi_intelext_blockinfo {
|
||||
uint16_t NumIdentBlocks;
|
||||
@ -196,7 +196,7 @@ struct cfi_intelext_blockinfo {
|
||||
uint16_t MinBlockEraseCycles;
|
||||
uint8_t BitsPerCell;
|
||||
uint8_t BlockCap;
|
||||
} __attribute__((packed));
|
||||
} __packed;
|
||||
|
||||
struct cfi_intelext_regioninfo {
|
||||
uint16_t NumIdentPartitions;
|
||||
@ -205,7 +205,7 @@ struct cfi_intelext_regioninfo {
|
||||
uint8_t NumOpAllowedSimEraMode;
|
||||
uint8_t NumBlockTypes;
|
||||
struct cfi_intelext_blockinfo BlockTypes[1];
|
||||
} __attribute__((packed));
|
||||
} __packed;
|
||||
|
||||
struct cfi_intelext_programming_regioninfo {
|
||||
uint8_t ProgRegShift;
|
||||
@ -214,7 +214,7 @@ struct cfi_intelext_programming_regioninfo {
|
||||
uint8_t Reserved2;
|
||||
uint8_t ControlInvalid;
|
||||
uint8_t Reserved3;
|
||||
} __attribute__((packed));
|
||||
} __packed;
|
||||
|
||||
/* Vendor-Specific PRI for AMD/Fujitsu Extended Command Set (0x0002) */
|
||||
|
||||
@ -233,7 +233,7 @@ struct cfi_pri_amdstd {
|
||||
uint8_t VppMin;
|
||||
uint8_t VppMax;
|
||||
uint8_t TopBottom;
|
||||
} __attribute__((packed));
|
||||
} __packed;
|
||||
|
||||
/* Vendor-Specific PRI for Atmel chips (command set 0x0002) */
|
||||
|
||||
@ -245,18 +245,18 @@ struct cfi_pri_atmel {
|
||||
uint8_t BottomBoot;
|
||||
uint8_t BurstMode;
|
||||
uint8_t PageMode;
|
||||
} __attribute__((packed));
|
||||
} __packed;
|
||||
|
||||
struct cfi_pri_query {
|
||||
uint8_t NumFields;
|
||||
uint32_t ProtField[1]; /* Not host ordered */
|
||||
} __attribute__((packed));
|
||||
} __packed;
|
||||
|
||||
struct cfi_bri_query {
|
||||
uint8_t PageModeReadCap;
|
||||
uint8_t NumFields;
|
||||
uint32_t ConfField[1]; /* Not host ordered */
|
||||
} __attribute__((packed));
|
||||
} __packed;
|
||||
|
||||
#define P_ID_NONE 0x0000
|
||||
#define P_ID_INTEL_EXT 0x0001
|
||||
|
@ -587,6 +587,11 @@ struct nand_buffers {
|
||||
* @ecc_step_ds: [INTERN] ECC step required by the @ecc_strength_ds,
|
||||
* also from the datasheet. It is the recommended ECC step
|
||||
* size, if known; if unknown, set to zero.
|
||||
* @onfi_timing_mode_default: [INTERN] default ONFI timing mode. This field is
|
||||
* either deduced from the datasheet if the NAND
|
||||
* chip is not ONFI compliant or set to 0 if it is
|
||||
* (an ONFI chip is always configured in mode 0
|
||||
* after a NAND reset)
|
||||
* @numchips: [INTERN] number of physical chips
|
||||
* @chipsize: [INTERN] the size of one chip for multichip arrays
|
||||
* @pagemask: [INTERN] page number mask = number of (pages / chip) - 1
|
||||
@ -671,6 +676,7 @@ struct nand_chip {
|
||||
uint8_t bits_per_cell;
|
||||
uint16_t ecc_strength_ds;
|
||||
uint16_t ecc_step_ds;
|
||||
int onfi_timing_mode_default;
|
||||
int badblockpos;
|
||||
int badblockbits;
|
||||
|
||||
@ -766,12 +772,17 @@ struct nand_chip {
|
||||
* @options: stores various chip bit options
|
||||
* @id_len: The valid length of the @id.
|
||||
* @oobsize: OOB size
|
||||
* @ecc: ECC correctability and step information from the datasheet.
|
||||
* @ecc.strength_ds: The ECC correctability from the datasheet, same as the
|
||||
* @ecc_strength_ds in nand_chip{}.
|
||||
* @ecc.step_ds: The ECC step required by the @ecc.strength_ds, same as the
|
||||
* @ecc_step_ds in nand_chip{}, also from the datasheet.
|
||||
* For example, the "4bit ECC for each 512Byte" can be set with
|
||||
* NAND_ECC_INFO(4, 512).
|
||||
* @onfi_timing_mode_default: the default ONFI timing mode entered after a NAND
|
||||
* reset. Should be deduced from timings described
|
||||
* in the datasheet.
|
||||
*
|
||||
*/
|
||||
struct nand_flash_dev {
|
||||
char *name;
|
||||
@ -792,6 +803,7 @@ struct nand_flash_dev {
|
||||
uint16_t strength_ds;
|
||||
uint16_t step_ds;
|
||||
} ecc;
|
||||
int onfi_timing_mode_default;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -42,8 +42,24 @@ struct elm_errorvec {
|
||||
int error_loc[16];
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_MTD_NAND_OMAP_BCH)
|
||||
void elm_decode_bch_error_page(struct device *dev, u8 *ecc_calc,
|
||||
struct elm_errorvec *err_vec);
|
||||
int elm_config(struct device *dev, enum bch_ecc bch_type,
|
||||
int ecc_steps, int ecc_step_size, int ecc_syndrome_size);
|
||||
#else
|
||||
static inline void
|
||||
elm_decode_bch_error_page(struct device *dev, u8 *ecc_calc,
|
||||
struct elm_errorvec *err_vec)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int elm_config(struct device *dev, enum bch_ecc bch_type,
|
||||
int ecc_steps, int ecc_step_size,
|
||||
int ecc_syndrome_size)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
#endif /* CONFIG_MTD_NAND_ECC_BCH */
|
||||
|
||||
#endif /* __ELM_H */
|
||||
|
@ -71,6 +71,7 @@ struct omap_nand_platform_data {
|
||||
struct mtd_partition *parts;
|
||||
int nr_parts;
|
||||
bool dev_ready;
|
||||
bool flash_bbt;
|
||||
enum nand_io xfer_type;
|
||||
int devsize;
|
||||
enum omap_ecc ecc_opt;
|
||||
|
Loading…
Reference in New Issue
Block a user