X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=drivers%2Fmtd%2Fnand%2Fmxc_nand.c;h=f12b07e7adc720e9537be24e18d82bd22993b0cf;hb=0abdd9d01ac6ca58d8c5765bdaf4283949fdcd76;hp=9633858a7d518bbb86e9c2507c50ee1bd2b78f30;hpb=995a4b1d83a08223c82c1e15778b02e85e5bba51;p=u-boot diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index 9633858a7d..f12b07e7ad 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -3,190 +3,35 @@ * Copyright 2008 Sascha Hauer, kernel@pengutronix.de * Copyright 2009 Ilya Yanok, * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. + * SPDX-License-Identifier: GPL-2.0+ */ #include #include #include #include -#if defined(CONFIG_MX27) || defined(CONFIG_MX25) +#if defined(CONFIG_MX25) || defined(CONFIG_MX27) || defined(CONFIG_MX35) || \ + defined(CONFIG_MX51) || defined(CONFIG_MX53) #include #endif +#include "mxc_nand.h" #define DRIVER_NAME "mxc_nand" -/* - * TODO: Use same register defs here as nand_spl mxc nand driver. - */ -/* - * Register map and bit definitions for the Freescale NAND Flash Controller - * present in various i.MX devices. - * - * MX31 and MX27 have version 1 which has - * 4 512 byte main buffers and - * 4 16 byte spare buffers - * to support up to 2K byte pagesize nand. - * Reading or writing a 2K page requires 4 FDI/FDO cycles. - * - * MX25 has version 1.1 which has - * 8 512 byte main buffers and - * 8 64 byte spare buffers - * to support up to 4K byte pagesize nand. - * Reading or writing a 2K or 4K page requires only 1 FDI/FDO cycle. - * Also some of registers are moved and/or changed meaning as seen below. - */ -#if defined(CONFIG_MX31) || defined(CONFIG_MX27) -#define MXC_NFC_V1 -#elif defined(CONFIG_MX25) -#define MXC_NFC_V1_1 -#else -#warning "MXC NFC version not defined" -#endif - -#if defined(MXC_NFC_V1) -#define NAND_MXC_NR_BUFS 4 -#define NAND_MXC_SPARE_BUF_SIZE 16 -#define NAND_MXC_REG_OFFSET 0xe00 -#define is_mxc_nfc_11() 0 -#elif defined(MXC_NFC_V1_1) -#define NAND_MXC_NR_BUFS 8 -#define NAND_MXC_SPARE_BUF_SIZE 64 -#define NAND_MXC_REG_OFFSET 0x1e00 -#define is_mxc_nfc_11() 1 -#else -#error "define CONFIG_NAND_MXC_VXXX to use mtd mxc nand driver" -#endif -struct nfc_regs { - uint8_t main_area[NAND_MXC_NR_BUFS][0x200]; - uint8_t spare_area[NAND_MXC_NR_BUFS][NAND_MXC_SPARE_BUF_SIZE]; - /* - * reserved size is offset of nfc registers - * minus total main and spare sizes - */ - uint8_t reserved1[NAND_MXC_REG_OFFSET - - NAND_MXC_NR_BUFS * (512 + NAND_MXC_SPARE_BUF_SIZE)]; -#if defined(MXC_NFC_V1) - uint16_t nfc_buf_size; - uint16_t reserved2; - uint16_t nfc_buf_addr; - uint16_t nfc_flash_addr; - uint16_t nfc_flash_cmd; - uint16_t nfc_config; - uint16_t nfc_ecc_status_result; - uint16_t nfc_rsltmain_area; - uint16_t nfc_rsltspare_area; - uint16_t nfc_wrprot; - uint16_t nfc_unlockstart_blkaddr; - uint16_t nfc_unlockend_blkaddr; - uint16_t nfc_nf_wrprst; - uint16_t nfc_config1; - uint16_t nfc_config2; -#elif defined(MXC_NFC_V1_1) - uint16_t reserved2[2]; - uint16_t nfc_buf_addr; - uint16_t nfc_flash_addr; - uint16_t nfc_flash_cmd; - uint16_t nfc_config; - uint16_t nfc_ecc_status_result; - uint16_t nfc_ecc_status_result2; - uint16_t nfc_spare_area_size; - uint16_t nfc_wrprot; - uint16_t reserved3[2]; - uint16_t nfc_nf_wrprst; - uint16_t nfc_config1; - uint16_t nfc_config2; - uint16_t reserved4; - uint16_t nfc_unlockstart_blkaddr; - uint16_t nfc_unlockend_blkaddr; - uint16_t nfc_unlockstart_blkaddr1; - uint16_t nfc_unlockend_blkaddr1; - uint16_t nfc_unlockstart_blkaddr2; - uint16_t nfc_unlockend_blkaddr2; - uint16_t nfc_unlockstart_blkaddr3; - uint16_t nfc_unlockend_blkaddr3; -#endif -}; - -/* - * Set INT to 0, FCMD to 1, rest to 0 in NFC_CONFIG2 Register - * for Command operation - */ -#define NFC_CMD 0x1 - -/* - * Set INT to 0, FADD to 1, rest to 0 in NFC_CONFIG2 Register - * for Address operation - */ -#define NFC_ADDR 0x2 - -/* - * Set INT to 0, FDI to 1, rest to 0 in NFC_CONFIG2 Register - * for Input operation - */ -#define NFC_INPUT 0x4 - -/* - * Set INT to 0, FDO to 001, rest to 0 in NFC_CONFIG2 Register - * for Data Output operation - */ -#define NFC_OUTPUT 0x8 - -/* - * Set INT to 0, FD0 to 010, rest to 0 in NFC_CONFIG2 Register - * for Read ID operation - */ -#define NFC_ID 0x10 - -/* - * Set INT to 0, FDO to 100, rest to 0 in NFC_CONFIG2 Register - * for Read Status operation - */ -#define NFC_STATUS 0x20 - -/* - * Set INT to 1, rest to 0 in NFC_CONFIG2 Register for Read - * Status operation - */ -#define NFC_INT 0x8000 +struct mxc_nand_host { + struct mtd_info mtd; + struct nand_chip *nand; -#ifdef MXC_NFC_V1_1 -#define NFC_4_8N_ECC (1 << 0) -#else -#define NFC_4_8N_ECC 0 + struct mxc_nand_regs __iomem *regs; +#ifdef MXC_NFC_V3_2 + struct mxc_nand_ip_regs __iomem *ip_regs; #endif -#define NFC_SP_EN (1 << 2) -#define NFC_ECC_EN (1 << 3) -#define NFC_BIG (1 << 5) -#define NFC_RST (1 << 6) -#define NFC_CE (1 << 7) -#define NFC_ONE_CYCLE (1 << 8) - -typedef enum {false, true} bool; - -struct mxc_nand_host { - struct mtd_info mtd; - struct nand_chip *nand; - - struct nfc_regs __iomem *regs; - int spare_only; - int status_request; - int pagesize_2k; - int clk_act; - uint16_t col_addr; - unsigned int page_addr; + int spare_only; + int status_request; + int pagesize_2k; + int clk_act; + uint16_t col_addr; + unsigned int page_addr; }; static struct mxc_nand_host mxc_host; @@ -222,7 +67,7 @@ static struct nand_ecclayout nand_hw_eccoob2k = { .oobfree = { {2, 4}, {11, 11}, {27, 11}, {43, 11}, {59, 5} }, }; #endif -#elif defined(MXC_NFC_V1_1) +#elif defined(MXC_NFC_V2_1) || defined(MXC_NFC_V3_2) #ifndef CONFIG_SYS_NAND_LARGEPAGE static struct nand_ecclayout nand_hw_eccoob = { .eccbytes = 9, @@ -243,46 +88,14 @@ static struct nand_ecclayout nand_hw_eccoob2k = { #endif #endif -#ifdef CONFIG_MX27 static int is_16bit_nand(void) { - struct system_control_regs *sc_regs = - (struct system_control_regs *)IMX_SYSTEM_CTL_BASE; - - if (readl(&sc_regs->fmcr) & NF_16BIT_SEL) - return 1; - else - return 0; -} -#elif defined(CONFIG_MX31) -static int is_16bit_nand(void) -{ - struct clock_control_regs *sc_regs = - (struct clock_control_regs *)CCM_BASE; - - if (readl(&sc_regs->rcsr) & CCM_RCSR_NF16B) - return 1; - else - return 0; -} -#elif defined(CONFIG_MX25) -static int is_16bit_nand(void) -{ - struct ccm_regs *ccm = - (struct ccm_regs *)IMX_CCM_BASE; - - if (readl(&ccm->rcsr) & CCM_RCSR_NF_16BIT_SEL) - return 1; - else - return 0; -} +#if defined(CONFIG_SYS_NAND_BUSWIDTH_16BIT) + return 1; #else -#warning "8/16 bit NAND autodetection not supported" -static int is_16bit_nand(void) -{ return 0; -} #endif +} static uint32_t *mxc_nand_memcpy32(uint32_t *dest, uint32_t *source, size_t size) { @@ -296,7 +109,7 @@ static uint32_t *mxc_nand_memcpy32(uint32_t *dest, uint32_t *source, size_t size /* * This function polls the NANDFC to wait for the basic operation to - * complete by checking the INT bit of config2 register. + * complete by checking the INT bit. */ static void wait_op_done(struct mxc_nand_host *host, int max_retries, uint16_t param) @@ -304,10 +117,17 @@ static void wait_op_done(struct mxc_nand_host *host, int max_retries, uint32_t tmp; while (max_retries-- > 0) { - if (readw(&host->regs->nfc_config2) & NFC_INT) { - tmp = readw(&host->regs->nfc_config2); - tmp &= ~NFC_INT; - writew(tmp, &host->regs->nfc_config2); +#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1) + tmp = readnfc(&host->regs->config2); + if (tmp & NFC_V1_V2_CONFIG2_INT) { + tmp &= ~NFC_V1_V2_CONFIG2_INT; + writenfc(tmp, &host->regs->config2); +#elif defined(MXC_NFC_V3_2) + tmp = readnfc(&host->ip_regs->ipc); + if (tmp & NFC_V3_IPC_INT) { + tmp &= ~NFC_V3_IPC_INT; + writenfc(tmp, &host->ip_regs->ipc); +#endif break; } udelay(1); @@ -326,8 +146,8 @@ static void send_cmd(struct mxc_nand_host *host, uint16_t cmd) { MTDDEBUG(MTD_DEBUG_LEVEL3, "send_cmd(host, 0x%x)\n", cmd); - writew(cmd, &host->regs->nfc_flash_cmd); - writew(NFC_CMD, &host->regs->nfc_config2); + writenfc(cmd, &host->regs->flash_cmd); + writenfc(NFC_CMD, &host->regs->operation); /* Wait for operation to complete */ wait_op_done(host, TROP_US_DELAY, cmd); @@ -342,15 +162,15 @@ static void send_addr(struct mxc_nand_host *host, uint16_t addr) { MTDDEBUG(MTD_DEBUG_LEVEL3, "send_addr(host, 0x%x)\n", addr); - writew(addr, &host->regs->nfc_flash_addr); - writew(NFC_ADDR, &host->regs->nfc_config2); + writenfc(addr, &host->regs->flash_addr); + writenfc(NFC_ADDR, &host->regs->operation); /* Wait for operation to complete */ wait_op_done(host, TROP_US_DELAY, addr); } /* - * This function requests the NANDFC to initate the transfer + * This function requests the NANDFC to initiate the transfer * of data currently in the NANDFC RAM buffer to the NAND device. */ static void send_prog_page(struct mxc_nand_host *host, uint8_t buf_id, @@ -359,7 +179,7 @@ static void send_prog_page(struct mxc_nand_host *host, uint8_t buf_id, if (spare_only) MTDDEBUG(MTD_DEBUG_LEVEL1, "send_prog_page (%d)\n", spare_only); - if (is_mxc_nfc_11()) { + if (is_mxc_nfc_21() || is_mxc_nfc_32()) { int i; /* * The controller copies the 64 bytes of spare data from @@ -375,26 +195,33 @@ static void send_prog_page(struct mxc_nand_host *host, uint8_t buf_id, } } - writew(buf_id, &host->regs->nfc_buf_addr); +#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1) + writenfc(buf_id, &host->regs->buf_addr); +#elif defined(MXC_NFC_V3_2) + uint32_t tmp = readnfc(&host->regs->config1); + tmp &= ~NFC_V3_CONFIG1_RBA_MASK; + tmp |= NFC_V3_CONFIG1_RBA(buf_id); + writenfc(tmp, &host->regs->config1); +#endif /* Configure spare or page+spare access */ if (!host->pagesize_2k) { - uint16_t config1 = readw(&host->regs->nfc_config1); + uint32_t config1 = readnfc(&host->regs->config1); if (spare_only) - config1 |= NFC_SP_EN; + config1 |= NFC_CONFIG1_SP_EN; else - config1 &= ~(NFC_SP_EN); - writew(config1, &host->regs->nfc_config1); + config1 &= ~NFC_CONFIG1_SP_EN; + writenfc(config1, &host->regs->config1); } - writew(NFC_INPUT, &host->regs->nfc_config2); + writenfc(NFC_INPUT, &host->regs->operation); /* Wait for operation to complete */ wait_op_done(host, TROP_US_DELAY, spare_only); } /* - * Requests NANDFC to initated the transfer of data from the + * Requests NANDFC to initiate the transfer of data from the * NAND device into in the NANDFC ram buffer. */ static void send_read_page(struct mxc_nand_host *host, uint8_t buf_id, @@ -402,24 +229,31 @@ static void send_read_page(struct mxc_nand_host *host, uint8_t buf_id, { MTDDEBUG(MTD_DEBUG_LEVEL3, "send_read_page (%d)\n", spare_only); - writew(buf_id, &host->regs->nfc_buf_addr); +#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1) + writenfc(buf_id, &host->regs->buf_addr); +#elif defined(MXC_NFC_V3_2) + uint32_t tmp = readnfc(&host->regs->config1); + tmp &= ~NFC_V3_CONFIG1_RBA_MASK; + tmp |= NFC_V3_CONFIG1_RBA(buf_id); + writenfc(tmp, &host->regs->config1); +#endif /* Configure spare or page+spare access */ if (!host->pagesize_2k) { - uint32_t config1 = readw(&host->regs->nfc_config1); + uint32_t config1 = readnfc(&host->regs->config1); if (spare_only) - config1 |= NFC_SP_EN; + config1 |= NFC_CONFIG1_SP_EN; else - config1 &= ~NFC_SP_EN; - writew(config1, &host->regs->nfc_config1); + config1 &= ~NFC_CONFIG1_SP_EN; + writenfc(config1, &host->regs->config1); } - writew(NFC_OUTPUT, &host->regs->nfc_config2); + writenfc(NFC_OUTPUT, &host->regs->operation); /* Wait for operation to complete */ wait_op_done(host, TROP_US_DELAY, spare_only); - if (is_mxc_nfc_11()) { + if (is_mxc_nfc_21() || is_mxc_nfc_32()) { int i; /* @@ -439,17 +273,23 @@ static void send_read_page(struct mxc_nand_host *host, uint8_t buf_id, /* Request the NANDFC to perform a read of the NAND device ID. */ static void send_read_id(struct mxc_nand_host *host) { - uint16_t tmp; + uint32_t tmp; +#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1) /* NANDFC buffer 0 is used for device ID output */ - writew(0x0, &host->regs->nfc_buf_addr); + writenfc(0x0, &host->regs->buf_addr); +#elif defined(MXC_NFC_V3_2) + tmp = readnfc(&host->regs->config1); + tmp &= ~NFC_V3_CONFIG1_RBA_MASK; + writenfc(tmp, &host->regs->config1); +#endif /* Read ID into main buffer */ - tmp = readw(&host->regs->nfc_config1); - tmp &= ~NFC_SP_EN; - writew(tmp, &host->regs->nfc_config1); + tmp = readnfc(&host->regs->config1); + tmp &= ~NFC_CONFIG1_SP_EN; + writenfc(tmp, &host->regs->config1); - writew(NFC_ID, &host->regs->nfc_config2); + writenfc(NFC_ID, &host->regs->operation); /* Wait for operation to complete */ wait_op_done(host, TROP_US_DELAY, 0); @@ -461,32 +301,40 @@ static void send_read_id(struct mxc_nand_host *host) */ static uint16_t get_dev_status(struct mxc_nand_host *host) { +#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1) void __iomem *main_buf = host->regs->main_area[1]; uint32_t store; - uint16_t ret, tmp; +#endif + uint32_t ret, tmp; /* Issue status request to NAND device */ +#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1) /* store the main area1 first word, later do recovery */ store = readl(main_buf); /* NANDFC buffer 1 is used for device status */ - writew(1, &host->regs->nfc_buf_addr); + writenfc(1, &host->regs->buf_addr); +#endif /* Read status into main buffer */ - tmp = readw(&host->regs->nfc_config1); - tmp &= ~NFC_SP_EN; - writew(tmp, &host->regs->nfc_config1); + tmp = readnfc(&host->regs->config1); + tmp &= ~NFC_CONFIG1_SP_EN; + writenfc(tmp, &host->regs->config1); - writew(NFC_STATUS, &host->regs->nfc_config2); + writenfc(NFC_STATUS, &host->regs->operation); /* Wait for operation to complete */ wait_op_done(host, TROP_US_DELAY, 0); +#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1) /* * Status is placed in first word of main buffer * get status, then recovery area 1 data */ ret = readw(main_buf); writel(store, main_buf); +#elif defined(MXC_NFC_V3_2) + ret = readnfc(&host->regs->config1) >> 16; +#endif return ret; } @@ -501,32 +349,42 @@ static int mxc_nand_dev_ready(struct mtd_info *mtd) return 1; } -#ifdef CONFIG_MXC_NAND_HWECC -static void mxc_nand_enable_hwecc(struct mtd_info *mtd, int mode) -{ - /* - * If HW ECC is enabled, we turn it on during init. There is - * no need to enable again here. - */ -} - -#ifdef MXC_NFC_V1_1 static void _mxc_nand_enable_hwecc(struct mtd_info *mtd, int on) { struct nand_chip *nand_chip = mtd->priv; struct mxc_nand_host *host = nand_chip->priv; - uint16_t tmp = readw(&host->regs->nfc_config1); +#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1) + uint16_t tmp = readnfc(&host->regs->config1); if (on) - tmp |= NFC_ECC_EN; + tmp |= NFC_V1_V2_CONFIG1_ECC_EN; else - tmp &= ~NFC_ECC_EN; - writew(tmp, &host->regs->nfc_config1); + tmp &= ~NFC_V1_V2_CONFIG1_ECC_EN; + writenfc(tmp, &host->regs->config1); +#elif defined(MXC_NFC_V3_2) + uint32_t tmp = readnfc(&host->ip_regs->config2); + + if (on) + tmp |= NFC_V3_CONFIG2_ECC_EN; + else + tmp &= ~NFC_V3_CONFIG2_ECC_EN; + writenfc(tmp, &host->ip_regs->config2); +#endif } +#ifdef CONFIG_MXC_NAND_HWECC +static void mxc_nand_enable_hwecc(struct mtd_info *mtd, int mode) +{ + /* + * If HW ECC is enabled, we turn it on during init. There is + * no need to enable again here. + */ +} + +#if defined(MXC_NFC_V2_1) || defined(MXC_NFC_V3_2) static int mxc_nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip, - int page, int sndcmd) + int page) { struct mxc_nand_host *host = chip->priv; uint8_t *buf = chip->oob_poi; @@ -537,7 +395,7 @@ static int mxc_nand_read_oob_syndrome(struct mtd_info *mtd, MTDDEBUG(MTD_DEBUG_LEVEL0, "%s: Reading OOB area of page %u to oob %p\n", - __FUNCTION__, host->page_addr, buf); + __func__, page, buf); chip->cmdfunc(mtd, NAND_CMD_READOOB, mtd->writesize, page); for (i = 0; i < chip->ecc.steps; i++) { @@ -580,6 +438,7 @@ static int mxc_nand_read_oob_syndrome(struct mtd_info *mtd, static int mxc_nand_read_page_raw_syndrome(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, + int oob_required, int page) { struct mxc_nand_host *host = chip->priv; @@ -591,7 +450,7 @@ static int mxc_nand_read_page_raw_syndrome(struct mtd_info *mtd, int n; _mxc_nand_enable_hwecc(mtd, 0); - chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, host->page_addr); + chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); for (n = 0, steps = chip->ecc.steps; steps > 0; n++, steps--) { host->col_addr = n * eccsize; @@ -616,7 +475,7 @@ static int mxc_nand_read_page_raw_syndrome(struct mtd_info *mtd, size = mtd->oobsize - (oob - chip->oob_poi); if (size) chip->read_buf(mtd, oob, size); - _mxc_nand_enable_hwecc(mtd, 0); + _mxc_nand_enable_hwecc(mtd, 1); return 0; } @@ -624,6 +483,7 @@ static int mxc_nand_read_page_raw_syndrome(struct mtd_info *mtd, static int mxc_nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, + int oob_required, int page) { struct mxc_nand_host *host = chip->priv; @@ -635,9 +495,9 @@ static int mxc_nand_read_page_syndrome(struct mtd_info *mtd, uint8_t *oob = chip->oob_poi; MTDDEBUG(MTD_DEBUG_LEVEL1, "Reading page %u to buf %p oob %p\n", - host->page_addr, buf, oob); + page, buf, oob); - /* first read out the data area and the available portion of OOB */ + /* first read the data area and the available portion of OOB */ for (n = 0; eccsteps; n++, eccsteps--, p += eccsize) { int stat; @@ -673,7 +533,7 @@ static int mxc_nand_read_page_syndrome(struct mtd_info *mtd, /* Then switch ECC off and read the OOB area to get the ECC code */ _mxc_nand_enable_hwecc(mtd, 0); - chip->cmdfunc(mtd, NAND_CMD_READOOB, mtd->writesize, host->page_addr); + chip->cmdfunc(mtd, NAND_CMD_READOOB, mtd->writesize, page); eccsteps = chip->ecc.steps; oob = chip->oob_poi + chip->ecc.prepad; for (n = 0; eccsteps; n++, eccsteps--, p += eccsize) { @@ -713,9 +573,10 @@ static int mxc_nand_write_oob_syndrome(struct mtd_info *mtd, return status & NAND_STATUS_FAIL ? -EIO : 0; } -static void mxc_nand_write_page_raw_syndrome(struct mtd_info *mtd, +static int mxc_nand_write_page_raw_syndrome(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf) + const uint8_t *buf, + int oob_required) { struct mxc_nand_host *host = chip->priv; int eccsize = chip->ecc.size; @@ -749,11 +610,13 @@ static void mxc_nand_write_page_raw_syndrome(struct mtd_info *mtd, size = mtd->oobsize - (oob - chip->oob_poi); if (size) chip->write_buf(mtd, oob, size); + return 0; } -static void mxc_nand_write_page_syndrome(struct mtd_info *mtd, +static int mxc_nand_write_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf) + const uint8_t *buf, + int oob_required) { struct mxc_nand_host *host = chip->priv; int i, n, eccsize = chip->ecc.size; @@ -792,6 +655,7 @@ static void mxc_nand_write_page_syndrome(struct mtd_info *mtd, i = mtd->oobsize - (oob - chip->oob_poi); if (i) chip->write_buf(mtd, oob, i); + return 0; } static int mxc_nand_correct_data(struct mtd_info *mtd, u_char *dat, @@ -799,7 +663,7 @@ static int mxc_nand_correct_data(struct mtd_info *mtd, u_char *dat, { struct nand_chip *nand_chip = mtd->priv; struct mxc_nand_host *host = nand_chip->priv; - uint16_t ecc_status = readw(&host->regs->nfc_ecc_status_result); + uint32_t ecc_status = readl(&host->regs->ecc_status_result); int subpages = mtd->writesize / nand_chip->subpagesize; int pg2blk_shift = nand_chip->phys_erase_shift - nand_chip->page_shift; @@ -832,7 +696,6 @@ static int mxc_nand_correct_data(struct mtd_info *mtd, u_char *dat, #define mxc_nand_write_page_syndrome NULL #define mxc_nand_write_page_raw_syndrome NULL #define mxc_nand_write_oob_syndrome NULL -#define mxc_nfc_11_nand_correct_data NULL static int mxc_nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc) @@ -845,7 +708,7 @@ static int mxc_nand_correct_data(struct mtd_info *mtd, u_char *dat, * additional correction. 2-Bit errors cannot be corrected by * HW ECC, so we need to return failure */ - uint16_t ecc_status = readw(&host->regs->nfc_ecc_status_result); + uint16_t ecc_status = readnfc(&host->regs->ecc_status_result); if (((ecc_status & 0x3) == 2) || ((ecc_status >> 2) == 2)) { MTDDEBUG(MTD_DEBUG_LEVEL0, @@ -857,8 +720,6 @@ static int mxc_nand_correct_data(struct mtd_info *mtd, u_char *dat, } #endif - - static int mxc_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code) { @@ -1088,30 +949,6 @@ static void mxc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) host->col_addr = col; } -/* - * Used by the upper layer to verify the data in NAND Flash - * with the data in the buf. - */ -static int mxc_nand_verify_buf(struct mtd_info *mtd, - const u_char *buf, int len) -{ - u_char tmp[256]; - uint bsize; - - while (len) { - bsize = min(len, 256); - mxc_nand_read_buf(mtd, tmp, bsize); - - if (memcmp(buf, tmp, bsize)) - return 1; - - buf += bsize; - len -= bsize; - } - - return 0; -} - /* * This function is used by upper layer for select and * deselect of the NAND chip @@ -1181,7 +1018,7 @@ void mxc_nand_command(struct mtd_info *mtd, unsigned command, /* * before sending SEQIN command for partial write, * we need read one page out. FSL NFC does not support - * partial write. It alway send out 512+ecc+512+ecc ... + * partial write. It always sends out 512+ecc+512+ecc * for large page nand flash. But for small page nand * flash, it does support SPARE ONLY operation. */ @@ -1210,8 +1047,8 @@ void mxc_nand_command(struct mtd_info *mtd, unsigned command, case NAND_CMD_PAGEPROG: send_prog_page(host, 0, host->spare_only); - if (host->pagesize_2k && !is_mxc_nfc_11()) { - /* data in 4 areas datas */ + if (host->pagesize_2k && is_mxc_nfc_1()) { + /* data in 4 areas */ send_prog_page(host, 1, host->spare_only); send_prog_page(host, 2, host->spare_only); send_prog_page(host, 3, host->spare_only); @@ -1227,10 +1064,9 @@ void mxc_nand_command(struct mtd_info *mtd, unsigned command, if (column != -1) { /* * MXC NANDFC can only perform full page+spare or - * spare-only read/write. When the upper layers - * layers perform a read/write buf operation, - * we will used the saved column adress to index into - * the full page. + * spare-only read/write. When the upper layers perform + * a read/write buffer operation, we will use the saved + * column address to index into the full page. */ send_addr(host, 0); if (host->pagesize_2k) @@ -1261,7 +1097,7 @@ void mxc_nand_command(struct mtd_info *mtd, unsigned command, send_cmd(host, NAND_CMD_READSTART); /* read for each AREA */ send_read_page(host, 0, host->spare_only); - if (!is_mxc_nfc_11()) { + if (is_mxc_nfc_1()) { send_read_page(host, 1, host->spare_only); send_read_page(host, 2, host->spare_only); send_read_page(host, 3, host->spare_only); @@ -1287,29 +1123,45 @@ void mxc_nand_command(struct mtd_info *mtd, unsigned command, } } -#ifdef MXC_NFC_V1_1 -static void mxc_setup_config1(void) -{ - uint16_t tmp; +#ifdef CONFIG_SYS_NAND_USE_FLASH_BBT + +static u8 bbt_pattern[] = {'B', 'b', 't', '0' }; +static u8 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, +}; - tmp = readw(&host->regs->nfc_config1); - tmp |= NFC_ONE_CYCLE; - tmp |= NFC_4_8N_ECC; - writew(tmp, &host->regs->nfc_config1); - if (host->pagesize_2k) - writew(64/2, &host->regs->nfc_spare_area_size); - else - writew(16/2, &host->regs->nfc_spare_area_size); -} -#else -#define mxc_setup_config1() #endif int board_nand_init(struct nand_chip *this) { struct mtd_info *mtd; - uint16_t tmp; - int err = 0; +#if defined(MXC_NFC_V2_1) || defined(MXC_NFC_V3_2) + uint32_t tmp; +#endif + +#ifdef CONFIG_SYS_NAND_USE_FLASH_BBT + this->bbt_options |= NAND_BBT_USE_FLASH; + this->bbt_td = &bbt_main_descr; + this->bbt_md = &bbt_mirror_descr; +#endif /* structures must be linked */ mtd = &host->mtd; @@ -1327,16 +1179,19 @@ int board_nand_init(struct nand_chip *this) this->read_word = mxc_nand_read_word; this->write_buf = mxc_nand_write_buf; this->read_buf = mxc_nand_read_buf; - this->verify_buf = mxc_nand_verify_buf; - host->regs = (struct nfc_regs __iomem *)CONFIG_MXC_NAND_REGS_BASE; + host->regs = (struct mxc_nand_regs __iomem *)CONFIG_MXC_NAND_REGS_BASE; +#ifdef MXC_NFC_V3_2 + host->ip_regs = + (struct mxc_nand_ip_regs __iomem *)CONFIG_MXC_NAND_IP_REGS_BASE; +#endif host->clk_act = 1; #ifdef CONFIG_MXC_NAND_HWECC this->ecc.calculate = mxc_nand_calculate_ecc; this->ecc.hwctl = mxc_nand_enable_hwecc; this->ecc.correct = mxc_nand_correct_data; - if (is_mxc_nfc_11()) { + if (is_mxc_nfc_21() || is_mxc_nfc_32()) { this->ecc.mode = NAND_ECC_HW_SYNDROME; this->ecc.read_page = mxc_nand_read_page_syndrome; this->ecc.read_page_raw = mxc_nand_read_page_raw_syndrome; @@ -1350,46 +1205,113 @@ int board_nand_init(struct nand_chip *this) this->ecc.mode = NAND_ECC_HW; } + if (is_mxc_nfc_1()) + this->ecc.strength = 1; + else + this->ecc.strength = 4; + host->pagesize_2k = 0; this->ecc.size = 512; - tmp = readw(&host->regs->nfc_config1); - tmp |= NFC_ECC_EN; - writew(tmp, &host->regs->nfc_config1); + _mxc_nand_enable_hwecc(mtd, 1); #else this->ecc.layout = &nand_soft_eccoob; this->ecc.mode = NAND_ECC_SOFT; - tmp = readw(&host->regs->nfc_config1); - tmp &= ~NFC_ECC_EN; - writew(tmp, &host->regs->nfc_config1); + _mxc_nand_enable_hwecc(mtd, 0); #endif /* Reset NAND */ this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); + /* NAND bus width determines access functions used by upper layer */ + if (is_16bit_nand()) + this->options |= NAND_BUSWIDTH_16; + +#ifdef CONFIG_SYS_NAND_LARGEPAGE + host->pagesize_2k = 1; + this->ecc.layout = &nand_hw_eccoob2k; +#else + host->pagesize_2k = 0; + this->ecc.layout = &nand_hw_eccoob; +#endif + +#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1) +#ifdef MXC_NFC_V2_1 + tmp = readnfc(&host->regs->config1); + tmp |= NFC_V2_CONFIG1_ONE_CYCLE; + tmp |= NFC_V2_CONFIG1_ECC_MODE_4; + writenfc(tmp, &host->regs->config1); + if (host->pagesize_2k) + writenfc(64/2, &host->regs->spare_area_size); + else + writenfc(16/2, &host->regs->spare_area_size); +#endif + /* * preset operation * Unlock the internal RAM Buffer */ - writew(0x2, &host->regs->nfc_config); + writenfc(0x2, &host->regs->config); /* Blocks to be unlocked */ - writew(0x0, &host->regs->nfc_unlockstart_blkaddr); - writew(0x4000, &host->regs->nfc_unlockend_blkaddr); + writenfc(0x0, &host->regs->unlockstart_blkaddr); + /* Originally (Freescale LTIB 2.6.21) 0x4000 was written to the + * unlockend_blkaddr, but the magic 0x4000 does not always work + * when writing more than some 32 megabytes (on 2k page nands) + * However 0xFFFF doesn't seem to have this kind + * of limitation (tried it back and forth several times). + * The linux kernel driver sets this to 0xFFFF for the v2 controller + * only, but probably this was not tested there for v1. + * The very same limitation seems to apply to this kernel driver. + * This might be NAND chip specific and the i.MX31 datasheet is + * extremely vague about the semantics of this register. + */ + writenfc(0xFFFF, &host->regs->unlockend_blkaddr); /* Unlock Block Command for given address range */ - writew(0x4, &host->regs->nfc_wrprot); + writenfc(0x4, &host->regs->wrprot); +#elif defined(MXC_NFC_V3_2) + writenfc(NFC_V3_CONFIG1_RBA(0), &host->regs->config1); + writenfc(NFC_V3_IPC_CREQ, &host->ip_regs->ipc); - /* NAND bus width determines access funtions used by upper layer */ - if (is_16bit_nand()) - this->options |= NAND_BUSWIDTH_16; + /* Unlock the internal RAM Buffer */ + writenfc(NFC_V3_WRPROT_BLS_UNLOCK | NFC_V3_WRPROT_UNLOCK, + &host->ip_regs->wrprot); -#ifdef CONFIG_SYS_NAND_LARGEPAGE - host->pagesize_2k = 1; - this->ecc.layout = &nand_hw_eccoob2k; -#else - host->pagesize_2k = 0; - this->ecc.layout = &nand_hw_eccoob; + /* Blocks to be unlocked */ + for (tmp = 0; tmp < CONFIG_SYS_NAND_MAX_CHIPS; tmp++) + writenfc(0x0 | 0xFFFF << 16, + &host->ip_regs->wrprot_unlock_blkaddr[tmp]); + + writenfc(0, &host->ip_regs->ipc); + + tmp = readnfc(&host->ip_regs->config2); + tmp &= ~(NFC_V3_CONFIG2_SPAS_MASK | NFC_V3_CONFIG2_EDC_MASK | + NFC_V3_CONFIG2_ECC_MODE_8 | NFC_V3_CONFIG2_PS_MASK); + tmp |= NFC_V3_CONFIG2_ONE_CYCLE; + + if (host->pagesize_2k) { + tmp |= NFC_V3_CONFIG2_SPAS(64/2); + tmp |= NFC_V3_CONFIG2_PS_2048; + } else { + tmp |= NFC_V3_CONFIG2_SPAS(16/2); + tmp |= NFC_V3_CONFIG2_PS_512; + } + + writenfc(tmp, &host->ip_regs->config2); + + tmp = NFC_V3_CONFIG3_NUM_OF_DEVS(0) | + NFC_V3_CONFIG3_NO_SDMA | + NFC_V3_CONFIG3_RBB_MODE | + NFC_V3_CONFIG3_SBB(6) | /* Reset default */ + NFC_V3_CONFIG3_ADD_OP(0); + + if (!(this->options & NAND_BUSWIDTH_16)) + tmp |= NFC_V3_CONFIG3_FW8; + + writenfc(tmp, &host->ip_regs->config3); + + writenfc(0, &host->ip_regs->delay_line); #endif - mxc_setup_config1(); - return err; + + return 0; }