#include <pkgconf/hal.h>
#include <cyg/hal/hal_arch.h>
#include <cyg/hal/hal_cache.h>
+#include <cyg/hal/hal_misc.h>
#include <cyg/io/nand_bbt.h>
#include <redboot.h>
#include <stdlib.h>
#define _FLASH_PRIVATE_
#include <cyg/io/flash.h>
+#ifdef CYGHWR_FLASH_NAND_BBT_HEADER
#include CYGHWR_FLASH_NAND_BBT_HEADER
+#endif
#include <cyg/io/imx_nfc.h>
#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,
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;
#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
#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
static const flash_dev_info_t supported_devices[] = {
#include <cyg/io/mxc_nand_parts.inl>
};
-#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)
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
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;
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;
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",
// 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)) &&
return FLASH_ERR_DRV_WRONG_PART;
}
- nand_flash_index = i;
mxcnfc_init_ok = true;
if (NF_PG_SZ == 2048) {
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);
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++;
{
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);
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) {
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);
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
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;
{
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.
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;
}
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;
*
* @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;
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",
}
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.
* @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;
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)) {
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;
}
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(".");
incr_address:
addr += partial_block_size;
partial_block_size = NF_BLK_SZ;
- g_block_offset++;
}
if (update) {
if (program_bbt_to_flash() != 0) {
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;
}
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);
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);
}
// 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
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);
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)
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;
// 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
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);
}
// 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
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);
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;
}
local_cmd_entry("show",
"Show a page main/spare areas or spare area only (-s)",
- "-f <raw page address> [-s]",
+ "-f <raw page address> | -b <block> [-s]",
nand_show,
NAND_cmds
);
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) {
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;
}
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++) {
&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;
}
}
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);
}
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)) {
}
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;
}
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;
}
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);
} else {
nfc_erase_region(ra, len, 1, 1);
}
+ FLASH_Disable((u8 *)ra, (u8 *)ra + len);
diag_printf("\n");
}
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;
}
{
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);
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) {
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");
}
}