diff options
Diffstat (limited to 'kernel/arch/cris/arch-v32/drivers/mach-fs/nandflash.c')
-rw-r--r-- | kernel/arch/cris/arch-v32/drivers/mach-fs/nandflash.c | 174 |
1 files changed, 174 insertions, 0 deletions
diff --git a/kernel/arch/cris/arch-v32/drivers/mach-fs/nandflash.c b/kernel/arch/cris/arch-v32/drivers/mach-fs/nandflash.c new file mode 100644 index 000000000..e03238454 --- /dev/null +++ b/kernel/arch/cris/arch-v32/drivers/mach-fs/nandflash.c @@ -0,0 +1,174 @@ +/* + * arch/cris/arch-v32/drivers/nandflash.c + * + * Copyright (c) 2004 + * + * Derived from drivers/mtd/nand/spia.c + * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) + * + * 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 <linux/slab.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> +#include <linux/mtd/partitions.h> +#include <arch/memmap.h> +#include <hwregs/reg_map.h> +#include <hwregs/reg_rdwr.h> +#include <hwregs/gio_defs.h> +#include <hwregs/bif_core_defs.h> +#include <asm/io.h> + +#define CE_BIT 4 +#define CLE_BIT 5 +#define ALE_BIT 6 +#define BY_BIT 7 + +struct mtd_info_wrapper { + struct mtd_info info; + struct nand_chip chip; +}; + +/* Bitmask for control pins */ +#define PIN_BITMASK ((1 << CE_BIT) | (1 << CLE_BIT) | (1 << ALE_BIT)) + +/* Bitmask for mtd nand control bits */ +#define CTRL_BITMASK (NAND_NCE | NAND_CLE | NAND_ALE) + + +static struct mtd_info *crisv32_mtd; +/* + * hardware specific access to control-lines + */ +static void crisv32_hwcontrol(struct mtd_info *mtd, int cmd, + unsigned int ctrl) +{ + unsigned long flags; + reg_gio_rw_pa_dout dout; + struct nand_chip *this = mtd->priv; + + local_irq_save(flags); + + /* control bits change */ + if (ctrl & NAND_CTRL_CHANGE) { + dout = REG_RD(gio, regi_gio, rw_pa_dout); + dout.data &= ~PIN_BITMASK; + +#if (CE_BIT == 4 && NAND_NCE == 1 && \ + CLE_BIT == 5 && NAND_CLE == 2 && \ + ALE_BIT == 6 && NAND_ALE == 4) + /* Pins in same order as control bits, but shifted. + * Optimize for this case; works for 2.6.18 */ + dout.data |= ((ctrl & CTRL_BITMASK) ^ NAND_NCE) << CE_BIT; +#else + /* the slow way */ + if (!(ctrl & NAND_NCE)) + dout.data |= (1 << CE_BIT); + if (ctrl & NAND_CLE) + dout.data |= (1 << CLE_BIT); + if (ctrl & NAND_ALE) + dout.data |= (1 << ALE_BIT); +#endif + REG_WR(gio, regi_gio, rw_pa_dout, dout); + } + + /* command to chip */ + if (cmd != NAND_CMD_NONE) + writeb(cmd, this->IO_ADDR_W); + + local_irq_restore(flags); +} + +/* +* read device ready pin +*/ +static int crisv32_device_ready(struct mtd_info *mtd) +{ + reg_gio_r_pa_din din = REG_RD(gio, regi_gio, r_pa_din); + return ((din.data & (1 << BY_BIT)) >> BY_BIT); +} + +/* + * Main initialization routine + */ +struct mtd_info *__init crisv32_nand_flash_probe(void) +{ + void __iomem *read_cs; + void __iomem *write_cs; + + reg_bif_core_rw_grp3_cfg bif_cfg = REG_RD(bif_core, regi_bif_core, + rw_grp3_cfg); + reg_gio_rw_pa_oe pa_oe = REG_RD(gio, regi_gio, rw_pa_oe); + struct mtd_info_wrapper *wrapper; + struct nand_chip *this; + int err = 0; + + /* Allocate memory for MTD device structure and private data */ + wrapper = kzalloc(sizeof(struct mtd_info_wrapper), GFP_KERNEL); + if (!wrapper) { + printk(KERN_ERR "Unable to allocate CRISv32 NAND MTD " + "device structure.\n"); + err = -ENOMEM; + return NULL; + } + + read_cs = ioremap(MEM_CSP0_START | MEM_NON_CACHEABLE, 8192); + write_cs = ioremap(MEM_CSP1_START | MEM_NON_CACHEABLE, 8192); + + if (!read_cs || !write_cs) { + printk(KERN_ERR "CRISv32 NAND ioremap failed\n"); + err = -EIO; + goto out_mtd; + } + + /* Get pointer to private data */ + this = &wrapper->chip; + crisv32_mtd = &wrapper->info; + + pa_oe.oe |= 1 << CE_BIT; + pa_oe.oe |= 1 << ALE_BIT; + pa_oe.oe |= 1 << CLE_BIT; + pa_oe.oe &= ~(1 << BY_BIT); + REG_WR(gio, regi_gio, rw_pa_oe, pa_oe); + + bif_cfg.gated_csp0 = regk_bif_core_rd; + bif_cfg.gated_csp1 = regk_bif_core_wr; + REG_WR(bif_core, regi_bif_core, rw_grp3_cfg, bif_cfg); + + /* Link the private data with the MTD structure */ + crisv32_mtd->priv = this; + + /* Set address of NAND IO lines */ + this->IO_ADDR_R = read_cs; + this->IO_ADDR_W = write_cs; + this->cmd_ctrl = crisv32_hwcontrol; + this->dev_ready = crisv32_device_ready; + /* 20 us command delay time */ + this->chip_delay = 20; + this->ecc.mode = NAND_ECC_SOFT; + + /* Enable the following for a flash based bad block table */ + /* this->bbt_options = NAND_BBT_USE_FLASH; */ + + /* Scan to find existence of the device */ + if (nand_scan(crisv32_mtd, 1)) { + err = -ENXIO; + goto out_ior; + } + + return crisv32_mtd; + +out_ior: + iounmap((void *)read_cs); + iounmap((void *)write_cs); +out_mtd: + kfree(wrapper); + return NULL; +} + |