From a43e2b53a23bbd6955209a01a8388508f9205857 Mon Sep 17 00:00:00 2001 From: Marcin Juszkiewicz Date: Tue, 30 Oct 2007 15:21:19 +0000 Subject: linux-rp: update Tosa patchset in 2.6.22 and 2.6.23 - close #3233 USB Host patches are not updated --- packages/linux/linux-rp-2.6.23/tmio-nand-r8.patch | 1188 +++++++++++++++++++++ 1 file changed, 1188 insertions(+) create mode 100644 packages/linux/linux-rp-2.6.23/tmio-nand-r8.patch (limited to 'packages/linux/linux-rp-2.6.23/tmio-nand-r8.patch') diff --git a/packages/linux/linux-rp-2.6.23/tmio-nand-r8.patch b/packages/linux/linux-rp-2.6.23/tmio-nand-r8.patch new file mode 100644 index 0000000000..3a30c2f34c --- /dev/null +++ b/packages/linux/linux-rp-2.6.23/tmio-nand-r8.patch @@ -0,0 +1,1188 @@ + drivers/mtd/nand/Kconfig | 7 + + drivers/mtd/nand/Makefile | 1 + + drivers/mtd/nand/tmio.c | 554 +++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 562 insertions(+), 0 deletions(-) + +diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig +index f1d60b6..b9c8796 100644 +--- a/drivers/mtd/nand/Kconfig ++++ b/drivers/mtd/nand/Kconfig +@@ -69,6 +69,13 @@ config MTD_NAND_AMS_DELTA + help + Support for NAND flash on Amstrad E3 (Delta). + ++config MTD_NAND_TMIO ++ tristate "NAND Flash device on Toshiba Mobile IO Controller" ++ depends on MTD_NAND && TOSHIBA_TC6393XB ++ help ++ Support for NAND flash connected to a Toshiba Mobile IO ++ Controller in some PDAs, including the Sharp SL6000x. ++ + config MTD_NAND_TOTO + tristate "NAND Flash device on TOTO board" + depends on ARCH_OMAP && BROKEN +diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile +index edba1db..64f24e1 100644 +--- a/drivers/mtd/nand/Makefile ++++ b/drivers/mtd/nand/Makefile +@@ -27,5 +27,6 @@ obj-$(CONFIG_MTD_NAND_AT91) += at91_nand.o + obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o + obj-$(CONFIG_MTD_NAND_BASLER_EXCITE) += excite_nandflash.o + obj-$(CONFIG_MTD_NAND_PLATFORM) += plat_nand.o ++obj-$(CONFIG_MTD_NAND_TMIO) += tmio.o + + nand-objs := nand_base.o nand_bbt.o +diff --git a/drivers/mtd/nand/tmio.c b/drivers/mtd/nand/tmio.c +new file mode 100644 +index 0000000..d196553 +--- /dev/null ++++ b/drivers/mtd/nand/tmio.c +@@ -0,0 +1,554 @@ ++/* ++ * A device driver for NAND flash connected to a Toshiba Mobile IO ++ * controller. This is known to work with the following variants: ++ * TC6393XB revision 3 ++ * ++ * Maintainer: Chris Humbert ++ * ++ * Copyright (C) 2005 Chris Humbert ++ * Copyright (C) 2005 Dirk Opfer ++ * Copyright (C) 2004 SHARP ++ * Copyright (C) 2002 Lineo Japan, Inc. ++ * Copyright (C) Ian Molton and Sebastian Carlier ++ * ++ * Based on Sharp's NAND driver, sharp_sl_tc6393.c ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#define mtd_printk(level, mtd, format, arg...) \ ++ printk (level "%s: " format, mtd->name, ## arg) ++#define mtd_warn(mtd, format, arg...) \ ++ mtd_printk (KERN_WARNING, mtd, format, ## arg) ++ ++/*--------------------------------------------------------------------------*/ ++ ++/* tmio_nfcr.mode Register Command List */ ++#define FCR_MODE_DATA 0x94 // Data Data_Mode ++#define FCR_MODE_COMMAND 0x95 // Data Command_Mode ++#define FCR_MODE_ADDRESS 0x96 // Data Address_Mode ++ ++#define FCR_MODE_HWECC_CALC 0xB4 // HW-ECC Data ++#define FCR_MODE_HWECC_RESULT 0xD4 // HW-ECC Calculation Result Read_Mode ++#define FCR_MODE_HWECC_RESET 0xF4 // HW-ECC Reset ++ ++#define FCR_MODE_POWER_ON 0x0C // Power Supply ON to SSFDC card ++#define FCR_MODE_POWER_OFF 0x08 // Power Supply OFF to SSFDC card ++ ++#define FCR_MODE_LED_OFF 0x00 // LED OFF ++#define FCR_MODE_LED_ON 0x04 // LED ON ++ ++#define FCR_MODE_EJECT_ON 0x68 // Ejection Demand from Penguin is Advanced ++#define FCR_MODE_EJECT_OFF 0x08 // Ejection Demand from Penguin is Not Advanced ++ ++#define FCR_MODE_LOCK 0x6C // Operates By Lock_Mode. Ejection Switch is Invalid ++#define FCR_MODE_UNLOCK 0x0C // Operates By UnLock_Mode.Ejection Switch is Effective ++ ++#define FCR_MODE_CONTROLLER_ID 0x40 // Controller ID Read ++#define FCR_MODE_STANDBY 0x00 // SSFDC card Changes Standby State ++ ++#define FCR_MODE_WE 0x80 ++#define FCR_MODE_ECC1 0x40 ++#define FCR_MODE_ECC0 0x20 ++#define FCR_MODE_CE 0x10 ++#define FCR_MODE_PCNT1 0x08 ++#define FCR_MODE_PCNT0 0x04 ++#define FCR_MODE_ALE 0x02 ++#define FCR_MODE_CLE 0x01 ++ ++#define FCR_STATUS_BUSY 0x80 ++ ++/* ++ * NAND Flash Host Controller Configuration Register ++ */ ++struct tmio_nfhccr { ++ u8 x00[4]; ++ u16 command; /* 0x04 Command */ ++ u8 x01[0x0a]; ++ u16 base[2]; /* 0x10 NAND Flash Control Reg Base Addr*/ ++ u8 x02[0x29]; ++ u8 intp; /* 0x3d Interrupt Pin */ ++ u8 x03[0x0a]; ++ u8 inte; /* 0x48 Interrupt Enable */ ++ u8 x04; ++ u8 ec; /* 0x4a Event Control */ ++ u8 x05; ++ u8 icc; /* 0x4c Internal Clock Control */ ++ u8 x06[0x0e]; ++ u8 eccc; /* 0x5b ECC Control */ ++ u8 x07[4]; ++ u8 nftc; /* 0x60 NAND Flash Transaction Control */ ++ u8 nfm; /* 0x61 NAND Flash Monitor */ ++ u8 nfpsc; /* 0x62 NAND Flash Power Supply Control */ ++ u8 nfdc; /* 0x63 NAND Flash Detect Control */ ++ u8 x08[0x9c]; ++} __attribute__ ((packed)); ++ ++/* ++ * NAND Flash Control Register ++ */ ++struct tmio_nfcr { ++union { ++ u8 u8; /* 0x00 Data Register */ ++ u16 u16; ++ u32 u32; ++} __attribute__ ((packed)); ++ u8 mode; /* 0x04 Mode Register */ ++ u8 status; /* 0x05 Status Register */ ++ u8 isr; /* 0x06 Interrupt Status Register */ ++ u8 imr; /* 0x07 Interrupt Mask Register */ ++} __attribute__ ((packed)); ++ ++struct tmio_nand { ++ struct mtd_info mtd; ++ struct nand_chip chip; ++ ++ struct tmio_nfhccr __iomem * ccr; ++ struct tmio_nfcr __iomem * fcr; ++ ++ unsigned int irq; ++ ++ /* for tmio_nand_read_byte */ ++ u8 read; ++ unsigned read_good:1; ++}; ++ ++#define mtd_to_tmio(m) container_of(m, struct tmio_nand, mtd) ++ ++/*--------------------------------------------------------------------------*/ ++ ++static void tmio_nand_hwcontrol(struct mtd_info *mtd, int cmd, ++ unsigned int ctrl) ++{ ++ struct tmio_nand *tmio = mtd_to_tmio (mtd); ++ struct tmio_nfcr __iomem *fcr = tmio->fcr; ++ struct nand_chip *chip = mtd->priv; ++ ++ if (ctrl & NAND_CTRL_CHANGE) { ++ u8 mode; ++ ++ if (ctrl & NAND_NCE) { ++ mode = FCR_MODE_DATA; ++ ++ if (ctrl & NAND_CLE) ++ mode |= FCR_MODE_CLE; ++ else ++ mode &= ~FCR_MODE_CLE; ++ ++ if (ctrl & NAND_ALE) ++ mode |= FCR_MODE_ALE; ++ else ++ mode &= ~FCR_MODE_ALE; ++ } else { ++ mode = FCR_MODE_STANDBY; ++ } ++ ++ iowrite8 (mode, &fcr->mode); ++ tmio->read_good = 0; ++ } ++ ++ if (cmd != NAND_CMD_NONE) ++ writeb(cmd, chip->IO_ADDR_W); ++} ++ ++static int tmio_nand_dev_ready (struct mtd_info* mtd) ++{ ++ struct tmio_nand* tmio = mtd_to_tmio (mtd); ++ struct tmio_nfcr __iomem * fcr = tmio->fcr; ++ ++ return !(ioread8 (&fcr->status) & FCR_STATUS_BUSY); ++} ++ ++static irqreturn_t tmio_irq (int irq, void *__tmio) ++{ ++ struct tmio_nand* tmio = __tmio; ++ struct nand_chip* this = &tmio->chip; ++ struct tmio_nfcr __iomem * fcr = tmio->fcr; ++ ++ /* disable RDYREQ interrupt */ ++ iowrite8 (0x00, &fcr->imr); ++ ++ if (unlikely (!waitqueue_active (&this->controller->wq))) ++ printk (KERN_WARNING TMIO_NAME_NAND ": spurious interrupt\n"); ++ ++ wake_up (&this->controller->wq); ++ return IRQ_HANDLED; ++} ++ ++/* ++ * The TMIO core has a RDYREQ interrupt on the posedge of #SMRB. ++ * This interrupt is normally disabled, but for long operations like ++ * erase and write, we enable it to wake us up. The irq handler ++ * disables the interrupt. ++ */ ++static int ++tmio_nand_wait (struct mtd_info *mtd, struct nand_chip *this) ++{ ++ struct tmio_nand* tmio = mtd_to_tmio (mtd); ++ struct tmio_nfcr __iomem * fcr = tmio->fcr; ++ long timeout; ++ ++ /* enable RDYREQ interrupt */ ++ iowrite8 (0x0f, &fcr->isr); ++ iowrite8 (0x81, &fcr->imr); ++ ++ timeout = wait_event_timeout (this->controller->wq, tmio_nand_dev_ready (mtd), ++ msecs_to_jiffies (this->state == FL_ERASING ? 400 : 20)); ++ ++ if (unlikely (!tmio_nand_dev_ready (mtd))) { ++ iowrite8 (0x00, &fcr->imr); ++ mtd_warn (mtd, "still busy with %s after %d ms\n", ++ this->state == FL_ERASING ? "erase" : "program", ++ this->state == FL_ERASING ? 400 : 20); ++ ++ } else if (unlikely (!timeout)) { ++ iowrite8 (0x00, &fcr->imr); ++ mtd_warn (mtd, "timeout waiting for interrupt\n"); ++ } ++ ++ this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1); ++ return this->read_byte (mtd); ++} ++ ++/* ++ * The TMIO controller combines two 8-bit data bytes into one 16-bit ++ * word. This function separates them so nand_base.c works as expected, ++ * especially its NAND_CMD_READID routines. ++ * ++ * To prevent stale data from being read, tmio_nand_hwcontrol() clears ++ * tmio->read_good. ++ */ ++static u_char tmio_nand_read_byte (struct mtd_info *mtd) ++{ ++ struct tmio_nand* tmio = mtd_to_tmio (mtd); ++ struct tmio_nfcr __iomem * fcr = tmio->fcr; ++ unsigned int data; ++ ++ if (tmio->read_good--) ++ return tmio->read; ++ ++ data = ioread16 (&fcr->u16); ++ tmio->read = data >> 8; ++ return data; ++} ++ ++/* ++ * The TMIO controller converts an 8-bit NAND interface to a 16-bit ++ * bus interface, so all data reads and writes must be 16-bit wide. ++ * Thus, we implement 16-bit versions of the read, write, and verify ++ * buffer functions. ++ */ ++static void ++tmio_nand_write_buf (struct mtd_info *mtd, const u_char *buf, int len) ++{ ++ struct tmio_nand* tmio = mtd_to_tmio (mtd); ++ struct tmio_nfcr __iomem * fcr = tmio->fcr; ++ ++ iowrite16_rep (&fcr->u16, buf, len >> 1); ++} ++ ++static void tmio_nand_read_buf (struct mtd_info *mtd, u_char *buf, int len) ++{ ++ struct tmio_nand* tmio = mtd_to_tmio (mtd); ++ struct tmio_nfcr __iomem * fcr = tmio->fcr; ++ ++ ioread16_rep (&fcr->u16, buf, len >> 1); ++} ++ ++static int ++tmio_nand_verify_buf (struct mtd_info *mtd, const u_char *buf, int len) ++{ ++ struct tmio_nand* tmio = mtd_to_tmio (mtd); ++ struct tmio_nfcr __iomem * fcr = tmio->fcr; ++ u16* p = (u16*) buf; ++ ++ for (len >>= 1; len; len--) ++ if (*(p++) != ioread16 (&fcr->u16)) ++ return -EFAULT; ++ return 0; ++} ++ ++static void tmio_nand_enable_hwecc (struct mtd_info* mtd, int mode) ++{ ++ struct tmio_nand* tmio = mtd_to_tmio (mtd); ++ struct tmio_nfcr __iomem * fcr = tmio->fcr; ++ ++ iowrite8 (FCR_MODE_HWECC_RESET, &fcr->mode); ++ ioread8 (&fcr->u8); /* dummy read */ ++ iowrite8 (FCR_MODE_HWECC_CALC, &fcr->mode); ++} ++ ++static int tmio_nand_calculate_ecc (struct mtd_info* mtd, const u_char* dat, ++ u_char* ecc_code) ++{ ++ struct tmio_nand* tmio = mtd_to_tmio (mtd); ++ struct tmio_nfcr __iomem * fcr = tmio->fcr; ++ unsigned int ecc; ++ ++ iowrite8 (FCR_MODE_HWECC_RESULT, &fcr->mode); ++ ++ ecc = ioread16 (&fcr->u16); ++ ecc_code[1] = ecc; // 000-255 LP7-0 ++ ecc_code[0] = ecc >> 8; // 000-255 LP15-8 ++ ecc = ioread16 (&fcr->u16); ++ ecc_code[2] = ecc; // 000-255 CP5-0,11b ++ ecc_code[4] = ecc >> 8; // 256-511 LP7-0 ++ ecc = ioread16 (&fcr->u16); ++ ecc_code[3] = ecc; // 256-511 LP15-8 ++ ecc_code[5] = ecc >> 8; // 256-511 CP5-0,11b ++ ++ iowrite8 (FCR_MODE_DATA, &fcr->mode); ++ return 0; ++} ++ ++static void tmio_hw_init (struct device *dev, struct tmio_nand *tmio) ++{ ++ struct resource* nfcr = tmio_resource_control (dev); ++ struct tmio_device* tdev = dev_to_tdev (dev); ++ struct tmio_nfhccr __iomem * ccr = tmio->ccr; ++ struct tmio_nfcr __iomem * fcr = tmio->fcr; ++ unsigned long base; ++ ++ /* (89h) SMD Buffer ON By TC6393XB SystemConfig gpibfc1 */ ++ tdev->ops->clock (dev, 1); ++ tdev->ops->function (dev, 1); ++ ++ /* (4Ch) CLKRUN Enable 1st spcrunc */ ++ iowrite8 (0x81, &ccr->icc); ++ ++ /* (10h)BaseAddress 0x1000 spba.spba2 */ ++ base = nfcr->start - tdev->iomem->start; ++ iowrite16 (base, ccr->base + 0); ++ iowrite16 (base >> 16, ccr->base + 1); ++ ++ /* (04h)Command Register I/O spcmd */ ++ iowrite8 (0x02, &ccr->command); ++ ++ /* (62h) Power Supply Control ssmpwc */ ++ /* HardPowerOFF - SuspendOFF - PowerSupplyWait_4MS */ ++ iowrite8 (0x02, &ccr->nfpsc); ++ ++ /* (63h) Detect Control ssmdtc */ ++ iowrite8 (0x02, &ccr->nfdc); ++ ++ /* Interrupt status register clear sintst */ ++ iowrite8 (0x0f, &fcr->isr); ++ ++ /* After power supply, Media are reset smode */ ++ iowrite8 (FCR_MODE_POWER_ON, &fcr->mode); ++ iowrite8 (FCR_MODE_COMMAND, &fcr->mode); ++ iowrite8 (NAND_CMD_RESET, &fcr->u8); ++ ++ /* Standby Mode smode */ ++ iowrite8 (FCR_MODE_STANDBY, &fcr->mode); ++ ++ mdelay (5); ++} ++ ++static void tmio_hw_stop (struct device *dev, struct tmio_nand *tmio) ++{ ++ struct tmio_device* tdev = dev_to_tdev (dev); ++ struct tmio_nfcr __iomem * fcr = tmio->fcr; ++ ++ iowrite8 (FCR_MODE_POWER_OFF, &fcr->mode); ++ tdev->ops->function (dev, 0); ++ tdev->ops->clock (dev, 0); ++} ++ ++/*--------------------------------------------------------------------------*/ ++ ++#ifdef CONFIG_MTD_PARTITIONS ++static const char *part_probes[] = { "cmdlinepart", NULL }; ++#endif ++ ++static int tmio_probe (struct device *dev) ++{ ++ struct tmio_device* tdev = dev_to_tdev (dev); ++ struct tmio_nand_platform_data* tnpd = dev->platform_data; ++ struct resource* ccr = tmio_resource_config (dev); ++ struct resource* fcr = tmio_resource_control (dev); ++ struct resource* irq = tmio_resource_irq (dev); ++ struct tmio_nand* tmio; ++ struct mtd_info* mtd; ++ struct nand_chip* this; ++ struct mtd_partition* parts; ++ int nbparts = 0; ++ int retval; ++ ++ if (!tnpd) ++ return -EINVAL; ++ ++ retval = request_resource (tdev->iomem, ccr); ++ if (retval) ++ goto err_request_ccr; ++ ++ retval = request_resource (tdev->iomem, fcr); ++ if (retval) ++ goto err_request_fcr; ++ ++ tmio = kzalloc (sizeof *tmio, GFP_KERNEL); ++ if (!tmio) { ++ retval = -ENOMEM; ++ goto err_kzalloc; ++ } ++ ++ dev_set_drvdata (dev, tmio); ++ mtd = &tmio->mtd; ++ this = &tmio->chip; ++ mtd->priv = this; ++ mtd->name = TMIO_NAME_NAND; ++ ++ tmio->ccr = ioremap (ccr->start, ccr->end - ccr->start + 1); ++ if (!tmio->ccr) { ++ retval = -EIO; ++ goto err_iomap_ccr; ++ } ++ ++ tmio->fcr = ioremap (fcr->start, fcr->end - fcr->start + 1); ++ if (!tmio->fcr) { ++ retval = -EIO; ++ goto err_iomap_fcr; ++ } ++ ++ tmio_hw_init (dev, tmio); ++ ++ /* Set address of NAND IO lines */ ++ this->IO_ADDR_R = tmio->fcr; ++ this->IO_ADDR_W = tmio->fcr; ++ ++ /* Set address of hardware control function */ ++ this->cmd_ctrl = tmio_nand_hwcontrol; ++ this->dev_ready = tmio_nand_dev_ready; ++ this->read_byte = tmio_nand_read_byte; ++ this->write_buf = tmio_nand_write_buf; ++ this->read_buf = tmio_nand_read_buf; ++ this->verify_buf = tmio_nand_verify_buf; ++ ++ /* set eccmode using hardware ECC */ ++ this->ecc.mode = NAND_ECC_HW; ++ this->ecc.size = 512; ++ this->ecc.bytes = 6; ++ this->ecc.hwctl = tmio_nand_enable_hwecc; ++ this->ecc.calculate = tmio_nand_calculate_ecc; ++ this->ecc.correct = nand_correct_data; ++ this->badblock_pattern = tnpd->badblock_pattern; ++ ++ /* 15 us command delay time */ ++ this->chip_delay = 15; ++ ++ if (irq->start) { ++ retval = request_irq (irq->start, &tmio_irq, ++ IRQF_DISABLED, irq->name, tmio); ++ if (!retval) { ++ tmio->irq = irq->start; ++ this->waitfunc = tmio_nand_wait; ++ } else ++ mtd_warn (mtd, "request_irq error %d\n", retval); ++ } ++ ++ /* Scan to find existence of the device */ ++ if (nand_scan (mtd, 1)) { ++ retval = -ENODEV; ++ goto err_scan; ++ } ++ ++ /* Register the partitions */ ++#ifdef CONFIG_MTD_PARTITIONS ++ nbparts = parse_mtd_partitions (mtd, part_probes, &parts, 0); ++#endif ++ if (nbparts <= 0) { ++ parts = tnpd->partition; ++ nbparts = tnpd->num_partitions; ++ } ++ ++ add_mtd_partitions (mtd, parts, nbparts); ++ return 0; ++ ++err_scan: ++ if (tmio->irq) ++ free_irq (tmio->irq, tmio); ++ tmio_hw_stop (dev, tmio); ++ iounmap (tmio->fcr); ++err_iomap_fcr: ++ iounmap (tmio->ccr); ++err_iomap_ccr: ++ kfree (tmio); ++err_kzalloc: ++ release_resource (fcr); ++err_request_fcr: ++ release_resource (ccr); ++err_request_ccr: ++ return retval; ++} ++ ++static int tmio_remove (struct device *dev) ++{ ++ struct tmio_nand* tmio = dev_get_drvdata (dev); ++ ++ nand_release (&tmio->mtd); ++ if (tmio->irq) ++ free_irq (tmio->irq, tmio); ++ tmio_hw_stop (dev, tmio); ++ iounmap (tmio->fcr); ++ iounmap (tmio->ccr); ++ kfree (tmio); ++ release_resource (tmio_resource_control (dev)); ++ release_resource (tmio_resource_config (dev)); ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++static int tmio_suspend (struct device *dev, pm_message_t state) ++{ ++ tmio_hw_stop (dev, dev_get_drvdata (dev)); ++ return 0; ++} ++ ++static int tmio_resume (struct device *dev) ++{ ++ tmio_hw_init (dev, dev_get_drvdata (dev)); ++ return 0; ++} ++#endif ++ ++static struct device_driver tmio_driver = { ++ .name = TMIO_NAME_NAND, ++ .bus = &tmio_bus_type, ++ .probe = tmio_probe, ++ .remove = tmio_remove, ++#ifdef CONFIG_PM ++ .suspend = tmio_suspend, ++ .resume = tmio_resume, ++#endif ++}; ++ ++static int __init tmio_init (void) { ++ return driver_register (&tmio_driver); ++} ++ ++static void __exit tmio_exit (void) { ++ driver_unregister (&tmio_driver); ++} ++ ++module_init (tmio_init); ++module_exit (tmio_exit); ++ ++MODULE_LICENSE ("GPL"); ++MODULE_AUTHOR ("Dirk Opfer, Chris Humbert"); ++MODULE_DESCRIPTION ("NAND flash driver on Toshiba Mobile IO controller"); + drivers/mtd/nand/Kconfig | 7 + + drivers/mtd/nand/Makefile | 1 + + drivers/mtd/nand/tmio.c | 554 +++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 562 insertions(+), 0 deletions(-) + +diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig +index f1d60b6..b9c8796 100644 +--- a/drivers/mtd/nand/Kconfig ++++ b/drivers/mtd/nand/Kconfig +@@ -69,6 +69,13 @@ config MTD_NAND_AMS_DELTA + help + Support for NAND flash on Amstrad E3 (Delta). + ++config MTD_NAND_TMIO ++ tristate "NAND Flash device on Toshiba Mobile IO Controller" ++ depends on MTD_NAND && TOSHIBA_TC6393XB ++ help ++ Support for NAND flash connected to a Toshiba Mobile IO ++ Controller in some PDAs, including the Sharp SL6000x. ++ + config MTD_NAND_TOTO + tristate "NAND Flash device on TOTO board" + depends on ARCH_OMAP && BROKEN +diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile +index edba1db..64f24e1 100644 +--- a/drivers/mtd/nand/Makefile ++++ b/drivers/mtd/nand/Makefile +@@ -27,5 +27,6 @@ obj-$(CONFIG_MTD_NAND_AT91) += at91_nand.o + obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o + obj-$(CONFIG_MTD_NAND_BASLER_EXCITE) += excite_nandflash.o + obj-$(CONFIG_MTD_NAND_PLATFORM) += plat_nand.o ++obj-$(CONFIG_MTD_NAND_TMIO) += tmio.o + + nand-objs := nand_base.o nand_bbt.o +diff --git a/drivers/mtd/nand/tmio.c b/drivers/mtd/nand/tmio.c +new file mode 100644 +index 0000000..d196553 +--- /dev/null ++++ b/drivers/mtd/nand/tmio.c +@@ -0,0 +1,554 @@ ++/* ++ * A device driver for NAND flash connected to a Toshiba Mobile IO ++ * controller. This is known to work with the following variants: ++ * TC6393XB revision 3 ++ * ++ * Maintainer: Chris Humbert ++ * ++ * Copyright (C) 2005 Chris Humbert ++ * Copyright (C) 2005 Dirk Opfer ++ * Copyright (C) 2004 SHARP ++ * Copyright (C) 2002 Lineo Japan, Inc. ++ * Copyright (C) Ian Molton and Sebastian Carlier ++ * ++ * Based on Sharp's NAND driver, sharp_sl_tc6393.c ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#define mtd_printk(level, mtd, format, arg...) \ ++ printk (level "%s: " format, mtd->name, ## arg) ++#define mtd_warn(mtd, format, arg...) \ ++ mtd_printk (KERN_WARNING, mtd, format, ## arg) ++ ++/*--------------------------------------------------------------------------*/ ++ ++/* tmio_nfcr.mode Register Command List */ ++#define FCR_MODE_DATA 0x94 // Data Data_Mode ++#define FCR_MODE_COMMAND 0x95 // Data Command_Mode ++#define FCR_MODE_ADDRESS 0x96 // Data Address_Mode ++ ++#define FCR_MODE_HWECC_CALC 0xB4 // HW-ECC Data ++#define FCR_MODE_HWECC_RESULT 0xD4 // HW-ECC Calculation Result Read_Mode ++#define FCR_MODE_HWECC_RESET 0xF4 // HW-ECC Reset ++ ++#define FCR_MODE_POWER_ON 0x0C // Power Supply ON to SSFDC card ++#define FCR_MODE_POWER_OFF 0x08 // Power Supply OFF to SSFDC card ++ ++#define FCR_MODE_LED_OFF 0x00 // LED OFF ++#define FCR_MODE_LED_ON 0x04 // LED ON ++ ++#define FCR_MODE_EJECT_ON 0x68 // Ejection Demand from Penguin is Advanced ++#define FCR_MODE_EJECT_OFF 0x08 // Ejection Demand from Penguin is Not Advanced ++ ++#define FCR_MODE_LOCK 0x6C // Operates By Lock_Mode. Ejection Switch is Invalid ++#define FCR_MODE_UNLOCK 0x0C // Operates By UnLock_Mode.Ejection Switch is Effective ++ ++#define FCR_MODE_CONTROLLER_ID 0x40 // Controller ID Read ++#define FCR_MODE_STANDBY 0x00 // SSFDC card Changes Standby State ++ ++#define FCR_MODE_WE 0x80 ++#define FCR_MODE_ECC1 0x40 ++#define FCR_MODE_ECC0 0x20 ++#define FCR_MODE_CE 0x10 ++#define FCR_MODE_PCNT1 0x08 ++#define FCR_MODE_PCNT0 0x04 ++#define FCR_MODE_ALE 0x02 ++#define FCR_MODE_CLE 0x01 ++ ++#define FCR_STATUS_BUSY 0x80 ++ ++/* ++ * NAND Flash Host Controller Configuration Register ++ */ ++struct tmio_nfhccr { ++ u8 x00[4]; ++ u16 command; /* 0x04 Command */ ++ u8 x01[0x0a]; ++ u16 base[2]; /* 0x10 NAND Flash Control Reg Base Addr*/ ++ u8 x02[0x29]; ++ u8 intp; /* 0x3d Interrupt Pin */ ++ u8 x03[0x0a]; ++ u8 inte; /* 0x48 Interrupt Enable */ ++ u8 x04; ++ u8 ec; /* 0x4a Event Control */ ++ u8 x05; ++ u8 icc; /* 0x4c Internal Clock Control */ ++ u8 x06[0x0e]; ++ u8 eccc; /* 0x5b ECC Control */ ++ u8 x07[4]; ++ u8 nftc; /* 0x60 NAND Flash Transaction Control */ ++ u8 nfm; /* 0x61 NAND Flash Monitor */ ++ u8 nfpsc; /* 0x62 NAND Flash Power Supply Control */ ++ u8 nfdc; /* 0x63 NAND Flash Detect Control */ ++ u8 x08[0x9c]; ++} __attribute__ ((packed)); ++ ++/* ++ * NAND Flash Control Register ++ */ ++struct tmio_nfcr { ++union { ++ u8 u8; /* 0x00 Data Register */ ++ u16 u16; ++ u32 u32; ++} __attribute__ ((packed)); ++ u8 mode; /* 0x04 Mode Register */ ++ u8 status; /* 0x05 Status Register */ ++ u8 isr; /* 0x06 Interrupt Status Register */ ++ u8 imr; /* 0x07 Interrupt Mask Register */ ++} __attribute__ ((packed)); ++ ++struct tmio_nand { ++ struct mtd_info mtd; ++ struct nand_chip chip; ++ ++ struct tmio_nfhccr __iomem * ccr; ++ struct tmio_nfcr __iomem * fcr; ++ ++ unsigned int irq; ++ ++ /* for tmio_nand_read_byte */ ++ u8 read; ++ unsigned read_good:1; ++}; ++ ++#define mtd_to_tmio(m) container_of(m, struct tmio_nand, mtd) ++ ++/*--------------------------------------------------------------------------*/ ++ ++static void tmio_nand_hwcontrol(struct mtd_info *mtd, int cmd, ++ unsigned int ctrl) ++{ ++ struct tmio_nand *tmio = mtd_to_tmio (mtd); ++ struct tmio_nfcr __iomem *fcr = tmio->fcr; ++ struct nand_chip *chip = mtd->priv; ++ ++ if (ctrl & NAND_CTRL_CHANGE) { ++ u8 mode; ++ ++ if (ctrl & NAND_NCE) { ++ mode = FCR_MODE_DATA; ++ ++ if (ctrl & NAND_CLE) ++ mode |= FCR_MODE_CLE; ++ else ++ mode &= ~FCR_MODE_CLE; ++ ++ if (ctrl & NAND_ALE) ++ mode |= FCR_MODE_ALE; ++ else ++ mode &= ~FCR_MODE_ALE; ++ } else { ++ mode = FCR_MODE_STANDBY; ++ } ++ ++ iowrite8 (mode, &fcr->mode); ++ tmio->read_good = 0; ++ } ++ ++ if (cmd != NAND_CMD_NONE) ++ writeb(cmd, chip->IO_ADDR_W); ++} ++ ++static int tmio_nand_dev_ready (struct mtd_info* mtd) ++{ ++ struct tmio_nand* tmio = mtd_to_tmio (mtd); ++ struct tmio_nfcr __iomem * fcr = tmio->fcr; ++ ++ return !(ioread8 (&fcr->status) & FCR_STATUS_BUSY); ++} ++ ++static irqreturn_t tmio_irq (int irq, void *__tmio) ++{ ++ struct tmio_nand* tmio = __tmio; ++ struct nand_chip* this = &tmio->chip; ++ struct tmio_nfcr __iomem * fcr = tmio->fcr; ++ ++ /* disable RDYREQ interrupt */ ++ iowrite8 (0x00, &fcr->imr); ++ ++ if (unlikely (!waitqueue_active (&this->controller->wq))) ++ printk (KERN_WARNING TMIO_NAME_NAND ": spurious interrupt\n"); ++ ++ wake_up (&this->controller->wq); ++ return IRQ_HANDLED; ++} ++ ++/* ++ * The TMIO core has a RDYREQ interrupt on the posedge of #SMRB. ++ * This interrupt is normally disabled, but for long operations like ++ * erase and write, we enable it to wake us up. The irq handler ++ * disables the interrupt. ++ */ ++static int ++tmio_nand_wait (struct mtd_info *mtd, struct nand_chip *this) ++{ ++ struct tmio_nand* tmio = mtd_to_tmio (mtd); ++ struct tmio_nfcr __iomem * fcr = tmio->fcr; ++ long timeout; ++ ++ /* enable RDYREQ interrupt */ ++ iowrite8 (0x0f, &fcr->isr); ++ iowrite8 (0x81, &fcr->imr); ++ ++ timeout = wait_event_timeout (this->controller->wq, tmio_nand_dev_ready (mtd), ++ msecs_to_jiffies (this->state == FL_ERASING ? 400 : 20)); ++ ++ if (unlikely (!tmio_nand_dev_ready (mtd))) { ++ iowrite8 (0x00, &fcr->imr); ++ mtd_warn (mtd, "still busy with %s after %d ms\n", ++ this->state == FL_ERASING ? "erase" : "program", ++ this->state == FL_ERASING ? 400 : 20); ++ ++ } else if (unlikely (!timeout)) { ++ iowrite8 (0x00, &fcr->imr); ++ mtd_warn (mtd, "timeout waiting for interrupt\n"); ++ } ++ ++ this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1); ++ return this->read_byte (mtd); ++} ++ ++/* ++ * The TMIO controller combines two 8-bit data bytes into one 16-bit ++ * word. This function separates them so nand_base.c works as expected, ++ * especially its NAND_CMD_READID routines. ++ * ++ * To prevent stale data from being read, tmio_nand_hwcontrol() clears ++ * tmio->read_good. ++ */ ++static u_char tmio_nand_read_byte (struct mtd_info *mtd) ++{ ++ struct tmio_nand* tmio = mtd_to_tmio (mtd); ++ struct tmio_nfcr __iomem * fcr = tmio->fcr; ++ unsigned int data; ++ ++ if (tmio->read_good--) ++ return tmio->read; ++ ++ data = ioread16 (&fcr->u16); ++ tmio->read = data >> 8; ++ return data; ++} ++ ++/* ++ * The TMIO controller converts an 8-bit NAND interface to a 16-bit ++ * bus interface, so all data reads and writes must be 16-bit wide. ++ * Thus, we implement 16-bit versions of the read, write, and verify ++ * buffer functions. ++ */ ++static void ++tmio_nand_write_buf (struct mtd_info *mtd, const u_char *buf, int len) ++{ ++ struct tmio_nand* tmio = mtd_to_tmio (mtd); ++ struct tmio_nfcr __iomem * fcr = tmio->fcr; ++ ++ iowrite16_rep (&fcr->u16, buf, len >> 1); ++} ++ ++static void tmio_nand_read_buf (struct mtd_info *mtd, u_char *buf, int len) ++{ ++ struct tmio_nand* tmio = mtd_to_tmio (mtd); ++ struct tmio_nfcr __iomem * fcr = tmio->fcr; ++ ++ ioread16_rep (&fcr->u16, buf, len >> 1); ++} ++ ++static int ++tmio_nand_verify_buf (struct mtd_info *mtd, const u_char *buf, int len) ++{ ++ struct tmio_nand* tmio = mtd_to_tmio (mtd); ++ struct tmio_nfcr __iomem * fcr = tmio->fcr; ++ u16* p = (u16*) buf; ++ ++ for (len >>= 1; len; len--) ++ if (*(p++) != ioread16 (&fcr->u16)) ++ return -EFAULT; ++ return 0; ++} ++ ++static void tmio_nand_enable_hwecc (struct mtd_info* mtd, int mode) ++{ ++ struct tmio_nand* tmio = mtd_to_tmio (mtd); ++ struct tmio_nfcr __iomem * fcr = tmio->fcr; ++ ++ iowrite8 (FCR_MODE_HWECC_RESET, &fcr->mode); ++ ioread8 (&fcr->u8); /* dummy read */ ++ iowrite8 (FCR_MODE_HWECC_CALC, &fcr->mode); ++} ++ ++static int tmio_nand_calculate_ecc (struct mtd_info* mtd, const u_char* dat, ++ u_char* ecc_code) ++{ ++ struct tmio_nand* tmio = mtd_to_tmio (mtd); ++ struct tmio_nfcr __iomem * fcr = tmio->fcr; ++ unsigned int ecc; ++ ++ iowrite8 (FCR_MODE_HWECC_RESULT, &fcr->mode); ++ ++ ecc = ioread16 (&fcr->u16); ++ ecc_code[1] = ecc; // 000-255 LP7-0 ++ ecc_code[0] = ecc >> 8; // 000-255 LP15-8 ++ ecc = ioread16 (&fcr->u16); ++ ecc_code[2] = ecc; // 000-255 CP5-0,11b ++ ecc_code[4] = ecc >> 8; // 256-511 LP7-0 ++ ecc = ioread16 (&fcr->u16); ++ ecc_code[3] = ecc; // 256-511 LP15-8 ++ ecc_code[5] = ecc >> 8; // 256-511 CP5-0,11b ++ ++ iowrite8 (FCR_MODE_DATA, &fcr->mode); ++ return 0; ++} ++ ++static void tmio_hw_init (struct device *dev, struct tmio_nand *tmio) ++{ ++ struct resource* nfcr = tmio_resource_control (dev); ++ struct tmio_device* tdev = dev_to_tdev (dev); ++ struct tmio_nfhccr __iomem * ccr = tmio->ccr; ++ struct tmio_nfcr __iomem * fcr = tmio->fcr; ++ unsigned long base; ++ ++ /* (89h) SMD Buffer ON By TC6393XB SystemConfig gpibfc1 */ ++ tdev->ops->clock (dev, 1); ++ tdev->ops->function (dev, 1); ++ ++ /* (4Ch) CLKRUN Enable 1st spcrunc */ ++ iowrite8 (0x81, &ccr->icc); ++ ++ /* (10h)BaseAddress 0x1000 spba.spba2 */ ++ base = nfcr->start - tdev->iomem->start; ++ iowrite16 (base, ccr->base + 0); ++ iowrite16 (base >> 16, ccr->base + 1); ++ ++ /* (04h)Command Register I/O spcmd */ ++ iowrite8 (0x02, &ccr->command); ++ ++ /* (62h) Power Supply Control ssmpwc */ ++ /* HardPowerOFF - SuspendOFF - PowerSupplyWait_4MS */ ++ iowrite8 (0x02, &ccr->nfpsc); ++ ++ /* (63h) Detect Control ssmdtc */ ++ iowrite8 (0x02, &ccr->nfdc); ++ ++ /* Interrupt status register clear sintst */ ++ iowrite8 (0x0f, &fcr->isr); ++ ++ /* After power supply, Media are reset smode */ ++ iowrite8 (FCR_MODE_POWER_ON, &fcr->mode); ++ iowrite8 (FCR_MODE_COMMAND, &fcr->mode); ++ iowrite8 (NAND_CMD_RESET, &fcr->u8); ++ ++ /* Standby Mode smode */ ++ iowrite8 (FCR_MODE_STANDBY, &fcr->mode); ++ ++ mdelay (5); ++} ++ ++static void tmio_hw_stop (struct device *dev, struct tmio_nand *tmio) ++{ ++ struct tmio_device* tdev = dev_to_tdev (dev); ++ struct tmio_nfcr __iomem * fcr = tmio->fcr; ++ ++ iowrite8 (FCR_MODE_POWER_OFF, &fcr->mode); ++ tdev->ops->function (dev, 0); ++ tdev->ops->clock (dev, 0); ++} ++ ++/*--------------------------------------------------------------------------*/ ++ ++#ifdef CONFIG_MTD_PARTITIONS ++static const char *part_probes[] = { "cmdlinepart", NULL }; ++#endif ++ ++static int tmio_probe (struct device *dev) ++{ ++ struct tmio_device* tdev = dev_to_tdev (dev); ++ struct tmio_nand_platform_data* tnpd = dev->platform_data; ++ struct resource* ccr = tmio_resource_config (dev); ++ struct resource* fcr = tmio_resource_control (dev); ++ struct resource* irq = tmio_resource_irq (dev); ++ struct tmio_nand* tmio; ++ struct mtd_info* mtd; ++ struct nand_chip* this; ++ struct mtd_partition* parts; ++ int nbparts = 0; ++ int retval; ++ ++ if (!tnpd) ++ return -EINVAL; ++ ++ retval = request_resource (tdev->iomem, ccr); ++ if (retval) ++ goto err_request_ccr; ++ ++ retval = request_resource (tdev->iomem, fcr); ++ if (retval) ++ goto err_request_fcr; ++ ++ tmio = kzalloc (sizeof *tmio, GFP_KERNEL); ++ if (!tmio) { ++ retval = -ENOMEM; ++ goto err_kzalloc; ++ } ++ ++ dev_set_drvdata (dev, tmio); ++ mtd = &tmio->mtd; ++ this = &tmio->chip; ++ mtd->priv = this; ++ mtd->name = TMIO_NAME_NAND; ++ ++ tmio->ccr = ioremap (ccr->start, ccr->end - ccr->start + 1); ++ if (!tmio->ccr) { ++ retval = -EIO; ++ goto err_iomap_ccr; ++ } ++ ++ tmio->fcr = ioremap (fcr->start, fcr->end - fcr->start + 1); ++ if (!tmio->fcr) { ++ retval = -EIO; ++ goto err_iomap_fcr; ++ } ++ ++ tmio_hw_init (dev, tmio); ++ ++ /* Set address of NAND IO lines */ ++ this->IO_ADDR_R = tmio->fcr; ++ this->IO_ADDR_W = tmio->fcr; ++ ++ /* Set address of hardware control function */ ++ this->cmd_ctrl = tmio_nand_hwcontrol; ++ this->dev_ready = tmio_nand_dev_ready; ++ this->read_byte = tmio_nand_read_byte; ++ this->write_buf = tmio_nand_write_buf; ++ this->read_buf = tmio_nand_read_buf; ++ this->verify_buf = tmio_nand_verify_buf; ++ ++ /* set eccmode using hardware ECC */ ++ this->ecc.mode = NAND_ECC_HW; ++ this->ecc.size = 512; ++ this->ecc.bytes = 6; ++ this->ecc.hwctl = tmio_nand_enable_hwecc; ++ this->ecc.calculate = tmio_nand_calculate_ecc; ++ this->ecc.correct = nand_correct_data; ++ this->badblock_pattern = tnpd->badblock_pattern; ++ ++ /* 15 us command delay time */ ++ this->chip_delay = 15; ++ ++ if (irq->start) { ++ retval = request_irq (irq->start, &tmio_irq, ++ IRQF_DISABLED, irq->name, tmio); ++ if (!retval) { ++ tmio->irq = irq->start; ++ this->waitfunc = tmio_nand_wait; ++ } else ++ mtd_warn (mtd, "request_irq error %d\n", retval); ++ } ++ ++ /* Scan to find existence of the device */ ++ if (nand_scan (mtd, 1)) { ++ retval = -ENODEV; ++ goto err_scan; ++ } ++ ++ /* Register the partitions */ ++#ifdef CONFIG_MTD_PARTITIONS ++ nbparts = parse_mtd_partitions (mtd, part_probes, &parts, 0); ++#endif ++ if (nbparts <= 0) { ++ parts = tnpd->partition; ++ nbparts = tnpd->num_partitions; ++ } ++ ++ add_mtd_partitions (mtd, parts, nbparts); ++ return 0; ++ ++err_scan: ++ if (tmio->irq) ++ free_irq (tmio->irq, tmio); ++ tmio_hw_stop (dev, tmio); ++ iounmap (tmio->fcr); ++err_iomap_fcr: ++ iounmap (tmio->ccr); ++err_iomap_ccr: ++ kfree (tmio); ++err_kzalloc: ++ release_resource (fcr); ++err_request_fcr: ++ release_resource (ccr); ++err_request_ccr: ++ return retval; ++} ++ ++static int tmio_remove (struct device *dev) ++{ ++ struct tmio_nand* tmio = dev_get_drvdata (dev); ++ ++ nand_release (&tmio->mtd); ++ if (tmio->irq) ++ free_irq (tmio->irq, tmio); ++ tmio_hw_stop (dev, tmio); ++ iounmap (tmio->fcr); ++ iounmap (tmio->ccr); ++ kfree (tmio); ++ release_resource (tmio_resource_control (dev)); ++ release_resource (tmio_resource_config (dev)); ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++static int tmio_suspend (struct device *dev, pm_message_t state) ++{ ++ tmio_hw_stop (dev, dev_get_drvdata (dev)); ++ return 0; ++} ++ ++static int tmio_resume (struct device *dev) ++{ ++ tmio_hw_init (dev, dev_get_drvdata (dev)); ++ return 0; ++} ++#endif ++ ++static struct device_driver tmio_driver = { ++ .name = TMIO_NAME_NAND, ++ .bus = &tmio_bus_type, ++ .probe = tmio_probe, ++ .remove = tmio_remove, ++#ifdef CONFIG_PM ++ .suspend = tmio_suspend, ++ .resume = tmio_resume, ++#endif ++}; ++ ++static int __init tmio_init (void) { ++ return driver_register (&tmio_driver); ++} ++ ++static void __exit tmio_exit (void) { ++ driver_unregister (&tmio_driver); ++} ++ ++module_init (tmio_init); ++module_exit (tmio_exit); ++ ++MODULE_LICENSE ("GPL"); ++MODULE_AUTHOR ("Dirk Opfer, Chris Humbert"); ++MODULE_DESCRIPTION ("NAND flash driver on Toshiba Mobile IO controller"); -- cgit v1.2.3 From 566c8bb147d8ba79662edcd755883793e0c945f5 Mon Sep 17 00:00:00 2001 From: Marcin Juszkiewicz Date: Wed, 31 Oct 2007 10:44:22 +0000 Subject: linux-rp: cleaned Tosa patches (my fault) --- packages/linux/linux-rp-2.6.23/tmio-nand-r8.patch | 594 ---------------------- 1 file changed, 594 deletions(-) (limited to 'packages/linux/linux-rp-2.6.23/tmio-nand-r8.patch') diff --git a/packages/linux/linux-rp-2.6.23/tmio-nand-r8.patch b/packages/linux/linux-rp-2.6.23/tmio-nand-r8.patch index 3a30c2f34c..a71fd114a8 100644 --- a/packages/linux/linux-rp-2.6.23/tmio-nand-r8.patch +++ b/packages/linux/linux-rp-2.6.23/tmio-nand-r8.patch @@ -592,597 +592,3 @@ index 0000000..d196553 +MODULE_LICENSE ("GPL"); +MODULE_AUTHOR ("Dirk Opfer, Chris Humbert"); +MODULE_DESCRIPTION ("NAND flash driver on Toshiba Mobile IO controller"); - drivers/mtd/nand/Kconfig | 7 + - drivers/mtd/nand/Makefile | 1 + - drivers/mtd/nand/tmio.c | 554 +++++++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 562 insertions(+), 0 deletions(-) - -diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig -index f1d60b6..b9c8796 100644 ---- a/drivers/mtd/nand/Kconfig -+++ b/drivers/mtd/nand/Kconfig -@@ -69,6 +69,13 @@ config MTD_NAND_AMS_DELTA - help - Support for NAND flash on Amstrad E3 (Delta). - -+config MTD_NAND_TMIO -+ tristate "NAND Flash device on Toshiba Mobile IO Controller" -+ depends on MTD_NAND && TOSHIBA_TC6393XB -+ help -+ Support for NAND flash connected to a Toshiba Mobile IO -+ Controller in some PDAs, including the Sharp SL6000x. -+ - config MTD_NAND_TOTO - tristate "NAND Flash device on TOTO board" - depends on ARCH_OMAP && BROKEN -diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile -index edba1db..64f24e1 100644 ---- a/drivers/mtd/nand/Makefile -+++ b/drivers/mtd/nand/Makefile -@@ -27,5 +27,6 @@ obj-$(CONFIG_MTD_NAND_AT91) += at91_nand.o - obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o - obj-$(CONFIG_MTD_NAND_BASLER_EXCITE) += excite_nandflash.o - obj-$(CONFIG_MTD_NAND_PLATFORM) += plat_nand.o -+obj-$(CONFIG_MTD_NAND_TMIO) += tmio.o - - nand-objs := nand_base.o nand_bbt.o -diff --git a/drivers/mtd/nand/tmio.c b/drivers/mtd/nand/tmio.c -new file mode 100644 -index 0000000..d196553 ---- /dev/null -+++ b/drivers/mtd/nand/tmio.c -@@ -0,0 +1,554 @@ -+/* -+ * A device driver for NAND flash connected to a Toshiba Mobile IO -+ * controller. This is known to work with the following variants: -+ * TC6393XB revision 3 -+ * -+ * Maintainer: Chris Humbert -+ * -+ * Copyright (C) 2005 Chris Humbert -+ * Copyright (C) 2005 Dirk Opfer -+ * Copyright (C) 2004 SHARP -+ * Copyright (C) 2002 Lineo Japan, Inc. -+ * Copyright (C) Ian Molton and Sebastian Carlier -+ * -+ * Based on Sharp's NAND driver, sharp_sl_tc6393.c -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+#define mtd_printk(level, mtd, format, arg...) \ -+ printk (level "%s: " format, mtd->name, ## arg) -+#define mtd_warn(mtd, format, arg...) \ -+ mtd_printk (KERN_WARNING, mtd, format, ## arg) -+ -+/*--------------------------------------------------------------------------*/ -+ -+/* tmio_nfcr.mode Register Command List */ -+#define FCR_MODE_DATA 0x94 // Data Data_Mode -+#define FCR_MODE_COMMAND 0x95 // Data Command_Mode -+#define FCR_MODE_ADDRESS 0x96 // Data Address_Mode -+ -+#define FCR_MODE_HWECC_CALC 0xB4 // HW-ECC Data -+#define FCR_MODE_HWECC_RESULT 0xD4 // HW-ECC Calculation Result Read_Mode -+#define FCR_MODE_HWECC_RESET 0xF4 // HW-ECC Reset -+ -+#define FCR_MODE_POWER_ON 0x0C // Power Supply ON to SSFDC card -+#define FCR_MODE_POWER_OFF 0x08 // Power Supply OFF to SSFDC card -+ -+#define FCR_MODE_LED_OFF 0x00 // LED OFF -+#define FCR_MODE_LED_ON 0x04 // LED ON -+ -+#define FCR_MODE_EJECT_ON 0x68 // Ejection Demand from Penguin is Advanced -+#define FCR_MODE_EJECT_OFF 0x08 // Ejection Demand from Penguin is Not Advanced -+ -+#define FCR_MODE_LOCK 0x6C // Operates By Lock_Mode. Ejection Switch is Invalid -+#define FCR_MODE_UNLOCK 0x0C // Operates By UnLock_Mode.Ejection Switch is Effective -+ -+#define FCR_MODE_CONTROLLER_ID 0x40 // Controller ID Read -+#define FCR_MODE_STANDBY 0x00 // SSFDC card Changes Standby State -+ -+#define FCR_MODE_WE 0x80 -+#define FCR_MODE_ECC1 0x40 -+#define FCR_MODE_ECC0 0x20 -+#define FCR_MODE_CE 0x10 -+#define FCR_MODE_PCNT1 0x08 -+#define FCR_MODE_PCNT0 0x04 -+#define FCR_MODE_ALE 0x02 -+#define FCR_MODE_CLE 0x01 -+ -+#define FCR_STATUS_BUSY 0x80 -+ -+/* -+ * NAND Flash Host Controller Configuration Register -+ */ -+struct tmio_nfhccr { -+ u8 x00[4]; -+ u16 command; /* 0x04 Command */ -+ u8 x01[0x0a]; -+ u16 base[2]; /* 0x10 NAND Flash Control Reg Base Addr*/ -+ u8 x02[0x29]; -+ u8 intp; /* 0x3d Interrupt Pin */ -+ u8 x03[0x0a]; -+ u8 inte; /* 0x48 Interrupt Enable */ -+ u8 x04; -+ u8 ec; /* 0x4a Event Control */ -+ u8 x05; -+ u8 icc; /* 0x4c Internal Clock Control */ -+ u8 x06[0x0e]; -+ u8 eccc; /* 0x5b ECC Control */ -+ u8 x07[4]; -+ u8 nftc; /* 0x60 NAND Flash Transaction Control */ -+ u8 nfm; /* 0x61 NAND Flash Monitor */ -+ u8 nfpsc; /* 0x62 NAND Flash Power Supply Control */ -+ u8 nfdc; /* 0x63 NAND Flash Detect Control */ -+ u8 x08[0x9c]; -+} __attribute__ ((packed)); -+ -+/* -+ * NAND Flash Control Register -+ */ -+struct tmio_nfcr { -+union { -+ u8 u8; /* 0x00 Data Register */ -+ u16 u16; -+ u32 u32; -+} __attribute__ ((packed)); -+ u8 mode; /* 0x04 Mode Register */ -+ u8 status; /* 0x05 Status Register */ -+ u8 isr; /* 0x06 Interrupt Status Register */ -+ u8 imr; /* 0x07 Interrupt Mask Register */ -+} __attribute__ ((packed)); -+ -+struct tmio_nand { -+ struct mtd_info mtd; -+ struct nand_chip chip; -+ -+ struct tmio_nfhccr __iomem * ccr; -+ struct tmio_nfcr __iomem * fcr; -+ -+ unsigned int irq; -+ -+ /* for tmio_nand_read_byte */ -+ u8 read; -+ unsigned read_good:1; -+}; -+ -+#define mtd_to_tmio(m) container_of(m, struct tmio_nand, mtd) -+ -+/*--------------------------------------------------------------------------*/ -+ -+static void tmio_nand_hwcontrol(struct mtd_info *mtd, int cmd, -+ unsigned int ctrl) -+{ -+ struct tmio_nand *tmio = mtd_to_tmio (mtd); -+ struct tmio_nfcr __iomem *fcr = tmio->fcr; -+ struct nand_chip *chip = mtd->priv; -+ -+ if (ctrl & NAND_CTRL_CHANGE) { -+ u8 mode; -+ -+ if (ctrl & NAND_NCE) { -+ mode = FCR_MODE_DATA; -+ -+ if (ctrl & NAND_CLE) -+ mode |= FCR_MODE_CLE; -+ else -+ mode &= ~FCR_MODE_CLE; -+ -+ if (ctrl & NAND_ALE) -+ mode |= FCR_MODE_ALE; -+ else -+ mode &= ~FCR_MODE_ALE; -+ } else { -+ mode = FCR_MODE_STANDBY; -+ } -+ -+ iowrite8 (mode, &fcr->mode); -+ tmio->read_good = 0; -+ } -+ -+ if (cmd != NAND_CMD_NONE) -+ writeb(cmd, chip->IO_ADDR_W); -+} -+ -+static int tmio_nand_dev_ready (struct mtd_info* mtd) -+{ -+ struct tmio_nand* tmio = mtd_to_tmio (mtd); -+ struct tmio_nfcr __iomem * fcr = tmio->fcr; -+ -+ return !(ioread8 (&fcr->status) & FCR_STATUS_BUSY); -+} -+ -+static irqreturn_t tmio_irq (int irq, void *__tmio) -+{ -+ struct tmio_nand* tmio = __tmio; -+ struct nand_chip* this = &tmio->chip; -+ struct tmio_nfcr __iomem * fcr = tmio->fcr; -+ -+ /* disable RDYREQ interrupt */ -+ iowrite8 (0x00, &fcr->imr); -+ -+ if (unlikely (!waitqueue_active (&this->controller->wq))) -+ printk (KERN_WARNING TMIO_NAME_NAND ": spurious interrupt\n"); -+ -+ wake_up (&this->controller->wq); -+ return IRQ_HANDLED; -+} -+ -+/* -+ * The TMIO core has a RDYREQ interrupt on the posedge of #SMRB. -+ * This interrupt is normally disabled, but for long operations like -+ * erase and write, we enable it to wake us up. The irq handler -+ * disables the interrupt. -+ */ -+static int -+tmio_nand_wait (struct mtd_info *mtd, struct nand_chip *this) -+{ -+ struct tmio_nand* tmio = mtd_to_tmio (mtd); -+ struct tmio_nfcr __iomem * fcr = tmio->fcr; -+ long timeout; -+ -+ /* enable RDYREQ interrupt */ -+ iowrite8 (0x0f, &fcr->isr); -+ iowrite8 (0x81, &fcr->imr); -+ -+ timeout = wait_event_timeout (this->controller->wq, tmio_nand_dev_ready (mtd), -+ msecs_to_jiffies (this->state == FL_ERASING ? 400 : 20)); -+ -+ if (unlikely (!tmio_nand_dev_ready (mtd))) { -+ iowrite8 (0x00, &fcr->imr); -+ mtd_warn (mtd, "still busy with %s after %d ms\n", -+ this->state == FL_ERASING ? "erase" : "program", -+ this->state == FL_ERASING ? 400 : 20); -+ -+ } else if (unlikely (!timeout)) { -+ iowrite8 (0x00, &fcr->imr); -+ mtd_warn (mtd, "timeout waiting for interrupt\n"); -+ } -+ -+ this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1); -+ return this->read_byte (mtd); -+} -+ -+/* -+ * The TMIO controller combines two 8-bit data bytes into one 16-bit -+ * word. This function separates them so nand_base.c works as expected, -+ * especially its NAND_CMD_READID routines. -+ * -+ * To prevent stale data from being read, tmio_nand_hwcontrol() clears -+ * tmio->read_good. -+ */ -+static u_char tmio_nand_read_byte (struct mtd_info *mtd) -+{ -+ struct tmio_nand* tmio = mtd_to_tmio (mtd); -+ struct tmio_nfcr __iomem * fcr = tmio->fcr; -+ unsigned int data; -+ -+ if (tmio->read_good--) -+ return tmio->read; -+ -+ data = ioread16 (&fcr->u16); -+ tmio->read = data >> 8; -+ return data; -+} -+ -+/* -+ * The TMIO controller converts an 8-bit NAND interface to a 16-bit -+ * bus interface, so all data reads and writes must be 16-bit wide. -+ * Thus, we implement 16-bit versions of the read, write, and verify -+ * buffer functions. -+ */ -+static void -+tmio_nand_write_buf (struct mtd_info *mtd, const u_char *buf, int len) -+{ -+ struct tmio_nand* tmio = mtd_to_tmio (mtd); -+ struct tmio_nfcr __iomem * fcr = tmio->fcr; -+ -+ iowrite16_rep (&fcr->u16, buf, len >> 1); -+} -+ -+static void tmio_nand_read_buf (struct mtd_info *mtd, u_char *buf, int len) -+{ -+ struct tmio_nand* tmio = mtd_to_tmio (mtd); -+ struct tmio_nfcr __iomem * fcr = tmio->fcr; -+ -+ ioread16_rep (&fcr->u16, buf, len >> 1); -+} -+ -+static int -+tmio_nand_verify_buf (struct mtd_info *mtd, const u_char *buf, int len) -+{ -+ struct tmio_nand* tmio = mtd_to_tmio (mtd); -+ struct tmio_nfcr __iomem * fcr = tmio->fcr; -+ u16* p = (u16*) buf; -+ -+ for (len >>= 1; len; len--) -+ if (*(p++) != ioread16 (&fcr->u16)) -+ return -EFAULT; -+ return 0; -+} -+ -+static void tmio_nand_enable_hwecc (struct mtd_info* mtd, int mode) -+{ -+ struct tmio_nand* tmio = mtd_to_tmio (mtd); -+ struct tmio_nfcr __iomem * fcr = tmio->fcr; -+ -+ iowrite8 (FCR_MODE_HWECC_RESET, &fcr->mode); -+ ioread8 (&fcr->u8); /* dummy read */ -+ iowrite8 (FCR_MODE_HWECC_CALC, &fcr->mode); -+} -+ -+static int tmio_nand_calculate_ecc (struct mtd_info* mtd, const u_char* dat, -+ u_char* ecc_code) -+{ -+ struct tmio_nand* tmio = mtd_to_tmio (mtd); -+ struct tmio_nfcr __iomem * fcr = tmio->fcr; -+ unsigned int ecc; -+ -+ iowrite8 (FCR_MODE_HWECC_RESULT, &fcr->mode); -+ -+ ecc = ioread16 (&fcr->u16); -+ ecc_code[1] = ecc; // 000-255 LP7-0 -+ ecc_code[0] = ecc >> 8; // 000-255 LP15-8 -+ ecc = ioread16 (&fcr->u16); -+ ecc_code[2] = ecc; // 000-255 CP5-0,11b -+ ecc_code[4] = ecc >> 8; // 256-511 LP7-0 -+ ecc = ioread16 (&fcr->u16); -+ ecc_code[3] = ecc; // 256-511 LP15-8 -+ ecc_code[5] = ecc >> 8; // 256-511 CP5-0,11b -+ -+ iowrite8 (FCR_MODE_DATA, &fcr->mode); -+ return 0; -+} -+ -+static void tmio_hw_init (struct device *dev, struct tmio_nand *tmio) -+{ -+ struct resource* nfcr = tmio_resource_control (dev); -+ struct tmio_device* tdev = dev_to_tdev (dev); -+ struct tmio_nfhccr __iomem * ccr = tmio->ccr; -+ struct tmio_nfcr __iomem * fcr = tmio->fcr; -+ unsigned long base; -+ -+ /* (89h) SMD Buffer ON By TC6393XB SystemConfig gpibfc1 */ -+ tdev->ops->clock (dev, 1); -+ tdev->ops->function (dev, 1); -+ -+ /* (4Ch) CLKRUN Enable 1st spcrunc */ -+ iowrite8 (0x81, &ccr->icc); -+ -+ /* (10h)BaseAddress 0x1000 spba.spba2 */ -+ base = nfcr->start - tdev->iomem->start; -+ iowrite16 (base, ccr->base + 0); -+ iowrite16 (base >> 16, ccr->base + 1); -+ -+ /* (04h)Command Register I/O spcmd */ -+ iowrite8 (0x02, &ccr->command); -+ -+ /* (62h) Power Supply Control ssmpwc */ -+ /* HardPowerOFF - SuspendOFF - PowerSupplyWait_4MS */ -+ iowrite8 (0x02, &ccr->nfpsc); -+ -+ /* (63h) Detect Control ssmdtc */ -+ iowrite8 (0x02, &ccr->nfdc); -+ -+ /* Interrupt status register clear sintst */ -+ iowrite8 (0x0f, &fcr->isr); -+ -+ /* After power supply, Media are reset smode */ -+ iowrite8 (FCR_MODE_POWER_ON, &fcr->mode); -+ iowrite8 (FCR_MODE_COMMAND, &fcr->mode); -+ iowrite8 (NAND_CMD_RESET, &fcr->u8); -+ -+ /* Standby Mode smode */ -+ iowrite8 (FCR_MODE_STANDBY, &fcr->mode); -+ -+ mdelay (5); -+} -+ -+static void tmio_hw_stop (struct device *dev, struct tmio_nand *tmio) -+{ -+ struct tmio_device* tdev = dev_to_tdev (dev); -+ struct tmio_nfcr __iomem * fcr = tmio->fcr; -+ -+ iowrite8 (FCR_MODE_POWER_OFF, &fcr->mode); -+ tdev->ops->function (dev, 0); -+ tdev->ops->clock (dev, 0); -+} -+ -+/*--------------------------------------------------------------------------*/ -+ -+#ifdef CONFIG_MTD_PARTITIONS -+static const char *part_probes[] = { "cmdlinepart", NULL }; -+#endif -+ -+static int tmio_probe (struct device *dev) -+{ -+ struct tmio_device* tdev = dev_to_tdev (dev); -+ struct tmio_nand_platform_data* tnpd = dev->platform_data; -+ struct resource* ccr = tmio_resource_config (dev); -+ struct resource* fcr = tmio_resource_control (dev); -+ struct resource* irq = tmio_resource_irq (dev); -+ struct tmio_nand* tmio; -+ struct mtd_info* mtd; -+ struct nand_chip* this; -+ struct mtd_partition* parts; -+ int nbparts = 0; -+ int retval; -+ -+ if (!tnpd) -+ return -EINVAL; -+ -+ retval = request_resource (tdev->iomem, ccr); -+ if (retval) -+ goto err_request_ccr; -+ -+ retval = request_resource (tdev->iomem, fcr); -+ if (retval) -+ goto err_request_fcr; -+ -+ tmio = kzalloc (sizeof *tmio, GFP_KERNEL); -+ if (!tmio) { -+ retval = -ENOMEM; -+ goto err_kzalloc; -+ } -+ -+ dev_set_drvdata (dev, tmio); -+ mtd = &tmio->mtd; -+ this = &tmio->chip; -+ mtd->priv = this; -+ mtd->name = TMIO_NAME_NAND; -+ -+ tmio->ccr = ioremap (ccr->start, ccr->end - ccr->start + 1); -+ if (!tmio->ccr) { -+ retval = -EIO; -+ goto err_iomap_ccr; -+ } -+ -+ tmio->fcr = ioremap (fcr->start, fcr->end - fcr->start + 1); -+ if (!tmio->fcr) { -+ retval = -EIO; -+ goto err_iomap_fcr; -+ } -+ -+ tmio_hw_init (dev, tmio); -+ -+ /* Set address of NAND IO lines */ -+ this->IO_ADDR_R = tmio->fcr; -+ this->IO_ADDR_W = tmio->fcr; -+ -+ /* Set address of hardware control function */ -+ this->cmd_ctrl = tmio_nand_hwcontrol; -+ this->dev_ready = tmio_nand_dev_ready; -+ this->read_byte = tmio_nand_read_byte; -+ this->write_buf = tmio_nand_write_buf; -+ this->read_buf = tmio_nand_read_buf; -+ this->verify_buf = tmio_nand_verify_buf; -+ -+ /* set eccmode using hardware ECC */ -+ this->ecc.mode = NAND_ECC_HW; -+ this->ecc.size = 512; -+ this->ecc.bytes = 6; -+ this->ecc.hwctl = tmio_nand_enable_hwecc; -+ this->ecc.calculate = tmio_nand_calculate_ecc; -+ this->ecc.correct = nand_correct_data; -+ this->badblock_pattern = tnpd->badblock_pattern; -+ -+ /* 15 us command delay time */ -+ this->chip_delay = 15; -+ -+ if (irq->start) { -+ retval = request_irq (irq->start, &tmio_irq, -+ IRQF_DISABLED, irq->name, tmio); -+ if (!retval) { -+ tmio->irq = irq->start; -+ this->waitfunc = tmio_nand_wait; -+ } else -+ mtd_warn (mtd, "request_irq error %d\n", retval); -+ } -+ -+ /* Scan to find existence of the device */ -+ if (nand_scan (mtd, 1)) { -+ retval = -ENODEV; -+ goto err_scan; -+ } -+ -+ /* Register the partitions */ -+#ifdef CONFIG_MTD_PARTITIONS -+ nbparts = parse_mtd_partitions (mtd, part_probes, &parts, 0); -+#endif -+ if (nbparts <= 0) { -+ parts = tnpd->partition; -+ nbparts = tnpd->num_partitions; -+ } -+ -+ add_mtd_partitions (mtd, parts, nbparts); -+ return 0; -+ -+err_scan: -+ if (tmio->irq) -+ free_irq (tmio->irq, tmio); -+ tmio_hw_stop (dev, tmio); -+ iounmap (tmio->fcr); -+err_iomap_fcr: -+ iounmap (tmio->ccr); -+err_iomap_ccr: -+ kfree (tmio); -+err_kzalloc: -+ release_resource (fcr); -+err_request_fcr: -+ release_resource (ccr); -+err_request_ccr: -+ return retval; -+} -+ -+static int tmio_remove (struct device *dev) -+{ -+ struct tmio_nand* tmio = dev_get_drvdata (dev); -+ -+ nand_release (&tmio->mtd); -+ if (tmio->irq) -+ free_irq (tmio->irq, tmio); -+ tmio_hw_stop (dev, tmio); -+ iounmap (tmio->fcr); -+ iounmap (tmio->ccr); -+ kfree (tmio); -+ release_resource (tmio_resource_control (dev)); -+ release_resource (tmio_resource_config (dev)); -+ return 0; -+} -+ -+#ifdef CONFIG_PM -+static int tmio_suspend (struct device *dev, pm_message_t state) -+{ -+ tmio_hw_stop (dev, dev_get_drvdata (dev)); -+ return 0; -+} -+ -+static int tmio_resume (struct device *dev) -+{ -+ tmio_hw_init (dev, dev_get_drvdata (dev)); -+ return 0; -+} -+#endif -+ -+static struct device_driver tmio_driver = { -+ .name = TMIO_NAME_NAND, -+ .bus = &tmio_bus_type, -+ .probe = tmio_probe, -+ .remove = tmio_remove, -+#ifdef CONFIG_PM -+ .suspend = tmio_suspend, -+ .resume = tmio_resume, -+#endif -+}; -+ -+static int __init tmio_init (void) { -+ return driver_register (&tmio_driver); -+} -+ -+static void __exit tmio_exit (void) { -+ driver_unregister (&tmio_driver); -+} -+ -+module_init (tmio_init); -+module_exit (tmio_exit); -+ -+MODULE_LICENSE ("GPL"); -+MODULE_AUTHOR ("Dirk Opfer, Chris Humbert"); -+MODULE_DESCRIPTION ("NAND flash driver on Toshiba Mobile IO controller"); -- cgit v1.2.3