summaryrefslogtreecommitdiffstats
path: root/meta/packages/linux/linux-cmx270-2.6.17/mtd_fixes-r0.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta/packages/linux/linux-cmx270-2.6.17/mtd_fixes-r0.patch')
-rw-r--r--meta/packages/linux/linux-cmx270-2.6.17/mtd_fixes-r0.patch599
1 files changed, 599 insertions, 0 deletions
diff --git a/meta/packages/linux/linux-cmx270-2.6.17/mtd_fixes-r0.patch b/meta/packages/linux/linux-cmx270-2.6.17/mtd_fixes-r0.patch
new file mode 100644
index 0000000000..d77e9d8fbd
--- /dev/null
+++ b/meta/packages/linux/linux-cmx270-2.6.17/mtd_fixes-r0.patch
@@ -0,0 +1,599 @@
+Index: linux-2.6.17/drivers/mtd/nand/cm-x270.c
+===================================================================
+--- linux-2.6.17.orig/drivers/mtd/nand/cm-x270.c 2006-07-18 15:40:10.000000000 +0100
++++ linux-2.6.17/drivers/mtd/nand/cm-x270.c 2006-07-19 15:35:18.000000000 +0100
+@@ -1,7 +1,13 @@
+ /*
+- * drivers/mtd/nand/cm-x270.c
++ * linux/drivers/mtd/nand/cmx270-nand.c
++ *
++ * Copyright (C) 2006 Compulab, Ltd.
++ * Mike Rapoport <mike@compulab.co.il>
++ *
++ * Derived from drivers/mtd/nand/h1910.c
++ * Copyright (C) 2002 Marius Gröger (mag@sysgo.de)
++ * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de)
+ *
+- * Copyright (c) 2006, 8D Technologies inc.
+ *
+ * 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
+@@ -9,397 +15,269 @@
+ *
+ * Overview:
+ * This is a device driver for the NAND flash device found on the
+- * cm-x270 compulab SBC.
+- *
+- * Changelog:
+- * - April 2006, Raphael Assenat <raph@8d.com>:
+- * Creation of the driver.
++ * CM-X270 board.
+ */
+
+-#include <linux/delay.h>
++#include <linux/slab.h>
++#include <linux/init.h>
++#include <linux/module.h>
+ #include <linux/mtd/mtd.h>
+ #include <linux/mtd/nand.h>
+ #include <linux/mtd/partitions.h>
+-#include <asm/hardware.h>
++
+ #include <asm/io.h>
++#include <asm/irq.h>
++
++#include <asm/arch/hardware.h>
+ #include <asm/arch/pxa-regs.h>
+-#include <asm/arch/cm-x270.h>
+
++#define GPIO_NAND_CS (11)
++#define GPIO_NAND_RB (89)
+
+-static struct mtd_info *cmx270_mtd = NULL;
+-static void *cmx270_nand_io_base;
+-#define OFFSET_BASE 0
+-#define OFFSET_CLE 4
+-#define OFFSET_ALE 8
+-
+-#define DEFAULT_NUM_PARTITIONS 1
+-static int nr_partitions;
+-static struct mtd_partition cmx270_default_partition_info[] = {
+- {
+- .name = "rootfs",
+- .offset = 0,
+- .size = MTDPART_SIZ_FULL,
+- },
+-};
++/* This macro needed to ensure in-order operation of GPIO and local
++ * bus. Without both asm command and dummy uncached read there're
++ * states when NAND access is broken. I've looked for such macro(s) in
++ * include/asm-arm but found nothing approptiate.
++ * dmac_clean_range is close, but is makes cache invalidation
++ * unnecessary here and it cannot be used in module
++ */
++#define DRAIN_WB() \
++ do { \
++ unsigned char dummy; \
++ asm volatile ("mcr p15, 0, r0, c7, c10, 4":::"r0"); \
++ dummy=*((unsigned char*)UNCACHED_ADDR); \
++ } while(0)
+
+-static void cmx270_nand_hwcontrol(struct mtd_info *mtd, int cmd)
+-{
+- udelay(1);
+- switch(cmd)
++/* MTD structure for CM-X270 board */
++static struct mtd_info *cmx270_nand_mtd;
++
++/* remaped IO address of the device */
++static void __iomem *cmx270_nand_io;
++
++/*
++ * Define static partitions for flash device
++ */
++static struct mtd_partition partition_info[] = {
+ {
+- case NAND_CTL_SETNCE:
+- GPCR(CM_X270_GPIO_NAND_CS) = GPIO_bit(CM_X270_GPIO_NAND_CS);
+- break;
+- case NAND_CTL_CLRNCE:
+- GPSR(CM_X270_GPIO_NAND_CS) = GPIO_bit(CM_X270_GPIO_NAND_CS);
+- break;
++ .name = "cmx270-0",
++ .offset = 0,
++ .size = MTDPART_SIZ_FULL
+ }
+- udelay(1);
+-}
+-
+-static int cmx270_nand_device_ready(struct mtd_info *mtd)
+-{
+- /* I was getting ecc errors on reads, but adding this delay
+- made the problem disappear. There is probably a timing
+- issue somewhere. */
+- //ndelay (500);
+- udelay (25);
++};
++#define NUM_PARTITIONS (ARRAY_SIZE(partition_info))
+
+- return GPLR(CM_X270_GPIO_NAND_RB) & GPIO_bit(CM_X270_GPIO_NAND_RB);
+-}
++const char *part_probes[] = { "cmdlinepart", NULL };
+
+-static u_char cmx270_nand_read_byte(struct mtd_info *mtd)
++static u_char cmx270_read_byte(struct mtd_info *mtd)
+ {
+ struct nand_chip *this = mtd->priv;
+-// unsigned long raw = readl(this->IO_ADDR_R);
+- unsigned char res = ( readl(this->IO_ADDR_R) >> 16 ) & 0xff;
+- return res;
+-}
+
+-static void cmx270_nand_write_byte(struct mtd_info *mtd, u_char byte)
+-{
+- struct nand_chip *this = mtd->priv;
+- writel( (byte<<16), this->IO_ADDR_W );
+- udelay(1);
++ return (readl(this->IO_ADDR_R) >> 16);
+ }
+
+-static void cmx270_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
++static void cmx270_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
+ {
+ int i;
+ struct nand_chip *this = mtd->priv;
+
+ for (i=0; i<len; i++)
+- writel((buf[i]<<16), this->IO_ADDR_W);
+- udelay(1);
++ writel((*buf++ << 16), this->IO_ADDR_W);
+ }
+
+-static void cmx270_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
++static void cmx270_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+ {
+ int i;
+ struct nand_chip *this = mtd->priv;
+
+ for (i=0; i<len; i++)
+- buf[i] = (readl(this->IO_ADDR_R) >> 16 ) & 0xff;
+- udelay(1);
++ *buf++ = readl(this->IO_ADDR_R) >> 16;
+ }
+
+-static int cmx270_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
++static int cmx270_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
+ {
+ int i;
+ struct nand_chip *this = mtd->priv;
+
+ for (i=0; i<len; i++)
+- if (buf[i] != ((readl(this->IO_ADDR_R) >> 16) & 0xff))
++ if (buf[i] != (u_char)(readl(this->IO_ADDR_R) >> 16))
+ return -EFAULT;
+- udelay(1);
+
+ return 0;
+ }
+
+-static void cmx270_nand_write_ALE(struct mtd_info *mtd, const u_char byte)
++static inline void nand_cs_on(void)
+ {
+- struct nand_chip *this = mtd->priv;
+- writel( byte << 16 , this->IO_ADDR_W + OFFSET_ALE);
+- udelay(1);
++ GPCR(GPIO_NAND_CS) = GPIO_bit(GPIO_NAND_CS);
+ }
+
+-static void cmx270_nand_write_CLE(struct mtd_info *mtd, const u_char byte)
++static void nand_cs_off(void)
+ {
+- struct nand_chip *this = mtd->priv;
+- writel( byte << 16 , this->IO_ADDR_W + OFFSET_CLE);
+- udelay(1);
++ DRAIN_WB();
++
++ GPSR(GPIO_NAND_CS) = GPIO_bit(GPIO_NAND_CS);
+ }
+
+-/* Same as nand_core:nand_command() but with different memory
+- * addresses for writing to ALE and CLE and without 16 bit support.
++/*
++ * hardware specific access to control-lines
+ */
+-static void cmx270_nand_command(struct mtd_info *mtd, unsigned command, int column, int page_addr)
++static void cmx270_hwcontrol(struct mtd_info *mtd, int cmd)
+ {
+- register struct nand_chip *this = mtd->priv;
++ struct nand_chip* this = (struct nand_chip *) (mtd->priv);
++ unsigned int nandaddr = (unsigned int)this->IO_ADDR_R;
+
+-// printk("cmd: 0x%02x col: 0x%x page_addr: 0x%x\n",
+-// command, column, page_addr);
+-
+- if (command == NAND_CMD_SEQIN) {
+- int readcmd;
+-
+- if (column >= mtd->oobblock) {
+- /* OOB area */
+- column -= mtd->oobblock;
+- readcmd = NAND_CMD_READOOB;
+- } else if (column < 256) {
+- /* First 256 bytes --> READ0 */
+- readcmd = NAND_CMD_READ0;
+- } else {
+- column -= 256;
+- readcmd = NAND_CMD_READ1;
+- }
+- cmx270_nand_write_CLE(mtd, readcmd);
+- }
+- cmx270_nand_write_CLE(mtd, command);
++ DRAIN_WB();
+
+- if (column != -1 || page_addr != -1) {
+-
+- /* Serially input address */
+- if (column != -1) {
+- cmx270_nand_write_ALE(mtd, column);
+- }
+- if (page_addr != -1) {
+- cmx270_nand_write_ALE(mtd, (unsigned char) (page_addr & 0xff));
+- cmx270_nand_write_ALE(mtd, (unsigned char) ((page_addr >> 8) & 0xff));
+- /* One more address cycle for devices > 32MiB */
+- if (this->chipsize > (32 << 20))
+- cmx270_nand_write_ALE(mtd, (unsigned char) ((page_addr >> 16) & 0x0f));
+- }
+- }
++ switch(cmd) {
+
+- /*
+- * program and erase have their own busy handlers
+- * status and sequential in needs no delay
+- */
+- switch (command) {
+-
+- case NAND_CMD_PAGEPROG:
+- case NAND_CMD_ERASE1:
+- case NAND_CMD_ERASE2:
+- case NAND_CMD_SEQIN:
+- case NAND_CMD_STATUS:
+- return;
+-
+- case NAND_CMD_RESET:
+- if (this->dev_ready)
+- break;
+- udelay(this->chip_delay);
+- cmx270_nand_write_CLE(mtd, NAND_CMD_STATUS);
+- while ( !(this->read_byte(mtd) & 0x40));
+- return;
+-
+- /* This applies to read commands */
+- default:
+- /*
+- * If we don't have access to the busy pin, we apply the given
+- * command delay
+- */
+- if (!this->dev_ready) {
+- udelay(this->chip_delay);
+- return;
+- }
+- }
+-
+- /* Apply this short delay always to ensure that we do wait tWB in
+- * any case on any machine. */
+- ndelay (100);
+- /* wait until command is processed */
+- while (!this->dev_ready(mtd));
+- ndelay (100);
++ case NAND_CTL_SETCLE:
++ nandaddr |= (1 << 2);
++ this->IO_ADDR_R = (void __iomem*)nandaddr;
++ this->IO_ADDR_W = (void __iomem*)nandaddr;
++ break;
++ case NAND_CTL_CLRCLE:
++ nandaddr &= ~(1 << 2);
++ this->IO_ADDR_R = (void __iomem*)nandaddr;
++ this->IO_ADDR_W = (void __iomem*)nandaddr;
++ break;
++
++ case NAND_CTL_SETALE:
++ nandaddr |= (1 << 3);
++ this->IO_ADDR_R = (void __iomem*)nandaddr;
++ this->IO_ADDR_W = (void __iomem*)nandaddr;
++ break;
++ case NAND_CTL_CLRALE:
++ nandaddr &= ~(1 << 3);
++ this->IO_ADDR_R = (void __iomem*)nandaddr;
++ this->IO_ADDR_W = (void __iomem*)nandaddr;
++ break;
++
++ case NAND_CTL_SETNCE:
++ nand_cs_on();
++ break;
++ case NAND_CTL_CLRNCE:
++ nand_cs_off();
++ break;
++ }
++
++ DRAIN_WB();
+ }
+
+-/* Same as nand_core:nand_command_lp() but with different memory
+- * addresses for writing to ALE and CLE and without 16 bit support.
++
++/*
++ * read device ready pin
+ */
+-static void cmx270_nand_command_lp (struct mtd_info *mtd, unsigned command, int column, int page_addr)
++static int cmx270_device_ready(struct mtd_info *mtd)
+ {
+- register struct nand_chip *this = mtd->priv;
+-
+- /* Emulate NAND_CMD_READOOB */
+- if (command == NAND_CMD_READOOB) {
+- column += mtd->oobblock;
+- command = NAND_CMD_READ0;
+-// printk("Read OOB: column: $%x, page: $%x\n", column, page_addr);
+- }
+-
+- /* Write out the command to the device. */
+- cmx270_nand_write_CLE(mtd, command);
+-
+- if (column != -1 || page_addr != -1) {
+-
+- /* Serially input address */
+- if (column != -1) {
+- cmx270_nand_write_ALE(mtd, column & 0xff);
+- cmx270_nand_write_ALE(mtd, column >> 8);
+- if ((column >> 8) > 0xf) {
+- printk("out of range column\n");
+- }
+- }
+- if (page_addr != -1) {
+- cmx270_nand_write_ALE(mtd, (unsigned char) (page_addr & 0xff));
+- cmx270_nand_write_ALE(mtd, (unsigned char) ((page_addr >> 8) & 0xff));
+- /* One more address cycle for devices > 128MiB */
+- if (this->chipsize > (128 << 20)) {
+- cmx270_nand_write_ALE(mtd, (unsigned char) ((page_addr >> 16) & 0xff));
+- }
+- }
+- }
++ DRAIN_WB();
+
+- udelay(1);
+-
+- /*
+- * program and erase have their own busy handlers
+- * status and sequential in needs no delay
+- */
+- switch (command) {
+-
+- case NAND_CMD_CACHEDPROG:
+- case NAND_CMD_PAGEPROG:
+- case NAND_CMD_ERASE1:
+- case NAND_CMD_ERASE2:
+- case NAND_CMD_SEQIN:
+- case NAND_CMD_STATUS:
+- case NAND_CMD_DEPLETE1:
+- return;
+-
+- /*
+- * read error status commands require only a short delay
+- */
+- case NAND_CMD_STATUS_ERROR:
+- case NAND_CMD_STATUS_ERROR0:
+- case NAND_CMD_STATUS_ERROR1:
+- case NAND_CMD_STATUS_ERROR2:
+- case NAND_CMD_STATUS_ERROR3:
+- udelay(this->chip_delay);
+- return;
+-
+- case NAND_CMD_RESET:
+- if (this->dev_ready)
+- break;
+- udelay(this->chip_delay);
+- cmx270_nand_write_CLE(mtd, NAND_CMD_STATUS);
+- while ( !(this->read_byte(mtd) & NAND_STATUS_READY));
+- return;
+-
+- case NAND_CMD_READ0:
+- /* Write out the start read command */
+- cmx270_nand_write_CLE(mtd, NAND_CMD_READSTART);
+- /* Fall through into ready check */
+-
+- /* This applies to read commands */
+- default:
+- /*
+- * If we don't have access to the busy pin, we apply the given
+- * command delay
+- */
+- if (!this->dev_ready) {
+- udelay (this->chip_delay);
+- return;
+- }
+- }
+-
+- /* Apply this short delay always to ensure that we do wait tWB in
+- * any case on any machine. */
+- ndelay (100);
+- /* wait until command is processed */
+- while (!this->dev_ready(mtd));
++ return (GPLR(GPIO_NAND_RB) & GPIO_bit(GPIO_NAND_RB));
+ }
+
+-
+-#ifdef CONFIG_MTD_PARTITIONS
+-const char *part_probes[] = { "cmdlinepart", NULL };
+-#endif
+-
+-int __init cmx270_nand_init(void)
++/*
++ * Main initialization routine
++ */
++static int __devinit cmx270_init(void)
+ {
+ struct nand_chip *this;
+- struct mtd_partition* cmx270_partition_info;
+- int err = 0;
+-
+- pxa_gpio_mode(CM_X270_GPIO_NAND_RB);
++ const char *part_type;
++ struct mtd_partition *mtd_parts;
++ int mtd_parts_nb = 0;
++ int ret;
+
+- GPSR(CM_X270_GPIO_NAND_CS) = GPIO_bit(CM_X270_GPIO_NAND_CS);
+- pxa_gpio_mode(CM_X270_GPIO_NAND_CS | GPIO_OUT);
+-
+ /* Allocate memory for MTD device structure and private data */
+- cmx270_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip),
+- GFP_KERNEL);
+- if (!cmx270_mtd) {
+- printk(KERN_WARNING "Unable to allocate cm-x270 NAND mtd device structure.\n");
+- err = -ENOMEM;
+- goto out;
++ cmx270_nand_mtd = kzalloc(sizeof(struct mtd_info) +
++ sizeof(struct nand_chip),
++ GFP_KERNEL);
++ if (!cmx270_nand_mtd) {
++ printk("Unable to allocate CM-X270 NAND MTD device structure.\n");
++ return -ENOMEM;
+ }
+
+- /* map physical address */
+- cmx270_nand_io_base = ioremap(CM_X270_NAND_PHYS, 0x100);
+- if (!cmx270_nand_io_base) {
+- err = -EIO;
+- goto out_mtd;
++ cmx270_nand_io = ioremap(PXA_CS1_PHYS, 12);
++ if (!cmx270_nand_io) {
++ printk("Unable to ioremap NAND device\n");
++ ret = -EINVAL;
++ goto err1;
+ }
+
+ /* Get pointer to private data */
+- this = (struct nand_chip *)(&cmx270_mtd[1]);
+-
+- /* Initialize structures */
+- memset((char *) cmx270_mtd, 0, sizeof(struct mtd_info));
+- memset((char *) this, 0, sizeof(struct nand_chip));
++ this = (struct nand_chip *)(&cmx270_nand_mtd[1]);
+
+ /* Link the private data with the MTD structure */
+- cmx270_mtd->priv = this;
++ cmx270_nand_mtd->owner = THIS_MODULE;
++ cmx270_nand_mtd->priv = this;
+
+- this->IO_ADDR_R = cmx270_nand_io_base;
+- this->IO_ADDR_W = cmx270_nand_io_base;
+- this->read_byte = cmx270_nand_read_byte;
+- this->write_byte = cmx270_nand_write_byte;
+- this->write_buf = cmx270_nand_write_buf;
+- this->read_buf = cmx270_nand_read_buf;
+- this->verify_buf = cmx270_nand_verify_buf;
+- this->hwcontrol = cmx270_nand_hwcontrol;
+- this->dev_ready = cmx270_nand_device_ready;
+- this->cmdfunc = cmx270_nand_command_lp;
+- this->chip_delay = 25;
++ /* insert callbacks */
++ this->IO_ADDR_R = cmx270_nand_io;
++ this->IO_ADDR_W = cmx270_nand_io;
++ this->hwcontrol = cmx270_hwcontrol;
++ this->dev_ready = cmx270_device_ready;
++
++ /* 15 us command delay time */
++ this->chip_delay = 20;
+ this->eccmode = NAND_ECC_SOFT;
+
+- /* Scan to find existance of the device */
+- if (nand_scan(cmx270_mtd, 1)) {
+- err = -ENXIO;
+- goto out_ior;
++ /* read/write functions */
++ this->read_byte = cmx270_read_byte;
++ this->read_buf = cmx270_read_buf;
++ this->write_buf = cmx270_write_buf;
++ this->verify_buf = cmx270_verify_buf;
++
++ /* Scan to find existence of the device */
++ if (nand_scan (cmx270_nand_mtd, 1)) {
++ printk(KERN_NOTICE "No NAND device\n");
++ ret = -ENXIO;
++ goto err2;
++ }
++
++#ifdef CONFIG_MTD_CMDLINE_PARTS
++ mtd_parts_nb = parse_mtd_partitions(cmx270_nand_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) {
++ mtd_parts = partition_info;
++ mtd_parts_nb = NUM_PARTITIONS;
++ part_type = "static";
+ }
+
+ /* Register the partitions */
+- cmx270_mtd->name = "cmx270-mtd";
+- nr_partitions = parse_mtd_partitions(cmx270_mtd, part_probes, &cmx270_partition_info, 0);
+- if (nr_partitions <= 0) {
+- nr_partitions = DEFAULT_NUM_PARTITIONS;
+- cmx270_partition_info = cmx270_default_partition_info;
+- }
++ printk(KERN_NOTICE "Using %s partition definition\n", part_type);
++ ret = add_mtd_partitions(cmx270_nand_mtd, mtd_parts, mtd_parts_nb);
++ if (ret)
++ goto err2;
++
++ /* Return happy */
++ return 0;
++
++err2:
++ iounmap(cmx270_nand_io);
++err1:
++ kfree(cmx270_nand_mtd);
++
++ return ret;
+
+- add_mtd_partitions(cmx270_mtd, cmx270_partition_info, nr_partitions);
+-
+- goto out;
+-
+-out_ior:
+- iounmap((void*) cmx270_nand_io_base);
+-out_mtd:
+- kfree(cmx270_mtd);
+-out:
+- return err;
+ }
+-module_init(cmx270_nand_init);
++module_init(cmx270_init);
+
+-static void __exit cmx270_nand_cleanup(void)
++/*
++ * Clean up routine
++ */
++static void __devexit cmx270_cleanup(void)
+ {
+- nand_release(cmx270_mtd);
+- kfree(cmx270_mtd);
++ /* Release resources, unregister device */
++ nand_release(cmx270_nand_mtd);
++
++ iounmap(cmx270_nand_io);
++
++ /* Free the MTD device structure */
++ kfree (cmx270_nand_mtd);
+ }
++module_exit(cmx270_cleanup);
+
+ MODULE_LICENSE("GPL");
+-MODULE_AUTHOR("Raphael Assenat <raph@8d.com>");
+-MODULE_DESCRIPTION("NAND flash driver for cm-x270 boards");
+-
++MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>");
++MODULE_DESCRIPTION("NAND flash driver for Compulab CM-X270 Module");