Index: linux-davinci/drivers/mtd/nand/davinci_nand.c =================================================================== --- /dev/null +++ linux-davinci/drivers/mtd/nand/davinci_nand.c @@ -0,0 +1,638 @@ +/* + * 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 + * Troy Kisky + * Dirk Behme + * + * -------------------------------------------------------------------------- + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#ifdef CONFIG_NAND_FLASH_HW_ECC +#define DAVINCI_NAND_ECC_MODE NAND_ECC_HW3_512 +#else +#define DAVINCI_NAND_ECC_MODE NAND_ECC_SOFT +#endif + +#define DRIVER_NAME "davinci_nand" + +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 + +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) +{ + /* Read register ECC and clear it */ + return davinci_nand_readl(NANDF1ECC_OFFSET); +} + +/* + * 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 = nand_davinci_readecc(mtd); + /* squeeze 0 middle bits out so that it fits in 3 bytes */ + unsigned int tmp = (ecc_val&0x0fff)|((ecc_val&0x0fff0000)>>4); + /* invert so that erased block ecc is correct */ + tmp = ~tmp; + ecc_code[0] = (u_char)(tmp); + ecc_code[1] = (u_char)(tmp >> 8); + ecc_code[2] = (u_char)(tmp >> 16); + + return 0; +} + +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 = mtd->priv; + u_int32_t eccNand = read_ecc[0] | (read_ecc[1] << 8) | + (read_ecc[2] << 16); + u_int32_t eccCalc = calc_ecc[0] | (calc_ecc[1] << 8) | + (calc_ecc[2] << 16); + u_int32_t diff = eccCalc ^ eccNand; + + if (diff) { + if ((((diff>>12)^diff) & 0xfff) == 0xfff) { + /* Correctable error */ + if ((diff>>(12+3)) < chip->ecc.size) { + dat[diff>>(12+3)] ^= (1 << ((diff>>12)&7)); + return 1; + } else { + return -1; + } + } else if (!(diff & (diff-1))) { + /* Single bit ECC error in the ECC itself, + nothing to fix */ + return 1; + } else { + /* Uncorrectable error */ + return -1; + } + + } + 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 nand_davinci_dev_ready(struct mtd_info *mtd) +{ + return (davinci_nand_readl(NANDFSR_OFFSET) & NAND_BUSY_FLAG); +} + +static void nand_davinci_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 nand_davinci_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 __devinit nand_davinci_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 __devinit nand_davinci_probe(struct platform_device *pdev) +{ + struct nand_platform_data *pdata = pdev->dev.platform_data; + struct resource *res = pdev->resource; + struct nand_chip *chip; + struct device *dev = NULL; + u32 nand_rev_code; +#ifdef CONFIG_MTD_CMDLINE_PARTS + char *master_name; + int mtd_parts_nb = 0; + struct mtd_partition *mtd_parts = 0; +#endif + + 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(res->start, res->end - res->start); + 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 */ + nand_davinci_set_eccsize(chip); + nand_davinci_set_eccbytes(chip); + + /* Set address of hardware control function */ + chip->cmd_ctrl = nand_davinci_hwcontrol; + chip->dev_ready = nand_davinci_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_davinci_flash_init(); + + nand_davinci_mtd->owner = THIS_MODULE; + + /* 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; + } + + /* Register the partitions */ + add_mtd_partitions(nand_davinci_mtd, pdata->parts, pdata->nr_parts); + +#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_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; +} + +/* + * Clean up routine + */ +static int nand_davinci_remove(struct platform_device *pdev) +{ + 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); + + return 0; +} + + +static struct platform_driver nand_davinci_driver = { + .probe = nand_davinci_probe, + .remove = nand_davinci_remove, + .driver = { + .name = DRIVER_NAME, + }, +}; + +static int __init nand_davinci_init(void) +{ + return platform_driver_register(&nand_davinci_driver); +} +module_init(nand_davinci_init); + +#ifdef MODULE +static void __exit nand_davinci_exit(void) +{ + platform_driver_unregister(&nand_davinci_driver); +} +module_exit(nand_davinci_exit); +#endif + +MODULE_ALIAS(DRIVER_NAME); +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,17 @@ 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. 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,45 @@ +/* + * include/asm-arm/arch-davinci/nand.h + * + * Copyright (C) 2006 Texas Instruments. + * + * ported to 2.6.23 (C) 2008 by + * Sander Huijsen + * Troy Kisky + * Dirk Behme + * + * -------------------------------------------------------------------------- + * + * 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 NAND_BUSY_FLAG 0x01 + +#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 -/* 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) Index: linux-davinci/arch/arm/mach-davinci/board-evm.c =================================================================== --- linux-davinci.orig/arch/arm/mach-davinci/board-evm.c +++ linux-davinci/arch/arm/mach-davinci/board-evm.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -27,6 +28,7 @@ #include #include +#include #include /* other misc. init functions */ @@ -38,7 +40,7 @@ void __init davinci_init_common_hw(void) /* NOR Flash base address set to CS0 by default */ #define NOR_FLASH_PHYS 0x02000000 -static struct mtd_partition davinci_evm_partitions[] = { +static struct mtd_partition davinci_evm_norflash_partitions[] = { /* bootloader (U-Boot, etc) in first 4 sectors */ { .name = "bootloader", @@ -69,30 +71,63 @@ static struct mtd_partition davinci_evm_ } }; -static struct physmap_flash_data davinci_evm_flash_data = { +static struct physmap_flash_data davinci_evm_norflash_data = { .width = 2, - .parts = davinci_evm_partitions, - .nr_parts = ARRAY_SIZE(davinci_evm_partitions), + .parts = davinci_evm_norflash_partitions, + .nr_parts = ARRAY_SIZE(davinci_evm_norflash_partitions), }; /* NOTE: CFI probe will correctly detect flash part as 32M, but EMIF * limits addresses to 16M, so using addresses past 16M will wrap */ -static struct resource davinci_evm_flash_resource = { +static struct resource davinci_evm_norflash_resource = { .start = NOR_FLASH_PHYS, .end = NOR_FLASH_PHYS + SZ_16M - 1, .flags = IORESOURCE_MEM, }; -static struct platform_device davinci_evm_flash_device = { +static struct platform_device davinci_evm_norflash_device = { .name = "physmap-flash", .id = 0, .dev = { - .platform_data = &davinci_evm_flash_data, + .platform_data = &davinci_evm_norflash_data, }, .num_resources = 1, - .resource = &davinci_evm_flash_resource, + .resource = &davinci_evm_norflash_resource, }; +#if defined(CONFIG_MTD_NAND_DAVINCI) || defined(CONFIG_MTD_NAND_DAVINCI_MODULE) +struct mtd_partition davinci_evm_nandflash_partition[] = { + /* 5 MB space at the beginning for bootloader and kernel */ + { + .name = "NAND filesystem", + .offset = 5 * SZ_1M, + .size = MTDPART_SIZ_FULL, + .mask_flags = 0, + } +}; + +static struct nand_platform_data davinci_evm_nandflash_data = { + .parts = davinci_evm_nandflash_partition, + .nr_parts = ARRAY_SIZE(davinci_evm_nandflash_partition), +}; + +static struct resource davinci_evm_nandflash_resource = { + .start = DAVINCI_ASYNC_EMIF_DATA_CE0_BASE, + .end = DAVINCI_ASYNC_EMIF_DATA_CE0_BASE + SZ_16K - 1, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device davinci_evm_nandflash_device = { + .name = "davinci_nand", + .id = 0, + .dev = { + .platform_data = &davinci_evm_nandflash_data, + }, + .num_resources = 1, + .resource = &davinci_evm_nandflash_resource, +}; +#endif + #if defined(CONFIG_FB_DAVINCI) || defined(CONFIG_FB_DAVINCI_MODULE) static u64 davinci_fb_dma_mask = DMA_32BIT_MASK; @@ -168,7 +203,10 @@ static struct platform_device rtc_dev = }; static struct platform_device *davinci_evm_devices[] __initdata = { - &davinci_evm_flash_device, + &davinci_evm_norflash_device, +#if defined(CONFIG_MTD_NAND_DAVINCI) || defined(CONFIG_MTD_NAND_DAVINCI_MODULE) + &davinci_evm_nandflash_device, +#endif #if defined(CONFIG_FB_DAVINCI) || defined(CONFIG_FB_DAVINCI_MODULE) &davinci_fb_device, #endif