/* * linux/drivers/mtd/nand/nand_davinci.c * * NAND Flash Driver * * Copyright (C) 2004 Texas Instruments. * * ---------------------------------------------------------------------------- * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * ---------------------------------------------------------------------------- * * Overview: * This is a device driver for the NAND flash device found on the * DaVinci board which utilizes the Samsung k9k2g08 part. * Modifications: ver. 1.0: Feb 2005, Vinod/Sudhakar Mistral - * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if 0 static int parameter_number = 0; static char *init_parameter[4]; module_param_array(init_parameter, charp, ¶meter_number, S_IRUGO); MODULE_PARM_DESC(init_parameter, "nand"); /*--- filesystem ---*/ #endif #define DAVINCI_NAND_BASE_ADDR DAVINCI_ASYNC_EMIF_CNTRL_BASE /*--- #define DEBUG_NAND ---*/ #if defined(DEBUG_NAND) #define DBG_NAND(args ...) printk(args) #else #define DBG_NAND(args ...) #endif static struct clk *nand_clock; /* * MTD structure for DaVinici board */ static struct mtd_info *nand_davinci_mtd = NULL; #define NAND_READ_START 0x00 #define NAND_READ_END 0x30 #define NAND_STATUS 0x70 static int nand_flash_init (struct nand_chip *chip, unsigned int chip_select); /* * Define partitions for flash device */ static struct mtd_partition partition_info[] = { #ifdef CONFIG_NAND_FLASH_LINUX { name: "Flash partition 0", offset: SZ_1M, size: 4 * SZ_1M}, { name: "Flash partition 1", offset: 5 * SZ_1M, size: 59 * SZ_1M}, #else { name: "NAND Flash partition", offset: 0, size: 32 * SZ_1M}, #endif }; #ifdef CONFIG_NAND_FLASH_LINUX #define NUM_PARTITIONS 2 #else #define NUM_PARTITIONS 1 #endif #define MASK_CLE 0x10 /*--- EMIF_ADDRESS A2 ---*/ #define MASK_ALE 0x0A /*--- EMIF_ADDRESS A1 ---*/ /*------------------------------------------------------------------------------------------*\ * hardware specific access to control-lines \*------------------------------------------------------------------------------------------*/ static void nand_davinci_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) { struct nand_chip *this = mtd->priv; u32 IO_ADDR_W = (u32) this->IO_ADDR_W; DBG_NAND("[davinci_hw_control] cmd 0x%x ctrl 0x%x ", cmd, ctrl); if (ctrl & NAND_CTRL_CHANGE) { IO_ADDR_W &= ~(MASK_ALE|MASK_CLE); switch(ctrl & ~NAND_CTRL_CHANGE) { case NAND_CTRL_CLE: DBG_NAND(" "); IO_ADDR_W |= MASK_CLE; break; case NAND_CTRL_ALE: DBG_NAND(" "); IO_ADDR_W |= MASK_ALE; break; } this->IO_ADDR_W = (void __iomem *) IO_ADDR_W; } if (cmd != NAND_CMD_NONE) { DBG_NAND(" write 0x%x\n", IO_ADDR_W); writew(cmd, IO_ADDR_W); } #if defined(DEBUG_NAND) else printk("\n"); #endif } /*------------------------------------------------------------------------------------------*\ * im aktuellen Design soll GPIO42 als CS eingesetzt werden \*------------------------------------------------------------------------------------------*/ static void nand_davinci_select_chip(struct mtd_info *mtd, int chip) { struct nand_chip *this = mtd->priv; DBG_NAND("[nand_davinci_select_chip] %d\n", chip); switch (chip) { case -1: davinci_gpio_out_bit(42, 1); /*--- release CS ---*/ break; case 0: davinci_gpio_out_bit(42, 0); /*--- set CS ---*/ break; default: BUG(); } } /* * Main initialization routine */ int __init nand_davinci_init (void) { struct nand_chip *this; struct device *dev = NULL; nand_clock = clk_get (dev, "AEMIFCLK"); if (IS_ERR(nand_clock)) return -1; clk_enable (nand_clock); /* Allocate memory for MTD device structure and private data */ nand_davinci_mtd = kzalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip), GFP_KERNEL); if (!nand_davinci_mtd) { printk ("Unable to allocate davinci NAND MTD device structure.\n"); return -ENOMEM; } /* Get pointer to private data */ this = (struct nand_chip *) (&nand_davinci_mtd[1]); this->chip_delay = 0; this->select_chip = nand_davinci_select_chip; this->options = NAND_BUSWIDTH_16; /*--- unser NAND ist 16-bittig angeschlossen ---*/ this->ecc.mode = NAND_ECC_SOFT; this->cmd_ctrl = nand_davinci_hwcontrol; /* Set address of hardware control function */ nand_davinci_mtd->priv = this; /* Link the private data with the MTD structure */ if (!nand_flash_init(this, CONFIG_MTD_NAND_DAVINCI_CHIPSELECT)) { nand_davinci_mtd->owner = THIS_MODULE; /* Scan to find existence of the device */ if (nand_scan (nand_davinci_mtd, 1)) { printk ("Chip Select is not set for NAND\n"); goto error; } /* Register the partitions */ add_mtd_partitions(nand_davinci_mtd, partition_info, NUM_PARTITIONS); } else goto error; #if 0 if (parameter_number) { int ret; struct erase_info instr; instr.addr = 0; instr.len = (32<<20); printk("[nand_davinci] erase Flash from 0x%x to 0x%x\n", inst.addr, inst.addr + inst.len); ret = nand_davinci_mtd->erase(nand_davinci_mtd, &instr); printk("[nand_davinci] erase returned %d\n", ret); } #endif { int ret,i; size_t len; unsigned char *buffer = (unsigned char *)kzalloc(4096, GFP_KERNEL); unsigned int *p = (unsigned int *)buffer; ret = nand_davinci_mtd->read(nand_davinci_mtd, 0, 4096, &len, buffer); printk("[nand_davinci_init] read 0x%x %d\n", ret, len); for (i=0;i<1024;i++) { printk("0x%x ", *p++); } } /* Return happy */ return 0; error: clk_disable (nand_clock); kfree (nand_davinci_mtd); return -ENXIO; } module_init(nand_davinci_init); int nand_flash_init (struct nand_chip *chip, unsigned int chip_select) { struct EMIF_register_memory_map *EMIF_Register = (struct EMIF_register_memory_map *)IO_ADDRESS(DAVINCI_ASYNC_EMIF_CNTRL_BASE); u32 flash_address; u32 acfg = 0x3FFFFFFD; u32 nand_rev_code; nand_rev_code = EMIF_Register->RevCodeSR; printk("DaVinci NAND Controller rev. %d.%d\n", (nand_rev_code >>8) & 0xff, nand_rev_code & 0xff); /*--- init GPIO42 ---*/ if (davinci_gpio_ctrl(42, GPIO_PIN, GPIO_OUTPUT_PIN)) { printk("[nand_flash_init] unable to set GPIO\n"); return 1; } /*------------------------------------------------------------------* * NAND FLASH CHIP TIMEOUT @ 594 MHz * * * * AEMIF.CLK freq = PLL1/6 = 594/6 = 99 MHz * * AEMIF.CLK period = 1/99 MHz = 10 ns * * * *------------------------------------------------------------------*/ acfg = 0 #if 0 | ( 0 << 31 ) // selectStrobe | ( 0 << 30 ) // extWait | ( 1 << 26 ) // writeSetup // 20 ns | ( 3 << 20 ) // writeStrobe // 60 ns | ( 1 << 17 ) // writeHold // 30 ns | ( 1 << 13 ) // readSetup // 20 ns | ( 5 << 7 ) // readStrobe // 60 ns | ( 1 << 4 ) // readHold // 30 ns | ( 3 << 2 ) // turnAround // 40 ns #else | ( 0 << 31 ) // selectStrobe | ( 0 << 30 ) // extWait | ( 1 << 26 ) // writeSetup // 20 ns | ( 5 << 20 ) // writeStrobe // 60 ns | ( 2 << 17 ) // writeHold // 30 ns | ( 1 << 13 ) // readSetup // 20 ns | ( 5 << 7 ) // readStrobe // 60 ns | ( 2 << 4 ) // readHold // 30 ns | ( 3 << 2 ) // turnAround // 40 ns #endif ; if (chip->options & NAND_BUSWIDTH_16) { printk("[nand_flash_init] set Buswidth 16 Bit\n"); acfg += 1; /*--- Buswidth 16-bit ---*/ } switch (chip_select) { case 2: EMIF_Register->NANDFCR.Bits.CS2NAND = 1; flash_address = 0x2000000; if (chip->ecc.mode == NAND_ECC_HW) EMIF_Register->NANDFCR.Bits.CS2ECC = 1; break; case 3: EMIF_Register->NANDFCR.Bits.CS3NAND = 1; flash_address = 0x4000000; if (chip->ecc.mode == NAND_ECC_HW) EMIF_Register->NANDFCR.Bits.CS3ECC = 1; break; case 4: EMIF_Register->NANDFCR.Bits.CS4NAND = 1; flash_address = 0x6000000; if (chip->ecc.mode == NAND_ECC_HW) EMIF_Register->NANDFCR.Bits.CS4ECC = 1; break; case 5: EMIF_Register->NANDFCR.Bits.CS5NAND = 1; flash_address = 0x8000000; if (chip->ecc.mode == NAND_ECC_HW) EMIF_Register->NANDFCR.Bits.CS5ECC = 1; break; default: printk("[nand_flash_init] chipselect %d not valid\n", chip_select); return 1; } /*--- 4k io-mem für den NAND mappen ---*/ chip->IO_ADDR_W = chip->IO_ADDR_R = (void __iomem *)ioremap_nocache(flash_address, (1<<12)); if (!chip->IO_ADDR_W) { printk("[nand_flash_init] can not map Memory for 0x%x\n", flash_address); return 1; } DBG_NAND("[nand_flash_init] Memory 0x%x chipselect %d acfg 0x%x\n", chip->IO_ADDR_W, chip_select, acfg); EMIF_Register->AsyncBankCR[chip_select-2].Register = acfg; /*--- der Index beginnt bei 0 (CS2) ---*/ return 0; } /* * Clean up routine */ #ifdef MODULE static void __exit nand_davinci_cleanup (void) { clk_disable (nand_clock); /* Release resources, unregister device */ nand_release (nand_davinci_mtd); /* Free the MTD device structure */ kfree (nand_davinci_mtd); } module_exit(nand_davinci_cleanup); #endif MODULE_LICENSE("GPL"); MODULE_AUTHOR("Texas Instruments"); MODULE_DESCRIPTION("Board-specific glue layer for NAND flash on davinci board");