summaryrefslogtreecommitdiffstats
path: root/drivers/mtd/nand/nand_imx.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd/nand/nand_imx.c')
-rw-r--r--drivers/mtd/nand/nand_imx.c718
1 files changed, 469 insertions, 249 deletions
diff --git a/drivers/mtd/nand/nand_imx.c b/drivers/mtd/nand/nand_imx.c
index 63ba188789..9a15ab2c98 100644
--- a/drivers/mtd/nand/nand_imx.c
+++ b/drivers/mtd/nand/nand_imx.c
@@ -30,103 +30,107 @@
#include <asm/io.h>
#include <errno.h>
-#define DVR_VER "2.0"
-
#define nfc_is_v21() (cpu_is_mx25() || cpu_is_mx35())
#define nfc_is_v1() (cpu_is_mx31() || cpu_is_mx27() || cpu_is_mx21())
+#define nfc_is_v3_2() cpu_is_mx51()
+#define nfc_is_v3() nfc_is_v3_2()
+
+#define NFC_V1_ECC_STATUS_RESULT 0x0c
+#define NFC_V1_RSLTMAIN_AREA 0x0e
+#define NFC_V1_RSLTSPARE_AREA 0x10
+
+#define NFC_V2_ECC_STATUS_RESULT1 0x0c
+#define NFC_V2_ECC_STATUS_RESULT2 0x0e
+#define NFC_V2_SPAS 0x10
+
+#define NFC_V1_V2_BUF_SIZE 0x00
+#define NFC_V1_V2_BUF_ADDR 0x04
+#define NFC_V1_V2_FLASH_ADDR 0x06
+#define NFC_V1_V2_FLASH_CMD 0x08
+#define NFC_V1_V2_CONFIG 0x0a
+
+#define NFC_V1_V2_WRPROT 0x12
+#define NFC_V1_UNLOCKSTART_BLKADDR 0x14
+#define NFC_V1_UNLOCKEND_BLKADDR 0x16
+#define NFC_V21_UNLOCKSTART_BLKADDR 0x20
+#define NFC_V21_UNLOCKEND_BLKADDR 0x22
+#define NFC_V1_V2_NF_WRPRST 0x18
+#define NFC_V1_V2_CONFIG1 0x1a
+#define NFC_V1_V2_CONFIG2 0x1c
+
+#define NFC_V2_CONFIG1_ECC_MODE_4 (1 << 0)
+#define NFC_V1_V2_CONFIG1_SP_EN (1 << 2)
+#define NFC_V1_V2_CONFIG1_ECC_EN (1 << 3)
+#define NFC_V1_V2_CONFIG1_INT_MSK (1 << 4)
+#define NFC_V1_V2_CONFIG1_BIG (1 << 5)
+#define NFC_V1_V2_CONFIG1_RST (1 << 6)
+#define NFC_V1_V2_CONFIG1_CE (1 << 7)
+#define NFC_V1_V2_CONFIG1_ONE_CYCLE (1 << 8)
+#define NFC_V2_CONFIG1_PPB(x) (((x) & 0x3) << 9)
+#define NFC_V2_CONFIG1_FP_INT (1 << 11)
+
+#define NFC_V1_V2_CONFIG2_INT (1 << 15)
+
+#define NFC_V2_SPAS_SPARESIZE(spas) ((spas) >> 1)
/*
- * Addresses for NFC registers
- */
-#define NFC_BUF_SIZE 0xE00
-#define NFC_BUF_ADDR 0xE04
-#define NFC_FLASH_ADDR 0xE06
-#define NFC_FLASH_CMD 0xE08
-#define NFC_CONFIG 0xE0A
-#define NFC_ECC_STATUS_RESULT 0xE0C
-#define NFC_RSLTMAIN_AREA 0xE0E
-#define NFC_RSLTSPARE_AREA 0xE10
-#define NFC_SPAS 0xe10
-#define NFC_WRPROT 0xE12
-#define NFC_V1_UNLOCKSTART_BLKADDR 0xe14
-#define NFC_V1_UNLOCKEND_BLKADDR 0xe16
-#define NFC_V21_UNLOCKSTART_BLKADDR 0xe20
-#define NFC_V21_UNLOCKEND_BLKADDR 0xe22
-#define NFC_NF_WRPRST 0xE18
-#define NFC_CONFIG1 0xE1A
-#define NFC_CONFIG2 0xE1C
-
-/*
- * Addresses for NFC RAM BUFFER Main area 0
- */
-#define MAIN_AREA0 0x000
-#define MAIN_AREA1 0x200
-#define MAIN_AREA2 0x400
-#define MAIN_AREA3 0x600
-
-/*
- * Addresses for NFC SPARE BUFFER Spare area 0
- */
-#define SPARE_AREA0 0x800
-#define SPARE_AREA1 0x810
-#define SPARE_AREA2 0x820
-#define SPARE_AREA3 0x830
-
-/*
- * 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
+ * Operation modes for the NFC. Valid for v1, v2 and v3
+ * type controllers.
*/
-#define NFC_INT 0x8000
-
-#define NFC_ECC_MODE (1 << 0)
-#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_SPAS_16 8
-#define NFC_SPAS_64 32
-#define NFC_SPAS_128 64
-#define NFC_SPAS_218 109
+#define NFC_CMD (1 << 0)
+#define NFC_ADDR (1 << 1)
+#define NFC_INPUT (1 << 2)
+#define NFC_OUTPUT (1 << 3)
+#define NFC_ID (1 << 4)
+#define NFC_STATUS (1 << 5)
+
+#define NFC_V3_FLASH_CMD (host->regs_axi + 0x00)
+#define NFC_V3_FLASH_ADDR0 (host->regs_axi + 0x04)
+
+#define NFC_V3_CONFIG1 (host->regs_axi + 0x34)
+#define NFC_V3_CONFIG1_SP_EN (1 << 0)
+#define NFC_V3_CONFIG1_RBA(x) (((x) & 0x7 ) << 4)
+
+#define NFC_V3_ECC_STATUS_RESULT (host->regs_axi + 0x38)
+
+#define NFC_V3_LAUNCH (host->regs_axi + 0x40)
+
+#define NFC_V3_WRPROT (host->regs_ip + 0x0)
+#define NFC_V3_WRPROT_LOCK_TIGHT (1 << 0)
+#define NFC_V3_WRPROT_LOCK (1 << 1)
+#define NFC_V3_WRPROT_UNLOCK (1 << 2)
+#define NFC_V3_WRPROT_BLS_UNLOCK (2 << 6)
+
+#define NFC_V3_WRPROT_UNLOCK_BLK_ADD0 (host->regs_ip + 0x04)
+
+#define NFC_V3_CONFIG2 (host->regs_ip + 0x24)
+#define NFC_V3_CONFIG2_PS_512 (0 << 0)
+#define NFC_V3_CONFIG2_PS_2048 (1 << 0)
+#define NFC_V3_CONFIG2_PS_4096 (2 << 0)
+#define NFC_V3_CONFIG2_ONE_CYCLE (1 << 2)
+#define NFC_V3_CONFIG2_ECC_EN (1 << 3)
+#define NFC_V3_CONFIG2_2CMD_PHASES (1 << 4)
+#define NFC_V3_CONFIG2_NUM_ADDR_PHASE0 (1 << 5)
+#define NFC_V3_CONFIG2_ECC_MODE_8 (1 << 6)
+#define NFC_V3_CONFIG2_PPB(x) (((x) & 0x3) << 7)
+#define NFC_V3_CONFIG2_NUM_ADDR_PHASE1(x) (((x) & 0x3) << 12)
+#define NFC_V3_CONFIG2_INT_MSK (1 << 15)
+#define NFC_V3_CONFIG2_ST_CMD(x) (((x) & 0xff) << 24)
+#define NFC_V3_CONFIG2_SPAS(x) (((x) & 0xff) << 16)
+
+#define NFC_V3_CONFIG3 (host->regs_ip + 0x28)
+#define NFC_V3_CONFIG3_ADD_OP(x) (((x) & 0x3) << 0)
+#define NFC_V3_CONFIG3_FW8 (1 << 3)
+#define NFC_V3_CONFIG3_SBB(x) (((x) & 0x7) << 8)
+#define NFC_V3_CONFIG3_NUM_OF_DEVICES(x) (((x) & 0x7) << 12)
+#define NFC_V3_CONFIG3_RBB_MODE (1 << 15)
+#define NFC_V3_CONFIG3_NO_SDMA (1 << 20)
+
+#define NFC_V3_IPC (host->regs_ip + 0x2C)
+#define NFC_V3_IPC_CREQ (1 << 0)
+#define NFC_V3_IPC_INT (1 << 31)
+
+#define NFC_V3_DELAY_LINE (host->regs_ip + 0x34)
#ifdef CONFIG_NAND_IMX_BOOT
#define __nand_boot_init __bare_init
@@ -142,10 +146,11 @@ struct imx_nand_host {
void *spare0;
void *main_area0;
- void *main_area1;
void __iomem *base;
void __iomem *regs;
+ void __iomem *regs_axi;
+ void __iomem *regs_ip;
int status_request;
struct clk *clk;
@@ -153,7 +158,15 @@ struct imx_nand_host {
uint8_t *data_buf;
unsigned int buf_start;
int spare_len;
-
+ int eccsize;
+
+ void (*preset)(struct mtd_info *);
+ void (*send_cmd)(struct imx_nand_host *, uint16_t);
+ void (*send_addr)(struct imx_nand_host *, uint16_t);
+ void (*send_page)(struct imx_nand_host *, unsigned int);
+ void (*send_read_id)(struct imx_nand_host *);
+ uint16_t (*get_dev_status)(struct imx_nand_host *);
+ int (*check_int)(struct imx_nand_host *);
};
/*
@@ -215,16 +228,35 @@ static void memcpy32(void *trg, const void *src, int size)
*t++ = *s++;
}
-/*
- * This function polls the NANDFC to wait for the basic operation to complete by
- * checking the INT bit of config2 register.
- *
- * @param max_retries number of retry attempts (separated by 1 us)
- * @param param parameter for debug
- */
+static int check_int_v3(struct imx_nand_host *host)
+{
+ uint32_t tmp;
+
+ tmp = readl(NFC_V3_IPC);
+ if (!(tmp & NFC_V3_IPC_INT))
+ return 0;
+
+ tmp &= ~NFC_V3_IPC_INT;
+ writel(tmp, NFC_V3_IPC);
+
+ return 1;
+}
+
+static int check_int_v1_v2(struct imx_nand_host *host)
+{
+ uint32_t tmp;
+
+ tmp = readw(host->regs + NFC_V1_V2_CONFIG2);
+ if (!(tmp & NFC_V1_V2_CONFIG2_INT))
+ return 0;
+
+ writew(tmp & ~NFC_V1_V2_CONFIG2_INT, host->regs + NFC_V1_V2_CONFIG2);
+
+ return 1;
+}
+
static void wait_op_done(struct imx_nand_host *host)
{
- u32 tmp;
int i;
/* This is a timeout of roughly 15ms on my system. We
@@ -232,12 +264,8 @@ static void wait_op_done(struct imx_nand_host *host)
* here as we might be here from nand booting.
*/
for (i = 0; i < 100000; i++) {
- if (readw(host->regs + NFC_CONFIG2) & NFC_INT) {
- tmp = readw(host->regs + NFC_CONFIG2);
- tmp &= ~NFC_INT;
- writew(tmp, host->regs + NFC_CONFIG2);
+ if (host->check_int(host))
return;
- }
}
}
@@ -247,19 +275,31 @@ static void wait_op_done(struct imx_nand_host *host)
*
* @param cmd command for NAND Flash
*/
-static void send_cmd(struct imx_nand_host *host, u16 cmd)
+static void send_cmd_v3(struct imx_nand_host *host, uint16_t cmd)
+{
+ /* fill command */
+ writel(cmd, NFC_V3_FLASH_CMD);
+
+ /* send out command */
+ writel(NFC_CMD, NFC_V3_LAUNCH);
+
+ /* Wait for operation to complete */
+ wait_op_done(host);
+}
+
+static void send_cmd_v1_v2(struct imx_nand_host *host, u16 cmd)
{
MTD_DEBUG(MTD_DEBUG_LEVEL3, "send_cmd(host, 0x%x)\n", cmd);
- writew(cmd, host->regs + NFC_FLASH_CMD);
- writew(NFC_CMD, host->regs + NFC_CONFIG2);
+ writew(cmd, host->regs + NFC_V1_V2_FLASH_CMD);
+ writew(NFC_CMD, host->regs + NFC_V1_V2_CONFIG2);
if (cpu_is_mx21() && (cmd == NAND_CMD_RESET)) {
/* Reset completion is indicated by NFC_CONFIG2 */
/* being set to 0 */
int i;
for (i = 0; i < 100000; i++) {
- if (readw(host->regs + NFC_CONFIG2) == 0) {
+ if (readw(host->regs + NFC_V1_V2_CONFIG2) == 0) {
break;
}
}
@@ -276,12 +316,23 @@ static void send_cmd(struct imx_nand_host *host, u16 cmd)
* @param addr address to be written to NFC.
* @param islast True if this is the last address cycle for command
*/
-static void send_addr(struct imx_nand_host *host, u16 addr)
+static void send_addr_v3(struct imx_nand_host *host, uint16_t addr)
+{
+ /* fill address */
+ writel(addr, NFC_V3_FLASH_ADDR0);
+
+ /* send out address */
+ writel(NFC_ADDR, NFC_V3_LAUNCH);
+
+ wait_op_done(host);
+}
+
+static void send_addr_v1_v2(struct imx_nand_host *host, u16 addr)
{
MTD_DEBUG(MTD_DEBUG_LEVEL3, "send_addr(host, 0x%x %d)\n", addr, islast);
- writew(addr, host->regs + NFC_FLASH_ADDR);
- writew(NFC_ADDR, host->regs + NFC_CONFIG2);
+ writew(addr, host->regs + NFC_V1_V2_FLASH_ADDR);
+ writew(NFC_ADDR, host->regs + NFC_V1_V2_CONFIG2);
/* Wait for operation to complete */
wait_op_done(host);
@@ -294,7 +345,21 @@ static void send_addr(struct imx_nand_host *host, u16 addr)
* @param buf_id Specify Internal RAM Buffer number (0-3)
* @param spare_only set true if only the spare area is transferred
*/
-static void send_page(struct imx_nand_host *host,
+static void send_page_v3(struct imx_nand_host *host, unsigned int ops)
+{
+ uint32_t tmp;
+
+ tmp = readl(NFC_V3_CONFIG1);
+ tmp &= ~(7 << 4);
+ writel(tmp, NFC_V3_CONFIG1);
+
+ /* transfer data from NFC ram to nand */
+ writel(ops, NFC_V3_LAUNCH);
+
+ wait_op_done(host);
+}
+
+static void send_page_v1_v2(struct imx_nand_host *host,
unsigned int ops)
{
int bufs, i;
@@ -306,9 +371,9 @@ static void send_page(struct imx_nand_host *host,
for (i = 0; i < bufs; i++) {
/* NANDFC buffer 0 is used for page read/write */
- writew(i, host->regs + NFC_BUF_ADDR);
+ writew(i, host->regs + NFC_V1_V2_BUF_ADDR);
- writew(ops, host->regs + NFC_CONFIG2);
+ writew(ops, host->regs + NFC_V1_V2_CONFIG2);
/* Wait for operation to complete */
wait_op_done(host);
@@ -319,20 +384,24 @@ static void send_page(struct imx_nand_host *host,
* This function requests the NANDFC to perform a read of the
* NAND device ID.
*/
-static void send_read_id(struct imx_nand_host *host)
+static void send_read_id_v3(struct imx_nand_host *host)
+{
+ /* Read ID into main buffer */
+ writel(NFC_ID, NFC_V3_LAUNCH);
+
+ wait_op_done(host);
+
+ memcpy(host->data_buf, host->main_area0, 16);
+}
+
+static void send_read_id_v1_v2(struct imx_nand_host *host)
{
struct nand_chip *this = &host->nand;
- u16 tmp;
/* NANDFC buffer 0 is used for device ID output */
- writew(0x0, host->regs + NFC_BUF_ADDR);
-
- /* Read ID into main buffer */
- tmp = readw(host->regs + NFC_CONFIG1);
- tmp &= ~NFC_SP_EN;
- writew(tmp, host->regs + NFC_CONFIG1);
+ writew(0x0, host->regs + NFC_V1_V2_BUF_ADDR);
- writew(NFC_ID, host->regs + NFC_CONFIG2);
+ writew(NFC_ID, host->regs + NFC_V1_V2_CONFIG2);
/* Wait for operation to complete */
wait_op_done(host);
@@ -359,35 +428,39 @@ static void send_read_id(struct imx_nand_host *host)
*
* @return device status
*/
-static u16 get_dev_status(struct imx_nand_host *host)
+static uint16_t get_dev_status_v3(struct imx_nand_host *host)
{
- volatile u16 *mainbuf = host->main_area1;
+ writew(NFC_STATUS, NFC_V3_LAUNCH);
+ wait_op_done(host);
+
+ return readl(NFC_V3_CONFIG1) >> 16;
+}
+
+static u16 get_dev_status_v1_v2(struct imx_nand_host *host)
+{
+ void *main_buf = host->main_area0;
u32 store;
- u16 ret, tmp;
- /* Issue status request to NAND device */
+ u16 ret;
+
+ writew(0x0, host->regs + NFC_V1_V2_BUF_ADDR);
- /* store the main area1 first word, later do recovery */
- store = *((u32 *) mainbuf);
/*
- * NANDFC buffer 1 is used for device status to prevent
- * corruption of read/write buffer on status requests.
+ * The device status is stored in main_area0. To
+ * prevent corruption of the buffer save the value
+ * and restore it afterwards.
*/
- writew(1, host->regs + NFC_BUF_ADDR);
-
- /* Read status into main buffer */
- tmp = readw(host->regs + NFC_CONFIG1);
- tmp &= ~NFC_SP_EN;
- writew(tmp, host->regs + NFC_CONFIG1);
+ store = readl(main_buf);
- writew(NFC_STATUS, host->regs + NFC_CONFIG2);
+ writew(NFC_STATUS, host->regs + NFC_V1_V2_CONFIG2);
/* Wait for operation to complete */
wait_op_done(host);
/* Status is placed in first word of main buffer */
/* get status, then recovery area 1 data */
- ret = mainbuf[0];
- *((u32 *) mainbuf) = store;
+ ret = readw(main_buf);
+
+ writel(store, main_buf);
return ret;
}
@@ -416,7 +489,7 @@ static void imx_nand_enable_hwecc(struct mtd_info *mtd, int mode)
*/
}
-static int imx_nand_correct_data(struct mtd_info *mtd, u_char * dat,
+static int imx_nand_correct_data_v1(struct mtd_info *mtd, u_char * dat,
u_char * read_ecc, u_char * calc_ecc)
{
struct nand_chip *nand_chip = mtd->priv;
@@ -427,7 +500,7 @@ static int imx_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
*/
- u16 ecc_status = readw(host->regs + NFC_ECC_STATUS_RESULT);
+ u16 ecc_status = readw(host->regs + NFC_V1_ECC_STATUS_RESULT);
if (((ecc_status & 0x3) == 2) || ((ecc_status >> 2) == 2)) {
MTD_DEBUG(MTD_DEBUG_LEVEL0,
@@ -438,6 +511,43 @@ static int imx_nand_correct_data(struct mtd_info *mtd, u_char * dat,
return 0;
}
+static int imx_nand_correct_data_v2_v3(struct mtd_info *mtd, u_char *dat,
+ u_char *read_ecc, u_char *calc_ecc)
+{
+ struct nand_chip *nand_chip = mtd->priv;
+ struct imx_nand_host *host = nand_chip->priv;
+ u32 ecc_stat, err;
+ int no_subpages = 1;
+ int ret = 0;
+ u8 ecc_bit_mask, err_limit;
+
+ ecc_bit_mask = (host->eccsize == 4) ? 0x7 : 0xf;
+ err_limit = (host->eccsize == 4) ? 0x4 : 0x8;
+
+ no_subpages = mtd->writesize >> 9;
+
+ if (nfc_is_v21())
+ ecc_stat = readl(host->regs + NFC_V2_ECC_STATUS_RESULT1);
+ else
+ ecc_stat = readl(NFC_V3_ECC_STATUS_RESULT);
+
+ do {
+ err = ecc_stat & ecc_bit_mask;
+ if (err > err_limit) {
+ printk(KERN_WARNING "UnCorrectable RS-ECC Error\n");
+ return -1;
+ } else {
+ ret += err;
+ }
+ ecc_stat >>= 4;
+ } while (--no_subpages);
+
+ mtd->ecc_stats.corrected += ret;
+ pr_debug("%d Symbol Correctable RS-ECC Error\n", ret);
+
+ return ret;
+}
+
static int imx_nand_calculate_ecc(struct mtd_info *mtd, const u_char * dat,
u_char * ecc_code)
{
@@ -459,7 +569,7 @@ static u_char imx_nand_read_byte(struct mtd_info *mtd)
/* Check for status request */
if (host->status_request)
- return get_dev_status(host) & 0xFF;
+ return host->get_dev_status(host) & 0xFF;
ret = *(uint8_t *)(host->data_buf + host->buf_start);
host->buf_start++;
@@ -627,37 +737,164 @@ static void mxc_do_addr_cycle(struct mtd_info *mtd, int column, int page_addr)
* we will used the saved column adress to index into
* the full page.
*/
- send_addr(host, 0);
+ host->send_addr(host, 0);
if (host->pagesize_2k)
/* another col addr cycle for 2k page */
- send_addr(host, 0);
+ host->send_addr(host, 0);
}
/*
* Write out page address, if necessary
*/
if (page_addr != -1) {
- send_addr(host, (page_addr & 0xff)); /* paddr_0 - p_addr_7 */
+ host->send_addr(host, (page_addr & 0xff)); /* paddr_0 - p_addr_7 */
if (host->pagesize_2k) {
- send_addr(host, (page_addr >> 8) & 0xFF);
+ host->send_addr(host, (page_addr >> 8) & 0xFF);
if (mtd->size >= 0x10000000) {
- send_addr(host, (page_addr >> 16) & 0xff);
+ host->send_addr(host, (page_addr >> 16) & 0xff);
}
} else {
/* One more address cycle for higher density devices */
if (mtd->size >= 0x4000000) {
/* paddr_8 - paddr_15 */
- send_addr(host, (page_addr >> 8) & 0xff);
- send_addr(host, (page_addr >> 16) & 0xff);
+ host->send_addr(host, (page_addr >> 8) & 0xff);
+ host->send_addr(host, (page_addr >> 16) & 0xff);
} else
/* paddr_8 - paddr_15 */
- send_addr(host, (page_addr >> 8) & 0xff);
+ host->send_addr(host, (page_addr >> 8) & 0xff);
}
}
}
/*
+ * v2 and v3 type controllers can do 4bit or 8bit ecc depending
+ * on how much oob the nand chip has. For 8bit ecc we need at least
+ * 26 bytes of oob data per 512 byte block.
+ */
+static int get_eccsize(struct mtd_info *mtd)
+{
+ int oobbytes_per_512 = 0;
+
+ oobbytes_per_512 = mtd->oobsize * 512 / mtd->writesize;
+
+ if (oobbytes_per_512 < 26)
+ return 4;
+ else
+ return 8;
+}
+
+static void preset_v1_v2(struct mtd_info *mtd)
+{
+ struct nand_chip *nand_chip = mtd->priv;
+ struct imx_nand_host *host = nand_chip->priv;
+ uint16_t config1 = 0;
+
+ if (nand_chip->ecc.mode == NAND_ECC_HW)
+ config1 |= NFC_V1_V2_CONFIG1_ECC_EN;
+
+ if (nfc_is_v21())
+ config1 |= NFC_V2_CONFIG1_FP_INT;
+
+ if (nfc_is_v21() && mtd->writesize) {
+ uint16_t pages_per_block = mtd->erasesize / mtd->writesize;
+
+ host->eccsize = get_eccsize(mtd);
+ if (host->eccsize == 4)
+ config1 |= NFC_V2_CONFIG1_ECC_MODE_4;
+
+ config1 |= NFC_V2_CONFIG1_PPB(ffs(pages_per_block) - 6);
+ } else {
+ host->eccsize = 1;
+ }
+
+ writew(config1, host->regs + NFC_V1_V2_CONFIG1);
+ /* preset operation */
+
+ /* Unlock the internal RAM Buffer */
+ writew(0x2, host->regs + NFC_V1_V2_CONFIG);
+
+ /* Blocks to be unlocked */
+ if (nfc_is_v21()) {
+ writew(0x0, host->regs + NFC_V21_UNLOCKSTART_BLKADDR);
+ writew(0xffff, host->regs + NFC_V21_UNLOCKEND_BLKADDR);
+ } else if (nfc_is_v1()) {
+ writew(0x0, host->regs + NFC_V1_UNLOCKSTART_BLKADDR);
+ writew(0x4000, host->regs + NFC_V1_UNLOCKEND_BLKADDR);
+ } else
+ BUG();
+
+ /* Unlock Block Command for given address range */
+ writew(0x4, host->regs + NFC_V1_V2_WRPROT);
+}
+
+static void preset_v3(struct mtd_info *mtd)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct imx_nand_host *host = chip->priv;
+ uint32_t config2, config3;
+ int i, addr_phases;
+
+ writel(NFC_V3_CONFIG1_RBA(0), NFC_V3_CONFIG1);
+ writel(NFC_V3_IPC_CREQ, NFC_V3_IPC);
+
+ /* Unlock the internal RAM Buffer */
+ writel(NFC_V3_WRPROT_BLS_UNLOCK | NFC_V3_WRPROT_UNLOCK,
+ NFC_V3_WRPROT);
+
+ /* Blocks to be unlocked */
+ for (i = 0; i < NAND_MAX_CHIPS; i++)
+ writel(0x0 | (0xffff << 16),
+ NFC_V3_WRPROT_UNLOCK_BLK_ADD0 + (i << 2));
+
+ writel(0, NFC_V3_IPC);
+
+ config2 = NFC_V3_CONFIG2_ONE_CYCLE |
+ NFC_V3_CONFIG2_2CMD_PHASES |
+ NFC_V3_CONFIG2_SPAS(mtd->oobsize >> 1) |
+ NFC_V3_CONFIG2_ST_CMD(0x70) |
+ NFC_V3_CONFIG2_NUM_ADDR_PHASE0;
+
+ if (chip->ecc.mode == NAND_ECC_HW)
+ config2 |= NFC_V3_CONFIG2_ECC_EN;
+
+ addr_phases = fls(chip->pagemask) >> 3;
+
+ if (mtd->writesize == 2048) {
+ config2 |= NFC_V3_CONFIG2_PS_2048;
+ config2 |= NFC_V3_CONFIG2_NUM_ADDR_PHASE1(addr_phases);
+ } else if (mtd->writesize == 4096) {
+ config2 |= NFC_V3_CONFIG2_PS_4096;
+ config2 |= NFC_V3_CONFIG2_NUM_ADDR_PHASE1(addr_phases);
+ } else {
+ config2 |= NFC_V3_CONFIG2_PS_512;
+ config2 |= NFC_V3_CONFIG2_NUM_ADDR_PHASE1(addr_phases - 1);
+ }
+
+ if (mtd->writesize) {
+ config2 |= NFC_V3_CONFIG2_PPB(ffs(mtd->erasesize / mtd->writesize) - 6);
+ host->eccsize = get_eccsize(mtd);
+ if (host->eccsize == 8)
+ config2 |= NFC_V3_CONFIG2_ECC_MODE_8;
+ }
+
+ writel(config2, NFC_V3_CONFIG2);
+
+ config3 = NFC_V3_CONFIG3_NUM_OF_DEVICES(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 (!(chip->options & NAND_BUSWIDTH_16))
+ config3 |= NFC_V3_CONFIG3_FW8;
+
+ writel(config3, NFC_V3_CONFIG3);
+
+ writel(0, NFC_V3_DELAY_LINE);
+}
+
+/*
* This function is used by the upper layer to write command to NAND Flash for
* different operations to be carried out on NAND Flash
*
@@ -685,11 +922,15 @@ static void imx_nand_command(struct mtd_info *mtd, unsigned command,
* Command pre-processing step
*/
switch (command) {
+ case NAND_CMD_RESET:
+ host->preset(mtd);
+ host->send_cmd(host, command);
+ break;
case NAND_CMD_STATUS:
host->buf_start = 0;
host->status_request = 1;
- send_cmd(host, command);
+ host->send_cmd(host, command);
mxc_do_addr_cycle(mtd, column, page_addr);
break;
@@ -702,14 +943,14 @@ static void imx_nand_command(struct mtd_info *mtd, unsigned command,
command = NAND_CMD_READ0;
- send_cmd(host, command);
+ host->send_cmd(host, command);
mxc_do_addr_cycle(mtd, column, page_addr);
if (host->pagesize_2k)
/* send read confirm command */
- send_cmd(host, NAND_CMD_READSTART);
+ host->send_cmd(host, NAND_CMD_READSTART);
- send_page(host, NFC_OUTPUT);
+ host->send_page(host, NFC_OUTPUT);
memcpy32(host->data_buf, host->main_area0, mtd->writesize);
copy_spare(mtd, 1);
@@ -733,15 +974,15 @@ static void imx_nand_command(struct mtd_info *mtd, unsigned command,
/* Set program pointer to spare region */
if (!host->pagesize_2k)
- send_cmd(host, NAND_CMD_READOOB);
+ host->send_cmd(host, NAND_CMD_READOOB);
} else {
host->buf_start = column;
/* Set program pointer to page start */
if (!host->pagesize_2k)
- send_cmd(host, NAND_CMD_READ0);
+ host->send_cmd(host, NAND_CMD_READ0);
}
- send_cmd(host, command);
+ host->send_cmd(host, command);
mxc_do_addr_cycle(mtd, column, page_addr);
break;
@@ -749,22 +990,21 @@ static void imx_nand_command(struct mtd_info *mtd, unsigned command,
case NAND_CMD_PAGEPROG:
memcpy32(host->main_area0, host->data_buf, mtd->writesize);
copy_spare(mtd, 0);
- send_page(host, NFC_INPUT);
- send_cmd(host, command);
+ host->send_page(host, NFC_INPUT);
+ host->send_cmd(host, command);
mxc_do_addr_cycle(mtd, column, page_addr);
break;
case NAND_CMD_READID:
- send_cmd(host, command);
+ host->send_cmd(host, command);
mxc_do_addr_cycle(mtd, column, page_addr);
host->buf_start = 0;
- send_read_id(host);
+ host->send_read_id(host);
break;
case NAND_CMD_ERASE1:
case NAND_CMD_ERASE2:
- case NAND_CMD_RESET:
- send_cmd(host, command);
+ host->send_cmd(host, command);
mxc_do_addr_cycle(mtd, column, page_addr);
break;
}
@@ -839,7 +1079,6 @@ static int __init imxnd_probe(struct device_d *dev)
struct imx_nand_platform_data *pdata = dev->platform_data;
struct imx_nand_host *host;
struct nand_ecclayout *oob_smallpage, *oob_largepage;
- u16 tmp;
int err = 0;
#ifdef CONFIG_ARCH_IMX27
@@ -858,20 +1097,45 @@ static int __init imxnd_probe(struct device_d *dev)
host->base = (void __iomem *)dev->map_base;
host->main_area0 = host->base;
- host->main_area1 = host->base + 0x200;
+
+ if (nfc_is_v1() || nfc_is_v21()) {
+ host->preset = preset_v1_v2;
+ host->send_cmd = send_cmd_v1_v2;
+ host->send_addr = send_addr_v1_v2;
+ host->send_page = send_page_v1_v2;
+ host->send_read_id = send_read_id_v1_v2;
+ host->get_dev_status = get_dev_status_v1_v2;
+ host->check_int = check_int_v1_v2;
+ }
if (nfc_is_v21()) {
- host->regs = host->base + 0x1000;
+ host->regs = host->base + 0x1e00;
host->spare0 = host->base + 0x1000;
host->spare_len = 64;
oob_smallpage = &nandv2_hw_eccoob_smallpage;
oob_largepage = &nandv2_hw_eccoob_largepage;
} else if (nfc_is_v1()) {
- host->regs = host->base;
+ host->regs = host->base + 0xe00;
host->spare0 = host->base + 0x800;
host->spare_len = 16;
oob_smallpage = &nandv1_hw_eccoob_smallpage;
oob_largepage = &nandv1_hw_eccoob_largepage;
+ } else if (nfc_is_v3_2()) {
+#ifdef CONFIG_ARCH_IMX51
+ host->regs_ip = (void *)MX51_NFC_BASE_ADDR;
+#endif
+ host->regs_axi = host->base + 0x1e00;
+ host->spare0 = host->base + 0x1000;
+ host->spare_len = 64;
+ host->preset = preset_v3;
+ host->send_cmd = send_cmd_v3;
+ host->send_addr = send_addr_v3;
+ host->send_page = send_page_v3;
+ host->send_read_id = send_read_id_v3;
+ host->get_dev_status = get_dev_status_v3;
+ host->check_int = check_int_v3;
+ oob_smallpage = &nandv2_hw_eccoob_smallpage;
+ oob_largepage = &nandv2_hw_eccoob_largepage;
}
host->dev = dev;
@@ -900,52 +1164,20 @@ static int __init imxnd_probe(struct device_d *dev)
clk_enable(host->clk);
#endif
- tmp = readw(host->regs + NFC_CONFIG1);
- tmp |= NFC_INT_MSK;
- tmp &= ~NFC_SP_EN;
- if (nfc_is_v21())
- /* currently no support for 218 byte OOB with stronger ECC */
- tmp |= NFC_ECC_MODE;
- writew(tmp, host->regs + NFC_CONFIG1);
-
if (pdata->hw_ecc) {
this->ecc.calculate = imx_nand_calculate_ecc;
this->ecc.hwctl = imx_nand_enable_hwecc;
- this->ecc.correct = imx_nand_correct_data;
+ if (nfc_is_v1())
+ this->ecc.correct = imx_nand_correct_data_v1;
+ else
+ this->ecc.correct = imx_nand_correct_data_v2_v3;
this->ecc.mode = NAND_ECC_HW;
this->ecc.size = 512;
- tmp = readw(host->regs + NFC_CONFIG1);
- tmp |= NFC_ECC_EN;
- writew(tmp, host->regs + NFC_CONFIG1);
} else {
this->ecc.size = 512;
this->ecc.mode = NAND_ECC_SOFT;
- tmp = readw(host->regs + NFC_CONFIG1);
- tmp &= ~NFC_ECC_EN;
- writew(tmp, host->regs + NFC_CONFIG1);
- }
-
- /* Reset NAND */
- this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
-
- /* preset operation */
- /* Unlock the internal RAM Buffer */
- writew(0x2, host->regs + NFC_CONFIG);
-
- /* Blocks to be unlocked */
- if (nfc_is_v21()) {
- writew(0x0, host->regs + NFC_V21_UNLOCKSTART_BLKADDR);
- writew(0xffff, host->regs + NFC_V21_UNLOCKEND_BLKADDR);
- this->ecc.bytes = 9;
- } else if (nfc_is_v1()) {
- writew(0x0, host->regs + NFC_V1_UNLOCKSTART_BLKADDR);
- writew(0x4000, host->regs + NFC_V1_UNLOCKEND_BLKADDR);
- this->ecc.bytes = 3;
}
- /* Unlock Block Command for given address range */
- writew(0x4, host->regs + NFC_WRPROT);
-
this->ecc.layout = oob_smallpage;
/* NAND bus width determines access funtions used by upper layer */
@@ -968,24 +1200,19 @@ static int __init imxnd_probe(struct device_d *dev)
goto escan;
}
+ /* Call preset again, with correct writesize this time */
+ host->preset(mtd);
+
imx_nand_set_layout(mtd->writesize, pdata->width == 2 ? 16 : 8);
if (mtd->writesize == 2048) {
this->ecc.layout = oob_largepage;
host->pagesize_2k = 1;
- if (nfc_is_v21()) {
- tmp = readw(host->regs + NFC_SPAS);
- tmp &= 0xff00;
- tmp |= NFC_SPAS_64;
- writew(tmp, host->regs + NFC_SPAS);
- }
+ if (nfc_is_v21())
+ writew(NFC_V2_SPAS_SPARESIZE(64), host->regs + NFC_V2_SPAS);
} else {
- if (nfc_is_v21()) {
- tmp = readw(host->regs + NFC_SPAS);
- tmp &= 0xff00;
- tmp |= NFC_SPAS_16;
- writew(tmp, host->regs + NFC_SPAS);
- }
+ if (nfc_is_v21())
+ writew(NFC_V2_SPAS_SPARESIZE(16), host->regs + NFC_V2_SPAS);
}
/* second phase scan */
@@ -1018,14 +1245,14 @@ static void __nand_boot_init noinline imx_nandboot_wait_op_done(void *regs)
u32 r;
while (1) {
- r = readw(regs + NFC_CONFIG2);
- if (r & NFC_INT)
+ r = readw(regs + NFC_V1_V2_CONFIG2);
+ if (r & NFC_V1_V2_CONFIG2_INT)
break;
};
- r &= ~NFC_INT;
+ r &= ~NFC_V1_V2_CONFIG2_INT;
- writew(r, regs + NFC_CONFIG2);
+ writew(r, regs + NFC_V1_V2_CONFIG2);
}
/*
@@ -1036,8 +1263,8 @@ static void __nand_boot_init noinline imx_nandboot_wait_op_done(void *regs)
*/
static void __nand_boot_init imx_nandboot_send_cmd(void *regs, u16 cmd)
{
- writew(cmd, regs + NFC_FLASH_CMD);
- writew(NFC_CMD, regs + NFC_CONFIG2);
+ writew(cmd, regs + NFC_V1_V2_FLASH_CMD);
+ writew(NFC_CMD, regs + NFC_V1_V2_CONFIG2);
imx_nandboot_wait_op_done(regs);
}
@@ -1052,8 +1279,8 @@ static void __nand_boot_init imx_nandboot_send_cmd(void *regs, u16 cmd)
*/
static void __nand_boot_init noinline imx_nandboot_send_addr(void *regs, u16 addr)
{
- writew(addr, regs + NFC_FLASH_ADDR);
- writew(NFC_ADDR, regs + NFC_CONFIG2);
+ writew(addr, regs + NFC_V1_V2_FLASH_ADDR);
+ writew(NFC_ADDR, regs + NFC_V1_V2_CONFIG2);
/* Wait for operation to complete */
imx_nandboot_wait_op_done(regs);
@@ -1088,9 +1315,9 @@ static void __nand_boot_init imx_nandboot_send_page(void *regs,
for (i = 0; i < bufs; i++) {
/* NANDFC buffer 0 is used for page read/write */
- writew(i, regs + NFC_BUF_ADDR);
+ writew(i, regs + NFC_V1_V2_BUF_ADDR);
- writew(ops, regs + NFC_CONFIG2);
+ writew(ops, regs + NFC_V1_V2_CONFIG2);
/* Wait for operation to complete */
imx_nandboot_wait_op_done(regs);
@@ -1159,10 +1386,10 @@ void __nand_boot_init imx_nand_load_image(void *dest, int size)
base = (void __iomem *)IMX_NFC_BASE;
if (nfc_is_v21()) {
- regs = base + 0x1000;
+ regs = base + 0x1e00;
spare0 = base + 0x1000;
} else if (nfc_is_v1()) {
- regs = base;
+ regs = base + 0xe00;
spare0 = base + 0x800;
}
@@ -1170,31 +1397,24 @@ void __nand_boot_init imx_nand_load_image(void *dest, int size)
/* preset operation */
/* Unlock the internal RAM Buffer */
- writew(0x2, regs + NFC_CONFIG);
+ writew(0x2, regs + NFC_V1_V2_CONFIG);
/* Unlock Block Command for given address range */
- writew(0x4, regs + NFC_WRPROT);
+ writew(0x4, regs + NFC_V1_V2_WRPROT);
- tmp = readw(regs + NFC_CONFIG1);
- tmp |= NFC_ECC_EN;
+ tmp = readw(regs + NFC_V1_V2_CONFIG1);
+ tmp |= NFC_V1_V2_CONFIG1_ECC_EN;
if (nfc_is_v21())
/* currently no support for 218 byte OOB with stronger ECC */
- tmp |= NFC_ECC_MODE;
- tmp &= ~(NFC_SP_EN | NFC_INT_MSK);
- writew(tmp, regs + NFC_CONFIG1);
+ tmp |= NFC_V2_CONFIG1_ECC_MODE_4;
+ tmp &= ~(NFC_V1_V2_CONFIG1_SP_EN | NFC_V1_V2_CONFIG1_INT_MSK);
+ writew(tmp, regs + NFC_V1_V2_CONFIG1);
if (nfc_is_v21()) {
- if (pagesize_2k) {
- tmp = readw(regs + NFC_SPAS);
- tmp &= 0xff00;
- tmp |= NFC_SPAS_64;
- writew(tmp, regs + NFC_SPAS);
- } else {
- tmp = readw(regs + NFC_SPAS);
- tmp &= 0xff00;
- tmp |= NFC_SPAS_16;
- writew(tmp, regs + NFC_SPAS);
- }
+ if (pagesize_2k)
+ writew(NFC_V2_SPAS_SPARESIZE(64), regs + NFC_V2_SPAS);
+ else
+ writew(NFC_V2_SPAS_SPARESIZE(16), regs + NFC_V2_SPAS);
}
block = page = 0;