699 lines
21 KiB
C
699 lines
21 KiB
C
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <inttypes.h>
|
|
#include <byteorder.h>
|
|
#include "flasher_guard.h"
|
|
#include "syscall-arom.h"
|
|
#include "reg.h"
|
|
#include "secureboot.h"
|
|
#include "pmic.h"
|
|
#include "sys-boot-mode.h"
|
|
#include "sys_close_all.h"
|
|
#include "smux.h"
|
|
#include "etimer.h"
|
|
#include "clock.h"
|
|
#include "arom-crane.h"
|
|
#include "pmu.h"
|
|
#include "property.h"
|
|
#include "transfer-control.h"
|
|
#include "loader.h"
|
|
#include "ptable.h"
|
|
#include "cpu.h"
|
|
#include "flash.h"
|
|
#include "boot_img.h"
|
|
#include "heapmem.h"
|
|
#include "fastboot.h"
|
|
#include "tbbr_img_def.h"
|
|
#include "fip.h"
|
|
#include "nvctr_flash.h"
|
|
#include "usb_serial.h"
|
|
|
|
/* Log configuration */
|
|
#include "log.h"
|
|
#define LOG_MODULE "Boot2"
|
|
#define LOG_LEVEL LOG_LEVEL_MAIN
|
|
/*---------------------------------------------------------------------------*/
|
|
#define QUEC_CUST_FEATURE 1
|
|
#if (defined(QUEC_CUST_FEATURE)&& (AROM_VERSION == AROM_VER_2022_11_06_CRANEL_CR5))
|
|
#define DOWNLOAD_CMD_DETECT_WAIT_MSECONDS 1200 /* ms */
|
|
#else
|
|
#define DOWNLOAD_CMD_DETECT_WAIT_MSECONDS 1000 /* ms */
|
|
#endif
|
|
#define AROM_VERSION_CRANEW_SERIES (AROM_VERSION == AROM_VER_2022_07_28_CRANEW_Z2)
|
|
#define AROM_VERSION_CRANE_SERIES (AROM_VERSION == AROM_VER_2020_07_30_CRANEGM_A0 || \
|
|
AROM_VERSION == AROM_VER_2021_10_16_CRANEL_A0 || \
|
|
AROM_VERSION == AROM_VER_2022_11_06_CRANEL_CR5 || \
|
|
AROM_VERSION == AROM_VER_2024_04_30_LAPWING_CR5 || \
|
|
AROM_VERSION == AROM_VER_2022_11_11_CRANEG_CR5)
|
|
/*---------------------------------------------------------------------------*/
|
|
/**
|
|
* Preamble message type
|
|
*/
|
|
enum {
|
|
PREAMBLE_DOWNLOAD,
|
|
PREAMBLE_PRODUCTION
|
|
};
|
|
/*---------------------------------------------------------------------------*/
|
|
#if AROM_VERSION != AROM_VER_2022_08_08_CRANEW_CR5
|
|
static void crane_boot2_init(void);
|
|
static void boot2_preamble_callback(const char *preamble, smux_dev_t dev);
|
|
static void transfer_arom_do_download(void);
|
|
static int do_boot_pz1(void);
|
|
#if (defined(BOARD_CRANE) || defined(BOARD_CRANEW_MCU))
|
|
static char *boardid_string;
|
|
#endif
|
|
#endif
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
extern unsigned char __lzma_decode_start, __lzma_decode_size;
|
|
/*---------------------------------------------------------------------------*/
|
|
#if (defined(BOARD_CRANE) || defined(BOARD_CRANEW_MCU))
|
|
#define PROP_NAME_BOARDID "bl2.boardid"
|
|
#endif
|
|
/*---------------------------------------------------------------------------*/
|
|
__attribute__((constructor)) static void
|
|
platform_init(void)
|
|
{
|
|
#if defined(CPU_MODEL_CRANE) || defined(CPU_MODEL_CRANEW_MCU)
|
|
#if AROM_VERSION == AROM_VER_2022_08_08_CRANEW_CR5
|
|
sys_boot_mode_set(SYS_BOOT_MODE_NORMAL);
|
|
#else
|
|
char r_cmd;
|
|
|
|
pmic_init();
|
|
|
|
pmic_get_restart_cmd(&r_cmd);
|
|
if(r_cmd == RESTART_CMD_USB_DOWNLOAD) {
|
|
sys_boot_mode_set(SYS_BOOT_MODE_FORCE_DOWNLOAD);
|
|
pmic_set_restart_cmd(RESTART_CMD_NORMAL_POWERON);
|
|
} else if(r_cmd == RESTART_CMD_FORCE_NORMAL_POWERON) {
|
|
sys_boot_mode_set(SYS_BOOT_MODE_NORMAL);
|
|
pmic_set_restart_status(RESTART_STATUS_NORMAL_POWERON);
|
|
} else if(r_cmd == RESTART_CMD_PRODUCTION) {
|
|
/* The production mode is detected from the pmic restart cmd register */
|
|
sys_boot_mode_set(SYS_BOOT_MODE_PRODUCTION);
|
|
#if defined(BOARD_CRANE)
|
|
/*
|
|
* For Crane chips, Watch1 CR5 never reach here.
|
|
*
|
|
* Keep the pmic restart cmd to "production mode" to ensure compatiblity
|
|
* with already mass-producrd products. On those chips, CP(CR5), acting as
|
|
* host, checks pmic restart cmd register to process different bootmode and
|
|
* then set it to the right value.
|
|
*/
|
|
#else
|
|
/*
|
|
* For Watch1 MCU.
|
|
*
|
|
* Set the pmic restart cmd register to "normal poweron" for the next
|
|
* restart. The production mode flag will be passed to the Boot33 by the
|
|
* property of bl2.bootmode, and the subsequent software will never use
|
|
* the pmic register to determine the boot mode.
|
|
*/
|
|
pmic_set_restart_cmd(RESTART_CMD_NORMAL_POWERON);
|
|
#endif /* BOARD_CRANE */
|
|
} else {
|
|
/* RESTART_CMD_NORMAL_POWERON and unknown cmd */
|
|
sys_boot_mode_set(SYS_BOOT_MODE_TRY_DOWNLOAD);
|
|
/* set_restart_status or set_restart_cmd will after cmd detect finished. */
|
|
}
|
|
#endif
|
|
#endif
|
|
}
|
|
/*---------------------------------------------------------------------------*/
|
|
#if 0
|
|
static void
|
|
display_binary(void *data, size_t len)
|
|
{
|
|
#define BYTE_COUNT_EACH_LINE 8
|
|
|
|
static const char hex[] = "0123456789ABCDEF";
|
|
static const char seperator = ',';
|
|
unsigned char *p = (unsigned char *)data;
|
|
char stash[BYTE_COUNT_EACH_LINE * (2 + 2 + 1) + 1];
|
|
size_t j = 0;
|
|
for(size_t i = 0; i < len; i++) {
|
|
stash[j++] = '0';
|
|
stash[j++] = 'x';
|
|
stash[j++] = hex[(p[i] >> 4) & 0xF];
|
|
stash[j++] = hex[p[i] & 0xF];
|
|
stash[j++] = seperator;
|
|
if(j == sizeof(stash) - 1) {
|
|
stash[j] = '\0';
|
|
LOG_INFO("%s\n", stash);
|
|
j = 0;
|
|
}
|
|
}
|
|
if(j) {
|
|
stash[j] = '\0';
|
|
LOG_INFO("%s\n", stash);
|
|
}
|
|
}
|
|
#endif
|
|
/*---------------------------------------------------------------------------*/
|
|
#define USB2_REG0B_DEFAULT_VAL 0x3000
|
|
/*---------------------------------------------------------------------------*/
|
|
static void
|
|
usb_check_reg_before_init(void)
|
|
{
|
|
uint32_t reg_usb2_0A, reg_usb2_0B;
|
|
uint32_t reg_usb2_0A_val, reg_usb2_0B_val;
|
|
|
|
reg_usb2_0A = UTMI_BASE + UTMI_USB2_REG0A;
|
|
reg_usb2_0B = UTMI_BASE + UTMI_USB2_REG0B;
|
|
|
|
reg_usb2_0A_val = readl(reg_usb2_0A);
|
|
reg_usb2_0B_val = readl(reg_usb2_0B);
|
|
|
|
if(reg_usb2_0A_val != 0 || reg_usb2_0B_val != 0x3000) {
|
|
writel(0, reg_usb2_0A);
|
|
writel(USB2_REG0B_DEFAULT_VAL, reg_usb2_0B);
|
|
}
|
|
}
|
|
/*---------------------------------------------------------------------------*/
|
|
static void
|
|
set_preamble_mode(void)
|
|
{
|
|
usb_check_reg_before_init();
|
|
smux_running_mode_set(SMUX_MODE_PREAMBLE);
|
|
}
|
|
/*---------------------------------------------------------------------------*/
|
|
#if AROM_VERSION_CRANE_SERIES
|
|
static bool
|
|
flash_check_qspi2_nor_device(const void *data, size_t size)
|
|
{
|
|
size_t flash_info_size = 0;
|
|
struct flash_info *info;
|
|
|
|
do {
|
|
info = (struct flash_info *)data;
|
|
if(info->magic != FLASH_INFO_MAGIC) {
|
|
return false;
|
|
}
|
|
size_t len = sizeof(struct flash_info);
|
|
len += (info->compatible_device_num - 1) * sizeof(struct compatible_device);
|
|
flash_info_size += len;
|
|
data = (char *)data + len;
|
|
if(flash_info_size > size) {
|
|
return false;
|
|
}
|
|
if(!strcmp(info->device_type, FLASH_TYPE_QSPI2_NOR)) {
|
|
return true;
|
|
}
|
|
} while(info->chained);
|
|
|
|
return false;
|
|
}
|
|
#endif
|
|
/*---------------------------------------------------------------------------*/
|
|
static int
|
|
do_boot(void)
|
|
{
|
|
smux_running_mode_set(SMUX_MODE_BYPASS);
|
|
|
|
#if AROM_VERSION_CRANE_SERIES
|
|
/* asic-sv evb case */
|
|
if(do_boot_pz1()) {
|
|
LOG_ERR("can not boot pz1!\n");
|
|
return SYS_BOOT_MODE_FORCE_DOWNLOAD;
|
|
}
|
|
|
|
extern char __lzma_alloc_base, __lzma_alloc_size;
|
|
uint8_t *stash = (uint8_t *)((uintptr_t)&__lzma_alloc_base + SZALLOC_OFFSET);
|
|
ssize_t stash_size = (uintptr_t)&__lzma_alloc_size - SZALLOC_OFFSET;
|
|
stash_size = sb_volume_read("flashinfo", stash, stash_size);
|
|
if(stash_size < 0) {
|
|
LOG_ERR("can not read volume 'flashinfo'\n");
|
|
set_preamble_mode();
|
|
return SYS_BOOT_MODE_FORCE_DOWNLOAD;
|
|
}
|
|
|
|
#ifdef USE_ARB
|
|
if(is_valid_fip(stash)) {
|
|
int ret = fip_get_image(stash, BL2_IMAGE_ID, (uint64_t *)&stash, NULL);
|
|
if(ret < 0) {
|
|
LOG_ERR("Get 'flashinfo' failed!\n");
|
|
return SYS_BOOT_MODE_FORCE_DOWNLOAD;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if(flash_check_qspi2_nor_device(stash, stash_size)) {
|
|
slt_do_boot_prepare();
|
|
LOG_INFO("Refresh volume for booting from qspi2.\n");
|
|
sb_volume_exit();
|
|
if(sb_volume_init() < 0) {
|
|
LOG_ERR("Initialize volume partition failed!\n");
|
|
set_preamble_mode();
|
|
return SYS_BOOT_MODE_FORCE_DOWNLOAD;
|
|
}
|
|
|
|
/* Reload new ptable */
|
|
if(ptable_loader()) {
|
|
LOG_ERR("Load ptable failed!\n");
|
|
set_preamble_mode();
|
|
return SYS_BOOT_MODE_FORCE_DOWNLOAD;
|
|
}
|
|
}
|
|
#elif AROM_VERSION_CRANEW_SERIES
|
|
/* asic-sv evb case */
|
|
if(do_boot_pz1()) {
|
|
LOG_ERR("can not boot pz1!\n");
|
|
return SYS_BOOT_MODE_FORCE_DOWNLOAD;
|
|
}
|
|
#endif
|
|
|
|
if(!do_boot_cb()) {
|
|
set_preamble_mode();
|
|
return SYS_BOOT_MODE_FORCE_DOWNLOAD;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#if AROM_VERSION != AROM_VER_2022_08_08_CRANEW_CR5
|
|
/*
|
|
* Normally it should not exceed 500ms, but it depends on Windows, which is not
|
|
* a real time OS, and it has been observed that the enumeration exceeds 3
|
|
* second.
|
|
*
|
|
* Note: If USB is connected but driver is not installed, it will wait for
|
|
* tiemout before continuing to execute.
|
|
*/
|
|
#define USB_ENUMERATION_TIMEOUT_MS 5000
|
|
/*---------------------------------------------------------------------------*/
|
|
PROCESS(boot2_process, "Crane boot2 process");
|
|
/*---------------------------------------------------------------------------*/
|
|
PROCESS_THREAD(boot2_process, ev, data)
|
|
{
|
|
(void)data;
|
|
static struct etimer timer;
|
|
static bool timer_started;
|
|
static clock_time_t t, timeout;
|
|
static bool usb_enumeration_stage;
|
|
|
|
PROCESS_BEGIN();
|
|
|
|
/* setup a periodic timer that expires after 1 seconds. */
|
|
LOG_PRINT("Waiting for %d ms to detect download command.\n", DOWNLOAD_CMD_DETECT_WAIT_MSECONDS);
|
|
smux_register_preamble_callback(boot2_preamble_callback);
|
|
|
|
#ifdef BOARD_CRANE
|
|
uart_rx_fixup();
|
|
#endif
|
|
|
|
smux_running_mode_set(SMUX_MODE_PREAMBLE);
|
|
/*
|
|
* Set smux mode to PREAMBLE will flush logs, taking up approximately 200ms.
|
|
* This time should be excluded from the wait download cmd period. So start
|
|
* timer after set smux mode.
|
|
*/
|
|
t = clock_time();
|
|
timeout = t + USB_ENUMERATION_TIMEOUT_MS;
|
|
usb_enumeration_stage = true;
|
|
|
|
while(1) {
|
|
/* Wait for USB enumeration to complete before waiting for download cmd */
|
|
while(usb_enumeration_stage) {
|
|
t = clock_time();
|
|
if((t > timeout) || usb_enumeration_is_complete()) {
|
|
if(t > timeout) {
|
|
/* USB enumeration failed, try to continue */
|
|
LOG_WARN("Usb enumeration timeout.\n");
|
|
}
|
|
|
|
/*
|
|
* USB enumeration complete or timeout, start timer to wait download
|
|
* cmd.
|
|
*/
|
|
usb_enumeration_stage = false;
|
|
etimer_set(&timer, CLOCK_SECOND * DOWNLOAD_CMD_DETECT_WAIT_MSECONDS / 1000);
|
|
timer_started = true;
|
|
|
|
break;
|
|
} else {
|
|
PROCESS_PAUSE();
|
|
}
|
|
}
|
|
|
|
PROCESS_YIELD();
|
|
|
|
switch(ev) {
|
|
case PROCESS_EVENT_TIMER:
|
|
if(smux_running_mode_get() == SMUX_MODE_PREAMBLE) {
|
|
smux_running_mode_set(SMUX_MODE_BYPASS);
|
|
char r_cmd;
|
|
pmic_get_restart_cmd(&r_cmd);
|
|
pmic_set_restart_status(r_cmd);
|
|
LOG_INFO("No download command detected, continue booting.\n");
|
|
if(timer_started) {
|
|
etimer_stop(&timer);
|
|
}
|
|
if(!do_boot()) {
|
|
timer_started = false;
|
|
} else {
|
|
set_preamble_mode();
|
|
}
|
|
}
|
|
break;
|
|
|
|
case PREAMBLE_DOWNLOAD:
|
|
/* stop timer */
|
|
if(timer_started) {
|
|
etimer_stop(&timer);
|
|
timer_started = false;
|
|
}
|
|
break;
|
|
|
|
case PREAMBLE_PRODUCTION:
|
|
LOG_INFO("PROD CMD ACCEPTED!\n");
|
|
smux_running_mode_set(SMUX_MODE_BYPASS);
|
|
smux_use_device(SMUX_DEV_UART);
|
|
#if defined(BOARD_CRANE)
|
|
/*
|
|
* For Crane chips.
|
|
*
|
|
* Watch1 CR5 should never reach here becasue the production mode flag is
|
|
* set by the host through sw_scratch register and detected in Bootrom,
|
|
* not by preamble.
|
|
*
|
|
* For other Crane chips, set the pmic restart cmd to "production mode" to
|
|
* ensure compatiblity with already mass-producrd products. On those chips,
|
|
* CP(CR5), acting as host, checks the pmic restart cmd register to process
|
|
* different bootmode and then set it to the right value.
|
|
*
|
|
* Since the pmic cmd and status are mapped to the same pmic register, cmd
|
|
* is used instead of status.
|
|
*/
|
|
pmic_set_restart_cmd(RESTART_STATUS_PRODUCTION);
|
|
#else
|
|
/*
|
|
* For Watch1 MCU.
|
|
*
|
|
* The production mode flag will be passed to the Boot33 by the property of
|
|
* bl2.bootmode, and the subsequent software will never use pmic register
|
|
* to determine the boot mode.
|
|
*/
|
|
#endif /* BOARD_CRANE */
|
|
sys_boot_mode_set(SYS_BOOT_MODE_PRODUCTION);
|
|
if(timer_started) {
|
|
etimer_stop(&timer);
|
|
}
|
|
if(!do_boot()) {
|
|
timer_started = false;
|
|
} else {
|
|
set_preamble_mode();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
PROCESS_END();
|
|
}
|
|
/*---------------------------------------------------------------------------*/
|
|
static void
|
|
crane_boot2_init(void)
|
|
{
|
|
process_start(&boot2_process, NULL);
|
|
}
|
|
/*---------------------------------------------------------------------------*/
|
|
static void
|
|
transfer_arom_do_download(void)
|
|
{
|
|
/* unregister preamble callback first */
|
|
smux_register_preamble_callback(NULL);
|
|
process_post_synch(arom_main_process(), PREAMBLE_DOWNLOAD, NULL);
|
|
process_exit(&boot2_process);
|
|
#if (defined(BOARD_CRANE))
|
|
#if AROM_VERSION <= AROM_VER_2021_10_16_CRANEL_A0
|
|
size_t len = strlen(boardid_string);
|
|
char *p = arom_heapmem_alloc(len + 1); /* must use arom heap */
|
|
strcpy(p, boardid_string);
|
|
fastboot_publish("boardid", p);
|
|
#endif
|
|
#endif
|
|
}
|
|
/*---------------------------------------------------------------------------*/
|
|
static void
|
|
boot2_preamble_callback(const char *preamble, smux_dev_t dev)
|
|
{
|
|
static enum { PREAMBLE_TYPE_UNKNOWN,
|
|
PREAMBLE_TYPE_UUUU,
|
|
PREAMBLE_TYPE_UABT,
|
|
PREAMBLE_TYPE_PROD } preamble_type;
|
|
|
|
if(!strncmp(preamble, SMUX_PREAMBLE_UUUU, SMUX_PREAMBLE_SIZE)) {
|
|
if(preamble_type != PREAMBLE_TYPE_UUUU) {
|
|
preamble_type = PREAMBLE_TYPE_UUUU;
|
|
}
|
|
} else if(!strncmp(preamble, SMUX_PREAMBLE_UABT, SMUX_PREAMBLE_SIZE)) {
|
|
if(preamble_type != PREAMBLE_TYPE_UABT) {
|
|
preamble_type = PREAMBLE_TYPE_UABT;
|
|
}
|
|
} else if(!strncmp(preamble, SMUX_PREAMBLE_PROD, SMUX_PREAMBLE_SIZE)) {
|
|
if(preamble_type != PREAMBLE_TYPE_PROD) {
|
|
preamble_type = PREAMBLE_TYPE_PROD;
|
|
}
|
|
} else {
|
|
preamble_type = PREAMBLE_TYPE_UNKNOWN;
|
|
return;
|
|
}
|
|
|
|
switch(preamble_type) {
|
|
case PREAMBLE_TYPE_UUUU:
|
|
smux_use_device(dev);
|
|
smux_write_stdout((uint8_t *)SMUX_PREAMBLE_UABT, SMUX_PREAMBLE_SIZE);
|
|
process_post(&boot2_process, PREAMBLE_DOWNLOAD, NULL);
|
|
break;
|
|
case PREAMBLE_TYPE_UABT:
|
|
smux_use_device(dev);
|
|
/* handle download by bootrom */
|
|
transfer_arom_do_download();
|
|
smux_write_stdout((uint8_t *)SMUX_PREAMBLE_UABT, SMUX_PREAMBLE_SIZE);
|
|
break;
|
|
case PREAMBLE_TYPE_PROD:
|
|
smux_use_device(dev);
|
|
process_post(&boot2_process, PREAMBLE_PRODUCTION, NULL);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
/*---------------------------------------------------------------------------*/
|
|
/* if ptable has pz1 img, boot pz1 */
|
|
static int
|
|
do_boot_pz1(void)
|
|
{
|
|
struct ptentry *entry = ptable_find_entry("pz1");
|
|
|
|
/* if found 'pz1' partition boot to 'pz1' partition's xip address */
|
|
if(entry) {
|
|
LOG_INFO("Found pz1 partition, just load and boot to %p\n",
|
|
(void *)(uintptr_t)entry->vstart);
|
|
if(entry->vstart == (uintptr_t)&__lzma_decode_start) {
|
|
if(sb_flash_read(entry->start, &__lzma_decode_start, entry->size) != (int)entry->size) {
|
|
return -1;
|
|
}
|
|
}
|
|
boot_xip_address(entry->vstart);
|
|
/* never return */
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
/*---------------------------------------------------------------------------*/
|
|
#if QSPI_PROBE_IN_BOOT2_ENABLE
|
|
static void
|
|
flash_probe_in_boot2(void)
|
|
{
|
|
|
|
LOG_PRINT("flash_probe_in_boot2 enter!\n");
|
|
extern char __lzma_alloc_base, __lzma_alloc_size;
|
|
uint8_t *stash = (uint8_t *)((uintptr_t)&__lzma_alloc_base + SZALLOC_OFFSET);
|
|
ssize_t stash_size = (uintptr_t)&__lzma_alloc_size - SZALLOC_OFFSET;
|
|
|
|
stash_size = sb_volume_read("flashinfo", stash, stash_size);
|
|
if(stash_size < 0) {
|
|
LOG_ERR("Read volume 'flashinfo' failed!\n");
|
|
return;
|
|
}
|
|
LOG_PRINT("flash_info_size = %u!\n", stash_size);
|
|
if(flash_info_init(stash, stash_size) == 0) {
|
|
flash_force_all_probe();
|
|
}
|
|
}
|
|
#endif
|
|
/*---------------------------------------------------------------------------*/
|
|
#if USE_ARB
|
|
/*
|
|
* NV Counters layout:
|
|
* ___________________________________________________________________________
|
|
* | init_value | counter | swap counter| init_value | counter | swap counter|
|
|
* |____________|_________|_____________|____________|_________|_____________|
|
|
* | page 0 | page 1 | page 0 | page 1 |
|
|
* |______________________|_____________|______________________|_____________|
|
|
* | primary sector 0 | backup sector 1 |
|
|
* |____________________________________|____________________________________|
|
|
*
|
|
* The nv counter partition should be on the same flash devive as the
|
|
* Bootloader because Boot2 reads flash through the sb_flash_read()
|
|
* syscall which can only read the device where the Bootloader is located.
|
|
*
|
|
* This function must be called after the pattition table initialization.
|
|
*/
|
|
static int
|
|
display_plat_nvctr(void)
|
|
{
|
|
struct ptentry *pt_nv = ptable_find_entry(NV_CTR_PART_NAME);
|
|
if(!pt_nv) {
|
|
/*
|
|
* In some layouts, such as eMMC, the nv counter partition is in
|
|
* the private partition.
|
|
*/
|
|
pt_nv = ptable_find_entry(PRIVATE_PART_NAME);
|
|
if(!pt_nv) {
|
|
LOG_INFO("No nv counter partition\n");
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Read 512 bytes from nv counter partition to memory because:
|
|
* 1. sb_flash_read() dose not support to access not page(512 bytes) aligned
|
|
* data with eMMC.
|
|
* 2. 512 bytes is enough for get nv counter.
|
|
*/
|
|
extern char __lzma_alloc_base;
|
|
void *stash = (void *)((uintptr_t)&__lzma_alloc_base + SZALLOC_OFFSET);
|
|
const size_t size = 512;
|
|
|
|
if(sb_flash_read(pt_nv->start, stash, size) != size) {
|
|
LOG_ERR("Read nv counter failed!\n");
|
|
return -1;
|
|
}
|
|
|
|
flash_otp_nv_ctr_region_t *nv_ctr = stash;
|
|
if(nv_ctr->init_value != OTP_NV_COUNTERS_INITIALIZED) {
|
|
LOG_ERR("NV counter is invalid!\n");
|
|
return -1;
|
|
}
|
|
|
|
LOG_INFO("Platform nv counter: %lu\n",
|
|
nv_ctr->nv_counters[CHECK_NV_CTR_INDEX].nv_ctr);
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
/*---------------------------------------------------------------------------*/
|
|
int
|
|
main(void)
|
|
{
|
|
LOG_PRINT("Executing boot2 application...\n");
|
|
LOG_PRINT("Boot2 version: %s\n", BOOTLOADER_VERSION);
|
|
|
|
#ifdef USE_ARB
|
|
enable_flasher_guard();
|
|
#endif
|
|
|
|
if(arom_production_mode_get() == 1) {
|
|
/* set production mode flag */
|
|
#if defined(BOARD_CRANE) && AROM_VERSION != AROM_VER_2022_08_08_CRANEW_CR5
|
|
/*
|
|
* For Crane chips except for Watch 1 CR5.
|
|
*
|
|
* Set the pmic restart cmd to "production mode" to ensure compatiblity
|
|
* with already mass-producrd products. On those chips, CP(CR5), acting as
|
|
* host, checks the pmic restart cmd register to process different
|
|
* bootmode and then set it to the right value.
|
|
*
|
|
* Since the cmd and status are mapped to the same pmic register, cmd is
|
|
* used instead of status.
|
|
*/
|
|
pmic_set_restart_cmd(RESTART_STATUS_PRODUCTION);
|
|
#else
|
|
/*
|
|
* For Watch1 MCU and Watch1 CR5.
|
|
*
|
|
* The production mode flag will be passed to the Boot33 by the property
|
|
* of bl2.bootmode, and the subsequent software will use never pmic
|
|
* register to determine the boot mode.
|
|
*/
|
|
#endif /* defined(BOARD_CRANE) && AROM_VERSION != AROM_VER_2022_08_08_CRANEW_CR5 */
|
|
sys_boot_mode_set(SYS_BOOT_MODE_PRODUCTION);
|
|
}
|
|
|
|
sys_boot_mode_t boot_mode = sys_boot_mode_get();
|
|
|
|
if(ptable_loader()) {
|
|
LOG_ERR("Load ptable failed!\n");
|
|
return -1;
|
|
}
|
|
|
|
#if USE_ARB
|
|
/* This function must be called after the pattition table initialization. */
|
|
display_plat_nvctr();
|
|
#endif
|
|
|
|
#if QSPI_PROBE_IN_BOOT2_ENABLE
|
|
flash_probe_in_boot2();
|
|
#endif
|
|
|
|
#if AROM_VERSION != AROM_VER_2022_08_08_CRANEW_CR5
|
|
#if (defined(BOARD_CRANE) || defined(BOARD_CRANEW_MCU))
|
|
boardid_string = volume_read_boardid();
|
|
asr_property_set(PROP_NAME_BOARDID, boardid_string);
|
|
LOG_INFO("BOARD_ID: %s\n", boardid_string);
|
|
#endif
|
|
#endif
|
|
|
|
/*
|
|
* can not know whether usb-vbus is connected or not,
|
|
* try download mode only support usb-vbus connected case,
|
|
* if usb-vbus not connected, customer use at+qdownload = 1 to enter force download mode
|
|
*/
|
|
#if AROM_VERSION != AROM_VER_2022_08_08_CRANEW_CR5
|
|
if(!usb_connect()) {
|
|
LOG_WARN("usb is not connected\n");
|
|
if(boot_mode == SYS_BOOT_MODE_TRY_DOWNLOAD) {
|
|
#if DISABLE_UART_TRY_DOWNLOAD
|
|
boot_mode = SYS_BOOT_MODE_NORMAL;
|
|
#endif
|
|
}
|
|
}
|
|
#endif
|
|
|
|
switch(boot_mode) {
|
|
case SYS_BOOT_MODE_NORMAL:
|
|
LOG_INFO("Running in normal boot mode.\n");
|
|
return do_boot();
|
|
case SYS_BOOT_MODE_PRODUCTION:
|
|
LOG_INFO("Running in production mode.\n");
|
|
return do_boot();
|
|
#if AROM_VERSION != AROM_VER_2022_08_08_CRANEW_CR5
|
|
case SYS_BOOT_MODE_TRY_DOWNLOAD:
|
|
LOG_INFO("Running in try downloading mode.\n");
|
|
crane_boot2_init();
|
|
return 0;
|
|
#endif
|
|
case SYS_BOOT_MODE_FORCE_DOWNLOAD:
|
|
LOG_INFO("Running in force downloading mode.\n");
|
|
#if AROM_VERSION == AROM_VER_2020_07_30_CRANEGM_A0
|
|
/* only for AROM_VER_2020_07_30_CRANEGM_A0 */
|
|
/* an patch for arom-crane 0730
|
|
* fix bug for AT fall back invalid.
|
|
* arom-crane miss judge ret from boot2, so use negative value.
|
|
*/
|
|
return -SYS_BOOT_MODE_FORCE_DOWNLOAD;
|
|
#else
|
|
return SYS_BOOT_MODE_FORCE_DOWNLOAD;
|
|
#endif
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return -1;
|
|
}
|