This patch adds NAND driver to recent git. Tested on DM6446 DVEVM.
It is mainly based on Sander Huijsen <[EMAIL PROTECTED]> work. http://linux.omap.com/pipermail/davinci-linux-open-source/2007-December/004788.html Signed-off-by: Dirk Behme <[EMAIL PROTECTED]>
Index: linux-davinci/drivers/mtd/nand/davinci_nand.c =================================================================== --- /dev/null +++ linux-davinci/drivers/mtd/nand/davinci_nand.c @@ -0,0 +1,748 @@ +/* + * linux/drivers/mtd/nand/davinci_nand.c + * + * NAND Flash Driver + * + * Copyright (C) 2006 Texas Instruments. + * + * ported to 2.6.23 (C) 2008 by + * Sander Huijsen <[EMAIL PROTECTED]> + * Dirk Behme <[EMAIL PROTECTED]> + * + * -------------------------------------------------------------------------- + * + * 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 + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/err.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> +#include <linux/mtd/partitions.h> + +#include <asm/arch/hardware.h> +#include <asm/arch/nand.h> +#include <asm/arch/mux.h> + +#ifdef CONFIG_NAND_FLASH_HW_ECC +#define DAVINCI_NAND_ECC_MODE NAND_ECC_HW3_256 +#else +#define DAVINCI_NAND_ECC_MODE NAND_ECC_SOFT +#endif + +static struct clk *nand_clock; +static void __iomem *nand_vaddr; + +/* + * MTD structure for DaVinici board + */ +static struct mtd_info *nand_davinci_mtd; + +#ifdef CONFIG_MTD_PARTITIONS +const char *part_probes[] = { "cmdlinepart", NULL }; +#endif + +/* + * Define partitions for flash device + */ +static struct mtd_partition partition_info[] = { +#ifdef CONFIG_NAND_FLASH_LINUX + { .name = "Kernel", + .offset = 0x00104000, + .size = 0x003FC000}, + + { .name = "User Space", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL}, +#else + { .name = "User Space", + .offset = 5 * SZ_1M, + .size = 59 * SZ_1M}, +#endif +}; + +#define NUM_PARTITIONS ARRAY_SIZE(partition_info) + +static uint8_t scan_ff_pattern[] = { 0xff, 0xff }; + +/* BB marker is byte 5 in OOB of page 0 */ +static struct nand_bbt_descr davinci_memorybased_small = { + .options = NAND_BBT_SCAN2NDPAGE, + .offs = 5, + .len = 1, + .pattern = scan_ff_pattern +}; + +/* BB marker is bytes 0-1 in OOB of page 0 */ +static struct nand_bbt_descr davinci_memorybased_large = { + .options = 0, + .offs = 0, + .len = 2, + .pattern = scan_ff_pattern +}; + +inline unsigned int davinci_nand_readl(int offset) +{ + return davinci_readl(DAVINCI_ASYNC_EMIF_CNTRL_BASE + offset); +} + +inline void davinci_nand_writel(unsigned long value, int offset) +{ + davinci_writel(value, DAVINCI_ASYNC_EMIF_CNTRL_BASE + offset); +} + +/* + * Hardware specific access to control-lines + */ +static void nand_davinci_hwcontrol(struct mtd_info *mtd, int cmd, + unsigned int ctrl) +{ + struct nand_chip *chip = mtd->priv; + u32 IO_ADDR_W = (u32)chip->IO_ADDR_W; + + /* Did the control lines change? */ + if (ctrl & NAND_CTRL_CHANGE) { + IO_ADDR_W &= ~(MASK_ALE|MASK_CLE); + + if ((ctrl & NAND_CTRL_CLE) == NAND_CTRL_CLE) + IO_ADDR_W |= MASK_CLE; + else if ((ctrl & NAND_CTRL_ALE) == NAND_CTRL_ALE) + IO_ADDR_W |= MASK_ALE; + + chip->IO_ADDR_W = (void __iomem *)IO_ADDR_W; + } + + if (cmd != NAND_CMD_NONE) + writeb(cmd, chip->IO_ADDR_W); +} + +static void nand_davinci_select_chip(struct mtd_info *mtd, int chip) +{ + /* do nothing */ +} + +#ifdef CONFIG_NAND_FLASH_HW_ECC +static void nand_davinci_enable_hwecc(struct mtd_info *mtd, int mode) +{ + u32 retval; + + /* Reset ECC hardware */ + retval = davinci_nand_readl(NANDF1ECC_OFFSET); + + /* Restart ECC hardware */ + retval = davinci_nand_readl(NANDFCR_OFFSET); + retval |= (1 << 8); + davinci_nand_writel(retval, NANDFCR_OFFSET); +} + +/* + * Read DaVinci ECC register + */ +static u32 nand_davinci_readecc(struct mtd_info *mtd) +{ + u32 l; + + /* Read register ECC and clear P2048e/o */ + l = davinci_nand_readl(NANDF1ECC_OFFSET); + l &= ~0x08000800; + + return l; +} + +/* + * Rework register value to correct ECC values for MTD + */ +static void nand_davinci_gen_true_ecc(const u32 ecc_val, u8 *ecc_buf) +{ + ecc_buf[0] = ~(P1024o(ecc_val) | P1024e(ecc_val) | P512o(ecc_val) | + P512e(ecc_val) | P256o(ecc_val) | P256e(ecc_val) | + P128o(ecc_val) | P128e(ecc_val)); + + ecc_buf[1] = ~(P64o(ecc_val) | P64e(ecc_val) | P32o(ecc_val) | + P32e(ecc_val) | P16o(ecc_val) | P16e(ecc_val) | + P8o(ecc_val) | P8e(ecc_val)); + + ecc_buf[2] = ~(P4o(ecc_val) | P4e(ecc_val) | P2o(ecc_val) | + P2e(ecc_val) | P1o(ecc_val) | P1e(ecc_val) | + P2048o(ecc_val) | P2048e(ecc_val)); +} + +/* + * Read DaVinci ECC registers and rework into MTD format + */ +static int nand_davinci_calculate_ecc(struct mtd_info *mtd, + const u_char *dat, u_char *ecc_code) +{ + unsigned int ecc_val; + + ecc_val = nand_davinci_readecc(mtd); + nand_davinci_gen_true_ecc(ecc_val, ecc_code); + + return 0; +} + +/* + * Compare ECC for calculated (ecc_new) and stored data (ecc_old). + * At this point, we're using actual MTD formatted ECC bytes. + * Because the HW calculates the ECC over 256 bytes, P2048e/o + * are ignored. This function is called twice for each 512-byte page. + */ +static int nand_davinci_compare_ecc(u8 *ecc_old, /* read from NAND memory */ + u8 *ecc_new, /* read from register */ + u8 *page_data) /* actual page data */ +{ + int i; + u32 ecc, ecc_o, ecc_e; + u32 ecce_new, ecce_old; + u32 ecco_new, ecco_old; + + for (i = 0; i < 3; i++) { + ecc_old[i] = ~ecc_old[i]; + ecc_new[i] = ~ecc_new[i]; + } + + /* Note that Even and Odd bits are interleaved! + * + * After the following operation, the ECC bits are + * formatted like this: + * + * bit0 == P1E + * bit1 == P1O + * : + * bit20 == P1024E + * bit21 == P1024O + * + * Please note, that P2048e/o are discarded (always 1). + */ + ecce_old = ecc_old[2]>>2 | ecc_old[1]<<6 | ecc_old[0]<<14; + ecce_new = ecc_new[2]>>2 | ecc_new[1]<<6 | ecc_new[0]<<14; + + /* Align ECC(Odd) and clear all remaining bits. + * + * After the following operations for Odd and Even ECC values, + * the bits are formatted like this: + * + * Even Odd + * bit0 == P1E P1O + * bit1 == 1 0 + * bit2 == P2E P2O + * bit3 == 1 0 + * : + * bit20 == P1024E P1024O + * bit21 == 1 0 + */ + + /* Align ECC(Odd) */ + ecco_old = ecce_old >> 1; + ecco_new = ecce_new >> 1; + + /* Mask ECC(Odd) */ + ecco_old &= MASK_ODD; + ecco_new &= MASK_ODD; + + /* Mask ECC(Even) */ + ecce_old |= MASK_EVEN; + ecce_new |= MASK_EVEN; + + /* Calculate overall ECC */ + ecc_o = ecco_old ^ ecco_new; + ecc_e = ecce_old ^ ecce_new; + ecc = ecc_e ^ ecc_o; + + /* When ecc equals 0, no error occured */ + if (!ecc) { + /* This shouldn't happen, because the memcmp() in + * nand_davinci_correct_data() would have caught it. + */ + return 0; + } + + /* If a single bit is set in ecc, only an ECC value is wrong */ + if (!(ecc & (ecc-1))) { + printk(KERN_NOTICE "Ignoring incorrect ECC value; " \ + "data is ok.\n"); + return 0; + } + + /* Check for single correctable bit error (ecc is all 1's)*/ + if (!(~ecc)) { + u16 addr = 0; + u8 byte, bit; + + /* Calculate address of incorrect bit */ + for (i = 0; i < 11; i++) { + addr |= (ecc_o & 0x1) << i; + ecc_o >>= 2; + } + + byte = addr >> 3; /* 3 bit column parity */ + bit = addr & 0x7; /* 8 bit row parity */ + + /* Now flip the corresponding bit */ + page_data[byte] ^= (1 << bit); + + printk(KERN_NOTICE "Corrected single bit: byte %d bit %d\n", + byte, bit); + + return 0; + } + + /* Unrecoverable error in page data */ + return -1; +} + +static int nand_davinci_correct_data(struct mtd_info *mtd, u_char *dat, + u_char *read_ecc, u_char *calc_ecc) +{ + struct nand_chip *chip; + int block_count = 0, i, r; + + chip = mtd->priv; + block_count = chip->ecc.mode == NAND_ECC_HW12_2048 ? 4 : 1; + + for (i = 0; i < block_count; i++) { + if (memcmp(read_ecc, calc_ecc, 3) != 0) { + r = nand_davinci_compare_ecc(read_ecc, calc_ecc, dat); + if (r < 0) + return r; + } + read_ecc += 3; + calc_ecc += 3; + dat += 512; + } + return 0; +} +#endif + +/* + * Read OOB data from flash. + */ +static int read_oob_and_check(struct mtd_info *mtd, loff_t offs, uint8_t *buf, + struct nand_bbt_descr *bd) +{ + int i, ret; + int page; + struct nand_chip *chip = mtd->priv; + + /* Calculate page address from offset */ + page = (int)(offs >> chip->page_shift); + page &= chip->pagemask; + + /* Read OOB data from flash */ + ret = chip->ecc.read_oob(mtd, chip, page, 1); + if (ret < 0) + return ret; + + /* Copy read OOB data to the buffer*/ + memcpy(buf, chip->oob_poi, mtd->oobsize); + + /* Check pattern against BBM in OOB area */ + for (i = 0; i < bd->len; i++) { + if (buf[bd->offs + i] != bd->pattern[i]) + return 1; + } + return 0; +} + +/* + * Fill in the memory based Bad Block Table (BBT). + */ +static int nand_davinci_memory_bbt(struct mtd_info *mtd, + struct nand_bbt_descr *bd) +{ + int i, numblocks; + int startblock = 0; + loff_t from = 0; + struct nand_chip *chip = mtd->priv; + int blocksize = 1 << chip->bbt_erase_shift; + uint8_t *buf = chip->buffers->databuf; + int len = bd->options & NAND_BBT_SCAN2NDPAGE ? 2 : 1; + + /* -numblocks- is 2 times the actual number of eraseblocks */ + numblocks = mtd->size >> (chip->bbt_erase_shift - 1); + + /* Now loop through all eraseblocks in the flash */ + for (i = startblock; i < numblocks; i += 2) { + int j, ret; + int offs = from; + + /* If NAND_BBT_SCAN2NDPAGE flag is set in bd->options, + * also each 2nd page of an eraseblock is checked + * for a Bad Block Marker. In that case, len equals 2. + */ + for (j = 0; j < len; j++) { + /* Read OOB data and check pattern */ + ret = read_oob_and_check(mtd, from, buf, bd); + if (ret < 0) + return ret; + + /* Check pattern for bad block markers */ + if (ret) { + /* Mark bad block by writing 0b11 in the + table */ + chip->bbt[i >> 3] |= 0x03 << (i & 0x6); + + printk(KERN_WARNING "Bad eraseblock %d at " \ + "0x%08x\n", i >> 1, + (unsigned int)from); + + mtd->ecc_stats.badblocks++; + break; + } + offs += mtd->writesize; + } + + /* Make -from- point to next eraseblock */ + from += blocksize; + } + + printk(KERN_NOTICE "Bad block scan: %d out of %d blocks are bad.\n", + mtd->ecc_stats.badblocks, numblocks>>1); + + return 0; +} + +/* + * This function creates a memory based bad block table (BBT). + * It is largely based on the standard BBT function, but all + * unnecessary junk is thrown out to speed up. + */ +static int nand_davinci_scan_bbt(struct mtd_info *mtd) +{ + struct nand_chip *chip = mtd->priv; + struct nand_bbt_descr *bd; + int len, ret = 0; + + chip->bbt_td = NULL; + chip->bbt_md = NULL; + + /* pagesize determines location of BBM */ + if (mtd->writesize > 512) + bd = &davinci_memorybased_large; + else + bd = &davinci_memorybased_small; + + chip->badblock_pattern = bd; + + /* Use 2 bits per page meaning 4 page markers per byte */ + len = mtd->size >> (chip->bbt_erase_shift + 2); + + /* Allocate memory (2bit per block) and clear the memory bad block + table */ + chip->bbt = kzalloc(len, GFP_KERNEL); + if (!chip->bbt) { + printk(KERN_ERR "nand_davinci_scan_bbt: Out of memory\n"); + return -ENOMEM; + } + + /* Now try to fill in the BBT */ + ret = nand_davinci_memory_bbt(mtd, bd); + if (ret) { + printk(KERN_ERR "nand_davinci_scan_bbt: " + "Can't scan flash and build the RAM-based BBT\n"); + + kfree(chip->bbt); + chip->bbt = NULL; + } + + return ret; +} + +/* + * Read from memory register: we can read 4 bytes at a time. + * The hardware takes care of actually reading the NAND flash. + */ +static void nand_davinci_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) +{ + int i; + int num_words = len >> 2; + u32 *p = (u32 *)buf; + struct nand_chip *chip = mtd->priv; + + for (i = 0; i < num_words; i++) + p[i] = readl(chip->IO_ADDR_R); +} + +/* + * Check hardware register for wait status. Returns 1 if device is ready, + * 0 if it is still busy. + */ +static int davinci_nand_dev_ready(struct mtd_info *mtd) +{ + return (davinci_nand_readl(NANDFSR_OFFSET) & NAND_BUSY_FLAG); +} + +static void davinci_nand_set_eccsize(struct nand_chip *chip) +{ + chip->ecc.size = 256; + +#ifdef CONFIG_NAND_FLASH_HW_ECC + switch (chip->ecc.mode) { + case NAND_ECC_HW12_2048: + chip->ecc.size = 2048; + break; + + case NAND_ECC_HW3_512: + case NAND_ECC_HW6_512: + case NAND_ECC_HW8_512: + chip->ecc.size = 512; + break; + + case NAND_ECC_HW3_256: + default: + /* do nothing */ + break; + } +#endif +} + +static void davinci_nand_set_eccbytes(struct nand_chip *chip) +{ + chip->ecc.bytes = 3; + +#ifdef CONFIG_NAND_FLASH_HW_ECC + switch (chip->ecc.mode) { + case NAND_ECC_HW12_2048: + chip->ecc.bytes += 4; + case NAND_ECC_HW8_512: + chip->ecc.bytes += 2; + case NAND_ECC_HW6_512: + chip->ecc.bytes += 3; + case NAND_ECC_HW3_512: + case NAND_ECC_HW3_256: + default: + /* do nothing */ + break; + } +#endif +} + +static void __init nand_flash_init(void) +{ + u32 regval, tmp; + + /* Check for correct pin mux, reconfigure if necessary */ + tmp = davinci_readl(DAVINCI_SYSTEM_MODULE_BASE + PINMUX0); + + if ((tmp & 0x20020C1F) != 0x00000C1F) { + /* Disable HPI and ATA mux */ + davinci_mux_peripheral(DAVINCI_MUX_HPIEN, 0); + davinci_mux_peripheral(DAVINCI_MUX_ATAEN, 0); + + /* Enable VLYNQ and AEAW */ + davinci_mux_peripheral(DAVINCI_MUX_AEAW0, 1); + davinci_mux_peripheral(DAVINCI_MUX_AEAW1, 1); + davinci_mux_peripheral(DAVINCI_MUX_AEAW2, 1); + davinci_mux_peripheral(DAVINCI_MUX_AEAW3, 1); + davinci_mux_peripheral(DAVINCI_MUX_AEAW4, 1); + davinci_mux_peripheral(DAVINCI_MUX_VLSCREN, 1); + davinci_mux_peripheral(DAVINCI_MUX_VLYNQEN, 1); + + regval = davinci_readl(DAVINCI_SYSTEM_MODULE_BASE + PINMUX0); + + printk(KERN_WARNING "Warning: MUX config for NAND: Set " \ + "PINMUX0 reg to 0x%08x, was 0x%08x, should be done " \ + "by bootloader.\n", regval, tmp); + } + + regval = davinci_nand_readl(AWCCR_OFFSET); + regval |= 0x10000000; + davinci_nand_writel(regval, AWCCR_OFFSET); + + /*------------------------------------------------------------------* + * NAND FLASH CHIP TIMEOUT @ 459 MHz * + * * + * AEMIF.CLK freq = PLL1/6 = 459/6 = 76.5 MHz * + * AEMIF.CLK period = 1/76.5 MHz = 13.1 ns * + * * + *------------------------------------------------------------------*/ + regval = 0 + | (0 << 31) /* selectStrobe */ + | (0 << 30) /* extWait */ + | (1 << 26) /* writeSetup 10 ns */ + | (3 << 20) /* writeStrobe 40 ns */ + | (1 << 17) /* writeHold 10 ns */ + | (0 << 13) /* readSetup 10 ns */ + | (3 << 7) /* readStrobe 60 ns */ + | (0 << 4) /* readHold 10 ns */ + | (3 << 2) /* turnAround ?? ns */ + | (0 << 0) /* asyncSize 8-bit bus */ + ; + tmp = davinci_nand_readl(A1CR_OFFSET); + if (tmp != regval) { + printk(KERN_WARNING "Warning: NAND config: Set A1CR " \ + "reg to 0x%08x, was 0x%08x, should be done by " \ + "bootloader.\n", regval, tmp); + davinci_nand_writel(regval, A1CR_OFFSET); /* 0x0434018C */ + } + + davinci_nand_writel(0x00000101, NANDFCR_OFFSET); +} + +/* + * Main initialization routine + */ +int __init nand_davinci_init(void) +{ +#ifdef CONFIG_MTD_CMDLINE_PARTS + char *master_name; + int mtd_parts_nb = 0; + struct mtd_partition *mtd_parts = 0; +#endif + struct nand_chip *chip; + struct device *dev = NULL; + u32 nand_rev_code; + + nand_clock = clk_get(dev, "AEMIFCLK"); + if (IS_ERR(nand_clock)) { + printk(KERN_ERR "Error %ld getting AEMIFCLK clock?\n", + PTR_ERR(nand_clock)); + return -1; + } + + clk_enable(nand_clock); + + /* Allocate memory for MTD device structure and private data */ + nand_davinci_mtd = kmalloc(sizeof(struct mtd_info) + + sizeof(struct nand_chip), GFP_KERNEL); + + if (!nand_davinci_mtd) { + printk(KERN_ERR "Unable to allocate davinci NAND MTD device " \ + "structure.\n"); + clk_disable(nand_clock); + return -ENOMEM; + } + + /* Get pointer to private data */ + chip = (struct nand_chip *) (&nand_davinci_mtd[1]); + + /* Initialize structures */ + memset((char *)nand_davinci_mtd, 0, sizeof(struct mtd_info)); + memset((char *)chip, 0, sizeof(struct nand_chip)); + + /* Link the private data with the MTD structure */ + nand_davinci_mtd->priv = chip; + + nand_rev_code = davinci_nand_readl(NRCSR_OFFSET); + + printk("DaVinci NAND Controller rev. %d.%d\n", + (nand_rev_code >> 8) & 0xff, nand_rev_code & 0xff); + + nand_vaddr = ioremap(DAVINCI_ASYNC_EMIF_DATA_CE0_BASE, SZ_16K); + if (nand_vaddr == NULL) { + printk(KERN_ERR "DaVinci NAND: ioremap failed.\n"); + clk_disable(nand_clock); + kfree(nand_davinci_mtd); + return -ENOMEM; + } + + chip->IO_ADDR_R = (void __iomem *)nand_vaddr; + chip->IO_ADDR_W = (void __iomem *)nand_vaddr; + chip->chip_delay = 0; + chip->select_chip = nand_davinci_select_chip; + chip->options = 0; + chip->ecc.mode = DAVINCI_NAND_ECC_MODE; + + /* Set ECC size and bytes */ + davinci_nand_set_eccsize(chip); + davinci_nand_set_eccbytes(chip); + + /* Set address of hardware control function */ + chip->cmd_ctrl = nand_davinci_hwcontrol; + chip->dev_ready = davinci_nand_dev_ready; + +#ifdef CONFIG_NAND_FLASH_HW_ECC + chip->ecc.calculate = nand_davinci_calculate_ecc; + chip->ecc.correct = nand_davinci_correct_data; + chip->ecc.hwctl = nand_davinci_enable_hwecc; +#endif + + /* Speed up the read buffer */ + chip->read_buf = nand_davinci_read_buf; + + /* Speed up the creation of the bad block table */ + chip->scan_bbt = nand_davinci_scan_bbt; + + nand_flash_init(); + + /* Scan to find existence of the device */ + if (nand_scan(nand_davinci_mtd, 1)) { + printk(KERN_ERR "Chip Select is not set for NAND\n"); + clk_disable(nand_clock); + kfree(nand_davinci_mtd); + return -ENXIO; + } + + nand_davinci_mtd->owner = THIS_MODULE; + + /* Register the partitions */ + add_mtd_partitions(nand_davinci_mtd, partition_info, NUM_PARTITIONS); + +#ifdef CONFIG_MTD_CMDLINE_PARTS + /* Set nand_davinci_mtd->name = 0 temporarily */ + master_name = nand_davinci_mtd->name; + nand_davinci_mtd->name = (char *)0; + + /* nand_davinci_mtd->name == 0, means: don't bother checking + <mtd-id> */ + mtd_parts_nb = parse_mtd_partitions(nand_davinci_mtd, part_probes, + &mtd_parts, 0); + + /* Restore nand_davinci_mtd->name */ + nand_davinci_mtd->name = master_name; + + add_mtd_partitions(nand_davinci_mtd, mtd_parts, mtd_parts_nb); +#endif + + return 0; +} +module_init(nand_davinci_init); + +/* + * Clean up routine + */ +#ifdef MODULE +static void __exit nand_davinci_cleanup(void) +{ + clk_disable(nand_clock); + + if (nand_vaddr) + iounmap(nand_vaddr); + + /* 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"); Index: linux-davinci/drivers/mtd/nand/Makefile =================================================================== --- linux-davinci.orig/drivers/mtd/nand/Makefile +++ linux-davinci/drivers/mtd/nand/Makefile @@ -29,5 +29,6 @@ obj-$(CONFIG_MTD_NAND_AT91) += at91_nan 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_DAVINCI) += davinci_nand.o nand-objs := nand_base.o nand_bbt.o Index: linux-davinci/drivers/mtd/nand/Kconfig =================================================================== --- linux-davinci.orig/drivers/mtd/nand/Kconfig +++ linux-davinci/drivers/mtd/nand/Kconfig @@ -293,5 +293,23 @@ config MTD_NAND_PLATFORM devices. You will need to provide platform-specific functions via platform_data. +config MTD_NAND_DAVINCI + tristate "NAND Flash device on DaVinci SoC" + depends on MTD_NAND + select MTD_PARTITIONS + help + Support for NAND flash on Texas Instruments DaVinci SoC. + +config NAND_FLASH_HW_ECC + bool "Hardware ECC Support on NAND Device for DaVinci" + depends on MTD_NAND_DAVINCI + help + Support for Hardware ECC on NAND device for DaVinci. + +config NAND_FLASH_LINUX + bool "Bootloader upgrade on NAND Device for DaVinci" + depends on MTD_NAND_DAVINCI + help + Support for flashing U-Boot/Linux Image on NAND device for DaVinci. endif # MTD_NAND Index: linux-davinci/include/asm-arm/arch-davinci/nand.h =================================================================== --- /dev/null +++ linux-davinci/include/asm-arm/arch-davinci/nand.h @@ -0,0 +1,116 @@ +/* + * include/asm-arm/arch-davinci/nand.h + * + * Copyright (C) 2006 Texas Instruments. + * + * ported to 2.6.23 (C) 2008 by + * Sander Huijsen <[EMAIL PROTECTED]> + * Dirk Behme <[EMAIL PROTECTED]> + * + * -------------------------------------------------------------------------- + * + * 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. + * -------------------------------------------------------------------------- + * + */ + +#ifndef __ARCH_ARM_DAVINCI_NAND_H +#define __ARCH_ARM_DAVINCI_NAND_H + +#define NRCSR_OFFSET 0x00 +#define AWCCR_OFFSET 0x04 +#define A1CR_OFFSET 0x10 +#define NANDFCR_OFFSET 0x60 +#define NANDFSR_OFFSET 0x64 +#define NANDF1ECC_OFFSET 0x70 + +#define MASK_ALE 0x0A +#define MASK_CLE 0x10 + +#define MASK_EVEN 0xFFEAAAAA +#define MASK_ODD (~MASK_EVEN) + +#define NAND_BUSY_FLAG 0x01 + +#ifdef CONFIG_NAND_FLASH_HW_ECC +#define NAND_Ecc_P1e (1 << 0) +#define NAND_Ecc_P2e (1 << 1) +#define NAND_Ecc_P4e (1 << 2) +#define NAND_Ecc_P8e (1 << 3) +#define NAND_Ecc_P16e (1 << 4) +#define NAND_Ecc_P32e (1 << 5) +#define NAND_Ecc_P64e (1 << 6) +#define NAND_Ecc_P128e (1 << 7) +#define NAND_Ecc_P256e (1 << 8) +#define NAND_Ecc_P512e (1 << 9) +#define NAND_Ecc_P1024e (1 << 10) +#define NAND_Ecc_P2048e (1 << 11) + +#define NAND_Ecc_P1o (1 << 16) +#define NAND_Ecc_P2o (1 << 17) +#define NAND_Ecc_P4o (1 << 18) +#define NAND_Ecc_P8o (1 << 19) +#define NAND_Ecc_P16o (1 << 20) +#define NAND_Ecc_P32o (1 << 21) +#define NAND_Ecc_P64o (1 << 22) +#define NAND_Ecc_P128o (1 << 23) +#define NAND_Ecc_P256o (1 << 24) +#define NAND_Ecc_P512o (1 << 25) +#define NAND_Ecc_P1024o (1 << 26) +#define NAND_Ecc_P2048o (1 << 27) + +#define TF(value) (value ? 1 : 0) + +#define P2048e(a) (TF(a & NAND_Ecc_P2048e) << 0) +#define P2048o(a) (TF(a & NAND_Ecc_P2048o) << 1) +#define P1e(a) (TF(a & NAND_Ecc_P1e) << 2) +#define P1o(a) (TF(a & NAND_Ecc_P1o) << 3) +#define P2e(a) (TF(a & NAND_Ecc_P2e) << 4) +#define P2o(a) (TF(a & NAND_Ecc_P2o) << 5) +#define P4e(a) (TF(a & NAND_Ecc_P4e) << 6) +#define P4o(a) (TF(a & NAND_Ecc_P4o) << 7) + +#define P8e(a) (TF(a & NAND_Ecc_P8e) << 0) +#define P8o(a) (TF(a & NAND_Ecc_P8o) << 1) +#define P16e(a) (TF(a & NAND_Ecc_P16e) << 2) +#define P16o(a) (TF(a & NAND_Ecc_P16o) << 3) +#define P32e(a) (TF(a & NAND_Ecc_P32e) << 4) +#define P32o(a) (TF(a & NAND_Ecc_P32o) << 5) +#define P64e(a) (TF(a & NAND_Ecc_P64e) << 6) +#define P64o(a) (TF(a & NAND_Ecc_P64o) << 7) + +#define P128e(a) (TF(a & NAND_Ecc_P128e) << 0) +#define P128o(a) (TF(a & NAND_Ecc_P128o) << 1) +#define P256e(a) (TF(a & NAND_Ecc_P256e) << 2) +#define P256o(a) (TF(a & NAND_Ecc_P256o) << 3) +#define P512e(a) (TF(a & NAND_Ecc_P512e) << 4) +#define P512o(a) (TF(a & NAND_Ecc_P512o) << 5) +#define P1024e(a) (TF(a & NAND_Ecc_P1024e) << 6) +#define P1024o(a) (TF(a & NAND_Ecc_P1024o) << 7) + +#define P8e_s(a) (TF(a & NAND_Ecc_P8e) << 0) +#define P8o_s(a) (TF(a & NAND_Ecc_P8o) << 1) +#define P16e_s(a) (TF(a & NAND_Ecc_P16e) << 2) +#define P16o_s(a) (TF(a & NAND_Ecc_P16o) << 3) +#define P1e_s(a) (TF(a & NAND_Ecc_P1e) << 4) +#define P1o_s(a) (TF(a & NAND_Ecc_P1o) << 5) +#define P2e_s(a) (TF(a & NAND_Ecc_P2e) << 6) +#define P2o_s(a) (TF(a & NAND_Ecc_P2o) << 7) + +#define P4e_s(a) (TF(a & NAND_Ecc_P4e) << 0) +#define P4o_s(a) (TF(a & NAND_Ecc_P4o) << 1) +#endif + +#endif /* __ARCH_ARM_DAVINCI_NAND_H */ Index: linux-davinci/arch/arm/mach-davinci/mux.c =================================================================== --- linux-davinci.orig/arch/arm/mach-davinci/mux.c +++ linux-davinci/arch/arm/mach-davinci/mux.c @@ -15,10 +15,6 @@ #include <asm/arch/mux.h> -/* System control register offsets */ -#define PINMUX0 0x00 -#define PINMUX1 0x04 - static DEFINE_SPINLOCK(mux_lock); void davinci_mux_peripheral(unsigned int mux, unsigned int enable) Index: linux-davinci/include/asm-arm/arch-davinci/mux.h =================================================================== --- linux-davinci.orig/include/asm-arm/arch-davinci/mux.h +++ linux-davinci/include/asm-arm/arch-davinci/mux.h @@ -11,6 +11,11 @@ #ifndef __ASM_ARCH_MUX_H #define __ASM_ARCH_MUX_H +/* System control register offsets */ +#define PINMUX0 0x00 +#define PINMUX1 0x04 + +/* System control register bits */ #define DAVINCI_MUX_AEAW0 0 #define DAVINCI_MUX_AEAW1 1 #define DAVINCI_MUX_AEAW2 2 Index: linux-davinci/include/linux/mtd/nand.h =================================================================== --- linux-davinci.orig/include/linux/mtd/nand.h +++ linux-davinci/include/linux/mtd/nand.h @@ -123,6 +123,13 @@ typedef enum { NAND_ECC_SOFT, NAND_ECC_HW, NAND_ECC_HW_SYNDROME, +#ifdef CONFIG_NAND_FLASH_HW_ECC + NAND_ECC_HW3_256, + NAND_ECC_HW3_512, + NAND_ECC_HW6_512, + NAND_ECC_HW8_512, + NAND_ECC_HW12_2048, +#endif } nand_ecc_modes_t; /* Index: linux-davinci/drivers/mtd/nand/nand_base.c =================================================================== --- linux-davinci.orig/drivers/mtd/nand/nand_base.c +++ linux-davinci/drivers/mtd/nand/nand_base.c @@ -2456,6 +2456,13 @@ int nand_scan_tail(struct mtd_info *mtd) chip->ecc.write_page_raw = nand_write_page_raw; switch (chip->ecc.mode) { +#ifdef CONFIG_NAND_FLASH_HW_ECC + case NAND_ECC_HW12_2048: + case NAND_ECC_HW8_512: + case NAND_ECC_HW6_512: + case NAND_ECC_HW3_512: + case NAND_ECC_HW3_256: +#endif case NAND_ECC_HW: /* Use standard hwecc read page function ? */ if (!chip->ecc.read_page)
_______________________________________________ Davinci-linux-open-source mailing list Davinci-linux-open-source@linux.davincidsp.com http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source