* [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
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