diff options
author | Ingo Molnar <mingo@elte.hu> | 2008-10-13 11:05:51 +0200 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-10-13 11:05:51 +0200 |
commit | accba5f3965d6a9d1bf7c1e1a7995d17e9d521b6 (patch) | |
tree | 8fb40782e79472ed882ff2098d4dd295557278ee /drivers/mtd | |
parent | x86/oprofile: reanaming op_model_athlon.c to op_model_amd.c (diff) | |
parent | MAINTAINERS: remove colon from headings (diff) | |
download | linux-accba5f3965d6a9d1bf7c1e1a7995d17e9d521b6.tar.xz linux-accba5f3965d6a9d1bf7c1e1a7995d17e9d521b6.zip |
Merge branch 'linus' into oprofile-v2
Conflicts:
arch/x86/kernel/apic_32.c
arch/x86/oprofile/nmi_int.c
include/linux/pci_ids.h
Diffstat (limited to 'drivers/mtd')
133 files changed, 2207 insertions, 1143 deletions
diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index eed06d068fd1..14f11f8b9e5f 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig @@ -1,5 +1,3 @@ -# $Id: Kconfig,v 1.11 2005/11/07 11:14:19 gleixner Exp $ - menuconfig MTD tristate "Memory Technology Device (MTD) support" depends on HAS_IOMEM diff --git a/drivers/mtd/afs.c b/drivers/mtd/afs.c index 52d51eb91c16..d072ca5be689 100644 --- a/drivers/mtd/afs.c +++ b/drivers/mtd/afs.c @@ -21,8 +21,6 @@ This is access code for flashes using ARM's flash partitioning standards. - $Id: afs.c,v 1.15 2005/11/07 11:14:19 gleixner Exp $ - ======================================================================*/ #include <linux/module.h> diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index fcd1aeccdf93..5f1b472137a0 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c @@ -4,8 +4,6 @@ * * (C) 2000 Red Hat. GPL'd * - * $Id: cfi_cmdset_0001.c,v 1.186 2005/11/23 22:07:52 nico Exp $ - * * * 10/10/2000 Nicolas Pitre <nico@cam.org> * - completely revamped method functions so they are aware and @@ -50,6 +48,8 @@ #define I82802AC 0x00ac #define MANUFACTURER_ST 0x0020 #define M50LPW080 0x002F +#define M50FLW080A 0x0080 +#define M50FLW080B 0x0081 #define AT49BV640D 0x02de static int cfi_intelext_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *); @@ -204,7 +204,7 @@ static void fixup_intel_strataflash(struct mtd_info *mtd, void* param) { struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; - struct cfi_pri_amdstd *extp = cfi->cmdset_priv; + struct cfi_pri_intelext *extp = cfi->cmdset_priv; printk(KERN_WARNING "cfi_cmdset_0001: Suspend " "erase on write disabled.\n"); @@ -301,6 +301,8 @@ static struct cfi_fixup jedec_fixup_table[] = { { MANUFACTURER_INTEL, I82802AB, fixup_use_fwh_lock, NULL, }, { MANUFACTURER_INTEL, I82802AC, fixup_use_fwh_lock, NULL, }, { MANUFACTURER_ST, M50LPW080, fixup_use_fwh_lock, NULL, }, + { MANUFACTURER_ST, M50FLW080A, fixup_use_fwh_lock, NULL, }, + { MANUFACTURER_ST, M50FLW080B, fixup_use_fwh_lock, NULL, }, { 0, 0, NULL, NULL } }; static struct cfi_fixup fixup_table[] = { @@ -1147,7 +1149,7 @@ static int inval_cache_and_wait_for_operation( struct cfi_private *cfi = map->fldrv_priv; map_word status, status_OK = CMD(0x80); int chip_state = chip->state; - unsigned int timeo, sleep_time; + unsigned int timeo, sleep_time, reset_timeo; spin_unlock(chip->mutex); if (inval_len) @@ -1158,6 +1160,7 @@ static int inval_cache_and_wait_for_operation( timeo = chip_op_time * 8; if (!timeo) timeo = 500000; + reset_timeo = timeo; sleep_time = chip_op_time / 2; for (;;) { @@ -1199,6 +1202,12 @@ static int inval_cache_and_wait_for_operation( remove_wait_queue(&chip->wq, &wait); spin_lock(chip->mutex); } + if (chip->erase_suspended || chip->write_suspended) { + /* Suspend has occured while sleep: reset timeout */ + timeo = reset_timeo; + chip->erase_suspended = 0; + chip->write_suspended = 0; + } } /* Done and happy. */ diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index f7fcc6389533..a972cc6be436 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -16,9 +16,6 @@ * Occasionally maintained by Thayne Harbaugh tharbaugh at lnxi dot com * * This code is GPL - * - * $Id: cfi_cmdset_0002.c,v 1.122 2005/11/07 11:14:22 gleixner Exp $ - * */ #include <linux/module.h> diff --git a/drivers/mtd/chips/cfi_cmdset_0020.c b/drivers/mtd/chips/cfi_cmdset_0020.c index 1b720cc571f3..d4714dd9f7ab 100644 --- a/drivers/mtd/chips/cfi_cmdset_0020.c +++ b/drivers/mtd/chips/cfi_cmdset_0020.c @@ -4,8 +4,6 @@ * * (C) 2000 Red Hat. GPL'd * - * $Id: cfi_cmdset_0020.c,v 1.22 2005/11/07 11:14:22 gleixner Exp $ - * * 10/10/2000 Nicolas Pitre <nico@cam.org> * - completely revamped method functions so they are aware and * independent of the flash geometry (buswidth, interleave, etc.) diff --git a/drivers/mtd/chips/cfi_probe.c b/drivers/mtd/chips/cfi_probe.c index a4463a91ce31..c418e92e1d92 100644 --- a/drivers/mtd/chips/cfi_probe.c +++ b/drivers/mtd/chips/cfi_probe.c @@ -1,7 +1,6 @@ /* Common Flash Interface probe code. (C) 2000 Red Hat. GPL'd. - $Id: cfi_probe.c,v 1.86 2005/11/29 14:48:31 gleixner Exp $ */ #include <linux/module.h> diff --git a/drivers/mtd/chips/cfi_util.c b/drivers/mtd/chips/cfi_util.c index 72e0022a47bf..0ee457018016 100644 --- a/drivers/mtd/chips/cfi_util.c +++ b/drivers/mtd/chips/cfi_util.c @@ -6,9 +6,6 @@ * Copyright (C) 2003 STMicroelectronics Limited * * This code is covered by the GPL. - * - * $Id: cfi_util.c,v 1.10 2005/11/07 11:14:23 gleixner Exp $ - * */ #include <linux/module.h> diff --git a/drivers/mtd/chips/chipreg.c b/drivers/mtd/chips/chipreg.c index 2174c97549f0..c85760968227 100644 --- a/drivers/mtd/chips/chipreg.c +++ b/drivers/mtd/chips/chipreg.c @@ -1,6 +1,4 @@ /* - * $Id: chipreg.c,v 1.17 2004/11/16 18:29:00 dwmw2 Exp $ - * * Registration for chip drivers * */ diff --git a/drivers/mtd/chips/gen_probe.c b/drivers/mtd/chips/gen_probe.c index d338b8c92780..f061885b2812 100644 --- a/drivers/mtd/chips/gen_probe.c +++ b/drivers/mtd/chips/gen_probe.c @@ -2,7 +2,6 @@ * Routines common to all CFI-type probes. * (C) 2001-2003 Red Hat, Inc. * GPL'd - * $Id: gen_probe.c,v 1.24 2005/11/07 11:14:23 gleixner Exp $ */ #include <linux/kernel.h> @@ -71,8 +70,8 @@ static struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chi interleave and device type, etc. */ if (!genprobe_new_chip(map, cp, &cfi)) { /* The probe didn't like it */ - printk(KERN_DEBUG "%s: Found no %s device at location zero\n", - cp->name, map->name); + pr_debug("%s: Found no %s device at location zero\n", + cp->name, map->name); return NULL; } diff --git a/drivers/mtd/chips/jedec_probe.c b/drivers/mtd/chips/jedec_probe.c index aa07575eb288..f84ab6182148 100644 --- a/drivers/mtd/chips/jedec_probe.c +++ b/drivers/mtd/chips/jedec_probe.c @@ -1,7 +1,6 @@ /* Common Flash Interface probe code. (C) 2000 Red Hat. GPL'd. - $Id: jedec_probe.c,v 1.66 2005/11/07 11:14:23 gleixner Exp $ See JEDEC (http://www.jedec.org/) standard JESD21C (section 3.5) for the standard this probe goes back to. @@ -26,6 +25,7 @@ /* Manufacturers */ #define MANUFACTURER_AMD 0x0001 #define MANUFACTURER_ATMEL 0x001f +#define MANUFACTURER_EON 0x001c #define MANUFACTURER_FUJITSU 0x0004 #define MANUFACTURER_HYUNDAI 0x00AD #define MANUFACTURER_INTEL 0x0089 @@ -37,10 +37,11 @@ #define MANUFACTURER_ST 0x0020 #define MANUFACTURER_TOSHIBA 0x0098 #define MANUFACTURER_WINBOND 0x00da +#define CONTINUATION_CODE 0x007f /* AMD */ -#define AM29DL800BB 0x22C8 +#define AM29DL800BB 0x22CB #define AM29DL800BT 0x224A #define AM29F800BB 0x2258 @@ -58,6 +59,8 @@ #define AM29LV040B 0x004F #define AM29F032B 0x0041 #define AM29F002T 0x00B0 +#define AM29SL800DB 0x226B +#define AM29SL800DT 0x22EA /* Atmel */ #define AT49BV512 0x0003 @@ -67,6 +70,10 @@ #define AT49BV32X 0x00C8 #define AT49BV32XT 0x00C9 +/* Eon */ +#define EN29SL800BB 0x226B +#define EN29SL800BT 0x22EA + /* Fujitsu */ #define MBM29F040C 0x00A4 #define MBM29F800BA 0x2258 @@ -141,6 +148,8 @@ #define M50FW080 0x002D #define M50FW016 0x002E #define M50LPW080 0x002F +#define M50FLW080A 0x0080 +#define M50FLW080B 0x0081 /* SST */ #define SST29EE020 0x0010 @@ -191,6 +200,7 @@ enum uaddr { MTD_UADDR_0x0555_0x0AAA, MTD_UADDR_0x5555_0x2AAA, MTD_UADDR_0x0AAA_0x0555, + MTD_UADDR_0xAAAA_0x5555, MTD_UADDR_DONT_CARE, /* Requires an arbitrary address */ MTD_UADDR_UNNECESSARY, /* Does not require any address */ }; @@ -238,6 +248,11 @@ static const struct unlock_addr unlock_addrs[] = { .addr2 = 0x0555 }, + [MTD_UADDR_0xAAAA_0x5555] = { + .addr1 = 0xaaaa, + .addr2 = 0x5555 + }, + [MTD_UADDR_DONT_CARE] = { .addr1 = 0x0000, /* Doesn't matter which address */ .addr2 = 0x0000 /* is used - must be last entry */ @@ -522,6 +537,36 @@ static const struct amd_flash_info jedec_table[] = { ERASEINFO(0x04000,1), } }, { + .mfr_id = MANUFACTURER_AMD, + .dev_id = AM29SL800DT, + .name = "AMD AM29SL800DT", + .devtypes = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8, + .uaddr = MTD_UADDR_0x0AAA_0x0555, + .dev_size = SIZE_1MiB, + .cmd_set = P_ID_AMD_STD, + .nr_regions = 4, + .regions = { + ERASEINFO(0x10000,15), + ERASEINFO(0x08000,1), + ERASEINFO(0x02000,2), + ERASEINFO(0x04000,1), + } + }, { + .mfr_id = MANUFACTURER_AMD, + .dev_id = AM29SL800DB, + .name = "AMD AM29SL800DB", + .devtypes = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8, + .uaddr = MTD_UADDR_0x0AAA_0x0555, + .dev_size = SIZE_1MiB, + .cmd_set = P_ID_AMD_STD, + .nr_regions = 4, + .regions = { + ERASEINFO(0x04000,1), + ERASEINFO(0x02000,2), + ERASEINFO(0x08000,1), + ERASEINFO(0x10000,15), + } + }, { .mfr_id = MANUFACTURER_ATMEL, .dev_id = AT49BV512, .name = "Atmel AT49BV512", @@ -599,6 +644,36 @@ static const struct amd_flash_info jedec_table[] = { ERASEINFO(0x02000,8) } }, { + .mfr_id = MANUFACTURER_EON, + .dev_id = EN29SL800BT, + .name = "Eon EN29SL800BT", + .devtypes = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8, + .uaddr = MTD_UADDR_0x0AAA_0x0555, + .dev_size = SIZE_1MiB, + .cmd_set = P_ID_AMD_STD, + .nr_regions = 4, + .regions = { + ERASEINFO(0x10000,15), + ERASEINFO(0x08000,1), + ERASEINFO(0x02000,2), + ERASEINFO(0x04000,1), + } + }, { + .mfr_id = MANUFACTURER_EON, + .dev_id = EN29SL800BB, + .name = "Eon EN29SL800BB", + .devtypes = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8, + .uaddr = MTD_UADDR_0x0AAA_0x0555, + .dev_size = SIZE_1MiB, + .cmd_set = P_ID_AMD_STD, + .nr_regions = 4, + .regions = { + ERASEINFO(0x04000,1), + ERASEINFO(0x02000,2), + ERASEINFO(0x08000,1), + ERASEINFO(0x10000,15), + } + }, { .mfr_id = MANUFACTURER_FUJITSU, .dev_id = MBM29F040C, .name = "Fujitsu MBM29F040C", @@ -1392,8 +1467,8 @@ static const struct amd_flash_info jedec_table[] = { .mfr_id = MANUFACTURER_SST, /* should be CFI */ .dev_id = SST39LF160, .name = "SST 39LF160", - .devtypes = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8, - .uaddr = MTD_UADDR_0x5555_0x2AAA, /* ???? */ + .devtypes = CFI_DEVICETYPE_X16, + .uaddr = MTD_UADDR_0xAAAA_0x5555, .dev_size = SIZE_2MiB, .cmd_set = P_ID_AMD_STD, .nr_regions = 2, @@ -1405,8 +1480,8 @@ static const struct amd_flash_info jedec_table[] = { .mfr_id = MANUFACTURER_SST, /* should be CFI */ .dev_id = SST39VF1601, .name = "SST 39VF1601", - .devtypes = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8, - .uaddr = MTD_UADDR_0x5555_0x2AAA, /* ???? */ + .devtypes = CFI_DEVICETYPE_X16, + .uaddr = MTD_UADDR_0xAAAA_0x5555, .dev_size = SIZE_2MiB, .cmd_set = P_ID_AMD_STD, .nr_regions = 2, @@ -1590,6 +1665,36 @@ static const struct amd_flash_info jedec_table[] = { .nr_regions = 1, .regions = { ERASEINFO(0x10000,16), + }, + }, { + .mfr_id = MANUFACTURER_ST, + .dev_id = M50FLW080A, + .name = "ST M50FLW080A", + .devtypes = CFI_DEVICETYPE_X8, + .uaddr = MTD_UADDR_UNNECESSARY, + .dev_size = SIZE_1MiB, + .cmd_set = P_ID_INTEL_EXT, + .nr_regions = 4, + .regions = { + ERASEINFO(0x1000,16), + ERASEINFO(0x10000,13), + ERASEINFO(0x1000,16), + ERASEINFO(0x1000,16), + } + }, { + .mfr_id = MANUFACTURER_ST, + .dev_id = M50FLW080B, + .name = "ST M50FLW080B", + .devtypes = CFI_DEVICETYPE_X8, + .uaddr = MTD_UADDR_UNNECESSARY, + .dev_size = SIZE_1MiB, + .cmd_set = P_ID_INTEL_EXT, + .nr_regions = 4, + .regions = { + ERASEINFO(0x1000,16), + ERASEINFO(0x1000,16), + ERASEINFO(0x10000,13), + ERASEINFO(0x1000,16), } }, { .mfr_id = MANUFACTURER_TOSHIBA, @@ -1696,9 +1801,21 @@ static inline u32 jedec_read_mfr(struct map_info *map, uint32_t base, { map_word result; unsigned long mask; - u32 ofs = cfi_build_cmd_addr(0, cfi_interleave(cfi), cfi->device_type); - mask = (1 << (cfi->device_type * 8)) -1; - result = map_read(map, base + ofs); + int bank = 0; + + /* According to JEDEC "Standard Manufacturer's Identification Code" + * (http://www.jedec.org/download/search/jep106W.pdf) + * several first banks can contain 0x7f instead of actual ID + */ + do { + uint32_t ofs = cfi_build_cmd_addr(0 + (bank << 8), + cfi_interleave(cfi), + cfi->device_type); + mask = (1 << (cfi->device_type * 8)) - 1; + result = map_read(map, base + ofs); + bank++; + } while ((result.x[0] & mask) == CONTINUATION_CODE); + return result.x[0] & mask; } diff --git a/drivers/mtd/chips/map_absent.c b/drivers/mtd/chips/map_absent.c index fc478c0f93f5..494d30d0631a 100644 --- a/drivers/mtd/chips/map_absent.c +++ b/drivers/mtd/chips/map_absent.c @@ -1,7 +1,6 @@ /* * Common code to handle absent "placeholder" devices * Copyright 2001 Resilience Corporation <ebrower@resilience.com> - * $Id: map_absent.c,v 1.6 2005/11/07 11:14:23 gleixner Exp $ * * This map driver is used to allocate "placeholder" MTD * devices on systems that have socketed/removable media. diff --git a/drivers/mtd/chips/map_ram.c b/drivers/mtd/chips/map_ram.c index 5cb6d5263661..072dd8abf33a 100644 --- a/drivers/mtd/chips/map_ram.c +++ b/drivers/mtd/chips/map_ram.c @@ -1,7 +1,6 @@ /* * Common code to handle map devices which are simple RAM * (C) 2000 Red Hat. GPL'd. - * $Id: map_ram.c,v 1.22 2005/01/05 18:05:12 dwmw2 Exp $ */ #include <linux/module.h> diff --git a/drivers/mtd/chips/map_rom.c b/drivers/mtd/chips/map_rom.c index cb27f855074c..821d0ed6bae3 100644 --- a/drivers/mtd/chips/map_rom.c +++ b/drivers/mtd/chips/map_rom.c @@ -1,7 +1,6 @@ /* * Common code to handle map devices which are simple ROM * (C) 2000 Red Hat. GPL'd. - * $Id: map_rom.c,v 1.23 2005/01/05 18:05:12 dwmw2 Exp $ */ #include <linux/module.h> diff --git a/drivers/mtd/cmdlinepart.c b/drivers/mtd/cmdlinepart.c index e472a0e9de9d..71bc07f149b7 100644 --- a/drivers/mtd/cmdlinepart.c +++ b/drivers/mtd/cmdlinepart.c @@ -1,6 +1,4 @@ /* - * $Id: cmdlinepart.c,v 1.19 2005/11/07 11:14:19 gleixner Exp $ - * * Read flash partition table from command line * * Copyright 2002 SYSGO Real-Time Solutions GmbH @@ -308,7 +306,7 @@ static int parse_cmdline_partitions(struct mtd_info *master, unsigned long offset; int i; struct cmdline_mtd_partition *part; - char *mtd_id = master->name; + const char *mtd_id = master->name; /* parse command line */ if (!cmdline_parsed) diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig index 35ed1103dbb2..9c613f06623c 100644 --- a/drivers/mtd/devices/Kconfig +++ b/drivers/mtd/devices/Kconfig @@ -1,5 +1,4 @@ # drivers/mtd/maps/Kconfig -# $Id: Kconfig,v 1.18 2005/11/07 11:14:24 gleixner Exp $ menu "Self-contained MTD device drivers" depends on MTD!=n diff --git a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile index 0f788d5c4bf8..0993d5cf3923 100644 --- a/drivers/mtd/devices/Makefile +++ b/drivers/mtd/devices/Makefile @@ -1,7 +1,6 @@ # # linux/drivers/devices/Makefile # -# $Id: Makefile.common,v 1.7 2004/12/22 17:51:15 joern Exp $ obj-$(CONFIG_MTD_DOC2000) += doc2000.o obj-$(CONFIG_MTD_DOC2001) += doc2001.o diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c index 7b72a1b36115..91fbba767635 100644 --- a/drivers/mtd/devices/block2mtd.c +++ b/drivers/mtd/devices/block2mtd.c @@ -1,6 +1,4 @@ /* - * $Id: block2mtd.c,v 1.30 2005/11/29 14:48:32 gleixner Exp $ - * * block2mtd.c - create an mtd from a block device * * Copyright (C) 2001,2002 Simon Evans <spse@secret.org.uk> @@ -20,9 +18,6 @@ #include <linux/mutex.h> #include <linux/mount.h> -#define VERSION "$Revision: 1.30 $" - - #define ERROR(fmt, args...) printk(KERN_ERR "block2mtd: " fmt "\n" , ## args) #define INFO(fmt, args...) printk(KERN_INFO "block2mtd: " fmt "\n" , ## args) @@ -453,7 +448,6 @@ MODULE_PARM_DESC(block2mtd, "Device to use. \"block2mtd=<dev>[,<erasesize>]\""); static int __init block2mtd_init(void) { int ret = 0; - INFO("version " VERSION); #ifndef MODULE if (strlen(block2mtd_paramline)) diff --git a/drivers/mtd/devices/doc2000.c b/drivers/mtd/devices/doc2000.c index 846989f292e3..50de839c77a9 100644 --- a/drivers/mtd/devices/doc2000.c +++ b/drivers/mtd/devices/doc2000.c @@ -3,8 +3,6 @@ * Linux driver for Disk-On-Chip 2000 and Millennium * (c) 1999 Machine Vision Holdings, Inc. * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org> - * - * $Id: doc2000.c,v 1.67 2005/11/07 11:14:24 gleixner Exp $ */ #include <linux/kernel.h> diff --git a/drivers/mtd/devices/doc2001.c b/drivers/mtd/devices/doc2001.c index 6413efc045e0..e32c568c1145 100644 --- a/drivers/mtd/devices/doc2001.c +++ b/drivers/mtd/devices/doc2001.c @@ -3,8 +3,6 @@ * Linux driver for Disk-On-Chip Millennium * (c) 1999 Machine Vision Holdings, Inc. * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org> - * - * $Id: doc2001.c,v 1.49 2005/11/07 11:14:24 gleixner Exp $ */ #include <linux/kernel.h> diff --git a/drivers/mtd/devices/doc2001plus.c b/drivers/mtd/devices/doc2001plus.c index 83be3461658f..d853f891b586 100644 --- a/drivers/mtd/devices/doc2001plus.c +++ b/drivers/mtd/devices/doc2001plus.c @@ -6,8 +6,6 @@ * (c) 1999 Machine Vision Holdings, Inc. * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org> * - * $Id: doc2001plus.c,v 1.14 2005/11/07 11:14:24 gleixner Exp $ - * * Released under GPL */ diff --git a/drivers/mtd/devices/docecc.c b/drivers/mtd/devices/docecc.c index fd8a8daba3a8..874e51b110a2 100644 --- a/drivers/mtd/devices/docecc.c +++ b/drivers/mtd/devices/docecc.c @@ -7,8 +7,6 @@ * Author: Fabrice Bellard (fabrice.bellard@netgem.com) * Copyright (C) 2000 Netgem S.A. * - * $Id: docecc.c,v 1.7 2005/11/07 11:14:25 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 diff --git a/drivers/mtd/devices/docprobe.c b/drivers/mtd/devices/docprobe.c index d8cc94ec4e50..6e62922942b1 100644 --- a/drivers/mtd/devices/docprobe.c +++ b/drivers/mtd/devices/docprobe.c @@ -4,9 +4,6 @@ /* (C) 1999 Machine Vision Holdings, Inc. */ /* (C) 1999-2003 David Woodhouse <dwmw2@infradead.org> */ -/* $Id: docprobe.c,v 1.46 2005/11/07 11:14:25 gleixner Exp $ */ - - /* DOC_PASSIVE_PROBE: In order to ensure that the BIOS checksum is correct at boot time, and @@ -79,8 +76,6 @@ static unsigned long __initdata doc_locations[] = { 0xe0000, 0xe2000, 0xe4000, 0xe6000, 0xe8000, 0xea000, 0xec000, 0xee000, #endif /* CONFIG_MTD_DOCPROBE_HIGH */ -#elif defined(__PPC__) - 0xe4000000, #else #warning Unknown architecture for DiskOnChip. No default probe locations defined #endif diff --git a/drivers/mtd/devices/lart.c b/drivers/mtd/devices/lart.c index 1d324e5c412d..f4bda4cee495 100644 --- a/drivers/mtd/devices/lart.c +++ b/drivers/mtd/devices/lart.c @@ -2,8 +2,6 @@ /* * MTD driver for the 28F160F3 Flash Memory (non-CFI) on LART. * - * $Id: lart.c,v 1.9 2005/11/07 11:14:25 gleixner Exp $ - * * Author: Abraham vd Merwe <abraham@2d3d.co.za> * * Copyright (c) 2001, 2d3D, Inc. diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index b402269301f6..b35c3333e210 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -33,6 +33,7 @@ /* Flash opcodes. */ #define OPCODE_WREN 0x06 /* Write enable */ #define OPCODE_RDSR 0x05 /* Read status register */ +#define OPCODE_WRSR 0x01 /* Write status register 1 byte */ #define OPCODE_NORM_READ 0x03 /* Read data bytes (low frequency) */ #define OPCODE_FAST_READ 0x0b /* Read data bytes (high frequency) */ #define OPCODE_PP 0x02 /* Page program (up to 256 bytes) */ @@ -112,6 +113,17 @@ static int read_sr(struct m25p *flash) return val; } +/* + * Write status register 1 byte + * Returns negative if error occurred. + */ +static int write_sr(struct m25p *flash, u8 val) +{ + flash->command[0] = OPCODE_WRSR; + flash->command[1] = val; + + return spi_write(flash->spi, flash->command, 2); +} /* * Set write enable latch with Write Enable command. @@ -589,6 +601,16 @@ static int __devinit m25p_probe(struct spi_device *spi) mutex_init(&flash->lock); dev_set_drvdata(&spi->dev, flash); + /* + * Atmel serial flash tend to power up + * with the software protection bits set + */ + + if (info->jedec_id >> 16 == 0x1f) { + write_enable(flash); + write_sr(flash, 0); + } + if (data && data->name) flash->mtd.name = data->name; else diff --git a/drivers/mtd/devices/ms02-nv.c b/drivers/mtd/devices/ms02-nv.c index 9cff119a2024..6a9a24a80a6d 100644 --- a/drivers/mtd/devices/ms02-nv.c +++ b/drivers/mtd/devices/ms02-nv.c @@ -5,8 +5,6 @@ * 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. - * - * $Id: ms02-nv.c,v 1.11 2005/11/14 13:41:47 macro Exp $ */ #include <linux/init.h> diff --git a/drivers/mtd/devices/ms02-nv.h b/drivers/mtd/devices/ms02-nv.h index 8a6eef7cfee3..04deafd3a771 100644 --- a/drivers/mtd/devices/ms02-nv.h +++ b/drivers/mtd/devices/ms02-nv.h @@ -9,8 +9,6 @@ * 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. - * - * $Id: ms02-nv.h,v 1.3 2003/08/19 09:25:36 dwmw2 Exp $ */ #include <linux/ioport.h> diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c index b35e4813a3a5..8bd0dea6885f 100644 --- a/drivers/mtd/devices/mtd_dataflash.c +++ b/drivers/mtd/devices/mtd_dataflash.c @@ -15,6 +15,8 @@ #include <linux/delay.h> #include <linux/device.h> #include <linux/mutex.h> +#include <linux/err.h> + #include <linux/spi/spi.h> #include <linux/spi/flash.h> @@ -82,7 +84,7 @@ struct dataflash { - u8 command[4]; + uint8_t command[4]; char name[24]; unsigned partitioned:1; @@ -150,7 +152,7 @@ static int dataflash_erase(struct mtd_info *mtd, struct erase_info *instr) struct spi_transfer x = { .tx_dma = 0, }; struct spi_message msg; unsigned blocksize = priv->page_size << 3; - u8 *command; + uint8_t *command; DEBUG(MTD_DEBUG_LEVEL2, "%s: erase addr=0x%x len 0x%x\n", spi->dev.bus_id, @@ -182,8 +184,8 @@ static int dataflash_erase(struct mtd_info *mtd, struct erase_info *instr) pageaddr = pageaddr << priv->page_offset; command[0] = do_block ? OP_ERASE_BLOCK : OP_ERASE_PAGE; - command[1] = (u8)(pageaddr >> 16); - command[2] = (u8)(pageaddr >> 8); + command[1] = (uint8_t)(pageaddr >> 16); + command[2] = (uint8_t)(pageaddr >> 8); command[3] = 0; DEBUG(MTD_DEBUG_LEVEL3, "ERASE %s: (%x) %x %x %x [%i]\n", @@ -234,7 +236,7 @@ static int dataflash_read(struct mtd_info *mtd, loff_t from, size_t len, struct spi_transfer x[2] = { { .tx_dma = 0, }, }; struct spi_message msg; unsigned int addr; - u8 *command; + uint8_t *command; int status; DEBUG(MTD_DEBUG_LEVEL2, "%s: read 0x%x..0x%x\n", @@ -274,9 +276,9 @@ static int dataflash_read(struct mtd_info *mtd, loff_t from, size_t len, * fewer "don't care" bytes. Both buffers stay unchanged. */ command[0] = OP_READ_CONTINUOUS; - command[1] = (u8)(addr >> 16); - command[2] = (u8)(addr >> 8); - command[3] = (u8)(addr >> 0); + command[1] = (uint8_t)(addr >> 16); + command[2] = (uint8_t)(addr >> 8); + command[3] = (uint8_t)(addr >> 0); /* plus 4 "don't care" bytes */ status = spi_sync(priv->spi, &msg); @@ -311,7 +313,7 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len, size_t remaining = len; u_char *writebuf = (u_char *) buf; int status = -EINVAL; - u8 *command; + uint8_t *command; DEBUG(MTD_DEBUG_LEVEL2, "%s: write 0x%x..0x%x\n", spi->dev.bus_id, (unsigned)to, (unsigned)(to + len)); @@ -487,7 +489,8 @@ add_dataflash(struct spi_device *spi, char *name, device->write = dataflash_write; device->priv = priv; - dev_info(&spi->dev, "%s (%d KBytes)\n", name, device->size/1024); + dev_info(&spi->dev, "%s (%d KBytes) pagesize %d bytes\n", + name, DIV_ROUND_UP(device->size, 1024), pagesize); dev_set_drvdata(&spi->dev, priv); if (mtd_has_partitions()) { @@ -516,12 +519,135 @@ add_dataflash(struct spi_device *spi, char *name, return add_mtd_device(device) == 1 ? -ENODEV : 0; } +struct flash_info { + char *name; + + /* JEDEC id has a high byte of zero plus three data bytes: + * the manufacturer id, then a two byte device id. + */ + uint32_t jedec_id; + + /* The size listed here is what works with OP_ERASE_PAGE. */ + unsigned nr_pages; + uint16_t pagesize; + uint16_t pageoffset; + + uint16_t flags; +#define SUP_POW2PS 0x0002 /* supports 2^N byte pages */ +#define IS_POW2PS 0x0001 /* uses 2^N byte pages */ +}; + +static struct flash_info __devinitdata dataflash_data [] = { + + /* + * NOTE: chips with SUP_POW2PS (rev D and up) need two entries, + * one with IS_POW2PS and the other without. The entry with the + * non-2^N byte page size can't name exact chip revisions without + * losing backwards compatibility for cmdlinepart. + * + * These newer chips also support 128-byte security registers (with + * 64 bytes one-time-programmable) and software write-protection. + */ + { "AT45DB011B", 0x1f2200, 512, 264, 9, SUP_POW2PS}, + { "at45db011d", 0x1f2200, 512, 256, 8, SUP_POW2PS | IS_POW2PS}, + + { "AT45DB021B", 0x1f2300, 1024, 264, 9, SUP_POW2PS}, + { "at45db021d", 0x1f2300, 1024, 256, 8, SUP_POW2PS | IS_POW2PS}, + + { "AT45DB041x", 0x1f2400, 2048, 264, 9, SUP_POW2PS}, + { "at45db041d", 0x1f2400, 2048, 256, 8, SUP_POW2PS | IS_POW2PS}, + + { "AT45DB081B", 0x1f2500, 4096, 264, 9, SUP_POW2PS}, + { "at45db081d", 0x1f2500, 4096, 256, 8, SUP_POW2PS | IS_POW2PS}, + + { "AT45DB161x", 0x1f2600, 4096, 528, 10, SUP_POW2PS}, + { "at45db161d", 0x1f2600, 4096, 512, 9, SUP_POW2PS | IS_POW2PS}, + + { "AT45DB321x", 0x1f2700, 8192, 528, 10, 0}, /* rev C */ + + { "AT45DB321x", 0x1f2701, 8192, 528, 10, SUP_POW2PS}, + { "at45db321d", 0x1f2701, 8192, 512, 9, SUP_POW2PS | IS_POW2PS}, + + { "AT45DB642x", 0x1f2800, 8192, 1056, 11, SUP_POW2PS}, + { "at45db642d", 0x1f2800, 8192, 1024, 10, SUP_POW2PS | IS_POW2PS}, +}; + +static struct flash_info *__devinit jedec_probe(struct spi_device *spi) +{ + int tmp; + uint8_t code = OP_READ_ID; + uint8_t id[3]; + uint32_t jedec; + struct flash_info *info; + int status; + + /* JEDEC also defines an optional "extended device information" + * string for after vendor-specific data, after the three bytes + * we use here. Supporting some chips might require using it. + * + * If the vendor ID isn't Atmel's (0x1f), assume this call failed. + * That's not an error; only rev C and newer chips handle it, and + * only Atmel sells these chips. + */ + tmp = spi_write_then_read(spi, &code, 1, id, 3); + if (tmp < 0) { + DEBUG(MTD_DEBUG_LEVEL0, "%s: error %d reading JEDEC ID\n", + spi->dev.bus_id, tmp); + return ERR_PTR(tmp); + } + if (id[0] != 0x1f) + return NULL; + + jedec = id[0]; + jedec = jedec << 8; + jedec |= id[1]; + jedec = jedec << 8; + jedec |= id[2]; + + for (tmp = 0, info = dataflash_data; + tmp < ARRAY_SIZE(dataflash_data); + tmp++, info++) { + if (info->jedec_id == jedec) { + DEBUG(MTD_DEBUG_LEVEL1, "%s: OTP, sector protect%s\n", + dev_name(&spi->dev), + (info->flags & SUP_POW2PS) + ? ", binary pagesize" : "" + ); + if (info->flags & SUP_POW2PS) { + status = dataflash_status(spi); + if (status < 0) { + DEBUG(MTD_DEBUG_LEVEL1, + "%s: status error %d\n", + dev_name(&spi->dev), status); + return ERR_PTR(status); + } + if (status & 0x1) { + if (info->flags & IS_POW2PS) + return info; + } else { + if (!(info->flags & IS_POW2PS)) + return info; + } + } + } + } + + /* + * Treat other chips as errors ... we won't know the right page + * size (it might be binary) even when we can tell which density + * class is involved (legacy chip id scheme). + */ + dev_warn(&spi->dev, "JEDEC id %06x not handled\n", jedec); + return ERR_PTR(-ENODEV); +} + /* - * Detect and initialize DataFlash device: + * Detect and initialize DataFlash device, using JEDEC IDs on newer chips + * or else the ID code embedded in the status bits: * * Device Density ID code #Pages PageSize Offset * AT45DB011B 1Mbit (128K) xx0011xx (0x0c) 512 264 9 - * AT45DB021B 2Mbit (256K) xx0101xx (0x14) 1025 264 9 + * AT45DB021B 2Mbit (256K) xx0101xx (0x14) 1024 264 9 * AT45DB041B 4Mbit (512K) xx0111xx (0x1c) 2048 264 9 * AT45DB081B 8Mbit (1M) xx1001xx (0x24) 4096 264 9 * AT45DB0161B 16Mbit (2M) xx1011xx (0x2c) 4096 528 10 @@ -532,7 +658,24 @@ add_dataflash(struct spi_device *spi, char *name, static int __devinit dataflash_probe(struct spi_device *spi) { int status; + struct flash_info *info; + /* + * Try to detect dataflash by JEDEC ID. + * If it succeeds we know we have either a C or D part. + * D will support power of 2 pagesize option. + */ + info = jedec_probe(spi); + if (IS_ERR(info)) + return PTR_ERR(info); + if (info != NULL) + return add_dataflash(spi, info->name, info->nr_pages, + info->pagesize, info->pageoffset); + + /* + * Older chips support only legacy commands, identifing + * capacity using bits in the status byte. + */ status = dataflash_status(spi); if (status <= 0 || status == 0xff) { DEBUG(MTD_DEBUG_LEVEL1, "%s: status error %d\n", @@ -551,7 +694,7 @@ static int __devinit dataflash_probe(struct spi_device *spi) status = add_dataflash(spi, "AT45DB011B", 512, 264, 9); break; case 0x14: /* 0 1 0 1 x x */ - status = add_dataflash(spi, "AT45DB021B", 1025, 264, 9); + status = add_dataflash(spi, "AT45DB021B", 1024, 264, 9); break; case 0x1c: /* 0 1 1 1 x x */ status = add_dataflash(spi, "AT45DB041x", 2048, 264, 9); diff --git a/drivers/mtd/devices/mtdram.c b/drivers/mtd/devices/mtdram.c index 0399be178620..3aaca88847d3 100644 --- a/drivers/mtd/devices/mtdram.c +++ b/drivers/mtd/devices/mtdram.c @@ -1,6 +1,5 @@ /* * mtdram - a test mtd device - * $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> diff --git a/drivers/mtd/devices/phram.c b/drivers/mtd/devices/phram.c index c7987b1c5e01..088fbb7595b5 100644 --- a/drivers/mtd/devices/phram.c +++ b/drivers/mtd/devices/phram.c @@ -1,6 +1,4 @@ /** - * $Id: phram.c,v 1.16 2005/11/07 11:14:25 gleixner Exp $ - * * Copyright (c) ???? Jochen Schäuble <psionic@psionic.de> * Copyright (c) 2003-2004 Joern Engel <joern@wh.fh-wedel.de> * diff --git a/drivers/mtd/devices/pmc551.c b/drivers/mtd/devices/pmc551.c index bc9981749064..d38bca64bb15 100644 --- a/drivers/mtd/devices/pmc551.c +++ b/drivers/mtd/devices/pmc551.c @@ -1,6 +1,4 @@ /* - * $Id: pmc551.c,v 1.32 2005/11/07 11:14:25 gleixner Exp $ - * * PMC551 PCI Mezzanine Ram Device * * Author: diff --git a/drivers/mtd/devices/slram.c b/drivers/mtd/devices/slram.c index cb86db746f28..a425d09f35a0 100644 --- a/drivers/mtd/devices/slram.c +++ b/drivers/mtd/devices/slram.c @@ -1,7 +1,5 @@ /*====================================================================== - $Id: slram.c,v 1.36 2005/11/07 11:14:25 gleixner 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 use slram at least mtdblock or mtdchar is required (for block or diff --git a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c index 5c29872184e6..9bf581c4f740 100644 --- a/drivers/mtd/ftl.c +++ b/drivers/mtd/ftl.c @@ -1,5 +1,4 @@ /* This version ported to the Linux-MTD system by dwmw2@infradead.org - * $Id: ftl.c,v 1.59 2005/11/29 14:48:31 gleixner Exp $ * * Fixes: Arnaldo Carvalho de Melo <acme@conectiva.com.br> * - fixes some leaks on failure in build_maps and ftl_notify_add, cleanups @@ -1006,6 +1005,29 @@ static int ftl_writesect(struct mtd_blktrans_dev *dev, return ftl_write((void *)dev, buf, block, 1); } +static int ftl_discardsect(struct mtd_blktrans_dev *dev, + unsigned long sector, unsigned nr_sects) +{ + partition_t *part = (void *)dev; + uint32_t bsize = 1 << part->header.EraseUnitSize; + + DEBUG(1, "FTL erase sector %ld for %d sectors\n", + sector, nr_sects); + + while (nr_sects) { + uint32_t old_addr = part->VirtualBlockMap[sector]; + if (old_addr != 0xffffffff) { + part->VirtualBlockMap[sector] = 0xffffffff; + part->EUNInfo[old_addr/bsize].Deleted++; + if (set_bam_entry(part, old_addr, 0)) + return -EIO; + } + nr_sects--; + sector++; + } + + return 0; +} /*====================================================================*/ static void ftl_freepart(partition_t *part) @@ -1070,6 +1092,7 @@ static struct mtd_blktrans_ops ftl_tr = { .blksize = SECTOR_SIZE, .readsect = ftl_readsect, .writesect = ftl_writesect, + .discard = ftl_discardsect, .getgeo = ftl_getgeo, .add_mtd = ftl_add_mtd, .remove_dev = ftl_remove_dev, @@ -1078,8 +1101,6 @@ static struct mtd_blktrans_ops ftl_tr = { static int init_ftl(void) { - DEBUG(0, "$Id: ftl.c,v 1.59 2005/11/29 14:48:31 gleixner Exp $\n"); - return register_mtd_blktrans(&ftl_tr); } diff --git a/drivers/mtd/inftlcore.c b/drivers/mtd/inftlcore.c index b0e396504e67..c4f9d3378b24 100644 --- a/drivers/mtd/inftlcore.c +++ b/drivers/mtd/inftlcore.c @@ -7,8 +7,6 @@ * (c) 1999 Machine Vision Holdings, Inc. * Author: David Woodhouse <dwmw2@infradead.org> * - * $Id: inftlcore.c,v 1.19 2005/11/07 11:14:20 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 @@ -953,9 +951,6 @@ static struct mtd_blktrans_ops inftl_tr = { static int __init init_inftl(void) { - printk(KERN_INFO "INFTL: inftlcore.c $Revision: 1.19 $, " - "inftlmount.c %s\n", inftlmountrev); - return register_mtd_blktrans(&inftl_tr); } diff --git a/drivers/mtd/inftlmount.c b/drivers/mtd/inftlmount.c index c551d2f0779c..9113628ed1ef 100644 --- a/drivers/mtd/inftlmount.c +++ b/drivers/mtd/inftlmount.c @@ -8,8 +8,6 @@ * Author: Fabrice Bellard (fabrice.bellard@netgem.com) * Copyright (C) 2000 Netgem S.A. * - * $Id: inftlmount.c,v 1.18 2005/11/07 11:14:20 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 @@ -39,8 +37,6 @@ #include <linux/mtd/inftl.h> #include <linux/mtd/compatmac.h> -char inftlmountrev[]="$Revision: 1.18 $"; - /* * find_boot_record: Find the INFTL Media Header and its Spare copy which * contains the various device information of the INFTL partition and diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index d2fbc2964523..df8e00bba07b 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig @@ -1,5 +1,4 @@ # drivers/mtd/maps/Kconfig -# $Id: Kconfig,v 1.61 2005/11/07 11:14:26 gleixner Exp $ menu "Mapping drivers for chip access" depends on MTD!=n @@ -510,6 +509,17 @@ config MTD_PCMCIA_ANONYMOUS If unsure, say N. +config MTD_BFIN_ASYNC + tristate "Blackfin BF533-STAMP Flash Chip Support" + depends on BFIN533_STAMP && MTD_CFI + select MTD_PARTITIONS + default y + help + Map driver which allows for simultaneous utilization of + ethernet and CFI parallel flash. + + If compiled as a module, it will be called bfin-async-flash. + config MTD_UCLINUX tristate "Generic uClinux RAM/ROM filesystem support" depends on MTD_PARTITIONS && !MMU @@ -539,24 +549,6 @@ config MTD_DMV182 help Map driver for Dy-4 SVME/DMV-182 board. -config MTD_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), or the - Thorcom VR1000 - - Note, this driver *cannot* over-ride the WP link on the - board, or currently detect the state of the link. - -config MTD_BAST_MAXSIZE - int "Maximum size for BAST flash area (MiB)" - depends on MTD_BAST - default "4" - config MTD_SHARP_SL tristate "ROM mapped on Sharp SL Series" depends on ARCH_PXA diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile index c6ce8673dab2..6cda6df973e5 100644 --- a/drivers/mtd/maps/Makefile +++ b/drivers/mtd/maps/Makefile @@ -1,7 +1,6 @@ # # linux/drivers/maps/Makefile # -# $Id: Makefile.common,v 1.34 2005/11/07 11:14:26 gleixner Exp $ ifeq ($(CONFIG_MTD_COMPLEX_MAPPINGS),y) obj-$(CONFIG_MTD) += map_funcs.o @@ -10,7 +9,6 @@ endif # Chip mappings obj-$(CONFIG_MTD_CDB89712) += cdb89712.o obj-$(CONFIG_MTD_ARM_INTEGRATOR)+= integrator-flash.o -obj-$(CONFIG_MTD_BAST) += bast-flash.o obj-$(CONFIG_MTD_CFI_FLAGADM) += cfi_flagadm.o obj-$(CONFIG_MTD_DC21285) += dc21285.o obj-$(CONFIG_MTD_DILNETPC) += dilnetpc.o @@ -66,3 +64,4 @@ obj-$(CONFIG_MTD_SHARP_SL) += sharpsl-flash.o obj-$(CONFIG_MTD_PLATRAM) += plat-ram.o obj-$(CONFIG_MTD_OMAP_NOR) += omap_nor.o obj-$(CONFIG_MTD_INTEL_VR_NOR) += intel_vr_nor.o +obj-$(CONFIG_MTD_BFIN_ASYNC) += bfin-async-flash.o diff --git a/drivers/mtd/maps/amd76xrom.c b/drivers/mtd/maps/amd76xrom.c index 728aed6ad722..d1eec7d3243f 100644 --- a/drivers/mtd/maps/amd76xrom.c +++ b/drivers/mtd/maps/amd76xrom.c @@ -2,12 +2,10 @@ * amd76xrom.c * * Normal mappings of chips in physical memory - * $Id: amd76xrom.c,v 1.21 2005/11/07 11:14:26 gleixner Exp $ */ #include <linux/module.h> #include <linux/types.h> -#include <linux/version.h> #include <linux/kernel.h> #include <linux/init.h> #include <asm/io.h> diff --git a/drivers/mtd/maps/autcpu12-nvram.c b/drivers/mtd/maps/autcpu12-nvram.c index 7ed3424dd959..53664188fc47 100644 --- a/drivers/mtd/maps/autcpu12-nvram.c +++ b/drivers/mtd/maps/autcpu12-nvram.c @@ -2,8 +2,6 @@ * NV-RAM memory access on autcpu12 * (C) 2002 Thomas Gleixner (gleixner@autronix.de) * - * $Id: autcpu12-nvram.c,v 1.9 2005/11/07 11:14:26 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 @@ -27,8 +25,8 @@ #include <linux/init.h> #include <asm/io.h> #include <asm/sizes.h> -#include <asm/hardware.h> -#include <asm/arch/autcpu12.h> +#include <mach/hardware.h> +#include <mach/autcpu12.h> #include <linux/mtd/mtd.h> #include <linux/mtd/map.h> #include <linux/mtd/partitions.h> diff --git a/drivers/mtd/maps/bast-flash.c b/drivers/mtd/maps/bast-flash.c deleted file mode 100644 index 1f492062f8ca..000000000000 --- a/drivers/mtd/maps/bast-flash.c +++ /dev/null @@ -1,226 +0,0 @@ -/* linux/drivers/mtd/maps/bast-flash.c - * - * 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.5 2005/11/07 11:14:26 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/slab.h> -#include <linux/platform_device.h> -#include <linux/mtd/mtd.h> -#include <linux/mtd/map.h> -#include <linux/mtd/partitions.h> - -#include <asm/io.h> -#include <asm/mach/flash.h> - -#include <asm/arch/map.h> -#include <asm/arch/bast-map.h> -#include <asm/arch/bast-cpld.h> - -#ifdef CONFIG_MTD_BAST_MAXSIZE -#define AREA_MAXSIZE (CONFIG_MTD_BAST_MAXSIZE * SZ_1M) -#else -#define AREA_MAXSIZE (32 * SZ_1M) -#endif - -#define PFX "bast-flash: " - -struct bast_flash_info { - struct mtd_info *mtd; - struct map_info map; - struct mtd_partition *partitions; - struct resource *area; -}; - -static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; - -static void bast_flash_setrw(int to) -{ - unsigned int val; - unsigned long flags; - - local_irq_save(flags); - val = __raw_readb(BAST_VA_CTRL3); - - if (to) - val |= BAST_CPLD_CTRL3_ROMWEN; - else - val &= ~BAST_CPLD_CTRL3_ROMWEN; - - pr_debug("new cpld ctrl3=%02x\n", val); - - __raw_writeb(val, BAST_VA_CTRL3); - local_irq_restore(flags); -} - -static int bast_flash_remove(struct platform_device *pdev) -{ - struct bast_flash_info *info = platform_get_drvdata(pdev); - - platform_set_drvdata(pdev, NULL); - - if (info == NULL) - return 0; - - if (info->map.virt != NULL) - iounmap(info->map.virt); - - if (info->mtd) { - del_mtd_partitions(info->mtd); - map_destroy(info->mtd); - } - - kfree(info->partitions); - - if (info->area) { - release_resource(info->area); - kfree(info->area); - } - - kfree(info); - - return 0; -} - -static int bast_flash_probe(struct platform_device *pdev) -{ - struct bast_flash_info *info; - struct resource *res; - int err = 0; - - info = kmalloc(sizeof(*info), GFP_KERNEL); - if (info == NULL) { - printk(KERN_ERR PFX "no memory for flash info\n"); - err = -ENOMEM; - goto exit_error; - } - - memzero(info, sizeof(*info)); - platform_set_drvdata(pdev, info); - - res = pdev->resource; /* assume that the flash has one resource */ - - info->map.phys = res->start; - info->map.size = res->end - res->start + 1; - info->map.name = pdev->dev.bus_id; - info->map.bankwidth = 2; - - if (info->map.size > AREA_MAXSIZE) - info->map.size = AREA_MAXSIZE; - - pr_debug("%s: area %08lx, size %ld\n", __func__, - info->map.phys, info->map.size); - - info->area = request_mem_region(res->start, info->map.size, - pdev->name); - if (info->area == NULL) { - printk(KERN_ERR PFX "cannot reserve flash memory region\n"); - err = -ENOENT; - goto exit_error; - } - - info->map.virt = ioremap(res->start, info->map.size); - pr_debug("%s: virt at %08x\n", __func__, (int)info->map.virt); - - if (info->map.virt == 0) { - printk(KERN_ERR PFX "failed to ioremap() region\n"); - err = -EIO; - goto exit_error; - } - - simple_map_init(&info->map); - - /* enable the write to the flash area */ - - bast_flash_setrw(1); - - /* probe for the device(s) */ - - info->mtd = do_map_probe("jedec_probe", &info->map); - if (info->mtd == NULL) - info->mtd = do_map_probe("cfi_probe", &info->map); - - if (info->mtd == NULL) { - printk(KERN_ERR PFX "map_probe() failed\n"); - err = -ENXIO; - goto exit_error; - } - - /* mark ourselves as the owner */ - info->mtd->owner = THIS_MODULE; - - err = parse_mtd_partitions(info->mtd, probes, &info->partitions, 0); - if (err > 0) { - 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) - return 0; - - /* fall through to exit error */ - - exit_error: - bast_flash_remove(pdev); - return err; -} - -static struct platform_driver bast_flash_driver = { - .probe = bast_flash_probe, - .remove = bast_flash_remove, - .driver = { - .name = "bast-nor", - .owner = THIS_MODULE, - }, -}; - -static int __init bast_flash_init(void) -{ - printk("BAST NOR-Flash Driver, (c) 2004 Simtec Electronics\n"); - return platform_driver_register(&bast_flash_driver); -} - -static void __exit bast_flash_exit(void) -{ - platform_driver_unregister(&bast_flash_driver); -} - -module_init(bast_flash_init); -module_exit(bast_flash_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); -MODULE_DESCRIPTION("BAST MTD Map driver"); -MODULE_ALIAS("platform:bast-nor"); diff --git a/drivers/mtd/maps/bfin-async-flash.c b/drivers/mtd/maps/bfin-async-flash.c new file mode 100644 index 000000000000..6fec86aaed7e --- /dev/null +++ b/drivers/mtd/maps/bfin-async-flash.c @@ -0,0 +1,219 @@ +/* + * drivers/mtd/maps/bfin-async-flash.c + * + * Handle the case where flash memory and ethernet mac/phy are + * mapped onto the same async bank. The BF533-STAMP does this + * for example. All board-specific configuration goes in your + * board resources file. + * + * Copyright 2000 Nicolas Pitre <nico@cam.org> + * Copyright 2005-2008 Analog Devices Inc. + * + * Enter bugs at http://blackfin.uclinux.org/ + * + * Licensed under the GPL-2 or later. + */ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/map.h> +#include <linux/mtd/partitions.h> +#include <linux/mtd/physmap.h> +#include <linux/platform_device.h> +#include <linux/types.h> + +#include <asm/blackfin.h> +#include <linux/gpio.h> +#include <linux/io.h> +#include <asm/unaligned.h> + +#define pr_devinit(fmt, args...) ({ static const __devinitconst char __fmt[] = fmt; printk(__fmt, ## args); }) + +#define DRIVER_NAME "bfin-async-flash" + +struct async_state { + struct mtd_info *mtd; + struct map_info map; + int enet_flash_pin; + uint32_t flash_ambctl0, flash_ambctl1; + uint32_t save_ambctl0, save_ambctl1; + unsigned long irq_flags; +}; + +static void switch_to_flash(struct async_state *state) +{ + local_irq_save(state->irq_flags); + + gpio_set_value(state->enet_flash_pin, 0); + + state->save_ambctl0 = bfin_read_EBIU_AMBCTL0(); + state->save_ambctl1 = bfin_read_EBIU_AMBCTL1(); + bfin_write_EBIU_AMBCTL0(state->flash_ambctl0); + bfin_write_EBIU_AMBCTL1(state->flash_ambctl1); + SSYNC(); +} + +static void switch_back(struct async_state *state) +{ + bfin_write_EBIU_AMBCTL0(state->save_ambctl0); + bfin_write_EBIU_AMBCTL1(state->save_ambctl1); + SSYNC(); + + gpio_set_value(state->enet_flash_pin, 1); + + local_irq_restore(state->irq_flags); +} + +static map_word bfin_read(struct map_info *map, unsigned long ofs) +{ + struct async_state *state = (struct async_state *)map->map_priv_1; + uint16_t word; + map_word test; + + switch_to_flash(state); + + word = readw(map->virt + ofs); + + switch_back(state); + + test.x[0] = word; + return test; +} + +static void bfin_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) +{ + struct async_state *state = (struct async_state *)map->map_priv_1; + + switch_to_flash(state); + + memcpy(to, map->virt + from, len); + + switch_back(state); +} + +static void bfin_write(struct map_info *map, map_word d1, unsigned long ofs) +{ + struct async_state *state = (struct async_state *)map->map_priv_1; + uint16_t d; + + d = d1.x[0]; + + switch_to_flash(state); + + writew(d, map->virt + ofs); + SSYNC(); + + switch_back(state); +} + +static void bfin_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) +{ + struct async_state *state = (struct async_state *)map->map_priv_1; + + switch_to_flash(state); + + memcpy(map->virt + to, from, len); + SSYNC(); + + switch_back(state); +} + +#ifdef CONFIG_MTD_PARTITIONS +static const char *part_probe_types[] = { "cmdlinepart", "RedBoot", NULL }; +#endif + +static int __devinit bfin_flash_probe(struct platform_device *pdev) +{ + int ret; + struct physmap_flash_data *pdata = pdev->dev.platform_data; + struct resource *memory = platform_get_resource(pdev, IORESOURCE_MEM, 0); + struct resource *flash_ambctl = platform_get_resource(pdev, IORESOURCE_MEM, 1); + struct async_state *state; + + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (!state) + return -ENOMEM; + + state->map.name = DRIVER_NAME; + state->map.read = bfin_read; + state->map.copy_from = bfin_copy_from; + state->map.write = bfin_write; + state->map.copy_to = bfin_copy_to; + state->map.bankwidth = pdata->width; + state->map.size = memory->end - memory->start + 1; + state->map.virt = (void __iomem *)memory->start; + state->map.phys = memory->start; + state->map.map_priv_1 = (unsigned long)state; + state->enet_flash_pin = platform_get_irq(pdev, 0); + state->flash_ambctl0 = flash_ambctl->start; + state->flash_ambctl1 = flash_ambctl->end; + + if (gpio_request(state->enet_flash_pin, DRIVER_NAME)) { + pr_devinit(KERN_ERR DRIVER_NAME ": Failed to request gpio %d\n", state->enet_flash_pin); + return -EBUSY; + } + gpio_direction_output(state->enet_flash_pin, 1); + + pr_devinit(KERN_NOTICE DRIVER_NAME ": probing %d-bit flash bus\n", state->map.bankwidth * 8); + state->mtd = do_map_probe(memory->name, &state->map); + if (!state->mtd) + return -ENXIO; + +#ifdef CONFIG_MTD_PARTITIONS + ret = parse_mtd_partitions(state->mtd, part_probe_types, &pdata->parts, 0); + if (ret > 0) { + pr_devinit(KERN_NOTICE DRIVER_NAME ": Using commandline partition definition\n"); + add_mtd_partitions(state->mtd, pdata->parts, ret); + + } else if (pdata->nr_parts) { + pr_devinit(KERN_NOTICE DRIVER_NAME ": Using board partition definition\n"); + add_mtd_partitions(state->mtd, pdata->parts, pdata->nr_parts); + + } else +#endif + { + pr_devinit(KERN_NOTICE DRIVER_NAME ": no partition info available, registering whole flash at once\n"); + add_mtd_device(state->mtd); + } + + platform_set_drvdata(pdev, state); + + return 0; +} + +static int __devexit bfin_flash_remove(struct platform_device *pdev) +{ + struct async_state *state = platform_get_drvdata(pdev); + gpio_free(state->enet_flash_pin); +#ifdef CONFIG_MTD_PARTITIONS + del_mtd_partitions(state->mtd); +#endif + map_destroy(state->mtd); + kfree(state); + return 0; +} + +static struct platform_driver bfin_flash_driver = { + .probe = bfin_flash_probe, + .remove = __devexit_p(bfin_flash_remove), + .driver = { + .name = DRIVER_NAME, + }, +}; + +static int __init bfin_flash_init(void) +{ + return platform_driver_register(&bfin_flash_driver); +} +module_init(bfin_flash_init); + +static void __exit bfin_flash_exit(void) +{ + platform_driver_unregister(&bfin_flash_driver); +} +module_exit(bfin_flash_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("MTD map driver for Blackfins with flash/ethernet on same async bank"); diff --git a/drivers/mtd/maps/cdb89712.c b/drivers/mtd/maps/cdb89712.c index 9f17bb6c5a9d..e5059aa3c724 100644 --- a/drivers/mtd/maps/cdb89712.c +++ b/drivers/mtd/maps/cdb89712.c @@ -1,7 +1,6 @@ /* * Flash on Cirrus CDB89712 * - * $Id: cdb89712.c,v 1.11 2005/11/07 11:14:26 gleixner Exp $ */ #include <linux/module.h> @@ -10,7 +9,7 @@ #include <linux/ioport.h> #include <linux/init.h> #include <asm/io.h> -#include <asm/arch/hardware.h> +#include <mach/hardware.h> #include <linux/mtd/mtd.h> #include <linux/mtd/map.h> #include <linux/mtd/partitions.h> diff --git a/drivers/mtd/maps/ceiva.c b/drivers/mtd/maps/ceiva.c index 629e6e2641a8..60e68bde0fea 100644 --- a/drivers/mtd/maps/ceiva.c +++ b/drivers/mtd/maps/ceiva.c @@ -11,7 +11,6 @@ * * (C) 2000 Nicolas Pitre <nico@cam.org> * - * $Id: ceiva.c,v 1.11 2004/09/16 23:27:12 gleixner Exp $ */ #include <linux/module.h> @@ -26,7 +25,7 @@ #include <linux/mtd/partitions.h> #include <linux/mtd/concat.h> -#include <asm/hardware.h> +#include <mach/hardware.h> #include <asm/mach-types.h> #include <asm/io.h> #include <asm/sizes.h> diff --git a/drivers/mtd/maps/cfi_flagadm.c b/drivers/mtd/maps/cfi_flagadm.c index 65e5ee552010..0ecc3f6d735b 100644 --- a/drivers/mtd/maps/cfi_flagadm.c +++ b/drivers/mtd/maps/cfi_flagadm.c @@ -1,8 +1,6 @@ /* * Copyright © 2001 Flaga hf. Medical Devices, Kári Davíðsson <kd@flaga.is> * - * $Id: cfi_flagadm.c,v 1.15 2005/11/07 11:14:26 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 diff --git a/drivers/mtd/maps/ck804xrom.c b/drivers/mtd/maps/ck804xrom.c index effaf7cdefab..1a6feb4474de 100644 --- a/drivers/mtd/maps/ck804xrom.c +++ b/drivers/mtd/maps/ck804xrom.c @@ -9,7 +9,6 @@ #include <linux/module.h> #include <linux/types.h> -#include <linux/version.h> #include <linux/kernel.h> #include <linux/init.h> #include <asm/io.h> diff --git a/drivers/mtd/maps/dbox2-flash.c b/drivers/mtd/maps/dbox2-flash.c index 92a9c7fac993..e115667bf1d0 100644 --- a/drivers/mtd/maps/dbox2-flash.c +++ b/drivers/mtd/maps/dbox2-flash.c @@ -1,6 +1,4 @@ /* - * $Id: dbox2-flash.c,v 1.14 2005/11/07 11:14:26 gleixner Exp $ - * * D-Box 2 flash driver */ diff --git a/drivers/mtd/maps/dc21285.c b/drivers/mtd/maps/dc21285.c index b32bb9347d71..3aa018c092f8 100644 --- a/drivers/mtd/maps/dc21285.c +++ b/drivers/mtd/maps/dc21285.c @@ -4,8 +4,6 @@ * (C) 2000 Nicolas Pitre <nico@cam.org> * * This code is GPL - * - * $Id: dc21285.c,v 1.24 2005/11/07 11:14:26 gleixner Exp $ */ #include <linux/module.h> #include <linux/types.h> diff --git a/drivers/mtd/maps/dilnetpc.c b/drivers/mtd/maps/dilnetpc.c index 1c3b34ad7325..0713e3a5a22c 100644 --- a/drivers/mtd/maps/dilnetpc.c +++ b/drivers/mtd/maps/dilnetpc.c @@ -14,8 +14,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: dilnetpc.c,v 1.20 2005/11/07 11:14:26 gleixner Exp $ - * * The DIL/Net PC is a tiny embedded PC board made by SSV Embedded Systems * featuring the AMD Elan SC410 processor. There are two variants of this * board: DNP/1486 and ADNP/1486. The DNP version has 2 megs of flash diff --git a/drivers/mtd/maps/dmv182.c b/drivers/mtd/maps/dmv182.c index e0558b0b2fe6..d171674eb2ed 100644 --- a/drivers/mtd/maps/dmv182.c +++ b/drivers/mtd/maps/dmv182.c @@ -4,8 +4,6 @@ * * Flash map driver for the Dy4 SVME182 board * - * $Id: dmv182.c,v 1.6 2005/11/07 11:14:26 gleixner Exp $ - * * Copyright 2003-2004, TimeSys Corporation * * Based on the SVME181 flash map, by Tom Nelson, Dot4, Inc. for TimeSys Corp. diff --git a/drivers/mtd/maps/ebony.c b/drivers/mtd/maps/ebony.c index 1488bb92f26f..d92b7c70d3ed 100644 --- a/drivers/mtd/maps/ebony.c +++ b/drivers/mtd/maps/ebony.c @@ -1,6 +1,4 @@ /* - * $Id: ebony.c,v 1.16 2005/11/07 11:14:26 gleixner Exp $ - * * Mapping for Ebony user flash * * Matt Porter <mporter@kernel.crashing.org> diff --git a/drivers/mtd/maps/edb7312.c b/drivers/mtd/maps/edb7312.c index 1c5b97c89685..9433738c1664 100644 --- a/drivers/mtd/maps/edb7312.c +++ b/drivers/mtd/maps/edb7312.c @@ -1,6 +1,4 @@ /* - * $Id: edb7312.c,v 1.14 2005/11/07 11:14:27 gleixner Exp $ - * * Handle mapping of the NOR flash on Cogent EDB7312 boards * * Copyright 2002 SYSGO Real-Time Solutions GmbH diff --git a/drivers/mtd/maps/esb2rom.c b/drivers/mtd/maps/esb2rom.c index aa64a4752781..bbbcdd4c8d13 100644 --- a/drivers/mtd/maps/esb2rom.c +++ b/drivers/mtd/maps/esb2rom.c @@ -12,7 +12,6 @@ #include <linux/module.h> #include <linux/types.h> -#include <linux/version.h> #include <linux/kernel.h> #include <linux/init.h> #include <asm/io.h> diff --git a/drivers/mtd/maps/fortunet.c b/drivers/mtd/maps/fortunet.c index 7c50c271651c..a8e3fde4cbd5 100644 --- a/drivers/mtd/maps/fortunet.c +++ b/drivers/mtd/maps/fortunet.c @@ -1,6 +1,5 @@ /* fortunet.c memory map * - * $Id: fortunet.c,v 1.11 2005/11/07 11:14:27 gleixner Exp $ */ #include <linux/module.h> diff --git a/drivers/mtd/maps/h720x-flash.c b/drivers/mtd/maps/h720x-flash.c index 6dde3182d64a..35fef655ccc4 100644 --- a/drivers/mtd/maps/h720x-flash.c +++ b/drivers/mtd/maps/h720x-flash.c @@ -2,8 +2,6 @@ * Flash memory access on Hynix GMS30C7201/HMS30C7202 based * evaluation boards * - * $Id: h720x-flash.c,v 1.12 2005/11/07 11:14:27 gleixner Exp $ - * * (C) 2002 Jungjun Kim <jungjun.kim@hynix.com> * 2003 Thomas Gleixner <tglx@linutronix.de> */ @@ -18,7 +16,7 @@ #include <linux/mtd/mtd.h> #include <linux/mtd/map.h> #include <linux/mtd/partitions.h> -#include <asm/hardware.h> +#include <mach/hardware.h> #include <asm/io.h> static struct mtd_info *mymtd; diff --git a/drivers/mtd/maps/ichxrom.c b/drivers/mtd/maps/ichxrom.c index 2c884c49e84a..aeb6c916e23f 100644 --- a/drivers/mtd/maps/ichxrom.c +++ b/drivers/mtd/maps/ichxrom.c @@ -2,7 +2,6 @@ * ichxrom.c * * Normal mappings of chips in physical memory - * $Id: ichxrom.c,v 1.19 2005/11/07 11:14:27 gleixner Exp $ */ #include <linux/module.h> diff --git a/drivers/mtd/maps/impa7.c b/drivers/mtd/maps/impa7.c index a0b4dc7155dc..2682ab51a367 100644 --- a/drivers/mtd/maps/impa7.c +++ b/drivers/mtd/maps/impa7.c @@ -1,6 +1,4 @@ /* - * $Id: impa7.c,v 1.14 2005/11/07 11:14:27 gleixner Exp $ - * * Handle mapping of the NOR flash on implementa A7 boards * * Copyright 2002 SYSGO Real-Time Solutions GmbH diff --git a/drivers/mtd/maps/integrator-flash.c b/drivers/mtd/maps/integrator-flash.c index 325c8880c437..7100ee3c7b01 100644 --- a/drivers/mtd/maps/integrator-flash.c +++ b/drivers/mtd/maps/integrator-flash.c @@ -22,8 +22,6 @@ This is access code for flashes using ARM's flash partitioning standards. - $Id: integrator-flash.c,v 1.20 2005/11/07 11:14:27 gleixner Exp $ - ======================================================================*/ #include <linux/module.h> @@ -39,7 +37,7 @@ #include <linux/mtd/partitions.h> #include <asm/mach/flash.h> -#include <asm/hardware.h> +#include <mach/hardware.h> #include <asm/io.h> #include <asm/system.h> diff --git a/drivers/mtd/maps/ipaq-flash.c b/drivers/mtd/maps/ipaq-flash.c index f27c132794c3..ed58f6a77bd9 100644 --- a/drivers/mtd/maps/ipaq-flash.c +++ b/drivers/mtd/maps/ipaq-flash.c @@ -4,8 +4,6 @@ * (C) 2000 Nicolas Pitre <nico@cam.org> * (C) 2002 Hewlett-Packard Company <jamey.hicks@hp.com> * (C) 2003 Christian Pellegrin <chri@ascensit.com>, <chri@infis.univ.ts.it>: concatenation of multiple flashes - * - * $Id: ipaq-flash.c,v 1.5 2005/11/07 11:14:27 gleixner Exp $ */ #include <linux/module.h> @@ -26,8 +24,8 @@ #include <linux/mtd/concat.h> #endif -#include <asm/hardware.h> -#include <asm/arch-sa1100/h3600.h> +#include <mach/hardware.h> +#include <mach/h3600.h> #include <asm/io.h> diff --git a/drivers/mtd/maps/ixp2000.c b/drivers/mtd/maps/ixp2000.c index c8396b8574c4..dcdb1f17577d 100644 --- a/drivers/mtd/maps/ixp2000.c +++ b/drivers/mtd/maps/ixp2000.c @@ -1,6 +1,4 @@ /* - * $Id: ixp2000.c,v 1.9 2005/11/07 11:14:27 gleixner Exp $ - * * drivers/mtd/maps/ixp2000.c * * Mapping for the Intel XScale IXP2000 based systems @@ -32,7 +30,7 @@ #include <linux/mtd/partitions.h> #include <asm/io.h> -#include <asm/hardware.h> +#include <mach/hardware.h> #include <asm/mach/flash.h> #include <linux/reboot.h> diff --git a/drivers/mtd/maps/ixp4xx.c b/drivers/mtd/maps/ixp4xx.c index 01f19a4714b5..9c7a5fbd4e51 100644 --- a/drivers/mtd/maps/ixp4xx.c +++ b/drivers/mtd/maps/ixp4xx.c @@ -1,6 +1,4 @@ /* - * $Id: ixp4xx.c,v 1.13 2005/11/16 16:23:21 dvrabel Exp $ - * * drivers/mtd/maps/ixp4xx.c * * MTD Map file for IXP4XX based systems. Please do not make per-board diff --git a/drivers/mtd/maps/l440gx.c b/drivers/mtd/maps/l440gx.c index 67620adf4811..9e054503c4cf 100644 --- a/drivers/mtd/maps/l440gx.c +++ b/drivers/mtd/maps/l440gx.c @@ -1,6 +1,4 @@ /* - * $Id: l440gx.c,v 1.18 2005/11/07 11:14:27 gleixner Exp $ - * * BIOS Flash chip on Intel 440GX board. * * Bugs this currently does not work under linuxBIOS. diff --git a/drivers/mtd/maps/map_funcs.c b/drivers/mtd/maps/map_funcs.c index 9105e6ca0aa6..3f268370eeca 100644 --- a/drivers/mtd/maps/map_funcs.c +++ b/drivers/mtd/maps/map_funcs.c @@ -1,6 +1,4 @@ /* - * $Id: map_funcs.c,v 1.10 2005/06/06 23:04:36 tpoynor Exp $ - * * Out-of-line map I/O functions for simple maps when CONFIG_COMPLEX_MAPPINGS * is enabled. */ diff --git a/drivers/mtd/maps/mbx860.c b/drivers/mtd/maps/mbx860.c index 06b118727846..706f67394b07 100644 --- a/drivers/mtd/maps/mbx860.c +++ b/drivers/mtd/maps/mbx860.c @@ -1,6 +1,4 @@ /* - * $Id: mbx860.c,v 1.9 2005/11/07 11:14:27 gleixner Exp $ - * * Handle mapping of the flash on MBX860 boards * * Author: Anton Todorov diff --git a/drivers/mtd/maps/netsc520.c b/drivers/mtd/maps/netsc520.c index 95dcab2146ad..c0cb319b2b70 100644 --- a/drivers/mtd/maps/netsc520.c +++ b/drivers/mtd/maps/netsc520.c @@ -3,8 +3,6 @@ * Copyright (C) 2001 Mark Langsdorf (mark.langsdorf@amd.com) * based on sc520cdp.c by Sysgo Real-Time Solutions GmbH * - * $Id: netsc520.c,v 1.14 2005/11/07 11:14: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 diff --git a/drivers/mtd/maps/nettel.c b/drivers/mtd/maps/nettel.c index 0c9b305a72e0..965e6c6d6ab0 100644 --- a/drivers/mtd/maps/nettel.c +++ b/drivers/mtd/maps/nettel.c @@ -5,8 +5,6 @@ * * (C) Copyright 2000-2001, Greg Ungerer (gerg@snapgear.com) * (C) Copyright 2001-2002, SnapGear (www.snapgear.com) - * - * $Id: nettel.c,v 1.12 2005/11/29 14:30:00 gleixner Exp $ */ /****************************************************************************/ diff --git a/drivers/mtd/maps/octagon-5066.c b/drivers/mtd/maps/octagon-5066.c index a6642db3d325..43e04c1d22a9 100644 --- a/drivers/mtd/maps/octagon-5066.c +++ b/drivers/mtd/maps/octagon-5066.c @@ -1,4 +1,3 @@ -// $Id: octagon-5066.c,v 1.28 2005/11/07 11:14:27 gleixner Exp $ /* ###################################################################### Octagon 5066 MTD Driver. diff --git a/drivers/mtd/maps/omap-toto-flash.c b/drivers/mtd/maps/omap-toto-flash.c index e6e391efbeb6..0a60ebbc2175 100644 --- a/drivers/mtd/maps/omap-toto-flash.c +++ b/drivers/mtd/maps/omap-toto-flash.c @@ -4,8 +4,6 @@ * jzhang@ti.com (C) 2003 Texas Instruments. * * (C) 2002 MontVista Software, Inc. - * - * $Id: omap-toto-flash.c,v 1.5 2005/11/07 11:14:27 gleixner Exp $ */ #include <linux/module.h> diff --git a/drivers/mtd/maps/omap_nor.c b/drivers/mtd/maps/omap_nor.c index 68eec6c6c517..05f276af15da 100644 --- a/drivers/mtd/maps/omap_nor.c +++ b/drivers/mtd/maps/omap_nor.c @@ -43,9 +43,9 @@ #include <linux/mtd/partitions.h> #include <asm/io.h> -#include <asm/hardware.h> +#include <mach/hardware.h> #include <asm/mach/flash.h> -#include <asm/arch/tc.h> +#include <mach/tc.h> #ifdef CONFIG_MTD_PARTITIONS static const char *part_probes[] = { /* "RedBoot", */ "cmdlinepart", NULL }; diff --git a/drivers/mtd/maps/pci.c b/drivers/mtd/maps/pci.c index d2ab1bae9c34..5c6a25c90380 100644 --- a/drivers/mtd/maps/pci.c +++ b/drivers/mtd/maps/pci.c @@ -7,8 +7,6 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * - * $Id: pci.c,v 1.14 2005/11/17 08:20:27 dwmw2 Exp $ - * * Generic PCI memory map driver. We support the following boards: * - Intel IQ80310 ATU. * - Intel EBSA285 (blank rom programming mode). Tested working 27/09/2001 diff --git a/drivers/mtd/maps/pcmciamtd.c b/drivers/mtd/maps/pcmciamtd.c index 0cc31675aeb9..90924fb00481 100644 --- a/drivers/mtd/maps/pcmciamtd.c +++ b/drivers/mtd/maps/pcmciamtd.c @@ -1,6 +1,4 @@ /* - * $Id: pcmciamtd.c,v 1.55 2005/11/07 11:14:28 gleixner Exp $ - * * pcmciamtd.c - MTD driver for PCMCIA flash memory cards * * Author: Simon Evans <spse@secret.org.uk> @@ -48,7 +46,6 @@ static const int debug = 0; #define DRIVER_DESC "PCMCIA Flash memory card driver" -#define DRIVER_VERSION "$Revision: 1.55 $" /* Size of the PCMCIA address space: 26 bits = 64 MB */ #define MAX_PCMCIA_ADDR 0x4000000 @@ -785,7 +782,7 @@ static struct pcmcia_driver pcmciamtd_driver = { static int __init init_pcmciamtd(void) { - info(DRIVER_DESC " " DRIVER_VERSION); + info(DRIVER_DESC); if(bankwidth && bankwidth != 1 && bankwidth != 2) { info("bad bankwidth (%d), using default", bankwidth); diff --git a/drivers/mtd/maps/physmap.c b/drivers/mtd/maps/physmap.c index 183255fcfdcb..42d844f8f6bf 100644 --- a/drivers/mtd/maps/physmap.c +++ b/drivers/mtd/maps/physmap.c @@ -1,6 +1,4 @@ /* - * $Id: physmap.c,v 1.39 2005/11/29 14:49:36 gleixner Exp $ - * * Normal mappings of chips in physical memory * * Copyright (C) 2003 MontaVista Software Inc. @@ -203,7 +201,19 @@ static int physmap_flash_suspend(struct platform_device *dev, pm_message_t state int i; for (i = 0; i < MAX_RESOURCES && info->mtd[i]; i++) - ret |= info->mtd[i]->suspend(info->mtd[i]); + if (info->mtd[i]->suspend) { + ret = info->mtd[i]->suspend(info->mtd[i]); + if (ret) + goto fail; + } + + return 0; +fail: + for (--i; i >= 0; --i) + if (info->mtd[i]->suspend) { + BUG_ON(!info->mtd[i]->resume); + info->mtd[i]->resume(info->mtd[i]); + } return ret; } @@ -214,7 +224,8 @@ static int physmap_flash_resume(struct platform_device *dev) int i; for (i = 0; i < MAX_RESOURCES && info->mtd[i]; i++) - info->mtd[i]->resume(info->mtd[i]); + if (info->mtd[i]->resume) + info->mtd[i]->resume(info->mtd[i]); return 0; } @@ -225,8 +236,9 @@ static void physmap_flash_shutdown(struct platform_device *dev) int i; for (i = 0; i < MAX_RESOURCES && info->mtd[i]; i++) - if (info->mtd[i]->suspend(info->mtd[i]) == 0) - info->mtd[i]->resume(info->mtd[i]); + if (info->mtd[i]->suspend && info->mtd[i]->resume) + if (info->mtd[i]->suspend(info->mtd[i]) == 0) + info->mtd[i]->resume(info->mtd[i]); } #else #define physmap_flash_suspend NULL diff --git a/drivers/mtd/maps/plat-ram.c b/drivers/mtd/maps/plat-ram.c index 3eb2643b2328..e7dd9c8a965e 100644 --- a/drivers/mtd/maps/plat-ram.c +++ b/drivers/mtd/maps/plat-ram.c @@ -6,8 +6,6 @@ * * Generic platfrom device based RAM map * - * $Id: plat-ram.c,v 1.7 2005/11/07 11:14:28 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 diff --git a/drivers/mtd/maps/pxa2xx-flash.c b/drivers/mtd/maps/pxa2xx-flash.c index 82113295c266..771139c5bf87 100644 --- a/drivers/mtd/maps/pxa2xx-flash.c +++ b/drivers/mtd/maps/pxa2xx-flash.c @@ -19,7 +19,7 @@ #include <linux/mtd/partitions.h> #include <asm/io.h> -#include <asm/hardware.h> +#include <mach/hardware.h> #include <asm/cacheflush.h> #include <asm/mach/flash.h> diff --git a/drivers/mtd/maps/redwood.c b/drivers/mtd/maps/redwood.c index 4d858b3d5f82..de002eb1a7fe 100644 --- a/drivers/mtd/maps/redwood.c +++ b/drivers/mtd/maps/redwood.c @@ -1,6 +1,4 @@ /* - * $Id: redwood.c,v 1.11 2005/11/07 11:14:28 gleixner Exp $ - * * drivers/mtd/maps/redwood.c * * FLASH map for the IBM Redwood 4/5/6 boards. diff --git a/drivers/mtd/maps/rpxlite.c b/drivers/mtd/maps/rpxlite.c index 809a0c8e7aaf..14d90edb4430 100644 --- a/drivers/mtd/maps/rpxlite.c +++ b/drivers/mtd/maps/rpxlite.c @@ -1,6 +1,4 @@ /* - * $Id: rpxlite.c,v 1.22 2004/11/04 13:24:15 gleixner Exp $ - * * Handle mapping of the flash on the RPX Lite and CLLF boards */ diff --git a/drivers/mtd/maps/sa1100-flash.c b/drivers/mtd/maps/sa1100-flash.c index c7d5a52a2d55..7df6bbf0e4d9 100644 --- a/drivers/mtd/maps/sa1100-flash.c +++ b/drivers/mtd/maps/sa1100-flash.c @@ -2,8 +2,6 @@ * Flash memory access on SA11x0 based devices * * (C) 2000 Nicolas Pitre <nico@cam.org> - * - * $Id: sa1100-flash.c,v 1.51 2005/11/07 11:14:28 gleixner Exp $ */ #include <linux/module.h> #include <linux/types.h> @@ -20,7 +18,7 @@ #include <linux/mtd/partitions.h> #include <linux/mtd/concat.h> -#include <asm/hardware.h> +#include <mach/hardware.h> #include <asm/io.h> #include <asm/sizes.h> #include <asm/mach/flash.h> diff --git a/drivers/mtd/maps/sbc8240.c b/drivers/mtd/maps/sbc8240.c index b8c1331b7a04..6e1e99cd2b59 100644 --- a/drivers/mtd/maps/sbc8240.c +++ b/drivers/mtd/maps/sbc8240.c @@ -4,9 +4,6 @@ * Carolyn Smith, Tektronix, Inc. * * This code is GPLed - * - * $Id: sbc8240.c,v 1.5 2005/11/07 11:14:28 gleixner Exp $ - * */ /* diff --git a/drivers/mtd/maps/sbc_gxx.c b/drivers/mtd/maps/sbc_gxx.c index 7cc4041d096d..1b1c0b7e11ef 100644 --- a/drivers/mtd/maps/sbc_gxx.c +++ b/drivers/mtd/maps/sbc_gxx.c @@ -17,8 +17,6 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - $Id: sbc_gxx.c,v 1.35 2005/11/07 11:14:28 gleixner Exp $ - The SBC-MediaGX / SBC-GXx has up to 16 MiB of Intel StrataFlash (28F320/28F640) in x8 mode. diff --git a/drivers/mtd/maps/sc520cdp.c b/drivers/mtd/maps/sc520cdp.c index 4045e372b90d..85c1e56309ec 100644 --- a/drivers/mtd/maps/sc520cdp.c +++ b/drivers/mtd/maps/sc520cdp.c @@ -16,8 +16,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: sc520cdp.c,v 1.23 2005/11/17 08:20:27 dwmw2 Exp $ - * * * The SC520CDP is an evaluation board for the Elan SC520 processor available * from AMD. It has two banks of 32-bit Flash ROM, each 8 Megabytes in size, diff --git a/drivers/mtd/maps/scb2_flash.c b/drivers/mtd/maps/scb2_flash.c index 0fc5584324e3..21169e6d646c 100644 --- a/drivers/mtd/maps/scb2_flash.c +++ b/drivers/mtd/maps/scb2_flash.c @@ -1,6 +1,5 @@ /* * MTD map driver for BIOS Flash on Intel SCB2 boards - * $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> * diff --git a/drivers/mtd/maps/scx200_docflash.c b/drivers/mtd/maps/scx200_docflash.c index 5e2bce22f37c..b5391ebb736e 100644 --- a/drivers/mtd/maps/scx200_docflash.c +++ b/drivers/mtd/maps/scx200_docflash.c @@ -2,8 +2,6 @@ Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com> - $Id: scx200_docflash.c,v 1.12 2005/11/07 11:14:28 gleixner Exp $ - National Semiconductor SCx200 flash mapped with DOCCS */ diff --git a/drivers/mtd/maps/sharpsl-flash.c b/drivers/mtd/maps/sharpsl-flash.c index 917dc778f24e..026eab028189 100644 --- a/drivers/mtd/maps/sharpsl-flash.c +++ b/drivers/mtd/maps/sharpsl-flash.c @@ -4,8 +4,6 @@ * Copyright (C) 2001 Lineo Japan, Inc. * Copyright (C) 2002 SHARP * - * $Id: sharpsl-flash.c,v 1.7 2005/11/07 11:14:28 gleixner 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 * diff --git a/drivers/mtd/maps/solutionengine.c b/drivers/mtd/maps/solutionengine.c index d76ceef453ce..0eb41d9c6786 100644 --- a/drivers/mtd/maps/solutionengine.c +++ b/drivers/mtd/maps/solutionengine.c @@ -1,6 +1,4 @@ /* - * $Id: solutionengine.c,v 1.15 2005/11/07 11:14:28 gleixner Exp $ - * * Flash and EPROM on Hitachi Solution Engine and similar boards. * * (C) 2001 Red Hat, Inc. diff --git a/drivers/mtd/maps/sun_uflash.c b/drivers/mtd/maps/sun_uflash.c index 001af7f7ddda..fd7a1017399a 100644 --- a/drivers/mtd/maps/sun_uflash.c +++ b/drivers/mtd/maps/sun_uflash.c @@ -1,13 +1,10 @@ -/* $Id: sun_uflash.c,v 1.13 2005/11/07 11:14:28 gleixner Exp $ - * - * sun_uflash - Driver implementation for user-programmable flash - * present on many Sun Microsystems SME boardsets. +/* sun_uflash.c - Driver for user-programmable flash on + * Sun Microsystems SME boardsets. * * This driver does NOT provide access to the OBP-flash for * safety reasons-- use <linux>/drivers/sbus/char/flash.c instead. * * Copyright (c) 2001 Eric Brower (ebrower@usa.net) - * */ #include <linux/kernel.h> @@ -16,8 +13,8 @@ #include <linux/errno.h> #include <linux/init.h> #include <linux/ioport.h> -#include <asm/ebus.h> -#include <asm/oplib.h> +#include <linux/of.h> +#include <linux/of_device.h> #include <asm/prom.h> #include <asm/uaccess.h> #include <asm/io.h> @@ -26,67 +23,65 @@ #include <linux/mtd/map.h> #define UFLASH_OBPNAME "flashprom" -#define UFLASH_DEVNAME "userflash" +#define DRIVER_NAME "sun_uflash" +#define PFX DRIVER_NAME ": " #define UFLASH_WINDOW_SIZE 0x200000 #define UFLASH_BUSWIDTH 1 /* EBus is 8-bit */ MODULE_AUTHOR("Eric Brower <ebrower@usa.net>"); MODULE_DESCRIPTION("User-programmable flash device on Sun Microsystems boardsets"); -MODULE_SUPPORTED_DEVICE("userflash"); +MODULE_SUPPORTED_DEVICE(DRIVER_NAME); MODULE_LICENSE("GPL"); -MODULE_VERSION("2.0"); +MODULE_VERSION("2.1"); -static LIST_HEAD(device_list); struct uflash_dev { const char *name; /* device name */ struct map_info map; /* mtd map info */ struct mtd_info *mtd; /* mtd info */ }; - struct map_info uflash_map_templ = { .name = "SUNW,???-????", .size = UFLASH_WINDOW_SIZE, .bankwidth = UFLASH_BUSWIDTH, }; -int uflash_devinit(struct linux_ebus_device *edev, struct device_node *dp) +int uflash_devinit(struct of_device *op, struct device_node *dp) { struct uflash_dev *up; - struct resource *res; - res = &edev->resource[0]; - - if (edev->num_addrs != 1) { + if (op->resource[1].flags) { /* Non-CFI userflash device-- once I find one we * can work on supporting it. */ - printk("%s: unsupported device at 0x%llx (%d regs): " \ - "email ebrower@usa.net\n", - dp->full_name, (unsigned long long)res->start, - edev->num_addrs); + printk(KERN_ERR PFX "Unsupported device at %s, 0x%llx\n", + dp->full_name, (unsigned long long)op->resource[0].start); return -ENODEV; } up = kzalloc(sizeof(struct uflash_dev), GFP_KERNEL); - if (!up) + if (!up) { + printk(KERN_ERR PFX "Cannot allocate struct uflash_dev\n"); return -ENOMEM; + } /* copy defaults and tweak parameters */ memcpy(&up->map, &uflash_map_templ, sizeof(uflash_map_templ)); - up->map.size = (res->end - res->start) + 1UL; + + up->map.size = resource_size(&op->resource[0]); up->name = of_get_property(dp, "model", NULL); if (up->name && 0 < strlen(up->name)) up->map.name = (char *)up->name; - up->map.phys = res->start; + up->map.phys = op->resource[0].start; - up->map.virt = ioremap_nocache(res->start, up->map.size); + up->map.virt = of_ioremap(&op->resource[0], 0, up->map.size, + DRIVER_NAME); if (!up->map.virt) { - printk("%s: Failed to map device.\n", dp->full_name); + printk(KERN_ERR PFX "Failed to map device.\n"); kfree(up); return -EINVAL; @@ -97,7 +92,7 @@ int uflash_devinit(struct linux_ebus_device *edev, struct device_node *dp) /* MTD registration */ up->mtd = do_map_probe("cfi_probe", &up->map); if (!up->mtd) { - iounmap(up->map.virt); + of_iounmap(&op->resource[0], up->map.virt, up->map.size); kfree(up); return -ENXIO; @@ -107,32 +102,34 @@ int uflash_devinit(struct linux_ebus_device *edev, struct device_node *dp) add_mtd_device(up->mtd); - dev_set_drvdata(&edev->ofdev.dev, up); + dev_set_drvdata(&op->dev, up); return 0; } -static int __devinit uflash_probe(struct of_device *dev, const struct of_device_id *match) +static int __devinit uflash_probe(struct of_device *op, const struct of_device_id *match) { - struct linux_ebus_device *edev = to_ebus_device(&dev->dev); - struct device_node *dp = dev->node; + struct device_node *dp = op->node; - if (of_find_property(dp, "user", NULL)) + /* Flashprom must have the "user" property in order to + * be used by this driver. + */ + if (!of_find_property(dp, "user", NULL)) return -ENODEV; - return uflash_devinit(edev, dp); + return uflash_devinit(op, dp); } -static int __devexit uflash_remove(struct of_device *dev) +static int __devexit uflash_remove(struct of_device *op) { - struct uflash_dev *up = dev_get_drvdata(&dev->dev); + struct uflash_dev *up = dev_get_drvdata(&op->dev); if (up->mtd) { del_mtd_device(up->mtd); map_destroy(up->mtd); } if (up->map.virt) { - iounmap(up->map.virt); + of_iounmap(&op->resource[0], up->map.virt, up->map.size); up->map.virt = NULL; } @@ -141,7 +138,7 @@ static int __devexit uflash_remove(struct of_device *dev) return 0; } -static struct of_device_id uflash_match[] = { +static const struct of_device_id uflash_match[] = { { .name = UFLASH_OBPNAME, }, @@ -151,7 +148,7 @@ static struct of_device_id uflash_match[] = { MODULE_DEVICE_TABLE(of, uflash_match); static struct of_platform_driver uflash_driver = { - .name = UFLASH_DEVNAME, + .name = DRIVER_NAME, .match_table = uflash_match, .probe = uflash_probe, .remove = __devexit_p(uflash_remove), @@ -159,7 +156,7 @@ static struct of_platform_driver uflash_driver = { static int __init uflash_init(void) { - return of_register_driver(&uflash_driver, &ebus_bus_type); + return of_register_driver(&uflash_driver, &of_bus_type); } static void __exit uflash_exit(void) diff --git a/drivers/mtd/maps/tqm8xxl.c b/drivers/mtd/maps/tqm8xxl.c index 521734057314..a5d3d8531faa 100644 --- a/drivers/mtd/maps/tqm8xxl.c +++ b/drivers/mtd/maps/tqm8xxl.c @@ -2,8 +2,6 @@ * Handle mapping of the flash memory access routines * on TQM8xxL based devices. * - * $Id: tqm8xxl.c,v 1.15 2005/11/07 11:14:28 gleixner Exp $ - * * based on rpxlite.c * * Copyright(C) 2001 Kirk Lee <kirk@hpc.ee.ntu.edu.tw> diff --git a/drivers/mtd/maps/ts5500_flash.c b/drivers/mtd/maps/ts5500_flash.c index b47270e850bc..e2147bf11c88 100644 --- a/drivers/mtd/maps/ts5500_flash.c +++ b/drivers/mtd/maps/ts5500_flash.c @@ -22,8 +22,6 @@ * - Drive A and B use the resident flash disk (RFD) flash translation layer. * - If you have created your own jffs file system and the bios overwrites * it during boot, try disabling Drive A: and B: in the boot order. - * - * $Id: ts5500_flash.c,v 1.5 2005/11/07 11:14:28 gleixner Exp $ */ #include <linux/init.h> diff --git a/drivers/mtd/maps/tsunami_flash.c b/drivers/mtd/maps/tsunami_flash.c index 0f915ac3102e..77a8bfc02577 100644 --- a/drivers/mtd/maps/tsunami_flash.c +++ b/drivers/mtd/maps/tsunami_flash.c @@ -2,7 +2,6 @@ * tsunami_flash.c * * flash chip on alpha ds10... - * $Id: tsunami_flash.c,v 1.10 2005/11/07 11:14:29 gleixner Exp $ */ #include <asm/io.h> #include <asm/core_tsunami.h> diff --git a/drivers/mtd/maps/uclinux.c b/drivers/mtd/maps/uclinux.c index 3fcf92130aa4..0dc645f8152f 100644 --- a/drivers/mtd/maps/uclinux.c +++ b/drivers/mtd/maps/uclinux.c @@ -4,8 +4,6 @@ * uclinux.c -- generic memory mapped MTD driver for uclinux * * (C) Copyright 2002, Greg Ungerer (gerg@snapgear.com) - * - * $Id: uclinux.c,v 1.12 2005/11/07 11:14:29 gleixner Exp $ */ /****************************************************************************/ diff --git a/drivers/mtd/maps/vmax301.c b/drivers/mtd/maps/vmax301.c index b3e487395435..5a0c9a353b0f 100644 --- a/drivers/mtd/maps/vmax301.c +++ b/drivers/mtd/maps/vmax301.c @@ -1,4 +1,3 @@ -// $Id: vmax301.c,v 1.32 2005/11/07 11:14:29 gleixner Exp $ /* ###################################################################### Tempustech VMAX SBC301 MTD Driver. diff --git a/drivers/mtd/maps/walnut.c b/drivers/mtd/maps/walnut.c index ca932122fb64..e243476c8171 100644 --- a/drivers/mtd/maps/walnut.c +++ b/drivers/mtd/maps/walnut.c @@ -1,6 +1,4 @@ /* - * $Id: walnut.c,v 1.3 2005/11/07 11:14:29 gleixner Exp $ - * * Mapping for Walnut flash * (used ebony.c as a "framework") * diff --git a/drivers/mtd/maps/wr_sbc82xx_flash.c b/drivers/mtd/maps/wr_sbc82xx_flash.c index ac5b8105b6ef..413b0cf9bbd2 100644 --- a/drivers/mtd/maps/wr_sbc82xx_flash.c +++ b/drivers/mtd/maps/wr_sbc82xx_flash.c @@ -1,6 +1,4 @@ /* - * $Id: wr_sbc82xx_flash.c,v 1.8 2005/11/07 11:14:29 gleixner Exp $ - * * Map for flash chips on Wind River PowerQUICC II SBC82xx board. * * Copyright (C) 2004 Red Hat, Inc. diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c index 839eed8430a2..681d5aca2af4 100644 --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c @@ -1,6 +1,4 @@ /* - * $Id: mtd_blkdevs.c,v 1.27 2005/11/07 11:14:20 gleixner Exp $ - * * (C) 2003 David Woodhouse <dwmw2@infradead.org> * * Interface to Linux 2.5 block layer for MTD 'translation layers'. @@ -34,6 +32,14 @@ struct mtd_blkcore_priv { spinlock_t queue_lock; }; +static int blktrans_discard_request(struct request_queue *q, + struct request *req) +{ + req->cmd_type = REQ_TYPE_LINUX_BLOCK; + req->cmd[0] = REQ_LB_OP_DISCARD; + return 0; +} + static int do_blktrans_request(struct mtd_blktrans_ops *tr, struct mtd_blktrans_dev *dev, struct request *req) @@ -46,6 +52,10 @@ static int do_blktrans_request(struct mtd_blktrans_ops *tr, buf = req->buffer; + if (req->cmd_type == REQ_TYPE_LINUX_BLOCK && + req->cmd[0] == REQ_LB_OP_DISCARD) + return !tr->discard(dev, block, nsect); + if (!blk_fs_request(req)) return 0; @@ -212,7 +222,7 @@ static struct block_device_operations mtd_blktrans_ops = { int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) { struct mtd_blktrans_ops *tr = new->tr; - struct list_head *this; + struct mtd_blktrans_dev *d; int last_devnum = -1; struct gendisk *gd; @@ -221,8 +231,7 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) BUG(); } - list_for_each(this, &tr->devs) { - struct mtd_blktrans_dev *d = list_entry(this, struct mtd_blktrans_dev, list); + list_for_each_entry(d, &tr->devs, list) { if (new->devnum == -1) { /* Use first free number */ if (d->devnum != last_devnum+1) { @@ -309,33 +318,24 @@ int del_mtd_blktrans_dev(struct mtd_blktrans_dev *old) static void blktrans_notify_remove(struct mtd_info *mtd) { - struct list_head *this, *this2, *next; - - list_for_each(this, &blktrans_majors) { - struct mtd_blktrans_ops *tr = list_entry(this, struct mtd_blktrans_ops, list); - - list_for_each_safe(this2, next, &tr->devs) { - struct mtd_blktrans_dev *dev = list_entry(this2, struct mtd_blktrans_dev, list); + struct mtd_blktrans_ops *tr; + struct mtd_blktrans_dev *dev, *next; + list_for_each_entry(tr, &blktrans_majors, list) + list_for_each_entry_safe(dev, next, &tr->devs, list) if (dev->mtd == mtd) tr->remove_dev(dev); - } - } } static void blktrans_notify_add(struct mtd_info *mtd) { - struct list_head *this; + struct mtd_blktrans_ops *tr; if (mtd->type == MTD_ABSENT) return; - list_for_each(this, &blktrans_majors) { - struct mtd_blktrans_ops *tr = list_entry(this, struct mtd_blktrans_ops, list); - + list_for_each_entry(tr, &blktrans_majors, list) tr->add_mtd(tr, mtd); - } - } static struct mtd_notifier blktrans_notifier = { @@ -379,6 +379,10 @@ int register_mtd_blktrans(struct mtd_blktrans_ops *tr) tr->blkcore_priv->rq->queuedata = tr; blk_queue_hardsect_size(tr->blkcore_priv->rq, tr->blksize); + if (tr->discard) + blk_queue_set_discard(tr->blkcore_priv->rq, + blktrans_discard_request); + tr->blkshift = ffs(tr->blksize) - 1; tr->blkcore_priv->thread = kthread_run(mtd_blktrans_thread, tr, @@ -406,7 +410,7 @@ int register_mtd_blktrans(struct mtd_blktrans_ops *tr) int deregister_mtd_blktrans(struct mtd_blktrans_ops *tr) { - struct list_head *this, *next; + struct mtd_blktrans_dev *dev, *next; mutex_lock(&mtd_table_mutex); @@ -416,10 +420,8 @@ int deregister_mtd_blktrans(struct mtd_blktrans_ops *tr) /* Remove it from the list of active majors */ list_del(&tr->list); - list_for_each_safe(this, next, &tr->devs) { - struct mtd_blktrans_dev *dev = list_entry(this, struct mtd_blktrans_dev, list); + list_for_each_entry_safe(dev, next, &tr->devs, list) tr->remove_dev(dev); - } blk_cleanup_queue(tr->blkcore_priv->rq); unregister_blkdev(tr->major, tr->name); diff --git a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c index 952da30b1745..208c6faa0358 100644 --- a/drivers/mtd/mtdblock.c +++ b/drivers/mtd/mtdblock.c @@ -1,8 +1,6 @@ /* * Direct MTD block device access * - * $Id: mtdblock.c,v 1.68 2005/11/07 11:14:20 gleixner Exp $ - * * (C) 2000-2003 Nicolas Pitre <nico@cam.org> * (C) 1999-2003 David Woodhouse <dwmw2@infradead.org> */ diff --git a/drivers/mtd/mtdblock_ro.c b/drivers/mtd/mtdblock_ro.c index f79dbb49b1a2..852165f8b1c3 100644 --- a/drivers/mtd/mtdblock_ro.c +++ b/drivers/mtd/mtdblock_ro.c @@ -1,6 +1,4 @@ /* - * $Id: mtdblock_ro.c,v 1.19 2004/11/16 18:28:59 dwmw2 Exp $ - * * (C) 2003 David Woodhouse <dwmw2@infradead.org> * * Simple read-only (writable only for RAM) mtdblock driver diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index aef9f4b687c9..e00d424e6575 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -1,6 +1,4 @@ /* - * $Id: mtdchar.c,v 1.76 2005/11/07 11:14:20 gleixner Exp $ - * * Character-device access to raw MTD devices. * */ @@ -412,16 +410,20 @@ static int mtd_ioctl(struct inode *inode, struct file *file, case MEMGETREGIONINFO: { - struct region_info_user ur; + uint32_t ur_idx; + struct mtd_erase_region_info *kr; + struct region_info_user *ur = (struct region_info_user *) argp; - if (copy_from_user(&ur, argp, sizeof(struct region_info_user))) + if (get_user(ur_idx, &(ur->regionindex))) return -EFAULT; - if (ur.regionindex >= mtd->numeraseregions) - return -EINVAL; - if (copy_to_user(argp, &(mtd->eraseregions[ur.regionindex]), - sizeof(struct mtd_erase_region_info))) + kr = &(mtd->eraseregions[ur_idx]); + + if (put_user(kr->offset, &(ur->offset)) + || put_user(kr->erasesize, &(ur->erasesize)) + || put_user(kr->numblocks, &(ur->numblocks))) return -EFAULT; + break; } @@ -494,6 +496,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file, { struct mtd_oob_buf buf; struct mtd_oob_ops ops; + struct mtd_oob_buf __user *user_buf = argp; uint32_t retlen; if(!(file->f_mode & 2)) @@ -537,8 +540,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file, if (ops.oobretlen > 0xFFFFFFFFU) ret = -EOVERFLOW; retlen = ops.oobretlen; - if (copy_to_user(&((struct mtd_oob_buf *)argp)->length, - &retlen, sizeof(buf.length))) + if (copy_to_user(&user_buf->length, &retlen, sizeof(buf.length))) ret = -EFAULT; kfree(ops.oobbuf); @@ -592,29 +594,29 @@ static int mtd_ioctl(struct inode *inode, struct file *file, case MEMLOCK: { - struct erase_info_user info; + struct erase_info_user einfo; - if (copy_from_user(&info, argp, sizeof(info))) + if (copy_from_user(&einfo, argp, sizeof(einfo))) return -EFAULT; if (!mtd->lock) ret = -EOPNOTSUPP; else - ret = mtd->lock(mtd, info.start, info.length); + ret = mtd->lock(mtd, einfo.start, einfo.length); break; } case MEMUNLOCK: { - struct erase_info_user info; + struct erase_info_user einfo; - if (copy_from_user(&info, argp, sizeof(info))) + if (copy_from_user(&einfo, argp, sizeof(einfo))) return -EFAULT; if (!mtd->unlock) ret = -EOPNOTSUPP; else - ret = mtd->unlock(mtd, info.start, info.length); + ret = mtd->unlock(mtd, einfo.start, einfo.length); break; } @@ -714,15 +716,15 @@ static int mtd_ioctl(struct inode *inode, struct file *file, case OTPLOCK: { - struct otp_info info; + struct otp_info oinfo; if (mfi->mode != MTD_MODE_OTP_USER) return -EINVAL; - if (copy_from_user(&info, argp, sizeof(info))) + if (copy_from_user(&oinfo, argp, sizeof(oinfo))) return -EFAULT; if (!mtd->lock_user_prot_reg) return -EOPNOTSUPP; - ret = mtd->lock_user_prot_reg(mtd, info.start, info.length); + ret = mtd->lock_user_prot_reg(mtd, oinfo.start, oinfo.length); break; } #endif diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c index d563dcd4b264..2972a5edb73d 100644 --- a/drivers/mtd/mtdconcat.c +++ b/drivers/mtd/mtdconcat.c @@ -6,8 +6,6 @@ * NAND support by Christian Gan <cgan@iders.ca> * * This code is GPL - * - * $Id: mtdconcat.c,v 1.11 2005/11/07 11:14:20 gleixner Exp $ */ #include <linux/kernel.h> diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index f7e7890e5bc6..a9d246949820 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -1,6 +1,4 @@ /* - * $Id: mtdcore.c,v 1.47 2005/11/07 11:14:20 gleixner Exp $ - * * Core registration and callback routines for MTD * drivers and users. * @@ -53,7 +51,7 @@ int add_mtd_device(struct mtd_info *mtd) for (i=0; i < MAX_MTD_DEVICES; i++) if (!mtd_table[i]) { - struct list_head *this; + struct mtd_notifier *not; mtd_table[i] = mtd; mtd->index = i; @@ -72,10 +70,8 @@ int add_mtd_device(struct mtd_info *mtd) DEBUG(0, "mtd: Giving out device %d to %s\n",i, mtd->name); /* No need to get a refcount on the module containing the notifier, since we hold the mtd_table_mutex */ - list_for_each(this, &mtd_notifiers) { - struct mtd_notifier *not = list_entry(this, struct mtd_notifier, list); + list_for_each_entry(not, &mtd_notifiers, list) not->add(mtd); - } mutex_unlock(&mtd_table_mutex); /* We _know_ we aren't being removed, because @@ -113,14 +109,12 @@ int del_mtd_device (struct mtd_info *mtd) mtd->index, mtd->name, mtd->usecount); ret = -EBUSY; } else { - struct list_head *this; + struct mtd_notifier *not; /* No need to get a refcount on the module containing the notifier, since we hold the mtd_table_mutex */ - list_for_each(this, &mtd_notifiers) { - struct mtd_notifier *not = list_entry(this, struct mtd_notifier, list); + list_for_each_entry(not, &mtd_notifiers, list) not->remove(mtd); - } mtd_table[mtd->index] = NULL; diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 07c701169344..edb90b58a9b1 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -5,8 +5,6 @@ * * This code is GPL * - * $Id: mtdpart.c,v 1.55 2005/11/07 11:14:20 gleixner Exp $ - * * 02-21-2002 Thomas Gleixner <gleixner@autronix.de> * added support for read_oob, write_oob */ @@ -46,8 +44,8 @@ struct mtd_part { * to the _real_ device. */ -static int part_read (struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, u_char *buf) +static int part_read(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf) { struct mtd_part *part = PART(mtd); int res; @@ -56,7 +54,7 @@ static int part_read (struct mtd_info *mtd, loff_t from, size_t len, len = 0; else if (from + len > mtd->size) len = mtd->size - from; - res = part->master->read (part->master, from + part->offset, + res = part->master->read(part->master, from + part->offset, len, retlen, buf); if (unlikely(res)) { if (res == -EUCLEAN) @@ -67,8 +65,8 @@ static int part_read (struct mtd_info *mtd, loff_t from, size_t len, return res; } -static int part_point (struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, void **virt, resource_size_t *phys) +static int part_point(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, void **virt, resource_size_t *phys) { struct mtd_part *part = PART(mtd); if (from >= mtd->size) @@ -87,7 +85,7 @@ static void part_unpoint(struct mtd_info *mtd, loff_t from, size_t len) } static int part_read_oob(struct mtd_info *mtd, loff_t from, - struct mtd_oob_ops *ops) + struct mtd_oob_ops *ops) { struct mtd_part *part = PART(mtd); int res; @@ -107,38 +105,38 @@ static int part_read_oob(struct mtd_info *mtd, loff_t from, return res; } -static int part_read_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, u_char *buf) +static int part_read_user_prot_reg(struct mtd_info *mtd, loff_t from, + size_t len, size_t *retlen, u_char *buf) { struct mtd_part *part = PART(mtd); - return part->master->read_user_prot_reg (part->master, from, + return part->master->read_user_prot_reg(part->master, from, len, retlen, buf); } -static int part_get_user_prot_info (struct mtd_info *mtd, - struct otp_info *buf, size_t len) +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); + 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) +static int part_read_fact_prot_reg(struct mtd_info *mtd, loff_t from, + size_t len, size_t *retlen, u_char *buf) { struct mtd_part *part = PART(mtd); - return part->master->read_fact_prot_reg (part->master, from, + return part->master->read_fact_prot_reg(part->master, from, len, retlen, buf); } -static int part_get_fact_prot_info (struct mtd_info *mtd, - struct otp_info *buf, size_t len) +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); + 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) +static int part_write(struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf) { struct mtd_part *part = PART(mtd); if (!(mtd->flags & MTD_WRITEABLE)) @@ -147,12 +145,12 @@ static int part_write (struct mtd_info *mtd, loff_t to, size_t len, len = 0; else if (to + len > mtd->size) len = mtd->size - to; - return part->master->write (part->master, to + part->offset, + return part->master->write(part->master, to + part->offset, len, retlen, buf); } -static int part_panic_write (struct mtd_info *mtd, loff_t to, size_t len, - size_t *retlen, const u_char *buf) +static int part_panic_write(struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf) { struct mtd_part *part = PART(mtd); if (!(mtd->flags & MTD_WRITEABLE)) @@ -161,12 +159,12 @@ static int part_panic_write (struct mtd_info *mtd, loff_t to, size_t len, len = 0; else if (to + len > mtd->size) len = mtd->size - to; - return part->master->panic_write (part->master, to + part->offset, + return part->master->panic_write(part->master, to + part->offset, len, retlen, buf); } static int part_write_oob(struct mtd_info *mtd, loff_t to, - struct mtd_oob_ops *ops) + struct mtd_oob_ops *ops) { struct mtd_part *part = PART(mtd); @@ -180,31 +178,32 @@ static int part_write_oob(struct mtd_info *mtd, loff_t to, return part->master->write_oob(part->master, to + part->offset, ops); } -static int part_write_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, u_char *buf) +static int part_write_user_prot_reg(struct mtd_info *mtd, loff_t from, + size_t len, size_t *retlen, u_char *buf) { struct mtd_part *part = PART(mtd); - return part->master->write_user_prot_reg (part->master, from, + return part->master->write_user_prot_reg(part->master, from, len, retlen, buf); } -static int part_lock_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len) +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); + 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) +static int part_writev(struct mtd_info *mtd, const struct kvec *vecs, + unsigned long count, loff_t to, size_t *retlen) { struct mtd_part *part = PART(mtd); if (!(mtd->flags & MTD_WRITEABLE)) return -EROFS; - return part->master->writev (part->master, vecs, count, + return part->master->writev(part->master, vecs, count, to + part->offset, retlen); } -static int part_erase (struct mtd_info *mtd, struct erase_info *instr) +static int part_erase(struct mtd_info *mtd, struct erase_info *instr) { struct mtd_part *part = PART(mtd); int ret; @@ -236,7 +235,7 @@ void mtd_erase_callback(struct erase_info *instr) } EXPORT_SYMBOL_GPL(mtd_erase_callback); -static int part_lock (struct mtd_info *mtd, loff_t ofs, size_t len) +static int part_lock(struct mtd_info *mtd, loff_t ofs, size_t len) { struct mtd_part *part = PART(mtd); if ((len + ofs) > mtd->size) @@ -244,7 +243,7 @@ static int part_lock (struct mtd_info *mtd, loff_t ofs, size_t len) return part->master->lock(part->master, ofs + part->offset, len); } -static int part_unlock (struct mtd_info *mtd, loff_t ofs, size_t len) +static int part_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) { struct mtd_part *part = PART(mtd); if ((len + ofs) > mtd->size) @@ -270,7 +269,7 @@ static void part_resume(struct mtd_info *mtd) part->master->resume(part->master); } -static int part_block_isbad (struct mtd_info *mtd, loff_t ofs) +static int part_block_isbad(struct mtd_info *mtd, loff_t ofs) { struct mtd_part *part = PART(mtd); if (ofs >= mtd->size) @@ -279,7 +278,7 @@ static int part_block_isbad (struct mtd_info *mtd, loff_t ofs) return part->master->block_isbad(part->master, ofs); } -static int part_block_markbad (struct mtd_info *mtd, loff_t ofs) +static int part_block_markbad(struct mtd_info *mtd, loff_t ofs) { struct mtd_part *part = PART(mtd); int res; @@ -302,229 +301,237 @@ static int part_block_markbad (struct mtd_info *mtd, loff_t ofs) int del_mtd_partitions(struct mtd_info *master) { - struct list_head *node; - struct mtd_part *slave; + struct mtd_part *slave, *next; - for (node = mtd_partitions.next; - node != &mtd_partitions; - node = node->next) { - slave = list_entry(node, struct mtd_part, list); + list_for_each_entry_safe(slave, next, &mtd_partitions, list) if (slave->master == master) { - struct list_head *prev = node->prev; - __list_del(prev, node->next); - if(slave->registered) + list_del(&slave->list); + if (slave->registered) del_mtd_device(&slave->mtd); kfree(slave); - node = prev; } - } return 0; } +EXPORT_SYMBOL(del_mtd_partitions); -/* - * This function, given a master MTD object and a partition table, creates - * and registers slave MTD objects which are bound to the master according to - * the partition definitions. - * (Q: should we register the master MTD object as well?) - */ - -int add_mtd_partitions(struct mtd_info *master, - const struct mtd_partition *parts, - int nbparts) +static struct mtd_part *add_one_partition(struct mtd_info *master, + const struct mtd_partition *part, int partno, + u_int32_t cur_offset) { struct mtd_part *slave; - u_int32_t cur_offset = 0; - int i; - - printk (KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nbparts, master->name); - - for (i = 0; i < nbparts; i++) { - /* allocate the partition structure */ - slave = kzalloc (sizeof(*slave), GFP_KERNEL); - if (!slave) { - printk ("memory allocation error while creating partitions for \"%s\"\n", - master->name); - del_mtd_partitions(master); - return -ENOMEM; - } - list_add(&slave->list, &mtd_partitions); + /* allocate the partition structure */ + slave = kzalloc(sizeof(*slave), GFP_KERNEL); + if (!slave) { + printk(KERN_ERR"memory allocation error while creating partitions for \"%s\"\n", + master->name); + del_mtd_partitions(master); + return NULL; + } + list_add(&slave->list, &mtd_partitions); - /* set up the MTD object for this partition */ - slave->mtd.type = master->type; - slave->mtd.flags = master->flags & ~parts[i].mask_flags; - slave->mtd.size = parts[i].size; - slave->mtd.writesize = master->writesize; - slave->mtd.oobsize = master->oobsize; - slave->mtd.oobavail = master->oobavail; - slave->mtd.subpage_sft = master->subpage_sft; + /* set up the MTD object for this partition */ + slave->mtd.type = master->type; + slave->mtd.flags = master->flags & ~part->mask_flags; + slave->mtd.size = part->size; + slave->mtd.writesize = master->writesize; + slave->mtd.oobsize = master->oobsize; + slave->mtd.oobavail = master->oobavail; + slave->mtd.subpage_sft = master->subpage_sft; - slave->mtd.name = parts[i].name; - slave->mtd.owner = master->owner; + slave->mtd.name = part->name; + slave->mtd.owner = master->owner; - slave->mtd.read = part_read; - slave->mtd.write = part_write; + slave->mtd.read = part_read; + slave->mtd.write = part_write; - if (master->panic_write) - slave->mtd.panic_write = part_panic_write; + if (master->panic_write) + slave->mtd.panic_write = part_panic_write; - if(master->point && master->unpoint){ - slave->mtd.point = part_point; - slave->mtd.unpoint = part_unpoint; - } + if (master->point && master->unpoint) { + slave->mtd.point = part_point; + slave->mtd.unpoint = part_unpoint; + } - if (master->read_oob) - slave->mtd.read_oob = part_read_oob; - if (master->write_oob) - slave->mtd.write_oob = part_write_oob; - if(master->read_user_prot_reg) - slave->mtd.read_user_prot_reg = part_read_user_prot_reg; - if(master->read_fact_prot_reg) - 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) { - slave->mtd.suspend = part_suspend; - slave->mtd.resume = part_resume; + if (master->read_oob) + slave->mtd.read_oob = part_read_oob; + if (master->write_oob) + slave->mtd.write_oob = part_write_oob; + if (master->read_user_prot_reg) + slave->mtd.read_user_prot_reg = part_read_user_prot_reg; + if (master->read_fact_prot_reg) + 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 (!partno && master->suspend && master->resume) { + slave->mtd.suspend = part_suspend; + slave->mtd.resume = part_resume; + } + if (master->writev) + slave->mtd.writev = part_writev; + if (master->lock) + slave->mtd.lock = part_lock; + if (master->unlock) + slave->mtd.unlock = part_unlock; + if (master->block_isbad) + slave->mtd.block_isbad = part_block_isbad; + if (master->block_markbad) + slave->mtd.block_markbad = part_block_markbad; + slave->mtd.erase = part_erase; + slave->master = master; + slave->offset = part->offset; + slave->index = partno; + + if (slave->offset == MTDPART_OFS_APPEND) + slave->offset = cur_offset; + if (slave->offset == MTDPART_OFS_NXTBLK) { + slave->offset = cur_offset; + if ((cur_offset % master->erasesize) != 0) { + /* Round up to next erasesize */ + slave->offset = ((cur_offset / master->erasesize) + 1) * master->erasesize; + printk(KERN_NOTICE "Moving partition %d: " + "0x%08x -> 0x%08x\n", partno, + cur_offset, slave->offset); } - if (master->writev) - slave->mtd.writev = part_writev; - if (master->lock) - slave->mtd.lock = part_lock; - if (master->unlock) - slave->mtd.unlock = part_unlock; - if (master->block_isbad) - slave->mtd.block_isbad = part_block_isbad; - if (master->block_markbad) - slave->mtd.block_markbad = part_block_markbad; - slave->mtd.erase = part_erase; - slave->master = master; - slave->offset = parts[i].offset; - slave->index = i; - - if (slave->offset == MTDPART_OFS_APPEND) - slave->offset = cur_offset; - if (slave->offset == MTDPART_OFS_NXTBLK) { - slave->offset = cur_offset; - if ((cur_offset % master->erasesize) != 0) { - /* Round up to next erasesize */ - slave->offset = ((cur_offset / master->erasesize) + 1) * master->erasesize; - printk(KERN_NOTICE "Moving partition %d: " - "0x%08x -> 0x%08x\n", i, - cur_offset, slave->offset); + } + if (slave->mtd.size == MTDPART_SIZ_FULL) + slave->mtd.size = master->size - slave->offset; + + printk(KERN_NOTICE "0x%08x-0x%08x : \"%s\"\n", slave->offset, + slave->offset + slave->mtd.size, slave->mtd.name); + + /* let's do some sanity checks */ + if (slave->offset >= master->size) { + /* let's register it anyway to preserve ordering */ + slave->offset = 0; + slave->mtd.size = 0; + printk(KERN_ERR"mtd: partition \"%s\" is out of reach -- disabled\n", + part->name); + goto out_register; + } + if (slave->offset + slave->mtd.size > master->size) { + slave->mtd.size = master->size - slave->offset; + printk(KERN_WARNING"mtd: partition \"%s\" extends beyond the end of device \"%s\" -- size truncated to %#x\n", + part->name, master->name, slave->mtd.size); + } + if (master->numeraseregions > 1) { + /* Deal with variable erase size stuff */ + int i, max = master->numeraseregions; + u32 end = slave->offset + slave->mtd.size; + struct mtd_erase_region_info *regions = master->eraseregions; + + /* Find the first erase regions which is part of this + * partition. */ + for (i = 0; i < max && regions[i].offset <= slave->offset; i++) + ; + /* The loop searched for the region _behind_ the first one */ + i--; + + /* Pick biggest erasesize */ + for (; i < max && regions[i].offset < end; i++) { + if (slave->mtd.erasesize < regions[i].erasesize) { + slave->mtd.erasesize = regions[i].erasesize; } } - if (slave->mtd.size == MTDPART_SIZ_FULL) - slave->mtd.size = master->size - slave->offset; - cur_offset = slave->offset + slave->mtd.size; + BUG_ON(slave->mtd.erasesize == 0); + } else { + /* Single erase size */ + slave->mtd.erasesize = master->erasesize; + } - printk (KERN_NOTICE "0x%08x-0x%08x : \"%s\"\n", slave->offset, - slave->offset + slave->mtd.size, slave->mtd.name); + if ((slave->mtd.flags & MTD_WRITEABLE) && + (slave->offset % slave->mtd.erasesize)) { + /* Doesn't start on a boundary of major erase size */ + /* FIXME: Let it be writable if it is on a boundary of + * _minor_ erase size though */ + slave->mtd.flags &= ~MTD_WRITEABLE; + printk(KERN_WARNING"mtd: partition \"%s\" doesn't start on an erase block boundary -- force read-only\n", + part->name); + } + if ((slave->mtd.flags & MTD_WRITEABLE) && + (slave->mtd.size % slave->mtd.erasesize)) { + slave->mtd.flags &= ~MTD_WRITEABLE; + printk(KERN_WARNING"mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n", + part->name); + } - /* let's do some sanity checks */ - if (slave->offset >= master->size) { - /* let's register it anyway to preserve ordering */ - slave->offset = 0; - slave->mtd.size = 0; - printk ("mtd: partition \"%s\" is out of reach -- disabled\n", - parts[i].name); - } - if (slave->offset + slave->mtd.size > master->size) { - slave->mtd.size = master->size - slave->offset; - printk ("mtd: partition \"%s\" extends beyond the end of device \"%s\" -- size truncated to %#x\n", - parts[i].name, master->name, slave->mtd.size); - } - if (master->numeraseregions>1) { - /* Deal with variable erase size stuff */ - int i; - struct mtd_erase_region_info *regions = master->eraseregions; - - /* Find the first erase regions which is part of this partition. */ - for (i=0; i < master->numeraseregions && slave->offset >= regions[i].offset; i++) - ; - - for (i--; i < master->numeraseregions && slave->offset + slave->mtd.size > regions[i].offset; i++) { - if (slave->mtd.erasesize < regions[i].erasesize) { - slave->mtd.erasesize = regions[i].erasesize; - } - } - } else { - /* Single erase size */ - slave->mtd.erasesize = master->erasesize; - } + slave->mtd.ecclayout = master->ecclayout; + if (master->block_isbad) { + uint32_t offs = 0; - if ((slave->mtd.flags & MTD_WRITEABLE) && - (slave->offset % slave->mtd.erasesize)) { - /* Doesn't start on a boundary of major erase size */ - /* FIXME: Let it be writable if it is on a boundary of _minor_ erase size though */ - slave->mtd.flags &= ~MTD_WRITEABLE; - printk ("mtd: partition \"%s\" doesn't start on an erase block boundary -- force read-only\n", - parts[i].name); - } - if ((slave->mtd.flags & MTD_WRITEABLE) && - (slave->mtd.size % slave->mtd.erasesize)) { - slave->mtd.flags &= ~MTD_WRITEABLE; - printk ("mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n", - parts[i].name); + while (offs < slave->mtd.size) { + if (master->block_isbad(master, + offs + slave->offset)) + slave->mtd.ecc_stats.badblocks++; + offs += slave->mtd.erasesize; } + } - slave->mtd.ecclayout = master->ecclayout; - if (master->block_isbad) { - uint32_t offs = 0; +out_register: + if (part->mtdp) { + /* store the object pointer (caller may or may not register it*/ + *part->mtdp = &slave->mtd; + slave->registered = 0; + } else { + /* register our partition */ + add_mtd_device(&slave->mtd); + slave->registered = 1; + } + return slave; +} - while(offs < slave->mtd.size) { - if (master->block_isbad(master, - offs + slave->offset)) - slave->mtd.ecc_stats.badblocks++; - offs += slave->mtd.erasesize; - } - } +/* + * This function, given a master MTD object and a partition table, creates + * and registers slave MTD objects which are bound to the master according to + * the partition definitions. + * (Q: should we register the master MTD object as well?) + */ - if(parts[i].mtdp) - { /* store the object pointer (caller may or may not register it */ - *parts[i].mtdp = &slave->mtd; - slave->registered = 0; - } - else - { - /* register our partition */ - add_mtd_device(&slave->mtd); - slave->registered = 1; - } +int add_mtd_partitions(struct mtd_info *master, + const struct mtd_partition *parts, + int nbparts) +{ + struct mtd_part *slave; + u_int32_t cur_offset = 0; + int i; + + printk(KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nbparts, master->name); + + for (i = 0; i < nbparts; i++) { + slave = add_one_partition(master, parts + i, i, cur_offset); + if (!slave) + return -ENOMEM; + cur_offset = slave->offset + slave->mtd.size; } return 0; } - EXPORT_SYMBOL(add_mtd_partitions); -EXPORT_SYMBOL(del_mtd_partitions); static DEFINE_SPINLOCK(part_parser_lock); static LIST_HEAD(part_parsers); static struct mtd_part_parser *get_partition_parser(const char *name) { - struct list_head *this; - void *ret = NULL; - spin_lock(&part_parser_lock); + struct mtd_part_parser *p, *ret = NULL; - list_for_each(this, &part_parsers) { - struct mtd_part_parser *p = list_entry(this, struct mtd_part_parser, list); + spin_lock(&part_parser_lock); + list_for_each_entry(p, &part_parsers, list) if (!strcmp(p->name, name) && try_module_get(p->owner)) { ret = p; break; } - } + spin_unlock(&part_parser_lock); return ret; @@ -538,6 +545,7 @@ int register_mtd_parser(struct mtd_part_parser *p) return 0; } +EXPORT_SYMBOL_GPL(register_mtd_parser); int deregister_mtd_parser(struct mtd_part_parser *p) { @@ -546,6 +554,7 @@ int deregister_mtd_parser(struct mtd_part_parser *p) spin_unlock(&part_parser_lock); return 0; } +EXPORT_SYMBOL_GPL(deregister_mtd_parser); int parse_mtd_partitions(struct mtd_info *master, const char **types, struct mtd_partition **pparts, unsigned long origin) @@ -573,7 +582,4 @@ int parse_mtd_partitions(struct mtd_info *master, const char **types, } return ret; } - EXPORT_SYMBOL_GPL(parse_mtd_partitions); -EXPORT_SYMBOL_GPL(register_mtd_parser); -EXPORT_SYMBOL_GPL(deregister_mtd_parser); diff --git a/drivers/mtd/mtdsuper.c b/drivers/mtd/mtdsuper.c index 28cc6787a800..00d46e137b2a 100644 --- a/drivers/mtd/mtdsuper.c +++ b/drivers/mtd/mtdsuper.c @@ -125,8 +125,11 @@ int get_sb_mtd(struct file_system_type *fs_type, int flags, int (*fill_super)(struct super_block *, void *, int), struct vfsmount *mnt) { - struct nameidata nd; - int mtdnr, ret; +#ifdef CONFIG_BLOCK + struct block_device *bdev; + int ret, major; +#endif + int mtdnr; if (!dev_name) return -EINVAL; @@ -178,45 +181,38 @@ int get_sb_mtd(struct file_system_type *fs_type, int flags, } } +#ifdef CONFIG_BLOCK /* try the old way - the hack where we allowed users to mount * /dev/mtdblock$(n) but didn't actually _use_ the blockdev */ - ret = path_lookup(dev_name, LOOKUP_FOLLOW, &nd); - - DEBUG(1, "MTDSB: path_lookup() returned %d, inode %p\n", - ret, nd.path.dentry ? nd.path.dentry->d_inode : NULL); - - if (ret) + bdev = lookup_bdev(dev_name); + if (IS_ERR(bdev)) { + ret = PTR_ERR(bdev); + DEBUG(1, "MTDSB: lookup_bdev() returned %d\n", ret); return ret; + } + DEBUG(1, "MTDSB: lookup_bdev() returned 0\n"); ret = -EINVAL; - if (!S_ISBLK(nd.path.dentry->d_inode->i_mode)) - goto out; - - if (nd.path.mnt->mnt_flags & MNT_NODEV) { - ret = -EACCES; - goto out; - } + major = MAJOR(bdev->bd_dev); + mtdnr = MINOR(bdev->bd_dev); + bdput(bdev); - if (imajor(nd.path.dentry->d_inode) != MTD_BLOCK_MAJOR) + if (major != MTD_BLOCK_MAJOR) goto not_an_MTD_device; - mtdnr = iminor(nd.path.dentry->d_inode); - path_put(&nd.path); - return get_sb_mtd_nr(fs_type, flags, dev_name, data, mtdnr, fill_super, mnt); not_an_MTD_device: +#endif /* CONFIG_BLOCK */ + if (!(flags & MS_SILENT)) printk(KERN_NOTICE "MTD: Attempt to mount non-MTD device \"%s\"\n", dev_name); -out: - path_put(&nd.path); - return ret; - + return -EINVAL; } EXPORT_SYMBOL_GPL(get_sb_mtd); diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 5076faf9ca66..41f361c49b32 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -1,5 +1,4 @@ # drivers/mtd/nand/Kconfig -# $Id: Kconfig,v 1.35 2005/11/07 11:14:30 gleixner Exp $ menuconfig MTD_NAND tristate "NAND Device Support" @@ -105,11 +104,24 @@ config MTD_NAND_BF5XX config MTD_NAND_BF5XX_HWECC bool "BF5XX NAND Hardware ECC" + default y depends on MTD_NAND_BF5XX help Enable the use of the BF5XX's internal ECC generator when using NAND. +config MTD_NAND_BF5XX_BOOTROM_ECC + bool "Use Blackfin BootROM ECC Layout" + default n + depends on MTD_NAND_BF5XX_HWECC + help + If you wish to modify NAND pages and allow the Blackfin on-chip + BootROM to boot from them, say Y here. This is only necessary + if you are booting U-Boot out of NAND and you wish to update + U-Boot from Linux' userspace. Otherwise, you should say N here. + + If unsure, say N. + config MTD_NAND_RTC_FROM4 tristate "Renesas Flash ROM 4-slot interface board (FROM_BOARD4)" depends on SH_SOLUTION_ENGINE @@ -272,22 +284,23 @@ config MTD_NAND_CS553X If you say "m", the module will be called "cs553x_nand.ko". -config MTD_NAND_AT91 - bool "Support for NAND Flash / SmartMedia on AT91" - depends on ARCH_AT91 +config MTD_NAND_ATMEL + tristate "Support for NAND Flash / SmartMedia on AT91 and AVR32" + depends on ARCH_AT91 || AVR32 help Enables support for NAND Flash / Smart Media Card interface - on Atmel AT91 processors. + on Atmel AT91 and AVR32 processors. choice - prompt "ECC management for NAND Flash / SmartMedia on AT91" - depends on MTD_NAND_AT91 + prompt "ECC management for NAND Flash / SmartMedia on AT91 / AVR32" + depends on MTD_NAND_ATMEL -config MTD_NAND_AT91_ECC_HW +config MTD_NAND_ATMEL_ECC_HW bool "Hardware ECC" - depends on ARCH_AT91SAM9263 || ARCH_AT91SAM9260 + depends on ARCH_AT91SAM9263 || ARCH_AT91SAM9260 || AVR32 help - Uses hardware ECC provided by the at91sam9260/at91sam9263 chip - instead of software ECC. + Use hardware ECC instead of software ECC when the chip + supports it. + The hardware ECC controller is capable of single bit error correction and 2-bit random detection per page. @@ -297,16 +310,16 @@ config MTD_NAND_AT91_ECC_HW If unsure, say Y -config MTD_NAND_AT91_ECC_SOFT +config MTD_NAND_ATMEL_ECC_SOFT bool "Software ECC" help - Uses software ECC. + Use software ECC. NB : hardware and software ECC schemes are incompatible. If you switch from one to another, you'll have to erase your mtd partition. -config MTD_NAND_AT91_ECC_NONE +config MTD_NAND_ATMEL_ECC_NONE bool "No ECC (testing only, DANGEROUS)" depends on DEBUG_KERNEL help @@ -338,6 +351,13 @@ config MTD_NAND_PASEMI Enables support for NAND Flash interface on PA Semi PWRficient based boards +config MTD_NAND_TMIO + tristate "NAND Flash device on Toshiba Mobile IO Controller" + depends on MTD_NAND && MFD_TMIO + help + Support for NAND flash connected to a Toshiba Mobile IO + Controller in some PDAs, including the Sharp SL6000x. + config MTD_NAND_NANDSIM tristate "Support for NAND Flash Simulator" depends on MTD_PARTITIONS diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index a6e74a46992a..b786c5da82da 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -1,7 +1,6 @@ # # linux/drivers/nand/Makefile # -# $Id: Makefile.common,v 1.15 2004/11/26 12:28:22 dedekind Exp $ obj-$(CONFIG_MTD_NAND) += nand.o nand_ecc.o obj-$(CONFIG_MTD_NAND_IDS) += nand_ids.o @@ -24,10 +23,11 @@ obj-$(CONFIG_MTD_NAND_TS7250) += ts7250.o obj-$(CONFIG_MTD_NAND_NANDSIM) += nandsim.o obj-$(CONFIG_MTD_NAND_CS553X) += cs553x_nand.o obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o -obj-$(CONFIG_MTD_NAND_AT91) += at91_nand.o +obj-$(CONFIG_MTD_NAND_ATMEL) += atmel_nand.o obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o obj-$(CONFIG_MTD_NAND_BASLER_EXCITE) += excite_nandflash.o obj-$(CONFIG_MTD_NAND_PXA3xx) += pxa3xx_nand.o +obj-$(CONFIG_MTD_NAND_TMIO) += tmio_nand.o obj-$(CONFIG_MTD_NAND_PLATFORM) += plat_nand.o obj-$(CONFIG_MTD_ALAUDA) += alauda.o obj-$(CONFIG_MTD_NAND_PASEMI) += pasemi_nand.o diff --git a/drivers/mtd/nand/ams-delta.c b/drivers/mtd/nand/ams-delta.c index a0ba07c36ee9..26d42987971f 100644 --- a/drivers/mtd/nand/ams-delta.c +++ b/drivers/mtd/nand/ams-delta.c @@ -22,10 +22,10 @@ #include <linux/mtd/nand.h> #include <linux/mtd/partitions.h> #include <asm/io.h> -#include <asm/arch/hardware.h> +#include <mach/hardware.h> #include <asm/sizes.h> -#include <asm/arch/gpio.h> -#include <asm/arch/board-ams-delta.h> +#include <mach/gpio.h> +#include <mach/board-ams-delta.h> /* * MTD structure for E3 (Delta) diff --git a/drivers/mtd/nand/at91_nand.c b/drivers/mtd/nand/atmel_nand.c index 0adb287027a2..3387e0d5076b 100644 --- a/drivers/mtd/nand/at91_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -1,6 +1,4 @@ /* - * drivers/mtd/nand/at91_nand.c - * * Copyright (C) 2003 Rick Bronson * * Derived from drivers/mtd/nand/autcpu12.c @@ -31,20 +29,19 @@ #include <linux/mtd/nand.h> #include <linux/mtd/partitions.h> -#include <asm/io.h> -#include <asm/sizes.h> +#include <linux/gpio.h> +#include <linux/io.h> -#include <asm/hardware.h> -#include <asm/arch/board.h> -#include <asm/arch/gpio.h> +#include <mach/board.h> +#include <mach/cpu.h> -#ifdef CONFIG_MTD_NAND_AT91_ECC_HW +#ifdef CONFIG_MTD_NAND_ATMEL_ECC_HW #define hard_ecc 1 #else #define hard_ecc 0 #endif -#ifdef CONFIG_MTD_NAND_AT91_ECC_NONE +#ifdef CONFIG_MTD_NAND_ATMEL_ECC_NONE #define no_ecc 1 #else #define no_ecc 0 @@ -52,18 +49,18 @@ /* Register access macros */ #define ecc_readl(add, reg) \ - __raw_readl(add + AT91_ECC_##reg) + __raw_readl(add + ATMEL_ECC_##reg) #define ecc_writel(add, reg, value) \ - __raw_writel((value), add + AT91_ECC_##reg) + __raw_writel((value), add + ATMEL_ECC_##reg) -#include <asm/arch/at91_ecc.h> /* AT91SAM9260/3 ECC registers */ +#include "atmel_nand_ecc.h" /* Hardware ECC registers */ /* oob layout for large page size * bad block info is on bytes 0 and 1 * the bytes have to be consecutives to avoid * several NAND_CMD_RNDOUT during read */ -static struct nand_ecclayout at91_oobinfo_large = { +static struct nand_ecclayout atmel_oobinfo_large = { .eccbytes = 4, .eccpos = {60, 61, 62, 63}, .oobfree = { @@ -76,7 +73,7 @@ static struct nand_ecclayout at91_oobinfo_large = { * the bytes have to be consecutives to avoid * several NAND_CMD_RNDOUT during read */ -static struct nand_ecclayout at91_oobinfo_small = { +static struct nand_ecclayout atmel_oobinfo_small = { .eccbytes = 4, .eccpos = {0, 1, 2, 3}, .oobfree = { @@ -84,11 +81,11 @@ static struct nand_ecclayout at91_oobinfo_small = { }, }; -struct at91_nand_host { +struct atmel_nand_host { struct nand_chip nand_chip; struct mtd_info mtd; void __iomem *io_base; - struct at91_nand_data *board; + struct atmel_nand_data *board; struct device *dev; void __iomem *ecc; }; @@ -96,34 +93,34 @@ struct at91_nand_host { /* * Enable NAND. */ -static void at91_nand_enable(struct at91_nand_host *host) +static void atmel_nand_enable(struct atmel_nand_host *host) { if (host->board->enable_pin) - at91_set_gpio_value(host->board->enable_pin, 0); + gpio_set_value(host->board->enable_pin, 0); } /* * Disable NAND. */ -static void at91_nand_disable(struct at91_nand_host *host) +static void atmel_nand_disable(struct atmel_nand_host *host) { if (host->board->enable_pin) - at91_set_gpio_value(host->board->enable_pin, 1); + gpio_set_value(host->board->enable_pin, 1); } /* * Hardware specific access to control-lines */ -static void at91_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) +static void atmel_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) { struct nand_chip *nand_chip = mtd->priv; - struct at91_nand_host *host = nand_chip->priv; + struct atmel_nand_host *host = nand_chip->priv; if (ctrl & NAND_CTRL_CHANGE) { if (ctrl & NAND_NCE) - at91_nand_enable(host); + atmel_nand_enable(host); else - at91_nand_disable(host); + atmel_nand_disable(host); } if (cmd == NAND_CMD_NONE) return; @@ -137,18 +134,49 @@ static void at91_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) /* * Read the Device Ready pin. */ -static int at91_nand_device_ready(struct mtd_info *mtd) +static int atmel_nand_device_ready(struct mtd_info *mtd) { struct nand_chip *nand_chip = mtd->priv; - struct at91_nand_host *host = nand_chip->priv; + struct atmel_nand_host *host = nand_chip->priv; - return at91_get_gpio_value(host->board->rdy_pin); + return gpio_get_value(host->board->rdy_pin); +} + +/* + * Minimal-overhead PIO for data access. + */ +static void atmel_read_buf(struct mtd_info *mtd, u8 *buf, int len) +{ + struct nand_chip *nand_chip = mtd->priv; + + __raw_readsb(nand_chip->IO_ADDR_R, buf, len); +} + +static void atmel_read_buf16(struct mtd_info *mtd, u8 *buf, int len) +{ + struct nand_chip *nand_chip = mtd->priv; + + __raw_readsw(nand_chip->IO_ADDR_R, buf, len / 2); +} + +static void atmel_write_buf(struct mtd_info *mtd, const u8 *buf, int len) +{ + struct nand_chip *nand_chip = mtd->priv; + + __raw_writesb(nand_chip->IO_ADDR_W, buf, len); +} + +static void atmel_write_buf16(struct mtd_info *mtd, const u8 *buf, int len) +{ + struct nand_chip *nand_chip = mtd->priv; + + __raw_writesw(nand_chip->IO_ADDR_W, buf, len / 2); } /* * write oob for small pages */ -static int at91_nand_write_oob_512(struct mtd_info *mtd, +static int atmel_nand_write_oob_512(struct mtd_info *mtd, struct nand_chip *chip, int page) { int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad; @@ -176,7 +204,7 @@ static int at91_nand_write_oob_512(struct mtd_info *mtd, /* * read oob for small pages */ -static int at91_nand_read_oob_512(struct mtd_info *mtd, +static int atmel_nand_read_oob_512(struct mtd_info *mtd, struct nand_chip *chip, int page, int sndcmd) { if (sndcmd) { @@ -196,11 +224,11 @@ static int at91_nand_read_oob_512(struct mtd_info *mtd, * dat: raw data (unused) * ecc_code: buffer for ECC */ -static int at91_nand_calculate(struct mtd_info *mtd, +static int atmel_nand_calculate(struct mtd_info *mtd, const u_char *dat, unsigned char *ecc_code) { struct nand_chip *nand_chip = mtd->priv; - struct at91_nand_host *host = nand_chip->priv; + struct atmel_nand_host *host = nand_chip->priv; uint32_t *eccpos = nand_chip->ecc.layout->eccpos; unsigned int ecc_value; @@ -211,7 +239,7 @@ static int at91_nand_calculate(struct mtd_info *mtd, ecc_code[eccpos[1]] = (ecc_value >> 8) & 0xFF; /* get the last 2 ECC bytes */ - ecc_value = ecc_readl(host->ecc, NPR) & AT91_ECC_NPARITY; + ecc_value = ecc_readl(host->ecc, NPR) & ATMEL_ECC_NPARITY; ecc_code[eccpos[2]] = ecc_value & 0xFF; ecc_code[eccpos[3]] = (ecc_value >> 8) & 0xFF; @@ -226,7 +254,7 @@ static int at91_nand_calculate(struct mtd_info *mtd, * chip: nand chip info structure * buf: buffer to store read data */ -static int at91_nand_read_page(struct mtd_info *mtd, +static int atmel_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf) { int eccsize = chip->ecc.size; @@ -237,6 +265,19 @@ static int at91_nand_read_page(struct mtd_info *mtd, uint8_t *ecc_pos; int stat; + /* + * Errata: ALE is incorrectly wired up to the ECC controller + * on the AP7000, so it will include the address cycles in the + * ECC calculation. + * + * Workaround: Reset the parity registers before reading the + * actual data. + */ + if (cpu_is_at32ap7000()) { + struct atmel_nand_host *host = chip->priv; + ecc_writel(host->ecc, CR, ATMEL_ECC_RST); + } + /* read the page */ chip->read_buf(mtd, p, eccsize); @@ -285,11 +326,11 @@ static int at91_nand_read_page(struct mtd_info *mtd, * * Detect and correct a 1 bit error for a page */ -static int at91_nand_correct(struct mtd_info *mtd, u_char *dat, +static int atmel_nand_correct(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *isnull) { struct nand_chip *nand_chip = mtd->priv; - struct at91_nand_host *host = nand_chip->priv; + struct atmel_nand_host *host = nand_chip->priv; unsigned int ecc_status; unsigned int ecc_word, ecc_bit; @@ -297,43 +338,43 @@ static int at91_nand_correct(struct mtd_info *mtd, u_char *dat, ecc_status = ecc_readl(host->ecc, SR); /* if there's no error */ - if (likely(!(ecc_status & AT91_ECC_RECERR))) + if (likely(!(ecc_status & ATMEL_ECC_RECERR))) return 0; /* get error bit offset (4 bits) */ - ecc_bit = ecc_readl(host->ecc, PR) & AT91_ECC_BITADDR; + ecc_bit = ecc_readl(host->ecc, PR) & ATMEL_ECC_BITADDR; /* get word address (12 bits) */ - ecc_word = ecc_readl(host->ecc, PR) & AT91_ECC_WORDADDR; + ecc_word = ecc_readl(host->ecc, PR) & ATMEL_ECC_WORDADDR; ecc_word >>= 4; /* if there are multiple errors */ - if (ecc_status & AT91_ECC_MULERR) { + if (ecc_status & ATMEL_ECC_MULERR) { /* check if it is a freshly erased block * (filled with 0xff) */ - if ((ecc_bit == AT91_ECC_BITADDR) - && (ecc_word == (AT91_ECC_WORDADDR >> 4))) { + if ((ecc_bit == ATMEL_ECC_BITADDR) + && (ecc_word == (ATMEL_ECC_WORDADDR >> 4))) { /* the block has just been erased, return OK */ return 0; } /* it doesn't seems to be a freshly * erased block. * We can't correct so many errors */ - dev_dbg(host->dev, "at91_nand : multiple errors detected." + dev_dbg(host->dev, "atmel_nand : multiple errors detected." " Unable to correct.\n"); return -EIO; } /* if there's a single bit error : we can correct it */ - if (ecc_status & AT91_ECC_ECCERR) { + if (ecc_status & ATMEL_ECC_ECCERR) { /* there's nothing much to do here. * the bit error is on the ECC itself. */ - dev_dbg(host->dev, "at91_nand : one bit error on ECC code." + dev_dbg(host->dev, "atmel_nand : one bit error on ECC code." " Nothing to correct\n"); return 0; } - dev_dbg(host->dev, "at91_nand : one bit error on data." + dev_dbg(host->dev, "atmel_nand : one bit error on data." " (word offset in the page :" " 0x%x bit offset : 0x%x)\n", ecc_word, ecc_bit); @@ -345,14 +386,21 @@ static int at91_nand_correct(struct mtd_info *mtd, u_char *dat, /* 8 bits words */ dat[ecc_word] ^= (1 << ecc_bit); } - dev_dbg(host->dev, "at91_nand : error corrected\n"); + dev_dbg(host->dev, "atmel_nand : error corrected\n"); return 1; } /* - * Enable HW ECC : unsused + * Enable HW ECC : unused on most chips */ -static void at91_nand_hwctl(struct mtd_info *mtd, int mode) { ; } +static void atmel_nand_hwctl(struct mtd_info *mtd, int mode) +{ + if (cpu_is_at32ap7000()) { + struct nand_chip *nand_chip = mtd->priv; + struct atmel_nand_host *host = nand_chip->priv; + ecc_writel(host->ecc, CR, ATMEL_ECC_RST); + } +} #ifdef CONFIG_MTD_PARTITIONS static const char *part_probes[] = { "cmdlinepart", NULL }; @@ -361,9 +409,9 @@ static const char *part_probes[] = { "cmdlinepart", NULL }; /* * Probe for the NAND device. */ -static int __init at91_nand_probe(struct platform_device *pdev) +static int __init atmel_nand_probe(struct platform_device *pdev) { - struct at91_nand_host *host; + struct atmel_nand_host *host; struct mtd_info *mtd; struct nand_chip *nand_chip; struct resource *regs; @@ -375,24 +423,24 @@ static int __init at91_nand_probe(struct platform_device *pdev) int num_partitions = 0; #endif - /* Allocate memory for the device structure (and zero it) */ - host = kzalloc(sizeof(struct at91_nand_host), GFP_KERNEL); - if (!host) { - printk(KERN_ERR "at91_nand: failed to allocate device structure.\n"); - return -ENOMEM; - } - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!mem) { - printk(KERN_ERR "at91_nand: can't get I/O resource mem\n"); + printk(KERN_ERR "atmel_nand: can't get I/O resource mem\n"); return -ENXIO; } + /* Allocate memory for the device structure (and zero it) */ + host = kzalloc(sizeof(struct atmel_nand_host), GFP_KERNEL); + if (!host) { + printk(KERN_ERR "atmel_nand: failed to allocate device structure.\n"); + return -ENOMEM; + } + host->io_base = ioremap(mem->start, mem->end - mem->start + 1); if (host->io_base == NULL) { - printk(KERN_ERR "at91_nand: ioremap failed\n"); - kfree(host); - return -EIO; + printk(KERN_ERR "atmel_nand: ioremap failed\n"); + res = -EIO; + goto err_nand_ioremap; } mtd = &host->mtd; @@ -407,14 +455,14 @@ static int __init at91_nand_probe(struct platform_device *pdev) /* Set address of NAND IO lines */ nand_chip->IO_ADDR_R = host->io_base; nand_chip->IO_ADDR_W = host->io_base; - nand_chip->cmd_ctrl = at91_nand_cmd_ctrl; + nand_chip->cmd_ctrl = atmel_nand_cmd_ctrl; if (host->board->rdy_pin) - nand_chip->dev_ready = at91_nand_device_ready; + nand_chip->dev_ready = atmel_nand_device_ready; regs = platform_get_resource(pdev, IORESOURCE_MEM, 1); if (!regs && hard_ecc) { - printk(KERN_ERR "at91_nand: can't get I/O resource " + printk(KERN_ERR "atmel_nand: can't get I/O resource " "regs\nFalling back on software ECC\n"); } @@ -424,15 +472,15 @@ static int __init at91_nand_probe(struct platform_device *pdev) if (hard_ecc && regs) { host->ecc = ioremap(regs->start, regs->end - regs->start + 1); if (host->ecc == NULL) { - printk(KERN_ERR "at91_nand: ioremap failed\n"); + printk(KERN_ERR "atmel_nand: ioremap failed\n"); res = -EIO; goto err_ecc_ioremap; } nand_chip->ecc.mode = NAND_ECC_HW_SYNDROME; - nand_chip->ecc.calculate = at91_nand_calculate; - nand_chip->ecc.correct = at91_nand_correct; - nand_chip->ecc.hwctl = at91_nand_hwctl; - nand_chip->ecc.read_page = at91_nand_read_page; + nand_chip->ecc.calculate = atmel_nand_calculate; + nand_chip->ecc.correct = atmel_nand_correct; + nand_chip->ecc.hwctl = atmel_nand_hwctl; + nand_chip->ecc.read_page = atmel_nand_read_page; nand_chip->ecc.bytes = 4; nand_chip->ecc.prepad = 0; nand_chip->ecc.postpad = 0; @@ -440,24 +488,30 @@ static int __init at91_nand_probe(struct platform_device *pdev) nand_chip->chip_delay = 20; /* 20us command delay time */ - if (host->board->bus_width_16) /* 16-bit bus width */ + if (host->board->bus_width_16) { /* 16-bit bus width */ nand_chip->options |= NAND_BUSWIDTH_16; + nand_chip->read_buf = atmel_read_buf16; + nand_chip->write_buf = atmel_write_buf16; + } else { + nand_chip->read_buf = atmel_read_buf; + nand_chip->write_buf = atmel_write_buf; + } platform_set_drvdata(pdev, host); - at91_nand_enable(host); + atmel_nand_enable(host); if (host->board->det_pin) { - if (at91_get_gpio_value(host->board->det_pin)) { - printk ("No SmartMedia card inserted.\n"); + if (gpio_get_value(host->board->det_pin)) { + printk("No SmartMedia card inserted.\n"); res = ENXIO; - goto out; + goto err_no_card; } } /* first scan to find the device and get the page size */ if (nand_scan_ident(mtd, 1)) { res = -ENXIO; - goto out; + goto err_scan_ident; } if (nand_chip->ecc.mode == NAND_ECC_HW_SYNDROME) { @@ -467,22 +521,22 @@ static int __init at91_nand_probe(struct platform_device *pdev) /* set ECC page size and oob layout */ switch (mtd->writesize) { case 512: - nand_chip->ecc.layout = &at91_oobinfo_small; - nand_chip->ecc.read_oob = at91_nand_read_oob_512; - nand_chip->ecc.write_oob = at91_nand_write_oob_512; - ecc_writel(host->ecc, MR, AT91_ECC_PAGESIZE_528); + nand_chip->ecc.layout = &atmel_oobinfo_small; + nand_chip->ecc.read_oob = atmel_nand_read_oob_512; + nand_chip->ecc.write_oob = atmel_nand_write_oob_512; + ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_528); break; case 1024: - nand_chip->ecc.layout = &at91_oobinfo_large; - ecc_writel(host->ecc, MR, AT91_ECC_PAGESIZE_1056); + nand_chip->ecc.layout = &atmel_oobinfo_large; + ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_1056); break; case 2048: - nand_chip->ecc.layout = &at91_oobinfo_large; - ecc_writel(host->ecc, MR, AT91_ECC_PAGESIZE_2112); + nand_chip->ecc.layout = &atmel_oobinfo_large; + ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_2112); break; case 4096: - nand_chip->ecc.layout = &at91_oobinfo_large; - ecc_writel(host->ecc, MR, AT91_ECC_PAGESIZE_4224); + nand_chip->ecc.layout = &atmel_oobinfo_large; + ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_4224); break; default: /* page size not handled by HW ECC */ @@ -502,12 +556,12 @@ static int __init at91_nand_probe(struct platform_device *pdev) /* second phase scan */ if (nand_scan_tail(mtd)) { res = -ENXIO; - goto out; + goto err_scan_tail; } #ifdef CONFIG_MTD_PARTITIONS #ifdef CONFIG_MTD_CMDLINE_PARTS - mtd->name = "at91_nand"; + mtd->name = "atmel_nand"; num_partitions = parse_mtd_partitions(mtd, part_probes, &partitions, 0); #endif @@ -516,9 +570,9 @@ static int __init at91_nand_probe(struct platform_device *pdev) &num_partitions); if ((!partitions) || (num_partitions == 0)) { - printk(KERN_ERR "at91_nand: No parititions defined, or unsupported device.\n"); + printk(KERN_ERR "atmel_nand: No parititions defined, or unsupported device.\n"); res = ENXIO; - goto release; + goto err_no_partitions; } res = add_mtd_partitions(mtd, partitions, num_partitions); @@ -530,17 +584,19 @@ static int __init at91_nand_probe(struct platform_device *pdev) return res; #ifdef CONFIG_MTD_PARTITIONS -release: +err_no_partitions: #endif nand_release(mtd); - -out: - iounmap(host->ecc); - -err_ecc_ioremap: - at91_nand_disable(host); +err_scan_tail: +err_scan_ident: +err_no_card: + atmel_nand_disable(host); platform_set_drvdata(pdev, NULL); + if (host->ecc) + iounmap(host->ecc); +err_ecc_ioremap: iounmap(host->io_base); +err_nand_ioremap: kfree(host); return res; } @@ -548,47 +604,47 @@ err_ecc_ioremap: /* * Remove a NAND device. */ -static int __devexit at91_nand_remove(struct platform_device *pdev) +static int __exit atmel_nand_remove(struct platform_device *pdev) { - struct at91_nand_host *host = platform_get_drvdata(pdev); + struct atmel_nand_host *host = platform_get_drvdata(pdev); struct mtd_info *mtd = &host->mtd; nand_release(mtd); - at91_nand_disable(host); + atmel_nand_disable(host); + if (host->ecc) + iounmap(host->ecc); iounmap(host->io_base); - iounmap(host->ecc); kfree(host); return 0; } -static struct platform_driver at91_nand_driver = { - .probe = at91_nand_probe, - .remove = at91_nand_remove, +static struct platform_driver atmel_nand_driver = { + .remove = __exit_p(atmel_nand_remove), .driver = { - .name = "at91_nand", + .name = "atmel_nand", .owner = THIS_MODULE, }, }; -static int __init at91_nand_init(void) +static int __init atmel_nand_init(void) { - return platform_driver_register(&at91_nand_driver); + return platform_driver_probe(&atmel_nand_driver, atmel_nand_probe); } -static void __exit at91_nand_exit(void) +static void __exit atmel_nand_exit(void) { - platform_driver_unregister(&at91_nand_driver); + platform_driver_unregister(&atmel_nand_driver); } -module_init(at91_nand_init); -module_exit(at91_nand_exit); +module_init(atmel_nand_init); +module_exit(atmel_nand_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Rick Bronson"); -MODULE_DESCRIPTION("NAND/SmartMedia driver for AT91RM9200 / AT91SAM9"); -MODULE_ALIAS("platform:at91_nand"); +MODULE_DESCRIPTION("NAND/SmartMedia driver for AT91 / AVR32"); +MODULE_ALIAS("platform:atmel_nand"); diff --git a/drivers/mtd/nand/atmel_nand_ecc.h b/drivers/mtd/nand/atmel_nand_ecc.h new file mode 100644 index 000000000000..578c776e1356 --- /dev/null +++ b/drivers/mtd/nand/atmel_nand_ecc.h @@ -0,0 +1,39 @@ +/* + * Error Corrected Code Controller (ECC) - System peripherals regsters. + * Based on AT91SAM9260 datasheet revision B. + * + * Copyright (C) 2007 Andrew Victor + * Copyright (C) 2007 Atmel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef ATMEL_NAND_ECC_H +#define ATMEL_NAND_ECC_H + +#define ATMEL_ECC_CR 0x00 /* Control register */ +#define ATMEL_ECC_RST (1 << 0) /* Reset parity */ + +#define ATMEL_ECC_MR 0x04 /* Mode register */ +#define ATMEL_ECC_PAGESIZE (3 << 0) /* Page Size */ +#define ATMEL_ECC_PAGESIZE_528 (0) +#define ATMEL_ECC_PAGESIZE_1056 (1) +#define ATMEL_ECC_PAGESIZE_2112 (2) +#define ATMEL_ECC_PAGESIZE_4224 (3) + +#define ATMEL_ECC_SR 0x08 /* Status register */ +#define ATMEL_ECC_RECERR (1 << 0) /* Recoverable Error */ +#define ATMEL_ECC_ECCERR (1 << 1) /* ECC Single Bit Error */ +#define ATMEL_ECC_MULERR (1 << 2) /* Multiple Errors */ + +#define ATMEL_ECC_PR 0x0c /* Parity register */ +#define ATMEL_ECC_BITADDR (0xf << 0) /* Bit Error Address */ +#define ATMEL_ECC_WORDADDR (0xfff << 4) /* Word Error Address */ + +#define ATMEL_ECC_NPR 0x10 /* NParity register */ +#define ATMEL_ECC_NPARITY (0xffff << 0) /* NParity */ + +#endif diff --git a/drivers/mtd/nand/au1550nd.c b/drivers/mtd/nand/au1550nd.c index 09e421a96893..92c334ff4508 100644 --- a/drivers/mtd/nand/au1550nd.c +++ b/drivers/mtd/nand/au1550nd.c @@ -3,8 +3,6 @@ * * Copyright (C) 2004 Embedded Edge, LLC * - * $Id: au1550nd.c,v 1.13 2005/11/07 11:14:30 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 * published by the Free Software Foundation. @@ -18,7 +16,6 @@ #include <linux/mtd/mtd.h> #include <linux/mtd/nand.h> #include <linux/mtd/partitions.h> -#include <linux/version.h> #include <asm/io.h> #include <asm/mach-au1x00/au1xxx.h> @@ -604,8 +601,6 @@ module_init(au1xxx_nand_init); */ static void __exit au1550_cleanup(void) { - struct nand_chip *this = (struct nand_chip *)&au1550_mtd[1]; - /* Release resources, unregister device */ nand_release(au1550_mtd); diff --git a/drivers/mtd/nand/autcpu12.c b/drivers/mtd/nand/autcpu12.c index dd38011ee0b7..7c95da1f612c 100644 --- a/drivers/mtd/nand/autcpu12.c +++ b/drivers/mtd/nand/autcpu12.c @@ -6,8 +6,6 @@ * Derived from drivers/mtd/spia.c * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) * - * $Id: autcpu12.c,v 1.23 2005/11/07 11:14:30 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 * published by the Free Software Foundation. @@ -34,9 +32,9 @@ #include <linux/mtd/nand.h> #include <linux/mtd/partitions.h> #include <asm/io.h> -#include <asm/arch/hardware.h> +#include <mach/hardware.h> #include <asm/sizes.h> -#include <asm/arch/autcpu12.h> +#include <mach/autcpu12.h> /* * MTD structure for AUTCPU12 board diff --git a/drivers/mtd/nand/bf5xx_nand.c b/drivers/mtd/nand/bf5xx_nand.c index e87a57297328..9af2a2cc1153 100644 --- a/drivers/mtd/nand/bf5xx_nand.c +++ b/drivers/mtd/nand/bf5xx_nand.c @@ -91,6 +91,41 @@ static const unsigned short bfin_nfc_pin_req[] = P_NAND_ALE, 0}; +#ifdef CONFIG_MTD_NAND_BF5XX_BOOTROM_ECC +static uint8_t bbt_pattern[] = { 0xff }; + +static struct nand_bbt_descr bootrom_bbt = { + .options = 0, + .offs = 63, + .len = 1, + .pattern = bbt_pattern, +}; + +static struct nand_ecclayout bootrom_ecclayout = { + .eccbytes = 24, + .eccpos = { + 0x8 * 0, 0x8 * 0 + 1, 0x8 * 0 + 2, + 0x8 * 1, 0x8 * 1 + 1, 0x8 * 1 + 2, + 0x8 * 2, 0x8 * 2 + 1, 0x8 * 2 + 2, + 0x8 * 3, 0x8 * 3 + 1, 0x8 * 3 + 2, + 0x8 * 4, 0x8 * 4 + 1, 0x8 * 4 + 2, + 0x8 * 5, 0x8 * 5 + 1, 0x8 * 5 + 2, + 0x8 * 6, 0x8 * 6 + 1, 0x8 * 6 + 2, + 0x8 * 7, 0x8 * 7 + 1, 0x8 * 7 + 2 + }, + .oobfree = { + { 0x8 * 0 + 3, 5 }, + { 0x8 * 1 + 3, 5 }, + { 0x8 * 2 + 3, 5 }, + { 0x8 * 3 + 3, 5 }, + { 0x8 * 4 + 3, 5 }, + { 0x8 * 5 + 3, 5 }, + { 0x8 * 6 + 3, 5 }, + { 0x8 * 7 + 3, 5 }, + } +}; +#endif + /* * Data structures for bf5xx nand flash controller driver */ @@ -273,7 +308,7 @@ static int bf5xx_nand_correct_data(struct mtd_info *mtd, u_char *dat, dat += 256; read_ecc += 8; calc_ecc += 8; - ret = bf5xx_nand_correct_data_256(mtd, dat, read_ecc, calc_ecc); + ret |= bf5xx_nand_correct_data_256(mtd, dat, read_ecc, calc_ecc); } return ret; @@ -298,7 +333,7 @@ static int bf5xx_nand_calculate_ecc(struct mtd_info *mtd, ecc0 = bfin_read_NFC_ECC0(); ecc1 = bfin_read_NFC_ECC1(); - code[0] = (ecc0 & 0x3FF) | ((ecc1 & 0x3FF) << 11); + code[0] = (ecc0 & 0x7ff) | ((ecc1 & 0x7ff) << 11); dev_dbg(info->device, "returning ecc 0x%08x\n", code[0]); @@ -310,7 +345,7 @@ static int bf5xx_nand_calculate_ecc(struct mtd_info *mtd, if (page_size == 512) { ecc0 = bfin_read_NFC_ECC2(); ecc1 = bfin_read_NFC_ECC3(); - code[1] = (ecc0 & 0x3FF) | ((ecc1 & 0x3FF) << 11); + code[1] = (ecc0 & 0x7ff) | ((ecc1 & 0x7ff) << 11); /* second 3 bytes in ecc_code for second 256 * bytes of 512 page size @@ -514,7 +549,6 @@ static void bf5xx_nand_dma_write_buf(struct mtd_info *mtd, /* * System initialization functions */ - static int bf5xx_nand_dma_init(struct bf5xx_nand_info *info) { int ret; @@ -547,6 +581,13 @@ static int bf5xx_nand_dma_init(struct bf5xx_nand_info *info) return 0; } +static void bf5xx_nand_dma_remove(struct bf5xx_nand_info *info) +{ + /* Free NFC DMA channel */ + if (hardware_ecc) + free_dma(CH_NFC); +} + /* * BF5XX NFC hardware initialization * - pin mux setup @@ -605,7 +646,7 @@ static int bf5xx_nand_add_partition(struct bf5xx_nand_info *info) #endif } -static int bf5xx_nand_remove(struct platform_device *pdev) +static int __devexit bf5xx_nand_remove(struct platform_device *pdev) { struct bf5xx_nand_info *info = to_nand_info(pdev); struct mtd_info *mtd = NULL; @@ -623,6 +664,7 @@ static int bf5xx_nand_remove(struct platform_device *pdev) } peripheral_free_list(bfin_nfc_pin_req); + bf5xx_nand_dma_remove(info); /* free the common resources */ kfree(info); @@ -638,7 +680,7 @@ static int bf5xx_nand_remove(struct platform_device *pdev) * it can allocate all necessary resources then calls the * nand layer to look for devices */ -static int bf5xx_nand_probe(struct platform_device *pdev) +static int __devinit bf5xx_nand_probe(struct platform_device *pdev) { struct bf5xx_nand_platform *plat = to_nand_plat(pdev); struct bf5xx_nand_info *info = NULL; @@ -648,22 +690,21 @@ static int bf5xx_nand_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "(%p)\n", pdev); - if (peripheral_request_list(bfin_nfc_pin_req, DRV_NAME)) { - printk(KERN_ERR DRV_NAME - ": Requesting Peripherals failed\n"); - return -EFAULT; - } - if (!plat) { dev_err(&pdev->dev, "no platform specific information\n"); - goto exit_error; + return -EINVAL; + } + + if (peripheral_request_list(bfin_nfc_pin_req, DRV_NAME)) { + dev_err(&pdev->dev, "requesting Peripherals failed\n"); + return -EFAULT; } info = kzalloc(sizeof(*info), GFP_KERNEL); if (info == NULL) { dev_err(&pdev->dev, "no memory for flash info\n"); err = -ENOMEM; - goto exit_error; + goto out_err_kzalloc; } platform_set_drvdata(pdev, info); @@ -707,11 +748,16 @@ static int bf5xx_nand_probe(struct platform_device *pdev) /* initialise the hardware */ err = bf5xx_nand_hw_init(info); - if (err != 0) - goto exit_error; + if (err) + goto out_err_hw_init; /* setup hardware ECC data struct */ if (hardware_ecc) { +#ifdef CONFIG_MTD_NAND_BF5XX_BOOTROM_ECC + chip->badblock_pattern = &bootrom_bbt; + chip->ecc.layout = &bootrom_ecclayout; +#endif + if (plat->page_size == NFC_PG_SIZE_256) { chip->ecc.bytes = 3; chip->ecc.size = 256; @@ -733,7 +779,7 @@ static int bf5xx_nand_probe(struct platform_device *pdev) /* scan hardware nand chip and setup mtd info data struct */ if (nand_scan(mtd, 1)) { err = -ENXIO; - goto exit_error; + goto out_err_nand_scan; } /* add NAND partition */ @@ -742,11 +788,14 @@ static int bf5xx_nand_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "initialised ok\n"); return 0; -exit_error: - bf5xx_nand_remove(pdev); +out_err_nand_scan: + bf5xx_nand_dma_remove(info); +out_err_hw_init: + platform_set_drvdata(pdev, NULL); + kfree(info); +out_err_kzalloc: + peripheral_free_list(bfin_nfc_pin_req); - if (err == 0) - err = -EINVAL; return err; } @@ -775,7 +824,7 @@ static int bf5xx_nand_resume(struct platform_device *dev) /* driver device registration */ static struct platform_driver bf5xx_nand_driver = { .probe = bf5xx_nand_probe, - .remove = bf5xx_nand_remove, + .remove = __devexit_p(bf5xx_nand_remove), .suspend = bf5xx_nand_suspend, .resume = bf5xx_nand_resume, .driver = { diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c index da6ceaa80ba1..95345d051579 100644 --- a/drivers/mtd/nand/cafe_nand.c +++ b/drivers/mtd/nand/cafe_nand.c @@ -626,10 +626,12 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev, { struct mtd_info *mtd; struct cafe_priv *cafe; - struct mtd_partition *parts; uint32_t ctrl; - int nr_parts; int err = 0; +#ifdef CONFIG_MTD_PARTITIONS + struct mtd_partition *parts; + int nr_parts; +#endif /* Very old versions shared the same PCI ident for all three functions on the chip. Verify the class too... */ diff --git a/drivers/mtd/nand/cmx270_nand.c b/drivers/mtd/nand/cmx270_nand.c index fc8529bedfdf..fa129c09bca8 100644 --- a/drivers/mtd/nand/cmx270_nand.c +++ b/drivers/mtd/nand/cmx270_nand.c @@ -26,8 +26,8 @@ #include <asm/irq.h> #include <asm/mach-types.h> -#include <asm/arch/hardware.h> -#include <asm/arch/pxa-regs.h> +#include <mach/hardware.h> +#include <mach/pxa-regs.h> #define GPIO_NAND_CS (11) #define GPIO_NAND_RB (89) @@ -156,7 +156,7 @@ static int cmx270_init(void) int mtd_parts_nb = 0; int ret; - if (!machine_is_armcore()) + if (!(machine_is_armcore() && cpu_is_pxa27x())) return -ENODEV; ret = gpio_request(GPIO_NAND_CS, "NAND CS"); diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index 0e72153b3297..e4226e02d63e 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c @@ -15,8 +15,6 @@ * converted to the generic Reed-Solomon library by Thomas Gleixner <tglx@linutronix.de> * * Interface to generic NAND code for M-Systems DiskOnChip devices - * - * $Id: diskonchip.c,v 1.55 2005/11/07 11:14:30 gleixner Exp $ */ #include <linux/kernel.h> @@ -54,8 +52,6 @@ static unsigned long __initdata doc_locations[] = { 0xe0000, 0xe2000, 0xe4000, 0xe6000, 0xe8000, 0xea000, 0xec000, 0xee000, #endif /* CONFIG_MTD_DOCPROBE_HIGH */ -#elif defined(__PPC__) - 0xe4000000, #else #warning Unknown architecture for DiskOnChip. No default probe locations defined #endif @@ -1129,9 +1125,9 @@ static inline int __init nftl_partscan(struct mtd_info *mtd, struct mtd_partitio goto out; mh = (struct NFTLMediaHeader *)buf; - mh->NumEraseUnits = le16_to_cpu(mh->NumEraseUnits); - mh->FirstPhysicalEUN = le16_to_cpu(mh->FirstPhysicalEUN); - mh->FormattedSize = le32_to_cpu(mh->FormattedSize); + le16_to_cpus(&mh->NumEraseUnits); + le16_to_cpus(&mh->FirstPhysicalEUN); + le32_to_cpus(&mh->FormattedSize); printk(KERN_INFO " DataOrgID = %s\n" " NumEraseUnits = %d\n" @@ -1239,12 +1235,12 @@ static inline int __init inftl_partscan(struct mtd_info *mtd, struct mtd_partiti doc->mh1_page = doc->mh0_page + (4096 >> this->page_shift); mh = (struct INFTLMediaHeader *)buf; - mh->NoOfBootImageBlocks = le32_to_cpu(mh->NoOfBootImageBlocks); - mh->NoOfBinaryPartitions = le32_to_cpu(mh->NoOfBinaryPartitions); - mh->NoOfBDTLPartitions = le32_to_cpu(mh->NoOfBDTLPartitions); - mh->BlockMultiplierBits = le32_to_cpu(mh->BlockMultiplierBits); - mh->FormatFlags = le32_to_cpu(mh->FormatFlags); - mh->PercentUsed = le32_to_cpu(mh->PercentUsed); + le32_to_cpus(&mh->NoOfBootImageBlocks); + le32_to_cpus(&mh->NoOfBinaryPartitions); + le32_to_cpus(&mh->NoOfBDTLPartitions); + le32_to_cpus(&mh->BlockMultiplierBits); + le32_to_cpus(&mh->FormatFlags); + le32_to_cpus(&mh->PercentUsed); printk(KERN_INFO " bootRecordID = %s\n" " NoOfBootImageBlocks = %d\n" @@ -1281,12 +1277,12 @@ static inline int __init inftl_partscan(struct mtd_info *mtd, struct mtd_partiti /* Scan the partitions */ for (i = 0; (i < 4); i++) { ip = &(mh->Partitions[i]); - ip->virtualUnits = le32_to_cpu(ip->virtualUnits); - ip->firstUnit = le32_to_cpu(ip->firstUnit); - ip->lastUnit = le32_to_cpu(ip->lastUnit); - ip->flags = le32_to_cpu(ip->flags); - ip->spareUnits = le32_to_cpu(ip->spareUnits); - ip->Reserved0 = le32_to_cpu(ip->Reserved0); + le32_to_cpus(&ip->virtualUnits); + le32_to_cpus(&ip->firstUnit); + le32_to_cpus(&ip->lastUnit); + le32_to_cpus(&ip->flags); + le32_to_cpus(&ip->spareUnits); + le32_to_cpus(&ip->Reserved0); printk(KERN_INFO " PARTITION[%d] ->\n" " virtualUnits = %d\n" diff --git a/drivers/mtd/nand/edb7312.c b/drivers/mtd/nand/edb7312.c index ba67bbec20d3..86366bfba9f8 100644 --- a/drivers/mtd/nand/edb7312.c +++ b/drivers/mtd/nand/edb7312.c @@ -6,8 +6,6 @@ * Derived from drivers/mtd/nand/autcpu12.c * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) * - * $Id: edb7312.c,v 1.12 2005/11/07 11:14:30 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 * published by the Free Software Foundation. @@ -25,7 +23,7 @@ #include <linux/mtd/nand.h> #include <linux/mtd/partitions.h> #include <asm/io.h> -#include <asm/arch/hardware.h> /* for CLPS7111_VIRT_BASE */ +#include <mach/hardware.h> /* for CLPS7111_VIRT_BASE */ #include <asm/sizes.h> #include <asm/hardware/clps7111.h> diff --git a/drivers/mtd/nand/excite_nandflash.c b/drivers/mtd/nand/excite_nandflash.c index bed87290decc..ced14b5294d5 100644 --- a/drivers/mtd/nand/excite_nandflash.c +++ b/drivers/mtd/nand/excite_nandflash.c @@ -209,7 +209,7 @@ static int __init excite_nand_probe(struct device *dev) if (likely(!scan_res)) { DEBUG(MTD_DEBUG_LEVEL2, "%s: register partitions\n", module_id); add_mtd_partitions(&drvdata->board_mtd, partition_info, - sizeof partition_info / sizeof partition_info[0]); + ARRAY_SIZE(partition_info)); } else { iounmap(drvdata->regs); kfree(drvdata); diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c index 4b69aacdf5ca..98ad3cefcaf4 100644 --- a/drivers/mtd/nand/fsl_elbc_nand.c +++ b/drivers/mtd/nand/fsl_elbc_nand.c @@ -89,7 +89,6 @@ static struct nand_ecclayout fsl_elbc_oob_sp_eccm0 = { .eccbytes = 3, .eccpos = {6, 7, 8}, .oobfree = { {0, 5}, {9, 7} }, - .oobavail = 12, }; /* Small Page FLASH with FMR[ECCM] = 1 */ @@ -97,7 +96,6 @@ static struct nand_ecclayout fsl_elbc_oob_sp_eccm1 = { .eccbytes = 3, .eccpos = {8, 9, 10}, .oobfree = { {0, 5}, {6, 2}, {11, 5} }, - .oobavail = 12, }; /* Large Page FLASH with FMR[ECCM] = 0 */ @@ -105,7 +103,6 @@ static struct nand_ecclayout fsl_elbc_oob_lp_eccm0 = { .eccbytes = 12, .eccpos = {6, 7, 8, 22, 23, 24, 38, 39, 40, 54, 55, 56}, .oobfree = { {1, 5}, {9, 13}, {25, 13}, {41, 13}, {57, 7} }, - .oobavail = 48, }; /* Large Page FLASH with FMR[ECCM] = 1 */ @@ -113,7 +110,48 @@ static struct nand_ecclayout fsl_elbc_oob_lp_eccm1 = { .eccbytes = 12, .eccpos = {8, 9, 10, 24, 25, 26, 40, 41, 42, 56, 57, 58}, .oobfree = { {1, 7}, {11, 13}, {27, 13}, {43, 13}, {59, 5} }, - .oobavail = 48, +}; + +/* + * fsl_elbc_oob_lp_eccm* specify that LP NAND's OOB free area starts at offset + * 1, so we have to adjust bad block pattern. This pattern should be used for + * x8 chips only. So far hardware does not support x16 chips anyway. + */ +static u8 scan_ff_pattern[] = { 0xff, }; + +static struct nand_bbt_descr largepage_memorybased = { + .options = 0, + .offs = 0, + .len = 1, + .pattern = scan_ff_pattern, +}; + +/* + * ELBC may use HW ECC, so that OOB offsets, that NAND core uses for bbt, + * interfere with ECC positions, that's why we implement our own descriptors. + * OOB {11, 5}, works for both SP and LP chips, with ECCM = 1 and ECCM = 0. + */ +static u8 bbt_pattern[] = {'B', 'b', 't', '0' }; +static u8 mirror_pattern[] = {'1', 't', 'b', 'B' }; + +static struct nand_bbt_descr bbt_main_descr = { + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | + NAND_BBT_2BIT | NAND_BBT_VERSION, + .offs = 11, + .len = 4, + .veroffs = 15, + .maxblocks = 4, + .pattern = bbt_pattern, +}; + +static struct nand_bbt_descr bbt_mirror_descr = { + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | + NAND_BBT_2BIT | NAND_BBT_VERSION, + .offs = 11, + .len = 4, + .veroffs = 15, + .maxblocks = 4, + .pattern = mirror_pattern, }; /*=================================*/ @@ -687,8 +725,7 @@ static int fsl_elbc_chip_init_tail(struct mtd_info *mtd) chip->ecc.layout = (priv->fmr & FMR_ECCM) ? &fsl_elbc_oob_lp_eccm1 : &fsl_elbc_oob_lp_eccm0; - mtd->ecclayout = chip->ecc.layout; - mtd->oobavail = chip->ecc.layout->oobavail; + chip->badblock_pattern = &largepage_memorybased; } } else { dev_err(ctrl->dev, @@ -752,8 +789,12 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv) chip->cmdfunc = fsl_elbc_cmdfunc; chip->waitfunc = fsl_elbc_wait; + chip->bbt_td = &bbt_main_descr; + chip->bbt_md = &bbt_mirror_descr; + /* set up nand options */ - chip->options = NAND_NO_READRDY | NAND_NO_AUTOINCR; + chip->options = NAND_NO_READRDY | NAND_NO_AUTOINCR | + NAND_USE_FLASH_BBT; chip->controller = &ctrl->controller; chip->priv = priv; @@ -795,8 +836,8 @@ static int fsl_elbc_chip_remove(struct fsl_elbc_mtd *priv) return 0; } -static int fsl_elbc_chip_probe(struct fsl_elbc_ctrl *ctrl, - struct device_node *node) +static int __devinit fsl_elbc_chip_probe(struct fsl_elbc_ctrl *ctrl, + struct device_node *node) { struct fsl_lbc_regs __iomem *lbc = ctrl->regs; struct fsl_elbc_mtd *priv; @@ -846,7 +887,7 @@ static int fsl_elbc_chip_probe(struct fsl_elbc_ctrl *ctrl, goto err; } - priv->mtd.name = kasprintf(GFP_KERNEL, "%x.flash", res.start); + priv->mtd.name = kasprintf(GFP_KERNEL, "%x.flash", (unsigned)res.start); if (!priv->mtd.name) { ret = -ENOMEM; goto err; @@ -917,7 +958,7 @@ static int __devinit fsl_elbc_ctrl_init(struct fsl_elbc_ctrl *ctrl) return 0; } -static int __devexit fsl_elbc_ctrl_remove(struct of_device *ofdev) +static int fsl_elbc_ctrl_remove(struct of_device *ofdev) { struct fsl_elbc_ctrl *ctrl = dev_get_drvdata(&ofdev->dev); int i; @@ -1041,7 +1082,7 @@ static struct of_platform_driver fsl_elbc_ctrl_driver = { }, .match_table = fsl_elbc_match, .probe = fsl_elbc_ctrl_probe, - .remove = __devexit_p(fsl_elbc_ctrl_remove), + .remove = fsl_elbc_ctrl_remove, }; static int __init fsl_elbc_init(void) diff --git a/drivers/mtd/nand/h1910.c b/drivers/mtd/nand/h1910.c index 2d585d2d090c..f8ce79b446ed 100644 --- a/drivers/mtd/nand/h1910.c +++ b/drivers/mtd/nand/h1910.c @@ -7,8 +7,6 @@ * Copyright (C) 2002 Marius Gröger (mag@sysgo.de) * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) * - * $Id: h1910.c,v 1.6 2005/11/07 11:14:30 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 * published by the Free Software Foundation. @@ -26,10 +24,10 @@ #include <linux/mtd/nand.h> #include <linux/mtd/partitions.h> #include <asm/io.h> -#include <asm/arch/hardware.h> /* for CLPS7111_VIRT_BASE */ +#include <mach/hardware.h> /* for CLPS7111_VIRT_BASE */ #include <asm/sizes.h> -#include <asm/arch/h1900-gpio.h> -#include <asm/arch/ipaq.h> +#include <mach/h1900-gpio.h> +#include <mach/ipaq.h> /* * MTD structure for EDB7312 board diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index ba1bdf787323..d1129bae6c27 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -798,6 +798,87 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, } /** + * nand_read_subpage - [REPLACABLE] software ecc based sub-page read function + * @mtd: mtd info structure + * @chip: nand chip info structure + * @dataofs offset of requested data within the page + * @readlen data length + * @buf: buffer to store read data + */ +static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi) +{ + int start_step, end_step, num_steps; + uint32_t *eccpos = chip->ecc.layout->eccpos; + uint8_t *p; + int data_col_addr, i, gaps = 0; + int datafrag_len, eccfrag_len, aligned_len, aligned_pos; + int busw = (chip->options & NAND_BUSWIDTH_16) ? 2 : 1; + + /* Column address wihin the page aligned to ECC size (256bytes). */ + start_step = data_offs / chip->ecc.size; + end_step = (data_offs + readlen - 1) / chip->ecc.size; + num_steps = end_step - start_step + 1; + + /* Data size aligned to ECC ecc.size*/ + datafrag_len = num_steps * chip->ecc.size; + eccfrag_len = num_steps * chip->ecc.bytes; + + data_col_addr = start_step * chip->ecc.size; + /* If we read not a page aligned data */ + if (data_col_addr != 0) + chip->cmdfunc(mtd, NAND_CMD_RNDOUT, data_col_addr, -1); + + p = bufpoi + data_col_addr; + chip->read_buf(mtd, p, datafrag_len); + + /* Calculate ECC */ + for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size) + chip->ecc.calculate(mtd, p, &chip->buffers->ecccalc[i]); + + /* The performance is faster if to position offsets + according to ecc.pos. Let make sure here that + there are no gaps in ecc positions */ + for (i = 0; i < eccfrag_len - 1; i++) { + if (eccpos[i + start_step * chip->ecc.bytes] + 1 != + eccpos[i + start_step * chip->ecc.bytes + 1]) { + gaps = 1; + break; + } + } + if (gaps) { + chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1); + chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); + } else { + /* send the command to read the particular ecc bytes */ + /* take care about buswidth alignment in read_buf */ + aligned_pos = eccpos[start_step * chip->ecc.bytes] & ~(busw - 1); + aligned_len = eccfrag_len; + if (eccpos[start_step * chip->ecc.bytes] & (busw - 1)) + aligned_len++; + if (eccpos[(start_step + num_steps) * chip->ecc.bytes] & (busw - 1)) + aligned_len++; + + chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize + aligned_pos, -1); + chip->read_buf(mtd, &chip->oob_poi[aligned_pos], aligned_len); + } + + for (i = 0; i < eccfrag_len; i++) + chip->buffers->ecccode[i] = chip->oob_poi[eccpos[i + start_step * chip->ecc.bytes]]; + + p = bufpoi + data_col_addr; + for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size) { + int stat; + + stat = chip->ecc.correct(mtd, p, &chip->buffers->ecccode[i], &chip->buffers->ecccalc[i]); + if (stat == -1) + mtd->ecc_stats.failed++; + else + mtd->ecc_stats.corrected += stat; + } + return 0; +} + +/** * nand_read_page_hwecc - [REPLACABLE] hardware ecc based page read function * @mtd: mtd info structure * @chip: nand chip info structure @@ -994,6 +1075,8 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, /* Now read the page into the buffer */ if (unlikely(ops->mode == MTD_OOB_RAW)) ret = chip->ecc.read_page_raw(mtd, chip, bufpoi); + else if (!aligned && NAND_SUBPAGE_READ(chip) && !oob) + ret = chip->ecc.read_subpage(mtd, chip, col, bytes, bufpoi); else ret = chip->ecc.read_page(mtd, chip, bufpoi); if (ret < 0) @@ -1001,7 +1084,8 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, /* Transfer not aligned data */ if (!aligned) { - chip->pagebuf = realpage; + if (!NAND_SUBPAGE_READ(chip) && !oob) + chip->pagebuf = realpage; memcpy(buf, chip->buffers->databuf + col, bytes); } @@ -2521,6 +2605,7 @@ int nand_scan_tail(struct mtd_info *mtd) chip->ecc.calculate = nand_calculate_ecc; chip->ecc.correct = nand_correct_data; chip->ecc.read_page = nand_read_page_swecc; + chip->ecc.read_subpage = nand_read_subpage; chip->ecc.write_page = nand_write_page_swecc; chip->ecc.read_oob = nand_read_oob_std; chip->ecc.write_oob = nand_write_oob_std; diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index 5e121ceaa598..0b1c48595f12 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -6,8 +6,6 @@ * * Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de) * - * $Id: nand_bbt.c,v 1.36 2005/11/07 11:14:30 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 * published by the Free Software Foundation. diff --git a/drivers/mtd/nand/nand_ecc.c b/drivers/mtd/nand/nand_ecc.c index 9003a135e050..918a806a8471 100644 --- a/drivers/mtd/nand/nand_ecc.c +++ b/drivers/mtd/nand/nand_ecc.c @@ -9,8 +9,6 @@ * * Copyright (C) 2006 Thomas Gleixner <tglx@linutronix.de> * - * $Id: nand_ecc.c,v 1.15 2005/11/07 11:14:30 gleixner Exp $ - * * This file 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 or (at your option) any diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c index a3e3ab0185d5..69ee2c90eb0b 100644 --- a/drivers/mtd/nand/nand_ids.c +++ b/drivers/mtd/nand/nand_ids.c @@ -3,8 +3,6 @@ * * Copyright (C) 2002 Thomas Gleixner (tglx@linutronix.de) * - * $Id: nand_ids.c,v 1.16 2005/11/07 11:14:31 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 * published by the Free Software Foundation. diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index bb885d1fcab5..556e8131ecdc 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c @@ -21,8 +21,6 @@ * 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: nandsim.c,v 1.8 2005/03/19 15:33:56 dedekind Exp $ */ #include <linux/init.h> @@ -30,6 +28,7 @@ #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/vmalloc.h> +#include <asm/div64.h> #include <linux/slab.h> #include <linux/errno.h> #include <linux/string.h> @@ -39,6 +38,7 @@ #include <linux/delay.h> #include <linux/list.h> #include <linux/random.h> +#include <asm/div64.h> /* Default simulator parameters values */ #if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE) || \ @@ -208,13 +208,16 @@ MODULE_PARM_DESC(overridesize, "Specifies the NAND Flash size overriding the I #define STATE_CMD_READID 0x0000000A /* read ID */ #define STATE_CMD_ERASE2 0x0000000B /* sector erase second command */ #define STATE_CMD_RESET 0x0000000C /* reset */ +#define STATE_CMD_RNDOUT 0x0000000D /* random output command */ +#define STATE_CMD_RNDOUTSTART 0x0000000E /* random output start command */ #define STATE_CMD_MASK 0x0000000F /* command states mask */ /* After an address is input, the simulator goes to one of these states */ #define STATE_ADDR_PAGE 0x00000010 /* full (row, column) address is accepted */ #define STATE_ADDR_SEC 0x00000020 /* sector address was accepted */ -#define STATE_ADDR_ZERO 0x00000030 /* one byte zero address was accepted */ -#define STATE_ADDR_MASK 0x00000030 /* address states mask */ +#define STATE_ADDR_COLUMN 0x00000030 /* column address was accepted */ +#define STATE_ADDR_ZERO 0x00000040 /* one byte zero address was accepted */ +#define STATE_ADDR_MASK 0x00000070 /* address states mask */ /* Durind data input/output the simulator is in these states */ #define STATE_DATAIN 0x00000100 /* waiting for data input */ @@ -241,7 +244,7 @@ MODULE_PARM_DESC(overridesize, "Specifies the NAND Flash size overriding the I #define ACTION_OOBOFF 0x00600000 /* add to address OOB offset */ #define ACTION_MASK 0x00700000 /* action mask */ -#define NS_OPER_NUM 12 /* Number of operations supported by the simulator */ +#define NS_OPER_NUM 13 /* Number of operations supported by the simulator */ #define NS_OPER_STATES 6 /* Maximum number of states in operation */ #define OPT_ANY 0xFFFFFFFF /* any chip supports this operation */ @@ -298,11 +301,11 @@ struct nandsim { /* NAND flash "geometry" */ struct nandsin_geometry { - uint32_t totsz; /* total flash size, bytes */ + uint64_t totsz; /* total flash size, bytes */ uint32_t secsz; /* flash sector (erase block) size, bytes */ uint pgsz; /* NAND flash page size, bytes */ uint oobsz; /* page OOB area size, bytes */ - uint32_t totszoob; /* total flash size including OOB, bytes */ + uint64_t totszoob; /* total flash size including OOB, bytes */ uint pgszoob; /* page size including OOB , bytes*/ uint secszoob; /* sector size including OOB, bytes */ uint pgnum; /* total number of pages */ @@ -374,7 +377,10 @@ static struct nandsim_operations { {OPT_ANY, {STATE_CMD_READID, STATE_ADDR_ZERO, STATE_DATAOUT_ID, STATE_READY}}, /* Large page devices read page */ {OPT_LARGEPAGE, {STATE_CMD_READ0, STATE_ADDR_PAGE, STATE_CMD_READSTART | ACTION_CPY, - STATE_DATAOUT, STATE_READY}} + STATE_DATAOUT, STATE_READY}}, + /* Large page devices random page read */ + {OPT_LARGEPAGE, {STATE_CMD_RNDOUT, STATE_ADDR_COLUMN, STATE_CMD_RNDOUTSTART | ACTION_CPY, + STATE_DATAOUT, STATE_READY}}, }; struct weak_block { @@ -459,6 +465,12 @@ static char *get_partition_name(int i) return kstrdup(buf, GFP_KERNEL); } +static u_int64_t divide(u_int64_t n, u_int32_t d) +{ + do_div(n, d); + return n; +} + /* * Initialize the nandsim structure. * @@ -469,8 +481,8 @@ static int init_nandsim(struct mtd_info *mtd) struct nand_chip *chip = (struct nand_chip *)mtd->priv; struct nandsim *ns = (struct nandsim *)(chip->priv); int i, ret = 0; - u_int32_t remains; - u_int32_t next_offset; + u_int64_t remains; + u_int64_t next_offset; if (NS_IS_INITIALIZED(ns)) { NS_ERR("init_nandsim: nandsim is already initialized\n"); @@ -487,8 +499,8 @@ static int init_nandsim(struct mtd_info *mtd) ns->geom.oobsz = mtd->oobsize; ns->geom.secsz = mtd->erasesize; ns->geom.pgszoob = ns->geom.pgsz + ns->geom.oobsz; - ns->geom.pgnum = ns->geom.totsz / ns->geom.pgsz; - ns->geom.totszoob = ns->geom.totsz + ns->geom.pgnum * ns->geom.oobsz; + ns->geom.pgnum = divide(ns->geom.totsz, ns->geom.pgsz); + ns->geom.totszoob = ns->geom.totsz + (uint64_t)ns->geom.pgnum * ns->geom.oobsz; ns->geom.secshift = ffs(ns->geom.secsz) - 1; ns->geom.pgshift = chip->page_shift; ns->geom.oobshift = ffs(ns->geom.oobsz) - 1; @@ -511,7 +523,7 @@ static int init_nandsim(struct mtd_info *mtd) } if (ns->options & OPT_SMALLPAGE) { - if (ns->geom.totsz < (32 << 20)) { + if (ns->geom.totsz <= (32 << 20)) { ns->geom.pgaddrbytes = 3; ns->geom.secaddrbytes = 2; } else { @@ -537,15 +549,16 @@ static int init_nandsim(struct mtd_info *mtd) remains = ns->geom.totsz; next_offset = 0; for (i = 0; i < parts_num; ++i) { - unsigned long part = parts[i]; - if (!part || part > remains / ns->geom.secsz) { + u_int64_t part_sz = (u_int64_t)parts[i] * ns->geom.secsz; + + if (!part_sz || part_sz > remains) { NS_ERR("bad partition size.\n"); ret = -EINVAL; goto error; } ns->partitions[i].name = get_partition_name(i); ns->partitions[i].offset = next_offset; - ns->partitions[i].size = part * ns->geom.secsz; + ns->partitions[i].size = part_sz; next_offset += ns->partitions[i].size; remains -= ns->partitions[i].size; } @@ -573,7 +586,8 @@ static int init_nandsim(struct mtd_info *mtd) if (ns->busw == 16) NS_WARN("16-bit flashes support wasn't tested\n"); - printk("flash size: %u MiB\n", ns->geom.totsz >> 20); + printk("flash size: %llu MiB\n", + (unsigned long long)ns->geom.totsz >> 20); printk("page size: %u bytes\n", ns->geom.pgsz); printk("OOB area size: %u bytes\n", ns->geom.oobsz); printk("sector size: %u KiB\n", ns->geom.secsz >> 10); @@ -582,8 +596,9 @@ static int init_nandsim(struct mtd_info *mtd) printk("bus width: %u\n", ns->busw); printk("bits in sector size: %u\n", ns->geom.secshift); printk("bits in page size: %u\n", ns->geom.pgshift); - printk("bits in OOB size: %u\n", ns->geom.oobshift); - printk("flash size with OOB: %u KiB\n", ns->geom.totszoob >> 10); + printk("bits in OOB size: %u\n", ns->geom.oobshift); + printk("flash size with OOB: %llu KiB\n", + (unsigned long long)ns->geom.totszoob >> 10); printk("page address bytes: %u\n", ns->geom.pgaddrbytes); printk("sector address bytes: %u\n", ns->geom.secaddrbytes); printk("options: %#x\n", ns->options); @@ -825,7 +840,7 @@ static int setup_wear_reporting(struct mtd_info *mtd) if (!rptwear) return 0; - wear_eb_count = mtd->size / mtd->erasesize; + wear_eb_count = divide(mtd->size, mtd->erasesize); mem = wear_eb_count * sizeof(unsigned long); if (mem / sizeof(unsigned long) != wear_eb_count) { NS_ERR("Too many erase blocks for wear reporting\n"); @@ -931,12 +946,18 @@ static char *get_state_name(uint32_t state) return "STATE_CMD_ERASE2"; case STATE_CMD_RESET: return "STATE_CMD_RESET"; + case STATE_CMD_RNDOUT: + return "STATE_CMD_RNDOUT"; + case STATE_CMD_RNDOUTSTART: + return "STATE_CMD_RNDOUTSTART"; case STATE_ADDR_PAGE: return "STATE_ADDR_PAGE"; case STATE_ADDR_SEC: return "STATE_ADDR_SEC"; case STATE_ADDR_ZERO: return "STATE_ADDR_ZERO"; + case STATE_ADDR_COLUMN: + return "STATE_ADDR_COLUMN"; case STATE_DATAIN: return "STATE_DATAIN"; case STATE_DATAOUT: @@ -967,6 +988,7 @@ static int check_command(int cmd) switch (cmd) { case NAND_CMD_READ0: + case NAND_CMD_READ1: case NAND_CMD_READSTART: case NAND_CMD_PAGEPROG: case NAND_CMD_READOOB: @@ -976,7 +998,8 @@ static int check_command(int cmd) case NAND_CMD_READID: case NAND_CMD_ERASE2: case NAND_CMD_RESET: - case NAND_CMD_READ1: + case NAND_CMD_RNDOUT: + case NAND_CMD_RNDOUTSTART: return 0; case NAND_CMD_STATUS_MULTI: @@ -1015,6 +1038,10 @@ static uint32_t get_state_by_command(unsigned command) return STATE_CMD_ERASE2; case NAND_CMD_RESET: return STATE_CMD_RESET; + case NAND_CMD_RNDOUT: + return STATE_CMD_RNDOUT; + case NAND_CMD_RNDOUTSTART: + return STATE_CMD_RNDOUTSTART; } NS_ERR("get_state_by_command: unknown command, BUG\n"); @@ -1576,6 +1603,11 @@ static void switch_state(struct nandsim *ns) ns->regs.num = 1; break; + case STATE_ADDR_COLUMN: + /* Column address is always 2 bytes */ + ns->regs.num = ns->geom.pgaddrbytes - ns->geom.secaddrbytes; + break; + default: NS_ERR("switch_state: BUG! unknown address state\n"); } @@ -1687,15 +1719,21 @@ static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte) return; } - /* - * Chip might still be in STATE_DATAOUT - * (if OPT_AUTOINCR feature is supported), STATE_DATAOUT_STATUS or - * STATE_DATAOUT_STATUS_M state. If so, switch state. - */ + /* Check that the command byte is correct */ + if (check_command(byte)) { + NS_ERR("write_byte: unknown command %#x\n", (uint)byte); + return; + } + if (NS_STATE(ns->state) == STATE_DATAOUT_STATUS || NS_STATE(ns->state) == STATE_DATAOUT_STATUS_M - || ((ns->options & OPT_AUTOINCR) && NS_STATE(ns->state) == STATE_DATAOUT)) + || NS_STATE(ns->state) == STATE_DATAOUT) { + int row = ns->regs.row; + switch_state(ns); + if (byte == NAND_CMD_RNDOUT) + ns->regs.row = row; + } /* Check if chip is expecting command */ if (NS_STATE(ns->nxstate) != STATE_UNKNOWN && !(ns->nxstate & STATE_CMD_MASK)) { @@ -1709,12 +1747,6 @@ static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte) switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); } - /* Check that the command byte is correct */ - if (check_command(byte)) { - NS_ERR("write_byte: unknown command %#x\n", (uint)byte); - return; - } - NS_DBG("command byte corresponding to %s state accepted\n", get_state_name(get_state_by_command(byte))); ns->regs.command = byte; @@ -2013,7 +2045,7 @@ static int __init ns_init_module(void) } if (overridesize) { - u_int32_t new_size = nsmtd->erasesize << overridesize; + u_int64_t new_size = (u_int64_t)nsmtd->erasesize << overridesize; if (new_size >> overridesize != nsmtd->erasesize) { NS_ERR("overridesize is too big\n"); goto err_exit; @@ -2021,7 +2053,8 @@ static int __init ns_init_module(void) /* N.B. This relies on nand_scan not doing anything with the size before we change it */ nsmtd->size = new_size; chip->chipsize = new_size; - chip->chip_shift = ffs(new_size) - 1; + chip->chip_shift = ffs(nsmtd->erasesize) + overridesize - 1; + chip->pagemask = (chip->chipsize >> chip->page_shift) - 1; } if ((retval = setup_wear_reporting(nsmtd)) != 0) diff --git a/drivers/mtd/nand/orion_nand.c b/drivers/mtd/nand/orion_nand.c index ee2ac3948cd8..917cf8d3ae95 100644 --- a/drivers/mtd/nand/orion_nand.c +++ b/drivers/mtd/nand/orion_nand.c @@ -18,8 +18,8 @@ #include <linux/mtd/partitions.h> #include <asm/io.h> #include <asm/sizes.h> -#include <asm/arch/hardware.h> -#include <asm/plat-orion/orion_nand.h> +#include <mach/hardware.h> +#include <plat/orion_nand.h> #ifdef CONFIG_MTD_CMDLINE_PARTS static const char *part_probes[] = { "cmdlinepart", NULL }; diff --git a/drivers/mtd/nand/ppchameleonevb.c b/drivers/mtd/nand/ppchameleonevb.c index 082073acf20f..cc8658431851 100644 --- a/drivers/mtd/nand/ppchameleonevb.c +++ b/drivers/mtd/nand/ppchameleonevb.c @@ -6,8 +6,6 @@ * Derived from drivers/mtd/nand/edb7312.c * * - * $Id: ppchameleonevb.c,v 1.7 2005/11/07 11:14:31 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 * published by the Free Software Foundation. diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index fe2bc7e42119..a64ad15b8fdd 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -22,8 +22,8 @@ #include <linux/irq.h> #include <asm/dma.h> -#include <asm/arch/pxa-regs.h> -#include <asm/arch/pxa3xx_nand.h> +#include <mach/pxa-regs.h> +#include <mach/pxa3xx_nand.h> #define CHIP_DELAY_TIMEOUT (2 * HZ/10) diff --git a/drivers/mtd/nand/rtc_from4.c b/drivers/mtd/nand/rtc_from4.c index 26f88215bc47..a033c4cd8e16 100644 --- a/drivers/mtd/nand/rtc_from4.c +++ b/drivers/mtd/nand/rtc_from4.c @@ -6,8 +6,6 @@ * Derived from drivers/mtd/nand/spia.c * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) * - * $Id: rtc_from4.c,v 1.10 2005/11/07 11:14:31 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 * published by the Free Software Foundation. diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index b34a460ab679..556139ed1fdf 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c @@ -1,26 +1,10 @@ /* linux/drivers/mtd/nand/s3c2410.c * - * Copyright (c) 2004,2005 Simtec Electronics - * http://www.simtec.co.uk/products/SWLINUX/ + * Copyright © 2004-2008 Simtec Electronics + * http://armlinux.simtec.co.uk/ * Ben Dooks <ben@simtec.co.uk> * - * Samsung S3C2410/S3C240 NAND driver - * - * Changelog: - * 21-Sep-2004 BJD Initial version - * 23-Sep-2004 BJD Multiple 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 - * 02-May-2005 BJD Fixed s3c2440 support - * 02-May-2005 BJD Reduced hwcontrol decode - * 20-Jun-2005 BJD Updated s3c2440 support, fixed timing bug - * 08-Jul-2005 BJD Fix OOPS when no platform data supplied - * 20-Oct-2005 BJD Fix timing calculation bug - * 14-Jan-2006 BJD Allow clock to be stopped when idle - * - * $Id: s3c2410.c,v 1.23 2006/04/01 18:06:29 bjd Exp $ + * Samsung S3C2410/S3C2440/S3C2412 NAND driver * * 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 @@ -52,6 +36,7 @@ #include <linux/err.h> #include <linux/slab.h> #include <linux/clk.h> +#include <linux/cpufreq.h> #include <linux/mtd/mtd.h> #include <linux/mtd/nand.h> @@ -120,8 +105,13 @@ struct s3c2410_nand_info { int sel_bit; int mtd_count; unsigned long save_sel; + unsigned long clk_rate; enum s3c_cpu_type cpu_type; + +#ifdef CONFIG_CPU_FREQ + struct notifier_block freq_transition; +#endif }; /* conversion functions */ @@ -179,17 +169,18 @@ static int s3c_nand_calc_rate(int wanted, unsigned long clk, int max) /* controller setup */ -static int s3c2410_nand_inithw(struct s3c2410_nand_info *info, - struct platform_device *pdev) +static int s3c2410_nand_setrate(struct s3c2410_nand_info *info) { - struct s3c2410_platform_nand *plat = to_nand_plat(pdev); - unsigned long clkrate = clk_get_rate(info->clk); + struct s3c2410_platform_nand *plat = info->platform; int tacls_max = (info->cpu_type == TYPE_S3C2412) ? 8 : 4; int tacls, twrph0, twrph1; - unsigned long cfg = 0; + unsigned long clkrate = clk_get_rate(info->clk); + unsigned long set, cfg, mask; + unsigned long flags; /* calculate the timing information for the controller */ + info->clk_rate = clkrate; clkrate /= 1000; /* turn clock into kHz for ease of use */ if (plat != NULL) { @@ -211,28 +202,69 @@ static int s3c2410_nand_inithw(struct s3c2410_nand_info *info, dev_info(info->device, "Tacls=%d, %dns Twrph0=%d %dns, Twrph1=%d %dns\n", tacls, to_ns(tacls, clkrate), twrph0, to_ns(twrph0, clkrate), twrph1, to_ns(twrph1, clkrate)); + switch (info->cpu_type) { + case TYPE_S3C2410: + mask = (S3C2410_NFCONF_TACLS(3) | + S3C2410_NFCONF_TWRPH0(7) | + S3C2410_NFCONF_TWRPH1(7)); + set = S3C2410_NFCONF_EN; + set |= S3C2410_NFCONF_TACLS(tacls - 1); + set |= S3C2410_NFCONF_TWRPH0(twrph0 - 1); + set |= S3C2410_NFCONF_TWRPH1(twrph1 - 1); + break; + + case TYPE_S3C2440: + case TYPE_S3C2412: + mask = (S3C2410_NFCONF_TACLS(tacls_max - 1) | + S3C2410_NFCONF_TWRPH0(7) | + S3C2410_NFCONF_TWRPH1(7)); + + set = S3C2440_NFCONF_TACLS(tacls - 1); + set |= S3C2440_NFCONF_TWRPH0(twrph0 - 1); + set |= S3C2440_NFCONF_TWRPH1(twrph1 - 1); + break; + + default: + /* keep compiler happy */ + mask = 0; + set = 0; + BUG(); + } + + dev_dbg(info->device, "NF_CONF is 0x%lx\n", cfg); + + local_irq_save(flags); + + cfg = readl(info->regs + S3C2410_NFCONF); + cfg &= ~mask; + cfg |= set; + writel(cfg, info->regs + S3C2410_NFCONF); + + local_irq_restore(flags); + + return 0; +} + +static int s3c2410_nand_inithw(struct s3c2410_nand_info *info) +{ + int ret; + + ret = s3c2410_nand_setrate(info); + if (ret < 0) + return ret; + switch (info->cpu_type) { case TYPE_S3C2410: - cfg = S3C2410_NFCONF_EN; - cfg |= S3C2410_NFCONF_TACLS(tacls - 1); - cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1); - cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1); + default: break; case TYPE_S3C2440: case TYPE_S3C2412: - cfg = S3C2440_NFCONF_TACLS(tacls - 1); - cfg |= S3C2440_NFCONF_TWRPH0(twrph0 - 1); - cfg |= S3C2440_NFCONF_TWRPH1(twrph1 - 1); - /* enable the controller and de-assert nFCE */ writel(S3C2440_NFCONT_ENABLE, info->regs + S3C2440_NFCONT); } - dev_dbg(info->device, "NF_CONF is 0x%lx\n", cfg); - - writel(cfg, info->regs + S3C2410_NFCONF); return 0; } @@ -513,6 +545,52 @@ static void s3c2440_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int writesl(info->regs + S3C2440_NFDATA, buf, len / 4); } +/* cpufreq driver support */ + +#ifdef CONFIG_CPU_FREQ + +static int s3c2410_nand_cpufreq_transition(struct notifier_block *nb, + unsigned long val, void *data) +{ + struct s3c2410_nand_info *info; + unsigned long newclk; + + info = container_of(nb, struct s3c2410_nand_info, freq_transition); + newclk = clk_get_rate(info->clk); + + if ((val == CPUFREQ_POSTCHANGE && newclk < info->clk_rate) || + (val == CPUFREQ_PRECHANGE && newclk > info->clk_rate)) { + s3c2410_nand_setrate(info); + } + + return 0; +} + +static inline int s3c2410_nand_cpufreq_register(struct s3c2410_nand_info *info) +{ + info->freq_transition.notifier_call = s3c2410_nand_cpufreq_transition; + + return cpufreq_register_notifier(&info->freq_transition, + CPUFREQ_TRANSITION_NOTIFIER); +} + +static inline void s3c2410_nand_cpufreq_deregister(struct s3c2410_nand_info *info) +{ + cpufreq_unregister_notifier(&info->freq_transition, + CPUFREQ_TRANSITION_NOTIFIER); +} + +#else +static inline int s3c2410_nand_cpufreq_register(struct s3c2410_nand_info *info) +{ + return 0; +} + +static inline void s3c2410_nand_cpufreq_deregister(struct s3c2410_nand_info *info) +{ +} +#endif + /* device management functions */ static int s3c2410_nand_remove(struct platform_device *pdev) @@ -524,9 +602,10 @@ static int s3c2410_nand_remove(struct platform_device *pdev) if (info == NULL) return 0; - /* first thing we need to do is release all our mtds - * and their partitions, then go through freeing the - * resources used + s3c2410_nand_cpufreq_deregister(info); + + /* Release all our mtds and their partitions, then go through + * freeing the resources used */ if (info->mtds != NULL) { @@ -691,7 +770,8 @@ static void s3c2410_nand_update_chip(struct s3c2410_nand_info *info, { struct nand_chip *chip = &nmtd->chip; - printk("%s: chip %p: %d\n", __func__, chip, chip->page_shift); + dev_dbg(info->device, "chip %p => page shift %d\n", + chip, chip->page_shift); if (hardware_ecc) { /* change the behaviour depending on wether we are using @@ -784,7 +864,7 @@ static int s3c24xx_nand_probe(struct platform_device *pdev, /* initialise the hardware */ - err = s3c2410_nand_inithw(info, pdev); + err = s3c2410_nand_inithw(info); if (err != 0) goto exit_error; @@ -827,6 +907,12 @@ static int s3c24xx_nand_probe(struct platform_device *pdev, sets++; } + err = s3c2410_nand_cpufreq_register(info); + if (err < 0) { + dev_err(&pdev->dev, "failed to init cpufreq support\n"); + goto exit_error; + } + if (allow_clk_stop(info)) { dev_info(&pdev->dev, "clock idle support enabled\n"); clk_disable(info->clk); @@ -874,7 +960,7 @@ static int s3c24xx_nand_resume(struct platform_device *dev) if (info) { clk_enable(info->clk); - s3c2410_nand_inithw(info, dev); + s3c2410_nand_inithw(info); /* Restore the state of the nFCE line. */ diff --git a/drivers/mtd/nand/sharpsl.c b/drivers/mtd/nand/sharpsl.c index 033f8800b1e6..30a518e211bd 100644 --- a/drivers/mtd/nand/sharpsl.c +++ b/drivers/mtd/nand/sharpsl.c @@ -3,8 +3,6 @@ * * Copyright (C) 2004 Richard Purdie * - * $Id: sharpsl.c,v 1.7 2005/11/07 11:14:31 gleixner Exp $ - * * Based on Sharp's NAND driver sharp_sl.c * * This program is free software; you can redistribute it and/or modify @@ -23,7 +21,7 @@ #include <linux/mtd/partitions.h> #include <linux/interrupt.h> #include <asm/io.h> -#include <asm/hardware.h> +#include <mach/hardware.h> #include <asm/mach-types.h> static void __iomem *sharpsl_io_base; diff --git a/drivers/mtd/nand/spia.c b/drivers/mtd/nand/spia.c index 1f6d429b1583..0cc6d0acb8fe 100644 --- a/drivers/mtd/nand/spia.c +++ b/drivers/mtd/nand/spia.c @@ -8,8 +8,6 @@ * to controllines (due to change in nand.c) * page_cache added * - * $Id: spia.c,v 1.25 2005/11/07 11:14:31 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 * published by the Free Software Foundation. diff --git a/drivers/mtd/nand/tmio_nand.c b/drivers/mtd/nand/tmio_nand.c new file mode 100644 index 000000000000..edb1e322113d --- /dev/null +++ b/drivers/mtd/nand/tmio_nand.c @@ -0,0 +1,556 @@ +/* + * Toshiba TMIO NAND flash controller driver + * + * Slightly murky pre-git history of the driver: + * + * Copyright (c) Ian Molton 2004, 2005, 2008 + * Original work, independant of sharps code. Included hardware ECC support. + * Hard ECC did not work for writes in the early revisions. + * Copyright (c) Dirk Opfer 2005. + * Modifications developed from sharps code but + * NOT containing any, ported onto Ians base. + * Copyright (c) Chris Humbert 2005 + * Copyright (c) Dmitry Baryshkov 2008 + * Minor fixes + * + * Parts copyright Sebastian Carlier + * + * This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + * + */ + + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/mfd/core.h> +#include <linux/mfd/tmio.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/interrupt.h> +#include <linux/ioport.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> +#include <linux/mtd/nand_ecc.h> +#include <linux/mtd/partitions.h> + +/*--------------------------------------------------------------------------*/ + +/* + * NAND Flash Host Controller Configuration Register + */ +#define CCR_COMMAND 0x04 /* w Command */ +#define CCR_BASE 0x10 /* l NAND Flash Control Reg Base Addr */ +#define CCR_INTP 0x3d /* b Interrupt Pin */ +#define CCR_INTE 0x48 /* b Interrupt Enable */ +#define CCR_EC 0x4a /* b Event Control */ +#define CCR_ICC 0x4c /* b Internal Clock Control */ +#define CCR_ECCC 0x5b /* b ECC Control */ +#define CCR_NFTC 0x60 /* b NAND Flash Transaction Control */ +#define CCR_NFM 0x61 /* b NAND Flash Monitor */ +#define CCR_NFPSC 0x62 /* b NAND Flash Power Supply Control */ +#define CCR_NFDC 0x63 /* b NAND Flash Detect Control */ + +/* + * NAND Flash Control Register + */ +#define FCR_DATA 0x00 /* bwl Data Register */ +#define FCR_MODE 0x04 /* b Mode Register */ +#define FCR_STATUS 0x05 /* b Status Register */ +#define FCR_ISR 0x06 /* b Interrupt Status Register */ +#define FCR_IMR 0x07 /* b Interrupt Mask Register */ + +/* FCR_MODE Register Command List */ +#define FCR_MODE_DATA 0x94 /* Data Data_Mode */ +#define FCR_MODE_COMMAND 0x95 /* Data Command_Mode */ +#define FCR_MODE_ADDRESS 0x96 /* Data Address_Mode */ + +#define FCR_MODE_HWECC_CALC 0xB4 /* HW-ECC Data */ +#define FCR_MODE_HWECC_RESULT 0xD4 /* HW-ECC Calc result Read_Mode */ +#define FCR_MODE_HWECC_RESET 0xF4 /* HW-ECC Reset */ + +#define FCR_MODE_POWER_ON 0x0C /* Power Supply ON to SSFDC card */ +#define FCR_MODE_POWER_OFF 0x08 /* Power Supply OFF to SSFDC card */ + +#define FCR_MODE_LED_OFF 0x00 /* LED OFF */ +#define FCR_MODE_LED_ON 0x04 /* LED ON */ + +#define FCR_MODE_EJECT_ON 0x68 /* Ejection events active */ +#define FCR_MODE_EJECT_OFF 0x08 /* Ejection events ignored */ + +#define FCR_MODE_LOCK 0x6C /* Lock_Mode. Eject Switch Invalid */ +#define FCR_MODE_UNLOCK 0x0C /* UnLock_Mode. Eject Switch is valid */ + +#define FCR_MODE_CONTROLLER_ID 0x40 /* Controller ID Read */ +#define FCR_MODE_STANDBY 0x00 /* SSFDC card Changes Standby State */ + +#define FCR_MODE_WE 0x80 +#define FCR_MODE_ECC1 0x40 +#define FCR_MODE_ECC0 0x20 +#define FCR_MODE_CE 0x10 +#define FCR_MODE_PCNT1 0x08 +#define FCR_MODE_PCNT0 0x04 +#define FCR_MODE_ALE 0x02 +#define FCR_MODE_CLE 0x01 + +#define FCR_STATUS_BUSY 0x80 + +/*--------------------------------------------------------------------------*/ + +struct tmio_nand { + struct mtd_info mtd; + struct nand_chip chip; + + struct platform_device *dev; + + void __iomem *ccr; + void __iomem *fcr; + unsigned long fcr_base; + + unsigned int irq; + + /* for tmio_nand_read_byte */ + u8 read; + unsigned read_good:1; +}; + +#define mtd_to_tmio(m) container_of(m, struct tmio_nand, mtd) + +#ifdef CONFIG_MTD_CMDLINE_PARTS +static const char *part_probes[] = { "cmdlinepart", NULL }; +#endif + +/*--------------------------------------------------------------------------*/ + +static void tmio_nand_hwcontrol(struct mtd_info *mtd, int cmd, + unsigned int ctrl) +{ + struct tmio_nand *tmio = mtd_to_tmio(mtd); + struct nand_chip *chip = mtd->priv; + + if (ctrl & NAND_CTRL_CHANGE) { + u8 mode; + + if (ctrl & NAND_NCE) { + mode = FCR_MODE_DATA; + + if (ctrl & NAND_CLE) + mode |= FCR_MODE_CLE; + else + mode &= ~FCR_MODE_CLE; + + if (ctrl & NAND_ALE) + mode |= FCR_MODE_ALE; + else + mode &= ~FCR_MODE_ALE; + } else { + mode = FCR_MODE_STANDBY; + } + + tmio_iowrite8(mode, tmio->fcr + FCR_MODE); + tmio->read_good = 0; + } + + if (cmd != NAND_CMD_NONE) + tmio_iowrite8(cmd, chip->IO_ADDR_W); +} + +static int tmio_nand_dev_ready(struct mtd_info *mtd) +{ + struct tmio_nand *tmio = mtd_to_tmio(mtd); + + return !(tmio_ioread8(tmio->fcr + FCR_STATUS) & FCR_STATUS_BUSY); +} + +static irqreturn_t tmio_irq(int irq, void *__tmio) +{ + struct tmio_nand *tmio = __tmio; + struct nand_chip *nand_chip = &tmio->chip; + + /* disable RDYREQ interrupt */ + tmio_iowrite8(0x00, tmio->fcr + FCR_IMR); + + if (unlikely(!waitqueue_active(&nand_chip->controller->wq))) + dev_warn(&tmio->dev->dev, "spurious interrupt\n"); + + wake_up(&nand_chip->controller->wq); + return IRQ_HANDLED; +} + +/* + *The TMIO core has a RDYREQ interrupt on the posedge of #SMRB. + *This interrupt is normally disabled, but for long operations like + *erase and write, we enable it to wake us up. The irq handler + *disables the interrupt. + */ +static int +tmio_nand_wait(struct mtd_info *mtd, struct nand_chip *nand_chip) +{ + struct tmio_nand *tmio = mtd_to_tmio(mtd); + long timeout; + + /* enable RDYREQ interrupt */ + tmio_iowrite8(0x0f, tmio->fcr + FCR_ISR); + tmio_iowrite8(0x81, tmio->fcr + FCR_IMR); + + timeout = wait_event_timeout(nand_chip->controller->wq, + tmio_nand_dev_ready(mtd), + msecs_to_jiffies(nand_chip->state == FL_ERASING ? 400 : 20)); + + if (unlikely(!tmio_nand_dev_ready(mtd))) { + tmio_iowrite8(0x00, tmio->fcr + FCR_IMR); + dev_warn(&tmio->dev->dev, "still busy with %s after %d ms\n", + nand_chip->state == FL_ERASING ? "erase" : "program", + nand_chip->state == FL_ERASING ? 400 : 20); + + } else if (unlikely(!timeout)) { + tmio_iowrite8(0x00, tmio->fcr + FCR_IMR); + dev_warn(&tmio->dev->dev, "timeout waiting for interrupt\n"); + } + + nand_chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); + return nand_chip->read_byte(mtd); +} + +/* + *The TMIO controller combines two 8-bit data bytes into one 16-bit + *word. This function separates them so nand_base.c works as expected, + *especially its NAND_CMD_READID routines. + * + *To prevent stale data from being read, tmio_nand_hwcontrol() clears + *tmio->read_good. + */ +static u_char tmio_nand_read_byte(struct mtd_info *mtd) +{ + struct tmio_nand *tmio = mtd_to_tmio(mtd); + unsigned int data; + + if (tmio->read_good--) + return tmio->read; + + data = tmio_ioread16(tmio->fcr + FCR_DATA); + tmio->read = data >> 8; + return data; +} + +/* + *The TMIO controller converts an 8-bit NAND interface to a 16-bit + *bus interface, so all data reads and writes must be 16-bit wide. + *Thus, we implement 16-bit versions of the read, write, and verify + *buffer functions. + */ +static void +tmio_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) +{ + struct tmio_nand *tmio = mtd_to_tmio(mtd); + + tmio_iowrite16_rep(tmio->fcr + FCR_DATA, buf, len >> 1); +} + +static void tmio_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) +{ + struct tmio_nand *tmio = mtd_to_tmio(mtd); + + tmio_ioread16_rep(tmio->fcr + FCR_DATA, buf, len >> 1); +} + +static int +tmio_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len) +{ + struct tmio_nand *tmio = mtd_to_tmio(mtd); + u16 *p = (u16 *) buf; + + for (len >>= 1; len; len--) + if (*(p++) != tmio_ioread16(tmio->fcr + FCR_DATA)) + return -EFAULT; + return 0; +} + +static void tmio_nand_enable_hwecc(struct mtd_info *mtd, int mode) +{ + struct tmio_nand *tmio = mtd_to_tmio(mtd); + + tmio_iowrite8(FCR_MODE_HWECC_RESET, tmio->fcr + FCR_MODE); + tmio_ioread8(tmio->fcr + FCR_DATA); /* dummy read */ + tmio_iowrite8(FCR_MODE_HWECC_CALC, tmio->fcr + FCR_MODE); +} + +static int tmio_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, + u_char *ecc_code) +{ + struct tmio_nand *tmio = mtd_to_tmio(mtd); + unsigned int ecc; + + tmio_iowrite8(FCR_MODE_HWECC_RESULT, tmio->fcr + FCR_MODE); + + ecc = tmio_ioread16(tmio->fcr + FCR_DATA); + ecc_code[1] = ecc; /* 000-255 LP7-0 */ + ecc_code[0] = ecc >> 8; /* 000-255 LP15-8 */ + ecc = tmio_ioread16(tmio->fcr + FCR_DATA); + ecc_code[2] = ecc; /* 000-255 CP5-0,11b */ + ecc_code[4] = ecc >> 8; /* 256-511 LP7-0 */ + ecc = tmio_ioread16(tmio->fcr + FCR_DATA); + ecc_code[3] = ecc; /* 256-511 LP15-8 */ + ecc_code[5] = ecc >> 8; /* 256-511 CP5-0,11b */ + + tmio_iowrite8(FCR_MODE_DATA, tmio->fcr + FCR_MODE); + return 0; +} + +static int tmio_hw_init(struct platform_device *dev, struct tmio_nand *tmio) +{ + struct mfd_cell *cell = (struct mfd_cell *)dev->dev.platform_data; + int ret; + + if (cell->enable) { + ret = cell->enable(dev); + if (ret) + return ret; + } + + /* (4Ch) CLKRUN Enable 1st spcrunc */ + tmio_iowrite8(0x81, tmio->ccr + CCR_ICC); + + /* (10h)BaseAddress 0x1000 spba.spba2 */ + tmio_iowrite16(tmio->fcr_base, tmio->ccr + CCR_BASE); + tmio_iowrite16(tmio->fcr_base >> 16, tmio->ccr + CCR_BASE + 2); + + /* (04h)Command Register I/O spcmd */ + tmio_iowrite8(0x02, tmio->ccr + CCR_COMMAND); + + /* (62h) Power Supply Control ssmpwc */ + /* HardPowerOFF - SuspendOFF - PowerSupplyWait_4MS */ + tmio_iowrite8(0x02, tmio->ccr + CCR_NFPSC); + + /* (63h) Detect Control ssmdtc */ + tmio_iowrite8(0x02, tmio->ccr + CCR_NFDC); + + /* Interrupt status register clear sintst */ + tmio_iowrite8(0x0f, tmio->fcr + FCR_ISR); + + /* After power supply, Media are reset smode */ + tmio_iowrite8(FCR_MODE_POWER_ON, tmio->fcr + FCR_MODE); + tmio_iowrite8(FCR_MODE_COMMAND, tmio->fcr + FCR_MODE); + tmio_iowrite8(NAND_CMD_RESET, tmio->fcr + FCR_DATA); + + /* Standby Mode smode */ + tmio_iowrite8(FCR_MODE_STANDBY, tmio->fcr + FCR_MODE); + + mdelay(5); + + return 0; +} + +static void tmio_hw_stop(struct platform_device *dev, struct tmio_nand *tmio) +{ + struct mfd_cell *cell = (struct mfd_cell *)dev->dev.platform_data; + + tmio_iowrite8(FCR_MODE_POWER_OFF, tmio->fcr + FCR_MODE); + if (cell->disable) + cell->disable(dev); +} + +static int tmio_probe(struct platform_device *dev) +{ + struct mfd_cell *cell = (struct mfd_cell *)dev->dev.platform_data; + struct tmio_nand_data *data = cell->driver_data; + struct resource *fcr = platform_get_resource(dev, + IORESOURCE_MEM, 0); + struct resource *ccr = platform_get_resource(dev, + IORESOURCE_MEM, 1); + int irq = platform_get_irq(dev, 0); + struct tmio_nand *tmio; + struct mtd_info *mtd; + struct nand_chip *nand_chip; +#ifdef CONFIG_MTD_PARTITIONS + struct mtd_partition *parts; + int nbparts = 0; +#endif + int retval; + + if (data == NULL) + dev_warn(&dev->dev, "NULL platform data!\n"); + + tmio = kzalloc(sizeof *tmio, GFP_KERNEL); + if (!tmio) { + retval = -ENOMEM; + goto err_kzalloc; + } + + tmio->dev = dev; + + platform_set_drvdata(dev, tmio); + mtd = &tmio->mtd; + nand_chip = &tmio->chip; + mtd->priv = nand_chip; + mtd->name = "tmio-nand"; + + tmio->ccr = ioremap(ccr->start, ccr->end - ccr->start + 1); + if (!tmio->ccr) { + retval = -EIO; + goto err_iomap_ccr; + } + + tmio->fcr_base = fcr->start & 0xfffff; + tmio->fcr = ioremap(fcr->start, fcr->end - fcr->start + 1); + if (!tmio->fcr) { + retval = -EIO; + goto err_iomap_fcr; + } + + retval = tmio_hw_init(dev, tmio); + if (retval) + goto err_hwinit; + + /* Set address of NAND IO lines */ + nand_chip->IO_ADDR_R = tmio->fcr; + nand_chip->IO_ADDR_W = tmio->fcr; + + /* Set address of hardware control function */ + nand_chip->cmd_ctrl = tmio_nand_hwcontrol; + nand_chip->dev_ready = tmio_nand_dev_ready; + nand_chip->read_byte = tmio_nand_read_byte; + nand_chip->write_buf = tmio_nand_write_buf; + nand_chip->read_buf = tmio_nand_read_buf; + nand_chip->verify_buf = tmio_nand_verify_buf; + + /* set eccmode using hardware ECC */ + nand_chip->ecc.mode = NAND_ECC_HW; + nand_chip->ecc.size = 512; + nand_chip->ecc.bytes = 6; + nand_chip->ecc.hwctl = tmio_nand_enable_hwecc; + nand_chip->ecc.calculate = tmio_nand_calculate_ecc; + nand_chip->ecc.correct = nand_correct_data; + + if (data) + nand_chip->badblock_pattern = data->badblock_pattern; + + /* 15 us command delay time */ + nand_chip->chip_delay = 15; + + retval = request_irq(irq, &tmio_irq, + IRQF_DISABLED, dev->dev.bus_id, tmio); + if (retval) { + dev_err(&dev->dev, "request_irq error %d\n", retval); + goto err_irq; + } + + tmio->irq = irq; + nand_chip->waitfunc = tmio_nand_wait; + + /* Scan to find existence of the device */ + if (nand_scan(mtd, 1)) { + retval = -ENODEV; + goto err_scan; + } + /* Register the partitions */ +#ifdef CONFIG_MTD_PARTITIONS +#ifdef CONFIG_MTD_CMDLINE_PARTS + nbparts = parse_mtd_partitions(mtd, part_probes, &parts, 0); +#endif + if (nbparts <= 0 && data) { + parts = data->partition; + nbparts = data->num_partitions; + } + + if (nbparts) + retval = add_mtd_partitions(mtd, parts, nbparts); + else +#endif + retval = add_mtd_device(mtd); + + if (!retval) + return retval; + + nand_release(mtd); + +err_scan: + if (tmio->irq) + free_irq(tmio->irq, tmio); +err_irq: + tmio_hw_stop(dev, tmio); +err_hwinit: + iounmap(tmio->fcr); +err_iomap_fcr: + iounmap(tmio->ccr); +err_iomap_ccr: + kfree(tmio); +err_kzalloc: + return retval; +} + +static int tmio_remove(struct platform_device *dev) +{ + struct tmio_nand *tmio = platform_get_drvdata(dev); + + nand_release(&tmio->mtd); + if (tmio->irq) + free_irq(tmio->irq, tmio); + tmio_hw_stop(dev, tmio); + iounmap(tmio->fcr); + iounmap(tmio->ccr); + kfree(tmio); + return 0; +} + +#ifdef CONFIG_PM +static int tmio_suspend(struct platform_device *dev, pm_message_t state) +{ + struct mfd_cell *cell = (struct mfd_cell *)dev->dev.platform_data; + + if (cell->suspend) + cell->suspend(dev); + + tmio_hw_stop(dev, platform_get_drvdata(dev)); + return 0; +} + +static int tmio_resume(struct platform_device *dev) +{ + struct mfd_cell *cell = (struct mfd_cell *)dev->dev.platform_data; + + /* FIXME - is this required or merely another attack of the broken + * SHARP platform? Looks suspicious. + */ + tmio_hw_init(dev, platform_get_drvdata(dev)); + + if (cell->resume) + cell->resume(dev); + + return 0; +} +#else +#define tmio_suspend NULL +#define tmio_resume NULL +#endif + +static struct platform_driver tmio_driver = { + .driver.name = "tmio-nand", + .driver.owner = THIS_MODULE, + .probe = tmio_probe, + .remove = tmio_remove, + .suspend = tmio_suspend, + .resume = tmio_resume, +}; + +static int __init tmio_init(void) +{ + return platform_driver_register(&tmio_driver); +} + +static void __exit tmio_exit(void) +{ + platform_driver_unregister(&tmio_driver); +} + +module_init(tmio_init); +module_exit(tmio_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Ian Molton, Dirk Opfer, Chris Humbert, Dmitry Baryshkov"); +MODULE_DESCRIPTION("NAND flash driver on Toshiba Mobile IO controller"); +MODULE_ALIAS("platform:tmio-nand"); diff --git a/drivers/mtd/nand/toto.c b/drivers/mtd/nand/toto.c index f9e2d4a0ab8c..bbf492e6830d 100644 --- a/drivers/mtd/nand/toto.c +++ b/drivers/mtd/nand/toto.c @@ -14,8 +14,6 @@ * Overview: * This is a device driver for the NAND flash device found on the * TI fido board. It supports 32MiB and 64MiB cards - * - * $Id: toto.c,v 1.5 2005/11/07 11:14:31 gleixner Exp $ */ #include <linux/slab.h> diff --git a/drivers/mtd/nand/ts7250.c b/drivers/mtd/nand/ts7250.c index f40081069ab2..2c410a011317 100644 --- a/drivers/mtd/nand/ts7250.c +++ b/drivers/mtd/nand/ts7250.c @@ -9,8 +9,6 @@ * Derived from drivers/mtd/nand/autcpu12.c * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) * - * $Id: ts7250.c,v 1.4 2004/12/30 22:02:07 joff 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 * published by the Free Software Foundation. @@ -27,7 +25,7 @@ #include <linux/mtd/nand.h> #include <linux/mtd/partitions.h> #include <asm/io.h> -#include <asm/arch/hardware.h> +#include <mach/hardware.h> #include <asm/sizes.h> #include <asm/mach-types.h> diff --git a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c index 0c9ce19ea27a..320b929abe79 100644 --- a/drivers/mtd/nftlcore.c +++ b/drivers/mtd/nftlcore.c @@ -1,7 +1,6 @@ /* Linux driver for NAND Flash Translation Layer */ /* (c) 1999 Machine Vision Holdings, Inc. */ /* Author: David Woodhouse <dwmw2@infradead.org> */ -/* $Id: nftlcore.c,v 1.98 2005/11/07 11:14:21 gleixner Exp $ */ /* The contents of this file are distributed under the GNU General @@ -803,12 +802,8 @@ static struct mtd_blktrans_ops nftl_tr = { .owner = THIS_MODULE, }; -extern char nftlmountrev[]; - static int __init init_nftl(void) { - printk(KERN_INFO "NFTL driver: nftlcore.c $Revision: 1.98 $, nftlmount.c %s\n", nftlmountrev); - return register_mtd_blktrans(&nftl_tr); } diff --git a/drivers/mtd/nftlmount.c b/drivers/mtd/nftlmount.c index 345e6eff89ce..ccc4f209fbb5 100644 --- a/drivers/mtd/nftlmount.c +++ b/drivers/mtd/nftlmount.c @@ -4,8 +4,6 @@ * Author: Fabrice Bellard (fabrice.bellard@netgem.com) * Copyright (C) 2000 Netgem S.A. * - * $Id: nftlmount.c,v 1.41 2005/11/07 11:14:21 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 @@ -31,8 +29,6 @@ #define SECTORSIZE 512 -char nftlmountrev[]="$Revision: 1.41 $"; - /* find_boot_record: Find the NFTL Media Header and its Spare copy which contains the * various device information of the NFTL partition and Bad Unit Table. Update * the ReplUnitTable[] table accroding to the Bad Unit Table. ReplUnitTable[] diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 5d7965f7e9ce..926cf3a4135d 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -325,28 +325,11 @@ static int onenand_wait(struct mtd_info *mtd, int state) ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS); - if (ctrl & ONENAND_CTRL_ERROR) { - printk(KERN_ERR "onenand_wait: controller error = 0x%04x\n", ctrl); - if (ctrl & ONENAND_CTRL_LOCK) - printk(KERN_ERR "onenand_wait: it's locked error.\n"); - if (state == FL_READING) { - /* - * A power loss while writing can result in a page - * becoming unreadable. When the device is mounted - * again, reading that page gives controller errors. - * Upper level software like JFFS2 treat -EIO as fatal, - * refusing to mount at all. That means it is necessary - * to treat the error as an ECC error to allow recovery. - * Note that typically in this case, the eraseblock can - * still be erased and rewritten i.e. it has not become - * a bad block. - */ - mtd->ecc_stats.failed++; - return -EBADMSG; - } - return -EIO; - } - + /* + * In the Spec. it checks the controller status first + * However if you get the correct information in case of + * power off recovery (POR) test, it should read ECC status first + */ if (interrupt & ONENAND_INT_READ) { int ecc = this->read_word(this->base + ONENAND_REG_ECC_STATUS); if (ecc) { @@ -364,6 +347,15 @@ static int onenand_wait(struct mtd_info *mtd, int state) return -EIO; } + /* If there's controller error, it's a real error */ + if (ctrl & ONENAND_CTRL_ERROR) { + printk(KERN_ERR "onenand_wait: controller error = 0x%04x\n", + ctrl); + if (ctrl & ONENAND_CTRL_LOCK) + printk(KERN_ERR "onenand_wait: it's locked error.\n"); + return -EIO; + } + return 0; } @@ -1135,22 +1127,26 @@ static int onenand_bbt_wait(struct mtd_info *mtd, int state) interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT); ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS); - /* Initial bad block case: 0x2400 or 0x0400 */ - if (ctrl & ONENAND_CTRL_ERROR) { - printk(KERN_DEBUG "onenand_bbt_wait: controller error = 0x%04x\n", ctrl); - return ONENAND_BBT_READ_ERROR; - } - if (interrupt & ONENAND_INT_READ) { int ecc = this->read_word(this->base + ONENAND_REG_ECC_STATUS); - if (ecc & ONENAND_ECC_2BIT_ALL) + if (ecc & ONENAND_ECC_2BIT_ALL) { + printk(KERN_INFO "onenand_bbt_wait: ecc error = 0x%04x" + ", controller error 0x%04x\n", ecc, ctrl); return ONENAND_BBT_READ_ERROR; + } } else { printk(KERN_ERR "onenand_bbt_wait: read timeout!" "ctrl=0x%04x intr=0x%04x\n", ctrl, interrupt); return ONENAND_BBT_READ_FATAL_ERROR; } + /* Initial bad block case: 0x2400 or 0x0400 */ + if (ctrl & ONENAND_CTRL_ERROR) { + printk(KERN_DEBUG "onenand_bbt_wait: " + "controller error = 0x%04x\n", ctrl); + return ONENAND_BBT_READ_ERROR; + } + return 0; } diff --git a/drivers/mtd/redboot.c b/drivers/mtd/redboot.c index c5030f94f04e..2d600a1bf2aa 100644 --- a/drivers/mtd/redboot.c +++ b/drivers/mtd/redboot.c @@ -1,6 +1,4 @@ /* - * $Id: redboot.c,v 1.21 2006/03/30 18:34:37 bjd Exp $ - * * Parse RedBoot-style Flash Image System (FIS) tables and * produce a Linux partition array to match. */ diff --git a/drivers/mtd/rfd_ftl.c b/drivers/mtd/rfd_ftl.c index c84e45465499..e538c0a72abb 100644 --- a/drivers/mtd/rfd_ftl.c +++ b/drivers/mtd/rfd_ftl.c @@ -3,8 +3,6 @@ * * Copyright (C) 2005 Sean Young <sean@mess.org> * - * $Id: rfd_ftl.c,v 1.8 2006/01/15 12:51:44 sean Exp $ - * * This type of flash translation layer (FTL) is used by the Embedded BIOS * by General Software. It is known as the Resident Flash Disk (RFD), see: * |