[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