988 lines
29 KiB
C
988 lines
29 KiB
C
#include <string.h>
|
|
#include "project.h"
|
|
#include "base.h"
|
|
#include "kmdw_dfu.h"
|
|
#include "kmdw_utils_crc.h"
|
|
#include "kdev_flash.h"
|
|
#include "kmdw_model.h"
|
|
#include "kmdw_console.h"
|
|
#include "kdrv_clock.h"
|
|
#include "kmdw_power_manager.h"
|
|
#include "kdp_system.h"
|
|
#include "kdrv_cmsis_core.h"
|
|
|
|
#define VERIFY_BLK_SZ FLASH_MINI_BLOCK_SIZE //0x1000
|
|
|
|
#define MODEL_INFO_FLASH_ADDR FLASH_MODEL_FW_INFO_ADDR
|
|
#define MODEL_ALL_BIN_FLASH_ADDR FLASH_MODEL_ALL_ADDR
|
|
|
|
#define BOOT_STATE_CONFIRMED 0x1
|
|
#define BOOT_STATE_FIRST_BOOT 0x2
|
|
#define BOOT_STATE_POST_FIRST_BOOT 0x4
|
|
#define BOOT_STATE_NOT_CONFIRMED 0x8
|
|
|
|
#define MAX_BOOT_SEQ 0x7ffffff0
|
|
|
|
typedef struct {
|
|
u32 partition_id;
|
|
u32 seq;
|
|
u32 flag;
|
|
} dfu_boot_cfg_item_t;
|
|
|
|
typedef struct {
|
|
dfu_boot_cfg_item_t scpu_cfg;
|
|
dfu_boot_cfg_item_t ncpu_cfg;
|
|
} dfu_boot_cfg_t;
|
|
|
|
// Initial buffer for boot configuration
|
|
static u8 init_ver_buf[0x40 + sizeof(dfu_boot_cfg_t)];
|
|
|
|
/* tmp buffer for content verification
|
|
* passed by caller, length should be at least VERIFY_BLK_SZ */
|
|
static u8 *tmp_ver_buf = init_ver_buf;
|
|
static FnReadData fn_read_data = NULL;
|
|
|
|
/* ############################
|
|
* ## static functions ##
|
|
* ############################ */
|
|
|
|
static dfu_boot_cfg_t boot_cfg_0, boot_cfg_1;
|
|
|
|
int flashing;
|
|
|
|
static int flash_wait_ready(int timeout_ms)
|
|
{
|
|
kdev_flash_status_t flash_status;
|
|
int i;
|
|
|
|
for (i = 0; i < timeout_ms; i++) {
|
|
flash_status = kdev_flash_get_status();
|
|
if (flash_status.busy == 0) break;
|
|
kdrv_delay_us(1*1000);
|
|
}
|
|
if (i == timeout_ms) i = -1; // we have timed out
|
|
return i;
|
|
}
|
|
|
|
static int dfu_update_sleep(enum kmdw_power_manager_device_id dev_id)
|
|
{
|
|
while (flashing == 1) {
|
|
err_msg("dfu_update_sleep: stop for flashing.\n");
|
|
osThreadFlagsWait(BIT27, osFlagsWaitAll, osWaitForever);
|
|
}
|
|
err_msg("dfu_update_sleep: ok\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int dfu_update_deep_sleep(enum kmdw_power_manager_device_id dev_id)
|
|
{
|
|
while (flashing == 1) {
|
|
err_msg("dfu_update_deep_sleep: stop for flashing.\n");
|
|
osThreadFlagsWait(BIT27, osFlagsWaitAll, osWaitForever);
|
|
}
|
|
err_msg("dfu_update_deep_sleep: ok\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
Compare flash content with buffer content, the size shall be more than 4k,
|
|
because small block (<4k) was verified already, here is to verify the
|
|
consistency/integrity among 4k blocks
|
|
Return:
|
|
0 - success
|
|
-1 - fail
|
|
*/
|
|
|
|
static int dfu_post_flash_verify_4kblock(u32 flash_addr, u32 size, u8 *pbuf)
|
|
{
|
|
int remainder, loop, i, ret, len;
|
|
|
|
loop = size / VERIFY_BLK_SZ;
|
|
if (size % VERIFY_BLK_SZ)
|
|
loop += 1;
|
|
remainder = size;
|
|
u8* flash_sector_check = tmp_ver_buf + 0x40;
|
|
|
|
for (i = 0; i < loop; i++) {
|
|
len = remainder > VERIFY_BLK_SZ ? VERIFY_BLK_SZ : remainder;
|
|
kdev_flash_readdata((flash_addr + i * VERIFY_BLK_SZ) & 0xFFFFF000,
|
|
flash_sector_check, len); // read the new sector
|
|
ret = flash_wait_ready(300);
|
|
if (ret == -1)
|
|
{
|
|
err_msg("Flash read failure, timeout\n");
|
|
return -1;
|
|
}
|
|
|
|
ret = memcmp(flash_sector_check, pbuf + i * VERIFY_BLK_SZ, len);
|
|
if (ret != 0)
|
|
{
|
|
err_msg("Found diff, flash failed\n");
|
|
return -1;
|
|
}
|
|
remainder -= len;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
Write memory data to flash, the size is 4k blocks (i.e. n*4k)
|
|
|
|
Return:
|
|
0 - success
|
|
-1 - fail
|
|
*/
|
|
static int dfu_mem_to_flash_4k_blocks(u32 mem_addr, u32 flash_addr, u32 size)
|
|
{
|
|
int ret;
|
|
|
|
if (mem_addr & 0x1f != 0)
|
|
{
|
|
err_msg("memory address does not align to 32bit boundary");
|
|
return -1;
|
|
}
|
|
|
|
if (flash_addr & 0x1f != 0)
|
|
{
|
|
err_msg("flash address does not align to 32bit boundary");
|
|
return -1;
|
|
}
|
|
|
|
/* erase flash sectors firstly */
|
|
|
|
u16 sect_num = size / VERIFY_BLK_SZ; /* sector size = 4K */
|
|
if (size % VERIFY_BLK_SZ)
|
|
sect_num += 1;
|
|
u32 offset = 0;
|
|
u32 length = size;
|
|
u32 len = 0;
|
|
for (int sect = 0; sect < sect_num; sect++)
|
|
{
|
|
len = length > VERIFY_BLK_SZ ? VERIFY_BLK_SZ : length;
|
|
kdev_flash_erase_sector(flash_addr + offset);
|
|
ret = flash_wait_ready(300); // wait for the erase operation to complete
|
|
if (ret < 0) {
|
|
dbg_msg("Erase Flash Sector Timeout\n");
|
|
}
|
|
|
|
kdev_flash_programdata((uint32_t)(flash_addr + offset), (void *)(mem_addr + offset), len);
|
|
|
|
offset += len;
|
|
length -= len;
|
|
}
|
|
|
|
kdrv_delay_us(500 * 1000);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
Write memory data to flash, the size is less than 4k
|
|
|
|
Return:
|
|
0 - success
|
|
-1 - fail
|
|
*/
|
|
static int dfu_mem_to_flash_small_block(u32 mem_addr, u32 flash_addr, u32 size)
|
|
{
|
|
int ret;
|
|
|
|
/* validate parameters */
|
|
if (size >= VERIFY_BLK_SZ)
|
|
{
|
|
err_msg("Wrong size, bigger than 4K");
|
|
return -1;
|
|
}
|
|
|
|
if (mem_addr & 0x1f != 0)
|
|
{
|
|
err_msg("memory address does not align to 32bit boundary");
|
|
return -1;
|
|
}
|
|
|
|
if (flash_addr & 0x1f != 0)
|
|
{
|
|
err_msg("flash address does not align to 32bit boundary");
|
|
return -1;
|
|
}
|
|
|
|
/* erase flash sectors firstly */
|
|
|
|
kdev_flash_erase_sector(flash_addr);
|
|
ret = flash_wait_ready(300); // wait for the erase operation to complete
|
|
if (ret < 0) {
|
|
dbg_msg("Erase Flash Sector Timeout\n");
|
|
}
|
|
|
|
kdev_flash_programdata(flash_addr, (void *)mem_addr, size);
|
|
flash_wait_ready(500);
|
|
|
|
/* read back for confirmation*/
|
|
u8* flash_sector_check = tmp_ver_buf + 0x40;
|
|
kdev_flash_readdata(flash_addr, flash_sector_check, size);
|
|
ret = flash_wait_ready(300);
|
|
if (memcmp((void *)mem_addr, (void *)flash_sector_check, size)) {
|
|
err_msg("Flash readback verification fail at flash addr=%x\n", flash_addr);
|
|
return -1;
|
|
}
|
|
|
|
kdrv_delay_us(200 * 1000);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void dfu_init_partition_boot_cfg()
|
|
{
|
|
int ret;
|
|
boot_cfg_0.scpu_cfg.partition_id = 0;
|
|
boot_cfg_0.scpu_cfg.seq = 1;
|
|
boot_cfg_0.scpu_cfg.flag = BOOT_STATE_CONFIRMED;
|
|
|
|
boot_cfg_0.ncpu_cfg.partition_id = 0;
|
|
boot_cfg_0.ncpu_cfg.seq = 1;
|
|
boot_cfg_0.ncpu_cfg.flag = BOOT_STATE_CONFIRMED;
|
|
|
|
boot_cfg_1.scpu_cfg.partition_id = 1;
|
|
boot_cfg_1.scpu_cfg.seq = 0;
|
|
boot_cfg_1.scpu_cfg.flag = BOOT_STATE_NOT_CONFIRMED;
|
|
|
|
boot_cfg_1.ncpu_cfg.partition_id = 1;
|
|
boot_cfg_1.ncpu_cfg.seq = 0;
|
|
boot_cfg_1.ncpu_cfg.flag = BOOT_STATE_NOT_CONFIRMED;
|
|
|
|
kdev_flash_erase_sector(PARTITION_0_CFG_START_IN_FLASH);
|
|
|
|
ret = flash_wait_ready(200);
|
|
if (ret < 0) {
|
|
err_msg("Error: Erase Flash Sector Timeout\n");
|
|
}
|
|
|
|
kdev_flash_erase_sector(PARTITION_1_CFG_START_IN_FLASH);
|
|
|
|
ret = flash_wait_ready(200);
|
|
if (ret < 0) {
|
|
err_msg("Error: Erase Flash Sector Timeout\n");
|
|
}
|
|
|
|
kdev_flash_programdata(PARTITION_0_CFG_START_IN_FLASH, &boot_cfg_0, 32);
|
|
ret = flash_wait_ready(200);
|
|
if (ret < 0) {
|
|
err_msg("Error: Flash partition 0 config Timeout\n");
|
|
}
|
|
|
|
kdev_flash_programdata(PARTITION_1_CFG_START_IN_FLASH, &boot_cfg_1, 32);
|
|
ret = flash_wait_ready(200);
|
|
if (ret < 0) {
|
|
err_msg("Error: Flash partition 1 config Timeout\n");
|
|
}
|
|
|
|
}
|
|
|
|
static void dfu_pre_update()
|
|
{
|
|
NVIC_DisableIRQ(UART_FTUART010_0_IRQ); //UART0
|
|
NVIC_DisableIRQ(UART_FTUART010_1_IRQ); //UART1
|
|
NVIC_DisableIRQ(UART_FTUART010_1_1_IRQ); //UART2
|
|
NVIC_DisableIRQ(UART_FTUART010_1_2_IRQ); //UART3
|
|
NVIC_DisableIRQ(UART_FTUART010_1_3_IRQ); //UART4
|
|
NVIC_DisableIRQ(NPU_NPU_IRQ); //NPU
|
|
}
|
|
|
|
static void dfu_update_abort(u32 reload_flag)
|
|
{
|
|
if (reload_flag)
|
|
kmdw_model_refresh_models(); // reload all the models again
|
|
NVIC_EnableIRQ(UART_FTUART010_0_IRQ); //UART0
|
|
NVIC_EnableIRQ(UART_FTUART010_1_IRQ); //UART1
|
|
NVIC_EnableIRQ(UART_FTUART010_1_1_IRQ); //UART2
|
|
NVIC_EnableIRQ(UART_FTUART010_1_2_IRQ); //UART3
|
|
NVIC_EnableIRQ(UART_FTUART010_1_3_IRQ); //UART4
|
|
NVIC_EnableIRQ(NPU_NPU_IRQ); //NPU
|
|
}
|
|
|
|
/* ############################
|
|
* ## public functions ##
|
|
* ############################ */
|
|
|
|
int kmdw_dfu_init(u8 *tmp_buf, FnReadData fn_read)
|
|
{
|
|
static int flash_checked = 0;
|
|
int ret;
|
|
|
|
if (tmp_buf)
|
|
tmp_ver_buf = tmp_buf;
|
|
if (fn_read)
|
|
fn_read_data = fn_read;
|
|
|
|
if (flash_checked)
|
|
return 0;
|
|
flash_checked = 1;
|
|
|
|
struct kmdw_power_manager_s pms = {
|
|
.sleep = dfu_update_sleep,
|
|
.deep_sleep = dfu_update_deep_sleep,
|
|
};
|
|
|
|
/* read flash to mem */
|
|
|
|
kdev_flash_readdata(PARTITION_0_CFG_START_IN_FLASH, &boot_cfg_0, sizeof(boot_cfg_0));
|
|
flash_wait_ready(300);
|
|
|
|
kdev_flash_readdata(PARTITION_1_CFG_START_IN_FLASH, &boot_cfg_1, sizeof(boot_cfg_1));
|
|
flash_wait_ready(300);
|
|
|
|
if ((boot_cfg_0.scpu_cfg.flag == 0xffffffff) && (boot_cfg_1.scpu_cfg.flag == 0xffffffff)) {
|
|
ret = -1;
|
|
goto exit;
|
|
}
|
|
|
|
if ((boot_cfg_0.scpu_cfg.flag == BOOT_STATE_FIRST_BOOT) ||
|
|
(boot_cfg_0.ncpu_cfg.flag == BOOT_STATE_FIRST_BOOT) ||
|
|
(boot_cfg_1.scpu_cfg.flag == BOOT_STATE_FIRST_BOOT) ||
|
|
(boot_cfg_1.ncpu_cfg.flag == BOOT_STATE_FIRST_BOOT)) {
|
|
err_msg("Error: wrong state, BOOT_STATE_FIRST_BOOT shall not be here\n");
|
|
ret = -1;
|
|
goto exit;
|
|
}
|
|
|
|
/* determine if necessary to read flash */
|
|
|
|
if ((boot_cfg_0.scpu_cfg.flag != BOOT_STATE_POST_FIRST_BOOT) &&
|
|
(boot_cfg_0.ncpu_cfg.flag != BOOT_STATE_POST_FIRST_BOOT) &&
|
|
(boot_cfg_1.scpu_cfg.flag != BOOT_STATE_POST_FIRST_BOOT) &&
|
|
(boot_cfg_1.ncpu_cfg.flag != BOOT_STATE_POST_FIRST_BOOT)) {
|
|
|
|
ret = 0;
|
|
goto exit;
|
|
}
|
|
|
|
if (boot_cfg_0.scpu_cfg.flag == BOOT_STATE_POST_FIRST_BOOT) {
|
|
boot_cfg_0.scpu_cfg.flag = BOOT_STATE_CONFIRMED;
|
|
if(boot_cfg_1.scpu_cfg.flag == BOOT_STATE_CONFIRMED) {
|
|
boot_cfg_1.scpu_cfg.flag = BOOT_STATE_NOT_CONFIRMED;
|
|
}
|
|
err_msg("SCPU partition 0 was confirmed\n");
|
|
|
|
}
|
|
|
|
if (boot_cfg_0.ncpu_cfg.flag == BOOT_STATE_POST_FIRST_BOOT) {
|
|
boot_cfg_0.ncpu_cfg.flag = BOOT_STATE_CONFIRMED;
|
|
if(boot_cfg_1.ncpu_cfg.flag == BOOT_STATE_CONFIRMED) {
|
|
boot_cfg_1.ncpu_cfg.flag = BOOT_STATE_NOT_CONFIRMED;
|
|
}
|
|
err_msg("NCPU partition 0 was confirmed\n");
|
|
}
|
|
|
|
if (boot_cfg_1.scpu_cfg.flag == BOOT_STATE_POST_FIRST_BOOT) {
|
|
boot_cfg_1.scpu_cfg.flag = BOOT_STATE_CONFIRMED;
|
|
if(boot_cfg_0.scpu_cfg.flag == BOOT_STATE_CONFIRMED) {
|
|
boot_cfg_0.scpu_cfg.flag = BOOT_STATE_NOT_CONFIRMED;
|
|
}
|
|
err_msg("SCPU partition 1 was confirmed\n");
|
|
}
|
|
|
|
if (boot_cfg_1.ncpu_cfg.flag == BOOT_STATE_POST_FIRST_BOOT) {
|
|
boot_cfg_1.ncpu_cfg.flag = BOOT_STATE_CONFIRMED;
|
|
if(boot_cfg_0.ncpu_cfg.flag == BOOT_STATE_CONFIRMED) {
|
|
boot_cfg_0.ncpu_cfg.flag = BOOT_STATE_NOT_CONFIRMED;
|
|
}
|
|
err_msg("NCPU partition 1 was confirmed\n");
|
|
}
|
|
|
|
/* write back to flash */
|
|
ret = dfu_mem_to_flash_small_block((u32)&boot_cfg_0, PARTITION_0_CFG_START_IN_FLASH, sizeof(boot_cfg_0));
|
|
if (ret == -1)
|
|
{
|
|
err_msg("Flash write fail on %x\n", PARTITION_0_CFG_START_IN_FLASH);
|
|
ret = MSG_FLASH_FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
ret = dfu_mem_to_flash_small_block((u32)&boot_cfg_1, PARTITION_1_CFG_START_IN_FLASH, sizeof(boot_cfg_1));
|
|
if (ret == -1)
|
|
{
|
|
err_msg("Flash write fail on %x\n", PARTITION_1_CFG_START_IN_FLASH);
|
|
ret = MSG_FLASH_FAIL;
|
|
} else {
|
|
ret = 0;
|
|
}
|
|
|
|
exit:
|
|
kmdw_power_manager_register(KMDW_POWER_MANAGER_DEVICE_DFU_UPDATE, &pms);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int kmdw_dfu_get_active_scpu_partition()
|
|
{
|
|
kdev_flash_readdata(PARTITION_0_CFG_START_IN_FLASH, &boot_cfg_0, sizeof(boot_cfg_0));
|
|
flash_wait_ready(300);
|
|
kdev_flash_readdata(PARTITION_1_CFG_START_IN_FLASH, &boot_cfg_1, sizeof(boot_cfg_1));
|
|
flash_wait_ready(300);
|
|
|
|
if ((boot_cfg_0.scpu_cfg.flag == 0xffffffff) && (boot_cfg_1.scpu_cfg.flag == 0xffffffff)) {
|
|
// no config data is there, need to create them for partition 0/1
|
|
dfu_init_partition_boot_cfg();
|
|
return 0;
|
|
}
|
|
|
|
if (boot_cfg_0.scpu_cfg.flag & boot_cfg_1.scpu_cfg.flag & BOOT_STATE_CONFIRMED)
|
|
{
|
|
err_msg("Critical Error: 2 active SCPU boot config\n");
|
|
return -1;
|
|
}
|
|
|
|
if ((boot_cfg_0.scpu_cfg.partition_id == boot_cfg_1.scpu_cfg.partition_id)
|
|
&& (boot_cfg_0.scpu_cfg.seq == boot_cfg_1.scpu_cfg.seq))
|
|
{
|
|
// no config data is there, need to create them for partition 0/1
|
|
dfu_init_partition_boot_cfg();
|
|
return 0;
|
|
}
|
|
|
|
if ((boot_cfg_0.scpu_cfg.flag & BOOT_STATE_CONFIRMED) == BOOT_STATE_CONFIRMED)
|
|
return 0;
|
|
|
|
if ((boot_cfg_1.scpu_cfg.flag & BOOT_STATE_CONFIRMED) == BOOT_STATE_CONFIRMED)
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
int kmdw_dfu_get_active_ncpu_partition()
|
|
{
|
|
kdev_flash_readdata(PARTITION_0_CFG_START_IN_FLASH, &boot_cfg_0, sizeof(boot_cfg_0));
|
|
flash_wait_ready(300);
|
|
|
|
kdev_flash_readdata(PARTITION_1_CFG_START_IN_FLASH, &boot_cfg_1, sizeof(boot_cfg_1));
|
|
flash_wait_ready(300);
|
|
|
|
if ((boot_cfg_0.ncpu_cfg.flag == 0xffffffff) && (boot_cfg_1.ncpu_cfg.flag == 0xffffffff)) {
|
|
// no config data is there, need to create them for partition 0/1
|
|
dfu_init_partition_boot_cfg();
|
|
return 0;
|
|
}
|
|
|
|
if (boot_cfg_0.ncpu_cfg.flag & boot_cfg_1.ncpu_cfg.flag & BOOT_STATE_CONFIRMED)
|
|
{
|
|
err_msg("Critical Error: 2 active NCPU boot config\n");
|
|
return -1;
|
|
}
|
|
|
|
if ((boot_cfg_0.ncpu_cfg.partition_id == boot_cfg_1.ncpu_cfg.partition_id) &&
|
|
(boot_cfg_0.ncpu_cfg.seq == boot_cfg_1.ncpu_cfg.seq))
|
|
{
|
|
// no config data is there, need to create them for partition 0/1
|
|
dfu_init_partition_boot_cfg();
|
|
return 0;
|
|
}
|
|
|
|
if ((boot_cfg_0.ncpu_cfg.flag & BOOT_STATE_CONFIRMED) == BOOT_STATE_CONFIRMED)
|
|
return 0;
|
|
|
|
if ((boot_cfg_1.ncpu_cfg.flag & BOOT_STATE_CONFIRMED) == BOOT_STATE_CONFIRMED)
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
int kmdw_dfu_update_scpu()
|
|
{
|
|
int ret;
|
|
u8 *pBase;
|
|
u32 local_sum32, remote_sum32;
|
|
u8 pre_active_partition;
|
|
u32 flash_cfg_addr, flash_data_addr;
|
|
dfu_boot_cfg_t dfu_cfg;
|
|
u32 seq;
|
|
|
|
flashing = 1;
|
|
err_msg("kmdw_dfu_update_scpu: flashing ...\n");
|
|
|
|
dfu_pre_update();
|
|
|
|
pBase = (u8 *)DDR_BEGIN;
|
|
memset(pBase, 0, SCPU_IMAGE_SIZE);
|
|
ret = fn_read_data((u32)pBase, SCPU_IMAGE_SIZE);
|
|
if (ret == SCPU_IMAGE_SIZE)
|
|
{
|
|
local_sum32 = kmdw_utils_crc_gen_sum32(pBase, SCPU_IMAGE_SIZE - 4);
|
|
remote_sum32 = *(u32 *)(pBase + SCPU_IMAGE_SIZE - 4);
|
|
if (local_sum32 != remote_sum32) {
|
|
ret = MSG_AUTH_FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
}
|
|
else {
|
|
ret = MSG_DATA_ERROR;
|
|
goto exit;
|
|
}
|
|
|
|
pre_active_partition = kmdw_dfu_get_active_scpu_partition();
|
|
if (pre_active_partition == 0) {
|
|
// active partition is 0, flash to partition 1
|
|
flash_cfg_addr = PARTITION_1_CFG_START_IN_FLASH;
|
|
flash_data_addr = SCPU_PARTITION1_START_IN_FLASH;
|
|
}
|
|
else if(pre_active_partition == 1){
|
|
// active partition is 1, flash to partition 0
|
|
flash_cfg_addr = PARTITION_0_CFG_START_IN_FLASH;
|
|
flash_data_addr = SCPU_PARTITION0_START_IN_FLASH;
|
|
} else {
|
|
ret = MSG_FLASH_FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
// flash data
|
|
ret = dfu_mem_to_flash_4k_blocks((u32)pBase, (u32)flash_data_addr, SCPU_IMAGE_SIZE);
|
|
if (ret == -1)
|
|
{
|
|
ret = MSG_FLASH_FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
ret = dfu_post_flash_verify_4kblock(flash_data_addr, SCPU_IMAGE_SIZE, pBase);
|
|
if (ret != 0) {
|
|
err_msg("Error: post flash verification failed\n");
|
|
ret = MSG_FLASH_FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
// update boot cfg
|
|
|
|
if (pre_active_partition == 0) {
|
|
seq = MAX(boot_cfg_0.scpu_cfg.seq, boot_cfg_1.scpu_cfg.seq);
|
|
|
|
if(seq > MAX_BOOT_SEQ){
|
|
boot_cfg_0.scpu_cfg.seq = 0;
|
|
boot_cfg_1.scpu_cfg.seq = 1;
|
|
} else {
|
|
boot_cfg_1.scpu_cfg.seq = seq + 1;
|
|
}
|
|
boot_cfg_1.scpu_cfg.flag = BOOT_STATE_FIRST_BOOT;
|
|
dfu_cfg = boot_cfg_1;
|
|
}
|
|
else {
|
|
seq = MAX(boot_cfg_0.scpu_cfg.seq, boot_cfg_1.scpu_cfg.seq);
|
|
|
|
if(seq > MAX_BOOT_SEQ){
|
|
boot_cfg_0.scpu_cfg.seq = 1;
|
|
boot_cfg_1.scpu_cfg.seq = 0;
|
|
} else {
|
|
boot_cfg_0.scpu_cfg.seq = seq + 1;
|
|
}
|
|
boot_cfg_0.scpu_cfg.flag = BOOT_STATE_FIRST_BOOT;
|
|
dfu_cfg = boot_cfg_0;
|
|
}
|
|
|
|
ret = dfu_mem_to_flash_small_block((u32)&dfu_cfg, flash_cfg_addr, sizeof(dfu_cfg));
|
|
|
|
kdev_flash_readdata(PARTITION_0_CFG_START_IN_FLASH, &boot_cfg_0, sizeof(boot_cfg_0));
|
|
flash_wait_ready(300);
|
|
|
|
kdev_flash_readdata(PARTITION_1_CFG_START_IN_FLASH, &boot_cfg_1, sizeof(boot_cfg_1));
|
|
flash_wait_ready(300);
|
|
|
|
if (pre_active_partition == 0) {
|
|
ret = memcmp(&boot_cfg_1, &dfu_cfg, sizeof(dfu_cfg));
|
|
}
|
|
else {
|
|
ret = memcmp(&boot_cfg_0, &dfu_cfg, sizeof(dfu_cfg));
|
|
}
|
|
|
|
if (ret == -1)
|
|
ret = MSG_FLASH_FAIL;
|
|
else
|
|
ret = SUCCESS;
|
|
|
|
exit:
|
|
err_msg("kmdw_dfu_update_scpu: flashing done\n");
|
|
flashing = 0;
|
|
return ret;
|
|
}
|
|
|
|
int kmdw_dfu_update_ncpu()
|
|
{
|
|
int ret;
|
|
u8 *pBase;
|
|
u32 local_sum32, remote_sum32;
|
|
u8 pre_active_partition;
|
|
u32 flash_cfg_addr, flash_data_addr;
|
|
dfu_boot_cfg_t dfu_cfg;
|
|
u32 seq;
|
|
|
|
flashing = 1;
|
|
err_msg("kmdw_dfu_update_ncpu: flashing ...\n");
|
|
|
|
dfu_pre_update();
|
|
|
|
pBase = (u8 *)DDR_BEGIN;
|
|
memset(pBase, 0, NCPU_IMAGE_SIZE);
|
|
ret = fn_read_data((u32)pBase, (u32)NCPU_IMAGE_SIZE);
|
|
if (ret == NCPU_IMAGE_SIZE)
|
|
{
|
|
local_sum32 = kmdw_utils_crc_gen_sum32(pBase, NCPU_IMAGE_SIZE - 4);
|
|
remote_sum32 = *(u32 *)(pBase + NCPU_IMAGE_SIZE - 4);
|
|
if (local_sum32 != remote_sum32) {
|
|
ret = MSG_AUTH_FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
}
|
|
else {
|
|
ret = MSG_DATA_ERROR;
|
|
goto exit;
|
|
}
|
|
|
|
pre_active_partition = kmdw_dfu_get_active_ncpu_partition();
|
|
if (pre_active_partition == 0) {
|
|
// active partition is 0, flash to partition 1
|
|
flash_cfg_addr = PARTITION_1_CFG_START_IN_FLASH;
|
|
flash_data_addr = NCPU_PARTITION1_START_IN_FLASH;
|
|
}
|
|
else if (pre_active_partition == 1){
|
|
// active partition is 1, flash to partition 0
|
|
flash_cfg_addr = PARTITION_0_CFG_START_IN_FLASH;
|
|
flash_data_addr = NCPU_PARTITION0_START_IN_FLASH;
|
|
} else {
|
|
ret = MSG_FLASH_FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
// flash data
|
|
ret = dfu_mem_to_flash_4k_blocks((u32)pBase, (u32)flash_data_addr, NCPU_IMAGE_SIZE);
|
|
if (ret == -1)
|
|
{
|
|
ret = MSG_FLASH_FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
ret = dfu_post_flash_verify_4kblock(flash_data_addr, NCPU_IMAGE_SIZE, pBase);
|
|
if (ret != 0) {
|
|
err_msg("Error: post flash verification failed\n");
|
|
ret = MSG_FLASH_FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
// update boot cfg
|
|
|
|
if (pre_active_partition == 0) {
|
|
seq = MAX(boot_cfg_0.ncpu_cfg.seq, boot_cfg_1.ncpu_cfg.seq);
|
|
|
|
if(seq > MAX_BOOT_SEQ){
|
|
boot_cfg_0.ncpu_cfg.seq = 0;
|
|
boot_cfg_1.ncpu_cfg.seq = 1;
|
|
} else {
|
|
boot_cfg_1.ncpu_cfg.seq = seq + 1;
|
|
}
|
|
|
|
boot_cfg_1.ncpu_cfg.flag = BOOT_STATE_FIRST_BOOT;
|
|
dfu_cfg = boot_cfg_1;
|
|
}
|
|
else {
|
|
seq = MAX(boot_cfg_0.ncpu_cfg.seq, boot_cfg_1.ncpu_cfg.seq);
|
|
|
|
if(seq > MAX_BOOT_SEQ){
|
|
boot_cfg_0.ncpu_cfg.seq = 1;
|
|
boot_cfg_1.ncpu_cfg.seq = 0;
|
|
} else {
|
|
boot_cfg_0.ncpu_cfg.seq = seq + 1;
|
|
}
|
|
|
|
boot_cfg_0.ncpu_cfg.flag = BOOT_STATE_FIRST_BOOT;
|
|
dfu_cfg = boot_cfg_0;
|
|
}
|
|
|
|
ret = dfu_mem_to_flash_small_block((u32)&dfu_cfg, flash_cfg_addr, sizeof(dfu_cfg));
|
|
if (ret == -1)
|
|
{
|
|
ret = MSG_FLASH_FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
kdev_flash_readdata(PARTITION_0_CFG_START_IN_FLASH, &boot_cfg_0, sizeof(boot_cfg_0));
|
|
flash_wait_ready(300);
|
|
|
|
kdev_flash_readdata(PARTITION_1_CFG_START_IN_FLASH, &boot_cfg_1, sizeof(boot_cfg_1));
|
|
flash_wait_ready(300);
|
|
|
|
if (pre_active_partition == 0) {
|
|
ret = memcmp(&boot_cfg_1, &dfu_cfg, sizeof(dfu_cfg));
|
|
}
|
|
else {
|
|
ret = memcmp(&boot_cfg_0, &dfu_cfg, sizeof(dfu_cfg));
|
|
}
|
|
|
|
if (ret != 0) {
|
|
err_msg("Error: partition config read back compare fail\n");
|
|
ret = MSG_FLASH_FAIL;
|
|
} else {
|
|
ret = SUCCESS;
|
|
}
|
|
|
|
exit:
|
|
err_msg("kmdw_dfu_update_ncpu: flashing done\n");
|
|
flashing = 0;
|
|
return ret;
|
|
}
|
|
|
|
int kmdw_dfu_update_model(u32 info_size, u32 model_size)
|
|
{
|
|
u32 sum32_download, sum32_embedded;
|
|
u32 ddr_buf;
|
|
int ret;
|
|
u32 size;
|
|
|
|
info_size >>= 16;
|
|
|
|
if (info_size == 0) {
|
|
// non NEF
|
|
size = model_size;
|
|
} else {
|
|
// NEF
|
|
size = info_size + model_size;
|
|
}
|
|
|
|
err_msg("kmdw_dfu_update_model: flashing ...\n");
|
|
dbg_msg("kmdw_dfu_update_model: size: %d %d\n", info_size, model_size);
|
|
dfu_pre_update();
|
|
|
|
ddr_buf = DDR_BEGIN;
|
|
ret = fn_read_data(ddr_buf, size);
|
|
if (ret == size) {
|
|
if (info_size == 0) {
|
|
// non NEF
|
|
sum32_embedded = *(u32 *)(ddr_buf + size - 4);
|
|
sum32_download = kmdw_utils_crc_gen_sum32((u8 *)ddr_buf, size - 4);
|
|
} else {
|
|
// NEF
|
|
u32 model_count;
|
|
kmdw_model_fw_info_t *info_p = (kmdw_model_fw_info_t *)ddr_buf;
|
|
kmdw_model_fw_info_ext_t *info2_p;
|
|
|
|
model_count = info_p->model_count;
|
|
dbg_msg("kmdw_dfu_update_model: model count is %d\n", model_count);
|
|
info2_p = (kmdw_model_fw_info_ext_t *)(ddr_buf + sizeof(uint32_t) + model_count * sizeof(struct kdp_model_s));
|
|
sum32_embedded = info2_p->model_checksum;
|
|
sum32_download = sum32_embedded; // TODO: use crc32 algorithm
|
|
dbg_msg("kmdw_dfu_update_model: checksum 0x%X\n", sum32_download);
|
|
}
|
|
|
|
if (sum32_embedded != sum32_download) {
|
|
err_msg("kmdw_dfu_update_model: checksum error 0x%X : 0x%X\n", sum32_embedded, sum32_download);
|
|
dfu_update_abort(1);
|
|
return MSG_AUTH_FAIL;
|
|
}
|
|
} else {
|
|
dfu_update_abort(1);
|
|
return MSG_DATA_ERROR;
|
|
}
|
|
|
|
if (info_size == 0) {
|
|
// flash model_dfu.bin
|
|
ret = dfu_mem_to_flash_4k_blocks(ddr_buf, MODEL_INFO_FLASH_ADDR, size);
|
|
if (ret == -1) {
|
|
err_msg("Error: flash model_dfu.bin failed %d\n", ret);
|
|
return MSG_FLASH_FAIL;
|
|
}
|
|
|
|
ret = dfu_post_flash_verify_4kblock((u32)MODEL_INFO_FLASH_ADDR, size,
|
|
(u8 *)ddr_buf);
|
|
if (ret != 0) {
|
|
err_msg("Error: verify model_dfu.bin failed %d\n", ret);
|
|
return MSG_FLASH_FAIL;
|
|
}
|
|
} else {
|
|
// check flash space
|
|
if ( model_size > (FLASH_END_ADDR - MODEL_ALL_BIN_FLASH_ADDR) ) {
|
|
err_msg("Error: Not enough flash space\n");
|
|
return MSG_FLASH_NO_SPACE;
|
|
}
|
|
|
|
// flash fw_info.bin
|
|
ret = dfu_mem_to_flash_4k_blocks(ddr_buf, MODEL_INFO_FLASH_ADDR, info_size);
|
|
if (ret == -1) {
|
|
err_msg("Error: flash fw_info.bin failed %d\n", ret);
|
|
return MSG_FLASH_FAIL;
|
|
}
|
|
|
|
ret = dfu_post_flash_verify_4kblock((u32)MODEL_INFO_FLASH_ADDR, info_size,
|
|
(u8 *)ddr_buf);
|
|
if (ret != 0) {
|
|
err_msg("Error: verify fw_info.bin failed %d\n", ret);
|
|
return MSG_FLASH_FAIL;
|
|
}
|
|
|
|
// flash all_models.bin
|
|
ret = dfu_mem_to_flash_4k_blocks(ddr_buf+info_size, MODEL_ALL_BIN_FLASH_ADDR, model_size);
|
|
if (ret == -1) {
|
|
err_msg("Error: flash all_models.bin failed %d\n", ret);
|
|
return MSG_FLASH_FAIL;
|
|
}
|
|
|
|
ret = dfu_post_flash_verify_4kblock((u32)MODEL_ALL_BIN_FLASH_ADDR, model_size,
|
|
(u8 *)(ddr_buf+info_size));
|
|
if (ret != 0) {
|
|
err_msg("Error: verify all_models.bin failed %d\n", ret);
|
|
return MSG_FLASH_FAIL;
|
|
}
|
|
}
|
|
|
|
err_msg("kmdw_dfu_update_model: flashing done\n");
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
int kmdw_dfu_update_spl(u32 file_size)
|
|
{
|
|
u32 ddr_buf, size = file_size;
|
|
int ret;
|
|
u16 tmp;
|
|
|
|
dbg_msg("kmdw_dfu_spl: flashing ...\n");
|
|
dfu_pre_update();
|
|
|
|
ddr_buf = DDR_BEGIN;
|
|
ret = fn_read_data(ddr_buf, size);
|
|
if (ret != size) { // spl has no checksum
|
|
dfu_update_abort(0);
|
|
return MSG_DATA_ERROR;
|
|
}
|
|
|
|
if ((size % VERIFY_BLK_SZ) != 0) {
|
|
tmp = (size + VERIFY_BLK_SZ - 1) / VERIFY_BLK_SZ;
|
|
size = tmp * VERIFY_BLK_SZ;
|
|
}
|
|
|
|
// flash data
|
|
ret = dfu_mem_to_flash_4k_blocks(ddr_buf, 0, size);
|
|
if (ret == -1) {
|
|
dfu_update_abort(0);
|
|
return MSG_FLASH_FAIL;
|
|
}
|
|
|
|
ret = dfu_post_flash_verify_4kblock(0, size, (u8 *)ddr_buf);
|
|
dfu_update_abort(0);
|
|
if (ret != 0) {
|
|
err_msg("Error: post flash verification failed\n");
|
|
return MSG_FLASH_FAIL;
|
|
}
|
|
|
|
dbg_msg("kmdw_dfu_update_spl: flashing done\n");
|
|
kdp_sys_update_spl_image(ddr_buf, file_size);
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
int kmdw_dfu_switch_active_partition(u32 partition)
|
|
{
|
|
u32 seq;
|
|
int ret;
|
|
|
|
if((partition != 1) && (partition != 2)) {
|
|
err_msg("Error: wrong partition number\n");
|
|
return -1;
|
|
}
|
|
|
|
kdev_flash_readdata(PARTITION_0_CFG_START_IN_FLASH, &boot_cfg_0, sizeof(boot_cfg_0));
|
|
flash_wait_ready(300);
|
|
|
|
kdev_flash_readdata(PARTITION_1_CFG_START_IN_FLASH, &boot_cfg_1, sizeof(boot_cfg_1));
|
|
flash_wait_ready(300);
|
|
|
|
if ((boot_cfg_0.scpu_cfg.flag == 0xffffffff) && (boot_cfg_1.scpu_cfg.flag == 0xffffffff)) {
|
|
// no config data is there, need to create them for partition 0/1
|
|
dfu_init_partition_boot_cfg();
|
|
return 0;
|
|
}
|
|
|
|
if (boot_cfg_0.ncpu_cfg.flag & boot_cfg_1.ncpu_cfg.flag & BOOT_STATE_CONFIRMED)
|
|
{
|
|
err_msg("Critical Error: 2 active NCPU boot config\n");
|
|
return -1;
|
|
}
|
|
|
|
if ((boot_cfg_0.ncpu_cfg.partition_id == boot_cfg_1.ncpu_cfg.partition_id)
|
|
&& (boot_cfg_0.ncpu_cfg.seq == boot_cfg_1.ncpu_cfg.seq))
|
|
{
|
|
// no config data is there, need to create them for partition 0/1
|
|
dfu_init_partition_boot_cfg();
|
|
err_msg("only one partition, cannot switch\n");
|
|
return -1;
|
|
}
|
|
|
|
if (partition == 1) //switch SCPU
|
|
{
|
|
/* determine if any update ever happened, if not, just return */
|
|
if ((boot_cfg_0.scpu_cfg.flag == BOOT_STATE_CONFIRMED) &&
|
|
(boot_cfg_0.scpu_cfg.seq == 1) &&
|
|
(boot_cfg_1.scpu_cfg.flag == BOOT_STATE_NOT_CONFIRMED) &&
|
|
(boot_cfg_1.scpu_cfg.seq == 0))
|
|
{
|
|
err_msg("Never have SCPU firmware updated, cannot switch\n");
|
|
return -1;
|
|
}
|
|
|
|
if (boot_cfg_0.scpu_cfg.flag == BOOT_STATE_CONFIRMED)
|
|
{
|
|
boot_cfg_1.scpu_cfg.flag = BOOT_STATE_CONFIRMED;
|
|
seq = MAX(boot_cfg_0.scpu_cfg.seq, boot_cfg_1.scpu_cfg.seq);
|
|
boot_cfg_1.scpu_cfg.seq = seq + 1;
|
|
boot_cfg_0.scpu_cfg.flag = BOOT_STATE_NOT_CONFIRMED;
|
|
|
|
} else if (boot_cfg_1.scpu_cfg.flag == BOOT_STATE_CONFIRMED)
|
|
{
|
|
boot_cfg_0.scpu_cfg.flag = BOOT_STATE_CONFIRMED;
|
|
seq = MAX(boot_cfg_0.scpu_cfg.seq, boot_cfg_1.scpu_cfg.seq);
|
|
boot_cfg_0.scpu_cfg.seq = seq + 1;
|
|
boot_cfg_1.scpu_cfg.flag = BOOT_STATE_NOT_CONFIRMED;
|
|
}
|
|
}
|
|
|
|
if (partition == 2) //switch NCPU
|
|
{
|
|
|
|
/* determine if any update ever happened, if not, just return */
|
|
if ((boot_cfg_0.ncpu_cfg.flag == BOOT_STATE_CONFIRMED) &&
|
|
(boot_cfg_0.ncpu_cfg.seq == 1) &&
|
|
(boot_cfg_1.ncpu_cfg.flag == BOOT_STATE_NOT_CONFIRMED) &&
|
|
(boot_cfg_1.ncpu_cfg.seq == 0))
|
|
{
|
|
err_msg("Never have NCPU firmware updated, cannot switch\n");
|
|
return -1;
|
|
}
|
|
|
|
if (boot_cfg_0.ncpu_cfg.flag == BOOT_STATE_CONFIRMED)
|
|
{
|
|
boot_cfg_1.ncpu_cfg.flag = BOOT_STATE_CONFIRMED;
|
|
seq = MAX(boot_cfg_0.ncpu_cfg.seq, boot_cfg_1.ncpu_cfg.seq);
|
|
boot_cfg_1.ncpu_cfg.seq = seq + 1;
|
|
boot_cfg_0.ncpu_cfg.flag = BOOT_STATE_NOT_CONFIRMED;
|
|
|
|
} else if (boot_cfg_1.ncpu_cfg.flag == BOOT_STATE_CONFIRMED)
|
|
{
|
|
boot_cfg_0.ncpu_cfg.flag = BOOT_STATE_CONFIRMED;
|
|
seq = MAX(boot_cfg_0.ncpu_cfg.seq, boot_cfg_1.ncpu_cfg.seq);
|
|
boot_cfg_0.ncpu_cfg.seq = seq + 1;
|
|
boot_cfg_1.ncpu_cfg.flag = BOOT_STATE_NOT_CONFIRMED;
|
|
}
|
|
|
|
}
|
|
|
|
ret = dfu_mem_to_flash_small_block((u32)&boot_cfg_0, PARTITION_0_CFG_START_IN_FLASH, sizeof(boot_cfg_0));
|
|
if (ret == -1)
|
|
{
|
|
err_msg("Flash write fail on %x\n", PARTITION_0_CFG_START_IN_FLASH);
|
|
return MSG_FLASH_FAIL;
|
|
}
|
|
|
|
ret = dfu_mem_to_flash_small_block((u32)&boot_cfg_1, PARTITION_1_CFG_START_IN_FLASH, sizeof(boot_cfg_1));
|
|
if (ret == -1)
|
|
{
|
|
err_msg("Flash write fail on %x\n", PARTITION_1_CFG_START_IN_FLASH);
|
|
return MSG_FLASH_FAIL;
|
|
}
|
|
return SUCCESS;
|
|
}
|