aboutsummaryrefslogtreecommitdiff
path: root/arch/riscv/lib/bootm.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/riscv/lib/bootm.c')
-rw-r--r--arch/riscv/lib/bootm.c87
1 files changed, 81 insertions, 6 deletions
diff --git a/arch/riscv/lib/bootm.c b/arch/riscv/lib/bootm.c
index 942a1174..837154d6 100644
--- a/arch/riscv/lib/bootm.c
+++ b/arch/riscv/lib/bootm.c
@@ -14,7 +14,11 @@
#include <opensbi.h>
#include <asm/byteorder.h>
#include <asm/csr.h>
+#include <asm/io.h>
#include <asm/smp.h>
+#include <asm/barrier.h>
+#include <asm/atomic.h>
+#include <asm/arch-thead/light-reset.h>
#include <dm/device.h>
#include <dm/root.h>
#include <u-boot/zlib.h>
@@ -22,6 +26,12 @@
DECLARE_GLOBAL_DATA_PTR;
static struct fw_dynamic_info opensbi_info;
+static atomic_t _harts_count = ATOMIC_INITIALIZER(3);
+static ulong _load_start;
+static ulong _dtb_addr;
+static ulong _dyn_info_addr;
+
+extern void secondary_entry();
__weak void board_quiesce_devices(void)
{
@@ -81,6 +91,58 @@ static void boot_prep_linux(bootm_headers_t *images)
}
}
+void next_stage(void)
+{
+ void (*next_entry)(unsigned long arg0,unsigned long arg1,unsigned long arg2);
+
+ next_entry = (void (*))(_load_start);
+ ulong hartid = csr_read(CSR_MHARTID);
+
+ atomic_sub_return(&_harts_count, 1);
+ /*
+ * set $a0 = hartid
+ * set $a1 = $dtb_addr
+ * set $a2 = $dyn_info_addr
+ */
+ next_entry(hartid, _dtb_addr , _dyn_info_addr);
+}
+
+bool has_reset_sample(ulong dtb_addr)
+{
+ int node_offset;
+ node_offset = fdt_path_offset(dtb_addr, "/soc/reset-sample");
+ if (node_offset < 0) {
+ printf("## fdt has no reset_sample\n");
+ return false;
+ } else {
+ printf("## fdt has reset_sample\n");
+ return true;
+ }
+}
+
+static void reset_sample(void)
+{
+ ulong addr;
+ uint addr_l, addr_h;
+
+ // RESET ADDR
+ addr = (unsigned long)(void *)secondary_entry;
+ addr_h = (uint)(addr >> 32);
+ addr_l = (uint)(addr & 0xFFFFFFFF);
+ // writel(addr_h, (volatile void *)REG_C910_CORE0_RVBA_H);
+ // writel(addr_l, (volatile void *)REG_C910_CORE0_RVBA_L);
+ writel(addr_h, (volatile void *)REG_C910_CORE1_RVBA_H);
+ writel(addr_l, (volatile void *)REG_C910_CORE1_RVBA_L);
+ writel(addr_h, (volatile void *)REG_C910_CORE2_RVBA_H);
+ writel(addr_l, (volatile void *)REG_C910_CORE2_RVBA_L);
+ writel(addr_h, (volatile void *)REG_C910_CORE3_RVBA_H);
+ writel(addr_l, (volatile void *)REG_C910_CORE3_RVBA_L);
+
+ // RESET
+ writel(0x1F, (volatile void *)REG_C910_SWRST);
+ writel(0x1, (volatile void *)REG_PLIC_DELEGATE);
+}
+
static void boot_jump_linux(bootm_headers_t *images, int flag)
{
void (*kernel)(ulong hart, void *dtb, struct fw_dynamic_info *p);
@@ -98,12 +160,25 @@ static void boot_jump_linux(bootm_headers_t *images, int flag)
announce_and_cleanup(fake);
- opensbi_info.magic = FW_DYNAMIC_INFO_MAGIC_VALUE;
- opensbi_info.version = 0x1;
- opensbi_info.next_addr = images->os.start;
- opensbi_info.next_mode = FW_DYNAMIC_INFO_NEXT_MODE_S;
- opensbi_info.options = 0;
- opensbi_info.boot_hart = 0;
+ _load_start = kernel;
+ _dtb_addr = images->ft_addr;
+ _dyn_info_addr = (ulong)&opensbi_info;
+ if (!has_reset_sample(_dtb_addr)) {
+ opensbi_info.magic = FW_DYNAMIC_INFO_MAGIC_VALUE;
+ opensbi_info.version = 0x2;
+ opensbi_info.next_addr = images->os.start;
+ opensbi_info.next_mode = FW_DYNAMIC_INFO_NEXT_MODE_S;
+ opensbi_info.options = 0;
+ opensbi_info.boot_hart = 0;
+ reset_sample();
+ } else {
+ opensbi_info.magic = FW_DYNAMIC_INFO_MAGIC_VALUE;
+ opensbi_info.version = 0x1;
+ opensbi_info.next_addr = images->os.start;
+ opensbi_info.next_mode = FW_DYNAMIC_INFO_NEXT_MODE_S;
+ opensbi_info.options = 0;
+ opensbi_info.boot_hart = 0;
+ }
if (!fake) {
if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len) {