[PATCH] ppc32: STXXTC board mtd bits.

Pantelis Antoniou pantelis.antoniou at gmail.com
Tue Dec 6 16:58:49 EST 2005


Support NOR & NAND present in Silicon Turnkey's XTc.

---
commit 721e1a97125a2f6118efc52b169a045a0334deb5
tree 508fde3b74cda7abf47c42421049330ec4116088
parent 76d9ad9d0440e6f26ff87899284a90cd865dd330
author Pantelis Antoniou <pantelis.antoniou at gmail.com> Tue, 06 Dec 2005 23:18:16 +0200
committer Pantelis Antoniou <pantelis.antoniou at gmail.com> Tue, 06 Dec 2005 23:18:16 +0200

 drivers/mtd/maps/Kconfig       |    6 +
 drivers/mtd/maps/Makefile      |    1 
 drivers/mtd/maps/stxxtc_nor.c  |  268 +++++++++++++++++++++++++++++++++++++++
 drivers/mtd/nand/Kconfig       |    8 +
 drivers/mtd/nand/Makefile      |    1 
 drivers/mtd/nand/stxxtc_nand.c |  277 ++++++++++++++++++++++++++++++++++++++++
 6 files changed, 560 insertions(+), 1 deletions(-)

diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
--- a/drivers/mtd/maps/Kconfig
+++ b/drivers/mtd/maps/Kconfig
@@ -639,5 +639,11 @@ config MTD_PLATRAM
 
 	  This selection automatically selects the map_ram driver.
 
+config MTD_STXXTC_NOR
+	tristate "NOR Map driver for STXXTC NOR flash"
+	depends on STXXTC && MTD_CONCAT && MTD_PARTITIONS && MTD_CFI_INTELEXT
+	help
+	  Map driver for Silicon Turnkey eXpress XTc NOR flash. 
+
 endmenu
 
diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile
--- a/drivers/mtd/maps/Makefile
+++ b/drivers/mtd/maps/Makefile
@@ -72,3 +72,4 @@ obj-$(CONFIG_MTD_PLATRAM)	+= plat-ram.o
 obj-$(CONFIG_MTD_OMAP_NOR)	+= omap_nor.o
 obj-$(CONFIG_MTD_MTX1)		+= mtx-1_flash.o
 obj-$(CONFIG_MTD_TQM834x)	+= tqm834x.o
+obj-$(CONFIG_MTD_STXXTC_NOR)	+= stxxtc_nor.o
diff --git a/drivers/mtd/maps/stxxtc_nor.c b/drivers/mtd/maps/stxxtc_nor.c
new file mode 100644
--- /dev/null
+++ b/drivers/mtd/maps/stxxtc_nor.c
@@ -0,0 +1,268 @@
+/*
+ * Handle mapping of the flash on the STXXTC board
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <asm/io.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/concat.h>
+
+/* Boot flash; same on every board */
+static struct mtd_info *stxxtc_mtd;
+
+#define SECTORSZ(x)	((x) * 64 * 1024)
+
+#define UBOOT_CODE_SECTORS	4
+
+#define ENV1_PART	0
+#define ENV2_PART	1
+
+#define CHKP1_PART	2
+#define CHKP2_PART	3
+
+#define STRG1_PART	4
+
+#define BOOT_PART	5
+
+#define STRG2_PART	6
+
+/* partition_info gives details on the logical partitions that the split the
+ * single flash device into. If the size if zero we use up to the end of the
+ * device. */
+static struct mtd_partition pi[]= {
+	[ENV1_PART] = {
+		.name		= "u-boot_env_#1_0_4000",
+		.size		= SECTORSZ(1),
+		.offset		= SECTORSZ(0),
+	},
+	[ENV2_PART] = {
+		.name		= "u-boot_env_#2_0_4000",
+		.size		= SECTORSZ(1),
+		.offset		= SECTORSZ(1),
+	},
+	[CHKP1_PART] = {
+		.name		= "checkpoint_#1",
+		.size		= SECTORSZ(1),
+		.offset		= SECTORSZ(2),
+	},
+	[CHKP2_PART] = {
+		.name		= "checkpoint_#2",
+		.size		= SECTORSZ(1),
+		.offset		= SECTORSZ(3),
+	},
+	[STRG1_PART] = {
+		.name		= "storage_#1",
+		.size		= 0,	/* to be filled */
+		.offset		= SECTORSZ(4),
+	},
+	[BOOT_PART] = {
+		.name		= "u-boot_code",
+		.size		= SECTORSZ(UBOOT_CODE_SECTORS),
+		.offset		= 0,	/* to be filled */
+		.mask_flags	= MTD_WRITEABLE,	/* don't allow writes at all */
+	},
+	[STRG2_PART] = {
+		.name		= "storage_#2",
+		.size		= 0,	/* what ever remains */
+		.offset		= 0,	/* to be filled */
+	}
+};
+
+#define NUM_PARTITIONS (sizeof(pi) / sizeof(pi[0]))
+
+#define WINDOW_ADDR	0x40000000
+#define WINDOW_SIZE	0x00200000
+
+struct map_info stxxtc_map = {
+	.name		= "STXXTC_boot_flash",
+	.size		= WINDOW_SIZE,
+	.bankwidth	= 2,
+	.phys		= WINDOW_ADDR,
+};
+
+/* two chips supported */
+#define NR_CHIPS	2
+
+struct stxxtc_nor_info {
+	unsigned long base;
+	unsigned long map_size;
+	char *mapname;
+	int width;
+	struct map_info map;
+	struct mtd_info *mtd;
+	struct resource *res;
+};
+
+static struct stxxtc_nor_info info[NR_CHIPS] = {
+	{
+		.base		= 0x40000000,
+		.map_size	= 0x01000000,
+		.width		= 2,
+		.mapname	= "stxxtc_NOR_flash_#1",
+	}, {
+		.base		= 0x42000000,
+		.map_size	= 0x01000000,
+		.width		= 2,
+		.mapname	= "stxxtc_NOR_flash_#2",
+	}
+};
+
+int __init init_stxxtc_nor(void)
+{
+	struct stxxtc_nor_info *ni;
+	int i, j, r = 0, found = 0;
+	unsigned long mask, off;
+	struct mtd_info *subdev[NR_CHIPS];
+
+	memset(subdev, 0, sizeof(subdev));
+
+	for (i = 0, ni = info; i < NR_CHIPS; i++, ni++) {
+
+		memset(&ni->map, 0, sizeof(ni->map));
+
+		ni->res = request_mem_region(ni->base, ni->map_size, ni->mapname);
+		if (ni->res == NULL) {
+			r = -EBUSY;
+			goto err;
+		}
+
+		ni->map.virt = ioremap(ni->base, ni->map_size);
+		if (ni->map.virt == NULL) {
+			r = -ENOMEM;
+			goto err;
+		}
+		ni->map.name = ni->mapname;
+		ni->map.phys = ni->base;
+		ni->map.bankwidth = 2;
+		ni->map.size = ni->map_size;
+		simple_map_init(&ni->map);
+
+		ni->mtd = do_map_probe("cfi_probe", &ni->map);
+		if (ni->mtd == NULL) {
+			/* chip missing; just cleanup and continue */
+			iounmap(ni->map.virt);
+			release_resource(ni->res);
+			ni->res = NULL;
+			memset(&ni->map, 0, sizeof(ni->map));
+			continue;
+		}
+
+		ni->mtd->owner = THIS_MODULE;
+
+		found++;
+
+	}
+
+	/* no chips found... */
+	if (found == 0) {
+		printk(KERN_INFO "stxxtc_nor: No devices found\n");
+		return -ENXIO;
+	}
+
+	/* first chip must exist. */
+	ni = &info[0]; i = 0; j = 0;
+	if (ni->mtd == NULL) {
+		printk(KERN_INFO "stxxtc_nor: First chip missing, not able to continue\n");
+		r = -ENXIO;
+		goto err;
+	}
+
+	printk(KERN_INFO "stxxtc_nor: CFI device found at 0x%08lx, "
+			"%dMiB, %d-bit wide\n", 
+			ni->base, ni->mtd->size >> 20, ni->width * 8);
+
+	/* find out where u-boot code is. It's size is 256K and is located
+	 * at the last megabyte of the first flash, for example a 2M flash
+	 * will have the u-boot part at offset 0x00100000
+	 */
+
+	mask = ni->mtd->size - 1;
+	off = 0xFFF00000 & mask;
+	printk(KERN_INFO "u-boot offset is at 0x%08lx\n", off);
+
+	/* keep it */
+	subdev[j++] = ni->mtd;
+
+	/* next */
+	i++; ni++;
+
+	/* report what we found */
+	for (; i < NR_CHIPS; i++, ni++) {
+		if (ni->mtd == NULL)
+			continue;
+		printk(KERN_INFO "stxxtc_nor: CFI device found at 0x%08lx, "
+				"%dMiB, %d-bit wide\n", 
+				ni->base, ni->mtd->size >> 20, ni->width * 8);
+		subdev[j++] = ni->mtd;
+	}
+
+	/* concat all the devices into one */
+	stxxtc_mtd = mtd_concat_create(subdev, found, "stxxtc NOR flash");
+	if (stxxtc_mtd == NULL) {
+		r = -ENXIO;
+		goto err;
+	}
+	stxxtc_mtd->owner = THIS_MODULE;
+
+	/* fixup partitions */
+	pi[STRG1_PART].size	= off - pi[STRG1_PART].offset;
+	pi[BOOT_PART].offset 	= off;
+	pi[STRG2_PART].offset	= pi[BOOT_PART].offset + pi[BOOT_PART].size;
+
+	add_mtd_partitions(stxxtc_mtd, pi, NUM_PARTITIONS);
+
+	return 0;
+
+err:
+	if (stxxtc_mtd != NULL) {
+		del_mtd_partitions(stxxtc_mtd);
+		mtd_concat_destroy(stxxtc_mtd);
+	}
+
+	for (i = NR_CHIPS - 1, ni = info + i; i >= 0; i--, ni--) {
+		if (ni->mtd)
+			map_destroy(ni->mtd);
+		if (ni->map.virt)
+			iounmap(ni->map.virt);
+		if (ni->res != NULL)
+			release_resource(ni->res);
+	}
+
+
+	return r;
+}
+
+static void __exit cleanup_stxxtc_nor(void)
+{
+	int i;
+	struct stxxtc_nor_info *ni;
+
+	if (stxxtc_mtd != NULL) {
+		del_mtd_partitions(stxxtc_mtd);
+		mtd_concat_destroy(stxxtc_mtd);
+	}
+
+	for (i = NR_CHIPS - 1, ni = info + i; i >= 0; i--, ni--) {
+		if (ni->mtd)
+			map_destroy(ni->mtd);
+		if (ni->map.virt)
+			iounmap(ni->map.virt);
+		if (ni->res != NULL)
+			release_resource(ni->res);
+	}
+
+}
+
+module_init(init_stxxtc_nor);
+module_exit(cleanup_stxxtc_nor);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Pantelis Antoniou <pantelis.antoniou at gmail.com>");
+MODULE_DESCRIPTION("MTD map driver for STXXTC boards");
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -190,5 +190,11 @@ config MTD_NAND_DISKONCHIP_BBTWRITE
 	help
 	  The simulator may simulate verious NAND flash chips for the
 	  MTD nand layer.
- 
+
+config MTD_NAND_STXXTC
+	tristate "NAND Flash support for STXXTC"
+	depends on STXXTC && MTD_NAND
+	help
+	  Use the NAND flash present on Silicon Turnkey eXpress XTc.
+
 endmenu
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -18,5 +18,6 @@ obj-$(CONFIG_MTD_NAND_H1900)		+= h1910.o
 obj-$(CONFIG_MTD_NAND_RTC_FROM4)	+= rtc_from4.o
 obj-$(CONFIG_MTD_NAND_SHARPSL)		+= sharpsl.o
 obj-$(CONFIG_MTD_NAND_NANDSIM)		+= nandsim.o
+obj-$(CONFIG_MTD_NAND_STXXTC)		+= stxxtc_nand.o
 
 nand-objs = nand_base.o nand_bbt.o
diff --git a/drivers/mtd/nand/stxxtc_nand.c b/drivers/mtd/nand/stxxtc_nand.c
new file mode 100644
--- /dev/null
+++ b/drivers/mtd/nand/stxxtc_nand.c
@@ -0,0 +1,277 @@
+/*
+ *  drivers/mtd/nand/stxxtc_nand.c
+ *
+ *  Copyright (C) 2005 Pantelis Antoniou <pantelis.antoniou at gmail.com>
+ *                     Dan Malek <dan at embeddedalley.com>
+ *
+ *  Derived from drivers/mtd/nand/edb7312.c
+ *
+ * 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/config.h>
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/init.h>
+#include <asm/io.h>
+#include <asm/semaphore.h>
+
+#include <platforms/stxxtc.h>
+
+/******************************************************************************/
+
+static struct mtd_info *stxxtc_mtd = NULL;
+static unsigned int stxxtc_fio_base;
+static int mtd_parts_nb = 0;
+static struct mtd_partition *mtd_parts;
+static const char *part_type = NULL;
+static const char *part_probes[] = { "cmdlinepart", NULL };
+
+/* we need these */
+extern struct semaphore mtd_table_mutex;
+extern struct mtd_info *mtd_table[MAX_MTD_DEVICES];
+
+/******************************************************************************/
+
+/* 
+ * hardware specific access to control-lines
+ */
+static void stxxtc_hwcontrol(struct mtd_info *mtd, int cmd) 
+{
+	unsigned long flags;
+	
+	local_irq_save(flags);
+
+	switch (cmd) {
+
+		case NAND_CTL_SETNCE:
+			_PIN_LO(F_CE);
+			break;
+
+		case NAND_CTL_CLRNCE:
+			_PIN_HI(F_CE);
+			break;
+
+		case NAND_CTL_SETCLE:
+			_PIN_HI(F_CLE);
+			break;
+
+		case NAND_CTL_CLRCLE:
+			_PIN_LO(F_CLE);
+			break;
+
+		case NAND_CTL_SETALE:
+			_PIN_HI(F_ALE);
+			break;
+
+		case NAND_CTL_CLRALE:
+			_PIN_LO(F_ALE);
+			break;
+	}
+
+	local_irq_restore(flags);
+}
+
+/*
+ *	read device ready pin
+ */
+static int stxxtc_device_ready(struct mtd_info *mtd)
+{
+	return _PIN_GET(F_RY_BY);
+}
+
+/*
+ * Main initialization routine
+ */
+static int __init stxxtc_init(void)
+{
+	struct nand_chip *this = NULL;
+	int i, j, err = 0, rootidx;
+	const char *s, *rootmark="root=/dev/mtdblock";
+	unsigned int curroff, sz;
+	struct mtd_partition *part;
+	
+	/* Allocate memory for MTD device structure and private data */
+	stxxtc_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL);
+	if (!stxxtc_mtd) {
+		printk("Unable to allocate STXXTC NAND MTD device structure.\n");
+		err = -ENOMEM;
+		goto out;
+	}
+
+	/* map physical adress */
+	stxxtc_fio_base = (unsigned long)ioremap(NAND_BASE, NAND_SIZE);
+	if(!stxxtc_fio_base) {
+		printk("ioremap STXXTC NAND flash failed\n");
+		err = -EIO;
+		goto out;
+	}
+	
+	/* Get pointer to private data */
+	this = (struct nand_chip *)&stxxtc_mtd[1];
+	
+	/* Initialize structures */
+	memset((char *) stxxtc_mtd, 0, sizeof(struct mtd_info));
+	memset((char *) this, 0, sizeof(struct nand_chip));
+	
+	/* Link the private data with the MTD structure */
+	stxxtc_mtd->priv = this;
+	
+	/* insert callbacks */
+	this->IO_ADDR_R = (void __iomem *)stxxtc_fio_base;
+	this->IO_ADDR_W = (void __iomem *)stxxtc_fio_base;
+	this->hwcontrol = stxxtc_hwcontrol;
+	this->dev_ready = stxxtc_device_ready;
+	/* 15 us command delay time (XXX actually not used) */
+	this->chip_delay = 15;
+	/* TODO F_RY_BY pin is interrupt capable but it's not used as such */
+	this->eccmode = NAND_ECC_SOFT;
+	
+	/* Scan to find existence of the device (minimum size is 8MiB) */
+	if (nand_scan(stxxtc_mtd, 1) || stxxtc_mtd->size < 8 * 1024 * 1024) {
+		err = -ENXIO;
+		goto out;
+	}
+
+	/* Set internal data buffer */
+	this->data_buf = kmalloc(stxxtc_mtd->oobblock + stxxtc_mtd->oobsize, GFP_KERNEL);
+	if (this->data_buf == NULL) {
+		printk(KERN_ERR "stxxtc_nand: Unable to allocate data buffer\n");
+		err = -ENOMEM;
+		goto out;
+	}
+
+
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+	stxxtc_mtd->name = "stxxtc-nand";
+	mtd_parts_nb = parse_mtd_partitions(stxxtc_mtd, part_probes, &mtd_parts, 0);
+	if (mtd_parts_nb > 0)
+		part_type = "command line";
+	else
+		mtd_parts_nb = 0;
+#endif
+	if (mtd_parts_nb == 0) {
+
+		mtd_parts_nb = 3;
+
+		mtd_parts = kmalloc(sizeof(*mtd_parts) * mtd_parts_nb, GFP_KERNEL);
+		if (mtd_parts == NULL) {
+			printk(KERN_ERR "stxxtc_nand: Unable to allocate partition table buffer\n");
+			err = -ENOMEM;
+			goto out;
+		}
+		memset(mtd_parts, 0, sizeof(*mtd_parts) * mtd_parts_nb);
+
+		part = mtd_parts;
+
+		curroff = 0;
+
+		sz = (stxxtc_mtd->size - 512 * 1024) / 2;
+
+		part->name	= "STXXTC_root_fs_#1";
+		part->offset	= curroff;
+		part->size	= sz;
+		/* part->mask_flags= MTD_WRITEABLE; */
+		part++;
+		curroff += sz;
+
+		part->name	= "STXXTC_root_fs_#2";
+		part->offset	= curroff;
+		part->size	= sz;
+		part++;
+		curroff += sz;
+
+		part->name	= "Persistent_storage";
+		part->offset	= curroff;
+		part->size	= stxxtc_mtd->size - curroff;
+		part++;
+
+		part_type = "static";
+	}
+
+	/* lookup index of root MTD partition (if any) */
+	if ((s = strstr(saved_command_line, rootmark)) != NULL) {
+
+		rootidx = simple_strtoul(s + strlen(rootmark), NULL, 10);
+
+		/* XXX we assume that no-one will interrupts afterwards */
+		down(&mtd_table_mutex);
+		for (i = 0, j = 0; i < MAX_MTD_DEVICES; i++) {
+
+			if (mtd_table[i] != NULL)
+				continue;
+
+			if (i == rootidx) {
+				printk(KERN_INFO "stxxtc_nand: Marking root device mtd%d as read-only (%d)\n", i, j);
+				mtd_parts[j].mask_flags = MTD_WRITEABLE;
+				break;
+			}
+
+			if (++j >= mtd_parts_nb)
+				break;
+		}
+		up(&mtd_table_mutex);
+
+	}
+
+	/* Register the partitions */
+	printk(KERN_NOTICE "Using %s partition definition\n", part_type);
+	err = add_mtd_partitions(stxxtc_mtd, mtd_parts, mtd_parts_nb);
+	if (err != 0) {
+		printk(KERN_ERR "stxxtc_nand: Unable to add mtd partitions\n");
+		goto out;
+	}
+
+	kfree(mtd_parts);
+	mtd_parts = NULL;
+
+	return 0;
+
+out:
+	if (mtd_parts)
+		kfree(mtd_parts);
+	if (stxxtc_fio_base)
+		iounmap((void *)stxxtc_fio_base);
+	if (this && this->data_buf)
+		kfree(this->data_buf);
+	if (stxxtc_mtd)
+		kfree(stxxtc_mtd);
+	return err;
+}
+
+/*
+ * Clean up routine
+ */
+static void __exit stxxtc_cleanup(void)
+{
+	struct nand_chip *this = (struct nand_chip *) &stxxtc_mtd[1];
+
+	/* Unregister the device */
+	del_mtd_device(stxxtc_mtd);
+	
+	/* unmap */
+	iounmap((void *)stxxtc_fio_base);
+
+	/* free data buffer */
+	kfree(this->data_buf);
+
+	/* Free the MTD device structure */
+	kfree(stxxtc_mtd);
+}
+
+module_init(stxxtc_init);
+module_exit(stxxtc_cleanup);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Pantelis Antoniou <pantelis.antoniou at gmail.com>");
+MODULE_DESCRIPTION("MTD map driver for STXXTC");
+
+




More information about the linux-mtd mailing list