diff options
author | Quinn Jensen <quinn.jensen@freescale.com> | 2007-10-24 21:26:22 -0600 |
---|---|---|
committer | Quinn Jensen <quinn.jensen@freescale.com> | 2007-10-24 21:26:22 -0600 |
commit | 5b82378eeccb61decc379e84d308afb1dc8e5954 (patch) | |
tree | 04accf0f28912519f846dbc40695a528a253a66d | |
parent | 8a7b6b845328acfbec1e69b2437eda8e78419835 (diff) |
CR ENGR00043959 Merging mxc nand driver across RS ECC NFCs
Patch for CR ENGR00043959 Merging mxc nand driver across RS ECC NFCs
DevTech Note: This patch also supports Redboot partition parsing on NAND,
and updates the NOR driver to use kzalloc instead of kmalloc/memset as
is being done throughout the mainline kernel. Applies to linux 2.6.22
kernel for MX platforms.
http://www.bitshrine.org/gpp/linux-2.6.22-mx-CR-ENGR00043959-Merging-mxc-nand-driver-ac.patch
-rw-r--r-- | drivers/mtd/maps/mxc_nor.c | 4 | ||||
-rw-r--r-- | drivers/mtd/nand/mxc_nd.c | 2 | ||||
-rw-r--r-- | drivers/mtd/nand/mxc_nd2.c | 251 | ||||
-rw-r--r-- | drivers/mtd/nand/mxc_nd2.h | 281 |
4 files changed, 421 insertions, 117 deletions
diff --git a/drivers/mtd/maps/mxc_nor.c b/drivers/mtd/maps/mxc_nor.c index 6ffe33944c94..14da2a28ea57 100644 --- a/drivers/mtd/maps/mxc_nor.c +++ b/drivers/mtd/maps/mxc_nor.c @@ -57,12 +57,10 @@ static int __devinit mxcflash_probe(struct platform_device *pdev) struct resource *res = pdev->resource; unsigned long size = res->end - res->start + 1; - info = kmalloc(sizeof(struct mxcflash_info), GFP_KERNEL); + info = kzalloc(sizeof(struct mxcflash_info), GFP_KERNEL); if (!info) return -ENOMEM; - memset(info, 0, sizeof(struct mxcflash_info)); - if (!request_mem_region(res->start, size, "flash")) { err = -EBUSY; goto out_free_info; diff --git a/drivers/mtd/nand/mxc_nd.c b/drivers/mtd/nand/mxc_nd.c index 08ea25ad9421..2168e8f24cbf 100644 --- a/drivers/mtd/nand/mxc_nd.c +++ b/drivers/mtd/nand/mxc_nd.c @@ -110,7 +110,7 @@ static struct nand_ecclayout nand_hw_eccoob_16 = { */ #ifdef CONFIG_MTD_PARTITIONS -static const char *part_probes[] = { /* "RedBoot", */ "cmdlinepart", NULL }; +static const char *part_probes[] = { "RedBoot", "cmdlinepart", NULL }; #endif static wait_queue_head_t irq_waitq; diff --git a/drivers/mtd/nand/mxc_nd2.c b/drivers/mtd/nand/mxc_nd2.c index d3a8993ccb2e..b13399e1fc5e 100644 --- a/drivers/mtd/nand/mxc_nd2.c +++ b/drivers/mtd/nand/mxc_nd2.c @@ -17,29 +17,20 @@ #include <linux/module.h> #include <linux/mtd/mtd.h> #include <linux/mtd/nand.h> -#include <linux/mtd/partitions.h> #include <linux/interrupt.h> #include <linux/device.h> #include <linux/platform_device.h> #include <linux/clk.h> #include <linux/err.h> - +#include <linux/mtd/partitions.h> #include <asm/mach/flash.h> #include <asm/io.h> +#include "mxc_nd2.h" -#include "mxc_nd.h" +#define DVR_VER "2.3" -#define DVR_VER "2.11" - -/* - * Define delays in microsec for NAND device operations - */ -#define TROP_US_DELAY 2000 - -/* - * Macro useful to check if the nand chip is 2K page - */ -#define IS_2K_PAGE_NAND (mtd->writesize == NAND_PAGESIZE_2KB) +/* Global address Variables */ +static u32 nfc_axi_base, nfc_ip_base; static void mxc_swap_2k_bi_main_sp(void); @@ -52,6 +43,11 @@ struct mxc_mtd_s { static struct mxc_mtd_s *mxc_nand_data; +/* + * Define delays in microsec for NAND device operations + */ +#define TROP_US_DELAY 2000 + struct nand_info { bool bSpareOnly; bool bStatusRequest; @@ -66,11 +62,11 @@ static int hardware_ecc = 0; static int hardware_ecc = 1; #endif -static int scan_done; -static int skip_erase; static int page_to_block_shift; static int g_page_mask; -static uint8_t *oob_data_shadow_p; +static int scan_done; +static int skip_erase; +static u8 *oob_data_shadow_p; /* * OOB data that is shadowed in the SDRAM to prevent the Spare only access * to the Nand chip. This is valid only for the JFFS2 File System. @@ -117,7 +113,7 @@ static struct nand_ecclayout nand_hw_eccoob_2k = { */ /*! - * @file mxc_nd2.c + * @file mxc_nd3.c * * @brief This file contains the hardware specific layer for NAND Flash on * MXC processor @@ -126,14 +122,15 @@ static struct nand_ecclayout nand_hw_eccoob_2k = { */ #ifdef CONFIG_MTD_PARTITIONS -static const char *part_probes[] = { "cmdlinepart", NULL }; +static const char *part_probes[] = { "RedBoot", "cmdlinepart", NULL }; #endif static wait_queue_head_t irq_waitq; static irqreturn_t mxc_nfc_irq(int irq, void *dev_id) { - NFC_CONFIG1 |= NFC_INT_MSK; /* Disable interrupt */ + /* Disable Interuupt */ + raw_write(raw_read(REG_NFC_INTRRUPT) | NFC_INT_MSK, REG_NFC_INTRRUPT); wake_up(&irq_waitq); return IRQ_HANDLED; @@ -151,6 +148,7 @@ static u8 mxc_main_xfer_buf[2048] ____cacheline_aligned; * mark_oob_data_clean - marks a block to indicate that the block is erased * and doesnot contain JFFS2 clean marker. */ + static void mark_oob_data_dirty(u32 page, int update_sp) { u32 blk = page >> page_to_block_shift; @@ -171,6 +169,7 @@ static int is_oob_data_dirty(u32 page) static void mark_oob_data_clean(u32 page) { + u32 blk = page >> page_to_block_shift; u32 off = blk / 8; u32 bit = blk % 8; @@ -216,17 +215,23 @@ static void nfc_memcpy(void *dst, const void *src, int len) */ static void wait_op_done(int maxRetries, bool useirq) { + if (useirq) { - if ((NFC_CONFIG2 & NFC_INT) == 0) { - NFC_CONFIG1 &= ~NFC_INT_MSK; /* Enable interrupt */ - wait_event(irq_waitq, NFC_CONFIG2 & NFC_INT); - NFC_CONFIG2 &= ~NFC_INT; + if ((raw_read(REG_NFC_OPS_STAT) & NFC_OPS_STAT) == 0) { + /* Enable Interuupt */ + raw_write(raw_read(REG_NFC_INTRRUPT) & ~NFC_INT_MSK, + REG_NFC_INTRRUPT); + wait_event(irq_waitq, + (raw_read(REG_NFC_OPS_STAT) & NFC_OPS_STAT)); + raw_write((raw_read(REG_NFC_OPS_STAT) & ~NFC_OPS_STAT), + REG_NFC_OPS_STAT); } } else { while (1) { maxRetries--; - if (NFC_CONFIG2 & NFC_INT) { - NFC_CONFIG2 &= ~NFC_INT; + if (raw_read(REG_NFC_OPS_STAT) & NFC_OPS_STAT) { + raw_write((raw_read(REG_NFC_OPS_STAT) & + ~NFC_OPS_STAT), REG_NFC_OPS_STAT); break; } udelay(1); @@ -249,8 +254,9 @@ static void send_cmd(u16 cmd, bool useirq) { DEBUG(MTD_DEBUG_LEVEL3, "send_cmd(0x%x, %d)\n", cmd, useirq); - NFC_FLASH_CMD = (u16) cmd; - NFC_CONFIG2 = NFC_CMD; + raw_write(cmd, REG_NFC_FLASH_CMD); + ACK_OPS; + raw_write(NFC_CMD, REG_NFC_OPS); /* Wait for operation to complete */ wait_op_done(TROP_US_DELAY, useirq); @@ -267,9 +273,10 @@ static void send_cmd(u16 cmd, bool useirq) static void send_addr(u16 addr, bool useirq) { DEBUG(MTD_DEBUG_LEVEL3, "send_addr(0x%x %d)\n", addr, useirq); + raw_write((addr << NFC_FLASH_ADDR_SHIFT), REG_NFC_FLASH_ADDR); - NFC_FLASH_ADDR = addr; - NFC_CONFIG2 = NFC_ADDR; + ACK_OPS; /* defined only for V3 */ + raw_write(NFC_ADDR, REG_NFC_OPS); /* Wait for operation to complete */ wait_op_done(TROP_US_DELAY, useirq); @@ -283,12 +290,16 @@ static void send_addr(u16 addr, bool useirq) */ static void send_prog_page(u8 buf_id) { + u32 val = buf_id; DEBUG(MTD_DEBUG_LEVEL3, "%s\n", __FUNCTION__); - /* NFC buffer 0 is used for page read/write */ - NFC_BUF_ADDR = buf_id; + NFC_SET_RBA(val, RBA_BUFFER0); /* defined only for V3 */ + + /* Set RBA bits for BUFFER val */ + raw_write(val, REG_NFC_SET_RBA); - NFC_CONFIG2 = NFC_INPUT; + ACK_OPS; /* defined only for V3 */ + raw_write(NFC_INPUT, REG_NFC_OPS); /* Wait for operation to complete */ wait_op_done(TROP_US_DELAY, true); @@ -302,12 +313,15 @@ static void send_prog_page(u8 buf_id) */ static void send_read_page(u8 buf_id) { + u32 val = buf_id; DEBUG(MTD_DEBUG_LEVEL3, "%s\n", __FUNCTION__); - /* NFC buffer 0 is used for page read/write */ - NFC_BUF_ADDR = buf_id; + NFC_SET_RBA(val, RBA_BUFFER0); /* defined only for V3 */ + /* Set RBA bits for BUFFER val */ + raw_write(val, REG_NFC_SET_RBA); - NFC_CONFIG2 = NFC_OUTPUT; + ACK_OPS; /* defined only for V3 */ + raw_write(NFC_OUTPUT, REG_NFC_OPS); /* Wait for operation to complete */ wait_op_done(TROP_US_DELAY, true); @@ -319,14 +333,21 @@ static void send_read_page(u8 buf_id) */ static void send_read_id(void) { + u32 val = 0; + /* NFC buffer 0 is used for device ID output */ - NFC_BUF_ADDR = 0x0; + /* Set RBA bits for BUFFER0 */ + + NFC_SET_RBA(val, RBA_BUFFER0); /* defined only for V3 */ + raw_write(val, REG_NFC_SET_RBA); + ACK_OPS; /* defined only for V3 */ /* Read ID into main buffer */ - NFC_CONFIG2 = NFC_ID; + raw_write(NFC_ID, REG_NFC_OPS); /* Wait for operation to complete */ wait_op_done(TROP_US_DELAY, true); + } /*! @@ -338,20 +359,27 @@ static void send_read_id(void) static u16 get_dev_status(void) { volatile u16 *mainBuf = MAIN_AREA1; - u32 store; + volatile u32 store; + u32 val = 1; u16 ret; /* Issue status request to NAND device */ /* store the main area1 first word, later do recovery */ store = *((u32 *) mainBuf); + *(u32 *) mainBuf = 0x0; + /* * NFC buffer 1 is used for device status to prevent * corruption of read/write buffer on status requests. */ - NFC_BUF_ADDR = 1; + /* Set RBA bits for BUFFER1 */ + NFC_SET_RBA(val, RBA_BUFFER1); /* defined only for V3 */ + raw_write(val, REG_NFC_SET_RBA); + + ACK_OPS; /* defined only for V3 */ /* Read status into main buffer */ - NFC_CONFIG2 = NFC_STATUS; + raw_write(NFC_STATUS, REG_NFC_OPS); /* Wait for operation to complete */ wait_op_done(TROP_US_DELAY, true); @@ -360,7 +388,6 @@ static u16 get_dev_status(void) /* get status, then recovery area 1 data */ ret = mainBuf[0]; *((u32 *) mainBuf) = store; - return ret; } @@ -374,15 +401,17 @@ static u16 get_dev_status(void) static int mxc_nand_dev_ready(struct mtd_info *mtd) { /* - * NFC handles R/B internally.Therefore,this function - * always returns status as ready. + * For V1/V2 NFC this function returns always 1. */ - return 1; + if (CHECK_NFC_RB) + return 1; + else + return 0; } static void mxc_nand_enable_hwecc(struct mtd_info *mtd, int mode) { - NFC_CONFIG1 |= NFC_ECC_EN; + raw_write((raw_read(REG_NFC_ECC_EN) | NFC_ECC_EN), REG_NFC_ECC_EN); return; } @@ -401,7 +430,7 @@ static int mxc_check_ecc_status(struct mtd_info *mtd) no_subpages = 4; } - ecc_stat = NFC_ECC_STATUS_RESULT; + ecc_stat = raw_read(REG_NFC_ECC_STATUS_RESULT); do { err = ecc_stat & 0x7; if (err > 0x4) { @@ -433,6 +462,7 @@ static int mxc_nand_correct_data(struct mtd_info *mtd, u_char * dat, * 4 symbols of 9 bits each in 528 byte page. * So this function is not required. */ + static int mxc_nand_calculate_ecc(struct mtd_info *mtd, const u_char * dat, u_char * ecc_code) { @@ -443,7 +473,7 @@ static int mxc_nand_calculate_ecc(struct mtd_info *mtd, const u_char * dat, /*! * This function reads byte from the NAND Flash * - * @param mtd MTD structure for the NAND Flash + * @param mtd MTD structure for the NAND Flash * * @return data read from the NAND Flash */ @@ -520,6 +550,11 @@ static u16 mxc_nand_read_word(struct mtd_info *mtd) */ static u_char mxc_nand_read_byte16(struct mtd_info *mtd) { + /* Check for status request */ + if (g_nandfc_info.bStatusRequest) { + return (get_dev_status() & 0xFF); + } + return mxc_nand_read_word(mtd) & 0xFF; } @@ -613,11 +648,12 @@ static void mxc_nand_select_chip(struct mtd_info *mtd, int chip) } if (chip == -1) { - NFC_CONFIG1 &= ~(NFC_CE); + raw_write((raw_read(REG_NFC_CE) & ~NFC_CE), REG_NFC_CE); return; } - NFC_CONFIG1 |= NFC_CE; + raw_write((raw_read(REG_NFC_CE) | NFC_CE), REG_NFC_CE); + #endif switch (chip) { @@ -656,6 +692,7 @@ static void mxc_do_addr_cycle(struct mtd_info *mtd, int column, int page_addr) page_addr >>= 8; } while (page_mask != 0); } + } /* @@ -669,10 +706,7 @@ static void read_full_page(struct mtd_info *mtd, int page_addr) if (IS_2K_PAGE_NAND) { send_cmd(NAND_CMD_READSTART, false); - send_read_page(0); - send_read_page(1); - send_read_page(2); - send_read_page(3); + READ_2K_PAGE; mxc_swap_2k_bi_main_sp(); } else { send_read_page(0); @@ -719,7 +753,6 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, DEBUG(MTD_DEBUG_LEVEL3, "mxc_nand_command (cmd = 0x%x, col = 0x%x, page = 0x%x)\n", command, column, page_addr); - /* * Reset command state information */ @@ -768,11 +801,9 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, case NAND_CMD_PAGEPROG: if (!g_nandfc_info.bSpareOnly) { - send_prog_page(0); if (IS_2K_PAGE_NAND) { - send_prog_page(1); - send_prog_page(2); - send_prog_page(3); + PROG_2K_PAGE} else { + send_prog_page(0); } } else { return; @@ -816,10 +847,7 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, /* send read confirm command */ send_cmd(NAND_CMD_READSTART, true); /* read for each AREA */ - send_read_page(0); - send_read_page(1); - send_read_page(2); - send_read_page(3); + READ_2K_PAGE; } else { send_read_page(0); } @@ -858,7 +886,9 @@ static void mxc_low_erase(struct mtd_info *mtd) #define mxc_low_erase(x) #endif -// Kevin: why do we need this??? +/* Kevin: why do we need this???, + * Yes, to avoid LED event trigger functions which will add code, -Raj*/ + static int mxc_nand_wait(struct mtd_info *mtd, struct nand_chip *chip) { unsigned long timeo = jiffies; @@ -872,8 +902,16 @@ static int mxc_nand_wait(struct mtd_info *mtd, struct nand_chip *chip) send_cmd(NAND_CMD_STATUS, 1); while (time_before(jiffies, timeo)) { - if (get_dev_status() & NAND_STATUS_READY) - break; +#ifdef CONFIG_ARCH_MXC_HAS_NFC_V3 + if (chip->dev_ready) { + if (chip->dev_ready(mtd)) + break; + } else +#endif + { + if (get_dev_status() & NAND_STATUS_READY) + break; + } cond_resched(); } @@ -894,8 +932,8 @@ static int mxc_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip, read_full_page(mtd, page); sndcmd = 0; } - nfc_memcpy((void *)chip->oob_poi, (void *)SPARE_AREA0, mtd->oobsize); + nfc_memcpy((void *)chip->oob_poi, (void *)SPARE_AREA0, mtd->oobsize); return sndcmd; } @@ -904,26 +942,14 @@ static int mxc_nand_write_oob(struct mtd_info *mtd, struct nand_chip *chip, { int status = 0; const uint8_t *buf = chip->oob_poi; + int read_oob_col = 0; + volatile uint16_t *p_addr = SPARE_AREA0; //FIXME Check for bad block marking if (0xFF == buf[chip->badblockpos]) { mark_oob_data_dirty(page, 1); } else { - int read_oob_col; - int read_oob_cmd; - volatile uint16_t *p_addr; - - if (IS_2K_PAGE_NAND) { - read_oob_col = 2048; - read_oob_cmd = NAND_CMD_READ0; - p_addr = MAIN_AREA0; - } else { - read_oob_col = 0; - read_oob_cmd = NAND_CMD_READOOB; - p_addr = SPARE_AREA0; - } - /* This is only place, Spare Only write happens */ - send_cmd(read_oob_cmd, false); + send_cmd(NAND_CMD_READ0, false); send_cmd(NAND_CMD_SEQIN, false); mxc_do_addr_cycle(mtd, read_oob_col, page); @@ -933,19 +959,12 @@ static int mxc_nand_write_oob(struct mtd_info *mtd, struct nand_chip *chip, send_cmd(NAND_CMD_PAGEPROG, true); status = mxc_nand_wait(mtd, chip); - if (status & NAND_STATUS_FAIL) return -EIO; } - return 0; } -// read column 464-465 byte but only 464 for bad block marker -#define BAD_BLK_MARKER_464 (*((volatile u16 *)IO_ADDRESS(NFC_BASE_ADDR + 0x600 + 464))) -// read column 0-1 byte, but only 1 is used for swapped main area data -#define BAD_BLK_MARKER_SP_0 (*((volatile u16 *)IO_ADDRESS(NFC_BASE_ADDR + 0x800))) - /* * This function does the trick of swapping the 464th byte in the last RAM * buffer in the main area with the 0th byte in the spare area. This seems @@ -957,13 +976,14 @@ static int mxc_nand_write_oob(struct mtd_info *mtd, struct nand_chip *chip, static void mxc_swap_2k_bi_main_sp(void) { u16 tmp1, tmp2, new_tmp1; - tmp1 = BAD_BLK_MARKER_464; - tmp2 = BAD_BLK_MARKER_SP_0; + tmp1 = __raw_readw(BAD_BLK_MARKER_464); + tmp2 = __raw_readw(BAD_BLK_MARKER_SP_0); new_tmp1 = (tmp1 & 0xFF00) | (tmp2 >> 8); tmp2 = (tmp1 << 8) | (tmp2 & 0xFF); - BAD_BLK_MARKER_464 = new_tmp1; - BAD_BLK_MARKER_SP_0 = tmp2; + __raw_writew(new_tmp1, BAD_BLK_MARKER_464); + __raw_writew(tmp2, BAD_BLK_MARKER_SP_0); + } /* Kevin: This is solid but need to optimize the nfc_memcpy */ @@ -1040,11 +1060,6 @@ static int mxc_nand_scan_bbt(struct mtd_info *mtd) /* propagate ecc.layout to mtd_info */ mtd->ecclayout = this->ecc.layout; - /* NAND bus width determines access funtions used by upper layer */ - if (this->options & NAND_BUSWIDTH_16) { - NFMS |= (1 << NFMS_NF_DWIDTH); - } - this->bbt_td = NULL; this->bbt_md = NULL; if (!this->badblock_pattern) { @@ -1069,19 +1084,23 @@ static int __init mxcnd_probe(struct platform_device *pdev) struct nand_chip *this; struct mtd_info *mtd; struct flash_platform_data *flash = pdev->dev.platform_data; - int nr_parts = 0, n; + int nr_parts = 0, n, err = 0; - int err = 0; + nfc_axi_base = IO_ADDRESS(NFC_AXI_BASE_ADDR); + nfc_ip_base = IO_ADDRESS(NFC_BASE_ADDR); + + /* Resetting NFC */ + raw_write(NFC_RST, REG_NFC_RST); /* Allocate memory for MTD device structure and private data */ - mxc_nand_data = kmalloc(sizeof(struct mxc_mtd_s), GFP_KERNEL); + mxc_nand_data = kzalloc(sizeof(struct mxc_mtd_s), GFP_KERNEL); if (!mxc_nand_data) { printk(KERN_ERR "%s: failed to allocate mtd_info\n", __FUNCTION__); err = -ENOMEM; goto out; } - memset(mxc_nand_data, 0, sizeof(struct mxc_mtd_s)); + memset((char *)&g_nandfc_info, 0, sizeof(g_nandfc_info)); mxc_nand_data->dev = &pdev->dev; @@ -1093,7 +1112,6 @@ static int __init mxcnd_probe(struct platform_device *pdev) /* 5 us command delay time */ this->chip_delay = 5; - this->priv = mxc_nand_data; this->dev_ready = mxc_nand_dev_ready; this->cmdfunc = mxc_nand_command; @@ -1105,15 +1123,19 @@ static int __init mxcnd_probe(struct platform_device *pdev) this->read_buf = mxc_nand_read_buf; this->verify_buf = mxc_nand_verify_buf; this->scan_bbt = mxc_nand_scan_bbt; + /* NAND bus width determines access funtions used by upper layer */ if (flash->width == 2) { - this->options |= NAND_BUSWIDTH_16; this->read_byte = mxc_nand_read_byte16; + this->options |= NAND_BUSWIDTH_16; + NFMS |= (1 << NFMS_NF_DWIDTH); } nfc_clk = clk_get(&pdev->dev, "nfc_clk"); clk_enable(nfc_clk); /* Enabled here to satisfy following reset command to succeed */ - NFC_CONFIG1 |= NFC_INT_MSK; + /* Disable interrupt */ + raw_write((raw_read(REG_NFC_INTRRUPT) | NFC_INT_MSK), REG_NFC_INTRRUPT); + init_waitqueue_head(&irq_waitq); err = request_irq(INT_NANDFC, mxc_nfc_irq, 0, "mxc_nd", NULL); if (err) { @@ -1132,26 +1154,29 @@ static int __init mxcnd_probe(struct platform_device *pdev) this->ecc.mode = NAND_ECC_HW; this->ecc.size = 512; /* RS-ECC is applied for both MAIN+SPARE not MAIN alone */ this->ecc.bytes = 9; /* used for both main and spare area */ - NFC_CONFIG1 |= NFC_ECC_EN; + raw_write((raw_read(REG_NFC_ECC_EN) | NFC_ECC_EN), + REG_NFC_ECC_EN); } else { this->ecc.mode = NAND_ECC_SOFT; - NFC_CONFIG1 &= ~NFC_ECC_EN; + raw_write((raw_read(REG_NFC_ECC_EN) & ~NFC_ECC_EN), + REG_NFC_ECC_EN); } - NFC_CONFIG1 &= ~(NFC_SP_EN); + + raw_write(raw_read(REG_NFC_SP_EN) & ~NFC_SP_EN, REG_NFC_SP_EN); /* Reset NAND */ this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); /* preset operation */ /* Unlock the internal RAM Buffer */ - NFC_CONFIG = 0x2; + raw_write(NFC_SET_BLS(NFC_BLS_UNLCOKED), REG_NFC_BLS); /* Blocks to be unlocked */ - NFC_UNLOCKSTART_BLKADDR = 0x0; - NFC_UNLOCKEND_BLKADDR = 0xFFFF; + /* Start Address = 0X0, End Address = 0xFFFF */ + UNLOCK_ADDR(0x0, 0xFFFF); /* Unlock Block Command for given address range */ - NFC_WRPROT = 0x4; + raw_write(NFC_SET_WPC(NFC_WPC_UNLOCK), REG_NFC_WPC); /* Scan to find existence of the device */ if (nand_scan(mtd, 1)) { @@ -1325,5 +1350,5 @@ module_init(mxc_nd_init); module_exit(mxc_nd_cleanup); MODULE_AUTHOR("Freescale Semiconductor, Inc."); -MODULE_DESCRIPTION("MXC NAND MTD driver Version 2"); +MODULE_DESCRIPTION("MXC NAND MTD driver Version 2-3"); MODULE_LICENSE("GPL"); diff --git a/drivers/mtd/nand/mxc_nd2.h b/drivers/mtd/nand/mxc_nd2.h new file mode 100644 index 000000000000..069370ad8a6a --- /dev/null +++ b/drivers/mtd/nand/mxc_nd2.h @@ -0,0 +1,281 @@ +/* + * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * 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 + */ + +/*! + * @file mxc_nd.h + * + * @brief This file contains the NAND Flash Controller register information. + * + * + * @ingroup NAND_MTD + */ + +#ifndef __MXC_ND2_H__ +#define __MXC_ND2_H__ + +#include <asm/hardware.h> + +#define IS_2K_PAGE_NAND (mtd->writesize == NAND_PAGESIZE_2KB) +#define NAND_PAGESIZE_2KB NAND_MAX_PAGESIZE + +#ifdef CONFIG_ARCH_MXC_HAS_NFC_V3 +/* + * For V3 NFC registers Definition + */ + +/* AXI Bus Mapped */ +#define NFC_AXI_BASE_ADDR NFC_BASE_ADDR_AXI +#define NFC_FLASH_ADDR_CMD (nfc_axi_base + 0xE00) +#define NFC_CONFIG1 (nfc_axi_base + 0xE04) +#define NFC_ECC_STATUS_RESULT (nfc_axi_base + 0xE08) +#define LAUNCH_NFC (nfc_axi_base + 0xE0C) + +/* IP Bus Mapped */ +#define NFC_WRPROT (nfc_ip_base + 0x00) +#define NFC_WRPROT_UNLOCK_BLK_ADD0 (nfc_ip_base + 0x04) +#define NFC_WRPROT_UNLOCK_BLK_ADD1 (nfc_ip_base + 0x08) +#define NFC_WRPROT_UNLOCK_BLK_ADD2 (nfc_ip_base + 0x0C) +#define NFC_WRPROT_UNLOCK_BLK_ADD3 (nfc_ip_base + 0x10) +#define NFC_CONFIG2 (nfc_ip_base + 0x14) +#define NFC_IPC (nfc_ip_base + 0x18) +#define NFC_AXI_ERR_ADD (nfc_ip_base + 0x1C) + +/*! + * Addresses for NFC RAM BUFFER Main area 0 + */ +#define MAIN_AREA0 (volatile u16 *)IO_ADDRESS(NFC_BASE_ADDR_AXI + 0x000) +#define MAIN_AREA1 (volatile u16 *)IO_ADDRESS(NFC_BASE_ADDR_AXI + 0x200) +#define MAIN_AREA2 (volatile u16 *)IO_ADDRESS(NFC_BASE_ADDR_AXI + 0x400) +#define MAIN_AREA3 (volatile u16 *)IO_ADDRESS(NFC_BASE_ADDR_AXI + 0x600) + +/*! + * Addresses for NFC SPARE BUFFER Spare area 0 + */ +#define SPARE_AREA0 (volatile u16 *)IO_ADDRESS(NFC_BASE_ADDR_AXI + 0x800) +#define SPARE_AREA1 (volatile u16 *)IO_ADDRESS(NFC_BASE_ADDR_AXI + 0x810) +#define SPARE_AREA2 (volatile u16 *)IO_ADDRESS(NFC_BASE_ADDR_AXI + 0x820) +#define SPARE_AREA3 (volatile u16 *)IO_ADDRESS(NFC_BASE_ADDR_AXI + 0x830) + +/* read column 464-465 byte but only 464 for bad block marker */ +#define BAD_BLK_MARKER_464 IO_ADDRESS(NFC_BASE_ADDR_AXI + 0x600 + 464) +/* read column 0-1 byte, but only 1 is used for swapped main area data */ +#define BAD_BLK_MARKER_SP_0 IO_ADDRESS(NFC_BASE_ADDR_AXI + 0x800) + +/*! + * Set 1 to specific operation bit, rest to 0 in LAUNCH_NFC Register for + * Specific operation + */ +#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_OPS_STAT (1 << 31) +#define NFC_INT_MSK (1 << 4) +#define NFC_BIG (1 << 5) +#define NFC_FLASH_ADDR_SHIFT 16 +#define NFC_UNLOCK_END_ADDR_SHIFT 16 +#define RBA_BUFFER0 (0 << 4) +#define RBA_BUFFER1 (1 << 4) +#define RBA_BUFFER2 (2 << 4) +#define RBA_BUFFER3 (3 << 4) +#define RBA_RESET ~(3 << 4) +#define NFC_RB (1 << 29) +#define NFC_ECC_EN (1 << 3) +#define NFC_CE (1 << 1) +#define NFC_RST (1 << 6) +#define NFC_PPB_32 (0 << 7) +#define NFC_PPB_64 (1 << 7) +#define NFC_PPB_128 (2 << 7) +#define NFC_PPB_256 (3 << 7) +#define NFC_PPB_RESET ~(3 << 7) +#define NFC_SP_EN (1) +#define NFC_BLS_LOCKED (0 << 16) +#define NFC_BLS_LOCKED_DEFAULT (1 << 16) +#define NFC_BLS_UNLCOKED (2 << 16) +#define NFC_BLS_RESET ~(3 << 16) +#define NFC_WPC_LOCK_TIGHT (1) +#define NFC_WPC_LOCK (1 << 1) +#define NFC_WPC_UNLOCK (1 << 2) +#define NFC_WPC_RESET ~(7) + +/* NFC Register Mapping */ +#define REG_NFC_OPS_STAT NFC_IPC +#define REG_NFC_INTRRUPT NFC_CONFIG2 +#define REG_NFC_FLASH_ADDR NFC_FLASH_ADDR_CMD +#define REG_NFC_FLASH_CMD NFC_FLASH_ADDR_CMD +#define REG_NFC_OPS LAUNCH_NFC +#define REG_NFC_SET_RBA NFC_CONFIG1 +#define REG_NFC_RB NFC_IPC +#define REG_NFC_ECC_EN NFC_CONFIG2 +#define REG_NFC_ECC_STATUS_RESULT NFC_ECC_STATUS_RESULT +#define REG_NFC_CE NFC_CONFIG1 +#define REG_NFC_RST NFC_CONFIG2 +#define REG_NFC_PPB NFC_CONFIG2 +#define REG_NFC_SP_EN NFC_CONFIG1 +#define REG_NFC_BLS NFC_WRPROT +#define REG_UNLOCK_BLK_ADD0 NFC_WRPROT_UNLOCK_BLK_ADD0 +#define REG_UNLOCK_BLK_ADD1 NFC_WRPROT_UNLOCK_BLK_ADD1 +#define REG_UNLOCK_BLK_ADD2 NFC_WRPROT_UNLOCK_BLK_ADD2 +#define REG_UNLOCK_BLK_ADD3 NFC_WRPROT_UNLOCK_BLK_ADD3 +#define REG_NFC_WPC NFC_WRPROT + +/* NFC V3 Specific MACRO functions definitions */ +#define raw_write(v,a) __raw_writel(v,a) +#define raw_read(a) __raw_readl(a) + +/* Explcit ack ops status (if any), before issue of any command */ +#define ACK_OPS raw_write((raw_read(REG_NFC_OPS_STAT) & ~NFC_OPS_STAT), REG_NFC_OPS_STAT); + +/* NFC buffer 0 to 3 are used for page read/write, starting with buffer0 */ +/* Set RBA bits for BUFFER0 */ +#define NFC_SET_RBA(val, buf_id) \ + val = ((raw_read(REG_NFC_SET_RBA) & RBA_RESET) | buf_id); + +#define UNLOCK_ADDR(start_addr,end_addr) \ + raw_write(start_addr | (end_addr << NFC_UNLOCK_END_ADDR_SHIFT), REG_UNLOCK_BLK_ADD0); + +#define NFC_SET_BLS(val) ((raw_read(REG_NFC_BLS) & NFC_BLS_RESET) | val ) +#define NFC_SET_WPC(val) ((raw_read(REG_NFC_WPC) & NFC_WPC_RESET) | val ) +#define CHECK_NFC_RB raw_read(REG_NFC_RB) & NFC_RB + +#define READ_2K_PAGE send_read_page(0); +#define PROG_2K_PAGE send_prog_page(0); + +#elif CONFIG_ARCH_MXC_HAS_NFC_V2 + +/* + * For V1/V2 NFC registers Definition + */ + +#define NFC_AXI_BASE_ADDR 0x00 +/* + * Addresses for NFC registers + */ +#define NFC_BUF_SIZE (nfc_ip_base + 0xE00) +#define NFC_BUF_ADDR (nfc_ip_base + 0xE04) +#define NFC_FLASH_ADDR (nfc_ip_base + 0xE06) +#define NFC_FLASH_CMD (nfc_ip_base + 0xE08) +#define NFC_CONFIG (nfc_ip_base + 0xE0A) +#define NFC_ECC_STATUS_RESULT (nfc_ip_base + 0xE0C) +#define NFC_RSLTMAIN_AREA (nfc_ip_base + 0xE0E) +#define NFC_RSLTSPARE_AREA (nfc_ip_base + 0xE10) +#define NFC_WRPROT (nfc_ip_base + 0xE12) +#define NFC_UNLOCKSTART_BLKADDR (nfc_ip_base + 0xE14) +#define NFC_UNLOCKEND_BLKADDR (nfc_ip_base + 0xE16) +#define NFC_NF_WRPRST (nfc_ip_base + 0xE18) +#define NFC_CONFIG1 (nfc_ip_base + 0xE1A) +#define NFC_CONFIG2 (nfc_ip_base + 0xE1C) + +/*! + * Addresses for NFC RAM BUFFER Main area 0 + */ +#define MAIN_AREA0 (volatile u16 *)IO_ADDRESS(NFC_BASE_ADDR + 0x000) +#define MAIN_AREA1 (volatile u16 *)IO_ADDRESS(NFC_BASE_ADDR + 0x200) +#define MAIN_AREA2 (volatile u16 *)IO_ADDRESS(NFC_BASE_ADDR + 0x400) +#define MAIN_AREA3 (volatile u16 *)IO_ADDRESS(NFC_BASE_ADDR + 0x600) + +/*! + * Addresses for NFC SPARE BUFFER Spare area 0 + */ +#define SPARE_AREA0 (volatile u16 *)IO_ADDRESS(NFC_BASE_ADDR + 0x800) +#define SPARE_AREA1 (volatile u16 *)IO_ADDRESS(NFC_BASE_ADDR + 0x810) +#define SPARE_AREA2 (volatile u16 *)IO_ADDRESS(NFC_BASE_ADDR + 0x820) +#define SPARE_AREA3 (volatile u16 *)IO_ADDRESS(NFC_BASE_ADDR + 0x830) + +/* read column 464-465 byte but only 464 for bad block marker */ +#define BAD_BLK_MARKER_464 IO_ADDRESS(NFC_BASE_ADDR + 0x600 + 464) +/* read column 0-1 byte, but only 1 is used for swapped main area data */ +#define BAD_BLK_MARKER_SP_0 IO_ADDRESS(NFC_BASE_ADDR + 0x800) + +/*! + * Set INT to 0, Set 1 to specific operation bit, rest to 0 in LAUNCH_NFC Register for + * Specific operation + */ +#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_OPS_STAT (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_UNLCOKED 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 + +/* NFC Register Mapping */ +#define REG_NFC_OPS_STAT NFC_CONFIG2 +#define REG_NFC_INTRRUPT NFC_CONFIG1 +#define REG_NFC_FLASH_ADDR NFC_FLASH_ADDR +#define REG_NFC_FLASH_CMD NFC_FLASH_CMD +#define REG_NFC_OPS NFC_CONFIG2 +#define REG_NFC_SET_RBA NFC_BUF_ADDR +#define REG_NFC_ECC_EN NFC_CONFIG1 +#define REG_NFC_ECC_STATUS_RESULT NFC_ECC_STATUS_RESULT +#define REG_NFC_CE NFC_CONFIG1 +#define REG_NFC_SP_EN NFC_CONFIG1 +#define REG_NFC_BLS NFC_CONFIG +#define REG_NFC_WPC NFC_WRPROT +#define REG_START_BLKADDR NFC_UNLOCKSTART_BLKADDR +#define REG_END_BLKADDR NFC_UNLOCKEND_BLKADDR +#define REG_NFC_RST NFC_CONFIG1 + +/* NFC V1/V2 Specific MACRO functions definitions */ + +#define raw_write(v,a) __raw_writew(v,a) +#define raw_read(a) __raw_readw(a) + +#define NFC_SET_BLS(val) val + +#define UNLOCK_ADDR(start_addr,end_addr) \ + raw_write(start_addr,REG_START_BLKADDR);\ + raw_write(end_addr,REG_END_BLKADDR); + +#define NFC_SET_WPC(val) val + +/* NULL Definitions */ +#define ACK_OPS +#define NFC_SET_RBA(val,buf_id) + +#define READ_2K_PAGE send_read_page(0);\ + send_read_page(1);\ + send_read_page(2);\ + send_read_page(3); + +#define PROG_2K_PAGE send_prog_page(0);\ + send_prog_page(1);\ + send_prog_page(2);\ + send_prog_page(3); + +#define CHECK_NFC_RB 1 + +#endif + +#endif /* MXCND_H */ |