1200 lines
28 KiB
C
Executable File
1200 lines
28 KiB
C
Executable File
/*
|
|
* Copyright (C) 2017 XRADIO TECHNOLOGY CO., LTD. All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the
|
|
* distribution.
|
|
* 3. Neither the name of XRADIO TECHNOLOGY CO., LTD. nor the names of
|
|
* its contributors may be used to endorse or promote products derived
|
|
* from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include "image/flash.h"
|
|
#include "driver/chip/hal_timer.h"
|
|
#include "driver/chip/hal_xip.h"
|
|
#include "cmd_debug.h"
|
|
#include "cmd_timer.h"
|
|
#include "cmd_util.h"
|
|
#include "cmd_flash.h"
|
|
#include "driver/chip/hal_flash.h"
|
|
#include "driver/hal_dev.h"
|
|
#include "driver/chip/hal_sysctl.h"
|
|
#include "../board/board_common.h"
|
|
|
|
#define MFLASH 0
|
|
|
|
static enum cmd_status cmd_flash_start_exec(char *cmd)
|
|
{
|
|
if (HAL_Flash_Open(MFLASH, 5000) != HAL_OK) {
|
|
CMD_ERR("flash driver open failed\n");
|
|
return CMD_STATUS_FAIL;
|
|
}
|
|
|
|
return CMD_STATUS_OK;
|
|
}
|
|
|
|
static enum cmd_status cmd_flash_stop_exec(char *cmd)
|
|
{
|
|
/* deinie driver */
|
|
if (HAL_Flash_Close(MFLASH) != HAL_OK) {
|
|
CMD_ERR("flash driver close failed\n");
|
|
return CMD_STATUS_FAIL;
|
|
}
|
|
|
|
return CMD_STATUS_OK;
|
|
}
|
|
|
|
#define FLASH_TEST_BUF_SIZE (0x100)
|
|
|
|
/* drv flash erase s=4kb a=0x110000
|
|
*/
|
|
static enum cmd_status cmd_flash_erase_exec(char *cmd)
|
|
{
|
|
int32_t cnt;
|
|
char size_str[8];
|
|
uint32_t addr;
|
|
FlashEraseMode size_type;
|
|
int32_t size;
|
|
uint8_t buf[FLASH_TEST_BUF_SIZE];
|
|
|
|
/* get param */
|
|
cnt = cmd_sscanf(cmd, "s=%7s a=0x%x", size_str, &addr);
|
|
|
|
/* check param */
|
|
if (cnt != 2) {
|
|
CMD_ERR("invalid param number %d\n", cnt);
|
|
return CMD_STATUS_INVALID_ARG;
|
|
}
|
|
|
|
if (cmd_strcmp(size_str, "chip") == 0) {
|
|
size_type = FLASH_ERASE_CHIP;
|
|
size = 0;
|
|
} else if (cmd_strcmp(size_str, "64kb") == 0) {
|
|
size = 0x10000;
|
|
size_type = FLASH_ERASE_64KB;
|
|
} else if (cmd_strcmp(size_str, "32kb") == 0) {
|
|
size_type = FLASH_ERASE_32KB;
|
|
size = 0x8000;
|
|
} else if (cmd_strcmp(size_str, "4kb") == 0) {
|
|
size = 0x1000;
|
|
size_type = FLASH_ERASE_4KB;
|
|
} else {
|
|
CMD_ERR("invalid size %s\n", size_str);
|
|
return CMD_STATUS_INVALID_ARG;
|
|
}
|
|
|
|
/* erase */
|
|
//HAL_Flash_MemoryOf(MFLASH, size_type, addr, &addr);
|
|
if (HAL_Flash_Erase(MFLASH, size_type, addr, 1) != HAL_OK) {
|
|
CMD_ERR("flash erase failed\n");
|
|
return CMD_STATUS_FAIL;
|
|
}
|
|
|
|
while (size > 0) {
|
|
int32_t tmp_size =
|
|
(size < FLASH_TEST_BUF_SIZE) ? size : FLASH_TEST_BUF_SIZE;
|
|
|
|
//CMD_DBG("tmp_size: %d\n", tmp_size);
|
|
|
|
if (HAL_Flash_Read(MFLASH, addr, buf, tmp_size) != HAL_OK) {
|
|
CMD_ERR("flash read failed\n");
|
|
return CMD_STATUS_FAIL;
|
|
}
|
|
|
|
size -= tmp_size;
|
|
addr += tmp_size;
|
|
|
|
while (--tmp_size >= 0) {
|
|
if ((uint8_t)(~(buf[tmp_size])) != 0) {
|
|
CMD_ERR("flash erase failed: read data from flash != 0xFF,"
|
|
" ~data = 0x%x, tmp_size = %d\n",
|
|
(uint8_t)(~(buf[tmp_size])), tmp_size);
|
|
return CMD_STATUS_FAIL;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
return CMD_STATUS_OK;
|
|
}
|
|
|
|
/* drv flash write a=0x110000 s=32
|
|
* or drv flash write a=0x110000 s=32 sa=0x120000
|
|
* or drv flash write a=0x110000 s=32 sa=0x1400000
|
|
*/
|
|
static enum cmd_status cmd_flash_write_exec(char *cmd)
|
|
{
|
|
uint32_t cnt;
|
|
uint32_t waddr, raddr = -1;
|
|
int32_t size;
|
|
uint8_t *wbuf, *wbuf_bk;
|
|
uint8_t *rbuf;
|
|
|
|
/* get param */
|
|
cnt = cmd_sscanf(cmd, "a=0x%x s=%d sa=0x%x", &waddr, &size, &raddr);
|
|
/* check param */
|
|
if (cnt != 3) {
|
|
cnt = cmd_sscanf(cmd, "a=0x%x s=%d", &waddr, &size);
|
|
if (cnt != 2) {
|
|
CMD_ERR("invalid param number %d\n", cnt);
|
|
return CMD_STATUS_INVALID_ARG;
|
|
}
|
|
}
|
|
|
|
cmd_write_respond(CMD_STATUS_OK, "OK");
|
|
|
|
if (size == 0) {
|
|
// special handle
|
|
wbuf = cmd_malloc(size+5);
|
|
if (wbuf == NULL) {
|
|
CMD_ERR("no memory\n");
|
|
return CMD_STATUS_FAIL;
|
|
}
|
|
memset(wbuf, 0, (size+5));
|
|
wbuf[0] = 0x1;
|
|
|
|
if (HAL_Flash_Write(MFLASH, waddr, wbuf, size) != HAL_OK) {
|
|
CMD_ERR("flash write failed\n");
|
|
}
|
|
cmd_free(wbuf);
|
|
return CMD_STATUS_ACKED;
|
|
}
|
|
|
|
wbuf = cmd_malloc(size);
|
|
if (wbuf == NULL) {
|
|
CMD_ERR("no memory\n");
|
|
return CMD_STATUS_FAIL;
|
|
}
|
|
wbuf_bk = wbuf;
|
|
|
|
rbuf = cmd_malloc(size);
|
|
if (rbuf == NULL) {
|
|
CMD_ERR("no memory\n");
|
|
cmd_free(wbuf);
|
|
return CMD_STATUS_FAIL;
|
|
}
|
|
|
|
if (raddr == -1) {
|
|
cmd_raw_mode_enable();
|
|
cmd_raw_mode_read(wbuf, size, 30000);
|
|
} else if ((raddr >= PSRAM_START_ADDR) && (raddr < PSRAM_END_ADDR)) {
|
|
#ifndef CONFIG_PSRAM
|
|
CMD_ERR("open psram when write source data from psram!\n");
|
|
cmd_free(wbuf);
|
|
cmd_free(rbuf);
|
|
return CMD_STATUS_FAIL;
|
|
#endif
|
|
wbuf = (uint8_t *)raddr;
|
|
} else {
|
|
#ifndef CONFIG_XIP
|
|
CMD_ERR("open xip when write source data from xip!\n");
|
|
cmd_free(wbuf);
|
|
cmd_free(rbuf);
|
|
return CMD_STATUS_FAIL;
|
|
#endif
|
|
wbuf = (uint8_t *)raddr;
|
|
}
|
|
|
|
/* write */
|
|
if (HAL_Flash_Write(MFLASH, waddr, wbuf, size) != HAL_OK) {
|
|
CMD_ERR("flash write failed\n");
|
|
}
|
|
|
|
if (HAL_Flash_Read(MFLASH, waddr, rbuf, size) != HAL_OK) {
|
|
CMD_ERR("flash read failed\n");
|
|
}
|
|
|
|
if (raddr == -1) {
|
|
cmd_raw_mode_write(rbuf, size);
|
|
cmd_raw_mode_disable();
|
|
} else {
|
|
print_hex_dump_bytes(rbuf, size);
|
|
}
|
|
|
|
cmd_free(wbuf_bk);
|
|
cmd_free(rbuf);
|
|
|
|
return CMD_STATUS_ACKED;
|
|
}
|
|
|
|
/* drv flash read a=0x10000 s=32
|
|
*/
|
|
static enum cmd_status cmd_flash_read_exec(char *cmd)
|
|
{
|
|
int32_t cnt;
|
|
uint8_t *buf;
|
|
uint32_t addr;
|
|
uint32_t size;
|
|
char *pre_str = "read buf:";
|
|
|
|
/* get param */
|
|
cnt = cmd_sscanf(cmd, "a=0x%x s=%u", &addr, &size);
|
|
|
|
/* check param */
|
|
if (cnt != 2) {
|
|
CMD_ERR("invalid param number %d\n", cnt);
|
|
return CMD_STATUS_INVALID_ARG;
|
|
}
|
|
|
|
cmd_write_respond(CMD_STATUS_OK, "OK");
|
|
|
|
if (size == 0) {
|
|
// special handle
|
|
buf = cmd_malloc(size+5);
|
|
if (buf == NULL) {
|
|
CMD_ERR("no memory\n");
|
|
cmd_free(buf);
|
|
return CMD_STATUS_FAIL;
|
|
}
|
|
|
|
if (HAL_Flash_Read(MFLASH, addr, buf, size) != HAL_OK) {
|
|
CMD_ERR("spi driver read failed\n");
|
|
}
|
|
cmd_free(buf);
|
|
return CMD_STATUS_ACKED;
|
|
}
|
|
|
|
/* read */
|
|
buf = cmd_malloc(size);
|
|
if (buf == NULL) {
|
|
CMD_ERR("no memory\n");
|
|
cmd_free(buf);
|
|
return CMD_STATUS_FAIL;
|
|
}
|
|
|
|
if (HAL_Flash_Read(MFLASH, addr, buf, size) != HAL_OK) {
|
|
CMD_ERR("spi driver read failed\n");
|
|
cmd_free(buf);
|
|
return CMD_STATUS_FAIL;
|
|
}
|
|
|
|
cmd_print_uint8_array(buf, size);
|
|
cmd_raw_mode_write((uint8_t *)pre_str, strlen(pre_str));
|
|
cmd_raw_mode_write(buf, size);
|
|
cmd_free(buf);
|
|
return CMD_STATUS_ACKED;
|
|
}
|
|
|
|
/* drv flash overwrite a=0x110000 s=32
|
|
*/
|
|
static enum cmd_status cmd_flash_overwrite_exec(char *cmd)
|
|
{
|
|
uint32_t cnt;
|
|
uint32_t addr;
|
|
int32_t size;
|
|
uint8_t *wbuf;
|
|
int ret;
|
|
|
|
/* get param */
|
|
cnt = cmd_sscanf(cmd, "a=0x%x s=%d", &addr, &size);
|
|
|
|
/* check param */
|
|
if (cnt != 2) {
|
|
CMD_ERR("invalid param number %d\n", cnt);
|
|
return CMD_STATUS_INVALID_ARG;
|
|
}
|
|
|
|
wbuf = cmd_malloc(size);
|
|
if (wbuf == NULL) {
|
|
CMD_ERR("no memory\n");
|
|
return CMD_STATUS_FAIL;
|
|
}
|
|
|
|
cmd_write_respond(CMD_STATUS_OK, "OK");
|
|
|
|
cmd_raw_mode_enable();
|
|
cmd_raw_mode_read(wbuf, size, 30000);
|
|
|
|
/* write */
|
|
if ((ret = HAL_Flash_Overwrite(MFLASH, addr, wbuf, size)) != HAL_OK) {
|
|
CMD_ERR("flash write failed: %d\n", ret);
|
|
}
|
|
|
|
if ((ret = HAL_Flash_Check(MFLASH, addr, wbuf, size)) != 0) {
|
|
CMD_ERR("flash write not success %d\n", ret);
|
|
}
|
|
|
|
cmd_raw_mode_disable();
|
|
|
|
cmd_free(wbuf);
|
|
|
|
return CMD_STATUS_ACKED;
|
|
}
|
|
|
|
int8_t flash_test_rdwr(uint32_t flash, uint32_t addr, uint32_t max_size, uint8_t *buf)
|
|
{
|
|
uint32_t len = max_size;
|
|
uint8_t *tmp1, *tmp2;
|
|
static uint8_t tmpdata = 0x5a;
|
|
|
|
tmp1 = buf;
|
|
tmp2 = buf + len;
|
|
|
|
cmd_memset(tmp1, tmpdata, len);
|
|
cmd_memset(tmp2, 0, len);
|
|
if (flash_erase(flash, addr, max_size) != 0) {
|
|
printf("Flash Erase failure!(addr: 0x%08x)\r\n", addr);
|
|
return -1;
|
|
}
|
|
|
|
if (flash_write(flash, addr, tmp1, len) != len) {
|
|
printf("Flash Write failure!(addr: 0x%08x)\r\n", addr);
|
|
return -1;
|
|
}
|
|
if (flash_read(flash, addr, tmp2, len) != len) {
|
|
printf("Flash Read failure!(addr: 0x%08x)\r\n", addr);
|
|
return -1;
|
|
}
|
|
if (cmd_memcmp(tmp2, tmp1, len) == 0) {
|
|
tmpdata = ~tmpdata;
|
|
return 0;
|
|
} else {
|
|
printf("Flash w&r check res failure!(addr: 0x%08x)\r\n", addr);
|
|
#if 0
|
|
for (uint32_t i = 0x0; i < 4096; i++) {
|
|
if ((i%16) == 0 && (i != 0))
|
|
printf("\n");
|
|
if (tmp1[i] != tmp2[i])
|
|
printf("\n*****error data pos:%d,tmp1:0x%02x,tmp2:0x%02x*****\n",
|
|
i, tmp1[i], tmp2[i]);
|
|
else
|
|
printf("%02x ", tmp2[i]);
|
|
}
|
|
#endif
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
int8_t flash_test_read(uint32_t flash, uint32_t addr, uint32_t len, uint8_t *buf)
|
|
{
|
|
cmd_memset(buf, 0, len);
|
|
if (flash_read(flash, addr, buf, len) != len)
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
#if (defined FLASH_XIP_OPT_WRITE) && (defined FLASH_XIP_OPT_ERASR)
|
|
#define USER_PRIO 4
|
|
#define USER_STACKSIZE 2048
|
|
|
|
static OS_Thread_t g_user_thread;
|
|
|
|
void timer0_callback(void *arg)
|
|
{
|
|
static uint32_t ti0 = 0;
|
|
|
|
if (++ti0 >= 1000) {
|
|
ti0 = 0;
|
|
printf("%s,%d fn:%p\n", __func__, __LINE__, timer0_callback);
|
|
}
|
|
}
|
|
|
|
void timer1_callback(void *arg)
|
|
{
|
|
static uint32_t ti1 = 0;
|
|
|
|
if (++ti1 >= 1000) {
|
|
ti1 = 0;
|
|
printf("%s,%d fn:%p\n", __func__, __LINE__, timer1_callback);
|
|
}
|
|
}
|
|
|
|
static HAL_Status timer_inital(TIMER_ID id)
|
|
{
|
|
TIMER_InitParam param;
|
|
|
|
param.cfg = HAL_TIMER_MakeInitCfg(TIMER_MODE_REPEAT, TIMER_CLK_SRC_HFCLK,
|
|
TIMER_CLK_PRESCALER_4); /* 10M */
|
|
param.period = 10000;
|
|
param.isEnableIRQ = 1;
|
|
if (id == TIMER0_ID)
|
|
param.callback = timer0_callback;
|
|
else
|
|
param.callback = timer1_callback;
|
|
param.arg = (void *)id;
|
|
if (HAL_TIMER_Init((TIMER_ID)id, ¶m) != HAL_OK) {
|
|
return HAL_ERROR;
|
|
}
|
|
HAL_TIMER_Start((TIMER_ID)id);
|
|
|
|
return HAL_OK;
|
|
}
|
|
|
|
#define FLASH_TEST_START_ADD 0x180000 /* 1.5M */
|
|
#define FLASH_TEST_END_ADD 0x200000 /* 2M */
|
|
#define FLASH_TEST_ADD_STEP 0x1000 /* 4K */
|
|
#define FLASH_TEST_LOOP_CNT 1000
|
|
|
|
void optimize_press_task(void *arg)
|
|
{
|
|
uint32_t erase_cnt = 0;
|
|
uint32_t write_add = FLASH_TEST_START_ADD, read_add = 0;
|
|
int status = 0;
|
|
uint32_t cnt = 0, read_len = 1;
|
|
uint8_t *buf = cmd_malloc(FLASH_TEST_ADD_STEP * 2 + 16);
|
|
|
|
printf("run user task per 100ms...%d\n", erase_cnt);
|
|
while (1) {
|
|
status = flash_test_rdwr(0, write_add, FLASH_TEST_ADD_STEP, buf);
|
|
if (status < 0) {
|
|
printf("\nstop..addr: 0x%08x, earse_cnt: %d\n",
|
|
write_add, erase_cnt);
|
|
break;
|
|
}
|
|
|
|
if (read_len > FLASH_TEST_ADD_STEP)
|
|
read_len = 1;
|
|
status = flash_test_read(0, read_add, read_len, buf);
|
|
if (status < 0) {
|
|
printf("\nstop..addr: 0x%08x, earse_cnt: %d\n",
|
|
read_add, erase_cnt);
|
|
break;
|
|
}
|
|
if (read_add < FLASH_TEST_END_ADD) {
|
|
read_add += read_len;
|
|
} else {
|
|
printf("addr: 0x%08x, read times reached max....\n",
|
|
read_add);
|
|
read_add = 0;
|
|
}
|
|
read_len++;
|
|
|
|
if (++erase_cnt >= FLASH_TEST_LOOP_CNT) {
|
|
erase_cnt = 0;
|
|
if (write_add < FLASH_TEST_END_ADD) {
|
|
write_add += FLASH_TEST_ADD_STEP;
|
|
} else {
|
|
printf("addr: 0x%08x, Erase times reached max....\n",
|
|
write_add);
|
|
write_add = FLASH_TEST_START_ADD;
|
|
}
|
|
}
|
|
OS_MSleep(50);
|
|
++cnt;
|
|
if ((cnt % 200) == 1)
|
|
printf("%s cnt:%d radd:%x wadd:%x\n",
|
|
__func__, cnt, read_add, write_add);
|
|
}
|
|
printf("%s exit\n", __func__);
|
|
cmd_free(buf);
|
|
HAL_TIMER_Stop(TIMER0_ID);
|
|
OS_ThreadDelete(NULL);
|
|
}
|
|
|
|
static enum cmd_status cmd_flash_optimize_exec(char *cmd)
|
|
{
|
|
uint32_t cnt, tn;
|
|
|
|
printf("%s\n", __func__);
|
|
cnt = cmd_sscanf(cmd, "%d", &tn);
|
|
|
|
/* check param */
|
|
if (cnt != 1) {
|
|
CMD_ERR("invalid param number %d\n", cnt);
|
|
return CMD_STATUS_INVALID_ARG;
|
|
}
|
|
|
|
if (tn > 0) {
|
|
timer_inital(TIMER0_ID);
|
|
if (tn >= 2)
|
|
timer_inital(TIMER1_ID);
|
|
}
|
|
|
|
if (OS_ThreadCreate(&g_user_thread,
|
|
"flash_optm",
|
|
optimize_press_task,
|
|
NULL,
|
|
USER_PRIO,
|
|
USER_STACKSIZE) != OS_OK) {
|
|
printf("create user task failed!\r\n");
|
|
return CMD_STATUS_FAIL;
|
|
}
|
|
|
|
return CMD_STATUS_OK;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
*FLASH_READ_NORMAL_MODE = 1 << 0, ->1
|
|
*FLASH_READ_FAST_MODE = 1 << 1, ->2
|
|
*FLASH_READ_DUAL_O_MODE = 1 << 2, ->4
|
|
*FLASH_READ_DUAL_IO_MODE = 1 << 3, ->8
|
|
*FLASH_READ_QUAD_O_MODE = 1 << 4, ->16
|
|
*FLASH_READ_QUAD_IO_MODE = 1 << 5, ->32
|
|
*FLASH_READ_QPI_MODE = 1 << 6, ->64
|
|
*/
|
|
static enum cmd_status cmd_flash_set_rmode_exec(char *cmd)
|
|
{
|
|
uint32_t cnt;
|
|
uint32_t rmod;
|
|
char rmod_str[10];
|
|
|
|
/* get param */
|
|
cnt = cmd_sscanf(cmd, "rmod=%9s", rmod_str);
|
|
|
|
/* check param */
|
|
if (cnt != 1) {
|
|
CMD_ERR("invalid param number %d\n", cnt);
|
|
return CMD_STATUS_INVALID_ARG;
|
|
}
|
|
|
|
if (cmd_strcmp(rmod_str, "normal") == 0) {
|
|
rmod = 0x1;
|
|
} else if (cmd_strcmp(rmod_str, "fast") == 0) {
|
|
rmod = 0x2;
|
|
} else if (cmd_strcmp(rmod_str, "dual_o") == 0) {
|
|
rmod = 0x4;
|
|
} else if (cmd_strcmp(rmod_str, "dual_io") == 0) {
|
|
rmod = 0x8;
|
|
} else if (cmd_strcmp(rmod_str, "quad_o") == 0) {
|
|
rmod = 0x10;//16
|
|
} else if (cmd_strcmp(rmod_str, "quad_io") == 0) {
|
|
rmod = 0x20;//32
|
|
} else if (cmd_strcmp(rmod_str, "qpi") == 0) {
|
|
rmod = 0x40;//64
|
|
} else {
|
|
CMD_ERR("invalid rmod %s\n", rmod_str);
|
|
return CMD_STATUS_INVALID_ARG;
|
|
}
|
|
|
|
if (HAL_Flash_Ioctl(MFLASH, FLASH_SET_READ_MODE, rmod) != HAL_OK) {
|
|
CMD_ERR("set flash read mode failed\n");
|
|
return CMD_STATUS_FAIL;
|
|
}
|
|
|
|
return CMD_STATUS_OK;
|
|
}
|
|
|
|
/*
|
|
*FLASH_PAGEPROGRAM = 1 << 0, ->1
|
|
*FLASH_QUAD_PAGEPROGRAM = 1 << 1, ->2
|
|
*/
|
|
static enum cmd_status cmd_flash_set_program_mode_exec(char *cmd)
|
|
{
|
|
/* deinie driver */
|
|
uint32_t cnt;
|
|
uint32_t wmod;
|
|
char wmod_str[10];
|
|
|
|
/* get param */
|
|
cnt = cmd_sscanf(cmd, "wmod=%9s", wmod_str);
|
|
|
|
/* check param */
|
|
if (cnt != 1) {
|
|
CMD_ERR("invalid param number %d\n", cnt);
|
|
return CMD_STATUS_INVALID_ARG;
|
|
}
|
|
|
|
if (cmd_strcmp(wmod_str, "page") == 0) {
|
|
wmod = 0x1;
|
|
} else if (cmd_strcmp(wmod_str, "quad_page") == 0) {
|
|
wmod = 0x2;
|
|
} else {
|
|
CMD_ERR("invalid wmod %s\n", wmod_str);
|
|
return CMD_STATUS_INVALID_ARG;
|
|
}
|
|
|
|
if (HAL_Flash_Ioctl(MFLASH, FLASH_SET_PAGEPROGRAM_MODE, wmod) != HAL_OK) {
|
|
CMD_ERR("set flash pageprogram mode failed\n");
|
|
return CMD_STATUS_FAIL;
|
|
}
|
|
|
|
return CMD_STATUS_OK;
|
|
}
|
|
|
|
/*
|
|
* flash press s=0x100000 e=0x1FF000 b=8192 l=50
|
|
*
|
|
* at least run one time when close xip for this test
|
|
*/
|
|
#define FLAH_WR_PRESS_DEBUG_ON 1
|
|
#define FLAH_WR_PRESS_TEST_DEBUG_SIZE (500 * 1024)
|
|
|
|
static void cmd_flash_press_test_task(void *arg)
|
|
{
|
|
uint32_t ret;
|
|
uint32_t addr, size, len, pos, write_pos;
|
|
uint32_t test_cnt;
|
|
uint8_t *wbuf, *rbuf;
|
|
uint32_t cnt, saddr, eaddr, bs, loop;
|
|
|
|
/* get param */
|
|
cnt = cmd_sscanf((char *)arg, "s=0x%x e=0x%x b=%d l=%d",
|
|
&saddr, &eaddr, &bs, &loop);
|
|
/* check param */
|
|
if (cnt != 4) {
|
|
CMD_ERR("invalid param number %d\n", cnt);
|
|
goto fail;
|
|
}
|
|
if ((eaddr - saddr) < bs) {
|
|
CMD_ERR("(end addr - start addr) must > buf size !\n");
|
|
goto fail;
|
|
}
|
|
#if FLAH_WR_PRESS_DEBUG_ON
|
|
uint32_t debug_size, debug_size_unit;
|
|
|
|
debug_size = FLAH_WR_PRESS_TEST_DEBUG_SIZE;
|
|
debug_size_unit = FLAH_WR_PRESS_TEST_DEBUG_SIZE;
|
|
#endif
|
|
|
|
len = bs;
|
|
addr = saddr;
|
|
size = eaddr - addr;
|
|
|
|
test_cnt = 0;
|
|
pos = len;
|
|
write_pos = 0;
|
|
|
|
wbuf = cmd_malloc(len);
|
|
if (wbuf == NULL) {
|
|
CMD_ERR("no memory, malloc size %d fail\n", len);
|
|
goto fail;
|
|
}
|
|
memset(wbuf, 0, len);
|
|
|
|
rbuf = cmd_malloc(len);
|
|
if (rbuf == NULL) {
|
|
CMD_ERR("no memory, malloc size %d fail\n", len);
|
|
cmd_free(wbuf);
|
|
goto fail;
|
|
}
|
|
memset(rbuf, 0, len);
|
|
|
|
for (int i = 0; i < len; ++i) {
|
|
wbuf[i] = ((i) & 0xff);
|
|
}
|
|
|
|
CMD_DBG("flash erase start\n");
|
|
|
|
if (flash_erase(MFLASH, addr, size)) {
|
|
CMD_ERR("flash erase err, add: 0x%x, size: 0x%x\n", addr, size);
|
|
goto out;
|
|
}
|
|
CMD_DBG("flash erase ok, add: 0x%x, size: 0x%x\n", addr, size);
|
|
|
|
while (1) {
|
|
ret = flash_write(MFLASH, addr + write_pos, wbuf, pos);
|
|
if (ret != pos) {
|
|
CMD_ERR("flash write err len:%d pos:%d\n", len, pos);
|
|
break;
|
|
}
|
|
ret = flash_read(MFLASH, addr + write_pos, rbuf, pos);
|
|
if (ret != pos) {
|
|
CMD_ERR("flash read err len:%d pos:%d\n", len, pos);
|
|
break;
|
|
}
|
|
|
|
for (int j = 0; j < pos; ++j) {
|
|
if (rbuf[j] != ((j) & 0xff)) {
|
|
CMD_ERR("flash read check err len:%d pos:%d + %d\n",
|
|
len, write_pos, j);
|
|
CMD_ERR("j:%d, now pos:%d\n", j, pos);
|
|
if (j < 32)
|
|
j = 0;
|
|
else
|
|
j -= 32;
|
|
print_hex_dump(NULL, DUMP_PREFIX_ADDRESS, 32, 1,
|
|
&rbuf[j], 64, 0);
|
|
ret = -1;
|
|
break;
|
|
}
|
|
}
|
|
if (ret != pos)
|
|
break;
|
|
memset(rbuf, 0, len);
|
|
|
|
write_pos += pos;
|
|
#if FLAH_WR_PRESS_DEBUG_ON
|
|
if (write_pos >= debug_size) {
|
|
CMD_DBG("write data:%dKB\n", write_pos / 1024);
|
|
debug_size += debug_size_unit;
|
|
}
|
|
#endif
|
|
if ((size - write_pos) > len)
|
|
pos = len;
|
|
else
|
|
pos = size - write_pos;
|
|
|
|
if (pos == 0) {
|
|
CMD_DBG("flash write & read over, addr:0x%x ~ 0x%x, len:%dKB\n",
|
|
addr, addr + write_pos, size / 1024);
|
|
|
|
if (++test_cnt >= loop) {
|
|
break;
|
|
} else {
|
|
CMD_DBG("flash test end, run test count:%d, should run:%d\n",
|
|
test_cnt, loop);
|
|
|
|
CMD_DBG("flash erase start\n");
|
|
if (flash_erase(MFLASH, addr, size)) {
|
|
CMD_ERR("flash erase err, add: 0x%x, size: 0x%x\n", addr,
|
|
size);
|
|
//break;
|
|
} else {
|
|
CMD_DBG("flash erase ok, add: 0x%x, size: 0x%x\n", addr,
|
|
size);
|
|
}
|
|
pos = len;
|
|
write_pos = 0;
|
|
#if FLAH_WR_PRESS_DEBUG_ON
|
|
debug_size = FLAH_WR_PRESS_TEST_DEBUG_SIZE;
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
CMD_DBG("flash test end, run test count:%d, should run:%d\n", test_cnt,
|
|
loop);
|
|
|
|
out:
|
|
cmd_free(wbuf);
|
|
cmd_free(rbuf);
|
|
fail:
|
|
OS_ThreadDelete(NULL);
|
|
}
|
|
|
|
static void cmd_flash_bench_task(void *arg)
|
|
{
|
|
int32_t err = 0;
|
|
char *cmd = (char *)arg;
|
|
uint32_t mode, start_addr, loop;
|
|
uint32_t cnt, erase_kb = 4;
|
|
float throuth_mb;
|
|
float time_use;
|
|
FlashEraseMode size_type = FLASH_ERASE_4KB;
|
|
|
|
cnt = cmd_sscanf(cmd, "m=0x%x a=0x%x n=%d", &mode, &start_addr, &loop);
|
|
if (cnt != 3 || loop < 1) {
|
|
CMD_ERR("invalid argument %s\n", cmd);
|
|
goto out;
|
|
}
|
|
|
|
time_perf_init();
|
|
|
|
printf("\n");
|
|
for (int _l = 0; _l < loop; _l++) {
|
|
for (int i = 0; i < 20; i++) {
|
|
int j;
|
|
uint32_t bench_size = 1024 * (1 << i);
|
|
uint32_t *buf = cmd_malloc(bench_size);
|
|
|
|
if (!buf) {
|
|
CMD_DBG("%s test end for malloc buff failed.\n", __func__);
|
|
break;
|
|
}
|
|
|
|
for (j = 0; j < bench_size / 4; j++)
|
|
buf[j] = j;
|
|
|
|
if (mode & 0x1) {
|
|
cnt = 1;
|
|
if (bench_size <= 4*1024) {
|
|
size_type = FLASH_ERASE_4KB;
|
|
erase_kb = 4;
|
|
} else if (bench_size <= 32*1024) {
|
|
size_type = FLASH_ERASE_32KB;
|
|
erase_kb = 32;
|
|
} else {
|
|
size_type = FLASH_ERASE_64KB;
|
|
cnt = DIV_ROUND_UP(bench_size, 64*1024);
|
|
erase_kb = 64 * cnt;
|
|
}
|
|
|
|
time_perf_tag();
|
|
err = HAL_Flash_Erase(MFLASH, size_type, start_addr, cnt);
|
|
time_use = (float)time_perf_tag() / 1000.0;
|
|
if (time_use < 0.001)
|
|
time_use = 0.001;
|
|
if (err) {
|
|
CMD_ERR("erase err!\n");
|
|
goto next;
|
|
} else {
|
|
throuth_mb = erase_kb * 1024 / time_use / 1000;
|
|
printf("%s erase ok, %3d", __func__, erase_kb);
|
|
printf(" KB use:%3.3f ms, throughput:%2.3f MB/S\n",
|
|
time_use, throuth_mb);
|
|
}
|
|
}
|
|
|
|
if (mode & 0x2) {
|
|
time_perf_tag();
|
|
err = HAL_Flash_Write(MFLASH, start_addr,
|
|
(const unsigned char *)buf, bench_size);
|
|
time_use = (float)time_perf_tag() / 1000.0;
|
|
if (time_use < 0.001)
|
|
time_use = 0.001;
|
|
if (err) {
|
|
CMD_ERR("write err!\n");
|
|
goto next;
|
|
} else {
|
|
throuth_mb = bench_size * 1000 / 1024 / time_use / 1000;
|
|
printf("%s write ok, %3d", __func__, bench_size / 1024);
|
|
printf(" KB use:%3.3f ms, throughput:%2.3f MB/S\n",
|
|
time_use, throuth_mb);
|
|
}
|
|
}
|
|
|
|
if (mode & 0x4) {
|
|
for (j = 0; j < bench_size / 4; j++)
|
|
buf[j] = 0;
|
|
|
|
time_perf_tag();
|
|
err = HAL_Flash_Read(MFLASH, start_addr, (uint8_t *)buf,
|
|
bench_size);
|
|
time_use = (float)time_perf_tag() / 1000.0;
|
|
if (time_use < 0.001)
|
|
time_use = 0.001;
|
|
if (err) {
|
|
CMD_ERR("read err!\n");
|
|
goto next;
|
|
} else {
|
|
throuth_mb = bench_size * 1000 / 1024 / time_use / 1000;
|
|
}
|
|
|
|
err = 0;
|
|
for (j = 0; j < bench_size / 4; j++) {
|
|
if (buf[j] != j) {
|
|
err = -1;
|
|
break;
|
|
}
|
|
}
|
|
if (err) {
|
|
CMD_ERR("bench_size:%d write data err:0x%x should:0x%x,"
|
|
" idx:%d!\n", bench_size, buf[j], j, j);
|
|
j = j > 16 ? j - 16 : 0;
|
|
print_hex_dump_bytes((const void *)&buf[j], 256);
|
|
goto next;
|
|
}
|
|
printf("%s read ok, %3d", __func__, bench_size / 1024);
|
|
printf(" KB use:%3.3f ms, throughput:%2.3f MB/S\n",
|
|
time_use, throuth_mb);
|
|
}
|
|
|
|
next:
|
|
cmd_free(buf);
|
|
if (err)
|
|
break;
|
|
}
|
|
}
|
|
|
|
out:
|
|
CMD_DBG("%s test end\n", __func__);
|
|
time_perf_deinit();
|
|
|
|
cmd_free(arg);
|
|
OS_ThreadDelete(NULL);
|
|
}
|
|
|
|
#define CMD_ARG_LEN 64
|
|
|
|
/* flash bench m=<mode> <a=0xaddr> n=<loop_num>
|
|
* <mode>: 1: erase, 2: write, 4: read, other is add
|
|
* flash bench m=0x7 a=0x100000 n=1
|
|
*/
|
|
static enum cmd_status cmd_flash_bench_exec(char *cmd)
|
|
{
|
|
OS_Thread_t thread;
|
|
char *param;
|
|
uint32_t len;
|
|
|
|
len = strlen(cmd);
|
|
if (len >= CMD_ARG_LEN - 1) {
|
|
CMD_ERR("should adjust CMD_ARG_LEN to %d\n", len);
|
|
return CMD_STATUS_FAIL;
|
|
}
|
|
|
|
param = cmd_malloc(CMD_ARG_LEN);
|
|
if (!param)
|
|
return CMD_STATUS_FAIL;
|
|
memcpy(param, cmd, len);
|
|
param[len + 1] = 0;
|
|
|
|
OS_ThreadSetInvalid(&thread);
|
|
if (OS_ThreadCreate(&thread,
|
|
"",
|
|
cmd_flash_bench_task,
|
|
param,
|
|
OS_THREAD_PRIO_APP,
|
|
2 * 1024) != OS_OK) {
|
|
CMD_ERR("create flash bench test task failed\n");
|
|
return CMD_STATUS_FAIL;
|
|
}
|
|
|
|
return CMD_STATUS_OK;
|
|
}
|
|
|
|
/*
|
|
* flash press s=0x100000 e=0x1FF000 b=8192 l=50
|
|
*/
|
|
static enum cmd_status cmd_flash_press_exec(char *cmd)
|
|
{
|
|
uint32_t cnt, saddr, eaddr, bs, loop;
|
|
|
|
/* get param */
|
|
cnt = cmd_sscanf(cmd, "s=0x%x e=0x%x b=%d l=%d", &saddr, &eaddr, &bs,
|
|
&loop);
|
|
|
|
/* check param */
|
|
if (cnt != 4) {
|
|
CMD_ERR("invalid param number %d\n", cnt);
|
|
return CMD_STATUS_INVALID_ARG;
|
|
}
|
|
|
|
OS_Thread_t thread;
|
|
|
|
OS_ThreadSetInvalid(&thread);
|
|
if (OS_ThreadCreate(&thread,
|
|
"",
|
|
cmd_flash_press_test_task,
|
|
cmd,
|
|
OS_THREAD_PRIO_APP,
|
|
2 * 1024) != OS_OK) {
|
|
CMD_ERR("create flash press test task failed\n");
|
|
return CMD_STATUS_FAIL;
|
|
}
|
|
|
|
return CMD_STATUS_OK;
|
|
}
|
|
|
|
static void cmd_flash_press_r_test_task(void *arg)
|
|
{
|
|
uint32_t ret;
|
|
uint32_t addr, size, len, pos, write_pos;
|
|
uint32_t test_cnt;
|
|
uint8_t *wbuf, *rbuf;
|
|
uint32_t cnt, saddr, eaddr, bs, loop;
|
|
|
|
/* get param */
|
|
cnt = cmd_sscanf((char *)arg, "s=0x%x e=0x%x b=%d l=%d", &saddr, &eaddr,
|
|
&bs, &loop);
|
|
/* check param */
|
|
if (cnt != 4) {
|
|
CMD_ERR("invalid param number %d\n", cnt);
|
|
goto fail;
|
|
}
|
|
if ((eaddr - saddr) < bs) {
|
|
CMD_ERR("(end addr - start addr) must > buf size !\n");
|
|
goto fail;
|
|
}
|
|
#if FLAH_WR_PRESS_DEBUG_ON
|
|
uint32_t debug_size, debug_size_unit;
|
|
|
|
debug_size = FLAH_WR_PRESS_TEST_DEBUG_SIZE;
|
|
debug_size_unit = FLAH_WR_PRESS_TEST_DEBUG_SIZE;
|
|
#endif
|
|
|
|
len = bs;
|
|
addr = saddr;
|
|
size = eaddr - addr;
|
|
|
|
test_cnt = 0;
|
|
pos = len;
|
|
write_pos = 0;
|
|
|
|
wbuf = cmd_malloc(len);
|
|
if (wbuf == NULL) {
|
|
CMD_ERR("no memory, malloc size %d fail\n", len);
|
|
goto fail;
|
|
}
|
|
memset(wbuf, 0, len);
|
|
|
|
rbuf = cmd_malloc(len);
|
|
if (rbuf == NULL) {
|
|
CMD_ERR("no memory, malloc size %d fail\n", len);
|
|
cmd_free(wbuf);
|
|
goto fail;
|
|
}
|
|
memset(rbuf, 0, len);
|
|
|
|
for (int i = 0; i < len; ++i) {
|
|
wbuf[i] = ((i) & 0xff);
|
|
}
|
|
|
|
CMD_DBG("flash erase start\n");
|
|
|
|
if (flash_erase(MFLASH, addr, size)) {
|
|
CMD_ERR("flash erase err, add: 0x%x, size: 0x%x\n", addr, size);
|
|
goto out;
|
|
}
|
|
CMD_DBG("flash erase ok, add: 0x%x, size: 0x%x\n", addr, size);
|
|
while (1) {
|
|
ret = flash_write(MFLASH, addr + write_pos, wbuf, pos);
|
|
if (ret != pos) {
|
|
CMD_ERR("flash write err len:%d pos:%d\n", len, pos);
|
|
goto out;
|
|
}
|
|
CMD_DBG("write data:%dKB\n", write_pos / 1024);
|
|
write_pos += pos;
|
|
if ((size - write_pos) > len)
|
|
pos = len;
|
|
else
|
|
pos = size - write_pos;
|
|
if (pos == 0) {
|
|
CMD_DBG("flash write over, addr:0x%x ~ 0x%x, len:%dKB\n",
|
|
addr, addr + write_pos, size / 1024);
|
|
break;
|
|
}
|
|
}
|
|
|
|
pos = len;
|
|
write_pos = 0;
|
|
#if FLAH_WR_PRESS_DEBUG_ON
|
|
debug_size = FLAH_WR_PRESS_TEST_DEBUG_SIZE;
|
|
#endif
|
|
while (1) {
|
|
ret = flash_read(MFLASH, addr + write_pos, rbuf, pos);
|
|
if (ret != pos) {
|
|
CMD_ERR("flash read err:%d len pos:%d\n", len, pos);
|
|
goto out;
|
|
}
|
|
|
|
for (int j = 0; j < pos; ++j) {
|
|
if (rbuf[j] != ((j) & 0xff)) {
|
|
CMD_ERR("flash read check err len:%d pos:%d + %d\n", len, write_pos, j);
|
|
CMD_ERR("j:%d, now pos:%d\n", j, pos);
|
|
#if 1
|
|
for (int dm = ((j > 0) ? (j - 1) : j); dm < pos; ++dm) {
|
|
if ((dm > 0) && (dm % 16) == 0) {
|
|
printf("\n");
|
|
}
|
|
printf(" %02X", rbuf[dm]);
|
|
}
|
|
printf("\n");
|
|
#endif
|
|
goto out;
|
|
}
|
|
}
|
|
memset(rbuf, 0, len);
|
|
|
|
write_pos += pos;
|
|
#if FLAH_WR_PRESS_DEBUG_ON
|
|
if (write_pos >= debug_size) {
|
|
CMD_DBG("read data:%dKB\n", write_pos / 1024);
|
|
debug_size += debug_size_unit;
|
|
}
|
|
#endif
|
|
if ((size - write_pos) > len)
|
|
pos = len;
|
|
else
|
|
pos = size - write_pos;
|
|
|
|
if (pos == 0) {
|
|
CMD_DBG("flash read over, addr:0x%x ~ 0x%x, len:%dKB\n",
|
|
addr, addr + write_pos, size / 1024);
|
|
|
|
if (++test_cnt >= loop) {
|
|
break;
|
|
} else {
|
|
pos = len;
|
|
write_pos = 0;
|
|
#if FLAH_WR_PRESS_DEBUG_ON
|
|
debug_size = FLAH_WR_PRESS_TEST_DEBUG_SIZE;
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
CMD_DBG("flash read test end, run test count:%d, should run:%d\n",
|
|
test_cnt, loop);
|
|
|
|
out:
|
|
cmd_free(wbuf);
|
|
cmd_free(rbuf);
|
|
fail:
|
|
OS_ThreadDelete(NULL);
|
|
}
|
|
|
|
/*
|
|
* flash press_r s=0x100000 e=0x1FF000 b=8192 l=50
|
|
*/
|
|
static enum cmd_status cmd_flash_press_r_exec(char *cmd)
|
|
{
|
|
uint32_t cnt, saddr, eaddr, bs, loop;
|
|
|
|
/* get param */
|
|
cnt = cmd_sscanf(cmd, "s=0x%x e=0x%x b=%d l=%d", &saddr, &eaddr, &bs,
|
|
&loop);
|
|
|
|
/* check param */
|
|
if (cnt != 4) {
|
|
CMD_ERR("invalid param number %d\n", cnt);
|
|
return CMD_STATUS_INVALID_ARG;
|
|
}
|
|
|
|
OS_Thread_t thread;
|
|
|
|
OS_ThreadSetInvalid(&thread);
|
|
if (OS_ThreadCreate(&thread,
|
|
"",
|
|
cmd_flash_press_r_test_task,
|
|
cmd,
|
|
OS_THREAD_PRIO_APP,
|
|
2 * 1024) != OS_OK) {
|
|
CMD_ERR("create flash read press test task failed\n");
|
|
return CMD_STATUS_FAIL;
|
|
}
|
|
|
|
return CMD_STATUS_OK;
|
|
}
|
|
|
|
static enum cmd_status cmd_flash_enter_sip_exec(char *cmd)
|
|
{
|
|
//writel(0x429D0001, 0x4000A044);
|
|
HAL_SYSCTL_SetSipFlashTestMapMode();
|
|
HAL_BoardIoctl(HAL_BIR_PINMUX_INIT, HAL_MKDEV(HAL_DEV_MAJOR_FLASHC, NOT_SIP_FLASH), 0);
|
|
HAL_BoardIoctl(HAL_BIR_PINMUX_INIT, HAL_MKDEV(HAL_DEV_MAJOR_FLASHC, SIP_FLASH), 0);
|
|
|
|
return CMD_STATUS_OK;
|
|
}
|
|
|
|
/*
|
|
* brief Flash Auto Test Command
|
|
* command start {spiNum} {csNum} {freq} {mode}
|
|
* stop
|
|
* config {ioMode}// -----need to be supported by Flash chip
|
|
* erase {size} {addr}
|
|
* write {addr} "{str}"
|
|
* read {str/hex} {addr} {size} // recommanded that size should not too large
|
|
*/
|
|
static const struct cmd_data g_flash_cmds[] = {
|
|
{ "start", cmd_flash_start_exec },
|
|
{ "stop", cmd_flash_stop_exec },
|
|
{ "erase", cmd_flash_erase_exec },
|
|
{ "write", cmd_flash_write_exec },
|
|
{ "read", cmd_flash_read_exec },
|
|
{ "overwrite", cmd_flash_overwrite_exec },
|
|
#if (defined FLASH_XIP_OPT_WRITE) && (defined FLASH_XIP_OPT_ERASR)
|
|
{ "optimize", cmd_flash_optimize_exec },
|
|
#endif
|
|
{ "set_rmod", cmd_flash_set_rmode_exec },
|
|
{ "set_wmod", cmd_flash_set_program_mode_exec },
|
|
{ "bench", cmd_flash_bench_exec },
|
|
{ "press", cmd_flash_press_exec },
|
|
{ "press_r", cmd_flash_press_r_exec },
|
|
{ "enter_sip", cmd_flash_enter_sip_exec },
|
|
};
|
|
|
|
enum cmd_status cmd_flash_exec(char *cmd)
|
|
{
|
|
return cmd_exec(cmd, g_flash_cmds, cmd_nitems(g_flash_cmds));
|
|
}
|