summaryrefslogtreecommitdiff
path: root/drivers/mtd
diff options
context:
space:
mode:
authorDavid S. Miller <davem@nuts.ninka.net>2002-10-15 07:41:35 -0700
committerDavid S. Miller <davem@nuts.ninka.net>2002-10-15 07:41:35 -0700
commit8fbfe7cd5594010a23cb4e81786d1fb8015ffdee (patch)
treeb5be190f22984395209823ec3cac1c76fc93f67f /drivers/mtd
parente22f7f5fd43205bfd20ea3a7bb4e689cb3f3d278 (diff)
parent5a7728c6d3eb83df9d120944cca4cf476dd326a1 (diff)
Merge nuts.ninka.net:/home/davem/src/BK/network-2.5
into nuts.ninka.net:/home/davem/src/BK/net-2.5
Diffstat (limited to 'drivers/mtd')
-rw-r--r--drivers/mtd/Config.help60
-rw-r--r--drivers/mtd/Config.in5
-rw-r--r--drivers/mtd/Makefile11
-rw-r--r--drivers/mtd/bootldr.c214
-rw-r--r--drivers/mtd/cmdline.c343
-rw-r--r--drivers/mtd/ftl.c3
-rw-r--r--drivers/mtd/maps/Config.help109
-rw-r--r--drivers/mtd/maps/Config.in12
-rw-r--r--drivers/mtd/maps/Makefile20
-rw-r--r--drivers/mtd/maps/autcpu12-nvram.c179
-rw-r--r--drivers/mtd/maps/ceiva.c408
-rw-r--r--drivers/mtd/maps/dc21285.c25
-rw-r--r--drivers/mtd/maps/edb7312.c202
-rw-r--r--drivers/mtd/maps/epxa10db-flash.c233
-rw-r--r--drivers/mtd/maps/fortunet.c309
-rw-r--r--drivers/mtd/maps/impa7.c234
-rw-r--r--drivers/mtd/maps/iq80310.c5
-rw-r--r--drivers/mtd/maps/pci.c385
-rw-r--r--drivers/mtd/maps/pcmciamtd.c893
-rw-r--r--drivers/mtd/maps/sa1100-flash.c1554
-rw-r--r--drivers/mtd/mtdblock.c5
-rw-r--r--drivers/mtd/mtdblock_ro.c4
-rw-r--r--drivers/mtd/mtdconcat.c675
-rw-r--r--drivers/mtd/nftlcore.c4
24 files changed, 5111 insertions, 781 deletions
diff --git a/drivers/mtd/Config.help b/drivers/mtd/Config.help
index 822dc7424d34..83e9b5c7d44b 100644
--- a/drivers/mtd/Config.help
+++ b/drivers/mtd/Config.help
@@ -21,36 +21,62 @@ CONFIG_MTD_PARTITIONS
devices. Partitioning on NFTL 'devices' is a different - that's the
'normal' form of partitioning used on a block device.
+CONFIG_MTD_CONCAT
+ Support for concatenating several MTD devices into a single
+ (virtual) one. This allows you to have -for example- a JFFS(2)
+ file system spanning multiple physical flash chips. If unsure,
+ say 'Y'.
+
CONFIG_MTD_REDBOOT_PARTS
RedBoot is a ROM monitor and bootloader which deals with multiple
- 'images' in flash devices by putting a table in the last erase block
- of the device, similar to a partition table, which gives the
- offsets, lengths and names of all the images stored in the flash.
+ 'images' in flash devices by putting a table in the last erase
+ block of the device, similar to a partition table, which gives
+ the offsets, lengths and names of all the images stored in the
+ flash.
If you need code which can detect and parse this table, and register
MTD 'partitions' corresponding to each image in the table, enable
- this option.
+ this option.
You will still need the parsing functions to be called by the driver
- for your particular device. It won't happen automatically. The
- SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for
+ for your particular device. It won't happen automatically. The
+ SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for
example.
-CONFIG_MTD_BOOTLDR_PARTS
- The Compaq bootldr deals with multiple 'images' in flash devices
- by putting a table in one of the first erase blocks of the device,
- similar to a partition table, which gives the offsets, lengths and
- names of all the images stored in the flash.
-
- If you need code which can detect and parse this table, and register
- MTD 'partitions' corresponding to each image in the table, enable
- this option.
-
+CONFIG_MTD_CMDLINE_PARTS
+ Allow generic configuration of the MTD paritition tables via the kernel
+ command line. Multiple flash resources are supported for hardware where
+ different kinds of flash memory are available.
+
You will still need the parsing functions to be called by the driver
for your particular device. It won't happen automatically. The
SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for
example.
+ The format for the command line is as follows:
+
+ mtdparts=<mtddef>[;<mtddef]
+ <mtddef> := <mtd-id>:<partdef>[,<partdef>]
+ <partdef> := <size>[@offset][<name>][ro]
+ <mtd-id> := unique id used in mapping driver/device
+ <size> := standard linux memsize OR "-" to denote all
+ remaining space
+ <name> := (NAME)
+
+ Due to the way Linux handles the command line, no spaces are
+ allowed in the partition definition, including mtd id's and partition
+ names.
+
+ Examples:
+
+ 1 flash resource (mtd-id "sa1100"), with 1 single writable partition:
+ mtdparts=sa1100:-
+
+ Same flash, but 2 named partitions, the first one being read-only:
+ mtdparts=sa1100:256k(ARMboot)ro,-(root)
+
+ If unsure, say 'N'.
+
CONFIG_MTD_AFS_PARTS
The ARM Firmware Suite allows the user to divide flash devices into
multiple 'images'. Each such image has a header containing its name
@@ -61,7 +87,7 @@ CONFIG_MTD_AFS_PARTS
enable this option.
You will still need the parsing functions to be called by the driver
- for your particular device. It won't happen automatically. The
+ for your particular device. It won't happen automatically. The
'armflash' map driver (CONFIG_MTD_ARMFLASH) does this, for example.
CONFIG_MTD_DEBUG_VERBOSE
diff --git a/drivers/mtd/Config.in b/drivers/mtd/Config.in
index 797f79667844..7e3d3ffd2983 100644
--- a/drivers/mtd/Config.in
+++ b/drivers/mtd/Config.in
@@ -1,5 +1,5 @@
-# $Id: Config.in,v 1.71 2001/10/03 11:38:38 dwmw2 Exp $
+# $Id: Config.in,v 1.74 2002/04/23 13:52:14 mag Exp $
mainmenu_option next_comment
comment 'Memory Technology Devices (MTD)'
@@ -12,9 +12,10 @@ if [ "$CONFIG_MTD" = "y" -o "$CONFIG_MTD" = "m" ]; then
int ' Debugging verbosity (0 = quiet, 3 = noisy)' CONFIG_MTD_DEBUG_VERBOSE 0
fi
dep_tristate ' MTD partitioning support' CONFIG_MTD_PARTITIONS $CONFIG_MTD
+ dep_tristate ' MTD concatenating support' CONFIG_MTD_CONCAT $CONFIG_MTD
dep_tristate ' RedBoot partition table parsing' CONFIG_MTD_REDBOOT_PARTS $CONFIG_MTD_PARTITIONS
+ dep_tristate ' Command line partition table parsing' CONFIG_MTD_CMDLINE_PARTS $CONFIG_MTD_PARTITIONS
if [ "$CONFIG_ARM" = "y" ]; then
- dep_tristate ' Compaq bootldr partition table parsing' CONFIG_MTD_BOOTLDR_PARTS $CONFIG_MTD_PARTITIONS
dep_tristate ' ARM Firmware Suite partition parsing' CONFIG_MTD_AFS_PARTS $CONFIG_MTD_PARTITIONS
fi
diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
index 4b8108198e7e..7ec5dfbb2501 100644
--- a/drivers/mtd/Makefile
+++ b/drivers/mtd/Makefile
@@ -1,12 +1,12 @@
#
# Makefile for the memory technology device drivers.
#
-#
-# $Id: Makefile,v 1.63 2001/06/13 09:43:07 dwmw2 Exp $
+# Based on:
+# $Id: Makefile,v 1.66 2002/04/23 13:52:14 mag Exp $
-export-objs := mtdcore.o mtdpart.o redboot.o bootldr.o afs.o
+export-objs := mtdcore.o mtdpart.o redboot.o cmdline.o afs.o mtdconcat.o
-obj-y += chips/ maps/ devices/ nand/
+obj-y += chips/ maps/ devices/ nand/
# *** BIG UGLY NOTE ***
#
@@ -26,9 +26,10 @@ obj-y += chips/ maps/ devices/ nand/
# Core functionality.
obj-$(CONFIG_MTD) += mtdcore.o
+obj-$(CONFIG_MTD_CONCAT) += mtdconcat.o
obj-$(CONFIG_MTD_PARTITIONS) += mtdpart.o
obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o
-obj-$(CONFIG_MTD_BOOTLDR_PARTS) += bootldr.o
+obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdline.o
obj-$(CONFIG_MTD_AFS_PARTS) += afs.o
# 'Users' - code which presents functionality to userspace.
diff --git a/drivers/mtd/bootldr.c b/drivers/mtd/bootldr.c
deleted file mode 100644
index 43fcd6bea8b8..000000000000
--- a/drivers/mtd/bootldr.c
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * Read flash partition table from Compaq Bootloader
- *
- * Copyright 2001 Compaq Computer Corporation.
- *
- * $Id: bootldr.c,v 1.6 2001/10/02 15:05:11 dwmw2 Exp $
- *
- * Use consistent with the GNU GPL is permitted,
- * provided that this copyright notice is
- * preserved in its entirety in all copies and derived works.
- *
- * COMPAQ COMPUTER CORPORATION MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
- * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
- * FITNESS FOR ANY PARTICULAR PURPOSE.
- *
- */
-
-/*
- * Maintainer: Jamey Hicks (jamey.hicks@compaq.com)
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/partitions.h>
-#include <asm/setup.h>
-#include <linux/bootmem.h>
-
-#define FLASH_PARTITION_NAMELEN 32
-enum LFR_FLAGS {
- LFR_SIZE_PREFIX = 1, /* prefix data with 4-byte size */
- LFR_PATCH_BOOTLDR = 2, /* patch bootloader's 0th instruction */
- LFR_KERNEL = 4, /* add BOOTIMG_MAGIC, imgsize and VKERNEL_BASE to head of programmed region (see bootldr.c) */
- LFR_EXPAND = 8 /* expand partition size to fit rest of flash */
-};
-
-// the tags are parsed too early to malloc or alloc_bootmem so we'll fix it
-// for now
-#define MAX_NUM_PARTITIONS 8
-typedef struct FlashRegion {
- char name[FLASH_PARTITION_NAMELEN];
- unsigned long base;
- unsigned long size;
- enum LFR_FLAGS flags;
-} FlashRegion;
-
-typedef struct BootldrFlashPartitionTable {
- int magic; /* should be filled with 0x646c7470 (btlp) BOOTLDR_PARTITION_MAGIC */
- int npartitions;
- struct FlashRegion partition[8];
-} BootldrFlashPartitionTable;
-
-#define BOOTLDR_MAGIC 0x646c7462 /* btld: marks a valid bootldr image */
-#define BOOTLDR_PARTITION_MAGIC 0x646c7470 /* btlp: marks a valid bootldr partition table in params sector */
-
-#define BOOTLDR_MAGIC_OFFSET 0x20 /* offset 0x20 into the bootldr */
-#define BOOTCAP_OFFSET 0X30 /* offset 0x30 into the bootldr */
-
-#define BOOTCAP_WAKEUP (1<<0)
-#define BOOTCAP_PARTITIONS (1<<1) /* partition table stored in params sector */
-#define BOOTCAP_PARAMS_AFTER_BOOTLDR (1<<2) /* params sector right after bootldr sector(s), else in last sector */
-
-static struct BootldrFlashPartitionTable Table;
-static struct BootldrFlashPartitionTable *partition_table = NULL;
-
-
-int parse_bootldr_partitions(struct mtd_info *master, struct mtd_partition **pparts)
-{
- struct mtd_partition *parts;
- int ret, retlen, i;
- int npartitions = 0;
- long partition_table_offset;
- long bootmagic = 0;
- long bootcap = 0;
- int namelen = 0;
-
- char *names;
-
-#if 0
- /* verify bootldr magic */
- ret = master->read(master, BOOTLDR_MAGIC_OFFSET, sizeof(long), &retlen, (void *)&bootmagic);
- if (ret)
- goto out;
- if (bootmagic != BOOTLDR_MAGIC)
- goto out;
- /* see if bootldr supports partition tables and where to find the partition table */
- ret = master->read(master, BOOTCAP_OFFSET, sizeof(long), &retlen, (void *)&bootcap);
- if (ret)
- goto out;
-
- if (!(bootcap & BOOTCAP_PARTITIONS))
- goto out;
- if (bootcap & BOOTCAP_PARAMS_AFTER_BOOTLDR)
- partition_table_offset = master->erasesize;
- else
- partition_table_offset = master->size - master->erasesize;
-
- printk(__FUNCTION__ ": partition_table_offset=%#lx\n", partition_table_offset);
- printk(__FUNCTION__ ": ptable_addr=%#lx\n", ptable_addr);
-
-
- /* Read the partition table */
- partition_table = (struct BootldrFlashPartitionTable *)kmalloc(PAGE_SIZE, GFP_KERNEL);
- if (!partition_table)
- return -ENOMEM;
-
- ret = master->read(master, partition_table_offset,
- PAGE_SIZE, &retlen, (void *)partition_table);
- if (ret)
- goto out;
-
-#endif
- if (!partition_table)
- return -ENOMEM;
-
-
- printk(__FUNCTION__ ": magic=%#x\n", partition_table->magic);
- printk(__FUNCTION__ ": numPartitions=%#x\n", partition_table->npartitions);
-
-
- /* check for partition table magic number */
- if (partition_table->magic != BOOTLDR_PARTITION_MAGIC)
- goto out;
- npartitions = (partition_table->npartitions > MAX_NUM_PARTITIONS)?
- MAX_NUM_PARTITIONS:partition_table->npartitions;
-
- printk(__FUNCTION__ ": npartitions=%#x\n", npartitions);
-
- for (i = 0; i < npartitions; i++) {
- namelen += strlen(partition_table->partition[i].name) + 1;
- }
-
- parts = kmalloc(sizeof(*parts)*npartitions + namelen, GFP_KERNEL);
- if (!parts) {
- ret = -ENOMEM;
- goto out;
- }
- names = (char *)&parts[npartitions];
- memset(parts, 0, sizeof(*parts)*npartitions + namelen);
-
-
-
- // from here we use the partition table
- for (i = 0; i < npartitions; i++) {
- struct FlashRegion *partition = &partition_table->partition[i];
- const char *name = partition->name;
- parts[i].name = names;
- names += strlen(name) + 1;
- strcpy(parts[i].name, name);
-
- if (partition->flags & LFR_EXPAND)
- parts[i].size = MTDPART_SIZ_FULL;
- else
- parts[i].size = partition->size;
- parts[i].offset = partition->base;
- parts[i].mask_flags = 0;
-
- printk(" partition %s o=%x s=%x\n",
- parts[i].name, parts[i].offset, parts[i].size);
-
- }
-
- ret = npartitions;
- *pparts = parts;
-
- out:
-#if 0
- if (partition_table)
- kfree(partition_table);
-#endif
-
- return ret;
-}
-
-
-static int __init parse_tag_ptable(const struct tag *tag)
-{
- char buf[128];
- int i;
- int j;
-
- partition_table = &Table;
-
-#ifdef CONFIG_DEBUG_LL
- sprintf(buf,"ptable: magic = = 0x%lx npartitions= %d \n",
- tag->u.ptable.magic,tag->u.ptable.npartitions);
- printascii(buf);
-
- for (i=0; i<tag->u.ptable.npartitions; i++){
- sprintf(buf,"ptable: partition name = %s base= 0x%lx size= 0x%lx flags= 0x%lx\n",
- (char *) (&tag->u.ptable.partition[i].name[0]),
- tag->u.ptable.partition[i].base,
- tag->u.ptable.partition[i].size,
- tag->u.ptable.partition[i].flags);
- printascii(buf);
- }
-#endif
-
- memcpy((void *)partition_table,(void *) (&(tag->u.ptable)),sizeof(partition_table) +
- sizeof(struct FlashRegion)*tag->u.ptable.npartitions);
-
-
- return 0;
-}
-
-__tagtable(ATAG_PTABLE, parse_tag_ptable);
-
-EXPORT_SYMBOL(parse_bootldr_partitions);
-
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Compaq Computer Corporation");
-MODULE_DESCRIPTION("Parsing code for Compaq bootldr partitions");
diff --git a/drivers/mtd/cmdline.c b/drivers/mtd/cmdline.c
new file mode 100644
index 000000000000..4d92157f46de
--- /dev/null
+++ b/drivers/mtd/cmdline.c
@@ -0,0 +1,343 @@
+/*
+ * $Id: cmdline.c,v 1.4 2002/09/13 01:18:38 jamey Exp $
+ *
+ * Read flash partition table from command line
+ *
+ * Copyright 2002 SYSGO Real-Time Solutions GmbH
+ *
+ * The format for the command line is as follows:
+ *
+ * mtdparts=<mtddef>[;<mtddef]
+ * <mtddef> := <mtd-id>:<partdef>[,<partdef>]
+ * <partdef> := <size>[@offset][<name>][ro]
+ * <mtd-id> := unique id used in mapping driver/device
+ * <size> := standard linux memsize OR "-" to denote all remaining space
+ * <name> := '(' NAME ')'
+ *
+ * Examples:
+ *
+ * 1 NOR Flash, with 1 single writable partition:
+ * edb7312-nor:-
+ *
+ * 1 NOR Flash with 2 partitions, 1 NAND with one
+ * edb7312-nor:256k(ARMboot)ro,-(root);edb7312-nand:-(home)
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <asm/setup.h>
+#include <linux/bootmem.h>
+
+/* error message prefix */
+#define ERRP "mtd: "
+
+/* debug macro */
+#if 0
+#define dbg(x) do { printk("DEBUG-CMDLINE-PART: "); printk x; } while(0)
+#else
+#define dbg(x)
+#endif
+
+
+/* special size referring to all the remaining space in a partition */
+#define SIZE_REMAINING 0xffffffff
+
+struct cmdline_mtd_partition {
+ struct cmdline_mtd_partition *next;
+ char *mtd_id;
+ int num_parts;
+ struct mtd_partition *parts;
+};
+
+/* mtdpart_setup() parses into here */
+static struct cmdline_mtd_partition *partitions;
+
+/* the command line passed to mtdpart_setupd() */
+static char *cmdline;
+static int cmdline_parsed = 0;
+
+/*
+ * Parse one partition definition for an MTD. Since there can be many
+ * comma separated partition definitions, this function calls itself
+ * recursively until no more partition definitions are found. Nice side
+ * effect: the memory to keep the mtd_partition structs and the names
+ * is allocated upon the last definition being found. At that point the
+ * syntax has been verified ok.
+ */
+static struct mtd_partition * newpart(char *s,
+ char **retptr,
+ int *num_parts,
+ int this_part,
+ unsigned char **extra_mem_ptr,
+ int extra_mem_size)
+{
+ struct mtd_partition *parts;
+ unsigned long size;
+ unsigned long offset = 0;
+ char *name;
+ int name_len;
+ unsigned char *extra_mem;
+ char delim;
+ unsigned int mask_flags;
+
+ /* fetch the partition size */
+ if (*s == '-')
+ { /* assign all remaining space to this partition */
+ size = SIZE_REMAINING;
+ s++;
+ }
+ else
+ {
+ size = memparse(s, &s);
+ if (size < PAGE_SIZE)
+ {
+ printk(KERN_ERR ERRP "partition size too small (%lx)\n", size);
+ return 0;
+ }
+ }
+
+ /* fetch partition name and flags */
+ mask_flags = 0; /* this is going to be a regular partition */
+ delim = 0;
+ /* check for offset */
+ if (*s == '@')
+ {
+ s++;
+ offset = memparse(s, &s);
+ }
+ /* now look for name */
+ if (*s == '(')
+ {
+ delim = ')';
+ }
+ if (delim)
+ {
+ char *p;
+
+ name = ++s;
+ if ((p = strchr(name, delim)) == 0)
+ {
+ printk(KERN_ERR ERRP "no closing %c found in partition name\n", delim);
+ return 0;
+ }
+ name_len = p - name;
+ s = p + 1;
+ }
+ else
+ {
+ name = NULL;
+ name_len = 13; /* Partition_000 */
+ }
+
+ /* record name length for memory allocation later */
+ extra_mem_size += name_len + 1;
+
+ /* test for options */
+ if (strncmp(s, "ro", 2) == 0)
+ {
+ mask_flags |= MTD_WRITEABLE;
+ s += 2;
+ }
+
+ /* test if more partitions are following */
+ if (*s == ',')
+ {
+ if (size == SIZE_REMAINING)
+ {
+ printk(KERN_ERR ERRP "no partitions allowed after a fill-up partition\n");
+ return 0;
+ }
+ /* more partitions follow, parse them */
+ if ((parts = newpart(s + 1, &s, num_parts,
+ this_part + 1, &extra_mem, extra_mem_size)) == 0)
+ return 0;
+ }
+ else
+ { /* this is the last partition: allocate space for all */
+ int alloc_size;
+
+ *num_parts = this_part + 1;
+ alloc_size = *num_parts * sizeof(struct mtd_partition) +
+ extra_mem_size;
+ parts = kmalloc(alloc_size, GFP_KERNEL);
+ if (!parts)
+ {
+ printk(KERN_ERR ERRP "out of memory\n");
+ return 0;
+ }
+ memset(parts, 0, alloc_size);
+ extra_mem = (unsigned char *)(parts + *num_parts);
+ }
+ /* enter this partition (offset will be calculated later if it is zero at this point) */
+ parts[this_part].size = size;
+ parts[this_part].offset = offset;
+ parts[this_part].mask_flags = mask_flags;
+ if (name)
+ {
+ strncpy(extra_mem, name, name_len);
+ extra_mem[name_len] = 0;
+ }
+ else
+ {
+ sprintf(extra_mem, "Partition_%03d", this_part);
+ }
+ parts[this_part].name = extra_mem;
+ extra_mem += name_len + 1;
+
+ dbg(("partition %d: name <%s>, offset %x, size %x, mask flags %x\n",
+ this_part,
+ parts[this_part].name,
+ parts[this_part].offset,
+ parts[this_part].size,
+ parts[this_part].mask_flags));
+
+ /* return (updated) pointer to extra_mem memory */
+ if (extra_mem_ptr)
+ *extra_mem_ptr = extra_mem;
+
+ /* return (updated) pointer command line string */
+ *retptr = s;
+
+ /* return partition table */
+ return parts;
+}
+
+/*
+ * Parse the command line.
+ */
+static int mtdpart_setup_real(char *s)
+{
+ cmdline_parsed = 1;
+
+ for( ; s != NULL; )
+ {
+ struct cmdline_mtd_partition *this_mtd;
+ struct mtd_partition *parts;
+ int mtd_id_len;
+ int num_parts;
+ char *p, *mtd_id;
+
+ mtd_id = s;
+ /* fetch <mtd-id> */
+ if (!(p = strchr(s, ':')))
+ {
+ printk(KERN_ERR ERRP "no mtd-id\n");
+ return 0;
+ }
+ mtd_id_len = p - mtd_id;
+
+ dbg(("parsing <%s>\n", p+1));
+
+ /*
+ * parse one mtd. have it reserve memory for the
+ * struct cmdline_mtd_partition and the mtd-id string.
+ */
+ parts = newpart(p + 1, /* cmdline */
+ &s, /* out: updated cmdline ptr */
+ &num_parts, /* out: number of parts */
+ 0, /* first partition */
+ (unsigned char**)&this_mtd, /* out: extra mem */
+ mtd_id_len + 1 + sizeof(*this_mtd));
+
+ /* enter results */
+ this_mtd->parts = parts;
+ this_mtd->num_parts = num_parts;
+ this_mtd->mtd_id = (char*)(this_mtd + 1);
+ strncpy(this_mtd->mtd_id, mtd_id, mtd_id_len);
+ this_mtd->mtd_id[mtd_id_len] = 0;
+
+ /* link into chain */
+ this_mtd->next = partitions;
+ partitions = this_mtd;
+
+ dbg(("mtdid=<%s> num_parts=<%d>\n",
+ this_mtd->mtd_id, this_mtd->num_parts));
+
+
+ /* EOS - we're done */
+ if (*s == 0)
+ break;
+
+ /* does another spec follow? */
+ if (*s != ';')
+ {
+ printk(KERN_ERR ERRP "bad character after partition (%c)\n", *s);
+ return 0;
+ }
+ s++;
+ }
+ return 1;
+}
+
+/*
+ * Main function to be called from the MTD mapping driver/device to
+ * obtain the partitioning information. At this point the command line
+ * arguments will actually be parsed and turned to struct mtd_partition
+ * information.
+ */
+int parse_cmdline_partitions(struct mtd_info *master,
+ struct mtd_partition **pparts,
+ const char *mtd_id)
+{
+ unsigned long offset;
+ int i;
+ struct cmdline_mtd_partition *part;
+
+ if (!cmdline)
+ return -EINVAL;
+
+ /* parse command line */
+ if (!cmdline_parsed)
+ mtdpart_setup_real(cmdline);
+
+ for(part = partitions; part; part = part->next)
+ {
+ if (!strcmp(part->mtd_id, mtd_id))
+ {
+ for(i = 0, offset = 0; i < part->num_parts; i++)
+ {
+ if (!part->parts[i].offset)
+ part->parts[i].offset = offset;
+ else
+ offset = part->parts[i].offset;
+ if (part->parts[i].size == SIZE_REMAINING)
+ part->parts[i].size = master->size - offset;
+ if (offset + part->parts[i].size > master->size)
+ {
+ printk(KERN_WARNING ERRP
+ "%s: partitioning exceeds flash size, truncating\n",
+ mtd_id);
+ part->parts[i].size = master->size - offset;
+ part->num_parts = i;
+ }
+ offset += part->parts[i].size;
+ }
+ *pparts = part->parts;
+ return part->num_parts;
+ }
+ }
+ return -EINVAL;
+}
+
+
+/*
+ * This is the handler for our kernel parameter, called from
+ * main.c::checksetup(). Note that we can not yet kmalloc() anything,
+ * so we only save the commandline for later processing.
+ */
+static int __init mtdpart_setup(char *s)
+{
+ cmdline = s;
+ return 1;
+}
+
+__setup("mtdparts=", mtdpart_setup);
+
+EXPORT_SYMBOL(parse_cmdline_partitions);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Marius Groeger <mag@sysgo.de>");
+MODULE_DESCRIPTION("Command line configuration of MTD partitions");
diff --git a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c
index 341ad2252885..e40e34d3c7d6 100644
--- a/drivers/mtd/ftl.c
+++ b/drivers/mtd/ftl.c
@@ -1223,7 +1223,7 @@ static void ftl_notify_add(struct mtd_info *mtd)
}
partition = kmalloc(sizeof(partition_t), GFP_KERNEL);
- disk = alloc_disk();
+ disk = alloc_disk(1 << PART_BITS);
if (!partition||!disk) {
printk(KERN_WARNING "No memory to scan for FTL on %s\n",
@@ -1237,7 +1237,6 @@ static void ftl_notify_add(struct mtd_info *mtd)
sprintf(disk->disk_name, "ftl%c", 'a' + device);
disk->major = FTL_MAJOR;
disk->first_minor = device << 4;
- disk->minor_shift = PART_BITS;
disk->fops = &ftl_blk_fops;
partition->mtd = mtd;
partition->disk = disk;
diff --git a/drivers/mtd/maps/Config.help b/drivers/mtd/maps/Config.help
index aaf3a1aa894e..d4cc1af6505e 100644
--- a/drivers/mtd/maps/Config.help
+++ b/drivers/mtd/maps/Config.help
@@ -1,3 +1,32 @@
+CONFIG_MTD_CDB89712
+ This enables access to the flash or ROM chips on the CDB89712 board.
+ If you have such a board, say 'Y'.
+
+CONFIG_MTD_CEIVA
+ This enables access to the flash chips on the Ceiva/Polaroid
+ PhotoMax Digital Picture Frame.
+ If you have such a device, say 'Y'.
+
+CONFIG_MTD_FORTUNET
+ This enables access to the Flash on the FortuNet board. If you
+ have such a board, say 'Y'.
+
+CONFIG_MTD_AUTCPU12
+ This enables access to the NV-RAM on autronix autcpu12 board.
+ If you have such a board, say 'Y'.
+
+CONFIG_MTD_EDB7312
+ This enables access to the CFI Flash on the Cogent EDB7312 board.
+ If you have such a board, say 'Y' here.
+
+CONFIG_MTD_NAND_EDB7312
+ This enables access to the NAND Flash on the Cogent EDB7312 board.
+ If you have such a board, say 'Y' here.
+
+CONFIG_MTD_IMPA7
+ This enables access to the NOR Flash on the impA7 board of
+ implementa GmbH. If you have such a board, say 'Y' here.
+
CONFIG_MTD_SA1100
This enables access to the flash chips on most platforms based on
the SA1100 and SA1110, including the Assabet and the Compaq iPAQ.
@@ -39,6 +68,12 @@ CONFIG_MTD_SUN_UFLASH
CONFIG_MTD_NORA
If you had to ask, you don't have one. Say 'N'.
+CONFIG_MTD_L440GX
+ Support for treating the BIOS flash chip on Intel L440GX motherboards
+ as an MTD device - with this you can reprogram your BIOS.
+
+ BE VERY CAREFUL.
+
CONFIG_MTD_PNC2000
PNC-2000 is the name of Network Camera product from PHOTRON
Ltd. in Japan. It uses CFI-compliant flash.
@@ -50,6 +85,13 @@ CONFIG_MTD_RPXLITE
to communicate with the chips on the RPXLite board. More at
<http://www.embeddedplanet.com/rpx_lite_specification_sheet.htm>.
+CONFIG_MTD_TQM8XXL
+ The TQM8xxL PowerPC board has up to two banks of CFI-compliant
+ chips, currently uses AMD one. This 'mapping' driver supports
+ that arrangement, allowing the CFI probe and command set driver
+ code to communicate with the chips on the TQM8xxL board. More at
+ <http://www.denx.de/embedded-ppc-en.html>.
+
CONFIG_MTD_SC520CDP
The SC520 CDP board has two banks of CFI-compliant chips and one
Dual-in-line JEDEC chip. This 'mapping' driver supports that
@@ -59,7 +101,7 @@ CONFIG_MTD_SBC_GXX
This provides a driver for the on-board flash of Arcom Control
Systems' SBC-GXn family of boards, formerly known as SBC-MediaGX.
By default the flash is split into 3 partitions which are accessed
- as separate MTD devices. This board utilizes Intel StrataFlash.
+ as separate MTD devices. This board utilizes Intel StrataFlash.
More info at
<http://www.arcomcontrols.com/products/icp/pc104/processors/>.
@@ -78,6 +120,11 @@ CONFIG_MTD_NETSC520
demonstration board. If you have one of these boards and would like
to use the flash chips on it, say 'Y'.
+CONFIG_MTD_OCELOT
+ This enables access routines for the boot flash device and for the
+ NVRAM on the Momenco Ocelot board. If you have one of these boards
+ and would like access to either of these, say 'Y'.
+
CONFIG_MTD_ELAN_104NC
This provides a driver for the on-board flash of the Arcom Control
System's ELAN-104NC development board. By default the flash
@@ -91,17 +138,17 @@ CONFIG_MTD_DC21285
<http://developer.intel.com/design/bridge/quicklist/dsc-21285.htm>.
CONFIG_MTD_CSTM_MIPS_IXX
- This provides a mapping driver for the Integrated Tecnology Express,
- Inc (ITE) QED-4N-S01B eval board and the Globespan IVR Reference
- Board. It provides the necessary addressing, length, buswidth, vpp
- code and addition setup of the flash device for these boards. In
- addition, this mapping driver can be used for other boards via
- setting of the CONFIG_MTD_CSTM_MIPS_IXX_START/LEN/BUSWIDTH
- parameters. This mapping will provide one mtd device using one
- partition. The start address can be offset from the beginning of
- flash and the len can be less than the total flash device size to
- allow a window into the flash. Both CFI and JEDEC probes are
- called.
+ This provides a mapping driver for the Integrated Tecnology
+ Express, Inc (ITE) QED-4N-S01B eval board and the Globespan IVR
+ Reference Board. It provides the necessary addressing, length,
+ buswidth, vpp code and addition setup of the flash device for
+ these boards. In addition, this mapping driver can be used for
+ other boards via setting of the CONFIG_MTD_CSTM_MIPS_IXX_START/
+ LEN/BUSWIDTH parameters. This mapping will provide one mtd device
+ using one partition. The start address can be offset from the
+ beginning of flash and the len can be less than the total flash
+ device size to allow a window into the flash. Both CFI and JEDEC
+ probes are called.
CONFIG_MTD_CSTM_MIPS_IXX_START
This is the physical memory location that the MTD driver will
@@ -141,6 +188,11 @@ CONFIG_MTD_OCTAGON
Computer. More information on the board is available at
<http://www.octagonsystems.com/Products/5066/5066.html>.
+CONFIG_MTD_PCMCIA
+ Map driver for accessing PCMCIA linear flash memory cards. These
+ cards are usually around 4-16MiB in size. This does not include
+ Compact Flash cards which are treated as IDE devices.
+
CONFIG_MTD_VMAX
This provides a 'mapping' driver which supports the way in which
the flash chips are connected in the Tempustech VMAX SBC301 Single
@@ -148,32 +200,21 @@ CONFIG_MTD_VMAX
<http://www.tempustech.com/tt301.htm>.
CONFIG_MTD_CFI_FLAGADM
- Mapping for the Flaga digital module. If you don´t have one, ignore
+ Mapping for the Flaga digital module. If you don´t have one, ignore
this setting.
-CONFIG_MTD_OCELOT
- This enables access routines for the boot flash device and for the
- NVRAM on the Momenco Ocelot board. If you have one of these boards
- and would like access to either of these, say 'Y'.
-
-CONFIG_MTD_CDB89712
- This enables access to the flash or ROM chips on the CDB89712 board.
- If you have such a board, say 'Y'.
-
-CONFIG_MTD_L440GX
- Support for treating the BIOS flash chip on Intel L440GX motherboards
- as an MTD device - with this you can reprogram your BIOS.
-
- BE VERY CAREFUL.
-
CONFIG_MTD_SOLUTIONENGINE
This enables access to the flash chips on the Hitachi SolutionEngine and
similar boards. Say 'Y' if you are building a kernel for such a board.
-CONFIG_MTD_TQM8XXL
- The TQM8xxL PowerPC board has up to two banks of CFI-compliant
- chips, currently uses AMD one. This 'mapping' driver supports
- that arrangement, allowing the CFI probe and command set driver
- code to communicate with the chips on the TQM8xxL board. More at
- <http://www.denx.de/embedded-ppc-en.html>.
+CONFIG_MTD_EPXA10DB
+ This enables support for the flash devices on the Altera
+ Excalibur XA10 Development Board. If you are building a kernel
+ for on of these boards then you should say 'Y' otherwise say 'N'.
+
+CONFIG_MTD_PCI
+ Mapping for accessing flash devices on add-in cards like the Intel XScale
+ IQ80310 card, and the Intel EBSA285 card in blank ROM programming mode
+ (please see the manual for the link settings).
+ If you are not sure, say N.
diff --git a/drivers/mtd/maps/Config.in b/drivers/mtd/maps/Config.in
index 7b4cbd4eda85..e0668372fa79 100644
--- a/drivers/mtd/maps/Config.in
+++ b/drivers/mtd/maps/Config.in
@@ -56,8 +56,18 @@ if [ "$CONFIG_ARM" = "y" ]; then
dep_tristate ' CFI Flash device mapped on ARM Integrator/P720T' CONFIG_MTD_ARM_INTEGRATOR $CONFIG_MTD_CFI
dep_tristate ' Cirrus CDB89712 evaluation board mappings' CONFIG_MTD_CDB89712 $CONFIG_MTD_CFI $CONFIG_ARCH_CDB89712
dep_tristate ' CFI Flash device mapped on StrongARM SA11x0' CONFIG_MTD_SA1100 $CONFIG_MTD_CFI $CONFIG_ARCH_SA1100 $CONFIG_MTD_PARTITIONS
- dep_tristate ' CFI Flash device mapped on DC21285 Footbridge' CONFIG_MTD_DC21285 $CONFIG_MTD_CFI $CONFIG_ARCH_FOOTBRIDGE $CONFIG_MTD_PARTITIONS
+ dep_tristate ' CFI Flash device mapped on DC21285 Footbridge' CONFIG_MTD_DC21285 $CONFIG_MTD_CFI $CONFIG_ARCH_FOOTBRIDGE
dep_tristate ' CFI Flash device mapped on the XScale IQ80310 board' CONFIG_MTD_IQ80310 $CONFIG_MTD_CFI $CONFIG_ARCH_IQ80310
+ dep_tristate ' CFI Flash device mapped on Epxa10db' CONFIG_MTD_EPXA10DB $CONFIG_MTD_CFI $CONFIG_MTD_PARTITIONS $CONFIG_ARCH_CAMELOT
+ dep_tristate ' CFI Flash device mapped on the FortuNet board' CONFIG_MTD_FORTUNET $CONFIG_MTD_CFI $CONFIG_MTD_PARTITIONS $CONFIG_SA1100_FORTUNET
+ dep_tristate ' NV-RAM mapping AUTCPU12 board' CONFIG_MTD_AUTCPU12 $CONFIG_ARCH_AUTCPU12
+ dep_tristate ' CFI Flash device mapped on EDB7312' CONFIG_MTD_EDB7312 $CONFIG_MTD_CFI
+ dep_tristate ' JEDEC Flash device mapped on impA7' CONFIG_MTD_IMPA7 $CONFIG_MTD_JEDECPROBE
+ dep_tristate ' JEDEC Flash device mapped on Ceiva/Polaroid PhotoMax Digital Picture Frame' CONFIG_MTD_CEIVA $CONFIG_MTD_JEDECPROBE $CONFIG_ARCH_CEIVA
fi
+# This needs CFI or JEDEC, depending on the cards found.
+dep_tristate ' PCI MTD driver' CONFIG_MTD_PCI $CONFIG_MTD $CONFIG_PCI
+dep_tristate ' PCMCIA MTD driver' CONFIG_MTD_PCMCIA $CONFIG_MTD $CONFIG_PCMCIA
+
endmenu
diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile
index c0bdc2fa8f23..f4acee989d04 100644
--- a/drivers/mtd/maps/Makefile
+++ b/drivers/mtd/maps/Makefile
@@ -4,29 +4,37 @@
# $Id: Makefile,v 1.13 2001/08/16 15:16:58 rmk Exp $
# Chip mappings
-obj-$(CONFIG_MTD_CDB89712) += cdb89712.o
+obj-$(CONFIG_MTD_CDB89712) += cdb89712.o
obj-$(CONFIG_MTD_ARM_INTEGRATOR)+= integrator-flash.o
obj-$(CONFIG_MTD_CFI_FLAGADM) += cfi_flagadm.o
-obj-$(CONFIG_MTD_CSTM_MIPS_IXX) += cstm_mips_ixx.o
-obj-$(CONFIG_MTD_DC21285) += dc21285.o
-obj-$(CONFIG_MTD_ELAN_104NC) += elan-104nc.o
+obj-$(CONFIG_MTD_CSTM_MIPS_IXX) += cstm_mips_ixx.o
+obj-$(CONFIG_MTD_DC21285) += dc21285.o
+obj-$(CONFIG_MTD_ELAN_104NC) += elan-104nc.o
+obj-$(CONFIG_MTD_EPXA10DB) += epxa10db-flash.o
obj-$(CONFIG_MTD_IQ80310) += iq80310.o
obj-$(CONFIG_MTD_L440GX) += l440gx.o
obj-$(CONFIG_MTD_NORA) += nora.o
+obj-$(CONFIG_MTD_CEIVA) += ceiva.o
obj-$(CONFIG_MTD_OCTAGON) += octagon-5066.o
obj-$(CONFIG_MTD_PHYSMAP) += physmap.o
obj-$(CONFIG_MTD_PNC2000) += pnc2000.o
+obj-$(CONFIG_MTD_PCMCIA) += pcmciamtd.o
obj-$(CONFIG_MTD_RPXLITE) += rpxlite.o
obj-$(CONFIG_MTD_TQM8XXL) += tqm8xxl.o
-obj-$(CONFIG_MTD_SA1100) += sa1100-flash.o
+obj-$(CONFIG_MTD_SA1100) += sa1100-flash.o
obj-$(CONFIG_MTD_SBC_GXX) += sbc_gxx.o
obj-$(CONFIG_MTD_SC520CDP) += sc520cdp.o
obj-$(CONFIG_MTD_NETSC520) += netsc520.o
-obj-$(CONFIG_MTD_SUN_UFLASH) += sun_uflash.o
+obj-$(CONFIG_MTD_SUN_UFLASH) += sun_uflash.o
obj-$(CONFIG_MTD_VMAX) += vmax301.o
obj-$(CONFIG_MTD_SCx200_DOCFLASH)+= scx200_docflash.o
obj-$(CONFIG_MTD_DBOX2) += dbox2-flash.o
obj-$(CONFIG_MTD_OCELOT) += ocelot.o
obj-$(CONFIG_MTD_SOLUTIONENGINE)+= solutionengine.o
+obj-$(CONFIG_MTD_PCI) += pci.o
+obj-$(CONFIG_MTD_AUTCPU12) += autcpu12-nvram.o
+obj-$(CONFIG_MTD_EDB7312) += edb7312.o
+obj-$(CONFIG_MTD_IMPA7) += impa7.o
+obj-$(CONFIG_MTD_FORTUNET) += fortunet.o
include $(TOPDIR)/Rules.make
diff --git a/drivers/mtd/maps/autcpu12-nvram.c b/drivers/mtd/maps/autcpu12-nvram.c
new file mode 100644
index 000000000000..db78b01e6438
--- /dev/null
+++ b/drivers/mtd/maps/autcpu12-nvram.c
@@ -0,0 +1,179 @@
+/*
+ * NV-RAM memory access on autcpu12
+ * (C) 2002 Thomas Gleixner (gleixner@autronix.de)
+ *
+ * $Id: autcpu12-nvram.c,v 1.1 2002/02/22 09:30:24 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/kernel.h>
+#include <linux/ioport.h>
+#include <asm/io.h>
+#include <asm/sizes.h>
+#include <asm/hardware.h>
+#include <asm/arch/autcpu12.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+
+__u8 autcpu12_read8(struct map_info *map, unsigned long ofs)
+{
+ return __raw_readb(map->map_priv_1 + ofs);
+}
+
+__u16 autcpu12_read16(struct map_info *map, unsigned long ofs)
+{
+ return __raw_readw(map->map_priv_1 + ofs);
+}
+
+__u32 autcpu12_read32(struct map_info *map, unsigned long ofs)
+{
+ return __raw_readl(map->map_priv_1 + ofs);
+}
+
+void autcpu12_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+ __raw_writeb(d, map->map_priv_1 + adr);
+ mb();
+}
+
+void autcpu12_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+ __raw_writew(d, map->map_priv_1 + adr);
+ mb();
+}
+
+void autcpu12_write32(struct map_info *map, __u32 d, unsigned long adr)
+{
+ __raw_writel(d, map->map_priv_1 + adr);
+ mb();
+}
+
+void autcpu12_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+ memcpy_fromio(to, map->map_priv_1 + from, len);
+}
+
+void autcpu12_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+ while(len) {
+ __raw_writeb(*(unsigned char *) from, map->map_priv_1 + to);
+ from++;
+ to++;
+ len--;
+ }
+}
+
+static struct mtd_info *sram_mtd;
+
+struct map_info autcpu12_sram_map = {
+ name: "SRAM",
+ size: 32768,
+ buswidth: 8,
+ read8: autcpu12_read8,
+ read16: autcpu12_read16,
+ read32: autcpu12_read32,
+ copy_from: autcpu12_copy_from,
+ write8: autcpu12_write8,
+ write16: autcpu12_write16,
+ write32: autcpu12_write32,
+ copy_to: autcpu12_copy_to
+};
+
+static int __init init_autcpu12_sram (void)
+{
+ int err, save0, save1;
+
+ autcpu12_sram_map.map_priv_1 = (unsigned long)ioremap(0x12000000, SZ_128K);
+ if (!autcpu12_sram_map.map_priv_1) {
+ printk("Failed to ioremap autcpu12 NV-RAM space\n");
+ err = -EIO;
+ goto out;
+ }
+
+ /*
+ * Check for 32K/128K
+ * read ofs 0
+ * read ofs 0x10000
+ * Write complement to ofs 0x100000
+ * Read and check result on ofs 0x0
+ * Restore contents
+ */
+ save0 = autcpu12_read32(&autcpu12_sram_map,0);
+ save1 = autcpu12_read32(&autcpu12_sram_map,0x10000);
+ autcpu12_write32(&autcpu12_sram_map,~save0,0x10000);
+ /* if we find this pattern on 0x0, we have 32K size
+ * restore contents and exit
+ */
+ if ( autcpu12_read32(&autcpu12_sram_map,0) != save0) {
+ autcpu12_write32(&autcpu12_sram_map,save0,0x0);
+ goto map;
+ }
+ /* We have a 128K found, restore 0x10000 and set size
+ * to 128K
+ */
+ autcpu12_write32(&autcpu12_sram_map,save1,0x10000);
+ autcpu12_sram_map.size = SZ_128K;
+
+map:
+ sram_mtd = do_map_probe("map_ram", &autcpu12_sram_map);
+ if (!sram_mtd) {
+ printk("NV-RAM probe failed\n");
+ err = -ENXIO;
+ goto out_ioremap;
+ }
+
+ sram_mtd->module = THIS_MODULE;
+ sram_mtd->erasesize = 16;
+
+ if (add_mtd_device(sram_mtd)) {
+ printk("NV-RAM device addition failed\n");
+ err = -ENOMEM;
+ goto out_probe;
+ }
+
+ printk("NV-RAM device size %ldK registered on AUTCPU12\n",autcpu12_sram_map.size/SZ_1K);
+
+ return 0;
+
+out_probe:
+ map_destroy(sram_mtd);
+ sram_mtd = 0;
+
+out_ioremap:
+ iounmap((void *)autcpu12_sram_map.map_priv_1);
+out:
+ return err;
+}
+
+static void __exit cleanup_autcpu12_maps(void)
+{
+ if (sram_mtd) {
+ del_mtd_device(sram_mtd);
+ map_destroy(sram_mtd);
+ iounmap((void *)autcpu12_sram_map.map_priv_1);
+ }
+}
+
+module_init(init_autcpu12_sram);
+module_exit(cleanup_autcpu12_maps);
+
+MODULE_AUTHOR("Thomas Gleixner");
+MODULE_DESCRIPTION("autcpu12 NV-RAM map driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/maps/ceiva.c b/drivers/mtd/maps/ceiva.c
new file mode 100644
index 000000000000..259a9a8b76c0
--- /dev/null
+++ b/drivers/mtd/maps/ceiva.c
@@ -0,0 +1,408 @@
+/*
+ * Ceiva flash memory driver.
+ * Copyright (C) 2002 Rob Scott <rscott@mtrob.fdns.net>
+ *
+ * Note: this driver supports jedec compatible devices. Modification
+ * for CFI compatible devices should be straight forward: change
+ * jedec_probe to cfi_probe.
+ *
+ * Based on: sa1100-flash.c, which has the following copyright:
+ * Flash memory access on SA11x0 based devices
+ *
+ * (C) 2000 Nicolas Pitre <nico@cam.org>
+ *
+ * $Id: ceiva.c,v 1.2 2002/10/14 12:50:22 rmk Exp $
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/concat.h>
+
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/io.h>
+#include <asm/sizes.h>
+
+/*
+ * This isnt complete yet, so...
+ */
+#define CONFIG_MTD_CEIVA_STATICMAP
+
+static __u8 clps_read8(struct map_info *map, unsigned long ofs)
+{
+ return readb(map->map_priv_1 + ofs);
+}
+
+static __u16 clps_read16(struct map_info *map, unsigned long ofs)
+{
+ return readw(map->map_priv_1 + ofs);
+}
+
+static __u32 clps_read32(struct map_info *map, unsigned long ofs)
+{
+ return readl(map->map_priv_1 + ofs);
+}
+
+static void clps_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+ memcpy(to, (void *)(map->map_priv_1 + from), len);
+}
+
+static void clps_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+ writeb(d, map->map_priv_1 + adr);
+}
+
+static void clps_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+ writew(d, map->map_priv_1 + adr);
+}
+
+static void clps_write32(struct map_info *map, __u32 d, unsigned long adr)
+{
+ writel(d, map->map_priv_1 + adr);
+}
+
+static void clps_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+ memcpy((void *)(map->map_priv_1 + to), from, len);
+}
+
+static struct map_info clps_map __initdata = {
+ name: "clps flash",
+ read8: clps_read8,
+ read16: clps_read16,
+ read32: clps_read32,
+ copy_from: clps_copy_from,
+ write8: clps_write8,
+ write16: clps_write16,
+ write32: clps_write32,
+ copy_to: clps_copy_to,
+};
+
+#ifdef CONFIG_MTD_CEIVA_STATICMAP
+/*
+ * See include/linux/mtd/partitions.h for definition of the mtd_partition
+ * structure.
+ *
+ * Please note:
+ * 1. The flash size given should be the largest flash size that can
+ * be accomodated.
+ *
+ * 2. The bus width must defined in clps_setup_flash.
+ *
+ * The MTD layer will detect flash chip aliasing and reduce the size of
+ * the map accordingly.
+ *
+ */
+
+#ifdef CONFIG_ARCH_CEIVA
+/* Flash / Partition sizing */
+/* For the 28F8003, we use the block mapping to calcuate the sizes */
+#define MAX_SIZE_KiB (16 + 8 + 8 + 96 + (7*128))
+#define BOOT_PARTITION_SIZE_KiB (16)
+#define PARAMS_PARTITION_SIZE_KiB (8)
+#define KERNEL_PARTITION_SIZE_KiB (4*128)
+/* Use both remaing portion of first flash, and all of second flash */
+#define ROOT_PARTITION_SIZE_KiB (3*128) + (8*128)
+
+static struct mtd_partition ceiva_partitions[] = {
+ {
+ name: "Ceiva BOOT partition",
+ size: BOOT_PARTITION_SIZE_KiB*1024,
+ offset: 0,
+
+ },{
+ name: "Ceiva parameters partition",
+ size: PARAMS_PARTITION_SIZE_KiB*1024,
+ offset: (16 + 8) * 1024,
+ },{
+ name: "Ceiva kernel partition",
+ size: (KERNEL_PARTITION_SIZE_KiB)*1024,
+ offset: 0x20000,
+
+ },{
+ name: "Ceiva root filesystem partition",
+ offset: MTDPART_OFS_APPEND,
+ size: (ROOT_PARTITION_SIZE_KiB)*1024,
+ }
+};
+#endif
+
+static int __init clps_static_partitions(struct mtd_partition **parts)
+{
+ int nb_parts = 0;
+
+#ifdef CONFIG_ARCH_CEIVA
+ if (machine_is_ceiva()) {
+ *parts = ceiva_partitions;
+ nb_parts = ARRAY_SIZE(ceiva_partitions);
+ }
+#endif
+ return nb_parts;
+}
+#endif
+
+struct clps_info {
+ unsigned long base;
+ unsigned long size;
+ int width;
+ void *vbase;
+ struct map_info *map;
+ struct mtd_info *mtd;
+ struct resource *res;
+};
+
+#define NR_SUBMTD 4
+
+static struct clps_info info[NR_SUBMTD];
+
+static int __init clps_setup_mtd(struct clps_info *clps, int nr, struct mtd_info **rmtd)
+{
+ struct mtd_info *subdev[nr];
+ struct map_info *maps;
+ int i, found = 0, ret = 0;
+
+ /*
+ * Allocate the map_info structs in one go.
+ */
+ maps = kmalloc(sizeof(struct map_info) * nr, GFP_KERNEL);
+ if (!maps)
+ return -ENOMEM;
+
+ /*
+ * Claim and then map the memory regions.
+ */
+ for (i = 0; i < nr; i++) {
+ if (clps[i].base == (unsigned long)-1)
+ break;
+
+ clps[i].res = request_mem_region(clps[i].base, clps[i].size, "clps flash");
+ if (!clps[i].res) {
+ ret = -EBUSY;
+ break;
+ }
+
+ clps[i].map = maps + i;
+ memcpy(clps[i].map, &clps_map, sizeof(struct map_info));
+
+ clps[i].vbase = ioremap(clps[i].base, clps[i].size);
+ if (!clps[i].vbase) {
+ ret = -ENOMEM;
+ break;
+ }
+
+ clps[i].map->map_priv_1 = (unsigned long)clps[i].vbase;
+ clps[i].map->buswidth = clps[i].width;
+ clps[i].map->size = clps[i].size;
+
+ clps[i].mtd = do_map_probe("jedec_probe", clps[i].map);
+ if (clps[i].mtd == NULL) {
+ ret = -ENXIO;
+ break;
+ }
+ clps[i].mtd->module = THIS_MODULE;
+ subdev[i] = clps[i].mtd;
+
+ printk(KERN_INFO "clps flash: JEDEC device at 0x%08lx, %dMiB, "
+ "%d-bit\n", clps[i].base, clps[i].mtd->size >> 20,
+ clps[i].width * 8);
+ found += 1;
+ }
+
+ /*
+ * ENXIO is special. It means we didn't find a chip when
+ * we probed. We need to tear down the mapping, free the
+ * resource and mark it as such.
+ */
+ if (ret == -ENXIO) {
+ iounmap(clps[i].vbase);
+ clps[i].vbase = NULL;
+ release_resource(clps[i].res);
+ clps[i].res = NULL;
+ }
+
+ /*
+ * If we found one device, don't bother with concat support.
+ * If we found multiple devices, use concat if we have it
+ * available, otherwise fail.
+ */
+ if (ret == 0 || ret == -ENXIO) {
+ if (found == 1) {
+ *rmtd = subdev[0];
+ ret = 0;
+ } else if (found > 1) {
+ /*
+ * We detected multiple devices. Concatenate
+ * them together.
+ */
+#ifdef CONFIG_MTD_CONCAT
+ *rmtd = mtd_concat_create(subdev, found,
+ "clps flash");
+ if (*rmtd == NULL)
+ ret = -ENXIO;
+#else
+ printk(KERN_ERR "clps flash: multiple devices "
+ "found but MTD concat support disabled.\n");
+ ret = -ENXIO;
+#endif
+ }
+ }
+
+ /*
+ * If we failed, clean up.
+ */
+ if (ret) {
+ do {
+ if (clps[i].mtd)
+ map_destroy(clps[i].mtd);
+ if (clps[i].vbase)
+ iounmap(clps[i].vbase);
+ if (clps[i].res)
+ release_resource(clps[i].res);
+ } while (i--);
+
+ kfree(maps);
+ }
+
+ return ret;
+}
+
+static void __exit clps_destroy_mtd(struct clps_info *clps, struct mtd_info *mtd)
+{
+ int i;
+
+ del_mtd_partitions(mtd);
+
+ if (mtd != clps[0].mtd)
+ mtd_concat_destroy(mtd);
+
+ for (i = NR_SUBMTD; i >= 0; i--) {
+ if (clps[i].mtd)
+ map_destroy(clps[i].mtd);
+ if (clps[i].vbase)
+ iounmap(clps[i].vbase);
+ if (clps[i].res)
+ release_resource(clps[i].res);
+ }
+ kfree(clps[0].map);
+}
+
+/*
+ * We define the memory space, size, and width for the flash memory
+ * space here.
+ */
+
+static int __init clps_setup_flash(void)
+{
+ int nr;
+
+#ifdef CONFIG_ARCH_CEIVA
+ if (machine_is_ceiva()) {
+ info[0].base = CS0_PHYS_BASE;
+ info[0].size = SZ_32M;
+ info[0].width = CEIVA_FLASH_WIDTH;
+ info[1].base = CS1_PHYS_BASE;
+ info[1].size = SZ_32M;
+ info[1].width = CEIVA_FLASH_WIDTH;
+ nr = 2;
+ }
+#endif
+ return nr;
+}
+
+extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts);
+extern int parse_cmdline_partitions(struct mtd_info *master, struct mtd_partition **pparts, char *);
+
+static struct mtd_partition *parsed_parts;
+
+static void __init clps_locate_partitions(struct mtd_info *mtd)
+{
+ const char *part_type = NULL;
+ int nr_parts = 0;
+ do {
+ /*
+ * Partition selection stuff.
+ */
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+ nr_parts = parse_cmdline_partitions(mtd, &parsed_parts, "clps");
+ if (nr_parts > 0) {
+ part_type = "command line";
+ break;
+ }
+#endif
+#ifdef CONFIG_MTD_REDBOOT_PARTS
+ nr_parts = parse_redboot_partitions(mtd, &parsed_parts);
+ if (nr_parts > 0) {
+ part_type = "RedBoot";
+ break;
+ }
+#endif
+#ifdef CONFIG_MTD_CEIVA_STATICMAP
+ nr_parts = clps_static_partitions(&parsed_parts);
+ if (nr_parts > 0) {
+ part_type = "static";
+ break;
+ }
+ printk("found: %d partitions\n", nr_parts);
+#endif
+ } while (0);
+
+ if (nr_parts == 0) {
+ printk(KERN_NOTICE "clps flash: no partition info "
+ "available, registering whole flash\n");
+ add_mtd_device(mtd);
+ } else {
+ printk(KERN_NOTICE "clps flash: using %s partition "
+ "definition\n", part_type);
+ add_mtd_partitions(mtd, parsed_parts, nr_parts);
+ }
+
+ /* Always succeeds. */
+}
+
+static void __exit clps_destroy_partitions(void)
+{
+ if (parsed_parts)
+ kfree(parsed_parts);
+}
+
+static struct mtd_info *mymtd;
+
+static int __init clps_mtd_init(void)
+{
+ int ret;
+ int nr;
+
+ nr = clps_setup_flash();
+ if (nr < 0)
+ return nr;
+
+ ret = clps_setup_mtd(info, nr, &mymtd);
+ if (ret)
+ return ret;
+
+ clps_locate_partitions(mymtd);
+
+ return 0;
+}
+
+static void __exit clps_mtd_cleanup(void)
+{
+ clps_destroy_mtd(info, mymtd);
+ clps_destroy_partitions();
+}
+
+module_init(clps_mtd_init);
+module_exit(clps_mtd_cleanup);
+
+MODULE_AUTHOR("Rob Scott");
+MODULE_DESCRIPTION("Cirrus Logic JEDEC map driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/maps/dc21285.c b/drivers/mtd/maps/dc21285.c
index e7eea7ef53b2..f030f3447302 100644
--- a/drivers/mtd/maps/dc21285.c
+++ b/drivers/mtd/maps/dc21285.c
@@ -5,9 +5,9 @@
*
* This code is GPL
*
- * $Id: dc21285.c,v 1.6 2001/10/02 15:05:14 dwmw2 Exp $
+ * $Id: dc21285.c,v 1.9 2002/10/14 12:22:10 rmk Exp $
*/
-
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
@@ -44,15 +44,15 @@ void dc21285_copy_from(struct map_info *map, void *to, unsigned long from, ssize
void dc21285_write8(struct map_info *map, __u8 d, unsigned long adr)
{
- *CSR_ROMWRITEREG = adr;
+ *CSR_ROMWRITEREG = adr & 3;
adr &= ~3;
*(__u8*)(map->map_priv_1 + adr) = d;
}
void dc21285_write16(struct map_info *map, __u16 d, unsigned long adr)
{
- *CSR_ROMWRITEREG = adr;
- adr &= ~1;
+ *CSR_ROMWRITEREG = adr & 3;
+ adr &= ~3;
*(__u16*)(map->map_priv_1 + adr) = d;
}
@@ -131,7 +131,7 @@ int __init init_dc21285(void)
dc21285_map.buswidth*8);
/* Let's map the flash area */
- dc21285_map.map_priv_1 = (unsigned long)__ioremap(DC21285_FLASH, 16*1024*1024, 0);
+ dc21285_map.map_priv_1 = (unsigned long)ioremap(DC21285_FLASH, 16*1024*1024);
if (!dc21285_map.map_priv_1) {
printk("Failed to ioremap\n");
return -EIO;
@@ -139,21 +139,22 @@ int __init init_dc21285(void)
mymtd = do_map_probe("cfi_probe", &dc21285_map);
if (mymtd) {
- int nrparts;
+ int nrparts = 0;
mymtd->module = THIS_MODULE;
/* partition fixup */
+#ifdef CONFIG_MTD_REDBOOT_PARTS
nrparts = parse_redboot_partitions(mymtd, &dc21285_parts);
- if (nrparts <=0) {
+#endif
+ if (nrparts > 0) {
+ add_mtd_partitions(mymtd, dc21285_parts, nrparts);
+ } else if (nrparts == 0) {
printk(KERN_NOTICE "RedBoot partition table failed\n");
- iounmap((void *)dc21285_map.map_priv_1);
- return -ENXIO;
+ add_mtd_device(mymtd);
}
- add_mtd_partitions(mymtd, dc21285_parts, nrparts);
-
/*
* Flash timing is determined with bits 19-16 of the
* CSR_SA110_CNTL. The value is the number of wait cycles, or
diff --git a/drivers/mtd/maps/edb7312.c b/drivers/mtd/maps/edb7312.c
new file mode 100644
index 000000000000..405429d92735
--- /dev/null
+++ b/drivers/mtd/maps/edb7312.c
@@ -0,0 +1,202 @@
+/*
+ * $Id: edb7312.c,v 1.2 2002/09/05 05:11:24 acurtis Exp $
+ *
+ * Handle mapping of the NOR flash on Cogent EDB7312 boards
+ *
+ * Copyright 2002 SYSGO Real-Time Solutions GmbH
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/config.h>
+
+#ifdef CONFIG_MTD_PARTITIONS
+#include <linux/mtd/partitions.h>
+#endif
+
+#define WINDOW_ADDR 0x00000000 /* physical properties of flash */
+#define WINDOW_SIZE 0x01000000
+#define BUSWIDTH 2
+#define FLASH_BLOCKSIZE_MAIN 0x20000
+#define FLASH_NUMBLOCKS_MAIN 128
+/* can be "cfi_probe", "jedec_probe", "map_rom", 0 }; */
+#define PROBETYPES { "cfi_probe", 0 }
+
+#define MSG_PREFIX "EDB7312-NOR:" /* prefix for our printk()'s */
+#define MTDID "edb7312-nor" /* for mtdparts= partitioning */
+
+static struct mtd_info *mymtd;
+
+__u8 edb7312nor_read8(struct map_info *map, unsigned long ofs)
+{
+ return __raw_readb(map->map_priv_1 + ofs);
+}
+
+__u16 edb7312nor_read16(struct map_info *map, unsigned long ofs)
+{
+ return __raw_readw(map->map_priv_1 + ofs);
+}
+
+__u32 edb7312nor_read32(struct map_info *map, unsigned long ofs)
+{
+ return __raw_readl(map->map_priv_1 + ofs);
+}
+
+void edb7312nor_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+ memcpy_fromio(to, map->map_priv_1 + from, len);
+}
+
+void edb7312nor_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+ __raw_writeb(d, map->map_priv_1 + adr);
+ mb();
+}
+
+void edb7312nor_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+ __raw_writew(d, map->map_priv_1 + adr);
+ mb();
+}
+
+void edb7312nor_write32(struct map_info *map, __u32 d, unsigned long adr)
+{
+ __raw_writel(d, map->map_priv_1 + adr);
+ mb();
+}
+
+void edb7312nor_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+ memcpy_toio(map->map_priv_1 + to, from, len);
+}
+
+struct map_info edb7312nor_map = {
+ name: "NOR flash on EDB7312",
+ size: WINDOW_SIZE,
+ buswidth: BUSWIDTH,
+ read8: edb7312nor_read8,
+ read16: edb7312nor_read16,
+ read32: edb7312nor_read32,
+ copy_from: edb7312nor_copy_from,
+ write8: edb7312nor_write8,
+ write16: edb7312nor_write16,
+ write32: edb7312nor_write32,
+ copy_to: edb7312nor_copy_to
+};
+
+#ifdef CONFIG_MTD_PARTITIONS
+
+/*
+ * MTD partitioning stuff
+ */
+static struct mtd_partition static_partitions[3] =
+{
+ {
+ name: "ARMboot",
+ size: 0x40000,
+ offset: 0
+ },
+ {
+ name: "Kernel",
+ size: 0x200000,
+ offset: 0x40000
+ },
+ {
+ name: "RootFS",
+ size: 0xDC0000,
+ offset: 0x240000
+ },
+};
+
+#define NB_OF(x) (sizeof (x) / sizeof (x[0]))
+
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+int parse_cmdline_partitions(struct mtd_info *master,
+ struct mtd_partition **pparts,
+ const char *mtd_id);
+#endif
+
+#endif
+
+static int mtd_parts_nb = 0;
+static struct mtd_partition *mtd_parts = 0;
+
+int __init init_edb7312nor(void)
+{
+ static const char *rom_probe_types[] = PROBETYPES;
+ const char **type;
+ const char *part_type = 0;
+
+ printk(KERN_NOTICE MSG_PREFIX "0x%08x at 0x%08x\n",
+ WINDOW_SIZE, WINDOW_ADDR);
+ edb7312nor_map.map_priv_1 = (unsigned long)
+ ioremap(WINDOW_ADDR, WINDOW_SIZE);
+
+ if (!edb7312nor_map.map_priv_1) {
+ printk(MSG_PREFIX "failed to ioremap\n");
+ return -EIO;
+ }
+
+ mymtd = 0;
+ type = rom_probe_types;
+ for(; !mymtd && *type; type++) {
+ mymtd = do_map_probe(*type, &edb7312nor_map);
+ }
+ if (mymtd) {
+ mymtd->module = THIS_MODULE;
+
+#ifdef CONFIG_MTD_PARTITIONS
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+ mtd_parts_nb = parse_cmdline_partitions(mymtd, &mtd_parts, MTDID);
+ if (mtd_parts_nb > 0)
+ part_type = "command line";
+#endif
+ if (mtd_parts_nb == 0)
+ {
+ mtd_parts = static_partitions;
+ mtd_parts_nb = NB_OF(static_partitions);
+ part_type = "static";
+ }
+#endif
+ add_mtd_device(mymtd);
+ if (mtd_parts_nb == 0)
+ printk(KERN_NOTICE MSG_PREFIX "no partition info available\n");
+ else
+ {
+ printk(KERN_NOTICE MSG_PREFIX
+ "using %s partition definition\n", part_type);
+ add_mtd_partitions(mymtd, mtd_parts, mtd_parts_nb);
+ }
+ return 0;
+ }
+
+ iounmap((void *)edb7312nor_map.map_priv_1);
+ return -ENXIO;
+}
+
+static void __exit cleanup_edb7312nor(void)
+{
+ if (mymtd) {
+ del_mtd_device(mymtd);
+ map_destroy(mymtd);
+ }
+ if (edb7312nor_map.map_priv_1) {
+ iounmap((void *)edb7312nor_map.map_priv_1);
+ edb7312nor_map.map_priv_1 = 0;
+ }
+}
+
+module_init(init_edb7312nor);
+module_exit(cleanup_edb7312nor);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Marius Groeger <mag@sysgo.de>");
+MODULE_DESCRIPTION("Generic configurable MTD map driver");
diff --git a/drivers/mtd/maps/epxa10db-flash.c b/drivers/mtd/maps/epxa10db-flash.c
new file mode 100644
index 000000000000..cb4c76e4bb71
--- /dev/null
+++ b/drivers/mtd/maps/epxa10db-flash.c
@@ -0,0 +1,233 @@
+/*
+ * Flash memory access on EPXA based devices
+ *
+ * (C) 2000 Nicolas Pitre <nico@cam.org>
+ * Copyright (C) 2001 Altera Corporation
+ * Copyright (C) 2001 Red Hat, Inc.
+ *
+ * $Id: epxa10db-flash.c,v 1.4 2002/08/22 10:46:19 cdavies 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/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/hardware.h>
+#ifdef CONFIG_EPXA10DB
+#define BOARD_NAME "EPXA10DB"
+#else
+#define BOARD_NAME "EPXA1DB"
+#endif
+
+static int nr_parts = 0;
+static struct mtd_partition *parts;
+
+static struct mtd_info *mymtd;
+
+extern int parse_redboot_partitions(struct mtd_info *, struct mtd_partition **);
+static int epxa_default_partitions(struct mtd_info *master, struct mtd_partition **pparts);
+
+static __u8 epxa_read8(struct map_info *map, unsigned long ofs)
+{
+ return __raw_readb(map->map_priv_1 + ofs);
+}
+
+static __u16 epxa_read16(struct map_info *map, unsigned long ofs)
+{
+ return __raw_readw(map->map_priv_1 + ofs);
+}
+
+static __u32 epxa_read32(struct map_info *map, unsigned long ofs)
+{
+ return __raw_readl(map->map_priv_1 + ofs);
+}
+
+static void epxa_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+ memcpy_fromio(to, (void *)(map->map_priv_1 + from), len);
+}
+
+static void epxa_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+ __raw_writeb(d, map->map_priv_1 + adr);
+ mb();
+}
+
+static void epxa_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+ __raw_writew(d, map->map_priv_1 + adr);
+ mb();
+}
+
+static void epxa_write32(struct map_info *map, __u32 d, unsigned long adr)
+{
+ __raw_writel(d, map->map_priv_1 + adr);
+ mb();
+}
+
+static void epxa_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+ memcpy_toio((void *)(map->map_priv_1 + to), from, len);
+}
+
+
+
+static struct map_info epxa_map = {
+ name: "EPXA flash",
+ size: FLASH_SIZE,
+ buswidth: 2,
+ read8: epxa_read8,
+ read16: epxa_read16,
+ read32: epxa_read32,
+ copy_from: epxa_copy_from,
+ write8: epxa_write8,
+ write16: epxa_write16,
+ write32: epxa_write32,
+ copy_to: epxa_copy_to
+};
+
+
+static int __init epxa_mtd_init(void)
+{
+ int i;
+
+ printk(KERN_NOTICE "%s flash device: %x at %x\n", BOARD_NAME, FLASH_SIZE, FLASH_START);
+ epxa_map.map_priv_1 = (unsigned long)ioremap(FLASH_START, FLASH_SIZE);
+ if (!epxa_map.map_priv_1) {
+ printk("Failed to ioremap %s flash\n",BOARD_NAME);
+ return -EIO;
+ }
+
+ mymtd = do_map_probe("cfi_probe", &epxa_map);
+ if (!mymtd) {
+ iounmap((void *)epxa_map.map_priv_1);
+ return -ENXIO;
+ }
+
+ mymtd->module = THIS_MODULE;
+
+ /* Unlock the flash device. */
+ if(mymtd->unlock){
+ for (i=0; i<mymtd->numeraseregions;i++){
+ int j;
+ for(j=0;j<mymtd->eraseregions[i].numblocks;j++){
+ mymtd->unlock(mymtd,mymtd->eraseregions[i].offset + j * mymtd->eraseregions[i].erasesize,mymtd->eraseregions[i].erasesize);
+ }
+ }
+ }
+
+#ifdef CONFIG_MTD_REDBOOT_PARTS
+ nr_parts = parse_redboot_partitions(mymtd, &parts);
+
+ if (nr_parts > 0) {
+ add_mtd_partitions(mymtd, parts, nr_parts);
+ return 0;
+ }
+#endif
+#ifdef CONFIG_MTD_AFS_PARTS
+ nr_parts = parse_afs_partitions(mymtd, &parts);
+
+ if (nr_parts > 0) {
+ add_mtd_partitions(mymtd, parts, nr_parts);
+ return 0;
+ }
+#endif
+
+ /* No recognised partitioning schemes found - use defaults */
+ nr_parts = epxa_default_partitions(mymtd, &parts);
+ if (nr_parts > 0) {
+ add_mtd_partitions(mymtd, parts, nr_parts);
+ return 0;
+ }
+
+ /* If all else fails... */
+ add_mtd_device(mymtd);
+ return 0;
+}
+
+static void __exit epxa_mtd_cleanup(void)
+{
+ if (mymtd) {
+ if (nr_parts)
+ del_mtd_partitions(mymtd);
+ else
+ del_mtd_device(mymtd);
+ map_destroy(mymtd);
+ }
+ if (epxa_map.map_priv_1) {
+ iounmap((void *)epxa_map.map_priv_1);
+ epxa_map.map_priv_1 = 0;
+ }
+}
+
+
+/*
+ * This will do for now, once we decide which bootldr we're finally
+ * going to use then we'll remove this function and do it properly
+ *
+ * Partions are currently (as offsets from base of flash):
+ * 0x00000000 - 0x003FFFFF - bootloader (!)
+ * 0x00400000 - 0x00FFFFFF - Flashdisk
+ */
+
+static int __init epxa_default_partitions(struct mtd_info *master, struct mtd_partition **pparts)
+{
+ struct mtd_partition *parts;
+ int ret, i;
+ int npartitions = 0;
+ char *names;
+ const char *name = "jffs";
+
+ printk("Using default partitions for %s\n",BOARD_NAME);
+ npartitions=1;
+ parts = kmalloc(npartitions*sizeof(*parts)+strlen(name), GFP_KERNEL);
+ memzero(parts,npartitions*sizeof(*parts)+strlen(name));
+ if (!parts) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ i=0;
+ names = (char *)&parts[npartitions];
+ parts[i].name = names;
+ names += strlen(name) + 1;
+ strcpy(parts[i].name, name);
+
+#ifdef CONFIG_EPXA10DB
+ parts[i].size = FLASH_SIZE-0x00400000;
+ parts[i].offset = 0x00400000;
+#else
+ parts[i].size = FLASH_SIZE-0x00180000;
+ parts[i].offset = 0x00180000;
+#endif
+
+ out:
+ *pparts = parts;
+ return npartitions;
+}
+
+
+module_init(epxa_mtd_init);
+module_exit(epxa_mtd_cleanup);
+
+MODULE_AUTHOR("Clive Davies");
+MODULE_DESCRIPTION("Altera epxa mtd flash map");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/maps/fortunet.c b/drivers/mtd/maps/fortunet.c
new file mode 100644
index 000000000000..98fd322e9523
--- /dev/null
+++ b/drivers/mtd/maps/fortunet.c
@@ -0,0 +1,309 @@
+/* fortunet.c memory map
+ *
+ * $Id: fortunet.c,v 1.2 2002/10/14 12:50:22 rmk Exp $
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+
+#define MAX_NUM_REGIONS 4
+#define MAX_NUM_PARTITIONS 8
+
+#define DEF_WINDOW_ADDR_PHY 0x00000000
+#define DEF_WINDOW_SIZE 0x00800000 // 8 Mega Bytes
+
+#define MTD_FORTUNET_PK "MTD FortuNet: "
+
+#define MAX_NAME_SIZE 128
+
+struct map_region
+{
+ int window_addr_phyical;
+ int altbuswidth;
+ struct map_info map_info;
+ struct mtd_info *mymtd;
+ struct mtd_partition parts[MAX_NUM_PARTITIONS];
+ char map_name[MAX_NAME_SIZE];
+ char parts_name[MAX_NUM_PARTITIONS][MAX_NAME_SIZE];
+};
+
+static struct map_region map_regions[MAX_NUM_REGIONS];
+static int map_regions_set[MAX_NUM_REGIONS] = {0,0,0,0};
+static int map_regions_parts[MAX_NUM_REGIONS] = {0,0,0,0};
+
+
+__u8 fortunet_read8(struct map_info *map, unsigned long ofs)
+{
+ return *(__u8 *)(map->map_priv_1 + ofs);
+}
+
+__u16 fortunet_read16(struct map_info *map, unsigned long ofs)
+{
+ return *(__u16 *)(map->map_priv_1 + ofs);
+}
+
+__u32 fortunet_read32(struct map_info *map, unsigned long ofs)
+{
+ return *(__u32 *)(map->map_priv_1 + ofs);
+}
+
+void fortunet_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+ memcpy(to, (void *)(map->map_priv_1 + from), len);
+}
+
+void fortunet_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+ *(__u8 *)(map->map_priv_1 + adr) = d;
+}
+
+void fortunet_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+ *(__u16 *)(map->map_priv_1 + adr) = d;
+}
+
+void fortunet_write32(struct map_info *map, __u32 d, unsigned long adr)
+{
+ *(__u32 *)(map->map_priv_1 + adr) = d;
+}
+
+void fortunet_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+ memcpy((void *)(map->map_priv_1 + to), from, len);
+}
+
+struct map_info default_map = {
+ size: DEF_WINDOW_SIZE,
+ buswidth: 4,
+ read8: fortunet_read8,
+ read16: fortunet_read16,
+ read32: fortunet_read32,
+ copy_from: fortunet_copy_from,
+ write8: fortunet_write8,
+ write16: fortunet_write16,
+ write32: fortunet_write32,
+ copy_to: fortunet_copy_to
+};
+
+static char * __init get_string_option(char *dest,int dest_size,char *sor)
+{
+ if(!dest_size)
+ return sor;
+ dest_size--;
+ while(*sor)
+ {
+ if(*sor==',')
+ {
+ sor++;
+ break;
+ }
+ else if(*sor=='\"')
+ {
+ sor++;
+ while(*sor)
+ {
+ if(*sor=='\"')
+ {
+ sor++;
+ break;
+ }
+ *dest = *sor;
+ dest++;
+ sor++;
+ dest_size--;
+ if(!dest_size)
+ {
+ *dest = 0;
+ return sor;
+ }
+ }
+ }
+ else
+ {
+ *dest = *sor;
+ dest++;
+ sor++;
+ dest_size--;
+ if(!dest_size)
+ {
+ *dest = 0;
+ return sor;
+ }
+ }
+ }
+ *dest = 0;
+ return sor;
+}
+
+static int __init MTD_New_Region(char *line)
+{
+ char string[MAX_NAME_SIZE];
+ int params[6];
+ get_options (get_string_option(string,sizeof(string),line),6,params);
+ if(params[0]<1)
+ {
+ printk(MTD_FORTUNET_PK "Bad paramters for MTD Region "
+ " name,region-number[,base,size,buswidth,altbuswidth]\n");
+ return 1;
+ }
+ if((params[1]<0)||(params[1]>=MAX_NUM_REGIONS))
+ {
+ printk(MTD_FORTUNET_PK "Bad region index of %d only have 0..%u regions\n",
+ params[1],MAX_NUM_REGIONS-1);
+ return 1;
+ }
+ memset(&map_regions[params[1]],0,sizeof(map_regions[params[1]]));
+ memcpy(&map_regions[params[1]].map_info,
+ &default_map,sizeof(map_regions[params[1]].map_info));
+ map_regions_set[params[1]] = 1;
+ map_regions[params[1]].window_addr_phyical = DEF_WINDOW_ADDR_PHY;
+ map_regions[params[1]].altbuswidth = 2;
+ map_regions[params[1]].mymtd = NULL;
+ map_regions[params[1]].map_info.name = map_regions[params[1]].map_name;
+ strcpy(map_regions[params[1]].map_info.name,string);
+ if(params[0]>1)
+ {
+ map_regions[params[1]].window_addr_phyical = params[2];
+ }
+ if(params[0]>2)
+ {
+ map_regions[params[1]].map_info.size = params[3];
+ }
+ if(params[0]>3)
+ {
+ map_regions[params[1]].map_info.buswidth = params[4];
+ }
+ if(params[0]>4)
+ {
+ map_regions[params[1]].altbuswidth = params[5];
+ }
+ return 1;
+}
+
+static int __init MTD_New_Partion(char *line)
+{
+ char string[MAX_NAME_SIZE];
+ int params[4];
+ get_options (get_string_option(string,sizeof(string),line),4,params);
+ if(params[0]<3)
+ {
+ printk(MTD_FORTUNET_PK "Bad paramters for MTD Partion "
+ " name,region-number,size,offset\n");
+ return 1;
+ }
+ if((params[1]<0)||(params[1]>=MAX_NUM_REGIONS))
+ {
+ printk(MTD_FORTUNET_PK "Bad region index of %d only have 0..%u regions\n",
+ params[1],MAX_NUM_REGIONS-1);
+ return 1;
+ }
+ if(map_regions_parts[params[1]]>=MAX_NUM_PARTITIONS)
+ {
+ printk(MTD_FORTUNET_PK "Out of space for partion in this region\n");
+ return 1;
+ }
+ map_regions[params[1]].parts[map_regions_parts[params[1]]].name =
+ map_regions[params[1]]. parts_name[map_regions_parts[params[1]]];
+ strcpy(map_regions[params[1]].parts[map_regions_parts[params[1]]].name,string);
+ map_regions[params[1]].parts[map_regions_parts[params[1]]].size =
+ params[2];
+ map_regions[params[1]].parts[map_regions_parts[params[1]]].offset =
+ params[3];
+ map_regions[params[1]].parts[map_regions_parts[params[1]]].mask_flags = 0;
+ map_regions_parts[params[1]]++;
+ return 1;
+}
+
+__setup("MTD_Region=", MTD_New_Region);
+__setup("MTD_Partion=", MTD_New_Partion);
+
+int __init init_fortunet(void)
+{
+ int ix,iy;
+ for(iy=ix=0;ix<MAX_NUM_REGIONS;ix++)
+ {
+ if(map_regions_parts[ix]&&(!map_regions_set[ix]))
+ {
+ printk(MTD_FORTUNET_PK "Region %d is not setup (Seting to default)\n",
+ ix);
+ memset(&map_regions[ix],0,sizeof(map_regions[ix]));
+ memcpy(&map_regions[ix].map_info,&default_map,
+ sizeof(map_regions[ix].map_info));
+ map_regions_set[ix] = 1;
+ map_regions[ix].window_addr_phyical = DEF_WINDOW_ADDR_PHY;
+ map_regions[ix].altbuswidth = 2;
+ map_regions[ix].mymtd = NULL;
+ map_regions[ix].map_info.name = map_regions[ix].map_name;
+ strcpy(map_regions[ix].map_info.name,"FORTUNET");
+ }
+ if(map_regions_set[ix])
+ {
+ iy++;
+ printk(KERN_NOTICE MTD_FORTUNET_PK "%s flash device at phyicaly "
+ " address %x size %x\n",
+ map_regions[ix].map_info.name,
+ map_regions[ix].window_addr_phyical,
+ map_regions[ix].map_info.size);
+ map_regions[ix].map_info.map_priv_1 =
+ (int)ioremap_nocache(
+ map_regions[ix].window_addr_phyical,
+ map_regions[ix].map_info.size);
+ if(!map_regions[ix].map_info.map_priv_1)
+ {
+ printk(MTD_FORTUNET_PK "%s flash failed to ioremap!\n",
+ map_regions[ix].map_info.name);
+ return -ENXIO;
+ }
+ printk(KERN_NOTICE MTD_FORTUNET_PK "%s flash is veritualy at: %x\n",
+ map_regions[ix].map_info.name,
+ map_regions[ix].map_info.map_priv_1);
+ map_regions[ix].mymtd = do_map_probe("cfi_probe",
+ &map_regions[ix].map_info);
+ if((!map_regions[ix].mymtd)&&(
+ map_regions[ix].altbuswidth!=map_regions[ix].map_info.buswidth))
+ {
+ printk(KERN_NOTICE MTD_FORTUNET_PK "Trying alternet buswidth "
+ "for %s flash.\n",
+ map_regions[ix].map_info.name);
+ map_regions[ix].map_info.buswidth =
+ map_regions[ix].altbuswidth;
+ map_regions[ix].mymtd = do_map_probe("cfi_probe",
+ &map_regions[ix].map_info);
+ }
+ map_regions[ix].mymtd->module = THIS_MODULE;
+ add_mtd_partitions(map_regions[ix].mymtd,
+ map_regions[ix].parts,map_regions_parts[ix]);
+ }
+ }
+ if(iy)
+ return 0;
+ return -ENXIO;
+}
+
+static void __exit cleanup_fortunet(void)
+{
+ int ix;
+ for(ix=0;ix<MAX_NUM_REGIONS;ix++)
+ {
+ if(map_regions_set[ix])
+ {
+ if( map_regions[ix].mymtd )
+ {
+ del_mtd_partitions( map_regions[ix].mymtd );
+ map_destroy( map_regions[ix].mymtd );
+ }
+ iounmap((void *)map_regions[ix].map_info.map_priv_1);
+ }
+ }
+}
+
+module_init(init_fortunet);
+module_exit(cleanup_fortunet);
+
+MODULE_AUTHOR("FortuNet, Inc.");
+MODULE_DESCRIPTION("MTD map driver for FortuNet boards");
diff --git a/drivers/mtd/maps/impa7.c b/drivers/mtd/maps/impa7.c
new file mode 100644
index 000000000000..3dc382bc9511
--- /dev/null
+++ b/drivers/mtd/maps/impa7.c
@@ -0,0 +1,234 @@
+/*
+ * $Id: impa7.c,v 1.2 2002/09/05 05:11:24 acurtis Exp $
+ *
+ * Handle mapping of the NOR flash on implementa A7 boards
+ *
+ * Copyright 2002 SYSGO Real-Time Solutions GmbH
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/config.h>
+
+#ifdef CONFIG_MTD_PARTITIONS
+#include <linux/mtd/partitions.h>
+#endif
+
+#define WINDOW_ADDR0 0x00000000 /* physical properties of flash */
+#define WINDOW_SIZE0 0x00800000
+#define WINDOW_ADDR1 0x10000000 /* physical properties of flash */
+#define WINDOW_SIZE1 0x00800000
+#define NUM_FLASHBANKS 2
+#define BUSWIDTH 4
+
+/* can be { "cfi_probe", "jedec_probe", "map_rom", 0 }; */
+#define PROBETYPES { "jedec_probe", 0 }
+
+#define MSG_PREFIX "impA7:" /* prefix for our printk()'s */
+#define MTDID "impa7-%d" /* for mtdparts= partitioning */
+
+static struct mtd_info *impa7_mtd[NUM_FLASHBANKS] = { 0 };
+
+__u8 impa7_read8(struct map_info *map, unsigned long ofs)
+{
+ return __raw_readb(map->map_priv_1 + ofs);
+}
+
+__u16 impa7_read16(struct map_info *map, unsigned long ofs)
+{
+ return __raw_readw(map->map_priv_1 + ofs);
+}
+
+__u32 impa7_read32(struct map_info *map, unsigned long ofs)
+{
+ return __raw_readl(map->map_priv_1 + ofs);
+}
+
+void impa7_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+ memcpy_fromio(to, map->map_priv_1 + from, len);
+}
+
+void impa7_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+ __raw_writeb(d, map->map_priv_1 + adr);
+ mb();
+}
+
+void impa7_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+ __raw_writew(d, map->map_priv_1 + adr);
+ mb();
+}
+
+void impa7_write32(struct map_info *map, __u32 d, unsigned long adr)
+{
+ __raw_writel(d, map->map_priv_1 + adr);
+ mb();
+}
+
+void impa7_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+ memcpy_toio(map->map_priv_1 + to, from, len);
+}
+
+static struct map_info impa7_map[NUM_FLASHBANKS] = {
+ {
+ name: "impA7 NOR Flash Bank #0",
+ size: WINDOW_SIZE0,
+ buswidth: BUSWIDTH,
+ read8: impa7_read8,
+ read16: impa7_read16,
+ read32: impa7_read32,
+ copy_from: impa7_copy_from,
+ write8: impa7_write8,
+ write16: impa7_write16,
+ write32: impa7_write32,
+ copy_to: impa7_copy_to
+ },
+ {
+ name: "impA7 NOR Flash Bank #1",
+ size: WINDOW_SIZE1,
+ buswidth: BUSWIDTH,
+ read8: impa7_read8,
+ read16: impa7_read16,
+ read32: impa7_read32,
+ copy_from: impa7_copy_from,
+ write8: impa7_write8,
+ write16: impa7_write16,
+ write32: impa7_write32,
+ copy_to: impa7_copy_to
+ },
+};
+
+#ifdef CONFIG_MTD_PARTITIONS
+
+/*
+ * MTD partitioning stuff
+ */
+static struct mtd_partition static_partitions[] =
+{
+ {
+ name: "FileSystem",
+ size: 0x800000,
+ offset: 0x00000000
+ },
+};
+
+#define NB_OF(x) (sizeof (x) / sizeof (x[0]))
+
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+int parse_cmdline_partitions(struct mtd_info *master,
+ struct mtd_partition **pparts,
+ const char *mtd_id);
+#endif
+
+#endif
+
+static int mtd_parts_nb = 0;
+static struct mtd_partition *mtd_parts = 0;
+
+int __init init_impa7(void)
+{
+ static const char *rom_probe_types[] = PROBETYPES;
+ const char **type;
+ const char *part_type = 0;
+ int i;
+ static struct { u_long addr; u_long size; } pt[NUM_FLASHBANKS] = {
+ { WINDOW_ADDR0, WINDOW_SIZE0 },
+ { WINDOW_ADDR1, WINDOW_SIZE1 },
+ };
+ char mtdid[10];
+ int devicesfound = 0;
+
+ for(i=0; i<NUM_FLASHBANKS; i++)
+ {
+ printk(KERN_NOTICE MSG_PREFIX "probing 0x%08lx at 0x%08lx\n",
+ pt[i].size, pt[i].addr);
+ impa7_map[i].map_priv_1 = (unsigned long)
+ ioremap(pt[i].addr, pt[i].size);
+
+ if (!impa7_map[i].map_priv_1) {
+ printk(MSG_PREFIX "failed to ioremap\n");
+ return -EIO;
+ }
+
+ impa7_mtd[i] = 0;
+ type = rom_probe_types;
+ for(; !impa7_mtd[i] && *type; type++) {
+ impa7_mtd[i] = do_map_probe(*type, &impa7_map[i]);
+ }
+
+ if (impa7_mtd[i])
+ {
+ impa7_mtd[i]->module = THIS_MODULE;
+ add_mtd_device(impa7_mtd[i]);
+ devicesfound++;
+#ifdef CONFIG_MTD_PARTITIONS
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+ sprintf(mtdid, MTDID, i);
+ mtd_parts_nb = parse_cmdline_partitions(impa7_mtd[i],
+ &mtd_parts,
+ mtdid);
+ if (mtd_parts_nb > 0)
+ part_type = "command line";
+#endif
+ if (mtd_parts_nb <= 0)
+ {
+ mtd_parts = static_partitions;
+ mtd_parts_nb = NB_OF(static_partitions);
+ part_type = "static";
+ }
+ if (mtd_parts_nb <= 0)
+ {
+ printk(KERN_NOTICE MSG_PREFIX
+ "no partition info available\n");
+ }
+ else
+ {
+ printk(KERN_NOTICE MSG_PREFIX
+ "using %s partition definition\n",
+ part_type);
+ add_mtd_partitions(impa7_mtd[i],
+ mtd_parts, mtd_parts_nb);
+ }
+#endif
+ }
+ else
+ iounmap((void *)impa7_map[i].map_priv_1);
+ }
+ return devicesfound == 0 ? -ENXIO : 0;
+}
+
+static void __exit cleanup_impa7(void)
+{
+ int i;
+ for (i=0; i<NUM_FLASHBANKS; i++)
+ {
+ if (impa7_mtd[i])
+ {
+ del_mtd_device(impa7_mtd[i]);
+ map_destroy(impa7_mtd[i]);
+ }
+ if (impa7_map[i].map_priv_1)
+ {
+ iounmap((void *)impa7_map[i].map_priv_1);
+ impa7_map[i].map_priv_1 = 0;
+ }
+ }
+}
+
+module_init(init_impa7);
+module_exit(cleanup_impa7);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Pavel Bartusek <pba@sysgo.de>");
+MODULE_DESCRIPTION("MTD map driver for implementa impA7");
diff --git a/drivers/mtd/maps/iq80310.c b/drivers/mtd/maps/iq80310.c
index cb3cb05766d1..3a301135831b 100644
--- a/drivers/mtd/maps/iq80310.c
+++ b/drivers/mtd/maps/iq80310.c
@@ -1,5 +1,5 @@
/*
- * $Id: iq80310.c,v 1.8 2001/10/02 15:05:14 dwmw2 Exp $
+ * $Id: iq80310.c,v 1.9 2002/01/01 22:45:02 rmk Exp $
*
* Mapping for the Intel XScale IQ80310 evaluation board
*
@@ -116,7 +116,7 @@ static int __init init_iq80310(void)
int parsed_nr_parts = 0;
char *part_type = "static";
- iq80310_map.map_priv_1 = (unsigned long)__ioremap(WINDOW_ADDR, WINDOW_SIZE, 0);
+ iq80310_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE);
if (!iq80310_map.map_priv_1) {
printk("Failed to ioremap\n");
return -EIO;
@@ -161,7 +161,6 @@ static void __exit cleanup_iq80310(void)
}
if (iq80310_map.map_priv_1)
iounmap((void *)iq80310_map.map_priv_1);
- return 0;
}
module_init(init_iq80310);
diff --git a/drivers/mtd/maps/pci.c b/drivers/mtd/maps/pci.c
new file mode 100644
index 000000000000..ccc854980c6f
--- /dev/null
+++ b/drivers/mtd/maps/pci.c
@@ -0,0 +1,385 @@
+/*
+ * linux/drivers/mtd/maps/pci.c
+ *
+ * Copyright (C) 2001 Russell King, All rights reserved.
+ *
+ * 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.
+ *
+ * $Id: pci.c,v 1.1 2001/09/27 20:28:45 rmk 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
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+
+struct map_pci_info;
+
+struct mtd_pci_info {
+ int (*init)(struct pci_dev *dev, struct map_pci_info *map);
+ void (*exit)(struct pci_dev *dev, struct map_pci_info *map);
+ unsigned long (*translate)(struct map_pci_info *map, unsigned long ofs);
+ const char *map_name;
+};
+
+struct map_pci_info {
+ struct map_info map;
+ void *base;
+ void (*exit)(struct pci_dev *dev, struct map_pci_info *map);
+ unsigned long (*translate)(struct map_pci_info *map, unsigned long ofs);
+ struct pci_dev *dev;
+};
+
+/*
+ * Intel IOP80310 Flash driver
+ */
+
+static int
+intel_iq80310_init(struct pci_dev *dev, struct map_pci_info *map)
+{
+ u32 win_base;
+
+ map->map.buswidth = 1;
+ map->map.size = 0x00800000;
+ map->base = ioremap_nocache(pci_resource_start(dev, 0),
+ pci_resource_len(dev, 0));
+
+ if (!map->base)
+ return -ENOMEM;
+
+ /*
+ * We want to base the memory window at Xscale
+ * bus address 0, not 0x1000.
+ */
+ pci_read_config_dword(dev, 0x44, &win_base);
+ pci_write_config_dword(dev, 0x44, 0);
+
+ map->map.map_priv_2 = win_base;
+
+ return 0;
+}
+
+static void
+intel_iq80310_exit(struct pci_dev *dev, struct map_pci_info *map)
+{
+ if (map->base)
+ iounmap((void *)map->base);
+ pci_write_config_dword(dev, 0x44, map->map.map_priv_2);
+}
+
+static unsigned long
+intel_iq80310_translate(struct map_pci_info *map, unsigned long ofs)
+{
+ unsigned long page_addr = ofs & 0x00400000;
+
+ /*
+ * This mundges the flash location so we avoid
+ * the first 80 bytes (they appear to read nonsense).
+ */
+ if (page_addr) {
+ writel(0x00000008, map->base + 0x1558);
+ writel(0x00000000, map->base + 0x1550);
+ } else {
+ writel(0x00000007, map->base + 0x1558);
+ writel(0x00800000, map->base + 0x1550);
+ ofs += 0x00800000;
+ }
+
+ return ofs;
+}
+
+static struct mtd_pci_info intel_iq80310_info = {
+ init: intel_iq80310_init,
+ exit: intel_iq80310_exit,
+ translate: intel_iq80310_translate,
+ map_name: "cfi_probe",
+};
+
+/*
+ * Intel DC21285 driver
+ */
+
+static int
+intel_dc21285_init(struct pci_dev *dev, struct map_pci_info *map)
+{
+ unsigned long base, len;
+
+ base = pci_resource_start(dev, PCI_ROM_RESOURCE);
+ len = pci_resource_len(dev, PCI_ROM_RESOURCE);
+
+ if (!len || !base) {
+ /*
+ * No ROM resource
+ */
+ base = pci_resource_start(dev, 2);
+ len = pci_resource_len(dev, 2);
+
+ /*
+ * We need to re-allocate PCI BAR2 address range to the
+ * PCI ROM BAR, and disable PCI BAR2.
+ */
+ } else {
+ /*
+ * Hmm, if an address was allocated to the ROM resource, but
+ * not enabled, should we be allocating a new resource for it
+ * or simply enabling it?
+ */
+ if (!(pci_resource_flags(dev, PCI_ROM_RESOURCE) &
+ PCI_ROM_ADDRESS_ENABLE)) {
+ u32 val;
+ pci_resource_flags(dev, PCI_ROM_RESOURCE) |= PCI_ROM_ADDRESS_ENABLE;
+ pci_read_config_dword(dev, PCI_ROM_ADDRESS, &val);
+ val |= PCI_ROM_ADDRESS_ENABLE;
+ pci_write_config_dword(dev, PCI_ROM_ADDRESS, val);
+ printk("%s: enabling expansion ROM\n", dev->slot_name);
+ }
+ }
+
+ if (!len || !base)
+ return -ENXIO;
+
+ map->map.buswidth = 4;
+ map->map.size = len;
+ map->base = ioremap_nocache(base, len);
+
+ if (!map->base)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static void
+intel_dc21285_exit(struct pci_dev *dev, struct map_pci_info *map)
+{
+ u32 val;
+
+ if (map->base)
+ iounmap((void *)map->base);
+
+ /*
+ * We need to undo the PCI BAR2/PCI ROM BAR address alteration.
+ */
+ pci_resource_flags(dev, PCI_ROM_RESOURCE) &= ~PCI_ROM_ADDRESS_ENABLE;
+ pci_read_config_dword(dev, PCI_ROM_ADDRESS, &val);
+ val &= ~PCI_ROM_ADDRESS_ENABLE;
+ pci_write_config_dword(dev, PCI_ROM_ADDRESS, val);
+}
+
+static unsigned long
+intel_dc21285_translate(struct map_pci_info *map, unsigned long ofs)
+{
+ return ofs & 0x00ffffc0 ? ofs : (ofs ^ (1 << 5));
+}
+
+static struct mtd_pci_info intel_dc21285_info = {
+ init: intel_dc21285_init,
+ exit: intel_dc21285_exit,
+ translate: intel_dc21285_translate,
+ map_name: "jedec_probe",
+};
+
+/*
+ * PCI device ID table
+ */
+
+static struct pci_device_id mtd_pci_ids[] __devinitdata = {
+ {
+ vendor: PCI_VENDOR_ID_INTEL,
+ device: 0x530d,
+ subvendor: PCI_ANY_ID,
+ subdevice: PCI_ANY_ID,
+ class: PCI_CLASS_MEMORY_OTHER << 8,
+ class_mask: 0xffff00,
+ driver_data: (unsigned long)&intel_iq80310_info,
+ },
+ {
+ vendor: PCI_VENDOR_ID_DEC,
+ device: PCI_DEVICE_ID_DEC_21285,
+ subvendor: 0, /* DC21285 defaults to 0 on reset */
+ subdevice: 0, /* DC21285 defaults to 0 on reset */
+ class: 0,
+ class_mask: 0,
+ driver_data: (unsigned long)&intel_dc21285_info,
+ },
+ { 0, }
+};
+
+/*
+ * Generic code follows.
+ */
+
+static u8 mtd_pci_read8(struct map_info *_map, unsigned long ofs)
+{
+ struct map_pci_info *map = (struct map_pci_info *)_map;
+ u8 val = readb(map->base + map->translate(map, ofs));
+// printk("read8 : %08lx => %02x\n", ofs, val);
+ return val;
+}
+
+static u16 mtd_pci_read16(struct map_info *_map, unsigned long ofs)
+{
+ struct map_pci_info *map = (struct map_pci_info *)_map;
+ u16 val = readw(map->base + map->translate(map, ofs));
+// printk("read16: %08lx => %04x\n", ofs, val);
+ return val;
+}
+
+static u32 mtd_pci_read32(struct map_info *_map, unsigned long ofs)
+{
+ struct map_pci_info *map = (struct map_pci_info *)_map;
+ u32 val = readl(map->base + map->translate(map, ofs));
+// printk("read32: %08lx => %08x\n", ofs, val);
+ return val;
+}
+
+static void mtd_pci_copyfrom(struct map_info *_map, void *to, unsigned long from, ssize_t len)
+{
+ struct map_pci_info *map = (struct map_pci_info *)_map;
+ memcpy_fromio(to, map->base + map->translate(map, from), len);
+}
+
+static void mtd_pci_write8(struct map_info *_map, u8 val, unsigned long ofs)
+{
+ struct map_pci_info *map = (struct map_pci_info *)_map;
+// printk("write8 : %08lx <= %02x\n", ofs, val);
+ writeb(val, map->base + map->translate(map, ofs));
+}
+
+static void mtd_pci_write16(struct map_info *_map, u16 val, unsigned long ofs)
+{
+ struct map_pci_info *map = (struct map_pci_info *)_map;
+// printk("write16: %08lx <= %04x\n", ofs, val);
+ writew(val, map->base + map->translate(map, ofs));
+}
+
+static void mtd_pci_write32(struct map_info *_map, u32 val, unsigned long ofs)
+{
+ struct map_pci_info *map = (struct map_pci_info *)_map;
+// printk("write32: %08lx <= %08x\n", ofs, val);
+ writel(val, map->base + map->translate(map, ofs));
+}
+
+static void mtd_pci_copyto(struct map_info *_map, unsigned long to, const void *from, ssize_t len)
+{
+ struct map_pci_info *map = (struct map_pci_info *)_map;
+ memcpy_toio(map->base + map->translate(map, to), from, len);
+}
+
+static struct map_info mtd_pci_map = {
+ read8: mtd_pci_read8,
+ read16: mtd_pci_read16,
+ read32: mtd_pci_read32,
+ copy_from: mtd_pci_copyfrom,
+ write8: mtd_pci_write8,
+ write16: mtd_pci_write16,
+ write32: mtd_pci_write32,
+ copy_to: mtd_pci_copyto,
+};
+
+static int __devinit
+mtd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ struct mtd_pci_info *info = (struct mtd_pci_info *)id->driver_data;
+ struct map_pci_info *map = NULL;
+ struct mtd_info *mtd = NULL;
+ int err;
+
+ err = pci_enable_device(dev);
+ if (err)
+ goto out;
+
+ err = pci_request_regions(dev, "pci mtd");
+ if (err)
+ goto out;
+
+ map = kmalloc(sizeof(*map), GFP_KERNEL);
+ err = -ENOMEM;
+ if (!map)
+ goto release;
+
+ map->map = mtd_pci_map;
+ map->map.name = dev->slot_name;
+ map->dev = dev;
+ map->exit = info->exit;
+ map->translate = info->translate;
+
+ err = info->init(dev, map);
+ if (err)
+ goto release;
+
+ /* tsk - do_map_probe should take const char * */
+ mtd = do_map_probe((char *)info->map_name, &map->map);
+ err = -ENODEV;
+ if (!mtd)
+ goto release;
+
+ mtd->module = THIS_MODULE;
+ add_mtd_device(mtd);
+
+ pci_set_drvdata(dev, mtd);
+
+ return 0;
+
+release:
+ if (mtd)
+ map_destroy(mtd);
+
+ if (map) {
+ map->exit(dev, map);
+ kfree(map);
+ }
+
+ pci_release_regions(dev);
+out:
+ return err;
+}
+
+static void __devexit
+mtd_pci_remove(struct pci_dev *dev)
+{
+ struct mtd_info *mtd = pci_get_drvdata(dev);
+ struct map_pci_info *map = mtd->priv;
+
+ del_mtd_device(mtd);
+ map_destroy(mtd);
+ map->exit(dev, map);
+ kfree(map);
+
+ pci_set_drvdata(dev, NULL);
+ pci_release_regions(dev);
+}
+
+static struct pci_driver mtd_pci_driver = {
+ name: "MTD PCI",
+ probe: mtd_pci_probe,
+ remove: mtd_pci_remove,
+ id_table: mtd_pci_ids,
+};
+
+static int __init mtd_pci_maps_init(void)
+{
+ return pci_module_init(&mtd_pci_driver);
+}
+
+static void __exit mtd_pci_maps_exit(void)
+{
+ pci_unregister_driver(&mtd_pci_driver);
+}
+
+module_init(mtd_pci_maps_init);
+module_exit(mtd_pci_maps_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
+MODULE_DESCRIPTION("Generic PCI map driver");
+MODULE_DEVICE_TABLE(pci, mtd_pci_ids);
+
diff --git a/drivers/mtd/maps/pcmciamtd.c b/drivers/mtd/maps/pcmciamtd.c
new file mode 100644
index 000000000000..fb87cdd8b873
--- /dev/null
+++ b/drivers/mtd/maps/pcmciamtd.c
@@ -0,0 +1,893 @@
+/*
+ * $Id: pcmciamtd.c,v 1.36 2002/10/14 18:49:12 rmk Exp $
+ *
+ * pcmciamtd.c - MTD driver for PCMCIA flash memory cards
+ *
+ * Author: Simon Evans <spse@secret.org.uk>
+ *
+ * Copyright (C) 2002 Simon Evans
+ *
+ * Licence: GPL
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/timer.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+
+#include <linux/mtd/map.h>
+
+#ifdef CONFIG_MTD_DEBUG
+static int debug = CONFIG_MTD_DEBUG_VERBOSE;
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Set Debug Level 0=quiet, 5=noisy");
+#undef DEBUG
+#define DEBUG(n, format, arg...) \
+ if (n <= debug) { \
+ printk(KERN_DEBUG __FILE__ ":%s(): " format "\n", __FUNCTION__ , ## arg); \
+ }
+
+#else
+#undef DEBUG
+#define DEBUG(n, arg...)
+static const int debug = 0;
+#endif
+
+#define err(format, arg...) printk(KERN_ERR __FILE__ ": " format "\n" , ## arg)
+#define info(format, arg...) printk(KERN_INFO __FILE__ ": " format "\n" , ## arg)
+#define warn(format, arg...) printk(KERN_WARNING __FILE__ ": " format "\n" , ## arg)
+
+
+#define DRIVER_DESC "PCMCIA Flash memory card driver"
+#define DRIVER_VERSION "$Revision: 1.36 $"
+
+/* Size of the PCMCIA address space: 26 bits = 64 MB */
+#define MAX_PCMCIA_ADDR 0x4000000
+
+struct pcmciamtd_dev {
+ struct list_head list;
+ dev_link_t link; /* PCMCIA link */
+ caddr_t win_base; /* ioremapped address of PCMCIA window */
+ unsigned int win_size; /* size of window */
+ unsigned int cardsize; /* size of whole card */
+ unsigned int offset; /* offset into card the window currently points at */
+ struct map_info pcmcia_map;
+ struct mtd_info *mtd_info;
+ u8 vpp;
+ char mtd_name[sizeof(struct cistpl_vers_1_t)];
+};
+
+
+static dev_info_t dev_info = "pcmciamtd";
+static LIST_HEAD(dev_list);
+
+/* Module parameters */
+
+/* 2 = do 16-bit transfers, 1 = do 8-bit transfers */
+static int buswidth = 2;
+
+/* Speed of memory accesses, in ns */
+static int mem_speed;
+
+/* Force the size of an SRAM card */
+static int force_size;
+
+/* Force Vpp */
+static int vpp;
+
+/* Set Vpp */
+static int setvpp;
+
+/* Force card to be treated as FLASH, ROM or RAM */
+static int mem_type;
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Simon Evans <spse@secret.org.uk>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_PARM(buswidth, "i");
+MODULE_PARM_DESC(buswidth, "Set buswidth (1=8 bit, 2=16 bit, default=2)");
+MODULE_PARM(mem_speed, "i");
+MODULE_PARM_DESC(mem_speed, "Set memory access speed in ns");
+MODULE_PARM(force_size, "i");
+MODULE_PARM_DESC(force_size, "Force size of card in MB (1-64)");
+MODULE_PARM(setvpp, "i");
+MODULE_PARM_DESC(setvpp, "Set Vpp (0=Never, 1=On writes, 2=Always on, default=0)");
+MODULE_PARM(vpp, "i");
+MODULE_PARM_DESC(vpp, "Vpp value in 1/10ths eg 33=3.3V 120=12V (Dangerous)");
+MODULE_PARM(mem_type, "i");
+MODULE_PARM_DESC(mem_type, "Set Memory type (0=Flash, 1=RAM, 2=ROM, default=0)");
+
+
+
+static void inline cs_error(client_handle_t handle, int func, int ret)
+{
+ error_info_t err = { func, ret };
+ CardServices(ReportError, handle, &err);
+}
+
+
+/* read/write{8,16} copy_{from,to} routines with window remapping to access whole card */
+
+static caddr_t remap_window(struct map_info *map, unsigned long to)
+{
+ struct pcmciamtd_dev *dev = (struct pcmciamtd_dev *)map->map_priv_1;
+ window_handle_t win = (window_handle_t)map->map_priv_2;
+ memreq_t mrq;
+ int ret;
+
+ mrq.CardOffset = to & ~(dev->win_size-1);
+ if(mrq.CardOffset != dev->offset) {
+ DEBUG(2, "Remapping window from 0x%8.8x to 0x%8.8x",
+ dev->offset, mrq.CardOffset);
+ mrq.Page = 0;
+ if( (ret = CardServices(MapMemPage, win, &mrq)) != CS_SUCCESS) {
+ cs_error(dev->link.handle, MapMemPage, ret);
+ return NULL;
+ }
+ dev->offset = mrq.CardOffset;
+ }
+ return dev->win_base + (to & (dev->win_size-1));
+}
+
+
+static u8 pcmcia_read8_remap(struct map_info *map, unsigned long ofs)
+{
+ caddr_t addr;
+ u8 d;
+
+ addr = remap_window(map, ofs);
+ if(!addr)
+ return 0;
+
+ d = readb(addr);
+ DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%02x", ofs, addr, d);
+ return d;
+}
+
+
+static u16 pcmcia_read16_remap(struct map_info *map, unsigned long ofs)
+{
+ caddr_t addr;
+ u16 d;
+
+ addr = remap_window(map, ofs);
+ if(!addr)
+ return 0;
+
+ d = readw(addr);
+ DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%04x", ofs, addr, d);
+ return d;
+}
+
+
+static void pcmcia_copy_from_remap(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+ struct pcmciamtd_dev *dev = (struct pcmciamtd_dev *)map->map_priv_1;
+ unsigned long win_size = dev->win_size;
+
+ DEBUG(3, "to = %p from = %lu len = %u", to, from, len);
+ while(len) {
+ int toread = win_size - (from & (win_size-1));
+ caddr_t addr;
+
+ if(toread > len)
+ toread = len;
+
+ addr = remap_window(map, from);
+ if(!addr)
+ return;
+
+ DEBUG(4, "memcpy from %p to %p len = %d", addr, to, toread);
+ memcpy_fromio(to, addr, toread);
+ len -= toread;
+ to += toread;
+ from += toread;
+ }
+}
+
+
+static void pcmcia_write8_remap(struct map_info *map, u8 d, unsigned long adr)
+{
+ caddr_t addr = remap_window(map, adr);
+
+ if(!addr)
+ return;
+
+ DEBUG(3, "adr = 0x%08lx (%p) data = 0x%02x", adr, addr, d);
+ writeb(d, addr);
+}
+
+
+static void pcmcia_write16_remap(struct map_info *map, u16 d, unsigned long adr)
+{
+ caddr_t addr = remap_window(map, adr);
+ if(!addr)
+ return;
+
+ DEBUG(3, "adr = 0x%08lx (%p) data = 0x%04x", adr, addr, d);
+ writew(d, addr);
+}
+
+
+static void pcmcia_copy_to_remap(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+ struct pcmciamtd_dev *dev = (struct pcmciamtd_dev *)map->map_priv_1;
+ unsigned long win_size = dev->win_size;
+
+ DEBUG(3, "to = %lu from = %p len = %u", to, from, len);
+ while(len) {
+ int towrite = win_size - (to & (win_size-1));
+ caddr_t addr;
+
+ if(towrite > len)
+ towrite = len;
+
+ addr = remap_window(map, to);
+ if(!addr)
+ return;
+
+ DEBUG(4, "memcpy from %p to %p len = %d", from, addr, towrite);
+ memcpy_toio(addr, from, towrite);
+ len -= towrite;
+ to += towrite;
+ from += towrite;
+ }
+}
+
+
+/* read/write{8,16} copy_{from,to} routines with direct access */
+
+static u8 pcmcia_read8(struct map_info *map, unsigned long ofs)
+{
+ caddr_t win_base = (caddr_t)map->map_priv_2;
+ u8 d;
+
+ d = readb(win_base + ofs);
+ DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%02x", ofs, win_base + ofs, d);
+ return d;
+}
+
+
+static u16 pcmcia_read16(struct map_info *map, unsigned long ofs)
+{
+ caddr_t win_base = (caddr_t)map->map_priv_2;
+ u16 d;
+
+ d = readw(win_base + ofs);
+ DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%04x", ofs, win_base + ofs, d);
+ return d;
+}
+
+
+static void pcmcia_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+ caddr_t win_base = (caddr_t)map->map_priv_2;
+
+ DEBUG(3, "to = %p from = %lu len = %u", to, from, len);
+ memcpy_fromio(to, win_base + from, len);
+}
+
+
+static void pcmcia_write8(struct map_info *map, u8 d, unsigned long adr)
+{
+ caddr_t win_base = (caddr_t)map->map_priv_2;
+
+ DEBUG(3, "adr = 0x%08lx (%p) data = 0x%02x", adr, win_base + adr, d);
+ writeb(d, win_base + adr);
+}
+
+
+static void pcmcia_write16(struct map_info *map, u16 d, unsigned long adr)
+{
+ caddr_t win_base = (caddr_t)map->map_priv_2;
+
+ DEBUG(3, "adr = 0x%08lx (%p) data = 0x%04x", adr, win_base + adr, d);
+ writew(d, win_base + adr);
+}
+
+
+static void pcmcia_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+ caddr_t win_base = (caddr_t)map->map_priv_2;
+
+ DEBUG(3, "to = %lu from = %p len = %u", to, from, len);
+ memcpy_toio(win_base + to, from, len);
+}
+
+
+static void pcmciamtd_set_vpp(struct map_info *map, int on)
+{
+ struct pcmciamtd_dev *dev = (struct pcmciamtd_dev *)map->map_priv_1;
+ dev_link_t *link = &dev->link;
+ modconf_t mod;
+ int ret;
+
+ mod.Attributes = CONF_VPP1_CHANGE_VALID | CONF_VPP2_CHANGE_VALID;
+ mod.Vcc = 0;
+ mod.Vpp1 = mod.Vpp2 = on ? dev->vpp : 0;
+
+ DEBUG(2, "dev = %p on = %d vpp = %d\n", dev, on, dev->vpp);
+ ret = CardServices(ModifyConfiguration, link->handle, &mod);
+ if(ret != CS_SUCCESS) {
+ cs_error(link->handle, ModifyConfiguration, ret);
+ }
+}
+
+
+/* After a card is removed, pcmciamtd_release() will unregister the
+ * device, and release the PCMCIA configuration. If the device is
+ * still open, this will be postponed until it is closed.
+ */
+
+static void pcmciamtd_release(u_long arg)
+{
+ dev_link_t *link = (dev_link_t *)arg;
+ struct pcmciamtd_dev *dev = NULL;
+ int ret;
+ struct list_head *temp1, *temp2;
+
+ DEBUG(3, "link = 0x%p", link);
+ /* Find device in list */
+ list_for_each_safe(temp1, temp2, &dev_list) {
+ dev = list_entry(temp1, struct pcmciamtd_dev, list);
+ if(link == &dev->link)
+ break;
+ }
+ if(link != &dev->link) {
+ DEBUG(1, "Cant find %p in dev_list", link);
+ return;
+ }
+
+ if(dev) {
+ if(dev->mtd_info) {
+ del_mtd_device(dev->mtd_info);
+ dev->mtd_info = NULL;
+ MOD_DEC_USE_COUNT;
+ }
+ if (link->win) {
+ if(dev->win_base) {
+ iounmap(dev->win_base);
+ dev->win_base = NULL;
+ }
+ CardServices(ReleaseWindow, link->win);
+ }
+ ret = CardServices(ReleaseConfiguration, link->handle);
+ if(ret != CS_SUCCESS)
+ cs_error(link->handle, ReleaseConfiguration, ret);
+
+ }
+ link->state &= ~DEV_CONFIG;
+}
+
+
+static void card_settings(struct pcmciamtd_dev *dev, dev_link_t *link, int *new_name)
+{
+ int rc;
+ tuple_t tuple;
+ cisparse_t parse;
+ u_char buf[64];
+
+ tuple.Attributes = 0;
+ tuple.TupleData = (cisdata_t *)buf;
+ tuple.TupleDataMax = sizeof(buf);
+ tuple.TupleOffset = 0;
+ tuple.DesiredTuple = RETURN_FIRST_TUPLE;
+
+ rc = CardServices(GetFirstTuple, link->handle, &tuple);
+ while(rc == CS_SUCCESS) {
+ rc = CardServices(GetTupleData, link->handle, &tuple);
+ if(rc != CS_SUCCESS) {
+ cs_error(link->handle, GetTupleData, rc);
+ break;
+ }
+ rc = CardServices(ParseTuple, link->handle, &tuple, &parse);
+ if(rc != CS_SUCCESS) {
+ cs_error(link->handle, ParseTuple, rc);
+ break;
+ }
+
+ switch(tuple.TupleCode) {
+ case CISTPL_FORMAT: {
+ cistpl_format_t *t = &parse.format;
+ (void)t; /* Shut up, gcc */
+ DEBUG(2, "Format type: %u, Error Detection: %u, offset = %u, length =%u",
+ t->type, t->edc, t->offset, t->length);
+ break;
+
+ }
+
+ case CISTPL_DEVICE: {
+ cistpl_device_t *t = &parse.device;
+ int i;
+ DEBUG(2, "Common memory:");
+ dev->pcmcia_map.size = t->dev[0].size;
+ for(i = 0; i < t->ndev; i++) {
+ DEBUG(2, "Region %d, type = %u", i, t->dev[i].type);
+ DEBUG(2, "Region %d, wp = %u", i, t->dev[i].wp);
+ DEBUG(2, "Region %d, speed = %u ns", i, t->dev[i].speed);
+ DEBUG(2, "Region %d, size = %u bytes", i, t->dev[i].size);
+ }
+ break;
+ }
+
+ case CISTPL_VERS_1: {
+ cistpl_vers_1_t *t = &parse.version_1;
+ int i;
+ if(t->ns) {
+ dev->mtd_name[0] = '\0';
+ for(i = 0; i < t->ns; i++) {
+ if(i)
+ strcat(dev->mtd_name, " ");
+ strcat(dev->mtd_name, t->str+t->ofs[i]);
+ }
+ }
+ DEBUG(2, "Found name: %s", dev->mtd_name);
+ break;
+ }
+
+ case CISTPL_JEDEC_C: {
+ cistpl_jedec_t *t = &parse.jedec;
+ int i;
+ for(i = 0; i < t->nid; i++) {
+ DEBUG(2, "JEDEC: 0x%02x 0x%02x", t->id[i].mfr, t->id[i].info);
+ }
+ break;
+ }
+
+ case CISTPL_DEVICE_GEO: {
+ cistpl_device_geo_t *t = &parse.device_geo;
+ int i;
+ dev->pcmcia_map.buswidth = t->geo[0].buswidth;
+ for(i = 0; i < t->ngeo; i++) {
+ DEBUG(2, "region: %d buswidth = %u", i, t->geo[i].buswidth);
+ DEBUG(2, "region: %d erase_block = %u", i, t->geo[i].erase_block);
+ DEBUG(2, "region: %d read_block = %u", i, t->geo[i].read_block);
+ DEBUG(2, "region: %d write_block = %u", i, t->geo[i].write_block);
+ DEBUG(2, "region: %d partition = %u", i, t->geo[i].partition);
+ DEBUG(2, "region: %d interleave = %u", i, t->geo[i].interleave);
+ }
+ break;
+ }
+
+ default:
+ DEBUG(2, "Unknown tuple code %d", tuple.TupleCode);
+ }
+
+ rc = CardServices(GetNextTuple, link->handle, &tuple, &parse);
+ }
+ if(!dev->pcmcia_map.size)
+ dev->pcmcia_map.size = MAX_PCMCIA_ADDR;
+
+ if(!dev->pcmcia_map.buswidth)
+ dev->pcmcia_map.buswidth = 2;
+
+ if(force_size) {
+ dev->pcmcia_map.size = force_size << 20;
+ DEBUG(2, "size forced to %dM", force_size);
+
+ }
+
+ if(buswidth) {
+ dev->pcmcia_map.buswidth = buswidth;
+ DEBUG(2, "buswidth forced to %d", buswidth);
+ }
+
+ dev->pcmcia_map.name = dev->mtd_name;
+ if(!dev->mtd_name[0]) {
+ strcpy(dev->mtd_name, "PCMCIA Memory card");
+ *new_name = 1;
+ }
+
+ DEBUG(1, "Device: Size: %lu Width:%d Name: %s",
+ dev->pcmcia_map.size, dev->pcmcia_map.buswidth << 3, dev->mtd_name);
+}
+
+
+/* pcmciamtd_config() is scheduled to run after a CARD_INSERTION event
+ * is received, to configure the PCMCIA socket, and to make the
+ * MTD device available to the system.
+ */
+
+#define CS_CHECK(fn, args...) \
+while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
+
+static void pcmciamtd_config(dev_link_t *link)
+{
+ struct pcmciamtd_dev *dev = link->priv;
+ struct mtd_info *mtd = NULL;
+ cs_status_t status;
+ win_req_t req;
+ int last_ret = 0, last_fn = 0;
+ int ret;
+ int i;
+ config_info_t t;
+ static char *probes[] = { "jedec_probe", "cfi_probe" };
+ cisinfo_t cisinfo;
+ int new_name = 0;
+
+ DEBUG(3, "link=0x%p", link);
+
+ /* Configure card */
+ link->state |= DEV_CONFIG;
+
+ DEBUG(2, "Validating CIS");
+ ret = CardServices(ValidateCIS, link->handle, &cisinfo);
+ if(ret != CS_SUCCESS) {
+ cs_error(link->handle, GetTupleData, ret);
+ } else {
+ DEBUG(2, "ValidateCIS found %d chains", cisinfo.Chains);
+ }
+
+ card_settings(dev, link, &new_name);
+
+ dev->pcmcia_map.read8 = pcmcia_read8_remap;
+ dev->pcmcia_map.read16 = pcmcia_read16_remap;
+ dev->pcmcia_map.copy_from = pcmcia_copy_from_remap;
+ dev->pcmcia_map.write8 = pcmcia_write8_remap;
+ dev->pcmcia_map.write16 = pcmcia_write16_remap;
+ dev->pcmcia_map.copy_to = pcmcia_copy_to_remap;
+ if(setvpp == 1)
+ dev->pcmcia_map.set_vpp = pcmciamtd_set_vpp;
+
+ /* Request a memory window for PCMCIA. Some architeures can map windows upto the maximum
+ that PCMCIA can support (64Mb) - this is ideal and we aim for a window the size of the
+ whole card - otherwise we try smaller windows until we succeed */
+
+ req.Attributes = WIN_MEMORY_TYPE_CM | WIN_ENABLE;
+ req.Attributes |= (dev->pcmcia_map.buswidth == 1) ? WIN_DATA_WIDTH_8 : WIN_DATA_WIDTH_16;
+ req.Base = 0;
+ req.AccessSpeed = mem_speed;
+ link->win = (window_handle_t)link->handle;
+ req.Size = (force_size) ? force_size << 20 : MAX_PCMCIA_ADDR;
+ dev->win_size = 0;
+
+ do {
+ int ret;
+ DEBUG(2, "requesting window with size = %dKB memspeed = %d",
+ req.Size >> 10, req.AccessSpeed);
+ link->win = (window_handle_t)link->handle;
+ ret = CardServices(RequestWindow, &link->win, &req);
+ DEBUG(2, "ret = %d dev->win_size = %d", ret, dev->win_size);
+ if(ret) {
+ req.Size >>= 1;
+ } else {
+ DEBUG(2, "Got window of size %dKB", req.Size >> 10);
+ dev->win_size = req.Size;
+ break;
+ }
+ } while(req.Size >= 0x1000);
+
+ DEBUG(2, "dev->win_size = %d", dev->win_size);
+
+ if(!dev->win_size) {
+ err("Cant allocate memory window");
+ pcmciamtd_release((u_long)link);
+ return;
+ }
+ DEBUG(1, "Allocated a window of %dKB", dev->win_size >> 10);
+
+ /* Get write protect status */
+ CS_CHECK(GetStatus, link->handle, &status);
+ DEBUG(2, "status value: 0x%x window handle = 0x%8.8lx",
+ status.CardState, (unsigned long)link->win);
+ dev->win_base = ioremap(req.Base, req.Size);
+ if(!dev->win_base) {
+ err("ioremap(%lu, %u) failed", req.Base, req.Size);
+ pcmciamtd_release((u_long)link);
+ return;
+ }
+ DEBUG(1, "mapped window dev = %p req.base = 0x%lx base = %p size = 0x%x",
+ dev, req.Base, dev->win_base, req.Size);
+ dev->cardsize = 0;
+ dev->offset = 0;
+
+ dev->pcmcia_map.map_priv_1 = (unsigned long)dev;
+ dev->pcmcia_map.map_priv_2 = (unsigned long)link->win;
+
+ DEBUG(2, "Getting configuration");
+ CS_CHECK(GetConfigurationInfo, link->handle, &t);
+ DEBUG(2, "Vcc = %d Vpp1 = %d Vpp2 = %d", t.Vcc, t.Vpp1, t.Vpp2);
+ dev->vpp = (vpp) ? vpp : t.Vpp1;
+ link->conf.Attributes = 0;
+ link->conf.Vcc = t.Vcc;
+ if(setvpp == 2) {
+ link->conf.Vpp1 = dev->vpp;
+ link->conf.Vpp2 = dev->vpp;
+ } else {
+ link->conf.Vpp1 = 0;
+ link->conf.Vpp2 = 0;
+ }
+
+ link->conf.IntType = INT_MEMORY;
+ link->conf.ConfigBase = t.ConfigBase;
+ link->conf.Status = t.Status;
+ link->conf.Pin = t.Pin;
+ link->conf.Copy = t.Copy;
+ link->conf.ExtStatus = t.ExtStatus;
+ link->conf.ConfigIndex = 0;
+ link->conf.Present = t.Present;
+ DEBUG(2, "Setting Configuration");
+ ret = CardServices(RequestConfiguration, link->handle, &link->conf);
+ if(ret != CS_SUCCESS) {
+ cs_error(link->handle, RequestConfiguration, ret);
+ }
+
+ link->dev = NULL;
+ link->state &= ~DEV_CONFIG_PENDING;
+
+ if(mem_type == 1) {
+ mtd = do_map_probe("map_ram", &dev->pcmcia_map);
+ } else if(mem_type == 2) {
+ mtd = do_map_probe("map_rom", &dev->pcmcia_map);
+ } else {
+ for(i = 0; i < sizeof(probes) / sizeof(char *); i++) {
+ DEBUG(1, "Trying %s", probes[i]);
+ mtd = do_map_probe(probes[i], &dev->pcmcia_map);
+ if(mtd)
+ break;
+
+ DEBUG(1, "FAILED: %s", probes[i]);
+ }
+ }
+
+ if(!mtd) {
+ DEBUG(1, "Cant find an MTD");
+ pcmciamtd_release((u_long)link);
+ return;
+ }
+
+ dev->mtd_info = mtd;
+ mtd->module = THIS_MODULE;
+ dev->cardsize = mtd->size;
+
+ if(new_name) {
+ int size = 0;
+ char unit = ' ';
+ /* Since we are using a default name, make it better by adding in the
+ size */
+ if(mtd->size < 1048576) { /* <1MB in size, show size in K */
+ size = mtd->size >> 10;
+ unit = 'K';
+ } else {
+ size = mtd->size >> 20;
+ unit = 'M';
+ }
+ sprintf(mtd->name, "%d%cB %s", size, unit, "PCMCIA Memory card");
+ }
+
+ /* If the memory found is fits completely into the mapped PCMCIA window,
+ use the faster non-remapping read/write functions */
+ if(dev->cardsize <= dev->win_size) {
+ DEBUG(1, "Using non remapping memory functions");
+
+ dev->pcmcia_map.map_priv_2 = (unsigned long)dev->win_base;
+ dev->pcmcia_map.read8 = pcmcia_read8;
+ dev->pcmcia_map.read16 = pcmcia_read16;
+ dev->pcmcia_map.copy_from = pcmcia_copy_from;
+ dev->pcmcia_map.write8 = pcmcia_write8;
+ dev->pcmcia_map.write16 = pcmcia_write16;
+ dev->pcmcia_map.copy_to = pcmcia_copy_to;
+ }
+
+ MOD_INC_USE_COUNT;
+ if(add_mtd_device(mtd)) {
+ dev->mtd_info = NULL;
+ MOD_DEC_USE_COUNT;
+ err("Couldnt register MTD device");
+ pcmciamtd_release((u_long)link);
+ return;
+ }
+ DEBUG(1, "mtd added @ %p mtd->priv = %p", mtd, mtd->priv);
+
+ return;
+
+ cs_failed:
+ cs_error(link->handle, last_fn, last_ret);
+ err("CS Error, exiting");
+ pcmciamtd_release((u_long)link);
+ return;
+}
+
+
+/* The card status event handler. Mostly, this schedules other
+ * stuff to run after an event is received. A CARD_REMOVAL event
+ * also sets some flags to discourage the driver from trying
+ * to talk to the card any more.
+ */
+
+static int pcmciamtd_event(event_t event, int priority,
+ event_callback_args_t *args)
+{
+ dev_link_t *link = args->client_data;
+
+ DEBUG(1, "event=0x%06x", event);
+ switch (event) {
+ case CS_EVENT_CARD_REMOVAL:
+ DEBUG(2, "EVENT_CARD_REMOVAL");
+ link->state &= ~DEV_PRESENT;
+ if (link->state & DEV_CONFIG)
+ mod_timer(&link->release, jiffies + HZ/20);
+ break;
+ case CS_EVENT_CARD_INSERTION:
+ DEBUG(2, "EVENT_CARD_INSERTION");
+ link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+ pcmciamtd_config(link);
+ break;
+ case CS_EVENT_PM_SUSPEND:
+ DEBUG(2, "EVENT_PM_SUSPEND");
+ link->state |= DEV_SUSPEND;
+ /* Fall through... */
+ case CS_EVENT_RESET_PHYSICAL:
+ DEBUG(2, "EVENT_RESET_PHYSICAL");
+ /* get_lock(link); */
+ break;
+ case CS_EVENT_PM_RESUME:
+ DEBUG(2, "EVENT_PM_RESUME");
+ link->state &= ~DEV_SUSPEND;
+ /* Fall through... */
+ case CS_EVENT_CARD_RESET:
+ DEBUG(2, "EVENT_CARD_RESET");
+ /* free_lock(link); */
+ break;
+ default:
+ DEBUG(2, "Unknown event %d", event);
+ }
+ return 0;
+}
+
+
+/* This deletes a driver "instance". The device is de-registered
+ * with Card Services. If it has been released, all local data
+ * structures are freed. Otherwise, the structures will be freed
+ * when the device is released.
+ */
+
+static void pcmciamtd_detach(dev_link_t *link)
+{
+ int ret;
+ struct pcmciamtd_dev *dev = NULL;
+ struct list_head *temp1, *temp2;
+
+ DEBUG(3, "link=0x%p", link);
+
+ /* Find device in list */
+ list_for_each_safe(temp1, temp2, &dev_list) {
+ dev = list_entry(temp1, struct pcmciamtd_dev, list);
+ if(link == &dev->link)
+ break;
+ }
+ if(link != &dev->link) {
+ DEBUG(1, "Cant find %p in dev_list", link);
+ return;
+ }
+
+ del_timer(&link->release);
+
+ if(!dev) {
+ DEBUG(3, "dev is NULL");
+ return;
+ }
+
+ if (link->state & DEV_CONFIG) {
+ //pcmciamtd_release((u_long)link);
+ DEBUG(3, "DEV_CONFIG set");
+ link->state |= DEV_STALE_LINK;
+ return;
+ }
+
+ if (link->handle) {
+ DEBUG(2, "Deregistering with card services");
+ ret = CardServices(DeregisterClient, link->handle);
+ if (ret != CS_SUCCESS)
+ cs_error(link->handle, DeregisterClient, ret);
+ }
+ DEBUG(3, "Freeing dev (%p)", dev);
+ list_del(&dev->list);
+ link->priv = NULL;
+ kfree(dev);
+}
+
+
+/* pcmciamtd_attach() creates an "instance" of the driver, allocating
+ * local data structures for one device. The device is registered
+ * with Card Services.
+ */
+
+static dev_link_t *pcmciamtd_attach(void)
+{
+ struct pcmciamtd_dev *dev;
+ dev_link_t *link;
+ client_reg_t client_reg;
+ int ret;
+
+ /* Create new memory card device */
+ dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev) return NULL;
+ DEBUG(1, "dev=0x%p", dev);
+
+ memset(dev, 0, sizeof(*dev));
+ link = &dev->link; link->priv = dev;
+
+ link->release.function = &pcmciamtd_release;
+ link->release.data = (u_long)link;
+
+ link->conf.Attributes = 0;
+ link->conf.IntType = INT_MEMORY;
+
+ list_add(&dev->list, &dev_list);
+
+ /* Register with Card Services */
+ client_reg.dev_info = &dev_info;
+ client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+ client_reg.EventMask =
+ CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+ CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+ CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+ client_reg.event_handler = &pcmciamtd_event;
+ client_reg.Version = 0x0210;
+ client_reg.event_callback_args.client_data = link;
+ DEBUG(2, "Calling RegisterClient");
+ ret = CardServices(RegisterClient, &link->handle, &client_reg);
+ if (ret != 0) {
+ cs_error(link->handle, RegisterClient, ret);
+ pcmciamtd_detach(link);
+ return NULL;
+ }
+
+ return link;
+}
+
+
+static int __init init_pcmciamtd(void)
+{
+ servinfo_t serv;
+
+ info(DRIVER_DESC " " DRIVER_VERSION);
+ CardServices(GetCardServicesInfo, &serv);
+ if (serv.Revision != CS_RELEASE_CODE) {
+ err("Card Services release does not match!");
+ return -1;
+ }
+
+ if(buswidth && buswidth != 1 && buswidth != 2) {
+ info("bad buswidth (%d), using default", buswidth);
+ buswidth = 2;
+ }
+ if(force_size && (force_size < 1 || force_size > 64)) {
+ info("bad force_size (%d), using default", force_size);
+ force_size = 0;
+ }
+ if(mem_type && mem_type != 1 && mem_type != 2) {
+ info("bad mem_type (%d), using default", mem_type);
+ mem_type = 0;
+ }
+ register_pccard_driver(&dev_info, &pcmciamtd_attach, &pcmciamtd_detach);
+ return 0;
+}
+
+
+static void __exit exit_pcmciamtd(void)
+{
+ struct list_head *temp1, *temp2;
+
+ DEBUG(1, DRIVER_DESC " unloading");
+ unregister_pccard_driver(&dev_info);
+ list_for_each_safe(temp1, temp2, &dev_list) {
+ dev_link_t *link = &list_entry(temp1, struct pcmciamtd_dev, list)->link;
+ if (link && (link->state & DEV_CONFIG)) {
+ pcmciamtd_release((u_long)link);
+ pcmciamtd_detach(link);
+ }
+ }
+}
+
+module_init(init_pcmciamtd);
+module_exit(exit_pcmciamtd);
diff --git a/drivers/mtd/maps/sa1100-flash.c b/drivers/mtd/maps/sa1100-flash.c
index b6c1c0f9efe7..b2592a0a0d63 100644
--- a/drivers/mtd/maps/sa1100-flash.c
+++ b/drivers/mtd/maps/sa1100-flash.c
@@ -3,28 +3,35 @@
*
* (C) 2000 Nicolas Pitre <nico@cam.org>
*
- * $Id: sa1100-flash.c,v 1.22 2001/10/02 10:04:52 rmk Exp $
+ * $Id: sa1100-flash.c,v 1.28 2002/05/07 13:48:38 abz Exp $
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
+#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
#include <linux/mtd/partitions.h>
+#include <linux/mtd/concat.h>
#include <asm/hardware.h>
+#include <asm/mach-types.h>
#include <asm/io.h>
+#include <asm/sizes.h>
+#include <asm/arch/h3600.h>
#ifndef CONFIG_ARCH_SA1100
#error This is for SA1100 architecture only
#endif
-
-#define WINDOW_ADDR 0xe8000000
+/*
+ * This isnt complete yet, so...
+ */
+#define CONFIG_MTD_SA1100_STATICMAP 1
static __u8 sa1100_read8(struct map_info *map, unsigned long ofs)
{
@@ -66,33 +73,7 @@ static void sa1100_copy_to(struct map_info *map, unsigned long to, const void *f
memcpy((void *)(map->map_priv_1 + to), from, len);
}
-
-#ifdef CONFIG_SA1100_H3600
-
-static void h3600_set_vpp(struct map_info *map, int vpp)
-{
- if (vpp)
- set_h3600_egpio(EGPIO_H3600_VPP_ON);
- else
- clr_h3600_egpio(EGPIO_H3600_VPP_ON);
-}
-
-#endif
-
-#ifdef CONFIG_SA1100_JORNADA720
-
-static void jornada720_set_vpp(int vpp)
-{
- if (vpp)
- PPSR |= 0x80;
- else
- PPSR &= ~0x80;
- PPDR |= 0x80;
-}
-
-#endif
-
-static struct map_info sa1100_map = {
+static struct map_info sa1100_map __initdata = {
name: "SA1100 flash",
read8: sa1100_read8,
read16: sa1100_read16,
@@ -102,609 +83,1232 @@ static struct map_info sa1100_map = {
write16: sa1100_write16,
write32: sa1100_write32,
copy_to: sa1100_copy_to,
-
- map_priv_1: WINDOW_ADDR,
};
+#ifdef CONFIG_MTD_SA1100_STATICMAP
/*
* Here are partition information for all known SA1100-based devices.
* See include/linux/mtd/partitions.h for definition of the mtd_partition
* structure.
- *
- * The *_max_flash_size is the maximum possible mapped flash size which
- * is not necessarily the actual flash size. It must correspond to the
- * value specified in the mapping definition defined by the
- * "struct map_desc *_io_desc" for the corresponding machine.
+ *
+ * Please note:
+ * 1. We no longer support static flash mappings via the machine io_desc
+ * structure.
+ * 2. The flash size given should be the largest flash size that can
+ * be accomodated.
+ *
+ * The MTD layer will detect flash chip aliasing and reduce the size of
+ * the map accordingly.
+ *
+ * Please keep these in alphabetical order, and formatted as per existing
+ * entries. Thanks.
*/
-#ifdef CONFIG_SA1100_ASSABET
+#ifdef CONFIG_SA1100_ADSBITSY
+static struct mtd_partition adsbitsy_partitions[] = {
+ {
+ name: "bootROM",
+ size: 0x80000,
+ offset: 0,
+ mask_flags: MTD_WRITEABLE, /* force read-only */
+ }, {
+ name: "zImage",
+ size: 0x100000,
+ offset: MTDPART_OFS_APPEND,
+ mask_flags: MTD_WRITEABLE, /* force read-only */
+ }, {
+ name: "ramdisk.gz",
+ size: 0x300000,
+ offset: MTDPART_OFS_APPEND,
+ mask_flags: MTD_WRITEABLE, /* force read-only */
+ }, {
+ name: "User FS",
+ size: MTDPART_SIZ_FULL,
+ offset: MTDPART_OFS_APPEND,
+ }
+};
+#endif
+#ifdef CONFIG_SA1100_ASSABET
/* Phase 4 Assabet has two 28F160B3 flash parts in bank 0: */
-static unsigned long assabet4_max_flash_size = 0x00400000;
static struct mtd_partition assabet4_partitions[] = {
- {
- name: "bootloader",
- size: 0x00020000,
- offset: 0,
- mask_flags: MTD_WRITEABLE
- },{
- name: "bootloader params",
- size: 0x00020000,
- offset: MTDPART_OFS_APPEND,
- mask_flags: MTD_WRITEABLE
- },{
- name: "jffs",
- size: MTDPART_SIZ_FULL,
- offset: MTDPART_OFS_APPEND
- }
+ {
+ name: "bootloader",
+ size: 0x00020000,
+ offset: 0,
+ mask_flags: MTD_WRITEABLE,
+ }, {
+ name: "bootloader params",
+ size: 0x00020000,
+ offset: MTDPART_OFS_APPEND,
+ mask_flags: MTD_WRITEABLE,
+ }, {
+ name: "jffs",
+ size: MTDPART_SIZ_FULL,
+ offset: MTDPART_OFS_APPEND,
+ }
};
/* Phase 5 Assabet has two 28F128J3A flash parts in bank 0: */
-static unsigned long assabet5_max_flash_size = 0x02000000;
static struct mtd_partition assabet5_partitions[] = {
- {
- name: "bootloader",
- size: 0x00040000,
- offset: 0,
- mask_flags: MTD_WRITEABLE
- },{
- name: "bootloader params",
- size: 0x00040000,
- offset: MTDPART_OFS_APPEND,
- mask_flags: MTD_WRITEABLE
- },{
- name: "jffs",
- size: MTDPART_SIZ_FULL,
- offset: MTDPART_OFS_APPEND
- }
+ {
+ name: "bootloader",
+ size: 0x00040000,
+ offset: 0,
+ mask_flags: MTD_WRITEABLE,
+ }, {
+ name: "bootloader params",
+ size: 0x00040000,
+ offset: MTDPART_OFS_APPEND,
+ mask_flags: MTD_WRITEABLE,
+ }, {
+ name: "jffs",
+ size: MTDPART_SIZ_FULL,
+ offset: MTDPART_OFS_APPEND,
+ }
};
-#define assabet_max_flash_size assabet5_max_flash_size
-#define assabet_partitions assabet5_partitions
-
+#define assabet_partitions assabet5_partitions
#endif
-#ifdef CONFIG_SA1100_FLEXANET
-
-/* Flexanet has two 28F128J3A flash parts in bank 0: */
-static unsigned long flexanet_max_flash_size = 0x02000000;
-static struct mtd_partition flexanet_partitions[] = {
- {
- name: "bootloader",
- size: 0x00040000,
- offset: 0,
- mask_flags: MTD_WRITEABLE
- },{
- name: "bootloader params",
- size: 0x00040000,
- offset: MTDPART_OFS_APPEND,
- mask_flags: MTD_WRITEABLE
- },{
- name: "kernel",
- size: 0x000C0000,
- offset: MTDPART_OFS_APPEND,
- mask_flags: MTD_WRITEABLE
- },{
- name: "altkernel",
- size: 0x000C0000,
- offset: MTDPART_OFS_APPEND,
- mask_flags: MTD_WRITEABLE
- },{
- name: "root",
- size: 0x00400000,
- offset: MTDPART_OFS_APPEND,
- mask_flags: MTD_WRITEABLE
- },{
- name: "free1",
- size: 0x00300000,
- offset: MTDPART_OFS_APPEND,
- mask_flags: MTD_WRITEABLE
- },{
- name: "free2",
- size: 0x00300000,
- offset: MTDPART_OFS_APPEND,
- mask_flags: MTD_WRITEABLE
- },{
- name: "free3",
- size: MTDPART_SIZ_FULL,
- offset: MTDPART_OFS_APPEND,
- mask_flags: MTD_WRITEABLE
- }
+#ifdef CONFIG_SA1100_BADGE4
+/*
+ * 1 x Intel 28F320C3BA100 Advanced+ Boot Block Flash (32 Mi bit)
+ * Eight 4 KiW Parameter Bottom Blocks (64 KiB)
+ * Sixty-three 32 KiW Main Blocks (4032 Ki b)
+ */
+static struct mtd_partition badge4_partitions[] = {
+ {
+ name: "BLOB boot loader",
+ offset: 0,
+ size: 0x0000A000
+ }, {
+ name: "params",
+ offset: MTDPART_OFS_APPEND,
+ size: 0x00006000
+ }, {
+ name: "kernel",
+ offset: MTDPART_OFS_APPEND,
+ size: 0x00100000
+ }, {
+ name: "root",
+ offset: MTDPART_OFS_APPEND,
+ size: MTDPART_SIZ_FULL
+ }
};
-
#endif
-#ifdef CONFIG_SA1100_HUW_WEBPANEL
-static unsigned long huw_webpanel_max_flash_size = 0x01000000;
-static struct mtd_partition huw_webpanel_partitions[] = {
- {
- name: "Loader",
- size: 0x00040000,
- offset: 0,
- },{
- name: "Sector 1",
- size: 0x00040000,
- offset: MTDPART_OFS_APPEND,
- },{
- size: MTDPART_SIZ_FULL,
- offset: MTDPART_OFS_APPEND,
+
+#ifdef CONFIG_SA1100_CERF
+#ifdef CONFIG_SA1100_CERF_FLASH_32MB
+static struct mtd_partition cerf_partitions[] = {
+ {
+ name: "firmware",
+ size: 0x00040000,
+ offset: 0,
+ }, {
+ name: "params",
+ size: 0x00040000,
+ offset: 0x00040000,
+ }, {
+ name: "kernel",
+ size: 0x00100000,
+ offset: 0x00080000,
+ }, {
+ name: "rootdisk",
+ size: 0x01E80000,
+ offset: 0x00180000,
}
};
-#endif /* CONFIG_SA1100_HUW_WEBPANEL */
-
-
-#ifdef CONFIG_SA1100_H3600
-
-static unsigned long h3600_max_flash_size = 0x02000000;
-static struct mtd_partition h3600_partitions[] = {
+#elif defined CONFIG_SA1100_CERF_FLASH_16MB
+static struct mtd_partition cerf_partitions[] = {
{
- name: "H3600 boot firmware",
- size: 0x00040000,
- offset: 0,
- mask_flags: MTD_WRITEABLE /* force read-only */
- },{
- name: "H3600 kernel",
- size: 0x00080000,
- offset: 0x40000
- },{
- name: "H3600 params",
- size: 0x00040000,
- offset: 0xC0000
- },{
-#ifdef CONFIG_JFFS2_FS
- name: "H3600 root jffs2",
- offset: 0x00100000,
- size: MTDPART_SIZ_FULL
+ name: "firmware",
+ size: 0x00020000,
+ offset: 0,
+ }, {
+ name: "params",
+ size: 0x00020000,
+ offset: 0x00020000,
+ }, {
+ name: "kernel",
+ size: 0x00100000,
+ offset: 0x00040000,
+ }, {
+ name: "rootdisk",
+ size: 0x00EC0000,
+ offset: 0x00140000,
+ }
+};
+#elif defined CONFIG_SA1100_CERF_FLASH_8MB
+# error "Unwritten type definition"
#else
- name: "H3600 initrd",
- size: 0x00100000,
- offset: 0x00100000
- },{
- name: "H3600 root cramfs",
- size: 0x00300000,
- offset: 0x00200000
- },{
- name: "H3600 usr cramfs",
- size: 0x00800000,
- offset: 0x00500000
- },{
- name: "H3600 usr local",
- offset: 0x00d00000,
- size: MTDPART_SIZ_FULL
+# error "Undefined memory orientation for CERF in sa1100-flash.c"
+#endif
#endif
+
+#ifdef CONFIG_SA1100_CONSUS
+static struct mtd_partition consus_partitions[] = {
+ {
+ name: "Consus boot firmware",
+ offset: 0,
+ size: 0x00040000,
+ mask_flags: MTD_WRITABLE, /* force read-only */
+ }, {
+ name: "Consus kernel",
+ offset: 0x00040000,
+ size: 0x00100000,
+ mask_flags: 0,
+ }, {
+ name: "Consus disk",
+ offset: 0x00140000,
+ /* The rest (up to 16M) for jffs. We could put 0 and
+ make it find the size automatically, but right now
+ i have 32 megs. jffs will use all 32 megs if given
+ the chance, and this leads to horrible problems
+ when you try to re-flash the image because blob
+ won't erase the whole partition. */
+ size: 0x01000000 - 0x00140000,
+ mask_flags: 0,
+ }, {
+ /* this disk is a secondary disk, which can be used as
+ needed, for simplicity, make it the size of the other
+ consus partition, although realistically it could be
+ the remainder of the disk (depending on the file
+ system used) */
+ name: "Consus disk2",
+ offset: 0x01000000,
+ size: 0x01000000 - 0x00140000,
+ mask_flags: 0,
}
};
+#endif
+#ifdef CONFIG_SA1100_FLEXANET
+/* Flexanet has two 28F128J3A flash parts in bank 0: */
+#define FLEXANET_FLASH_SIZE 0x02000000
+static struct mtd_partition flexanet_partitions[] = {
+ {
+ name: "bootloader",
+ size: 0x00040000,
+ offset: 0,
+ mask_flags: MTD_WRITEABLE,
+ }, {
+ name: "bootloader params",
+ size: 0x00040000,
+ offset: MTDPART_OFS_APPEND,
+ mask_flags: MTD_WRITEABLE,
+ }, {
+ name: "kernel",
+ size: 0x000C0000,
+ offset: MTDPART_OFS_APPEND,
+ mask_flags: MTD_WRITEABLE,
+ }, {
+ name: "altkernel",
+ size: 0x000C0000,
+ offset: MTDPART_OFS_APPEND,
+ mask_flags: MTD_WRITEABLE,
+ }, {
+ name: "root",
+ size: 0x00400000,
+ offset: MTDPART_OFS_APPEND,
+ mask_flags: MTD_WRITEABLE,
+ }, {
+ name: "free1",
+ size: 0x00300000,
+ offset: MTDPART_OFS_APPEND,
+ mask_flags: MTD_WRITEABLE,
+ }, {
+ name: "free2",
+ size: 0x00300000,
+ offset: MTDPART_OFS_APPEND,
+ mask_flags: MTD_WRITEABLE,
+ }, {
+ name: "free3",
+ size: MTDPART_SIZ_FULL,
+ offset: MTDPART_OFS_APPEND,
+ mask_flags: MTD_WRITEABLE,
+ }
+};
#endif
+
#ifdef CONFIG_SA1100_FREEBIRD
-static unsigned long freebird_max_flash_size = 0x02000000;
static struct mtd_partition freebird_partitions[] = {
#if CONFIG_SA1100_FREEBIRD_NEW
- {
- name: "firmware",
- size: 0x00040000,
- offset: 0,
- mask_flags: MTD_WRITEABLE /* force read-only */
- },{
- name: "kernel",
- size: 0x00080000,
- offset: 0x40000
- },{
- name: "params",
- size: 0x00040000,
- offset: 0xC0000
- },{
- name: "initrd",
- size: 0x00100000,
- offset: 0x00100000
- },{
- name: "root cramfs",
- size: 0x00300000,
- offset: 0x00200000
- },{
- name: "usr cramfs",
- size: 0x00C00000,
- offset: 0x00500000
- },{
- name: "local",
- offset: 0x01100000,
- size: MTDPART_SIZ_FULL
+ {
+ name: "firmware",
+ size: 0x00040000,
+ offset: 0,
+ mask_flags: MTD_WRITEABLE, /* force read-only */
+ }, {
+ name: "kernel",
+ size: 0x00080000,
+ offset: 0x00040000,
+ }, {
+ name: "params",
+ size: 0x00040000,
+ offset: 0x000C0000,
+ }, {
+ name: "initrd",
+ size: 0x00100000,
+ offset: 0x00100000,
+ }, {
+ name: "root cramfs",
+ size: 0x00300000,
+ offset: 0x00200000,
+ }, {
+ name: "usr cramfs",
+ size: 0x00C00000,
+ offset: 0x00500000,
+ }, {
+ name: "local",
+ size: MTDPART_SIZ_FULL,
+ offset: 0x01100000,
}
#else
- { offset: 0, size: 0x00040000, },
- { offset: MTDPART_OFS_APPEND, size: 0x000c0000, },
- { offset: MTDPART_OFS_APPEND, size: 0x00400000, },
- { offset: MTDPART_OFS_APPEND, size: MTDPART_SIZ_FULL }
+ {
+ size: 0x00040000,
+ offset: 0,
+ }, {
+ size: 0x000c0000,
+ offset: MTDPART_OFS_APPEND,
+ }, {
+ size: 0x00400000,
+ offset: MTDPART_OFS_APPEND,
+ }, {
+ size: MTDPART_SIZ_FULL,
+ offset: MTDPART_OFS_APPEND,
+ }
#endif
- };
+};
#endif
-
-
-#ifdef CONFIG_SA1100_CERF
-static unsigned long cerf_max_flash_size = 0x01000000;
-static struct mtd_partition cerf_partitions[] = {
- { offset: 0, size: 0x00800000 },
- { offset: MTDPART_OFS_APPEND, size: 0x00800000 }
+#ifdef CONFIG_SA1100_FRODO
+/* Frodo has 2 x 16M 28F128J3A flash chips in bank 0: */
+static struct mtd_partition frodo_partitions[] =
+{
+ {
+ name: "bootloader",
+ size: 0x00040000,
+ offset: 0x00000000,
+ mask_flags: MTD_WRITEABLE
+ }, {
+ name: "bootloader params",
+ size: 0x00040000,
+ offset: MTDPART_OFS_APPEND,
+ mask_flags: MTD_WRITEABLE
+ }, {
+ name: "kernel",
+ size: 0x00100000,
+ offset: MTDPART_OFS_APPEND,
+ mask_flags: MTD_WRITEABLE
+ }, {
+ name: "ramdisk",
+ size: 0x00400000,
+ offset: MTDPART_OFS_APPEND,
+ mask_flags: MTD_WRITEABLE
+ }, {
+ name: "file system",
+ size: MTDPART_SIZ_FULL,
+ offset: MTDPART_OFS_APPEND
+ }
};
-
#endif
#ifdef CONFIG_SA1100_GRAPHICSCLIENT
-
-static unsigned long graphicsclient_max_flash_size = 0x01000000;
static struct mtd_partition graphicsclient_partitions[] = {
- {
- name: "zImage",
- offset: 0,
- size: 0x100000
- },
- {
- name: "ramdisk.gz",
- offset: MTDPART_OFS_APPEND,
- size: 0x300000
- },
- {
- name: "User FS",
- offset: MTDPART_OFS_APPEND,
- size: MTDPART_SIZ_FULL
+ {
+ name: "zImage",
+ size: 0x100000,
+ offset: 0,
+ mask_flags: MTD_WRITEABLE, /* force read-only */
+ }, {
+ name: "ramdisk.gz",
+ size: 0x300000,
+ offset: MTDPART_OFS_APPEND,
+ mask_flags: MTD_WRITEABLE, /* force read-only */
+ }, {
+ name: "User FS",
+ size: MTDPART_SIZ_FULL,
+ offset: MTDPART_OFS_APPEND,
}
};
-
#endif
#ifdef CONFIG_SA1100_GRAPHICSMASTER
-
-static unsigned long graphicsmaster_max_flash_size = 0x01000000;
static struct mtd_partition graphicsmaster_partitions[] = {
- {
- name: "zImage",
- offset: 0,
- size: 0x100000
+ {
+ name: "zImage",
+ size: 0x100000,
+ offset: 0,
+ mask_flags: MTD_WRITEABLE, /* force read-only */
},
- {
- name: "ramdisk.gz",
- offset: MTDPART_OFS_APPEND,
- size: 0x300000
+ {
+ name: "ramdisk.gz",
+ size: 0x300000,
+ offset: MTDPART_OFS_APPEND,
+ mask_flags: MTD_WRITEABLE, /* force read-only */
},
- {
- name: "User FS",
- offset: MTDPART_OFS_APPEND,
- size: MTDPART_SIZ_FULL
+ {
+ name: "User FS",
+ size: MTDPART_SIZ_FULL,
+ offset: MTDPART_OFS_APPEND,
}
};
+#endif
+#ifdef CONFIG_SA1100_H3XXX
+static struct mtd_partition h3xxx_partitions[] = {
+ {
+ name: "H3XXX boot firmware",
+ size: 0x00040000,
+ offset: 0,
+ mask_flags: MTD_WRITEABLE, /* force read-only */
+ }, {
+#ifdef CONFIG_MTD_2PARTS_IPAQ
+ name: "H3XXX root jffs2",
+ size: MTDPART_SIZ_FULL,
+ offset: 0x00040000,
+#else
+ name: "H3XXX kernel",
+ size: 0x00080000,
+ offset: 0x00040000,
+ }, {
+ name: "H3XXX params",
+ size: 0x00040000,
+ offset: 0x000C0000,
+ }, {
+#ifdef CONFIG_JFFS2_FS
+ name: "H3XXX root jffs2",
+ size: MTDPART_SIZ_FULL,
+ offset: 0x00100000,
+#else
+ name: "H3XXX initrd",
+ size: 0x00100000,
+ offset: 0x00100000,
+ }, {
+ name: "H3XXX root cramfs",
+ size: 0x00300000,
+ offset: 0x00200000,
+ }, {
+ name: "H3XXX usr cramfs",
+ size: 0x00800000,
+ offset: 0x00500000,
+ }, {
+ name: "H3XXX usr local",
+ size: MTDPART_SIZ_FULL,
+ offset: 0x00d00000,
+#endif
#endif
+ }
+};
-#ifdef CONFIG_SA1100_PANGOLIN
+static void h3xxx_set_vpp(struct map_info *map, int vpp)
+{
+ assign_h3600_egpio(IPAQ_EGPIO_VPP_ON, vpp);
+}
+#else
+#define h3xxx_set_vpp NULL
+#endif
-static unsigned long pangolin_max_flash_size = 0x04000000;
-static struct mtd_partition pangolin_partitions[] = {
- {
- name: "boot firmware",
- offset: 0x00000000,
- size: 0x00080000,
- mask_flags: MTD_WRITEABLE, /* force read-only */
- },
- {
- name: "kernel",
- offset: 0x00080000,
- size: 0x00100000,
- },
+#ifdef CONFIG_SA1100_HUW_WEBPANEL
+static struct mtd_partition huw_webpanel_partitions[] = {
{
- name: "initrd",
- offset: 0x00180000,
- size: 0x00280000,
- },
+ name: "Loader",
+ size: 0x00040000,
+ offset: 0,
+ }, {
+ name: "Sector 1",
+ size: 0x00040000,
+ offset: MTDPART_OFS_APPEND,
+ }, {
+ size: MTDPART_SIZ_FULL,
+ offset: MTDPART_OFS_APPEND,
+ }
+};
+#endif
+
+#ifdef CONFIG_SA1100_JORNADA720
+static struct mtd_partition jornada720_partitions[] = {
{
- name: "initrd-test",
- offset: 0x00400000,
- size: 0x03C00000,
+ name: "JORNADA720 boot firmware",
+ size: 0x00040000,
+ offset: 0,
+ mask_flags: MTD_WRITEABLE, /* force read-only */
+ }, {
+ name: "JORNADA720 kernel",
+ size: 0x000c0000,
+ offset: 0x00040000,
+ }, {
+ name: "JORNADA720 params",
+ size: 0x00040000,
+ offset: 0x00100000,
+ }, {
+ name: "JORNADA720 initrd",
+ size: 0x00100000,
+ offset: 0x00140000,
+ }, {
+ name: "JORNADA720 root cramfs",
+ size: 0x00300000,
+ offset: 0x00240000,
+ }, {
+ name: "JORNADA720 usr cramfs",
+ size: 0x00800000,
+ offset: 0x00540000,
+ }, {
+ name: "JORNADA720 usr local",
+ size: 0 /* will expand to the end of the flash */
+ offset: 0x00d00000,
}
};
+static void jornada720_set_vpp(int vpp)
+{
+ if (vpp)
+ PPSR |= 0x80;
+ else
+ PPSR &= ~0x80;
+ PPDR |= 0x80;
+}
+#else
+#define jornada720_set_vpp NULL
#endif
-#ifdef CONFIG_SA1100_YOPY
+#ifdef CONFIG_SA1100_PANGOLIN
+static struct mtd_partition pangolin_partitions[] = {
+ {
+ name: "boot firmware",
+ size: 0x00080000,
+ offset: 0x00000000,
+ mask_flags: MTD_WRITEABLE, /* force read-only */
+ }, {
+ name: "kernel",
+ size: 0x00100000,
+ offset: 0x00080000,
+ }, {
+ name: "initrd",
+ size: 0x00280000,
+ offset: 0x00180000,
+ }, {
+ name: "initrd-test",
+ size: 0x03C00000,
+ offset: 0x00400000,
+ }
+};
+#endif
-static unsigned long yopy_max_flash_size = 0x08000000;
-static struct mtd_partition yopy_partitions[] = {
+#ifdef CONFIG_SA1100_PT_SYSTEM3
+/* erase size is 0x40000 == 256k partitions have to have this boundary */
+static struct mtd_partition system3_partitions[] = {
{
- name: "boot firmware",
- offset: 0x00000000,
- size: 0x00040000,
- mask_flags: MTD_WRITEABLE, /* force read-only */
+ name: "BLOB",
+ size: 0x00040000,
+ offset: 0x00000000,
+ mask_flags: MTD_WRITEABLE, /* force read-only */
+ }, {
+ name: "config",
+ size: 0x00040000,
+ offset: MTDPART_OFS_APPEND,
+ }, {
+ name: "kernel",
+ size: 0x00100000,
+ offset: MTDPART_OFS_APPEND,
+ }, {
+ name: "root",
+ size: MTDPART_SIZ_FULL,
+ offset: MTDPART_OFS_APPEND,
+ }
+};
+#endif
+
+#ifdef CONFIG_SA1100_SHANNON
+static struct mtd_partition shannon_partitions[] = {
+ {
+ name: "BLOB boot loader",
+ offset: 0,
+ size: 0x20000
},
{
name: "kernel",
- offset: 0x00080000,
- size: 0x00080000,
+ offset: MTDPART_OFS_APPEND,
+ size: 0xe0000
},
- {
+ {
name: "initrd",
- offset: 0x00100000,
- size: 0x00300000,
- },
- {
- name: "root",
- offset: 0x00400000,
- size: 0x01000000,
- },
+ offset: MTDPART_OFS_APPEND,
+ size: MTDPART_SIZ_FULL
+ }
};
#endif
-#ifdef CONFIG_SA1100_JORNADA720
-
-static unsigned long jornada720_max_flash_size = 0x02000000;
-static struct mtd_partition jornada720_partitions[] = {
+#ifdef CONFIG_SA1100_SHERMAN
+static struct mtd_partition sherman_partitions[] = {
{
- name: "JORNADA720 boot firmware",
- size: 0x00040000,
- offset: 0,
- mask_flags: MTD_WRITEABLE /* force read-only */
- },{
- name: "JORNADA720 kernel",
- size: 0x000c0000,
- offset: 0x40000
- },{
- name: "JORNADA720 params",
- size: 0x00040000,
- offset: 0x100000
- },{
- name: "JORNADA720 initrd",
- size: 0x00100000,
- offset: 0x00140000
- },{
- name: "JORNADA720 root cramfs",
- size: 0x00300000,
- offset: 0x00240000
- },{
- name: "JORNADA720 usr cramfs",
- size: 0x00800000,
- offset: 0x00540000
- },{
- name: "JORNADA720 usr local",
- offset: 0x00d00000,
- size: 0 /* will expand to the end of the flash */
+ size: 0x50000,
+ offset: 0,
+ }, {
+ size: 0x70000,
+ offset: MTDPART_OFS_APPEND,
+ }, {
+ size: 0x600000,
+ offset: MTDPART_OFS_APPEND,
+ }, {
+ size: 0xA0000,
+ offset: MTDPART_OFS_APPEND,
}
};
#endif
-#ifdef CONFIG_SA1100_SHERMAN
-
-static unsigned long sherman_max_flash_size = 0x02000000;
-static struct mtd_partition sherman_partitions[] = {
- { offset: 0, size: 0x50000 },
- { offset: MTDPART_OFS_APPEND, size: 0x70000 },
- { offset: MTDPART_OFS_APPEND, size: 0x600000 },
- { offset: MTDPART_OFS_APPEND, size: 0xA0000 }
-};
-
+#ifdef CONFIG_SA1100_SIMPAD
+static struct mtd_partition simpad_partitions[] = {
+ {
+ name: "SIMpad boot firmware",
+ size: 0x00080000,
+ offset: 0,
+ mask_flags: MTD_WRITEABLE, /* force read-only */
+ }, {
+ name: "SIMpad kernel",
+ size: 0x00100000,
+ offset: 0x00080000,
+ }, {
+#ifdef CONFIG_JFFS2_FS
+ name: "SIMpad root jffs2",
+ size: MTDPART_SIZ_FULL,
+ offset: 0x00180000,
+#else
+ name: "SIMpad initrd",
+ size: 0x00300000,
+ offset: 0x00180000,
+ }, {
+ name: "SIMpad root cramfs",
+ size: 0x00300000,
+ offset: 0x00480000,
+ }, {
+ name: "SIMpad usr cramfs",
+ size: 0x005c0000,
+ offset: 0x00780000,
+ }, {
+ name: "SIMpad usr local",
+ size: MTDPART_SIZ_FULL,
+ offset: 0x00d40000,
#endif
+ }
+};
+#endif /* CONFIG_SA1100_SIMPAD */
#ifdef CONFIG_SA1100_STORK
-
-static unsigned long stork_max_flash_size = 0x02000000;
static struct mtd_partition stork_partitions[] = {
{
- name: "STORK boot firmware",
- size: 0x00040000,
- offset: 0,
- mask_flags: MTD_WRITEABLE /* force read-only */
- },{
- name: "STORK params",
- size: 0x00040000,
- offset: 0x40000
- },{
- name: "STORK kernel",
- size: 0x00100000,
- offset: 0x80000
- },{
+ name: "STORK boot firmware",
+ size: 0x00040000,
+ offset: 0,
+ mask_flags: MTD_WRITEABLE, /* force read-only */
+ }, {
+ name: "STORK params",
+ size: 0x00040000,
+ offset: 0x00040000,
+ }, {
+ name: "STORK kernel",
+ size: 0x00100000,
+ offset: 0x00080000,
+ }, {
#ifdef CONFIG_JFFS2_FS
- name: "STORK root jffs2",
- offset: 0x00180000,
- size: MTDPART_SIZ_FULL
+ name: "STORK root jffs2",
+ offset: 0x00180000,
+ size: MTDPART_SIZ_FULL,
#else
- name: "STORK initrd",
- size: 0x00100000,
- offset: 0x00180000
- },{
- name: "STORK root cramfs",
- size: 0x00300000,
- offset: 0x00280000
- },{
- name: "STORK usr cramfs",
- size: 0x00800000,
- offset: 0x00580000
- },{
- name: "STORK usr local",
- offset: 0x00d80000,
- size: MTDPART_SIZ_FULL
+ name: "STORK initrd",
+ size: 0x00100000,
+ offset: 0x00180000,
+ }, {
+ name: "STORK root cramfs",
+ size: 0x00300000,
+ offset: 0x00280000,
+ }, {
+ name: "STORK usr cramfs",
+ size: 0x00800000,
+ offset: 0x00580000,
+ }, {
+ name: "STORK usr local",
+ offset: 0x00d80000,
+ size: MTDPART_SIZ_FULL,
#endif
}
};
-
#endif
-#define NB_OF(x) (sizeof(x)/sizeof(x[0]))
-
-
-extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts);
-extern int parse_bootldr_partitions(struct mtd_info *master, struct mtd_partition **pparts);
+#ifdef CONFIG_SA1100_TRIZEPS
+static struct mtd_partition trizeps_partitions[] = {
+ {
+ name: "Bootloader & the kernel",
+ size: 0x00200000,
+ offset: 0,
+ }, {
+ name: "Data",
+ size: 0x00400000,
+ offset: MTDPART_OFS_APPEND,
+ }, {
+ size: MTDPART_SIZ_FULL,
+ offset: MTDPART_OFS_APPEND,
+ }
+};
+#endif
-static struct mtd_partition *parsed_parts;
-static struct mtd_info *mymtd;
+#ifdef CONFIG_SA1100_YOPY
+static struct mtd_partition yopy_partitions[] = {
+ {
+ name: "boot firmware",
+ size: 0x00040000,
+ offset: 0x00000000,
+ mask_flags: MTD_WRITEABLE, /* force read-only */
+ }, {
+ name: "kernel",
+ size: 0x00080000,
+ offset: 0x00080000,
+ }, {
+ name: "initrd",
+ size: 0x00300000,
+ offset: 0x00100000,
+ }, {
+ name: "root",
+ size: 0x01000000,
+ offset: 0x00400000,
+ }
+};
+#endif
-int __init sa1100_mtd_init(void)
+static int __init sa1100_static_partitions(struct mtd_partition **parts)
{
- struct mtd_partition *parts;
int nb_parts = 0;
- int parsed_nr_parts = 0;
- char *part_type;
-
- /* Default flash buswidth */
- sa1100_map.buswidth = (MSC0 & MSC_RBW) ? 2 : 4;
- /*
- * Static partition definition selection
- */
- part_type = "static";
+#ifdef CONFIG_SA1100_ADSBITSY
+ if (machine_is_adsbitsy()) {
+ *parts = adsbitsy_partitions;
+ nb_parts = ARRAY_SIZE(adsbitsy_partitions);
+ }
+#endif
#ifdef CONFIG_SA1100_ASSABET
if (machine_is_assabet()) {
- parts = assabet_partitions;
- nb_parts = NB_OF(assabet_partitions);
- sa1100_map.size = assabet_max_flash_size;
+ *parts = assabet_partitions;
+ nb_parts = ARRAY_SIZE(assabet_partitions);
}
#endif
-
-#ifdef CONFIG_SA1100_HUW_WEBPANEL
- if (machine_is_huw_webpanel()) {
- parts = huw_webpanel_partitions;
- nb_parts = NB_OF(huw_webpanel_partitions);
- sa1100_map.size = huw_webpanel_max_flash_size;
+#ifdef CONFIG_SA1100_BADGE4
+ if (machine_is_badge4()) {
+ *parts = badge4_partitions;
+ nb_parts = ARRAY_SIZE(badge4_partitions);
}
#endif
-
-#ifdef CONFIG_SA1100_H3600
- if (machine_is_h3600()) {
- parts = h3600_partitions;
- nb_parts = NB_OF(h3600_partitions);
- sa1100_map.size = h3600_max_flash_size;
- sa1100_map.set_vpp = h3600_set_vpp;
+#ifdef CONFIG_SA1100_CERF
+ if (machine_is_cerf()) {
+ *parts = cerf_partitions;
+ nb_parts = ARRAY_SIZE(cerf_partitions);
+ }
+#endif
+#ifdef CONFIG_SA1100_CONSUS
+ if (machine_is_consus()) {
+ *parts = consus_partitions;
+ nb_parts = ARRAY_SIZE(consus_partitions);
+ }
+#endif
+#ifdef CONFIG_SA1100_FLEXANET
+ if (machine_is_flexanet()) {
+ *parts = flexanet_partitions;
+ nb_parts = ARRAY_SIZE(flexanet_partitions);
}
#endif
#ifdef CONFIG_SA1100_FREEBIRD
if (machine_is_freebird()) {
- parts = freebird_partitions;
- nb_parts = NB_OF(freebird_partitions);
- sa1100_map.size = freebird_max_flash_size;
+ *parts = freebird_partitions;
+ nb_parts = ARRAY_SIZE(freebird_partitions);
}
#endif
-#ifdef CONFIG_SA1100_CERF
- if (machine_is_cerf()) {
- parts = cerf_partitions;
- nb_parts = NB_OF(cerf_partitions);
- sa1100_map.size = cerf_max_flash_size;
+#ifdef CONFIG_SA1100_FRODO
+ if (machine_is_frodo()) {
+ *parts = frodo_partitions;
+ nb_parts = ARRAY_SIZE(frodo_partitions);
}
-#endif
+#endif
#ifdef CONFIG_SA1100_GRAPHICSCLIENT
if (machine_is_graphicsclient()) {
- parts = graphicsclient_partitions;
- nb_parts = NB_OF(graphicsclient_partitions);
- sa1100_map.size = graphicsclient_max_flash_size;
- sa1100_map.buswidth = (MSC1 & MSC_RBW) ? 2:4;
+ *parts = graphicsclient_partitions;
+ nb_parts = ARRAY_SIZE(graphicsclient_partitions);
}
#endif
#ifdef CONFIG_SA1100_GRAPHICSMASTER
if (machine_is_graphicsmaster()) {
- parts = graphicsmaster_partitions;
- nb_parts = NB_OF(graphicsmaster_partitions);
- sa1100_map.size = graphicsmaster_max_flash_size;
- sa1100_map.buswidth = (MSC1 & MSC_RBW) ? 2:4;
+ *parts = graphicsmaster_partitions;
+ nb_parts = ARRAY_SIZE(graphicsmaster_partitions);
}
#endif
-#ifdef CONFIG_SA1100_PANGOLIN
- if (machine_is_pangolin()) {
- parts = pangolin_partitions;
- nb_parts = NB_OF(pangolin_partitions);
- sa1100_map.size = pangolin_max_flash_size;
+#ifdef CONFIG_SA1100_H3XXX
+ if (machine_is_h3xxx()) {
+ *parts = h3xxx_partitions;
+ nb_parts = ARRAY_SIZE(h3xxx_partitions);
+ }
+#endif
+#ifdef CONFIG_SA1100_HUW_WEBPANEL
+ if (machine_is_huw_webpanel()) {
+ *parts = huw_webpanel_partitions;
+ nb_parts = ARRAY_SIZE(huw_webpanel_partitions);
}
#endif
#ifdef CONFIG_SA1100_JORNADA720
if (machine_is_jornada720()) {
- parts = jornada720_partitions;
- nb_parts = NB_OF(jornada720_partitions);
- sa1100_map.size = jornada720_max_flash_size;
- sa1100_map.set_vpp = jornada720_set_vpp;
+ *parts = jornada720_partitions;
+ nb_parts = ARRAY_SIZE(jornada720_partitions);
}
#endif
-#ifdef CONFIG_SA1100_YOPY
- if (machine_is_yopy()) {
- parts = yopy_partitions;
- nb_parts = NB_OF(yopy_partitions);
- sa1100_map.size = yopy_max_flash_size;
+#ifdef CONFIG_SA1100_PANGOLIN
+ if (machine_is_pangolin()) {
+ *parts = pangolin_partitions;
+ nb_parts = ARRAY_SIZE(pangolin_partitions);
+ }
+#endif
+#ifdef CONFIG_SA1100_PT_SYSTEM3
+ if (machine_is_pt_system3()) {
+ *parts = system3_partitions;
+ nb_parts = ARRAY_SIZE(system3_partitions);
+ }
+#endif
+#ifdef CONFIG_SA1100_SHANNON
+ if (machine_is_shannon()) {
+ *parts = shannon_partitions;
+ nb_parts = ARRAY_SIZE(shannon_partitions);
}
#endif
#ifdef CONFIG_SA1100_SHERMAN
if (machine_is_sherman()) {
- parts = sherman_partitions;
- nb_parts = NB_OF(sherman_partitions);
- sa1100_map.size = sherman_max_flash_size;
+ *parts = sherman_partitions;
+ nb_parts = ARRAY_SIZE(sherman_partitions);
}
#endif
-#ifdef CONFIG_SA1100_FLEXANET
- if (machine_is_flexanet()) {
- parts = flexanet_partitions;
- nb_parts = NB_OF(flexanet_partitions);
- sa1100_map.size = flexanet_max_flash_size;
+#ifdef CONFIG_SA1100_SIMPAD
+ if (machine_is_simpad()) {
+ *parts = simpad_partitions;
+ nb_parts = ARRAY_SIZE(simpad_partitions);
}
#endif
#ifdef CONFIG_SA1100_STORK
if (machine_is_stork()) {
- parts = stork_partitions;
- nb_parts = NB_OF(stork_partitions);
- sa1100_map.size = stork_max_flash_size;
+ *parts = stork_partitions;
+ nb_parts = ARRAY_SIZE(stork_partitions);
+ }
+#endif
+#ifdef CONFIG_SA1100_TRIZEPS
+ if (machine_is_trizeps()) {
+ *parts = trizeps_partitions;
+ nb_parts = ARRAY_SIZE(trizeps_parititons);
+ }
+#endif
+#ifdef CONFIG_SA1100_YOPY
+ if (machine_is_yopy()) {
+ *parts = yopy_partitions;
+ nb_parts = ARRAY_SIZE(yopy_partitions);
}
#endif
+ return nb_parts;
+}
+#endif
+
+struct sa_info {
+ unsigned long base;
+ unsigned long size;
+ int width;
+ void *vbase;
+ struct map_info *map;
+ struct mtd_info *mtd;
+ struct resource *res;
+};
+
+#define NR_SUBMTD 4
+
+static struct sa_info info[NR_SUBMTD];
+
+static int __init sa1100_setup_mtd(struct sa_info *sa, int nr, struct mtd_info **rmtd)
+{
+ struct mtd_info *subdev[nr];
+ struct map_info *maps;
+ int i, found = 0, ret = 0;
+
/*
- * Now let's probe for the actual flash. Do it here since
- * specific machine settings might have been set above.
+ * Allocate the map_info structs in one go.
*/
- printk(KERN_NOTICE "SA1100 flash: probing %d-bit flash bus\n", sa1100_map.buswidth*8);
- mymtd = do_map_probe("cfi_probe", &sa1100_map);
- if (!mymtd)
- return -ENXIO;
- mymtd->module = THIS_MODULE;
+ maps = kmalloc(sizeof(struct map_info) * nr, GFP_KERNEL);
+ if (!maps)
+ return -ENOMEM;
/*
- * Dynamic partition selection stuff (might override the static ones)
+ * Claim and then map the memory regions.
*/
-#ifdef CONFIG_MTD_REDBOOT_PARTS
- if (parsed_nr_parts == 0) {
- int ret = parse_redboot_partitions(mymtd, &parsed_parts);
-
- if (ret > 0) {
- part_type = "RedBoot";
- parsed_nr_parts = ret;
+ for (i = 0; i < nr; i++) {
+ if (sa[i].base == (unsigned long)-1)
+ break;
+
+ sa[i].res = request_mem_region(sa[i].base, sa[i].size, "sa1100 flash");
+ if (!sa[i].res) {
+ ret = -EBUSY;
+ break;
+ }
+
+ sa[i].map = maps + i;
+ memcpy(sa[i].map, &sa1100_map, sizeof(struct map_info));
+
+ sa[i].vbase = ioremap(sa[i].base, sa[i].size);
+ if (!sa[i].vbase) {
+ ret = -ENOMEM;
+ break;
}
+
+ sa[i].map->map_priv_1 = (unsigned long)sa[i].vbase;
+ sa[i].map->buswidth = sa[i].width;
+ sa[i].map->size = sa[i].size;
+
+ /*
+ * Now let's probe for the actual flash. Do it here since
+ * specific machine settings might have been set above.
+ */
+ sa[i].mtd = do_map_probe("cfi_probe", sa[i].map);
+ if (sa[i].mtd == NULL) {
+ ret = -ENXIO;
+ break;
+ }
+ sa[i].mtd->module = THIS_MODULE;
+ subdev[i] = sa[i].mtd;
+
+ printk(KERN_INFO "SA1100 flash: CFI device at 0x%08lx, %dMiB, "
+ "%d-bit\n", sa[i].base, sa[i].mtd->size >> 20,
+ sa[i].width * 8);
+ found += 1;
}
+
+ /*
+ * ENXIO is special. It means we didn't find a chip when
+ * we probed. We need to tear down the mapping, free the
+ * resource and mark it as such.
+ */
+ if (ret == -ENXIO) {
+ iounmap(sa[i].vbase);
+ sa[i].vbase = NULL;
+ release_resource(sa[i].res);
+ sa[i].res = NULL;
+ }
+
+ /*
+ * If we found one device, don't bother with concat support.
+ * If we found multiple devices, use concat if we have it
+ * available, otherwise fail.
+ */
+ if (ret == 0 || ret == -ENXIO) {
+ if (found == 1) {
+ *rmtd = subdev[0];
+ ret = 0;
+ } else if (found > 1) {
+ /*
+ * We detected multiple devices. Concatenate
+ * them together.
+ */
+#ifdef CONFIG_MTD_CONCAT
+ *rmtd = mtd_concat_create(subdev, found,
+ "sa1100 flash");
+ if (*rmtd == NULL)
+ ret = -ENXIO;
+#else
+ printk(KERN_ERR "SA1100 flash: multiple devices "
+ "found but MTD concat support disabled.\n");
+ ret = -ENXIO;
#endif
-#ifdef CONFIG_MTD_BOOTLDR_PARTS
- if (parsed_nr_parts == 0) {
- int ret = parse_bootldr_partitions(mymtd, &parsed_parts);
- if (ret > 0) {
- part_type = "Compaq bootldr";
- parsed_nr_parts = ret;
}
}
-#endif
- if (parsed_nr_parts > 0) {
- parts = parsed_parts;
- nb_parts = parsed_nr_parts;
+ /*
+ * If we failed, clean up.
+ */
+ if (ret) {
+ do {
+ if (sa[i].mtd)
+ map_destroy(sa[i].mtd);
+ if (sa[i].vbase)
+ iounmap(sa[i].vbase);
+ if (sa[i].res)
+ release_resource(sa[i].res);
+ } while (i--);
+
+ kfree(maps);
}
- if (nb_parts == 0) {
- printk(KERN_NOTICE "SA1100 flash: no partition info available, registering whole flash at once\n");
- add_mtd_device(mymtd);
+ return ret;
+}
+
+static void __exit sa1100_destroy_mtd(struct sa_info *sa, struct mtd_info *mtd)
+{
+ int i;
+
+ del_mtd_partitions(mtd);
+
+ if (mtd != sa[0].mtd)
+ mtd_concat_destroy(mtd);
+
+ for (i = NR_SUBMTD; i >= 0; i--) {
+ if (sa[i].mtd)
+ map_destroy(sa[i].mtd);
+ if (sa[i].vbase)
+ iounmap(sa[i].vbase);
+ if (sa[i].res)
+ release_resource(sa[i].res);
+ }
+ kfree(sa[0].map);
+}
+
+static int __init sa1100_locate_flash(void)
+{
+ int i, nr = -ENODEV;
+
+ if (machine_is_adsbitsy()) {
+ info[0].base = SA1100_CS1_PHYS;
+ info[0].size = SZ_32M;
+ nr = 1;
+ }
+ if (machine_is_assabet()) {
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_32M;
+ info[1].base = SA1100_CS1_PHYS; /* neponset */
+ info[1].size = SZ_32M;
+ nr = 2;
+ }
+ if (machine_is_badge4()) {
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_4M;
+ nr = 1;
+ }
+ if (machine_is_cerf()) {
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_32M;
+ nr = 1;
+ }
+ if (machine_is_consus()) {
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_32M;
+ nr = 1;
+ }
+ if (machine_is_flexanet()) {
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_32M;
+ nr = 1;
+ }
+ if (machine_is_freebird()) {
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_32M;
+ nr = 1;
+ }
+ if (machine_is_frodo()) {
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_32M;
+ nr = 1;
+ }
+ if (machine_is_graphicsclient()) {
+ info[0].base = SA1100_CS1_PHYS;
+ info[0].size = SZ_32M;
+ nr = 1;
+ }
+ if (machine_is_graphicsmaster()) {
+ info[0].base = SA1100_CS1_PHYS;
+ info[0].size = SZ_16M;
+ nr = 1;
+ }
+ if (machine_is_h3xxx()) {
+ sa1100_map.set_vpp = h3xxx_set_vpp;
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_32M;
+ nr = 1;
+ }
+ if (machine_is_huw_webpanel()) {
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_16M;
+ nr = 1;
+ }
+ if (machine_is_itsy()) {
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_32M;
+ nr = 1;
+ }
+ if (machine_is_jornada720()) {
+ sa1100_map.set_vpp = jornada720_set_vpp;
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_32M;
+ nr = 1;
+ }
+ if (machine_is_nanoengine()) {
+ info[0].base = SA1100_CS0_PHYS;
+ info[1].size = SZ_32M;
+ nr = 1;
+ }
+ if (machine_is_pangolin()) {
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_64M;
+ nr = 1;
+ }
+ if (machine_is_pfs168()) {
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_32M;
+ nr = 1;
+ }
+ if (machine_is_pleb()) {
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_4M;
+ info[1].base = SA1100_CS1_PHYS;
+ info[1].size = SZ_4M;
+ nr = 2;
+ }
+ if (machine_is_pt_system3()) {
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_16M;
+ nr = 1;
+ }
+ if (machine_is_shannon()) {
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_4M;
+ nr = 1;
+ }
+ if (machine_is_sherman()) {
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_32M;
+ nr = 1;
+ }
+ if (machine_is_simpad()) {
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_32M;
+ nr = 1;
+ }
+ if (machine_is_stork()) {
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_32M;
+ nr = 1;
+ }
+ if (machine_is_trizeps()) {
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_16M;
+ nr = 1;
+ }
+ if (machine_is_victor()) {
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_2M;
+ nr = 1;
+ }
+ if (machine_is_yopy()) {
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_64M;
+ info[1].base = SA1100_CS1_PHYS;
+ info[1].size = SZ_64M;
+ nr = 2;
+ }
+
+ if (nr < 0)
+ return nr;
+
+ /*
+ * Retrieve the buswidth from the MSC registers.
+ * We currently only implement CS0 and CS1 here.
+ */
+ for (i = 0; i < nr; i++) {
+ switch (info[i].base) {
+ default:
+ printk(KERN_WARNING "SA1100 flash: unknown base address "
+ "0x%08lx, assuming CS0\n", info[i].base);
+ case SA1100_CS0_PHYS:
+ info[i].width = (MSC0 & MSC_RBW) ? 2 : 4;
+ break;
+
+ case SA1100_CS1_PHYS:
+ info[i].width = ((MSC0 >> 16) & MSC_RBW) ? 2 : 4;
+ break;
+ }
+ }
+
+ return nr;
+}
+
+extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts);
+extern int parse_cmdline_partitions(struct mtd_info *master, struct mtd_partition **pparts, char *);
+
+static struct mtd_partition *parsed_parts;
+
+static void __init sa1100_locate_partitions(struct mtd_info *mtd)
+{
+ const char *part_type = NULL;
+ int nr_parts = 0;
+
+ do {
+ /*
+ * Partition selection stuff.
+ */
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+ nr_parts = parse_cmdline_partitions(mtd, &parsed_parts, "sa1100");
+ if (nr_parts > 0) {
+ part_type = "command line";
+ break;
+ }
+#endif
+#ifdef CONFIG_MTD_REDBOOT_PARTS
+ nr_parts = parse_redboot_partitions(mtd, &parsed_parts);
+ if (nr_parts > 0) {
+ part_type = "RedBoot";
+ break;
+ }
+#endif
+#ifdef CONFIG_MTD_SA1100_STATICMAP
+ nr_parts = sa1100_static_partitions(&parsed_parts);
+ if (nr_parts > 0) {
+ part_type = "static";
+ break;
+ }
+#endif
+ } while (0);
+
+ if (nr_parts == 0) {
+ printk(KERN_NOTICE "SA1100 flash: no partition info "
+ "available, registering whole flash\n");
+ add_mtd_device(mtd);
} else {
- printk(KERN_NOTICE "Using %s partition definition\n", part_type);
- add_mtd_partitions(mymtd, parts, nb_parts);
+ printk(KERN_NOTICE "SA1100 flash: using %s partition "
+ "definition\n", part_type);
+ add_mtd_partitions(mtd, parsed_parts, nr_parts);
}
- return 0;
+
+ /* Always succeeds. */
+}
+
+static void __exit sa1100_destroy_partitions(void)
+{
+ if (parsed_parts)
+ kfree(parsed_parts);
+}
+
+static struct mtd_info *mymtd;
+
+static int __init sa1100_mtd_init(void)
+{
+ int ret;
+ int nr;
+
+ nr = sa1100_locate_flash();
+ if (nr < 0)
+ return nr;
+
+ ret = sa1100_setup_mtd(info, nr, &mymtd);
+ if (ret == 0)
+ sa1100_locate_partitions(mymtd);
+
+ return ret;
}
static void __exit sa1100_mtd_cleanup(void)
{
- if (mymtd) {
- del_mtd_partitions(mymtd);
- map_destroy(mymtd);
- if (parsed_parts)
- kfree(parsed_parts);
- }
+ sa1100_destroy_mtd(info, mymtd);
+ sa1100_destroy_partitions();
}
module_init(sa1100_mtd_init);
diff --git a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c
index 1ad148bd3364..a39bcab25891 100644
--- a/drivers/mtd/mtdblock.c
+++ b/drivers/mtd/mtdblock.c
@@ -295,7 +295,7 @@ static int mtdblock_open(struct inode *inode, struct file *file)
spin_unlock(&mtdblks_lock);
mtdblk = kmalloc(sizeof(struct mtdblk_dev), GFP_KERNEL);
- disk = alloc_disk();
+ disk = alloc_disk(1);
if (!mtdblk || !disk)
goto Enomem;
memset(mtdblk, 0, sizeof(*mtdblk));
@@ -313,7 +313,6 @@ static int mtdblock_open(struct inode *inode, struct file *file)
}
disk->major = MAJOR_NR;
disk->first_minor = dev;
- disk->minor_shift = 0;
disk->fops = &mtd_fops;
sprintf(disk->disk_name, "mtd%d", dev);
mtdblk->disk = disk;
@@ -518,8 +517,6 @@ static int mtdblock_ioctl(struct inode * inode, struct file * file,
switch (cmd) {
case BLKFLSBUF:
- if(!capable(CAP_SYS_ADMIN))
- return -EACCES;
fsync_bdev(inode->i_bdev);
invalidate_bdev(inode->i_bdev, 0);
down(&mtdblk->cache_sem);
diff --git a/drivers/mtd/mtdblock_ro.c b/drivers/mtd/mtdblock_ro.c
index 65b97e3a11df..1878f540f3b6 100644
--- a/drivers/mtd/mtdblock_ro.c
+++ b/drivers/mtd/mtdblock_ro.c
@@ -201,8 +201,6 @@ static int mtdblock_ioctl(struct inode * inode, struct file * file,
if (!mtd || cmd != BLKFLSBUF)
return -EINVAL;
- if(!capable(CAP_SYS_ADMIN))
- return -EACCES;
fsync_bdev(inode->i_bdev);
invalidate_bdev(inode->i_bdev, 0);
if (mtd->sync)
@@ -224,7 +222,7 @@ int __init init_mtdblock(void)
int i;
for (i = 0; i < MAX_MTD_DEVICES; i++) {
- struct gendisk *disk = alloc_disk();
+ struct gendisk *disk = alloc_disk(1);
if (!disk)
goto out;
disk->major = MAJOR_NR;
diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c
new file mode 100644
index 000000000000..4c16c0e43e0f
--- /dev/null
+++ b/drivers/mtd/mtdconcat.c
@@ -0,0 +1,675 @@
+/*
+ * MTD device concatenation layer
+ *
+ * (C) 2002 Robert Kaiser <rkaiser@sysgo.de>
+ *
+ * This code is GPL
+ *
+ * $Id: mtdconcat.c,v 1.3 2002/05/21 21:04:25 dwmw2 Exp $
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/concat.h>
+
+/*
+ * Our storage structure:
+ * Subdev points to an array of pointers to struct mtd_info objects
+ * which is allocated along with this structure
+ *
+ */
+struct mtd_concat {
+ struct mtd_info mtd;
+ int num_subdev;
+ struct mtd_info **subdev;
+};
+
+/*
+ * how to calculate the size required for the above structure,
+ * including the pointer array subdev points to:
+ */
+#define SIZEOF_STRUCT_MTD_CONCAT(num_subdev) \
+ ((sizeof(struct mtd_concat) + (num_subdev) * sizeof(struct mtd_info *)))
+
+
+/*
+ * Given a pointer to the MTD object in the mtd_concat structure,
+ * we can retrieve the pointer to that structure with this macro.
+ */
+#define CONCAT(x) ((struct mtd_concat *)(x))
+
+
+/*
+ * MTD methods which look up the relevant subdevice, translate the
+ * effective address and pass through to the subdevice.
+ */
+
+static int concat_read (struct mtd_info *mtd, loff_t from, size_t len,
+ size_t *retlen, u_char *buf)
+{
+ struct mtd_concat *concat = CONCAT(mtd);
+ int err = -EINVAL;
+ int i;
+
+ *retlen = 0;
+
+ for(i = 0; i < concat->num_subdev; i++)
+ {
+ struct mtd_info *subdev = concat->subdev[i];
+ size_t size, retsize;
+
+ if (from >= subdev->size)
+ {
+ size = 0;
+ from -= subdev->size;
+ }
+ else
+ {
+ if (from + len > subdev->size)
+ size = subdev->size - from;
+ else
+ size = len;
+
+ err = subdev->read(subdev, from, size, &retsize, buf);
+
+ if(err)
+ break;
+
+ *retlen += retsize;
+ len -= size;
+ if(len == 0)
+ break;
+
+ err = -EINVAL;
+ buf += size;
+ from = 0;
+ }
+ }
+ return err;
+}
+
+static int concat_write (struct mtd_info *mtd, loff_t to, size_t len,
+ size_t *retlen, const u_char *buf)
+{
+ struct mtd_concat *concat = CONCAT(mtd);
+ int err = -EINVAL;
+ int i;
+
+ if (!(mtd->flags & MTD_WRITEABLE))
+ return -EROFS;
+
+ *retlen = 0;
+
+ for(i = 0; i < concat->num_subdev; i++)
+ {
+ struct mtd_info *subdev = concat->subdev[i];
+ size_t size, retsize;
+
+ if (to >= subdev->size)
+ {
+ size = 0;
+ to -= subdev->size;
+ }
+ else
+ {
+ if (to + len > subdev->size)
+ size = subdev->size - to;
+ else
+ size = len;
+
+ if (!(subdev->flags & MTD_WRITEABLE))
+ err = -EROFS;
+ else
+ err = subdev->write(subdev, to, size, &retsize, buf);
+
+ if(err)
+ break;
+
+ *retlen += retsize;
+ len -= size;
+ if(len == 0)
+ break;
+
+ err = -EINVAL;
+ buf += size;
+ to = 0;
+ }
+ }
+ return err;
+}
+
+static void concat_erase_callback (struct erase_info *instr)
+{
+ wake_up((wait_queue_head_t *)instr->priv);
+}
+
+static int concat_dev_erase(struct mtd_info *mtd, struct erase_info *erase)
+{
+ int err;
+ wait_queue_head_t waitq;
+ DECLARE_WAITQUEUE(wait, current);
+
+ /*
+ * This code was stol^H^H^H^Hinspired by mtdchar.c
+ */
+ init_waitqueue_head(&waitq);
+
+ erase->mtd = mtd;
+ erase->callback = concat_erase_callback;
+ erase->priv = (unsigned long)&waitq;
+
+ /*
+ * FIXME: Allow INTERRUPTIBLE. Which means
+ * not having the wait_queue head on the stack.
+ */
+ err = mtd->erase(mtd, erase);
+ if (!err)
+ {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ add_wait_queue(&waitq, &wait);
+ if (erase->state != MTD_ERASE_DONE && erase->state != MTD_ERASE_FAILED)
+ schedule();
+ remove_wait_queue(&waitq, &wait);
+ set_current_state(TASK_RUNNING);
+
+ err = (erase->state == MTD_ERASE_FAILED) ? -EIO : 0;
+ }
+ return err;
+}
+
+static int concat_erase (struct mtd_info *mtd, struct erase_info *instr)
+{
+ struct mtd_concat *concat = CONCAT(mtd);
+ struct mtd_info *subdev;
+ int i, err;
+ u_int32_t length;
+ struct erase_info *erase;
+
+ if (!(mtd->flags & MTD_WRITEABLE))
+ return -EROFS;
+
+ if(instr->addr > concat->mtd.size)
+ return -EINVAL;
+
+ if(instr->len + instr->addr > concat->mtd.size)
+ return -EINVAL;
+
+ /*
+ * Check for proper erase block alignment of the to-be-erased area.
+ * It is easier to do this based on the super device's erase
+ * region info rather than looking at each particular sub-device
+ * in turn.
+ */
+ if (!concat->mtd.numeraseregions)
+ { /* the easy case: device has uniform erase block size */
+ if(instr->addr & (concat->mtd.erasesize - 1))
+ return -EINVAL;
+ if(instr->len & (concat->mtd.erasesize - 1))
+ return -EINVAL;
+ }
+ else
+ { /* device has variable erase size */
+ struct mtd_erase_region_info *erase_regions = concat->mtd.eraseregions;
+
+ /*
+ * Find the erase region where the to-be-erased area begins:
+ */
+ for(i = 0; i < concat->mtd.numeraseregions &&
+ instr->addr >= erase_regions[i].offset; i++)
+ ;
+ --i;
+
+ /*
+ * Now erase_regions[i] is the region in which the
+ * to-be-erased area begins. Verify that the starting
+ * offset is aligned to this region's erase size:
+ */
+ if (instr->addr & (erase_regions[i].erasesize-1))
+ return -EINVAL;
+
+ /*
+ * now find the erase region where the to-be-erased area ends:
+ */
+ for(; i < concat->mtd.numeraseregions &&
+ (instr->addr + instr->len) >= erase_regions[i].offset ; ++i)
+ ;
+ --i;
+ /*
+ * check if the ending offset is aligned to this region's erase size
+ */
+ if ((instr->addr + instr->len) & (erase_regions[i].erasesize-1))
+ return -EINVAL;
+ }
+
+ /* make a local copy of instr to avoid modifying the caller's struct */
+ erase = kmalloc(sizeof(struct erase_info),GFP_KERNEL);
+
+ if (!erase)
+ return -ENOMEM;
+
+ *erase = *instr;
+ length = instr->len;
+
+ /*
+ * find the subdevice where the to-be-erased area begins, adjust
+ * starting offset to be relative to the subdevice start
+ */
+ for(i = 0; i < concat->num_subdev; i++)
+ {
+ subdev = concat->subdev[i];
+ if(subdev->size <= erase->addr)
+ erase->addr -= subdev->size;
+ else
+ break;
+ }
+ if(i >= concat->num_subdev) /* must never happen since size */
+ BUG(); /* limit has been verified above */
+
+ /* now do the erase: */
+ err = 0;
+ for(;length > 0; i++) /* loop for all subevices affected by this request */
+ {
+ subdev = concat->subdev[i]; /* get current subdevice */
+
+ /* limit length to subdevice's size: */
+ if(erase->addr + length > subdev->size)
+ erase->len = subdev->size - erase->addr;
+ else
+ erase->len = length;
+
+ if (!(subdev->flags & MTD_WRITEABLE))
+ {
+ err = -EROFS;
+ break;
+ }
+ length -= erase->len;
+ if ((err = concat_dev_erase(subdev, erase)))
+ {
+ if(err == -EINVAL) /* sanity check: must never happen since */
+ BUG(); /* block alignment has been checked above */
+ break;
+ }
+ /*
+ * erase->addr specifies the offset of the area to be
+ * erased *within the current subdevice*. It can be
+ * non-zero only the first time through this loop, i.e.
+ * for the first subdevice where blocks need to be erased.
+ * All the following erases must begin at the start of the
+ * current subdevice, i.e. at offset zero.
+ */
+ erase->addr = 0;
+ }
+ kfree(erase);
+ if (err)
+ return err;
+
+ instr->state = MTD_ERASE_DONE;
+ if (instr->callback)
+ instr->callback(instr);
+ return 0;
+}
+
+static int concat_lock (struct mtd_info *mtd, loff_t ofs, size_t len)
+{
+ struct mtd_concat *concat = CONCAT(mtd);
+ int i, err = -EINVAL;
+
+ if ((len + ofs) > mtd->size)
+ return -EINVAL;
+
+ for(i = 0; i < concat->num_subdev; i++)
+ {
+ struct mtd_info *subdev = concat->subdev[i];
+ size_t size;
+
+ if (ofs >= subdev->size)
+ {
+ size = 0;
+ ofs -= subdev->size;
+ }
+ else
+ {
+ if (ofs + len > subdev->size)
+ size = subdev->size - ofs;
+ else
+ size = len;
+
+ err = subdev->lock(subdev, ofs, size);
+
+ if(err)
+ break;
+
+ len -= size;
+ if(len == 0)
+ break;
+
+ err = -EINVAL;
+ ofs = 0;
+ }
+ }
+ return err;
+}
+
+static int concat_unlock (struct mtd_info *mtd, loff_t ofs, size_t len)
+{
+ struct mtd_concat *concat = CONCAT(mtd);
+ int i, err = 0;
+
+ if ((len + ofs) > mtd->size)
+ return -EINVAL;
+
+ for(i = 0; i < concat->num_subdev; i++)
+ {
+ struct mtd_info *subdev = concat->subdev[i];
+ size_t size;
+
+ if (ofs >= subdev->size)
+ {
+ size = 0;
+ ofs -= subdev->size;
+ }
+ else
+ {
+ if (ofs + len > subdev->size)
+ size = subdev->size - ofs;
+ else
+ size = len;
+
+ err = subdev->unlock(subdev, ofs, size);
+
+ if(err)
+ break;
+
+ len -= size;
+ if(len == 0)
+ break;
+
+ err = -EINVAL;
+ ofs = 0;
+ }
+ }
+ return err;
+}
+
+static void concat_sync(struct mtd_info *mtd)
+{
+ struct mtd_concat *concat = CONCAT(mtd);
+ int i;
+
+ for(i = 0; i < concat->num_subdev; i++)
+ {
+ struct mtd_info *subdev = concat->subdev[i];
+ subdev->sync(subdev);
+ }
+}
+
+static int concat_suspend(struct mtd_info *mtd)
+{
+ struct mtd_concat *concat = CONCAT(mtd);
+ int i, rc = 0;
+
+ for(i = 0; i < concat->num_subdev; i++)
+ {
+ struct mtd_info *subdev = concat->subdev[i];
+ if((rc = subdev->suspend(subdev)) < 0)
+ return rc;
+ }
+ return rc;
+}
+
+static void concat_resume(struct mtd_info *mtd)
+{
+ struct mtd_concat *concat = CONCAT(mtd);
+ int i;
+
+ for(i = 0; i < concat->num_subdev; i++)
+ {
+ struct mtd_info *subdev = concat->subdev[i];
+ subdev->resume(subdev);
+ }
+}
+
+/*
+ * This function constructs a virtual MTD device by concatenating
+ * num_devs MTD devices. A pointer to the new device object is
+ * stored to *new_dev upon success. This function does _not_
+ * register any devices: this is the caller's responsibility.
+ */
+struct mtd_info *mtd_concat_create(
+ struct mtd_info *subdev[], /* subdevices to concatenate */
+ int num_devs, /* number of subdevices */
+ char *name) /* name for the new device */
+{
+ int i;
+ size_t size;
+ struct mtd_concat *concat;
+ u_int32_t max_erasesize, curr_erasesize;
+ int num_erase_region;
+
+ printk(KERN_NOTICE "Concatenating MTD devices:\n");
+ for(i = 0; i < num_devs; i++)
+ printk(KERN_NOTICE "(%d): \"%s\"\n", i, subdev[i]->name);
+ printk(KERN_NOTICE "into device \"%s\"\n", name);
+
+ /* allocate the device structure */
+ size = SIZEOF_STRUCT_MTD_CONCAT(num_devs);
+ concat = kmalloc (size, GFP_KERNEL);
+ if(!concat)
+ {
+ printk ("memory allocation error while creating concatenated device \"%s\"\n",
+ name);
+ return NULL;
+ }
+ memset(concat, 0, size);
+ concat->subdev = (struct mtd_info **)(concat + 1);
+
+ /*
+ * Set up the new "super" device's MTD object structure, check for
+ * incompatibilites between the subdevices.
+ */
+ concat->mtd.type = subdev[0]->type;
+ concat->mtd.flags = subdev[0]->flags;
+ concat->mtd.size = subdev[0]->size;
+ concat->mtd.erasesize = subdev[0]->erasesize;
+ concat->mtd.oobblock = subdev[0]->oobblock;
+ concat->mtd.oobsize = subdev[0]->oobsize;
+ concat->mtd.ecctype = subdev[0]->ecctype;
+ concat->mtd.eccsize = subdev[0]->eccsize;
+
+ concat->subdev[0] = subdev[0];
+
+ for(i = 1; i < num_devs; i++)
+ {
+ if(concat->mtd.type != subdev[i]->type)
+ {
+ kfree(concat);
+ printk ("Incompatible device type on \"%s\"\n", subdev[i]->name);
+ return NULL;
+ }
+ if(concat->mtd.flags != subdev[i]->flags)
+ { /*
+ * Expect all flags except MTD_WRITEABLE to be equal on
+ * all subdevices.
+ */
+ if((concat->mtd.flags ^ subdev[i]->flags) & ~MTD_WRITEABLE)
+ {
+ kfree(concat);
+ printk ("Incompatible device flags on \"%s\"\n", subdev[i]->name);
+ return NULL;
+ }
+ else /* if writeable attribute differs, make super device writeable */
+ concat->mtd.flags |= subdev[i]->flags & MTD_WRITEABLE;
+ }
+ concat->mtd.size += subdev[i]->size;
+ if(concat->mtd.oobblock != subdev[i]->oobblock ||
+ concat->mtd.oobsize != subdev[i]->oobsize ||
+ concat->mtd.ecctype != subdev[i]->ecctype ||
+ concat->mtd.eccsize != subdev[i]->eccsize)
+ {
+ kfree(concat);
+ printk ("Incompatible OOB or ECC data on \"%s\"\n", subdev[i]->name);
+ return NULL;
+ }
+ concat->subdev[i] = subdev[i];
+
+ }
+
+ concat->num_subdev = num_devs;
+ concat->mtd.name = name;
+
+ /*
+ * NOTE: for now, we do not provide any readv()/writev() methods
+ * because they are messy to implement and they are not
+ * used to a great extent anyway.
+ */
+ concat->mtd.erase = concat_erase;
+ concat->mtd.read = concat_read;
+ concat->mtd.write = concat_write;
+ concat->mtd.sync = concat_sync;
+ concat->mtd.lock = concat_lock;
+ concat->mtd.unlock = concat_unlock;
+ concat->mtd.suspend = concat_suspend;
+ concat->mtd.resume = concat_resume;
+
+
+ /*
+ * Combine the erase block size info of the subdevices:
+ *
+ * first, walk the map of the new device and see how
+ * many changes in erase size we have
+ */
+ max_erasesize = curr_erasesize = subdev[0]->erasesize;
+ num_erase_region = 1;
+ for(i = 0; i < num_devs; i++)
+ {
+ if(subdev[i]->numeraseregions == 0)
+ { /* current subdevice has uniform erase size */
+ if(subdev[i]->erasesize != curr_erasesize)
+ { /* if it differs from the last subdevice's erase size, count it */
+ ++num_erase_region;
+ curr_erasesize = subdev[i]->erasesize;
+ if(curr_erasesize > max_erasesize)
+ max_erasesize = curr_erasesize;
+ }
+ }
+ else
+ { /* current subdevice has variable erase size */
+ int j;
+ for(j = 0; j < subdev[i]->numeraseregions; j++)
+ { /* walk the list of erase regions, count any changes */
+ if(subdev[i]->eraseregions[j].erasesize != curr_erasesize)
+ {
+ ++num_erase_region;
+ curr_erasesize = subdev[i]->eraseregions[j].erasesize;
+ if(curr_erasesize > max_erasesize)
+ max_erasesize = curr_erasesize;
+ }
+ }
+ }
+ }
+
+ if(num_erase_region == 1)
+ { /*
+ * All subdevices have the same uniform erase size.
+ * This is easy:
+ */
+ concat->mtd.erasesize = curr_erasesize;
+ concat->mtd.numeraseregions = 0;
+ }
+ else
+ { /*
+ * erase block size varies across the subdevices: allocate
+ * space to store the data describing the variable erase regions
+ */
+ struct mtd_erase_region_info *erase_region_p;
+ u_int32_t begin, position;
+
+ concat->mtd.erasesize = max_erasesize;
+ concat->mtd.numeraseregions = num_erase_region;
+ concat->mtd.eraseregions = erase_region_p = kmalloc (
+ num_erase_region * sizeof(struct mtd_erase_region_info), GFP_KERNEL);
+ if(!erase_region_p)
+ {
+ kfree(concat);
+ printk ("memory allocation error while creating erase region list"
+ " for device \"%s\"\n", name);
+ return NULL;
+ }
+
+ /*
+ * walk the map of the new device once more and fill in
+ * in erase region info:
+ */
+ curr_erasesize = subdev[0]->erasesize;
+ begin = position = 0;
+ for(i = 0; i < num_devs; i++)
+ {
+ if(subdev[i]->numeraseregions == 0)
+ { /* current subdevice has uniform erase size */
+ if(subdev[i]->erasesize != curr_erasesize)
+ { /*
+ * fill in an mtd_erase_region_info structure for the area
+ * we have walked so far:
+ */
+ erase_region_p->offset = begin;
+ erase_region_p->erasesize = curr_erasesize;
+ erase_region_p->numblocks = (position - begin) / curr_erasesize;
+ begin = position;
+
+ curr_erasesize = subdev[i]->erasesize;
+ ++erase_region_p;
+ }
+ position += subdev[i]->size;
+ }
+ else
+ { /* current subdevice has variable erase size */
+ int j;
+ for(j = 0; j < subdev[i]->numeraseregions; j++)
+ { /* walk the list of erase regions, count any changes */
+ if(subdev[i]->eraseregions[j].erasesize != curr_erasesize)
+ {
+ erase_region_p->offset = begin;
+ erase_region_p->erasesize = curr_erasesize;
+ erase_region_p->numblocks = (position - begin) / curr_erasesize;
+ begin = position;
+
+ curr_erasesize = subdev[i]->eraseregions[j].erasesize;
+ ++erase_region_p;
+ }
+ position += subdev[i]->eraseregions[j].numblocks * curr_erasesize;
+ }
+ }
+ }
+ /* Now write the final entry */
+ erase_region_p->offset = begin;
+ erase_region_p->erasesize = curr_erasesize;
+ erase_region_p->numblocks = (position - begin) / curr_erasesize;
+ }
+
+ return &concat->mtd;
+}
+
+/*
+ * This function destroys an MTD object obtained from concat_mtd_devs()
+ */
+
+void mtd_concat_destroy(struct mtd_info *mtd)
+{
+ struct mtd_concat *concat = CONCAT(mtd);
+ if(concat->mtd.numeraseregions)
+ kfree(concat->mtd.eraseregions);
+ kfree(concat);
+}
+
+
+EXPORT_SYMBOL(mtd_concat_create);
+EXPORT_SYMBOL(mtd_concat_destroy);
+
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Robert Kaiser <rkaiser@sysgo.de>");
+MODULE_DESCRIPTION("Generic support for concatenating of MTD devices");
diff --git a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c
index 60d26b10740e..292894af8252 100644
--- a/drivers/mtd/nftlcore.c
+++ b/drivers/mtd/nftlcore.c
@@ -74,7 +74,7 @@ static void NFTL_setup(struct mtd_info *mtd)
}
nftl = kmalloc(sizeof(struct NFTLrecord), GFP_KERNEL);
- gd = alloc_disk();
+ gd = alloc_disk(1 << NFTL_PARTN_BITS);
if (!nftl || !gd) {
kfree(nftl);
put_disk(gd);
@@ -132,7 +132,6 @@ static void NFTL_setup(struct mtd_info *mtd)
sprintf(gd->disk_name, "nftl%c", 'a' + firstfree);
gd->major = MAJOR_NR;
gd->first_minor = firstfree << NFTL_PARTN_BITS;
- gd->minor_shift = NFTL_PARTN_BITS;
set_capacity(gd, nftl->nr_sects);
nftl->disk = gd;
add_disk(gd);
@@ -771,7 +770,6 @@ static int nftl_ioctl(struct inode * inode, struct file * file, unsigned int cmd
return copy_to_user((void *)arg, &g, sizeof g) ? -EFAULT : 0;
}
case BLKFLSBUF:
- if (!capable(CAP_SYS_ADMIN)) return -EACCES;
fsync_bdev(inode->i_bdev);
invalidate_bdev(inode->i_bdev, 0);
if (nftl->mtd->sync)