/**************************************************************************** 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() { }