summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mtd/chips/Kconfig27
-rw-r--r--drivers/mtd/chips/amd_flash.c14
-rw-r--r--drivers/mtd/chips/cfi_cmdset_0001.c578
-rw-r--r--drivers/mtd/chips/cfi_cmdset_0002.c99
-rw-r--r--drivers/mtd/chips/gen_probe.c4
-rw-r--r--drivers/mtd/chips/jedec_probe.c28
-rw-r--r--drivers/mtd/devices/block2mtd.c20
-rw-r--r--drivers/mtd/devices/mtdram.c265
-rw-r--r--drivers/mtd/devices/phram.c34
-rw-r--r--drivers/mtd/devices/slram.c23
-rw-r--r--drivers/mtd/ftl.c5
-rw-r--r--drivers/mtd/maps/Kconfig100
-rw-r--r--drivers/mtd/maps/Makefile9
-rw-r--r--drivers/mtd/maps/alchemy-flash.c192
-rw-r--r--drivers/mtd/maps/amd76xrom.c4
-rw-r--r--drivers/mtd/maps/bast-flash.c13
-rw-r--r--drivers/mtd/maps/db1550-flash.c187
-rw-r--r--drivers/mtd/maps/db1x00-flash.c226
-rw-r--r--drivers/mtd/maps/elan-104nc.c228
-rw-r--r--drivers/mtd/maps/ichxrom.c4
-rw-r--r--drivers/mtd/maps/ixp2000.c7
-rw-r--r--drivers/mtd/maps/pb1550-flash.c203
-rw-r--r--drivers/mtd/maps/pb1xxx-flash.c178
-rw-r--r--drivers/mtd/maps/pci.c4
-rw-r--r--drivers/mtd/maps/plat-ram.c278
-rw-r--r--drivers/mtd/maps/scb2_flash.c4
-rw-r--r--drivers/mtd/maps/sharpsl-flash.c33
-rw-r--r--drivers/mtd/mtdchar.c130
-rw-r--r--drivers/mtd/mtdcore.c6
-rw-r--r--drivers/mtd/mtdpart.c28
-rw-r--r--drivers/mtd/nand/diskonchip.c96
-rw-r--r--drivers/mtd/nand/nand_base.c240
-rw-r--r--drivers/mtd/nand/nand_bbt.c75
-rw-r--r--drivers/mtd/nand/nand_ids.c6
-rw-r--r--drivers/mtd/nand/nandsim.c41
-rw-r--r--drivers/mtd/nand/rtc_from4.c140
-rw-r--r--drivers/mtd/nand/s3c2410.c134
-rwxr-xr-xdrivers/mtd/nand/sharpsl.c4
38 files changed, 1817 insertions, 1850 deletions
diff --git a/drivers/mtd/chips/Kconfig b/drivers/mtd/chips/Kconfig
index d682dbc8157..f4eda1e40d5 100644
--- a/drivers/mtd/chips/Kconfig
+++ b/drivers/mtd/chips/Kconfig
@@ -1,5 +1,5 @@
# drivers/mtd/chips/Kconfig
-# $Id: Kconfig,v 1.13 2004/12/01 15:49:10 nico Exp $
+# $Id: Kconfig,v 1.14 2005/02/08 17:11:15 nico Exp $
menu "RAM/ROM/Flash chip drivers"
depends on MTD!=n
@@ -155,6 +155,31 @@ config MTD_CFI_I8
If your flash chips are interleaved in eights - i.e. you have eight
flash chips addressed by each bus cycle, then say 'Y'.
+config MTD_OTP
+ bool "Protection Registers aka one-time programmable (OTP) bits"
+ depends on MTD_CFI_ADV_OPTIONS
+ default n
+ help
+ This enables support for reading, writing and locking so called
+ "Protection Registers" present on some flash chips.
+ A subset of them are pre-programmed at the factory with a
+ unique set of values. The rest is user-programmable.
+
+ The user-programmable Protection Registers contain one-time
+ programmable (OTP) bits; when programmed, register bits cannot be
+ erased. Each Protection Register can be accessed multiple times to
+ program individual bits, as long as the register remains unlocked.
+
+ Each Protection Register has an associated Lock Register bit. When a
+ Lock Register bit is programmed, the associated Protection Register
+ can only be read; it can no longer be programmed. Additionally,
+ because the Lock Register bits themselves are OTP, when programmed,
+ Lock Register bits cannot be erased. Therefore, when a Protection
+ Register is locked, it cannot be unlocked.
+
+ This feature should therefore be used with extreme care. Any mistake
+ in the programming of OTP bits will waste them.
+
config MTD_CFI_INTELEXT
tristate "Support for Intel/Sharp flash chips"
depends on MTD_GEN_PROBE
diff --git a/drivers/mtd/chips/amd_flash.c b/drivers/mtd/chips/amd_flash.c
index 41e2e3e3160..2dafeba3f3d 100644
--- a/drivers/mtd/chips/amd_flash.c
+++ b/drivers/mtd/chips/amd_flash.c
@@ -3,7 +3,7 @@
*
* Author: Jonas Holmberg <jonas.holmberg@axis.com>
*
- * $Id: amd_flash.c,v 1.26 2004/11/20 12:49:04 dwmw2 Exp $
+ * $Id: amd_flash.c,v 1.27 2005/02/04 07:43:09 jonashg Exp $
*
* Copyright (c) 2001 Axis Communications AB
*
@@ -67,7 +67,6 @@
#define AM29LV160DT 0x22C4
#define AM29LV160DB 0x2249
#define AM29BDS323D 0x22D1
-#define AM29BDS643D 0x227E
/* Atmel */
#define AT49xV16x 0x00C0
@@ -618,17 +617,6 @@ static struct mtd_info *amd_flash_probe(struct map_info *map)
{ .offset = 0x3f0000, .erasesize = 0x02000, .numblocks = 8 },
}
}, {
- .mfr_id = MANUFACTURER_AMD,
- .dev_id = AM29BDS643D,
- .name = "AMD AM29BDS643D",
- .size = 0x00800000,
- .numeraseregions = 3,
- .regions = {
- { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 96 },
- { .offset = 0x600000, .erasesize = 0x10000, .numblocks = 31 },
- { .offset = 0x7f0000, .erasesize = 0x02000, .numblocks = 8 },
- }
- }, {
.mfr_id = MANUFACTURER_ATMEL,
.dev_id = AT49xV16x,
.name = "Atmel AT49xV16x",
diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c
index c268bcd7172..8b1304531d8 100644
--- a/drivers/mtd/chips/cfi_cmdset_0001.c
+++ b/drivers/mtd/chips/cfi_cmdset_0001.c
@@ -4,7 +4,7 @@
*
* (C) 2000 Red Hat. GPL'd
*
- * $Id: cfi_cmdset_0001.c,v 1.164 2004/11/16 18:29:00 dwmw2 Exp $
+ * $Id: cfi_cmdset_0001.c,v 1.178 2005/05/19 17:05:43 nico Exp $
*
*
* 10/10/2000 Nicolas Pitre <nico@cam.org>
@@ -29,6 +29,7 @@
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
+#include <linux/reboot.h>
#include <linux/mtd/xip.h>
#include <linux/mtd/map.h>
#include <linux/mtd/mtd.h>
@@ -48,16 +49,25 @@
#define M50LPW080 0x002F
static int cfi_intelext_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
-//static int cfi_intelext_read_user_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
-//static int cfi_intelext_read_fact_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
static int cfi_intelext_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
static int cfi_intelext_write_buffers(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
static int cfi_intelext_erase_varsize(struct mtd_info *, struct erase_info *);
static void cfi_intelext_sync (struct mtd_info *);
static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len);
static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len);
+#ifdef CONFIG_MTD_OTP
+static int cfi_intelext_read_fact_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
+static int cfi_intelext_read_user_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
+static int cfi_intelext_write_user_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
+static int cfi_intelext_lock_user_prot_reg (struct mtd_info *, loff_t, size_t);
+static int cfi_intelext_get_fact_prot_info (struct mtd_info *,
+ struct otp_info *, size_t);
+static int cfi_intelext_get_user_prot_info (struct mtd_info *,
+ struct otp_info *, size_t);
+#endif
static int cfi_intelext_suspend (struct mtd_info *);
static void cfi_intelext_resume (struct mtd_info *);
+static int cfi_intelext_reboot (struct notifier_block *, unsigned long, void *);
static void cfi_intelext_destroy(struct mtd_info *);
@@ -252,7 +262,8 @@ read_pri_intelext(struct map_info *map, __u16 adr)
int nb_parts, i;
/* Protection Register info */
- extra_size += (extp->NumProtectionFields - 1) * (4 + 6);
+ extra_size += (extp->NumProtectionFields - 1) *
+ sizeof(struct cfi_intelext_otpinfo);
/* Burst Read info */
extra_size += 6;
@@ -324,7 +335,9 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary)
mtd->resume = cfi_intelext_resume;
mtd->flags = MTD_CAP_NORFLASH;
mtd->name = map->name;
-
+
+ mtd->reboot_notifier.notifier_call = cfi_intelext_reboot;
+
if (cfi->cfi_mode == CFI_MODE_CFI) {
/*
* It's a real CFI chip, not one for which the probe
@@ -422,9 +435,13 @@ static struct mtd_info *cfi_intelext_setup(struct mtd_info *mtd)
mtd->eraseregions[i].numblocks);
}
-#if 0
- mtd->read_user_prot_reg = cfi_intelext_read_user_prot_reg;
+#ifdef CONFIG_MTD_OTP
mtd->read_fact_prot_reg = cfi_intelext_read_fact_prot_reg;
+ mtd->read_user_prot_reg = cfi_intelext_read_user_prot_reg;
+ mtd->write_user_prot_reg = cfi_intelext_write_user_prot_reg;
+ mtd->lock_user_prot_reg = cfi_intelext_lock_user_prot_reg;
+ mtd->get_fact_prot_info = cfi_intelext_get_fact_prot_info;
+ mtd->get_user_prot_info = cfi_intelext_get_user_prot_info;
#endif
/* This function has the potential to distort the reality
@@ -433,6 +450,7 @@ static struct mtd_info *cfi_intelext_setup(struct mtd_info *mtd)
goto setup_err;
__module_get(THIS_MODULE);
+ register_reboot_notifier(&mtd->reboot_notifier);
return mtd;
setup_err:
@@ -471,7 +489,8 @@ static int cfi_intelext_partition_fixup(struct mtd_info *mtd,
int offs, numregions, numparts, partshift, numvirtchips, i, j;
/* Protection Register info */
- offs = (extp->NumProtectionFields - 1) * (4 + 6);
+ offs = (extp->NumProtectionFields - 1) *
+ sizeof(struct cfi_intelext_otpinfo);
/* Burst Read info */
offs += 6;
@@ -563,7 +582,7 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
resettime:
timeo = jiffies + HZ;
retry:
- if (chip->priv && (mode == FL_WRITING || mode == FL_ERASING)) {
+ if (chip->priv && (mode == FL_WRITING || mode == FL_ERASING || mode == FL_OTP_WRITE)) {
/*
* OK. We have possibility for contension on the write/erase
* operations which are global to the real chip and not per
@@ -807,10 +826,6 @@ static void put_chip(struct map_info *map, struct flchip *chip, unsigned long ad
* assembly to make sure inline functions were actually inlined and that gcc
* didn't emit calls to its own support functions). Also configuring MTD CFI
* support to a single buswidth and a single interleave is also recommended.
- * Note that not only IRQs are disabled but the preemption count is also
- * increased to prevent other locking primitives (namely spin_unlock) from
- * decrementing the preempt count to zero and scheduling the CPU away while
- * not in array mode.
*/
static void xip_disable(struct map_info *map, struct flchip *chip,
@@ -818,7 +833,6 @@ static void xip_disable(struct map_info *map, struct flchip *chip,
{
/* TODO: chips with no XIP use should ignore and return */
(void) map_read(map, adr); /* ensure mmu mapping is up to date */
- preempt_disable();
local_irq_disable();
}
@@ -833,7 +847,6 @@ static void __xipram xip_enable(struct map_info *map, struct flchip *chip,
(void) map_read(map, adr);
asm volatile (".rep 8; nop; .endr"); /* fill instruction prefetch */
local_irq_enable();
- preempt_enable();
}
/*
@@ -909,7 +922,7 @@ static void __xipram xip_udelay(struct map_info *map, struct flchip *chip,
(void) map_read(map, adr);
asm volatile (".rep 8; nop; .endr");
local_irq_enable();
- preempt_enable();
+ spin_unlock(chip->mutex);
asm volatile (".rep 8; nop; .endr");
cond_resched();
@@ -919,15 +932,15 @@ static void __xipram xip_udelay(struct map_info *map, struct flchip *chip,
* a suspended erase state. If so let's wait
* until it's done.
*/
- preempt_disable();
+ spin_lock(chip->mutex);
while (chip->state != newstate) {
DECLARE_WAITQUEUE(wait, current);
set_current_state(TASK_UNINTERRUPTIBLE);
add_wait_queue(&chip->wq, &wait);
- preempt_enable();
+ spin_unlock(chip->mutex);
schedule();
remove_wait_queue(&chip->wq, &wait);
- preempt_disable();
+ spin_lock(chip->mutex);
}
/* Disallow XIP again */
local_irq_disable();
@@ -956,12 +969,14 @@ static void __xipram xip_udelay(struct map_info *map, struct flchip *chip,
* The INVALIDATE_CACHED_RANGE() macro is normally used in parallel while
* the flash is actively programming or erasing since we have to poll for
* the operation to complete anyway. We can't do that in a generic way with
- * a XIP setup so do it before the actual flash operation in this case.
+ * a XIP setup so do it before the actual flash operation in this case
+ * and stub it out from INVALIDATE_CACHE_UDELAY.
*/
-#undef INVALIDATE_CACHED_RANGE
-#define INVALIDATE_CACHED_RANGE(x...)
-#define XIP_INVAL_CACHED_RANGE(map, from, size) \
- do { if(map->inval_cache) map->inval_cache(map, from, size); } while(0)
+#define XIP_INVAL_CACHED_RANGE(map, from, size) \
+ INVALIDATE_CACHED_RANGE(map, from, size)
+
+#define INVALIDATE_CACHE_UDELAY(map, chip, adr, len, usec) \
+ UDELAY(map, chip, adr, usec)
/*
* Extra notes:
@@ -984,11 +999,23 @@ static void __xipram xip_udelay(struct map_info *map, struct flchip *chip,
#define xip_disable(map, chip, adr)
#define xip_enable(map, chip, adr)
-
-#define UDELAY(map, chip, adr, usec) cfi_udelay(usec)
-
#define XIP_INVAL_CACHED_RANGE(x...)
+#define UDELAY(map, chip, adr, usec) \
+do { \
+ spin_unlock(chip->mutex); \
+ cfi_udelay(usec); \
+ spin_lock(chip->mutex); \
+} while (0)
+
+#define INVALIDATE_CACHE_UDELAY(map, chip, adr, len, usec) \
+do { \
+ spin_unlock(chip->mutex); \
+ INVALIDATE_CACHED_RANGE(map, adr, len); \
+ cfi_udelay(usec); \
+ spin_lock(chip->mutex); \
+} while (0)
+
#endif
static int do_point_onechip (struct map_info *map, struct flchip *chip, loff_t adr, size_t len)
@@ -1176,111 +1203,11 @@ static int cfi_intelext_read (struct mtd_info *mtd, loff_t from, size_t len, siz
return ret;
}
-#if 0
-static int __xipram cfi_intelext_read_prot_reg (struct mtd_info *mtd,
- loff_t from, size_t len,
- size_t *retlen,
- u_char *buf,
- int base_offst, int reg_sz)
-{
- struct map_info *map = mtd->priv;
- struct cfi_private *cfi = map->fldrv_priv;
- struct cfi_pri_intelext *extp = cfi->cmdset_priv;
- struct flchip *chip;
- int ofs_factor = cfi->interleave * cfi->device_type;
- int count = len;
- int chip_num, offst;
- int ret;
-
- chip_num = ((unsigned int)from/reg_sz);
- offst = from - (reg_sz*chip_num)+base_offst;
-
- while (count) {
- /* Calculate which chip & protection register offset we need */
-
- if (chip_num >= cfi->numchips)
- goto out;
-
- chip = &cfi->chips[chip_num];
-
- spin_lock(chip->mutex);
- ret = get_chip(map, chip, chip->start, FL_JEDEC_QUERY);
- if (ret) {
- spin_unlock(chip->mutex);
- return (len-count)?:ret;
- }
-
- xip_disable(map, chip, chip->start);
-
- if (chip->state != FL_JEDEC_QUERY) {
- map_write(map, CMD(0x90), chip->start);
- chip->state = FL_JEDEC_QUERY;
- }
-
- while (count && ((offst-base_offst) < reg_sz)) {
- *buf = map_read8(map,(chip->start+((extp->ProtRegAddr+1)*ofs_factor)+offst));
- buf++;
- offst++;
- count--;
- }
-
- xip_enable(map, chip, chip->start);
- put_chip(map, chip, chip->start);
- spin_unlock(chip->mutex);
-
- /* Move on to the next chip */
- chip_num++;
- offst = base_offst;
- }
-
- out:
- return len-count;
-}
-
-static int cfi_intelext_read_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
-{
- struct map_info *map = mtd->priv;
- struct cfi_private *cfi = map->fldrv_priv;
- struct cfi_pri_intelext *extp=cfi->cmdset_priv;
- int base_offst,reg_sz;
-
- /* Check that we actually have some protection registers */
- if(!extp || !(extp->FeatureSupport&64)){
- printk(KERN_WARNING "%s: This flash device has no protection data to read!\n",map->name);
- return 0;
- }
-
- base_offst=(1<<extp->FactProtRegSize);
- reg_sz=(1<<extp->UserProtRegSize);
-
- return cfi_intelext_read_prot_reg(mtd, from, len, retlen, buf, base_offst, reg_sz);
-}
-
-static int cfi_intelext_read_fact_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
-{
- struct map_info *map = mtd->priv;
- struct cfi_private *cfi = map->fldrv_priv;
- struct cfi_pri_intelext *extp=cfi->cmdset_priv;
- int base_offst,reg_sz;
-
- /* Check that we actually have some protection registers */
- if(!extp || !(extp->FeatureSupport&64)){
- printk(KERN_WARNING "%s: This flash device has no protection data to read!\n",map->name);
- return 0;
- }
-
- base_offst=0;
- reg_sz=(1<<extp->FactProtRegSize);
-
- return cfi_intelext_read_prot_reg(mtd, from, len, retlen, buf, base_offst, reg_sz);
-}
-#endif
-
static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
- unsigned long adr, map_word datum)
+ unsigned long adr, map_word datum, int mode)
{
struct cfi_private *cfi = map->fldrv_priv;
- map_word status, status_OK;
+ map_word status, status_OK, write_cmd;
unsigned long timeo;
int z, ret=0;
@@ -1288,9 +1215,14 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
/* Let's determine this according to the interleave only once */
status_OK = CMD(0x80);
+ switch (mode) {
+ case FL_WRITING: write_cmd = CMD(0x40); break;
+ case FL_OTP_WRITE: write_cmd = CMD(0xc0); break;
+ default: return -EINVAL;
+ }
spin_lock(chip->mutex);
- ret = get_chip(map, chip, adr, FL_WRITING);
+ ret = get_chip(map, chip, adr, mode);
if (ret) {
spin_unlock(chip->mutex);
return ret;
@@ -1299,19 +1231,18 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
XIP_INVAL_CACHED_RANGE(map, adr, map_bankwidth(map));
ENABLE_VPP(map);
xip_disable(map, chip, adr);
- map_write(map, CMD(0x40), adr);
+ map_write(map, write_cmd, adr);
map_write(map, datum, adr);
- chip->state = FL_WRITING;
+ chip->state = mode;
- spin_unlock(chip->mutex);
- INVALIDATE_CACHED_RANGE(map, adr, map_bankwidth(map));
- UDELAY(map, chip, adr, chip->word_write_time);
- spin_lock(chip->mutex);
+ INVALIDATE_CACHE_UDELAY(map, chip,
+ adr, map_bankwidth(map),
+ chip->word_write_time);
timeo = jiffies + (HZ/2);
z = 0;
for (;;) {
- if (chip->state != FL_WRITING) {
+ if (chip->state != mode) {
/* Someone's suspended the write. Sleep */
DECLARE_WAITQUEUE(wait, current);
@@ -1339,10 +1270,8 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
}
/* Latency issues. Drop the lock, wait a while and retry */
- spin_unlock(chip->mutex);
z++;
UDELAY(map, chip, adr, 1);
- spin_lock(chip->mutex);
}
if (!z) {
chip->word_write_time--;
@@ -1399,7 +1328,7 @@ static int cfi_intelext_write_words (struct mtd_info *mtd, loff_t to , size_t le
datum = map_word_load_partial(map, datum, buf, gap, n);
ret = do_write_oneword(map, &cfi->chips[chipnum],
- bus_ofs, datum);
+ bus_ofs, datum, FL_WRITING);
if (ret)
return ret;
@@ -1420,7 +1349,7 @@ static int cfi_intelext_write_words (struct mtd_info *mtd, loff_t to , size_t le
map_word datum = map_word_load(map, buf);
ret = do_write_oneword(map, &cfi->chips[chipnum],
- ofs, datum);
+ ofs, datum, FL_WRITING);
if (ret)
return ret;
@@ -1444,7 +1373,7 @@ static int cfi_intelext_write_words (struct mtd_info *mtd, loff_t to , size_t le
datum = map_word_load_partial(map, datum, buf, 0, len);
ret = do_write_oneword(map, &cfi->chips[chipnum],
- ofs, datum);
+ ofs, datum, FL_WRITING);
if (ret)
return ret;
@@ -1506,9 +1435,7 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
if (map_word_andequal(map, status, status_OK, status_OK))
break;
- spin_unlock(chip->mutex);
UDELAY(map, chip, cmd_adr, 1);
- spin_lock(chip->mutex);
if (++z > 20) {
/* Argh. Not ready for write to buffer */
@@ -1554,10 +1481,9 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
map_write(map, CMD(0xd0), cmd_adr);
chip->state = FL_WRITING;
- spin_unlock(chip->mutex);
- INVALIDATE_CACHED_RANGE(map, adr, len);
- UDELAY(map, chip, cmd_adr, chip->buffer_write_time);
- spin_lock(chip->mutex);
+ INVALIDATE_CACHE_UDELAY(map, chip,
+ cmd_adr, len,
+ chip->buffer_write_time);
timeo = jiffies + (HZ/2);
z = 0;
@@ -1589,10 +1515,8 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
}
/* Latency issues. Drop the lock, wait a while and retry */
- spin_unlock(chip->mutex);
- UDELAY(map, chip, cmd_adr, 1);
z++;
- spin_lock(chip->mutex);
+ UDELAY(map, chip, cmd_adr, 1);
}
if (!z) {
chip->buffer_write_time--;
@@ -1720,10 +1644,9 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
chip->state = FL_ERASING;
chip->erase_suspended = 0;
- spin_unlock(chip->mutex);
- INVALIDATE_CACHED_RANGE(map, adr, len);
- UDELAY(map, chip, adr, chip->erase_time*1000/2);
- spin_lock(chip->mutex);
+ INVALIDATE_CACHE_UDELAY(map, chip,
+ adr, len,
+ chip->erase_time*1000/2);
/* FIXME. Use a timer to check this, and return immediately. */
/* Once the state machine's known to be working I'll do that */
@@ -1768,9 +1691,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
}
/* Latency issues. Drop the lock, wait a while and retry */
- spin_unlock(chip->mutex);
UDELAY(map, chip, adr, 1000000/HZ);
- spin_lock(chip->mutex);
}
/* We've broken this before. It doesn't hurt to be safe */
@@ -1780,44 +1701,34 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
/* check for lock bit */
if (map_word_bitsset(map, status, CMD(0x3a))) {
- unsigned char chipstatus;
+ unsigned long chipstatus;
/* Reset the error bits */
map_write(map, CMD(0x50), adr);
map_write(map, CMD(0x70), adr);
xip_enable(map, chip, adr);
- chipstatus = status.x[0];
- if (!map_word_equal(map, status, CMD(chipstatus))) {
- int i, w;
- for (w=0; w<map_words(map); w++) {
- for (i = 0; i<cfi_interleave(cfi); i++) {
- chipstatus |= status.x[w] >> (cfi->device_type * 8);
- }
- }
- printk(KERN_WARNING "Status is not identical for all chips: 0x%lx. Merging to give 0x%02x\n",
- status.x[0], chipstatus);
- }
+ chipstatus = MERGESTATUS(status);
if ((chipstatus & 0x30) == 0x30) {
- printk(KERN_NOTICE "Chip reports improper command sequence: status 0x%x\n", chipstatus);
+ printk(KERN_NOTICE "Chip reports improper command sequence: status 0x%lx\n", chipstatus);
ret = -EIO;
} else if (chipstatus & 0x02) {
/* Protection bit set */
ret = -EROFS;
} else if (chipstatus & 0x8) {
/* Voltage */
- printk(KERN_WARNING "Chip reports voltage low on erase: status 0x%x\n", chipstatus);
+ printk(KERN_WARNING "Chip reports voltage low on erase: status 0x%lx\n", chipstatus);
ret = -EIO;
} else if (chipstatus & 0x20) {
if (retries--) {
- printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%x. Retrying...\n", adr, chipstatus);
+ printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%lx. Retrying...\n", adr, chipstatus);
timeo = jiffies + HZ;
put_chip(map, chip, adr);
spin_unlock(chip->mutex);
goto retry;
}
- printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%x\n", adr, chipstatus);
+ printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%lx\n", adr, chipstatus);
ret = -EIO;
}
} else {
@@ -1882,6 +1793,7 @@ static void cfi_intelext_sync (struct mtd_info *mtd)
if (chip->state == FL_SYNCING) {
chip->state = chip->oldstate;
+ chip->oldstate = FL_READY;
wake_up(&chip->wq);
}
spin_unlock(chip->mutex);
@@ -1897,8 +1809,9 @@ static int __xipram do_printlockstatus_oneblock(struct map_info *map,
struct cfi_private *cfi = map->fldrv_priv;
int status, ofs_factor = cfi->interleave * cfi->device_type;
+ adr += chip->start;
xip_disable(map, chip, adr+(2*ofs_factor));
- cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL);
+ map_write(map, CMD(0x90), adr+(2*ofs_factor));
chip->state = FL_JEDEC_QUERY;
status = cfi_read_query(map, adr+(2*ofs_factor));
xip_enable(map, chip, 0);
@@ -1915,6 +1828,7 @@ static int __xipram do_xxlock_oneblock(struct map_info *map, struct flchip *chip
unsigned long adr, int len, void *thunk)
{
struct cfi_private *cfi = map->fldrv_priv;
+ struct cfi_pri_intelext *extp = cfi->cmdset_priv;
map_word status, status_OK;
unsigned long timeo = jiffies + HZ;
int ret;
@@ -1944,9 +1858,13 @@ static int __xipram do_xxlock_oneblock(struct map_info *map, struct flchip *chip
} else
BUG();
- spin_unlock(chip->mutex);
- UDELAY(map, chip, adr, 1000000/HZ);
- spin_lock(chip->mutex);
+ /*
+ * If Instant Individual Block Locking supported then no need
+ * to delay.
+ */
+
+ if (!extp || !(extp->FeatureSupport & (1 << 5)))
+ UDELAY(map, chip, adr, 1000000/HZ);
/* FIXME. Use a timer to check this, and return immediately. */
/* Once the state machine's known to be working I'll do that */
@@ -1973,9 +1891,7 @@ static int __xipram do_xxlock_oneblock(struct map_info *map, struct flchip *chip
}
/* Latency issues. Drop the lock, wait a while and retry */
- spin_unlock(chip->mutex);
UDELAY(map, chip, adr, 1);
- spin_lock(chip->mutex);
}
/* Done and happy. */
@@ -2034,6 +1950,274 @@ static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
return ret;
}
+#ifdef CONFIG_MTD_OTP
+
+typedef int (*otp_op_t)(struct map_info *map, struct flchip *chip,
+ u_long data_offset, u_char *buf, u_int size,
+ u_long prot_offset, u_int groupno, u_int groupsize);
+
+static int __xipram
+do_otp_read(struct map_info *map, struct flchip *chip, u_long offset,
+ u_char *buf, u_int size, u_long prot, u_int grpno, u_int grpsz)
+{
+ struct cfi_private *cfi = map->fldrv_priv;
+ int ret;
+
+ spin_lock(chip->mutex);
+ ret = get_chip(map, chip, chip->start, FL_JEDEC_QUERY);
+ if (ret) {
+ spin_unlock(chip->mutex);
+ return ret;
+ }
+
+ /* let's ensure we're not reading back cached data from array mode */
+ INVALIDATE_CACHED_RANGE(map, chip->start + offset, size);
+
+ xip_disable(map, chip, chip->start);
+ if (chip->state != FL_JEDEC_QUERY) {
+ map_write(map, CMD(0x90), chip->start);
+ chip->state = FL_JEDEC_QUERY;
+ }
+ map_copy_from(map, buf, chip->start + offset, size);
+ xip_enable(map, chip, chip->start);
+
+ /* then ensure we don't keep OTP data in the cache */
+ INVALIDATE_CACHED_RANGE(map, chip->start + offset, size);
+
+ put_chip(map, chip, chip->start);
+ spin_unlock(chip->mutex);
+ return 0;
+}
+
+static int
+do_otp_write(struct map_info *map, struct flchip *chip, u_long offset,
+ u_char *buf, u_int size, u_long prot, u_int grpno, u_int grpsz)
+{
+ int ret;
+
+ while (size) {
+ unsigned long bus_ofs = offset & ~(map_bankwidth(map)-1);
+ int gap = offset - bus_ofs;
+ int n = min_t(int, size, map_bankwidth(map)-gap);
+ map_word datum = map_word_ff(map);
+
+ datum = map_word_load_partial(map, datum, buf, gap, n);
+ ret = do_write_oneword(map, chip, bus_ofs, datum, FL_OTP_WRITE);
+ if (ret)
+ return ret;
+
+ offset += n;
+ buf += n;
+ size -= n;
+ }
+
+ return 0;
+}
+
+static int
+do_otp_lock(struct map_info *map, struct flchip *chip, u_long offset,
+ u_char *buf, u_int size, u_long prot, u_int grpno, u_int grpsz)
+{
+ struct cfi_private *cfi = map->fldrv_priv;
+ map_word datum;
+
+ /* make sure area matches group boundaries */
+ if (size != grpsz)
+ return -EXDEV;
+
+ datum = map_word_ff(map);
+ datum = map_word_clr(map, datum, CMD(1 << grpno));
+ return do_write_oneword(map, chip, prot, datum, FL_OTP_WRITE);
+}
+
+static int cfi_intelext_otp_walk(struct mtd_info *mtd, loff_t from, size_t len,
+ size_t *retlen, u_char *buf,
+ otp_op_t action, int user_regs)
+{
+ struct map_info *map = mtd->priv;
+ struct cfi_private *cfi = map->fldrv_priv;
+ struct cfi_pri_intelext *extp = cfi->cmdset_priv;
+ struct flchip *chip;
+ struct cfi_intelext_otpinfo *otp;
+ u_long devsize, reg_prot_offset, data_offset;
+ u_int chip_num, chip_step, field, reg_fact_size, reg_user_size;
+ u_int groups, groupno, groupsize, reg_fact_groups, reg_user_groups;
+ int ret;
+
+ *retlen = 0;
+
+ /* Check that we actually have some OTP registers */
+ if (!extp || !(extp->FeatureSupport & 64) || !extp->NumProtectionFields)
+ return -ENODATA;
+
+ /* we need real chips here not virtual ones */
+ devsize = (1 << cfi->cfiq->DevSize) * cfi->interleave;
+ chip_step = devsize >> cfi->chipshift;
+ chip_num = 0;
+
+ /* Some chips have OTP located in the _top_ partition only.
+ For example: Intel 28F256L18T (T means top-parameter device) */
+ if (cfi->mfr == MANUFACTURER_INTEL) {
+ switch (cfi->id) {
+ case 0x880b:
+ case 0x880c:
+ case 0x880d:
+ chip_num = chip_step - 1;
+ }
+ }
+
+ for ( ; chip_num < cfi->numchips; chip_num += chip_step) {
+ chip = &cfi->chips[chip_num];
+ otp = (struct cfi_intelext_otpinfo *)&extp->extra[0];
+
+ /* first OTP region */
+ field = 0;
+ reg_prot_offset = extp->ProtRegAddr;
+ reg_fact_groups = 1;
+ reg_fact_size = 1 << extp->FactProtRegSize;
+ reg_user_groups = 1;
+ reg_user_size = 1 << extp->UserProtRegSize;
+
+ while (len > 0) {
+ /* flash geometry fixup */
+ data_offset = reg_prot_offset + 1;
+ data_offset *= cfi->interleave * cfi->device_type;
+ reg_prot_offset *= cfi->interleave * cfi->device_type;
+ reg_fact_size *= cfi->interleave;
+ reg_user_size *= cfi->interleave;
+
+ if (user_regs) {
+ groups = reg_user_groups;
+ groupsize = reg_user_size;
+ /* skip over factory reg area */
+ groupno = reg_fact_groups;
+ data_offset += reg_fact_groups * reg_fact_size;
+ } else {
+ groups = reg_fact_groups;
+ groupsize = reg_fact_size;
+ groupno = 0;
+ }
+
+ while (len > 0 && groups > 0) {
+ if (!action) {
+ /*
+ * Special case: if action is NULL
+ * we fill buf with otp_info records.
+ */
+ struct otp_info *otpinfo;
+ map_word lockword;
+ len -= sizeof(struct otp_info);
+ if (len <= 0)
+ return -ENOSPC;
+ ret = do_otp_read(map, chip,
+ reg_prot_offset,
+ (u_char *)&lockword,
+ map_bankwidth(map),
+ 0, 0, 0);
+ if (ret)
+ return ret;
+ otpinfo = (struct otp_info *)buf;
+ otpinfo->start = from;
+ otpinfo->length = groupsize;
+ otpinfo->locked =
+ !map_word_bitsset(map, lockword,
+ CMD(1 << groupno));
+ from += groupsize;
+ buf += sizeof(*otpinfo);
+ *retlen += sizeof(*otpinfo);
+ } else if (from >= groupsize) {
+ from -= groupsize;
+ data_offset += groupsize;
+ } else {
+ int size = groupsize;
+ data_offset += from;
+ size -= from;
+ from = 0;
+ if (size > len)
+ size = len;
+ ret = action(map, chip, data_offset,
+ buf, size, reg_prot_offset,
+ groupno, groupsize);
+ if (ret < 0)
+ return ret;
+ buf += size;
+ len -= size;
+ *retlen += size;
+ data_offset += size;
+ }
+ groupno++;
+ groups--;
+ }
+
+ /* next OTP region */
+ if (++field == extp->NumProtectionFields)
+ break;
+ reg_prot_offset = otp->ProtRegAddr;
+ reg_fact_groups = otp->FactGroups;
+ reg_fact_size = 1 << otp->FactProtRegSize;
+ reg_user_groups = otp->UserGroups;
+ reg_user_size = 1 << otp->UserProtRegSize;
+ otp++;
+ }
+ }
+
+ return 0;
+}
+
+static int cfi_intelext_read_fact_prot_reg(struct mtd_info *mtd, loff_t from,
+ size_t len, size_t *retlen,
+ u_char *buf)
+{
+ return cfi_intelext_otp_walk(mtd, from, len, retlen,
+ buf, do_otp_read, 0);
+}
+
+static int cfi_intelext_read_user_prot_reg(struct mtd_info *mtd, loff_t from,
+ size_t len, size_t *retlen,
+ u_char *buf)
+{
+ return cfi_intelext_otp_walk(mtd, from, len, retlen,
+ buf, do_otp_read, 1);
+}
+
+static int cfi_intelext_write_user_prot_reg(struct mtd_info *mtd, loff_t from,
+ size_t len, size_t *retlen,
+ u_char *buf)
+{
+ return cfi_intelext_otp_walk(mtd, from, len, retlen,
+ buf, do_otp_write, 1);
+}
+
+static int cfi_intelext_lock_user_prot_reg(struct mtd_info *mtd,
+ loff_t from, size_t len)
+{
+ size_t retlen;
+ return cfi_intelext_otp_walk(mtd, from, len, &retlen,
+ NULL, do_otp_lock, 1);
+}
+
+static int cfi_intelext_get_fact_prot_info(struct mtd_info *mtd,
+ struct otp_info *buf, size_t len)
+{
+ size_t retlen;
+ int ret;
+
+ ret = cfi_intelext_otp_walk(mtd, 0, len, &retlen, (u_char *)buf, NULL, 0);
+ return ret ? : retlen;
+}
+
+static int cfi_intelext_get_user_prot_info(struct mtd_info *mtd,
+ struct otp_info *buf, size_t len)
+{
+ size_t retlen;
+ int ret;
+
+ ret = cfi_intelext_otp_walk(mtd, 0, len, &retlen, (u_char *)buf, NULL, 1);
+ return ret ? : retlen;
+}
+
+#endif
+
static int cfi_intelext_suspend(struct mtd_info *mtd)
{
struct map_info *map = mtd->priv;
@@ -2125,10 +2309,46 @@ static void cfi_intelext_resume(struct mtd_info *mtd)
}
}
+static int cfi_intelext_reset(struct mtd_info *mtd)
+{
+ struct map_info *map = mtd->priv;
+ struct cfi_private *cfi = map->fldrv_priv;
+ int i, ret;
+
+ for (i=0; i < cfi->numchips; i++) {
+ struct flchip *chip = &cfi->chips[i];
+
+ /* force the completion of any ongoing operation
+ and switch to array mode so any bootloader in
+ flash is accessible for soft reboot. */
+ spin_lock(chip->mutex);
+ ret = get_chip(map, chip, chip->start, FL_SYNCING);
+ if (!ret) {
+ map_write(map, CMD(0xff), chip->start);
+ chip->state = FL_READY;
+ }
+ spin_unlock(chip->mutex);
+ }
+
+ return 0;
+}
+
+static int cfi_intelext_reboot(struct notifier_block *nb, unsigned long val,
+ void *v)
+{
+ struct mtd_info *mtd;
+
+ mtd = container_of(nb, struct mtd_info, reboot_notifier);
+ cfi_intelext_reset(mtd);
+ return NOTIFY_DONE;
+}
+
static void cfi_intelext_destroy(struct mtd_info *mtd)
{
struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv;
+ cfi_intelext_reset(mtd);
+ unregister_reboot_notifier(&mtd->reboot_notifier);
kfree(cfi->cmdset_priv);
kfree(cfi->cfiq);
kfree(cfi->chips[0].priv);
diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c
index fca8ff6f7e1..59849236f52 100644
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
@@ -13,7 +13,7 @@
*
* This code is GPL
*
- * $Id: cfi_cmdset_0002.c,v 1.114 2004/12/11 15:43:53 dedekind Exp $
+ * $Id: cfi_cmdset_0002.c,v 1.115 2005/05/20 03:28:23 eric Exp $
*
*/
@@ -43,6 +43,7 @@
#define MANUFACTURER_AMD 0x0001
#define MANUFACTURER_SST 0x00BF
#define SST49LF004B 0x0060
+#define SST49LF008A 0x005a
static int cfi_amdstd_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
static int cfi_amdstd_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
@@ -191,6 +192,7 @@ static struct cfi_fixup cfi_fixup_table[] = {
};
static struct cfi_fixup jedec_fixup_table[] = {
{ MANUFACTURER_SST, SST49LF004B, fixup_use_fwh_lock, NULL, },
+ { MANUFACTURER_SST, SST49LF008A, fixup_use_fwh_lock, NULL, },
{ 0, 0, NULL, NULL }
};
@@ -401,6 +403,32 @@ static int chip_ready(struct map_info *map, unsigned long addr)
return map_word_equal(map, d, t);
}
+/*
+ * Return true if the chip is ready and has the correct value.
+ *
+ * Ready is one of: read mode, query mode, erase-suspend-read mode (in any
+ * non-suspended sector) and it is indicated by no bits toggling.
+ *
+ * Error are indicated by toggling bits or bits held with the wrong value,
+ * or with bits toggling.
+ *
+ * Note that anything more complicated than checking if no bits are toggling
+ * (including checking DQ5 for an error status) is tricky to get working
+ * correctly and is therefore not done (particulary with interleaved chips
+ * as each chip must be checked independantly of the others).
+ *
+ */
+static int chip_good(struct map_info *map, unsigned long addr, map_word expected)
+{
+ map_word oldd, curd;
+
+ oldd = map_read(map, addr);
+ curd = map_read(map, addr);
+
+ return map_word_equal(map, oldd, curd) &&
+ map_word_equal(map, curd, expected);
+}
+
static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode)
{
DECLARE_WAITQUEUE(wait, current);
@@ -765,26 +793,29 @@ static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned
}
if (chip_ready(map, adr))
- goto op_done;
+ break;
- if (time_after(jiffies, timeo))
+ if (time_after(jiffies, timeo)) {
+ printk(KERN_WARNING "MTD %s(): software timeout\n", __func__);
break;
+ }
/* Latency issues. Drop the lock, wait a while and retry */
cfi_spin_unlock(chip->mutex);
cfi_udelay(1);
cfi_spin_lock(chip->mutex);
}
+ /* Did we succeed? */
+ if (!chip_good(map, adr, datum)) {
+ /* reset on all failures. */
+ map_write( map, CMD(0xF0), chip->start );
+ /* FIXME - should have reset delay before continuing */
- printk(KERN_WARNING "MTD %s(): software timeout\n", __func__);
-
- /* reset on all failures. */
- map_write( map, CMD(0xF0), chip->start );
- /* FIXME - should have reset delay before continuing */
- if (++retry_cnt <= MAX_WORD_RETRIES)
- goto retry;
+ if (++retry_cnt <= MAX_WORD_RETRIES)
+ goto retry;
- ret = -EIO;
+ ret = -EIO;
+ }
op_done:
chip->state = FL_READY;
put_chip(map, chip, adr);
@@ -1187,10 +1218,13 @@ static inline int do_erase_chip(struct map_info *map, struct flchip *chip)
}
if (chip_ready(map, adr))
- goto op_done;
+ break;
- if (time_after(jiffies, timeo))
+ if (time_after(jiffies, timeo)) {
+ printk(KERN_WARNING "MTD %s(): software timeout\n",
+ __func__ );
break;
+ }
/* Latency issues. Drop the lock, wait a while and retry */
cfi_spin_unlock(chip->mutex);
@@ -1198,16 +1232,15 @@ static inline int do_erase_chip(struct map_info *map, struct flchip *chip)
schedule_timeout(1);
cfi_spin_lock(chip->mutex);
}
+ /* Did we succeed? */
+ if (!chip_good(map, adr, map_word_ff(map))) {
+ /* reset on all failures. */
+ map_write( map, CMD(0xF0), chip->start );
+ /* FIXME - should have reset delay before continuing */
- printk(KERN_WARNING "MTD %s(): software timeout\n",
- __func__ );
-
- /* reset on all failures. */
- map_write( map, CMD(0xF0), chip->start );
- /* FIXME - should have reset delay before continuing */
+ ret = -EIO;
+ }
- ret = -EIO;
- op_done:
chip->state = FL_READY;
put_chip(map, chip, adr);
cfi_spin_unlock(chip->mutex);
@@ -1272,10 +1305,13 @@ static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, u
}
if (chip_ready(map, adr))
- goto op_done;
+ break;
- if (time_after(jiffies, timeo))
+ if (time_after(jiffies, timeo)) {
+ printk(KERN_WARNING "MTD %s(): software timeout\n",
+ __func__ );
break;
+ }
/* Latency issues. Drop the lock, wait a while and retry */
cfi_spin_unlock(chip->mutex);
@@ -1283,16 +1319,15 @@ static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, u
schedule_timeout(1);
cfi_spin_lock(chip->mutex);
}
-
- printk(KERN_WARNING "MTD %s(): software timeout\n",
- __func__ );
-
- /* reset on all failures. */
- map_write( map, CMD(0xF0), chip->start );
- /* FIXME - should have reset delay before continuing */
+ /* Did we succeed? */
+ if (chip_good(map, adr, map_word_ff(map))) {
+ /* reset on all failures. */
+ map_write( map, CMD(0xF0), chip->start );
+ /* FIXME - should have reset delay before continuing */
+
+ ret = -EIO;
+ }
- ret = -EIO;
- op_done:
chip->state = FL_READY;
put_chip(map, chip, adr);
cfi_spin_unlock(chip->mutex);
diff --git a/drivers/mtd/chips/gen_probe.c b/drivers/mtd/chips/gen_probe.c
index fc982c4671f..dc065b22f79 100644
--- a/drivers/mtd/chips/gen_probe.c
+++ b/drivers/mtd/chips/gen_probe.c
@@ -2,7 +2,7 @@
* Routines common to all CFI-type probes.
* (C) 2001-2003 Red Hat, Inc.
* GPL'd
- * $Id: gen_probe.c,v 1.21 2004/08/14 15:14:05 dwmw2 Exp $
+ * $Id: gen_probe.c,v 1.22 2005/01/24 23:49:50 rmk Exp $
*/
#include <linux/kernel.h>
@@ -162,7 +162,7 @@ static int genprobe_new_chip(struct map_info *map, struct chip_probe *cp,
int max_chips = map_bankwidth(map); /* And minimum 1 */
int nr_chips, type;
- for (nr_chips = min_chips; nr_chips <= max_chips; nr_chips <<= 1) {
+ for (nr_chips = max_chips; nr_chips >= min_chips; nr_chips >>= 1) {
if (!cfi_interleave_supported(nr_chips))
continue;
diff --git a/drivers/mtd/chips/jedec_probe.c b/drivers/mtd/chips/jedec_probe.c
index 30325a25ab9..30da428eb7b 100644
--- a/drivers/mtd/chips/jedec_probe.c
+++ b/drivers/mtd/chips/jedec_probe.c
@@ -1,7 +1,7 @@
/*
Common Flash Interface probe code.
(C) 2000 Red Hat. GPL'd.
- $Id: jedec_probe.c,v 1.61 2004/11/19 20:52:16 thayne Exp $
+ $Id: jedec_probe.c,v 1.63 2005/02/14 16:30:32 bjd Exp $
See JEDEC (http://www.jedec.org/) standard JESD21C (section 3.5)
for the standard this probe goes back to.
@@ -142,6 +142,7 @@
#define SST29LE512 0x003d
#define SST39LF800 0x2781
#define SST39LF160 0x2782
+#define SST39VF1601 0x234b
#define SST39LF512 0x00D4
#define SST39LF010 0x00D5
#define SST39LF020 0x00D6
@@ -1448,6 +1449,21 @@ static const struct amd_flash_info jedec_table[] = {
ERASEINFO(0x1000,256),
ERASEINFO(0x1000,256)
}
+ }, {
+ .mfr_id = MANUFACTURER_SST, /* should be CFI */
+ .dev_id = SST39VF1601,
+ .name = "SST 39VF1601",
+ .uaddr = {
+ [0] = MTD_UADDR_0x5555_0x2AAA, /* x8 */
+ [1] = MTD_UADDR_0x5555_0x2AAA /* x16 */
+ },
+ .DevSize = SIZE_2MiB,
+ .CmdSet = P_ID_AMD_STD,
+ .NumEraseRegions= 2,
+ .regions = {
+ ERASEINFO(0x1000,256),
+ ERASEINFO(0x1000,256)
+ }
}, {
.mfr_id = MANUFACTURER_ST, /* FIXME - CFI device? */
@@ -1856,6 +1872,16 @@ static inline int jedec_match( __u32 base,
case CFI_DEVICETYPE_X8:
mfr = (__u8)finfo->mfr_id;
id = (__u8)finfo->dev_id;
+
+ /* bjd: it seems that if we do this, we can end up
+ * detecting 16bit flashes as an 8bit device, even though
+ * there aren't.
+ */
+ if (finfo->dev_id > 0xff) {
+ DEBUG( MTD_DEBUG_LEVEL3, "%s(): ID is not 8bit\n",
+ __func__);
+ goto match_done;
+ }
break;
case CFI_DEVICETYPE_X16:
mfr = (__u16)finfo->mfr_id;
diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c
index cfe6ccf0797..4a7a805e756 100644
--- a/drivers/mtd/devices/block2mtd.c
+++ b/drivers/mtd/devices/block2mtd.c
@@ -1,10 +1,9 @@
/*
- * $Id: block2mtd.c,v 1.23 2005/01/05 17:05:46 dwmw2 Exp $
+ * $Id: block2mtd.c,v 1.28 2005/03/19 22:40:44 gleixner Exp $
*
* block2mtd.c - create an mtd from a block device
*
* Copyright (C) 2001,2002 Simon Evans <spse@secret.org.uk>
- * Copyright (C) 2004 Gareth Bult <Gareth@Encryptec.net>
* Copyright (C) 2004,2005 Jörn Engel <joern@wh.fh-wedel.de>
*
* Licence: GPL
@@ -20,7 +19,7 @@
#include <linux/mtd/mtd.h>
#include <linux/buffer_head.h>
-#define VERSION "$Revision: 1.23 $"
+#define VERSION "$Revision: 1.28 $"
#define ERROR(fmt, args...) printk(KERN_ERR "block2mtd: " fmt "\n" , ## args)
@@ -89,7 +88,6 @@ void cache_readahead(struct address_space *mapping, int index)
static struct page* page_readahead(struct address_space *mapping, int index)
{
filler_t *filler = (filler_t*)mapping->a_ops->readpage;
- //do_page_cache_readahead(mapping, index, XXX, 64);
cache_readahead(mapping, index);
return read_cache_page(mapping, index, filler, NULL);
}
@@ -157,7 +155,7 @@ static int block2mtd_read(struct mtd_info *mtd, loff_t from, size_t len,
struct block2mtd_dev *dev = mtd->priv;
struct page *page;
int index = from >> PAGE_SHIFT;
- int offset = from & (PAGE_SHIFT-1);
+ int offset = from & (PAGE_SIZE-1);
int cpylen;
if (from > mtd->size)
@@ -370,16 +368,16 @@ static int ustrtoul(const char *cp, char **endp, unsigned int base)
}
-static int parse_num32(u32 *num32, const char *token)
+static int parse_num(size_t *num, const char *token)
{
char *endp;
- unsigned long n;
+ size_t n;
- n = ustrtoul(token, &endp, 0);
+ n = (size_t) ustrtoul(token, &endp, 0);
if (*endp)
return -EINVAL;
- *num32 = n;
+ *num = n;
return 0;
}
@@ -422,7 +420,7 @@ static int block2mtd_setup(const char *val, struct kernel_param *kp)
char buf[80+12], *str=buf; /* 80 for device, 12 for erase size */
char *token[2];
char *name;
- u32 erase_size = PAGE_SIZE;
+ size_t erase_size = PAGE_SIZE;
int i, ret;
if (strnlen(val, sizeof(buf)) >= sizeof(buf))
@@ -449,7 +447,7 @@ static int block2mtd_setup(const char *val, struct kernel_param *kp)
return 0;
if (token[1]) {
- ret = parse_num32(&erase_size, token[1]);
+ ret = parse_num(&erase_size, token[1]);
if (ret)
parse_err("illegal erase size");
}
diff --git a/drivers/mtd/devices/mtdram.c b/drivers/mtd/devices/mtdram.c
index edac4156d69..bb713fed2f3 100644
--- a/drivers/mtd/devices/mtdram.c
+++ b/drivers/mtd/devices/mtdram.c
@@ -1,9 +1,10 @@
/*
* mtdram - a test mtd device
- * $Id: mtdram.c,v 1.35 2005/01/05 18:05:12 dwmw2 Exp $
+ * $Id: mtdram.c,v 1.37 2005/04/21 03:42:11 joern Exp $
* Author: Alexander Larsson <alex@cendio.se>
*
* Copyright (c) 1999 Alexander Larsson <alex@cendio.se>
+ * Copyright (c) 2005 Joern Engel <joern@wh.fh-wedel.de>
*
* This code is GPL
*
@@ -18,213 +19,140 @@
#include <linux/mtd/compatmac.h>
#include <linux/mtd/mtd.h>
-#ifndef CONFIG_MTDRAM_ABS_POS
- #define CONFIG_MTDRAM_ABS_POS 0
-#endif
-
-#if CONFIG_MTDRAM_ABS_POS > 0
- #include <asm/io.h>
-#endif
-
-#ifdef MODULE
static unsigned long total_size = CONFIG_MTDRAM_TOTAL_SIZE;
static unsigned long erase_size = CONFIG_MTDRAM_ERASE_SIZE;
-module_param(total_size,ulong,0);
-MODULE_PARM_DESC(total_size, "Total device size in KiB");
-module_param(erase_size,ulong,0);
-MODULE_PARM_DESC(erase_size, "Device erase block size in KiB");
#define MTDRAM_TOTAL_SIZE (total_size * 1024)
#define MTDRAM_ERASE_SIZE (erase_size * 1024)
-#else
-#define MTDRAM_TOTAL_SIZE (CONFIG_MTDRAM_TOTAL_SIZE * 1024)
-#define MTDRAM_ERASE_SIZE (CONFIG_MTDRAM_ERASE_SIZE * 1024)
-#endif
+#ifdef MODULE
+module_param(total_size, ulong, 0);
+MODULE_PARM_DESC(total_size, "Total device size in KiB");
+module_param(erase_size, ulong, 0);
+MODULE_PARM_DESC(erase_size, "Device erase block size in KiB");
+#endif
// We could store these in the mtd structure, but we only support 1 device..
static struct mtd_info *mtd_info;
-
-static int
-ram_erase(struct mtd_info *mtd, struct erase_info *instr)
+static int ram_erase(struct mtd_info *mtd, struct erase_info *instr)
{
- DEBUG(MTD_DEBUG_LEVEL2, "ram_erase(pos:%ld, len:%ld)\n", (long)instr->addr, (long)instr->len);
- if (instr->addr + instr->len > mtd->size) {
- DEBUG(MTD_DEBUG_LEVEL1, "ram_erase() out of bounds (%ld > %ld)\n", (long)(instr->addr + instr->len), (long)mtd->size);
- return -EINVAL;
- }
-
- memset((char *)mtd->priv + instr->addr, 0xff, instr->len);
-
- instr->state = MTD_ERASE_DONE;
- mtd_erase_callback(instr);
-
- return 0;
+ if (instr->addr + instr->len > mtd->size)
+ return -EINVAL;
+
+ memset((char *)mtd->priv + instr->addr, 0xff, instr->len);
+
+ instr->state = MTD_ERASE_DONE;
+ mtd_erase_callback(instr);
+
+ return 0;
}
-static int ram_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf)
+static int ram_point(struct mtd_info *mtd, loff_t from, size_t len,
+ size_t *retlen, u_char **mtdbuf)
{
- if (from + len > mtd->size)
- return -EINVAL;
-
- *mtdbuf = mtd->priv + from;
- *retlen = len;
- return 0;
+ if (from + len > mtd->size)
+ return -EINVAL;
+
+ *mtdbuf = mtd->priv + from;
+ *retlen = len;
+ return 0;
}
-static void ram_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from,
- size_t len)
+static void ram_unpoint(struct mtd_info *mtd, u_char * addr, loff_t from,
+ size_t len)
{
- DEBUG(MTD_DEBUG_LEVEL2, "ram_unpoint\n");
}
static int ram_read(struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char *buf)
+ size_t *retlen, u_char *buf)
{
- DEBUG(MTD_DEBUG_LEVEL2, "ram_read(pos:%ld, len:%ld)\n", (long)from, (long)len);
- if (from + len > mtd->size) {
- DEBUG(MTD_DEBUG_LEVEL1, "ram_read() out of bounds (%ld > %ld)\n", (long)(from + len), (long)mtd->size);
- return -EINVAL;
- }
+ if (from + len > mtd->size)
+ return -EINVAL;
- memcpy(buf, mtd->priv + from, len);
+ memcpy(buf, mtd->priv + from, len);
- *retlen=len;
- return 0;
+ *retlen = len;
+ return 0;
}
static int ram_write(struct mtd_info *mtd, loff_t to, size_t len,
- size_t *retlen, const u_char *buf)
+ size_t *retlen, const u_char *buf)
{
- DEBUG(MTD_DEBUG_LEVEL2, "ram_write(pos:%ld, len:%ld)\n", (long)to, (long)len);
- if (to + len > mtd->size) {
- DEBUG(MTD_DEBUG_LEVEL1, "ram_write() out of bounds (%ld > %ld)\n", (long)(to + len), (long)mtd->size);
- return -EINVAL;
- }
+ if (to + len > mtd->size)
+ return -EINVAL;
- memcpy ((char *)mtd->priv + to, buf, len);
+ memcpy((char *)mtd->priv + to, buf, len);
- *retlen=len;
- return 0;
+ *retlen = len;
+ return 0;
}
static void __exit cleanup_mtdram(void)
{
- if (mtd_info) {
- del_mtd_device(mtd_info);
-#if CONFIG_MTDRAM_TOTAL_SIZE > 0
- if (mtd_info->priv)
-#if CONFIG_MTDRAM_ABS_POS > 0
- iounmap(mtd_info->priv);
-#else
- vfree(mtd_info->priv);
-#endif
-#endif
- kfree(mtd_info);
- }
-}
-
-int mtdram_init_device(struct mtd_info *mtd, void *mapped_address,
- unsigned long size, char *name)
-{
- memset(mtd, 0, sizeof(*mtd));
-
- /* Setup the MTD structure */
- mtd->name = name;
- mtd->type = MTD_RAM;
- mtd->flags = MTD_CAP_RAM;
- mtd->size = size;
- mtd->erasesize = MTDRAM_ERASE_SIZE;
- mtd->priv = mapped_address;
-
- mtd->owner = THIS_MODULE;
- mtd->erase = ram_erase;
- mtd->point = ram_point;
- mtd->unpoint = ram_unpoint;
- mtd->read = ram_read;
- mtd->write = ram_write;
-
- if (add_mtd_device(mtd)) {
- return -EIO;
- }
-
- return 0;
-}
-
-#if CONFIG_MTDRAM_TOTAL_SIZE > 0
-#if CONFIG_MTDRAM_ABS_POS > 0
-static int __init init_mtdram(void)
-{
- void *addr;
- int err;
- /* Allocate some memory */
- mtd_info = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
- if (!mtd_info)
- return -ENOMEM;
-
- addr = ioremap(CONFIG_MTDRAM_ABS_POS, MTDRAM_TOTAL_SIZE);
- if (!addr) {
- DEBUG(MTD_DEBUG_LEVEL1,
- "Failed to ioremap) memory region of size %ld at ABS_POS:%ld\n",
- (long)MTDRAM_TOTAL_SIZE, (long)CONFIG_MTDRAM_ABS_POS);
- kfree(mtd_info);
- mtd_info = NULL;
- return -ENOMEM;
- }
- err = mtdram_init_device(mtd_info, addr,
- MTDRAM_TOTAL_SIZE, "mtdram test device");
- if (err)
- {
- iounmap(addr);
- kfree(mtd_info);
- mtd_info = NULL;
- return err;
- }
- memset(mtd_info->priv, 0xff, MTDRAM_TOTAL_SIZE);
- return err;
+ if (mtd_info) {
+ del_mtd_device(mtd_info);
+ if (mtd_info->priv)
+ vfree(mtd_info->priv);
+ kfree(mtd_info);
+ }
}
-#else /* CONFIG_MTDRAM_ABS_POS > 0 */
-
-static int __init init_mtdram(void)
+int mtdram_init_device(struct mtd_info *mtd, void *mapped_address,
+ unsigned long size, char *name)
{
- void *addr;
- int err;
- /* Allocate some memory */
- mtd_info = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
- if (!mtd_info)
- return -ENOMEM;
-
- addr = vmalloc(MTDRAM_TOTAL_SIZE);
- if (!addr) {
- DEBUG(MTD_DEBUG_LEVEL1,
- "Failed to vmalloc memory region of size %ld\n",
- (long)MTDRAM_TOTAL_SIZE);
- kfree(mtd_info);
- mtd_info = NULL;
- return -ENOMEM;
- }
- err = mtdram_init_device(mtd_info, addr,
- MTDRAM_TOTAL_SIZE, "mtdram test device");
- if (err)
- {
- vfree(addr);
- kfree(mtd_info);
- mtd_info = NULL;
- return err;
- }
- memset(mtd_info->priv, 0xff, MTDRAM_TOTAL_SIZE);
- return err;
+ memset(mtd, 0, sizeof(*mtd));
+
+ /* Setup the MTD structure */
+ mtd->name = name;
+ mtd->type = MTD_RAM;
+ mtd->flags = MTD_CAP_RAM;
+ mtd->size = size;
+ mtd->erasesize = MTDRAM_ERASE_SIZE;
+ mtd->priv = mapped_address;
+
+ mtd->owner = THIS_MODULE;
+ mtd->erase = ram_erase;
+ mtd->point = ram_point;
+ mtd->unpoint = ram_unpoint;
+ mtd->read = ram_read;
+ mtd->write = ram_write;
+
+ if (add_mtd_device(mtd)) {
+ return -EIO;
+ }
+
+ return 0;
}
-#endif /* !(CONFIG_MTDRAM_ABS_POS > 0) */
-
-#else /* CONFIG_MTDRAM_TOTAL_SIZE > 0 */
static int __init init_mtdram(void)
{
- return 0;
+ void *addr;
+ int err;
+
+ if (!total_size)
+ return -EINVAL;
+
+ /* Allocate some memory */
+ mtd_info = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
+ if (!mtd_info)
+ return -ENOMEM;
+
+ addr = vmalloc(MTDRAM_TOTAL_SIZE);
+ if (!addr) {
+ kfree(mtd_info);
+ mtd_info = NULL;
+ return -ENOMEM;
+ }
+ err = mtdram_init_device(mtd_info, addr, MTDRAM_TOTAL_SIZE, "mtdram test device");
+ if (err) {
+ vfree(addr);
+ kfree(mtd_info);
+ mtd_info = NULL;
+ return err;
+ }
+ memset(mtd_info->priv, 0xff, MTDRAM_TOTAL_SIZE);
+ return err;
}
-#endif /* !(CONFIG_MTDRAM_TOTAL_SIZE > 0) */
module_init(init_mtdram);
module_exit(cleanup_mtdram);
@@ -232,4 +160,3 @@ module_exit(cleanup_mtdram);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Alexander Larsson <alexl@redhat.com>");
MODULE_DESCRIPTION("Simulated MTD driver for testing");
-
diff --git a/drivers/mtd/devices/phram.c b/drivers/mtd/devices/phram.c
index 5f8e164ddb7..a423a382095 100644
--- a/drivers/mtd/devices/phram.c
+++ b/drivers/mtd/devices/phram.c
@@ -1,5 +1,5 @@
/**
- * $Id: phram.c,v 1.11 2005/01/05 18:05:13 dwmw2 Exp $
+ * $Id: phram.c,v 1.14 2005/03/07 21:43:38 joern Exp $
*
* Copyright (c) ???? Jochen Schäuble <psionic@psionic.de>
* Copyright (c) 2003-2004 Jörn Engel <joern@wh.fh-wedel.de>
@@ -15,9 +15,7 @@
*
* Example:
* phram=swap,64Mi,128Mi phram=test,900Mi,1Mi
- *
*/
-
#include <asm/io.h>
#include <linux/init.h>
#include <linux/kernel.h>
@@ -36,7 +34,6 @@ struct phram_mtd_list {
static LIST_HEAD(phram_list);
-
static int phram_erase(struct mtd_info *mtd, struct erase_info *instr)
{
u_char *start = mtd->priv;
@@ -71,7 +68,8 @@ static int phram_point(struct mtd_info *mtd, loff_t from, size_t len,
return 0;
}
-static void phram_unpoint(struct mtd_info *mtd, u_char *addr, loff_t from, size_t len)
+static void phram_unpoint(struct mtd_info *mtd, u_char *addr, loff_t from,
+ size_t len)
{
}
@@ -80,8 +78,11 @@ static int phram_read(struct mtd_info *mtd, loff_t from, size_t len,
{
u_char *start = mtd->priv;
- if (from + len > mtd->size)
+ if (from >= mtd->size)
return -EINVAL;
+
+ if (len > mtd->size - from)
+ len = mtd->size - from;
memcpy(buf, start + from, len);
@@ -94,8 +95,11 @@ static int phram_write(struct mtd_info *mtd, loff_t to, size_t len,
{
u_char *start = mtd->priv;
- if (to + len > mtd->size)
+ if (to >= mtd->size)
return -EINVAL;
+
+ if (len > mtd->size - to)
+ len = mtd->size - to;
memcpy(start + to, buf, len);
@@ -107,9 +111,9 @@ static int phram_write(struct mtd_info *mtd, loff_t to, size_t len,
static void unregister_devices(void)
{
- struct phram_mtd_list *this;
+ struct phram_mtd_list *this, *safe;
- list_for_each_entry(this, &phram_list, list) {
+ list_for_each_entry_safe(this, safe, &phram_list, list) {
del_mtd_device(&this->mtd);
iounmap(this->mtd.priv);
kfree(this);
@@ -145,7 +149,7 @@ static int register_device(char *name, unsigned long start, unsigned long len)
new->mtd.write = phram_write;
new->mtd.owner = THIS_MODULE;
new->mtd.type = MTD_RAM;
- new->mtd.erasesize = 0;
+ new->mtd.erasesize = PAGE_SIZE;
ret = -EAGAIN;
if (add_mtd_device(&new->mtd)) {
@@ -214,6 +218,15 @@ static int parse_name(char **pname, const char *token)
return 0;
}
+
+static inline void kill_final_newline(char *str)
+{
+ char *newline = strrchr(str, '\n');
+ if (newline && !newline[1])
+ *newline = 0;
+}
+
+
#define parse_err(fmt, args...) do { \
ERROR(fmt , ## args); \
return 0; \
@@ -232,6 +245,7 @@ static int phram_setup(const char *val, struct kernel_param *kp)
parse_err("parameter too long\n");
strcpy(str, val);
+ kill_final_newline(str);
for (i=0; i<3; i++)
token[i] = strsep(&str, ",");
diff --git a/drivers/mtd/devices/slram.c b/drivers/mtd/devices/slram.c
index 5ab15e643be..84fa91392a8 100644
--- a/drivers/mtd/devices/slram.c
+++ b/drivers/mtd/devices/slram.c
@@ -1,6 +1,6 @@
/*======================================================================
- $Id: slram.c,v 1.33 2005/01/05 18:05:13 dwmw2 Exp $
+ $Id: slram.c,v 1.34 2005/01/06 21:16:42 jwboyer Exp $
This driver provides a method to access memory not used by the kernel
itself (i.e. if the kernel commandline mem=xxx is used). To actually
@@ -50,6 +50,7 @@
#include <linux/mtd/mtd.h>
#define SLRAM_MAX_DEVICES_PARAMS 6 /* 3 parameters / device */
+#define SLRAM_BLK_SZ 0x4000
#define T(fmt, args...) printk(KERN_DEBUG fmt, ## args)
#define E(fmt, args...) printk(KERN_NOTICE fmt, ## args)
@@ -108,6 +109,9 @@ static int slram_point(struct mtd_info *mtd, loff_t from, size_t len,
{
slram_priv_t *priv = mtd->priv;
+ if (from + len > mtd->size)
+ return -EINVAL;
+
*mtdbuf = priv->start + from;
*retlen = len;
return(0);
@@ -121,7 +125,13 @@ static int slram_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf)
{
slram_priv_t *priv = mtd->priv;
-
+
+ if (from > mtd->size)
+ return -EINVAL;
+
+ if (from + len > mtd->size)
+ len = mtd->size - from;
+
memcpy(buf, priv->start + from, len);
*retlen = len;
@@ -133,6 +143,9 @@ static int slram_write(struct mtd_info *mtd, loff_t to, size_t len,
{
slram_priv_t *priv = mtd->priv;
+ if (to + len > mtd->size)
+ return -EINVAL;
+
memcpy(priv->start + to, buf, len);
*retlen = len;
@@ -188,7 +201,7 @@ static int register_device(char *name, unsigned long start, unsigned long length
(*curmtd)->mtdinfo->name = name;
(*curmtd)->mtdinfo->size = length;
(*curmtd)->mtdinfo->flags = MTD_CLEAR_BITS | MTD_SET_BITS |
- MTD_WRITEB_WRITEABLE | MTD_VOLATILE;
+ MTD_WRITEB_WRITEABLE | MTD_VOLATILE | MTD_CAP_RAM;
(*curmtd)->mtdinfo->erase = slram_erase;
(*curmtd)->mtdinfo->point = slram_point;
(*curmtd)->mtdinfo->unpoint = slram_unpoint;
@@ -196,7 +209,7 @@ static int register_device(char *name, unsigned long start, unsigned long length
(*curmtd)->mtdinfo->write = slram_write;
(*curmtd)->mtdinfo->owner = THIS_MODULE;
(*curmtd)->mtdinfo->type = MTD_RAM;
- (*curmtd)->mtdinfo->erasesize = 0x0;
+ (*curmtd)->mtdinfo->erasesize = SLRAM_BLK_SZ;
if (add_mtd_device((*curmtd)->mtdinfo)) {
E("slram: Failed to register new device\n");
@@ -261,7 +274,7 @@ static int parse_cmdline(char *devname, char *szstart, char *szlength)
}
T("slram: devname=%s, devstart=0x%lx, devlength=0x%lx\n",
devname, devstart, devlength);
- if ((devstart < 0) || (devlength < 0)) {
+ if ((devstart < 0) || (devlength < 0) || (devlength % SLRAM_BLK_SZ != 0)) {
E("slram: Illegal start / length parameter.\n");
return(-EINVAL);
}
diff --git a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c
index 18cc8846e73..d9ab60b36fd 100644
--- a/drivers/mtd/ftl.c
+++ b/drivers/mtd/ftl.c
@@ -1,5 +1,5 @@
/* This version ported to the Linux-MTD system by dwmw2@infradead.org
- * $Id: ftl.c,v 1.54 2004/11/16 18:33:15 dwmw2 Exp $
+ * $Id: ftl.c,v 1.55 2005/01/17 13:47:21 hvr Exp $
*
* Fixes: Arnaldo Carvalho de Melo <acme@conectiva.com.br>
* - fixes some leaks on failure in build_maps and ftl_notify_add, cleanups
@@ -357,6 +357,7 @@ static int erase_xfer(partition_t *part,
if (!erase)
return -ENOMEM;
+ erase->mtd = part->mbd.mtd;
erase->callback = ftl_erase_callback;
erase->addr = xfer->Offset;
erase->len = 1 << part->header.EraseUnitSize;
@@ -1096,7 +1097,7 @@ struct mtd_blktrans_ops ftl_tr = {
int init_ftl(void)
{
- DEBUG(0, "$Id: ftl.c,v 1.54 2004/11/16 18:33:15 dwmw2 Exp $\n");
+ DEBUG(0, "$Id: ftl.c,v 1.55 2005/01/17 13:47:21 hvr Exp $\n");
return register_mtd_blktrans(&ftl_tr);
}
diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
index 8480057eadb..8d27dbf3fa8 100644
--- a/drivers/mtd/maps/Kconfig
+++ b/drivers/mtd/maps/Kconfig
@@ -1,5 +1,5 @@
# drivers/mtd/maps/Kconfig
-# $Id: Kconfig,v 1.42 2005/01/05 16:59:50 dwmw2 Exp $
+# $Id: Kconfig,v 1.51 2005/03/18 02:07:22 gleixner Exp $
menu "Mapping drivers for chip access"
depends on MTD!=n
@@ -122,16 +122,6 @@ config MTD_SBC_GXX
More info at
<http://www.arcomcontrols.com/products/icp/pc104/processors/SBC_GX1.htm>.
-config MTD_ELAN_104NC
- tristate "CFI Flash device mapped on Arcom ELAN-104NC"
- depends on X86 && MTD_CFI_INTELEXT && MTD_PARTITIONS && MTD_COMPLEX_MAPPINGS
- help
- This provides a driver for the on-board flash of the Arcom Control
- System's ELAN-104NC development board. By default the flash
- is split into 3 partitions which are accessed as separate MTD
- devices. This board utilizes Intel StrataFlash. More info at
- <http://www.arcomcontrols.com/products/icp/pc104/processors/ELAN104NC.htm>.
-
config MTD_LUBBOCK
tristate "CFI Flash device mapped on Intel Lubbock XScale eval board"
depends on ARCH_LUBBOCK && MTD_CFI_INTELEXT && MTD_PARTITIONS
@@ -213,74 +203,11 @@ config MTD_NETtel
help
Support for flash chips on NETtel/SecureEdge/SnapGear boards.
-config MTD_PB1XXX
- tristate "Flash devices on Alchemy PB1xxx boards"
- depends on MIPS && ( MIPS_PB1000 || MIPS_PB1100 || MIPS_PB1500 )
- help
- Flash memory access on Alchemy Pb1000/Pb1100/Pb1500 boards
-
-config MTD_PB1XXX_BOOT
- bool "PB1x00 boot flash device"
- depends on MTD_PB1XXX && ( MIPS_PB1100 || MIPS_PB1500 )
- help
- Use the first of the two 32MiB flash banks on Pb1100/Pb1500 board.
- You can say 'Y' to both this and 'MTD_PB1XXX_USER' below, to use
- both banks.
-
-config MTD_PB1XXX_USER
- bool "PB1x00 user flash device"
- depends on MTD_PB1XXX && ( MIPS_PB1100 || MIPS_PB1500 )
- default y if MTD_PB1XX_BOOT = n
- help
- Use the second of the two 32MiB flash banks on Pb1100/Pb1500 board.
- You can say 'Y' to both this and 'MTD_PB1XXX_BOOT' above, to use
- both banks.
-
-config MTD_PB1550
- tristate "Flash devices on Alchemy PB1550 board"
- depends on MIPS && MIPS_PB1550
+config MTD_ALCHEMY
+ tristate ' AMD Alchemy Pb1xxx/Db1xxx/RDK MTD support'
+ depends on MIPS && SOC_AU1X00
help
- Flash memory access on Alchemy Pb1550 board
-
-config MTD_PB1550_BOOT
- bool "PB1550 boot flash device"
- depends on MTD_PB1550
- help
- Use the first of the two 64MiB flash banks on Pb1550 board.
- You can say 'Y' to both this and 'MTD_PB1550_USER' below, to use
- both banks.
-
-config MTD_PB1550_USER
- bool "PB1550 user flash device"
- depends on MTD_PB1550
- default y if MTD_PB1550_BOOT = n
- help
- Use the second of the two 64MiB flash banks on Pb1550 board.
- You can say 'Y' to both this and 'MTD_PB1550_BOOT' above, to use
- both banks.
-
-config MTD_DB1550
- tristate "Flash devices on Alchemy DB1550 board"
- depends on MIPS && MIPS_DB1550
- help
- Flash memory access on Alchemy Db1550 board
-
-config MTD_DB1550_BOOT
- bool "DB1550 boot flash device"
- depends on MTD_DB1550
- help
- Use the first of the two 64MiB flash banks on Db1550 board.
- You can say 'Y' to both this and 'MTD_DB1550_USER' below, to use
- both banks.
-
-config MTD_DB1550_USER
- bool "DB1550 user flash device"
- depends on MTD_DB1550
- default y if MTD_DB1550_BOOT = n
- help
- Use the second of the two 64MiB flash banks on Db1550 board.
- You can say 'Y' to both this and 'MTD_DB1550_BOOT' above, to use
- both banks.
+ Flash memory access on AMD Alchemy Pb/Db/RDK Reference Boards
config MTD_DILNETPC
tristate "CFI Flash device mapped on DIL/Net PC"
@@ -637,13 +564,14 @@ config MTD_DMV182
Map driver for Dy-4 SVME/DMV-182 board.
config MTD_BAST
- tristate "Map driver for Simtec BAST (EB2410ITX)"
- depends on ARCH_BAST
+ tristate "Map driver for Simtec BAST (EB2410ITX) or Thorcom VR1000"
+ depends on ARCH_BAST || MACH_VR1000
select MTD_PARTITIONS
select MTD_MAP_BANK_WIDTH_16
select MTD_JEDECPROBE
help
- Map driver for NOR flash on the Simtec BAST (EB2410ITX).
+ Map driver for NOR flash on the Simtec BAST (EB2410ITX), or the
+ Thorcom VR1000
Note, this driver *cannot* over-ride the WP link on the
board, or currently detect the state of the link.
@@ -659,5 +587,15 @@ config MTD_SHARP_SL
help
This enables access to the flash chip on the Sharp SL Series of PDAs.
+config MTD_PLATRAM
+ tristate "Map driver for platform device RAM (mtd-ram)"
+ depends on MTD
+ select MTD_RAM
+ help
+ Map driver for RAM areas described via the platform device
+ system.
+
+ This selection automatically selects the map_ram driver.
+
endmenu
diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile
index 7ffe02b8530..164cafc101c 100644
--- a/drivers/mtd/maps/Makefile
+++ b/drivers/mtd/maps/Makefile
@@ -1,7 +1,7 @@
#
# linux/drivers/maps/Makefile
#
-# $Id: Makefile.common,v 1.23 2005/01/05 17:06:36 dwmw2 Exp $
+# $Id: Makefile.common,v 1.26 2005/03/02 14:51:04 dvrabel Exp $
ifeq ($(CONFIG_MTD_COMPLEX_MAPPINGS),y)
obj-$(CONFIG_MTD) += map_funcs.o
@@ -15,7 +15,6 @@ obj-$(CONFIG_MTD_CFI_FLAGADM) += cfi_flagadm.o
obj-$(CONFIG_MTD_CSTM_MIPS_IXX) += cstm_mips_ixx.o
obj-$(CONFIG_MTD_DC21285) += dc21285.o
obj-$(CONFIG_MTD_DILNETPC) += dilnetpc.o
-obj-$(CONFIG_MTD_ELAN_104NC) += elan-104nc.o
obj-$(CONFIG_MTD_EPXA10DB) += epxa10db-flash.o
obj-$(CONFIG_MTD_IQ80310) += iq80310.o
obj-$(CONFIG_MTD_L440GX) += l440gx.o
@@ -44,10 +43,7 @@ obj-$(CONFIG_MTD_DBOX2) += dbox2-flash.o
obj-$(CONFIG_MTD_OCELOT) += ocelot.o
obj-$(CONFIG_MTD_SOLUTIONENGINE)+= solutionengine.o
obj-$(CONFIG_MTD_PCI) += pci.o
-obj-$(CONFIG_MTD_PB1XXX) += pb1xxx-flash.o
-obj-$(CONFIG_MTD_DB1X00) += db1x00-flash.o
-obj-$(CONFIG_MTD_PB1550) += pb1550-flash.o
-obj-$(CONFIG_MTD_DB1550) += db1550-flash.o
+obj-$(CONFIG_MTD_ALCHEMY) += alchemy-flash.o
obj-$(CONFIG_MTD_LASAT) += lasat.o
obj-$(CONFIG_MTD_AUTCPU12) += autcpu12-nvram.o
obj-$(CONFIG_MTD_EDB7312) += edb7312.o
@@ -71,3 +67,4 @@ obj-$(CONFIG_MTD_IXP2000) += ixp2000.o
obj-$(CONFIG_MTD_WRSBC8260) += wr_sbc82xx_flash.o
obj-$(CONFIG_MTD_DMV182) += dmv182.o
obj-$(CONFIG_MTD_SHARP_SL) += sharpsl-flash.o
+obj-$(CONFIG_MTD_PLATRAM) += plat-ram.o
diff --git a/drivers/mtd/maps/alchemy-flash.c b/drivers/mtd/maps/alchemy-flash.c
new file mode 100644
index 00000000000..27fd2a3c3b6
--- /dev/null
+++ b/drivers/mtd/maps/alchemy-flash.c
@@ -0,0 +1,192 @@
+/*
+ * Flash memory access on AMD Alchemy evaluation boards
+ *
+ * $Id: alchemy-flash.c,v 1.1 2005/02/27 21:50:21 ppopov Exp $
+ *
+ * (C) 2003, 2004 Pete Popov <ppopov@embeddedalley.com>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/io.h>
+
+#ifdef DEBUG_RW
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+#ifdef CONFIG_MIPS_PB1000
+#define BOARD_MAP_NAME "Pb1000 Flash"
+#define BOARD_FLASH_SIZE 0x00800000 /* 8MB */
+#define BOARD_FLASH_WIDTH 4 /* 32-bits */
+#endif
+
+#ifdef CONFIG_MIPS_PB1500
+#define BOARD_MAP_NAME "Pb1500 Flash"
+#define BOARD_FLASH_SIZE 0x04000000 /* 64MB */
+#define BOARD_FLASH_WIDTH 4 /* 32-bits */
+#endif
+
+#ifdef CONFIG_MIPS_PB1100
+#define BOARD_MAP_NAME "Pb1100 Flash"
+#define BOARD_FLASH_SIZE 0x04000000 /* 64MB */
+#define BOARD_FLASH_WIDTH 4 /* 32-bits */
+#endif
+
+#ifdef CONFIG_MIPS_PB1550
+#define BOARD_MAP_NAME "Pb1550 Flash"
+#define BOARD_FLASH_SIZE 0x08000000 /* 128MB */
+#define BOARD_FLASH_WIDTH 4 /* 32-bits */
+#endif
+
+#ifdef CONFIG_MIPS_PB1200
+#define BOARD_MAP_NAME "Pb1200 Flash"
+#define BOARD_FLASH_SIZE 0x08000000 /* 128MB */
+#define BOARD_FLASH_WIDTH 2 /* 16-bits */
+#endif
+
+#ifdef CONFIG_MIPS_DB1000
+#define BOARD_MAP_NAME "Db1000 Flash"
+#define BOARD_FLASH_SIZE 0x02000000 /* 32MB */
+#define BOARD_FLASH_WIDTH 4 /* 32-bits */
+#endif
+
+#ifdef CONFIG_MIPS_DB1500
+#define BOARD_MAP_NAME "Db1500 Flash"
+#define BOARD_FLASH_SIZE 0x02000000 /* 32MB */
+#define BOARD_FLASH_WIDTH 4 /* 32-bits */
+#endif
+
+#ifdef CONFIG_MIPS_DB1100
+#define BOARD_MAP_NAME "Db1100 Flash"
+#define BOARD_FLASH_SIZE 0x02000000 /* 32MB */
+#define BOARD_FLASH_WIDTH 4 /* 32-bits */
+#endif
+
+#ifdef CONFIG_MIPS_DB1550
+#define BOARD_MAP_NAME "Db1550 Flash"
+#define BOARD_FLASH_SIZE 0x08000000 /* 128MB */
+#define BOARD_FLASH_WIDTH 4 /* 32-bits */
+#endif
+
+#ifdef CONFIG_MIPS_DB1200
+#define BOARD_MAP_NAME "Db1200 Flash"
+#define BOARD_FLASH_SIZE 0x04000000 /* 64MB */
+#define BOARD_FLASH_WIDTH 2 /* 16-bits */
+#endif
+
+#ifdef CONFIG_MIPS_HYDROGEN3
+#define BOARD_MAP_NAME "Hydrogen3 Flash"
+#define BOARD_FLASH_SIZE 0x02000000 /* 32MB */
+#define BOARD_FLASH_WIDTH 4 /* 32-bits */
+#define USE_LOCAL_ACCESSORS /* why? */
+#endif
+
+#ifdef CONFIG_MIPS_BOSPORUS
+#define BOARD_MAP_NAME "Bosporus Flash"
+#define BOARD_FLASH_SIZE 0x01000000 /* 16MB */
+#define BOARD_FLASH_WIDTH 2 /* 16-bits */
+#endif
+
+#ifdef CONFIG_MIPS_MIRAGE
+#define BOARD_MAP_NAME "Mirage Flash"
+#define BOARD_FLASH_SIZE 0x04000000 /* 64MB */
+#define BOARD_FLASH_WIDTH 4 /* 32-bits */
+#define USE_LOCAL_ACCESSORS /* why? */
+#endif
+
+static struct map_info alchemy_map = {
+ .name = BOARD_MAP_NAME,
+};
+
+static struct mtd_partition alchemy_partitions[] = {
+ {
+ .name = "User FS",
+ .size = BOARD_FLASH_SIZE - 0x00400000,
+ .offset = 0x0000000
+ },{
+ .name = "YAMON",
+ .size = 0x0100000,
+ .offset = MTDPART_OFS_APPEND,
+ .mask_flags = MTD_WRITEABLE
+ },{
+ .name = "raw kernel",
+ .size = (0x300000 - 0x40000), /* last 256KB is yamon env */
+ .offset = MTDPART_OFS_APPEND,
+ }
+};
+
+#define NB_OF(x) (sizeof(x)/sizeof(x[0]))
+
+static struct mtd_info *mymtd;
+
+int __init alchemy_mtd_init(void)
+{
+ struct mtd_partition *parts;
+ int nb_parts = 0;
+ unsigned long window_addr;
+ unsigned long window_size;
+
+ /* Default flash buswidth */
+ alchemy_map.bankwidth = BOARD_FLASH_WIDTH;
+
+ window_addr = 0x20000000 - BOARD_FLASH_SIZE;
+ window_size = BOARD_FLASH_SIZE;
+#ifdef CONFIG_MIPS_MIRAGE_WHY
+ /* Boot ROM flash bank only; no user bank */
+ window_addr = 0x1C000000;
+ window_size = 0x04000000;
+ /* USERFS from 0x1C00 0000 to 0x1FC00000 */
+ alchemy_partitions[0].size = 0x03C00000;
+#endif
+
+ /*
+ * Static partition definition selection
+ */
+ parts = alchemy_partitions;
+ nb_parts = NB_OF(alchemy_partitions);
+ alchemy_map.size = window_size;
+
+ /*
+ * Now let's probe for the actual flash. Do it here since
+ * specific machine settings might have been set above.
+ */
+ printk(KERN_NOTICE BOARD_MAP_NAME ": probing %d-bit flash bus\n",
+ alchemy_map.bankwidth*8);
+ alchemy_map.virt = ioremap(window_addr, window_size);
+ mymtd = do_map_probe("cfi_probe", &alchemy_map);
+ if (!mymtd) {
+ iounmap(alchemy_map.virt);
+ return -ENXIO;
+ }
+ mymtd->owner = THIS_MODULE;
+
+ add_mtd_partitions(mymtd, parts, nb_parts);
+ return 0;
+}
+
+static void __exit alchemy_mtd_cleanup(void)
+{
+ if (mymtd) {
+ del_mtd_partitions(mymtd);
+ map_destroy(mymtd);
+ iounmap(alchemy_map.virt);
+ }
+}
+
+module_init(alchemy_mtd_init);
+module_exit(alchemy_mtd_cleanup);
+
+MODULE_AUTHOR("Embedded Alley Solutions, Inc");
+MODULE_DESCRIPTION(BOARD_MAP_NAME " MTD driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/maps/amd76xrom.c b/drivers/mtd/maps/amd76xrom.c
index 51e97b05304..e8a900a7768 100644
--- a/drivers/mtd/maps/amd76xrom.c
+++ b/drivers/mtd/maps/amd76xrom.c
@@ -2,7 +2,7 @@
* amd76xrom.c
*
* Normal mappings of chips in physical memory
- * $Id: amd76xrom.c,v 1.19 2004/11/28 09:40:39 dwmw2 Exp $
+ * $Id: amd76xrom.c,v 1.20 2005/03/18 14:04:35 gleixner Exp $
*/
#include <linux/module.h>
@@ -314,7 +314,7 @@ static int __init init_amd76xrom(void)
}
return -ENXIO;
#if 0
- return pci_module_init(&amd76xrom_driver);
+ return pci_register_driver(&amd76xrom_driver);
#endif
}
diff --git a/drivers/mtd/maps/bast-flash.c b/drivers/mtd/maps/bast-flash.c
index 44de3a81b27..0c45464e3f7 100644
--- a/drivers/mtd/maps/bast-flash.c
+++ b/drivers/mtd/maps/bast-flash.c
@@ -1,14 +1,15 @@
/* linux/drivers/mtd/maps/bast_flash.c
*
- * Copyright (c) 2004 Simtec Electronics
- * Ben Dooks <ben@simtec.co.uk>
+ * Copyright (c) 2004-2005 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
*
* Simtec Bast (EB2410ITX) NOR MTD Mapping driver
*
* Changelog:
* 20-Sep-2004 BJD Initial version
+ * 17-Jan-2005 BJD Add whole device if no partitions found
*
- * $Id: bast-flash.c,v 1.1 2004/09/21 14:29:04 bjd Exp $
+ * $Id: bast-flash.c,v 1.2 2005/01/18 11:13:47 bjd Exp $
*
* 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
@@ -46,9 +47,9 @@
#include <asm/arch/bast-cpld.h>
#ifdef CONFIG_MTD_BAST_MAXSIZE
-#define AREA_MAXSIZE (CONFIG_MTD_BAST_MAXSIZE * (1024*1024))
+#define AREA_MAXSIZE (CONFIG_MTD_BAST_MAXSIZE * SZ_1M)
#else
-#define AREA_MAXSIZE (32*1024*1024)
+#define AREA_MAXSIZE (32 * SZ_1M)
#endif
#define PFX "bast-flash: "
@@ -189,6 +190,8 @@ static int bast_flash_probe(struct device *dev)
err = add_mtd_partitions(info->mtd, info->partitions, err);
if (err)
printk(KERN_ERR PFX "cannot add/parse partitions\n");
+ } else {
+ err = add_mtd_device(info->mtd);
}
if (err == 0)
diff --git a/drivers/mtd/maps/db1550-flash.c b/drivers/mtd/maps/db1550-flash.c
deleted file mode 100644
index d213888462a..00000000000
--- a/drivers/mtd/maps/db1550-flash.c
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * Flash memory access on Alchemy Db1550 board
- *
- * $Id: db1550-flash.c,v 1.7 2004/11/04 13:24:14 gleixner Exp $
- *
- * (C) 2004 Embedded Edge, LLC, based on db1550-flash.c:
- * (C) 2003, 2004 Pete Popov <ppopov@embeddedalley.com>
- *
- */
-
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-
-#include <asm/io.h>
-
-#ifdef DEBUG_RW
-#define DBG(x...) printk(x)
-#else
-#define DBG(x...)
-#endif
-
-static unsigned long window_addr;
-static unsigned long window_size;
-
-
-static struct map_info db1550_map = {
- .name = "Db1550 flash",
-};
-
-static unsigned char flash_bankwidth = 4;
-
-/*
- * Support only 64MB NOR Flash parts
- */
-
-#if defined(CONFIG_MTD_DB1550_BOOT) && defined(CONFIG_MTD_DB1550_USER)
-#define DB1550_BOTH_BANKS
-#elif defined(CONFIG_MTD_DB1550_BOOT) && !defined(CONFIG_MTD_DB1550_USER)
-#define DB1550_BOOT_ONLY
-#elif !defined(CONFIG_MTD_DB1550_BOOT) && defined(CONFIG_MTD_DB1550_USER)
-#define DB1550_USER_ONLY
-#endif
-
-#ifdef DB1550_BOTH_BANKS
-/* both banks will be used. Combine the first bank and the first
- * part of the second bank together into a single jffs/jffs2
- * partition.
- */
-static struct mtd_partition db1550_partitions[] = {
- /* assume boot[2:0]:swap is '0000' or '1000', which translates to:
- * 1C00 0000 1FFF FFFF CE0 64MB Boot NOR Flash
- * 1800 0000 1BFF FFFF CE0 64MB Param NOR Flash
- */
- {
- .name = "User FS",
- .size = (0x1FC00000 - 0x18000000),
- .offset = 0x0000000
- },{
- .name = "yamon",
- .size = 0x0100000,
- .offset = MTDPART_OFS_APPEND,
- .mask_flags = MTD_WRITEABLE
- },{
- .name = "raw kernel",
- .size = (0x300000 - 0x40000), /* last 256KB is yamon env */
- .offset = MTDPART_OFS_APPEND,
- }
-};
-#elif defined(DB1550_BOOT_ONLY)
-static struct mtd_partition db1550_partitions[] = {
- /* assume boot[2:0]:swap is '0000' or '1000', which translates to:
- * 1C00 0000 1FFF FFFF CE0 64MB Boot NOR Flash
- */
- {
- .name = "User FS",
- .size = 0x03c00000,
- .offset = 0x0000000
- },{
- .name = "yamon",
- .size = 0x0100000,
- .offset = MTDPART_OFS_APPEND,
- .mask_flags = MTD_WRITEABLE
- },{
- .name = "raw kernel",
- .size = (0x300000-0x40000), /* last 256KB is yamon env */
- .offset = MTDPART_OFS_APPEND,
- }
-};
-#elif defined(DB1550_USER_ONLY)
-static struct mtd_partition db1550_partitions[] = {
- /* assume boot[2:0]:swap is '0000' or '1000', which translates to:
- * 1800 0000 1BFF FFFF CE0 64MB Param NOR Flash
- */
- {
- .name = "User FS",
- .size = (0x4000000 - 0x200000), /* reserve 2MB for raw kernel */
- .offset = 0x0000000
- },{
- .name = "raw kernel",
- .size = MTDPART_SIZ_FULL,
- .offset = MTDPART_OFS_APPEND,
- }
-};
-#else
-#error MTD_DB1550 define combo error /* should never happen */
-#endif
-
-#define NB_OF(x) (sizeof(x)/sizeof(x[0]))
-
-static struct mtd_info *mymtd;
-
-/*
- * Probe the flash density and setup window address and size
- * based on user CONFIG options. There are times when we don't
- * want the MTD driver to be probing the boot or user flash,
- * so having the option to enable only one bank is important.
- */
-int setup_flash_params(void)
-{
-#if defined(DB1550_BOTH_BANKS)
- window_addr = 0x18000000;
- window_size = 0x8000000;
-#elif defined(DB1550_BOOT_ONLY)
- window_addr = 0x1C000000;
- window_size = 0x4000000;
-#else /* USER ONLY */
- window_addr = 0x18000000;
- window_size = 0x4000000;
-#endif
- return 0;
-}
-
-int __init db1550_mtd_init(void)
-{
- struct mtd_partition *parts;
- int nb_parts = 0;
-
- /* Default flash bankwidth */
- db1550_map.bankwidth = flash_bankwidth;
-
- if (setup_flash_params())
- return -ENXIO;
-
- /*
- * Static partition definition selection
- */
- parts = db1550_partitions;
- nb_parts = NB_OF(db1550_partitions);
- db1550_map.size = window_size;
-
- /*
- * Now let's probe for the actual flash. Do it here since
- * specific machine settings might have been set above.
- */
- printk(KERN_NOTICE "Db1550 flash: probing %d-bit flash bus\n",
- db1550_map.bankwidth*8);
- db1550_map.virt = ioremap(window_addr, window_size);
- mymtd = do_map_probe("cfi_probe", &db1550_map);
- if (!mymtd) return -ENXIO;
- mymtd->owner = THIS_MODULE;
-
- add_mtd_partitions(mymtd, parts, nb_parts);
- return 0;
-}
-
-static void __exit db1550_mtd_cleanup(void)
-{
- if (mymtd) {
- del_mtd_partitions(mymtd);
- map_destroy(mymtd);
- iounmap((void *) db1550_map.virt);
- }
-}
-
-module_init(db1550_mtd_init);
-module_exit(db1550_mtd_cleanup);
-
-MODULE_AUTHOR("Embedded Edge, LLC");
-MODULE_DESCRIPTION("Db1550 mtd map driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/maps/db1x00-flash.c b/drivers/mtd/maps/db1x00-flash.c
deleted file mode 100644
index faa68ec5690..00000000000
--- a/drivers/mtd/maps/db1x00-flash.c
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * Flash memory access on Alchemy Db1xxx boards
- *
- * $Id: db1x00-flash.c,v 1.6 2004/11/04 13:24:14 gleixner Exp $
- *
- * (C) 2003 Pete Popov <ppopov@embeddedalley.com>
- *
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-
-#include <asm/io.h>
-
-#ifdef DEBUG_RW
-#define DBG(x...) printk(x)
-#else
-#define DBG(x...)
-#endif
-
-/* MTD CONFIG OPTIONS */
-#if defined(CONFIG_MTD_DB1X00_BOOT) && defined(CONFIG_MTD_DB1X00_USER)
-#define DB1X00_BOTH_BANKS
-#elif defined(CONFIG_MTD_DB1X00_BOOT) && !defined(CONFIG_MTD_DB1X00_USER)
-#define DB1X00_BOOT_ONLY
-#elif !defined(CONFIG_MTD_DB1X00_BOOT) && defined(CONFIG_MTD_DB1X00_USER)
-#define DB1X00_USER_ONLY
-#endif
-
-static unsigned long window_addr;
-static unsigned long window_size;
-static unsigned long flash_size;
-
-static unsigned short *bcsr = (unsigned short *)0xAE000000;
-static unsigned char flash_bankwidth = 4;
-
-/*
- * The Db1x boards support different flash densities. We setup
- * the mtd_partition structures below for default of 64Mbit
- * flash densities, and override the partitions sizes, if
- * necessary, after we check the board status register.
- */
-
-#ifdef DB1X00_BOTH_BANKS
-/* both banks will be used. Combine the first bank and the first
- * part of the second bank together into a single jffs/jffs2
- * partition.
- */
-static struct mtd_partition db1x00_partitions[] = {
- {
- .name = "User FS",
- .size = 0x1c00000,
- .offset = 0x0000000
- },{
- .name = "yamon",
- .size = 0x0100000,
- .offset = MTDPART_OFS_APPEND,
- .mask_flags = MTD_WRITEABLE
- },{
- .name = "raw kernel",
- .size = (0x300000-0x40000), /* last 256KB is env */
- .offset = MTDPART_OFS_APPEND,
- }
-};
-#elif defined(DB1X00_BOOT_ONLY)
-static struct mtd_partition db1x00_partitions[] = {
- {
- .name = "User FS",
- .size = 0x00c00000,
- .offset = 0x0000000
- },{
- .name = "yamon",
- .size = 0x0100000,
- .offset = MTDPART_OFS_APPEND,
- .mask_flags = MTD_WRITEABLE
- },{
- .name = "raw kernel",
- .size = (0x300000-0x40000), /* last 256KB is env */
- .offset = MTDPART_OFS_APPEND,
- }
-};
-#elif defined(DB1X00_USER_ONLY)
-static struct mtd_partition db1x00_partitions[] = {
- {
- .name = "User FS",
- .size = 0x0e00000,
- .offset = 0x0000000
- },{
- .name = "raw kernel",
- .size = MTDPART_SIZ_FULL,
- .offset = MTDPART_OFS_APPEND,
- }
-};
-#else
-#error MTD_DB1X00 define combo error /* should never happen */
-#endif
-#define NB_OF(x) (sizeof(x)/sizeof(x[0]))
-
-#define NAME "Db1x00 Linux Flash"
-
-static struct map_info db1xxx_mtd_map = {
- .name = NAME,
-};
-
-static struct mtd_partition *parsed_parts;
-static struct mtd_info *db1xxx_mtd;
-
-/*
- * Probe the flash density and setup window address and size
- * based on user CONFIG options. There are times when we don't
- * want the MTD driver to be probing the boot or user flash,
- * so having the option to enable only one bank is important.
- */
-int setup_flash_params(void)
-{
- switch ((bcsr[2] >> 14) & 0x3) {
- case 0: /* 64Mbit devices */
- flash_size = 0x800000; /* 8MB per part */
-#if defined(DB1X00_BOTH_BANKS)
- window_addr = 0x1E000000;
- window_size = 0x2000000;
-#elif defined(DB1X00_BOOT_ONLY)
- window_addr = 0x1F000000;
- window_size = 0x1000000;
-#else /* USER ONLY */
- window_addr = 0x1E000000;
- window_size = 0x1000000;
-#endif
- break;
- case 1:
- /* 128 Mbit devices */
- flash_size = 0x1000000; /* 16MB per part */
-#if defined(DB1X00_BOTH_BANKS)
- window_addr = 0x1C000000;
- window_size = 0x4000000;
- /* USERFS from 0x1C00 0000 to 0x1FC0 0000 */
- db1x00_partitions[0].size = 0x3C00000;
-#elif defined(DB1X00_BOOT_ONLY)
- window_addr = 0x1E000000;
- window_size = 0x2000000;
- /* USERFS from 0x1E00 0000 to 0x1FC0 0000 */
- db1x00_partitions[0].size = 0x1C00000;
-#else /* USER ONLY */
- window_addr = 0x1C000000;
- window_size = 0x2000000;
- /* USERFS from 0x1C00 0000 to 0x1DE00000 */
- db1x00_partitions[0].size = 0x1DE0000;
-#endif
- break;
- case 2:
- /* 256 Mbit devices */
- flash_size = 0x4000000; /* 64MB per part */
-#if defined(DB1X00_BOTH_BANKS)
- return 1;
-#elif defined(DB1X00_BOOT_ONLY)
- /* Boot ROM flash bank only; no user bank */
- window_addr = 0x1C000000;
- window_size = 0x4000000;
- /* USERFS from 0x1C00 0000 to 0x1FC00000 */
- db1x00_partitions[0].size = 0x3C00000;
-#else /* USER ONLY */
- return 1;
-#endif
- break;
- default:
- return 1;
- }
- db1xxx_mtd_map.size = window_size;
- db1xxx_mtd_map.bankwidth = flash_bankwidth;
- db1xxx_mtd_map.phys = window_addr;
- db1xxx_mtd_map.bankwidth = flash_bankwidth;
- return 0;
-}
-
-int __init db1x00_mtd_init(void)
-{
- struct mtd_partition *parts;
- int nb_parts = 0;
-
- if (setup_flash_params())
- return -ENXIO;
-
- /*
- * Static partition definition selection
- */
- parts = db1x00_partitions;
- nb_parts = NB_OF(db1x00_partitions);
-
- /*
- * Now let's probe for the actual flash. Do it here since
- * specific machine settings might have been set above.
- */
- printk(KERN_NOTICE "Db1xxx flash: probing %d-bit flash bus\n",
- db1xxx_mtd_map.bankwidth*8);
- db1xxx_mtd_map.virt = ioremap(window_addr, window_size);
- db1xxx_mtd = do_map_probe("cfi_probe", &db1xxx_mtd_map);
- if (!db1xxx_mtd) return -ENXIO;
- db1xxx_mtd->owner = THIS_MODULE;
-
- add_mtd_partitions(db1xxx_mtd, parts, nb_parts);
- return 0;
-}
-
-static void __exit db1x00_mtd_cleanup(void)
-{
- if (db1xxx_mtd) {
- del_mtd_partitions(db1xxx_mtd);
- map_destroy(db1xxx_mtd);
- if (parsed_parts)
- kfree(parsed_parts);
- }
-}
-
-module_init(db1x00_mtd_init);
-module_exit(db1x00_mtd_cleanup);
-
-MODULE_AUTHOR("Pete Popov");
-MODULE_DESCRIPTION("Db1x00 mtd map driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/maps/elan-104nc.c b/drivers/mtd/maps/elan-104nc.c
deleted file mode 100644
index e9465f5c069..00000000000
--- a/drivers/mtd/maps/elan-104nc.c
+++ /dev/null
@@ -1,228 +0,0 @@
-/* elan-104nc.c -- MTD map driver for Arcom Control Systems ELAN-104NC
-
- Copyright (C) 2000 Arcom Control System Ltd
-
- 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
-
- $Id: elan-104nc.c,v 1.25 2004/11/28 09:40:39 dwmw2 Exp $
-
-The ELAN-104NC has up to 8 Mibyte of Intel StrataFlash (28F320/28F640) in x16
-mode. This drivers uses the CFI probe and Intel Extended Command Set drivers.
-
-The flash is accessed as follows:
-
- 32 kbyte memory window at 0xb0000-0xb7fff
-
- 16 bit I/O port (0x22) for some sort of paging.
-
-The single flash device is divided into 3 partition which appear as separate
-MTD devices.
-
-Linux thinks that the I/O port is used by the PIC and hence check_region() will
-always fail. So we don't do it. I just hope it doesn't break anything.
-*/
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <asm/io.h>
-
-#include <linux/mtd/map.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/partitions.h>
-
-#define WINDOW_START 0xb0000
-/* Number of bits in offset. */
-#define WINDOW_SHIFT 15
-#define WINDOW_LENGTH (1 << WINDOW_SHIFT)
-/* The bits for the offset into the window. */
-#define WINDOW_MASK (WINDOW_LENGTH-1)
-#define PAGE_IO 0x22
-#define PAGE_IO_SIZE 2
-
-static volatile int page_in_window = -1; // Current page in window.
-static void __iomem *iomapadr;
-static DEFINE_SPINLOCK(elan_104nc_spin);
-
-/* 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 = "ELAN-104NC flash boot partition",
- .offset = 0,
- .size = 640*1024 },
- { .name = "ELAN-104NC flash partition 1",
- .offset = 640*1024,
- .size = 896*1024 },
- { .name = "ELAN-104NC flash partition 2",
- .offset = (640+896)*1024 }
-};
-#define NUM_PARTITIONS (sizeof(partition_info)/sizeof(partition_info[0]))
-
-/*
- * If no idea what is going on here. This is taken from the FlashFX stuff.
- */
-#define ROMCS 1
-
-static inline void elan_104nc_setup(void)
-{
- u16 t;
-
- outw( 0x0023 + ROMCS*2, PAGE_IO );
- t=inb( PAGE_IO+1 );
-
- t=(t & 0xf9) | 0x04;
-
- outw( ((0x0023 + ROMCS*2) | (t << 8)), PAGE_IO );
-}
-
-static inline void elan_104nc_page(struct map_info *map, unsigned long ofs)
-{
- unsigned long page = ofs >> WINDOW_SHIFT;
-
- if( page!=page_in_window ) {
- int cmd1;
- int cmd2;
-
- cmd1=(page & 0x700) + 0x0833 + ROMCS*0x4000;
- cmd2=((page & 0xff) << 8) + 0x0032;
-
- outw( cmd1, PAGE_IO );
- outw( cmd2, PAGE_IO );
-
- page_in_window = page;
- }
-}
-
-
-static map_word elan_104nc_read16(struct map_info *map, unsigned long ofs)
-{
- map_word ret;
- spin_lock(&elan_104nc_spin);
- elan_104nc_page(map, ofs);
- ret.x[0] = readw(iomapadr + (ofs & WINDOW_MASK));
- spin_unlock(&elan_104nc_spin);
- return ret;
-}
-
-static void elan_104nc_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
-{
- while (len) {
- unsigned long thislen = len;
- if (len > (WINDOW_LENGTH - (from & WINDOW_MASK)))
- thislen = WINDOW_LENGTH-(from & WINDOW_MASK);
-
- spin_lock(&elan_104nc_spin);
- elan_104nc_page(map, from);
- memcpy_fromio(to, iomapadr + (from & WINDOW_MASK), thislen);
- spin_unlock(&elan_104nc_spin);
- to += thislen;
- from += thislen;
- len -= thislen;
- }
-}
-
-static void elan_104nc_write16(struct map_info *map, map_word d, unsigned long adr)
-{
- spin_lock(&elan_104nc_spin);
- elan_104nc_page(map, adr);
- writew(d.x[0], iomapadr + (adr & WINDOW_MASK));
- spin_unlock(&elan_104nc_spin);
-}
-
-static void elan_104nc_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
-{
- while(len) {
- unsigned long thislen = len;
- if (len > (WINDOW_LENGTH - (to & WINDOW_MASK)))
- thislen = WINDOW_LENGTH-(to & WINDOW_MASK);
-
- spin_lock(&elan_104nc_spin);
- elan_104nc_page(map, to);
- memcpy_toio(iomapadr + (to & WINDOW_MASK), from, thislen);
- spin_unlock(&elan_104nc_spin);
- to += thislen;
- from += thislen;
- len -= thislen;
- }
-}
-
-static struct map_info elan_104nc_map = {
- .name = "ELAN-104NC flash",
- .phys = NO_XIP,
- .size = 8*1024*1024, /* this must be set to a maximum possible amount
- of flash so the cfi probe routines find all
- the chips */
- .bankwidth = 2,
- .read = elan_104nc_read16,
- .copy_from = elan_104nc_copy_from,
- .write = elan_104nc_write16,
- .copy_to = elan_104nc_copy_to
-};
-
-/* MTD device for all of the flash. */
-static struct mtd_info *all_mtd;
-
-static void cleanup_elan_104nc(void)
-{
- if( all_mtd ) {
- del_mtd_partitions( all_mtd );
- map_destroy( all_mtd );
- }
-
- iounmap(iomapadr);
-}
-
-static int __init init_elan_104nc(void)
-{
- /* Urg! We use I/O port 0x22 without request_region()ing it,
- because it's already allocated to the PIC. */
-
- iomapadr = ioremap(WINDOW_START, WINDOW_LENGTH);
- if (!iomapadr) {
- printk( KERN_ERR"%s: failed to ioremap memory region\n",
- elan_104nc_map.name );
- return -EIO;
- }
-
- printk( KERN_INFO"%s: IO:0x%x-0x%x MEM:0x%x-0x%x\n",
- elan_104nc_map.name,
- PAGE_IO, PAGE_IO+PAGE_IO_SIZE-1,
- WINDOW_START, WINDOW_START+WINDOW_LENGTH-1 );
-
- elan_104nc_setup();
-
- /* Probe for chip. */
- all_mtd = do_map_probe("cfi_probe", &elan_104nc_map );
- if( !all_mtd ) {
- cleanup_elan_104nc();
- return -ENXIO;
- }
-
- all_mtd->owner = THIS_MODULE;
-
- /* Create MTD devices for each partition. */
- add_mtd_partitions( all_mtd, partition_info, NUM_PARTITIONS );
-
- return 0;
-}
-
-module_init(init_elan_104nc);
-module_exit(cleanup_elan_104nc);
-
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Arcom Control Systems Ltd.");
-MODULE_DESCRIPTION("MTD map driver for Arcom Control Systems ELAN-104NC");
diff --git a/drivers/mtd/maps/ichxrom.c b/drivers/mtd/maps/ichxrom.c
index 29d1cc1bb42..1800ceedf38 100644
--- a/drivers/mtd/maps/ichxrom.c
+++ b/drivers/mtd/maps/ichxrom.c
@@ -2,7 +2,7 @@
* ichxrom.c
*
* Normal mappings of chips in physical memory
- * $Id: ichxrom.c,v 1.16 2004/11/28 09:40:39 dwmw2 Exp $
+ * $Id: ichxrom.c,v 1.17 2005/03/18 14:04:35 gleixner Exp $
*/
#include <linux/module.h>
@@ -366,7 +366,7 @@ static int __init init_ichxrom(void)
}
return -ENXIO;
#if 0
- return pci_module_init(&ichxrom_driver);
+ return pci_register_driver(&ichxrom_driver);
#endif
}
diff --git a/drivers/mtd/maps/ixp2000.c b/drivers/mtd/maps/ixp2000.c
index c5b5f447e34..3e94b616743 100644
--- a/drivers/mtd/maps/ixp2000.c
+++ b/drivers/mtd/maps/ixp2000.c
@@ -1,5 +1,5 @@
/*
- * $Id: ixp2000.c,v 1.5 2004/11/16 17:15:48 dsaxena Exp $
+ * $Id: ixp2000.c,v 1.6 2005/03/18 14:07:46 gleixner Exp $
*
* drivers/mtd/maps/ixp2000.c
*
@@ -216,11 +216,6 @@ static int ixp2000_flash_probe(struct device *_dev)
goto Error;
}
- /*
- * Setup read mode for FLASH
- */
- *IXP2000_SLOWPORT_FRM = 1;
-
#if defined(__ARMEB__)
/*
* Enable erratum 44 workaround for NPUs with broken slowport
diff --git a/drivers/mtd/maps/pb1550-flash.c b/drivers/mtd/maps/pb1550-flash.c
deleted file mode 100644
index 1424726a219..00000000000
--- a/drivers/mtd/maps/pb1550-flash.c
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * Flash memory access on Alchemy Pb1550 board
- *
- * $Id: pb1550-flash.c,v 1.6 2004/11/04 13:24:15 gleixner Exp $
- *
- * (C) 2004 Embedded Edge, LLC, based on pb1550-flash.c:
- * (C) 2003 Pete Popov <ppopov@pacbell.net>
- *
- */
-
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-
-#include <asm/io.h>
-#include <asm/au1000.h>
-#include <asm/pb1550.h>
-
-#ifdef DEBUG_RW
-#define DBG(x...) printk(x)
-#else
-#define DBG(x...)
-#endif
-
-static unsigned long window_addr;
-static unsigned long window_size;
-
-
-static struct map_info pb1550_map = {
- .name = "Pb1550 flash",
-};
-
-static unsigned char flash_bankwidth = 4;
-
-/*
- * Support only 64MB NOR Flash parts
- */
-
-#ifdef PB1550_BOTH_BANKS
-/* both banks will be used. Combine the first bank and the first
- * part of the second bank together into a single jffs/jffs2
- * partition.
- */
-static struct mtd_partition pb1550_partitions[] = {
- /* assume boot[2:0]:swap is '0000' or '1000', which translates to:
- * 1C00 0000 1FFF FFFF CE0 64MB Boot NOR Flash
- * 1800 0000 1BFF FFFF CE0 64MB Param NOR Flash
- */
- {
- .name = "User FS",
- .size = (0x1FC00000 - 0x18000000),
- .offset = 0x0000000
- },{
- .name = "yamon",
- .size = 0x0100000,
- .offset = MTDPART_OFS_APPEND,
- .mask_flags = MTD_WRITEABLE
- },{
- .name = "raw kernel",
- .size = (0x300000 - 0x40000), /* last 256KB is yamon env */
- .offset = MTDPART_OFS_APPEND,
- }
-};
-#elif defined(PB1550_BOOT_ONLY)
-static struct mtd_partition pb1550_partitions[] = {
- /* assume boot[2:0]:swap is '0000' or '1000', which translates to:
- * 1C00 0000 1FFF FFFF CE0 64MB Boot NOR Flash
- */
- {
- .name = "User FS",
- .size = 0x03c00000,
- .offset = 0x0000000
- },{
- .name = "yamon",
- .size = 0x0100000,
- .offset = MTDPART_OFS_APPEND,
- .mask_flags = MTD_WRITEABLE
- },{
- .name = "raw kernel",
- .size = (0x300000-0x40000), /* last 256KB is yamon env */
- .offset = MTDPART_OFS_APPEND,
- }
-};
-#elif defined(PB1550_USER_ONLY)
-static struct mtd_partition pb1550_partitions[] = {
- /* assume boot[2:0]:swap is '0000' or '1000', which translates to:
- * 1800 0000 1BFF FFFF CE0 64MB Param NOR Flash
- */
- {
- .name = "User FS",
- .size = (0x4000000 - 0x200000), /* reserve 2MB for raw kernel */
- .offset = 0x0000000
- },{
- .name = "raw kernel",
- .size = MTDPART_SIZ_FULL,
- .offset = MTDPART_OFS_APPEND,
- }
-};
-#else
-#error MTD_PB1550 define combo error /* should never happen */
-#endif
-
-#define NB_OF(x) (sizeof(x)/sizeof(x[0]))
-
-static struct mtd_info *mymtd;
-
-/*
- * Probe the flash density and setup window address and size
- * based on user CONFIG options. There are times when we don't
- * want the MTD driver to be probing the boot or user flash,
- * so having the option to enable only one bank is important.
- */
-int setup_flash_params(void)
-{
- u16 boot_swapboot;
- boot_swapboot = (au_readl(MEM_STSTAT) & (0x7<<1)) |
- ((bcsr->status >> 6) & 0x1);
- printk("Pb1550 MTD: boot:swap %d\n", boot_swapboot);
-
- switch (boot_swapboot) {
- case 0: /* 512Mbit devices, both enabled */
- case 1:
- case 8:
- case 9:
-#if defined(PB1550_BOTH_BANKS)
- window_addr = 0x18000000;
- window_size = 0x8000000;
-#elif defined(PB1550_BOOT_ONLY)
- window_addr = 0x1C000000;
- window_size = 0x4000000;
-#else /* USER ONLY */
- window_addr = 0x1E000000;
- window_size = 0x4000000;
-#endif
- break;
- case 0xC:
- case 0xD:
- case 0xE:
- case 0xF:
- /* 64 MB Boot NOR Flash is disabled */
- /* and the start address is moved to 0x0C00000 */
- window_addr = 0x0C000000;
- window_size = 0x4000000;
- default:
- printk("Pb1550 MTD: unsupported boot:swap setting\n");
- return 1;
- }
- return 0;
-}
-
-int __init pb1550_mtd_init(void)
-{
- struct mtd_partition *parts;
- int nb_parts = 0;
-
- /* Default flash bankwidth */
- pb1550_map.bankwidth = flash_bankwidth;
-
- if (setup_flash_params())
- return -ENXIO;
-
- /*
- * Static partition definition selection
- */
- parts = pb1550_partitions;
- nb_parts = NB_OF(pb1550_partitions);
- pb1550_map.size = window_size;
-
- /*
- * Now let's probe for the actual flash. Do it here since
- * specific machine settings might have been set above.
- */
- printk(KERN_NOTICE "Pb1550 flash: probing %d-bit flash bus\n",
- pb1550_map.bankwidth*8);
- pb1550_map.virt = ioremap(window_addr, window_size);
- mymtd = do_map_probe("cfi_probe", &pb1550_map);
- if (!mymtd) return -ENXIO;
- mymtd->owner = THIS_MODULE;
-
- add_mtd_partitions(mymtd, parts, nb_parts);
- return 0;
-}
-
-static void __exit pb1550_mtd_cleanup(void)
-{
- if (mymtd) {
- del_mtd_partitions(mymtd);
- map_destroy(mymtd);
- }
-}
-
-module_init(pb1550_mtd_init);
-module_exit(pb1550_mtd_cleanup);
-
-MODULE_AUTHOR("Embedded Edge, LLC");
-MODULE_DESCRIPTION("Pb1550 mtd map driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/maps/pb1xxx-flash.c b/drivers/mtd/maps/pb1xxx-flash.c
deleted file mode 100644
index 06e73154055..00000000000
--- a/drivers/mtd/maps/pb1xxx-flash.c
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * Flash memory access on Alchemy Pb1xxx boards
- *
- * (C) 2001 Pete Popov <ppopov@mvista.com>
- *
- * $Id: pb1xxx-flash.c,v 1.14 2004/11/04 13:24:15 gleixner Exp $
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-
-#include <asm/io.h>
-
-#ifdef DEBUG_RW
-#define DBG(x...) printk(x)
-#else
-#define DBG(x...)
-#endif
-
-#ifdef CONFIG_MIPS_PB1000
-
-#define WINDOW_ADDR 0x1F800000
-#define WINDOW_SIZE 0x800000
-
-static struct mtd_partition pb1xxx_partitions[] = {
- {
- .name = "yamon env",
- .size = 0x00020000,
- .offset = 0,
- .mask_flags = MTD_WRITEABLE},
- {
- .name = "User FS",
- .size = 0x003e0000,
- .offset = 0x20000,},
- {
- .name = "boot code",
- .size = 0x100000,
- .offset = 0x400000,
- .mask_flags = MTD_WRITEABLE},
- {
- .name = "raw/kernel",
- .size = 0x300000,
- .offset = 0x500000}
-};
-
-#elif defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_PB1100)
-
-#if defined(CONFIG_MTD_PB1500_BOOT) && defined(CONFIG_MTD_PB1500_USER)
-/* both 32MB banks will be used. Combine the first 32MB bank and the
- * first 28MB of the second bank together into a single jffs/jffs2
- * partition.
- */
-#define WINDOW_ADDR 0x1C000000
-#define WINDOW_SIZE 0x4000000
-static struct mtd_partition pb1xxx_partitions[] = {
- {
- .name = "User FS",
- .size = 0x3c00000,
- .offset = 0x0000000
- },{
- .name = "yamon",
- .size = 0x0100000,
- .offset = 0x3c00000,
- .mask_flags = MTD_WRITEABLE
- },{
- .name = "raw kernel",
- .size = 0x02c0000,
- .offset = 0x3d00000
- }
-};
-#elif defined(CONFIG_MTD_PB1500_BOOT) && !defined(CONFIG_MTD_PB1500_USER)
-#define WINDOW_ADDR 0x1E000000
-#define WINDOW_SIZE 0x2000000
-static struct mtd_partition pb1xxx_partitions[] = {
- {
- .name = "User FS",
- .size = 0x1c00000,
- .offset = 0x0000000
- },{
- .name = "yamon",
- .size = 0x0100000,
- .offset = 0x1c00000,
- .mask_flags = MTD_WRITEABLE
- },{
- .name = "raw kernel",
- .size = 0x02c0000,
- .offset = 0x1d00000
- }
-};
-#elif !defined(CONFIG_MTD_PB1500_BOOT) && defined(CONFIG_MTD_PB1500_USER)
-#define WINDOW_ADDR 0x1C000000
-#define WINDOW_SIZE 0x2000000
-static struct mtd_partition pb1xxx_partitions[] = {
- {
- .name = "User FS",
- .size = 0x1e00000,
- .offset = 0x0000000
- },{
- .name = "raw kernel",
- .size = 0x0200000,
- .offset = 0x1e00000,
- }
-};
-#else
-#error MTD_PB1500 define combo error /* should never happen */
-#endif
-#else
-#error Unsupported board
-#endif
-
-#define NAME "Pb1x00 Linux Flash"
-#define PADDR WINDOW_ADDR
-#define BUSWIDTH 4
-#define SIZE WINDOW_SIZE
-#define PARTITIONS 4
-
-static struct map_info pb1xxx_mtd_map = {
- .name = NAME,
- .size = SIZE,
- .bankwidth = BUSWIDTH,
- .phys = PADDR,
-};
-
-static struct mtd_info *pb1xxx_mtd;
-
-int __init pb1xxx_mtd_init(void)
-{
- struct mtd_partition *parts;
- int nb_parts = 0;
- char *part_type;
-
- /*
- * Static partition definition selection
- */
- part_type = "static";
- parts = pb1xxx_partitions;
- nb_parts = ARRAY_SIZE(pb1xxx_partitions);
-
- /*
- * Now let's probe for the actual flash. Do it here since
- * specific machine settings might have been set above.
- */
- printk(KERN_NOTICE "Pb1xxx flash: probing %d-bit flash bus\n",
- BUSWIDTH*8);
- pb1xxx_mtd_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE);
-
- simple_map_init(&pb1xxx_mtd_map);
-
- pb1xxx_mtd = do_map_probe("cfi_probe", &pb1xxx_mtd_map);
- if (!pb1xxx_mtd) return -ENXIO;
- pb1xxx_mtd->owner = THIS_MODULE;
-
- add_mtd_partitions(pb1xxx_mtd, parts, nb_parts);
- return 0;
-}
-
-static void __exit pb1xxx_mtd_cleanup(void)
-{
- if (pb1xxx_mtd) {
- del_mtd_partitions(pb1xxx_mtd);
- map_destroy(pb1xxx_mtd);
- iounmap((void *) pb1xxx_mtd_map.virt);
- }
-}
-
-module_init(pb1xxx_mtd_init);
-module_exit(pb1xxx_mtd_cleanup);
-
-MODULE_AUTHOR("Pete Popov");
-MODULE_DESCRIPTION("Pb1xxx CFI map driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/maps/pci.c b/drivers/mtd/maps/pci.c
index 08b60bdc538..18dbd3af1ea 100644
--- a/drivers/mtd/maps/pci.c
+++ b/drivers/mtd/maps/pci.c
@@ -7,7 +7,7 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
- * $Id: pci.c,v 1.9 2004/11/28 09:40:40 dwmw2 Exp $
+ * $Id: pci.c,v 1.10 2005/03/18 14:04:35 gleixner Exp $
*
* Generic PCI memory map driver. We support the following boards:
* - Intel IQ80310 ATU.
@@ -370,7 +370,7 @@ static struct pci_driver mtd_pci_driver = {
static int __init mtd_pci_maps_init(void)
{
- return pci_module_init(&mtd_pci_driver);
+ return pci_register_driver(&mtd_pci_driver);
}
static void __exit mtd_pci_maps_exit(void)
diff --git a/drivers/mtd/maps/plat-ram.c b/drivers/mtd/maps/plat-ram.c
new file mode 100644
index 00000000000..118b04544ca
--- /dev/null
+++ b/drivers/mtd/maps/plat-ram.c
@@ -0,0 +1,278 @@
+/* drivers/mtd/maps/plat-ram.c
+ *
+ * (c) 2004-2005 Simtec Electronics
+ * http://www.simtec.co.uk/products/SWLINUX/
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * Generic platfrom device based RAM map
+ *
+ * $Id: plat-ram.c,v 1.3 2005/03/19 22:41:27 gleixner Exp $
+ *
+ * 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/module.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/device.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/plat-ram.h>
+
+#include <asm/io.h>
+
+/* private structure for each mtd platform ram device created */
+
+struct platram_info {
+ struct device *dev;
+ struct mtd_info *mtd;
+ struct map_info map;
+ struct mtd_partition *partitions;
+ struct resource *area;
+ struct platdata_mtd_ram *pdata;
+};
+
+/* to_platram_info()
+ *
+ * device private data to struct platram_info conversion
+*/
+
+static inline struct platram_info *to_platram_info(struct device *dev)
+{
+ return (struct platram_info *)dev_get_drvdata(dev);
+}
+
+/* platram_setrw
+ *
+ * call the platform device's set rw/ro control
+ *
+ * to = 0 => read-only
+ * = 1 => read-write
+*/
+
+static inline void platram_setrw(struct platram_info *info, int to)
+{
+ if (info->pdata == NULL)
+ return;
+
+ if (info->pdata->set_rw != NULL)
+ (info->pdata->set_rw)(info->dev, to);
+}
+
+/* platram_remove
+ *
+ * called to remove the device from the driver's control
+*/
+
+static int platram_remove(struct device *dev)
+{
+ struct platram_info *info = to_platram_info(dev);
+
+ dev_set_drvdata(dev, NULL);
+
+ dev_dbg(dev, "removing device\n");
+
+ if (info == NULL)
+ return 0;
+
+ if (info->mtd) {
+#ifdef CONFIG_MTD_PARTITIONS
+ if (info->partitions) {
+ del_mtd_partitions(info->mtd);
+ kfree(info->partitions);
+ }
+#endif
+ del_mtd_device(info->mtd);
+ map_destroy(info->mtd);
+ }
+
+ /* ensure ram is left read-only */
+
+ platram_setrw(info, PLATRAM_RO);
+
+ /* release resources */
+
+ if (info->area) {
+ release_resource(info->area);
+ kfree(info->area);
+ }
+
+ if (info->map.virt != NULL)
+ iounmap(info->map.virt);
+
+ kfree(info);
+
+ return 0;
+}
+
+/* platram_probe
+ *
+ * called from device drive system when a device matching our
+ * driver is found.
+*/
+
+static int platram_probe(struct device *dev)
+{
+ struct platform_device *pd = to_platform_device(dev);
+ struct platdata_mtd_ram *pdata;
+ struct platram_info *info;
+ struct resource *res;
+ int err = 0;
+
+ dev_dbg(dev, "probe entered\n");
+
+ if (dev->platform_data == NULL) {
+ dev_err(dev, "no platform data supplied\n");
+ err = -ENOENT;
+ goto exit_error;
+ }
+
+ pdata = dev->platform_data;
+
+ info = kmalloc(sizeof(*info), GFP_KERNEL);
+ if (info == NULL) {
+ dev_err(dev, "no memory for flash info\n");
+ err = -ENOMEM;
+ goto exit_error;
+ }
+
+ memset(info, 0, sizeof(*info));
+ dev_set_drvdata(dev, info);
+
+ info->dev = dev;
+ info->pdata = pdata;
+
+ /* get the resource for the memory mapping */
+
+ res = platform_get_resource(pd, IORESOURCE_MEM, 0);
+
+ if (res == NULL) {
+ dev_err(dev, "no memory resource specified\n");
+ err = -ENOENT;
+ goto exit_free;
+ }
+
+ dev_dbg(dev, "got platform resource %p (0x%lx)\n", res, res->start);
+
+ /* setup map parameters */
+
+ info->map.phys = res->start;
+ info->map.size = (res->end - res->start) + 1;
+ info->map.name = pdata->mapname != NULL ? pdata->mapname : pd->name;
+ info->map.bankwidth = pdata->bankwidth;
+
+ /* register our usage of the memory area */
+
+ info->area = request_mem_region(res->start, info->map.size, pd->name);
+ if (info->area == NULL) {
+ dev_err(dev, "failed to request memory region\n");
+ err = -EIO;
+ goto exit_free;
+ }
+
+ /* remap the memory area */
+
+ info->map.virt = ioremap(res->start, info->map.size);
+ dev_dbg(dev, "virt %p, %lu bytes\n", info->map.virt, info->map.size);
+
+ if (info->map.virt == NULL) {
+ dev_err(dev, "failed to ioremap() region\n");
+ err = -EIO;
+ goto exit_free;
+ }
+
+ simple_map_init(&info->map);
+
+ dev_dbg(dev, "initialised map, probing for mtd\n");
+
+ /* probe for the right mtd map driver */
+
+ info->mtd = do_map_probe("map_ram" , &info->map);
+ if (info->mtd == NULL) {
+ dev_err(dev, "failed to probe for map_ram\n");
+ err = -ENOMEM;
+ goto exit_free;
+ }
+
+ info->mtd->owner = THIS_MODULE;
+
+ platram_setrw(info, PLATRAM_RW);
+
+ /* check to see if there are any available partitions, or wether
+ * to add this device whole */
+
+#ifdef CONFIG_MTD_PARTITIONS
+ if (pdata->nr_partitions > 0) {
+ const char **probes = { NULL };
+
+ if (pdata->probes)
+ probes = (const char **)pdata->probes;
+
+ err = parse_mtd_partitions(info->mtd, probes,
+ &info->partitions, 0);
+ if (err > 0) {
+ err = add_mtd_partitions(info->mtd, info->partitions,
+ err);
+ }
+ }
+#endif /* CONFIG_MTD_PARTITIONS */
+
+ if (add_mtd_device(info->mtd)) {
+ dev_err(dev, "add_mtd_device() failed\n");
+ err = -ENOMEM;
+ }
+
+ dev_info(dev, "registered mtd device\n");
+ return err;
+
+ exit_free:
+ platram_remove(dev);
+ exit_error:
+ return err;
+}
+
+/* device driver info */
+
+static struct device_driver platram_driver = {
+ .name = "mtd-ram",
+ .bus = &platform_bus_type,
+ .probe = platram_probe,
+ .remove = platram_remove,
+};
+
+/* module init/exit */
+
+static int __init platram_init(void)
+{
+ printk("Generic platform RAM MTD, (c) 2004 Simtec Electronics\n");
+ return driver_register(&platram_driver);
+}
+
+static void __exit platram_exit(void)
+{
+ driver_unregister(&platram_driver);
+}
+
+module_init(platram_init);
+module_exit(platram_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
+MODULE_DESCRIPTION("MTD platform RAM map driver");
diff --git a/drivers/mtd/maps/scb2_flash.c b/drivers/mtd/maps/scb2_flash.c
index 5bb3b600e5d..97a8dfd6925 100644
--- a/drivers/mtd/maps/scb2_flash.c
+++ b/drivers/mtd/maps/scb2_flash.c
@@ -1,6 +1,6 @@
/*
* MTD map driver for BIOS Flash on Intel SCB2 boards
- * $Id: scb2_flash.c,v 1.11 2004/11/28 09:40:40 dwmw2 Exp $
+ * $Id: scb2_flash.c,v 1.12 2005/03/18 14:04:35 gleixner Exp $
* Copyright (C) 2002 Sun Microsystems, Inc.
* Tim Hockin <thockin@sun.com>
*
@@ -238,7 +238,7 @@ static struct pci_driver scb2_flash_driver = {
static int __init
scb2_flash_init(void)
{
- return pci_module_init(&scb2_flash_driver);
+ return pci_register_driver(&scb2_flash_driver);
}
static void __exit
diff --git a/drivers/mtd/maps/sharpsl-flash.c b/drivers/mtd/maps/sharpsl-flash.c
index b3b39cb7c60..d15da6fd84c 100644
--- a/drivers/mtd/maps/sharpsl-flash.c
+++ b/drivers/mtd/maps/sharpsl-flash.c
@@ -4,7 +4,7 @@
* Copyright (C) 2001 Lineo Japan, Inc.
* Copyright (C) 2002 SHARP
*
- * $Id: sharpsl-flash.c,v 1.2 2004/11/24 20:38:06 rpurdie Exp $
+ * $Id: sharpsl-flash.c,v 1.5 2005/03/21 08:42:11 rpurdie Exp $
*
* based on rpxlite.c,v 1.15 2001/10/02 15:05:14 dwmw2 Exp
* Handle mapping of the flash on the RPX Lite and CLLF boards
@@ -24,13 +24,14 @@
#include <linux/module.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 <asm/io.h>
+#include <asm/mach-types.h>
#define WINDOW_ADDR 0x00000000
-#define WINDOW_SIZE 0x01000000
+#define WINDOW_SIZE 0x00800000
#define BANK_WIDTH 2
static struct mtd_info *mymtd;
@@ -44,9 +45,7 @@ struct map_info sharpsl_map = {
static struct mtd_partition sharpsl_partitions[1] = {
{
- name: "Filesystem",
- size: 0x006d0000,
- offset: 0x00120000
+ name: "Boot PROM Filesystem",
}
};
@@ -58,12 +57,16 @@ int __init init_sharpsl(void)
int nb_parts = 0;
char *part_type = "static";
- printk(KERN_NOTICE "Sharp SL series flash device: %x at %x\n", WINDOW_SIZE, WINDOW_ADDR);
+ printk(KERN_NOTICE "Sharp SL series flash device: %x at %x\n",
+ WINDOW_SIZE, WINDOW_ADDR);
sharpsl_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE);
if (!sharpsl_map.virt) {
printk("Failed to ioremap\n");
return -EIO;
}
+
+ simple_map_init(&sharpsl_map);
+
mymtd = do_map_probe("map_rom", &sharpsl_map);
if (!mymtd) {
iounmap(sharpsl_map.virt);
@@ -72,6 +75,22 @@ int __init init_sharpsl(void)
mymtd->owner = THIS_MODULE;
+ if (machine_is_corgi() || machine_is_shepherd() || machine_is_husky()
+ || machine_is_poodle()) {
+ sharpsl_partitions[0].size=0x006d0000;
+ sharpsl_partitions[0].offset=0x00120000;
+ } else if (machine_is_tosa()) {
+ sharpsl_partitions[0].size=0x006a0000;
+ sharpsl_partitions[0].offset=0x00160000;
+ } else if (machine_is_spitz()) {
+ sharpsl_partitions[0].size=0x006b0000;
+ sharpsl_partitions[0].offset=0x00140000;
+ } else {
+ map_destroy(mymtd);
+ iounmap(sharpsl_map.virt);
+ return -ENODEV;
+ }
+
parts = sharpsl_partitions;
nb_parts = NB_OF(sharpsl_partitions);
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index 510ad78312c..da3f1a8f756 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -1,5 +1,5 @@
/*
- * $Id: mtdchar.c,v 1.66 2005/01/05 18:05:11 dwmw2 Exp $
+ * $Id: mtdchar.c,v 1.70 2005/04/01 15:36:11 nico Exp $
*
* Character-device access to raw MTD devices.
*
@@ -59,9 +59,25 @@ static inline void mtdchar_devfs_exit(void)
#define mtdchar_devfs_exit() do { } while(0)
#endif
+/*
+ * We use file->private_data to store a pointer to the MTDdevice.
+ * Since alighment is at least 32 bits, we have 2 bits free for OTP
+ * modes as well.
+ */
+
+#define TO_MTD(file) (struct mtd_info *)((long)((file)->private_data) & ~3L)
+
+#define MTD_MODE_OTP_FACT 1
+#define MTD_MODE_OTP_USER 2
+#define MTD_MODE(file) ((long)((file)->private_data) & 3)
+
+#define SET_MTD_MODE(file, mode) \
+ do { long __p = (long)((file)->private_data); \
+ (file)->private_data = (void *)((__p & ~3L) | mode); } while (0)
+
static loff_t mtd_lseek (struct file *file, loff_t offset, int orig)
{
- struct mtd_info *mtd = file->private_data;
+ struct mtd_info *mtd = TO_MTD(file);
switch (orig) {
case 0:
@@ -134,7 +150,7 @@ static int mtd_close(struct inode *inode, struct file *file)
DEBUG(MTD_DEBUG_LEVEL0, "MTD_close\n");
- mtd = file->private_data;
+ mtd = TO_MTD(file);
if (mtd->sync)
mtd->sync(mtd);
@@ -151,7 +167,7 @@ static int mtd_close(struct inode *inode, struct file *file)
static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t *ppos)
{
- struct mtd_info *mtd = file->private_data;
+ struct mtd_info *mtd = TO_MTD(file);
size_t retlen=0;
size_t total_retlen=0;
int ret=0;
@@ -178,7 +194,16 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t
if (!kbuf)
return -ENOMEM;
- ret = MTD_READ(mtd, *ppos, len, &retlen, kbuf);
+ switch (MTD_MODE(file)) {
+ case MTD_MODE_OTP_FACT:
+ ret = mtd->read_fact_prot_reg(mtd, *ppos, len, &retlen, kbuf);
+ break;
+ case MTD_MODE_OTP_USER:
+ ret = mtd->read_user_prot_reg(mtd, *ppos, len, &retlen, kbuf);
+ break;
+ default:
+ ret = MTD_READ(mtd, *ppos, len, &retlen, kbuf);
+ }
/* Nand returns -EBADMSG on ecc errors, but it returns
* the data. For our userspace tools it is important
* to dump areas with ecc errors !
@@ -196,6 +221,8 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t
count -= retlen;
buf += retlen;
+ if (retlen == 0)
+ count = 0;
}
else {
kfree(kbuf);
@@ -210,7 +237,7 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t
static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count,loff_t *ppos)
{
- struct mtd_info *mtd = file->private_data;
+ struct mtd_info *mtd = TO_MTD(file);
char *kbuf;
size_t retlen;
size_t total_retlen=0;
@@ -245,7 +272,20 @@ static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count
return -EFAULT;
}
- ret = (*(mtd->write))(mtd, *ppos, len, &retlen, kbuf);
+ switch (MTD_MODE(file)) {
+ case MTD_MODE_OTP_FACT:
+ ret = -EROFS;
+ break;
+ case MTD_MODE_OTP_USER:
+ if (!mtd->write_user_prot_reg) {
+ ret = -EOPNOTSUPP;
+ break;
+ }
+ ret = mtd->write_user_prot_reg(mtd, *ppos, len, &retlen, kbuf);
+ break;
+ default:
+ ret = (*(mtd->write))(mtd, *ppos, len, &retlen, kbuf);
+ }
if (!ret) {
*ppos += retlen;
total_retlen += retlen;
@@ -276,7 +316,7 @@ static void mtdchar_erase_callback (struct erase_info *instr)
static int mtd_ioctl(struct inode *inode, struct file *file,
u_int cmd, u_long arg)
{
- struct mtd_info *mtd = file->private_data;
+ struct mtd_info *mtd = TO_MTD(file);
void __user *argp = (void __user *)arg;
int ret = 0;
u_long size;
@@ -518,6 +558,80 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
break;
}
+#ifdef CONFIG_MTD_OTP
+ case OTPSELECT:
+ {
+ int mode;
+ if (copy_from_user(&mode, argp, sizeof(int)))
+ return -EFAULT;
+ SET_MTD_MODE(file, 0);
+ switch (mode) {
+ case MTD_OTP_FACTORY:
+ if (!mtd->read_fact_prot_reg)
+ ret = -EOPNOTSUPP;
+ else
+ SET_MTD_MODE(file, MTD_MODE_OTP_FACT);
+ break;
+ case MTD_OTP_USER:
+ if (!mtd->read_fact_prot_reg)
+ ret = -EOPNOTSUPP;
+ else
+ SET_MTD_MODE(file, MTD_MODE_OTP_USER);
+ break;
+ default:
+ ret = -EINVAL;
+ case MTD_OTP_OFF:
+ break;
+ }
+ file->f_pos = 0;
+ break;
+ }
+
+ case OTPGETREGIONCOUNT:
+ case OTPGETREGIONINFO:
+ {
+ struct otp_info *buf = kmalloc(4096, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+ ret = -EOPNOTSUPP;
+ switch (MTD_MODE(file)) {
+ case MTD_MODE_OTP_FACT:
+ if (mtd->get_fact_prot_info)
+ ret = mtd->get_fact_prot_info(mtd, buf, 4096);
+ break;
+ case MTD_MODE_OTP_USER:
+ if (mtd->get_user_prot_info)
+ ret = mtd->get_user_prot_info(mtd, buf, 4096);
+ break;
+ }
+ if (ret >= 0) {
+ if (cmd == OTPGETREGIONCOUNT) {
+ int nbr = ret / sizeof(struct otp_info);
+ ret = copy_to_user(argp, &nbr, sizeof(int));
+ } else
+ ret = copy_to_user(argp, buf, ret);
+ if (ret)
+ ret = -EFAULT;
+ }
+ kfree(buf);
+ break;
+ }
+
+ case OTPLOCK:
+ {
+ struct otp_info info;
+
+ if (MTD_MODE(file) != MTD_MODE_OTP_USER)
+ return -EINVAL;
+ if (copy_from_user(&info, argp, sizeof(info)))
+ return -EFAULT;
+ if (!mtd->lock_user_prot_reg)
+ return -EOPNOTSUPP;
+ ret = mtd->lock_user_prot_reg(mtd, info.start, info.length);
+ break;
+ }
+#endif
+
default:
ret = -ENOTTY;
}
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index 9c0315d1b1c..dc86df18e94 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -1,5 +1,5 @@
/*
- * $Id: mtdcore.c,v 1.44 2004/11/16 18:28:59 dwmw2 Exp $
+ * $Id: mtdcore.c,v 1.45 2005/02/18 14:34:50 dedekind Exp $
*
* Core registration and callback routines for MTD
* drivers and users.
@@ -149,8 +149,8 @@ void register_mtd_user (struct mtd_notifier *new)
}
/**
- * register_mtd_user - unregister a 'user' of MTD devices.
- * @new: pointer to notifier info structure
+ * unregister_mtd_user - unregister a 'user' of MTD devices.
+ * @old: pointer to notifier info structure
*
* Removes a callback function pair from the list of 'users' to be
* notified upon addition or removal of MTD devices. Causes the
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index 96ebb52f24b..b92e6bfffaf 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -5,7 +5,7 @@
*
* This code is GPL
*
- * $Id: mtdpart.c,v 1.51 2004/11/16 18:28:59 dwmw2 Exp $
+ * $Id: mtdpart.c,v 1.53 2005/02/08 17:11:13 nico Exp $
*
* 02-21-2002 Thomas Gleixner <gleixner@autronix.de>
* added support for read_oob, write_oob
@@ -116,6 +116,13 @@ static int part_read_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t le
len, retlen, buf);
}
+static int part_get_user_prot_info (struct mtd_info *mtd,
+ struct otp_info *buf, size_t len)
+{
+ struct mtd_part *part = PART(mtd);
+ return part->master->get_user_prot_info (part->master, buf, len);
+}
+
static int part_read_fact_prot_reg (struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf)
{
@@ -124,6 +131,13 @@ static int part_read_fact_prot_reg (struct mtd_info *mtd, loff_t from, size_t le
len, retlen, buf);
}
+static int part_get_fact_prot_info (struct mtd_info *mtd,
+ struct otp_info *buf, size_t len)
+{
+ struct mtd_part *part = PART(mtd);
+ return part->master->get_fact_prot_info (part->master, buf, len);
+}
+
static int part_write (struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf)
{
@@ -182,6 +196,12 @@ static int part_write_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t l
len, retlen, buf);
}
+static int part_lock_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len)
+{
+ struct mtd_part *part = PART(mtd);
+ return part->master->lock_user_prot_reg (part->master, from, len);
+}
+
static int part_writev (struct mtd_info *mtd, const struct kvec *vecs,
unsigned long count, loff_t to, size_t *retlen)
{
@@ -409,6 +429,12 @@ int add_mtd_partitions(struct mtd_info *master,
slave->mtd.read_fact_prot_reg = part_read_fact_prot_reg;
if(master->write_user_prot_reg)
slave->mtd.write_user_prot_reg = part_write_user_prot_reg;
+ if(master->lock_user_prot_reg)
+ slave->mtd.lock_user_prot_reg = part_lock_user_prot_reg;
+ if(master->get_user_prot_info)
+ slave->mtd.get_user_prot_info = part_get_user_prot_info;
+ if(master->get_fact_prot_info)
+ slave->mtd.get_fact_prot_info = part_get_fact_prot_info;
if (master->sync)
slave->mtd.sync = part_sync;
if (!i && master->suspend && master->resume) {
diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c
index 02135c3ac29..fdb5d4ad3d5 100644
--- a/drivers/mtd/nand/diskonchip.c
+++ b/drivers/mtd/nand/diskonchip.c
@@ -16,7 +16,7 @@
*
* Interface to generic NAND code for M-Systems DiskOnChip devices
*
- * $Id: diskonchip.c,v 1.45 2005/01/05 18:05:14 dwmw2 Exp $
+ * $Id: diskonchip.c,v 1.54 2005/04/07 14:22:55 dbrown Exp $
*/
#include <linux/kernel.h>
@@ -35,13 +35,13 @@
#include <linux/mtd/inftl.h>
/* Where to look for the devices? */
-#ifndef CONFIG_MTD_DISKONCHIP_PROBE_ADDRESS
-#define CONFIG_MTD_DISKONCHIP_PROBE_ADDRESS 0
+#ifndef CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS
+#define CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS 0
#endif
static unsigned long __initdata doc_locations[] = {
#if defined (__alpha__) || defined(__i386__) || defined(__x86_64__)
-#ifdef CONFIG_MTD_DISKONCHIP_PROBE_HIGH
+#ifdef CONFIG_MTD_NAND_DISKONCHIP_PROBE_HIGH
0xfffc8000, 0xfffca000, 0xfffcc000, 0xfffce000,
0xfffd0000, 0xfffd2000, 0xfffd4000, 0xfffd6000,
0xfffd8000, 0xfffda000, 0xfffdc000, 0xfffde000,
@@ -81,11 +81,6 @@ struct doc_priv {
struct mtd_info *nextdoc;
};
-/* Max number of eraseblocks to scan (from start of device) for the (I)NFTL
- MediaHeader. The spec says to just keep going, I think, but that's just
- silly. */
-#define MAX_MEDIAHEADER_SCAN 8
-
/* This is the syndrome computed by the HW ecc generator upon reading an empty
page, one with all 0xff for data and stored ecc code. */
static u_char empty_read_syndrome[6] = { 0x26, 0xff, 0x6d, 0x47, 0x73, 0x7a };
@@ -111,10 +106,11 @@ module_param(try_dword, int, 0);
static int no_ecc_failures=0;
module_param(no_ecc_failures, int, 0);
-#ifdef CONFIG_MTD_PARTITIONS
static int no_autopart=0;
module_param(no_autopart, int, 0);
-#endif
+
+static int show_firmware_partition=0;
+module_param(show_firmware_partition, int, 0);
#ifdef MTD_NAND_DISKONCHIP_BBTWRITE
static int inftl_bbt_write=1;
@@ -123,7 +119,7 @@ static int inftl_bbt_write=0;
#endif
module_param(inftl_bbt_write, int, 0);
-static unsigned long doc_config_location = CONFIG_MTD_DISKONCHIP_PROBE_ADDRESS;
+static unsigned long doc_config_location = CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS;
module_param(doc_config_location, ulong, 0);
MODULE_PARM_DESC(doc_config_location, "Physical memory address at which to probe for DiskOnChip");
@@ -410,7 +406,12 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr)
doc200x_hwcontrol(mtd, NAND_CTL_SETALE);
this->write_byte(mtd, 0);
doc200x_hwcontrol(mtd, NAND_CTL_CLRALE);
-
+
+ /* We cant' use dev_ready here, but at least we wait for the
+ * command to complete
+ */
+ udelay(50);
+
ret = this->read_byte(mtd) << 8;
ret |= this->read_byte(mtd);
@@ -429,6 +430,8 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr)
doc2000_write_byte(mtd, 0);
doc200x_hwcontrol(mtd, NAND_CTL_CLRALE);
+ udelay(50);
+
ident.dword = readl(docptr + DoC_2k_CDSN_IO);
if (((ident.byte[0] << 8) | ident.byte[1]) == ret) {
printk(KERN_INFO "DiskOnChip 2000 responds to DWORD access\n");
@@ -1046,11 +1049,21 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_
//u_char mydatabuf[528];
+/* The strange out-of-order .oobfree list below is a (possibly unneeded)
+ * attempt to retain compatibility. It used to read:
+ * .oobfree = { {8, 8} }
+ * Since that leaves two bytes unusable, it was changed. But the following
+ * scheme might affect existing jffs2 installs by moving the cleanmarker:
+ * .oobfree = { {6, 10} }
+ * jffs2 seems to handle the above gracefully, but the current scheme seems
+ * safer. The only problem with it is that any code that parses oobfree must
+ * be able to handle out-of-order segments.
+ */
static struct nand_oobinfo doc200x_oobinfo = {
.useecc = MTD_NANDECC_AUTOPLACE,
.eccbytes = 6,
.eccpos = {0, 1, 2, 3, 4, 5},
- .oobfree = { {8, 8} }
+ .oobfree = { {8, 8}, {6, 2} }
};
/* Find the (I)NFTL Media Header, and optionally also the mirror media header.
@@ -1064,12 +1077,11 @@ static int __init find_media_headers(struct mtd_info *mtd, u_char *buf,
{
struct nand_chip *this = mtd->priv;
struct doc_priv *doc = this->priv;
- unsigned offs, end = (MAX_MEDIAHEADER_SCAN << this->phys_erase_shift);
+ unsigned offs;
int ret;
size_t retlen;
- end = min(end, mtd->size); // paranoia
- for (offs = 0; offs < end; offs += mtd->erasesize) {
+ for (offs = 0; offs < mtd->size; offs += mtd->erasesize) {
ret = mtd->read(mtd, offs, mtd->oobblock, &retlen, buf);
if (retlen != mtd->oobblock) continue;
if (ret) {
@@ -1111,6 +1123,7 @@ static inline int __init nftl_partscan(struct mtd_info *mtd,
u_char *buf;
struct NFTLMediaHeader *mh;
const unsigned psize = 1 << this->page_shift;
+ int numparts = 0;
unsigned blocks, maxblocks;
int offs, numheaders;
@@ -1122,8 +1135,10 @@ static inline int __init nftl_partscan(struct mtd_info *mtd,
if (!(numheaders=find_media_headers(mtd, buf, "ANAND", 1))) goto out;
mh = (struct NFTLMediaHeader *) buf;
-//#ifdef CONFIG_MTD_DEBUG_VERBOSE
-// if (CONFIG_MTD_DEBUG_VERBOSE >= 2)
+ mh->NumEraseUnits = le16_to_cpu(mh->NumEraseUnits);
+ mh->FirstPhysicalEUN = le16_to_cpu(mh->FirstPhysicalEUN);
+ mh->FormattedSize = le32_to_cpu(mh->FormattedSize);
+
printk(KERN_INFO " DataOrgID = %s\n"
" NumEraseUnits = %d\n"
" FirstPhysicalEUN = %d\n"
@@ -1132,7 +1147,6 @@ static inline int __init nftl_partscan(struct mtd_info *mtd,
mh->DataOrgID, mh->NumEraseUnits,
mh->FirstPhysicalEUN, mh->FormattedSize,
mh->UnitSizeFactor);
-//#endif
blocks = mtd->size >> this->phys_erase_shift;
maxblocks = min(32768U, mtd->erasesize - psize);
@@ -1175,23 +1189,28 @@ static inline int __init nftl_partscan(struct mtd_info *mtd,
offs <<= this->page_shift;
offs += mtd->erasesize;
- //parts[0].name = " DiskOnChip Boot / Media Header partition";
- //parts[0].offset = 0;
- //parts[0].size = offs;
+ if (show_firmware_partition == 1) {
+ parts[0].name = " DiskOnChip Firmware / Media Header partition";
+ parts[0].offset = 0;
+ parts[0].size = offs;
+ numparts = 1;
+ }
- parts[0].name = " DiskOnChip BDTL partition";
- parts[0].offset = offs;
- parts[0].size = (mh->NumEraseUnits - numheaders) << this->bbt_erase_shift;
+ parts[numparts].name = " DiskOnChip BDTL partition";
+ parts[numparts].offset = offs;
+ parts[numparts].size = (mh->NumEraseUnits - numheaders) << this->bbt_erase_shift;
+
+ offs += parts[numparts].size;
+ numparts++;
- offs += parts[0].size;
if (offs < mtd->size) {
- parts[1].name = " DiskOnChip Remainder partition";
- parts[1].offset = offs;
- parts[1].size = mtd->size - offs;
- ret = 2;
- goto out;
+ parts[numparts].name = " DiskOnChip Remainder partition";
+ parts[numparts].offset = offs;
+ parts[numparts].size = mtd->size - offs;
+ numparts++;
}
- ret = 1;
+
+ ret = numparts;
out:
kfree(buf);
return ret;
@@ -1233,8 +1252,6 @@ static inline int __init inftl_partscan(struct mtd_info *mtd,
mh->FormatFlags = le32_to_cpu(mh->FormatFlags);
mh->PercentUsed = le32_to_cpu(mh->PercentUsed);
-//#ifdef CONFIG_MTD_DEBUG_VERBOSE
-// if (CONFIG_MTD_DEBUG_VERBOSE >= 2)
printk(KERN_INFO " bootRecordID = %s\n"
" NoOfBootImageBlocks = %d\n"
" NoOfBinaryPartitions = %d\n"
@@ -1252,7 +1269,6 @@ static inline int __init inftl_partscan(struct mtd_info *mtd,
((unsigned char *) &mh->OsakVersion)[2] & 0xf,
((unsigned char *) &mh->OsakVersion)[3] & 0xf,
mh->PercentUsed);
-//#endif
vshift = this->phys_erase_shift + mh->BlockMultiplierBits;
@@ -1278,8 +1294,6 @@ static inline int __init inftl_partscan(struct mtd_info *mtd,
ip->spareUnits = le32_to_cpu(ip->spareUnits);
ip->Reserved0 = le32_to_cpu(ip->Reserved0);
-//#ifdef CONFIG_MTD_DEBUG_VERBOSE
-// if (CONFIG_MTD_DEBUG_VERBOSE >= 2)
printk(KERN_INFO " PARTITION[%d] ->\n"
" virtualUnits = %d\n"
" firstUnit = %d\n"
@@ -1289,16 +1303,14 @@ static inline int __init inftl_partscan(struct mtd_info *mtd,
i, ip->virtualUnits, ip->firstUnit,
ip->lastUnit, ip->flags,
ip->spareUnits);
-//#endif
-/*
- if ((i == 0) && (ip->firstUnit > 0)) {
+ if ((show_firmware_partition == 1) &&
+ (i == 0) && (ip->firstUnit > 0)) {
parts[0].name = " DiskOnChip IPL / Media Header partition";
parts[0].offset = 0;
parts[0].size = mtd->erasesize * ip->firstUnit;
numparts = 1;
}
-*/
if (ip->flags & INFTL_BINARY)
parts[numparts].name = " DiskOnChip BDK partition";
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 44d5b128911..f1db0bf9306 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -28,6 +28,24 @@
* among multiple independend devices. Suggestions and initial patch
* from Ben Dooks <ben-mtd@fluff.org>
*
+ * 12-05-2004 dmarlin: add workaround for Renesas AG-AND chips "disturb" issue.
+ * Basically, any block not rewritten may lose data when surrounding blocks
+ * are rewritten many times. JFFS2 ensures this doesn't happen for blocks
+ * it uses, but the Bad Block Table(s) may not be rewritten. To ensure they
+ * do not lose data, force them to be rewritten when some of the surrounding
+ * blocks are erased. Rather than tracking a specific nearby block (which
+ * could itself go bad), use a page address 'mask' to select several blocks
+ * in the same area, and rewrite the BBT when any of them are erased.
+ *
+ * 01-03-2005 dmarlin: added support for the device recovery command sequence for Renesas
+ * AG-AND chips. 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.
+ *
+ * 01-20-2005 dmarlin: added support for optional hardware specific callback routine to
+ * perform extra error status checks on erase and write failures. This required
+ * adding a wrapper function for nand_read_ecc.
+ *
* Credits:
* David Woodhouse for adding multichip support
*
@@ -41,7 +59,7 @@
* The AG-AND chips have nice features for speed improvement,
* which are not supported yet. Read / program 4 pages in one go.
*
- * $Id: nand_base.c,v 1.126 2004/12/13 11:22:25 lavinen Exp $
+ * $Id: nand_base.c,v 1.143 2005/05/19 16:10:22 gleixner Exp $
*
* 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
@@ -443,7 +461,8 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
/* Get block number */
block = ((int) ofs) >> this->bbt_erase_shift;
- this->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);
+ if (this->bbt)
+ this->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);
/* Do we have a flash based bad block table ? */
if (this->options & NAND_USE_FLASH_BBT)
@@ -466,7 +485,7 @@ static int nand_check_wp (struct mtd_info *mtd)
struct nand_chip *this = mtd->priv;
/* Check the WP bit */
this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1);
- return (this->read_byte(mtd) & 0x80) ? 0 : 1;
+ return (this->read_byte(mtd) & NAND_STATUS_WP) ? 0 : 1;
}
/**
@@ -490,6 +509,22 @@ static int nand_block_checkbad (struct mtd_info *mtd, loff_t ofs, int getchip, i
return nand_isbad_bbt (mtd, ofs, allowbbt);
}
+/*
+ * Wait for the ready pin, after a command
+ * The timeout is catched later.
+ */
+static void nand_wait_ready(struct mtd_info *mtd)
+{
+ struct nand_chip *this = mtd->priv;
+ unsigned long timeo = jiffies + 2;
+
+ /* wait until command is processed or timeout occures */
+ do {
+ if (this->dev_ready(mtd))
+ return;
+ } while (time_before(jiffies, timeo));
+}
+
/**
* nand_command - [DEFAULT] Send command to NAND device
* @mtd: MTD device structure
@@ -571,7 +606,7 @@ static void nand_command (struct mtd_info *mtd, unsigned command, int column, in
this->hwcontrol(mtd, NAND_CTL_SETCLE);
this->write_byte(mtd, NAND_CMD_STATUS);
this->hwcontrol(mtd, NAND_CTL_CLRCLE);
- while ( !(this->read_byte(mtd) & 0x40));
+ while ( !(this->read_byte(mtd) & NAND_STATUS_READY));
return;
/* This applies to read commands */
@@ -585,12 +620,11 @@ static void nand_command (struct mtd_info *mtd, unsigned command, int column, in
return;
}
}
-
/* Apply this short delay always to ensure that we do wait tWB in
* any case on any machine. */
ndelay (100);
- /* wait until command is processed */
- while (!this->dev_ready(mtd));
+
+ nand_wait_ready(mtd);
}
/**
@@ -619,7 +653,7 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column,
/* Begin command latch cycle */
this->hwcontrol(mtd, NAND_CTL_SETCLE);
/* Write out the command to the device. */
- this->write_byte(mtd, command);
+ this->write_byte(mtd, (command & 0xff));
/* End command latch cycle */
this->hwcontrol(mtd, NAND_CTL_CLRCLE);
@@ -647,8 +681,8 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column,
/*
* program and erase have their own busy handlers
- * status and sequential in needs no delay
- */
+ * status, sequential in, and deplete1 need no delay
+ */
switch (command) {
case NAND_CMD_CACHEDPROG:
@@ -657,8 +691,19 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column,
case NAND_CMD_ERASE2:
case NAND_CMD_SEQIN:
case NAND_CMD_STATUS:
+ case NAND_CMD_DEPLETE1:
return;
+ /*
+ * read error status commands require only a short delay
+ */
+ 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(this->chip_delay);
+ return;
case NAND_CMD_RESET:
if (this->dev_ready)
@@ -667,7 +712,7 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column,
this->hwcontrol(mtd, NAND_CTL_SETCLE);
this->write_byte(mtd, NAND_CMD_STATUS);
this->hwcontrol(mtd, NAND_CTL_CLRCLE);
- while ( !(this->read_byte(mtd) & 0x40));
+ while ( !(this->read_byte(mtd) & NAND_STATUS_READY));
return;
case NAND_CMD_READ0:
@@ -690,12 +735,12 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column,
return;
}
}
-
+
/* Apply this short delay always to ensure that we do wait tWB in
* any case on any machine. */
ndelay (100);
- /* wait until command is processed */
- while (!this->dev_ready(mtd));
+
+ nand_wait_ready(mtd);
}
/**
@@ -785,7 +830,7 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state)
if (this->read_byte(mtd) & NAND_STATUS_READY)
break;
}
- yield ();
+ cond_resched();
}
status = (int) this->read_byte(mtd);
return status;
@@ -871,8 +916,14 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa
if (!cached) {
/* call wait ready function */
status = this->waitfunc (mtd, this, FL_WRITING);
+
+ /* See if operation failed and additional status checks are available */
+ if ((status & NAND_STATUS_FAIL) && (this->errstat)) {
+ status = this->errstat(mtd, this, FL_WRITING, status, page);
+ }
+
/* See if device thinks it succeeded */
- if (status & 0x01) {
+ if (status & NAND_STATUS_FAIL) {
DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write, page 0x%08x, ", __FUNCTION__, page);
return -EIO;
}
@@ -975,7 +1026,7 @@ static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int
if (!this->dev_ready)
udelay (this->chip_delay);
else
- while (!this->dev_ready(mtd));
+ nand_wait_ready(mtd);
/* All done, return happy */
if (!numpages)
@@ -997,23 +1048,24 @@ out:
#endif
/**
- * nand_read - [MTD Interface] MTD compability function for nand_read_ecc
+ * nand_read - [MTD Interface] MTD compability function for nand_do_read_ecc
* @mtd: MTD device structure
* @from: offset to read from
* @len: number of bytes to read
* @retlen: pointer to variable to store the number of read bytes
* @buf: the databuffer to put data
*
- * This function simply calls nand_read_ecc with oob buffer and oobsel = NULL
-*/
+ * This function simply calls nand_do_read_ecc with oob buffer and oobsel = NULL
+ * and flags = 0xff
+ */
static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf)
{
- return nand_read_ecc (mtd, from, len, retlen, buf, NULL, NULL);
-}
+ return nand_do_read_ecc (mtd, from, len, retlen, buf, NULL, &mtd->oobinfo, 0xff);
+}
/**
- * nand_read_ecc - [MTD Interface] Read data with ECC
+ * nand_read_ecc - [MTD Interface] MTD compability function for nand_do_read_ecc
* @mtd: MTD device structure
* @from: offset to read from
* @len: number of bytes to read
@@ -1022,11 +1074,39 @@ static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * re
* @oob_buf: filesystem supplied oob data buffer
* @oobsel: oob selection structure
*
- * NAND read with ECC
+ * This function simply calls nand_do_read_ecc with flags = 0xff
*/
static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
size_t * retlen, u_char * buf, u_char * oob_buf, struct nand_oobinfo *oobsel)
{
+ /* use userspace supplied oobinfo, if zero */
+ if (oobsel == NULL)
+ oobsel = &mtd->oobinfo;
+ return nand_do_read_ecc(mtd, from, len, retlen, buf, oob_buf, oobsel, 0xff);
+}
+
+
+/**
+ * nand_do_read_ecc - [MTD Interface] Read data with ECC
+ * @mtd: MTD device structure
+ * @from: offset to read from
+ * @len: number of bytes to read
+ * @retlen: pointer to variable to store the number of read bytes
+ * @buf: the databuffer to put data
+ * @oob_buf: filesystem supplied oob data buffer (can be NULL)
+ * @oobsel: oob selection structure
+ * @flags: flag to indicate if nand_get_device/nand_release_device should be preformed
+ * and how many corrected error bits are acceptable:
+ * bits 0..7 - number of tolerable errors
+ * bit 8 - 0 == do not get/release chip, 1 == get/release chip
+ *
+ * NAND read with ECC
+ */
+int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
+ size_t * retlen, u_char * buf, u_char * oob_buf,
+ struct nand_oobinfo *oobsel, int flags)
+{
+
int i, j, col, realpage, page, end, ecc, chipnr, sndcmd = 1;
int read = 0, oob = 0, ecc_status = 0, ecc_failed = 0;
struct nand_chip *this = mtd->priv;
@@ -1051,12 +1131,9 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
}
/* Grab the lock and see if the device is available */
- nand_get_device (this, mtd ,FL_READING);
+ if (flags & NAND_GET_DEVICE)
+ nand_get_device (this, mtd, FL_READING);
- /* use userspace supplied oobinfo, if zero */
- if (oobsel == NULL)
- oobsel = &mtd->oobinfo;
-
/* Autoplace of oob data ? Use the default placement scheme */
if (oobsel->useecc == MTD_NANDECC_AUTOPLACE)
oobsel = this->autooob;
@@ -1118,7 +1195,8 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
}
/* get oob area, if we have no oob buffer from fs-driver */
- if (!oob_buf || oobsel->useecc == MTD_NANDECC_AUTOPLACE)
+ if (!oob_buf || oobsel->useecc == MTD_NANDECC_AUTOPLACE ||
+ oobsel->useecc == MTD_NANDECC_AUTOPL_USR)
oob_data = &this->data_buf[end];
eccsteps = this->eccsteps;
@@ -1155,7 +1233,8 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
/* We calc error correction directly, it checks the hw
* generator for an error, reads back the syndrome and
* does the error correction on the fly */
- if (this->correct_data(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]) == -1) {
+ ecc_status = this->correct_data(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]);
+ if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) {
DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: "
"Failed ECC read, page 0x%08x on chip %d\n", page, chipnr);
ecc_failed++;
@@ -1194,7 +1273,7 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
p[i] = ecc_status;
}
- if (ecc_status == -1) {
+ if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) {
DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page);
ecc_failed++;
}
@@ -1206,14 +1285,14 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
/* without autoplace. Legacy mode used by YAFFS1 */
switch(oobsel->useecc) {
case MTD_NANDECC_AUTOPLACE:
+ case MTD_NANDECC_AUTOPL_USR:
/* Walk through the autoplace chunks */
- for (i = 0, j = 0; j < mtd->oobavail; i++) {
+ for (i = 0; oobsel->oobfree[i][1]; i++) {
int from = oobsel->oobfree[i][0];
int num = oobsel->oobfree[i][1];
memcpy(&oob_buf[oob], &oob_data[from], num);
- j+= num;
+ oob += num;
}
- oob += mtd->oobavail;
break;
case MTD_NANDECC_PLACE:
/* YAFFS1 legacy mode */
@@ -1239,7 +1318,7 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
if (!this->dev_ready)
udelay (this->chip_delay);
else
- while (!this->dev_ready(mtd));
+ nand_wait_ready(mtd);
if (read == len)
break;
@@ -1264,7 +1343,8 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
}
/* Deselect and wake up anyone waiting on the device */
- nand_release_device(mtd);
+ if (flags & NAND_GET_DEVICE)
+ nand_release_device(mtd);
/*
* Return success, if no ECC failures, else -EBADMSG
@@ -1337,7 +1417,7 @@ static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t
if (!this->dev_ready)
udelay (this->chip_delay);
else
- while (!this->dev_ready(mtd));
+ nand_wait_ready(mtd);
/* Read more ? */
if (i < len) {
@@ -1417,7 +1497,7 @@ int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len,
if (!this->dev_ready)
udelay (this->chip_delay);
else
- while (!this->dev_ready(mtd));
+ nand_wait_ready(mtd);
/* Check, if the chip supports auto page increment */
if (!NAND_CANAUTOINCR(this) || !(page & blockcheck))
@@ -1567,6 +1647,8 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
oobsel = this->autooob;
autoplace = 1;
}
+ if (oobsel->useecc == MTD_NANDECC_AUTOPL_USR)
+ autoplace = 1;
/* Setup variables and oob buffer */
totalpages = len >> this->page_shift;
@@ -1733,7 +1815,7 @@ static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t *
status = this->waitfunc (mtd, this, FL_WRITING);
/* See if device thinks it succeeded */
- if (status & 0x01) {
+ if (status & NAND_STATUS_FAIL) {
DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write, page 0x%08x\n", page);
ret = -EIO;
goto out;
@@ -1841,6 +1923,8 @@ static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsig
oobsel = this->autooob;
autoplace = 1;
}
+ if (oobsel->useecc == MTD_NANDECC_AUTOPL_USR)
+ autoplace = 1;
/* Setup start page */
page = (int) (to >> this->page_shift);
@@ -1987,6 +2071,7 @@ 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_intern - [NAND Interface] erase block(s)
* @mtd: MTD device structure
@@ -1999,6 +2084,10 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb
{
int page, len, status, pages_per_block, ret, chipnr;
struct nand_chip *this = mtd->priv;
+ int rewrite_bbt[NAND_MAX_CHIPS]={0}; /* flags to indicate the page, if bbt needs to be rewritten. */
+ unsigned int bbt_masked_page; /* bbt mask to compare to page being erased. */
+ /* It is used to see if the current page is in the same */
+ /* 256 block group and the same bank as the bbt. */
DEBUG (MTD_DEBUG_LEVEL3,
"nand_erase: start = 0x%08x, len = %i\n", (unsigned int) instr->addr, (unsigned int) instr->len);
@@ -2044,6 +2133,13 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb
goto erase_exit;
}
+ /* if BBT requires refresh, set the BBT page mask to see if the BBT should be rewritten */
+ if (this->options & BBT_AUTO_REFRESH) {
+ bbt_masked_page = this->bbt_td->pages[chipnr] & BBT_PAGE_MASK;
+ } else {
+ bbt_masked_page = 0xffffffff; /* should not match anything */
+ }
+
/* Loop through the pages */
len = instr->len;
@@ -2066,13 +2162,26 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb
status = this->waitfunc (mtd, this, FL_ERASING);
+ /* See if operation failed and additional status checks are available */
+ if ((status & NAND_STATUS_FAIL) && (this->errstat)) {
+ status = this->errstat(mtd, this, FL_ERASING, status, page);
+ }
+
/* See if block erase succeeded */
- if (status & 0x01) {
+ if (status & NAND_STATUS_FAIL) {
DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: " "Failed erase, page 0x%08x\n", page);
instr->state = MTD_ERASE_FAILED;
instr->fail_addr = (page << this->page_shift);
goto erase_exit;
}
+
+ /* if BBT requires refresh, set the BBT rewrite flag to the page being erased */
+ if (this->options & BBT_AUTO_REFRESH) {
+ if (((page & BBT_PAGE_MASK) == bbt_masked_page) &&
+ (page != this->bbt_td->pages[chipnr])) {
+ rewrite_bbt[chipnr] = (page << this->page_shift);
+ }
+ }
/* Increment page address and decrement length */
len -= (1 << this->phys_erase_shift);
@@ -2083,6 +2192,13 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb
chipnr++;
this->select_chip(mtd, -1);
this->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 ((this->options & BBT_AUTO_REFRESH) && (this->bbt_td->options & NAND_BBT_PERCHIP)) {
+ bbt_masked_page = this->bbt_td->pages[chipnr] & BBT_PAGE_MASK;
+ }
+
}
}
instr->state = MTD_ERASE_DONE;
@@ -2097,6 +2213,18 @@ erase_exit:
/* Deselect and wake up anyone waiting on the device */
nand_release_device(mtd);
+ /* if BBT requires refresh and erase was successful, rewrite any selected bad block tables */
+ if ((this->options & BBT_AUTO_REFRESH) && (!ret)) {
+ for (chipnr = 0; chipnr < this->numchips; chipnr++) {
+ if (rewrite_bbt[chipnr]) {
+ /* update the BBT for chip */
+ DEBUG (MTD_DEBUG_LEVEL0, "nand_erase_nand: nand_update_bbt (%d:0x%0x 0x%0x)\n",
+ chipnr, rewrite_bbt[chipnr], this->bbt_td->pages[chipnr]);
+ nand_update_bbt (mtd, rewrite_bbt[chipnr]);
+ }
+ }
+ }
+
/* Return more or less happy */
return ret;
}
@@ -2168,7 +2296,7 @@ static int nand_block_markbad (struct mtd_info *mtd, loff_t ofs)
*/
int nand_scan (struct mtd_info *mtd, int maxchips)
{
- int i, j, nand_maf_id, nand_dev_id, busw;
+ int i, nand_maf_id, nand_dev_id, busw, maf_id;
struct nand_chip *this = mtd->priv;
/* Get buswidth to select the correct functions*/
@@ -2256,12 +2384,18 @@ int nand_scan (struct mtd_info *mtd, int maxchips)
busw = nand_flash_ids[i].options & NAND_BUSWIDTH_16;
}
+ /* Try to identify manufacturer */
+ for (maf_id = 0; nand_manuf_ids[maf_id].id != 0x0; maf_id++) {
+ if (nand_manuf_ids[maf_id].id == nand_maf_id)
+ break;
+ }
+
/* Check, if buswidth is correct. Hardware drivers should set
* this correct ! */
if (busw != (this->options & NAND_BUSWIDTH_16)) {
printk (KERN_INFO "NAND device: Manufacturer ID:"
" 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id,
- nand_manuf_ids[i].name , mtd->name);
+ nand_manuf_ids[maf_id].name , mtd->name);
printk (KERN_WARNING
"NAND bus width %d instead %d bit\n",
(this->options & NAND_BUSWIDTH_16) ? 16 : 8,
@@ -2300,14 +2434,9 @@ int nand_scan (struct mtd_info *mtd, int maxchips)
if (mtd->oobblock > 512 && this->cmdfunc == nand_command)
this->cmdfunc = nand_command_lp;
- /* Try to identify manufacturer */
- for (j = 0; nand_manuf_ids[j].id != 0x0; j++) {
- if (nand_manuf_ids[j].id == nand_maf_id)
- break;
- }
printk (KERN_INFO "NAND device: Manufacturer ID:"
" 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id,
- nand_manuf_ids[j].name , nand_flash_ids[i].name);
+ nand_manuf_ids[maf_id].name , nand_flash_ids[i].name);
break;
}
@@ -2388,12 +2517,9 @@ int nand_scan (struct mtd_info *mtd, int maxchips)
/* The number of bytes available for the filesystem to place fs dependend
* oob data */
- if (this->options & NAND_BUSWIDTH_16) {
- mtd->oobavail = mtd->oobsize - (this->autooob->eccbytes + 2);
- if (this->autooob->eccbytes & 0x01)
- mtd->oobavail--;
- } else
- mtd->oobavail = mtd->oobsize - (this->autooob->eccbytes + 1);
+ mtd->oobavail = 0;
+ for (i = 0; this->autooob->oobfree[i][1]; i++)
+ mtd->oobavail += this->autooob->oobfree[i][1];
/*
* check ECC mode, default to software
@@ -2524,6 +2650,10 @@ int nand_scan (struct mtd_info *mtd, int maxchips)
memcpy(&mtd->oobinfo, this->autooob, sizeof(mtd->oobinfo));
mtd->owner = THIS_MODULE;
+
+ /* Check, if we should skip the bad block table scan */
+ if (this->options & NAND_SKIP_BBTSCAN)
+ return 0;
/* Build bad block table */
return this->scan_bbt (mtd);
diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c
index 9a1949751c1..c85c69dec54 100644
--- a/drivers/mtd/nand/nand_bbt.c
+++ b/drivers/mtd/nand/nand_bbt.c
@@ -6,7 +6,7 @@
*
* Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de)
*
- * $Id: nand_bbt.c,v 1.28 2004/11/13 10:19:09 gleixner Exp $
+ * $Id: nand_bbt.c,v 1.31 2005/02/16 17:09:36 dedekind Exp $
*
* 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
@@ -77,17 +77,17 @@
*/
static int check_pattern (uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td)
{
- int i, end;
+ int i, end = 0;
uint8_t *p = buf;
- end = paglen + td->offs;
if (td->options & NAND_BBT_SCANEMPTY) {
+ end = paglen + td->offs;
for (i = 0; i < end; i++) {
if (p[i] != 0xff)
return -1;
}
+ p += end;
}
- p += end;
/* Compare the pattern */
for (i = 0; i < td->len; i++) {
@@ -95,9 +95,9 @@ static int check_pattern (uint8_t *buf, int len, int paglen, struct nand_bbt_des
return -1;
}
- p += td->len;
- end += td->len;
if (td->options & NAND_BBT_SCANEMPTY) {
+ p += td->len;
+ end += td->len;
for (i = end; i < len; i++) {
if (*p++ != 0xff)
return -1;
@@ -252,7 +252,7 @@ static int read_abs_bbts (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_de
* Create a bad block table by scanning the device
* for the given good/bad block identify pattern
*/
-static void create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd, int chip)
+static int create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd, int chip)
{
struct nand_chip *this = mtd->priv;
int i, j, numblocks, len, scanlen;
@@ -270,9 +270,17 @@ static void create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
else
len = 1;
}
- scanlen = mtd->oobblock + mtd->oobsize;
- readlen = len * mtd->oobblock;
- ooblen = len * mtd->oobsize;
+
+ if (!(bd->options & NAND_BBT_SCANEMPTY)) {
+ /* We need only read few bytes from the OOB area */
+ scanlen = ooblen = 0;
+ readlen = bd->len;
+ } else {
+ /* Full page content should be read */
+ scanlen = mtd->oobblock + mtd->oobsize;
+ readlen = len * mtd->oobblock;
+ ooblen = len * mtd->oobsize;
+ }
if (chip == -1) {
/* Note that numblocks is 2 * (real numblocks) here, see i+=2 below as it
@@ -284,7 +292,7 @@ static void create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
if (chip >= this->numchips) {
printk (KERN_WARNING "create_bbt(): chipnr (%d) > available chips (%d)\n",
chip + 1, this->numchips);
- return;
+ return -EINVAL;
}
numblocks = this->chipsize >> (this->bbt_erase_shift - 1);
startblock = chip * numblocks;
@@ -293,8 +301,22 @@ static void create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
}
for (i = startblock; i < numblocks;) {
- nand_read_raw (mtd, buf, from, readlen, ooblen);
+ int ret;
+
+ if (bd->options & NAND_BBT_SCANEMPTY)
+ if ((ret = nand_read_raw (mtd, buf, from, readlen, ooblen)))
+ return ret;
+
for (j = 0; j < len; j++) {
+ if (!(bd->options & NAND_BBT_SCANEMPTY)) {
+ size_t retlen;
+
+ /* No need to read pages fully, just read required OOB bytes */
+ ret = mtd->read_oob(mtd, from + j * mtd->oobblock + bd->offs,
+ readlen, &retlen, &buf[0]);
+ if (ret)
+ return ret;
+ }
if (check_pattern (&buf[j * scanlen], scanlen, mtd->oobblock, bd)) {
this->bbt[i >> 3] |= 0x03 << (i & 0x6);
printk (KERN_WARNING "Bad eraseblock %d at 0x%08x\n",
@@ -305,6 +327,8 @@ static void create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
i += 2;
from += (1 << this->bbt_erase_shift);
}
+
+ return 0;
}
/**
@@ -589,14 +613,12 @@ write:
* The function creates a memory based bbt by scanning the device
* for manufacturer / software marked good / bad blocks
*/
-static int nand_memory_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd)
+static inline int nand_memory_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd)
{
struct nand_chip *this = mtd->priv;
- /* Ensure that we only scan for the pattern and nothing else */
- bd->options = 0;
- create_bbt (mtd, this->data_buf, bd, -1);
- return 0;
+ bd->options &= ~NAND_BBT_SCANEMPTY;
+ return create_bbt (mtd, this->data_buf, bd, -1);
}
/**
@@ -808,8 +830,14 @@ int nand_scan_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd)
/* If no primary table decriptor is given, scan the device
* to build a memory based bad block table
*/
- if (!td)
- return nand_memory_bbt(mtd, bd);
+ if (!td) {
+ if ((res = nand_memory_bbt(mtd, bd))) {
+ printk (KERN_ERR "nand_bbt: Can't scan flash and build the RAM-based BBT\n");
+ kfree (this->bbt);
+ this->bbt = NULL;
+ }
+ return res;
+ }
/* Allocate a temporary buffer for one eraseblock incl. oob */
len = (1 << this->bbt_erase_shift);
@@ -904,14 +932,11 @@ out:
}
/* Define some generic bad / good block scan pattern which are used
- * while scanning a device for factory marked good / bad blocks
- *
- * The memory based patterns just
- */
+ * while scanning a device for factory marked good / bad blocks. */
static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
static struct nand_bbt_descr smallpage_memorybased = {
- .options = 0,
+ .options = NAND_BBT_SCAN2NDPAGE,
.offs = 5,
.len = 1,
.pattern = scan_ff_pattern
@@ -1042,7 +1067,7 @@ int nand_isbad_bbt (struct mtd_info *mtd, loff_t offs, int allowbbt)
res = (this->bbt[block >> 3] >> (block & 0x06)) & 0x03;
DEBUG (MTD_DEBUG_LEVEL2, "nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n",
- (unsigned int)offs, res, block >> 1);
+ (unsigned int)offs, block >> 1, res);
switch ((int)res) {
case 0x00: return 0;
diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c
index 2d8c4321275..79945e6ce2b 100644
--- a/drivers/mtd/nand/nand_ids.c
+++ b/drivers/mtd/nand/nand_ids.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2002 Thomas Gleixner (tglx@linutronix.de)
*
- * $Id: nand_ids.c,v 1.10 2004/05/26 13:40:12 gleixner Exp $
+ * $Id: nand_ids.c,v 1.12 2005/02/16 09:33:27 gleixner Exp $
*
* 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
@@ -62,8 +62,6 @@ struct nand_flash_dev nand_flash_ids[] = {
{"NAND 256MiB 3,3V 8-bit", 0x71, 512, 256, 0x4000, 0},
- {"NAND 512MiB 3,3V 8-bit", 0xDC, 512, 512, 0x4000, 0},
-
/* These are the new chips with large page size. The pagesize
* and the erasesize is determined from the extended id bytes
*/
@@ -103,7 +101,7 @@ struct nand_flash_dev nand_flash_ids[] = {
* 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_NO_AUTOINCR | NAND_4PAGE_ARRAY},
+ {"AND 128MiB 3,3V 8-bit", 0x01, 2048, 128, 0x4000, NAND_IS_AND | NAND_NO_AUTOINCR | NAND_4PAGE_ARRAY | BBT_AUTO_REFRESH},
{NULL,}
};
diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index 13feefd7d8c..754b6ed7ce1 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -22,7 +22,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
*
- * $Id: nandsim.c,v 1.7 2004/12/06 11:53:06 dedekind Exp $
+ * $Id: nandsim.c,v 1.8 2005/03/19 15:33:56 dedekind Exp $
*/
#include <linux/config.h>
@@ -1484,33 +1484,6 @@ ns_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
}
/*
- * Having only NAND chip IDs we call nand_scan which detects NAND flash
- * parameters and then calls scan_bbt in order to scan/find/build the
- * NAND flash bad block table. But since at that moment the NAND flash
- * image isn't allocated in the simulator, errors arise. To avoid this
- * we redefine the scan_bbt callback and initialize the nandsim structure
- * before the flash media scanning.
- */
-int ns_scan_bbt(struct mtd_info *mtd)
-{
- struct nand_chip *chip = (struct nand_chip *)mtd->priv;
- struct nandsim *ns = (struct nandsim *)(chip->priv);
- int retval;
-
- if (!NS_IS_INITIALIZED(ns))
- if ((retval = init_nandsim(mtd)) != 0) {
- NS_ERR("scan_bbt: can't initialize the nandsim structure\n");
- return retval;
- }
- if ((retval = nand_default_bbt(mtd)) != 0) {
- free_nandsim(ns);
- return retval;
- }
-
- return 0;
-}
-
-/*
* Module initialization function
*/
int __init ns_init_module(void)
@@ -1544,7 +1517,6 @@ int __init ns_init_module(void)
chip->hwcontrol = ns_hwcontrol;
chip->read_byte = ns_nand_read_byte;
chip->dev_ready = ns_device_ready;
- chip->scan_bbt = ns_scan_bbt;
chip->write_byte = ns_nand_write_byte;
chip->write_buf = ns_nand_write_buf;
chip->read_buf = ns_nand_read_buf;
@@ -1552,6 +1524,7 @@ int __init ns_init_module(void)
chip->write_word = ns_nand_write_word;
chip->read_word = ns_nand_read_word;
chip->eccmode = NAND_ECC_SOFT;
+ chip->options |= NAND_SKIP_BBTSCAN;
/*
* Perform minimum nandsim structure initialization to handle
@@ -1580,6 +1553,16 @@ int __init ns_init_module(void)
goto error;
}
+ if ((retval = init_nandsim(nsmtd)) != 0) {
+ NS_ERR("scan_bbt: can't initialize the nandsim structure\n");
+ goto error;
+ }
+
+ if ((retval = nand_default_bbt(nsmtd)) != 0) {
+ free_nandsim(nand);
+ goto error;
+ }
+
/* Register NAND as one big partition */
add_mtd_partitions(nsmtd, &nand->part, 1);
diff --git a/drivers/mtd/nand/rtc_from4.c b/drivers/mtd/nand/rtc_from4.c
index 02305a2adca..031051cbde7 100644
--- a/drivers/mtd/nand/rtc_from4.c
+++ b/drivers/mtd/nand/rtc_from4.c
@@ -6,7 +6,7 @@
* Derived from drivers/mtd/nand/spia.c
* Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
*
- * $Id: rtc_from4.c,v 1.7 2004/11/04 12:53:10 gleixner Exp $
+ * $Id: rtc_from4.c,v 1.9 2005/01/24 20:40:11 dmarlin Exp $
*
* 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
@@ -83,13 +83,18 @@ static struct mtd_info *rtc_from4_mtd = NULL;
#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 = P2SEGADDR(RTC_FROM4_FIO_BASE);
+static void __iomem *rtc_from4_fio_base = (void *)P2SEGADDR(RTC_FROM4_FIO_BASE);
const static struct mtd_partition partition_info[] = {
{
@@ -267,7 +272,6 @@ static void rtc_from4_nand_select_chip(struct mtd_info *mtd, int chip)
}
-
/*
* rtc_from4_nand_device_ready - hardware specific ready/busy check
* @mtd: MTD device structure
@@ -286,6 +290,40 @@ static int rtc_from4_nand_device_ready(struct mtd_info *mtd)
}
+
+/*
+ * 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
@@ -329,6 +367,7 @@ static void rtc_from4_enable_hwecc(struct mtd_info *mtd, int mode)
}
+
/*
* rtc_from4_calculate_ecc - hardware specific code to read ECC code
* @mtd: MTD device structure
@@ -356,6 +395,7 @@ static void rtc_from4_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_c
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
@@ -365,16 +405,14 @@ static void rtc_from4_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_c
*
* 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
+ * and hopefully correct the error.
*
- * For now I use the code, which we read from the FLASH to use the RS lib,
- * as the syndrom conversion has a unresolved issue.
*/
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], tmp;
+ uint16_t par[6], syn[6];
uint8_t ecc[8];
volatile unsigned short *rs_ecc;
@@ -416,15 +454,86 @@ static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_cha
}
/* Let the library code do its magic.*/
- res = decode_rs8(rs_decoder, buf, par, 512, syn, 0, NULL, 0xff, NULL);
+ res = decode_rs8(rs_decoder, (uint8_t *)buf, par, 512, syn, 0, NULL, 0xff, NULL);
if (res > 0) {
DEBUG (MTD_DEBUG_LEVEL0, "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)) {
+ 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);
+ if (!(rtn & ERR_STAT_ECC_AVAILABLE)) {
+ er_stat |= 1<<(i+1); /* err_ecc_not_avail */
+ }
+ }
+ }
+ } else if (state == FL_WRITING) {
+ /* 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)) {
+ er_stat |= 1<<1; /* err_ecc_not_avail */
+ } else {
+ len = mtd->oobblock;
+ buf = kmalloc (len, GFP_KERNEL);
+ if (!buf) {
+ printk (KERN_ERR "rtc_from4_errstat: Out of memory!\n");
+ er_stat = 1; /* if we can't check, assume failed */
+ } else {
+ /* recovery read */
+ /* page read */
+ rtn = nand_do_read_ecc (mtd, page, len, &retlen, buf, NULL, this->autooob, 1);
+ if (rtn) { /* if read failed or > 1-bit error corrected */
+ er_stat |= 1<<1; /* ECC read failed */
+ }
+ kfree(buf);
+ }
+ }
+ }
+
+ 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
*/
@@ -432,6 +541,7 @@ int __init rtc_from4_init (void)
{
struct nand_chip *this;
unsigned short bcr1, bcr2, wcr2;
+ int i;
/* Allocate memory for MTD device structure and private data */
rtc_from4_mtd = kmalloc(sizeof(struct mtd_info) + sizeof (struct nand_chip),
@@ -483,6 +593,8 @@ int __init rtc_from4_init (void)
this->eccmode = NAND_ECC_HW8_512;
this->options |= NAND_HWECC_SYNDROME;
+ /* 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->autooob = &rtc_from4_nand_oobinfo;
this->enable_hwecc = rtc_from4_enable_hwecc;
@@ -504,6 +616,18 @@ int __init rtc_from4_init (void)
return -ENXIO;
}
+ /* 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 */
add_mtd_partitions(rtc_from4_mtd, partition_info, NUM_PARTITIONS);
diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c
index d05e9b97947..64b1d95e3e3 100644
--- a/drivers/mtd/nand/s3c2410.c
+++ b/drivers/mtd/nand/s3c2410.c
@@ -1,7 +1,8 @@
/* linux/drivers/mtd/nand/s3c2410.c
*
* Copyright (c) 2004 Simtec Electronics
- * Ben Dooks <ben@simtec.co.uk>
+ * http://www.simtec.co.uk/products/SWLINUX/
+ * Ben Dooks <ben@simtec.co.uk>
*
* Samsung S3C2410 NAND driver
*
@@ -10,8 +11,10 @@
* 23-Sep-2004 BJD Mulitple device support
* 28-Sep-2004 BJD Fixed ECC placement for Hardware mode
* 12-Oct-2004 BJD Fixed errors in use of platform data
+ * 18-Feb-2005 BJD Fix sparse errors
+ * 14-Mar-2005 BJD Applied tglx's code reduction patch
*
- * $Id: s3c2410.c,v 1.7 2005/01/05 18:05:14 dwmw2 Exp $
+ * $Id: s3c2410.c,v 1.12 2005/03/17 11:31:26 bjd Exp $
*
* 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
@@ -69,10 +72,10 @@ static int hardware_ecc = 0;
*/
static struct nand_oobinfo nand_hw_eccoob = {
- .useecc = MTD_NANDECC_AUTOPLACE,
- .eccbytes = 3,
- .eccpos = {0, 1, 2 },
- .oobfree = { {8, 8} }
+ .useecc = MTD_NANDECC_AUTOPLACE,
+ .eccbytes = 3,
+ .eccpos = {0, 1, 2 },
+ .oobfree = { {8, 8} }
};
/* controller and mtd information */
@@ -99,7 +102,7 @@ struct s3c2410_nand_info {
struct device *device;
struct resource *area;
struct clk *clk;
- void *regs;
+ void __iomem *regs;
int mtd_count;
};
@@ -234,6 +237,7 @@ static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip)
static void s3c2410_nand_hwcontrol(struct mtd_info *mtd, int cmd)
{
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+ struct nand_chip *chip = mtd->priv;
unsigned long cur;
switch (cmd) {
@@ -249,117 +253,22 @@ static void s3c2410_nand_hwcontrol(struct mtd_info *mtd, int cmd)
writel(cur, info->regs + S3C2410_NFCONF);
break;
- /* we don't need to implement these */
case NAND_CTL_SETCLE:
- case NAND_CTL_CLRCLE:
- case NAND_CTL_SETALE:
- case NAND_CTL_CLRALE:
- pr_debug(PFX "s3c2410_nand_hwcontrol(%d) unusedn", cmd);
+ chip->IO_ADDR_W = info->regs + S3C2410_NFCMD;
break;
- }
-}
-
-/* s3c2410_nand_command
- *
- * This function implements sending commands and the relevant address
- * information to the chip, via the hardware controller. Since the
- * S3C2410 generates the correct ALE/CLE signaling automatically, we
- * do not need to use hwcontrol.
-*/
-
-static void s3c2410_nand_command (struct mtd_info *mtd, unsigned command,
- int column, int page_addr)
-{
- register struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
- register struct nand_chip *this = mtd->priv;
-
- /*
- * Write out the command to the device.
- */
- if (command == NAND_CMD_SEQIN) {
- int readcmd;
-
- if (column >= mtd->oobblock) {
- /* OOB area */
- column -= mtd->oobblock;
- readcmd = NAND_CMD_READOOB;
- } else if (column < 256) {
- /* First 256 bytes --> READ0 */
- readcmd = NAND_CMD_READ0;
- } else {
- column -= 256;
- readcmd = NAND_CMD_READ1;
- }
-
- writeb(readcmd, info->regs + S3C2410_NFCMD);
- }
- writeb(command, info->regs + S3C2410_NFCMD);
-
- /* Set ALE and clear CLE to start address cycle */
- if (column != -1 || page_addr != -1) {
+ case NAND_CTL_SETALE:
+ chip->IO_ADDR_W = info->regs + S3C2410_NFADDR;
+ break;
- /* Serially input address */
- if (column != -1) {
- /* Adjust columns for 16 bit buswidth */
- if (this->options & NAND_BUSWIDTH_16)
- column >>= 1;
- writeb(column, info->regs + S3C2410_NFADDR);
- }
- if (page_addr != -1) {
- writeb((unsigned char) (page_addr), info->regs + S3C2410_NFADDR);
- writeb((unsigned char) (page_addr >> 8), info->regs + S3C2410_NFADDR);
- /* One more address cycle for higher density devices */
- if (this->chipsize & 0x0c000000)
- writeb((unsigned char) ((page_addr >> 16) & 0x0f),
- info->regs + S3C2410_NFADDR);
- }
- /* Latch in address */
- }
-
- /*
- * program and erase have their own busy handlers
- * status and sequential in needs no delay
- */
- switch (command) {
-
- case NAND_CMD_PAGEPROG:
- case NAND_CMD_ERASE1:
- case NAND_CMD_ERASE2:
- case NAND_CMD_SEQIN:
- case NAND_CMD_STATUS:
- return;
-
- case NAND_CMD_RESET:
- if (this->dev_ready)
- break;
-
- udelay(this->chip_delay);
- writeb(NAND_CMD_STATUS, info->regs + S3C2410_NFCMD);
-
- while ( !(this->read_byte(mtd) & 0x40));
- return;
-
- /* This applies to read commands */
+ /* NAND_CTL_CLRCLE: */
+ /* NAND_CTL_CLRALE: */
default:
- /*
- * If we don't have access to the busy pin, we apply the given
- * command delay
- */
- if (!this->dev_ready) {
- udelay (this->chip_delay);
- return;
- }
+ chip->IO_ADDR_W = info->regs + S3C2410_NFDATA;
+ break;
}
-
- /* Apply this short delay always to ensure that we do wait tWB in
- * any case on any machine. */
- ndelay (100);
- /* wait until command is processed */
- while (!this->dev_ready(mtd));
}
-
/* s3c2410_nand_devready()
*
* returns 0 if the nand is busy, 1 if it is ready
@@ -523,11 +432,10 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
{
struct nand_chip *chip = &nmtd->chip;
- chip->IO_ADDR_R = (char *)info->regs + S3C2410_NFDATA;
- chip->IO_ADDR_W = (char *)info->regs + S3C2410_NFDATA;
+ chip->IO_ADDR_R = info->regs + S3C2410_NFDATA;
+ chip->IO_ADDR_W = info->regs + S3C2410_NFDATA;
chip->hwcontrol = s3c2410_nand_hwcontrol;
chip->dev_ready = s3c2410_nand_devready;
- chip->cmdfunc = s3c2410_nand_command;
chip->write_buf = s3c2410_nand_write_buf;
chip->read_buf = s3c2410_nand_read_buf;
chip->select_chip = s3c2410_nand_select_chip;
diff --git a/drivers/mtd/nand/sharpsl.c b/drivers/mtd/nand/sharpsl.c
index 29572793334..9853b87bb75 100755
--- a/drivers/mtd/nand/sharpsl.c
+++ b/drivers/mtd/nand/sharpsl.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2004 Richard Purdie
*
- * $Id: sharpsl.c,v 1.3 2005/01/03 14:53:50 rpurdie Exp $
+ * $Id: sharpsl.c,v 1.4 2005/01/23 11:09:19 rpurdie Exp $
*
* Based on Sharp's NAND driver sharp_sl.c
*
@@ -216,7 +216,7 @@ sharpsl_nand_init(void)
nr_partitions = DEFAULT_NUM_PARTITIONS;
sharpsl_partition_info = sharpsl_nand_default_partition_info;
if (machine_is_poodle()) {
- sharpsl_partition_info[1].size=22 * 1024 * 1024;
+ sharpsl_partition_info[1].size=30 * 1024 * 1024;
} else if (machine_is_corgi() || machine_is_shepherd()) {
sharpsl_partition_info[1].size=25 * 1024 * 1024;
} else if (machine_is_husky()) {