summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2010-11-10 12:35:18 +0100
committerSascha Hauer <s.hauer@pengutronix.de>2010-11-12 08:08:02 +0100
commitce15c024c17751443d932a7c2b8cb0c8a90901bf (patch)
tree68411265834c228f30ad2c745477f5e9fa0f1803 /drivers
parent691bff00629694a53ae9f600d716edaca3d0ab94 (diff)
downloadbarebox-ce15c024c17751443d932a7c2b8cb0c8a90901bf.tar.gz
barebox-ce15c024c17751443d932a7c2b8cb0c8a90901bf.tar.xz
imx nand: Add v3 (i.MX51) support
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mtd/nand/Kconfig4
-rw-r--r--drivers/mtd/nand/nand_imx.c208
2 files changed, 209 insertions, 3 deletions
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index bc95195116..034bb6fe49 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -11,12 +11,12 @@ if NAND
config NAND_IMX
bool
prompt "i.MX NAND driver"
- depends on ARCH_IMX21 || ARCH_IMX27 || ARCH_IMX31 || ARCH_IMX35 || ARCH_IMX25
+ depends on ARCH_IMX21 || ARCH_IMX27 || ARCH_IMX31 || ARCH_IMX35 || ARCH_IMX25 || ARCH_IMX51
config NAND_IMX_BOOT
bool
prompt "Support Starting barebox from NAND"
- depends on NAND_IMX || NAND_IMX_V2
+ depends on NAND_IMX && !ARCH_IMX51
choice
depends on NAND_IMX_BOOT
diff --git a/drivers/mtd/nand/nand_imx.c b/drivers/mtd/nand/nand_imx.c
index 9e2ba32b87..9a15ab2c98 100644
--- a/drivers/mtd/nand/nand_imx.c
+++ b/drivers/mtd/nand/nand_imx.c
@@ -32,6 +32,8 @@
#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
@@ -82,6 +84,54 @@
#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
#else
@@ -99,6 +149,8 @@ struct imx_nand_host {
void __iomem *base;
void __iomem *regs;
+ void __iomem *regs_axi;
+ void __iomem *regs_ip;
int status_request;
struct clk *clk;
@@ -176,6 +228,20 @@ static void memcpy32(void *trg, const void *src, int size)
*t++ = *s++;
}
+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;
@@ -209,6 +275,18 @@ static void wait_op_done(struct imx_nand_host *host)
*
* @param cmd command for NAND Flash
*/
+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);
@@ -238,6 +316,17 @@ static void send_cmd_v1_v2(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_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);
@@ -256,6 +345,20 @@ static void send_addr_v1_v2(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_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)
{
@@ -281,6 +384,16 @@ static void send_page_v1_v2(struct imx_nand_host *host,
* This function requests the NANDFC to perform a read of the
* NAND device ID.
*/
+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;
@@ -315,6 +428,14 @@ static void send_read_id_v1_v2(struct imx_nand_host *host)
*
* @return device status
*/
+static uint16_t get_dev_status_v3(struct imx_nand_host *host)
+{
+ 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;
@@ -405,7 +526,10 @@ static int imx_nand_correct_data_v2_v3(struct mtd_info *mtd, u_char *dat,
no_subpages = mtd->writesize >> 9;
- ecc_stat = readl(host->regs + NFC_V2_ECC_STATUS_RESULT1);
+ 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;
@@ -704,6 +828,72 @@ static void preset_v1_v2(struct mtd_info *mtd)
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
@@ -930,6 +1120,22 @@ static int __init imxnd_probe(struct device_d *dev)
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;