// SPI flash size = 4 MB
static bool init = false;
static cyg_mutex_t nv_mutex;
static unsigned char *e2prom_buf = NULL;
static unsigned long e2prom_sz = SZ_2K;
static unsigned long logical_e2prom_cur_idx = 0;
static unsigned long nr_logical_e2prom = 1;
static unsigned long blk_sz = SZ_64K;
#include "oem-nv-lib.c"
static int program_data(void)
{
cyg_flashaddr_t err_addr;
cyg_flashaddr_t flash_base = NV_FLASH_BYTES_ADDR;
int status;
unsigned long flash_offset;
flash_offset = logical_e2prom_cur_idx * e2prom_sz;
oem_printf("[OEM][%s] logical_e2prom_cur_idx: %d, flash_offset: 0x%x(%dK)\n",
__func__, logical_e2prom_cur_idx, flash_offset, (flash_offset/SZ_1K));
// 1) Mark we will program data
status = cyg_flash_program(flash_base + flash_offset,
e2prom_buf, 2, &err_addr);
if (status != CYG_FLASH_ERR_OK) {
oem_printf("[OEM][%s] 1) flash program err!!\n", __func__);
goto err;
}
// 2) Programming data
status = cyg_flash_program(flash_base + flash_offset + SZ_E2PROM_HDR,
e2prom_buf + SZ_E2PROM_HDR, e2prom_sz - SZ_E2PROM_HDR, &err_addr);
if (status != CYG_FLASH_ERR_OK) {
oem_printf("[OEM][%s] 2) flash program err!!\n", __func__);
goto err;
}
// 3) Mark we have completed programming data
status = cyg_flash_program(flash_base + flash_offset + 2,
e2prom_buf + 2, 2, &err_addr);
if (status != CYG_FLASH_ERR_OK) {
oem_printf("[OEM][%s] 3) flash program err!!\n", __func__);
goto err;
}
return 0;
err:
// TODO:
return -1;
}
static int recovery_of_sudden_power_cut(void)
{
cyg_flashaddr_t err_addr;
cyg_flashaddr_t flash_base = NV_FLASH_BYTES_ADDR;
int i;
int status;
unsigned long flash_offset;
for (i = logical_e2prom_cur_idx; i > 0; i--) {
flash_offset = i * e2prom_sz;
status = cyg_flash_read(flash_base + flash_offset, e2prom_buf, e2prom_sz, &err_addr);
if (status != CYG_FLASH_ERR_OK) {
oem_printf("[OEM][%s] flash read err!!\n", __func__);
goto err;
}
// little endian
//oem_printf("magic: 0x%x\n", ((unsigned int*)e2prom_buf)[0]);
if (((unsigned int *)e2prom_buf)[0] == 0xaaaa5555) {
oem_printf("[OEM] i: %d, logical_e2prom_cur_idx: %d\n", i, logical_e2prom_cur_idx);
break;
}
}
if (i != logical_e2prom_cur_idx) {
oem_printf("[OEM][%s] call cyg_flash_erase()\n", __func__);
cyg_flash_erase(flash_base, blk_sz, &err_addr);
logical_e2prom_cur_idx = 0;
if (program_data() < 0) {
goto err;
}
}
return 0;
err:
return -1;
}
static void show_flash_ptn(void)
{
// uboot
// offset: 0, size: 192K
// for CFG_set & CFG_get(User config, Switch parameter)
// Bottom-Boot flsh_cfg_off: 16K, flsh_cfg_sz: 20K
// Top-Boot flsh_cfg_off: 4M - 20K, flsh_cfg_sz: 20K
// !!No-Boot flsh_cfg_off: 196K(0x31000), flsh_cfg_sz: 20K
//oem_printf("[OEM] flsh_cfg_off: 0x%x, flsh_cfg_sz: 0x%x\n", flsh_cfg_off, flsh_cfg_sz);
// for emulating eeprom to save MAC ADDR(RF parameter)
// Bottom-Boot flsh_cfg_boot_off: 12K
// Top-Boot flsh_cfg_boot_off: 60K
// !!No-Boot flsh_cfg_boot_off: 256K(0x40000), size: 512B
oem_printf("[OEM] flsh_cfg_boot_off: 0x%x(%dK)\n", flsh_cfg_boot_off,
(flsh_cfg_boot_off/SZ_1K));
// for eCos firmware and size
// Bottom-Boot flsh_cfg_fwm_off: 64K, flsh_cfg_fwm_sz: 4M - 64K
// Top-Boot flsh_cfg_fwm_off: 64K, flsh_cfg_sz: 4M - 64K - 20K
// !!No-Boot flsh_cfg_fwm_off: 320K(0x50000), flsh_cfg_sz: 4M - 320K
oem_printf("[OEM] flsh_cfg_fwm_off: 0x%x(%dK), flsh_cfg_fwm_sz: 0x%x(%dK)\n",
flsh_cfg_fwm_off, (flsh_cfg_fwm_off/SZ_1K),
flsh_cfg_fwm_sz, (flsh_cfg_fwm_sz/SZ_1K));
// for OEM NV read & write
oem_printf("[OEM] flsh_nv_off: 0x%x(%dK)\n", NV_FLASH_BYTES_ADDR,
NV_FLASH_BYTES_ADDR/SZ_1K);
}
API int nv_init(void)
{
cyg_flash_info_t cfi;
cyg_flashaddr_t err_addr;
cyg_flashaddr_t flash_base = NV_FLASH_BYTES_ADDR;
int status;
unsigned long flash_offset;
///
show_flash_ptn();
oem_printf("[OEM] nv memory used size: %d Bytes\n", get_nvm_size());
///
// Initializing the FLASH library
cyg_flash_set_global_printf((cyg_flash_printf *)&diag_printf);
cyg_flash_init(NULL);
if (cyg_flash_get_info(0, &cfi) == CYG_FLASH_ERR_OK) {
if (cfi.block_info) {
blk_sz = cfi.block_info->block_size;
// nr_logical_e2prom should be >= 1
nr_logical_e2prom = blk_sz / e2prom_sz;
oem_printf("[OEM] nr_logical_e2prom: %d\n", nr_logical_e2prom);
oem_printf("[OEM] start_addr: 0x%x, end_addr: 0x%x, num_block_infos: %d, "
"block_size: %d, blocks: %d\n",
cfi.start, cfi.end, cfi.num_block_infos,
cfi.block_info->block_size, cfi.block_info->blocks);
if (!e2prom_buf) {
e2prom_buf = (unsigned char *)malloc(e2prom_sz);
if (!e2prom_buf) {
oem_printf("[OEM][%s] Can not allocate memory for e2prom_buf!!\n", __func__);
goto err;
}
}
for (logical_e2prom_cur_idx = 0; logical_e2prom_cur_idx < nr_logical_e2prom;
logical_e2prom_cur_idx++) {
flash_offset = logical_e2prom_cur_idx * e2prom_sz;
status = cyg_flash_read(flash_base + flash_offset, e2prom_buf, e2prom_sz, &err_addr);
if (status != CYG_FLASH_ERR_OK) {
logical_e2prom_cur_idx = 0;
oem_printf("[OEM][%s] flash read err!!\n", __func__);
goto err;
}
if (e2prom_buf[0] == 0xff &&
e2prom_buf[1] == 0xff &&
e2prom_buf[2] == 0xff &&
e2prom_buf[3] == 0xff) {
oem_printf("[OEM][%s] Got a free logical e2prom idx: %d\n",
__func__, logical_e2prom_cur_idx);
break;
}
}
oem_printf("[OEM][%s] before chng, logical e2prom idx: %d\n",
__func__, logical_e2prom_cur_idx);
if (logical_e2prom_cur_idx == nr_logical_e2prom) {
cyg_flash_erase(flash_base, blk_sz, &err_addr);
logical_e2prom_cur_idx = 0;
if (program_data() < 0) {
goto err;
}
} else if (logical_e2prom_cur_idx > 0 && logical_e2prom_cur_idx < nr_logical_e2prom) {
logical_e2prom_cur_idx--;
}
if (recovery_of_sudden_power_cut() < 0) {
goto err;
}
init = true;
}
}
cyg_mutex_init(&nv_mutex);
return 0;
err:
return -1;
}
API int nv_read(nv_items_enum_t id, u8 *buf, int len)
{
cyg_flashaddr_t err_addr;
// flash_base is where in the flash to read from, it is a byte address,
// not sector address.
cyg_flashaddr_t flash_base = NV_FLASH_BYTES_ADDR;
int status;
unsigned long flash_offset = 0;
long nv_offset = NV_OFFSET(id);
unsigned long nv_sz = NV_SZ(id);
cyg_mutex_lock(&nv_mutex);
if (!init) {
if (false == nv_init()) {
goto err;
}
}
if (nv_offset < 0) {
goto err;
}
if (nv_sz > len) {
nv_sz = len;
}
flash_offset = logical_e2prom_cur_idx * e2prom_sz;
status = cyg_flash_read(flash_base + flash_offset + nv_offset, (void *)buf, nv_sz, &err_addr);
if (status != CYG_FLASH_ERR_OK) {
oem_printf("[OEM][%s] flash read err!!\n", __func__);
goto err;
}
cyg_mutex_unlock(&nv_mutex);
oem_printf("[OEM][%s] succeeded in reading nv_%d, nv_sz: %d Bytes "
"@logical_e2prom_cur_idx: %d\n", __func__, id, nv_sz,
logical_e2prom_cur_idx);
return nv_sz;
err:
cyg_mutex_unlock(&nv_mutex);
return -1;
}
API int nv_write(nv_items_enum_t id, u8 *buf, int len)
{
unsigned char magic[] = {0x55, 0x55, 0xaa, 0xaa};
cyg_flashaddr_t err_addr;
// flash_base is where in the flash to write from, it is a byte address,
// not sector address.
cyg_flashaddr_t flash_base = NV_FLASH_BYTES_ADDR;
int status;
unsigned long flash_offset = 0;
long nv_offset = NV_OFFSET(id);
unsigned long nv_sz = NV_SZ(id);
cyg_mutex_lock(&nv_mutex);
if (!init) {
if (false == nv_init()) {
goto err;
}
}
if (nv_offset < 0) {
goto err;
}
if (nv_sz > len) {
nv_sz = len;
}
flash_offset = logical_e2prom_cur_idx * e2prom_sz;
status = cyg_flash_read(flash_base + flash_offset, e2prom_buf, e2prom_sz, &err_addr);
if (status != CYG_FLASH_ERR_OK) {
oem_printf("[OEM][%s] flash read err!!\n", __func__);
goto err;
}
memcpy(e2prom_buf, magic, sizeof(magic));
memcpy(e2prom_buf + nv_offset, buf, nv_sz);
#if defined(BATCH_COMMIT)
cyg_mutex_unlock(&nv_mutex);
return nv_sz;
#else
// No any data in e2prom, so check here
if (0 == logical_e2prom_cur_idx) {
status = cyg_flash_read(flash_base, buf, 4, &err_addr);
if (status != CYG_FLASH_ERR_OK) {
oem_printf("[OEM][%s] Oops here, check it manually\n", __func__);
} else if (CYG_FLASH_ERR_OK == status && buf[0] == 0xff &&
buf[1] == 0xff &&
buf[2] == 0xff &&
buf[3] == 0xff) {
oem_printf("[OEM][%s] do not add e2prom cur index\n", __func__);
} else {
logical_e2prom_cur_idx++;
}
} else {
logical_e2prom_cur_idx++;
}
if (logical_e2prom_cur_idx >= nr_logical_e2prom) {
logical_e2prom_cur_idx = 0;
cyg_flash_erase(flash_base, blk_sz, &err_addr);
}
if (program_data() < 0) {
goto err;
}
cyg_mutex_unlock(&nv_mutex);
return nv_sz;
#endif
err:
cyg_mutex_unlock(&nv_mutex);
return -1;
}
#if defined(BATCH_COMMIT)
API int nv_commit(void)
{
cyg_flashaddr_t err_addr;
cyg_flashaddr_t flash_base = NV_FLASH_BYTES_ADDR;
int status;
u8 buf[4];
cyg_mutex_lock(&nv_mutex);
// No any data in e2prom, so check here
if (0 == logical_e2prom_cur_idx) {
status = cyg_flash_read(flash_base, buf, 4, &err_addr);
if (status != CYG_FLASH_ERR_OK) {
oem_printf("[OEM][%s] Oops here, check it manually\n", __func__);
} else if (CYG_FLASH_ERR_OK == status && buf[0] == 0xff &&
buf[1] == 0xff &&
buf[2] == 0xff &&
buf[3] == 0xff) {
oem_printf("[OEM][%s] do not add e2prom cur index\n", __func__);
} else {
logical_e2prom_cur_idx++;
}
} else {
logical_e2prom_cur_idx++;
}
if (logical_e2prom_cur_idx >= nr_logical_e2prom) {
oem_printf("[OEM][%s] need erase block, logical_e2prom_cur_idx: %d\n",
__func__, logical_e2prom_cur_idx);
logical_e2prom_cur_idx = 0;
cyg_flash_erase(flash_base, blk_sz, &err_addr);
}
// 3M = 0x300000
// spi rd 300000 64
// spi wr 300000 55 55 aa aa
// spi er 300000 65536
if (program_data() < 0) {
goto err;
}
cyg_mutex_unlock(&nv_mutex);
oem_printf("[OEM][%s] succeeded in updating logical_e2prom_cur_idx: %d\n",
__func__, logical_e2prom_cur_idx);
return 0;
err:
cyg_mutex_unlock(&nv_mutex);
return -1;
}
#else
API int nv_commit(void)
{
return 0;
}
#endif