public inbox for linux-mtd@lists.infradead.org
 help / color / mirror / Atom feed
* [PATCH 2.6.12-rc2] Add flash mapping for Radstone PPC7D
@ 2005-04-08  9:48 Chris Elston
  2005-04-08  9:50 ` David Woodhouse
  0 siblings, 1 reply; 2+ messages in thread
From: Chris Elston @ 2005-04-08  9:48 UTC (permalink / raw)
  To: linux-mtd; +Cc: dwmw2

[-- Attachment #1: Type: text/plain, Size: 975 bytes --]

This patch adds MTD mapping support for the PPC7D.  Because of the potentially
large amount of SDRAM on this platform I have had to map each bank of flash
into kernel virtual address space on demand.  I've done this by providing my
own read/write/copy_from/copy_to functions which map the required bank and then
drop straight through to the standard inline versions.  This doesn't seem to
create a large performance hit, but I don't have any quantative results to back
that up.

Comments/criticisms on this technique and the rest of the patch would be much 
appreciated.

Thanks

Chris.

________________________________________________________________________
This e-mail has been scanned for all viruses by Star. The
service is powered by MessageLabs. For more information on a proactive
anti-virus service working around the clock, around the globe, visit:
http://www.star.net.uk
________________________________________________________________________

[-- Attachment #2: ppc7d_mtd_map.patch --]
[-- Type: application/octet-stream, Size: 11098 bytes --]

diff -Naur linux-2.6.12-rc2/drivers/mtd/maps/Kconfig linux-2.6.12-rc2-cde/drivers/mtd/maps/Kconfig
--- linux-2.6.12-rc2/drivers/mtd/maps/Kconfig	2005-04-07 12:31:44.000000000 +0100
+++ linux-2.6.12-rc2-cde/drivers/mtd/maps/Kconfig	2005-04-07 12:28:55.000000000 +0100
@@ -139,6 +139,17 @@
 	  This provides a driver for the on-board flash of the Intel
 	  'Lubbock' XScale evaluation board.
 
+config MTD_RSPPC7D
+        tristate "CFI Flash device mapped on Radstone PPC7D board"
+	depends on RADSTONE_PPC7D
+	select MTD_PARTITIONS
+	select MTD_COMPLEX_MAPPINGS
+        select MTD_CONCAT 
+	select MTD_CFI_INTELEXT
+        help
+          This provides a 'mapping' driver for the on-board flash of
+          the Radstone PPC7D board.
+
 config MTD_OCTAGON
 	tristate "JEDEC Flash device mapped on Octagon 5066 SBC"
 	depends on X86 && MTD_JEDEC && MTD_COMPLEX_MAPPINGS
diff -Naur linux-2.6.12-rc2/drivers/mtd/maps/Makefile linux-2.6.12-rc2-cde/drivers/mtd/maps/Makefile
--- linux-2.6.12-rc2/drivers/mtd/maps/Makefile	2005-04-07 12:31:44.000000000 +0100
+++ linux-2.6.12-rc2-cde/drivers/mtd/maps/Makefile	2005-04-07 12:28:55.000000000 +0100
@@ -23,6 +23,7 @@
 obj-$(CONFIG_MTD_ICHXROM)	+= ichxrom.o
 obj-$(CONFIG_MTD_TSUNAMI)	+= tsunami_flash.o
 obj-$(CONFIG_MTD_LUBBOCK)	+= lubbock-flash.o
+obj-$(CONFIG_MTD_RSPPC7D)       += rsppc7d-flash.o
 obj-$(CONFIG_MTD_MBX860)	+= mbx860.o
 obj-$(CONFIG_MTD_CEIVA)		+= ceiva.o
 obj-$(CONFIG_MTD_OCTAGON)	+= octagon-5066.o
diff -Naur linux-2.6.12-rc2/drivers/mtd/maps/rsppc7d-flash.c linux-2.6.12-rc2-cde/drivers/mtd/maps/rsppc7d-flash.c
--- linux-2.6.12-rc2/drivers/mtd/maps/rsppc7d-flash.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.12-rc2-cde/drivers/mtd/maps/rsppc7d-flash.c	2005-04-07 12:28:55.000000000 +0100
@@ -0,0 +1,372 @@
+/*
+ * Radstone Technology PPC7D Flash memory driver.
+ * Copyright (C) 2005 Radstone Technology <chris.elston@radstone.co.uk>
+ *
+ * Based on: ceiva.c, which has the following copyright:
+ * Ceiva flash memory driver.
+ * Copyright (C) 2002 Rob Scott <rscott@mtrob.fdns.net>
+ *
+ * Based on: sa1100-flash.c, which has the following copyright:
+ * Flash memory access on SA11x0 based devices
+ *
+ * (C) 2000 Nicolas Pitre <nico@cam.org>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/concat.h>
+
+#include <asm/io.h>
+#include <asm/ppcboot.h>
+
+#include <platforms/radstone_ppc7d.h>
+
+extern unsigned char __res[]; /* residual data structure */
+static bd_t *binfo = (bd_t *)__res;
+
+/*
+ * See include/linux/mtd/partitions.h for definition of the mtd_partition
+ * structure.
+ */
+
+#define RSPPC7D_BOOT_PARTITION_SIZE	0x800000
+#define RSPPC7D_KERNEL_PARTITION_SIZE	0x400000
+
+static struct mtd_partition rsppc7d_partitions[] = {
+        {
+                .name =         "User",
+                .size =         0,	/* set at runtime */
+                .offset =       0
+        },{
+                .name =         "Kernel",
+                .size =         RSPPC7D_KERNEL_PARTITION_SIZE,
+                .offset =       MTDPART_OFS_APPEND
+        },{
+                .name =         "PPCBoot",
+                .size =         RSPPC7D_BOOT_PARTITION_SIZE,
+                .offset =       MTDPART_OFS_APPEND,
+                .mask_flags =   MTD_WRITEABLE  /* force read-only */
+        }
+};
+
+static int __init rsppc7d_static_partitions(struct mtd_partition **parts)
+{
+	int nb_parts = 0;
+
+	rsppc7d_partitions[0].size = binfo->bi_flashsize - 
+				     RSPPC7D_KERNEL_PARTITION_SIZE - 
+				     RSPPC7D_BOOT_PARTITION_SIZE;
+	*parts       = rsppc7d_partitions;
+	nb_parts     = ARRAY_SIZE(rsppc7d_partitions);
+
+	return nb_parts;
+}
+
+struct rsppc7d_info {
+	unsigned long base;
+	unsigned long size;
+	int width;
+	void __iomem *vbase;
+	struct map_info *map;
+	struct mtd_info *mtd;
+	struct resource *res;
+};
+
+static struct map_info *io_mapped_map = NULL;
+
+/*
+ * In order to avoid running out of vmalloc space, this
+ * function is used to 'page' the map which is currently 
+ * being used in and out of vmalloc.
+ */
+static void __iomem *rsppc7d_ioremap_flash(struct map_info *map)
+{
+	if (map != io_mapped_map) {
+		if (io_mapped_map) {
+			iounmap(io_mapped_map->virt);
+			io_mapped_map->virt = NULL;
+		}
+		io_mapped_map = map;
+		io_mapped_map->virt = ioremap(map->phys, map->size);
+		if (!io_mapped_map->virt) {
+			printk(KERN_ERR "rsppc7d_flash: unable to ioremap Flash\n");
+		}
+	}
+
+	return io_mapped_map->virt;
+}
+
+/* 
+ * Flash access functions - fall through to default 
+ * functions after ioremapping the current map.
+ */
+static inline map_word rsppc7d_flash_read(struct map_info *map, unsigned long ofs)
+{
+	rsppc7d_ioremap_flash(map);
+	return inline_map_read(map, ofs);
+}
+
+static void rsppc7d_flash_write(struct map_info *map, const map_word datum, unsigned long ofs)
+{
+	rsppc7d_ioremap_flash(map);
+	inline_map_write(map, datum, ofs);	
+}
+
+static void rsppc7d_flash_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+	rsppc7d_ioremap_flash(map);
+	inline_map_copy_from(map, to, from, len);
+}
+
+static void rsppc7d_flash_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+	rsppc7d_ioremap_flash(map);
+	inline_map_copy_to(map, to, from, len);
+}
+
+#define MAX_NR_SUBMTD 4
+
+static struct rsppc7d_info info[MAX_NR_SUBMTD];
+
+static int __init rsppc7d_setup_mtd(struct rsppc7d_info *rsppc7d, 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;
+	memset(maps, 0, sizeof(struct map_info) * nr);
+
+	/*
+	 * Claim and then map the memory regions.
+	 */
+	for (i = 0; i < nr; i++) {
+		if (rsppc7d[i].base == (unsigned long)-1)
+			break;
+		
+		rsppc7d[i].res = request_mem_region(rsppc7d[i].base, rsppc7d[i].size, "rsppc7d flash");
+		if (!rsppc7d[i].res) {
+			ret = -EBUSY;
+			break;
+		}
+
+		rsppc7d[i].map = maps + i;
+
+		rsppc7d[i].map->name = "rsppc7d flash";
+		rsppc7d[i].map->size = rsppc7d[i].size;
+		rsppc7d[i].map->phys = rsppc7d[i].base;
+		rsppc7d[i].map->bankwidth = rsppc7d[i].width;
+
+		rsppc7d[i].map->read = rsppc7d_flash_read;
+		rsppc7d[i].map->write = rsppc7d_flash_write;
+		rsppc7d[i].map->copy_from = rsppc7d_flash_copy_from;
+		rsppc7d[i].map->copy_to = rsppc7d_flash_copy_to;
+
+		rsppc7d[i].mtd = do_map_probe("cfi_probe", rsppc7d[i].map);
+		if (rsppc7d[i].mtd == NULL) {
+			ret = -ENXIO;
+			break;
+		}
+		rsppc7d[i].mtd->owner = THIS_MODULE;
+		subdev[i] = rsppc7d[i].mtd;
+
+		printk(KERN_INFO "rsppc7d flash: CFI device at 0x%08lx, %dMiB, "
+			"%d-bit\n", rsppc7d[i].base, rsppc7d[i].mtd->size >> 20,
+			rsppc7d[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) {
+		release_resource(rsppc7d[i].res);
+		rsppc7d[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,
+						  "rsppc7d flash");
+			if (*rmtd == NULL)
+				ret = -ENXIO;
+#else
+			printk(KERN_ERR "rsppc7d flash: multiple devices "
+			       "found but MTD concat support disabled.\n");
+			ret = -ENXIO;
+#endif
+		}
+	}
+
+	/*
+	 * If we failed, clean up.
+	 */
+	if (ret) {
+		do {
+			if (rsppc7d[i].mtd)
+				map_destroy(rsppc7d[i].mtd);
+			if (rsppc7d[i].res)
+				release_resource(rsppc7d[i].res);
+		} while (i--);
+
+		kfree(maps);
+	}
+
+	return ret;
+}
+
+static void __exit rsppc7d_destroy_mtd(struct rsppc7d_info *rsppc7d, struct mtd_info *mtd)
+{
+	int i;
+
+	del_mtd_partitions(mtd);
+
+	if (mtd != rsppc7d[0].mtd)
+		mtd_concat_destroy(mtd);
+
+	for (i = MAX_NR_SUBMTD; i >= 0; i--) {
+		if (rsppc7d[i].mtd)
+			map_destroy(rsppc7d[i].mtd);
+		if (rsppc7d[i].res)
+			release_resource(rsppc7d[i].res);
+	}
+
+	if (io_mapped_map)
+		iounmap(io_mapped_map->virt);
+
+	kfree(rsppc7d[0].map);
+}
+
+/*
+ * We define the memory space, size, and width for the flash memory
+ * space here.
+ */
+
+#define RSPPC7D_FLASH_BANK_WIDTH 4
+
+static int __init rsppc7d_setup_flash(void)
+{
+	int nr, banksz, banknr;
+	unsigned char memcfg;
+
+        static int flash_sizes[4] = { 0x04000000, 0x02000000, 0, 0x01000000 };
+        static int flash_banks[4] = { 4, 3, 2, 1 };
+
+	memcfg = inb(PPC7D_CPLD_MEM_CONFIG_EXTEND);
+	banksz = flash_sizes[memcfg & PPC7D_CPLD_FLASH_DEV_SIZE_MASK];
+	banknr = flash_banks[(memcfg & PPC7D_CPLD_FLASH_BANK_NUM_MASK) >> 2];
+
+	for (nr = 0; nr < banknr; nr++)
+	{
+		info[nr].base = binfo->bi_flashstart + (nr * banksz);
+		info[nr].size = banksz;
+		info[nr].width = RSPPC7D_FLASH_BANK_WIDTH;
+	}
+
+	return banknr;
+}
+
+static struct mtd_partition *parsed_parts;
+static const char *probes[] = { "cmdlinepart", NULL };
+
+static void __init rsppc7d_locate_partitions(struct mtd_info *mtd)
+{
+	const char *part_type = NULL;
+	int nr_parts = 0;
+	do {
+		/*
+		 * Partition selection stuff.
+		 */
+		nr_parts = parse_mtd_partitions(mtd, probes, &parsed_parts, 0);
+		if (nr_parts > 0) {
+			part_type = "command line";
+			break;
+		}
+		nr_parts = rsppc7d_static_partitions(&parsed_parts);
+		if (nr_parts > 0) {
+			part_type = "static";
+			break;
+		}
+		printk("found: %d partitions\n", nr_parts);
+	} while (0);
+
+	if (nr_parts == 0) {
+		printk(KERN_NOTICE "rsppc7d flash: no partition info "
+			"available, registering whole flash\n");
+		add_mtd_device(mtd);
+	} else {
+		printk(KERN_NOTICE "rsppc7d flash: using %s partition "
+			"definition\n", part_type);
+		add_mtd_partitions(mtd, parsed_parts, nr_parts);
+	}
+
+	/* Always succeeds. */
+}
+
+static void __exit rsppc7d_destroy_partitions(void)
+{
+	if (parsed_parts)
+		kfree(parsed_parts);
+}
+
+static struct mtd_info *mymtd;
+
+static int __init rsppc7d_mtd_init(void)
+{
+	int ret;
+	int nr;
+
+	nr = rsppc7d_setup_flash();
+	if (nr < 0)
+		return nr;
+
+	ret = rsppc7d_setup_mtd(info, nr, &mymtd);
+	if (ret)
+		return ret;
+
+	rsppc7d_locate_partitions(mymtd);
+
+	return 0;
+}
+
+static void __exit rsppc7d_mtd_cleanup(void)
+{
+	rsppc7d_destroy_mtd(info, mymtd);
+	rsppc7d_destroy_partitions();
+}
+
+module_init(rsppc7d_mtd_init);
+module_exit(rsppc7d_mtd_cleanup);
+
+MODULE_AUTHOR("Chris Elston <chris.elston@radstone.co.uk>");
+MODULE_DESCRIPTION("MTD map driver for Radstone PPC7D");
+MODULE_LICENSE("GPL");

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [PATCH 2.6.12-rc2] Add flash mapping for Radstone PPC7D
  2005-04-08  9:48 [PATCH 2.6.12-rc2] Add flash mapping for Radstone PPC7D Chris Elston
@ 2005-04-08  9:50 ` David Woodhouse
  0 siblings, 0 replies; 2+ messages in thread
From: David Woodhouse @ 2005-04-08  9:50 UTC (permalink / raw)
  To: Chris Elston; +Cc: linux-mtd

On Fri, 2005-04-08 at 10:48 +0100, Chris Elston wrote:
> Comments/criticisms on this technique and the rest of the patch would
> be much appreciated.

vmalloc() can sleep, but you may not in your read/write map functions.

-- 
dwmw2

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2005-04-08  9:51 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-04-08  9:48 [PATCH 2.6.12-rc2] Add flash mapping for Radstone PPC7D Chris Elston
2005-04-08  9:50 ` David Woodhouse

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox