[PATCH v2 08/16] LoongArch: CPU assembly routines
Yao Zi
me at ziyao.cc
Wed Jul 1 13:18:00 CEST 2026
From: Jiaxun Yang <jiaxun.yang at flygoat.com>
start.S for initialisation, smp_secondary routine for
a spin-table like interface for secondary cpus.
Signed-off-by: Jiaxun Yang <jiaxun.yang at flygoat.com>
Signed-off-by: Yao Zi <me at ziyao.cc>
---
Changed from v1
- Replace t6, which is volatile across C function boundaries, with s5
to hold relocation offset in start.S
- Fix typo "CLear" in smp_secondary.S
arch/loongarch/cpu/Makefile | 4 +
arch/loongarch/cpu/cpu.c | 27 +++++
arch/loongarch/cpu/smp_secondary.S | 55 ++++++++++
arch/loongarch/cpu/start.S | 170 +++++++++++++++++++++++++++++
4 files changed, 256 insertions(+)
create mode 100644 arch/loongarch/cpu/cpu.c
create mode 100644 arch/loongarch/cpu/smp_secondary.S
create mode 100644 arch/loongarch/cpu/start.S
diff --git a/arch/loongarch/cpu/Makefile b/arch/loongarch/cpu/Makefile
index 3dbed94cc624..d3c38a16d057 100644
--- a/arch/loongarch/cpu/Makefile
+++ b/arch/loongarch/cpu/Makefile
@@ -3,3 +3,7 @@
# Copyright (C) 2024 Jiaxun yang <jiaxun.yang at flygoat.com>
#
+extra-y = start.o
+
+obj-y += cpu.o
+obj-y += smp_secondary.o
diff --git a/arch/loongarch/cpu/cpu.c b/arch/loongarch/cpu/cpu.c
new file mode 100644
index 000000000000..1f03fff964f0
--- /dev/null
+++ b/arch/loongarch/cpu/cpu.c
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018, Bin Meng <bmeng.cn at gmail.com>
+ */
+
+#include <command.h>
+#include <cpu.h>
+#include <cpu_func.h>
+#include <dm.h>
+#include <dm/lists.h>
+#include <event.h>
+#include <hang.h>
+#include <init.h>
+#include <log.h>
+#include <asm/system.h>
+#include <dm/uclass-internal.h>
+#include <linux/bitops.h>
+
+#if !CONFIG_IS_ENABLED(SYSRESET)
+void reset_cpu(void)
+{
+ printf("resetting ...\n");
+
+ printf("reset not supported yet\n");
+ hang();
+}
+#endif
diff --git a/arch/loongarch/cpu/smp_secondary.S b/arch/loongarch/cpu/smp_secondary.S
new file mode 100644
index 000000000000..4ef4b16a3fb6
--- /dev/null
+++ b/arch/loongarch/cpu/smp_secondary.S
@@ -0,0 +1,55 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Loop to run on secondary cores for LoongArch CPU
+ *
+ * Copyright (C) 2024 Jiaxun Yang <jiaxun.yang at flygoat.com>
+ */
+
+#include <linux/linkage.h>
+#include <asm/asm.h>
+#include <asm/loongarch.h>
+#include <asm/arch/entry-init.h>
+
+ENTRY(secondary_core_loop)
+ smp_secondary_setup
+
+ PTR_LI t0, LOONGARCH_IOCSR_MBUF0
+ LONG_IOCSRWR zero, t0
+
+ /* Enable IPI interrupt for wakeup */
+ LONG_LI t0, ECFGF_IPI
+ csrxchg t0, t0, LOONGARCH_CSR_ECFG
+
+ LONG_LI t0, 0xffffffff
+ li.w t1, LOONGARCH_IOCSR_IPI_CLEAR
+ iocsrwr.w t0, t1
+ li.w t1, LOONGARCH_IOCSR_IPI_EN
+ iocsrwr.w t0, t1
+
+ /* t1 for spin table */
+ PTR_LI t1, LOONGARCH_IOCSR_MBUF0
+
+1:
+ /* Query spin table */
+ idle 0
+ nop
+ iocsrrd.w t0, t1
+ beqz t0, 1b
+
+ /* Clear IPI interrupt */
+ PTR_LI t1, LOONGARCH_IOCSR_IPI_STATUS
+ iocsrrd.w t0, t1
+ PTR_LI t1, LOONGARCH_IOCSR_IPI_CLEAR
+ iocsrwr.w t0, t1
+
+ /* Mask all interrupts */
+ LONG_LI t0, ECFG0_IM
+ csrxchg zero, t0, LOONGARCH_CSR_ECFG
+
+ /* Jump to secondary core */
+ PTR_LI t1, LOONGARCH_IOCSR_MBUF0
+ LONG_IOCSRRD t0, t1
+ /* If we ever return, put us back to the loop */
+ la.pcrel ra, secondary_core_loop
+ jirl zero, t0, 0
+END(secondary_core_loop)
diff --git a/arch/loongarch/cpu/start.S b/arch/loongarch/cpu/start.S
new file mode 100644
index 000000000000..57a1a61fc28c
--- /dev/null
+++ b/arch/loongarch/cpu/start.S
@@ -0,0 +1,170 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Startup Code for LoongArch CPU
+ *
+ * Copyright (C) 2024 Jiaxun Yang <jiaxun.yang at flygoat.com>
+ */
+
+#include <asm-offsets.h>
+#include <config.h>
+#include <elf.h>
+#include <system-constants.h>
+#include <asm/addrspace.h>
+#include <asm/asm.h>
+#include <asm/loongarch.h>
+#include <asm/arch/entry-init.h>
+
+#define BOOTCORE_ID 0
+
+.section .text
+.globl _start
+_start:
+ /* Allow arch specific setup code for MCSR stuff */
+ entry_setup
+
+ /* Disable interrupt */
+ LONG_LI t0, CSR_CRMD_IE
+ csrxchg zero, t0, LOONGARCH_CSR_CRMD
+
+ /* Configure reset ebase */
+ la.pcrel t0, exception_entry
+ csrwr t0, LOONGARCH_CSR_EENTRY
+
+ /* Setup direct map window for later use */
+ PTR_LI t0, CSR_DMW0_INIT
+ csrwr t0, LOONGARCH_CSR_DMWIN0
+ PTR_LI t0, CSR_DMW1_INIT
+ csrwr t0, LOONGARCH_CSR_DMWIN1
+
+ /* Branch out for nonboot core */
+ csrrd t0, LOONGARCH_CSR_CPUID
+ andi t0, t0, CSR_CPUID_COREID
+ LONG_LI t1, BOOTCORE_ID
+ bne t1, t0, secondary_core_loop
+
+/*
+ * Set stackpointer in internal/ex RAM to call board_init_f
+ */
+call_board_init_f:
+ PTR_LI t0, (SYS_INIT_SP_ADDR & STACK_ALIGN)
+ move sp, t0 /* save stack pointer */
+/*
+ * Now sp points to the right stack belonging to current CPU.
+ * It's essential before any function call, otherwise, we get data-race.
+ */
+
+call_board_init_f_0:
+ /* find top of reserve space */
+ PTR_LI t1, 1
+ PTR_SLL t1, t1, CONFIG_STACK_SIZE_SHIFT
+ PTR_SUB a0, t0, t1 /* t1 -> size of all CPU stacks */
+ bl board_init_f_alloc_reserve
+
+ /* Set global pointer to u0 ($r21) */
+ move u0, a0
+ bl board_init_f_init_reserve
+
+ /* Probe and enable cache */
+ bl probe_caches
+ bl enable_caches
+
+#ifdef CONFIG_DEBUG_UART
+ bl debug_uart_init
+#endif
+
+ move a0, zero /* a0 <-- boot_flags = 0 */
+ la.pcrel t5, board_init_f
+ jirl ra, t5, 0 /* jump to board_init_f() */
+
+ move sp, s0
+
+/*
+ * void relocate_code(addr_sp, gd, addr_moni)
+ *
+ * This "function" does not return, instead it continues in RAM
+ * after relocating the monitor code.
+ *
+ */
+.globl relocate_code
+relocate_code:
+ move s2, a0 /* save addr_sp */
+ move s3, a1 /* save addr of gd */
+ move s4, a2 /* save addr of destination */
+
+/*
+ *Set up the stack
+ */
+stack_setup:
+ move sp, s2
+ la.pcrel t0, _start
+ PTR_SUB s5, s4, t0 /* s5 <- relocation offset */
+ beq t0, s4, clear_bss /* skip relocation */
+
+ move t1, s4 /* t1 <- scratch for copy_loop */
+ la.pcrel t2, __bss_start /* t2 <- source end address */
+
+copy_loop:
+ LONG_L t5, t0, 0
+ PTR_ADDI t0, t0, LONGSIZE
+ LONG_S t5, t1, 0
+ PTR_ADDI t1, t1, LONGSIZE
+ blt t0, t2, copy_loop
+
+/*
+ * Update dynamic relocations after board_init_f
+ */
+fix_rela_dyn:
+ la.pcrel t1, __rel_dyn_start
+ la.pcrel t2, __rel_dyn_end
+ beq t1, t2, clear_bss
+ PTR_ADD t1, t1, s5 /* t1 <- rela_dyn_start in RAM */
+ PTR_ADD t2, t2, s5 /* t2 <- rela_dyn_end in RAM */
+
+6:
+ PTR_L t5, t1, PTRSIZE /* t5 <-- relocation info:type */
+ PTR_LI t3, R_LARCH_RELATIVE /* reloc type R_LARCH_RELATIVE */
+ bne t5, t3, 8f /* skip non-RELATIVE entries */
+ PTR_L t3, t1, 0
+ PTR_L t5, t1, (PTRSIZE * 2) /* t5 <-- addend */
+ PTR_ADD t5, t5, s5 /* t5 <-- location to fix up in RAM */
+ PTR_ADD t3, t3, s5 /* t3 <-- location to fix up in RAM */
+ PTR_S t5, t3, 0
+8:
+ PTR_ADDI t1, t1, (PTRSIZE * 3)
+ blt t1, t2, 6b
+
+
+ /* Update exception entry */
+ la.pcrel t0, exception_entry
+ PTR_ADD t0, t0, s5
+ csrwr t0, LOONGARCH_CSR_EENTRY
+
+clear_bss:
+ la.pcrel t0, __bss_start /* t0 <- rel __bss_start in FLASH */
+ PTR_ADD t0, t0, s5 /* t0 <- rel __bss_start in RAM */
+ la.pcrel t1, __bss_end /* t1 <- rel __bss_end in FLASH */
+ PTR_ADD t1, t1, s5 /* t1 <- rel __bss_end in RAM */
+
+clbss_l:
+ LONG_S zero, t0, 0 /* clear loop... */
+ PTR_ADDI t0, t0, LONGSIZE
+ blt t0, t1, clbss_l
+
+
+/*
+ * We are done. Do not return, instead branch to second part of board
+ * initialization, now running from RAM.
+ */
+call_board_init_r:
+ bl invalidate_icache_all
+ bl flush_dcache_all
+ la.pcrel t0, board_init_r /* offset of board_init_r() */
+ PTR_ADD t4, t0, s5 /* real address of board_init_r() */
+/*
+ * setup parameters for board_init_r
+ */
+ move a0, s3 /* gd_t */
+ move a1, s4 /* dest_addr */
+ move s0, zero /* fp == NULL */
+ jirl ra, t4, 0 /* jump to board_init_r() */
+
--
2.54.0
More information about the U-Boot
mailing list