2025-10-10 16:07:00 +08:00

390 lines
11 KiB
C

// Copyright 2020-2021 Beken
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <driver/flash.h>
#include <driver/flash_partition.h>
#include "cli.h"
#include "flash_driver.h"
#if CONFIG_TFM_FLASH_NSC
#include "tfm_flash_nsc.h"
#endif
static void cli_flash_help(void)
{
CLI_LOGI("flash driver init\n");
CLI_LOGI("flash_driver deinit\n");
CLI_LOGI("flash {erase|write|read} [start_addr] [len]\n");
CLI_LOGI("flash_partition show\n");
CLI_LOGI("flash_erase_test ble\n");
}
static void cli_flash_cmd(char *pcWriteBuffer, int xWriteBufferLen, int argc, char **argv)
{
char *msg = NULL;
if (argc < 2) {
cli_flash_help();
return;
}
uint32_t start_addr = os_strtoul(argv[2], NULL, 16);
uint32_t len = os_strtoul(argv[3], NULL, 16);
if (os_strcmp(argv[1], "erase") == 0) {
bk_flash_set_protect_type(FLASH_PROTECT_NONE);
for (uint32_t addr = start_addr; addr < (start_addr + len); addr += FLASH_SECTOR_SIZE) {
bk_flash_erase_sector(addr);
}
bk_flash_set_protect_type(FLASH_UNPROTECT_LAST_BLOCK);
msg = CLI_CMD_RSP_SUCCEED;
} else if (os_strcmp(argv[1], "read") == 0) {
uint8_t buf[FLASH_PAGE_SIZE] = {0};
for (uint32_t addr = start_addr; addr < (start_addr + len); addr += FLASH_PAGE_SIZE) {
os_memset(buf, 0, FLASH_PAGE_SIZE);
bk_flash_read_bytes(addr, buf, FLASH_PAGE_SIZE);
CLI_LOGI("flash read addr:%x\r\n", addr);
CLI_LOGI("dump read flash data:\r\n");
for (uint32_t i = 0; i < 16; i++) {
for (uint32_t j = 0; j < 16; j++) {
os_printf("%02x ", buf[i * 16 + j]);
}
os_printf("\r\n");
}
}
msg = CLI_CMD_RSP_SUCCEED;
} else if (os_strcmp(argv[1], "write") == 0) {
uint8_t buf[FLASH_PAGE_SIZE] = {0};
for (uint32_t i = 0; i < FLASH_PAGE_SIZE; i++) {
buf[i] = i;
}
bk_flash_set_protect_type(FLASH_PROTECT_NONE);
for (uint32_t addr = start_addr; addr < (start_addr + len); addr += FLASH_PAGE_SIZE) {
bk_flash_write_bytes(addr, buf, FLASH_PAGE_SIZE);
}
bk_flash_set_protect_type(FLASH_UNPROTECT_LAST_BLOCK);
msg = CLI_CMD_RSP_SUCCEED;
} else if (os_strcmp(argv[1], "get_id") == 0) {
uint32_t flash_id = bk_flash_get_id();
CLI_LOGI("flash_id:%x\r\n", flash_id);
msg = CLI_CMD_RSP_SUCCEED;
} else if (os_strcmp(argv[1], "set_line") == 0) {
/*enable FLASH_QUAD_ENABLE first*/
uint16_t line_mode = os_strtoul(argv[2], NULL, 16);
bk_flash_set_line_mode(line_mode);
msg = CLI_CMD_RSP_SUCCEED;
} else if (os_strcmp(argv[1], "mutex_test") == 0) {
extern void flash_svr_test_task(void * param);
int task_pri = os_strtoul(argv[2], NULL, 16);
rtos_create_thread(NULL, task_pri, "flash_test", flash_svr_test_task, 2048, NULL);
msg = CLI_CMD_RSP_SUCCEED;
} else {
cli_flash_help();
msg = CLI_CMD_RSP_ERROR;
}
os_memcpy(pcWriteBuffer, msg, os_strlen(msg));
}
#if CONFIG_TFM_FLASH_NSC
static void cli_flash_cmd_s(char *pcWriteBuffer, int xWriteBufferLen, int argc, char **argv)
{
char *msg = NULL;
if (argc < 2) {
cli_flash_help();
return;
}
uint32_t start_addr = os_strtoul(argv[2], NULL, 16);
uint32_t len = os_strtoul(argv[3], NULL, 16);
if (os_strcmp(argv[1], "erase") == 0) {
psa_flash_set_protect_type(FLASH_PROTECT_NONE);
for (uint32_t addr = start_addr; addr < (start_addr + len); addr += FLASH_SECTOR_SIZE) {
psa_flash_erase_sector(addr);
}
psa_flash_set_protect_type(FLASH_UNPROTECT_LAST_BLOCK);
msg = CLI_CMD_RSP_SUCCEED;
} else if (os_strcmp(argv[1], "read") == 0) {
uint8_t buf[FLASH_PAGE_SIZE] = {0};
for (uint32_t addr = start_addr; addr < (start_addr + len); addr += FLASH_PAGE_SIZE) {
os_memset(buf, 0, FLASH_PAGE_SIZE);
psa_flash_read_bytes(addr, buf, FLASH_PAGE_SIZE);
CLI_LOGI("flash read addr:%x\r\n", addr);
CLI_LOGI("dump read flash data:\r\n");
for (uint32_t i = 0; i < 16; i++) {
for (uint32_t j = 0; j < 16; j++) {
os_printf("%02x ", buf[i * 16 + j]);
}
os_printf("\r\n");
}
}
msg = CLI_CMD_RSP_SUCCEED;
} else if (os_strcmp(argv[1], "write") == 0) {
uint8_t buf[FLASH_PAGE_SIZE] = {0};
for (uint32_t i = 0; i < FLASH_PAGE_SIZE; i++) {
buf[i] = i;
}
int level = rtos_enter_critical();
psa_flash_set_protect_type(FLASH_PROTECT_NONE);
for (uint32_t addr = start_addr; addr < (start_addr + len); addr += FLASH_PAGE_SIZE) {
psa_flash_write_bytes(addr, buf, FLASH_PAGE_SIZE);
}
psa_flash_set_protect_type(FLASH_UNPROTECT_LAST_BLOCK);
rtos_exit_critical(level);
msg = CLI_CMD_RSP_SUCCEED;
} else {
cli_flash_help();
msg = CLI_CMD_RSP_ERROR;
}
os_memcpy(pcWriteBuffer, msg, os_strlen(msg));
}
#endif
static void cli_flash_partition_cmd(char *pcWriteBuffer, int xWriteBufferLen, int argc, char **argv)
{
bk_logic_partition_t *partition;
if (os_strcmp(argv[1], "show") == 0) {
for (bk_partition_t par= BK_PARTITION_BOOTLOADER; par < BK_PARTITION_MAX; par++) {
partition = bk_flash_partition_get_info(par);
if (partition == NULL)
continue;
CLI_LOGI("%4d | %11s | Dev:%d | 0x%08lx | 0x%08lx |\r\n", par,
partition->partition_description, partition->partition_owner,
partition->partition_start_addr, partition->partition_length);
}
} else {
cli_flash_help();
}
}
/*
* flash erase will affect ble connecting, unless flash erase while ble is sleeping
* This test case aims to do flash erasing with ble sleeping and connecting
*/
#define S_WAKE_UP (0)
#define S_SLEEP (1)
#define S_POWER_OFF (2)
#define S_NO_BT (3)
#define ERASE_TOUCH_TIMEOUT (3000)//ms
#define ERASE_FLASH_TIMEOUT (56)//ms
static u32 bt_sleepend_time = -1; //when cb return,bt is sleep ,recoeding the bt will sleep how long
static u32 bt_cb_anchor_time = 0; //when cb return ,record current time ;
static u8 bt_sleep_state = S_NO_BT; //record bt state;the default is 3(S_NO_BT);
static void flash_test_ble_sleep_cb(uint8_t is_sleeping, uint32_t slp_period);
typedef void (*ble_sleep_state_cb)(uint8_t is_sleeping, uint32_t slp_period);
extern void bk_ble_register_sleep_state_callback(ble_sleep_state_cb cb);
static void flash_test_ble_sleep_cb(uint8_t is_sleeping, uint32_t slp_period)
{
GLOBAL_INT_DECLARATION();
GLOBAL_INT_DISABLE();
bt_sleep_state = is_sleeping ;
bt_cb_anchor_time = rtos_get_time();
if (is_sleeping == S_SLEEP)
{
bt_sleepend_time = bt_cb_anchor_time + slp_period/32;
}
GLOBAL_INT_RESTORE();
}
static int ble_callback_deal_handler(uint32_t deal_flash_time)
{
uint32_t cur_time =0;
uint32_t temp_time = 0;
int ret_val = 0;
cur_time = rtos_get_time();
GLOBAL_INT_DECLARATION();
GLOBAL_INT_DISABLE();
do
{
if(bt_sleep_state == S_POWER_OFF) //poweroff
{
ret_val = 1;
break;
}
else if(bt_sleep_state == S_WAKE_UP) //wakeup
{
if(cur_time >= bt_cb_anchor_time)
{
temp_time = (cur_time - bt_cb_anchor_time);
}
else
{
temp_time = 0xFFFFFFFF - bt_cb_anchor_time + cur_time;
}
if(temp_time >= ERASE_TOUCH_TIMEOUT)
{
bt_sleep_state = S_NO_BT;
ret_val = 1;
break;
}
ret_val = 0;
break;
}
else if(bt_sleep_state == S_SLEEP) //sleep
{
if(bt_sleepend_time > bt_cb_anchor_time)
{
if(bt_sleepend_time < cur_time)
{
ret_val = 1;
break;
}
else if(cur_time < bt_cb_anchor_time)
{
ret_val = 1;
break;
}
else if((bt_sleepend_time - cur_time) >= deal_flash_time)
{
ret_val = 1;
break;
}
else
{
ret_val = 0;
break;
}
}
else
{
temp_time = 0;
if((cur_time > bt_sleepend_time)&&(bt_cb_anchor_time > cur_time))
{
ret_val = 1;
break;
}
else if(bt_cb_anchor_time <= cur_time)
{
temp_time = 0xFFFFFFFF - cur_time + bt_sleepend_time;
}
else
{
temp_time = bt_sleepend_time - cur_time;
}
if(temp_time >= deal_flash_time )
{
ret_val = 1;
break;
}
else
{
ret_val = 0;
break;
}
}
}
else
{
ret_val = 1;
break;
}
}while(0);
GLOBAL_INT_RESTORE();
return ret_val;
}
void flash_erase_with_ble_sleep(uint32_t erase_addr)
{
uint32_t anchor_time = 0;
uint32_t temp_time = 0;
uint8_t flash_erase_ready = 0;
anchor_time = rtos_get_time();
while(1)
{
flash_erase_ready = ble_callback_deal_handler(ERASE_FLASH_TIMEOUT);
temp_time = rtos_get_time();
if(temp_time >= anchor_time)
{
temp_time -= anchor_time;
}
else
{
temp_time += (0xFFFFFFFF - anchor_time);
}
if(temp_time >= ERASE_TOUCH_TIMEOUT)
flash_erase_ready = 1;
if(flash_erase_ready == 1)
{
bk_flash_erase_sector(erase_addr);
flash_erase_ready = 0;
break;
}
else
{
rtos_delay_milliseconds(2);
}
}
}
static void cli_flash_erase_test_with_ble(char *pcWriteBuffer, int xWriteBufferLen, int argc, char **argv)
{
char *msg = NULL;
uint32_t start_addr = 0x260000;
uint32_t erase_len = 0x180000;
if (os_strcmp(argv[1], "ble") == 0) {
#if (CONFIG_BLUETOOTH)
bk_ble_register_sleep_state_callback(flash_test_ble_sleep_cb);
#endif
for (uint32_t erase_addr = start_addr; erase_addr <= (start_addr + erase_len);) {
flash_erase_with_ble_sleep(erase_addr);
erase_addr += FLASH_SECTOR_SIZE;
CLI_LOGI("erase_addr:%x\r\n", erase_addr);
}
CLI_LOGI("cli_flash_erase_test_with_ble finish.\r\n");
msg = CLI_CMD_RSP_SUCCEED;
} else {
cli_flash_help();
msg = CLI_CMD_RSP_ERROR;
}
os_memcpy(pcWriteBuffer, msg, os_strlen(msg));
}
#define FLASH_CMD_CNT (sizeof(s_flash_commands) / sizeof(struct cli_command))
static const struct cli_command s_flash_commands[] = {
{"flash", "flash {erase|read|write} [start_addr] [len]", cli_flash_cmd},
#if CONFIG_TFM_FLASH_NSC
{"flash_s", "flash {erase|read|write} [start_addr] [len]", cli_flash_cmd_s},
#endif
{"flash_partition", "flash_partition {show}", cli_flash_partition_cmd},
{"flash_erase_test", "cli_flash_erase_test with ble connecting", cli_flash_erase_test_with_ble},
};
int cli_flash_init(void)
{
BK_LOG_ON_ERR(bk_flash_driver_init());
return cli_register_commands(s_flash_commands, FLASH_CMD_CNT);
}