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:
commit
ca2a88f56a
|
@ -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>;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -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>;
|
||||
};
|
|
@ -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>;
|
||||
};
|
||||
};
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
|
@ -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:
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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";
|
||||
};
|
||||
|
||||
|
|
|
@ -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";
|
||||
};
|
||||
|
||||
|
|
|
@ -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";
|
||||
};
|
||||
|
||||
|
|
|
@ -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";
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
|
@ -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 = {
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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 };
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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... */
|
||||
};
|
||||
|
|
|
@ -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>");
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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");
|
|
@ -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,
|
||||
},
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
bcm47xxnflash-y += main.o
|
||||
bcm47xxnflash-y += ops_bcm4706.o
|
||||
|
||||
obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH) += bcm47xxnflash.o
|
|
@ -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 */
|
|
@ -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);
|
|
@ -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;
|
||||
}
|
|
@ -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 = {
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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_*/
|
||||
|
|
|
@ -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");
|
|
@ -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);
|
|
@ -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 };
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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");
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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++;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue