660 lines
22 KiB
C
660 lines
22 KiB
C
/*
|
|
* Copyright (c) CompanyNameMagicTag 2012-2019. All rights reserved.
|
|
* Description: FLASH drive adjustment. Flash_ram.c code
|
|
* Author: CompanyName
|
|
* Create: 2012-06-08
|
|
*/
|
|
#include "flash_ram.h"
|
|
#include "flash_prv.h"
|
|
|
|
#include <soc_mdm_types.h>
|
|
#include <soc_mdm_flash.h>
|
|
#include <soc_stdlib.h>
|
|
#include <soc_mdm_isr.h>
|
|
#include <soc_mdm_mux.h>
|
|
#include <soc_mdm_timer.h>
|
|
#include <soc_ft_nv.h>
|
|
#include <soc_mdm_ver.h>
|
|
#include <soc_partition_table.h>
|
|
#include <soc_flash_prv.h>
|
|
#include <soc_lowpower.h>
|
|
#ifdef PRODUCT_CFG_SUPPORT_FLASH_PROTECT
|
|
#include <soc_mdm_timer.h>
|
|
#include <soc_ft_nv.h>
|
|
#include <soc_mdm_isr.h>
|
|
#include <soc_mdm_flash_protect.h>
|
|
#endif
|
|
|
|
#define BLOCK_SIZE 0x1000
|
|
EXT_SPI_FLASH_CTRL_S g_flash_drv_ctrl = {
|
|
0,
|
|
};
|
|
|
|
EXT_CONST EXT_SPI_FLASH_BASIC_INFO_S g_flash_usr_info_tbl[] = {
|
|
{ "UNKNOWN", {0, }, _16M, EXT_FLASH_SUPPORT_DEFAULT, 0, 0},
|
|
{ "W25Q40", {0xEF, 0x40, 0x13, }, _512K, EXT_FLASH_SUPPORT_ERASE464CHIP, 3, 0},
|
|
{ "GD25Q40", {0xC8, 0x40, 0x13, }, _512K, EXT_FLASH_SUPPORT_ERASE464CHIP, 3, 0},
|
|
{ "W25Q16", {0xEF, 0x40, 0x15, }, _2M, EXT_FLASH_SUPPORT_ERASE464CHIP, 3, 0},
|
|
};
|
|
|
|
#define BACK_BUFFER_SIZE 1024
|
|
#define DMA_BUFFER_SIZE 256
|
|
td_u32 g_back_buffer[BACK_BUFFER_SIZE] = { 0 };
|
|
td_u32 g_dma_buffer[DMA_BUFFER_SIZE] = { 0 };
|
|
|
|
flash_prepare_func g_flash_prepare_func;
|
|
flash_restore_func g_flash_restore_func;
|
|
|
|
#define FLASH_READ_TICK_MAX 50
|
|
#define FLASH_WRITE_TICK_MAX 500
|
|
#define FLASH_ERASE_TICK_MAX 1000
|
|
|
|
/* Flash protection feature code */
|
|
#ifdef PRODUCT_CFG_SUPPORT_FLASH_PROTECT
|
|
|
|
#define REG_PROTECT_FLASH (DW21_SYSCTRL_SC_GEN_REG3_REG)
|
|
/* The highest bit indicates whether flash protection is supported */
|
|
#define SUPPORT_PROTECT_FLASH ((td_u32)0x1 << 31)
|
|
#define PROTECT_TIMEOUT_1 6000 /* Volatile write flash status register, timeout value seconds */
|
|
#define PROTECT_TIMEOUT_2 3600000 /* Non-volatile write flash status register, timeout value hourly */
|
|
|
|
typedef struct {
|
|
td_u32 cmp_bp : 6;
|
|
td_u32 block : 13;
|
|
td_u32 reseve : 13;
|
|
} ext_flash_protect_size;
|
|
|
|
ext_flash_protect_ctrl g_protect_ctrl = {
|
|
0,
|
|
};
|
|
|
|
/*
|
|
* 1. Different chip settings are different, please re-confirm the form when replacing the flash chip;
|
|
* 2.bit settings refer to the Flash manual memory protection section, this table refers to W25Q40C and GD25Q40C;
|
|
* 3. It can be streamlined or refined according to the actual space;
|
|
*/
|
|
EXT_CONST ext_flash_protect_size g_flash_protect_size[] = {
|
|
/* bit[5]:cmp
|
|
* bit[4]:sec: 1:4KB 0:64KB
|
|
* bit[3]:tb: 0:top 1:bottom
|
|
* bit[2:0]:bp[2:0]: See device manual
|
|
*/
|
|
{ 0b000000, 0x0, 0 }, /* not protected */
|
|
{ 0b011001, 0x1, 0 }, /* Protect 4KB */
|
|
{ 0b011010, 0x2, 0 }, /* Protect 8KB */
|
|
{ 0b011011, 0x4, 0 }, /* Protect 16KB */
|
|
{ 0b011100, 0x8, 0 }, /* Protect 32KB */
|
|
{ 0b001001, 0x10, 0 }, /* Protect 64KB */
|
|
{ 0b001010, 0x20, 0 }, /* Protect 128KB */
|
|
{ 0b100011, 0x40, 0 }, /* Protect 256KB */
|
|
{ 0b100010, 0x60, 0 }, /* Protect 384KB (512-128) */
|
|
{ 0b100001, 0x70, 0 }, /* Protection 448KB (512-64) */
|
|
{ 0b110110, 0x78, 0 }, /* Protect 480KB (512-32) */
|
|
{ 0b110011, 0x7C, 0 }, /* Protection 496KB (512-16) */
|
|
{ 0b110010, 0x7E, 0 }, /* Protect 504KB(512-8) */
|
|
{ 0b011111, 0x80, 0 }, /* Protect 512KB */
|
|
};
|
|
|
|
td_u32 flash_protect_config(td_u32 ep_addr, td_u32 timeout);
|
|
td_u32 flash_volatile_protect_config(td_u32 ep_addr, td_u32 timeout);
|
|
|
|
td_void flash_lock(td_void)
|
|
{
|
|
if (!uapi_is_int_context()) {
|
|
uapi_mux_pend(g_flash_drv_ctrl.mutex_handle, EXT_SYS_WAIT_FOREVER);
|
|
}
|
|
}
|
|
|
|
td_void flash_unlock(td_void)
|
|
{
|
|
if (!uapi_is_int_context()) {
|
|
uapi_mux_post(g_flash_drv_ctrl.mutex_handle);
|
|
}
|
|
}
|
|
|
|
EXT_PRV td_u32 spi_flash_write_sr_reg(td_u8 cmd, td_u8 *data, td_u8 data_len, td_bool is_volatile)
|
|
{
|
|
td_u32 temp_data = 0;
|
|
td_u32 ret;
|
|
|
|
/* Internal pass parameters, the judgment return value is omitted here */
|
|
(td_void)memcpy_s(&temp_data, sizeof(temp_data), data, data_len);
|
|
|
|
if (is_volatile) {
|
|
ext_sfc_write(SFC_REG_CMD_INS, SPI_CMD_VSR_WREN);
|
|
ext_sfc_write(SFC_REG_CMD_CONFIG, (td_u32)(SFC_CMD_CONFIG_SEL_CS | SFC_CMD_CONFIG_START));
|
|
ret = spif_wait_config_start();
|
|
if (ret != EXT_ROM_ERR_SUCCESS) {
|
|
return ret;
|
|
}
|
|
} else {
|
|
ret = spif_write_enable(TD_TRUE);
|
|
if (ret) {
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
ext_sfc_write(SFC_REG_CMD_INS, cmd);
|
|
ext_sfc_write(SFC_REG_CMD_DATABUF1, temp_data);
|
|
|
|
ext_sfc_write(SFC_REG_CMD_CONFIG,
|
|
SFC_CMD_CONFIG_SEL_CS | SFC_CMD_CONFIG_DATA_EN | SFC_CMD_CONFIG_DATA_CNT(data_len) | SFC_CMD_CONFIG_START);
|
|
|
|
ret = spif_wait_config_start();
|
|
if (ret != EXT_ROM_ERR_SUCCESS) {
|
|
return ret;
|
|
}
|
|
|
|
return EXT_ROM_ERR_SUCCESS;
|
|
}
|
|
#define SPI_REG_DATA_COUNT 2
|
|
#define SPI_CMP_BP_SHIFT_RIGHT_COUNT 5
|
|
#define SPI_FLASH_STATUS_REG_SHIFT_LEFT_COUNT 8
|
|
#define SPI_FLASH_WRITE_SR_REG_BP_SHIFT_LEFT_COUNT 2
|
|
#define SPI_FLASH_WRITE_SR_REG_CMP_SHIFT_LEFT_COUNT 6
|
|
td_u32 spi_flash_set_protect(td_u8 cmp_bp, td_bool is_volatile)
|
|
{
|
|
td_u32 ret;
|
|
td_u8 data[SPI_REG_DATA_COUNT] = { 0 };
|
|
td_u8 cmp = (cmp_bp >> SPI_CMP_BP_SHIFT_RIGHT_COUNT) & 0x1;
|
|
td_u8 bp = cmp_bp & 0x1F;
|
|
ext_flash_protect_ctrl *ctrl = &g_protect_ctrl;
|
|
|
|
ret = spi_flash_read_reg(SPI_CMD_RDSR, &data[0], 1);
|
|
if (ret != EXT_ROM_ERR_SUCCESS) {
|
|
return ret;
|
|
}
|
|
ret = spi_flash_read_reg(SPI_CMD_RDSR2, &data[1], 1);
|
|
if (ret != EXT_ROM_ERR_SUCCESS) {
|
|
return ret;
|
|
}
|
|
ctrl->flash_status_reg = data[0] | (data[1] << SPI_FLASH_STATUS_REG_SHIFT_LEFT_COUNT);
|
|
if (((data[0] & (0x1F << SPI_FLASH_WRITE_SR_REG_BP_SHIFT_LEFT_COUNT)) ==
|
|
(bp << SPI_FLASH_WRITE_SR_REG_BP_SHIFT_LEFT_COUNT)) &&
|
|
((data[1] & (0x1 << SPI_FLASH_WRITE_SR_REG_CMP_SHIFT_LEFT_COUNT)) ==
|
|
(cmp << SPI_FLASH_WRITE_SR_REG_CMP_SHIFT_LEFT_COUNT))) {
|
|
return EXT_ROM_ERR_SUCCESS;
|
|
}
|
|
|
|
data[0] &= ~(0x1f << SPI_FLASH_WRITE_SR_REG_BP_SHIFT_LEFT_COUNT);
|
|
data[0] |= (td_u8)(bp << SPI_FLASH_WRITE_SR_REG_BP_SHIFT_LEFT_COUNT);
|
|
data[1] &= ~(0x1 << SPI_FLASH_WRITE_SR_REG_CMP_SHIFT_LEFT_COUNT);
|
|
data[1] |= (td_u8)(cmp << SPI_FLASH_WRITE_SR_REG_CMP_SHIFT_LEFT_COUNT);
|
|
ret = spi_flash_write_sr_reg(SPI_CMD_WRSR1, data, SPI_REG_DATA_COUNT, is_volatile);
|
|
if (ret != EXT_ROM_ERR_SUCCESS) {
|
|
return ret;
|
|
}
|
|
|
|
ret = spi_flash_read_reg(SPI_CMD_RDSR, &data[0], 1);
|
|
if (ret != EXT_ROM_ERR_SUCCESS) {
|
|
return ret;
|
|
}
|
|
ret = spi_flash_read_reg(SPI_CMD_RDSR2, &data[1], 1);
|
|
if (ret != EXT_ROM_ERR_SUCCESS) {
|
|
return ret;
|
|
}
|
|
ctrl->flash_status_reg = data[0] | (data[1] << SPI_FLASH_STATUS_REG_SHIFT_LEFT_COUNT);
|
|
if (((data[0] & (0x1F << SPI_FLASH_WRITE_SR_REG_BP_SHIFT_LEFT_COUNT)) ==
|
|
(bp << SPI_FLASH_WRITE_SR_REG_BP_SHIFT_LEFT_COUNT)) &&
|
|
((data[1] & (0x1 << SPI_FLASH_WRITE_SR_REG_CMP_SHIFT_LEFT_COUNT)) ==
|
|
(cmp << SPI_FLASH_WRITE_SR_REG_CMP_SHIFT_LEFT_COUNT))) {
|
|
return EXT_ROM_ERR_SUCCESS;
|
|
} else {
|
|
return EXT_ERR_FLASH_PROTECT_WRITE_STATUS_REG;
|
|
}
|
|
}
|
|
|
|
EXT_PRV td_void flash_protect_job(td_u32 data_1, td_u32 data_2, td_u32 data_3, td_u32 data_4, td_u32 data_5)
|
|
{
|
|
td_bool is_volatile = (td_bool)data_1;
|
|
ext_flash_protect_ctrl *ctrl = &g_protect_ctrl;
|
|
td_u32 ret;
|
|
|
|
ext_unref_param(data_2);
|
|
ext_unref_param(data_3);
|
|
ext_unref_param(data_4);
|
|
ext_unref_param(data_5);
|
|
if (is_volatile) {
|
|
ret = flash_volatile_protect_config(0xFFFFFFFF, 0);
|
|
} else {
|
|
ret = flash_protect_config(0xFFFFFFFF, 0);
|
|
}
|
|
if (ret != EXT_ERR_SUCCESS) {
|
|
ctrl->job_run_errs++;
|
|
}
|
|
}
|
|
|
|
EXT_PRV td_void flash_protect_timeout(td_u32 is_volatile)
|
|
{
|
|
td_u32 ret;
|
|
ext_flash_protect_ctrl *ctrl = &g_protect_ctrl;
|
|
|
|
ret = uapi_irq_add_job(EXT_JOB_PRIORITY_15, flash_protect_job, (td_u32)is_volatile, 0, 0, 0, 0);
|
|
if (ret != EXT_ERR_SUCCESS) {
|
|
ctrl->job_add_errs++;
|
|
}
|
|
ctrl->timer_started = TD_FALSE;
|
|
}
|
|
|
|
EXT_PRV td_u32 get_timer_val(ext_flash_protect_type type)
|
|
{
|
|
if (type == EXT_FLASH_PROTECT_TYPE_1) {
|
|
return PROTECT_TIMEOUT_1;
|
|
} else if (type == EXT_FLASH_PROTECT_TYPE_2) {
|
|
return PROTECT_TIMEOUT_2;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
EXT_PRV td_u32 flash_protect(td_u32 addr, td_u32 timeout, td_bool is_volatile, td_bool to_reduce_times)
|
|
{
|
|
td_u32 ret;
|
|
td_s8 i;
|
|
ext_flash_protect_ctrl *ctrl = &g_protect_ctrl;
|
|
|
|
if (ctrl->enable == TD_FALSE) {
|
|
return EXT_ERR_SUCCESS; /* Returned successfully without being enabled */
|
|
}
|
|
td_u32 block = (addr / BLOCK_SIZE);
|
|
if (to_reduce_times && block >= ctrl->current_block) {
|
|
/* To erase/write the address has been unlocked */
|
|
return EXT_ERR_SUCCESS;
|
|
}
|
|
for (i = (sizeof(g_flash_protect_size) / sizeof(ext_flash_protect_size)) - 1; i >= 0; i--) {
|
|
if (block >= g_flash_protect_size[i].block) {
|
|
ctrl->protected_times++;
|
|
ret = spi_flash_set_protect(g_flash_protect_size[i].cmp_bp, is_volatile);
|
|
if (ret != EXT_ERR_SUCCESS) {
|
|
ctrl->protect_errs++;
|
|
return ret;
|
|
}
|
|
|
|
ctrl->current_block = g_flash_protect_size[i].block;
|
|
|
|
break;
|
|
}
|
|
}
|
|
if (i < 0) {
|
|
ctrl->protect_errs++;
|
|
return EXT_ERR_NOT_FOUND;
|
|
}
|
|
if (timeout) {
|
|
if (timeout == PROTECT_TIMEOUT_AUTO) {
|
|
ctrl->timer_timeout = get_timer_val((ext_flash_protect_type)(ctrl->default_type));
|
|
}
|
|
ret = uapi_timer_start(&(ctrl->timer_handle), (timer_proc_func)flash_protect_timeout, ctrl->timer_timeout,
|
|
EXT_TIMER_TYPE_ONCE, is_volatile);
|
|
if (ret != EXT_ERR_SUCCESS) {
|
|
ctrl->start_timer_errs++;
|
|
return ret;
|
|
}
|
|
ctrl->timer_started = TD_TRUE;
|
|
ctrl->timer_created = TD_TRUE;
|
|
} else {
|
|
if ((ctrl->timer_created == TD_TRUE) || (ctrl->timer_started == TD_TRUE)) {
|
|
(td_void)uapi_timer_stop(&(ctrl->timer_handle));
|
|
ctrl->timer_started = TD_FALSE;
|
|
}
|
|
}
|
|
return EXT_ERR_SUCCESS;
|
|
}
|
|
|
|
td_u32 uapi_flash_protect_init(ext_flash_protect_type type)
|
|
{
|
|
ext_flash_protect_ctrl *ctrl = &g_protect_ctrl;
|
|
|
|
if (type >= EXT_FLASH_PROTECT_TYPE_MAX) {
|
|
return EXT_ERR_INVALID_PARAMETER;
|
|
}
|
|
ctrl->default_type = type;
|
|
|
|
return EXT_ERR_SUCCESS;
|
|
}
|
|
|
|
td_u32 uapi_flash_protect_enable(td_bool enable)
|
|
{
|
|
ext_flash_protect_ctrl *ctrl = &g_protect_ctrl;
|
|
|
|
flash_lock();
|
|
if (enable) {
|
|
td_u32 reg_val;
|
|
|
|
if (ctrl->default_type == EXT_FLASH_PROTECT_NONE) {
|
|
flash_unlock();
|
|
return EXT_ERR_NOT_SUPPORT;
|
|
}
|
|
reg_val = UAPI_REG_READ_VAL32(REG_PROTECT_FLASH);
|
|
if (!(reg_val & SUPPORT_PROTECT_FLASH)) {
|
|
flash_unlock();
|
|
return EXT_ERR_FLASH_PROTECT_BOOT_COMPATIBILITY;
|
|
}
|
|
ctrl->enable = TD_TRUE;
|
|
} else {
|
|
flash_protect_config(0, 0); /* Release all protection */
|
|
ctrl->enable = TD_FALSE;
|
|
}
|
|
flash_unlock();
|
|
return EXT_ERR_SUCCESS;
|
|
}
|
|
|
|
td_u32 flash_protect_config(td_u32 ep_addr, td_u32 timeout)
|
|
{
|
|
td_u32 ret;
|
|
|
|
flash_lock();
|
|
ret = flash_protect(ep_addr, timeout, TD_FALSE, TD_FALSE);
|
|
flash_unlock();
|
|
return ret;
|
|
}
|
|
|
|
td_u32 flash_volatile_protect_config(td_u32 ep_addr, td_u32 timeout)
|
|
{
|
|
td_u32 ret;
|
|
ext_flash_protect_ctrl *ctrl = &g_protect_ctrl;
|
|
|
|
flash_lock();
|
|
if (ctrl->default_type != EXT_FLASH_PROTECT_TYPE_1) {
|
|
flash_unlock();
|
|
return EXT_ERR_NOT_SUPPORT;
|
|
}
|
|
ret = flash_protect(ep_addr, timeout, TD_TRUE, TD_FALSE);
|
|
flash_unlock();
|
|
|
|
return ret;
|
|
}
|
|
|
|
td_u32 uapi_flash_protect_config(td_u32 ep_addr, td_u32 timeout)
|
|
{
|
|
ext_flash_protect_ctrl *ctrl = &g_protect_ctrl;
|
|
|
|
if (ctrl->enable == TD_FALSE) {
|
|
return EXT_ERR_NOT_SUPPORT;
|
|
}
|
|
|
|
return flash_protect_config(ep_addr, timeout);
|
|
}
|
|
|
|
td_u32 uapi_flash_volatile_protect_config(td_u32 ep_addr, td_u32 timeout)
|
|
{
|
|
ext_flash_protect_ctrl *ctrl = &g_protect_ctrl;
|
|
|
|
if (ctrl->enable == TD_FALSE) {
|
|
return EXT_ERR_NOT_SUPPORT;
|
|
}
|
|
|
|
return flash_volatile_protect_config(ep_addr, timeout);
|
|
}
|
|
|
|
ext_flash_protect_ctrl *uapi_flash_protect_get_ctrl_info(td_void)
|
|
{
|
|
return &g_protect_ctrl;
|
|
}
|
|
|
|
#endif /* PRODUCT_CFG_SUPPORT_FLASH_PROTECT */
|
|
|
|
EXT_PRV td_u32 flash_check_ram_addr_size(EXT_CONST td_u32 addr, td_u32 size)
|
|
{
|
|
if (addr >= EXT_PERMANENT_MEM_END_ADDR && addr < EXT_DYNAMIC_MEM_VIR_END_ADDR) {
|
|
return EXT_ERR_FLASH_INVALID_RAM_ADDR;
|
|
}
|
|
|
|
if (addr + size > EXT_PERMANENT_MEM_END_ADDR && addr + size <= EXT_DYNAMIC_MEM_VIR_END_ADDR) {
|
|
return EXT_ERR_FLASH_INVALID_RAM_ADDR;
|
|
}
|
|
return EXT_ERR_SUCCESS;
|
|
}
|
|
/*
|
|
* Quickly read the flash interface for missing pages, requiring:
|
|
* The FLASH and RAM addresses are aligned in 4 bytes.
|
|
* Internal address writes use physical addresses instead of virtual addresses.
|
|
*/
|
|
td_u32 uapi_flash_fast_read(td_u32 flash_addr, td_u32 flash_read_size, td_u8 *flash_read_data)
|
|
{
|
|
td_u32 ret;
|
|
EXT_SPI_FLASH_CTRL_S *spif_ctrl = &g_flash_drv_ctrl;
|
|
|
|
if (spif_ctrl->bInit != TD_TRUE) {
|
|
return EXT_ERR_NO_INITILIZATION;
|
|
}
|
|
|
|
flash_lock();
|
|
ret = spif_ctrl->p_read(spif_ctrl, flash_addr, flash_read_size, flash_read_data, TD_FALSE);
|
|
flash_unlock();
|
|
|
|
return ret;
|
|
}
|
|
|
|
td_u32 uapi_flash_erase_in(EXT_IN td_u32 flash_addr, EXT_IN td_u32 flash_erase_size)
|
|
{
|
|
td_u32 ret = EXT_ERR_FAILURE;
|
|
EXT_SPI_FLASH_CTRL_S *spif_ctrl = &g_flash_drv_ctrl;
|
|
|
|
ret = sfc_check_para(spif_ctrl, flash_addr, flash_erase_size, EXT_FLASH_CHECK_PARAM_OPT_ERASE);
|
|
if (ret != EXT_ERR_SUCCESS) {
|
|
flash_info_print("uapi_flash_erase ret1:%x\r\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
flash_lock();
|
|
if (g_flash_prepare_func) {
|
|
g_flash_prepare_func();
|
|
}
|
|
#ifdef PRODUCT_CFG_SUPPORT_FLASH_PROTECT
|
|
ret = flash_protect(flash_addr, PROTECT_TIMEOUT_AUTO, TD_TRUE, TD_TRUE);
|
|
if (ret != EXT_ERR_SUCCESS) {
|
|
if (g_flash_restore_func) {
|
|
g_flash_restore_func();
|
|
}
|
|
flash_unlock();
|
|
return ret;
|
|
}
|
|
#endif /* PRODUCT_CFG_SUPPORT_FLASH_PROTECT */
|
|
ret = flash_erase_prv(spif_ctrl, flash_addr, flash_erase_size);
|
|
if (g_flash_restore_func) {
|
|
g_flash_restore_func();
|
|
}
|
|
flash_unlock();
|
|
|
|
flash_info_print("uapi_flash_erase ret:%x addr:%x len:%x\r\n", ret, flash_addr, flash_erase_size);
|
|
return ret;
|
|
}
|
|
|
|
td_u32 uapi_flash_write_in(EXT_CONST td_u32 flash_addr, td_u32 flash_write_size, EXT_CONST td_u8 *flash_write_data,
|
|
td_bool do_erase)
|
|
{
|
|
td_u32 ret = EXT_ERR_FAILURE;
|
|
EXT_SPI_FLASH_CTRL_S *spif_ctrl = &g_flash_drv_ctrl;
|
|
|
|
if (flash_write_data == TD_NULL) {
|
|
flash_info_print("write pBuf\r\n");
|
|
return EXT_ERR_INVALID_PARAMETER;
|
|
}
|
|
|
|
ret = flash_check_ram_addr_size((td_u32)(uintptr_t)flash_write_data, flash_write_size);
|
|
if (ret != EXT_ERR_SUCCESS) {
|
|
return ret;
|
|
}
|
|
|
|
ret = sfc_check_para(spif_ctrl, flash_addr, flash_write_size, EXT_FLASH_CHECK_PARAM_OPT_WRITE);
|
|
if (ret != EXT_ERR_SUCCESS) {
|
|
flash_info_print("uapi_flash_write ret1:%x\r\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
flash_lock();
|
|
uapi_lowpower_forbid(EXT_LOWPOWER_ID_FLASH, EXT_SLEEP_DEEP);
|
|
if (g_flash_prepare_func) {
|
|
g_flash_prepare_func();
|
|
}
|
|
#ifdef PRODUCT_CFG_SUPPORT_FLASH_PROTECT
|
|
ret = flash_protect(flash_addr, PROTECT_TIMEOUT_AUTO, TD_TRUE, TD_TRUE);
|
|
if (ret != EXT_ERR_SUCCESS) {
|
|
if (g_flash_restore_func) {
|
|
g_flash_restore_func();
|
|
}
|
|
uapi_lowpower_unforbid(EXT_LOWPOWER_ID_FLASH, EXT_SLEEP_DEEP, FLASH_WRITE_TICK_MAX);
|
|
flash_unlock();
|
|
return ret;
|
|
}
|
|
#endif /* PRODUCT_CFG_SUPPORT_FLASH_PROTECT */
|
|
ret = flash_write_prv(spif_ctrl, flash_addr, (td_u8 *)flash_write_data, flash_write_size, do_erase);
|
|
if (g_flash_restore_func) {
|
|
g_flash_restore_func();
|
|
}
|
|
uapi_lowpower_unforbid(EXT_LOWPOWER_ID_FLASH, EXT_SLEEP_DEEP, FLASH_WRITE_TICK_MAX);
|
|
flash_unlock();
|
|
|
|
flash_info_print("uapi_flash_write ret:%x addr:%x len:%x\r\n", ret, flash_addr, flash_write_size);
|
|
return ret;
|
|
}
|
|
|
|
td_u32 uapi_flash_read_in(td_u32 flash_addr, td_u32 flash_read_size, td_u8 *flash_read_data)
|
|
{
|
|
EXT_SPI_FLASH_CTRL_S *spif_ctrl = &g_flash_drv_ctrl;
|
|
td_u32 ret;
|
|
|
|
if (flash_read_data == TD_NULL) {
|
|
flash_info_print("pBuf fail\r\n");
|
|
return EXT_ERR_FLASH_INVALID_PARAM_DATA_NULL;
|
|
}
|
|
|
|
ret = flash_check_ram_addr_size((td_u32)(uintptr_t)flash_read_data, flash_read_size);
|
|
if (ret != EXT_ERR_SUCCESS) {
|
|
return ret;
|
|
}
|
|
|
|
ret = sfc_check_para(spif_ctrl, flash_addr, flash_read_size, EXT_FLASH_CHECK_PARAM_OPT_READ);
|
|
if (ret != EXT_ERR_SUCCESS) {
|
|
flash_info_print("flash_check_para fail %x\r\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
flash_lock();
|
|
uapi_lowpower_forbid(EXT_LOWPOWER_ID_FLASH, EXT_SLEEP_DEEP);
|
|
if (g_flash_prepare_func) {
|
|
g_flash_prepare_func();
|
|
}
|
|
ret = flash_read_prv(spif_ctrl, flash_addr, flash_read_data, flash_read_size);
|
|
if (g_flash_restore_func) {
|
|
g_flash_restore_func();
|
|
}
|
|
uapi_lowpower_unforbid(EXT_LOWPOWER_ID_FLASH, EXT_SLEEP_DEEP, FLASH_READ_TICK_MAX);
|
|
flash_unlock();
|
|
|
|
flash_info_print("uapi_flash_read ret2:%x addr:%x len:%x\r\n", ret, flash_addr, flash_read_size);
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* Command definition, support for general command input, and remapping, replacing own functions
|
|
*/
|
|
td_u32 uapi_flash_ioctl_in(td_u16 cmd, td_void *data)
|
|
{
|
|
td_u32 ret;
|
|
EXT_SPI_FLASH_CTRL_S *spif_ctrl = &g_flash_drv_ctrl;
|
|
|
|
if (spif_ctrl->bInit != TD_TRUE) {
|
|
return EXT_ERR_NO_INITILIZATION;
|
|
}
|
|
|
|
flash_lock();
|
|
uapi_lowpower_forbid(EXT_LOWPOWER_ID_FLASH, EXT_SLEEP_DEEP);
|
|
ret = flash_ioctl(spif_ctrl, cmd, data);
|
|
uapi_lowpower_unforbid(EXT_LOWPOWER_ID_FLASH, EXT_SLEEP_DEEP, FLASH_ERASE_TICK_MAX);
|
|
flash_unlock();
|
|
return ret;
|
|
}
|
|
|
|
td_u32 uapi_flash_erase(EXT_CONST td_u32 addr, EXT_CONST td_u32 size)
|
|
{
|
|
return uapi_flash_erase_in(addr, size);
|
|
}
|
|
td_u32 uapi_flash_write(EXT_CONST td_u32 addr, td_u32 size, EXT_CONST td_u8 *data, td_bool do_erase)
|
|
{
|
|
return uapi_flash_write_in(addr, size, data, do_erase);
|
|
}
|
|
td_u32 uapi_flash_read(EXT_CONST td_u32 addr, EXT_CONST td_u32 size, td_u8 *data)
|
|
{
|
|
return uapi_flash_read_in(addr, size, data);
|
|
}
|
|
td_u32 uapi_flash_ioctl(EXT_IN td_u16 cmd, EXT_INOUT td_void *data)
|
|
{
|
|
return uapi_flash_ioctl_in(cmd, data);
|
|
}
|
|
#define CHIP_ID_SIZE 8
|
|
#define DMA_RAM_SIZE 1024
|
|
|
|
td_u32 uapi_flash_init(td_void)
|
|
{
|
|
EXT_SPI_FLASH_CTRL_S *spif_ctrl = &g_flash_drv_ctrl;
|
|
td_u8 chip_id[CHIP_ID_SIZE] = { 0 };
|
|
td_u32 reg_val;
|
|
|
|
if (spif_ctrl->bInit == TD_TRUE) {
|
|
return EXT_ERR_FLASH_RE_INIT;
|
|
}
|
|
|
|
uapi_lowpower_forbid(EXT_LOWPOWER_ID_FLASH, EXT_SLEEP_DEEP);
|
|
/* Configure the FLASH clock */
|
|
reg_val = UAPI_REG_READ_VAL32(DW21_CRG_REG_SC_PERI_CLKSEL_REG);
|
|
reg_val &= ~(0x1f << CRG_REG_SFC_CLK_SEL_OFFSET);
|
|
reg_val |= (0x9 << CRG_REG_SFC_CLK_SEL_OFFSET); /* divided by 4 75m */
|
|
UAPI_REG_WRITE32(DW21_CRG_REG_SC_PERI_CLKSEL_REG, reg_val);
|
|
|
|
/* Configure DMA buffer */
|
|
spif_ctrl->p_dma_ram_buffer = (td_u8 *)g_dma_buffer;
|
|
spif_ctrl->dma_ram_size = DMA_RAM_SIZE;
|
|
|
|
/* Configure write with wipe backup space, support write interface do_erase to TD_TRUE option */
|
|
spif_ctrl->p_back_up_buf = (td_u8 *)g_back_buffer;
|
|
|
|
/* Initialize the FLASH controller */
|
|
sfc_sys_init();
|
|
|
|
/* Initialize the FLASH driver according to the FLASH ID */
|
|
td_u32 ret = spi_flash_basic_info_probe(spif_ctrl, chip_id, (EXT_SPI_FLASH_BASIC_INFO_S *)g_flash_usr_info_tbl,
|
|
sizeof(g_flash_usr_info_tbl) / sizeof(g_flash_usr_info_tbl[0]));
|
|
if (ret != EXT_ERR_SUCCESS) {
|
|
goto END;
|
|
}
|
|
|
|
/* Configure FLASH to be 4-wire read mode */
|
|
if (spi_flash_enable_quad_mode() == EXT_ERR_SUCCESS) {
|
|
(td_void)memcpy_s(&spif_ctrl->opt_read, sizeof(spif_ctrl->opt_read), &g_spi_opt_fast_quad_out_read,
|
|
sizeof(SPI_FLASH_OPERATION_S));
|
|
}
|
|
|
|
/* Create a FLASH mutex */
|
|
ret = uapi_mux_create(&(spif_ctrl->mutex_handle), "sfc");
|
|
if (ret != EXT_ERR_SUCCESS) {
|
|
goto END;
|
|
}
|
|
#ifdef PRODUCT_CFG_SUPPORT_FLASH_PROTECT
|
|
/* For the DW21EV100 chip, the user needs to adapt the
|
|
protection driver according to the actual Flash selection */
|
|
if (EXT_FTM_CHIP_TYPE_21SV == uapi_get_hw_chip_type()) {
|
|
if (!(spif_ctrl->basic_info.chip_attribute & EXT_SPI_FLASH_CHIP_ATTRIBUTE_IS_DEFAULT_ITEM)) {
|
|
ret = uapi_flash_protect_init((ext_flash_protect_type)(spif_ctrl->basic_info.protect_type));
|
|
if (ret == EXT_ERR_SUCCESS) {
|
|
(td_void)uapi_flash_protect_enable(TD_TRUE);
|
|
ret = uapi_flash_protect_config(spif_ctrl->basic_info.chip_size, 0);
|
|
}
|
|
}
|
|
}
|
|
#endif /* PRODUCT_CFG_SUPPORT_FLASH_PROTECT */
|
|
spif_ctrl->bInit = TD_TRUE;
|
|
END:
|
|
if (ret) {
|
|
sfc_sys_exit();
|
|
}
|
|
uapi_lowpower_unforbid(EXT_LOWPOWER_ID_FLASH, EXT_SLEEP_DEEP, 0);
|
|
return ret;
|
|
}
|
|
|
|
__init td_void uapi_flash_register(EXT_FLASH_REGISTER_S sfunc)
|
|
{
|
|
g_flash_prepare_func = sfunc.prepare_func;
|
|
g_flash_restore_func = sfunc.restore_func;
|
|
}
|