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 <[EMAIL PROTECTED]> --- 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 */ -- 1.5.6.2.255.gbed62 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot