diff options
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.patch | 599 |
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"); |