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

Reply via email to