Files
NANOKVM-LicheeRV-Nano-Build…/fsbl/plat/cv181x/bl2/bl2_opt.c
916BGAI dbbad1938a fsbl: sync sg200x-dev through 5a80c12
Update the vendored FSBL from Sophgo sg200x-dev commit
426d1e7eccce84b34169e5f21de7d6e7da1804a1 to
5a80c127cf614dea7f534d5b5352886a1c720d37, incorporating 24 upstream
commits. Keep the local plat/sg200x symlink to cv181x.

Import the upstream DDR, clock, storage and boot-image changes together
with their platform support, prebuilt firmware and licensing files.
All 935 upstream files match the target revision.

Validation on LicheeRV Nano (SG2002/C906, SD, DDR3-1866 x16):
- Cross-build BL2 with the existing Xuantie GCC 10.2.0 toolchain.
- Repack FIP while preserving the installed OpenSBI and U-Boot byte
  for byte; verify headers, payload checksums, entry addresses and LZMA.
- Software reboot and power-cycle boot succeed; memtester 16M 1 passes
  all 18 checks.

Validation covers the FSBL update with existing later boot stages.
Full firmware builds, A53 and video/HID acceptance are not covered.
2026-11-06 18:34:01 +08:00

614 lines
16 KiB
C

/*
* Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <debug.h>
#include <bitwise_ops.h>
#include <console.h>
#include <platform.h>
#include <rom_api.h>
#include <bl2.h>
#include <ddr.h>
#include <ddr_sys.h>
#include <rtc.h>
#include <string.h>
#include <decompress.h>
#include <delay_timer.h>
#include <security/security.h>
#include <emmc/emmc.h>
#include <cv_spi_nand.h>
uint64_t load_addr = 0x0c000;
uint64_t run_addr = 0x8000C000;
uint64_t reading_size = 0x020000;
struct _time_records *time_records = (void *)TIME_RECORDS_ADDR;
struct fip_param1 *fip_param1 = (void *)PARAM1_BASE;
static struct fip_param2 fip_param2 __aligned(BLOCK_SIZE);
static union {
struct ddr_param ddr_param;
struct loader_2nd_header loader_2nd_header;
uint8_t buf[BLOCK_SIZE];
} sram_union_buf __aligned(BLOCK_SIZE);
int init_comm_info(int ret) __attribute__((weak));
int init_comm_info(int ret)
{
return ret;
}
void print_sram_log(void)
{
uint32_t *const log_size = (void *)BOOT_LOG_LEN_ADDR;
uint8_t *const log_buf = (void *)phys_to_dma(BOOT_LOG_BUF_BASE);
uint32_t i;
static const char m1[] = "\nSRAM Log: ========================================\n";
static const char m2[] = "\nSRAM Log end: ====================================\n";
for (i = 0; m1[i]; i++)
console_putc(m1[i]);
for (i = 0; i < *log_size; i++)
console_putc(log_buf[i]);
for (i = 0; m2[i]; i++)
console_putc(m2[i]);
}
void lock_efuse_chipsn(void)
{
int value = mmio_read_32(EFUSE_W_LOCK0_REG);
if (efuse_power_on()) {
NOTICE("efuse power on fail\n");
return;
}
if ((value & (0x1 << BIT_FTSN3_LOCK)) == 0)
efuse_program_bit(0x26, BIT_FTSN3_LOCK);
if ((value & (0x1 << BIT_FTSN4_LOCK)) == 0)
efuse_program_bit(0x26, BIT_FTSN4_LOCK);
if (efuse_refresh_shadow()) {
NOTICE("efuse refresh shadow fail\n");
return;
}
value = mmio_read_32(EFUSE_W_LOCK0_REG);
if (((value & (0x3 << BIT_FTSN3_LOCK)) >> BIT_FTSN3_LOCK) != 0x3)
NOTICE("lock efuse chipsn fail\n");
if (efuse_power_off()) {
NOTICE("efuse power off fail\n");
return;
}
}
int load_param2(int retry)
{
uint32_t crc;
int ret = -1;
NOTICE("P2S/0x%lx/%p.\n", sizeof(fip_param2), &fip_param2);
ret = p_rom_api_load_image(&fip_param2, fip_param1->param2_loadaddr, PARAM2_SIZE, retry);
if (ret < 0) {
return ret;
}
if (fip_param2.magic1 != FIP_PARAM2_MAGIC1) {
WARN("LP2_NOMAGIC\n");
return -1;
}
crc = p_rom_api_image_crc(&fip_param2.reserved1, sizeof(fip_param2) - 12);
if (crc != fip_param2.param2_cksum) {
ERROR("param2_cksum (0x%x/0x%x)\n", crc, fip_param2.param2_cksum);
return -1;
}
NOTICE("P2E.\n");
return 0;
}
int load_ddr(void)
{
#ifndef ENABLE_BOOT0
int retry = 0;
retry_from_flash:
for (retry = 0; retry < p_rom_api_get_number_of_retries(); retry++) {
if (load_param2(retry) < 0)
continue;
break;
}
if (retry >= p_rom_api_get_number_of_retries()) {
switch (p_rom_api_get_boot_src()) {
case BOOT_SRC_UART:
case BOOT_SRC_SD:
case BOOT_SRC_USB:
WARN("DL cancelled. Load flash. (%d).\n", retry);
// Continue to boot from flash if boot from external source
p_rom_api_flash_init();
goto retry_from_flash;
default:
ERROR("Failed to load param2 (%d).\n", retry);
panic_handler();
}
}
#endif
time_records->ddr_init_start = read_time_ms();
ddr_init(&sram_union_buf.ddr_param);
time_records->ddr_init_end = read_time_ms();
return 0;
}
static int emmc_read_fip_bl2(uint32_t offset, uint32_t size, uintptr_t buf)
{
int lba = 0;
if (((offset & EMMC_BLOCK_MASK) != 0) || ((buf & EMMC_BLOCK_MASK) != 0) || ((size & EMMC_BLOCK_MASK) != 0))
return -22;
lba = offset / EMMC_BLOCK_SIZE;
// INFO("%s offset %x,lba %d, size %d, dst buf 0x%lx\n", __func__, offset, lba, size, buf);
if (size != emmc_partition_read_blocks(EMMC_PARTITION_BOOT1, lba, buf, size))
return -5;
return 0;
}
static int load_data_from_storage(void *buffer, uint32_t offset, uint32_t size, int retry)
{
static int is_get_boot_src;
static int boot_src;
if (!is_get_boot_src) {
boot_src = p_rom_api_get_boot_src();
is_get_boot_src = 1;
/* reinit eMMC */
if (boot_src == BOOT_SRC_EMMC)
bm_emmc_init();
}
//use BL2 eMMC driver to load image
if (boot_src == BOOT_SRC_EMMC) {
return emmc_read_fip_bl2(offset, size, (uintptr_t)buffer);
} else {
return p_rom_api_load_image(buffer, offset, size, retry);
}
}
int load_blcp_2nd(int retry)
{
uint32_t crc, rtos_base;
int ret = -1;
// if no blcp_2nd, release_blcp_2nd should be ddr_init_end
time_records->release_blcp_2nd = time_records->ddr_init_end;
NOTICE("C2S/0x%x/0x%x/0x%x.\n", fip_param2.blcp_2nd_loadaddr, fip_param2.blcp_2nd_runaddr,
fip_param2.blcp_2nd_size);
if (!fip_param2.blcp_2nd_runaddr) {
NOTICE("No C906L image.\n");
return 0;
}
if (!IN_RANGE(fip_param2.blcp_2nd_runaddr, DRAM_BASE, DRAM_SIZE)) {
ERROR("blcp_2nd_runaddr (0x%x) is not in DRAM.\n", fip_param2.blcp_2nd_runaddr);
panic_handler();
}
if (!IN_RANGE(fip_param2.blcp_2nd_runaddr + fip_param2.blcp_2nd_size, DRAM_BASE, DRAM_SIZE)) {
ERROR("blcp_2nd_size (0x%x) is not in DRAM.\n", fip_param2.blcp_2nd_size);
panic_handler();
}
ret = load_data_from_storage((void *)(uintptr_t)fip_param2.blcp_2nd_runaddr, fip_param2.blcp_2nd_loadaddr,
fip_param2.blcp_2nd_size, retry);
if (ret < 0) {
return ret;
}
crc = p_rom_api_image_crc((void *)(uintptr_t)fip_param2.blcp_2nd_runaddr, fip_param2.blcp_2nd_size);
if (crc != fip_param2.blcp_2nd_cksum) {
ERROR("blcp_2nd_cksum (0x%x/0x%x)\n", crc, fip_param2.blcp_2nd_cksum);
return -1;
}
ret = dec_verify_image((void *)(uintptr_t)fip_param2.blcp_2nd_runaddr, fip_param2.blcp_2nd_size, 0, fip_param1);
if (ret < 0) {
ERROR("verify blcp 2nd (%d)\n", ret);
return ret;
}
flush_dcache_range(fip_param2.blcp_2nd_runaddr, fip_param2.blcp_2nd_size);
rtos_base = mmio_read_32(AXI_SRAM_RTOS_BASE);
init_comm_info(0);
switch (p_rom_api_get_boot_src()) {
case BOOT_SRC_UART:
// case BOOT_SRC_SD:
// case BOOT_SRC_USB:
break;
default:
time_records->release_blcp_2nd = read_time_ms();
if (rtos_base == CVI_RTOS_MAGIC_CODE) {
mmio_write_32(AXI_SRAM_RTOS_BASE, fip_param2.blcp_2nd_runaddr);
} else {
reset_c906l(fip_param2.blcp_2nd_runaddr);
}
}
NOTICE("C2E.\n");
return 0;
}
int load_monitor(int retry, uint64_t *monitor_entry)
{
uint32_t crc;
int ret = -1;
NOTICE("MS/0x%x/0x%x/0x%x.\n", fip_param2.monitor_loadaddr, fip_param2.monitor_runaddr,
fip_param2.monitor_size);
if (!fip_param2.monitor_runaddr) {
NOTICE("No monitor.\n");
return 0;
}
if (!IN_RANGE(fip_param2.monitor_runaddr, DRAM_BASE, DRAM_SIZE)) {
ERROR("monitor_runaddr (0x%x) is not in DRAM.\n", fip_param2.monitor_runaddr);
panic_handler();
}
if (!IN_RANGE(fip_param2.monitor_runaddr + fip_param2.monitor_size, DRAM_BASE, DRAM_SIZE)) {
ERROR("monitor_size (0x%x) is not in DRAM.\n", fip_param2.monitor_size);
panic_handler();
}
ret = load_data_from_storage((void *)(uintptr_t)fip_param2.monitor_runaddr, fip_param2.monitor_loadaddr,
fip_param2.monitor_size, retry);
if (ret < 0) {
return ret;
}
crc = p_rom_api_image_crc((void *)(uintptr_t)fip_param2.monitor_runaddr, fip_param2.monitor_size);
if (crc != fip_param2.monitor_cksum) {
ERROR("monitor_cksum (0x%x/0x%x)\n", crc, fip_param2.monitor_cksum);
return -1;
}
ret = dec_verify_image((void *)(uintptr_t)fip_param2.monitor_runaddr, fip_param2.monitor_size, 0, fip_param1);
if (ret < 0) {
ERROR("verify monitor (%d)\n", ret);
return ret;
}
flush_dcache_range(fip_param2.monitor_runaddr, fip_param2.monitor_size);
NOTICE("ME.\n");
*monitor_entry = fip_param2.monitor_runaddr;
return 0;
}
#ifdef ENABLE_BURN_BUTTON
int button_usb_down_pressed(void)
{
// Modify the GPIO configuration as needed!!!!!!!!!
uint8_t gpio_grp = GPIO_GRP, gpio_pin = GPIO_PIN; // XGPIOB[3];
NOTICE("gpio_grp = %d gpio_pin = %d\n", gpio_grp, gpio_pin);
// gpio base addr: gpioa, gpiob, gpioc, gpiod, pwr_gpio;
uint32_t gpio_base[5] = { 0x03020000, 0x03021000, 0x03022000, 0x03023000, 0x05021000 };
uint32_t gpio_direction_addr = gpio_base[gpio_grp] + 0x4;
uint32_t gpio_value_addr = gpio_base[gpio_grp] + 0x50;
uint32_t val = 0x1;
/* pinmux config */
// mmio_write_32(0x03001098, 0x3);
/* open internel pull up */
// mmio_write_32(0x05027020, 0x44);
/* gpio input mode */
val = mmio_read_32(gpio_direction_addr) & (~(1 << gpio_pin));
mmio_write_32(gpio_direction_addr, val);
/* gpio debouncing */
val = (mmio_read_32(gpio_value_addr) >> gpio_pin) & 0x1;
NOTICE("key value = %u (key down should be 0)\n", val);
if (!val) {
mdelay(10);
val = (mmio_read_32(gpio_value_addr) >> gpio_pin) & 0x1;
NOTICE("repeat key value = %u (key down should be 0)\n", val);
return !val;
}
return 0; // pressed:1 unpressed:0
}
int load_uboot(void *image_buf, int retry)
{
int ret = -1;
int reading_size = 0;
reading_size = ROUND_UP(fip_param2.loader_2nd_b_size, BLOCK_SIZE);
NOTICE("reading_size:%x, addr:=0x%x\n", reading_size, fip_param2.loader_2nd_b_loadaddr);
ret = load_data_from_storage(image_buf, fip_param2.loader_2nd_b_loadaddr, reading_size, retry);
if (ret < 0) {
return -1;
}
return 0;
}
#endif
int load_loader_2nd(int retry, uint64_t *loader_2nd_entry)
{
struct loader_2nd_header *loader_2nd_header = &sram_union_buf.loader_2nd_header;
uint32_t crc;
int ret = -1;
const int cksum_offset =
offsetof(struct loader_2nd_header, cksum) + sizeof(((struct loader_2nd_header *)0)->cksum);
enum COMPRESS_TYPE comp_type = COMP_NONE;
int reading_size;
void *image_buf;
NOTICE("L2/0x%x.\n", fip_param2.loader_2nd_loadaddr);
ret = load_data_from_storage(loader_2nd_header, fip_param2.loader_2nd_loadaddr, BLOCK_SIZE, retry);
if (ret < 0) {
return -1;
}
reading_size = ROUND_UP(loader_2nd_header->size, BLOCK_SIZE);
NOTICE("L2/0x%x/0x%x/0x%lx/0x%x/0x%x\n", loader_2nd_header->magic, loader_2nd_header->cksum,
loader_2nd_header->runaddr, loader_2nd_header->size, reading_size);
#ifdef ENABLE_BURN_BUTTON
if (button_usb_down_pressed()) {
NOTICE("usb_down button pressed.\n");
mmio_write_32(BOOT_SOURCE_FLAG_ADDR, MAGIC_NUM_USB_DL);
loader_2nd_header->runaddr = CONFIG_SYS_TEXT_BASE;
ret = load_uboot((void *)loader_2nd_header->runaddr, retry);
if (ret < 0) {
return -1;
}
goto done;
}
#endif
switch (loader_2nd_header->magic) {
case LOADER_2ND_MAGIC_LZMA:
comp_type = COMP_LZMA;
break;
case LOADER_2ND_MAGIC_LZ4:
comp_type = COMP_LZ4;
break;
default:
comp_type = COMP_NONE;
break;
}
if (comp_type) {
NOTICE("COMP/%d.\n", comp_type);
image_buf = (void *)DECOMP_BUF_ADDR;
} else {
image_buf = (void *)loader_2nd_header->runaddr;
}
ret = p_rom_api_load_image(image_buf, fip_param2.loader_2nd_loadaddr, reading_size, retry);
if (ret < 0) {
return -1;
}
crc = p_rom_api_image_crc(image_buf + cksum_offset, loader_2nd_header->size - cksum_offset);
if (crc != loader_2nd_header->cksum) {
ERROR("loader_2nd_cksum (0x%x/0x%x)\n", crc, loader_2nd_header->cksum);
return -1;
}
ret = dec_verify_image(image_buf + cksum_offset, loader_2nd_header->size - cksum_offset,
sizeof(struct loader_2nd_header) - cksum_offset, fip_param1);
if (ret < 0) {
ERROR("verify loader 2nd (%d)\n", ret);
return ret;
}
time_records->load_loader_2nd_end = read_time_ms();
sys_switch_all_to_pll();
time_records->fsbl_decomp_start = read_time_ms();
if (comp_type) {
size_t dst_size = DECOMP_DST_SIZE;
// header is not compressed.
void *dst = (void *)loader_2nd_header->runaddr;
memcpy(dst, image_buf, sizeof(struct loader_2nd_header));
image_buf += sizeof(struct loader_2nd_header);
ret = decompress(dst + sizeof(struct loader_2nd_header), &dst_size, image_buf, loader_2nd_header->size,
comp_type);
if (ret < 0) {
ERROR("Failed to decompress loader_2nd (%d/%lu)\n", ret, dst_size);
return -1;
}
reading_size = dst_size;
}
#ifdef ENABLE_BURN_BUTTON
done:
#endif
flush_dcache_range(loader_2nd_header->runaddr, reading_size);
time_records->fsbl_decomp_end = read_time_ms();
NOTICE("Loader_2nd loaded.\n");
*loader_2nd_entry = loader_2nd_header->runaddr + sizeof(struct loader_2nd_header);
return 0;
}
int load_loader_2nd_alios(int retry, uint64_t *loader_2nd_entry)
{
void *image_buf;
int ret = -1;
#ifdef BOOT_SPINOR
load_addr = 0x0c000;
#endif
#ifdef BOOT_EMMC
load_addr = 0x00000;
#endif
#ifdef BOOT_SPINAND
load_addr = 0x280000;
#endif
uint64_t loadaddr_alios = load_addr;
uint64_t runaddr_alios = run_addr;
uint64_t size_alios = reading_size;
image_buf = (void *)runaddr_alios;
NOTICE("loadaddr_alios:0x%lx runaddr_alios:0x%lx.\n", loadaddr_alios, runaddr_alios);
#ifdef BOOT_SPINAND
/* SPI-NAND uses the in-tree raw-read driver: read linearly by physical
* page, bypassing the ROM API FIP (FIPH/fip_vector) scan. The single-image
* RTT boot partition is not in the NAND-FIP layout, so the ROM API returns
* FIP0NC. get_nand_info() self-calibrates the geometry on the first read.
* Compiled only into spinand boot0 images; the full-FIP paths are untouched,
* symmetric with cv180x. */
{
static int nand_info_ready;
if (!nand_info_ready) {
get_nand_info();
nand_info_ready = 1;
}
ret = cv_spi_nand_read_data(image_buf, loadaddr_alios, size_alios);
}
#else
ret = p_rom_api_load_image(image_buf, loadaddr_alios, size_alios, retry);
#endif
/* Must check the return value: the original code ignored ret and jumped to
* run_addr executing garbage on a failed load, causing a panic. */
if (ret < 0) {
ERROR("load loader_2nd_alios failed (%d)\n", ret);
return ret;
}
NOTICE("image_buf:0x%lx.\n", *((uint64_t *)runaddr_alios));
if (security_is_tee_enabled()) {
ret = dec_verify_image(image_buf,size_alios, 0, fip_param1);
if (ret < 0) {
ERROR("verify alios boot0 failed (%d)\n", ret);
return ret;
}
}
sys_switch_all_to_pll();
*loader_2nd_entry = run_addr;
return 0;
}
int load_rest(void)
{
int retry = 0;
uint64_t monitor_entry = 0;
uint64_t loader_2nd_entry = 0;
// Init sys PLL and switch clocks to PLL
sys_pll_init();
#ifndef ENABLE_BOOT0
#ifdef FSBL_FASTBOOT
mmio_write_32(0x030020B8, 0x00030009); // improve axi clock from 300m to 500m
#endif
retry_from_flash:
for (retry = 0; retry < p_rom_api_get_number_of_retries(); retry++) {
if (load_blcp_2nd(retry) < 0)
continue;
if (load_monitor(retry, &monitor_entry) < 0)
continue;
if (load_loader_2nd(retry, &loader_2nd_entry) < 0)
continue;
break;
}
if (retry >= p_rom_api_get_number_of_retries()) {
switch (p_rom_api_get_boot_src()) {
case BOOT_SRC_UART:
case BOOT_SRC_SD:
case BOOT_SRC_USB:
WARN("DL cancelled. Load flash. (%d).\n", retry);
// Continue to boot from flash if boot from external source
p_rom_api_flash_init();
goto retry_from_flash;
default:
ERROR("Failed to load rest (%d).\n", retry);
panic_handler();
}
}
#ifdef FSBL_FASTBOOT
mmio_write_32(0x030020B8, 0x00050009); // restore axi clock from 500m to 300m
#endif
sync_cache();
console_flush();
// switch_rtc_mode_2nd_stage();
#else
#ifdef ENABLE_FASTBOOT0
mmio_write_32(0x030020B8, 0x00030009);
#endif
if (load_loader_2nd_alios(retry, &loader_2nd_entry) < 0)
return -1;
#ifdef ENABLE_FASTBOOT0
mmio_write_32(0x030020B8, 0x00050009);
#endif
sync_cache();
// switch_rtc_mode_2nd_stage();
#ifdef __riscv
/*
* RISC-V: jump_to_loader_2nd() is empty; jump_to_monitor() calls the
* image directly in M-mode, which is how the loaded image is started.
* AArch64: leave monitor_entry at 0 so jump_to_loader_2nd() drops to
* EL2-NS. jump_to_monitor() would enter the image at secure EL3 with
* BL31 params, and the image loaded here is not a BL31 monitor.
*/
monitor_entry = run_addr;
#endif
#endif
if (monitor_entry) {
NOTICE("Jump to monitor at 0x%lx.\n", monitor_entry);
jump_to_monitor(monitor_entry, loader_2nd_entry);
} else {
NOTICE("Jump to loader_2nd at 0x%lx.\n", loader_2nd_entry);
jump_to_loader_2nd(loader_2nd_entry);
}
return 0;
}