X-Git-Url: https://git.karo-electronics.de/?a=blobdiff_plain;f=packages%2Fdevs%2Fflash%2Farm%2Fmxc%2Fv2_0%2Fsrc%2Fmxc_nfc.c;h=7b19ff0ef19488de8046f03c2bdb61a9a955644e;hb=84d27734bc516723cef57f3f9564d1f54675cb4c;hp=c1f704b099ec791a7378c93522398f867430441b;hpb=e9c95ab24ba03bb83084777ddbb405d8bb54f041;p=karo-tx-redboot.git diff --git a/packages/devs/flash/arm/mxc/v2_0/src/mxc_nfc.c b/packages/devs/flash/arm/mxc/v2_0/src/mxc_nfc.c index c1f704b0..7b19ff0e 100644 --- a/packages/devs/flash/arm/mxc/v2_0/src/mxc_nfc.c +++ b/packages/devs/flash/arm/mxc/v2_0/src/mxc_nfc.c @@ -84,6 +84,7 @@ #include #include #include +#include #include #include #include @@ -94,7 +95,9 @@ #define _FLASH_PRIVATE_ #include +#ifdef CYGHWR_FLASH_NAND_BBT_HEADER #include CYGHWR_FLASH_NAND_BBT_HEADER +#endif #include @@ -118,8 +121,8 @@ CYG_MACRO_END #define MXC_UNLOCK_BLK_END 0xFFFF extern unsigned int hal_timer_count(void); -int nfc_program_region(flash_addr_t addr, u8 *buf, u32 len); -int nfc_erase_region(flash_addr_t addr, u32 len, bool skip_bad, bool verbose); +static int nfc_program_region(flash_addr_t addr, u8 *buf, u32 len); +static int nfc_erase_region(flash_addr_t addr, u32 len, bool skip_bad, bool verbose); static int nfc_write_pg_random(u32 pg_no, u32 pg_off, u8 *buf, u32 ecc_force); static int nfc_read_pg_random(u32 pg_no, u32 pg_off, u32 ecc_force, u32 cs_line, @@ -134,10 +137,9 @@ static int nfc_program_blk(u32 ra, u8 *buf, u32 len); static void print_pkt_16(u16 *pkt, u32 len); // globals -static int nand_flash_index = -1; static int g_ecc_enable = true; static int g_spare_only_read_ok = true; -static int g_nfc_debug_level = NFC_DEBUG_NONE; +static int g_nfc_debug_level = NFC_DEBUG_DEF; static bool g_nfc_debug_measure = false; static bool g_is_2k_page = false; static unsigned int g_block_offset; @@ -165,7 +167,7 @@ CYG_MACRO_END #define NAND_CONFIGURATION1_REG 0xDEADEEEE #define NFC_FLASH_CONFIG2_REG 0xDEADEEEE #define NFC_FLASH_CONFIG2_ECC_EN 0xDEADEEEE -#define write_nfc_ip_reg(a, b) +#define write_nfc_ip_reg(a, b) CYG_EMPTY_STATEMENT #endif #ifndef MXCFLASH_SELECT_MULTI @@ -175,10 +177,19 @@ void nandflash_query(void *data) #endif { u32 id[2]; + + nfc_printf(NFC_DEBUG_MIN, "%s@%d data=%p\n", __FUNCTION__, __LINE__, data); + read_nflash_id(&id[0], 0); - nfc_printf(NFC_DEBUG_MAX, "%s(ID=0x%02x: 0x%02x, 0x%02x, 0x%02x)\n", __FUNCTION__, + nfc_printf(NFC_DEBUG_MIN, "%s(ID=0x%02x: 0x%02x, 0x%02x, 0x%02x)\n", __FUNCTION__, id[0] & 0xff, (id[0] >> 8) & 0xff, (id[0] >> 16) & 0xff, id[0] >> 24); - memcpy(data, id, sizeof(id)); + if (data != NULL) { + nfc_printf(NFC_DEBUG_MAX, "%s@%d copy flash ID from %p to %p\n", + __FUNCTION__, __LINE__, &id[0], data); + memcpy(data, id, sizeof(id)); + } + nfc_printf(NFC_DEBUG_MAX, "%s@%d called from %p\n", __FUNCTION__, __LINE__, + __builtin_return_address(0)); } #ifndef MXCFLASH_SELECT_MULTI @@ -279,21 +290,21 @@ static const flash_dev_info_t *flash_dev_info; static const flash_dev_info_t supported_devices[] = { #include }; -#define NUM_DEVICES NUM_ELEMS(supported_devices) - -#define COL_CYCLE flash_dev_info->col_cycle -#define ROW_CYCLE flash_dev_info->row_cycle -#define NF_PG_SZ ((flash_dev_info->page_size) * num_of_nand_chips) -#define NF_SPARE_SZ ((flash_dev_info->spare_size) * num_of_nand_chips) -#define NF_PG_PER_BLK flash_dev_info->pages_per_block -#define NF_DEV_SZ ((flash_dev_info->device_size) * num_of_nand_chips_for_nandsize) -#define NF_BLK_SZ ((flash_dev_info->block_size) * num_of_nand_chips) -#define NF_BLK_CNT ((flash_dev_info->block_count) / scale_block_cnt) -#define NF_VEND_INFO flash_dev_info->vendor_info -#define NF_OPTIONS flash_dev_info->options -#define NF_BBT_MAX_NR flash_dev_info->bbt_blk_max_nr -#define NF_OPTIONS flash_dev_info->options -#define NF_BI_OFF flash_dev_info->bi_off +#define NUM_DEVICES NUM_ELEMS(supported_devices) + +#define COL_CYCLE flash_dev_info->col_cycle +#define ROW_CYCLE flash_dev_info->row_cycle +#define NF_PG_SZ (flash_dev_info->page_size * num_of_nand_chips) +#define NF_SPARE_SZ (flash_dev_info->spare_size * num_of_nand_chips) +#define NF_PG_PER_BLK flash_dev_info->pages_per_block +#define NF_DEV_SZ (flash_dev_info->device_size * num_of_nand_chips_for_nandsize) +#define NF_BLK_SZ (flash_dev_info->block_size * num_of_nand_chips) +#define NF_BLK_CNT (flash_dev_info->block_count / scale_block_cnt) +#define NF_VEND_INFO flash_dev_info->vendor_info +#define NF_OPTIONS flash_dev_info->options +#define NF_BBT_MAX_NR flash_dev_info->bbt_blk_max_nr +#define NF_OPTIONS flash_dev_info->options +#define NF_BI_OFF flash_dev_info->bi_off #define MXC_NAND_ADDR_MASK (NF_DEV_SZ - 1) #define BLOCK_TO_OFFSET(blk) ((blk) * NF_PG_PER_BLK * NF_PG_SZ) @@ -304,7 +315,7 @@ static const flash_dev_info_t supported_devices[] = { static u8 *g_bbt, *g_page_buf; static u32 g_bbt_sz; -static bool mxcnfc_init_ok = false; +static bool mxcnfc_init_ok; static bool mxc_nfc_scan_done; // this callback allows the platform specific function to be called right @@ -322,7 +333,7 @@ static int flash_enable; static flash_addr_t nfc_l_to_p(flash_addr_t addr) { if (g_block_offset == 0) { - return addr; + return addr & MXC_NAND_ADDR_MASK; } else { flash_addr_t ra; u32 block = (addr & MXC_NAND_ADDR_MASK) / NF_BLK_SZ; @@ -340,19 +351,26 @@ static flash_addr_t nfc_l_to_p(flash_addr_t addr) static int flash_addr_valid(flash_addr_t addr) { + if (!flash_enable) { + nfc_printf(NFC_DEBUG_MIN, "No flash area enabled\n"); + return 1; + } if (addr < flash_region_start || addr >= flash_region_end) { diag_printf("Flash address 0x%08llx is outside valid region 0x%08llx..0x%08llx\n", (u64)addr, (u64)flash_region_start, (u64)flash_region_end); + return 0; } - return addr >= flash_region_start && addr < flash_region_end; + return 1; } /* FIXME: we should pass flash_addr_t as arguments */ void mxc_flash_enable(void *start, void *end) { flash_addr_t s = (unsigned long)start & MXC_NAND_ADDR_MASK; - flash_addr_t e = (unsigned long)end & MXC_NAND_ADDR_MASK; + flash_addr_t e = ((unsigned long)end - 1) & MXC_NAND_ADDR_MASK; + if (start == end) + return; if (flash_enable++ == 0) { flash_region_start = s; flash_region_end = e; @@ -371,8 +389,10 @@ void mxc_flash_enable(void *start, void *end) void mxc_flash_disable(void *start, void *end) { flash_addr_t s = (unsigned long)start & MXC_NAND_ADDR_MASK; - flash_addr_t e = (unsigned long)end & MXC_NAND_ADDR_MASK; + flash_addr_t e = ((unsigned long)end - 1) & MXC_NAND_ADDR_MASK; + if (start == end) + return; if (flash_enable) { if (--flash_enable == 0) { diag_printf1("Disabling flash region 0x%08llx..0x%08llx\n", @@ -408,6 +428,7 @@ nandflash_hwr_init(void) // Look through table for device data flash_dev_query(&id[0]); + flash_dev_info = supported_devices; for (i = 0; i < NUM_DEVICES; i++) { if ((flash_dev_info->device_id == (id[0] & 0xffff)) && @@ -424,7 +445,6 @@ nandflash_hwr_init(void) return FLASH_ERR_DRV_WRONG_PART; } - nand_flash_index = i; mxcnfc_init_ok = true; if (NF_PG_SZ == 2048) { @@ -439,12 +459,12 @@ nandflash_hwr_init(void) nfc_printf(NFC_DEBUG_MED, "%s(): %d out of NUM_DEVICES=%d, id=0x%02x\n", __FUNCTION__, i, NUM_DEVICES, flash_dev_info->device_id); - if (nfc_setup) { + if (nfc_setup) g_nfc_version = nfc_setup(NF_PG_SZ / num_of_nand_chips, flash_dev_info->port_size, - flash_dev_info->type, num_of_nand_chips); - } + flash_dev_info->type, num_of_nand_chips); + diag_printf1("NFC version: %02x\n", g_nfc_version); - if (g_nfc_version == MXC_NFC_V3) { + if (g_nfc_version >= MXC_NFC_V3) { for (i = 2; i <= NUM_OF_CS_LINES; i++) { u32 id_tmp[2]; read_nflash_id(&id_tmp[0], i - 1); @@ -605,6 +625,8 @@ static void nfc_buf_write(unsigned long dst, void *src, u32 len) if (!nfc_verify_addr(dst, len)) { return; } + diag_printf1("Copying %u byte from %p..%p to flash buffer %08lx..%08lx\n", + len, bp, bp + len - 1, dst, dst + len - 1); if (dst & 1) { store_byte(d, 1, *bp); d++; @@ -676,7 +698,7 @@ static void read_nflash_id(u32 *id, u32 cs_line) { volatile u32 *ptr = (volatile u32*)NAND_MAIN_BUF0; - nfc_printf(NFC_DEBUG_MIN, "%s: read flash id from chip %d @ %p\n", + nfc_printf(NFC_DEBUG_MIN, "%s: read flash id from chip %d @ %p\n", __FUNCTION__, cs_line, ptr); NFC_PRESET(MXC_UNLOCK_BLK_END); @@ -686,15 +708,15 @@ static void read_nflash_id(u32 *id, u32 cs_line) start_nfc_addr_ops(FLASH_Read_ID, 0, 0, 0, cs_line, num_of_nand_chips); NFC_DATA_OUTPUT(RAM_BUF_0, FDO_FLASH_ID, g_ecc_enable); - *id++ = *ptr++; - *id++ = *ptr++; + *id++ = *ptr++; + *id++ = *ptr++; } static void mark_blk_bad(unsigned int block, unsigned char *buf, enum blk_bad_type bad_type) { - unsigned int off = block >> 2; // byte offset - each byte can hold status for 4 blocks - unsigned int sft = (block & 3) << 1; // bit shift 0, 2, 4, 6 + unsigned int off = block >> 2; // byte offset - each byte can hold status for 4 blocks + unsigned int sft = (block & 3) << 1; // bit shift 0, 2, 4, 6 unsigned char val = buf[off]; if (block > NF_BLK_CNT) { @@ -739,7 +761,7 @@ static int nfc_is_badblock(u32 block, u8 *buf) res = (buf[off] >> sft) & 0x3; if (res) { addr = BLOCK_TO_OFFSET(block); - diag_printf1("Block %u at %08llx is marked %s (%d) in BBT@%p[%02x] mask %02x\n", + diag_printf1("Block %u at 0x%08llx is marked %s (%d) in BBT@%p[%02x] mask %02x\n", block, (u64)addr, res == BLK_RESERVED ? "reserved" : res == BLK_BAD_FACTORY ? "factory bad" : "runtime bad", res, buf, off, 3 << sft); @@ -798,6 +820,19 @@ static int nfc_is_badblock(u32 block, u8 *buf) return 0; } +static inline void mxc_nfc_buf_clear(unsigned long buf, u8 pattern, int size) +{ + int i; + u16 *p = (u16 *)buf; + u16 fill = pattern; + + fill = (fill << 8) | pattern; + for (i = 0; i < size >> 1; i++) { + p[i] = fill; + } +} + +#ifdef CYGHWR_FLASH_NAND_BBT_HEADER /* * check_short_pattern - [GENERIC] check if a pattern is in the buffer * @buf: the buffer to search @@ -851,18 +886,6 @@ static int mxc_nfc_write_bbt_page(struct nand_bbt_descr *td) return 0; } -static inline void mxc_nfc_buf_clear(unsigned long buf, u8 pattern, int size) -{ - int i; - u16 *p = (u16 *)buf; - u16 fill = pattern; - - fill = (fill << 8) | pattern; - for (i = 0; i < size >> 1; i++) { - p[i] = fill; - } -} - static int mxc_nfc_write_bbt(struct nand_bbt_descr *td, struct nand_bbt_descr *md) { int ret = -1; @@ -961,6 +984,12 @@ static int program_bbt_to_flash(void) { return mxc_nfc_update_bbt(g_mxc_nfc_bbt_main_descr, g_mxc_nfc_bbt_mirror_descr); } +#else +static int program_bbt_to_flash(void) +{ + return 0; +} +#endif /*! * Unconditionally erase a block without checking the BI field. @@ -975,15 +1004,15 @@ static int nfc_erase_blk(u32 ra) u16 flash_status, i; u32 pg_no, pg_off; - if (g_nfc_version == MXC_NFC_V3) { + if (g_nfc_version >= MXC_NFC_V3) { // combine the two commands for erase - writel((FLASH_Start_Erase << 8) | FLASH_Block_Erase, NAND_CMD_REG); + nfc_reg_write((FLASH_Start_Erase << 8) | FLASH_Block_Erase, NAND_CMD_REG); pg_no = ra / NF_PG_SZ; pg_off = ra % NF_PG_SZ; for (i = 0; i < num_of_nand_chips; i++) { start_nfc_addr_ops(FLASH_Block_Erase, pg_no, pg_off, 1, i, num_of_nand_chips); // start auto-erase - writel(NAND_LAUNCH_AUTO_ERASE, NAND_LAUNCH_REG); + nfc_reg_write(NAND_LAUNCH_AUTO_ERASE, NAND_LAUNCH_REG); wait_op_done(); pg_off = 0; } @@ -1037,7 +1066,11 @@ static int nfc_program_blk(u32 ra, u8 *buf, u32 len) buf += NF_PG_SZ; } if (len != 0) { + diag_printf1("Clearing flash buffer from %p..%p\n", g_page_buf + len - 1, + g_page_buf + NF_PG_SZ - 1); memset(g_page_buf + len, 0xFF, NF_PG_SZ - len); + diag_printf1("Copying partial page from %p..%p to %p..%p\n", + buf, buf + len - 1, g_page_buf, g_page_buf + len); memcpy(g_page_buf, buf, len); if (nfc_write_pg_random(ra / NF_PG_SZ, ra % NF_PG_SZ, g_page_buf, 0) != 0) { num_of_nand_chips = temp; @@ -1058,7 +1091,7 @@ static int nfc_program_blk(u32 ra, u8 *buf, u32 len) * * @return FLASH_ERR_OK (0) if successful; non-zero otherwise */ -int nfc_erase_region(flash_addr_t addr, u32 len, bool skip_bad, bool verbose) +static int nfc_erase_region(flash_addr_t addr, u32 len, bool skip_bad, bool verbose) { u32 sz, blk, update = 0, j = 0; @@ -1073,9 +1106,12 @@ int nfc_erase_region(flash_addr_t addr, u32 len, bool skip_bad, bool verbose) diag_printf("Error: invalid length %u (must be > 0 and block aligned)\n", len); return FLASH_ERR_INVALID; } - addr = nfc_l_to_p(addr); + addr &= MXC_NAND_ADDR_MASK; // now addr has to be block aligned for (sz = 0; sz < len; addr += NF_BLK_SZ, j++, sz += NF_BLK_SZ) { + if (!flash_addr_valid(addr)) { + return 0; + } blk = OFFSET_TO_BLOCK(addr); if (skip_bad && nfc_is_badblock(blk, g_bbt)) { diag_printf("\nSkipping bad block %u at addr 0x%08llx\n", @@ -1084,7 +1120,7 @@ int nfc_erase_region(flash_addr_t addr, u32 len, bool skip_bad, bool verbose) } if (nfc_erase_blk(addr) != 0) { diag_printf("\n** Error: Failed to erase block %u at addr 0x%08llx\n", - blk, (u64)addr); + blk, (u64)addr); mark_blk_bad(blk, g_bbt, BLK_BAD_RUNTIME); // we don't need to update the table immediately here since even // with power loss now, we should see the same erase error again. @@ -1114,7 +1150,7 @@ int nfc_erase_region(flash_addr_t addr, u32 len, bool skip_bad, bool verbose) * @param len number of bytes * @return FLASH_ERR_OK (0) if successful; non-zero otherwise */ -int nfc_program_region(flash_addr_t addr, u8 *buf, u32 len) +static int nfc_program_region(flash_addr_t addr, u8 *buf, u32 len) { u32 sz, blk, update = 0, partial_block_size; @@ -1130,8 +1166,9 @@ int nfc_program_region(flash_addr_t addr, u8 *buf, u32 len) return FLASH_ERR_INVALID; } - partial_block_size = addr % NF_BLK_SZ; + partial_block_size = NF_BLK_SZ - (addr % NF_BLK_SZ); + mxc_nfc_buf_clear(NAND_SPAR_BUF0, 0xff, NF_SPARE_SZ); addr = nfc_l_to_p(addr); while (1) { if (!flash_addr_valid(addr)) { @@ -1142,6 +1179,7 @@ int nfc_program_region(flash_addr_t addr, u8 *buf, u32 len) blk = OFFSET_TO_BLOCK(addr); if (nfc_is_badblock(blk, g_bbt)) { diag_printf("\nSkipping bad block %u at addr 0x%08llx\n", blk, addr); + g_block_offset++; goto incr_address; } @@ -1154,6 +1192,7 @@ int nfc_program_region(flash_addr_t addr, u8 *buf, u32 len) mark_blk_bad(blk, g_bbt, BLK_BAD_RUNTIME); // we don't need to update the table immediately here since even // with power loss now, we should see the same program error again. + g_block_offset++; goto incr_address; } diag_printf("."); @@ -1166,7 +1205,6 @@ int nfc_program_region(flash_addr_t addr, u8 *buf, u32 len) incr_address: addr += partial_block_size; partial_block_size = NF_BLK_SZ; - g_block_offset++; } if (update) { if (program_bbt_to_flash() != 0) { @@ -1196,13 +1234,13 @@ int nfc_read_region(flash_addr_t addr, u8 *buf, u32 len) nfc_printf(NFC_DEBUG_MED, "%s: addr=0x%08llx, offset=%03x buf=0x%p, len=0x%08x\n", __FUNCTION__, addr, offset, buf, len); - addr = nfc_l_to_p(addr); if (addr < (u32)flash_info.start || (addr + len) > (u32)flash_info.end || len == 0) { diag_printf("** Error: flash address 0x%08llx..0x%08llx outside valid range %p..%p\n", (u64)addr, (u64)addr + len - 1, flash_info.start, flash_info.end); return FLASH_ERR_INVALID; } + addr = nfc_l_to_p(addr); while (len > 0) { int i; @@ -1283,11 +1321,21 @@ static int nfc_write_pg_random(u32 pg_no, u32 pg_off, u8 *buf, u32 ecc_force) } diag_printf1("%s(0x%x, 0x%x, %d)\n", __FUNCTION__, pg_no, pg_off, ecc_force); + if (g_nfc_version != MXC_NFC_V1) { + int i; - switch (g_nfc_version & 0xf0) { - case MXC_NFC_V3: + for (i = 1; i < NFC_SPARE_BUF_SZ / 16; i++) { + memcpy((void *)(NAND_SPAR_BUF0 + i * NFC_SPARE_BUF_SZ), + (void *)(NAND_SPAR_BUF0 + i * 16), 16); + } + } + if (g_nfc_version >= MXC_NFC_V3) { /* Check if Page size is greater than NFC buffer */ do { + rba = nfc_reg_read(NAND_CONFIGURATION1_REG); + if ((rba >> 4) & 0x7) { + nfc_reg_write(rba & ~0x70, NAND_CONFIGURATION1_REG); + } if (write_count <= NFC_BUFSIZE) { // No need to worry about the spare area nfc_buf_write(NAND_MAIN_BUF0, buf, write_count); @@ -1299,7 +1347,7 @@ static int nfc_write_pg_random(u32 pg_no, u32 pg_off, u8 *buf, u32 ecc_force) buf += NFC_BUFSIZE; } // combine the two commands for program - writel((FLASH_Program << 8) | FLASH_Send_Data, NAND_CMD_REG); + nfc_reg_write((FLASH_Program << 8) | FLASH_Send_Data, NAND_CMD_REG); for (i = start_point; i < num_of_nand_chips; i++) { rba = rba_count * ((NF_PG_SZ / num_of_nand_chips) / 512); @@ -1310,38 +1358,30 @@ static int nfc_write_pg_random(u32 pg_no, u32 pg_off, u8 *buf, u32 ecc_force) } // For ECC - v = readl(NFC_FLASH_CONFIG2_REG) & ~NFC_FLASH_CONFIG2_ECC_EN; + 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_Program, pg_no, pg_off, 0, i, num_of_nand_chips); // start auto-program - writel(NAND_LAUNCH_AUTO_PROG, NAND_LAUNCH_REG); + nfc_reg_write(NAND_LAUNCH_AUTO_PROG, NAND_LAUNCH_REG); if (i < (num_of_nand_chips - i)) wait_for_auto_prog_done(); else wait_op_done(); pg_off = 0; rba_count++; + rba = nfc_reg_read(NAND_CONFIGURATION1_REG); + } + flash_status = NFC_STATUS_READ(); + // check I/O bit 0 to see if it is 0 for success + if ((flash_status & ((0x1 << num_of_nand_chips) - 1)) != 0) { + return -1; } start_point = i; } while (write_count > 0); - flash_status = NFC_STATUS_READ(); - // check I/O bit 0 to see if it is 0 for success - if ((flash_status & ((0x1 << num_of_nand_chips) - 1)) != 0) { - return -1; - } - break; - default: - if (g_nfc_version != MXC_NFC_V1) { - int i; - - for (i = 1; i < NFC_SPARE_BUF_SZ / 16; i++) { - memcpy((void *)(NAND_SPAR_BUF0 + i * NFC_SPARE_BUF_SZ), - (void *)(NAND_SPAR_BUF0 + i * 16), 16); - } - } + } else { nfc_buf_write(NAND_MAIN_BUF0, buf, NF_PG_SZ); #ifdef BARKER_CODE_SWAP_LOC // To replace the data at offset MXC_NAND_BOOT_LOAD_BARKER with @@ -1349,9 +1389,9 @@ static int nfc_write_pg_random(u32 pg_no, u32 pg_off, u8 *buf, u32 ecc_force) if (pg_no == 0) { diag_printf("\n[INFO]: copy data at 0x%x to spare area and set it to 0x%x\n", BARKER_CODE_SWAP_LOC, BARKER_CODE_VAL); - writel(readl(NFC_BASE + BARKER_CODE_SWAP_LOC), NAND_SPAR_BUF0); + nfc_reg_write(nfc_reg_read(NFC_BASE + BARKER_CODE_SWAP_LOC), NAND_SPAR_BUF0); // todo: set BARKER_CODE_VAL and BARKER_CODE_SWAP_LOC for skye, etc. - writel(BARKER_CODE_VAL, NFC_BASE + BARKER_CODE_SWAP_LOC); + nfc_reg_write(BARKER_CODE_VAL, NFC_BASE + BARKER_CODE_SWAP_LOC); } #endif NFC_CMD_INPUT(FLASH_Send_Data); @@ -1380,7 +1420,73 @@ static int nfc_write_pg_random(u32 pg_no, u32 pg_off, u8 *buf, u32 ecc_force) return 0; } -#ifndef NFC_V3_0 +#ifdef NFC_V3_0 +/* + * 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; + int i; + + // 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(); + + for (i = 1; i < NFC_SPARE_BUF_SZ / 16; i++) { + memcpy((void *)(NAND_SPAR_BUF0 + i * 16), + (void *)(NAND_SPAR_BUF0 + i * NFC_SPARE_BUF_SZ), 16); + } + 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(v & ~(0x0100 << cs_line), NAND_STATUS_SUM_REG); + diag_printf("ECC error from NAND_STATUS_SUM_REG(0x%08lx) = 0x%08x\n", + NAND_STATUS_SUM_REG, v); + diag_printf("NAND_ECC_STATUS_RESULT_REG(0x%08lx) = 0x%08x\n", NAND_ECC_STATUS_RESULT_REG, + nfc_reg_read(NAND_ECC_STATUS_RESULT_REG)); + res = -1; + } + return res; +} +#else // for version V1 and V2 of NFC static int nfc_read_pg_random(u32 pg_no, u32 pg_off, u32 ecc_force, u32 cs_line, u32 num_of_nand_chips) @@ -1430,7 +1536,7 @@ static int nfc_read_pg_random(u32 pg_no, u32 pg_off, u32 ecc_force, u32 cs_line, NFC_DATA_OUTPUT(RAM_BUF_3, FDO_PAGE_SPARE, ecc); } if (ecc) { - t1 = readl(ECC_STATUS_RESULT_REG); + t1 = nfc_reg_read(ECC_STATUS_RESULT_REG); if (g_is_2k_page || g_is_4k_page) { t2 = (t1 >> 4) & 0xF; t3 = (t1 >> 8) & 0xF; @@ -1470,7 +1576,7 @@ static int nfc_read_pg_random(u32 pg_no, u32 pg_off, u32 ecc_force, u32 cs_line, // This is needed for certain platforms if (pg_no == 0) { diag_printf("\n[INFO]: copy back data from spare to 0x%x\n", BARKER_CODE_SWAP_LOC); - writel(readl(NAND_SPAR_BUF0), NFC_BASE + BARKER_CODE_SWAP_LOC); + nfc_reg_write(nfc_reg_read(NAND_SPAR_BUF0), NFC_BASE + BARKER_CODE_SWAP_LOC); } #endif @@ -1505,13 +1611,25 @@ static int nfc_write_page(u32 pg_no, u32 pg_off, u32 ecc_force) ecc = 0; } + if (g_nfc_version != MXC_NFC_V1) { + int i; + + for (i = NFC_SPARE_BUF_SZ / 16 - 1; i >= 0; i--) { + memcpy((void *)(NAND_SPAR_BUF0 + i * NFC_SPARE_BUF_SZ), + (void *)(NAND_SPAR_BUF0 + i * 16), 16); + } + } if (g_nfc_version == MXC_NFC_V3) { int i; u32 v; u32 start_point = 0, rba, rba_count = 0; + rba = nfc_reg_read(NAND_CONFIGURATION1_REG); + if ((rba >> 4) & 0x7) { + nfc_reg_write(rba & ~0x70, NAND_CONFIGURATION1_REG); + } // combine the two commands for program - writel((FLASH_Program << 8) | FLASH_Send_Data, NAND_CMD_REG); + nfc_reg_write((FLASH_Program << 8) | FLASH_Send_Data, NAND_CMD_REG); for (i = start_point; i < num_of_nand_chips; i++) { rba = rba_count * ((NF_PG_SZ / num_of_nand_chips) / 512); @@ -1522,14 +1640,14 @@ static int nfc_write_page(u32 pg_no, u32 pg_off, u32 ecc_force) } // For ECC - v = readl(NFC_FLASH_CONFIG2_REG) & ~NFC_FLASH_CONFIG2_ECC_EN; + 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_Program, pg_no, pg_off, 0, i, num_of_nand_chips); // start auto-program - writel(NAND_LAUNCH_AUTO_PROG, NAND_LAUNCH_REG); + nfc_reg_write(NAND_LAUNCH_AUTO_PROG, NAND_LAUNCH_REG); if (i < (num_of_nand_chips - i)) wait_for_auto_prog_done(); else @@ -1537,17 +1655,14 @@ static int nfc_write_page(u32 pg_no, u32 pg_off, u32 ecc_force) pg_off = 0; rba_count++; } - start_point = i; flash_status = NFC_STATUS_READ(); - } else { - if (g_nfc_version != MXC_NFC_V1) { - int i; - - for (i = NFC_SPARE_BUF_SZ / 16 - 1; i >= 0; i--) { - memcpy((void *)(NAND_SPAR_BUF0 + i * NFC_SPARE_BUF_SZ), - (void *)(NAND_SPAR_BUF0 + i * 16), 16); - } + // check I/O bit 0 to see if it is 0 for success + if ((flash_status & ((0x1 << num_of_nand_chips) - 1)) != 0) { + return -1; } + rba = nfc_reg_read(NAND_CONFIGURATION1_REG); + start_point = i; + } else { NFC_CMD_INPUT(FLASH_Send_Data); start_nfc_addr_ops(FLASH_Program, pg_no, pg_off, 0, 0, num_of_nand_chips); @@ -1564,11 +1679,11 @@ static int nfc_write_page(u32 pg_no, u32 pg_off, u32 ecc_force) NFC_CMD_INPUT(FLASH_Program); flash_status = NFC_STATUS_READ(); - } - if ((flash_status & 0x1) != 0) { - diag_printf("** Error: failed to program page %u at addr 0x%08llx\n", - pg_no, (u64)pg_no * NF_PG_SZ + pg_off); - return -1; + if ((flash_status & 0x1) != 0) { + diag_printf("** Error: failed to program page %u at addr 0x%08llx\n", + pg_no, (u64)pg_no * NF_PG_SZ + pg_off); + return -1; + } } return 0; } @@ -1730,7 +1845,7 @@ local_cmd_entry("info", local_cmd_entry("show", "Show a page main/spare areas or spare area only (-s)", - "-f [-s]", + "-f | -b [-s]", nand_show, NAND_cmds ); @@ -1815,24 +1930,33 @@ static void nand_usage(char *why) static u32 curr_addr; static void nand_show(int argc, char *argv[]) { - u32 ra; + u32 ra, block; bool flash_addr_set = false; + bool block_set = false; bool spar_only = false; - struct option_info opts[2]; + struct option_info opts[3]; init_opts(&opts[0], 'f', true, OPTION_ARG_TYPE_NUM, &ra, &flash_addr_set, "NAND FLASH memory byte address"); - init_opts(&opts[1], 's', false, OPTION_ARG_TYPE_FLG, + init_opts(&opts[1], 'b', true, OPTION_ARG_TYPE_NUM, + &block, &block_set, "NAND FLASH memory block number"); + init_opts(&opts[2], 's', false, OPTION_ARG_TYPE_FLG, &spar_only, NULL, "Spare only"); - if (!scan_opts(argc, argv, 2, opts, 2, 0, 0, 0)) { + if (!scan_opts(argc, argv, 2, opts, NUM_ELEMS(opts), NULL, 0, NULL)) { return; } - if (!flash_addr_set) { + if (flash_addr_set && block_set) { + nand_usage("options -f and -b are mutually exclusive"); + return; + } else if (flash_addr_set) { + curr_addr = ra; + } else if (block_set) { + ra = BLOCK_TO_OFFSET(block) + (unsigned long)flash_info.start; + curr_addr = ra; + } else { ra = curr_addr; curr_addr += NF_PG_SZ; - } else { - curr_addr = ra; } if (ra % NF_PG_SZ) { @@ -1872,7 +1996,7 @@ static void nand_read(int argc, char *argv[]) init_opts(&opts[3], 'c', true, OPTION_ARG_TYPE_NUM, &col, &col_set, "column addr"); - if (!scan_opts(argc, argv, 2, opts, 4, 0, 0, 0)) { + if (!scan_opts(argc, argv, 2, opts, NUM_ELEMS(opts), NULL, 0, NULL)) { nand_usage("invalid arguments"); return; } @@ -1915,6 +2039,12 @@ static void nand_read(int argc, char *argv[]) diag_printf("\n** Error: flash address: 0x%08x out of range\n", ra); return; } + if (nfc_is_badblock(OFFSET_TO_BLOCK(ra), g_bbt)) { + diag_printf("\nSkipping bad block %u at addr=0x%08llx\n", + OFFSET_TO_BLOCK(ra), (u64)ra); + ra = (OFFSET_TO_BLOCK(ra) + 1) * NF_BLK_SZ; + continue; + } pg_no = ra / NF_PG_SZ; pg_off = ra % NF_PG_SZ; for (i = 0; i < num_of_nand_chips; i++) { @@ -1957,7 +2087,7 @@ static void nand_write(int argc, char *argv[]) &len, &length_set, "image length [in FLASH]"); init_opts(&opts[3], 'c', true, OPTION_ARG_TYPE_NUM, &col, &col_set, "column addr"); - if (!scan_opts(argc, argv, 2, opts, 4, 0, 0, 0)) { + if (!scan_opts(argc, argv, 2, opts, NUM_ELEMS(opts), NULL, 0, NULL)) { nand_usage("invalid arguments"); return; } @@ -1968,8 +2098,9 @@ static void nand_write(int argc, char *argv[]) } if ((mem_addr < (CYG_ADDRESS)ram_start) || - ((mem_addr+len) >= (CYG_ADDRESS)ram_end)) { - diag_printf("** WARNING: RAM address: %p may be invalid\n", (void *)mem_addr); + ((mem_addr + len) >= (CYG_ADDRESS)ram_end)) { + diag_printf("** WARNING: RAM address range: %p..%p may be invalid\n", + (void *)mem_addr, (void *)(mem_addr + len)); diag_printf(" valid range is %p-%p\n", (void *)ram_start, (void *)ram_end); } @@ -1994,9 +2125,11 @@ static void nand_write(int argc, char *argv[]) mem_addr_st = mem_addr; len_st = len; ra &= MXC_NAND_ADDR_MASK; + + mxc_nfc_buf_clear(NAND_SPAR_BUF0, 0xff, NF_SPARE_SZ); do { if (OFFSET_TO_BLOCK(ra) > (NF_BLK_CNT - 1)) { - diag_printf("\nOut of range: addr=0x%08x\n", ra); + diag_printf("\nFlash address 0x%08x out of range\n", ra); return; } if (nfc_is_badblock(OFFSET_TO_BLOCK(ra), g_bbt)) { @@ -2016,7 +2149,7 @@ static void nand_write(int argc, char *argv[]) } mark_blk_bad(OFFSET_TO_BLOCK(ra), g_bbt, BLK_BAD_RUNTIME); ra = (OFFSET_TO_BLOCK(ra) + 1) * NF_BLK_SZ; //make sure block size aligned - mem_addr = mem_addr_st; // rewind to blocl boundary + mem_addr = mem_addr_st; // rewind to block boundary len = len_st; continue; } @@ -2104,7 +2237,7 @@ static void nand_erase(int argc, char *argv[]) init_opts(&opts[2], 'o', false, OPTION_ARG_TYPE_FLG, &force_erase_set, &force_erase_set, "force erases block"); - if (!scan_opts(argc, argv, 2, opts, 4, 0, 0, 0)) { + if (!scan_opts(argc, argv, 2, opts, NUM_ELEMS(opts), NULL, 0, NULL)) { nand_usage("invalid arguments"); return; } @@ -2113,19 +2246,28 @@ static void nand_erase(int argc, char *argv[]) nand_usage("missing argument"); return; } - if ((ra % NF_BLK_SZ) != 0 || - (len % NF_BLK_SZ) != 0 || len == 0) { - diag_printf("Address or length is not block aligned or length is zero!\n"); + if ((ra % NF_BLK_SZ) != 0) { + diag_printf("Address must be block aligned!\n"); diag_printf("Block size is 0x%x\n", NF_BLK_SZ); return; } + if ((len % NF_BLK_SZ) != 0) { + diag_printf("length must be block aligned!\n"); + diag_printf("Block size is 0x%x\n", NF_BLK_SZ); + return; + } + if (len == 0) { + diag_printf("length must be > 0!\n"); + return; + } - if (!verify_action("About to erase 0x%x bytes from nand offset 0x%x\n", len, ra)) { + if (!verify_action("About to erase 0x%08x bytes from nand offset 0x%08x", len, ra)) { diag_printf("** Aborted\n"); return; } - // now ra is block aligned + diag_printf1("Enabling flash from %p..%p\n", (u8 *)ra, (u8 *)ra + len - 1); + FLASH_Enable((u8 *)ra, (u8 *)ra + len); if (force_erase_set == true) { diag_printf("Force erase ..."); nfc_erase_region(ra, len, 0, 1); @@ -2133,6 +2275,7 @@ static void nand_erase(int argc, char *argv[]) } else { nfc_erase_region(ra, len, 1, 1); } + FLASH_Disable((u8 *)ra, (u8 *)ra + len); diag_printf("\n"); } @@ -2149,7 +2292,7 @@ static void nand_scan(int argc, char *argv[]) init_opts(&opts[1], 'r', false, OPTION_ARG_TYPE_FLG, &force_rescan, NULL, "force low level re-scan"); - if (!scan_opts(argc, argv, 2, opts, 2, 0, 0, 0)) { + if (!scan_opts(argc, argv, 2, opts, NUM_ELEMS(opts), NULL, 0, NULL)) { nand_usage("invalid arguments"); return; } @@ -2192,11 +2335,6 @@ static void nand_info(int argc, char *argv[]) { u32 i, j = 0; - if (nand_flash_index == -1) { - diag_printf("Can't find valid NAND flash: %d\n", __LINE__); - return; - } - diag_printf("\nType:\t\t %s\n", NF_VEND_INFO); diag_printf("Total size:\t 0x%08x bytes (%d MiB)\n", NF_DEV_SZ, NF_DEV_SZ / SZ_1M); diag_printf("Total blocks:\t 0x%x (%d)\n", NF_BLK_CNT, NF_BLK_CNT); @@ -2289,12 +2427,15 @@ static void do_nand_cmds(int argc, char *argv[]) struct cmd *cmd; if (!mxcnfc_init_ok) { + flash_hwr_init(); + if (!mxcnfc_init_ok) { #ifdef CYGHWR_DEVS_FLASH_MXC_MULTI - diag_printf("Warning: NAND flash hasn't been initialized. Try \"factive nand\" first\n\n"); + diag_printf("Warning: NAND flash hasn't been initialized. Try \"factive nand\" first\n\n"); #else - diag_printf("Error: NAND flash hasn't been initialized\n"); + diag_printf("Error: NAND flash hasn't been initialized\n"); #endif - return; + return; + } } if (argc < 2) { @@ -2352,29 +2493,24 @@ static void print_page(u32 addr, bool spare_only) diag_printf("Non page-aligned read not supported here: 0x%x\n", addr); return; } - if (spare_only) { - diag_printf("Error %d: Not supported\n", __LINE__); - return; - } else { - pg_no = addr / NF_PG_SZ; - pg_off = addr % NF_PG_SZ; - for (i = 0; i < num_of_nand_chips; i++) { - if (nfc_read_page(i, pg_no, pg_off) != 0) { - diag_printf("Error %d: uncorrectable. But still printing ...\n", __LINE__); - } - pg_off = 0; - diag_printf("\n============ Printing block(%d) page(%d) ==============\n", - blk_num, pg_num); - - diag_printf("<<<<<<<<< spare area >>>>>>>>>\n"); - print_pkt_16((u16*)NAND_SPAR_BUF0, NF_SPARE_SZ); + pg_no = addr / NF_PG_SZ; + pg_off = addr % NF_PG_SZ; + for (i = 0; i < num_of_nand_chips; i++) { + if (nfc_read_page(i, pg_no, pg_off) != 0) { + diag_printf("Error %d: uncorrectable. But still printing ...\n", __LINE__); + } + pg_off = 0; + diag_printf("\n============ Printing block(%d) page(%d) ==============\n", + blk_num, pg_num); - if (!spare_only) { - diag_printf("<<<<<<<<< main area >>>>>>>>>\n"); - print_pkt_16((u16*)NAND_MAIN_BUF0, NF_PG_SZ / num_of_nand_chips); - } + diag_printf("<<<<<<<<< spare area >>>>>>>>>\n"); + print_pkt_16((u16*)NAND_SPAR_BUF0, NF_SPARE_SZ); - diag_printf("\n"); + if (!spare_only) { + diag_printf("<<<<<<<<< main area >>>>>>>>>\n"); + print_pkt_16((u16*)NAND_MAIN_BUF0, NF_PG_SZ / num_of_nand_chips); } + + diag_printf("\n"); } }