Sander Huijsen wrote:
We've been using the nand_davinci driver for some time now in the 2.6.20
kernel. We have ported the 2.6.10 version to 2.6.20, therefore I think
some work needs to be done to get the driver into the 2.6.23 tree.
Attached you'll find the files that we changed in order to use NAND
flash with the DaVinci. I hope you'll be able to take these files and
integrate them into the git-tree. There is just one thing you should be
aware of: we're using the flash a little bit differently than intended.
It has to do with the mapping of partitions on mtd devices. In the
driver source file nand_davinci.c, you can find this in line 695-698, so
you probably want to remove these lines. :-)

This driver is tested on the following NAND devices: * ST NAND512R3A (512 Mbit, page size: 512+16 bytes, block size: 16K+512
bytes)
* Samsung K9F1208R0C-JIB0 (512 Mbit, page size: 512+16 bytes, block
size: 16K+512 bytes)

Let us know how you're doing.

Many thanks!

In case somebody finds it useful or likes to test, result of first cleanup in attachment.

It applies and compiles cleanly against recent git and checkpatch is happy about it. Hopefully no functional change, but not runtime tested yet.

Best regards

Dirk

-----Original Message-----
From:
[EMAIL PROTECTED]
cidsp.com
[mailto:[EMAIL PROTECTED]
ux.davincidsp.com] On Behalf Of Dirk Behme
Sent: Wednesday, December 19, 2007 8:23 AM
To: [email protected]
Subject: Re: NAND support in git kernel

Kevin Hilman wrote:

Philip Balister wrote:


I've been beating my head against a wall trying to figure out how to
support NAND flash with the git kernel. My current thought is that I
need to take the NAND driver from the MV kernel and get it working

with

git. Is this the correct approach? Or is there a better approach?

You're right.  The NAND driver has yet to be forward ported from the

MV

kernel.


Anybody works on this? I'd like to have a look to it, would be nice if I don't have to start from scratch though ;)

Cheers

Dirk


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) 2007 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;
+#endif
+       struct nand_chip     *chip;
+       struct device        *dev = NULL;
+       u32                  nand_rev_code;
+       int                  mtd_parts_nb = 0;
+       struct mtd_partition *mtd_parts = 0;
+
+       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) 2007 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
[email protected]
http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source

Reply via email to