X-Git-Url: https://git.kernelconcepts.de/?p=karo-tx-redboot.git;a=blobdiff_plain;f=packages%2Fdevs%2Fflash%2Farm%2Fmxc%2Fv2_0%2Finclude%2Fmxc_nfc_v3.h;h=347e813330504550e995a75c66d8f5c157e3118f;hp=cacf665a23aea4c2246577874070831faccf3e62;hb=43332e15a2dd377c015fa6cc97a4db1534887d06;hpb=0f7b702a94a73bd594f31ef97f2a4d36d9ef4a66 diff --git a/packages/devs/flash/arm/mxc/v2_0/include/mxc_nfc_v3.h b/packages/devs/flash/arm/mxc/v2_0/include/mxc_nfc_v3.h index cacf665a..347e8133 100644 --- a/packages/devs/flash/arm/mxc/v2_0/include/mxc_nfc_v3.h +++ b/packages/devs/flash/arm/mxc/v2_0/include/mxc_nfc_v3.h @@ -55,76 +55,153 @@ #include #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 ((readl(NFC_IPC_REG) & NFC_IPC_AUTO_DONE) == 0) \ - {} \ - write_nfc_ip_reg((readl(NFC_IPC_REG) & ~NFC_IPC_AUTO_DONE), NFC_IPC_REG); \ - } while (0) +#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", \ + __func__); \ + break; \ + } \ + } \ + if (MAX_LOOPS - loops < max_loops) { \ + diag_printf1("%s: auto_prog done after %u loops\n", \ + __FUNCTION__, MAX_LOOPS - loops); \ + max_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() \ - do { \ - while ((readl(NFC_IPC_REG) & NFC_IPC_INT) == 0) \ - {} \ - write_nfc_ip_reg(0, NFC_IPC_REG); \ - } while (0) +#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", \ + __func__); \ + break; \ + } \ + } \ + if (MAX_LOOPS - loops < max_loops) { \ + diag_printf1("%s: NFC ready after %u loops\n", \ + __FUNCTION__, MAX_LOOPS - loops); \ + max_loops = MAX_LOOPS - loops; \ + } \ + nfc_reg_write(0, NFC_IPC_REG); \ + CYG_MACRO_END + +#if 0 +#define nfc_reg_read(r) readl(r) +#define nfc_reg_write(v, r) writel(v, r) +#else +#define nfc_reg_read(r) __nfc_reg_read(r, #r, __func__, __LINE__) +#define nfc_reg_write(v, r) __nfc_reg_write(v, r, #r, __func__, __LINE__) -static void write_nfc_ip_reg(u32 val, u32 reg) +static inline u32 __nfc_reg_read(unsigned long reg, const char *reg_name, + const char *fn, int ln) +{ + u32 val; + + val = readl(reg); + if (g_nfc_debug_level >= NFC_DEBUG_MAX) + diag_printf("%s@%d: Read %08x from %s[%08lx]\n", fn, ln, val, reg_name, reg); + return val; +} + +static inline void __nfc_reg_write(u32 val, unsigned long reg, + const char *reg_name, const char *fn, int ln) { - writel(NFC_IPC_CREQ, NFC_IPC_REG); - while((readl(NFC_IPC_REG) & NFC_IPC_CACK) == 0); + if (g_nfc_debug_level >= NFC_DEBUG_MAX) + diag_printf("%s@%d: Writing %08x to %s[%08lx]\n", fn, ln, val, reg_name, reg); + writel(val, reg); +} +#endif - writel(val, reg); - writel((readl(NFC_IPC_REG) & ~NFC_IPC_CREQ), NFC_IPC_REG); +static void write_nfc_ip_reg(u32 val, u32 reg) +{ + 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); + } + + 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 (MAX_LOOPS - loops < max_loops) { + diag_printf1("%s: NFC ready after %u loops\n", + __FUNCTION__, MAX_LOOPS - loops); + max_loops = MAX_LOOPS - loops; + } + nfc_reg_write(val, reg); + nfc_reg_write((nfc_reg_read(NFC_IPC_REG) & ~NFC_IPC_CREQ), NFC_IPC_REG); } /*! @@ -135,69 +212,55 @@ static void write_nfc_ip_reg(u32 val, u32 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 = readl(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 = readl(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; + } - writel(v, NAND_CONFIGURATION1_REG); + nfc_reg_write(v, NAND_CONFIGURATION1_REG); - writel(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) { - writel(cmd & 0xFFFF, NAND_CMD_REG); - writel(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 = readl(NAND_CONFIGURATION1_REG) & (~0x7071); - v |= (cs_line << 12); - writel(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) +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 readl(NAND_STATUS_SUM_REG); -#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 { - writel(NAND_LAUNCH_AUTO_STAT, NAND_LAUNCH_REG); - status = (readl(NAND_CONFIGURATION1_REG) & 0x00FF0000) >> 16; - } while ((status & 0x40) == 0); // make sure I/O 6 == 1 - /* Get Pass/Fail status */ - status = (readl(NAND_CONFIGURATION1_REG) >> 16) & 0x1; - status_sum |= (status << i); - } - return status_sum; -#endif + if (val != 0) { + diag_printf("NFC STATUS: %04x\n", val); + } + return val; } /* This function uses a global variable for the page size. It shouldn't be a big @@ -207,104 +270,41 @@ static u16 NFC_STATUS_READ(void) */ 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 - writel(0x0, NAND_ADD0_REG + (4 * cs_line)); - writel(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; - } 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; - } - } - writel(add0, NAND_ADD0_REG); - writel(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 - writel(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 = readl(NAND_CONFIGURATION1_REG) & (~0x71); - writel(v, NAND_CONFIGURATION1_REG); - - // For ECC - v = readl(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 - writel((FLASH_Read_Mode1_LG << 8) | FLASH_Read_Mode1, NAND_CMD_REG); - } else { - // just one command is enough for 512 page - writel(FLASH_Read_Mode1, NAND_CMD_REG); - } - - // start auto-read - writel(NAND_LAUNCH_AUTO_READ, NAND_LAUNCH_REG); - wait_op_done(); - - v = readl(NAND_STATUS_SUM_REG); - // test for CS0 ECC error from the STATUS_SUM register - if ((v & (0x0100 << cs_line)) != 0) { - // clear the status - writel((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, - readl(NAND_ECC_STATUS_RESULT_REG)); - res = -1; - } - return res; + 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; + } 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); } /*! @@ -312,7 +312,6 @@ static int nfc_read_pg_random(u32 pg_no, u32 pg_off, u32 ecc_force, u32 cs_line, */ 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_