lock_lfvx/bk_idk/middleware/driver/flash/flash_driver_ext.c
2025-10-10 16:07:00 +08:00

383 lines
10 KiB
C
Executable File

// 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 <components/ate.h>
#include <os/mem.h>
#include <driver/flash.h>
#include <os/os.h>
#include "bk_pm_model.h"
#include "flash_driver.h"
#include "flash_hal.h"
#include "sys_driver.h"
#include "driver/flash_partition.h"
#include <modules/chip_support.h>
#include "flash_bypass.h"
#if (CONFIG_SOC_BK7236XX) || (CONFIG_SOC_BK7239XX)
#include "partitions_gen.h"
#endif
#define FLASH_OPERATE_SIZE_AND_OFFSET (4096)
bk_err_t bk_spec_flash_write_bytes(bk_partition_t partition, const uint8_t *user_buf, uint32_t size,uint32_t offset)
{
bk_logic_partition_t *bk_ptr = NULL;
u8 *save_flashdata_buff = NULL;
bk_ptr = bk_flash_partition_get_info(partition);
if((size + offset) > FLASH_OPERATE_SIZE_AND_OFFSET)
return BK_FAIL;
save_flashdata_buff= os_malloc(bk_ptr->partition_length);
if(save_flashdata_buff == NULL)
{
os_printf("save_flashdata_buff malloc err\r\n");
return BK_FAIL;
}
bk_flash_read_bytes((bk_ptr->partition_start_addr),(uint8_t *)save_flashdata_buff, bk_ptr->partition_length);
bk_flash_erase_sector(bk_ptr->partition_start_addr);
os_memcpy((save_flashdata_buff + offset), user_buf, size);
bk_flash_write_bytes(bk_ptr->partition_start_addr ,(uint8_t *)save_flashdata_buff, bk_ptr->partition_length);
os_free(save_flashdata_buff);
save_flashdata_buff = NULL;
return BK_OK;
}
__attribute__((section(".iram")))
#if CONFIG_ARCH_RISCV
void * __attribute__((no_execit, optimize("-O3"))) bk_memcpy_4w(void *dst, void *src, unsigned int size)
#else
void * __attribute__((optimize("-O3"))) bk_memcpy_4w(void *dst, const void *src, unsigned int size) /* 4 words copy. */
#endif
{
unsigned char *dst_ptr = (unsigned char *)dst;
const unsigned char *src_ptr = (const unsigned char *)src;
unsigned int temp1, temp2, temp3, temp4;
if((((unsigned int)src_ptr ^ (unsigned int)dst_ptr) & (sizeof(unsigned int) - 1)) == 0)
{
while( (unsigned int)src_ptr & (sizeof(unsigned int) - 1) )
{
if(size == 0)
return dst;
size--;
*dst_ptr++ = *src_ptr++;
}
const unsigned int *src_wptr = (const unsigned int *)src_ptr;
unsigned int *dst_wptr = (unsigned int *)dst_ptr;
while( size >= (sizeof(unsigned int) * 4) )
{
temp1 = src_wptr[0];
temp2 = src_wptr[1];
temp3 = src_wptr[2];
temp4 = src_wptr[3];
dst_wptr[0] = temp1;
dst_wptr[1] = temp2;
dst_wptr[2] = temp3;
dst_wptr[3] = temp4;
src_wptr += 4;
dst_wptr += 4;
size -= (sizeof(unsigned int) * 4);
}
while( size >= sizeof(unsigned int) )
{
*dst_wptr++ = *src_wptr++;
size -= sizeof(unsigned int);
}
src_ptr = (const unsigned char *)src_wptr;
dst_ptr = (unsigned char *)dst_wptr;
}
while( size > 0 )
{
*dst_ptr++ = *src_ptr++;
size --;
}
return dst;
}
#if defined(CONFIG_SECURITY_OTA) && !defined(CONFIG_TFM_FWU)
#include "partitions.h"
#include "_ota.h"
#if CONFIG_CACHE_ENABLE
#include "cache.h"
#endif
#if CONFIG_INT_WDT
#include <driver/wdt.h>
#include "bk_wdt.h"
#endif
#define CEIL_ALIGN_34(addr) (((addr) + 34 - 1) / 34 * 34)
extern bk_err_t bk_flash_erase_sector(uint32_t address);
extern bk_err_t bk_flash_erase_32k(uint32_t address);
extern bk_err_t bk_flash_erase_block(uint32_t address);
extern void bk_flash_enable_cpu_data_wr(void);
extern void bk_flash_disable_cpu_data_wr(void);
static inline bool is_64k_aligned(uint32_t addr)
{
return ((addr & (KB(64) - 1)) == 0);
}
static inline bool is_32k_aligned(uint32_t addr)
{
return ((addr & (KB(32) - 1)) == 0);
}
/*make sure wdt is closed!*/
bk_err_t bk_flash_erase_fast(uint32_t erase_off, uint32_t len)
{
uint32_t erase_size = 0;
int erase_remain = len;
while (erase_remain > 0) {
if ((erase_remain >= KB(64)) && is_64k_aligned(erase_off)) {
FLASH_LOGD("64k erase: off=%x remain=%x\r\n", erase_off, erase_remain);
bk_flash_erase_block(erase_off);
erase_size = KB(64);
} else if ((erase_remain >= KB(32)) && is_32k_aligned(erase_off)) {
FLASH_LOGD("32k erase: off=%x remain=%x\r\n", erase_off, erase_remain);
bk_flash_erase_32k(erase_off);
erase_size = KB(32);
} else {
FLASH_LOGD("4k erase: off=%x remain=%x\r\n", erase_off, erase_remain);
bk_flash_erase_sector(erase_off);
erase_size = KB(4);
}
erase_off += erase_size;
erase_remain -= erase_size;
}
return BK_OK;
}
__attribute__((section(".iram")))
static void *flash_memcpy(void *d, const void *s, size_t n)
{
return bk_memcpy_4w(d, s, n);
}
__attribute__((section(".iram")))
static void bk_flash_write_cbus_flush(uint32_t address, const uint8_t *user_buf, uint32_t size)
{
volatile uint8_t * temp1;
volatile uint8_t * temp2;
uint8_t temp_data;
if(size > 64)
{
temp1 = (volatile uint8_t *)(0x02000000 + address);
temp2 = (volatile uint8_t *)(0x02000000 + address + 32);
temp_data = *temp1;
temp_data = *temp2;
}
else
{
if((address & (0x1000 - 1)) > 0x800)
{
temp1 = (volatile uint8_t *)(0x02000000 + address - 64); /// sure ????
temp2 = (volatile uint8_t *)(0x02000000 + address - 32);
temp_data = *temp1;
temp_data = *temp2;
}
else
{
temp1 = (volatile uint8_t *)(0x02000000 + address + 64);
temp2 = (volatile uint8_t *)(0x02000000 + address + 96);
temp_data = *temp1;
temp_data = *temp2;
}
}
(void)temp_data;
}
__attribute__((section(".iram")))
static void bk_flash_write_cbus(uint32_t address, const uint8_t *user_buf, uint32_t size)
{
bk_flash_enable_cpu_data_wr();
flash_memcpy((char*)(0x02000000+address), user_buf,size);
// flush out the prefecth buffers (2 buffers, buffer len = 32 bytes.).
bk_flash_write_cbus_flush(address, user_buf,size);
bk_flash_disable_cpu_data_wr();
}
#if CONFIG_OTA_OVERWRITE
static void bk_flash_overwrite_write_dbus(uint32_t off, const void *src, uint32_t len)
{
uint32_t fa_addr = CONFIG_OTA_PHY_PARTITION_OFFSET;
uint32_t addr = fa_addr + off;
bk_flash_write_bytes(addr, src, len);
}
static void bk_flash_overwrite_update(uint32_t off, const void *src, uint32_t len)
{
bk_flash_overwrite_write_dbus(off, src, len);
}
#endif
__attribute__((section(".iram")))
void bk_flash_read_cbus(uint32_t address, void *user_buf, uint32_t size)
{
flash_memcpy((char*)user_buf, (const char*)(0x02000000+address),size);
}
#if CONFIG_DIRECT_XIP
__attribute__((section(".iram")))
static void bk_flash_xip_write_cbus(uint32_t off, const void *src, uint32_t len)
{
uint32_t fa_off = FLASH_PHY2VIRTUAL(CEIL_ALIGN_34(CONFIG_PRIMARY_ALL_PHY_PARTITION_OFFSET));
if((fa_off+off) & 0x31) // MUST aligh with 32-byte.
return;
uint32_t int_status = rtos_disable_int();
#if CONFIG_CACHE_ENABLE
enable_dcache(0);
#endif
uint32_t write_addr = (fa_off+off);
write_addr |= 1 << 24;
bk_flash_write_cbus(write_addr,src,len);
#if CONFIG_CACHE_ENABLE
enable_dcache(1);
#endif
rtos_enable_int(int_status);
}
void bk_flash_xip_write_dbus(uint32_t off, const void *src, uint32_t len)
{
uint32_t update_id = (flash_get_excute_enable() ^ 1);
uint32_t fa_addr;
if (update_id == 0) {
fa_addr = CONFIG_PRIMARY_ALL_PHY_PARTITION_OFFSET;
} else {
fa_addr = CONFIG_SECONDARY_ALL_PHY_PARTITION_OFFSET;
}
uint32_t addr = fa_addr + off;
bk_flash_write_bytes(addr, src, len);
}
void bk_flash_xip_update(uint32_t off, const void *src, uint32_t len)
{
#if CONFIG_OTA_ENCRYPTED
bk_flash_xip_write_dbus(off, src, len);
#else
bk_flash_xip_write_cbus(off, src, len);
#endif
}
static uint32_t boot_xip_magic_off(uint32_t fa_id)
{
uint32_t phy_offset = 0xFFFFFFFF;
if(fa_id == 0) {
phy_offset = CEIL_ALIGN_34(CONFIG_PRIMARY_ALL_PHY_PARTITION_OFFSET + CONFIG_PRIMARY_ALL_PHY_PARTITION_SIZE - 4096);
} else if (fa_id == 1){
phy_offset = CEIL_ALIGN_34(CONFIG_SECONDARY_ALL_PHY_PARTITION_OFFSET + CONFIG_SECONDARY_ALL_PHY_PARTITION_SIZE - 4096);
}
return phy_offset;
}
void bk_flash_write_xip_status(uint32_t fa_id, uint32_t type, uint32_t status)
{
uint32_t offset = boot_xip_magic_off(fa_id) + (type -1 ) * 32;
const uint8_t * value = (const uint8_t *)&(status);
bk_flash_write_bytes(offset,value,4);
}
#endif /*CONFIG_DIRECT_XIP*/
#if CONFIG_OTA_CONFIRM_UPDATE
static uint32_t boot_overwrite_magic_off(void)
{
uint32_t phy_offset = (CONFIG_PRIMARY_ALL_PHY_PARTITION_OFFSET + CONFIG_PRIMARY_ALL_PHY_PARTITION_SIZE - 4);
return phy_offset;
}
void bk_flash_ota_write_confirm(uint32_t status)
{
uint32_t offset = boot_overwrite_magic_off();
const uint8_t * value = (const uint8_t *)&(status);
bk_flash_write_bytes(offset,value,4);
}
void bk_flash_ota_erase_confirm()
{
bk_flash_erase_fast(CONFIG_PRIMARY_ALL_PHY_PARTITION_OFFSET + CONFIG_PRIMARY_ALL_PHY_PARTITION_SIZE - 4096,4096);
}
#endif
void bk_flash_ota_update(uint32_t off, const void *src, uint32_t len)
{
#if CONFIG_DIRECT_XIP
bk_flash_xip_update(off, src, len);
#elif CONFIG_OTA_OVERWRITE
bk_flash_overwrite_update(off, src, len);
#endif
}
void bk_flash_ota_erase(void)
{
#if CONFIG_DIRECT_XIP
uint32_t update_id = flash_get_excute_enable() ^ 1;
uint32_t erase_addr;
if (update_id == 0) {
erase_addr = CONFIG_PRIMARY_ALL_PHY_PARTITION_OFFSET;
} else {
erase_addr = CONFIG_SECONDARY_ALL_PHY_PARTITION_OFFSET;
}
uint32_t erase_size = CONFIG_PRIMARY_ALL_PHY_PARTITION_SIZE;
#elif CONFIG_OTA_OVERWRITE
bk_flash_erase_fast(CONFIG_PRIMARY_ALL_PHY_PARTITION_OFFSET + CONFIG_PRIMARY_ALL_PHY_PARTITION_SIZE - 4096,4096);
uint32_t erase_addr = CONFIG_OTA_PHY_PARTITION_OFFSET;
uint32_t erase_size = CONFIG_OTA_PHY_PARTITION_SIZE;
#endif
#if CONFIG_INT_WDT
extern bk_err_t bk_wdt_stop(void);
extern bk_err_t bk_wdt_start(uint32_t timeout_ms);
bk_wdt_stop();
#endif
bk_flash_erase_fast(erase_addr,erase_size);
#if CONFIG_INT_WDT
bk_wdt_start(CONFIG_INT_WDT_PERIOD_MS);
#endif
}
#if CONFIG_DIRECT_XIP
void bk_flash_ota_write_magic(void)
{
uint32_t update_id = flash_get_excute_enable() ^ 1;
bk_flash_write_xip_status(update_id,XIP_MAGIC_TYPE,XIP_SET);
}
#endif
#endif // CONFIG_SECURITY_OTA && !CONFIG_TFM_FWU