All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 00/16] LoongArch initial support
@ 2026-07-01 11:17 Yao Zi
  2026-07-01 11:17 ` [PATCH v2 01/16] lib: fdtdec: Handle multiple memory nodes Yao Zi
                   ` (18 more replies)
  0 siblings, 19 replies; 56+ messages in thread
From: Yao Zi @ 2026-07-01 11:17 UTC (permalink / raw)
  To: Tom Rini, Jiaxun Yang, Heinrich Schuchardt, Ilias Apalodimas
  Cc: u-boot, Yao Zi

Hi all,

After talking to Jiaxun privately, I decided to take over the series.

So far this series has implemented general support for initializing CPU,
exceptions, kernel booting, CPU and timer drivers, QEMU LoongArch virt
machine support and UEFI standard compliant EFI booting support.

LoongArch had defined 3 ISA variants, LA64, LA32 and LA32R (Reduced,
intended for MCUs and education purpose). This is a little-endian only
architecture. Only LA64 is implemented in this series since the hardware
is more widely available, and I'll work on 32bit support later.

This series had passed checkpatch with exceptions on some false alarms
and headers imported elsewhere. I've tested virtio devices, direct
kernel booting, efistub kernel booting and grub. For loongarch64 CI, I
would continue to work on Jiaxun's another series[1] soon.

Toolchain can be found at [2] or using upstream one, to build

	make qemu-loongarch64_defconfig
	make

To run in QEMU:

	qemu-system-loongarch64 -nographic -machine virt -bios u-boot.bin

TODOs on the architecture & board:
- loongson,ls7a-rtc driver
 - The only device on QEMU board haven't been supported yet
- LoongArch sandbox host support
- TLB enablement
 - This is required for real CPU to utilize caches
- Possibly EFI-APP support for real machine

I have one question regarding the process: I've decided to
coordinate with Jiaxun to maintain the loongarch port, and AFAIK we
would need a custodian tree on U-Boot's GitLab instance in order to run
CI. If this true, what's the process of creating a tree?

Thanks for your time and review!

Link to v1: https://lore.kernel.org/u-boot/20240522-loongarch-v1-0-1407e0b69678@flygoat.com/

[1]: https://lore.kernel.org/u-boot/20240717-docker-image-v1-0-7c7fc6251e7a@flygoat.com/
[2]: https://mirrors.edge.kernel.org/pub/tools/crosstool/files/bin/x86_64/14.2.0/x86_64-gcc-14.2.0-nolibc-loongarch64-linux.tar.gz

Jiaxun Yang (16):
  lib: fdtdec: Handle multiple memory nodes
  linux/io.h: Use map_physmem to implement ioremap
  image: Take entry point as an output of setup_booti
  elf: Define LoongArch bits
  image: Define IH_ARCH_LOONGARCH
  LoongArch: skeleton and headers
  LoongArch: lib: General routines
  LoongArch: CPU assembly routines
  LoongArch: Exception handling
  LoongArch: Boot Image bits
  LoongArch: Generic CPU type
  cpu: Add loongarch_cpu driver
  timer: Add loongarch_timer driver
  board: emulation: Add qemu-loongarch
  efi: LoongArch: Define LoongArch bits everywhere
  efi: LoongArch: Implement everything

 Makefile                                      |    2 +
 arch/Kconfig                                  |   15 +
 arch/arm/lib/image.c                          |    3 +-
 arch/loongarch/Kconfig                        |   49 +
 arch/loongarch/Makefile                       |   19 +
 arch/loongarch/config.mk                      |   27 +
 arch/loongarch/cpu/Makefile                   |    9 +
 arch/loongarch/cpu/cpu.c                      |   27 +
 arch/loongarch/cpu/generic/Kconfig            |   13 +
 arch/loongarch/cpu/generic/Makefile           |    7 +
 arch/loongarch/cpu/generic/cpu.c              |   22 +
 arch/loongarch/cpu/generic/dram.c             |   21 +
 arch/loongarch/cpu/genex.S                    |   21 +
 arch/loongarch/cpu/smp_secondary.S            |   55 +
 arch/loongarch/cpu/start.S                    |  170 ++
 arch/loongarch/cpu/u-boot.lds                 |   85 +
 arch/loongarch/dts/Makefile                   |    6 +
 arch/loongarch/dts/qemu-loongarch64.dts       |    9 +
 arch/loongarch/include/asm/acpi_table.h       |    8 +
 arch/loongarch/include/asm/addrspace.h        |   86 +
 .../include/asm/arch-generic/entry-init.h     |   15 +
 arch/loongarch/include/asm/asm.h              |  186 +++
 arch/loongarch/include/asm/atomic.h           |   12 +
 arch/loongarch/include/asm/barrier.h          |  138 ++
 arch/loongarch/include/asm/bitops.h           |  156 ++
 arch/loongarch/include/asm/byteorder.h        |   22 +
 arch/loongarch/include/asm/cache.h            |   34 +
 arch/loongarch/include/asm/config.h           |   11 +
 arch/loongarch/include/asm/cpu.h              |  123 ++
 arch/loongarch/include/asm/dma-mapping.h      |   27 +
 arch/loongarch/include/asm/global_data.h      |   50 +
 arch/loongarch/include/asm/gpio.h             |   11 +
 arch/loongarch/include/asm/io.h               |  399 +++++
 arch/loongarch/include/asm/linkage.h          |   11 +
 arch/loongarch/include/asm/loongarch.h        | 1467 +++++++++++++++++
 arch/loongarch/include/asm/posix_types.h      |   87 +
 arch/loongarch/include/asm/processor.h        |   11 +
 arch/loongarch/include/asm/ptrace.h           |   33 +
 arch/loongarch/include/asm/regdef.h           |   42 +
 arch/loongarch/include/asm/sections.h         |    8 +
 arch/loongarch/include/asm/setjmp.h           |   25 +
 arch/loongarch/include/asm/spl.h              |   11 +
 arch/loongarch/include/asm/stackframe.h       |  175 ++
 arch/loongarch/include/asm/string.h           |   11 +
 arch/loongarch/include/asm/system.h           |   74 +
 arch/loongarch/include/asm/types.h            |   37 +
 arch/loongarch/include/asm/u-boot-loongarch.h |   23 +
 arch/loongarch/include/asm/u-boot.h           |   30 +
 arch/loongarch/include/asm/unaligned.h        |   11 +
 arch/loongarch/lib/Makefile                   |   26 +
 arch/loongarch/lib/asm-offsets.c              |   66 +
 arch/loongarch/lib/boot.c                     |   14 +
 arch/loongarch/lib/bootm.c                    |  163 ++
 arch/loongarch/lib/cache.c                    |  213 +++
 arch/loongarch/lib/crt0_loongarch_efi.S       |  182 ++
 arch/loongarch/lib/elf_loongarch_efi.lds      |   76 +
 arch/loongarch/lib/image.c                    |   66 +
 arch/loongarch/lib/interrupts.c               |  189 +++
 arch/loongarch/lib/reloc_loongarch_efi.c      |  107 ++
 arch/loongarch/lib/reset.c                    |   14 +
 arch/loongarch/lib/setjmp.S                   |   52 +
 arch/riscv/lib/image.c                        |    4 +-
 arch/sandbox/lib/bootm.c                      |    2 +-
 board/emulation/qemu-loongarch/Kconfig        |   68 +
 board/emulation/qemu-loongarch/MAINTAINERS    |    7 +
 board/emulation/qemu-loongarch/Makefile       |    6 +
 .../emulation/qemu-loongarch/qemu-loongarch.c |   67 +
 .../qemu-loongarch/qemu-loongarch.env         |    6 +
 boot/bootm.c                                  |    5 +-
 boot/image.c                                  |    1 +
 cmd/Kconfig                                   |    2 +-
 cmd/booti.c                                   |    5 +-
 common/spl/spl.c                              |    9 +-
 configs/qemu-loongarch64_defconfig            |   36 +
 drivers/cpu/Kconfig                           |    6 +
 drivers/cpu/Makefile                          |    1 +
 drivers/cpu/loongarch_cpu.c                   |  148 ++
 drivers/timer/Kconfig                         |    8 +
 drivers/timer/Makefile                        |    1 +
 drivers/timer/loongarch_timer.c               |  112 ++
 include/asm-generic/global_data.h             |    2 +-
 include/asm-generic/pe.h                      |    2 +
 include/config_distro_bootcmd.h               |    5 +
 include/configs/qemu-loongarch.h              |   13 +
 include/elf.h                                 |    9 +-
 include/host_arch.h                           |    2 +
 include/image.h                               |    4 +-
 include/linux/io.h                            |    3 +-
 include/pe.h                                  |    1 +
 lib/efi_loader/Kconfig                        |    2 +-
 lib/efi_loader/efi_helper.c                   |    7 +
 lib/efi_loader/efi_image_loader.c             |   33 +
 lib/efi_loader/efi_runtime.c                  |    4 +
 .../efi_selftest_miniapp_exception.c          |    3 +
 lib/fdtdec.c                                  |  129 +-
 95 files changed, 5704 insertions(+), 71 deletions(-)
 create mode 100644 arch/loongarch/Kconfig
 create mode 100644 arch/loongarch/Makefile
 create mode 100644 arch/loongarch/config.mk
 create mode 100644 arch/loongarch/cpu/Makefile
 create mode 100644 arch/loongarch/cpu/cpu.c
 create mode 100644 arch/loongarch/cpu/generic/Kconfig
 create mode 100644 arch/loongarch/cpu/generic/Makefile
 create mode 100644 arch/loongarch/cpu/generic/cpu.c
 create mode 100644 arch/loongarch/cpu/generic/dram.c
 create mode 100644 arch/loongarch/cpu/genex.S
 create mode 100644 arch/loongarch/cpu/smp_secondary.S
 create mode 100644 arch/loongarch/cpu/start.S
 create mode 100644 arch/loongarch/cpu/u-boot.lds
 create mode 100644 arch/loongarch/dts/Makefile
 create mode 100644 arch/loongarch/dts/qemu-loongarch64.dts
 create mode 100644 arch/loongarch/include/asm/acpi_table.h
 create mode 100644 arch/loongarch/include/asm/addrspace.h
 create mode 100644 arch/loongarch/include/asm/arch-generic/entry-init.h
 create mode 100644 arch/loongarch/include/asm/asm.h
 create mode 100644 arch/loongarch/include/asm/atomic.h
 create mode 100644 arch/loongarch/include/asm/barrier.h
 create mode 100644 arch/loongarch/include/asm/bitops.h
 create mode 100644 arch/loongarch/include/asm/byteorder.h
 create mode 100644 arch/loongarch/include/asm/cache.h
 create mode 100644 arch/loongarch/include/asm/config.h
 create mode 100644 arch/loongarch/include/asm/cpu.h
 create mode 100644 arch/loongarch/include/asm/dma-mapping.h
 create mode 100644 arch/loongarch/include/asm/global_data.h
 create mode 100644 arch/loongarch/include/asm/gpio.h
 create mode 100644 arch/loongarch/include/asm/io.h
 create mode 100644 arch/loongarch/include/asm/linkage.h
 create mode 100644 arch/loongarch/include/asm/loongarch.h
 create mode 100644 arch/loongarch/include/asm/posix_types.h
 create mode 100644 arch/loongarch/include/asm/processor.h
 create mode 100644 arch/loongarch/include/asm/ptrace.h
 create mode 100644 arch/loongarch/include/asm/regdef.h
 create mode 100644 arch/loongarch/include/asm/sections.h
 create mode 100644 arch/loongarch/include/asm/setjmp.h
 create mode 100644 arch/loongarch/include/asm/spl.h
 create mode 100644 arch/loongarch/include/asm/stackframe.h
 create mode 100644 arch/loongarch/include/asm/string.h
 create mode 100644 arch/loongarch/include/asm/system.h
 create mode 100644 arch/loongarch/include/asm/types.h
 create mode 100644 arch/loongarch/include/asm/u-boot-loongarch.h
 create mode 100644 arch/loongarch/include/asm/u-boot.h
 create mode 100644 arch/loongarch/include/asm/unaligned.h
 create mode 100644 arch/loongarch/lib/Makefile
 create mode 100644 arch/loongarch/lib/asm-offsets.c
 create mode 100644 arch/loongarch/lib/boot.c
 create mode 100644 arch/loongarch/lib/bootm.c
 create mode 100644 arch/loongarch/lib/cache.c
 create mode 100644 arch/loongarch/lib/crt0_loongarch_efi.S
 create mode 100644 arch/loongarch/lib/elf_loongarch_efi.lds
 create mode 100644 arch/loongarch/lib/image.c
 create mode 100644 arch/loongarch/lib/interrupts.c
 create mode 100644 arch/loongarch/lib/reloc_loongarch_efi.c
 create mode 100644 arch/loongarch/lib/reset.c
 create mode 100644 arch/loongarch/lib/setjmp.S
 create mode 100644 board/emulation/qemu-loongarch/Kconfig
 create mode 100644 board/emulation/qemu-loongarch/MAINTAINERS
 create mode 100644 board/emulation/qemu-loongarch/Makefile
 create mode 100644 board/emulation/qemu-loongarch/qemu-loongarch.c
 create mode 100644 board/emulation/qemu-loongarch/qemu-loongarch.env
 create mode 100644 configs/qemu-loongarch64_defconfig
 create mode 100644 drivers/cpu/loongarch_cpu.c
 create mode 100644 drivers/timer/loongarch_timer.c
 create mode 100644 include/configs/qemu-loongarch.h


base-commit: 0d8e33717d7e5b2a4034cc88f18bf233f77801e7
-- 
2.54.0


^ permalink raw reply	[flat|nested] 56+ messages in thread

* [PATCH v2 01/16] lib: fdtdec: Handle multiple memory nodes
  2026-07-01 11:17 [PATCH v2 00/16] LoongArch initial support Yao Zi
@ 2026-07-01 11:17 ` Yao Zi
  2026-07-02 10:22   ` Simon Glass
  2026-07-01 11:17 ` [PATCH v2 02/16] linux/io.h: Use map_physmem to implement ioremap Yao Zi
                   ` (17 subsequent siblings)
  18 siblings, 1 reply; 56+ messages in thread
From: Yao Zi @ 2026-07-01 11:17 UTC (permalink / raw)
  To: Tom Rini, Jiaxun Yang, Heinrich Schuchardt, Ilias Apalodimas
  Cc: u-boot, Yao Zi

From: Jiaxun Yang <jiaxun.yang@flygoat.com>

Current code only tries to fetch the first memory node found in
fdt tree and determine memory banks from multiple reg properties.

Specification allows multiple memory nodes in devicetree, rework
fdtdec_setup_mem_size_base_lowest and fdtdec_setup_memory_banksize
to iterate over all memory nodes.

Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
Signed-off-by: Yao Zi <me@ziyao.cc>
---

Hi Simon,

It's hard to add unit tests for these two functions since they operate
on global states (gd), so I don't do so. Is it acceptable, or is there
a better way to do this?

Changed from v1
- Reword commit message to reflect the fact that dtspec allows multiple
  memory nodes
- Replace sort_memory_banks() with qsort()
- Do not use CONFIG_VAL when referencing NR_DRAM_BANKS to avoid breaking
  SPL build
- print gd->ram_size with %pap instead of %lx, drop unnecessary cast for
  gd->ram_base in fdtdec_setup_size_base_lowest()
- Style improvements

 include/asm-generic/global_data.h |   2 +-
 lib/fdtdec.c                      | 129 +++++++++++++++++-------------
 2 files changed, 76 insertions(+), 55 deletions(-)

diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h
index ad7ebb1bbc95..a4df897543a8 100644
--- a/include/asm-generic/global_data.h
+++ b/include/asm-generic/global_data.h
@@ -460,7 +460,7 @@ struct global_data {
 	/**
 	 * @dram: array describing DRAM banks (start address and size for each bank)
 	 */
-	struct {			/* RAM configuration */
+	struct dram_bank {		/* RAM configuration */
 		phys_addr_t start;
 		phys_size_t size;
 	} dram[CONFIG_NR_DRAM_BANKS];
diff --git a/lib/fdtdec.c b/lib/fdtdec.c
index b91e067106dd..33fd7359f2eb 100644
--- a/lib/fdtdec.c
+++ b/lib/fdtdec.c
@@ -36,6 +36,7 @@
 #include <linux/lzo.h>
 #include <linux/ioport.h>
 #include <asm/global_data.h>
+#include <sort.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -1115,90 +1116,110 @@ ofnode fdtdec_get_next_memory_node(ofnode mem)
 	return get_next_memory_node(mem);
 }
 
+static int cmp_memory_bank(const void *a, const void *b)
+{
+	const struct dram_bank *a1 = a, *b1 = b;
+
+	return a1->start > b1->start ? 1 :
+	       a1->start < b1->start ? -1 : 0;
+}
+
 int fdtdec_setup_memory_banksize(void)
 {
-	int bank, ret, reg = 0;
-	struct resource res;
+	int bank = 0;
 	ofnode mem = ofnode_null();
 
-	mem = get_next_memory_node(mem);
-	if (!ofnode_valid(mem)) {
-		debug("%s: Missing /memory node\n", __func__);
-		return -EINVAL;
-	}
+	while (true) {
+		struct resource res;
+		int reg = 0;
 
-	for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; bank++) {
-		ret = ofnode_read_resource(mem, reg++, &res);
-		if (ret < 0) {
-			reg = 0;
-			mem = get_next_memory_node(mem);
-			if (!ofnode_valid(mem))
-				break;
+		mem = get_next_memory_node(mem);
+		if (!ofnode_valid(mem))
+			break;
+
+		while (true) {
+			int ret = ofnode_read_resource(mem, reg, &res);
 
-			ret = ofnode_read_resource(mem, reg++, &res);
 			if (ret < 0)
 				break;
-		}
 
-		if (ret != 0)
-			return -EINVAL;
+			if (bank >= CONFIG_NR_DRAM_BANKS)
+				goto too_may_memory_banks;
 
-		gd->dram[bank].start = (phys_addr_t)res.start;
-		gd->dram[bank].size =
-			(phys_size_t)(res.end - res.start + 1);
+			gd->dram[bank].start = res.start;
+			gd->dram[bank].size =
+					(phys_size_t)(res.end - res.start + 1);
 
-		debug("%s: DRAM Bank #%d: start = %pap, size = %pap\n",
-		      __func__, bank,
-		      &gd->dram[bank].start,
-		      &gd->dram[bank].size);
+			log_debug("%s: DRAM Bank #%d %s.%d: start = 0x%llx, size = 0x%llx\n",
+				  __func__, bank, ofnode_get_name(mem), reg,
+				 (unsigned long long)gd->dram[bank].start,
+				 (unsigned long long)gd->dram[bank].size);
+			reg++;
+			bank++;
+		}
+	}
+
+	if (!bank) {
+		log_warning("%s: Missing /memory node\n", __func__);
+		return -EINVAL;
 	}
 
+	qsort(gd->dram, bank, sizeof(gd->dram[0]), cmp_memory_bank);
+
 	return 0;
+
+too_may_memory_banks:
+	log_warning("%s: Too many memory banks\n", __func__);
+	return -EINVAL;
 }
 
 int fdtdec_setup_mem_size_base_lowest(void)
 {
-	int bank, ret, reg = 0;
-	struct resource res;
-	unsigned long base;
-	phys_size_t size;
+	int bank = 0;
 	ofnode mem = ofnode_null();
+	__maybe_unused const char *final_name;
+	__maybe_unused int final_reg;
 
-	gd->ram_base = (unsigned long)~0;
+	gd->ram_base = ULONG_MAX;
 
-	mem = get_next_memory_node(mem);
-	if (!ofnode_valid(mem)) {
-		debug("%s: Missing /memory node\n", __func__);
-		return -EINVAL;
-	}
+	while (true) {
+		struct resource res;
+		phys_size_t base, size;
+		int reg = 0;
 
-	for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; bank++) {
-		ret = ofnode_read_resource(mem, reg++, &res);
-		if (ret < 0) {
-			reg = 0;
-			mem = get_next_memory_node(mem);
-			if (!ofnode_valid(mem))
-				break;
+		mem = get_next_memory_node(mem);
+		if (!ofnode_valid(mem))
+			break;
+
+		while (true) {
+			int ret = ofnode_read_resource(mem, reg, &res);
 
-			ret = ofnode_read_resource(mem, reg++, &res);
 			if (ret < 0)
 				break;
-		}
 
-		if (ret != 0)
-			return -EINVAL;
-
-		base = (unsigned long)res.start;
-		size = (phys_size_t)(res.end - res.start + 1);
+			base = res.start;
+			size = res.end - res.start + 1;
+			if (gd->ram_base > base && size) {
+				gd->ram_base = base;
+				gd->ram_size = size;
+				final_name = ofnode_get_name(mem);
+				final_reg = reg;
+			}
 
-		if (gd->ram_base > base && size) {
-			gd->ram_base = base;
-			gd->ram_size = size;
-			debug("%s: Initial DRAM base %lx size %lx\n",
-			      __func__, base, (unsigned long)size);
+			reg++;
+			bank++;
 		}
 	}
 
+	if (!bank) {
+		log_warning("%s: Missing /memory node\n", __func__);
+		return -EINVAL;
+	}
+
+	log_debug("%s: Initial DRAM %s.%d: base %lx size %pap\n",
+		  __func__, final_name, final_reg,
+		  gd->ram_base, &gd->ram_size);
+
 	return 0;
 }
 
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH v2 02/16] linux/io.h: Use map_physmem to implement ioremap
  2026-07-01 11:17 [PATCH v2 00/16] LoongArch initial support Yao Zi
  2026-07-01 11:17 ` [PATCH v2 01/16] lib: fdtdec: Handle multiple memory nodes Yao Zi
@ 2026-07-01 11:17 ` Yao Zi
  2026-07-02 10:21   ` Simon Glass
  2026-07-01 11:17 ` [PATCH v2 03/16] image: Take entry point as an output of setup_booti Yao Zi
                   ` (16 subsequent siblings)
  18 siblings, 1 reply; 56+ messages in thread
From: Yao Zi @ 2026-07-01 11:17 UTC (permalink / raw)
  To: Tom Rini, Jiaxun Yang, Heinrich Schuchardt, Ilias Apalodimas
  Cc: u-boot, Yao Zi

From: Jiaxun Yang <jiaxun.yang@flygoat.com>

ioremap API is here to be compatible with Linux drivers,
to maintain compatibility we need to ensure we are using
the same way to determine virtual address for IO devices
from physical address.

map_physmem is U-Boot's standard way for doing the trick,
we should follow that. For architectures VA == PA it has
no impact, for MIPS it has it's own ioremap implementation
in asm/io.h anyway.

Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
Signed-off-by: Yao Zi <me@ziyao.cc>
---

(No changes since v1)

 include/linux/io.h | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/include/linux/io.h b/include/linux/io.h
index 79847886be95..ada6525a1c6a 100644
--- a/include/linux/io.h
+++ b/include/linux/io.h
@@ -59,11 +59,12 @@ static inline void iowrite64(u64 value, volatile void __iomem *addr)
 static inline void __iomem *ioremap(resource_size_t offset,
 				    resource_size_t size)
 {
-	return (void __iomem *)(unsigned long)offset;
+	return (void __iomem *)map_physmem(offset, size, MAP_NOCACHE);
 }
 
 static inline void iounmap(void __iomem *addr)
 {
+	return unmap_physmem(addr, MAP_NOCACHE);
 }
 #endif
 
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH v2 03/16] image: Take entry point as an output of setup_booti
  2026-07-01 11:17 [PATCH v2 00/16] LoongArch initial support Yao Zi
  2026-07-01 11:17 ` [PATCH v2 01/16] lib: fdtdec: Handle multiple memory nodes Yao Zi
  2026-07-01 11:17 ` [PATCH v2 02/16] linux/io.h: Use map_physmem to implement ioremap Yao Zi
@ 2026-07-01 11:17 ` Yao Zi
  2026-07-01 17:39   ` Tom Rini
  2026-07-02  9:46   ` Simon Glass
  2026-07-01 11:17 ` [PATCH v2 04/16] elf: Define LoongArch bits Yao Zi
                   ` (15 subsequent siblings)
  18 siblings, 2 replies; 56+ messages in thread
From: Yao Zi @ 2026-07-01 11:17 UTC (permalink / raw)
  To: Tom Rini, Jiaxun Yang, Heinrich Schuchardt, Ilias Apalodimas
  Cc: u-boot, Yao Zi

From: Jiaxun Yang <jiaxun.yang@flygoat.com>

For LoongArch the start of the image is not the entry
point to the image.

We refactor the code base to allow entry point to be
supplied by setup_booti.

Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
Signed-off-by: Yao Zi <me@ziyao.cc>
---

Changed from v1
- Correct type of "entry" argument for RISC-V and sandbox

 arch/arm/lib/image.c     | 3 ++-
 arch/riscv/lib/image.c   | 4 +++-
 arch/sandbox/lib/bootm.c | 2 +-
 boot/bootm.c             | 5 +++--
 cmd/booti.c              | 5 +++--
 common/spl/spl.c         | 9 +++++----
 include/image.h          | 3 ++-
 7 files changed, 19 insertions(+), 12 deletions(-)

diff --git a/arch/arm/lib/image.c b/arch/arm/lib/image.c
index 2268661de93a..62c28b8310a5 100644
--- a/arch/arm/lib/image.c
+++ b/arch/arm/lib/image.c
@@ -29,7 +29,7 @@ struct Image_header {
 };
 
 int booti_setup(ulong image, ulong *relocated_addr, ulong *size,
-		bool force_reloc)
+		ulong *entry, bool force_reloc)
 {
 	struct Image_header *ih;
 	uint64_t dst;
@@ -72,6 +72,7 @@ int booti_setup(ulong image, ulong *relocated_addr, ulong *size,
 		dst = gd->dram[0].start;
 
 	*relocated_addr = ALIGN(dst, SZ_2M) + text_offset;
+	*entry = *relocated_addr;
 
 	unmap_sysmem(ih);
 
diff --git a/arch/riscv/lib/image.c b/arch/riscv/lib/image.c
index a82f48e9a505..300be365ddfd 100644
--- a/arch/riscv/lib/image.c
+++ b/arch/riscv/lib/image.c
@@ -33,7 +33,7 @@ struct linux_image_h {
 };
 
 int booti_setup(ulong image, ulong *relocated_addr, ulong *size,
-		bool force_reloc)
+		ulong *entry, bool force_reloc)
 {
 	struct linux_image_h *lhdr;
 
@@ -56,6 +56,8 @@ int booti_setup(ulong image, ulong *relocated_addr, ulong *size,
 		*relocated_addr = image;
 	}
 
+	*entry = *relocated_addr;
+
 	unmap_sysmem(lhdr);
 
 	return 0;
diff --git a/arch/sandbox/lib/bootm.c b/arch/sandbox/lib/bootm.c
index 7a5f6f7d36ed..1a41c7c2735b 100644
--- a/arch/sandbox/lib/bootm.c
+++ b/arch/sandbox/lib/bootm.c
@@ -84,7 +84,7 @@ int do_bootm_linux(int flag, struct bootm_info *bmi)
 
 /* used for testing 'booti' command */
 int booti_setup(ulong image, ulong *relocated_addr, ulong *size,
-		bool force_reloc)
+		ulong *entry, bool force_reloc)
 {
 	log_err("Booting is not supported on the sandbox.\n");
 
diff --git a/boot/bootm.c b/boot/bootm.c
index 4c260a5f5ced..50d18cb2c294 100644
--- a/boot/bootm.c
+++ b/boot/bootm.c
@@ -693,9 +693,10 @@ static int bootm_load_os(struct bootm_headers *images, int boot_progress)
 	    images->os.os == IH_OS_LINUX) {
 		ulong relocated_addr;
 		ulong image_size;
+		ulong entry;
 		int ret;
 
-		ret = booti_setup(load, &relocated_addr, &image_size, false);
+		ret = booti_setup(load, &relocated_addr, &image_size, &entry, false);
 		if (ret) {
 			printf("Failed to prep arm64 kernel (err=%d)\n", ret);
 			return BOOTM_ERR_RESET;
@@ -709,7 +710,7 @@ static int bootm_load_os(struct bootm_headers *images, int boot_progress)
 			memmove((void *)relocated_addr, load_buf, image_size);
 		}
 
-		images->ep = relocated_addr;
+		images->ep = entry;
 		images->os.start = relocated_addr;
 		images->os.end = relocated_addr + image_size;
 	}
diff --git a/cmd/booti.c b/cmd/booti.c
index e6f67d6e1368..24c55ff92a27 100644
--- a/cmd/booti.c
+++ b/cmd/booti.c
@@ -27,6 +27,7 @@ static int booti_start(struct bootm_info *bmi)
 	ulong ld;
 	ulong relocated_addr;
 	ulong image_size;
+	ulong entry;
 	uint8_t *temp;
 	ulong dest;
 	ulong dest_end;
@@ -74,7 +75,7 @@ static int booti_start(struct bootm_info *bmi)
 	}
 	unmap_sysmem((void *)ld);
 
-	ret = booti_setup(ld, &relocated_addr, &image_size, false);
+	ret = booti_setup(ld, &relocated_addr, &image_size, &entry, false);
 	if (ret)
 		return 1;
 
@@ -85,7 +86,7 @@ static int booti_start(struct bootm_info *bmi)
 		memmove((void *)relocated_addr, (void *)ld, image_size);
 	}
 
-	images->ep = relocated_addr;
+	images->ep = entry;
 	images->os.start = relocated_addr;
 	images->os.end = relocated_addr + image_size;
 
diff --git a/common/spl/spl.c b/common/spl/spl.c
index 722b18c98edc..1d32b0a5b7fd 100644
--- a/common/spl/spl.c
+++ b/common/spl/spl.c
@@ -114,7 +114,8 @@ int __weak bootz_setup(ulong image, ulong *start, ulong *end)
 	 return 1;
 }
 
-int __weak booti_setup(ulong image, ulong *relocated_addr, ulong *size, bool force_reloc)
+int __weak booti_setup(ulong image, ulong *relocated_addr, ulong *size,
+		       ulong *entry, bool force_reloc)
 {
 	 return 1;
 }
@@ -341,13 +342,13 @@ int spl_parse_image_header(struct spl_image_info *spl_image,
 	}
 
 	if (IS_ENABLED(CONFIG_SPL_OS_BOOT) && IS_ENABLED(CONFIG_SPL_BOOTI)) {
-		ulong start, size;
+		ulong start, size, entry;
 
-		if (!booti_setup((ulong)header, &start, &size, 0)) {
+		if (!booti_setup((ulong)header, &start, &size, &entry, 0)) {
 			spl_image->name = "Linux";
 			spl_image->os = IH_OS_LINUX;
 			spl_image->load_addr = start;
-			spl_image->entry_point = start;
+			spl_image->entry_point = entry;
 			spl_image->size = size;
 			debug(PHASE_PROMPT
 			      "payload Image, load addr: 0x%lx size: %d\n",
diff --git a/include/image.h b/include/image.h
index 9c8a746d576e..97f66b9045bd 100644
--- a/include/image.h
+++ b/include/image.h
@@ -1131,11 +1131,12 @@ int bootz_setup(ulong image, ulong *start, ulong *end);
  * @image: Address of image
  * @start: Returns start address of image
  * @size : Returns size image
+ * @entry: Returns entry point of image
  * @force_reloc: Ignore image->ep field, always place image to RAM start
  * Return: 0 if OK, 1 if the image was not recognised
  */
 int booti_setup(ulong image, ulong *relocated_addr, ulong *size,
-		bool force_reloc);
+		ulong *entry, bool force_reloc);
 
 /*******************************************************************/
 /* New uImage format specific code (prefixed with fit_) */
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH v2 04/16] elf: Define LoongArch bits
  2026-07-01 11:17 [PATCH v2 00/16] LoongArch initial support Yao Zi
                   ` (2 preceding siblings ...)
  2026-07-01 11:17 ` [PATCH v2 03/16] image: Take entry point as an output of setup_booti Yao Zi
@ 2026-07-01 11:17 ` Yao Zi
  2026-07-02 10:24   ` Simon Glass
  2026-07-01 11:17 ` [PATCH v2 05/16] image: Define IH_ARCH_LOONGARCH Yao Zi
                   ` (14 subsequent siblings)
  18 siblings, 1 reply; 56+ messages in thread
From: Yao Zi @ 2026-07-01 11:17 UTC (permalink / raw)
  To: Tom Rini, Jiaxun Yang, Heinrich Schuchardt, Ilias Apalodimas
  Cc: u-boot, Yao Zi

From: Jiaxun Yang <jiaxun.yang@flygoat.com>

They all come from glibc's elf.h

Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
Reviewed-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
Signed-off-by: Yao Zi <me@ziyao.cc>
---

Changed from v1
- Re-title to "elf: Define LoongArch bits" (with the semicolon)
- No function changes involved

 include/elf.h | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/include/elf.h b/include/elf.h
index b88e6cf4032b..b69b1adc404e 100644
--- a/include/elf.h
+++ b/include/elf.h
@@ -225,7 +225,8 @@ typedef struct {
 #define EM_MN10300	89		/* Matsushita MN10200 */
 #define EM_MN10200	90		/* Matsushita MN10200 */
 #define EM_PJ		91		/* picoJava */
-#define EM_NUM		92		/* number of machine types */
+#define EM_LOONGARCH	258	/* LoongArch */
+
 
 /* Version */
 #define EV_NONE		0		/* Invalid */
@@ -705,6 +706,12 @@ unsigned long elf_hash(const unsigned char *name);
 #define R_RISCV_64		2
 #define R_RISCV_RELATIVE	3
 
+/* LoongArch Relocations */
+#define R_LARCH_NONE				0
+#define R_LARCH_32				1
+#define R_LARCH_64				2
+#define R_LARCH_RELATIVE			3
+
 #ifndef __ASSEMBLY__
 unsigned long bootelf_exec(ulong (*entry)(int, char * const[]),
 			   int argc, char *const argv[]);
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH v2 05/16] image: Define IH_ARCH_LOONGARCH
  2026-07-01 11:17 [PATCH v2 00/16] LoongArch initial support Yao Zi
                   ` (3 preceding siblings ...)
  2026-07-01 11:17 ` [PATCH v2 04/16] elf: Define LoongArch bits Yao Zi
@ 2026-07-01 11:17 ` Yao Zi
  2026-07-02  9:44   ` Simon Glass
  2026-07-01 11:17 ` [PATCH v2 06/16] LoongArch: skeleton and headers Yao Zi
                   ` (13 subsequent siblings)
  18 siblings, 1 reply; 56+ messages in thread
From: Yao Zi @ 2026-07-01 11:17 UTC (permalink / raw)
  To: Tom Rini, Jiaxun Yang, Heinrich Schuchardt, Ilias Apalodimas
  Cc: u-boot, Yao Zi

From: Jiaxun Yang <jiaxun.yang@flygoat.com>

Allocate the next value to IH_ARCH_LOONGARCH.

Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
Reviewed-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
Signed-off-by: Yao Zi <me@ziyao.cc>
---

(No functional changes since v1)

 boot/image.c    | 1 +
 include/image.h | 1 +
 2 files changed, 2 insertions(+)

diff --git a/boot/image.c b/boot/image.c
index 185d52ba492f..fddbf01e04f2 100644
--- a/boot/image.c
+++ b/boot/image.c
@@ -86,6 +86,7 @@ static const table_entry_t uimage_arch[] = {
 	{	IH_ARCH_X86_64,		"x86_64",	"AMD x86_64",	},
 	{	IH_ARCH_XTENSA,		"xtensa",	"Xtensa",	},
 	{	IH_ARCH_RISCV,		"riscv",	"RISC-V",	},
+	{	IH_ARCH_LOONGARCH,	"loongarch",	"LoongArch",	},
 	{	-1,			"",		"",		},
 };
 
diff --git a/include/image.h b/include/image.h
index 97f66b9045bd..157e6655fe41 100644
--- a/include/image.h
+++ b/include/image.h
@@ -139,6 +139,7 @@ enum {
 	IH_ARCH_X86_64,			/* AMD x86_64, Intel and Via */
 	IH_ARCH_XTENSA,			/* Xtensa	*/
 	IH_ARCH_RISCV,			/* RISC-V */
+	IH_ARCH_LOONGARCH,		/* Loongson LoongArch */
 
 	IH_ARCH_COUNT,
 };
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH v2 06/16] LoongArch: skeleton and headers
  2026-07-01 11:17 [PATCH v2 00/16] LoongArch initial support Yao Zi
                   ` (4 preceding siblings ...)
  2026-07-01 11:17 ` [PATCH v2 05/16] image: Define IH_ARCH_LOONGARCH Yao Zi
@ 2026-07-01 11:17 ` Yao Zi
  2026-07-01 17:47   ` Tom Rini
  2026-07-02 10:28   ` Simon Glass
  2026-07-01 11:17 ` [PATCH v2 07/16] LoongArch: lib: General routines Yao Zi
                   ` (12 subsequent siblings)
  18 siblings, 2 replies; 56+ messages in thread
From: Yao Zi @ 2026-07-01 11:17 UTC (permalink / raw)
  To: Tom Rini, Jiaxun Yang, Heinrich Schuchardt, Ilias Apalodimas
  Cc: u-boot, Yao Zi

From: Jiaxun Yang <jiaxun.yang@flygoat.com>

Commit for directories, Kconfig, Makefile and headers

Some of them are copied from linux, some of them are derived
from other architectures, the rest are wriiten on my own.

Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
Signed-off-by: Yao Zi <me@ziyao.cc>
---

Hi Heinrich,

I kept the naming of CONFIG_ARCH_LA64 (instead of using the full name
ARCH_LOONGARCH64) since it's shorter, and we already have similar
CONFIG_ARCH_RV64I, and etc. in U-Boot. Is is okay for you?

Changed from v1
- Remove the redundant dtbs target from arch/loongarch/dts/Makefile
- Add loongarch64 definitions for HOST_ARCH
- Whitespace clean-up

 Makefile                                      |    2 +
 arch/Kconfig                                  |   15 +
 arch/loongarch/Kconfig                        |   40 +
 arch/loongarch/Makefile                       |   19 +
 arch/loongarch/config.mk                      |   23 +
 arch/loongarch/cpu/Makefile                   |    5 +
 arch/loongarch/cpu/u-boot.lds                 |   85 +
 arch/loongarch/dts/Makefile                   |    6 +
 arch/loongarch/include/asm/acpi_table.h       |    8 +
 arch/loongarch/include/asm/addrspace.h        |   86 +
 .../include/asm/arch-generic/entry-init.h     |   15 +
 arch/loongarch/include/asm/asm.h              |  186 +++
 arch/loongarch/include/asm/atomic.h           |   12 +
 arch/loongarch/include/asm/barrier.h          |  138 ++
 arch/loongarch/include/asm/bitops.h           |  156 ++
 arch/loongarch/include/asm/byteorder.h        |   22 +
 arch/loongarch/include/asm/cache.h            |   24 +
 arch/loongarch/include/asm/config.h           |   11 +
 arch/loongarch/include/asm/cpu.h              |  123 ++
 arch/loongarch/include/asm/dma-mapping.h      |   27 +
 arch/loongarch/include/asm/global_data.h      |   43 +
 arch/loongarch/include/asm/gpio.h             |   11 +
 arch/loongarch/include/asm/io.h               |  399 +++++
 arch/loongarch/include/asm/linkage.h          |   11 +
 arch/loongarch/include/asm/loongarch.h        | 1467 +++++++++++++++++
 arch/loongarch/include/asm/posix_types.h      |   87 +
 arch/loongarch/include/asm/processor.h        |   11 +
 arch/loongarch/include/asm/ptrace.h           |   33 +
 arch/loongarch/include/asm/regdef.h           |   42 +
 arch/loongarch/include/asm/sections.h         |    8 +
 arch/loongarch/include/asm/setjmp.h           |   25 +
 arch/loongarch/include/asm/spl.h              |   11 +
 arch/loongarch/include/asm/string.h           |   11 +
 arch/loongarch/include/asm/system.h           |   74 +
 arch/loongarch/include/asm/types.h            |   37 +
 arch/loongarch/include/asm/u-boot-loongarch.h |   23 +
 arch/loongarch/include/asm/u-boot.h           |   30 +
 arch/loongarch/include/asm/unaligned.h        |   11 +
 arch/loongarch/lib/Makefile                   |    5 +
 include/host_arch.h                           |    2 +
 40 files changed, 3344 insertions(+)
 create mode 100644 arch/loongarch/Kconfig
 create mode 100644 arch/loongarch/Makefile
 create mode 100644 arch/loongarch/config.mk
 create mode 100644 arch/loongarch/cpu/Makefile
 create mode 100644 arch/loongarch/cpu/u-boot.lds
 create mode 100644 arch/loongarch/dts/Makefile
 create mode 100644 arch/loongarch/include/asm/acpi_table.h
 create mode 100644 arch/loongarch/include/asm/addrspace.h
 create mode 100644 arch/loongarch/include/asm/arch-generic/entry-init.h
 create mode 100644 arch/loongarch/include/asm/asm.h
 create mode 100644 arch/loongarch/include/asm/atomic.h
 create mode 100644 arch/loongarch/include/asm/barrier.h
 create mode 100644 arch/loongarch/include/asm/bitops.h
 create mode 100644 arch/loongarch/include/asm/byteorder.h
 create mode 100644 arch/loongarch/include/asm/cache.h
 create mode 100644 arch/loongarch/include/asm/config.h
 create mode 100644 arch/loongarch/include/asm/cpu.h
 create mode 100644 arch/loongarch/include/asm/dma-mapping.h
 create mode 100644 arch/loongarch/include/asm/global_data.h
 create mode 100644 arch/loongarch/include/asm/gpio.h
 create mode 100644 arch/loongarch/include/asm/io.h
 create mode 100644 arch/loongarch/include/asm/linkage.h
 create mode 100644 arch/loongarch/include/asm/loongarch.h
 create mode 100644 arch/loongarch/include/asm/posix_types.h
 create mode 100644 arch/loongarch/include/asm/processor.h
 create mode 100644 arch/loongarch/include/asm/ptrace.h
 create mode 100644 arch/loongarch/include/asm/regdef.h
 create mode 100644 arch/loongarch/include/asm/sections.h
 create mode 100644 arch/loongarch/include/asm/setjmp.h
 create mode 100644 arch/loongarch/include/asm/spl.h
 create mode 100644 arch/loongarch/include/asm/string.h
 create mode 100644 arch/loongarch/include/asm/system.h
 create mode 100644 arch/loongarch/include/asm/types.h
 create mode 100644 arch/loongarch/include/asm/u-boot-loongarch.h
 create mode 100644 arch/loongarch/include/asm/u-boot.h
 create mode 100644 arch/loongarch/include/asm/unaligned.h
 create mode 100644 arch/loongarch/lib/Makefile

diff --git a/Makefile b/Makefile
index d8287323c43d..848391d12f92 100644
--- a/Makefile
+++ b/Makefile
@@ -243,6 +243,8 @@ else ifeq ("riscv32", $(MK_ARCH))
   export HOST_ARCH=$(HOST_ARCH_RISCV32)
 else ifeq ("riscv64", $(MK_ARCH))
   export HOST_ARCH=$(HOST_ARCH_RISCV64)
+else ifeq ("loongarch64", $(MK_ARCH))
+  export HOST_ARCH=$(HOST_ARCH_LOONGARCH64)
 endif
 undefine MK_ARCH
 
diff --git a/arch/Kconfig b/arch/Kconfig
index 8d63afeb138e..f73efa885906 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -110,6 +110,20 @@ config ARM
 	select SUPPORT_LITTLE_ENDIAN
 	select SUPPORT_OF_CONTROL
 
+config LOONGARCH
+	bool "LoongArch architecture"
+	select CREATE_ARCH_SYMLINK
+	select SUPPORT_OF_CONTROL
+	select OF_CONTROL
+	select DM
+	select DM_EVENT
+	imply DM_SERIAL
+	imply BLK
+	imply CLK
+	imply MTD
+	imply TIMER
+	imply CMD_DM
+
 config M68K
 	bool "M68000 architecture"
 	select HAVE_PRIVATE_LIBGCC
@@ -569,6 +583,7 @@ config SYS_NONCACHED_MEMORY
 
 source "arch/arc/Kconfig"
 source "arch/arm/Kconfig"
+source "arch/loongarch/Kconfig"
 source "arch/m68k/Kconfig"
 source "arch/microblaze/Kconfig"
 source "arch/mips/Kconfig"
diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig
new file mode 100644
index 000000000000..4e8e9d4ee88b
--- /dev/null
+++ b/arch/loongarch/Kconfig
@@ -0,0 +1,40 @@
+menu "LoongArch architecture"
+	depends on LOONGARCH
+
+config SYS_ARCH
+	default "loongarch"
+
+choice
+	prompt "Target select"
+
+endchoice
+
+# board-specific options below
+
+# platform-specific options below
+
+# architecture-specific options below
+choice
+	prompt "Base ISA"
+
+config ARCH_LA64
+	bool "LoongArch64"
+	select 64BIT
+	select PHYS_64BIT
+	help
+	  Choose this option to target the LoongArch64 base ISA.
+
+endchoice
+
+config DMA_ADDR_T_64BIT
+	bool
+	default y if 64BIT
+
+config STACK_SIZE_SHIFT
+	int
+	default 14
+
+config OF_BOARD_FIXUP
+	default y if OF_SEPARATE
+
+endmenu
diff --git a/arch/loongarch/Makefile b/arch/loongarch/Makefile
new file mode 100644
index 000000000000..288c695a634d
--- /dev/null
+++ b/arch/loongarch/Makefile
@@ -0,0 +1,19 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (C) 2024 Jiaxun yang <jiaxun.yang@flygoat.com>
+#
+
+ARCH_FLAGS = -march=loongarch64 -mabi=lp64s -msoft-float
+
+ifeq ($(CONFIG_$(SPL_)FRAMEPOINTER),y)
+	ARCH_FLAGS += -fno-omit-frame-pointer
+endif
+
+PLATFORM_CPPFLAGS += $(ARCH_FLAGS)
+
+head-y := arch/loongarch/cpu/start.o
+
+libs-y += arch/loongarch/cpu/
+libs-y += arch/loongarch/cpu/$(CPU)/
+libs-y += arch/loongarch/lib/
+
diff --git a/arch/loongarch/config.mk b/arch/loongarch/config.mk
new file mode 100644
index 000000000000..7c247400e361
--- /dev/null
+++ b/arch/loongarch/config.mk
@@ -0,0 +1,23 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (C) 2024 Jiaxun yang <jiaxun.yang@flygoat.com>
+#
+
+32bit-bfd		= elf32-loongarch
+64bit-bfd		= elf64-loongarch
+32bit-emul		= elf32loongarch
+64bit-emul		= elf64loongarch
+
+ifdef CONFIG_32BIT
+KBUILD_LDFLAGS		+= -m $(32bit-emul)
+PLATFORM_ELFFLAGS	+= -B loongarch -O $(32bit-bfd)
+endif
+
+ifdef CONFIG_64BIT
+KBUILD_LDFLAGS		+= -m $(64bit-emul)
+PLATFORM_ELFFLAGS	+= -B loongarch -O $(64bit-bfd)
+endif
+
+PLATFORM_CPPFLAGS	+= -fpic
+PLATFORM_RELFLAGS	+= -fno-common -ffunction-sections -fdata-sections
+LDFLAGS_u-boot		+= --gc-sections -static -pie
diff --git a/arch/loongarch/cpu/Makefile b/arch/loongarch/cpu/Makefile
new file mode 100644
index 000000000000..3dbed94cc624
--- /dev/null
+++ b/arch/loongarch/cpu/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (C) 2024 Jiaxun yang <jiaxun.yang@flygoat.com>
+#
+
diff --git a/arch/loongarch/cpu/u-boot.lds b/arch/loongarch/cpu/u-boot.lds
new file mode 100644
index 000000000000..2f0201c0c817
--- /dev/null
+++ b/arch/loongarch/cpu/u-boot.lds
@@ -0,0 +1,85 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2024 Jiaxun Yang <jiaxun.yang@flygoat.com>
+ */
+
+OUTPUT_ARCH(loongarch)
+ENTRY(_start)
+
+SECTIONS
+{
+	. = ALIGN(4);
+	.text : {
+		arch/loongarch/cpu/start.o	(.text)
+	}
+
+	/* This needs to come before *(.text*) */
+	.efi_runtime : {
+		__efi_runtime_start = .;
+		*(.text.efi_runtime*)
+		*(.rodata.efi_runtime*)
+		*(.data.efi_runtime*)
+		__efi_runtime_stop = .;
+	}
+
+	.text_rest : {
+		*(.text*)
+	}
+
+	. = ALIGN(4);
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
+
+	. = ALIGN(4);
+	.data : {
+		*(.data*)
+	}
+	. = ALIGN(4);
+
+	.got : {
+		__got_start = .;
+		*(.got.plt) *(.got)
+		__got_end = .;
+	}
+
+	. = ALIGN(4);
+
+	__u_boot_list : {
+		KEEP(*(SORT(__u_boot_list*)));
+	}
+
+	. = ALIGN(8);
+
+	.efi_runtime_rel : {
+		__efi_runtime_rel_start = .;
+		*(.rel*.efi_runtime)
+		*(.rel*.efi_runtime.*)
+		__efi_runtime_rel_stop = .;
+	}
+
+	/DISCARD/ : { *(.rela.plt*) }
+	.rela.dyn : {
+		__rel_dyn_start = .;
+		*(.rela*)
+		__rel_dyn_end = .;
+	}
+
+	. = ALIGN(8);
+
+	.dynsym : {
+		__dyn_sym_start = .;
+		*(.dynsym)
+		__dyn_sym_end = .;
+	}
+
+	. = ALIGN(8);
+
+	_end = .;
+	__init_end = .;
+
+	.bss : {
+		__bss_start = .;
+		*(.bss*)
+		. = ALIGN(8);
+		__bss_end = .;
+	}
+}
diff --git a/arch/loongarch/dts/Makefile b/arch/loongarch/dts/Makefile
new file mode 100644
index 000000000000..5cc395b6ea5d
--- /dev/null
+++ b/arch/loongarch/dts/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0+
+
+include $(srctree)/scripts/Makefile.dts
+
+# Add any required device tree compiler flags here
+DTC_FLAGS += -R 4 -p 0x1000
diff --git a/arch/loongarch/include/asm/acpi_table.h b/arch/loongarch/include/asm/acpi_table.h
new file mode 100644
index 000000000000..db2f644f07af
--- /dev/null
+++ b/arch/loongarch/include/asm/acpi_table.h
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef __ASM_ACPI_TABLE_H__
+#define __ASM_ACPI_TABLE_H__
+
+/* Dummy header */
+
+#endif /* __ASM_ACPI_TABLE_H__ */
diff --git a/arch/loongarch/include/asm/addrspace.h b/arch/loongarch/include/asm/addrspace.h
new file mode 100644
index 000000000000..e2f534ee22c7
--- /dev/null
+++ b/arch/loongarch/include/asm/addrspace.h
@@ -0,0 +1,86 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
+ * Copyright (C) 2024 Jiaxun Yang <jiaxun.yang@flygoat.com>
+ *
+ * Derived from MIPS:
+ * Copyright (C) 1996, 99 Ralf Baechle
+ * Copyright (C) 2000, 2002  Maciej W. Rozycki
+ * Copyright (C) 1990, 1999 by Silicon Graphics, Inc.
+ */
+#ifndef _ASM_ADDRSPACE_H
+#define _ASM_ADDRSPACE_H
+
+#include <linux/const.h>
+#include <linux/sizes.h>
+
+#include <asm/loongarch.h>
+
+#ifndef IO_BASE
+#define IO_BASE			CSR_DMW0_BASE
+#endif
+
+#ifndef CACHE_BASE
+#define CACHE_BASE		CSR_DMW1_BASE
+#endif
+
+#ifndef UNCACHE_BASE
+#define UNCACHE_BASE		CSR_DMW0_BASE
+#endif
+
+#define DMW_PABITS	48
+#define TO_PHYS_MASK	((1ULL << DMW_PABITS) - 1)
+
+#define TO_PHYS(x)		(		((x) & TO_PHYS_MASK))
+#define TO_CACHE(x)		(CACHE_BASE   |	((x) & TO_PHYS_MASK))
+#define TO_UNCACHE(x)		(UNCACHE_BASE |	((x) & TO_PHYS_MASK))
+
+#ifdef __ASSEMBLY__
+#define _ATYPE_
+#define _ATYPE32_
+#define _ATYPE64_
+#else
+#define _ATYPE_		__PTRDIFF_TYPE__
+#define _ATYPE32_	int
+#define _ATYPE64_	__s64
+#endif
+
+#ifdef CONFIG_64BIT
+#define _CONST64_(x)	_UL(x)
+#else
+#define _CONST64_(x)	_ULL(x)
+#endif
+
+/*
+ *  32/64-bit LoongArch address spaces
+ */
+#ifdef __ASSEMBLY__
+#define _ACAST32_
+#define _ACAST64_
+#else
+#define _ACAST32_		(_ATYPE_)(_ATYPE32_)	/* widen if necessary */
+#define _ACAST64_		(_ATYPE64_)		/* do _not_ narrow */
+#endif
+
+#ifdef CONFIG_32BIT
+
+#define UVRANGE			0x00000000
+#define KPRANGE0		0x80000000
+#define KPRANGE1		0xa0000000
+#define KVRANGE			0xc0000000
+
+#else
+
+#define XUVRANGE		_CONST64_(0x0000000000000000)
+#define XSPRANGE		_CONST64_(0x4000000000000000)
+#define XKPRANGE		_CONST64_(0x8000000000000000)
+#define XKVRANGE		_CONST64_(0xc000000000000000)
+
+#endif
+
+/*
+ * Returns the physical address of a KPRANGEx / XKPRANGE address
+ */
+#define PHYSADDR(a)		((_ACAST64_(a)) & TO_PHYS_MASK)
+
+#endif /* _ASM_ADDRSPACE_H */
diff --git a/arch/loongarch/include/asm/arch-generic/entry-init.h b/arch/loongarch/include/asm/arch-generic/entry-init.h
new file mode 100644
index 000000000000..a618f66d0d7a
--- /dev/null
+++ b/arch/loongarch/include/asm/arch-generic/entry-init.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2024 Jiaxun Yang <jiaxun.yang@flygoat.com>
+ */
+
+#ifndef __ASM_ENTRY_INIT_H
+#define __ASM_ENTRY_INIT_H
+
+	.macro	entry_setup
+	.endm
+
+	.macro	smp_secondary_setup
+	.endm
+
+#endif
diff --git a/arch/loongarch/include/asm/asm.h b/arch/loongarch/include/asm/asm.h
new file mode 100644
index 000000000000..176bf42cdccf
--- /dev/null
+++ b/arch/loongarch/include/asm/asm.h
@@ -0,0 +1,186 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Some useful macros for LoongArch assembler code
+ *
+ * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
+ * Copyright (C) 2024 Jiaxun Yang <jiaxun.yang@flygoat.com>
+ *
+ * Derived from MIPS:
+ * Copyright (C) 1995, 1996, 1997, 1999, 2001 by Ralf Baechle
+ * Copyright (C) 1999 by Silicon Graphics, Inc.
+ * Copyright (C) 2001 MIPS Technologies, Inc.
+ * Copyright (C) 2002  Maciej W. Rozycki
+ */
+#ifndef __ASM_ASM_H
+#define __ASM_ASM_H
+
+#include <asm/regdef.h>
+
+/*
+ * Stack alignment
+ */
+#define STACK_ALIGN	~(0xf)
+
+/*
+ * Macros to handle different pointer/register sizes for 32/64-bit code
+ */
+
+/*
+ * Size of a register
+ */
+#if defined(__loongarch__) && __loongarch_grlen == 64
+#define SZREG	4
+#else
+#define SZREG	8
+#endif
+
+/*
+ * Use the following macros in assemblercode to load/store registers,
+ * pointers etc.
+ */
+#if (SZREG == 4)
+#define REG_L		ld.w
+#define REG_S		st.w
+#define REG_ADD		add.w
+#define REG_SUB		sub.w
+#else /* SZREG == 8 */
+#define REG_L		ld.d
+#define REG_S		st.d
+#define REG_ADD		add.d
+#define REG_SUB		sub.d
+#endif
+
+/*
+ * How to add/sub/load/store/shift C int variables.
+ */
+#if (__SIZEOF_INT__ == 4)
+#define INT_ADD		add.w
+#define INT_ADDI	addi.w
+#define INT_SUB		sub.w
+#define INT_L		ld.w
+#define INT_S		st.w
+#define INT_SLL		slli.w
+#define INT_SLLV	sll.w
+#define INT_SRL		srli.w
+#define INT_SRLV	srl.w
+#define INT_SRA		srai.w
+#define INT_SRAV	sra.w
+#endif
+
+#if (__SIZEOF_INT__ == 8)
+#define INT_ADD		add.d
+#define INT_ADDI	addi.d
+#define INT_SUB		sub.d
+#define INT_L		ld.d
+#define INT_S		st.d
+#define INT_SLL		slli.d
+#define INT_SLLV	sll.d
+#define INT_SRL		srli.d
+#define INT_SRLV	srl.d
+#define INT_SRA		srai.d
+#define INT_SRAV	sra.d
+#endif
+
+/*
+ * How to add/sub/load/store/shift C long variables.
+ */
+#if (__SIZEOF_LONG__ == 4)
+#define LONG_ADD	add.w
+#define LONG_ADDI	addi.w
+#define LONG_SUB	sub.w
+#define LONG_L		ld.w
+#define LONG_LI		li.w
+#define LONG_S		st.w
+#define LONG_SLL	slli.w
+#define LONG_SLLV	sll.w
+#define LONG_SRL	srli.w
+#define LONG_SRLV	srl.w
+#define LONG_SRA	srai.w
+#define LONG_SRAV	sra.w
+#define LONG_IOCSRRD	iocsrrd.w
+#define LONG_IOCSRWR	iocsrwr.w
+
+#ifdef __ASSEMBLY__
+#define LONG		.word
+#endif
+#define LONGSIZE	4
+#define LONGMASK	3
+#define LONGLOG		2
+#endif
+
+#if (__SIZEOF_LONG__ == 8)
+#define LONG_ADD	add.d
+#define LONG_ADDI	addi.d
+#define LONG_SUB	sub.d
+#define LONG_L		ld.d
+#define LONG_LI		li.d
+#define LONG_S		st.d
+#define LONG_SLL	slli.d
+#define LONG_SLLV	sll.d
+#define LONG_SRL	srli.d
+#define LONG_SRLV	srl.d
+#define LONG_SRA	srai.d
+#define LONG_SRAV	sra.d
+#define LONG_IOCSRRD	iocsrrd.w
+#define LONG_IOCSRWR	iocsrwr.w
+
+#ifdef __ASSEMBLY__
+#define LONG		.dword
+#endif
+#define LONGSIZE	8
+#define LONGMASK	7
+#define LONGLOG		3
+#endif
+
+/*
+ * How to add/sub/load/store/shift pointers.
+ */
+#if (__SIZEOF_POINTER__ == 4)
+#define PTR_ADD		add.w
+#define PTR_ADDI	addi.w
+#define PTR_SUB		sub.w
+#define PTR_L		ld.w
+#define PTR_S		st.w
+#define PTR_LI		li.w
+#define PTR_SLL		slli.w
+#define PTR_SLLV	sll.w
+#define PTR_SRL		srli.w
+#define PTR_SRLV	srl.w
+#define PTR_SRA		srai.w
+#define PTR_SRAV	sra.w
+#define PTR_MUL		mul.w
+
+#define PTR_SCALESHIFT	2
+
+#ifdef __ASSEMBLY__
+#define PTR		.word
+#endif
+#define PTRSIZE		4
+#define PTRLOG		2
+#endif
+
+#if (__SIZEOF_POINTER__ == 8)
+#define PTR_ADD		add.d
+#define PTR_ADDI	addi.d
+#define PTR_SUB		sub.d
+#define PTR_L		ld.d
+#define PTR_S		st.d
+#define PTR_LI		li.d
+#define PTR_SLL		slli.d
+#define PTR_SLLV	sll.d
+#define PTR_SRL		srli.d
+#define PTR_SRLV	srl.d
+#define PTR_SRA		srai.d
+#define PTR_SRAV	sra.d
+#define PTR_MUL		mul.d
+
+#define PTR_SCALESHIFT	3
+
+#ifdef __ASSEMBLY__
+#define PTR		.dword
+#endif
+#define PTRSIZE		8
+#define PTRLOG		3
+#endif
+
+#endif /* __ASM_ASM_H */
diff --git a/arch/loongarch/include/asm/atomic.h b/arch/loongarch/include/asm/atomic.h
new file mode 100644
index 000000000000..abd0b6f5f342
--- /dev/null
+++ b/arch/loongarch/include/asm/atomic.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2024 Jiaxun Yang <jiaxun.yang@flygoat.com>
+ */
+
+#ifndef __LOONGARCH_ATOMIC_H
+#define __LOONGARCH_ATOMIC_H
+
+#include <asm/system.h>
+#include <asm-generic/atomic.h>
+
+#endif
diff --git a/arch/loongarch/include/asm/barrier.h b/arch/loongarch/include/asm/barrier.h
new file mode 100644
index 000000000000..952222116f50
--- /dev/null
+++ b/arch/loongarch/include/asm/barrier.h
@@ -0,0 +1,138 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
+ * Copyright (C) 2024 Jiaxun Yang <jiaxun.yang@flygoat.com>
+ */
+#ifndef __ASM_BARRIER_H
+#define __ASM_BARRIER_H
+
+/*
+ * Hint encoding:
+ *
+ * Bit4: ordering or completion (0: completion, 1: ordering)
+ * Bit3: barrier for previous read (0: true, 1: false)
+ * Bit2: barrier for previous write (0: true, 1: false)
+ * Bit1: barrier for succeeding read (0: true, 1: false)
+ * Bit0: barrier for succeeding write (0: true, 1: false)
+ *
+ * Hint 0x700: barrier for "read after read" from the same address
+ */
+
+#define DBAR(hint) __asm__ __volatile__("dbar %0 " : : "I"(hint) : "memory")
+
+#define crwrw		0b00000
+#define cr_r_		0b00101
+#define c_w_w		0b01010
+
+#define orwrw		0b10000
+#define or_r_		0b10101
+#define o_w_w		0b11010
+
+#define orw_w		0b10010
+#define or_rw		0b10100
+
+#define c_sync()	DBAR(crwrw)
+#define c_rsync()	DBAR(cr_r_)
+#define c_wsync()	DBAR(c_w_w)
+
+#define o_sync()	DBAR(orwrw)
+#define o_rsync()	DBAR(or_r_)
+#define o_wsync()	DBAR(o_w_w)
+
+#define ldacq_mb()	DBAR(or_rw)
+#define strel_mb()	DBAR(orw_w)
+
+#define mb()		c_sync()
+#define rmb()		c_rsync()
+#define wmb()		c_wsync()
+#define iob()		c_sync()
+#define wbflush()	c_sync()
+
+#define __smp_mb()	o_sync()
+#define __smp_rmb()	o_rsync()
+#define __smp_wmb()	o_wsync()
+
+#ifdef CONFIG_SMP
+#define __WEAK_LLSC_MB		"	dbar 0x700	\n"
+#else
+#define __WEAK_LLSC_MB		"			\n"
+#endif
+
+#define __smp_mb__before_atomic()	barrier()
+#define __smp_mb__after_atomic()	barrier()
+
+/**
+ * array_index_mask_nospec() - generate a ~0 mask when index < size, 0 otherwise
+ * @index: array element index
+ * @size: number of elements in array
+ *
+ * Returns:
+ *     0 - (@index < @size)
+ */
+#define array_index_mask_nospec array_index_mask_nospec
+static inline unsigned long array_index_mask_nospec(unsigned long index,
+						    unsigned long size)
+{
+	unsigned long mask;
+
+	__asm__ __volatile__(
+		"sltu	%0, %1, %2\n\t"
+#if (__SIZEOF_LONG__ == 4)
+		"sub.w	%0, $zero, %0\n\t"
+#elif (__SIZEOF_LONG__ == 8)
+		"sub.d	%0, $zero, %0\n\t"
+#endif
+		: "=r" (mask)
+		: "r" (index), "r" (size)
+		:);
+
+	return mask;
+}
+
+#define __smp_load_acquire(p)				\
+({							\
+	typeof(*p) ___p1 = READ_ONCE(*p);		\
+	compiletime_assert_atomic_type(*p);		\
+	ldacq_mb();					\
+	___p1;						\
+})
+
+#define __smp_store_release(p, v)			\
+do {							\
+	compiletime_assert_atomic_type(*p);		\
+	strel_mb();					\
+	WRITE_ONCE(*p, v);				\
+} while (0)
+
+#define __smp_store_mb(p, v)							\
+do {										\
+	union { typeof(p) __val; char __c[1]; } __u =				\
+		{ .__val = (__force typeof(p)) (v) };				\
+	unsigned long __tmp;							\
+	switch (sizeof(p)) {							\
+	case 1:									\
+		*(volatile __u8 *)&p = *(__u8 *)__u.__c;			\
+		__smp_mb();							\
+		break;								\
+	case 2:									\
+		*(volatile __u16 *)&p = *(__u16 *)__u.__c;			\
+		__smp_mb();							\
+		break;								\
+	case 4:									\
+		__asm__ __volatile__(						\
+		"amswap_db.w %[tmp], %[val], %[mem]	\n"			\
+		: [mem] "+ZB" (*(u32 *)&p), [tmp] "=&r" (__tmp)			\
+		: [val] "r" (*(__u32 *)__u.__c)					\
+		: );								\
+		break;								\
+	case 8:									\
+		__asm__ __volatile__(						\
+		"amswap_db.d %[tmp], %[val], %[mem]	\n"			\
+		: [mem] "+ZB" (*(u64 *)&p), [tmp] "=&r" (__tmp)			\
+		: [val] "r" (*(__u64 *)__u.__c)					\
+		: );								\
+		break;								\
+	}									\
+} while (0)
+
+#endif /* __ASM_BARRIER_H */
diff --git a/arch/loongarch/include/asm/bitops.h b/arch/loongarch/include/asm/bitops.h
new file mode 100644
index 000000000000..32a60d218b7e
--- /dev/null
+++ b/arch/loongarch/include/asm/bitops.h
@@ -0,0 +1,156 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright 1995, Russell King.
+ * Various bits and pieces copyrights include:
+ * Linus Torvalds (test_bit).
+ *
+ * Copyright (C) 2017 Andes Technology Corporation
+ * Rick Chen, Andes Technology Corporation <rick@andestech.com>
+ *
+ * Copyright (C) 2024 Jiaxun Yang <jiaxun.yang@flygoat.com>
+ *
+ * bit 0 is the LSB of addr; bit 32 is the LSB of (addr+1).
+ *
+ * Please note that the code in this file should never be included
+ * from user space.  Many of these are not implemented in assembler
+ * since they would be too costly.  Also, they require privileged
+ * instructions (which are not available from user mode) to ensure
+ * that they are atomic.
+ */
+
+#ifndef __ASM_LOONGARCH_BITOPS_H
+#define __ASM_LOONGARCH_BITOPS_H
+
+#ifdef __KERNEL__
+
+#include <asm/barrier.h>
+
+#include <asm-generic/bitops/builtin-ffs.h>
+#include <asm-generic/bitops/builtin-fls.h>
+#include <asm-generic/bitops/builtin-__ffs.h>
+#include <asm-generic/bitops/builtin-__fls.h>
+#include <asm-generic/bitops/fls64.h>
+
+#define PLATFORM_FFS
+
+static inline void __change_bit(int nr, void *addr)
+{
+	int mask;
+	unsigned long *ADDR = (unsigned long *)addr;
+
+	ADDR += nr >> 5;
+	mask = 1 << (nr & 31);
+	*ADDR ^= mask;
+}
+
+static inline int __test_and_set_bit(int nr, void *addr)
+{
+	int mask, retval;
+	unsigned int *a = (unsigned int *)addr;
+
+	a += nr >> 5;
+	mask = 1 << (nr & 0x1f);
+	retval = (mask & *a) != 0;
+	*a |= mask;
+	return retval;
+}
+
+static inline int __test_and_clear_bit(int nr, void *addr)
+{
+	int mask, retval;
+	unsigned int *a = (unsigned int *)addr;
+
+	a += nr >> 5;
+	mask = 1 << (nr & 0x1f);
+	retval = (mask & *a) != 0;
+	*a &= ~mask;
+	return retval;
+}
+
+static inline int __test_and_change_bit(int nr, void *addr)
+{
+	int mask, retval;
+	unsigned int *a = (unsigned int *)addr;
+
+	a += nr >> 5;
+	mask = 1 << (nr & 0x1f);
+	retval = (mask & *a) != 0;
+	*a ^= mask;
+	return retval;
+}
+
+/*
+ * This routine doesn't need to be atomic.
+ */
+static inline int test_bit(int nr, const void *addr)
+{
+	return ((unsigned char *)addr)[nr >> 3] & (1U << (nr & 7));
+}
+
+/*
+ * ffz = Find First Zero in word. Undefined if no zero exists,
+ * so code should check against ~0UL first..
+ */
+static inline unsigned long ffz(unsigned long word)
+{
+	int k;
+
+	word = ~word;
+	k = 31;
+	if (word & 0x0000ffff) {
+		k -= 16; word <<= 16;
+	}
+	if (word & 0x00ff0000) {
+		k -= 8;  word <<= 8;
+	}
+	if (word & 0x0f000000) {
+		k -= 4;  word <<= 4;
+	}
+	if (word & 0x30000000) {
+		k -= 2;  word <<= 2;
+	}
+	if (word & 0x40000000)
+		k -= 1;
+
+	return k;
+}
+
+/*
+ * ffs: find first bit set. This is defined the same way as
+ * the libc and compiler builtin ffs routines, therefore
+ * differs in spirit from the above ffz (man ffs).
+ */
+
+/*
+ * redefined in include/linux/bitops.h
+ * #define ffs(x) generic_ffs(x)
+ */
+
+/*
+ * hweightN: returns the hamming weight (i.e. the number
+ * of bits set) of a N-bit word
+ */
+
+#define hweight32(x) generic_hweight32(x)
+#define hweight16(x) generic_hweight16(x)
+#define hweight8(x) generic_hweight8(x)
+
+#define test_and_set_bit		__test_and_set_bit
+#define test_and_clear_bit		__test_and_clear_bit
+
+#define ext2_set_bit			test_and_set_bit
+#define ext2_clear_bit			test_and_clear_bit
+#define ext2_test_bit			test_bit
+#define ext2_find_first_zero_bit	find_first_zero_bit
+#define ext2_find_next_zero_bit		find_next_zero_bit
+
+/* Bitmap functions for the minix filesystem. */
+#define minix_test_and_set_bit(nr, addr)	test_and_set_bit(nr, addr)
+#define minix_set_bit(nr, addr)			set_bit(nr, addr)
+#define minix_test_and_clear_bit(nr, addr)	test_and_clear_bit(nr, addr)
+#define minix_test_bit(nr, addr)		test_bit(nr, addr)
+#define minix_find_first_zero_bit(addr, size)	find_first_zero_bit(addr, size)
+
+#endif /* __KERNEL__ */
+
+#endif /* __ASM_LOONGARCH_BITOPS_H */
diff --git a/arch/loongarch/include/asm/byteorder.h b/arch/loongarch/include/asm/byteorder.h
new file mode 100644
index 000000000000..ba25f25729ac
--- /dev/null
+++ b/arch/loongarch/include/asm/byteorder.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2024 Jiaxun Yang <jiaxun.yang@flygoat.com>
+ */
+
+#ifndef __ASM_LOONGARCH_BYTEORDER_H
+#define __ASM_LOONGARCH_BYTEORDER_H
+
+#include <asm/types.h>
+
+#if !defined(__STRICT_ANSI__) || defined(__KERNEL__)
+#  define __BYTEORDER_HAS_U64__
+#  define __SWAB_64_THRU_32__
+#endif
+
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+#include <linux/byteorder/little_endian.h>
+#else
+#include <linux/byteorder/big_endian.h>
+#endif
+
+#endif
diff --git a/arch/loongarch/include/asm/cache.h b/arch/loongarch/include/asm/cache.h
new file mode 100644
index 000000000000..854dd0c0a02e
--- /dev/null
+++ b/arch/loongarch/include/asm/cache.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2024 Jiaxun Yang <jiaxun.yang@flygoat.com>
+ */
+
+#ifndef _ASM_LOONGARCH_CACHE_H
+#define _ASM_LOONGARCH_CACHE_H
+
+/* cache */
+void cache_flush(void);
+
+#define cache_op(op, addr)						\
+	__asm__ __volatile__(						\
+	"	cacop	%0, %1					\n"	\
+	:								\
+	: "i" (op), "ZC" (*(unsigned char *)(addr)))
+
+#ifdef CONFIG_SYS_CACHELINE_SIZE
+#define ARCH_DMA_MINALIGN	CONFIG_SYS_CACHELINE_SIZE
+#else
+#define ARCH_DMA_MINALIGN	32
+#endif
+
+#endif /* _ASM_LOONGARCH_CACHE_H */
diff --git a/arch/loongarch/include/asm/config.h b/arch/loongarch/include/asm/config.h
new file mode 100644
index 000000000000..23eb49847e7b
--- /dev/null
+++ b/arch/loongarch/include/asm/config.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2024 Jiaxun Yang <jiaxun.yang@flygoat.com>
+ */
+
+#ifndef _ASM_CONFIG_H_
+#define _ASM_CONFIG_H_
+
+/* Dummy header */
+
+#endif
diff --git a/arch/loongarch/include/asm/cpu.h b/arch/loongarch/include/asm/cpu.h
new file mode 100644
index 000000000000..e65ef273ed46
--- /dev/null
+++ b/arch/loongarch/include/asm/cpu.h
@@ -0,0 +1,123 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * cpu.h: Values of the PRID register used to match up
+ *	  various LoongArch CPU types.
+ *
+ * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
+ */
+#ifndef _ASM_CPU_H
+#define _ASM_CPU_H
+
+#include <linux/bitops.h>
+
+/*
+ * As described in LoongArch specs from Loongson Technology, the PRID register
+ * (CPUCFG.00) has the following layout:
+ *
+ * +---------------+----------------+------------+--------------------+
+ * | Reserved      | Company ID     | Series ID  |  Product ID        |
+ * +---------------+----------------+------------+--------------------+
+ *  31		 24 23		  16 15	       12 11		     0
+ */
+
+/*
+ * Assigned Company values for bits 23:16 of the PRID register.
+ */
+
+#define PRID_COMP_MASK		0xff0000
+
+#define PRID_COMP_LOONGSON	0x140000
+
+/*
+ * Assigned Series ID values for bits 15:12 of the PRID register. In order
+ * to detect a certain CPU type exactly eventually additional registers may
+ * need to be examined.
+ */
+
+#define PRID_SERIES_MASK	0xf000
+
+#define PRID_SERIES_LA132	0x8000  /* Loongson 32bit */
+#define PRID_SERIES_LA264	0xa000  /* Loongson 64bit, 2-issue */
+#define PRID_SERIES_LA364	0xb000  /* Loongson 64bit, 3-issue */
+#define PRID_SERIES_LA464	0xc000  /* Loongson 64bit, 4-issue */
+#define PRID_SERIES_LA664	0xd000  /* Loongson 64bit, 6-issue */
+
+/*
+ * Particular Product ID values for bits 11:0 of the PRID register.
+ */
+
+#define PRID_PRODUCT_MASK	0x0fff
+
+
+/*
+ * ISA Level encodings
+ *
+ */
+
+#define LOONGARCH_CPU_ISA_LA32R 0x00000001
+#define LOONGARCH_CPU_ISA_LA32S 0x00000002
+#define LOONGARCH_CPU_ISA_LA64  0x00000004
+
+#define LOONGARCH_CPU_ISA_32BIT (LOONGARCH_CPU_ISA_LA32R | LOONGARCH_CPU_ISA_LA32S)
+#define LOONGARCH_CPU_ISA_64BIT LOONGARCH_CPU_ISA_LA64
+
+/*
+ * CPU Option encodings
+ */
+#define CPU_FEATURE_CPUCFG		0	/* CPU has CPUCFG */
+#define CPU_FEATURE_LAM			1	/* CPU has Atomic instructions */
+#define CPU_FEATURE_UAL			2	/* CPU supports unaligned access */
+#define CPU_FEATURE_FPU			3	/* CPU has FPU */
+#define CPU_FEATURE_LSX			4	/* CPU has LSX (128-bit SIMD) */
+#define CPU_FEATURE_LASX		5	/* CPU has LASX (256-bit SIMD) */
+#define CPU_FEATURE_CRC32		6	/* CPU has CRC32 instructions */
+#define CPU_FEATURE_COMPLEX		7	/* CPU has Complex instructions */
+#define CPU_FEATURE_CRYPTO		8	/* CPU has Crypto instructions */
+#define CPU_FEATURE_LVZ			9	/* CPU has Virtualization extension */
+#define CPU_FEATURE_LBT_X86		10	/* CPU has X86 Binary Translation */
+#define CPU_FEATURE_LBT_ARM		11	/* CPU has ARM Binary Translation */
+#define CPU_FEATURE_LBT_MIPS		12	/* CPU has MIPS Binary Translation */
+#define CPU_FEATURE_TLB			13	/* CPU has TLB */
+#define CPU_FEATURE_CSR			14	/* CPU has CSR */
+#define CPU_FEATURE_WATCH		15	/* CPU has watchpoint registers */
+#define CPU_FEATURE_VINT		16	/* CPU has vectored interrupts */
+#define CPU_FEATURE_CSRIPI		17	/* CPU has CSR-IPI */
+#define CPU_FEATURE_EXTIOI		18	/* CPU has EXT-IOI */
+#define CPU_FEATURE_PREFETCH		19	/* CPU has prefetch instructions */
+#define CPU_FEATURE_PMP			20	/* CPU has perfermance counter */
+#define CPU_FEATURE_SCALEFREQ		21	/* CPU supports cpufreq scaling */
+#define CPU_FEATURE_FLATMODE		22	/* CPU has flat mode */
+#define CPU_FEATURE_EIODECODE		23	/* CPU has EXTIOI interrupt pin decode mode */
+#define CPU_FEATURE_GUESTID		24	/* CPU has GuestID feature */
+#define CPU_FEATURE_HYPERVISOR		25	/* CPU has hypervisor (running in VM) */
+#define CPU_FEATURE_PTW			26	/* CPU has hardware page table walker */
+
+#define LOONGARCH_CPU_CPUCFG		BIT_ULL(CPU_FEATURE_CPUCFG)
+#define LOONGARCH_CPU_LAM		BIT_ULL(CPU_FEATURE_LAM)
+#define LOONGARCH_CPU_UAL		BIT_ULL(CPU_FEATURE_UAL)
+#define LOONGARCH_CPU_FPU		BIT_ULL(CPU_FEATURE_FPU)
+#define LOONGARCH_CPU_LSX		BIT_ULL(CPU_FEATURE_LSX)
+#define LOONGARCH_CPU_LASX		BIT_ULL(CPU_FEATURE_LASX)
+#define LOONGARCH_CPU_CRC32		BIT_ULL(CPU_FEATURE_CRC32)
+#define LOONGARCH_CPU_COMPLEX		BIT_ULL(CPU_FEATURE_COMPLEX)
+#define LOONGARCH_CPU_CRYPTO		BIT_ULL(CPU_FEATURE_CRYPTO)
+#define LOONGARCH_CPU_LVZ		BIT_ULL(CPU_FEATURE_LVZ)
+#define LOONGARCH_CPU_LBT_X86		BIT_ULL(CPU_FEATURE_LBT_X86)
+#define LOONGARCH_CPU_LBT_ARM		BIT_ULL(CPU_FEATURE_LBT_ARM)
+#define LOONGARCH_CPU_LBT_MIPS		BIT_ULL(CPU_FEATURE_LBT_MIPS)
+#define LOONGARCH_CPU_TLB		BIT_ULL(CPU_FEATURE_TLB)
+#define LOONGARCH_CPU_CSR		BIT_ULL(CPU_FEATURE_CSR)
+#define LOONGARCH_CPU_WATCH		BIT_ULL(CPU_FEATURE_WATCH)
+#define LOONGARCH_CPU_VINT		BIT_ULL(CPU_FEATURE_VINT)
+#define LOONGARCH_CPU_CSRIPI		BIT_ULL(CPU_FEATURE_CSRIPI)
+#define LOONGARCH_CPU_EXTIOI		BIT_ULL(CPU_FEATURE_EXTIOI)
+#define LOONGARCH_CPU_PREFETCH		BIT_ULL(CPU_FEATURE_PREFETCH)
+#define LOONGARCH_CPU_PMP		BIT_ULL(CPU_FEATURE_PMP)
+#define LOONGARCH_CPU_SCALEFREQ		BIT_ULL(CPU_FEATURE_SCALEFREQ)
+#define LOONGARCH_CPU_FLATMODE		BIT_ULL(CPU_FEATURE_FLATMODE)
+#define LOONGARCH_CPU_EIODECODE		BIT_ULL(CPU_FEATURE_EIODECODE)
+#define LOONGARCH_CPU_GUESTID		BIT_ULL(CPU_FEATURE_GUESTID)
+#define LOONGARCH_CPU_HYPERVISOR	BIT_ULL(CPU_FEATURE_HYPERVISOR)
+#define LOONGARCH_CPU_PTW		BIT_ULL(CPU_FEATURE_PTW)
+
+#endif /* _ASM_CPU_H */
diff --git a/arch/loongarch/include/asm/dma-mapping.h b/arch/loongarch/include/asm/dma-mapping.h
new file mode 100644
index 000000000000..87088815b955
--- /dev/null
+++ b/arch/loongarch/include/asm/dma-mapping.h
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2024 Jiaxun Yang <jiaxun.yang@flygoat.com>
+ */
+
+#ifndef __ASM_LOONGARCH_DMA_MAPPING_H
+#define __ASM_LOONGARCH_DMA_MAPPING_H
+
+#include <linux/types.h>
+#include <asm/cache.h>
+#include <cpu_func.h>
+#include <linux/dma-direction.h>
+#include <malloc.h>
+
+static inline void *dma_alloc_coherent(size_t len, unsigned long *handle)
+{
+	/* TODO:For non-coherent system allocate from DMW1 */
+	*handle = (unsigned long)memalign(ARCH_DMA_MINALIGN, len);
+	return (void *)*handle;
+}
+
+static inline void dma_free_coherent(void *addr)
+{
+	free(addr);
+}
+
+#endif
diff --git a/arch/loongarch/include/asm/global_data.h b/arch/loongarch/include/asm/global_data.h
new file mode 100644
index 000000000000..2a9a525e2f37
--- /dev/null
+++ b/arch/loongarch/include/asm/global_data.h
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (C) Copyright 2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Copyright (C) 2024 Jiaxun Yang <jiaxun.yang@flygoat.com>
+ */
+
+#ifndef __ASM_GBL_DATA_H
+#define __ASM_GBL_DATA_H
+
+#include <linux/types.h>
+#include <asm/u-boot.h>
+#include <compiler.h>
+
+/* Architecture-specific global data */
+struct arch_global_data {
+#if CONFIG_IS_ENABLED(ACPI)
+	ulong table_start;		/* Start address of ACPI tables */
+	ulong table_end;		/* End address of ACPI tables */
+	ulong table_start_high;		/* Start address of high ACPI tables */
+	ulong table_end_high;		/* End address of high ACPI tables */
+#endif
+#ifdef CONFIG_SMBIOS
+	ulong smbios_start;		/* Start address of SMBIOS table */
+#endif
+};
+
+#include <asm-generic/global_data.h>
+
+/* GD is stored in u0 (per CPU pointer) */
+#define DECLARE_GLOBAL_DATA_PTR register gd_t *gd asm ("$r21")
+
+static inline void set_gd(volatile gd_t *gd_ptr)
+{
+#ifdef CONFIG_64BIT
+	asm volatile("ld.d $r21, %0\n" : : "m"(gd_ptr));
+#else
+	asm volatile("ld.w $r21, %0\n" : : "m"(gd_ptr));
+#endif
+}
+
+#endif /* __ASM_GBL_DATA_H */
diff --git a/arch/loongarch/include/asm/gpio.h b/arch/loongarch/include/asm/gpio.h
new file mode 100644
index 000000000000..b2508fc2e9f8
--- /dev/null
+++ b/arch/loongarch/include/asm/gpio.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2024 Jiaxun Yang <jiaxun.yang@flygoat.com>
+ */
+
+#ifndef __ASM_GPIO_H
+#define __ASM_GPIO_H
+
+#include <asm-generic/gpio.h>
+
+#endif
diff --git a/arch/loongarch/include/asm/io.h b/arch/loongarch/include/asm/io.h
new file mode 100644
index 000000000000..1fd6ccd9f9a7
--- /dev/null
+++ b/arch/loongarch/include/asm/io.h
@@ -0,0 +1,399 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2017 Andes Technology Corporation
+ * Rick Chen, Andes Technology Corporation <rick@andestech.com>
+ *
+ * Copyright (C) 2024 Jiaxun Yang <jiaxun.yang@flygoat.com>
+ */
+
+#ifndef __ASM_LOONGARCH_IO_H
+#define __ASM_LOONGARCH_IO_H
+
+#include <linux/types.h>
+#include <asm/addrspace.h>
+#include <asm/barrier.h>
+#include <asm/byteorder.h>
+
+static inline void sync(void)
+{
+}
+
+#define __arch_getb(a)			(*(volatile unsigned char *)(a))
+#define __arch_getw(a)			(*(volatile unsigned short *)(a))
+#define __arch_getl(a)			(*(volatile unsigned int *)(a))
+#define __arch_getq(a)			(*(volatile unsigned long long *)(a))
+
+#define __arch_putb(v, a)		(*(volatile unsigned char *)(a) = (v))
+#define __arch_putw(v, a)		(*(volatile unsigned short *)(a) = (v))
+#define __arch_putl(v, a)		(*(volatile unsigned int *)(a) = (v))
+#define __arch_putq(v, a)		(*(volatile unsigned long long *)(a) = (v))
+
+#define __raw_writeb(v, a)		__arch_putb(v, a)
+#define __raw_writew(v, a)		__arch_putw(v, a)
+#define __raw_writel(v, a)		__arch_putl(v, a)
+#define __raw_writeq(v, a)		__arch_putq(v, a)
+
+#define __raw_readb(a)			__arch_getb(a)
+#define __raw_readw(a)			__arch_getw(a)
+#define __raw_readl(a)			__arch_getl(a)
+#define __raw_readq(a)			__arch_getq(a)
+
+/* adding for cadence_qspi_apb.c */
+#define memcpy_fromio(a, c, l)		memcpy((a), (c), (l))
+#define memcpy_toio(c, a, l)		memcpy((c), (a), (l))
+
+#define dmb()		mb()
+#define __iormb()	rmb()
+#define __iowmb()	wmb()
+
+static inline void writeb(u8 val, volatile void __iomem *addr)
+{
+	__iowmb();
+	__arch_putb(val, addr);
+}
+
+static inline void writew(u16 val, volatile void __iomem *addr)
+{
+	__iowmb();
+	__arch_putw(val, addr);
+}
+
+static inline void writel(u32 val, volatile void __iomem *addr)
+{
+	__iowmb();
+	__arch_putl(val, addr);
+}
+
+static inline void writeq(u64 val, volatile void __iomem *addr)
+{
+	__iowmb();
+	__arch_putq(val, addr);
+}
+
+static inline u8 readb(const volatile void __iomem *addr)
+{
+	u8	val;
+
+	val = __arch_getb(addr);
+	__iormb();
+	return val;
+}
+
+static inline u16 readw(const volatile void __iomem *addr)
+{
+	u16	val;
+
+	val = __arch_getw(addr);
+	__iormb();
+	return val;
+}
+
+static inline u32 readl(const volatile void __iomem *addr)
+{
+	u32	val;
+
+	val = __arch_getl(addr);
+	__iormb();
+	return val;
+}
+
+static inline u64 readq(const volatile void __iomem *addr)
+{
+	u64	val;
+
+	val = __arch_getq(addr);
+	__iormb();
+	return val;
+}
+
+/*
+ * The compiler seems to be incapable of optimising constants
+ * properly.  Spell it out to the compiler in some cases.
+ * These are only valid for small values of "off" (< 1<<12)
+ */
+#define __raw_base_writeb(val, base, off)	__arch_base_putb(val, base, off)
+#define __raw_base_writew(val, base, off)	__arch_base_putw(val, base, off)
+#define __raw_base_writel(val, base, off)	__arch_base_putl(val, base, off)
+
+#define __raw_base_readb(base, off)	__arch_base_getb(base, off)
+#define __raw_base_readw(base, off)	__arch_base_getw(base, off)
+#define __raw_base_readl(base, off)	__arch_base_getl(base, off)
+
+#define out_arch(type, endian, a, v)	__raw_write##type(cpu_to_##endian(v), a)
+#define in_arch(type, endian, a)	endian##_to_cpu(__raw_read##type(a))
+
+#define out_le32(a, v)			out_arch(l, le32, a, v)
+#define out_le16(a, v)			out_arch(w, le16, a, v)
+
+#define in_le32(a)			in_arch(l, le32, a)
+#define in_le16(a)			in_arch(w, le16, a)
+
+#define out_be32(a, v)			out_arch(l, be32, a, v)
+#define out_be16(a, v)			out_arch(w, be16, a, v)
+
+#define in_be32(a)			in_arch(l, be32, a)
+#define in_be16(a)			in_arch(w, be16, a)
+
+#define out_8(a, v)			__raw_writeb(v, a)
+#define in_8(a)				__raw_readb(a)
+
+/*
+ * Clear and set bits in one shot. These macros can be used to clear and
+ * set multiple bits in a register using a single call. These macros can
+ * also be used to set a multiple-bit bit pattern using a mask, by
+ * specifying the mask in the 'clear' parameter and the new bit pattern
+ * in the 'set' parameter.
+ */
+
+#define clrbits(type, addr, clear) \
+	out_##type((addr), in_##type(addr) & ~(clear))
+
+#define setbits(type, addr, set) \
+	out_##type((addr), in_##type(addr) | (set))
+
+#define clrsetbits(type, addr, clear, set) \
+	out_##type((addr), (in_##type(addr) & ~(clear)) | (set))
+
+#define clrbits_be32(addr, clear) clrbits(be32, addr, clear)
+#define setbits_be32(addr, set) setbits(be32, addr, set)
+#define clrsetbits_be32(addr, clear, set) clrsetbits(be32, addr, clear, set)
+
+#define clrbits_le32(addr, clear) clrbits(le32, addr, clear)
+#define setbits_le32(addr, set) setbits(le32, addr, set)
+#define clrsetbits_le32(addr, clear, set) clrsetbits(le32, addr, clear, set)
+
+#define clrbits_be16(addr, clear) clrbits(be16, addr, clear)
+#define setbits_be16(addr, set) setbits(be16, addr, set)
+#define clrsetbits_be16(addr, clear, set) clrsetbits(be16, addr, clear, set)
+
+#define clrbits_le16(addr, clear) clrbits(le16, addr, clear)
+#define setbits_le16(addr, set) setbits(le16, addr, set)
+#define clrsetbits_le16(addr, clear, set) clrsetbits(le16, addr, clear, set)
+
+#define clrbits_8(addr, clear) clrbits(8, addr, clear)
+#define setbits_8(addr, set) setbits(8, addr, set)
+#define clrsetbits_8(addr, clear, set) clrsetbits(8, addr, clear, set)
+
+
+/*
+ *  IO port access primitives
+ *  -------------------------
+ *
+ * LoongArch doesn't have special IO access instructions just like
+ * ARM and RISC-V all IO is either memory mapped or IOCSR mapped.
+ *
+ * Note that these are defined to perform little endian accesses
+ * only.  Their primary purpose is to access PCI and ISA peripherals.
+ */
+#ifdef __io
+#define outb(v, p)			__raw_writeb(v, __io(p))
+#define outw(v, p)			__raw_writew(cpu_to_le16(v), __io(p))
+#define outl(v, p)			__raw_writel(cpu_to_le32(v), __io(p))
+
+#define inb(p)	({ unsigned int __v = __raw_readb(__io(p)); __v; })
+#define inw(p)	({ unsigned int __v = le16_to_cpu(__raw_readw(__io(p))); __v; })
+#define inl(p)	({ unsigned int __v = le32_to_cpu(__raw_readl(__io(p))); __v; })
+
+#define outsb(p, d, l)			writesb(__io(p), d, l)
+#define outsw(p, d, l)			writesw(__io(p), d, l)
+#define outsl(p, d, l)			writesl(__io(p), d, l)
+
+#define insb(p, d, l)			readsb(__io(p), d, l)
+#define insw(p, d, l)			readsw(__io(p), d, l)
+#define insl(p, d, l)			readsl(__io(p), d, l)
+
+static inline void readsb(const volatile void __iomem *addr, void *data,
+			  unsigned int bytelen)
+{
+	unsigned char *ptr;
+	unsigned char *ptr2;
+
+	ptr = (unsigned char *)addr;
+	ptr2 = (unsigned char *)data;
+
+	while (bytelen) {
+		*ptr2 = *ptr;
+		ptr2++;
+		bytelen--;
+	}
+}
+
+static inline void readsw(const volatile void __iomem *addr, void *data,
+			  unsigned int wordlen)
+{
+	unsigned short *ptr;
+	unsigned short *ptr2;
+
+	ptr = (unsigned short *)addr;
+	ptr2 = (unsigned short *)data;
+
+	while (wordlen) {
+		*ptr2 = *ptr;
+		ptr2++;
+		wordlen--;
+	}
+}
+
+static inline void readsl(const volatile void __iomem *addr, void *data,
+			  unsigned int longlen)
+{
+	unsigned int *ptr;
+	unsigned int *ptr2;
+
+	ptr = (unsigned int *)addr;
+	ptr2 = (unsigned int *)data;
+
+	while (longlen) {
+		*ptr2 = *ptr;
+		ptr2++;
+		longlen--;
+	}
+}
+
+static inline void writesb(volatile void __iomem *addr, const void *data,
+			   unsigned int bytelen)
+{
+	unsigned char *ptr;
+	unsigned char *ptr2;
+
+	ptr = (unsigned char *)addr;
+	ptr2 = (unsigned char *)data;
+
+	while (bytelen) {
+		*ptr = *ptr2;
+		ptr2++;
+		bytelen--;
+	}
+}
+
+static inline void writesw(volatile void __iomem *addr, const void *data,
+			   unsigned int wordlen)
+{
+	unsigned short *ptr;
+	unsigned short *ptr2;
+
+	ptr = (unsigned short *)addr;
+	ptr2 = (unsigned short *)data;
+
+	while (wordlen) {
+		*ptr = *ptr2;
+		ptr2++;
+		wordlen--;
+	}
+}
+
+static inline void writesl(volatile void __iomem *addr, const void *data,
+			   unsigned int longlen)
+{
+	unsigned int *ptr;
+	unsigned int *ptr2;
+
+	ptr = (unsigned int *)addr;
+	ptr2 = (unsigned int *)data;
+
+	while (longlen) {
+		*ptr = *ptr2;
+		ptr2++;
+		longlen--;
+	}
+}
+
+#define readsb readsb
+#define readsw readsw
+#define readsl readsl
+#define writesb writesb
+#define writesw writesw
+#define writesl writesl
+
+#endif
+
+#define outb_p(val, port)		outb((val), (port))
+#define outw_p(val, port)		outw((val), (port))
+#define outl_p(val, port)		outl((val), (port))
+#define inb_p(port)			inb((port))
+#define inw_p(port)			inw((port))
+#define inl_p(port)			inl((port))
+
+#define outsb_p(port, from, len)	outsb(port, from, len)
+#define outsw_p(port, from, len)	outsw(port, from, len)
+#define outsl_p(port, from, len)	outsl(port, from, len)
+#define insb_p(port, to, len)		insb(port, to, len)
+#define insw_p(port, to, len)		insw(port, to, len)
+#define insl_p(port, to, len)		insl(port, to, len)
+
+/*
+ * Unordered I/O memory access primitives.  These are even more relaxed than
+ * the relaxed versions, as they don't even order accesses between successive
+ * operations to the I/O regions.
+ */
+#define readb_cpu(c)		({ u8  __r = __raw_readb(c); __r; })
+#define readw_cpu(c)		({ u16 __r = le16_to_cpu((__force __le16)__raw_readw(c)); __r; })
+#define readl_cpu(c)		({ u32 __r = le32_to_cpu((__force __le32)__raw_readl(c)); __r; })
+
+#define writeb_cpu(v, c)	((void)__raw_writeb((v), (c)))
+#define writew_cpu(v, c)	((void)__raw_writew((__force u16)cpu_to_le16(v), (c)))
+#define writel_cpu(v, c)	((void)__raw_writel((__force u32)cpu_to_le32(v), (c)))
+
+#ifdef CONFIG_64BIT
+#define readq_cpu(c)		({ u64 __r = le64_to_cpu((__force __le64)__raw_readq(c)); __r; })
+#define writeq_cpu(v, c)	((void)__raw_writeq((__force u64)cpu_to_le64(v), (c)))
+#endif
+
+/*
+ * Relaxed I/O memory access primitives. These follow the Device memory
+ * ordering rules but do not guarantee any ordering relative to Normal memory
+ * accesses.  These are defined to order the indicated access (either a read or
+ * write) with all other I/O memory accesses to the same peripheral. Since the
+ * platform specification defines that all I/O regions are strongly ordered on
+ * channel 0, no explicit fences are required to enforce this ordering.
+ */
+/* FIXME: These are now the same as asm-generic */
+#define __io_rbr()		do {} while (0)
+#define __io_rar()		do {} while (0)
+#define __io_rbw()		do {} while (0)
+#define __io_raw()		do {} while (0)
+
+#define readb_relaxed(c)	({ u8  __v; __io_rbr(); __v = readb_cpu(c); __io_rar(); __v; })
+#define readw_relaxed(c)	({ u16 __v; __io_rbr(); __v = readw_cpu(c); __io_rar(); __v; })
+#define readl_relaxed(c)	({ u32 __v; __io_rbr(); __v = readl_cpu(c); __io_rar(); __v; })
+
+#define writeb_relaxed(v, c)	({ __io_rbw(); writeb_cpu((v), (c)); __io_raw(); })
+#define writew_relaxed(v, c)	({ __io_rbw(); writew_cpu((v), (c)); __io_raw(); })
+#define writel_relaxed(v, c)	({ __io_rbw(); writel_cpu((v), (c)); __io_raw(); })
+
+#ifdef CONFIG_64BIT
+#define readq_relaxed(c)	({ u64 __v; __io_rbr(); __v = readq_cpu(c); __io_rar(); __v; })
+#define writeq_relaxed(v, c)	({ __io_rbw(); writeq_cpu((v), (c)); __io_raw(); })
+#endif
+
+static inline phys_addr_t virt_to_phys(volatile const void *address)
+{
+	return TO_PHYS((unsigned long)address);
+}
+#define virt_to_phys virt_to_phys
+
+static inline void *phys_to_virt(phys_addr_t address)
+{
+	/* Assume it is always for U-Boot memory access */
+	return (void *)(address);
+}
+#define phys_to_virt phys_to_virt
+
+/* These two needs to be uncaced */
+#define MAP_NOCACHE		1
+#define MAP_WRCOMBINE	MAP_NOCACHE
+
+static inline void *map_physmem(phys_addr_t paddr, unsigned long len,
+				unsigned long flags)
+{
+	if (flags == MAP_NOCACHE)
+		return (void *)TO_UNCACHE(paddr);
+
+	/* Assume cached mapping is always for U-Boot memory access */
+	return (void *)(paddr);
+}
+#define map_physmem map_physmem
+
+#include <asm-generic/io.h>
+
+#endif	/* __ASM_LOONGARCH_IO_H */
diff --git a/arch/loongarch/include/asm/linkage.h b/arch/loongarch/include/asm/linkage.h
new file mode 100644
index 000000000000..f004bdd8efe3
--- /dev/null
+++ b/arch/loongarch/include/asm/linkage.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2024 Jiaxun Yang <jiaxun.yang@flygoat.com>
+ */
+
+#ifndef __ASM_LINKAGE_H
+#define __ASM_LINKAGE_H
+
+/* Dummy header */
+
+#endif
diff --git a/arch/loongarch/include/asm/loongarch.h b/arch/loongarch/include/asm/loongarch.h
new file mode 100644
index 000000000000..72625b38c9a7
--- /dev/null
+++ b/arch/loongarch/include/asm/loongarch.h
@@ -0,0 +1,1467 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
+ * Copyright (C) 2024 Jiaxun Yang <jiaxun.yang@flygoat.com>
+ */
+#ifndef _ASM_LOONGARCH_H
+#define _ASM_LOONGARCH_H
+
+#include <linux/bitops.h>
+#include <linux/const.h>
+#ifndef __ASSEMBLY__
+#include <linux/types.h>
+#include <larchintrin.h>
+
+/* CPUCFG */
+#define read_cpucfg(reg) __cpucfg(reg)
+
+#endif /* !__ASSEMBLY__ */
+
+/*
+ *  Configure language
+ */
+#ifdef __ASSEMBLY__
+#define _ULCAST_
+#define _U64CAST_
+#else
+#define _ULCAST_ (unsigned long)
+#define _U64CAST_ (u64)
+#endif
+
+#ifdef __ASSEMBLY__
+
+/* LoongArch Registers */
+#define REG_ZERO	0x0
+#define REG_RA		0x1
+#define REG_TP		0x2
+#define REG_SP		0x3
+#define REG_A0		0x4 /* Reused as V0 for return value */
+#define REG_A1		0x5 /* Reused as V1 for return value */
+#define REG_A2		0x6
+#define REG_A3		0x7
+#define REG_A4		0x8
+#define REG_A5		0x9
+#define REG_A6		0xa
+#define REG_A7		0xb
+#define REG_T0		0xc
+#define REG_T1		0xd
+#define REG_T2		0xe
+#define REG_T3		0xf
+#define REG_T4		0x10
+#define REG_T5		0x11
+#define REG_T6		0x12
+#define REG_T7		0x13
+#define REG_T8		0x14
+#define REG_U0		0x15 /* Kernel uses it as percpu base */
+#define REG_FP		0x16
+#define REG_S0		0x17
+#define REG_S1		0x18
+#define REG_S2		0x19
+#define REG_S3		0x1a
+#define REG_S4		0x1b
+#define REG_S5		0x1c
+#define REG_S6		0x1d
+#define REG_S7		0x1e
+#define REG_S8		0x1f
+
+#endif /* __ASSEMBLY__ */
+
+/* Bit fields for CPUCFG registers */
+#define LOONGARCH_CPUCFG0		0x0
+#define  CPUCFG0_PRID			GENMASK(31, 0)
+
+#define LOONGARCH_CPUCFG1		0x1
+#define  CPUCFG1_ISGR32			BIT(0)
+#define  CPUCFG1_ISGR64			BIT(1)
+#define  CPUCFG1_PAGING			BIT(2)
+#define  CPUCFG1_IOCSR			BIT(3)
+#define  CPUCFG1_PABITS			GENMASK(11, 4)
+#define  CPUCFG1_VABITS			GENMASK(19, 12)
+#define  CPUCFG1_UAL			BIT(20)
+#define  CPUCFG1_RI			BIT(21)
+#define  CPUCFG1_EP			BIT(22)
+#define  CPUCFG1_RPLV			BIT(23)
+#define  CPUCFG1_HUGEPG			BIT(24)
+#define  CPUCFG1_CRC32			BIT(25)
+#define  CPUCFG1_MSGINT			BIT(26)
+
+#define LOONGARCH_CPUCFG2		0x2
+#define  CPUCFG2_FP			BIT(0)
+#define  CPUCFG2_FPSP			BIT(1)
+#define  CPUCFG2_FPDP			BIT(2)
+#define  CPUCFG2_FPVERS			GENMASK(5, 3)
+#define  CPUCFG2_LSX			BIT(6)
+#define  CPUCFG2_LASX			BIT(7)
+#define  CPUCFG2_COMPLEX		BIT(8)
+#define  CPUCFG2_CRYPTO			BIT(9)
+#define  CPUCFG2_LVZP			BIT(10)
+#define  CPUCFG2_LVZVER			GENMASK(13, 11)
+#define  CPUCFG2_LLFTP			BIT(14)
+#define  CPUCFG2_LLFTPREV		GENMASK(17, 15)
+#define  CPUCFG2_X86BT			BIT(18)
+#define  CPUCFG2_ARMBT			BIT(19)
+#define  CPUCFG2_MIPSBT			BIT(20)
+#define  CPUCFG2_LSPW			BIT(21)
+#define  CPUCFG2_LAM			BIT(22)
+#define  CPUCFG2_PTW			BIT(24)
+
+#define LOONGARCH_CPUCFG3		0x3
+#define  CPUCFG3_CCDMA			BIT(0)
+#define  CPUCFG3_SFB			BIT(1)
+#define  CPUCFG3_UCACC			BIT(2)
+#define  CPUCFG3_LLEXC			BIT(3)
+#define  CPUCFG3_SCDLY			BIT(4)
+#define  CPUCFG3_LLDBAR			BIT(5)
+#define  CPUCFG3_ITLBT			BIT(6)
+#define  CPUCFG3_ICACHET		BIT(7)
+#define  CPUCFG3_SPW_LVL		GENMASK(10, 8)
+#define  CPUCFG3_SPW_HG_HF		BIT(11)
+#define  CPUCFG3_RVA			BIT(12)
+#define  CPUCFG3_RVAMAX			GENMASK(16, 13)
+
+#define LOONGARCH_CPUCFG4		0x4
+#define  CPUCFG4_CCFREQ			GENMASK(31, 0)
+
+#define LOONGARCH_CPUCFG5		0x5
+#define  CPUCFG5_CCMUL			GENMASK(15, 0)
+#define  CPUCFG5_CCDIV			GENMASK(31, 16)
+
+#define LOONGARCH_CPUCFG6		0x6
+#define  CPUCFG6_PMP			BIT(0)
+#define  CPUCFG6_PAMVER			GENMASK(3, 1)
+#define  CPUCFG6_PMNUM			GENMASK(7, 4)
+#define  CPUCFG6_PMBITS			GENMASK(13, 8)
+#define  CPUCFG6_UPM			BIT(14)
+
+#define LOONGARCH_CPUCFG16		0x10
+#define  CPUCFG16_L1_IUPRE		BIT(0)
+#define  CPUCFG16_L1_IUUNIFY		BIT(1)
+#define  CPUCFG16_L1_DPRE		BIT(2)
+#define  CPUCFG16_L2_IUPRE		BIT(3)
+#define  CPUCFG16_L2_IUUNIFY		BIT(4)
+#define  CPUCFG16_L2_IUPRIV		BIT(5)
+#define  CPUCFG16_L2_IUINCL		BIT(6)
+#define  CPUCFG16_L2_DPRE		BIT(7)
+#define  CPUCFG16_L2_DPRIV		BIT(8)
+#define  CPUCFG16_L2_DINCL		BIT(9)
+#define  CPUCFG16_L3_IUPRE		BIT(10)
+#define  CPUCFG16_L3_IUUNIFY		BIT(11)
+#define  CPUCFG16_L3_IUPRIV		BIT(12)
+#define  CPUCFG16_L3_IUINCL		BIT(13)
+#define  CPUCFG16_L3_DPRE		BIT(14)
+#define  CPUCFG16_L3_DPRIV		BIT(15)
+#define  CPUCFG16_L3_DINCL		BIT(16)
+
+#define LOONGARCH_CPUCFG17		0x11
+#define LOONGARCH_CPUCFG18		0x12
+#define LOONGARCH_CPUCFG19		0x13
+#define LOONGARCH_CPUCFG20		0x14
+#define  CPUCFG_CACHE_WAYS_M		GENMASK(15, 0)
+#define  CPUCFG_CACHE_SETS_M		GENMASK(23, 16)
+#define  CPUCFG_CACHE_LSIZE_M		GENMASK(30, 24)
+#define  CPUCFG_CACHE_WAYS		0
+#define  CPUCFG_CACHE_SETS		16
+#define  CPUCFG_CACHE_LSIZE		24
+
+#define LOONGARCH_CPUCFG48		0x30
+#define  CPUCFG48_MCSR_LCK		BIT(0)
+#define  CPUCFG48_NAP_EN		BIT(1)
+#define  CPUCFG48_VFPU_CG		BIT(2)
+#define  CPUCFG48_RAM_CG		BIT(3)
+
+/*
+ * CPUCFG index area: 0x40000000 -- 0x400000ff
+ * SW emulation for KVM hypervirsor
+ */
+#define CPUCFG_KVM_BASE			0x40000000
+#define CPUCFG_KVM_SIZE			0x100
+
+#define CPUCFG_KVM_SIG			(CPUCFG_KVM_BASE + 0)
+#define  KVM_SIGNATURE			"KVM\0"
+#define CPUCFG_KVM_FEATURE		(CPUCFG_KVM_BASE + 4)
+#define  KVM_FEATURE_IPI		BIT(1)
+
+#ifndef __ASSEMBLY__
+
+/* CSR */
+#define csr_read32(reg) __csrrd_w(reg)
+#define csr_read64(reg) __csrrd_d(reg)
+#define csr_write32(val, reg) __csrwr_w(val, reg)
+#define csr_write64(val, reg) __csrwr_d(val, reg)
+#define csr_xchg32(val, mask, reg) __csrxchg_w(val, mask, reg)
+#define csr_xchg64(val, mask, reg) __csrxchg_d(val, mask, reg)
+
+/* IOCSR */
+#define iocsr_read32(reg) __iocsrrd_w(reg)
+#define iocsr_read64(reg) __iocsrrd_d(reg)
+#define iocsr_write32(val, reg) __iocsrwr_w(val, reg)
+#define iocsr_write64(val, reg) __iocsrwr_d(val, reg)
+
+#endif /* !__ASSEMBLY__ */
+
+/* CSR register number */
+
+/* Basic CSR registers */
+#define LOONGARCH_CSR_CRMD		0x0	/* Current mode info */
+#define  CSR_CRMD_WE_SHIFT		9
+#define  CSR_CRMD_WE			(_ULCAST_(0x1) << CSR_CRMD_WE_SHIFT)
+#define  CSR_CRMD_DACM_SHIFT		7
+#define  CSR_CRMD_DACM_WIDTH		2
+#define  CSR_CRMD_DACM			(_ULCAST_(0x3) << CSR_CRMD_DACM_SHIFT)
+#define  CSR_CRMD_DACF_SHIFT		5
+#define  CSR_CRMD_DACF_WIDTH		2
+#define  CSR_CRMD_DACF			(_ULCAST_(0x3) << CSR_CRMD_DACF_SHIFT)
+#define  CSR_CRMD_PG_SHIFT		4
+#define  CSR_CRMD_PG			(_ULCAST_(0x1) << CSR_CRMD_PG_SHIFT)
+#define  CSR_CRMD_DA_SHIFT		3
+#define  CSR_CRMD_DA			(_ULCAST_(0x1) << CSR_CRMD_DA_SHIFT)
+#define  CSR_CRMD_IE_SHIFT		2
+#define  CSR_CRMD_IE			(_ULCAST_(0x1) << CSR_CRMD_IE_SHIFT)
+#define  CSR_CRMD_PLV_SHIFT		0
+#define  CSR_CRMD_PLV_WIDTH		2
+#define  CSR_CRMD_PLV			(_ULCAST_(0x3) << CSR_CRMD_PLV_SHIFT)
+
+#define PLV_KERN			0
+#define PLV_USER			3
+#define PLV_MASK			0x3
+
+#define LOONGARCH_CSR_PRMD		0x1	/* Prev-exception mode info */
+#define  CSR_PRMD_PWE_SHIFT		3
+#define  CSR_PRMD_PWE			(_ULCAST_(0x1) << CSR_PRMD_PWE_SHIFT)
+#define  CSR_PRMD_PIE_SHIFT		2
+#define  CSR_PRMD_PIE			(_ULCAST_(0x1) << CSR_PRMD_PIE_SHIFT)
+#define  CSR_PRMD_PPLV_SHIFT		0
+#define  CSR_PRMD_PPLV_WIDTH		2
+#define  CSR_PRMD_PPLV			(_ULCAST_(0x3) << CSR_PRMD_PPLV_SHIFT)
+
+#define LOONGARCH_CSR_EUEN		0x2	/* Extended unit enable */
+#define  CSR_EUEN_LBTEN_SHIFT		3
+#define  CSR_EUEN_LBTEN			(_ULCAST_(0x1) << CSR_EUEN_LBTEN_SHIFT)
+#define  CSR_EUEN_LASXEN_SHIFT		2
+#define  CSR_EUEN_LASXEN		(_ULCAST_(0x1) << CSR_EUEN_LASXEN_SHIFT)
+#define  CSR_EUEN_LSXEN_SHIFT		1
+#define  CSR_EUEN_LSXEN			(_ULCAST_(0x1) << CSR_EUEN_LSXEN_SHIFT)
+#define  CSR_EUEN_FPEN_SHIFT		0
+#define  CSR_EUEN_FPEN			(_ULCAST_(0x1) << CSR_EUEN_FPEN_SHIFT)
+
+#define LOONGARCH_CSR_MISC		0x3	/* Misc config */
+
+#define LOONGARCH_CSR_ECFG		0x4	/* Exception config */
+#define  CSR_ECFG_VS_SHIFT		16
+#define  CSR_ECFG_VS_WIDTH		3
+#define  CSR_ECFG_VS_SHIFT_END		(CSR_ECFG_VS_SHIFT + CSR_ECFG_VS_WIDTH - 1)
+#define  CSR_ECFG_VS			(_ULCAST_(0x7) << CSR_ECFG_VS_SHIFT)
+#define  CSR_ECFG_IM_SHIFT		0
+#define  CSR_ECFG_IM_WIDTH		14
+#define  CSR_ECFG_IM			(_ULCAST_(0x3fff) << CSR_ECFG_IM_SHIFT)
+
+#define LOONGARCH_CSR_ESTAT		0x5	/* Exception status */
+#define  CSR_ESTAT_ESUBCODE_SHIFT	22
+#define  CSR_ESTAT_ESUBCODE_WIDTH	9
+#define  CSR_ESTAT_ESUBCODE		(_ULCAST_(0x1ff) << CSR_ESTAT_ESUBCODE_SHIFT)
+#define  CSR_ESTAT_EXC_SHIFT		16
+#define  CSR_ESTAT_EXC_WIDTH		6
+#define  CSR_ESTAT_EXC			(_ULCAST_(0x3f) << CSR_ESTAT_EXC_SHIFT)
+#define  CSR_ESTAT_IS_SHIFT		0
+#define  CSR_ESTAT_IS_WIDTH		14
+#define  CSR_ESTAT_IS			(_ULCAST_(0x3fff) << CSR_ESTAT_IS_SHIFT)
+
+#define LOONGARCH_CSR_ERA		0x6	/* ERA */
+
+#define LOONGARCH_CSR_BADV		0x7	/* Bad virtual address */
+
+#define LOONGARCH_CSR_BADI		0x8	/* Bad instruction */
+
+#define LOONGARCH_CSR_EENTRY		0xc	/* Exception entry */
+
+/* TLB related CSR registers */
+#define LOONGARCH_CSR_TLBIDX		0x10	/* TLB Index, EHINV, PageSize, NP */
+#define  CSR_TLBIDX_EHINV_SHIFT		31
+#define  CSR_TLBIDX_EHINV		(_ULCAST_(1) << CSR_TLBIDX_EHINV_SHIFT)
+#define  CSR_TLBIDX_PS_SHIFT		24
+#define  CSR_TLBIDX_PS_WIDTH		6
+#define  CSR_TLBIDX_PS			(_ULCAST_(0x3f) << CSR_TLBIDX_PS_SHIFT)
+#define  CSR_TLBIDX_IDX_SHIFT		0
+#define  CSR_TLBIDX_IDX_WIDTH		12
+#define  CSR_TLBIDX_IDX			(_ULCAST_(0xfff) << CSR_TLBIDX_IDX_SHIFT)
+#define  CSR_TLBIDX_SIZEM		0x3f000000
+#define  CSR_TLBIDX_SIZE		CSR_TLBIDX_PS_SHIFT
+#define  CSR_TLBIDX_IDXM		0xfff
+#define  CSR_INVALID_ENTRY(e)		(CSR_TLBIDX_EHINV | e)
+
+#define LOONGARCH_CSR_TLBEHI		0x11	/* TLB EntryHi */
+
+#define LOONGARCH_CSR_TLBELO0		0x12	/* TLB EntryLo0 */
+#define  CSR_TLBLO0_RPLV_SHIFT		63
+#define  CSR_TLBLO0_RPLV		(_ULCAST_(0x1) << CSR_TLBLO0_RPLV_SHIFT)
+#define  CSR_TLBLO0_NX_SHIFT		62
+#define  CSR_TLBLO0_NX			(_ULCAST_(0x1) << CSR_TLBLO0_NX_SHIFT)
+#define  CSR_TLBLO0_NR_SHIFT		61
+#define  CSR_TLBLO0_NR			(_ULCAST_(0x1) << CSR_TLBLO0_NR_SHIFT)
+#define  CSR_TLBLO0_PFN_SHIFT		12
+#define  CSR_TLBLO0_PFN_WIDTH		36
+#define  CSR_TLBLO0_PFN			(_ULCAST_(0xfffffffff) << CSR_TLBLO0_PFN_SHIFT)
+#define  CSR_TLBLO0_GLOBAL_SHIFT	6
+#define  CSR_TLBLO0_GLOBAL		(_ULCAST_(0x1) << CSR_TLBLO0_GLOBAL_SHIFT)
+#define  CSR_TLBLO0_CCA_SHIFT		4
+#define  CSR_TLBLO0_CCA_WIDTH		2
+#define  CSR_TLBLO0_CCA			(_ULCAST_(0x3) << CSR_TLBLO0_CCA_SHIFT)
+#define  CSR_TLBLO0_PLV_SHIFT		2
+#define  CSR_TLBLO0_PLV_WIDTH		2
+#define  CSR_TLBLO0_PLV			(_ULCAST_(0x3) << CSR_TLBLO0_PLV_SHIFT)
+#define  CSR_TLBLO0_WE_SHIFT		1
+#define  CSR_TLBLO0_WE			(_ULCAST_(0x1) << CSR_TLBLO0_WE_SHIFT)
+#define  CSR_TLBLO0_V_SHIFT		0
+#define  CSR_TLBLO0_V			(_ULCAST_(0x1) << CSR_TLBLO0_V_SHIFT)
+
+#define LOONGARCH_CSR_TLBELO1		0x13	/* TLB EntryLo1 */
+#define  CSR_TLBLO1_RPLV_SHIFT		63
+#define  CSR_TLBLO1_RPLV		(_ULCAST_(0x1) << CSR_TLBLO1_RPLV_SHIFT)
+#define  CSR_TLBLO1_NX_SHIFT		62
+#define  CSR_TLBLO1_NX			(_ULCAST_(0x1) << CSR_TLBLO1_NX_SHIFT)
+#define  CSR_TLBLO1_NR_SHIFT		61
+#define  CSR_TLBLO1_NR			(_ULCAST_(0x1) << CSR_TLBLO1_NR_SHIFT)
+#define  CSR_TLBLO1_PFN_SHIFT		12
+#define  CSR_TLBLO1_PFN_WIDTH		36
+#define  CSR_TLBLO1_PFN			(_ULCAST_(0xfffffffff) << CSR_TLBLO1_PFN_SHIFT)
+#define  CSR_TLBLO1_GLOBAL_SHIFT	6
+#define  CSR_TLBLO1_GLOBAL		(_ULCAST_(0x1) << CSR_TLBLO1_GLOBAL_SHIFT)
+#define  CSR_TLBLO1_CCA_SHIFT		4
+#define  CSR_TLBLO1_CCA_WIDTH		2
+#define  CSR_TLBLO1_CCA			(_ULCAST_(0x3) << CSR_TLBLO1_CCA_SHIFT)
+#define  CSR_TLBLO1_PLV_SHIFT		2
+#define  CSR_TLBLO1_PLV_WIDTH		2
+#define  CSR_TLBLO1_PLV			(_ULCAST_(0x3) << CSR_TLBLO1_PLV_SHIFT)
+#define  CSR_TLBLO1_WE_SHIFT		1
+#define  CSR_TLBLO1_WE			(_ULCAST_(0x1) << CSR_TLBLO1_WE_SHIFT)
+#define  CSR_TLBLO1_V_SHIFT		0
+#define  CSR_TLBLO1_V			(_ULCAST_(0x1) << CSR_TLBLO1_V_SHIFT)
+
+#define LOONGARCH_CSR_GTLBC		0x15	/* Guest TLB control */
+#define  CSR_GTLBC_TGID_SHIFT		16
+#define  CSR_GTLBC_TGID_WIDTH		8
+#define  CSR_GTLBC_TGID_SHIFT_END	(CSR_GTLBC_TGID_SHIFT + CSR_GTLBC_TGID_WIDTH - 1)
+#define  CSR_GTLBC_TGID			(_ULCAST_(0xff) << CSR_GTLBC_TGID_SHIFT)
+#define  CSR_GTLBC_TOTI_SHIFT		13
+#define  CSR_GTLBC_TOTI			(_ULCAST_(0x1) << CSR_GTLBC_TOTI_SHIFT)
+#define  CSR_GTLBC_USETGID_SHIFT	12
+#define  CSR_GTLBC_USETGID		(_ULCAST_(0x1) << CSR_GTLBC_USETGID_SHIFT)
+#define  CSR_GTLBC_GMTLBSZ_SHIFT	0
+#define  CSR_GTLBC_GMTLBSZ_WIDTH	6
+#define  CSR_GTLBC_GMTLBSZ		(_ULCAST_(0x3f) << CSR_GTLBC_GMTLBSZ_SHIFT)
+
+#define LOONGARCH_CSR_TRGP		0x16	/* TLBR read guest info */
+#define  CSR_TRGP_RID_SHIFT		16
+#define  CSR_TRGP_RID_WIDTH		8
+#define  CSR_TRGP_RID			(_ULCAST_(0xff) << CSR_TRGP_RID_SHIFT)
+#define  CSR_TRGP_GTLB_SHIFT		0
+#define  CSR_TRGP_GTLB			(1 << CSR_TRGP_GTLB_SHIFT)
+
+#define LOONGARCH_CSR_ASID		0x18	/* ASID */
+#define  CSR_ASID_BIT_SHIFT		16	/* ASIDBits */
+#define  CSR_ASID_BIT_WIDTH		8
+#define  CSR_ASID_BIT			(_ULCAST_(0xff) << CSR_ASID_BIT_SHIFT)
+#define  CSR_ASID_ASID_SHIFT		0
+#define  CSR_ASID_ASID_WIDTH		10
+#define  CSR_ASID_ASID			(_ULCAST_(0x3ff) << CSR_ASID_ASID_SHIFT)
+
+#define LOONGARCH_CSR_PGDL		0x19	/* Page table base address when VA[VALEN-1] = 0 */
+
+#define LOONGARCH_CSR_PGDH		0x1a	/* Page table base address when VA[VALEN-1] = 1 */
+
+#define LOONGARCH_CSR_PGD		0x1b	/* Page table base */
+
+#define LOONGARCH_CSR_PWCTL0		0x1c	/* PWCtl0 */
+#define  CSR_PWCTL0_PTEW_SHIFT		30
+#define  CSR_PWCTL0_PTEW_WIDTH		2
+#define  CSR_PWCTL0_PTEW		(_ULCAST_(0x3) << CSR_PWCTL0_PTEW_SHIFT)
+#define  CSR_PWCTL0_DIR1WIDTH_SHIFT	25
+#define  CSR_PWCTL0_DIR1WIDTH_WIDTH	5
+#define  CSR_PWCTL0_DIR1WIDTH		(_ULCAST_(0x1f) << CSR_PWCTL0_DIR1WIDTH_SHIFT)
+#define  CSR_PWCTL0_DIR1BASE_SHIFT	20
+#define  CSR_PWCTL0_DIR1BASE_WIDTH	5
+#define  CSR_PWCTL0_DIR1BASE		(_ULCAST_(0x1f) << CSR_PWCTL0_DIR1BASE_SHIFT)
+#define  CSR_PWCTL0_DIR0WIDTH_SHIFT	15
+#define  CSR_PWCTL0_DIR0WIDTH_WIDTH	5
+#define  CSR_PWCTL0_DIR0WIDTH		(_ULCAST_(0x1f) << CSR_PWCTL0_DIR0WIDTH_SHIFT)
+#define  CSR_PWCTL0_DIR0BASE_SHIFT	10
+#define  CSR_PWCTL0_DIR0BASE_WIDTH	5
+#define  CSR_PWCTL0_DIR0BASE		(_ULCAST_(0x1f) << CSR_PWCTL0_DIR0BASE_SHIFT)
+#define  CSR_PWCTL0_PTWIDTH_SHIFT	5
+#define  CSR_PWCTL0_PTWIDTH_WIDTH	5
+#define  CSR_PWCTL0_PTWIDTH		(_ULCAST_(0x1f) << CSR_PWCTL0_PTWIDTH_SHIFT)
+#define  CSR_PWCTL0_PTBASE_SHIFT	0
+#define  CSR_PWCTL0_PTBASE_WIDTH	5
+#define  CSR_PWCTL0_PTBASE		(_ULCAST_(0x1f) << CSR_PWCTL0_PTBASE_SHIFT)
+
+#define LOONGARCH_CSR_PWCTL1		0x1d	/* PWCtl1 */
+#define  CSR_PWCTL1_PTW_SHIFT		24
+#define  CSR_PWCTL1_PTW_WIDTH		1
+#define  CSR_PWCTL1_PTW			(_ULCAST_(0x1) << CSR_PWCTL1_PTW_SHIFT)
+#define  CSR_PWCTL1_DIR3WIDTH_SHIFT	18
+#define  CSR_PWCTL1_DIR3WIDTH_WIDTH	5
+#define  CSR_PWCTL1_DIR3WIDTH		(_ULCAST_(0x1f) << CSR_PWCTL1_DIR3WIDTH_SHIFT)
+#define  CSR_PWCTL1_DIR3BASE_SHIFT	12
+#define  CSR_PWCTL1_DIR3BASE_WIDTH	5
+#define  CSR_PWCTL1_DIR3BASE		(_ULCAST_(0x1f) << CSR_PWCTL0_DIR3BASE_SHIFT)
+#define  CSR_PWCTL1_DIR2WIDTH_SHIFT	6
+#define  CSR_PWCTL1_DIR2WIDTH_WIDTH	5
+#define  CSR_PWCTL1_DIR2WIDTH		(_ULCAST_(0x1f) << CSR_PWCTL1_DIR2WIDTH_SHIFT)
+#define  CSR_PWCTL1_DIR2BASE_SHIFT	0
+#define  CSR_PWCTL1_DIR2BASE_WIDTH	5
+#define  CSR_PWCTL1_DIR2BASE		(_ULCAST_(0x1f) << CSR_PWCTL0_DIR2BASE_SHIFT)
+
+#define LOONGARCH_CSR_STLBPGSIZE	0x1e
+#define  CSR_STLBPGSIZE_PS_WIDTH	6
+#define  CSR_STLBPGSIZE_PS		(_ULCAST_(0x3f))
+
+#define LOONGARCH_CSR_RVACFG		0x1f
+#define  CSR_RVACFG_RDVA_WIDTH		4
+#define  CSR_RVACFG_RDVA		(_ULCAST_(0xf))
+
+/* Config CSR registers */
+#define LOONGARCH_CSR_CPUID		0x20	/* CPU core id */
+#define  CSR_CPUID_COREID_WIDTH		9
+#define  CSR_CPUID_COREID		_ULCAST_(0x1ff)
+
+#define LOONGARCH_CSR_PRCFG1		0x21	/* Config1 */
+#define  CSR_CONF1_VSMAX_SHIFT		12
+#define  CSR_CONF1_VSMAX_WIDTH		3
+#define  CSR_CONF1_VSMAX		(_ULCAST_(7) << CSR_CONF1_VSMAX_SHIFT)
+#define  CSR_CONF1_TMRBITS_SHIFT	4
+#define  CSR_CONF1_TMRBITS_WIDTH	8
+#define  CSR_CONF1_TMRBITS		(_ULCAST_(0xff) << CSR_CONF1_TMRBITS_SHIFT)
+#define  CSR_CONF1_KSNUM_WIDTH		4
+#define  CSR_CONF1_KSNUM		_ULCAST_(0xf)
+
+#define LOONGARCH_CSR_PRCFG2		0x22	/* Config2 */
+#define  CSR_CONF2_PGMASK_SUPP		0x3ffff000
+
+#define LOONGARCH_CSR_PRCFG3		0x23	/* Config3 */
+#define  CSR_CONF3_STLBIDX_SHIFT	20
+#define  CSR_CONF3_STLBIDX_WIDTH	6
+#define  CSR_CONF3_STLBIDX		(_ULCAST_(0x3f) << CSR_CONF3_STLBIDX_SHIFT)
+#define  CSR_CONF3_STLBWAYS_SHIFT	12
+#define  CSR_CONF3_STLBWAYS_WIDTH	8
+#define  CSR_CONF3_STLBWAYS		(_ULCAST_(0xff) << CSR_CONF3_STLBWAYS_SHIFT)
+#define  CSR_CONF3_MTLBSIZE_SHIFT	4
+#define  CSR_CONF3_MTLBSIZE_WIDTH	8
+#define  CSR_CONF3_MTLBSIZE		(_ULCAST_(0xff) << CSR_CONF3_MTLBSIZE_SHIFT)
+#define  CSR_CONF3_TLBTYPE_SHIFT	0
+#define  CSR_CONF3_TLBTYPE_WIDTH	4
+#define  CSR_CONF3_TLBTYPE		(_ULCAST_(0xf) << CSR_CONF3_TLBTYPE_SHIFT)
+
+/* KSave registers */
+#define LOONGARCH_CSR_KS0		0x30
+#define LOONGARCH_CSR_KS1		0x31
+#define LOONGARCH_CSR_KS2		0x32
+#define LOONGARCH_CSR_KS3		0x33
+#define LOONGARCH_CSR_KS4		0x34
+#define LOONGARCH_CSR_KS5		0x35
+#define LOONGARCH_CSR_KS6		0x36
+#define LOONGARCH_CSR_KS7		0x37
+#define LOONGARCH_CSR_KS8		0x38
+
+/* Exception allocated KS0, KS1 and KS2 statically */
+#define EXCEPTION_KS0			LOONGARCH_CSR_KS0
+#define EXCEPTION_KS1			LOONGARCH_CSR_KS1
+#define EXCEPTION_KS2			LOONGARCH_CSR_KS2
+#define EXC_KSAVE_MASK			(1 << 0 | 1 << 1 | 1 << 2)
+
+/* Percpu-data base allocated KS3 statically */
+#define PERCPU_BASE_KS			LOONGARCH_CSR_KS3
+#define PERCPU_KSAVE_MASK		(1 << 3)
+
+/* KVM allocated KS4 and KS5 statically */
+#define KVM_VCPU_KS			LOONGARCH_CSR_KS4
+#define KVM_TEMP_KS			LOONGARCH_CSR_KS5
+#define KVM_KSAVE_MASK			(1 << 4 | 1 << 5)
+
+/* Timer registers */
+#define LOONGARCH_CSR_TMID		0x40	/* Timer ID */
+
+#define LOONGARCH_CSR_TCFG		0x41	/* Timer config */
+#define  CSR_TCFG_VAL_SHIFT		2
+#define	 CSR_TCFG_VAL_WIDTH		48
+#define  CSR_TCFG_VAL			(_ULCAST_(0x3fffffffffff) << CSR_TCFG_VAL_SHIFT)
+#define  CSR_TCFG_PERIOD_SHIFT		1
+#define  CSR_TCFG_PERIOD		(_ULCAST_(0x1) << CSR_TCFG_PERIOD_SHIFT)
+#define  CSR_TCFG_EN			(_ULCAST_(0x1))
+
+#define LOONGARCH_CSR_TVAL		0x42	/* Timer value */
+
+#define LOONGARCH_CSR_CNTC		0x43	/* Timer offset */
+
+#define LOONGARCH_CSR_TINTCLR		0x44	/* Timer interrupt clear */
+#define  CSR_TINTCLR_TI_SHIFT		0
+#define  CSR_TINTCLR_TI			(1 << CSR_TINTCLR_TI_SHIFT)
+
+/* Guest registers */
+#define LOONGARCH_CSR_GSTAT		0x50	/* Guest status */
+#define  CSR_GSTAT_GID_SHIFT		16
+#define  CSR_GSTAT_GID_WIDTH		8
+#define  CSR_GSTAT_GID_SHIFT_END	(CSR_GSTAT_GID_SHIFT + CSR_GSTAT_GID_WIDTH - 1)
+#define  CSR_GSTAT_GID			(_ULCAST_(0xff) << CSR_GSTAT_GID_SHIFT)
+#define  CSR_GSTAT_GIDBIT_SHIFT		4
+#define  CSR_GSTAT_GIDBIT_WIDTH		6
+#define  CSR_GSTAT_GIDBIT		(_ULCAST_(0x3f) << CSR_GSTAT_GIDBIT_SHIFT)
+#define  CSR_GSTAT_PVM_SHIFT		1
+#define  CSR_GSTAT_PVM			(_ULCAST_(0x1) << CSR_GSTAT_PVM_SHIFT)
+#define  CSR_GSTAT_VM_SHIFT		0
+#define  CSR_GSTAT_VM			(_ULCAST_(0x1) << CSR_GSTAT_VM_SHIFT)
+
+#define LOONGARCH_CSR_GCFG		0x51	/* Guest config */
+#define  CSR_GCFG_GPERF_SHIFT		24
+#define  CSR_GCFG_GPERF_WIDTH		3
+#define  CSR_GCFG_GPERF			(_ULCAST_(0x7) << CSR_GCFG_GPERF_SHIFT)
+#define  CSR_GCFG_GCI_SHIFT		20
+#define  CSR_GCFG_GCI_WIDTH		2
+#define  CSR_GCFG_GCI			(_ULCAST_(0x3) << CSR_GCFG_GCI_SHIFT)
+#define  CSR_GCFG_GCI_ALL		(_ULCAST_(0x0) << CSR_GCFG_GCI_SHIFT)
+#define  CSR_GCFG_GCI_HIT		(_ULCAST_(0x1) << CSR_GCFG_GCI_SHIFT)
+#define  CSR_GCFG_GCI_SECURE		(_ULCAST_(0x2) << CSR_GCFG_GCI_SHIFT)
+#define  CSR_GCFG_GCIP_SHIFT		16
+#define  CSR_GCFG_GCIP			(_ULCAST_(0xf) << CSR_GCFG_GCIP_SHIFT)
+#define  CSR_GCFG_GCIP_ALL		(_ULCAST_(0x1) << CSR_GCFG_GCIP_SHIFT)
+#define  CSR_GCFG_GCIP_HIT		(_ULCAST_(0x1) << (CSR_GCFG_GCIP_SHIFT + 1))
+#define  CSR_GCFG_GCIP_SECURE		(_ULCAST_(0x1) << (CSR_GCFG_GCIP_SHIFT + 2))
+#define  CSR_GCFG_TORU_SHIFT		15
+#define  CSR_GCFG_TORU			(_ULCAST_(0x1) << CSR_GCFG_TORU_SHIFT)
+#define  CSR_GCFG_TORUP_SHIFT		14
+#define  CSR_GCFG_TORUP			(_ULCAST_(0x1) << CSR_GCFG_TORUP_SHIFT)
+#define  CSR_GCFG_TOP_SHIFT		13
+#define  CSR_GCFG_TOP			(_ULCAST_(0x1) << CSR_GCFG_TOP_SHIFT)
+#define  CSR_GCFG_TOPP_SHIFT		12
+#define  CSR_GCFG_TOPP			(_ULCAST_(0x1) << CSR_GCFG_TOPP_SHIFT)
+#define  CSR_GCFG_TOE_SHIFT		11
+#define  CSR_GCFG_TOE			(_ULCAST_(0x1) << CSR_GCFG_TOE_SHIFT)
+#define  CSR_GCFG_TOEP_SHIFT		10
+#define  CSR_GCFG_TOEP			(_ULCAST_(0x1) << CSR_GCFG_TOEP_SHIFT)
+#define  CSR_GCFG_TIT_SHIFT		9
+#define  CSR_GCFG_TIT			(_ULCAST_(0x1) << CSR_GCFG_TIT_SHIFT)
+#define  CSR_GCFG_TITP_SHIFT		8
+#define  CSR_GCFG_TITP			(_ULCAST_(0x1) << CSR_GCFG_TITP_SHIFT)
+#define  CSR_GCFG_SIT_SHIFT		7
+#define  CSR_GCFG_SIT			(_ULCAST_(0x1) << CSR_GCFG_SIT_SHIFT)
+#define  CSR_GCFG_SITP_SHIFT		6
+#define  CSR_GCFG_SITP			(_ULCAST_(0x1) << CSR_GCFG_SITP_SHIFT)
+#define  CSR_GCFG_MATC_SHITF		4
+#define  CSR_GCFG_MATC_WIDTH		2
+#define  CSR_GCFG_MATC_MASK		(_ULCAST_(0x3) << CSR_GCFG_MATC_SHITF)
+#define  CSR_GCFG_MATC_GUEST		(_ULCAST_(0x0) << CSR_GCFG_MATC_SHITF)
+#define  CSR_GCFG_MATC_ROOT		(_ULCAST_(0x1) << CSR_GCFG_MATC_SHITF)
+#define  CSR_GCFG_MATC_NEST		(_ULCAST_(0x2) << CSR_GCFG_MATC_SHITF)
+#define  CSR_GCFG_MATP_NEST_SHIFT	2
+#define  CSR_GCFG_MATP_NEST		(_ULCAST_(0x1) << CSR_GCFG_MATP_NEST_SHIFT)
+#define  CSR_GCFG_MATP_ROOT_SHIFT	1
+#define  CSR_GCFG_MATP_ROOT		(_ULCAST_(0x1) << CSR_GCFG_MATP_ROOT_SHIFT)
+#define  CSR_GCFG_MATP_GUEST_SHIFT	0
+#define  CSR_GCFG_MATP_GUEST		(_ULCAST_(0x1) << CSR_GCFG_MATP_GUEST_SHIFT)
+
+#define LOONGARCH_CSR_GINTC		0x52	/* Guest interrupt control */
+#define  CSR_GINTC_HC_SHIFT		16
+#define  CSR_GINTC_HC_WIDTH		8
+#define  CSR_GINTC_HC			(_ULCAST_(0xff) << CSR_GINTC_HC_SHIFT)
+#define  CSR_GINTC_PIP_SHIFT		8
+#define  CSR_GINTC_PIP_WIDTH		8
+#define  CSR_GINTC_PIP			(_ULCAST_(0xff) << CSR_GINTC_PIP_SHIFT)
+#define  CSR_GINTC_VIP_SHIFT		0
+#define  CSR_GINTC_VIP_WIDTH		8
+#define  CSR_GINTC_VIP			(_ULCAST_(0xff))
+
+#define LOONGARCH_CSR_GCNTC		0x53	/* Guest timer offset */
+
+/* LLBCTL register */
+#define LOONGARCH_CSR_LLBCTL		0x60	/* LLBit control */
+#define  CSR_LLBCTL_ROLLB_SHIFT		0
+#define  CSR_LLBCTL_ROLLB		(_ULCAST_(1) << CSR_LLBCTL_ROLLB_SHIFT)
+#define  CSR_LLBCTL_WCLLB_SHIFT		1
+#define  CSR_LLBCTL_WCLLB		(_ULCAST_(1) << CSR_LLBCTL_WCLLB_SHIFT)
+#define  CSR_LLBCTL_KLO_SHIFT		2
+#define  CSR_LLBCTL_KLO			(_ULCAST_(1) << CSR_LLBCTL_KLO_SHIFT)
+
+/* Implement dependent */
+#define LOONGARCH_CSR_IMPCTL1		0x80	/* Loongson config1 */
+#define  CSR_MISPEC_SHIFT		20
+#define  CSR_MISPEC_WIDTH		8
+#define  CSR_MISPEC			(_ULCAST_(0xff) << CSR_MISPEC_SHIFT)
+#define  CSR_SSEN_SHIFT			18
+#define  CSR_SSEN			(_ULCAST_(1) << CSR_SSEN_SHIFT)
+#define  CSR_SCRAND_SHIFT		17
+#define  CSR_SCRAND			(_ULCAST_(1) << CSR_SCRAND_SHIFT)
+#define  CSR_LLEXCL_SHIFT		16
+#define  CSR_LLEXCL			(_ULCAST_(1) << CSR_LLEXCL_SHIFT)
+#define  CSR_DISVC_SHIFT		15
+#define  CSR_DISVC			(_ULCAST_(1) << CSR_DISVC_SHIFT)
+#define  CSR_VCLRU_SHIFT		14
+#define  CSR_VCLRU			(_ULCAST_(1) << CSR_VCLRU_SHIFT)
+#define  CSR_DCLRU_SHIFT		13
+#define  CSR_DCLRU			(_ULCAST_(1) << CSR_DCLRU_SHIFT)
+#define  CSR_FASTLDQ_SHIFT		12
+#define  CSR_FASTLDQ			(_ULCAST_(1) << CSR_FASTLDQ_SHIFT)
+#define  CSR_USERCAC_SHIFT		11
+#define  CSR_USERCAC			(_ULCAST_(1) << CSR_USERCAC_SHIFT)
+#define  CSR_ANTI_MISPEC_SHIFT		10
+#define  CSR_ANTI_MISPEC		(_ULCAST_(1) << CSR_ANTI_MISPEC_SHIFT)
+#define  CSR_AUTO_FLUSHSFB_SHIFT	9
+#define  CSR_AUTO_FLUSHSFB		(_ULCAST_(1) << CSR_AUTO_FLUSHSFB_SHIFT)
+#define  CSR_STFILL_SHIFT		8
+#define  CSR_STFILL			(_ULCAST_(1) << CSR_STFILL_SHIFT)
+#define  CSR_LIFEP_SHIFT		7
+#define  CSR_LIFEP			(_ULCAST_(1) << CSR_LIFEP_SHIFT)
+#define  CSR_LLSYNC_SHIFT		6
+#define  CSR_LLSYNC			(_ULCAST_(1) << CSR_LLSYNC_SHIFT)
+#define  CSR_BRBTDIS_SHIFT		5
+#define  CSR_BRBTDIS			(_ULCAST_(1) << CSR_BRBTDIS_SHIFT)
+#define  CSR_RASDIS_SHIFT		4
+#define  CSR_RASDIS			(_ULCAST_(1) << CSR_RASDIS_SHIFT)
+#define  CSR_STPRE_SHIFT		2
+#define  CSR_STPRE_WIDTH		2
+#define  CSR_STPRE			(_ULCAST_(3) << CSR_STPRE_SHIFT)
+#define  CSR_INSTPRE_SHIFT		1
+#define  CSR_INSTPRE			(_ULCAST_(1) << CSR_INSTPRE_SHIFT)
+#define  CSR_DATAPRE_SHIFT		0
+#define  CSR_DATAPRE			(_ULCAST_(1) << CSR_DATAPRE_SHIFT)
+
+#define LOONGARCH_CSR_IMPCTL2		0x81	/* Loongson config2 */
+#define  CSR_FLUSH_MTLB_SHIFT		0
+#define  CSR_FLUSH_MTLB			(_ULCAST_(1) << CSR_FLUSH_MTLB_SHIFT)
+#define  CSR_FLUSH_STLB_SHIFT		1
+#define  CSR_FLUSH_STLB			(_ULCAST_(1) << CSR_FLUSH_STLB_SHIFT)
+#define  CSR_FLUSH_DTLB_SHIFT		2
+#define  CSR_FLUSH_DTLB			(_ULCAST_(1) << CSR_FLUSH_DTLB_SHIFT)
+#define  CSR_FLUSH_ITLB_SHIFT		3
+#define  CSR_FLUSH_ITLB			(_ULCAST_(1) << CSR_FLUSH_ITLB_SHIFT)
+#define  CSR_FLUSH_BTAC_SHIFT		4
+#define  CSR_FLUSH_BTAC			(_ULCAST_(1) << CSR_FLUSH_BTAC_SHIFT)
+
+#define LOONGARCH_CSR_GNMI		0x82
+
+/* TLB Refill registers */
+#define LOONGARCH_CSR_TLBRENTRY		0x88	/* TLB refill exception entry */
+#define LOONGARCH_CSR_TLBRBADV		0x89	/* TLB refill badvaddr */
+#define LOONGARCH_CSR_TLBRERA		0x8a	/* TLB refill ERA */
+#define LOONGARCH_CSR_TLBRSAVE		0x8b	/* KSave for TLB refill exception */
+#define LOONGARCH_CSR_TLBRELO0		0x8c	/* TLB refill entrylo0 */
+#define LOONGARCH_CSR_TLBRELO1		0x8d	/* TLB refill entrylo1 */
+#define LOONGARCH_CSR_TLBREHI		0x8e	/* TLB refill entryhi */
+#define  CSR_TLBREHI_PS_SHIFT		0
+#define  CSR_TLBREHI_PS			(_ULCAST_(0x3f) << CSR_TLBREHI_PS_SHIFT)
+#define LOONGARCH_CSR_TLBRPRMD		0x8f	/* TLB refill mode info */
+
+/* Machine Error registers */
+#define LOONGARCH_CSR_MERRCTL		0x90	/* MERRCTL */
+#define LOONGARCH_CSR_MERRINFO1		0x91	/* MError info1 */
+#define LOONGARCH_CSR_MERRINFO2		0x92	/* MError info2 */
+#define LOONGARCH_CSR_MERRENTRY		0x93	/* MError exception entry */
+#define LOONGARCH_CSR_MERRERA		0x94	/* MError exception ERA */
+#define LOONGARCH_CSR_MERRSAVE		0x95	/* KSave for machine error exception */
+
+#define LOONGARCH_CSR_CTAG		0x98	/* TagLo + TagHi */
+
+#define LOONGARCH_CSR_PRID		0xc0
+
+/* Shadow MCSR : 0xc0 ~ 0xff */
+#define LOONGARCH_CSR_MCSR0		0xc0	/* CPUCFG0 and CPUCFG1 */
+#define  MCSR0_INT_IMPL_SHIFT		58
+#define  MCSR0_INT_IMPL			0
+#define  MCSR0_IOCSR_BRD_SHIFT		57
+#define  MCSR0_IOCSR_BRD		(_ULCAST_(1) << MCSR0_IOCSR_BRD_SHIFT)
+#define  MCSR0_HUGEPG_SHIFT		56
+#define  MCSR0_HUGEPG			(_ULCAST_(1) << MCSR0_HUGEPG_SHIFT)
+#define  MCSR0_RPLMTLB_SHIFT		55
+#define  MCSR0_RPLMTLB			(_ULCAST_(1) << MCSR0_RPLMTLB_SHIFT)
+#define  MCSR0_EP_SHIFT			54
+#define  MCSR0_EP			(_ULCAST_(1) << MCSR0_EP_SHIFT)
+#define  MCSR0_RI_SHIFT			53
+#define  MCSR0_RI			(_ULCAST_(1) << MCSR0_RI_SHIFT)
+#define  MCSR0_UAL_SHIFT		52
+#define  MCSR0_UAL			(_ULCAST_(1) << MCSR0_UAL_SHIFT)
+#define  MCSR0_VABIT_SHIFT		44
+#define  MCSR0_VABIT_WIDTH		8
+#define  MCSR0_VABIT			(_ULCAST_(0xff) << MCSR0_VABIT_SHIFT)
+#define  VABIT_DEFAULT			0x2f
+#define  MCSR0_PABIT_SHIFT		36
+#define  MCSR0_PABIT_WIDTH		8
+#define  MCSR0_PABIT			(_ULCAST_(0xff) << MCSR0_PABIT_SHIFT)
+#define  PABIT_DEFAULT			0x2f
+#define  MCSR0_IOCSR_SHIFT		35
+#define  MCSR0_IOCSR			(_ULCAST_(1) << MCSR0_IOCSR_SHIFT)
+#define  MCSR0_PAGING_SHIFT		34
+#define  MCSR0_PAGING			(_ULCAST_(1) << MCSR0_PAGING_SHIFT)
+#define  MCSR0_GR64_SHIFT		33
+#define  MCSR0_GR64			(_ULCAST_(1) << MCSR0_GR64_SHIFT)
+#define  GR64_DEFAULT			1
+#define  MCSR0_GR32_SHIFT		32
+#define  MCSR0_GR32			(_ULCAST_(1) << MCSR0_GR32_SHIFT)
+#define  GR32_DEFAULT			0
+#define  MCSR0_PRID_WIDTH		32
+#define  MCSR0_PRID			0x14C010
+
+#define LOONGARCH_CSR_MCSR1		0xc1	/* CPUCFG2 and CPUCFG3 */
+#define  MCSR1_HPFOLD_SHIFT		43
+#define  MCSR1_HPFOLD			(_ULCAST_(1) << MCSR1_HPFOLD_SHIFT)
+#define  MCSR1_SPW_LVL_SHIFT		40
+#define  MCSR1_SPW_LVL_WIDTH		3
+#define  MCSR1_SPW_LVL			(_ULCAST_(7) << MCSR1_SPW_LVL_SHIFT)
+#define  MCSR1_ICACHET_SHIFT		39
+#define  MCSR1_ICACHET			(_ULCAST_(1) << MCSR1_ICACHET_SHIFT)
+#define  MCSR1_ITLBT_SHIFT		38
+#define  MCSR1_ITLBT			(_ULCAST_(1) << MCSR1_ITLBT_SHIFT)
+#define  MCSR1_LLDBAR_SHIFT		37
+#define  MCSR1_LLDBAR			(_ULCAST_(1) << MCSR1_LLDBAR_SHIFT)
+#define  MCSR1_SCDLY_SHIFT		36
+#define  MCSR1_SCDLY			(_ULCAST_(1) << MCSR1_SCDLY_SHIFT)
+#define  MCSR1_LLEXC_SHIFT		35
+#define  MCSR1_LLEXC			(_ULCAST_(1) << MCSR1_LLEXC_SHIFT)
+#define  MCSR1_UCACC_SHIFT		34
+#define  MCSR1_UCACC			(_ULCAST_(1) << MCSR1_UCACC_SHIFT)
+#define  MCSR1_SFB_SHIFT		33
+#define  MCSR1_SFB			(_ULCAST_(1) << MCSR1_SFB_SHIFT)
+#define  MCSR1_CCDMA_SHIFT		32
+#define  MCSR1_CCDMA			(_ULCAST_(1) << MCSR1_CCDMA_SHIFT)
+#define  MCSR1_LAMO_SHIFT		22
+#define  MCSR1_LAMO			(_ULCAST_(1) << MCSR1_LAMO_SHIFT)
+#define  MCSR1_LSPW_SHIFT		21
+#define  MCSR1_LSPW			(_ULCAST_(1) << MCSR1_LSPW_SHIFT)
+#define  MCSR1_MIPSBT_SHIFT		20
+#define  MCSR1_MIPSBT			(_ULCAST_(1) << MCSR1_MIPSBT_SHIFT)
+#define  MCSR1_ARMBT_SHIFT		19
+#define  MCSR1_ARMBT			(_ULCAST_(1) << MCSR1_ARMBT_SHIFT)
+#define  MCSR1_X86BT_SHIFT		18
+#define  MCSR1_X86BT			(_ULCAST_(1) << MCSR1_X86BT_SHIFT)
+#define  MCSR1_LLFTPVERS_SHIFT		15
+#define  MCSR1_LLFTPVERS_WIDTH		3
+#define  MCSR1_LLFTPVERS		(_ULCAST_(7) << MCSR1_LLFTPVERS_SHIFT)
+#define  MCSR1_LLFTP_SHIFT		14
+#define  MCSR1_LLFTP			(_ULCAST_(1) << MCSR1_LLFTP_SHIFT)
+#define  MCSR1_VZVERS_SHIFT		11
+#define  MCSR1_VZVERS_WIDTH		3
+#define  MCSR1_VZVERS			(_ULCAST_(7) << MCSR1_VZVERS_SHIFT)
+#define  MCSR1_VZ_SHIFT			10
+#define  MCSR1_VZ			(_ULCAST_(1) << MCSR1_VZ_SHIFT)
+#define  MCSR1_CRYPTO_SHIFT		9
+#define  MCSR1_CRYPTO			(_ULCAST_(1) << MCSR1_CRYPTO_SHIFT)
+#define  MCSR1_COMPLEX_SHIFT		8
+#define  MCSR1_COMPLEX			(_ULCAST_(1) << MCSR1_COMPLEX_SHIFT)
+#define  MCSR1_LASX_SHIFT		7
+#define  MCSR1_LASX			(_ULCAST_(1) << MCSR1_LASX_SHIFT)
+#define  MCSR1_LSX_SHIFT		6
+#define  MCSR1_LSX			(_ULCAST_(1) << MCSR1_LSX_SHIFT)
+#define  MCSR1_FPVERS_SHIFT		3
+#define  MCSR1_FPVERS_WIDTH		3
+#define  MCSR1_FPVERS			(_ULCAST_(7) << MCSR1_FPVERS_SHIFT)
+#define  MCSR1_FPDP_SHIFT		2
+#define  MCSR1_FPDP			(_ULCAST_(1) << MCSR1_FPDP_SHIFT)
+#define  MCSR1_FPSP_SHIFT		1
+#define  MCSR1_FPSP			(_ULCAST_(1) << MCSR1_FPSP_SHIFT)
+#define  MCSR1_FP_SHIFT			0
+#define  MCSR1_FP			(_ULCAST_(1) << MCSR1_FP_SHIFT)
+
+#define LOONGARCH_CSR_MCSR2		0xc2	/* CPUCFG4 and CPUCFG5 */
+#define  MCSR2_CCDIV_SHIFT		48
+#define  MCSR2_CCDIV_WIDTH		16
+#define  MCSR2_CCDIV			(_ULCAST_(0xffff) << MCSR2_CCDIV_SHIFT)
+#define  MCSR2_CCMUL_SHIFT		32
+#define  MCSR2_CCMUL_WIDTH		16
+#define  MCSR2_CCMUL			(_ULCAST_(0xffff) << MCSR2_CCMUL_SHIFT)
+#define  MCSR2_CCFREQ_WIDTH		32
+#define  MCSR2_CCFREQ			(_ULCAST_(0xffffffff))
+#define  CCFREQ_DEFAULT			0x5f5e100	/* 100MHz */
+
+#define LOONGARCH_CSR_MCSR3		0xc3	/* CPUCFG6 */
+#define  MCSR3_UPM_SHIFT		14
+#define  MCSR3_UPM			(_ULCAST_(1) << MCSR3_UPM_SHIFT)
+#define  MCSR3_PMBITS_SHIFT		8
+#define  MCSR3_PMBITS_WIDTH		6
+#define  MCSR3_PMBITS			(_ULCAST_(0x3f) << MCSR3_PMBITS_SHIFT)
+#define  PMBITS_DEFAULT			0x40
+#define  MCSR3_PMNUM_SHIFT		4
+#define  MCSR3_PMNUM_WIDTH		4
+#define  MCSR3_PMNUM			(_ULCAST_(0xf) << MCSR3_PMNUM_SHIFT)
+#define  MCSR3_PAMVER_SHIFT		1
+#define  MCSR3_PAMVER_WIDTH		3
+#define  MCSR3_PAMVER			(_ULCAST_(0x7) << MCSR3_PAMVER_SHIFT)
+#define  MCSR3_PMP_SHIFT		0
+#define  MCSR3_PMP			(_ULCAST_(1) << MCSR3_PMP_SHIFT)
+
+#define LOONGARCH_CSR_MCSR8		0xc8	/* CPUCFG16 and CPUCFG17 */
+#define  MCSR8_L1I_SIZE_SHIFT		56
+#define  MCSR8_L1I_SIZE_WIDTH		7
+#define  MCSR8_L1I_SIZE			(_ULCAST_(0x7f) << MCSR8_L1I_SIZE_SHIFT)
+#define  MCSR8_L1I_IDX_SHIFT		48
+#define  MCSR8_L1I_IDX_WIDTH		8
+#define  MCSR8_L1I_IDX			(_ULCAST_(0xff) << MCSR8_L1I_IDX_SHIFT)
+#define  MCSR8_L1I_WAY_SHIFT		32
+#define  MCSR8_L1I_WAY_WIDTH		16
+#define  MCSR8_L1I_WAY			(_ULCAST_(0xffff) << MCSR8_L1I_WAY_SHIFT)
+#define  MCSR8_L3DINCL_SHIFT		16
+#define  MCSR8_L3DINCL			(_ULCAST_(1) << MCSR8_L3DINCL_SHIFT)
+#define  MCSR8_L3DPRIV_SHIFT		15
+#define  MCSR8_L3DPRIV			(_ULCAST_(1) << MCSR8_L3DPRIV_SHIFT)
+#define  MCSR8_L3DPRE_SHIFT		14
+#define  MCSR8_L3DPRE			(_ULCAST_(1) << MCSR8_L3DPRE_SHIFT)
+#define  MCSR8_L3IUINCL_SHIFT		13
+#define  MCSR8_L3IUINCL			(_ULCAST_(1) << MCSR8_L3IUINCL_SHIFT)
+#define  MCSR8_L3IUPRIV_SHIFT		12
+#define  MCSR8_L3IUPRIV			(_ULCAST_(1) << MCSR8_L3IUPRIV_SHIFT)
+#define  MCSR8_L3IUUNIFY_SHIFT		11
+#define  MCSR8_L3IUUNIFY		(_ULCAST_(1) << MCSR8_L3IUUNIFY_SHIFT)
+#define  MCSR8_L3IUPRE_SHIFT		10
+#define  MCSR8_L3IUPRE			(_ULCAST_(1) << MCSR8_L3IUPRE_SHIFT)
+#define  MCSR8_L2DINCL_SHIFT		9
+#define  MCSR8_L2DINCL			(_ULCAST_(1) << MCSR8_L2DINCL_SHIFT)
+#define  MCSR8_L2DPRIV_SHIFT		8
+#define  MCSR8_L2DPRIV			(_ULCAST_(1) << MCSR8_L2DPRIV_SHIFT)
+#define  MCSR8_L2DPRE_SHIFT		7
+#define  MCSR8_L2DPRE			(_ULCAST_(1) << MCSR8_L2DPRE_SHIFT)
+#define  MCSR8_L2IUINCL_SHIFT		6
+#define  MCSR8_L2IUINCL			(_ULCAST_(1) << MCSR8_L2IUINCL_SHIFT)
+#define  MCSR8_L2IUPRIV_SHIFT		5
+#define  MCSR8_L2IUPRIV			(_ULCAST_(1) << MCSR8_L2IUPRIV_SHIFT)
+#define  MCSR8_L2IUUNIFY_SHIFT		4
+#define  MCSR8_L2IUUNIFY		(_ULCAST_(1) << MCSR8_L2IUUNIFY_SHIFT)
+#define  MCSR8_L2IUPRE_SHIFT		3
+#define  MCSR8_L2IUPRE			(_ULCAST_(1) << MCSR8_L2IUPRE_SHIFT)
+#define  MCSR8_L1DPRE_SHIFT		2
+#define  MCSR8_L1DPRE			(_ULCAST_(1) << MCSR8_L1DPRE_SHIFT)
+#define  MCSR8_L1IUUNIFY_SHIFT		1
+#define  MCSR8_L1IUUNIFY		(_ULCAST_(1) << MCSR8_L1IUUNIFY_SHIFT)
+#define  MCSR8_L1IUPRE_SHIFT		0
+#define  MCSR8_L1IUPRE			(_ULCAST_(1) << MCSR8_L1IUPRE_SHIFT)
+
+#define LOONGARCH_CSR_MCSR9		0xc9	/* CPUCFG18 and CPUCFG19 */
+#define  MCSR9_L2U_SIZE_SHIFT		56
+#define  MCSR9_L2U_SIZE_WIDTH		7
+#define  MCSR9_L2U_SIZE			(_ULCAST_(0x7f) << MCSR9_L2U_SIZE_SHIFT)
+#define  MCSR9_L2U_IDX_SHIFT		48
+#define  MCSR9_L2U_IDX_WIDTH		8
+#define  MCSR9_L2U_IDX			(_ULCAST_(0xff) << MCSR9_IDX_LOG_SHIFT)
+#define  MCSR9_L2U_WAY_SHIFT		32
+#define  MCSR9_L2U_WAY_WIDTH		16
+#define  MCSR9_L2U_WAY			(_ULCAST_(0xffff) << MCSR9_L2U_WAY_SHIFT)
+#define  MCSR9_L1D_SIZE_SHIFT		24
+#define  MCSR9_L1D_SIZE_WIDTH		7
+#define  MCSR9_L1D_SIZE			(_ULCAST_(0x7f) << MCSR9_L1D_SIZE_SHIFT)
+#define  MCSR9_L1D_IDX_SHIFT		16
+#define  MCSR9_L1D_IDX_WIDTH		8
+#define  MCSR9_L1D_IDX			(_ULCAST_(0xff) << MCSR9_L1D_IDX_SHIFT)
+#define  MCSR9_L1D_WAY_SHIFT		0
+#define  MCSR9_L1D_WAY_WIDTH		16
+#define  MCSR9_L1D_WAY			(_ULCAST_(0xffff) << MCSR9_L1D_WAY_SHIFT)
+
+#define LOONGARCH_CSR_MCSR10		0xca	/* CPUCFG20 */
+#define  MCSR10_L3U_SIZE_SHIFT		24
+#define  MCSR10_L3U_SIZE_WIDTH		7
+#define  MCSR10_L3U_SIZE		(_ULCAST_(0x7f) << MCSR10_L3U_SIZE_SHIFT)
+#define  MCSR10_L3U_IDX_SHIFT		16
+#define  MCSR10_L3U_IDX_WIDTH		8
+#define  MCSR10_L3U_IDX			(_ULCAST_(0xff) << MCSR10_L3U_IDX_SHIFT)
+#define  MCSR10_L3U_WAY_SHIFT		0
+#define  MCSR10_L3U_WAY_WIDTH		16
+#define  MCSR10_L3U_WAY			(_ULCAST_(0xffff) << MCSR10_L3U_WAY_SHIFT)
+
+#define LOONGARCH_CSR_MCSR24		0xf0	/* cpucfg48 */
+#define  MCSR24_RAMCG_SHIFT		3
+#define  MCSR24_RAMCG			(_ULCAST_(1) << MCSR24_RAMCG_SHIFT)
+#define  MCSR24_VFPUCG_SHIFT		2
+#define  MCSR24_VFPUCG			(_ULCAST_(1) << MCSR24_VFPUCG_SHIFT)
+#define  MCSR24_NAPEN_SHIFT		1
+#define  MCSR24_NAPEN			(_ULCAST_(1) << MCSR24_NAPEN_SHIFT)
+#define  MCSR24_MCSRLOCK_SHIFT		0
+#define  MCSR24_MCSRLOCK		(_ULCAST_(1) << MCSR24_MCSRLOCK_SHIFT)
+
+/* Uncached accelerate windows registers */
+#define LOONGARCH_CSR_UCAWIN		0x100
+#define LOONGARCH_CSR_UCAWIN0_LO	0x102
+#define LOONGARCH_CSR_UCAWIN0_HI	0x103
+#define LOONGARCH_CSR_UCAWIN1_LO	0x104
+#define LOONGARCH_CSR_UCAWIN1_HI	0x105
+#define LOONGARCH_CSR_UCAWIN2_LO	0x106
+#define LOONGARCH_CSR_UCAWIN2_HI	0x107
+#define LOONGARCH_CSR_UCAWIN3_LO	0x108
+#define LOONGARCH_CSR_UCAWIN3_HI	0x109
+
+/* Direct Map windows registers */
+#define LOONGARCH_CSR_DMWIN0		0x180	/* 64 direct map win0: MEM & IF */
+#define LOONGARCH_CSR_DMWIN1		0x181	/* 64 direct map win1: MEM & IF */
+#define LOONGARCH_CSR_DMWIN2		0x182	/* 64 direct map win2: MEM */
+#define LOONGARCH_CSR_DMWIN3		0x183	/* 64 direct map win3: MEM */
+
+/* Direct Map window 0/1 */
+#define CSR_DMW0_PLV0		_CONST64_(1 << 0)
+#define CSR_DMW0_VSEG		_CONST64_(0x8000)
+#define CSR_DMW0_BASE		(CSR_DMW0_VSEG << DMW_PABITS)
+#define CSR_DMW0_INIT		(CSR_DMW0_BASE | CSR_DMW0_PLV0)
+
+#define CSR_DMW1_PLV0		_CONST64_(1 << 0)
+#define CSR_DMW1_MAT		_CONST64_(1 << 4)
+#define CSR_DMW1_VSEG		_CONST64_(0x9000)
+#define CSR_DMW1_BASE		(CSR_DMW1_VSEG << DMW_PABITS)
+#define CSR_DMW1_INIT		(CSR_DMW1_BASE | CSR_DMW1_MAT | CSR_DMW1_PLV0)
+
+/* Performance Counter registers */
+#define LOONGARCH_CSR_PERFCTRL0		0x200	/* 32 perf event 0 config */
+#define LOONGARCH_CSR_PERFCNTR0		0x201	/* 64 perf event 0 count value */
+#define LOONGARCH_CSR_PERFCTRL1		0x202	/* 32 perf event 1 config */
+#define LOONGARCH_CSR_PERFCNTR1		0x203	/* 64 perf event 1 count value */
+#define LOONGARCH_CSR_PERFCTRL2		0x204	/* 32 perf event 2 config */
+#define LOONGARCH_CSR_PERFCNTR2		0x205	/* 64 perf event 2 count value */
+#define LOONGARCH_CSR_PERFCTRL3		0x206	/* 32 perf event 3 config */
+#define LOONGARCH_CSR_PERFCNTR3		0x207	/* 64 perf event 3 count value */
+#define  CSR_PERFCTRL_PLV0		(_ULCAST_(1) << 16)
+#define  CSR_PERFCTRL_PLV1		(_ULCAST_(1) << 17)
+#define  CSR_PERFCTRL_PLV2		(_ULCAST_(1) << 18)
+#define  CSR_PERFCTRL_PLV3		(_ULCAST_(1) << 19)
+#define  CSR_PERFCTRL_IE		(_ULCAST_(1) << 20)
+#define  CSR_PERFCTRL_EVENT		0x3ff
+
+/* Debug registers */
+#define LOONGARCH_CSR_MWPC		0x300	/* data breakpoint config */
+#define LOONGARCH_CSR_MWPS		0x301	/* data breakpoint status */
+
+#define LOONGARCH_CSR_DB0ADDR		0x310	/* data breakpoint 0 address */
+#define LOONGARCH_CSR_DB0MASK		0x311	/* data breakpoint 0 mask */
+#define LOONGARCH_CSR_DB0CTRL		0x312	/* data breakpoint 0 control */
+#define LOONGARCH_CSR_DB0ASID		0x313	/* data breakpoint 0 asid */
+
+#define LOONGARCH_CSR_DB1ADDR		0x318	/* data breakpoint 1 address */
+#define LOONGARCH_CSR_DB1MASK		0x319	/* data breakpoint 1 mask */
+#define LOONGARCH_CSR_DB1CTRL		0x31a	/* data breakpoint 1 control */
+#define LOONGARCH_CSR_DB1ASID		0x31b	/* data breakpoint 1 asid */
+
+#define LOONGARCH_CSR_DB2ADDR		0x320	/* data breakpoint 2 address */
+#define LOONGARCH_CSR_DB2MASK		0x321	/* data breakpoint 2 mask */
+#define LOONGARCH_CSR_DB2CTRL		0x322	/* data breakpoint 2 control */
+#define LOONGARCH_CSR_DB2ASID		0x323	/* data breakpoint 2 asid */
+
+#define LOONGARCH_CSR_DB3ADDR		0x328	/* data breakpoint 3 address */
+#define LOONGARCH_CSR_DB3MASK		0x329	/* data breakpoint 3 mask */
+#define LOONGARCH_CSR_DB3CTRL		0x32a	/* data breakpoint 3 control */
+#define LOONGARCH_CSR_DB3ASID		0x32b	/* data breakpoint 3 asid */
+
+#define LOONGARCH_CSR_DB4ADDR		0x330	/* data breakpoint 4 address */
+#define LOONGARCH_CSR_DB4MASK		0x331	/* data breakpoint 4 maks */
+#define LOONGARCH_CSR_DB4CTRL		0x332	/* data breakpoint 4 control */
+#define LOONGARCH_CSR_DB4ASID		0x333	/* data breakpoint 4 asid */
+
+#define LOONGARCH_CSR_DB5ADDR		0x338	/* data breakpoint 5 address */
+#define LOONGARCH_CSR_DB5MASK		0x339	/* data breakpoint 5 mask */
+#define LOONGARCH_CSR_DB5CTRL		0x33a	/* data breakpoint 5 control */
+#define LOONGARCH_CSR_DB5ASID		0x33b	/* data breakpoint 5 asid */
+
+#define LOONGARCH_CSR_DB6ADDR		0x340	/* data breakpoint 6 address */
+#define LOONGARCH_CSR_DB6MASK		0x341	/* data breakpoint 6 mask */
+#define LOONGARCH_CSR_DB6CTRL		0x342	/* data breakpoint 6 control */
+#define LOONGARCH_CSR_DB6ASID		0x343	/* data breakpoint 6 asid */
+
+#define LOONGARCH_CSR_DB7ADDR		0x348	/* data breakpoint 7 address */
+#define LOONGARCH_CSR_DB7MASK		0x349	/* data breakpoint 7 mask */
+#define LOONGARCH_CSR_DB7CTRL		0x34a	/* data breakpoint 7 control */
+#define LOONGARCH_CSR_DB7ASID		0x34b	/* data breakpoint 7 asid */
+
+#define LOONGARCH_CSR_FWPC		0x380	/* instruction breakpoint config */
+#define LOONGARCH_CSR_FWPS		0x381	/* instruction breakpoint status */
+
+#define LOONGARCH_CSR_IB0ADDR		0x390	/* inst breakpoint 0 address */
+#define LOONGARCH_CSR_IB0MASK		0x391	/* inst breakpoint 0 mask */
+#define LOONGARCH_CSR_IB0CTRL		0x392	/* inst breakpoint 0 control */
+#define LOONGARCH_CSR_IB0ASID		0x393	/* inst breakpoint 0 asid */
+
+#define LOONGARCH_CSR_IB1ADDR		0x398	/* inst breakpoint 1 address */
+#define LOONGARCH_CSR_IB1MASK		0x399	/* inst breakpoint 1 mask */
+#define LOONGARCH_CSR_IB1CTRL		0x39a	/* inst breakpoint 1 control */
+#define LOONGARCH_CSR_IB1ASID		0x39b	/* inst breakpoint 1 asid */
+
+#define LOONGARCH_CSR_IB2ADDR		0x3a0	/* inst breakpoint 2 address */
+#define LOONGARCH_CSR_IB2MASK		0x3a1	/* inst breakpoint 2 mask */
+#define LOONGARCH_CSR_IB2CTRL		0x3a2	/* inst breakpoint 2 control */
+#define LOONGARCH_CSR_IB2ASID		0x3a3	/* inst breakpoint 2 asid */
+
+#define LOONGARCH_CSR_IB3ADDR		0x3a8	/* inst breakpoint 3 address */
+#define LOONGARCH_CSR_IB3MASK		0x3a9	/* breakpoint 3 mask */
+#define LOONGARCH_CSR_IB3CTRL		0x3aa	/* inst breakpoint 3 control */
+#define LOONGARCH_CSR_IB3ASID		0x3ab	/* inst breakpoint 3 asid */
+
+#define LOONGARCH_CSR_IB4ADDR		0x3b0	/* inst breakpoint 4 address */
+#define LOONGARCH_CSR_IB4MASK		0x3b1	/* inst breakpoint 4 mask */
+#define LOONGARCH_CSR_IB4CTRL		0x3b2	/* inst breakpoint 4 control */
+#define LOONGARCH_CSR_IB4ASID		0x3b3	/* inst breakpoint 4 asid */
+
+#define LOONGARCH_CSR_IB5ADDR		0x3b8	/* inst breakpoint 5 address */
+#define LOONGARCH_CSR_IB5MASK		0x3b9	/* inst breakpoint 5 mask */
+#define LOONGARCH_CSR_IB5CTRL		0x3ba	/* inst breakpoint 5 control */
+#define LOONGARCH_CSR_IB5ASID		0x3bb	/* inst breakpoint 5 asid */
+
+#define LOONGARCH_CSR_IB6ADDR		0x3c0	/* inst breakpoint 6 address */
+#define LOONGARCH_CSR_IB6MASK		0x3c1	/* inst breakpoint 6 mask */
+#define LOONGARCH_CSR_IB6CTRL		0x3c2	/* inst breakpoint 6 control */
+#define LOONGARCH_CSR_IB6ASID		0x3c3	/* inst breakpoint 6 asid */
+
+#define LOONGARCH_CSR_IB7ADDR		0x3c8	/* inst breakpoint 7 address */
+#define LOONGARCH_CSR_IB7MASK		0x3c9	/* inst breakpoint 7 mask */
+#define LOONGARCH_CSR_IB7CTRL		0x3ca	/* inst breakpoint 7 control */
+#define LOONGARCH_CSR_IB7ASID		0x3cb	/* inst breakpoint 7 asid */
+
+#define LOONGARCH_CSR_DEBUG		0x500	/* debug config */
+#define LOONGARCH_CSR_DERA		0x501	/* debug era */
+#define LOONGARCH_CSR_DESAVE		0x502	/* debug save */
+
+#define CSR_FWPC_SKIP_SHIFT		16
+#define CSR_FWPC_SKIP			(_ULCAST_(1) << CSR_FWPC_SKIP_SHIFT)
+
+/*
+ * CSR_ECFG IM
+ */
+#define ECFG0_IM		0x00001fff
+#define ECFGB_SIP0		0
+#define ECFGF_SIP0		(_ULCAST_(1) << ECFGB_SIP0)
+#define ECFGB_SIP1		1
+#define ECFGF_SIP1		(_ULCAST_(1) << ECFGB_SIP1)
+#define ECFGB_IP0		2
+#define ECFGF_IP0		(_ULCAST_(1) << ECFGB_IP0)
+#define ECFGB_IP1		3
+#define ECFGF_IP1		(_ULCAST_(1) << ECFGB_IP1)
+#define ECFGB_IP2		4
+#define ECFGF_IP2		(_ULCAST_(1) << ECFGB_IP2)
+#define ECFGB_IP3		5
+#define ECFGF_IP3		(_ULCAST_(1) << ECFGB_IP3)
+#define ECFGB_IP4		6
+#define ECFGF_IP4		(_ULCAST_(1) << ECFGB_IP4)
+#define ECFGB_IP5		7
+#define ECFGF_IP5		(_ULCAST_(1) << ECFGB_IP5)
+#define ECFGB_IP6		8
+#define ECFGF_IP6		(_ULCAST_(1) << ECFGB_IP6)
+#define ECFGB_IP7		9
+#define ECFGF_IP7		(_ULCAST_(1) << ECFGB_IP7)
+#define ECFGB_PMC		10
+#define ECFGF_PMC		(_ULCAST_(1) << ECFGB_PMC)
+#define ECFGB_TIMER		11
+#define ECFGF_TIMER		(_ULCAST_(1) << ECFGB_TIMER)
+#define ECFGB_IPI		12
+#define ECFGF_IPI		(_ULCAST_(1) << ECFGB_IPI)
+#define ECFGF(hwirq)		(_ULCAST_(1) << hwirq)
+
+#define ESTATF_IP		0x00003fff
+
+#define LOONGARCH_IOCSR_FEATURES	0x8
+#define  IOCSRF_TEMP			BIT_ULL(0)
+#define  IOCSRF_NODECNT			BIT_ULL(1)
+#define  IOCSRF_MSI			BIT_ULL(2)
+#define  IOCSRF_EXTIOI			BIT_ULL(3)
+#define  IOCSRF_CSRIPI			BIT_ULL(4)
+#define  IOCSRF_FREQCSR			BIT_ULL(5)
+#define  IOCSRF_FREQSCALE		BIT_ULL(6)
+#define  IOCSRF_DVFSV1			BIT_ULL(7)
+#define  IOCSRF_EIODECODE		BIT_ULL(9)
+#define  IOCSRF_FLATMODE		BIT_ULL(10)
+#define  IOCSRF_VM			BIT_ULL(11)
+
+#define LOONGARCH_IOCSR_VENDOR		0x10
+
+#define LOONGARCH_IOCSR_CPUNAME		0x20
+
+#define LOONGARCH_IOCSR_NODECNT		0x408
+
+#define LOONGARCH_IOCSR_MISC_FUNC	0x420
+#define  IOCSR_MISC_FUNC_TIMER_RESET	BIT_ULL(21)
+#define  IOCSR_MISC_FUNC_EXT_IOI_EN	BIT_ULL(48)
+
+#define LOONGARCH_IOCSR_CPUTEMP		0x428
+
+/* PerCore CSR, only accessible by local cores */
+#define LOONGARCH_IOCSR_IPI_STATUS	0x1000
+#define LOONGARCH_IOCSR_IPI_EN		0x1004
+#define LOONGARCH_IOCSR_IPI_SET		0x1008
+#define LOONGARCH_IOCSR_IPI_CLEAR	0x100c
+#define LOONGARCH_IOCSR_MBUF0		0x1020
+#define LOONGARCH_IOCSR_MBUF1		0x1028
+#define LOONGARCH_IOCSR_MBUF2		0x1030
+#define LOONGARCH_IOCSR_MBUF3		0x1038
+
+#define LOONGARCH_IOCSR_IPI_SEND	0x1040
+#define  IOCSR_IPI_SEND_IP_SHIFT	0
+#define  IOCSR_IPI_SEND_CPU_SHIFT	16
+#define  IOCSR_IPI_SEND_BLOCKING	BIT(31)
+
+#define LOONGARCH_IOCSR_MBUF_SEND	0x1048
+#define  IOCSR_MBUF_SEND_BLOCKING	BIT_ULL(31)
+#define  IOCSR_MBUF_SEND_BOX_SHIFT	2
+#define  IOCSR_MBUF_SEND_BOX_LO(box)	(box << 1)
+#define  IOCSR_MBUF_SEND_BOX_HI(box)	((box << 1) + 1)
+#define  IOCSR_MBUF_SEND_CPU_SHIFT	16
+#define  IOCSR_MBUF_SEND_BUF_SHIFT	32
+#define  IOCSR_MBUF_SEND_H32_MASK	0xFFFFFFFF00000000ULL
+
+#define LOONGARCH_IOCSR_ANY_SEND	0x1158
+#define  IOCSR_ANY_SEND_BLOCKING	BIT_ULL(31)
+#define  IOCSR_ANY_SEND_CPU_SHIFT	16
+#define  IOCSR_ANY_SEND_MASK_SHIFT	27
+#define  IOCSR_ANY_SEND_BUF_SHIFT	32
+#define  IOCSR_ANY_SEND_H32_MASK	0xFFFFFFFF00000000ULL
+
+/* Register offset and bit definition for CSR access */
+#define LOONGARCH_IOCSR_TIMER_CFG       0x1060
+#define LOONGARCH_IOCSR_TIMER_TICK      0x1070
+#define  IOCSR_TIMER_CFG_RESERVED       (_ULCAST_(1) << 63)
+#define  IOCSR_TIMER_CFG_PERIODIC       (_ULCAST_(1) << 62)
+#define  IOCSR_TIMER_CFG_EN             (_ULCAST_(1) << 61)
+#define  IOCSR_TIMER_MASK		0x0ffffffffffffULL
+#define  IOCSR_TIMER_INITVAL_RST        (_ULCAST_(0xffff) << 48)
+
+#define LOONGARCH_IOCSR_EXTIOI_NODEMAP_BASE	0x14a0
+#define LOONGARCH_IOCSR_EXTIOI_IPMAP_BASE	0x14c0
+#define LOONGARCH_IOCSR_EXTIOI_EN_BASE		0x1600
+#define LOONGARCH_IOCSR_EXTIOI_BOUNCE_BASE	0x1680
+#define LOONGARCH_IOCSR_EXTIOI_ISR_BASE		0x1800
+#define LOONGARCH_IOCSR_EXTIOI_ROUTE_BASE	0x1c00
+#define IOCSR_EXTIOI_VECTOR_NUM			256
+
+#ifndef __ASSEMBLY__
+
+static __always_inline u64 drdtime(void)
+{
+	u64 val = 0;
+
+	__asm__ __volatile__(
+		"rdtime.d %0, $zero\n\t"
+		: "=r"(val)
+		:
+		);
+	return val;
+}
+
+static __always_inline u32 rdtimeh(void)
+{
+	u32 val = 0;
+
+	__asm__ __volatile__(
+		"rdtimeh.w %0, $zero\n\t"
+		: "=r"(val)
+		:
+		);
+	return val;
+}
+
+static __always_inline u32 rdtimel(void)
+{
+	u32 val = 0;
+
+	__asm__ __volatile__(
+		"rdtimel.w %0, $zero\n\t"
+		: "=r"(val)
+		:
+		);
+	return val;
+}
+
+static inline unsigned int get_csr_cpuid(void)
+{
+	return csr_read32(LOONGARCH_CSR_CPUID);
+}
+
+static inline void csr_any_send(unsigned int addr, unsigned int data,
+				unsigned int data_mask, unsigned int cpu)
+{
+	uint64_t val = 0;
+
+	val = IOCSR_ANY_SEND_BLOCKING | addr;
+	val |= (cpu << IOCSR_ANY_SEND_CPU_SHIFT);
+	val |= (data_mask << IOCSR_ANY_SEND_MASK_SHIFT);
+	val |= ((uint64_t)data << IOCSR_ANY_SEND_BUF_SHIFT);
+	iocsr_write64(val, LOONGARCH_IOCSR_ANY_SEND);
+}
+
+static inline unsigned int read_csr_excode(void)
+{
+	return (csr_read32(LOONGARCH_CSR_ESTAT) & CSR_ESTAT_EXC) >> CSR_ESTAT_EXC_SHIFT;
+}
+
+static inline void write_csr_index(unsigned int idx)
+{
+	csr_xchg32(idx, CSR_TLBIDX_IDXM, LOONGARCH_CSR_TLBIDX);
+}
+
+static inline unsigned int read_csr_pagesize(void)
+{
+	return (csr_read32(LOONGARCH_CSR_TLBIDX) & CSR_TLBIDX_SIZEM) >> CSR_TLBIDX_SIZE;
+}
+
+static inline void write_csr_pagesize(unsigned int size)
+{
+	csr_xchg32(size << CSR_TLBIDX_SIZE, CSR_TLBIDX_SIZEM, LOONGARCH_CSR_TLBIDX);
+}
+
+static inline unsigned int read_csr_tlbrefill_pagesize(void)
+{
+	return (csr_read64(LOONGARCH_CSR_TLBREHI) & CSR_TLBREHI_PS) >> CSR_TLBREHI_PS_SHIFT;
+}
+
+static inline void write_csr_tlbrefill_pagesize(unsigned int size)
+{
+	csr_xchg64(size << CSR_TLBREHI_PS_SHIFT, CSR_TLBREHI_PS, LOONGARCH_CSR_TLBREHI);
+}
+
+#define read_csr_asid()			csr_read32(LOONGARCH_CSR_ASID)
+#define write_csr_asid(val)		csr_write32(val, LOONGARCH_CSR_ASID)
+#define read_csr_entryhi()		csr_read64(LOONGARCH_CSR_TLBEHI)
+#define write_csr_entryhi(val)		csr_write64(val, LOONGARCH_CSR_TLBEHI)
+#define read_csr_entrylo0()		csr_read64(LOONGARCH_CSR_TLBELO0)
+#define write_csr_entrylo0(val)		csr_write64(val, LOONGARCH_CSR_TLBELO0)
+#define read_csr_entrylo1()		csr_read64(LOONGARCH_CSR_TLBELO1)
+#define write_csr_entrylo1(val)		csr_write64(val, LOONGARCH_CSR_TLBELO1)
+#define read_csr_ecfg()			csr_read32(LOONGARCH_CSR_ECFG)
+#define write_csr_ecfg(val)		csr_write32(val, LOONGARCH_CSR_ECFG)
+#define read_csr_estat()		csr_read32(LOONGARCH_CSR_ESTAT)
+#define write_csr_estat(val)		csr_write32(val, LOONGARCH_CSR_ESTAT)
+#define read_csr_tlbidx()		csr_read32(LOONGARCH_CSR_TLBIDX)
+#define write_csr_tlbidx(val)		csr_write32(val, LOONGARCH_CSR_TLBIDX)
+#define read_csr_euen()			csr_read32(LOONGARCH_CSR_EUEN)
+#define write_csr_euen(val)		csr_write32(val, LOONGARCH_CSR_EUEN)
+#define read_csr_cpuid()		csr_read32(LOONGARCH_CSR_CPUID)
+#define read_csr_prcfg1()		csr_read64(LOONGARCH_CSR_PRCFG1)
+#define write_csr_prcfg1(val)		csr_write64(val, LOONGARCH_CSR_PRCFG1)
+#define read_csr_prcfg2()		csr_read64(LOONGARCH_CSR_PRCFG2)
+#define write_csr_prcfg2(val)		csr_write64(val, LOONGARCH_CSR_PRCFG2)
+#define read_csr_prcfg3()		csr_read64(LOONGARCH_CSR_PRCFG3)
+#define write_csr_prcfg3(val)		csr_write64(val, LOONGARCH_CSR_PRCFG3)
+#define read_csr_stlbpgsize()		csr_read32(LOONGARCH_CSR_STLBPGSIZE)
+#define write_csr_stlbpgsize(val)	csr_write32(val, LOONGARCH_CSR_STLBPGSIZE)
+#define read_csr_rvacfg()		csr_read32(LOONGARCH_CSR_RVACFG)
+#define write_csr_rvacfg(val)		csr_write32(val, LOONGARCH_CSR_RVACFG)
+#define write_csr_tintclear(val)	csr_write32(val, LOONGARCH_CSR_TINTCLR)
+#define read_csr_impctl1()		csr_read64(LOONGARCH_CSR_IMPCTL1)
+#define write_csr_impctl1(val)		csr_write64(val, LOONGARCH_CSR_IMPCTL1)
+#define write_csr_impctl2(val)		csr_write64(val, LOONGARCH_CSR_IMPCTL2)
+
+#define read_csr_perfctrl0()		csr_read64(LOONGARCH_CSR_PERFCTRL0)
+#define read_csr_perfcntr0()		csr_read64(LOONGARCH_CSR_PERFCNTR0)
+#define read_csr_perfctrl1()		csr_read64(LOONGARCH_CSR_PERFCTRL1)
+#define read_csr_perfcntr1()		csr_read64(LOONGARCH_CSR_PERFCNTR1)
+#define read_csr_perfctrl2()		csr_read64(LOONGARCH_CSR_PERFCTRL2)
+#define read_csr_perfcntr2()		csr_read64(LOONGARCH_CSR_PERFCNTR2)
+#define read_csr_perfctrl3()		csr_read64(LOONGARCH_CSR_PERFCTRL3)
+#define read_csr_perfcntr3()		csr_read64(LOONGARCH_CSR_PERFCNTR3)
+#define write_csr_perfctrl0(val)	csr_write64(val, LOONGARCH_CSR_PERFCTRL0)
+#define write_csr_perfcntr0(val)	csr_write64(val, LOONGARCH_CSR_PERFCNTR0)
+#define write_csr_perfctrl1(val)	csr_write64(val, LOONGARCH_CSR_PERFCTRL1)
+#define write_csr_perfcntr1(val)	csr_write64(val, LOONGARCH_CSR_PERFCNTR1)
+#define write_csr_perfctrl2(val)	csr_write64(val, LOONGARCH_CSR_PERFCTRL2)
+#define write_csr_perfcntr2(val)	csr_write64(val, LOONGARCH_CSR_PERFCNTR2)
+#define write_csr_perfctrl3(val)	csr_write64(val, LOONGARCH_CSR_PERFCTRL3)
+#define write_csr_perfcntr3(val)	csr_write64(val, LOONGARCH_CSR_PERFCNTR3)
+
+/*
+ * Manipulate bits in a register.
+ */
+#define __BUILD_CSR_COMMON(name)				\
+static inline unsigned long					\
+set_##name(unsigned long set)					\
+{								\
+	unsigned long res, new;					\
+								\
+	res = read_##name();					\
+	new = res | set;					\
+	write_##name(new);					\
+								\
+	return res;						\
+}								\
+								\
+static inline unsigned long					\
+clear_##name(unsigned long clear)				\
+{								\
+	unsigned long res, new;					\
+								\
+	res = read_##name();					\
+	new = res & ~clear;					\
+	write_##name(new);					\
+								\
+	return res;						\
+}								\
+								\
+static inline unsigned long					\
+change_##name(unsigned long change, unsigned long val)		\
+{								\
+	unsigned long res, new;					\
+								\
+	res = read_##name();					\
+	new = res & ~change;					\
+	new |= (val & change);					\
+	write_##name(new);					\
+								\
+	return res;						\
+}
+
+#define __BUILD_CSR_OP(name)	__BUILD_CSR_COMMON(csr_##name)
+
+__BUILD_CSR_OP(euen)
+__BUILD_CSR_OP(ecfg)
+__BUILD_CSR_OP(tlbidx)
+
+#define set_csr_estat(val)	\
+	csr_xchg32(val, val, LOONGARCH_CSR_ESTAT)
+#define clear_csr_estat(val)	\
+	csr_xchg32(~(val), val, LOONGARCH_CSR_ESTAT)
+
+#endif /* __ASSEMBLY__ */
+
+/* Generic EntryLo bit definitions */
+#define ENTRYLO_V		(_ULCAST_(1) << 0)
+#define ENTRYLO_D		(_ULCAST_(1) << 1)
+#define ENTRYLO_PLV_SHIFT	2
+#define ENTRYLO_PLV		(_ULCAST_(3) << ENTRYLO_PLV_SHIFT)
+#define ENTRYLO_C_SHIFT		4
+#define ENTRYLO_C		(_ULCAST_(3) << ENTRYLO_C_SHIFT)
+#define ENTRYLO_G		(_ULCAST_(1) << 6)
+#define ENTRYLO_NR		(_ULCAST_(1) << 61)
+#define ENTRYLO_NX		(_ULCAST_(1) << 62)
+
+/* Values for PageSize register */
+#define PS_4K		0x0000000c
+#define PS_8K		0x0000000d
+#define PS_16K		0x0000000e
+#define PS_32K		0x0000000f
+#define PS_64K		0x00000010
+#define PS_128K		0x00000011
+#define PS_256K		0x00000012
+#define PS_512K		0x00000013
+#define PS_1M		0x00000014
+#define PS_2M		0x00000015
+#define PS_4M		0x00000016
+#define PS_8M		0x00000017
+#define PS_16M		0x00000018
+#define PS_32M		0x00000019
+#define PS_64M		0x0000001a
+#define PS_128M		0x0000001b
+#define PS_256M		0x0000001c
+#define PS_512M		0x0000001d
+#define PS_1G		0x0000001e
+
+/* ExStatus.ExcCode */
+#define EXCCODE_RSV		0	/* Reserved */
+#define EXCCODE_TLBL		1	/* TLB miss on a load */
+#define EXCCODE_TLBS		2	/* TLB miss on a store */
+#define EXCCODE_TLBI		3	/* TLB miss on a ifetch */
+#define EXCCODE_TLBM		4	/* TLB modified fault */
+#define EXCCODE_TLBNR		5	/* TLB Read-Inhibit exception */
+#define EXCCODE_TLBNX		6	/* TLB Execution-Inhibit exception */
+#define EXCCODE_TLBPE		7	/* TLB Privilege Error */
+#define EXCCODE_ADE		8	/* Address Error */
+	#define EXSUBCODE_ADEF		0	/* Fetch Instruction */
+	#define EXSUBCODE_ADEM		1	/* Access Memory*/
+#define EXCCODE_ALE		9	/* Unalign Access */
+#define EXCCODE_BCE		10	/* Bounds Check Error */
+#define EXCCODE_SYS		11	/* System call */
+#define EXCCODE_BP		12	/* Breakpoint */
+#define EXCCODE_INE		13	/* Inst. Not Exist */
+#define EXCCODE_IPE		14	/* Inst. Privileged Error */
+#define EXCCODE_FPDIS		15	/* FPU Disabled */
+#define EXCCODE_LSXDIS		16	/* LSX Disabled */
+#define EXCCODE_LASXDIS		17	/* LASX Disabled */
+#define EXCCODE_FPE		18	/* Floating Point Exception */
+	#define EXCSUBCODE_FPE		0	/* Floating Point Exception */
+	#define EXCSUBCODE_VFPE		1	/* Vector Exception */
+#define EXCCODE_WATCH		19	/* WatchPoint Exception */
+	#define EXCSUBCODE_WPEF		0	/* ... on Instruction Fetch */
+	#define EXCSUBCODE_WPEM		1	/* ... on Memory Accesses */
+#define EXCCODE_BTDIS		20	/* Binary Trans. Disabled */
+#define EXCCODE_BTE		21	/* Binary Trans. Exception */
+#define EXCCODE_GSPR		22	/* Guest Privileged Error */
+#define EXCCODE_HVC		23	/* Hypercall */
+#define EXCCODE_GCM		24	/* Guest CSR modified */
+	#define EXCSUBCODE_GCSC		0	/* Software caused */
+	#define EXCSUBCODE_GCHC		1	/* Hardware caused */
+#define EXCCODE_SE		25	/* Security */
+
+/* Interrupt numbers */
+#define INT_SWI0	0	/* Software Interrupts */
+#define INT_SWI1	1
+#define INT_HWI0	2	/* Hardware Interrupts */
+#define INT_HWI1	3
+#define INT_HWI2	4
+#define INT_HWI3	5
+#define INT_HWI4	6
+#define INT_HWI5	7
+#define INT_HWI6	8
+#define INT_HWI7	9
+#define INT_PCOV	10	/* Performance Counter Overflow */
+#define INT_TI		11	/* Timer */
+#define INT_IPI		12
+#define INT_NMI		13
+
+/* ExcCodes corresponding to interrupts */
+#define EXCCODE_INT_NUM		(INT_NMI + 1)
+#define EXCCODE_INT_START	64
+#define EXCCODE_INT_END		(EXCCODE_INT_START + EXCCODE_INT_NUM - 1)
+
+/* FPU Status Register Names */
+#ifndef CONFIG_AS_HAS_FCSR_CLASS
+#define LOONGARCH_FCSR0	$r0
+#define LOONGARCH_FCSR1	$r1
+#define LOONGARCH_FCSR2	$r2
+#define LOONGARCH_FCSR3	$r3
+#else
+#define LOONGARCH_FCSR0	$fcsr0
+#define LOONGARCH_FCSR1	$fcsr1
+#define LOONGARCH_FCSR2	$fcsr2
+#define LOONGARCH_FCSR3	$fcsr3
+#endif
+
+/* FPU Status Register Values */
+#define FPU_CSR_RSVD	0xe0e0fce0
+
+/*
+ * X the exception cause indicator
+ * E the exception enable
+ * S the sticky/flag bit
+ */
+#define FPU_CSR_ALL_X	0x1f000000
+#define FPU_CSR_INV_X	0x10000000
+#define FPU_CSR_DIV_X	0x08000000
+#define FPU_CSR_OVF_X	0x04000000
+#define FPU_CSR_UDF_X	0x02000000
+#define FPU_CSR_INE_X	0x01000000
+
+#define FPU_CSR_ALL_S	0x001f0000
+#define FPU_CSR_INV_S	0x00100000
+#define FPU_CSR_DIV_S	0x00080000
+#define FPU_CSR_OVF_S	0x00040000
+#define FPU_CSR_UDF_S	0x00020000
+#define FPU_CSR_INE_S	0x00010000
+
+#define FPU_CSR_ALL_E	0x0000001f
+#define FPU_CSR_INV_E	0x00000010
+#define FPU_CSR_DIV_E	0x00000008
+#define FPU_CSR_OVF_E	0x00000004
+#define FPU_CSR_UDF_E	0x00000002
+#define FPU_CSR_INE_E	0x00000001
+
+/* Bits 8 and 9 of FPU Status Register specify the rounding mode */
+#define FPU_CSR_RM	0x300
+#define FPU_CSR_RN	0x000	/* nearest */
+#define FPU_CSR_RZ	0x100	/* towards zero */
+#define FPU_CSR_RU	0x200	/* towards +Infinity */
+#define FPU_CSR_RD	0x300	/* towards -Infinity */
+
+/* Bit 6 of FPU Status Register specify the LBT TOP simulation mode */
+#define FPU_CSR_TM_SHIFT	0x6
+#define FPU_CSR_TM		(_ULCAST_(1) << FPU_CSR_TM_SHIFT)
+
+#define read_fcsr(source)	\
+({	\
+	unsigned int __res;	\
+\
+	__asm__ __volatile__(	\
+	"	movfcsr2gr	%0, "__stringify(source)" \n"	\
+	: "=r" (__res));	\
+	__res;	\
+})
+
+#define write_fcsr(dest, val) \
+do {	\
+	__asm__ __volatile__(	\
+	"	movgr2fcsr	"__stringify(dest)", %0	\n"	\
+	: : "r" (val));	\
+} while (0)
+
+#endif /* _ASM_LOONGARCH_H */
diff --git a/arch/loongarch/include/asm/posix_types.h b/arch/loongarch/include/asm/posix_types.h
new file mode 100644
index 000000000000..0ed5fa4c5fae
--- /dev/null
+++ b/arch/loongarch/include/asm/posix_types.h
@@ -0,0 +1,87 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * linux/include/asm-arm/posix_types.h
+ *
+ * Copyright (C) 1996-1998 Russell King.
+ *
+ * Copyright (C) 2011 Andes Technology Corporation
+ * Copyright (C) 2010 Shawn Lin (nobuhiro@andestech.com)
+ * Copyright (C) 2011 Macpaul Lin (macpaul@andestech.com)
+ * Copyright (C) 2017 Rick Chen (rick@andestech.com)
+ * Copyright (C) 2024 Jiaxun Yang <jiaxun.yang@flygoat.com>
+ */
+#ifndef __ARCH_LOONGARCH_POSIX_TYPES_H
+#define __ARCH_LOONGARCH_POSIX_TYPES_H
+
+/*
+ * This file is generally used by user-level software, so you need to
+ * be a little careful about namespace pollution etc.  Also, we cannot
+ * assume GCC is being used.
+ */
+
+typedef unsigned short		__kernel_dev_t;
+typedef unsigned long		__kernel_ino_t;
+typedef unsigned short		__kernel_mode_t;
+typedef unsigned short		__kernel_nlink_t;
+typedef long			__kernel_off_t;
+typedef int			__kernel_pid_t;
+typedef unsigned short		__kernel_ipc_pid_t;
+typedef unsigned short		__kernel_uid_t;
+typedef unsigned short		__kernel_gid_t;
+#ifdef __GNUC__
+typedef __SIZE_TYPE__		__kernel_size_t;
+#else
+typedef unsigned long		__kernel_size_t;
+#endif
+typedef long			__kernel_ssize_t;
+typedef long			__kernel_ptrdiff_t;
+typedef long			__kernel_time_t;
+typedef long			__kernel_suseconds_t;
+typedef long			__kernel_clock_t;
+typedef int			__kernel_daddr_t;
+typedef char			*__kernel_caddr_t;
+typedef unsigned short		__kernel_uid16_t;
+typedef unsigned short		__kernel_gid16_t;
+typedef unsigned int		__kernel_uid32_t;
+typedef unsigned int		__kernel_gid32_t;
+
+typedef unsigned short		__kernel_old_uid_t;
+typedef unsigned short		__kernel_old_gid_t;
+
+#ifdef __GNUC__
+typedef long long		__kernel_loff_t;
+#endif
+
+typedef struct {
+#if defined(__KERNEL__) || defined(__USE_ALL)
+	int	val[2];
+#else /* !defined(__KERNEL__) && !defined(__USE_ALL) */
+	int	__val[2];
+#endif /* !defined(__KERNEL__) && !defined(__USE_ALL) */
+} __kernel_fsid_t;
+
+#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2)
+
+#undef	__FD_SET
+#define __FD_SET(_fd, fdsetp) \
+	typeof(_fd) (fd) = (_fd); \
+	(((fd_set *)fdsetp)->fds_bits[fd >> 5] |= (1 << (fd & 31)))
+
+#undef	__FD_CLR
+#define __FD_CLR(_fd, fdsetp) \
+	typeof(_fd) (fd) = (_fd); \
+	(((fd_set *)fdsetp)->fds_bits[fd >> 5] &= ~(1 << (fd & 31)))
+
+#undef	__FD_ISSET
+#define __FD_ISSET(_fd, fdsetp) \
+	typeof(_fd) (fd) = (_fd); \
+	((((fd_set *)fdsetp)->fds_bits[fd >> 5] & (1 << (fd & 31))) != 0)
+
+#undef	__FD_ZERO
+#define __FD_ZERO(_fdsetp) \
+	typeof(_fdsetp) (fd) = (_fdsetp); \
+	(memset(fdsetp, 0, sizeof(*(fd_set *)fdsetp)))
+
+#endif
+
+#endif /* __ARCH_LOONGARCH_POSIX_TYPES_H */
diff --git a/arch/loongarch/include/asm/processor.h b/arch/loongarch/include/asm/processor.h
new file mode 100644
index 000000000000..7242a3e6ca7e
--- /dev/null
+++ b/arch/loongarch/include/asm/processor.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2024 Jiaxun Yang <jiaxun.yang@flygoat.com>
+ */
+
+#ifndef __ASM_LOONGARCH_PROCESSOR_H
+#define __ASM_LOONGARCH_PROCESSOR_H
+
+/* Dummy header */
+
+#endif /* __ASM_LOONGARCH_PROCESSOR_H */
diff --git a/arch/loongarch/include/asm/ptrace.h b/arch/loongarch/include/asm/ptrace.h
new file mode 100644
index 000000000000..1b3c2b5b8f16
--- /dev/null
+++ b/arch/loongarch/include/asm/ptrace.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2024 Jiaxun Yang <jiaxun.yang@flygoat.com>
+ */
+
+#ifndef __ASM_LOONGARCH_PTRACE_H
+#define __ASM_LOONGARCH_PTRACE_H
+
+struct pt_regs {
+	/* Main processor registers. */
+	unsigned long regs[32];
+
+	/* Original syscall arg0. */
+	unsigned long orig_a0;
+
+	/* Special CSR registers. */
+	unsigned long csr_era;
+	unsigned long csr_badvaddr;
+	unsigned long csr_crmd;
+	unsigned long csr_prmd;
+	unsigned long csr_euen;
+	unsigned long csr_ecfg;
+	unsigned long csr_estat;
+	unsigned long __last[];
+} __aligned(8);
+
+#ifdef CONFIG_64BIT
+#define REG_FMT "%016lx"
+#else
+#define REG_FMT "%08lx"
+#endif
+
+#endif /* __ASM_LOONGARCH_PTRACE_H */
diff --git a/arch/loongarch/include/asm/regdef.h b/arch/loongarch/include/asm/regdef.h
new file mode 100644
index 000000000000..5fbc0d4757e3
--- /dev/null
+++ b/arch/loongarch/include/asm/regdef.h
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
+ * Copyright (C) 2024 Jiaxun Yang <jiaxun.yang@flygoat.com>
+ */
+#ifndef _ASM_REGDEF_H
+#define _ASM_REGDEF_H
+
+#define zero	$r0	/* wired zero */
+#define ra	$r1	/* return address */
+#define tp	$r2
+#define sp	$r3	/* stack pointer */
+#define a0	$r4	/* argument registers, a0/a1 reused as v0/v1 for return value */
+#define a1	$r5
+#define a2	$r6
+#define a3	$r7
+#define a4	$r8
+#define a5	$r9
+#define a6	$r10
+#define a7	$r11
+#define t0	$r12	/* caller saved */
+#define t1	$r13
+#define t2	$r14
+#define t3	$r15
+#define t4	$r16
+#define t5	$r17
+#define t6	$r18
+#define t7	$r19
+#define t8	$r20
+#define u0	$r21
+#define fp	$r22	/* frame pointer */
+#define s0	$r23	/* callee saved */
+#define s1	$r24
+#define s2	$r25
+#define s3	$r26
+#define s4	$r27
+#define s5	$r28
+#define s6	$r29
+#define s7	$r30
+#define s8	$r31
+
+#endif /* _ASM_REGDEF_H */
diff --git a/arch/loongarch/include/asm/sections.h b/arch/loongarch/include/asm/sections.h
new file mode 100644
index 000000000000..9f5009a1f235
--- /dev/null
+++ b/arch/loongarch/include/asm/sections.h
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+
+#ifndef __ASM_LOONGARCH_SECTIONS_H
+#define __ASM_LOONGARCH_SECTIONS_H
+
+#include <asm-generic/sections.h>
+
+#endif
diff --git a/arch/loongarch/include/asm/setjmp.h b/arch/loongarch/include/asm/setjmp.h
new file mode 100644
index 000000000000..295198a38964
--- /dev/null
+++ b/arch/loongarch/include/asm/setjmp.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2024 Jiaxun Yang <jiaxun.yang@flygoat.com>
+ */
+
+#ifndef _SETJMP_H_
+#define _SETJMP_H_
+
+/*
+ * This really should be opaque, but the EFI implementation wrongly
+ * assumes that a 'struct jmp_buf_data' is defined.
+ */
+struct jmp_buf_data {
+	unsigned long s_regs[9];	/* s0 - 8 */
+	unsigned long fp;
+	unsigned long sp;
+	unsigned long ra;
+};
+
+typedef struct jmp_buf_data jmp_buf[1];
+
+int setjmp(jmp_buf jmp);
+void longjmp(jmp_buf jmp, int ret);
+
+#endif /* _SETJMP_H_ */
diff --git a/arch/loongarch/include/asm/spl.h b/arch/loongarch/include/asm/spl.h
new file mode 100644
index 000000000000..b8b19f65cb36
--- /dev/null
+++ b/arch/loongarch/include/asm/spl.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2024 Jiaxun Yang <jiaxun.yang@flygoat.com>
+ */
+
+#ifndef __ASM_SPL_H
+#define __ASM_SPL_H
+
+/* Dummy header */
+
+#endif
diff --git a/arch/loongarch/include/asm/string.h b/arch/loongarch/include/asm/string.h
new file mode 100644
index 000000000000..09877956de9a
--- /dev/null
+++ b/arch/loongarch/include/asm/string.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2024 Jiaxun Yang <jiaxun.yang@flygoat.com>
+ */
+
+#ifndef __ASM_STRING_H
+#define __ASM_STRING_H
+
+/* Dummy header */
+
+#endif
diff --git a/arch/loongarch/include/asm/system.h b/arch/loongarch/include/asm/system.h
new file mode 100644
index 000000000000..79c47418d52c
--- /dev/null
+++ b/arch/loongarch/include/asm/system.h
@@ -0,0 +1,74 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2024 Jiaxun Yang <jiaxun.yang@flygoat.com>
+ */
+
+#ifndef __ASM_LOONGARCH_SYSTEM_H
+#define __ASM_LOONGARCH_SYSTEM_H
+
+#include <asm/loongarch.h>
+
+struct event;
+
+/*
+ * Interrupt configuration macros
+ */
+
+static inline void arch_local_irq_enable(void)
+{
+	u32 flags = CSR_CRMD_IE;
+
+	__asm__ __volatile__(
+		"csrxchg %[val], %[mask], %[reg]\n\t"
+		: [val] "+r" (flags)
+		: [mask] "r" (CSR_CRMD_IE), [reg] "i" (LOONGARCH_CSR_CRMD)
+		: "memory");
+}
+
+#define local_irq_enable arch_local_irq_enable
+
+static inline void arch_local_irq_disable(void)
+{
+	u32 flags = 0;
+
+	__asm__ __volatile__(
+		"csrxchg %[val], %[mask], %[reg]\n\t"
+		: [val] "+r" (flags)
+		: [mask] "r" (CSR_CRMD_IE), [reg] "i" (LOONGARCH_CSR_CRMD)
+		: "memory");
+}
+
+#define local_irq_disable arch_local_irq_disable
+
+static inline unsigned long arch_local_irq_save(void)
+{
+	unsigned long flags = 0;
+
+	__asm__ __volatile__(
+		"csrxchg %[val], %[mask], %[reg]\n\t"
+		: [val] "+r" (flags)
+		: [mask] "r" (CSR_CRMD_IE), [reg] "i" (LOONGARCH_CSR_CRMD)
+		: "memory");
+	return flags;
+}
+
+#define local_irq_save(__flags)                                 \
+	do {                                                        \
+		__flags = arch_local_irq_save(CSR_SSTATUS, SR_SIE) & SR_SIE; \
+	} while (0)
+
+static inline void arch_local_irq_restore(unsigned long flags)
+{
+	__asm__ __volatile__(
+		"csrxchg %[val], %[mask], %[reg]\n\t"
+		: [val] "+r" (flags)
+		: [mask] "r" (CSR_CRMD_IE), [reg] "i" (LOONGARCH_CSR_CRMD)
+		: "memory");
+}
+
+#define local_irq_restore(__flags)              \
+	do {                                        \
+		arch_local_irq_restore(__flags); \
+	} while (0)
+
+#endif
diff --git a/arch/loongarch/include/asm/types.h b/arch/loongarch/include/asm/types.h
new file mode 100644
index 000000000000..414e8f9160a0
--- /dev/null
+++ b/arch/loongarch/include/asm/types.h
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2011 Andes Technology Corporation
+ * Copyright (C) 2010 Shawn Lin (nobuhiro@andestech.com)
+ * Copyright (C) 2011 Macpaul Lin (macpaul@andestech.com)
+ * Copyright (C) 2017 Rick Chen (rick@andestech.com)
+ * Copyright (C) 2024 Jiaxun Yang <jiaxun.yang@flygoat.com>
+ */
+
+#ifndef __ASM_LOONGARCH_TYPES_H
+#define __ASM_LOONGARCH_TYPES_H
+
+#include <asm-generic/int-ll64.h>
+
+typedef unsigned short umode_t;
+
+/*
+ * These aren't exported outside the kernel to avoid name space clashes
+ */
+#ifdef __KERNEL__
+
+#define BITS_PER_LONG _LOONGARCH_SZLONG
+
+#include <stddef.h>
+
+#ifdef CONFIG_DMA_ADDR_T_64BIT
+typedef u64 dma_addr_t;
+#else
+typedef u32 dma_addr_t;
+#endif
+
+typedef unsigned long long phys_addr_t;
+typedef unsigned long long phys_size_t;
+
+#endif /* __KERNEL__ */
+
+#endif
diff --git a/arch/loongarch/include/asm/u-boot-loongarch.h b/arch/loongarch/include/asm/u-boot-loongarch.h
new file mode 100644
index 000000000000..7f21d2a3e963
--- /dev/null
+++ b/arch/loongarch/include/asm/u-boot-loongarch.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Marius Groeger <mgroeger@sysgo.de>
+ *
+ * Copyright (C) 2017 Andes Technology Corporation
+ * Rick Chen, Andes Technology Corporation <rick@andestech.com>
+ *
+ * Copyright (C) 2024 Jiaxun Yang <jiaxun.yang@flygoat.com>
+ */
+
+#ifndef _U_BOOT_LOONGARCH_H_
+#define _U_BOOT_LOONGARCH_H_
+
+/* cpu/.../cpu.c */
+int cleanup_before_linux(void);
+
+/* board/.../... */
+int board_init(void);
+void board_quiesce_devices(void);
+
+#endif
diff --git a/arch/loongarch/include/asm/u-boot.h b/arch/loongarch/include/asm/u-boot.h
new file mode 100644
index 000000000000..123a7f09a01c
--- /dev/null
+++ b/arch/loongarch/include/asm/u-boot.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Marius Groeger <mgroeger@sysgo.de>
+ *
+ * Copyright (C) 2017 Andes Technology Corporation
+ * Rick Chen, Andes Technology Corporation <rick@andestech.com>
+ *
+ * Copyright (C) 2024 Jiaxun Yang <jiaxun.yang@flygoat.com>
+ *
+ ********************************************************************
+ * NOTE: This header file defines an interface to U-Boot. Including
+ * this (unmodified) header file in another file is considered normal
+ * use of U-Boot, and does *not* fall under the heading of "derived
+ * work".
+ ********************************************************************
+ */
+
+#ifndef _U_BOOT_H_
+#define _U_BOOT_H_	1
+
+/* Use the generic board which requires a unified bd_info */
+#include <asm-generic/u-boot.h>
+#include <asm/u-boot-loongarch.h>
+
+/* For image.h:image_check_target_arch() */
+#define IH_ARCH_DEFAULT IH_ARCH_LOONGARCH
+
+#endif	/* _U_BOOT_H_ */
diff --git a/arch/loongarch/include/asm/unaligned.h b/arch/loongarch/include/asm/unaligned.h
new file mode 100644
index 000000000000..65cd4340ce93
--- /dev/null
+++ b/arch/loongarch/include/asm/unaligned.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2024 Jiaxun Yang <jiaxun.yang@flygoat.com>
+ */
+
+#ifndef __ASM_LOONGARCH_UNALIGNED_H
+#define __ASM_LOONGARCH_UNALIGNED_H
+
+#include <asm-generic/unaligned.h>
+
+#endif
diff --git a/arch/loongarch/lib/Makefile b/arch/loongarch/lib/Makefile
new file mode 100644
index 000000000000..3dbed94cc624
--- /dev/null
+++ b/arch/loongarch/lib/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (C) 2024 Jiaxun yang <jiaxun.yang@flygoat.com>
+#
+
diff --git a/include/host_arch.h b/include/host_arch.h
index 261194bd7c6e..ceeb61d6ad88 100644
--- a/include/host_arch.h
+++ b/include/host_arch.h
@@ -10,6 +10,7 @@
 #if 0
 export HOST_ARCH_AARCH64=0xaa64
 export HOST_ARCH_ARM=0x00a7
+export HOST_ARCH_LOONGARCH64=0x6264
 export HOST_ARCH_RISCV32=0x5032
 export HOST_ARCH_RISCV64=0x5064
 export HOST_ARCH_X86=0x0386
@@ -20,6 +21,7 @@ export HOST_ARCH_X86_64=0x8664
 
 #define HOST_ARCH_AARCH64 0xaa64
 #define HOST_ARCH_ARM 0x00a7
+#define HOST_ARCH_LOONGARCH64 0x6264
 #define HOST_ARCH_RISCV32 0x5032
 #define HOST_ARCH_RISCV64 0x5064
 #define HOST_ARCH_X86 0x0386
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH v2 07/16] LoongArch: lib: General routines
  2026-07-01 11:17 [PATCH v2 00/16] LoongArch initial support Yao Zi
                   ` (5 preceding siblings ...)
  2026-07-01 11:17 ` [PATCH v2 06/16] LoongArch: skeleton and headers Yao Zi
@ 2026-07-01 11:17 ` Yao Zi
  2026-07-01 17:49   ` Tom Rini
  2026-07-02 10:28   ` Simon Glass
  2026-07-01 11:18 ` [PATCH v2 08/16] LoongArch: CPU assembly routines Yao Zi
                   ` (11 subsequent siblings)
  18 siblings, 2 replies; 56+ messages in thread
From: Yao Zi @ 2026-07-01 11:17 UTC (permalink / raw)
  To: Tom Rini, Jiaxun Yang, Heinrich Schuchardt, Ilias Apalodimas
  Cc: u-boot, Yao Zi

From: Jiaxun Yang <jiaxun.yang@flygoat.com>

Add some common library routines for the architecture.

Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
Signed-off-by: Yao Zi <me@ziyao.cc>
---

Changed from v1
- Correctly implement dcache operations

 arch/loongarch/include/asm/cache.h       |  10 ++
 arch/loongarch/include/asm/global_data.h |   7 +
 arch/loongarch/lib/Makefile              |   7 +
 arch/loongarch/lib/asm-offsets.c         |  66 +++++++
 arch/loongarch/lib/boot.c                |  14 ++
 arch/loongarch/lib/cache.c               | 213 +++++++++++++++++++++++
 arch/loongarch/lib/reset.c               |  14 ++
 arch/loongarch/lib/setjmp.S              |  52 ++++++
 8 files changed, 383 insertions(+)
 create mode 100644 arch/loongarch/lib/asm-offsets.c
 create mode 100644 arch/loongarch/lib/boot.c
 create mode 100644 arch/loongarch/lib/cache.c
 create mode 100644 arch/loongarch/lib/reset.c
 create mode 100644 arch/loongarch/lib/setjmp.S

diff --git a/arch/loongarch/include/asm/cache.h b/arch/loongarch/include/asm/cache.h
index 854dd0c0a02e..2dd4e82340bb 100644
--- a/arch/loongarch/include/asm/cache.h
+++ b/arch/loongarch/include/asm/cache.h
@@ -6,8 +6,11 @@
 #ifndef _ASM_LOONGARCH_CACHE_H
 #define _ASM_LOONGARCH_CACHE_H
 
+#include <linux/bitops.h>
+
 /* cache */
 void cache_flush(void);
+void probe_caches(void);
 
 #define cache_op(op, addr)						\
 	__asm__ __volatile__(						\
@@ -15,6 +18,13 @@ void cache_flush(void);
 	:								\
 	: "i" (op), "ZC" (*(unsigned char *)(addr)))
 
+#define CACHE_MAX_LEVEL		3
+#define CACHE_MAX_INDEX		6
+#define CACHE_OP		GENMASK(4, 3)
+#define  CACHE_INDEX_INVWB	0x1
+#define  CACHE_HIT_INVWB	0x2
+#define CACHE_INDEX		GENMASK(2, 0)
+
 #ifdef CONFIG_SYS_CACHELINE_SIZE
 #define ARCH_DMA_MINALIGN	CONFIG_SYS_CACHELINE_SIZE
 #else
diff --git a/arch/loongarch/include/asm/global_data.h b/arch/loongarch/include/asm/global_data.h
index 2a9a525e2f37..7aab802ca04d 100644
--- a/arch/loongarch/include/asm/global_data.h
+++ b/arch/loongarch/include/asm/global_data.h
@@ -10,6 +10,7 @@
 #define __ASM_GBL_DATA_H
 
 #include <linux/types.h>
+#include <asm/cache.h>
 #include <asm/u-boot.h>
 #include <compiler.h>
 
@@ -24,6 +25,12 @@ struct arch_global_data {
 #ifdef CONFIG_SMBIOS
 	ulong smbios_start;		/* Start address of SMBIOS table */
 #endif
+	ushort dcache_ways[CACHE_MAX_INDEX];
+	ushort dcache_sets[CACHE_MAX_INDEX];
+	ushort dcache_linesizes[CACHE_MAX_INDEX];
+	ushort dcache_index[CACHE_MAX_INDEX];
+	ushort dcache_levels;
+	bool dcache_inclusive;
 };
 
 #include <asm-generic/global_data.h>
diff --git a/arch/loongarch/lib/Makefile b/arch/loongarch/lib/Makefile
index 3dbed94cc624..3c17b9cd85af 100644
--- a/arch/loongarch/lib/Makefile
+++ b/arch/loongarch/lib/Makefile
@@ -3,3 +3,10 @@
 # Copyright (C) 2024 Jiaxun yang <jiaxun.yang@flygoat.com>
 #
 
+obj-$(CONFIG_CMD_GO) += boot.o
+obj-y	+= cache.o
+obj-y	+= interrupts.o
+ifeq ($(CONFIG_$(SPL_)SYSRESET),)
+obj-y	+= reset.o
+endif
+obj-y	+= setjmp.o
diff --git a/arch/loongarch/lib/asm-offsets.c b/arch/loongarch/lib/asm-offsets.c
new file mode 100644
index 000000000000..e3f4c629b63d
--- /dev/null
+++ b/arch/loongarch/lib/asm-offsets.c
@@ -0,0 +1,66 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2024 Jiaxun Yang <jiaxun.yang@flygoat.com>
+ *
+ * From arch/x86/lib/asm-offsets.c
+ *
+ * This program is used to generate definitions needed by
+ * assembly language modules.
+ */
+
+#include <asm/global_data.h>
+#include <asm/ptrace.h>
+#include <linux/kbuild.h>
+
+static void __used output_ptreg_defines(void)
+{
+	COMMENT("LoongArch pt_regs offsets.");
+	OFFSET(PT_R0, pt_regs, regs[0]);
+	OFFSET(PT_R1, pt_regs, regs[1]);
+	OFFSET(PT_R2, pt_regs, regs[2]);
+	OFFSET(PT_R3, pt_regs, regs[3]);
+	OFFSET(PT_R4, pt_regs, regs[4]);
+	OFFSET(PT_R5, pt_regs, regs[5]);
+	OFFSET(PT_R6, pt_regs, regs[6]);
+	OFFSET(PT_R7, pt_regs, regs[7]);
+	OFFSET(PT_R8, pt_regs, regs[8]);
+	OFFSET(PT_R9, pt_regs, regs[9]);
+	OFFSET(PT_R10, pt_regs, regs[10]);
+	OFFSET(PT_R11, pt_regs, regs[11]);
+	OFFSET(PT_R12, pt_regs, regs[12]);
+	OFFSET(PT_R13, pt_regs, regs[13]);
+	OFFSET(PT_R14, pt_regs, regs[14]);
+	OFFSET(PT_R15, pt_regs, regs[15]);
+	OFFSET(PT_R16, pt_regs, regs[16]);
+	OFFSET(PT_R17, pt_regs, regs[17]);
+	OFFSET(PT_R18, pt_regs, regs[18]);
+	OFFSET(PT_R19, pt_regs, regs[19]);
+	OFFSET(PT_R20, pt_regs, regs[20]);
+	OFFSET(PT_R21, pt_regs, regs[21]);
+	OFFSET(PT_R22, pt_regs, regs[22]);
+	OFFSET(PT_R23, pt_regs, regs[23]);
+	OFFSET(PT_R24, pt_regs, regs[24]);
+	OFFSET(PT_R25, pt_regs, regs[25]);
+	OFFSET(PT_R26, pt_regs, regs[26]);
+	OFFSET(PT_R27, pt_regs, regs[27]);
+	OFFSET(PT_R28, pt_regs, regs[28]);
+	OFFSET(PT_R29, pt_regs, regs[29]);
+	OFFSET(PT_R30, pt_regs, regs[30]);
+	OFFSET(PT_R31, pt_regs, regs[31]);
+	OFFSET(PT_CRMD, pt_regs, csr_crmd);
+	OFFSET(PT_PRMD, pt_regs, csr_prmd);
+	OFFSET(PT_EUEN, pt_regs, csr_euen);
+	OFFSET(PT_ECFG, pt_regs, csr_ecfg);
+	OFFSET(PT_ESTAT, pt_regs, csr_estat);
+	OFFSET(PT_ERA, pt_regs, csr_era);
+	OFFSET(PT_BVADDR, pt_regs, csr_badvaddr);
+	OFFSET(PT_ORIG_A0, pt_regs, orig_a0);
+	DEFINE(PT_SIZE, sizeof(struct pt_regs));
+	BLANK();
+}
+
+int main(void)
+{
+	output_ptreg_defines();
+	return 0;
+}
diff --git a/arch/loongarch/lib/boot.c b/arch/loongarch/lib/boot.c
new file mode 100644
index 000000000000..327be16bb59f
--- /dev/null
+++ b/arch/loongarch/lib/boot.c
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2024 Jiaxun Yang <jiaxun.yang@flygoat.com>
+ */
+
+#include <asm/u-boot.h>
+
+unsigned long do_go_exec(ulong (*entry)(int, char * const []),
+			 int argc, char *const argv[])
+{
+	cleanup_before_linux();
+
+	return entry(argc, argv);
+}
diff --git a/arch/loongarch/lib/cache.c b/arch/loongarch/lib/cache.c
new file mode 100644
index 000000000000..ee27ec28b724
--- /dev/null
+++ b/arch/loongarch/lib/cache.c
@@ -0,0 +1,213 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2024 Jiaxun Yang <jiaxun.yang@flygoat.com>
+ * Copyright (C) 2026 Yao Zi <me@ziyao.cc>
+ */
+
+#include <asm/cache.h>
+#include <asm/global_data.h>
+#include <asm/loongarch.h>
+#include <cpu_func.h>
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+
+#define CPUCFG_LX_IUPRE		BIT(0)
+#define CPUCFG_LX_IUUNIFY	BIT(1)
+#define CPUCFG_LX_IUINCL	BIT(3)
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static inline void flush_cache_line_index(unsigned int index,
+					  unsigned long addr)
+{
+#define do_flush(index)							\
+	case index:							\
+		cache_op(FIELD_PREP(CACHE_OP, CACHE_INDEX_INVWB) |	\
+			 FIELD_PREP(CACHE_INDEX, index),		\
+			 index);					\
+		break;
+
+	switch (index) {
+		do_flush(0);
+		do_flush(1);
+		do_flush(2);
+		do_flush(3);
+		do_flush(4);
+		do_flush(5);
+	}
+
+#undef do_flush
+}
+
+static inline void flush_cache_line_hit(unsigned int index, unsigned long addr)
+{
+#define do_flush(index)							\
+	case index:							\
+		cache_op(FIELD_PREP(CACHE_OP, CACHE_HIT_INVWB) |	\
+			 FIELD_PREP(CACHE_INDEX, index),		\
+			 addr);						\
+		break;
+
+	switch (index) {
+		do_flush(0);
+		do_flush(1);
+		do_flush(2);
+		do_flush(3);
+		do_flush(4);
+		do_flush(5);
+	}
+
+#undef do_flush
+}
+
+void invalidate_icache_all(void)
+{
+	asm volatile ("\tibar 0\n"::);
+}
+
+static void flush_dcache_level_all(unsigned int level)
+{
+	unsigned int way, set;
+	unsigned long index = 0;
+
+	for (set = 0; set < gd->arch.dcache_sets[level]; set++) {
+		for (way = 0; way < gd->arch.dcache_ways[level]; way++) {
+			flush_cache_line_index(gd->arch.dcache_index[level],
+					       index);
+			index++;
+		}
+
+		index -= gd->arch.dcache_ways[level];
+		index += gd->arch.dcache_linesizes[level];
+	}
+}
+
+__weak void flush_dcache_all(void)
+{
+	unsigned int level;
+
+	if (gd->arch.dcache_inclusive) {
+		flush_dcache_level_all(gd->arch.dcache_levels - 1);
+		return;
+	}
+
+	for (level = 0; level < gd->arch.dcache_levels; level++)
+		flush_dcache_level_all(level);
+}
+
+static void flush_dcache_level(unsigned int level, unsigned long addr,
+			       unsigned long end)
+{
+	for (; addr < end; addr += gd->arch.dcache_linesizes[level])
+		flush_cache_line_hit(gd->arch.dcache_index[level], addr);
+}
+
+__weak void flush_dcache_range(unsigned long start, unsigned long end)
+{
+	unsigned int level;
+
+	if (gd->arch.dcache_inclusive) {
+		flush_dcache_level(gd->arch.dcache_levels - 1, start, end);
+		return;
+	}
+
+	for (level = 0; level < gd->arch.dcache_levels; level++)
+		flush_dcache_level(level, start, end);
+}
+
+__weak void invalidate_icache_range(unsigned long start, unsigned long end)
+{
+	/* LoongArch mandatory hardware I-Cache coherence */
+	invalidate_icache_all();
+}
+
+__weak void invalidate_dcache_range(unsigned long start, unsigned long end)
+{
+	flush_dcache_range(start, end);
+}
+
+__weak void cache_flush(void)
+{
+	flush_dcache_all();
+}
+
+__weak void cache_invalidate(void)
+{
+	flush_dcache_all();
+}
+
+__weak void flush_cache(unsigned long addr, unsigned long size)
+{
+	invalidate_icache_range(addr, addr + size);
+	flush_dcache_range(addr, addr + size);
+}
+
+__weak void dcache_enable(void)
+{
+}
+
+__weak void dcache_disable(void)
+{
+}
+
+__weak int dcache_status(void)
+{
+	return 0;
+}
+
+static void populate_dcache_properties(u32 cfg0, unsigned int level,
+				       unsigned int cfgoff)
+{
+	u32 cfg1 = read_cpucfg(cfgoff);
+
+	if (level != 0)
+		gd->arch.dcache_inclusive = cfg0 & CPUCFG_LX_IUINCL;
+
+	gd->arch.dcache_ways[level] = FIELD_GET(CPUCFG_CACHE_WAYS_M, cfg1) + 1;
+	gd->arch.dcache_sets[level] = 1 << FIELD_GET(CPUCFG_CACHE_SETS_M, cfg1);
+	gd->arch.dcache_linesizes[level] = 1 << FIELD_GET(CPUCFG_CACHE_LSIZE_M, cfg1);
+}
+
+void probe_caches(void)
+{
+	unsigned int level = 0, index = 0;
+	u32 cfg = read_cpucfg(LOONGARCH_CPUCFG16);
+
+	if (cfg & CPUCFG16_L1_IUPRE) {
+		if (cfg & CPUCFG16_L1_IUUNIFY) {
+			gd->arch.dcache_index[level] = index;
+			populate_dcache_properties(cfg, level++,
+						   LOONGARCH_CPUCFG17);
+		}
+
+		index++;
+	}
+
+	if (cfg & CPUCFG16_L1_DPRE) {
+		gd->arch.dcache_index[level] = index++;
+		populate_dcache_properties(cfg, level++, LOONGARCH_CPUCFG18);
+	}
+
+	cfg >>= 3;
+
+	for (; level < 3; level++) {
+		if (cfg & CPUCFG_LX_IUPRE && cfg & CPUCFG_LX_IUUNIFY) {
+			gd->arch.dcache_index[level] = index++;
+			populate_dcache_properties(cfg, level,
+						   LOONGARCH_CPUCFG17 + level);
+		} else {
+			break;
+		}
+
+		cfg >>= 7;
+	}
+
+	gd->arch.dcache_levels = level;
+}
+
+__weak void enable_caches(void)
+{
+	cache_invalidate();
+	/* Enable cache for direct address translation mode */
+	csr_xchg64(1 << CSR_CRMD_DACM_SHIFT, CSR_CRMD_DACM, LOONGARCH_CSR_CRMD);
+}
diff --git a/arch/loongarch/lib/reset.c b/arch/loongarch/lib/reset.c
new file mode 100644
index 000000000000..ddf29ee41d95
--- /dev/null
+++ b/arch/loongarch/lib/reset.c
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2024 Jiaxun Yang <jiaxun.yang@flygoat.com>
+ */
+
+#include <command.h>
+#include <cpu_func.h>
+
+int do_reset(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
+{
+	reset_cpu();
+
+	return 0;
+}
diff --git a/arch/loongarch/lib/setjmp.S b/arch/loongarch/lib/setjmp.S
new file mode 100644
index 000000000000..12981d0013fa
--- /dev/null
+++ b/arch/loongarch/lib/setjmp.S
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2024 Jiaxun Yang <jiaxun.yang@flygoat.com>
+ */
+
+#include <config.h>
+#include <asm/asm.h>
+#include <linux/linkage.h>
+
+.pushsection .text.setjmp, "ax"
+ENTRY(setjmp)
+	LONG_S		s0, a0, 0
+	LONG_S 		s1, a0, (1 * LONGSIZE)
+	LONG_S		s2, a0, (2 * LONGSIZE)
+	LONG_S		s3, a0, (3 * LONGSIZE)
+	LONG_S		s4, a0, (4 * LONGSIZE)
+	LONG_S		s5, a0, (5 * LONGSIZE)
+	LONG_S		s6, a0, (6 * LONGSIZE)
+	LONG_S		s7, a0, (7 * LONGSIZE)
+	LONG_S		s8, a0, (8 * LONGSIZE)
+	LONG_S		fp, a0, (9 * LONGSIZE)
+	LONG_S		sp, a0, (10 * LONGSIZE)
+	LONG_S		ra, a0, (11 * LONGSIZE)
+
+	move		a0, zero
+	ret
+ENDPROC(setjmp)
+.popsection
+
+.pushsection .text.longjmp, "ax"
+ENTRY(longjmp)
+	LONG_L		s0, a0, 0
+	LONG_L 		s1, a0, (1 * LONGSIZE)
+	LONG_L		s2, a0, (2 * LONGSIZE)
+	LONG_L		s3, a0, (3 * LONGSIZE)
+	LONG_L		s4, a0, (4 * LONGSIZE)
+	LONG_L		s5, a0, (5 * LONGSIZE)
+	LONG_L		s6, a0, (6 * LONGSIZE)
+	LONG_L		s7, a0, (7 * LONGSIZE)
+	LONG_L		s8, a0, (8 * LONGSIZE)
+	LONG_L		fp, a0, (9 * LONGSIZE)
+	LONG_L		sp, a0, (10 * LONGSIZE)
+	LONG_L		ra, a0, (11 * LONGSIZE)
+
+	/* Move the return value in place, but return 1 if passed 0. */
+	li.w		a0, 1
+	beqz		a1, 1f
+	move		a0, a1
+1:
+	jr		ra
+ENDPROC(longjmp)
+.popsection
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH v2 08/16] LoongArch: CPU assembly routines
  2026-07-01 11:17 [PATCH v2 00/16] LoongArch initial support Yao Zi
                   ` (6 preceding siblings ...)
  2026-07-01 11:17 ` [PATCH v2 07/16] LoongArch: lib: General routines Yao Zi
@ 2026-07-01 11:18 ` Yao Zi
  2026-07-02 10:25   ` Simon Glass
  2026-07-01 11:18 ` [PATCH v2 09/16] LoongArch: Exception handling Yao Zi
                   ` (10 subsequent siblings)
  18 siblings, 1 reply; 56+ messages in thread
From: Yao Zi @ 2026-07-01 11:18 UTC (permalink / raw)
  To: Tom Rini, Jiaxun Yang, Heinrich Schuchardt, Ilias Apalodimas
  Cc: u-boot, Yao Zi

From: Jiaxun Yang <jiaxun.yang@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@flygoat.com>
Signed-off-by: Yao Zi <me@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@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@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@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@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


^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH v2 09/16] LoongArch: Exception handling
  2026-07-01 11:17 [PATCH v2 00/16] LoongArch initial support Yao Zi
                   ` (7 preceding siblings ...)
  2026-07-01 11:18 ` [PATCH v2 08/16] LoongArch: CPU assembly routines Yao Zi
@ 2026-07-01 11:18 ` Yao Zi
  2026-07-02 10:25   ` Simon Glass
  2026-07-01 11:18 ` [PATCH v2 10/16] LoongArch: Boot Image bits Yao Zi
                   ` (9 subsequent siblings)
  18 siblings, 1 reply; 56+ messages in thread
From: Yao Zi @ 2026-07-01 11:18 UTC (permalink / raw)
  To: Tom Rini, Jiaxun Yang, Heinrich Schuchardt, Ilias Apalodimas
  Cc: u-boot, Yao Zi

From: Jiaxun Yang <jiaxun.yang@flygoat.com>

Add exception entry assembly code, import stackframe.h
from Linux, provide debug prints when exception happens.

Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
Signed-off-by: Yao Zi <me@ziyao.cc>
---

(No changes since v1)

 arch/loongarch/Kconfig                  |   3 +
 arch/loongarch/cpu/Makefile             |   2 +-
 arch/loongarch/cpu/genex.S              |  21 +++
 arch/loongarch/include/asm/stackframe.h | 175 ++++++++++++++++++++++
 arch/loongarch/lib/interrupts.c         | 189 ++++++++++++++++++++++++
 5 files changed, 389 insertions(+), 1 deletion(-)
 create mode 100644 arch/loongarch/cpu/genex.S
 create mode 100644 arch/loongarch/include/asm/stackframe.h
 create mode 100644 arch/loongarch/lib/interrupts.c

diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig
index 4e8e9d4ee88b..109d37d8e2c7 100644
--- a/arch/loongarch/Kconfig
+++ b/arch/loongarch/Kconfig
@@ -30,6 +30,9 @@ config DMA_ADDR_T_64BIT
 	bool
 	default y if 64BIT
 
+config SHOW_REGS
+	bool "Show registers on unhandled exception"
+
 config STACK_SIZE_SHIFT
 	int
 	default 14
diff --git a/arch/loongarch/cpu/Makefile b/arch/loongarch/cpu/Makefile
index d3c38a16d057..6b3dd7ad7d69 100644
--- a/arch/loongarch/cpu/Makefile
+++ b/arch/loongarch/cpu/Makefile
@@ -6,4 +6,4 @@
 extra-y = start.o
 
 obj-y += cpu.o
-obj-y += smp_secondary.o
+obj-y += smp_secondary.o genex.o
diff --git a/arch/loongarch/cpu/genex.S b/arch/loongarch/cpu/genex.S
new file mode 100644
index 000000000000..18d183a352b9
--- /dev/null
+++ b/arch/loongarch/cpu/genex.S
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Exception entry for LoongArch CPU
+ *
+ * Copyright (C) 2024 Jiaxun Yang <jiaxun.yang@flygoat.com>
+ */
+
+#include <linux/linkage.h>
+#include <asm/asm.h>
+#include <asm/loongarch.h>
+#include <asm/stackframe.h>
+
+.align 12
+ENTRY(exception_entry)
+	BACKUP_T0T1
+	SAVE_ALL
+	move		a0, sp
+	la.pcrel	t0, do_exceptions
+	jirl		ra, t0, 0
+	RESTORE_ALL_AND_RET
+END(exception_entry)
diff --git a/arch/loongarch/include/asm/stackframe.h b/arch/loongarch/include/asm/stackframe.h
new file mode 100644
index 000000000000..932150afdfaf
--- /dev/null
+++ b/arch/loongarch/include/asm/stackframe.h
@@ -0,0 +1,175 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
+ * Copyright (C) 2024 Jiaxun Yang <jiaxun.yang@flygoat.com>
+ */
+#ifndef _ASM_STACKFRAME_H
+#define _ASM_STACKFRAME_H
+
+#include <asm/addrspace.h>
+#include <asm/asm.h>
+#include <generated/asm-offsets.h>
+#include <asm/loongarch.h>
+
+/* Make the addition of cfi info a little easier. */
+	.macro cfi_rel_offset reg offset=0 docfi=0
+	.if \docfi
+	.cfi_rel_offset \reg, \offset
+	.endif
+	.endm
+
+	.macro cfi_st reg offset=0 docfi=0
+	cfi_rel_offset \reg, \offset, \docfi
+	LONG_S	\reg, sp, \offset
+	.endm
+
+	.macro cfi_restore reg offset=0 docfi=0
+	.if \docfi
+	.cfi_restore \reg
+	.endif
+	.endm
+
+	.macro cfi_ld reg offset=0 docfi=0
+	LONG_L	\reg, sp, \offset
+	cfi_restore \reg \offset \docfi
+	.endm
+
+	.macro BACKUP_T0T1
+	csrwr	t0, EXCEPTION_KS0
+	csrwr	t1, EXCEPTION_KS1
+	.endm
+
+	.macro RELOAD_T0T1
+	csrrd   t0, EXCEPTION_KS0
+	csrrd   t1, EXCEPTION_KS1
+	.endm
+
+	.macro	SAVE_TEMP docfi=0
+	RELOAD_T0T1
+	cfi_st	t0, PT_R12, \docfi
+	cfi_st	t1, PT_R13, \docfi
+	cfi_st	t2, PT_R14, \docfi
+	cfi_st	t3, PT_R15, \docfi
+	cfi_st	t4, PT_R16, \docfi
+	cfi_st	t5, PT_R17, \docfi
+	cfi_st	t6, PT_R18, \docfi
+	cfi_st	t7, PT_R19, \docfi
+	cfi_st	t8, PT_R20, \docfi
+	.endm
+
+	.macro	SAVE_STATIC docfi=0
+	cfi_st	s0, PT_R23, \docfi
+	cfi_st	s1, PT_R24, \docfi
+	cfi_st	s2, PT_R25, \docfi
+	cfi_st	s3, PT_R26, \docfi
+	cfi_st	s4, PT_R27, \docfi
+	cfi_st	s5, PT_R28, \docfi
+	cfi_st	s6, PT_R29, \docfi
+	cfi_st	s7, PT_R30, \docfi
+	cfi_st	s8, PT_R31, \docfi
+	.endm
+
+	.macro	SAVE_SOME docfi=0
+	PTR_ADDI sp, sp, -PT_SIZE
+	.if \docfi
+	.cfi_def_cfa sp, 0
+	.endif
+	cfi_st	t0, PT_R3, \docfi
+	cfi_rel_offset  sp, PT_R3, \docfi
+	LONG_S	zero, sp, PT_R0
+	csrrd	t0, LOONGARCH_CSR_PRMD
+	LONG_S	t0, sp, PT_PRMD
+	csrrd	t0, LOONGARCH_CSR_CRMD
+	LONG_S	t0, sp, PT_CRMD
+	csrrd	t0, LOONGARCH_CSR_EUEN
+	LONG_S  t0, sp, PT_EUEN
+	csrrd	t0, LOONGARCH_CSR_ECFG
+	LONG_S	t0, sp, PT_ECFG
+	csrrd	t0, LOONGARCH_CSR_ESTAT
+	PTR_S	t0, sp, PT_ESTAT
+	cfi_st	ra, PT_R1, \docfi
+	cfi_st	a0, PT_R4, \docfi
+	cfi_st	a1, PT_R5, \docfi
+	cfi_st	a2, PT_R6, \docfi
+	cfi_st	a3, PT_R7, \docfi
+	cfi_st	a4, PT_R8, \docfi
+	cfi_st	a5, PT_R9, \docfi
+	cfi_st	a6, PT_R10, \docfi
+	cfi_st	a7, PT_R11, \docfi
+	csrrd	ra, LOONGARCH_CSR_ERA
+	LONG_S	ra, sp, PT_ERA
+	.if \docfi
+	.cfi_rel_offset ra, PT_ERA
+	.endif
+	cfi_st	tp, PT_R2, \docfi
+	cfi_st	fp, PT_R22, \docfi
+	/* Save U0 for sanity */
+	cfi_st  u0, PT_R21, \docfi
+	.endm
+
+	.macro	SAVE_ALL docfi=0
+	SAVE_SOME \docfi
+	SAVE_TEMP \docfi
+	SAVE_STATIC \docfi
+	.endm
+
+	.macro	RESTORE_TEMP docfi=0
+	cfi_ld	t0, PT_R12, \docfi
+	cfi_ld	t1, PT_R13, \docfi
+	cfi_ld	t2, PT_R14, \docfi
+	cfi_ld	t3, PT_R15, \docfi
+	cfi_ld	t4, PT_R16, \docfi
+	cfi_ld	t5, PT_R17, \docfi
+	cfi_ld	t6, PT_R18, \docfi
+	cfi_ld	t7, PT_R19, \docfi
+	cfi_ld	t8, PT_R20, \docfi
+	.endm
+
+	.macro	RESTORE_STATIC docfi=0
+	cfi_ld	s0, PT_R23, \docfi
+	cfi_ld	s1, PT_R24, \docfi
+	cfi_ld	s2, PT_R25, \docfi
+	cfi_ld	s3, PT_R26, \docfi
+	cfi_ld	s4, PT_R27, \docfi
+	cfi_ld	s5, PT_R28, \docfi
+	cfi_ld	s6, PT_R29, \docfi
+	cfi_ld	s7, PT_R30, \docfi
+	cfi_ld	s8, PT_R31, \docfi
+	.endm
+
+	.macro	RESTORE_SOME docfi=0
+	LONG_L	a0, sp, PT_PRMD
+	andi    a0, a0, 0x3	/* extract pplv bit */
+	beqz    a0, 8f
+	cfi_ld  u0, PT_R21, \docfi
+8:
+	LONG_L	a0, sp, PT_ERA
+	csrwr	a0, LOONGARCH_CSR_ERA
+	LONG_L	a0, sp, PT_PRMD
+	csrwr	a0, LOONGARCH_CSR_PRMD
+	cfi_ld	ra, PT_R1, \docfi
+	cfi_ld	a0, PT_R4, \docfi
+	cfi_ld	a1, PT_R5, \docfi
+	cfi_ld	a2, PT_R6, \docfi
+	cfi_ld	a3, PT_R7, \docfi
+	cfi_ld	a4, PT_R8, \docfi
+	cfi_ld	a5, PT_R9, \docfi
+	cfi_ld	a6, PT_R10, \docfi
+	cfi_ld	a7, PT_R11, \docfi
+	cfi_ld	tp, PT_R2, \docfi
+	cfi_ld	fp, PT_R22, \docfi
+	.endm
+
+	.macro	RESTORE_SP_AND_RET docfi=0
+	cfi_ld	sp, PT_R3, \docfi
+	ertn
+	.endm
+
+	.macro	RESTORE_ALL_AND_RET docfi=0
+	RESTORE_STATIC \docfi
+	RESTORE_TEMP \docfi
+	RESTORE_SOME \docfi
+	RESTORE_SP_AND_RET \docfi
+	.endm
+
+#endif /* _ASM_STACKFRAME_H */
diff --git a/arch/loongarch/lib/interrupts.c b/arch/loongarch/lib/interrupts.c
new file mode 100644
index 000000000000..4fbd3dea1407
--- /dev/null
+++ b/arch/loongarch/lib/interrupts.c
@@ -0,0 +1,189 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2024 Jiaxun Yang <jiaxun.yang@flygoat.com>
+ */
+
+#include <linux/compat.h>
+#include <linux/bitfield.h>
+#include <linux/linkage.h>
+#include <hang.h>
+#include <interrupt.h>
+#include <irq_func.h>
+#include <asm/global_data.h>
+#include <asm/ptrace.h>
+#include <asm/system.h>
+#include <asm/regdef.h>
+#include <asm/loongarch.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static struct resume_data *resume;
+
+void set_resume(struct resume_data *data)
+{
+	resume = data;
+}
+
+static void show_regs(struct pt_regs *regs)
+{
+#if IS_ENABLED(CONFIG_SHOW_REGS)
+	const int field = 2 * sizeof(unsigned long);
+
+#define GPR_FIELD(x) field, regs->regs[x]
+	printf("pc %0*lx ra %0*lx tp %0*lx sp %0*lx\n",
+	       field, regs->csr_era, GPR_FIELD(1), GPR_FIELD(2), GPR_FIELD(3));
+	printf("a0 %0*lx a1 %0*lx a2 %0*lx a3 %0*lx\n",
+	       GPR_FIELD(4), GPR_FIELD(5), GPR_FIELD(6), GPR_FIELD(7));
+	printf("a4 %0*lx a5 %0*lx a6 %0*lx a7 %0*lx\n",
+	       GPR_FIELD(8), GPR_FIELD(9), GPR_FIELD(10), GPR_FIELD(11));
+	printf("t0 %0*lx t1 %0*lx t2 %0*lx t3 %0*lx\n",
+	       GPR_FIELD(12), GPR_FIELD(13), GPR_FIELD(14), GPR_FIELD(15));
+	printf("t4 %0*lx t5 %0*lx t6 %0*lx t7 %0*lx\n",
+	       GPR_FIELD(16), GPR_FIELD(17), GPR_FIELD(18), GPR_FIELD(19));
+	printf("t8 %0*lx u0 %0*lx s9 %0*lx s0 %0*lx\n",
+	       GPR_FIELD(20), GPR_FIELD(21), GPR_FIELD(22), GPR_FIELD(23));
+	printf("s1 %0*lx s2 %0*lx s3 %0*lx s4 %0*lx\n",
+	       GPR_FIELD(24), GPR_FIELD(25), GPR_FIELD(26), GPR_FIELD(27));
+	printf("s5 %0*lx s6 %0*lx s7 %0*lx s8 %0*lx\n",
+	       GPR_FIELD(28), GPR_FIELD(29), GPR_FIELD(30), GPR_FIELD(31));
+#endif
+}
+
+static void __maybe_unused show_backtrace(struct pt_regs *regs)
+{
+	uintptr_t *fp = (uintptr_t *)regs->regs[0x16];
+	unsigned int count = 0;
+	ulong ra;
+
+	printf("\nbacktrace:\n");
+
+	/*
+	 * there are a few entry points where the s0 register is
+	 * set to gd, so to avoid changing those, just abort if
+	 * the value is the same.
+	 */
+	while (fp && fp != (uintptr_t *)gd) {
+		ra = fp[-1];
+		printf("%3d: fp: " REG_FMT " ra: " REG_FMT,
+		       count, (ulong)fp, ra);
+
+		if (gd && gd->flags & GD_FLG_RELOC)
+			printf(" - ra: " REG_FMT " reloc adjusted\n",
+			       ra - gd->reloc_off);
+		else
+			printf("\n");
+
+		fp = (uintptr_t *)fp[-2];
+		count++;
+	}
+}
+
+static const char *humanize_exc_name(unsigned int ecode, unsigned int esubcode)
+{
+	/*
+	 * LoongArch users and developers are probably more familiar with
+	 * those names found in the ISA manual, so we are going to print out
+	 * the latter. This will require some mapping.
+	 */
+	switch (ecode) {
+	case EXCCODE_RSV: return "INT";
+	case EXCCODE_TLBL: return "PIL";
+	case EXCCODE_TLBS: return "PIS";
+	case EXCCODE_TLBI: return "PIF";
+	case EXCCODE_TLBM: return "PME";
+	case EXCCODE_TLBNR: return "PNR";
+	case EXCCODE_TLBNX: return "PNX";
+	case EXCCODE_TLBPE: return "PPI";
+	case EXCCODE_ADE:
+		switch (esubcode) {
+		case EXSUBCODE_ADEF: return "ADEF";
+		case EXSUBCODE_ADEM: return "ADEM";
+		}
+		break;
+	case EXCCODE_ALE: return "ALE";
+	case EXCCODE_BCE: return "BCE";
+	case EXCCODE_SYS: return "SYS";
+	case EXCCODE_BP: return "BRK";
+	case EXCCODE_INE: return "INE";
+	case EXCCODE_IPE: return "IPE";
+	case EXCCODE_FPDIS: return "FPD";
+	case EXCCODE_LSXDIS: return "SXD";
+	case EXCCODE_LASXDIS: return "ASXD";
+	case EXCCODE_FPE:
+		switch (esubcode) {
+		case EXCSUBCODE_FPE: return "FPE";
+		case EXCSUBCODE_VFPE: return "VFPE";
+		}
+		break;
+	case EXCCODE_WATCH:
+		switch (esubcode) {
+		case EXCSUBCODE_WPEF: return "WPEF";
+		case EXCSUBCODE_WPEM: return "WPEM";
+		}
+		break;
+	case EXCCODE_BTDIS: return "BTD";
+	case EXCCODE_BTE: return "BTE";
+	case EXCCODE_GSPR: return "GSPR";
+	case EXCCODE_HVC: return "HVC";
+	case EXCCODE_GCM:
+		switch (esubcode) {
+		case EXCSUBCODE_GCSC: return "GCSC";
+		case EXCSUBCODE_GCHC: return "GCHC";
+		}
+		break;
+	/*
+	 * The manual did not mention the EXCCODE_SE case, but print out it
+	 * nevertheless.
+	 */
+	case EXCCODE_SE: return "SE";
+	}
+
+	return "???";
+}
+
+asmlinkage void do_exceptions(struct pt_regs *regs)
+{
+	unsigned int ecode = FIELD_GET(CSR_ESTAT_EXC, regs->csr_estat);
+	unsigned int esubcode = FIELD_GET(CSR_ESTAT_ESUBCODE, regs->csr_estat);
+
+	printf("Unhandled exception: %s\n", humanize_exc_name(ecode, esubcode));
+
+	printf("ERA: " REG_FMT " ra: " REG_FMT "\n",
+	       regs->csr_era, regs->regs[1]);
+	/* Print relocation adjustments, but only if gd is initialized */
+	if (gd && gd->flags & GD_FLG_RELOC)
+		printf("ERA: " REG_FMT " ra: " REG_FMT " reloc adjusted\n",
+		       regs->csr_era - gd->reloc_off, regs->regs[1] - gd->reloc_off);
+
+	printf("CRMD: " REG_FMT "\n", regs->csr_crmd);
+	if (ecode >= EXCCODE_TLBL && ecode <= EXCCODE_ALE)
+		printf("BADV: " REG_FMT "\n", regs->csr_badvaddr);
+
+	printf("\n");
+	show_regs(regs);
+
+	if (CONFIG_IS_ENABLED(FRAMEPOINTER))
+		show_backtrace(regs);
+
+	panic("\n");
+}
+
+int interrupt_init(void)
+{
+	return 0;
+}
+
+/*
+ * enable interrupts
+ */
+void enable_interrupts(void)
+{
+}
+
+/*
+ * disable interrupts
+ */
+int disable_interrupts(void)
+{
+	return 0;
+}
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH v2 10/16] LoongArch: Boot Image bits
  2026-07-01 11:17 [PATCH v2 00/16] LoongArch initial support Yao Zi
                   ` (8 preceding siblings ...)
  2026-07-01 11:18 ` [PATCH v2 09/16] LoongArch: Exception handling Yao Zi
@ 2026-07-01 11:18 ` Yao Zi
  2026-07-01 17:53   ` Tom Rini
  2026-07-02 10:26   ` Simon Glass
  2026-07-01 11:18 ` [PATCH v2 11/16] LoongArch: Generic CPU type Yao Zi
                   ` (8 subsequent siblings)
  18 siblings, 2 replies; 56+ messages in thread
From: Yao Zi @ 2026-07-01 11:18 UTC (permalink / raw)
  To: Tom Rini, Jiaxun Yang, Heinrich Schuchardt, Ilias Apalodimas
  Cc: u-boot, Yao Zi

From: Jiaxun Yang <jiaxun.yang@flygoat.com>

Implement loading and booting functions for LoongArch
standard kernel image as per spec.

LoongArch kernel do expect us to fake a efi systemtable
for passing fdt to kernel, we don't need to implement any
EFI functions for kernel because it won't look into anything
beside devicetree from that table if we tell kernel we are
not efi compatible by setting a0 boot argument to zero.

Link: https://docs.kernel.org/arch/loongarch/booting.html
Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
Signed-off-by: Yao Zi <me@ziyao.cc>
---

Changed from v1
- Remove now unused arch_lmb_reserve()

 arch/loongarch/lib/Makefile |   2 +
 arch/loongarch/lib/bootm.c  | 163 ++++++++++++++++++++++++++++++++++++
 arch/loongarch/lib/image.c  |  66 +++++++++++++++
 cmd/Kconfig                 |   2 +-
 4 files changed, 232 insertions(+), 1 deletion(-)
 create mode 100644 arch/loongarch/lib/bootm.c
 create mode 100644 arch/loongarch/lib/image.c

diff --git a/arch/loongarch/lib/Makefile b/arch/loongarch/lib/Makefile
index 3c17b9cd85af..e65e66357a9b 100644
--- a/arch/loongarch/lib/Makefile
+++ b/arch/loongarch/lib/Makefile
@@ -3,6 +3,8 @@
 # Copyright (C) 2024 Jiaxun yang <jiaxun.yang@flygoat.com>
 #
 
+obj-$(CONFIG_CMD_BOOTM) += bootm.o
+obj-$(CONFIG_CMD_BOOTI) += bootm.o image.o
 obj-$(CONFIG_CMD_GO) += boot.o
 obj-y	+= cache.o
 obj-y	+= interrupts.o
diff --git a/arch/loongarch/lib/bootm.c b/arch/loongarch/lib/bootm.c
new file mode 100644
index 000000000000..432ad1cfe970
--- /dev/null
+++ b/arch/loongarch/lib/bootm.c
@@ -0,0 +1,163 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2024 Jiaxun Yang <jiaxun.yang@flygoat.com>
+ */
+
+#include <bootstage.h>
+#include <bootm.h>
+#include <command.h>
+#include <dm.h>
+#include <efi.h>
+#include <efi_api.h>
+#include <fdt_support.h>
+#include <hang.h>
+#include <log.h>
+#include <linux/sizes.h>
+#include <memalign.h>
+#include <asm/global_data.h>
+#include <dm/root.h>
+#include <image.h>
+#include <asm/byteorder.h>
+#include <dm/device.h>
+#include <dm/root.h>
+#include <u-boot/zlib.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static const efi_guid_t efi_guid_fdt = EFI_FDT_GUID;
+
+__weak void board_quiesce_devices(void)
+{
+}
+
+/**
+ * announce_and_cleanup() - Print message and prepare for kernel boot
+ *
+ * @fake: non-zero to do everything except actually boot
+ */
+static void announce_and_cleanup(int fake)
+{
+	printf("\nStarting kernel ...%s\n\n", fake ?
+		"(fake run for tracing)" : "");
+	bootstage_mark_name(BOOTSTAGE_ID_BOOTM_HANDOFF, "start_kernel");
+#if CONFIG_IS_ENABLED(BOOTSTAGE_FDT)
+	bootstage_fdt_add_report();
+#endif
+#if CONFIG_IS_ENABLED(BOOTSTAGE_REPORT)
+	bootstage_report();
+#endif
+
+#if CONFIG_IS_ENABLED(USB_DEVICE)
+	udc_disconnect();
+#endif
+
+	board_quiesce_devices();
+
+	/*
+	 * Call remove function of all devices with a removal flag set.
+	 * This may be useful for last-stage operations, like cancelling
+	 * of DMA operation or releasing device internal buffers.
+	 */
+	dm_remove_devices_flags(DM_REMOVE_ACTIVE_ALL);
+
+	cleanup_before_linux();
+}
+
+/* LoongArch do expect a EFI style systab */
+static int generate_systab(struct bootm_headers *images)
+{
+	const int nr_cfgtab = 1;
+	struct bd_info *kbd = images->kbd;
+	struct efi_system_table *systab;
+	struct efi_configuration_table *cfgtab;
+	size_t table_size = sizeof(struct efi_system_table) +
+			    nr_cfgtab * sizeof(struct efi_configuration_table);
+
+	systab = memalign(SZ_64K, table_size);
+	if (!systab) {
+		log_warning("Failed to allocate memory for systab\n");
+		return -ENOMEM;
+	}
+	memset(systab, 0, table_size);
+
+	cfgtab = (void *)systab + sizeof(struct efi_system_table);
+
+	systab->hdr.signature = EFI_SYSTEM_TABLE_SIGNATURE;
+	systab->hdr.headersize = sizeof(struct efi_system_table);
+	systab->nr_tables = nr_cfgtab;
+	systab->tables = cfgtab;
+	systab->hdr.crc32 = crc32(0, (const unsigned char *)systab,
+				systab->hdr.headersize);
+
+	cfgtab[0].guid = efi_guid_fdt;
+	cfgtab[0].table = images->ft_addr;
+
+	kbd->bi_boot_params = (phys_addr_t)systab;
+
+	return 0;
+}
+
+static void boot_prep_linux(struct bootm_headers *images)
+{
+	if (CONFIG_IS_ENABLED(OF_LIBFDT) && IS_ENABLED(CONFIG_LMB) && images->ft_len) {
+		debug("using: FDT\n");
+		if (image_setup_linux(images)) {
+			printf("FDT creation failed! hanging...");
+			hang();
+		}
+		if (generate_systab(images)) {
+			printf("Failed to generate EFI systab\n");
+			hang();
+		}
+	} else {
+		printf("Device tree not found or missing FDT support\n");
+		hang();
+	}
+}
+
+static void boot_jump_linux(struct bootm_headers *images, int flag)
+{
+	void (*kernel)(ulong efi_boot, char *argc, void *dtb);
+	int fake = (flag & BOOTM_STATE_OS_FAKE_GO);
+
+	kernel = (void (*)(ulong efi_boot, char *argc, void *dtb))images->ep;
+
+	bootstage_mark(BOOTSTAGE_ID_RUN_OS);
+
+	debug("## Transferring control to kernel (at address %08lx) ...\n",
+	      (ulong)kernel);
+
+	announce_and_cleanup(fake);
+
+	if (!fake) {
+		if (CONFIG_IS_ENABLED(OF_LIBFDT) && images->ft_len)
+			kernel(0, NULL, (void *)images->kbd->bi_boot_params);
+	}
+}
+
+int do_bootm_linux(int flag, struct bootm_info *bmi)
+{
+	struct bootm_headers *images = bmi->images;
+
+	if (flag & BOOTM_STATE_OS_BD_T || flag & BOOTM_STATE_OS_CMDLINE)
+		return -1;
+
+	if (flag & BOOTM_STATE_OS_PREP) {
+		boot_prep_linux(images);
+		return 0;
+	}
+
+	if (flag & (BOOTM_STATE_OS_GO | BOOTM_STATE_OS_FAKE_GO)) {
+		boot_jump_linux(images, flag);
+		return 0;
+	}
+
+	boot_prep_linux(images);
+	boot_jump_linux(images, flag);
+	return 0;
+}
+
+int do_bootm_vxworks(int flag, struct bootm_info *bmi)
+{
+	return do_bootm_linux(flag, bmi);
+}
diff --git a/arch/loongarch/lib/image.c b/arch/loongarch/lib/image.c
new file mode 100644
index 000000000000..a10a35f6e90c
--- /dev/null
+++ b/arch/loongarch/lib/image.c
@@ -0,0 +1,66 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2024 Jiaxun Yang <jiaxun.yang@flygoat.com>
+ *
+ * Based on riscv/lib/image.c
+ */
+
+#include <image.h>
+#include <mapmem.h>
+#include <errno.h>
+#include <asm/global_data.h>
+#include <linux/sizes.h>
+#include <linux/stddef.h>
+#include <asm/addrspace.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define LINUX_LOONGARCH_IMAGE_MAGIC	0x818223cd
+
+struct linux_image_h {
+	uint32_t	code0;			/* Executable code */
+	uint32_t	code1;			/* Executable code */
+	uint64_t	kernel_entry;	/* Kernel entry point */
+	uint64_t	image_size;		/* Effective Image size */
+	uint64_t	load_offset;	/* load offset */
+	uint64_t	res1;			/* reserved */
+	uint64_t	res2;			/* reserved */
+	uint64_t	res3;			/* reserved */
+	uint32_t	magic;			/* Magic number */
+	uint32_t	pe_header;		/* Offset to the PE header */
+};
+
+int booti_setup(ulong image, ulong *relocated_addr, ulong *size, ulong *ep,
+		bool force_reloc)
+{
+	struct linux_image_h *lhdr;
+	phys_addr_t ep_phys;
+
+	lhdr = (struct linux_image_h *)map_sysmem(image, 0);
+
+	if (lhdr->magic != LINUX_LOONGARCH_IMAGE_MAGIC) {
+		puts("Bad Linux LoongArch Image magic!\n");
+		return -EINVAL;
+	}
+
+	if (lhdr->image_size == 0) {
+		puts("Image lacks image_size field, error!\n");
+		return -EINVAL;
+	}
+
+	*size = lhdr->image_size;
+	if (force_reloc ||
+	    (gd->ram_base <= image && image < gd->ram_base + gd->ram_size)) {
+		*relocated_addr = gd->ram_base + lhdr->load_offset;
+	} else {
+		*relocated_addr = image;
+	}
+
+	/* To workaround kernel supplying DMW based virtual address */
+	ep_phys = TO_PHYS(lhdr->kernel_entry);
+	*ep = *relocated_addr + (ep_phys - lhdr->load_offset);
+
+	unmap_sysmem(lhdr);
+
+	return 0;
+}
diff --git a/cmd/Kconfig b/cmd/Kconfig
index d0fb7397067e..e874b245086d 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -395,7 +395,7 @@ config CMD_BOOTZ
 
 config CMD_BOOTI
 	bool "booti"
-	depends on ARM64 || RISCV || SANDBOX
+	depends on ARM64 || LOONGARCH || RISCV || SANDBOX
 	depends on LMB
 	default y
 	select LIB_BOOTI
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH v2 11/16] LoongArch: Generic CPU type
  2026-07-01 11:17 [PATCH v2 00/16] LoongArch initial support Yao Zi
                   ` (9 preceding siblings ...)
  2026-07-01 11:18 ` [PATCH v2 10/16] LoongArch: Boot Image bits Yao Zi
@ 2026-07-01 11:18 ` Yao Zi
  2026-07-01 17:55   ` Tom Rini
  2026-07-02 10:26   ` Simon Glass
  2026-07-01 11:18 ` [PATCH v2 12/16] cpu: Add loongarch_cpu driver Yao Zi
                   ` (7 subsequent siblings)
  18 siblings, 2 replies; 56+ messages in thread
From: Yao Zi @ 2026-07-01 11:18 UTC (permalink / raw)
  To: Tom Rini, Jiaxun Yang, Heinrich Schuchardt, Ilias Apalodimas
  Cc: u-boot, Yao Zi

From: Jiaxun Yang <jiaxun.yang@flygoat.com>

Provide a generic CPU type with some common routines
that expected to be implemented at CPU level.

Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
Signed-off-by: Yao Zi <me@ziyao.cc>
---

(No changes from v1)

 arch/loongarch/Kconfig              |  1 +
 arch/loongarch/cpu/generic/Kconfig  | 13 +++++++++++++
 arch/loongarch/cpu/generic/Makefile |  7 +++++++
 arch/loongarch/cpu/generic/cpu.c    | 22 ++++++++++++++++++++++
 arch/loongarch/cpu/generic/dram.c   | 21 +++++++++++++++++++++
 5 files changed, 64 insertions(+)
 create mode 100644 arch/loongarch/cpu/generic/Kconfig
 create mode 100644 arch/loongarch/cpu/generic/Makefile
 create mode 100644 arch/loongarch/cpu/generic/cpu.c
 create mode 100644 arch/loongarch/cpu/generic/dram.c

diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig
index 109d37d8e2c7..5254afb2cd05 100644
--- a/arch/loongarch/Kconfig
+++ b/arch/loongarch/Kconfig
@@ -12,6 +12,7 @@ endchoice
 # board-specific options below
 
 # platform-specific options below
+source "arch/loongarch/cpu/generic/Kconfig"
 
 # architecture-specific options below
 choice
diff --git a/arch/loongarch/cpu/generic/Kconfig b/arch/loongarch/cpu/generic/Kconfig
new file mode 100644
index 000000000000..ac7556d6d4d0
--- /dev/null
+++ b/arch/loongarch/cpu/generic/Kconfig
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (C) 2024 Jiaxun yang <jiaxun.yang@flygoat.com>
+#
+
+config GENERIC_LOONGARCH
+	bool
+	select SYS_CACHE_SHIFT_6
+	imply CPU
+	imply CPU_LOONGARCH
+	imply LOONGARCH_TIMER
+	imply CMD_CPU
+
diff --git a/arch/loongarch/cpu/generic/Makefile b/arch/loongarch/cpu/generic/Makefile
new file mode 100644
index 000000000000..c98d63b4f831
--- /dev/null
+++ b/arch/loongarch/cpu/generic/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (C) 2024 Jiaxun yang <jiaxun.yang@flygoat.com>
+#
+
+obj-y += dram.o
+obj-y += cpu.o
diff --git a/arch/loongarch/cpu/generic/cpu.c b/arch/loongarch/cpu/generic/cpu.c
new file mode 100644
index 000000000000..5c849faf2bac
--- /dev/null
+++ b/arch/loongarch/cpu/generic/cpu.c
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2024 Jiaxun Yang <jiaxun.yang@flygoat.com>
+ */
+
+#include <irq_func.h>
+#include <asm/cache.h>
+
+/*
+ * cleanup_before_linux() is called just before we call linux
+ * it prepares the processor for linux
+ *
+ * we disable interrupt and caches.
+ */
+int cleanup_before_linux(void)
+{
+	disable_interrupts();
+
+	cache_flush();
+
+	return 0;
+}
diff --git a/arch/loongarch/cpu/generic/dram.c b/arch/loongarch/cpu/generic/dram.c
new file mode 100644
index 000000000000..101b45786194
--- /dev/null
+++ b/arch/loongarch/cpu/generic/dram.c
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2024 Jiaxun Yang <jiaxun.yang@flygoat.com>
+ */
+
+#include <fdtdec.h>
+#include <init.h>
+#include <asm/global_data.h>
+#include <linux/sizes.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int dram_init(void)
+{
+	return fdtdec_setup_mem_size_base_lowest();
+}
+
+int dram_init_banksize(void)
+{
+	return fdtdec_setup_memory_banksize();
+}
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH v2 12/16] cpu: Add loongarch_cpu driver
  2026-07-01 11:17 [PATCH v2 00/16] LoongArch initial support Yao Zi
                   ` (10 preceding siblings ...)
  2026-07-01 11:18 ` [PATCH v2 11/16] LoongArch: Generic CPU type Yao Zi
@ 2026-07-01 11:18 ` Yao Zi
  2026-07-02 10:26   ` Simon Glass
  2026-07-01 11:18 ` [PATCH v2 13/16] timer: Add loongarch_timer driver Yao Zi
                   ` (6 subsequent siblings)
  18 siblings, 1 reply; 56+ messages in thread
From: Yao Zi @ 2026-07-01 11:18 UTC (permalink / raw)
  To: Tom Rini, Jiaxun Yang, Heinrich Schuchardt, Ilias Apalodimas
  Cc: u-boot, Yao Zi

From: Jiaxun Yang <jiaxun.yang@flygoat.com>

Implement a driver for LoongArch CPU solely for gathering
some information bits from FDT and CPU level config registers.

Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
Signed-off-by: Yao Zi <me@ziyao.cc>
---

Changed from v1
- Drop unnecessary check against -ENOTSUPP clk_enable()'s return value
  in loongarch_cpu_probe()

 drivers/cpu/Kconfig         |   6 ++
 drivers/cpu/Makefile        |   1 +
 drivers/cpu/loongarch_cpu.c | 148 ++++++++++++++++++++++++++++++++++++
 3 files changed, 155 insertions(+)
 create mode 100644 drivers/cpu/loongarch_cpu.c

diff --git a/drivers/cpu/Kconfig b/drivers/cpu/Kconfig
index c805c0bbfa19..9fd43ff88fde 100644
--- a/drivers/cpu/Kconfig
+++ b/drivers/cpu/Kconfig
@@ -13,6 +13,12 @@ config CPU_IMX
 	help
 	  Support CPU cores for SoCs of the i.MX series.
 
+config CPU_LOONGARCH
+	bool "Enable LoongArch CPU driver"
+	depends on CPU && LOONGARCH
+	help
+	  Support CPU cores for LoongArch processors.
+
 config CPU_MPC83XX
 	bool "Enable MPC83xx CPU driver"
 	depends on CPU && MPC83xx
diff --git a/drivers/cpu/Makefile b/drivers/cpu/Makefile
index eaf494706e2c..d9c0db74dd5a 100644
--- a/drivers/cpu/Makefile
+++ b/drivers/cpu/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_ARCH_AT91) += at91_cpu.o
 obj-$(CONFIG_ARCH_MEDIATEK) += mtk_cpu.o
 obj-$(CONFIG_CPU_ARMV8) += armv8_cpu.o
 obj-$(CONFIG_CPU_IMX) += imx8_cpu.o
+obj-$(CONFIG_CPU_LOONGARCH) += loongarch_cpu.o
 obj-$(CONFIG_CPU_MPC83XX) += mpc83xx_cpu.o
 obj-$(CONFIG_CPU_RISCV) += riscv_cpu.o
 obj-$(CONFIG_CPU_MICROBLAZE) += microblaze_cpu.o
diff --git a/drivers/cpu/loongarch_cpu.c b/drivers/cpu/loongarch_cpu.c
new file mode 100644
index 000000000000..f168ae23cf67
--- /dev/null
+++ b/drivers/cpu/loongarch_cpu.c
@@ -0,0 +1,148 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2024 Jiaxun Yang <jiaxun.yang@flygoat.com>
+ */
+
+#include <clk.h>
+#include <cpu.h>
+#include <dm.h>
+#include <errno.h>
+#include <log.h>
+#include <asm/loongarch.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+
+static int loongarch_cpu_get_desc(const struct udevice *dev, char *buf, int size)
+{
+	const char *cpu;
+
+	/* We try to get CPU name from IOCSR first */
+	if ((read_cpucfg(LOONGARCH_CPUCFG1) & CPUCFG1_IOCSR)) {
+		int i;
+		char vendor_buf[9] = { 0 };
+		char name_buf[9] = { 0 };
+		u64 vendor = iocsr_read64(LOONGARCH_IOCSR_VENDOR);
+		u64 name = iocsr_read64(LOONGARCH_IOCSR_CPUNAME);
+
+		if (!vendor || !name)
+			goto get_desc_dt;
+
+		for (i = 0; i < sizeof(u64); i++) {
+			vendor_buf[i] = vendor & 0xff;
+			name_buf[i] = name & 0xff;
+			vendor >>= 8;
+			name >>= 8;
+		}
+
+		snprintf(buf, size, "%s-%s", vendor_buf, name_buf);
+
+		return 0;
+	}
+
+get_desc_dt:
+	cpu = dev_read_string(dev, "compatible");
+	if (!cpu || size < (strlen(cpu) + 1))
+		return -ENOSPC;
+
+	strcpy(buf, cpu);
+
+	return 0;
+}
+
+static int loongarch_cpu_get_info(const struct udevice *dev, struct cpu_info *info)
+{
+	int ret;
+	struct clk clk;
+
+	/* First try getting the frequency from the assigned clock */
+	ret = clk_get_by_index((struct udevice *)dev, 0, &clk);
+	if (!ret) {
+		ret = clk_get_rate(&clk);
+		if (!IS_ERR_VALUE(ret))
+			info->cpu_freq = ret;
+	}
+
+	if (!info->cpu_freq)
+		dev_read_u32(dev, "clock-frequency", (u32 *)&info->cpu_freq);
+
+	if (read_cpucfg(LOONGARCH_CPUCFG1) & CPUCFG1_PAGING)
+		info->features |= BIT(CPU_FEAT_MMU);
+
+	if (read_cpucfg(LOONGARCH_CPUCFG16) & CPUCFG16_L1_IUPRE)
+		info->features |= BIT(CPU_FEAT_L1_CACHE);
+
+	return 0;
+}
+
+static int loongarch_cpu_get_count(const struct udevice *dev)
+{
+	ofnode node;
+	int num = 0;
+
+	ofnode_for_each_subnode(node, dev_ofnode(dev->parent)) {
+		const char *device_type;
+
+		/* skip if core is marked as not available in the device tree */
+		if (!ofnode_is_enabled(node))
+			continue;
+
+		device_type = ofnode_read_string(node, "device_type");
+		if (!device_type)
+			continue;
+		if (strcmp(device_type, "cpu") == 0)
+			num++;
+	}
+
+	return num;
+}
+
+static int loongarch_cpu_bind(struct udevice *dev)
+{
+	struct cpu_plat *plat = dev_get_parent_plat(dev);
+
+	plat->cpu_id = dev_read_addr(dev);
+
+	return 0;
+}
+
+static int loongarch_cpu_probe(struct udevice *dev)
+{
+	int ret = 0;
+	struct clk clk;
+
+	/* Get a clock if it exists */
+	ret = clk_get_by_index(dev, 0, &clk);
+	if (ret)
+		return 0;
+
+	ret = clk_enable(&clk);
+	if (ret == -ENOSYS)
+		return 0;
+	else
+		return ret;
+}
+
+static const struct cpu_ops loongarch_cpu_ops = {
+	.get_desc	= loongarch_cpu_get_desc,
+	.get_info	= loongarch_cpu_get_info,
+	.get_count	= loongarch_cpu_get_count,
+};
+
+static const struct udevice_id loongarch_cpu_ids[] = {
+	{ .compatible = "loongarch,Loongson-3A5000" }, /* From QEMU, undocumented */
+	{ .compatible = "loongson,la264" },
+	{ .compatible = "loongson,la364" },
+	{ }
+};
+
+U_BOOT_DRIVER(loongarch_cpu) = {
+	.name = "loongarch_cpu",
+	.id = UCLASS_CPU,
+	.of_match = loongarch_cpu_ids,
+	.bind = loongarch_cpu_bind,
+	.probe = loongarch_cpu_probe,
+	.ops = &loongarch_cpu_ops,
+	.flags = DM_FLAG_PRE_RELOC,
+};
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH v2 13/16] timer: Add loongarch_timer driver
  2026-07-01 11:17 [PATCH v2 00/16] LoongArch initial support Yao Zi
                   ` (11 preceding siblings ...)
  2026-07-01 11:18 ` [PATCH v2 12/16] cpu: Add loongarch_cpu driver Yao Zi
@ 2026-07-01 11:18 ` Yao Zi
  2026-07-02 10:27   ` Simon Glass
  2026-07-01 11:18 ` [PATCH v2 14/16] board: emulation: Add qemu-loongarch Yao Zi
                   ` (5 subsequent siblings)
  18 siblings, 1 reply; 56+ messages in thread
From: Yao Zi @ 2026-07-01 11:18 UTC (permalink / raw)
  To: Tom Rini, Jiaxun Yang, Heinrich Schuchardt, Ilias Apalodimas
  Cc: u-boot, Yao Zi

From: Jiaxun Yang <jiaxun.yang@flygoat.com>

Implement a timer driver for LoongArch architecture driver.

It's synced in hardware for every core in a system, and frequency
information can be gathered from CPUCFG instruction.

It is not described in fdt, thus I have to declare a DRVINFO
for it.

Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
Signed-off-by: Yao Zi <me@ziyao.cc>
---

(No changes from v1)

 drivers/timer/Kconfig           |   8 +++
 drivers/timer/Makefile          |   1 +
 drivers/timer/loongarch_timer.c | 112 ++++++++++++++++++++++++++++++++
 3 files changed, 121 insertions(+)
 create mode 100644 drivers/timer/loongarch_timer.c

diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig
index 500a25638a96..6feb53328147 100644
--- a/drivers/timer/Kconfig
+++ b/drivers/timer/Kconfig
@@ -348,4 +348,12 @@ config GOLDFISH_TIMER
 	  It uses the Goldfish RTC hardware to provide a nanosecond-resolution
 	  timer, commonly found in QEMU virt machines.
 
+config LOONGARCH_TIMER
+	bool "LoongArch CPU timer support"
+	depends on TIMER
+	depends on LOONGARCH
+	help
+	  Select this to enable support for the timer found on
+	  LoongArch CPUs.
+
 endmenu
diff --git a/drivers/timer/Makefile b/drivers/timer/Makefile
index d8b3f2b65d4c..0b70b915bfeb 100644
--- a/drivers/timer/Makefile
+++ b/drivers/timer/Makefile
@@ -37,3 +37,4 @@ obj-$(CONFIG_IMX_GPT_TIMER)	+= imx-gpt-timer.o
 obj-$(CONFIG_XILINX_TIMER)	+= xilinx-timer.o
 obj-$(CONFIG_STARFIVE_TIMER)	+= starfive-timer.o
 obj-$(CONFIG_GOLDFISH_TIMER)	+= goldfish_timer.o
+obj-$(CONFIG_LOONGARCH_TIMER)	+= loongarch_timer.o
diff --git a/drivers/timer/loongarch_timer.c b/drivers/timer/loongarch_timer.c
new file mode 100644
index 000000000000..4b9f9307511f
--- /dev/null
+++ b/drivers/timer/loongarch_timer.c
@@ -0,0 +1,112 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2024 Jiaxun Yang <jiaxun.yang@flygoat.com>
+ */
+
+#include <dm.h>
+#include <errno.h>
+#include <timer.h>
+#include <asm/loongarch.h>
+
+static u64 notrace loongarch_timer_get_count(struct udevice *dev)
+{
+	u32 hi, lo;
+
+	if (IS_ENABLED(CONFIG_64BIT))
+		return drdtime();
+
+	do {
+		hi = rdtimeh();
+		lo = rdtimel();
+	} while (hi != rdtimeh());
+
+	return ((u64)hi << 32) | lo;
+}
+
+static unsigned int loongarch_timer_get_freq_cpucfg(void)
+{
+	unsigned int res;
+	unsigned int base_freq;
+	unsigned int cfm, cfd;
+
+	res = read_cpucfg(LOONGARCH_CPUCFG2);
+	if (!(res & CPUCFG2_LLFTP))
+		return 0;
+
+	base_freq = read_cpucfg(LOONGARCH_CPUCFG4);
+	res = read_cpucfg(LOONGARCH_CPUCFG5);
+	cfm = res & 0xffff;
+	cfd = (res >> 16) & 0xffff;
+
+	if (!base_freq || !cfm || !cfd)
+		return 0;
+
+	return (base_freq * cfm / cfd);
+}
+
+#if IS_ENABLED(CONFIG_TIMER_EARLY)
+/**
+ * timer_early_get_rate() - Get the timer rate before driver model
+ */
+unsigned long notrace timer_early_get_rate(void)
+{
+	return loongarch_timer_get_freq_cpucfg();
+}
+
+/**
+ * timer_early_get_count() - Get the timer count before driver model
+ *
+ */
+u64 notrace timer_early_get_count(void)
+{
+	return loongarch_timer_get_count(NULL);
+}
+#endif
+
+#if CONFIG_IS_ENABLED(BOOTSTAGE)
+ulong timer_get_boot_us(void)
+{
+	int ret;
+	u64 ticks = 0;
+	u32 rate;
+
+	ret = dm_timer_init();
+	if (!ret) {
+		rate = timer_get_rate(gd->timer);
+		timer_get_count(gd->timer, &ticks);
+	} else {
+		rate = loongarch_timer_get_freq_cpucfg();
+		ticks = loongarch_timer_get_count(NULL);
+	}
+
+	/* Below is converted from time(us) = (tick / rate) * 10000000 */
+	return lldiv(ticks * 1000, (rate / 1000));
+}
+#endif
+
+static int loongarch_timer_bind(struct udevice *dev)
+{
+	struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+	u32 rate;
+
+	rate = loongarch_timer_get_freq_cpucfg();
+	uc_priv->clock_rate = rate;
+
+	return 0;
+}
+
+static const struct timer_ops loongarch_timer_ops = {
+	.get_count = loongarch_timer_get_count,
+};
+
+U_BOOT_DRIVER(loongarch_timer) = {
+	.name = "loongarch_timer",
+	.id = UCLASS_TIMER,
+	.probe = loongarch_timer_bind,
+	.ops = &loongarch_timer_ops,
+	.flags = DM_FLAG_PRE_RELOC,
+};
+
+U_BOOT_DRVINFO(loongarch_timer) = {
+	.name = "loongarch_timer",
+};
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH v2 14/16] board: emulation: Add qemu-loongarch
  2026-07-01 11:17 [PATCH v2 00/16] LoongArch initial support Yao Zi
                   ` (12 preceding siblings ...)
  2026-07-01 11:18 ` [PATCH v2 13/16] timer: Add loongarch_timer driver Yao Zi
@ 2026-07-01 11:18 ` Yao Zi
  2026-07-02 10:27   ` Simon Glass
  2026-07-01 11:18 ` [PATCH v2 15/16] efi: LoongArch: Define LoongArch bits everywhere Yao Zi
                   ` (4 subsequent siblings)
  18 siblings, 1 reply; 56+ messages in thread
From: Yao Zi @ 2026-07-01 11:18 UTC (permalink / raw)
  To: Tom Rini, Jiaxun Yang, Heinrich Schuchardt, Ilias Apalodimas
  Cc: u-boot, Yao Zi

From: Jiaxun Yang <jiaxun.yang@flygoat.com>

Yet another generic QEMU VIRT machine.
QEMU placed FDT in memory before launching U-Boot, so we
can just obtian FDT here.

Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
Signed-off-by: Yao Zi <me@ziyao.cc>
---

Changed from v1
- Remove dynamic setup for environment variables

 arch/loongarch/Kconfig                        |  5 ++
 arch/loongarch/dts/qemu-loongarch64.dts       |  9 +++
 board/emulation/qemu-loongarch/Kconfig        | 68 +++++++++++++++++++
 board/emulation/qemu-loongarch/MAINTAINERS    |  7 ++
 board/emulation/qemu-loongarch/Makefile       |  6 ++
 .../emulation/qemu-loongarch/qemu-loongarch.c | 67 ++++++++++++++++++
 .../qemu-loongarch/qemu-loongarch.env         |  6 ++
 configs/qemu-loongarch64_defconfig            | 36 ++++++++++
 include/configs/qemu-loongarch.h              | 13 ++++
 9 files changed, 217 insertions(+)
 create mode 100644 arch/loongarch/dts/qemu-loongarch64.dts
 create mode 100644 board/emulation/qemu-loongarch/Kconfig
 create mode 100644 board/emulation/qemu-loongarch/MAINTAINERS
 create mode 100644 board/emulation/qemu-loongarch/Makefile
 create mode 100644 board/emulation/qemu-loongarch/qemu-loongarch.c
 create mode 100644 board/emulation/qemu-loongarch/qemu-loongarch.env
 create mode 100644 configs/qemu-loongarch64_defconfig
 create mode 100644 include/configs/qemu-loongarch.h

diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig
index 5254afb2cd05..6cf7ad9b3a4f 100644
--- a/arch/loongarch/Kconfig
+++ b/arch/loongarch/Kconfig
@@ -7,9 +7,14 @@ config SYS_ARCH
 choice
 	prompt "Target select"
 
+config TARGET_QEMU_LOONGARCH_VIRT
+	bool "Support QEMU Virt Board"
+	select BOARD_LATE_INIT
+
 endchoice
 
 # board-specific options below
+source "board/emulation/qemu-loongarch/Kconfig"
 
 # platform-specific options below
 source "arch/loongarch/cpu/generic/Kconfig"
diff --git a/arch/loongarch/dts/qemu-loongarch64.dts b/arch/loongarch/dts/qemu-loongarch64.dts
new file mode 100644
index 000000000000..39d303798fcb
--- /dev/null
+++ b/arch/loongarch/dts/qemu-loongarch64.dts
@@ -0,0 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2024 Jiaxun Yang <jiaxun.yang@flygoat.com>
+ */
+
+/dts-v1/;
+
+/ {
+};
diff --git a/board/emulation/qemu-loongarch/Kconfig b/board/emulation/qemu-loongarch/Kconfig
new file mode 100644
index 000000000000..188cd6967bfd
--- /dev/null
+++ b/board/emulation/qemu-loongarch/Kconfig
@@ -0,0 +1,68 @@
+if TARGET_QEMU_LOONGARCH_VIRT
+
+config SYS_BOARD
+	default "qemu-loongarch"
+
+config SYS_VENDOR
+	default "emulation"
+
+config SYS_CPU
+	default "generic"
+
+config SYS_CONFIG_NAME
+	default "qemu-loongarch"
+
+config TEXT_BASE
+	default 0x1c000000
+
+config BOARD_SPECIFIC_OPTIONS # dummy
+	def_bool y
+	select GENERIC_LOONGARCH
+	imply AHCI
+	imply BOARD_LATE_INIT
+	imply PCI_INIT_R
+	imply CMD_PCI
+	imply CMD_POWEROFF
+	imply CMD_SCSI
+	imply CMD_PING
+	imply CMD_EXT2
+	imply CMD_EXT4
+	imply CMD_FAT
+	imply CMD_FS_GENERIC
+	imply DOS_PARTITION
+	imply ISO_PARTITION
+	imply EFI_PARTITION
+	imply SCSI_AHCI
+	imply AHCI_PCI
+	imply E1000
+	imply PCI
+	imply NVME_PCI
+	imply PCIE_ECAM_GENERIC
+	imply DM_RNG
+	imply DM_RTC
+	imply QFW
+	imply QFW_MMIO
+	imply SCSI
+	imply SYS_NS16550
+	imply SYSRESET
+	imply SYSRESET_CMD_POWEROFF
+	imply SYSRESET_SYSCON
+	imply VIRTIO_MMIO
+	imply VIRTIO_PCI
+	imply VIRTIO_NET
+	imply VIRTIO_BLK
+	imply MTD_NOR_FLASH
+	imply CFI_FLASH
+	imply OF_HAS_PRIOR_STAGE
+	imply VIDEO
+	imply VIDEO_BOCHS
+	imply SYS_WHITE_ON_BLACK
+	imply USB
+	imply USB_XHCI_HCD
+	imply USB_XHCI_PCI
+	imply USB_KEYBOARD
+	imply CMD_USB
+	imply UFS
+	imply UFS_PCI
+
+endif
diff --git a/board/emulation/qemu-loongarch/MAINTAINERS b/board/emulation/qemu-loongarch/MAINTAINERS
new file mode 100644
index 000000000000..0ecd8201fb96
--- /dev/null
+++ b/board/emulation/qemu-loongarch/MAINTAINERS
@@ -0,0 +1,7 @@
+QEMU LOONGARCH 'VIRT' BOARD
+M:	Jiaxun Yang <jiaxun.yang@flygoat.com>
+S:	Maintained
+F:	board/emulation/qemu-loongarch/
+F:	board/emulation/common/
+F:	include/configs/qemu-loongarch.h
+F:	configs/qemu-loongarch64_defconfig
diff --git a/board/emulation/qemu-loongarch/Makefile b/board/emulation/qemu-loongarch/Makefile
new file mode 100644
index 000000000000..a928b90780e9
--- /dev/null
+++ b/board/emulation/qemu-loongarch/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (C) 2024 Jiaxun yang <jiaxun.yang@flygoat.com>
+#
+
+obj-y	+= qemu-loongarch.o
diff --git a/board/emulation/qemu-loongarch/qemu-loongarch.c b/board/emulation/qemu-loongarch/qemu-loongarch.c
new file mode 100644
index 000000000000..834a36345010
--- /dev/null
+++ b/board/emulation/qemu-loongarch/qemu-loongarch.c
@@ -0,0 +1,67 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2024 Jiaxun Yang <jiaxun.yang@flygoat.com>
+ */
+
+#include <dm.h>
+#include <dm/ofnode.h>
+#include <env.h>
+#include <fdtdec.h>
+#include <image.h>
+#include <linux/sizes.h>
+#include <lmb.h>
+#include <log.h>
+#include <spl.h>
+#include <init.h>
+#include <usb.h>
+#include <virtio_types.h>
+#include <virtio.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#if IS_ENABLED(CONFIG_MTD_NOR_FLASH)
+int is_flash_available(void)
+{
+	if (!ofnode_equal(ofnode_by_compatible(ofnode_null(), "cfi-flash"),
+			  ofnode_null()))
+		return 1;
+
+	return 0;
+}
+#endif
+
+phys_addr_t board_get_usable_ram_top(phys_size_t total_size)
+{
+	/* Limit RAM used by U-Boot to the DDR low region */
+	if (gd->ram_top > 0x10000000)
+		return 0x10000000;
+
+	return gd->ram_top;
+}
+
+int board_init(void)
+{
+	return 0;
+}
+
+int board_late_init(void)
+{
+	/* start usb so that usb keyboard can be used as input device */
+	if (CONFIG_IS_ENABLED(USB_KEYBOARD))
+		usb_init();
+
+	/*
+	 * Make sure virtio bus is enumerated so that peripherals
+	 * on the virtio bus can be discovered by their drivers
+	 */
+	virtio_init();
+
+	return 0;
+}
+
+int board_fdt_blob_setup(void **fdtp)
+{
+	/* Stored the DTB address there during our init */
+	*fdtp = (void *)(ulong)0x100000;
+	return 0;
+}
diff --git a/board/emulation/qemu-loongarch/qemu-loongarch.env b/board/emulation/qemu-loongarch/qemu-loongarch.env
new file mode 100644
index 000000000000..2d130510607d
--- /dev/null
+++ b/board/emulation/qemu-loongarch/qemu-loongarch.env
@@ -0,0 +1,6 @@
+
+stdin=serial,usbkbd
+stdout=serial,vidconsole
+stderr=serial,vidconsole
+
+boot_targets=qfw usb scsi virtio nvme dhcp
diff --git a/configs/qemu-loongarch64_defconfig b/configs/qemu-loongarch64_defconfig
new file mode 100644
index 000000000000..d7f9c4338486
--- /dev/null
+++ b/configs/qemu-loongarch64_defconfig
@@ -0,0 +1,36 @@
+CONFIG_LOONGARCH=y
+CONFIG_SYS_MALLOC_LEN=0x800000
+CONFIG_SYS_MALLOC_F_LEN=0x4000
+CONFIG_NR_DRAM_BANKS=8
+CONFIG_ENV_SIZE=0x20000
+CONFIG_DEFAULT_DEVICE_TREE="qemu-loongarch64"
+CONFIG_DM_RESET=y
+CONFIG_SYS_LOAD_ADDR=0x02000000
+CONFIG_SHOW_REGS=y
+# CONFIG_OF_BOARD_FIXUP is not set
+CONFIG_SYS_PCI_64BIT=y
+CONFIG_FIT=y
+CONFIG_BOOTSTD_FULL=y
+CONFIG_SYS_BOOTM_LEN=0x4000000
+CONFIG_USE_BOOTARGS=y
+CONFIG_BOOTARGS_SUBST=y
+CONFIG_DISPLAY_CPUINFO=y
+CONFIG_DISPLAY_BOARDINFO=y
+# CONFIG_CMD_MII is not set
+CONFIG_CMD_2048=y
+CONFIG_CMD_RTC=y
+CONFIG_CMD_TIME=y
+CONFIG_CMD_SYSBOOT=y
+CONFIG_CMD_QFW=y
+CONFIG_PARTITION_TYPE_GUID=y
+CONFIG_SYS_RELOC_GD_ENV_ADDR=y
+CONFIG_BLKMAP=y
+CONFIG_EFI_MEDIA=y
+CONFIG_DM_MMC=y
+CONFIG_DM_MTD=y
+CONFIG_FLASH_SHOW_PROGRESS=0
+CONFIG_SYS_MAX_FLASH_BANKS=2
+CONFIG_PCI_REGION_MULTI_ENTRY=y
+CONFIG_DM_REBOOT_MODE=y
+CONFIG_RESET_SYSCON=y
+CONFIG_HEXDUMP=y
diff --git a/include/configs/qemu-loongarch.h b/include/configs/qemu-loongarch.h
new file mode 100644
index 000000000000..c1af4fee83ff
--- /dev/null
+++ b/include/configs/qemu-loongarch.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (c) 2024 Jiaxun Yang <jiaxun.yang@flygoat.com>
+ */
+
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+/* Those values are chosen by LoongArchQemuPkg */
+#define CFG_SYS_INIT_RAM_ADDR	0x10000
+#define CFG_SYS_INIT_RAM_SIZE	0x10000
+
+#endif
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH v2 15/16] efi: LoongArch: Define LoongArch bits everywhere
  2026-07-01 11:17 [PATCH v2 00/16] LoongArch initial support Yao Zi
                   ` (13 preceding siblings ...)
  2026-07-01 11:18 ` [PATCH v2 14/16] board: emulation: Add qemu-loongarch Yao Zi
@ 2026-07-01 11:18 ` Yao Zi
  2026-07-02 10:27   ` Simon Glass
  2026-07-01 11:18 ` [PATCH v2 16/16] efi: LoongArch: Implement everything Yao Zi
                   ` (3 subsequent siblings)
  18 siblings, 1 reply; 56+ messages in thread
From: Yao Zi @ 2026-07-01 11:18 UTC (permalink / raw)
  To: Tom Rini, Jiaxun Yang, Heinrich Schuchardt, Ilias Apalodimas
  Cc: u-boot, Yao Zi

From: Jiaxun Yang <jiaxun.yang@flygoat.com>

They are all coming from UEFI specification, PE-COFF specification,
or IANA websites.

Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
Signed-off-by: Yao Zi <me@ziyao.cc>
---

- Reword commit message, replacing "PE spec" with "PE-COFF specification"
- Replace obsolete __loongarch64 macro with __loongarch__ and
  __loongarch_grlen
- Use a true undefined instruction in efi_selftest_miniapp_exception.c
- Define HOST_BOOTEFI_NAME and HOST_PXE_ARCH
- Introduce definition for IMAGE_REL_BASEd_LOONGARCH64_MARK_LA

 include/asm-generic/pe.h                          | 2 ++
 include/config_distro_bootcmd.h                   | 5 +++++
 include/pe.h                                      | 1 +
 lib/efi_loader/efi_helper.c                       | 4 ++++
 lib/efi_loader/efi_image_loader.c                 | 7 +++++++
 lib/efi_loader/efi_runtime.c                      | 4 ++++
 lib/efi_selftest/efi_selftest_miniapp_exception.c | 3 +++
 7 files changed, 26 insertions(+)

diff --git a/include/asm-generic/pe.h b/include/asm-generic/pe.h
index cd5b6ad62bf0..fb93f2621715 100644
--- a/include/asm-generic/pe.h
+++ b/include/asm-generic/pe.h
@@ -38,6 +38,8 @@
 #define IMAGE_FILE_MACHINE_ARM64		0xaa64
 #define IMAGE_FILE_MACHINE_RISCV32		0x5032
 #define IMAGE_FILE_MACHINE_RISCV64		0x5064
+#define IMAGE_FILE_MACHINE_LOONGARCH32	0x6232
+#define IMAGE_FILE_MACHINE_LOONGARCH64	0x6264
 
 /* Header magic constants */
 #define IMAGE_NT_OPTIONAL_HDR32_MAGIC		0x010b
diff --git a/include/config_distro_bootcmd.h b/include/config_distro_bootcmd.h
index 8d6f80a0ce5c..7722ba7627fc 100644
--- a/include/config_distro_bootcmd.h
+++ b/include/config_distro_bootcmd.h
@@ -118,6 +118,8 @@
 #define BOOTEFI_NAME "bootriscv32.efi"
 #elif defined(CONFIG_ARCH_RV64I)
 #define BOOTEFI_NAME "bootriscv64.efi"
+#elif defined(CONFIG_ARCH_LA64)
+#define BOOTEFI_NAME "bootloongarch64.efi"
 #endif
 #endif
 
@@ -371,6 +373,9 @@
 #elif defined(CONFIG_ARCH_RV64I) || ((defined(__riscv) && __riscv_xlen == 64))
 #define BOOTENV_EFI_PXE_ARCH "0x1b"
 #define BOOTENV_EFI_PXE_VCI "PXEClient:Arch:00027:UNDI:003000"
+#elif defined(CONFIG_ARCH_LA64) || (defined(__loongarch__) && __loongarch_grlen == 64))
+#define BOOTENV_EFI_PXE_ARCH "0x27"
+#define BOOTENV_EFI_PXE_VCI "PXEClient:Arch:00039:UNDI:003000"
 #elif defined(CONFIG_SANDBOX)
 # error "sandbox EFI support is only supported on ARM and x86"
 #else
diff --git a/include/pe.h b/include/pe.h
index 086f2b860e99..2340631f82fe 100644
--- a/include/pe.h
+++ b/include/pe.h
@@ -194,6 +194,7 @@ typedef struct _IMAGE_RELOCATION
 #define IMAGE_REL_BASED_THUMB_MOV32             7 /* yes, 7 too */
 #define IMAGE_REL_BASED_RISCV_LOW12I		7 /* yes, 7 too */
 #define IMAGE_REL_BASED_RISCV_LOW12S		8
+#define IMAGE_REL_BASED_LOONGARCH64_MARK_LA	8 /* yes, 8 too */
 #define IMAGE_REL_BASED_MIPS_JMPADDR16          9
 #define IMAGE_REL_BASED_IA64_IMM64              9 /* yes, 9 too */
 #define IMAGE_REL_BASED_DIR64                   10
diff --git a/lib/efi_loader/efi_helper.c b/lib/efi_loader/efi_helper.c
index 44b806aadc4f..bc48e265b901 100644
--- a/lib/efi_loader/efi_helper.c
+++ b/lib/efi_loader/efi_helper.c
@@ -62,6 +62,8 @@
 #define BOOTEFI_NAME "BOOTRISCV32.EFI"
 #elif defined(CONFIG_ARCH_RV64I)
 #define BOOTEFI_NAME "BOOTRISCV64.EFI"
+#elif defined(CONFIG_ARCH_LA64)
+#define BOOTEFI_NAME "BOOTLOONGARCH64.EFI"
 #else
 #error Unsupported UEFI architecture
 #endif
@@ -94,6 +96,8 @@ int efi_get_pxe_arch(void)
 		return 0x19;
 	else if (IS_ENABLED(CONFIG_ARCH_RV64I))
 		return 0x1b;
+	else if (IS_ENABLED(CONFIG_ARCH_LA64))
+		return 0x27;
 
 	return -EINVAL;
 }
diff --git a/lib/efi_loader/efi_image_loader.c b/lib/efi_loader/efi_image_loader.c
index f9a2d2df405d..bed5f1817266 100644
--- a/lib/efi_loader/efi_image_loader.c
+++ b/lib/efi_loader/efi_image_loader.c
@@ -51,6 +51,13 @@ static int machines[] = {
 #if defined(__riscv) && (__riscv_xlen == 64)
 	IMAGE_FILE_MACHINE_RISCV64,
 #endif
+
+#if defined(__loongarch__) && __loongarch_grlen == 64
+	IMAGE_FILE_MACHINE_LOONGARCH64,
+#endif
+#if defined(__loongarch__) && __loongarch_grlen == 32
+	IMAGE_FILE_MACHINE_LOONGARCH32,
+#endif
 	0 };
 
 /**
diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c
index 73d4097464c0..de50d72d634a 100644
--- a/lib/efi_loader/efi_runtime.c
+++ b/lib/efi_loader/efi_runtime.c
@@ -78,6 +78,10 @@ struct dyn_sym {
 #else
 #error unknown riscv target
 #endif
+#elif defined(__loongarch__)
+#define R_RELATIVE	R_LARCH_RELATIVE
+#define R_MASK		0xffffffffULL
+#define IS_RELA		1
 #else
 #error Need to add relocation awareness
 #endif
diff --git a/lib/efi_selftest/efi_selftest_miniapp_exception.c b/lib/efi_selftest/efi_selftest_miniapp_exception.c
index f668cdac4ab2..648206c17098 100644
--- a/lib/efi_selftest/efi_selftest_miniapp_exception.c
+++ b/lib/efi_selftest/efi_selftest_miniapp_exception.c
@@ -35,6 +35,9 @@ efi_status_t EFIAPI efi_main(efi_handle_t handle,
 	asm volatile (".word 0xffffffff\n");
 #elif defined(CONFIG_X86)
 	asm volatile (".word 0xffff\n");
+#elif defined(CONFIG_LOONGARCH)
+	/* ud 31 */
+	asm volatile (".word 0x386007ff\n");
 #elif defined(CONFIG_SANDBOX)
 #if (HOST_ARCH == HOST_ARCH_ARM || HOST_ARCH == HOST_ARCH_AARCH64)
 	asm volatile (".word 0xe7f7defb\n");
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH v2 16/16] efi: LoongArch: Implement everything
  2026-07-01 11:17 [PATCH v2 00/16] LoongArch initial support Yao Zi
                   ` (14 preceding siblings ...)
  2026-07-01 11:18 ` [PATCH v2 15/16] efi: LoongArch: Define LoongArch bits everywhere Yao Zi
@ 2026-07-01 11:18 ` Yao Zi
  2026-07-02 10:29   ` Simon Glass
  2026-07-01 15:53 ` [PATCH v2 00/16] LoongArch initial support Jiaxun Yang
                   ` (2 subsequent siblings)
  18 siblings, 1 reply; 56+ messages in thread
From: Yao Zi @ 2026-07-01 11:18 UTC (permalink / raw)
  To: Tom Rini, Jiaxun Yang, Heinrich Schuchardt, Ilias Apalodimas
  Cc: u-boot, Yao Zi

From: Jiaxun Yang <jiaxun.yang@flygoat.com>

Implement crt, reloc, linker scripts, wire things up in
Makefiles and Kconfig.

Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
Signed-off-by: Yao Zi <me@ziyao.cc>
---

Changed from v1
- Replace obsolete macro __loongarch64 with __loongarch__ and
  __loongarch_grlen
- Support relocation of IMAGE_REL_BASED_LOONGARCH64_MARK_LA

 arch/loongarch/config.mk                 |   4 +
 arch/loongarch/lib/Makefile              |  12 ++
 arch/loongarch/lib/crt0_loongarch_efi.S  | 182 +++++++++++++++++++++++
 arch/loongarch/lib/elf_loongarch_efi.lds |  76 ++++++++++
 arch/loongarch/lib/reloc_loongarch_efi.c | 107 +++++++++++++
 lib/efi_loader/Kconfig                   |   2 +-
 lib/efi_loader/efi_helper.c              |   3 +
 lib/efi_loader/efi_image_loader.c        |  26 ++++
 8 files changed, 411 insertions(+), 1 deletion(-)
 create mode 100644 arch/loongarch/lib/crt0_loongarch_efi.S
 create mode 100644 arch/loongarch/lib/elf_loongarch_efi.lds
 create mode 100644 arch/loongarch/lib/reloc_loongarch_efi.c

diff --git a/arch/loongarch/config.mk b/arch/loongarch/config.mk
index 7c247400e361..bae4566e9b62 100644
--- a/arch/loongarch/config.mk
+++ b/arch/loongarch/config.mk
@@ -21,3 +21,7 @@ endif
 PLATFORM_CPPFLAGS	+= -fpic
 PLATFORM_RELFLAGS	+= -fno-common -ffunction-sections -fdata-sections
 LDFLAGS_u-boot		+= --gc-sections -static -pie
+
+EFI_LDS				:= elf_loongarch_efi.lds
+EFI_CRT0			:= crt0_loongarch_efi.o
+EFI_RELOC			:= reloc_loongarch_efi.o
diff --git a/arch/loongarch/lib/Makefile b/arch/loongarch/lib/Makefile
index e65e66357a9b..17d2b1160b41 100644
--- a/arch/loongarch/lib/Makefile
+++ b/arch/loongarch/lib/Makefile
@@ -12,3 +12,15 @@ ifeq ($(CONFIG_$(SPL_)SYSRESET),)
 obj-y	+= reset.o
 endif
 obj-y	+= setjmp.o
+
+# For building EFI apps
+CFLAGS_NON_EFI := -fstack-protector-strong
+CFLAGS_$(EFI_CRT0) := $(CFLAGS_EFI)
+CFLAGS_REMOVE_$(EFI_CRT0) := $(CFLAGS_NON_EFI)
+
+CFLAGS_$(EFI_RELOC) := $(CFLAGS_EFI)
+CFLAGS_REMOVE_$(EFI_RELOC) := $(CFLAGS_NON_EFI)
+
+extra-$(CONFIG_CMD_BOOTEFI_HELLO_COMPILE) += $(EFI_CRT0) $(EFI_RELOC)
+extra-$(CONFIG_CMD_BOOTEFI_SELFTEST) += $(EFI_CRT0) $(EFI_RELOC)
+extra-$(CONFIG_EFI) += $(EFI_CRT0) $(EFI_RELOC)
diff --git a/arch/loongarch/lib/crt0_loongarch_efi.S b/arch/loongarch/lib/crt0_loongarch_efi.S
new file mode 100644
index 000000000000..2048d3b515c3
--- /dev/null
+++ b/arch/loongarch/lib/crt0_loongarch_efi.S
@@ -0,0 +1,182 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * crt0-efi-loongarch.S - PE/COFF header for LoongArch EFI applications
+ *
+ * Copright (C) 2024 Jiaxun Yang <jiaxun.yang@flygoat.com>
+ */
+
+#include <asm-generic/pe.h>
+#include <asm/asm.h>
+
+#if __loongarch_grlen == 64
+#define PE_MACHINE	IMAGE_FILE_MACHINE_LOONGARCH64
+#define PE_MAGIC    IMAGE_NT_OPTIONAL_HDR64_MAGIC
+#define IMG_CHARACTERISTICS \
+	(IMAGE_FILE_EXECUTABLE_IMAGE | \
+	 IMAGE_FILE_LINE_NUMS_STRIPPED | \
+	 IMAGE_FILE_LOCAL_SYMS_STRIPPED | \
+	 IMAGE_FILE_LARGE_ADDRESS_AWARE | \
+	 IMAGE_FILE_DEBUG_STRIPPED)
+#else
+#define PE_MACHINE	IMAGE_FILE_MACHINE_LOONGARCH32
+#define PE_MAGIC    IMAGE_NT_OPTIONAL_HDR32_MAGIC
+#define IMG_CHARACTERISTICS \
+	(IMAGE_FILE_EXECUTABLE_IMAGE | \
+	 IMAGE_FILE_LINE_NUMS_STRIPPED | \
+	 IMAGE_FILE_LOCAL_SYMS_STRIPPED | \
+	 IMAGE_FILE_DEBUG_STRIPPED)
+#endif
+
+	.section	.text.head
+
+	/*
+	 * Magic "MZ" signature for PE/COFF
+	 */
+	.globl	ImageBase
+ImageBase:
+	.short	IMAGE_DOS_SIGNATURE		/* 'MZ' */
+	.skip	58
+	.long	pe_header - ImageBase		/* Offset to the PE header */
+pe_header:
+	.long	IMAGE_NT_SIGNATURE		/* 'PE' */
+coff_header:
+	.short	PE_MACHINE			/* LoongArch 64/32-bit */
+	.short	3				/* nr_sections */
+	.long	0				/* TimeDateStamp */
+	.long	0				/* PointerToSymbolTable */
+	.long	0				/* NumberOfSymbols */
+	.short	section_table - optional_header	/* SizeOfOptionalHeader */
+	.short	IMG_CHARACTERISTICS		/* Characteristics */
+optional_header:
+	.short	PE_MAGIC			/* PE32(+) format */
+	.byte	0x02				/* MajorLinkerVersion */
+	.byte	0x14				/* MinorLinkerVersion */
+	.long	_edata - _start			/* SizeOfCode */
+	.long	0				/* SizeOfInitializedData */
+	.long	0				/* SizeOfUninitializedData */
+	.long	_start - ImageBase		/* AddressOfEntryPoint */
+	.long	_start - ImageBase		/* BaseOfCode */
+#if __loongarch_grlen != 64
+	.long	0				/* BaseOfData */
+#endif
+
+extra_header_fields:
+	LONG	0
+	.long	0x200				/* SectionAlignment */
+	.long	0x200				/* FileAlignment */
+	.short	0				/* MajorOperatingSystemVersion */
+	.short	0				/* MinorOperatingSystemVersion */
+	.short	1				/* MajorImageVersion */
+	.short	0				/* MinorImageVersion */
+	.short	0				/* MajorSubsystemVersion */
+	.short	0				/* MinorSubsystemVersion */
+	.long	0				/* Win32VersionValue */
+
+	.long	_edata - ImageBase		/* SizeOfImage */
+
+	/*
+	 * Everything before the kernel image is considered part of the header
+	 */
+	.long	_start - ImageBase		/* SizeOfHeaders */
+	.long	0				/* CheckSum */
+	.short	IMAGE_SUBSYSTEM_EFI_APPLICATION /* Subsystem */
+#if CONFIG_VENDOR_EFI
+	.short	0				/* DllCharacteristics */
+#else
+	.short	IMAGE_DLLCHARACTERISTICS_NX_COMPAT
+#endif
+	LONG	0				/* SizeOfStackReserve */
+	LONG	0				/* SizeOfStackCommit */
+	LONG	0				/* SizeOfHeapReserve */
+	LONG	0				/* SizeOfHeapCommit */
+
+	.long	0				/* LoaderFlags */
+	.long	0x6				/* NumberOfRvaAndSizes */
+
+	.quad	0				/* ExportTable */
+	.quad	0				/* ImportTable */
+	.quad	0				/* ResourceTable */
+	.quad	0				/* ExceptionTable */
+	.quad	0				/* CertificationTable */
+	.quad	0				/* BaseRelocationTable */
+
+	/* Section table */
+section_table:
+
+	/*
+	 * The EFI application loader requires a relocation section
+	 * because EFI applications must be relocatable.  This is a
+	 * dummy section as far as we are concerned.
+	 */
+	.ascii	".reloc"
+	.byte	0
+	.byte	0			/* end of 0 padding of section name */
+	.long	0
+	.long	0
+	.long	0			/* SizeOfRawData */
+	.long	0			/* PointerToRawData */
+	.long	0			/* PointerToRelocations */
+	.long	0			/* PointerToLineNumbers */
+	.short	0			/* NumberOfRelocations */
+	.short	0			/* NumberOfLineNumbers */
+	.long	0x42100040		/* Characteristics (section flags) */
+
+
+	.ascii	".text"
+	.byte	0
+	.byte	0
+	.byte	0			/* end of 0 padding of section name */
+	.long	_etext - _start		/* VirtualSize */
+	.long	_start - ImageBase	/* VirtualAddress */
+	.long	_etext - _start		/* SizeOfRawData */
+	.long	_start - ImageBase	/* PointerToRawData */
+	.long	0			/* PointerToRelocations (0 for executables) */
+	.long	0			/* PointerToLineNumbers (0 for executables) */
+	.short	0			/* NumberOfRelocations  (0 for executables) */
+	.short	0			/* NumberOfLineNumbers  (0 for executables) */
+	/* Characteristics (section flags) */
+	.long	(IMAGE_SCN_MEM_READ | \
+		 IMAGE_SCN_MEM_EXECUTE | \
+		 IMAGE_SCN_CNT_CODE)
+
+	.ascii	".data"
+	.byte	0
+	.byte	0
+	.byte	0			/* end of 0 padding of section name */
+	.long	_edata - _data		/* VirtualSize */
+	.long	_data - ImageBase	/* VirtualAddress */
+	.long	_edata - _data		/* SizeOfRawData */
+	.long	_data - ImageBase	/* PointerToRawData */
+	.long	0			/* PointerToRelocations */
+	.long	0			/* PointerToLineNumbers */
+	.short	0			/* NumberOfRelocations */
+	.short	0			/* NumberOfLineNumbers */
+	/* Characteristics (section flags) */
+	.long	(IMAGE_SCN_MEM_WRITE | \
+		 IMAGE_SCN_MEM_READ | \
+		 IMAGE_SCN_CNT_INITIALIZED_DATA)
+
+	.align		12
+	.globl	_start
+	.type	_start, @function
+_start:
+	PTR_ADDI	sp, sp, -(3 * LONGSIZE)
+	LONG_S		ra, sp, 0
+	LONG_S		a0, sp, (1 * LONGSIZE)
+	LONG_S		a1, sp, (2 * LONGSIZE)
+
+	move		a2, a0		/* a2: ImageHandle */
+	move		a3, a1		/* a3: SystemTable */
+	la.local	a0, ImageBase	/* a0: ImageBase */
+	la.local	a1, _DYNAMIC	/* a1: DynamicSection */
+	bl 	  	_relocate
+	bnez		a0, 0f
+
+	LONG_L		a0, sp, (1 * LONGSIZE)
+	LONG_L		a1, sp, (2 * LONGSIZE)
+	bl		efi_main
+
+0:	LONG_L		ra, sp, 0
+	PTR_ADDI	sp, sp, (3 * LONGSIZE)
+	jr			ra
+	.end	  _start
diff --git a/arch/loongarch/lib/elf_loongarch_efi.lds b/arch/loongarch/lib/elf_loongarch_efi.lds
new file mode 100644
index 000000000000..050e5a52a0b3
--- /dev/null
+++ b/arch/loongarch/lib/elf_loongarch_efi.lds
@@ -0,0 +1,76 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+/*
+ * U-Boot LoongArch
+ *
+ * Modified from arch/riscv/lib/elf_riscv64_efi.lds
+ */
+
+OUTPUT_ARCH(loongarch)
+
+PHDRS
+{
+	data PT_LOAD FLAGS(3); /* SHF_WRITE | SHF_ALLOC */
+}
+
+ENTRY(_start)
+SECTIONS
+{
+	.text 0x0 : {
+		_text = .;
+		*(.text.head)
+		*(.text)
+		*(.text.*)
+		*(.gnu.linkonce.t.*)
+		*(.srodata)
+		*(.rodata*)
+		. = ALIGN(16);
+		*(.dynamic);
+		. = ALIGN(512);
+	}
+	.rela.dyn : { *(.rela.dyn) }
+	.rela.plt : { *(.rela.plt) }
+	.rela.got : { *(.rela.got) }
+	.rela.data : { *(.rela.data) *(.rela.data*) }
+	_etext = .;
+	_text_size = . - _text;
+	. = ALIGN(4096);
+	.data : {
+		_data = .;
+		*(.sdata)
+		*(.data)
+		*(.data1)
+		*(.data.*)
+		*(.got.plt)
+		*(.got)
+
+		/*
+		 * The EFI loader doesn't seem to like a .bss section, so we
+		 * stick it all into .data:
+		 */
+		. = ALIGN(16);
+		_bss = .;
+		*(.sbss)
+		*(.scommon)
+		*(.dynbss)
+		*(.bss)
+		*(.bss.*)
+		*(COMMON)
+		. = ALIGN(512);
+		_bss_end = .;
+		_edata = .;
+	} :data
+	_data_size = _edata - _data;
+
+	. = ALIGN(4096);
+	.dynsym   : { *(.dynsym) }
+	. = ALIGN(4096);
+	.dynstr   : { *(.dynstr) }
+	. = ALIGN(4096);
+	.note.gnu.build-id : { *(.note.gnu.build-id) }
+	/DISCARD/ : {
+		*(.rel.reloc)
+		*(.eh_frame)
+		*(.note.GNU-stack)
+	}
+	.comment 0 : { *(.comment) }
+}
diff --git a/arch/loongarch/lib/reloc_loongarch_efi.c b/arch/loongarch/lib/reloc_loongarch_efi.c
new file mode 100644
index 000000000000..2985da268d80
--- /dev/null
+++ b/arch/loongarch/lib/reloc_loongarch_efi.c
@@ -0,0 +1,107 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* reloc_loongarch.c - position independent ELF shared object relocator
+   Copyright (C) 2018 Alexander Graf <agraf@suse.de>
+   Copyright (C) 2014 Linaro Ltd. <ard.biesheuvel@linaro.org>
+   Copyright (C) 1999 Hewlett-Packard Co.
+	Contributed by David Mosberger <davidm@hpl.hp.com>.
+
+    All rights reserved.
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions
+    are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials
+      provided with the distribution.
+    * Neither the name of Hewlett-Packard Co. nor the names of its
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+    CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+    INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+    MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+    BE LIABLE FOR ANYDIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+    OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+    TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+    SUCH DAMAGE.
+*/
+
+#include <efi.h>
+
+#include <elf.h>
+
+#if __loongarch_grlen == 64
+#define Elf_Dyn		Elf64_Dyn
+#define Elf_Rela	Elf64_Rela
+#define ELF_R_TYPE	ELF64_R_TYPE
+#else
+#define Elf_Dyn		Elf32_Dyn
+#define Elf_Rela	Elf32_Rela
+#define ELF_R_TYPE	ELF32_R_TYPE
+#endif
+
+efi_status_t EFIAPI _relocate(long ldbase, Elf_Dyn *dyn)
+{
+	long relsz = 0, relent = 0;
+	Elf_Rela *rel = 0;
+	unsigned long *addr;
+	int i;
+
+	for (i = 0; dyn[i].d_tag != DT_NULL; ++i) {
+		switch (dyn[i].d_tag) {
+		case DT_RELA:
+			rel = (Elf_Rela *)
+				((unsigned long)dyn[i].d_un.d_ptr
+					+ ldbase);
+			break;
+		case DT_RELASZ:
+			relsz = dyn[i].d_un.d_val;
+			break;
+		case DT_RELAENT:
+			relent = dyn[i].d_un.d_val;
+			break;
+		case DT_PLTGOT:
+			addr = (unsigned long *)
+				((unsigned long)dyn[i].d_un.d_ptr
+					+ ldbase);
+			break;
+		default:
+			break;
+		}
+	}
+
+	if (!rel && relent == 0)
+		return EFI_SUCCESS;
+
+	if (!rel || relent == 0)
+		return EFI_LOAD_ERROR;
+
+	while (relsz > 0) {
+		/* apply the relocs */
+		switch (ELF_R_TYPE(rel->r_info)) {
+		case R_LARCH_NONE:
+			break;
+		case R_LARCH_RELATIVE:
+			addr = (unsigned long *)
+				(ldbase + rel->r_offset);
+			*addr += ldbase;
+			break;
+		default:
+			break;
+		}
+		rel = (Elf_Rela *)((char *)rel + relent);
+		relsz -= relent;
+	}
+	return EFI_SUCCESS;
+}
+
diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig
index 4cb13ae7c8a8..89988f199f7b 100644
--- a/lib/efi_loader/Kconfig
+++ b/lib/efi_loader/Kconfig
@@ -7,7 +7,7 @@ config EFI_LOADER
 			SYS_CPU = arm1176 || \
 			SYS_CPU = armv7   || \
 			SYS_CPU = armv8)  || \
-		X86 || RISCV || SANDBOX)
+		X86 || RISCV || LOONGARCH || SANDBOX)
 	# We have not fully removed the requirement for some block device
 	depends on BLK
 	# We need EFI_STUB_64BIT to be set on x86_64 with EFI_STUB
diff --git a/lib/efi_loader/efi_helper.c b/lib/efi_loader/efi_helper.c
index bc48e265b901..641b001a9a16 100644
--- a/lib/efi_loader/efi_helper.c
+++ b/lib/efi_loader/efi_helper.c
@@ -44,6 +44,9 @@
 #elif HOST_ARCH == HOST_ARCH_RISCV64
 #define HOST_BOOTEFI_NAME "BOOTRISCV64.EFI"
 #define HOST_PXE_ARCH 0x1b
+#elif HOST_ARCH == HOST_ARCH_LOONGARCH64
+#define HOST_BOOTEFI_NAME "BOOTLOONGARCH64.EFI"
+#define HOST_PXE_ARCH 0x27
 #else
 #error Unsupported Host architecture
 #endif
diff --git a/lib/efi_loader/efi_image_loader.c b/lib/efi_loader/efi_image_loader.c
index bed5f1817266..3c28923003dc 100644
--- a/lib/efi_loader/efi_image_loader.c
+++ b/lib/efi_loader/efi_image_loader.c
@@ -19,6 +19,7 @@
 #include <crypto/mscode.h>
 #include <crypto/pkcs7_parser.h>
 #include <linux/err.h>
+#include <linux/bitfield.h>
 
 const efi_guid_t efi_global_variable_guid = EFI_GLOBAL_VARIABLE_GUID;
 const efi_guid_t efi_guid_device_path = EFI_DEVICE_PATH_PROTOCOL_GUID;
@@ -165,6 +166,7 @@ static efi_status_t efi_loader_relocate(const IMAGE_BASE_RELOCATION *rel,
 			uint32_t entry_offset = *relocs & 0xfff;
 			unsigned long offset;
 			int type = *relocs >> EFI_PAGE_SHIFT;
+			__maybe_unused uint64_t tmp;
 			uint64_t *x64;
 			uint32_t *x32;
 			uint16_t *x16;
@@ -230,6 +232,30 @@ static efi_status_t efi_loader_relocate(const IMAGE_BASE_RELOCATION *rel,
 					log_err("Unsupported reloc offset\n");
 					return EFI_LOAD_ERROR;
 				}
+				break;
+#elif defined(__loongarch__) && __loongarch_grlen == 64
+			case IMAGE_REL_BASED_LOONGARCH64_MARK_LA:
+				if (virt_size - offset < 16) {
+					log_debug("relocation address out of bounds\n");
+					return EFI_LOAD_ERROR;
+				}
+
+				tmp = FIELD_GET(GENMASK(24, 5), x32[0]) << 12;
+				tmp |= FIELD_GET(GENMASK(21, 10), x32[1]);
+				tmp |= FIELD_GET(GENMASK(24, 5), x32[2]) << 32;
+				tmp |= FIELD_GET(GENMASK(21, 10), x32[3]) << 52;
+				tmp += (uint64_t)delta;
+
+				x32[0] &= ~GENMASK(24, 5);
+				x32[0] |= FIELD_PREP(GENMASK(24, 5), tmp >> 12);
+				x32[1] &= ~GENMASK(21, 10);
+				x32[1] |= FIELD_PREP(GENMASK(21, 10), tmp);
+				x32[2] &= ~GENMASK(24, 5);
+				x32[2] |= FIELD_PREP(GENMASK(24, 5), tmp >> 32);
+				x32[3] &= ~GENMASK(21, 10);
+				x32[3] |= FIELD_PREP(GENMASK(21, 10),
+						     tmp >> 52);
+
 				break;
 #endif
 			default:
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 56+ messages in thread

* Re: [PATCH v2 00/16] LoongArch initial support
  2026-07-01 11:17 [PATCH v2 00/16] LoongArch initial support Yao Zi
                   ` (15 preceding siblings ...)
  2026-07-01 11:18 ` [PATCH v2 16/16] efi: LoongArch: Implement everything Yao Zi
@ 2026-07-01 15:53 ` Jiaxun Yang
  2026-07-01 17:59 ` Tom Rini
  2026-07-02 10:31 ` [v2,00/16] " Simon Glass
  18 siblings, 0 replies; 56+ messages in thread
From: Jiaxun Yang @ 2026-07-01 15:53 UTC (permalink / raw)
  To: Yao Zi, Tom Rini, Heinrich Schuchardt, Ilias Apalodimas; +Cc: u-boot



On Wed, 1 Jul 2026, at 12:17 PM, Yao Zi wrote:
> Hi all,
>
> After talking to Jiaxun privately, I decided to take over the series.

Many thanks for continuing this work!

I'd like to add that Yao have addressed most of the comments I received
for v1. 

I'm always happy to coordinate on next steps for LoongArch port. I'm
also happy to co-maintain the port with Ziyao if we made it into upstream.

Thanks
Jiaxun

>
> So far this series has implemented general support for initializing CPU,
> exceptions, kernel booting, CPU and timer drivers, QEMU LoongArch virt
> machine support and UEFI standard compliant EFI booting support.
>
> LoongArch had defined 3 ISA variants, LA64, LA32 and LA32R (Reduced,
> intended for MCUs and education purpose). This is a little-endian only
> architecture. Only LA64 is implemented in this series since the hardware
> is more widely available, and I'll work on 32bit support later.
>
> This series had passed checkpatch with exceptions on some false alarms
> and headers imported elsewhere. I've tested virtio devices, direct
> kernel booting, efistub kernel booting and grub. For loongarch64 CI, I
> would continue to work on Jiaxun's another series[1] soon.
>
> Toolchain can be found at [2] or using upstream one, to build
>
> 	make qemu-loongarch64_defconfig
> 	make
>
> To run in QEMU:
>
> 	qemu-system-loongarch64 -nographic -machine virt -bios u-boot.bin
>
> TODOs on the architecture & board:
> - loongson,ls7a-rtc driver
>  - The only device on QEMU board haven't been supported yet
> - LoongArch sandbox host support
> - TLB enablement
>  - This is required for real CPU to utilize caches
> - Possibly EFI-APP support for real machine
>
> I have one question regarding the process: I've decided to
> coordinate with Jiaxun to maintain the loongarch port, and AFAIK we
> would need a custodian tree on U-Boot's GitLab instance in order to run
> CI. If this true, what's the process of creating a tree?
>
> Thanks for your time and review!
>
> Link to v1: 
> https://lore.kernel.org/u-boot/20240522-loongarch-v1-0-1407e0b69678@flygoat.com/
>
> [1]: 
> https://lore.kernel.org/u-boot/20240717-docker-image-v1-0-7c7fc6251e7a@flygoat.com/
> [2]: 
> https://mirrors.edge.kernel.org/pub/tools/crosstool/files/bin/x86_64/14.2.0/x86_64-gcc-14.2.0-nolibc-loongarch64-linux.tar.gz
>
> Jiaxun Yang (16):
>   lib: fdtdec: Handle multiple memory nodes
>   linux/io.h: Use map_physmem to implement ioremap
>   image: Take entry point as an output of setup_booti
>   elf: Define LoongArch bits
>   image: Define IH_ARCH_LOONGARCH
>   LoongArch: skeleton and headers
>   LoongArch: lib: General routines
>   LoongArch: CPU assembly routines
>   LoongArch: Exception handling
>   LoongArch: Boot Image bits
>   LoongArch: Generic CPU type
>   cpu: Add loongarch_cpu driver
>   timer: Add loongarch_timer driver
>   board: emulation: Add qemu-loongarch
>   efi: LoongArch: Define LoongArch bits everywhere
>   efi: LoongArch: Implement everything
>
>  Makefile                                      |    2 +
>  arch/Kconfig                                  |   15 +
>  arch/arm/lib/image.c                          |    3 +-
>  arch/loongarch/Kconfig                        |   49 +
>  arch/loongarch/Makefile                       |   19 +
>  arch/loongarch/config.mk                      |   27 +
>  arch/loongarch/cpu/Makefile                   |    9 +
>  arch/loongarch/cpu/cpu.c                      |   27 +
>  arch/loongarch/cpu/generic/Kconfig            |   13 +
>  arch/loongarch/cpu/generic/Makefile           |    7 +
>  arch/loongarch/cpu/generic/cpu.c              |   22 +
>  arch/loongarch/cpu/generic/dram.c             |   21 +
>  arch/loongarch/cpu/genex.S                    |   21 +
>  arch/loongarch/cpu/smp_secondary.S            |   55 +
>  arch/loongarch/cpu/start.S                    |  170 ++
>  arch/loongarch/cpu/u-boot.lds                 |   85 +
>  arch/loongarch/dts/Makefile                   |    6 +
>  arch/loongarch/dts/qemu-loongarch64.dts       |    9 +
>  arch/loongarch/include/asm/acpi_table.h       |    8 +
>  arch/loongarch/include/asm/addrspace.h        |   86 +
>  .../include/asm/arch-generic/entry-init.h     |   15 +
>  arch/loongarch/include/asm/asm.h              |  186 +++
>  arch/loongarch/include/asm/atomic.h           |   12 +
>  arch/loongarch/include/asm/barrier.h          |  138 ++
>  arch/loongarch/include/asm/bitops.h           |  156 ++
>  arch/loongarch/include/asm/byteorder.h        |   22 +
>  arch/loongarch/include/asm/cache.h            |   34 +
>  arch/loongarch/include/asm/config.h           |   11 +
>  arch/loongarch/include/asm/cpu.h              |  123 ++
>  arch/loongarch/include/asm/dma-mapping.h      |   27 +
>  arch/loongarch/include/asm/global_data.h      |   50 +
>  arch/loongarch/include/asm/gpio.h             |   11 +
>  arch/loongarch/include/asm/io.h               |  399 +++++
>  arch/loongarch/include/asm/linkage.h          |   11 +
>  arch/loongarch/include/asm/loongarch.h        | 1467 +++++++++++++++++
>  arch/loongarch/include/asm/posix_types.h      |   87 +
>  arch/loongarch/include/asm/processor.h        |   11 +
>  arch/loongarch/include/asm/ptrace.h           |   33 +
>  arch/loongarch/include/asm/regdef.h           |   42 +
>  arch/loongarch/include/asm/sections.h         |    8 +
>  arch/loongarch/include/asm/setjmp.h           |   25 +
>  arch/loongarch/include/asm/spl.h              |   11 +
>  arch/loongarch/include/asm/stackframe.h       |  175 ++
>  arch/loongarch/include/asm/string.h           |   11 +
>  arch/loongarch/include/asm/system.h           |   74 +
>  arch/loongarch/include/asm/types.h            |   37 +
>  arch/loongarch/include/asm/u-boot-loongarch.h |   23 +
>  arch/loongarch/include/asm/u-boot.h           |   30 +
>  arch/loongarch/include/asm/unaligned.h        |   11 +
>  arch/loongarch/lib/Makefile                   |   26 +
>  arch/loongarch/lib/asm-offsets.c              |   66 +
>  arch/loongarch/lib/boot.c                     |   14 +
>  arch/loongarch/lib/bootm.c                    |  163 ++
>  arch/loongarch/lib/cache.c                    |  213 +++
>  arch/loongarch/lib/crt0_loongarch_efi.S       |  182 ++
>  arch/loongarch/lib/elf_loongarch_efi.lds      |   76 +
>  arch/loongarch/lib/image.c                    |   66 +
>  arch/loongarch/lib/interrupts.c               |  189 +++
>  arch/loongarch/lib/reloc_loongarch_efi.c      |  107 ++
>  arch/loongarch/lib/reset.c                    |   14 +
>  arch/loongarch/lib/setjmp.S                   |   52 +
>  arch/riscv/lib/image.c                        |    4 +-
>  arch/sandbox/lib/bootm.c                      |    2 +-
>  board/emulation/qemu-loongarch/Kconfig        |   68 +
>  board/emulation/qemu-loongarch/MAINTAINERS    |    7 +
>  board/emulation/qemu-loongarch/Makefile       |    6 +
>  .../emulation/qemu-loongarch/qemu-loongarch.c |   67 +
>  .../qemu-loongarch/qemu-loongarch.env         |    6 +
>  boot/bootm.c                                  |    5 +-
>  boot/image.c                                  |    1 +
>  cmd/Kconfig                                   |    2 +-
>  cmd/booti.c                                   |    5 +-
>  common/spl/spl.c                              |    9 +-
>  configs/qemu-loongarch64_defconfig            |   36 +
>  drivers/cpu/Kconfig                           |    6 +
>  drivers/cpu/Makefile                          |    1 +
>  drivers/cpu/loongarch_cpu.c                   |  148 ++
>  drivers/timer/Kconfig                         |    8 +
>  drivers/timer/Makefile                        |    1 +
>  drivers/timer/loongarch_timer.c               |  112 ++
>  include/asm-generic/global_data.h             |    2 +-
>  include/asm-generic/pe.h                      |    2 +
>  include/config_distro_bootcmd.h               |    5 +
>  include/configs/qemu-loongarch.h              |   13 +
>  include/elf.h                                 |    9 +-
>  include/host_arch.h                           |    2 +
>  include/image.h                               |    4 +-
>  include/linux/io.h                            |    3 +-
>  include/pe.h                                  |    1 +
>  lib/efi_loader/Kconfig                        |    2 +-
>  lib/efi_loader/efi_helper.c                   |    7 +
>  lib/efi_loader/efi_image_loader.c             |   33 +
>  lib/efi_loader/efi_runtime.c                  |    4 +
>  .../efi_selftest_miniapp_exception.c          |    3 +
>  lib/fdtdec.c                                  |  129 +-
>  95 files changed, 5704 insertions(+), 71 deletions(-)
>  create mode 100644 arch/loongarch/Kconfig
>  create mode 100644 arch/loongarch/Makefile
>  create mode 100644 arch/loongarch/config.mk
>  create mode 100644 arch/loongarch/cpu/Makefile
>  create mode 100644 arch/loongarch/cpu/cpu.c
>  create mode 100644 arch/loongarch/cpu/generic/Kconfig
>  create mode 100644 arch/loongarch/cpu/generic/Makefile
>  create mode 100644 arch/loongarch/cpu/generic/cpu.c
>  create mode 100644 arch/loongarch/cpu/generic/dram.c
>  create mode 100644 arch/loongarch/cpu/genex.S
>  create mode 100644 arch/loongarch/cpu/smp_secondary.S
>  create mode 100644 arch/loongarch/cpu/start.S
>  create mode 100644 arch/loongarch/cpu/u-boot.lds
>  create mode 100644 arch/loongarch/dts/Makefile
>  create mode 100644 arch/loongarch/dts/qemu-loongarch64.dts
>  create mode 100644 arch/loongarch/include/asm/acpi_table.h
>  create mode 100644 arch/loongarch/include/asm/addrspace.h
>  create mode 100644 arch/loongarch/include/asm/arch-generic/entry-init.h
>  create mode 100644 arch/loongarch/include/asm/asm.h
>  create mode 100644 arch/loongarch/include/asm/atomic.h
>  create mode 100644 arch/loongarch/include/asm/barrier.h
>  create mode 100644 arch/loongarch/include/asm/bitops.h
>  create mode 100644 arch/loongarch/include/asm/byteorder.h
>  create mode 100644 arch/loongarch/include/asm/cache.h
>  create mode 100644 arch/loongarch/include/asm/config.h
>  create mode 100644 arch/loongarch/include/asm/cpu.h
>  create mode 100644 arch/loongarch/include/asm/dma-mapping.h
>  create mode 100644 arch/loongarch/include/asm/global_data.h
>  create mode 100644 arch/loongarch/include/asm/gpio.h
>  create mode 100644 arch/loongarch/include/asm/io.h
>  create mode 100644 arch/loongarch/include/asm/linkage.h
>  create mode 100644 arch/loongarch/include/asm/loongarch.h
>  create mode 100644 arch/loongarch/include/asm/posix_types.h
>  create mode 100644 arch/loongarch/include/asm/processor.h
>  create mode 100644 arch/loongarch/include/asm/ptrace.h
>  create mode 100644 arch/loongarch/include/asm/regdef.h
>  create mode 100644 arch/loongarch/include/asm/sections.h
>  create mode 100644 arch/loongarch/include/asm/setjmp.h
>  create mode 100644 arch/loongarch/include/asm/spl.h
>  create mode 100644 arch/loongarch/include/asm/stackframe.h
>  create mode 100644 arch/loongarch/include/asm/string.h
>  create mode 100644 arch/loongarch/include/asm/system.h
>  create mode 100644 arch/loongarch/include/asm/types.h
>  create mode 100644 arch/loongarch/include/asm/u-boot-loongarch.h
>  create mode 100644 arch/loongarch/include/asm/u-boot.h
>  create mode 100644 arch/loongarch/include/asm/unaligned.h
>  create mode 100644 arch/loongarch/lib/Makefile
>  create mode 100644 arch/loongarch/lib/asm-offsets.c
>  create mode 100644 arch/loongarch/lib/boot.c
>  create mode 100644 arch/loongarch/lib/bootm.c
>  create mode 100644 arch/loongarch/lib/cache.c
>  create mode 100644 arch/loongarch/lib/crt0_loongarch_efi.S
>  create mode 100644 arch/loongarch/lib/elf_loongarch_efi.lds
>  create mode 100644 arch/loongarch/lib/image.c
>  create mode 100644 arch/loongarch/lib/interrupts.c
>  create mode 100644 arch/loongarch/lib/reloc_loongarch_efi.c
>  create mode 100644 arch/loongarch/lib/reset.c
>  create mode 100644 arch/loongarch/lib/setjmp.S
>  create mode 100644 board/emulation/qemu-loongarch/Kconfig
>  create mode 100644 board/emulation/qemu-loongarch/MAINTAINERS
>  create mode 100644 board/emulation/qemu-loongarch/Makefile
>  create mode 100644 board/emulation/qemu-loongarch/qemu-loongarch.c
>  create mode 100644 board/emulation/qemu-loongarch/qemu-loongarch.env
>  create mode 100644 configs/qemu-loongarch64_defconfig
>  create mode 100644 drivers/cpu/loongarch_cpu.c
>  create mode 100644 drivers/timer/loongarch_timer.c
>  create mode 100644 include/configs/qemu-loongarch.h
>
>
> base-commit: 0d8e33717d7e5b2a4034cc88f18bf233f77801e7
> -- 
> 2.54.0

-- 
- Jiaxun

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v2 03/16] image: Take entry point as an output of setup_booti
  2026-07-01 11:17 ` [PATCH v2 03/16] image: Take entry point as an output of setup_booti Yao Zi
@ 2026-07-01 17:39   ` Tom Rini
  2026-07-02 20:39     ` Yao Zi
  2026-07-02  9:46   ` Simon Glass
  1 sibling, 1 reply; 56+ messages in thread
From: Tom Rini @ 2026-07-01 17:39 UTC (permalink / raw)
  To: Yao Zi; +Cc: Jiaxun Yang, Heinrich Schuchardt, Ilias Apalodimas, u-boot

[-- Attachment #1: Type: text/plain, Size: 656 bytes --]

On Wed, Jul 01, 2026 at 11:17:55AM +0000, Yao Zi wrote:

> From: Jiaxun Yang <jiaxun.yang@flygoat.com>
> 
> For LoongArch the start of the image is not the entry
> point to the image.
> 
> We refactor the code base to allow entry point to be
> supplied by setup_booti.
> 
> Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
> Signed-off-by: Yao Zi <me@ziyao.cc>
> ---
> 
> Changed from v1
> - Correct type of "entry" argument for RISC-V and sandbox

Can you please also provide a link to
https://www.kernel.org/doc/html/latest/arch/loongarch/booting.html which
probably should cover this, but I'm not entirely sure does?

-- 
Tom

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v2 06/16] LoongArch: skeleton and headers
  2026-07-01 11:17 ` [PATCH v2 06/16] LoongArch: skeleton and headers Yao Zi
@ 2026-07-01 17:47   ` Tom Rini
  2026-07-02 20:40     ` Yao Zi
  2026-07-02 10:28   ` Simon Glass
  1 sibling, 1 reply; 56+ messages in thread
From: Tom Rini @ 2026-07-01 17:47 UTC (permalink / raw)
  To: Yao Zi; +Cc: Jiaxun Yang, Heinrich Schuchardt, Ilias Apalodimas, u-boot

[-- Attachment #1: Type: text/plain, Size: 894 bytes --]

On Wed, Jul 01, 2026 at 11:17:58AM +0000, Yao Zi wrote:

> From: Jiaxun Yang <jiaxun.yang@flygoat.com>
> 
> Commit for directories, Kconfig, Makefile and headers
> 
> Some of them are copied from linux, some of them are derived
> from other architectures, the rest are wriiten on my own.
> 
> Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
> Signed-off-by: Yao Zi <me@ziyao.cc>
> ---
> 
> Hi Heinrich,
> 
> I kept the naming of CONFIG_ARCH_LA64 (instead of using the full name
> ARCH_LOONGARCH64) since it's shorter, and we already have similar
> CONFIG_ARCH_RV64I, and etc. in U-Boot. Is is okay for you?

We should use CONFIG_LOONGARCH here, to mirror the kernel I think. The
CONFIG_ARCH_ namespace in U-Boot maps more to the usage of CONFIG_ARCH_
in the kernel, for ARM (and ARM64) platforms rather than describing a
CPU level architectural feature.

-- 
Tom

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v2 07/16] LoongArch: lib: General routines
  2026-07-01 11:17 ` [PATCH v2 07/16] LoongArch: lib: General routines Yao Zi
@ 2026-07-01 17:49   ` Tom Rini
  2026-07-02  9:24     ` Jiaxun Yang
  2026-07-02 10:28   ` Simon Glass
  1 sibling, 1 reply; 56+ messages in thread
From: Tom Rini @ 2026-07-01 17:49 UTC (permalink / raw)
  To: Yao Zi; +Cc: Jiaxun Yang, Heinrich Schuchardt, Ilias Apalodimas, u-boot

[-- Attachment #1: Type: text/plain, Size: 768 bytes --]

On Wed, Jul 01, 2026 at 11:17:59AM +0000, Yao Zi wrote:

> From: Jiaxun Yang <jiaxun.yang@flygoat.com>
> 
> Add some common library routines for the architecture.
> 
> Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
> Signed-off-by: Yao Zi <me@ziyao.cc>
[snip]
> +#define CACHE_MAX_LEVEL		3
> +#define CACHE_MAX_INDEX		6
> +#define CACHE_OP		GENMASK(4, 3)
> +#define  CACHE_INDEX_INVWB	0x1
> +#define  CACHE_HIT_INVWB	0x2
> +#define CACHE_INDEX		GENMASK(2, 0)

I was expecting checkpatch.pl to catch the double space here, but it
didn't. It did warn about a few other things in macros, which should be
checked out at least. And that comment applies for the whole series,
along with a manual check for other spacing issues, thanks!

-- 
Tom

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v2 10/16] LoongArch: Boot Image bits
  2026-07-01 11:18 ` [PATCH v2 10/16] LoongArch: Boot Image bits Yao Zi
@ 2026-07-01 17:53   ` Tom Rini
  2026-07-02 10:26   ` Simon Glass
  1 sibling, 0 replies; 56+ messages in thread
From: Tom Rini @ 2026-07-01 17:53 UTC (permalink / raw)
  To: Yao Zi; +Cc: Jiaxun Yang, Heinrich Schuchardt, Ilias Apalodimas, u-boot

[-- Attachment #1: Type: text/plain, Size: 2415 bytes --]

On Wed, Jul 01, 2026 at 11:18:02AM +0000, Yao Zi wrote:

> From: Jiaxun Yang <jiaxun.yang@flygoat.com>
> 
> Implement loading and booting functions for LoongArch
> standard kernel image as per spec.
> 
> LoongArch kernel do expect us to fake a efi systemtable
> for passing fdt to kernel, we don't need to implement any
> EFI functions for kernel because it won't look into anything
> beside devicetree from that table if we tell kernel we are
> not efi compatible by setting a0 boot argument to zero.
> 
> Link: https://docs.kernel.org/arch/loongarch/booting.html
> Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
> Signed-off-by: Yao Zi <me@ziyao.cc>
> ---
> 
> Changed from v1
> - Remove now unused arch_lmb_reserve()
> 
>  arch/loongarch/lib/Makefile |   2 +
>  arch/loongarch/lib/bootm.c  | 163 ++++++++++++++++++++++++++++++++++++
>  arch/loongarch/lib/image.c  |  66 +++++++++++++++
>  cmd/Kconfig                 |   2 +-
>  4 files changed, 232 insertions(+), 1 deletion(-)
>  create mode 100644 arch/loongarch/lib/bootm.c
>  create mode 100644 arch/loongarch/lib/image.c
> 
> diff --git a/arch/loongarch/lib/Makefile b/arch/loongarch/lib/Makefile
> index 3c17b9cd85af..e65e66357a9b 100644
> --- a/arch/loongarch/lib/Makefile
> +++ b/arch/loongarch/lib/Makefile
> @@ -3,6 +3,8 @@
>  # Copyright (C) 2024 Jiaxun yang <jiaxun.yang@flygoat.com>
>  #
>  
> +obj-$(CONFIG_CMD_BOOTM) += bootm.o
> +obj-$(CONFIG_CMD_BOOTI) += bootm.o image.o

We have LIB_BOOT[MI] symbols now, which should be used here instead.

[snip]
> +/**
> + * announce_and_cleanup() - Print message and prepare for kernel boot
> + *
> + * @fake: non-zero to do everything except actually boot
> + */
> +static void announce_and_cleanup(int fake)
> +{
> +	printf("\nStarting kernel ...%s\n\n", fake ?
> +		"(fake run for tracing)" : "");
> +	bootstage_mark_name(BOOTSTAGE_ID_BOOTM_HANDOFF, "start_kernel");
> +#if CONFIG_IS_ENABLED(BOOTSTAGE_FDT)
> +	bootstage_fdt_add_report();
> +#endif
> +#if CONFIG_IS_ENABLED(BOOTSTAGE_REPORT)
> +	bootstage_report();
> +#endif
> +
> +#if CONFIG_IS_ENABLED(USB_DEVICE)
> +	udc_disconnect();
> +#endif

We don't have USB_DEVICE anymore, so I think you should look at the git
changes to arm and riscv for example to these functions, since the
loongarch port was done, to catch up on current best practices here.
Thanks.

-- 
Tom

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v2 11/16] LoongArch: Generic CPU type
  2026-07-01 11:18 ` [PATCH v2 11/16] LoongArch: Generic CPU type Yao Zi
@ 2026-07-01 17:55   ` Tom Rini
  2026-07-02 10:26   ` Simon Glass
  1 sibling, 0 replies; 56+ messages in thread
From: Tom Rini @ 2026-07-01 17:55 UTC (permalink / raw)
  To: Yao Zi; +Cc: Jiaxun Yang, Heinrich Schuchardt, Ilias Apalodimas, u-boot

[-- Attachment #1: Type: text/plain, Size: 1920 bytes --]

On Wed, Jul 01, 2026 at 11:18:03AM +0000, Yao Zi wrote:
> From: Jiaxun Yang <jiaxun.yang@flygoat.com>
> 
> Provide a generic CPU type with some common routines
> that expected to be implemented at CPU level.
> 
> Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
> Signed-off-by: Yao Zi <me@ziyao.cc>
> ---
> 
> (No changes from v1)
> 
>  arch/loongarch/Kconfig              |  1 +
>  arch/loongarch/cpu/generic/Kconfig  | 13 +++++++++++++
>  arch/loongarch/cpu/generic/Makefile |  7 +++++++
>  arch/loongarch/cpu/generic/cpu.c    | 22 ++++++++++++++++++++++
>  arch/loongarch/cpu/generic/dram.c   | 21 +++++++++++++++++++++
>  5 files changed, 64 insertions(+)
>  create mode 100644 arch/loongarch/cpu/generic/Kconfig
>  create mode 100644 arch/loongarch/cpu/generic/Makefile
>  create mode 100644 arch/loongarch/cpu/generic/cpu.c
>  create mode 100644 arch/loongarch/cpu/generic/dram.c
> 
> diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig
> index 109d37d8e2c7..5254afb2cd05 100644
> --- a/arch/loongarch/Kconfig
> +++ b/arch/loongarch/Kconfig
> @@ -12,6 +12,7 @@ endchoice
>  # board-specific options below
>  
>  # platform-specific options below
> +source "arch/loongarch/cpu/generic/Kconfig"
>  
>  # architecture-specific options below
>  choice
> diff --git a/arch/loongarch/cpu/generic/Kconfig b/arch/loongarch/cpu/generic/Kconfig
> new file mode 100644
> index 000000000000..ac7556d6d4d0
> --- /dev/null
> +++ b/arch/loongarch/cpu/generic/Kconfig
> @@ -0,0 +1,13 @@
> +# SPDX-License-Identifier: GPL-2.0+
> +#
> +# Copyright (C) 2024 Jiaxun yang <jiaxun.yang@flygoat.com>
> +#
> +
> +config GENERIC_LOONGARCH
> +	bool
> +	select SYS_CACHE_SHIFT_6
> +	imply CPU
> +	imply CPU_LOONGARCH
> +	imply LOONGARCH_TIMER
> +	imply CMD_CPU

Which of these "imply" values can ever really be turned off? CMD_CPU?
Yes, others, I don't know.

-- 
Tom

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v2 00/16] LoongArch initial support
  2026-07-01 11:17 [PATCH v2 00/16] LoongArch initial support Yao Zi
                   ` (16 preceding siblings ...)
  2026-07-01 15:53 ` [PATCH v2 00/16] LoongArch initial support Jiaxun Yang
@ 2026-07-01 17:59 ` Tom Rini
  2026-07-02 10:31 ` [v2,00/16] " Simon Glass
  18 siblings, 0 replies; 56+ messages in thread
From: Tom Rini @ 2026-07-01 17:59 UTC (permalink / raw)
  To: Yao Zi; +Cc: Jiaxun Yang, Heinrich Schuchardt, Ilias Apalodimas, u-boot

[-- Attachment #1: Type: text/plain, Size: 2244 bytes --]

On Wed, Jul 01, 2026 at 11:17:52AM +0000, Yao Zi wrote:

> Hi all,
> 
> After talking to Jiaxun privately, I decided to take over the series.
> 
> So far this series has implemented general support for initializing CPU,
> exceptions, kernel booting, CPU and timer drivers, QEMU LoongArch virt
> machine support and UEFI standard compliant EFI booting support.
> 
> LoongArch had defined 3 ISA variants, LA64, LA32 and LA32R (Reduced,
> intended for MCUs and education purpose). This is a little-endian only
> architecture. Only LA64 is implemented in this series since the hardware
> is more widely available, and I'll work on 32bit support later.
> 
> This series had passed checkpatch with exceptions on some false alarms
> and headers imported elsewhere. I've tested virtio devices, direct
> kernel booting, efistub kernel booting and grub. For loongarch64 CI, I
> would continue to work on Jiaxun's another series[1] soon.
> 
> Toolchain can be found at [2] or using upstream one, to build
> 
> 	make qemu-loongarch64_defconfig
> 	make
> 
> To run in QEMU:
> 
> 	qemu-system-loongarch64 -nographic -machine virt -bios u-boot.bin

So on this note, we need to also have changes for:
- buildman to fetch the toolchain, which is easy since it's part of the
  normal kernel.org ones.
- tools/docker/Dockerfile to fetch the toolchain, for CI
- Changes to .gitlab-ci.yml and .azure-pipelines.yml to build loongarch
- Changes to those files to also fire off QEMU for loonarch
- Changes to https://source.denx.de/u-boot/u-boot-test-hooks to support
  the previous requirement.

> 
> TODOs on the architecture & board:
> - loongson,ls7a-rtc driver
>  - The only device on QEMU board haven't been supported yet
> - LoongArch sandbox host support
> - TLB enablement
>  - This is required for real CPU to utilize caches
> - Possibly EFI-APP support for real machine
> 
> I have one question regarding the process: I've decided to
> coordinate with Jiaxun to maintain the loongarch port, and AFAIK we
> would need a custodian tree on U-Boot's GitLab instance in order to run
> CI. If this true, what's the process of creating a tree?

I can work with you both off-list to get one created.

-- 
Tom

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v2 07/16] LoongArch: lib: General routines
  2026-07-01 17:49   ` Tom Rini
@ 2026-07-02  9:24     ` Jiaxun Yang
  2026-07-02 10:54       ` Simon Glass
  2026-07-02 14:07       ` Tom Rini
  0 siblings, 2 replies; 56+ messages in thread
From: Jiaxun Yang @ 2026-07-02  9:24 UTC (permalink / raw)
  To: Tom Rini, Yao Zi; +Cc: Heinrich Schuchardt, Ilias Apalodimas, u-boot



On Wed, 1 Jul 2026, at 6:49 PM, Tom Rini wrote:
> On Wed, Jul 01, 2026 at 11:17:59AM +0000, Yao Zi wrote:
>
>> From: Jiaxun Yang <jiaxun.yang@flygoat.com>
>> 
>> Add some common library routines for the architecture.
>> 
>> Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
>> Signed-off-by: Yao Zi <me@ziyao.cc>
> [snip]
>> +#define CACHE_MAX_LEVEL		3
>> +#define CACHE_MAX_INDEX		6
>> +#define CACHE_OP		GENMASK(4, 3)
>> +#define  CACHE_INDEX_INVWB	0x1
>> +#define  CACHE_HIT_INVWB	0x2
>> +#define CACHE_INDEX		GENMASK(2, 0)
>
> I was expecting checkpatch.pl to catch the double space here, but it
> didn't. It did warn about a few other things in macros, which should be
> checked out at least. And that comment applies for the whole series,
> along with a manual check for other spacing issues, thanks!

Those style issues are mostly copied over Linux kernel counterparts, should
we leave them as is to ease kernel rebasing effort, or fix them for consistency
with rest of the U-Boot?

Thanks

>
> -- 
> Tom
>
> Attachments:
> * signature.asc

-- 
- Jiaxun

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v2 05/16] image: Define IH_ARCH_LOONGARCH
  2026-07-01 11:17 ` [PATCH v2 05/16] image: Define IH_ARCH_LOONGARCH Yao Zi
@ 2026-07-02  9:44   ` Simon Glass
  0 siblings, 0 replies; 56+ messages in thread
From: Simon Glass @ 2026-07-02  9:44 UTC (permalink / raw)
  To: me; +Cc: Tom Rini, Jiaxun Yang, Heinrich Schuchardt, Ilias Apalodimas,
	u-boot

On 2026-07-01T11:17:53, Yao Zi <me@ziyao.cc> wrote:
> image: Define IH_ARCH_LOONGARCH
>
> Allocate the next value to IH_ARCH_LOONGARCH.
>
> Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
> Reviewed-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
> Signed-off-by: Yao Zi <me@ziyao.cc>
>
> boot/image.c    | 1 +
>  include/image.h | 1 +
>  2 files changed, 2 insertions(+)

Reviewed-by: Simon Glass <sjg@chromium.org>

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v2 03/16] image: Take entry point as an output of setup_booti
  2026-07-01 11:17 ` [PATCH v2 03/16] image: Take entry point as an output of setup_booti Yao Zi
  2026-07-01 17:39   ` Tom Rini
@ 2026-07-02  9:46   ` Simon Glass
  1 sibling, 0 replies; 56+ messages in thread
From: Simon Glass @ 2026-07-02  9:46 UTC (permalink / raw)
  To: me; +Cc: Tom Rini, Jiaxun Yang, Heinrich Schuchardt, Ilias Apalodimas,
	u-boot

Hi Yao,

On 2026-07-01T11:17:53, Yao Zi <me@ziyao.cc> wrote:
> image: Take entry point as an output of setup_booti

The function is called booti_setup(), not setup_booti - please fix the subject.

>
> For LoongArch the start of the image is not the entry
> point to the image.
>
> We refactor the code base to allow entry point to be
> supplied by setup_booti.

Use imperative mode:

Refactor the code base to allow...

>
> Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
> Signed-off-by: Yao Zi <me@ziyao.cc>
>
> arch/arm/lib/image.c     | 3 ++-
>  arch/riscv/lib/image.c   | 4 +++-
>  arch/sandbox/lib/bootm.c | 2 +-
>  boot/bootm.c             | 5 +++--
>  cmd/booti.c              | 5 +++--
>  common/spl/spl.c         | 9 +++++----
>  include/image.h          | 3 ++-
>  7 files changed, 19 insertions(+), 12 deletions(-)

> diff --git a/include/image.h b/include/image.h
> @@ -1131,11 +1131,12 @@ int bootz_setup(ulong image, ulong *start, ulong *end);
>   * @image: Address of image
>   * @start: Returns start address of image
>   * @size : Returns size image
> + * @entry: Returns entry point of image
>   * @force_reloc: Ignore image->ep field, always place image to RAM start
>   * Return: 0 if OK, 1 if the image was not recognised
>   */
>  int booti_setup(ulong image, ulong *relocated_addr, ulong *size,
> -             bool force_reloc);
> +             ulong *entry, bool force_reloc);

While you are here, please fix the @start: tag to match the actual
parameter name (relocated_addr), and drop 'aarch64' from the
description above since this now covers arm64, RISC-V and LoongArch.

Regards,
Simon

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v2 02/16] linux/io.h: Use map_physmem to implement ioremap
  2026-07-01 11:17 ` [PATCH v2 02/16] linux/io.h: Use map_physmem to implement ioremap Yao Zi
@ 2026-07-02 10:21   ` Simon Glass
  0 siblings, 0 replies; 56+ messages in thread
From: Simon Glass @ 2026-07-02 10:21 UTC (permalink / raw)
  To: me; +Cc: Tom Rini, Jiaxun Yang, Heinrich Schuchardt, Ilias Apalodimas,
	u-boot

Hi Jiaxun,

On 2026-07-01T11:17:53, Yao Zi <me@ziyao.cc> wrote:
> linux/io.h: Use map_physmem to implement ioremap
>
> ioremap API is here to be compatible with Linux drivers,
> to maintain compatibility we need to ensure we are using
> the same way to determine virtual address for IO devices
> from physical address.
>
> map_physmem is U-Boot's standard way for doing the trick,
> we should follow that. For architectures VA == PA it has
> no impact, for MIPS it has it's own ioremap implementation
> in asm/io.h anyway.
>
> Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
> Signed-off-by: Yao Zi <me@ziyao.cc>
>
> include/linux/io.h | 3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)

> diff --git a/include/linux/io.h b/include/linux/io.h
> @@ -59,11 +59,12 @@ static inline void iowrite64(u64 value, volatile void __iomem *addr)
>  static inline void __iomem *ioremap(resource_size_t offset,
>                                   resource_size_t size)
>  {
> -     return (void __iomem *)(unsigned long)offset;
> +     return (void __iomem *)map_physmem(offset, size, MAP_NOCACHE);
>  }

This affects sandbox, but should be fine.

Reviewed-by: Simon Glass <sjg@chromium.org>

Regards,
Simon

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v2 01/16] lib: fdtdec: Handle multiple memory nodes
  2026-07-01 11:17 ` [PATCH v2 01/16] lib: fdtdec: Handle multiple memory nodes Yao Zi
@ 2026-07-02 10:22   ` Simon Glass
  2026-07-02 20:39     ` Yao Zi
  0 siblings, 1 reply; 56+ messages in thread
From: Simon Glass @ 2026-07-02 10:22 UTC (permalink / raw)
  To: me; +Cc: Tom Rini, Jiaxun Yang, Heinrich Schuchardt, Ilias Apalodimas,
	u-boot

Hi Jiaxun,

On 2026-07-01T11:17:53, Yao Zi <me@ziyao.cc> wrote:
> lib: fdtdec: Handle multiple memory nodes
>
> Current code only tries to fetch the first memory node found in
> fdt tree and determine memory banks from multiple reg properties.
>
> Specification allows multiple memory nodes in devicetree, rework
> fdtdec_setup_mem_size_base_lowest and fdtdec_setup_memory_banksize
> to iterate over all memory nodes.
>
> Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
> Signed-off-by: Yao Zi <me@ziyao.cc>
>
> include/asm-generic/global_data.h |   2 +-
>  lib/fdtdec.c                      | 129 ++++++++++++++++++++++----------------
>  2 files changed, 76 insertions(+), 55 deletions(-)

> diff --git a/lib/fdtdec.c b/lib/fdtdec.c
> @@ -1115,90 +1116,110 @@ ofnode fdtdec_get_next_memory_node(ofnode mem)
> +too_may_memory_banks:
> +     log_warning("%s: Too many memory banks\n", __func__);
> +     return -EINVAL;
> +}

Typo - too_may_memory_banks should be too_many_memory_banks. While
you are here, please drop the goto... bank is bounded, so a single
check after the loops (or bank < CONFIG_NR_DRAM_BANKS in the inner
while) gives a single return path.

> diff --git a/lib/fdtdec.c b/lib/fdtdec.c
> @@ -1115,90 +1116,110 @@ ofnode fdtdec_get_next_memory_node(ofnode mem)
> +                     log_debug("%s: DRAM Bank #%d %s.%d: start = 0x%llx, size = 0x%llx\n",
> +                               __func__, bank, ofnode_get_name(mem), reg,
> +                              (unsigned long long)gd->dram[bank].start,
> +                              (unsigned long long)gd->dram[bank].size);

The current code uses %pap with &gd->dram[bank].start, which is the
idiomatic way to print phys_addr_t/phys_size_t iand should avoid
needing casts. Can you keep %pap here (and in the message below)?

> diff --git a/lib/fdtdec.c b/lib/fdtdec.c
> @@ -1115,90 +1116,110 @@ ofnode fdtdec_get_next_memory_node(ofnode mem)
> +     while (true) {
> +             struct resource res;
> +             phys_size_t base, size;
> +             int reg = 0;

You should really use phys_addr_t for base

Regards,
Simon

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v2 04/16] elf: Define LoongArch bits
  2026-07-01 11:17 ` [PATCH v2 04/16] elf: Define LoongArch bits Yao Zi
@ 2026-07-02 10:24   ` Simon Glass
  0 siblings, 0 replies; 56+ messages in thread
From: Simon Glass @ 2026-07-02 10:24 UTC (permalink / raw)
  To: me; +Cc: Tom Rini, Jiaxun Yang, Heinrich Schuchardt, Ilias Apalodimas,
	u-boot

Hi Yao,

On 2026-07-01T11:17:53, Yao Zi <me@ziyao.cc> wrote:
> elf: Define LoongArch bits
>
> They all come from glibc's elf.h
>
> Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
> Reviewed-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
> Signed-off-by: Yao Zi <me@ziyao.cc>
>
> include/elf.h | 9 ++++++++-
>  1 file changed, 8 insertions(+), 1 deletion(-)

Reviewed-by: Simon Glass <sjg@chromium.org>

> diff --git a/include/elf.h b/include/elf.h
> @@ -225,7 +225,8 @@ typedef struct {
> -#define EM_NUM               92              /* number of machine types */
> +#define EM_LOONGARCH 258     /* LoongArch */
> +
>
>  /* Version */

Two blank lines are left between the new define and the /* Version */
comment. Please drop one.

Regards,
Simon

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v2 08/16] LoongArch: CPU assembly routines
  2026-07-01 11:18 ` [PATCH v2 08/16] LoongArch: CPU assembly routines Yao Zi
@ 2026-07-02 10:25   ` Simon Glass
  2026-07-03 20:12     ` Yao Zi
  0 siblings, 1 reply; 56+ messages in thread
From: Simon Glass @ 2026-07-02 10:25 UTC (permalink / raw)
  To: me; +Cc: Tom Rini, Jiaxun Yang, Heinrich Schuchardt, Ilias Apalodimas,
	u-boot

Hi Yao,

On 2026-07-01T11:17:53, Yao Zi <me@ziyao.cc> wrote:
> LoongArch: CPU assembly routines
>
> start.S for initialisation, smp_secondary routine for
> a spin-table like interface for secondary cpus.
>
> Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
> Signed-off-by: Yao Zi <me@ziyao.cc>
>
> 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(+)

> diff --git a/arch/loongarch/cpu/cpu.c b/arch/loongarch/cpu/cpu.c
> @@ -0,0 +1,27 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
> + */

Good to keep that copyright (if that is where the code was derived)
but you could add your own too.

> diff --git a/arch/loongarch/cpu/cpu.c b/arch/loongarch/cpu/cpu.c
> @@ -0,0 +1,27 @@
> +#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>

Most of these are unused - only printf() and hang() are referenced.
Please prune to the minimum required.

> diff --git a/arch/loongarch/cpu/cpu.c b/arch/loongarch/cpu/cpu.c
> @@ -0,0 +1,27 @@
> +#if !CONFIG_IS_ENABLED(SYSRESET)
> +void reset_cpu(void)
> +{
> +     printf("resetting ...\n");
> +
> +     printf("reset not supported yet\n");
> +     hang();
> +}
> +#endif

Printing 'resetting ...' immediately followed by 'reset not supported
yet' is confusing. Please drop the first message.

> diff --git a/arch/loongarch/cpu/start.S b/arch/loongarch/cpu/start.S
> @@ -0,0 +1,170 @@
> +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 */

The comment is misleading - t1 holds a single stack's size, not the
combined size of all CPU stacks. Please match arch/riscv/cpu/start.S
('top of stack of first CPU').

> diff --git a/arch/loongarch/cpu/start.S b/arch/loongarch/cpu/start.S
> @@ -0,0 +1,170 @@
> +     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

s0 is never assigned before this point, so if board_init_f() ever
returned here sp would be zero. Today this is dead code because
jump_to_copy() reaches relocate_code() via a normal C call, but the
instruction is misleading. Please remove it, or if you intend to
mirror the RISC-V flow, add the missing 'move s0, a0' after
board_init_f_alloc_reserve() and a comment explaining what s0 holds.

> diff --git a/arch/loongarch/cpu/start.S b/arch/loongarch/cpu/start.S
> @@ -0,0 +1,170 @@
> +     csrrd           t0, LOONGARCH_CSR_CPUID
> +     andi            t0, t0, CSR_CPUID_COREID
> +     LONG_LI         t1, BOOTCORE_ID
> +     bne                     t1, t0, secondary_core_loop

Stray extra tab after bne

> diff --git a/arch/loongarch/cpu/smp_secondary.S b/arch/loongarch/cpu/smp_secondary.S
> @@ -0,0 +1,55 @@
> +1:
> +     /* Query spin table */
> +     idle 0
> +     nop
> +     iocsrrd.w       t0, t1
> +     beqz            t0, 1b

Is the nop after idle 0 required by the ISA (to guarantee the
wake-up completes before the load) or just padding? A
one-line comment would help.

Regards,
Simon

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v2 09/16] LoongArch: Exception handling
  2026-07-01 11:18 ` [PATCH v2 09/16] LoongArch: Exception handling Yao Zi
@ 2026-07-02 10:25   ` Simon Glass
  0 siblings, 0 replies; 56+ messages in thread
From: Simon Glass @ 2026-07-02 10:25 UTC (permalink / raw)
  To: me; +Cc: Tom Rini, Jiaxun Yang, Heinrich Schuchardt, Ilias Apalodimas,
	u-boot

Hi Jiaxun,

On 2026-07-01T11:17:53, Yao Zi <me@ziyao.cc> wrote:
> LoongArch: Exception handling
>
> Add exception entry assembly code, import stackframe.h
> from Linux, provide debug prints when exception happens.
>
> Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
> Signed-off-by: Yao Zi <me@ziyao.cc>
>
> arch/loongarch/Kconfig                  |   3 +
>  arch/loongarch/cpu/Makefile             |   2 +-
>  arch/loongarch/cpu/genex.S              |  21 ++++
>  arch/loongarch/include/asm/stackframe.h | 175 +++++++++++++++++++++++++++++
>  arch/loongarch/lib/interrupts.c         | 189 ++++++++++++++++++++++++++++++++
>  5 files changed, 389 insertions(+), 1 deletion(-)

> diff --git a/arch/loongarch/lib/interrupts.c b/arch/loongarch/lib/interrupts.c
> @@ -0,0 +1,189 @@
> +static void show_regs(struct pt_regs *regs)
> +{
> +#if IS_ENABLED(CONFIG_SHOW_REGS)
> +     const int field = 2 * sizeof(unsigned long);

Please use 'if (CONFIG_IS_ENABLED(SHOW_REGS))' at the call site (as
you do for FRAMEPOINTER below) rather than wrapping the function
body in #if - that also lets you honour SPL_SHOW_REGS.

> diff --git a/arch/loongarch/lib/interrupts.c b/arch/loongarch/lib/interrupts.c
> @@ -0,0 +1,189 @@
> +static void __maybe_unused show_backtrace(struct pt_regs *regs)
> +{
> +     uintptr_t *fp = (uintptr_t *)regs->regs[0x16];

Magic 0x16 (= 22 = fp) is hard to read. Please use a named constant,
or add an fp accessor / use the regdef indices.

> diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig
> @@ -30,6 +30,9 @@ config DMA_ADDR_T_64BIT
> +config SHOW_REGS
> +     bool "Show registers on unhandled exception"

Missing help text, and please follow the RISC-V pattern: default y
plus a matching SPL_SHOW_REGS entry. Otherwise the default on
LoongArch is to hide all GPRs on a crash, making triage harder.

Regards,
Simon

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v2 10/16] LoongArch: Boot Image bits
  2026-07-01 11:18 ` [PATCH v2 10/16] LoongArch: Boot Image bits Yao Zi
  2026-07-01 17:53   ` Tom Rini
@ 2026-07-02 10:26   ` Simon Glass
  1 sibling, 0 replies; 56+ messages in thread
From: Simon Glass @ 2026-07-02 10:26 UTC (permalink / raw)
  To: me; +Cc: Tom Rini, Jiaxun Yang, Heinrich Schuchardt, Ilias Apalodimas,
	u-boot

Hi Yao,

On 2026-07-01T11:17:53, Yao Zi <me@ziyao.cc> wrote:
> LoongArch: Boot Image bits
>
> Implement loading and booting functions for LoongArch
> standard kernel image as per spec.
>
> LoongArch kernel do expect us to fake a efi systemtable
> for passing fdt to kernel, we don't need to implement any
> EFI functions for kernel because it won't look into anything
> beside devicetree from that table if we tell kernel we are
> not efi compatible by setting a0 boot argument to zero.
>
> Link: https://docs.kernel.org/arch/loongarch/booting.html
> Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
> Signed-off-by: Yao Zi <me@ziyao.cc>
>
> arch/loongarch/lib/Makefile |   2 +
>  arch/loongarch/lib/bootm.c  | 163 ++++++++++++++++++++++++++++++++++++++++++++
>  arch/loongarch/lib/image.c  |  66 ++++++++++++++++++
>  cmd/Kconfig                 |   2 +-
>  4 files changed, 232 insertions(+), 1 deletion(-)

> diff --git a/arch/loongarch/lib/bootm.c b/arch/loongarch/lib/bootm.c
> @@ -0,0 +1,163 @@
> +#include <bootstage.h>
> +#include <bootm.h>
> +#include <command.h>
> +#include <dm.h>
> +#include <efi.h>
> +#include <efi_api.h>
> +#include <fdt_support.h>
> +#include <hang.h>
> +#include <log.h>
> +#include <linux/sizes.h>
> +#include <memalign.h>
> +#include <asm/global_data.h>
> +#include <dm/root.h>
> +#include <image.h>
> +#include <asm/byteorder.h>
> +#include <dm/device.h>
> +#include <dm/root.h>
> +#include <u-boot/zlib.h>

dm/root.h is listed twice - please drop the duplicate, and sort the
block while you are here.

https://docs.u-boot.org/en/latest/develop/codingstyle.html#include-files

> diff --git a/arch/loongarch/lib/bootm.c b/arch/loongarch/lib/bootm.c
> @@ -0,0 +1,163 @@
> +/* LoongArch do expect a EFI style systab */
> +static int generate_systab(struct bootm_headers *images)
> +{
> +     const int nr_cfgtab = 1;
> +     struct bd_info *kbd = images->kbd;
> +     struct efi_system_table *systab;
> +     struct efi_configuration_table *cfgtab;
> +     size_t table_size = sizeof(struct efi_system_table) +
> +                         nr_cfgtab * sizeof(struct efi_configuration_table);
> +
> +     systab = memalign(SZ_64K, table_size);

Please add a comment on why 64K alignment is required.

> diff --git a/arch/loongarch/lib/bootm.c b/arch/loongarch/lib/bootm.c
> @@ -0,0 +1,163 @@
> +static void boot_jump_linux(struct bootm_headers *images, int flag)
> +{
> +     void (*kernel)(ulong efi_boot, char *argc, void *dtb);
> +     int fake = (flag & BOOTM_STATE_OS_FAKE_GO);
> +
> +     kernel = (void (*)(ulong efi_boot, char *argc, void *dtb))images->ep;

The second argument is the kernel command line, not argc - please
rename to cmdline. The third is the fake systab pointer, not a raw
dtb; please rename that too.

> diff --git a/arch/loongarch/lib/bootm.c b/arch/loongarch/lib/bootm.c
> @@ -0,0 +1,163 @@
> +     if (!fake) {
> +             if (CONFIG_IS_ENABLED(OF_LIBFDT) && images->ft_len)
> +                     kernel(0, NULL, (void *)images->kbd->bi_boot_params);
> +     }

Per the LoongArch booting spec, a1 is the kernel command line.
Passing NULL means the bootargs env var never reaches the kernel
via that path - it will only be seen in /chosen/bootargs

So don't you wan to pass images->cmdline_start here?

Also, if OF_LIBFDT is disabled or ft_len is zero we drop through
without jumping *after* announce_and_cleanup() has torn devices
down. Please panic() / hang() in that case rather than silently return.

> diff --git a/arch/loongarch/lib/image.c b/arch/loongarch/lib/image.c
> @@ -0,0 +1,66 @@
> +struct linux_image_h {
> +     uint32_t        code0;                  /* Executable code */
> +     uint32_t        code1;                  /* Executable code */
> +     uint64_t        kernel_entry;   /* Kernel entry point */
> +     uint64_t        image_size;             /* Effective Image size */
> +     uint64_t        load_offset;    /* load offset */
> +     uint64_t        res1;                   /* reserved */
> +     uint64_t        res2;                   /* reserved */
> +     uint64_t        res3;                   /* reserved */
> +     uint32_t        magic;                  /* Magic number */
> +     uint32_t        pe_header;              /* Offset to the PE header */
> +};

Comment tabs after kernel_entry/image_size/load_offset are
inconsistent with the first two members - please tidy so the
comments line up. Also use u32/u64 for consistency with the rest
of U-Boot.

I have to wonder whether it would be OK to share this struct with
RISC-V in a header file?

> diff --git a/arch/loongarch/lib/image.c b/arch/loongarch/lib/image.c
> @@ -0,0 +1,66 @@
> +     /* To workaround kernel supplying DMW based virtual address */
> +     ep_phys = TO_PHYS(lhdr->kernel_entry);
> +     *ep = *relocated_addr + (ep_phys - lhdr->load_offset);

Please expand this comment - from context it looks like kernel_entry
is a DMW virtual address, and you are converting to a physical
offset within the image and re-basing onto the relocated load
address. Spell that out, with a pointer to the relevant paragraph
of the booting spec.

Regards,
Simon

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v2 11/16] LoongArch: Generic CPU type
  2026-07-01 11:18 ` [PATCH v2 11/16] LoongArch: Generic CPU type Yao Zi
  2026-07-01 17:55   ` Tom Rini
@ 2026-07-02 10:26   ` Simon Glass
  1 sibling, 0 replies; 56+ messages in thread
From: Simon Glass @ 2026-07-02 10:26 UTC (permalink / raw)
  To: me; +Cc: Tom Rini, Jiaxun Yang, Heinrich Schuchardt, Ilias Apalodimas,
	u-boot

Hi Yao,

On 2026-07-01T11:17:53, Yao Zi <me@ziyao.cc> wrote:
> LoongArch: Generic CPU type
>
> Provide a generic CPU type with some common routines
> that expected to be implemented at CPU level.
>
> Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
> Signed-off-by: Yao Zi <me@ziyao.cc>
>
> arch/loongarch/Kconfig              |  1 +
>  arch/loongarch/cpu/generic/Kconfig  | 13 +++++++++++++
>  arch/loongarch/cpu/generic/Makefile |  7 +++++++
>  arch/loongarch/cpu/generic/cpu.c    | 22 ++++++++++++++++++++++
>  arch/loongarch/cpu/generic/dram.c   | 21 +++++++++++++++++++++
>  5 files changed, 64 insertions(+)

> LoongArch: Generic CPU type

'generic CPU type' isn't quite right - this adds the 'generic'
platform (common cleanup/DRAM code) rather than a CPU type. Please
reword and fix the grammar of the second sentence ('some common
routines that are expected to be implemented at the CPU level'). A
short note on what falls under this bucket vs. the actual CPU driver
(patch 12) would help.

> diff --git a/arch/loongarch/cpu/generic/cpu.c b/arch/loongarch/cpu/generic/cpu.c
> @@ -0,0 +1,22 @@
> +/*
> + * cleanup_before_linux() is called just before we call linux
> + * it prepares the processor for linux
> + *
> + * we disable interrupt and caches.
> + */
> +int cleanup_before_linux(void)
> +{
> +     disable_interrupts();
> +
> +     cache_flush();
> +
> +     return 0;
> +}

The comment says 'we disable interrupt and caches' but the code
only disables interrupts and flushes the caches. Please fix the
comment to match (or, if disabling the caches was intended, add
that). Also, 'Linux' should be capitalised.

> diff --git a/arch/loongarch/cpu/generic/dram.c b/arch/loongarch/cpu/generic/dram.c
> @@ -0,0 +1,21 @@
> +#include <fdtdec.h>
> +#include <init.h>
> +#include <asm/global_data.h>
> +#include <linux/sizes.h>
> +
> +DECLARE_GLOBAL_DATA_PTR;

Neither gd nor anything from linux/sizes.h or asm/global_data.h is
used here. Please drop the unused includes and DECLARE_GLOBAL_DATA_PTR.
Compare arch/riscv/cpu/generic/dram.c which keeps this to just
fdtdec.h and init.h.

Regards,
Simon

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v2 12/16] cpu: Add loongarch_cpu driver
  2026-07-01 11:18 ` [PATCH v2 12/16] cpu: Add loongarch_cpu driver Yao Zi
@ 2026-07-02 10:26   ` Simon Glass
  0 siblings, 0 replies; 56+ messages in thread
From: Simon Glass @ 2026-07-02 10:26 UTC (permalink / raw)
  To: me; +Cc: Tom Rini, Jiaxun Yang, Heinrich Schuchardt, Ilias Apalodimas,
	u-boot

Hi Jiaxun,

On 2026-07-01T11:17:53, Yao Zi <me@ziyao.cc> wrote:
> cpu: Add loongarch_cpu driver
>
> Implement a driver for LoongArch CPU solely for gathering
> some information bits from FDT and CPU level config registers.
>
> Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
> Signed-off-by: Yao Zi <me@ziyao.cc>
>
> drivers/cpu/Kconfig         |   6 ++
>  drivers/cpu/Makefile        |   1 +
>  drivers/cpu/loongarch_cpu.c | 148 ++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 155 insertions(+)

> diff --git a/drivers/cpu/loongarch_cpu.c b/drivers/cpu/loongarch_cpu.c
> @@ -0,0 +1,148 @@
> +static int loongarch_cpu_get_desc(const struct udevice *dev, char *buf, int size)
> +{
> +     const char *cpu;
> +
> +     /* We try to get CPU name from IOCSR first */
> +     if ((read_cpucfg(LOONGARCH_CPUCFG1) & CPUCFG1_IOCSR)) {
> +             int i;
> +             char vendor_buf[9] = { 0 };
> +             char name_buf[9] = { 0 };
> +             u64 vendor = iocsr_read64(LOONGARCH_IOCSR_VENDOR);
> +             u64 name = iocsr_read64(LOONGARCH_IOCSR_CPUNAME);
> +
> +             if (!vendor || !name)
> +                     goto get_desc_dt;
> +
> +             for (i = 0; i < sizeof(u64); i++) {
> +                     vendor_buf[i] = vendor & 0xff;
> +                     name_buf[i] = name & 0xff;
> +                     vendor >>= 8;
> +                     name >>= 8;
> +             }
> +
> +             snprintf(buf, size, '%s-%s', vendor_buf, name_buf);
> +
> +             return 0;
> +     }
> +
> +get_desc_dt:
> +     cpu = dev_read_string(dev, 'compatible');

Please drop the goto - it jumps out of an if-body to a label at the
same scope. Close the if-body when the IOCSR read is valid and let
the DT path fall through.

Also, snprintf() can silently truncate if size is smaller than the
composed string; please return -ENOSPC in that case, similar to the
DT branch below.

Regards,
Simon

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v2 13/16] timer: Add loongarch_timer driver
  2026-07-01 11:18 ` [PATCH v2 13/16] timer: Add loongarch_timer driver Yao Zi
@ 2026-07-02 10:27   ` Simon Glass
  0 siblings, 0 replies; 56+ messages in thread
From: Simon Glass @ 2026-07-02 10:27 UTC (permalink / raw)
  To: me; +Cc: Tom Rini, Jiaxun Yang, Heinrich Schuchardt, Ilias Apalodimas,
	u-boot

Hi Yao,

On 2026-07-01T11:17:53, Yao Zi <me@ziyao.cc> wrote:
> timer: Add loongarch_timer driver
>
> Implement a timer driver for LoongArch architecture driver.
>
> It's synced in hardware for every core in a system, and frequency
> information can be gathered from CPUCFG instruction.
>
> It is not described in fdt, thus I have to declare a DRVINFO
> for it.
>
> Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
> Signed-off-by: Yao Zi <me@ziyao.cc>
>
> drivers/timer/Kconfig           |   8 +++
>  drivers/timer/Makefile          |   1 +
>  drivers/timer/loongarch_timer.c | 112 ++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 121 insertions(+)

> diff --git a/drivers/timer/loongarch_timer.c b/drivers/timer/loongarch_timer.c
> @@ -0,0 +1,112 @@
> +#include <dm.h>
> +#include <errno.h>
> +#include <timer.h>
> +#include <asm/loongarch.h>

lldiv() is used below but div64.h is not included. Please add it
(see riscv_timer.c).

> diff --git a/drivers/timer/loongarch_timer.c b/drivers/timer/loongarch_timer.c
> @@ -0,0 +1,112 @@
> +static int loongarch_timer_bind(struct udevice *dev)
> +{
> +     struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
> +     u32 rate;
> +
> +     rate = loongarch_timer_get_freq_cpucfg();
> +     uc_priv->clock_rate = rate;
> +
> +     return 0;
> +}

This is wired up as .probe below, so please rename to
loongarch_timer_probe(). Also, if loongarch_timer_get_freq_cpucfg()
returns 0 (LLFTP not present, or CPUCFG5 reads back zero) the driver
still probes with clock_rate=0, which then trips a divide-by-zero
in timer_get_boot_us(). Perhaps return -EINVAL in that case?

> diff --git a/drivers/timer/loongarch_timer.c b/drivers/timer/loongarch_timer.c
> @@ -0,0 +1,112 @@
> +     /* Below is converted from time(us) = (tick / rate) * 10000000 */
> +     return lldiv(ticks * 1000, (rate / 1000));

This comment is copied from riscv_timer.c and has the same typo -
us is 10^6, not 10^7. Worth fixing here (or factoring the helper
out so both architectures share it).

Regards,
Simon

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v2 14/16] board: emulation: Add qemu-loongarch
  2026-07-01 11:18 ` [PATCH v2 14/16] board: emulation: Add qemu-loongarch Yao Zi
@ 2026-07-02 10:27   ` Simon Glass
  0 siblings, 0 replies; 56+ messages in thread
From: Simon Glass @ 2026-07-02 10:27 UTC (permalink / raw)
  To: me; +Cc: Tom Rini, Jiaxun Yang, Heinrich Schuchardt, Ilias Apalodimas,
	u-boot

Hi Yao,

On 2026-07-01T11:17:53, Yao Zi <me@ziyao.cc> wrote:
> board: emulation: Add qemu-loongarch
>
> Yet another generic QEMU VIRT machine.
> QEMU placed FDT in memory before launching U-Boot, so we
> can just obtian FDT here.
>
> Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
> Signed-off-by: Yao Zi <me@ziyao.cc>
>
> arch/loongarch/Kconfig                            |  5 ++
>  arch/loongarch/dts/qemu-loongarch64.dts           |  9 +++
>  board/emulation/qemu-loongarch/Kconfig            | 68 +++++++++++++++++++++++
>  board/emulation/qemu-loongarch/MAINTAINERS        |  7 +++
>  board/emulation/qemu-loongarch/Makefile           |  6 ++
>  board/emulation/qemu-loongarch/qemu-loongarch.c   | 67 ++++++++++++++++++++++
>  board/emulation/qemu-loongarch/qemu-loongarch.env |  6 ++
>  configs/qemu-loongarch64_defconfig                | 36 ++++++++++++
>  include/configs/qemu-loongarch.h                  | 13 +++++
>  9 files changed, 217 insertions(+)

> Yet another generic QEMU VIRT machine.
> QEMU placed FDT in memory before launching U-Boot, so we
> can just obtian FDT here.

Please flesh this out a bit more - how the board is booted,
memory-layout assumptions, the FDT source. Also 'obtian' -> 'obtain'
and use present tense ('QEMU places the FDT ...').

> diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig
> @@ -7,9 +7,14 @@ config SYS_ARCH
>  choice
>       prompt "Target select"
>
> +config TARGET_QEMU_LOONGARCH_VIRT
> +     bool "Support QEMU Virt Board"
> +     select BOARD_LATE_INIT
> +
>  endchoice

Please move this symbol into board/emulation/qemu-loongarch/Kconfig
alongside the other options, so the arch Kconfig only lists the
choice. Also BOARD_LATE_INIT is duplicated as an 'imply' inside
BOARD_SPECIFIC_OPTIONS - pick one.

> diff --git a/board/emulation/qemu-loongarch/qemu-loongarch.c b/board/emulation/qemu-loongarch/qemu-loongarch.c
> @@ -0,0 +1,67 @@
> +phys_addr_t board_get_usable_ram_top(phys_size_t total_size)
> +{
> +     /* Limit RAM used by U-Boot to the DDR low region */
> +     if (gd->ram_top > 0x10000000)
> +             return 0x10000000;
> +
> +     return gd->ram_top;
> +}

Please introduce a named constant for 0x10000000 (something like
SYS_LOWMEM_TOP), and explain in the comment why the low region
matters - TLB/direct-map restriction, or a QEMU quirk?

> diff --git a/board/emulation/qemu-loongarch/qemu-loongarch.c b/board/emulation/qemu-loongarch/qemu-loongarch.c
> @@ -0,0 +1,67 @@
> +int board_init(void)
> +{
> +     return 0;
> +}

If there is nothing to do, please drop in favour of the weak default.

> diff --git a/board/emulation/qemu-loongarch/qemu-loongarch.c b/board/emulation/qemu-loongarch/qemu-loongarch.c
> @@ -0,0 +1,67 @@
> +int board_fdt_blob_setup(void **fdtp)
> +{
> +     /* Stored the DTB address there during our init */
> +     *fdtp = (void *)(ulong)0x100000;
> +     return 0;
> +}

The comment is misleading - U-Boot does not store the DTB anywhere;
QEMU (LoongArchQemuPkg) places it at this address. Please rework
the comment, and use a named constant rather than 0x100000. It
would also be worth an fdt_check_header() before returning success,
so a mis-launch fails cleanly.

> diff --git a/board/emulation/qemu-loongarch/qemu-loongarch.env b/board/emulation/qemu-loongarch/qemu-loongarch.env
> @@ -0,0 +1,6 @@
> +
> +stdin=serial,usbkbd
> +stdout=serial,vidconsole
> +stderr=serial,vidconsole

Drop the leading blank line.

> diff --git a/include/configs/qemu-loongarch.h b/include/configs/qemu-loongarch.h
> @@ -0,0 +1,13 @@
> +/* Those values are chosen by LoongArchQemuPkg */
> +#define CFG_SYS_INIT_RAM_ADDR        0x10000
> +#define CFG_SYS_INIT_RAM_SIZE        0x10000

'These values', not 'Those'. Also, since both the DTB address
(0x100000) and the low-RAM cap (0x10000000) are baked into the C
file, please pull those into this header so the QEMU/edk2 ABI lives
in one place.

Regards,
Simon

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v2 15/16] efi: LoongArch: Define LoongArch bits everywhere
  2026-07-01 11:18 ` [PATCH v2 15/16] efi: LoongArch: Define LoongArch bits everywhere Yao Zi
@ 2026-07-02 10:27   ` Simon Glass
  0 siblings, 0 replies; 56+ messages in thread
From: Simon Glass @ 2026-07-02 10:27 UTC (permalink / raw)
  To: me; +Cc: Tom Rini, Jiaxun Yang, Heinrich Schuchardt, Ilias Apalodimas,
	u-boot

Hi Yao,

On 2026-07-01T11:17:53, Yao Zi <me@ziyao.cc> wrote:
> efi: LoongArch: Define LoongArch bits everywhere
>
> They are all coming from UEFI specification, PE-COFF specification,
> or IANA websites.
>
> Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
> Signed-off-by: Yao Zi <me@ziyao.cc>
>
> include/asm-generic/pe.h                          | 2 ++
>  include/config_distro_bootcmd.h                   | 5 +++++
>  include/pe.h                                      | 1 +
>  lib/efi_loader/efi_helper.c                       | 4 ++++
>  lib/efi_loader/efi_image_loader.c                 | 7 +++++++
>  lib/efi_loader/efi_runtime.c                      | 4 ++++
>  lib/efi_selftest/efi_selftest_miniapp_exception.c | 3 +++
>  7 files changed, 26 insertions(+)

> They are all coming from UEFI specification, PE-COFF specification,
> or IANA websites.

Please expand this to say what is actually added (PE machine types,
relocation type, PXE arch number, BOOTEFI filename, R_LARCH_RELATIVE
runtime reloc, selftest trap instruction) - 'bits everywhere' is
hard to grep for later.

> diff --git a/include/config_distro_bootcmd.h b/include/config_distro_bootcmd.h
> @@ -371,6 +373,9 @@
> +#elif defined(CONFIG_ARCH_LA64) || (defined(__loongarch__) && __loongarch_grlen == 64))

Unbalanced parentheses - one extra ')' at the end.

> diff --git a/lib/efi_selftest/efi_selftest_miniapp_exception.c b/lib/efi_selftest/efi_selftest_miniapp_exception.c
> @@ -35,6 +35,9 @@ efi_status_t EFIAPI efi_main(efi_handle_t handle,
> +#elif defined(CONFIG_LOONGARCH)
> +     /* ud 31 */
> +     asm volatile (".word 0x386007ff\n");

The rest of the series keys off CONFIG_ARCH_LA64. Please pick one
and use it consistently - otherwise a future LA32 build will
trigger this ud but be missing all the other bits. Given Tom's
suggestion on patch 6 to move to CONFIG_LOONGARCH, that is probably
the way to unify it.

> diff --git a/include/pe.h b/include/pe.h
> @@ -194,6 +194,7 @@ typedef struct _IMAGE_RELOCATION
> +#define IMAGE_REL_BASED_LOONGARCH64_MARK_LA  8 /* yes, 8 too */

The PE-COFF spec also defines IMAGE_REL_BASED_LOONGARCH32_MARK_LA
(=8). Since __loongarch_grlen == 32 is handled in efi_image_loader.c
below, it would be tidier to add both here even if only the 64-bit
one is wired up today.

Regards,
Simon

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v2 07/16] LoongArch: lib: General routines
  2026-07-01 11:17 ` [PATCH v2 07/16] LoongArch: lib: General routines Yao Zi
  2026-07-01 17:49   ` Tom Rini
@ 2026-07-02 10:28   ` Simon Glass
  2026-07-02 21:46     ` Yao Zi
  1 sibling, 1 reply; 56+ messages in thread
From: Simon Glass @ 2026-07-02 10:28 UTC (permalink / raw)
  To: me; +Cc: Tom Rini, Jiaxun Yang, Heinrich Schuchardt, Ilias Apalodimas,
	u-boot

Hi Yao,

On 2026-07-01T11:17:53, Yao Zi <me@ziyao.cc> wrote:
> LoongArch: lib: General routines
>
> Add some common library routines for the architecture.
>
> Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
> Signed-off-by: Yao Zi <me@ziyao.cc>
>
> arch/loongarch/include/asm/cache.h       |  10 ++
>  arch/loongarch/include/asm/global_data.h |   7 +
>  arch/loongarch/lib/Makefile              |   7 +
>  arch/loongarch/lib/asm-offsets.c         |  66 ++++++++++
>  arch/loongarch/lib/boot.c                |  14 ++
>  arch/loongarch/lib/cache.c               | 213 +++++++++++++++++++++++++++++++
>  arch/loongarch/lib/reset.c               |  14 ++
>  arch/loongarch/lib/setjmp.S              |  52 ++++++++
>  8 files changed, 383 insertions(+)

> Add some common library routines for the architecture.

Please expand the commit message: list what the routines are
(cache maintenance, setjmp/longjmp, asm-offsets, do_go_exec,
do_reset) and note that cache handling probes the hierarchy via
CPUCFG.

> diff --git a/arch/loongarch/lib/cache.c b/arch/loongarch/lib/cache.c
> @@ -0,0 +1,213 @@
> +static inline void flush_cache_line_index(unsigned int index,
> +                                       unsigned long addr)
> +{
> +#define do_flush(index)                                                      \
> +     case index:                                                     \
> +             cache_op(FIELD_PREP(CACHE_OP, CACHE_INDEX_INVWB) |      \
> +                      FIELD_PREP(CACHE_INDEX, index),                \
> +                      index);                                        \
> +             break;
> +
> +     switch (index) {
> +             do_flush(0);
> +             do_flush(1);
> +             do_flush(2);
> +             do_flush(3);
> +             do_flush(4);
> +             do_flush(5);
> +     }
> +
> +#undef do_flush
> +}

addr is silently dropped. Inside do_flush() the token index
resolves to the macro parameter (0..5, the cache identifier), so
cache_op() always gets the small constant as its address operand.
The way/set offset that flush_dcache_level_all() computes never
reaches the CACOP instruction, so this hammers way 0 / set 0 of
the selected cache repeatedly instead of walking it. Please pass
addr through (rename the macro parameter to avoid the shadow), and
confirm with a real by-index flush test.

> diff --git a/arch/loongarch/lib/cache.c b/arch/loongarch/lib/cache.c
> @@ -0,0 +1,213 @@
> +void probe_caches(void)
> +{
> +     unsigned int level = 0, index = 0;
> +     u32 cfg = read_cpucfg(LOONGARCH_CPUCFG16);
> +
> +     if (cfg & CPUCFG16_L1_IUPRE) {
> +             if (cfg & CPUCFG16_L1_IUUNIFY) {
> +                     gd->arch.dcache_index[level] = index;
> +                     populate_dcache_properties(cfg, level++,
> +                                                LOONGARCH_CPUCFG17);
> +             }
> +
> +             index++;
> +     }
> +
> +     if (cfg & CPUCFG16_L1_DPRE) {
> +             gd->arch.dcache_index[level] = index++;
> +             populate_dcache_properties(cfg, level++, LOONGARCH_CPUCFG18);
> +     }
> +
> +     cfg >>= 3;
> +
> +     for (; level < 3; level++) {

Please use CACHE_MAX_LEVEL rather than the bare 3.
populate_dcache_properties() also sets dcache_inclusive from cfg
whenever level != 0, but on the L1D path cfg is still CPUCFG16 -
the L1 inclusive bit describes L1I vs L1D, not L1D vs L2, so this
looks incorrect. Please double-check.

> diff --git a/arch/loongarch/include/asm/cache.h b/arch/loongarch/include/asm/cache.h
> @@ -15,6 +18,13 @@ void cache_flush(void);
> +#define CACHE_MAX_LEVEL              3
> +#define CACHE_MAX_INDEX              6

A short comment on what these two bounds represent (max dcache
levels tracked vs. max hardware cache-id encoded in CACOP) would
help - they are easy to confuse.

> diff --git a/arch/loongarch/lib/setjmp.S b/arch/loongarch/lib/setjmp.S
> @@ -0,0 +1,52 @@
> +ENTRY(setjmp)
> +     LONG_S          s0, a0, 0
> +     LONG_S          s1, a0, (1 * LONGSIZE)

Stray space after LONG_S here (and in longjmp). Please clean up.

Regards,
Simon

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v2 06/16] LoongArch: skeleton and headers
  2026-07-01 11:17 ` [PATCH v2 06/16] LoongArch: skeleton and headers Yao Zi
  2026-07-01 17:47   ` Tom Rini
@ 2026-07-02 10:28   ` Simon Glass
  2026-07-02 21:22     ` Yao Zi
  1 sibling, 1 reply; 56+ messages in thread
From: Simon Glass @ 2026-07-02 10:28 UTC (permalink / raw)
  To: me; +Cc: Tom Rini, Jiaxun Yang, Heinrich Schuchardt, Ilias Apalodimas,
	u-boot

Hi Jiaxun,

On 2026-07-01T11:17:53, Yao Zi <me@ziyao.cc> wrote:
> LoongArch: skeleton and headers
>
> Commit for directories, Kconfig, Makefile and headers
>
> Some of them are copied from linux, some of them are derived
> from other architectures, the rest are wriiten on my own.
>
> Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
> Signed-off-by: Yao Zi <me@ziyao.cc>

> Some of them are copied from linux, some of them are derived
> from other architectures, the rest are wriiten on my own.

Typo: wriiten -> written. Please also expand this into a proper
motivation paragraph - what LoongArch is, which ISA variant this
covers, and where the imported headers came from.

> diff --git a/arch/loongarch/include/asm/asm.h b/arch/loongarch/include/asm/asm.h
> @@ -0,0 +1,186 @@
> +/*
> + * Size of a register
> + */
> +#if defined(__loongarch__) && __loongarch_grlen == 64
> +#define SZREG        4
> +#else
> +#define SZREG        8
> +#endif

This is inverted - on 64-bit LoongArch a register is 8 bytes, not
4. The result is that REG_L/REG_S resolve to ld.w/st.w on the only
ISA this series supports. Linux seems to use __loongarch64, BTW.

> diff --git a/arch/loongarch/include/asm/system.h b/arch/loongarch/include/asm/system.h
> @@ -0,0 +1,74 @@
> +#define local_irq_save(__flags)                                 \
> +     do {                                                        \
> +             __flags = arch_local_irq_save(CSR_SSTATUS, SR_SIE) & SR_SIE; \
> +     } while (0)

This is leftover RISC-V code - arch_local_irq_save() above takes
no arguments, and CSR_SSTATUS/SR_SIE are not defined for LoongArch.
It compiles today because nothing invokes local_irq_save(), but
will break the moment anyone does. Please rewrite to call the
LoongArch save/restore helpers, matching the enable/disable pattern
above.

> diff --git a/arch/loongarch/include/asm/types.h b/arch/loongarch/include/asm/types.h
> @@ -0,0 +1,37 @@
> +#ifdef __KERNEL__
> +
> +#define BITS_PER_LONG _LOONGARCH_SZLONG

_LOONGARCH_SZLONG is never defined anywhere in the tree, so this
expands to an empty token. Please either define it (e.g. 64 for LA64)
or drop this and rely on asm-generic/bitsperlong.h like other arches.

> diff --git a/arch/loongarch/Makefile b/arch/loongarch/Makefile
> @@ -0,0 +1,19 @@
> +ARCH_FLAGS = -march=loongarch64 -mabi=lp64s -msoft-float

Since LA32 is on the TODO list, please gate this on CONFIG_ARCH_LA64
(or whatever the final symbol is) rather than hard-coding
loongarch64/lp64s.

Regards,
Simon

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v2 16/16] efi: LoongArch: Implement everything
  2026-07-01 11:18 ` [PATCH v2 16/16] efi: LoongArch: Implement everything Yao Zi
@ 2026-07-02 10:29   ` Simon Glass
  0 siblings, 0 replies; 56+ messages in thread
From: Simon Glass @ 2026-07-02 10:29 UTC (permalink / raw)
  To: me; +Cc: Tom Rini, Jiaxun Yang, Heinrich Schuchardt, Ilias Apalodimas,
	u-boot

Hi Yao,

On 2026-07-01T11:17:53, Yao Zi <me@ziyao.cc> wrote:
> efi: LoongArch: Implement everything
>
> Implement crt, reloc, linker scripts, wire things up in
> Makefiles and Kconfig.
>
> Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
> Signed-off-by: Yao Zi <me@ziyao.cc>
>
> arch/loongarch/config.mk                 |   4 +
>  arch/loongarch/lib/Makefile              |  12 ++
>  arch/loongarch/lib/crt0_loongarch_efi.S  | 182 +++++++++++++++++++++++++++++
>  arch/loongarch/lib/elf_loongarch_efi.lds |  76 +++++++++++++
>  arch/loongarch/lib/reloc_loongarch_efi.c | 107 ++++++++++++++++++
>  lib/efi_loader/Kconfig                   |   2 +-
>  lib/efi_loader/efi_helper.c              |   3 +
>  lib/efi_loader/efi_image_loader.c        |  26 +++++
>  8 files changed, 411 insertions(+), 1 deletion(-)

>     efi: LoongArch: Implement everything
>
>     Implement crt, reloc, linker scripts, wire things up in
>     Makefiles and Kconfig.

The subject and body do not really say what this patch does. It
also silently adds handling for a new PE relocation type
(IMAGE_REL_BASED_LOONGARCH64_MARK_LA) in the shared EFI loader,
which is not mentioned. Please expand to describe the LoongArch EFI
application entry sequence, the .reloc stub, the MARK_LA relocation
format being decoded, and why it is needed.

> diff --git a/lib/efi_loader/efi_image_loader.c b/lib/efi_loader/efi_image_loader.c
> @@ -230,6 +232,30 @@ static efi_status_t efi_loader_relocate(const IMAGE_BASE_RELOCATION *rel,
> +#elif defined(__loongarch__) && __loongarch_grlen == 64
> +                     case IMAGE_REL_BASED_LOONGARCH64_MARK_LA:

This is a non-trivial change to shared code and would be much
easier to review as its own patch, with a commit message explaining
the four-instruction pcalau12i/addi/lu32i/lu52i sequence being
patched and citing the PE-COFF spec. Please split it out.

> diff --git a/arch/loongarch/lib/crt0_loongarch_efi.S b/arch/loongarch/lib/crt0_loongarch_efi.S
> @@ -0,0 +1,182 @@
> + * Copright (C) 2024 Jiaxun Yang <jiaxun.yang@flygoat.com>

Typo - Copright -> Copyright (the RISC-V file this was cloned from
has the same typo, but please don't propagate it).

> diff --git a/arch/loongarch/lib/crt0_loongarch_efi.S b/arch/loongarch/lib/crt0_loongarch_efi.S
> @@ -0,0 +1,182 @@
> +     bl              _relocate

...
> +     jr                      ra
> +     .end      _start

The whitespace here (mixed tabs and multiple spaces after the
mnemonic) is inconsistent with the rest of the file - please tidy.

> diff --git a/arch/loongarch/lib/reloc_loongarch_efi.c b/arch/loongarch/lib/reloc_loongarch_efi.c
> @@ -0,0 +1,107 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/* reloc_loongarch.c - position independent ELF shared object relocator
> +   Copyright (C) 2018 Alexander Graf <agraf@suse.de>

...
> +    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND

The SPDX tag says GPL-2.0+ but the pasted licence block is
BSD-2-Clause from the RISC-V/ARM copies. Please either drop the BSD
text (relying on SPDX) or reconcile the two — as-is the file is
self-contradictory. Also the filename in the first line still reads
reloc_loongarch.c.

> diff --git a/arch/loongarch/lib/reloc_loongarch_efi.c b/arch/loongarch/lib/reloc_loongarch_efi.c
> @@ -0,0 +1,107 @@
> +             case DT_PLTGOT:
> +                     addr = (unsigned long *)
> +                             ((unsigned long)dyn[i].d_un.d_ptr
> +                                     + ldbase);
> +                     break;

The value written to addr here is never read before being
overwritten in the loop below. Dead code inherited from the RISC-V
copy - please drop the DT_PLTGOT case.

> diff --git a/arch/loongarch/lib/Makefile b/arch/loongarch/lib/Makefile
> @@ -12,3 +12,15 @@ ifeq ($(CONFIG_$(SPL_)SYSRESET),)
> +extra-$(CONFIG_CMD_BOOTEFI_HELLO_COMPILE) += $(EFI_CRT0) $(EFI_RELOC)
> +extra-$(CONFIG_CMD_BOOTEFI_SELFTEST) += $(EFI_CRT0) $(EFI_RELOC)
> +extra-$(CONFIG_EFI) += $(EFI_CRT0) $(EFI_RELOC)

Have you built and run the EFI selftest and the hello app on
qemu-loongarch64? The cover letter mentions efistub kernel and grub
but not these. If not, please drop the two lines that pull them in
until they have been exercised, or note in the commit message that
they build but are untested.

Regards,
Simon

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [v2,00/16] LoongArch initial support
  2026-07-01 11:17 [PATCH v2 00/16] LoongArch initial support Yao Zi
                   ` (17 preceding siblings ...)
  2026-07-01 17:59 ` Tom Rini
@ 2026-07-02 10:31 ` Simon Glass
  18 siblings, 0 replies; 56+ messages in thread
From: Simon Glass @ 2026-07-02 10:31 UTC (permalink / raw)
  To: me; +Cc: u-boot

Hi Yao,

On 2026-07-01T11:17:53, Yao Zi <me@ziyao.cc> wrote:

> So far this series has implemented general support for initializing CPU,
> exceptions, kernel booting, CPU and timer drivers, QEMU LoongArch virt
> machine support and UEFI standard compliant EFI booting support.

Thanks for picking this up. The split between generic and arch-specific
changes makes review much easier.

I think Tom mentions this but please add doc/arch/loongarch.rst and
doc/board/emulation/qemu-loongarch.rst

> board/emulation/qemu-loongarch/MAINTAINERS

The board has its own MAINTAINERS stanza but there is no top-level
entry for arch/loongarch/. Please add one covering arch/loongarch/,
drivers/cpu/loongarch_cpu.c and drivers/timer/loongarch_timer.c

Regards,
Simon

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v2 07/16] LoongArch: lib: General routines
  2026-07-02  9:24     ` Jiaxun Yang
@ 2026-07-02 10:54       ` Simon Glass
  2026-07-02 14:07       ` Tom Rini
  1 sibling, 0 replies; 56+ messages in thread
From: Simon Glass @ 2026-07-02 10:54 UTC (permalink / raw)
  To: Jiaxun Yang
  Cc: Tom Rini, Yao Zi, Heinrich Schuchardt, Ilias Apalodimas,
	U-Boot Mailing List

Hi Jiaxun,

On Thu, 2 Jul 2026, 10:24 Jiaxun Yang, <jiaxun.yang@flygoat.com> wrote:
>
>
>
> On Wed, 1 Jul 2026, at 6:49 PM, Tom Rini wrote:
> > On Wed, Jul 01, 2026 at 11:17:59AM +0000, Yao Zi wrote:
> >
> >> From: Jiaxun Yang <jiaxun.yang@flygoat.com>
> >>
> >> Add some common library routines for the architecture.
> >>
> >> Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
> >> Signed-off-by: Yao Zi <me@ziyao.cc>
> > [snip]
> >> +#define CACHE_MAX_LEVEL             3
> >> +#define CACHE_MAX_INDEX             6
> >> +#define CACHE_OP            GENMASK(4, 3)
> >> +#define  CACHE_INDEX_INVWB  0x1
> >> +#define  CACHE_HIT_INVWB    0x2
> >> +#define CACHE_INDEX         GENMASK(2, 0)
> >
> > I was expecting checkpatch.pl to catch the double space here, but it
> > didn't. It did warn about a few other things in macros, which should be
> > checked out at least. And that comment applies for the whole series,
> > along with a manual check for other spacing issues, thanks!
>
> Those style issues are mostly copied over Linux kernel counterparts, should
> we leave them as is to ease kernel rebasing effort, or fix them for consistency
> with rest of the U-Boot?

Oh I missed this - if it is easier for you to maintain by matching the
checkpatch problems then it seems OK to me. You could mention that in
the commit msg so people know to ignore the problems.

Regards,
Simon

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v2 07/16] LoongArch: lib: General routines
  2026-07-02  9:24     ` Jiaxun Yang
  2026-07-02 10:54       ` Simon Glass
@ 2026-07-02 14:07       ` Tom Rini
  2026-07-02 20:56         ` Yao Zi
  1 sibling, 1 reply; 56+ messages in thread
From: Tom Rini @ 2026-07-02 14:07 UTC (permalink / raw)
  To: Jiaxun Yang; +Cc: Yao Zi, Heinrich Schuchardt, Ilias Apalodimas, u-boot

[-- Attachment #1: Type: text/plain, Size: 1380 bytes --]

On Thu, Jul 02, 2026 at 10:24:28AM +0100, Jiaxun Yang wrote:
> 
> 
> On Wed, 1 Jul 2026, at 6:49 PM, Tom Rini wrote:
> > On Wed, Jul 01, 2026 at 11:17:59AM +0000, Yao Zi wrote:
> >
> >> From: Jiaxun Yang <jiaxun.yang@flygoat.com>
> >> 
> >> Add some common library routines for the architecture.
> >> 
> >> Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
> >> Signed-off-by: Yao Zi <me@ziyao.cc>
> > [snip]
> >> +#define CACHE_MAX_LEVEL		3
> >> +#define CACHE_MAX_INDEX		6
> >> +#define CACHE_OP		GENMASK(4, 3)
> >> +#define  CACHE_INDEX_INVWB	0x1
> >> +#define  CACHE_HIT_INVWB	0x2
> >> +#define CACHE_INDEX		GENMASK(2, 0)
> >
> > I was expecting checkpatch.pl to catch the double space here, but it
> > didn't. It did warn about a few other things in macros, which should be
> > checked out at least. And that comment applies for the whole series,
> > along with a manual check for other spacing issues, thanks!
> 
> Those style issues are mostly copied over Linux kernel counterparts, should
> we leave them as is to ease kernel rebasing effort, or fix them for consistency
> with rest of the U-Boot?

Ah, OK then yes, we can leave those if it's a match-up with the kernel,
but should make note of that in the commit message when applicable, not
just the cover letter. It will make finding that reasoning easier in the
future.

-- 
Tom

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v2 01/16] lib: fdtdec: Handle multiple memory nodes
  2026-07-02 10:22   ` Simon Glass
@ 2026-07-02 20:39     ` Yao Zi
  0 siblings, 0 replies; 56+ messages in thread
From: Yao Zi @ 2026-07-02 20:39 UTC (permalink / raw)
  To: Simon Glass, me
  Cc: Tom Rini, Jiaxun Yang, Heinrich Schuchardt, Ilias Apalodimas,
	u-boot

On Thu, Jul 02, 2026 at 11:22:14AM +0100, Simon Glass wrote:
> Hi Jiaxun,
> 
> On 2026-07-01T11:17:53, Yao Zi <me@ziyao.cc> wrote:
> > lib: fdtdec: Handle multiple memory nodes
> >
> > Current code only tries to fetch the first memory node found in
> > fdt tree and determine memory banks from multiple reg properties.
> >
> > Specification allows multiple memory nodes in devicetree, rework
> > fdtdec_setup_mem_size_base_lowest and fdtdec_setup_memory_banksize
> > to iterate over all memory nodes.
> >
> > Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
> > Signed-off-by: Yao Zi <me@ziyao.cc>
> >
> > include/asm-generic/global_data.h |   2 +-
> >  lib/fdtdec.c                      | 129 ++++++++++++++++++++++----------------
> >  2 files changed, 76 insertions(+), 55 deletions(-)
> 
> > diff --git a/lib/fdtdec.c b/lib/fdtdec.c
> > @@ -1115,90 +1116,110 @@ ofnode fdtdec_get_next_memory_node(ofnode mem)
> > +too_may_memory_banks:
> > +     log_warning("%s: Too many memory banks\n", __func__);
> > +     return -EINVAL;
> > +}
> 
> Typo - too_may_memory_banks should be too_many_memory_banks. While
> you are here, please drop the goto... bank is bounded, so a single
> check after the loops (or bank < CONFIG_NR_DRAM_BANKS in the inner
> while) gives a single return path.

Thanks for the advice. I don't think it's okay to have only a check
after the loops, in which case we might iterate over the boundary of
gd->dram[]; and if we use bank < CONFIG_NR_DRAM_BANKS for the condition
of the inner loop, another additional check is still necessary after
the loops because we want to give out the message and a correct return
value indicating the error, right?

Alternatively, I think we could drop the goto statement and instead
return immediately in the inner loop if CONFIG_NR_DRAM_BANKS is not
sufficient, is it okay for you?

> > diff --git a/lib/fdtdec.c b/lib/fdtdec.c
> > @@ -1115,90 +1116,110 @@ ofnode fdtdec_get_next_memory_node(ofnode mem)
> > +                     log_debug("%s: DRAM Bank #%d %s.%d: start = 0x%llx, size = 0x%llx\n",
> > +                               __func__, bank, ofnode_get_name(mem), reg,
> > +                              (unsigned long long)gd->dram[bank].start,
> > +                              (unsigned long long)gd->dram[bank].size);
> 
> The current code uses %pap with &gd->dram[bank].start, which is the
> idiomatic way to print phys_addr_t/phys_size_t iand should avoid
> needing casts. Can you keep %pap here (and in the message below)?

Sure, this makes sense. When rebasing, I noted the change in current
master, but had only remembered to update the log_debug() message in
fdtdec_setup_mem_size_base_lowest() to use %pap.

> > diff --git a/lib/fdtdec.c b/lib/fdtdec.c
> > @@ -1115,90 +1116,110 @@ ofnode fdtdec_get_next_memory_node(ofnode mem)
> > +     while (true) {
> > +             struct resource res;
> > +             phys_size_t base, size;
> > +             int reg = 0;
> 
> You should really use phys_addr_t for base

Ok.

> Regards,
> Simon

Best regards,
Yao Zi

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v2 03/16] image: Take entry point as an output of setup_booti
  2026-07-01 17:39   ` Tom Rini
@ 2026-07-02 20:39     ` Yao Zi
  2026-07-02 20:55       ` Tom Rini
  0 siblings, 1 reply; 56+ messages in thread
From: Yao Zi @ 2026-07-02 20:39 UTC (permalink / raw)
  To: Tom Rini, Yao Zi
  Cc: Jiaxun Yang, Heinrich Schuchardt, Ilias Apalodimas, u-boot

On Wed, Jul 01, 2026 at 11:39:40AM -0600, Tom Rini wrote:
> On Wed, Jul 01, 2026 at 11:17:55AM +0000, Yao Zi wrote:
> 
> > From: Jiaxun Yang <jiaxun.yang@flygoat.com>
> > 
> > For LoongArch the start of the image is not the entry
> > point to the image.
> > 
> > We refactor the code base to allow entry point to be
> > supplied by setup_booti.
> > 
> > Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
> > Signed-off-by: Yao Zi <me@ziyao.cc>
> > ---
> > 
> > Changed from v1
> > - Correct type of "entry" argument for RISC-V and sandbox
> 
> Can you please also provide a link to
> https://www.kernel.org/doc/html/latest/arch/loongarch/booting.html which
> probably should cover this, but I'm not entirely sure does?

It does in a non-obvious way, quoting part of the image header,

	u32     MZ_MAGIC                /* "MZ", MS-DOS header */
	u32     res0 = 0                /* Reserved */
	u64     kernel_entry            /* Kernel entry point */

comparing it to the RISC-V version[1],

	u32 code0;                /* Executable code */
	u32 code1;                /* Executable code */
	u64 text_offset;          /* Image load offset, little endian */
	u64 image_size;           /* Effective Image size, little endian */

The start of LoongArch image isn't marked as executable.

Additionally, should I include the URL of "latest" kernel documentation,
or using a link with explicit kernel version (e.g. [2]) to ensure the
content doesn't change or become 404 over time?

> -- 
> Tom

Regards,
Yao Zi

[1]: https://www.kernel.org/doc/html/v6.6/riscv/boot-image-header.html
[2]: https://www.kernel.org/doc/html/v7.1/arch/loongarch/booting.html

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v2 06/16] LoongArch: skeleton and headers
  2026-07-01 17:47   ` Tom Rini
@ 2026-07-02 20:40     ` Yao Zi
  2026-07-02 20:57       ` Tom Rini
  0 siblings, 1 reply; 56+ messages in thread
From: Yao Zi @ 2026-07-02 20:40 UTC (permalink / raw)
  To: Tom Rini, Yao Zi
  Cc: Jiaxun Yang, Heinrich Schuchardt, Ilias Apalodimas, u-boot

On Wed, Jul 01, 2026 at 11:47:00AM -0600, Tom Rini wrote:
> On Wed, Jul 01, 2026 at 11:17:58AM +0000, Yao Zi wrote:
> 
> > From: Jiaxun Yang <jiaxun.yang@flygoat.com>
> > 
> > Commit for directories, Kconfig, Makefile and headers
> > 
> > Some of them are copied from linux, some of them are derived
> > from other architectures, the rest are wriiten on my own.
> > 
> > Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
> > Signed-off-by: Yao Zi <me@ziyao.cc>
> > ---
> > 
> > Hi Heinrich,
> > 
> > I kept the naming of CONFIG_ARCH_LA64 (instead of using the full name
> > ARCH_LOONGARCH64) since it's shorter, and we already have similar
> > CONFIG_ARCH_RV64I, and etc. in U-Boot. Is is okay for you?
> 
> We should use CONFIG_LOONGARCH here, to mirror the kernel I think. The
> CONFIG_ARCH_ namespace in U-Boot maps more to the usage of CONFIG_ARCH_
> in the kernel, for ARM (and ARM64) platforms rather than describing a
> CPU level architectural feature.

Oops, to make it clear, we do have a CONFIG_LOONGARCH symbol to
indicate LoongArch platforms, and CONFIG_ARCH_LA64 is for
distinguishing LA64 with LA32 and LA32R variants which would be
introduced in the future, just like the case of CONFIG_ARCH_RV32I and
CONFIG_ARCH_RV64I. Does this make sense for you?

> -- 
> Tom

Regards,
Yao Zi

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v2 03/16] image: Take entry point as an output of setup_booti
  2026-07-02 20:39     ` Yao Zi
@ 2026-07-02 20:55       ` Tom Rini
  2026-07-02 21:10         ` Yao Zi
  0 siblings, 1 reply; 56+ messages in thread
From: Tom Rini @ 2026-07-02 20:55 UTC (permalink / raw)
  To: Yao Zi; +Cc: Jiaxun Yang, Heinrich Schuchardt, Ilias Apalodimas, u-boot

[-- Attachment #1: Type: text/plain, Size: 1859 bytes --]

On Thu, Jul 02, 2026 at 08:39:44PM +0000, Yao Zi wrote:
> On Wed, Jul 01, 2026 at 11:39:40AM -0600, Tom Rini wrote:
> > On Wed, Jul 01, 2026 at 11:17:55AM +0000, Yao Zi wrote:
> > 
> > > From: Jiaxun Yang <jiaxun.yang@flygoat.com>
> > > 
> > > For LoongArch the start of the image is not the entry
> > > point to the image.
> > > 
> > > We refactor the code base to allow entry point to be
> > > supplied by setup_booti.
> > > 
> > > Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
> > > Signed-off-by: Yao Zi <me@ziyao.cc>
> > > ---
> > > 
> > > Changed from v1
> > > - Correct type of "entry" argument for RISC-V and sandbox
> > 
> > Can you please also provide a link to
> > https://www.kernel.org/doc/html/latest/arch/loongarch/booting.html which
> > probably should cover this, but I'm not entirely sure does?
> 
> It does in a non-obvious way, quoting part of the image header,
> 
> 	u32     MZ_MAGIC                /* "MZ", MS-DOS header */
> 	u32     res0 = 0                /* Reserved */
> 	u64     kernel_entry            /* Kernel entry point */
> 
> comparing it to the RISC-V version[1],
> 
> 	u32 code0;                /* Executable code */
> 	u32 code1;                /* Executable code */
> 	u64 text_offset;          /* Image load offset, little endian */
> 	u64 image_size;           /* Effective Image size, little endian */
>
> The start of LoongArch image isn't marked as executable.

Perhaps it's worth clarifying in the kernel documentation then? Thanks.
 
> Additionally, should I include the URL of "latest" kernel documentation,
> or using a link with explicit kernel version (e.g. [2]) to ensure the
> content doesn't change or become 404 over time?

Ah, true, yes, lets point at the v7.1 tag, or whatever you're testing
this against, to cover future changes if any.

-- 
Tom

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v2 07/16] LoongArch: lib: General routines
  2026-07-02 14:07       ` Tom Rini
@ 2026-07-02 20:56         ` Yao Zi
  2026-07-02 20:58           ` Tom Rini
  0 siblings, 1 reply; 56+ messages in thread
From: Yao Zi @ 2026-07-02 20:56 UTC (permalink / raw)
  To: Tom Rini, Jiaxun Yang
  Cc: Yao Zi, Heinrich Schuchardt, Ilias Apalodimas, u-boot

On Thu, Jul 02, 2026 at 08:07:08AM -0600, Tom Rini wrote:
> On Thu, Jul 02, 2026 at 10:24:28AM +0100, Jiaxun Yang wrote:
> > 
> > 
> > On Wed, 1 Jul 2026, at 6:49 PM, Tom Rini wrote:
> > > On Wed, Jul 01, 2026 at 11:17:59AM +0000, Yao Zi wrote:
> > >
> > >> From: Jiaxun Yang <jiaxun.yang@flygoat.com>
> > >> 
> > >> Add some common library routines for the architecture.
> > >> 
> > >> Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
> > >> Signed-off-by: Yao Zi <me@ziyao.cc>
> > > [snip]
> > >> +#define CACHE_MAX_LEVEL		3
> > >> +#define CACHE_MAX_INDEX		6
> > >> +#define CACHE_OP		GENMASK(4, 3)
> > >> +#define  CACHE_INDEX_INVWB	0x1
> > >> +#define  CACHE_HIT_INVWB	0x2
> > >> +#define CACHE_INDEX		GENMASK(2, 0)
> > >
> > > I was expecting checkpatch.pl to catch the double space here, but it
> > > didn't. It did warn about a few other things in macros, which should be
> > > checked out at least. And that comment applies for the whole series,
> > > along with a manual check for other spacing issues, thanks!
> > 
> > Those style issues are mostly copied over Linux kernel counterparts, should
> > we leave them as is to ease kernel rebasing effort, or fix them for consistency
> > with rest of the U-Boot?
> 
> Ah, OK then yes, we can leave those if it's a match-up with the kernel,
> but should make note of that in the commit message when applicable, not
> just the cover letter. It will make finding that reasoning easier in the
> future.

Yes, most style issues are in files copied from the kernel side, before
sending v2, I do have a brief look and fix some of them (for example,
mixed TAB/space and multiple empty lines).

But the diff quoted here isn't copied from kernel side, it's written by
myself. I consider the double space meaningful since these two macros
are two possible values of CACHE_OP, and found similar styles in
tools/zynqmqimage.h (PART_ATTR_*) and kernel side, do you think it's
acceptable?

> -- 
> Tom

Regards,
Yao Zi

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v2 06/16] LoongArch: skeleton and headers
  2026-07-02 20:40     ` Yao Zi
@ 2026-07-02 20:57       ` Tom Rini
  0 siblings, 0 replies; 56+ messages in thread
From: Tom Rini @ 2026-07-02 20:57 UTC (permalink / raw)
  To: Yao Zi; +Cc: Jiaxun Yang, Heinrich Schuchardt, Ilias Apalodimas, u-boot

[-- Attachment #1: Type: text/plain, Size: 1485 bytes --]

On Thu, Jul 02, 2026 at 08:40:24PM +0000, Yao Zi wrote:
> On Wed, Jul 01, 2026 at 11:47:00AM -0600, Tom Rini wrote:
> > On Wed, Jul 01, 2026 at 11:17:58AM +0000, Yao Zi wrote:
> > 
> > > From: Jiaxun Yang <jiaxun.yang@flygoat.com>
> > > 
> > > Commit for directories, Kconfig, Makefile and headers
> > > 
> > > Some of them are copied from linux, some of them are derived
> > > from other architectures, the rest are wriiten on my own.
> > > 
> > > Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
> > > Signed-off-by: Yao Zi <me@ziyao.cc>
> > > ---
> > > 
> > > Hi Heinrich,
> > > 
> > > I kept the naming of CONFIG_ARCH_LA64 (instead of using the full name
> > > ARCH_LOONGARCH64) since it's shorter, and we already have similar
> > > CONFIG_ARCH_RV64I, and etc. in U-Boot. Is is okay for you?
> > 
> > We should use CONFIG_LOONGARCH here, to mirror the kernel I think. The
> > CONFIG_ARCH_ namespace in U-Boot maps more to the usage of CONFIG_ARCH_
> > in the kernel, for ARM (and ARM64) platforms rather than describing a
> > CPU level architectural feature.
> 
> Oops, to make it clear, we do have a CONFIG_LOONGARCH symbol to
> indicate LoongArch platforms, and CONFIG_ARCH_LA64 is for
> distinguishing LA64 with LA32 and LA32R variants which would be
> introduced in the future, just like the case of CONFIG_ARCH_RV32I and
> CONFIG_ARCH_RV64I. Does this make sense for you?

Ah, OK, yes, that makes sense, thanks for explaining.

-- 
Tom

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v2 07/16] LoongArch: lib: General routines
  2026-07-02 20:56         ` Yao Zi
@ 2026-07-02 20:58           ` Tom Rini
  0 siblings, 0 replies; 56+ messages in thread
From: Tom Rini @ 2026-07-02 20:58 UTC (permalink / raw)
  To: Yao Zi; +Cc: Jiaxun Yang, Heinrich Schuchardt, Ilias Apalodimas, u-boot

[-- Attachment #1: Type: text/plain, Size: 2225 bytes --]

On Thu, Jul 02, 2026 at 08:56:46PM +0000, Yao Zi wrote:
> On Thu, Jul 02, 2026 at 08:07:08AM -0600, Tom Rini wrote:
> > On Thu, Jul 02, 2026 at 10:24:28AM +0100, Jiaxun Yang wrote:
> > > 
> > > 
> > > On Wed, 1 Jul 2026, at 6:49 PM, Tom Rini wrote:
> > > > On Wed, Jul 01, 2026 at 11:17:59AM +0000, Yao Zi wrote:
> > > >
> > > >> From: Jiaxun Yang <jiaxun.yang@flygoat.com>
> > > >> 
> > > >> Add some common library routines for the architecture.
> > > >> 
> > > >> Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
> > > >> Signed-off-by: Yao Zi <me@ziyao.cc>
> > > > [snip]
> > > >> +#define CACHE_MAX_LEVEL		3
> > > >> +#define CACHE_MAX_INDEX		6
> > > >> +#define CACHE_OP		GENMASK(4, 3)
> > > >> +#define  CACHE_INDEX_INVWB	0x1
> > > >> +#define  CACHE_HIT_INVWB	0x2
> > > >> +#define CACHE_INDEX		GENMASK(2, 0)
> > > >
> > > > I was expecting checkpatch.pl to catch the double space here, but it
> > > > didn't. It did warn about a few other things in macros, which should be
> > > > checked out at least. And that comment applies for the whole series,
> > > > along with a manual check for other spacing issues, thanks!
> > > 
> > > Those style issues are mostly copied over Linux kernel counterparts, should
> > > we leave them as is to ease kernel rebasing effort, or fix them for consistency
> > > with rest of the U-Boot?
> > 
> > Ah, OK then yes, we can leave those if it's a match-up with the kernel,
> > but should make note of that in the commit message when applicable, not
> > just the cover letter. It will make finding that reasoning easier in the
> > future.
> 
> Yes, most style issues are in files copied from the kernel side, before
> sending v2, I do have a brief look and fix some of them (for example,
> mixed TAB/space and multiple empty lines).
> 
> But the diff quoted here isn't copied from kernel side, it's written by
> myself. I consider the double space meaningful since these two macros
> are two possible values of CACHE_OP, and found similar styles in
> tools/zynqmqimage.h (PART_ATTR_*) and kernel side, do you think it's
> acceptable?

We have 178 other files doing this, so, it's not a NAK if it's really
helpful to you.

-- 
Tom

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v2 03/16] image: Take entry point as an output of setup_booti
  2026-07-02 20:55       ` Tom Rini
@ 2026-07-02 21:10         ` Yao Zi
  0 siblings, 0 replies; 56+ messages in thread
From: Yao Zi @ 2026-07-02 21:10 UTC (permalink / raw)
  To: Tom Rini, Yao Zi
  Cc: Jiaxun Yang, Heinrich Schuchardt, Ilias Apalodimas, u-boot

On Thu, Jul 02, 2026 at 02:55:22PM -0600, Tom Rini wrote:
> On Thu, Jul 02, 2026 at 08:39:44PM +0000, Yao Zi wrote:
> > On Wed, Jul 01, 2026 at 11:39:40AM -0600, Tom Rini wrote:
> > > On Wed, Jul 01, 2026 at 11:17:55AM +0000, Yao Zi wrote:
> > > 
> > > > From: Jiaxun Yang <jiaxun.yang@flygoat.com>
> > > > 
> > > > For LoongArch the start of the image is not the entry
> > > > point to the image.
> > > > 
> > > > We refactor the code base to allow entry point to be
> > > > supplied by setup_booti.
> > > > 
> > > > Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
> > > > Signed-off-by: Yao Zi <me@ziyao.cc>
> > > > ---
> > > > 
> > > > Changed from v1
> > > > - Correct type of "entry" argument for RISC-V and sandbox
> > > 
> > > Can you please also provide a link to
> > > https://www.kernel.org/doc/html/latest/arch/loongarch/booting.html which
> > > probably should cover this, but I'm not entirely sure does?
> > 
> > It does in a non-obvious way, quoting part of the image header,
> > 
> > 	u32     MZ_MAGIC                /* "MZ", MS-DOS header */
> > 	u32     res0 = 0                /* Reserved */
> > 	u64     kernel_entry            /* Kernel entry point */
> > 
> > comparing it to the RISC-V version[1],
> > 
> > 	u32 code0;                /* Executable code */
> > 	u32 code1;                /* Executable code */
> > 	u64 text_offset;          /* Image load offset, little endian */
> > 	u64 image_size;           /* Effective Image size, little endian */
> >
> > The start of LoongArch image isn't marked as executable.
> 
> Perhaps it's worth clarifying in the kernel documentation then? Thanks.

Sure, Jiaxun and I plan to improve the kernel side documentation, and
additionally improve LoongArch image header to make the image executable
from its start, aligning with aarch64 and riscv64.

However, there isn't a promise when it would land, and even with the
improvement to image header, we still have to parse the text_offset
field to keep compatibility with older images.

> > Additionally, should I include the URL of "latest" kernel documentation,
> > or using a link with explicit kernel version (e.g. [2]) to ensure the
> > content doesn't change or become 404 over time?
> 
> Ah, true, yes, lets point at the v7.1 tag, or whatever you're testing
> this against, to cover future changes if any.
> 
> -- 
> Tom

Best regards,
Yao Zi

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v2 06/16] LoongArch: skeleton and headers
  2026-07-02 10:28   ` Simon Glass
@ 2026-07-02 21:22     ` Yao Zi
  0 siblings, 0 replies; 56+ messages in thread
From: Yao Zi @ 2026-07-02 21:22 UTC (permalink / raw)
  To: Simon Glass, me
  Cc: Tom Rini, Jiaxun Yang, Heinrich Schuchardt, Ilias Apalodimas,
	u-boot

On Thu, Jul 02, 2026 at 11:28:23AM +0100, Simon Glass wrote:
> Hi Jiaxun,
> 
> On 2026-07-01T11:17:53, Yao Zi <me@ziyao.cc> wrote:
> > LoongArch: skeleton and headers
> >
> > Commit for directories, Kconfig, Makefile and headers
> >
> > Some of them are copied from linux, some of them are derived
> > from other architectures, the rest are wriiten on my own.
> >
> > Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
> > Signed-off-by: Yao Zi <me@ziyao.cc>
> 
> > Some of them are copied from linux, some of them are derived
> > from other architectures, the rest are wriiten on my own.
> 

...

> > diff --git a/arch/loongarch/include/asm/asm.h b/arch/loongarch/include/asm/asm.h
> > @@ -0,0 +1,186 @@
> > +/*
> > + * Size of a register
> > + */
> > +#if defined(__loongarch__) && __loongarch_grlen == 64
> > +#define SZREG        4
> > +#else
> > +#define SZREG        8
> > +#endif
> 
> This is inverted - on 64-bit LoongArch a register is 8 bytes, not
> 4. The result is that REG_L/REG_S resolve to ld.w/st.w on the only
> ISA this series supports. Linux seems to use __loongarch64, BTW.

__loongarch64 is a deprecated macro, provided for only compatibility
reasons[1]. For v1 of the series Heinrich has raised this[2], so I
tried to migrate to the new ones but obviously messed it up here :(

...

> > diff --git a/arch/loongarch/include/asm/types.h b/arch/loongarch/include/asm/types.h
> > @@ -0,0 +1,37 @@
> > +#ifdef __KERNEL__
> > +
> > +#define BITS_PER_LONG _LOONGARCH_SZLONG
> 
> _LOONGARCH_SZLONG is never defined anywhere in the tree, so this
> expands to an empty token. Please either define it (e.g. 64 for LA64)
> or drop this and rely on asm-generic/bitsperlong.h like other arches.

_LOONGARCH_SZLONG is a pre-defined macro provided by toolchain[3], so
it wouldn't be expanded to an empty token. But after examining the
toolchain convention documentation, I did find it's also deprecated.
Will drop it in the next version.

> Regards,
> Simon

Thanks,
Yao Zi

[1]: https://github.com/loongson/la-toolchain-conventions/blob/36d207cd76301618624d10e67daf7b7f1c060411/LoongArch-toolchain-conventions-EN.adoc?plain=1#L791
[2]: https://lore.kernel.org/u-boot/304f9e83-45eb-4f8e-98f3-2658aac5c20b@gmx.de/
[3]: https://github.com/loongson/la-toolchain-conventions/blob/36d207cd76301618624d10e67daf7b7f1c060411/LoongArch-toolchain-conventions-EN.adoc?plain=1#L811

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v2 07/16] LoongArch: lib: General routines
  2026-07-02 10:28   ` Simon Glass
@ 2026-07-02 21:46     ` Yao Zi
  0 siblings, 0 replies; 56+ messages in thread
From: Yao Zi @ 2026-07-02 21:46 UTC (permalink / raw)
  To: Simon Glass, me
  Cc: Tom Rini, Jiaxun Yang, Heinrich Schuchardt, Ilias Apalodimas,
	u-boot

On Thu, Jul 02, 2026 at 11:28:08AM +0100, Simon Glass wrote:
> Hi Yao,
> 
> On 2026-07-01T11:17:53, Yao Zi <me@ziyao.cc> wrote:
> > LoongArch: lib: General routines
> >
> > Add some common library routines for the architecture.
> >
> > Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
> > Signed-off-by: Yao Zi <me@ziyao.cc>
> >
> > arch/loongarch/include/asm/cache.h       |  10 ++
> >  arch/loongarch/include/asm/global_data.h |   7 +
> >  arch/loongarch/lib/Makefile              |   7 +
> >  arch/loongarch/lib/asm-offsets.c         |  66 ++++++++++
> >  arch/loongarch/lib/boot.c                |  14 ++
> >  arch/loongarch/lib/cache.c               | 213 +++++++++++++++++++++++++++++++
> >  arch/loongarch/lib/reset.c               |  14 ++
> >  arch/loongarch/lib/setjmp.S              |  52 ++++++++
> >  8 files changed, 383 insertions(+)
> 
> > Add some common library routines for the architecture.

...

> > diff --git a/arch/loongarch/lib/cache.c b/arch/loongarch/lib/cache.c
> > @@ -0,0 +1,213 @@
> > +static inline void flush_cache_line_index(unsigned int index,
> > +                                       unsigned long addr)
> > +{
> > +#define do_flush(index)                                                      \
> > +     case index:                                                     \
> > +             cache_op(FIELD_PREP(CACHE_OP, CACHE_INDEX_INVWB) |      \
> > +                      FIELD_PREP(CACHE_INDEX, index),                \
> > +                      index);                                        \
> > +             break;
> > +
> > +     switch (index) {
> > +             do_flush(0);
> > +             do_flush(1);
> > +             do_flush(2);
> > +             do_flush(3);
> > +             do_flush(4);
> > +             do_flush(5);
> > +     }
> > +
> > +#undef do_flush
> > +}
> 
> addr is silently dropped. Inside do_flush() the token index
> resolves to the macro parameter (0..5, the cache identifier), so
> cache_op() always gets the small constant as its address operand.
> The way/set offset that flush_dcache_level_all() computes never
> reaches the CACOP instruction, so this hammers way 0 / set 0 of
> the selected cache repeatedly instead of walking it. Please pass
> addr through (rename the macro parameter to avoid the shadow), and
> confirm with a real by-index flush test.

Oops, yes. Thanks for pointing out.

> > diff --git a/arch/loongarch/lib/cache.c b/arch/loongarch/lib/cache.c
> > @@ -0,0 +1,213 @@
> > +void probe_caches(void)
> > +{
> > +     unsigned int level = 0, index = 0;
> > +     u32 cfg = read_cpucfg(LOONGARCH_CPUCFG16);
> > +
> > +     if (cfg & CPUCFG16_L1_IUPRE) {
> > +             if (cfg & CPUCFG16_L1_IUUNIFY) {
> > +                     gd->arch.dcache_index[level] = index;
> > +                     populate_dcache_properties(cfg, level++,
> > +                                                LOONGARCH_CPUCFG17);
> > +             }
> > +
> > +             index++;
> > +     }
> > +
> > +     if (cfg & CPUCFG16_L1_DPRE) {
> > +             gd->arch.dcache_index[level] = index++;
> > +             populate_dcache_properties(cfg, level++, LOONGARCH_CPUCFG18);
> > +     }
> > +
> > +     cfg >>= 3;
> > +
> > +     for (; level < 3; level++) {
> 
> Please use CACHE_MAX_LEVEL rather than the bare 3.

Ok.

> populate_dcache_properties() also sets dcache_inclusive from cfg
> whenever level != 0, but on the L1D path cfg is still CPUCFG16 -
> the L1 inclusive bit describes L1I vs L1D, not L1D vs L2, so this
> looks incorrect. Please double-check.

The numbering logic for caches used by CACOP are quite confusing, and I
think it deserves some comments in the file. For CACOP instructions, it
indexes caches in the following order,

- L1I or L1 unified
- L1D
- L2I or L2 unified
- L2D
- L3I or L3 unified
- L3D

The index only counts caches present on the system, e.g., for a system
with L1I, L1D, L2 unified and L3 unified, they're respectively indexed
through 0-3 instead of 0, 1, 2, 4.

Furthermore, current architecture definition provides no cpucfg
register for L2D/L3D information L3D, so the current code assumes L2
and L3, if present, must be unified or instruction-only.

Back in the logic, L1_IUPRE means either L1I or L1 unified is present,
and "index" is increased in this case, but "level" is only increased if
L1_IUUNIFY is set, which means L1 is unified and L1_DPRE must not be
set. So populate_dcache_properties() would never be fired to probe
L1D with level = 1.

I'll add some comments on this in v3.

...

> Simon

Best regards,
Yao Zi

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v2 08/16] LoongArch: CPU assembly routines
  2026-07-02 10:25   ` Simon Glass
@ 2026-07-03 20:12     ` Yao Zi
  2026-07-04 11:22       ` Jiaxun Yang
  0 siblings, 1 reply; 56+ messages in thread
From: Yao Zi @ 2026-07-03 20:12 UTC (permalink / raw)
  To: Simon Glass, me
  Cc: Tom Rini, Jiaxun Yang, Heinrich Schuchardt, Ilias Apalodimas,
	u-boot

On Thu, Jul 02, 2026 at 11:25:39AM +0100, Simon Glass wrote:
> Hi Yao,
> 
> On 2026-07-01T11:17:53, Yao Zi <me@ziyao.cc> wrote:
> > LoongArch: CPU assembly routines
> >
> > start.S for initialisation, smp_secondary routine for
> > a spin-table like interface for secondary cpus.
> >
> > Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
> > Signed-off-by: Yao Zi <me@ziyao.cc>
> >
> > 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(+)

...

> > diff --git a/arch/loongarch/cpu/smp_secondary.S b/arch/loongarch/cpu/smp_secondary.S
> > @@ -0,0 +1,55 @@
> > +1:
> > +     /* Query spin table */
> > +     idle 0
> > +     nop
> > +     iocsrrd.w       t0, t1
> > +     beqz            t0, 1b
> 
> Is the nop after idle 0 required by the ISA (to guarantee the
> wake-up completes before the load) or just padding? A
> one-line comment would help.

I don't think such requirements exist, and LoongArch instructions are
always 4-byte so there's nothing to pad, too. This is likely
unintentionally left when re-writing the assembly, and I'll remove it
in the next version.

> Regards,
> Simon

Best regards,
Yao Zi

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v2 08/16] LoongArch: CPU assembly routines
  2026-07-03 20:12     ` Yao Zi
@ 2026-07-04 11:22       ` Jiaxun Yang
  0 siblings, 0 replies; 56+ messages in thread
From: Jiaxun Yang @ 2026-07-04 11:22 UTC (permalink / raw)
  To: Yao Zi, Simon Glass
  Cc: Tom Rini, Heinrich Schuchardt, Ilias Apalodimas, u-boot



On Fri, 3 Jul 2026, at 9:12 PM, Yao Zi wrote:
[...]
>> 
>> Is the nop after idle 0 required by the ISA (to guarantee the
>> wake-up completes before the load) or just padding? A
>> one-line comment would help.
>
> I don't think such requirements exist, and LoongArch instructions are
> always 4-byte so there's nothing to pad, too. This is likely
> unintentionally left when re-writing the assembly, and I'll remove it
> in the next version.

This is carried over from Loongson's UEFI assembly. I'd rather not to
touch it.

Thanks

>
>> Regards,
>> Simon
>
> Best regards,
> Yao Zi

-- 
- Jiaxun

^ permalink raw reply	[flat|nested] 56+ messages in thread

end of thread, other threads:[~2026-07-04 11:22 UTC | newest]

Thread overview: 56+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-01 11:17 [PATCH v2 00/16] LoongArch initial support Yao Zi
2026-07-01 11:17 ` [PATCH v2 01/16] lib: fdtdec: Handle multiple memory nodes Yao Zi
2026-07-02 10:22   ` Simon Glass
2026-07-02 20:39     ` Yao Zi
2026-07-01 11:17 ` [PATCH v2 02/16] linux/io.h: Use map_physmem to implement ioremap Yao Zi
2026-07-02 10:21   ` Simon Glass
2026-07-01 11:17 ` [PATCH v2 03/16] image: Take entry point as an output of setup_booti Yao Zi
2026-07-01 17:39   ` Tom Rini
2026-07-02 20:39     ` Yao Zi
2026-07-02 20:55       ` Tom Rini
2026-07-02 21:10         ` Yao Zi
2026-07-02  9:46   ` Simon Glass
2026-07-01 11:17 ` [PATCH v2 04/16] elf: Define LoongArch bits Yao Zi
2026-07-02 10:24   ` Simon Glass
2026-07-01 11:17 ` [PATCH v2 05/16] image: Define IH_ARCH_LOONGARCH Yao Zi
2026-07-02  9:44   ` Simon Glass
2026-07-01 11:17 ` [PATCH v2 06/16] LoongArch: skeleton and headers Yao Zi
2026-07-01 17:47   ` Tom Rini
2026-07-02 20:40     ` Yao Zi
2026-07-02 20:57       ` Tom Rini
2026-07-02 10:28   ` Simon Glass
2026-07-02 21:22     ` Yao Zi
2026-07-01 11:17 ` [PATCH v2 07/16] LoongArch: lib: General routines Yao Zi
2026-07-01 17:49   ` Tom Rini
2026-07-02  9:24     ` Jiaxun Yang
2026-07-02 10:54       ` Simon Glass
2026-07-02 14:07       ` Tom Rini
2026-07-02 20:56         ` Yao Zi
2026-07-02 20:58           ` Tom Rini
2026-07-02 10:28   ` Simon Glass
2026-07-02 21:46     ` Yao Zi
2026-07-01 11:18 ` [PATCH v2 08/16] LoongArch: CPU assembly routines Yao Zi
2026-07-02 10:25   ` Simon Glass
2026-07-03 20:12     ` Yao Zi
2026-07-04 11:22       ` Jiaxun Yang
2026-07-01 11:18 ` [PATCH v2 09/16] LoongArch: Exception handling Yao Zi
2026-07-02 10:25   ` Simon Glass
2026-07-01 11:18 ` [PATCH v2 10/16] LoongArch: Boot Image bits Yao Zi
2026-07-01 17:53   ` Tom Rini
2026-07-02 10:26   ` Simon Glass
2026-07-01 11:18 ` [PATCH v2 11/16] LoongArch: Generic CPU type Yao Zi
2026-07-01 17:55   ` Tom Rini
2026-07-02 10:26   ` Simon Glass
2026-07-01 11:18 ` [PATCH v2 12/16] cpu: Add loongarch_cpu driver Yao Zi
2026-07-02 10:26   ` Simon Glass
2026-07-01 11:18 ` [PATCH v2 13/16] timer: Add loongarch_timer driver Yao Zi
2026-07-02 10:27   ` Simon Glass
2026-07-01 11:18 ` [PATCH v2 14/16] board: emulation: Add qemu-loongarch Yao Zi
2026-07-02 10:27   ` Simon Glass
2026-07-01 11:18 ` [PATCH v2 15/16] efi: LoongArch: Define LoongArch bits everywhere Yao Zi
2026-07-02 10:27   ` Simon Glass
2026-07-01 11:18 ` [PATCH v2 16/16] efi: LoongArch: Implement everything Yao Zi
2026-07-02 10:29   ` Simon Glass
2026-07-01 15:53 ` [PATCH v2 00/16] LoongArch initial support Jiaxun Yang
2026-07-01 17:59 ` Tom Rini
2026-07-02 10:31 ` [v2,00/16] " Simon Glass

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.