473 lines
13 KiB
C
473 lines
13 KiB
C
/****************************************************************************
|
||
|
||
Copyright(c) 2019 by Aerospace C.Power (Chongqing) Microelectronics. ALL RIGHTS RESERVED.
|
||
|
||
This Information is proprietary to Aerospace C.Power (Chongqing) Microelectronics and MAY NOT
|
||
be copied by any method or incorporated into another program without
|
||
the express written consent of Aerospace C.Power. This Information or any portion
|
||
thereof remains the property of Aerospace C.Power. The Information contained herein
|
||
is believed to be accurate and Aerospace C.Power assumes no responsibility or
|
||
liability for its use in any way and conveys no license or title under
|
||
any patent or copyright and makes no representation or warranty that this
|
||
Information is free from patent or copyright infringement.
|
||
|
||
****************************************************************************/
|
||
#include "os_types.h"
|
||
|
||
#include "ahb.h"
|
||
#include "apb.h"
|
||
#include "flash.h"
|
||
#include "common.h"
|
||
#include "decomp.h"
|
||
#include "watchdog.h"
|
||
|
||
#include "iot_mtd.h"
|
||
#include "iot_img_hdr.h"
|
||
#include "iot_system.h"
|
||
#include "iot_flash_layout.h"
|
||
|
||
#include "iot_crc_api.h"
|
||
#include "iot_errno_api.h"
|
||
|
||
#include "sbl_boot.h"
|
||
#include "sbl_boot_hw.h"
|
||
#include "sbl_printf.h"
|
||
|
||
/* Timer reg */
|
||
#define GP_TMR_BASE_ADDR 0x44003000
|
||
#define GTMR0_CTRL_CFG_ADDR (GP_TMR_BASE_ADDR + 0x04)
|
||
#define GTMR0_CFG_ADDR (GP_TMR_BASE_ADDR + 0x08)
|
||
#define GTMR0_INT_STS_ADDR (GP_TMR_BASE_ADDR + 0x0c)
|
||
#define GTMR0_CLR_ADDR (GP_TMR_BASE_ADDR + 0x14)
|
||
#define GTMR0_CNT_DONE (0x2)
|
||
|
||
//FW address mapping
|
||
#define FW_FLASH_ADDR 0x1c020000
|
||
#define FW_RAM_ADDR 0x18000000
|
||
|
||
extern uint32_t g_is_first_run;
|
||
extern char sbl_fw_uncp[PARAM_VAL_LEN_MAX];
|
||
|
||
extern void os_mem_cpy(void *dst, const void *src, uint32_t len);
|
||
extern void os_mem_move(void *dst, const void *src, uint32_t len);
|
||
extern int32_t os_mem_cmp(const void *dst, const void *src, uint32_t len);
|
||
extern void os_mem_set(void *ptr, uint8_t value, uint32_t len);
|
||
|
||
extern str_format_context log_ctxt;
|
||
extern int format_str_v(const str_format_context *ctxt, const char *format,
|
||
va_list ap);
|
||
|
||
/**
|
||
* @brief sbl_boot_hw_init(): hardware init.
|
||
* @return -1: failed; 0: succeed.
|
||
*/
|
||
uint32_t sbl_boot_hw_init(void)
|
||
{
|
||
flash_init(0);
|
||
|
||
sbl_printf_init(format_str_v, &log_ctxt);
|
||
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* @brief sbl_wdg_ena(): enable watchdog.
|
||
* @return none.
|
||
*/
|
||
void sbl_wdg_ena(void)
|
||
{
|
||
uint32_t cpu = 0;
|
||
|
||
apb_enable(APB_WDG0);
|
||
wdg_set_cmp(cpu, SET_WDG_INTC_CMP);
|
||
wdg_set_timeout_cmp(cpu, SET_WDG_TIMEOUT_CMP);
|
||
wdg_set_cpurst_cmp(cpu, SET_WDG_CPURST_CMP);
|
||
wdg_set_fullrst_cmp(cpu, SET_WDG_FULLRST_CMP);
|
||
wdg_cnt_enable(cpu);
|
||
wdg_enable(cpu);
|
||
}
|
||
|
||
/**
|
||
* @brief sbl_wdg_disable(): disable watchdog.
|
||
* @return none.
|
||
*/
|
||
void sbl_wdg_disable(void)
|
||
{
|
||
uint32_t cpu = 0;
|
||
|
||
wdg_cnt_disable(cpu);
|
||
wdg_disable(cpu);
|
||
}
|
||
|
||
/**
|
||
* @brief sbl_scratch_reg_set(): set scratch regsiter with watchdog reset flag.
|
||
* @return none.
|
||
*/
|
||
void sbl_scratch_reg_set(void)
|
||
{
|
||
ahb_scratch_r0_set(WDT_RESET_FLAG);
|
||
}
|
||
|
||
/**
|
||
* @brief sbl_check_reset_by_wdg(): judge reset cause is watchdog or not.
|
||
* @return 1 -> is watchdog reset, 0 -> not 1.
|
||
*/
|
||
uint32_t sbl_check_reset_by_wdg(void)
|
||
{
|
||
if (ahb_scratch_r0_get() == WDT_RESET_FLAG) {
|
||
return 1;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* @brief sbl_timer_run: start gp-timer.
|
||
* @param ms: timeout counter, unit is ms.
|
||
* @return none.
|
||
*/
|
||
void sbl_timer_run(int ms)
|
||
{
|
||
REG32(GTMR0_CFG_ADDR) = ms;
|
||
REG32(GTMR0_CTRL_CFG_ADDR) = (1<<4) | (1<<1); /*(1MHz enable)*/
|
||
}
|
||
|
||
/**
|
||
* @brief sbl_timer_clr: clear gp-timer interrupt flag.
|
||
* @return none.
|
||
*/
|
||
void sbl_timer_clr(void)
|
||
{
|
||
REG32(GTMR0_CLR_ADDR) = (1<<0) | (1<<1); /* intc and cnt clr */
|
||
}
|
||
|
||
/**
|
||
* @brief sbl_timer_cnt_done: get gp-timer cnt_done interrupt state.
|
||
* @return none.
|
||
*/
|
||
int sbl_timer_cnt_done(void)
|
||
{
|
||
return (REG32(GTMR0_INT_STS_ADDR) & GTMR0_CNT_DONE) ? 1 : 0;
|
||
}
|
||
|
||
/**
|
||
* @brief sbl_fastboot_flag_set: set(save) fastboot flag.
|
||
* @param fboot: fastboot flag.
|
||
* @return none.
|
||
*/
|
||
void sbl_fastboot_flag_set(uint32_t fboot)
|
||
{
|
||
/* kl2 not support rom passing fastboot flag */
|
||
(void)fboot;
|
||
}
|
||
|
||
/**
|
||
* @brief sbl_fastboot_flag_get: get fastboot flag.
|
||
* @return 1 -> is fast boot mode, 0 -> not 1.
|
||
*/
|
||
uint32_t sbl_fastboot_flag_get(void)
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* @brief image_check() Check for valid fw at the specified address.
|
||
* @param addr: addr to check.
|
||
* @param hdr: pointer to store header information.
|
||
* @param crc_flag: CRC check mark or not.
|
||
* @return -1: no valid header; 0: valid header.
|
||
*/
|
||
static int image_check(uint32_t addr, imgHdr *hdr, uint8_t crc_flag)
|
||
{
|
||
char block[HEADER_TOLTAL_SIZE];
|
||
uint8_t *src = (uint8_t *)addr;
|
||
uint32_t len_total = 0;
|
||
uint8_t reason = 0;
|
||
|
||
/* clear i/dcache */
|
||
ahb_cache_clear();
|
||
os_mem_cpy(block, src, sizeof(imgHdr));
|
||
img_header_construct(hdr, block);
|
||
|
||
if (iot_imghdr_get_guard(hdr) != IMAGE_GUARD) {
|
||
reason = 1;
|
||
goto err;
|
||
}
|
||
|
||
if (crc_flag) {
|
||
uint32_t img_crc = iot_imghdr_get_imgCRC(hdr);
|
||
len_total = iot_imghdr_get_imgSize(hdr);
|
||
len_total = IMAGE_LEN_FOR_CRC(len_total);
|
||
uint32_t crc = iot_getcrc32((uint8_t *)addr + HEADER_TOLTAL_SIZE, len_total);
|
||
if (crc != img_crc) {
|
||
reason = 2;
|
||
goto err;
|
||
}
|
||
}
|
||
return 0;
|
||
|
||
err:
|
||
sbl_printf("image_check error, addr:0x%x, reason:%d\r\n", addr, reason);
|
||
return -1;
|
||
}
|
||
|
||
/**
|
||
* @brief image_copy(): copy firmware to specified address.
|
||
* @param src & dst: source and destination addresses(partition start location).
|
||
* @param hdr: pointer to store header information.
|
||
* @param header_move: if you copy the header,
|
||
you need to erase the header information of the source address.
|
||
* @return -1: no valid header; 0: valid header.
|
||
*/
|
||
static int image_copy(uint8_t *src, uint8_t *dst, imgHdr *hdr, uint8_t header_move)
|
||
{
|
||
int rc = 0;
|
||
flash_write_param_t param = {0};
|
||
uint32_t len_image = 0;
|
||
uint32_t len_copy = 0;
|
||
uint8_t *addr_crc = NULL;
|
||
uint8_t *src_copy = src;
|
||
uint8_t *dst_copy = dst;
|
||
uint8_t reason = 0;
|
||
|
||
len_image = iot_imghdr_get_imgSize(hdr);
|
||
len_image = IMAGE_LEN_FOR_CRC(len_image);
|
||
if (header_move) {
|
||
len_copy = len_image + HEADER_TOLTAL_SIZE;
|
||
addr_crc = dst_copy + HEADER_TOLTAL_SIZE;
|
||
} else {
|
||
src_copy += HEADER_TOLTAL_SIZE;
|
||
dst_copy += HEADER_TOLTAL_SIZE;
|
||
len_copy = len_image;
|
||
addr_crc = dst_copy;
|
||
}
|
||
/*write to the FW addr in flash*/
|
||
param.read_mode = MOD_SFC_READ_QUAD_IO_FAST;
|
||
param.write_mode = MOD_SFC_PROG_QUAD;
|
||
param.is_erase = 1;
|
||
param.sw_mode = MOD_SW_MODE_DIS;
|
||
param.erase_mode = MODE_ERASE_SECTOR;
|
||
rc = flash_write(src_copy, (uint32_t)dst_copy, len_copy, ¶m);
|
||
if(rc != 0 ) {
|
||
reason = 1;
|
||
goto err;
|
||
} else {
|
||
sbl_printf("fw image copied into flash \r\n");
|
||
if (iot_imghdr_get_imgCRC(hdr) != 0 ) {
|
||
uint32_t img_crc = iot_imghdr_get_imgCRC(hdr);
|
||
uint32_t crc = iot_getcrc32(addr_crc, len_image);
|
||
if ( crc != img_crc) {
|
||
reason = 2;
|
||
goto err;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (header_move) {
|
||
if (flash_erase((uint32_t)src, ¶m) != ERR_OK) {
|
||
reason = 3;
|
||
goto err;
|
||
}
|
||
}
|
||
return 0;
|
||
|
||
err:
|
||
sbl_printf("image_copy error, reason:%d\r\n", reason);
|
||
return -1;
|
||
}
|
||
|
||
/**
|
||
* @brief get_fw_addr_info(): get firmware storage and running address.
|
||
* @param fw_addr: pointer to save storage address.
|
||
* @param run_addr: pointer to save run address.
|
||
* @param flash_size: flash size, see flash_size_t.
|
||
* @param start_part: pointer of sbl_start_part.
|
||
* @return -1: no valid header; 0: valid header.
|
||
*/
|
||
static int get_fw_addr_info(uint32_t *fw_addr, uint32_t *run_addr,
|
||
uint8_t flash_size, uint32_t start_part)
|
||
{
|
||
int ret = 0;
|
||
imgHdr hdr = {0};
|
||
|
||
#if RUN_IN_PSRAM
|
||
*run_addr = FW_RAM_ADDR;
|
||
#else
|
||
*run_addr = FW_FLASH_ADDR + HEADER_TOLTAL_SIZE;
|
||
#endif
|
||
|
||
/* get firmware address */
|
||
if (start_part == 0) { //fw1
|
||
iot_layout_get_part_offset(PART_NUM_FW1, fw_addr);
|
||
} else { //fw2
|
||
iot_layout_get_part_offset(PART_NUM_FW2, fw_addr);
|
||
}
|
||
*fw_addr += FLASH_BASE_ADDRESS;
|
||
|
||
/* check image integrity */
|
||
if (g_is_first_run) {
|
||
if (image_check(*fw_addr, &hdr, 1) < 0) {
|
||
ret = -1;
|
||
goto out;
|
||
}
|
||
}
|
||
|
||
out:
|
||
sbl_printf("get fw addr:0x%x, run addr:0x%x\r\n", *fw_addr, *run_addr);
|
||
return ret;
|
||
}
|
||
|
||
/**
|
||
* @brief fw_image_decompress_to_psram(): decompress image to psram.
|
||
* @param fw_addr: firmware address.
|
||
* @param run_addr: run address.
|
||
* @return -1: failed; 0: succeed.
|
||
*/
|
||
int fw_image_decompress_to_psram(uint32_t fw_addr, uint32_t run_addr)
|
||
{
|
||
uint8_t *src = NULL;
|
||
uint8_t *dst = NULL;
|
||
int rc = 0;
|
||
imgHdr hdr = {0};
|
||
|
||
/* the compressed or valid data does not contain a header */
|
||
src = (uint8_t *)fw_addr + HEADER_TOLTAL_SIZE;
|
||
dst = (uint8_t *)run_addr;
|
||
|
||
if (image_check(fw_addr, &hdr, 0) < 0) {
|
||
return -1;
|
||
}
|
||
|
||
rc = fw_image_decompress(src, dst, iot_imghdr_get_imgSize(&hdr));
|
||
|
||
if(rc != 0 ){
|
||
os_mem_cpy(dst, src, iot_imghdr_get_imgSize(&hdr));
|
||
//ahb_dmc_cache_flush((uint32_t)dst, hdr._imgSize);
|
||
}
|
||
sbl_printf("decompressed fw image into RAM \r\n");
|
||
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* @brief fw_image_decompress_to_flash(): decompress image to flash.
|
||
* @param fw_addr: firmware address.
|
||
* @param run_addr: run address.
|
||
* @return -1: failed; 0: succeed.
|
||
*/
|
||
int fw_image_decompress_to_flash(uint32_t fw_addr, uint32_t run_addr)
|
||
{
|
||
uint8_t *src = NULL;
|
||
uint8_t *dst = NULL;
|
||
int rc = 0;
|
||
imgHdr hdr = {0};
|
||
|
||
src = (uint8_t *)fw_addr;
|
||
dst = (uint8_t *)run_addr;
|
||
|
||
if (image_check(fw_addr, &hdr, 0) < 0) {
|
||
return -1;
|
||
}
|
||
|
||
/*compatable with 1M image upgrade*/
|
||
if (iot_imghdr_get_imgType(&hdr) == imgFRW) {
|
||
if (image_copy(src, dst - HEADER_TOLTAL_SIZE, &hdr, 0) < 0) {
|
||
return -1;
|
||
}
|
||
} else {
|
||
rc = fw_image_decompress(src+sizeof(imgHdr), dst, iot_imghdr_get_imgSize(&hdr));
|
||
if(rc != 0 ) {
|
||
sbl_printf("fw image decompressed ERROR! \r\n");
|
||
return -1;
|
||
} else {
|
||
uint32_t fw_crc = 0, crc = 0;
|
||
sbl_printf("fw image decompressed into flash \r\n");
|
||
fw_crc = iot_imghdr_get_fwCRC(&hdr);
|
||
crc = iot_getcrc32(dst, iot_imghdr_get_fwSize(&hdr));
|
||
if (crc != fw_crc) {
|
||
sbl_printf("decompress fw crc error\r\n");
|
||
return -1;
|
||
}
|
||
}
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* @brief sbl_load_next_firmware(): load custom app or plc app firmware.
|
||
* @param run_addr: pointer of run address.
|
||
* @param flash_size: flash size
|
||
* @param start_part: start part.
|
||
* @psram psram_eb: next firmware run in psram or not.
|
||
* @return 0: load firmware succeed, 1: load firmware failed.
|
||
*/
|
||
uint32_t sbl_load_next_firmware(uint32_t *run_addr,
|
||
uint32_t flash_size, uint32_t start_part, uint32_t psram_eb)
|
||
{
|
||
uint32_t fw_addr = 0;
|
||
(void)psram_eb;
|
||
|
||
if (get_fw_addr_info(&fw_addr, run_addr, (uint8_t)flash_size, start_part) < 0) {
|
||
sbl_printf("No valid firmware found......\r\n");
|
||
while(1);
|
||
}
|
||
|
||
#if RUN_IN_PSRAM
|
||
if(fw_image_decompress_to_psram(fw_addr, *run_addr) < 0) {
|
||
/* copy image failed */
|
||
sbl_printf("......\r\n");
|
||
while(1);
|
||
}
|
||
#else
|
||
if (flash_size == FLASH_1M) {
|
||
/* 1m flash firmware is uncompressed and there is no run partition */
|
||
if (start_part) {
|
||
uint32_t offset1, offset2, size;
|
||
sbl_printf("re-mapping flash space\r\n");
|
||
iot_layout_get_part_offset(PART_NUM_FW1, &offset1);
|
||
iot_layout_get_part_offset(PART_NUM_FW2, &offset2);
|
||
iot_layout_get_part_size(PART_NUM_FW1, &size);
|
||
if (flash_addr_mapping(offset1, offset2, size) != 0) {
|
||
sbl_printf("re-mapping error\r\n");
|
||
while(1);
|
||
}
|
||
}
|
||
} else if ((os_mem_cmp(sbl_fw_uncp, "0", 1) == 0)) {
|
||
/* 2m and 4m flash firmware needs to be decompressed */
|
||
if(fw_image_decompress_to_flash(fw_addr, *run_addr) < 0) {
|
||
/* decompress image failed */
|
||
sbl_printf("......\r\n");
|
||
while(1);
|
||
} else{
|
||
/*decompress success*/
|
||
sbl_fw_uncp_success();
|
||
}
|
||
}
|
||
#endif
|
||
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* @brief sbl_jump_next_firmware(): jump to custom app or plc app firmware.
|
||
* @param run_addr: next firmware run address.
|
||
* @param mode: firmware run mode.
|
||
* @param print_eb: printf function enable or not.
|
||
* @param flash_size: flash size.
|
||
* @param psram_eb: next firmware run in psram or not.
|
||
* @return 0: jump to firmware succeed, 1: jump to firmware failed.
|
||
*/
|
||
uint32_t sbl_jump_next_firmware(uint32_t run_addr,
|
||
int mode, int print_eb, int flash_size, int psram_eb)
|
||
{
|
||
typedef void(*pgm_start_t)(int, int, int, int);
|
||
|
||
pgm_start_t pgm_start = (pgm_start_t)run_addr;
|
||
sbl_printf("\r\njump@0x%x\r\n", (int)pgm_start);
|
||
pgm_start(mode, print_eb, flash_size, psram_eb);
|
||
return 0;
|
||
}
|
||
|
||
// kl1会操作一下tms引脚,这个操作对kl2和kl3应该是无效的
|
||
void sbl_tms_interrupt_disable()
|
||
{
|
||
} |