400 lines
12 KiB
C
400 lines
12 KiB
C
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdbool.h>
|
|
#include "psram.h"
|
|
#include "pmic.h"
|
|
#include "cpu.h"
|
|
#include "secureboot.h"
|
|
#include "aboot.h"
|
|
#include "reg.h"
|
|
#include "smux.h"
|
|
#include "property.h"
|
|
#include "efuse.h"
|
|
#include "syscall-arom.h"
|
|
#include "pmu.h"
|
|
#if defined(CPU_MODEL_CRANE)
|
|
#include "freq.h"
|
|
#include "mpu.h"
|
|
#endif
|
|
|
|
#define NOT_MCU_CR5 ((AROM_VERSION != AROM_VER_2022_08_08_CRANEW_CR5))
|
|
|
|
#define SUPPORT_DDR_MEMORY (AROM_VERSION == AROM_VER_2022_11_11_CRANEG_CR5)
|
|
|
|
#define SUPPORT_PSRAM_MEMORY (AROM_VERSION != AROM_VER_2022_11_11_CRANEG_CR5 && \
|
|
AROM_VERSION != AROM_VER_2024_04_30_LAPWING_CR5 && \
|
|
AROM_VERSION != AROM_VER_2022_08_08_CRANEW_CR5)
|
|
#if SUPPORT_DDR_MEMORY
|
|
#include "ddr.h"
|
|
#endif
|
|
|
|
#include "log.h"
|
|
#define LOG_MODULE "Preboot"
|
|
#define LOG_LEVEL LOG_LEVEL_MAIN
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
#define SUPPORT_BOOT_GO_TO_PRODUCTION 0
|
|
/*---------------------------------------------------------------------------*/
|
|
#if defined(CPU_MODEL_CRANE)
|
|
extern char __lzma_decode_start, __lzma_decode_size;
|
|
#endif
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
#define UMTI_BASE 0xD4207000
|
|
#define USB_PHY_REG_04 0x10
|
|
#define USB_PHY_REG_25 0x94
|
|
#define USB_PHY_REG_28 0xA0
|
|
#define USB_PHY_REG_29 0xA4
|
|
#define HS_ISEL_MASK (0x3 << 12)
|
|
#define HS_ISEL (0x3 << 12)
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
#define QUECTEL_PREBOOT_OPT
|
|
#ifdef QUECTEL_PREBOOT_OPT
|
|
#include "i2c.h"
|
|
static int Quec_PMIC_GET_PWEKY_STATUS(void)
|
|
{
|
|
uint8_t reg_val;
|
|
pi2c_read_reg(0x01, ®_val);
|
|
if(reg_val & (0x01<<1))
|
|
{
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
return 0;
|
|
}
|
|
static int Quec_PowerOnCheck(void)
|
|
{
|
|
unsigned int i=0;
|
|
|
|
//uart_printf("[Quec][PWK]OnkeyPowerOnCheck\r\n");
|
|
/* Set 15s for power-down-by-long-ONKEY-pressing period, this register is
|
|
restricted to change only one bit each time. */
|
|
pi2c_init(PMIC_BASE_PAGE_ADDR);
|
|
#if (AROM_VERSION == AROM_VER_2022_11_06_CRANEL_CR5)
|
|
for(i=0;i<80;i++) // 1602ƽ̨ 520ms+100ms(run here need 270ms )= 620ms for powerkey check.
|
|
#elif (AROM_VERSION == AROM_VER_2020_07_30_CRANEGM_A0)
|
|
for(i=0;i<20;i++)
|
|
#else
|
|
for(i=0;i<5;i++) // 1606ƽ̨ 520ms+100ms(run here need 270ms )= 620ms for powerkey check.
|
|
#endif
|
|
{
|
|
if (!Quec_PMIC_GET_PWEKY_STATUS())
|
|
{
|
|
LOG_PRINT("short press, do poweroff!!\r\n");
|
|
clock_wait_ms(10); /* 100 ms */
|
|
return 1; //Power down if ONKEY is not pressed long enough.
|
|
}
|
|
clock_wait_ms(1); /* 5 ms */
|
|
}
|
|
LOG_PRINT("long press, do poweron!!\r\n");
|
|
return 0;
|
|
}
|
|
|
|
|
|
void quec_powerkey_check(void)
|
|
{
|
|
unsigned char power_up_flag = 0xff, i = 0;
|
|
unsigned char val;
|
|
int pmic_reset_retry = 3;
|
|
unsigned char reg[10] = {0};
|
|
|
|
while(pmic_reset_retry--) {
|
|
pi2c_bus_reset();
|
|
pi2c_reset();
|
|
pi2c_init(PMIC_BASE_PAGE_ADDR);
|
|
if(pi2c_read_reg(PMIC_ID, &val) == 0) {
|
|
break;
|
|
}
|
|
}
|
|
pi2c_read_reg(0x01, ®[0]);//status
|
|
pi2c_read_reg(0x10, ®[1]);
|
|
pi2c_read_reg(0xe5, ®[2]);
|
|
pi2c_read_reg(0xe6, ®[3]);
|
|
pi2c_read_reg(0xe2, ®[4]);
|
|
pi2c_read_reg(0xeb, ®[5]);
|
|
LOG_PRINT("PMIC REG:0x01,0x10,0xe5,0xe6,0xe2,0xeb\r\n");
|
|
LOG_PRINT("PMIC VAL:0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x\r\n",reg[0],reg[1],reg[2],reg[3],reg[4],reg[5]);
|
|
if(smux_running_mode_get() == SMUX_MODE_NORMAL)
|
|
{
|
|
power_up_flag = 0x01; // hot power on
|
|
LOG_PRINT("download mode, do power on\n");
|
|
}
|
|
else
|
|
{
|
|
if (PMIC_PID(val) == PM802)
|
|
{
|
|
pi2c_read_reg(0x10, ®[0]); //read power up log
|
|
pi2c_read_reg(0xf0, ®[1]); //read xo reg
|
|
pi2c_read_reg(0x01, ®[2]); //read exton1n status
|
|
|
|
if((reg[1] & 0xf0) == 0x0) //cold power up
|
|
{
|
|
if((reg[0] == 0x0) && ((reg[2] & 0x02) == 0)) // unkown wakeup source && pwrkey is not pressed
|
|
{
|
|
LOG_PRINT("unkown wakeup:%d, do power off!!!\n",reg[0]);
|
|
|
|
pi2c_write_reg(0xe2, 0xf0); //set discharger timer to 0S //default 2S
|
|
pi2c_read_reg(0xe7, ®[0]);
|
|
pi2c_write_reg(0xe7, (reg[0] & 0xfb)); //disalbe fault wakeup
|
|
pi2c_read_reg(0x0d, ®[0]);
|
|
pi2c_write_reg(0x0d, (reg[0])|0x20) ;
|
|
return;
|
|
}
|
|
}
|
|
pi2c_write_reg(0xe2, 0xf1); //set discharger timer back to 1S
|
|
}
|
|
|
|
if( 0 == (reg[5]&0x80))
|
|
{
|
|
power_up_flag = 0x00; // cold power on
|
|
LOG_PRINT("cold power on\n");
|
|
}
|
|
else
|
|
{
|
|
power_up_flag = 0x01; // hot power on
|
|
LOG_PRINT("hot power on\n");
|
|
}
|
|
if(0x00 == power_up_flag) // cold power on
|
|
{
|
|
|
|
if(Quec_PowerOnCheck())
|
|
{
|
|
LOG_PRINT("warning: powkey too short !!!!!\r\n");
|
|
//quec_pmic_sw_pdown();
|
|
pmic_sw_pdown();
|
|
return;
|
|
}
|
|
//save hot flag
|
|
pi2c_write_reg(0xeb, (reg[5] | 0x80));
|
|
}
|
|
}
|
|
for(i = 0;i < 10; i++)
|
|
{
|
|
if(reg[i] == 0x0)
|
|
{
|
|
reg[i] = 0xFF;
|
|
}
|
|
}
|
|
reg[9] = 0x0;
|
|
asr_property_set("power_down_reg", (const char*)(reg));
|
|
}
|
|
#endif
|
|
void
|
|
usb_phy_config(void)
|
|
{
|
|
unsigned val;
|
|
unsigned chip_id;
|
|
|
|
chip_id = hw_chip_id();
|
|
if(chip_id == CHIP_ID_CRANE) {
|
|
/* driver strength */
|
|
val = (unsigned)readl(UMTI_BASE + USB_PHY_REG_28);
|
|
writel((val & ~HS_ISEL_MASK) | HS_ISEL, UMTI_BASE + USB_PHY_REG_28);
|
|
LOG_PRINT("Usb phy reg 28 0x%x -> 0x%lx\n", val, readl(UMTI_BASE + USB_PHY_REG_28));
|
|
} else if((CHIP_ID_CRANEG == chip_id) || (CHIP_ID_CRANEM == chip_id)) {
|
|
val = (unsigned)readl(UMTI_BASE + USB_PHY_REG_29);
|
|
writel((val & ~0x1F) | 0x1B, UMTI_BASE + USB_PHY_REG_29);
|
|
LOG_PRINT("Usb phy reg 29 0x%x -> 0x%lx\n", val, readl(UMTI_BASE + USB_PHY_REG_29));
|
|
val = (unsigned)readl(UMTI_BASE + USB_PHY_REG_25);
|
|
writel(val | (BIT7), UMTI_BASE + USB_PHY_REG_25);
|
|
val = (unsigned)readl(UMTI_BASE + USB_PHY_REG_04);
|
|
writel(val | (BIT4 | BIT5 | BIT6), UMTI_BASE + USB_PHY_REG_04);
|
|
}
|
|
}
|
|
/*---------------------------------------------------------------------------*/
|
|
#if defined(CPU_MODEL_CRANE) && (AROM_VERSION != AROM_VER_2024_04_30_LAPWING_CR5)
|
|
static void
|
|
psram_mpu_config(void)
|
|
{
|
|
#if SUPPORT_DDR_MEMORY
|
|
extern char __ddr_base;
|
|
unsigned base = (unsigned)&__ddr_base;
|
|
unsigned size = get_ddr_size();
|
|
#else
|
|
extern char __psram_base;
|
|
unsigned base = (unsigned)&__psram_base;
|
|
unsigned size = get_psram_size();
|
|
#endif
|
|
|
|
mpu_region_config(ATCM_CODE_REGION_NUM, 0x0, 0x10000, MPU_ATTR_RWX);
|
|
mpu_region_config(PSRAM_DDR_REGION_NUM_RWX, base, size, MPU_ATTR_RWX);
|
|
mpu_region_config(PSRAM_DDR_REGION_NUM_NONE, 0x0, 0x80000000, MPU_ATTR_NONE);
|
|
|
|
/* These used memory(>= 0x8000_0000) should be configurated to MPU normal,
|
|
* if not configurated in bootrom for Cortex R5.
|
|
*/
|
|
#if (AROM_VERSION == AROM_VER_2020_07_30_CRANEGM_A0 || \
|
|
AROM_VERSION == AROM_VER_2022_11_06_CRANEL_CR5)
|
|
extern char __aram_ctext_start, __aram_ctext_size;
|
|
mpu_region_config(L2SRAM_REGION_NUM, &__aram_ctext_start, &__aram_ctext_size, MPU_ATTR_RWX);
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
#if NOT_MCU_CR5
|
|
static int
|
|
pmic_config(void)
|
|
{
|
|
if(hw_platform_type() != HW_PLATFORM_TYPE_SILICON) {
|
|
return 0;
|
|
}
|
|
|
|
pmic_setup();
|
|
|
|
uint8_t powerup_reason = pmic_powerup_get_reason();
|
|
LOG_PRINT("Power_up_reason=0x%x.\n", powerup_reason);
|
|
|
|
pmic_fault_wu_en_disable();
|
|
|
|
uint8_t pmic_id = pmic_get_id();
|
|
/* PM803 is different with others */
|
|
uint8_t invalid_bits = (pmic_id == PM803) ? PM803_INVALID_STATE :
|
|
PM813_INVALID_STATE;
|
|
|
|
if(powerup_reason & invalid_bits) {
|
|
LOG_WARN("Warning: power_up_reason=0x%x is abnormal.\n", powerup_reason);
|
|
/* pmic_sw_pdown(); */
|
|
/* return 0; */
|
|
}
|
|
|
|
switch(pmic_id) {
|
|
case PM802:
|
|
case PM802S:
|
|
/* workaround for PM802, if power up log = 0 or 8(bat_wu_log), pmic power down. PM813 no this hardware bug. */
|
|
if(0 == powerup_reason || 8 == powerup_reason) {
|
|
LOG_WARN("Warning: power_up_reason = 0 or 8(bat_wu_log). need pmic power down\n");
|
|
pmic_sw_pdown();
|
|
/* never reach here. */
|
|
}
|
|
break;
|
|
case PM813L:
|
|
/* pmic813L A0's bug: onkey reason cannot set bit in powerup_reason, So add workaround */
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
/*---------------------------------------------------------------------------*/
|
|
int
|
|
main(void)
|
|
{
|
|
/*read or write geu, must enable clk at first, else, geu bank dump always be 0. */
|
|
#if (AROM_VERSION != AROM_VER_2022_08_08_CRANEW_CR5)
|
|
/* watch1 cr5 does not require the use of the GEU module. */
|
|
geu_clk_enable();
|
|
#endif
|
|
|
|
#if defined(CPU_MODEL_CRANE)
|
|
cr5_axi_set_max_freq();
|
|
#endif
|
|
|
|
LOG_PRINT("Executing preboot application...\n");
|
|
LOG_PRINT("Preboot version: %s\n", BOOTLOADER_VERSION);
|
|
|
|
/* force init prop 1K space: 0XB0020C00~ 0xB0021000 */
|
|
asr_property_area_init(1);
|
|
asr_property_set("bl2.preboot.ver", BOOTLOADER_VERSION);
|
|
|
|
#if defined(CPU_MODEL_CRANE) || defined(CPU_MODEL_CRANEW_MCU)
|
|
#if NOT_MCU_CR5
|
|
/* arom-crane alread print log, this is only for set prop */
|
|
if(!fuse_trust_boot_enabled()) {
|
|
/*LOG_PRINT("### Non-trusted boot mode. ###\n"); */
|
|
asr_property_set("bl1.secureboot", "0");
|
|
} else {
|
|
/*LOG_PRINT("### Trusted boot mode. ###\n"); */
|
|
asr_property_set("bl1.secureboot", "1");
|
|
}
|
|
#else
|
|
/*LOG_PRINT("### Non-trusted boot mode. ###\n"); */
|
|
asr_property_set("bl1.secureboot", "0");
|
|
#endif
|
|
|
|
#if NOT_MCU_CR5
|
|
/*
|
|
* "halt": When download completed, if usb pull out, board powerdown. defaultly it is "halt",
|
|
* "reboot": some customer want to reboot instead of powerdown, so customer set it to "reboot" manually.
|
|
* "noaction": if vbus is unconnected, usb_connect() is 0.
|
|
* need set "noaction" to workaround the bug:
|
|
* After download, flasher judges that it is usb pulled out, enter forcedown by mistake.
|
|
*/
|
|
asr_property_set("bl2.usb_disconnect", "halt");
|
|
|
|
/* enter production mode after go(boot continue) if bl2.go_production is true */
|
|
#if SUPPORT_BOOT_GO_TO_PRODUCTION
|
|
asr_property_set(PROP_NAME_GO_PRODUCTION, "true");
|
|
#endif
|
|
|
|
usb_phy_config();
|
|
|
|
fuse_read_lotid();
|
|
|
|
//Move it to pmic_setuppmic_setup(void),after i2c initialization
|
|
//#ifdef QUECTEL_PREBOOT_OPT
|
|
// quec_powerkey_check();
|
|
//#endif
|
|
pmic_config();
|
|
#endif
|
|
#endif
|
|
|
|
#if AROM_VERSION == AROM_VER_2022_07_28_WATCH1
|
|
if(efuse_modem_type_is_radio()) {
|
|
asr_property_set("cp.modem.type", "MODEM_RADIO");
|
|
} else {
|
|
asr_property_set("cp.modem.type", "MODEM_ZERO");
|
|
}
|
|
#endif
|
|
|
|
#if (SUPPORT_DDR_MEMORY)
|
|
unsigned chip_id = hw_chip_id();
|
|
if(chip_id == CHIP_ID_CRANEGT) {
|
|
ddr_init();
|
|
}
|
|
#endif
|
|
|
|
#if (SUPPORT_PSRAM_MEMORY)
|
|
psram_init();
|
|
#endif
|
|
|
|
#if AROM_VERSION == AROM_VER_2022_08_08_CRANEW_CR5
|
|
/*
|
|
* Watch1 cr5 psram is initialized in Harmony, and initialization is no longer repeated in
|
|
* bootloader, mcu will write cr5 psram type to SW_SCRATCH(0xD4282CE8) register bit[15:8]
|
|
* in Harmony, so cr5 read SW_SCRATCH bit[15:8] to get psram type here.
|
|
*/
|
|
char psram_type_str[PROP_VALUE_MAX] = "";
|
|
extern void psram_type_name_get_by_sw_scratch(char *psram_type_str, size_t size);
|
|
psram_type_name_get_by_sw_scratch(psram_type_str, sizeof(psram_type_str));
|
|
asr_property_set("fuse.psram.type", psram_type_str);
|
|
#endif
|
|
|
|
#if defined(CPU_MODEL_CRANE)
|
|
#if (AROM_VERSION != AROM_VER_2024_04_30_LAPWING_CR5)
|
|
psram_mpu_config();
|
|
#endif
|
|
/*
|
|
* Atcm 64K is not enough to parse bootloder volume, so update to psram.
|
|
*/
|
|
LOG_INFO("Set fip image load address spaces to 0x%x\n",
|
|
(unsigned)&__lzma_decode_start);
|
|
sb_fip_image_setup((void *)&__lzma_decode_start, (unsigned)&__lzma_decode_size);
|
|
#endif
|
|
|
|
#if (AROM_VERSION == AROM_VER_2022_08_08_CRANEW_CR5)
|
|
uint32_t val = readl(CIU_BASE + SW_SCRATCH);
|
|
val = (val & ~FLAGS_RUNNING_STAGE_MASK) | FLAGS_RUNNING_STAGE_PREBOOT_COMPLETE;
|
|
writel(val, CIU_BASE + SW_SCRATCH);
|
|
LOG_INFO("Set running stage: [0x%x] = 0x%x.\n", (CIU_BASE + SW_SCRATCH), (unsigned)readl(CIU_BASE + SW_SCRATCH));
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
/*---------------------------------------------------------------------------*/
|