#include <pkgconf/devs_flash_onmxc.h>
#include "mxc_nand_specifics.h"
-#define PG_2K_DATA_OP_MULTI_CYCLES() false
-#define ADDR_INPUT_SIZE 8
-
-#define NAND_MAIN_BUF0 (NFC_BASE + 0x000)
-#define NAND_MAIN_BUF1 (NFC_BASE + 0x200)
-#define NAND_MAIN_BUF2 (NFC_BASE + 0x400)
-#define NAND_MAIN_BUF3 (NFC_BASE + 0x600)
-#define NAND_MAIN_BUF4 (NFC_BASE + 0x800)
-#define NAND_MAIN_BUF5 (NFC_BASE + 0xA00)
-#define NAND_MAIN_BUF6 (NFC_BASE + 0xC00)
-#define NAND_MAIN_BUF7 (NFC_BASE + 0xE00)
-#define NAND_SPAR_BUF0 (NFC_BASE + 0x1000)
-#define NAND_SPAR_BUF1 (NFC_BASE + 0x1040)
-#define NAND_SPAR_BUF2 (NFC_BASE + 0x1080)
-#define NAND_SPAR_BUF3 (NFC_BASE + 0x10C0)
-#define NAND_SPAR_BUF4 (NFC_BASE + 0x1100)
-#define NAND_SPAR_BUF5 (NFC_BASE + 0x1140)
-#define NAND_SPAR_BUF6 (NFC_BASE + 0x1180)
-#define NAND_SPAR_BUF7 (NFC_BASE + 0x11C0)
+#define PG_2K_DATA_OP_MULTI_CYCLES() false
+#define ADDR_INPUT_SIZE 8
+
+#define NAND_MAIN_BUF0 (NFC_BASE + 0x000)
+#define NAND_MAIN_BUF1 (NFC_BASE + 0x200)
+#define NAND_MAIN_BUF2 (NFC_BASE + 0x400)
+#define NAND_MAIN_BUF3 (NFC_BASE + 0x600)
+#define NAND_MAIN_BUF4 (NFC_BASE + 0x800)
+#define NAND_MAIN_BUF5 (NFC_BASE + 0xA00)
+#define NAND_MAIN_BUF6 (NFC_BASE + 0xC00)
+#define NAND_MAIN_BUF7 (NFC_BASE + 0xE00)
+#define NAND_SPAR_BUF0 (NFC_BASE + 0x1000)
+#define NAND_SPAR_BUF1 (NFC_BASE + 0x1040)
+#define NAND_SPAR_BUF2 (NFC_BASE + 0x1080)
+#define NAND_SPAR_BUF3 (NFC_BASE + 0x10C0)
+#define NAND_SPAR_BUF4 (NFC_BASE + 0x1100)
+#define NAND_SPAR_BUF5 (NFC_BASE + 0x1140)
+#define NAND_SPAR_BUF6 (NFC_BASE + 0x1180)
+#define NAND_SPAR_BUF7 (NFC_BASE + 0x11C0)
// The following defines are not used. Just for compilation purpose
-#define ECC_STATUS_RESULT_REG 0xDEADFFFF
+#define ECC_STATUS_RESULT_REG 0xDEADFFFF
#define NFC_DATA_INPUT(buf_no, earea, en)
#define NFC_DATA_INPUT_2k(buf_no)
// dummy function as it is not needed for automatic operations
#define NFC_ADDR_INPUT(addr)
#define NFC_ARCH_INIT()
-#define NUM_OF_CS_LINES 8
-#define NFC_BUFSIZE 4096
+#define NUM_OF_CS_LINES 8
+#define NFC_BUFSIZE 4096
+#define NFC_SPARE_BUF_SZ 64
enum nfc_internal_buf {
- RAM_BUF_0 = 0x0 << 4,
- RAM_BUF_1 = 0x1 << 4,
- RAM_BUF_2 = 0x2 << 4,
- RAM_BUF_3 = 0x3 << 4,
- RAM_BUF_4 = 0x4 << 4,
- RAM_BUF_5 = 0x5 << 4,
- RAM_BUF_6 = 0x6 << 4,
- RAM_BUF_7 = 0x7 << 4,
+ RAM_BUF_0 = 0x0 << 4,
+ RAM_BUF_1 = 0x1 << 4,
+ RAM_BUF_2 = 0x2 << 4,
+ RAM_BUF_3 = 0x3 << 4,
+ RAM_BUF_4 = 0x4 << 4,
+ RAM_BUF_5 = 0x5 << 4,
+ RAM_BUF_6 = 0x6 << 4,
+ RAM_BUF_7 = 0x7 << 4,
};
enum nfc_output_mode {
- FDO_PAGE_SPARE = 0x0008,
- FDO_SPARE_ONLY = 0x1008, // LSB has to be 0x08
- FDO_FLASH_ID = 0x0010,
- FDO_FLASH_STATUS = 0x0020,
+ FDO_PAGE_SPARE = 0x0008,
+ FDO_SPARE_ONLY = 0x1008, // LSB has to be 0x08
+ FDO_FLASH_ID = 0x0010,
+ FDO_FLASH_STATUS = 0x0020,
};
-#define wait_for_auto_prog_done() \
- do { \
- while ((nfc_reg_read(NFC_IPC_REG) & NFC_IPC_AUTO_DONE) == 0) { \
- } \
- write_nfc_ip_reg((nfc_reg_read(NFC_IPC_REG) & ~NFC_IPC_AUTO_DONE), NFC_IPC_REG); \
- } while (0)
+#if 1
+#define MAX_LOOPS 10000
+#define wait_for_auto_prog_done() \
+ CYG_MACRO_START \
+ int loops = MAX_LOOPS; \
+ static int max_loops = MAX_LOOPS; \
+ while ((nfc_reg_read(NFC_IPC_REG) & NFC_IPC_AUTO_DONE) == 0) { \
+ HAL_DELAY_US(10); \
+ if (loops-- < 0) { \
+ diag_printf("%s: Timeout waiting for prog done\n", __FUNCTION__); \
+ break; \
+ } \
+ } \
+ if (loops < max_loops) { \
+ diag_printf1("%s: auto_prog done after %u loops\n", \
+ __FUNCTION__, MAX_LOOPS - loops); \
+ max_loops = loops; \
+ } \
+ nfc_reg_write((nfc_reg_read(NFC_IPC_REG) & ~NFC_IPC_AUTO_DONE), \
+ NFC_IPC_REG); \
+ CYG_MACRO_END
+
+// Polls the NANDFC to wait for an operation to complete
+#define wait_op_done() \
+ CYG_MACRO_START \
+ int loops = MAX_LOOPS; \
+ static int max_loops = MAX_LOOPS; \
+ while ((nfc_reg_read(NFC_IPC_REG) & NFC_IPC_INT) == 0) { \
+ HAL_DELAY_US(10); \
+ if (loops-- < 0) { \
+ diag_printf("%s: Timeout waiting for NFC ready\n", __FUNCTION__); \
+ break; \
+ } \
+ } \
+ if (loops < max_loops) { \
+ diag_printf1("%s: NFC ready after %u loops\n", \
+ __FUNCTION__, MAX_LOOPS - loops); \
+ max_loops = loops; \
+ } \
+ nfc_reg_write(0, NFC_IPC_REG); \
+ CYG_MACRO_END
+#else
+#define wait_for_auto_prog_done() \
+ CYG_MACRO_START \
+ while ((nfc_reg_read(NFC_IPC_REG) & NFC_IPC_AUTO_DONE) == 0) {
+ }
+ nfc_reg_write((nfc_reg_read(NFC_IPC_REG) & ~NFC_IPC_AUTO_DONE),
+ NFC_IPC_REG);
+ CYG_MACRO_END
// Polls the NANDFC to wait for an operation to complete
-#define wait_op_done() \
- do { \
- while ((nfc_reg_read(NFC_IPC_REG) & NFC_IPC_INT) == 0) \
- {} \
- write_nfc_ip_reg(0, NFC_IPC_REG); \
- } while (0)
+#define wait_op_done()
+ CYG_MACRO_START
+ while ((nfc_reg_read(NFC_IPC_REG) & NFC_IPC_INT) == 0) {
+ }
+ nfc_reg_write(0, NFC_IPC_REG);
+ CYG_MACRO_END
+#endif
-#if 0
+#if 1
+#include <cyg/hal/plf_mmap.h>
#define nfc_reg_write(v, r) __nfc_reg_write(v, (void *)(r), #r, __FUNCTION__)
static inline void __nfc_reg_write(u32 val, void *addr,
const char *reg, const char *fn)
{
- diag_printf1("%s: Writing %08x to %s[%04lx]\n", fn, val, reg,
- (unsigned long)addr & 0x1fff);
+ unsigned long pa;
+ HAL_VIRT_TO_PHYS_ADDRESS((unsigned long)addr, pa);
+ diag_printf1("%s: Writing %08x to %s[%04lx]\n", fn, val, reg, pa);
writel(val, addr);
}
const char *reg, const char *fn)
{
u32 val;
+ unsigned long pa;
+
+ HAL_VIRT_TO_PHYS_ADDRESS((unsigned long)addr, pa);
val = readl(addr);
- diag_printf1("%s: Read %08x from %s[%04lx]\n", fn, val, reg,
- (unsigned long)addr & 0x1fff);
+ diag_printf1("%s: Read %08x from %s[%04lx]\n", fn, val, reg, pa);
return val;
}
#else
static void write_nfc_ip_reg(u32 val, u32 reg)
{
- nfc_reg_write(NFC_IPC_CREQ, NFC_IPC_REG);
- while((nfc_reg_read(NFC_IPC_REG) & NFC_IPC_CACK) == 0);
+ unsigned int ipc = nfc_reg_read(NFC_IPC_REG);
+ int loops = MAX_LOOPS;
+ static int max_loops = MAX_LOOPS;
+
+ if (ipc & NFC_IPC_CACK) {
+ diag_printf("%s: IPC ACK already set!\n", __FUNCTION__);
+ } else {
+ nfc_reg_write(NFC_IPC_CREQ, NFC_IPC_REG);
+ }
- nfc_reg_write(val, reg);
- nfc_reg_write((nfc_reg_read(NFC_IPC_REG) & ~NFC_IPC_CREQ), NFC_IPC_REG);
+ while ((nfc_reg_read(NFC_IPC_REG) & NFC_IPC_CACK) == 0) {
+ HAL_DELAY_US(1);
+ if (loops-- < 0) {
+ diag_printf("%s: Timeout waiting for IPC ready\n", __FUNCTION__);
+ return;
+ }
+ }
+ if (loops < max_loops) {
+ diag_printf("%s: NFC ready after %u loops\n",
+ __FUNCTION__, MAX_LOOPS - loops);
+ max_loops = loops;
+ }
+ nfc_reg_write(val, reg);
+ nfc_reg_write((nfc_reg_read(NFC_IPC_REG) & ~NFC_IPC_CREQ), NFC_IPC_REG);
}
/*!
* @param ecc_en 1 - ecc enabled; 0 - ecc disabled
*/
static void NFC_DATA_OUTPUT(enum nfc_internal_buf buf_no, enum nfc_output_mode mode,
- int ecc_en)
+ int ecc_en)
{
- u32 v = nfc_reg_read(NFC_FLASH_CONFIG2_REG);
+ u32 v = nfc_reg_read(NFC_FLASH_CONFIG2_REG);
- if ((v & NFC_FLASH_CONFIG2_ECC_EN) != 0 && ecc_en == 0) {
- write_nfc_ip_reg(v & ~NFC_FLASH_CONFIG2_ECC_EN, NFC_FLASH_CONFIG2_REG);
- }
- if ((v & NFC_FLASH_CONFIG2_ECC_EN) == 0 && ecc_en != 0) {
- write_nfc_ip_reg(v | NFC_FLASH_CONFIG2_ECC_EN, NFC_FLASH_CONFIG2_REG);
- }
+ if ((v & NFC_FLASH_CONFIG2_ECC_EN) != 0 && ecc_en == 0) {
+ write_nfc_ip_reg(v & ~NFC_FLASH_CONFIG2_ECC_EN, NFC_FLASH_CONFIG2_REG);
+ }
+ if ((v & NFC_FLASH_CONFIG2_ECC_EN) == 0 && ecc_en != 0) {
+ write_nfc_ip_reg(v | NFC_FLASH_CONFIG2_ECC_EN, NFC_FLASH_CONFIG2_REG);
+ }
- v = nfc_reg_read(NAND_CONFIGURATION1_REG);
+ v = nfc_reg_read(NAND_CONFIGURATION1_REG);
- if (mode == FDO_SPARE_ONLY) {
- v = (v & ~0x71) | buf_no | NAND_CONFIGURATION1_SP_EN;
- } else {
- v = (v & ~0x71) | buf_no;
- }
+ if (mode == FDO_SPARE_ONLY) {
+ v = (v & ~0x71) | buf_no | NAND_CONFIGURATION1_SP_EN;
+ } else {
+ v = (v & ~0x71) | buf_no;
+ }
- nfc_reg_write(v, NAND_CONFIGURATION1_REG);
+ nfc_reg_write(v, NAND_CONFIGURATION1_REG);
- nfc_reg_write(mode & 0xFF, NAND_LAUNCH_REG);
- wait_op_done();
+ nfc_reg_write(mode & 0xFF, NAND_LAUNCH_REG);
+ wait_op_done();
}
static void NFC_CMD_INPUT(u32 cmd)
{
- nfc_reg_write(cmd & 0xFFFF, NAND_CMD_REG);
- nfc_reg_write(NAND_LAUNCH_FCMD, NAND_LAUNCH_REG);
- wait_op_done();
+ nfc_reg_write(cmd & 0xFFFF, NAND_CMD_REG);
+ nfc_reg_write(NAND_LAUNCH_FCMD, NAND_LAUNCH_REG);
+ wait_op_done();
}
static void NFC_SET_NFC_ACTIVE_CS(u32 cs_line)
{
- u32 v;
+ u32 v;
- v = nfc_reg_read(NAND_CONFIGURATION1_REG) & (~0x7071);
- v |= (cs_line << 12);
- nfc_reg_write(v, NAND_CONFIGURATION1_REG);
+ v = nfc_reg_read(NAND_CONFIGURATION1_REG) & ~0x7071;
+ v |= (cs_line << 12);
+ nfc_reg_write(v, NAND_CONFIGURATION1_REG);
}
-static u16 NFC_STATUS_READ(void)
+#ifdef IMX51_TO_2
+static inline u16 NFC_STATUS_READ(void)
{
- u32 status;
- u16 status_sum = 0;
- int i;
+ u16 val = nfc_reg_read(NAND_STATUS_SUM_REG);
-#ifdef IMX51_TO_2
- return nfc_reg_read(NAND_STATUS_SUM_REG);
+ if (val != 0) {
+ diag_printf("NFC STATUS: %04x\n", val);
+ }
+ return val;
+}
#else
- /* Cannot rely on STATUS_SUM register due to errata */
- for (i = 0; i < num_of_nand_chips; i++) {
- NFC_SET_NFC_ACTIVE_CS(i);
- do {
- nfc_reg_write(NAND_LAUNCH_AUTO_STAT, NAND_LAUNCH_REG);
- status = (nfc_reg_read(NAND_CONFIGURATION1_REG) & 0x00FF0000) >> 16;
- } while ((status & 0x40) == 0); // make sure I/O 6 == 1
- /* Get Pass/Fail status */
- status = (nfc_reg_read(NAND_CONFIGURATION1_REG) >> 16) & 0x1;
- status_sum |= (status << i);
- }
- return status_sum;
-#endif
+static inline u16 NFC_STATUS_READ(void)
+{
+ u32 status;
+ int i;
+ u16 status_sum = 0;
+
+ /* Cannot rely on STATUS_SUM register due to errata */
+ for (i = 0; i < num_of_nand_chips; i++) {
+ NFC_SET_NFC_ACTIVE_CS(i);
+ do {
+ nfc_reg_write(NAND_LAUNCH_AUTO_STAT, NAND_LAUNCH_REG);
+ status = (nfc_reg_read(NAND_CONFIGURATION1_REG) & 0x00FF0000) >> 16;
+ } while ((status & 0x40) == 0); // make sure I/O 6 == 1
+ /* Get Pass/Fail status */
+ status = (nfc_reg_read(NAND_CONFIGURATION1_REG) >> 16) & 0x1;
+ status_sum |= (status << i);
+ }
+ diag_printf("NFC TO2 STATUS: %04x\n", status_sum);
+ return status_sum;
}
+#endif
/* This function uses a global variable for the page size. It shouldn't be a big
* problem since we don't expect mixed page size nand flash parts on the same IC.
*/
static void start_nfc_addr_ops(u32 ops, u32 pg_no, u16 pg_off, u32 is_erase, u32 cs_line, u32 num_of_chips)
{
- u32 add0, add8, page_number;
- int num_of_bits[] = {0, 0, 1, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 4};
-
- if (ops == FLASH_Read_ID) {
- // issue addr cycle
- nfc_reg_write(0x0, NAND_ADD0_REG + (4 * cs_line));
- nfc_reg_write(NAND_LAUNCH_FADD, NAND_LAUNCH_REG);
- wait_op_done();
- return;
- }
+ u32 add0, add8, page_number;
+ int num_of_bits[] = {0, 0, 1, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 4};
+
+ if (ops == FLASH_Read_ID) {
+ // issue addr cycle
+ nfc_reg_write(0x0, NAND_ADD0_REG + (4 * cs_line));
+ nfc_reg_write(NAND_LAUNCH_FADD, NAND_LAUNCH_REG);
+ wait_op_done();
+ return;
+ }
- if (num_of_chips > 1) {
- page_number = (pg_no << num_of_bits[num_of_chips]) | (cs_line & (num_of_chips - 1));
- } else {
- page_number = pg_no;
- }
- if (is_erase) {
- add0 = page_number;
- add8 = 0;
- } else {
- // for both read and write
- if (g_is_2k_page || g_is_4k_page) {
- // the first two addr cycles are for column addr. Page number starts
- // from the 3rd addr cycle.
- add0 = pg_off | (page_number << 16);
- add8 = page_number >> 16;
+ if (num_of_chips > 1) {
+ page_number = (pg_no << num_of_bits[num_of_chips]) | (cs_line & (num_of_chips - 1));
} else {
- diag_printf("too bad, die\n");
- asm("1: b 1b");
- // For 512B page, the first addr cycle is for column addr. Page number
- // starts from the 2nd addr cycle.
- add0 = (pg_off & 0xFF) | (page_number << 8);
- add8 = page_number >> 24;
+ page_number = pg_no;
}
- }
- nfc_reg_write(add0, NAND_ADD0_REG);
- nfc_reg_write(add8, NAND_ADD8_REG);
-}
-
-/*
- * Do a page read at random address
- *
- * @param pg_no page number offset from 0
- * @param pg_off byte offset within the page
- * @param ecc_force can force ecc to be off. Otherwise, by default it is on
- * unless the page offset is non-zero
- * @param cs_line indicates which NAND of interleaved NAND devices is used
- *
- * @return 0 if successful; non-zero otherwise
- */
-static int nfc_read_pg_random(u32 pg_no, u32 pg_off, u32 ecc_force, u32 cs_line, u32 num_of_chips)
-{
- u32 ecc = NFC_FLASH_CONFIG2_ECC_EN;
- u32 v, res = 0;
-
- // clear the NAND_STATUS_SUM_REG register
- nfc_reg_write(0, NAND_STATUS_SUM_REG);
-
- // the 2nd condition is to test for unaligned page address -- ecc has to be off.
- if (ecc_force == ECC_FORCE_OFF || pg_off != 0 ) {
- ecc = 0;
- }
-
- // Take care of config1 for RBA and SP_EN
- v = nfc_reg_read(NAND_CONFIGURATION1_REG) & (~0x71);
- nfc_reg_write(v, NAND_CONFIGURATION1_REG);
-
- // For ECC
- v = nfc_reg_read(NFC_FLASH_CONFIG2_REG) & (~NFC_FLASH_CONFIG2_ECC_EN);
- // setup config2 register for ECC enable or not
- write_nfc_ip_reg(v | ecc, NFC_FLASH_CONFIG2_REG);
-
- start_nfc_addr_ops(FLASH_Read_Mode1, pg_no, pg_off, 0, cs_line, num_of_chips);
-
- if (g_is_2k_page || g_is_4k_page) {
- // combine the two commands for 2k/4k page read
- nfc_reg_write((FLASH_Read_Mode1_LG << 8) | FLASH_Read_Mode1, NAND_CMD_REG);
- } else {
- // just one command is enough for 512 page
- nfc_reg_write(FLASH_Read_Mode1, NAND_CMD_REG);
- }
-
- // start auto-read
- nfc_reg_write(NAND_LAUNCH_AUTO_READ, NAND_LAUNCH_REG);
- wait_op_done();
-
- v = nfc_reg_read(NAND_STATUS_SUM_REG);
- // test for CS0 ECC error from the STATUS_SUM register
- if ((v & (0x0100 << cs_line)) != 0) {
- // clear the status
- nfc_reg_write((0x0100 << cs_line), NAND_STATUS_SUM_REG);
- diag_printf("ECC error from NAND_STATUS_SUM_REG(0x%x) = 0x%x\n",
- NAND_STATUS_SUM_REG, v);
- diag_printf("NAND_ECC_STATUS_RESULT_REG(0x%x) = 0x%x\n", NAND_ECC_STATUS_RESULT_REG,
- nfc_reg_read(NAND_ECC_STATUS_RESULT_REG));
- res = -1;
- }
- return res;
+ if (is_erase) {
+ add0 = page_number;
+ add8 = 0;
+ } else {
+ // for both read and write
+ if (g_is_2k_page || g_is_4k_page) {
+ // the first two addr cycles are for column addr. Page number starts
+ // from the 3rd addr cycle.
+ add0 = pg_off | (page_number << 16);
+ add8 = page_number >> 16;
+ } else {
+ // For 512B page, the first addr cycle is for column addr. Page number
+ // starts from the 2nd addr cycle.
+ add0 = (pg_off & 0xFF) | (page_number << 8);
+ add8 = page_number >> 24;
+ }
+ }
+ nfc_reg_write(add0, NAND_ADD0_REG);
+ nfc_reg_write(add8, NAND_ADD8_REG);
}
/*!
*/
static void NFC_PRESET(u32 max_block_count)
{
- // not needed. It is done in plf_hardware_init()
+ // not needed. It is done in plf_hardware_init()
}
-
#endif // _MXC_NFC_V3_H_