diff options
Diffstat (limited to 'arch/riscv')
-rw-r--r-- | arch/riscv/Kconfig | 99 | ||||
-rw-r--r-- | arch/riscv/Makefile | 5 | ||||
-rw-r--r-- | arch/riscv/cpu/generic/dram.c | 16 | ||||
-rw-r--r-- | arch/riscv/dts/binman.dtsi | 38 | ||||
-rw-r--r-- | arch/riscv/include/asm/string.h | 18 | ||||
-rw-r--r-- | arch/riscv/lib/Makefile | 3 | ||||
-rw-r--r-- | arch/riscv/lib/andes_plicsw.c | 24 | ||||
-rw-r--r-- | arch/riscv/lib/strcmp_zbb.S | 81 | ||||
-rw-r--r-- | arch/riscv/lib/strlen_zbb.S | 101 | ||||
-rw-r--r-- | arch/riscv/lib/strncmp_zbb.S | 94 |
10 files changed, 445 insertions, 34 deletions
diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 183885ebe7d..e291456530b 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -187,6 +187,97 @@ config RISCV_ISA_D riscv32 ABI from ilp32 to ilp32d and the riscv64 ABI from lp64 to lp64d. +config RISCV_ISA_ZBB + bool "Zbb extension support for bit manipulation instructions" + help + Adds ZBB extension (basic bit manipulation) to the ISA subsets + that the toolchain is allowed to emit when building U-Boot. + The Zbb extension provides instructions to accelerate a number + of bit-specific operations (count bit population, sign extending, + bitrotation, etc) and enables optimized string routines. + +menu "Use assembly optimized implementation of string routines" + +config USE_ARCH_STRLEN + bool "Use an assembly optimized implementation of strlen" + default y + depends on RISCV_ISA_ZBB + help + Enable the generation of an optimized version of strlen using + Zbb extension. + +config SPL_USE_ARCH_STRLEN + bool "Use an assembly optimized implementation of strlen for SPL" + default y if USE_ARCH_STRLEN + depends on RISCV_ISA_ZBB + depends on SPL + help + Enable the generation of an optimized version of strlen using + Zbb extension. + +config TPL_USE_ARCH_STRLEN + bool "Use an assembly optimized implementation of strlen for TPL" + default y if USE_ARCH_STRLEN + depends on RISCV_ISA_ZBB + depends on TPL + help + Enable the generation of an optimized version of strlen using + Zbb extension. + +config USE_ARCH_STRCMP + bool "Use an assembly optimized implementation of strcmp" + default y + depends on RISCV_ISA_ZBB + help + Enable the generation of an optimized version of strcmp using + Zbb extension. + +config SPL_USE_ARCH_STRCMP + bool "Use an assembly optimized implementation of strcmp for SPL" + default y if USE_ARCH_STRCMP + depends on RISCV_ISA_ZBB + depends on SPL + help + Enable the generation of an optimized version of strcmp using + Zbb extension. + +config TPL_USE_ARCH_STRCMP + bool "Use an assembly optimized implementation of strcmp for TPL" + default y if USE_ARCH_STRCMP + depends on RISCV_ISA_ZBB + depends on TPL + help + Enable the generation of an optimized version of strcmp using + Zbb extension. + +config USE_ARCH_STRNCMP + bool "Use an assembly optimized implementation of strncmp" + default y + depends on RISCV_ISA_ZBB + help + Enable the generation of an optimized version of strncmp using + Zbb extension. + +config SPL_USE_ARCH_STRNCMP + bool "Use an assembly optimized implementation of strncmp for SPL" + default y if USE_ARCH_STRNCMP + depends on RISCV_ISA_ZBB + depends on SPL + help + Enable the generation of an optimized version of strncmp using + Zbb extension. + +config TPL_USE_ARCH_STRNCMP + bool "Use an assembly optimized implementation of strncmp for TPL" + default y if USE_ARCH_STRNCMP + depends on RISCV_ISA_ZBB + depends on TPL + help + Enable the generation of an optimized version of strncmp using + Zbb extension. + +endmenu + config RISCV_ISA_A def_bool y @@ -424,4 +515,12 @@ config TPL_USE_ARCH_MEMSET endmenu +config SPL_LOAD_FIT_OPENSBI_OS_BOOT + bool "Enable SPL (OpenSBI OS boot mode) applying linux from FIT" + depends on SPL_LOAD_FIT + help + Use fw_dynamic from the FIT image, and u-boot SPL will invoke it directly. + This is a shortcut boot flow, from u-boot SPL -> OpenSBI -> u-boot proper + -> linux to u-boot SPL -> OpenSBI -> linux. + endmenu diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile index 4963b5109b2..b3ef87078b5 100644 --- a/arch/riscv/Makefile +++ b/arch/riscv/Makefile @@ -24,6 +24,9 @@ endif ifeq ($(CONFIG_RISCV_ISA_C),y) ARCH_C = c endif +ifeq ($(CONFIG_RISCV_ISA_ZBB),y) + ARCH_ZBB = _zbb +endif ifeq ($(CONFIG_CMODEL_MEDLOW),y) CMODEL = medlow endif @@ -32,7 +35,7 @@ ifeq ($(CONFIG_CMODEL_MEDANY),y) endif -RISCV_MARCH = $(ARCH_BASE)$(ARCH_A)$(ARCH_F)$(ARCH_D)$(ARCH_C) +RISCV_MARCH = $(ARCH_BASE)$(ARCH_A)$(ARCH_F)$(ARCH_D)$(ARCH_C)$(ARCH_ZBB) ABI = $(ABI_BASE)$(ABI_D) # Newer binutils versions default to ISA spec version 20191213 which moves some diff --git a/arch/riscv/cpu/generic/dram.c b/arch/riscv/cpu/generic/dram.c index 94d8018407e..1b51bae9b66 100644 --- a/arch/riscv/cpu/generic/dram.c +++ b/arch/riscv/cpu/generic/dram.c @@ -20,19 +20,3 @@ int dram_init_banksize(void) { return fdtdec_setup_memory_banksize(); } - -phys_addr_t board_get_usable_ram_top(phys_size_t total_size) -{ - /* - * Ensure that we run from first 4GB so that all - * addresses used by U-Boot are 32bit addresses. - * - * This in-turn ensures that 32bit DMA capable - * devices work fine because DMA mapping APIs will - * provide 32bit DMA addresses only. - */ - if (gd->ram_top >= SZ_4G) - return SZ_4G - 1; - - return gd->ram_top; -} diff --git a/arch/riscv/dts/binman.dtsi b/arch/riscv/dts/binman.dtsi index 156cb00971e..6b4eb8dc7b9 100644 --- a/arch/riscv/dts/binman.dtsi +++ b/arch/riscv/dts/binman.dtsi @@ -5,6 +5,9 @@ #include <config.h> +#define U64_TO_U32_H(addr) (((addr) >> 32) & 0xffffffff) +#define U64_TO_U32_L(addr) ((addr) & 0xffffffff) + / { binman: binman { multiple-images; @@ -13,26 +16,47 @@ &binman { itb { + +#ifndef CONFIG_SPL_LOAD_FIT_OPENSBI_OS_BOOT filename = "u-boot.itb"; +#else + filename = "linux.itb"; +#endif fit { description = "Configuration to load OpenSBI before U-Boot"; - #address-cells = <1>; + #address-cells = <2>; fit,fdt-list = "of-list"; images { +#ifndef CONFIG_SPL_LOAD_FIT_OPENSBI_OS_BOOT uboot { description = "U-Boot"; type = "standalone"; os = "U-Boot"; arch = "riscv"; compression = "none"; - load = <CONFIG_TEXT_BASE>; + load = <U64_TO_U32_H(CONFIG_TEXT_BASE) + U64_TO_U32_L(CONFIG_TEXT_BASE)>; uboot_blob: blob-ext { filename = "u-boot-nodtb.bin"; }; }; +#else + linux { + description = "Linux"; + type = "standalone"; + os = "Linux"; + arch = "riscv"; + compression = "none"; + load = <CONFIG_TEXT_BASE>; + + linux_blob: blob-ext { + filename = "Image"; + }; + }; +#endif opensbi { description = "OpenSBI fw_dynamic Firmware"; @@ -40,8 +64,10 @@ os = "opensbi"; arch = "riscv"; compression = "none"; - load = <CONFIG_SPL_OPENSBI_LOAD_ADDR>; - entry = <CONFIG_SPL_OPENSBI_LOAD_ADDR>; + load = <U64_TO_U32_H(CONFIG_SPL_OPENSBI_LOAD_ADDR) + U64_TO_U32_L(CONFIG_SPL_OPENSBI_LOAD_ADDR)>; + entry = <U64_TO_U32_H(CONFIG_SPL_OPENSBI_LOAD_ADDR) + U64_TO_U32_L(CONFIG_SPL_OPENSBI_LOAD_ADDR)>; opensbi_blob: opensbi { filename = "fw_dynamic.bin"; @@ -68,7 +94,11 @@ #endif description = "NAME"; firmware = "opensbi"; +#ifndef CONFIG_SPL_LOAD_FIT_OPENSBI_OS_BOOT loadables = "uboot"; +#else + loadables = "linux"; +#endif #ifndef CONFIG_OF_BOARD fdt = "fdt-SEQ"; #endif diff --git a/arch/riscv/include/asm/string.h b/arch/riscv/include/asm/string.h index 7dee3e4c9f6..38ad85fe3bb 100644 --- a/arch/riscv/include/asm/string.h +++ b/arch/riscv/include/asm/string.h @@ -40,4 +40,22 @@ extern void *memmove(void *, const void *, __kernel_size_t); #endif extern void *memset(void *, int, __kernel_size_t); +#undef __HAVE_ARCH_STRLEN +#if CONFIG_IS_ENABLED(USE_ARCH_STRLEN) +#define __HAVE_ARCH_STRLEN +#endif +extern __kernel_size_t strlen(const char *); + +#undef __HAVE_ARCH_STRCMP +#if CONFIG_IS_ENABLED(USE_ARCH_STRCMP) +#define __HAVE_ARCH_STRCMP +#endif +extern int strcmp(const char *, const char *); + +#undef __HAVE_ARCH_STRNCMP +#if CONFIG_IS_ENABLED(USE_ARCH_STRNCMP) +#define __HAVE_ARCH_STRNCMP +#endif +extern int strncmp(const char *, const char *, size_t __kernel_size_t); + #endif /* __ASM_RISCV_STRING_H */ diff --git a/arch/riscv/lib/Makefile b/arch/riscv/lib/Makefile index 02c4d8fcc6c..9a05b662fd6 100644 --- a/arch/riscv/lib/Makefile +++ b/arch/riscv/lib/Makefile @@ -42,5 +42,8 @@ extra-$(CONFIG_EFI) += $(EFI_CRT0) $(EFI_RELOC) obj-$(CONFIG_$(SPL_TPL_)USE_ARCH_MEMSET) += memset.o obj-$(CONFIG_$(SPL_TPL_)USE_ARCH_MEMMOVE) += memmove.o obj-$(CONFIG_$(SPL_TPL_)USE_ARCH_MEMCPY) += memcpy.o +obj-$(CONFIG_$(SPL_TPL_)USE_ARCH_STRLEN) += strlen_zbb.o +obj-$(CONFIG_$(SPL_TPL_)USE_ARCH_STRCMP) += strcmp_zbb.o +obj-$(CONFIG_$(SPL_TPL_)USE_ARCH_STRNCMP) += strncmp_zbb.o obj-$(CONFIG_$(SPL_TPL_)SEMIHOSTING) += semihosting.o diff --git a/arch/riscv/lib/andes_plicsw.c b/arch/riscv/lib/andes_plicsw.c index 75184080890..6fd49e873b1 100644 --- a/arch/riscv/lib/andes_plicsw.c +++ b/arch/riscv/lib/andes_plicsw.c @@ -22,7 +22,7 @@ #include <linux/err.h> /* pending register */ -#define PENDING_REG(base, hart) ((ulong)(base) + 0x1000 + ((hart) / 4) * 4) +#define PENDING_REG(base) ((ulong)(base) + 0x1000) /* enable register */ #define ENABLE_REG(base, hart) ((ulong)(base) + 0x2000 + (hart) * 0x80) /* claim register */ @@ -30,10 +30,11 @@ /* priority register */ #define PRIORITY_REG(base) ((ulong)(base) + PLICSW_PRIORITY_BASE) -#define ENABLE_HART_IPI (0x01010101) -#define SEND_IPI_TO_HART(hart) (0x1 << (hart)) +/* Bit 0 of PLIC-SW pending array is hardwired to zero, so we start from bit 1 */ +#define FIRST_AVAILABLE_BIT 0x2 +#define SEND_IPI_TO_HART(hart) (FIRST_AVAILABLE_BIT << (hart)) #define PLICSW_PRIORITY_BASE 0x4 -#define PLICSW_INTERRUPT_PER_HART 0x8 +#define PLICSW_INTERRUPT_PER_HART 0x1 DECLARE_GLOBAL_DATA_PTR; @@ -41,9 +42,8 @@ static int enable_ipi(int hart) { unsigned int en; - en = ENABLE_HART_IPI << hart; + en = FIRST_AVAILABLE_BIT << hart; writel(en, (void __iomem *)ENABLE_REG(gd->arch.plicsw, hart)); - writel(en, (void __iomem *)ENABLE_REG(gd->arch.plicsw + 0x4, hart)); return 0; } @@ -75,7 +75,7 @@ int riscv_init_ipi(void) ret = uclass_find_first_device(UCLASS_CPU, &dev); if (ret) return ret; - else if (!dev) + if (!dev) return -ENODEV; ofnode_for_each_subnode(node, dev_ofnode(dev->parent)) { @@ -105,10 +105,9 @@ int riscv_init_ipi(void) int riscv_send_ipi(int hart) { - unsigned int ipi = (SEND_IPI_TO_HART(hart) << (8 * gd->arch.boot_hart)); + unsigned int ipi = SEND_IPI_TO_HART(hart); - writel(ipi, (void __iomem *)PENDING_REG(gd->arch.plicsw, - gd->arch.boot_hart)); + writel(ipi, (void __iomem *)PENDING_REG(gd->arch.plicsw)); return 0; } @@ -125,10 +124,9 @@ int riscv_clear_ipi(int hart) int riscv_get_ipi(int hart, int *pending) { - unsigned int ipi = (SEND_IPI_TO_HART(hart) << (8 * gd->arch.boot_hart)); + unsigned int ipi = SEND_IPI_TO_HART(hart); - *pending = readl((void __iomem *)PENDING_REG(gd->arch.plicsw, - gd->arch.boot_hart)); + *pending = readl((void __iomem *)PENDING_REG(gd->arch.plicsw)); *pending = !!(*pending & ipi); return 0; diff --git a/arch/riscv/lib/strcmp_zbb.S b/arch/riscv/lib/strcmp_zbb.S new file mode 100644 index 00000000000..e5a367c0e5c --- /dev/null +++ b/arch/riscv/lib/strcmp_zbb.S @@ -0,0 +1,81 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Taken from Linux arch/riscv/lib/strcmp.S + */ + +#include <linux/linkage.h> +#include <asm/asm.h> + +ENTRY(__strcmp) +WEAK(strcmp) +.option push +.option arch,+zbb + /* + * Returns + * a0 - comparison result, value like strcmp + * + * Parameters + * a0 - string1 + * a1 - string2 + * + * Clobbers + * t0, t1, t2, t3, t4 + */ + + or t2, a0, a1 + li t4, -1 + and t2, t2, SZREG-1 + bnez t2, 3f + + /* Main loop for aligned string. */ + .p2align 3 +1: + REG_L t0, 0(a0) + REG_L t1, 0(a1) + orc.b t3, t0 + bne t3, t4, 2f + addi a0, a0, SZREG + addi a1, a1, SZREG + beq t0, t1, 1b + + /* + * Words don't match, and no null byte in the first + * word. Get bytes in big-endian order and compare. + */ +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + rev8 t0, t0 + rev8 t1, t1 +#endif + + /* Synthesize (t0 >= t1) ? 1 : -1 in a branchless sequence. */ + sltu a0, t0, t1 + neg a0, a0 + ori a0, a0, 1 + ret + +2: + /* + * Found a null byte. + * If words don't match, fall back to simple loop. + */ + bne t0, t1, 3f + + /* Otherwise, strings are equal. */ + li a0, 0 + ret + + /* Simple loop for misaligned strings. */ + .p2align 3 +3: + lbu t0, 0(a0) + lbu t1, 0(a1) + addi a0, a0, 1 + addi a1, a1, 1 + bne t0, t1, 4f + bnez t0, 3b + +4: + sub a0, t0, t1 + ret +.option pop +END(__strcmp) diff --git a/arch/riscv/lib/strlen_zbb.S b/arch/riscv/lib/strlen_zbb.S new file mode 100644 index 00000000000..bd8fa4c0bd0 --- /dev/null +++ b/arch/riscv/lib/strlen_zbb.S @@ -0,0 +1,101 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Taken from Linux arch/riscv/lib/strlen.S + */ + +#include <linux/linkage.h> +#include <asm/asm.h> + +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +# define CZ ctz +# define SHIFT srl +#else +# define CZ clz +# define SHIFT sll +#endif + +ENTRY(__strlen) +WEAK(strlen) +.option push +.option arch,+zbb + /* + * Returns + * a0 - string length + * + * Parameters + * a0 - String to measure + * + * Clobbers + * t0, t1, t2, t3 + */ + + /* Number of irrelevant bytes in the first word. */ + andi t2, a0, SZREG-1 + + /* Align pointer. */ + andi t0, a0, -SZREG + + li t3, SZREG + sub t3, t3, t2 + slli t2, t2, 3 + + /* Get the first word. */ + REG_L t1, 0(t0) + + /* + * Shift away the partial data we loaded to remove the irrelevant bytes + * preceding the string with the effect of adding NUL bytes at the + * end of the string's first word. + */ + SHIFT t1, t1, t2 + + /* Convert non-NUL into 0xff and NUL into 0x00. */ + orc.b t1, t1 + + /* Convert non-NUL into 0x00 and NUL into 0xff. */ + not t1, t1 + + /* + * Search for the first set bit (corresponding to a NUL byte in the + * original chunk). + */ + CZ t1, t1 + + /* + * The first chunk is special: compare against the number + * of valid bytes in this chunk. + */ + srli a0, t1, 3 + bgtu t3, a0, 2f + + /* Prepare for the word comparison loop. */ + addi t2, t0, SZREG + li t3, -1 + + /* + * Our critical loop is 4 instructions and processes data in + * 4 byte or 8 byte chunks. + */ + .p2align 3 +1: + REG_L t1, SZREG(t0) + addi t0, t0, SZREG + orc.b t1, t1 + beq t1, t3, 1b + + not t1, t1 + CZ t1, t1 + srli t1, t1, 3 + + /* Get number of processed bytes. */ + sub t2, t0, t2 + + /* Add number of characters in the first word. */ + add a0, a0, t2 + + /* Add number of characters in the last word. */ + add a0, a0, t1 +2: + ret +.option pop +END(__strlen) diff --git a/arch/riscv/lib/strncmp_zbb.S b/arch/riscv/lib/strncmp_zbb.S new file mode 100644 index 00000000000..00e0fec3a66 --- /dev/null +++ b/arch/riscv/lib/strncmp_zbb.S @@ -0,0 +1,94 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Taken from Linux arch/riscv/lib/strncmp.S + */ + +#include <linux/linkage.h> +#include <asm/asm.h> + +ENTRY(__strncmp) +WEAK(strncmp) +.option push +.option arch,+zbb + /* + * Returns + * a0 - comparison result, like strncmp + * + * Parameters + * a0 - string1 + * a1 - string2 + * a2 - number of characters to compare + * + * Clobbers + * t0, t1, t2, t3, t4, t5, t6 + */ + + or t2, a0, a1 + li t5, -1 + and t2, t2, SZREG-1 + add t4, a0, a2 + bnez t2, 3f + + /* Adjust limit for fast-path. */ + andi t6, t4, -SZREG + + /* Main loop for aligned string. */ + .p2align 3 +1: + bge a0, t6, 3f + REG_L t0, 0(a0) + REG_L t1, 0(a1) + orc.b t3, t0 + bne t3, t5, 2f + orc.b t3, t1 + bne t3, t5, 2f + addi a0, a0, SZREG + addi a1, a1, SZREG + beq t0, t1, 1b + + /* + * Words don't match, and no null byte in the first + * word. Get bytes in big-endian order and compare. + */ +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + rev8 t0, t0 + rev8 t1, t1 +#endif + + /* Synthesize (t0 >= t1) ? 1 : -1 in a branchless sequence. */ + sltu a0, t0, t1 + neg a0, a0 + ori a0, a0, 1 + ret + +2: + /* + * Found a null byte. + * If words don't match, fall back to simple loop. + */ + bne t0, t1, 3f + + /* Otherwise, strings are equal. */ + li a0, 0 + ret + + /* Simple loop for misaligned strings. */ + .p2align 3 +3: + bge a0, t4, 5f + lbu t0, 0(a0) + lbu t1, 0(a1) + addi a0, a0, 1 + addi a1, a1, 1 + bne t0, t1, 4f + bnez t0, 3b + +4: + sub a0, t0, t1 + ret + +5: + li a0, 0 + ret +.option pop +END(__strncmp) |