forked from riscv-software-src/opensbi
-
Notifications
You must be signed in to change notification settings - Fork 0
A Previous Stage Bootloader Example
Shawn Xu edited this page Aug 13, 2024
·
1 revision
OpenSBI cannot work in XIP mode, so it need a previous stage bootloader to do something it cannot do.
Here is an example using hpm sdk.
CMakeLists.txt:
# Copyright (c) 2024 HPMicro
# SPDX-License-Identifier: BSD-3-Clause
cmake_minimum_required(VERSION 3.13)
find_package(hpm-sdk REQUIRED HINTS $ENV{HPM_SDK_BASE})
project(opensbi_loader)
sdk_app_src(src/loader.c)
sdk_compile_definitions(-DINIT_EXT_RAM_FOR_DATA)
sdk_compile_definitions(-DUSE_NONVECTOR_MODE=1)
generate_ide_projects()
- INIT_EXT_RAM_FOR_DATA needs to be defined to 1 to init the SDRAM
- USE_NONVECTOR_MODE needs to be defined to 1 to avoid sdk using the vector mode which is not supported by OpenSBI
C source
/*
* Copyright (c) 2021 HPMicro
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include <stdio.h>
#include "hpm_debug_console.h"
#include "hpm_pcfg_drv.h"
#include "hpm_clock_drv.h"
#include "hpm_uart_drv.h"
#include "hpm_pllctlv2_drv.h"
#include "pinmux.h"
#define LED_FLASH_PERIOD_IN_MS 300
#define OPENSBI_SRC_ADDR 0x80010000
#define OPENSBI_SIZE 0x18000
#define OPENSBI_EXEC_ADDR 0
#define LINUX_IMAGE_SRC_ADDR 0x80040000
#define LINUX_IMAGE_SIZE_MAX (2 * 1024 * 1024)
#define LINUX_IMAGE_EXEC_ADDR 0x40000000
#define LINUX_DTB_SRC_ADDR 0x80310000
#define LINUX_DTB_SIZE_MAX 0x4000
#define LINUX_DTB_DST_ADDR 0x40300000
void (*open_sbi_entry)(int, int, int);
static void loader_pre_init_clock(void)
{
uint32_t cpu0_freq = clock_get_frequency(clock_cpu0);
if (cpu0_freq == PLLCTL_SOC_PLL_REFCLK_FREQ) {
/* Configure the External OSC ramp-up time: ~9ms */
pllctlv2_xtal_set_rampup_time(HPM_PLLCTLV2, 32UL * 1000UL * 9U);
/* Select clock setting preset1 */
sysctl_clock_set_preset(HPM_SYSCTL, 2);
}
/* Add most Clocks to group 0 */
/* not open uart clock in this API, uart should configure pin function before opening clock */
clock_add_to_group(clock_cpu0, 0);
clock_add_to_group(clock_ahbp, 0);
clock_add_to_group(clock_axic, 0);
clock_add_to_group(clock_axis, 0);
clock_add_to_group(clock_mchtmr0, 0);
clock_add_to_group(clock_femc, 0);
clock_add_to_group(clock_xpi0, 0);
clock_add_to_group(clock_xpi1, 0);
clock_add_to_group(clock_sdp, 0);
clock_add_to_group(clock_xdma, 0);
clock_add_to_group(clock_ram0, 0);
clock_add_to_group(clock_gpio, 0);
clock_add_to_group(clock_mbx0, 0);
clock_add_to_group(clock_hdma, 0);
clock_add_to_group(clock_rng, 0);
/* Connect Group0 to CPU0 */
clock_connect_group_to_cpu(0, 0);
/* Configure CPU to 480MHz, AXI/AHB to 160MHz */
sysctl_config_cpu0_domain_clock(HPM_SYSCTL, clock_source_pll1_clk0, 1, 3, 3);
/* Configure PLL1_CLK0 Post Divider to 1.2 */
pllctlv2_set_postdiv(HPM_PLLCTLV2, 1, 0, 1);
/* Configure PLL1 clock frequencey to 576MHz, the PLL1_CLK0 frequency = 576MHz / 1.2 = 480MHz */
pllctlv2_init_pll_with_freq(HPM_PLLCTLV2, 1, 576000000);
clock_update_core_clock();
/* Configure mchtmr to 24MHz */
clock_set_source_divider(clock_mchtmr0, clk_src_osc24m, 1);
}
static void loader_pre_init_console_clock(void)
{
/* uart needs to configure pin function before enabling clock, otherwise the level change of
uart rx pin when configuring pin function will cause a wrong data to be received.
And a uart rx dma request will be generated by default uart fifo dma trigger level. */
init_uart_pins((UART_Type *) HPM_UART0);
/* Configure the UART clock to 24MHz */
clock_set_source_divider(clock_uart0, clk_src_osc24m, 1U);
clock_add_to_group(clock_uart0, 0);
}
int main(void)
{
pcfg_dcdc_set_voltage(HPM_PCFG, 1100);
loader_pre_init_clock();
loader_pre_init_console_clock();
memcpy((void *)OPENSBI_EXEC_ADDR, (void *)OPENSBI_SRC_ADDR, OPENSBI_SIZE);
memcpy((void *)LINUX_IMAGE_EXEC_ADDR, (void *)LINUX_IMAGE_SRC_ADDR, LINUX_IMAGE_SIZE_MAX);
memcpy((void *)LINUX_DTB_DST_ADDR, (void *)LINUX_DTB_SRC_ADDR, LINUX_DTB_SIZE_MAX);
open_sbi_entry = (void(*)(int, int, int))OPENSBI_EXEC_ADDR;
__asm volatile ("fence iorw, iorw");
__asm volatile ("fence.i");
open_sbi_entry(0, 0, 0);
return 0;
}