Commit 4553d469 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'mtd/for-5.4' of git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux

Pull MTD updates from Richard Weinberger:
 "MTD core changes:
   - add debugfs nodes for querying the flash name and id
   - mtd parser reorganization

  SPI NOR core changes:
   - always use bounce buffer for register read/writes
   - move m25p80 code in spi-nor.c
   - rework hwcaps selection for the spi-mem case
   - rework the core in order to move the manufacturer specific code out
     of it:
       - regroup flash parameters in 'struct spi_nor_flash_parameter'
       - add default_init() and post_sfdp() hooks to tweak the flash
         parameters
       - introduce the ->set_4byte(), ->convert_addr() and ->setup()
         methods, to deal with manufacturer specific code
       - rework the SPI NOR lock/unlock logic
   - fix an error code in spi_nor_read_raw()
   - fix a memory leak bug
   - enable the debugfs for the partname and partid
   - add support for few flashes

  SPI NOR controller drivers changes:
   - intel-spi:
       - Whitelist 4B read commands
       - Add support for Intel Tiger Lake SPI serial flash
   - aspeed-smc: Add of_node_put()
   - hisi-sfc: add of_node_put()
   - cadence-quadspi: Fix QSPI RCU Schedule Stall

  NAND core:
   - Fixing typos
   - Adding missing of_node_put() in various drivers

  Raw NAND controller drivers:
   - Macronix: new controller driver
   - Omap2: fix the number of bitflips returned
   - Brcmnand: fix a pointer not iterating over all the page chunks
   - W90x900: driver removed
   - Onenand: fix a memory leak
   - Sharpsl: missing include guard
   - STM32: avoid warnings when building with W=1
   - Ingenic: fix a coccinelle warning
   - r852: call a helper to simplify the code

  CFI core:
   - Kill useless initializer in mtd_do_chip_probe()
   - Fix a rare write failure seen on some cfi_cmdset_0002 compliant
     Parallel NORs
   - Bunch of cleanups for cfi_cmdset_0002 driver's write functions by
     Tokunori Ikegami"

* tag 'mtd/for-5.4' of git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux: (77 commits)
  mtd: pmc551: Remove set but not used variable 'soff_lo'
  mtd: cfi_cmdset_0002: Fix do_erase_chip() to get chip as erasing mode
  mtd: sm_ftl: Fix memory leak in sm_init_zone() error path
  mtd: parsers: Move CMDLINE parser
  mtd: parsers: Move OF parser
  mtd: parsers: Move BCM63xx parser
  mtd: parsers: Move BCM47xx parser
  mtd: parsers: Move TI AR7 parser
  mtd: pismo: Simplify getting the adapter of a client
  mtd: phram: Module parameters add writable permissions
  mtd: pxa2xx: Use ioremap_cache insted of ioremap_cached
  mtd: spi-nor: Rename "n25q512a" to "mt25qu512a (n25q512a)"
  mtd: spi-nor: Add support for mt35xu02g
  mtd: rawnand: omap2: Fix number of bitflips reporting with ELM
  mtd: rawnand: brcmnand: Fix ecc chunk calculation for erased page bitfips
  mtd: spi-nor: remove superfluous pass of nor->info->sector_size
  mtd: spi-nor: enable the debugfs for the partname and partid
  mtd: mtdcore: add debugfs nodes for querying the flash name and id
  mtd: spi-nor: hisi-sfc: Add of_node_put() before break
  mtd: spi-nor: aspeed-smc: Add of_node_put()
  ...
parents 6cb2e9ee 2cfcfadb
Macronix Raw NAND Controller Device Tree Bindings
-------------------------------------------------
Required properties:
- compatible: should be "mxic,multi-itfc-v009-nand-controller"
- reg: should contain 1 entry for the registers
- #address-cells: should be set to 1
- #size-cells: should be set to 0
- interrupts: interrupt line connected to this raw NAND controller
- clock-names: should contain "ps", "send" and "send_dly"
- clocks: should contain 3 phandles for the "ps", "send" and
"send_dly" clocks
Children nodes:
- children nodes represent the available NAND chips.
See Documentation/devicetree/bindings/mtd/nand-controller.yaml
for more details on generic bindings.
Example:
nand: nand-controller@43c30000 {
compatible = "mxic,multi-itfc-v009-nand-controller";
reg = <0x43c30000 0x10000>;
#address-cells = <1>;
#size-cells = <0>;
interrupts = <GIC_SPI 0x1d IRQ_TYPE_EDGE_RISING>;
clocks = <&clkwizard 0>, <&clkwizard 1>, <&clkc 15>;
clock-names = "send", "send_dly", "ps";
nand@0 {
reg = <0>;
nand-ecc-mode = "soft";
nand-ecc-algo = "bch";
};
};
......@@ -23,73 +23,6 @@ config MTD_TESTS
WARNING: some of the tests will ERASE entire MTD device which they
test. Do not use these tests unless you really know what you do.
config MTD_CMDLINE_PARTS
tristate "Command line partition table parsing"
depends on MTD
help
Allow generic configuration of the MTD partition tables via the kernel
command line. Multiple flash resources are supported for hardware where
different kinds of flash memory are available.
You will still need the parsing functions to be called by the driver
for your particular device. It won't happen automatically. The
SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for
example.
The format for the command line is as follows:
mtdparts=<mtddef>[;<mtddef]
<mtddef> := <mtd-id>:<partdef>[,<partdef>]
<partdef> := <size>[@offset][<name>][ro]
<mtd-id> := unique id used in mapping driver/device
<size> := standard linux memsize OR "-" to denote all
remaining space
<name> := (NAME)
Due to the way Linux handles the command line, no spaces are
allowed in the partition definition, including mtd id's and partition
names.
Examples:
1 flash resource (mtd-id "sa1100"), with 1 single writable partition:
mtdparts=sa1100:-
Same flash, but 2 named partitions, the first one being read-only:
mtdparts=sa1100:256k(ARMboot)ro,-(root)
If unsure, say 'N'.
config MTD_OF_PARTS
tristate "OpenFirmware partitioning information support"
default y
depends on OF
help
This provides a partition parsing function which derives
the partition map from the children of the flash node,
as described in Documentation/devicetree/bindings/mtd/partition.txt.
config MTD_AR7_PARTS
tristate "TI AR7 partitioning support"
help
TI AR7 partitioning support
config MTD_BCM63XX_PARTS
tristate "BCM63XX CFE partitioning support"
depends on BCM63XX || BMIPS_GENERIC || COMPILE_TEST
select CRC32
select MTD_PARSER_IMAGETAG
help
This provides partition parsing for BCM63xx devices with CFE
bootloaders.
config MTD_BCM47XX_PARTS
tristate "BCM47XX partitioning support"
depends on BCM47XX || ARCH_BCM_5301X
help
This provides partitions parser for devices based on BCM47xx
boards.
menu "Partition parsers"
source "drivers/mtd/parsers/Kconfig"
endmenu
......
......@@ -7,11 +7,6 @@
obj-$(CONFIG_MTD) += mtd.o
mtd-y := mtdcore.o mtdsuper.o mtdconcat.o mtdpart.o mtdchar.o
obj-$(CONFIG_MTD_OF_PARTS) += ofpart.o
obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o
obj-$(CONFIG_MTD_AR7_PARTS) += ar7part.o
obj-$(CONFIG_MTD_BCM63XX_PARTS) += bcm63xxpart.o
obj-$(CONFIG_MTD_BCM47XX_PARTS) += bcm47xxpart.o
obj-y += parsers/
# 'Users' - code which presents functionality to userspace.
......
This diff is collapsed.
......@@ -20,7 +20,7 @@ static int genprobe_new_chip(struct map_info *map, struct chip_probe *cp,
struct mtd_info *mtd_do_chip_probe(struct map_info *map, struct chip_probe *cp)
{
struct mtd_info *mtd = NULL;
struct mtd_info *mtd;
struct cfi_private *cfi;
/* First probe the map to see if we have CFI stuff there. */
......
......@@ -79,24 +79,6 @@ config MTD_DATAFLASH_OTP
other key product data. The second half is programmed with a
unique-to-each-chip bit pattern at the factory.
config MTD_M25P80
tristate "Support most SPI Flash chips (AT26DF, M25P, W25X, ...)"
depends on SPI_MASTER && MTD_SPI_NOR
select SPI_MEM
help
This enables access to most modern SPI flash chips, used for
program and data storage. Series supported include Atmel AT26DF,
Spansion S25SL, SST 25VF, ST M25P, and Winbond W25X. Other chips
are supported as well. See the driver source for the current list,
or to add other chips.
Note that the original DataFlash chips (AT45 series, not AT26DF),
need an entirely different driver.
Set up your spi devices with the right board-specific platform data,
if you want to specify device partitioning or to use a device which
doesn't support the JEDEC ID instruction.
config MTD_MCHP23K256
tristate "Microchip 23K256 SRAM"
depends on SPI_MASTER
......
......@@ -12,7 +12,6 @@ obj-$(CONFIG_MTD_MTDRAM) += mtdram.o
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_MCHP23K256) += mchp23k256.o
obj-$(CONFIG_MTD_SPEAR_SMI) += spear_smi.o
obj-$(CONFIG_MTD_SST25L) += sst25l.o
......
// SPDX-License-Identifier: GPL-2.0-only
/*
* MTD SPI driver for ST M25Pxx (and similar) serial flash chips
*
* Author: Mike Lavender, mike@steroidmicros.com
*
* Copyright (c) 2005, Intec Automation Inc.
*
* Some parts are based on lart.c by Abraham Van Der Merwe
*
* Cleaned up and generalized based on mtd_dataflash.c
*/
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi-mem.h>
#include <linux/spi/flash.h>
#include <linux/mtd/spi-nor.h>
struct m25p {
struct spi_mem *spimem;
struct spi_nor spi_nor;
};
static int m25p80_read_reg(struct spi_nor *nor, u8 code, u8 *val, int len)
{
struct m25p *flash = nor->priv;
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, 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;
}
static int m25p80_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
{
struct m25p *flash = nor->priv;
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, NULL, 1));
void *scratchbuf;
int ret;
scratchbuf = kmemdup(buf, len, GFP_KERNEL);
if (!scratchbuf)
return -ENOMEM;
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,
const u_char *buf)
{
struct m25p *flash = nor->priv;
struct spi_mem_op op =
SPI_MEM_OP(SPI_MEM_OP_CMD(nor->program_opcode, 1),
SPI_MEM_OP_ADDR(nor->addr_width, to, 1),
SPI_MEM_OP_NO_DUMMY,
SPI_MEM_OP_DATA_OUT(len, buf, 1));
int ret;
/* get transfer protocols. */
op.cmd.buswidth = spi_nor_get_protocol_inst_nbits(nor->write_proto);
op.addr.buswidth = spi_nor_get_protocol_addr_nbits(nor->write_proto);
op.data.buswidth = spi_nor_get_protocol_data_nbits(nor->write_proto);
if (nor->program_opcode == SPINOR_OP_AAI_WP && nor->sst_write_second)
op.addr.nbytes = 0;
ret = spi_mem_adjust_op_size(flash->spimem, &op);
if (ret)
return ret;
op.data.nbytes = len < op.data.nbytes ? len : op.data.nbytes;
ret = spi_mem_exec_op(flash->spimem, &op);
if (ret)
return ret;
return op.data.nbytes;
}
/*
* Read an address range from the nor chip. The address range
* may be any size provided it is within the physical boundaries.
*/
static ssize_t m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
u_char *buf)
{
struct m25p *flash = nor->priv;
struct spi_mem_op op =
SPI_MEM_OP(SPI_MEM_OP_CMD(nor->read_opcode, 1),
SPI_MEM_OP_ADDR(nor->addr_width, from, 1),
SPI_MEM_OP_DUMMY(nor->read_dummy, 1),
SPI_MEM_OP_DATA_IN(len, buf, 1));
size_t remaining = len;
int ret;
/* get transfer protocols. */
op.cmd.buswidth = spi_nor_get_protocol_inst_nbits(nor->read_proto);
op.addr.buswidth = spi_nor_get_protocol_addr_nbits(nor->read_proto);
op.dummy.buswidth = op.addr.buswidth;
op.data.buswidth = spi_nor_get_protocol_data_nbits(nor->read_proto);
/* convert the dummy cycles to the number of bytes */
op.dummy.nbytes = (nor->read_dummy * op.dummy.buswidth) / 8;
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;
op.addr.val += op.data.nbytes;
remaining -= op.data.nbytes;
op.data.buf.in += op.data.nbytes;
}
return len;
}
/*
* board specific setup should have ensured the SPI clock used here
* matches what the READ command supports, at least until this driver
* understands FAST_READ (for clocks over 25 MHz).
*/
static int m25p_probe(struct spi_mem *spimem)
{
struct spi_device *spi = spimem->spi;
struct flash_platform_data *data;
struct m25p *flash;
struct spi_nor *nor;
struct spi_nor_hwcaps hwcaps = {
.mask = SNOR_HWCAPS_READ |
SNOR_HWCAPS_READ_FAST |
SNOR_HWCAPS_PP,
};
char *flash_name;
int ret;
data = dev_get_platdata(&spimem->spi->dev);
flash = devm_kzalloc(&spimem->spi->dev, sizeof(*flash), GFP_KERNEL);
if (!flash)
return -ENOMEM;
nor = &flash->spi_nor;
/* install the hooks */
nor->read = m25p80_read;
nor->write = m25p80_write;
nor->write_reg = m25p80_write_reg;
nor->read_reg = m25p80_read_reg;
nor->dev = &spimem->spi->dev;
spi_nor_set_flash_node(nor, spi->dev.of_node);
nor->priv = flash;
spi_mem_set_drvdata(spimem, flash);
flash->spimem = spimem;
if (spi->mode & SPI_RX_OCTAL) {
hwcaps.mask |= SNOR_HWCAPS_READ_1_1_8;
if (spi->mode & SPI_TX_OCTAL)
hwcaps.mask |= (SNOR_HWCAPS_READ_1_8_8 |
SNOR_HWCAPS_PP_1_1_8 |
SNOR_HWCAPS_PP_1_8_8);
} else if (spi->mode & SPI_RX_QUAD) {
hwcaps.mask |= SNOR_HWCAPS_READ_1_1_4;
if (spi->mode & SPI_TX_QUAD)
hwcaps.mask |= (SNOR_HWCAPS_READ_1_4_4 |
SNOR_HWCAPS_PP_1_1_4 |
SNOR_HWCAPS_PP_1_4_4);
} else if (spi->mode & SPI_RX_DUAL) {
hwcaps.mask |= SNOR_HWCAPS_READ_1_1_2;
if (spi->mode & SPI_TX_DUAL)
hwcaps.mask |= SNOR_HWCAPS_READ_1_2_2;
}
if (data && data->name)
nor->mtd.name = data->name;
if (!nor->mtd.name)
nor->mtd.name = spi_mem_get_name(spimem);
/* 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)
flash_name = data->type;
else if (!strcmp(spi->modalias, "spi-nor"))
flash_name = NULL; /* auto-detect */
else
flash_name = spi->modalias;
ret = spi_nor_scan(nor, flash_name, &hwcaps);
if (ret)
return ret;
return mtd_device_register(&nor->mtd, data ? data->parts : NULL,
data ? data->nr_parts : 0);
}
static int m25p_remove(struct spi_mem *spimem)
{
struct m25p *flash = spi_mem_get_drvdata(spimem);
spi_nor_restore(&flash->spi_nor);
/* Clean up MTD stuff. */
return mtd_device_unregister(&flash->spi_nor.mtd);
}
static void m25p_shutdown(struct spi_mem *spimem)
{
struct m25p *flash = spi_mem_get_drvdata(spimem);
spi_nor_restore(&flash->spi_nor);
}
/*
* Do NOT add to this array without reading the following:
*
* Historically, many flash devices are bound to this driver by their name. But
* since most of these flash are compatible to some extent, and their
* differences can often be differentiated by the JEDEC read-ID command, we
* encourage new users to add support to the spi-nor library, and simply bind
* against a generic string here (e.g., "jedec,spi-nor").
*
* Many flash names are kept here in this list (as well as in spi-nor.c) to
* keep them available as module aliases for existing platforms.
*/
static const struct spi_device_id m25p_ids[] = {
/*
* Allow non-DT platform devices to bind to the "spi-nor" modalias, and
* hack around the fact that the SPI core does not provide uevent
* matching for .of_match_table
*/
{"spi-nor"},
/*
* Entries not used in DTs that should be safe to drop after replacing
* them with "spi-nor" in platform data.
*/
{"s25sl064a"}, {"w25x16"}, {"m25p10"}, {"m25px64"},
/*
* Entries that were used in DTs without "jedec,spi-nor" fallback and
* should be kept for backward compatibility.
*/
{"at25df321a"}, {"at25df641"}, {"at26df081a"},
{"mx25l4005a"}, {"mx25l1606e"}, {"mx25l6405d"}, {"mx25l12805d"},
{"mx25l25635e"},{"mx66l51235l"},
{"n25q064"}, {"n25q128a11"}, {"n25q128a13"}, {"n25q512a"},
{"s25fl256s1"}, {"s25fl512s"}, {"s25sl12801"}, {"s25fl008k"},
{"s25fl064k"},
{"sst25vf040b"},{"sst25vf016b"},{"sst25vf032b"},{"sst25wf040"},
{"m25p40"}, {"m25p80"}, {"m25p16"}, {"m25p32"},
{"m25p64"}, {"m25p128"},
{"w25x80"}, {"w25x32"}, {"w25q32"}, {"w25q32dw"},
{"w25q80bl"}, {"w25q128"}, {"w25q256"},
/* Flashes that can't be detected using JEDEC */
{"m25p05-nonjedec"}, {"m25p10-nonjedec"}, {"m25p20-nonjedec"},
{"m25p40-nonjedec"}, {"m25p80-nonjedec"}, {"m25p16-nonjedec"},
{"m25p32-nonjedec"}, {"m25p64-nonjedec"}, {"m25p128-nonjedec"},
/* Everspin MRAMs (non-JEDEC) */
{ "mr25h128" }, /* 128 Kib, 40 MHz */
{ "mr25h256" }, /* 256 Kib, 40 MHz */
{ "mr25h10" }, /* 1 Mib, 40 MHz */
{ "mr25h40" }, /* 4 Mib, 40 MHz */
{ },
};
MODULE_DEVICE_TABLE(spi, m25p_ids);
static const struct of_device_id m25p_of_table[] = {
/*
* Generic compatibility for SPI NOR that can be identified by the
* JEDEC READ ID opcode (0x9F). Use this, if possible.
*/
{ .compatible = "jedec,spi-nor" },
{}
};
MODULE_DEVICE_TABLE(of, m25p_of_table);
static struct spi_mem_driver m25p80_driver = {
.spidrv = {
.driver = {
.name = "m25p80",
.of_match_table = m25p_of_table,
},
.id_table = m25p_ids,
},
.probe = m25p_probe,
.remove = m25p_remove,
.shutdown = m25p_shutdown,
/* REVISIT: many of these chips have deep power-down modes, which
* should clearly be entered on suspend() to minimize power use.
* And also when they're otherwise idle...
*/
};
module_spi_mem_driver(m25p80_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Mike Lavender");
MODULE_DESCRIPTION("MTD SPI driver for ST M25Pxx flash chips");
......@@ -294,7 +294,7 @@ static int phram_param_call(const char *val, const struct kernel_param *kp)
#endif
}
module_param_call(phram, phram_param_call, NULL, NULL, 000);
module_param_call(phram, phram_param_call, NULL, NULL, 0200);
MODULE_PARM_DESC(phram, "Memory region to map. \"phram=<name>,<start>,<length>\"");
......
......@@ -135,7 +135,7 @@ static int pmc551_point(struct mtd_info *mtd, loff_t from, size_t len,
static int pmc551_erase(struct mtd_info *mtd, struct erase_info *instr)
{
struct mypriv *priv = mtd->priv;
u32 soff_hi, soff_lo; /* start address offset hi/lo */
u32 soff_hi; /* start address offset hi */
u32 eoff_hi, eoff_lo; /* end address offset hi/lo */
unsigned long end;
u_char *ptr;
......@@ -150,7 +150,6 @@ static int pmc551_erase(struct mtd_info *mtd, struct erase_info *instr)
eoff_hi = end & ~(priv->asize - 1);
soff_hi = instr->addr & ~(priv->asize - 1);
eoff_lo = end & (priv->asize - 1);
soff_lo = instr->addr & (priv->asize - 1);
pmc551_point(mtd, instr->addr, instr->len, &retlen,
(void **)&ptr, NULL);
......@@ -225,7 +224,7 @@ static int pmc551_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t * retlen, u_char * buf)
{
struct mypriv *priv = mtd->priv;
u32 soff_hi, soff_lo; /* start address offset hi/lo */
u32 soff_hi; /* start address offset hi */
u32 eoff_hi, eoff_lo; /* end address offset hi/lo */
unsigned long end;
u_char *ptr;
......@@ -239,7 +238,6 @@ static int pmc551_read(struct mtd_info *mtd, loff_t from, size_t len,
end = from + len - 1;
soff_hi = from & ~(priv->asize - 1);
eoff_hi = end & ~(priv->asize - 1);
soff_lo = from & (priv->asize - 1);
eoff_lo = end & (priv->asize - 1);
pmc551_point(mtd, from, len, retlen, (void **)&ptr, NULL);
......@@ -282,7 +280,7 @@ static int pmc551_write(struct mtd_info *mtd, loff_t to, size_t len,
size_t * retlen, const u_char * buf)
{
struct mypriv *priv = mtd->priv;
u32 soff_hi, soff_lo; /* start address offset hi/lo */
u32 soff_hi; /* start address offset hi */
u32 eoff_hi, eoff_lo; /* end address offset hi/lo */
unsigned long end;
u_char *ptr;
......@@ -296,7 +294,6 @@ static int pmc551_write(struct mtd_info *mtd, loff_t to, size_t len,
end = to + len - 1;
soff_hi = to & ~(priv->asize - 1);
eoff_hi = end & ~(priv->asize - 1);
soff_lo = to & (priv->asize - 1);
eoff_lo = end & (priv->asize - 1);
pmc551_point(mtd, to, len, retlen, (void **)&ptr, NULL);
......
......@@ -211,13 +211,12 @@ static int pismo_remove(struct i2c_client *client)
static int pismo_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
struct pismo_pdata *pdata = client->dev.platform_data;
struct pismo_eeprom eeprom;
struct pismo_data *pismo;
int ret, i;
if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) {
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
dev_err(&client->dev, "functionality mismatch\n");
return -EIO;
}
......
......@@ -68,8 +68,7 @@ static int pxa2xx_flash_probe(struct platform_device *pdev)
info->map.name);
return -ENOMEM;
}
info->map.cached =
ioremap_cached(info->map.phys, info->map.size);
info->map.cached = ioremap_cache(info->map.phys, info->map.size);
if (!info->map.cached)
printk(KERN_WARNING "Failed to ioremap cached %s\n",
info->map.name);
......
......@@ -335,6 +335,82 @@ static const struct device_type mtd_devtype = {
.release = mtd_release,
};
static int mtd_partid_show(struct seq_file *s, void *p)
{
struct mtd_info *mtd = s->private;
seq_printf(s, "%s\n", mtd->dbg.partid);
return 0;
}
static int mtd_partid_debugfs_open(struct inode *inode, struct file *file)
{
return single_open(file, mtd_partid_show, inode->i_private);
}
static const struct file_operations mtd_partid_debug_fops = {
.open = mtd_partid_debugfs_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static int mtd_partname_show(struct seq_file *s, void *p)
{
struct mtd_info *mtd = s->private;
seq_printf(s, "%s\n", mtd->dbg.partname);
return 0;
}
static int mtd_partname_debugfs_open(struct inode *inode, struct file *file)
{
return single_open(file, mtd_partname_show, inode->i_private);
}
static const struct file_operations mtd_partname_debug_fops = {
.open = mtd_partname_debugfs_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static struct dentry *dfs_dir_mtd;
static void mtd_debugfs_populate(struct mtd_info *mtd)
{
struct device *dev = &mtd->dev;
struct dentry *root, *dent;
if (IS_ERR_OR_NULL(dfs_dir_mtd))
return;
root = debugfs_create_dir(dev_name(dev), dfs_dir_mtd);
if (IS_ERR_OR_NULL(root)) {
dev_dbg(dev, "won't show data in debugfs\n");
return;
}
mtd->dbg.dfs_dir = root;
if (mtd->dbg.partid) {
dent = debugfs_create_file("partid", 0400, root, mtd,
&mtd_partid_debug_fops);
if (IS_ERR_OR_NULL(dent))
dev_err(dev, "can't create debugfs entry for partid\n");
}
if (mtd->dbg.partname) {
dent = debugfs_create_file("partname", 0400, root, mtd,
&mtd_partname_debug_fops);
if (IS_ERR_OR_NULL(dent))
dev_err(dev,
"can't create debugfs entry for partname\n");
}
}
#ifndef CONFIG_MMU
unsigned mtd_mmap_capabilities(struct mtd_info *mtd)
{
......@@ -512,8 +588,6 @@ static int mtd_nvmem_add(struct mtd_info *mtd)
return 0;
}
static struct dentry *dfs_dir_mtd;
/**
* add_mtd_device - register an MTD device
* @mtd: pointer to new MTD device info structure
......@@ -607,13 +681,7 @@ int add_mtd_device(struct mtd_info *mtd)
if (error)
goto fail_nvmem_add;
if (!IS_ERR_OR_NULL(dfs_dir_mtd)) {
mtd->dbg.dfs_dir = debugfs_create_dir(dev_name(&mtd->dev), dfs_dir_mtd);
if (IS_ERR_OR_NULL(mtd->dbg.dfs_dir)) {
pr_debug("mtd device %s won't show data in debugfs\n",
dev_name(&mtd->dev));
}
}
mtd_debugfs_populate(mtd);
device_create(&mtd_class, mtd->dev.parent, MTD_DEVT(i) + 1, NULL,
"mtd%dro", i);
......
......@@ -3880,6 +3880,9 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
if (!this->oob_buf) {
if (this->options & ONENAND_PAGEBUF_ALLOC) {
this->options &= ~ONENAND_PAGEBUF_ALLOC;
#ifdef CONFIG_MTD_ONENAND_VERIFY_WRITE
kfree(this->verify_buf);
#endif
kfree(this->page_buf);
}
return -ENOMEM;
......
......@@ -351,14 +351,6 @@ config MTD_NAND_SOCRATES
help
Enables support for NAND Flash chips wired onto Socrates board.
config MTD_NAND_NUC900
tristate "Nuvoton NUC9xx/w90p910 NAND controller"
depends on ARCH_W90X900 || COMPILE_TEST
depends on HAS_IOMEM
help
This enables the driver for the NAND Flash on evaluation board based
on w90p910 / NUC9xx.
source "drivers/mtd/nand/raw/ingenic/Kconfig"
config MTD_NAND_FSMC
......@@ -407,6 +399,12 @@ config MTD_NAND_MTK
Enables support for NAND controller on MTK SoCs.
This controller is found on mt27xx, mt81xx, mt65xx SoCs.
config MTD_NAND_MXIC
tristate "Macronix raw NAND controller"
depends on HAS_IOMEM || COMPILE_TEST
help
This selects the Macronix raw NAND controller driver.
config MTD_NAND_TEGRA
tristate "NVIDIA Tegra NAND controller"
depends on ARCH_TEGRA || COMPILE_TEST
......
......@@ -41,7 +41,6 @@ obj-$(CONFIG_MTD_NAND_SH_FLCTL) += sh_flctl.o
obj-$(CONFIG_MTD_NAND_MXC) += mxc_nand.o
obj-$(CONFIG_MTD_NAND_SOCRATES) += socrates_nand.o
obj-$(CONFIG_MTD_NAND_TXX9NDFMC) += txx9ndfmc.o
obj-$(CONFIG_MTD_NAND_NUC900) += nuc900_nand.o
obj-$(CONFIG_MTD_NAND_MPC5121_NFC) += mpc5121_nfc.o
obj-$(CONFIG_MTD_NAND_VF610_NFC) += vf610_nfc.o
obj-$(CONFIG_MTD_NAND_RICOH) += r852.o
......@@ -54,6 +53,7 @@ obj-$(CONFIG_MTD_NAND_HISI504) += hisi504_nand.o
obj-$(CONFIG_MTD_NAND_BRCMNAND) += brcmnand/
obj-$(CONFIG_MTD_NAND_QCOM) += qcom_nandc.o
obj-$(CONFIG_MTD_NAND_MTK) += mtk_ecc.o mtk_nand.o
obj-$(CONFIG_MTD_NAND_MXIC) += mxic_nand.o
obj-$(CONFIG_MTD_NAND_TEGRA) += tegra_nand.o
obj-$(CONFIG_MTD_NAND_STM32_FMC2) += stm32_fmc2_nand.o
obj-$(CONFIG_MTD_NAND_MESON) += meson_nand.o
......
......@@ -1792,6 +1792,7 @@ static int brcmstb_nand_verify_erased_page(struct mtd_info *mtd,
int bitflips = 0;
int page = addr >> chip->page_shift;
int ret;
void *ecc_chunk;
if (!buf)
buf = nand_get_data_buf(chip);
......@@ -1804,7 +1805,9 @@ static int brcmstb_nand_verify_erased_page(struct mtd_info *mtd,
return ret;
for (i = 0; i < chip->ecc.steps; i++, oob += sas) {
ret = nand_check_erased_ecc_chunk(buf, chip->ecc.size,
ecc_chunk = buf + chip->ecc.size * i;
ret = nand_check_erased_ecc_chunk(ecc_chunk,
chip->ecc.size,
oob, sas, NULL, 0,
chip->ecc.strength);
if (ret < 0)
......
......@@ -310,7 +310,6 @@ static int ingenic_nand_init_chip(struct platform_device *pdev,
struct device *dev = &pdev->dev;
struct ingenic_nand *nand;
struct ingenic_nand_cs *cs;
struct resource *res;
struct nand_chip *chip;
struct mtd_info *mtd;
const __be32 *reg;
......@@ -326,8 +325,7 @@ static int ingenic_nand_init_chip(struct platform_device *pdev,
jz4780_nemc_set_type(nfc->dev, cs->bank, JZ4780_NEMC_BANK_NAND);
res = platform_get_resource(pdev, IORESOURCE_MEM, chipnr);
cs->base = devm_ioremap_resource(dev, res);
cs->base = devm_platform_ioremap_resource(pdev, chipnr);
if (IS_ERR(cs->base))
return PTR_ERR(cs->base);
......@@ -418,6 +416,7 @@ static int ingenic_nand_init_chips(struct ingenic_nfc *nfc,
ret = ingenic_nand_init_chip(pdev, nfc, np, i);
if (ret) {
ingenic_nand_cleanup_chips(nfc);
of_node_put(np);
return ret;
}
......
......@@ -1320,6 +1320,7 @@ static int meson_nfc_nand_chips_init(struct device *dev,
ret = meson_nfc_nand_chip_init(dev, nfc, nand_np);
if (ret) {
meson_nfc_nand_chip_cleanup(nfc);
of_node_put(nand_np);
return ret;
}
}
......
This diff is collapsed.
......@@ -4112,7 +4112,7 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to,
struct mtd_oob_ops *ops)
{
struct nand_chip *chip = mtd_to_nand(mtd);
int ret = -ENOTSUPP;
int ret;
ops->retlen = 0;
......
......@@ -1232,7 +1232,7 @@ static int nand_scan_bbt(struct nand_chip *this, struct nand_bbt_descr *bd)
if (!td) {
if ((res = nand_memory_bbt(this, bd))) {
pr_err("nand_bbt: can't scan flash and build the RAM-based BBT\n");
goto err;
goto err_free_bbt;
}
return 0;
}
......@@ -1245,7 +1245,7 @@ static int nand_scan_bbt(struct nand_chip *this, struct nand_bbt_descr *bd)
buf = vmalloc(len);
if (!buf) {
res = -ENOMEM;
goto err;
goto err_free_bbt;
}
/* Is the bbt at a given page? */
......@@ -1258,7 +1258,7 @@ static int nand_scan_bbt(struct nand_chip *this, struct nand_bbt_descr *bd)
res = check_create(this, buf, bd);
if (res)
goto err;
goto err_free_buf;
/* Prevent the bbt regions from erasing / writing */
mark_bbt_region(this, td);
......@@ -1268,7 +1268,9 @@ static int nand_scan_bbt(struct nand_chip *this, struct nand_bbt_descr *bd)
vfree(buf);
return 0;
err:
err_free_buf:
vfree(buf);
err_free_bbt:
kfree(this->bbt);
this->bbt = NULL;
return res;
......
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright © 2009 Nuvoton technology corporation.
*
* Wan ZongShun <mcuos.com@gmail.com>
*/
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/rawnand.h>
#include <linux/mtd/partitions.h>
#define REG_FMICSR 0x00
#define REG_SMCSR 0xa0
#define REG_SMISR 0xac
#define REG_SMCMD 0xb0
#define REG_SMADDR 0xb4
#define REG_SMDATA 0xb8
#define RESET_FMI 0x01
#define NAND_EN 0x08
#define READYBUSY (0x01 << 18)
#define SWRST 0x01
#define PSIZE (0x01 << 3)
#define DMARWEN (0x03 << 1)
#define BUSWID (0x01 << 4)
#define ECC4EN (0x01 << 5)
#define WP (0x01 << 24)
#define NANDCS (0x01 << 25)
#define ENDADDR (0x01 << 31)
#define read_data_reg(dev) \
__raw_readl((dev)->reg + REG_SMDATA)
#define write_data_reg(dev, val) \
__raw_writel((val), (dev)->reg + REG_SMDATA)
#define write_cmd_reg(dev, val) \
__raw_writel((val), (dev)->reg + REG_SMCMD)
#define write_addr_reg(dev, val) \
__raw_writel((val), (dev)->reg + REG_SMADDR)
struct nuc900_nand {
struct nand_chip chip;
void __iomem *reg;
struct clk *clk;
spinlock_t lock;
};
static inline struct nuc900_nand *mtd_to_nuc900(struct mtd_info *mtd)
{
return container_of(mtd_to_nand(mtd), struct nuc900_nand, chip);
}
static const struct mtd_partition partitions[] = {
{
.name = "NAND FS 0",
.offset = 0,
.size = 8 * 1024 * 1024
},
{
.name = "NAND FS 1",
.offset = MTDPART_OFS_APPEND,
.size = MTDPART_SIZ_FULL
}
};
static unsigned char nuc900_nand_read_byte(struct nand_chip *chip)
{
unsigned char ret;
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 nand_chip *chip,
unsigned char *buf, int len)
{
int i;
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 nand_chip *chip,
const unsigned char *buf, int len)
{
int i;
struct nuc900_nand *nand = mtd_to_nuc900(nand_to_mtd(chip));
for (i = 0; i < len; i++)
write_data_reg(nand, buf[i]);
}
static int nuc900_check_rb(struct nuc900_nand *nand)
{
unsigned int val;
spin_lock(&nand->lock);
val = __raw_readl(nand->reg + REG_SMISR);
val &= READYBUSY;
spin_unlock(&nand->lock);
return val;
}
static int nuc900_nand_devready(struct nand_chip *chip)
{
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 nand_chip *chip,
unsigned int command,
int column, int page_addr)
{
struct mtd_info *mtd = nand_to_mtd(chip);
struct nuc900_nand *nand = mtd_to_nuc900(mtd);
if (command == NAND_CMD_READOOB) {
column += mtd->writesize;
command = NAND_CMD_READ0;
}
write_cmd_reg(nand, command & 0xff);
if (column != -1 || page_addr != -1) {
if (column != -1) {
if (chip->options & NAND_BUSWIDTH_16 &&
!nand_opcode_8bits(command))
column >>= 1;
write_addr_reg(nand, column);
write_addr_reg(nand, column >> 8 | ENDADDR);
}
if (page_addr != -1) {
write_addr_reg(nand, page_addr);
if (chip->options & NAND_ROW_ADDR_3) {
write_addr_reg(nand, page_addr >> 8);
write_addr_reg(nand, page_addr >> 16 | ENDADDR);
} else {
write_addr_reg(nand, page_addr >> 8 | ENDADDR);
}
}
}
switch (command) {
case NAND_CMD_CACHEDPROG:
case NAND_CMD_PAGEPROG:
case NAND_CMD_ERASE1:
case NAND_CMD_ERASE2:
case NAND_CMD_SEQIN:
case NAND_CMD_RNDIN:
case NAND_CMD_STATUS:
return;
case NAND_CMD_RESET:
if (chip->legacy.dev_ready)
break;
udelay(chip->legacy.chip_delay);
write_cmd_reg(nand, NAND_CMD_STATUS);
write_cmd_reg(nand, command);
while (!nuc900_check_rb(nand))
;
return;
case NAND_CMD_RNDOUT:
write_cmd_reg(nand, NAND_CMD_RNDOUTSTART);
return;
case NAND_CMD_READ0:
write_cmd_reg(nand, NAND_CMD_READSTART);
/* fall through */
default:
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);
while (!chip->legacy.dev_ready(chip))
;
}
static void nuc900_nand_enable(struct nuc900_nand *nand)
{
unsigned int val;
spin_lock(&nand->lock);
__raw_writel(RESET_FMI, (nand->reg + REG_FMICSR));
val = __raw_readl(nand->reg + REG_FMICSR);
if (!(val & NAND_EN))
__raw_writel(val | NAND_EN, nand->reg + REG_FMICSR);
val = __raw_readl(nand->reg + REG_SMCSR);
val &= ~(SWRST|PSIZE|DMARWEN|BUSWID|ECC4EN|NANDCS);
val |= WP;
__raw_writel(val, nand->reg + REG_SMCSR);
spin_unlock(&nand->lock);
}
static int nuc900_nand_probe(struct platform_device *pdev)
{
struct nuc900_nand *nuc900_nand;
struct nand_chip *chip;
struct mtd_info *mtd;
struct resource *res;
nuc900_nand = devm_kzalloc(&pdev->dev, sizeof(struct nuc900_nand),
GFP_KERNEL);
if (!nuc900_nand)
return -ENOMEM;
chip = &(nuc900_nand->chip);
mtd = nand_to_mtd(chip);
mtd->dev.parent = &pdev->dev;
spin_lock_init(&nuc900_nand->lock);
nuc900_nand->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(nuc900_nand->clk))
return -ENOENT;
clk_enable(nuc900_nand->clk);
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;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
nuc900_nand->reg = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(nuc900_nand->reg))
return PTR_ERR(nuc900_nand->reg);
nuc900_nand_enable(nuc900_nand);
if (nand_scan(chip, 1))
return -ENXIO;
mtd_device_register(mtd, partitions, ARRAY_SIZE(partitions));
platform_set_drvdata(pdev, nuc900_nand);
return 0;
}
static int nuc900_nand_remove(struct platform_device *pdev)
{
struct nuc900_nand *nuc900_nand = platform_get_drvdata(pdev);
nand_release(&nuc900_nand->chip);
clk_disable(nuc900_nand->clk);
return 0;
}
static struct platform_driver nuc900_nand_driver = {
.probe = nuc900_nand_probe,
.remove = nuc900_nand_remove,
.driver = {
.name = "nuc900-fmi",
},
};
module_platform_driver(nuc900_nand_driver);
MODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>");
MODULE_DESCRIPTION("w90p910/NUC9xx nand driver!");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:nuc900-fmi");
......@@ -1501,7 +1501,7 @@ static int omap_elm_correct_data(struct nand_chip *chip, u_char *data,
}
/* Update number of correctable errors */
stat += err_vec[i].error_count;
stat = max_t(unsigned int, stat, err_vec[i].error_count);
/* Update page data with sector size */
data += ecc->size;
......
......@@ -116,7 +116,7 @@ static int oxnas_nand_probe(struct platform_device *pdev)
GFP_KERNEL);
if (!chip) {
err = -ENOMEM;
goto err_clk_unprepare;
goto err_release_child;
}
chip->controller = &oxnas->base;
......@@ -137,12 +137,12 @@ static int oxnas_nand_probe(struct platform_device *pdev)
/* Scan to find existence of the device */
err = nand_scan(chip, 1);
if (err)
goto err_clk_unprepare;
goto err_release_child;
err = mtd_device_register(mtd, NULL, 0);
if (err) {
nand_release(chip);
goto err_clk_unprepare;
goto err_release_child;
}
oxnas->chips[nchips] = chip;
......@@ -159,6 +159,8 @@ static int oxnas_nand_probe(struct platform_device *pdev)
return 0;
err_release_child:
of_node_put(nand_np);
err_clk_unprepare:
clk_disable_unprepare(oxnas->clk);
return err;
......
......@@ -998,7 +998,7 @@ static void r852_shutdown(struct pci_dev *pci_dev)
#ifdef CONFIG_PM_SLEEP
static int r852_suspend(struct device *device)
{
struct r852_device *dev = pci_get_drvdata(to_pci_dev(device));
struct r852_device *dev = dev_get_drvdata(device);
if (dev->ctlreg & R852_CTL_CARDENABLE)
return -EBUSY;
......@@ -1019,7 +1019,7 @@ 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 r852_device *dev = dev_get_drvdata(device);
r852_disable_irqs(dev);
r852_card_update_present(dev);
......
......@@ -1427,21 +1427,16 @@ static void stm32_fmc2_calc_timings(struct nand_chip *chip,
struct stm32_fmc2_timings *tims = &nand->timings;
unsigned long hclk = clk_get_rate(fmc2->clk);
unsigned long hclkp = NSEC_PER_SEC / (hclk / 1000);
int tar, tclr, thiz, twait, tset_mem, tset_att, thold_mem, thold_att;
tar = hclkp;
if (tar < sdrt->tAR_min)
tar = sdrt->tAR_min;
tims->tar = DIV_ROUND_UP(tar, hclkp) - 1;
if (tims->tar > FMC2_PCR_TIMING_MASK)
tims->tar = FMC2_PCR_TIMING_MASK;
tclr = hclkp;
if (tclr < sdrt->tCLR_min)
tclr = sdrt->tCLR_min;
tims->tclr = DIV_ROUND_UP(tclr, hclkp) - 1;
if (tims->tclr > FMC2_PCR_TIMING_MASK)
tims->tclr = FMC2_PCR_TIMING_MASK;
unsigned long timing, tar, tclr, thiz, twait;
unsigned long tset_mem, tset_att, thold_mem, thold_att;
tar = max_t(unsigned long, hclkp, sdrt->tAR_min);
timing = DIV_ROUND_UP(tar, hclkp) - 1;
tims->tar = min_t(unsigned long, timing, FMC2_PCR_TIMING_MASK);
tclr = max_t(unsigned long, hclkp, sdrt->tCLR_min);
timing = DIV_ROUND_UP(tclr, hclkp) - 1;
tims->tclr = min_t(unsigned long, timing, FMC2_PCR_TIMING_MASK);
tims->thiz = FMC2_THIZ;
thiz = (tims->thiz + 1) * hclkp;
......@@ -1451,18 +1446,11 @@ static void stm32_fmc2_calc_timings(struct nand_chip *chip,
* tWAIT > tWP
* tWAIT > tREA + tIO
*/
twait = hclkp;
if (twait < sdrt->tRP_min)
twait = sdrt->tRP_min;
if (twait < sdrt->tWP_min)
twait = sdrt->tWP_min;
if (twait < sdrt->tREA_max + FMC2_TIO)
twait = sdrt->tREA_max + FMC2_TIO;
tims->twait = DIV_ROUND_UP(twait, hclkp);
if (tims->twait == 0)
tims->twait = 1;
else if (tims->twait > FMC2_PMEM_PATT_TIMING_MASK)
tims->twait = FMC2_PMEM_PATT_TIMING_MASK;
twait = max_t(unsigned long, hclkp, sdrt->tRP_min);
twait = max_t(unsigned long, twait, sdrt->tWP_min);
twait = max_t(unsigned long, twait, sdrt->tREA_max + FMC2_TIO);
timing = DIV_ROUND_UP(twait, hclkp);
tims->twait = clamp_val(timing, 1, FMC2_PMEM_PATT_TIMING_MASK);
/*
* tSETUP_MEM > tCS - tWAIT
......@@ -1477,20 +1465,15 @@ static void stm32_fmc2_calc_timings(struct nand_chip *chip,
if (twait > thiz && (sdrt->tDS_min > twait - thiz) &&
(tset_mem < sdrt->tDS_min - (twait - thiz)))
tset_mem = sdrt->tDS_min - (twait - thiz);
tims->tset_mem = DIV_ROUND_UP(tset_mem, hclkp);
if (tims->tset_mem == 0)
tims->tset_mem = 1;
else if (tims->tset_mem > FMC2_PMEM_PATT_TIMING_MASK)
tims->tset_mem = FMC2_PMEM_PATT_TIMING_MASK;
timing = DIV_ROUND_UP(tset_mem, hclkp);
tims->tset_mem = clamp_val(timing, 1, FMC2_PMEM_PATT_TIMING_MASK);
/*
* tHOLD_MEM > tCH
* tHOLD_MEM > tREH - tSETUP_MEM
* tHOLD_MEM > max(tRC, tWC) - (tSETUP_MEM + tWAIT)
*/
thold_mem = hclkp;
if (thold_mem < sdrt->tCH_min)
thold_mem = sdrt->tCH_min;
thold_mem = max_t(unsigned long, hclkp, sdrt->tCH_min);
if (sdrt->tREH_min > tset_mem &&
(thold_mem < sdrt->tREH_min - tset_mem))
thold_mem = sdrt->tREH_min - tset_mem;
......@@ -1500,11 +1483,8 @@ static void stm32_fmc2_calc_timings(struct nand_chip *chip,
if ((sdrt->tWC_min > tset_mem + twait) &&
(thold_mem < sdrt->tWC_min - (tset_mem + twait)))
thold_mem = sdrt->tWC_min - (tset_mem + twait);
tims->thold_mem = DIV_ROUND_UP(thold_mem, hclkp);
if (tims->thold_mem == 0)
tims->thold_mem = 1;
else if (tims->thold_mem > FMC2_PMEM_PATT_TIMING_MASK)
tims->thold_mem = FMC2_PMEM_PATT_TIMING_MASK;
timing = DIV_ROUND_UP(thold_mem, hclkp);
tims->thold_mem = clamp_val(timing, 1, FMC2_PMEM_PATT_TIMING_MASK);
/*
* tSETUP_ATT > tCS - tWAIT
......@@ -1526,11 +1506,8 @@ static void stm32_fmc2_calc_timings(struct nand_chip *chip,
if (twait > thiz && (sdrt->tDS_min > twait - thiz) &&
(tset_att < sdrt->tDS_min - (twait - thiz)))
tset_att = sdrt->tDS_min - (twait - thiz);
tims->tset_att = DIV_ROUND_UP(tset_att, hclkp);
if (tims->tset_att == 0)
tims->tset_att = 1;
else if (tims->tset_att > FMC2_PMEM_PATT_TIMING_MASK)
tims->tset_att = FMC2_PMEM_PATT_TIMING_MASK;
timing = DIV_ROUND_UP(tset_att, hclkp);
tims->tset_att = clamp_val(timing, 1, FMC2_PMEM_PATT_TIMING_MASK);
/*
* tHOLD_ATT > tALH
......@@ -1545,17 +1522,11 @@ static void stm32_fmc2_calc_timings(struct nand_chip *chip,
* tHOLD_ATT > tRC - (tSETUP_ATT + tWAIT)
* tHOLD_ATT > tWC - (tSETUP_ATT + tWAIT)
*/
thold_att = hclkp;
if (thold_att < sdrt->tALH_min)
thold_att = sdrt->tALH_min;
if (thold_att < sdrt->tCH_min)
thold_att = sdrt->tCH_min;
if (thold_att < sdrt->tCLH_min)
thold_att = sdrt->tCLH_min;
if (thold_att < sdrt->tCOH_min)
thold_att = sdrt->tCOH_min;
if (thold_att < sdrt->tDH_min)
thold_att = sdrt->tDH_min;
thold_att = max_t(unsigned long, hclkp, sdrt->tALH_min);
thold_att = max_t(unsigned long, thold_att, sdrt->tCH_min);
thold_att = max_t(unsigned long, thold_att, sdrt->tCLH_min);
thold_att = max_t(unsigned long, thold_att, sdrt->tCOH_min);
thold_att = max_t(unsigned long, thold_att, sdrt->tDH_min);
if ((sdrt->tWB_max + FMC2_TIO + FMC2_TSYNC > tset_mem) &&
(thold_att < sdrt->tWB_max + FMC2_TIO + FMC2_TSYNC - tset_mem))
thold_att = sdrt->tWB_max + FMC2_TIO + FMC2_TSYNC - tset_mem;
......@@ -1574,11 +1545,8 @@ static void stm32_fmc2_calc_timings(struct nand_chip *chip,
if ((sdrt->tWC_min > tset_att + twait) &&
(thold_att < sdrt->tWC_min - (tset_att + twait)))
thold_att = sdrt->tWC_min - (tset_att + twait);
tims->thold_att = DIV_ROUND_UP(thold_att, hclkp);
if (tims->thold_att == 0)
tims->thold_att = 1;
else if (tims->thold_att > FMC2_PMEM_PATT_TIMING_MASK)
tims->thold_att = FMC2_PMEM_PATT_TIMING_MASK;
timing = DIV_ROUND_UP(thold_att, hclkp);
tims->thold_att = clamp_val(timing, 1, FMC2_PMEM_PATT_TIMING_MASK);
}
static int stm32_fmc2_setup_interface(struct nand_chip *chip, int chipnr,
......
......@@ -659,6 +659,7 @@ static int tango_nand_probe(struct platform_device *pdev)
err = chip_init(&pdev->dev, np);
if (err) {
tango_nand_remove(pdev);
of_node_put(np);
return err;
}
}
......
......@@ -862,6 +862,7 @@ static int vf610_nfc_probe(struct platform_device *pdev)
dev_err(nfc->dev,
"Only one NAND chip supported!\n");
err = -EINVAL;
of_node_put(child);
goto err_disable_clk;
}
......
# SPDX-License-Identifier: GPL-2.0-only
config MTD_AR7_PARTS
tristate "TI AR7 partitioning parser"
help
TI AR7 partitioning parser support
config MTD_BCM47XX_PARTS
tristate "BCM47XX partitioning parser"
depends on BCM47XX || ARCH_BCM_5301X
help
This provides partitions parser for devices based on BCM47xx
boards.
config MTD_BCM63XX_PARTS
tristate "BCM63XX CFE partitioning parser"
depends on BCM63XX || BMIPS_GENERIC || COMPILE_TEST
select CRC32
select MTD_PARSER_IMAGETAG
help
This provides partition parsing for BCM63xx devices with CFE
bootloaders.
config MTD_CMDLINE_PARTS
tristate "Command line partition table parsing"
depends on MTD
help
Allow generic configuration of the MTD partition tables via the kernel
command line. Multiple flash resources are supported for hardware where
different kinds of flash memory are available.
You will still need the parsing functions to be called by the driver
for your particular device. It won't happen automatically. The
SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for
example.
The format for the command line is as follows:
mtdparts=<mtddef>[;<mtddef]
<mtddef> := <mtd-id>:<partdef>[,<partdef>]
<partdef> := <size>[@offset][<name>][ro]
<mtd-id> := unique id used in mapping driver/device
<size> := standard linux memsize OR "-" to denote all
remaining space
<name> := (NAME)
Due to the way Linux handles the command line, no spaces are
allowed in the partition definition, including mtd id's and partition
names.
Examples:
1 flash resource (mtd-id "sa1100"), with 1 single writable partition:
mtdparts=sa1100:-
Same flash, but 2 named partitions, the first one being read-only:
mtdparts=sa1100:256k(ARMboot)ro,-(root)
If unsure, say 'N'.
config MTD_OF_PARTS
tristate "OpenFirmware (device tree) partitioning parser"
default y
depends on OF
help
This provides a open firmware device tree partition parser
which derives the partition map from the children of the
flash memory node, as described in
Documentation/devicetree/bindings/mtd/partition.txt.
config MTD_PARSER_IMAGETAG
tristate "Parser for BCM963XX Image Tag format partitions"
depends on BCM63XX || BMIPS_GENERIC || COMPILE_TEST
......
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_MTD_AR7_PARTS) += ar7part.o
obj-$(CONFIG_MTD_BCM47XX_PARTS) += bcm47xxpart.o
obj-$(CONFIG_MTD_BCM63XX_PARTS) += bcm63xxpart.o
obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o
obj-$(CONFIG_MTD_OF_PARTS) += ofpart.o
obj-$(CONFIG_MTD_PARSER_IMAGETAG) += parser_imagetag.o
obj-$(CONFIG_MTD_AFS_PARTS) += afs.o
obj-$(CONFIG_MTD_PARSER_TRX) += parser_trx.o
......
......@@ -774,8 +774,11 @@ static int sm_init_zone(struct sm_ftl *ftl, int zone_num)
continue;
/* Read the oob of first sector */
if (sm_read_sector(ftl, zone_num, block, 0, NULL, &oob))
if (sm_read_sector(ftl, zone_num, block, 0, NULL, &oob)) {
kfifo_free(&zone->free_sectors);
kfree(zone->lba_to_phys_table);
return -EIO;
}
/* Test to see if block is erased. It is enough to test
first sector, because erase happens in one shot */
......
......@@ -2,6 +2,8 @@
menuconfig MTD_SPI_NOR
tristate "SPI-NOR device support"
depends on MTD
depends on MTD && SPI_MASTER
select SPI_MEM
help
This is the framework for the SPI NOR which can be used by the SPI
device drivers and the SPI-NOR device driver.
......
......@@ -836,8 +836,10 @@ static int aspeed_smc_setup_flash(struct aspeed_smc_controller *controller,
controller->chips[cs] = chip;
}
if (ret)
if (ret) {
of_node_put(child);
aspeed_smc_unregister(controller);
}
return ret;
}
......
......@@ -13,6 +13,7 @@
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/jiffies.h>
#include <linux/kernel.h>
#include <linux/module.h>
......@@ -241,23 +242,13 @@ struct cqspi_driver_platdata {
#define CQSPI_IRQ_STATUS_MASK 0x1FFFF
static int cqspi_wait_for_bit(void __iomem *reg, const u32 mask, bool clear)
static int cqspi_wait_for_bit(void __iomem *reg, const u32 mask, bool clr)
{
unsigned long end = jiffies + msecs_to_jiffies(CQSPI_TIMEOUT_MS);
u32 val;
while (1) {
val = readl(reg);
if (clear)
val = ~val;
val &= mask;
if (val == mask)
return 0;
if (time_after(jiffies, end))
return -ETIMEDOUT;
}
return readl_relaxed_poll_timeout(reg, val,
(((clr ? ~val : val) & mask) == mask),
10, CQSPI_TIMEOUT_MS * 1000);
}
static bool cqspi_is_idle(struct cqspi_st *cqspi)
......
......@@ -401,6 +401,7 @@ static int hisi_spi_nor_register_all(struct hifmc_host *host)
if (host->num_chip == HIFMC_MAX_CHIP_NUM) {
dev_warn(dev, "Flash device number exceeds the maximum chipselect number\n");
of_node_put(np);
break;
}
}
......
......@@ -65,6 +65,7 @@ static const struct pci_device_id intel_spi_pci_ids[] = {
{ PCI_VDEVICE(INTEL, 0x19e0), (unsigned long)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x34a4), (unsigned long)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x4b24), (unsigned long)&bxt_info },
{ PCI_VDEVICE(INTEL, 0xa0a4), (unsigned long)&bxt_info },
{ PCI_VDEVICE(INTEL, 0xa1a4), (unsigned long)&bxt_info },
{ PCI_VDEVICE(INTEL, 0xa224), (unsigned long)&bxt_info },
{ },
......
......@@ -621,6 +621,8 @@ static ssize_t intel_spi_read(struct spi_nor *nor, loff_t from, size_t len,
switch (nor->read_opcode) {
case SPINOR_OP_READ:
case SPINOR_OP_READ_FAST:
case SPINOR_OP_READ_4B:
case SPINOR_OP_READ_FAST_4B:
break;
default:
return -EINVAL;
......
This diff is collapsed.
......@@ -189,6 +189,9 @@ struct module; /* only needed for owner field in mtd_info */
*/
struct mtd_debug_info {
struct dentry *dfs_dir;
const char *partname;
const char *partid;
};
struct mtd_info {
......
......@@ -346,7 +346,7 @@ static inline unsigned int nanddev_ntargets(const struct nand_device *nand)
}
/**
* nanddev_neraseblocks() - Get the total number of erasablocks
* nanddev_neraseblocks() - Get the total number of eraseblocks
* @nand: NAND device
*
* Return: the total number of eraseblocks exposed by @nand.
......
......@@ -5,6 +5,9 @@
* Copyright (C) 2008 Dmitry Baryshkov
*/
#ifndef _MTD_SHARPSL_H
#define _MTD_SHARPSL_H
#include <linux/mtd/rawnand.h>
#include <linux/mtd/nand_ecc.h>
#include <linux/mtd/partitions.h>
......@@ -16,3 +19,5 @@ struct sharpsl_nand_platform_data {
unsigned int nr_partitions;
const char *const *part_parsers;
};
#endif /* _MTD_SHARPSL_H */
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment