diff options
Diffstat (limited to 'drivers/mtd/nand')
-rw-r--r-- | drivers/mtd/nand/Kconfig | 4 | ||||
-rw-r--r-- | drivers/mtd/nand/ams-delta.c | 57 | ||||
-rw-r--r-- | drivers/mtd/nand/au1550nd.c | 56 | ||||
-rw-r--r-- | drivers/mtd/nand/autcpu12.c | 77 | ||||
-rw-r--r-- | drivers/mtd/nand/cs553x_nand.c | 33 | ||||
-rw-r--r-- | drivers/mtd/nand/diskonchip.c | 86 | ||||
-rw-r--r-- | drivers/mtd/nand/edb7312.c | 42 | ||||
-rw-r--r-- | drivers/mtd/nand/h1910.c | 40 | ||||
-rw-r--r-- | drivers/mtd/nand/nand_base.c | 480 | ||||
-rw-r--r-- | drivers/mtd/nand/nand_bbt.c | 104 | ||||
-rw-r--r-- | drivers/mtd/nand/nandsim.c | 89 | ||||
-rw-r--r-- | drivers/mtd/nand/ndfc.c | 23 | ||||
-rw-r--r-- | drivers/mtd/nand/ppchameleonevb.c | 102 | ||||
-rw-r--r-- | drivers/mtd/nand/rtc_from4.c | 34 | ||||
-rw-r--r-- | drivers/mtd/nand/s3c2410.c | 64 | ||||
-rw-r--r-- | drivers/mtd/nand/sharpsl.c | 41 | ||||
-rw-r--r-- | drivers/mtd/nand/spia.c | 27 | ||||
-rw-r--r-- | drivers/mtd/nand/toto.c | 65 | ||||
-rw-r--r-- | drivers/mtd/nand/ts7250.c | 44 |
19 files changed, 557 insertions, 911 deletions
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index c2cb87fc4cb8..f24408d92688 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -65,7 +65,7 @@ config MTD_NAND_AMS_DELTA config MTD_NAND_TOTO tristate "NAND Flash device on TOTO board" - depends on ARCH_OMAP && MTD_NAND + depends on ARCH_OMAP && MTD_NAND && BROKEN help Support for NAND flash on Texas Instruments Toto platform. @@ -96,7 +96,7 @@ config MTD_NAND_RTC_FROM4 config MTD_NAND_PPCHAMELEONEVB tristate "NAND Flash device on PPChameleonEVB board" - depends on PPCHAMELEONEVB && MTD_NAND + depends on PPCHAMELEONEVB && MTD_NAND && BROKEN help This enables the NAND flash driver on the PPChameleon EVB Board. diff --git a/drivers/mtd/nand/ams-delta.c b/drivers/mtd/nand/ams-delta.c index aeaf2dece095..d7897dc6b3c8 100644 --- a/drivers/mtd/nand/ams-delta.c +++ b/drivers/mtd/nand/ams-delta.c @@ -34,13 +34,6 @@ static struct mtd_info *ams_delta_mtd = NULL; #define NAND_MASK (AMS_DELTA_LATCH2_NAND_NRE | AMS_DELTA_LATCH2_NAND_NWE | AMS_DELTA_LATCH2_NAND_CLE | AMS_DELTA_LATCH2_NAND_ALE | AMS_DELTA_LATCH2_NAND_NCE | AMS_DELTA_LATCH2_NAND_NWP) -#define T_NAND_CTL_CLRALE(iob) ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_ALE, 0) -#define T_NAND_CTL_SETALE(iob) ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_ALE, AMS_DELTA_LATCH2_NAND_ALE) -#define T_NAND_CTL_CLRCLE(iob) ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_CLE, 0) -#define T_NAND_CTL_SETCLE(iob) ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_CLE, AMS_DELTA_LATCH2_NAND_CLE) -#define T_NAND_CTL_SETNCE(iob) ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NCE, 0) -#define T_NAND_CTL_CLRNCE(iob) ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NCE, AMS_DELTA_LATCH2_NAND_NCE) - /* * Define partitions for flash devices */ @@ -66,25 +59,6 @@ static struct mtd_partition partition_info[] = { .size = 3 * SZ_256K }, }; -/* - * hardware specific access to control-lines -*/ - -static void ams_delta_hwcontrol(struct mtd_info *mtd, int cmd) -{ - switch (cmd) { - - case NAND_CTL_SETCLE: T_NAND_CTL_SETCLE(cmd); break; - case NAND_CTL_CLRCLE: T_NAND_CTL_CLRCLE(cmd); break; - - case NAND_CTL_SETALE: T_NAND_CTL_SETALE(cmd); break; - case NAND_CTL_CLRALE: T_NAND_CTL_CLRALE(cmd); break; - - case NAND_CTL_SETNCE: T_NAND_CTL_SETNCE(cmd); break; - case NAND_CTL_CLRNCE: T_NAND_CTL_CLRNCE(cmd); break; - } -} - static void ams_delta_write_byte(struct mtd_info *mtd, u_char byte) { struct nand_chip *this = mtd->priv; @@ -141,6 +115,32 @@ static int ams_delta_verify_buf(struct mtd_info *mtd, const u_char *buf, return 0; } +/* + * Command control function + * + * ctrl: + * NAND_NCE: bit 0 -> bit 2 + * NAND_CLE: bit 1 -> bit 7 + * NAND_ALE: bit 2 -> bit 6 + */ +static void ams_delta_hwcontrol(struct mtd_info *mtd, int cmd, + unsigned int ctrl) +{ + + if (ctrl & NAND_CTRL_CHANGE) { + unsigned long bits; + + bits = (~ctrl & NAND_NCE) << 2; + bits |= (ctrl & NAND_CLE) << 7; + bits |= (ctrl & NAND_ALE) << 6; + + ams_delta_latch2_write(0xC2, bits); + } + + if (cmd != NAND_CMD_NONE) + ams_delta_write_byte(mtd, cmd); +} + static int ams_delta_nand_ready(struct mtd_info *mtd) { return omap_get_gpio_datain(AMS_DELTA_GPIO_PIN_NAND_RB); @@ -179,11 +179,10 @@ static int __init ams_delta_init(void) this->IO_ADDR_R = (OMAP_MPUIO_BASE + OMAP_MPUIO_INPUT_LATCH); this->IO_ADDR_W = (OMAP_MPUIO_BASE + OMAP_MPUIO_OUTPUT); this->read_byte = ams_delta_read_byte; - this->write_byte = ams_delta_write_byte; this->write_buf = ams_delta_write_buf; this->read_buf = ams_delta_read_buf; this->verify_buf = ams_delta_verify_buf; - this->hwcontrol = ams_delta_hwcontrol; + this->cmd_ctrl = ams_delta_hwcontrol; if (!omap_request_gpio(AMS_DELTA_GPIO_PIN_NAND_RB)) { this->dev_ready = ams_delta_nand_ready; } else { @@ -200,7 +199,7 @@ static int __init ams_delta_init(void) AMS_DELTA_LATCH2_NAND_NCE | AMS_DELTA_LATCH2_NAND_NWP); - /* Scan to find existance of the device */ + /* Scan to find existance of the device */ if (nand_scan(ams_delta_mtd, 1)) { err = -ENXIO; goto out_mtd; diff --git a/drivers/mtd/nand/au1550nd.c b/drivers/mtd/nand/au1550nd.c index 29dde7dcafa1..31228334da12 100644 --- a/drivers/mtd/nand/au1550nd.c +++ b/drivers/mtd/nand/au1550nd.c @@ -40,6 +40,7 @@ static struct mtd_info *au1550_mtd = NULL; static void __iomem *p_nand; static int nand_width = 1; /* default x8 */ +static void (*au1550_write_byte)(struct mtd_info *, u_char); /* * Define partitions for flash device @@ -129,21 +130,6 @@ static u16 au_read_word(struct mtd_info *mtd) } /** - * au_write_word - write one word to the chip - * @mtd: MTD device structure - * @word: data word to write - * - * write function for 16bit buswith without - * endianess conversion - */ -static void au_write_word(struct mtd_info *mtd, u16 word) -{ - struct nand_chip *this = mtd->priv; - writew(word, this->IO_ADDR_W); - au_sync(); -} - -/** * au_write_buf - write buffer to chip * @mtd: MTD device structure * @buf: data buffer @@ -269,6 +255,18 @@ static int au_verify_buf16(struct mtd_info *mtd, const u_char *buf, int len) return 0; } +/* Select the chip by setting nCE to low */ +#define NAND_CTL_SETNCE 1 +/* Deselect the chip by setting nCE to high */ +#define NAND_CTL_CLRNCE 2 +/* Select the command latch by setting CLE to high */ +#define NAND_CTL_SETCLE 3 +/* Deselect the command latch by setting CLE to low */ +#define NAND_CTL_CLRCLE 4 +/* Select the address latch by setting ALE to high */ +#define NAND_CTL_SETALE 5 +/* Deselect the address latch by setting ALE to low */ +#define NAND_CTL_CLRALE 6 static void au1550_hwcontrol(struct mtd_info *mtd, int cmd) { @@ -349,7 +347,7 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i ulong flags; /* Begin command latch cycle */ - this->hwcontrol(mtd, NAND_CTL_SETCLE); + au1550_hwcontrol(mtd, NAND_CTL_SETCLE); /* * Write out the command to the device. */ @@ -367,25 +365,25 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i column -= 256; readcmd = NAND_CMD_READ1; } - this->write_byte(mtd, readcmd); + au1550_write_byte(mtd, readcmd); } - this->write_byte(mtd, command); + au1550_write_byte(mtd, command); /* Set ALE and clear CLE to start address cycle */ - this->hwcontrol(mtd, NAND_CTL_CLRCLE); + au1550_hwcontrol(mtd, NAND_CTL_CLRCLE); if (column != -1 || page_addr != -1) { - this->hwcontrol(mtd, NAND_CTL_SETALE); + au1550_hwcontrol(mtd, NAND_CTL_SETALE); /* Serially input address */ if (column != -1) { /* Adjust columns for 16 bit buswidth */ if (this->options & NAND_BUSWIDTH_16) column >>= 1; - this->write_byte(mtd, column); + au1550_write_byte(mtd, column); } if (page_addr != -1) { - this->write_byte(mtd, (u8)(page_addr & 0xff)); + au1550_write_byte(mtd, (u8)(page_addr & 0xff)); if (command == NAND_CMD_READ0 || command == NAND_CMD_READ1 || @@ -400,17 +398,17 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i */ ce_override = 1; local_irq_save(flags); - this->hwcontrol(mtd, NAND_CTL_SETNCE); + au1550_hwcontrol(mtd, NAND_CTL_SETNCE); } - this->write_byte(mtd, (u8)(page_addr >> 8)); + au1550_write_byte(mtd, (u8)(page_addr >> 8)); /* One more address cycle for devices > 32MiB */ if (this->chipsize > (32 << 20)) - this->write_byte(mtd, (u8)((page_addr >> 16) & 0x0f)); + au1550_write_byte(mtd, (u8)((page_addr >> 16) & 0x0f)); } /* Latch in address */ - this->hwcontrol(mtd, NAND_CTL_CLRALE); + au1550_hwcontrol(mtd, NAND_CTL_CLRALE); } /* @@ -443,7 +441,7 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i udelay(1); /* Release -CE and re-enable interrupts. */ - this->hwcontrol(mtd, NAND_CTL_CLRNCE); + au1550_hwcontrol(mtd, NAND_CTL_CLRNCE); local_irq_restore(flags); return; } @@ -571,7 +569,6 @@ static int __init au1xxx_nand_init(void) nand_width = au_readl(MEM_STCFG3) & (1 << 22); /* Set address of hardware control function */ - this->hwcontrol = au1550_hwcontrol; this->dev_ready = au1550_device_ready; this->select_chip = au1550_select_chip; this->cmdfunc = au1550_command; @@ -586,8 +583,7 @@ static int __init au1xxx_nand_init(void) this->options |= NAND_BUSWIDTH_16; this->read_byte = (!nand_width) ? au_read_byte16 : au_read_byte; - this->write_byte = (!nand_width) ? au_write_byte16 : au_write_byte; - this->write_word = au_write_word; + au1550_write_byte = (!nand_width) ? au_write_byte16 : au_write_byte; this->read_word = au_read_word; this->write_buf = (!nand_width) ? au_write_buf16 : au_write_buf; this->read_buf = (!nand_width) ? au_read_buf16 : au_read_buf; diff --git a/drivers/mtd/nand/autcpu12.c b/drivers/mtd/nand/autcpu12.c index dbb1b6267ade..fe94ae9ae1f2 100644 --- a/drivers/mtd/nand/autcpu12.c +++ b/drivers/mtd/nand/autcpu12.c @@ -4,7 +4,7 @@ * Copyright (c) 2002 Thomas Gleixner <tgxl@linutronix.de> * * Derived from drivers/mtd/spia.c - * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) + * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) * * $Id: autcpu12.c,v 1.23 2005/11/07 11:14:30 gleixner Exp $ * @@ -42,11 +42,6 @@ * MTD structure for AUTCPU12 board */ static struct mtd_info *autcpu12_mtd = NULL; - -static int autcpu12_io_base = CS89712_VIRT_BASE; -static int autcpu12_fio_pbase = AUTCPU12_PHYS_SMC; -static int autcpu12_fio_ctrl = AUTCPU12_SMC_SELECT_OFFSET; -static int autcpu12_pedr = AUTCPU12_SMC_PORT_OFFSET; static void __iomem *autcpu12_fio_base; /* @@ -94,31 +89,42 @@ static struct mtd_partition partition_info128k[] = { #define NUM_PARTITIONS128K 2 /* * hardware specific access to control-lines -*/ - -static void autcpu12_hwcontrol(struct mtd_info *mtd, int cmd) + * + * ALE bit 4 autcpu12_pedr + * CLE bit 5 autcpu12_pedr + * NCE bit 0 fio_ctrl + * + */ +static void autcpu12_hwcontrol(struct mtd_info *mtd, int cmd, + unsigned int ctrl) { - switch (cmd) { + struct nand_chip *chip = mtd->priv; - case NAND_CTL_SETCLE: (*(volatile unsigned char *) (autcpu12_io_base + autcpu12_pedr)) |= AUTCPU12_SMC_CLE; break; - case NAND_CTL_CLRCLE: (*(volatile unsigned char *) (autcpu12_io_base + autcpu12_pedr)) &= ~AUTCPU12_SMC_CLE; break; + if (ctrl & NAND_CTRL_CHANGE) { + void __iomem *addr + unsigned char bits; - case NAND_CTL_SETALE: (*(volatile unsigned char *) (autcpu12_io_base + autcpu12_pedr)) |= AUTCPU12_SMC_ALE; break; - case NAND_CTL_CLRALE: (*(volatile unsigned char *) (autcpu12_io_base + autcpu12_pedr)) &= ~AUTCPU12_SMC_ALE; break; + addr = CS89712_VIRT_BASE + AUTCPU12_SMC_PORT_OFFSET; + bits = (ctrl & NAND_CLE) << 4; + bits |= (ctrl & NAND_ALE) << 2; + writeb((readb(addr) & ~0x30) | bits, addr); - case NAND_CTL_SETNCE: (*(volatile unsigned char *) (autcpu12_fio_base + autcpu12_fio_ctrl)) = 0x01; break; - case NAND_CTL_CLRNCE: (*(volatile unsigned char *) (autcpu12_fio_base + autcpu12_fio_ctrl)) = 0x00; break; + addr = autcpu12_fio_base + AUTCPU12_SMC_SELECT_OFFSET; + writeb((readb(addr) & ~0x1) | (ctrl & NAND_NCE), addr); } + + if (cmd != NAND_CMD_NONE) + writeb(cmd, chip->IO_ADDR_W); } /* -* read device ready pin -*/ + * read device ready pin + */ int autcpu12_device_ready(struct mtd_info *mtd) { + void __iomem *addr = CS89712_VIRT_BASE + AUTCPU12_SMC_PORT_OFFSET; - return ((*(volatile unsigned char *)(autcpu12_io_base + autcpu12_pedr)) & AUTCPU12_SMC_RDY) ? 1 : 0; - + return readb(addr) & AUTCPU12_SMC_RDY; } /* @@ -130,7 +136,8 @@ static int __init autcpu12_init(void) int err = 0; /* Allocate memory for MTD device structure and private data */ - autcpu12_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL); + autcpu12_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), + GFP_KERNEL); if (!autcpu12_mtd) { printk("Unable to allocate AUTCPU12 NAND MTD device structure.\n"); err = -ENOMEM; @@ -138,7 +145,7 @@ static int __init autcpu12_init(void) } /* map physical adress */ - autcpu12_fio_base = ioremap(autcpu12_fio_pbase, SZ_1K); + autcpu12_fio_base = ioremap(AUTCPU12_PHYS_SMC, SZ_1K); if (!autcpu12_fio_base) { printk("Ioremap autcpu12 SmartMedia Card failed\n"); err = -EIO; @@ -159,7 +166,7 @@ static int __init autcpu12_init(void) /* Set address of NAND IO lines */ this->IO_ADDR_R = autcpu12_fio_base; this->IO_ADDR_W = autcpu12_fio_base; - this->hwcontrol = autcpu12_hwcontrol; + this->cmd_ctrl = autcpu12_hwcontrol; this->dev_ready = autcpu12_device_ready; /* 20 us command delay time */ this->chip_delay = 20; @@ -179,10 +186,22 @@ static int __init autcpu12_init(void) /* Register the partitions */ switch (autcpu12_mtd->size) { - case SZ_16M: add_mtd_partitions(autcpu12_mtd, partition_info16k, NUM_PARTITIONS16K); break; - case SZ_32M: add_mtd_partitions(autcpu12_mtd, partition_info32k, NUM_PARTITIONS32K); break; - case SZ_64M: add_mtd_partitions(autcpu12_mtd, partition_info64k, NUM_PARTITIONS64K); break; - case SZ_128M: add_mtd_partitions(autcpu12_mtd, partition_info128k, NUM_PARTITIONS128K); break; + case SZ_16M: + add_mtd_partitions(autcpu12_mtd, partition_info16k, + NUM_PARTITIONS16K); + break; + case SZ_32M: + add_mtd_partitions(autcpu12_mtd, partition_info32k, + NUM_PARTITIONS32K); + break; + case SZ_64M: + add_mtd_partitions(autcpu12_mtd, partition_info64k, + NUM_PARTITIONS64K); + break; + case SZ_128M: + add_mtd_partitions(autcpu12_mtd, partition_info128k, + NUM_PARTITIONS128K); + break; default: printk("Unsupported SmartMedia device\n"); err = -ENXIO; @@ -191,7 +210,7 @@ static int __init autcpu12_init(void) goto out; out_ior: - iounmap((void *)autcpu12_fio_base); + iounmap(autcpu12_fio_base); out_mtd: kfree(autcpu12_mtd); out: @@ -209,7 +228,7 @@ static void __exit autcpu12_cleanup(void) nand_release(autcpu12_mtd); /* unmap physical adress */ - iounmap((void *)autcpu12_fio_base); + iounmap(autcpu12_fio_base); /* Free the MTD device structure */ kfree(autcpu12_mtd); diff --git a/drivers/mtd/nand/cs553x_nand.c b/drivers/mtd/nand/cs553x_nand.c index 064f3feadf53..1e0348ae325f 100644 --- a/drivers/mtd/nand/cs553x_nand.c +++ b/drivers/mtd/nand/cs553x_nand.c @@ -131,33 +131,17 @@ static void cs553x_write_byte(struct mtd_info *mtd, u_char byte) writeb(byte, this->IO_ADDR_W + 0x801); } -static void cs553x_hwcontrol(struct mtd_info *mtd, int cmd) +static void cs553x_hwcontrol(struct mtd_info *mtd, int cmd, + unsigned int ctrl) { struct nand_chip *this = mtd->priv; void __iomem *mmio_base = this->IO_ADDR_R; - unsigned char ctl; - - switch (cmd) { - case NAND_CTL_SETCLE: - ctl = CS_NAND_CTL_CLE; - break; - - case NAND_CTL_CLRCLE: - case NAND_CTL_CLRALE: - case NAND_CTL_SETNCE: - ctl = 0; - break; - - case NAND_CTL_SETALE: - ctl = CS_NAND_CTL_ALE; - break; - - default: - case NAND_CTL_CLRNCE: - ctl = CS_NAND_CTL_CE; - break; + if (ctrl & NAND_CTRL_CHANGE) { + unsigned char ctl = (ctrl & ~NAND_CTRL_CHANGE ) ^ 0x01; + writeb(ctl, mmio_base + MM_NAND_CTL); } - writeb(ctl, mmio_base + MM_NAND_CTL); + if (cmd != NAND_CMD_NONE) + cs553x_write_byte(mtd, cmd); } static int cs553x_device_ready(struct mtd_info *mtd) @@ -233,10 +217,9 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr) goto out_mtd; } - this->hwcontrol = cs553x_hwcontrol; + this->cmd_ctrl = cs553x_hwcontrol; this->dev_ready = cs553x_device_ready; this->read_byte = cs553x_read_byte; - this->write_byte = cs553x_write_byte; this->read_buf = cs553x_read_buf; this->write_buf = cs553x_write_buf; diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index b771608ef84e..2ec9080e2b14 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c @@ -95,7 +95,8 @@ static u_char empty_write_ecc[6] = { 0x4b, 0x00, 0xe2, 0x0e, 0x93, 0xf7 }; #define DoC_is_Millennium(doc) ((doc)->ChipID == DOC_ChipID_DocMil) #define DoC_is_2000(doc) ((doc)->ChipID == DOC_ChipID_Doc2k) -static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd); +static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd, + unsigned int bitmask); static void doc200x_select_chip(struct mtd_info *mtd, int chip); static int debug = 0; @@ -402,12 +403,10 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr) uint16_t ret; doc200x_select_chip(mtd, nr); - doc200x_hwcontrol(mtd, NAND_CTL_SETCLE); - this->write_byte(mtd, NAND_CMD_READID); - doc200x_hwcontrol(mtd, NAND_CTL_CLRCLE); - doc200x_hwcontrol(mtd, NAND_CTL_SETALE); - this->write_byte(mtd, 0); - doc200x_hwcontrol(mtd, NAND_CTL_CLRALE); + doc200x_hwcontrol(mtd, NAND_CMD_READID, + NAND_CTRL_CLE | NAND_CTRL_CHANGE); + doc200x_hwcontrol(mtd, 0, NAND_CTRL_ALE | NAND_CTRL_CHANGE); + doc200x_hwcontrol(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); /* We cant' use dev_ready here, but at least we wait for the * command to complete @@ -425,12 +424,11 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr) } ident; void __iomem *docptr = doc->virtadr; - doc200x_hwcontrol(mtd, NAND_CTL_SETCLE); - doc2000_write_byte(mtd, NAND_CMD_READID); - doc200x_hwcontrol(mtd, NAND_CTL_CLRCLE); - doc200x_hwcontrol(mtd, NAND_CTL_SETALE); - doc2000_write_byte(mtd, 0); - doc200x_hwcontrol(mtd, NAND_CTL_CLRALE); + doc200x_hwcontrol(mtd, NAND_CMD_READID, + NAND_CTRL_CLE | NAND_CTRL_CHANGE); + doc200x_hwcontrol(mtd, 0, NAND_CTRL_ALE | NAND_CTRL_CHANGE); + doc200x_hwcontrol(mtd, NAND_CMD_NONE, + NAND_NCE | NAND_CTRL_CHANGE); udelay(50); @@ -690,54 +688,41 @@ static void doc200x_select_chip(struct mtd_info *mtd, int chip) chip -= (floor * doc->chips_per_floor); /* 11.4.4 -- deassert CE before changing chip */ - doc200x_hwcontrol(mtd, NAND_CTL_CLRNCE); + doc200x_hwcontrol(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE); WriteDOC(floor, docptr, FloorSelect); WriteDOC(chip, docptr, CDSNDeviceSelect); - doc200x_hwcontrol(mtd, NAND_CTL_SETNCE); + doc200x_hwcontrol(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); doc->curchip = chip; doc->curfloor = floor; } -static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd) +#define CDSN_CTRL_MSK (CDSN_CTRL_CE | CDSN_CTRL_CLE | CDSN_CTRL_ALE) + +static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd, + unsigned int ctrl) { struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; void __iomem *docptr = doc->virtadr; - switch (cmd) { - case NAND_CTL_SETNCE: - doc->CDSNControl |= CDSN_CTRL_CE; - break; - case NAND_CTL_CLRNCE: - doc->CDSNControl &= ~CDSN_CTRL_CE; - break; - case NAND_CTL_SETCLE: - doc->CDSNControl |= CDSN_CTRL_CLE; - break; - case NAND_CTL_CLRCLE: - doc->CDSNControl &= ~CDSN_CTRL_CLE; - break; - case NAND_CTL_SETALE: - doc->CDSNControl |= CDSN_CTRL_ALE; - break; - case NAND_CTL_CLRALE: - doc->CDSNControl &= ~CDSN_CTRL_ALE; - break; - case NAND_CTL_SETWP: - doc->CDSNControl |= CDSN_CTRL_WP; - break; - case NAND_CTL_CLRWP: - doc->CDSNControl &= ~CDSN_CTRL_WP; - break; + if (ctrl & NAND_CTRL_CHANGE) { + doc->CDSNControl &= ~CDSN_CTRL_MSK; + doc->CDSNControl |= ctrl & CDSN_CTRL_MSK; + if (debug) + printk("hwcontrol(%d): %02x\n", cmd, doc->CDSNControl); + WriteDOC(doc->CDSNControl, docptr, CDSNControl); + /* 11.4.3 -- 4 NOPs after CSDNControl write */ + DoC_Delay(doc, 4); + } + if (cmd != NAND_CMD_NONE) { + if (DoC_is_2000(doc)) + doc2000_write_byte(mtd, cmd); + else + doc2001_write_byte(mtd, cmd); } - if (debug) - printk("hwcontrol(%d): %02x\n", cmd, doc->CDSNControl); - WriteDOC(doc->CDSNControl, docptr, CDSNControl); - /* 11.4.3 -- 4 NOPs after CSDNControl write */ - DoC_Delay(doc, 4); } static void doc2001plus_command(struct mtd_info *mtd, unsigned command, int column, int page_addr) @@ -1454,7 +1439,6 @@ static inline int __init doc2000_init(struct mtd_info *mtd) struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; - this->write_byte = doc2000_write_byte; this->read_byte = doc2000_read_byte; this->write_buf = doc2000_writebuf; this->read_buf = doc2000_readbuf; @@ -1472,7 +1456,6 @@ static inline int __init doc2001_init(struct mtd_info *mtd) struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; - this->write_byte = doc2001_write_byte; this->read_byte = doc2001_read_byte; this->write_buf = doc2001_writebuf; this->read_buf = doc2001_readbuf; @@ -1504,16 +1487,15 @@ static inline int __init doc2001plus_init(struct mtd_info *mtd) struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; - this->write_byte = NULL; this->read_byte = doc2001plus_read_byte; this->write_buf = doc2001plus_writebuf; this->read_buf = doc2001plus_readbuf; this->verify_buf = doc2001plus_verifybuf; this->scan_bbt = inftl_scan_bbt; - this->hwcontrol = NULL; + this->cmd_ctrl = NULL; this->select_chip = doc2001plus_select_chip; this->cmdfunc = doc2001plus_command; - this->enable_hwecc = doc2001plus_enable_hwecc; + this->ecc.hwctl = doc2001plus_enable_hwecc; doc->chips_per_floor = 1; mtd->name = "DiskOnChip Millennium Plus"; @@ -1670,7 +1652,7 @@ static int __init doc_probe(unsigned long physadr) nand->priv = doc; nand->select_chip = doc200x_select_chip; - nand->hwcontrol = doc200x_hwcontrol; + nand->cmd_ctrl = doc200x_hwcontrol; nand->dev_ready = doc200x_dev_ready; nand->waitfunc = doc200x_wait; nand->block_bad = doc200x_block_bad; diff --git a/drivers/mtd/nand/edb7312.c b/drivers/mtd/nand/edb7312.c index 8e56570af91f..ba5a2174a408 100644 --- a/drivers/mtd/nand/edb7312.c +++ b/drivers/mtd/nand/edb7312.c @@ -73,32 +73,26 @@ static struct mtd_partition partition_info[] = { /* * hardware specific access to control-lines + * + * NAND_NCE: bit 0 -> bit 7 + * NAND_CLE: bit 1 -> bit 4 + * NAND_ALE: bit 2 -> bit 5 */ -static void ep7312_hwcontrol(struct mtd_info *mtd, int cmd) +static void ep7312_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) { - switch (cmd) { - - case NAND_CTL_SETCLE: - clps_writeb(clps_readb(ep7312_pxdr) | 0x10, ep7312_pxdr); - break; - case NAND_CTL_CLRCLE: - clps_writeb(clps_readb(ep7312_pxdr) & ~0x10, ep7312_pxdr); - break; - - case NAND_CTL_SETALE: - clps_writeb(clps_readb(ep7312_pxdr) | 0x20, ep7312_pxdr); - break; - case NAND_CTL_CLRALE: - clps_writeb(clps_readb(ep7312_pxdr) & ~0x20, ep7312_pxdr); - break; - - case NAND_CTL_SETNCE: - clps_writeb((clps_readb(ep7312_pxdr) | 0x80) & ~0x40, ep7312_pxdr); - break; - case NAND_CTL_CLRNCE: - clps_writeb((clps_readb(ep7312_pxdr) | 0x80) | 0x40, ep7312_pxdr); - break; + struct nand_chip *chip = mtd->priv; + + if (ctrl & NAND_CTRL_CHANGE) { + unsigned char bits; + + bits = (ctrl & (NAND_CLE | NAND_ALE)) << 3; + bits = (ctrl & NAND_NCE) << 7; + + clps_writeb((clps_readb(ep7312_pxdr) & 0xB0) | 0x10, + ep7312_pxdr); } + if (cmd != NAND_CMD_NONE) + writeb(cmd, chip->IO_ADDR_W); } /* @@ -159,7 +153,7 @@ static int __init ep7312_init(void) /* insert callbacks */ this->IO_ADDR_R = ep7312_fio_base; this->IO_ADDR_W = ep7312_fio_base; - this->hwcontrol = ep7312_hwcontrol; + this->cmd_ctrl = ep7312_hwcontrol; this->dev_ready = ep7312_device_ready; /* 15 us command delay time */ this->chip_delay = 15; diff --git a/drivers/mtd/nand/h1910.c b/drivers/mtd/nand/h1910.c index 06e91fa11b34..2d585d2d090c 100644 --- a/drivers/mtd/nand/h1910.c +++ b/drivers/mtd/nand/h1910.c @@ -56,36 +56,18 @@ static struct mtd_partition partition_info[] = { /* * hardware specific access to control-lines + * + * NAND_NCE: bit 0 - don't care + * NAND_CLE: bit 1 - address bit 2 + * NAND_ALE: bit 2 - address bit 3 */ -static void h1910_hwcontrol(struct mtd_info *mtd, int cmd) +static void h1910_hwcontrol(struct mtd_info *mtd, int cmd, + unsigned int ctrl) { - struct nand_chip *this = (struct nand_chip *)(mtd->priv); - - switch (cmd) { - - case NAND_CTL_SETCLE: - this->IO_ADDR_R |= (1 << 2); - this->IO_ADDR_W |= (1 << 2); - break; - case NAND_CTL_CLRCLE: - this->IO_ADDR_R &= ~(1 << 2); - this->IO_ADDR_W &= ~(1 << 2); - break; - - case NAND_CTL_SETALE: - this->IO_ADDR_R |= (1 << 3); - this->IO_ADDR_W |= (1 << 3); - break; - case NAND_CTL_CLRALE: - this->IO_ADDR_R &= ~(1 << 3); - this->IO_ADDR_W &= ~(1 << 3); - break; - - case NAND_CTL_SETNCE: - break; - case NAND_CTL_CLRNCE: - break; - } + struct nand_chip *chip = mtd->priv; + + if (cmd != NAND_CMD_NONE) + writeb(cmd, chip->IO_ADDR_W | ((ctrl & 0x6) << 1)); } /* @@ -145,7 +127,7 @@ static int __init h1910_init(void) /* insert callbacks */ this->IO_ADDR_R = nandaddr; this->IO_ADDR_W = nandaddr; - this->hwcontrol = h1910_hwcontrol; + this->cmd_ctrl = h1910_hwcontrol; this->dev_ready = NULL; /* unknown whether that was correct or not so we will just do it like this */ /* 15 us command delay time */ this->chip_delay = 50; diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 778535006c83..649c238837bb 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -139,23 +139,12 @@ static int nand_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len); static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, uint8_t *buf); -static int nand_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, uint8_t *buf, uint8_t *eccbuf, - struct nand_oobinfo *oobsel); static int nand_read_oob(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, uint8_t *buf); static int nand_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const uint8_t *buf); -static int nand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, - size_t *retlen, const uint8_t *buf, uint8_t *eccbuf, - struct nand_oobinfo *oobsel); static int nand_write_oob(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const uint8_t *buf); -static int nand_writev(struct mtd_info *mtd, const struct kvec *vecs, - unsigned long count, loff_t to, size_t *retlen); -static int nand_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs, - unsigned long count, loff_t to, size_t *retlen, - uint8_t *eccbuf, struct nand_oobinfo *oobsel); static int nand_erase(struct mtd_info *mtd, struct erase_info *instr); static void nand_sync(struct mtd_info *mtd); @@ -175,6 +164,12 @@ static int nand_verify_pages(struct mtd_info *mtd, struct nand_chip *this, static int nand_get_device(struct nand_chip *this, struct mtd_info *mtd, int new_state); +/* + * For devices which display every fart in the system on a seperate LED. Is + * compiled away when LED support is disabled. + */ +DEFINE_LED_TRIGGER(nand_led_trigger); + /** * nand_release_device - [GENERIC] release chip * @mtd: MTD device structure @@ -209,19 +204,6 @@ static uint8_t nand_read_byte(struct mtd_info *mtd) } /** - * nand_write_byte - [DEFAULT] write one byte to the chip - * @mtd: MTD device structure - * @byte: pointer to data byte to write - * - * Default write function for 8it buswith - */ -static void nand_write_byte(struct mtd_info *mtd, uint8_t byte) -{ - struct nand_chip *this = mtd->priv; - writeb(byte, this->IO_ADDR_W); -} - -/** * nand_read_byte16 - [DEFAULT] read one byte endianess aware from the chip * @mtd: MTD device structure * @@ -235,20 +217,6 @@ static uint8_t nand_read_byte16(struct mtd_info *mtd) } /** - * nand_write_byte16 - [DEFAULT] write one byte endianess aware to the chip - * @mtd: MTD device structure - * @byte: pointer to data byte to write - * - * Default write function for 16bit buswith with - * endianess conversion - */ -static void nand_write_byte16(struct mtd_info *mtd, uint8_t byte) -{ - struct nand_chip *this = mtd->priv; - writew(le16_to_cpu((u16) byte), this->IO_ADDR_W); -} - -/** * nand_read_word - [DEFAULT] read one word from the chip * @mtd: MTD device structure * @@ -262,20 +230,6 @@ static u16 nand_read_word(struct mtd_info *mtd) } /** - * nand_write_word - [DEFAULT] write one word to the chip - * @mtd: MTD device structure - * @word: data word to write - * - * Default write function for 16bit buswith without - * endianess conversion - */ -static void nand_write_word(struct mtd_info *mtd, u16 word) -{ - struct nand_chip *this = mtd->priv; - writew(word, this->IO_ADDR_W); -} - -/** * nand_select_chip - [DEFAULT] control CE line * @mtd: MTD device structure * @chip: chipnumber to select, -1 for deselect @@ -287,10 +241,10 @@ static void nand_select_chip(struct mtd_info *mtd, int chip) struct nand_chip *this = mtd->priv; switch (chip) { case -1: - this->hwcontrol(mtd, NAND_CTL_CLRNCE); + this->cmd_ctrl(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE); break; case 0: - this->hwcontrol(mtd, NAND_CTL_SETNCE); + this->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); break; default: @@ -528,8 +482,6 @@ static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip, return nand_isbad_bbt(mtd, ofs, allowbbt); } -DEFINE_LED_TRIGGER(nand_led_trigger); - /* * Wait for the ready pin, after a command * The timeout is catched later. @@ -559,13 +511,12 @@ static void nand_wait_ready(struct mtd_info *mtd) * Send command to NAND device. This function is used for small page * devices (256/512 Bytes per page) */ -static void nand_command(struct mtd_info *mtd, unsigned command, int column, - int page_addr) +static void nand_command(struct mtd_info *mtd, unsigned int command, + int column, int page_addr) { register struct nand_chip *this = mtd->priv; + int ctrl = NAND_CTRL_CLE | NAND_CTRL_CHANGE; - /* Begin command latch cycle */ - this->hwcontrol(mtd, NAND_CTL_SETCLE); /* * Write out the command to the device. */ @@ -583,33 +534,32 @@ static void nand_command(struct mtd_info *mtd, unsigned command, int column, column -= 256; readcmd = NAND_CMD_READ1; } - this->write_byte(mtd, readcmd); + this->cmd_ctrl(mtd, readcmd, ctrl); + ctrl &= ~NAND_CTRL_CHANGE; } - this->write_byte(mtd, command); - - /* Set ALE and clear CLE to start address cycle */ - this->hwcontrol(mtd, NAND_CTL_CLRCLE); - - if (column != -1 || page_addr != -1) { - this->hwcontrol(mtd, NAND_CTL_SETALE); + this->cmd_ctrl(mtd, command, ctrl); - /* Serially input address */ - if (column != -1) { - /* Adjust columns for 16 bit buswidth */ - if (this->options & NAND_BUSWIDTH_16) - column >>= 1; - this->write_byte(mtd, column); - } - if (page_addr != -1) { - this->write_byte(mtd, (uint8_t)(page_addr & 0xff)); - this->write_byte(mtd, (uint8_t)((page_addr >> 8) & 0xff)); - /* One more address cycle for devices > 32MiB */ - if (this->chipsize > (32 << 20)) - this->write_byte(mtd, (uint8_t)((page_addr >> 16) & 0x0f)); - } - /* Latch in address */ - this->hwcontrol(mtd, NAND_CTL_CLRALE); + /* + * Address cycle, when necessary + */ + ctrl = NAND_CTRL_ALE | NAND_CTRL_CHANGE; + /* Serially input address */ + if (column != -1) { + /* Adjust columns for 16 bit buswidth */ + if (this->options & NAND_BUSWIDTH_16) + column >>= 1; + this->cmd_ctrl(mtd, column, ctrl); + ctrl &= ~NAND_CTRL_CHANGE; + } + if (page_addr != -1) { + this->cmd_ctrl(mtd, page_addr, ctrl); + ctrl &= ~NAND_CTRL_CHANGE; + this->cmd_ctrl(mtd, page_addr >> 8, ctrl); + /* One more address cycle for devices > 32MiB */ + if (this->chipsize > (32 << 20)) + this->cmd_ctrl(mtd, page_addr >> 16, ctrl); } + this->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); /* * program and erase have their own busy handlers @@ -622,15 +572,16 @@ static void nand_command(struct mtd_info *mtd, unsigned command, int column, case NAND_CMD_ERASE2: case NAND_CMD_SEQIN: case NAND_CMD_STATUS: + this->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE); return; case NAND_CMD_RESET: if (this->dev_ready) break; udelay(this->chip_delay); - this->hwcontrol(mtd, NAND_CTL_SETCLE); - this->write_byte(mtd, NAND_CMD_STATUS); - this->hwcontrol(mtd, NAND_CTL_CLRCLE); + this->cmd_ctrl(mtd, NAND_CMD_STATUS, + NAND_CTRL_CLE | NAND_CTRL_CHANGE); + this->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE); while (!(this->read_byte(mtd) & NAND_STATUS_READY)) ; return; @@ -659,12 +610,13 @@ static void nand_command(struct mtd_info *mtd, unsigned command, int column, * @column: the column address for this command, -1 if none * @page_addr: the page address for this command, -1 if none * - * Send command to NAND device. This is the version for the new large page devices - * We dont have the separate regions as we have in the small page devices. - * We must emulate NAND_CMD_READOOB to keep the code compatible. + * Send command to NAND device. This is the version for the new large page + * devices We dont have the separate regions as we have in the small page + * devices. We must emulate NAND_CMD_READOOB to keep the code compatible. * */ -static void nand_command_lp(struct mtd_info *mtd, unsigned command, int column, int page_addr) +static void nand_command_lp(struct mtd_info *mtd, unsigned int command, + int column, int page_addr) { register struct nand_chip *this = mtd->priv; @@ -674,34 +626,33 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned command, int column, command = NAND_CMD_READ0; } - /* Begin command latch cycle */ - this->hwcontrol(mtd, NAND_CTL_SETCLE); - /* Write out the command to the device. */ - this->write_byte(mtd, (command & 0xff)); - /* End command latch cycle */ - this->hwcontrol(mtd, NAND_CTL_CLRCLE); + /* Command latch cycle */ + this->cmd_ctrl(mtd, command & 0xff, + NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); if (column != -1 || page_addr != -1) { - this->hwcontrol(mtd, NAND_CTL_SETALE); + int ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE; /* Serially input address */ if (column != -1) { /* Adjust columns for 16 bit buswidth */ if (this->options & NAND_BUSWIDTH_16) column >>= 1; - this->write_byte(mtd, column & 0xff); - this->write_byte(mtd, column >> 8); + this->cmd_ctrl(mtd, column, ctrl); + ctrl &= ~NAND_CTRL_CHANGE; + this->cmd_ctrl(mtd, column >> 8, ctrl); } if (page_addr != -1) { - this->write_byte(mtd, (uint8_t)(page_addr & 0xff)); - this->write_byte(mtd, (uint8_t)((page_addr >> 8) & 0xff)); + this->cmd_ctrl(mtd, page_addr, ctrl); + this->cmd_ctrl(mtd, page_addr >> 8, + NAND_NCE | NAND_ALE); /* One more address cycle for devices > 128MiB */ if (this->chipsize > (128 << 20)) - this->write_byte(mtd, (uint8_t)((page_addr >> 16) & 0xff)); + this->cmd_ctrl(mtd, page_addr >> 16, + NAND_NCE | NAND_ALE); } - /* Latch in address */ - this->hwcontrol(mtd, NAND_CTL_CLRALE); } + this->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); /* * program and erase have their own busy handlers @@ -733,20 +684,14 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned command, int column, if (this->dev_ready) break; udelay(this->chip_delay); - this->hwcontrol(mtd, NAND_CTL_SETCLE); - this->write_byte(mtd, NAND_CMD_STATUS); - this->hwcontrol(mtd, NAND_CTL_CLRCLE); + this->cmd_ctrl(mtd, NAND_CMD_STATUS, NAND_NCE | NAND_CLE); + this->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE); while (!(this->read_byte(mtd) & NAND_STATUS_READY)) ; return; case NAND_CMD_READ0: - /* Begin command latch cycle */ - this->hwcontrol(mtd, NAND_CTL_SETCLE); - /* Write out the start read command */ - this->write_byte(mtd, NAND_CMD_READSTART); - /* End command latch cycle */ - this->hwcontrol(mtd, NAND_CTL_CLRCLE); - /* Fall through into ready check */ + this->cmd_ctrl(mtd, NAND_CMD_READSTART, NAND_NCE | NAND_CLE); + this->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE); /* This applies to read commands */ default: @@ -1085,27 +1030,6 @@ static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retl } /** - * nand_read_ecc - [MTD Interface] MTD compability function for nand_do_read_ecc - * @mtd: MTD device structure - * @from: offset to read from - * @len: number of bytes to read - * @retlen: pointer to variable to store the number of read bytes - * @buf: the databuffer to put data - * @oob_buf: filesystem supplied oob data buffer - * @oobsel: oob selection structure - * - * This function simply calls nand_do_read_ecc with flags = 0xff - */ -static int nand_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, uint8_t *buf, uint8_t *oob_buf, struct nand_oobinfo *oobsel) -{ - /* use userspace supplied oobinfo, if zero */ - if (oobsel == NULL) - oobsel = &mtd->oobinfo; - return nand_do_read_ecc(mtd, from, len, retlen, buf, oob_buf, oobsel, 0xff); -} - -/** * nand_do_read_ecc - [MTD Interface] Read data with ECC * @mtd: MTD device structure * @from: offset to read from @@ -1529,6 +1453,56 @@ int nand_read_raw(struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len, s } /** + * nand_write_raw - [GENERIC] Write raw data including oob + * @mtd: MTD device structure + * @buf: source buffer + * @to: offset to write to + * @len: number of bytes to write + * @buf: source buffer + * @oob: oob buffer + * + * Write raw data including oob + */ +int nand_write_raw(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, + uint8_t *buf, uint8_t *oob) +{ + struct nand_chip *this = mtd->priv; + int page = (int)(to >> this->page_shift); + int chip = (int)(to >> this->chip_shift); + int ret; + + *retlen = 0; + + /* Do not allow writes past end of device */ + if ((to + len) > mtd->size) { + DEBUG(MTD_DEBUG_LEVEL0, "nand_read_raw: Attempt write " + "beyond end of device\n"); + return -EINVAL; + } + + /* Grab the lock and see if the device is available */ + nand_get_device(this, mtd, FL_WRITING); + + this->select_chip(mtd, chip); + this->data_poi = buf; + + while (len != *retlen) { + ret = nand_write_page(mtd, this, page, oob, &mtd->oobinfo, 0); + if (ret) + return ret; + page++; + *retlen += mtd->writesize; + this->data_poi += mtd->writesize; + oob += mtd->oobsize; + } + + /* Deselect and wake up anyone waiting on the device */ + nand_release_device(mtd); + return 0; +} +EXPORT_SYMBOL_GPL(nand_write_raw); + +/** * nand_prepare_oobbuf - [GENERIC] Prepare the out of band buffer * @mtd: MTD device structure * @fsbuf: buffer given by fs driver @@ -1590,57 +1564,39 @@ static uint8_t *nand_prepare_oobbuf(struct mtd_info *mtd, uint8_t *fsbuf, struct #define NOTALIGNED(x) (x & (mtd->writesize-1)) != 0 /** - * nand_write - [MTD Interface] compability function for nand_write_ecc + * nand_write - [MTD Interface] NAND write with ECC * @mtd: MTD device structure * @to: offset to write to * @len: number of bytes to write * @retlen: pointer to variable to store the number of written bytes * @buf: the data to write * - * This function simply calls nand_write_ecc with oob buffer and oobsel = NULL - * -*/ -static int nand_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const uint8_t *buf) -{ - return (nand_write_ecc(mtd, to, len, retlen, buf, NULL, NULL)); -} - -/** - * nand_write_ecc - [MTD Interface] NAND write with ECC - * @mtd: MTD device structure - * @to: offset to write to - * @len: number of bytes to write - * @retlen: pointer to variable to store the number of written bytes - * @buf: the data to write - * @eccbuf: filesystem supplied oob data buffer - * @oobsel: oob selection structure - * * NAND write with ECC */ -static int nand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, - size_t *retlen, const uint8_t *buf, uint8_t *eccbuf, - struct nand_oobinfo *oobsel) +static int nand_write(struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const uint8_t *buf) { int startpage, page, ret = -EIO, oob = 0, written = 0, chipnr; int autoplace = 0, numpages, totalpages; struct nand_chip *this = mtd->priv; - uint8_t *oobbuf, *bufstart; + uint8_t *oobbuf, *bufstart, *eccbuf = NULL; int ppblock = (1 << (this->phys_erase_shift - this->page_shift)); + struct nand_oobinfo *oobsel = &mtd->oobinfo; - DEBUG(MTD_DEBUG_LEVEL3, "nand_write_ecc: to = 0x%08x, len = %i\n", (unsigned int)to, (int)len); + DEBUG(MTD_DEBUG_LEVEL3, "nand_write: to = 0x%08x, len = %i\n", (unsigned int)to, (int)len); /* Initialize retlen, in case of early exit */ *retlen = 0; /* Do not allow write past end of device */ if ((to + len) > mtd->size) { - DEBUG(MTD_DEBUG_LEVEL0, "nand_write_ecc: Attempt to write past end of page\n"); + DEBUG(MTD_DEBUG_LEVEL0, "nand_write: Attempt to write past end of page\n"); return -EINVAL; } /* reject writes, which are not page aligned */ if (NOTALIGNED(to) || NOTALIGNED(len)) { - printk(KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n"); + printk(KERN_NOTICE "nand_write: Attempt to write not page aligned data\n"); return -EINVAL; } @@ -1656,10 +1612,6 @@ static int nand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, if (nand_check_wp(mtd)) goto out; - /* if oobsel is NULL, use chip defaults */ - if (oobsel == NULL) - oobsel = &mtd->oobinfo; - /* Autoplace of oob data ? Use the default placement scheme */ if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) { oobsel = this->autooob; @@ -1694,7 +1646,7 @@ static int nand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, */ ret = nand_write_page(mtd, this, page, &oobbuf[oob], oobsel, (--numpages > 0)); if (ret) { - DEBUG(MTD_DEBUG_LEVEL0, "nand_write_ecc: write_page failed %d\n", ret); + DEBUG(MTD_DEBUG_LEVEL0, "nand_write: write_page failed %d\n", ret); goto out; } /* Next oob page */ @@ -1717,7 +1669,7 @@ static int nand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, ret = nand_verify_pages(mtd, this, startpage, page - startpage, oobbuf, oobsel, chipnr, (eccbuf != NULL)); if (ret) { - DEBUG(MTD_DEBUG_LEVEL0, "nand_write_ecc: verify_pages failed %d\n", ret); + DEBUG(MTD_DEBUG_LEVEL0, "nand_write: verify_pages failed %d\n", ret); goto out; } *retlen = written; @@ -1746,7 +1698,7 @@ static int nand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, if (!ret) *retlen = written; else - DEBUG(MTD_DEBUG_LEVEL0, "nand_write_ecc: verify_pages failed %d\n", ret); + DEBUG(MTD_DEBUG_LEVEL0, "nand_write: verify_pages failed %d\n", ret); out: /* Deselect and wake up anyone waiting on the device */ @@ -1857,187 +1809,6 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to, size_t len, size_t *r } /** - * nand_writev - [MTD Interface] compabilty function for nand_writev_ecc - * @mtd: MTD device structure - * @vecs: the iovectors to write - * @count: number of vectors - * @to: offset to write to - * @retlen: pointer to variable to store the number of written bytes - * - * NAND write with kvec. This just calls the ecc function - */ -static int nand_writev(struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, - loff_t to, size_t *retlen) -{ - return (nand_writev_ecc(mtd, vecs, count, to, retlen, NULL, NULL)); -} - -/** - * nand_writev_ecc - [MTD Interface] write with iovec with ecc - * @mtd: MTD device structure - * @vecs: the iovectors to write - * @count: number of vectors - * @to: offset to write to - * @retlen: pointer to variable to store the number of written bytes - * @eccbuf: filesystem supplied oob data buffer - * @oobsel: oob selection structure - * - * NAND write with iovec with ecc - */ -static int nand_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, - loff_t to, size_t *retlen, uint8_t *eccbuf, struct nand_oobinfo *oobsel) -{ - int i, page, len, total_len, ret = -EIO, written = 0, chipnr; - int oob, numpages, autoplace = 0, startpage; - struct nand_chip *this = mtd->priv; - int ppblock = (1 << (this->phys_erase_shift - this->page_shift)); - uint8_t *oobbuf, *bufstart; - - /* Preset written len for early exit */ - *retlen = 0; - - /* Calculate total length of data */ - total_len = 0; - for (i = 0; i < count; i++) - total_len += (int)vecs[i].iov_len; - - DEBUG(MTD_DEBUG_LEVEL3, "nand_writev: to = 0x%08x, len = %i, count = %ld\n", (unsigned int)to, (unsigned int)total_len, count); - - /* Do not allow write past end of page */ - if ((to + total_len) > mtd->size) { - DEBUG(MTD_DEBUG_LEVEL0, "nand_writev: Attempted write past end of device\n"); - return -EINVAL; - } - - /* reject writes, which are not page aligned */ - if (NOTALIGNED(to) || NOTALIGNED(total_len)) { - printk(KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n"); - return -EINVAL; - } - - /* Grab the lock and see if the device is available */ - nand_get_device(this, mtd, FL_WRITING); - - /* Get the current chip-nr */ - chipnr = (int)(to >> this->chip_shift); - /* Select the NAND device */ - this->select_chip(mtd, chipnr); - - /* Check, if it is write protected */ - if (nand_check_wp(mtd)) - goto out; - - /* if oobsel is NULL, use chip defaults */ - if (oobsel == NULL) - oobsel = &mtd->oobinfo; - - /* Autoplace of oob data ? Use the default placement scheme */ - if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) { - oobsel = this->autooob; - autoplace = 1; - } - if (oobsel->useecc == MTD_NANDECC_AUTOPL_USR) - autoplace = 1; - - /* Setup start page */ - page = (int)(to >> this->page_shift); - /* Invalidate the page cache, if we write to the cached page */ - if (page <= this->pagebuf && this->pagebuf < ((to + total_len) >> this->page_shift)) - this->pagebuf = -1; - - startpage = page & this->pagemask; - - /* Loop until all kvec' data has been written */ - len = 0; - while (count) { - /* If the given tuple is >= pagesize then - * write it out from the iov - */ - if ((vecs->iov_len - len) >= mtd->writesize) { - /* Calc number of pages we can write - * out of this iov in one go */ - numpages = (vecs->iov_len - len) >> this->page_shift; - /* Do not cross block boundaries */ - numpages = min(ppblock - (startpage & (ppblock - 1)), numpages); - oobbuf = nand_prepare_oobbuf(mtd, NULL, oobsel, autoplace, numpages); - bufstart = (uint8_t *) vecs->iov_base; - bufstart += len; - this->data_poi = bufstart; - oob = 0; - for (i = 1; i <= numpages; i++) { - /* Write one page. If this is the last page to write - * then use the real pageprogram command, else select - * cached programming if supported by the chip. - */ - ret = nand_write_page(mtd, this, page & this->pagemask, - &oobbuf[oob], oobsel, i != numpages); - if (ret) - goto out; - this->data_poi += mtd->writesize; - len += mtd->writesize; - oob += mtd->oobsize; - page++; - } - /* Check, if we have to switch to the next tuple */ - if (len >= (int)vecs->iov_len) { - vecs++; - len = 0; - count--; - } - } else { - /* We must use the internal buffer, read data out of each - * tuple until we have a full page to write - */ - int cnt = 0; - while (cnt < mtd->writesize) { - if (vecs->iov_base != NULL && vecs->iov_len) - this->data_buf[cnt++] = ((uint8_t *) vecs->iov_base)[len++]; - /* Check, if we have to switch to the next tuple */ - if (len >= (int)vecs->iov_len) { - vecs++; - len = 0; - count--; - } - } - this->pagebuf = page; - this->data_poi = this->data_buf; - bufstart = this->data_poi; - numpages = 1; - oobbuf = nand_prepare_oobbuf(mtd, NULL, oobsel, autoplace, numpages); - ret = nand_write_page(mtd, this, page & this->pagemask, oobbuf, oobsel, 0); - if (ret) - goto out; - page++; - } - - this->data_poi = bufstart; - ret = nand_verify_pages(mtd, this, startpage, numpages, oobbuf, oobsel, chipnr, 0); - if (ret) - goto out; - - written += mtd->writesize * numpages; - /* All done ? */ - if (!count) - break; - - startpage = page & this->pagemask; - /* Check, if we cross a chip boundary */ - if (!startpage) { - chipnr++; - this->select_chip(mtd, -1); - this->select_chip(mtd, chipnr); - } - } - ret = 0; - out: - /* Deselect and wake up anyone waiting on the device */ - nand_release_device(mtd); - - *retlen = written; - return ret; -} - -/** * single_erease_cmd - [GENERIC] NAND standard block erase command function * @mtd: MTD device structure * @page: the page address of the block which will be erased @@ -2392,12 +2163,8 @@ static void nand_set_defaults(struct nand_chip *this, int busw) if (!this->select_chip) this->select_chip = nand_select_chip; - if (!this->write_byte) - this->write_byte = busw ? nand_write_byte16 : nand_write_byte; if (!this->read_byte) this->read_byte = busw ? nand_read_byte16 : nand_read_byte; - if (!this->write_word) - this->write_word = nand_write_word; if (!this->read_word) this->read_word = nand_read_word; if (!this->block_bad) @@ -2713,13 +2480,8 @@ int nand_scan(struct mtd_info *mtd, int maxchips) mtd->unpoint = NULL; mtd->read = nand_read; mtd->write = nand_write; - mtd->read_ecc = nand_read_ecc; - mtd->write_ecc = nand_write_ecc; mtd->read_oob = nand_read_oob; mtd->write_oob = nand_write_oob; - mtd->readv = NULL; - mtd->writev = nand_writev; - mtd->writev_ecc = nand_writev_ecc; mtd->sync = nand_sync; mtd->lock = NULL; mtd->unlock = NULL; diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index fbccb2a25186..ecaaca18d1e0 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -156,7 +156,7 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, while (totlen) { len = min(totlen, (size_t) (1 << this->bbt_erase_shift)); - res = mtd->read_ecc(mtd, from, len, &retlen, buf, NULL, this->autooob); + res = mtd->read(mtd, from, len, &retlen, buf); if (res < 0) { if (retlen != len) { printk(KERN_INFO "nand_bbt: Error reading bad block table\n"); @@ -471,17 +471,17 @@ static int search_read_bbts(struct mtd_info *mtd, uint8_t * buf, struct nand_bbt * */ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, - struct nand_bbt_descr *td, struct nand_bbt_descr *md, int chipsel) + struct nand_bbt_descr *td, struct nand_bbt_descr *md, + int chipsel) { struct nand_chip *this = mtd->priv; - struct nand_oobinfo oobinfo; struct erase_info einfo; int i, j, res, chip = 0; int bits, startblock, dir, page, offs, numblocks, sft, sftmsk; - int nrchips, bbtoffs, pageoffs; + int nrchips, bbtoffs, pageoffs, ooboffs; uint8_t msk[4]; uint8_t rcode = td->reserved_block_code; - size_t retlen, len = 0; + size_t retlen, len = 0, ooblen; loff_t to; if (!rcode) @@ -526,12 +526,14 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, for (i = 0; i < td->maxblocks; i++) { int block = startblock + dir * i; /* Check, if the block is bad */ - switch ((this->bbt[block >> 2] >> (2 * (block & 0x03))) & 0x03) { + switch ((this->bbt[block >> 2] >> + (2 * (block & 0x03))) & 0x03) { case 0x01: case 0x03: continue; } - page = block << (this->bbt_erase_shift - this->page_shift); + page = block << + (this->bbt_erase_shift - this->page_shift); /* Check, if the block is used by the mirror table */ if (!md || md->pages[chip] != page) goto write; @@ -542,11 +544,20 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, /* Set up shift count and masks for the flash table */ bits = td->options & NAND_BBT_NRBITS_MSK; + msk[2] = ~rcode; switch (bits) { - case 1: sft = 3; sftmsk = 0x07; msk[0] = 0x00; msk[1] = 0x01; msk[2] = ~rcode; msk[3] = 0x01; break; - case 2: sft = 2; sftmsk = 0x06; msk[0] = 0x00; msk[1] = 0x01; msk[2] = ~rcode; msk[3] = 0x03; break; - case 4: sft = 1; sftmsk = 0x04; msk[0] = 0x00; msk[1] = 0x0C; msk[2] = ~rcode; msk[3] = 0x0f; break; - case 8: sft = 0; sftmsk = 0x00; msk[0] = 0x00; msk[1] = 0x0F; msk[2] = ~rcode; msk[3] = 0xff; break; + case 1: sft = 3; sftmsk = 0x07; msk[0] = 0x00; msk[1] = 0x01; + msk[3] = 0x01; + break; + case 2: sft = 2; sftmsk = 0x06; msk[0] = 0x00; msk[1] = 0x01; + msk[3] = 0x03; + break; + case 4: sft = 1; sftmsk = 0x04; msk[0] = 0x00; msk[1] = 0x0C; + msk[3] = 0x0f; + break; + case 8: sft = 0; sftmsk = 0x00; msk[0] = 0x00; msk[1] = 0x0F; + msk[3] = 0xff; + break; default: return -EINVAL; } @@ -554,49 +565,55 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, to = ((loff_t) page) << this->page_shift; - memcpy(&oobinfo, this->autooob, sizeof(oobinfo)); - oobinfo.useecc = MTD_NANDECC_PLACEONLY; - /* Must we save the block contents ? */ if (td->options & NAND_BBT_SAVECONTENT) { /* Make it block aligned */ to &= ~((loff_t) ((1 << this->bbt_erase_shift) - 1)); len = 1 << this->bbt_erase_shift; - res = mtd->read_ecc(mtd, to, len, &retlen, buf, &buf[len], &oobinfo); + res = mtd->read(mtd, to, len, &retlen, buf); if (res < 0) { if (retlen != len) { - printk(KERN_INFO - "nand_bbt: Error reading block for writing the bad block table\n"); + printk(KERN_INFO "nand_bbt: Error " + "reading block for writing " + "the bad block table\n"); return res; } - printk(KERN_WARNING "nand_bbt: ECC error while reading block for writing bad block table\n"); + printk(KERN_WARNING "nand_bbt: ECC error " + "while reading block for writing " + "bad block table\n"); } + /* Read oob data */ + ooblen = (len >> this->page_shift) * mtd->oobsize; + res = mtd->read_oob(mtd, to + mtd->writesize, ooblen, + &retlen, &buf[len]); + if (res < 0 || retlen != ooblen) + goto outerr; + /* Calc the byte offset in the buffer */ pageoffs = page - (int)(to >> this->page_shift); offs = pageoffs << this->page_shift; /* Preset the bbt area with 0xff */ memset(&buf[offs], 0xff, (size_t) (numblocks >> sft)); - /* Preset the bbt's oob area with 0xff */ - memset(&buf[len + pageoffs * mtd->oobsize], 0xff, - ((len >> this->page_shift) - pageoffs) * mtd->oobsize); - if (td->options & NAND_BBT_VERSION) { - buf[len + (pageoffs * mtd->oobsize) + td->veroffs] = td->version[chip]; - } + ooboffs = len + (pageoffs * mtd->oobsize); + } else { /* Calc length */ len = (size_t) (numblocks >> sft); /* Make it page aligned ! */ - len = (len + (mtd->writesize - 1)) & ~(mtd->writesize - 1); + len = (len + (mtd->writesize - 1)) & + ~(mtd->writesize - 1); /* Preset the buffer with 0xff */ - memset(buf, 0xff, len + (len >> this->page_shift) * mtd->oobsize); + memset(buf, 0xff, len + + (len >> this->page_shift)* mtd->oobsize); offs = 0; + ooboffs = len; /* Pattern is located in oob area of first page */ - memcpy(&buf[len + td->offs], td->pattern, td->len); - if (td->options & NAND_BBT_VERSION) { - buf[len + td->veroffs] = td->version[chip]; - } + memcpy(&buf[ooboffs + td->offs], td->pattern, td->len); } + if (td->options & NAND_BBT_VERSION) + buf[ooboffs + td->veroffs] = td->version[chip]; + /* walk through the memory table */ for (i = 0; i < numblocks;) { uint8_t dat; @@ -604,7 +621,8 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, for (j = 0; j < 4; j++, i++) { int sftcnt = (i << (3 - sft)) & sftmsk; /* Do not store the reserved bbt blocks ! */ - buf[offs + (i >> sft)] &= ~(msk[dat & 0x03] << sftcnt); + buf[offs + (i >> sft)] &= + ~(msk[dat & 0x03] << sftcnt); dat >>= 2; } } @@ -614,23 +632,25 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, einfo.addr = (unsigned long)to; einfo.len = 1 << this->bbt_erase_shift; res = nand_erase_nand(mtd, &einfo, 1); - if (res < 0) { - printk(KERN_WARNING "nand_bbt: Error during block erase: %d\n", res); - return res; - } + if (res < 0) + goto outerr; - res = mtd->write_ecc(mtd, to, len, &retlen, buf, &buf[len], &oobinfo); - if (res < 0) { - printk(KERN_WARNING "nand_bbt: Error while writing bad block table %d\n", res); - return res; - } - printk(KERN_DEBUG "Bad block table written to 0x%08x, version 0x%02X\n", - (unsigned int)to, td->version[chip]); + res = nand_write_raw(mtd, to, len, &retlen, buf, &buf[len]); + if (res < 0) + goto outerr; + + printk(KERN_DEBUG "Bad block table written to 0x%08x, version " + "0x%02X\n", (unsigned int)to, td->version[chip]); /* Mark it as used */ td->pages[chip] = page; } return 0; + + outerr: + printk(KERN_WARNING + "nand_bbt: Error while writing bad block table %d\n", res); + return res; } /** diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index 22af9b29d2bf..ebd64abc8be8 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c @@ -1071,68 +1071,6 @@ switch_state(struct nandsim *ns) } } -static void -ns_hwcontrol(struct mtd_info *mtd, int cmd) -{ - struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv; - - switch (cmd) { - - /* set CLE line high */ - case NAND_CTL_SETCLE: - NS_DBG("ns_hwcontrol: start command latch cycles\n"); - ns->lines.cle = 1; - break; - - /* set CLE line low */ - case NAND_CTL_CLRCLE: - NS_DBG("ns_hwcontrol: stop command latch cycles\n"); - ns->lines.cle = 0; - break; - - /* set ALE line high */ - case NAND_CTL_SETALE: - NS_DBG("ns_hwcontrol: start address latch cycles\n"); - ns->lines.ale = 1; - break; - - /* set ALE line low */ - case NAND_CTL_CLRALE: - NS_DBG("ns_hwcontrol: stop address latch cycles\n"); - ns->lines.ale = 0; - break; - - /* set WP line high */ - case NAND_CTL_SETWP: - NS_DBG("ns_hwcontrol: enable write protection\n"); - ns->lines.wp = 1; - break; - - /* set WP line low */ - case NAND_CTL_CLRWP: - NS_DBG("ns_hwcontrol: disable write protection\n"); - ns->lines.wp = 0; - break; - - /* set CE line low */ - case NAND_CTL_SETNCE: - NS_DBG("ns_hwcontrol: enable chip\n"); - ns->lines.ce = 1; - break; - - /* set CE line high */ - case NAND_CTL_CLRNCE: - NS_DBG("ns_hwcontrol: disable chip\n"); - ns->lines.ce = 0; - break; - - default: - NS_ERR("hwcontrol: unknown command\n"); - } - - return; -} - static u_char ns_nand_read_byte(struct mtd_info *mtd) { @@ -1359,6 +1297,18 @@ ns_nand_write_byte(struct mtd_info *mtd, u_char byte) return; } +static void ns_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int bitmask) +{ + struct nandsim *ns = ((struct nand_chip *)mtd->priv)->priv; + + ns->lines.cle = bitmask & NAND_CLE ? 1 : 0; + ns->lines.ale = bitmask & NAND_ALE ? 1 : 0; + ns->lines.ce = bitmask & NAND_NCE ? 1 : 0; + + if (cmd != NAND_CMD_NONE) + ns_nand_write_byte(mtd, cmd); +} + static int ns_device_ready(struct mtd_info *mtd) { @@ -1377,17 +1327,6 @@ ns_nand_read_word(struct mtd_info *mtd) } static void -ns_nand_write_word(struct mtd_info *mtd, uint16_t word) -{ - struct nand_chip *chip = (struct nand_chip *)mtd->priv; - - NS_DBG("write_word\n"); - - chip->write_byte(mtd, word & 0xFF); - chip->write_byte(mtd, word >> 8); -} - -static void ns_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) { struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv; @@ -1514,14 +1453,12 @@ static int __init ns_init_module(void) /* * Register simulator's callbacks. */ - chip->hwcontrol = ns_hwcontrol; + chip->cmd_ctrl = ns_hwcontrol; chip->read_byte = ns_nand_read_byte; chip->dev_ready = ns_device_ready; - chip->write_byte = ns_nand_write_byte; chip->write_buf = ns_nand_write_buf; chip->read_buf = ns_nand_read_buf; chip->verify_buf = ns_nand_verify_buf; - chip->write_word = ns_nand_write_word; chip->read_word = ns_nand_read_word; chip->ecc.mode = NAND_ECC_SOFT; chip->options |= NAND_SKIP_BBTSCAN; diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c index e2dc81de106a..481541a683ca 100644 --- a/drivers/mtd/nand/ndfc.c +++ b/drivers/mtd/nand/ndfc.c @@ -60,22 +60,17 @@ static void ndfc_select_chip(struct mtd_info *mtd, int chip) writel(ccr, ndfc->ndfcbase + NDFC_CCR); } -static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd) +static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) { - struct ndfc_controller *ndfc = &ndfc_ctrl; struct nand_chip *chip = mtd->priv; - switch (cmd) { - case NAND_CTL_SETCLE: - chip->IO_ADDR_W = ndfc->ndfcbase + NDFC_CMD; - break; - case NAND_CTL_SETALE: - chip->IO_ADDR_W = ndfc->ndfcbase + NDFC_ALE; - break; - default: - chip->IO_ADDR_W = ndfc->ndfcbase + NDFC_DATA; - break; - } + if (cmd == NAND_CMD_NONE) + return; + + if (ctrl & NAND_CLE) + writel(cmd & 0xFF, chip->IO_ADDR_W + NDFC_CMD); + else + writel(cmd & 0xFF, chip->IO_ADDR_W + NDFC_ALE); } static int ndfc_ready(struct mtd_info *mtd) @@ -158,7 +153,7 @@ static void ndfc_chip_init(struct ndfc_nand_mtd *mtd) chip->IO_ADDR_R = ndfc->ndfcbase + NDFC_DATA; chip->IO_ADDR_W = ndfc->ndfcbase + NDFC_DATA; - chip->hwcontrol = ndfc_hwcontrol; + chip->cmd_ctrl = ndfc_hwcontrol; chip->dev_ready = ndfc_ready; chip->select_chip = ndfc_select_chip; chip->chip_delay = 50; diff --git a/drivers/mtd/nand/ppchameleonevb.c b/drivers/mtd/nand/ppchameleonevb.c index 9fab0998524d..22fa65c12ab9 100644 --- a/drivers/mtd/nand/ppchameleonevb.c +++ b/drivers/mtd/nand/ppchameleonevb.c @@ -108,54 +108,68 @@ extern int parse_cmdline_partitions(struct mtd_info *master, struct mtd_partitio /* * hardware specific access to control-lines */ -static void ppchameleon_hwcontrol(struct mtd_info *mtdinfo, int cmd) +static void ppchameleon_hwcontrol(struct mtd_info *mtdinfo, int cmd, + unsigned int ctrl) { - switch (cmd) { - - case NAND_CTL_SETCLE: - MACRO_NAND_CTL_SETCLE((unsigned long)CFG_NAND0_PADDR); - break; - case NAND_CTL_CLRCLE: - MACRO_NAND_CTL_CLRCLE((unsigned long)CFG_NAND0_PADDR); - break; - case NAND_CTL_SETALE: - MACRO_NAND_CTL_SETALE((unsigned long)CFG_NAND0_PADDR); - break; - case NAND_CTL_CLRALE: - MACRO_NAND_CTL_CLRALE((unsigned long)CFG_NAND0_PADDR); - break; - case NAND_CTL_SETNCE: - MACRO_NAND_ENABLE_CE((unsigned long)CFG_NAND0_PADDR); - break; - case NAND_CTL_CLRNCE: - MACRO_NAND_DISABLE_CE((unsigned long)CFG_NAND0_PADDR); - break; + struct nand_chip *chip = mtd->priv; + + if (ctrl & NAND_CTRL_CHANGE) { +#error Missing headerfiles. No way to fix this. -tglx + switch (cmd) { + case NAND_CTL_SETCLE: + MACRO_NAND_CTL_SETCLE((unsigned long)CFG_NAND0_PADDR); + break; + case NAND_CTL_CLRCLE: + MACRO_NAND_CTL_CLRCLE((unsigned long)CFG_NAND0_PADDR); + break; + case NAND_CTL_SETALE: + MACRO_NAND_CTL_SETALE((unsigned long)CFG_NAND0_PADDR); + break; + case NAND_CTL_CLRALE: + MACRO_NAND_CTL_CLRALE((unsigned long)CFG_NAND0_PADDR); + break; + case NAND_CTL_SETNCE: + MACRO_NAND_ENABLE_CE((unsigned long)CFG_NAND0_PADDR); + break; + case NAND_CTL_CLRNCE: + MACRO_NAND_DISABLE_CE((unsigned long)CFG_NAND0_PADDR); + break; + } } + if (cmd != NAND_CMD_NONE) + writeb(cmd, chip->IO_ADDR_W); } -static void ppchameleonevb_hwcontrol(struct mtd_info *mtdinfo, int cmd) +static void ppchameleonevb_hwcontrol(struct mtd_info *mtdinfo, int cmd, + unsigned int ctrl) { - switch (cmd) { - - case NAND_CTL_SETCLE: - MACRO_NAND_CTL_SETCLE((unsigned long)CFG_NAND1_PADDR); - break; - case NAND_CTL_CLRCLE: - MACRO_NAND_CTL_CLRCLE((unsigned long)CFG_NAND1_PADDR); - break; - case NAND_CTL_SETALE: - MACRO_NAND_CTL_SETALE((unsigned long)CFG_NAND1_PADDR); - break; - case NAND_CTL_CLRALE: - MACRO_NAND_CTL_CLRALE((unsigned long)CFG_NAND1_PADDR); - break; - case NAND_CTL_SETNCE: - MACRO_NAND_ENABLE_CE((unsigned long)CFG_NAND1_PADDR); - break; - case NAND_CTL_CLRNCE: - MACRO_NAND_DISABLE_CE((unsigned long)CFG_NAND1_PADDR); - break; + struct nand_chip *chip = mtd->priv; + + if (ctrl & NAND_CTRL_CHANGE) { +#error Missing headerfiles. No way to fix this. -tglx + switch (cmd) { + case NAND_CTL_SETCLE: + MACRO_NAND_CTL_SETCLE((unsigned long)CFG_NAND1_PADDR); + break; + case NAND_CTL_CLRCLE: + MACRO_NAND_CTL_CLRCLE((unsigned long)CFG_NAND1_PADDR); + break; + case NAND_CTL_SETALE: + MACRO_NAND_CTL_SETALE((unsigned long)CFG_NAND1_PADDR); + break; + case NAND_CTL_CLRALE: + MACRO_NAND_CTL_CLRALE((unsigned long)CFG_NAND1_PADDR); + break; + case NAND_CTL_SETNCE: + MACRO_NAND_ENABLE_CE((unsigned long)CFG_NAND1_PADDR); + break; + case NAND_CTL_CLRNCE: + MACRO_NAND_DISABLE_CE((unsigned long)CFG_NAND1_PADDR); + break; + } } + if (cmd != NAND_CMD_NONE) + writeb(cmd, chip->IO_ADDR_W); } #ifdef USE_READY_BUSY_PIN @@ -251,7 +265,7 @@ static int __init ppchameleonevb_init(void) /* insert callbacks */ this->IO_ADDR_R = ppchameleon_fio_base; this->IO_ADDR_W = ppchameleon_fio_base; - this->hwcontrol = ppchameleon_hwcontrol; + this->cmd_ctrl = ppchameleon_hwcontrol; #ifdef USE_READY_BUSY_PIN this->dev_ready = ppchameleon_device_ready; #endif @@ -351,7 +365,7 @@ static int __init ppchameleonevb_init(void) /* insert callbacks */ this->IO_ADDR_R = ppchameleonevb_fio_base; this->IO_ADDR_W = ppchameleonevb_fio_base; - this->hwcontrol = ppchameleonevb_hwcontrol; + this->cmd_ctrl = ppchameleonevb_hwcontrol; #ifdef USE_READY_BUSY_PIN this->dev_ready = ppchameleonevb_device_ready; #endif diff --git a/drivers/mtd/nand/rtc_from4.c b/drivers/mtd/nand/rtc_from4.c index f8e631c89a60..6c97bfaea19a 100644 --- a/drivers/mtd/nand/rtc_from4.c +++ b/drivers/mtd/nand/rtc_from4.c @@ -208,32 +208,18 @@ static uint8_t revbits[256] = { * Address lines (A24-A22), so no action is required here. * */ -static void rtc_from4_hwcontrol(struct mtd_info *mtd, int cmd) +static void rtc_from4_hwcontrol(struct mtd_info *mtd, int cmd, + unsigned int ctrl) { - struct nand_chip *this = (struct nand_chip *)(mtd->priv); + struct nand_chip *chip = (mtd->priv); - switch (cmd) { + if (cmd == NAND_CMD_NONE) + return; - case NAND_CTL_SETCLE: - this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W | RTC_FROM4_CLE); - break; - case NAND_CTL_CLRCLE: - this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W & ~RTC_FROM4_CLE); - break; - - case NAND_CTL_SETALE: - this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W | RTC_FROM4_ALE); - break; - case NAND_CTL_CLRALE: - this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W & ~RTC_FROM4_ALE); - break; - - case NAND_CTL_SETNCE: - break; - case NAND_CTL_CLRNCE: - break; - - } + if (ctrl & NAND_CLE) + writeb(cmd, chip->IO_ADDR_W | RTC_FROM4_CLE); + else + writeb(cmd, chip->IO_ADDR_W | RTC_FROM4_ALE); } /* @@ -559,7 +545,7 @@ static int __init rtc_from4_init(void) this->IO_ADDR_R = rtc_from4_fio_base; this->IO_ADDR_W = rtc_from4_fio_base; /* Set address of hardware control function */ - this->hwcontrol = rtc_from4_hwcontrol; + this->cmd_ctrl = rtc_from4_hwcontrol; /* Set address of chip select function */ this->select_chip = rtc_from4_nand_select_chip; /* command delay time (in us) */ diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index 608340a25278..215227d1a65c 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c @@ -256,60 +256,36 @@ static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip) * */ -static void s3c2410_nand_hwcontrol(struct mtd_info *mtd, int cmd) +static void s3c2410_nand_hwcontrol(struct mtd_info *mtd, int cmd, + unsigend int ctrl) { struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); struct nand_chip *chip = mtd->priv; - switch (cmd) { - case NAND_CTL_SETNCE: - case NAND_CTL_CLRNCE: - printk(KERN_ERR "%s: called for NCE\n", __FUNCTION__); - break; - - case NAND_CTL_SETCLE: - chip->IO_ADDR_W = info->regs + S3C2410_NFCMD; - break; - - case NAND_CTL_SETALE: - chip->IO_ADDR_W = info->regs + S3C2410_NFADDR; - break; - - /* NAND_CTL_CLRCLE: */ - /* NAND_CTL_CLRALE: */ - default: - chip->IO_ADDR_W = info->regs + S3C2410_NFDATA; - break; - } + if (cmd == NAND_CMD_NONE) + return; + + if (cmd & NAND_CLE) + writeb(cmd, info->regs + S3C2410_NFCMD); + else + writeb(cmd, info->regs + S3C2410_NFADDR); } /* command and control functions */ -static void s3c2440_nand_hwcontrol(struct mtd_info *mtd, int cmd) +static void s3c2410_nand_hwcontrol(struct mtd_info *mtd, int cmd, + unsigend int ctrl) { struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); struct nand_chip *chip = mtd->priv; - switch (cmd) { - case NAND_CTL_SETNCE: - case NAND_CTL_CLRNCE: - printk(KERN_ERR "%s: called for NCE\n", __FUNCTION__); - break; - - case NAND_CTL_SETCLE: - chip->IO_ADDR_W = info->regs + S3C2440_NFCMD; - break; - - case NAND_CTL_SETALE: - chip->IO_ADDR_W = info->regs + S3C2440_NFADDR; - break; - - /* NAND_CTL_CLRCLE: */ - /* NAND_CTL_CLRALE: */ - default: - chip->IO_ADDR_W = info->regs + S3C2440_NFDATA; - break; - } + if (cmd == NAND_CMD_NONE) + return; + + if (cmd & NAND_CLE) + writeb(cmd, info->regs + S3C2440_NFCMD); + else + writeb(cmd, info->regs + S3C2440_NFADDR); } /* s3c2410_nand_devready() @@ -498,7 +474,7 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info, chip->IO_ADDR_R = info->regs + S3C2410_NFDATA; chip->IO_ADDR_W = info->regs + S3C2410_NFDATA; - chip->hwcontrol = s3c2410_nand_hwcontrol; + chip->cmd_ctrl = s3c2410_nand_hwcontrol; chip->dev_ready = s3c2410_nand_devready; chip->write_buf = s3c2410_nand_write_buf; chip->read_buf = s3c2410_nand_read_buf; @@ -511,7 +487,7 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info, if (info->is_s3c2440) { chip->IO_ADDR_R = info->regs + S3C2440_NFDATA; chip->IO_ADDR_W = info->regs + S3C2440_NFDATA; - chip->hwcontrol = s3c2440_nand_hwcontrol; + chip->cmd_ctrl = s3c2440_nand_hwcontrol; } nmtd->info = info; diff --git a/drivers/mtd/nand/sharpsl.c b/drivers/mtd/nand/sharpsl.c index 5554d0b97c8c..45a1da724bff 100644 --- a/drivers/mtd/nand/sharpsl.c +++ b/drivers/mtd/nand/sharpsl.c @@ -77,31 +77,26 @@ static struct mtd_partition sharpsl_nand_default_partition_info[] = { /* * hardware specific access to control-lines + * ctrl: + * NAND_CNE: bit 0 -> bit 0 & 4 + * NAND_CLE: bit 1 -> bit 1 + * NAND_ALE: bit 2 -> bit 2 + * */ -static void sharpsl_nand_hwcontrol(struct mtd_info *mtd, int cmd) +static void sharpsl_nand_hwcontrol(struct mtd_info *mtd, int cmd, + unsigned int ctrl) { - switch (cmd) { - case NAND_CTL_SETCLE: - writeb(readb(FLASHCTL) | FLCLE, FLASHCTL); - break; - case NAND_CTL_CLRCLE: - writeb(readb(FLASHCTL) & ~FLCLE, FLASHCTL); - break; - - case NAND_CTL_SETALE: - writeb(readb(FLASHCTL) | FLALE, FLASHCTL); - break; - case NAND_CTL_CLRALE: - writeb(readb(FLASHCTL) & ~FLALE, FLASHCTL); - break; - - case NAND_CTL_SETNCE: - writeb(readb(FLASHCTL) & ~(FLCE0 | FLCE1), FLASHCTL); - break; - case NAND_CTL_CLRNCE: - writeb(readb(FLASHCTL) | (FLCE0 | FLCE1), FLASHCTL); - break; + struct nand_chip *chip = mtd->priv; + + if (ctrl & NAND_CTRL_CHANGE) { + unsigned char bits = ctrl & 0x07; + + bits |= (ctrl & 0x01) << 4; + writeb((readb(FLASHCTL) & 0x17) | bits, FLASHCTL); } + + if (cmd != NAND_CMD_NONE) + writeb(cmd, chip->IO_ADDR_W); } static uint8_t scan_ff_pattern[] = { 0xff, 0xff }; @@ -196,7 +191,7 @@ static int __init sharpsl_nand_init(void) this->IO_ADDR_R = FLASHIO; this->IO_ADDR_W = FLASHIO; /* Set address of hardware control function */ - this->hwcontrol = sharpsl_nand_hwcontrol; + this->cmd_ctrl = sharpsl_nand_hwcontrol; this->dev_ready = sharpsl_nand_dev_ready; /* 15 us command delay time */ this->chip_delay = 15; diff --git a/drivers/mtd/nand/spia.c b/drivers/mtd/nand/spia.c index 9737f1d67c3c..1f6d429b1583 100644 --- a/drivers/mtd/nand/spia.c +++ b/drivers/mtd/nand/spia.c @@ -82,20 +82,27 @@ static const struct mtd_partition partition_info[] = { /* * hardware specific access to control-lines -*/ + * + * ctrl: + * NAND_CNE: bit 0 -> bit 2 + * NAND_CLE: bit 1 -> bit 0 + * NAND_ALE: bit 2 -> bit 1 + */ static void spia_hwcontrol(struct mtd_info *mtd, int cmd) { - switch (cmd) { + struct nand_chip *chip = mtd->priv; - case NAND_CTL_SETCLE: (*(volatile unsigned char *) (spia_io_base + spia_pedr)) |= 0x01; break; - case NAND_CTL_CLRCLE: (*(volatile unsigned char *) (spia_io_base + spia_pedr)) &= ~0x01; break; + if (ctrl & NAND_CTRL_CHANGE) { + void __iomem *addr = spia_io_base + spia_pedr; + unsigned char bits; - case NAND_CTL_SETALE: (*(volatile unsigned char *) (spia_io_base + spia_pedr)) |= 0x02; break; - case NAND_CTL_CLRALE: (*(volatile unsigned char *) (spia_io_base + spia_pedr)) &= ~0x02; break; - - case NAND_CTL_SETNCE: (*(volatile unsigned char *) (spia_io_base + spia_pedr)) &= ~0x04; break; - case NAND_CTL_CLRNCE: (*(volatile unsigned char *) (spia_io_base + spia_pedr)) |= 0x04; break; + bits = (ctrl & NAND_CNE) << 2; + bits |= (ctrl & NAND_CLE | NAND_ALE) >> 1; + writeb((readb(addr) & ~0x7) | bits, addr); } + + if (cmd != NAND_CMD_NONE) + writeb(cmd, chip->IO_ADDR_W); } /* @@ -133,7 +140,7 @@ static int __init spia_init(void) this->IO_ADDR_R = (void __iomem *)spia_fio_base; this->IO_ADDR_W = (void __iomem *)spia_fio_base; /* Set address of hardware control function */ - this->hwcontrol = spia_hwcontrol; + this->cmd_ctrl = spia_hwcontrol; /* 15 us command delay time */ this->chip_delay = 15; diff --git a/drivers/mtd/nand/toto.c b/drivers/mtd/nand/toto.c index 50aa6a46911f..a9cf0190c27a 100644 --- a/drivers/mtd/nand/toto.c +++ b/drivers/mtd/nand/toto.c @@ -32,6 +32,8 @@ #include <asm/arch-omap1510/hardware.h> #include <asm/arch/gpio.h> +#define CONFIG_NAND_WORKAROUND 1 + /* * MTD structure for TOTO board */ @@ -39,25 +41,6 @@ static struct mtd_info *toto_mtd = NULL; static unsigned long toto_io_base = OMAP_FLASH_1_BASE; -#define CONFIG_NAND_WORKAROUND 1 - -#define NAND_NCE 0x4000 -#define NAND_CLE 0x1000 -#define NAND_ALE 0x0002 -#define NAND_MASK (NAND_CLE | NAND_ALE | NAND_NCE) - -#define T_NAND_CTL_CLRALE(iob) gpiosetout(NAND_ALE, 0) -#define T_NAND_CTL_SETALE(iob) gpiosetout(NAND_ALE, NAND_ALE) -#ifdef CONFIG_NAND_WORKAROUND /* "some" dev boards busted, blue wired to rts2 :( */ -#define T_NAND_CTL_CLRCLE(iob) gpiosetout(NAND_CLE, 0); rts2setout(2, 2) -#define T_NAND_CTL_SETCLE(iob) gpiosetout(NAND_CLE, NAND_CLE); rts2setout(2, 0) -#else -#define T_NAND_CTL_CLRCLE(iob) gpiosetout(NAND_CLE, 0) -#define T_NAND_CTL_SETCLE(iob) gpiosetout(NAND_CLE, NAND_CLE) -#endif -#define T_NAND_CTL_SETNCE(iob) gpiosetout(NAND_NCE, 0) -#define T_NAND_CTL_CLRNCE(iob) gpiosetout(NAND_NCE, NAND_NCE) - /* * Define partitions for flash devices */ @@ -91,25 +74,43 @@ static struct mtd_partition partition_info32M[] = { #define NUM_PARTITIONS32M 3 #define NUM_PARTITIONS64M 4 + /* * hardware specific access to control-lines -*/ - -static void toto_hwcontrol(struct mtd_info *mtd, int cmd) + * + * ctrl: + * NAND_NCE: bit 0 -> bit 14 (0x4000) + * NAND_CLE: bit 1 -> bit 12 (0x1000) + * NAND_ALE: bit 2 -> bit 1 (0x0002) + */ +static void toto_hwcontrol(struct mtd_info *mtd, int cmd, + unsigned int ctrl) { + struct nand_chip *chip = mtd->priv; + + if (ctrl & NAND_CTRL_CHANGE) { + unsigned long bits; - udelay(1); /* hopefully enough time for tc make proceding write to clear */ - switch (cmd) { - case NAND_CTL_SETCLE: T_NAND_CTL_SETCLE(cmd); break; - case NAND_CTL_CLRCLE: T_NAND_CTL_CLRCLE(cmd); break; + /* hopefully enough time for tc make proceding write to clear */ + udelay(1); - case NAND_CTL_SETALE: T_NAND_CTL_SETALE(cmd); break; - case NAND_CTL_CLRALE: T_NAND_CTL_CLRALE(cmd); break; + bits = (~ctrl & NAND_NCE) << 14; + bits |= (ctrl & NAND_CLE) << 12; + bits |= (ctrl & NAND_ALE) >> 1; - case NAND_CTL_SETNCE: T_NAND_CTL_SETNCE(cmd); break; - case NAND_CTL_CLRNCE: T_NAND_CTL_CLRNCE(cmd); break; +#warning Wild guess as gpiosetout() is nowhere defined in the kernel source - tglx + gpiosetout(0x5002, bits); + +#ifdef CONFIG_NAND_WORKAROUND + /* "some" dev boards busted, blue wired to rts2 :( */ + rts2setout(2, (ctrl & NAND_CLE) << 1); +#endif + /* allow time to ensure gpio state to over take memory write */ + udelay(1); } - udelay(1); /* allow time to ensure gpio state to over take memory write */ + + if (cmd != NAND_CMD_NONE) + writeb(cmd, chip->IO_ADDR_W); } /* @@ -142,7 +143,7 @@ static int __init toto_init(void) /* Set address of NAND IO lines */ this->IO_ADDR_R = toto_io_base; this->IO_ADDR_W = toto_io_base; - this->hwcontrol = toto_hwcontrol; + this->cmd_ctrl = toto_hwcontrol; this->dev_ready = NULL; /* 25 us command delay time */ this->chip_delay = 30; diff --git a/drivers/mtd/nand/ts7250.c b/drivers/mtd/nand/ts7250.c index 70bce1b0326c..a0b4b1edcb0d 100644 --- a/drivers/mtd/nand/ts7250.c +++ b/drivers/mtd/nand/ts7250.c @@ -83,31 +83,29 @@ static struct mtd_partition partition_info128[] = { /* * hardware specific access to control-lines + * + * ctrl: + * NAND_NCE: bit 0 -> bit 2 + * NAND_CLE: bit 1 -> bit 1 + * NAND_ALE: bit 2 -> bit 0 */ -static void ts7250_hwcontrol(struct mtd_info *mtd, int cmd) +static void ts7250_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) { - unsigned long ctrl = TS72XX_NAND_CONTROL_VIRT_BASE; - - switch (cmd) { - case NAND_CTL_SETCLE: - __raw_writeb(__raw_readb(ctrl) | 0x2, ctrl); - break; - case NAND_CTL_CLRCLE: - __raw_writeb(__raw_readb(ctrl) & ~0x2, ctrl); - break; - case NAND_CTL_SETALE: - __raw_writeb(__raw_readb(ctrl) | 0x1, ctrl); - break; - case NAND_CTL_CLRALE: - __raw_writeb(__raw_readb(ctrl) & ~0x1, ctrl); - break; - case NAND_CTL_SETNCE: - __raw_writeb(__raw_readb(ctrl) | 0x4, ctrl); - break; - case NAND_CTL_CLRNCE: - __raw_writeb(__raw_readb(ctrl) & ~0x4, ctrl); - break; + struct nand_chip *chip = mtd->priv; + + if (ctrl & NAND_CTRL_CHANGE) { + unsigned long addr = TS72XX_NAND_CONTROL_VIRT_BASE; + unsigned char bits; + + bits = (ctrl & NAND_CNE) << 2; + bits |= ctrl & NAND_CLE; + bits |= (ctrl & NAND_ALE) >> 2; + + __raw_writeb((__raw_readb(addr) & ~0x7) | bits, addr); } + + if (cmd != NAND_CMD_NONE) + writeb(cmd, chip->IO_ADDR_W); } /* @@ -152,7 +150,7 @@ static int __init ts7250_init(void) /* insert callbacks */ this->IO_ADDR_R = (void *)TS72XX_NAND_DATA_VIRT_BASE; this->IO_ADDR_W = (void *)TS72XX_NAND_DATA_VIRT_BASE; - this->hwcontrol = ts7250_hwcontrol; + this->cmd_ctrl = ts7250_hwcontrol; this->dev_ready = ts7250_device_ready; this->chip_delay = 15; this->ecc.mode = NAND_ECC_SOFT; |