提交 ef9a61be 编写于 作者: L Linus Torvalds

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

Pull mtd updates from David Woodhouse:
 - factor out common code from MTD tests
 - nand-gpio cleanup and portability to non-ARM
 - m25p80 support for 4-byte addressing chips, other new chips
 - pxa3xx cleanup and support for new platforms
 - remove obsolete alauda, octagon-5066 drivers
 - erase/write support for bcm47xxsflash
 - improve detection of ECC requirements for NAND, controller setup
 - NFC acceleration support for atmel-nand, read/write via SRAM
 - etc

* tag 'for-linus-20130909' of git://git.infradead.org/linux-mtd: (184 commits)
  mtd: chips: Add support for PMC SPI Flash chips in m25p80.c
  mtd: ofpart: use for_each_child_of_node() macro
  mtd: mtdswap: replace strict_strtoul() with kstrtoul()
  mtd cs553x_nand: use kzalloc() instead of memset
  mtd: atmel_nand: fix error return code in atmel_nand_probe()
  mtd: bcm47xxsflash: writing support
  mtd: bcm47xxsflash: implement erasing support
  mtd: bcm47xxsflash: convert to module_platform_driver instead of init/exit
  mtd: bcm47xxsflash: convert kzalloc to avoid invalid access
  mtd: remove alauda driver
  mtd: nand: mxc_nand: mark 'const' properly
  mtd: maps: cfi_flagadm: add missing __iomem annotation
  mtd: spear_smi: add missing __iomem annotation
  mtd: r852: Staticize local symbols
  mtd: nandsim: Staticize local symbols
  mtd: impa7: add missing __iomem annotation
  mtd: sm_ftl: Staticize local symbols
  mtd: m25p80: add support for mr25h10
  mtd: m25p80: make CONFIG_M25PXX_USE_FAST_READ safe to enable
  mtd: m25p80: Pass flags through CAT25_INFO macro
  ...
...@@ -128,9 +128,8 @@ KernelVersion: 3.4 ...@@ -128,9 +128,8 @@ KernelVersion: 3.4
Contact: linux-mtd@lists.infradead.org Contact: linux-mtd@lists.infradead.org
Description: Description:
Maximum number of bit errors that the device is capable of Maximum number of bit errors that the device is capable of
correcting within each region covering an ecc step. This will correcting within each region covering an ECC step (see
always be a non-negative integer. Note that some devices will ecc_step_size). This will always be a non-negative integer.
have multiple ecc steps within each writesize region.
In the case of devices lacking any ECC capability, it is 0. In the case of devices lacking any ECC capability, it is 0.
...@@ -173,3 +172,15 @@ Description: ...@@ -173,3 +172,15 @@ Description:
This is generally applicable only to NAND flash devices with ECC This is generally applicable only to NAND flash devices with ECC
capability. It is ignored on devices lacking ECC capability; capability. It is ignored on devices lacking ECC capability;
i.e., devices for which ecc_strength is zero. i.e., devices for which ecc_strength is zero.
What: /sys/class/mtd/mtdX/ecc_step_size
Date: May 2013
KernelVersion: 3.10
Contact: linux-mtd@lists.infradead.org
Description:
The size of a single region covered by ECC, known as the ECC
step. Devices may have several equally sized ECC steps within
each writesize region.
It will always be a non-negative integer. In the case of
devices lacking any ECC capability, it is 0.
...@@ -1224,8 +1224,6 @@ in this page</entry> ...@@ -1224,8 +1224,6 @@ in this page</entry>
#define NAND_BBT_CREATE 0x00000200 #define NAND_BBT_CREATE 0x00000200
/* Search good / bad pattern through all pages of a block */ /* Search good / bad pattern through all pages of a block */
#define NAND_BBT_SCANALLPAGES 0x00000400 #define NAND_BBT_SCANALLPAGES 0x00000400
/* Scan block empty during good / bad block scan */
#define NAND_BBT_SCANEMPTY 0x00000800
/* Write bbt if neccecary */ /* Write bbt if neccecary */
#define NAND_BBT_WRITE 0x00001000 #define NAND_BBT_WRITE 0x00001000
/* Read and write back block contents when writing bbt */ /* Read and write back block contents when writing bbt */
......
...@@ -15,6 +15,7 @@ Required properties: ...@@ -15,6 +15,7 @@ Required properties:
optional gpio and may be set to 0 if not present. optional gpio and may be set to 0 if not present.
Optional properties: Optional properties:
- atmel,nand-has-dma : boolean to support dma transfer for nand read/write.
- nand-ecc-mode : String, operation mode of the NAND ecc mode, soft by default. - nand-ecc-mode : String, operation mode of the NAND ecc mode, soft by default.
Supported values are: "none", "soft", "hw", "hw_syndrome", "hw_oob_first", Supported values are: "none", "soft", "hw", "hw_syndrome", "hw_oob_first",
"soft_bch". "soft_bch".
...@@ -29,6 +30,14 @@ Optional properties: ...@@ -29,6 +30,14 @@ Optional properties:
sector size 1024. sector size 1024.
- nand-bus-width : 8 or 16 bus width if not present 8 - nand-bus-width : 8 or 16 bus width if not present 8
- nand-on-flash-bbt: boolean to enable on flash bbt option if not present false - nand-on-flash-bbt: boolean to enable on flash bbt option if not present false
- Nand Flash Controller(NFC) is a slave driver under Atmel nand flash
- Required properties:
- compatible : "atmel,sama5d3-nfc".
- reg : should specify the address and size used for NFC command registers,
NFC registers and NFC Sram. NFC Sram address and size can be absent
if don't want to use it.
- Optional properties:
- atmel,write-by-sram: boolean to enable NFC write by sram.
Examples: Examples:
nand0: nand@40000000,0 { nand0: nand@40000000,0 {
...@@ -77,3 +86,22 @@ nand0: nand@40000000 { ...@@ -77,3 +86,22 @@ nand0: nand@40000000 {
... ...
}; };
}; };
/* for NFC supported chips */
nand0: nand@40000000 {
compatible = "atmel,at91rm9200-nand";
#address-cells = <1>;
#size-cells = <1>;
ranges;
...
nfc@70000000 {
compatible = "atmel,sama5d3-nfc";
#address-cells = <1>;
#size-cells = <1>;
reg = <
0x70000000 0x10000000 /* NFC Command Registers */
0xffffc000 0x00000070 /* NFC HSMC regs */
0x00200000 0x00100000 /* NFC SRAM banks */
>;
};
};
* FSMC NAND ST Microelectronics Flexible Static Memory Controller (FSMC)
NAND Interface
Required properties: Required properties:
- compatible : "st,spear600-fsmc-nand", "stericsson,fsmc-nand" - compatible : "st,spear600-fsmc-nand", "stericsson,fsmc-nand"
...@@ -9,6 +10,26 @@ Optional properties: ...@@ -9,6 +10,26 @@ Optional properties:
- bank-width : Width (in bytes) of the device. If not present, the width - bank-width : Width (in bytes) of the device. If not present, the width
defaults to 1 byte defaults to 1 byte
- nand-skip-bbtscan: Indicates the the BBT scanning should be skipped - nand-skip-bbtscan: Indicates the the BBT scanning should be skipped
- timings: array of 6 bytes for NAND timings. The meanings of these bytes
are:
byte 0 TCLR : CLE to RE delay in number of AHB clock cycles, only 4 bits
are valid. Zero means one clockcycle, 15 means 16 clock
cycles.
byte 1 TAR : ALE to RE delay, 4 bits are valid. Same format as TCLR.
byte 2 THIZ : number of HCLK clock cycles during which the data bus is
kept in Hi-Z (tristate) after the start of a write access.
Only valid for write transactions. Zero means zero cycles,
255 means 255 cycles.
byte 3 THOLD : number of HCLK clock cycles to hold the address (and data
when writing) after the command deassertation. Zero means
one cycle, 255 means 256 cycles.
byte 4 TWAIT : number of HCLK clock cycles to assert the command to the
NAND flash in response to SMWAITn. Zero means 1 cycle,
255 means 256 cycles.
byte 5 TSET : number of HCLK clock cycles to assert the address before the
command is asserted. Zero means one cycle, 255 means 256
cycles.
- bank: default NAND bank to use (0-3 are valid, 0 is the default).
Example: Example:
...@@ -24,6 +45,8 @@ Example: ...@@ -24,6 +45,8 @@ Example:
bank-width = <1>; bank-width = <1>;
nand-skip-bbtscan; nand-skip-bbtscan;
timings = /bits/ 8 <0 0 0 2 3 0>;
bank = <1>;
partition@0 { partition@0 {
... ...
......
...@@ -4,6 +4,7 @@ Partitions can be represented by sub-nodes of an mtd device. This can be used ...@@ -4,6 +4,7 @@ Partitions can be represented by sub-nodes of an mtd device. This can be used
on platforms which have strong conventions about which portions of a flash are on platforms which have strong conventions about which portions of a flash are
used for what purposes, but which don't use an on-flash partition table such used for what purposes, but which don't use an on-flash partition table such
as RedBoot. as RedBoot.
NOTE: if the sub-node has a compatible string, then it is not a partition.
#address-cells & #size-cells must both be present in the mtd device. There are #address-cells & #size-cells must both be present in the mtd device. There are
two valid values for both: two valid values for both:
......
...@@ -1983,6 +1983,9 @@ at32_add_device_nand(unsigned int id, struct atmel_nand_data *data) ...@@ -1983,6 +1983,9 @@ at32_add_device_nand(unsigned int id, struct atmel_nand_data *data)
ARRAY_SIZE(smc_cs3_resource))) ARRAY_SIZE(smc_cs3_resource)))
goto fail; goto fail;
/* For at32ap7000, we use the reset workaround for nand driver */
data->need_reset_workaround = true;
if (platform_device_add_data(pdev, data, if (platform_device_add_data(pdev, data,
sizeof(struct atmel_nand_data))) sizeof(struct atmel_nand_data)))
goto fail; goto fail;
......
...@@ -35,6 +35,8 @@ struct bcm963xx_nvram { ...@@ -35,6 +35,8 @@ struct bcm963xx_nvram {
u32 checksum_high; u32 checksum_high;
}; };
#define BCM63XX_DEFAULT_PSI_SIZE 64
static struct bcm963xx_nvram nvram; static struct bcm963xx_nvram nvram;
static int mac_addr_used; static int mac_addr_used;
...@@ -114,3 +116,12 @@ int bcm63xx_nvram_get_mac_address(u8 *mac) ...@@ -114,3 +116,12 @@ int bcm63xx_nvram_get_mac_address(u8 *mac)
return 0; return 0;
} }
EXPORT_SYMBOL(bcm63xx_nvram_get_mac_address); EXPORT_SYMBOL(bcm63xx_nvram_get_mac_address);
int bcm63xx_nvram_get_psi_size(void)
{
if (nvram.psi_size > 0)
return nvram.psi_size;
return BCM63XX_DEFAULT_PSI_SIZE;
}
EXPORT_SYMBOL(bcm63xx_nvram_get_psi_size);
...@@ -30,4 +30,6 @@ u8 *bcm63xx_nvram_get_name(void); ...@@ -30,4 +30,6 @@ u8 *bcm63xx_nvram_get_name(void);
*/ */
int bcm63xx_nvram_get_mac_address(u8 *mac); int bcm63xx_nvram_get_mac_address(u8 *mac);
int bcm63xx_nvram_get_psi_size(void);
#endif /* BCM63XX_NVRAM_H */ #endif /* BCM63XX_NVRAM_H */
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* Copyright © 2006-2008 Florian Fainelli <florian@openwrt.org> * Copyright © 2006-2008 Florian Fainelli <florian@openwrt.org>
* Mike Albon <malbon@openwrt.org> * Mike Albon <malbon@openwrt.org>
* Copyright © 2009-2010 Daniel Dickinson <openwrt@cshore.neomailbox.net> * Copyright © 2009-2010 Daniel Dickinson <openwrt@cshore.neomailbox.net>
* Copyright © 2011-2012 Jonas Gorski <jonas.gorski@gmail.com> * Copyright © 2011-2013 Jonas Gorski <jonas.gorski@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
...@@ -27,17 +27,19 @@ ...@@ -27,17 +27,19 @@
#include <linux/crc32.h> #include <linux/crc32.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/sizes.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/mtd/mtd.h> #include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h> #include <linux/mtd/partitions.h>
#include <asm/mach-bcm63xx/bcm63xx_nvram.h>
#include <asm/mach-bcm63xx/bcm963xx_tag.h> #include <asm/mach-bcm63xx/bcm963xx_tag.h>
#include <asm/mach-bcm63xx/board_bcm963xx.h> #include <asm/mach-bcm63xx/board_bcm963xx.h>
#define BCM63XX_EXTENDED_SIZE 0xBFC00000 /* Extended flash address */ #define BCM63XX_EXTENDED_SIZE 0xBFC00000 /* Extended flash address */
#define BCM63XX_CFE_BLOCK_SIZE 0x10000 /* always at least 64KiB */ #define BCM63XX_CFE_BLOCK_SIZE SZ_64K /* always at least 64KiB */
#define BCM63XX_CFE_MAGIC_OFFSET 0x4e0 #define BCM63XX_CFE_MAGIC_OFFSET 0x4e0
...@@ -90,7 +92,8 @@ static int bcm63xx_parse_cfe_partitions(struct mtd_info *master, ...@@ -90,7 +92,8 @@ static int bcm63xx_parse_cfe_partitions(struct mtd_info *master,
BCM63XX_CFE_BLOCK_SIZE); BCM63XX_CFE_BLOCK_SIZE);
cfelen = cfe_erasesize; cfelen = cfe_erasesize;
nvramlen = cfe_erasesize; nvramlen = bcm63xx_nvram_get_psi_size() * SZ_1K;
nvramlen = roundup(nvramlen, cfe_erasesize);
/* Allocate memory for buffer */ /* Allocate memory for buffer */
buf = vmalloc(sizeof(struct bcm_tag)); buf = vmalloc(sizeof(struct bcm_tag));
......
...@@ -1571,8 +1571,8 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, ...@@ -1571,8 +1571,8 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
xip_enable(map, chip, adr); xip_enable(map, chip, adr);
/* FIXME - should have reset delay before continuing */ /* FIXME - should have reset delay before continuing */
printk(KERN_WARNING "MTD %s(): software timeout\n", printk(KERN_WARNING "MTD %s(): software timeout, address:0x%.8lx.\n",
__func__ ); __func__, adr);
ret = -EIO; ret = -EIO;
op_done: op_done:
......
...@@ -211,9 +211,7 @@ static inline struct mtd_info *cfi_cmdset_unknown(struct map_info *map, ...@@ -211,9 +211,7 @@ static inline struct mtd_info *cfi_cmdset_unknown(struct map_info *map,
probe_function = __symbol_get(probename); probe_function = __symbol_get(probename);
if (!probe_function) { if (!probe_function) {
char modname[sizeof("cfi_cmdset_%4.4X")]; request_module("cfi_cmdset_%4.4X", type);
sprintf(modname, "cfi_cmdset_%4.4X", type);
request_module(modname);
probe_function = __symbol_get(probename); probe_function = __symbol_get(probename);
} }
......
...@@ -120,7 +120,7 @@ ...@@ -120,7 +120,7 @@
#define PM49FL008 0x006A #define PM49FL008 0x006A
/* Sharp */ /* Sharp */
#define LH28F640BF 0x00b0 #define LH28F640BF 0x00B0
/* ST - www.st.com */ /* ST - www.st.com */
#define M29F800AB 0x0058 #define M29F800AB 0x0058
...@@ -1299,13 +1299,14 @@ static const struct amd_flash_info jedec_table[] = { ...@@ -1299,13 +1299,14 @@ static const struct amd_flash_info jedec_table[] = {
.mfr_id = CFI_MFR_SHARP, .mfr_id = CFI_MFR_SHARP,
.dev_id = LH28F640BF, .dev_id = LH28F640BF,
.name = "LH28F640BF", .name = "LH28F640BF",
.devtypes = CFI_DEVICETYPE_X8, .devtypes = CFI_DEVICETYPE_X16,
.uaddr = MTD_UADDR_UNNECESSARY, .uaddr = MTD_UADDR_UNNECESSARY,
.dev_size = SIZE_4MiB, .dev_size = SIZE_8MiB,
.cmd_set = P_ID_INTEL_STD, .cmd_set = P_ID_INTEL_EXT,
.nr_regions = 1, .nr_regions = 2,
.regions = { .regions = {
ERASEINFO(0x40000,16), ERASEINFO(0x10000, 127),
ERASEINFO(0x02000, 8),
} }
}, { }, {
.mfr_id = CFI_MFR_SST, .mfr_id = CFI_MFR_SST,
......
...@@ -224,59 +224,4 @@ config BCH_CONST_T ...@@ -224,59 +224,4 @@ config BCH_CONST_T
default 4 default 4
endif endif
config MTD_DOCPROBE
tristate
select MTD_DOCECC
config MTD_DOCECC
tristate
config MTD_DOCPROBE_ADVANCED
bool "Advanced detection options for DiskOnChip"
depends on MTD_DOCPROBE
help
This option allows you to specify nonstandard address at which to
probe for a DiskOnChip, or to change the detection options. You
are unlikely to need any of this unless you are using LinuxBIOS.
Say 'N'.
config MTD_DOCPROBE_ADDRESS
hex "Physical address of DiskOnChip" if MTD_DOCPROBE_ADVANCED
depends on MTD_DOCPROBE
default "0x0"
---help---
By default, the probe for DiskOnChip devices will look for a
DiskOnChip at every multiple of 0x2000 between 0xC8000 and 0xEE000.
This option allows you to specify a single address at which to probe
for the device, which is useful if you have other devices in that
range which get upset when they are probed.
(Note that on PowerPC, the normal probe will only check at
0xE4000000.)
Normally, you should leave this set to zero, to allow the probe at
the normal addresses.
config MTD_DOCPROBE_HIGH
bool "Probe high addresses"
depends on MTD_DOCPROBE_ADVANCED
help
By default, the probe for DiskOnChip devices will look for a
DiskOnChip at every multiple of 0x2000 between 0xC8000 and 0xEE000.
This option changes to make it probe between 0xFFFC8000 and
0xFFFEE000. Unless you are using LinuxBIOS, this is unlikely to be
useful to you. Say 'N'.
config MTD_DOCPROBE_55AA
bool "Probe for 0x55 0xAA BIOS Extension Signature"
depends on MTD_DOCPROBE_ADVANCED
help
Check for the 0x55 0xAA signature of a DiskOnChip, and do not
continue with probing if it is absent. The signature will always be
present for a DiskOnChip 2000 or a normal DiskOnChip Millennium.
Only if you have overwritten the first block of a DiskOnChip
Millennium will it be absent. Enable this option if you are using
LinuxBIOS or if you need to recover a DiskOnChip Millennium on which
you have managed to wipe the first block.
endmenu endmenu
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/delay.h>
#include <linux/mtd/mtd.h> #include <linux/mtd/mtd.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/bcma/bcma.h> #include <linux/bcma/bcma.h>
...@@ -12,6 +13,93 @@ MODULE_DESCRIPTION("Serial flash driver for BCMA bus"); ...@@ -12,6 +13,93 @@ MODULE_DESCRIPTION("Serial flash driver for BCMA bus");
static const char * const probes[] = { "bcm47xxpart", NULL }; static const char * const probes[] = { "bcm47xxpart", NULL };
/**************************************************
* Various helpers
**************************************************/
static void bcm47xxsflash_cmd(struct bcm47xxsflash *b47s, u32 opcode)
{
int i;
b47s->cc_write(b47s, BCMA_CC_FLASHCTL, BCMA_CC_FLASHCTL_START | opcode);
for (i = 0; i < 1000; i++) {
if (!(b47s->cc_read(b47s, BCMA_CC_FLASHCTL) &
BCMA_CC_FLASHCTL_BUSY))
return;
cpu_relax();
}
pr_err("Control command failed (timeout)!\n");
}
static int bcm47xxsflash_poll(struct bcm47xxsflash *b47s, int timeout)
{
unsigned long deadline = jiffies + timeout;
do {
switch (b47s->type) {
case BCM47XXSFLASH_TYPE_ST:
bcm47xxsflash_cmd(b47s, OPCODE_ST_RDSR);
if (!(b47s->cc_read(b47s, BCMA_CC_FLASHDATA) &
SR_ST_WIP))
return 0;
break;
case BCM47XXSFLASH_TYPE_ATMEL:
bcm47xxsflash_cmd(b47s, OPCODE_AT_STATUS);
if (b47s->cc_read(b47s, BCMA_CC_FLASHDATA) &
SR_AT_READY)
return 0;
break;
}
cpu_relax();
udelay(1);
} while (!time_after_eq(jiffies, deadline));
pr_err("Timeout waiting for flash to be ready!\n");
return -EBUSY;
}
/**************************************************
* MTD ops
**************************************************/
static int bcm47xxsflash_erase(struct mtd_info *mtd, struct erase_info *erase)
{
struct bcm47xxsflash *b47s = mtd->priv;
int err;
switch (b47s->type) {
case BCM47XXSFLASH_TYPE_ST:
bcm47xxsflash_cmd(b47s, OPCODE_ST_WREN);
b47s->cc_write(b47s, BCMA_CC_FLASHADDR, erase->addr);
/* Newer flashes have "sub-sectors" which can be erased
* independently with a new command: ST_SSE. The ST_SE command
* erases 64KB just as before.
*/
if (b47s->blocksize < (64 * 1024))
bcm47xxsflash_cmd(b47s, OPCODE_ST_SSE);
else
bcm47xxsflash_cmd(b47s, OPCODE_ST_SE);
break;
case BCM47XXSFLASH_TYPE_ATMEL:
b47s->cc_write(b47s, BCMA_CC_FLASHADDR, erase->addr << 1);
bcm47xxsflash_cmd(b47s, OPCODE_AT_PAGE_ERASE);
break;
}
err = bcm47xxsflash_poll(b47s, HZ);
if (err)
erase->state = MTD_ERASE_FAILED;
else
erase->state = MTD_ERASE_DONE;
if (erase->callback)
erase->callback(erase);
return err;
}
static int bcm47xxsflash_read(struct mtd_info *mtd, loff_t from, size_t len, static int bcm47xxsflash_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf) size_t *retlen, u_char *buf)
{ {
...@@ -28,6 +116,127 @@ static int bcm47xxsflash_read(struct mtd_info *mtd, loff_t from, size_t len, ...@@ -28,6 +116,127 @@ static int bcm47xxsflash_read(struct mtd_info *mtd, loff_t from, size_t len,
return len; return len;
} }
static int bcm47xxsflash_write_st(struct mtd_info *mtd, u32 offset, size_t len,
const u_char *buf)
{
struct bcm47xxsflash *b47s = mtd->priv;
int written = 0;
/* Enable writes */
bcm47xxsflash_cmd(b47s, OPCODE_ST_WREN);
/* Write first byte */
b47s->cc_write(b47s, BCMA_CC_FLASHADDR, offset);
b47s->cc_write(b47s, BCMA_CC_FLASHDATA, *buf++);
/* Program page */
if (b47s->bcma_cc->core->id.rev < 20) {
bcm47xxsflash_cmd(b47s, OPCODE_ST_PP);
return 1; /* 1B written */
}
/* Program page and set CSA (on newer chips we can continue writing) */
bcm47xxsflash_cmd(b47s, OPCODE_ST_CSA | OPCODE_ST_PP);
offset++;
len--;
written++;
while (len > 0) {
/* Page boundary, another function call is needed */
if ((offset & 0xFF) == 0)
break;
bcm47xxsflash_cmd(b47s, OPCODE_ST_CSA | *buf++);
offset++;
len--;
written++;
}
/* All done, drop CSA & poll */
b47s->cc_write(b47s, BCMA_CC_FLASHCTL, 0);
udelay(1);
if (bcm47xxsflash_poll(b47s, HZ / 10))
pr_err("Flash rejected dropping CSA\n");
return written;
}
static int bcm47xxsflash_write_at(struct mtd_info *mtd, u32 offset, size_t len,
const u_char *buf)
{
struct bcm47xxsflash *b47s = mtd->priv;
u32 mask = b47s->blocksize - 1;
u32 page = (offset & ~mask) << 1;
u32 byte = offset & mask;
int written = 0;
/* If we don't overwrite whole page, read it to the buffer first */
if (byte || (len < b47s->blocksize)) {
int err;
b47s->cc_write(b47s, BCMA_CC_FLASHADDR, page);
bcm47xxsflash_cmd(b47s, OPCODE_AT_BUF1_LOAD);
/* 250 us for AT45DB321B */
err = bcm47xxsflash_poll(b47s, HZ / 1000);
if (err) {
pr_err("Timeout reading page 0x%X info buffer\n", page);
return err;
}
}
/* Change buffer content with our data */
while (len > 0) {
/* Page boundary, another function call is needed */
if (byte == b47s->blocksize)
break;
b47s->cc_write(b47s, BCMA_CC_FLASHADDR, byte++);
b47s->cc_write(b47s, BCMA_CC_FLASHDATA, *buf++);
bcm47xxsflash_cmd(b47s, OPCODE_AT_BUF1_WRITE);
len--;
written++;
}
/* Program page with the buffer content */
b47s->cc_write(b47s, BCMA_CC_FLASHADDR, page);
bcm47xxsflash_cmd(b47s, OPCODE_AT_BUF1_PROGRAM);
return written;
}
static int bcm47xxsflash_write(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf)
{
struct bcm47xxsflash *b47s = mtd->priv;
int written;
/* Writing functions can return without writing all passed data, for
* example when the hardware is too old or when we git page boundary.
*/
while (len > 0) {
switch (b47s->type) {
case BCM47XXSFLASH_TYPE_ST:
written = bcm47xxsflash_write_st(mtd, to, len, buf);
break;
case BCM47XXSFLASH_TYPE_ATMEL:
written = bcm47xxsflash_write_at(mtd, to, len, buf);
break;
default:
BUG_ON(1);
}
if (written < 0) {
pr_err("Error writing at offset 0x%llX\n", to);
return written;
}
to += (loff_t)written;
len -= written;
*retlen += written;
buf += written;
}
return 0;
}
static void bcm47xxsflash_fill_mtd(struct bcm47xxsflash *b47s) static void bcm47xxsflash_fill_mtd(struct bcm47xxsflash *b47s)
{ {
struct mtd_info *mtd = &b47s->mtd; struct mtd_info *mtd = &b47s->mtd;
...@@ -35,33 +244,48 @@ static void bcm47xxsflash_fill_mtd(struct bcm47xxsflash *b47s) ...@@ -35,33 +244,48 @@ static void bcm47xxsflash_fill_mtd(struct bcm47xxsflash *b47s)
mtd->priv = b47s; mtd->priv = b47s;
mtd->name = "bcm47xxsflash"; mtd->name = "bcm47xxsflash";
mtd->owner = THIS_MODULE; mtd->owner = THIS_MODULE;
mtd->type = MTD_ROM;
mtd->type = MTD_NORFLASH;
mtd->flags = MTD_CAP_NORFLASH;
mtd->size = b47s->size; mtd->size = b47s->size;
mtd->_read = bcm47xxsflash_read; mtd->erasesize = b47s->blocksize;
mtd->writesize = 1;
mtd->writebufsize = 1;
/* TODO: implement writing support and verify/change following code */ mtd->_erase = bcm47xxsflash_erase;
mtd->flags = MTD_CAP_ROM; mtd->_read = bcm47xxsflash_read;
mtd->writebufsize = mtd->writesize = 1; mtd->_write = bcm47xxsflash_write;
} }
/************************************************** /**************************************************
* BCMA * BCMA
**************************************************/ **************************************************/
static int bcm47xxsflash_bcma_cc_read(struct bcm47xxsflash *b47s, u16 offset)
{
return bcma_cc_read32(b47s->bcma_cc, offset);
}
static void bcm47xxsflash_bcma_cc_write(struct bcm47xxsflash *b47s, u16 offset,
u32 value)
{
bcma_cc_write32(b47s->bcma_cc, offset, value);
}
static int bcm47xxsflash_bcma_probe(struct platform_device *pdev) static int bcm47xxsflash_bcma_probe(struct platform_device *pdev)
{ {
struct bcma_sflash *sflash = dev_get_platdata(&pdev->dev); struct bcma_sflash *sflash = dev_get_platdata(&pdev->dev);
struct bcm47xxsflash *b47s; struct bcm47xxsflash *b47s;
int err; int err;
b47s = kzalloc(sizeof(*b47s), GFP_KERNEL); b47s = devm_kzalloc(&pdev->dev, sizeof(*b47s), GFP_KERNEL);
if (!b47s) { if (!b47s)
err = -ENOMEM; return -ENOMEM;
goto out;
}
sflash->priv = b47s; sflash->priv = b47s;
b47s->bcma_cc = container_of(sflash, struct bcma_drv_cc, sflash); b47s->bcma_cc = container_of(sflash, struct bcma_drv_cc, sflash);
b47s->cc_read = bcm47xxsflash_bcma_cc_read;
b47s->cc_write = bcm47xxsflash_bcma_cc_write;
switch (b47s->bcma_cc->capabilities & BCMA_CC_CAP_FLASHT) { switch (b47s->bcma_cc->capabilities & BCMA_CC_CAP_FLASHT) {
case BCMA_CC_FLASHT_STSER: case BCMA_CC_FLASHT_STSER:
...@@ -81,15 +305,13 @@ static int bcm47xxsflash_bcma_probe(struct platform_device *pdev) ...@@ -81,15 +305,13 @@ static int bcm47xxsflash_bcma_probe(struct platform_device *pdev)
err = mtd_device_parse_register(&b47s->mtd, probes, NULL, NULL, 0); err = mtd_device_parse_register(&b47s->mtd, probes, NULL, NULL, 0);
if (err) { if (err) {
pr_err("Failed to register MTD device: %d\n", err); pr_err("Failed to register MTD device: %d\n", err);
goto err_dev_reg; return err;
} }
return 0; if (bcm47xxsflash_poll(b47s, HZ / 10))
pr_warn("Serial flash busy\n");
err_dev_reg: return 0;
kfree(&b47s->mtd);
out:
return err;
} }
static int bcm47xxsflash_bcma_remove(struct platform_device *pdev) static int bcm47xxsflash_bcma_remove(struct platform_device *pdev)
...@@ -98,7 +320,6 @@ static int bcm47xxsflash_bcma_remove(struct platform_device *pdev) ...@@ -98,7 +320,6 @@ static int bcm47xxsflash_bcma_remove(struct platform_device *pdev)
struct bcm47xxsflash *b47s = sflash->priv; struct bcm47xxsflash *b47s = sflash->priv;
mtd_device_unregister(&b47s->mtd); mtd_device_unregister(&b47s->mtd);
kfree(b47s);
return 0; return 0;
} }
...@@ -116,22 +337,4 @@ static struct platform_driver bcma_sflash_driver = { ...@@ -116,22 +337,4 @@ static struct platform_driver bcma_sflash_driver = {
* Init * Init
**************************************************/ **************************************************/
static int __init bcm47xxsflash_init(void) module_platform_driver(bcma_sflash_driver);
{
int err;
err = platform_driver_register(&bcma_sflash_driver);
if (err)
pr_err("Failed to register BCMA serial flash driver: %d\n",
err);
return err;
}
static void __exit bcm47xxsflash_exit(void)
{
platform_driver_unregister(&bcma_sflash_driver);
}
module_init(bcm47xxsflash_init);
module_exit(bcm47xxsflash_exit);
...@@ -60,6 +60,8 @@ enum bcm47xxsflash_type { ...@@ -60,6 +60,8 @@ enum bcm47xxsflash_type {
struct bcm47xxsflash { struct bcm47xxsflash {
struct bcma_drv_cc *bcma_cc; struct bcma_drv_cc *bcma_cc;
int (*cc_read)(struct bcm47xxsflash *b47s, u16 offset);
void (*cc_write)(struct bcm47xxsflash *b47s, u16 offset, u32 value);
enum bcm47xxsflash_type type; enum bcm47xxsflash_type type;
......
...@@ -6,6 +6,9 @@ ...@@ -6,6 +6,9 @@
* *
* Licence: GPL * Licence: GPL
*/ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h> #include <linux/module.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/blkdev.h> #include <linux/blkdev.h>
...@@ -18,10 +21,6 @@ ...@@ -18,10 +21,6 @@
#include <linux/mount.h> #include <linux/mount.h>
#include <linux/slab.h> #include <linux/slab.h>
#define ERROR(fmt, args...) printk(KERN_ERR "block2mtd: " fmt "\n" , ## args)
#define INFO(fmt, args...) printk(KERN_INFO "block2mtd: " fmt "\n" , ## args)
/* Info for the block device */ /* Info for the block device */
struct block2mtd_dev { struct block2mtd_dev {
struct list_head list; struct list_head list;
...@@ -84,7 +83,7 @@ static int block2mtd_erase(struct mtd_info *mtd, struct erase_info *instr) ...@@ -84,7 +83,7 @@ static int block2mtd_erase(struct mtd_info *mtd, struct erase_info *instr)
err = _block2mtd_erase(dev, from, len); err = _block2mtd_erase(dev, from, len);
mutex_unlock(&dev->write_mutex); mutex_unlock(&dev->write_mutex);
if (err) { if (err) {
ERROR("erase failed err = %d", err); pr_err("erase failed err = %d\n", err);
instr->state = MTD_ERASE_FAILED; instr->state = MTD_ERASE_FAILED;
} else } else
instr->state = MTD_ERASE_DONE; instr->state = MTD_ERASE_DONE;
...@@ -239,13 +238,13 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size) ...@@ -239,13 +238,13 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size)
#endif #endif
if (IS_ERR(bdev)) { if (IS_ERR(bdev)) {
ERROR("error: cannot open device %s", devname); pr_err("error: cannot open device %s\n", devname);
goto devinit_err; goto devinit_err;
} }
dev->blkdev = bdev; dev->blkdev = bdev;
if (MAJOR(bdev->bd_dev) == MTD_BLOCK_MAJOR) { if (MAJOR(bdev->bd_dev) == MTD_BLOCK_MAJOR) {
ERROR("attempting to use an MTD device as a block device"); pr_err("attempting to use an MTD device as a block device\n");
goto devinit_err; goto devinit_err;
} }
...@@ -277,9 +276,10 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size) ...@@ -277,9 +276,10 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size)
goto devinit_err; goto devinit_err;
} }
list_add(&dev->list, &blkmtd_device_list); list_add(&dev->list, &blkmtd_device_list);
INFO("mtd%d: [%s] erase_size = %dKiB [%d]", dev->mtd.index, pr_info("mtd%d: [%s] erase_size = %dKiB [%d]\n",
dev->mtd.name + strlen("block2mtd: "), dev->mtd.index,
dev->mtd.erasesize >> 10, dev->mtd.erasesize); dev->mtd.name + strlen("block2mtd: "),
dev->mtd.erasesize >> 10, dev->mtd.erasesize);
return dev; return dev;
devinit_err: devinit_err:
...@@ -339,17 +339,11 @@ static inline void kill_final_newline(char *str) ...@@ -339,17 +339,11 @@ static inline void kill_final_newline(char *str)
} }
#define parse_err(fmt, args...) do { \
ERROR(fmt, ## args); \
return 0; \
} while (0)
#ifndef MODULE #ifndef MODULE
static int block2mtd_init_called = 0; static int block2mtd_init_called = 0;
static char block2mtd_paramline[80 + 12]; /* 80 for device, 12 for erase size */ static char block2mtd_paramline[80 + 12]; /* 80 for device, 12 for erase size */
#endif #endif
static int block2mtd_setup2(const char *val) static int block2mtd_setup2(const char *val)
{ {
char buf[80 + 12]; /* 80 for device, 12 for erase size */ char buf[80 + 12]; /* 80 for device, 12 for erase size */
...@@ -359,8 +353,10 @@ static int block2mtd_setup2(const char *val) ...@@ -359,8 +353,10 @@ static int block2mtd_setup2(const char *val)
size_t erase_size = PAGE_SIZE; size_t erase_size = PAGE_SIZE;
int i, ret; int i, ret;
if (strnlen(val, sizeof(buf)) >= sizeof(buf)) if (strnlen(val, sizeof(buf)) >= sizeof(buf)) {
parse_err("parameter too long"); pr_err("parameter too long\n");
return 0;
}
strcpy(str, val); strcpy(str, val);
kill_final_newline(str); kill_final_newline(str);
...@@ -368,20 +364,27 @@ static int block2mtd_setup2(const char *val) ...@@ -368,20 +364,27 @@ static int block2mtd_setup2(const char *val)
for (i = 0; i < 2; i++) for (i = 0; i < 2; i++)
token[i] = strsep(&str, ","); token[i] = strsep(&str, ",");
if (str) if (str) {
parse_err("too many arguments"); pr_err("too many arguments\n");
return 0;
}
if (!token[0]) if (!token[0]) {
parse_err("no argument"); pr_err("no argument\n");
return 0;
}
name = token[0]; name = token[0];
if (strlen(name) + 1 > 80) if (strlen(name) + 1 > 80) {
parse_err("device name too long"); pr_err("device name too long\n");
return 0;
}
if (token[1]) { if (token[1]) {
ret = parse_num(&erase_size, token[1]); ret = parse_num(&erase_size, token[1]);
if (ret) { if (ret) {
parse_err("illegal erase size"); pr_err("illegal erase size\n");
return 0;
} }
} }
...@@ -444,8 +447,9 @@ static void block2mtd_exit(void) ...@@ -444,8 +447,9 @@ static void block2mtd_exit(void)
struct block2mtd_dev *dev = list_entry(pos, typeof(*dev), list); struct block2mtd_dev *dev = list_entry(pos, typeof(*dev), list);
block2mtd_sync(&dev->mtd); block2mtd_sync(&dev->mtd);
mtd_device_unregister(&dev->mtd); mtd_device_unregister(&dev->mtd);
INFO("mtd%d: [%s] removed", dev->mtd.index, pr_info("mtd%d: [%s] removed\n",
dev->mtd.name + strlen("block2mtd: ")); dev->mtd.index,
dev->mtd.name + strlen("block2mtd: "));
list_del(&dev->list); list_del(&dev->list);
block2mtd_free_device(dev); block2mtd_free_device(dev);
} }
......
...@@ -20,14 +20,21 @@ ...@@ -20,14 +20,21 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/sched.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/platform_data/elm.h> #include <linux/platform_data/elm.h>
#define ELM_SYSCONFIG 0x010
#define ELM_IRQSTATUS 0x018 #define ELM_IRQSTATUS 0x018
#define ELM_IRQENABLE 0x01c #define ELM_IRQENABLE 0x01c
#define ELM_LOCATION_CONFIG 0x020 #define ELM_LOCATION_CONFIG 0x020
#define ELM_PAGE_CTRL 0x080 #define ELM_PAGE_CTRL 0x080
#define ELM_SYNDROME_FRAGMENT_0 0x400 #define ELM_SYNDROME_FRAGMENT_0 0x400
#define ELM_SYNDROME_FRAGMENT_1 0x404
#define ELM_SYNDROME_FRAGMENT_2 0x408
#define ELM_SYNDROME_FRAGMENT_3 0x40c
#define ELM_SYNDROME_FRAGMENT_4 0x410
#define ELM_SYNDROME_FRAGMENT_5 0x414
#define ELM_SYNDROME_FRAGMENT_6 0x418 #define ELM_SYNDROME_FRAGMENT_6 0x418
#define ELM_LOCATION_STATUS 0x800 #define ELM_LOCATION_STATUS 0x800
#define ELM_ERROR_LOCATION_0 0x880 #define ELM_ERROR_LOCATION_0 0x880
...@@ -56,12 +63,27 @@ ...@@ -56,12 +63,27 @@
#define SYNDROME_FRAGMENT_REG_SIZE 0x40 #define SYNDROME_FRAGMENT_REG_SIZE 0x40
#define ERROR_LOCATION_SIZE 0x100 #define ERROR_LOCATION_SIZE 0x100
struct elm_registers {
u32 elm_irqenable;
u32 elm_sysconfig;
u32 elm_location_config;
u32 elm_page_ctrl;
u32 elm_syndrome_fragment_6[ERROR_VECTOR_MAX];
u32 elm_syndrome_fragment_5[ERROR_VECTOR_MAX];
u32 elm_syndrome_fragment_4[ERROR_VECTOR_MAX];
u32 elm_syndrome_fragment_3[ERROR_VECTOR_MAX];
u32 elm_syndrome_fragment_2[ERROR_VECTOR_MAX];
u32 elm_syndrome_fragment_1[ERROR_VECTOR_MAX];
u32 elm_syndrome_fragment_0[ERROR_VECTOR_MAX];
};
struct elm_info { struct elm_info {
struct device *dev; struct device *dev;
void __iomem *elm_base; void __iomem *elm_base;
struct completion elm_completion; struct completion elm_completion;
struct list_head list; struct list_head list;
enum bch_ecc bch_type; enum bch_ecc bch_type;
struct elm_registers elm_regs;
}; };
static LIST_HEAD(elm_devices); static LIST_HEAD(elm_devices);
...@@ -346,14 +368,9 @@ static int elm_probe(struct platform_device *pdev) ...@@ -346,14 +368,9 @@ static int elm_probe(struct platform_device *pdev)
} }
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) { info->elm_base = devm_ioremap_resource(&pdev->dev, res);
dev_err(&pdev->dev, "no memory resource defined\n"); if (IS_ERR(info->elm_base))
return -ENODEV; return PTR_ERR(info->elm_base);
}
info->elm_base = devm_request_and_ioremap(&pdev->dev, res);
if (!info->elm_base)
return -EADDRNOTAVAIL;
ret = devm_request_irq(&pdev->dev, irq->start, elm_isr, 0, ret = devm_request_irq(&pdev->dev, irq->start, elm_isr, 0,
pdev->name, info); pdev->name, info);
...@@ -381,10 +398,103 @@ static int elm_remove(struct platform_device *pdev) ...@@ -381,10 +398,103 @@ static int elm_remove(struct platform_device *pdev)
{ {
pm_runtime_put_sync(&pdev->dev); pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
platform_set_drvdata(pdev, NULL);
return 0; return 0;
} }
/**
* elm_context_save
* saves ELM configurations to preserve them across Hardware powered-down
*/
static int elm_context_save(struct elm_info *info)
{
struct elm_registers *regs = &info->elm_regs;
enum bch_ecc bch_type = info->bch_type;
u32 offset = 0, i;
regs->elm_irqenable = elm_read_reg(info, ELM_IRQENABLE);
regs->elm_sysconfig = elm_read_reg(info, ELM_SYSCONFIG);
regs->elm_location_config = elm_read_reg(info, ELM_LOCATION_CONFIG);
regs->elm_page_ctrl = elm_read_reg(info, ELM_PAGE_CTRL);
for (i = 0; i < ERROR_VECTOR_MAX; i++) {
offset = i * SYNDROME_FRAGMENT_REG_SIZE;
switch (bch_type) {
case BCH8_ECC:
regs->elm_syndrome_fragment_3[i] = elm_read_reg(info,
ELM_SYNDROME_FRAGMENT_3 + offset);
regs->elm_syndrome_fragment_2[i] = elm_read_reg(info,
ELM_SYNDROME_FRAGMENT_2 + offset);
case BCH4_ECC:
regs->elm_syndrome_fragment_1[i] = elm_read_reg(info,
ELM_SYNDROME_FRAGMENT_1 + offset);
regs->elm_syndrome_fragment_0[i] = elm_read_reg(info,
ELM_SYNDROME_FRAGMENT_0 + offset);
default:
return -EINVAL;
}
/* ELM SYNDROME_VALID bit in SYNDROME_FRAGMENT_6[] needs
* to be saved for all BCH schemes*/
regs->elm_syndrome_fragment_6[i] = elm_read_reg(info,
ELM_SYNDROME_FRAGMENT_6 + offset);
}
return 0;
}
/**
* elm_context_restore
* writes configurations saved duing power-down back into ELM registers
*/
static int elm_context_restore(struct elm_info *info)
{
struct elm_registers *regs = &info->elm_regs;
enum bch_ecc bch_type = info->bch_type;
u32 offset = 0, i;
elm_write_reg(info, ELM_IRQENABLE, regs->elm_irqenable);
elm_write_reg(info, ELM_SYSCONFIG, regs->elm_sysconfig);
elm_write_reg(info, ELM_LOCATION_CONFIG, regs->elm_location_config);
elm_write_reg(info, ELM_PAGE_CTRL, regs->elm_page_ctrl);
for (i = 0; i < ERROR_VECTOR_MAX; i++) {
offset = i * SYNDROME_FRAGMENT_REG_SIZE;
switch (bch_type) {
case BCH8_ECC:
elm_write_reg(info, ELM_SYNDROME_FRAGMENT_3 + offset,
regs->elm_syndrome_fragment_3[i]);
elm_write_reg(info, ELM_SYNDROME_FRAGMENT_2 + offset,
regs->elm_syndrome_fragment_2[i]);
case BCH4_ECC:
elm_write_reg(info, ELM_SYNDROME_FRAGMENT_1 + offset,
regs->elm_syndrome_fragment_1[i]);
elm_write_reg(info, ELM_SYNDROME_FRAGMENT_0 + offset,
regs->elm_syndrome_fragment_0[i]);
default:
return -EINVAL;
}
/* ELM_SYNDROME_VALID bit to be set in last to trigger FSM */
elm_write_reg(info, ELM_SYNDROME_FRAGMENT_6 + offset,
regs->elm_syndrome_fragment_6[i] &
ELM_SYNDROME_VALID);
}
return 0;
}
static int elm_suspend(struct device *dev)
{
struct elm_info *info = dev_get_drvdata(dev);
elm_context_save(info);
pm_runtime_put_sync(dev);
return 0;
}
static int elm_resume(struct device *dev)
{
struct elm_info *info = dev_get_drvdata(dev);
pm_runtime_get_sync(dev);
elm_context_restore(info);
return 0;
}
static SIMPLE_DEV_PM_OPS(elm_pm_ops, elm_suspend, elm_resume);
#ifdef CONFIG_OF #ifdef CONFIG_OF
static const struct of_device_id elm_of_match[] = { static const struct of_device_id elm_of_match[] = {
{ .compatible = "ti,am3352-elm" }, { .compatible = "ti,am3352-elm" },
...@@ -398,6 +508,7 @@ static struct platform_driver elm_driver = { ...@@ -398,6 +508,7 @@ static struct platform_driver elm_driver = {
.name = "elm", .name = "elm",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.of_match_table = of_match_ptr(elm_of_match), .of_match_table = of_match_ptr(elm_of_match),
.pm = &elm_pm_ops,
}, },
.probe = elm_probe, .probe = elm_probe,
.remove = elm_remove, .remove = elm_remove,
......
...@@ -43,17 +43,24 @@ ...@@ -43,17 +43,24 @@
#define OPCODE_FAST_READ 0x0b /* Read data bytes (high frequency) */ #define OPCODE_FAST_READ 0x0b /* Read data bytes (high frequency) */
#define OPCODE_PP 0x02 /* Page program (up to 256 bytes) */ #define OPCODE_PP 0x02 /* Page program (up to 256 bytes) */
#define OPCODE_BE_4K 0x20 /* Erase 4KiB block */ #define OPCODE_BE_4K 0x20 /* Erase 4KiB block */
#define OPCODE_BE_4K_PMC 0xd7 /* Erase 4KiB block on PMC chips */
#define OPCODE_BE_32K 0x52 /* Erase 32KiB block */ #define OPCODE_BE_32K 0x52 /* Erase 32KiB block */
#define OPCODE_CHIP_ERASE 0xc7 /* Erase whole flash chip */ #define OPCODE_CHIP_ERASE 0xc7 /* Erase whole flash chip */
#define OPCODE_SE 0xd8 /* Sector erase (usually 64KiB) */ #define OPCODE_SE 0xd8 /* Sector erase (usually 64KiB) */
#define OPCODE_RDID 0x9f /* Read JEDEC ID */ #define OPCODE_RDID 0x9f /* Read JEDEC ID */
/* 4-byte address opcodes - used on Spansion and some Macronix flashes. */
#define OPCODE_NORM_READ_4B 0x13 /* Read data bytes (low frequency) */
#define OPCODE_FAST_READ_4B 0x0c /* Read data bytes (high frequency) */
#define OPCODE_PP_4B 0x12 /* Page program (up to 256 bytes) */
#define OPCODE_SE_4B 0xdc /* Sector erase (usually 64KiB) */
/* Used for SST flashes only. */ /* Used for SST flashes only. */
#define OPCODE_BP 0x02 /* Byte program */ #define OPCODE_BP 0x02 /* Byte program */
#define OPCODE_WRDI 0x04 /* Write disable */ #define OPCODE_WRDI 0x04 /* Write disable */
#define OPCODE_AAI_WP 0xad /* Auto address increment word program */ #define OPCODE_AAI_WP 0xad /* Auto address increment word program */
/* Used for Macronix flashes only. */ /* Used for Macronix and Winbond flashes. */
#define OPCODE_EN4B 0xb7 /* Enter 4-byte mode */ #define OPCODE_EN4B 0xb7 /* Enter 4-byte mode */
#define OPCODE_EX4B 0xe9 /* Exit 4-byte mode */ #define OPCODE_EX4B 0xe9 /* Exit 4-byte mode */
...@@ -84,6 +91,8 @@ struct m25p { ...@@ -84,6 +91,8 @@ struct m25p {
u16 page_size; u16 page_size;
u16 addr_width; u16 addr_width;
u8 erase_opcode; u8 erase_opcode;
u8 read_opcode;
u8 program_opcode;
u8 *command; u8 *command;
bool fast_read; bool fast_read;
}; };
...@@ -161,6 +170,7 @@ static inline int set_4byte(struct m25p *flash, u32 jedec_id, int enable) ...@@ -161,6 +170,7 @@ static inline int set_4byte(struct m25p *flash, u32 jedec_id, int enable)
{ {
switch (JEDEC_MFR(jedec_id)) { switch (JEDEC_MFR(jedec_id)) {
case CFI_MFR_MACRONIX: case CFI_MFR_MACRONIX:
case CFI_MFR_ST: /* Micron, actually */
case 0xEF /* winbond */: case 0xEF /* winbond */:
flash->command[0] = enable ? OPCODE_EN4B : OPCODE_EX4B; flash->command[0] = enable ? OPCODE_EN4B : OPCODE_EX4B;
return spi_write(flash->spi, flash->command, 1); return spi_write(flash->spi, flash->command, 1);
...@@ -371,7 +381,7 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len, ...@@ -371,7 +381,7 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len,
*/ */
/* Set up the write data buffer. */ /* Set up the write data buffer. */
opcode = flash->fast_read ? OPCODE_FAST_READ : OPCODE_NORM_READ; opcode = flash->read_opcode;
flash->command[0] = opcode; flash->command[0] = opcode;
m25p_addr2cmd(flash, from, flash->command); m25p_addr2cmd(flash, from, flash->command);
...@@ -422,7 +432,7 @@ static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len, ...@@ -422,7 +432,7 @@ static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len,
write_enable(flash); write_enable(flash);
/* Set up the opcode in the write buffer. */ /* Set up the opcode in the write buffer. */
flash->command[0] = OPCODE_PP; flash->command[0] = flash->program_opcode;
m25p_addr2cmd(flash, to, flash->command); m25p_addr2cmd(flash, to, flash->command);
page_offset = to & (flash->page_size - 1); page_offset = to & (flash->page_size - 1);
...@@ -682,6 +692,8 @@ struct flash_info { ...@@ -682,6 +692,8 @@ struct flash_info {
#define SECT_4K 0x01 /* OPCODE_BE_4K works uniformly */ #define SECT_4K 0x01 /* OPCODE_BE_4K works uniformly */
#define M25P_NO_ERASE 0x02 /* No erase command needed */ #define M25P_NO_ERASE 0x02 /* No erase command needed */
#define SST_WRITE 0x04 /* use SST byte programming */ #define SST_WRITE 0x04 /* use SST byte programming */
#define M25P_NO_FR 0x08 /* Can't do fastread */
#define SECT_4K_PMC 0x10 /* OPCODE_BE_4K_PMC works uniformly */
}; };
#define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \ #define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \
...@@ -694,13 +706,13 @@ struct flash_info { ...@@ -694,13 +706,13 @@ struct flash_info {
.flags = (_flags), \ .flags = (_flags), \
}) })
#define CAT25_INFO(_sector_size, _n_sectors, _page_size, _addr_width) \ #define CAT25_INFO(_sector_size, _n_sectors, _page_size, _addr_width, _flags) \
((kernel_ulong_t)&(struct flash_info) { \ ((kernel_ulong_t)&(struct flash_info) { \
.sector_size = (_sector_size), \ .sector_size = (_sector_size), \
.n_sectors = (_n_sectors), \ .n_sectors = (_n_sectors), \
.page_size = (_page_size), \ .page_size = (_page_size), \
.addr_width = (_addr_width), \ .addr_width = (_addr_width), \
.flags = M25P_NO_ERASE, \ .flags = (_flags), \
}) })
/* NOTE: double check command sets and memory organization when you add /* NOTE: double check command sets and memory organization when you add
...@@ -732,7 +744,8 @@ static const struct spi_device_id m25p_ids[] = { ...@@ -732,7 +744,8 @@ static const struct spi_device_id m25p_ids[] = {
{ "en25qh256", INFO(0x1c7019, 0, 64 * 1024, 512, 0) }, { "en25qh256", INFO(0x1c7019, 0, 64 * 1024, 512, 0) },
/* Everspin */ /* Everspin */
{ "mr25h256", CAT25_INFO( 32 * 1024, 1, 256, 2) }, { "mr25h256", CAT25_INFO( 32 * 1024, 1, 256, 2, M25P_NO_ERASE | M25P_NO_FR) },
{ "mr25h10", CAT25_INFO(128 * 1024, 1, 256, 3, M25P_NO_ERASE | M25P_NO_FR) },
/* GigaDevice */ /* GigaDevice */
{ "gd25q32", INFO(0xc84016, 0, 64 * 1024, 64, SECT_4K) }, { "gd25q32", INFO(0xc84016, 0, 64 * 1024, 64, SECT_4K) },
...@@ -762,6 +775,11 @@ static const struct spi_device_id m25p_ids[] = { ...@@ -762,6 +775,11 @@ static const struct spi_device_id m25p_ids[] = {
{ "n25q128a13", INFO(0x20ba18, 0, 64 * 1024, 256, 0) }, { "n25q128a13", INFO(0x20ba18, 0, 64 * 1024, 256, 0) },
{ "n25q256a", INFO(0x20ba19, 0, 64 * 1024, 512, SECT_4K) }, { "n25q256a", INFO(0x20ba19, 0, 64 * 1024, 512, SECT_4K) },
/* PMC */
{ "pm25lv512", INFO(0, 0, 32 * 1024, 2, SECT_4K_PMC) },
{ "pm25lv010", INFO(0, 0, 32 * 1024, 4, SECT_4K_PMC) },
{ "pm25lq032", INFO(0x7f9d46, 0, 64 * 1024, 64, SECT_4K) },
/* Spansion -- single (large) sector size only, at least /* Spansion -- single (large) sector size only, at least
* for the chips listed here (without boot sectors). * for the chips listed here (without boot sectors).
*/ */
...@@ -840,17 +858,18 @@ static const struct spi_device_id m25p_ids[] = { ...@@ -840,17 +858,18 @@ static const struct spi_device_id m25p_ids[] = {
{ "w25q32dw", INFO(0xef6016, 0, 64 * 1024, 64, SECT_4K) }, { "w25q32dw", INFO(0xef6016, 0, 64 * 1024, 64, SECT_4K) },
{ "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) }, { "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) },
{ "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) }, { "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) },
{ "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) },
{ "w25q80", INFO(0xef5014, 0, 64 * 1024, 16, SECT_4K) }, { "w25q80", INFO(0xef5014, 0, 64 * 1024, 16, SECT_4K) },
{ "w25q80bl", INFO(0xef4014, 0, 64 * 1024, 16, SECT_4K) }, { "w25q80bl", INFO(0xef4014, 0, 64 * 1024, 16, SECT_4K) },
{ "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) }, { "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) },
{ "w25q256", INFO(0xef4019, 0, 64 * 1024, 512, SECT_4K) }, { "w25q256", INFO(0xef4019, 0, 64 * 1024, 512, SECT_4K) },
/* Catalyst / On Semiconductor -- non-JEDEC */ /* Catalyst / On Semiconductor -- non-JEDEC */
{ "cat25c11", CAT25_INFO( 16, 8, 16, 1) }, { "cat25c11", CAT25_INFO( 16, 8, 16, 1, M25P_NO_ERASE | M25P_NO_FR) },
{ "cat25c03", CAT25_INFO( 32, 8, 16, 2) }, { "cat25c03", CAT25_INFO( 32, 8, 16, 2, M25P_NO_ERASE | M25P_NO_FR) },
{ "cat25c09", CAT25_INFO( 128, 8, 32, 2) }, { "cat25c09", CAT25_INFO( 128, 8, 32, 2, M25P_NO_ERASE | M25P_NO_FR) },
{ "cat25c17", CAT25_INFO( 256, 8, 32, 2) }, { "cat25c17", CAT25_INFO( 256, 8, 32, 2, M25P_NO_ERASE | M25P_NO_FR) },
{ "cat25128", CAT25_INFO(2048, 8, 64, 2) }, { "cat25128", CAT25_INFO(2048, 8, 64, 2, M25P_NO_ERASE | M25P_NO_FR) },
{ }, { },
}; };
MODULE_DEVICE_TABLE(spi, m25p_ids); MODULE_DEVICE_TABLE(spi, m25p_ids);
...@@ -920,7 +939,7 @@ static int m25p_probe(struct spi_device *spi) ...@@ -920,7 +939,7 @@ static int m25p_probe(struct spi_device *spi)
* a chip ID, try the JEDEC id commands; they'll work for most * a chip ID, try the JEDEC id commands; they'll work for most
* newer chips, even if we don't recognize the particular chip. * newer chips, even if we don't recognize the particular chip.
*/ */
data = spi->dev.platform_data; data = dev_get_platdata(&spi->dev);
if (data && data->type) { if (data && data->type) {
const struct spi_device_id *plat_id; const struct spi_device_id *plat_id;
...@@ -972,7 +991,7 @@ static int m25p_probe(struct spi_device *spi) ...@@ -972,7 +991,7 @@ static int m25p_probe(struct spi_device *spi)
flash->spi = spi; flash->spi = spi;
mutex_init(&flash->lock); mutex_init(&flash->lock);
dev_set_drvdata(&spi->dev, flash); spi_set_drvdata(spi, flash);
/* /*
* Atmel, SST and Intel/Numonyx serial flash tend to power * Atmel, SST and Intel/Numonyx serial flash tend to power
...@@ -1014,6 +1033,9 @@ static int m25p_probe(struct spi_device *spi) ...@@ -1014,6 +1033,9 @@ static int m25p_probe(struct spi_device *spi)
if (info->flags & SECT_4K) { if (info->flags & SECT_4K) {
flash->erase_opcode = OPCODE_BE_4K; flash->erase_opcode = OPCODE_BE_4K;
flash->mtd.erasesize = 4096; flash->mtd.erasesize = 4096;
} else if (info->flags & SECT_4K_PMC) {
flash->erase_opcode = OPCODE_BE_4K_PMC;
flash->mtd.erasesize = 4096;
} else { } else {
flash->erase_opcode = OPCODE_SE; flash->erase_opcode = OPCODE_SE;
flash->mtd.erasesize = info->sector_size; flash->mtd.erasesize = info->sector_size;
...@@ -1028,24 +1050,41 @@ static int m25p_probe(struct spi_device *spi) ...@@ -1028,24 +1050,41 @@ static int m25p_probe(struct spi_device *spi)
flash->mtd.writebufsize = flash->page_size; flash->mtd.writebufsize = flash->page_size;
flash->fast_read = false; flash->fast_read = false;
#ifdef CONFIG_OF
if (np && of_property_read_bool(np, "m25p,fast-read")) if (np && of_property_read_bool(np, "m25p,fast-read"))
flash->fast_read = true; flash->fast_read = true;
#endif
#ifdef CONFIG_M25PXX_USE_FAST_READ #ifdef CONFIG_M25PXX_USE_FAST_READ
flash->fast_read = true; flash->fast_read = true;
#endif #endif
if (info->flags & M25P_NO_FR)
flash->fast_read = false;
/* Default commands */
if (flash->fast_read)
flash->read_opcode = OPCODE_FAST_READ;
else
flash->read_opcode = OPCODE_NORM_READ;
flash->program_opcode = OPCODE_PP;
if (info->addr_width) if (info->addr_width)
flash->addr_width = info->addr_width; flash->addr_width = info->addr_width;
else { else if (flash->mtd.size > 0x1000000) {
/* enable 4-byte addressing if the device exceeds 16MiB */ /* enable 4-byte addressing if the device exceeds 16MiB */
if (flash->mtd.size > 0x1000000) { flash->addr_width = 4;
flash->addr_width = 4; if (JEDEC_MFR(info->jedec_id) == CFI_MFR_AMD) {
set_4byte(flash, info->jedec_id, 1); /* Dedicated 4-byte command set */
flash->read_opcode = flash->fast_read ?
OPCODE_FAST_READ_4B :
OPCODE_NORM_READ_4B;
flash->program_opcode = OPCODE_PP_4B;
/* No small sector erase for 4-byte command set */
flash->erase_opcode = OPCODE_SE_4B;
flash->mtd.erasesize = info->sector_size;
} else } else
flash->addr_width = 3; set_4byte(flash, info->jedec_id, 1);
} else {
flash->addr_width = 3;
} }
dev_info(&spi->dev, "%s (%lld Kbytes)\n", id->name, dev_info(&spi->dev, "%s (%lld Kbytes)\n", id->name,
...@@ -1080,7 +1119,7 @@ static int m25p_probe(struct spi_device *spi) ...@@ -1080,7 +1119,7 @@ static int m25p_probe(struct spi_device *spi)
static int m25p_remove(struct spi_device *spi) static int m25p_remove(struct spi_device *spi)
{ {
struct m25p *flash = dev_get_drvdata(&spi->dev); struct m25p *flash = spi_get_drvdata(spi);
int status; int status;
/* Clean up MTD stuff. */ /* Clean up MTD stuff. */
......
...@@ -622,7 +622,7 @@ static int add_dataflash_otp(struct spi_device *spi, char *name, int nr_pages, ...@@ -622,7 +622,7 @@ static int add_dataflash_otp(struct spi_device *spi, char *name, int nr_pages,
struct dataflash *priv; struct dataflash *priv;
struct mtd_info *device; struct mtd_info *device;
struct mtd_part_parser_data ppdata; struct mtd_part_parser_data ppdata;
struct flash_platform_data *pdata = spi->dev.platform_data; struct flash_platform_data *pdata = dev_get_platdata(&spi->dev);
char *otp_tag = ""; char *otp_tag = "";
int err = 0; int err = 0;
...@@ -661,7 +661,7 @@ static int add_dataflash_otp(struct spi_device *spi, char *name, int nr_pages, ...@@ -661,7 +661,7 @@ static int add_dataflash_otp(struct spi_device *spi, char *name, int nr_pages,
dev_info(&spi->dev, "%s (%lld KBytes) pagesize %d bytes%s\n", dev_info(&spi->dev, "%s (%lld KBytes) pagesize %d bytes%s\n",
name, (long long)((device->size + 1023) >> 10), name, (long long)((device->size + 1023) >> 10),
pagesize, otp_tag); pagesize, otp_tag);
dev_set_drvdata(&spi->dev, priv); spi_set_drvdata(spi, priv);
ppdata.of_node = spi->dev.of_node; ppdata.of_node = spi->dev.of_node;
err = mtd_device_parse_register(device, NULL, &ppdata, err = mtd_device_parse_register(device, NULL, &ppdata,
...@@ -671,7 +671,7 @@ static int add_dataflash_otp(struct spi_device *spi, char *name, int nr_pages, ...@@ -671,7 +671,7 @@ static int add_dataflash_otp(struct spi_device *spi, char *name, int nr_pages,
if (!err) if (!err)
return 0; return 0;
dev_set_drvdata(&spi->dev, NULL); spi_set_drvdata(spi, NULL);
kfree(priv); kfree(priv);
return err; return err;
} }
...@@ -895,14 +895,14 @@ static int dataflash_probe(struct spi_device *spi) ...@@ -895,14 +895,14 @@ static int dataflash_probe(struct spi_device *spi)
static int dataflash_remove(struct spi_device *spi) static int dataflash_remove(struct spi_device *spi)
{ {
struct dataflash *flash = dev_get_drvdata(&spi->dev); struct dataflash *flash = spi_get_drvdata(spi);
int status; int status;
pr_debug("%s: remove\n", dev_name(&spi->dev)); pr_debug("%s: remove\n", dev_name(&spi->dev));
status = mtd_device_unregister(&flash->mtd); status = mtd_device_unregister(&flash->mtd);
if (status == 0) { if (status == 0) {
dev_set_drvdata(&spi->dev, NULL); spi_set_drvdata(spi, NULL);
kfree(flash); kfree(flash);
} }
return status; return status;
......
...@@ -550,7 +550,7 @@ static int spear_mtd_read(struct mtd_info *mtd, loff_t from, size_t len, ...@@ -550,7 +550,7 @@ static int spear_mtd_read(struct mtd_info *mtd, loff_t from, size_t len,
{ {
struct spear_snor_flash *flash = get_flash_data(mtd); struct spear_snor_flash *flash = get_flash_data(mtd);
struct spear_smi *dev = mtd->priv; struct spear_smi *dev = mtd->priv;
void *src; void __iomem *src;
u32 ctrlreg1, val; u32 ctrlreg1, val;
int ret; int ret;
...@@ -583,7 +583,7 @@ static int spear_mtd_read(struct mtd_info *mtd, loff_t from, size_t len, ...@@ -583,7 +583,7 @@ static int spear_mtd_read(struct mtd_info *mtd, loff_t from, size_t len,
writel(val, dev->io_base + SMI_CR1); writel(val, dev->io_base + SMI_CR1);
memcpy_fromio(buf, (u8 *)src, len); memcpy_fromio(buf, src, len);
/* restore ctrl reg1 */ /* restore ctrl reg1 */
writel(ctrlreg1, dev->io_base + SMI_CR1); writel(ctrlreg1, dev->io_base + SMI_CR1);
...@@ -596,7 +596,7 @@ static int spear_mtd_read(struct mtd_info *mtd, loff_t from, size_t len, ...@@ -596,7 +596,7 @@ static int spear_mtd_read(struct mtd_info *mtd, loff_t from, size_t len,
} }
static inline int spear_smi_cpy_toio(struct spear_smi *dev, u32 bank, static inline int spear_smi_cpy_toio(struct spear_smi *dev, u32 bank,
void *dest, const void *src, size_t len) void __iomem *dest, const void *src, size_t len)
{ {
int ret; int ret;
u32 ctrlreg1; u32 ctrlreg1;
...@@ -643,7 +643,7 @@ static int spear_mtd_write(struct mtd_info *mtd, loff_t to, size_t len, ...@@ -643,7 +643,7 @@ static int spear_mtd_write(struct mtd_info *mtd, loff_t to, size_t len,
{ {
struct spear_snor_flash *flash = get_flash_data(mtd); struct spear_snor_flash *flash = get_flash_data(mtd);
struct spear_smi *dev = mtd->priv; struct spear_smi *dev = mtd->priv;
void *dest; void __iomem *dest;
u32 page_offset, page_size; u32 page_offset, page_size;
int ret; int ret;
...@@ -995,14 +995,12 @@ static int spear_smi_probe(struct platform_device *pdev) ...@@ -995,14 +995,12 @@ static int spear_smi_probe(struct platform_device *pdev)
ret = spear_smi_setup_banks(pdev, i, pdata->np[i]); ret = spear_smi_setup_banks(pdev, i, pdata->np[i]);
if (ret) { if (ret) {
dev_err(&dev->pdev->dev, "bank setup failed\n"); dev_err(&dev->pdev->dev, "bank setup failed\n");
goto err_bank_setup; goto err_irq;
} }
} }
return 0; return 0;
err_bank_setup:
platform_set_drvdata(pdev, NULL);
err_irq: err_irq:
clk_disable_unprepare(dev->clk); clk_disable_unprepare(dev->clk);
err: err:
...@@ -1040,12 +1038,11 @@ static int spear_smi_remove(struct platform_device *pdev) ...@@ -1040,12 +1038,11 @@ static int spear_smi_remove(struct platform_device *pdev)
} }
clk_disable_unprepare(dev->clk); clk_disable_unprepare(dev->clk);
platform_set_drvdata(pdev, NULL);
return 0; return 0;
} }
#ifdef CONFIG_PM #ifdef CONFIG_PM_SLEEP
static int spear_smi_suspend(struct device *dev) static int spear_smi_suspend(struct device *dev)
{ {
struct spear_smi *sdev = dev_get_drvdata(dev); struct spear_smi *sdev = dev_get_drvdata(dev);
...@@ -1068,9 +1065,9 @@ static int spear_smi_resume(struct device *dev) ...@@ -1068,9 +1065,9 @@ static int spear_smi_resume(struct device *dev)
spear_smi_hw_init(sdev); spear_smi_hw_init(sdev);
return ret; return ret;
} }
#endif
static SIMPLE_DEV_PM_OPS(spear_smi_pm_ops, spear_smi_suspend, spear_smi_resume); static SIMPLE_DEV_PM_OPS(spear_smi_pm_ops, spear_smi_suspend, spear_smi_resume);
#endif
#ifdef CONFIG_OF #ifdef CONFIG_OF
static const struct of_device_id spear_smi_id_table[] = { static const struct of_device_id spear_smi_id_table[] = {
...@@ -1086,9 +1083,7 @@ static struct platform_driver spear_smi_driver = { ...@@ -1086,9 +1083,7 @@ static struct platform_driver spear_smi_driver = {
.bus = &platform_bus_type, .bus = &platform_bus_type,
.owner = THIS_MODULE, .owner = THIS_MODULE,
.of_match_table = of_match_ptr(spear_smi_id_table), .of_match_table = of_match_ptr(spear_smi_id_table),
#ifdef CONFIG_PM
.pm = &spear_smi_pm_ops, .pm = &spear_smi_pm_ops,
#endif
}, },
.probe = spear_smi_probe, .probe = spear_smi_probe,
.remove = spear_smi_remove, .remove = spear_smi_remove,
......
...@@ -370,9 +370,9 @@ static int sst25l_probe(struct spi_device *spi) ...@@ -370,9 +370,9 @@ static int sst25l_probe(struct spi_device *spi)
flash->spi = spi; flash->spi = spi;
mutex_init(&flash->lock); mutex_init(&flash->lock);
dev_set_drvdata(&spi->dev, flash); spi_set_drvdata(spi, flash);
data = spi->dev.platform_data; data = dev_get_platdata(&spi->dev);
if (data && data->name) if (data && data->name)
flash->mtd.name = data->name; flash->mtd.name = data->name;
else else
...@@ -404,7 +404,7 @@ static int sst25l_probe(struct spi_device *spi) ...@@ -404,7 +404,7 @@ static int sst25l_probe(struct spi_device *spi)
data ? data->nr_parts : 0); data ? data->nr_parts : 0);
if (ret) { if (ret) {
kfree(flash); kfree(flash);
dev_set_drvdata(&spi->dev, NULL); spi_set_drvdata(spi, NULL);
return -ENODEV; return -ENODEV;
} }
...@@ -413,7 +413,7 @@ static int sst25l_probe(struct spi_device *spi) ...@@ -413,7 +413,7 @@ static int sst25l_probe(struct spi_device *spi)
static int sst25l_remove(struct spi_device *spi) static int sst25l_remove(struct spi_device *spi)
{ {
struct sst25l_flash *flash = dev_get_drvdata(&spi->dev); struct sst25l_flash *flash = spi_get_drvdata(spi);
int ret; int ret;
ret = mtd_device_unregister(&flash->mtd); ret = mtd_device_unregister(&flash->mtd);
......
...@@ -157,24 +157,6 @@ config MTD_PXA2XX ...@@ -157,24 +157,6 @@ config MTD_PXA2XX
help help
This provides a driver for the NOR flash attached to a PXA2xx chip. This provides a driver for the NOR flash attached to a PXA2xx chip.
config MTD_OCTAGON
tristate "JEDEC Flash device mapped on Octagon 5066 SBC"
depends on X86 && MTD_JEDEC && MTD_COMPLEX_MAPPINGS
help
This provides a 'mapping' driver which supports the way in which
the flash chips are connected in the Octagon-5066 Single Board
Computer. More information on the board is available at
<http://www.octagonsystems.com/products/5066.aspx>.
config MTD_VMAX
tristate "JEDEC Flash device mapped on Tempustech VMAX SBC301"
depends on X86 && MTD_JEDEC && MTD_COMPLEX_MAPPINGS
help
This provides a 'mapping' driver which supports the way in which
the flash chips are connected in the Tempustech VMAX SBC301 Single
Board Computer. More information on the board is available at
<http://www.tempustech.com/>.
config MTD_SCx200_DOCFLASH config MTD_SCx200_DOCFLASH
tristate "Flash device mapped with DOCCS on NatSemi SCx200" tristate "Flash device mapped with DOCCS on NatSemi SCx200"
depends on SCx200 && MTD_CFI depends on SCx200 && MTD_CFI
......
...@@ -16,7 +16,6 @@ obj-$(CONFIG_MTD_ICHXROM) += ichxrom.o ...@@ -16,7 +16,6 @@ obj-$(CONFIG_MTD_ICHXROM) += ichxrom.o
obj-$(CONFIG_MTD_CK804XROM) += ck804xrom.o obj-$(CONFIG_MTD_CK804XROM) += ck804xrom.o
obj-$(CONFIG_MTD_TSUNAMI) += tsunami_flash.o obj-$(CONFIG_MTD_TSUNAMI) += tsunami_flash.o
obj-$(CONFIG_MTD_PXA2XX) += pxa2xx-flash.o obj-$(CONFIG_MTD_PXA2XX) += pxa2xx-flash.o
obj-$(CONFIG_MTD_OCTAGON) += octagon-5066.o
obj-$(CONFIG_MTD_PHYSMAP) += physmap.o obj-$(CONFIG_MTD_PHYSMAP) += physmap.o
obj-$(CONFIG_MTD_PHYSMAP_OF) += physmap_of.o obj-$(CONFIG_MTD_PHYSMAP_OF) += physmap_of.o
obj-$(CONFIG_MTD_PISMO) += pismo.o obj-$(CONFIG_MTD_PISMO) += pismo.o
...@@ -28,7 +27,6 @@ obj-$(CONFIG_MTD_SC520CDP) += sc520cdp.o ...@@ -28,7 +27,6 @@ obj-$(CONFIG_MTD_SC520CDP) += sc520cdp.o
obj-$(CONFIG_MTD_NETSC520) += netsc520.o obj-$(CONFIG_MTD_NETSC520) += netsc520.o
obj-$(CONFIG_MTD_TS5500) += ts5500_flash.o obj-$(CONFIG_MTD_TS5500) += ts5500_flash.o
obj-$(CONFIG_MTD_SUN_UFLASH) += sun_uflash.o obj-$(CONFIG_MTD_SUN_UFLASH) += sun_uflash.o
obj-$(CONFIG_MTD_VMAX) += vmax301.o
obj-$(CONFIG_MTD_SCx200_DOCFLASH)+= scx200_docflash.o obj-$(CONFIG_MTD_SCx200_DOCFLASH)+= scx200_docflash.o
obj-$(CONFIG_MTD_SOLUTIONENGINE)+= solutionengine.o obj-$(CONFIG_MTD_SOLUTIONENGINE)+= solutionengine.o
obj-$(CONFIG_MTD_PCI) += pci.o obj-$(CONFIG_MTD_PCI) += pci.o
......
...@@ -128,7 +128,7 @@ static const char * const part_probe_types[] = { ...@@ -128,7 +128,7 @@ static const char * const part_probe_types[] = {
static int bfin_flash_probe(struct platform_device *pdev) static int bfin_flash_probe(struct platform_device *pdev)
{ {
int ret; int ret;
struct physmap_flash_data *pdata = pdev->dev.platform_data; struct physmap_flash_data *pdata = dev_get_platdata(&pdev->dev);
struct resource *memory = platform_get_resource(pdev, IORESOURCE_MEM, 0); struct resource *memory = platform_get_resource(pdev, IORESOURCE_MEM, 0);
struct resource *flash_ambctl = platform_get_resource(pdev, IORESOURCE_MEM, 1); struct resource *flash_ambctl = platform_get_resource(pdev, IORESOURCE_MEM, 1);
struct async_state *state; struct async_state *state;
......
...@@ -55,13 +55,13 @@ ...@@ -55,13 +55,13 @@
#define FLASH_PARTITION3_SIZE 0x001C0000 #define FLASH_PARTITION3_SIZE 0x001C0000
struct map_info flagadm_map = { static struct map_info flagadm_map = {
.name = "FlagaDM flash device", .name = "FlagaDM flash device",
.size = FLASH_SIZE, .size = FLASH_SIZE,
.bankwidth = 2, .bankwidth = 2,
}; };
struct mtd_partition flagadm_parts[] = { static struct mtd_partition flagadm_parts[] = {
{ {
.name = "Bootloader", .name = "Bootloader",
.offset = FLASH_PARTITION0_ADDR, .offset = FLASH_PARTITION0_ADDR,
...@@ -112,7 +112,7 @@ static int __init init_flagadm(void) ...@@ -112,7 +112,7 @@ static int __init init_flagadm(void)
return 0; return 0;
} }
iounmap((void *)flagadm_map.virt); iounmap((void __iomem *)flagadm_map.virt);
return -ENXIO; return -ENXIO;
} }
...@@ -123,8 +123,8 @@ static void __exit cleanup_flagadm(void) ...@@ -123,8 +123,8 @@ static void __exit cleanup_flagadm(void)
map_destroy(mymtd); map_destroy(mymtd);
} }
if (flagadm_map.virt) { if (flagadm_map.virt) {
iounmap((void *)flagadm_map.virt); iounmap((void __iomem *)flagadm_map.virt);
flagadm_map.virt = 0; flagadm_map.virt = NULL;
} }
} }
......
...@@ -196,7 +196,7 @@ static int gpio_flash_probe(struct platform_device *pdev) ...@@ -196,7 +196,7 @@ static int gpio_flash_probe(struct platform_device *pdev)
struct resource *gpios; struct resource *gpios;
struct async_state *state; struct async_state *state;
pdata = pdev->dev.platform_data; pdata = dev_get_platdata(&pdev->dev);
memory = platform_get_resource(pdev, IORESOURCE_MEM, 0); memory = platform_get_resource(pdev, IORESOURCE_MEM, 0);
gpios = platform_get_resource(pdev, IORESOURCE_IRQ, 0); gpios = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
......
...@@ -79,7 +79,7 @@ static int __init init_impa7(void) ...@@ -79,7 +79,7 @@ static int __init init_impa7(void)
} }
simple_map_init(&impa7_map[i]); simple_map_init(&impa7_map[i]);
impa7_mtd[i] = 0; impa7_mtd[i] = NULL;
type = rom_probe_types; type = rom_probe_types;
for(; !impa7_mtd[i] && *type; type++) { for(; !impa7_mtd[i] && *type; type++) {
impa7_mtd[i] = do_map_probe(*type, &impa7_map[i]); impa7_mtd[i] = do_map_probe(*type, &impa7_map[i]);
...@@ -91,9 +91,9 @@ static int __init init_impa7(void) ...@@ -91,9 +91,9 @@ static int __init init_impa7(void)
mtd_device_parse_register(impa7_mtd[i], NULL, NULL, mtd_device_parse_register(impa7_mtd[i], NULL, NULL,
partitions, partitions,
ARRAY_SIZE(partitions)); ARRAY_SIZE(partitions));
} else {
iounmap((void __iomem *)impa7_map[i].virt);
} }
else
iounmap((void *)impa7_map[i].virt);
} }
return devicesfound == 0 ? -ENXIO : 0; return devicesfound == 0 ? -ENXIO : 0;
} }
...@@ -105,8 +105,8 @@ static void __exit cleanup_impa7(void) ...@@ -105,8 +105,8 @@ static void __exit cleanup_impa7(void)
if (impa7_mtd[i]) { if (impa7_mtd[i]) {
mtd_device_unregister(impa7_mtd[i]); mtd_device_unregister(impa7_mtd[i]);
map_destroy(impa7_mtd[i]); map_destroy(impa7_mtd[i]);
iounmap((void *)impa7_map[i].virt); iounmap((void __iomem *)impa7_map[i].virt);
impa7_map[i].virt = 0; impa7_map[i].virt = NULL;
} }
} }
} }
......
...@@ -152,11 +152,9 @@ static const char * const probes[] = { "RedBoot", "cmdlinepart", NULL }; ...@@ -152,11 +152,9 @@ static const char * const probes[] = { "RedBoot", "cmdlinepart", NULL };
static int ixp4xx_flash_remove(struct platform_device *dev) static int ixp4xx_flash_remove(struct platform_device *dev)
{ {
struct flash_platform_data *plat = dev->dev.platform_data; struct flash_platform_data *plat = dev_get_platdata(&dev->dev);
struct ixp4xx_flash_info *info = platform_get_drvdata(dev); struct ixp4xx_flash_info *info = platform_get_drvdata(dev);
platform_set_drvdata(dev, NULL);
if(!info) if(!info)
return 0; return 0;
...@@ -180,7 +178,7 @@ static int ixp4xx_flash_remove(struct platform_device *dev) ...@@ -180,7 +178,7 @@ static int ixp4xx_flash_remove(struct platform_device *dev)
static int ixp4xx_flash_probe(struct platform_device *dev) static int ixp4xx_flash_probe(struct platform_device *dev)
{ {
struct flash_platform_data *plat = dev->dev.platform_data; struct flash_platform_data *plat = dev_get_platdata(&dev->dev);
struct ixp4xx_flash_info *info; struct ixp4xx_flash_info *info;
struct mtd_part_parser_data ppdata = { struct mtd_part_parser_data ppdata = {
.origin = dev->resource->start, .origin = dev->resource->start,
......
...@@ -102,9 +102,8 @@ static int latch_addr_flash_remove(struct platform_device *dev) ...@@ -102,9 +102,8 @@ static int latch_addr_flash_remove(struct platform_device *dev)
info = platform_get_drvdata(dev); info = platform_get_drvdata(dev);
if (info == NULL) if (info == NULL)
return 0; return 0;
platform_set_drvdata(dev, NULL);
latch_addr_data = dev->dev.platform_data; latch_addr_data = dev_get_platdata(&dev->dev);
if (info->mtd != NULL) { if (info->mtd != NULL) {
mtd_device_unregister(info->mtd); mtd_device_unregister(info->mtd);
...@@ -135,7 +134,7 @@ static int latch_addr_flash_probe(struct platform_device *dev) ...@@ -135,7 +134,7 @@ static int latch_addr_flash_probe(struct platform_device *dev)
int chipsel; int chipsel;
int err; int err;
latch_addr_data = dev->dev.platform_data; latch_addr_data = dev_get_platdata(&dev->dev);
if (latch_addr_data == NULL) if (latch_addr_data == NULL)
return -ENODEV; return -ENODEV;
......
/* ######################################################################
Octagon 5066 MTD Driver.
The Octagon 5066 is a SBC based on AMD's 586-WB running at 133 MHZ. It
comes with a builtin AMD 29F016 flash chip and a socketed EEPROM that
is replacable by flash. Both units are mapped through a multiplexer
into a 32k memory window at 0xe8000. The control register for the
multiplexing unit is located at IO 0x208 with a bit map of
0-5 Page Selection in 32k increments
6-7 Device selection:
00 SSD off
01 SSD 0 (Socket)
10 SSD 1 (Flash chip)
11 undefined
On each SSD, the first 128k is reserved for use by the bios
(actually it IS the bios..) This only matters if you are booting off the
flash, you must not put a file system starting there.
The driver tries to do a detection algorithm to guess what sort of devices
are plugged into the sockets.
##################################################################### */
#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <asm/io.h>
#include <linux/mtd/map.h>
#include <linux/mtd/mtd.h>
#define WINDOW_START 0xe8000
#define WINDOW_LENGTH 0x8000
#define WINDOW_SHIFT 27
#define WINDOW_MASK 0x7FFF
#define PAGE_IO 0x208
static volatile char page_n_dev = 0;
static unsigned long iomapadr;
static DEFINE_SPINLOCK(oct5066_spin);
/*
* We use map_priv_1 to identify which device we are.
*/
static void __oct5066_page(struct map_info *map, __u8 byte)
{
outb(byte,PAGE_IO);
page_n_dev = byte;
}
static inline void oct5066_page(struct map_info *map, unsigned long ofs)
{
__u8 byte = map->map_priv_1 | (ofs >> WINDOW_SHIFT);
if (page_n_dev != byte)
__oct5066_page(map, byte);
}
static map_word oct5066_read8(struct map_info *map, unsigned long ofs)
{
map_word ret;
spin_lock(&oct5066_spin);
oct5066_page(map, ofs);
ret.x[0] = readb(iomapadr + (ofs & WINDOW_MASK));
spin_unlock(&oct5066_spin);
return ret;
}
static void oct5066_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
{
while(len) {
unsigned long thislen = len;
if (len > (WINDOW_LENGTH - (from & WINDOW_MASK)))
thislen = WINDOW_LENGTH-(from & WINDOW_MASK);
spin_lock(&oct5066_spin);
oct5066_page(map, from);
memcpy_fromio(to, iomapadr + from, thislen);
spin_unlock(&oct5066_spin);
to += thislen;
from += thislen;
len -= thislen;
}
}
static void oct5066_write8(struct map_info *map, map_word d, unsigned long adr)
{
spin_lock(&oct5066_spin);
oct5066_page(map, adr);
writeb(d.x[0], iomapadr + (adr & WINDOW_MASK));
spin_unlock(&oct5066_spin);
}
static void oct5066_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
{
while(len) {
unsigned long thislen = len;
if (len > (WINDOW_LENGTH - (to & WINDOW_MASK)))
thislen = WINDOW_LENGTH-(to & WINDOW_MASK);
spin_lock(&oct5066_spin);
oct5066_page(map, to);
memcpy_toio(iomapadr + to, from, thislen);
spin_unlock(&oct5066_spin);
to += thislen;
from += thislen;
len -= thislen;
}
}
static struct map_info oct5066_map[2] = {
{
.name = "Octagon 5066 Socket",
.phys = NO_XIP,
.size = 512 * 1024,
.bankwidth = 1,
.read = oct5066_read8,
.copy_from = oct5066_copy_from,
.write = oct5066_write8,
.copy_to = oct5066_copy_to,
.map_priv_1 = 1<<6
},
{
.name = "Octagon 5066 Internal Flash",
.phys = NO_XIP,
.size = 2 * 1024 * 1024,
.bankwidth = 1,
.read = oct5066_read8,
.copy_from = oct5066_copy_from,
.write = oct5066_write8,
.copy_to = oct5066_copy_to,
.map_priv_1 = 2<<6
}
};
static struct mtd_info *oct5066_mtd[2] = {NULL, NULL};
// OctProbe - Sense if this is an octagon card
// ---------------------------------------------------------------------
/* Perform a simple validity test, we map the window select SSD0 and
change pages while monitoring the window. A change in the window,
controlled by the PAGE_IO port is a functioning 5066 board. This will
fail if the thing in the socket is set to a uniform value. */
static int __init OctProbe(void)
{
unsigned int Base = (1 << 6);
unsigned long I;
unsigned long Values[10];
for (I = 0; I != 20; I++)
{
outb(Base + (I%10),PAGE_IO);
if (I < 10)
{
// Record the value and check for uniqueness
Values[I%10] = readl(iomapadr);
if (I > 0 && Values[I%10] == Values[0])
return -EAGAIN;
}
else
{
// Make sure we get the same values on the second pass
if (Values[I%10] != readl(iomapadr))
return -EAGAIN;
}
}
return 0;
}
void cleanup_oct5066(void)
{
int i;
for (i=0; i<2; i++) {
if (oct5066_mtd[i]) {
mtd_device_unregister(oct5066_mtd[i]);
map_destroy(oct5066_mtd[i]);
}
}
iounmap((void *)iomapadr);
release_region(PAGE_IO, 1);
}
static int __init init_oct5066(void)
{
int i;
int ret = 0;
// Do an autoprobe sequence
if (!request_region(PAGE_IO,1,"Octagon SSD")) {
printk(KERN_NOTICE "5066: Page Register in Use\n");
return -EAGAIN;
}
iomapadr = (unsigned long)ioremap(WINDOW_START, WINDOW_LENGTH);
if (!iomapadr) {
printk(KERN_NOTICE "Failed to ioremap memory region\n");
ret = -EIO;
goto out_rel;
}
if (OctProbe() != 0) {
printk(KERN_NOTICE "5066: Octagon Probe Failed, is this an Octagon 5066 SBC?\n");
iounmap((void *)iomapadr);
ret = -EAGAIN;
goto out_unmap;
}
// Print out our little header..
printk("Octagon 5066 SSD IO:0x%x MEM:0x%x-0x%x\n",PAGE_IO,WINDOW_START,
WINDOW_START+WINDOW_LENGTH);
for (i=0; i<2; i++) {
oct5066_mtd[i] = do_map_probe("cfi_probe", &oct5066_map[i]);
if (!oct5066_mtd[i])
oct5066_mtd[i] = do_map_probe("jedec", &oct5066_map[i]);
if (!oct5066_mtd[i])
oct5066_mtd[i] = do_map_probe("map_ram", &oct5066_map[i]);
if (!oct5066_mtd[i])
oct5066_mtd[i] = do_map_probe("map_rom", &oct5066_map[i]);
if (oct5066_mtd[i]) {
oct5066_mtd[i]->owner = THIS_MODULE;
mtd_device_register(oct5066_mtd[i], NULL, 0);
}
}
if (!oct5066_mtd[0] && !oct5066_mtd[1]) {
cleanup_oct5066();
return -ENXIO;
}
return 0;
out_unmap:
iounmap((void *)iomapadr);
out_rel:
release_region(PAGE_IO, 1);
return ret;
}
module_init(init_oct5066);
module_exit(cleanup_oct5066);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jason Gunthorpe <jgg@deltatee.com>, David Woodhouse <dwmw2@infradead.org>");
MODULE_DESCRIPTION("MTD map driver for Octagon 5066 Single Board Computer");
...@@ -40,9 +40,8 @@ static int physmap_flash_remove(struct platform_device *dev) ...@@ -40,9 +40,8 @@ static int physmap_flash_remove(struct platform_device *dev)
info = platform_get_drvdata(dev); info = platform_get_drvdata(dev);
if (info == NULL) if (info == NULL)
return 0; return 0;
platform_set_drvdata(dev, NULL);
physmap_data = dev->dev.platform_data; physmap_data = dev_get_platdata(&dev->dev);
if (info->cmtd) { if (info->cmtd) {
mtd_device_unregister(info->cmtd); mtd_device_unregister(info->cmtd);
...@@ -69,7 +68,7 @@ static void physmap_set_vpp(struct map_info *map, int state) ...@@ -69,7 +68,7 @@ static void physmap_set_vpp(struct map_info *map, int state)
unsigned long flags; unsigned long flags;
pdev = (struct platform_device *)map->map_priv_1; pdev = (struct platform_device *)map->map_priv_1;
physmap_data = pdev->dev.platform_data; physmap_data = dev_get_platdata(&pdev->dev);
if (!physmap_data->set_vpp) if (!physmap_data->set_vpp)
return; return;
...@@ -103,7 +102,7 @@ static int physmap_flash_probe(struct platform_device *dev) ...@@ -103,7 +102,7 @@ static int physmap_flash_probe(struct platform_device *dev)
int i; int i;
int devices_found = 0; int devices_found = 0;
physmap_data = dev->dev.platform_data; physmap_data = dev_get_platdata(&dev->dev);
if (physmap_data == NULL) if (physmap_data == NULL)
return -ENODEV; return -ENODEV;
......
...@@ -84,8 +84,6 @@ static int platram_remove(struct platform_device *pdev) ...@@ -84,8 +84,6 @@ static int platram_remove(struct platform_device *pdev)
{ {
struct platram_info *info = to_platram_info(pdev); struct platram_info *info = to_platram_info(pdev);
platform_set_drvdata(pdev, NULL);
dev_dbg(&pdev->dev, "removing device\n"); dev_dbg(&pdev->dev, "removing device\n");
if (info == NULL) if (info == NULL)
...@@ -130,13 +128,13 @@ static int platram_probe(struct platform_device *pdev) ...@@ -130,13 +128,13 @@ static int platram_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev, "probe entered\n"); dev_dbg(&pdev->dev, "probe entered\n");
if (pdev->dev.platform_data == NULL) { if (dev_get_platdata(&pdev->dev) == NULL) {
dev_err(&pdev->dev, "no platform data supplied\n"); dev_err(&pdev->dev, "no platform data supplied\n");
err = -ENOENT; err = -ENOENT;
goto exit_error; goto exit_error;
} }
pdata = pdev->dev.platform_data; pdata = dev_get_platdata(&pdev->dev);
info = kzalloc(sizeof(*info), GFP_KERNEL); info = kzalloc(sizeof(*info), GFP_KERNEL);
if (info == NULL) { if (info == NULL) {
......
...@@ -49,7 +49,7 @@ static const char * const probes[] = { "RedBoot", "cmdlinepart", NULL }; ...@@ -49,7 +49,7 @@ static const char * const probes[] = { "RedBoot", "cmdlinepart", NULL };
static int 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 flash_platform_data *flash = dev_get_platdata(&pdev->dev);
struct pxa2xx_flash_info *info; struct pxa2xx_flash_info *info;
struct resource *res; struct resource *res;
...@@ -107,8 +107,6 @@ static int pxa2xx_flash_remove(struct platform_device *dev) ...@@ -107,8 +107,6 @@ static int pxa2xx_flash_remove(struct platform_device *dev)
{ {
struct pxa2xx_flash_info *info = platform_get_drvdata(dev); struct pxa2xx_flash_info *info = platform_get_drvdata(dev);
platform_set_drvdata(dev, NULL);
mtd_device_unregister(info->mtd); mtd_device_unregister(info->mtd);
map_destroy(info->mtd); map_destroy(info->mtd);
......
...@@ -34,10 +34,9 @@ static int rbtx4939_flash_remove(struct platform_device *dev) ...@@ -34,10 +34,9 @@ static int rbtx4939_flash_remove(struct platform_device *dev)
info = platform_get_drvdata(dev); info = platform_get_drvdata(dev);
if (!info) if (!info)
return 0; return 0;
platform_set_drvdata(dev, NULL);
if (info->mtd) { if (info->mtd) {
struct rbtx4939_flash_data *pdata = dev->dev.platform_data; struct rbtx4939_flash_data *pdata = dev_get_platdata(&dev->dev);
mtd_device_unregister(info->mtd); mtd_device_unregister(info->mtd);
map_destroy(info->mtd); map_destroy(info->mtd);
...@@ -57,7 +56,7 @@ static int rbtx4939_flash_probe(struct platform_device *dev) ...@@ -57,7 +56,7 @@ static int rbtx4939_flash_probe(struct platform_device *dev)
int err = 0; int err = 0;
unsigned long size; unsigned long size;
pdata = dev->dev.platform_data; pdata = dev_get_platdata(&dev->dev);
if (!pdata) if (!pdata)
return -ENODEV; return -ENODEV;
......
...@@ -248,7 +248,7 @@ static const char * const part_probes[] = { "cmdlinepart", "RedBoot", NULL }; ...@@ -248,7 +248,7 @@ static const char * const part_probes[] = { "cmdlinepart", "RedBoot", NULL };
static int 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 flash_platform_data *plat = dev_get_platdata(&pdev->dev);
struct sa_info *info; struct sa_info *info;
int err; int err;
...@@ -277,9 +277,8 @@ static int sa1100_mtd_probe(struct platform_device *pdev) ...@@ -277,9 +277,8 @@ static int sa1100_mtd_probe(struct platform_device *pdev)
static int __exit sa1100_mtd_remove(struct platform_device *pdev) static int __exit sa1100_mtd_remove(struct platform_device *pdev)
{ {
struct sa_info *info = platform_get_drvdata(pdev); struct sa_info *info = platform_get_drvdata(pdev);
struct flash_platform_data *plat = pdev->dev.platform_data; struct flash_platform_data *plat = dev_get_platdata(&pdev->dev);
platform_set_drvdata(pdev, NULL);
sa1100_destroy(info, plat); sa1100_destroy(info, plat);
return 0; return 0;
......
/* ######################################################################
Tempustech VMAX SBC301 MTD Driver.
The VMAx 301 is a SBC based on . It
comes with three builtin AMD 29F016B flash chips and a socket for SRAM or
more flash. Each unit has it's own 8k mapping into a settable region
(0xD8000). There are two 8k mappings for each MTD, the first is always set
to the lower 8k of the device the second is paged. Writing a 16 bit page
value to anywhere in the first 8k will cause the second 8k to page around.
To boot the device a bios extension must be installed into the first 8k
of flash that is smart enough to copy itself down, page in the rest of
itself and begin executing.
##################################################################### */
#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/spinlock.h>
#include <asm/io.h>
#include <linux/mtd/map.h>
#include <linux/mtd/mtd.h>
#define WINDOW_START 0xd8000
#define WINDOW_LENGTH 0x2000
#define WINDOW_SHIFT 25
#define WINDOW_MASK 0x1FFF
/* Actually we could use two spinlocks, but we'd have to have
more private space in the struct map_info. We lose a little
performance like this, but we'd probably lose more by having
the extra indirection from having one of the map->map_priv
fields pointing to yet another private struct.
*/
static DEFINE_SPINLOCK(vmax301_spin);
static void __vmax301_page(struct map_info *map, unsigned long page)
{
writew(page, map->map_priv_2 - WINDOW_LENGTH);
map->map_priv_1 = page;
}
static inline void vmax301_page(struct map_info *map,
unsigned long ofs)
{
unsigned long page = (ofs >> WINDOW_SHIFT);
if (map->map_priv_1 != page)
__vmax301_page(map, page);
}
static map_word vmax301_read8(struct map_info *map, unsigned long ofs)
{
map_word ret;
spin_lock(&vmax301_spin);
vmax301_page(map, ofs);
ret.x[0] = readb(map->map_priv_2 + (ofs & WINDOW_MASK));
spin_unlock(&vmax301_spin);
return ret;
}
static void vmax301_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
{
while(len) {
unsigned long thislen = len;
if (len > (WINDOW_LENGTH - (from & WINDOW_MASK)))
thislen = WINDOW_LENGTH-(from & WINDOW_MASK);
spin_lock(&vmax301_spin);
vmax301_page(map, from);
memcpy_fromio(to, map->map_priv_2 + from, thislen);
spin_unlock(&vmax301_spin);
to += thislen;
from += thislen;
len -= thislen;
}
}
static void vmax301_write8(struct map_info *map, map_word d, unsigned long adr)
{
spin_lock(&vmax301_spin);
vmax301_page(map, adr);
writeb(d.x[0], map->map_priv_2 + (adr & WINDOW_MASK));
spin_unlock(&vmax301_spin);
}
static void vmax301_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
{
while(len) {
unsigned long thislen = len;
if (len > (WINDOW_LENGTH - (to & WINDOW_MASK)))
thislen = WINDOW_LENGTH-(to & WINDOW_MASK);
spin_lock(&vmax301_spin);
vmax301_page(map, to);
memcpy_toio(map->map_priv_2 + to, from, thislen);
spin_unlock(&vmax301_spin);
to += thislen;
from += thislen;
len -= thislen;
}
}
static struct map_info vmax_map[2] = {
{
.name = "VMAX301 Internal Flash",
.phys = NO_XIP,
.size = 3*2*1024*1024,
.bankwidth = 1,
.read = vmax301_read8,
.copy_from = vmax301_copy_from,
.write = vmax301_write8,
.copy_to = vmax301_copy_to,
.map_priv_1 = WINDOW_START + WINDOW_LENGTH,
.map_priv_2 = 0xFFFFFFFF
},
{
.name = "VMAX301 Socket",
.phys = NO_XIP,
.size = 0,
.bankwidth = 1,
.read = vmax301_read8,
.copy_from = vmax301_copy_from,
.write = vmax301_write8,
.copy_to = vmax301_copy_to,
.map_priv_1 = WINDOW_START + (3*WINDOW_LENGTH),
.map_priv_2 = 0xFFFFFFFF
}
};
static struct mtd_info *vmax_mtd[2] = {NULL, NULL};
static void __exit cleanup_vmax301(void)
{
int i;
for (i=0; i<2; i++) {
if (vmax_mtd[i]) {
mtd_device_unregister(vmax_mtd[i]);
map_destroy(vmax_mtd[i]);
}
}
iounmap((void *)vmax_map[0].map_priv_1 - WINDOW_START);
}
static int __init init_vmax301(void)
{
int i;
unsigned long iomapadr;
// Print out our little header..
printk("Tempustech VMAX 301 MEM:0x%x-0x%x\n",WINDOW_START,
WINDOW_START+4*WINDOW_LENGTH);
iomapadr = (unsigned long)ioremap(WINDOW_START, WINDOW_LENGTH*4);
if (!iomapadr) {
printk("Failed to ioremap memory region\n");
return -EIO;
}
/* Put the address in the map's private data area.
We store the actual MTD IO address rather than the
address of the first half, because it's used more
often.
*/
vmax_map[0].map_priv_2 = iomapadr + WINDOW_START;
vmax_map[1].map_priv_2 = iomapadr + (3*WINDOW_START);
for (i=0; i<2; i++) {
vmax_mtd[i] = do_map_probe("cfi_probe", &vmax_map[i]);
if (!vmax_mtd[i])
vmax_mtd[i] = do_map_probe("jedec", &vmax_map[i]);
if (!vmax_mtd[i])
vmax_mtd[i] = do_map_probe("map_ram", &vmax_map[i]);
if (!vmax_mtd[i])
vmax_mtd[i] = do_map_probe("map_rom", &vmax_map[i]);
if (vmax_mtd[i]) {
vmax_mtd[i]->owner = THIS_MODULE;
mtd_device_register(vmax_mtd[i], NULL, 0);
}
}
if (!vmax_mtd[0] && !vmax_mtd[1]) {
iounmap((void *)iomapadr);
return -ENXIO;
}
return 0;
}
module_init(init_vmax301);
module_exit(cleanup_vmax301);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
MODULE_DESCRIPTION("MTD map driver for Tempustech VMAX SBC301 board");
...@@ -285,6 +285,16 @@ static DEVICE_ATTR(bitflip_threshold, S_IRUGO | S_IWUSR, ...@@ -285,6 +285,16 @@ static DEVICE_ATTR(bitflip_threshold, S_IRUGO | S_IWUSR,
mtd_bitflip_threshold_show, mtd_bitflip_threshold_show,
mtd_bitflip_threshold_store); mtd_bitflip_threshold_store);
static ssize_t mtd_ecc_step_size_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mtd_info *mtd = dev_get_drvdata(dev);
return snprintf(buf, PAGE_SIZE, "%u\n", mtd->ecc_step_size);
}
static DEVICE_ATTR(ecc_step_size, S_IRUGO, mtd_ecc_step_size_show, NULL);
static struct attribute *mtd_attrs[] = { static struct attribute *mtd_attrs[] = {
&dev_attr_type.attr, &dev_attr_type.attr,
&dev_attr_flags.attr, &dev_attr_flags.attr,
...@@ -296,6 +306,7 @@ static struct attribute *mtd_attrs[] = { ...@@ -296,6 +306,7 @@ static struct attribute *mtd_attrs[] = {
&dev_attr_numeraseregions.attr, &dev_attr_numeraseregions.attr,
&dev_attr_name.attr, &dev_attr_name.attr,
&dev_attr_ecc_strength.attr, &dev_attr_ecc_strength.attr,
&dev_attr_ecc_step_size.attr,
&dev_attr_bitflip_threshold.attr, &dev_attr_bitflip_threshold.attr,
NULL, NULL,
}; };
......
...@@ -516,6 +516,7 @@ static struct mtd_part *allocate_partition(struct mtd_info *master, ...@@ -516,6 +516,7 @@ static struct mtd_part *allocate_partition(struct mtd_info *master,
} }
slave->mtd.ecclayout = master->ecclayout; slave->mtd.ecclayout = master->ecclayout;
slave->mtd.ecc_step_size = master->ecc_step_size;
slave->mtd.ecc_strength = master->ecc_strength; slave->mtd.ecc_strength = master->ecc_strength;
slave->mtd.bitflip_threshold = master->bitflip_threshold; slave->mtd.bitflip_threshold = master->bitflip_threshold;
......
...@@ -1425,7 +1425,7 @@ static void mtdswap_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) ...@@ -1425,7 +1425,7 @@ static void mtdswap_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
return; return;
while ((this_opt = strsep(&parts, ",")) != NULL) { while ((this_opt = strsep(&parts, ",")) != NULL) {
if (strict_strtoul(this_opt, 0, &part) < 0) if (kstrtoul(this_opt, 0, &part) < 0)
return; return;
if (mtd->index == part) if (mtd->index == part)
......
...@@ -43,6 +43,7 @@ config MTD_SM_COMMON ...@@ -43,6 +43,7 @@ config MTD_SM_COMMON
config MTD_NAND_DENALI config MTD_NAND_DENALI
tristate "Support Denali NAND controller" tristate "Support Denali NAND controller"
depends on HAS_DMA
help help
Enable support for the Denali NAND controller. This should be Enable support for the Denali NAND controller. This should be
combined with either the PCI or platform drivers to provide device combined with either the PCI or platform drivers to provide device
...@@ -75,7 +76,7 @@ config MTD_NAND_DENALI_SCRATCH_REG_ADDR ...@@ -75,7 +76,7 @@ config MTD_NAND_DENALI_SCRATCH_REG_ADDR
config MTD_NAND_GPIO config MTD_NAND_GPIO
tristate "GPIO NAND Flash driver" tristate "GPIO NAND Flash driver"
depends on GPIOLIB && ARM depends on GPIOLIB
help help
This enables a GPIO based NAND flash driver. This enables a GPIO based NAND flash driver.
...@@ -354,7 +355,7 @@ config MTD_NAND_ATMEL ...@@ -354,7 +355,7 @@ config MTD_NAND_ATMEL
config MTD_NAND_PXA3xx config MTD_NAND_PXA3xx
tristate "Support for NAND flash devices on PXA3xx" tristate "Support for NAND flash devices on PXA3xx"
depends on PXA3xx || ARCH_MMP depends on PXA3xx || ARCH_MMP || PLAT_ORION
help help
This enables the driver for the NAND flash device found on This enables the driver for the NAND flash device found on
PXA3xx processors PXA3xx processors
...@@ -432,13 +433,6 @@ config MTD_NAND_PLATFORM ...@@ -432,13 +433,6 @@ config MTD_NAND_PLATFORM
devices. You will need to provide platform-specific functions devices. You will need to provide platform-specific functions
via platform_data. via platform_data.
config MTD_ALAUDA
tristate "MTD driver for Olympus MAUSB-10 and Fujifilm DPC-R1"
depends on USB
help
These two (and possibly other) Alauda-based cardreaders for
SmartMedia and xD allow raw flash access.
config MTD_NAND_ORION config MTD_NAND_ORION
tristate "NAND Flash support for Marvell Orion SoC" tristate "NAND Flash support for Marvell Orion SoC"
depends on PLAT_ORION depends on PLAT_ORION
......
...@@ -31,7 +31,6 @@ obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o ...@@ -31,7 +31,6 @@ obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o
obj-$(CONFIG_MTD_NAND_PXA3xx) += pxa3xx_nand.o obj-$(CONFIG_MTD_NAND_PXA3xx) += pxa3xx_nand.o
obj-$(CONFIG_MTD_NAND_TMIO) += tmio_nand.o obj-$(CONFIG_MTD_NAND_TMIO) += tmio_nand.o
obj-$(CONFIG_MTD_NAND_PLATFORM) += plat_nand.o obj-$(CONFIG_MTD_NAND_PLATFORM) += plat_nand.o
obj-$(CONFIG_MTD_ALAUDA) += alauda.o
obj-$(CONFIG_MTD_NAND_PASEMI) += pasemi_nand.o obj-$(CONFIG_MTD_NAND_PASEMI) += pasemi_nand.o
obj-$(CONFIG_MTD_NAND_ORION) += orion_nand.o obj-$(CONFIG_MTD_NAND_ORION) += orion_nand.o
obj-$(CONFIG_MTD_NAND_FSL_ELBC) += fsl_elbc_nand.o obj-$(CONFIG_MTD_NAND_FSL_ELBC) += fsl_elbc_nand.o
......
/*
* MTD driver for Alauda chips
*
* Copyright (C) 2007 Joern Engel <joern@logfs.org>
*
* Based on drivers/usb/usb-skeleton.c which is:
* Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com)
* and on drivers/usb/storage/alauda.c, which is:
* (c) 2005 Daniel Drake <dsd@gentoo.org>
*
* Idea and initial work by Arnd Bergmann <arnd@arndb.de>
*/
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/kref.h>
#include <linux/usb.h>
#include <linux/mutex.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand_ecc.h>
/* Control commands */
#define ALAUDA_GET_XD_MEDIA_STATUS 0x08
#define ALAUDA_ACK_XD_MEDIA_CHANGE 0x0a
#define ALAUDA_GET_XD_MEDIA_SIG 0x86
/* Common prefix */
#define ALAUDA_BULK_CMD 0x40
/* The two ports */
#define ALAUDA_PORT_XD 0x00
#define ALAUDA_PORT_SM 0x01
/* Bulk commands */
#define ALAUDA_BULK_READ_PAGE 0x84
#define ALAUDA_BULK_READ_OOB 0x85 /* don't use, there's a chip bug */
#define ALAUDA_BULK_READ_BLOCK 0x94
#define ALAUDA_BULK_ERASE_BLOCK 0xa3
#define ALAUDA_BULK_WRITE_PAGE 0xa4
#define ALAUDA_BULK_WRITE_BLOCK 0xb4
#define ALAUDA_BULK_RESET_MEDIA 0xe0
/* Address shifting */
#define PBA_LO(pba) ((pba & 0xF) << 5)
#define PBA_HI(pba) (pba >> 3)
#define PBA_ZONE(pba) (pba >> 11)
#define TIMEOUT HZ
static const struct usb_device_id alauda_table[] = {
{ USB_DEVICE(0x0584, 0x0008) }, /* Fujifilm DPC-R1 */
{ USB_DEVICE(0x07b4, 0x010a) }, /* Olympus MAUSB-10 */
{ }
};
MODULE_DEVICE_TABLE(usb, alauda_table);
struct alauda_card {
u8 id; /* id byte */
u8 chipshift; /* 1<<chipshift total size */
u8 pageshift; /* 1<<pageshift page size */
u8 blockshift; /* 1<<blockshift block size */
};
struct alauda {
struct usb_device *dev;
struct usb_interface *interface;
struct mtd_info *mtd;
struct alauda_card *card;
struct mutex card_mutex;
u32 pagemask;
u32 bytemask;
u32 blockmask;
unsigned int write_out;
unsigned int bulk_in;
unsigned int bulk_out;
u8 port;
struct kref kref;
};
static struct alauda_card alauda_card_ids[] = {
/* NAND flash */
{ 0x6e, 20, 8, 12}, /* 1 MB */
{ 0xe8, 20, 8, 12}, /* 1 MB */
{ 0xec, 20, 8, 12}, /* 1 MB */
{ 0x64, 21, 8, 12}, /* 2 MB */
{ 0xea, 21, 8, 12}, /* 2 MB */
{ 0x6b, 22, 9, 13}, /* 4 MB */
{ 0xe3, 22, 9, 13}, /* 4 MB */
{ 0xe5, 22, 9, 13}, /* 4 MB */
{ 0xe6, 23, 9, 13}, /* 8 MB */
{ 0x73, 24, 9, 14}, /* 16 MB */
{ 0x75, 25, 9, 14}, /* 32 MB */
{ 0x76, 26, 9, 14}, /* 64 MB */
{ 0x79, 27, 9, 14}, /* 128 MB */
{ 0x71, 28, 9, 14}, /* 256 MB */
/* MASK ROM */
{ 0x5d, 21, 9, 13}, /* 2 MB */
{ 0xd5, 22, 9, 13}, /* 4 MB */
{ 0xd6, 23, 9, 13}, /* 8 MB */
{ 0x57, 24, 9, 13}, /* 16 MB */
{ 0x58, 25, 9, 13}, /* 32 MB */
{ }
};
static struct alauda_card *get_card(u8 id)
{
struct alauda_card *card;
for (card = alauda_card_ids; card->id; card++)
if (card->id == id)
return card;
return NULL;
}
static void alauda_delete(struct kref *kref)
{
struct alauda *al = container_of(kref, struct alauda, kref);
if (al->mtd) {
mtd_device_unregister(al->mtd);
kfree(al->mtd);
}
usb_put_dev(al->dev);
kfree(al);
}
static int alauda_get_media_status(struct alauda *al, void *buf)
{
int ret;
mutex_lock(&al->card_mutex);
ret = usb_control_msg(al->dev, usb_rcvctrlpipe(al->dev, 0),
ALAUDA_GET_XD_MEDIA_STATUS, 0xc0, 0, 1, buf, 2, HZ);
mutex_unlock(&al->card_mutex);
return ret;
}
static int alauda_ack_media(struct alauda *al)
{
int ret;
mutex_lock(&al->card_mutex);
ret = usb_control_msg(al->dev, usb_sndctrlpipe(al->dev, 0),
ALAUDA_ACK_XD_MEDIA_CHANGE, 0x40, 0, 1, NULL, 0, HZ);
mutex_unlock(&al->card_mutex);
return ret;
}
static int alauda_get_media_signatures(struct alauda *al, void *buf)
{
int ret;
mutex_lock(&al->card_mutex);
ret = usb_control_msg(al->dev, usb_rcvctrlpipe(al->dev, 0),
ALAUDA_GET_XD_MEDIA_SIG, 0xc0, 0, 0, buf, 4, HZ);
mutex_unlock(&al->card_mutex);
return ret;
}
static void alauda_reset(struct alauda *al)
{
u8 command[] = {
ALAUDA_BULK_CMD, ALAUDA_BULK_RESET_MEDIA, 0, 0,
0, 0, 0, 0, al->port
};
mutex_lock(&al->card_mutex);
usb_bulk_msg(al->dev, al->bulk_out, command, 9, NULL, HZ);
mutex_unlock(&al->card_mutex);
}
static void correct_data(void *buf, void *read_ecc,
int *corrected, int *uncorrected)
{
u8 calc_ecc[3];
int err;
nand_calculate_ecc(NULL, buf, calc_ecc);
err = nand_correct_data(NULL, buf, read_ecc, calc_ecc);
if (err) {
if (err > 0)
(*corrected)++;
else
(*uncorrected)++;
}
}
struct alauda_sg_request {
struct urb *urb[3];
struct completion comp;
};
static void alauda_complete(struct urb *urb)
{
struct completion *comp = urb->context;
if (comp)
complete(comp);
}
static int __alauda_read_page(struct mtd_info *mtd, loff_t from, void *buf,
void *oob)
{
struct alauda_sg_request sg;
struct alauda *al = mtd->priv;
u32 pba = from >> al->card->blockshift;
u32 page = (from >> al->card->pageshift) & al->pagemask;
u8 command[] = {
ALAUDA_BULK_CMD, ALAUDA_BULK_READ_PAGE, PBA_HI(pba),
PBA_ZONE(pba), 0, PBA_LO(pba) + page, 1, 0, al->port
};
int i, err;
for (i=0; i<3; i++)
sg.urb[i] = NULL;
err = -ENOMEM;
for (i=0; i<3; i++) {
sg.urb[i] = usb_alloc_urb(0, GFP_NOIO);
if (!sg.urb[i])
goto out;
}
init_completion(&sg.comp);
usb_fill_bulk_urb(sg.urb[0], al->dev, al->bulk_out, command, 9,
alauda_complete, NULL);
usb_fill_bulk_urb(sg.urb[1], al->dev, al->bulk_in, buf, mtd->writesize,
alauda_complete, NULL);
usb_fill_bulk_urb(sg.urb[2], al->dev, al->bulk_in, oob, 16,
alauda_complete, &sg.comp);
mutex_lock(&al->card_mutex);
for (i=0; i<3; i++) {
err = usb_submit_urb(sg.urb[i], GFP_NOIO);
if (err)
goto cancel;
}
if (!wait_for_completion_timeout(&sg.comp, TIMEOUT)) {
err = -ETIMEDOUT;
cancel:
for (i=0; i<3; i++) {
usb_kill_urb(sg.urb[i]);
}
}
mutex_unlock(&al->card_mutex);
out:
usb_free_urb(sg.urb[0]);
usb_free_urb(sg.urb[1]);
usb_free_urb(sg.urb[2]);
return err;
}
static int alauda_read_page(struct mtd_info *mtd, loff_t from,
void *buf, u8 *oob, int *corrected, int *uncorrected)
{
int err;
err = __alauda_read_page(mtd, from, buf, oob);
if (err)
return err;
correct_data(buf, oob+13, corrected, uncorrected);
correct_data(buf+256, oob+8, corrected, uncorrected);
return 0;
}
static int alauda_write_page(struct mtd_info *mtd, loff_t to, void *buf,
void *oob)
{
struct alauda_sg_request sg;
struct alauda *al = mtd->priv;
u32 pba = to >> al->card->blockshift;
u32 page = (to >> al->card->pageshift) & al->pagemask;
u8 command[] = {
ALAUDA_BULK_CMD, ALAUDA_BULK_WRITE_PAGE, PBA_HI(pba),
PBA_ZONE(pba), 0, PBA_LO(pba) + page, 32, 0, al->port
};
int i, err;
for (i=0; i<3; i++)
sg.urb[i] = NULL;
err = -ENOMEM;
for (i=0; i<3; i++) {
sg.urb[i] = usb_alloc_urb(0, GFP_NOIO);
if (!sg.urb[i])
goto out;
}
init_completion(&sg.comp);
usb_fill_bulk_urb(sg.urb[0], al->dev, al->bulk_out, command, 9,
alauda_complete, NULL);
usb_fill_bulk_urb(sg.urb[1], al->dev, al->write_out, buf,mtd->writesize,
alauda_complete, NULL);
usb_fill_bulk_urb(sg.urb[2], al->dev, al->write_out, oob, 16,
alauda_complete, &sg.comp);
mutex_lock(&al->card_mutex);
for (i=0; i<3; i++) {
err = usb_submit_urb(sg.urb[i], GFP_NOIO);
if (err)
goto cancel;
}
if (!wait_for_completion_timeout(&sg.comp, TIMEOUT)) {
err = -ETIMEDOUT;
cancel:
for (i=0; i<3; i++) {
usb_kill_urb(sg.urb[i]);
}
}
mutex_unlock(&al->card_mutex);
out:
usb_free_urb(sg.urb[0]);
usb_free_urb(sg.urb[1]);
usb_free_urb(sg.urb[2]);
return err;
}
static int alauda_erase_block(struct mtd_info *mtd, loff_t ofs)
{
struct alauda_sg_request sg;
struct alauda *al = mtd->priv;
u32 pba = ofs >> al->card->blockshift;
u8 command[] = {
ALAUDA_BULK_CMD, ALAUDA_BULK_ERASE_BLOCK, PBA_HI(pba),
PBA_ZONE(pba), 0, PBA_LO(pba), 0x02, 0, al->port
};
u8 buf[2];
int i, err;
for (i=0; i<2; i++)
sg.urb[i] = NULL;
err = -ENOMEM;
for (i=0; i<2; i++) {
sg.urb[i] = usb_alloc_urb(0, GFP_NOIO);
if (!sg.urb[i])
goto out;
}
init_completion(&sg.comp);
usb_fill_bulk_urb(sg.urb[0], al->dev, al->bulk_out, command, 9,
alauda_complete, NULL);
usb_fill_bulk_urb(sg.urb[1], al->dev, al->bulk_in, buf, 2,
alauda_complete, &sg.comp);
mutex_lock(&al->card_mutex);
for (i=0; i<2; i++) {
err = usb_submit_urb(sg.urb[i], GFP_NOIO);
if (err)
goto cancel;
}
if (!wait_for_completion_timeout(&sg.comp, TIMEOUT)) {
err = -ETIMEDOUT;
cancel:
for (i=0; i<2; i++) {
usb_kill_urb(sg.urb[i]);
}
}
mutex_unlock(&al->card_mutex);
out:
usb_free_urb(sg.urb[0]);
usb_free_urb(sg.urb[1]);
return err;
}
static int alauda_read_oob(struct mtd_info *mtd, loff_t from, void *oob)
{
static u8 ignore_buf[512]; /* write only */
return __alauda_read_page(mtd, from, ignore_buf, oob);
}
static int alauda_isbad(struct mtd_info *mtd, loff_t ofs)
{
u8 oob[16];
int err;
err = alauda_read_oob(mtd, ofs, oob);
if (err)
return err;
/* A block is marked bad if two or more bits are zero */
return hweight8(oob[5]) >= 7 ? 0 : 1;
}
static int alauda_bounce_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf)
{
struct alauda *al = mtd->priv;
void *bounce_buf;
int err, corrected=0, uncorrected=0;
bounce_buf = kmalloc(mtd->writesize, GFP_KERNEL);
if (!bounce_buf)
return -ENOMEM;
*retlen = len;
while (len) {
u8 oob[16];
size_t byte = from & al->bytemask;
size_t cplen = min(len, mtd->writesize - byte);
err = alauda_read_page(mtd, from, bounce_buf, oob,
&corrected, &uncorrected);
if (err)
goto out;
memcpy(buf, bounce_buf + byte, cplen);
buf += cplen;
from += cplen;
len -= cplen;
}
err = 0;
if (corrected)
err = 1; /* return max_bitflips per ecc step */
if (uncorrected)
err = -EBADMSG;
out:
kfree(bounce_buf);
return err;
}
static int alauda_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf)
{
struct alauda *al = mtd->priv;
int err, corrected=0, uncorrected=0;
if ((from & al->bytemask) || (len & al->bytemask))
return alauda_bounce_read(mtd, from, len, retlen, buf);
*retlen = len;
while (len) {
u8 oob[16];
err = alauda_read_page(mtd, from, buf, oob,
&corrected, &uncorrected);
if (err)
return err;
buf += mtd->writesize;
from += mtd->writesize;
len -= mtd->writesize;
}
err = 0;
if (corrected)
err = 1; /* return max_bitflips per ecc step */
if (uncorrected)
err = -EBADMSG;
return err;
}
static int alauda_write(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf)
{
struct alauda *al = mtd->priv;
int err;
if ((to & al->bytemask) || (len & al->bytemask))
return -EINVAL;
*retlen = len;
while (len) {
u32 page = (to >> al->card->pageshift) & al->pagemask;
u8 oob[16] = { 'h', 'e', 'l', 'l', 'o', 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
/* don't write to bad blocks */
if (page == 0) {
err = alauda_isbad(mtd, to);
if (err) {
return -EIO;
}
}
nand_calculate_ecc(mtd, buf, &oob[13]);
nand_calculate_ecc(mtd, buf+256, &oob[8]);
err = alauda_write_page(mtd, to, (void*)buf, oob);
if (err)
return err;
buf += mtd->writesize;
to += mtd->writesize;
len -= mtd->writesize;
}
return 0;
}
static int __alauda_erase(struct mtd_info *mtd, struct erase_info *instr)
{
struct alauda *al = mtd->priv;
u32 ofs = instr->addr;
u32 len = instr->len;
int err;
if ((ofs & al->blockmask) || (len & al->blockmask))
return -EINVAL;
while (len) {
/* don't erase bad blocks */
err = alauda_isbad(mtd, ofs);
if (err > 0)
err = -EIO;
if (err < 0)
return err;
err = alauda_erase_block(mtd, ofs);
if (err < 0)
return err;
ofs += mtd->erasesize;
len -= mtd->erasesize;
}
return 0;
}
static int alauda_erase(struct mtd_info *mtd, struct erase_info *instr)
{
int err;
err = __alauda_erase(mtd, instr);
instr->state = err ? MTD_ERASE_FAILED : MTD_ERASE_DONE;
mtd_erase_callback(instr);
return err;
}
static int alauda_init_media(struct alauda *al)
{
u8 buf[4], *b0=buf, *b1=buf+1;
struct alauda_card *card;
struct mtd_info *mtd;
int err;
mtd = kzalloc(sizeof(*mtd), GFP_KERNEL);
if (!mtd)
return -ENOMEM;
for (;;) {
err = alauda_get_media_status(al, buf);
if (err < 0)
goto error;
if (*b0 & 0x10)
break;
msleep(20);
}
err = alauda_ack_media(al);
if (err)
goto error;
msleep(10);
err = alauda_get_media_status(al, buf);
if (err < 0)
goto error;
if (*b0 != 0x14) {
/* media not ready */
err = -EIO;
goto error;
}
err = alauda_get_media_signatures(al, buf);
if (err < 0)
goto error;
card = get_card(*b1);
if (!card) {
printk(KERN_ERR"Alauda: unknown card id %02x\n", *b1);
err = -EIO;
goto error;
}
printk(KERN_INFO"pagesize=%x\nerasesize=%x\nsize=%xMiB\n",
1<<card->pageshift, 1<<card->blockshift,
1<<(card->chipshift-20));
al->card = card;
al->pagemask = (1 << (card->blockshift - card->pageshift)) - 1;
al->bytemask = (1 << card->pageshift) - 1;
al->blockmask = (1 << card->blockshift) - 1;
mtd->name = "alauda";
mtd->size = 1<<card->chipshift;
mtd->erasesize = 1<<card->blockshift;
mtd->writesize = 1<<card->pageshift;
mtd->type = MTD_NANDFLASH;
mtd->flags = MTD_CAP_NANDFLASH;
mtd->_read = alauda_read;
mtd->_write = alauda_write;
mtd->_erase = alauda_erase;
mtd->_block_isbad = alauda_isbad;
mtd->priv = al;
mtd->owner = THIS_MODULE;
mtd->ecc_strength = 1;
err = mtd_device_register(mtd, NULL, 0);
if (err) {
err = -ENFILE;
goto error;
}
al->mtd = mtd;
alauda_reset(al); /* no clue whether this is necessary */
return 0;
error:
kfree(mtd);
return err;
}
static int alauda_check_media(struct alauda *al)
{
u8 buf[2], *b0 = buf, *b1 = buf+1;
int err;
err = alauda_get_media_status(al, buf);
if (err < 0)
return err;
if ((*b1 & 0x01) == 0) {
/* door open */
return -EIO;
}
if ((*b0 & 0x80) || ((*b0 & 0x1F) == 0x10)) {
/* no media ? */
return -EIO;
}
if (*b0 & 0x08) {
/* media change ? */
return alauda_init_media(al);
}
return 0;
}
static int alauda_probe(struct usb_interface *interface,
const struct usb_device_id *id)
{
struct alauda *al;
struct usb_host_interface *iface;
struct usb_endpoint_descriptor *ep,
*ep_in=NULL, *ep_out=NULL, *ep_wr=NULL;
int i, err = -ENOMEM;
al = kzalloc(2*sizeof(*al), GFP_KERNEL);
if (!al)
goto error;
kref_init(&al->kref);
usb_set_intfdata(interface, al);
al->dev = usb_get_dev(interface_to_usbdev(interface));
al->interface = interface;
iface = interface->cur_altsetting;
for (i = 0; i < iface->desc.bNumEndpoints; ++i) {
ep = &iface->endpoint[i].desc;
if (usb_endpoint_is_bulk_in(ep)) {
ep_in = ep;
} else if (usb_endpoint_is_bulk_out(ep)) {
if (i==0)
ep_wr = ep;
else
ep_out = ep;
}
}
err = -EIO;
if (!ep_wr || !ep_in || !ep_out)
goto error;
al->write_out = usb_sndbulkpipe(al->dev,
usb_endpoint_num(ep_wr));
al->bulk_in = usb_rcvbulkpipe(al->dev,
usb_endpoint_num(ep_in));
al->bulk_out = usb_sndbulkpipe(al->dev,
usb_endpoint_num(ep_out));
/* second device is identical up to now */
memcpy(al+1, al, sizeof(*al));
mutex_init(&al[0].card_mutex);
mutex_init(&al[1].card_mutex);
al[0].port = ALAUDA_PORT_XD;
al[1].port = ALAUDA_PORT_SM;
dev_info(&interface->dev, "alauda probed\n");
alauda_check_media(al);
alauda_check_media(al+1);
return 0;
error:
if (al)
kref_put(&al->kref, alauda_delete);
return err;
}
static void alauda_disconnect(struct usb_interface *interface)
{
struct alauda *al;
al = usb_get_intfdata(interface);
usb_set_intfdata(interface, NULL);
/* FIXME: prevent more I/O from starting */
/* decrement our usage count */
if (al)
kref_put(&al->kref, alauda_delete);
dev_info(&interface->dev, "alauda gone");
}
static struct usb_driver alauda_driver = {
.name = "alauda",
.probe = alauda_probe,
.disconnect = alauda_disconnect,
.id_table = alauda_table,
};
module_usb_driver(alauda_driver);
MODULE_LICENSE("GPL");
...@@ -258,7 +258,6 @@ static int ams_delta_init(struct platform_device *pdev) ...@@ -258,7 +258,6 @@ static int ams_delta_init(struct platform_device *pdev)
out_mtd: out_mtd:
gpio_free_array(_mandatory_gpio, ARRAY_SIZE(_mandatory_gpio)); gpio_free_array(_mandatory_gpio, ARRAY_SIZE(_mandatory_gpio));
out_gpio: out_gpio:
platform_set_drvdata(pdev, NULL);
gpio_free(AMS_DELTA_GPIO_PIN_NAND_RB); gpio_free(AMS_DELTA_GPIO_PIN_NAND_RB);
iounmap(io_base); iounmap(io_base);
out_free: out_free:
......
此差异已折叠。
/*
* Atmel Nand Flash Controller (NFC) - System peripherals regsters.
* Based on SAMA5D3 datasheet.
*
* © Copyright 2013 Atmel Corporation.
*
* 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.
*/
#ifndef ATMEL_NAND_NFC_H
#define ATMEL_NAND_NFC_H
/*
* HSMC NFC registers
*/
#define ATMEL_HSMC_NFC_CFG 0x00 /* NFC Configuration Register */
#define NFC_CFG_PAGESIZE (7 << 0)
#define NFC_CFG_PAGESIZE_512 (0 << 0)
#define NFC_CFG_PAGESIZE_1024 (1 << 0)
#define NFC_CFG_PAGESIZE_2048 (2 << 0)
#define NFC_CFG_PAGESIZE_4096 (3 << 0)
#define NFC_CFG_PAGESIZE_8192 (4 << 0)
#define NFC_CFG_WSPARE (1 << 8)
#define NFC_CFG_RSPARE (1 << 9)
#define NFC_CFG_NFC_DTOCYC (0xf << 16)
#define NFC_CFG_NFC_DTOMUL (0x7 << 20)
#define NFC_CFG_NFC_SPARESIZE (0x7f << 24)
#define NFC_CFG_NFC_SPARESIZE_BIT_POS 24
#define ATMEL_HSMC_NFC_CTRL 0x04 /* NFC Control Register */
#define NFC_CTRL_ENABLE (1 << 0)
#define NFC_CTRL_DISABLE (1 << 1)
#define ATMEL_HSMC_NFC_SR 0x08 /* NFC Status Register */
#define NFC_SR_XFR_DONE (1 << 16)
#define NFC_SR_CMD_DONE (1 << 17)
#define NFC_SR_RB_EDGE (1 << 24)
#define ATMEL_HSMC_NFC_IER 0x0c
#define ATMEL_HSMC_NFC_IDR 0x10
#define ATMEL_HSMC_NFC_IMR 0x14
#define ATMEL_HSMC_NFC_CYCLE0 0x18 /* NFC Address Cycle Zero */
#define ATMEL_HSMC_NFC_ADDR_CYCLE0 (0xff)
#define ATMEL_HSMC_NFC_BANK 0x1c /* NFC Bank Register */
#define ATMEL_HSMC_NFC_BANK0 (0 << 0)
#define ATMEL_HSMC_NFC_BANK1 (1 << 0)
#define nfc_writel(addr, reg, value) \
writel((value), (addr) + ATMEL_HSMC_NFC_##reg)
#define nfc_readl(addr, reg) \
readl_relaxed((addr) + ATMEL_HSMC_NFC_##reg)
/*
* NFC Address Command definitions
*/
#define NFCADDR_CMD_CMD1 (0xff << 2) /* Command for Cycle 1 */
#define NFCADDR_CMD_CMD1_BIT_POS 2
#define NFCADDR_CMD_CMD2 (0xff << 10) /* Command for Cycle 2 */
#define NFCADDR_CMD_CMD2_BIT_POS 10
#define NFCADDR_CMD_VCMD2 (0x1 << 18) /* Valid Cycle 2 Command */
#define NFCADDR_CMD_ACYCLE (0x7 << 19) /* Number of Address required */
#define NFCADDR_CMD_ACYCLE_NONE (0x0 << 19)
#define NFCADDR_CMD_ACYCLE_1 (0x1 << 19)
#define NFCADDR_CMD_ACYCLE_2 (0x2 << 19)
#define NFCADDR_CMD_ACYCLE_3 (0x3 << 19)
#define NFCADDR_CMD_ACYCLE_4 (0x4 << 19)
#define NFCADDR_CMD_ACYCLE_5 (0x5 << 19)
#define NFCADDR_CMD_ACYCLE_BIT_POS 19
#define NFCADDR_CMD_CSID (0x7 << 22) /* Chip Select Identifier */
#define NFCADDR_CMD_CSID_0 (0x0 << 22)
#define NFCADDR_CMD_CSID_1 (0x1 << 22)
#define NFCADDR_CMD_CSID_2 (0x2 << 22)
#define NFCADDR_CMD_CSID_3 (0x3 << 22)
#define NFCADDR_CMD_CSID_4 (0x4 << 22)
#define NFCADDR_CMD_CSID_5 (0x5 << 22)
#define NFCADDR_CMD_CSID_6 (0x6 << 22)
#define NFCADDR_CMD_CSID_7 (0x7 << 22)
#define NFCADDR_CMD_DATAEN (0x1 << 25) /* Data Transfer Enable */
#define NFCADDR_CMD_DATADIS (0x0 << 25) /* Data Transfer Disable */
#define NFCADDR_CMD_NFCRD (0x0 << 26) /* NFC Read Enable */
#define NFCADDR_CMD_NFCWR (0x1 << 26) /* NFC Write Enable */
#define NFCADDR_CMD_NFCBUSY (0x1 << 27) /* NFC Busy */
#define nfc_cmd_addr1234_writel(cmd, addr1234, nfc_base) \
writel((addr1234), (cmd) + nfc_base)
#define nfc_cmd_readl(bitstatus, nfc_base) \
readl_relaxed((bitstatus) + nfc_base)
#define NFC_TIME_OUT_MS 100
#define NFC_SRAM_BANK1_OFFSET 0x1200
#endif
...@@ -411,7 +411,7 @@ static int au1550nd_probe(struct platform_device *pdev) ...@@ -411,7 +411,7 @@ static int au1550nd_probe(struct platform_device *pdev)
struct resource *r; struct resource *r;
int ret, cs; int ret, cs;
pd = pdev->dev.platform_data; pd = dev_get_platdata(&pdev->dev);
if (!pd) { if (!pd) {
dev_err(&pdev->dev, "missing platform data\n"); dev_err(&pdev->dev, "missing platform data\n");
return -ENODEV; return -ENODEV;
......
...@@ -171,7 +171,7 @@ static struct bf5xx_nand_info *to_nand_info(struct platform_device *pdev) ...@@ -171,7 +171,7 @@ static struct bf5xx_nand_info *to_nand_info(struct platform_device *pdev)
static struct bf5xx_nand_platform *to_nand_plat(struct platform_device *pdev) static struct bf5xx_nand_platform *to_nand_plat(struct platform_device *pdev)
{ {
return pdev->dev.platform_data; return dev_get_platdata(&pdev->dev);
} }
/* /*
...@@ -671,8 +671,6 @@ static int bf5xx_nand_remove(struct platform_device *pdev) ...@@ -671,8 +671,6 @@ static int bf5xx_nand_remove(struct platform_device *pdev)
{ {
struct bf5xx_nand_info *info = to_nand_info(pdev); struct bf5xx_nand_info *info = to_nand_info(pdev);
platform_set_drvdata(pdev, NULL);
/* first thing we need to do is release all our mtds /* first thing we need to do is release all our mtds
* and their partitions, then go through freeing the * and their partitions, then go through freeing the
* resources used * resources used
...@@ -832,7 +830,6 @@ static int bf5xx_nand_probe(struct platform_device *pdev) ...@@ -832,7 +830,6 @@ static int bf5xx_nand_probe(struct platform_device *pdev)
out_err_nand_scan: out_err_nand_scan:
bf5xx_nand_dma_remove(info); bf5xx_nand_dma_remove(info);
out_err_hw_init: out_err_hw_init:
platform_set_drvdata(pdev, NULL);
kfree(info); kfree(info);
out_err_kzalloc: out_err_kzalloc:
peripheral_free_list(bfin_nfc_pin_req); peripheral_free_list(bfin_nfc_pin_req);
......
...@@ -197,7 +197,7 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr) ...@@ -197,7 +197,7 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr)
} }
/* Allocate memory for MTD device structure and private data */ /* Allocate memory for MTD device structure and private data */
new_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL); new_mtd = kzalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL);
if (!new_mtd) { if (!new_mtd) {
printk(KERN_WARNING "Unable to allocate CS553X NAND MTD device structure.\n"); printk(KERN_WARNING "Unable to allocate CS553X NAND MTD device structure.\n");
err = -ENOMEM; err = -ENOMEM;
...@@ -207,10 +207,6 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr) ...@@ -207,10 +207,6 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr)
/* Get pointer to private data */ /* Get pointer to private data */
this = (struct nand_chip *)(&new_mtd[1]); this = (struct nand_chip *)(&new_mtd[1]);
/* Initialize structures */
memset(new_mtd, 0, sizeof(struct mtd_info));
memset(this, 0, sizeof(struct nand_chip));
/* Link the private data with the MTD structure */ /* Link the private data with the MTD structure */
new_mtd->priv = this; new_mtd->priv = this;
new_mtd->owner = THIS_MODULE; new_mtd->owner = THIS_MODULE;
......
...@@ -530,7 +530,7 @@ MODULE_DEVICE_TABLE(of, davinci_nand_of_match); ...@@ -530,7 +530,7 @@ MODULE_DEVICE_TABLE(of, davinci_nand_of_match);
static struct davinci_nand_pdata static struct davinci_nand_pdata
*nand_davinci_get_pdata(struct platform_device *pdev) *nand_davinci_get_pdata(struct platform_device *pdev)
{ {
if (!pdev->dev.platform_data && pdev->dev.of_node) { if (!dev_get_platdata(&pdev->dev) && pdev->dev.of_node) {
struct davinci_nand_pdata *pdata; struct davinci_nand_pdata *pdata;
const char *mode; const char *mode;
u32 prop; u32 prop;
...@@ -575,13 +575,13 @@ static struct davinci_nand_pdata ...@@ -575,13 +575,13 @@ static struct davinci_nand_pdata
pdata->bbt_options = NAND_BBT_USE_FLASH; pdata->bbt_options = NAND_BBT_USE_FLASH;
} }
return pdev->dev.platform_data; return dev_get_platdata(&pdev->dev);
} }
#else #else
static struct davinci_nand_pdata static struct davinci_nand_pdata
*nand_davinci_get_pdata(struct platform_device *pdev) *nand_davinci_get_pdata(struct platform_device *pdev)
{ {
return pdev->dev.platform_data; return dev_get_platdata(&pdev->dev);
} }
#endif #endif
...@@ -623,11 +623,14 @@ static int __init nand_davinci_probe(struct platform_device *pdev) ...@@ -623,11 +623,14 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
goto err_nomem; goto err_nomem;
} }
vaddr = devm_request_and_ioremap(&pdev->dev, res1); vaddr = devm_ioremap_resource(&pdev->dev, res1);
base = devm_request_and_ioremap(&pdev->dev, res2); if (IS_ERR(vaddr)) {
if (!vaddr || !base) { ret = PTR_ERR(vaddr);
dev_err(&pdev->dev, "ioremap failed\n"); goto err_ioremap;
ret = -EADDRNOTAVAIL; }
base = devm_ioremap_resource(&pdev->dev, res2);
if (IS_ERR(base)) {
ret = PTR_ERR(base);
goto err_ioremap; goto err_ioremap;
} }
......
...@@ -1520,7 +1520,7 @@ int denali_init(struct denali_nand_info *denali) ...@@ -1520,7 +1520,7 @@ int denali_init(struct denali_nand_info *denali)
* so just let controller do 15bit ECC for MLC and 8bit ECC for * so just let controller do 15bit ECC for MLC and 8bit ECC for
* SLC if possible. * SLC if possible.
* */ * */
if (denali->nand.cellinfo & 0xc && if (denali->nand.cellinfo & NAND_CI_CELLTYPE_MSK &&
(denali->mtd.oobsize > (denali->bbtskipbytes + (denali->mtd.oobsize > (denali->bbtskipbytes +
ECC_15BITS * (denali->mtd.writesize / ECC_15BITS * (denali->mtd.writesize /
ECC_SECTOR_SIZE)))) { ECC_SECTOR_SIZE)))) {
......
...@@ -46,13 +46,13 @@ static unsigned long __initdata doc_locations[] = { ...@@ -46,13 +46,13 @@ static unsigned long __initdata doc_locations[] = {
0xfffd8000, 0xfffda000, 0xfffdc000, 0xfffde000, 0xfffd8000, 0xfffda000, 0xfffdc000, 0xfffde000,
0xfffe0000, 0xfffe2000, 0xfffe4000, 0xfffe6000, 0xfffe0000, 0xfffe2000, 0xfffe4000, 0xfffe6000,
0xfffe8000, 0xfffea000, 0xfffec000, 0xfffee000, 0xfffe8000, 0xfffea000, 0xfffec000, 0xfffee000,
#else /* CONFIG_MTD_DOCPROBE_HIGH */ #else
0xc8000, 0xca000, 0xcc000, 0xce000, 0xc8000, 0xca000, 0xcc000, 0xce000,
0xd0000, 0xd2000, 0xd4000, 0xd6000, 0xd0000, 0xd2000, 0xd4000, 0xd6000,
0xd8000, 0xda000, 0xdc000, 0xde000, 0xd8000, 0xda000, 0xdc000, 0xde000,
0xe0000, 0xe2000, 0xe4000, 0xe6000, 0xe0000, 0xe2000, 0xe4000, 0xe6000,
0xe8000, 0xea000, 0xec000, 0xee000, 0xe8000, 0xea000, 0xec000, 0xee000,
#endif /* CONFIG_MTD_DOCPROBE_HIGH */ #endif
#endif #endif
0xffffffff }; 0xffffffff };
......
...@@ -1093,7 +1093,6 @@ static int docg4_block_markbad(struct mtd_info *mtd, loff_t ofs) ...@@ -1093,7 +1093,6 @@ static int docg4_block_markbad(struct mtd_info *mtd, loff_t ofs)
struct nand_chip *nand = mtd->priv; struct nand_chip *nand = mtd->priv;
struct docg4_priv *doc = nand->priv; struct docg4_priv *doc = nand->priv;
struct nand_bbt_descr *bbtd = nand->badblock_pattern; struct nand_bbt_descr *bbtd = nand->badblock_pattern;
int block = (int)(ofs >> nand->bbt_erase_shift);
int page = (int)(ofs >> nand->page_shift); int page = (int)(ofs >> nand->page_shift);
uint32_t g4_addr = mtd_to_docg4_address(page, 0); uint32_t g4_addr = mtd_to_docg4_address(page, 0);
...@@ -1108,9 +1107,6 @@ static int docg4_block_markbad(struct mtd_info *mtd, loff_t ofs) ...@@ -1108,9 +1107,6 @@ static int docg4_block_markbad(struct mtd_info *mtd, loff_t ofs)
if (buf == NULL) if (buf == NULL)
return -ENOMEM; return -ENOMEM;
/* update bbt in memory */
nand->bbt[block / 4] |= 0x01 << ((block & 0x03) * 2);
/* write bit-wise negation of pattern to oob buffer */ /* write bit-wise negation of pattern to oob buffer */
memset(nand->oob_poi, 0xff, mtd->oobsize); memset(nand->oob_poi, 0xff, mtd->oobsize);
for (i = 0; i < bbtd->len; i++) for (i = 0; i < bbtd->len; i++)
...@@ -1120,8 +1116,6 @@ static int docg4_block_markbad(struct mtd_info *mtd, loff_t ofs) ...@@ -1120,8 +1116,6 @@ static int docg4_block_markbad(struct mtd_info *mtd, loff_t ofs)
write_page_prologue(mtd, g4_addr); write_page_prologue(mtd, g4_addr);
docg4_write_page(mtd, nand, buf, 1); docg4_write_page(mtd, nand, buf, 1);
ret = pageprog(mtd); ret = pageprog(mtd);
if (!ret)
mtd->ecc_stats.badblocks++;
kfree(buf); kfree(buf);
...@@ -1368,7 +1362,6 @@ static int __init probe_docg4(struct platform_device *pdev) ...@@ -1368,7 +1362,6 @@ static int __init probe_docg4(struct platform_device *pdev)
struct nand_chip *nand = mtd->priv; struct nand_chip *nand = mtd->priv;
struct docg4_priv *doc = nand->priv; struct docg4_priv *doc = nand->priv;
nand_release(mtd); /* deletes partitions and mtd devices */ nand_release(mtd); /* deletes partitions and mtd devices */
platform_set_drvdata(pdev, NULL);
free_bch(doc->bch); free_bch(doc->bch);
kfree(mtd); kfree(mtd);
} }
...@@ -1380,7 +1373,6 @@ static int __exit cleanup_docg4(struct platform_device *pdev) ...@@ -1380,7 +1373,6 @@ static int __exit cleanup_docg4(struct platform_device *pdev)
{ {
struct docg4_priv *doc = platform_get_drvdata(pdev); struct docg4_priv *doc = platform_get_drvdata(pdev);
nand_release(doc->mtd); nand_release(doc->mtd);
platform_set_drvdata(pdev, NULL);
free_bch(doc->bch); free_bch(doc->bch);
kfree(doc->mtd); kfree(doc->mtd);
iounmap(doc->virtadr); iounmap(doc->virtadr);
......
...@@ -823,7 +823,7 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv) ...@@ -823,7 +823,7 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
/* set up nand options */ /* set up nand options */
chip->bbt_options = NAND_BBT_USE_FLASH; chip->bbt_options = NAND_BBT_USE_FLASH;
chip->options = NAND_NO_SUBPAGE_WRITE;
if (ioread32be(&ifc->cspr_cs[priv->bank].cspr) & CSPR_PORT_SIZE_16) { if (ioread32be(&ifc->cspr_cs[priv->bank].cspr) & CSPR_PORT_SIZE_16) {
chip->read_byte = fsl_ifc_read_byte16; chip->read_byte = fsl_ifc_read_byte16;
...@@ -908,7 +908,6 @@ static int fsl_ifc_chip_remove(struct fsl_ifc_mtd *priv) ...@@ -908,7 +908,6 @@ static int fsl_ifc_chip_remove(struct fsl_ifc_mtd *priv)
ifc_nand_ctrl->chips[priv->bank] = NULL; ifc_nand_ctrl->chips[priv->bank] = NULL;
dev_set_drvdata(priv->dev, NULL); dev_set_drvdata(priv->dev, NULL);
kfree(priv);
return 0; return 0;
} }
......
...@@ -889,6 +889,24 @@ static int fsmc_nand_probe_config_dt(struct platform_device *pdev, ...@@ -889,6 +889,24 @@ static int fsmc_nand_probe_config_dt(struct platform_device *pdev,
if (of_get_property(np, "nand-skip-bbtscan", NULL)) if (of_get_property(np, "nand-skip-bbtscan", NULL))
pdata->options = NAND_SKIP_BBTSCAN; pdata->options = NAND_SKIP_BBTSCAN;
pdata->nand_timings = devm_kzalloc(&pdev->dev,
sizeof(*pdata->nand_timings), GFP_KERNEL);
if (!pdata->nand_timings) {
dev_err(&pdev->dev, "no memory for nand_timing\n");
return -ENOMEM;
}
of_property_read_u8_array(np, "timings", (u8 *)pdata->nand_timings,
sizeof(*pdata->nand_timings));
/* Set default NAND bank to 0 */
pdata->bank = 0;
if (!of_property_read_u32(np, "bank", &val)) {
if (val > 3) {
dev_err(&pdev->dev, "invalid bank %u\n", val);
return -EINVAL;
}
pdata->bank = val;
}
return 0; return 0;
} }
#else #else
...@@ -940,9 +958,6 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) ...@@ -940,9 +958,6 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
} }
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_data"); res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_data");
if (!res)
return -EINVAL;
host->data_va = devm_ioremap_resource(&pdev->dev, res); host->data_va = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(host->data_va)) if (IS_ERR(host->data_va))
return PTR_ERR(host->data_va); return PTR_ERR(host->data_va);
...@@ -950,25 +965,16 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) ...@@ -950,25 +965,16 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
host->data_pa = (dma_addr_t)res->start; host->data_pa = (dma_addr_t)res->start;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_addr"); res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_addr");
if (!res)
return -EINVAL;
host->addr_va = devm_ioremap_resource(&pdev->dev, res); host->addr_va = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(host->addr_va)) if (IS_ERR(host->addr_va))
return PTR_ERR(host->addr_va); return PTR_ERR(host->addr_va);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_cmd"); res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_cmd");
if (!res)
return -EINVAL;
host->cmd_va = devm_ioremap_resource(&pdev->dev, res); host->cmd_va = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(host->cmd_va)) if (IS_ERR(host->cmd_va))
return PTR_ERR(host->cmd_va); return PTR_ERR(host->cmd_va);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fsmc_regs"); res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fsmc_regs");
if (!res)
return -EINVAL;
host->regs_va = devm_ioremap_resource(&pdev->dev, res); host->regs_va = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(host->regs_va)) if (IS_ERR(host->regs_va))
return PTR_ERR(host->regs_va); return PTR_ERR(host->regs_va);
...@@ -1174,8 +1180,6 @@ static int fsmc_nand_remove(struct platform_device *pdev) ...@@ -1174,8 +1180,6 @@ static int fsmc_nand_remove(struct platform_device *pdev)
{ {
struct fsmc_nand_data *host = platform_get_drvdata(pdev); struct fsmc_nand_data *host = platform_get_drvdata(pdev);
platform_set_drvdata(pdev, NULL);
if (host) { if (host) {
nand_release(&host->mtd); nand_release(&host->mtd);
...@@ -1190,7 +1194,7 @@ static int fsmc_nand_remove(struct platform_device *pdev) ...@@ -1190,7 +1194,7 @@ static int fsmc_nand_remove(struct platform_device *pdev)
return 0; return 0;
} }
#ifdef CONFIG_PM #ifdef CONFIG_PM_SLEEP
static int fsmc_nand_suspend(struct device *dev) static int fsmc_nand_suspend(struct device *dev)
{ {
struct fsmc_nand_data *host = dev_get_drvdata(dev); struct fsmc_nand_data *host = dev_get_drvdata(dev);
...@@ -1210,9 +1214,9 @@ static int fsmc_nand_resume(struct device *dev) ...@@ -1210,9 +1214,9 @@ static int fsmc_nand_resume(struct device *dev)
} }
return 0; return 0;
} }
#endif
static SIMPLE_DEV_PM_OPS(fsmc_nand_pm_ops, fsmc_nand_suspend, fsmc_nand_resume); static SIMPLE_DEV_PM_OPS(fsmc_nand_pm_ops, fsmc_nand_suspend, fsmc_nand_resume);
#endif
#ifdef CONFIG_OF #ifdef CONFIG_OF
static const struct of_device_id fsmc_nand_id_table[] = { static const struct of_device_id fsmc_nand_id_table[] = {
...@@ -1229,9 +1233,7 @@ static struct platform_driver fsmc_nand_driver = { ...@@ -1229,9 +1233,7 @@ static struct platform_driver fsmc_nand_driver = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.name = "fsmc-nand", .name = "fsmc-nand",
.of_match_table = of_match_ptr(fsmc_nand_id_table), .of_match_table = of_match_ptr(fsmc_nand_id_table),
#ifdef CONFIG_PM
.pm = &fsmc_nand_pm_ops, .pm = &fsmc_nand_pm_ops,
#endif
}, },
}; };
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/err.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -86,59 +87,11 @@ static void gpio_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) ...@@ -86,59 +87,11 @@ static void gpio_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
gpio_nand_dosync(gpiomtd); gpio_nand_dosync(gpiomtd);
} }
static void gpio_nand_writebuf(struct mtd_info *mtd, const u_char *buf, int len)
{
struct nand_chip *this = mtd->priv;
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;
ioread8_rep(this->IO_ADDR_R, buf, len);
}
static void gpio_nand_writebuf16(struct mtd_info *mtd, const u_char *buf,
int len)
{
struct nand_chip *this = mtd->priv;
if (IS_ALIGNED((unsigned long)buf, 2)) {
iowrite16_rep(this->IO_ADDR_W, buf, len>>1);
} else {
int i;
unsigned short *ptr = (unsigned short *)buf;
for (i = 0; i < len; i += 2, ptr++)
writew(*ptr, this->IO_ADDR_W);
}
}
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)) {
ioread16_rep(this->IO_ADDR_R, buf, len>>1);
} else {
int i;
unsigned short *ptr = (unsigned short *)buf;
for (i = 0; i < len; i += 2, ptr++)
*ptr = readw(this->IO_ADDR_R);
}
}
static int gpio_nand_devready(struct mtd_info *mtd) static int gpio_nand_devready(struct mtd_info *mtd)
{ {
struct gpiomtd *gpiomtd = gpio_nand_getpriv(mtd); struct gpiomtd *gpiomtd = gpio_nand_getpriv(mtd);
if (gpio_is_valid(gpiomtd->plat.gpio_rdy)) return gpio_get_value(gpiomtd->plat.gpio_rdy);
return gpio_get_value(gpiomtd->plat.gpio_rdy);
return 1;
} }
#ifdef CONFIG_OF #ifdef CONFIG_OF
...@@ -153,6 +106,9 @@ static int gpio_nand_get_config_of(const struct device *dev, ...@@ -153,6 +106,9 @@ static int gpio_nand_get_config_of(const struct device *dev,
{ {
u32 val; u32 val;
if (!dev->of_node)
return -ENODEV;
if (!of_property_read_u32(dev->of_node, "bank-width", &val)) { if (!of_property_read_u32(dev->of_node, "bank-width", &val)) {
if (val == 2) { if (val == 2) {
plat->options |= NAND_BUSWIDTH_16; plat->options |= NAND_BUSWIDTH_16;
...@@ -211,8 +167,8 @@ static inline int gpio_nand_get_config(const struct device *dev, ...@@ -211,8 +167,8 @@ static inline int gpio_nand_get_config(const struct device *dev,
if (!ret) if (!ret)
return ret; return ret;
if (dev->platform_data) { if (dev_get_platdata(dev)) {
memcpy(plat, dev->platform_data, sizeof(*plat)); memcpy(plat, dev_get_platdata(dev), sizeof(*plat));
return 0; return 0;
} }
...@@ -230,145 +186,100 @@ gpio_nand_get_io_sync(struct platform_device *pdev) ...@@ -230,145 +186,100 @@ gpio_nand_get_io_sync(struct platform_device *pdev)
return platform_get_resource(pdev, IORESOURCE_MEM, 1); return platform_get_resource(pdev, IORESOURCE_MEM, 1);
} }
static int gpio_nand_remove(struct platform_device *dev) static int gpio_nand_remove(struct platform_device *pdev)
{ {
struct gpiomtd *gpiomtd = platform_get_drvdata(dev); struct gpiomtd *gpiomtd = platform_get_drvdata(pdev);
struct resource *res;
nand_release(&gpiomtd->mtd_info); nand_release(&gpiomtd->mtd_info);
res = gpio_nand_get_io_sync(dev);
iounmap(gpiomtd->io_sync);
if (res)
release_mem_region(res->start, resource_size(res));
res = platform_get_resource(dev, IORESOURCE_MEM, 0);
iounmap(gpiomtd->nand_chip.IO_ADDR_R);
release_mem_region(res->start, resource_size(res));
if (gpio_is_valid(gpiomtd->plat.gpio_nwp)) if (gpio_is_valid(gpiomtd->plat.gpio_nwp))
gpio_set_value(gpiomtd->plat.gpio_nwp, 0); gpio_set_value(gpiomtd->plat.gpio_nwp, 0);
gpio_set_value(gpiomtd->plat.gpio_nce, 1); gpio_set_value(gpiomtd->plat.gpio_nce, 1);
gpio_free(gpiomtd->plat.gpio_cle);
gpio_free(gpiomtd->plat.gpio_ale);
gpio_free(gpiomtd->plat.gpio_nce);
if (gpio_is_valid(gpiomtd->plat.gpio_nwp))
gpio_free(gpiomtd->plat.gpio_nwp);
if (gpio_is_valid(gpiomtd->plat.gpio_rdy))
gpio_free(gpiomtd->plat.gpio_rdy);
return 0; return 0;
} }
static void __iomem *request_and_remap(struct resource *res, size_t size, static int gpio_nand_probe(struct platform_device *pdev)
const char *name, int *err)
{
void __iomem *ptr;
if (!request_mem_region(res->start, resource_size(res), name)) {
*err = -EBUSY;
return NULL;
}
ptr = ioremap(res->start, size);
if (!ptr) {
release_mem_region(res->start, resource_size(res));
*err = -ENOMEM;
}
return ptr;
}
static int gpio_nand_probe(struct platform_device *dev)
{ {
struct gpiomtd *gpiomtd; struct gpiomtd *gpiomtd;
struct nand_chip *this; struct nand_chip *chip;
struct resource *res0, *res1; struct resource *res;
struct mtd_part_parser_data ppdata = {}; struct mtd_part_parser_data ppdata = {};
int ret = 0; int ret = 0;
if (!dev->dev.of_node && !dev->dev.platform_data) if (!pdev->dev.of_node && !dev_get_platdata(&pdev->dev))
return -EINVAL;
res0 = platform_get_resource(dev, IORESOURCE_MEM, 0);
if (!res0)
return -EINVAL; return -EINVAL;
gpiomtd = devm_kzalloc(&dev->dev, sizeof(*gpiomtd), GFP_KERNEL); gpiomtd = devm_kzalloc(&pdev->dev, sizeof(*gpiomtd), GFP_KERNEL);
if (gpiomtd == NULL) { if (!gpiomtd) {
dev_err(&dev->dev, "failed to create NAND MTD\n"); dev_err(&pdev->dev, "failed to create NAND MTD\n");
return -ENOMEM; return -ENOMEM;
} }
this = &gpiomtd->nand_chip; chip = &gpiomtd->nand_chip;
this->IO_ADDR_R = request_and_remap(res0, 2, "NAND", &ret);
if (!this->IO_ADDR_R) {
dev_err(&dev->dev, "unable to map NAND\n");
goto err_map;
}
res1 = gpio_nand_get_io_sync(dev); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res1) { chip->IO_ADDR_R = devm_ioremap_resource(&pdev->dev, res);
gpiomtd->io_sync = request_and_remap(res1, 4, "NAND sync", &ret); if (IS_ERR(chip->IO_ADDR_R))
if (!gpiomtd->io_sync) { return PTR_ERR(chip->IO_ADDR_R);
dev_err(&dev->dev, "unable to map sync NAND\n");
goto err_sync; res = gpio_nand_get_io_sync(pdev);
} if (res) {
gpiomtd->io_sync = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(gpiomtd->io_sync))
return PTR_ERR(gpiomtd->io_sync);
} }
ret = gpio_nand_get_config(&dev->dev, &gpiomtd->plat); ret = gpio_nand_get_config(&pdev->dev, &gpiomtd->plat);
if (ret) if (ret)
goto err_nce; return ret;
ret = gpio_request(gpiomtd->plat.gpio_nce, "NAND NCE"); ret = devm_gpio_request(&pdev->dev, gpiomtd->plat.gpio_nce, "NAND NCE");
if (ret) if (ret)
goto err_nce; return ret;
gpio_direction_output(gpiomtd->plat.gpio_nce, 1); gpio_direction_output(gpiomtd->plat.gpio_nce, 1);
if (gpio_is_valid(gpiomtd->plat.gpio_nwp)) { if (gpio_is_valid(gpiomtd->plat.gpio_nwp)) {
ret = gpio_request(gpiomtd->plat.gpio_nwp, "NAND NWP"); ret = devm_gpio_request(&pdev->dev, gpiomtd->plat.gpio_nwp,
"NAND NWP");
if (ret) if (ret)
goto err_nwp; return ret;
gpio_direction_output(gpiomtd->plat.gpio_nwp, 1);
} }
ret = gpio_request(gpiomtd->plat.gpio_ale, "NAND ALE");
ret = devm_gpio_request(&pdev->dev, gpiomtd->plat.gpio_ale, "NAND ALE");
if (ret) if (ret)
goto err_ale; return ret;
gpio_direction_output(gpiomtd->plat.gpio_ale, 0); gpio_direction_output(gpiomtd->plat.gpio_ale, 0);
ret = gpio_request(gpiomtd->plat.gpio_cle, "NAND CLE");
ret = devm_gpio_request(&pdev->dev, gpiomtd->plat.gpio_cle, "NAND CLE");
if (ret) if (ret)
goto err_cle; return ret;
gpio_direction_output(gpiomtd->plat.gpio_cle, 0); gpio_direction_output(gpiomtd->plat.gpio_cle, 0);
if (gpio_is_valid(gpiomtd->plat.gpio_rdy)) { if (gpio_is_valid(gpiomtd->plat.gpio_rdy)) {
ret = gpio_request(gpiomtd->plat.gpio_rdy, "NAND RDY"); ret = devm_gpio_request(&pdev->dev, gpiomtd->plat.gpio_rdy,
"NAND RDY");
if (ret) if (ret)
goto err_rdy; return ret;
gpio_direction_input(gpiomtd->plat.gpio_rdy); gpio_direction_input(gpiomtd->plat.gpio_rdy);
chip->dev_ready = gpio_nand_devready;
} }
chip->IO_ADDR_W = chip->IO_ADDR_R;
chip->ecc.mode = NAND_ECC_SOFT;
chip->options = gpiomtd->plat.options;
chip->chip_delay = gpiomtd->plat.chip_delay;
chip->cmd_ctrl = gpio_nand_cmd_ctrl;
this->IO_ADDR_W = this->IO_ADDR_R; gpiomtd->mtd_info.priv = chip;
this->ecc.mode = NAND_ECC_SOFT; gpiomtd->mtd_info.owner = THIS_MODULE;
this->options = gpiomtd->plat.options;
this->chip_delay = gpiomtd->plat.chip_delay;
/* install our routines */
this->cmd_ctrl = gpio_nand_cmd_ctrl;
this->dev_ready = gpio_nand_devready;
if (this->options & NAND_BUSWIDTH_16) { platform_set_drvdata(pdev, gpiomtd);
this->read_buf = gpio_nand_readbuf16;
this->write_buf = gpio_nand_writebuf16;
} else {
this->read_buf = gpio_nand_readbuf;
this->write_buf = gpio_nand_writebuf;
}
/* set the mtd private data for the nand driver */ if (gpio_is_valid(gpiomtd->plat.gpio_nwp))
gpiomtd->mtd_info.priv = this; gpio_direction_output(gpiomtd->plat.gpio_nwp, 1);
gpiomtd->mtd_info.owner = THIS_MODULE;
if (nand_scan(&gpiomtd->mtd_info, 1)) { if (nand_scan(&gpiomtd->mtd_info, 1)) {
dev_err(&dev->dev, "no nand chips found?\n");
ret = -ENXIO; ret = -ENXIO;
goto err_wp; goto err_wp;
} }
...@@ -377,38 +288,17 @@ static int gpio_nand_probe(struct platform_device *dev) ...@@ -377,38 +288,17 @@ static int gpio_nand_probe(struct platform_device *dev)
gpiomtd->plat.adjust_parts(&gpiomtd->plat, gpiomtd->plat.adjust_parts(&gpiomtd->plat,
gpiomtd->mtd_info.size); gpiomtd->mtd_info.size);
ppdata.of_node = dev->dev.of_node; ppdata.of_node = pdev->dev.of_node;
ret = mtd_device_parse_register(&gpiomtd->mtd_info, NULL, &ppdata, ret = mtd_device_parse_register(&gpiomtd->mtd_info, NULL, &ppdata,
gpiomtd->plat.parts, gpiomtd->plat.parts,
gpiomtd->plat.num_parts); gpiomtd->plat.num_parts);
if (ret) if (!ret)
goto err_wp; return 0;
platform_set_drvdata(dev, gpiomtd);
return 0;
err_wp: err_wp:
if (gpio_is_valid(gpiomtd->plat.gpio_nwp)) if (gpio_is_valid(gpiomtd->plat.gpio_nwp))
gpio_set_value(gpiomtd->plat.gpio_nwp, 0); gpio_set_value(gpiomtd->plat.gpio_nwp, 0);
if (gpio_is_valid(gpiomtd->plat.gpio_rdy))
gpio_free(gpiomtd->plat.gpio_rdy);
err_rdy:
gpio_free(gpiomtd->plat.gpio_cle);
err_cle:
gpio_free(gpiomtd->plat.gpio_ale);
err_ale:
if (gpio_is_valid(gpiomtd->plat.gpio_nwp))
gpio_free(gpiomtd->plat.gpio_nwp);
err_nwp:
gpio_free(gpiomtd->plat.gpio_nce);
err_nce:
iounmap(gpiomtd->io_sync);
if (res1)
release_mem_region(res1->start, resource_size(res1));
err_sync:
iounmap(gpiomtd->nand_chip.IO_ADDR_R);
release_mem_region(res0->start, resource_size(res0));
err_map:
return ret; return ret;
} }
...@@ -417,6 +307,7 @@ static struct platform_driver gpio_nand_driver = { ...@@ -417,6 +307,7 @@ static struct platform_driver gpio_nand_driver = {
.remove = gpio_nand_remove, .remove = gpio_nand_remove,
.driver = { .driver = {
.name = "gpio-nand", .name = "gpio-nand",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(gpio_nand_id_table), .of_match_table = of_match_ptr(gpio_nand_id_table),
}, },
}; };
......
...@@ -411,7 +411,7 @@ static int jz_nand_probe(struct platform_device *pdev) ...@@ -411,7 +411,7 @@ static int jz_nand_probe(struct platform_device *pdev)
struct jz_nand *nand; struct jz_nand *nand;
struct nand_chip *chip; struct nand_chip *chip;
struct mtd_info *mtd; struct mtd_info *mtd;
struct jz_nand_platform_data *pdata = pdev->dev.platform_data; struct jz_nand_platform_data *pdata = dev_get_platdata(&pdev->dev);
size_t chipnr, bank_idx; size_t chipnr, bank_idx;
uint8_t nand_maf_id = 0, nand_dev_id = 0; uint8_t nand_maf_id = 0, nand_dev_id = 0;
...@@ -538,7 +538,6 @@ static int jz_nand_probe(struct platform_device *pdev) ...@@ -538,7 +538,6 @@ static int jz_nand_probe(struct platform_device *pdev)
err_gpio_busy: err_gpio_busy:
if (pdata && gpio_is_valid(pdata->busy_gpio)) if (pdata && gpio_is_valid(pdata->busy_gpio))
gpio_free(pdata->busy_gpio); gpio_free(pdata->busy_gpio);
platform_set_drvdata(pdev, NULL);
err_iounmap_mmio: err_iounmap_mmio:
jz_nand_iounmap_resource(nand->mem, nand->base); jz_nand_iounmap_resource(nand->mem, nand->base);
err_free: err_free:
...@@ -549,7 +548,7 @@ static int jz_nand_probe(struct platform_device *pdev) ...@@ -549,7 +548,7 @@ static int jz_nand_probe(struct platform_device *pdev)
static int 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 *nand = platform_get_drvdata(pdev);
struct jz_nand_platform_data *pdata = pdev->dev.platform_data; struct jz_nand_platform_data *pdata = dev_get_platdata(&pdev->dev);
size_t i; size_t i;
nand_release(&nand->mtd); nand_release(&nand->mtd);
...@@ -570,7 +569,6 @@ static int jz_nand_remove(struct platform_device *pdev) ...@@ -570,7 +569,6 @@ static int jz_nand_remove(struct platform_device *pdev)
jz_nand_iounmap_resource(nand->mem, nand->base); jz_nand_iounmap_resource(nand->mem, nand->base);
platform_set_drvdata(pdev, NULL);
kfree(nand); kfree(nand);
return 0; return 0;
......
...@@ -696,7 +696,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev) ...@@ -696,7 +696,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
} }
lpc32xx_wp_disable(host); lpc32xx_wp_disable(host);
host->pdata = pdev->dev.platform_data; host->pdata = dev_get_platdata(&pdev->dev);
nand_chip->priv = host; /* link the private data structures */ nand_chip->priv = host; /* link the private data structures */
mtd->priv = nand_chip; mtd->priv = nand_chip;
...@@ -828,7 +828,6 @@ static int lpc32xx_nand_probe(struct platform_device *pdev) ...@@ -828,7 +828,6 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
err_exit2: err_exit2:
clk_disable(host->clk); clk_disable(host->clk);
clk_put(host->clk); clk_put(host->clk);
platform_set_drvdata(pdev, NULL);
err_exit1: err_exit1:
lpc32xx_wp_enable(host); lpc32xx_wp_enable(host);
gpio_free(host->ncfg->wp_gpio); gpio_free(host->ncfg->wp_gpio);
...@@ -851,7 +850,6 @@ static int lpc32xx_nand_remove(struct platform_device *pdev) ...@@ -851,7 +850,6 @@ static int lpc32xx_nand_remove(struct platform_device *pdev)
clk_disable(host->clk); clk_disable(host->clk);
clk_put(host->clk); clk_put(host->clk);
platform_set_drvdata(pdev, NULL);
lpc32xx_wp_enable(host); lpc32xx_wp_enable(host);
gpio_free(host->ncfg->wp_gpio); gpio_free(host->ncfg->wp_gpio);
......
...@@ -798,7 +798,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev) ...@@ -798,7 +798,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
} }
lpc32xx_wp_disable(host); lpc32xx_wp_disable(host);
host->pdata = pdev->dev.platform_data; host->pdata = dev_get_platdata(&pdev->dev);
mtd = &host->mtd; mtd = &host->mtd;
chip = &host->nand_chip; chip = &host->nand_chip;
...@@ -936,7 +936,6 @@ static int lpc32xx_nand_probe(struct platform_device *pdev) ...@@ -936,7 +936,6 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
err_exit2: err_exit2:
clk_disable(host->clk); clk_disable(host->clk);
clk_put(host->clk); clk_put(host->clk);
platform_set_drvdata(pdev, NULL);
err_exit1: err_exit1:
lpc32xx_wp_enable(host); lpc32xx_wp_enable(host);
gpio_free(host->ncfg->wp_gpio); gpio_free(host->ncfg->wp_gpio);
...@@ -963,7 +962,6 @@ static int lpc32xx_nand_remove(struct platform_device *pdev) ...@@ -963,7 +962,6 @@ static int lpc32xx_nand_remove(struct platform_device *pdev)
clk_disable(host->clk); clk_disable(host->clk);
clk_put(host->clk); clk_put(host->clk);
platform_set_drvdata(pdev, NULL);
lpc32xx_wp_enable(host); lpc32xx_wp_enable(host);
gpio_free(host->ncfg->wp_gpio); gpio_free(host->ncfg->wp_gpio);
......
...@@ -266,7 +266,7 @@ static struct nand_ecclayout nandv2_hw_eccoob_4k = { ...@@ -266,7 +266,7 @@ static struct nand_ecclayout nandv2_hw_eccoob_4k = {
} }
}; };
static const char const *part_probes[] = { static const char * const part_probes[] = {
"cmdlinepart", "RedBoot", "ofpart", NULL }; "cmdlinepart", "RedBoot", "ofpart", NULL };
static void memcpy32_fromio(void *trg, const void __iomem *src, size_t size) static void memcpy32_fromio(void *trg, const void __iomem *src, size_t size)
...@@ -1432,7 +1432,8 @@ static int mxcnd_probe(struct platform_device *pdev) ...@@ -1432,7 +1432,8 @@ static int mxcnd_probe(struct platform_device *pdev)
err = mxcnd_probe_dt(host); err = mxcnd_probe_dt(host);
if (err > 0) { if (err > 0) {
struct mxc_nand_platform_data *pdata = pdev->dev.platform_data; struct mxc_nand_platform_data *pdata =
dev_get_platdata(&pdev->dev);
if (pdata) { if (pdata) {
host->pdata = *pdata; host->pdata = *pdata;
host->devtype_data = (struct mxc_nand_devtype_data *) host->devtype_data = (struct mxc_nand_devtype_data *)
...@@ -1446,8 +1447,6 @@ static int mxcnd_probe(struct platform_device *pdev) ...@@ -1446,8 +1447,6 @@ static int mxcnd_probe(struct platform_device *pdev)
if (host->devtype_data->needs_ip) { if (host->devtype_data->needs_ip) {
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
host->regs_ip = devm_ioremap_resource(&pdev->dev, res); host->regs_ip = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(host->regs_ip)) if (IS_ERR(host->regs_ip))
return PTR_ERR(host->regs_ip); return PTR_ERR(host->regs_ip);
...@@ -1457,9 +1456,6 @@ static int mxcnd_probe(struct platform_device *pdev) ...@@ -1457,9 +1456,6 @@ static int mxcnd_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
} }
if (!res)
return -ENODEV;
host->base = devm_ioremap_resource(&pdev->dev, res); host->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(host->base)) if (IS_ERR(host->base))
return PTR_ERR(host->base); return PTR_ERR(host->base);
...@@ -1578,8 +1574,6 @@ static int mxcnd_remove(struct platform_device *pdev) ...@@ -1578,8 +1574,6 @@ static int mxcnd_remove(struct platform_device *pdev)
{ {
struct mxc_nand_host *host = platform_get_drvdata(pdev); struct mxc_nand_host *host = platform_get_drvdata(pdev);
platform_set_drvdata(pdev, NULL);
nand_release(&host->mtd); nand_release(&host->mtd);
return 0; return 0;
......
此差异已折叠。
此差异已折叠。
...@@ -33,16 +33,16 @@ struct nand_flash_dev nand_flash_ids[] = { ...@@ -33,16 +33,16 @@ struct nand_flash_dev nand_flash_ids[] = {
*/ */
{"TC58NVG2S0F 4G 3.3V 8-bit", {"TC58NVG2S0F 4G 3.3V 8-bit",
{ .id = {0x98, 0xdc, 0x90, 0x26, 0x76, 0x15, 0x01, 0x08} }, { .id = {0x98, 0xdc, 0x90, 0x26, 0x76, 0x15, 0x01, 0x08} },
SZ_4K, SZ_512, SZ_256K, 0, 8, 224}, SZ_4K, SZ_512, SZ_256K, 0, 8, 224, NAND_ECC_INFO(4, SZ_512) },
{"TC58NVG3S0F 8G 3.3V 8-bit", {"TC58NVG3S0F 8G 3.3V 8-bit",
{ .id = {0x98, 0xd3, 0x90, 0x26, 0x76, 0x15, 0x02, 0x08} }, { .id = {0x98, 0xd3, 0x90, 0x26, 0x76, 0x15, 0x02, 0x08} },
SZ_4K, SZ_1K, SZ_256K, 0, 8, 232}, SZ_4K, SZ_1K, SZ_256K, 0, 8, 232, NAND_ECC_INFO(4, SZ_512) },
{"TC58NVG5D2 32G 3.3V 8-bit", {"TC58NVG5D2 32G 3.3V 8-bit",
{ .id = {0x98, 0xd7, 0x94, 0x32, 0x76, 0x56, 0x09, 0x00} }, { .id = {0x98, 0xd7, 0x94, 0x32, 0x76, 0x56, 0x09, 0x00} },
SZ_8K, SZ_4K, SZ_1M, 0, 8, 640}, SZ_8K, SZ_4K, SZ_1M, 0, 8, 640, NAND_ECC_INFO(40, SZ_1K) },
{"TC58NVG6D2 64G 3.3V 8-bit", {"TC58NVG6D2 64G 3.3V 8-bit",
{ .id = {0x98, 0xde, 0x94, 0x82, 0x76, 0x56, 0x04, 0x20} }, { .id = {0x98, 0xde, 0x94, 0x82, 0x76, 0x56, 0x04, 0x20} },
SZ_8K, SZ_8K, SZ_2M, 0, 8, 640}, SZ_8K, SZ_8K, SZ_2M, 0, 8, 640, NAND_ECC_INFO(40, SZ_1K) },
LEGACY_ID_NAND("NAND 4MiB 5V 8-bit", 0x6B, 4, SZ_8K, SP_OPTIONS), LEGACY_ID_NAND("NAND 4MiB 5V 8-bit", 0x6B, 4, SZ_8K, SP_OPTIONS),
LEGACY_ID_NAND("NAND 4MiB 3,3V 8-bit", 0xE3, 4, SZ_8K, SP_OPTIONS), LEGACY_ID_NAND("NAND 4MiB 3,3V 8-bit", 0xE3, 4, SZ_8K, SP_OPTIONS),
......
...@@ -205,7 +205,7 @@ MODULE_PARM_DESC(bch, "Enable BCH ecc and set how many bits should " ...@@ -205,7 +205,7 @@ MODULE_PARM_DESC(bch, "Enable BCH ecc and set how many bits should "
/* Calculate the page offset in flash RAM image by (row, column) address */ /* Calculate the page offset in flash RAM image by (row, column) address */
#define NS_RAW_OFFSET(ns) \ #define NS_RAW_OFFSET(ns) \
(((ns)->regs.row << (ns)->geom.pgshift) + ((ns)->regs.row * (ns)->geom.oobsz) + (ns)->regs.column) (((ns)->regs.row * (ns)->geom.pgszoob) + (ns)->regs.column)
/* Calculate the OOB offset in flash RAM image by (row, column) address */ /* Calculate the OOB offset in flash RAM image by (row, column) address */
#define NS_RAW_OFFSET_OOB(ns) (NS_RAW_OFFSET(ns) + ns->geom.pgsz) #define NS_RAW_OFFSET_OOB(ns) (NS_RAW_OFFSET(ns) + ns->geom.pgsz)
...@@ -336,7 +336,6 @@ struct nandsim { ...@@ -336,7 +336,6 @@ struct nandsim {
uint pgsec; /* number of pages per sector */ uint pgsec; /* number of pages per sector */
uint secshift; /* bits number in sector size */ uint secshift; /* bits number in sector size */
uint pgshift; /* bits number in page size */ uint pgshift; /* bits number in page size */
uint oobshift; /* bits number in OOB size */
uint pgaddrbytes; /* bytes per page address */ uint pgaddrbytes; /* bytes per page address */
uint secaddrbytes; /* bytes per sector address */ uint secaddrbytes; /* bytes per sector address */
uint idbytes; /* the number ID bytes that this chip outputs */ uint idbytes; /* the number ID bytes that this chip outputs */
...@@ -363,7 +362,7 @@ struct nandsim { ...@@ -363,7 +362,7 @@ struct nandsim {
/* Fields needed when using a cache file */ /* Fields needed when using a cache file */
struct file *cfile; /* Open file */ struct file *cfile; /* Open file */
unsigned char *pages_written; /* Which pages have been written */ unsigned long *pages_written; /* Which pages have been written */
void *file_buf; void *file_buf;
struct page *held_pages[NS_MAX_HELD_PAGES]; struct page *held_pages[NS_MAX_HELD_PAGES];
int held_cnt; int held_cnt;
...@@ -586,7 +585,8 @@ static int alloc_device(struct nandsim *ns) ...@@ -586,7 +585,8 @@ static int alloc_device(struct nandsim *ns)
err = -EINVAL; err = -EINVAL;
goto err_close; goto err_close;
} }
ns->pages_written = vzalloc(ns->geom.pgnum); ns->pages_written = vzalloc(BITS_TO_LONGS(ns->geom.pgnum) *
sizeof(unsigned long));
if (!ns->pages_written) { if (!ns->pages_written) {
NS_ERR("alloc_device: unable to allocate pages written array\n"); NS_ERR("alloc_device: unable to allocate pages written array\n");
err = -ENOMEM; err = -ENOMEM;
...@@ -653,9 +653,7 @@ static void free_device(struct nandsim *ns) ...@@ -653,9 +653,7 @@ static void free_device(struct nandsim *ns)
static char *get_partition_name(int i) static char *get_partition_name(int i)
{ {
char buf[64]; return kasprintf(GFP_KERNEL, "NAND simulator partition %d", i);
sprintf(buf, "NAND simulator partition %d", i);
return kstrdup(buf, GFP_KERNEL);
} }
/* /*
...@@ -690,7 +688,6 @@ static int init_nandsim(struct mtd_info *mtd) ...@@ -690,7 +688,6 @@ static int init_nandsim(struct mtd_info *mtd)
ns->geom.totszoob = ns->geom.totsz + (uint64_t)ns->geom.pgnum * ns->geom.oobsz; ns->geom.totszoob = ns->geom.totsz + (uint64_t)ns->geom.pgnum * ns->geom.oobsz;
ns->geom.secshift = ffs(ns->geom.secsz) - 1; ns->geom.secshift = ffs(ns->geom.secsz) - 1;
ns->geom.pgshift = chip->page_shift; ns->geom.pgshift = chip->page_shift;
ns->geom.oobshift = ffs(ns->geom.oobsz) - 1;
ns->geom.pgsec = ns->geom.secsz / ns->geom.pgsz; ns->geom.pgsec = ns->geom.secsz / ns->geom.pgsz;
ns->geom.secszoob = ns->geom.secsz + ns->geom.oobsz * ns->geom.pgsec; ns->geom.secszoob = ns->geom.secsz + ns->geom.oobsz * ns->geom.pgsec;
ns->options = 0; ns->options = 0;
...@@ -761,12 +758,6 @@ static int init_nandsim(struct mtd_info *mtd) ...@@ -761,12 +758,6 @@ static int init_nandsim(struct mtd_info *mtd)
ns->nbparts += 1; ns->nbparts += 1;
} }
/* Detect how many ID bytes the NAND chip outputs */
for (i = 0; nand_flash_ids[i].name != NULL; i++) {
if (second_id_byte != nand_flash_ids[i].dev_id)
continue;
}
if (ns->busw == 16) if (ns->busw == 16)
NS_WARN("16-bit flashes support wasn't tested\n"); NS_WARN("16-bit flashes support wasn't tested\n");
...@@ -780,7 +771,7 @@ static int init_nandsim(struct mtd_info *mtd) ...@@ -780,7 +771,7 @@ static int init_nandsim(struct mtd_info *mtd)
printk("bus width: %u\n", ns->busw); printk("bus width: %u\n", ns->busw);
printk("bits in sector size: %u\n", ns->geom.secshift); printk("bits in sector size: %u\n", ns->geom.secshift);
printk("bits in page size: %u\n", ns->geom.pgshift); printk("bits in page size: %u\n", ns->geom.pgshift);
printk("bits in OOB size: %u\n", ns->geom.oobshift); printk("bits in OOB size: %u\n", ffs(ns->geom.oobsz) - 1);
printk("flash size with OOB: %llu KiB\n", printk("flash size with OOB: %llu KiB\n",
(unsigned long long)ns->geom.totszoob >> 10); (unsigned long long)ns->geom.totszoob >> 10);
printk("page address bytes: %u\n", ns->geom.pgaddrbytes); printk("page address bytes: %u\n", ns->geom.pgaddrbytes);
...@@ -1442,7 +1433,7 @@ static inline u_char *NS_PAGE_BYTE_OFF(struct nandsim *ns) ...@@ -1442,7 +1433,7 @@ static inline u_char *NS_PAGE_BYTE_OFF(struct nandsim *ns)
return NS_GET_PAGE(ns)->byte + ns->regs.column + ns->regs.off; return NS_GET_PAGE(ns)->byte + ns->regs.column + ns->regs.off;
} }
int do_read_error(struct nandsim *ns, int num) static int do_read_error(struct nandsim *ns, int num)
{ {
unsigned int page_no = ns->regs.row; unsigned int page_no = ns->regs.row;
...@@ -1454,7 +1445,7 @@ int do_read_error(struct nandsim *ns, int num) ...@@ -1454,7 +1445,7 @@ int do_read_error(struct nandsim *ns, int num)
return 0; return 0;
} }
void do_bit_flips(struct nandsim *ns, int num) static void do_bit_flips(struct nandsim *ns, int num)
{ {
if (bitflips && prandom_u32() < (1 << 22)) { if (bitflips && prandom_u32() < (1 << 22)) {
int flips = 1; int flips = 1;
...@@ -1479,7 +1470,7 @@ static void read_page(struct nandsim *ns, int num) ...@@ -1479,7 +1470,7 @@ static void read_page(struct nandsim *ns, int num)
union ns_mem *mypage; union ns_mem *mypage;
if (ns->cfile) { if (ns->cfile) {
if (!ns->pages_written[ns->regs.row]) { if (!test_bit(ns->regs.row, ns->pages_written)) {
NS_DBG("read_page: page %d not written\n", ns->regs.row); NS_DBG("read_page: page %d not written\n", ns->regs.row);
memset(ns->buf.byte, 0xFF, num); memset(ns->buf.byte, 0xFF, num);
} else { } else {
...@@ -1490,7 +1481,7 @@ static void read_page(struct nandsim *ns, int num) ...@@ -1490,7 +1481,7 @@ static void read_page(struct nandsim *ns, int num)
ns->regs.row, ns->regs.column + ns->regs.off); ns->regs.row, ns->regs.column + ns->regs.off);
if (do_read_error(ns, num)) if (do_read_error(ns, num))
return; return;
pos = (loff_t)ns->regs.row * ns->geom.pgszoob + ns->regs.column + ns->regs.off; pos = (loff_t)NS_RAW_OFFSET(ns) + ns->regs.off;
tx = read_file(ns, ns->cfile, ns->buf.byte, num, pos); tx = read_file(ns, ns->cfile, ns->buf.byte, num, pos);
if (tx != num) { if (tx != num) {
NS_ERR("read_page: read error for page %d ret %ld\n", ns->regs.row, (long)tx); NS_ERR("read_page: read error for page %d ret %ld\n", ns->regs.row, (long)tx);
...@@ -1525,9 +1516,9 @@ static void erase_sector(struct nandsim *ns) ...@@ -1525,9 +1516,9 @@ static void erase_sector(struct nandsim *ns)
if (ns->cfile) { if (ns->cfile) {
for (i = 0; i < ns->geom.pgsec; i++) for (i = 0; i < ns->geom.pgsec; i++)
if (ns->pages_written[ns->regs.row + i]) { if (__test_and_clear_bit(ns->regs.row + i,
ns->pages_written)) {
NS_DBG("erase_sector: freeing page %d\n", ns->regs.row + i); NS_DBG("erase_sector: freeing page %d\n", ns->regs.row + i);
ns->pages_written[ns->regs.row + i] = 0;
} }
return; return;
} }
...@@ -1559,8 +1550,8 @@ static int prog_page(struct nandsim *ns, int num) ...@@ -1559,8 +1550,8 @@ static int prog_page(struct nandsim *ns, int num)
NS_DBG("prog_page: writing page %d\n", ns->regs.row); NS_DBG("prog_page: writing page %d\n", ns->regs.row);
pg_off = ns->file_buf + ns->regs.column + ns->regs.off; pg_off = ns->file_buf + ns->regs.column + ns->regs.off;
off = (loff_t)ns->regs.row * ns->geom.pgszoob + ns->regs.column + ns->regs.off; off = (loff_t)NS_RAW_OFFSET(ns) + ns->regs.off;
if (!ns->pages_written[ns->regs.row]) { if (!test_bit(ns->regs.row, ns->pages_written)) {
all = 1; all = 1;
memset(ns->file_buf, 0xff, ns->geom.pgszoob); memset(ns->file_buf, 0xff, ns->geom.pgszoob);
} else { } else {
...@@ -1580,7 +1571,7 @@ static int prog_page(struct nandsim *ns, int num) ...@@ -1580,7 +1571,7 @@ static int prog_page(struct nandsim *ns, int num)
NS_ERR("prog_page: write error for page %d ret %ld\n", ns->regs.row, (long)tx); NS_ERR("prog_page: write error for page %d ret %ld\n", ns->regs.row, (long)tx);
return -1; return -1;
} }
ns->pages_written[ns->regs.row] = 1; __set_bit(ns->regs.row, ns->pages_written);
} else { } else {
tx = write_file(ns, ns->cfile, pg_off, num, off); tx = write_file(ns, ns->cfile, pg_off, num, off);
if (tx != num) { if (tx != num) {
......
...@@ -324,8 +324,6 @@ static int nuc900_nand_remove(struct platform_device *pdev) ...@@ -324,8 +324,6 @@ static int nuc900_nand_remove(struct platform_device *pdev)
kfree(nuc900_nand); kfree(nuc900_nand);
platform_set_drvdata(pdev, NULL);
return 0; return 0;
} }
......
此差异已折叠。
...@@ -130,8 +130,9 @@ static int __init orion_nand_probe(struct platform_device *pdev) ...@@ -130,8 +130,9 @@ static int __init orion_nand_probe(struct platform_device *pdev)
if (!of_property_read_u32(pdev->dev.of_node, if (!of_property_read_u32(pdev->dev.of_node,
"chip-delay", &val)) "chip-delay", &val))
board->chip_delay = (u8)val; board->chip_delay = (u8)val;
} else } else {
board = pdev->dev.platform_data; board = dev_get_platdata(&pdev->dev);
}
mtd->priv = nc; mtd->priv = nc;
mtd->owner = THIS_MODULE; mtd->owner = THIS_MODULE;
...@@ -186,7 +187,6 @@ static int __init orion_nand_probe(struct platform_device *pdev) ...@@ -186,7 +187,6 @@ static int __init orion_nand_probe(struct platform_device *pdev)
clk_disable_unprepare(clk); clk_disable_unprepare(clk);
clk_put(clk); clk_put(clk);
} }
platform_set_drvdata(pdev, NULL);
iounmap(io_base); iounmap(io_base);
no_res: no_res:
kfree(nc); kfree(nc);
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册