[PATCH 00/16] LoongArch initial support

Hi all,
Sorry for flooding the mailing list recently, yet another huge RFC series ahead.
So after working on MIPS, arm64be and Xtensa I'm now on LoongArch, as suggested by Heinrich.
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). Currently, only LA64 is implemented as 32bit support in open sourc world is not mature yet. However, most of the code is written with 32 bit support in mind, so it should be trivial to add 32 bit support in the future.
It is a little endian only architecture.
This series had passed checkpatch with exceptions on some false alarms and headers imported elsewhere.
I had tested virtio devices, qfw direct kernel booting, efistub kernel booting and grub.
Toolchain can be found at [1] or using upstream one, I had also discovered a couple of issues in kernel and QEMU in the porting process, patches at [2] and [3].
To build: ``` make qemu-loongarch64_defconfig make ``
To run in QEMU (patched): ``` qemu-system-loongarch64 -nographic -machine virt -bios u-boot.bin ```
TODOs for me on this series: - Documents - I'll write board level document for QEMU, what should I write at architecture level? - MAINTAINERS entries - I'm not sure what I should add here, please suggest! - Further clean-ups
TODOs on the architecture & board: - loongson,ls7a-rtc driver - The only device on QEMU board haven't been supported yet - LoongArch sandbox host support - Implement LoongArch's PE relocations - No application is using it so far, pe-format spec is not really clear. - TLB enablement - This is required for real CPU to utilize caches - Possibly EFI-APP support for real machine
Porting to real SoCs is out of my scope as a hobbyist, I'll try to convince Loongson people or other hobbyists to work on that. I intended to use U-Boot as an OVMF replacement and second stage BL.
Any comments are much appreciated!
Thanks
Signed-off-by: Jiaxun Yang jiaxun.yang@flygoat.com --- 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.h 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
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 | 28 + 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 | 169 +++ arch/loongarch/cpu/u-boot.lds | 85 ++ arch/loongarch/dts/Makefile | 13 + arch/loongarch/dts/qemu-loongarch64.dts | 9 + arch/loongarch/include/asm/acpi_table.h | 8 + arch/loongarch/include/asm/addrspace.h | 87 ++ .../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 | 1468 ++++++++++++++++++++ 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 | 177 +++ arch/loongarch/lib/cache.c | 73 + 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 + board/emulation/qemu-loongarch/qemu-loongarch.c | 84 ++ board/emulation/qemu-loongarch/qemu-loongarch.env | 6 + boot/bootm.c | 5 +- boot/bootmeth_efi.c | 2 + 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/pe.h | 2 + include/config_distro_bootcmd.h | 5 + include/configs/qemu-loongarch.h | 13 + include/efi_default_filename.h | 2 + include/elf.h | 9 +- include/image.h | 4 +- include/linux/io.h | 3 +- lib/efi_loader/Kconfig | 2 +- lib/efi_loader/efi_image_loader.c | 7 + lib/efi_loader/efi_runtime.c | 4 + lib/efi_selftest/efi_selftest_miniapp_exception.c | 2 + lib/fdtdec.c | 137 +- 92 files changed, 5559 insertions(+), 70 deletions(-) --- base-commit: a7f0154c412859323396111dd0c09dbafbc153cb change-id: 20240522-loongarch-8a04c1e34a47
Best regards,

Current code only tries to fetch the first memory node found in fdt tree and determine memory banks from multiple reg properties.
Linux do allow 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 --- lib/fdtdec.c | 137 ++++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 83 insertions(+), 54 deletions(-)
diff --git a/lib/fdtdec.c b/lib/fdtdec.c index b2c59ab3818b..403b363043d6 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -1075,90 +1075,119 @@ ofnode get_next_memory_node(ofnode mem) return mem; }
+static void sort_memory_banks(int num) +{ + int i, j; + phys_addr_t tmp_start; + phys_size_t tmp_size; + struct bd_info *bd = gd->bd; + + for (i = 0; i < num - 1; i++) { + for (j = i + 1; j < num; j++) { + if (bd->bi_dram[i].start > bd->bi_dram[j].start) { + tmp_start = bd->bi_dram[i].start; + tmp_size = bd->bi_dram[i].size; + bd->bi_dram[i].start = bd->bi_dram[j].start; + bd->bi_dram[i].size = bd->bi_dram[j].size; + bd->bi_dram[j].start = tmp_start; + bd->bi_dram[j].size = tmp_size; + } + } + } +} + 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;
- ret = ofnode_read_resource(mem, reg++, &res); + while (true) { + int ret = ofnode_read_resource(mem, reg, &res); if (ret < 0) break; - }
- if (ret != 0) - return -EINVAL; + if (bank >= CONFIG_VAL(NR_DRAM_BANKS)) + goto too_may_memory_banks;
- gd->bd->bi_dram[bank].start = (phys_addr_t)res.start; - gd->bd->bi_dram[bank].size = - (phys_size_t)(res.end - res.start + 1); + gd->bd->bi_dram[bank].start = (phys_addr_t)res.start; + gd->bd->bi_dram[bank].size = + (phys_size_t)(res.end - res.start + 1);
- debug("%s: DRAM Bank #%d: start = 0x%llx, size = 0x%llx\n", - __func__, bank, - (unsigned long long)gd->bd->bi_dram[bank].start, - (unsigned long long)gd->bd->bi_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->bd->bi_dram[bank].start, + (unsigned long long)gd->bd->bi_dram[bank].size); + reg++; + bank++; + } }
+ if (!bank) { + log_warning("%s: Missing /memory node\n", __func__); + return -EINVAL; + } + + sort_memory_banks(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;
- 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;
- ret = ofnode_read_resource(mem, reg++, &res); + while (true) { + int ret = ofnode_read_resource(mem, reg, &res); if (ret < 0) break; + 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; + } + reg++; + bank++; } + }
- if (ret != 0) - return -EINVAL; - - base = (unsigned long)res.start; - size = (phys_size_t)(res.end - res.start + 1); - - 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); - } + if (!bank) { + log_warning("%s: Missing /memory node\n", __func__); + return -EINVAL; }
+ log_debug("%s: Initial DRAM %s.%d: base %lx size %lx\n", + __func__, final_name, final_reg, + (ulong)gd->ram_base, (ulong)gd->ram_size); + return 0; }

On 22.05.24 17:34, Jiaxun Yang wrote:
Current code only tries to fetch the first memory node found in fdt tree and determine memory banks from multiple reg properties.
Linux do allow multiple memory nodes in devicetree, rework
%/do allow/allows/
It is not Linux that allows it but
Devicetree Specification, Release v0.4 https://github.com/devicetree-org/devicetree-specification/releases/download...
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
lib/fdtdec.c | 137 ++++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 83 insertions(+), 54 deletions(-)
diff --git a/lib/fdtdec.c b/lib/fdtdec.c index b2c59ab3818b..403b363043d6 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -1075,90 +1075,119 @@ ofnode get_next_memory_node(ofnode mem) return mem; }
+static void sort_memory_banks(int num) +{
- int i, j;
- phys_addr_t tmp_start;
- phys_size_t tmp_size;
- struct bd_info *bd = gd->bd;
- for (i = 0; i < num - 1; i++) {
for (j = i + 1; j < num; j++) {
if (bd->bi_dram[i].start > bd->bi_dram[j].start) {
tmp_start = bd->bi_dram[i].start;
tmp_size = bd->bi_dram[i].size;
bd->bi_dram[i].start = bd->bi_dram[j].start;
bd->bi_dram[i].size = bd->bi_dram[j].size;
bd->bi_dram[j].start = tmp_start;
bd->bi_dram[j].size = tmp_size;
}
}
- }
Please, use qsort() instead.
+}
- 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;
ret = ofnode_read_resource(mem, reg++, &res);
while (true) {
int ret = ofnode_read_resource(mem, reg, &res);
Please, leave a blank line after declarations.
if (ret < 0) break;
}
if (ret != 0)
return -EINVAL;
if (bank >= CONFIG_VAL(NR_DRAM_BANKS))
goto too_may_memory_banks;
gd->bd->bi_dram[bank].start = (phys_addr_t)res.start;
The conversion is superfluous.
gd->bd->bi_dram[bank].size =
(phys_size_t)(res.end - res.start + 1);
gd->bd->bi_dram[bank].start = (phys_addr_t)res.start;
gd->bd->bi_dram[bank].size =
(phys_size_t)(res.end - res.start + 1);
debug("%s: DRAM Bank #%d: start = 0x%llx, size = 0x%llx\n",
__func__, bank,
(unsigned long long)gd->bd->bi_dram[bank].start,
(unsigned long long)gd->bd->bi_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->bd->bi_dram[bank].start,
(unsigned long long)gd->bd->bi_dram[bank].size);
reg++;
bank++;
}
}
if (!bank) {
log_warning("%s: Missing /memory node\n", __func__);
return -EINVAL;
}
sort_memory_banks(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;
'__maybe_unused' is superfluous.
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;
ret = ofnode_read_resource(mem, reg++, &res);
while (true) {
int ret = ofnode_read_resource(mem, reg, &res); if (ret < 0) break;
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;
}
reg++;
}bank++;
- }
if (ret != 0)
return -EINVAL;
base = (unsigned long)res.start;
size = (phys_size_t)(res.end - res.start + 1);
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);
}
if (!bank) {
log_warning("%s: Missing /memory node\n", __func__);
return -EINVAL;
}
log_debug("%s: Initial DRAM %s.%d: base %lx size %lx\n",
__func__, final_name, final_reg,
(ulong)gd->ram_base, (ulong)gd->ram_size);
ram_base is already defined as unsigned long.
include/asm-generic/global_data.h:154: unsigned long ram_base;
Best regards
Heinrich
- return 0; }

在2024年6月11日六月 下午1:26,Heinrich Schuchardt写道: Hi Heinrich,
Thanks for your comments, will fix most of them in next reversion.
[...]
gd->bd->bi_dram[bank].start = (phys_addr_t)res.start;
The conversion is superfluous.
This is necessary as phys_addr_t can be unsigned long or unsigned long long.
[...]
- __maybe_unused const char *final_name;
- __maybe_unused int final_reg;
'__maybe_unused' is superfluous.
This is necessary as when LOG_DEBUG is disabled these two variables won't be referenced. Compilers would complain about it.
gd->ram_base = (unsigned long)~0;
gd->ram_base = ULONG_MAX;
[...]
Thanks

Hi Jiaxun,
On Tue, 11 Jun 2024 at 07:48, Jiaxun Yang jiaxun.yang@flygoat.com wrote:
在2024年6月11日六月 下午1:26,Heinrich Schuchardt写道: Hi Heinrich,
Thanks for your comments, will fix most of them in next reversion.
[...]
gd->bd->bi_dram[bank].start = (phys_addr_t)res.start;
The conversion is superfluous.
This is necessary as phys_addr_t can be unsigned long or unsigned long long.
[...]
- __maybe_unused const char *final_name;
- __maybe_unused int final_reg;
'__maybe_unused' is superfluous.
This is necessary as when LOG_DEBUG is disabled these two variables won't be referenced. Compilers would complain about it.
gd->ram_base = (unsigned long)~0;
gd->ram_base = ULONG_MAX;
[...]
Thanks
Can you please add a test for this function? Perhaps test/dm/fdtdec.c might be a good place?
Regards, Simon
- Jiaxun

Am 11. Juni 2024 20:51:55 MESZ schrieb Simon Glass sjg@chromium.org:
Hi Jiaxun,
On Tue, 11 Jun 2024 at 07:48, Jiaxun Yang jiaxun.yang@flygoat.com wrote:
在2024年6月11日六月 下午1:26,Heinrich Schuchardt写道: Hi Heinrich,
Thanks for your comments, will fix most of them in next reversion.
[...]
gd->bd->bi_dram[bank].start = (phys_addr_t)res.start;
The conversion is superfluous.
This is necessary as phys_addr_t can be unsigned long or unsigned long long.
In C++ you would get an error. In C an assignment to an integer type of different size does not lead to a warning.
Best regards
Heinrich
[...]
- __maybe_unused const char *final_name;
- __maybe_unused int final_reg;
'__maybe_unused' is superfluous.
This is necessary as when LOG_DEBUG is disabled these two variables won't be referenced. Compilers would complain about it.
gd->ram_base = (unsigned long)~0;
gd->ram_base = ULONG_MAX;
[...]
Thanks
Can you please add a test for this function? Perhaps test/dm/fdtdec.c might be a good place?
Regards, Simon
- Jiaxun

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 --- 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

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 --- 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 e394c1ad9093..024b6adc75e7 100644 --- a/arch/arm/lib/image.c +++ b/arch/arm/lib/image.c @@ -30,7 +30,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; @@ -73,6 +73,7 @@ int booti_setup(ulong image, ulong *relocated_addr, ulong *size, dst = gd->bd->bi_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..2fd1f6c535ae 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 44ba8b52e139..4ef34c81d6d2 100644 --- a/arch/sandbox/lib/bootm.c +++ b/arch/sandbox/lib/bootm.c @@ -83,7 +83,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 032f5a4a1605..770300132891 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 b9637b3ec3d8..9586a4c58ac1 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; @@ -73,7 +74,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;
@@ -84,7 +85,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 e06bc75d36b2..52a4bee13728 100644 --- a/common/spl/spl.c +++ b/common/spl/spl.c @@ -113,7 +113,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; } @@ -324,13 +325,13 @@ int spl_parse_image_header(struct spl_image_info *spl_image,
#if CONFIG_IS_ENABLED(OS_BOOT) #if defined(CMD_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(SPL_TPL_PROMPT "payload Image, load addr: 0x%lx size: %d\n", diff --git a/include/image.h b/include/image.h index acffd17e0dfd..a2bfc7bb19a3 100644 --- a/include/image.h +++ b/include/image.h @@ -1061,11 +1061,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_) */

On 22.05.24 17:34, Jiaxun Yang wrote:
For LoongArch the start of the image is not the entry point to the image.
Looking at arch/loongarch/kernel/head.S there seem to be two cases:
* The kernel has an EFI stub (CONFIG_EFI_STUB=y). The legacy physical entry point is available at offset 0x08 of the header. * The kernel has no EFI stub. The kernel entry point matches the start of the image.
Where do you differentiate between the cases?
Best regards
Heinrich
We refactor the code base to allow entry point to be supplied by setup_booti.
Signed-off-by: Jiaxun Yang jiaxun.yang@flygoat.com
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 e394c1ad9093..024b6adc75e7 100644 --- a/arch/arm/lib/image.c +++ b/arch/arm/lib/image.c @@ -30,7 +30,7 @@ struct Image_header { };
int booti_setup(ulong image, ulong *relocated_addr, ulong *size,
bool force_reloc)
{ struct Image_header *ih; uint64_t dst;ulong *entry, bool force_reloc)
@@ -73,6 +73,7 @@ int booti_setup(ulong image, ulong *relocated_addr, ulong *size, dst = gd->bd->bi_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..2fd1f6c535ae 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)
{ struct linux_image_h *lhdr;ulong entry, bool force_reloc)
@@ -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 44ba8b52e139..4ef34c81d6d2 100644 --- a/arch/sandbox/lib/bootm.c +++ b/arch/sandbox/lib/bootm.c @@ -83,7 +83,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)
{ log_err("Booting is not supported on the sandbox.\n");ulong entry, bool force_reloc)
diff --git a/boot/bootm.c b/boot/bootm.c index 032f5a4a1605..770300132891 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;
int ret;ulong entry;
ret = booti_setup(load, &relocated_addr, &image_size, false);
if (ret) { printf("Failed to prep arm64 kernel (err=%d)\n", ret); return BOOTM_ERR_RESET;ret = booti_setup(load, &relocated_addr, &image_size, &entry, false);
@@ -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->os.start = relocated_addr; images->os.end = relocated_addr + image_size; }images->ep = entry;
diff --git a/cmd/booti.c b/cmd/booti.c index b9637b3ec3d8..9586a4c58ac1 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;
@@ -73,7 +74,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;
@@ -84,7 +85,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 e06bc75d36b2..52a4bee13728 100644 --- a/common/spl/spl.c +++ b/common/spl/spl.c @@ -113,7 +113,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,
{ return 1; }ulong *entry, bool force_reloc)
@@ -324,13 +325,13 @@ int spl_parse_image_header(struct spl_image_info *spl_image,
#if CONFIG_IS_ENABLED(OS_BOOT) #if defined(CMD_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(SPL_TPL_PROMPT "payload Image, load addr: 0x%lx size: %d\n",
diff --git a/include/image.h b/include/image.h index acffd17e0dfd..a2bfc7bb19a3 100644 --- a/include/image.h +++ b/include/image.h @@ -1061,11 +1061,12 @@ int bootz_setup(ulong image, ulong *start, ulong *end);
- @image: Address of image
- @start: Returns start address of image
- @size : Returns size image
*/ int booti_setup(ulong image, ulong *relocated_addr, ulong *size,
- @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
bool force_reloc);
ulong *entry, bool force_reloc);
/*******************************************************************/ /* New uImage format specific code (prefixed with fit_) */

在2024年6月11日六月 下午2:02,Heinrich Schuchardt写道:
On 22.05.24 17:34, Jiaxun Yang wrote:
For LoongArch the start of the image is not the entry point to the image.
Looking at arch/loongarch/kernel/head.S there seem to be two cases:
- The kernel has an EFI stub (CONFIG_EFI_STUB=y). The legacy physical entry point is available at offset 0x08 of the
header.
- The kernel has no EFI stub. The kernel entry point matches the start of the image.
Where do you differentiate between the cases?
Hi Heinrich,
In case there is no EFI stub LoongArch would use elf format vmlinux, there is no real "raw" image for us.
bootelf can't be used at the moment as it doesn't setup FDT and other environments properly.
I'm planning to implement a bootlinuxelf command for this case, as MIPS, LoongArch, xtensa are all using ELF as default kernel image format.
Thanks - Jiaxun
[...]

On Tue, Jun 11, 2024 at 02:29:38PM +0100, Jiaxun Yang wrote:
在2024年6月11日六月 下午2:02,Heinrich Schuchardt写道:
On 22.05.24 17:34, Jiaxun Yang wrote:
For LoongArch the start of the image is not the entry point to the image.
Looking at arch/loongarch/kernel/head.S there seem to be two cases:
- The kernel has an EFI stub (CONFIG_EFI_STUB=y). The legacy physical entry point is available at offset 0x08 of the
header.
- The kernel has no EFI stub. The kernel entry point matches the start of the image.
Where do you differentiate between the cases?
Hi Heinrich,
In case there is no EFI stub LoongArch would use elf format vmlinux, there is no real "raw" image for us.
bootelf can't be used at the moment as it doesn't setup FDT and other environments properly.
I'm planning to implement a bootlinuxelf command for this case, as MIPS, LoongArch, xtensa are all using ELF as default kernel image format.
Please note that we have CONFIG_CMD_ELF_FDT_SETUP already, so adjusting things so that bootelf works for this case should be doable without a new command.

在2024年6月11日六月 下午2:52,Tom Rini写道:
On Tue, Jun 11, 2024 at 02:29:38PM +0100, Jiaxun Yang wrote:
在2024年6月11日六月 下午2:02,Heinrich Schuchardt写道:
On 22.05.24 17:34, Jiaxun Yang wrote:
For LoongArch the start of the image is not the entry point to the image.
Looking at arch/loongarch/kernel/head.S there seem to be two cases:
- The kernel has an EFI stub (CONFIG_EFI_STUB=y). The legacy physical entry point is available at offset 0x08 of the
header.
- The kernel has no EFI stub. The kernel entry point matches the start of the image.
Where do you differentiate between the cases?
Hi Heinrich,
In case there is no EFI stub LoongArch would use elf format vmlinux, there is no real "raw" image for us.
bootelf can't be used at the moment as it doesn't setup FDT and other environments properly.
I'm planning to implement a bootlinuxelf command for this case, as MIPS, LoongArch, xtensa are all using ELF as default kernel image format.
Please note that we have CONFIG_CMD_ELF_FDT_SETUP already, so adjusting things so that bootelf works for this case should be doable without a new command.
This is a little bit broken as then you'll need to bring architecture specific functions to bootelf to setup boot registers, initrd etc. It's fine for Arm64 which you just need to throw fdt into a location in memory but for MIPS and LoongArch you have to setup a good deal of other stuff.
Ideally those setups should be done with bootm_run_states as what we've done at booti, but that would be a semantic to bootelf command. I know many existing MIPS bare-metal applications rely on argc/argv style bootelf and I don't want to break them, thus I think a new command is necessary.
Thanks
-- Tom
附件:
- signature.asc

On Tue, Jun 11, 2024 at 03:01:00PM +0100, Jiaxun Yang wrote:
在2024年6月11日六月 下午2:52,Tom Rini写道:
On Tue, Jun 11, 2024 at 02:29:38PM +0100, Jiaxun Yang wrote:
在2024年6月11日六月 下午2:02,Heinrich Schuchardt写道:
On 22.05.24 17:34, Jiaxun Yang wrote:
For LoongArch the start of the image is not the entry point to the image.
Looking at arch/loongarch/kernel/head.S there seem to be two cases:
- The kernel has an EFI stub (CONFIG_EFI_STUB=y). The legacy physical entry point is available at offset 0x08 of the
header.
- The kernel has no EFI stub. The kernel entry point matches the start of the image.
Where do you differentiate between the cases?
Hi Heinrich,
In case there is no EFI stub LoongArch would use elf format vmlinux, there is no real "raw" image for us.
bootelf can't be used at the moment as it doesn't setup FDT and other environments properly.
I'm planning to implement a bootlinuxelf command for this case, as MIPS, LoongArch, xtensa are all using ELF as default kernel image format.
Please note that we have CONFIG_CMD_ELF_FDT_SETUP already, so adjusting things so that bootelf works for this case should be doable without a new command.
This is a little bit broken as then you'll need to bring architecture specific functions to bootelf to setup boot registers, initrd etc. It's fine for Arm64 which you just need to throw fdt into a location in memory but for MIPS and LoongArch you have to setup a good deal of other stuff.
Ideally those setups should be done with bootm_run_states as what we've done at booti, but that would be a semantic to bootelf command. I know many existing MIPS bare-metal applications rely on argc/argv style bootelf and I don't want to break them, thus I think a new command is necessary.
We should discuss this in its own thread, yeah. It's been a long while since I had to bootelf something non-trivial and one of the issues is that yes, a bunch of quiesce the system functionality wasn't done. Maybe it's just a matter of adding a flag to bootelf to say we're booting an OS rather than simple app and so call the normal boot os prep function chain.

They all come from glibc's elf.h
Signed-off-by: Jiaxun Yang jiaxun.yang@flygoat.com --- include/elf.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/include/elf.h b/include/elf.h index a4ba74d8abeb..cb3bb20c4f2e 100644 --- a/include/elf.h +++ b/include/elf.h @@ -219,7 +219,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 */ @@ -699,6 +700,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__ int valid_elf_image(unsigned long addr); unsigned long load_elf64_image_phdr(unsigned long addr);

On 5/22/24 17:34, Jiaxun Yang wrote:
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
include/elf.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/include/elf.h b/include/elf.h index a4ba74d8abeb..cb3bb20c4f2e 100644 --- a/include/elf.h +++ b/include/elf.h @@ -219,7 +219,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 */
@@ -699,6 +700,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__ int valid_elf_image(unsigned long addr); unsigned long load_elf64_image_phdr(unsigned long addr);

Allocate the next value to IH_ARCH_LOONGARCH.
Signed-off-by: Jiaxun Yang jiaxun.yang@flygoat.com --- boot/image.c | 1 + include/image.h | 1 + 2 files changed, 2 insertions(+)
diff --git a/boot/image.c b/boot/image.c index 073931cd7a3f..8955a095713d 100644 --- a/boot/image.c +++ b/boot/image.c @@ -96,6 +96,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 a2bfc7bb19a3..1dd6dfb82437 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, };

On 5/22/24 17:34, Jiaxun Yang wrote:
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
boot/image.c | 1 + include/image.h | 1 + 2 files changed, 2 insertions(+)
diff --git a/boot/image.c b/boot/image.c index 073931cd7a3f..8955a095713d 100644 --- a/boot/image.c +++ b/boot/image.c @@ -96,6 +96,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 a2bfc7bb19a3..1dd6dfb82437 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, };

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 --- 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 | 13 + arch/loongarch/include/asm/acpi_table.h | 8 + arch/loongarch/include/asm/addrspace.h | 87 ++ .../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 | 1468 ++++++++++++++++++++ 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 + 38 files changed, 3349 insertions(+)
diff --git a/arch/Kconfig b/arch/Kconfig index abd406d48841..236b0e637385 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -70,6 +70,20 @@ config ARM select SUPPORT_ACPI 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 @@ -496,6 +510,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..a71db58d48a9 --- /dev/null +++ b/arch/loongarch/dts/Makefile @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0+ + +include $(srctree)/scripts/Makefile.dts + +targets += $(dtb-y) + +DTC_FLAGS += -R 4 -p 0x1000 + +PHONY += dtbs +dtbs: $(addprefix $(obj)/, $(dtb-y)) + @: + +clean-files := *.dtb 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..b61be44587e6 --- /dev/null +++ b/arch/loongarch/include/asm/addrspace.h @@ -0,0 +1,87 @@ +/* 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..ba379dac3d98 --- /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 + */ +#ifndef __loongarch64 +#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..a5819aa90ced --- /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 priviledged + * 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..95b5f45bce2f --- /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..f6c8cc372349 --- /dev/null +++ b/arch/loongarch/include/asm/loongarch.h @@ -0,0 +1,1468 @@ +/* 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 +# +

On 22.05.24 17:34, Jiaxun Yang wrote:
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
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 | 13 + arch/loongarch/include/asm/acpi_table.h | 8 + arch/loongarch/include/asm/addrspace.h | 87 ++ .../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 | 1468 ++++++++++++++++++++ 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 + 38 files changed, 3349 insertions(+)
diff --git a/arch/Kconfig b/arch/Kconfig index abd406d48841..236b0e637385 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -70,6 +70,20 @@ config ARM select SUPPORT_ACPI 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
@@ -496,6 +510,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
While having short symbols is generally good, I would prefer something self explanatory: ARCH_LOONGARCH64.
Best regards
Heinrich
- 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..a71db58d48a9 --- /dev/null +++ b/arch/loongarch/dts/Makefile @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0+
+include $(srctree)/scripts/Makefile.dts
+targets += $(dtb-y)
+DTC_FLAGS += -R 4 -p 0x1000
+PHONY += dtbs +dtbs: $(addprefix $(obj)/, $(dtb-y))
- @:
+clean-files := *.dtb 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..b61be44587e6 --- /dev/null +++ b/arch/loongarch/include/asm/addrspace.h @@ -0,0 +1,87 @@ +/* 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..ba379dac3d98 --- /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
- */
+#ifndef __loongarch64 +#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..a5819aa90ced --- /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 priviledged
- 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..95b5f45bce2f --- /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..f6c8cc372349 --- /dev/null +++ b/arch/loongarch/include/asm/loongarch.h @@ -0,0 +1,1468 @@ +/* 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 +#

Add some common library routines for the architecture.
Signed-off-by: Jiaxun Yang jiaxun.yang@flygoat.com --- arch/loongarch/lib/Makefile | 7 ++++ arch/loongarch/lib/asm-offsets.c | 66 ++++++++++++++++++++++++++++++++++++ arch/loongarch/lib/boot.c | 14 ++++++++ arch/loongarch/lib/cache.c | 73 ++++++++++++++++++++++++++++++++++++++++ arch/loongarch/lib/reset.c | 14 ++++++++ arch/loongarch/lib/setjmp.S | 52 ++++++++++++++++++++++++++++ 6 files changed, 226 insertions(+)
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..54566edef8a3 --- /dev/null +++ b/arch/loongarch/lib/cache.c @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2024 Jiaxun Yang jiaxun.yang@flygoat.com + */ + +#include <cpu_func.h> +#include <asm/cache.h> +#include <asm/loongarch.h> + +void invalidate_icache_all(void) +{ + asm volatile ("\tibar 0\n"::); +} + +__weak void flush_dcache_all(void) +{ + asm volatile ("\tdbar 0\n"::); +} + +__weak void flush_dcache_range(unsigned long start, unsigned long end) +{ + /* Placeholder */ + flush_dcache_all(); +} + +__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) +{ + /* Placeholder */ + flush_dcache_all(); +} + +__weak void cache_flush(void) +{ + /* Placeholder */ + flush_dcache_all(); +} + +__weak void cache_invalidate(void) +{ + /* Placeholder */ + flush_dcache_all(); +} + +__weak void flush_cache(unsigned long addr, unsigned long size) +{ + cache_flush(); +} + +__weak void dcache_enable(void) +{ +} + +__weak void dcache_disable(void) +{ +} + +__weak int dcache_status(void) +{ + return 0; +} + +__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

On 5/22/24 17:34, Jiaxun Yang wrote:
Add some common library routines for the architecture.
Signed-off-by: Jiaxun Yang jiaxun.yang@flygoat.com
arch/loongarch/lib/Makefile | 7 ++++ arch/loongarch/lib/asm-offsets.c | 66 ++++++++++++++++++++++++++++++++++++ arch/loongarch/lib/boot.c | 14 ++++++++ arch/loongarch/lib/cache.c | 73 ++++++++++++++++++++++++++++++++++++++++ arch/loongarch/lib/reset.c | 14 ++++++++ arch/loongarch/lib/setjmp.S | 52 ++++++++++++++++++++++++++++ 6 files changed, 226 insertions(+)
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..54566edef8a3 --- /dev/null +++ b/arch/loongarch/lib/cache.c @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- Copyright (C) 2024 Jiaxun Yang jiaxun.yang@flygoat.com
- */
+#include <cpu_func.h> +#include <asm/cache.h> +#include <asm/loongarch.h>
+void invalidate_icache_all(void) +{
- asm volatile ("\tibar 0\n"::);
According to https://loongson.github.io/LoongArch-Documentation/LoongArch-Vol1-EN.html#_d... this is not invalidating the instruction cache.
After loading an image into memory and before executing it we must invalidate the instruction cache to ensure that the newly loaded code is executed.
I guess you want to use CACOP here.
+}
+__weak void flush_dcache_all(void)
In cmd/cache.c we have another __weak implementation. How is the linke:w meant to know which one to use?
I guess we need to fix cmd/cache.c. But that is beyond the scope of this series.
+{
- asm volatile ("\tdbar 0\n"::);
CACOP?
Best regards
Heinrich
+}
+__weak void flush_dcache_range(unsigned long start, unsigned long end) +{
- /* Placeholder */
- flush_dcache_all();
+}
+__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) +{
- /* Placeholder */
- flush_dcache_all();
+}
+__weak void cache_flush(void) +{
- /* Placeholder */
- flush_dcache_all();
+}
+__weak void cache_invalidate(void) +{
- /* Placeholder */
- flush_dcache_all();
+}
+__weak void flush_cache(unsigned long addr, unsigned long size) +{
- cache_flush();
+}
+__weak void dcache_enable(void) +{ +}
+__weak void dcache_disable(void) +{ +}
+__weak int dcache_status(void) +{
- return 0;
+}
+__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

在2024年6月16日六月 下午12:01,Heinrich Schuchardt写道:
On 5/22/24 17:34, Jiaxun Yang wrote:
Add some common library routines for the architecture.
Signed-off-by: Jiaxun Yang jiaxun.yang@flygoat.com
arch/loongarch/lib/Makefile | 7 ++++ arch/loongarch/lib/asm-offsets.c | 66 ++++++++++++++++++++++++++++++++++++ arch/loongarch/lib/boot.c | 14 ++++++++ arch/loongarch/lib/cache.c | 73 ++++++++++++++++++++++++++++++++++++++++ arch/loongarch/lib/reset.c | 14 ++++++++ arch/loongarch/lib/setjmp.S | 52 ++++++++++++++++++++++++++++ 6 files changed, 226 insertions(+)
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..54566edef8a3 --- /dev/null +++ b/arch/loongarch/lib/cache.c @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- Copyright (C) 2024 Jiaxun Yang jiaxun.yang@flygoat.com
- */
+#include <cpu_func.h> +#include <asm/cache.h> +#include <asm/loongarch.h>
+void invalidate_icache_all(void) +{
- asm volatile ("\tibar 0\n"::);
According to https://loongson.github.io/LoongArch-Documentation/LoongArch-Vol1-EN.html#_d... this is not invalidating the instruction cache.
After loading an image into memory and before executing it we must invalidate the instruction cache to ensure that the newly loaded code is executed.
I guess you want to use CACOP here.
Yes, I haven't thought about that yet :-( As this series is only concerning QEMU machine, I left all cache stuff blank.
I'll add it to future TODOs.
Thanks - Jiaxun
+}
+__weak void flush_dcache_all(void)
In cmd/cache.c we have another __weak implementation. How is the linke:w meant to know which one to use?
I guess we need to fix cmd/cache.c. But that is beyond the scope of this series.
+{
- asm volatile ("\tdbar 0\n"::);
CACOP?
Best regards
Heinrich

On 6/16/24 15:06, Jiaxun Yang wrote:
在2024年6月16日六月 下午12:01,Heinrich Schuchardt写道:
On 5/22/24 17:34, Jiaxun Yang wrote:
Add some common library routines for the architecture.
Signed-off-by: Jiaxun Yang jiaxun.yang@flygoat.com
arch/loongarch/lib/Makefile | 7 ++++ arch/loongarch/lib/asm-offsets.c | 66 ++++++++++++++++++++++++++++++++++++ arch/loongarch/lib/boot.c | 14 ++++++++ arch/loongarch/lib/cache.c | 73 ++++++++++++++++++++++++++++++++++++++++ arch/loongarch/lib/reset.c | 14 ++++++++ arch/loongarch/lib/setjmp.S | 52 ++++++++++++++++++++++++++++ 6 files changed, 226 insertions(+)
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..54566edef8a3 --- /dev/null +++ b/arch/loongarch/lib/cache.c @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- Copyright (C) 2024 Jiaxun Yang jiaxun.yang@flygoat.com
- */
+#include <cpu_func.h> +#include <asm/cache.h> +#include <asm/loongarch.h>
+void invalidate_icache_all(void) +{
- asm volatile ("\tibar 0\n"::);
According to https://loongson.github.io/LoongArch-Documentation/LoongArch-Vol1-EN.html#_d... this is not invalidating the instruction cache.
After loading an image into memory and before executing it we must invalidate the instruction cache to ensure that the newly loaded code is executed.
I guess you want to use CACOP here.
Yes, I haven't thought about that yet :-( As this series is only concerning QEMU machine, I left all cache stuff blank.
I'll add it to future TODOs.
Thanks
- Jiaxun
The "LoongArch Reference Manual" is available at:
https://loongson.github.io/LoongArch-Documentation/LoongArch-Vol1-EN.html#_c...
What irritates me in 2.1.7.1. Cache Coherency Maintenance of Instruction Cache is the word *can*:
The Cache coherency maintenance between the instruction Cache and the data Cache within the processor core *can* be implemented as hardware maintenance.
Maybe you have to consult the Chinese version.
处理器核内部指令 Cache 与数据 Cache 之间的缓存一致性维护可以实现为硬件维护
The cache consistency maintenance between the instruction cache and data cache inside the processor core *can* be implemented as hardware maintenance.
Best regards
Heinrich
+}
+__weak void flush_dcache_all(void)
In cmd/cache.c we have another __weak implementation. How is the linke:w meant to know which one to use?
I guess we need to fix cmd/cache.c. But that is beyond the scope of this series.
+{
- asm volatile ("\tdbar 0\n"::);
CACOP?
Best regards
Heinrich

在2024年6月16日六月 下午5:00,Heinrich Schuchardt写道: [...]
The "LoongArch Reference Manual" is available at:
https://loongson.github.io/LoongArch-Documentation/LoongArch-Vol1-EN.html#_c...
What irritates me in 2.1.7.1. Cache Coherency Maintenance of Instruction Cache is the word *can*:
The Cache coherency maintenance between the instruction Cache and the data Cache within the processor core *can* be implemented as hardware maintenance.
Maybe you have to consult the Chinese version.
处理器核内部指令 Cache 与数据 Cache 之间的缓存一致性维护可以实现为硬件维护
The cache consistency maintenance between the instruction cache and data cache inside the processor core *can* be implemented as hardware maintenance.
Hi Heinrich,
Thanks for the investigation! Impressive effort on decrypting Chinese semantics :-)
I had consulted Loongson folks, and they told me that all current hardware implementation do have I/D cache coherency maintained by hardware, see implementation[1] in kernel.
For dcache I'll implement it with cac_op.
Thanks [1]: https://elixir.bootlin.com/linux/v6.9.5/source/arch/loongarch/mm/cache.c
Best regards
Heinrich

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 --- arch/loongarch/cpu/Makefile | 4 + arch/loongarch/cpu/cpu.c | 28 ++++++ arch/loongarch/cpu/smp_secondary.S | 55 ++++++++++++ arch/loongarch/cpu/start.S | 169 +++++++++++++++++++++++++++++++++++++ 4 files changed, 256 insertions(+)
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..87c93c0cb20e --- /dev/null +++ b/arch/loongarch/cpu/cpu.c @@ -0,0 +1,28 @@ +// 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..1d7f02babb48 --- /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..69d52c5d7f4a --- /dev/null +++ b/arch/loongarch/cpu/start.S @@ -0,0 +1,169 @@ +/* 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 + + /* Enable cache */ + 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 t6, s4, t0 /* t6 <- 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, t6 /* t1 <- rela_dyn_start in RAM */ + PTR_ADD t2, t2, t6 /* 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, t6 /* t5 <-- location to fix up in RAM */ + PTR_ADD t3, t3, t6 /* 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, t6 + csrwr t0, LOONGARCH_CSR_EENTRY + +clear_bss: + la.pcrel t0, __bss_start /* t0 <- rel __bss_start in FLASH */ + PTR_ADD t0, t0, t6 /* t0 <- rel __bss_start in RAM */ + la.pcrel t1, __bss_end /* t1 <- rel __bss_end in FLASH */ + PTR_ADD t1, t1, t6 /* 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, t6 /* 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() */ +

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 --- 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/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..886c71034c3c --- /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 != NULL && 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; +}

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 --- arch/loongarch/lib/Makefile | 2 + arch/loongarch/lib/bootm.c | 177 ++++++++++++++++++++++++++++++++++++++++++++ arch/loongarch/lib/image.c | 66 +++++++++++++++++ cmd/Kconfig | 2 +- 4 files changed, 246 insertions(+), 1 deletion(-)
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..90d96fb47ffd --- /dev/null +++ b/arch/loongarch/lib/bootm.c @@ -0,0 +1,177 @@ +// 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); +} + +static ulong get_sp(void) +{ + ulong ret; + + asm("move %0, $sp" : "=r"(ret) : ); + return ret; +} + +void arch_lmb_reserve(struct lmb *lmb) +{ + arch_lmb_reserve_generic(lmb, get_sp(), gd->ram_top, 4096); +} 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 b026439c7731..97a5c2a1da7f 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -328,7 +328,7 @@ config CMD_BOOTZ
config CMD_BOOTI bool "booti" - depends on ARM64 || RISCV || SANDBOX + depends on ARM64 || LOONGARCH || RISCV || SANDBOX default y help Boot an AArch64 Linux Kernel image from memory.

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 --- 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(+)
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(); +}

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 --- drivers/cpu/Kconfig | 6 ++ drivers/cpu/Makefile | 1 + drivers/cpu/loongarch_cpu.c | 148 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 155 insertions(+)
diff --git a/drivers/cpu/Kconfig b/drivers/cpu/Kconfig index 1c3c810651ef..9cee9285194b 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 d4bbf6fa5e05..914819712f79 100644 --- a/drivers/cpu/Makefile +++ b/drivers/cpu/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_ARCH_IMX8) += imx8_cpu.o obj-$(CONFIG_ARCH_AT91) += at91_cpu.o obj-$(CONFIG_ARCH_MEDIATEK) += mtk_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..8ce6746054ff --- /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 || ret == -ENOTSUPP) + 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, +};

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 --- drivers/timer/Kconfig | 8 +++ drivers/timer/Makefile | 1 + drivers/timer/loongarch_timer.c | 112 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 121 insertions(+)
diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig index 60519c3b536c..e85c74a537ad 100644 --- a/drivers/timer/Kconfig +++ b/drivers/timer/Kconfig @@ -340,4 +340,12 @@ config STARFIVE_TIMER Select this to enable support for the timer found on Starfive SoC.
+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 b93145e8d437..632d7ac8fd83 100644 --- a/drivers/timer/Makefile +++ b/drivers/timer/Makefile @@ -35,3 +35,4 @@ obj-$(CONFIG_MCHP_PIT64B_TIMER) += mchp-pit64b-timer.o 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_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", +};

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 --- 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 | 84 +++++++++++++++++++++++ board/emulation/qemu-loongarch/qemu-loongarch.env | 6 ++ configs/qemu-loongarch64_defconfig | 36 ++++++++++ include/configs/qemu-loongarch.h | 13 ++++ 9 files changed, 234 insertions(+)
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..5cedd2c7479e --- /dev/null +++ b/board/emulation/qemu-loongarch/qemu-loongarch.c @@ -0,0 +1,84 @@ +// 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 <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; +} + +#define addr_alloc(lmb, size) lmb_alloc(lmb, size, SZ_64K) + +int board_late_init(void) +{ + struct lmb lmb; + u32 status = 0; + + lmb_init_and_reserve(&lmb, gd->bd, (void *)gd->fdt_blob); + + status |= env_set_hex("kernel_addr_r", addr_alloc(&lmb, SZ_128M)); + status |= env_set_hex("ramdisk_addr_r", addr_alloc(&lmb, SZ_128M)); + status |= env_set_hex("kernel_comp_addr_r", addr_alloc(&lmb, SZ_64M)); + status |= env_set_hex("kernel_comp_size", SZ_64M); + status |= env_set_hex("scriptaddr", addr_alloc(&lmb, SZ_4M)); + status |= env_set_hex("pxefile_addr_r", addr_alloc(&lmb, SZ_4M)); + status |= env_set_hex("fdt_addr_r", addr_alloc(&lmb, SZ_2M)); + + if (status) + log_warning("late_init: Failed to set run time variables\n"); + + /* 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; +} + +void *board_fdt_blob_setup(int *err) +{ + *err = 0; + /* Stored the DTB address there during our init */ + return (void *)(ulong)0x100000; +} 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

They are all coming from UEFI spec, Microsoft PE sepc, or IANA websites.
Signed-off-by: Jiaxun Yang jiaxun.yang@flygoat.com --- boot/bootmeth_efi.c | 2 ++ include/asm-generic/pe.h | 2 ++ include/config_distro_bootcmd.h | 5 +++++ include/efi_default_filename.h | 2 ++ lib/efi_loader/efi_image_loader.c | 7 +++++++ lib/efi_loader/efi_runtime.c | 4 ++++ lib/efi_selftest/efi_selftest_miniapp_exception.c | 2 ++ 7 files changed, 24 insertions(+)
diff --git a/boot/bootmeth_efi.c b/boot/bootmeth_efi.c index aebc5207fc01..b0207dac49c5 100644 --- a/boot/bootmeth_efi.c +++ b/boot/bootmeth_efi.c @@ -41,6 +41,8 @@ static int get_efi_pxe_arch(void) return 0x19; else if (IS_ENABLED(CONFIG_ARCH_RV64I)) return 0x1b; + else if (IS_ENABLED(CONFIG_ARCH_LA64)) + return 0x27; else if (IS_ENABLED(CONFIG_SANDBOX)) return 0; /* not used */
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 2a136b96a6d9..f8c3a4bb70ae 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
@@ -366,6 +368,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(__loongarch64) +#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/efi_default_filename.h b/include/efi_default_filename.h index 77932984b557..fac25039fd31 100644 --- a/include/efi_default_filename.h +++ b/include/efi_default_filename.h @@ -47,6 +47,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 diff --git a/lib/efi_loader/efi_image_loader.c b/lib/efi_loader/efi_image_loader.c index 604243603289..cb0619f27e8a 100644 --- a/lib/efi_loader/efi_image_loader.c +++ b/lib/efi_loader/efi_image_loader.c @@ -50,6 +50,13 @@ static int machines[] = { #if defined(__riscv) && (__riscv_xlen == 64) IMAGE_FILE_MACHINE_RISCV64, #endif + +#if defined(__loongarch64) + IMAGE_FILE_MACHINE_LOONGARCH64, +#endif +#if defined(__loongarch32) + IMAGE_FILE_MACHINE_LOONGARCH32, +#endif 0 };
/** diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c index 011bcd04836d..45bdf45b5812 100644 --- a/lib/efi_loader/efi_runtime.c +++ b/lib/efi_loader/efi_runtime.c @@ -76,6 +76,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..1e500a5ccc35 100644 --- a/lib/efi_selftest/efi_selftest_miniapp_exception.c +++ b/lib/efi_selftest/efi_selftest_miniapp_exception.c @@ -35,6 +35,8 @@ 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) + asm volatile ("break 0xf\n"); #elif defined(CONFIG_SANDBOX) #if (HOST_ARCH == HOST_ARCH_ARM || HOST_ARCH == HOST_ARCH_AARCH64) asm volatile (".word 0xe7f7defb\n");

On 22.05.24 17:34, Jiaxun Yang wrote:
They are all coming from UEFI spec, Microsoft PE sepc,
%s/PE sepc/PE-COFF specification/
or IANA websites.
Signed-off-by: Jiaxun Yang jiaxun.yang@flygoat.com
boot/bootmeth_efi.c | 2 ++ include/asm-generic/pe.h | 2 ++ include/config_distro_bootcmd.h | 5 +++++ include/efi_default_filename.h | 2 ++ lib/efi_loader/efi_image_loader.c | 7 +++++++ lib/efi_loader/efi_runtime.c | 4 ++++ lib/efi_selftest/efi_selftest_miniapp_exception.c | 2 ++ 7 files changed, 24 insertions(+)
diff --git a/boot/bootmeth_efi.c b/boot/bootmeth_efi.c index aebc5207fc01..b0207dac49c5 100644 --- a/boot/bootmeth_efi.c +++ b/boot/bootmeth_efi.c @@ -41,6 +41,8 @@ static int get_efi_pxe_arch(void) return 0x19; else if (IS_ENABLED(CONFIG_ARCH_RV64I)) return 0x1b;
- else if (IS_ENABLED(CONFIG_ARCH_LA64))
else if (IS_ENABLED(CONFIG_SANDBOX)) return 0; /* not used */return 0x27;
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 2a136b96a6d9..f8c3a4bb70ae 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
@@ -366,6 +368,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(__loongarch64)
Looking at https://loongson.github.io/LoongArch-Documentation/LoongArch-toolchain-conve...:
There the following symbols are mentioned:
__loongarch__ __loongarch_grlen
Table 15. C/C++ Built-in Macros Provided for Compatibility with Historical Code marks __loongarch64 as deprecated.
+#define BOOTENV_EFI_PXE_ARCH "0x27" +#define BOOTENV_EFI_PXE_VCI "PXEClient:Arch:00039:UNDI:003000"
Where are the 32bit defines?
Cf. https://www.iana.org/assignments/dhcpv6-parameters/dhcpv6-parameters.xhtml
0x00 0x25 LoongArch 32-bit UEFI 0x00 0x26 LoongArch 32-bit UEFI boot from http 0x00 0x27 LoongArch 64-bit UEFI 0x00 0x28 LoongArch 64-bit UEFI boot from http
#elif defined(CONFIG_SANDBOX) # error "sandbox EFI support is only supported on ARM and x86" #else diff --git a/include/efi_default_filename.h b/include/efi_default_filename.h index 77932984b557..fac25039fd31 100644 --- a/include/efi_default_filename.h +++ b/include/efi_default_filename.h @@ -47,6 +47,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 diff --git a/lib/efi_loader/efi_image_loader.c b/lib/efi_loader/efi_image_loader.c index 604243603289..cb0619f27e8a 100644 --- a/lib/efi_loader/efi_image_loader.c +++ b/lib/efi_loader/efi_image_loader.c @@ -50,6 +50,13 @@ static int machines[] = { #if defined(__riscv) && (__riscv_xlen == 64) IMAGE_FILE_MACHINE_RISCV64, #endif
+#if defined(__loongarch64)
marks __loongarch64 is deprecated.
- IMAGE_FILE_MACHINE_LOONGARCH64,
+#endif +#if defined(__loongarch32)
ditto
- IMAGE_FILE_MACHINE_LOONGARCH32,
+#endif 0 };
/** diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c index 011bcd04836d..45bdf45b5812 100644 --- a/lib/efi_loader/efi_runtime.c +++ b/lib/efi_loader/efi_runtime.c @@ -76,6 +76,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..1e500a5ccc35 100644 --- a/lib/efi_selftest/efi_selftest_miniapp_exception.c +++ b/lib/efi_selftest/efi_selftest_miniapp_exception.c @@ -35,6 +35,8 @@ 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)
- asm volatile ("break 0xf\n");
Can we use an undefined instruction here as for the other architectures, please.
Best regards
Heinrich
#elif defined(CONFIG_SANDBOX) #if (HOST_ARCH == HOST_ARCH_ARM || HOST_ARCH == HOST_ARCH_AARCH64) asm volatile (".word 0xe7f7defb\n");

在2024年5月23日五月 下午5:14,Heinrich Schuchardt写道: [...]
Looking at https://loongson.github.io/LoongArch-Documentation/LoongArch-toolchain-conve...:
There the following symbols are mentioned:
__loongarch__ __loongarch_grlen
Table 15. C/C++ Built-in Macros Provided for Compatibility with Historical Code marks __loongarch64 as deprecated.
Thanks, will use new macros instead.
+#define BOOTENV_EFI_PXE_ARCH "0x27" +#define BOOTENV_EFI_PXE_VCI "PXEClient:Arch:00039:UNDI:003000"
Where are the 32bit defines?
Since we don't have CONFIG_ARCH_LA32 in U-Boot yet I leave 32 bit alone. Those will need to be added when we get 32-bit ready.
Cf. https://www.iana.org/assignments/dhcpv6-parameters/dhcpv6-parameters.xhtml
0x00 0x25 LoongArch 32-bit UEFI 0x00 0x26 LoongArch 32-bit UEFI boot from http 0x00 0x27 LoongArch 64-bit UEFI 0x00 0x28 LoongArch 64-bit UEFI boot from http
[...]
+#elif defined(CONFIG_LOONGARCH)
- asm volatile ("break 0xf\n");
Can we use an undefined instruction here as for the other architectures, please.
LoongArch have way too many hidden opcodes that is not documented & will not trigger exception. It's pretty hard for me to identify an opcode that can trigger exception on all hardware (and including future hardware).
Meanwhile, breakpoint instruction with an invalid hint can always generate an SIGILL.
Thanks
Best regards
Heinrich
#elif defined(CONFIG_SANDBOX) #if (HOST_ARCH == HOST_ARCH_ARM || HOST_ARCH == HOST_ARCH_AARCH64) asm volatile (".word 0xe7f7defb\n");

Implement crt, reloc, linker scripts, wire things up in Makefiles and Kconfig.
Signed-off-by: Jiaxun Yang jiaxun.yang@flygoat.com --- 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 +- 6 files changed, 382 insertions(+), 1 deletion(-)
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..5be47045ad8a --- /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> + +#ifdef __loongarch64 +#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 */ +#ifndef __loongarch64 + .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..32a7d792103d --- /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> + +#ifdef __loongarch64 +#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 430bb7f0f7dc..1d82a062a215 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -5,7 +5,7 @@ config EFI_LOADER SYS_CPU = arm1176 || \ SYS_CPU = armv7 || \ SYS_CPU = armv8) || \ - X86 || RISCV || SANDBOX) + X86 || RISCV || LOONGARCH || SANDBOX) # We need EFI_STUB_64BIT to be set on x86_64 with EFI_STUB depends on !EFI_STUB || !X86_64 || EFI_STUB_64BIT # We need EFI_STUB_32BIT to be set on x86_32 with EFI_STUB

On 22.05.24 17:34, Jiaxun Yang wrote:
Implement crt, reloc, linker scripts, wire things up in Makefiles and Kconfig.
Signed-off-by: Jiaxun Yang jiaxun.yang@flygoat.com
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 +- 6 files changed, 382 insertions(+), 1 deletion(-)
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..5be47045ad8a --- /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>
+#ifdef __loongarch64 +#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 */
+#ifndef __loongarch64
- .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..32a7d792103d --- /dev/null +++ b/arch/loongarch/lib/reloc_loongarch_efi.c
The code seems to be very similar for all architectures. I wonder if one implementation could cover them all.
Best regards
Heinrich
@@ -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>
+#ifdef __loongarch64 +#define Elf_Dyn Elf64_Dyn +#define Elf_Rela Elf64_Rela +#define ELF_R_TYPE ELF64_R_TYPE +#else +#define Elf_Dyn Elf32_Dyn +#defiggne 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 430bb7f0f7dc..1d82a062a215 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -5,7 +5,7 @@ config EFI_LOADER SYS_CPU = arm1176 || \ SYS_CPU = armv7 || \ SYS_CPU = armv8) || \
X86 || RISCV || SANDBOX)
# We need EFI_STUB_64BIT to be set on x86_64 with EFI_STUB depends on !EFI_STUB || !X86_64 || EFI_STUB_64BIT # We need EFI_STUB_32BIT to be set on x86_32 with EFI_STUBX86 || RISCV || LOONGARCH || SANDBOX)

在2024年5月23日五月 下午5:26,Heinrich Schuchardt写道:
diff --git a/arch/loongarch/lib/reloc_loongarch_efi.c b/arch/loongarch/lib/reloc_loongarch_efi.c new file mode 100644 index 000000000000..32a7d792103d --- /dev/null +++ b/arch/loongarch/lib/reloc_loongarch_efi.c
The code seems to be very similar for all architectures. I wonder if one implementation could cover them all.
Not for MIPS due to differences on psABI dynamic relocations. We still need to handle differences between Rel and Rela and other tiny bits.
I think most architectures have their relocation handling code rooted from gnu-efi.
Thanks - Jiaxun
Best regards
Heinrich

On Wed, May 22, 2024 at 04:34:43PM +0100, Jiaxun Yang wrote:
Hi all,
Sorry for flooding the mailing list recently, yet another huge RFC series ahead.
So after working on MIPS, arm64be and Xtensa I'm now on LoongArch, as suggested by Heinrich.
My big feedback here, and it applies to all of your other series as well, is to please update CI to make use of and test this. On the Docker side, update tools/docker/Dockerfile as needed. For Azure, you can tell it to use a different image and then follow the documentation on https://docs.u-boot.org/en/latest/develop/ci_testing.html and for GitLab you can at least use their "linter" to make sure that your additions have the correct syntax. Thanks.

在2024年5月23日五月 下午4:25,Tom Rini写道:
On Wed, May 22, 2024 at 04:34:43PM +0100, Jiaxun Yang wrote:
Hi all,
Sorry for flooding the mailing list recently, yet another huge RFC series ahead.
So after working on MIPS, arm64be and Xtensa I'm now on LoongArch, as suggested by Heinrich.
My big feedback here, and it applies to all of your other series as well, is to please update CI to make use of and test this. On the Docker side, update tools/docker/Dockerfile as needed. For Azure, you can tell it to use a different image and then follow the documentation on https://docs.u-boot.org/en/latest/develop/ci_testing.html and for GitLab you can at least use their "linter" to make sure that your additions have the correct syntax. Thanks.
Hi Tom,
Thanks for the feedback, I thought CI is for custodians only :-)
Do you mean I should include azure/gitlab pipeline file to create pipeline for those new qemu targets?
Thanks
-- Tom
附件:
- signature.asc

On Thu, May 23, 2024 at 04:38:52PM +0100, Jiaxun Yang wrote:
在2024年5月23日五月 下午4:25,Tom Rini写道:
On Wed, May 22, 2024 at 04:34:43PM +0100, Jiaxun Yang wrote:
Hi all,
Sorry for flooding the mailing list recently, yet another huge RFC series ahead.
So after working on MIPS, arm64be and Xtensa I'm now on LoongArch, as suggested by Heinrich.
My big feedback here, and it applies to all of your other series as well, is to please update CI to make use of and test this. On the Docker side, update tools/docker/Dockerfile as needed. For Azure, you can tell it to use a different image and then follow the documentation on https://docs.u-boot.org/en/latest/develop/ci_testing.html and for GitLab you can at least use their "linter" to make sure that your additions have the correct syntax. Thanks.
Hi Tom,
Thanks for the feedback, I thought CI is for custodians only :-)
Do you mean I should include azure/gitlab pipeline file to create pipeline for those new qemu targets?
Yes, just like the rest of the QEMU targets.

在2024年5月23日五月 下午4:43,Tom Rini写道:
On Thu, May 23, 2024 at 04:38:52PM +0100, Jiaxun Yang wrote:
在2024年5月23日五月 下午4:25,Tom Rini写道:
On Wed, May 22, 2024 at 04:34:43PM +0100, Jiaxun Yang wrote:
Hi all,
Sorry for flooding the mailing list recently, yet another huge RFC series ahead.
So after working on MIPS, arm64be and Xtensa I'm now on LoongArch, as suggested by Heinrich.
My big feedback here, and it applies to all of your other series as well, is to please update CI to make use of and test this. On the Docker side, update tools/docker/Dockerfile as needed. For Azure, you can tell it to use a different image and then follow the documentation on https://docs.u-boot.org/en/latest/develop/ci_testing.html and for GitLab you can at least use their "linter" to make sure that your additions have the correct syntax. Thanks.
Hi Tom,
Thanks for the feedback, I thought CI is for custodians only :-)
Do you mean I should include azure/gitlab pipeline file to create pipeline for those new qemu targets?
Yes, just like the rest of the QEMU targets.
Hi Tom,
I've got CI working on azure-pipeline for my arm64be, xtensa and LoongArch work.
What is the best way to submit all these changes? I think I can send patches to update Dockerfile and CI hooks first, then after new docker image being built I'll combine CI related changes into these series and refresh all those series.
Will it work for you?
Thanks
-- Tom
附件:
- signature.asc

On Tue, Jun 04, 2024 at 11:50:20AM +0100, Jiaxun Yang wrote:
在2024年5月23日五月 下午4:43,Tom Rini写道:
On Thu, May 23, 2024 at 04:38:52PM +0100, Jiaxun Yang wrote:
在2024年5月23日五月 下午4:25,Tom Rini写道:
On Wed, May 22, 2024 at 04:34:43PM +0100, Jiaxun Yang wrote:
Hi all,
Sorry for flooding the mailing list recently, yet another huge RFC series ahead.
So after working on MIPS, arm64be and Xtensa I'm now on LoongArch, as suggested by Heinrich.
My big feedback here, and it applies to all of your other series as well, is to please update CI to make use of and test this. On the Docker side, update tools/docker/Dockerfile as needed. For Azure, you can tell it to use a different image and then follow the documentation on https://docs.u-boot.org/en/latest/develop/ci_testing.html and for GitLab you can at least use their "linter" to make sure that your additions have the correct syntax. Thanks.
Hi Tom,
Thanks for the feedback, I thought CI is for custodians only :-)
Do you mean I should include azure/gitlab pipeline file to create pipeline for those new qemu targets?
Yes, just like the rest of the QEMU targets.
Hi Tom,
I've got CI working on azure-pipeline for my arm64be, xtensa and LoongArch work.
What is the best way to submit all these changes? I think I can send patches to update Dockerfile and CI hooks first, then after new docker image being built I'll combine CI related changes into these series and refresh all those series.
Will it work for you?
Yes, please do a series that updates the Dockerfile and CI yaml files (do your best to update .gitlab-ci.yml as well, I'll fix it up if needed). Then say the other series depend on that previous one being applied. You can post an RFC patch or what have you that just changes to pointing at your test images instead and so long as it's a stand alone patch it's easy to drop. Thanks!

On Thu, 23 May 2024 at 16:39, Jiaxun Yang jiaxun.yang@flygoat.com wrote:
在2024年5月23日五月 下午4:25,Tom Rini写道:
On Wed, May 22, 2024 at 04:34:43PM +0100, Jiaxun Yang wrote:
Hi all,
Sorry for flooding the mailing list recently, yet another huge RFC series ahead.
So after working on MIPS, arm64be and Xtensa I'm now on LoongArch, as suggested by Heinrich.
My big feedback here, and it applies to all of your other series as well, is to please update CI to make use of and test this. On the Docker side, update tools/docker/Dockerfile as needed. For Azure, you can tell it to use a different image and then follow the documentation on https://docs.u-boot.org/en/latest/develop/ci_testing.html and for GitLab you can at least use their "linter" to make sure that your additions have the correct syntax. Thanks.
Hi Tom,
Thanks for the feedback, I thought CI is for custodians only :-)
Well when this lands you'll become a custodian ;-)
Do you mean I should include azure/gitlab pipeline file to create pipeline for those new qemu targets?
Thanks
-- Tom
附件:
- signature.asc
--
- Jiaxun
participants (5)
-
Heinrich Schuchardt
-
Jiaxun Yang
-
Peter Robinson
-
Simon Glass
-
Tom Rini