diff options
Diffstat (limited to 'drivers/mtd/nand/cs553x_nand.c')
| -rw-r--r-- | drivers/mtd/nand/cs553x_nand.c | 113 |
1 files changed, 63 insertions, 50 deletions
diff --git a/drivers/mtd/nand/cs553x_nand.c b/drivers/mtd/nand/cs553x_nand.c index bf251253ea1..88109d375ae 100644 --- a/drivers/mtd/nand/cs553x_nand.c +++ b/drivers/mtd/nand/cs553x_nand.c @@ -11,16 +11,18 @@ * published by the Free Software Foundation. * * Overview: - * This is a device driver for the NAND flash controller found on + * This is a device driver for the NAND flash controller found on * the AMD CS5535/CS5536 companion chipsets for the Geode processor. + * mtd-id for command line partitioning is cs553x_nand_cs[0-3] + * where 0-3 reflects the chip select for NAND. * */ +#include <linux/kernel.h> #include <linux/slab.h> #include <linux/init.h> #include <linux/module.h> #include <linux/delay.h> -#include <linux/pci.h> #include <linux/mtd/mtd.h> #include <linux/mtd/nand.h> #include <linux/mtd/nand_ecc.h> @@ -31,6 +33,10 @@ #define NR_CS553X_CONTROLLERS 4 +#define MSR_DIVIL_GLD_CAP 0x51400000 /* DIVIL capabilitiies */ +#define CAP_CS5535 0x2df000ULL +#define CAP_CS5536 0x5df500ULL + /* NAND Timing MSRs */ #define MSR_NANDF_DATA 0x5140001b /* NAND Flash Data Timing MSR */ #define MSR_NANDF_CTL 0x5140001c /* NAND Flash Control Timing */ @@ -131,33 +137,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) @@ -207,9 +197,8 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr) } /* Allocate memory for MTD device structure and private data */ - new_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL); + new_mtd = kzalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL); if (!new_mtd) { - printk(KERN_WARNING "Unable to allocate CS553X NAND MTD device structure.\n"); err = -ENOMEM; goto out; } @@ -217,10 +206,6 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr) /* Get pointer to private data */ this = (struct nand_chip *)(&new_mtd[1]); - /* Initialize structures */ - memset(new_mtd, 0, sizeof(struct mtd_info)); - memset(this, 0, sizeof(struct nand_chip)); - /* Link the private data with the MTD structure */ new_mtd->priv = this; new_mtd->owner = THIS_MODULE; @@ -233,53 +218,80 @@ 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; this->chip_delay = 0; - this->eccmode = NAND_ECC_HW3_256; - this->enable_hwecc = cs_enable_hwecc; - this->calculate_ecc = cs_calculate_ecc; - this->correct_data = nand_correct_data; - + this->ecc.mode = NAND_ECC_HW; + this->ecc.size = 256; + this->ecc.bytes = 3; + this->ecc.hwctl = cs_enable_hwecc; + this->ecc.calculate = cs_calculate_ecc; + this->ecc.correct = nand_correct_data; + this->ecc.strength = 1; + /* Enable the following for a flash based bad block table */ - this->options = NAND_USE_FLASH_BBT | NAND_NO_AUTOINCR; + this->bbt_options = NAND_BBT_USE_FLASH; - /* Scan to find existance of the device */ + /* Scan to find existence of the device */ if (nand_scan(new_mtd, 1)) { err = -ENXIO; goto out_ior; } + new_mtd->name = kasprintf(GFP_KERNEL, "cs553x_nand_cs%d", cs); + cs553x_mtd[cs] = new_mtd; goto out; out_ior: - iounmap((void *)this->IO_ADDR_R); + iounmap(this->IO_ADDR_R); out_mtd: kfree(new_mtd); out: return err; } +static int is_geode(void) +{ + /* These are the CPUs which will have a CS553[56] companion chip */ + if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD && + boot_cpu_data.x86 == 5 && + boot_cpu_data.x86_model == 10) + return 1; /* Geode LX */ + + if ((boot_cpu_data.x86_vendor == X86_VENDOR_NSC || + boot_cpu_data.x86_vendor == X86_VENDOR_CYRIX) && + boot_cpu_data.x86 == 5 && + boot_cpu_data.x86_model == 5) + return 1; /* Geode GX (née GX2) */ + + return 0; +} + static int __init cs553x_init(void) { int err = -ENXIO; int i; uint64_t val; - /* Check whether we actually have a CS5535 or CS5536 */ - if (!pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA, NULL) && - !pci_find_device(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA, NULL)) + /* If the CPU isn't a Geode GX or LX, abort */ + if (!is_geode()) return -ENXIO; + /* If it doesn't have the CS553[56], abort */ + rdmsrl(MSR_DIVIL_GLD_CAP, val); + val &= ~0xFFULL; + if (val != CAP_CS5535 && val != CAP_CS5536) + return -ENXIO; + + /* If it doesn't have the NAND controller enabled, abort */ rdmsrl(MSR_DIVIL_BALL_OPTS, val); - if (val & 1) { + if (val & PIN_OPT_IDE) { printk(KERN_INFO "CS553x NAND controller: Flash I/O not enabled in MSR_DIVIL_BALL_OPTS.\n"); return -ENXIO; } @@ -291,13 +303,13 @@ static int __init cs553x_init(void) err = cs553x_init_one(i, !!(val & FLSH_MEM_IO), val & 0xFFFFFFFF); } - /* Register all devices together here. This means we can easily hack it to + /* Register all devices together here. This means we can easily hack it to do mtdconcat etc. if we want to. */ for (i = 0; i < NR_CS553X_CONTROLLERS; i++) { if (cs553x_mtd[i]) { - add_mtd_device(cs553x_mtd[i]); - /* If any devices registered, return success. Else the last error. */ + mtd_device_parse_register(cs553x_mtd[i], NULL, NULL, + NULL, 0); err = 0; } } @@ -317,16 +329,17 @@ static void __exit cs553x_cleanup(void) void __iomem *mmio_base; if (!mtd) - break; + continue; this = cs553x_mtd[i]->priv; mmio_base = this->IO_ADDR_R; /* Release resources, unregister device */ nand_release(cs553x_mtd[i]); + kfree(cs553x_mtd[i]->name); cs553x_mtd[i] = NULL; - /* unmap physical adress */ + /* unmap physical address */ iounmap(mmio_base); /* Free the MTD device structure */ |
