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 + * + * 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 : - * Creation of the driver. + * CM-X270 board. */ -#include +#include +#include +#include #include #include #include -#include + #include +#include + +#include #include -#include +#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; iIO_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; iIO_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; iIO_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 "); -MODULE_DESCRIPTION("NAND flash driver for cm-x270 boards"); - +MODULE_AUTHOR("Mike Rapoport "); +MODULE_DESCRIPTION("NAND flash driver for Compulab CM-X270 Module");