KL520_SDK_2.2/mdw/dfu/kmdw_dfu.c
2025-12-17 15:55:25 +08:00

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;
}