dect
/
linux-2.6
Archived
13
0
Fork 0

MTD pull for 3.8

- Various cleanups especially in NAND tests
  - Add support for NAND flash on BCMA bus
  - DT support for sh_flctl and denali NAND drivers
  - Kill obsolete/superceded drivers (fortunet, nomadik_nand)
  - Fix JFFS2 locking bug in ENOMEM failure path
  - New SPI flash chips, as usual
  - Support writing in 'reliable mode' for DiskOnChip G4
  - Debugfs support in nandsim
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.12 (GNU/Linux)
 
 iEYEABECAAYFAlDSAa4ACgkQdwG7hYl686MMcACeNYa//ghPtccb5L+IRXsqaFDL
 Yi4AoLWOaOjN8qM4KUF/bfMEkwNGAePz
 =DaAQ
 -----END PGP SIGNATURE-----

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

Pull MTD updates from David Woodhouse:
 - Various cleanups especially in NAND tests
 - Add support for NAND flash on BCMA bus
 - DT support for sh_flctl and denali NAND drivers
 - Kill obsolete/superceded drivers (fortunet, nomadik_nand)
 - Fix JFFS2 locking bug in ENOMEM failure path
 - New SPI flash chips, as usual
 - Support writing in 'reliable mode' for DiskOnChip G4
 - Debugfs support in nandsim

* tag 'for-linus-20121219' of git://git.infradead.org/linux-mtd: (96 commits)
  mtd: nand: typo in nand_id_has_period() comments
  mtd: nand/gpio: use io{read,write}*_rep accessors
  mtd: block2mtd: throttle writes by calling balance_dirty_pages_ratelimited.
  mtd: nand: gpmi: reset BCH earlier, too, to avoid NAND startup problems
  mtd: nand/docg4: fix and improve read of factory bbt
  mtd: nand/docg4: reserve bb marker area in ecclayout
  mtd: nand/docg4: add support for writing in reliable mode
  mtd: mxc_nand: reorder part_probes to let cmdline override other sources
  mtd: mxc_nand: fix unbalanced clk_disable() in error path
  mtd: nandsim: Introduce debugfs infrastructure
  mtd: physmap_of: error checking to prevent a NULL pointer dereference
  mtg: docg3: potential divide by zero in doc_write_oob()
  mtd: bcm47xxnflash: writing support
  mtd: tests/read: initialize buffer for whole next page
  mtd: at91: atmel_nand: return bit flips for the PMECC read_page()
  mtd: fix recovery after failed write-buffer operation in cfi_cmdset_0002.c
  mtd: nand: onfi need to be probed in 8 bits mode
  mtd: nand: add NAND_BUSWIDTH_AUTO to autodetect bus width
  mtd: nand: print flash size during detection
  mted: nand_wait_ready timeout fix
  ...
This commit is contained in:
Linus Torvalds 2012-12-19 12:47:41 -08:00
commit ca2a88f56a
121 changed files with 2544 additions and 1833 deletions

View File

@ -23,6 +23,9 @@ Recommended properties :
- ti,davinci-nand-buswidth: buswidth 8 or 16
- ti,davinci-nand-use-bbt: use flash based bad block table support.
nand device bindings may contain additional sub-nodes describing
partitions of the address space. See partition.txt for more detail.
Example(da850 EVM ):
nand_cs3@62000000 {
compatible = "ti,davinci-nand";
@ -35,4 +38,9 @@ nand_cs3@62000000 {
ti,davinci-ecc-mode = "hw";
ti,davinci-ecc-bits = <4>;
ti,davinci-nand-use-bbt;
partition@180000 {
label = "ubifs";
reg = <0x180000 0x7e80000>;
};
};

View File

@ -0,0 +1,23 @@
* Denali NAND controller
Required properties:
- compatible : should be "denali,denali-nand-dt"
- reg : should contain registers location and length for data and reg.
- reg-names: Should contain the reg names "nand_data" and "denali_reg"
- interrupts : The interrupt number.
- dm-mask : DMA bit mask
The device tree may optionally contain sub-nodes describing partitions of the
address space. See partition.txt for more detail.
Examples:
nand: nand@ff900000 {
#address-cells = <1>;
#size-cells = <1>;
compatible = "denali,denali-nand-dt";
reg = <0xff900000 0x100000>, <0xffb80000 0x10000>;
reg-names = "nand_data", "denali_reg";
interrupts = <0 144 4>;
dma-mask = <0xffffffff>;
};

View File

@ -0,0 +1,49 @@
FLCTL NAND controller
Required properties:
- compatible : "renesas,shmobile-flctl-sh7372"
- reg : Address range of the FLCTL
- interrupts : flste IRQ number
- nand-bus-width : bus width to NAND chip
Optional properties:
- dmas: DMA specifier(s)
- dma-names: name for each DMA specifier. Valid names are
"data_tx", "data_rx", "ecc_tx", "ecc_rx"
The DMA fields are not used yet in the driver but are listed here for
completing the bindings.
The device tree may optionally contain sub-nodes describing partitions of the
address space. See partition.txt for more detail.
Example:
flctl@e6a30000 {
#address-cells = <1>;
#size-cells = <1>;
compatible = "renesas,shmobile-flctl-sh7372";
reg = <0xe6a30000 0x100>;
interrupts = <0x0d80>;
nand-bus-width = <16>;
dmas = <&dmac 1 /* data_tx */
&dmac 2;> /* data_rx */
dma-names = "data_tx", "data_rx";
system@0 {
label = "system";
reg = <0x0 0x8000000>;
};
userdata@8000000 {
label = "userdata";
reg = <0x8000000 0x10000000>;
};
cache@18000000 {
label = "cache";
reg = <0x18000000 0x8000000>;
};
};

View File

@ -3,9 +3,7 @@
Required properties:
- compatible : "st,spear600-fsmc-nand"
- reg : Address range of the mtd chip
- reg-names: Should contain the reg names "fsmc_regs" and "nand_data"
- st,ale-off : Chip specific offset to ALE
- st,cle-off : Chip specific offset to CLE
- reg-names: Should contain the reg names "fsmc_regs", "nand_data", "nand_addr" and "nand_cmd"
Optional properties:
- bank-width : Width (in bytes) of the device. If not present, the width
@ -19,10 +17,10 @@ Example:
#address-cells = <1>;
#size-cells = <1>;
reg = <0xd1800000 0x1000 /* FSMC Register */
0xd2000000 0x4000>; /* NAND Base */
reg-names = "fsmc_regs", "nand_data";
st,ale-off = <0x20000>;
st,cle-off = <0x10000>;
0xd2000000 0x0010 /* NAND Base DATA */
0xd2020000 0x0010 /* NAND Base ADDR */
0xd2010000 0x0010>; /* NAND Base CMD */
reg-names = "fsmc_regs", "nand_data", "nand_addr", "nand_cmd";
bank-width = <1>;
nand-skip-bbtscan;

View File

@ -0,0 +1,29 @@
* MTD SPI driver for ST M25Pxx (and similar) serial flash chips
Required properties:
- #address-cells, #size-cells : Must be present if the device has sub-nodes
representing partitions.
- compatible : Should be the manufacturer and the name of the chip. Bear in mind
the DT binding is not Linux-only, but in case of Linux, see the
"m25p_ids" table in drivers/mtd/devices/m25p80.c for the list of
supported chips.
- reg : Chip-Select number
- spi-max-frequency : Maximum frequency of the SPI bus the chip can operate at
Optional properties:
- m25p,fast-read : Use the "fast read" opcode to read data from the chip instead
of the usual "read" opcode. This opcode is not supported by
all chips and support for it can not be detected at runtime.
Refer to your chips' datasheet to check if this is supported
by your chip.
Example:
flash: m25p80@0 {
#address-cells = <1>;
#size-cells = <1>;
compatible = "spansion,m25p80";
reg = <0>;
spi-max-frequency = <40000000>;
m25p,fast-read;
};

View File

@ -23,6 +23,9 @@ file systems on embedded devices.
unaligned accesses as implemented in the JFFS2 code via memcpy().
By defining "no-unaligned-direct-access", the flash will not be
exposed directly to the MTD users (e.g. JFFS2) any more.
- linux,mtd-name: allow to specify the mtd name for retro capability with
physmap-flash drivers as boot loader pass the mtd partition via the old
device name physmap-flash.
For JEDEC compatible devices, the following additional properties
are defined:

View File

@ -73,7 +73,7 @@
400000
500000
600000 >;
status = "disable";
status = "disabled";
};
ahb {
@ -118,15 +118,15 @@
compatible = "st,spear600-fsmc-nand";
#address-cells = <1>;
#size-cells = <1>;
reg = <0xb0000000 0x1000 /* FSMC Register */
0xb0800000 0x0010>; /* NAND Base */
reg-names = "fsmc_regs", "nand_data";
reg = <0xb0000000 0x1000 /* FSMC Register*/
0xb0800000 0x0010 /* NAND Base DATA */
0xb0820000 0x0010 /* NAND Base ADDR */
0xb0810000 0x0010>; /* NAND Base CMD */
reg-names = "fsmc_regs", "nand_data", "nand_addr", "nand_cmd";
interrupts = <0 20 0x4
0 21 0x4
0 22 0x4
0 23 0x4>;
st,ale-off = <0x20000>;
st,cle-off = <0x10000>;
st,mode = <2>;
status = "disabled";
};
@ -144,7 +144,7 @@
compatible = "st,pcm-audio";
#address-cells = <0>;
#size-cells = <0>;
status = "disable";
status = "disabled";
};
smi: flash@ea000000 {

View File

@ -38,10 +38,10 @@
#address-cells = <1>;
#size-cells = <1>;
reg = <0x94000000 0x1000 /* FSMC Register */
0x80000000 0x0010>; /* NAND Base */
reg-names = "fsmc_regs", "nand_data";
st,ale-off = <0x20000>;
st,cle-off = <0x10000>;
0x80000000 0x0010 /* NAND Base DATA */
0x80020000 0x0010 /* NAND Base ADDR */
0x80010000 0x0010>; /* NAND Base CMD */
reg-names = "fsmc_regs", "nand_data", "nand_addr", "nand_cmd";
status = "disabled";
};

View File

@ -33,10 +33,10 @@
#address-cells = <1>;
#size-cells = <1>;
reg = <0x44000000 0x1000 /* FSMC Register */
0x40000000 0x0010>; /* NAND Base */
reg-names = "fsmc_regs", "nand_data";
st,ale-off = <0x10000>;
st,cle-off = <0x20000>;
0x40000000 0x0010 /* NAND Base DATA */
0x40020000 0x0010 /* NAND Base ADDR */
0x40010000 0x0010>; /* NAND Base CMD */
reg-names = "fsmc_regs", "nand_data", "nand_addr", "nand_cmd";
status = "disabled";
};

View File

@ -40,10 +40,10 @@
#address-cells = <1>;
#size-cells = <1>;
reg = <0x4c000000 0x1000 /* FSMC Register */
0x50000000 0x0010>; /* NAND Base */
reg-names = "fsmc_regs", "nand_data";
st,ale-off = <0x20000>;
st,cle-off = <0x10000>;
0x50000000 0x0010 /* NAND Base DATA */
0x50020000 0x0010 /* NAND Base ADDR */
0x50010000 0x0010>; /* NAND Base CMD */
reg-names = "fsmc_regs", "nand_data", "nand_addr", "nand_cmd";
status = "disabled";
};

View File

@ -76,10 +76,10 @@
#address-cells = <1>;
#size-cells = <1>;
reg = <0xd1800000 0x1000 /* FSMC Register */
0xd2000000 0x4000>; /* NAND Base */
reg-names = "fsmc_regs", "nand_data";
st,ale-off = <0x20000>;
st,cle-off = <0x10000>;
0xd2000000 0x0010 /* NAND Base DATA */
0xd2020000 0x0010 /* NAND Base ADDR */
0xd2010000 0x0010>; /* NAND Base CMD */
reg-names = "fsmc_regs", "nand_data", "nand_addr", "nand_cmd";
status = "disabled";
};

View File

@ -57,7 +57,7 @@ CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
CONFIG_MTD_NAND=y
CONFIG_MTD_NAND_ECC_SMC=y
CONFIG_MTD_NAND_NOMADIK=y
CONFIG_MTD_NAND_FSMC=y
CONFIG_MTD_ONENAND=y
CONFIG_MTD_ONENAND_VERIFY_WRITE=y
CONFIG_MTD_ONENAND_GENERIC=y

View File

@ -19,6 +19,7 @@
#include <linux/gpio.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/fsmc.h>
#include <linux/mtd/onenand.h>
#include <linux/mtd/partitions.h>
#include <linux/i2c.h>
@ -33,7 +34,6 @@
#include <asm/mach/arch.h>
#include <asm/mach/flash.h>
#include <asm/mach/time.h>
#include <mach/fsmc.h>
#include <mach/irqs.h>
#include "cpu-8815.h"
@ -42,39 +42,34 @@
#define SRC_CR_INIT_MASK 0x00007fff
#define SRC_CR_INIT_VAL 0x2aaa8000
#define ALE_OFF 0x1000000
#define CLE_OFF 0x800000
/* These addresses span 16MB, so use three individual pages */
static struct resource nhk8815_nand_resources[] = {
{
.name = "nand_data",
.start = 0x40000000,
.end = 0x40000000 + SZ_16K - 1,
.flags = IORESOURCE_MEM,
}, {
.name = "nand_addr",
.start = NAND_IO_ADDR,
.end = NAND_IO_ADDR + 0xfff,
.start = 0x40000000 + ALE_OFF,
.end = 0x40000000 +ALE_OFF + SZ_16K - 1,
.flags = IORESOURCE_MEM,
}, {
.name = "nand_cmd",
.start = NAND_IO_CMD,
.end = NAND_IO_CMD + 0xfff,
.start = 0x40000000 + CLE_OFF,
.end = 0x40000000 + CLE_OFF + SZ_16K - 1,
.flags = IORESOURCE_MEM,
}, {
.name = "nand_data",
.start = NAND_IO_DATA,
.end = NAND_IO_DATA + 0xfff,
.name = "fsmc_regs",
.start = NOMADIK_FSMC_BASE,
.end = NOMADIK_FSMC_BASE + SZ_4K - 1,
.flags = IORESOURCE_MEM,
}
},
};
static int nhk8815_nand_init(void)
{
/* FSMC setup for nand chip select (8-bit nand in 8815NHK) */
writel(0x0000000E, FSMC_PCR(0));
writel(0x000D0A00, FSMC_PMEM(0));
writel(0x00100A00, FSMC_PATT(0));
/* enable access to the chip select area */
writel(readl(FSMC_PCR(0)) | 0x04, FSMC_PCR(0));
return 0;
}
/*
* These partitions are the same as those used in the 2.6.20 release
* shipped by the vendor; the first two partitions are mandated
@ -108,20 +103,28 @@ static struct mtd_partition nhk8815_partitions[] = {
}
};
static struct nomadik_nand_platform_data nhk8815_nand_data = {
.parts = nhk8815_partitions,
.nparts = ARRAY_SIZE(nhk8815_partitions),
.options = NAND_COPYBACK | NAND_CACHEPRG | NAND_NO_PADDING,
.init = nhk8815_nand_init,
static struct fsmc_nand_timings nhk8815_nand_timings = {
.thiz = 0,
.thold = 0x10,
.twait = 0x0A,
.tset = 0,
};
static struct fsmc_nand_platform_data nhk8815_nand_platform_data = {
.nand_timings = &nhk8815_nand_timings,
.partitions = nhk8815_partitions,
.nr_partitions = ARRAY_SIZE(nhk8815_partitions),
.width = FSMC_NAND_BW8,
};
static struct platform_device nhk8815_nand_device = {
.name = "nomadik_nand",
.dev = {
.platform_data = &nhk8815_nand_data,
.name = "fsmc-nand",
.id = -1,
.resource = nhk8815_nand_resources,
.num_resources = ARRAY_SIZE(nhk8815_nand_resources),
.dev = {
.platform_data = &nhk8815_nand_platform_data,
},
.resource = nhk8815_nand_resources,
.num_resources = ARRAY_SIZE(nhk8815_nand_resources),
};
/* These are the partitions for the OneNand device, different from above */
@ -176,6 +179,10 @@ static struct platform_device nhk8815_onenand_device = {
.num_resources = ARRAY_SIZE(nhk8815_onenand_resource),
};
/* bus control reg. and bus timing reg. for CS0..CS3 */
#define FSMC_BCR(x) (NOMADIK_FSMC_VA + (x << 3))
#define FSMC_BTR(x) (NOMADIK_FSMC_VA + (x << 3) + 0x04)
static void __init nhk8815_onenand_init(void)
{
#ifdef CONFIG_MTD_ONENAND

View File

@ -1,29 +0,0 @@
/* Definitions for the Nomadik FSMC "Flexible Static Memory controller" */
#ifndef __ASM_ARCH_FSMC_H
#define __ASM_ARCH_FSMC_H
#include <mach/hardware.h>
/*
* Register list
*/
/* bus control reg. and bus timing reg. for CS0..CS3 */
#define FSMC_BCR(x) (NOMADIK_FSMC_VA + (x << 3))
#define FSMC_BTR(x) (NOMADIK_FSMC_VA + (x << 3) + 0x04)
/* PC-card and NAND:
* PCR = control register
* PMEM = memory timing
* PATT = attribute timing
* PIO = I/O timing
* PECCR = ECC result
*/
#define FSMC_PCR(x) (NOMADIK_FSMC_VA + ((2 + x) << 5) + 0x00)
#define FSMC_PMEM(x) (NOMADIK_FSMC_VA + ((2 + x) << 5) + 0x08)
#define FSMC_PATT(x) (NOMADIK_FSMC_VA + ((2 + x) << 5) + 0x0c)
#define FSMC_PIO(x) (NOMADIK_FSMC_VA + ((2 + x) << 5) + 0x10)
#define FSMC_PECCR(x) (NOMADIK_FSMC_VA + ((2 + x) << 5) + 0x14)
#endif /* __ASM_ARCH_FSMC_H */

View File

@ -249,6 +249,18 @@ static struct resource rtc_resources[] = {
* but these are not yet used by the driver.
*/
static struct resource fsmc_resources[] = {
{
.name = "nand_addr",
.start = U300_NAND_CS0_PHYS_BASE + PLAT_NAND_ALE,
.end = U300_NAND_CS0_PHYS_BASE + PLAT_NAND_ALE + SZ_16K - 1,
.flags = IORESOURCE_MEM,
},
{
.name = "nand_cmd",
.start = U300_NAND_CS0_PHYS_BASE + PLAT_NAND_CLE,
.end = U300_NAND_CS0_PHYS_BASE + PLAT_NAND_CLE + SZ_16K - 1,
.flags = IORESOURCE_MEM,
},
{
.name = "nand_data",
.start = U300_NAND_CS0_PHYS_BASE,
@ -1492,8 +1504,6 @@ static struct fsmc_nand_platform_data nand_platform_data = {
.nr_partitions = ARRAY_SIZE(u300_partitions),
.options = NAND_SKIP_BBTSCAN,
.width = FSMC_NAND_BW8,
.ale_off = PLAT_NAND_ALE,
.cle_off = PLAT_NAND_CLE,
};
static struct platform_device nand_device = {

View File

@ -13,12 +13,13 @@
#include <linux/export.h>
#include <linux/bcma/bcma.h>
static u32 bcma_chipco_pll_read(struct bcma_drv_cc *cc, u32 offset)
u32 bcma_chipco_pll_read(struct bcma_drv_cc *cc, u32 offset)
{
bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
return bcma_cc_read32(cc, BCMA_CC_PLLCTL_DATA);
}
EXPORT_SYMBOL_GPL(bcma_chipco_pll_read);
void bcma_chipco_pll_write(struct bcma_drv_cc *cc, u32 offset, u32 value)
{

View File

@ -20,6 +20,7 @@ void __init nomadik_clk_init(void)
clk_register_clkdev(clk, NULL, "gpio.2");
clk_register_clkdev(clk, NULL, "gpio.3");
clk_register_clkdev(clk, NULL, "rng");
clk_register_clkdev(clk, NULL, "fsmc-nand");
/*
* The 2.4 MHz TIMCLK reference clock is active at boot time, this is

View File

@ -26,19 +26,16 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/bootmem.h>
#include <linux/magic.h>
#include <linux/module.h>
#include <uapi/linux/magic.h>
#define AR7_PARTS 4
#define ROOT_OFFSET 0xe0000
#define LOADER_MAGIC1 le32_to_cpu(0xfeedfa42)
#define LOADER_MAGIC2 le32_to_cpu(0xfeed1281)
#ifndef SQUASHFS_MAGIC
#define SQUASHFS_MAGIC 0x73717368
#endif
struct ar7_bin_rec {
unsigned int checksum;
unsigned int length;

View File

@ -37,8 +37,7 @@
#define BCM63XX_EXTENDED_SIZE 0xBFC00000 /* Extended flash address */
#define BCM63XX_MIN_CFE_SIZE 0x10000 /* always at least 64KiB */
#define BCM63XX_MIN_NVRAM_SIZE 0x10000 /* always at least 64KiB */
#define BCM63XX_CFE_BLOCK_SIZE 0x10000 /* always at least 64KiB */
#define BCM63XX_CFE_MAGIC_OFFSET 0x4e0
@ -79,7 +78,7 @@ static int bcm63xx_parse_cfe_partitions(struct mtd_info *master,
unsigned int rootfsaddr, kerneladdr, spareaddr;
unsigned int rootfslen, kernellen, sparelen, totallen;
unsigned int cfelen, nvramlen;
int namelen = 0;
unsigned int cfe_erasesize;
int i;
u32 computed_crc;
bool rootfs_first = false;
@ -87,8 +86,11 @@ static int bcm63xx_parse_cfe_partitions(struct mtd_info *master,
if (bcm63xx_detect_cfe(master))
return -EINVAL;
cfelen = max_t(uint32_t, master->erasesize, BCM63XX_MIN_CFE_SIZE);
nvramlen = max_t(uint32_t, master->erasesize, BCM63XX_MIN_NVRAM_SIZE);
cfe_erasesize = max_t(uint32_t, master->erasesize,
BCM63XX_CFE_BLOCK_SIZE);
cfelen = cfe_erasesize;
nvramlen = cfe_erasesize;
/* Allocate memory for buffer */
buf = vmalloc(sizeof(struct bcm_tag));
@ -121,7 +123,6 @@ static int bcm63xx_parse_cfe_partitions(struct mtd_info *master,
kerneladdr = kerneladdr - BCM63XX_EXTENDED_SIZE;
rootfsaddr = rootfsaddr - BCM63XX_EXTENDED_SIZE;
spareaddr = roundup(totallen, master->erasesize) + cfelen;
sparelen = master->size - spareaddr - nvramlen;
if (rootfsaddr < kerneladdr) {
/* default Broadcom layout */
@ -139,19 +140,15 @@ static int bcm63xx_parse_cfe_partitions(struct mtd_info *master,
rootfslen = 0;
rootfsaddr = 0;
spareaddr = cfelen;
sparelen = master->size - cfelen - nvramlen;
}
sparelen = master->size - spareaddr - nvramlen;
/* Determine number of partitions */
namelen = 8;
if (rootfslen > 0) {
if (rootfslen > 0)
nrparts++;
namelen += 6;
}
if (kernellen > 0) {
if (kernellen > 0)
nrparts++;
namelen += 6;
}
/* Ask kernel for more memory */
parts = kzalloc(sizeof(*parts) * nrparts + 10 * nrparts, GFP_KERNEL);
@ -193,17 +190,16 @@ static int bcm63xx_parse_cfe_partitions(struct mtd_info *master,
parts[curpart].name = "nvram";
parts[curpart].offset = master->size - nvramlen;
parts[curpart].size = nvramlen;
curpart++;
/* Global partition "linux" to make easy firmware upgrade */
curpart++;
parts[curpart].name = "linux";
parts[curpart].offset = cfelen;
parts[curpart].size = master->size - cfelen - nvramlen;
for (i = 0; i < nrparts; i++)
pr_info("Partition %d is %s offset %lx and length %lx\n", i,
parts[i].name, (long unsigned int)(parts[i].offset),
(long unsigned int)(parts[i].size));
pr_info("Partition %d is %s offset %llx and length %llx\n", i,
parts[i].name, parts[i].offset, parts[i].size);
pr_info("Spare partition is offset %x and length %x\n", spareaddr,
sparelen);

View File

@ -1536,8 +1536,20 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
UDELAY(map, chip, adr, 1);
}
/* reset on all failures. */
map_write( map, CMD(0xF0), chip->start );
/*
* Recovery from write-buffer programming failures requires
* the write-to-buffer-reset sequence. Since the last part
* of the sequence also works as a normal reset, we can run
* the same commands regardless of why we are here.
* See e.g.
* http://www.spansion.com/Support/Application%20Notes/MirrorBit_Write_Buffer_Prog_Page_Buffer_Read_AN.pdf
*/
cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi,
cfi->device_type, NULL);
cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi,
cfi->device_type, NULL);
cfi_send_gen_cmd(0xF0, cfi->addr_unlock1, chip->start, map, cfi,
cfi->device_type, NULL);
xip_enable(map, chip, adr);
/* FIXME - should have reset delay before continuing */

View File

@ -56,8 +56,8 @@
/* special size referring to all the remaining space in a partition */
#define SIZE_REMAINING UINT_MAX
#define OFFSET_CONTINUOUS UINT_MAX
#define SIZE_REMAINING ULLONG_MAX
#define OFFSET_CONTINUOUS ULLONG_MAX
struct cmdline_mtd_partition {
struct cmdline_mtd_partition *next;
@ -89,7 +89,7 @@ static struct mtd_partition * newpart(char *s,
int extra_mem_size)
{
struct mtd_partition *parts;
unsigned long size, offset = OFFSET_CONTINUOUS;
unsigned long long size, offset = OFFSET_CONTINUOUS;
char *name;
int name_len;
unsigned char *extra_mem;
@ -104,7 +104,8 @@ static struct mtd_partition * newpart(char *s,
} else {
size = memparse(s, &s);
if (size < PAGE_SIZE) {
printk(KERN_ERR ERRP "partition size too small (%lx)\n", size);
printk(KERN_ERR ERRP "partition size too small (%llx)\n",
size);
return ERR_PTR(-EINVAL);
}
}
@ -296,7 +297,7 @@ static int parse_cmdline_partitions(struct mtd_info *master,
struct mtd_partition **pparts,
struct mtd_part_parser_data *data)
{
unsigned long offset;
unsigned long long offset;
int i, err;
struct cmdline_mtd_partition *part;
const char *mtd_id = master->name;
@ -308,48 +309,52 @@ static int parse_cmdline_partitions(struct mtd_info *master,
return err;
}
/*
* Search for the partition definition matching master->name.
* If master->name is not set, stop at first partition definition.
*/
for (part = partitions; part; part = part->next) {
if ((!mtd_id) || (!strcmp(part->mtd_id, mtd_id))) {
for (i = 0, offset = 0; i < part->num_parts; i++) {
if (part->parts[i].offset == OFFSET_CONTINUOUS)
part->parts[i].offset = offset;
else
offset = part->parts[i].offset;
if (part->parts[i].size == SIZE_REMAINING)
part->parts[i].size = master->size - offset;
if (part->parts[i].size == 0) {
printk(KERN_WARNING ERRP
"%s: skipping zero sized partition\n",
part->mtd_id);
part->num_parts--;
memmove(&part->parts[i],
&part->parts[i + 1],
sizeof(*part->parts) * (part->num_parts - i));
continue;
}
if (offset + part->parts[i].size > master->size) {
printk(KERN_WARNING ERRP
"%s: partitioning exceeds flash size, truncating\n",
part->mtd_id);
part->parts[i].size = master->size - offset;
}
offset += part->parts[i].size;
}
*pparts = kmemdup(part->parts,
sizeof(*part->parts) * part->num_parts,
GFP_KERNEL);
if (!*pparts)
return -ENOMEM;
return part->num_parts;
}
if ((!mtd_id) || (!strcmp(part->mtd_id, mtd_id)))
break;
}
return 0;
if (!part)
return 0;
for (i = 0, offset = 0; i < part->num_parts; i++) {
if (part->parts[i].offset == OFFSET_CONTINUOUS)
part->parts[i].offset = offset;
else
offset = part->parts[i].offset;
if (part->parts[i].size == SIZE_REMAINING)
part->parts[i].size = master->size - offset;
if (part->parts[i].size == 0) {
printk(KERN_WARNING ERRP
"%s: skipping zero sized partition\n",
part->mtd_id);
part->num_parts--;
memmove(&part->parts[i], &part->parts[i + 1],
sizeof(*part->parts) * (part->num_parts - i));
continue;
}
if (offset + part->parts[i].size > master->size) {
printk(KERN_WARNING ERRP
"%s: partitioning exceeds flash size, truncating\n",
part->mtd_id);
part->parts[i].size = master->size - offset;
}
offset += part->parts[i].size;
}
*pparts = kmemdup(part->parts, sizeof(*part->parts) * part->num_parts,
GFP_KERNEL);
if (!*pparts)
return -ENOMEM;
return part->num_parts;
}

View File

@ -66,7 +66,7 @@ out:
return err;
}
static int __devexit bcm47xxsflash_remove(struct platform_device *pdev)
static int bcm47xxsflash_remove(struct platform_device *pdev)
{
struct bcma_sflash *sflash = dev_get_platdata(&pdev->dev);
@ -77,7 +77,7 @@ static int __devexit bcm47xxsflash_remove(struct platform_device *pdev)
}
static struct platform_driver bcma_sflash_driver = {
.remove = __devexit_p(bcm47xxsflash_remove),
.remove = bcm47xxsflash_remove,
.driver = {
.name = "bcma_sflash",
.owner = THIS_MODULE,

View File

@ -62,6 +62,7 @@ static int _block2mtd_erase(struct block2mtd_dev *dev, loff_t to, size_t len)
memset(page_address(page), 0xff, PAGE_SIZE);
set_page_dirty(page);
unlock_page(page);
balance_dirty_pages_ratelimited(mapping);
break;
}
@ -152,6 +153,7 @@ static int _block2mtd_write(struct block2mtd_dev *dev, const u_char *buf,
memcpy(page_address(page) + offset, buf, cpylen);
set_page_dirty(page);
unlock_page(page);
balance_dirty_pages_ratelimited(mapping);
}
page_cache_release(page);
@ -433,7 +435,7 @@ static int __init block2mtd_init(void)
}
static void __devexit block2mtd_exit(void)
static void block2mtd_exit(void)
{
struct list_head *pos, *next;

View File

@ -1440,7 +1440,7 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs,
oobdelta = mtd->ecclayout->oobavail;
break;
default:
oobdelta = 0;
return -EINVAL;
}
if ((len % DOC_LAYOUT_PAGE_SIZE) || (ooblen % oobdelta) ||
(ofs % DOC_LAYOUT_PAGE_SIZE))

View File

@ -70,8 +70,6 @@ static unsigned long __initdata doc_locations[] = {
0xe0000, 0xe2000, 0xe4000, 0xe6000,
0xe8000, 0xea000, 0xec000, 0xee000,
#endif /* CONFIG_MTD_DOCPROBE_HIGH */
#else
#warning Unknown architecture for DiskOnChip. No default probe locations defined
#endif
0xffffffff };

View File

@ -73,14 +73,6 @@
#define MAX_READY_WAIT_JIFFIES (40 * HZ) /* M25P16 specs 40s max chip erase */
#define MAX_CMD_SIZE 5
#ifdef CONFIG_M25PXX_USE_FAST_READ
#define OPCODE_READ OPCODE_FAST_READ
#define FAST_READ_DUMMY_BYTE 1
#else
#define OPCODE_READ OPCODE_NORM_READ
#define FAST_READ_DUMMY_BYTE 0
#endif
#define JEDEC_MFR(_jedec_id) ((_jedec_id) >> 16)
/****************************************************************************/
@ -93,6 +85,7 @@ struct m25p {
u16 addr_width;
u8 erase_opcode;
u8 *command;
bool fast_read;
};
static inline struct m25p *mtd_to_m25p(struct mtd_info *mtd)
@ -168,6 +161,7 @@ static inline int set_4byte(struct m25p *flash, u32 jedec_id, int enable)
{
switch (JEDEC_MFR(jedec_id)) {
case CFI_MFR_MACRONIX:
case 0xEF /* winbond */:
flash->command[0] = enable ? OPCODE_EN4B : OPCODE_EX4B;
return spi_write(flash->spi, flash->command, 1);
default:
@ -342,6 +336,7 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len,
struct m25p *flash = mtd_to_m25p(mtd);
struct spi_transfer t[2];
struct spi_message m;
uint8_t opcode;
pr_debug("%s: %s from 0x%08x, len %zd\n", dev_name(&flash->spi->dev),
__func__, (u32)from, len);
@ -354,7 +349,7 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len,
* Should add 1 byte DUMMY_BYTE.
*/
t[0].tx_buf = flash->command;
t[0].len = m25p_cmdsz(flash) + FAST_READ_DUMMY_BYTE;
t[0].len = m25p_cmdsz(flash) + (flash->fast_read ? 1 : 0);
spi_message_add_tail(&t[0], &m);
t[1].rx_buf = buf;
@ -376,12 +371,14 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len,
*/
/* Set up the write data buffer. */
flash->command[0] = OPCODE_READ;
opcode = flash->fast_read ? OPCODE_FAST_READ : OPCODE_NORM_READ;
flash->command[0] = opcode;
m25p_addr2cmd(flash, from, flash->command);
spi_sync(flash->spi, &m);
*retlen = m.actual_length - m25p_cmdsz(flash) - FAST_READ_DUMMY_BYTE;
*retlen = m.actual_length - m25p_cmdsz(flash) -
(flash->fast_read ? 1 : 0);
mutex_unlock(&flash->lock);
@ -664,7 +661,8 @@ static const struct spi_device_id m25p_ids[] = {
{ "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) },
/* Micron */
{ "n25q128", INFO(0x20ba18, 0, 64 * 1024, 256, 0) },
{ "n25q128a11", INFO(0x20bb18, 0, 64 * 1024, 256, 0) },
{ "n25q128a13", INFO(0x20ba18, 0, 64 * 1024, 256, 0) },
{ "n25q256a", INFO(0x20ba19, 0, 64 * 1024, 512, SECT_4K) },
/* Spansion -- single (large) sector size only, at least
@ -745,6 +743,8 @@ static const struct spi_device_id m25p_ids[] = {
{ "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) },
{ "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) },
{ "w25q80", INFO(0xef5014, 0, 64 * 1024, 16, SECT_4K) },
{ "w25q80bl", INFO(0xef4014, 0, 64 * 1024, 16, SECT_4K) },
{ "w25q256", INFO(0xef4019, 0, 64 * 1024, 512, SECT_4K) },
/* Catalyst / On Semiconductor -- non-JEDEC */
{ "cat25c11", CAT25_INFO( 16, 8, 16, 1) },
@ -756,7 +756,7 @@ static const struct spi_device_id m25p_ids[] = {
};
MODULE_DEVICE_TABLE(spi, m25p_ids);
static const struct spi_device_id *__devinit jedec_probe(struct spi_device *spi)
static const struct spi_device_id *jedec_probe(struct spi_device *spi)
{
int tmp;
u8 code = OPCODE_RDID;
@ -801,7 +801,7 @@ static const struct spi_device_id *__devinit jedec_probe(struct spi_device *spi)
* matches what the READ command supports, at least until this driver
* understands FAST_READ (for clocks over 25 MHz).
*/
static int __devinit m25p_probe(struct spi_device *spi)
static int m25p_probe(struct spi_device *spi)
{
const struct spi_device_id *id = spi_get_device_id(spi);
struct flash_platform_data *data;
@ -809,9 +809,10 @@ static int __devinit m25p_probe(struct spi_device *spi)
struct flash_info *info;
unsigned i;
struct mtd_part_parser_data ppdata;
struct device_node __maybe_unused *np = spi->dev.of_node;
#ifdef CONFIG_MTD_OF_PARTS
if (!of_device_is_available(spi->dev.of_node))
if (!of_device_is_available(np))
return -ENODEV;
#endif
@ -863,7 +864,8 @@ static int __devinit m25p_probe(struct spi_device *spi)
flash = kzalloc(sizeof *flash, GFP_KERNEL);
if (!flash)
return -ENOMEM;
flash->command = kmalloc(MAX_CMD_SIZE + FAST_READ_DUMMY_BYTE, GFP_KERNEL);
flash->command = kmalloc(MAX_CMD_SIZE + (flash->fast_read ? 1 : 0),
GFP_KERNEL);
if (!flash->command) {
kfree(flash);
return -ENOMEM;
@ -920,6 +922,16 @@ static int __devinit m25p_probe(struct spi_device *spi)
flash->page_size = info->page_size;
flash->mtd.writebufsize = flash->page_size;
flash->fast_read = false;
#ifdef CONFIG_OF
if (np && of_property_read_bool(np, "m25p,fast-read"))
flash->fast_read = true;
#endif
#ifdef CONFIG_M25PXX_USE_FAST_READ
flash->fast_read = true;
#endif
if (info->addr_width)
flash->addr_width = info->addr_width;
else {
@ -961,7 +973,7 @@ static int __devinit m25p_probe(struct spi_device *spi)
}
static int __devexit m25p_remove(struct spi_device *spi)
static int m25p_remove(struct spi_device *spi)
{
struct m25p *flash = dev_get_drvdata(&spi->dev);
int status;
@ -983,7 +995,7 @@ static struct spi_driver m25p80_driver = {
},
.id_table = m25p_ids,
.probe = m25p_probe,
.remove = __devexit_p(m25p_remove),
.remove = m25p_remove,
/* REVISIT: many of these chips have deep power-down modes, which
* should clearly be entered on suspend() to minimize power use.

View File

@ -618,7 +618,7 @@ static char *otp_setup(struct mtd_info *device, char revision)
/*
* Register DataFlash device with MTD subsystem.
*/
static int __devinit
static int
add_dataflash_otp(struct spi_device *spi, char *name,
int nr_pages, int pagesize, int pageoffset, char revision)
{
@ -679,7 +679,7 @@ add_dataflash_otp(struct spi_device *spi, char *name,
return err;
}
static inline int __devinit
static inline int
add_dataflash(struct spi_device *spi, char *name,
int nr_pages, int pagesize, int pageoffset)
{
@ -705,7 +705,7 @@ struct flash_info {
#define IS_POW2PS 0x0001 /* uses 2^N byte pages */
};
static struct flash_info __devinitdata dataflash_data [] = {
static struct flash_info dataflash_data[] = {
/*
* NOTE: chips with SUP_POW2PS (rev D and up) need two entries,
@ -740,7 +740,7 @@ static struct flash_info __devinitdata dataflash_data [] = {
{ "at45db642d", 0x1f2800, 8192, 1024, 10, SUP_POW2PS | IS_POW2PS},
};
static struct flash_info *__devinit jedec_probe(struct spi_device *spi)
static struct flash_info *jedec_probe(struct spi_device *spi)
{
int tmp;
uint8_t code = OP_READ_ID;
@ -823,7 +823,7 @@ static struct flash_info *__devinit jedec_probe(struct spi_device *spi)
* AT45DB0642 64Mbit (8M) xx111xxx (0x3c) 8192 1056 11
* AT45DB1282 128Mbit (16M) xx0100xx (0x10) 16384 1056 11
*/
static int __devinit dataflash_probe(struct spi_device *spi)
static int dataflash_probe(struct spi_device *spi)
{
int status;
struct flash_info *info;
@ -897,7 +897,7 @@ static int __devinit dataflash_probe(struct spi_device *spi)
return status;
}
static int __devexit dataflash_remove(struct spi_device *spi)
static int dataflash_remove(struct spi_device *spi)
{
struct dataflash *flash = dev_get_drvdata(&spi->dev);
int status;
@ -920,7 +920,7 @@ static struct spi_driver dataflash_driver = {
},
.probe = dataflash_probe,
.remove = __devexit_p(dataflash_remove),
.remove = dataflash_remove,
/* FIXME: investigate suspend and resume... */
};

View File

@ -756,7 +756,7 @@ err_probe:
#ifdef CONFIG_OF
static int __devinit spear_smi_probe_config_dt(struct platform_device *pdev,
static int spear_smi_probe_config_dt(struct platform_device *pdev,
struct device_node *np)
{
struct spear_smi_plat_data *pdata = dev_get_platdata(&pdev->dev);
@ -799,7 +799,7 @@ static int __devinit spear_smi_probe_config_dt(struct platform_device *pdev,
return 0;
}
#else
static int __devinit spear_smi_probe_config_dt(struct platform_device *pdev,
static int spear_smi_probe_config_dt(struct platform_device *pdev,
struct device_node *np)
{
return -ENOSYS;
@ -901,7 +901,7 @@ static int spear_smi_setup_banks(struct platform_device *pdev,
* and do proper init for any found one.
* Returns 0 on success, non zero otherwise
*/
static int __devinit spear_smi_probe(struct platform_device *pdev)
static int spear_smi_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct spear_smi_plat_data *pdata = NULL;
@ -1016,7 +1016,7 @@ err:
*
* free all allocations and delete the partitions.
*/
static int __devexit spear_smi_remove(struct platform_device *pdev)
static int spear_smi_remove(struct platform_device *pdev)
{
struct spear_smi *dev;
struct spear_snor_flash *flash;
@ -1092,20 +1092,9 @@ static struct platform_driver spear_smi_driver = {
#endif
},
.probe = spear_smi_probe,
.remove = __devexit_p(spear_smi_remove),
.remove = spear_smi_remove,
};
static int spear_smi_init(void)
{
return platform_driver_register(&spear_smi_driver);
}
module_init(spear_smi_init);
static void spear_smi_exit(void)
{
platform_driver_unregister(&spear_smi_driver);
}
module_exit(spear_smi_exit);
module_platform_driver(spear_smi_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Ashish Priyadarshi, Shiraz Hashim <shiraz.hashim@st.com>");

View File

@ -64,7 +64,7 @@ struct flash_info {
#define to_sst25l_flash(x) container_of(x, struct sst25l_flash, mtd)
static struct flash_info __devinitdata sst25l_flash_info[] = {
static struct flash_info sst25l_flash_info[] = {
{"sst25lf020a", 0xbf43, 256, 1024, 4096},
{"sst25lf040a", 0xbf44, 256, 2048, 4096},
};
@ -313,7 +313,7 @@ out:
return ret;
}
static struct flash_info *__devinit sst25l_match_device(struct spi_device *spi)
static struct flash_info *sst25l_match_device(struct spi_device *spi)
{
struct flash_info *flash_info = NULL;
struct spi_message m;
@ -353,7 +353,7 @@ static struct flash_info *__devinit sst25l_match_device(struct spi_device *spi)
return flash_info;
}
static int __devinit sst25l_probe(struct spi_device *spi)
static int sst25l_probe(struct spi_device *spi)
{
struct flash_info *flash_info;
struct sst25l_flash *flash;
@ -411,7 +411,7 @@ static int __devinit sst25l_probe(struct spi_device *spi)
return 0;
}
static int __devexit sst25l_remove(struct spi_device *spi)
static int sst25l_remove(struct spi_device *spi)
{
struct sst25l_flash *flash = dev_get_drvdata(&spi->dev);
int ret;
@ -428,7 +428,7 @@ static struct spi_driver sst25l_driver = {
.owner = THIS_MODULE,
},
.probe = sst25l_probe,
.remove = __devexit_p(sst25l_remove),
.remove = sst25l_remove,
};
module_spi_driver(sst25l_driver);

View File

@ -358,13 +358,6 @@ config MTD_IXP2000
IXP2000 based board and would like to use the flash chips on it,
say 'Y'.
config MTD_FORTUNET
tristate "CFI Flash device mapped on the FortuNet board"
depends on MTD_CFI && SA1100_FORTUNET
help
This enables access to the Flash on the FortuNet board. If you
have such a board, say 'Y'.
config MTD_AUTCPU12
bool "NV-RAM mapping AUTCPU12 board"
depends on ARCH_AUTCPU12

View File

@ -39,7 +39,6 @@ obj-$(CONFIG_MTD_SOLUTIONENGINE)+= solutionengine.o
obj-$(CONFIG_MTD_PCI) += pci.o
obj-$(CONFIG_MTD_AUTCPU12) += autcpu12-nvram.o
obj-$(CONFIG_MTD_IMPA7) += impa7.o
obj-$(CONFIG_MTD_FORTUNET) += fortunet.o
obj-$(CONFIG_MTD_UCLINUX) += uclinux.o
obj-$(CONFIG_MTD_NETtel) += nettel.o
obj-$(CONFIG_MTD_SCB2_FLASH) += scb2_flash.o

View File

@ -100,8 +100,8 @@ static void amd76xrom_cleanup(struct amd76xrom_window *window)
}
static int __devinit amd76xrom_init_one (struct pci_dev *pdev,
const struct pci_device_id *ent)
static int amd76xrom_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL };
u8 byte;
@ -289,7 +289,7 @@ static int __devinit amd76xrom_init_one (struct pci_dev *pdev,
}
static void __devexit amd76xrom_remove_one (struct pci_dev *pdev)
static void amd76xrom_remove_one(struct pci_dev *pdev)
{
struct amd76xrom_window *window = &amd76xrom_window;
@ -347,4 +347,3 @@ module_exit(cleanup_amd76xrom);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Eric Biederman <ebiederman@lnxi.com>");
MODULE_DESCRIPTION("MTD map driver for BIOS chips on the AMD76X southbridge");

View File

@ -33,7 +33,7 @@ struct autcpu12_nvram_priv {
struct map_info map;
};
static int __devinit autcpu12_nvram_probe(struct platform_device *pdev)
static int autcpu12_nvram_probe(struct platform_device *pdev)
{
map_word tmp, save0, save1;
struct resource *res;
@ -105,7 +105,7 @@ static int __devinit autcpu12_nvram_probe(struct platform_device *pdev)
return -ENOMEM;
}
static int __devexit autcpu12_nvram_remove(struct platform_device *pdev)
static int autcpu12_nvram_remove(struct platform_device *pdev)
{
struct autcpu12_nvram_priv *priv = platform_get_drvdata(pdev);
@ -121,7 +121,7 @@ static struct platform_driver autcpu12_nvram_driver = {
.owner = THIS_MODULE,
},
.probe = autcpu12_nvram_probe,
.remove = __devexit_p(autcpu12_nvram_remove),
.remove = autcpu12_nvram_remove,
};
module_platform_driver(autcpu12_nvram_driver);

View File

@ -30,7 +30,8 @@
#include <linux/io.h>
#include <asm/unaligned.h>
#define pr_devinit(fmt, args...) ({ static const __devinitconst char __fmt[] = fmt; printk(__fmt, ## args); })
#define pr_devinit(fmt, args...) \
({ static const char __fmt[] = fmt; printk(__fmt, ## args); })
#define DRIVER_NAME "bfin-async-flash"
@ -123,7 +124,7 @@ static void bfin_flash_copy_to(struct map_info *map, unsigned long to, const voi
static const char *part_probe_types[] = { "cmdlinepart", "RedBoot", NULL };
static int __devinit bfin_flash_probe(struct platform_device *pdev)
static int bfin_flash_probe(struct platform_device *pdev)
{
int ret;
struct physmap_flash_data *pdata = pdev->dev.platform_data;
@ -172,7 +173,7 @@ static int __devinit bfin_flash_probe(struct platform_device *pdev)
return 0;
}
static int __devexit bfin_flash_remove(struct platform_device *pdev)
static int bfin_flash_remove(struct platform_device *pdev)
{
struct async_state *state = platform_get_drvdata(pdev);
gpio_free(state->enet_flash_pin);
@ -184,7 +185,7 @@ static int __devexit bfin_flash_remove(struct platform_device *pdev)
static struct platform_driver bfin_flash_driver = {
.probe = bfin_flash_probe,
.remove = __devexit_p(bfin_flash_remove),
.remove = bfin_flash_remove,
.driver = {
.name = DRIVER_NAME,
},

View File

@ -112,8 +112,8 @@ static void ck804xrom_cleanup(struct ck804xrom_window *window)
}
static int __devinit ck804xrom_init_one (struct pci_dev *pdev,
const struct pci_device_id *ent)
static int ck804xrom_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL };
u8 byte;
@ -320,7 +320,7 @@ static int __devinit ck804xrom_init_one (struct pci_dev *pdev,
}
static void __devexit ck804xrom_remove_one (struct pci_dev *pdev)
static void ck804xrom_remove_one(struct pci_dev *pdev)
{
struct ck804xrom_window *window = &ck804xrom_window;

View File

@ -144,7 +144,7 @@ static void esb2rom_cleanup(struct esb2rom_window *window)
pci_dev_put(window->pdev);
}
static int __devinit esb2rom_init_one(struct pci_dev *pdev,
static int esb2rom_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL };
@ -378,13 +378,13 @@ static int __devinit esb2rom_init_one(struct pci_dev *pdev,
return 0;
}
static void __devexit esb2rom_remove_one (struct pci_dev *pdev)
static void esb2rom_remove_one(struct pci_dev *pdev)
{
struct esb2rom_window *window = &esb2rom_window;
esb2rom_cleanup(window);
}
static struct pci_device_id esb2rom_pci_tbl[] __devinitdata = {
static struct pci_device_id esb2rom_pci_tbl[] = {
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0,
PCI_ANY_ID, PCI_ANY_ID, },
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0,

View File

@ -1,277 +0,0 @@
/* fortunet.c memory map
*
*/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/string.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
#include <linux/mtd/partitions.h>
#include <asm/io.h>
#define MAX_NUM_REGIONS 4
#define MAX_NUM_PARTITIONS 8
#define DEF_WINDOW_ADDR_PHY 0x00000000
#define DEF_WINDOW_SIZE 0x00800000 // 8 Mega Bytes
#define MTD_FORTUNET_PK "MTD FortuNet: "
#define MAX_NAME_SIZE 128
struct map_region
{
int window_addr_physical;
int altbankwidth;
struct map_info map_info;
struct mtd_info *mymtd;
struct mtd_partition parts[MAX_NUM_PARTITIONS];
char map_name[MAX_NAME_SIZE];
char parts_name[MAX_NUM_PARTITIONS][MAX_NAME_SIZE];
};
static struct map_region map_regions[MAX_NUM_REGIONS];
static int map_regions_set[MAX_NUM_REGIONS] = {0,0,0,0};
static int map_regions_parts[MAX_NUM_REGIONS] = {0,0,0,0};
struct map_info default_map = {
.size = DEF_WINDOW_SIZE,
.bankwidth = 4,
};
static char * __init get_string_option(char *dest,int dest_size,char *sor)
{
if(!dest_size)
return sor;
dest_size--;
while(*sor)
{
if(*sor==',')
{
sor++;
break;
}
else if(*sor=='\"')
{
sor++;
while(*sor)
{
if(*sor=='\"')
{
sor++;
break;
}
*dest = *sor;
dest++;
sor++;
dest_size--;
if(!dest_size)
{
*dest = 0;
return sor;
}
}
}
else
{
*dest = *sor;
dest++;
sor++;
dest_size--;
if(!dest_size)
{
*dest = 0;
return sor;
}
}
}
*dest = 0;
return sor;
}
static int __init MTD_New_Region(char *line)
{
char string[MAX_NAME_SIZE];
int params[6];
get_options (get_string_option(string,sizeof(string),line),6,params);
if(params[0]<1)
{
printk(MTD_FORTUNET_PK "Bad parameters for MTD Region "
" name,region-number[,base,size,bankwidth,altbankwidth]\n");
return 1;
}
if((params[1]<0)||(params[1]>=MAX_NUM_REGIONS))
{
printk(MTD_FORTUNET_PK "Bad region index of %d only have 0..%u regions\n",
params[1],MAX_NUM_REGIONS-1);
return 1;
}
memset(&map_regions[params[1]],0,sizeof(map_regions[params[1]]));
memcpy(&map_regions[params[1]].map_info,
&default_map,sizeof(map_regions[params[1]].map_info));
map_regions_set[params[1]] = 1;
map_regions[params[1]].window_addr_physical = DEF_WINDOW_ADDR_PHY;
map_regions[params[1]].altbankwidth = 2;
map_regions[params[1]].mymtd = NULL;
map_regions[params[1]].map_info.name = map_regions[params[1]].map_name;
strcpy(map_regions[params[1]].map_info.name,string);
if(params[0]>1)
{
map_regions[params[1]].window_addr_physical = params[2];
}
if(params[0]>2)
{
map_regions[params[1]].map_info.size = params[3];
}
if(params[0]>3)
{
map_regions[params[1]].map_info.bankwidth = params[4];
}
if(params[0]>4)
{
map_regions[params[1]].altbankwidth = params[5];
}
return 1;
}
static int __init MTD_New_Partition(char *line)
{
char string[MAX_NAME_SIZE];
int params[4];
get_options (get_string_option(string,sizeof(string),line),4,params);
if(params[0]<3)
{
printk(MTD_FORTUNET_PK "Bad parameters for MTD Partition "
" name,region-number,size,offset\n");
return 1;
}
if((params[1]<0)||(params[1]>=MAX_NUM_REGIONS))
{
printk(MTD_FORTUNET_PK "Bad region index of %d only have 0..%u regions\n",
params[1],MAX_NUM_REGIONS-1);
return 1;
}
if(map_regions_parts[params[1]]>=MAX_NUM_PARTITIONS)
{
printk(MTD_FORTUNET_PK "Out of space for partition in this region\n");
return 1;
}
map_regions[params[1]].parts[map_regions_parts[params[1]]].name =
map_regions[params[1]]. parts_name[map_regions_parts[params[1]]];
strcpy(map_regions[params[1]].parts[map_regions_parts[params[1]]].name,string);
map_regions[params[1]].parts[map_regions_parts[params[1]]].size =
params[2];
map_regions[params[1]].parts[map_regions_parts[params[1]]].offset =
params[3];
map_regions[params[1]].parts[map_regions_parts[params[1]]].mask_flags = 0;
map_regions_parts[params[1]]++;
return 1;
}
__setup("MTD_Region=", MTD_New_Region);
__setup("MTD_Partition=", MTD_New_Partition);
/* Backwards-spelling-compatibility */
__setup("MTD_Partion=", MTD_New_Partition);
static int __init init_fortunet(void)
{
int ix,iy;
for(iy=ix=0;ix<MAX_NUM_REGIONS;ix++)
{
if(map_regions_parts[ix]&&(!map_regions_set[ix]))
{
printk(MTD_FORTUNET_PK "Region %d is not setup (Setting to default)\n",
ix);
memset(&map_regions[ix],0,sizeof(map_regions[ix]));
memcpy(&map_regions[ix].map_info,&default_map,
sizeof(map_regions[ix].map_info));
map_regions_set[ix] = 1;
map_regions[ix].window_addr_physical = DEF_WINDOW_ADDR_PHY;
map_regions[ix].altbankwidth = 2;
map_regions[ix].mymtd = NULL;
map_regions[ix].map_info.name = map_regions[ix].map_name;
strcpy(map_regions[ix].map_info.name,"FORTUNET");
}
if(map_regions_set[ix])
{
iy++;
printk(KERN_NOTICE MTD_FORTUNET_PK "%s flash device at physically "
" address %x size %x\n",
map_regions[ix].map_info.name,
map_regions[ix].window_addr_physical,
map_regions[ix].map_info.size);
map_regions[ix].map_info.phys = map_regions[ix].window_addr_physical,
map_regions[ix].map_info.virt =
ioremap_nocache(
map_regions[ix].window_addr_physical,
map_regions[ix].map_info.size);
if(!map_regions[ix].map_info.virt)
{
int j = 0;
printk(MTD_FORTUNET_PK "%s flash failed to ioremap!\n",
map_regions[ix].map_info.name);
for (j = 0 ; j < ix; j++)
iounmap(map_regions[j].map_info.virt);
return -ENXIO;
}
simple_map_init(&map_regions[ix].map_info);
printk(KERN_NOTICE MTD_FORTUNET_PK "%s flash is virtually at: %x\n",
map_regions[ix].map_info.name,
map_regions[ix].map_info.virt);
map_regions[ix].mymtd = do_map_probe("cfi_probe",
&map_regions[ix].map_info);
if((!map_regions[ix].mymtd)&&(
map_regions[ix].altbankwidth!=map_regions[ix].map_info.bankwidth))
{
printk(KERN_NOTICE MTD_FORTUNET_PK "Trying alternate bankwidth "
"for %s flash.\n",
map_regions[ix].map_info.name);
map_regions[ix].map_info.bankwidth =
map_regions[ix].altbankwidth;
map_regions[ix].mymtd = do_map_probe("cfi_probe",
&map_regions[ix].map_info);
}
map_regions[ix].mymtd->owner = THIS_MODULE;
mtd_device_register(map_regions[ix].mymtd,
map_regions[ix].parts,
map_regions_parts[ix]);
}
}
if(iy)
return 0;
return -ENXIO;
}
static void __exit cleanup_fortunet(void)
{
int ix;
for(ix=0;ix<MAX_NUM_REGIONS;ix++)
{
if(map_regions_set[ix])
{
if( map_regions[ix].mymtd )
{
mtd_device_unregister(map_regions[ix].mymtd);
map_destroy( map_regions[ix].mymtd );
}
iounmap((void *)map_regions[ix].map_info.virt);
}
}
}
module_init(init_fortunet);
module_exit(cleanup_fortunet);
MODULE_AUTHOR("FortuNet, Inc.");
MODULE_DESCRIPTION("MTD map driver for FortuNet boards");

View File

@ -26,7 +26,8 @@
#include <linux/slab.h>
#include <linux/types.h>
#define pr_devinit(fmt, args...) ({ static const __devinitconst char __fmt[] = fmt; printk(__fmt, ## args); })
#define pr_devinit(fmt, args...) \
({ static const char __fmt[] = fmt; printk(__fmt, ## args); })
#define DRIVER_NAME "gpio-addr-flash"
#define PFX DRIVER_NAME ": "
@ -142,7 +143,8 @@ static void gf_write(struct map_info *map, map_word d1, unsigned long ofs)
*
* See gf_copy_from() caveat.
*/
static void gf_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
static void gf_copy_to(struct map_info *map, unsigned long to,
const void *from, ssize_t len)
{
struct async_state *state = gf_map_info_to_state(map);
@ -185,7 +187,7 @@ static const char *part_probe_types[] = { "cmdlinepart", "RedBoot", NULL };
* ...
* };
*/
static int __devinit gpio_flash_probe(struct platform_device *pdev)
static int gpio_flash_probe(struct platform_device *pdev)
{
size_t i, arr_size;
struct physmap_flash_data *pdata;
@ -258,7 +260,7 @@ static int __devinit gpio_flash_probe(struct platform_device *pdev)
return 0;
}
static int __devexit gpio_flash_remove(struct platform_device *pdev)
static int gpio_flash_remove(struct platform_device *pdev)
{
struct async_state *state = platform_get_drvdata(pdev);
size_t i = 0;
@ -273,7 +275,7 @@ static int __devexit gpio_flash_remove(struct platform_device *pdev)
static struct platform_driver gpio_flash_driver = {
.probe = gpio_flash_probe,
.remove = __devexit_p(gpio_flash_remove),
.remove = gpio_flash_remove,
.driver = {
.name = DRIVER_NAME,
},

View File

@ -84,8 +84,8 @@ static void ichxrom_cleanup(struct ichxrom_window *window)
}
static int __devinit ichxrom_init_one (struct pci_dev *pdev,
const struct pci_device_id *ent)
static int ichxrom_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL };
struct ichxrom_window *window = &ichxrom_window;
@ -315,13 +315,13 @@ static int __devinit ichxrom_init_one (struct pci_dev *pdev,
}
static void __devexit ichxrom_remove_one (struct pci_dev *pdev)
static void ichxrom_remove_one(struct pci_dev *pdev)
{
struct ichxrom_window *window = &ichxrom_window;
ichxrom_cleanup(window);
}
static struct pci_device_id ichxrom_pci_tbl[] __devinitdata = {
static struct pci_device_id ichxrom_pci_tbl[] = {
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0,
PCI_ANY_ID, PCI_ANY_ID, },
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0,

View File

@ -63,24 +63,24 @@ struct vr_nor_mtd {
#define TIMING_BYTE_EN (1 << 0) /* 8-bit vs 16-bit bus */
#define TIMING_MASK 0x3FFF0000
static void __devexit vr_nor_destroy_partitions(struct vr_nor_mtd *p)
static void vr_nor_destroy_partitions(struct vr_nor_mtd *p)
{
mtd_device_unregister(p->info);
}
static int __devinit vr_nor_init_partitions(struct vr_nor_mtd *p)
static int vr_nor_init_partitions(struct vr_nor_mtd *p)
{
/* register the flash bank */
/* partition the flash bank */
return mtd_device_parse_register(p->info, NULL, NULL, NULL, 0);
}
static void __devexit vr_nor_destroy_mtd_setup(struct vr_nor_mtd *p)
static void vr_nor_destroy_mtd_setup(struct vr_nor_mtd *p)
{
map_destroy(p->info);
}
static int __devinit vr_nor_mtd_setup(struct vr_nor_mtd *p)
static int vr_nor_mtd_setup(struct vr_nor_mtd *p)
{
static const char *probe_types[] =
{ "cfi_probe", "jedec_probe", NULL };
@ -96,7 +96,7 @@ static int __devinit vr_nor_mtd_setup(struct vr_nor_mtd *p)
return 0;
}
static void __devexit vr_nor_destroy_maps(struct vr_nor_mtd *p)
static void vr_nor_destroy_maps(struct vr_nor_mtd *p)
{
unsigned int exp_timing_cs0;
@ -116,7 +116,7 @@ static void __devexit vr_nor_destroy_maps(struct vr_nor_mtd *p)
* Initialize the map_info structure and map the flash.
* Returns 0 on success, nonzero otherwise.
*/
static int __devinit vr_nor_init_maps(struct vr_nor_mtd *p)
static int vr_nor_init_maps(struct vr_nor_mtd *p)
{
unsigned long csr_phys, csr_len;
unsigned long win_phys, win_len;
@ -176,7 +176,7 @@ static struct pci_device_id vr_nor_pci_ids[] = {
{0,}
};
static void __devexit vr_nor_pci_remove(struct pci_dev *dev)
static void vr_nor_pci_remove(struct pci_dev *dev)
{
struct vr_nor_mtd *p = pci_get_drvdata(dev);
@ -189,7 +189,7 @@ static void __devexit vr_nor_pci_remove(struct pci_dev *dev)
pci_disable_device(dev);
}
static int __devinit
static int
vr_nor_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
struct vr_nor_mtd *p = NULL;
@ -256,7 +256,7 @@ vr_nor_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
static struct pci_driver vr_nor_pci_driver = {
.name = DRV_NAME,
.probe = vr_nor_pci_probe,
.remove = __devexit_p(vr_nor_pci_remove),
.remove = vr_nor_pci_remove,
.id_table = vr_nor_pci_ids,
};

View File

@ -45,7 +45,7 @@ struct ltq_mtd {
};
static const char ltq_map_name[] = "ltq_nor";
static const char *ltq_probe_types[] __devinitconst = {
static const char *ltq_probe_types[] = {
"cmdlinepart", "ofpart", NULL };
static map_word
@ -109,7 +109,7 @@ ltq_copy_to(struct map_info *map, unsigned long to,
spin_unlock_irqrestore(&ebu_lock, flags);
}
static int __devinit
static int
ltq_mtd_probe(struct platform_device *pdev)
{
struct mtd_part_parser_data ppdata;
@ -185,7 +185,7 @@ err_out:
return err;
}
static int __devexit
static int
ltq_mtd_remove(struct platform_device *pdev)
{
struct ltq_mtd *ltq_mtd = platform_get_drvdata(pdev);
@ -209,7 +209,7 @@ MODULE_DEVICE_TABLE(of, ltq_mtd_match);
static struct platform_driver ltq_mtd_driver = {
.probe = ltq_mtd_probe,
.remove = __devexit_p(ltq_mtd_remove),
.remove = ltq_mtd_remove,
.driver = {
.name = "ltq-nor",
.owner = THIS_MODULE,

View File

@ -125,7 +125,7 @@ static int latch_addr_flash_remove(struct platform_device *dev)
return 0;
}
static int __devinit latch_addr_flash_probe(struct platform_device *dev)
static int latch_addr_flash_probe(struct platform_device *dev)
{
struct latch_addr_flash_data *latch_addr_data;
struct latch_addr_flash_info *info;
@ -218,7 +218,7 @@ done:
static struct platform_driver latch_addr_flash_driver = {
.probe = latch_addr_flash_probe,
.remove = __devexit_p(latch_addr_flash_remove),
.remove = latch_addr_flash_remove,
.driver = {
.name = DRIVER_NAME,
},

View File

@ -253,7 +253,7 @@ static struct pci_device_id mtd_pci_ids[] = {
* Generic code follows.
*/
static int __devinit
static int
mtd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
struct mtd_pci_info *info = (struct mtd_pci_info *)id->driver_data;
@ -308,7 +308,7 @@ out:
return err;
}
static void __devexit
static void
mtd_pci_remove(struct pci_dev *dev)
{
struct mtd_info *mtd = pci_get_drvdata(dev);
@ -326,7 +326,7 @@ mtd_pci_remove(struct pci_dev *dev)
static struct pci_driver mtd_pci_driver = {
.name = "MTD PCI",
.probe = mtd_pci_probe,
.remove = __devexit_p(mtd_pci_remove),
.remove = mtd_pci_remove,
.id_table = mtd_pci_ids,
};

View File

@ -77,7 +77,7 @@ static int of_flash_remove(struct platform_device *dev)
/* Helper function to handle probing of the obsolete "direct-mapped"
* compatible binding, which has an extra "probe-type" property
* describing the type of flash probe necessary. */
static struct mtd_info * __devinit obsolete_probe(struct platform_device *dev,
static struct mtd_info *obsolete_probe(struct platform_device *dev,
struct map_info *map)
{
struct device_node *dp = dev->dev.of_node;
@ -116,7 +116,7 @@ static struct mtd_info * __devinit obsolete_probe(struct platform_device *dev,
information. */
static const char *part_probe_types_def[] = { "cmdlinepart", "RedBoot",
"ofpart", "ofoldpart", NULL };
static const char ** __devinit of_get_probes(struct device_node *dp)
static const char **of_get_probes(struct device_node *dp)
{
const char *cp;
int cplen;
@ -145,14 +145,14 @@ static const char ** __devinit of_get_probes(struct device_node *dp)
return res;
}
static void __devinit of_free_probes(const char **probes)
static void of_free_probes(const char **probes)
{
if (probes != part_probe_types_def)
kfree(probes);
}
static struct of_device_id of_flash_match[];
static int __devinit of_flash_probe(struct platform_device *dev)
static int of_flash_probe(struct platform_device *dev)
{
const char **part_probe_types;
const struct of_device_id *match;
@ -170,6 +170,7 @@ static int __devinit of_flash_probe(struct platform_device *dev)
resource_size_t res_size;
struct mtd_part_parser_data ppdata;
bool map_indirect;
const char *mtd_name;
match = of_match_device(of_flash_match, &dev->dev);
if (!match)
@ -178,6 +179,8 @@ static int __devinit of_flash_probe(struct platform_device *dev)
reg_tuple_size = (of_n_addr_cells(dp) + of_n_size_cells(dp)) * sizeof(u32);
of_property_read_string(dp, "linux,mtd-name", &mtd_name);
/*
* Get number of "reg" tuples. Scan for MTD devices on area's
* described by each "reg" region. This makes it possible (including
@ -234,7 +237,7 @@ static int __devinit of_flash_probe(struct platform_device *dev)
goto err_out;
}
info->list[i].map.name = dev_name(&dev->dev);
info->list[i].map.name = mtd_name ?: dev_name(&dev->dev);
info->list[i].map.phys = res.start;
info->list[i].map.size = res_size;
info->list[i].map.bankwidth = be32_to_cpup(width);
@ -282,6 +285,7 @@ static int __devinit of_flash_probe(struct platform_device *dev)
}
err = 0;
info->cmtd = NULL;
if (info->list_size == 1) {
info->cmtd = info->list[0].mtd;
} else if (info->list_size > 1) {
@ -290,9 +294,10 @@ static int __devinit of_flash_probe(struct platform_device *dev)
*/
info->cmtd = mtd_concat_create(mtd_list, info->list_size,
dev_name(&dev->dev));
if (info->cmtd == NULL)
err = -ENXIO;
}
if (info->cmtd == NULL)
err = -ENXIO;
if (err)
goto err_out;

View File

@ -58,7 +58,7 @@ static void pismo_set_vpp(struct platform_device *pdev, int on)
pismo->vpp(pismo->vpp_data, on);
}
static unsigned int __devinit pismo_width_to_bytes(unsigned int width)
static unsigned int pismo_width_to_bytes(unsigned int width)
{
width &= 15;
if (width > 2)
@ -66,7 +66,7 @@ static unsigned int __devinit pismo_width_to_bytes(unsigned int width)
return 1 << width;
}
static int __devinit pismo_eeprom_read(struct i2c_client *client, void *buf,
static int pismo_eeprom_read(struct i2c_client *client, void *buf,
u8 addr, size_t size)
{
int ret;
@ -88,7 +88,7 @@ static int __devinit pismo_eeprom_read(struct i2c_client *client, void *buf,
return ret == ARRAY_SIZE(msg) ? size : -EIO;
}
static int __devinit pismo_add_device(struct pismo_data *pismo, int i,
static int pismo_add_device(struct pismo_data *pismo, int i,
struct pismo_mem *region, const char *name, void *pdata, size_t psize)
{
struct platform_device *dev;
@ -129,7 +129,7 @@ static int __devinit pismo_add_device(struct pismo_data *pismo, int i,
return ret;
}
static int __devinit pismo_add_nor(struct pismo_data *pismo, int i,
static int pismo_add_nor(struct pismo_data *pismo, int i,
struct pismo_mem *region)
{
struct physmap_flash_data data = {
@ -143,7 +143,7 @@ static int __devinit pismo_add_nor(struct pismo_data *pismo, int i,
&data, sizeof(data));
}
static int __devinit pismo_add_sram(struct pismo_data *pismo, int i,
static int pismo_add_sram(struct pismo_data *pismo, int i,
struct pismo_mem *region)
{
struct platdata_mtd_ram data = {
@ -154,7 +154,7 @@ static int __devinit pismo_add_sram(struct pismo_data *pismo, int i,
&data, sizeof(data));
}
static void __devinit pismo_add_one(struct pismo_data *pismo, int i,
static void pismo_add_one(struct pismo_data *pismo, int i,
const struct pismo_cs_block *cs, phys_addr_t base)
{
struct device *dev = &pismo->client->dev;
@ -197,7 +197,7 @@ static void __devinit pismo_add_one(struct pismo_data *pismo, int i,
}
}
static int __devexit pismo_remove(struct i2c_client *client)
static int pismo_remove(struct i2c_client *client)
{
struct pismo_data *pismo = i2c_get_clientdata(client);
int i;
@ -210,7 +210,7 @@ static int __devexit pismo_remove(struct i2c_client *client)
return 0;
}
static int __devinit pismo_probe(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);
@ -267,7 +267,7 @@ static struct i2c_driver pismo_driver = {
.owner = THIS_MODULE,
},
.probe = pismo_probe,
.remove = __devexit_p(pismo_remove),
.remove = pismo_remove,
.id_table = pismo_id,
};

View File

@ -49,7 +49,7 @@ struct pxa2xx_flash_info {
static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
static int __devinit pxa2xx_flash_probe(struct platform_device *pdev)
static int pxa2xx_flash_probe(struct platform_device *pdev)
{
struct flash_platform_data *flash = pdev->dev.platform_data;
struct pxa2xx_flash_info *info;
@ -105,7 +105,7 @@ static int __devinit pxa2xx_flash_probe(struct platform_device *pdev)
return 0;
}
static int __devexit pxa2xx_flash_remove(struct platform_device *dev)
static int pxa2xx_flash_remove(struct platform_device *dev)
{
struct pxa2xx_flash_info *info = platform_get_drvdata(dev);
@ -139,7 +139,7 @@ static struct platform_driver pxa2xx_flash_driver = {
.owner = THIS_MODULE,
},
.probe = pxa2xx_flash_probe,
.remove = __devexit_p(pxa2xx_flash_remove),
.remove = pxa2xx_flash_remove,
.shutdown = pxa2xx_flash_shutdown,
};

View File

@ -149,8 +149,8 @@ static void sa1100_destroy(struct sa_info *info, struct flash_platform_data *pla
plat->exit();
}
static struct sa_info *__devinit
sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *plat)
static struct sa_info *sa1100_setup_mtd(struct platform_device *pdev,
struct flash_platform_data *plat)
{
struct sa_info *info;
int nr, size, i, ret = 0;
@ -246,7 +246,7 @@ sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *plat)
static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL };
static int __devinit sa1100_mtd_probe(struct platform_device *pdev)
static int sa1100_mtd_probe(struct platform_device *pdev)
{
struct flash_platform_data *plat = pdev->dev.platform_data;
struct sa_info *info;

View File

@ -69,7 +69,7 @@ static struct map_info scb2_map = {
};
static int region_fail;
static int __devinit
static int
scb2_fixup_mtd(struct mtd_info *mtd)
{
int i;
@ -133,7 +133,7 @@ scb2_fixup_mtd(struct mtd_info *mtd)
/* CSB5's 'Function Control Register' has bits for decoding @ >= 0xffc00000 */
#define CSB5_FCR 0x41
#define CSB5_FCR_DECODE_ALL 0x0e
static int __devinit
static int
scb2_flash_probe(struct pci_dev *dev, const struct pci_device_id *ent)
{
u8 reg;
@ -197,7 +197,7 @@ scb2_flash_probe(struct pci_dev *dev, const struct pci_device_id *ent)
return 0;
}
static void __devexit
static void
scb2_flash_remove(struct pci_dev *dev)
{
if (!scb2_mtd)
@ -231,7 +231,7 @@ static struct pci_driver scb2_flash_driver = {
.name = "Intel SCB2 BIOS Flash",
.id_table = scb2_flash_pci_ids,
.probe = scb2_flash_probe,
.remove = __devexit_p(scb2_flash_remove),
.remove = scb2_flash_remove,
};
module_pci_driver(scb2_flash_driver);

View File

@ -108,7 +108,7 @@ int uflash_devinit(struct platform_device *op, struct device_node *dp)
return 0;
}
static int __devinit uflash_probe(struct platform_device *op)
static int uflash_probe(struct platform_device *op)
{
struct device_node *dp = op->dev.of_node;
@ -121,7 +121,7 @@ static int __devinit uflash_probe(struct platform_device *op)
return uflash_devinit(op, dp);
}
static int __devexit uflash_remove(struct platform_device *op)
static int uflash_remove(struct platform_device *op)
{
struct uflash_dev *up = dev_get_drvdata(&op->dev);
@ -155,7 +155,7 @@ static struct platform_driver uflash_driver = {
.of_match_table = uflash_match,
},
.probe = uflash_probe,
.remove = __devexit_p(uflash_remove),
.remove = uflash_remove,
};
module_platform_driver(uflash_driver);

View File

@ -596,7 +596,7 @@ fail_name:
}
/* Handles very basic info about the flash, queries for details */
static int __devinit vmu_connect(struct maple_device *mdev)
static int vmu_connect(struct maple_device *mdev)
{
unsigned long test_flash_data, basic_flash_data;
int c, error;
@ -690,7 +690,7 @@ fail_nomem:
return error;
}
static void __devexit vmu_disconnect(struct maple_device *mdev)
static void vmu_disconnect(struct maple_device *mdev)
{
struct memcard *card;
struct mdev_part *mpart;
@ -772,7 +772,7 @@ static void vmu_file_error(struct maple_device *mdev, void *recvbuf)
}
static int __devinit probe_maple_vmu(struct device *dev)
static int probe_maple_vmu(struct device *dev)
{
int error;
struct maple_device *mdev = to_maple_dev(dev);
@ -789,7 +789,7 @@ static int __devinit probe_maple_vmu(struct device *dev)
return 0;
}
static int __devexit remove_maple_vmu(struct device *dev)
static int remove_maple_vmu(struct device *dev)
{
struct maple_device *mdev = to_maple_dev(dev);
@ -802,7 +802,7 @@ static struct maple_driver vmu_flash_driver = {
.drv = {
.name = "Dreamcast_visual_memory",
.probe = probe_maple_vmu,
.remove = __devexit_p(remove_maple_vmu),
.remove = remove_maple_vmu,
},
};

View File

@ -32,7 +32,6 @@
#include <linux/hdreg.h>
#include <linux/init.h>
#include <linux/mutex.h>
#include <linux/kthread.h>
#include <asm/uaccess.h>
#include "mtdcore.h"
@ -121,16 +120,14 @@ static int do_blktrans_request(struct mtd_blktrans_ops *tr,
int mtd_blktrans_cease_background(struct mtd_blktrans_dev *dev)
{
if (kthread_should_stop())
return 1;
return dev->bg_stop;
}
EXPORT_SYMBOL_GPL(mtd_blktrans_cease_background);
static int mtd_blktrans_thread(void *arg)
static void mtd_blktrans_work(struct work_struct *work)
{
struct mtd_blktrans_dev *dev = arg;
struct mtd_blktrans_dev *dev =
container_of(work, struct mtd_blktrans_dev, work);
struct mtd_blktrans_ops *tr = dev->tr;
struct request_queue *rq = dev->rq;
struct request *req = NULL;
@ -138,7 +135,7 @@ static int mtd_blktrans_thread(void *arg)
spin_lock_irq(rq->queue_lock);
while (!kthread_should_stop()) {
while (1) {
int res;
dev->bg_stop = false;
@ -156,15 +153,7 @@ static int mtd_blktrans_thread(void *arg)
background_done = !dev->bg_stop;
continue;
}
set_current_state(TASK_INTERRUPTIBLE);
if (kthread_should_stop())
set_current_state(TASK_RUNNING);
spin_unlock_irq(rq->queue_lock);
schedule();
spin_lock_irq(rq->queue_lock);
continue;
break;
}
spin_unlock_irq(rq->queue_lock);
@ -185,8 +174,6 @@ static int mtd_blktrans_thread(void *arg)
__blk_end_request_all(req, -EIO);
spin_unlock_irq(rq->queue_lock);
return 0;
}
static void mtd_blktrans_request(struct request_queue *rq)
@ -199,10 +186,8 @@ static void mtd_blktrans_request(struct request_queue *rq)
if (!dev)
while ((req = blk_fetch_request(rq)) != NULL)
__blk_end_request_all(req, -ENODEV);
else {
dev->bg_stop = true;
wake_up_process(dev->thread);
}
else
queue_work(dev->wq, &dev->work);
}
static int blktrans_open(struct block_device *bdev, fmode_t mode)
@ -325,7 +310,7 @@ unlock:
return ret;
}
static const struct block_device_operations mtd_blktrans_ops = {
static const struct block_device_operations mtd_block_ops = {
.owner = THIS_MODULE,
.open = blktrans_open,
.release = blktrans_release,
@ -401,7 +386,7 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
gd->private_data = new;
gd->major = tr->major;
gd->first_minor = (new->devnum) << tr->part_bits;
gd->fops = &mtd_blktrans_ops;
gd->fops = &mtd_block_ops;
if (tr->part_bits)
if (new->devnum < 26)
@ -437,14 +422,13 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
gd->queue = new->rq;
/* Create processing thread */
/* TODO: workqueue ? */
new->thread = kthread_run(mtd_blktrans_thread, new,
"%s%d", tr->name, new->mtd->index);
if (IS_ERR(new->thread)) {
ret = PTR_ERR(new->thread);
/* Create processing workqueue */
new->wq = alloc_workqueue("%s%d", 0, 0,
tr->name, new->mtd->index);
if (!new->wq)
goto error4;
}
INIT_WORK(&new->work, mtd_blktrans_work);
gd->driverfs_dev = &new->mtd->dev;
if (new->readonly)
@ -484,9 +468,8 @@ int del_mtd_blktrans_dev(struct mtd_blktrans_dev *old)
/* Stop new requests to arrive */
del_gendisk(old->disk);
/* Stop the thread */
kthread_stop(old->thread);
/* Stop workqueue. This will perform any pending request. */
destroy_workqueue(old->wq);
/* Kill current requests */
spin_lock_irqsave(&old->queue_lock, flags);

View File

@ -271,7 +271,7 @@ static void find_next_position(struct mtdoops_context *cxt)
if (count[0] == 0xffffffff && count[1] == 0xffffffff)
mark_page_unused(cxt, page);
if (count[0] == 0xffffffff)
if (count[0] == 0xffffffff || count[1] != MTDOOPS_KERNMSG_MAGIC)
continue;
if (maxcount == 0xffffffff) {
maxcount = count[0];
@ -289,14 +289,13 @@ static void find_next_position(struct mtdoops_context *cxt)
}
}
if (maxcount == 0xffffffff) {
cxt->nextpage = 0;
cxt->nextcount = 1;
schedule_work(&cxt->work_erase);
return;
cxt->nextpage = cxt->oops_pages - 1;
cxt->nextcount = 0;
}
else {
cxt->nextpage = maxpos;
cxt->nextcount = maxcount;
}
cxt->nextpage = maxpos;
cxt->nextcount = maxcount;
mtdoops_inc_counter(cxt);
}

View File

@ -50,16 +50,30 @@ config MTD_NAND_MUSEUM_IDS
of these chips were reused by later, larger chips.
config MTD_NAND_DENALI
depends on PCI
tristate "Support Denali NAND controller"
help
Enable support for the Denali NAND controller. This should be
combined with either the PCI or platform drivers to provide device
registration.
config MTD_NAND_DENALI_PCI
tristate "Support Denali NAND controller on Intel Moorestown"
depends on PCI && MTD_NAND_DENALI
help
Enable the driver for NAND flash on Intel Moorestown, using the
Denali NAND controller core.
config MTD_NAND_DENALI_DT
tristate "Support Denali NAND controller as a DT device"
depends on HAVE_CLK && MTD_NAND_DENALI
help
Enable the driver for NAND flash on platforms using a Denali NAND
controller as a DT device.
config MTD_NAND_DENALI_SCRATCH_REG_ADDR
hex "Denali NAND size scratch register address"
default "0xFF108018"
depends on MTD_NAND_DENALI
depends on MTD_NAND_DENALI_PCI
help
Some platforms place the NAND chip size in a scratch register
because (some versions of) the driver aren't able to automatically
@ -433,6 +447,14 @@ config MTD_NAND_GPMI_NAND
block, such as SD card. So pay attention to it when you enable
the GPMI.
config MTD_NAND_BCM47XXNFLASH
tristate "Support for NAND flash on BCM4706 BCMA bus"
depends on BCMA_NFLASH
help
BCMA bus can have various flash memories attached, they are
registered by bcma as platform devices. This enables driver for
NAND flash memories. For now only BCM4706 is supported.
config MTD_NAND_PLATFORM
tristate "Support for generic platform NAND driver"
depends on HAS_IOMEM
@ -499,12 +521,6 @@ config MTD_NAND_MXC
This enables the driver for the NAND flash controller on the
MXC processors.
config MTD_NAND_NOMADIK
tristate "ST Nomadik 8815 NAND support"
depends on ARCH_NOMADIK
help
Driver for the NAND flash controller on the Nomadik, with ECC.
config MTD_NAND_SH_FLCTL
tristate "Support for NAND on Renesas SuperH FLCTL"
depends on SUPERH || ARCH_SHMOBILE

View File

@ -11,6 +11,8 @@ obj-$(CONFIG_MTD_SM_COMMON) += sm_common.o
obj-$(CONFIG_MTD_NAND_CAFE) += cafe_nand.o
obj-$(CONFIG_MTD_NAND_AMS_DELTA) += ams-delta.o
obj-$(CONFIG_MTD_NAND_DENALI) += denali.o
obj-$(CONFIG_MTD_NAND_DENALI_PCI) += denali_pci.o
obj-$(CONFIG_MTD_NAND_DENALI_DT) += denali_dt.o
obj-$(CONFIG_MTD_NAND_AU1550) += au1550nd.o
obj-$(CONFIG_MTD_NAND_BF5XX) += bf5xx_nand.o
obj-$(CONFIG_MTD_NAND_PPCHAMELEONEVB) += ppchameleonevb.o
@ -45,11 +47,11 @@ 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_NOMADIK) += nomadik_nand.o
obj-$(CONFIG_MTD_NAND_MPC5121_NFC) += mpc5121_nfc.o
obj-$(CONFIG_MTD_NAND_RICOH) += r852.o
obj-$(CONFIG_MTD_NAND_JZ4740) += jz4740_nand.o
obj-$(CONFIG_MTD_NAND_GPMI_NAND) += gpmi-nand/
obj-$(CONFIG_MTD_NAND_XWAY) += xway_nand.o
obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH) += bcm47xxnflash/
nand-objs := nand_base.o nand_bbt.o

View File

@ -173,7 +173,7 @@ static const struct gpio _mandatory_gpio[] = {
/*
* Main initialization routine
*/
static int __devinit ams_delta_init(struct platform_device *pdev)
static int ams_delta_init(struct platform_device *pdev)
{
struct nand_chip *this;
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@ -270,7 +270,7 @@ out_free:
/*
* Clean up routine
*/
static int __devexit ams_delta_cleanup(struct platform_device *pdev)
static int ams_delta_cleanup(struct platform_device *pdev)
{
void __iomem *io_base = platform_get_drvdata(pdev);
@ -289,7 +289,7 @@ static int __devexit ams_delta_cleanup(struct platform_device *pdev)
static struct platform_driver ams_delta_nand_driver = {
.probe = ams_delta_init,
.remove = __devexit_p(ams_delta_cleanup),
.remove = ams_delta_cleanup,
.driver = {
.name = "ams-delta-nand",
.owner = THIS_MODULE,

View File

@ -331,13 +331,13 @@ static void atmel_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
* 12-bits 20-bytes 21-bytes
* 24-bits 39-bytes 42-bytes
*/
static int __devinit pmecc_get_ecc_bytes(int cap, int sector_size)
static int pmecc_get_ecc_bytes(int cap, int sector_size)
{
int m = 12 + sector_size / 512;
return (m * cap + 7) / 8;
}
static void __devinit pmecc_config_ecc_layout(struct nand_ecclayout *layout,
static void pmecc_config_ecc_layout(struct nand_ecclayout *layout,
int oobsize, int ecc_len)
{
int i;
@ -353,7 +353,7 @@ static void __devinit pmecc_config_ecc_layout(struct nand_ecclayout *layout,
oobsize - ecc_len - layout->oobfree[0].offset;
}
static void __devinit __iomem *pmecc_get_alpha_to(struct atmel_nand_host *host)
static void __iomem *pmecc_get_alpha_to(struct atmel_nand_host *host)
{
int table_size;
@ -375,7 +375,7 @@ static void pmecc_data_free(struct atmel_nand_host *host)
kfree(host->pmecc_delta);
}
static int __devinit pmecc_data_alloc(struct atmel_nand_host *host)
static int pmecc_data_alloc(struct atmel_nand_host *host)
{
const int cap = host->pmecc_corr_cap;
@ -724,6 +724,7 @@ static int pmecc_correction(struct mtd_info *mtd, u32 pmecc_stat, uint8_t *buf,
struct atmel_nand_host *host = nand_chip->priv;
int i, err_nbr, eccbytes;
uint8_t *buf_pos;
int total_err = 0;
eccbytes = nand_chip->ecc.bytes;
for (i = 0; i < eccbytes; i++)
@ -751,12 +752,13 @@ normal_check:
pmecc_correct_data(mtd, buf_pos, ecc, i,
host->pmecc_bytes_per_sector, err_nbr);
mtd->ecc_stats.corrected += err_nbr;
total_err += err_nbr;
}
}
pmecc_stat >>= 1;
}
return 0;
return total_err;
}
static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
@ -768,6 +770,7 @@ static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
uint32_t *eccpos = chip->ecc.layout->eccpos;
uint32_t stat;
unsigned long end_time;
int bitflips = 0;
pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST);
pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
@ -790,11 +793,14 @@ static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
}
stat = pmecc_readl_relaxed(host->ecc, ISR);
if (stat != 0)
if (pmecc_correction(mtd, stat, buf, &oob[eccpos[0]]) != 0)
return -EIO;
if (stat != 0) {
bitflips = pmecc_correction(mtd, stat, buf, &oob[eccpos[0]]);
if (bitflips < 0)
/* uncorrectable errors */
return 0;
}
return 0;
return bitflips;
}
static int atmel_nand_pmecc_write_page(struct mtd_info *mtd,
@ -1206,7 +1212,7 @@ static void atmel_nand_hwctl(struct mtd_info *mtd, int mode)
}
#if defined(CONFIG_OF)
static int __devinit atmel_of_init_port(struct atmel_nand_host *host,
static int atmel_of_init_port(struct atmel_nand_host *host,
struct device_node *np)
{
u32 val, table_offset;
@ -1293,7 +1299,7 @@ static int __devinit atmel_of_init_port(struct atmel_nand_host *host,
return 0;
}
#else
static int __devinit atmel_of_init_port(struct atmel_nand_host *host,
static int atmel_of_init_port(struct atmel_nand_host *host,
struct device_node *np)
{
return -EINVAL;

View File

@ -382,7 +382,7 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i
while(!this->dev_ready(mtd));
}
static int __devinit find_nand_cs(unsigned long nand_base)
static int find_nand_cs(unsigned long nand_base)
{
void __iomem *base =
(void __iomem *)KSEG1ADDR(AU1000_STATIC_MEM_PHYS_ADDR);
@ -403,7 +403,7 @@ static int __devinit find_nand_cs(unsigned long nand_base)
return -ENODEV;
}
static int __devinit au1550nd_probe(struct platform_device *pdev)
static int au1550nd_probe(struct platform_device *pdev)
{
struct au1550nd_platdata *pd;
struct au1550nd_ctx *ctx;
@ -491,7 +491,7 @@ out1:
return ret;
}
static int __devexit au1550nd_remove(struct platform_device *pdev)
static int au1550nd_remove(struct platform_device *pdev)
{
struct au1550nd_ctx *ctx = platform_get_drvdata(pdev);
struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@ -509,7 +509,7 @@ static struct platform_driver au1550nd_driver = {
.owner = THIS_MODULE,
},
.probe = au1550nd_probe,
.remove = __devexit_p(au1550nd_remove),
.remove = au1550nd_remove,
};
module_platform_driver(au1550nd_driver);

View File

@ -0,0 +1,4 @@
bcm47xxnflash-y += main.o
bcm47xxnflash-y += ops_bcm4706.o
obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH) += bcm47xxnflash.o

View File

@ -0,0 +1,22 @@
#ifndef __BCM47XXNFLASH_H
#define __BCM47XXNFLASH_H
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
struct bcm47xxnflash {
struct bcma_drv_cc *cc;
struct nand_chip nand_chip;
struct mtd_info mtd;
unsigned curr_command;
int curr_page_addr;
int curr_column;
u8 id_data[8];
};
int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n);
#endif /* BCM47XXNFLASH */

View File

@ -0,0 +1,108 @@
/*
* BCM47XX NAND flash driver
*
* Copyright (C) 2012 Rafał Miłecki <zajec5@gmail.com>
*
* 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.
*
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/bcma/bcma.h>
#include "bcm47xxnflash.h"
MODULE_DESCRIPTION("NAND flash driver for BCMA bus");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Rafał Miłecki");
static const char *probes[] = { "bcm47xxpart", NULL };
static int bcm47xxnflash_probe(struct platform_device *pdev)
{
struct bcma_nflash *nflash = dev_get_platdata(&pdev->dev);
struct bcm47xxnflash *b47n;
int err = 0;
b47n = kzalloc(sizeof(*b47n), GFP_KERNEL);
if (!b47n) {
err = -ENOMEM;
goto out;
}
b47n->nand_chip.priv = b47n;
b47n->mtd.owner = THIS_MODULE;
b47n->mtd.priv = &b47n->nand_chip; /* Required */
b47n->cc = container_of(nflash, struct bcma_drv_cc, nflash);
if (b47n->cc->core->bus->chipinfo.id == BCMA_CHIP_ID_BCM4706) {
err = bcm47xxnflash_ops_bcm4706_init(b47n);
} else {
pr_err("Device not supported\n");
err = -ENOTSUPP;
}
if (err) {
pr_err("Initialization failed: %d\n", err);
goto err_init;
}
err = mtd_device_parse_register(&b47n->mtd, probes, NULL, NULL, 0);
if (err) {
pr_err("Failed to register MTD device: %d\n", err);
goto err_dev_reg;
}
return 0;
err_dev_reg:
err_init:
kfree(b47n);
out:
return err;
}
static int __devexit bcm47xxnflash_remove(struct platform_device *pdev)
{
struct bcma_nflash *nflash = dev_get_platdata(&pdev->dev);
if (nflash->mtd)
mtd_device_unregister(nflash->mtd);
return 0;
}
static struct platform_driver bcm47xxnflash_driver = {
.remove = __devexit_p(bcm47xxnflash_remove),
.driver = {
.name = "bcma_nflash",
.owner = THIS_MODULE,
},
};
static int __init bcm47xxnflash_init(void)
{
int err;
/*
* Platform device "bcma_nflash" exists on SoCs and is registered very
* early, it won't be added during runtime (use platform_driver_probe).
*/
err = platform_driver_probe(&bcm47xxnflash_driver, bcm47xxnflash_probe);
if (err)
pr_err("Failed to register serial flash driver: %d\n", err);
return err;
}
static void __exit bcm47xxnflash_exit(void)
{
platform_driver_unregister(&bcm47xxnflash_driver);
}
module_init(bcm47xxnflash_init);
module_exit(bcm47xxnflash_exit);

View File

@ -0,0 +1,413 @@
/*
* BCM47XX NAND flash driver
*
* Copyright (C) 2012 Rafał Miłecki <zajec5@gmail.com>
*
* 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.
*
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/bcma/bcma.h>
#include "bcm47xxnflash.h"
/* Broadcom uses 1'000'000 but it seems to be too many. Tests on WNDR4500 has
* shown 164 retries as maxiumum. */
#define NFLASH_READY_RETRIES 1000
#define NFLASH_SECTOR_SIZE 512
#define NCTL_CMD0 0x00010000
#define NCTL_CMD1W 0x00080000
#define NCTL_READ 0x00100000
#define NCTL_WRITE 0x00200000
#define NCTL_SPECADDR 0x01000000
#define NCTL_READY 0x04000000
#define NCTL_ERR 0x08000000
#define NCTL_CSA 0x40000000
#define NCTL_START 0x80000000
/**************************************************
* Various helpers
**************************************************/
static inline u8 bcm47xxnflash_ops_bcm4706_ns_to_cycle(u16 ns, u16 clock)
{
return ((ns * 1000 * clock) / 1000000) + 1;
}
static int bcm47xxnflash_ops_bcm4706_ctl_cmd(struct bcma_drv_cc *cc, u32 code)
{
int i = 0;
bcma_cc_write32(cc, BCMA_CC_NFLASH_CTL, NCTL_START | code);
for (i = 0; i < NFLASH_READY_RETRIES; i++) {
if (!(bcma_cc_read32(cc, BCMA_CC_NFLASH_CTL) & NCTL_START)) {
i = 0;
break;
}
}
if (i) {
pr_err("NFLASH control command not ready!\n");
return -EBUSY;
}
return 0;
}
static int bcm47xxnflash_ops_bcm4706_poll(struct bcma_drv_cc *cc)
{
int i;
for (i = 0; i < NFLASH_READY_RETRIES; i++) {
if (bcma_cc_read32(cc, BCMA_CC_NFLASH_CTL) & NCTL_READY) {
if (bcma_cc_read32(cc, BCMA_CC_NFLASH_CTL) &
BCMA_CC_NFLASH_CTL_ERR) {
pr_err("Error on polling\n");
return -EBUSY;
} else {
return 0;
}
}
}
pr_err("Polling timeout!\n");
return -EBUSY;
}
/**************************************************
* R/W
**************************************************/
static void bcm47xxnflash_ops_bcm4706_read(struct mtd_info *mtd, uint8_t *buf,
int len)
{
struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv;
struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv;
u32 ctlcode;
u32 *dest = (u32 *)buf;
int i;
int toread;
BUG_ON(b47n->curr_page_addr & ~nand_chip->pagemask);
/* Don't validate column using nand_chip->page_shift, it may be bigger
* when accessing OOB */
while (len) {
/* We can read maximum of 0x200 bytes at once */
toread = min(len, 0x200);
/* Set page and column */
bcma_cc_write32(b47n->cc, BCMA_CC_NFLASH_COL_ADDR,
b47n->curr_column);
bcma_cc_write32(b47n->cc, BCMA_CC_NFLASH_ROW_ADDR,
b47n->curr_page_addr);
/* Prepare to read */
ctlcode = NCTL_CSA | NCTL_CMD1W | 0x00040000 | 0x00020000 |
NCTL_CMD0;
ctlcode |= NAND_CMD_READSTART << 8;
if (bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc, ctlcode))
return;
if (bcm47xxnflash_ops_bcm4706_poll(b47n->cc))
return;
/* Eventually read some data :) */
for (i = 0; i < toread; i += 4, dest++) {
ctlcode = NCTL_CSA | 0x30000000 | NCTL_READ;
if (i == toread - 4) /* Last read goes without that */
ctlcode &= ~NCTL_CSA;
if (bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc,
ctlcode))
return;
*dest = bcma_cc_read32(b47n->cc, BCMA_CC_NFLASH_DATA);
}
b47n->curr_column += toread;
len -= toread;
}
}
static void bcm47xxnflash_ops_bcm4706_write(struct mtd_info *mtd,
const uint8_t *buf, int len)
{
struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv;
struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv;
struct bcma_drv_cc *cc = b47n->cc;
u32 ctlcode;
const u32 *data = (u32 *)buf;
int i;
BUG_ON(b47n->curr_page_addr & ~nand_chip->pagemask);
/* Don't validate column using nand_chip->page_shift, it may be bigger
* when accessing OOB */
for (i = 0; i < len; i += 4, data++) {
bcma_cc_write32(cc, BCMA_CC_NFLASH_DATA, *data);
ctlcode = NCTL_CSA | 0x30000000 | NCTL_WRITE;
if (i == len - 4) /* Last read goes without that */
ctlcode &= ~NCTL_CSA;
if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, ctlcode)) {
pr_err("%s ctl_cmd didn't work!\n", __func__);
return;
}
}
b47n->curr_column += len;
}
/**************************************************
* NAND chip ops
**************************************************/
/* Default nand_select_chip calls cmd_ctrl, which is not used in BCM4706 */
static void bcm47xxnflash_ops_bcm4706_select_chip(struct mtd_info *mtd,
int chip)
{
return;
}
/*
* Default nand_command and nand_command_lp don't match BCM4706 hardware layout.
* For example, reading chip id is performed in a non-standard way.
* Setting column and page is also handled differently, we use a special
* registers of ChipCommon core. Hacking cmd_ctrl to understand and convert
* standard commands would be much more complicated.
*/
static void bcm47xxnflash_ops_bcm4706_cmdfunc(struct mtd_info *mtd,
unsigned command, int column,
int page_addr)
{
struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv;
struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv;
struct bcma_drv_cc *cc = b47n->cc;
u32 ctlcode;
int i;
if (column != -1)
b47n->curr_column = column;
if (page_addr != -1)
b47n->curr_page_addr = page_addr;
switch (command) {
case NAND_CMD_RESET:
pr_warn("Chip reset not implemented yet\n");
break;
case NAND_CMD_READID:
ctlcode = NCTL_CSA | 0x01000000 | NCTL_CMD1W | NCTL_CMD0;
ctlcode |= NAND_CMD_READID;
if (bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc, ctlcode)) {
pr_err("READID error\n");
break;
}
/*
* Reading is specific, last one has to go without NCTL_CSA
* bit. We don't know how many reads NAND subsystem is going
* to perform, so cache everything.
*/
for (i = 0; i < ARRAY_SIZE(b47n->id_data); i++) {
ctlcode = NCTL_CSA | NCTL_READ;
if (i == ARRAY_SIZE(b47n->id_data) - 1)
ctlcode &= ~NCTL_CSA;
if (bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc,
ctlcode)) {
pr_err("READID error\n");
break;
}
b47n->id_data[i] =
bcma_cc_read32(b47n->cc, BCMA_CC_NFLASH_DATA)
& 0xFF;
}
break;
case NAND_CMD_STATUS:
ctlcode = NCTL_CSA | NCTL_CMD0 | NAND_CMD_STATUS;
if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, ctlcode))
pr_err("STATUS command error\n");
break;
case NAND_CMD_READ0:
break;
case NAND_CMD_READOOB:
if (page_addr != -1)
b47n->curr_column += mtd->writesize;
break;
case NAND_CMD_ERASE1:
bcma_cc_write32(cc, BCMA_CC_NFLASH_ROW_ADDR,
b47n->curr_page_addr);
ctlcode = 0x00040000 | NCTL_CMD1W | NCTL_CMD0 |
NAND_CMD_ERASE1 | (NAND_CMD_ERASE2 << 8);
if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, ctlcode))
pr_err("ERASE1 failed\n");
break;
case NAND_CMD_ERASE2:
break;
case NAND_CMD_SEQIN:
/* Set page and column */
bcma_cc_write32(cc, BCMA_CC_NFLASH_COL_ADDR,
b47n->curr_column);
bcma_cc_write32(cc, BCMA_CC_NFLASH_ROW_ADDR,
b47n->curr_page_addr);
/* Prepare to write */
ctlcode = 0x40000000 | 0x00040000 | 0x00020000 | 0x00010000;
ctlcode |= NAND_CMD_SEQIN;
if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, ctlcode))
pr_err("SEQIN failed\n");
break;
case NAND_CMD_PAGEPROG:
if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, 0x00010000 |
NAND_CMD_PAGEPROG))
pr_err("PAGEPROG failed\n");
if (bcm47xxnflash_ops_bcm4706_poll(cc))
pr_err("PAGEPROG not ready\n");
break;
default:
pr_err("Command 0x%X unsupported\n", command);
break;
}
b47n->curr_command = command;
}
static u8 bcm47xxnflash_ops_bcm4706_read_byte(struct mtd_info *mtd)
{
struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv;
struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv;
struct bcma_drv_cc *cc = b47n->cc;
u32 tmp = 0;
switch (b47n->curr_command) {
case NAND_CMD_READID:
if (b47n->curr_column >= ARRAY_SIZE(b47n->id_data)) {
pr_err("Requested invalid id_data: %d\n",
b47n->curr_column);
return 0;
}
return b47n->id_data[b47n->curr_column++];
case NAND_CMD_STATUS:
if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, NCTL_READ))
return 0;
return bcma_cc_read32(cc, BCMA_CC_NFLASH_DATA) & 0xff;
case NAND_CMD_READOOB:
bcm47xxnflash_ops_bcm4706_read(mtd, (u8 *)&tmp, 4);
return tmp & 0xFF;
}
pr_err("Invalid command for byte read: 0x%X\n", b47n->curr_command);
return 0;
}
static void bcm47xxnflash_ops_bcm4706_read_buf(struct mtd_info *mtd,
uint8_t *buf, int len)
{
struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv;
struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv;
switch (b47n->curr_command) {
case NAND_CMD_READ0:
case NAND_CMD_READOOB:
bcm47xxnflash_ops_bcm4706_read(mtd, buf, len);
return;
}
pr_err("Invalid command for buf read: 0x%X\n", b47n->curr_command);
}
static void bcm47xxnflash_ops_bcm4706_write_buf(struct mtd_info *mtd,
const uint8_t *buf, int len)
{
struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv;
struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv;
switch (b47n->curr_command) {
case NAND_CMD_SEQIN:
bcm47xxnflash_ops_bcm4706_write(mtd, buf, len);
return;
}
pr_err("Invalid command for buf write: 0x%X\n", b47n->curr_command);
}
/**************************************************
* Init
**************************************************/
int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n)
{
int err;
u32 freq;
u16 clock;
u8 w0, w1, w2, w3, w4;
unsigned long chipsize; /* MiB */
u8 tbits, col_bits, col_size, row_bits, row_bsize;
u32 val;
b47n->nand_chip.select_chip = bcm47xxnflash_ops_bcm4706_select_chip;
b47n->nand_chip.cmdfunc = bcm47xxnflash_ops_bcm4706_cmdfunc;
b47n->nand_chip.read_byte = bcm47xxnflash_ops_bcm4706_read_byte;
b47n->nand_chip.read_buf = bcm47xxnflash_ops_bcm4706_read_buf;
b47n->nand_chip.write_buf = bcm47xxnflash_ops_bcm4706_write_buf;
b47n->nand_chip.bbt_options = NAND_BBT_USE_FLASH;
b47n->nand_chip.ecc.mode = NAND_ECC_NONE; /* TODO: implement ECC */
/* Enable NAND flash access */
bcma_cc_set32(b47n->cc, BCMA_CC_4706_FLASHSCFG,
BCMA_CC_4706_FLASHSCFG_NF1);
/* Configure wait counters */
if (b47n->cc->status & BCMA_CC_CHIPST_4706_PKG_OPTION) {
freq = 100000000;
} else {
freq = bcma_chipco_pll_read(b47n->cc, 4);
freq = (freq * 0xFFF) >> 3;
freq = (freq * 25000000) >> 3;
}
clock = freq / 1000000;
w0 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(15, clock);
w1 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(20, clock);
w2 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(10, clock);
w3 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(10, clock);
w4 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(100, clock);
bcma_cc_write32(b47n->cc, BCMA_CC_NFLASH_WAITCNT0,
(w4 << 24 | w3 << 18 | w2 << 12 | w1 << 6 | w0));
/* Scan NAND */
err = nand_scan(&b47n->mtd, 1);
if (err) {
pr_err("Could not scan NAND flash: %d\n", err);
goto exit;
}
/* Configure FLASH */
chipsize = b47n->nand_chip.chipsize >> 20;
tbits = ffs(chipsize); /* find first bit set */
if (!tbits || tbits != fls(chipsize)) {
pr_err("Invalid flash size: 0x%lX\n", chipsize);
err = -ENOTSUPP;
goto exit;
}
tbits += 19; /* Broadcom increases *index* by 20, we increase *pos* */
col_bits = b47n->nand_chip.page_shift + 1;
col_size = (col_bits + 7) / 8;
row_bits = tbits - col_bits + 1;
row_bsize = (row_bits + 7) / 8;
val = ((row_bsize - 1) << 6) | ((col_size - 1) << 4) | 2;
bcma_cc_write32(b47n->cc, BCMA_CC_NFLASH_CONF, val);
exit:
if (err)
bcma_cc_mask32(b47n->cc, BCMA_CC_4706_FLASHSCFG,
~BCMA_CC_4706_FLASHSCFG_NF1);
return err;
}

View File

@ -658,7 +658,7 @@ static int bf5xx_nand_hw_init(struct bf5xx_nand_info *info)
/*
* Device management interface
*/
static int __devinit bf5xx_nand_add_partition(struct bf5xx_nand_info *info)
static int bf5xx_nand_add_partition(struct bf5xx_nand_info *info)
{
struct mtd_info *mtd = &info->mtd;
struct mtd_partition *parts = info->platform->partitions;
@ -667,7 +667,7 @@ static int __devinit bf5xx_nand_add_partition(struct bf5xx_nand_info *info)
return mtd_device_register(mtd, parts, nr);
}
static int __devexit bf5xx_nand_remove(struct platform_device *pdev)
static int bf5xx_nand_remove(struct platform_device *pdev)
{
struct bf5xx_nand_info *info = to_nand_info(pdev);
@ -725,7 +725,7 @@ static int bf5xx_nand_scan(struct mtd_info *mtd)
* it can allocate all necessary resources then calls the
* nand layer to look for devices
*/
static int __devinit bf5xx_nand_probe(struct platform_device *pdev)
static int bf5xx_nand_probe(struct platform_device *pdev)
{
struct bf5xx_nand_platform *plat = to_nand_plat(pdev);
struct bf5xx_nand_info *info = NULL;
@ -865,7 +865,7 @@ static int bf5xx_nand_resume(struct platform_device *dev)
/* driver device registration */
static struct platform_driver bf5xx_nand_driver = {
.probe = bf5xx_nand_probe,
.remove = __devexit_p(bf5xx_nand_remove),
.remove = bf5xx_nand_remove,
.suspend = bf5xx_nand_suspend,
.resume = bf5xx_nand_resume,
.driver = {

View File

@ -585,7 +585,7 @@ static int cafe_nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
}
/* F_2[X]/(X**6+X+1) */
static unsigned short __devinit gf64_mul(u8 a, u8 b)
static unsigned short gf64_mul(u8 a, u8 b)
{
u8 c;
unsigned int i;
@ -604,7 +604,7 @@ static unsigned short __devinit gf64_mul(u8 a, u8 b)
}
/* F_64[X]/(X**2+X+A**-1) with A the generator of F_64[X] */
static u16 __devinit gf4096_mul(u16 a, u16 b)
static u16 gf4096_mul(u16 a, u16 b)
{
u8 ah, al, bh, bl, ch, cl;
@ -619,14 +619,14 @@ static u16 __devinit gf4096_mul(u16 a, u16 b)
return (ch << 6) ^ cl;
}
static int __devinit cafe_mul(int x)
static int cafe_mul(int x)
{
if (x == 0)
return 1;
return gf4096_mul(x, 0xe01);
}
static int __devinit cafe_nand_probe(struct pci_dev *pdev,
static int cafe_nand_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
struct mtd_info *mtd;
@ -821,7 +821,7 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev,
return err;
}
static void __devexit cafe_nand_remove(struct pci_dev *pdev)
static void cafe_nand_remove(struct pci_dev *pdev)
{
struct mtd_info *mtd = pci_get_drvdata(pdev);
struct cafe_priv *cafe = mtd->priv;
@ -887,7 +887,7 @@ static struct pci_driver cafe_nand_pci_driver = {
.name = "CAFÉ NAND",
.id_table = cafe_nand_tbl,
.probe = cafe_nand_probe,
.remove = __devexit_p(cafe_nand_remove),
.remove = cafe_nand_remove,
.resume = cafe_nand_resume,
};

View File

@ -237,6 +237,7 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr)
this->ecc.hwctl = cs_enable_hwecc;
this->ecc.calculate = cs_calculate_ecc;
this->ecc.correct = nand_correct_data;
this->ecc.strength = 1;
/* Enable the following for a flash based bad block table */
this->bbt_options = NAND_BBT_USE_FLASH;
@ -247,8 +248,6 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr)
goto out_ior;
}
this->ecc.strength = 1;
new_mtd->name = kasprintf(GFP_KERNEL, "cs553x_nand_cs%d", cs);
cs553x_mtd[cs] = new_mtd;

View File

@ -821,9 +821,16 @@ syndrome_done:
if (ret < 0)
goto err_scan;
ret = mtd_device_parse_register(&info->mtd, NULL, NULL, pdata->parts,
pdata->nr_parts);
if (pdata->parts)
ret = mtd_device_parse_register(&info->mtd, NULL, NULL,
pdata->parts, pdata->nr_parts);
else {
struct mtd_part_parser_data ppdata;
ppdata.of_node = pdev->dev.of_node;
ret = mtd_device_parse_register(&info->mtd, NULL, &ppdata,
NULL, 0);
}
if (ret < 0)
goto err_scan;

View File

@ -16,14 +16,12 @@
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/wait.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/pci.h>
#include <linux/mtd/mtd.h>
#include <linux/module.h>
@ -89,13 +87,6 @@ MODULE_PARM_DESC(onfi_timing_mode, "Overrides default ONFI setting."
* format the bank into the proper bits for the controller */
#define BANK(x) ((x) << 24)
/* List of platforms this NAND controller has be integrated into */
static const struct pci_device_id denali_pci_ids[] = {
{ PCI_VDEVICE(INTEL, 0x0701), INTEL_CE4100 },
{ PCI_VDEVICE(INTEL, 0x0809), INTEL_MRST },
{ /* end: all zeroes */ }
};
/* forward declarations */
static void clear_interrupts(struct denali_nand_info *denali);
static uint32_t wait_for_irq(struct denali_nand_info *denali,
@ -699,7 +690,7 @@ static uint32_t wait_for_irq(struct denali_nand_info *denali, uint32_t irq_mask)
if (comp_res == 0) {
/* timeout */
printk(KERN_ERR "timeout occurred, status = 0x%x, mask = 0x%x\n",
pr_err("timeout occurred, status = 0x%x, mask = 0x%x\n",
intr_status, irq_mask);
intr_status = 0;
@ -1305,8 +1296,7 @@ static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col,
/* TODO: Read OOB data */
break;
default:
printk(KERN_ERR ": unsupported command"
" received 0x%x\n", cmd);
pr_err(": unsupported command received 0x%x\n", cmd);
break;
}
}
@ -1425,107 +1415,48 @@ void denali_drv_init(struct denali_nand_info *denali)
denali->irq_status = 0;
}
/* driver entry point */
static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
int denali_init(struct denali_nand_info *denali)
{
int ret = -ENODEV;
resource_size_t csr_base, mem_base;
unsigned long csr_len, mem_len;
struct denali_nand_info *denali;
int ret;
denali = kzalloc(sizeof(*denali), GFP_KERNEL);
if (!denali)
return -ENOMEM;
ret = pci_enable_device(dev);
if (ret) {
printk(KERN_ERR "Spectra: pci_enable_device failed.\n");
goto failed_alloc_memery;
}
if (id->driver_data == INTEL_CE4100) {
if (denali->platform == INTEL_CE4100) {
/* Due to a silicon limitation, we can only support
* ONFI timing mode 1 and below.
*/
if (onfi_timing_mode < -1 || onfi_timing_mode > 1) {
printk(KERN_ERR "Intel CE4100 only supports"
" ONFI timing mode 1 or below\n");
ret = -EINVAL;
goto failed_enable_dev;
}
denali->platform = INTEL_CE4100;
mem_base = pci_resource_start(dev, 0);
mem_len = pci_resource_len(dev, 1);
csr_base = pci_resource_start(dev, 1);
csr_len = pci_resource_len(dev, 1);
} else {
denali->platform = INTEL_MRST;
csr_base = pci_resource_start(dev, 0);
csr_len = pci_resource_len(dev, 0);
mem_base = pci_resource_start(dev, 1);
mem_len = pci_resource_len(dev, 1);
if (!mem_len) {
mem_base = csr_base + csr_len;
mem_len = csr_len;
pr_err("Intel CE4100 only supports ONFI timing mode 1 or below\n");
return -EINVAL;
}
}
/* Is 32-bit DMA supported? */
ret = dma_set_mask(&dev->dev, DMA_BIT_MASK(32));
ret = dma_set_mask(denali->dev, DMA_BIT_MASK(32));
if (ret) {
printk(KERN_ERR "Spectra: no usable DMA configuration\n");
goto failed_enable_dev;
pr_err("Spectra: no usable DMA configuration\n");
return ret;
}
denali->buf.dma_buf = dma_map_single(&dev->dev, denali->buf.buf,
denali->buf.dma_buf = dma_map_single(denali->dev, denali->buf.buf,
DENALI_BUF_SIZE,
DMA_BIDIRECTIONAL);
if (dma_mapping_error(&dev->dev, denali->buf.dma_buf)) {
dev_err(&dev->dev, "Spectra: failed to map DMA buffer\n");
goto failed_enable_dev;
if (dma_mapping_error(denali->dev, denali->buf.dma_buf)) {
dev_err(denali->dev, "Spectra: failed to map DMA buffer\n");
return -EIO;
}
pci_set_master(dev);
denali->dev = &dev->dev;
denali->mtd.dev.parent = &dev->dev;
ret = pci_request_regions(dev, DENALI_NAND_NAME);
if (ret) {
printk(KERN_ERR "Spectra: Unable to request memory regions\n");
goto failed_dma_map;
}
denali->flash_reg = ioremap_nocache(csr_base, csr_len);
if (!denali->flash_reg) {
printk(KERN_ERR "Spectra: Unable to remap memory region\n");
ret = -ENOMEM;
goto failed_req_regions;
}
denali->flash_mem = ioremap_nocache(mem_base, mem_len);
if (!denali->flash_mem) {
printk(KERN_ERR "Spectra: ioremap_nocache failed!");
ret = -ENOMEM;
goto failed_remap_reg;
}
denali->mtd.dev.parent = denali->dev;
denali_hw_init(denali);
denali_drv_init(denali);
/* denali_isr register is done after all the hardware
* initilization is finished*/
if (request_irq(dev->irq, denali_isr, IRQF_SHARED,
if (request_irq(denali->irq, denali_isr, IRQF_SHARED,
DENALI_NAND_NAME, denali)) {
printk(KERN_ERR "Spectra: Unable to allocate IRQ\n");
ret = -ENODEV;
goto failed_remap_mem;
pr_err("Spectra: Unable to allocate IRQ\n");
return -ENODEV;
}
/* now that our ISR is registered, we can enable interrupts */
denali_set_intr_modes(denali, true);
pci_set_drvdata(dev, denali);
denali->mtd.name = "denali-nand";
denali->mtd.owner = THIS_MODULE;
denali->mtd.priv = &denali->nand;
@ -1549,8 +1480,7 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
*/
if (denali->mtd.writesize > NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE) {
ret = -ENODEV;
printk(KERN_ERR "Spectra: device size not supported by this "
"version of MTD.");
pr_err("Spectra: device size not supported by this version of MTD.");
goto failed_req_irq;
}
@ -1602,8 +1532,8 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
} else if (denali->mtd.oobsize < (denali->bbtskipbytes +
ECC_8BITS * (denali->mtd.writesize /
ECC_SECTOR_SIZE))) {
printk(KERN_ERR "Your NAND chip OOB is not large enough to"
" contain 8bit ECC correction codes");
pr_err("Your NAND chip OOB is not large enough to \
contain 8bit ECC correction codes");
goto failed_req_irq;
} else {
denali->nand.ecc.strength = 8;
@ -1655,56 +1585,24 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
ret = mtd_device_register(&denali->mtd, NULL, 0);
if (ret) {
dev_err(&dev->dev, "Spectra: Failed to register MTD: %d\n",
dev_err(denali->dev, "Spectra: Failed to register MTD: %d\n",
ret);
goto failed_req_irq;
}
return 0;
failed_req_irq:
denali_irq_cleanup(dev->irq, denali);
failed_remap_mem:
iounmap(denali->flash_mem);
failed_remap_reg:
iounmap(denali->flash_reg);
failed_req_regions:
pci_release_regions(dev);
failed_dma_map:
dma_unmap_single(&dev->dev, denali->buf.dma_buf, DENALI_BUF_SIZE,
DMA_BIDIRECTIONAL);
failed_enable_dev:
pci_disable_device(dev);
failed_alloc_memery:
kfree(denali);
denali_irq_cleanup(denali->irq, denali);
return ret;
}
EXPORT_SYMBOL(denali_init);
/* driver exit point */
static void denali_pci_remove(struct pci_dev *dev)
void denali_remove(struct denali_nand_info *denali)
{
struct denali_nand_info *denali = pci_get_drvdata(dev);
nand_release(&denali->mtd);
denali_irq_cleanup(dev->irq, denali);
iounmap(denali->flash_reg);
iounmap(denali->flash_mem);
pci_release_regions(dev);
pci_disable_device(dev);
dma_unmap_single(&dev->dev, denali->buf.dma_buf, DENALI_BUF_SIZE,
DMA_BIDIRECTIONAL);
pci_set_drvdata(dev, NULL);
kfree(denali);
denali_irq_cleanup(denali->irq, denali);
dma_unmap_single(denali->dev, denali->buf.dma_buf, DENALI_BUF_SIZE,
DMA_BIDIRECTIONAL);
}
MODULE_DEVICE_TABLE(pci, denali_pci_ids);
static struct pci_driver denali_pci_driver = {
.name = DENALI_NAND_NAME,
.id_table = denali_pci_ids,
.probe = denali_pci_probe,
.remove = denali_pci_remove,
};
module_pci_driver(denali_pci_driver);
EXPORT_SYMBOL(denali_remove);

View File

@ -466,6 +466,7 @@ struct nand_buf {
#define INTEL_CE4100 1
#define INTEL_MRST 2
#define DT 3
struct denali_nand_info {
struct mtd_info mtd;
@ -487,6 +488,7 @@ struct denali_nand_info {
uint32_t irq_status;
int irq_debug_array[32];
int idx;
int irq;
uint32_t devnum; /* represent how many nands connected */
uint32_t fwblks; /* represent how many blocks FW used */
@ -496,4 +498,7 @@ struct denali_nand_info {
uint32_t max_banks;
};
extern int denali_init(struct denali_nand_info *denali);
extern void denali_remove(struct denali_nand_info *denali);
#endif /*_LLD_NAND_*/

View File

@ -0,0 +1,167 @@
/*
* NAND Flash Controller Device Driver for DT
*
* Copyright © 2011, Picochip.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*/
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/slab.h>
#include "denali.h"
struct denali_dt {
struct denali_nand_info denali;
struct clk *clk;
};
static void __iomem *request_and_map(struct device *dev,
const struct resource *res)
{
void __iomem *ptr;
if (!devm_request_mem_region(dev, res->start, resource_size(res),
"denali-dt")) {
dev_err(dev, "unable to request %s\n", res->name);
return NULL;
}
ptr = devm_ioremap_nocache(dev, res->start, resource_size(res));
if (!res)
dev_err(dev, "ioremap_nocache of %s failed!", res->name);
return ptr;
}
static const struct of_device_id denali_nand_dt_ids[] = {
{ .compatible = "denali,denali-nand-dt" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, denali_nand_dt_ids);
static u64 denali_dma_mask;
static int denali_dt_probe(struct platform_device *ofdev)
{
struct resource *denali_reg, *nand_data;
struct denali_dt *dt;
struct denali_nand_info *denali;
int ret;
const struct of_device_id *of_id;
of_id = of_match_device(denali_nand_dt_ids, &ofdev->dev);
if (of_id) {
ofdev->id_entry = of_id->data;
} else {
pr_err("Failed to find the right device id.\n");
return -ENOMEM;
}
dt = devm_kzalloc(&ofdev->dev, sizeof(*dt), GFP_KERNEL);
if (!dt)
return -ENOMEM;
denali = &dt->denali;
denali_reg = platform_get_resource_byname(ofdev, IORESOURCE_MEM, "denali_reg");
nand_data = platform_get_resource_byname(ofdev, IORESOURCE_MEM, "nand_data");
if (!denali_reg || !nand_data) {
dev_err(&ofdev->dev, "resources not completely defined\n");
return -EINVAL;
}
denali->platform = DT;
denali->dev = &ofdev->dev;
denali->irq = platform_get_irq(ofdev, 0);
if (denali->irq < 0) {
dev_err(&ofdev->dev, "no irq defined\n");
return -ENXIO;
}
denali->flash_reg = request_and_map(&ofdev->dev, denali_reg);
if (!denali->flash_reg)
return -ENOMEM;
denali->flash_mem = request_and_map(&ofdev->dev, nand_data);
if (!denali->flash_mem)
return -ENOMEM;
if (!of_property_read_u32(ofdev->dev.of_node,
"dma-mask", (u32 *)&denali_dma_mask)) {
denali->dev->dma_mask = &denali_dma_mask;
} else {
denali->dev->dma_mask = NULL;
}
dt->clk = clk_get(&ofdev->dev, NULL);
if (IS_ERR(dt->clk)) {
dev_err(&ofdev->dev, "no clk available\n");
return PTR_ERR(dt->clk);
}
clk_prepare_enable(dt->clk);
ret = denali_init(denali);
if (ret)
goto out_disable_clk;
platform_set_drvdata(ofdev, dt);
return 0;
out_disable_clk:
clk_disable_unprepare(dt->clk);
clk_put(dt->clk);
return ret;
}
static int denali_dt_remove(struct platform_device *ofdev)
{
struct denali_dt *dt = platform_get_drvdata(ofdev);
denali_remove(&dt->denali);
clk_disable(dt->clk);
clk_put(dt->clk);
return 0;
}
static struct platform_driver denali_dt_driver = {
.probe = denali_dt_probe,
.remove = denali_dt_remove,
.driver = {
.name = "denali-nand-dt",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(denali_nand_dt_ids),
},
};
static int __init denali_init_dt(void)
{
return platform_driver_register(&denali_dt_driver);
}
module_init(denali_init_dt);
static void __exit denali_exit_dt(void)
{
platform_driver_unregister(&denali_dt_driver);
}
module_exit(denali_exit_dt);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jamie Iles");
MODULE_DESCRIPTION("DT driver for Denali NAND controller");

View File

@ -0,0 +1,144 @@
/*
* NAND Flash Controller Device Driver
* Copyright © 2009-2010, Intel Corporation and its suppliers.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include "denali.h"
#define DENALI_NAND_NAME "denali-nand-pci"
/* List of platforms this NAND controller has be integrated into */
static DEFINE_PCI_DEVICE_TABLE(denali_pci_ids) = {
{ PCI_VDEVICE(INTEL, 0x0701), INTEL_CE4100 },
{ PCI_VDEVICE(INTEL, 0x0809), INTEL_MRST },
{ /* end: all zeroes */ }
};
MODULE_DEVICE_TABLE(pci, denali_pci_ids);
static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
int ret = -ENODEV;
resource_size_t csr_base, mem_base;
unsigned long csr_len, mem_len;
struct denali_nand_info *denali;
denali = kzalloc(sizeof(*denali), GFP_KERNEL);
if (!denali)
return -ENOMEM;
ret = pci_enable_device(dev);
if (ret) {
pr_err("Spectra: pci_enable_device failed.\n");
goto failed_alloc_memery;
}
if (id->driver_data == INTEL_CE4100) {
denali->platform = INTEL_CE4100;
mem_base = pci_resource_start(dev, 0);
mem_len = pci_resource_len(dev, 1);
csr_base = pci_resource_start(dev, 1);
csr_len = pci_resource_len(dev, 1);
} else {
denali->platform = INTEL_MRST;
csr_base = pci_resource_start(dev, 0);
csr_len = pci_resource_len(dev, 0);
mem_base = pci_resource_start(dev, 1);
mem_len = pci_resource_len(dev, 1);
if (!mem_len) {
mem_base = csr_base + csr_len;
mem_len = csr_len;
}
}
pci_set_master(dev);
denali->dev = &dev->dev;
denali->irq = dev->irq;
ret = pci_request_regions(dev, DENALI_NAND_NAME);
if (ret) {
pr_err("Spectra: Unable to request memory regions\n");
goto failed_enable_dev;
}
denali->flash_reg = ioremap_nocache(csr_base, csr_len);
if (!denali->flash_reg) {
pr_err("Spectra: Unable to remap memory region\n");
ret = -ENOMEM;
goto failed_req_regions;
}
denali->flash_mem = ioremap_nocache(mem_base, mem_len);
if (!denali->flash_mem) {
pr_err("Spectra: ioremap_nocache failed!");
ret = -ENOMEM;
goto failed_remap_reg;
}
ret = denali_init(denali);
if (ret)
goto failed_remap_mem;
pci_set_drvdata(dev, denali);
return 0;
failed_remap_mem:
iounmap(denali->flash_mem);
failed_remap_reg:
iounmap(denali->flash_reg);
failed_req_regions:
pci_release_regions(dev);
failed_enable_dev:
pci_disable_device(dev);
failed_alloc_memery:
kfree(denali);
return ret;
}
/* driver exit point */
static void denali_pci_remove(struct pci_dev *dev)
{
struct denali_nand_info *denali = pci_get_drvdata(dev);
denali_remove(denali);
iounmap(denali->flash_reg);
iounmap(denali->flash_mem);
pci_release_regions(dev);
pci_disable_device(dev);
pci_set_drvdata(dev, NULL);
kfree(denali);
}
static struct pci_driver denali_pci_driver = {
.name = DENALI_NAND_NAME,
.id_table = denali_pci_ids,
.probe = denali_pci_probe,
.remove = denali_pci_remove,
};
static int denali_init_pci(void)
{
pr_info("Spectra MTD driver built on %s @ %s\n", __DATE__, __TIME__);
return pci_register_driver(&denali_pci_driver);
}
module_init(denali_init_pci);
static void denali_exit_pci(void)
{
pci_unregister_driver(&denali_pci_driver);
}
module_exit(denali_exit_pci);

View File

@ -53,8 +53,6 @@ static unsigned long __initdata doc_locations[] = {
0xe0000, 0xe2000, 0xe4000, 0xe6000,
0xe8000, 0xea000, 0xec000, 0xee000,
#endif /* CONFIG_MTD_DOCPROBE_HIGH */
#else
#warning Unknown architecture for DiskOnChip. No default probe locations defined
#endif
0xffffffff };

View File

@ -45,6 +45,25 @@
#include <linux/bch.h>
#include <linux/bitrev.h>
/*
* In "reliable mode" consecutive 2k pages are used in parallel (in some
* fashion) to store the same data. The data can be read back from the
* even-numbered pages in the normal manner; odd-numbered pages will appear to
* contain junk. Systems that boot from the docg4 typically write the secondary
* program loader (SPL) code in this mode. The SPL is loaded by the initial
* program loader (IPL, stored in the docg4's 2k NOR-like region that is mapped
* to the reset vector address). This module parameter enables you to use this
* driver to write the SPL. When in this mode, no more than 2k of data can be
* written at a time, because the addresses do not increment in the normal
* manner, and the starting offset must be within an even-numbered 2k region;
* i.e., invalid starting offsets are 0x800, 0xa00, 0xc00, 0xe00, 0x1800,
* 0x1a00, ... Reliable mode is a special case and should not be used unless
* you know what you're doing.
*/
static bool reliable_mode;
module_param(reliable_mode, bool, 0);
MODULE_PARM_DESC(reliable_mode, "pages are programmed in reliable mode");
/*
* You'll want to ignore badblocks if you're reading a partition that contains
* data written by the TrueFFS library (i.e., by PalmOS, Windows, etc), since
@ -113,6 +132,7 @@ struct docg4_priv {
#define DOCG4_SEQ_PAGEWRITE 0x16
#define DOCG4_SEQ_PAGEPROG 0x1e
#define DOCG4_SEQ_BLOCKERASE 0x24
#define DOCG4_SEQ_SETMODE 0x45
/* DOC_FLASHCOMMAND register commands */
#define DOCG4_CMD_PAGE_READ 0x00
@ -122,6 +142,8 @@ struct docg4_priv {
#define DOC_CMD_PROG_BLOCK_ADDR 0x60
#define DOCG4_CMD_PAGEWRITE 0x80
#define DOC_CMD_PROG_CYCLE2 0x10
#define DOCG4_CMD_FAST_MODE 0xa3 /* functionality guessed */
#define DOC_CMD_RELIABLE_MODE 0x22
#define DOC_CMD_RESET 0xff
/* DOC_POWERMODE register bits */
@ -190,17 +212,20 @@ struct docg4_priv {
#define DOCG4_T 4 /* BCH alg corrects up to 4 bit errors */
#define DOCG4_FACTORY_BBT_PAGE 16 /* page where read-only factory bbt lives */
#define DOCG4_REDUNDANT_BBT_PAGE 24 /* page where redundant factory bbt lives */
/*
* Oob bytes 0 - 6 are available to the user.
* Byte 7 is hamming ecc for first 7 bytes. Bytes 8 - 14 are hw-generated ecc.
* Bytes 0, 1 are used as badblock marker.
* Bytes 2 - 6 are available to the user.
* Byte 7 is hamming ecc for first 7 oob bytes only.
* Bytes 8 - 14 are hw-generated ecc covering entire page + oob bytes 0 - 14.
* Byte 15 (the last) is used by the driver as a "page written" flag.
*/
static struct nand_ecclayout docg4_oobinfo = {
.eccbytes = 9,
.eccpos = {7, 8, 9, 10, 11, 12, 13, 14, 15},
.oobavail = 7,
.oobfree = { {0, 7} }
.oobavail = 5,
.oobfree = { {.offset = 2, .length = 5} }
};
/*
@ -611,6 +636,14 @@ static void write_page_prologue(struct mtd_info *mtd, uint32_t docg4_addr)
dev_dbg(doc->dev,
"docg4: %s: g4 addr: %x\n", __func__, docg4_addr);
sequence_reset(mtd);
if (unlikely(reliable_mode)) {
writew(DOCG4_SEQ_SETMODE, docptr + DOC_FLASHSEQUENCE);
writew(DOCG4_CMD_FAST_MODE, docptr + DOC_FLASHCOMMAND);
writew(DOC_CMD_RELIABLE_MODE, docptr + DOC_FLASHCOMMAND);
write_nop(docptr);
}
writew(DOCG4_SEQ_PAGEWRITE, docptr + DOC_FLASHSEQUENCE);
writew(DOCG4_CMD_PAGEWRITE, docptr + DOC_FLASHCOMMAND);
write_nop(docptr);
@ -691,6 +724,15 @@ static void docg4_command(struct mtd_info *mtd, unsigned command, int column,
break;
case NAND_CMD_SEQIN:
if (unlikely(reliable_mode)) {
uint16_t g4_page = g4_addr >> 16;
/* writes to odd-numbered 2k pages are invalid */
if (g4_page & 0x01)
dev_warn(doc->dev,
"invalid reliable mode address\n");
}
write_page_prologue(mtd, g4_addr);
/* hack for deferred write of oob bytes */
@ -979,16 +1021,15 @@ static int __init read_factory_bbt(struct mtd_info *mtd)
struct docg4_priv *doc = nand->priv;
uint32_t g4_addr = mtd_to_docg4_address(DOCG4_FACTORY_BBT_PAGE, 0);
uint8_t *buf;
int i, block, status;
int i, block;
__u32 eccfailed_stats = mtd->ecc_stats.failed;
buf = kzalloc(DOCG4_PAGE_SIZE, GFP_KERNEL);
if (buf == NULL)
return -ENOMEM;
read_page_prologue(mtd, g4_addr);
status = docg4_read_page(mtd, nand, buf, 0, DOCG4_FACTORY_BBT_PAGE);
if (status)
goto exit;
docg4_read_page(mtd, nand, buf, 0, DOCG4_FACTORY_BBT_PAGE);
/*
* If no memory-based bbt was created, exit. This will happen if module
@ -1000,6 +1041,20 @@ static int __init read_factory_bbt(struct mtd_info *mtd)
if (nand->bbt == NULL) /* no memory-based bbt */
goto exit;
if (mtd->ecc_stats.failed > eccfailed_stats) {
/*
* Whoops, an ecc failure ocurred reading the factory bbt.
* It is stored redundantly, so we get another chance.
*/
eccfailed_stats = mtd->ecc_stats.failed;
docg4_read_page(mtd, nand, buf, 0, DOCG4_REDUNDANT_BBT_PAGE);
if (mtd->ecc_stats.failed > eccfailed_stats) {
dev_warn(doc->dev,
"The factory bbt could not be read!\n");
goto exit;
}
}
/*
* Parse factory bbt and update memory-based bbt. Factory bbt format is
* simple: one bit per block, block numbers increase left to right (msb
@ -1019,7 +1074,7 @@ static int __init read_factory_bbt(struct mtd_info *mtd)
}
exit:
kfree(buf);
return status;
return 0;
}
static int docg4_block_markbad(struct mtd_info *mtd, loff_t ofs)

View File

@ -108,20 +108,6 @@ static struct nand_ecclayout fsl_elbc_oob_lp_eccm1 = {
.oobfree = { {1, 7}, {11, 13}, {27, 13}, {43, 13}, {59, 5} },
};
/*
* fsl_elbc_oob_lp_eccm* specify that LP NAND's OOB free area starts at offset
* 1, so we have to adjust bad block pattern. This pattern should be used for
* x8 chips only. So far hardware does not support x16 chips anyway.
*/
static u8 scan_ff_pattern[] = { 0xff, };
static struct nand_bbt_descr largepage_memorybased = {
.options = 0,
.offs = 0,
.len = 1,
.pattern = scan_ff_pattern,
};
/*
* ELBC may use HW ECC, so that OOB offsets, that NAND core uses for bbt,
* interfere with ECC positions, that's why we implement our own descriptors.
@ -699,7 +685,6 @@ static int fsl_elbc_chip_init_tail(struct mtd_info *mtd)
chip->ecc.layout = (priv->fmr & FMR_ECCM) ?
&fsl_elbc_oob_lp_eccm1 :
&fsl_elbc_oob_lp_eccm0;
chip->badblock_pattern = &largepage_memorybased;
}
} else {
dev_err(priv->dev,
@ -814,7 +799,7 @@ static int fsl_elbc_chip_remove(struct fsl_elbc_mtd *priv)
static DEFINE_MUTEX(fsl_elbc_nand_mutex);
static int __devinit fsl_elbc_nand_probe(struct platform_device *pdev)
static int fsl_elbc_nand_probe(struct platform_device *pdev)
{
struct fsl_lbc_regs __iomem *lbc;
struct fsl_elbc_mtd *priv;

View File

@ -389,7 +389,7 @@ static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command,
timing = IFC_FIR_OP_RBCD;
out_be32(&ifc->ifc_nand.nand_fir0,
(IFC_FIR_OP_CMD0 << IFC_NAND_FIR0_OP0_SHIFT) |
(IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
(IFC_FIR_OP_UA << IFC_NAND_FIR0_OP1_SHIFT) |
(timing << IFC_NAND_FIR0_OP2_SHIFT));
out_be32(&ifc->ifc_nand.nand_fcr0,
@ -754,7 +754,7 @@ static void fsl_ifc_sram_init(struct fsl_ifc_mtd *priv)
/* READID */
out_be32(&ifc->ifc_nand.nand_fir0,
(IFC_FIR_OP_CMD0 << IFC_NAND_FIR0_OP0_SHIFT) |
(IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
(IFC_FIR_OP_UA << IFC_NAND_FIR0_OP1_SHIFT) |
(IFC_FIR_OP_RB << IFC_NAND_FIR0_OP2_SHIFT));
out_be32(&ifc->ifc_nand.nand_fcr0,
@ -922,7 +922,7 @@ static int match_bank(struct fsl_ifc_regs __iomem *ifc, int bank,
static DEFINE_MUTEX(fsl_ifc_nand_mutex);
static int __devinit fsl_ifc_nand_probe(struct platform_device *dev)
static int fsl_ifc_nand_probe(struct platform_device *dev)
{
struct fsl_ifc_regs __iomem *ifc;
struct fsl_ifc_mtd *priv;

View File

@ -152,7 +152,7 @@ static void fun_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
fun_wait_rnb(fun);
}
static int __devinit fun_chip_init(struct fsl_upm_nand *fun,
static int fun_chip_init(struct fsl_upm_nand *fun,
const struct device_node *upm_np,
const struct resource *io_res)
{
@ -201,7 +201,7 @@ err:
return ret;
}
static int __devinit fun_probe(struct platform_device *ofdev)
static int fun_probe(struct platform_device *ofdev)
{
struct fsl_upm_nand *fun;
struct resource io_res;
@ -318,7 +318,7 @@ err1:
return ret;
}
static int __devexit fun_remove(struct platform_device *ofdev)
static int fun_remove(struct platform_device *ofdev)
{
struct fsl_upm_nand *fun = dev_get_drvdata(&ofdev->dev);
int i;
@ -350,7 +350,7 @@ static struct platform_driver of_fun_driver = {
.of_match_table = of_fun_match,
},
.probe = fun_probe,
.remove = __devexit_p(fun_remove),
.remove = fun_remove,
};
module_platform_driver(of_fun_driver);

View File

@ -361,7 +361,7 @@ static void fsmc_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
struct nand_chip *this = mtd->priv;
struct fsmc_nand_data *host = container_of(mtd,
struct fsmc_nand_data, mtd);
void *__iomem *regs = host->regs_va;
void __iomem *regs = host->regs_va;
unsigned int bank = host->bank;
if (ctrl & NAND_CTRL_CHANGE) {
@ -383,13 +383,13 @@ static void fsmc_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
pc |= FSMC_ENABLE;
else
pc &= ~FSMC_ENABLE;
writel(pc, FSMC_NAND_REG(regs, bank, PC));
writel_relaxed(pc, FSMC_NAND_REG(regs, bank, PC));
}
mb();
if (cmd != NAND_CMD_NONE)
writeb(cmd, this->IO_ADDR_W);
writeb_relaxed(cmd, this->IO_ADDR_W);
}
/*
@ -426,14 +426,18 @@ static void fsmc_nand_setup(void __iomem *regs, uint32_t bank,
tset = (tims->tset & FSMC_TSET_MASK) << FSMC_TSET_SHIFT;
if (busw)
writel(value | FSMC_DEVWID_16, FSMC_NAND_REG(regs, bank, PC));
writel_relaxed(value | FSMC_DEVWID_16,
FSMC_NAND_REG(regs, bank, PC));
else
writel(value | FSMC_DEVWID_8, FSMC_NAND_REG(regs, bank, PC));
writel_relaxed(value | FSMC_DEVWID_8,
FSMC_NAND_REG(regs, bank, PC));
writel(readl(FSMC_NAND_REG(regs, bank, PC)) | tclr | tar,
writel_relaxed(readl(FSMC_NAND_REG(regs, bank, PC)) | tclr | tar,
FSMC_NAND_REG(regs, bank, PC));
writel(thiz | thold | twait | tset, FSMC_NAND_REG(regs, bank, COMM));
writel(thiz | thold | twait | tset, FSMC_NAND_REG(regs, bank, ATTRIB));
writel_relaxed(thiz | thold | twait | tset,
FSMC_NAND_REG(regs, bank, COMM));
writel_relaxed(thiz | thold | twait | tset,
FSMC_NAND_REG(regs, bank, ATTRIB));
}
/*
@ -446,11 +450,11 @@ static void fsmc_enable_hwecc(struct mtd_info *mtd, int mode)
void __iomem *regs = host->regs_va;
uint32_t bank = host->bank;
writel(readl(FSMC_NAND_REG(regs, bank, PC)) & ~FSMC_ECCPLEN_256,
writel_relaxed(readl(FSMC_NAND_REG(regs, bank, PC)) & ~FSMC_ECCPLEN_256,
FSMC_NAND_REG(regs, bank, PC));
writel(readl(FSMC_NAND_REG(regs, bank, PC)) & ~FSMC_ECCEN,
writel_relaxed(readl(FSMC_NAND_REG(regs, bank, PC)) & ~FSMC_ECCEN,
FSMC_NAND_REG(regs, bank, PC));
writel(readl(FSMC_NAND_REG(regs, bank, PC)) | FSMC_ECCEN,
writel_relaxed(readl(FSMC_NAND_REG(regs, bank, PC)) | FSMC_ECCEN,
FSMC_NAND_REG(regs, bank, PC));
}
@ -470,7 +474,7 @@ static int fsmc_read_hwecc_ecc4(struct mtd_info *mtd, const uint8_t *data,
unsigned long deadline = jiffies + FSMC_BUSY_WAIT_TIMEOUT;
do {
if (readl(FSMC_NAND_REG(regs, bank, STS)) & FSMC_CODE_RDY)
if (readl_relaxed(FSMC_NAND_REG(regs, bank, STS)) & FSMC_CODE_RDY)
break;
else
cond_resched();
@ -481,25 +485,25 @@ static int fsmc_read_hwecc_ecc4(struct mtd_info *mtd, const uint8_t *data,
return -ETIMEDOUT;
}
ecc_tmp = readl(FSMC_NAND_REG(regs, bank, ECC1));
ecc_tmp = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC1));
ecc[0] = (uint8_t) (ecc_tmp >> 0);
ecc[1] = (uint8_t) (ecc_tmp >> 8);
ecc[2] = (uint8_t) (ecc_tmp >> 16);
ecc[3] = (uint8_t) (ecc_tmp >> 24);
ecc_tmp = readl(FSMC_NAND_REG(regs, bank, ECC2));
ecc_tmp = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC2));
ecc[4] = (uint8_t) (ecc_tmp >> 0);
ecc[5] = (uint8_t) (ecc_tmp >> 8);
ecc[6] = (uint8_t) (ecc_tmp >> 16);
ecc[7] = (uint8_t) (ecc_tmp >> 24);
ecc_tmp = readl(FSMC_NAND_REG(regs, bank, ECC3));
ecc_tmp = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC3));
ecc[8] = (uint8_t) (ecc_tmp >> 0);
ecc[9] = (uint8_t) (ecc_tmp >> 8);
ecc[10] = (uint8_t) (ecc_tmp >> 16);
ecc[11] = (uint8_t) (ecc_tmp >> 24);
ecc_tmp = readl(FSMC_NAND_REG(regs, bank, STS));
ecc_tmp = readl_relaxed(FSMC_NAND_REG(regs, bank, STS));
ecc[12] = (uint8_t) (ecc_tmp >> 16);
return 0;
@ -519,7 +523,7 @@ static int fsmc_read_hwecc_ecc1(struct mtd_info *mtd, const uint8_t *data,
uint32_t bank = host->bank;
uint32_t ecc_tmp;
ecc_tmp = readl(FSMC_NAND_REG(regs, bank, ECC1));
ecc_tmp = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC1));
ecc[0] = (uint8_t) (ecc_tmp >> 0);
ecc[1] = (uint8_t) (ecc_tmp >> 8);
ecc[2] = (uint8_t) (ecc_tmp >> 16);
@ -601,7 +605,7 @@ static int dma_xfer(struct fsmc_nand_data *host, void *buffer, int len,
dma_async_issue_pending(chan);
ret =
wait_for_completion_interruptible_timeout(&host->dma_access_complete,
wait_for_completion_timeout(&host->dma_access_complete,
msecs_to_jiffies(3000));
if (ret <= 0) {
chan->device->device_control(chan, DMA_TERMINATE_ALL, 0);
@ -628,10 +632,10 @@ static void fsmc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
uint32_t *p = (uint32_t *)buf;
len = len >> 2;
for (i = 0; i < len; i++)
writel(p[i], chip->IO_ADDR_W);
writel_relaxed(p[i], chip->IO_ADDR_W);
} else {
for (i = 0; i < len; i++)
writeb(buf[i], chip->IO_ADDR_W);
writeb_relaxed(buf[i], chip->IO_ADDR_W);
}
}
@ -651,10 +655,10 @@ static void fsmc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
uint32_t *p = (uint32_t *)buf;
len = len >> 2;
for (i = 0; i < len; i++)
p[i] = readl(chip->IO_ADDR_R);
p[i] = readl_relaxed(chip->IO_ADDR_R);
} else {
for (i = 0; i < len; i++)
buf[i] = readb(chip->IO_ADDR_R);
buf[i] = readb_relaxed(chip->IO_ADDR_R);
}
}
@ -783,7 +787,7 @@ static int fsmc_bch8_correct_data(struct mtd_info *mtd, uint8_t *dat,
uint32_t num_err, i;
uint32_t ecc1, ecc2, ecc3, ecc4;
num_err = (readl(FSMC_NAND_REG(regs, bank, STS)) >> 10) & 0xF;
num_err = (readl_relaxed(FSMC_NAND_REG(regs, bank, STS)) >> 10) & 0xF;
/* no bit flipping */
if (likely(num_err == 0))
@ -826,10 +830,10 @@ static int fsmc_bch8_correct_data(struct mtd_info *mtd, uint8_t *dat,
* uint64_t array and error offset indexes are populated in err_idx
* array
*/
ecc1 = readl(FSMC_NAND_REG(regs, bank, ECC1));
ecc2 = readl(FSMC_NAND_REG(regs, bank, ECC2));
ecc3 = readl(FSMC_NAND_REG(regs, bank, ECC3));
ecc4 = readl(FSMC_NAND_REG(regs, bank, STS));
ecc1 = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC1));
ecc2 = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC2));
ecc3 = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC3));
ecc4 = readl_relaxed(FSMC_NAND_REG(regs, bank, STS));
err_idx[0] = (ecc1 >> 0) & 0x1FFF;
err_idx[1] = (ecc1 >> 13) & 0x1FFF;
@ -860,7 +864,7 @@ static bool filter(struct dma_chan *chan, void *slave)
}
#ifdef CONFIG_OF
static int __devinit fsmc_nand_probe_config_dt(struct platform_device *pdev,
static int fsmc_nand_probe_config_dt(struct platform_device *pdev,
struct device_node *np)
{
struct fsmc_nand_platform_data *pdata = dev_get_platdata(&pdev->dev);
@ -876,15 +880,13 @@ static int __devinit fsmc_nand_probe_config_dt(struct platform_device *pdev,
return -EINVAL;
}
}
of_property_read_u32(np, "st,ale-off", &pdata->ale_off);
of_property_read_u32(np, "st,cle-off", &pdata->cle_off);
if (of_get_property(np, "nand-skip-bbtscan", NULL))
pdata->options = NAND_SKIP_BBTSCAN;
return 0;
}
#else
static int __devinit fsmc_nand_probe_config_dt(struct platform_device *pdev,
static int fsmc_nand_probe_config_dt(struct platform_device *pdev,
struct device_node *np)
{
return -ENOSYS;
@ -935,41 +937,28 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
if (!res)
return -EINVAL;
if (!devm_request_mem_region(&pdev->dev, res->start, resource_size(res),
pdev->name)) {
dev_err(&pdev->dev, "Failed to get memory data resourse\n");
return -ENOENT;
}
host->data_pa = (dma_addr_t)res->start;
host->data_va = devm_ioremap(&pdev->dev, res->start,
resource_size(res));
host->data_va = devm_request_and_ioremap(&pdev->dev, res);
if (!host->data_va) {
dev_err(&pdev->dev, "data ioremap failed\n");
return -ENOMEM;
}
host->data_pa = (dma_addr_t)res->start;
if (!devm_request_mem_region(&pdev->dev, res->start + pdata->ale_off,
resource_size(res), pdev->name)) {
dev_err(&pdev->dev, "Failed to get memory ale resourse\n");
return -ENOENT;
}
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_addr");
if (!res)
return -EINVAL;
host->addr_va = devm_ioremap(&pdev->dev, res->start + pdata->ale_off,
resource_size(res));
host->addr_va = devm_request_and_ioremap(&pdev->dev, res);
if (!host->addr_va) {
dev_err(&pdev->dev, "ale ioremap failed\n");
return -ENOMEM;
}
if (!devm_request_mem_region(&pdev->dev, res->start + pdata->cle_off,
resource_size(res), pdev->name)) {
dev_err(&pdev->dev, "Failed to get memory cle resourse\n");
return -ENOENT;
}
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_cmd");
if (!res)
return -EINVAL;
host->cmd_va = devm_ioremap(&pdev->dev, res->start + pdata->cle_off,
resource_size(res));
host->cmd_va = devm_request_and_ioremap(&pdev->dev, res);
if (!host->cmd_va) {
dev_err(&pdev->dev, "ale ioremap failed\n");
return -ENOMEM;
@ -979,14 +968,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
if (!res)
return -EINVAL;
if (!devm_request_mem_region(&pdev->dev, res->start, resource_size(res),
pdev->name)) {
dev_err(&pdev->dev, "Failed to get memory regs resourse\n");
return -ENOENT;
}
host->regs_va = devm_ioremap(&pdev->dev, res->start,
resource_size(res));
host->regs_va = devm_request_and_ioremap(&pdev->dev, res);
if (!host->regs_va) {
dev_err(&pdev->dev, "regs ioremap failed\n");
return -ENOMEM;

View File

@ -90,14 +90,14 @@ static void gpio_nand_writebuf(struct mtd_info *mtd, const u_char *buf, int len)
{
struct nand_chip *this = mtd->priv;
writesb(this->IO_ADDR_W, buf, len);
iowrite8_rep(this->IO_ADDR_W, buf, len);
}
static void gpio_nand_readbuf(struct mtd_info *mtd, u_char *buf, int len)
{
struct nand_chip *this = mtd->priv;
readsb(this->IO_ADDR_R, buf, len);
ioread8_rep(this->IO_ADDR_R, buf, len);
}
static void gpio_nand_writebuf16(struct mtd_info *mtd, const u_char *buf,
@ -106,7 +106,7 @@ static void gpio_nand_writebuf16(struct mtd_info *mtd, const u_char *buf,
struct nand_chip *this = mtd->priv;
if (IS_ALIGNED((unsigned long)buf, 2)) {
writesw(this->IO_ADDR_W, buf, len>>1);
iowrite16_rep(this->IO_ADDR_W, buf, len>>1);
} else {
int i;
unsigned short *ptr = (unsigned short *)buf;
@ -121,7 +121,7 @@ static void gpio_nand_readbuf16(struct mtd_info *mtd, u_char *buf, int len)
struct nand_chip *this = mtd->priv;
if (IS_ALIGNED((unsigned long)buf, 2)) {
readsw(this->IO_ADDR_R, buf, len>>1);
ioread16_rep(this->IO_ADDR_R, buf, len>>1);
} else {
int i;
unsigned short *ptr = (unsigned short *)buf;
@ -134,7 +134,11 @@ static void gpio_nand_readbuf16(struct mtd_info *mtd, u_char *buf, int len)
static int gpio_nand_devready(struct mtd_info *mtd)
{
struct gpiomtd *gpiomtd = gpio_nand_getpriv(mtd);
return gpio_get_value(gpiomtd->plat.gpio_rdy);
if (gpio_is_valid(gpiomtd->plat.gpio_rdy))
return gpio_get_value(gpiomtd->plat.gpio_rdy);
return 1;
}
#ifdef CONFIG_OF
@ -227,7 +231,7 @@ gpio_nand_get_io_sync(struct platform_device *pdev)
return platform_get_resource(pdev, IORESOURCE_MEM, 1);
}
static int __devexit gpio_nand_remove(struct platform_device *dev)
static int gpio_nand_remove(struct platform_device *dev)
{
struct gpiomtd *gpiomtd = platform_get_drvdata(dev);
struct resource *res;
@ -252,7 +256,8 @@ static int __devexit gpio_nand_remove(struct platform_device *dev)
gpio_free(gpiomtd->plat.gpio_nce);
if (gpio_is_valid(gpiomtd->plat.gpio_nwp))
gpio_free(gpiomtd->plat.gpio_nwp);
gpio_free(gpiomtd->plat.gpio_rdy);
if (gpio_is_valid(gpiomtd->plat.gpio_rdy))
gpio_free(gpiomtd->plat.gpio_rdy);
kfree(gpiomtd);
@ -277,7 +282,7 @@ static void __iomem *request_and_remap(struct resource *res, size_t size,
return ptr;
}
static int __devinit gpio_nand_probe(struct platform_device *dev)
static int gpio_nand_probe(struct platform_device *dev)
{
struct gpiomtd *gpiomtd;
struct nand_chip *this;
@ -336,10 +341,12 @@ static int __devinit gpio_nand_probe(struct platform_device *dev)
if (ret)
goto err_cle;
gpio_direction_output(gpiomtd->plat.gpio_cle, 0);
ret = gpio_request(gpiomtd->plat.gpio_rdy, "NAND RDY");
if (ret)
goto err_rdy;
gpio_direction_input(gpiomtd->plat.gpio_rdy);
if (gpio_is_valid(gpiomtd->plat.gpio_rdy)) {
ret = gpio_request(gpiomtd->plat.gpio_rdy, "NAND RDY");
if (ret)
goto err_rdy;
gpio_direction_input(gpiomtd->plat.gpio_rdy);
}
this->IO_ADDR_W = this->IO_ADDR_R;
@ -386,7 +393,8 @@ static int __devinit gpio_nand_probe(struct platform_device *dev)
err_wp:
if (gpio_is_valid(gpiomtd->plat.gpio_nwp))
gpio_set_value(gpiomtd->plat.gpio_nwp, 0);
gpio_free(gpiomtd->plat.gpio_rdy);
if (gpio_is_valid(gpiomtd->plat.gpio_rdy))
gpio_free(gpiomtd->plat.gpio_rdy);
err_rdy:
gpio_free(gpiomtd->plat.gpio_cle);
err_cle:

View File

@ -18,7 +18,6 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <linux/mtd/gpmi-nand.h>
#include <linux/delay.h>
#include <linux/clk.h>
@ -166,6 +165,15 @@ int gpmi_init(struct gpmi_nand_data *this)
if (ret)
goto err_out;
/*
* Reset BCH here, too. We got failures otherwise :(
* See later BCH reset for explanation of MX23 handling
*/
ret = gpmi_reset_block(r->bch_regs, GPMI_IS_MX23(this));
if (ret)
goto err_out;
/* Choose NAND mode. */
writel(BM_GPMI_CTRL1_GPMI_MODE, r->gpmi_regs + HW_GPMI_CTRL1_CLR);

View File

@ -25,7 +25,6 @@
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/mtd/gpmi-nand.h>
#include <linux/mtd/partitions.h>
#include <linux/pinctrl/consumer.h>
#include <linux/of.h>
@ -33,6 +32,12 @@
#include <linux/of_mtd.h>
#include "gpmi-nand.h"
/* Resource names for the GPMI NAND driver. */
#define GPMI_NAND_GPMI_REGS_ADDR_RES_NAME "gpmi-nand"
#define GPMI_NAND_BCH_REGS_ADDR_RES_NAME "bch"
#define GPMI_NAND_BCH_INTERRUPT_RES_NAME "bch"
#define GPMI_NAND_DMA_INTERRUPT_RES_NAME "gpmi-dma"
/* add our owner bbt descriptor */
static uint8_t scan_ff_pattern[] = { 0xff };
static struct nand_bbt_descr gpmi_bbt_descr = {
@ -222,7 +227,7 @@ void prepare_data_dma(struct gpmi_nand_data *this, enum dma_data_direction dr)
ret = dma_map_sg(this->dev, sgl, 1, dr);
if (ret == 0)
pr_err("map failed.\n");
pr_err("DMA mapping failed.\n");
this->direct_dma_map_ok = false;
}
@ -314,7 +319,7 @@ int start_dma_with_bch_irq(struct gpmi_nand_data *this,
return 0;
}
static int __devinit
static int
acquire_register_block(struct gpmi_nand_data *this, const char *res_name)
{
struct platform_device *pdev = this->pdev;
@ -355,7 +360,7 @@ static void release_register_block(struct gpmi_nand_data *this)
res->bch_regs = NULL;
}
static int __devinit
static int
acquire_bch_irq(struct gpmi_nand_data *this, irq_handler_t irq_h)
{
struct platform_device *pdev = this->pdev;
@ -422,7 +427,7 @@ static void release_dma_channels(struct gpmi_nand_data *this)
}
}
static int __devinit acquire_dma_channels(struct gpmi_nand_data *this)
static int acquire_dma_channels(struct gpmi_nand_data *this)
{
struct platform_device *pdev = this->pdev;
struct resource *r_dma;
@ -456,7 +461,7 @@ static int __devinit acquire_dma_channels(struct gpmi_nand_data *this)
dma_chan = dma_request_channel(mask, gpmi_dma_filter, this);
if (!dma_chan) {
pr_err("dma_request_channel failed.\n");
pr_err("Failed to request DMA channel.\n");
goto acquire_err;
}
@ -487,7 +492,7 @@ static char *extra_clks_for_mx6q[GPMI_CLK_MAX] = {
"gpmi_apb", "gpmi_bch", "gpmi_bch_apb", "per1_bch",
};
static int __devinit gpmi_get_clks(struct gpmi_nand_data *this)
static int gpmi_get_clks(struct gpmi_nand_data *this)
{
struct resources *r = &this->resources;
char **extra_clks = NULL;
@ -533,7 +538,7 @@ err_clock:
return -ENOMEM;
}
static int __devinit acquire_resources(struct gpmi_nand_data *this)
static int acquire_resources(struct gpmi_nand_data *this)
{
struct pinctrl *pinctrl;
int ret;
@ -583,7 +588,7 @@ static void release_resources(struct gpmi_nand_data *this)
release_dma_channels(this);
}
static int __devinit init_hardware(struct gpmi_nand_data *this)
static int init_hardware(struct gpmi_nand_data *this)
{
int ret;
@ -625,7 +630,8 @@ static int read_page_prepare(struct gpmi_nand_data *this,
length, DMA_FROM_DEVICE);
if (dma_mapping_error(dev, dest_phys)) {
if (alt_size < length) {
pr_err("Alternate buffer is too small\n");
pr_err("%s, Alternate buffer is too small\n",
__func__);
return -ENOMEM;
}
goto map_failed;
@ -675,7 +681,8 @@ static int send_page_prepare(struct gpmi_nand_data *this,
DMA_TO_DEVICE);
if (dma_mapping_error(dev, source_phys)) {
if (alt_size < length) {
pr_err("Alternate buffer is too small\n");
pr_err("%s, Alternate buffer is too small\n",
__func__);
return -ENOMEM;
}
goto map_failed;
@ -763,7 +770,7 @@ static int gpmi_alloc_dma_buffer(struct gpmi_nand_data *this)
error_alloc:
gpmi_free_dma_buffer(this);
pr_err("allocate DMA buffer ret!!\n");
pr_err("Error allocating DMA buffers!\n");
return -ENOMEM;
}
@ -1474,7 +1481,7 @@ static int gpmi_set_geometry(struct gpmi_nand_data *this)
/* Set up the NFC geometry which is used by BCH. */
ret = bch_set_geometry(this);
if (ret) {
pr_err("set geometry ret : %d\n", ret);
pr_err("Error setting BCH geometry : %d\n", ret);
return ret;
}
@ -1535,7 +1542,7 @@ static void gpmi_nfc_exit(struct gpmi_nand_data *this)
gpmi_free_dma_buffer(this);
}
static int __devinit gpmi_nfc_init(struct gpmi_nand_data *this)
static int gpmi_nfc_init(struct gpmi_nand_data *this)
{
struct mtd_info *mtd = &this->mtd;
struct nand_chip *chip = &this->nand;
@ -1618,7 +1625,7 @@ static const struct of_device_id gpmi_nand_id_table[] = {
};
MODULE_DEVICE_TABLE(of, gpmi_nand_id_table);
static int __devinit gpmi_nand_probe(struct platform_device *pdev)
static int gpmi_nand_probe(struct platform_device *pdev)
{
struct gpmi_nand_data *this;
const struct of_device_id *of_id;
@ -1668,7 +1675,7 @@ exit_acquire_resources:
return ret;
}
static int __devexit gpmi_nand_remove(struct platform_device *pdev)
static int gpmi_nand_remove(struct platform_device *pdev)
{
struct gpmi_nand_data *this = platform_get_drvdata(pdev);
@ -1685,7 +1692,7 @@ static struct platform_driver gpmi_nand_driver = {
.of_match_table = gpmi_nand_id_table,
},
.probe = gpmi_nand_probe,
.remove = __devexit_p(gpmi_nand_remove),
.remove = gpmi_nand_remove,
.id_table = gpmi_ids,
};
module_platform_driver(gpmi_nand_driver);

View File

@ -130,7 +130,6 @@ struct gpmi_nand_data {
/* System Interface */
struct device *dev;
struct platform_device *pdev;
struct gpmi_nand_platform_data *pdata;
/* Resources */
struct resources resources;

View File

@ -316,13 +316,17 @@ err:
return ret;
}
static inline void jz_nand_iounmap_resource(struct resource *res, void __iomem *base)
static inline void jz_nand_iounmap_resource(struct resource *res,
void __iomem *base)
{
iounmap(base);
release_mem_region(res->start, resource_size(res));
}
static int __devinit jz_nand_detect_bank(struct platform_device *pdev, struct jz_nand *nand, unsigned char bank, size_t chipnr, uint8_t *nand_maf_id, uint8_t *nand_dev_id) {
static int jz_nand_detect_bank(struct platform_device *pdev,
struct jz_nand *nand, unsigned char bank,
size_t chipnr, uint8_t *nand_maf_id,
uint8_t *nand_dev_id) {
int ret;
int gpio;
char gpio_name[9];
@ -400,7 +404,7 @@ notfound_gpio:
return ret;
}
static int __devinit jz_nand_probe(struct platform_device *pdev)
static int jz_nand_probe(struct platform_device *pdev)
{
int ret;
struct jz_nand *nand;
@ -541,7 +545,7 @@ err_free:
return ret;
}
static int __devexit jz_nand_remove(struct platform_device *pdev)
static int jz_nand_remove(struct platform_device *pdev)
{
struct jz_nand *nand = platform_get_drvdata(pdev);
struct jz_nand_platform_data *pdata = pdev->dev.platform_data;
@ -573,7 +577,7 @@ static int __devexit jz_nand_remove(struct platform_device *pdev)
static struct platform_driver jz_nand_driver = {
.probe = jz_nand_probe,
.remove = __devexit_p(jz_nand_remove),
.remove = jz_nand_remove,
.driver = {
.name = "jz4740-nand",
.owner = THIS_MODULE,

View File

@ -655,7 +655,7 @@ static struct lpc32xx_nand_cfg_mlc *lpc32xx_parse_dt(struct device *dev)
/*
* Probe for NAND controller
*/
static int __devinit lpc32xx_nand_probe(struct platform_device *pdev)
static int lpc32xx_nand_probe(struct platform_device *pdev)
{
struct lpc32xx_nand_host *host;
struct mtd_info *mtd;
@ -845,7 +845,7 @@ err_exit1:
/*
* Remove NAND device
*/
static int __devexit lpc32xx_nand_remove(struct platform_device *pdev)
static int lpc32xx_nand_remove(struct platform_device *pdev)
{
struct lpc32xx_nand_host *host = platform_get_drvdata(pdev);
struct mtd_info *mtd = &host->mtd;
@ -907,7 +907,7 @@ MODULE_DEVICE_TABLE(of, lpc32xx_nand_match);
static struct platform_driver lpc32xx_nand_driver = {
.probe = lpc32xx_nand_probe,
.remove = __devexit_p(lpc32xx_nand_remove),
.remove = lpc32xx_nand_remove,
.resume = lpc32xx_nand_resume,
.suspend = lpc32xx_nand_suspend,
.driver = {

View File

@ -755,7 +755,7 @@ static struct lpc32xx_nand_cfg_slc *lpc32xx_parse_dt(struct device *dev)
/*
* Probe for NAND controller
*/
static int __devinit lpc32xx_nand_probe(struct platform_device *pdev)
static int lpc32xx_nand_probe(struct platform_device *pdev)
{
struct lpc32xx_nand_host *host;
struct mtd_info *mtd;
@ -949,7 +949,7 @@ err_exit1:
/*
* Remove NAND device.
*/
static int __devexit lpc32xx_nand_remove(struct platform_device *pdev)
static int lpc32xx_nand_remove(struct platform_device *pdev)
{
uint32_t tmp;
struct lpc32xx_nand_host *host = platform_get_drvdata(pdev);
@ -1021,7 +1021,7 @@ MODULE_DEVICE_TABLE(of, lpc32xx_nand_match);
static struct platform_driver lpc32xx_nand_driver = {
.probe = lpc32xx_nand_probe,
.remove = __devexit_p(lpc32xx_nand_remove),
.remove = lpc32xx_nand_remove,
.resume = lpc32xx_nand_resume,
.suspend = lpc32xx_nand_suspend,
.driver = {

View File

@ -626,7 +626,7 @@ static void mpc5121_nfc_free(struct device *dev, struct mtd_info *mtd)
iounmap(prv->csreg);
}
static int __devinit mpc5121_nfc_probe(struct platform_device *op)
static int mpc5121_nfc_probe(struct platform_device *op)
{
struct device_node *rootnode, *dn = op->dev.of_node;
struct device *dev = &op->dev;
@ -827,7 +827,7 @@ error:
return retval;
}
static int __devexit mpc5121_nfc_remove(struct platform_device *op)
static int mpc5121_nfc_remove(struct platform_device *op)
{
struct device *dev = &op->dev;
struct mtd_info *mtd = dev_get_drvdata(dev);
@ -841,14 +841,14 @@ static int __devexit mpc5121_nfc_remove(struct platform_device *op)
return 0;
}
static struct of_device_id mpc5121_nfc_match[] __devinitdata = {
static struct of_device_id mpc5121_nfc_match[] = {
{ .compatible = "fsl,mpc5121-nfc", },
{},
};
static struct platform_driver mpc5121_nfc_driver = {
.probe = mpc5121_nfc_probe,
.remove = __devexit_p(mpc5121_nfc_remove),
.remove = mpc5121_nfc_remove,
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,

View File

@ -266,7 +266,8 @@ static struct nand_ecclayout nandv2_hw_eccoob_4k = {
}
};
static const char *part_probes[] = { "RedBoot", "cmdlinepart", "ofpart", NULL };
static const char const *part_probes[] = {
"cmdlinepart", "RedBoot", "ofpart", NULL };
static void memcpy32_fromio(void *trg, const void __iomem *src, size_t size)
{
@ -1378,7 +1379,7 @@ static int __init mxcnd_probe_dt(struct mxc_nand_host *host)
}
#endif
static int __devinit mxcnd_probe(struct platform_device *pdev)
static int mxcnd_probe(struct platform_device *pdev)
{
struct nand_chip *this;
struct mtd_info *mtd;
@ -1556,12 +1557,13 @@ static int __devinit mxcnd_probe(struct platform_device *pdev)
return 0;
escan:
clk_disable_unprepare(host->clk);
if (host->clk_act)
clk_disable_unprepare(host->clk);
return err;
}
static int __devexit mxcnd_remove(struct platform_device *pdev)
static int mxcnd_remove(struct platform_device *pdev)
{
struct mxc_nand_host *host = platform_get_drvdata(pdev);
@ -1580,7 +1582,7 @@ static struct platform_driver mxcnd_driver = {
},
.id_table = mxcnd_devtype,
.probe = mxcnd_probe,
.remove = __devexit_p(mxcnd_remove),
.remove = mxcnd_remove,
};
module_platform_driver(mxcnd_driver);

View File

@ -93,8 +93,7 @@ static struct nand_ecclayout nand_oob_128 = {
.length = 78} }
};
static int nand_get_device(struct nand_chip *chip, struct mtd_info *mtd,
int new_state);
static int nand_get_device(struct mtd_info *mtd, int new_state);
static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
struct mtd_oob_ops *ops);
@ -130,15 +129,12 @@ static int check_offs_len(struct mtd_info *mtd,
* nand_release_device - [GENERIC] release chip
* @mtd: MTD device structure
*
* Deselect, release chip lock and wake up anyone waiting on the device.
* Release chip lock and wake up anyone waiting on the device.
*/
static void nand_release_device(struct mtd_info *mtd)
{
struct nand_chip *chip = mtd->priv;
/* De-select the NAND device */
chip->select_chip(mtd, -1);
/* Release the controller and the chip */
spin_lock(&chip->controller->lock);
chip->controller->active = NULL;
@ -160,7 +156,7 @@ static uint8_t nand_read_byte(struct mtd_info *mtd)
}
/**
* nand_read_byte16 - [DEFAULT] read one byte endianess aware from the chip
* nand_read_byte16 - [DEFAULT] read one byte endianness aware from the chip
* nand_read_byte16 - [DEFAULT] read one byte endianness aware from the chip
* @mtd: MTD device structure
*
@ -303,7 +299,7 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
if (getchip) {
chipnr = (int)(ofs >> chip->chip_shift);
nand_get_device(chip, mtd, FL_READING);
nand_get_device(mtd, FL_READING);
/* Select the NAND device */
chip->select_chip(mtd, chipnr);
@ -333,8 +329,10 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
i++;
} while (!res && i < 2 && (chip->bbt_options & NAND_BBT_SCAN2NDPAGE));
if (getchip)
if (getchip) {
chip->select_chip(mtd, -1);
nand_release_device(mtd);
}
return res;
}
@ -383,7 +381,7 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
struct mtd_oob_ops ops;
loff_t wr_ofs = ofs;
nand_get_device(chip, mtd, FL_WRITING);
nand_get_device(mtd, FL_WRITING);
ops.datbuf = NULL;
ops.oobbuf = buf;
@ -492,7 +490,7 @@ static void panic_nand_wait_ready(struct mtd_info *mtd, unsigned long timeo)
void nand_wait_ready(struct mtd_info *mtd)
{
struct nand_chip *chip = mtd->priv;
unsigned long timeo = jiffies + 2;
unsigned long timeo = jiffies + msecs_to_jiffies(20);
/* 400ms timeout */
if (in_interrupt() || oops_in_progress)
@ -750,15 +748,15 @@ static void panic_nand_get_device(struct nand_chip *chip,
/**
* nand_get_device - [GENERIC] Get chip for selected access
* @chip: the nand chip descriptor
* @mtd: MTD device structure
* @new_state: the state which is requested
*
* Get the device and lock it for exclusive access
*/
static int
nand_get_device(struct nand_chip *chip, struct mtd_info *mtd, int new_state)
nand_get_device(struct mtd_info *mtd, int new_state)
{
struct nand_chip *chip = mtd->priv;
spinlock_t *lock = &chip->controller->lock;
wait_queue_head_t *wq = &chip->controller->wq;
DECLARE_WAITQUEUE(wait, current);
@ -865,6 +863,8 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
led_trigger_event(nand_led_trigger, LED_OFF);
status = (int)chip->read_byte(mtd);
/* This can happen if in case of timeout or buggy dev_ready */
WARN_ON(!(status & NAND_STATUS_READY));
return status;
}
@ -899,7 +899,7 @@ static int __nand_unlock(struct mtd_info *mtd, loff_t ofs,
/* Call wait ready function */
status = chip->waitfunc(mtd, chip);
/* See if device thinks it succeeded */
if (status & 0x01) {
if (status & NAND_STATUS_FAIL) {
pr_debug("%s: error status = 0x%08x\n",
__func__, status);
ret = -EIO;
@ -932,7 +932,7 @@ int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
if (ofs + len == mtd->size)
len -= mtd->erasesize;
nand_get_device(chip, mtd, FL_UNLOCKING);
nand_get_device(mtd, FL_UNLOCKING);
/* Shift to get chip number */
chipnr = ofs >> chip->chip_shift;
@ -950,6 +950,7 @@ int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
ret = __nand_unlock(mtd, ofs, len, 0);
out:
chip->select_chip(mtd, -1);
nand_release_device(mtd);
return ret;
@ -981,7 +982,7 @@ int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
if (check_offs_len(mtd, ofs, len))
ret = -EINVAL;
nand_get_device(chip, mtd, FL_LOCKING);
nand_get_device(mtd, FL_LOCKING);
/* Shift to get chip number */
chipnr = ofs >> chip->chip_shift;
@ -1004,7 +1005,7 @@ int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
/* Call wait ready function */
status = chip->waitfunc(mtd, chip);
/* See if device thinks it succeeded */
if (status & 0x01) {
if (status & NAND_STATUS_FAIL) {
pr_debug("%s: error status = 0x%08x\n",
__func__, status);
ret = -EIO;
@ -1014,6 +1015,7 @@ int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
ret = __nand_unlock(mtd, ofs, len, 0x1);
out:
chip->select_chip(mtd, -1);
nand_release_device(mtd);
return ret;
@ -1550,6 +1552,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
chip->select_chip(mtd, chipnr);
}
}
chip->select_chip(mtd, -1);
ops->retlen = ops->len - (size_t) readlen;
if (oob)
@ -1577,11 +1580,10 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
static int nand_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, uint8_t *buf)
{
struct nand_chip *chip = mtd->priv;
struct mtd_oob_ops ops;
int ret;
nand_get_device(chip, mtd, FL_READING);
nand_get_device(mtd, FL_READING);
ops.len = len;
ops.datbuf = buf;
ops.oobbuf = NULL;
@ -1804,6 +1806,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
chip->select_chip(mtd, chipnr);
}
}
chip->select_chip(mtd, -1);
ops->oobretlen = ops->ooblen - readlen;
@ -1827,7 +1830,6 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
static int nand_read_oob(struct mtd_info *mtd, loff_t from,
struct mtd_oob_ops *ops)
{
struct nand_chip *chip = mtd->priv;
int ret = -ENOTSUPP;
ops->retlen = 0;
@ -1839,7 +1841,7 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from,
return -EINVAL;
}
nand_get_device(chip, mtd, FL_READING);
nand_get_device(mtd, FL_READING);
switch (ops->mode) {
case MTD_OPS_PLACE_OOB:
@ -2186,8 +2188,10 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
chip->select_chip(mtd, chipnr);
/* Check, if it is write protected */
if (nand_check_wp(mtd))
return -EIO;
if (nand_check_wp(mtd)) {
ret = -EIO;
goto err_out;
}
realpage = (int)(to >> chip->page_shift);
page = realpage & chip->pagemask;
@ -2199,8 +2203,10 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
chip->pagebuf = -1;
/* Don't allow multipage oob writes with offset */
if (oob && ops->ooboffs && (ops->ooboffs + ops->ooblen > oobmaxlen))
return -EINVAL;
if (oob && ops->ooboffs && (ops->ooboffs + ops->ooblen > oobmaxlen)) {
ret = -EINVAL;
goto err_out;
}
while (1) {
int bytes = mtd->writesize;
@ -2251,6 +2257,9 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
ops->retlen = ops->len - writelen;
if (unlikely(oob))
ops->oobretlen = ops->ooblen;
err_out:
chip->select_chip(mtd, -1);
return ret;
}
@ -2302,11 +2311,10 @@ static int panic_nand_write(struct mtd_info *mtd, loff_t to, size_t len,
static int nand_write(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const uint8_t *buf)
{
struct nand_chip *chip = mtd->priv;
struct mtd_oob_ops ops;
int ret;
nand_get_device(chip, mtd, FL_WRITING);
nand_get_device(mtd, FL_WRITING);
ops.len = len;
ops.datbuf = (uint8_t *)buf;
ops.oobbuf = NULL;
@ -2377,8 +2385,10 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
/* Check, if it is write protected */
if (nand_check_wp(mtd))
if (nand_check_wp(mtd)) {
chip->select_chip(mtd, -1);
return -EROFS;
}
/* Invalidate the page cache, if we write to the cached page */
if (page == chip->pagebuf)
@ -2391,6 +2401,8 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
else
status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask);
chip->select_chip(mtd, -1);
if (status)
return status;
@ -2408,7 +2420,6 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
static int nand_write_oob(struct mtd_info *mtd, loff_t to,
struct mtd_oob_ops *ops)
{
struct nand_chip *chip = mtd->priv;
int ret = -ENOTSUPP;
ops->retlen = 0;
@ -2420,7 +2431,7 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to,
return -EINVAL;
}
nand_get_device(chip, mtd, FL_WRITING);
nand_get_device(mtd, FL_WRITING);
switch (ops->mode) {
case MTD_OPS_PLACE_OOB:
@ -2513,7 +2524,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
return -EINVAL;
/* Grab the lock and see if the device is available */
nand_get_device(chip, mtd, FL_ERASING);
nand_get_device(mtd, FL_ERASING);
/* Shift to get first page */
page = (int)(instr->addr >> chip->page_shift);
@ -2623,6 +2634,7 @@ erase_exit:
ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;
/* Deselect and wake up anyone waiting on the device */
chip->select_chip(mtd, -1);
nand_release_device(mtd);
/* Do call back function */
@ -2658,12 +2670,10 @@ erase_exit:
*/
static void nand_sync(struct mtd_info *mtd)
{
struct nand_chip *chip = mtd->priv;
pr_debug("%s: called\n", __func__);
/* Grab the lock and see if the device is available */
nand_get_device(chip, mtd, FL_SYNCING);
nand_get_device(mtd, FL_SYNCING);
/* Release it and go back */
nand_release_device(mtd);
}
@ -2749,9 +2759,7 @@ static int nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip,
*/
static int nand_suspend(struct mtd_info *mtd)
{
struct nand_chip *chip = mtd->priv;
return nand_get_device(chip, mtd, FL_PM_SUSPENDED);
return nand_get_device(mtd, FL_PM_SUSPENDED);
}
/**
@ -2849,6 +2857,8 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
int i;
int val;
/* ONFI need to be probed in 8 bits mode */
WARN_ON(chip->options & NAND_BUSWIDTH_16);
/* Try ONFI for unknown chip or LP */
chip->cmdfunc(mtd, NAND_CMD_READID, 0x20, -1);
if (chip->read_byte(mtd) != 'O' || chip->read_byte(mtd) != 'N' ||
@ -2913,7 +2923,7 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
*
* Check if an ID string is repeated within a given sequence of bytes at
* specific repetition interval period (e.g., {0x20,0x01,0x7F,0x20} has a
* period of 2). This is a helper function for nand_id_len(). Returns non-zero
* period of 3). This is a helper function for nand_id_len(). Returns non-zero
* if the repetition has a period of @period; otherwise, returns zero.
*/
static int nand_id_has_period(u8 *id_data, int arrlen, int period)
@ -3242,11 +3252,15 @@ ident_done:
break;
}
/*
* Check, if buswidth is correct. Hardware drivers should set
* chip correct!
*/
if (busw != (chip->options & NAND_BUSWIDTH_16)) {
if (chip->options & NAND_BUSWIDTH_AUTO) {
WARN_ON(chip->options & NAND_BUSWIDTH_16);
chip->options |= busw;
nand_set_defaults(chip, busw);
} else if (busw != (chip->options & NAND_BUSWIDTH_16)) {
/*
* Check, if buswidth is correct. Hardware drivers should set
* chip correct!
*/
pr_info("NAND device: Manufacturer ID:"
" 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id,
*dev_id, nand_manuf_ids[maf_idx].name, mtd->name);
@ -3285,10 +3299,10 @@ ident_done:
chip->cmdfunc = nand_command_lp;
pr_info("NAND device: Manufacturer ID: 0x%02x, Chip ID: 0x%02x (%s %s),"
" page size: %d, OOB size: %d\n",
" %dMiB, page size: %d, OOB size: %d\n",
*maf_id, *dev_id, nand_manuf_ids[maf_idx].name,
chip->onfi_version ? chip->onfi_params.model : type->name,
mtd->writesize, mtd->oobsize);
(int)(chip->chipsize >> 20), mtd->writesize, mtd->oobsize);
return type;
}
@ -3327,6 +3341,8 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
return PTR_ERR(type);
}
chip->select_chip(mtd, -1);
/* Check for a chip array */
for (i = 1; i < maxchips; i++) {
chip->select_chip(mtd, i);
@ -3336,8 +3352,11 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
/* Read manufacturer and device IDs */
if (nand_maf_id != chip->read_byte(mtd) ||
nand_dev_id != chip->read_byte(mtd))
nand_dev_id != chip->read_byte(mtd)) {
chip->select_chip(mtd, -1);
break;
}
chip->select_chip(mtd, -1);
}
if (i > 1)
pr_info("%d NAND chips detected\n", i);
@ -3596,9 +3615,6 @@ int nand_scan_tail(struct mtd_info *mtd)
/* Initialize state */
chip->state = FL_READY;
/* De-select the device */
chip->select_chip(mtd, -1);
/* Invalidate the pagebuffer reference */
chip->pagebuf = -1;

View File

@ -42,6 +42,8 @@
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/pagemap.h>
#include <linux/seq_file.h>
#include <linux/debugfs.h>
/* Default simulator parameters values */
#if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE) || \
@ -105,7 +107,6 @@ static char *weakblocks = NULL;
static char *weakpages = NULL;
static unsigned int bitflips = 0;
static char *gravepages = NULL;
static unsigned int rptwear = 0;
static unsigned int overridesize = 0;
static char *cache_file = NULL;
static unsigned int bbt;
@ -130,7 +131,6 @@ module_param(weakblocks, charp, 0400);
module_param(weakpages, charp, 0400);
module_param(bitflips, uint, 0400);
module_param(gravepages, charp, 0400);
module_param(rptwear, uint, 0400);
module_param(overridesize, uint, 0400);
module_param(cache_file, charp, 0400);
module_param(bbt, uint, 0400);
@ -162,7 +162,6 @@ MODULE_PARM_DESC(bitflips, "Maximum number of random bit flips per page (z
MODULE_PARM_DESC(gravepages, "Pages that lose data [: maximum reads (defaults to 3)]"
" separated by commas e.g. 1401:2 means page 1401"
" can be read only twice before failing");
MODULE_PARM_DESC(rptwear, "Number of erases between reporting wear, if not zero");
MODULE_PARM_DESC(overridesize, "Specifies the NAND Flash size overriding the ID bytes. "
"The size is specified in erase blocks and as the exponent of a power of two"
" e.g. 5 means a size of 32 erase blocks");
@ -286,6 +285,11 @@ MODULE_PARM_DESC(bch, "Enable BCH ecc and set how many bits should "
/* Maximum page cache pages needed to read or write a NAND page to the cache_file */
#define NS_MAX_HELD_PAGES 16
struct nandsim_debug_info {
struct dentry *dfs_root;
struct dentry *dfs_wear_report;
};
/*
* A union to represent flash memory contents and flash buffer.
*/
@ -365,6 +369,8 @@ struct nandsim {
void *file_buf;
struct page *held_pages[NS_MAX_HELD_PAGES];
int held_cnt;
struct nandsim_debug_info dbg;
};
/*
@ -442,11 +448,123 @@ static LIST_HEAD(grave_pages);
static unsigned long *erase_block_wear = NULL;
static unsigned int wear_eb_count = 0;
static unsigned long total_wear = 0;
static unsigned int rptwear_cnt = 0;
/* MTD structure for NAND controller */
static struct mtd_info *nsmtd;
static int nandsim_debugfs_show(struct seq_file *m, void *private)
{
unsigned long wmin = -1, wmax = 0, avg;
unsigned long deciles[10], decile_max[10], tot = 0;
unsigned int i;
/* Calc wear stats */
for (i = 0; i < wear_eb_count; ++i) {
unsigned long wear = erase_block_wear[i];
if (wear < wmin)
wmin = wear;
if (wear > wmax)
wmax = wear;
tot += wear;
}
for (i = 0; i < 9; ++i) {
deciles[i] = 0;
decile_max[i] = (wmax * (i + 1) + 5) / 10;
}
deciles[9] = 0;
decile_max[9] = wmax;
for (i = 0; i < wear_eb_count; ++i) {
int d;
unsigned long wear = erase_block_wear[i];
for (d = 0; d < 10; ++d)
if (wear <= decile_max[d]) {
deciles[d] += 1;
break;
}
}
avg = tot / wear_eb_count;
/* Output wear report */
seq_printf(m, "Total numbers of erases: %lu\n", tot);
seq_printf(m, "Number of erase blocks: %u\n", wear_eb_count);
seq_printf(m, "Average number of erases: %lu\n", avg);
seq_printf(m, "Maximum number of erases: %lu\n", wmax);
seq_printf(m, "Minimum number of erases: %lu\n", wmin);
for (i = 0; i < 10; ++i) {
unsigned long from = (i ? decile_max[i - 1] + 1 : 0);
if (from > decile_max[i])
continue;
seq_printf(m, "Number of ebs with erase counts from %lu to %lu : %lu\n",
from,
decile_max[i],
deciles[i]);
}
return 0;
}
static int nandsim_debugfs_open(struct inode *inode, struct file *file)
{
return single_open(file, nandsim_debugfs_show, inode->i_private);
}
static const struct file_operations dfs_fops = {
.open = nandsim_debugfs_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
/**
* nandsim_debugfs_create - initialize debugfs
* @dev: nandsim device description object
*
* This function creates all debugfs files for UBI device @ubi. Returns zero in
* case of success and a negative error code in case of failure.
*/
static int nandsim_debugfs_create(struct nandsim *dev)
{
struct nandsim_debug_info *dbg = &dev->dbg;
struct dentry *dent;
int err;
if (!IS_ENABLED(CONFIG_DEBUG_FS))
return 0;
dent = debugfs_create_dir("nandsim", NULL);
if (IS_ERR_OR_NULL(dent)) {
int err = dent ? -ENODEV : PTR_ERR(dent);
NS_ERR("cannot create \"nandsim\" debugfs directory, err %d\n",
err);
return err;
}
dbg->dfs_root = dent;
dent = debugfs_create_file("wear_report", S_IRUSR,
dbg->dfs_root, dev, &dfs_fops);
if (IS_ERR_OR_NULL(dent))
goto out_remove;
dbg->dfs_wear_report = dent;
return 0;
out_remove:
debugfs_remove_recursive(dbg->dfs_root);
err = dent ? PTR_ERR(dent) : -ENODEV;
return err;
}
/**
* nandsim_debugfs_remove - destroy all debugfs files
*/
static void nandsim_debugfs_remove(struct nandsim *ns)
{
if (IS_ENABLED(CONFIG_DEBUG_FS))
debugfs_remove_recursive(ns->dbg.dfs_root);
}
/*
* Allocate array of page pointers, create slab allocation for an array
* and initialize the array by NULL pointers.
@ -911,8 +1029,6 @@ static int setup_wear_reporting(struct mtd_info *mtd)
{
size_t mem;
if (!rptwear)
return 0;
wear_eb_count = div_u64(mtd->size, mtd->erasesize);
mem = wear_eb_count * sizeof(unsigned long);
if (mem / sizeof(unsigned long) != wear_eb_count) {
@ -929,64 +1045,18 @@ static int setup_wear_reporting(struct mtd_info *mtd)
static void update_wear(unsigned int erase_block_no)
{
unsigned long wmin = -1, wmax = 0, avg;
unsigned long deciles[10], decile_max[10], tot = 0;
unsigned int i;
if (!erase_block_wear)
return;
total_wear += 1;
/*
* TODO: Notify this through a debugfs entry,
* instead of showing an error message.
*/
if (total_wear == 0)
NS_ERR("Erase counter total overflow\n");
erase_block_wear[erase_block_no] += 1;
if (erase_block_wear[erase_block_no] == 0)
NS_ERR("Erase counter overflow for erase block %u\n", erase_block_no);
rptwear_cnt += 1;
if (rptwear_cnt < rptwear)
return;
rptwear_cnt = 0;
/* Calc wear stats */
for (i = 0; i < wear_eb_count; ++i) {
unsigned long wear = erase_block_wear[i];
if (wear < wmin)
wmin = wear;
if (wear > wmax)
wmax = wear;
tot += wear;
}
for (i = 0; i < 9; ++i) {
deciles[i] = 0;
decile_max[i] = (wmax * (i + 1) + 5) / 10;
}
deciles[9] = 0;
decile_max[9] = wmax;
for (i = 0; i < wear_eb_count; ++i) {
int d;
unsigned long wear = erase_block_wear[i];
for (d = 0; d < 10; ++d)
if (wear <= decile_max[d]) {
deciles[d] += 1;
break;
}
}
avg = tot / wear_eb_count;
/* Output wear report */
NS_INFO("*** Wear Report ***\n");
NS_INFO("Total numbers of erases: %lu\n", tot);
NS_INFO("Number of erase blocks: %u\n", wear_eb_count);
NS_INFO("Average number of erases: %lu\n", avg);
NS_INFO("Maximum number of erases: %lu\n", wmax);
NS_INFO("Minimum number of erases: %lu\n", wmin);
for (i = 0; i < 10; ++i) {
unsigned long from = (i ? decile_max[i - 1] + 1 : 0);
if (from > decile_max[i])
continue;
NS_INFO("Number of ebs with erase counts from %lu to %lu : %lu\n",
from,
decile_max[i],
deciles[i]);
}
NS_INFO("*** End of Wear Report ***\n");
}
/*
@ -2327,6 +2397,9 @@ static int __init ns_init_module(void)
if ((retval = setup_wear_reporting(nsmtd)) != 0)
goto err_exit;
if ((retval = nandsim_debugfs_create(nand)) != 0)
goto err_exit;
if ((retval = init_nandsim(nsmtd)) != 0)
goto err_exit;
@ -2366,6 +2439,7 @@ static void __exit ns_cleanup_module(void)
struct nandsim *ns = ((struct nand_chip *)nsmtd->priv)->priv;
int i;
nandsim_debugfs_remove(ns);
free_nandsim(ns); /* Free nandsim private resources */
nand_release(nsmtd); /* Unregister driver */
for (i = 0;i < ARRAY_SIZE(ns->partitions); ++i)

View File

@ -197,7 +197,7 @@ err:
return ret;
}
static int __devinit ndfc_probe(struct platform_device *ofdev)
static int ndfc_probe(struct platform_device *ofdev)
{
struct ndfc_controller *ndfc;
const __be32 *reg;
@ -256,7 +256,7 @@ static int __devinit ndfc_probe(struct platform_device *ofdev)
return 0;
}
static int __devexit ndfc_remove(struct platform_device *ofdev)
static int ndfc_remove(struct platform_device *ofdev)
{
struct ndfc_controller *ndfc = dev_get_drvdata(&ofdev->dev);
@ -279,7 +279,7 @@ static struct platform_driver ndfc_driver = {
.of_match_table = ndfc_match,
},
.probe = ndfc_probe,
.remove = __devexit_p(ndfc_remove),
.remove = ndfc_remove,
};
module_platform_driver(ndfc_driver);

View File

@ -1,235 +0,0 @@
/*
* drivers/mtd/nand/nomadik_nand.c
*
* Overview:
* Driver for on-board NAND flash on Nomadik Platforms
*
* Copyright © 2007 STMicroelectronics Pvt. Ltd.
* Author: Sachin Verma <sachin.verma@st.com>
*
* Copyright © 2009 Alessandro Rubini
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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/init.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/nand_ecc.h>
#include <linux/platform_device.h>
#include <linux/mtd/partitions.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/platform_data/mtd-nomadik-nand.h>
#include <mach/fsmc.h>
#include <mtd/mtd-abi.h>
struct nomadik_nand_host {
struct mtd_info mtd;
struct nand_chip nand;
void __iomem *data_va;
void __iomem *cmd_va;
void __iomem *addr_va;
struct nand_bbt_descr *bbt_desc;
};
static struct nand_ecclayout nomadik_ecc_layout = {
.eccbytes = 3 * 4,
.eccpos = { /* each subpage has 16 bytes: pos 2,3,4 hosts ECC */
0x02, 0x03, 0x04,
0x12, 0x13, 0x14,
0x22, 0x23, 0x24,
0x32, 0x33, 0x34},
/* let's keep bytes 5,6,7 for us, just in case we change ECC algo */
.oobfree = { {0x08, 0x08}, {0x18, 0x08}, {0x28, 0x08}, {0x38, 0x08} },
};
static void nomadik_ecc_control(struct mtd_info *mtd, int mode)
{
/* No need to enable hw ecc, it's on by default */
}
static void nomadik_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
struct nand_chip *nand = mtd->priv;
struct nomadik_nand_host *host = nand->priv;
if (cmd == NAND_CMD_NONE)
return;
if (ctrl & NAND_CLE)
writeb(cmd, host->cmd_va);
else
writeb(cmd, host->addr_va);
}
static int nomadik_nand_probe(struct platform_device *pdev)
{
struct nomadik_nand_platform_data *pdata = pdev->dev.platform_data;
struct nomadik_nand_host *host;
struct mtd_info *mtd;
struct nand_chip *nand;
struct resource *res;
int ret = 0;
/* Allocate memory for the device structure (and zero it) */
host = kzalloc(sizeof(struct nomadik_nand_host), GFP_KERNEL);
if (!host) {
dev_err(&pdev->dev, "Failed to allocate device structure.\n");
return -ENOMEM;
}
/* Call the client's init function, if any */
if (pdata->init)
ret = pdata->init();
if (ret < 0) {
dev_err(&pdev->dev, "Init function failed\n");
goto err;
}
/* ioremap three regions */
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_addr");
if (!res) {
ret = -EIO;
goto err_unmap;
}
host->addr_va = ioremap(res->start, resource_size(res));
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_data");
if (!res) {
ret = -EIO;
goto err_unmap;
}
host->data_va = ioremap(res->start, resource_size(res));
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_cmd");
if (!res) {
ret = -EIO;
goto err_unmap;
}
host->cmd_va = ioremap(res->start, resource_size(res));
if (!host->addr_va || !host->data_va || !host->cmd_va) {
ret = -ENOMEM;
goto err_unmap;
}
/* Link all private pointers */
mtd = &host->mtd;
nand = &host->nand;
mtd->priv = nand;
nand->priv = host;
host->mtd.owner = THIS_MODULE;
nand->IO_ADDR_R = host->data_va;
nand->IO_ADDR_W = host->data_va;
nand->cmd_ctrl = nomadik_cmd_ctrl;
/*
* This stanza declares ECC_HW but uses soft routines. It's because
* HW claims to make the calculation but not the correction. However,
* I haven't managed to get the desired data out of it until now.
*/
nand->ecc.mode = NAND_ECC_SOFT;
nand->ecc.layout = &nomadik_ecc_layout;
nand->ecc.hwctl = nomadik_ecc_control;
nand->ecc.size = 512;
nand->ecc.bytes = 3;
nand->options = pdata->options;
/*
* Scan to find existence of the device
*/
if (nand_scan(&host->mtd, 1)) {
ret = -ENXIO;
goto err_unmap;
}
mtd_device_register(&host->mtd, pdata->parts, pdata->nparts);
platform_set_drvdata(pdev, host);
return 0;
err_unmap:
if (host->cmd_va)
iounmap(host->cmd_va);
if (host->data_va)
iounmap(host->data_va);
if (host->addr_va)
iounmap(host->addr_va);
err:
kfree(host);
return ret;
}
/*
* Clean up routine
*/
static int nomadik_nand_remove(struct platform_device *pdev)
{
struct nomadik_nand_host *host = platform_get_drvdata(pdev);
struct nomadik_nand_platform_data *pdata = pdev->dev.platform_data;
if (pdata->exit)
pdata->exit();
if (host) {
nand_release(&host->mtd);
iounmap(host->cmd_va);
iounmap(host->data_va);
iounmap(host->addr_va);
kfree(host);
}
return 0;
}
static int nomadik_nand_suspend(struct device *dev)
{
struct nomadik_nand_host *host = dev_get_drvdata(dev);
int ret = 0;
if (host)
ret = mtd_suspend(&host->mtd);
return ret;
}
static int nomadik_nand_resume(struct device *dev)
{
struct nomadik_nand_host *host = dev_get_drvdata(dev);
if (host)
mtd_resume(&host->mtd);
return 0;
}
static const struct dev_pm_ops nomadik_nand_pm_ops = {
.suspend = nomadik_nand_suspend,
.resume = nomadik_nand_resume,
};
static struct platform_driver nomadik_nand_driver = {
.probe = nomadik_nand_probe,
.remove = nomadik_nand_remove,
.driver = {
.owner = THIS_MODULE,
.name = "nomadik_nand",
.pm = &nomadik_nand_pm_ops,
},
};
module_platform_driver(nomadik_nand_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("ST Microelectronics (sachin.verma@st.com)");
MODULE_DESCRIPTION("NAND driver for Nomadik Platform");

View File

@ -246,7 +246,7 @@ static void nuc900_nand_enable(struct nuc900_nand *nand)
spin_unlock(&nand->lock);
}
static int __devinit nuc900_nand_probe(struct platform_device *pdev)
static int nuc900_nand_probe(struct platform_device *pdev)
{
struct nuc900_nand *nuc900_nand;
struct nand_chip *chip;
@ -317,7 +317,7 @@ fail1: kfree(nuc900_nand);
return retval;
}
static int __devexit nuc900_nand_remove(struct platform_device *pdev)
static int nuc900_nand_remove(struct platform_device *pdev)
{
struct nuc900_nand *nuc900_nand = platform_get_drvdata(pdev);
struct resource *res;
@ -340,7 +340,7 @@ static int __devexit nuc900_nand_remove(struct platform_device *pdev)
static struct platform_driver nuc900_nand_driver = {
.probe = nuc900_nand_probe,
.remove = __devexit_p(nuc900_nand_remove),
.remove = nuc900_nand_remove,
.driver = {
.name = "nuc900-fmi",
.owner = THIS_MODULE,

View File

@ -1323,7 +1323,7 @@ static void omap3_free_bch(struct mtd_info *mtd)
}
#endif /* CONFIG_MTD_NAND_OMAP_BCH */
static int __devinit omap_nand_probe(struct platform_device *pdev)
static int omap_nand_probe(struct platform_device *pdev)
{
struct omap_nand_info *info;
struct omap_nand_platform_data *pdata;

View File

@ -194,7 +194,7 @@ no_res:
return ret;
}
static int __devexit orion_nand_remove(struct platform_device *pdev)
static int orion_nand_remove(struct platform_device *pdev)
{
struct mtd_info *mtd = platform_get_drvdata(pdev);
struct nand_chip *nc = mtd->priv;
@ -223,7 +223,7 @@ static struct of_device_id orion_nand_of_match_table[] = {
#endif
static struct platform_driver orion_nand_driver = {
.remove = __devexit_p(orion_nand_remove),
.remove = orion_nand_remove,
.driver = {
.name = "orion_nand",
.owner = THIS_MODULE,

View File

@ -89,7 +89,7 @@ int pasemi_device_ready(struct mtd_info *mtd)
return !!(inl(lpcctl) & LBICTRL_LPCCTL_NR);
}
static int __devinit pasemi_nand_probe(struct platform_device *ofdev)
static int pasemi_nand_probe(struct platform_device *ofdev)
{
struct pci_dev *pdev;
struct device_node *np = ofdev->dev.of_node;
@ -184,7 +184,7 @@ static int __devinit pasemi_nand_probe(struct platform_device *ofdev)
return err;
}
static int __devexit pasemi_nand_remove(struct platform_device *ofdev)
static int pasemi_nand_remove(struct platform_device *ofdev)
{
struct nand_chip *chip;

View File

@ -28,7 +28,7 @@ static const char *part_probe_types[] = { "cmdlinepart", NULL };
/*
* Probe for the NAND device.
*/
static int __devinit plat_nand_probe(struct platform_device *pdev)
static int plat_nand_probe(struct platform_device *pdev)
{
struct platform_nand_data *pdata = pdev->dev.platform_data;
struct mtd_part_parser_data ppdata;
@ -134,7 +134,7 @@ out_free:
/*
* Remove a NAND device.
*/
static int __devexit plat_nand_remove(struct platform_device *pdev)
static int plat_nand_remove(struct platform_device *pdev)
{
struct plat_nand_data *data = platform_get_drvdata(pdev);
struct platform_nand_data *pdata = pdev->dev.platform_data;
@ -160,7 +160,7 @@ MODULE_DEVICE_TABLE(of, plat_nand_match);
static struct platform_driver plat_nand_driver = {
.probe = plat_nand_probe,
.remove = __devexit_p(plat_nand_remove),
.remove = plat_nand_remove,
.driver = {
.name = "gen_nand",
.owner = THIS_MODULE,

View File

@ -730,11 +730,14 @@ static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info,
struct s3c2410_nand_mtd *mtd,
struct s3c2410_nand_set *set)
{
if (set)
if (set) {
mtd->mtd.name = set->name;
return mtd_device_parse_register(&mtd->mtd, NULL, NULL,
return mtd_device_parse_register(&mtd->mtd, NULL, NULL,
set->partitions, set->nr_partitions);
}
return -ENODEV;
}
/**

View File

@ -23,11 +23,18 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_mtd.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/sh_dma.h>
#include <linux/slab.h>
#include <linux/string.h>
@ -106,6 +113,84 @@ static void wait_completion(struct sh_flctl *flctl)
writeb(0x0, FLTRCR(flctl));
}
static void flctl_dma_complete(void *param)
{
struct sh_flctl *flctl = param;
complete(&flctl->dma_complete);
}
static void flctl_release_dma(struct sh_flctl *flctl)
{
if (flctl->chan_fifo0_rx) {
dma_release_channel(flctl->chan_fifo0_rx);
flctl->chan_fifo0_rx = NULL;
}
if (flctl->chan_fifo0_tx) {
dma_release_channel(flctl->chan_fifo0_tx);
flctl->chan_fifo0_tx = NULL;
}
}
static void flctl_setup_dma(struct sh_flctl *flctl)
{
dma_cap_mask_t mask;
struct dma_slave_config cfg;
struct platform_device *pdev = flctl->pdev;
struct sh_flctl_platform_data *pdata = pdev->dev.platform_data;
int ret;
if (!pdata)
return;
if (pdata->slave_id_fifo0_tx <= 0 || pdata->slave_id_fifo0_rx <= 0)
return;
/* We can only either use DMA for both Tx and Rx or not use it at all */
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
flctl->chan_fifo0_tx = dma_request_channel(mask, shdma_chan_filter,
(void *)pdata->slave_id_fifo0_tx);
dev_dbg(&pdev->dev, "%s: TX: got channel %p\n", __func__,
flctl->chan_fifo0_tx);
if (!flctl->chan_fifo0_tx)
return;
memset(&cfg, 0, sizeof(cfg));
cfg.slave_id = pdata->slave_id_fifo0_tx;
cfg.direction = DMA_MEM_TO_DEV;
cfg.dst_addr = (dma_addr_t)FLDTFIFO(flctl);
cfg.src_addr = 0;
ret = dmaengine_slave_config(flctl->chan_fifo0_tx, &cfg);
if (ret < 0)
goto err;
flctl->chan_fifo0_rx = dma_request_channel(mask, shdma_chan_filter,
(void *)pdata->slave_id_fifo0_rx);
dev_dbg(&pdev->dev, "%s: RX: got channel %p\n", __func__,
flctl->chan_fifo0_rx);
if (!flctl->chan_fifo0_rx)
goto err;
cfg.slave_id = pdata->slave_id_fifo0_rx;
cfg.direction = DMA_DEV_TO_MEM;
cfg.dst_addr = 0;
cfg.src_addr = (dma_addr_t)FLDTFIFO(flctl);
ret = dmaengine_slave_config(flctl->chan_fifo0_rx, &cfg);
if (ret < 0)
goto err;
init_completion(&flctl->dma_complete);
return;
err:
flctl_release_dma(flctl);
}
static void set_addr(struct mtd_info *mtd, int column, int page_addr)
{
struct sh_flctl *flctl = mtd_to_flctl(mtd);
@ -225,7 +310,7 @@ static enum flctl_ecc_res_t wait_recfifo_ready
for (i = 0; i < 3; i++) {
uint8_t org;
int index;
unsigned int index;
data = readl(ecc_reg[i]);
@ -261,6 +346,70 @@ static void wait_wecfifo_ready(struct sh_flctl *flctl)
timeout_error(flctl, __func__);
}
static int flctl_dma_fifo0_transfer(struct sh_flctl *flctl, unsigned long *buf,
int len, enum dma_data_direction dir)
{
struct dma_async_tx_descriptor *desc = NULL;
struct dma_chan *chan;
enum dma_transfer_direction tr_dir;
dma_addr_t dma_addr;
dma_cookie_t cookie = -EINVAL;
uint32_t reg;
int ret;
if (dir == DMA_FROM_DEVICE) {
chan = flctl->chan_fifo0_rx;
tr_dir = DMA_DEV_TO_MEM;
} else {
chan = flctl->chan_fifo0_tx;
tr_dir = DMA_MEM_TO_DEV;
}
dma_addr = dma_map_single(chan->device->dev, buf, len, dir);
if (dma_addr)
desc = dmaengine_prep_slave_single(chan, dma_addr, len,
tr_dir, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (desc) {
reg = readl(FLINTDMACR(flctl));
reg |= DREQ0EN;
writel(reg, FLINTDMACR(flctl));
desc->callback = flctl_dma_complete;
desc->callback_param = flctl;
cookie = dmaengine_submit(desc);
dma_async_issue_pending(chan);
} else {
/* DMA failed, fall back to PIO */
flctl_release_dma(flctl);
dev_warn(&flctl->pdev->dev,
"DMA failed, falling back to PIO\n");
ret = -EIO;
goto out;
}
ret =
wait_for_completion_timeout(&flctl->dma_complete,
msecs_to_jiffies(3000));
if (ret <= 0) {
chan->device->device_control(chan, DMA_TERMINATE_ALL, 0);
dev_err(&flctl->pdev->dev, "wait_for_completion_timeout\n");
}
out:
reg = readl(FLINTDMACR(flctl));
reg &= ~DREQ0EN;
writel(reg, FLINTDMACR(flctl));
dma_unmap_single(chan->device->dev, dma_addr, len, dir);
/* ret > 0 is success */
return ret;
}
static void read_datareg(struct sh_flctl *flctl, int offset)
{
unsigned long data;
@ -279,11 +428,20 @@ static void read_fiforeg(struct sh_flctl *flctl, int rlen, int offset)
len_4align = (rlen + 3) / 4;
/* initiate DMA transfer */
if (flctl->chan_fifo0_rx && rlen >= 32 &&
flctl_dma_fifo0_transfer(flctl, buf, rlen, DMA_DEV_TO_MEM) > 0)
goto convert; /* DMA success */
/* do polling transfer */
for (i = 0; i < len_4align; i++) {
wait_rfifo_ready(flctl);
buf[i] = readl(FLDTFIFO(flctl));
buf[i] = be32_to_cpu(buf[i]);
}
convert:
for (i = 0; i < len_4align; i++)
buf[i] = be32_to_cpu(buf[i]);
}
static enum flctl_ecc_res_t read_ecfiforeg
@ -305,28 +463,39 @@ static enum flctl_ecc_res_t read_ecfiforeg
return res;
}
static void write_fiforeg(struct sh_flctl *flctl, int rlen, int offset)
static void write_fiforeg(struct sh_flctl *flctl, int rlen,
unsigned int offset)
{
int i, len_4align;
unsigned long *data = (unsigned long *)&flctl->done_buff[offset];
void *fifo_addr = (void *)FLDTFIFO(flctl);
unsigned long *buf = (unsigned long *)&flctl->done_buff[offset];
len_4align = (rlen + 3) / 4;
for (i = 0; i < len_4align; i++) {
wait_wfifo_ready(flctl);
writel(cpu_to_be32(data[i]), fifo_addr);
writel(cpu_to_be32(buf[i]), FLDTFIFO(flctl));
}
}
static void write_ec_fiforeg(struct sh_flctl *flctl, int rlen, int offset)
static void write_ec_fiforeg(struct sh_flctl *flctl, int rlen,
unsigned int offset)
{
int i, len_4align;
unsigned long *data = (unsigned long *)&flctl->done_buff[offset];
unsigned long *buf = (unsigned long *)&flctl->done_buff[offset];
len_4align = (rlen + 3) / 4;
for (i = 0; i < len_4align; i++)
buf[i] = cpu_to_be32(buf[i]);
/* initiate DMA transfer */
if (flctl->chan_fifo0_tx && rlen >= 32 &&
flctl_dma_fifo0_transfer(flctl, buf, rlen, DMA_MEM_TO_DEV) > 0)
return; /* DMA success */
/* do polling transfer */
for (i = 0; i < len_4align; i++) {
wait_wecfifo_ready(flctl);
writel(cpu_to_be32(data[i]), FLECFIFO(flctl));
writel(buf[i], FLECFIFO(flctl));
}
}
@ -750,41 +919,35 @@ static void flctl_select_chip(struct mtd_info *mtd, int chipnr)
static void flctl_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
{
struct sh_flctl *flctl = mtd_to_flctl(mtd);
int index = flctl->index;
memcpy(&flctl->done_buff[index], buf, len);
memcpy(&flctl->done_buff[flctl->index], buf, len);
flctl->index += len;
}
static uint8_t flctl_read_byte(struct mtd_info *mtd)
{
struct sh_flctl *flctl = mtd_to_flctl(mtd);
int index = flctl->index;
uint8_t data;
data = flctl->done_buff[index];
data = flctl->done_buff[flctl->index];
flctl->index++;
return data;
}
static uint16_t flctl_read_word(struct mtd_info *mtd)
{
struct sh_flctl *flctl = mtd_to_flctl(mtd);
int index = flctl->index;
uint16_t data;
uint16_t *buf = (uint16_t *)&flctl->done_buff[index];
struct sh_flctl *flctl = mtd_to_flctl(mtd);
uint16_t *buf = (uint16_t *)&flctl->done_buff[flctl->index];
data = *buf;
flctl->index += 2;
return data;
flctl->index += 2;
return *buf;
}
static void flctl_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
{
struct sh_flctl *flctl = mtd_to_flctl(mtd);
int index = flctl->index;
memcpy(buf, &flctl->done_buff[index], len);
memcpy(buf, &flctl->done_buff[flctl->index], len);
flctl->index += len;
}
@ -858,7 +1021,74 @@ static irqreturn_t flctl_handle_flste(int irq, void *dev_id)
return IRQ_HANDLED;
}
static int __devinit flctl_probe(struct platform_device *pdev)
#ifdef CONFIG_OF
struct flctl_soc_config {
unsigned long flcmncr_val;
unsigned has_hwecc:1;
unsigned use_holden:1;
};
static struct flctl_soc_config flctl_sh7372_config = {
.flcmncr_val = CLK_16B_12L_4H | TYPESEL_SET | SHBUSSEL,
.has_hwecc = 1,
.use_holden = 1,
};
static const struct of_device_id of_flctl_match[] = {
{ .compatible = "renesas,shmobile-flctl-sh7372",
.data = &flctl_sh7372_config },
{},
};
MODULE_DEVICE_TABLE(of, of_flctl_match);
static struct sh_flctl_platform_data *flctl_parse_dt(struct device *dev)
{
const struct of_device_id *match;
struct flctl_soc_config *config;
struct sh_flctl_platform_data *pdata;
struct device_node *dn = dev->of_node;
int ret;
match = of_match_device(of_flctl_match, dev);
if (match)
config = (struct flctl_soc_config *)match->data;
else {
dev_err(dev, "%s: no OF configuration attached\n", __func__);
return NULL;
}
pdata = devm_kzalloc(dev, sizeof(struct sh_flctl_platform_data),
GFP_KERNEL);
if (!pdata) {
dev_err(dev, "%s: failed to allocate config data\n", __func__);
return NULL;
}
/* set SoC specific options */
pdata->flcmncr_val = config->flcmncr_val;
pdata->has_hwecc = config->has_hwecc;
pdata->use_holden = config->use_holden;
/* parse user defined options */
ret = of_get_nand_bus_width(dn);
if (ret == 16)
pdata->flcmncr_val |= SEL_16BIT;
else if (ret != 8) {
dev_err(dev, "%s: invalid bus width\n", __func__);
return NULL;
}
return pdata;
}
#else /* CONFIG_OF */
#define of_flctl_match NULL
static struct sh_flctl_platform_data *flctl_parse_dt(struct device *dev)
{
return NULL;
}
#endif /* CONFIG_OF */
static int flctl_probe(struct platform_device *pdev)
{
struct resource *res;
struct sh_flctl *flctl;
@ -867,12 +1097,7 @@ static int __devinit flctl_probe(struct platform_device *pdev)
struct sh_flctl_platform_data *pdata;
int ret = -ENXIO;
int irq;
pdata = pdev->dev.platform_data;
if (pdata == NULL) {
dev_err(&pdev->dev, "no platform data defined\n");
return -EINVAL;
}
struct mtd_part_parser_data ppdata = {};
flctl = kzalloc(sizeof(struct sh_flctl), GFP_KERNEL);
if (!flctl) {
@ -904,6 +1129,17 @@ static int __devinit flctl_probe(struct platform_device *pdev)
goto err_flste;
}
if (pdev->dev.of_node)
pdata = flctl_parse_dt(&pdev->dev);
else
pdata = pdev->dev.platform_data;
if (!pdata) {
dev_err(&pdev->dev, "no setup data defined\n");
ret = -EINVAL;
goto err_pdata;
}
platform_set_drvdata(pdev, flctl);
flctl_mtd = &flctl->mtd;
nand = &flctl->chip;
@ -932,6 +1168,8 @@ static int __devinit flctl_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
pm_runtime_resume(&pdev->dev);
flctl_setup_dma(flctl);
ret = nand_scan_ident(flctl_mtd, 1, NULL);
if (ret)
goto err_chip;
@ -944,12 +1182,16 @@ static int __devinit flctl_probe(struct platform_device *pdev)
if (ret)
goto err_chip;
mtd_device_register(flctl_mtd, pdata->parts, pdata->nr_parts);
ppdata.of_node = pdev->dev.of_node;
ret = mtd_device_parse_register(flctl_mtd, NULL, &ppdata, pdata->parts,
pdata->nr_parts);
return 0;
err_chip:
flctl_release_dma(flctl);
pm_runtime_disable(&pdev->dev);
err_pdata:
free_irq(irq, flctl);
err_flste:
iounmap(flctl->reg);
@ -958,10 +1200,11 @@ err_iomap:
return ret;
}
static int __devexit flctl_remove(struct platform_device *pdev)
static int flctl_remove(struct platform_device *pdev)
{
struct sh_flctl *flctl = platform_get_drvdata(pdev);
flctl_release_dma(flctl);
nand_release(&flctl->mtd);
pm_runtime_disable(&pdev->dev);
free_irq(platform_get_irq(pdev, 0), flctl);
@ -976,6 +1219,7 @@ static struct platform_driver flctl_driver = {
.driver = {
.name = "sh_flctl",
.owner = THIS_MODULE,
.of_match_table = of_flctl_match,
},
};

View File

@ -106,7 +106,7 @@ static int sharpsl_nand_calculate_ecc(struct mtd_info *mtd, const u_char * dat,
/*
* Main initialization routine
*/
static int __devinit sharpsl_nand_probe(struct platform_device *pdev)
static int sharpsl_nand_probe(struct platform_device *pdev)
{
struct nand_chip *this;
struct resource *r;
@ -205,7 +205,7 @@ err_get_res:
/*
* Clean up routine
*/
static int __devexit sharpsl_nand_remove(struct platform_device *pdev)
static int sharpsl_nand_remove(struct platform_device *pdev)
{
struct sharpsl_nand *sharpsl = platform_get_drvdata(pdev);
@ -228,7 +228,7 @@ static struct platform_driver sharpsl_nand_driver = {
.owner = THIS_MODULE,
},
.probe = sharpsl_nand_probe,
.remove = __devexit_p(sharpsl_nand_remove),
.remove = sharpsl_nand_remove,
};
module_platform_driver(sharpsl_nand_driver);

View File

@ -140,7 +140,7 @@ static int socrates_nand_device_ready(struct mtd_info *mtd)
/*
* Probe for the NAND device.
*/
static int __devinit socrates_nand_probe(struct platform_device *ofdev)
static int socrates_nand_probe(struct platform_device *ofdev)
{
struct socrates_nand_host *host;
struct mtd_info *mtd;
@ -220,7 +220,7 @@ out:
/*
* Remove a NAND device.
*/
static int __devexit socrates_nand_remove(struct platform_device *ofdev)
static int socrates_nand_remove(struct platform_device *ofdev)
{
struct socrates_nand_host *host = dev_get_drvdata(&ofdev->dev);
struct mtd_info *mtd = &host->mtd;
@ -251,7 +251,7 @@ static struct platform_driver socrates_nand_driver = {
.of_match_table = socrates_nand_match,
},
.probe = socrates_nand_probe,
.remove = __devexit_p(socrates_nand_remove),
.remove = socrates_nand_remove,
};
module_platform_driver(socrates_nand_driver);

View File

@ -71,7 +71,10 @@ static int parse_ofpart_partitions(struct mtd_info *master,
(*pparts)[i].name = (char *)partname;
if (of_get_property(pp, "read-only", &len))
(*pparts)[i].mask_flags = MTD_WRITEABLE;
(*pparts)[i].mask_flags |= MTD_WRITEABLE;
if (of_get_property(pp, "lock", &len))
(*pparts)[i].mask_flags |= MTD_POWERUP_LOCK;
i++;
}

View File

@ -35,7 +35,7 @@ struct onenand_info {
struct onenand_chip onenand;
};
static int __devinit generic_onenand_probe(struct platform_device *pdev)
static int generic_onenand_probe(struct platform_device *pdev)
{
struct onenand_info *info;
struct onenand_platform_data *pdata = pdev->dev.platform_data;
@ -88,7 +88,7 @@ out_free_info:
return err;
}
static int __devexit generic_onenand_remove(struct platform_device *pdev)
static int generic_onenand_remove(struct platform_device *pdev)
{
struct onenand_info *info = platform_get_drvdata(pdev);
struct resource *res = pdev->resource;
@ -112,7 +112,7 @@ static struct platform_driver generic_onenand_driver = {
.owner = THIS_MODULE,
},
.probe = generic_onenand_probe,
.remove = __devexit_p(generic_onenand_remove),
.remove = generic_onenand_remove,
};
module_platform_driver(generic_onenand_driver);

View File

@ -630,7 +630,7 @@ static int omap2_onenand_disable(struct mtd_info *mtd)
return ret;
}
static int __devinit omap2_onenand_probe(struct platform_device *pdev)
static int omap2_onenand_probe(struct platform_device *pdev)
{
struct omap_onenand_platform_data *pdata;
struct omap2_onenand *c;
@ -799,7 +799,7 @@ err_kfree:
return r;
}
static int __devexit omap2_onenand_remove(struct platform_device *pdev)
static int omap2_onenand_remove(struct platform_device *pdev)
{
struct omap2_onenand *c = dev_get_drvdata(&pdev->dev);
@ -822,7 +822,7 @@ static int __devexit omap2_onenand_remove(struct platform_device *pdev)
static struct platform_driver omap2_onenand_driver = {
.probe = omap2_onenand_probe,
.remove = __devexit_p(omap2_onenand_remove),
.remove = omap2_onenand_remove,
.shutdown = omap2_onenand_shutdown,
.driver = {
.name = DRIVER_NAME,

Some files were not shown because too many files have changed in this diff Show More