Commit 54245ed8 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull MTD updates from Brian Norris:
 "JFFS2:
   - fix a theoretical unbalanced locking issue; the lock handling was a
     bit unclean, but AFAICT, it didn't actually lead to real deadlocks

  NAND:
   - brcmnand driver: new driver supporting NAND controller found
     originally on Broadcom STB SoCs (BCM7xxx), but now also found on
     BCM63xxx, iProc (e.g., Cygnus, BCM5301x), BCM3xxx, and more

   - begin factoring out BBT code so it can be shared between
     traditional (parallel) NAND drivers and upcoming SPI NAND drivers
     (WIP)

   - add common DT-based init support, so nand_base can pick up some
     flash properties automatically, using established common NAND DT
     properties

   - mxc_nand: support 8-bit ECC

   - pxa3xx_nand:
     * fix build for ARM64
     * use a jiffies-based timeout

  SPI NOR:
   - add a few new IDs

   - clear out some unnecessary entries

   - make sure SECT_4K flags are correct for all (?) entries

  Core:
   - fix mtd->usecount race conditions (BUG_ON())

   - switch to modern PM ops

  Other:
   - CFI: save code space by de-inlining large functions

   - clean up some partition parser selection code across several
     drivers

   - various miscellaneous changes, mostly minor"

* tag 'for-linus-20150623' of git://git.infradead.org/linux-mtd: (57 commits)
  mtd: docg3: Fix kasprintf() usage
  mtd: docg3: Don't leak docg3->bbt in error path
  mtd: nandsim: Fix kasprintf() usage
  mtd: cs553x_nand: Fix kasprintf() usage
  mtd: r852: Fix device_create_file() usage
  mtd: brcmnand: drop unnecessary initialization
  mtd: propagate error codes from add_mtd_device()
  mtd: diskonchip: remove two-phase partitioning / registration
  mtd: dc21285: use raw spinlock functions for nw_gpio_lock
  mtd: chips: fixup dependencies, to prevent build error
  mtd: cfi_cmdset_0002: Initialize datum before calling map_word_load_partial
  mtd: cfi: deinline large functions
  mtd: lantiq-flash: use default partition parsers
  mtd: plat_nand: use default partition probe
  mtd: nand: correct indentation within conditional
  mtd: remove incorrect file name
  mtd: blktrans: use better error code for unimplemented ioctl()
  mtd: maps: Spelling s/reseved/reserved/
  mtd: blktrans: change blktrans_getgeo return value
  mtd: mxc_nand: generate nand_ecclayout for 8 bit ECC
  ...
parents 84e9c87e 0eb8618b
* Broadcom STB NAND Controller
The Broadcom Set-Top Box NAND controller supports low-level access to raw NAND
flash chips. It has a memory-mapped register interface for both control
registers and for its data input/output buffer. On some SoCs, this controller is
paired with a custom DMA engine (inventively named "Flash DMA") which supports
basic PROGRAM and READ functions, among other features.
This controller was originally designed for STB SoCs (BCM7xxx) but is now
available on a variety of Broadcom SoCs, including some BCM3xxx, BCM63xx, and
iProc/Cygnus. Its history includes several similar (but not fully register
compatible) versions.
Required properties:
- compatible : May contain an SoC-specific compatibility string (see below)
to account for any SoC-specific hardware bits that may be
added on top of the base core controller.
In addition, must contain compatibility information about
the core NAND controller, of the following form:
"brcm,brcmnand" and an appropriate version compatibility
string, like "brcm,brcmnand-v7.0"
Possible values:
brcm,brcmnand-v4.0
brcm,brcmnand-v5.0
brcm,brcmnand-v6.0
brcm,brcmnand-v6.1
brcm,brcmnand-v7.0
brcm,brcmnand-v7.1
brcm,brcmnand
- reg : the register start and length for NAND register region.
(optional) Flash DMA register range (if present)
(optional) NAND flash cache range (if at non-standard offset)
- reg-names : a list of the names corresponding to the previous register
ranges. Should contain "nand" and (optionally)
"flash-dma" and/or "nand-cache".
- interrupts : The NAND CTLRDY interrupt and (if Flash DMA is available)
FLASH_DMA_DONE
- interrupt-names : May be "nand_ctlrdy" or "flash_dma_done", if broken out as
individual interrupts.
May be "nand", if the SoC has the individual NAND
interrupts multiplexed behind another custom piece of
hardware
- interrupt-parent : See standard interrupt bindings
- #address-cells : <1> - subnodes give the chip-select number
- #size-cells : <0>
Optional properties:
- brcm,nand-has-wp : Some versions of this IP include a write-protect
(WP) control bit. It is always available on >=
v7.0. Use this property to describe the rare
earlier versions of this core that include WP
-- Additonal SoC-specific NAND controller properties --
The NAND controller is integrated differently on the variety of SoCs on which it
is found. Part of this integration involves providing status and enable bits
with which to control the 8 exposed NAND interrupts, as well as hardware for
configuring the endianness of the data bus. On some SoCs, these features are
handled via standard, modular components (e.g., their interrupts look like a
normal IRQ chip), but on others, they are controlled in unique and interesting
ways, sometimes with registers that lump multiple NAND-related functions
together. The former case can be described simply by the standard interrupts
properties in the main controller node. But for the latter exceptional cases,
we define additional 'compatible' properties and associated register resources within the NAND controller node above.
- compatible: Can be one of several SoC-specific strings. Each SoC may have
different requirements for its additional properties, as described below each
bullet point below.
* "brcm,nand-bcm63138"
- reg: (required) the 'NAND_INT_BASE' register range, with separate status
and enable registers
- reg-names: (required) "nand-int-base"
* "brcm,nand-iproc"
- reg: (required) the "IDM" register range, for interrupt enable and APB
bus access endianness configuration, and the "EXT" register range,
for interrupt status/ack.
- reg-names: (required) a list of the names corresponding to the previous
register ranges. Should contain "iproc-idm" and "iproc-ext".
* NAND chip-select
Each controller (compatible: "brcm,brcmnand") may contain one or more subnodes
to represent enabled chip-selects which (may) contain NAND flash chips. Their
properties are as follows.
Required properties:
- compatible : should contain "brcm,nandcs"
- reg : a single integer representing the chip-select
number (e.g., 0, 1, 2, etc.)
- #address-cells : see partition.txt
- #size-cells : see partition.txt
- nand-ecc-strength : see nand.txt
- nand-ecc-step-size : must be 512 or 1024. See nand.txt
Optional properties:
- nand-on-flash-bbt : boolean, to enable the on-flash BBT for this
chip-select. See nand.txt
- brcm,nand-oob-sector-size : integer, to denote the spare area sector size
expected for the ECC layout in use. This size, in
addition to the strength and step-size,
determines how the hardware BCH engine will lay
out the parity bytes it stores on the flash.
This property can be automatically determined by
the flash geometry (particularly the NAND page
and OOB size) in many cases, but when booting
from NAND, the boot controller has only a limited
number of available options for its default ECC
layout.
Each nandcs device node may optionally contain sub-nodes describing the flash
partition mapping. See partition.txt for more detail.
Example:
nand@f0442800 {
compatible = "brcm,brcmnand-v7.0", "brcm,brcmnand";
reg = <0xF0442800 0x600>,
<0xF0443000 0x100>;
reg-names = "nand", "flash-dma";
interrupt-parent = <&hif_intr2_intc>;
interrupts = <24>, <4>;
#address-cells = <1>;
#size-cells = <0>;
nandcs@1 {
compatible = "brcm,nandcs";
reg = <1>; // Chip select 1
nand-on-flash-bbt;
nand-ecc-strength = <12>;
nand-ecc-step-size = <512>;
// Partitions
#address-cells = <1>; // <2>, for 64-bit offset
#size-cells = <1>; // <2>, for 64-bit length
flash0.rootfs@0 {
reg = <0 0x10000000>;
};
flash0@0 {
reg = <0 0>; // MTDPART_SIZ_FULL
};
flash0.kernel@10000000 {
reg = <0x10000000 0x400000>;
};
};
};
......@@ -2267,6 +2267,12 @@ S: Supported
F: drivers/gpio/gpio-bcm-kona.c
F: Documentation/devicetree/bindings/gpio/gpio-bcm-kona.txt
BROADCOM STB NAND FLASH DRIVER
M: Brian Norris <computersforpeace@gmail.com>
L: linux-mtd@lists.infradead.org
S: Maintained
F: drivers/mtd/nand/brcmnand/
BROADCOM SPECIFIC AMBA DRIVER (BCMA)
M: Rafał Miłecki <zajec5@gmail.com>
L: linux-wireless@vger.kernel.org
......
......@@ -16,6 +16,7 @@ config MTD_CFI
config MTD_JEDECPROBE
tristate "Detect non-CFI AMD/JEDEC-compatible flash chips"
select MTD_GEN_PROBE
select MTD_CFI_UTIL
help
This option enables JEDEC-style probing of flash chips which are not
compatible with the Common Flash Interface, but will use the common
......
......@@ -1295,7 +1295,7 @@ static int do_otp_write(struct map_info *map, struct flchip *chip, loff_t adr,
unsigned long bus_ofs = adr & ~(map_bankwidth(map)-1);
int gap = adr - bus_ofs;
int n = min_t(int, len, map_bankwidth(map) - gap);
map_word datum;
map_word datum = map_word_ff(map);
if (n != map_bankwidth(map)) {
/* partial write of a word, load old contents */
......
......@@ -23,6 +23,194 @@
#include <linux/mtd/map.h>
#include <linux/mtd/cfi.h>
void cfi_udelay(int us)
{
if (us >= 1000) {
msleep((us+999)/1000);
} else {
udelay(us);
cond_resched();
}
}
EXPORT_SYMBOL(cfi_udelay);
/*
* Returns the command address according to the given geometry.
*/
uint32_t cfi_build_cmd_addr(uint32_t cmd_ofs,
struct map_info *map, struct cfi_private *cfi)
{
unsigned bankwidth = map_bankwidth(map);
unsigned interleave = cfi_interleave(cfi);
unsigned type = cfi->device_type;
uint32_t addr;
addr = (cmd_ofs * type) * interleave;
/* Modify the unlock address if we are in compatibility mode.
* For 16bit devices on 8 bit busses
* and 32bit devices on 16 bit busses
* set the low bit of the alternating bit sequence of the address.
*/
if (((type * interleave) > bankwidth) && ((cmd_ofs & 0xff) == 0xaa))
addr |= (type >> 1)*interleave;
return addr;
}
EXPORT_SYMBOL(cfi_build_cmd_addr);
/*
* Transforms the CFI command for the given geometry (bus width & interleave).
* It looks too long to be inline, but in the common case it should almost all
* get optimised away.
*/
map_word cfi_build_cmd(u_long cmd, struct map_info *map, struct cfi_private *cfi)
{
map_word val = { {0} };
int wordwidth, words_per_bus, chip_mode, chips_per_word;
unsigned long onecmd;
int i;
/* We do it this way to give the compiler a fighting chance
of optimising away all the crap for 'bankwidth' larger than
an unsigned long, in the common case where that support is
disabled */
if (map_bankwidth_is_large(map)) {
wordwidth = sizeof(unsigned long);
words_per_bus = (map_bankwidth(map)) / wordwidth; // i.e. normally 1
} else {
wordwidth = map_bankwidth(map);
words_per_bus = 1;
}
chip_mode = map_bankwidth(map) / cfi_interleave(cfi);
chips_per_word = wordwidth * cfi_interleave(cfi) / map_bankwidth(map);
/* First, determine what the bit-pattern should be for a single
device, according to chip mode and endianness... */
switch (chip_mode) {
default: BUG();
case 1:
onecmd = cmd;
break;
case 2:
onecmd = cpu_to_cfi16(map, cmd);
break;
case 4:
onecmd = cpu_to_cfi32(map, cmd);
break;
}
/* Now replicate it across the size of an unsigned long, or
just to the bus width as appropriate */
switch (chips_per_word) {
default: BUG();
#if BITS_PER_LONG >= 64
case 8:
onecmd |= (onecmd << (chip_mode * 32));
#endif
case 4:
onecmd |= (onecmd << (chip_mode * 16));
case 2:
onecmd |= (onecmd << (chip_mode * 8));
case 1:
;
}
/* And finally, for the multi-word case, replicate it
in all words in the structure */
for (i=0; i < words_per_bus; i++) {
val.x[i] = onecmd;
}
return val;
}
EXPORT_SYMBOL(cfi_build_cmd);
unsigned long cfi_merge_status(map_word val, struct map_info *map,
struct cfi_private *cfi)
{
int wordwidth, words_per_bus, chip_mode, chips_per_word;
unsigned long onestat, res = 0;
int i;
/* We do it this way to give the compiler a fighting chance
of optimising away all the crap for 'bankwidth' larger than
an unsigned long, in the common case where that support is
disabled */
if (map_bankwidth_is_large(map)) {
wordwidth = sizeof(unsigned long);
words_per_bus = (map_bankwidth(map)) / wordwidth; // i.e. normally 1
} else {
wordwidth = map_bankwidth(map);
words_per_bus = 1;
}
chip_mode = map_bankwidth(map) / cfi_interleave(cfi);
chips_per_word = wordwidth * cfi_interleave(cfi) / map_bankwidth(map);
onestat = val.x[0];
/* Or all status words together */
for (i=1; i < words_per_bus; i++) {
onestat |= val.x[i];
}
res = onestat;
switch(chips_per_word) {
default: BUG();
#if BITS_PER_LONG >= 64
case 8:
res |= (onestat >> (chip_mode * 32));
#endif
case 4:
res |= (onestat >> (chip_mode * 16));
case 2:
res |= (onestat >> (chip_mode * 8));
case 1:
;
}
/* Last, determine what the bit-pattern should be for a single
device, according to chip mode and endianness... */
switch (chip_mode) {
case 1:
break;
case 2:
res = cfi16_to_cpu(map, res);
break;
case 4:
res = cfi32_to_cpu(map, res);
break;
default: BUG();
}
return res;
}
EXPORT_SYMBOL(cfi_merge_status);
/*
* Sends a CFI command to a bank of flash for the given geometry.
*
* Returns the offset in flash where the command was written.
* If prev_val is non-null, it will be set to the value at the command address,
* before the command was written.
*/
uint32_t cfi_send_gen_cmd(u_char cmd, uint32_t cmd_addr, uint32_t base,
struct map_info *map, struct cfi_private *cfi,
int type, map_word *prev_val)
{
map_word val;
uint32_t addr = base + cfi_build_cmd_addr(cmd_addr, map, cfi);
val = cfi_build_cmd(cmd, map, cfi);
if (prev_val)
*prev_val = map_read(map, addr);
map_write(map, val, addr);
return addr - base;
}
EXPORT_SYMBOL(cfi_send_gen_cmd);
int __xipram cfi_qry_present(struct map_info *map, __u32 base,
struct cfi_private *cfi)
{
......
......@@ -1815,7 +1815,7 @@ static void doc_dbg_unregister(struct docg3 *docg3)
* @chip_id: The chip ID of the supported chip
* @mtd: The structure to fill
*/
static void __init doc_set_driver_info(int chip_id, struct mtd_info *mtd)
static int __init doc_set_driver_info(int chip_id, struct mtd_info *mtd)
{
struct docg3 *docg3 = mtd->priv;
int cfg;
......@@ -1828,6 +1828,8 @@ static void __init doc_set_driver_info(int chip_id, struct mtd_info *mtd)
case DOC_CHIPID_G3:
mtd->name = kasprintf(GFP_KERNEL, "docg3.%d",
docg3->device_id);
if (!mtd->name)
return -ENOMEM;
docg3->max_block = 2047;
break;
}
......@@ -1850,6 +1852,8 @@ static void __init doc_set_driver_info(int chip_id, struct mtd_info *mtd)
mtd->_block_isbad = doc_block_isbad;
mtd->ecclayout = &docg3_oobinfo;
mtd->ecc_strength = DOC_ECC_BCH_T;
return 0;
}
/**
......@@ -1900,7 +1904,7 @@ doc_probe_device(struct docg3_cascade *cascade, int floor, struct device *dev)
ret = 0;
if (chip_id != (u16)(~chip_id_inv)) {
goto nomem3;
goto nomem4;
}
switch (chip_id) {
......@@ -1910,15 +1914,19 @@ doc_probe_device(struct docg3_cascade *cascade, int floor, struct device *dev)
break;
default:
doc_err("Chip id %04x is not a DiskOnChip G3 chip\n", chip_id);
goto nomem3;
goto nomem4;
}
doc_set_driver_info(chip_id, mtd);
ret = doc_set_driver_info(chip_id, mtd);
if (ret)
goto nomem4;
doc_hamming_ecc_init(docg3, DOC_LAYOUT_OOB_PAGEINFO_SZ);
doc_reload_bbt(docg3);
return mtd;
nomem4:
kfree(docg3->bbt);
nomem3:
kfree(mtd);
nomem2:
......@@ -2117,7 +2125,7 @@ static int docg3_release(struct platform_device *pdev)
}
#ifdef CONFIG_OF
static struct of_device_id docg3_dt_ids[] = {
static const struct of_device_id docg3_dt_ids[] = {
{ .compatible = "m-systems,diskonchip-g3" },
{}
};
......
......@@ -261,45 +261,33 @@ static int m25p_remove(struct spi_device *spi)
* keep them available as module aliases for existing platforms.
*/
static const struct spi_device_id m25p_ids[] = {
{"at25fs010"}, {"at25fs040"}, {"at25df041a"}, {"at25df321a"},
{"at25df641"}, {"at26f004"}, {"at26df081a"}, {"at26df161a"},
{"at26df321"}, {"at45db081d"},
{"en25f32"}, {"en25p32"}, {"en25q32b"}, {"en25p64"},
{"en25q64"}, {"en25qh128"}, {"en25qh256"},
{"f25l32pa"},
{"mr25h256"}, {"mr25h10"},
{"gd25q32"}, {"gd25q64"},
{"160s33b"}, {"320s33b"}, {"640s33b"},
{"mx25l2005a"}, {"mx25l4005a"}, {"mx25l8005"}, {"mx25l1606e"},
{"mx25l3205d"}, {"mx25l3255e"}, {"mx25l6405d"}, {"mx25l12805d"},
{"mx25l12855e"},{"mx25l25635e"},{"mx25l25655e"},{"mx66l51235l"},
{"mx66l1g55g"},
{"n25q064"}, {"n25q128a11"}, {"n25q128a13"}, {"n25q256a"},
{"n25q512a"}, {"n25q512ax3"}, {"n25q00"},
{"pm25lv512"}, {"pm25lv010"}, {"pm25lq032"},
{"s25sl032p"}, {"s25sl064p"}, {"s25fl256s0"}, {"s25fl256s1"},
{"s25fl512s"}, {"s70fl01gs"}, {"s25sl12800"}, {"s25sl12801"},
{"s25fl129p0"}, {"s25fl129p1"}, {"s25sl004a"}, {"s25sl008a"},
{"s25sl016a"}, {"s25sl032a"}, {"s25sl064a"}, {"s25fl008k"},
{"s25fl016k"}, {"s25fl064k"}, {"s25fl132k"},
{"sst25vf040b"},{"sst25vf080b"},{"sst25vf016b"},{"sst25vf032b"},
{"sst25vf064c"},{"sst25wf512"}, {"sst25wf010"}, {"sst25wf020"},
{"sst25wf040"},
{"m25p05"}, {"m25p10"}, {"m25p20"}, {"m25p40"},
{"m25p80"}, {"m25p16"}, {"m25p32"}, {"m25p64"},
{"m25p128"}, {"n25q032"},
/*
* Entries not used in DTs that should be safe to drop after replacing
* them with "nor-jedec" in platform data.
*/
{"s25sl064a"}, {"w25x16"}, {"m25p10"}, {"m25px64"},
/*
* Entries that were used in DTs without "nor-jedec" fallback and should
* be kept for backward compatibility.
*/
{"at25df321a"}, {"at25df641"}, {"at26df081a"},
{"mr25h256"},
{"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"},
{"m45pe10"}, {"m45pe80"}, {"m45pe16"},
{"m25pe20"}, {"m25pe80"}, {"m25pe16"},
{"m25px16"}, {"m25px32"}, {"m25px32-s0"}, {"m25px32-s1"},
{"m25px64"}, {"m25px80"},
{"w25x10"}, {"w25x20"}, {"w25x40"}, {"w25x80"},
{"w25x16"}, {"w25x32"}, {"w25q32"}, {"w25q32dw"},
{"w25x64"}, {"w25q64"}, {"w25q80"}, {"w25q80bl"},
{"w25q128"}, {"w25q256"}, {"cat25c11"},
{"cat25c03"}, {"cat25c09"}, {"cat25c17"}, {"cat25128"},
/*
* Generic support for SPI NOR that can be identified by the JEDEC READ
......
/*
* SMI (Serial Memory Controller) device driver for Serial NOR Flash on
* SPEAr platform
* The serial nor interface is largely based on drivers/mtd/m25p80.c,
* however the SPI interface has been replaced by SMI.
* The serial nor interface is largely based on m25p80.c, however the SPI
* interface has been replaced by SMI.
*
* Copyright © 2010 STMicroelectronics.
* Ashish Priyadarshi
......
......@@ -326,7 +326,7 @@ config MTD_BFIN_ASYNC
config MTD_GPIO_ADDR
tristate "GPIO-assisted Flash Chip Support"
depends on GPIOLIB
depends on GPIOLIB || COMPILE_TEST
depends on MTD_COMPLEX_MAPPINGS
help
Map driver which allows flashes to be partially physically addressed
......
......@@ -138,7 +138,7 @@ static int amd76xrom_init_one(struct pci_dev *pdev,
/*
* Try to reserve the window mem region. If this fails then
* it is likely due to a fragment of the window being
* "reseved" by the BIOS. In the case that the
* "reserved" by the BIOS. In the case that the
* request_mem_region() fails then once the rom size is
* discovered we will try to reserve the unreserved fragment.
*/
......
......@@ -38,9 +38,9 @@ static void nw_en_write(void)
* we want to write a bit pattern XXX1 to Xilinx to enable
* the write gate, which will be open for about the next 2ms.
*/
spin_lock_irqsave(&nw_gpio_lock, flags);
raw_spin_lock_irqsave(&nw_gpio_lock, flags);
nw_cpld_modify(CPLD_FLASH_WR_ENABLE, CPLD_FLASH_WR_ENABLE);
spin_unlock_irqrestore(&nw_gpio_lock, flags);
raw_spin_unlock_irqrestore(&nw_gpio_lock, flags);
/*
* let the ISA bus to catch on...
......
......@@ -234,7 +234,7 @@ static int esb2rom_init_one(struct pci_dev *pdev,
/*
* Try to reserve the window mem region. If this fails then
* it is likely due to the window being "reseved" by the BIOS.
* it is likely due to the window being "reserved" by the BIOS.
*/
window->rsrc.name = MOD_NAME;
window->rsrc.start = window->phys;
......
......@@ -167,7 +167,7 @@ static int ichxrom_init_one(struct pci_dev *pdev,
/*
* Try to reserve the window mem region. If this fails then
* it is likely due to the window being "reseved" by the BIOS.
* it is likely due to the window being "reserved" by the BIOS.
*/
window->rsrc.name = MOD_NAME;
window->rsrc.start = window->phys;
......
......@@ -45,7 +45,6 @@ struct ltq_mtd {
};
static const char ltq_map_name[] = "ltq_nor";
static const char * const ltq_probe_types[] = { "cmdlinepart", "ofpart", NULL };
static map_word
ltq_read16(struct map_info *map, unsigned long adr)
......@@ -168,8 +167,7 @@ ltq_mtd_probe(struct platform_device *pdev)
cfi->addr_unlock2 ^= 1;
ppdata.of_node = pdev->dev.of_node;
err = mtd_device_parse_register(ltq_mtd->mtd, ltq_probe_types,
&ppdata, NULL, 0);
err = mtd_device_parse_register(ltq_mtd->mtd, NULL, &ppdata, NULL, 0);
if (err) {
dev_err(&pdev->dev, "failed to add partitions\n");
goto err_destroy;
......
......@@ -147,7 +147,7 @@ static void of_free_probes(const char * const *probes)
kfree(probes);
}
static struct of_device_id of_flash_match[];
static const struct of_device_id of_flash_match[];
static int of_flash_probe(struct platform_device *dev)
{
const char * const *part_probe_types;
......@@ -327,7 +327,7 @@ static int of_flash_probe(struct platform_device *dev)
return err;
}
static struct of_device_id of_flash_match[] = {
static const struct of_device_id of_flash_match[] = {
{
.compatible = "cfi-flash",
.data = (void *)"cfi_probe",
......
......@@ -197,6 +197,7 @@ static int blktrans_open(struct block_device *bdev, fmode_t mode)
return -ERESTARTSYS; /* FIXME: busy loop! -arnd*/
mutex_lock(&dev->lock);
mutex_lock(&mtd_table_mutex);
if (dev->open)
goto unlock;
......@@ -220,6 +221,7 @@ static int blktrans_open(struct block_device *bdev, fmode_t mode)
unlock:
dev->open++;
mutex_unlock(&mtd_table_mutex);
mutex_unlock(&dev->lock);
blktrans_dev_put(dev);
return ret;
......@@ -230,6 +232,7 @@ static int blktrans_open(struct block_device *bdev, fmode_t mode)
error_put:
module_put(dev->tr->owner);
kref_put(&dev->ref, blktrans_dev_release);
mutex_unlock(&mtd_table_mutex);
mutex_unlock(&dev->lock);
blktrans_dev_put(dev);
return ret;
......@@ -243,6 +246,7 @@ static void blktrans_release(struct gendisk *disk, fmode_t mode)
return;
mutex_lock(&dev->lock);
mutex_lock(&mtd_table_mutex);
if (--dev->open)
goto unlock;
......@@ -256,6 +260,7 @@ static void blktrans_release(struct gendisk *disk, fmode_t mode)
__put_mtd_device(dev->mtd);
}
unlock:
mutex_unlock(&mtd_table_mutex);
mutex_unlock(&dev->lock);
blktrans_dev_put(dev);
}
......@@ -273,7 +278,7 @@ static int blktrans_getgeo(struct block_device *bdev, struct hd_geometry *geo)
if (!dev->mtd)
goto unlock;
ret = dev->tr->getgeo ? dev->tr->getgeo(dev, geo) : 0;
ret = dev->tr->getgeo ? dev->tr->getgeo(dev, geo) : -ENOTTY;
unlock:
mutex_unlock(&dev->lock);
blktrans_dev_put(dev);
......
......@@ -48,14 +48,34 @@
static struct backing_dev_info mtd_bdi = {
};
static int mtd_cls_suspend(struct device *dev, pm_message_t state);
static int mtd_cls_resume(struct device *dev);
#ifdef CONFIG_PM_SLEEP
static int mtd_cls_suspend(struct device *dev)
{
struct mtd_info *mtd = dev_get_drvdata(dev);
return mtd ? mtd_suspend(mtd) : 0;
}
static int mtd_cls_resume(struct device *dev)
{
struct mtd_info *mtd = dev_get_drvdata(dev);
if (mtd)
mtd_resume(mtd);
return 0;
}
static SIMPLE_DEV_PM_OPS(mtd_cls_pm_ops, mtd_cls_suspend, mtd_cls_resume);
#define MTD_CLS_PM_OPS (&mtd_cls_pm_ops)
#else
#define MTD_CLS_PM_OPS NULL
#endif
static struct class mtd_class = {
.name = "mtd",
.owner = THIS_MODULE,
.suspend = mtd_cls_suspend,
.resume = mtd_cls_resume,
.pm = MTD_CLS_PM_OPS,
};
static DEFINE_IDR(mtd_idr);
......@@ -88,22 +108,6 @@ static void mtd_release(struct device *dev)
device_destroy(&mtd_class, index + 1);
}
static int mtd_cls_suspend(struct device *dev, pm_message_t state)
{
struct mtd_info *mtd = dev_get_drvdata(dev);
return mtd ? mtd_suspend(mtd) : 0;
}
static int mtd_cls_resume(struct device *dev)
{
struct mtd_info *mtd = dev_get_drvdata(dev);
if (mtd)
mtd_resume(mtd);
return 0;
}
static ssize_t mtd_type_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
......@@ -375,8 +379,7 @@ static int mtd_reboot_notifier(struct notifier_block *n, unsigned long state,
*
* Add a device to the list of MTD devices present in the system, and
* notify each currently active MTD 'user' of its arrival. Returns
* zero on success or 1 on failure, which currently will only happen
* if there is insufficient memory or a sysfs error.
* zero on success or non-zero on failure.
*/
int add_mtd_device(struct mtd_info *mtd)
......@@ -390,8 +393,10 @@ int add_mtd_device(struct mtd_info *mtd)
mutex_lock(&mtd_table_mutex);
i = idr_alloc(&mtd_idr, mtd, 0, 0, GFP_KERNEL);
if (i < 0)
if (i < 0) {
error = i;
goto fail_locked;
}
mtd->index = i;
mtd->usecount = 0;
......@@ -420,6 +425,8 @@ int add_mtd_device(struct mtd_info *mtd)
printk(KERN_WARNING
"%s: unlock failed, writes may not work\n",
mtd->name);
/* Ignore unlock failures? */
error = 0;
}
/* Caller should have set dev.parent to match the
......@@ -430,7 +437,8 @@ int add_mtd_device(struct mtd_info *mtd)
mtd->dev.devt = MTD_DEVT(i);
dev_set_name(&mtd->dev, "mtd%d", i);
dev_set_drvdata(&mtd->dev, mtd);
if (device_register(&mtd->dev) != 0)
error = device_register(&mtd->dev);
if (error)
goto fail_added;
device_create(&mtd_class, mtd->dev.parent, MTD_DEVT(i) + 1, NULL,
......@@ -454,7 +462,7 @@ int add_mtd_device(struct mtd_info *mtd)
idr_remove(&mtd_idr, i);
fail_locked:
mutex_unlock(&mtd_table_mutex);
return 1;
return error;
}
/**
......@@ -510,8 +518,8 @@ static int mtd_add_device_partitions(struct mtd_info *mtd,
if (nbparts == 0 || IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER)) {
ret = add_mtd_device(mtd);
if (ret == 1)
return -ENODEV;
if (ret)
return ret;
}
if (nbparts > 0) {
......
......@@ -76,7 +76,7 @@ config MTD_NAND_DENALI_SCRATCH_REG_ADDR
config MTD_NAND_GPIO
tristate "GPIO assisted NAND Flash driver"
depends on GPIOLIB
depends on GPIOLIB || COMPILE_TEST
help
This enables a NAND flash driver where control signals are
connected to GPIO pins, and commands and data are communicated
......@@ -394,6 +394,14 @@ config MTD_NAND_GPMI_NAND
block, such as SD card. So pay attention to it when you enable
the GPMI.
config MTD_NAND_BRCMNAND
tristate "Broadcom STB NAND controller"
depends on ARM || MIPS
help
Enables the Broadcom NAND controller driver. The controller was
originally designed for Set-Top Box but is used on various BCM7xxx,
BCM3xxx, BCM63xxx, iProc/Cygnus and more.
config MTD_NAND_BCM47XXNFLASH
tristate "Support for NAND flash on BCM4706 BCMA bus"
depends on BCMA_NFLASH
......
......@@ -52,5 +52,6 @@ obj-$(CONFIG_MTD_NAND_XWAY) += xway_nand.o
obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH) += bcm47xxnflash/
obj-$(CONFIG_MTD_NAND_SUNXI) += sunxi_nand.o
obj-$(CONFIG_MTD_NAND_HISI504) += hisi504_nand.o
obj-$(CONFIG_MTD_NAND_BRCMNAND) += brcmnand/
nand-objs := nand_base.o nand_bbt.o nand_timings.o
# link order matters; don't link the more generic brcmstb_nand.o before the
# more specific iproc_nand.o, for instance
obj-$(CONFIG_MTD_NAND_BRCMNAND) += iproc_nand.o
obj-$(CONFIG_MTD_NAND_BRCMNAND) += bcm63138_nand.o
obj-$(CONFIG_MTD_NAND_BRCMNAND) += brcmstb_nand.o
obj-$(CONFIG_MTD_NAND_BRCMNAND) += brcmnand.o
/*
* Copyright © 2015 Broadcom Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/device.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include "brcmnand.h"
struct bcm63138_nand_soc_priv {
void __iomem *base;
};
#define BCM63138_NAND_INT_STATUS 0x00
#define BCM63138_NAND_INT_EN 0x04
enum {
BCM63138_CTLRDY = BIT(4),
};
static bool bcm63138_nand_intc_ack(struct brcmnand_soc *soc)
{
struct bcm63138_nand_soc_priv *priv = soc->priv;
void __iomem *mmio = priv->base + BCM63138_NAND_INT_STATUS;
u32 val = brcmnand_readl(mmio);
if (val & BCM63138_CTLRDY) {
brcmnand_writel(val & ~BCM63138_CTLRDY, mmio);
return true;
}
return false;
}
static void bcm63138_nand_intc_set(struct brcmnand_soc *soc, bool en)
{
struct bcm63138_nand_soc_priv *priv = soc->priv;
void __iomem *mmio = priv->base + BCM63138_NAND_INT_EN;
u32 val = brcmnand_readl(mmio);
if (en)
val |= BCM63138_CTLRDY;
else
val &= ~BCM63138_CTLRDY;
brcmnand_writel(val, mmio);
}
static int bcm63138_nand_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct bcm63138_nand_soc_priv *priv;
struct brcmnand_soc *soc;
struct resource *res;
soc = devm_kzalloc(dev, sizeof(*soc), GFP_KERNEL);
if (!soc)
return -ENOMEM;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand-int-base");
priv->base = devm_ioremap_resource(dev, res);
if (IS_ERR(priv->base))
return PTR_ERR(priv->base);
soc->pdev = pdev;
soc->priv = priv;
soc->ctlrdy_ack = bcm63138_nand_intc_ack;
soc->ctlrdy_set_enabled = bcm63138_nand_intc_set;
return brcmnand_probe(pdev, soc);
}
static const struct of_device_id bcm63138_nand_of_match[] = {
{ .compatible = "brcm,nand-bcm63138" },
{},
};
MODULE_DEVICE_TABLE(of, bcm63138_nand_of_match);
static struct platform_driver bcm63138_nand_driver = {
.probe = bcm63138_nand_probe,
.remove = brcmnand_remove,
.driver = {
.name = "bcm63138_nand",
.pm = &brcmnand_pm_ops,
.of_match_table = bcm63138_nand_of_match,
}
};
module_platform_driver(bcm63138_nand_driver);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Brian Norris");
MODULE_DESCRIPTION("NAND driver for BCM63138");
This diff is collapsed.
/*
* Copyright © 2015 Broadcom Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef __BRCMNAND_H__
#define __BRCMNAND_H__
#include <linux/types.h>
#include <linux/io.h>
struct platform_device;
struct dev_pm_ops;
struct brcmnand_soc {
struct platform_device *pdev;
void *priv;
bool (*ctlrdy_ack)(struct brcmnand_soc *soc);
void (*ctlrdy_set_enabled)(struct brcmnand_soc *soc, bool en);
void (*prepare_data_bus)(struct brcmnand_soc *soc, bool prepare);
};
static inline void brcmnand_soc_data_bus_prepare(struct brcmnand_soc *soc)
{
if (soc && soc->prepare_data_bus)
soc->prepare_data_bus(soc, true);
}
static inline void brcmnand_soc_data_bus_unprepare(struct brcmnand_soc *soc)
{
if (soc && soc->prepare_data_bus)
soc->prepare_data_bus(soc, false);
}
static inline u32 brcmnand_readl(void __iomem *addr)
{
/*
* MIPS endianness is configured by boot strap, which also reverses all
* bus endianness (i.e., big-endian CPU + big endian bus ==> native
* endian I/O).
*
* Other architectures (e.g., ARM) either do not support big endian, or
* else leave I/O in little endian mode.
*/
if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(__BIG_ENDIAN))
return __raw_readl(addr);
else
return readl_relaxed(addr);
}
static inline void brcmnand_writel(u32 val, void __iomem *addr)
{
/* See brcmnand_readl() comments */
if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(__BIG_ENDIAN))
__raw_writel(val, addr);
else
writel_relaxed(val, addr);
}
int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc);
int brcmnand_remove(struct platform_device *pdev);
extern const struct dev_pm_ops brcmnand_pm_ops;
#endif /* __BRCMNAND_H__ */
/*
* Copyright © 2015 Broadcom Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/device.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include "brcmnand.h"
static const struct of_device_id brcmstb_nand_of_match[] = {
{ .compatible = "brcm,brcmnand" },
{},
};
MODULE_DEVICE_TABLE(of, brcmstb_nand_of_match);
static int brcmstb_nand_probe(struct platform_device *pdev)
{
return brcmnand_probe(pdev, NULL);
}
static struct platform_driver brcmstb_nand_driver = {
.probe = brcmstb_nand_probe,
.remove = brcmnand_remove,
.driver = {
.name = "brcmstb_nand",
.pm = &brcmnand_pm_ops,
.of_match_table = brcmstb_nand_of_match,
}
};
module_platform_driver(brcmstb_nand_driver);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Brian Norris");
MODULE_DESCRIPTION("NAND driver for Broadcom STB chips");
/*
* Copyright © 2015 Broadcom Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/device.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include "brcmnand.h"
struct iproc_nand_soc_priv {
void __iomem *idm_base;
void __iomem *ext_base;
spinlock_t idm_lock;
};
#define IPROC_NAND_CTLR_READY_OFFSET 0x10
#define IPROC_NAND_CTLR_READY BIT(0)
#define IPROC_NAND_IO_CTRL_OFFSET 0x00
#define IPROC_NAND_APB_LE_MODE BIT(24)
#define IPROC_NAND_INT_CTRL_READ_ENABLE BIT(6)
static bool iproc_nand_intc_ack(struct brcmnand_soc *soc)
{
struct iproc_nand_soc_priv *priv = soc->priv;
void __iomem *mmio = priv->ext_base + IPROC_NAND_CTLR_READY_OFFSET;
u32 val = brcmnand_readl(mmio);
if (val & IPROC_NAND_CTLR_READY) {
brcmnand_writel(IPROC_NAND_CTLR_READY, mmio);
return true;
}
return false;
}
static void iproc_nand_intc_set(struct brcmnand_soc *soc, bool en)
{
struct iproc_nand_soc_priv *priv = soc->priv;
void __iomem *mmio = priv->idm_base + IPROC_NAND_IO_CTRL_OFFSET;
u32 val;
unsigned long flags;
spin_lock_irqsave(&priv->idm_lock, flags);
val = brcmnand_readl(mmio);
if (en)
val |= IPROC_NAND_INT_CTRL_READ_ENABLE;
else
val &= ~IPROC_NAND_INT_CTRL_READ_ENABLE;
brcmnand_writel(val, mmio);
spin_unlock_irqrestore(&priv->idm_lock, flags);
}
static void iproc_nand_apb_access(struct brcmnand_soc *soc, bool prepare)
{
struct iproc_nand_soc_priv *priv = soc->priv;
void __iomem *mmio = priv->idm_base + IPROC_NAND_IO_CTRL_OFFSET;
u32 val;
unsigned long flags;
spin_lock_irqsave(&priv->idm_lock, flags);
val = brcmnand_readl(mmio);
if (prepare)
val |= IPROC_NAND_APB_LE_MODE;
else
val &= ~IPROC_NAND_APB_LE_MODE;
brcmnand_writel(val, mmio);
spin_unlock_irqrestore(&priv->idm_lock, flags);
}
static int iproc_nand_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct iproc_nand_soc_priv *priv;
struct brcmnand_soc *soc;
struct resource *res;
soc = devm_kzalloc(dev, sizeof(*soc), GFP_KERNEL);
if (!soc)
return -ENOMEM;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
spin_lock_init(&priv->idm_lock);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iproc-idm");
priv->idm_base = devm_ioremap_resource(dev, res);
if (IS_ERR(priv->idm_base))
return PTR_ERR(priv->idm_base);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iproc-ext");
priv->ext_base = devm_ioremap_resource(dev, res);
if (IS_ERR(priv->ext_base))
return PTR_ERR(priv->ext_base);
soc->pdev = pdev;
soc->priv = priv;
soc->ctlrdy_ack = iproc_nand_intc_ack;
soc->ctlrdy_set_enabled = iproc_nand_intc_set;
soc->prepare_data_bus = iproc_nand_apb_access;
return brcmnand_probe(pdev, soc);
}
static const struct of_device_id iproc_nand_of_match[] = {
{ .compatible = "brcm,nand-iproc" },
{},
};
MODULE_DEVICE_TABLE(of, iproc_nand_of_match);
static struct platform_driver iproc_nand_driver = {
.probe = iproc_nand_probe,
.remove = brcmnand_remove,
.driver = {
.name = "iproc_nand",
.pm = &brcmnand_pm_ops,
.of_match_table = iproc_nand_of_match,
}
};
module_platform_driver(iproc_nand_driver);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Brian Norris");
MODULE_AUTHOR("Ray Jui");
MODULE_DESCRIPTION("NAND driver for Broadcom IPROC-based SoCs");
......@@ -237,17 +237,23 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr)
/* Enable the following for a flash based bad block table */
this->bbt_options = NAND_BBT_USE_FLASH;
new_mtd->name = kasprintf(GFP_KERNEL, "cs553x_nand_cs%d", cs);
if (!new_mtd->name) {
err = -ENOMEM;
goto out_ior;
}
/* Scan to find existence of the device */
if (nand_scan(new_mtd, 1)) {
err = -ENXIO;
goto out_ior;
goto out_free;
}
new_mtd->name = kasprintf(GFP_KERNEL, "cs553x_nand_cs%d", cs);
cs553x_mtd[cs] = new_mtd;
goto out;
out_free:
kfree(new_mtd->name);
out_ior:
iounmap(this->IO_ADDR_R);
out_mtd:
......
......@@ -69,6 +69,9 @@ struct doc_priv {
int mh0_page;
int mh1_page;
struct mtd_info *nextdoc;
/* Handle the last stage of initialization (BBT scan, partitioning) */
int (*late_init)(struct mtd_info *mtd);
};
/* This is the syndrome computed by the HW ecc generator upon reading an empty
......@@ -1294,14 +1297,11 @@ static int __init nftl_scan_bbt(struct mtd_info *mtd)
this->bbt_md = NULL;
}
/* It's safe to set bd=NULL below because NAND_BBT_CREATE is not set.
At least as nand_bbt.c is currently written. */
if ((ret = nand_scan_bbt(mtd, NULL)))
ret = this->scan_bbt(mtd);
if (ret)
return ret;
mtd_device_register(mtd, NULL, 0);
if (!no_autopart)
mtd_device_register(mtd, parts, numparts);
return 0;
return mtd_device_register(mtd, parts, no_autopart ? 0 : numparts);
}
static int __init inftl_scan_bbt(struct mtd_info *mtd)
......@@ -1344,10 +1344,10 @@ static int __init inftl_scan_bbt(struct mtd_info *mtd)
this->bbt_md->pattern = "TBB_SYSM";
}
/* It's safe to set bd=NULL below because NAND_BBT_CREATE is not set.
At least as nand_bbt.c is currently written. */
if ((ret = nand_scan_bbt(mtd, NULL)))
ret = this->scan_bbt(mtd);
if (ret)
return ret;
memset((char *)parts, 0, sizeof(parts));
numparts = inftl_partscan(mtd, parts);
/* At least for now, require the INFTL Media Header. We could probably
......@@ -1355,10 +1355,7 @@ static int __init inftl_scan_bbt(struct mtd_info *mtd)
autopartitioning, but I want to give it more thought. */
if (!numparts)
return -EIO;
mtd_device_register(mtd, NULL, 0);
if (!no_autopart)
mtd_device_register(mtd, parts, numparts);
return 0;
return mtd_device_register(mtd, parts, no_autopart ? 0 : numparts);
}
static inline int __init doc2000_init(struct mtd_info *mtd)
......@@ -1369,7 +1366,7 @@ static inline int __init doc2000_init(struct mtd_info *mtd)
this->read_byte = doc2000_read_byte;
this->write_buf = doc2000_writebuf;
this->read_buf = doc2000_readbuf;
this->scan_bbt = nftl_scan_bbt;
doc->late_init = nftl_scan_bbt;
doc->CDSNControl = CDSN_CTRL_FLASH_IO | CDSN_CTRL_ECC_IO;
doc2000_count_chips(mtd);
......@@ -1396,13 +1393,13 @@ static inline int __init doc2001_init(struct mtd_info *mtd)
can have multiple chips. */
doc2000_count_chips(mtd);
mtd->name = "DiskOnChip 2000 (INFTL Model)";
this->scan_bbt = inftl_scan_bbt;
doc->late_init = inftl_scan_bbt;
return (4 * doc->chips_per_floor);
} else {
/* Bog-standard Millennium */
doc->chips_per_floor = 1;
mtd->name = "DiskOnChip Millennium";
this->scan_bbt = nftl_scan_bbt;
doc->late_init = nftl_scan_bbt;
return 1;
}
}
......@@ -1415,7 +1412,7 @@ static inline int __init doc2001plus_init(struct mtd_info *mtd)
this->read_byte = doc2001plus_read_byte;
this->write_buf = doc2001plus_writebuf;
this->read_buf = doc2001plus_readbuf;
this->scan_bbt = inftl_scan_bbt;
doc->late_init = inftl_scan_bbt;
this->cmd_ctrl = NULL;
this->select_chip = doc2001plus_select_chip;
this->cmdfunc = doc2001plus_command;
......@@ -1591,6 +1588,8 @@ static int __init doc_probe(unsigned long physadr)
nand->ecc.bytes = 6;
nand->ecc.strength = 2;
nand->bbt_options = NAND_BBT_USE_FLASH;
/* Skip the automatic BBT scan so we can run it manually */
nand->options |= NAND_SKIP_BBTSCAN;
doc->physadr = physadr;
doc->virtadr = virtadr;
......@@ -1608,7 +1607,7 @@ static int __init doc_probe(unsigned long physadr)
else
numchips = doc2001_init(mtd);
if ((ret = nand_scan(mtd, numchips))) {
if ((ret = nand_scan(mtd, numchips)) || (ret = doc->late_init(mtd))) {
/* DBB note: i believe nand_release is necessary here, as
buffers may have been allocated in nand_base. Check with
Thomas. FIX ME! */
......
......@@ -562,6 +562,7 @@ static int dma_xfer(struct fsmc_nand_data *host, void *buffer, int len,
dma_cookie_t cookie;
unsigned long flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
int ret;
unsigned long time_left;
if (direction == DMA_TO_DEVICE)
chan = host->write_dma_chan;
......@@ -601,14 +602,13 @@ static int dma_xfer(struct fsmc_nand_data *host, void *buffer, int len,
dma_async_issue_pending(chan);
ret =
time_left =
wait_for_completion_timeout(&host->dma_access_complete,
msecs_to_jiffies(3000));
if (ret <= 0) {
if (time_left == 0) {
dmaengine_terminate_all(chan);
dev_err(host->dev, "wait_for_completion_timeout\n");
if (!ret)
ret = -ETIMEDOUT;
ret = -ETIMEDOUT;
goto unmap_dma;
}
......
......@@ -837,7 +837,7 @@ static int mpc5121_nfc_remove(struct platform_device *op)
return 0;
}
static struct of_device_id mpc5121_nfc_match[] = {
static const struct of_device_id mpc5121_nfc_match[] = {
{ .compatible = "fsl,mpc5121-nfc", },
{},
};
......
......@@ -189,6 +189,7 @@ struct mxc_nand_host {
int clk_act;
int irq;
int eccsize;
int used_oobsize;
int active_cs;
struct completion op_completion;
......@@ -280,12 +281,44 @@ static void memcpy32_fromio(void *trg, const void __iomem *src, size_t size)
*t++ = __raw_readl(s++);
}
static void memcpy16_fromio(void *trg, const void __iomem *src, size_t size)
{
int i;
u16 *t = trg;
const __iomem u16 *s = src;
/* We assume that src (IO) is always 32bit aligned */
if (PTR_ALIGN(trg, 4) == trg && IS_ALIGNED(size, 4)) {
memcpy32_fromio(trg, src, size);
return;
}
for (i = 0; i < (size >> 1); i++)
*t++ = __raw_readw(s++);
}
static inline void memcpy32_toio(void __iomem *trg, const void *src, int size)
{
/* __iowrite32_copy use 32bit size values so divide by 4 */
__iowrite32_copy(trg, src, size / 4);
}
static void memcpy16_toio(void __iomem *trg, const void *src, int size)
{
int i;
__iomem u16 *t = trg;
const u16 *s = src;
/* We assume that trg (IO) is always 32bit aligned */
if (PTR_ALIGN(src, 4) == src && IS_ALIGNED(size, 4)) {
memcpy32_toio(trg, src, size);
return;
}
for (i = 0; i < (size >> 1); i++)
__raw_writew(*s++, t++);
}
static int check_int_v3(struct mxc_nand_host *host)
{
uint32_t tmp;
......@@ -807,32 +840,48 @@ static void mxc_nand_select_chip_v2(struct mtd_info *mtd, int chip)
}
/*
* Function to transfer data to/from spare area.
* The controller splits a page into data chunks of 512 bytes + partial oob.
* There are writesize / 512 such chunks, the size of the partial oob parts is
* oobsize / #chunks rounded down to a multiple of 2. The last oob chunk then
* contains additionally the byte lost by rounding (if any).
* This function handles the needed shuffling between host->data_buf (which
* holds a page in natural order, i.e. writesize bytes data + oobsize bytes
* spare) and the NFC buffer.
*/
static void copy_spare(struct mtd_info *mtd, bool bfrom)
{
struct nand_chip *this = mtd->priv;
struct mxc_nand_host *host = this->priv;
u16 i, j;
u16 n = mtd->writesize >> 9;
u16 i, oob_chunk_size;
u16 num_chunks = mtd->writesize / 512;
u8 *d = host->data_buf + mtd->writesize;
u8 __iomem *s = host->spare0;
u16 t = host->devtype_data->spare_len;
u16 sparebuf_size = host->devtype_data->spare_len;
j = (mtd->oobsize / n >> 1) << 1;
/* size of oob chunk for all but possibly the last one */
oob_chunk_size = (host->used_oobsize / num_chunks) & ~1;
if (bfrom) {
for (i = 0; i < n - 1; i++)
memcpy32_fromio(d + i * j, s + i * t, j);
/* the last section */
memcpy32_fromio(d + i * j, s + i * t, mtd->oobsize - i * j);
for (i = 0; i < num_chunks - 1; i++)
memcpy16_fromio(d + i * oob_chunk_size,
s + i * sparebuf_size,
oob_chunk_size);
/* the last chunk */
memcpy16_fromio(d + i * oob_chunk_size,
s + i * sparebuf_size,
host->used_oobsize - i * oob_chunk_size);
} else {
for (i = 0; i < n - 1; i++)
memcpy32_toio(&s[i * t], &d[i * j], j);
/* the last section */
memcpy32_toio(&s[i * t], &d[i * j], mtd->oobsize - i * j);
for (i = 0; i < num_chunks - 1; i++)
memcpy16_toio(&s[i * sparebuf_size],
&d[i * oob_chunk_size],
oob_chunk_size);
/* the last chunk */
memcpy16_toio(&s[oob_chunk_size * sparebuf_size],
&d[i * oob_chunk_size],
host->used_oobsize - i * oob_chunk_size);
}
}
......@@ -911,6 +960,23 @@ static int get_eccsize(struct mtd_info *mtd)
return 8;
}
static void ecc_8bit_layout_4k(struct nand_ecclayout *layout)
{
int i, j;
layout->eccbytes = 8*18;
for (i = 0; i < 8; i++)
for (j = 0; j < 18; j++)
layout->eccpos[i*18 + j] = i*26 + j + 7;
layout->oobfree[0].offset = 2;
layout->oobfree[0].length = 4;
for (i = 1; i < 8; i++) {
layout->oobfree[i].offset = i*26;
layout->oobfree[i].length = 7;
}
}
static void preset_v1(struct mtd_info *mtd)
{
struct nand_chip *nand_chip = mtd->priv;
......@@ -1350,7 +1416,7 @@ static inline int is_imx53_nfc(struct mxc_nand_host *host)
return host->devtype_data == &imx53_nand_devtype_data;
}
static struct platform_device_id mxcnd_devtype[] = {
static const struct platform_device_id mxcnd_devtype[] = {
{
.name = "imx21-nand",
.driver_data = (kernel_ulong_t) &imx21_nand_devtype_data,
......@@ -1587,8 +1653,20 @@ static int mxcnd_probe(struct platform_device *pdev)
if (mtd->writesize == 2048)
this->ecc.layout = host->devtype_data->ecclayout_2k;
else if (mtd->writesize == 4096)
else if (mtd->writesize == 4096) {
this->ecc.layout = host->devtype_data->ecclayout_4k;
if (get_eccsize(mtd) == 8)
ecc_8bit_layout_4k(this->ecc.layout);
}
/*
* Experimentation shows that i.MX NFC can only handle up to 218 oob
* bytes. Limit used_oobsize to 218 so as to not confuse copy_spare()
* into copying invalid data to/from the spare IO buffer, as this
* might cause ECC data corruption when doing sub-page write to a
* partially written page.
*/
host->used_oobsize = min(mtd->oobsize, 218U);
if (this->ecc.mode == NAND_ECC_HW) {
if (is_imx21_nfc(host) || is_imx27_nfc(host))
......
/*
* drivers/mtd/nand.c
*
* Overview:
* This is the generic MTD driver for NAND flash devices. It should be
* capable of working with almost all NAND chips currently available.
......@@ -48,6 +46,7 @@
#include <linux/leds.h>
#include <linux/io.h>
#include <linux/mtd/partitions.h>
#include <linux/of_mtd.h>
/* Define default oob placement schemes for large and small page devices */
static struct nand_ecclayout nand_oob_8 = {
......@@ -2928,9 +2927,6 @@ static int nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip,
& ONFI_OPT_CMD_SET_GET_FEATURES))
return -EINVAL;
/* clear the sub feature parameters */
memset(subfeature_param, 0, ONFI_SUBFEATURE_PARAM_LEN);
chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES, addr, -1);
for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
*subfeature_param++ = chip->read_byte(mtd);
......@@ -3689,7 +3685,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
if (find_full_id_nand(mtd, chip, type, id_data, &busw))
goto ident_done;
} else if (*dev_id == type->dev_id) {
break;
break;
}
}
......@@ -3798,6 +3794,39 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
return type;
}
static int nand_dt_init(struct mtd_info *mtd, struct nand_chip *chip,
struct device_node *dn)
{
int ecc_mode, ecc_strength, ecc_step;
if (of_get_nand_bus_width(dn) == 16)
chip->options |= NAND_BUSWIDTH_16;
if (of_get_nand_on_flash_bbt(dn))
chip->bbt_options |= NAND_BBT_USE_FLASH;
ecc_mode = of_get_nand_ecc_mode(dn);
ecc_strength = of_get_nand_ecc_strength(dn);
ecc_step = of_get_nand_ecc_step_size(dn);
if ((ecc_step >= 0 && !(ecc_strength >= 0)) ||
(!(ecc_step >= 0) && ecc_strength >= 0)) {
pr_err("must set both strength and step size in DT\n");
return -EINVAL;
}
if (ecc_mode >= 0)
chip->ecc.mode = ecc_mode;
if (ecc_strength >= 0)
chip->ecc.strength = ecc_strength;
if (ecc_step > 0)
chip->ecc.size = ecc_step;
return 0;
}
/**
* nand_scan_ident - [NAND Interface] Scan for the NAND device
* @mtd: MTD device structure
......@@ -3815,6 +3844,13 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
int i, nand_maf_id, nand_dev_id;
struct nand_chip *chip = mtd->priv;
struct nand_flash_dev *type;
int ret;
if (chip->dn) {
ret = nand_dt_init(mtd, chip, chip->dn);
if (ret)
return ret;
}
/* Set the default functions */
nand_set_defaults(chip, chip->options & NAND_BUSWIDTH_16);
......
/*
* drivers/mtd/nand_bbt.c
*
* Overview:
* Bad block table support for the NAND driver
*
......@@ -64,7 +62,6 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/bbm.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/nand_ecc.h>
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/vmalloc.h>
......@@ -720,7 +717,7 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
/* Must we save the block contents? */
if (td->options & NAND_BBT_SAVECONTENT) {
/* Make it block aligned */
to &= ~((loff_t)((1 << this->bbt_erase_shift) - 1));
to &= ~(((loff_t)1 << this->bbt_erase_shift) - 1);
len = 1 << this->bbt_erase_shift;
res = mtd_read(mtd, to, len, &retlen, buf);
if (res < 0) {
......@@ -1075,10 +1072,10 @@ static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd)
* The bad block table memory is allocated here. It must be freed by calling
* the nand_free_bbt function.
*/
int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
static int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
{
struct nand_chip *this = mtd->priv;
int len, res = 0;
int len, res;
uint8_t *buf;
struct nand_bbt_descr *td = this->bbt_td;
struct nand_bbt_descr *md = this->bbt_md;
......@@ -1099,10 +1096,9 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
if (!td) {
if ((res = nand_memory_bbt(mtd, bd))) {
pr_err("nand_bbt: can't scan flash and build the RAM-based BBT\n");
kfree(this->bbt);
this->bbt = NULL;
goto err;
}
return res;
return 0;
}
verify_bbt_descr(mtd, td);
verify_bbt_descr(mtd, md);
......@@ -1112,9 +1108,8 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
len += (len >> this->page_shift) * mtd->oobsize;
buf = vmalloc(len);
if (!buf) {
kfree(this->bbt);
this->bbt = NULL;
return -ENOMEM;
res = -ENOMEM;
goto err;
}
/* Is the bbt at a given page? */
......@@ -1126,6 +1121,8 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
}
res = check_create(mtd, buf, bd);
if (res)
goto err;
/* Prevent the bbt regions from erasing / writing */
mark_bbt_region(mtd, td);
......@@ -1133,6 +1130,11 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
mark_bbt_region(mtd, md);
vfree(buf);
return 0;
err:
kfree(this->bbt);
this->bbt = NULL;
return res;
}
......
/*
* drivers/mtd/nandids.c
*
* Copyright (C) 2002 Thomas Gleixner (tglx@linutronix.de)
*
* This program is free software; you can redistribute it and/or modify
......
......@@ -743,6 +743,11 @@ static int init_nandsim(struct mtd_info *mtd)
goto error;
}
ns->partitions[i].name = get_partition_name(i);
if (!ns->partitions[i].name) {
NS_ERR("unable to allocate memory.\n");
ret = -ENOMEM;
goto error;
}
ns->partitions[i].offset = next_offset;
ns->partitions[i].size = part_sz;
next_offset += ns->partitions[i].size;
......@@ -756,6 +761,11 @@ static int init_nandsim(struct mtd_info *mtd)
goto error;
}
ns->partitions[i].name = get_partition_name(i);
if (!ns->partitions[i].name) {
NS_ERR("unable to allocate memory.\n");
ret = -ENOMEM;
goto error;
}
ns->partitions[i].offset = next_offset;
ns->partitions[i].size = remains;
ns->nbparts += 1;
......
/*
* drivers/mtd/ndfc.c
*
* Overview:
* Platform independent driver for NDFC (NanD Flash Controller)
* integrated into EP440 cores
......
......@@ -24,8 +24,6 @@ struct plat_nand_data {
void __iomem *io_base;
};
static const char *part_probe_types[] = { "cmdlinepart", NULL };
/*
* Probe for the NAND device.
*/
......@@ -95,7 +93,7 @@ static int plat_nand_probe(struct platform_device *pdev)
goto out;
}
part_types = pdata->chip.part_probe_types ? : part_probe_types;
part_types = pdata->chip.part_probe_types;
ppdata.of_node = pdev->dev.of_node;
err = mtd_device_parse_register(&data->mtd, part_types, &ppdata,
......
......@@ -22,13 +22,14 @@
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/irq.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_mtd.h>
#if defined(CONFIG_ARCH_PXA) || defined(CONFIG_ARCH_MMP)
#if defined(CONFIG_ARM) && (defined(CONFIG_ARCH_PXA) || defined(CONFIG_ARCH_MMP))
#define ARCH_HAS_DMA
#endif
......@@ -483,7 +484,8 @@ static void disable_int(struct pxa3xx_nand_info *info, uint32_t int_mask)
static void drain_fifo(struct pxa3xx_nand_info *info, void *data, int len)
{
if (info->ecc_bch) {
int timeout;
u32 val;
int ret;
/*
* According to the datasheet, when reading from NDDB
......@@ -494,18 +496,14 @@ static void drain_fifo(struct pxa3xx_nand_info *info, void *data, int len)
* the polling on the last read.
*/
while (len > 8) {
__raw_readsl(info->mmio_base + NDDB, data, 8);
for (timeout = 0;
!(nand_readl(info, NDSR) & NDSR_RDDREQ);
timeout++) {
if (timeout >= 5) {
dev_err(&info->pdev->dev,
"Timeout on RDDREQ while draining the FIFO\n");
return;
}
mdelay(1);
readsl(info->mmio_base + NDDB, data, 8);
ret = readl_relaxed_poll_timeout(info->mmio_base + NDSR, val,
val & NDSR_RDDREQ, 1000, 5000);
if (ret) {
dev_err(&info->pdev->dev,
"Timeout on RDDREQ while draining the FIFO\n");
return;
}
data += 32;
......@@ -513,7 +511,7 @@ static void drain_fifo(struct pxa3xx_nand_info *info, void *data, int len)
}
}
__raw_readsl(info->mmio_base + NDDB, data, len);
readsl(info->mmio_base + NDDB, data, len);
}
static void handle_data_pio(struct pxa3xx_nand_info *info)
......@@ -522,14 +520,14 @@ static void handle_data_pio(struct pxa3xx_nand_info *info)
switch (info->state) {
case STATE_PIO_WRITING:
__raw_writesl(info->mmio_base + NDDB,
info->data_buff + info->data_buff_pos,
DIV_ROUND_UP(do_bytes, 4));
writesl(info->mmio_base + NDDB,
info->data_buff + info->data_buff_pos,
DIV_ROUND_UP(do_bytes, 4));
if (info->oob_size > 0)
__raw_writesl(info->mmio_base + NDDB,
info->oob_buff + info->oob_buff_pos,
DIV_ROUND_UP(info->oob_size, 4));
writesl(info->mmio_base + NDDB,
info->oob_buff + info->oob_buff_pos,
DIV_ROUND_UP(info->oob_size, 4));
break;
case STATE_PIO_READING:
drain_fifo(info,
......@@ -1630,8 +1628,7 @@ static int alloc_nand_resource(struct platform_device *pdev)
info->pdev = pdev;
info->variant = pxa3xx_nand_get_variant(pdev);
for (cs = 0; cs < pdata->num_cs; cs++) {
mtd = (struct mtd_info *)((unsigned int)&info[1] +
(sizeof(*mtd) + sizeof(*host)) * cs);
mtd = (void *)&info[1] + (sizeof(*mtd) + sizeof(*host)) * cs;
chip = (struct nand_chip *)(&mtd[1]);
host = (struct pxa3xx_nand_host *)chip;
info->host[cs] = host;
......
......@@ -653,11 +653,15 @@ static int r852_register_nand_device(struct r852_device *dev)
if (sm_register_device(dev->mtd, dev->sm))
goto error2;
if (device_create_file(&dev->mtd->dev, &dev_attr_media_type))
if (device_create_file(&dev->mtd->dev, &dev_attr_media_type)) {
message("can't create media type sysfs attribute");
goto error3;
}
dev->card_registred = 1;
return 0;
error3:
nand_release(dev->mtd);
error2:
kfree(dev->mtd);
error1:
......
......@@ -1105,7 +1105,7 @@ static int s3c24xx_nand_resume(struct platform_device *dev)
/* driver device registration */
static struct platform_device_id s3c24xx_driver_ids[] = {
static const struct platform_device_id s3c24xx_driver_ids[] = {
{
.name = "s3c2410-nand",
.driver_data = TYPE_S3C2410,
......
......@@ -160,14 +160,10 @@ static int xway_nand_probe(struct platform_device *pdev)
return 0;
}
/* allow users to override the partition in DT using the cmdline */
static const char *part_probes[] = { "cmdlinepart", "ofpart", NULL };
static struct platform_nand_data xway_nand_data = {
.chip = {
.nr_chips = 1,
.chip_delay = 30,
.part_probe_types = part_probes,
},
.ctrl = {
.probe = xway_nand_probe,
......
......@@ -1083,7 +1083,7 @@ static const struct dev_pm_ops s3c_pm_ops = {
.resume = s3c_pm_ops_resume,
};
static struct platform_device_id s3c_onenand_driver_ids[] = {
static const struct platform_device_id s3c_onenand_driver_ids[] = {
{
.name = "s3c6400-onenand",
.driver_data = TYPE_S3C6400,
......
......@@ -662,7 +662,7 @@ static int fsl_qspi_nor_setup_last(struct fsl_qspi *q)
return 0;
}
static struct of_device_id fsl_qspi_dt_ids[] = {
static const struct of_device_id fsl_qspi_dt_ids[] = {
{ .compatible = "fsl,vf610-qspi", .data = (void *)&vybrid_data, },
{ .compatible = "fsl,imx6sx-qspi", .data = (void *)&imx6sx_data, },
{ /* sentinel */ }
......
......@@ -513,6 +513,13 @@ static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
/* NOTE: double check command sets and memory organization when you add
* more nor chips. This current list focusses on newer chips, which
* have been converging on command sets which including JEDEC ID.
*
* All newly added entries should describe *hardware* and should use SECT_4K
* (or SECT_4K_PMC) if hardware supports erasing 4 KiB sectors. For usage
* scenarios excluding small sectors there is config option that can be
* disabled: CONFIG_MTD_SPI_NOR_USE_4K_SECTORS.
* For historical (and compatibility) reasons (before we got above config) some
* old entries may be missing 4K flag.
*/
static const struct spi_device_id spi_nor_ids[] = {
/* Atmel -- some are (confusingly) marketed as "DataFlash" */
......@@ -538,7 +545,7 @@ static const struct spi_device_id spi_nor_ids[] = {
{ "en25q64", INFO(0x1c3017, 0, 64 * 1024, 128, SECT_4K) },
{ "en25qh128", INFO(0x1c7018, 0, 64 * 1024, 256, 0) },
{ "en25qh256", INFO(0x1c7019, 0, 64 * 1024, 512, 0) },
{ "en25s64", INFO(0x1c3817, 0, 64 * 1024, 128, 0) },
{ "en25s64", INFO(0x1c3817, 0, 64 * 1024, 128, SECT_4K) },
/* ESMT */
{ "f25l32pa", INFO(0x8c2016, 0, 64 * 1024, 64, SECT_4K) },
......@@ -560,7 +567,11 @@ static const struct spi_device_id spi_nor_ids[] = {
{ "320s33b", INFO(0x898912, 0, 64 * 1024, 64, 0) },
{ "640s33b", INFO(0x898913, 0, 64 * 1024, 128, 0) },
/* ISSI */
{ "is25cd512", INFO(0x7f9d20, 0, 32 * 1024, 2, SECT_4K) },
/* Macronix */
{ "mx25l512e", INFO(0xc22010, 0, 64 * 1024, 1, SECT_4K) },
{ "mx25l2005a", INFO(0xc22012, 0, 64 * 1024, 4, SECT_4K) },
{ "mx25l4005a", INFO(0xc22013, 0, 64 * 1024, 8, SECT_4K) },
{ "mx25l8005", INFO(0xc22014, 0, 64 * 1024, 16, 0) },
......@@ -602,7 +613,7 @@ static const struct spi_device_id spi_nor_ids[] = {
{ "s70fl01gs", INFO(0x010221, 0x4d00, 256 * 1024, 256, 0) },
{ "s25sl12800", INFO(0x012018, 0x0300, 256 * 1024, 64, 0) },
{ "s25sl12801", INFO(0x012018, 0x0301, 64 * 1024, 256, 0) },
{ "s25fl128s", INFO6(0x012018, 0x4d0180, 64 * 1024, 256, SPI_NOR_QUAD_READ) },
{ "s25fl128s", INFO6(0x012018, 0x4d0180, 64 * 1024, 256, SECT_4K | SPI_NOR_QUAD_READ) },
{ "s25fl129p0", INFO(0x012018, 0x4d00, 256 * 1024, 64, 0) },
{ "s25fl129p1", INFO(0x012018, 0x4d01, 64 * 1024, 256, 0) },
{ "s25sl004a", INFO(0x010212, 0, 64 * 1024, 8, 0) },
......@@ -613,7 +624,8 @@ static const struct spi_device_id spi_nor_ids[] = {
{ "s25fl008k", INFO(0xef4014, 0, 64 * 1024, 16, SECT_4K) },
{ "s25fl016k", INFO(0xef4015, 0, 64 * 1024, 32, SECT_4K) },
{ "s25fl064k", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) },
{ "s25fl132k", INFO(0x014016, 0, 64 * 1024, 64, 0) },
{ "s25fl132k", INFO(0x014016, 0, 64 * 1024, 64, SECT_4K) },
{ "s25fl164k", INFO(0x014017, 0, 64 * 1024, 128, SECT_4K) },
/* SST -- large erase sizes are "overlays", "sectors" are 4K */
{ "sst25vf040b", INFO(0xbf258d, 0, 64 * 1024, 8, SECT_4K | SST_WRITE) },
......
......@@ -272,12 +272,9 @@ struct inode *jffs2_iget(struct super_block *sb, unsigned long ino)
mutex_lock(&f->sem);
ret = jffs2_do_read_inode(c, f, inode->i_ino, &latest_node);
if (ret)
goto error;
if (ret) {
mutex_unlock(&f->sem);
iget_failed(inode);
return ERR_PTR(ret);
}
inode->i_mode = jemode_to_cpu(latest_node.mode);
i_uid_write(inode, je16_to_cpu(latest_node.uid));
i_gid_write(inode, je16_to_cpu(latest_node.gid));
......
......@@ -1203,17 +1203,13 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c,
JFFS2_ERROR("failed to read from flash: error %d, %zd of %zd bytes read\n",
ret, retlen, sizeof(*latest_node));
/* FIXME: If this fails, there seems to be a memory leak. Find it. */
mutex_unlock(&f->sem);
jffs2_do_clear_inode(c, f);
return ret?ret:-EIO;
return ret ? ret : -EIO;
}
crc = crc32(0, latest_node, sizeof(*latest_node)-8);
if (crc != je32_to_cpu(latest_node->node_crc)) {
JFFS2_ERROR("CRC failed for read_inode of inode %u at physical location 0x%x\n",
f->inocache->ino, ref_offset(rii.latest_ref));
mutex_unlock(&f->sem);
jffs2_do_clear_inode(c, f);
return -EIO;
}
......@@ -1250,16 +1246,11 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c,
* keep in RAM to facilitate quick follow symlink
* operation. */
uint32_t csize = je32_to_cpu(latest_node->csize);
if (csize > JFFS2_MAX_NAME_LEN) {
mutex_unlock(&f->sem);
jffs2_do_clear_inode(c, f);
if (csize > JFFS2_MAX_NAME_LEN)
return -ENAMETOOLONG;
}
f->target = kmalloc(csize + 1, GFP_KERNEL);
if (!f->target) {
JFFS2_ERROR("can't allocate %u bytes of memory for the symlink target path cache\n", csize);
mutex_unlock(&f->sem);
jffs2_do_clear_inode(c, f);
return -ENOMEM;
}
......@@ -1271,8 +1262,6 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c,
ret = -EIO;
kfree(f->target);
f->target = NULL;
mutex_unlock(&f->sem);
jffs2_do_clear_inode(c, f);
return ret;
}
......@@ -1289,15 +1278,11 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c,
if (f->metadata) {
JFFS2_ERROR("Argh. Special inode #%u with mode 0%o had metadata node\n",
f->inocache->ino, jemode_to_cpu(latest_node->mode));
mutex_unlock(&f->sem);
jffs2_do_clear_inode(c, f);
return -EIO;
}
if (!frag_first(&f->fragtree)) {
JFFS2_ERROR("Argh. Special inode #%u with mode 0%o has no fragments\n",
f->inocache->ino, jemode_to_cpu(latest_node->mode));
mutex_unlock(&f->sem);
jffs2_do_clear_inode(c, f);
return -EIO;
}
/* ASSERT: f->fraglist != NULL */
......@@ -1305,8 +1290,6 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c,
JFFS2_ERROR("Argh. Special inode #%u with mode 0x%x had more than one node\n",
f->inocache->ino, jemode_to_cpu(latest_node->mode));
/* FIXME: Deal with it - check crc32, check for duplicate node, check times and discard the older one */
mutex_unlock(&f->sem);
jffs2_do_clear_inode(c, f);
return -EIO;
}
/* OK. We're happy */
......@@ -1400,10 +1383,8 @@ int jffs2_do_crccheck_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *i
f->inocache = ic;
ret = jffs2_do_read_inode_internal(c, f, &n);
if (!ret) {
mutex_unlock(&f->sem);
jffs2_do_clear_inode(c, f);
}
mutex_unlock(&f->sem);
jffs2_do_clear_inode(c, f);
jffs2_xattr_do_crccheck_inode(c, ic);
kfree (f);
return ret;
......
......@@ -296,183 +296,19 @@ struct cfi_private {
struct flchip chips[0]; /* per-chip data structure for each chip */
};
/*
* Returns the command address according to the given geometry.
*/
static inline uint32_t cfi_build_cmd_addr(uint32_t cmd_ofs,
struct map_info *map, struct cfi_private *cfi)
{
unsigned bankwidth = map_bankwidth(map);
unsigned interleave = cfi_interleave(cfi);
unsigned type = cfi->device_type;
uint32_t addr;
addr = (cmd_ofs * type) * interleave;
/* Modify the unlock address if we are in compatibility mode.
* For 16bit devices on 8 bit busses
* and 32bit devices on 16 bit busses
* set the low bit of the alternating bit sequence of the address.
*/
if (((type * interleave) > bankwidth) && ((cmd_ofs & 0xff) == 0xaa))
addr |= (type >> 1)*interleave;
return addr;
}
/*
* Transforms the CFI command for the given geometry (bus width & interleave).
* It looks too long to be inline, but in the common case it should almost all
* get optimised away.
*/
static inline map_word cfi_build_cmd(u_long cmd, struct map_info *map, struct cfi_private *cfi)
{
map_word val = { {0} };
int wordwidth, words_per_bus, chip_mode, chips_per_word;
unsigned long onecmd;
int i;
/* We do it this way to give the compiler a fighting chance
of optimising away all the crap for 'bankwidth' larger than
an unsigned long, in the common case where that support is
disabled */
if (map_bankwidth_is_large(map)) {
wordwidth = sizeof(unsigned long);
words_per_bus = (map_bankwidth(map)) / wordwidth; // i.e. normally 1
} else {
wordwidth = map_bankwidth(map);
words_per_bus = 1;
}
chip_mode = map_bankwidth(map) / cfi_interleave(cfi);
chips_per_word = wordwidth * cfi_interleave(cfi) / map_bankwidth(map);
/* First, determine what the bit-pattern should be for a single
device, according to chip mode and endianness... */
switch (chip_mode) {
default: BUG();
case 1:
onecmd = cmd;
break;
case 2:
onecmd = cpu_to_cfi16(map, cmd);
break;
case 4:
onecmd = cpu_to_cfi32(map, cmd);
break;
}
/* Now replicate it across the size of an unsigned long, or
just to the bus width as appropriate */
switch (chips_per_word) {
default: BUG();
#if BITS_PER_LONG >= 64
case 8:
onecmd |= (onecmd << (chip_mode * 32));
#endif
case 4:
onecmd |= (onecmd << (chip_mode * 16));
case 2:
onecmd |= (onecmd << (chip_mode * 8));
case 1:
;
}
uint32_t cfi_build_cmd_addr(uint32_t cmd_ofs,
struct map_info *map, struct cfi_private *cfi);
/* And finally, for the multi-word case, replicate it
in all words in the structure */
for (i=0; i < words_per_bus; i++) {
val.x[i] = onecmd;
}
return val;
}
map_word cfi_build_cmd(u_long cmd, struct map_info *map, struct cfi_private *cfi);
#define CMD(x) cfi_build_cmd((x), map, cfi)
static inline unsigned long cfi_merge_status(map_word val, struct map_info *map,
struct cfi_private *cfi)
{
int wordwidth, words_per_bus, chip_mode, chips_per_word;
unsigned long onestat, res = 0;
int i;
/* We do it this way to give the compiler a fighting chance
of optimising away all the crap for 'bankwidth' larger than
an unsigned long, in the common case where that support is
disabled */
if (map_bankwidth_is_large(map)) {
wordwidth = sizeof(unsigned long);
words_per_bus = (map_bankwidth(map)) / wordwidth; // i.e. normally 1
} else {
wordwidth = map_bankwidth(map);
words_per_bus = 1;
}
chip_mode = map_bankwidth(map) / cfi_interleave(cfi);
chips_per_word = wordwidth * cfi_interleave(cfi) / map_bankwidth(map);
onestat = val.x[0];
/* Or all status words together */
for (i=1; i < words_per_bus; i++) {
onestat |= val.x[i];
}
res = onestat;
switch(chips_per_word) {
default: BUG();
#if BITS_PER_LONG >= 64
case 8:
res |= (onestat >> (chip_mode * 32));
#endif
case 4:
res |= (onestat >> (chip_mode * 16));
case 2:
res |= (onestat >> (chip_mode * 8));
case 1:
;
}
/* Last, determine what the bit-pattern should be for a single
device, according to chip mode and endianness... */
switch (chip_mode) {
case 1:
break;
case 2:
res = cfi16_to_cpu(map, res);
break;
case 4:
res = cfi32_to_cpu(map, res);
break;
default: BUG();
}
return res;
}
unsigned long cfi_merge_status(map_word val, struct map_info *map,
struct cfi_private *cfi);
#define MERGESTATUS(x) cfi_merge_status((x), map, cfi)
/*
* Sends a CFI command to a bank of flash for the given geometry.
*
* Returns the offset in flash where the command was written.
* If prev_val is non-null, it will be set to the value at the command address,
* before the command was written.
*/
static inline uint32_t cfi_send_gen_cmd(u_char cmd, uint32_t cmd_addr, uint32_t base,
uint32_t cfi_send_gen_cmd(u_char cmd, uint32_t cmd_addr, uint32_t base,
struct map_info *map, struct cfi_private *cfi,
int type, map_word *prev_val)
{
map_word val;
uint32_t addr = base + cfi_build_cmd_addr(cmd_addr, map, cfi);
val = cfi_build_cmd(cmd, map, cfi);
if (prev_val)
*prev_val = map_read(map, addr);
map_write(map, val, addr);
return addr - base;
}
int type, map_word *prev_val);
static inline uint8_t cfi_read_query(struct map_info *map, uint32_t addr)
{
......@@ -506,15 +342,7 @@ static inline uint16_t cfi_read_query16(struct map_info *map, uint32_t addr)
}
}
static inline void cfi_udelay(int us)
{
if (us >= 1000) {
msleep((us+999)/1000);
} else {
udelay(us);
cond_resched();
}
}
void cfi_udelay(int us);
int __xipram cfi_qry_present(struct map_info *map, __u32 base,
struct cfi_private *cfi);
......
......@@ -26,6 +26,8 @@
struct mtd_info;
struct nand_flash_dev;
struct device_node;
/* Scan and identify a NAND device */
extern int nand_scan(struct mtd_info *mtd, int max_chips);
/*
......@@ -542,6 +544,7 @@ struct nand_buffers {
* flash device
* @IO_ADDR_W: [BOARDSPECIFIC] address to write the 8 I/O lines of the
* flash device.
* @dn: [BOARDSPECIFIC] device node describing this instance
* @read_byte: [REPLACEABLE] read one byte from the chip
* @read_word: [REPLACEABLE] read one word from the chip
* @write_byte: [REPLACEABLE] write a single byte to the chip on the
......@@ -644,6 +647,8 @@ struct nand_chip {
void __iomem *IO_ADDR_R;
void __iomem *IO_ADDR_W;
struct device_node *dn;
uint8_t (*read_byte)(struct mtd_info *mtd);
u16 (*read_word)(struct mtd_info *mtd);
void (*write_byte)(struct mtd_info *mtd, uint8_t byte);
......@@ -833,7 +838,6 @@ struct nand_manufacturers {
extern struct nand_flash_dev nand_flash_ids[];
extern struct nand_manufacturers nand_manuf_ids[];
extern int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd);
extern int nand_default_bbt(struct mtd_info *mtd);
extern int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs);
extern int nand_isreserved_bbt(struct mtd_info *mtd, loff_t offs);
......
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