summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorScott Sweeny <scott.sweeny@timesys.com>2010-09-01 12:02:01 -0400
committerScott Sweeny <scott.sweeny@timesys.com>2010-09-01 12:06:18 -0400
commit3456a4958ec2ecb2b2e35b1f37039fb28274f182 (patch)
treebf6aef6608c5410ad8b7e4f49dc2cc58aad22538 /drivers
parente1dce181db649aadcf5c83e9459ebf53dd038073 (diff)
Freescale board patch for MPC5125_TWR board
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mtd/nand/Makefile3
-rw-r--r--drivers/mtd/nand/fsl_nfc_nand.c1104
-rw-r--r--drivers/mtd/nand/fsl_nfc_nand_5125.c919
-rw-r--r--drivers/mtd/nand/mpc5125_nfc_mtc.mtcbin0 -> 18720 bytes
-rw-r--r--drivers/mtd/nand/mpc5125_nfc_struct.h27
-rw-r--r--drivers/mtd/nand/nand_base.c14
-rw-r--r--drivers/mtd/nand/nand_ids.c3
-rw-r--r--drivers/net/mpc512x_fec.c65
8 files changed, 2118 insertions, 17 deletions
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index 5974d7768d..33fcb91fcf 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -41,6 +41,8 @@ COBJS-$(CONFIG_NAND_FSL_UPM) += fsl_upm.o
COBJS-$(CONFIG_NAND_NOMADIK) += nomadik.o
COBJS-$(CONFIG_NAND_S3C64XX) += s3c64xx.o
COBJS-$(CONFIG_NAND_OMAP_GPMC) += omap_gpmc.o
+#COBJS-$(CONFIG_NAND_FSL_NFC) += fsl_nfc_nand.o
+COBJS-$(CONFIG_NAND_FSL_NFC) += fsl_nfc_nand_5125.o mpc5125_nfc_mtc.mtc
endif
COBJS := $(COBJS-y)
@@ -49,6 +51,7 @@ OBJS := $(addprefix $(obj),$(COBJS))
all: $(LIB)
+
$(LIB): $(obj).depend $(OBJS)
$(AR) $(ARFLAGS) $@ $(OBJS)
diff --git a/drivers/mtd/nand/fsl_nfc_nand.c b/drivers/mtd/nand/fsl_nfc_nand.c
new file mode 100644
index 0000000000..6efe18e865
--- /dev/null
+++ b/drivers/mtd/nand/fsl_nfc_nand.c
@@ -0,0 +1,1104 @@
+/*
+ * Copyright (C) 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * Based on drivers/mtd/nand/mpc5121_nand.c
+ * which was based on drivers/mtd/nand/mxc_nd.c
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <common.h>
+#include <malloc.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_ecc.h>
+
+#include <asm/io.h>
+#include <nand.h>
+
+#define MIN(x, y) ((x < y) ? x : y)
+
+static struct fsl_nfc_private {
+ struct mtd_info mtd;
+ char spare_only;
+ char status_req;
+ u16 col_addr;
+ int writesize;
+ int sparesize;
+ int width;
+ int chipsel;
+} *priv;
+
+#define IS_2K_PAGE_NAND (priv->writesize == 2048)
+#define IS_4K_PAGE_NAND (priv->writesize == 4096)
+#define IS_LARGE_PAGE_NAND (priv->writesize > 512)
+
+#define NFC_REG_BASE ((void *)CONFIG_SYS_NAND_BASE)
+/*
+ * FSL NFC registers Definition
+ */
+#define NFC_BUF_ADDR (NFC_REG_BASE + 0x1E04)
+#define NFC_FLASH_ADDR (NFC_REG_BASE + 0x1E06)
+#define NFC_FLASH_CMD (NFC_REG_BASE + 0x1E08)
+#define NFC_CONFIG (NFC_REG_BASE + 0x1E0A)
+#define NFC_ECC_STATUS1 (NFC_REG_BASE + 0x1E0C)
+#define NFC_ECC_STATUS2 (NFC_REG_BASE + 0x1E0E)
+#define NFC_SPAS (NFC_REG_BASE + 0x1E10)
+#define NFC_WRPROT (NFC_REG_BASE + 0x1E12)
+#define NFC_NF_WRPRST (NFC_REG_BASE + 0x1E18)
+#define NFC_CONFIG1 (NFC_REG_BASE + 0x1E1A)
+#define NFC_CONFIG2 (NFC_REG_BASE + 0x1E1C)
+#define NFC_UNLOCKSTART_BLKADDR0 (NFC_REG_BASE + 0x1E20)
+#define NFC_UNLOCKEND_BLKADDR0 (NFC_REG_BASE + 0x1E22)
+#define NFC_UNLOCKSTART_BLKADDR1 (NFC_REG_BASE + 0x1E24)
+#define NFC_UNLOCKEND_BLKADDR1 (NFC_REG_BASE + 0x1E26)
+#define NFC_UNLOCKSTART_BLKADDR2 (NFC_REG_BASE + 0x1E28)
+#define NFC_UNLOCKEND_BLKADDR2 (NFC_REG_BASE + 0x1E2A)
+#define NFC_UNLOCKSTART_BLKADDR3 (NFC_REG_BASE + 0x1E2C)
+#define NFC_UNLOCKEND_BLKADDR3 (NFC_REG_BASE + 0x1E2E)
+
+/*!
+ * Addresses for NFC MAIN RAM BUFFER areas
+ */
+#define MAIN_AREA(n) (NFC_REG_BASE + (n)*0x200)
+
+/*!
+ * Addresses for NFC SPARE BUFFER areas
+ */
+#define SPARE_LEN 0x40
+#define SPARE_AREA(n) (NFC_REG_BASE + 0x1000 + (n)*SPARE_LEN)
+
+#define NFC_CMD 0x1
+#define NFC_ADDR 0x2
+#define NFC_INPUT 0x4
+#define NFC_OUTPUT 0x8
+#define NFC_ID 0x10
+#define NFC_STATUS 0x20
+
+/* Bit Definitions */
+#define NFC_INT (1 << 15)
+#define NFC_SP_EN (1 << 2)
+#define NFC_ECC_EN (1 << 3)
+#define NFC_INT_MSK (1 << 4)
+#define NFC_BIG (1 << 5)
+#define NFC_RST (1 << 6)
+#define NFC_CE (1 << 7)
+#define NFC_ONE_CYCLE (1 << 8)
+#define NFC_BLS_LOCKED 0
+#define NFC_BLS_LOCKED_DEFAULT 1
+#define NFC_BLS_UNLOCKED 2
+#define NFC_WPC_LOCK_TIGHT 1
+#define NFC_WPC_LOCK (1 << 1)
+#define NFC_WPC_UNLOCK (1 << 2)
+#define NFC_FLASH_ADDR_SHIFT 0
+#define NFC_UNLOCK_END_ADDR_SHIFT 0
+
+#define NFC_ECC_MODE_4 1
+/*
+ * Define delays in microsec for NAND device operations
+ */
+#define TROP_US_DELAY 2000
+
+#if defined(CONFIG_PPC)
+#define NFC_WRITEL(r, v) out_be32(r, v)
+#define NFC_WRITEW(r, v) out_be16(r, v)
+#define NFC_WRITEB(r, v) out_8(r, v)
+#define NFC_READL(r) in_be32(r)
+#define NFC_READW(r) in_be16(r)
+#define NFC_READB(r) in_8(r)
+#elif defined(CONFIG_ARM)
+#define NFC_WRITEL(r, v) writel(v, r)
+#define NFC_WRITEW(r, v) writew(v, r)
+#define NFC_WRITEB(r, v) writeb(r, v)
+#define NFC_READL(r) readl(r)
+#define NFC_READW(r) readw(r)
+#define NFC_READB(r) readb(r)
+#endif
+
+
+#ifdef CONFIG_MTD_NAND_FSL_NFC_SWECC
+static int hardware_ecc;
+#else
+static int hardware_ecc = 1;
+#endif
+
+/*
+ * OOB placement block for use with hardware ecc generation
+ */
+static struct nand_ecclayout nand_hw_eccoob_512 = {
+ .eccbytes = 9,
+ .eccpos = {
+ 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ },
+ .oobfree = {
+ {0, 5} /* byte 5 is factory bad block marker */
+ },
+};
+
+static struct nand_ecclayout nand_hw_eccoob_2k = {
+ .eccbytes = 36,
+ .eccpos = {
+ /* 9 bytes of ecc for each 512 bytes of data */
+ 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ },
+ .oobfree = {
+ {2, 5}, /* bytes 0 and 1 are factory bad block markers */
+ {16, 7},
+ {32, 7},
+ {48, 7},
+ },
+};
+
+static struct nand_ecclayout nand_hw_eccoob_4k = {
+ .eccbytes = 64, /* actually 72 but only room for 64 */
+ .eccpos = {
+ /* 9 bytes of ecc for each 512 bytes of data */
+ 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 103, 104, 105, 106, 107, 108, 109, 110, 111,
+ 119, /* 120, 121, 122, 123, 124, 125, 126, 127, */
+ },
+ .oobfree = {
+ {2, 5}, /* bytes 0 and 1 are factory bad block markers */
+ {16, 7},
+ {32, 7},
+ {48, 7},
+ {64, 7},
+ {80, 7},
+ {96, 7},
+ {112, 7},
+ },
+};
+
+static struct nand_ecclayout nand_hw_eccoob_4k_218_spare = {
+ .eccbytes = 64, /* actually 144 but only room for 64 */
+ .eccpos = {
+ /* 18 bytes of ecc for each 512 bytes of data */
+ 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 33, 34, 35, 36, 37, 38, 39, 40, 41,
+ 42, 43, 44, 45, 46, 47, 48, 49, 50,
+ 59, 60, 61, 62, 63, 64, 65, 66, 67,
+ 68, 69, 70, 71, 72, 73, 74, 75, 76,
+ 85, 86, 87, 88, 89, 90, 91, 92, 93,
+ 94, /* 95, 96, 97, 98, 99, 100, 101, 102,
+ 111, 112, 113, 114, 115, 116, 117, 118, 119,
+ 120, 121, 122, 123, 124, 125, 126, 127, 128,
+ 137, 138, 139, 140, 141, 142, 143, 144, 145,
+ 146, 147, 148, 149, 150, 151, 152, 153, 154,
+ 163, 164, 165, 166, 167, 168, 169, 170, 171,
+ 172, 173, 174, 175, 176, 177, 178, 179, 180,
+ 189, 190, 191, 192, 193, 194, 195, 196, 197,
+ 198, 199, 200, 201, 202, 203, 204, 205, 206, */
+ },
+ .oobfree = {
+ {2, 5}, /* bytes 0 and 1 are factory bad block markers */
+ {25, 8},
+ {51, 8},
+ {77, 8},
+ {103, 8},
+ {129, 8},
+ {155, 8},
+ {181, 8},
+ },
+};
+
+/*
+ * Functions to transfer data to/from spare erea.
+ */
+static void copy_from_spare(struct mtd_info *mtd, void *pbuf, int len)
+{
+ int i, copy_count, copy_size;
+
+ copy_count = mtd->writesize / 512;
+ /*
+ * Each spare area has 16 bytes for 512, 2K and normal 4K nand.
+ * For 4K nand with large 218 byte spare size, the size is 26 bytes for
+ * the first 7 buffers and 36 for the last.
+ */
+ copy_size = priv->sparesize == 218 ? 26 : 16;
+
+ for (i = 0; i < copy_count - 1 && len > 0; i++) {
+ memcpy_fromio(pbuf, SPARE_AREA(i), MIN(len, copy_size));
+ pbuf += copy_size;
+ len -= copy_size;
+ }
+ if (len > 0)
+ memcpy_fromio(pbuf, SPARE_AREA(i), len);
+}
+
+static void copy_to_spare(struct mtd_info *mtd, void *pbuf, int len)
+{
+ int i, copy_count, copy_size;
+
+ copy_count = mtd->writesize / 512;
+ /*
+ * Each spare area has 16 bytes for 512, 2K and normal 4K nand.
+ * For 4K nand with large 218 byte spare size, the size is 26 bytes for
+ * the first 7 buffers and 36 for the last.
+ */
+ copy_size = priv->sparesize == 218 ? 26 : 16;
+
+ /*
+ * Each spare area has 16 bytes for 512, 2K and normal 4K nand.
+ * For 4K nand with large 218 byte spare size, the size is 26 bytes for
+ * the first 7 buffers and 36 for the last.
+ */
+ for (i = 0; i < copy_count - 1 && len > 0; i++) {
+ memcpy_toio(SPARE_AREA(i), pbuf, MIN(len, copy_size));
+ pbuf += copy_size;
+ len -= copy_size;
+ }
+ if (len > 0)
+ memcpy_toio(SPARE_AREA(i), pbuf, len);
+}
+
+/*!
+ * This function polls the NFC to wait for the basic operation to complete by
+ * checking the INT bit of config2 register.
+ *
+ * @max_retries number of retry attempts (separated by 1 us)
+ */
+static void wait_op_done(int max_retries)
+{
+
+ while (1) {
+ max_retries--;
+ if (NFC_READW(NFC_CONFIG2) & NFC_INT)
+ break;
+ udelay(1);
+ }
+ if (max_retries <= 0)
+ MTDDEBUG(MTD_DEBUG_LEVEL0, "%s: INT not set\n", __FUNCTION__);
+}
+
+/*!
+ * This function issues the specified command to the NAND device and
+ * waits for completion.
+ *
+ * @cmds command for NAND Flash
+ */
+static void send_cmd(u16 cmd)
+{
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "send_cmd(%#x)\n", cmd);
+
+ NFC_WRITEW(NFC_FLASH_CMD, cmd);
+ NFC_WRITEW(NFC_CONFIG2, NFC_CMD);
+
+ /* Wait for operation to complete */
+ wait_op_done(TROP_US_DELAY);
+}
+
+/*!
+ * This function sends an address (or partial address) to the
+ * NAND device. The address is used to select the source/destination for
+ * a NAND command.
+ *
+ * @addr address to be written to NFC.
+ */
+static void send_addr(u16 addr)
+{
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "send_addr(%#x)\n", addr);
+ NFC_WRITEW(NFC_FLASH_ADDR, (addr << NFC_FLASH_ADDR_SHIFT));
+
+ NFC_WRITEW(NFC_CONFIG2, NFC_ADDR);
+
+ /* Wait for operation to complete */
+ wait_op_done(TROP_US_DELAY);
+}
+
+/*!
+ * This function requests the NFC to initate the transfer
+ * of data currently in the NFC RAM buffer to the NAND device.
+ *
+ * @buf_id Specify Internal RAM Buffer number (0-3)
+ */
+static void send_prog_page(u8 buf_id)
+{
+ u32 val = NFC_READW(NFC_BUF_ADDR);
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "%s\n", __FUNCTION__);
+
+ /* Set RBA bits for BUFFER val */
+ val &= ~0x7;
+ val |= buf_id;
+ NFC_WRITEW(NFC_BUF_ADDR, val);
+
+ NFC_WRITEW(NFC_CONFIG2, NFC_INPUT);
+
+ /* Wait for operation to complete */
+ wait_op_done(TROP_US_DELAY);
+}
+
+/*!
+ * This function requests the NFC to initated the transfer
+ * of data from the NAND device into in the NFC ram buffer.
+ *
+ * @buf_id Specify Internal RAM Buffer number (0-3)
+ */
+static void send_read_page(u8 buf_id)
+{
+ u32 val = NFC_READW(NFC_BUF_ADDR);
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "%s\n", __FUNCTION__);
+
+ /* Set RBA bits for BUFFER val */
+ val &= ~0x7;
+ val |= buf_id;
+ NFC_WRITEW(NFC_BUF_ADDR, val);
+
+ NFC_WRITEW(NFC_CONFIG2, NFC_OUTPUT);
+
+ /* Wait for operation to complete */
+ wait_op_done(TROP_US_DELAY);
+}
+
+/*!
+ * This function requests the NFC to perform a read of the
+ * NAND device ID.
+ */
+static void send_read_id(void)
+{
+ u32 val = NFC_READW(NFC_BUF_ADDR);
+
+ /* NFC buffer 0 is used for device ID output */
+ /* Set RBA bits for BUFFER0 */
+ val &= ~0x7;
+ NFC_WRITEW(NFC_BUF_ADDR, val);
+
+ /* Read ID into main buffer */
+ NFC_WRITEW(NFC_CONFIG2, NFC_ID);
+
+ /* Wait for operation to complete */
+ wait_op_done(TROP_US_DELAY);
+
+}
+
+/*!
+ * This function requests the NFC to perform a read of the
+ * NAND device status and returns the current status.
+ *
+ * @return device status
+ */
+static u16 get_dev_status(void)
+{
+ u32 save;
+ u16 ret;
+ u32 val;
+ /* Issue status request to NAND device */
+
+ /* save the main area1 first word, later do recovery */
+ save = NFC_READL(MAIN_AREA(1));
+ NFC_WRITEL(MAIN_AREA(1), 0);
+
+ /*
+ * NFC buffer 1 is used for device status to prevent
+ * corruption of read/write buffer on status requests.
+ */
+
+ /* Select BUFFER1 */
+ val = NFC_READW(NFC_BUF_ADDR);
+ val &= ~0x7;
+ val |= 1;
+ NFC_WRITEW(NFC_BUF_ADDR, val);
+
+ /* Read status into main buffer */
+ NFC_WRITEW(NFC_CONFIG2, NFC_STATUS);
+
+ /* Wait for operation to complete */
+ wait_op_done(TROP_US_DELAY);
+
+ /* Status is placed in first word of main buffer */
+ /* get status, then recovery area 1 data */
+ if (NFC_READW(NFC_CONFIG1) & NFC_BIG)
+ ret = NFC_READB(MAIN_AREA(1));
+ else
+ ret = NFC_READB(MAIN_AREA(1) + 3);
+
+ NFC_WRITEL(MAIN_AREA(1), save);
+ return ret;
+}
+
+/*!
+ * This functions is used by upper layer to checks if device is ready
+ *
+ * @mtd MTD structure for the NAND Flash
+ *
+ * @return 0 if device is busy else 1
+ */
+static int fsl_nfc_dev_ready(struct mtd_info *mtd)
+{
+ return 1;
+}
+
+static void fsl_nfc_enable_hwecc(struct mtd_info *mtd, int mode)
+{
+ NFC_WRITEW(NFC_CONFIG1, (NFC_READW(NFC_CONFIG1) | NFC_ECC_EN));
+ return;
+}
+
+/*
+ * Function to record the ECC corrected/uncorrected errors resulted
+ * after a page read. This NFC detects and corrects upto to 4 symbols
+ * of 9-bits each.
+ */
+static int fsl_nfc_check_ecc_status(struct mtd_info *mtd)
+{
+ u32 ecc_stat, err;
+ int no_subpages = 1;
+ int ret = 0;
+ u8 ecc_bit_mask, err_limit;
+ int is_4bit_ecc = NFC_READW(NFC_CONFIG1) & NFC_ECC_MODE_4;
+
+ ecc_bit_mask = (is_4bit_ecc ? 0x7 : 0xf);
+ err_limit = (is_4bit_ecc ? 0x4 : 0x8);
+
+ no_subpages = mtd->writesize >> 9;
+
+ ecc_stat = NFC_READW(NFC_ECC_STATUS1);
+ do {
+ err = ecc_stat & ecc_bit_mask;
+ if (err > err_limit)
+ return -1;
+ else
+ ret += err;
+ ecc_stat >>= 4;
+ } while (--no_subpages);
+
+ return ret;
+}
+
+/*!
+ * This function reads byte from the NAND Flash
+ *
+ * @mtd MTD structure for the NAND Flash
+ *
+ * @return data read from the NAND Flash
+ */
+static u_char fsl_nfc_read_byte(struct mtd_info *mtd)
+{
+ void *area_buf;
+ u_char rv;
+
+ /* Check for status request */
+ if (priv->status_req) {
+ rv = get_dev_status() & 0xff;
+ return rv;
+ }
+
+ if (priv->spare_only)
+ area_buf = SPARE_AREA(0);
+ else
+ area_buf = MAIN_AREA(0);
+
+ rv = NFC_READB(area_buf + priv->col_addr);
+ priv->col_addr++;
+ return rv;
+}
+
+/*!
+ * This function reads word from the NAND Flash
+ *
+ * @mtd MTD structure for the NAND Flash
+ *
+ * @return data read from the NAND Flash
+ */
+static u16 fsl_nfc_read_word(struct mtd_info *mtd)
+{
+ u16 rv;
+ void *area_buf;
+
+ /* If we are accessing the spare region */
+ if (priv->spare_only)
+ area_buf = SPARE_AREA(0);
+ else
+ area_buf = MAIN_AREA(0);
+
+ /* Update saved column address */
+ rv = NFC_READW(area_buf + priv->col_addr);
+ priv->col_addr += 2;
+
+ return rv;
+}
+
+/*!
+ * This function reads byte from the NAND Flash
+ *
+ * @mtd MTD structure for the NAND Flash
+ *
+ * @return data read from the NAND Flash
+ */
+static u_char fsl_nfc_read_byte16(struct mtd_info *mtd)
+{
+ /* Check for status request */
+ if (priv->status_req)
+ return (get_dev_status() & 0xff);
+
+ return fsl_nfc_read_word(mtd) & 0xff;
+}
+
+/*!
+ * This function writes data of length \b len from buffer \b buf to the NAND
+ * internal RAM buffer's MAIN area 0.
+ *
+ * @mtd MTD structure for the NAND Flash
+ * @buf data to be written to NAND Flash
+ * @len number of bytes to be written
+ */
+static void fsl_nfc_write_buf(struct mtd_info *mtd,
+ const u_char *buf, int len)
+{
+ if (priv->col_addr >= mtd->writesize || priv->spare_only) {
+ copy_to_spare(mtd, (char *)buf, len);
+ return;
+ } else {
+ priv->col_addr += len;
+ memcpy_toio(MAIN_AREA(0), (void *)buf, len);
+ }
+}
+
+/*!
+ * This function id is used to read the data buffer from the NAND Flash. To
+ * read the data from NAND Flash first the data output cycle is initiated by
+ * the NFC, which copies the data to RAMbuffer. This data of length \b len is
+ * then copied to buffer \b buf.
+ *
+ * @mtd MTD structure for the NAND Flash
+ * @buf data to be read from NAND Flash
+ * @len number of bytes to be read
+ */
+static void fsl_nfc_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+{
+
+ if (priv->col_addr >= mtd->writesize || priv->spare_only) {
+ copy_from_spare(mtd, buf, len);
+ return;
+ } else {
+ priv->col_addr += len;
+ memcpy_fromio((void *)buf, MAIN_AREA(0), len);
+ }
+}
+
+/*!
+ * This function is used by the upper layer to verify the data in NAND Flash
+ * with the data in the \b buf.
+ *
+ * @mtd MTD structure for the NAND Flash
+ * @buf data to be verified
+ * @len length of the data to be verified
+ *
+ * @return -1 if error else 0
+ *
+ */
+static int fsl_nfc_verify_buf(struct mtd_info *mtd, const u_char *buf,
+ int len)
+{
+ void *main_buf = MAIN_AREA(0);
+ /* check for 32-bit alignment? */
+ u32 *p = (u32 *) buf;
+ u32 v = 0;
+
+ for (; len > 0; len -= 4, main_buf += 4)
+ v = NFC_READL(main_buf);
+ if (v != *p++)
+ return -1;
+ return 0;
+}
+
+static int fsl_nfc_get_hw_config(struct nand_chip *this)
+{
+ immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
+ u32 rcwh;
+ int rcwh_romloc;
+ int rcwh_ps;
+ int width;
+ int writesize = 0;
+ int sparesize = 0;
+
+ /*
+ * Only support 2K for now.
+ * Remove this when others are tested and debugged.
+ */
+#if 0
+ if (CONFIG_FSL_NFC_WRITE_SIZE != 2048) {
+ printf("FSL NFC: "
+ "%d byte write size flash support is untested\n",
+ CONFIG_FSL_NFC_WRITE_SIZE);
+ return -1;
+ }
+#endif
+ rcwh = NFC_READL((void *)&(im->reset.rcwh));
+ width = ((rcwh >> 6) & 0x1) ? 2 : 1;
+
+ if (width != CONFIG_FSL_NFC_WIDTH) {
+ printf("FSL NFC: Device width mismatch, compiled for %d, "
+ "reset configuration word width is %d\n",
+ CONFIG_FSL_NFC_WIDTH, width);
+ return -1;
+ }
+
+ if (width == 2) {
+ this->options |= NAND_BUSWIDTH_16;
+ this->read_byte = fsl_nfc_read_byte16;
+ }
+
+ /*
+ * Decode the rcwh_ps and rcwh_romloc
+ * bits from reset config word
+ * to determine write size
+ */
+ rcwh_ps = (rcwh >> 7) & 0x1;
+ rcwh_romloc = (rcwh >> 21) & 0x3;
+ switch (rcwh_ps << 2 | rcwh_romloc) {
+ case 0x0:
+ case 0x1:
+ writesize = 512;
+ sparesize = 16;
+ break;
+ case 0x2:
+ case 0x3:
+ writesize = 4096;
+ sparesize = 128;
+ break;
+ case 0x4:
+ case 0x5:
+ writesize = 2048;
+ sparesize = 64;
+ break;
+ case 0x6:
+ case 0x7:
+ writesize = 4096;
+ sparesize = 218;
+ break;
+ }
+ if (CONFIG_FSL_NFC_WRITE_SIZE != writesize) {
+ printf("FSL NFC: "
+ "Device write size mismatch, "
+ "compiled for %d, "
+ "size from reset configuration word is %d\n",
+ CONFIG_FSL_NFC_WRITE_SIZE, writesize);
+ return -1;
+ }
+ if (CONFIG_FSL_NFC_SPARE_SIZE != sparesize) {
+ printf("FSL NFC: "
+ "Device spare size mismatch, "
+ "compiled for %d, "
+ "size from reset configuration word is %d\n",
+ CONFIG_FSL_NFC_SPARE_SIZE, sparesize);
+ return -1;
+ }
+
+ priv->sparesize = sparesize;
+ priv->writesize = writesize;
+ priv->width = width;
+ return 0;
+}
+
+
+#ifndef CONFIG_FSL_NFC_BOARD_CS_FUNC
+static void fsl_nfc_select_chip(u8 cs)
+{
+ u32 val = NFC_READW(NFC_BUF_ADDR);
+
+ val &= ~0x60;
+ val |= cs << 5;
+ NFC_WRITEW(NFC_BUF_ADDR, val);
+}
+#define CONFIG_FSL_NFC_BOARD_CS_FUNC fsl_nfc_select_chip
+#endif
+
+
+/*!
+ * This function is used by upper layer for select and deselect of the NAND
+ * chip
+ *
+ * @mtd MTD structure for the NAND Flash
+ * @chip val indicating select or deselect
+ */
+static void fsl_nfc_select_chip(struct mtd_info *mtd, int chip)
+{
+ /*
+ * This is different than the linux version.
+ * Switching between chips is done via
+ * board_nand_select_device.
+ *
+ * Only valid chip numbers here are
+ * 0 select
+ * -1 deselect
+ */
+ if (chip < -1 || chip > 0) {
+ printf("FSL NFC: "
+ "ERROR: Illegal chip select (chip = %d)\n", chip);
+ }
+
+ if (chip < 0) {
+ NFC_WRITEW(NFC_CONFIG1, (NFC_READW(NFC_CONFIG1) & ~NFC_CE));
+ return;
+ }
+
+ NFC_WRITEW(NFC_CONFIG1, (NFC_READW(NFC_CONFIG1) | NFC_CE));
+
+ /*
+ * Turn on appropriate chip.
+ */
+ CONFIG_FSL_NFC_BOARD_CS_FUNC(priv->chipsel);
+}
+
+/*
+ * Function to perform the address cycles.
+ */
+static void fsl_nfc_do_addr_cycle(struct mtd_info *mtd, int column,
+ int page_addr)
+{
+ struct nand_chip *this = mtd->priv;
+ u32 page_mask = this->pagemask;
+
+ if (column != -1) {
+ send_addr(column & 0xff);
+ /* large page nand needs an extra column addr cycle */
+ if (IS_2K_PAGE_NAND)
+ send_addr((column >> 8) & 0xf);
+ else if (IS_4K_PAGE_NAND)
+ send_addr((column >> 8) & 0x1f);
+ }
+ if (page_addr != -1) {
+ do {
+ send_addr((page_addr & 0xff));
+ page_mask >>= 8;
+ page_addr >>= 8;
+ } while (page_mask != 0);
+ }
+}
+
+/*
+ * Function to read a page from nand device.
+ */
+static void read_full_page(struct mtd_info *mtd, int page_addr)
+{
+ send_cmd(NAND_CMD_READ0);
+
+ fsl_nfc_do_addr_cycle(mtd, 0, page_addr);
+
+ if (IS_LARGE_PAGE_NAND) {
+ send_cmd(NAND_CMD_READSTART);
+ send_read_page(0);
+ } else {
+ send_read_page(0);
+ }
+}
+
+/*!
+ * This function is used by the upper layer to write command to NAND Flash for
+ * different operations to be carried out on NAND Flash
+ *
+ * @mtd MTD structure for the NAND Flash
+ * @command command for NAND Flash
+ * @column column offset for the page read
+ * @page_addr page to be read from NAND Flash
+ */
+static void fsl_nfc_command(struct mtd_info *mtd, unsigned command,
+ int column, int page_addr)
+{
+ MTDDEBUG(MTD_DEBUG_LEVEL3,
+ "fsl_nfc_command (cmd = %#x, col = %#x, page = %#x)\n",
+ command, column, page_addr);
+ /*
+ * Reset command state information
+ */
+ priv->status_req = 0;
+
+ /* Reset column address to 0 */
+ priv->col_addr = 0;
+
+ /*
+ * Command pre-processing step
+ */
+ switch (command) {
+ case NAND_CMD_STATUS:
+ priv->status_req = 1;
+ break;
+
+ case NAND_CMD_READ0:
+ priv->spare_only = 0;
+ break;
+
+ case NAND_CMD_READOOB:
+ priv->col_addr = column;
+ priv->spare_only = 1;
+ command = NAND_CMD_READ0; /* only READ0 is valid */
+ break;
+
+ case NAND_CMD_SEQIN:
+ if (column >= mtd->writesize)
+ priv->spare_only = 1;
+ else
+ priv->spare_only = 0;
+ break;
+
+ case NAND_CMD_PAGEPROG:
+ if (!priv->spare_only)
+ send_prog_page(0);
+ else
+ return;
+ break;
+
+ case NAND_CMD_ERASE1:
+ break;
+ case NAND_CMD_ERASE2:
+ break;
+ }
+
+ /*
+ * Write out the command to the device.
+ */
+ send_cmd(command);
+
+ fsl_nfc_do_addr_cycle(mtd, column, page_addr);
+
+ /*
+ * Command post-processing step
+ */
+ switch (command) {
+
+ case NAND_CMD_READOOB:
+ case NAND_CMD_READ0:
+ if (IS_LARGE_PAGE_NAND) {
+ /* send read confirm command */
+ send_cmd(NAND_CMD_READSTART);
+ /* read for each AREA */
+ send_read_page(0);
+ } else
+ send_read_page(0);
+ break;
+
+ case NAND_CMD_READID:
+ send_read_id();
+ break;
+ }
+}
+
+static int fsl_nfc_wait(struct mtd_info *mtd, struct nand_chip *chip)
+{
+ return get_dev_status();
+}
+
+static int fsl_nfc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
+ int page, int sndcmd)
+{
+ if (sndcmd) {
+ read_full_page(mtd, page);
+ sndcmd = 0;
+ }
+
+ copy_from_spare(mtd, chip->oob_poi, mtd->oobsize);
+ return sndcmd;
+}
+
+static int fsl_nfc_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
+ int page)
+{
+ int status = 0;
+ int read_oob_col = 0;
+
+ send_cmd(NAND_CMD_READ0);
+ send_cmd(NAND_CMD_SEQIN);
+ fsl_nfc_do_addr_cycle(mtd, read_oob_col, page);
+
+ /* copy the oob data */
+ copy_to_spare(mtd, chip->oob_poi, mtd->oobsize);
+
+ send_prog_page(0);
+
+ send_cmd(NAND_CMD_PAGEPROG);
+
+ status = fsl_nfc_wait(mtd, chip);
+ if (status & NAND_STATUS_FAIL)
+ return -1;
+ return 0;
+}
+
+static int fsl_nfc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
+ uint8_t *buf)
+{
+ int stat;
+
+ stat = fsl_nfc_check_ecc_status(mtd);
+ if (stat == -1) {
+ mtd->ecc_stats.failed++;
+ printf("FSL NFC: UnCorrectable RS-ECC Error\n");
+ } else {
+ mtd->ecc_stats.corrected += stat;
+ if (stat)
+ printf("%d Symbol Correctable RS-ECC Error\n", stat);
+ }
+
+ memcpy_fromio((void *)buf, MAIN_AREA(0), mtd->writesize);
+ copy_from_spare(mtd, chip->oob_poi, mtd->oobsize);
+ return 0;
+}
+
+static void fsl_nfc_write_page(struct mtd_info *mtd,
+ struct nand_chip *chip, const uint8_t *buf)
+{
+ memcpy_toio(MAIN_AREA(0), buf, mtd->writesize);
+ copy_to_spare(mtd, chip->oob_poi, mtd->oobsize);
+}
+
+
+/*
+ * Generic flash bbt decriptors
+ */
+static uint8_t bbt_pattern[] = { 'B', 'b', 't', '0' };
+static uint8_t mirror_pattern[] = { '1', 't', 'b', 'B' };
+
+/*
+ * These are identical to the generic versions except
+ * for the offsets.
+ */
+static struct nand_bbt_descr bbt_main_descr = {
+ .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
+ | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
+ .offs = 0,
+ .len = 4,
+ .veroffs = 4,
+ .maxblocks = 4,
+ .pattern = bbt_pattern
+};
+
+static struct nand_bbt_descr bbt_mirror_descr = {
+ .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
+ | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
+ .offs = 0,
+ .len = 4,
+ .veroffs = 4,
+ .maxblocks = 4,
+ .pattern = mirror_pattern
+};
+
+void board_nand_select_device(struct nand_chip *nand, int chip)
+{
+ if (chip >= CONFIG_FSL_NFC_CHIPS) {
+ printf("FSL NFC: "
+ "ERROR: Illegal chip select (chip = %d)\n", chip);
+ return;
+ }
+ priv->chipsel = chip;
+}
+
+
+int board_nand_init(struct nand_chip *nand)
+{
+ struct mtd_info *mtd;
+
+ priv = malloc(sizeof(*priv));
+ if (!priv) {
+ printf("FSL NFC: failed to allocate priv structure\n");
+ return -1;
+ }
+ memset(priv, 0, sizeof(*priv));
+
+ if (fsl_nfc_get_hw_config(nand) < 0)
+ return -1;
+
+ mtd = &priv->mtd;
+ mtd->priv = nand;
+
+ /* 5 us command delay time */
+ nand->chip_delay = 5;
+
+ nand->dev_ready = fsl_nfc_dev_ready;
+ nand->cmdfunc = fsl_nfc_command;
+ nand->waitfunc = fsl_nfc_wait;
+ nand->select_chip = fsl_nfc_select_chip;
+ nand->options = NAND_USE_FLASH_BBT;
+ if (priv->width == 2) {
+ nand->options |= NAND_BUSWIDTH_16;
+ nand->read_byte = fsl_nfc_read_byte16;
+ }
+ nand->read_byte = fsl_nfc_read_byte;
+ nand->read_word = fsl_nfc_read_word;
+ nand->write_buf = fsl_nfc_write_buf;
+ nand->read_buf = fsl_nfc_read_buf;
+ nand->verify_buf = fsl_nfc_verify_buf;
+
+ nand->bbt_td = &bbt_main_descr;
+ nand->bbt_md = &bbt_mirror_descr;
+
+ NFC_WRITEW(NFC_CONFIG1, (NFC_READW(NFC_CONFIG1) | NFC_RST));
+
+ /* Disable interrupt */
+ NFC_WRITEW(NFC_CONFIG1, (NFC_READW(NFC_CONFIG1) | NFC_INT_MSK));
+
+ if (hardware_ecc) {
+ nand->ecc.read_page = fsl_nfc_read_page;
+ nand->ecc.write_page = fsl_nfc_write_page;
+ nand->ecc.read_oob = fsl_nfc_read_oob;
+ nand->ecc.write_oob = fsl_nfc_write_oob;
+ if (IS_2K_PAGE_NAND)
+ nand->ecc.layout = &nand_hw_eccoob_2k;
+ else if (IS_4K_PAGE_NAND)
+ if (priv->sparesize == 128)
+ nand->ecc.layout = &nand_hw_eccoob_4k;
+ else
+ nand->ecc.layout = &nand_hw_eccoob_4k_218_spare;
+ else
+ nand->ecc.layout = &nand_hw_eccoob_512;
+ /* propagate ecc.layout to mtd_info */
+ mtd->ecclayout = nand->ecc.layout;
+ nand->ecc.calculate = NULL;
+ nand->ecc.hwctl = fsl_nfc_enable_hwecc;
+ nand->ecc.correct = NULL;
+ nand->ecc.mode = NAND_ECC_HW;
+ /* RS-ECC is applied for both MAIN+SPARE not MAIN alone */
+ nand->ecc.size = 512;
+ nand->ecc.bytes = 9;
+ NFC_WRITEW(NFC_CONFIG1, (NFC_READW(NFC_CONFIG1) | NFC_ECC_EN));
+ } else {
+ nand->ecc.mode = NAND_ECC_SOFT;
+ NFC_WRITEW(NFC_CONFIG1, (NFC_READW(NFC_CONFIG1) & ~NFC_ECC_EN));
+ }
+
+ NFC_WRITEW(NFC_CONFIG1, NFC_READW(NFC_CONFIG1) & ~NFC_SP_EN);
+
+
+ /* Reset NAND */
+ nand->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
+
+ /* preset operation */
+ /* Unlock the internal RAM Buffer */
+ NFC_WRITEW(NFC_CONFIG, NFC_BLS_UNLOCKED);
+
+ /* Blocks to be unlocked */
+ NFC_WRITEW(NFC_UNLOCKSTART_BLKADDR0, 0x0);
+ NFC_WRITEW(NFC_UNLOCKEND_BLKADDR0, 0xffff);
+
+ /* Unlock Block Command for given address range */
+ NFC_WRITEW(NFC_WRPROT, NFC_WPC_UNLOCK);
+
+ /* Set sparesize */
+ NFC_WRITEW(NFC_SPAS,
+ (NFC_READW(NFC_SPAS) & 0xff00) | (priv->sparesize/2));
+
+ /*
+ * Only use 8bit ecc (aka not 4 bit) if large spare size
+ */
+ if (priv->sparesize == 218)
+ NFC_WRITEW(NFC_CONFIG1,
+ (NFC_READW(NFC_CONFIG1) & ~NFC_ECC_MODE_4));
+ else
+ NFC_WRITEW(NFC_CONFIG1,
+ (NFC_READW(NFC_CONFIG1) | NFC_ECC_MODE_4));
+
+ return 0;
+}
diff --git a/drivers/mtd/nand/fsl_nfc_nand_5125.c b/drivers/mtd/nand/fsl_nfc_nand_5125.c
new file mode 100644
index 0000000000..d0dc9f209c
--- /dev/null
+++ b/drivers/mtd/nand/fsl_nfc_nand_5125.c
@@ -0,0 +1,919 @@
+/*
+ * Copyright (C) 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * Based on drivers/mtd/nand/mpc5121_nand.c
+ * which was based on drivers/mtd/nand/mxc_nd.c
+ * ported by Cloudy chen <chen_yunsong@mtcera> LimePC Multimedia Technologies Co., Limited
+ *from mpc5121 to mpc5125
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#include <command.h>
+#include <common.h>
+#include <malloc.h>
+
+#include <mpc5125_nfc.h>
+#include <asm/io.h>
+#include <nand.h>
+#include "mpc5125_nfc_struct.h"
+#define MIN(x, y) ((x < y) ? x : y)
+
+#define NAND_DEBUG_INFO() printf("%s line:%d\n",__func__,__LINE__)
+#ifndef CONFIG_PPC
+#define CONFIG_PPC
+#endif
+
+static struct fsl_nfc_private {
+ struct mtd_info mtd;
+ char spare_only;
+ char status_req;
+ u16 col_addr;
+ int writesize;
+ int sparesize;
+ int width;
+ int chipsel;
+} *priv;
+
+static int get_status;
+static int get_id;
+
+#define IS_2K_PAGE_NAND (priv->writesize == 2048)
+#define IS_4K_PAGE_NAND (priv->writesize == 4096)
+#define IS_LARGE_PAGE_NAND (priv->writesize > 512)
+
+/*
+ * Define delays in microsec for NAND device operations
+ */
+#define TROP_US_DELAY 2000
+
+#if defined(CONFIG_PPC)
+#define NFC_WRITEL(r, v) out_be32(r, v)
+#define NFC_WRITEW(r, v) out_be16(r, v)
+#define NFC_WRITEB(r, v) out_8(r, v)
+#define NFC_READL(r) in_be32(r)
+#define NFC_READW(r) in_be16(r)
+#define NFC_READB(r) in_8(r)
+#elif defined(CONFIG_ARM)
+#define NFC_WRITEL(r, v) writel(v, r)
+#define NFC_WRITEW(r, v) writew(v, r)
+#define NFC_WRITEB(r, v) writeb(r, v)
+#define NFC_READL(r) readl(r)
+#define NFC_READW(r) readw(r)
+#define NFC_READB(r) readb(r)
+#endif
+
+
+#ifdef CONFIG_MTD_NAND_FSL_NFC_SWECC
+static int hardware_ecc;
+#else
+static int hardware_ecc = 0;
+#endif
+
+
+static void mpc5125_nfc_addr_cycle(struct mtd_info *mtd, int column, int page);
+u8 mpc5125_nfc_get_id(struct mtd_info *mtd,int col);
+static void mpc5125_cfg_iopad_init(void)
+{
+ //printf("enter mpc5125_cfg_iopad_init\n");
+ /* FLASH IO PAD Setting */
+ out_8(ioctl + BALL_NFC_IO0, PAD_NFC_IO | DS_MSR_3);
+ out_8(ioctl + BALL_NFC_IO1, PAD_NFC_IO | DS_MSR_3);
+ out_8(ioctl + BALL_NFC_IO2, PAD_NFC_IO | DS_MSR_3);
+ out_8(ioctl + BALL_NFC_IO3, PAD_NFC_IO | DS_MSR_3);
+ out_8(ioctl + BALL_NFC_IO4, PAD_NFC_IO | DS_MSR_3);
+ out_8(ioctl + BALL_NFC_IO5, PAD_NFC_IO | DS_MSR_3);
+ out_8(ioctl + BALL_NFC_IO6, PAD_NFC_IO | DS_MSR_3);
+ out_8(ioctl + BALL_NFC_IO7, PAD_NFC_IO | DS_MSR_3);
+
+ /* FLASH CONTROL PAD Setting */
+ out_8(ioctl + BALL_NFC_ALE, PAD_NFC_ALE | DS_MSR_3);
+ out_8(ioctl + BALL_NFC_CLE, PAD_NFC_CLE | DS_MSR_3);
+ out_8(ioctl + BALL_NFC_WE, PAD_NFC_WE | DS_MSR_3);
+ out_8(ioctl + BALL_NFC_RE, PAD_NFC_RE | DS_MSR_3);
+
+ /* NFC_CE0 */
+ out_8(ioctl + BALL_NFC_CE0, PAD_NFC_CE0 | DS_MSR_3);
+
+ out_8(ioctl + BALL_NFC_RB0, PAD_NFC_RB0| ST_Enabled | DS_MSR_3 | PUD_PUE);
+}
+
+/*
+ * OOB placement block for use with hardware ecc generation
+ */
+static struct nand_ecclayout nand_hw_eccoob_512 = {
+ .eccbytes = 9,
+ .eccpos = {
+ 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ },
+ .oobfree = {
+ {0, 5} /* byte 5 is factory bad block marker */
+ },
+};
+
+static struct nand_ecclayout nand_hw_eccoob_2k = {
+ .eccbytes = 36,
+ .eccpos = {
+ /* 9 bytes of ecc for each 512 bytes of data */
+ 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ },
+ .oobfree = {
+ {2, 5}, /* bytes 0 and 1 are factory bad block markers */
+ {16, 7},
+ {32, 7},
+ {48, 7},
+ },
+};
+#if 1
+/*for ecc_MODE=0x6 45bytes*2*/
+static struct nand_ecclayout nand_hw_eccoob_4k = {
+ .eccbytes = 90, /* actually 72 but only room for 64 */
+ .eccpos = {
+ /* 9 bytes of ecc for each 512 bytes of data */
+ 19,20,21,22,23,24,25,26,27,28,29,30,
+ 31,32,33,34,35,36,37,38,39,40,
+ 41, 42, 43, 44, 45, 46, 47,48,49,50,
+ 51,52,53,54,55, 56, 57, 58, 59, 60,
+ 61, 62, 63,
+ 83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,
+ 98,99,100,
+ 101,102,103,104,105,106,107,108,109,110,
+ 111,112,113,114,115,116,117,118,119,120,
+ 121,122,123,124,125,126,127/* 120, 121, 122, 123, 124, 125, 126, 127, */
+ },
+ .oobavail = 30,
+ .oobfree = { {4, 15}, {68, 15}}
+};
+#else
+static struct nand_ecclayout nand_hw_eccoob_4k = {
+ .eccbytes = 64, /* actually 72 but only room for 64 */
+ .eccpos = {
+ /* 9 bytes of ecc for each 512 bytes of data */
+ 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 103, 104, 105, 106, 107, 108, 109, 110, 111,
+ 119, /* 120, 121, 122, 123, 124, 125, 126, 127, */
+ },
+ .oobfree = {
+ {2, 5}, /* bytes 0 and 1 are factory bad block markers */
+ {16, 7},
+ {32, 7},
+ {48, 7},
+ {64, 7},
+ {80, 7},
+ {96, 7},
+ {112, 7},
+ },
+};
+#endif
+static struct nand_ecclayout nand_hw_eccoob_4k_218_spare = {
+ .eccbytes = 64, /* actually 144 but only room for 64 */
+ .eccpos = {
+ /* 18 bytes of ecc for each 512 bytes of data */
+ 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 33, 34, 35, 36, 37, 38, 39, 40, 41,
+ 42, 43, 44, 45, 46, 47, 48, 49, 50,
+ 59, 60, 61, 62, 63, 64, 65, 66, 67,
+ 68, 69, 70, 71, 72, 73, 74, 75, 76,
+ 85, 86, 87, 88, 89, 90, 91, 92, 93,
+ 94, /* 95, 96, 97, 98, 99, 100, 101, 102,
+ 111, 112, 113, 114, 115, 116, 117, 118, 119,
+ 120, 121, 122, 123, 124, 125, 126, 127, 128,
+ 137, 138, 139, 140, 141, 142, 143, 144, 145,
+ 146, 147, 148, 149, 150, 151, 152, 153, 154,
+ 163, 164, 165, 166, 167, 168, 169, 170, 171,
+ 172, 173, 174, 175, 176, 177, 178, 179, 180,
+ 189, 190, 191, 192, 193, 194, 195, 196, 197,
+ 198, 199, 200, 201, 202, 203, 204, 205, 206, */
+ },
+ .oobfree = {
+ {2, 5}, /* bytes 0 and 1 are factory bad block markers */
+ {25, 8},
+ {51, 8},
+ {77, 8},
+ {103, 8},
+ {129, 8},
+ {155, 8},
+ {181, 8},
+ },
+};
+
+ struct mpc5125_nfc_save_struct g_nfc_save;
+/*
+ * Functions to transfer data to/from spare erea.
+ */
+static void copy_from_spare(struct mtd_info *mtd, void *pbuf, int len)
+{
+
+ u16 ooblen = mtd->oobsize;
+ u8 i, count;
+ unsigned int sbsize, blksize;
+ /* Calculate number of valid bytes in each spare buffer */
+ count = mtd->writesize >> 11;
+ count=(count>0)?count:1;
+ sbsize = (ooblen / count >> 1) << 1;
+ /*printk("%s line:%d %s len:%d\n",__FUNCTION__,__LINE__,wr?"write":"read",size);*/
+ for(i=0;(i<count)&&len;i++)
+ {
+ blksize = min(sbsize, len);
+ memcpy_fromio(pbuf,
+ CONFIG_SYS_NAND_BASE + NFC_SPARE_AREA(i), blksize);
+ /*mpc5125_spare_debug(buffer,blksize);*/
+ pbuf += blksize;
+ len -= blksize;
+ }
+}
+
+static void copy_to_spare(struct mtd_info *mtd, void *pbuf, int len)
+{
+
+ u16 ooblen = mtd->oobsize;
+ u8 i, count;
+ unsigned int sbsize, blksize;
+ /* Calculate number of valid bytes in each spare buffer */
+ count = mtd->writesize >> 11;
+ count=(count>0)?count:1;
+ sbsize = (ooblen / count >> 1) << 1;
+ /*printk("%s line:%d %s len:%d\n",__FUNCTION__,__LINE__,wr?"write":"read",size);*/
+ for(i=0;(i<count)&&len;i++)
+ {
+ blksize = min(sbsize, len);
+ memcpy_toio(CONFIG_SYS_NAND_BASE + NFC_SPARE_AREA(i) ,
+ pbuf, blksize);
+ /*mpc5125_spare_debug(buffer,blksize);*/
+ pbuf += blksize;
+ len -= blksize;
+ }
+
+}
+static u32 nfc_read(uint reg)
+{
+ return in_be32(CONFIG_SYS_NAND_BASE + reg);
+}
+
+/* Write NFC register */
+static void nfc_write(uint reg, u32 val)
+{
+ out_be32(CONFIG_SYS_NAND_BASE + reg, val);
+}
+
+/* Set bits in NFC register */
+static inline void nfc_set(uint reg, u32 bits)
+{
+ nfc_write(reg, nfc_read(reg) | bits);
+}
+
+/* Clear bits in NFC register */
+static inline void nfc_clear( uint reg, u32 bits)
+{
+ nfc_write(reg, nfc_read( reg) & ~bits);
+}
+
+static void nfc_set_field(u32 reg, u32 mask, u32 shift, u32 val)
+{
+ out_be32(CONFIG_SYS_NAND_BASE + reg,
+ (in_be32(CONFIG_SYS_NAND_BASE + reg) & (~mask))
+ | val << shift);
+}
+static int nfc_get_field(u32 reg, u32 field_mask)
+{
+ return in_be32(CONFIG_SYS_NAND_BASE + reg) & field_mask;
+}
+
+/* clear cmd_done and cmd_idle falg for the coming command */
+static void mpc5125_nfc_clear(void)
+{
+
+ nfc_write(NFC_IRQ_STATUS, 1 << CMD_DONE_CLEAR_SHIFT);
+ nfc_write(NFC_IRQ_STATUS, 1 << IDLE_CLEAR_SHIFT);
+
+}
+/*!
+ * This function polls the NFC to wait for the basic operation to complete by
+ * checking the INT bit of config2 register.
+ *
+ * @max_retries number of retry attempts (separated by 1 us)
+ */
+static void wait_op_done(int max_retries)
+{
+ unsigned int tmp;
+ mpc5125_nfc_clear();
+ nfc_set_field(NFC_FLASH_CMD2, START_MASK,
+ START_SHIFT, 0x01);
+ while (1) {
+ max_retries--;
+ tmp=in_be32(CONFIG_SYS_NAND_BASE + NFC_IRQ_STATUS);
+ if(((tmp&(3<<29))==(3<<29))||((max_retries <= 0)))
+ {
+ out_be32(CONFIG_SYS_NAND_BASE+NFC_IRQ_STATUS,(3<<17));
+ break;
+ }
+ udelay(1);
+ }
+ if (max_retries <= 0)
+ printk( "%s: INT not set\n",__func__);
+ mpc5125_nfc_clear();
+}
+
+
+/* Invoke command cycle */
+static void
+mpc5125_nfc_send_cmd(u32 cmd_byte1,u32 cmd_byte2, u32 cmd_code)
+{
+ mpc5125_nfc_clear();
+ nfc_set_field( NFC_FLASH_CMD2, CMD_BYTE1_MASK,
+ CMD_BYTE1_SHIFT, cmd_byte1);
+
+ nfc_set_field( NFC_FLASH_CMD1, CMD_BYTE2_MASK,
+ CMD_BYTE2_SHIFT, cmd_byte2);
+
+ nfc_set_field( NFC_FLASH_CMD2, BUFNO_MASK,
+ BUFNO_SHIFT, 0);
+
+ nfc_set_field(NFC_FLASH_CMD2, CMD_CODE_MASK,
+ CMD_CODE_SHIFT, cmd_code);
+
+ if (cmd_code == RANDOM_OUT_CMD_CODE)
+ nfc_set_field( NFC_FLASH_CMD2, BUFNO_MASK,
+ BUFNO_SHIFT, 1);
+ /*
+ nfc_set_field(NFC_FLASH_CMD2, START_MASK,
+ START_SHIFT, 0x01);
+ */
+}
+static void mpc5125_nfc_send_one_byte(u32 cmd_byte1, u32 cmd_code)
+{
+ mpc5125_nfc_clear();
+
+ nfc_set_field( NFC_FLASH_CMD2, CMD_BYTE1_MASK,
+ CMD_BYTE1_SHIFT, cmd_byte1);
+
+ nfc_set_field( NFC_FLASH_CMD2, BUFNO_MASK,
+ BUFNO_SHIFT, 0);
+
+ nfc_set_field(NFC_FLASH_CMD2, CMD_CODE_MASK,
+ CMD_CODE_SHIFT, cmd_code);
+ /*
+ nfc_set_field(NFC_FLASH_CMD2, START_MASK,
+ START_SHIFT, 0x01);
+ */
+}
+
+static void copy_id_to_sram(void)
+{
+ unsigned int *area_buf;
+ area_buf = CONFIG_SYS_NAND_BASE + NFC_MAIN_AREA(0);
+ *area_buf++=nfc_read(NFC_FLASH_STATUS1);
+ *area_buf++=nfc_read(NFC_FLASH_STATUS2);
+}
+/* Write command to NAND flash */
+static void mpc5125_nfc_command(struct mtd_info *mtd, unsigned command,
+ int column, int page)
+{
+ priv->col_addr = (column >= 0) ? column : 0;
+ priv->spare_only = 0;
+ get_id = 0;
+ get_status = 0;
+ MTDDEBUG (MTD_DEBUG_LEVEL2, "command %08x page:%08x column:%08x\n",command,page,column);
+ switch (command) {
+ case NAND_CMD_PAGEPROG:
+ mpc5125_nfc_send_cmd(PROGRAM_PAGE_CMD_BYTE1,
+ PROGRAM_PAGE_CMD_BYTE2,
+ PROGRAM_PAGE_CMD_CODE);
+ wait_op_done(TROP_US_DELAY);
+ nfc_write(NFC_ROW_ADDR_INC, 0x0);
+ nfc_write(NFC_FLASH_CMD2, 0x8001c003);
+ wait_op_done(TROP_US_DELAY);
+ break;
+ /*
+ * NFC does not support sub-page reads and writes,
+ * so emulate them using full page transfers.
+ */
+ case NAND_CMD_READ0:
+ column = 0;
+ goto read0;
+ break;
+
+ case NAND_CMD_READ1:
+ priv->col_addr += 256;
+ command = NAND_CMD_READ0;
+ column = 0;
+ goto read0;
+ break;
+
+ case NAND_CMD_READOOB:
+ priv->spare_only = 1;
+ command = NAND_CMD_READ0;
+ column = 0;
+read0:
+ mpc5125_nfc_send_cmd( PAGE_READ_CMD_BYTE1,
+ PAGE_READ_CMD_BYTE2,
+ READ_PAGE_CMD_CODE);
+ break;
+
+ case NAND_CMD_SEQIN:
+ /*mpc5125_nfc_command(mtd,NAND_CMD_READ0, column, page);*/
+ column = 0;
+ goto read0;
+ break;
+
+ case NAND_CMD_ERASE1:
+ mpc5125_nfc_send_cmd( ERASE_CMD_BYTE1,
+ ERASE_CMD_BYTE2,
+ ERASE_CMD_CODE);
+ break;
+ case NAND_CMD_ERASE2:
+ return;
+ case NAND_CMD_READID:
+ get_id = 1;
+ mpc5125_nfc_send_one_byte(command, READ_ID_CMD_CODE);
+ wait_op_done(TROP_US_DELAY);
+ copy_id_to_sram();
+
+ return;
+ case NAND_CMD_STATUS:
+ get_status = 1;
+ mpc5125_nfc_send_one_byte(command, STATUS_READ_CMD_CODE);
+ break;
+ case NAND_CMD_RNDOUT:
+ mpc5125_nfc_send_cmd( RANDOM_OUT_CMD_BYTE1,
+ RANDOM_OUT_CMD_BYTE2,
+ RANDOM_OUT_CMD_CODE);
+ break;
+
+
+ case NAND_CMD_RESET:
+ mpc5125_nfc_send_one_byte(command, RESET_CMD_CODE);
+ break;
+
+ default:
+ return;
+ }
+ mpc5125_nfc_addr_cycle(mtd, priv->col_addr, page);
+ wait_op_done(TROP_US_DELAY);
+ MTDDEBUG (MTD_DEBUG_LEVEL2,"%s line:%d\n",__func__,__LINE__);
+}
+
+
+/*!
+ * This function requests the NFC to perform a read of the
+ * NAND device status and returns the current status.
+ *
+ * @return device status
+ */
+static u16 get_dev_status(void)
+{
+
+ u32 flash_status = 0;
+ u8 *pstatus;
+
+ flash_status = nfc_read(NFC_FLASH_STATUS2);
+ pstatus = (u8 *)&flash_status;
+ return *(pstatus + 3);
+}
+ u8 mpc5125_nfc_get_id(struct mtd_info *mtd,int col)
+{
+ u32 flash_id1 = 0;
+ u8 *pid;
+
+ flash_id1 = nfc_read(NFC_FLASH_STATUS1);
+ pid = (u8 *)&flash_id1;
+
+ return *(pid+col );
+}
+
+/*!
+ * This functions is used by upper layer to checks if device is ready
+ *
+ * @mtd MTD structure for the NAND Flash
+ *
+ * @return 0 if device is busy else 1
+ */
+static int fsl_nfc_dev_ready(struct mtd_info *mtd)
+{
+ return 1;
+}
+
+/*!
+ * This function reads byte from the NAND Flash
+ *
+ * @mtd MTD structure for the NAND Flash
+ *
+ * @return data read from the NAND Flash
+ */
+static u_char fsl_nfc_read_byte(struct mtd_info *mtd)
+{
+ void *area_buf;
+ u_char rv;
+
+ if (priv->status_req) {
+ rv = get_dev_status() & 0xff;
+ return rv;
+ }
+
+ if (priv->spare_only)
+ area_buf = CONFIG_SYS_NAND_BASE + NFC_SPARE_AREA(0);
+ else
+ area_buf = CONFIG_SYS_NAND_BASE + NFC_MAIN_AREA(0);
+
+ rv = NFC_READB(area_buf + priv->col_addr);
+ priv->col_addr++;
+ return rv;
+}
+
+/*!
+ * This function reads word from the NAND Flash
+ *
+ * @mtd MTD structure for the NAND Flash
+ *
+ * @return data read from the NAND Flash
+ */
+static u16 fsl_nfc_read_word(struct mtd_info *mtd)
+{
+ u16 rv;
+ void *area_buf;
+
+ /* If we are accessing the spare region */
+ if (priv->spare_only)
+ area_buf = CONFIG_SYS_NAND_BASE + NFC_SPARE_AREA(0);
+ else
+ area_buf = CONFIG_SYS_NAND_BASE + NFC_MAIN_AREA(0);
+
+ /* Update saved column address */
+ rv = NFC_READW(area_buf + priv->col_addr);
+ priv->col_addr += 2;
+
+ return rv;
+}
+
+
+/*!
+ * This function reads byte from the NAND Flash
+ *
+ * @mtd MTD structure for the NAND Flash
+ *
+ * @return data read from the NAND Flash
+ */
+static u_char fsl_nfc_read_byte16(struct mtd_info *mtd)
+{
+ /* Check for status request */
+ if (priv->status_req)
+ return (get_dev_status() & 0xff);
+
+ return fsl_nfc_read_word(mtd) & 0xff;
+}
+
+/*!
+ * This function writes data of length \b len from buffer \b buf to the NAND
+ * internal RAM buffer's MAIN area 0.
+ *
+ * @mtd MTD structure for the NAND Flash
+ * @buf data to be written to NAND Flash
+ * @len number of bytes to be written
+ */
+static void fsl_nfc_write_buf(struct mtd_info *mtd,
+ const u_char *buf, int len)
+{
+
+ if (priv->col_addr >= mtd->writesize || priv->spare_only) {
+ copy_to_spare(mtd, (char *)buf, len);
+ return;
+ } else {
+ unsigned int size,i;
+ unsigned int c=priv->col_addr;
+ priv->col_addr += len;
+ for(i=(c/PAGE_2K);i<4;i++)
+ {
+ size=min(len,PAGE_2K);
+ memcpy_toio(CONFIG_SYS_NAND_BASE + NFC_MAIN_AREA(i)+c, (void *)buf, size);
+ buf+=size;
+ len-=size;
+ if(!len)break;
+ }
+ }
+}
+
+/*!
+ * This function id is used to read the data buffer from the NAND Flash. To
+ * read the data from NAND Flash first the data output cycle is initiated by
+ * the NFC, which copies the data to RAMbuffer. This data of length \b len is
+ * then copied to buffer \b buf.
+ *
+ * @mtd MTD structure for the NAND Flash
+ * @buf data to be read from NAND Flash
+ * @len number of bytes to be read
+ */
+static void fsl_nfc_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+{
+
+ if (priv->col_addr >= mtd->writesize || priv->spare_only) {
+ copy_from_spare(mtd, buf, len);
+ return;
+ } else {
+ unsigned int size,i;
+ unsigned int c=priv->col_addr;
+ priv->col_addr += len;
+ for(i=(c/PAGE_2K);i<4;i++)
+ {
+ size=min(len,PAGE_2K);
+ memcpy_fromio(buf,CONFIG_SYS_NAND_BASE + NFC_MAIN_AREA(i) + c, size);
+ buf+=size;
+ len-=size;
+ if(!len)break;
+ }
+
+ }
+}
+
+/*!
+ * This function is used by the upper layer to verify the data in NAND Flash
+ * with the data in the \b buf.
+ *
+ * @mtd MTD structure for the NAND Flash
+ * @buf data to be verified
+ * @len length of the data to be verified
+ *
+ * @return -1 if error else 0
+ *
+ */
+static int fsl_nfc_verify_buf(struct mtd_info *mtd, const u_char *buf,
+ int len)
+{
+ void *main_buf = CONFIG_SYS_NAND_BASE + NFC_MAIN_AREA(0);
+ /* check for 32-bit alignment? */
+ u32 *p = (u32 *) buf;
+ u32 v = 0;
+
+ for (; len > 0; len -= 4, main_buf += 4)
+ v = NFC_READL(main_buf);
+ if (v != *p++)
+ return -1;
+ return 0;
+}
+
+static int fsl_nfc_get_hw_config(struct nand_chip *this)
+{
+ immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
+ u32 rcwh;
+ int rcwh_romloc;
+ int rcwh_ps;
+ int width;
+ int writesize = 0;
+ int sparesize = 0;
+
+ /*
+ * Only support 2K for now.
+ * Remove this when others are tested and debugged.
+ */
+
+ writesize=CONFIG_FSL_NFC_WRITE_SIZE;
+ sparesize = CONFIG_FSL_NFC_SPARE_SIZE;
+ width=1;
+
+ priv->sparesize = sparesize;
+ priv->writesize = writesize;
+ priv->width = width;
+ return 0;
+}
+
+
+#ifndef CONFIG_FSL_NFC_BOARD_CS_FUNC
+#error failed
+static void fsl_nfc_select_chip(u8 cs)
+{
+
+/*
+ u32 val = NFC_READW(NFC_BUF_ADDR);
+
+ val &= ~0x60;
+ val |= cs << 5;
+ NFC_WRITEW(NFC_BUF_ADDR, val);
+*/
+}
+#define CONFIG_FSL_NFC_BOARD_CS_FUNC fsl_nfc_select_chip
+#endif
+
+
+/*!
+ * This function is used by upper layer for select and deselect of the NAND
+ * chip
+ *
+ * @mtd MTD structure for the NAND Flash
+ * @chip val indicating select or deselect
+ */
+static void fsl_nfc_select_chip(struct mtd_info *mtd, int chip)
+{
+ /*
+ * This is different than the linux version.
+ * Switching between chips is done via
+ * board_nand_select_device.
+ *
+ * Only valid chip numbers here are
+ * 0 select
+ * -1 deselect
+ */
+
+
+ /*
+ * Turn on appropriate chip.
+ */
+
+ nfc_write(NFC_ROW_ADDR, ((1<<chip)<<28)|((1<<chip)<<24));
+
+
+}
+
+
+
+/* Do address cycle(s) */
+static void mpc5125_nfc_addr_cycle(struct mtd_info *mtd, int column, int page)
+{
+//printf("column=0x%x,page=0x%x\n",column,page);
+
+ if (column != -1) {
+ nfc_set_field( NFC_COL_ADDR,
+ COL_ADDR_MASK,
+ COL_ADDR_SHIFT, column);
+ }
+
+ if (page != -1) {
+ nfc_set_field( NFC_ROW_ADDR,
+ ROW_ADDR_MASK,
+ ROW_ADDR_SHIFT, page);
+ }
+ /* DMA Disable */
+ nfc_clear( NFC_FLASH_CONFIG, CONFIG_DMA_REQ_MASK);
+ /* PAGE_CNT = 1 */
+ nfc_set_field(NFC_FLASH_CONFIG, CONFIG_PAGE_CNT_MASK,
+ CONFIG_PAGE_CNT_SHIFT, 0x2);
+}
+
+
+
+
+static int fsl_nfc_wait(struct mtd_info *mtd, struct nand_chip *chip)
+{
+ return get_dev_status();
+}
+
+void board_nand_select_device(struct nand_chip *nand, int chip)
+{
+ if (chip >= CONFIG_FSL_NFC_CHIPS) {
+ printf("FSL NFC: "
+ "ERROR: Illegal chip select (chip = %d)\n", chip);
+ return;
+ }
+ priv->chipsel = chip;
+}
+/**
+ * nand_read_page_hwecc - [REPLACABLE] hardware ecc based page read function
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: buffer to store read data
+ *
+ * Not for syndrome calculating ecc controllers which need a special oob layout
+ */
+static int mpc5125_nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
+ uint8_t *buf)
+{
+
+ unsigned int stat;
+ u8 ecc_bytes=0,i;
+ u8 ecc_bytes_map[]={0,8,12,15,23,30,45,60};
+ stat=nfc_read(NFC_FLASH_CONFIG);
+ stat>>=17;
+ stat&=0x7;
+ ecc_bytes=ecc_bytes_map[stat];
+ stat=nfc_read( MPC5125_NFC_ECC_STATUS_ADD+4);
+ if(stat&0x80)
+ {
+ /*check the page is erased*/
+ if(stat&0x3f)
+ {
+ mtd->ecc_stats.failed++;
+ printk(KERN_WARNING "UnCorrectable RS-ECC Error\n");
+ }
+
+ }
+ else if(stat&0x3f)
+ {
+ /*printk(KERN_WARNING "Correctable ECC %d\n",stat&0x3f);*/
+ mtd->ecc_stats.corrected+=stat&0x3f;
+ }
+ fsl_nfc_read_buf (mtd, buf, mtd->writesize);
+ copy_from_spare(mtd,chip->oob_poi, mtd->oobsize);
+ return 0;
+}
+/**
+ * nand_write_page_hwecc - [REPLACABLE] hardware ecc based page write function
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: data buffer
+ */
+static void mpc5125_nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
+ const uint8_t *buf)
+{
+ fsl_nfc_write_buf(mtd, buf, mtd->writesize);
+ copy_to_spare(mtd,chip->oob_poi, mtd->oobsize);
+}
+
+
+int board_nand_init(struct nand_chip *nand)
+{
+ struct mtd_info *mtd;
+
+ priv = malloc(sizeof(*priv));
+ if (!priv) {
+ printf("FSL NFC: failed to allocate priv structure\n");
+ return -1;
+ }
+ memset(priv, 0, sizeof(*priv));
+
+ mpc5125_cfg_iopad_init();
+ if (fsl_nfc_get_hw_config(nand) < 0)
+ return -1;
+
+ mtd = &priv->mtd;
+ mtd->priv = nand;
+
+ /* 5 us command delay time */
+ nand->chip_delay = 8;
+ nand->page_shift =0;
+ nand->chip_shift = 0;
+
+ nand->dev_ready = fsl_nfc_dev_ready;
+ nand->cmdfunc = mpc5125_nfc_command;
+ nand->waitfunc = fsl_nfc_wait;
+ nand->select_chip = fsl_nfc_select_chip;
+ nand->options = NAND_USE_FLASH_BBT;
+ if (priv->width == 2) {
+ nand->options |= NAND_BUSWIDTH_16;
+ nand->read_byte = fsl_nfc_read_byte16;
+ }
+ nand->read_byte = fsl_nfc_read_byte;
+ nand->read_word = fsl_nfc_read_word;
+ nand->write_buf = fsl_nfc_write_buf;
+ nand->read_buf = fsl_nfc_read_buf;
+ nand->verify_buf = fsl_nfc_verify_buf;
+ nand->options = NAND_NO_AUTOINCR | NAND_USE_FLASH_BBT;
+ nand->ecc.mode = NAND_ECC_HW;
+ nand->ecclayout=&nand_hw_eccoob_4k;
+ nand->ecc.size = 512; /* RS-ECC is applied for both MAIN+SPARE not MAIN alone */
+ nand->ecc.bytes = 9; /* used for both main and spare area */
+ nand->ecc.read_page = mpc5125_nand_read_page_hwecc;
+ nand->ecc.write_page = mpc5125_nand_write_page_hwecc;
+
+ nfc_clear(NFC_IRQ_STATUS, CMD_DONE_EN_MASK| IDLE_EN_MASK);
+
+ /* SET SECTOR SIZE */
+ nfc_set_field( NFC_FLASH_CONFIG,
+ CONFIG_ECC_SRAM_ADDR_MASK,
+ CONFIG_ECC_SRAM_ADDR_SHIFT, (MPC5125_NFC_ECC_STATUS_ADD>>3)&0x00001ff);
+
+ nfc_write(NFC_SECTOR_SIZE, CONFIG_FSL_NFC_WRITE_SIZE/2 | CONFIG_FSL_NFC_SPARE_SIZE/2);
+ nfc_set_field(NFC_FLASH_CONFIG,
+ CONFIG_ECC_MODE_MASK,
+ CONFIG_ECC_MODE_SHIFT, ECC_45_BYTE);
+ nfc_set_field( NFC_FLASH_CONFIG,
+ CONFIG_ADDR_AUTO_INCR_MASK,
+ CONFIG_ADDR_AUTO_INCR_SHIFT, 0);
+
+ nfc_set_field(NFC_FLASH_CONFIG,
+ CONFIG_BUFNO_AUTO_INCR_MASK,
+ CONFIG_BUFNO_AUTO_INCR_SHIFT, 1);
+
+ nfc_set_field(NFC_FLASH_CONFIG,
+ CONFIG_16BIT_MASK,
+ CONFIG_16BIT_SHIFT, 0);
+ /* SET FAST_FLASH = 1 */
+ nfc_set_field(NFC_FLASH_CONFIG,
+ CONFIG_FAST_FLASH_MASK,
+ CONFIG_FAST_FLASH_SHIFT, 1);
+
+ nfc_set_field(NFC_FLASH_CONFIG,
+ CONFIG_BOOT_MODE_MASK,
+ CONFIG_BOOT_MODE_SHIFT, 0);
+
+ nfc_set_field(NFC_FLASH_CONFIG,
+ CONFIG_ECC_SRAM_REQ_MASK,
+ CONFIG_ECC_SRAM_REQ_SHIFT, 1);
+ g_nfc_save.nfc_config=nfc_read(NFC_FLASH_CONFIG);
+ g_nfc_save.nfc_sectsize=nfc_read(NFC_SECTOR_SIZE);
+ g_nfc_save.nfc_status=nfc_read(NFC_IRQ_STATUS);
+ return 0;
+}
+
+
+
diff --git a/drivers/mtd/nand/mpc5125_nfc_mtc.mtc b/drivers/mtd/nand/mpc5125_nfc_mtc.mtc
new file mode 100644
index 0000000000..4f13032b5c
--- /dev/null
+++ b/drivers/mtd/nand/mpc5125_nfc_mtc.mtc
Binary files differ
diff --git a/drivers/mtd/nand/mpc5125_nfc_struct.h b/drivers/mtd/nand/mpc5125_nfc_struct.h
new file mode 100644
index 0000000000..fb35b53e3a
--- /dev/null
+++ b/drivers/mtd/nand/mpc5125_nfc_struct.h
@@ -0,0 +1,27 @@
+/*
+ Provider: LimePC Multimedia Technologies Co., Limited
+ Date:04/15/2010
+ Copyright note: without provider's written consensus by the provider, any release
+ of provider's code could result in infrigement of provider's intellectural properties.
+ Autor:Cloudy Chen <chen_yunsong@mtcera.com>
+*/
+#ifndef MPC5125_NFC_STRUCT_H
+#define MPC5125_NFC_STRUCT_H
+#define IS_2K_PAGE_NAND (priv->writesize == 2048)
+#define IS_4K_PAGE_NAND (priv->writesize == 4096)
+#define IS_LARGE_PAGE_NAND (priv->writesize > 512)
+
+#define PAGES_PER_BLOCK 0x100
+#define MPC5125_NFC_ECC_STATUS_ADD (NFC_SPARE_AREA(0)+0xf0)
+#define PAGE_virtual_2K 0x0840
+
+#define ioctl CONFIG_SYS_IOCTRL_ADDR
+
+
+struct mpc5125_nfc_save_struct{
+ u32 nfc_sectsize;
+ u32 nfc_config;
+ u32 nfc_status;
+};
+#endif
+
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index d33fee242f..e2470d8178 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -2454,6 +2454,9 @@ static void nand_set_defaults(struct nand_chip *chip, int busw)
/*
* Get the flash and manufacturer id and lookup if the type is supported
*/
+ #ifdef CONFIG_ADS5125
+ extern u8 mpc5125_nfc_get_id(struct mtd_info *mtd,int col);
+ #endif
static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
struct nand_chip *chip,
int busw, int *maf_id)
@@ -2473,11 +2476,11 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
/* Send the command for reading device ID */
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
-
+ chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
/* Read manufacturer and device IDs */
+
*maf_id = chip->read_byte(mtd);
dev_id = chip->read_byte(mtd);
-
/* Try again to make sure, as some systems the bus-hold or other
* interface concerns can cause random data which looks like a
* possibly credible NAND flash to appear. If the two results do
@@ -2487,10 +2490,9 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
/* Read manufacturer and device IDs */
-
+
tmp_manf = chip->read_byte(mtd);
tmp_id = chip->read_byte(mtd);
-
if (tmp_manf != *maf_id || tmp_id != dev_id) {
printk(KERN_INFO "%s: second ID read did not match "
"%02x,%02x against %02x,%02x\n", __func__,
@@ -2762,7 +2764,9 @@ int nand_scan_tail(struct mtd_info *mtd)
chip->ecc.mode = NAND_ECC_SOFT;
case NAND_ECC_SOFT:
+#ifndef CONFIG_NAND_SPL
chip->ecc.calculate = nand_calculate_ecc;
+#endif
chip->ecc.correct = nand_correct_data;
chip->ecc.read_page = nand_read_page_swecc;
chip->ecc.read_subpage = nand_read_subpage;
@@ -2774,8 +2778,10 @@ int nand_scan_tail(struct mtd_info *mtd)
break;
case NAND_ECC_NONE:
+ /*
printk(KERN_WARNING "NAND_ECC_NONE selected by board driver. "
"This is not recommended !!\n");
+ */
chip->ecc.read_page = nand_read_page_raw;
chip->ecc.write_page = nand_write_page_raw;
chip->ecc.read_oob = nand_read_oob_std;
diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c
index 077c3051bc..5d243a62ff 100644
--- a/drivers/mtd/nand/nand_ids.c
+++ b/drivers/mtd/nand/nand_ids.c
@@ -110,6 +110,9 @@ struct nand_flash_dev nand_flash_ids[] = {
{"NAND 2GiB 1,8V 16-bit", 0xB5, 0, 2048, 0, LP_OPTIONS16},
{"NAND 2GiB 3,3V 16-bit", 0xC5, 0, 2048, 0, LP_OPTIONS16},
+ /*64 Gigabit*/
+ {"NAND 8 GiB 3,3V 8-bit", 0x68, 4096, 0x1000, 4096*256, 0},
+
/*
* Renesas AND 1 Gigabit. Those chips do not support extended id and
* have a strange page/block layout ! The chosen minimum erasesize is
diff --git a/drivers/net/mpc512x_fec.c b/drivers/net/mpc512x_fec.c
index 7078c4ef77..dd461307be 100644
--- a/drivers/net/mpc512x_fec.c
+++ b/drivers/net/mpc512x_fec.c
@@ -9,6 +9,7 @@
#include <common.h>
#include <mpc512x.h>
#include <malloc.h>
+#include <asm/io.h>
#include <net.h>
#include <netdev.h>
#include <miiphy.h>
@@ -17,6 +18,8 @@
DECLARE_GLOBAL_DATA_PTR;
#define DEBUG 0
+#define CURFEC_ADDR(devname) ((devname[3]=='2') ? \
+ (MPC512X_FEC + 0x2000) : MPC512X_FEC)
#if defined(CONFIG_CMD_NET) && defined(CONFIG_NET_MULTI) && \
defined(CONFIG_MPC512x_FEC)
@@ -41,13 +44,18 @@ static int rx_buff_idx = 0;
static void mpc512x_fec_phydump (char *devname)
{
uint16 phyStatus, i;
+#ifdef CONFIG_ADS5125
+ uint8 phyAddr = ((devname[3]=='2') ? CONFIG_PHY2_ADDR : CONFIG_PHY_ADDR);
+#else
uint8 phyAddr = CONFIG_PHY_ADDR;
+#endif
uint8 reg_mask[] = {
/* regs to print: 0...8, 21,27,31 */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1,
};
+ printf("Dump of %s at addr %2x\n", devname, phyAddr);
for (i = 0; i < 32; i++) {
if (reg_mask[i]) {
miiphy_read (devname, phyAddr, i, &phyStatus);
@@ -223,7 +231,7 @@ static int mpc512x_fec_init (struct eth_device *dev, bd_t * bis)
mpc512x_fec_priv *fec = (mpc512x_fec_priv *)dev->priv;
#if (DEBUG & 0x1)
- printf ("mpc512x_fec_init... Begin\n");
+ printf ("mpc512x_fec_init... with eth_device %s Begin\n", dev->name);
#endif
/* Set interrupt mask register */
@@ -239,7 +247,12 @@ static int mpc512x_fec_init (struct eth_device *dev, bd_t * bis)
fec->eth->op_pause = 0x00010020;
/* Frame length=1522; MII mode */
+#ifdef CONFIG_ADS5125
+ /* RMII Mode */
+ fec->eth->r_cntrl = (FEC_MAX_FRAME_LEN << 16) | 0x124;
+#else
fec->eth->r_cntrl = (FEC_MAX_FRAME_LEN << 16) | 0x24;
+#endif
/* Half-duplex, heartbeat disabled */
fec->eth->x_cntrl = 0x00000000;
@@ -277,12 +290,16 @@ static int mpc512x_fec_init (struct eth_device *dev, bd_t * bis)
int mpc512x_fec_init_phy (struct eth_device *dev, bd_t * bis)
{
mpc512x_fec_priv *fec = (mpc512x_fec_priv *)dev->priv;
- const uint8 phyAddr = CONFIG_PHY_ADDR; /* Only one PHY */
+#ifdef CONFIG_ADS5125
+ const uint8 phyAddr = ((dev->name[3]=='2') ? CONFIG_PHY2_ADDR : CONFIG_PHY_ADDR);
+#else
+ const uint8 phyAddr = CONFIG_PHY_ADDR;
+#endif
int timeout = 1;
uint16 phyStatus;
#if (DEBUG & 0x1)
- printf ("mpc512x_fec_init_phy... Begin\n");
+ printf ("mpc512x_fec_init_phy... with dev %s Begin\n", dev->name);
#endif
/*
@@ -407,6 +424,7 @@ static void mpc512x_fec_halt (struct eth_device *dev)
int counter = 0xffff;
#if (DEBUG & 0x2)
+ printf("In FEC Halt with device %s\n", dev->name);
if (fec->xcv_type != SEVENWIRE)
mpc512x_fec_phydump (dev->name);
#endif
@@ -458,7 +476,7 @@ static int mpc512x_fec_send (struct eth_device *dev, volatile void *eth_data,
volatile FEC_TBD *pTbd;
#if (DEBUG & 0x20)
- printf("tbd status: 0x%04x\n", fec->tbdBase[fec->tbdIndex].status);
+ printf("%s tbd status: 0x%04x\n", dev->name, fec->bdBase->tbd[fec->tbdIndex].status);
#endif
/*
@@ -608,14 +626,23 @@ int mpc512x_fec_initialize (bd_t * bis)
mpc512x_fec_priv *fec;
struct eth_device *dev;
int i;
+ char *memaddr;
char *tmp, *end, env_enetaddr[6];
void * bd;
+#ifdef CONFIG_ADS5125 /* 2nd RMII ethernet */
+ char *act = getenv("ethact");
+ memaddr = (char *)MPC512X_FEC;
+ if (act[3] == '2')
+ memaddr += 0x2000;
+#else
+ memaddr = (char *)MPC512X_FEC;
+#endif
fec = (mpc512x_fec_priv *) malloc (sizeof(*fec));
dev = (struct eth_device *) malloc (sizeof(*dev));
memset (dev, 0, sizeof *dev);
- fec->eth = (ethernet_regs *) MPC512X_FEC;
+ fec->eth = (ethernet_regs *) memaddr;
# ifndef CONFIG_FEC_10MBIT
fec->xcv_type = MII100;
@@ -623,13 +650,17 @@ int mpc512x_fec_initialize (bd_t * bis)
fec->xcv_type = MII10;
# endif
dev->priv = (void *)fec;
- dev->iobase = MPC512X_FEC;
+ dev->iobase = (int)memaddr;
dev->init = mpc512x_fec_init;
dev->halt = mpc512x_fec_halt;
dev->send = mpc512x_fec_send;
dev->recv = mpc512x_fec_recv;
sprintf (dev->name, "FEC ETHERNET");
+#ifdef CONFIG_ADS5125
+ if (memaddr != (char *)MPC512X_FEC)
+ sprintf (dev->name, "FEC2 ETHERNET");
+#endif
eth_register (dev);
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
@@ -638,7 +669,7 @@ int mpc512x_fec_initialize (bd_t * bis)
#endif
/* Clean up space FEC's MIB and FIFO RAM ...*/
- memset ((void *) MPC512X_FEC + 0x200, 0x00, 0x400);
+ memset ((void *) memaddr + 0x200, 0x00, 0x400);
/*
* Malloc space for BDs (must be quad word-aligned)
@@ -658,18 +689,26 @@ int mpc512x_fec_initialize (bd_t * bis)
*/
fec->eth->ievent = 0xffffffff;
+ /* rmii mode */
+ fec->eth->r_cntrl = (FEC_MAX_FRAME_LEN << 16) | 0x124;
+
/*
* Try to set the mac address now. The fec mac address is
* a garbage after reset. When not using fec for booting
* the Linux fec driver will try to work with this garbage.
*/
tmp = getenv ("ethaddr");
+
+ if(!tmp)
+ tmp = "AA:BB:CC:DD:EE:FF"; // fixme
+
if (tmp) {
for (i=0; i<6; i++) {
env_enetaddr[i] = tmp ? simple_strtoul (tmp, &end, 16) : 0;
if (tmp)
tmp = (*end) ? end+1 : end;
}
+
mpc512x_fec_set_hwaddr (fec, env_enetaddr);
fec->eth->gaddr1 = 0x00000000;
fec->eth->gaddr2 = 0x00000000;
@@ -684,7 +723,7 @@ int mpc512x_fec_initialize (bd_t * bis)
/********************************************************************/
int fec512x_miiphy_read (char *devname, uint8 phyAddr, uint8 regAddr, uint16 * retVal)
{
- ethernet_regs *eth = (ethernet_regs *) MPC512X_FEC;
+ ethernet_regs *eth = (ethernet_regs *) CURFEC_ADDR(devname);
uint32 reg; /* convenient holder for the PHY register */
uint32 phy; /* convenient holder for the PHY */
int timeout = 0xffff;
@@ -705,7 +744,7 @@ int fec512x_miiphy_read (char *devname, uint8 phyAddr, uint8 regAddr, uint16 * r
if (timeout == 0) {
#if (DEBUG & 0x2)
- printf ("Read MDIO failed...\n");
+ printf ("Read MDIO addr %x failed (%s)...\n", phyAddr, devname);
#endif
return -1;
}
@@ -726,7 +765,7 @@ int fec512x_miiphy_read (char *devname, uint8 phyAddr, uint8 regAddr, uint16 * r
/********************************************************************/
int fec512x_miiphy_write (char *devname, uint8 phyAddr, uint8 regAddr, uint16 data)
{
- ethernet_regs *eth = (ethernet_regs *) MPC512X_FEC;
+ ethernet_regs *eth = (ethernet_regs *) CURFEC_ADDR(devname);
uint32 reg; /* convenient holder for the PHY register */
uint32 phy; /* convenient holder for the PHY */
int timeout = 0xffff;
@@ -744,7 +783,7 @@ int fec512x_miiphy_write (char *devname, uint8 phyAddr, uint8 regAddr, uint16 da
if (timeout == 0) {
#if (DEBUG & 0x2)
- printf ("Write MDIO failed...\n");
+ printf ("Write MDIO failed (%s)...\n", devname);
#endif
return -1;
}