118a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson/* 218a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson * arch/cris/arch-v32/drivers/nandflash.c 318a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson * 418a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson * Copyright (c) 2007 518a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson * 618a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson * Derived from drivers/mtd/nand/spia.c 718a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) 818a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson * 918a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson * This program is free software; you can redistribute it and/or modify 1018a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson * it under the terms of the GNU General Public License version 2 as 1118a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson * published by the Free Software Foundation. 1218a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson * 1318a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson */ 1418a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson 1518a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson#include <linux/slab.h> 1618a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson#include <linux/init.h> 1718a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson#include <linux/module.h> 1818a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson#include <linux/mtd/mtd.h> 1918a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson#include <linux/mtd/nand.h> 2018a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson#include <linux/mtd/partitions.h> 21556dcee7b829e5c350c3ffdbdb87a8b15aa3c5d3Jesper Nilsson#include <arch/memmap.h> 2218a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson#include <hwregs/reg_map.h> 2318a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson#include <hwregs/reg_rdwr.h> 2418a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson#include <hwregs/pio_defs.h> 2518a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson#include <pinmux.h> 2618a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson#include <asm/io.h> 2718a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson 2818a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson#define MANUAL_ALE_CLE_CONTROL 1 2918a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson 3018a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson#define regf_ALE a0 3118a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson#define regf_CLE a1 3218a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson#define regf_NCE ce0_n 3318a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson 3418a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson#define CLE_BIT 10 3518a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson#define ALE_BIT 11 3618a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson#define CE_BIT 12 3718a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson 389f68ff9ee9ecae38a3b0bb3b9c4799cded19b27cJesper Nilssonstruct mtd_info_wrapper { 399f68ff9ee9ecae38a3b0bb3b9c4799cded19b27cJesper Nilsson struct mtd_info info; 409f68ff9ee9ecae38a3b0bb3b9c4799cded19b27cJesper Nilsson struct nand_chip chip; 419f68ff9ee9ecae38a3b0bb3b9c4799cded19b27cJesper Nilsson}; 429f68ff9ee9ecae38a3b0bb3b9c4799cded19b27cJesper Nilsson 4318a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson/* Bitmask for control pins */ 4418a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson#define PIN_BITMASK ((1 << CE_BIT) | (1 << CLE_BIT) | (1 << ALE_BIT)) 4518a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson 4618a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilssonstatic struct mtd_info *crisv32_mtd; 4718a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson/* 4818a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson * hardware specific access to control-lines 4918a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson */ 5018a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilssonstatic void crisv32_hwcontrol(struct mtd_info *mtd, int cmd, 5118a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson unsigned int ctrl) 5218a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson{ 5318a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson unsigned long flags; 5418a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson reg_pio_rw_dout dout; 5518a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson struct nand_chip *this = mtd->priv; 5618a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson 5718a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson local_irq_save(flags); 5818a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson 5918a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson /* control bits change */ 6018a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson if (ctrl & NAND_CTRL_CHANGE) { 6118a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson dout = REG_RD(pio, regi_pio, rw_dout); 6218a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson dout.regf_NCE = (ctrl & NAND_NCE) ? 0 : 1; 6318a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson 6418a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson#if !MANUAL_ALE_CLE_CONTROL 6518a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson if (ctrl & NAND_ALE) { 6618a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson /* A0 = ALE high */ 6718a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson this->IO_ADDR_W = (void __iomem *)REG_ADDR(pio, 6818a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson regi_pio, rw_io_access1); 6918a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson } else if (ctrl & NAND_CLE) { 7018a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson /* A1 = CLE high */ 7118a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson this->IO_ADDR_W = (void __iomem *)REG_ADDR(pio, 7218a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson regi_pio, rw_io_access2); 7318a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson } else { 7418a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson /* A1 = CLE and A0 = ALE low */ 7518a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson this->IO_ADDR_W = (void __iomem *)REG_ADDR(pio, 7618a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson regi_pio, rw_io_access0); 7718a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson } 7818a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson#else 7918a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson 8018a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson dout.regf_CLE = (ctrl & NAND_CLE) ? 1 : 0; 8118a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson dout.regf_ALE = (ctrl & NAND_ALE) ? 1 : 0; 8218a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson#endif 8318a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson REG_WR(pio, regi_pio, rw_dout, dout); 8418a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson } 8518a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson 8618a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson /* command to chip */ 8718a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson if (cmd != NAND_CMD_NONE) 8818a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson writeb(cmd, this->IO_ADDR_W); 8918a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson 9018a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson local_irq_restore(flags); 9118a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson} 9218a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson 9318a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson/* 9418a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson* read device ready pin 9518a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson*/ 969f68ff9ee9ecae38a3b0bb3b9c4799cded19b27cJesper Nilssonstatic int crisv32_device_ready(struct mtd_info *mtd) 9718a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson{ 9818a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson reg_pio_r_din din = REG_RD(pio, regi_pio, r_din); 9918a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson return din.rdy; 10018a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson} 10118a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson 10218a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson/* 10318a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson * Main initialization routine 10418a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson */ 10518a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilssonstruct mtd_info *__init crisv32_nand_flash_probe(void) 10618a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson{ 10718a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson void __iomem *read_cs; 10818a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson void __iomem *write_cs; 10918a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson 1109f68ff9ee9ecae38a3b0bb3b9c4799cded19b27cJesper Nilsson struct mtd_info_wrapper *wrapper; 11118a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson struct nand_chip *this; 11218a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson int err = 0; 11318a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson 11418a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson reg_pio_rw_man_ctrl man_ctrl = { 11518a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson .regf_NCE = regk_pio_yes, 11618a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson#if MANUAL_ALE_CLE_CONTROL 11718a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson .regf_ALE = regk_pio_yes, 11818a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson .regf_CLE = regk_pio_yes 11918a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson#endif 12018a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson }; 12118a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson reg_pio_rw_oe oe = { 12218a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson .regf_NCE = regk_pio_yes, 12318a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson#if MANUAL_ALE_CLE_CONTROL 12418a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson .regf_ALE = regk_pio_yes, 12518a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson .regf_CLE = regk_pio_yes 12618a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson#endif 12718a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson }; 12818a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson reg_pio_rw_dout dout = { .regf_NCE = 1 }; 12918a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson 13018a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson /* Allocate pio pins to pio */ 13118a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson crisv32_pinmux_alloc_fixed(pinmux_pio); 13218a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson /* Set up CE, ALE, CLE (ce0_n, a0, a1) for manual control and output */ 13318a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson REG_WR(pio, regi_pio, rw_man_ctrl, man_ctrl); 13418a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson REG_WR(pio, regi_pio, rw_dout, dout); 13518a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson REG_WR(pio, regi_pio, rw_oe, oe); 13618a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson 13718a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson /* Allocate memory for MTD device structure and private data */ 1389f68ff9ee9ecae38a3b0bb3b9c4799cded19b27cJesper Nilsson wrapper = kzalloc(sizeof(struct mtd_info_wrapper), GFP_KERNEL); 1399f68ff9ee9ecae38a3b0bb3b9c4799cded19b27cJesper Nilsson if (!wrapper) { 14018a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson printk(KERN_ERR "Unable to allocate CRISv32 NAND MTD " 14118a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson "device structure.\n"); 14218a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson err = -ENOMEM; 14318a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson return NULL; 14418a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson } 14518a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson 14618a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson read_cs = write_cs = (void __iomem *)REG_ADDR(pio, regi_pio, 14718a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson rw_io_access0); 14818a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson 14918a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson /* Get pointer to private data */ 1509f68ff9ee9ecae38a3b0bb3b9c4799cded19b27cJesper Nilsson this = &wrapper->chip; 1519f68ff9ee9ecae38a3b0bb3b9c4799cded19b27cJesper Nilsson crisv32_mtd = &wrapper->info; 15218a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson 15318a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson /* Link the private data with the MTD structure */ 15418a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson crisv32_mtd->priv = this; 15518a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson 15618a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson /* Set address of NAND IO lines */ 15718a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson this->IO_ADDR_R = read_cs; 15818a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson this->IO_ADDR_W = write_cs; 15918a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson this->cmd_ctrl = crisv32_hwcontrol; 16018a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson this->dev_ready = crisv32_device_ready; 16118a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson /* 20 us command delay time */ 16218a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson this->chip_delay = 20; 16318a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson this->ecc.mode = NAND_ECC_SOFT; 16418a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson 16518a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson /* Enable the following for a flash based bad block table */ 166bb9ebd4e714385a2592a482845865ef2d58b2868Brian Norris /* this->bbt_options = NAND_BBT_USE_FLASH; */ 16718a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson 16825985edcedea6396277003854657b5f3cb31a628Lucas De Marchi /* Scan to find existence of the device */ 16918a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson if (nand_scan(crisv32_mtd, 1)) { 17018a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson err = -ENXIO; 17118a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson goto out_mtd; 17218a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson } 17318a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson 17418a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson return crisv32_mtd; 17518a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson 17618a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilssonout_mtd: 1779f68ff9ee9ecae38a3b0bb3b9c4799cded19b27cJesper Nilsson kfree(wrapper); 17818a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson return NULL; 17918a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson} 18018a1e013cdd94d1ade2c07acdbac61d533c7fc60Jesper Nilsson 181