[U-Boot] [PATCH] ADS5121 NAND driver

ADS5121 rev4 / MPC5121e rev2 only
Only tested with: 2K page size 8 bit device width
This controller treats 2K pages as 4 512 byte pages and the hw ecc is over the combined 512 byte main area and the first 7 bytes of the spare area.
The hw ecc is stored in the last 9 bytes of the spare area.
This all means the the spare area can not be written separately from the main. This means unmodified JFFS2 will not work.
Signed-off-by: John Rigby jrigby@freescale.com --- board/ads5121/ads5121.c | 1 + drivers/mtd/nand/Makefile | 1 + drivers/mtd/nand/mpc5121rev2_nand.c | 1122 +++++++++++++++++++++++++++++++++++ include/configs/ads5121.h | 27 + 4 files changed, 1151 insertions(+), 0 deletions(-) create mode 100644 drivers/mtd/nand/mpc5121rev2_nand.c
diff --git a/board/ads5121/ads5121.c b/board/ads5121/ads5121.c index 0610928..3329f61 100644 --- a/board/ads5121/ads5121.c +++ b/board/ads5121/ads5121.c @@ -34,6 +34,7 @@ /* Clocks in use */ #define SCCR1_CLOCKS_EN (CLOCK_SCCR1_CFG_EN | \ CLOCK_SCCR1_LPC_EN | \ + CLOCK_SCCR1_NFC_EN | \ CLOCK_SCCR1_PSC_EN(CONFIG_PSC_CONSOLE) | \ CLOCK_SCCR1_PSCFIFO_EN | \ CLOCK_SCCR1_DDR_EN | \ diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index b0abe6e..7addda6 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -38,6 +38,7 @@ endif COBJS-$(CONFIG_NAND_FSL_ELBC) += fsl_elbc_nand.o COBJS-$(CONFIG_NAND_FSL_UPM) += fsl_upm.o COBJS-$(CONFIG_NAND_S3C64XX) += s3c64xx.o +COBJS-$(CONFIG_NAND_MPC5121) += mpc5121rev2_nand.o endif
COBJS := $(COBJS-y) diff --git a/drivers/mtd/nand/mpc5121rev2_nand.c b/drivers/mtd/nand/mpc5121rev2_nand.c new file mode 100644 index 0000000..88555ab --- /dev/null +++ b/drivers/mtd/nand/mpc5121rev2_nand.c @@ -0,0 +1,1122 @@ +/* + * Copyright 2004-2008 Freescale Semiconductor, Inc. All Rights Reserved. + * + * Based on drivers/mtd/nand/mpc5121_nand.c + * which was forked from 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> + +static struct mpc5121_nand_private { + struct mtd_info mtd; + char spare_only; + char status_req; + u16 col_addr; + int sparesize; + int width; + int chipsel; +} *priv; + +#define IS_2K_PAGE_NAND (mtd->writesize == 2048) +#define IS_4K_PAGE_NAND (mtd->writesize == 4096) +#define IS_LARGE_PAGE_NAND (mtd->writesize > 512) + +#define NFC_REG_BASE ((void *)CONFIG_SYS_NAND_BASE) +/* + * MPC5121 Rev2 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 + + +#ifdef CONFIG_MTD_NAND_MPC5121_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, + }, + .oobavail = 5, + .oobfree = { + {0, 5} + }, +}; + +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, + }, + .oobavail = 26, + .oobfree = { + {0, 5}, + {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, */ + }, + .oobavail = 54, + .oobfree = { + {0, 5}, + {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, */ + }, + .oobavail = 4, + .oobfree = { + {0, 5}, + {26, 8}, + {52, 8}, + {78, 8}, + {104, 8}, + {130, 8}, + {156, 8}, + {182, 8}, + }, +}; + +/* + * 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, size; + + count = mtd->writesize >> 9; + size = (ooblen / count >> 1) << 1; + + for (i = 0; i < count - 1; i++) { + memcpy_fromio(pbuf, SPARE_AREA(i), size); + pbuf += size; + len -= size; + } + memcpy_fromio(pbuf, SPARE_AREA(i), len); +} + +static void copy_to_spare(struct mtd_info *mtd, void *pbuf, int len) +{ + u16 ooblen = mtd->oobsize; + u8 i, count, size; + + count = mtd->writesize >> 9; + size = (ooblen / count >> 1) << 1; + + for (i = 0; i < count - 1; i++) { + memcpy_toio(SPARE_AREA(i), pbuf, size); + pbuf += size; + len -= size; + } + 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. + * + * @maxRetries number of retry attempts (separated by 1 us) + */ +static void wait_op_done(int maxRetries) +{ + + while (1) { + maxRetries--; + if (in_be16(NFC_CONFIG2) & NFC_INT) + break; + udelay(1); + } + if (maxRetries <= 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); + + out_be16(NFC_FLASH_CMD, cmd); + out_be16(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); + out_be16(NFC_FLASH_ADDR, (addr << NFC_FLASH_ADDR_SHIFT)); + + out_be16(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 = buf_id; + MTDDEBUG(MTD_DEBUG_LEVEL3, "%s\n", __FUNCTION__); + + /* Set RBA bits for BUFFER val */ + out_be16(NFC_BUF_ADDR, val); + + out_be16(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 = buf_id; + MTDDEBUG(MTD_DEBUG_LEVEL3, "%s\n", __FUNCTION__); + + /* Set RBA bits for BUFFER val */ + out_be16(NFC_BUF_ADDR, val); + + out_be16(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 = 0; + + /* NFC buffer 0 is used for device ID output */ + /* Set RBA bits for BUFFER0 */ + + out_be16(NFC_BUF_ADDR, val); + + /* Read ID into main buffer */ + out_be16(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; + /* Issue status request to NAND device */ + + /* save the main area1 first word, later do recovery */ + save = in_be32(MAIN_AREA(1)); + out_be32(MAIN_AREA(1), 0); + + /* + * NFC buffer 1 is used for device status to prevent + * corruption of read/write buffer on status requests. + */ + + /* Select BUFFER1 */ + out_be16(NFC_BUF_ADDR, 1); + + /* Read status into main buffer */ + out_be16(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 (in_be16(NFC_CONFIG1) & NFC_BIG) + ret = in_8(MAIN_AREA(1)); + else + ret = in_8(MAIN_AREA(1) + 3); + + out_be32(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 mpc5121_nand_dev_ready(struct mtd_info *mtd) +{ + return 1; +} + +static void mpc5121_nand_enable_hwecc(struct mtd_info *mtd, int mode) +{ + out_be16(NFC_CONFIG1, (in_be16(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 mpc5121_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 = in_be16(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 = in_be16(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; +} + +/* + * Function to correct the detected errors. This NFC corrects all the errors + * detected. So this function is not required. + */ +static int mpc5121_nand_correct_data(struct mtd_info *mtd, u_char *dat, + u_char *read_ecc, u_char *calc_ecc) +{ + panic("Shouldn't be called here: %d\n", __LINE__); + return 0; /* FIXME */ +} + +/* + * Function to calculate the ECC for the data to be stored in the Nand device. + * This NFC has a hardware RS(511,503) ECC engine together with the RS ECC + * CONTROL blocks are responsible for detection and correction of up to + * 4 symbols of 9 bits each in 528 byte page. + * So this function is not required. + */ + +static int mpc5121_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, + u_char *ecc_code) +{ + panic("Shouldn't be called here %d \n", __LINE__); + return 0; /* FIXME */ +} + +/*! + * 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 mpc5121_nand_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 = in_8(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 mpc5121_nand_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 = in_be16(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 mpc5121_nand_read_byte16(struct mtd_info *mtd) +{ + /* Check for status request */ + if (priv->status_req) + return (get_dev_status() & 0xff); + + return mpc5121_nand_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 mpc5121_nand_write_buf(struct mtd_info *mtd, + const u_char *buf, int len) +{ + printf("re-work may be needed?\n"); + 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 mpc5121_nand_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 mpc5121_nand_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; + + for (; len > 0; len -= 4, main_buf += 4) + v = in_be32(main_buf); + if (v != *p++) + return -1; + return 0; +} + +static int mpc5121_nand_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 1 + if (CONFIG_MPC5121_NAND_WRITE_SIZE != 2048) { + printf("MPC5121 NAND: " + "%d byte write size flash support is untested\n", + CONFIG_MPC5121_NAND_WRITE_SIZE); + return -1; + } +#endif + rcwh = in_be32((void *)&(im->reset.rcwh)); + width = ((rcwh >> 6) & 0x1) ? 2 : 1; + + if (width != CONFIG_MPC5121_NAND_WIDTH) { + printf("MPC5121 NAND: Device width mismatch, compiled for %d, " + "reset configuration word width is %d\n", + CONFIG_MPC5121_NAND_WIDTH, width); + return -1; + } + + if (width == 2) { + this->options |= NAND_BUSWIDTH_16; + this->read_byte = mpc5121_nand_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_MPC5121_NAND_WRITE_SIZE != writesize) { + printf("MPC5121 NAND: " + "Device write size mismatch, " + "compiled for %d, " + "size from reset configuration word is %d\n", + CONFIG_MPC5121_NAND_WRITE_SIZE, writesize); + return -1; + } + if (CONFIG_MPC5121_NAND_SPARE_SIZE != sparesize) { + printf("MPC5121 NAND: " + "Device spare size mismatch, " + "compiled for %d, " + "size from reset configuration word is %d\n", + CONFIG_MPC5121_NAND_SPARE_SIZE, sparesize); + return -1; + } + + priv->sparesize = sparesize; + priv->width = width; + return 0; +} + +static void mpc5121_cs_enable(int chip) +{ + unsigned char *csreg = (unsigned char *)CONFIG_SYS_CPLD_BASE + 0x09; + u8 v; + + v = in_8(csreg); + v |= 0xf; + v &= ~(1<<chip); + + out_8(csreg, v); +} + + +/*! + * 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 mpc5121_nand_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("MPC5121 NAND: " + "ERROR: Illegal chip select (chip = %d)\n", chip); + } + + if (chip < 0) { + out_be16(NFC_CONFIG1, (in_be16(NFC_CONFIG1) & ~NFC_CE)); + return; + } + + out_be16(NFC_CONFIG1, (in_be16(NFC_CONFIG1) | NFC_CE)); + + /* Turn on appropriate chip */ + mpc5121_cs_enable(priv->chipsel); +} + +/* + * Function to perform the address cycles. + */ +static void mpc5121_nand_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); + + mpc5121_nand_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 mpc5121_nand_command(struct mtd_info *mtd, unsigned command, + int column, int page_addr) +{ + MTDDEBUG(MTD_DEBUG_LEVEL3, + "mpc5121_nand_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); + + mpc5121_nand_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 mpc5121_nand_wait(struct mtd_info *mtd, struct nand_chip *chip) +{ + return (int)(get_dev_status()); +} + +static int mpc5121_nand_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 mpc5121_nand_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); + mpc5121_nand_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 = mpc5121_nand_wait(mtd, chip); + if (status & NAND_STATUS_FAIL) + return -1; + return 0; +} + +static int mpc5121_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip, + uint8_t *buf) +{ + int stat; + + stat = mpc5121_check_ecc_status(mtd); + if (stat == -1) { + mtd->ecc_stats.failed++; + printf("MPC5121 NAND: 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 mpc5121_nand_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); +} + +/* Define some generic bad / good block scan pattern which are used + * while scanning a device for factory marked good / bad blocks. */ +static uint8_t scan_ff_pattern[] = { 0xff, 0xff }; + +static struct nand_bbt_descr smallpage_memorybased = { + .options = NAND_BBT_SCAN2NDPAGE, + .offs = 5, + .len = 1, + .pattern = scan_ff_pattern +}; + +static struct nand_bbt_descr largepage_memorybased = { + .options = 0, + .offs = 5, + .len = 2, + .pattern = scan_ff_pattern +}; + +/* Generic flash bbt decriptors +*/ +static uint8_t bbt_pattern[] = { 'B', 'b', 't', '0' }; +static uint8_t mirror_pattern[] = { '1', 't', 'b', 'B' }; + +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 +}; + +static int mpc5121_nand_scan_bbt(struct mtd_info *mtd) +{ + struct nand_chip *this = mtd->priv; + + if (IS_2K_PAGE_NAND) + this->ecc.layout = &nand_hw_eccoob_2k; + else if (IS_4K_PAGE_NAND) + if (priv->sparesize == 128) + this->ecc.layout = &nand_hw_eccoob_4k; + else + this->ecc.layout = &nand_hw_eccoob_4k_218_spare; + else + this->ecc.layout = &nand_hw_eccoob_512; + + /* propagate ecc.layout to mtd_info */ + mtd->ecclayout = this->ecc.layout; + +#if 0 + /* jffs2 should not write oob */ + mtd->flags &= ~MTD_OOB_WRITEABLE; +#endif + + /* use flash based bbt */ + this->bbt_td = &bbt_main_descr; + this->bbt_md = &bbt_mirror_descr; + + /* update flash based bbt */ + this->options |= NAND_USE_FLASH_BBT; + + if (!this->badblock_pattern) + this->badblock_pattern = (mtd->writesize > 512) ? + &largepage_memorybased : &smallpage_memorybased; + + /* Build bad block table */ + return nand_scan_bbt(mtd, this->badblock_pattern); +} + +void board_nand_select_device(struct nand_chip *nand, int chip) +{ + if (chip >= CONFIG_MPC5121_NAND_CHIPS) { + printf("MPC5121 NAND: " + "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("MPC5121 NAND: failed to allocate priv structure\n"); + return -1; + } + memset(priv, 0, sizeof(*priv)); + + if (mpc5121_nand_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 = mpc5121_nand_dev_ready; + nand->cmdfunc = mpc5121_nand_command; + nand->waitfunc = mpc5121_nand_wait; + nand->select_chip = mpc5121_nand_select_chip; + if (priv->width == 2) { + nand->options |= NAND_BUSWIDTH_16; + nand->read_byte = mpc5121_nand_read_byte16; + } + nand->read_byte = mpc5121_nand_read_byte; + nand->read_word = mpc5121_nand_read_word; + nand->write_buf = mpc5121_nand_write_buf; + nand->read_buf = mpc5121_nand_read_buf; + nand->verify_buf = mpc5121_nand_verify_buf; + nand->scan_bbt = mpc5121_nand_scan_bbt; + + out_be16(NFC_CONFIG1, (in_be16(NFC_CONFIG1) | NFC_RST)); + + /* Disable interrupt */ + out_be16(NFC_CONFIG1, (in_be16(NFC_CONFIG1) | NFC_INT_MSK)); + + if (hardware_ecc) { + nand->ecc.read_page = mpc5121_nand_read_page; + nand->ecc.write_page = mpc5121_nand_write_page; + nand->ecc.read_oob = mpc5121_nand_read_oob; + nand->ecc.write_oob = mpc5121_nand_write_oob; + nand->ecc.layout = &nand_hw_eccoob_512; + nand->ecc.calculate = mpc5121_nand_calculate_ecc; + nand->ecc.hwctl = mpc5121_nand_enable_hwecc; + nand->ecc.correct = mpc5121_nand_correct_data; + 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; + out_be16(NFC_CONFIG1, (in_be16(NFC_CONFIG1) | NFC_ECC_EN)); + } else { + nand->ecc.mode = NAND_ECC_SOFT; + out_be16(NFC_CONFIG1, (in_be16(NFC_CONFIG1) & ~NFC_ECC_EN)); + } + + out_be16(NFC_CONFIG1, in_be16(NFC_CONFIG1) & ~NFC_SP_EN); + + + /* Reset NAND */ + nand->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); + + /* preset operation */ + /* Unlock the internal RAM Buffer */ + out_be16(NFC_CONFIG, NFC_BLS_UNLOCKED); + + /* Blocks to be unlocked */ + out_be16(NFC_UNLOCKSTART_BLKADDR0, 0x0); + out_be16(NFC_UNLOCKEND_BLKADDR0, 0xffff); + + /* Unlock Block Command for given address range */ + out_be16(NFC_WRPROT, NFC_WPC_UNLOCK); + + /* Set sparesize */ + out_be16(NFC_SPAS, (in_be16(NFC_SPAS) & 0xff00) | (priv->sparesize/2)); + + /* + * Only use 8bit ecc (aka not 4 bit) if large spare size + */ + if (priv->sparesize == 218) + out_be16(NFC_CONFIG1, (in_be16(NFC_CONFIG1) & ~NFC_ECC_MODE_4)); + else + out_be16(NFC_CONFIG1, (in_be16(NFC_CONFIG1) | NFC_ECC_MODE_4)); + + return 0; +} diff --git a/include/configs/ads5121.h b/include/configs/ads5121.h index 8ec5e9d..ea79cd1 100644 --- a/include/configs/ads5121.h +++ b/include/configs/ads5121.h @@ -33,6 +33,7 @@ * * 0x0000_0000 - 0x0FFF_FFFF DDR RAM (256 MB) * 0x3000_0000 - 0x3001_FFFF SRAM (128 KB) + * 0x4000_0000 - 0x400F_FFFF NFC (1 MB) * 0x8000_0000 - 0x803F_FFFF IMMR (4 MB) * 0x8200_0000 - 0x8200_001F CPLD (32 B) * 0x8400_0000 - 0x82FF_FFFF PCI I/O space (16 MB) @@ -199,6 +200,32 @@ #undef CONFIG_SYS_FLASH_CHECKSUM
/* + * NAND FLASH + * drivers/mtd/nand/mpc5121_mpc.c (rev 2 silicon/rev 4 boards only) + */ +#ifdef CONFIG_NAND_SPL +#define CONFIG_SYS_NAND_BASE 0xFFF00000 +#else +#define CONFIG_SYS_NAND_BASE 0x40000000 +#endif +#define CONFIG_CMD_NAND 1 +/* + * The flash on ADS5121 board is two flash chips in one package + */ +#define CONFIG_SYS_MAX_NAND_DEVICE 2 +#define NAND_MAX_CHIPS CONFIG_SYS_MAX_NAND_DEVICE +#define CONFIG_SYS_NAND_SELECT_DEVICE 1 +#define CONFIG_NAND_MPC5121 +/* + * Configuration parameters for MPC5121 NAND driver + */ +#define CONFIG_MPC5121_NAND_WIDTH 1 +#define CONFIG_MPC5121_NAND_WRITE_SIZE 2048 +#define CONFIG_MPC5121_NAND_SPARE_SIZE 64 +#define CONFIG_MPC5121_NAND_CHIPS 2 + + +/* * CPLD registers area is really only 32 bytes in size, but the smallest possible LP * window is 64KB */

John Rigby wrote:
ADS5121 rev4 / MPC5121e rev2 only
What is unique about that revision that it cannot share a driver? It certainly shouldn't be board-specific...
This controller treats 2K pages as 4 512 byte pages and the hw ecc is over the combined 512 byte main area and the first 7 bytes of the spare area.
The hw ecc is stored in the last 9 bytes of the spare area.
This all means the the spare area can not be written separately from the main. This means unmodified JFFS2 will not work.
Sigh... Smack the hardware people for me.
Signed-off-by: John Rigby jrigby@freescale.com
board/ads5121/ads5121.c | 1 + drivers/mtd/nand/Makefile | 1 + drivers/mtd/nand/mpc5121rev2_nand.c | 1122 +++++++++++++++++++++++++++++++++++
This filename is very specific, especially since the i.MX NAND controller looks very similar. How about fsl_nfc_nand.c?
diff --git a/drivers/mtd/nand/mpc5121rev2_nand.c b/drivers/mtd/nand/mpc5121rev2_nand.c new file mode 100644 index 0000000..88555ab --- /dev/null +++ b/drivers/mtd/nand/mpc5121rev2_nand.c @@ -0,0 +1,1122 @@ +/*
- Copyright 2004-2008 Freescale Semiconductor, Inc. All Rights Reserved.
- Based on drivers/mtd/nand/mpc5121_nand.c
- which was forked from drivers/mtd/nand/mxc_nd.c
Forking's bad, mmkay?
+/*
- 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,
- },
- .oobavail = 5,
- .oobfree = {
{0, 5}
- },
+};
Looks like you also have a free byte at offset 6.
Leave out oobavail, it will be calculated by generic code.
+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,
- },
- .oobavail = 26,
- .oobfree = {
{0, 5},
{16, 7},
{32, 7},
{48, 7},
- },
+};
Byte zero is not free (it's used for bad-block markers), and byte one should be reserved for this as well. Bytes 5 and 6 are free.
+static struct nand_ecclayout nand_hw_eccoob_4k = {
- .eccbytes = 64, /* actually 72 but only room for 64 */
Let's fix that, then.
+/*
- 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, size;
- count = mtd->writesize >> 9;
- size = (ooblen / count >> 1) << 1;
If you want to round down to the nearest even number, use & ~1 (why would it ever be odd?). If not, what's going on?
- for (i = 0; i < count - 1; i++) {
memcpy_fromio(pbuf, SPARE_AREA(i), size);
pbuf += size;
len -= size;
- }
Shouldn't you check to make sure that len doesn't go negative?
+/*!
- This function polls the NFC to wait for the basic operation to complete by
- checking the INT bit of config2 register.
- @maxRetries number of retry attempts (separated by 1 us)
- */
noJavaCase, please.
+/*
- Function to correct the detected errors. This NFC corrects all the errors
- detected. So this function is not required.
- */
+static int mpc5121_nand_correct_data(struct mtd_info *mtd, u_char *dat,
u_char *read_ecc, u_char *calc_ecc)
+{
- panic("Shouldn't be called here: %d\n", __LINE__);
- return 0; /* FIXME */
+}
+/*
- Function to calculate the ECC for the data to be stored in the Nand device.
- This NFC has a hardware RS(511,503) ECC engine together with the RS ECC
- CONTROL blocks are responsible for detection and correction of up to
- 4 symbols of 9 bits each in 528 byte page.
- So this function is not required.
- */
+static int mpc5121_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
u_char *ecc_code)
+{
- panic("Shouldn't be called here %d \n", __LINE__);
- return 0; /* FIXME */
+}
Just leave these function pointers NULL, since you replace read_page and write_page.
+static u_char mpc5121_nand_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 = in_8(area_buf + priv->col_addr); + priv->col_addr++; + return rv; +}
You appear to support using read_byte on the spare area with READOOB, but not if the buffer had merely advanced past the main area. Not sure that it matters here, though.
+/*!
- 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 mpc5121_nand_read_byte16(struct mtd_info *mtd) +{
- /* Check for status request */
- if (priv->status_req)
return (get_dev_status() & 0xff);
- return mpc5121_nand_read_word(mtd) & 0xff;
+}
read_byte should never be called with 16-bit NAND.
+/*!
- 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 mpc5121_nand_write_buf(struct mtd_info *mtd,
const u_char *buf, int len)
+{
- printf("re-work may be needed?\n");
Answer this before we apply the patch. :-)
- if (page_addr != -1)
do {
send_addr((page_addr & 0xff));
page_mask >>= 8;
page_addr >>= 8;
} while (page_mask != 0);
+}
Braces around multi-line if-bodies.
+/*
- 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);
- mpc5121_nand_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);
If you put braces around one half of the if, put it around the other.
+static int mpc5121_nand_wait(struct mtd_info *mtd, struct nand_chip *chip) +{
- return (int)(get_dev_status());
+}
Unnecessary cast.
+static int mpc5121_nand_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 mpc5121_nand_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);
- mpc5121_nand_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 = mpc5121_nand_wait(mtd, chip);
- if (status & NAND_STATUS_FAIL)
return -1;
- return 0;
+}
Why override these rather than let them go through the command function?
+static struct nand_bbt_descr smallpage_memorybased = {
- .options = NAND_BBT_SCAN2NDPAGE,
- .offs = 5,
- .len = 1,
- .pattern = scan_ff_pattern
+};
This is the default.
+static struct nand_bbt_descr largepage_memorybased = {
- .options = 0,
- .offs = 5,
- .len = 2,
- .pattern = scan_ff_pattern
+};
This isn't normal -- why are you starting it at offset 5?
+static int mpc5121_nand_scan_bbt(struct mtd_info *mtd) +{
- struct nand_chip *this = mtd->priv;
- if (IS_2K_PAGE_NAND)
this->ecc.layout = &nand_hw_eccoob_2k;
- else if (IS_4K_PAGE_NAND)
if (priv->sparesize == 128)
this->ecc.layout = &nand_hw_eccoob_4k;
else
this->ecc.layout = &nand_hw_eccoob_4k_218_spare;
- else
this->ecc.layout = &nand_hw_eccoob_512;
- /* propagate ecc.layout to mtd_info */
- mtd->ecclayout = this->ecc.layout;
+#if 0
- /* jffs2 should not write oob */
- mtd->flags &= ~MTD_OOB_WRITEABLE;
+#endif
Should this be set, or not? No dead code.
- /* use flash based bbt */
- this->bbt_td = &bbt_main_descr;
- this->bbt_md = &bbt_mirror_descr;
- /* update flash based bbt */
- this->options |= NAND_USE_FLASH_BBT;
- if (!this->badblock_pattern)
this->badblock_pattern = (mtd->writesize > 512) ?
&largepage_memorybased : &smallpage_memorybased;
- /* Build bad block table */
- return nand_scan_bbt(mtd, this->badblock_pattern);
+}
I'd rather scan_bbt not be abused for this -- we need to fix the NAND probe code so that drivers can do things between nand_scan() and nand_scan_tail().
-Scott

Scott, thanks for your feedback. I can easily fix most of the issues.
The one question I have is if this can go in only supporting 5121 rev2. If I need to add rev1 support it will take more time than I have right now.
Thanks John
Scott Wood wrote:
John Rigby wrote:
ADS5121 rev4 / MPC5121e rev2 only
What is unique about that revision that it cannot share a driver?
They could but it would be ugly.
It certainly shouldn't be board-specific...
I agree, the config belongs in the board config file and the chip select belongs in a board file.
This controller treats 2K pages as 4 512 byte pages and the hw ecc is over the combined 512 byte main area and the first 7 bytes of the spare area.
The hw ecc is stored in the last 9 bytes of the spare area.
This all means the the spare area can not be written separately from the main. This means unmodified JFFS2 will not work.
Sigh... Smack the hardware people for me.
Signed-off-by: John Rigby jrigby@freescale.com
board/ads5121/ads5121.c | 1 + drivers/mtd/nand/Makefile | 1 + drivers/mtd/nand/mpc5121rev2_nand.c | 1122 +++++++++++++++++++++++++++++++++++
This filename is very specific, especially since the i.MX NAND controller looks very similar. How about fsl_nfc_nand.c?
Ok.
diff --git a/drivers/mtd/nand/mpc5121rev2_nand.c b/drivers/mtd/nand/mpc5121rev2_nand.c new file mode 100644 index 0000000..88555ab --- /dev/null +++ b/drivers/mtd/nand/mpc5121rev2_nand.c @@ -0,0 +1,1122 @@ +/*
- Copyright 2004-2008 Freescale Semiconductor, Inc. All Rights Reserved.
- Based on drivers/mtd/nand/mpc5121_nand.c
- which was forked from drivers/mtd/nand/mxc_nd.c
Forking's bad, mmkay?
Yes, I'm guilty. The original was pretty ugly.
+/*
- 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,
- },
- .oobavail = 5,
- .oobfree = {
{0, 5}
- },
+};
Looks like you also have a free byte at offset 6.
Good catch.
Leave out oobavail, it will be calculated by generic code.
Ok.
+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,
- },
- .oobavail = 26,
- .oobfree = {
{0, 5},
{16, 7},
{32, 7},
{48, 7},
- },
+};
Byte zero is not free (it's used for bad-block markers), and byte one should be reserved for this as well. Bytes 5 and 6 are free.
Ok.
+static struct nand_ecclayout nand_hw_eccoob_4k = {
- .eccbytes = 64, /* actually 72 but only room for 64 */
Let's fix that, then.
This is defined in generic mtd code that has exposure to userland.
include/mtd/mtd-abi.h: /* * ECC layout control structure. Exported to userspace for * diagnosis and to allow creation of raw images */ struct nand_ecclayout { uint32_t eccbytes; uint32_t eccpos[64]; uint32_t oobavail; struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES]; };
+/*
- 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, size;
- count = mtd->writesize >> 9;
- size = (ooblen / count >> 1) << 1;
If you want to round down to the nearest even number, use & ~1 (why would it ever be odd?). If not, what's going on?
I'll clean this up. This is left over from the i.MX version where io access's have to be word at a time.
- for (i = 0; i < count - 1; i++) {
memcpy_fromio(pbuf, SPARE_AREA(i), size);
pbuf += size;
len -= size;
- }
Shouldn't you check to make sure that len doesn't go negative
yes
+/*!
- This function polls the NFC to wait for the basic operation to complete by
- checking the INT bit of config2 register.
- @maxRetries number of retry attempts (separated by 1 us)
- */
noJavaCase, please.
Oops, missed one.
+/*
- Function to correct the detected errors. This NFC corrects all the errors
- detected. So this function is not required.
- */
+static int mpc5121_nand_correct_data(struct mtd_info *mtd, u_char *dat,
u_char *read_ecc, u_char *calc_ecc)
+{
- panic("Shouldn't be called here: %d\n", __LINE__);
- return 0; /* FIXME */
+}
+/*
- Function to calculate the ECC for the data to be stored in the Nand device.
- This NFC has a hardware RS(511,503) ECC engine together with the RS ECC
- CONTROL blocks are responsible for detection and correction of up to
- 4 symbols of 9 bits each in 528 byte page.
- So this function is not required.
- */
+static int mpc5121_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
u_char *ecc_code)
+{
- panic("Shouldn't be called here %d \n", __LINE__);
- return 0; /* FIXME */
+}
Just leave these function pointers NULL, since you replace read_page and write_page.
ok
+static u_char mpc5121_nand_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 = in_8(area_buf + priv->col_addr);
- priv->col_addr++;
- return rv;
+}
You appear to support using read_byte on the spare area with READOOB, but not if the buffer had merely advanced past the main area. Not sure that it matters here, though.
ok
+/*!
- 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 mpc5121_nand_read_byte16(struct mtd_info *mtd) +{
- /* Check for status request */
- if (priv->status_req)
return (get_dev_status() & 0xff);
- return mpc5121_nand_read_word(mtd) & 0xff;
+}
read_byte should never be called with 16-bit NAND.
This is the replacement for nand_read_byte16 in nand_base.c. /** * nand_read_byte16 - [DEFAULT] read one byte endianess aware from the chip * @mtd: MTD device structure * * Default read function for 16bit buswith with * endianess conversion */ static uint8_t nand_read_byte16(struct mtd_info *mtd) { struct nand_chip *chip = mtd->priv; return (uint8_t) cpu_to_le16(readw(chip->IO_ADDR_R)); }
+/*!
- 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 mpc5121_nand_write_buf(struct mtd_info *mtd,
const u_char *buf, int len)
+{
- printf("re-work may be needed?\n");
Answer this before we apply the patch. :-)
Perhaps I can just get rid of this whole routine?
- if (page_addr != -1)
do {
send_addr((page_addr & 0xff));
page_mask >>= 8;
page_addr >>= 8;
} while (page_mask != 0);
+}
Braces around multi-line if-bodies.
ok
+/*
- 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);
- mpc5121_nand_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);
If you put braces around one half of the if, put it around the other.
ok
+static int mpc5121_nand_wait(struct mtd_info *mtd, struct nand_chip *chip) +{
- return (int)(get_dev_status());
+}
Unnecessary cast.
ok
+static int mpc5121_nand_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 mpc5121_nand_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);
- mpc5121_nand_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 = mpc5121_nand_wait(mtd, chip);
- if (status & NAND_STATUS_FAIL)
return -1;
- return 0;
+}
Why override these rather than let them go through the command function?
Not sure, I think it is so we can call the copy to/from spare routine.
+static struct nand_bbt_descr smallpage_memorybased = {
- .options = NAND_BBT_SCAN2NDPAGE,
- .offs = 5,
- .len = 1,
- .pattern = scan_ff_pattern
+};
This is the default.
ok
+static struct nand_bbt_descr largepage_memorybased = {
- .options = 0,
- .offs = 5,
- .len = 2,
- .pattern = scan_ff_pattern
+};
This isn't normal -- why are you starting it at offset 5?
will fix
+static int mpc5121_nand_scan_bbt(struct mtd_info *mtd) +{
- struct nand_chip *this = mtd->priv;
- if (IS_2K_PAGE_NAND)
this->ecc.layout = &nand_hw_eccoob_2k;
- else if (IS_4K_PAGE_NAND)
if (priv->sparesize == 128)
this->ecc.layout = &nand_hw_eccoob_4k;
else
this->ecc.layout = &nand_hw_eccoob_4k_218_spare;
- else
this->ecc.layout = &nand_hw_eccoob_512;
- /* propagate ecc.layout to mtd_info */
- mtd->ecclayout = this->ecc.layout;
+#if 0
- /* jffs2 should not write oob */
- mtd->flags &= ~MTD_OOB_WRITEABLE;
+#endif
Should this be set, or not? No dead code.
This is left over from the linux driver which has a patch that makes JFFS2 not write to the OOB area.
- /* use flash based bbt */
- this->bbt_td = &bbt_main_descr;
- this->bbt_md = &bbt_mirror_descr;
- /* update flash based bbt */
- this->options |= NAND_USE_FLASH_BBT;
- if (!this->badblock_pattern)
this->badblock_pattern = (mtd->writesize > 512) ?
&largepage_memorybased : &smallpage_memorybased;
- /* Build bad block table */
- return nand_scan_bbt(mtd, this->badblock_pattern);
+}
I'd rather scan_bbt not be abused for this -- we need to fix the NAND probe code so that drivers can do things between nand_scan() and nand_scan_tail().
And until then?
-Scott

Dear John,
In message 4908F3D0.6070608@freescale.com you wrote:
The one question I have is if this can go in only supporting 5121 rev2. If I need to add rev1 support it will take more time than I have right now.
I think it is perfectly OK to support only Rev. 2 (and later) of the chip. Rev. 1 is not really in production use anywhere, and the few customers who have early eval bords are probably better off to update theire hardware anyway.
Best regards,
Wolfgang Denk

On Wed, Oct 29, 2008 at 05:37:52PM -0600, John Rigby wrote:
Scott, thanks for your feedback. I can easily fix most of the issues.
The one question I have is if this can go in only supporting 5121 rev2. If I need to add rev1 support it will take more time than I have right now.
If rev1 is as dead as Wolfgang says, then I'm fine with leaving it out -- but that fact should be reflected in a comment, rather than the name of the driver. After all, this driver should support rev3 if there is one, right? :-)
+/*
- Copyright 2004-2008 Freescale Semiconductor, Inc. All Rights Reserved.
- Based on drivers/mtd/nand/mpc5121_nand.c
- which was forked from drivers/mtd/nand/mxc_nd.c
Forking's bad, mmkay?
Yes, I'm guilty. The original was pretty ugly.
If it's anything like the i.MX driver that was posted earlier, I agree entirely. :-)
I was just hoping that we could come up with one new, cleaned-up driver that supports both.
+static struct nand_ecclayout nand_hw_eccoob_4k = {
- .eccbytes = 64, /* actually 72 but only room for 64 */
Let's fix that, then.
This is defined in generic mtd code that has exposure to userland.
include/mtd/mtd-abi.h: /*
- ECC layout control structure. Exported to userspace for
- diagnosis and to allow creation of raw images
*/ struct nand_ecclayout { uint32_t eccbytes; uint32_t eccpos[64]; uint32_t oobavail; struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES]; };
Grr... I guess it's OK for now, as the main purpose of eccpos with hardware ECC is to exclude segments from use by other layers.
Very short-sighted API design, though.
read_byte should never be called with 16-bit NAND.
This is the replacement for nand_read_byte16 in nand_base.c.
Right, I should have verified my assumption before asserting it. :-P
Not sure why the generic nand_read_byte16 wasn't implemented in terms of the read_word method.
+/*!
- 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 mpc5121_nand_write_buf(struct mtd_info *mtd,
const u_char *buf, int len)
+{
- printf("re-work may be needed?\n");
Answer this before we apply the patch. :-)
Perhaps I can just get rid of this whole routine?
I don't think so...
Why override these rather than let them go through the command function?
Not sure, I think it is so we can call the copy to/from spare routine.
You can do that in write_buf/read_buf/etc.
I'd rather scan_bbt not be abused for this -- we need to fix the NAND probe code so that drivers can do things between nand_scan() and nand_scan_tail().
And until then?
It's OK for now -- that was more of a note to myself to hurry up and fix the NAND probing mechanism. :-)
-Scott

Dear John Rigby,
In message 1225313050-31063-1-git-send-email-jrigby@freescale.com you wrote:
ADS5121 rev4 / MPC5121e rev2 only
Only tested with: 2K page size 8 bit device width
This controller treats 2K pages as 4 512 byte pages and the hw ecc is over the combined 512 byte main area and the first 7 bytes of the spare area.
The hw ecc is stored in the last 9 bytes of the spare area.
This all means the the spare area can not be written separately from the main. This means unmodified JFFS2 will not work.
Hm... then what exactly is this good for? If we cannot use it with the normal Linux code I see little use cases for such a driver?
Best regards,
Wolfgang Denk

Wolfgang Denk wrote:
Dear John Rigby,
In message 1225313050-31063-1-git-send-email-jrigby@freescale.com you wrote:
ADS5121 rev4 / MPC5121e rev2 only
Only tested with: 2K page size 8 bit device width
This controller treats 2K pages as 4 512 byte pages and the hw ecc is over the combined 512 byte main area and the first 7 bytes of the spare area.
The hw ecc is stored in the last 9 bytes of the spare area.
This all means the the spare area can not be written separately from the main. This means unmodified JFFS2 will not work.
Hm... then what exactly is this good for? If we cannot use it with the normal Linux code I see little use cases for such a driver?
We have gone over this before offline. It works great for UBIFS. It also works with JFFS2 if you teach JFFS2 to leave the OOB area alone, though there have been reports that there are still issues.
My 5121 linux tree has the two patches necessary for JFFS2 to work, but I would recommend using UBIFS.
It is useful in u-boot because you may want to use u-boot to write a UBIFS image to NAND.
Best regards,
Wolfgang Denk
participants (3)
-
John Rigby
-
Scott Wood
-
Wolfgang Denk