350 lines
6.7 KiB
C
350 lines
6.7 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 <common/bk_include.h>
|
||
|
|
#include <os/os.h>
|
||
|
|
#include <driver/flash.h>
|
||
|
|
#include "flash_driver.h"
|
||
|
|
// #include "mb_ipc_cmd.h"
|
||
|
|
|
||
|
|
static void (*s_flash_op_notify)(uint32_t param) = NULL;
|
||
|
|
|
||
|
|
bk_err_t mb_flash_register_op_notify(void * notify_cb)
|
||
|
|
{
|
||
|
|
s_flash_op_notify = (void (*)(uint32_t))notify_cb;
|
||
|
|
|
||
|
|
return BK_OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
bk_err_t mb_flash_unregister_op_notify(void * notify_cb)
|
||
|
|
{
|
||
|
|
if(s_flash_op_notify == notify_cb)
|
||
|
|
{
|
||
|
|
s_flash_op_notify = NULL;
|
||
|
|
return BK_OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
return BK_ERR_FLASH_WAIT_CB_NOT_REGISTER;
|
||
|
|
}
|
||
|
|
|
||
|
|
#if CONFIG_FLASH_MB
|
||
|
|
|
||
|
|
#include <driver/mailbox_channel.h>
|
||
|
|
#if CONFIG_CACHE_ENABLE
|
||
|
|
#include "cache.h"
|
||
|
|
#endif
|
||
|
|
|
||
|
|
enum
|
||
|
|
{
|
||
|
|
IPC_FLASH_OP_COMPLETE = 0,
|
||
|
|
IPC_FLASH_OP_REQ,
|
||
|
|
IPC_FLASH_OP_ACK,
|
||
|
|
};
|
||
|
|
|
||
|
|
enum
|
||
|
|
{
|
||
|
|
IPC_FLASH_OP_START = 0,
|
||
|
|
IPC_FLASH_OP_END,
|
||
|
|
};
|
||
|
|
|
||
|
|
#if CONFIG_SYS_CPU0
|
||
|
|
#include <driver/aon_rtc.h>
|
||
|
|
|
||
|
|
#define FLASH_WAIT_ACK_TIMEOUT 5000
|
||
|
|
|
||
|
|
static volatile uint32_t flash_erase_ipc_state = IPC_FLASH_OP_COMPLETE;
|
||
|
|
|
||
|
|
extern int mb_ipc_cpu_is_power_off(u32 cpu_id);
|
||
|
|
|
||
|
|
#if 1 // new design of flash operation notification.
|
||
|
|
|
||
|
|
static bk_err_t send_flash_op_state(uint8_t state)
|
||
|
|
{
|
||
|
|
uint64_t us_start = 0;
|
||
|
|
uint64_t us_end = 0;
|
||
|
|
|
||
|
|
flash_erase_ipc_state = IPC_FLASH_OP_REQ;
|
||
|
|
|
||
|
|
mb_chnl_cmd_t cmd_buf;
|
||
|
|
|
||
|
|
cmd_buf.hdr.data = 0; /* clear hdr. */
|
||
|
|
cmd_buf.hdr.cmd = state;
|
||
|
|
cmd_buf.param1 = flash_erase_ipc_state;
|
||
|
|
|
||
|
|
bk_err_t ret_val = mb_chnl_write(MB_CHNL_FLASH, &cmd_buf);
|
||
|
|
|
||
|
|
if(ret_val != BK_OK)
|
||
|
|
return ret_val;
|
||
|
|
|
||
|
|
|
||
|
|
#if CONFIG_AON_RTC
|
||
|
|
us_start = bk_aon_rtc_get_us();
|
||
|
|
#endif
|
||
|
|
for(int i = 0; i < 2000; i++)
|
||
|
|
{
|
||
|
|
if(flash_erase_ipc_state == IPC_FLASH_OP_ACK)
|
||
|
|
{
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
#if CONFIG_AON_RTC
|
||
|
|
us_end = bk_aon_rtc_get_us();
|
||
|
|
#endif
|
||
|
|
// wait ack time should not be more than 5 ms
|
||
|
|
if((us_end - us_start) > FLASH_WAIT_ACK_TIMEOUT)
|
||
|
|
{
|
||
|
|
return BK_FAIL;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return BK_OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
bk_err_t mb_flash_op_prepare(void) // CPU0 notify CPU1 before flash operation
|
||
|
|
{
|
||
|
|
bk_err_t ret_val = BK_OK;
|
||
|
|
|
||
|
|
#if (CONFIG_CPU_CNT > 1)
|
||
|
|
if( mb_ipc_cpu_is_power_off(1) ) // cpu1 power off!
|
||
|
|
return BK_OK;
|
||
|
|
|
||
|
|
ret_val = send_flash_op_state(IPC_FLASH_OP_START);
|
||
|
|
#endif
|
||
|
|
|
||
|
|
return ret_val;
|
||
|
|
}
|
||
|
|
|
||
|
|
bk_err_t mb_flash_op_finish(void) // CPU0 notify CPU1 after flash operation
|
||
|
|
{
|
||
|
|
bk_err_t ret_val = BK_OK;
|
||
|
|
|
||
|
|
#if (CONFIG_CPU_CNT > 1)
|
||
|
|
if( mb_ipc_cpu_is_power_off(1) ) // cpu1 power off!
|
||
|
|
return BK_OK;
|
||
|
|
|
||
|
|
ret_val = send_flash_op_state(IPC_FLASH_OP_END);
|
||
|
|
#endif
|
||
|
|
|
||
|
|
return ret_val;
|
||
|
|
}
|
||
|
|
|
||
|
|
#else
|
||
|
|
|
||
|
|
static bk_err_t send_pause_cmd(uint8_t log_chnl)
|
||
|
|
{
|
||
|
|
mb_chnl_cmd_t cmd_buf;
|
||
|
|
cmd_buf.hdr.data = 0; /* clear hdr. */
|
||
|
|
cmd_buf.hdr.cmd = 1;
|
||
|
|
flash_erase_ipc_state = IPC_FLASH_OP_REQ;
|
||
|
|
cmd_buf.param1 = (u32)&flash_erase_ipc_state;
|
||
|
|
|
||
|
|
return mb_chnl_write(log_chnl, &cmd_buf);
|
||
|
|
}
|
||
|
|
|
||
|
|
bk_err_t mb_flash_op_prepare(void) // CPU0 notify CPU1 before flash operation
|
||
|
|
{
|
||
|
|
uint64_t us_start = 0;
|
||
|
|
uint64_t us_end = 0;
|
||
|
|
|
||
|
|
bk_err_t ret_val = send_pause_cmd(MB_CHNL_FLASH);
|
||
|
|
|
||
|
|
if(ret_val != BK_OK)
|
||
|
|
return ret_val;
|
||
|
|
|
||
|
|
us_start = bk_aon_rtc_get_us();
|
||
|
|
|
||
|
|
for(int i = 0; i < 2000; i++)
|
||
|
|
{
|
||
|
|
#if CONFIG_CACHE_ENABLE
|
||
|
|
flush_dcache((void *)&flash_erase_ipc_state, 4);
|
||
|
|
#endif
|
||
|
|
if(flash_erase_ipc_state == IPC_FLASH_OP_ACK)
|
||
|
|
{
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
us_end = bk_aon_rtc_get_us();
|
||
|
|
// wait ack time should not be more than 5 ms
|
||
|
|
if((us_end - us_start) > FLASH_WAIT_ACK_TIMEOUT)
|
||
|
|
{
|
||
|
|
return BK_FAIL;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return BK_OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
bk_err_t mb_flash_op_finish(void) // CPU0 notify CPU1 after flash operation
|
||
|
|
{
|
||
|
|
flash_erase_ipc_state = IPC_FLASH_OP_COMPLETE;
|
||
|
|
|
||
|
|
return BK_OK;
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
|
||
|
|
#endif
|
||
|
|
|
||
|
|
#if CONFIG_SYS_CPU1
|
||
|
|
|
||
|
|
#if 1
|
||
|
|
|
||
|
|
static void cpu1_pause_handle(mb_chnl_cmd_t *cmd_buf)
|
||
|
|
{
|
||
|
|
if(cmd_buf->param1 != IPC_FLASH_OP_REQ)
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
if(cmd_buf->hdr.cmd == IPC_FLASH_OP_START)
|
||
|
|
{
|
||
|
|
// disable the LCD dev interrupt.
|
||
|
|
if(s_flash_op_notify != NULL)
|
||
|
|
s_flash_op_notify(0);
|
||
|
|
}
|
||
|
|
else if(cmd_buf->hdr.cmd == IPC_FLASH_OP_END)
|
||
|
|
{
|
||
|
|
// enable the LCD dev interrupt.
|
||
|
|
if(s_flash_op_notify != NULL)
|
||
|
|
s_flash_op_notify(1);
|
||
|
|
}
|
||
|
|
|
||
|
|
cmd_buf->param1 = IPC_FLASH_OP_ACK;
|
||
|
|
|
||
|
|
return;
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
#else
|
||
|
|
|
||
|
|
__attribute__((section(".iram"))) static bk_err_t cpu1_pause_handle(mb_chnl_cmd_t *cmd_buf)
|
||
|
|
{
|
||
|
|
volatile uint32_t * stat_addr = (volatile uint32_t *)cmd_buf->param1;
|
||
|
|
|
||
|
|
#if CONFIG_CACHE_ENABLE
|
||
|
|
flush_dcache((void *)stat_addr, 4);
|
||
|
|
#endif
|
||
|
|
|
||
|
|
// only puase cpu1 when flash erasing
|
||
|
|
if(*(stat_addr) == IPC_FLASH_OP_REQ)
|
||
|
|
{
|
||
|
|
uint32_t flags = rtos_disable_int();
|
||
|
|
|
||
|
|
// disable the LCD dev interrupt.
|
||
|
|
if(s_flash_op_notify != NULL)
|
||
|
|
s_flash_op_notify(0);
|
||
|
|
|
||
|
|
rtos_enable_int(flags);
|
||
|
|
|
||
|
|
bk_flash_set_operate_status(FLASH_OP_BUSY);
|
||
|
|
*(stat_addr) = IPC_FLASH_OP_ACK;
|
||
|
|
while(*(stat_addr) != IPC_FLASH_OP_COMPLETE)
|
||
|
|
{
|
||
|
|
#if CONFIG_CACHE_ENABLE
|
||
|
|
flush_dcache((void *)stat_addr, 4);
|
||
|
|
#endif
|
||
|
|
}
|
||
|
|
bk_flash_set_operate_status(FLASH_OP_IDLE);
|
||
|
|
|
||
|
|
// enable the LCD dev interrupt.
|
||
|
|
if(s_flash_op_notify != NULL)
|
||
|
|
s_flash_op_notify(1);
|
||
|
|
}
|
||
|
|
|
||
|
|
return BK_OK;
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
|
||
|
|
#endif
|
||
|
|
|
||
|
|
#if CONFIG_SYS_CPU0
|
||
|
|
static void mb_flash_ipc_tx_cmpl_isr(void *chn_param, mb_chnl_ack_t *ack_buf)
|
||
|
|
{
|
||
|
|
if((ack_buf->hdr.state & CHNL_STATE_COM_FAIL) == 0)
|
||
|
|
{
|
||
|
|
flash_erase_ipc_state = ack_buf->ack_data1;
|
||
|
|
}
|
||
|
|
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
|
||
|
|
static void mb_flash_ipc_rx_isr(void *chn_param, mb_chnl_cmd_t *cmd_buf)
|
||
|
|
{
|
||
|
|
#if CONFIG_SYS_CPU1
|
||
|
|
cpu1_pause_handle(cmd_buf);
|
||
|
|
#endif
|
||
|
|
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
bk_err_t mb_flash_ipc_init(void)
|
||
|
|
{
|
||
|
|
bk_err_t ret_code = mb_chnl_open(MB_CHNL_FLASH, NULL);
|
||
|
|
|
||
|
|
if(ret_code != BK_OK)
|
||
|
|
{
|
||
|
|
return ret_code;
|
||
|
|
}
|
||
|
|
|
||
|
|
// call chnl driver to register isr callback;
|
||
|
|
#if CONFIG_SYS_CPU0
|
||
|
|
mb_chnl_ctrl(MB_CHNL_FLASH, MB_CHNL_SET_TX_CMPL_ISR, (void *)mb_flash_ipc_tx_cmpl_isr);
|
||
|
|
#endif
|
||
|
|
|
||
|
|
mb_chnl_ctrl(MB_CHNL_FLASH, MB_CHNL_SET_RX_ISR, (void *)mb_flash_ipc_rx_isr);
|
||
|
|
|
||
|
|
return ret_code;
|
||
|
|
}
|
||
|
|
|
||
|
|
#else
|
||
|
|
|
||
|
|
bk_err_t mb_flash_ipc_init(void)
|
||
|
|
{
|
||
|
|
return BK_OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
bk_err_t mb_flash_op_prepare(void)
|
||
|
|
{
|
||
|
|
// disable the LCD dev interrupt.
|
||
|
|
if(s_flash_op_notify != NULL)
|
||
|
|
s_flash_op_notify(0);
|
||
|
|
|
||
|
|
return BK_OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
bk_err_t mb_flash_op_finish(void)
|
||
|
|
{
|
||
|
|
// enable the LCD dev interrupt.
|
||
|
|
if(s_flash_op_notify != NULL)
|
||
|
|
s_flash_op_notify(1);
|
||
|
|
|
||
|
|
return BK_OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
#endif
|
||
|
|
|
||
|
|
static volatile flash_op_status_t s_flash_op_status = 0;
|
||
|
|
|
||
|
|
__attribute__((section(".itcm_sec_code"))) bk_err_t bk_flash_set_operate_status(flash_op_status_t status)
|
||
|
|
{
|
||
|
|
s_flash_op_status = status;
|
||
|
|
return BK_OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
__attribute__((section(".itcm_sec_code"))) flash_op_status_t bk_flash_get_operate_status(void)
|
||
|
|
{
|
||
|
|
return s_flash_op_status;
|
||
|
|
}
|
||
|
|
|