1
0
Fork 0

- Lots of cleanups from Artem, including deletion of some obsolete drivers

- Support partitions larger than 4GiB in device tree
 - Support for new SPI chips
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.13 (GNU/Linux)
 
 iEYEABECAAYFAlGLxzEACgkQdwG7hYl686M+PgCdHAn3fDzGW7gUL1tj43NCqaC8
 PWoAoNAD5YpI3wYEBxped2MjSfgbQMvq
 =hM2T
 -----END PGP SIGNATURE-----

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

Pull MTD update from David Woodhouse:

 - Lots of cleanups from Artem, including deletion of some obsolete
   drivers

 - Support partitions larger than 4GiB in device tree

 - Support for new SPI chips

* tag 'for-linus-20130509' of git://git.infradead.org/linux-mtd: (83 commits)
  mtd: omap2: Use module_platform_driver()
  mtd: bf5xx_nand: Use module_platform_driver()
  mtd: denali_dt: Remove redundant use of of_match_ptr
  mtd: denali_dt: Change return value to fix smatch warning
  mtd: denali_dt: Use module_platform_driver()
  mtd: denali_dt: Fix incorrect error check
  mtd: nand: subpage write support for hardware based ECC schemes
  mtd: omap2: use msecs_to_jiffies()
  mtd: nand_ids: use size macros
  mtd: nand_ids: improve LEGACY_ID_NAND macro a bit
  mtd: add 4 Toshiba nand chips for the full-id case
  mtd: add the support to parse out the full-id nand type
  mtd: add new fields to nand_flash_dev{}
  mtd: sh_flctl: Use of_match_ptr() macro
  mtd: gpio: Use of_match_ptr() macro
  mtd: gpio: Use devm_kzalloc()
  mtd: davinci_nand: Use of_match_ptr()
  mtd: dataflash: Use of_match_ptr() macro
  mtd: remove h720x flash support
  mtd: onenand: remove OneNAND simulator
  ...
wifi-calibration
Linus Torvalds 2013-05-09 10:15:46 -07:00
commit a637b0d459
89 changed files with 627 additions and 8161 deletions

View File

@ -14,8 +14,7 @@ Description:
The /sys/class/mtd/mtd{0,1,2,3,...} directories correspond
to each /dev/mtdX character device. These may represent
physical/simulated flash devices, partitions on a flash
device, or concatenated flash devices. They exist regardless
of whether CONFIG_MTD_CHAR is actually enabled.
device, or concatenated flash devices.
What: /sys/class/mtd/mtdXro/
Date: April 2009
@ -23,8 +22,7 @@ KernelVersion: 2.6.29
Contact: linux-mtd@lists.infradead.org
Description:
These directories provide the corresponding read-only device
nodes for /sys/class/mtd/mtdX/ . They are only created
(for the benefit of udev) if CONFIG_MTD_CHAR is enabled.
nodes for /sys/class/mtd/mtdX/ .
What: /sys/class/mtd/mtdX/dev
Date: April 2009

View File

@ -5,8 +5,12 @@ 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
as RedBoot.
#address-cells & #size-cells must both be present in the mtd device and be
equal to 1.
#address-cells & #size-cells must both be present in the mtd device. There are
two valid values for both:
<1>: for partitions that require a single 32-bit cell to represent their
size/address (aka the value is below 4 GiB)
<2>: for partitions that require two 32-bit cells to represent their
size/address (aka the value is 4 GiB or greater).
Required properties:
- reg : The partition's offset and size within the mtd bank.
@ -36,3 +40,31 @@ flash@0 {
reg = <0x0100000 0x200000>;
};
};
flash@1 {
#address-cells = <1>;
#size-cells = <2>;
/* a 4 GiB partition */
partition@0 {
label = "filesystem";
reg = <0x00000000 0x1 0x00000000>;
};
};
flash@2 {
#address-cells = <2>;
#size-cells = <2>;
/* an 8 GiB partition */
partition@0 {
label = "filesystem #1";
reg = <0x0 0x00000000 0x2 0x00000000>;
};
/* a 4 GiB partition */
partition@200000000 {
label = "filesystem #2";
reg = <0x2 0x00000000 0x1 0x00000000>;
};
};

View File

@ -162,7 +162,6 @@ config MACH_XCEP
select MTD
select MTD_CFI
select MTD_CFI_INTELEXT
select MTD_CHAR
select MTD_PHYSMAP
select PXA25x
select SMC91X

View File

@ -264,7 +264,6 @@ config ETRAX_AXISFLASHMAP
select MTD_CFI
select MTD_CFI_AMDSTD
select MTD_JEDECPROBE if ETRAX_ARCH_V32
select MTD_CHAR
select MTD_BLOCK
select MTD_COMPLEX_MAPPINGS
help

View File

@ -404,7 +404,6 @@ config ETRAX_AXISFLASHMAP
select MTD_CFI
select MTD_CFI_AMDSTD
select MTD_JEDECPROBE
select MTD_CHAR
select MTD_BLOCK
select MTD_COMPLEX_MAPPINGS
help

View File

@ -21,7 +21,7 @@
#include <linux/serial_reg.h>
#include <linux/time.h>
static const char *part_probes[] = { "bcm47xxpart", NULL };
static const char * const part_probes[] = { "bcm47xxpart", NULL };
static struct physmap_flash_data bcma_pflash_data = {
.part_probe_types = part_probes,

View File

@ -157,19 +157,6 @@ config MTD_BCM47XX_PARTS
comment "User Modules And Translation Layers"
config MTD_CHAR
tristate "Direct char device access to MTD devices"
help
This provides a character device for each MTD device present in
the system, allowing the user to read and write directly to the
memory chips, and also use ioctl() to obtain information about
the device, or to erase parts of it.
config HAVE_MTD_OTP
bool
help
Enable access to OTP regions using MTD_CHAR.
config MTD_BLKDEVS
tristate "Common interface to block layer for MTD 'translation layers'"
depends on BLOCK

View File

@ -4,7 +4,7 @@
# Core functionality.
obj-$(CONFIG_MTD) += mtd.o
mtd-y := mtdcore.o mtdsuper.o mtdconcat.o mtdpart.o
mtd-y := mtdcore.o mtdsuper.o mtdconcat.o mtdpart.o mtdchar.o
obj-$(CONFIG_MTD_OF_PARTS) += ofpart.o
obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o
@ -15,7 +15,6 @@ obj-$(CONFIG_MTD_BCM63XX_PARTS) += bcm63xxpart.o
obj-$(CONFIG_MTD_BCM47XX_PARTS) += bcm47xxpart.o
# 'Users' - code which presents functionality to userspace.
obj-$(CONFIG_MTD_CHAR) += mtdchar.o
obj-$(CONFIG_MTD_BLKDEVS) += mtd_blkdevs.o
obj-$(CONFIG_MTD_BLOCK) += mtdblock.o
obj-$(CONFIG_MTD_BLOCK_RO) += mtdblock_ro.o

View File

@ -146,7 +146,6 @@ config MTD_CFI_I8
config MTD_OTP
bool "Protection Registers aka one-time programmable (OTP) bits"
depends on MTD_CFI_ADV_OPTIONS
select HAVE_MTD_OTP
default n
help
This enables support for reading, writing and locking so called

View File

@ -71,7 +71,6 @@ config MTD_DATAFLASH_WRITE_VERIFY
config MTD_DATAFLASH_OTP
bool "DataFlash OTP support (Security Register)"
depends on MTD_DATAFLASH
select HAVE_MTD_OTP
help
Newer DataFlash chips (revisions C and D) support 128 bytes of
one-time-programmable (OTP) data. The first half may be written
@ -205,69 +204,6 @@ config MTD_BLOCK2MTD
comment "Disk-On-Chip Device Drivers"
config MTD_DOC2000
tristate "M-Systems Disk-On-Chip 2000 and Millennium (DEPRECATED)"
depends on MTD_NAND
select MTD_DOCPROBE
select MTD_NAND_IDS
---help---
This provides an MTD device driver for the M-Systems DiskOnChip
2000 and Millennium devices. Originally designed for the DiskOnChip
2000, it also now includes support for the DiskOnChip Millennium.
If you have problems with this driver and the DiskOnChip Millennium,
you may wish to try the alternative Millennium driver below. To use
the alternative driver, you will need to undefine DOC_SINGLE_DRIVER
in the <file:drivers/mtd/devices/docprobe.c> source code.
If you use this device, you probably also want to enable the NFTL
'NAND Flash Translation Layer' option below, which is used to
emulate a block device by using a kind of file system on the flash
chips.
NOTE: This driver is deprecated and will probably be removed soon.
Please try the new DiskOnChip driver under "NAND Flash Device
Drivers".
config MTD_DOC2001
tristate "M-Systems Disk-On-Chip Millennium-only alternative driver (DEPRECATED)"
depends on MTD_NAND
select MTD_DOCPROBE
select MTD_NAND_IDS
---help---
This provides an alternative MTD device driver for the M-Systems
DiskOnChip Millennium devices. Use this if you have problems with
the combined DiskOnChip 2000 and Millennium driver above. To get
the DiskOnChip probe code to load and use this driver instead of
the other one, you will need to undefine DOC_SINGLE_DRIVER near
the beginning of <file:drivers/mtd/devices/docprobe.c>.
If you use this device, you probably also want to enable the NFTL
'NAND Flash Translation Layer' option below, which is used to
emulate a block device by using a kind of file system on the flash
chips.
NOTE: This driver is deprecated and will probably be removed soon.
Please try the new DiskOnChip driver under "NAND Flash Device
Drivers".
config MTD_DOC2001PLUS
tristate "M-Systems Disk-On-Chip Millennium Plus"
depends on MTD_NAND
select MTD_DOCPROBE
select MTD_NAND_IDS
---help---
This provides an MTD device driver for the M-Systems DiskOnChip
Millennium Plus devices.
If you use this device, you probably also want to enable the INFTL
'Inverse NAND Flash Translation Layer' option below, which is used
to emulate a block device by using a kind of file system on the
flash chips.
NOTE: This driver will soon be replaced by the new DiskOnChip driver
under "NAND Flash Device Drivers" (currently that driver does not
support all Millennium Plus devices).
config MTD_DOCG3
tristate "M-Systems Disk-On-Chip G3"
select BCH

View File

@ -2,12 +2,7 @@
# linux/drivers/mtd/devices/Makefile
#
obj-$(CONFIG_MTD_DOC2000) += doc2000.o
obj-$(CONFIG_MTD_DOC2001) += doc2001.o
obj-$(CONFIG_MTD_DOC2001PLUS) += doc2001plus.o
obj-$(CONFIG_MTD_DOCG3) += docg3.o
obj-$(CONFIG_MTD_DOCPROBE) += docprobe.o
obj-$(CONFIG_MTD_DOCECC) += docecc.o
obj-$(CONFIG_MTD_SLRAM) += slram.o
obj-$(CONFIG_MTD_PHRAM) += phram.o
obj-$(CONFIG_MTD_PMC551) += pmc551.o

View File

@ -10,7 +10,7 @@
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Serial flash driver for BCMA bus");
static const char *probes[] = { "bcm47xxpart", NULL };
static const char * const probes[] = { "bcm47xxpart", NULL };
static int bcm47xxsflash_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf)
@ -61,6 +61,17 @@ static int bcm47xxsflash_bcma_probe(struct platform_device *pdev)
}
sflash->priv = b47s;
b47s->bcma_cc = container_of(sflash, struct bcma_drv_cc, sflash);
switch (b47s->bcma_cc->capabilities & BCMA_CC_CAP_FLASHT) {
case BCMA_CC_FLASHT_STSER:
b47s->type = BCM47XXSFLASH_TYPE_ST;
break;
case BCMA_CC_FLASHT_ATSER:
b47s->type = BCM47XXSFLASH_TYPE_ATMEL;
break;
}
b47s->window = sflash->window;
b47s->blocksize = sflash->blocksize;
b47s->numblocks = sflash->numblocks;

View File

@ -3,7 +3,66 @@
#include <linux/mtd/mtd.h>
/* Used for ST flashes only. */
#define OPCODE_ST_WREN 0x0006 /* Write Enable */
#define OPCODE_ST_WRDIS 0x0004 /* Write Disable */
#define OPCODE_ST_RDSR 0x0105 /* Read Status Register */
#define OPCODE_ST_WRSR 0x0101 /* Write Status Register */
#define OPCODE_ST_READ 0x0303 /* Read Data Bytes */
#define OPCODE_ST_PP 0x0302 /* Page Program */
#define OPCODE_ST_SE 0x02d8 /* Sector Erase */
#define OPCODE_ST_BE 0x00c7 /* Bulk Erase */
#define OPCODE_ST_DP 0x00b9 /* Deep Power-down */
#define OPCODE_ST_RES 0x03ab /* Read Electronic Signature */
#define OPCODE_ST_CSA 0x1000 /* Keep chip select asserted */
#define OPCODE_ST_SSE 0x0220 /* Sub-sector Erase */
/* Used for Atmel flashes only. */
#define OPCODE_AT_READ 0x07e8
#define OPCODE_AT_PAGE_READ 0x07d2
#define OPCODE_AT_STATUS 0x01d7
#define OPCODE_AT_BUF1_WRITE 0x0384
#define OPCODE_AT_BUF2_WRITE 0x0387
#define OPCODE_AT_BUF1_ERASE_PROGRAM 0x0283
#define OPCODE_AT_BUF2_ERASE_PROGRAM 0x0286
#define OPCODE_AT_BUF1_PROGRAM 0x0288
#define OPCODE_AT_BUF2_PROGRAM 0x0289
#define OPCODE_AT_PAGE_ERASE 0x0281
#define OPCODE_AT_BLOCK_ERASE 0x0250
#define OPCODE_AT_BUF1_WRITE_ERASE_PROGRAM 0x0382
#define OPCODE_AT_BUF2_WRITE_ERASE_PROGRAM 0x0385
#define OPCODE_AT_BUF1_LOAD 0x0253
#define OPCODE_AT_BUF2_LOAD 0x0255
#define OPCODE_AT_BUF1_COMPARE 0x0260
#define OPCODE_AT_BUF2_COMPARE 0x0261
#define OPCODE_AT_BUF1_REPROGRAM 0x0258
#define OPCODE_AT_BUF2_REPROGRAM 0x0259
/* Status register bits for ST flashes */
#define SR_ST_WIP 0x01 /* Write In Progress */
#define SR_ST_WEL 0x02 /* Write Enable Latch */
#define SR_ST_BP_MASK 0x1c /* Block Protect */
#define SR_ST_BP_SHIFT 2
#define SR_ST_SRWD 0x80 /* Status Register Write Disable */
/* Status register bits for Atmel flashes */
#define SR_AT_READY 0x80
#define SR_AT_MISMATCH 0x40
#define SR_AT_ID_MASK 0x38
#define SR_AT_ID_SHIFT 3
struct bcma_drv_cc;
enum bcm47xxsflash_type {
BCM47XXSFLASH_TYPE_ATMEL,
BCM47XXSFLASH_TYPE_ST,
};
struct bcm47xxsflash {
struct bcma_drv_cc *bcma_cc;
enum bcm47xxsflash_type type;
u32 window;
u32 blocksize;
u16 numblocks;

File diff suppressed because it is too large Load Diff

View File

@ -1,824 +0,0 @@
/*
* Linux driver for Disk-On-Chip Millennium
* (c) 1999 Machine Vision Holdings, Inc.
* (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org>
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <asm/errno.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/bitops.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/doc2000.h>
/* #define ECC_DEBUG */
/* I have no idea why some DoC chips can not use memcop_form|to_io().
* This may be due to the different revisions of the ASIC controller built-in or
* simplily a QA/Bug issue. Who knows ?? If you have trouble, please uncomment
* this:*/
#undef USE_MEMCPY
static int doc_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf);
static int doc_write(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf);
static int doc_read_oob(struct mtd_info *mtd, loff_t ofs,
struct mtd_oob_ops *ops);
static int doc_write_oob(struct mtd_info *mtd, loff_t ofs,
struct mtd_oob_ops *ops);
static int doc_erase (struct mtd_info *mtd, struct erase_info *instr);
static struct mtd_info *docmillist = NULL;
/* Perform the required delay cycles by reading from the NOP register */
static void DoC_Delay(void __iomem * docptr, unsigned short cycles)
{
volatile char dummy;
int i;
for (i = 0; i < cycles; i++)
dummy = ReadDOC(docptr, NOP);
}
/* DOC_WaitReady: Wait for RDY line to be asserted by the flash chip */
static int _DoC_WaitReady(void __iomem * docptr)
{
unsigned short c = 0xffff;
pr_debug("_DoC_WaitReady called for out-of-line wait\n");
/* Out-of-line routine to wait for chip response */
while (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B) && --c)
;
if (c == 0)
pr_debug("_DoC_WaitReady timed out.\n");
return (c == 0);
}
static inline int DoC_WaitReady(void __iomem * docptr)
{
/* This is inline, to optimise the common case, where it's ready instantly */
int ret = 0;
/* 4 read form NOP register should be issued in prior to the read from CDSNControl
see Software Requirement 11.4 item 2. */
DoC_Delay(docptr, 4);
if (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B))
/* Call the out-of-line routine to wait */
ret = _DoC_WaitReady(docptr);
/* issue 2 read from NOP register after reading from CDSNControl register
see Software Requirement 11.4 item 2. */
DoC_Delay(docptr, 2);
return ret;
}
/* DoC_Command: Send a flash command to the flash chip through the CDSN IO register
with the internal pipeline. Each of 4 delay cycles (read from the NOP register) is
required after writing to CDSN Control register, see Software Requirement 11.4 item 3. */
static void DoC_Command(void __iomem * docptr, unsigned char command,
unsigned char xtraflags)
{
/* Assert the CLE (Command Latch Enable) line to the flash chip */
WriteDOC(xtraflags | CDSN_CTRL_CLE | CDSN_CTRL_CE, docptr, CDSNControl);
DoC_Delay(docptr, 4);
/* Send the command */
WriteDOC(command, docptr, Mil_CDSN_IO);
WriteDOC(0x00, docptr, WritePipeTerm);
/* Lower the CLE line */
WriteDOC(xtraflags | CDSN_CTRL_CE, docptr, CDSNControl);
DoC_Delay(docptr, 4);
}
/* DoC_Address: Set the current address for the flash chip through the CDSN IO register
with the internal pipeline. Each of 4 delay cycles (read from the NOP register) is
required after writing to CDSN Control register, see Software Requirement 11.4 item 3. */
static inline void DoC_Address(void __iomem * docptr, int numbytes, unsigned long ofs,
unsigned char xtraflags1, unsigned char xtraflags2)
{
/* Assert the ALE (Address Latch Enable) line to the flash chip */
WriteDOC(xtraflags1 | CDSN_CTRL_ALE | CDSN_CTRL_CE, docptr, CDSNControl);
DoC_Delay(docptr, 4);
/* Send the address */
switch (numbytes)
{
case 1:
/* Send single byte, bits 0-7. */
WriteDOC(ofs & 0xff, docptr, Mil_CDSN_IO);
WriteDOC(0x00, docptr, WritePipeTerm);
break;
case 2:
/* Send bits 9-16 followed by 17-23 */
WriteDOC((ofs >> 9) & 0xff, docptr, Mil_CDSN_IO);
WriteDOC((ofs >> 17) & 0xff, docptr, Mil_CDSN_IO);
WriteDOC(0x00, docptr, WritePipeTerm);
break;
case 3:
/* Send 0-7, 9-16, then 17-23 */
WriteDOC(ofs & 0xff, docptr, Mil_CDSN_IO);
WriteDOC((ofs >> 9) & 0xff, docptr, Mil_CDSN_IO);
WriteDOC((ofs >> 17) & 0xff, docptr, Mil_CDSN_IO);
WriteDOC(0x00, docptr, WritePipeTerm);
break;
default:
return;
}
/* Lower the ALE line */
WriteDOC(xtraflags1 | xtraflags2 | CDSN_CTRL_CE, docptr, CDSNControl);
DoC_Delay(docptr, 4);
}
/* DoC_SelectChip: Select a given flash chip within the current floor */
static int DoC_SelectChip(void __iomem * docptr, int chip)
{
/* Select the individual flash chip requested */
WriteDOC(chip, docptr, CDSNDeviceSelect);
DoC_Delay(docptr, 4);
/* Wait for it to be ready */
return DoC_WaitReady(docptr);
}
/* DoC_SelectFloor: Select a given floor (bank of flash chips) */
static int DoC_SelectFloor(void __iomem * docptr, int floor)
{
/* Select the floor (bank) of chips required */
WriteDOC(floor, docptr, FloorSelect);
/* Wait for the chip to be ready */
return DoC_WaitReady(docptr);
}
/* DoC_IdentChip: Identify a given NAND chip given {floor,chip} */
static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip)
{
int mfr, id, i, j;
volatile char dummy;
/* Page in the required floor/chip
FIXME: is this supported by Millennium ?? */
DoC_SelectFloor(doc->virtadr, floor);
DoC_SelectChip(doc->virtadr, chip);
/* Reset the chip, see Software Requirement 11.4 item 1. */
DoC_Command(doc->virtadr, NAND_CMD_RESET, CDSN_CTRL_WP);
DoC_WaitReady(doc->virtadr);
/* Read the NAND chip ID: 1. Send ReadID command */
DoC_Command(doc->virtadr, NAND_CMD_READID, CDSN_CTRL_WP);
/* Read the NAND chip ID: 2. Send address byte zero */
DoC_Address(doc->virtadr, 1, 0x00, CDSN_CTRL_WP, 0x00);
/* Read the manufacturer and device id codes of the flash device through
CDSN IO register see Software Requirement 11.4 item 5.*/
dummy = ReadDOC(doc->virtadr, ReadPipeInit);
DoC_Delay(doc->virtadr, 2);
mfr = ReadDOC(doc->virtadr, Mil_CDSN_IO);
DoC_Delay(doc->virtadr, 2);
id = ReadDOC(doc->virtadr, Mil_CDSN_IO);
dummy = ReadDOC(doc->virtadr, LastDataRead);
/* No response - return failure */
if (mfr == 0xff || mfr == 0)
return 0;
/* FIXME: to deal with multi-flash on multi-Millennium case more carefully */
for (i = 0; nand_flash_ids[i].name != NULL; i++) {
if ( id == nand_flash_ids[i].id) {
/* Try to identify manufacturer */
for (j = 0; nand_manuf_ids[j].id != 0x0; j++) {
if (nand_manuf_ids[j].id == mfr)
break;
}
printk(KERN_INFO "Flash chip found: Manufacturer ID: %2.2X, "
"Chip ID: %2.2X (%s:%s)\n",
mfr, id, nand_manuf_ids[j].name, nand_flash_ids[i].name);
doc->mfr = mfr;
doc->id = id;
doc->chipshift = ffs((nand_flash_ids[i].chipsize << 20)) - 1;
break;
}
}
if (nand_flash_ids[i].name == NULL)
return 0;
else
return 1;
}
/* DoC_ScanChips: Find all NAND chips present in a DiskOnChip, and identify them */
static void DoC_ScanChips(struct DiskOnChip *this)
{
int floor, chip;
int numchips[MAX_FLOORS_MIL];
int ret;
this->numchips = 0;
this->mfr = 0;
this->id = 0;
/* For each floor, find the number of valid chips it contains */
for (floor = 0,ret = 1; floor < MAX_FLOORS_MIL; floor++) {
numchips[floor] = 0;
for (chip = 0; chip < MAX_CHIPS_MIL && ret != 0; chip++) {
ret = DoC_IdentChip(this, floor, chip);
if (ret) {
numchips[floor]++;
this->numchips++;
}
}
}
/* If there are none at all that we recognise, bail */
if (!this->numchips) {
printk("No flash chips recognised.\n");
return;
}
/* Allocate an array to hold the information for each chip */
this->chips = kmalloc(sizeof(struct Nand) * this->numchips, GFP_KERNEL);
if (!this->chips){
printk("No memory for allocating chip info structures\n");
return;
}
/* Fill out the chip array with {floor, chipno} for each
* detected chip in the device. */
for (floor = 0, ret = 0; floor < MAX_FLOORS_MIL; floor++) {
for (chip = 0 ; chip < numchips[floor] ; chip++) {
this->chips[ret].floor = floor;
this->chips[ret].chip = chip;
this->chips[ret].curadr = 0;
this->chips[ret].curmode = 0x50;
ret++;
}
}
/* Calculate and print the total size of the device */
this->totlen = this->numchips * (1 << this->chipshift);
printk(KERN_INFO "%d flash chips found. Total DiskOnChip size: %ld MiB\n",
this->numchips ,this->totlen >> 20);
}
static int DoCMil_is_alias(struct DiskOnChip *doc1, struct DiskOnChip *doc2)
{
int tmp1, tmp2, retval;
if (doc1->physadr == doc2->physadr)
return 1;
/* Use the alias resolution register which was set aside for this
* purpose. If it's value is the same on both chips, they might
* be the same chip, and we write to one and check for a change in
* the other. It's unclear if this register is usuable in the
* DoC 2000 (it's in the Millenium docs), but it seems to work. */
tmp1 = ReadDOC(doc1->virtadr, AliasResolution);
tmp2 = ReadDOC(doc2->virtadr, AliasResolution);
if (tmp1 != tmp2)
return 0;
WriteDOC((tmp1+1) % 0xff, doc1->virtadr, AliasResolution);
tmp2 = ReadDOC(doc2->virtadr, AliasResolution);
if (tmp2 == (tmp1+1) % 0xff)
retval = 1;
else
retval = 0;
/* Restore register contents. May not be necessary, but do it just to
* be safe. */
WriteDOC(tmp1, doc1->virtadr, AliasResolution);
return retval;
}
/* This routine is found from the docprobe code by symbol_get(),
* which will bump the use count of this module. */
void DoCMil_init(struct mtd_info *mtd)
{
struct DiskOnChip *this = mtd->priv;
struct DiskOnChip *old = NULL;
/* We must avoid being called twice for the same device. */
if (docmillist)
old = docmillist->priv;
while (old) {
if (DoCMil_is_alias(this, old)) {
printk(KERN_NOTICE "Ignoring DiskOnChip Millennium at "
"0x%lX - already configured\n", this->physadr);
iounmap(this->virtadr);
kfree(mtd);
return;
}
if (old->nextdoc)
old = old->nextdoc->priv;
else
old = NULL;
}
mtd->name = "DiskOnChip Millennium";
printk(KERN_NOTICE "DiskOnChip Millennium found at address 0x%lX\n",
this->physadr);
mtd->type = MTD_NANDFLASH;
mtd->flags = MTD_CAP_NANDFLASH;
/* FIXME: erase size is not always 8KiB */
mtd->erasesize = 0x2000;
mtd->writebufsize = mtd->writesize = 512;
mtd->oobsize = 16;
mtd->ecc_strength = 2;
mtd->owner = THIS_MODULE;
mtd->_erase = doc_erase;
mtd->_read = doc_read;
mtd->_write = doc_write;
mtd->_read_oob = doc_read_oob;
mtd->_write_oob = doc_write_oob;
this->curfloor = -1;
this->curchip = -1;
/* Ident all the chips present. */
DoC_ScanChips(this);
if (!this->totlen) {
kfree(mtd);
iounmap(this->virtadr);
} else {
this->nextdoc = docmillist;
docmillist = mtd;
mtd->size = this->totlen;
mtd_device_register(mtd, NULL, 0);
return;
}
}
EXPORT_SYMBOL_GPL(DoCMil_init);
static int doc_read (struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf)
{
int i, ret;
volatile char dummy;
unsigned char syndrome[6], eccbuf[6];
struct DiskOnChip *this = mtd->priv;
void __iomem *docptr = this->virtadr;
struct Nand *mychip = &this->chips[from >> (this->chipshift)];
/* Don't allow a single read to cross a 512-byte block boundary */
if (from + len > ((from | 0x1ff) + 1))
len = ((from | 0x1ff) + 1) - from;
/* Find the chip which is to be used and select it */
if (this->curfloor != mychip->floor) {
DoC_SelectFloor(docptr, mychip->floor);
DoC_SelectChip(docptr, mychip->chip);
} else if (this->curchip != mychip->chip) {
DoC_SelectChip(docptr, mychip->chip);
}
this->curfloor = mychip->floor;
this->curchip = mychip->chip;
/* issue the Read0 or Read1 command depend on which half of the page
we are accessing. Polling the Flash Ready bit after issue 3 bytes
address in Sequence Read Mode, see Software Requirement 11.4 item 1.*/
DoC_Command(docptr, (from >> 8) & 1, CDSN_CTRL_WP);
DoC_Address(docptr, 3, from, CDSN_CTRL_WP, 0x00);
DoC_WaitReady(docptr);
/* init the ECC engine, see Reed-Solomon EDC/ECC 11.1 .*/
WriteDOC (DOC_ECC_RESET, docptr, ECCConf);
WriteDOC (DOC_ECC_EN, docptr, ECCConf);
/* Read the data via the internal pipeline through CDSN IO register,
see Pipelined Read Operations 11.3 */
dummy = ReadDOC(docptr, ReadPipeInit);
#ifndef USE_MEMCPY
for (i = 0; i < len-1; i++) {
/* N.B. you have to increase the source address in this way or the
ECC logic will not work properly */
buf[i] = ReadDOC(docptr, Mil_CDSN_IO + (i & 0xff));
}
#else
memcpy_fromio(buf, docptr + DoC_Mil_CDSN_IO, len - 1);
#endif
buf[len - 1] = ReadDOC(docptr, LastDataRead);
/* Let the caller know we completed it */
*retlen = len;
ret = 0;
/* Read the ECC data from Spare Data Area,
see Reed-Solomon EDC/ECC 11.1 */
dummy = ReadDOC(docptr, ReadPipeInit);
#ifndef USE_MEMCPY
for (i = 0; i < 5; i++) {
/* N.B. you have to increase the source address in this way or the
ECC logic will not work properly */
eccbuf[i] = ReadDOC(docptr, Mil_CDSN_IO + i);
}
#else
memcpy_fromio(eccbuf, docptr + DoC_Mil_CDSN_IO, 5);
#endif
eccbuf[5] = ReadDOC(docptr, LastDataRead);
/* Flush the pipeline */
dummy = ReadDOC(docptr, ECCConf);
dummy = ReadDOC(docptr, ECCConf);
/* Check the ECC Status */
if (ReadDOC(docptr, ECCConf) & 0x80) {
int nb_errors;
/* There was an ECC error */
#ifdef ECC_DEBUG
printk("DiskOnChip ECC Error: Read at %lx\n", (long)from);
#endif
/* Read the ECC syndrome through the DiskOnChip ECC logic.
These syndrome will be all ZERO when there is no error */
for (i = 0; i < 6; i++) {
syndrome[i] = ReadDOC(docptr, ECCSyndrome0 + i);
}
nb_errors = doc_decode_ecc(buf, syndrome);
#ifdef ECC_DEBUG
printk("ECC Errors corrected: %x\n", nb_errors);
#endif
if (nb_errors < 0) {
/* We return error, but have actually done the read. Not that
this can be told to user-space, via sys_read(), but at least
MTD-aware stuff can know about it by checking *retlen */
ret = -EIO;
}
}
#ifdef PSYCHO_DEBUG
printk("ECC DATA at %lx: %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
(long)from, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3],
eccbuf[4], eccbuf[5]);
#endif
/* disable the ECC engine */
WriteDOC(DOC_ECC_DIS, docptr , ECCConf);
return ret;
}
static int doc_write (struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf)
{
int i,ret = 0;
char eccbuf[6];
volatile char dummy;
struct DiskOnChip *this = mtd->priv;
void __iomem *docptr = this->virtadr;
struct Nand *mychip = &this->chips[to >> (this->chipshift)];
#if 0
/* Don't allow a single write to cross a 512-byte block boundary */
if (to + len > ( (to | 0x1ff) + 1))
len = ((to | 0x1ff) + 1) - to;
#else
/* Don't allow writes which aren't exactly one block */
if (to & 0x1ff || len != 0x200)
return -EINVAL;
#endif
/* Find the chip which is to be used and select it */
if (this->curfloor != mychip->floor) {
DoC_SelectFloor(docptr, mychip->floor);
DoC_SelectChip(docptr, mychip->chip);
} else if (this->curchip != mychip->chip) {
DoC_SelectChip(docptr, mychip->chip);
}
this->curfloor = mychip->floor;
this->curchip = mychip->chip;
/* Reset the chip, see Software Requirement 11.4 item 1. */
DoC_Command(docptr, NAND_CMD_RESET, 0x00);
DoC_WaitReady(docptr);
/* Set device to main plane of flash */
DoC_Command(docptr, NAND_CMD_READ0, 0x00);
/* issue the Serial Data In command to initial the Page Program process */
DoC_Command(docptr, NAND_CMD_SEQIN, 0x00);
DoC_Address(docptr, 3, to, 0x00, 0x00);
DoC_WaitReady(docptr);
/* init the ECC engine, see Reed-Solomon EDC/ECC 11.1 .*/
WriteDOC (DOC_ECC_RESET, docptr, ECCConf);
WriteDOC (DOC_ECC_EN | DOC_ECC_RW, docptr, ECCConf);
/* Write the data via the internal pipeline through CDSN IO register,
see Pipelined Write Operations 11.2 */
#ifndef USE_MEMCPY
for (i = 0; i < len; i++) {
/* N.B. you have to increase the source address in this way or the
ECC logic will not work properly */
WriteDOC(buf[i], docptr, Mil_CDSN_IO + i);
}
#else
memcpy_toio(docptr + DoC_Mil_CDSN_IO, buf, len);
#endif
WriteDOC(0x00, docptr, WritePipeTerm);
/* Write ECC data to flash, the ECC info is generated by the DiskOnChip ECC logic
see Reed-Solomon EDC/ECC 11.1 */
WriteDOC(0, docptr, NOP);
WriteDOC(0, docptr, NOP);
WriteDOC(0, docptr, NOP);
/* Read the ECC data through the DiskOnChip ECC logic */
for (i = 0; i < 6; i++) {
eccbuf[i] = ReadDOC(docptr, ECCSyndrome0 + i);
}
/* ignore the ECC engine */
WriteDOC(DOC_ECC_DIS, docptr , ECCConf);
#ifndef USE_MEMCPY
/* Write the ECC data to flash */
for (i = 0; i < 6; i++) {
/* N.B. you have to increase the source address in this way or the
ECC logic will not work properly */
WriteDOC(eccbuf[i], docptr, Mil_CDSN_IO + i);
}
#else
memcpy_toio(docptr + DoC_Mil_CDSN_IO, eccbuf, 6);
#endif
/* write the block status BLOCK_USED (0x5555) at the end of ECC data
FIXME: this is only a hack for programming the IPL area for LinuxBIOS
and should be replace with proper codes in user space utilities */
WriteDOC(0x55, docptr, Mil_CDSN_IO);
WriteDOC(0x55, docptr, Mil_CDSN_IO + 1);
WriteDOC(0x00, docptr, WritePipeTerm);
#ifdef PSYCHO_DEBUG
printk("OOB data at %lx is %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
(long) to, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3],
eccbuf[4], eccbuf[5]);
#endif
/* Commit the Page Program command and wait for ready
see Software Requirement 11.4 item 1.*/
DoC_Command(docptr, NAND_CMD_PAGEPROG, 0x00);
DoC_WaitReady(docptr);
/* Read the status of the flash device through CDSN IO register
see Software Requirement 11.4 item 5.*/
DoC_Command(docptr, NAND_CMD_STATUS, CDSN_CTRL_WP);
dummy = ReadDOC(docptr, ReadPipeInit);
DoC_Delay(docptr, 2);
if (ReadDOC(docptr, Mil_CDSN_IO) & 1) {
printk("Error programming flash\n");
/* Error in programming
FIXME: implement Bad Block Replacement (in nftl.c ??) */
ret = -EIO;
}
dummy = ReadDOC(docptr, LastDataRead);
/* Let the caller know we completed it */
*retlen = len;
return ret;
}
static int doc_read_oob(struct mtd_info *mtd, loff_t ofs,
struct mtd_oob_ops *ops)
{
#ifndef USE_MEMCPY
int i;
#endif
volatile char dummy;
struct DiskOnChip *this = mtd->priv;
void __iomem *docptr = this->virtadr;
struct Nand *mychip = &this->chips[ofs >> this->chipshift];
uint8_t *buf = ops->oobbuf;
size_t len = ops->len;
BUG_ON(ops->mode != MTD_OPS_PLACE_OOB);
ofs += ops->ooboffs;
/* Find the chip which is to be used and select it */
if (this->curfloor != mychip->floor) {
DoC_SelectFloor(docptr, mychip->floor);
DoC_SelectChip(docptr, mychip->chip);
} else if (this->curchip != mychip->chip) {
DoC_SelectChip(docptr, mychip->chip);
}
this->curfloor = mychip->floor;
this->curchip = mychip->chip;
/* disable the ECC engine */
WriteDOC (DOC_ECC_RESET, docptr, ECCConf);
WriteDOC (DOC_ECC_DIS, docptr, ECCConf);
/* issue the Read2 command to set the pointer to the Spare Data Area.
Polling the Flash Ready bit after issue 3 bytes address in
Sequence Read Mode, see Software Requirement 11.4 item 1.*/
DoC_Command(docptr, NAND_CMD_READOOB, CDSN_CTRL_WP);
DoC_Address(docptr, 3, ofs, CDSN_CTRL_WP, 0x00);
DoC_WaitReady(docptr);
/* Read the data out via the internal pipeline through CDSN IO register,
see Pipelined Read Operations 11.3 */
dummy = ReadDOC(docptr, ReadPipeInit);
#ifndef USE_MEMCPY
for (i = 0; i < len-1; i++) {
/* N.B. you have to increase the source address in this way or the
ECC logic will not work properly */
buf[i] = ReadDOC(docptr, Mil_CDSN_IO + i);
}
#else
memcpy_fromio(buf, docptr + DoC_Mil_CDSN_IO, len - 1);
#endif
buf[len - 1] = ReadDOC(docptr, LastDataRead);
ops->retlen = len;
return 0;
}
static int doc_write_oob(struct mtd_info *mtd, loff_t ofs,
struct mtd_oob_ops *ops)
{
#ifndef USE_MEMCPY
int i;
#endif
volatile char dummy;
int ret = 0;
struct DiskOnChip *this = mtd->priv;
void __iomem *docptr = this->virtadr;
struct Nand *mychip = &this->chips[ofs >> this->chipshift];
uint8_t *buf = ops->oobbuf;
size_t len = ops->len;
BUG_ON(ops->mode != MTD_OPS_PLACE_OOB);
ofs += ops->ooboffs;
/* Find the chip which is to be used and select it */
if (this->curfloor != mychip->floor) {
DoC_SelectFloor(docptr, mychip->floor);
DoC_SelectChip(docptr, mychip->chip);
} else if (this->curchip != mychip->chip) {
DoC_SelectChip(docptr, mychip->chip);
}
this->curfloor = mychip->floor;
this->curchip = mychip->chip;
/* disable the ECC engine */
WriteDOC (DOC_ECC_RESET, docptr, ECCConf);
WriteDOC (DOC_ECC_DIS, docptr, ECCConf);
/* Reset the chip, see Software Requirement 11.4 item 1. */
DoC_Command(docptr, NAND_CMD_RESET, CDSN_CTRL_WP);
DoC_WaitReady(docptr);
/* issue the Read2 command to set the pointer to the Spare Data Area. */
DoC_Command(docptr, NAND_CMD_READOOB, CDSN_CTRL_WP);
/* issue the Serial Data In command to initial the Page Program process */
DoC_Command(docptr, NAND_CMD_SEQIN, 0x00);
DoC_Address(docptr, 3, ofs, 0x00, 0x00);
/* Write the data via the internal pipeline through CDSN IO register,
see Pipelined Write Operations 11.2 */
#ifndef USE_MEMCPY
for (i = 0; i < len; i++) {
/* N.B. you have to increase the source address in this way or the
ECC logic will not work properly */
WriteDOC(buf[i], docptr, Mil_CDSN_IO + i);
}
#else
memcpy_toio(docptr + DoC_Mil_CDSN_IO, buf, len);
#endif
WriteDOC(0x00, docptr, WritePipeTerm);
/* Commit the Page Program command and wait for ready
see Software Requirement 11.4 item 1.*/
DoC_Command(docptr, NAND_CMD_PAGEPROG, 0x00);
DoC_WaitReady(docptr);
/* Read the status of the flash device through CDSN IO register
see Software Requirement 11.4 item 5.*/
DoC_Command(docptr, NAND_CMD_STATUS, 0x00);
dummy = ReadDOC(docptr, ReadPipeInit);
DoC_Delay(docptr, 2);
if (ReadDOC(docptr, Mil_CDSN_IO) & 1) {
printk("Error programming oob data\n");
/* FIXME: implement Bad Block Replacement (in nftl.c ??) */
ops->retlen = 0;
ret = -EIO;
}
dummy = ReadDOC(docptr, LastDataRead);
ops->retlen = len;
return ret;
}
int doc_erase (struct mtd_info *mtd, struct erase_info *instr)
{
volatile char dummy;
struct DiskOnChip *this = mtd->priv;
__u32 ofs = instr->addr;
__u32 len = instr->len;
void __iomem *docptr = this->virtadr;
struct Nand *mychip = &this->chips[ofs >> this->chipshift];
if (len != mtd->erasesize)
printk(KERN_WARNING "Erase not right size (%x != %x)n",
len, mtd->erasesize);
/* Find the chip which is to be used and select it */
if (this->curfloor != mychip->floor) {
DoC_SelectFloor(docptr, mychip->floor);
DoC_SelectChip(docptr, mychip->chip);
} else if (this->curchip != mychip->chip) {
DoC_SelectChip(docptr, mychip->chip);
}
this->curfloor = mychip->floor;
this->curchip = mychip->chip;
instr->state = MTD_ERASE_PENDING;
/* issue the Erase Setup command */
DoC_Command(docptr, NAND_CMD_ERASE1, 0x00);
DoC_Address(docptr, 2, ofs, 0x00, 0x00);
/* Commit the Erase Start command and wait for ready
see Software Requirement 11.4 item 1.*/
DoC_Command(docptr, NAND_CMD_ERASE2, 0x00);
DoC_WaitReady(docptr);
instr->state = MTD_ERASING;
/* Read the status of the flash device through CDSN IO register
see Software Requirement 11.4 item 5.
FIXME: it seems that we are not wait long enough, some blocks are not
erased fully */
DoC_Command(docptr, NAND_CMD_STATUS, CDSN_CTRL_WP);
dummy = ReadDOC(docptr, ReadPipeInit);
DoC_Delay(docptr, 2);
if (ReadDOC(docptr, Mil_CDSN_IO) & 1) {
printk("Error Erasing at 0x%x\n", ofs);
/* There was an error
FIXME: implement Bad Block Replacement (in nftl.c ??) */
instr->state = MTD_ERASE_FAILED;
} else
instr->state = MTD_ERASE_DONE;
dummy = ReadDOC(docptr, LastDataRead);
mtd_erase_callback(instr);
return 0;
}
/****************************************************************************
*
* Module stuff
*
****************************************************************************/
static void __exit cleanup_doc2001(void)
{
struct mtd_info *mtd;
struct DiskOnChip *this;
while ((mtd=docmillist)) {
this = mtd->priv;
docmillist = this->nextdoc;
mtd_device_unregister(mtd);
iounmap(this->virtadr);
kfree(this->chips);
kfree(mtd);
}
}
module_exit(cleanup_doc2001);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org> et al.");
MODULE_DESCRIPTION("Alternative driver for DiskOnChip Millennium");

File diff suppressed because it is too large Load Diff

View File

@ -1,521 +0,0 @@
/*
* ECC algorithm for M-systems disk on chip. We use the excellent Reed
* Solmon code of Phil Karn (karn@ka9q.ampr.org) available under the
* GNU GPL License. The rest is simply to convert the disk on chip
* syndrome into a standard syndome.
*
* Author: Fabrice Bellard (fabrice.bellard@netgem.com)
* Copyright (C) 2000 Netgem S.A.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <asm/errno.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/doc2000.h>
#define DEBUG_ECC 0
/* need to undef it (from asm/termbits.h) */
#undef B0
#define MM 10 /* Symbol size in bits */
#define KK (1023-4) /* Number of data symbols per block */
#define B0 510 /* First root of generator polynomial, alpha form */
#define PRIM 1 /* power of alpha used to generate roots of generator poly */
#define NN ((1 << MM) - 1)
typedef unsigned short dtype;
/* 1+x^3+x^10 */
static const int Pp[MM+1] = { 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1 };
/* This defines the type used to store an element of the Galois Field
* used by the code. Make sure this is something larger than a char if
* if anything larger than GF(256) is used.
*
* Note: unsigned char will work up to GF(256) but int seems to run
* faster on the Pentium.
*/
typedef int gf;
/* No legal value in index form represents zero, so
* we need a special value for this purpose
*/
#define A0 (NN)
/* Compute x % NN, where NN is 2**MM - 1,
* without a slow divide
*/
static inline gf
modnn(int x)
{
while (x >= NN) {
x -= NN;
x = (x >> MM) + (x & NN);
}
return x;
}
#define CLEAR(a,n) {\
int ci;\
for(ci=(n)-1;ci >=0;ci--)\
(a)[ci] = 0;\
}
#define COPY(a,b,n) {\
int ci;\
for(ci=(n)-1;ci >=0;ci--)\
(a)[ci] = (b)[ci];\
}
#define COPYDOWN(a,b,n) {\
int ci;\
for(ci=(n)-1;ci >=0;ci--)\
(a)[ci] = (b)[ci];\
}
#define Ldec 1
/* generate GF(2**m) from the irreducible polynomial p(X) in Pp[0]..Pp[m]
lookup tables: index->polynomial form alpha_to[] contains j=alpha**i;
polynomial form -> index form index_of[j=alpha**i] = i
alpha=2 is the primitive element of GF(2**m)
HARI's COMMENT: (4/13/94) alpha_to[] can be used as follows:
Let @ represent the primitive element commonly called "alpha" that
is the root of the primitive polynomial p(x). Then in GF(2^m), for any
0 <= i <= 2^m-2,
@^i = a(0) + a(1) @ + a(2) @^2 + ... + a(m-1) @^(m-1)
where the binary vector (a(0),a(1),a(2),...,a(m-1)) is the representation
of the integer "alpha_to[i]" with a(0) being the LSB and a(m-1) the MSB. Thus for
example the polynomial representation of @^5 would be given by the binary
representation of the integer "alpha_to[5]".
Similarly, index_of[] can be used as follows:
As above, let @ represent the primitive element of GF(2^m) that is
the root of the primitive polynomial p(x). In order to find the power
of @ (alpha) that has the polynomial representation
a(0) + a(1) @ + a(2) @^2 + ... + a(m-1) @^(m-1)
we consider the integer "i" whose binary representation with a(0) being LSB
and a(m-1) MSB is (a(0),a(1),...,a(m-1)) and locate the entry
"index_of[i]". Now, @^index_of[i] is that element whose polynomial
representation is (a(0),a(1),a(2),...,a(m-1)).
NOTE:
The element alpha_to[2^m-1] = 0 always signifying that the
representation of "@^infinity" = 0 is (0,0,0,...,0).
Similarly, the element index_of[0] = A0 always signifying
that the power of alpha which has the polynomial representation
(0,0,...,0) is "infinity".
*/
static void
generate_gf(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1])
{
register int i, mask;
mask = 1;
Alpha_to[MM] = 0;
for (i = 0; i < MM; i++) {
Alpha_to[i] = mask;
Index_of[Alpha_to[i]] = i;
/* If Pp[i] == 1 then, term @^i occurs in poly-repr of @^MM */
if (Pp[i] != 0)
Alpha_to[MM] ^= mask; /* Bit-wise EXOR operation */
mask <<= 1; /* single left-shift */
}
Index_of[Alpha_to[MM]] = MM;
/*
* Have obtained poly-repr of @^MM. Poly-repr of @^(i+1) is given by
* poly-repr of @^i shifted left one-bit and accounting for any @^MM
* term that may occur when poly-repr of @^i is shifted.
*/
mask >>= 1;
for (i = MM + 1; i < NN; i++) {
if (Alpha_to[i - 1] >= mask)
Alpha_to[i] = Alpha_to[MM] ^ ((Alpha_to[i - 1] ^ mask) << 1);
else
Alpha_to[i] = Alpha_to[i - 1] << 1;
Index_of[Alpha_to[i]] = i;
}
Index_of[0] = A0;
Alpha_to[NN] = 0;
}
/*
* Performs ERRORS+ERASURES decoding of RS codes. bb[] is the content
* of the feedback shift register after having processed the data and
* the ECC.
*
* Return number of symbols corrected, or -1 if codeword is illegal
* or uncorrectable. If eras_pos is non-null, the detected error locations
* are written back. NOTE! This array must be at least NN-KK elements long.
* The corrected data are written in eras_val[]. They must be xor with the data
* to retrieve the correct data : data[erase_pos[i]] ^= erase_val[i] .
*
* First "no_eras" erasures are declared by the calling program. Then, the
* maximum # of errors correctable is t_after_eras = floor((NN-KK-no_eras)/2).
* If the number of channel errors is not greater than "t_after_eras" the
* transmitted codeword will be recovered. Details of algorithm can be found
* in R. Blahut's "Theory ... of Error-Correcting Codes".
* Warning: the eras_pos[] array must not contain duplicate entries; decoder failure
* will result. The decoder *could* check for this condition, but it would involve
* extra time on every decoding operation.
* */
static int
eras_dec_rs(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1],
gf bb[NN - KK + 1], gf eras_val[NN-KK], int eras_pos[NN-KK],
int no_eras)
{
int deg_lambda, el, deg_omega;
int i, j, r,k;
gf u,q,tmp,num1,num2,den,discr_r;
gf lambda[NN-KK + 1], s[NN-KK + 1]; /* Err+Eras Locator poly
* and syndrome poly */
gf b[NN-KK + 1], t[NN-KK + 1], omega[NN-KK + 1];
gf root[NN-KK], reg[NN-KK + 1], loc[NN-KK];
int syn_error, count;
syn_error = 0;
for(i=0;i<NN-KK;i++)
syn_error |= bb[i];
if (!syn_error) {
/* if remainder is zero, data[] is a codeword and there are no
* errors to correct. So return data[] unmodified
*/
count = 0;
goto finish;
}
for(i=1;i<=NN-KK;i++){
s[i] = bb[0];
}
for(j=1;j<NN-KK;j++){
if(bb[j] == 0)
continue;
tmp = Index_of[bb[j]];
for(i=1;i<=NN-KK;i++)
s[i] ^= Alpha_to[modnn(tmp + (B0+i-1)*PRIM*j)];
}
/* undo the feedback register implicit multiplication and convert
syndromes to index form */
for(i=1;i<=NN-KK;i++) {
tmp = Index_of[s[i]];
if (tmp != A0)
tmp = modnn(tmp + 2 * KK * (B0+i-1)*PRIM);
s[i] = tmp;
}
CLEAR(&lambda[1],NN-KK);
lambda[0] = 1;
if (no_eras > 0) {
/* Init lambda to be the erasure locator polynomial */
lambda[1] = Alpha_to[modnn(PRIM * eras_pos[0])];
for (i = 1; i < no_eras; i++) {
u = modnn(PRIM*eras_pos[i]);
for (j = i+1; j > 0; j--) {
tmp = Index_of[lambda[j - 1]];
if(tmp != A0)
lambda[j] ^= Alpha_to[modnn(u + tmp)];
}
}
#if DEBUG_ECC >= 1
/* Test code that verifies the erasure locator polynomial just constructed
Needed only for decoder debugging. */
/* find roots of the erasure location polynomial */
for(i=1;i<=no_eras;i++)
reg[i] = Index_of[lambda[i]];
count = 0;
for (i = 1,k=NN-Ldec; i <= NN; i++,k = modnn(NN+k-Ldec)) {
q = 1;
for (j = 1; j <= no_eras; j++)
if (reg[j] != A0) {
reg[j] = modnn(reg[j] + j);
q ^= Alpha_to[reg[j]];
}
if (q != 0)
continue;
/* store root and error location number indices */
root[count] = i;
loc[count] = k;
count++;
}
if (count != no_eras) {
printf("\n lambda(x) is WRONG\n");
count = -1;
goto finish;
}
#if DEBUG_ECC >= 2
printf("\n Erasure positions as determined by roots of Eras Loc Poly:\n");
for (i = 0; i < count; i++)
printf("%d ", loc[i]);
printf("\n");
#endif
#endif
}
for(i=0;i<NN-KK+1;i++)
b[i] = Index_of[lambda[i]];
/*
* Begin Berlekamp-Massey algorithm to determine error+erasure
* locator polynomial
*/
r = no_eras;
el = no_eras;
while (++r <= NN-KK) { /* r is the step number */
/* Compute discrepancy at the r-th step in poly-form */
discr_r = 0;
for (i = 0; i < r; i++){
if ((lambda[i] != 0) && (s[r - i] != A0)) {
discr_r ^= Alpha_to[modnn(Index_of[lambda[i]] + s[r - i])];
}
}
discr_r = Index_of[discr_r]; /* Index form */
if (discr_r == A0) {
/* 2 lines below: B(x) <-- x*B(x) */
COPYDOWN(&b[1],b,NN-KK);
b[0] = A0;
} else {
/* 7 lines below: T(x) <-- lambda(x) - discr_r*x*b(x) */
t[0] = lambda[0];
for (i = 0 ; i < NN-KK; i++) {
if(b[i] != A0)
t[i+1] = lambda[i+1] ^ Alpha_to[modnn(discr_r + b[i])];
else
t[i+1] = lambda[i+1];
}
if (2 * el <= r + no_eras - 1) {
el = r + no_eras - el;
/*
* 2 lines below: B(x) <-- inv(discr_r) *
* lambda(x)
*/
for (i = 0; i <= NN-KK; i++)
b[i] = (lambda[i] == 0) ? A0 : modnn(Index_of[lambda[i]] - discr_r + NN);
} else {
/* 2 lines below: B(x) <-- x*B(x) */
COPYDOWN(&b[1],b,NN-KK);
b[0] = A0;
}
COPY(lambda,t,NN-KK+1);
}
}
/* Convert lambda to index form and compute deg(lambda(x)) */
deg_lambda = 0;
for(i=0;i<NN-KK+1;i++){
lambda[i] = Index_of[lambda[i]];
if(lambda[i] != A0)
deg_lambda = i;
}
/*
* Find roots of the error+erasure locator polynomial by Chien
* Search
*/
COPY(&reg[1],&lambda[1],NN-KK);
count = 0; /* Number of roots of lambda(x) */
for (i = 1,k=NN-Ldec; i <= NN; i++,k = modnn(NN+k-Ldec)) {
q = 1;
for (j = deg_lambda; j > 0; j--){
if (reg[j] != A0) {
reg[j] = modnn(reg[j] + j);
q ^= Alpha_to[reg[j]];
}
}
if (q != 0)
continue;
/* store root (index-form) and error location number */
root[count] = i;
loc[count] = k;
/* If we've already found max possible roots,
* abort the search to save time
*/
if(++count == deg_lambda)
break;
}
if (deg_lambda != count) {
/*
* deg(lambda) unequal to number of roots => uncorrectable
* error detected
*/
count = -1;
goto finish;
}
/*
* Compute err+eras evaluator poly omega(x) = s(x)*lambda(x) (modulo
* x**(NN-KK)). in index form. Also find deg(omega).
*/
deg_omega = 0;
for (i = 0; i < NN-KK;i++){
tmp = 0;
j = (deg_lambda < i) ? deg_lambda : i;
for(;j >= 0; j--){
if ((s[i + 1 - j] != A0) && (lambda[j] != A0))
tmp ^= Alpha_to[modnn(s[i + 1 - j] + lambda[j])];
}
if(tmp != 0)
deg_omega = i;
omega[i] = Index_of[tmp];
}
omega[NN-KK] = A0;
/*
* Compute error values in poly-form. num1 = omega(inv(X(l))), num2 =
* inv(X(l))**(B0-1) and den = lambda_pr(inv(X(l))) all in poly-form
*/
for (j = count-1; j >=0; j--) {
num1 = 0;
for (i = deg_omega; i >= 0; i--) {
if (omega[i] != A0)
num1 ^= Alpha_to[modnn(omega[i] + i * root[j])];
}
num2 = Alpha_to[modnn(root[j] * (B0 - 1) + NN)];
den = 0;
/* lambda[i+1] for i even is the formal derivative lambda_pr of lambda[i] */
for (i = min(deg_lambda,NN-KK-1) & ~1; i >= 0; i -=2) {
if(lambda[i+1] != A0)
den ^= Alpha_to[modnn(lambda[i+1] + i * root[j])];
}
if (den == 0) {
#if DEBUG_ECC >= 1
printf("\n ERROR: denominator = 0\n");
#endif
/* Convert to dual- basis */
count = -1;
goto finish;
}
/* Apply error to data */
if (num1 != 0) {
eras_val[j] = Alpha_to[modnn(Index_of[num1] + Index_of[num2] + NN - Index_of[den])];
} else {
eras_val[j] = 0;
}
}
finish:
for(i=0;i<count;i++)
eras_pos[i] = loc[i];
return count;
}
/***************************************************************************/
/* The DOC specific code begins here */
#define SECTOR_SIZE 512
/* The sector bytes are packed into NB_DATA MM bits words */
#define NB_DATA (((SECTOR_SIZE + 1) * 8 + 6) / MM)
/*
* Correct the errors in 'sector[]' by using 'ecc1[]' which is the
* content of the feedback shift register applyied to the sector and
* the ECC. Return the number of errors corrected (and correct them in
* sector), or -1 if error
*/
int doc_decode_ecc(unsigned char sector[SECTOR_SIZE], unsigned char ecc1[6])
{
int parity, i, nb_errors;
gf bb[NN - KK + 1];
gf error_val[NN-KK];
int error_pos[NN-KK], pos, bitpos, index, val;
dtype *Alpha_to, *Index_of;
/* init log and exp tables here to save memory. However, it is slower */
Alpha_to = kmalloc((NN + 1) * sizeof(dtype), GFP_KERNEL);
if (!Alpha_to)
return -1;
Index_of = kmalloc((NN + 1) * sizeof(dtype), GFP_KERNEL);
if (!Index_of) {
kfree(Alpha_to);
return -1;
}
generate_gf(Alpha_to, Index_of);
parity = ecc1[1];
bb[0] = (ecc1[4] & 0xff) | ((ecc1[5] & 0x03) << 8);
bb[1] = ((ecc1[5] & 0xfc) >> 2) | ((ecc1[2] & 0x0f) << 6);
bb[2] = ((ecc1[2] & 0xf0) >> 4) | ((ecc1[3] & 0x3f) << 4);
bb[3] = ((ecc1[3] & 0xc0) >> 6) | ((ecc1[0] & 0xff) << 2);
nb_errors = eras_dec_rs(Alpha_to, Index_of, bb,
error_val, error_pos, 0);
if (nb_errors <= 0)
goto the_end;
/* correct the errors */
for(i=0;i<nb_errors;i++) {
pos = error_pos[i];
if (pos >= NB_DATA && pos < KK) {
nb_errors = -1;
goto the_end;
}
if (pos < NB_DATA) {
/* extract bit position (MSB first) */
pos = 10 * (NB_DATA - 1 - pos) - 6;
/* now correct the following 10 bits. At most two bytes
can be modified since pos is even */
index = (pos >> 3) ^ 1;
bitpos = pos & 7;
if ((index >= 0 && index < SECTOR_SIZE) ||
index == (SECTOR_SIZE + 1)) {
val = error_val[i] >> (2 + bitpos);
parity ^= val;
if (index < SECTOR_SIZE)
sector[index] ^= val;
}
index = ((pos >> 3) + 1) ^ 1;
bitpos = (bitpos + 10) & 7;
if (bitpos == 0)
bitpos = 8;
if ((index >= 0 && index < SECTOR_SIZE) ||
index == (SECTOR_SIZE + 1)) {
val = error_val[i] << (8 - bitpos);
parity ^= val;
if (index < SECTOR_SIZE)
sector[index] ^= val;
}
}
}
/* use parity to test extra errors */
if ((parity & 0xff) != 0)
nb_errors = -1;
the_end:
kfree(Alpha_to);
kfree(Index_of);
return nb_errors;
}
EXPORT_SYMBOL_GPL(doc_decode_ecc);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Fabrice Bellard <fabrice.bellard@netgem.com>");
MODULE_DESCRIPTION("ECC code for correcting errors detected by DiskOnChip 2000 and Millennium ECC hardware");

View File

@ -123,7 +123,7 @@ static inline void doc_flash_address(struct docg3 *docg3, u8 addr)
doc_writeb(docg3, addr, DOC_FLASHADDRESS);
}
static char const *part_probes[] = { "cmdlinepart", "saftlpart", NULL };
static char const * const part_probes[] = { "cmdlinepart", "saftlpart", NULL };
static int doc_register_readb(struct docg3 *docg3, int reg)
{
@ -2144,18 +2144,7 @@ static struct platform_driver g3_driver = {
.remove = __exit_p(docg3_release),
};
static int __init docg3_init(void)
{
return platform_driver_probe(&g3_driver, docg3_probe);
}
module_init(docg3_init);
static void __exit docg3_exit(void)
{
platform_driver_unregister(&g3_driver);
}
module_exit(docg3_exit);
module_platform_driver_probe(g3_driver, docg3_probe);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Robert Jarzmik <robert.jarzmik@free.fr>");

View File

@ -1,325 +0,0 @@
/* Linux driver for Disk-On-Chip devices */
/* Probe routines common to all DoC devices */
/* (C) 1999 Machine Vision Holdings, Inc. */
/* (C) 1999-2003 David Woodhouse <dwmw2@infradead.org> */
/* DOC_PASSIVE_PROBE:
In order to ensure that the BIOS checksum is correct at boot time, and
hence that the onboard BIOS extension gets executed, the DiskOnChip
goes into reset mode when it is read sequentially: all registers
return 0xff until the chip is woken up again by writing to the
DOCControl register.
Unfortunately, this means that the probe for the DiskOnChip is unsafe,
because one of the first things it does is write to where it thinks
the DOCControl register should be - which may well be shared memory
for another device. I've had machines which lock up when this is
attempted. Hence the possibility to do a passive probe, which will fail
to detect a chip in reset mode, but is at least guaranteed not to lock
the machine.
If you have this problem, uncomment the following line:
#define DOC_PASSIVE_PROBE
*/
/* DOC_SINGLE_DRIVER:
Millennium driver has been merged into DOC2000 driver.
The old Millennium-only driver has been retained just in case there
are problems with the new code. If the combined driver doesn't work
for you, you can try the old one by undefining DOC_SINGLE_DRIVER
below and also enabling it in your configuration. If this fixes the
problems, please send a report to the MTD mailing list at
<linux-mtd@lists.infradead.org>.
*/
#define DOC_SINGLE_DRIVER
#include <linux/kernel.h>
#include <linux/module.h>
#include <asm/errno.h>
#include <asm/io.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/doc2000.h>
static unsigned long doc_config_location = CONFIG_MTD_DOCPROBE_ADDRESS;
module_param(doc_config_location, ulong, 0);
MODULE_PARM_DESC(doc_config_location, "Physical memory address at which to probe for DiskOnChip");
static unsigned long __initdata doc_locations[] = {
#if defined (__alpha__) || defined(__i386__) || defined(__x86_64__)
#ifdef CONFIG_MTD_DOCPROBE_HIGH
0xfffc8000, 0xfffca000, 0xfffcc000, 0xfffce000,
0xfffd0000, 0xfffd2000, 0xfffd4000, 0xfffd6000,
0xfffd8000, 0xfffda000, 0xfffdc000, 0xfffde000,
0xfffe0000, 0xfffe2000, 0xfffe4000, 0xfffe6000,
0xfffe8000, 0xfffea000, 0xfffec000, 0xfffee000,
#else /* CONFIG_MTD_DOCPROBE_HIGH */
0xc8000, 0xca000, 0xcc000, 0xce000,
0xd0000, 0xd2000, 0xd4000, 0xd6000,
0xd8000, 0xda000, 0xdc000, 0xde000,
0xe0000, 0xe2000, 0xe4000, 0xe6000,
0xe8000, 0xea000, 0xec000, 0xee000,
#endif /* CONFIG_MTD_DOCPROBE_HIGH */
#endif
0xffffffff };
/* doccheck: Probe a given memory window to see if there's a DiskOnChip present */
static inline int __init doccheck(void __iomem *potential, unsigned long physadr)
{
void __iomem *window=potential;
unsigned char tmp, tmpb, tmpc, ChipID;
#ifndef DOC_PASSIVE_PROBE
unsigned char tmp2;
#endif
/* Routine copied from the Linux DOC driver */
#ifdef CONFIG_MTD_DOCPROBE_55AA
/* Check for 0x55 0xAA signature at beginning of window,
this is no longer true once we remove the IPL (for Millennium */
if (ReadDOC(window, Sig1) != 0x55 || ReadDOC(window, Sig2) != 0xaa)
return 0;
#endif /* CONFIG_MTD_DOCPROBE_55AA */
#ifndef DOC_PASSIVE_PROBE
/* It's not possible to cleanly detect the DiskOnChip - the
* bootup procedure will put the device into reset mode, and
* it's not possible to talk to it without actually writing
* to the DOCControl register. So we store the current contents
* of the DOCControl register's location, in case we later decide
* that it's not a DiskOnChip, and want to put it back how we
* found it.
*/
tmp2 = ReadDOC(window, DOCControl);
/* Reset the DiskOnChip ASIC */
WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET,
window, DOCControl);
WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET,
window, DOCControl);
/* Enable the DiskOnChip ASIC */
WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL,
window, DOCControl);
WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL,
window, DOCControl);
#endif /* !DOC_PASSIVE_PROBE */
/* We need to read the ChipID register four times. For some
newer DiskOnChip 2000 units, the first three reads will
return the DiskOnChip Millennium ident. Don't ask. */
ChipID = ReadDOC(window, ChipID);
switch (ChipID) {
case DOC_ChipID_Doc2k:
/* Check the TOGGLE bit in the ECC register */
tmp = ReadDOC(window, 2k_ECCStatus) & DOC_TOGGLE_BIT;
tmpb = ReadDOC(window, 2k_ECCStatus) & DOC_TOGGLE_BIT;
tmpc = ReadDOC(window, 2k_ECCStatus) & DOC_TOGGLE_BIT;
if (tmp != tmpb && tmp == tmpc)
return ChipID;
break;
case DOC_ChipID_DocMil:
/* Check for the new 2000 with Millennium ASIC */
ReadDOC(window, ChipID);
ReadDOC(window, ChipID);
if (ReadDOC(window, ChipID) != DOC_ChipID_DocMil)
ChipID = DOC_ChipID_Doc2kTSOP;
/* Check the TOGGLE bit in the ECC register */
tmp = ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT;
tmpb = ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT;
tmpc = ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT;
if (tmp != tmpb && tmp == tmpc)
return ChipID;
break;
case DOC_ChipID_DocMilPlus16:
case DOC_ChipID_DocMilPlus32:
case 0:
/* Possible Millennium+, need to do more checks */
#ifndef DOC_PASSIVE_PROBE
/* Possibly release from power down mode */
for (tmp = 0; (tmp < 4); tmp++)
ReadDOC(window, Mplus_Power);
/* Reset the DiskOnChip ASIC */
tmp = DOC_MODE_RESET | DOC_MODE_MDWREN | DOC_MODE_RST_LAT |
DOC_MODE_BDECT;
WriteDOC(tmp, window, Mplus_DOCControl);
WriteDOC(~tmp, window, Mplus_CtrlConfirm);
mdelay(1);
/* Enable the DiskOnChip ASIC */
tmp = DOC_MODE_NORMAL | DOC_MODE_MDWREN | DOC_MODE_RST_LAT |
DOC_MODE_BDECT;
WriteDOC(tmp, window, Mplus_DOCControl);
WriteDOC(~tmp, window, Mplus_CtrlConfirm);
mdelay(1);
#endif /* !DOC_PASSIVE_PROBE */
ChipID = ReadDOC(window, ChipID);
switch (ChipID) {
case DOC_ChipID_DocMilPlus16:
case DOC_ChipID_DocMilPlus32:
/* Check the TOGGLE bit in the toggle register */
tmp = ReadDOC(window, Mplus_Toggle) & DOC_TOGGLE_BIT;
tmpb = ReadDOC(window, Mplus_Toggle) & DOC_TOGGLE_BIT;
tmpc = ReadDOC(window, Mplus_Toggle) & DOC_TOGGLE_BIT;
if (tmp != tmpb && tmp == tmpc)
return ChipID;
default:
break;
}
/* FALL TRHU */
default:
#ifdef CONFIG_MTD_DOCPROBE_55AA
printk(KERN_DEBUG "Possible DiskOnChip with unknown ChipID %2.2X found at 0x%lx\n",
ChipID, physadr);
#endif
#ifndef DOC_PASSIVE_PROBE
/* Put back the contents of the DOCControl register, in case it's not
* actually a DiskOnChip.
*/
WriteDOC(tmp2, window, DOCControl);
#endif
return 0;
}
printk(KERN_WARNING "DiskOnChip failed TOGGLE test, dropping.\n");
#ifndef DOC_PASSIVE_PROBE
/* Put back the contents of the DOCControl register: it's not a DiskOnChip */
WriteDOC(tmp2, window, DOCControl);
#endif
return 0;
}
static int docfound;
extern void DoC2k_init(struct mtd_info *);
extern void DoCMil_init(struct mtd_info *);
extern void DoCMilPlus_init(struct mtd_info *);
static void __init DoC_Probe(unsigned long physadr)
{
void __iomem *docptr;
struct DiskOnChip *this;
struct mtd_info *mtd;
int ChipID;
char namebuf[15];
char *name = namebuf;
void (*initroutine)(struct mtd_info *) = NULL;
docptr = ioremap(physadr, DOC_IOREMAP_LEN);
if (!docptr)
return;
if ((ChipID = doccheck(docptr, physadr))) {
if (ChipID == DOC_ChipID_Doc2kTSOP) {
/* Remove this at your own peril. The hardware driver works but nothing prevents you from erasing bad blocks */
printk(KERN_NOTICE "Refusing to drive DiskOnChip 2000 TSOP until Bad Block Table is correctly supported by INFTL\n");
iounmap(docptr);
return;
}
docfound = 1;
mtd = kzalloc(sizeof(struct DiskOnChip) + sizeof(struct mtd_info), GFP_KERNEL);
if (!mtd) {
printk(KERN_WARNING "Cannot allocate memory for data structures. Dropping.\n");
iounmap(docptr);
return;
}
this = (struct DiskOnChip *)(&mtd[1]);
mtd->priv = this;
this->virtadr = docptr;
this->physadr = physadr;
this->ChipID = ChipID;
sprintf(namebuf, "with ChipID %2.2X", ChipID);
switch(ChipID) {
case DOC_ChipID_Doc2kTSOP:
name="2000 TSOP";
initroutine = symbol_request(DoC2k_init);
break;
case DOC_ChipID_Doc2k:
name="2000";
initroutine = symbol_request(DoC2k_init);
break;
case DOC_ChipID_DocMil:
name="Millennium";
#ifdef DOC_SINGLE_DRIVER
initroutine = symbol_request(DoC2k_init);
#else
initroutine = symbol_request(DoCMil_init);
#endif /* DOC_SINGLE_DRIVER */
break;
case DOC_ChipID_DocMilPlus16:
case DOC_ChipID_DocMilPlus32:
name="MillenniumPlus";
initroutine = symbol_request(DoCMilPlus_init);
break;
}
if (initroutine) {
(*initroutine)(mtd);
symbol_put_addr(initroutine);
return;
}
printk(KERN_NOTICE "Cannot find driver for DiskOnChip %s at 0x%lX\n", name, physadr);
kfree(mtd);
}
iounmap(docptr);
}
/****************************************************************************
*
* Module stuff
*
****************************************************************************/
static int __init init_doc(void)
{
int i;
if (doc_config_location) {
printk(KERN_INFO "Using configured DiskOnChip probe address 0x%lx\n", doc_config_location);
DoC_Probe(doc_config_location);
} else {
for (i=0; (doc_locations[i] != 0xffffffff); i++) {
DoC_Probe(doc_locations[i]);
}
}
/* No banner message any more. Print a message if no DiskOnChip
found, so the user knows we at least tried. */
if (!docfound)
printk(KERN_INFO "No recognised DiskOnChip devices found\n");
return -EAGAIN;
}
module_init(init_doc);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
MODULE_DESCRIPTION("Probe code for DiskOnChip 2000 and Millennium devices");

View File

@ -81,14 +81,21 @@ static u32 elm_read_reg(struct elm_info *info, int offset)
* @dev: ELM device
* @bch_type: Type of BCH ecc
*/
void elm_config(struct device *dev, enum bch_ecc bch_type)
int elm_config(struct device *dev, enum bch_ecc bch_type)
{
u32 reg_val;
struct elm_info *info = dev_get_drvdata(dev);
if (!info) {
dev_err(dev, "Unable to configure elm - device not probed?\n");
return -ENODEV;
}
reg_val = (bch_type & ECC_BCH_LEVEL_MASK) | (ELM_ECC_SIZE << 16);
elm_write_reg(info, ELM_LOCATION_CONFIG, reg_val);
info->bch_type = bch_type;
return 0;
}
EXPORT_SYMBOL(elm_config);

View File

@ -681,6 +681,7 @@ struct flash_info {
u16 flags;
#define SECT_4K 0x01 /* OPCODE_BE_4K works uniformly */
#define M25P_NO_ERASE 0x02 /* No erase command needed */
#define SST_WRITE 0x04 /* use SST byte programming */
};
#define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \
@ -728,6 +729,7 @@ static const struct spi_device_id m25p_ids[] = {
{ "en25q32b", INFO(0x1c3016, 0, 64 * 1024, 64, 0) },
{ "en25p64", INFO(0x1c2017, 0, 64 * 1024, 128, 0) },
{ "en25q64", INFO(0x1c3017, 0, 64 * 1024, 128, SECT_4K) },
{ "en25qh256", INFO(0x1c7019, 0, 64 * 1024, 512, 0) },
/* Everspin */
{ "mr25h256", CAT25_INFO( 32 * 1024, 1, 256, 2) },
@ -740,7 +742,6 @@ static const struct spi_device_id m25p_ids[] = {
{ "160s33b", INFO(0x898911, 0, 64 * 1024, 32, 0) },
{ "320s33b", INFO(0x898912, 0, 64 * 1024, 64, 0) },
{ "640s33b", INFO(0x898913, 0, 64 * 1024, 128, 0) },
{ "n25q064", INFO(0x20ba17, 0, 64 * 1024, 128, 0) },
/* Macronix */
{ "mx25l2005a", INFO(0xc22012, 0, 64 * 1024, 4, SECT_4K) },
@ -753,8 +754,10 @@ static const struct spi_device_id m25p_ids[] = {
{ "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) },
{ "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, 0) },
{ "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) },
{ "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, 0) },
/* Micron */
{ "n25q064", INFO(0x20ba17, 0, 64 * 1024, 128, 0) },
{ "n25q128a11", INFO(0x20bb18, 0, 64 * 1024, 256, 0) },
{ "n25q128a13", INFO(0x20ba18, 0, 64 * 1024, 256, 0) },
{ "n25q256a", INFO(0x20ba19, 0, 64 * 1024, 512, SECT_4K) },
@ -781,14 +784,15 @@ static const struct spi_device_id m25p_ids[] = {
{ "s25fl064k", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) },
/* SST -- large erase sizes are "overlays", "sectors" are 4K */
{ "sst25vf040b", INFO(0xbf258d, 0, 64 * 1024, 8, SECT_4K) },
{ "sst25vf080b", INFO(0xbf258e, 0, 64 * 1024, 16, SECT_4K) },
{ "sst25vf016b", INFO(0xbf2541, 0, 64 * 1024, 32, SECT_4K) },
{ "sst25vf032b", INFO(0xbf254a, 0, 64 * 1024, 64, SECT_4K) },
{ "sst25wf512", INFO(0xbf2501, 0, 64 * 1024, 1, SECT_4K) },
{ "sst25wf010", INFO(0xbf2502, 0, 64 * 1024, 2, SECT_4K) },
{ "sst25wf020", INFO(0xbf2503, 0, 64 * 1024, 4, SECT_4K) },
{ "sst25wf040", INFO(0xbf2504, 0, 64 * 1024, 8, SECT_4K) },
{ "sst25vf040b", INFO(0xbf258d, 0, 64 * 1024, 8, SECT_4K | SST_WRITE) },
{ "sst25vf080b", INFO(0xbf258e, 0, 64 * 1024, 16, SECT_4K | SST_WRITE) },
{ "sst25vf016b", INFO(0xbf2541, 0, 64 * 1024, 32, SECT_4K | SST_WRITE) },
{ "sst25vf032b", INFO(0xbf254a, 0, 64 * 1024, 64, SECT_4K | SST_WRITE) },
{ "sst25vf064c", INFO(0xbf254b, 0, 64 * 1024, 128, SECT_4K) },
{ "sst25wf512", INFO(0xbf2501, 0, 64 * 1024, 1, SECT_4K | SST_WRITE) },
{ "sst25wf010", INFO(0xbf2502, 0, 64 * 1024, 2, SECT_4K | SST_WRITE) },
{ "sst25wf020", INFO(0xbf2503, 0, 64 * 1024, 4, SECT_4K | SST_WRITE) },
{ "sst25wf040", INFO(0xbf2504, 0, 64 * 1024, 8, SECT_4K | SST_WRITE) },
/* ST Microelectronics -- newer production may have feature updates */
{ "m25p05", INFO(0x202010, 0, 32 * 1024, 2, 0) },
@ -838,6 +842,7 @@ static const struct spi_device_id m25p_ids[] = {
{ "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) },
{ "w25q80", INFO(0xef5014, 0, 64 * 1024, 16, SECT_4K) },
{ "w25q80bl", INFO(0xef4014, 0, 64 * 1024, 16, SECT_4K) },
{ "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) },
{ "w25q256", INFO(0xef4019, 0, 64 * 1024, 512, SECT_4K) },
/* Catalyst / On Semiconductor -- non-JEDEC */
@ -1000,7 +1005,7 @@ static int m25p_probe(struct spi_device *spi)
}
/* sst flash chips use AAI word program */
if (JEDEC_MFR(info->jedec_id) == CFI_MFR_SST)
if (info->flags & SST_WRITE)
flash->mtd._write = sst_write;
else
flash->mtd._write = m25p80_write;

View File

@ -105,8 +105,6 @@ static const struct of_device_id dataflash_dt_ids[] = {
{ .compatible = "atmel,dataflash", },
{ /* sentinel */ }
};
#else
#define dataflash_dt_ids NULL
#endif
/* ......................................................................... */
@ -914,7 +912,7 @@ static struct spi_driver dataflash_driver = {
.driver = {
.name = "mtd_dataflash",
.owner = THIS_MODULE,
.of_match_table = dataflash_dt_ids,
.of_match_table = of_match_ptr(dataflash_dt_ids),
},
.probe = dataflash_probe,

View File

@ -249,22 +249,6 @@ config MTD_LANTIQ
help
Support for NOR flash attached to the Lantiq SoC's External Bus Unit.
config MTD_DILNETPC
tristate "CFI Flash device mapped on DIL/Net PC"
depends on X86 && MTD_CFI_INTELEXT && BROKEN
help
MTD map driver for SSV DIL/Net PC Boards "DNP" and "ADNP".
For details, see <http://www.ssv-embedded.de/ssv/pc104/p169.htm>
and <http://www.ssv-embedded.de/ssv/pc104/p170.htm>
config MTD_DILNETPC_BOOTSIZE
hex "Size of DIL/Net PC flash boot partition"
depends on MTD_DILNETPC
default "0x80000"
help
The amount of space taken up by the kernel or Etherboot
on the DIL/Net PC flash chips.
config MTD_L440GX
tristate "BIOS flash chip on Intel L440GX boards"
depends on X86 && MTD_JEDECPROBE
@ -274,42 +258,6 @@ config MTD_L440GX
BE VERY CAREFUL.
config MTD_TQM8XXL
tristate "CFI Flash device mapped on TQM8XXL"
depends on MTD_CFI && TQM8xxL
help
The TQM8xxL PowerPC board has up to two banks of CFI-compliant
chips, currently uses AMD one. This 'mapping' driver supports
that arrangement, allowing the CFI probe and command set driver
code to communicate with the chips on the TQM8xxL board. More at
<http://www.denx.de/wiki/PPCEmbedded/>.
config MTD_RPXLITE
tristate "CFI Flash device mapped on RPX Lite or CLLF"
depends on MTD_CFI && (RPXCLASSIC || RPXLITE)
help
The RPXLite PowerPC board has CFI-compliant chips mapped in
a strange sparse mapping. This 'mapping' driver supports that
arrangement, allowing the CFI probe and command set driver code
to communicate with the chips on the RPXLite board. More at
<http://www.embeddedplanet.com/>.
config MTD_MBX860
tristate "System flash on MBX860 board"
depends on MTD_CFI && MBX
help
This enables access routines for the flash chips on the Motorola
MBX860 board. If you have one of these boards and would like
to use the flash chips on it, say 'Y'.
config MTD_DBOX2
tristate "CFI Flash device mapped on D-Box2"
depends on DBOX2 && MTD_CFI_INTELSTD && MTD_CFI_INTELEXT && MTD_CFI_AMDSTD
help
This enables access routines for the flash chips on the Nokia/Sagem
D-Box 2 board. If you have one of these boards and would like to use
the flash chips on it, say 'Y'.
config MTD_CFI_FLAGADM
tristate "CFI Flash device mapping on FlagaDM"
depends on 8xx && MTD_CFI
@ -349,15 +297,6 @@ config MTD_IXP4XX
IXDP425 and Coyote. If you have an IXP4xx based board and
would like to use the flash chips on it, say 'Y'.
config MTD_IXP2000
tristate "CFI Flash device mapped on Intel IXP2000 based systems"
depends on MTD_CFI && MTD_COMPLEX_MAPPINGS && ARCH_IXP2000
help
This enables MTD access to flash devices on platforms based
on Intel's IXP2000 family of network processors. If you have an
IXP2000 based board and would like to use the flash chips on it,
say 'Y'.
config MTD_AUTCPU12
bool "NV-RAM mapping AUTCPU12 board"
depends on ARCH_AUTCPU12
@ -372,13 +311,6 @@ config MTD_IMPA7
This enables access to the NOR Flash on the impA7 board of
implementa GmbH. If you have such a board, say 'Y' here.
config MTD_H720X
tristate "Hynix evaluation board mappings"
depends on MTD_CFI && ( ARCH_H7201 || ARCH_H7202 )
help
This enables access to the flash chips on the Hynix evaluation boards.
If you have such a board, say 'Y'.
# This needs CFI or JEDEC, depending on the cards found.
config MTD_PCI
tristate "PCI MTD driver"
@ -433,15 +365,6 @@ config MTD_UCLINUX
help
Map driver to support image based filesystems for uClinux.
config MTD_DMV182
tristate "Map driver for Dy-4 SVME/DMV-182 board."
depends on DMV182
select MTD_MAP_BANK_WIDTH_32
select MTD_CFI_I8
select MTD_CFI_AMDSTD
help
Map driver for Dy-4 SVME/DMV-182 board.
config MTD_INTEL_VR_NOR
tristate "NOR flash on Intel Vermilion Range Expansion Bus CS0"
depends on PCI

View File

@ -9,7 +9,6 @@ endif
# Chip mappings
obj-$(CONFIG_MTD_CFI_FLAGADM) += cfi_flagadm.o
obj-$(CONFIG_MTD_DC21285) += dc21285.o
obj-$(CONFIG_MTD_DILNETPC) += dilnetpc.o
obj-$(CONFIG_MTD_L440GX) += l440gx.o
obj-$(CONFIG_MTD_AMD76XROM) += amd76xrom.o
obj-$(CONFIG_MTD_ESB2ROM) += esb2rom.o
@ -17,15 +16,12 @@ obj-$(CONFIG_MTD_ICHXROM) += ichxrom.o
obj-$(CONFIG_MTD_CK804XROM) += ck804xrom.o
obj-$(CONFIG_MTD_TSUNAMI) += tsunami_flash.o
obj-$(CONFIG_MTD_PXA2XX) += pxa2xx-flash.o
obj-$(CONFIG_MTD_MBX860) += mbx860.o
obj-$(CONFIG_MTD_OCTAGON) += octagon-5066.o
obj-$(CONFIG_MTD_PHYSMAP) += physmap.o
obj-$(CONFIG_MTD_PHYSMAP_OF) += physmap_of.o
obj-$(CONFIG_MTD_PISMO) += pismo.o
obj-$(CONFIG_MTD_PMC_MSP_EVM) += pmcmsp-flash.o
obj-$(CONFIG_MTD_PCMCIA) += pcmciamtd.o
obj-$(CONFIG_MTD_RPXLITE) += rpxlite.o
obj-$(CONFIG_MTD_TQM8XXL) += tqm8xxl.o
obj-$(CONFIG_MTD_SA1100) += sa1100-flash.o
obj-$(CONFIG_MTD_SBC_GXX) += sbc_gxx.o
obj-$(CONFIG_MTD_SC520CDP) += sc520cdp.o
@ -34,7 +30,6 @@ obj-$(CONFIG_MTD_TS5500) += ts5500_flash.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_DBOX2) += dbox2-flash.o
obj-$(CONFIG_MTD_SOLUTIONENGINE)+= solutionengine.o
obj-$(CONFIG_MTD_PCI) += pci.o
obj-$(CONFIG_MTD_AUTCPU12) += autcpu12-nvram.o
@ -42,10 +37,7 @@ obj-$(CONFIG_MTD_IMPA7) += impa7.o
obj-$(CONFIG_MTD_UCLINUX) += uclinux.o
obj-$(CONFIG_MTD_NETtel) += nettel.o
obj-$(CONFIG_MTD_SCB2_FLASH) += scb2_flash.o
obj-$(CONFIG_MTD_H720X) += h720x-flash.o
obj-$(CONFIG_MTD_IXP4XX) += ixp4xx.o
obj-$(CONFIG_MTD_IXP2000) += ixp2000.o
obj-$(CONFIG_MTD_DMV182) += dmv182.o
obj-$(CONFIG_MTD_PLATRAM) += plat-ram.o
obj-$(CONFIG_MTD_INTEL_VR_NOR) += intel_vr_nor.o
obj-$(CONFIG_MTD_BFIN_ASYNC) += bfin-async-flash.o

View File

@ -122,7 +122,8 @@ static void bfin_flash_copy_to(struct map_info *map, unsigned long to, const voi
switch_back(state);
}
static const char *part_probe_types[] = { "cmdlinepart", "RedBoot", NULL };
static const char * const part_probe_types[] = {
"cmdlinepart", "RedBoot", NULL };
static int bfin_flash_probe(struct platform_device *pdev)
{

View File

@ -308,8 +308,7 @@ static int ck804xrom_init_one(struct pci_dev *pdev,
out:
/* Free any left over map structures */
if (map)
kfree(map);
kfree(map);
/* See if I have any map structures */
if (list_empty(&window->maps)) {

View File

@ -1,123 +0,0 @@
/*
* D-Box 2 flash driver
*/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <asm/io.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
#include <linux/mtd/partitions.h>
#include <linux/errno.h>
/* partition_info gives details on the logical partitions that the split the
* single flash device into. If the size if zero we use up to the end of the
* device. */
static struct mtd_partition partition_info[]= {
{
.name = "BR bootloader",
.size = 128 * 1024,
.offset = 0,
.mask_flags = MTD_WRITEABLE
},
{
.name = "FLFS (U-Boot)",
.size = 128 * 1024,
.offset = MTDPART_OFS_APPEND,
.mask_flags = 0
},
{
.name = "Root (SquashFS)",
.size = 7040 * 1024,
.offset = MTDPART_OFS_APPEND,
.mask_flags = 0
},
{
.name = "var (JFFS2)",
.size = 896 * 1024,
.offset = MTDPART_OFS_APPEND,
.mask_flags = 0
},
{
.name = "Flash without bootloader",
.size = MTDPART_SIZ_FULL,
.offset = 128 * 1024,
.mask_flags = 0
},
{
.name = "Complete Flash",
.size = MTDPART_SIZ_FULL,
.offset = 0,
.mask_flags = MTD_WRITEABLE
}
};
#define NUM_PARTITIONS ARRAY_SIZE(partition_info)
#define WINDOW_ADDR 0x10000000
#define WINDOW_SIZE 0x800000
static struct mtd_info *mymtd;
struct map_info dbox2_flash_map = {
.name = "D-Box 2 flash memory",
.size = WINDOW_SIZE,
.bankwidth = 4,
.phys = WINDOW_ADDR,
};
static int __init init_dbox2_flash(void)
{
printk(KERN_NOTICE "D-Box 2 flash driver (size->0x%X mem->0x%X)\n", WINDOW_SIZE, WINDOW_ADDR);
dbox2_flash_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE);
if (!dbox2_flash_map.virt) {
printk("Failed to ioremap\n");
return -EIO;
}
simple_map_init(&dbox2_flash_map);
// Probe for dual Intel 28F320 or dual AMD
mymtd = do_map_probe("cfi_probe", &dbox2_flash_map);
if (!mymtd) {
// Probe for single Intel 28F640
dbox2_flash_map.bankwidth = 2;
mymtd = do_map_probe("cfi_probe", &dbox2_flash_map);
}
if (mymtd) {
mymtd->owner = THIS_MODULE;
/* Create MTD devices for each partition. */
mtd_device_register(mymtd, partition_info, NUM_PARTITIONS);
return 0;
}
iounmap((void *)dbox2_flash_map.virt);
return -ENXIO;
}
static void __exit cleanup_dbox2_flash(void)
{
if (mymtd) {
mtd_device_unregister(mymtd);
map_destroy(mymtd);
}
if (dbox2_flash_map.virt) {
iounmap((void *)dbox2_flash_map.virt);
dbox2_flash_map.virt = 0;
}
}
module_init(init_dbox2_flash);
module_exit(cleanup_dbox2_flash);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Kári Davíðsson <kd@flaga.is>, Bastian Blank <waldi@tuxbox.org>, Alexander Wild <wild@te-elektronik.com>");
MODULE_DESCRIPTION("MTD map driver for D-Box 2 board");

View File

@ -143,9 +143,8 @@ static struct map_info dc21285_map = {
.copy_from = dc21285_copy_from,
};
/* Partition stuff */
static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
static const char * const probes[] = { "RedBoot", "cmdlinepart", NULL };
static int __init init_dc21285(void)
{

View File

@ -1,496 +0,0 @@
/* dilnetpc.c -- MTD map driver for SSV DIL/Net PC Boards "DNP" and "ADNP"
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
* The DIL/Net PC is a tiny embedded PC board made by SSV Embedded Systems
* featuring the AMD Elan SC410 processor. There are two variants of this
* board: DNP/1486 and ADNP/1486. The DNP version has 2 megs of flash
* ROM (Intel 28F016S3) and 8 megs of DRAM, the ADNP version has 4 megs
* flash and 16 megs of RAM.
* For details, see http://www.ssv-embedded.de/ssv/pc104/p169.htm
* and http://www.ssv-embedded.de/ssv/pc104/p170.htm
*/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/string.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/concat.h>
#include <asm/io.h>
/*
** The DIL/NetPC keeps its BIOS in two distinct flash blocks.
** Destroying any of these blocks transforms the DNPC into
** a paperweight (albeit not a very useful one, considering
** it only weighs a few grams).
**
** Therefore, the BIOS blocks must never be erased or written to
** except by people who know exactly what they are doing (e.g.
** to install a BIOS update). These partitions are marked read-only
** by default, but can be made read/write by undefining
** DNPC_BIOS_BLOCKS_WRITEPROTECTED:
*/
#define DNPC_BIOS_BLOCKS_WRITEPROTECTED
/*
** The ID string (in ROM) is checked to determine whether we
** are running on a DNP/1486 or ADNP/1486
*/
#define BIOSID_BASE 0x000fe100
#define ID_DNPC "DNP1486"
#define ID_ADNP "ADNP1486"
/*
** Address where the flash should appear in CPU space
*/
#define FLASH_BASE 0x2000000
/*
** Chip Setup and Control (CSC) indexed register space
*/
#define CSC_INDEX 0x22
#define CSC_DATA 0x23
#define CSC_MMSWAR 0x30 /* MMS window C-F attributes register */
#define CSC_MMSWDSR 0x31 /* MMS window C-F device select register */
#define CSC_RBWR 0xa7 /* GPIO Read-Back/Write Register B */
#define CSC_CR 0xd0 /* internal I/O device disable/Echo */
/* Z-bus/configuration register */
#define CSC_PCCMDCR 0xf1 /* PC card mode and DMA control register */
/*
** PC Card indexed register space:
*/
#define PCC_INDEX 0x3e0
#define PCC_DATA 0x3e1
#define PCC_AWER_B 0x46 /* Socket B Address Window enable register */
#define PCC_MWSAR_1_Lo 0x58 /* memory window 1 start address low register */
#define PCC_MWSAR_1_Hi 0x59 /* memory window 1 start address high register */
#define PCC_MWEAR_1_Lo 0x5A /* memory window 1 stop address low register */
#define PCC_MWEAR_1_Hi 0x5B /* memory window 1 stop address high register */
#define PCC_MWAOR_1_Lo 0x5C /* memory window 1 address offset low register */
#define PCC_MWAOR_1_Hi 0x5D /* memory window 1 address offset high register */
/*
** Access to SC4x0's Chip Setup and Control (CSC)
** and PC Card (PCC) indexed registers:
*/
static inline void setcsc(int reg, unsigned char data)
{
outb(reg, CSC_INDEX);
outb(data, CSC_DATA);
}
static inline unsigned char getcsc(int reg)
{
outb(reg, CSC_INDEX);
return(inb(CSC_DATA));
}
static inline void setpcc(int reg, unsigned char data)
{
outb(reg, PCC_INDEX);
outb(data, PCC_DATA);
}
static inline unsigned char getpcc(int reg)
{
outb(reg, PCC_INDEX);
return(inb(PCC_DATA));
}
/*
************************************************************
** Enable access to DIL/NetPC's flash by mapping it into
** the SC4x0's MMS Window C.
************************************************************
*/
static void dnpc_map_flash(unsigned long flash_base, unsigned long flash_size)
{
unsigned long flash_end = flash_base + flash_size - 1;
/*
** enable setup of MMS windows C-F:
*/
/* - enable PC Card indexed register space */
setcsc(CSC_CR, getcsc(CSC_CR) | 0x2);
/* - set PC Card controller to operate in standard mode */
setcsc(CSC_PCCMDCR, getcsc(CSC_PCCMDCR) & ~1);
/*
** Program base address and end address of window
** where the flash ROM should appear in CPU address space
*/
setpcc(PCC_MWSAR_1_Lo, (flash_base >> 12) & 0xff);
setpcc(PCC_MWSAR_1_Hi, (flash_base >> 20) & 0x3f);
setpcc(PCC_MWEAR_1_Lo, (flash_end >> 12) & 0xff);
setpcc(PCC_MWEAR_1_Hi, (flash_end >> 20) & 0x3f);
/* program offset of first flash location to appear in this window (0) */
setpcc(PCC_MWAOR_1_Lo, ((0 - flash_base) >> 12) & 0xff);
setpcc(PCC_MWAOR_1_Hi, ((0 - flash_base)>> 20) & 0x3f);
/* set attributes for MMS window C: non-cacheable, write-enabled */
setcsc(CSC_MMSWAR, getcsc(CSC_MMSWAR) & ~0x11);
/* select physical device ROMCS0 (i.e. flash) for MMS Window C */
setcsc(CSC_MMSWDSR, getcsc(CSC_MMSWDSR) & ~0x03);
/* enable memory window 1 */
setpcc(PCC_AWER_B, getpcc(PCC_AWER_B) | 0x02);
/* now disable PC Card indexed register space again */
setcsc(CSC_CR, getcsc(CSC_CR) & ~0x2);
}
/*
************************************************************
** Disable access to DIL/NetPC's flash by mapping it into
** the SC4x0's MMS Window C.
************************************************************
*/
static void dnpc_unmap_flash(void)
{
/* - enable PC Card indexed register space */
setcsc(CSC_CR, getcsc(CSC_CR) | 0x2);
/* disable memory window 1 */
setpcc(PCC_AWER_B, getpcc(PCC_AWER_B) & ~0x02);
/* now disable PC Card indexed register space again */
setcsc(CSC_CR, getcsc(CSC_CR) & ~0x2);
}
/*
************************************************************
** Enable/Disable VPP to write to flash
************************************************************
*/
static DEFINE_SPINLOCK(dnpc_spin);
static int vpp_counter = 0;
/*
** This is what has to be done for the DNP board ..
*/
static void dnp_set_vpp(struct map_info *not_used, int on)
{
spin_lock_irq(&dnpc_spin);
if (on)
{
if(++vpp_counter == 1)
setcsc(CSC_RBWR, getcsc(CSC_RBWR) & ~0x4);
}
else
{
if(--vpp_counter == 0)
setcsc(CSC_RBWR, getcsc(CSC_RBWR) | 0x4);
else
BUG_ON(vpp_counter < 0);
}
spin_unlock_irq(&dnpc_spin);
}
/*
** .. and this the ADNP version:
*/
static void adnp_set_vpp(struct map_info *not_used, int on)
{
spin_lock_irq(&dnpc_spin);
if (on)
{
if(++vpp_counter == 1)
setcsc(CSC_RBWR, getcsc(CSC_RBWR) & ~0x8);
}
else
{
if(--vpp_counter == 0)
setcsc(CSC_RBWR, getcsc(CSC_RBWR) | 0x8);
else
BUG_ON(vpp_counter < 0);
}
spin_unlock_irq(&dnpc_spin);
}
#define DNP_WINDOW_SIZE 0x00200000 /* DNP flash size is 2MiB */
#define ADNP_WINDOW_SIZE 0x00400000 /* ADNP flash size is 4MiB */
#define WINDOW_ADDR FLASH_BASE
static struct map_info dnpc_map = {
.name = "ADNP Flash Bank",
.size = ADNP_WINDOW_SIZE,
.bankwidth = 1,
.set_vpp = adnp_set_vpp,
.phys = WINDOW_ADDR
};
/*
** The layout of the flash is somewhat "strange":
**
** 1. 960 KiB (15 blocks) : Space for ROM Bootloader and user data
** 2. 64 KiB (1 block) : System BIOS
** 3. 960 KiB (15 blocks) : User Data (DNP model) or
** 3. 3008 KiB (47 blocks) : User Data (ADNP model)
** 4. 64 KiB (1 block) : System BIOS Entry
*/
static struct mtd_partition partition_info[]=
{
{
.name = "ADNP boot",
.offset = 0,
.size = 0xf0000,
},
{
.name = "ADNP system BIOS",
.offset = MTDPART_OFS_NXTBLK,
.size = 0x10000,
#ifdef DNPC_BIOS_BLOCKS_WRITEPROTECTED
.mask_flags = MTD_WRITEABLE,
#endif
},
{
.name = "ADNP file system",
.offset = MTDPART_OFS_NXTBLK,
.size = 0x2f0000,
},
{
.name = "ADNP system BIOS entry",
.offset = MTDPART_OFS_NXTBLK,
.size = MTDPART_SIZ_FULL,
#ifdef DNPC_BIOS_BLOCKS_WRITEPROTECTED
.mask_flags = MTD_WRITEABLE,
#endif
},
};
#define NUM_PARTITIONS ARRAY_SIZE(partition_info)
static struct mtd_info *mymtd;
static struct mtd_info *lowlvl_parts[NUM_PARTITIONS];
static struct mtd_info *merged_mtd;
/*
** "Highlevel" partition info:
**
** Using the MTD concat layer, we can re-arrange partitions to our
** liking: we construct a virtual MTD device by concatenating the
** partitions, specifying the sequence such that the boot block
** is immediately followed by the filesystem block (i.e. the stupid
** system BIOS block is mapped to a different place). When re-partitioning
** this concatenated MTD device, we can set the boot block size to
** an arbitrary (though erase block aligned) value i.e. not one that
** is dictated by the flash's physical layout. We can thus set the
** boot block to be e.g. 64 KB (which is fully sufficient if we want
** to boot an etherboot image) or to -say- 1.5 MB if we want to boot
** a large kernel image. In all cases, the remainder of the flash
** is available as file system space.
*/
static struct mtd_partition higlvl_partition_info[]=
{
{
.name = "ADNP boot block",
.offset = 0,
.size = CONFIG_MTD_DILNETPC_BOOTSIZE,
},
{
.name = "ADNP file system space",
.offset = MTDPART_OFS_NXTBLK,
.size = ADNP_WINDOW_SIZE-CONFIG_MTD_DILNETPC_BOOTSIZE-0x20000,
},
{
.name = "ADNP system BIOS + BIOS Entry",
.offset = MTDPART_OFS_NXTBLK,
.size = MTDPART_SIZ_FULL,
#ifdef DNPC_BIOS_BLOCKS_WRITEPROTECTED
.mask_flags = MTD_WRITEABLE,
#endif
},
};
#define NUM_HIGHLVL_PARTITIONS ARRAY_SIZE(higlvl_partition_info)
static int dnp_adnp_probe(void)
{
char *biosid, rc = -1;
biosid = (char*)ioremap(BIOSID_BASE, 16);
if(biosid)
{
if(!strcmp(biosid, ID_DNPC))
rc = 1; /* this is a DNPC */
else if(!strcmp(biosid, ID_ADNP))
rc = 0; /* this is a ADNPC */
}
iounmap((void *)biosid);
return(rc);
}
static int __init init_dnpc(void)
{
int is_dnp;
/*
** determine hardware (DNP/ADNP/invalid)
*/
if((is_dnp = dnp_adnp_probe()) < 0)
return -ENXIO;
/*
** Things are set up for ADNP by default
** -> modify all that needs to be different for DNP
*/
if(is_dnp)
{ /*
** Adjust window size, select correct set_vpp function.
** The partitioning scheme is identical on both DNP
** and ADNP except for the size of the third partition.
*/
int i;
dnpc_map.size = DNP_WINDOW_SIZE;
dnpc_map.set_vpp = dnp_set_vpp;
partition_info[2].size = 0xf0000;
/*
** increment all string pointers so the leading 'A' gets skipped,
** thus turning all occurrences of "ADNP ..." into "DNP ..."
*/
++dnpc_map.name;
for(i = 0; i < NUM_PARTITIONS; i++)
++partition_info[i].name;
higlvl_partition_info[1].size = DNP_WINDOW_SIZE -
CONFIG_MTD_DILNETPC_BOOTSIZE - 0x20000;
for(i = 0; i < NUM_HIGHLVL_PARTITIONS; i++)
++higlvl_partition_info[i].name;
}
printk(KERN_NOTICE "DIL/Net %s flash: 0x%lx at 0x%llx\n",
is_dnp ? "DNPC" : "ADNP", dnpc_map.size, (unsigned long long)dnpc_map.phys);
dnpc_map.virt = ioremap_nocache(dnpc_map.phys, dnpc_map.size);
dnpc_map_flash(dnpc_map.phys, dnpc_map.size);
if (!dnpc_map.virt) {
printk("Failed to ioremap_nocache\n");
return -EIO;
}
simple_map_init(&dnpc_map);
printk("FLASH virtual address: 0x%p\n", dnpc_map.virt);
mymtd = do_map_probe("jedec_probe", &dnpc_map);
if (!mymtd)
mymtd = do_map_probe("cfi_probe", &dnpc_map);
/*
** If flash probes fail, try to make flashes accessible
** at least as ROM. Ajust erasesize in this case since
** the default one (128M) will break our partitioning
*/
if (!mymtd)
if((mymtd = do_map_probe("map_rom", &dnpc_map)))
mymtd->erasesize = 0x10000;
if (!mymtd) {
iounmap(dnpc_map.virt);
return -ENXIO;
}
mymtd->owner = THIS_MODULE;
/*
** Supply pointers to lowlvl_parts[] array to add_mtd_partitions()
** -> add_mtd_partitions() will _not_ register MTD devices for
** the partitions, but will instead store pointers to the MTD
** objects it creates into our lowlvl_parts[] array.
** NOTE: we arrange the pointers such that the sequence of the
** partitions gets re-arranged: partition #2 follows
** partition #0.
*/
partition_info[0].mtdp = &lowlvl_parts[0];
partition_info[1].mtdp = &lowlvl_parts[2];
partition_info[2].mtdp = &lowlvl_parts[1];
partition_info[3].mtdp = &lowlvl_parts[3];
mtd_device_register(mymtd, partition_info, NUM_PARTITIONS);
/*
** now create a virtual MTD device by concatenating the for partitions
** (in the sequence given by the lowlvl_parts[] array.
*/
merged_mtd = mtd_concat_create(lowlvl_parts, NUM_PARTITIONS, "(A)DNP Flash Concatenated");
if(merged_mtd)
{ /*
** now partition the new device the way we want it. This time,
** we do not supply mtd pointers in higlvl_partition_info, so
** add_mtd_partitions() will register the devices.
*/
mtd_device_register(merged_mtd, higlvl_partition_info,
NUM_HIGHLVL_PARTITIONS);
}
return 0;
}
static void __exit cleanup_dnpc(void)
{
if(merged_mtd) {
mtd_device_unregister(merged_mtd);
mtd_concat_destroy(merged_mtd);
}
if (mymtd) {
mtd_device_unregister(mymtd);
map_destroy(mymtd);
}
if (dnpc_map.virt) {
iounmap(dnpc_map.virt);
dnpc_unmap_flash();
dnpc_map.virt = NULL;
}
}
module_init(init_dnpc);
module_exit(cleanup_dnpc);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Sysgo Real-Time Solutions GmbH");
MODULE_DESCRIPTION("MTD map driver for SSV DIL/NetPC DNP & ADNP");

View File

@ -1,146 +0,0 @@
/*
* drivers/mtd/maps/dmv182.c
*
* Flash map driver for the Dy4 SVME182 board
*
* Copyright 2003-2004, TimeSys Corporation
*
* Based on the SVME181 flash map, by Tom Nelson, Dot4, Inc. for TimeSys Corp.
*
* 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.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <asm/io.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
#include <linux/mtd/partitions.h>
#include <linux/errno.h>
/*
* This driver currently handles only the 16MiB user flash bank 1 on the
* board. It does not provide access to bank 0 (contains the Dy4 FFW), bank 2
* (VxWorks boot), or the optional 48MiB expansion flash.
*
* scott.wood@timesys.com: On the newer boards with 128MiB flash, it
* now supports the first 96MiB (the boot flash bank containing FFW
* is excluded). The VxWorks loader is in partition 1.
*/
#define FLASH_BASE_ADDR 0xf0000000
#define FLASH_BANK_SIZE (128*1024*1024)
MODULE_AUTHOR("Scott Wood, TimeSys Corporation <scott.wood@timesys.com>");
MODULE_DESCRIPTION("User-programmable flash device on the Dy4 SVME182 board");
MODULE_LICENSE("GPL");
static struct map_info svme182_map = {
.name = "Dy4 SVME182",
.bankwidth = 32,
.size = 128 * 1024 * 1024
};
#define BOOTIMAGE_PART_SIZE ((6*1024*1024)-RESERVED_PART_SIZE)
// Allow 6MiB for the kernel
#define NEW_BOOTIMAGE_PART_SIZE (6 * 1024 * 1024)
// Allow 1MiB for the bootloader
#define NEW_BOOTLOADER_PART_SIZE (1024 * 1024)
// Use the remaining 9MiB at the end of flash for the RFS
#define NEW_RFS_PART_SIZE (0x01000000 - NEW_BOOTLOADER_PART_SIZE - \
NEW_BOOTIMAGE_PART_SIZE)
static struct mtd_partition svme182_partitions[] = {
// The Lower PABS is only 128KiB, but the partition code doesn't
// like partitions that don't end on the largest erase block
// size of the device, even if all of the erase blocks in the
// partition are small ones. The hardware should prevent
// writes to the actual PABS areas.
{
name: "Lower PABS and CPU 0 bootloader or kernel",
size: 6*1024*1024,
offset: 0,
},
{
name: "Root Filesystem",
size: 10*1024*1024,
offset: MTDPART_OFS_NXTBLK
},
{
name: "CPU1 Bootloader",
size: 1024*1024,
offset: MTDPART_OFS_NXTBLK,
},
{
name: "Extra",
size: 110*1024*1024,
offset: MTDPART_OFS_NXTBLK
},
{
name: "Foundation Firmware and Upper PABS",
size: 1024*1024,
offset: MTDPART_OFS_NXTBLK,
mask_flags: MTD_WRITEABLE // read-only
}
};
static struct mtd_info *this_mtd;
static int __init init_svme182(void)
{
struct mtd_partition *partitions;
int num_parts = ARRAY_SIZE(svme182_partitions);
partitions = svme182_partitions;
svme182_map.virt = ioremap(FLASH_BASE_ADDR, svme182_map.size);
if (svme182_map.virt == 0) {
printk("Failed to ioremap FLASH memory area.\n");
return -EIO;
}
simple_map_init(&svme182_map);
this_mtd = do_map_probe("cfi_probe", &svme182_map);
if (!this_mtd)
{
iounmap((void *)svme182_map.virt);
return -ENXIO;
}
printk(KERN_NOTICE "SVME182 flash device: %dMiB at 0x%08x\n",
this_mtd->size >> 20, FLASH_BASE_ADDR);
this_mtd->owner = THIS_MODULE;
mtd_device_register(this_mtd, partitions, num_parts);
return 0;
}
static void __exit cleanup_svme182(void)
{
if (this_mtd)
{
mtd_device_unregister(this_mtd);
map_destroy(this_mtd);
}
if (svme182_map.virt)
{
iounmap((void *)svme182_map.virt);
svme182_map.virt = 0;
}
return;
}
module_init(init_svme182);
module_exit(cleanup_svme182);

View File

@ -157,7 +157,8 @@ static void gf_copy_to(struct map_info *map, unsigned long to,
memcpy_toio(map->virt + (to % state->win_size), from, len);
}
static const char *part_probe_types[] = { "cmdlinepart", "RedBoot", NULL };
static const char * const part_probe_types[] = {
"cmdlinepart", "RedBoot", NULL };
/**
* gpio_flash_probe() - setup a mapping for a GPIO assisted flash

View File

@ -1,120 +0,0 @@
/*
* Flash memory access on Hynix GMS30C7201/HMS30C7202 based
* evaluation boards
*
* (C) 2002 Jungjun Kim <jungjun.kim@hynix.com>
* 2003 Thomas Gleixner <tglx@linutronix.de>
*/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
#include <linux/mtd/partitions.h>
#include <mach/hardware.h>
#include <asm/io.h>
static struct mtd_info *mymtd;
static struct map_info h720x_map = {
.name = "H720X",
.bankwidth = 4,
.size = H720X_FLASH_SIZE,
.phys = H720X_FLASH_PHYS,
};
static struct mtd_partition h720x_partitions[] = {
{
.name = "ArMon",
.size = 0x00080000,
.offset = 0,
.mask_flags = MTD_WRITEABLE
},{
.name = "Env",
.size = 0x00040000,
.offset = 0x00080000,
.mask_flags = MTD_WRITEABLE
},{
.name = "Kernel",
.size = 0x00180000,
.offset = 0x000c0000,
.mask_flags = MTD_WRITEABLE
},{
.name = "Ramdisk",
.size = 0x00400000,
.offset = 0x00240000,
.mask_flags = MTD_WRITEABLE
},{
.name = "jffs2",
.size = MTDPART_SIZ_FULL,
.offset = MTDPART_OFS_APPEND
}
};
#define NUM_PARTITIONS ARRAY_SIZE(h720x_partitions)
/*
* Initialize FLASH support
*/
static int __init h720x_mtd_init(void)
{
h720x_map.virt = ioremap(h720x_map.phys, h720x_map.size);
if (!h720x_map.virt) {
printk(KERN_ERR "H720x-MTD: ioremap failed\n");
return -EIO;
}
simple_map_init(&h720x_map);
// Probe for flash bankwidth 4
printk (KERN_INFO "H720x-MTD probing 32bit FLASH\n");
mymtd = do_map_probe("cfi_probe", &h720x_map);
if (!mymtd) {
printk (KERN_INFO "H720x-MTD probing 16bit FLASH\n");
// Probe for bankwidth 2
h720x_map.bankwidth = 2;
mymtd = do_map_probe("cfi_probe", &h720x_map);
}
if (mymtd) {
mymtd->owner = THIS_MODULE;
mtd_device_parse_register(mymtd, NULL, NULL,
h720x_partitions, NUM_PARTITIONS);
return 0;
}
iounmap((void *)h720x_map.virt);
return -ENXIO;
}
/*
* Cleanup
*/
static void __exit h720x_mtd_cleanup(void)
{
if (mymtd) {
mtd_device_unregister(mymtd);
map_destroy(mymtd);
}
if (h720x_map.virt) {
iounmap((void *)h720x_map.virt);
h720x_map.virt = 0;
}
}
module_init(h720x_mtd_init);
module_exit(h720x_mtd_cleanup);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Thomas Gleixner <tglx@linutronix.de>");
MODULE_DESCRIPTION("MTD map driver for Hynix evaluation boards");

View File

@ -24,14 +24,12 @@
#define NUM_FLASHBANKS 2
#define BUSWIDTH 4
/* can be { "cfi_probe", "jedec_probe", "map_rom", NULL } */
#define PROBETYPES { "jedec_probe", NULL }
#define MSG_PREFIX "impA7:" /* prefix for our printk()'s */
#define MTDID "impa7-%d" /* for mtdparts= partitioning */
static struct mtd_info *impa7_mtd[NUM_FLASHBANKS];
static const char * const rom_probe_types[] = { "jedec_probe", NULL };
static struct map_info impa7_map[NUM_FLASHBANKS] = {
{
@ -60,8 +58,7 @@ static struct mtd_partition partitions[] =
static int __init init_impa7(void)
{
static const char *rom_probe_types[] = PROBETYPES;
const char **type;
const char * const *type;
int i;
static struct { u_long addr; u_long size; } pt[NUM_FLASHBANKS] = {
{ WINDOW_ADDR0, WINDOW_SIZE0 },

View File

@ -82,9 +82,9 @@ static void vr_nor_destroy_mtd_setup(struct vr_nor_mtd *p)
static int vr_nor_mtd_setup(struct vr_nor_mtd *p)
{
static const char *probe_types[] =
static const char * const probe_types[] =
{ "cfi_probe", "jedec_probe", NULL };
const char **type;
const char * const *type;
for (type = probe_types; !p->info && *type; type++)
p->info = do_map_probe(*type, &p->map);

View File

@ -1,253 +0,0 @@
/*
* drivers/mtd/maps/ixp2000.c
*
* Mapping for the Intel XScale IXP2000 based systems
*
* Copyright (C) 2002 Intel Corp.
* Copyright (C) 2003-2004 MontaVista Software, Inc.
*
* Original Author: Naeem M Afzal <naeem.m.afzal@intel.com>
* Maintainer: Deepak Saxena <dsaxena@plexity.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
#include <linux/mtd/partitions.h>
#include <asm/io.h>
#include <mach/hardware.h>
#include <asm/mach/flash.h>
#include <linux/reboot.h>
struct ixp2000_flash_info {
struct mtd_info *mtd;
struct map_info map;
struct resource *res;
};
static inline unsigned long flash_bank_setup(struct map_info *map, unsigned long ofs)
{
unsigned long (*set_bank)(unsigned long) =
(unsigned long(*)(unsigned long))map->map_priv_2;
return (set_bank ? set_bank(ofs) : ofs);
}
#ifdef __ARMEB__
/*
* Rev A0 and A1 of IXP2400 silicon have a broken addressing unit which
* causes the lower address bits to be XORed with 0x11 on 8 bit accesses
* and XORed with 0x10 on 16 bit accesses. See the spec update, erratum 44.
*/
static int erratum44_workaround = 0;
static inline unsigned long address_fix8_write(unsigned long addr)
{
if (erratum44_workaround) {
return (addr ^ 3);
}
return addr;
}
#else
#define address_fix8_write(x) (x)
#endif
static map_word ixp2000_flash_read8(struct map_info *map, unsigned long ofs)
{
map_word val;
val.x[0] = *((u8 *)(map->map_priv_1 + flash_bank_setup(map, ofs)));
return val;
}
/*
* We can't use the standard memcpy due to the broken SlowPort
* address translation on rev A0 and A1 silicon and the fact that
* we have banked flash.
*/
static void ixp2000_flash_copy_from(struct map_info *map, void *to,
unsigned long from, ssize_t len)
{
from = flash_bank_setup(map, from);
while(len--)
*(__u8 *) to++ = *(__u8 *)(map->map_priv_1 + from++);
}
static void ixp2000_flash_write8(struct map_info *map, map_word d, unsigned long ofs)
{
*(__u8 *) (address_fix8_write(map->map_priv_1 +
flash_bank_setup(map, ofs))) = d.x[0];
}
static void ixp2000_flash_copy_to(struct map_info *map, unsigned long to,
const void *from, ssize_t len)
{
to = flash_bank_setup(map, to);
while(len--) {
unsigned long tmp = address_fix8_write(map->map_priv_1 + to++);
*(__u8 *)(tmp) = *(__u8 *)(from++);
}
}
static int ixp2000_flash_remove(struct platform_device *dev)
{
struct flash_platform_data *plat = dev->dev.platform_data;
struct ixp2000_flash_info *info = platform_get_drvdata(dev);
platform_set_drvdata(dev, NULL);
if(!info)
return 0;
if (info->mtd) {
mtd_device_unregister(info->mtd);
map_destroy(info->mtd);
}
if (info->map.map_priv_1)
iounmap((void *) info->map.map_priv_1);
if (info->res) {
release_resource(info->res);
kfree(info->res);
}
if (plat->exit)
plat->exit();
return 0;
}
static int ixp2000_flash_probe(struct platform_device *dev)
{
static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
struct ixp2000_flash_data *ixp_data = dev->dev.platform_data;
struct flash_platform_data *plat;
struct ixp2000_flash_info *info;
unsigned long window_size;
int err = -1;
if (!ixp_data)
return -ENODEV;
plat = ixp_data->platform_data;
if (!plat)
return -ENODEV;
window_size = resource_size(dev->resource);
dev_info(&dev->dev, "Probe of IXP2000 flash(%d banks x %dMiB)\n",
ixp_data->nr_banks, ((u32)window_size >> 20));
if (plat->width != 1) {
dev_err(&dev->dev, "IXP2000 MTD map only supports 8-bit mode, asking for %d\n",
plat->width * 8);
return -EIO;
}
info = kzalloc(sizeof(struct ixp2000_flash_info), GFP_KERNEL);
if(!info) {
err = -ENOMEM;
goto Error;
}
platform_set_drvdata(dev, info);
/*
* Tell the MTD layer we're not 1:1 mapped so that it does
* not attempt to do a direct access on us.
*/
info->map.phys = NO_XIP;
info->map.size = ixp_data->nr_banks * window_size;
info->map.bankwidth = 1;
/*
* map_priv_2 is used to store a ptr to the bank_setup routine
*/
info->map.map_priv_2 = (unsigned long) ixp_data->bank_setup;
info->map.name = dev_name(&dev->dev);
info->map.read = ixp2000_flash_read8;
info->map.write = ixp2000_flash_write8;
info->map.copy_from = ixp2000_flash_copy_from;
info->map.copy_to = ixp2000_flash_copy_to;
info->res = request_mem_region(dev->resource->start,
resource_size(dev->resource),
dev_name(&dev->dev));
if (!info->res) {
dev_err(&dev->dev, "Could not reserve memory region\n");
err = -ENOMEM;
goto Error;
}
info->map.map_priv_1 =
(unsigned long)ioremap(dev->resource->start,
resource_size(dev->resource));
if (!info->map.map_priv_1) {
dev_err(&dev->dev, "Failed to ioremap flash region\n");
err = -EIO;
goto Error;
}
#if defined(__ARMEB__)
/*
* Enable erratum 44 workaround for NPUs with broken slowport
*/
erratum44_workaround = ixp2000_has_broken_slowport();
dev_info(&dev->dev, "Erratum 44 workaround %s\n",
erratum44_workaround ? "enabled" : "disabled");
#endif
info->mtd = do_map_probe(plat->map_name, &info->map);
if (!info->mtd) {
dev_err(&dev->dev, "map_probe failed\n");
err = -ENXIO;
goto Error;
}
info->mtd->owner = THIS_MODULE;
err = mtd_device_parse_register(info->mtd, probes, NULL, NULL, 0);
if (err)
goto Error;
return 0;
Error:
ixp2000_flash_remove(dev);
return err;
}
static struct platform_driver ixp2000_flash_driver = {
.probe = ixp2000_flash_probe,
.remove = ixp2000_flash_remove,
.driver = {
.name = "IXP2000-Flash",
.owner = THIS_MODULE,
},
};
module_platform_driver(ixp2000_flash_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net>");
MODULE_ALIAS("platform:IXP2000-Flash");

View File

@ -148,7 +148,7 @@ struct ixp4xx_flash_info {
struct resource *res;
};
static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
static const char * const probes[] = { "RedBoot", "cmdlinepart", NULL };
static int ixp4xx_flash_remove(struct platform_device *dev)
{

View File

@ -46,8 +46,7 @@ struct ltq_mtd {
};
static const char ltq_map_name[] = "ltq_nor";
static const char *ltq_probe_types[] = {
"cmdlinepart", "ofpart", NULL };
static const char * const ltq_probe_types[] = { "cmdlinepart", "ofpart", NULL };
static map_word
ltq_read16(struct map_info *map, unsigned long adr)

View File

@ -1,98 +0,0 @@
/*
* Handle mapping of the flash on MBX860 boards
*
* Author: Anton Todorov
* Copyright: (C) 2001 Emness Technology
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <asm/io.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
#include <linux/mtd/partitions.h>
#define WINDOW_ADDR 0xfe000000
#define WINDOW_SIZE 0x00200000
/* Flash / Partition sizing */
#define MAX_SIZE_KiB 8192
#define BOOT_PARTITION_SIZE_KiB 512
#define KERNEL_PARTITION_SIZE_KiB 5632
#define APP_PARTITION_SIZE_KiB 2048
#define NUM_PARTITIONS 3
/* partition_info gives details on the logical partitions that the split the
* single flash device into. If the size if zero we use up to the end of the
* device. */
static struct mtd_partition partition_info[]={
{ .name = "MBX flash BOOT partition",
.offset = 0,
.size = BOOT_PARTITION_SIZE_KiB*1024 },
{ .name = "MBX flash DATA partition",
.offset = BOOT_PARTITION_SIZE_KiB*1024,
.size = (KERNEL_PARTITION_SIZE_KiB)*1024 },
{ .name = "MBX flash APPLICATION partition",
.offset = (BOOT_PARTITION_SIZE_KiB+KERNEL_PARTITION_SIZE_KiB)*1024 }
};
static struct mtd_info *mymtd;
struct map_info mbx_map = {
.name = "MBX flash",
.size = WINDOW_SIZE,
.phys = WINDOW_ADDR,
.bankwidth = 4,
};
static int __init init_mbx(void)
{
printk(KERN_NOTICE "Motorola MBX flash device: 0x%x at 0x%x\n", WINDOW_SIZE*4, WINDOW_ADDR);
mbx_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE * 4);
if (!mbx_map.virt) {
printk("Failed to ioremap\n");
return -EIO;
}
simple_map_init(&mbx_map);
mymtd = do_map_probe("jedec_probe", &mbx_map);
if (mymtd) {
mymtd->owner = THIS_MODULE;
mtd_device_register(mymtd, NULL, 0);
mtd_device_register(mymtd, partition_info, NUM_PARTITIONS);
return 0;
}
iounmap((void *)mbx_map.virt);
return -ENXIO;
}
static void __exit cleanup_mbx(void)
{
if (mymtd) {
mtd_device_unregister(mymtd);
map_destroy(mymtd);
}
if (mbx_map.virt) {
iounmap((void *)mbx_map.virt);
mbx_map.virt = 0;
}
}
module_init(init_mbx);
module_exit(cleanup_mbx);
MODULE_AUTHOR("Anton Todorov <a.todorov@emness.com>");
MODULE_DESCRIPTION("MTD map driver for Motorola MBX860 board");
MODULE_LICENSE("GPL");

View File

@ -283,8 +283,7 @@ static int mtd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
if (err)
goto release;
/* tsk - do_map_probe should take const char * */
mtd = do_map_probe((char *)info->map_name, &map->map);
mtd = do_map_probe(info->map_name, &map->map);
err = -ENODEV;
if (!mtd)
goto release;

View File

@ -87,21 +87,18 @@ static void physmap_set_vpp(struct map_info *map, int state)
spin_unlock_irqrestore(&info->vpp_lock, flags);
}
static const char *rom_probe_types[] = {
"cfi_probe",
"jedec_probe",
"qinfo_probe",
"map_rom",
NULL };
static const char *part_probe_types[] = { "cmdlinepart", "RedBoot", "afs",
NULL };
static const char * const rom_probe_types[] = {
"cfi_probe", "jedec_probe", "qinfo_probe", "map_rom", NULL };
static const char * const part_probe_types[] = {
"cmdlinepart", "RedBoot", "afs", NULL };
static int physmap_flash_probe(struct platform_device *dev)
{
struct physmap_flash_data *physmap_data;
struct physmap_flash_info *info;
const char **probe_type;
const char **part_types;
const char * const *probe_type;
const char * const *part_types;
int err = 0;
int i;
int devices_found = 0;

View File

@ -71,6 +71,9 @@ static int of_flash_remove(struct platform_device *dev)
return 0;
}
static const char * const rom_probe_types[] = {
"cfi_probe", "jedec_probe", "map_rom" };
/* Helper function to handle probing of the obsolete "direct-mapped"
* compatible binding, which has an extra "probe-type" property
* describing the type of flash probe necessary. */
@ -80,8 +83,6 @@ static struct mtd_info *obsolete_probe(struct platform_device *dev,
struct device_node *dp = dev->dev.of_node;
const char *of_probe;
struct mtd_info *mtd;
static const char *rom_probe_types[]
= { "cfi_probe", "jedec_probe", "map_rom"};
int i;
dev_warn(&dev->dev, "Device tree uses obsolete \"direct-mapped\" "
@ -111,9 +112,10 @@ static struct mtd_info *obsolete_probe(struct platform_device *dev,
specifies the list of partition probers to use. If none is given then the
default is use. These take precedence over other device tree
information. */
static const char *part_probe_types_def[] = { "cmdlinepart", "RedBoot",
"ofpart", "ofoldpart", NULL };
static const char **of_get_probes(struct device_node *dp)
static const char * const part_probe_types_def[] = {
"cmdlinepart", "RedBoot", "ofpart", "ofoldpart", NULL };
static const char * const *of_get_probes(struct device_node *dp)
{
const char *cp;
int cplen;
@ -142,7 +144,7 @@ static const char **of_get_probes(struct device_node *dp)
return res;
}
static void of_free_probes(const char **probes)
static void of_free_probes(const char * const *probes)
{
if (probes != part_probe_types_def)
kfree(probes);
@ -151,7 +153,7 @@ static void of_free_probes(const char **probes)
static struct of_device_id of_flash_match[];
static int of_flash_probe(struct platform_device *dev)
{
const char **part_probe_types;
const char * const *part_probe_types;
const struct of_device_id *match;
struct device_node *dp = dev->dev.of_node;
struct resource res;

View File

@ -199,7 +199,7 @@ static int platram_probe(struct platform_device *pdev)
* supplied by the platform_data struct */
if (pdata->map_probes) {
const char **map_probes = pdata->map_probes;
const char * const *map_probes = pdata->map_probes;
for ( ; !info->mtd && *map_probes; map_probes++)
info->mtd = do_map_probe(*map_probes , &info->map);

View File

@ -45,9 +45,7 @@ struct pxa2xx_flash_info {
struct map_info map;
};
static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
static const char * const probes[] = { "RedBoot", "cmdlinepart", NULL };
static int pxa2xx_flash_probe(struct platform_device *pdev)
{

View File

@ -45,14 +45,15 @@ static int rbtx4939_flash_remove(struct platform_device *dev)
return 0;
}
static const char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL };
static const char * const rom_probe_types[] = {
"cfi_probe", "jedec_probe", NULL };
static int rbtx4939_flash_probe(struct platform_device *dev)
{
struct rbtx4939_flash_data *pdata;
struct rbtx4939_flash_info *info;
struct resource *res;
const char **probe_type;
const char * const *probe_type;
int err = 0;
unsigned long size;

View File

@ -1,64 +0,0 @@
/*
* Handle mapping of the flash on the RPX Lite and CLLF boards
*/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <asm/io.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
#define WINDOW_ADDR 0xfe000000
#define WINDOW_SIZE 0x800000
static struct mtd_info *mymtd;
static struct map_info rpxlite_map = {
.name = "RPX",
.size = WINDOW_SIZE,
.bankwidth = 4,
.phys = WINDOW_ADDR,
};
static int __init init_rpxlite(void)
{
printk(KERN_NOTICE "RPX Lite or CLLF flash device: %x at %x\n", WINDOW_SIZE*4, WINDOW_ADDR);
rpxlite_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE * 4);
if (!rpxlite_map.virt) {
printk("Failed to ioremap\n");
return -EIO;
}
simple_map_init(&rpxlite_map);
mymtd = do_map_probe("cfi_probe", &rpxlite_map);
if (mymtd) {
mymtd->owner = THIS_MODULE;
mtd_device_register(mymtd, NULL, 0);
return 0;
}
iounmap((void *)rpxlite_map.virt);
return -ENXIO;
}
static void __exit cleanup_rpxlite(void)
{
if (mymtd) {
mtd_device_unregister(mymtd);
map_destroy(mymtd);
}
if (rpxlite_map.virt) {
iounmap((void *)rpxlite_map.virt);
rpxlite_map.virt = 0;
}
}
module_init(init_rpxlite);
module_exit(cleanup_rpxlite);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Arnold Christensen <AKC@pel.dk>");
MODULE_DESCRIPTION("MTD map driver for RPX Lite and CLLF boards");

View File

@ -244,7 +244,7 @@ static struct sa_info *sa1100_setup_mtd(struct platform_device *pdev,
return ERR_PTR(ret);
}
static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL };
static const char * const part_probes[] = { "cmdlinepart", "RedBoot", NULL };
static int sa1100_mtd_probe(struct platform_device *pdev)
{

View File

@ -31,7 +31,7 @@ struct map_info soleng_flash_map = {
.bankwidth = 4,
};
static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
static const char * const probes[] = { "RedBoot", "cmdlinepart", NULL };
#ifdef CONFIG_MTD_SUPERH_RESERVE
static struct mtd_partition superh_se_partitions[] = {

View File

@ -1,249 +0,0 @@
/*
* Handle mapping of the flash memory access routines
* on TQM8xxL based devices.
*
* based on rpxlite.c
*
* Copyright(C) 2001 Kirk Lee <kirk@hpc.ee.ntu.edu.tw>
*
* This code is GPLed
*
*/
/*
* According to TQM8xxL hardware manual, TQM8xxL series have
* following flash memory organisations:
* | capacity | | chip type | | bank0 | | bank1 |
* 2MiB 512Kx16 2MiB 0
* 4MiB 1Mx16 4MiB 0
* 8MiB 1Mx16 4MiB 4MiB
* Thus, we choose CONFIG_MTD_CFI_I2 & CONFIG_MTD_CFI_B4 at
* kernel configuration.
*/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
#include <linux/mtd/partitions.h>
#include <asm/io.h>
#define FLASH_ADDR 0x40000000
#define FLASH_SIZE 0x00800000
#define FLASH_BANK_MAX 4
// trivial struct to describe partition information
struct mtd_part_def
{
int nums;
unsigned char *type;
struct mtd_partition* mtd_part;
};
//static struct mtd_info *mymtd;
static struct mtd_info* mtd_banks[FLASH_BANK_MAX];
static struct map_info* map_banks[FLASH_BANK_MAX];
static struct mtd_part_def part_banks[FLASH_BANK_MAX];
static unsigned long num_banks;
static void __iomem *start_scan_addr;
/*
* Here are partition information for all known TQM8xxL series devices.
* See include/linux/mtd/partitions.h for definition of the mtd_partition
* structure.
*
* The *_max_flash_size is the maximum possible mapped flash size which
* is not necessarily the actual flash size. It must correspond to the
* value specified in the mapping definition defined by the
* "struct map_desc *_io_desc" for the corresponding machine.
*/
/* Currently, TQM8xxL has up to 8MiB flash */
static unsigned long tqm8xxl_max_flash_size = 0x00800000;
/* partition definition for first flash bank
* (cf. "drivers/char/flash_config.c")
*/
static struct mtd_partition tqm8xxl_partitions[] = {
{
.name = "ppcboot",
.offset = 0x00000000,
.size = 0x00020000, /* 128KB */
.mask_flags = MTD_WRITEABLE, /* force read-only */
},
{
.name = "kernel", /* default kernel image */
.offset = 0x00020000,
.size = 0x000e0000,
.mask_flags = MTD_WRITEABLE, /* force read-only */
},
{
.name = "user",
.offset = 0x00100000,
.size = 0x00100000,
},
{
.name = "initrd",
.offset = 0x00200000,
.size = 0x00200000,
}
};
/* partition definition for second flash bank */
static struct mtd_partition tqm8xxl_fs_partitions[] = {
{
.name = "cramfs",
.offset = 0x00000000,
.size = 0x00200000,
},
{
.name = "jffs",
.offset = 0x00200000,
.size = 0x00200000,
//.size = MTDPART_SIZ_FULL,
}
};
static int __init init_tqm_mtd(void)
{
int idx = 0, ret = 0;
unsigned long flash_addr, flash_size, mtd_size = 0;
/* pointer to TQM8xxL board info data */
bd_t *bd = (bd_t *)__res;
flash_addr = bd->bi_flashstart;
flash_size = bd->bi_flashsize;
//request maximum flash size address space
start_scan_addr = ioremap(flash_addr, flash_size);
if (!start_scan_addr) {
printk(KERN_WARNING "%s:Failed to ioremap address:0x%x\n", __func__, flash_addr);
return -EIO;
}
for (idx = 0 ; idx < FLASH_BANK_MAX ; idx++) {
if(mtd_size >= flash_size)
break;
printk(KERN_INFO "%s: chip probing count %d\n", __func__, idx);
map_banks[idx] = kzalloc(sizeof(struct map_info), GFP_KERNEL);
if(map_banks[idx] == NULL) {
ret = -ENOMEM;
/* FIXME: What if some MTD devices were probed already? */
goto error_mem;
}
map_banks[idx]->name = kmalloc(16, GFP_KERNEL);
if (!map_banks[idx]->name) {
ret = -ENOMEM;
/* FIXME: What if some MTD devices were probed already? */
goto error_mem;
}
sprintf(map_banks[idx]->name, "TQM8xxL%d", idx);
map_banks[idx]->size = flash_size;
map_banks[idx]->bankwidth = 4;
simple_map_init(map_banks[idx]);
map_banks[idx]->virt = start_scan_addr;
map_banks[idx]->phys = flash_addr;
/* FIXME: This looks utterly bogus, but I'm trying to
preserve the behaviour of the original (shown here)...
map_banks[idx]->map_priv_1 =
start_scan_addr + ((idx > 0) ?
(mtd_banks[idx-1] ? mtd_banks[idx-1]->size : 0) : 0);
*/
if (idx && mtd_banks[idx-1]) {
map_banks[idx]->virt += mtd_banks[idx-1]->size;
map_banks[idx]->phys += mtd_banks[idx-1]->size;
}
//start to probe flash chips
mtd_banks[idx] = do_map_probe("cfi_probe", map_banks[idx]);
if (mtd_banks[idx]) {
mtd_banks[idx]->owner = THIS_MODULE;
mtd_size += mtd_banks[idx]->size;
num_banks++;
printk(KERN_INFO "%s: bank%d, name:%s, size:%dbytes \n", __func__, num_banks,
mtd_banks[idx]->name, mtd_banks[idx]->size);
}
}
/* no supported flash chips found */
if (!num_banks) {
printk(KERN_NOTICE "TQM8xxL: No support flash chips found!\n");
ret = -ENXIO;
goto error_mem;
}
/*
* Select Static partition definitions
*/
part_banks[0].mtd_part = tqm8xxl_partitions;
part_banks[0].type = "Static image";
part_banks[0].nums = ARRAY_SIZE(tqm8xxl_partitions);
part_banks[1].mtd_part = tqm8xxl_fs_partitions;
part_banks[1].type = "Static file system";
part_banks[1].nums = ARRAY_SIZE(tqm8xxl_fs_partitions);
for(idx = 0; idx < num_banks ; idx++) {
if (part_banks[idx].nums == 0)
printk(KERN_NOTICE "TQM flash%d: no partition info available, registering whole flash at once\n", idx);
else
printk(KERN_NOTICE "TQM flash%d: Using %s partition definition\n",
idx, part_banks[idx].type);
mtd_device_register(mtd_banks[idx], part_banks[idx].mtd_part,
part_banks[idx].nums);
}
return 0;
error_mem:
for(idx = 0 ; idx < FLASH_BANK_MAX ; idx++) {
if(map_banks[idx] != NULL) {
kfree(map_banks[idx]->name);
map_banks[idx]->name = NULL;
kfree(map_banks[idx]);
map_banks[idx] = NULL;
}
}
error:
iounmap(start_scan_addr);
return ret;
}
static void __exit cleanup_tqm_mtd(void)
{
unsigned int idx = 0;
for(idx = 0 ; idx < num_banks ; idx++) {
/* destroy mtd_info previously allocated */
if (mtd_banks[idx]) {
mtd_device_unregister(mtd_banks[idx]);
map_destroy(mtd_banks[idx]);
}
/* release map_info not used anymore */
kfree(map_banks[idx]->name);
kfree(map_banks[idx]);
}
if (start_scan_addr) {
iounmap(start_scan_addr);
start_scan_addr = 0;
}
}
module_init(init_tqm_mtd);
module_exit(cleanup_tqm_mtd);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Kirk Lee <kirk@hpc.ee.ntu.edu.tw>");
MODULE_DESCRIPTION("MTD map driver for TQM8xxL boards");

View File

@ -82,11 +82,12 @@ static void __exit cleanup_tsunami_flash(void)
tsunami_flash_mtd = 0;
}
static const char * const rom_probe_types[] = {
"cfi_probe", "jedec_probe", "map_rom", NULL };
static int __init init_tsunami_flash(void)
{
static const char *rom_probe_types[] = { "cfi_probe", "jedec_probe", "map_rom", NULL };
char **type;
const char * const *type;
tsunami_tig_writeb(FLASH_ENABLE_BYTE, FLASH_ENABLE_PORT);

View File

@ -38,6 +38,8 @@
#include <asm/uaccess.h>
#include "mtdcore.h"
static DEFINE_MUTEX(mtd_mutex);
/*
@ -365,37 +367,35 @@ static void mtdchar_erase_callback (struct erase_info *instr)
wake_up((wait_queue_head_t *)instr->priv);
}
#ifdef CONFIG_HAVE_MTD_OTP
static int otp_select_filemode(struct mtd_file_info *mfi, int mode)
{
struct mtd_info *mtd = mfi->mtd;
size_t retlen;
int ret = 0;
/*
* Make a fake call to mtd_read_fact_prot_reg() to check if OTP
* operations are supported.
*/
if (mtd_read_fact_prot_reg(mtd, -1, 0, &retlen, NULL) == -EOPNOTSUPP)
return -EOPNOTSUPP;
switch (mode) {
case MTD_OTP_FACTORY:
if (mtd_read_fact_prot_reg(mtd, -1, 0, &retlen, NULL) ==
-EOPNOTSUPP)
return -EOPNOTSUPP;
mfi->mode = MTD_FILE_MODE_OTP_FACTORY;
break;
case MTD_OTP_USER:
if (mtd_read_user_prot_reg(mtd, -1, 0, &retlen, NULL) ==
-EOPNOTSUPP)
return -EOPNOTSUPP;
mfi->mode = MTD_FILE_MODE_OTP_USER;
break;
default:
ret = -EINVAL;
case MTD_OTP_OFF:
mfi->mode = MTD_FILE_MODE_NORMAL;
break;
default:
return -EINVAL;
}
return ret;
return 0;
}
#else
# define otp_select_filemode(f,m) -EOPNOTSUPP
#endif
static int mtdchar_writeoob(struct file *file, struct mtd_info *mtd,
uint64_t start, uint32_t length, void __user *ptr,
@ -888,7 +888,6 @@ static int mtdchar_ioctl(struct file *file, u_int cmd, u_long arg)
break;
}
#ifdef CONFIG_HAVE_MTD_OTP
case OTPSELECT:
{
int mode;
@ -944,7 +943,6 @@ static int mtdchar_ioctl(struct file *file, u_int cmd, u_long arg)
ret = mtd_lock_user_prot_reg(mtd, oinfo.start, oinfo.length);
break;
}
#endif
/* This ioctl is being deprecated - it truncates the ECC layout */
case ECCGETLAYOUT:
@ -1185,23 +1183,25 @@ static struct file_system_type mtd_inodefs_type = {
};
MODULE_ALIAS_FS("mtd_inodefs");
static int __init init_mtdchar(void)
int __init init_mtdchar(void)
{
int ret;
ret = __register_chrdev(MTD_CHAR_MAJOR, 0, 1 << MINORBITS,
"mtd", &mtd_fops);
if (ret < 0) {
pr_notice("Can't allocate major number %d for "
"Memory Technology Devices.\n", MTD_CHAR_MAJOR);
pr_err("Can't allocate major number %d for MTD\n",
MTD_CHAR_MAJOR);
return ret;
}
ret = register_filesystem(&mtd_inodefs_type);
if (ret) {
pr_notice("Can't register mtd_inodefs filesystem: %d\n", ret);
pr_err("Can't register mtd_inodefs filesystem, error %d\n",
ret);
goto err_unregister_chdev;
}
return ret;
err_unregister_chdev:
@ -1209,18 +1209,10 @@ err_unregister_chdev:
return ret;
}
static void __exit cleanup_mtdchar(void)
void __exit cleanup_mtdchar(void)
{
unregister_filesystem(&mtd_inodefs_type);
__unregister_chrdev(MTD_CHAR_MAJOR, 0, 1 << MINORBITS, "mtd");
}
module_init(init_mtdchar);
module_exit(cleanup_mtdchar);
MODULE_ALIAS_CHARDEV_MAJOR(MTD_CHAR_MAJOR);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
MODULE_DESCRIPTION("Direct character-device access to MTD devices");
MODULE_ALIAS_CHARDEV_MAJOR(MTD_CHAR_MAJOR);

View File

@ -42,6 +42,7 @@
#include <linux/mtd/partitions.h>
#include "mtdcore.h"
/*
* backing device capabilities for non-mappable devices (such as NAND flash)
* - permits private mappings, copies are taken of the data
@ -97,11 +98,7 @@ EXPORT_SYMBOL_GPL(__mtd_next_device);
static LIST_HEAD(mtd_notifiers);
#if defined(CONFIG_MTD_CHAR) || defined(CONFIG_MTD_CHAR_MODULE)
#define MTD_DEVT(index) MKDEV(MTD_CHAR_MAJOR, (index)*2)
#else
#define MTD_DEVT(index) 0
#endif
/* REVISIT once MTD uses the driver model better, whoever allocates
* the mtd_info will probably want to use the release() hook...
@ -493,7 +490,7 @@ out_error:
*
* Returns zero in case of success and a negative error code in case of failure.
*/
int mtd_device_parse_register(struct mtd_info *mtd, const char **types,
int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types,
struct mtd_part_parser_data *parser_data,
const struct mtd_partition *parts,
int nr_parts)
@ -1117,8 +1114,6 @@ EXPORT_SYMBOL_GPL(mtd_kmalloc_up_to);
/*====================================================================*/
/* Support for /proc/mtd */
static struct proc_dir_entry *proc_mtd;
static int mtd_proc_show(struct seq_file *m, void *v)
{
struct mtd_info *mtd;
@ -1164,6 +1159,8 @@ static int __init mtd_bdi_init(struct backing_dev_info *bdi, const char *name)
return ret;
}
static struct proc_dir_entry *proc_mtd;
static int __init init_mtd(void)
{
int ret;
@ -1184,11 +1181,17 @@ static int __init init_mtd(void)
if (ret)
goto err_bdi3;
#ifdef CONFIG_PROC_FS
proc_mtd = proc_create("mtd", 0, NULL, &mtd_proc_ops);
#endif /* CONFIG_PROC_FS */
ret = init_mtdchar();
if (ret)
goto out_procfs;
return 0;
out_procfs:
if (proc_mtd)
remove_proc_entry("mtd", NULL);
err_bdi3:
bdi_destroy(&mtd_bdi_ro_mappable);
err_bdi2:
@ -1202,10 +1205,9 @@ err_reg:
static void __exit cleanup_mtd(void)
{
#ifdef CONFIG_PROC_FS
cleanup_mtdchar();
if (proc_mtd)
remove_proc_entry( "mtd", NULL);
#endif /* CONFIG_PROC_FS */
remove_proc_entry("mtd", NULL);
class_unregister(&mtd_class);
bdi_destroy(&mtd_bdi_unmappable);
bdi_destroy(&mtd_bdi_ro_mappable);

View File

@ -1,23 +1,21 @@
/* linux/drivers/mtd/mtdcore.h
*
* Header file for driver private mtdcore exports
*
/*
* These are exported solely for the purpose of mtd_blkdevs.c and mtdchar.c.
* You should not use them for _anything_ else.
*/
/* These are exported solely for the purpose of mtd_blkdevs.c. You
should not use them for _anything_ else */
extern struct mutex mtd_table_mutex;
extern struct mtd_info *__mtd_next_device(int i);
extern int add_mtd_device(struct mtd_info *mtd);
extern int del_mtd_device(struct mtd_info *mtd);
extern int add_mtd_partitions(struct mtd_info *, const struct mtd_partition *,
int);
extern int del_mtd_partitions(struct mtd_info *);
extern int parse_mtd_partitions(struct mtd_info *master, const char **types,
struct mtd_partition **pparts,
struct mtd_part_parser_data *data);
struct mtd_info *__mtd_next_device(int i);
int add_mtd_device(struct mtd_info *mtd);
int del_mtd_device(struct mtd_info *mtd);
int add_mtd_partitions(struct mtd_info *, const struct mtd_partition *, int);
int del_mtd_partitions(struct mtd_info *);
int parse_mtd_partitions(struct mtd_info *master, const char * const *types,
struct mtd_partition **pparts,
struct mtd_part_parser_data *data);
int __init init_mtdchar(void);
void __exit cleanup_mtdchar(void);
#define mtd_for_each_device(mtd) \
for ((mtd) = __mtd_next_device(0); \

View File

@ -694,7 +694,7 @@ EXPORT_SYMBOL_GPL(deregister_mtd_parser);
* Do not forget to update 'parse_mtd_partitions()' kerneldoc comment if you
* are changing this array!
*/
static const char *default_mtd_part_types[] = {
static const char * const default_mtd_part_types[] = {
"cmdlinepart",
"ofpart",
NULL
@ -720,7 +720,7 @@ static const char *default_mtd_part_types[] = {
* o a positive number of found partitions, in which case on exit @pparts will
* point to an array containing this number of &struct mtd_info objects.
*/
int parse_mtd_partitions(struct mtd_info *master, const char **types,
int parse_mtd_partitions(struct mtd_info *master, const char *const *types,
struct mtd_partition **pparts,
struct mtd_part_parser_data *data)
{

View File

@ -41,14 +41,6 @@ config MTD_SM_COMMON
tristate
default n
config MTD_NAND_MUSEUM_IDS
bool "Enable chip ids for obsolete ancient NAND devices"
default n
help
Enable this option only when your board has first generation
NAND chips (page size 256 byte, erase size 4-8KiB). The IDs
of these chips were reused by later, larger chips.
config MTD_NAND_DENALI
tristate "Support Denali NAND controller"
help
@ -81,12 +73,6 @@ config MTD_NAND_DENALI_SCRATCH_REG_ADDR
scratch register here to enable this feature. On Intel Moorestown
boards, the scratch register is at 0xFF108018.
config MTD_NAND_H1900
tristate "iPAQ H1900 flash"
depends on ARCH_PXA && BROKEN
help
This enables the driver for the iPAQ h1900 flash.
config MTD_NAND_GPIO
tristate "GPIO NAND Flash driver"
depends on GPIOLIB && ARM
@ -201,22 +187,6 @@ config MTD_NAND_BF5XX_BOOTROM_ECC
If unsure, say N.
config MTD_NAND_RTC_FROM4
tristate "Renesas Flash ROM 4-slot interface board (FROM_BOARD4)"
depends on SH_SOLUTION_ENGINE
select REED_SOLOMON
select REED_SOLOMON_DEC8
select BITREVERSE
help
This enables the driver for the Renesas Technology AG-AND
flash interface board (FROM_BOARD4)
config MTD_NAND_PPCHAMELEONEVB
tristate "NAND Flash device on PPChameleonEVB board"
depends on PPCHAMELEONEVB && BROKEN
help
This enables the NAND flash driver on the PPChameleon EVB Board.
config MTD_NAND_S3C2410
tristate "NAND Flash support for Samsung S3C SoCs"
depends on ARCH_S3C24XX || ARCH_S3C64XX

View File

@ -15,14 +15,11 @@ obj-$(CONFIG_MTD_NAND_DENALI_PCI) += denali_pci.o
obj-$(CONFIG_MTD_NAND_DENALI_DT) += denali_dt.o
obj-$(CONFIG_MTD_NAND_AU1550) += au1550nd.o
obj-$(CONFIG_MTD_NAND_BF5XX) += bf5xx_nand.o
obj-$(CONFIG_MTD_NAND_PPCHAMELEONEVB) += ppchameleonevb.o
obj-$(CONFIG_MTD_NAND_S3C2410) += s3c2410.o
obj-$(CONFIG_MTD_NAND_DAVINCI) += davinci_nand.o
obj-$(CONFIG_MTD_NAND_DISKONCHIP) += diskonchip.o
obj-$(CONFIG_MTD_NAND_DOCG4) += docg4.o
obj-$(CONFIG_MTD_NAND_FSMC) += fsmc_nand.o
obj-$(CONFIG_MTD_NAND_H1900) += h1910.o
obj-$(CONFIG_MTD_NAND_RTC_FROM4) += rtc_from4.o
obj-$(CONFIG_MTD_NAND_SHARPSL) += sharpsl.o
obj-$(CONFIG_MTD_NAND_NANDSIM) += nandsim.o
obj-$(CONFIG_MTD_NAND_CS553X) += cs553x_nand.o

View File

@ -1737,20 +1737,7 @@ static struct platform_driver atmel_nand_driver = {
},
};
static int __init atmel_nand_init(void)
{
return platform_driver_probe(&atmel_nand_driver, atmel_nand_probe);
}
static void __exit atmel_nand_exit(void)
{
platform_driver_unregister(&atmel_nand_driver);
}
module_init(atmel_nand_init);
module_exit(atmel_nand_exit);
module_platform_driver_probe(atmel_nand_driver, atmel_nand_probe);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Rick Bronson");

View File

@ -874,21 +874,7 @@ static struct platform_driver bf5xx_nand_driver = {
},
};
static int __init bf5xx_nand_init(void)
{
printk(KERN_INFO "%s, Version %s (c) 2007 Analog Devices, Inc.\n",
DRV_DESC, DRV_VERSION);
return platform_driver_register(&bf5xx_nand_driver);
}
static void __exit bf5xx_nand_exit(void)
{
platform_driver_unregister(&bf5xx_nand_driver);
}
module_init(bf5xx_nand_init);
module_exit(bf5xx_nand_exit);
module_platform_driver(bf5xx_nand_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR(DRV_AUTHOR);

View File

@ -303,13 +303,7 @@ static void cafe_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
case NAND_CMD_SEQIN:
case NAND_CMD_RNDIN:
case NAND_CMD_STATUS:
case NAND_CMD_DEPLETE1:
case NAND_CMD_RNDOUT:
case NAND_CMD_STATUS_ERROR:
case NAND_CMD_STATUS_ERROR0:
case NAND_CMD_STATUS_ERROR1:
case NAND_CMD_STATUS_ERROR2:
case NAND_CMD_STATUS_ERROR3:
cafe_writel(cafe, cafe->ctl2, NAND_CTRL2);
return;
}
@ -536,8 +530,8 @@ static int cafe_nand_write_page_lowlevel(struct mtd_info *mtd,
}
static int cafe_nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
const uint8_t *buf, int oob_required, int page,
int cached, int raw)
uint32_t offset, int data_len, const uint8_t *buf,
int oob_required, int page, int cached, int raw)
{
int status;

View File

@ -34,6 +34,7 @@
#include <linux/mtd/partitions.h>
#include <linux/slab.h>
#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/platform_data/mtd-davinci.h>
#include <linux/platform_data/mtd-davinci-aemif.h>
@ -577,7 +578,6 @@ static struct davinci_nand_pdata
return pdev->dev.platform_data;
}
#else
#define davinci_nand_of_match NULL
static struct davinci_nand_pdata
*nand_davinci_get_pdata(struct platform_device *pdev)
{
@ -878,22 +878,12 @@ static struct platform_driver nand_davinci_driver = {
.driver = {
.name = "davinci_nand",
.owner = THIS_MODULE,
.of_match_table = davinci_nand_of_match,
.of_match_table = of_match_ptr(davinci_nand_of_match),
},
};
MODULE_ALIAS("platform:davinci_nand");
static int __init nand_davinci_init(void)
{
return platform_driver_probe(&nand_davinci_driver, nand_davinci_probe);
}
module_init(nand_davinci_init);
static void __exit nand_davinci_exit(void)
{
platform_driver_unregister(&nand_davinci_driver);
}
module_exit(nand_davinci_exit);
module_platform_driver_probe(nand_davinci_driver, nand_davinci_probe);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Texas Instruments");

View File

@ -42,7 +42,7 @@ static void __iomem *request_and_map(struct device *dev,
}
ptr = devm_ioremap_nocache(dev, res->start, resource_size(res));
if (!res)
if (!ptr)
dev_err(dev, "ioremap_nocache of %s failed!", res->name);
return ptr;
@ -90,7 +90,7 @@ static int denali_dt_probe(struct platform_device *ofdev)
denali->irq = platform_get_irq(ofdev, 0);
if (denali->irq < 0) {
dev_err(&ofdev->dev, "no irq defined\n");
return -ENXIO;
return denali->irq;
}
denali->flash_reg = request_and_map(&ofdev->dev, denali_reg);
@ -146,21 +146,11 @@ static struct platform_driver denali_dt_driver = {
.driver = {
.name = "denali-nand-dt",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(denali_nand_dt_ids),
.of_match_table = denali_nand_dt_ids,
},
};
static int __init denali_init_dt(void)
{
return platform_driver_register(&denali_dt_driver);
}
module_init(denali_init_dt);
static void __exit denali_exit_dt(void)
{
platform_driver_unregister(&denali_dt_driver);
}
module_exit(denali_exit_dt);
module_platform_driver(denali_dt_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jamie Iles");

View File

@ -1397,18 +1397,7 @@ static struct platform_driver docg4_driver = {
.remove = __exit_p(cleanup_docg4),
};
static int __init docg4_init(void)
{
return platform_driver_probe(&docg4_driver, probe_docg4);
}
static void __exit docg4_exit(void)
{
platform_driver_unregister(&docg4_driver);
}
module_init(docg4_init);
module_exit(docg4_exit);
module_platform_driver_probe(docg4_driver, probe_docg4);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Mike Dunn");

View File

@ -1235,18 +1235,7 @@ static struct platform_driver fsmc_nand_driver = {
},
};
static int __init fsmc_nand_init(void)
{
return platform_driver_probe(&fsmc_nand_driver,
fsmc_nand_probe);
}
module_init(fsmc_nand_init);
static void __exit fsmc_nand_exit(void)
{
platform_driver_unregister(&fsmc_nand_driver);
}
module_exit(fsmc_nand_exit);
module_platform_driver_probe(fsmc_nand_driver, fsmc_nand_probe);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Vipin Kumar <vipin.kumar@st.com>, Ashish Priyadarshi");

View File

@ -190,7 +190,6 @@ static struct resource *gpio_nand_get_io_sync_of(struct platform_device *pdev)
return r;
}
#else /* CONFIG_OF */
#define gpio_nand_id_table NULL
static inline int gpio_nand_get_config_of(const struct device *dev,
struct gpio_nand_platdata *plat)
{
@ -259,8 +258,6 @@ static int gpio_nand_remove(struct platform_device *dev)
if (gpio_is_valid(gpiomtd->plat.gpio_rdy))
gpio_free(gpiomtd->plat.gpio_rdy);
kfree(gpiomtd);
return 0;
}
@ -297,7 +294,7 @@ static int gpio_nand_probe(struct platform_device *dev)
if (!res0)
return -EINVAL;
gpiomtd = kzalloc(sizeof(*gpiomtd), GFP_KERNEL);
gpiomtd = devm_kzalloc(&dev->dev, sizeof(*gpiomtd), GFP_KERNEL);
if (gpiomtd == NULL) {
dev_err(&dev->dev, "failed to create NAND MTD\n");
return -ENOMEM;
@ -412,7 +409,6 @@ err_sync:
iounmap(gpiomtd->nand_chip.IO_ADDR_R);
release_mem_region(res0->start, resource_size(res0));
err_map:
kfree(gpiomtd);
return ret;
}
@ -421,7 +417,7 @@ static struct platform_driver gpio_nand_driver = {
.remove = gpio_nand_remove,
.driver = {
.name = "gpio-nand",
.of_match_table = gpio_nand_id_table,
.of_match_table = of_match_ptr(gpio_nand_id_table),
},
};

View File

@ -1,167 +0,0 @@
/*
* drivers/mtd/nand/h1910.c
*
* Copyright (C) 2003 Joshua Wise (joshua@joshuawise.com)
*
* Derived from drivers/mtd/nand/edb7312.c
* Copyright (C) 2002 Marius Gröger (mag@sysgo.de)
* Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Overview:
* This is a device driver for the NAND flash device found on the
* iPAQ h1910 board which utilizes the Samsung K9F2808 part. This is
* a 128Mibit (16MiB x 8 bits) NAND flash device.
*/
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
#include <asm/io.h>
#include <mach/hardware.h>
#include <asm/sizes.h>
#include <mach/h1900-gpio.h>
#include <mach/ipaq.h>
/*
* MTD structure for EDB7312 board
*/
static struct mtd_info *h1910_nand_mtd = NULL;
/*
* Module stuff
*/
/*
* Define static partitions for flash device
*/
static struct mtd_partition partition_info[] = {
{name:"h1910 NAND Flash",
offset:0,
size:16 * 1024 * 1024}
};
#define NUM_PARTITIONS 1
/*
* hardware specific access to control-lines
*
* NAND_NCE: bit 0 - don't care
* NAND_CLE: bit 1 - address bit 2
* NAND_ALE: bit 2 - address bit 3
*/
static void h1910_hwcontrol(struct mtd_info *mtd, int cmd,
unsigned int ctrl)
{
struct nand_chip *chip = mtd->priv;
if (cmd != NAND_CMD_NONE)
writeb(cmd, chip->IO_ADDR_W | ((ctrl & 0x6) << 1));
}
/*
* read device ready pin
*/
#if 0
static int h1910_device_ready(struct mtd_info *mtd)
{
return (GPLR(55) & GPIO_bit(55));
}
#endif
/*
* Main initialization routine
*/
static int __init h1910_init(void)
{
struct nand_chip *this;
void __iomem *nandaddr;
if (!machine_is_h1900())
return -ENODEV;
nandaddr = ioremap(0x08000000, 0x1000);
if (!nandaddr) {
printk("Failed to ioremap nand flash.\n");
return -ENOMEM;
}
/* Allocate memory for MTD device structure and private data */
h1910_nand_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL);
if (!h1910_nand_mtd) {
printk("Unable to allocate h1910 NAND MTD device structure.\n");
iounmap((void *)nandaddr);
return -ENOMEM;
}
/* Get pointer to private data */
this = (struct nand_chip *)(&h1910_nand_mtd[1]);
/* Initialize structures */
memset(h1910_nand_mtd, 0, sizeof(struct mtd_info));
memset(this, 0, sizeof(struct nand_chip));
/* Link the private data with the MTD structure */
h1910_nand_mtd->priv = this;
h1910_nand_mtd->owner = THIS_MODULE;
/*
* Enable VPEN
*/
GPSR(37) = GPIO_bit(37);
/* insert callbacks */
this->IO_ADDR_R = nandaddr;
this->IO_ADDR_W = nandaddr;
this->cmd_ctrl = h1910_hwcontrol;
this->dev_ready = NULL; /* unknown whether that was correct or not so we will just do it like this */
/* 15 us command delay time */
this->chip_delay = 50;
this->ecc.mode = NAND_ECC_SOFT;
/* Scan to find existence of the device */
if (nand_scan(h1910_nand_mtd, 1)) {
printk(KERN_NOTICE "No NAND device - returning -ENXIO\n");
kfree(h1910_nand_mtd);
iounmap((void *)nandaddr);
return -ENXIO;
}
/* Register the partitions */
mtd_device_parse_register(h1910_nand_mtd, NULL, NULL, partition_info,
NUM_PARTITIONS);
/* Return happy */
return 0;
}
module_init(h1910_init);
/*
* Clean up routine
*/
static void __exit h1910_cleanup(void)
{
struct nand_chip *this = (struct nand_chip *)&h1910_nand_mtd[1];
/* Release resources, unregister device */
nand_release(h1910_nand_mtd);
/* Release io resource */
iounmap((void *)this->IO_ADDR_W);
/* Free the MTD device structure */
kfree(h1910_nand_mtd);
}
module_exit(h1910_cleanup);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Joshua Wise <joshua at joshuawise dot com>");
MODULE_DESCRIPTION("NAND flash driver for iPAQ h1910");

View File

@ -540,8 +540,8 @@ static int lpc32xx_write_page_lowlevel(struct mtd_info *mtd,
}
static int lpc32xx_write_page(struct mtd_info *mtd, struct nand_chip *chip,
const uint8_t *buf, int oob_required, int page,
int cached, int raw)
uint32_t offset, int data_len, const uint8_t *buf,
int oob_required, int page, int cached, int raw)
{
int res;

View File

@ -4,7 +4,6 @@
* Overview:
* This is the generic MTD driver for NAND flash devices. It should be
* capable of working with almost all NAND chips currently available.
* Basic support for AG-AND chips is provided.
*
* Additional technical information is available on
* http://www.linux-mtd.infradead.org/doc/nand.html
@ -22,8 +21,6 @@
* Enable cached programming for 2k page size chips
* Check, if mtd->ecctype should be set to MTD_ECC_HW
* if we have HW ECC support.
* The AG-AND chips have nice features for speed improvement,
* which are not supported yet. Read / program 4 pages in one go.
* BBT table is not serialized, has to be fixed
*
* This program is free software; you can redistribute it and/or modify
@ -515,7 +512,7 @@ EXPORT_SYMBOL_GPL(nand_wait_ready);
* @page_addr: the page address for this command, -1 if none
*
* Send command to NAND device. This function is used for small page devices
* (256/512 Bytes per page).
* (512 Bytes per page).
*/
static void nand_command(struct mtd_info *mtd, unsigned int command,
int column, int page_addr)
@ -631,8 +628,7 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
}
/* Command latch cycle */
chip->cmd_ctrl(mtd, command & 0xff,
NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
chip->cmd_ctrl(mtd, command, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
if (column != -1 || page_addr != -1) {
int ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE;
@ -671,16 +667,6 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
case NAND_CMD_SEQIN:
case NAND_CMD_RNDIN:
case NAND_CMD_STATUS:
case NAND_CMD_DEPLETE1:
return;
case NAND_CMD_STATUS_ERROR:
case NAND_CMD_STATUS_ERROR0:
case NAND_CMD_STATUS_ERROR1:
case NAND_CMD_STATUS_ERROR2:
case NAND_CMD_STATUS_ERROR3:
/* Read error status commands require only a short delay */
udelay(chip->chip_delay);
return;
case NAND_CMD_RESET:
@ -836,10 +822,7 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
*/
ndelay(100);
if ((state == FL_ERASING) && (chip->options & NAND_IS_AND))
chip->cmdfunc(mtd, NAND_CMD_STATUS_MULTI, -1, -1);
else
chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
if (in_interrupt() || oops_in_progress)
panic_nand_wait(mtd, chip, timeo);
@ -1127,7 +1110,7 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
}
/**
* nand_read_subpage - [REPLACEABLE] software ECC based sub-page read function
* nand_read_subpage - [REPLACEABLE] ECC based sub-page read function
* @mtd: mtd info structure
* @chip: nand chip info structure
* @data_offs: offset of requested data within the page
@ -1995,6 +1978,67 @@ static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
return 0;
}
/**
* nand_write_subpage_hwecc - [REPLACABLE] hardware ECC based subpage write
* @mtd: mtd info structure
* @chip: nand chip info structure
* @column: column address of subpage within the page
* @data_len: data length
* @oob_required: must write chip->oob_poi to OOB
*/
static int nand_write_subpage_hwecc(struct mtd_info *mtd,
struct nand_chip *chip, uint32_t offset,
uint32_t data_len, const uint8_t *data_buf,
int oob_required)
{
uint8_t *oob_buf = chip->oob_poi;
uint8_t *ecc_calc = chip->buffers->ecccalc;
int ecc_size = chip->ecc.size;
int ecc_bytes = chip->ecc.bytes;
int ecc_steps = chip->ecc.steps;
uint32_t *eccpos = chip->ecc.layout->eccpos;
uint32_t start_step = offset / ecc_size;
uint32_t end_step = (offset + data_len - 1) / ecc_size;
int oob_bytes = mtd->oobsize / ecc_steps;
int step, i;
for (step = 0; step < ecc_steps; step++) {
/* configure controller for WRITE access */
chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
/* write data (untouched subpages already masked by 0xFF) */
chip->write_buf(mtd, data_buf, ecc_size);
/* mask ECC of un-touched subpages by padding 0xFF */
if ((step < start_step) || (step > end_step))
memset(ecc_calc, 0xff, ecc_bytes);
else
chip->ecc.calculate(mtd, data_buf, ecc_calc);
/* mask OOB of un-touched subpages by padding 0xFF */
/* if oob_required, preserve OOB metadata of written subpage */
if (!oob_required || (step < start_step) || (step > end_step))
memset(oob_buf, 0xff, oob_bytes);
data_buf += ecc_size;
ecc_calc += ecc_bytes;
oob_buf += oob_bytes;
}
/* copy calculated ECC for whole page to chip->buffer->oob */
/* this include masked-value(0xFF) for unwritten subpages */
ecc_calc = chip->buffers->ecccalc;
for (i = 0; i < chip->ecc.total; i++)
chip->oob_poi[eccpos[i]] = ecc_calc[i];
/* write OOB buffer to NAND device */
chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
return 0;
}
/**
* nand_write_page_syndrome - [REPLACEABLE] hardware ECC syndrome based page write
* @mtd: mtd info structure
@ -2047,6 +2091,8 @@ static int nand_write_page_syndrome(struct mtd_info *mtd,
* nand_write_page - [REPLACEABLE] write one page
* @mtd: MTD device structure
* @chip: NAND chip descriptor
* @offset: address offset within the page
* @data_len: length of actual data to be written
* @buf: the data to write
* @oob_required: must write chip->oob_poi to OOB
* @page: page number to write
@ -2054,15 +2100,25 @@ static int nand_write_page_syndrome(struct mtd_info *mtd,
* @raw: use _raw version of write_page
*/
static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
const uint8_t *buf, int oob_required, int page,
int cached, int raw)
uint32_t offset, int data_len, const uint8_t *buf,
int oob_required, int page, int cached, int raw)
{
int status;
int status, subpage;
if (!(chip->options & NAND_NO_SUBPAGE_WRITE) &&
chip->ecc.write_subpage)
subpage = offset || (data_len < mtd->writesize);
else
subpage = 0;
chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
if (unlikely(raw))
status = chip->ecc.write_page_raw(mtd, chip, buf, oob_required);
status = chip->ecc.write_page_raw(mtd, chip, buf,
oob_required);
else if (subpage)
status = chip->ecc.write_subpage(mtd, chip, offset, data_len,
buf, oob_required);
else
status = chip->ecc.write_page(mtd, chip, buf, oob_required);
@ -2075,7 +2131,7 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
*/
cached = 0;
if (!cached || !(chip->options & NAND_CACHEPRG)) {
if (!cached || !NAND_HAS_CACHEPROG(chip)) {
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
status = chip->waitfunc(mtd, chip);
@ -2176,7 +2232,7 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
uint8_t *oob = ops->oobbuf;
uint8_t *buf = ops->datbuf;
int ret, subpage;
int ret;
int oob_required = oob ? 1 : 0;
ops->retlen = 0;
@ -2191,10 +2247,6 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
}
column = to & (mtd->writesize - 1);
subpage = column || (writelen & (mtd->writesize - 1));
if (subpage && oob)
return -EINVAL;
chipnr = (int)(to >> chip->chip_shift);
chip->select_chip(mtd, chipnr);
@ -2243,9 +2295,9 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
/* We still need to erase leftover OOB data */
memset(chip->oob_poi, 0xff, mtd->oobsize);
}
ret = chip->write_page(mtd, chip, wbuf, oob_required, page,
cached, (ops->mode == MTD_OPS_RAW));
ret = chip->write_page(mtd, chip, column, bytes, wbuf,
oob_required, page, cached,
(ops->mode == MTD_OPS_RAW));
if (ret)
break;
@ -2480,24 +2532,6 @@ static void single_erase_cmd(struct mtd_info *mtd, int page)
chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1);
}
/**
* multi_erase_cmd - [GENERIC] AND specific block erase command function
* @mtd: MTD device structure
* @page: the page address of the block which will be erased
*
* AND multi block erase command function. Erase 4 consecutive blocks.
*/
static void multi_erase_cmd(struct mtd_info *mtd, int page)
{
struct nand_chip *chip = mtd->priv;
/* Send commands to erase a block */
chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page++);
chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page++);
chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page++);
chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page);
chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1);
}
/**
* nand_erase - [MTD Interface] erase block(s)
* @mtd: MTD device structure
@ -2510,7 +2544,6 @@ static int nand_erase(struct mtd_info *mtd, struct erase_info *instr)
return nand_erase_nand(mtd, instr, 0);
}
#define BBT_PAGE_MASK 0xffffff3f
/**
* nand_erase_nand - [INTERN] erase block(s)
* @mtd: MTD device structure
@ -2524,8 +2557,6 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
{
int page, status, pages_per_block, ret, chipnr;
struct nand_chip *chip = mtd->priv;
loff_t rewrite_bbt[NAND_MAX_CHIPS] = {0};
unsigned int bbt_masked_page = 0xffffffff;
loff_t len;
pr_debug("%s: start = 0x%012llx, len = %llu\n",
@ -2556,15 +2587,6 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
goto erase_exit;
}
/*
* If BBT requires refresh, set the BBT page mask to see if the BBT
* should be rewritten. Otherwise the mask is set to 0xffffffff which
* can not be matched. This is also done when the bbt is actually
* erased to avoid recursive updates.
*/
if (chip->options & BBT_AUTO_REFRESH && !allowbbt)
bbt_masked_page = chip->bbt_td->pages[chipnr] & BBT_PAGE_MASK;
/* Loop through the pages */
len = instr->len;
@ -2610,15 +2632,6 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
goto erase_exit;
}
/*
* If BBT requires refresh, set the BBT rewrite flag to the
* page being erased.
*/
if (bbt_masked_page != 0xffffffff &&
(page & BBT_PAGE_MASK) == bbt_masked_page)
rewrite_bbt[chipnr] =
((loff_t)page << chip->page_shift);
/* Increment page address and decrement length */
len -= (1 << chip->phys_erase_shift);
page += pages_per_block;
@ -2628,15 +2641,6 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
chipnr++;
chip->select_chip(mtd, -1);
chip->select_chip(mtd, chipnr);
/*
* If BBT requires refresh and BBT-PERCHIP, set the BBT
* page mask to see if this BBT should be rewritten.
*/
if (bbt_masked_page != 0xffffffff &&
(chip->bbt_td->options & NAND_BBT_PERCHIP))
bbt_masked_page = chip->bbt_td->pages[chipnr] &
BBT_PAGE_MASK;
}
}
instr->state = MTD_ERASE_DONE;
@ -2653,23 +2657,6 @@ erase_exit:
if (!ret)
mtd_erase_callback(instr);
/*
* If BBT requires refresh and erase was successful, rewrite any
* selected bad block tables.
*/
if (bbt_masked_page == 0xffffffff || ret)
return ret;
for (chipnr = 0; chipnr < chip->numchips; chipnr++) {
if (!rewrite_bbt[chipnr])
continue;
/* Update the BBT for chip */
pr_debug("%s: nand_update_bbt (%d:0x%0llx 0x%0x)\n",
__func__, chipnr, rewrite_bbt[chipnr],
chip->bbt_td->pages[chipnr]);
nand_update_bbt(mtd, rewrite_bbt[chipnr]);
}
/* Return more or less happy */
return ret;
}
@ -2905,8 +2892,6 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
chip->onfi_version = 20;
else if (val & (1 << 1))
chip->onfi_version = 10;
else
chip->onfi_version = 0;
if (!chip->onfi_version) {
pr_info("%s: unsupported ONFI version: %d\n", __func__, val);
@ -3171,6 +3156,30 @@ static void nand_decode_bbm_options(struct mtd_info *mtd,
chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
}
static inline bool is_full_id_nand(struct nand_flash_dev *type)
{
return type->id_len;
}
static bool find_full_id_nand(struct mtd_info *mtd, struct nand_chip *chip,
struct nand_flash_dev *type, u8 *id_data, int *busw)
{
if (!strncmp(type->id, id_data, type->id_len)) {
mtd->writesize = type->pagesize;
mtd->erasesize = type->erasesize;
mtd->oobsize = type->oobsize;
chip->cellinfo = id_data[2];
chip->chipsize = (uint64_t)type->chipsize << 20;
chip->options |= type->options;
*busw = type->options & NAND_BUSWIDTH_16;
return true;
}
return false;
}
/*
* Get the flash and manufacturer id and lookup if the type is supported.
*/
@ -3222,9 +3231,14 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
if (!type)
type = nand_flash_ids;
for (; type->name != NULL; type++)
if (*dev_id == type->id)
break;
for (; type->name != NULL; type++) {
if (is_full_id_nand(type)) {
if (find_full_id_nand(mtd, chip, type, id_data, &busw))
goto ident_done;
} else if (*dev_id == type->dev_id) {
break;
}
}
chip->onfi_version = 0;
if (!type->name || !type->pagesize) {
@ -3302,12 +3316,7 @@ ident_done:
}
chip->badblockbits = 8;
/* Check for AND chips with 4 page planes */
if (chip->options & NAND_4PAGE_ARRAY)
chip->erase_cmd = multi_erase_cmd;
else
chip->erase_cmd = single_erase_cmd;
chip->erase_cmd = single_erase_cmd;
/* Do not replace user supplied command function! */
if (mtd->writesize > 512 && chip->cmdfunc == nand_command)
@ -3474,6 +3483,10 @@ int nand_scan_tail(struct mtd_info *mtd)
chip->ecc.read_oob = nand_read_oob_std;
if (!chip->ecc.write_oob)
chip->ecc.write_oob = nand_write_oob_std;
if (!chip->ecc.read_subpage)
chip->ecc.read_subpage = nand_read_subpage;
if (!chip->ecc.write_subpage)
chip->ecc.write_subpage = nand_write_subpage_hwecc;
case NAND_ECC_HW_SYNDROME:
if ((!chip->ecc.calculate || !chip->ecc.correct ||

View File

@ -1240,15 +1240,6 @@ int nand_update_bbt(struct mtd_info *mtd, loff_t offs)
*/
static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
static uint8_t scan_agand_pattern[] = { 0x1C, 0x71, 0xC7, 0x1C, 0x71, 0xC7 };
static struct nand_bbt_descr agand_flashbased = {
.options = NAND_BBT_SCANEMPTY | NAND_BBT_SCANALLPAGES,
.offs = 0x20,
.len = 6,
.pattern = scan_agand_pattern
};
/* Generic flash bbt descriptors */
static uint8_t bbt_pattern[] = {'B', 'b', 't', '0' };
static uint8_t mirror_pattern[] = {'1', 't', 'b', 'B' };
@ -1333,22 +1324,6 @@ int nand_default_bbt(struct mtd_info *mtd)
{
struct nand_chip *this = mtd->priv;
/*
* Default for AG-AND. We must use a flash based bad block table as the
* devices have factory marked _good_ blocks. Erasing those blocks
* leads to loss of the good / bad information, so we _must_ store this
* information in a good / bad table during startup.
*/
if (this->options & NAND_IS_AND) {
/* Use the default pattern descriptors */
if (!this->bbt_td) {
this->bbt_td = &bbt_main_descr;
this->bbt_md = &bbt_mirror_descr;
}
this->bbt_options |= NAND_BBT_USE_FLASH;
return nand_scan_bbt(mtd, &agand_flashbased);
}
/* Is a flash based bad block table requested? */
if (this->bbt_options & NAND_BBT_USE_FLASH) {
/* Use the default pattern descriptors */

View File

@ -10,163 +10,153 @@
*/
#include <linux/module.h>
#include <linux/mtd/nand.h>
/*
* Chip ID list
*
* Name. ID code, pagesize, chipsize in MegaByte, eraseblock size,
* options
*
* Pagesize; 0, 256, 512
* 0 get this information from the extended chip ID
+ 256 256 Byte page size
* 512 512 Byte page size
*/
struct nand_flash_dev nand_flash_ids[] = {
#define SP_OPTIONS NAND_NEED_READRDY
#define SP_OPTIONS16 (SP_OPTIONS | NAND_BUSWIDTH_16)
#include <linux/sizes.h>
#ifdef CONFIG_MTD_NAND_MUSEUM_IDS
{"NAND 1MiB 5V 8-bit", 0x6e, 256, 1, 0x1000, SP_OPTIONS},
{"NAND 2MiB 5V 8-bit", 0x64, 256, 2, 0x1000, SP_OPTIONS},
{"NAND 4MiB 5V 8-bit", 0x6b, 512, 4, 0x2000, SP_OPTIONS},
{"NAND 1MiB 3,3V 8-bit", 0xe8, 256, 1, 0x1000, SP_OPTIONS},
{"NAND 1MiB 3,3V 8-bit", 0xec, 256, 1, 0x1000, SP_OPTIONS},
{"NAND 2MiB 3,3V 8-bit", 0xea, 256, 2, 0x1000, SP_OPTIONS},
{"NAND 4MiB 3,3V 8-bit", 0xd5, 512, 4, 0x2000, SP_OPTIONS},
{"NAND 4MiB 3,3V 8-bit", 0xe3, 512, 4, 0x2000, SP_OPTIONS},
{"NAND 4MiB 3,3V 8-bit", 0xe5, 512, 4, 0x2000, SP_OPTIONS},
{"NAND 8MiB 3,3V 8-bit", 0xd6, 512, 8, 0x2000, SP_OPTIONS},
{"NAND 8MiB 1,8V 8-bit", 0x39, 512, 8, 0x2000, SP_OPTIONS},
{"NAND 8MiB 3,3V 8-bit", 0xe6, 512, 8, 0x2000, SP_OPTIONS},
{"NAND 8MiB 1,8V 16-bit", 0x49, 512, 8, 0x2000, SP_OPTIONS16},
{"NAND 8MiB 3,3V 16-bit", 0x59, 512, 8, 0x2000, SP_OPTIONS16},
#endif
{"NAND 16MiB 1,8V 8-bit", 0x33, 512, 16, 0x4000, SP_OPTIONS},
{"NAND 16MiB 3,3V 8-bit", 0x73, 512, 16, 0x4000, SP_OPTIONS},
{"NAND 16MiB 1,8V 16-bit", 0x43, 512, 16, 0x4000, SP_OPTIONS16},
{"NAND 16MiB 3,3V 16-bit", 0x53, 512, 16, 0x4000, SP_OPTIONS16},
{"NAND 32MiB 1,8V 8-bit", 0x35, 512, 32, 0x4000, SP_OPTIONS},
{"NAND 32MiB 3,3V 8-bit", 0x75, 512, 32, 0x4000, SP_OPTIONS},
{"NAND 32MiB 1,8V 16-bit", 0x45, 512, 32, 0x4000, SP_OPTIONS16},
{"NAND 32MiB 3,3V 16-bit", 0x55, 512, 32, 0x4000, SP_OPTIONS16},
{"NAND 64MiB 1,8V 8-bit", 0x36, 512, 64, 0x4000, SP_OPTIONS},
{"NAND 64MiB 3,3V 8-bit", 0x76, 512, 64, 0x4000, SP_OPTIONS},
{"NAND 64MiB 1,8V 16-bit", 0x46, 512, 64, 0x4000, SP_OPTIONS16},
{"NAND 64MiB 3,3V 16-bit", 0x56, 512, 64, 0x4000, SP_OPTIONS16},
{"NAND 128MiB 1,8V 8-bit", 0x78, 512, 128, 0x4000, SP_OPTIONS},
{"NAND 128MiB 1,8V 8-bit", 0x39, 512, 128, 0x4000, SP_OPTIONS},
{"NAND 128MiB 3,3V 8-bit", 0x79, 512, 128, 0x4000, SP_OPTIONS},
{"NAND 128MiB 1,8V 16-bit", 0x72, 512, 128, 0x4000, SP_OPTIONS16},
{"NAND 128MiB 1,8V 16-bit", 0x49, 512, 128, 0x4000, SP_OPTIONS16},
{"NAND 128MiB 3,3V 16-bit", 0x74, 512, 128, 0x4000, SP_OPTIONS16},
{"NAND 128MiB 3,3V 16-bit", 0x59, 512, 128, 0x4000, SP_OPTIONS16},
{"NAND 256MiB 3,3V 8-bit", 0x71, 512, 256, 0x4000, SP_OPTIONS},
/*
* These are the new chips with large page size. The pagesize and the
* erasesize is determined from the extended id bytes
*/
#define LP_OPTIONS NAND_SAMSUNG_LP_OPTIONS
#define LP_OPTIONS16 (LP_OPTIONS | NAND_BUSWIDTH_16)
/* 512 Megabit */
{"NAND 64MiB 1,8V 8-bit", 0xA2, 0, 64, 0, LP_OPTIONS},
{"NAND 64MiB 1,8V 8-bit", 0xA0, 0, 64, 0, LP_OPTIONS},
{"NAND 64MiB 3,3V 8-bit", 0xF2, 0, 64, 0, LP_OPTIONS},
{"NAND 64MiB 3,3V 8-bit", 0xD0, 0, 64, 0, LP_OPTIONS},
{"NAND 64MiB 3,3V 8-bit", 0xF0, 0, 64, 0, LP_OPTIONS},
{"NAND 64MiB 1,8V 16-bit", 0xB2, 0, 64, 0, LP_OPTIONS16},
{"NAND 64MiB 1,8V 16-bit", 0xB0, 0, 64, 0, LP_OPTIONS16},
{"NAND 64MiB 3,3V 16-bit", 0xC2, 0, 64, 0, LP_OPTIONS16},
{"NAND 64MiB 3,3V 16-bit", 0xC0, 0, 64, 0, LP_OPTIONS16},
/* 1 Gigabit */
{"NAND 128MiB 1,8V 8-bit", 0xA1, 0, 128, 0, LP_OPTIONS},
{"NAND 128MiB 3,3V 8-bit", 0xF1, 0, 128, 0, LP_OPTIONS},
{"NAND 128MiB 3,3V 8-bit", 0xD1, 0, 128, 0, LP_OPTIONS},
{"NAND 128MiB 1,8V 16-bit", 0xB1, 0, 128, 0, LP_OPTIONS16},
{"NAND 128MiB 3,3V 16-bit", 0xC1, 0, 128, 0, LP_OPTIONS16},
{"NAND 128MiB 1,8V 16-bit", 0xAD, 0, 128, 0, LP_OPTIONS16},
/* 2 Gigabit */
{"NAND 256MiB 1,8V 8-bit", 0xAA, 0, 256, 0, LP_OPTIONS},
{"NAND 256MiB 3,3V 8-bit", 0xDA, 0, 256, 0, LP_OPTIONS},
{"NAND 256MiB 1,8V 16-bit", 0xBA, 0, 256, 0, LP_OPTIONS16},
{"NAND 256MiB 3,3V 16-bit", 0xCA, 0, 256, 0, LP_OPTIONS16},
/* 4 Gigabit */
{"NAND 512MiB 1,8V 8-bit", 0xAC, 0, 512, 0, LP_OPTIONS},
{"NAND 512MiB 3,3V 8-bit", 0xDC, 0, 512, 0, LP_OPTIONS},
{"NAND 512MiB 1,8V 16-bit", 0xBC, 0, 512, 0, LP_OPTIONS16},
{"NAND 512MiB 3,3V 16-bit", 0xCC, 0, 512, 0, LP_OPTIONS16},
/* 8 Gigabit */
{"NAND 1GiB 1,8V 8-bit", 0xA3, 0, 1024, 0, LP_OPTIONS},
{"NAND 1GiB 3,3V 8-bit", 0xD3, 0, 1024, 0, LP_OPTIONS},
{"NAND 1GiB 1,8V 16-bit", 0xB3, 0, 1024, 0, LP_OPTIONS16},
{"NAND 1GiB 3,3V 16-bit", 0xC3, 0, 1024, 0, LP_OPTIONS16},
/* 16 Gigabit */
{"NAND 2GiB 1,8V 8-bit", 0xA5, 0, 2048, 0, LP_OPTIONS},
{"NAND 2GiB 3,3V 8-bit", 0xD5, 0, 2048, 0, LP_OPTIONS},
{"NAND 2GiB 1,8V 16-bit", 0xB5, 0, 2048, 0, LP_OPTIONS16},
{"NAND 2GiB 3,3V 16-bit", 0xC5, 0, 2048, 0, LP_OPTIONS16},
/* 32 Gigabit */
{"NAND 4GiB 1,8V 8-bit", 0xA7, 0, 4096, 0, LP_OPTIONS},
{"NAND 4GiB 3,3V 8-bit", 0xD7, 0, 4096, 0, LP_OPTIONS},
{"NAND 4GiB 1,8V 16-bit", 0xB7, 0, 4096, 0, LP_OPTIONS16},
{"NAND 4GiB 3,3V 16-bit", 0xC7, 0, 4096, 0, LP_OPTIONS16},
/* 64 Gigabit */
{"NAND 8GiB 1,8V 8-bit", 0xAE, 0, 8192, 0, LP_OPTIONS},
{"NAND 8GiB 3,3V 8-bit", 0xDE, 0, 8192, 0, LP_OPTIONS},
{"NAND 8GiB 1,8V 16-bit", 0xBE, 0, 8192, 0, LP_OPTIONS16},
{"NAND 8GiB 3,3V 16-bit", 0xCE, 0, 8192, 0, LP_OPTIONS16},
/* 128 Gigabit */
{"NAND 16GiB 1,8V 8-bit", 0x1A, 0, 16384, 0, LP_OPTIONS},
{"NAND 16GiB 3,3V 8-bit", 0x3A, 0, 16384, 0, LP_OPTIONS},
{"NAND 16GiB 1,8V 16-bit", 0x2A, 0, 16384, 0, LP_OPTIONS16},
{"NAND 16GiB 3,3V 16-bit", 0x4A, 0, 16384, 0, LP_OPTIONS16},
/* 256 Gigabit */
{"NAND 32GiB 1,8V 8-bit", 0x1C, 0, 32768, 0, LP_OPTIONS},
{"NAND 32GiB 3,3V 8-bit", 0x3C, 0, 32768, 0, LP_OPTIONS},
{"NAND 32GiB 1,8V 16-bit", 0x2C, 0, 32768, 0, LP_OPTIONS16},
{"NAND 32GiB 3,3V 16-bit", 0x4C, 0, 32768, 0, LP_OPTIONS16},
/* 512 Gigabit */
{"NAND 64GiB 1,8V 8-bit", 0x1E, 0, 65536, 0, LP_OPTIONS},
{"NAND 64GiB 3,3V 8-bit", 0x3E, 0, 65536, 0, LP_OPTIONS},
{"NAND 64GiB 1,8V 16-bit", 0x2E, 0, 65536, 0, LP_OPTIONS16},
{"NAND 64GiB 3,3V 16-bit", 0x4E, 0, 65536, 0, LP_OPTIONS16},
/*
* Renesas AND 1 Gigabit. Those chips do not support extended id and
* have a strange page/block layout ! The chosen minimum erasesize is
* 4 * 2 * 2048 = 16384 Byte, as those chips have an array of 4 page
* planes 1 block = 2 pages, but due to plane arrangement the blocks
* 0-3 consists of page 0 + 4,1 + 5, 2 + 6, 3 + 7 Anyway JFFS2 would
* increase the eraseblock size so we chose a combined one which can be
* erased in one go There are more speed improvements for reads and
* writes possible, but not implemented now
*/
{"AND 128MiB 3,3V 8-bit", 0x01, 2048, 128, 0x4000,
NAND_IS_AND | NAND_4PAGE_ARRAY | BBT_AUTO_REFRESH},
{NULL,}
};
#define SP_OPTIONS NAND_NEED_READRDY
#define SP_OPTIONS16 (SP_OPTIONS | NAND_BUSWIDTH_16)
/*
* Manufacturer ID list
*/
* The chip ID list:
* name, device ID, page size, chip size in MiB, eraseblock size, options
*
* If page size and eraseblock size are 0, the sizes are taken from the
* extended chip ID.
*/
struct nand_flash_dev nand_flash_ids[] = {
/*
* Some incompatible NAND chips share device ID's and so must be
* listed by full ID. We list them first so that we can easily identify
* the most specific match.
*/
{"TC58NVG2S0F 4G 3.3V 8-bit",
{ .id = {0x98, 0xdc, 0x90, 0x26, 0x76, 0x15, 0x01, 0x08} },
SZ_4K, SZ_512, SZ_256K, 0, 8, 224},
{"TC58NVG3S0F 8G 3.3V 8-bit",
{ .id = {0x98, 0xd3, 0x90, 0x26, 0x76, 0x15, 0x02, 0x08} },
SZ_4K, SZ_1K, SZ_256K, 0, 8, 232},
{"TC58NVG5D2 32G 3.3V 8-bit",
{ .id = {0x98, 0xd7, 0x94, 0x32, 0x76, 0x56, 0x09, 0x00} },
SZ_8K, SZ_4K, SZ_1M, 0, 8, 640},
{"TC58NVG6D2 64G 3.3V 8-bit",
{ .id = {0x98, 0xde, 0x94, 0x82, 0x76, 0x56, 0x04, 0x20} },
SZ_8K, SZ_8K, SZ_2M, 0, 8, 640},
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", 0xE5, 4, SZ_8K, SP_OPTIONS),
LEGACY_ID_NAND("NAND 8MiB 3,3V 8-bit", 0xD6, 8, SZ_8K, SP_OPTIONS),
LEGACY_ID_NAND("NAND 8MiB 3,3V 8-bit", 0xE6, 8, SZ_8K, SP_OPTIONS),
LEGACY_ID_NAND("NAND 16MiB 1,8V 8-bit", 0x33, 16, SZ_16K, SP_OPTIONS),
LEGACY_ID_NAND("NAND 16MiB 3,3V 8-bit", 0x73, 16, SZ_16K, SP_OPTIONS),
LEGACY_ID_NAND("NAND 16MiB 1,8V 16-bit", 0x43, 16, SZ_16K, SP_OPTIONS16),
LEGACY_ID_NAND("NAND 16MiB 3,3V 16-bit", 0x53, 16, SZ_16K, SP_OPTIONS16),
LEGACY_ID_NAND("NAND 32MiB 1,8V 8-bit", 0x35, 32, SZ_16K, SP_OPTIONS),
LEGACY_ID_NAND("NAND 32MiB 3,3V 8-bit", 0x75, 32, SZ_16K, SP_OPTIONS),
LEGACY_ID_NAND("NAND 32MiB 1,8V 16-bit", 0x45, 32, SZ_16K, SP_OPTIONS16),
LEGACY_ID_NAND("NAND 32MiB 3,3V 16-bit", 0x55, 32, SZ_16K, SP_OPTIONS16),
LEGACY_ID_NAND("NAND 64MiB 1,8V 8-bit", 0x36, 64, SZ_16K, SP_OPTIONS),
LEGACY_ID_NAND("NAND 64MiB 3,3V 8-bit", 0x76, 64, SZ_16K, SP_OPTIONS),
LEGACY_ID_NAND("NAND 64MiB 1,8V 16-bit", 0x46, 64, SZ_16K, SP_OPTIONS16),
LEGACY_ID_NAND("NAND 64MiB 3,3V 16-bit", 0x56, 64, SZ_16K, SP_OPTIONS16),
LEGACY_ID_NAND("NAND 128MiB 1,8V 8-bit", 0x78, 128, SZ_16K, SP_OPTIONS),
LEGACY_ID_NAND("NAND 128MiB 1,8V 8-bit", 0x39, 128, SZ_16K, SP_OPTIONS),
LEGACY_ID_NAND("NAND 128MiB 3,3V 8-bit", 0x79, 128, SZ_16K, SP_OPTIONS),
LEGACY_ID_NAND("NAND 128MiB 1,8V 16-bit", 0x72, 128, SZ_16K, SP_OPTIONS16),
LEGACY_ID_NAND("NAND 128MiB 1,8V 16-bit", 0x49, 128, SZ_16K, SP_OPTIONS16),
LEGACY_ID_NAND("NAND 128MiB 3,3V 16-bit", 0x74, 128, SZ_16K, SP_OPTIONS16),
LEGACY_ID_NAND("NAND 128MiB 3,3V 16-bit", 0x59, 128, SZ_16K, SP_OPTIONS16),
LEGACY_ID_NAND("NAND 256MiB 3,3V 8-bit", 0x71, 256, SZ_16K, SP_OPTIONS),
/*
* These are the new chips with large page size. Their page size and
* eraseblock size are determined from the extended ID bytes.
*/
/* 512 Megabit */
EXTENDED_ID_NAND("NAND 64MiB 1,8V 8-bit", 0xA2, 64, LP_OPTIONS),
EXTENDED_ID_NAND("NAND 64MiB 1,8V 8-bit", 0xA0, 64, LP_OPTIONS),
EXTENDED_ID_NAND("NAND 64MiB 3,3V 8-bit", 0xF2, 64, LP_OPTIONS),
EXTENDED_ID_NAND("NAND 64MiB 3,3V 8-bit", 0xD0, 64, LP_OPTIONS),
EXTENDED_ID_NAND("NAND 64MiB 3,3V 8-bit", 0xF0, 64, LP_OPTIONS),
EXTENDED_ID_NAND("NAND 64MiB 1,8V 16-bit", 0xB2, 64, LP_OPTIONS16),
EXTENDED_ID_NAND("NAND 64MiB 1,8V 16-bit", 0xB0, 64, LP_OPTIONS16),
EXTENDED_ID_NAND("NAND 64MiB 3,3V 16-bit", 0xC2, 64, LP_OPTIONS16),
EXTENDED_ID_NAND("NAND 64MiB 3,3V 16-bit", 0xC0, 64, LP_OPTIONS16),
/* 1 Gigabit */
EXTENDED_ID_NAND("NAND 128MiB 1,8V 8-bit", 0xA1, 128, LP_OPTIONS),
EXTENDED_ID_NAND("NAND 128MiB 3,3V 8-bit", 0xF1, 128, LP_OPTIONS),
EXTENDED_ID_NAND("NAND 128MiB 3,3V 8-bit", 0xD1, 128, LP_OPTIONS),
EXTENDED_ID_NAND("NAND 128MiB 1,8V 16-bit", 0xB1, 128, LP_OPTIONS16),
EXTENDED_ID_NAND("NAND 128MiB 3,3V 16-bit", 0xC1, 128, LP_OPTIONS16),
EXTENDED_ID_NAND("NAND 128MiB 1,8V 16-bit", 0xAD, 128, LP_OPTIONS16),
/* 2 Gigabit */
EXTENDED_ID_NAND("NAND 256MiB 1,8V 8-bit", 0xAA, 256, LP_OPTIONS),
EXTENDED_ID_NAND("NAND 256MiB 3,3V 8-bit", 0xDA, 256, LP_OPTIONS),
EXTENDED_ID_NAND("NAND 256MiB 1,8V 16-bit", 0xBA, 256, LP_OPTIONS16),
EXTENDED_ID_NAND("NAND 256MiB 3,3V 16-bit", 0xCA, 256, LP_OPTIONS16),
/* 4 Gigabit */
EXTENDED_ID_NAND("NAND 512MiB 1,8V 8-bit", 0xAC, 512, LP_OPTIONS),
EXTENDED_ID_NAND("NAND 512MiB 3,3V 8-bit", 0xDC, 512, LP_OPTIONS),
EXTENDED_ID_NAND("NAND 512MiB 1,8V 16-bit", 0xBC, 512, LP_OPTIONS16),
EXTENDED_ID_NAND("NAND 512MiB 3,3V 16-bit", 0xCC, 512, LP_OPTIONS16),
/* 8 Gigabit */
EXTENDED_ID_NAND("NAND 1GiB 1,8V 8-bit", 0xA3, 1024, LP_OPTIONS),
EXTENDED_ID_NAND("NAND 1GiB 3,3V 8-bit", 0xD3, 1024, LP_OPTIONS),
EXTENDED_ID_NAND("NAND 1GiB 1,8V 16-bit", 0xB3, 1024, LP_OPTIONS16),
EXTENDED_ID_NAND("NAND 1GiB 3,3V 16-bit", 0xC3, 1024, LP_OPTIONS16),
/* 16 Gigabit */
EXTENDED_ID_NAND("NAND 2GiB 1,8V 8-bit", 0xA5, 2048, LP_OPTIONS),
EXTENDED_ID_NAND("NAND 2GiB 3,3V 8-bit", 0xD5, 2048, LP_OPTIONS),
EXTENDED_ID_NAND("NAND 2GiB 1,8V 16-bit", 0xB5, 2048, LP_OPTIONS16),
EXTENDED_ID_NAND("NAND 2GiB 3,3V 16-bit", 0xC5, 2048, LP_OPTIONS16),
/* 32 Gigabit */
EXTENDED_ID_NAND("NAND 4GiB 1,8V 8-bit", 0xA7, 4096, LP_OPTIONS),
EXTENDED_ID_NAND("NAND 4GiB 3,3V 8-bit", 0xD7, 4096, LP_OPTIONS),
EXTENDED_ID_NAND("NAND 4GiB 1,8V 16-bit", 0xB7, 4096, LP_OPTIONS16),
EXTENDED_ID_NAND("NAND 4GiB 3,3V 16-bit", 0xC7, 4096, LP_OPTIONS16),
/* 64 Gigabit */
EXTENDED_ID_NAND("NAND 8GiB 1,8V 8-bit", 0xAE, 8192, LP_OPTIONS),
EXTENDED_ID_NAND("NAND 8GiB 3,3V 8-bit", 0xDE, 8192, LP_OPTIONS),
EXTENDED_ID_NAND("NAND 8GiB 1,8V 16-bit", 0xBE, 8192, LP_OPTIONS16),
EXTENDED_ID_NAND("NAND 8GiB 3,3V 16-bit", 0xCE, 8192, LP_OPTIONS16),
/* 128 Gigabit */
EXTENDED_ID_NAND("NAND 16GiB 1,8V 8-bit", 0x1A, 16384, LP_OPTIONS),
EXTENDED_ID_NAND("NAND 16GiB 3,3V 8-bit", 0x3A, 16384, LP_OPTIONS),
EXTENDED_ID_NAND("NAND 16GiB 1,8V 16-bit", 0x2A, 16384, LP_OPTIONS16),
EXTENDED_ID_NAND("NAND 16GiB 3,3V 16-bit", 0x4A, 16384, LP_OPTIONS16),
/* 256 Gigabit */
EXTENDED_ID_NAND("NAND 32GiB 1,8V 8-bit", 0x1C, 32768, LP_OPTIONS),
EXTENDED_ID_NAND("NAND 32GiB 3,3V 8-bit", 0x3C, 32768, LP_OPTIONS),
EXTENDED_ID_NAND("NAND 32GiB 1,8V 16-bit", 0x2C, 32768, LP_OPTIONS16),
EXTENDED_ID_NAND("NAND 32GiB 3,3V 16-bit", 0x4C, 32768, LP_OPTIONS16),
/* 512 Gigabit */
EXTENDED_ID_NAND("NAND 64GiB 1,8V 8-bit", 0x1E, 65536, LP_OPTIONS),
EXTENDED_ID_NAND("NAND 64GiB 3,3V 8-bit", 0x3E, 65536, LP_OPTIONS),
EXTENDED_ID_NAND("NAND 64GiB 1,8V 16-bit", 0x2E, 65536, LP_OPTIONS16),
EXTENDED_ID_NAND("NAND 64GiB 3,3V 16-bit", 0x4E, 65536, LP_OPTIONS16),
{NULL}
};
/* Manufacturer IDs */
struct nand_manufacturers nand_manuf_ids[] = {
{NAND_MFR_TOSHIBA, "Toshiba"},
{NAND_MFR_SAMSUNG, "Samsung"},

View File

@ -218,7 +218,6 @@ MODULE_PARM_DESC(bch, "Enable BCH ecc and set how many bits should "
#define STATE_CMD_READOOB 0x00000005 /* read OOB area */
#define STATE_CMD_ERASE1 0x00000006 /* sector erase first command */
#define STATE_CMD_STATUS 0x00000007 /* read status */
#define STATE_CMD_STATUS_M 0x00000008 /* read multi-plane status (isn't implemented) */
#define STATE_CMD_SEQIN 0x00000009 /* sequential data input */
#define STATE_CMD_READID 0x0000000A /* read ID */
#define STATE_CMD_ERASE2 0x0000000B /* sector erase second command */
@ -263,14 +262,13 @@ MODULE_PARM_DESC(bch, "Enable BCH ecc and set how many bits should "
#define NS_OPER_STATES 6 /* Maximum number of states in operation */
#define OPT_ANY 0xFFFFFFFF /* any chip supports this operation */
#define OPT_PAGE256 0x00000001 /* 256-byte page chips */
#define OPT_PAGE512 0x00000002 /* 512-byte page chips */
#define OPT_PAGE2048 0x00000008 /* 2048-byte page chips */
#define OPT_SMARTMEDIA 0x00000010 /* SmartMedia technology chips */
#define OPT_PAGE512_8BIT 0x00000040 /* 512-byte page chips with 8-bit bus width */
#define OPT_PAGE4096 0x00000080 /* 4096-byte page chips */
#define OPT_LARGEPAGE (OPT_PAGE2048 | OPT_PAGE4096) /* 2048 & 4096-byte page chips */
#define OPT_SMALLPAGE (OPT_PAGE256 | OPT_PAGE512) /* 256 and 512-byte page chips */
#define OPT_SMALLPAGE (OPT_PAGE512) /* 512-byte page chips */
/* Remove action bits from state */
#define NS_STATE(x) ((x) & ~ACTION_MASK)
@ -406,8 +404,6 @@ static struct nandsim_operations {
{OPT_ANY, {STATE_CMD_ERASE1, STATE_ADDR_SEC, STATE_CMD_ERASE2 | ACTION_SECERASE, STATE_READY}},
/* Read status */
{OPT_ANY, {STATE_CMD_STATUS, STATE_DATAOUT_STATUS, STATE_READY}},
/* Read multi-plane status */
{OPT_SMARTMEDIA, {STATE_CMD_STATUS_M, STATE_DATAOUT_STATUS_M, STATE_READY}},
/* Read ID */
{OPT_ANY, {STATE_CMD_READID, STATE_ADDR_ZERO, STATE_DATAOUT_ID, STATE_READY}},
/* Large page devices read page */
@ -699,10 +695,7 @@ static int init_nandsim(struct mtd_info *mtd)
ns->geom.secszoob = ns->geom.secsz + ns->geom.oobsz * ns->geom.pgsec;
ns->options = 0;
if (ns->geom.pgsz == 256) {
ns->options |= OPT_PAGE256;
}
else if (ns->geom.pgsz == 512) {
if (ns->geom.pgsz == 512) {
ns->options |= OPT_PAGE512;
if (ns->busw == 8)
ns->options |= OPT_PAGE512_8BIT;
@ -769,9 +762,9 @@ static int init_nandsim(struct mtd_info *mtd)
}
/* 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].id)
continue;
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)
@ -1079,8 +1072,6 @@ static char *get_state_name(uint32_t state)
return "STATE_CMD_ERASE1";
case STATE_CMD_STATUS:
return "STATE_CMD_STATUS";
case STATE_CMD_STATUS_M:
return "STATE_CMD_STATUS_M";
case STATE_CMD_SEQIN:
return "STATE_CMD_SEQIN";
case STATE_CMD_READID:
@ -1145,7 +1136,6 @@ static int check_command(int cmd)
case NAND_CMD_RNDOUTSTART:
return 0;
case NAND_CMD_STATUS_MULTI:
default:
return 1;
}
@ -1171,8 +1161,6 @@ static uint32_t get_state_by_command(unsigned command)
return STATE_CMD_ERASE1;
case NAND_CMD_STATUS:
return STATE_CMD_STATUS;
case NAND_CMD_STATUS_MULTI:
return STATE_CMD_STATUS_M;
case NAND_CMD_SEQIN:
return STATE_CMD_SEQIN;
case NAND_CMD_READID:
@ -2306,7 +2294,7 @@ static int __init ns_init_module(void)
nand->geom.idbytes = 2;
nand->regs.status = NS_STATUS_OK(nand);
nand->nxstate = STATE_UNKNOWN;
nand->options |= OPT_PAGE256; /* temporary value */
nand->options |= OPT_PAGE512; /* temporary value */
nand->ids[0] = first_id_byte;
nand->ids[1] = second_id_byte;
nand->ids[2] = third_id_byte;

View File

@ -177,15 +177,6 @@ static void nuc900_nand_command_lp(struct mtd_info *mtd, unsigned int command,
case NAND_CMD_SEQIN:
case NAND_CMD_RNDIN:
case NAND_CMD_STATUS:
case NAND_CMD_DEPLETE1:
return;
case NAND_CMD_STATUS_ERROR:
case NAND_CMD_STATUS_ERROR0:
case NAND_CMD_STATUS_ERROR1:
case NAND_CMD_STATUS_ERROR2:
case NAND_CMD_STATUS_ERROR3:
udelay(chip->chip_delay);
return;
case NAND_CMD_RESET:

View File

@ -1023,9 +1023,9 @@ static int omap_wait(struct mtd_info *mtd, struct nand_chip *chip)
int status, state = this->state;
if (state == FL_ERASING)
timeo += (HZ * 400) / 1000;
timeo += msecs_to_jiffies(400);
else
timeo += (HZ * 20) / 1000;
timeo += msecs_to_jiffies(20);
writeb(NAND_CMD_STATUS & 0xFF, info->reg.gpmc_nand_command);
while (time_before(jiffies, timeo)) {
@ -1701,8 +1701,9 @@ static int omap3_init_bch(struct mtd_info *mtd, int ecc_opt)
elm_node = of_find_node_by_phandle(be32_to_cpup(parp));
pdev = of_find_device_by_node(elm_node);
info->elm_dev = &pdev->dev;
elm_config(info->elm_dev, bch_type);
info->is_elm_used = true;
if (elm_config(info->elm_dev, bch_type) == 0)
info->is_elm_used = true;
}
if (info->is_elm_used && (mtd->writesize <= 4096)) {

View File

@ -231,18 +231,7 @@ static struct platform_driver orion_nand_driver = {
},
};
static int __init orion_nand_init(void)
{
return platform_driver_probe(&orion_nand_driver, orion_nand_probe);
}
static void __exit orion_nand_exit(void)
{
platform_driver_unregister(&orion_nand_driver);
}
module_init(orion_nand_init);
module_exit(orion_nand_exit);
module_platform_driver_probe(orion_nand_driver, orion_nand_probe);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Tzachi Perelstein");

View File

@ -1,403 +0,0 @@
/*
* drivers/mtd/nand/ppchameleonevb.c
*
* Copyright (C) 2003 DAVE Srl (info@wawnet.biz)
*
* Derived from drivers/mtd/nand/edb7312.c
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Overview:
* This is a device driver for the NAND flash devices found on the
* PPChameleon/PPChameleonEVB system.
* PPChameleon options (autodetected):
* - BA model: no NAND
* - ME model: 32MB (Samsung K9F5608U0B)
* - HI model: 128MB (Samsung K9F1G08UOM)
* PPChameleonEVB options:
* - 32MB (Samsung K9F5608U0B)
*/
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
#include <asm/io.h>
#include <platforms/PPChameleonEVB.h>
#undef USE_READY_BUSY_PIN
#define USE_READY_BUSY_PIN
/* see datasheets (tR) */
#define NAND_BIG_DELAY_US 25
#define NAND_SMALL_DELAY_US 10
/* handy sizes */
#define SZ_4M 0x00400000
#define NAND_SMALL_SIZE 0x02000000
#define NAND_MTD_NAME "ppchameleon-nand"
#define NAND_EVB_MTD_NAME "ppchameleonevb-nand"
/* GPIO pins used to drive NAND chip mounted on processor module */
#define NAND_nCE_GPIO_PIN (0x80000000 >> 1)
#define NAND_CLE_GPIO_PIN (0x80000000 >> 2)
#define NAND_ALE_GPIO_PIN (0x80000000 >> 3)
#define NAND_RB_GPIO_PIN (0x80000000 >> 4)
/* GPIO pins used to drive NAND chip mounted on EVB */
#define NAND_EVB_nCE_GPIO_PIN (0x80000000 >> 14)
#define NAND_EVB_CLE_GPIO_PIN (0x80000000 >> 15)
#define NAND_EVB_ALE_GPIO_PIN (0x80000000 >> 16)
#define NAND_EVB_RB_GPIO_PIN (0x80000000 >> 31)
/*
* MTD structure for PPChameleonEVB board
*/
static struct mtd_info *ppchameleon_mtd = NULL;
static struct mtd_info *ppchameleonevb_mtd = NULL;
/*
* Module stuff
*/
static unsigned long ppchameleon_fio_pbase = CFG_NAND0_PADDR;
static unsigned long ppchameleonevb_fio_pbase = CFG_NAND1_PADDR;
#ifdef MODULE
module_param(ppchameleon_fio_pbase, ulong, 0);
module_param(ppchameleonevb_fio_pbase, ulong, 0);
#else
__setup("ppchameleon_fio_pbase=", ppchameleon_fio_pbase);
__setup("ppchameleonevb_fio_pbase=", ppchameleonevb_fio_pbase);
#endif
/*
* Define static partitions for flash devices
*/
static struct mtd_partition partition_info_hi[] = {
{ .name = "PPChameleon HI Nand Flash",
.offset = 0,
.size = 128 * 1024 * 1024
}
};
static struct mtd_partition partition_info_me[] = {
{ .name = "PPChameleon ME Nand Flash",
.offset = 0,
.size = 32 * 1024 * 1024
}
};
static struct mtd_partition partition_info_evb[] = {
{ .name = "PPChameleonEVB Nand Flash",
.offset = 0,
.size = 32 * 1024 * 1024
}
};
#define NUM_PARTITIONS 1
/*
* hardware specific access to control-lines
*/
static void ppchameleon_hwcontrol(struct mtd_info *mtdinfo, int cmd,
unsigned int ctrl)
{
struct nand_chip *chip = mtd->priv;
if (ctrl & NAND_CTRL_CHANGE) {
#error Missing headerfiles. No way to fix this. -tglx
switch (cmd) {
case NAND_CTL_SETCLE:
MACRO_NAND_CTL_SETCLE((unsigned long)CFG_NAND0_PADDR);
break;
case NAND_CTL_CLRCLE:
MACRO_NAND_CTL_CLRCLE((unsigned long)CFG_NAND0_PADDR);
break;
case NAND_CTL_SETALE:
MACRO_NAND_CTL_SETALE((unsigned long)CFG_NAND0_PADDR);
break;
case NAND_CTL_CLRALE:
MACRO_NAND_CTL_CLRALE((unsigned long)CFG_NAND0_PADDR);
break;
case NAND_CTL_SETNCE:
MACRO_NAND_ENABLE_CE((unsigned long)CFG_NAND0_PADDR);
break;
case NAND_CTL_CLRNCE:
MACRO_NAND_DISABLE_CE((unsigned long)CFG_NAND0_PADDR);
break;
}
}
if (cmd != NAND_CMD_NONE)
writeb(cmd, chip->IO_ADDR_W);
}
static void ppchameleonevb_hwcontrol(struct mtd_info *mtdinfo, int cmd,
unsigned int ctrl)
{
struct nand_chip *chip = mtd->priv;
if (ctrl & NAND_CTRL_CHANGE) {
#error Missing headerfiles. No way to fix this. -tglx
switch (cmd) {
case NAND_CTL_SETCLE:
MACRO_NAND_CTL_SETCLE((unsigned long)CFG_NAND1_PADDR);
break;
case NAND_CTL_CLRCLE:
MACRO_NAND_CTL_CLRCLE((unsigned long)CFG_NAND1_PADDR);
break;
case NAND_CTL_SETALE:
MACRO_NAND_CTL_SETALE((unsigned long)CFG_NAND1_PADDR);
break;
case NAND_CTL_CLRALE:
MACRO_NAND_CTL_CLRALE((unsigned long)CFG_NAND1_PADDR);
break;
case NAND_CTL_SETNCE:
MACRO_NAND_ENABLE_CE((unsigned long)CFG_NAND1_PADDR);
break;
case NAND_CTL_CLRNCE:
MACRO_NAND_DISABLE_CE((unsigned long)CFG_NAND1_PADDR);
break;
}
}
if (cmd != NAND_CMD_NONE)
writeb(cmd, chip->IO_ADDR_W);
}
#ifdef USE_READY_BUSY_PIN
/*
* read device ready pin
*/
static int ppchameleon_device_ready(struct mtd_info *minfo)
{
if (in_be32((volatile unsigned *)GPIO0_IR) & NAND_RB_GPIO_PIN)
return 1;
return 0;
}
static int ppchameleonevb_device_ready(struct mtd_info *minfo)
{
if (in_be32((volatile unsigned *)GPIO0_IR) & NAND_EVB_RB_GPIO_PIN)
return 1;
return 0;
}
#endif
/*
* Main initialization routine
*/
static int __init ppchameleonevb_init(void)
{
struct nand_chip *this;
void __iomem *ppchameleon_fio_base;
void __iomem *ppchameleonevb_fio_base;
/*********************************
* Processor module NAND (if any) *
*********************************/
/* Allocate memory for MTD device structure and private data */
ppchameleon_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL);
if (!ppchameleon_mtd) {
printk("Unable to allocate PPChameleon NAND MTD device structure.\n");
return -ENOMEM;
}
/* map physical address */
ppchameleon_fio_base = ioremap(ppchameleon_fio_pbase, SZ_4M);
if (!ppchameleon_fio_base) {
printk("ioremap PPChameleon NAND flash failed\n");
kfree(ppchameleon_mtd);
return -EIO;
}
/* Get pointer to private data */
this = (struct nand_chip *)(&ppchameleon_mtd[1]);
/* Initialize structures */
memset(ppchameleon_mtd, 0, sizeof(struct mtd_info));
memset(this, 0, sizeof(struct nand_chip));
/* Link the private data with the MTD structure */
ppchameleon_mtd->priv = this;
ppchameleon_mtd->owner = THIS_MODULE;
/* Initialize GPIOs */
/* Pin mapping for NAND chip */
/*
CE GPIO_01
CLE GPIO_02
ALE GPIO_03
R/B GPIO_04
*/
/* output select */
out_be32((volatile unsigned *)GPIO0_OSRH, in_be32((volatile unsigned *)GPIO0_OSRH) & 0xC0FFFFFF);
/* three-state select */
out_be32((volatile unsigned *)GPIO0_TSRH, in_be32((volatile unsigned *)GPIO0_TSRH) & 0xC0FFFFFF);
/* enable output driver */
out_be32((volatile unsigned *)GPIO0_TCR,
in_be32((volatile unsigned *)GPIO0_TCR) | NAND_nCE_GPIO_PIN | NAND_CLE_GPIO_PIN | NAND_ALE_GPIO_PIN);
#ifdef USE_READY_BUSY_PIN
/* three-state select */
out_be32((volatile unsigned *)GPIO0_TSRH, in_be32((volatile unsigned *)GPIO0_TSRH) & 0xFF3FFFFF);
/* high-impedecence */
out_be32((volatile unsigned *)GPIO0_TCR, in_be32((volatile unsigned *)GPIO0_TCR) & (~NAND_RB_GPIO_PIN));
/* input select */
out_be32((volatile unsigned *)GPIO0_ISR1H,
(in_be32((volatile unsigned *)GPIO0_ISR1H) & 0xFF3FFFFF) | 0x00400000);
#endif
/* insert callbacks */
this->IO_ADDR_R = ppchameleon_fio_base;
this->IO_ADDR_W = ppchameleon_fio_base;
this->cmd_ctrl = ppchameleon_hwcontrol;
#ifdef USE_READY_BUSY_PIN
this->dev_ready = ppchameleon_device_ready;
#endif
this->chip_delay = NAND_BIG_DELAY_US;
/* ECC mode */
this->ecc.mode = NAND_ECC_SOFT;
/* Scan to find existence of the device (it could not be mounted) */
if (nand_scan(ppchameleon_mtd, 1)) {
iounmap((void *)ppchameleon_fio_base);
ppchameleon_fio_base = NULL;
kfree(ppchameleon_mtd);
goto nand_evb_init;
}
#ifndef USE_READY_BUSY_PIN
/* Adjust delay if necessary */
if (ppchameleon_mtd->size == NAND_SMALL_SIZE)
this->chip_delay = NAND_SMALL_DELAY_US;
#endif
ppchameleon_mtd->name = "ppchameleon-nand";
/* Register the partitions */
mtd_device_parse_register(ppchameleon_mtd, NULL, NULL,
ppchameleon_mtd->size == NAND_SMALL_SIZE ?
partition_info_me : partition_info_hi,
NUM_PARTITIONS);
nand_evb_init:
/****************************
* EVB NAND (always present) *
****************************/
/* Allocate memory for MTD device structure and private data */
ppchameleonevb_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL);
if (!ppchameleonevb_mtd) {
printk("Unable to allocate PPChameleonEVB NAND MTD device structure.\n");
if (ppchameleon_fio_base)
iounmap(ppchameleon_fio_base);
return -ENOMEM;
}
/* map physical address */
ppchameleonevb_fio_base = ioremap(ppchameleonevb_fio_pbase, SZ_4M);
if (!ppchameleonevb_fio_base) {
printk("ioremap PPChameleonEVB NAND flash failed\n");
kfree(ppchameleonevb_mtd);
if (ppchameleon_fio_base)
iounmap(ppchameleon_fio_base);
return -EIO;
}
/* Get pointer to private data */
this = (struct nand_chip *)(&ppchameleonevb_mtd[1]);
/* Initialize structures */
memset(ppchameleonevb_mtd, 0, sizeof(struct mtd_info));
memset(this, 0, sizeof(struct nand_chip));
/* Link the private data with the MTD structure */
ppchameleonevb_mtd->priv = this;
/* Initialize GPIOs */
/* Pin mapping for NAND chip */
/*
CE GPIO_14
CLE GPIO_15
ALE GPIO_16
R/B GPIO_31
*/
/* output select */
out_be32((volatile unsigned *)GPIO0_OSRH, in_be32((volatile unsigned *)GPIO0_OSRH) & 0xFFFFFFF0);
out_be32((volatile unsigned *)GPIO0_OSRL, in_be32((volatile unsigned *)GPIO0_OSRL) & 0x3FFFFFFF);
/* three-state select */
out_be32((volatile unsigned *)GPIO0_TSRH, in_be32((volatile unsigned *)GPIO0_TSRH) & 0xFFFFFFF0);
out_be32((volatile unsigned *)GPIO0_TSRL, in_be32((volatile unsigned *)GPIO0_TSRL) & 0x3FFFFFFF);
/* enable output driver */
out_be32((volatile unsigned *)GPIO0_TCR, in_be32((volatile unsigned *)GPIO0_TCR) | NAND_EVB_nCE_GPIO_PIN |
NAND_EVB_CLE_GPIO_PIN | NAND_EVB_ALE_GPIO_PIN);
#ifdef USE_READY_BUSY_PIN
/* three-state select */
out_be32((volatile unsigned *)GPIO0_TSRL, in_be32((volatile unsigned *)GPIO0_TSRL) & 0xFFFFFFFC);
/* high-impedecence */
out_be32((volatile unsigned *)GPIO0_TCR, in_be32((volatile unsigned *)GPIO0_TCR) & (~NAND_EVB_RB_GPIO_PIN));
/* input select */
out_be32((volatile unsigned *)GPIO0_ISR1L,
(in_be32((volatile unsigned *)GPIO0_ISR1L) & 0xFFFFFFFC) | 0x00000001);
#endif
/* insert callbacks */
this->IO_ADDR_R = ppchameleonevb_fio_base;
this->IO_ADDR_W = ppchameleonevb_fio_base;
this->cmd_ctrl = ppchameleonevb_hwcontrol;
#ifdef USE_READY_BUSY_PIN
this->dev_ready = ppchameleonevb_device_ready;
#endif
this->chip_delay = NAND_SMALL_DELAY_US;
/* ECC mode */
this->ecc.mode = NAND_ECC_SOFT;
/* Scan to find existence of the device */
if (nand_scan(ppchameleonevb_mtd, 1)) {
iounmap((void *)ppchameleonevb_fio_base);
kfree(ppchameleonevb_mtd);
if (ppchameleon_fio_base)
iounmap(ppchameleon_fio_base);
return -ENXIO;
}
ppchameleonevb_mtd->name = NAND_EVB_MTD_NAME;
/* Register the partitions */
mtd_device_parse_register(ppchameleonevb_mtd, NULL, NULL,
ppchameleon_mtd->size == NAND_SMALL_SIZE ?
partition_info_me : partition_info_hi,
NUM_PARTITIONS);
/* Return happy */
return 0;
}
module_init(ppchameleonevb_init);
/*
* Clean up routine
*/
static void __exit ppchameleonevb_cleanup(void)
{
struct nand_chip *this;
/* Release resources, unregister device(s) */
nand_release(ppchameleon_mtd);
nand_release(ppchameleonevb_mtd);
/* Release iomaps */
this = (struct nand_chip *) &ppchameleon_mtd[1];
iounmap((void *) this->IO_ADDR_R);
this = (struct nand_chip *) &ppchameleonevb_mtd[1];
iounmap((void *) this->IO_ADDR_R);
/* Free the MTD device structure */
kfree (ppchameleon_mtd);
kfree (ppchameleonevb_mtd);
}
module_exit(ppchameleonevb_cleanup);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("DAVE Srl <support-ppchameleon@dave-tech.it>");
MODULE_DESCRIPTION("MTD map driver for DAVE Srl PPChameleonEVB board");

View File

@ -989,7 +989,7 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd)
}
pxa3xx_flash_ids[0].name = f->name;
pxa3xx_flash_ids[0].id = (f->chip_id >> 8) & 0xffff;
pxa3xx_flash_ids[0].dev_id = (f->chip_id >> 8) & 0xffff;
pxa3xx_flash_ids[0].pagesize = f->page_size;
chipsize = (uint64_t)f->num_blocks * f->page_per_block * f->page_size;
pxa3xx_flash_ids[0].chipsize = chipsize >> 20;

View File

@ -1,624 +0,0 @@
/*
* drivers/mtd/nand/rtc_from4.c
*
* Copyright (C) 2004 Red Hat, Inc.
*
* Derived from drivers/mtd/nand/spia.c
* Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Overview:
* This is a device driver for the AG-AND flash device found on the
* Renesas Technology Corp. Flash ROM 4-slot interface board (FROM_BOARD4),
* which utilizes the Renesas HN29V1G91T-30 part.
* This chip is a 1 GBibit (128MiB x 8 bits) AG-AND flash device.
*/
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/rslib.h>
#include <linux/bitrev.h>
#include <linux/module.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
#include <asm/io.h>
/*
* MTD structure for Renesas board
*/
static struct mtd_info *rtc_from4_mtd = NULL;
#define RTC_FROM4_MAX_CHIPS 2
/* HS77x9 processor register defines */
#define SH77X9_BCR1 ((volatile unsigned short *)(0xFFFFFF60))
#define SH77X9_BCR2 ((volatile unsigned short *)(0xFFFFFF62))
#define SH77X9_WCR1 ((volatile unsigned short *)(0xFFFFFF64))
#define SH77X9_WCR2 ((volatile unsigned short *)(0xFFFFFF66))
#define SH77X9_MCR ((volatile unsigned short *)(0xFFFFFF68))
#define SH77X9_PCR ((volatile unsigned short *)(0xFFFFFF6C))
#define SH77X9_FRQCR ((volatile unsigned short *)(0xFFFFFF80))
/*
* Values specific to the Renesas Technology Corp. FROM_BOARD4 (used with HS77x9 processor)
*/
/* Address where flash is mapped */
#define RTC_FROM4_FIO_BASE 0x14000000
/* CLE and ALE are tied to address lines 5 & 4, respectively */
#define RTC_FROM4_CLE (1 << 5)
#define RTC_FROM4_ALE (1 << 4)
/* address lines A24-A22 used for chip selection */
#define RTC_FROM4_NAND_ADDR_SLOT3 (0x00800000)
#define RTC_FROM4_NAND_ADDR_SLOT4 (0x00C00000)
#define RTC_FROM4_NAND_ADDR_FPGA (0x01000000)
/* mask address lines A24-A22 used for chip selection */
#define RTC_FROM4_NAND_ADDR_MASK (RTC_FROM4_NAND_ADDR_SLOT3 | RTC_FROM4_NAND_ADDR_SLOT4 | RTC_FROM4_NAND_ADDR_FPGA)
/* FPGA status register for checking device ready (bit zero) */
#define RTC_FROM4_FPGA_SR (RTC_FROM4_NAND_ADDR_FPGA | 0x00000002)
#define RTC_FROM4_DEVICE_READY 0x0001
/* FPGA Reed-Solomon ECC Control register */
#define RTC_FROM4_RS_ECC_CTL (RTC_FROM4_NAND_ADDR_FPGA | 0x00000050)
#define RTC_FROM4_RS_ECC_CTL_CLR (1 << 7)
#define RTC_FROM4_RS_ECC_CTL_GEN (1 << 6)
#define RTC_FROM4_RS_ECC_CTL_FD_E (1 << 5)
/* FPGA Reed-Solomon ECC code base */
#define RTC_FROM4_RS_ECC (RTC_FROM4_NAND_ADDR_FPGA | 0x00000060)
#define RTC_FROM4_RS_ECCN (RTC_FROM4_NAND_ADDR_FPGA | 0x00000080)
/* FPGA Reed-Solomon ECC check register */
#define RTC_FROM4_RS_ECC_CHK (RTC_FROM4_NAND_ADDR_FPGA | 0x00000070)
#define RTC_FROM4_RS_ECC_CHK_ERROR (1 << 7)
#define ERR_STAT_ECC_AVAILABLE 0x20
/* Undefine for software ECC */
#define RTC_FROM4_HWECC 1
/* Define as 1 for no virtual erase blocks (in JFFS2) */
#define RTC_FROM4_NO_VIRTBLOCKS 0
/*
* Module stuff
*/
static void __iomem *rtc_from4_fio_base = (void *)P2SEGADDR(RTC_FROM4_FIO_BASE);
static const struct mtd_partition partition_info[] = {
{
.name = "Renesas flash partition 1",
.offset = 0,
.size = MTDPART_SIZ_FULL},
};
#define NUM_PARTITIONS 1
/*
* hardware specific flash bbt decriptors
* Note: this is to allow debugging by disabling
* NAND_BBT_CREATE and/or NAND_BBT_WRITE
*
*/
static uint8_t bbt_pattern[] = { 'B', 'b', 't', '0' };
static uint8_t mirror_pattern[] = { '1', 't', 'b', 'B' };
static struct nand_bbt_descr rtc_from4_bbt_main_descr = {
.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
.offs = 40,
.len = 4,
.veroffs = 44,
.maxblocks = 4,
.pattern = bbt_pattern
};
static struct nand_bbt_descr rtc_from4_bbt_mirror_descr = {
.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
.offs = 40,
.len = 4,
.veroffs = 44,
.maxblocks = 4,
.pattern = mirror_pattern
};
#ifdef RTC_FROM4_HWECC
/* the Reed Solomon control structure */
static struct rs_control *rs_decoder;
/*
* hardware specific Out Of Band information
*/
static struct nand_ecclayout rtc_from4_nand_oobinfo = {
.eccbytes = 32,
.eccpos = {
0, 1, 2, 3, 4, 5, 6, 7,
8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23,
24, 25, 26, 27, 28, 29, 30, 31},
.oobfree = {{32, 32}}
};
#endif
/*
* rtc_from4_hwcontrol - hardware specific access to control-lines
* @mtd: MTD device structure
* @cmd: hardware control command
*
* Address lines (A5 and A4) are used to control Command and Address Latch
* Enable on this board, so set the read/write address appropriately.
*
* Chip Enable is also controlled by the Chip Select (CS5) and
* Address lines (A24-A22), so no action is required here.
*
*/
static void rtc_from4_hwcontrol(struct mtd_info *mtd, int cmd,
unsigned int ctrl)
{
struct nand_chip *chip = (mtd->priv);
if (cmd == NAND_CMD_NONE)
return;
if (ctrl & NAND_CLE)
writeb(cmd, chip->IO_ADDR_W | RTC_FROM4_CLE);
else
writeb(cmd, chip->IO_ADDR_W | RTC_FROM4_ALE);
}
/*
* rtc_from4_nand_select_chip - hardware specific chip select
* @mtd: MTD device structure
* @chip: Chip to select (0 == slot 3, 1 == slot 4)
*
* The chip select is based on address lines A24-A22.
* This driver uses flash slots 3 and 4 (A23-A22).
*
*/
static void rtc_from4_nand_select_chip(struct mtd_info *mtd, int chip)
{
struct nand_chip *this = mtd->priv;
this->IO_ADDR_R = (void __iomem *)((unsigned long)this->IO_ADDR_R & ~RTC_FROM4_NAND_ADDR_MASK);
this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W & ~RTC_FROM4_NAND_ADDR_MASK);
switch (chip) {
case 0: /* select slot 3 chip */
this->IO_ADDR_R = (void __iomem *)((unsigned long)this->IO_ADDR_R | RTC_FROM4_NAND_ADDR_SLOT3);
this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W | RTC_FROM4_NAND_ADDR_SLOT3);
break;
case 1: /* select slot 4 chip */
this->IO_ADDR_R = (void __iomem *)((unsigned long)this->IO_ADDR_R | RTC_FROM4_NAND_ADDR_SLOT4);
this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W | RTC_FROM4_NAND_ADDR_SLOT4);
break;
}
}
/*
* rtc_from4_nand_device_ready - hardware specific ready/busy check
* @mtd: MTD device structure
*
* This board provides the Ready/Busy state in the status register
* of the FPGA. Bit zero indicates the RDY(1)/BSY(0) signal.
*
*/
static int rtc_from4_nand_device_ready(struct mtd_info *mtd)
{
unsigned short status;
status = *((volatile unsigned short *)(rtc_from4_fio_base + RTC_FROM4_FPGA_SR));
return (status & RTC_FROM4_DEVICE_READY);
}
/*
* deplete - code to perform device recovery in case there was a power loss
* @mtd: MTD device structure
* @chip: Chip to select (0 == slot 3, 1 == slot 4)
*
* If there was a sudden loss of power during an erase operation, a
* "device recovery" operation must be performed when power is restored
* to ensure correct operation. This routine performs the required steps
* for the requested chip.
*
* See page 86 of the data sheet for details.
*
*/
static void deplete(struct mtd_info *mtd, int chip)
{
struct nand_chip *this = mtd->priv;
/* wait until device is ready */
while (!this->dev_ready(mtd)) ;
this->select_chip(mtd, chip);
/* Send the commands for device recovery, phase 1 */
this->cmdfunc(mtd, NAND_CMD_DEPLETE1, 0x0000, 0x0000);
this->cmdfunc(mtd, NAND_CMD_DEPLETE2, -1, -1);
/* Send the commands for device recovery, phase 2 */
this->cmdfunc(mtd, NAND_CMD_DEPLETE1, 0x0000, 0x0004);
this->cmdfunc(mtd, NAND_CMD_DEPLETE2, -1, -1);
}
#ifdef RTC_FROM4_HWECC
/*
* rtc_from4_enable_hwecc - hardware specific hardware ECC enable function
* @mtd: MTD device structure
* @mode: I/O mode; read or write
*
* enable hardware ECC for data read or write
*
*/
static void rtc_from4_enable_hwecc(struct mtd_info *mtd, int mode)
{
volatile unsigned short *rs_ecc_ctl = (volatile unsigned short *)(rtc_from4_fio_base + RTC_FROM4_RS_ECC_CTL);
unsigned short status;
switch (mode) {
case NAND_ECC_READ:
status = RTC_FROM4_RS_ECC_CTL_CLR | RTC_FROM4_RS_ECC_CTL_FD_E;
*rs_ecc_ctl = status;
break;
case NAND_ECC_READSYN:
status = 0x00;
*rs_ecc_ctl = status;
break;
case NAND_ECC_WRITE:
status = RTC_FROM4_RS_ECC_CTL_CLR | RTC_FROM4_RS_ECC_CTL_GEN | RTC_FROM4_RS_ECC_CTL_FD_E;
*rs_ecc_ctl = status;
break;
default:
BUG();
break;
}
}
/*
* rtc_from4_calculate_ecc - hardware specific code to read ECC code
* @mtd: MTD device structure
* @dat: buffer containing the data to generate ECC codes
* @ecc_code ECC codes calculated
*
* The ECC code is calculated by the FPGA. All we have to do is read the values
* from the FPGA registers.
*
* Note: We read from the inverted registers, since data is inverted before
* the code is calculated. So all 0xff data (blank page) results in all 0xff rs code
*
*/
static void rtc_from4_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code)
{
volatile unsigned short *rs_eccn = (volatile unsigned short *)(rtc_from4_fio_base + RTC_FROM4_RS_ECCN);
unsigned short value;
int i;
for (i = 0; i < 8; i++) {
value = *rs_eccn;
ecc_code[i] = (unsigned char)value;
rs_eccn++;
}
ecc_code[7] |= 0x0f; /* set the last four bits (not used) */
}
/*
* rtc_from4_correct_data - hardware specific code to correct data using ECC code
* @mtd: MTD device structure
* @buf: buffer containing the data to generate ECC codes
* @ecc1 ECC codes read
* @ecc2 ECC codes calculated
*
* The FPGA tells us fast, if there's an error or not. If no, we go back happy
* else we read the ecc results from the fpga and call the rs library to decode
* and hopefully correct the error.
*
*/
static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_char *ecc1, u_char *ecc2)
{
int i, j, res;
unsigned short status;
uint16_t par[6], syn[6];
uint8_t ecc[8];
volatile unsigned short *rs_ecc;
status = *((volatile unsigned short *)(rtc_from4_fio_base + RTC_FROM4_RS_ECC_CHK));
if (!(status & RTC_FROM4_RS_ECC_CHK_ERROR)) {
return 0;
}
/* Read the syndrome pattern from the FPGA and correct the bitorder */
rs_ecc = (volatile unsigned short *)(rtc_from4_fio_base + RTC_FROM4_RS_ECC);
for (i = 0; i < 8; i++) {
ecc[i] = bitrev8(*rs_ecc);
rs_ecc++;
}
/* convert into 6 10bit syndrome fields */
par[5] = rs_decoder->index_of[(((uint16_t) ecc[0] >> 0) & 0x0ff) | (((uint16_t) ecc[1] << 8) & 0x300)];
par[4] = rs_decoder->index_of[(((uint16_t) ecc[1] >> 2) & 0x03f) | (((uint16_t) ecc[2] << 6) & 0x3c0)];
par[3] = rs_decoder->index_of[(((uint16_t) ecc[2] >> 4) & 0x00f) | (((uint16_t) ecc[3] << 4) & 0x3f0)];
par[2] = rs_decoder->index_of[(((uint16_t) ecc[3] >> 6) & 0x003) | (((uint16_t) ecc[4] << 2) & 0x3fc)];
par[1] = rs_decoder->index_of[(((uint16_t) ecc[5] >> 0) & 0x0ff) | (((uint16_t) ecc[6] << 8) & 0x300)];
par[0] = (((uint16_t) ecc[6] >> 2) & 0x03f) | (((uint16_t) ecc[7] << 6) & 0x3c0);
/* Convert to computable syndrome */
for (i = 0; i < 6; i++) {
syn[i] = par[0];
for (j = 1; j < 6; j++)
if (par[j] != rs_decoder->nn)
syn[i] ^= rs_decoder->alpha_to[rs_modnn(rs_decoder, par[j] + i * j)];
/* Convert to index form */
syn[i] = rs_decoder->index_of[syn[i]];
}
/* Let the library code do its magic. */
res = decode_rs8(rs_decoder, (uint8_t *) buf, par, 512, syn, 0, NULL, 0xff, NULL);
if (res > 0) {
pr_debug("rtc_from4_correct_data: " "ECC corrected %d errors on read\n", res);
}
return res;
}
/**
* rtc_from4_errstat - perform additional error status checks
* @mtd: MTD device structure
* @this: NAND chip structure
* @state: state or the operation
* @status: status code returned from read status
* @page: startpage inside the chip, must be called with (page & this->pagemask)
*
* Perform additional error status checks on erase and write failures
* to determine if errors are correctable. For this device, correctable
* 1-bit errors on erase and write are considered acceptable.
*
* note: see pages 34..37 of data sheet for details.
*
*/
static int rtc_from4_errstat(struct mtd_info *mtd, struct nand_chip *this,
int state, int status, int page)
{
int er_stat = 0;
int rtn, retlen;
size_t len;
uint8_t *buf;
int i;
this->cmdfunc(mtd, NAND_CMD_STATUS_CLEAR, -1, -1);
if (state == FL_ERASING) {
for (i = 0; i < 4; i++) {
if (!(status & 1 << (i + 1)))
continue;
this->cmdfunc(mtd, (NAND_CMD_STATUS_ERROR + i + 1),
-1, -1);
rtn = this->read_byte(mtd);
this->cmdfunc(mtd, NAND_CMD_STATUS_RESET, -1, -1);
/* err_ecc_not_avail */
if (!(rtn & ERR_STAT_ECC_AVAILABLE))
er_stat |= 1 << (i + 1);
}
} else if (state == FL_WRITING) {
unsigned long corrected = mtd->ecc_stats.corrected;
/* single bank write logic */
this->cmdfunc(mtd, NAND_CMD_STATUS_ERROR, -1, -1);
rtn = this->read_byte(mtd);
this->cmdfunc(mtd, NAND_CMD_STATUS_RESET, -1, -1);
if (!(rtn & ERR_STAT_ECC_AVAILABLE)) {
/* err_ecc_not_avail */
er_stat |= 1 << 1;
goto out;
}
len = mtd->writesize;
buf = kmalloc(len, GFP_KERNEL);
if (!buf) {
er_stat = 1;
goto out;
}
/* recovery read */
rtn = nand_do_read(mtd, page, len, &retlen, buf);
/* if read failed or > 1-bit error corrected */
if (rtn || (mtd->ecc_stats.corrected - corrected) > 1)
er_stat |= 1 << 1;
kfree(buf);
}
out:
rtn = status;
if (er_stat == 0) { /* if ECC is available */
rtn = (status & ~NAND_STATUS_FAIL); /* clear the error bit */
}
return rtn;
}
#endif
/*
* Main initialization routine
*/
static int __init rtc_from4_init(void)
{
struct nand_chip *this;
unsigned short bcr1, bcr2, wcr2;
int i;
int ret;
/* Allocate memory for MTD device structure and private data */
rtc_from4_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL);
if (!rtc_from4_mtd) {
printk("Unable to allocate Renesas NAND MTD device structure.\n");
return -ENOMEM;
}
/* Get pointer to private data */
this = (struct nand_chip *)(&rtc_from4_mtd[1]);
/* Initialize structures */
memset(rtc_from4_mtd, 0, sizeof(struct mtd_info));
memset(this, 0, sizeof(struct nand_chip));
/* Link the private data with the MTD structure */
rtc_from4_mtd->priv = this;
rtc_from4_mtd->owner = THIS_MODULE;
/* set area 5 as PCMCIA mode to clear the spec of tDH(Data hold time;9ns min) */
bcr1 = *SH77X9_BCR1 & ~0x0002;
bcr1 |= 0x0002;
*SH77X9_BCR1 = bcr1;
/* set */
bcr2 = *SH77X9_BCR2 & ~0x0c00;
bcr2 |= 0x0800;
*SH77X9_BCR2 = bcr2;
/* set area 5 wait states */
wcr2 = *SH77X9_WCR2 & ~0x1c00;
wcr2 |= 0x1c00;
*SH77X9_WCR2 = wcr2;
/* Set address of NAND IO lines */
this->IO_ADDR_R = rtc_from4_fio_base;
this->IO_ADDR_W = rtc_from4_fio_base;
/* Set address of hardware control function */
this->cmd_ctrl = rtc_from4_hwcontrol;
/* Set address of chip select function */
this->select_chip = rtc_from4_nand_select_chip;
/* command delay time (in us) */
this->chip_delay = 100;
/* return the status of the Ready/Busy line */
this->dev_ready = rtc_from4_nand_device_ready;
#ifdef RTC_FROM4_HWECC
printk(KERN_INFO "rtc_from4_init: using hardware ECC detection.\n");
this->ecc.mode = NAND_ECC_HW_SYNDROME;
this->ecc.size = 512;
this->ecc.bytes = 8;
this->ecc.strength = 3;
/* return the status of extra status and ECC checks */
this->errstat = rtc_from4_errstat;
/* set the nand_oobinfo to support FPGA H/W error detection */
this->ecc.layout = &rtc_from4_nand_oobinfo;
this->ecc.hwctl = rtc_from4_enable_hwecc;
this->ecc.calculate = rtc_from4_calculate_ecc;
this->ecc.correct = rtc_from4_correct_data;
/* We could create the decoder on demand, if memory is a concern.
* This way we have it handy, if an error happens
*
* Symbolsize is 10 (bits)
* Primitve polynomial is x^10+x^3+1
* first consecutive root is 0
* primitve element to generate roots = 1
* generator polinomial degree = 6
*/
rs_decoder = init_rs(10, 0x409, 0, 1, 6);
if (!rs_decoder) {
printk(KERN_ERR "Could not create a RS decoder\n");
ret = -ENOMEM;
goto err_1;
}
#else
printk(KERN_INFO "rtc_from4_init: using software ECC detection.\n");
this->ecc.mode = NAND_ECC_SOFT;
#endif
/* set the bad block tables to support debugging */
this->bbt_td = &rtc_from4_bbt_main_descr;
this->bbt_md = &rtc_from4_bbt_mirror_descr;
/* Scan to find existence of the device */
if (nand_scan(rtc_from4_mtd, RTC_FROM4_MAX_CHIPS)) {
ret = -ENXIO;
goto err_2;
}
/* Perform 'device recovery' for each chip in case there was a power loss. */
for (i = 0; i < this->numchips; i++) {
deplete(rtc_from4_mtd, i);
}
#if RTC_FROM4_NO_VIRTBLOCKS
/* use a smaller erase block to minimize wasted space when a block is bad */
/* note: this uses eight times as much RAM as using the default and makes */
/* mounts take four times as long. */
rtc_from4_mtd->flags |= MTD_NO_VIRTBLOCKS;
#endif
/* Register the partitions */
ret = mtd_device_register(rtc_from4_mtd, partition_info,
NUM_PARTITIONS);
if (ret)
goto err_3;
/* Return happy */
return 0;
err_3:
nand_release(rtc_from4_mtd);
err_2:
free_rs(rs_decoder);
err_1:
kfree(rtc_from4_mtd);
return ret;
}
module_init(rtc_from4_init);
/*
* Clean up routine
*/
static void __exit rtc_from4_cleanup(void)
{
/* Release resource, unregister partitions */
nand_release(rtc_from4_mtd);
/* Free the MTD device structure */
kfree(rtc_from4_mtd);
#ifdef RTC_FROM4_HWECC
/* Free the reed solomon resources */
if (rs_decoder) {
free_rs(rs_decoder);
}
#endif
}
module_exit(rtc_from4_cleanup);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("d.marlin <dmarlin@redhat.com");
MODULE_DESCRIPTION("Board-specific glue layer for AG-AND flash on Renesas FROM_BOARD4");

View File

@ -1081,7 +1081,6 @@ static struct sh_flctl_platform_data *flctl_parse_dt(struct device *dev)
return pdata;
}
#else /* CONFIG_OF */
#define of_flctl_match NULL
static struct sh_flctl_platform_data *flctl_parse_dt(struct device *dev)
{
return NULL;
@ -1219,22 +1218,11 @@ static struct platform_driver flctl_driver = {
.driver = {
.name = "sh_flctl",
.owner = THIS_MODULE,
.of_match_table = of_flctl_match,
.of_match_table = of_match_ptr(of_flctl_match),
},
};
static int __init flctl_nand_init(void)
{
return platform_driver_probe(&flctl_driver, flctl_probe);
}
static void __exit flctl_nand_cleanup(void)
{
platform_driver_unregister(&flctl_driver);
}
module_init(flctl_nand_init);
module_exit(flctl_nand_cleanup);
module_platform_driver_probe(flctl_driver, flctl_probe);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Yoshihiro Shimoda");

View File

@ -9,6 +9,7 @@
#include <linux/kernel.h>
#include <linux/mtd/nand.h>
#include <linux/module.h>
#include <linux/sizes.h>
#include "sm_common.h"
static struct nand_ecclayout nand_oob_sm = {
@ -67,44 +68,37 @@ static int sm_block_markbad(struct mtd_info *mtd, loff_t ofs)
return error;
}
static struct nand_flash_dev nand_smartmedia_flash_ids[] = {
{"SmartMedia 1MiB 5V", 0x6e, 256, 1, 0x1000, 0},
{"SmartMedia 1MiB 3,3V", 0xe8, 256, 1, 0x1000, 0},
{"SmartMedia 1MiB 3,3V", 0xec, 256, 1, 0x1000, 0},
{"SmartMedia 2MiB 3,3V", 0xea, 256, 2, 0x1000, 0},
{"SmartMedia 2MiB 5V", 0x64, 256, 2, 0x1000, 0},
{"SmartMedia 2MiB 3,3V ROM", 0x5d, 512, 2, 0x2000, NAND_ROM},
{"SmartMedia 4MiB 3,3V", 0xe3, 512, 4, 0x2000, 0},
{"SmartMedia 4MiB 3,3/5V", 0xe5, 512, 4, 0x2000, 0},
{"SmartMedia 4MiB 5V", 0x6b, 512, 4, 0x2000, 0},
{"SmartMedia 4MiB 3,3V ROM", 0xd5, 512, 4, 0x2000, NAND_ROM},
{"SmartMedia 8MiB 3,3V", 0xe6, 512, 8, 0x2000, 0},
{"SmartMedia 8MiB 3,3V ROM", 0xd6, 512, 8, 0x2000, NAND_ROM},
{"SmartMedia 16MiB 3,3V", 0x73, 512, 16, 0x4000, 0},
{"SmartMedia 16MiB 3,3V ROM", 0x57, 512, 16, 0x4000, NAND_ROM},
{"SmartMedia 32MiB 3,3V", 0x75, 512, 32, 0x4000, 0},
{"SmartMedia 32MiB 3,3V ROM", 0x58, 512, 32, 0x4000, NAND_ROM},
{"SmartMedia 64MiB 3,3V", 0x76, 512, 64, 0x4000, 0},
{"SmartMedia 64MiB 3,3V ROM", 0xd9, 512, 64, 0x4000, NAND_ROM},
{"SmartMedia 128MiB 3,3V", 0x79, 512, 128, 0x4000, 0},
{"SmartMedia 128MiB 3,3V ROM", 0xda, 512, 128, 0x4000, NAND_ROM},
{"SmartMedia 256MiB 3,3V", 0x71, 512, 256, 0x4000 },
{"SmartMedia 256MiB 3,3V ROM", 0x5b, 512, 256, 0x4000, NAND_ROM},
{NULL,}
LEGACY_ID_NAND("SmartMedia 2MiB 3,3V ROM", 0x5d, 2, SZ_8K, NAND_ROM),
LEGACY_ID_NAND("SmartMedia 4MiB 3,3V", 0xe3, 4, SZ_8K, 0),
LEGACY_ID_NAND("SmartMedia 4MiB 3,3/5V", 0xe5, 4, SZ_8K, 0),
LEGACY_ID_NAND("SmartMedia 4MiB 5V", 0x6b, 4, SZ_8K, 0),
LEGACY_ID_NAND("SmartMedia 4MiB 3,3V ROM", 0xd5, 4, SZ_8K, NAND_ROM),
LEGACY_ID_NAND("SmartMedia 8MiB 3,3V", 0xe6, 8, SZ_8K, 0),
LEGACY_ID_NAND("SmartMedia 8MiB 3,3V ROM", 0xd6, 8, SZ_8K, NAND_ROM),
LEGACY_ID_NAND("SmartMedia 16MiB 3,3V", 0x73, 16, SZ_16K, 0),
LEGACY_ID_NAND("SmartMedia 16MiB 3,3V ROM", 0x57, 16, SZ_16K, NAND_ROM),
LEGACY_ID_NAND("SmartMedia 32MiB 3,3V", 0x75, 32, SZ_16K, 0),
LEGACY_ID_NAND("SmartMedia 32MiB 3,3V ROM", 0x58, 32, SZ_16K, NAND_ROM),
LEGACY_ID_NAND("SmartMedia 64MiB 3,3V", 0x76, 64, SZ_16K, 0),
LEGACY_ID_NAND("SmartMedia 64MiB 3,3V ROM", 0xd9, 64, SZ_16K, NAND_ROM),
LEGACY_ID_NAND("SmartMedia 128MiB 3,3V", 0x79, 128, SZ_16K, 0),
LEGACY_ID_NAND("SmartMedia 128MiB 3,3V ROM", 0xda, 128, SZ_16K, NAND_ROM),
LEGACY_ID_NAND("SmartMedia 256MiB 3, 3V", 0x71, 256, SZ_16K, 0),
LEGACY_ID_NAND("SmartMedia 256MiB 3,3V ROM", 0x5b, 256, SZ_16K, NAND_ROM),
{NULL}
};
static struct nand_flash_dev nand_xd_flash_ids[] = {
{"xD 16MiB 3,3V", 0x73, 512, 16, 0x4000, 0},
{"xD 32MiB 3,3V", 0x75, 512, 32, 0x4000, 0},
{"xD 64MiB 3,3V", 0x76, 512, 64, 0x4000, 0},
{"xD 128MiB 3,3V", 0x79, 512, 128, 0x4000, 0},
{"xD 256MiB 3,3V", 0x71, 512, 256, 0x4000, NAND_BROKEN_XD},
{"xD 512MiB 3,3V", 0xdc, 512, 512, 0x4000, NAND_BROKEN_XD},
{"xD 1GiB 3,3V", 0xd3, 512, 1024, 0x4000, NAND_BROKEN_XD},
{"xD 2GiB 3,3V", 0xd5, 512, 2048, 0x4000, NAND_BROKEN_XD},
{NULL,}
LEGACY_ID_NAND("xD 16MiB 3,3V", 0x73, 16, SZ_16K, 0),
LEGACY_ID_NAND("xD 32MiB 3,3V", 0x75, 32, SZ_16K, 0),
LEGACY_ID_NAND("xD 64MiB 3,3V", 0x76, 64, SZ_16K, 0),
LEGACY_ID_NAND("xD 128MiB 3,3V", 0x79, 128, SZ_16K, 0),
LEGACY_ID_NAND("xD 256MiB 3,3V", 0x71, 256, SZ_16K, NAND_BROKEN_XD),
LEGACY_ID_NAND("xD 512MiB 3,3V", 0xdc, 512, SZ_16K, NAND_BROKEN_XD),
LEGACY_ID_NAND("xD 1GiB 3,3V", 0xd3, 1024, SZ_16K, NAND_BROKEN_XD),
LEGACY_ID_NAND("xD 2GiB 3,3V", 0xd5, 2048, SZ_16K, NAND_BROKEN_XD),
{NULL}
};
int sm_register_device(struct mtd_info *mtd, int smartmedia)

View File

@ -427,18 +427,7 @@ static struct platform_driver txx9ndfmc_driver = {
},
};
static int __init txx9ndfmc_init(void)
{
return platform_driver_probe(&txx9ndfmc_driver, txx9ndfmc_probe);
}
static void __exit txx9ndfmc_exit(void)
{
platform_driver_unregister(&txx9ndfmc_driver);
}
module_init(txx9ndfmc_init);
module_exit(txx9ndfmc_exit);
module_platform_driver_probe(txx9ndfmc_driver, txx9ndfmc_probe);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("TXx9 SoC NAND flash controller driver");

View File

@ -55,6 +55,7 @@ static int parse_ofpart_partitions(struct mtd_info *master,
while ((pp = of_get_next_child(node, pp))) {
const __be32 *reg;
int len;
int a_cells, s_cells;
reg = of_get_property(pp, "reg", &len);
if (!reg) {
@ -62,8 +63,10 @@ static int parse_ofpart_partitions(struct mtd_info *master,
continue;
}
(*pparts)[i].offset = be32_to_cpu(reg[0]);
(*pparts)[i].size = be32_to_cpu(reg[1]);
a_cells = of_n_addr_cells(pp);
s_cells = of_n_size_cells(pp);
(*pparts)[i].offset = of_read_number(reg, a_cells);
(*pparts)[i].size = of_read_number(reg + a_cells, s_cells);
partname = of_get_property(pp, "label", &len);
if (!partname)

View File

@ -40,7 +40,6 @@ config MTD_ONENAND_SAMSUNG
config MTD_ONENAND_OTP
bool "OneNAND OTP Support"
select HAVE_MTD_OTP
help
One Block of the NAND Flash Array memory is reserved as
a One-Time Programmable Block memory area.
@ -68,10 +67,4 @@ config MTD_ONENAND_2X_PROGRAM
And more recent chips
config MTD_ONENAND_SIM
tristate "OneNAND simulator support"
help
The simulator may simulate various OneNAND flash chips for the
OneNAND MTD layer.
endif # MTD_ONENAND

View File

@ -10,7 +10,4 @@ obj-$(CONFIG_MTD_ONENAND_GENERIC) += generic.o
obj-$(CONFIG_MTD_ONENAND_OMAP2) += omap2.o
obj-$(CONFIG_MTD_ONENAND_SAMSUNG) += samsung.o
# Simulator
obj-$(CONFIG_MTD_ONENAND_SIM) += onenand_sim.o
onenand-objs = onenand_base.o onenand_bbt.o

View File

@ -832,19 +832,7 @@ static struct platform_driver omap2_onenand_driver = {
},
};
static int __init omap2_onenand_init(void)
{
printk(KERN_INFO "OneNAND driver initializing\n");
return platform_driver_register(&omap2_onenand_driver);
}
static void __exit omap2_onenand_exit(void)
{
platform_driver_unregister(&omap2_onenand_driver);
}
module_init(omap2_onenand_init);
module_exit(omap2_onenand_exit);
module_platform_driver(omap2_onenand_driver);
MODULE_ALIAS("platform:" DRIVER_NAME);
MODULE_LICENSE("GPL");

View File

@ -1,564 +0,0 @@
/*
* linux/drivers/mtd/onenand/onenand_sim.c
*
* The OneNAND simulator
*
* Copyright © 2005-2007 Samsung Electronics
* Kyungmin Park <kyungmin.park@samsung.com>
*
* Vishak G <vishak.g at samsung.com>, Rohit Hagargundgi <h.rohit at samsung.com>
* Flex-OneNAND simulator support
* Copyright (C) Samsung Electronics, 2008
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/vmalloc.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/onenand.h>
#include <linux/io.h>
#ifndef CONFIG_ONENAND_SIM_MANUFACTURER
#define CONFIG_ONENAND_SIM_MANUFACTURER 0xec
#endif
#ifndef CONFIG_ONENAND_SIM_DEVICE_ID
#define CONFIG_ONENAND_SIM_DEVICE_ID 0x04
#endif
#define CONFIG_FLEXONENAND ((CONFIG_ONENAND_SIM_DEVICE_ID >> 9) & 1)
#ifndef CONFIG_ONENAND_SIM_VERSION_ID
#define CONFIG_ONENAND_SIM_VERSION_ID 0x1e
#endif
#ifndef CONFIG_ONENAND_SIM_TECHNOLOGY_ID
#define CONFIG_ONENAND_SIM_TECHNOLOGY_ID CONFIG_FLEXONENAND
#endif
/* Initial boundary values for Flex-OneNAND Simulator */
#ifndef CONFIG_FLEXONENAND_SIM_DIE0_BOUNDARY
#define CONFIG_FLEXONENAND_SIM_DIE0_BOUNDARY 0x01
#endif
#ifndef CONFIG_FLEXONENAND_SIM_DIE1_BOUNDARY
#define CONFIG_FLEXONENAND_SIM_DIE1_BOUNDARY 0x01
#endif
static int manuf_id = CONFIG_ONENAND_SIM_MANUFACTURER;
static int device_id = CONFIG_ONENAND_SIM_DEVICE_ID;
static int version_id = CONFIG_ONENAND_SIM_VERSION_ID;
static int technology_id = CONFIG_ONENAND_SIM_TECHNOLOGY_ID;
static int boundary[] = {
CONFIG_FLEXONENAND_SIM_DIE0_BOUNDARY,
CONFIG_FLEXONENAND_SIM_DIE1_BOUNDARY,
};
struct onenand_flash {
void __iomem *base;
void __iomem *data;
};
#define ONENAND_CORE(flash) (flash->data)
#define ONENAND_CORE_SPARE(flash, this, offset) \
((flash->data) + (this->chipsize) + (offset >> 5))
#define ONENAND_MAIN_AREA(this, offset) \
(this->base + ONENAND_DATARAM + offset)
#define ONENAND_SPARE_AREA(this, offset) \
(this->base + ONENAND_SPARERAM + offset)
#define ONENAND_GET_WP_STATUS(this) \
(readw(this->base + ONENAND_REG_WP_STATUS))
#define ONENAND_SET_WP_STATUS(v, this) \
(writew(v, this->base + ONENAND_REG_WP_STATUS))
/* It has all 0xff chars */
#define MAX_ONENAND_PAGESIZE (4096 + 128)
static unsigned char *ffchars;
#if CONFIG_FLEXONENAND
#define PARTITION_NAME "Flex-OneNAND simulator partition"
#else
#define PARTITION_NAME "OneNAND simulator partition"
#endif
static struct mtd_partition os_partitions[] = {
{
.name = PARTITION_NAME,
.offset = 0,
.size = MTDPART_SIZ_FULL,
},
};
/*
* OneNAND simulator mtd
*/
struct onenand_info {
struct mtd_info mtd;
struct mtd_partition *parts;
struct onenand_chip onenand;
struct onenand_flash flash;
};
static struct onenand_info *info;
#define DPRINTK(format, args...) \
do { \
printk(KERN_DEBUG "%s[%d]: " format "\n", __func__, \
__LINE__, ##args); \
} while (0)
/**
* onenand_lock_handle - Handle Lock scheme
* @this: OneNAND device structure
* @cmd: The command to be sent
*
* Send lock command to OneNAND device.
* The lock scheme depends on chip type.
*/
static void onenand_lock_handle(struct onenand_chip *this, int cmd)
{
int block_lock_scheme;
int status;
status = ONENAND_GET_WP_STATUS(this);
block_lock_scheme = !(this->options & ONENAND_HAS_CONT_LOCK);
switch (cmd) {
case ONENAND_CMD_UNLOCK:
case ONENAND_CMD_UNLOCK_ALL:
if (block_lock_scheme)
ONENAND_SET_WP_STATUS(ONENAND_WP_US, this);
else
ONENAND_SET_WP_STATUS(status | ONENAND_WP_US, this);
break;
case ONENAND_CMD_LOCK:
if (block_lock_scheme)
ONENAND_SET_WP_STATUS(ONENAND_WP_LS, this);
else
ONENAND_SET_WP_STATUS(status | ONENAND_WP_LS, this);
break;
case ONENAND_CMD_LOCK_TIGHT:
if (block_lock_scheme)
ONENAND_SET_WP_STATUS(ONENAND_WP_LTS, this);
else
ONENAND_SET_WP_STATUS(status | ONENAND_WP_LTS, this);
break;
default:
break;
}
}
/**
* onenand_bootram_handle - Handle BootRAM area
* @this: OneNAND device structure
* @cmd: The command to be sent
*
* Emulate BootRAM area. It is possible to do basic operation using BootRAM.
*/
static void onenand_bootram_handle(struct onenand_chip *this, int cmd)
{
switch (cmd) {
case ONENAND_CMD_READID:
writew(manuf_id, this->base);
writew(device_id, this->base + 2);
writew(version_id, this->base + 4);
break;
default:
/* REVIST: Handle other commands */
break;
}
}
/**
* onenand_update_interrupt - Set interrupt register
* @this: OneNAND device structure
* @cmd: The command to be sent
*
* Update interrupt register. The status depends on command.
*/
static void onenand_update_interrupt(struct onenand_chip *this, int cmd)
{
int interrupt = ONENAND_INT_MASTER;
switch (cmd) {
case ONENAND_CMD_READ:
case ONENAND_CMD_READOOB:
interrupt |= ONENAND_INT_READ;
break;
case ONENAND_CMD_PROG:
case ONENAND_CMD_PROGOOB:
interrupt |= ONENAND_INT_WRITE;
break;
case ONENAND_CMD_ERASE:
interrupt |= ONENAND_INT_ERASE;
break;
case ONENAND_CMD_RESET:
interrupt |= ONENAND_INT_RESET;
break;
default:
break;
}
writew(interrupt, this->base + ONENAND_REG_INTERRUPT);
}
/**
* onenand_check_overwrite - Check if over-write happened
* @dest: The destination pointer
* @src: The source pointer
* @count: The length to be check
*
* Returns: 0 on same, otherwise 1
*
* Compare the source with destination
*/
static int onenand_check_overwrite(void *dest, void *src, size_t count)
{
unsigned int *s = (unsigned int *) src;
unsigned int *d = (unsigned int *) dest;
int i;
count >>= 2;
for (i = 0; i < count; i++)
if ((*s++ ^ *d++) != 0)
return 1;
return 0;
}
/**
* onenand_data_handle - Handle OneNAND Core and DataRAM
* @this: OneNAND device structure
* @cmd: The command to be sent
* @dataram: Which dataram used
* @offset: The offset to OneNAND Core
*
* Copy data from OneNAND Core to DataRAM (read)
* Copy data from DataRAM to OneNAND Core (write)
* Erase the OneNAND Core (erase)
*/
static void onenand_data_handle(struct onenand_chip *this, int cmd,
int dataram, unsigned int offset)
{
struct mtd_info *mtd = &info->mtd;
struct onenand_flash *flash = this->priv;
int main_offset, spare_offset, die = 0;
void __iomem *src;
void __iomem *dest;
unsigned int i;
static int pi_operation;
int erasesize, rgn;
if (dataram) {
main_offset = mtd->writesize;
spare_offset = mtd->oobsize;
} else {
main_offset = 0;
spare_offset = 0;
}
if (pi_operation) {
die = readw(this->base + ONENAND_REG_START_ADDRESS2);
die >>= ONENAND_DDP_SHIFT;
}
switch (cmd) {
case FLEXONENAND_CMD_PI_ACCESS:
pi_operation = 1;
break;
case ONENAND_CMD_RESET:
pi_operation = 0;
break;
case ONENAND_CMD_READ:
src = ONENAND_CORE(flash) + offset;
dest = ONENAND_MAIN_AREA(this, main_offset);
if (pi_operation) {
writew(boundary[die], this->base + ONENAND_DATARAM);
break;
}
memcpy(dest, src, mtd->writesize);
/* Fall through */
case ONENAND_CMD_READOOB:
src = ONENAND_CORE_SPARE(flash, this, offset);
dest = ONENAND_SPARE_AREA(this, spare_offset);
memcpy(dest, src, mtd->oobsize);
break;
case ONENAND_CMD_PROG:
src = ONENAND_MAIN_AREA(this, main_offset);
dest = ONENAND_CORE(flash) + offset;
if (pi_operation) {
boundary[die] = readw(this->base + ONENAND_DATARAM);
break;
}
/* To handle partial write */
for (i = 0; i < (1 << mtd->subpage_sft); i++) {
int off = i * this->subpagesize;
if (!memcmp(src + off, ffchars, this->subpagesize))
continue;
if (memcmp(dest + off, ffchars, this->subpagesize) &&
onenand_check_overwrite(dest + off, src + off, this->subpagesize))
printk(KERN_ERR "over-write happened at 0x%08x\n", offset);
memcpy(dest + off, src + off, this->subpagesize);
}
/* Fall through */
case ONENAND_CMD_PROGOOB:
src = ONENAND_SPARE_AREA(this, spare_offset);
/* Check all data is 0xff chars */
if (!memcmp(src, ffchars, mtd->oobsize))
break;
dest = ONENAND_CORE_SPARE(flash, this, offset);
if (memcmp(dest, ffchars, mtd->oobsize) &&
onenand_check_overwrite(dest, src, mtd->oobsize))
printk(KERN_ERR "OOB: over-write happened at 0x%08x\n",
offset);
memcpy(dest, src, mtd->oobsize);
break;
case ONENAND_CMD_ERASE:
if (pi_operation)
break;
if (FLEXONENAND(this)) {
rgn = flexonenand_region(mtd, offset);
erasesize = mtd->eraseregions[rgn].erasesize;
} else
erasesize = mtd->erasesize;
memset(ONENAND_CORE(flash) + offset, 0xff, erasesize);
memset(ONENAND_CORE_SPARE(flash, this, offset), 0xff,
(erasesize >> 5));
break;
default:
break;
}
}
/**
* onenand_command_handle - Handle command
* @this: OneNAND device structure
* @cmd: The command to be sent
*
* Emulate OneNAND command.
*/
static void onenand_command_handle(struct onenand_chip *this, int cmd)
{
unsigned long offset = 0;
int block = -1, page = -1, bufferram = -1;
int dataram = 0;
switch (cmd) {
case ONENAND_CMD_UNLOCK:
case ONENAND_CMD_LOCK:
case ONENAND_CMD_LOCK_TIGHT:
case ONENAND_CMD_UNLOCK_ALL:
onenand_lock_handle(this, cmd);
break;
case ONENAND_CMD_BUFFERRAM:
/* Do nothing */
return;
default:
block = (int) readw(this->base + ONENAND_REG_START_ADDRESS1);
if (block & (1 << ONENAND_DDP_SHIFT)) {
block &= ~(1 << ONENAND_DDP_SHIFT);
/* The half of chip block */
block += this->chipsize >> (this->erase_shift + 1);
}
if (cmd == ONENAND_CMD_ERASE)
break;
page = (int) readw(this->base + ONENAND_REG_START_ADDRESS8);
page = (page >> ONENAND_FPA_SHIFT);
bufferram = (int) readw(this->base + ONENAND_REG_START_BUFFER);
bufferram >>= ONENAND_BSA_SHIFT;
bufferram &= ONENAND_BSA_DATARAM1;
dataram = (bufferram == ONENAND_BSA_DATARAM1) ? 1 : 0;
break;
}
if (block != -1)
offset = onenand_addr(this, block);
if (page != -1)
offset += page << this->page_shift;
onenand_data_handle(this, cmd, dataram, offset);
onenand_update_interrupt(this, cmd);
}
/**
* onenand_writew - [OneNAND Interface] Emulate write operation
* @value: value to write
* @addr: address to write
*
* Write OneNAND register with value
*/
static void onenand_writew(unsigned short value, void __iomem * addr)
{
struct onenand_chip *this = info->mtd.priv;
/* BootRAM handling */
if (addr < this->base + ONENAND_DATARAM) {
onenand_bootram_handle(this, value);
return;
}
/* Command handling */
if (addr == this->base + ONENAND_REG_COMMAND)
onenand_command_handle(this, value);
writew(value, addr);
}
/**
* flash_init - Initialize OneNAND simulator
* @flash: OneNAND simulator data strucutres
*
* Initialize OneNAND simulator.
*/
static int __init flash_init(struct onenand_flash *flash)
{
int density, size;
int buffer_size;
flash->base = kzalloc(131072, GFP_KERNEL);
if (!flash->base) {
printk(KERN_ERR "Unable to allocate base address.\n");
return -ENOMEM;
}
density = device_id >> ONENAND_DEVICE_DENSITY_SHIFT;
density &= ONENAND_DEVICE_DENSITY_MASK;
size = ((16 << 20) << density);
ONENAND_CORE(flash) = vmalloc(size + (size >> 5));
if (!ONENAND_CORE(flash)) {
printk(KERN_ERR "Unable to allocate nand core address.\n");
kfree(flash->base);
return -ENOMEM;
}
memset(ONENAND_CORE(flash), 0xff, size + (size >> 5));
/* Setup registers */
writew(manuf_id, flash->base + ONENAND_REG_MANUFACTURER_ID);
writew(device_id, flash->base + ONENAND_REG_DEVICE_ID);
writew(version_id, flash->base + ONENAND_REG_VERSION_ID);
writew(technology_id, flash->base + ONENAND_REG_TECHNOLOGY);
if (density < 2 && (!CONFIG_FLEXONENAND))
buffer_size = 0x0400; /* 1KiB page */
else
buffer_size = 0x0800; /* 2KiB page */
writew(buffer_size, flash->base + ONENAND_REG_DATA_BUFFER_SIZE);
return 0;
}
/**
* flash_exit - Clean up OneNAND simulator
* @flash: OneNAND simulator data structures
*
* Clean up OneNAND simulator.
*/
static void flash_exit(struct onenand_flash *flash)
{
vfree(ONENAND_CORE(flash));
kfree(flash->base);
}
static int __init onenand_sim_init(void)
{
/* Allocate all 0xff chars pointer */
ffchars = kmalloc(MAX_ONENAND_PAGESIZE, GFP_KERNEL);
if (!ffchars) {
printk(KERN_ERR "Unable to allocate ff chars.\n");
return -ENOMEM;
}
memset(ffchars, 0xff, MAX_ONENAND_PAGESIZE);
/* Allocate OneNAND simulator mtd pointer */
info = kzalloc(sizeof(struct onenand_info), GFP_KERNEL);
if (!info) {
printk(KERN_ERR "Unable to allocate core structures.\n");
kfree(ffchars);
return -ENOMEM;
}
/* Override write_word function */
info->onenand.write_word = onenand_writew;
if (flash_init(&info->flash)) {
printk(KERN_ERR "Unable to allocate flash.\n");
kfree(ffchars);
kfree(info);
return -ENOMEM;
}
info->parts = os_partitions;
info->onenand.base = info->flash.base;
info->onenand.priv = &info->flash;
info->mtd.name = "OneNAND simulator";
info->mtd.priv = &info->onenand;
info->mtd.owner = THIS_MODULE;
if (onenand_scan(&info->mtd, 1)) {
flash_exit(&info->flash);
kfree(ffchars);
kfree(info);
return -ENXIO;
}
mtd_device_register(&info->mtd, info->parts,
ARRAY_SIZE(os_partitions));
return 0;
}
static void __exit onenand_sim_exit(void)
{
struct onenand_chip *this = info->mtd.priv;
struct onenand_flash *flash = this->priv;
onenand_release(&info->mtd);
flash_exit(flash);
kfree(ffchars);
kfree(info);
}
module_init(onenand_sim_init);
module_exit(onenand_sim_exit);
MODULE_AUTHOR("Kyungmin Park <kyungmin.park@samsung.com>");
MODULE_DESCRIPTION("The OneNAND flash simulator");
MODULE_LICENSE("GPL");

View File

@ -18,7 +18,7 @@
#include "ssb_private.h"
static const char *part_probes[] = { "bcm47xxpart", NULL };
static const char * const part_probes[] = { "bcm47xxpart", NULL };
static struct physmap_flash_data ssb_pflash_data = {
.part_probe_types = part_probes,

View File

@ -362,10 +362,10 @@ struct mtd_partition;
struct mtd_part_parser_data;
extern int mtd_device_parse_register(struct mtd_info *mtd,
const char **part_probe_types,
struct mtd_part_parser_data *parser_data,
const struct mtd_partition *defparts,
int defnr_parts);
const char * const *part_probe_types,
struct mtd_part_parser_data *parser_data,
const struct mtd_partition *defparts,
int defnr_parts);
#define mtd_device_register(master, parts, nr_parts) \
mtd_device_parse_register(master, NULL, NULL, parts, nr_parts)
extern int mtd_device_unregister(struct mtd_info *master);

View File

@ -86,7 +86,6 @@ extern int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
#define NAND_CMD_READOOB 0x50
#define NAND_CMD_ERASE1 0x60
#define NAND_CMD_STATUS 0x70
#define NAND_CMD_STATUS_MULTI 0x71
#define NAND_CMD_SEQIN 0x80
#define NAND_CMD_RNDIN 0x85
#define NAND_CMD_READID 0x90
@ -105,25 +104,6 @@ extern int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
#define NAND_CMD_RNDOUTSTART 0xE0
#define NAND_CMD_CACHEDPROG 0x15
/* Extended commands for AG-AND device */
/*
* Note: the command for NAND_CMD_DEPLETE1 is really 0x00 but
* there is no way to distinguish that from NAND_CMD_READ0
* until the remaining sequence of commands has been completed
* so add a high order bit and mask it off in the command.
*/
#define NAND_CMD_DEPLETE1 0x100
#define NAND_CMD_DEPLETE2 0x38
#define NAND_CMD_STATUS_MULTI 0x71
#define NAND_CMD_STATUS_ERROR 0x72
/* multi-bank error status (banks 0-3) */
#define NAND_CMD_STATUS_ERROR0 0x73
#define NAND_CMD_STATUS_ERROR1 0x74
#define NAND_CMD_STATUS_ERROR2 0x75
#define NAND_CMD_STATUS_ERROR3 0x76
#define NAND_CMD_STATUS_RESET 0x7f
#define NAND_CMD_STATUS_CLEAR 0xff
#define NAND_CMD_NONE -1
/* Status bits */
@ -165,28 +145,8 @@ typedef enum {
*/
/* Buswidth is 16 bit */
#define NAND_BUSWIDTH_16 0x00000002
/* Device supports partial programming without padding */
#define NAND_NO_PADDING 0x00000004
/* Chip has cache program function */
#define NAND_CACHEPRG 0x00000008
/* Chip has copy back function */
#define NAND_COPYBACK 0x00000010
/*
* AND Chip which has 4 banks and a confusing page / block
* assignment. See Renesas datasheet for further information.
*/
#define NAND_IS_AND 0x00000020
/*
* Chip has a array of 4 pages which can be read without
* additional ready /busy waits.
*/
#define NAND_4PAGE_ARRAY 0x00000040
/*
* Chip requires that BBT is periodically rewritten to prevent
* bits from adjacent blocks from 'leaking' in altering data.
* This happens with the Renesas AG-AND chips, possibly others.
*/
#define BBT_AUTO_REFRESH 0x00000080
/*
* Chip requires ready check on read (for auto-incremented sequential read).
* True only for small page devices; large page devices do not support
@ -207,13 +167,10 @@ typedef enum {
#define NAND_SUBPAGE_READ 0x00001000
/* Options valid for Samsung large page devices */
#define NAND_SAMSUNG_LP_OPTIONS \
(NAND_NO_PADDING | NAND_CACHEPRG | NAND_COPYBACK)
#define NAND_SAMSUNG_LP_OPTIONS NAND_CACHEPRG
/* Macros to identify the above */
#define NAND_MUST_PAD(chip) (!(chip->options & NAND_NO_PADDING))
#define NAND_HAS_CACHEPROG(chip) ((chip->options & NAND_CACHEPRG))
#define NAND_HAS_COPYBACK(chip) ((chip->options & NAND_COPYBACK))
#define NAND_HAS_SUBPAGE_READ(chip) ((chip->options & NAND_SUBPAGE_READ))
/* Non chip related options */
@ -361,6 +318,7 @@ struct nand_hw_control {
* any single ECC step, 0 if bitflips uncorrectable, -EIO hw error
* @read_subpage: function to read parts of the page covered by ECC;
* returns same as read_page()
* @write_subpage: function to write parts of the page covered by ECC.
* @write_page: function to write a page according to the ECC generator
* requirements.
* @write_oob_raw: function to write chip OOB data without ECC
@ -392,6 +350,9 @@ struct nand_ecc_ctrl {
uint8_t *buf, int oob_required, int page);
int (*read_subpage)(struct mtd_info *mtd, struct nand_chip *chip,
uint32_t offs, uint32_t len, uint8_t *buf);
int (*write_subpage)(struct mtd_info *mtd, struct nand_chip *chip,
uint32_t offset, uint32_t data_len,
const uint8_t *data_buf, int oob_required);
int (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,
const uint8_t *buf, int oob_required);
int (*write_oob_raw)(struct mtd_info *mtd, struct nand_chip *chip,
@ -527,8 +488,8 @@ struct nand_chip {
int (*errstat)(struct mtd_info *mtd, struct nand_chip *this, int state,
int status, int page);
int (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,
const uint8_t *buf, int oob_required, int page,
int cached, int raw);
uint32_t offset, int data_len, const uint8_t *buf,
int oob_required, int page, int cached, int raw);
int (*onfi_set_features)(struct mtd_info *mtd, struct nand_chip *chip,
int feature_addr, uint8_t *subfeature_para);
int (*onfi_get_features)(struct mtd_info *mtd, struct nand_chip *chip,
@ -589,25 +550,65 @@ struct nand_chip {
#define NAND_MFR_MACRONIX 0xc2
#define NAND_MFR_EON 0x92
/* The maximum expected count of bytes in the NAND ID sequence */
#define NAND_MAX_ID_LEN 8
/*
* A helper for defining older NAND chips where the second ID byte fully
* defined the chip, including the geometry (chip size, eraseblock size, page
* size). All these chips have 512 bytes NAND page size.
*/
#define LEGACY_ID_NAND(nm, devid, chipsz, erasesz, opts) \
{ .name = (nm), {{ .dev_id = (devid) }}, .pagesize = 512, \
.chipsize = (chipsz), .erasesize = (erasesz), .options = (opts) }
/*
* A helper for defining newer chips which report their page size and
* eraseblock size via the extended ID bytes.
*
* The real difference between LEGACY_ID_NAND and EXTENDED_ID_NAND is that with
* EXTENDED_ID_NAND, manufacturers overloaded the same device ID so that the
* device ID now only represented a particular total chip size (and voltage,
* buswidth), and the page size, eraseblock size, and OOB size could vary while
* using the same device ID.
*/
#define EXTENDED_ID_NAND(nm, devid, chipsz, opts) \
{ .name = (nm), {{ .dev_id = (devid) }}, .chipsize = (chipsz), \
.options = (opts) }
/**
* struct nand_flash_dev - NAND Flash Device ID Structure
* @name: Identify the device type
* @id: device ID code
* @pagesize: Pagesize in bytes. Either 256 or 512 or 0
* If the pagesize is 0, then the real pagesize
* and the eraseize are determined from the
* extended id bytes in the chip
* @erasesize: Size of an erase block in the flash device.
* @chipsize: Total chipsize in Mega Bytes
* @options: Bitfield to store chip relevant options
* @name: a human-readable name of the NAND chip
* @dev_id: the device ID (the second byte of the full chip ID array)
* @mfr_id: manufecturer ID part of the full chip ID array (refers the same
* memory address as @id[0])
* @dev_id: device ID part of the full chip ID array (refers the same memory
* address as @id[1])
* @id: full device ID array
* @pagesize: size of the NAND page in bytes; if 0, then the real page size (as
* well as the eraseblock size) is determined from the extended NAND
* chip ID array)
* @chipsize: total chip size in MiB
* @erasesize: eraseblock size in bytes (determined from the extended ID if 0)
* @options: stores various chip bit options
* @id_len: The valid length of the @id.
* @oobsize: OOB size
*/
struct nand_flash_dev {
char *name;
int id;
unsigned long pagesize;
unsigned long chipsize;
unsigned long erasesize;
unsigned long options;
union {
struct {
uint8_t mfr_id;
uint8_t dev_id;
};
uint8_t id[NAND_MAX_ID_LEN];
};
unsigned int pagesize;
unsigned int chipsize;
unsigned int erasesize;
unsigned int options;
uint16_t id_len;
uint16_t oobsize;
};
/**

View File

@ -30,7 +30,7 @@ struct physmap_flash_data {
unsigned int pfow_base;
char *probe_type;
struct mtd_partition *parts;
const char **part_probe_types;
const char * const *part_probe_types;
};
#endif /* __LINUX_MTD_PHYSMAP__ */

View File

@ -20,8 +20,8 @@
struct platdata_mtd_ram {
const char *mapname;
const char **map_probes;
const char **probes;
const char * const *map_probes;
const char * const *probes;
struct mtd_partition *partitions;
int nr_partitions;
int bankwidth;

View File

@ -50,5 +50,5 @@ struct elm_errorvec {
void elm_decode_bch_error_page(struct device *dev, u8 *ecc_calc,
struct elm_errorvec *err_vec);
void elm_config(struct device *dev, enum bch_ecc bch_type);
int elm_config(struct device *dev, enum bch_ecc bch_type);
#endif /* __ELM_H */