diff options
Diffstat (limited to 'drivers/mtd/nand')
-rw-r--r-- | drivers/mtd/nand/Makefile | 3 | ||||
-rw-r--r-- | drivers/mtd/nand/fsl_nfc_nand.c | 1104 | ||||
-rw-r--r-- | drivers/mtd/nand/fsl_nfc_nand_5125.c | 919 | ||||
-rw-r--r-- | drivers/mtd/nand/mpc5125_nfc_mtc.mtc | bin | 0 -> 18720 bytes | |||
-rw-r--r-- | drivers/mtd/nand/mpc5125_nfc_struct.h | 27 | ||||
-rw-r--r-- | drivers/mtd/nand/nand_base.c | 14 | ||||
-rw-r--r-- | drivers/mtd/nand/nand_ids.c | 3 |
7 files changed, 2066 insertions, 4 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 Binary files differnew file mode 100644 index 0000000000..4f13032b5c --- /dev/null +++ b/drivers/mtd/nand/mpc5125_nfc_mtc.mtc 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 |