diff options
Diffstat (limited to 'arch/riscv/lib/bootm.c')
-rw-r--r-- | arch/riscv/lib/bootm.c | 87 |
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) { |