From a966634eda041311f1492139618dab143c863f81 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Wed, 25 Oct 2023 00:15:43 +0200 Subject: [PATCH 01/14] CI: use OpenSBI 1.3.1 for testing Use the most recent upstream release of OpenSBI for CI testing. Signed-off-by: Heinrich Schuchardt Reviewed-by: Leo Yu-Chi Liang --- .azure-pipelines.yml | 8 ++++---- .gitlab-ci.yml | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.azure-pipelines.yml b/.azure-pipelines.yml index eb9353fc3dc..d6f3fa423c6 100644 --- a/.azure-pipelines.yml +++ b/.azure-pipelines.yml @@ -203,12 +203,12 @@ stages: grub-mkimage --prefix=\"\" -o ~/grub_x86.efi -O i386-efi normal echo lsefimmap lsefi lsefisystab efinet tftp minicmd grub-mkimage --prefix=\"\" -o ~/grub_x64.efi -O x86_64-efi normal echo lsefimmap lsefi lsefisystab efinet tftp minicmd if [[ "\${TEST_PY_BD}" == "qemu-riscv32_spl" ]]; then - wget -O - https://github.com/riscv-software-src/opensbi/releases/download/v1.2/opensbi-1.2-rv-bin.tar.xz | tar -C /tmp -xJ; - export OPENSBI=/tmp/opensbi-1.2-rv-bin/share/opensbi/ilp32/generic/firmware/fw_dynamic.bin; + wget -O - https://github.com/riscv-software-src/opensbi/releases/download/v1.3.1/opensbi-1.3.1-rv-bin.tar.xz | tar -C /tmp -xJ; + export OPENSBI=/tmp/opensbi-1.3.1-rv-bin/share/opensbi/ilp32/generic/firmware/fw_dynamic.bin; fi if [[ "\${TEST_PY_BD}" == "qemu-riscv64_spl" ]] || [[ "\${TEST_PY_BD}" == "sifive_unleashed" ]]; then - wget -O - https://github.com/riscv-software-src/opensbi/releases/download/v1.2/opensbi-1.2-rv-bin.tar.xz | tar -C /tmp -xJ; - export OPENSBI=/tmp/opensbi-1.2-rv-bin/share/opensbi/lp64/generic/firmware/fw_dynamic.bin; + wget -O - https://github.com/riscv-software-src/opensbi/releases/download/v1.3.1/opensbi-1.3.1-rv-bin.tar.xz | tar -C /tmp -xJ; + export OPENSBI=/tmp/opensbi-1.3.1-rv-bin/share/opensbi/lp64/generic/firmware/fw_dynamic.bin; fi # the below corresponds to .gitlab-ci.yml "script" cd \${WORK_DIR} diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 1e11b5a6fea..fee165198ae 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -32,12 +32,12 @@ stages: - grub-mkimage --prefix="" -o ~/grub_x86.efi -O i386-efi normal echo lsefimmap lsefi lsefisystab efinet tftp minicmd - grub-mkimage --prefix="" -o ~/grub_x64.efi -O x86_64-efi normal echo lsefimmap lsefi lsefisystab efinet tftp minicmd - if [[ "${TEST_PY_BD}" == "qemu-riscv32_spl" ]]; then - wget -O - https://github.com/riscv-software-src/opensbi/releases/download/v1.2/opensbi-1.2-rv-bin.tar.xz | tar -C /tmp -xJ; - export OPENSBI=/tmp/opensbi-1.2-rv-bin/share/opensbi/ilp32/generic/firmware/fw_dynamic.bin; + wget -O - https://github.com/riscv-software-src/opensbi/releases/download/v1.3.1/opensbi-1.3.1-rv-bin.tar.xz | tar -C /tmp -xJ; + export OPENSBI=/tmp/opensbi-1.3.1-rv-bin/share/opensbi/ilp32/generic/firmware/fw_dynamic.bin; fi - if [[ "${TEST_PY_BD}" == "qemu-riscv64_spl" ]] || [[ "${TEST_PY_BD}" == "sifive_unleashed" ]]; then - wget -O - https://github.com/riscv-software-src/opensbi/releases/download/v1.2/opensbi-1.2-rv-bin.tar.xz | tar -C /tmp -xJ; - export OPENSBI=/tmp/opensbi-1.2-rv-bin/share/opensbi/lp64/generic/firmware/fw_dynamic.bin; + wget -O - https://github.com/riscv-software-src/opensbi/releases/download/v1.3.1/opensbi-1.3.1-rv-bin.tar.xz | tar -C /tmp -xJ; + export OPENSBI=/tmp/opensbi-1.3.1-rv-bin/share/opensbi/lp64/generic/firmware/fw_dynamic.bin; fi after_script: From 891a181cda56ce6f7ee05dec5051ea2bbe5a6c4c Mon Sep 17 00:00:00 2001 From: Yong-Xuan Wang Date: Thu, 26 Oct 2023 03:22:52 +0000 Subject: [PATCH 02/14] board: sifive: unmatched: move kernel load address to 0x80200000 U-boot initially loads the kernel image to the kernel_addr_r, and subsequently relocates it to memory address 0x80200000. Setting kernel_addr_r to 0x80200000 can eliminate one copy operation. Signed-off-by: Yong-Xuan Wang Reviewed-by: Tom Rini --- include/configs/sifive-unmatched.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/configs/sifive-unmatched.h b/include/configs/sifive-unmatched.h index 74150b7d4b0..de8bfc1123b 100644 --- a/include/configs/sifive-unmatched.h +++ b/include/configs/sifive-unmatched.h @@ -36,7 +36,7 @@ "name=system,size=-,bootable,type=${type_guid_gpt_system};" #define CFG_EXTRA_ENV_SETTINGS \ - "kernel_addr_r=0x84000000\0" \ + "kernel_addr_r=0x80200000\0" \ "kernel_comp_addr_r=0x88000000\0" \ "kernel_comp_size=0x4000000\0" \ "fdt_addr_r=0x8c000000\0" \ From a6a77e47343d0b511136b76da0c853304a3f1423 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Tue, 31 Oct 2023 00:32:12 -0500 Subject: [PATCH 03/14] riscv: Sort target configs alphabetically Clean things up for the next time somebody adds a target. Signed-off-by: Samuel Holland Reviewed-by: Leo Yu-Chi Liang --- arch/riscv/Kconfig | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 8fc81fb284c..6d0d812ddb5 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -14,6 +14,9 @@ config TARGET_ANDES_AE350 config TARGET_MICROCHIP_ICICLE bool "Support Microchip PolarFire-SoC Icicle Board" +config TARGET_OPENPITON_RISCV64 + bool "Support RISC-V cores on OpenPiton SoC" + config TARGET_QEMU_VIRT bool "Support QEMU Virt Board" @@ -24,6 +27,10 @@ config TARGET_SIFIVE_UNMATCHED bool "Support SiFive Unmatched Board" select SYS_CACHE_SHIFT_6 +config TARGET_SIPEED_MAIX + bool "Support Sipeed Maix Board" + select SYS_CACHE_SHIFT_6 + config TARGET_STARFIVE_VISIONFIVE2 bool "Support StarFive VisionFive2 Board" select BOARD_LATE_INIT @@ -32,13 +39,6 @@ config TARGET_TH1520_LPI4A bool "Support Sipeed's TH1520 Lichee PI 4A Board" select SYS_CACHE_SHIFT_6 -config TARGET_SIPEED_MAIX - bool "Support Sipeed Maix Board" - select SYS_CACHE_SHIFT_6 - -config TARGET_OPENPITON_RISCV64 - bool "Support RISC-V cores on OpenPiton SoC" - endchoice config SYS_ICACHE_OFF @@ -76,12 +76,12 @@ config SPL_ZERO_MEM_BEFORE_USE source "board/AndesTech/ae350/Kconfig" source "board/emulation/qemu-riscv/Kconfig" source "board/microchip/mpfs_icicle/Kconfig" +source "board/openpiton/riscv64/Kconfig" source "board/sifive/unleashed/Kconfig" source "board/sifive/unmatched/Kconfig" -source "board/thead/th1520_lpi4a/Kconfig" -source "board/openpiton/riscv64/Kconfig" source "board/sipeed/maix/Kconfig" source "board/starfive/visionfive2/Kconfig" +source "board/thead/th1520_lpi4a/Kconfig" # platform-specific options below source "arch/riscv/cpu/andesv5/Kconfig" From 3b00fab616b1150da745bbb36f6644842a24624f Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Tue, 31 Oct 2023 00:35:41 -0500 Subject: [PATCH 04/14] riscv: Align the trap handler to 64 bytes This is required on CPUs which always operate in CLIC mode, such as the T-HEAD E906 and E907. Per the CLIC specification: "In this mode, the trap vector base address held in mtvec is constrained to be aligned on a 64-byte or larger power-of-two boundary." Reported-by: Madushan Nishantha Signed-off-by: Samuel Holland Reviewed-by: Leo Yu-Chi Liang --- arch/riscv/cpu/mtrap.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/riscv/cpu/mtrap.S b/arch/riscv/cpu/mtrap.S index 6eb3ed1d5a8..5cad7b41ff7 100644 --- a/arch/riscv/cpu/mtrap.S +++ b/arch/riscv/cpu/mtrap.S @@ -26,7 +26,7 @@ .text /* trap entry */ - .align 2 + .align 6 .global trap_entry trap_entry: addi sp, sp, -32 * REGBYTES From bade208b5deb16120c6236e941c6e5f081e86c05 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Tue, 31 Oct 2023 00:37:20 -0500 Subject: [PATCH 05/14] riscv: Weakly define invalidate_icache_range() Some RISC-V CPUs, such as the T-HEAD XuanTie series, have a vendor-specific way to invalidate a portion of the instruction cache. Allow them to override invalidate_icache_range(). Signed-off-by: Samuel Holland Reviewed-by: Leo Yu-Chi Liang --- arch/riscv/lib/cache.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/riscv/lib/cache.c b/arch/riscv/lib/cache.c index c46b49eb0ac..afad7e117f3 100644 --- a/arch/riscv/lib/cache.c +++ b/arch/riscv/lib/cache.c @@ -19,7 +19,7 @@ __weak void flush_dcache_range(unsigned long start, unsigned long end) { } -void invalidate_icache_range(unsigned long start, unsigned long end) +__weak void invalidate_icache_range(unsigned long start, unsigned long end) { /* * RISC-V does not have an instruction for invalidating parts of the From 37c2faf3252e8423be0577bed1358bd6f59b4c10 Mon Sep 17 00:00:00 2001 From: Chanho Park Date: Tue, 31 Oct 2023 17:55:59 +0900 Subject: [PATCH 06/14] riscv: cpu: jh7110: Add gpio helper macros Add gpio.h header file that includes JH7110 helper macros. The file is imported from StarFive github[1] with small changes such as alignment. [1]: https://github.com/starfive-tech/u-boot Signed-off-by: Chanho Park Reviewed-by: Leo Yu-Chi Liang --- arch/riscv/include/asm/arch-jh7110/gpio.h | 85 +++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 arch/riscv/include/asm/arch-jh7110/gpio.h diff --git a/arch/riscv/include/asm/arch-jh7110/gpio.h b/arch/riscv/include/asm/arch-jh7110/gpio.h new file mode 100644 index 00000000000..90aa2f8a9ed --- /dev/null +++ b/arch/riscv/include/asm/arch-jh7110/gpio.h @@ -0,0 +1,85 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2023 StarFive Technology Co., Ltd. + * Author: yanhong + * + */ + +#ifndef _GPIO_STARFIVE_H_ +#define _GPIO_STARFIVE_H_ + +#include + +#define GPIO_NUM_SHIFT 2 /*one dword include 4 gpios*/ +#define GPIO_BYTE_SHIFT 3 + +#define GPIO_INDEX_MASK 0x3 + +#define GPIO_DOEN_MASK 0x3f +#define GPIO_DOUT_MASK 0x7f +#define GPIO_DIN_MASK 0x7f +#define GPIO_DS_MASK 0x06 +#define GPIO_DS_SHIFT 1 +#define GPIO_SLEW_MASK BIT(5) +#define GPIO_SLEW_SHIFT 5 +#define GPIO_PULL_MASK 0x18 +#define GPIO_PULL_SHIFT 3 +#define GPIO_PULL_UP 1 +#define GPIO_PULL_DOWN 2 + +#define NR_GPIOS 64 + +#define GPIO_OFFSET(gpio) \ + (((gpio) >> GPIO_NUM_SHIFT) << GPIO_NUM_SHIFT) + +#define GPIO_SHIFT(gpio) \ + (((gpio) & GPIO_INDEX_MASK) << GPIO_BYTE_SHIFT) + +enum gpio_state { + LOW, + HIGH +}; + +#define GPIO_DOEN 0x0 +#define GPIO_DOUT 0x40 +#define GPIO_DIN 0x80 +#define GPIO_EN 0xdc +#define GPIO_LOW_IE 0x100 +#define GPIO_HIGH_IE 0x104 +#define GPIO_CONFIG 0x120 + +#define SYS_IOMUX_DOEN(gpio, oen) \ + clrsetbits_le32(JH7110_SYS_IOMUX + GPIO_OFFSET(gpio), \ + GPIO_DOEN_MASK << GPIO_SHIFT(gpio), \ + (oen) << GPIO_SHIFT(gpio)) + +#define SYS_IOMUX_DOUT(gpio, gpo) \ + clrsetbits_le32(JH7110_SYS_IOMUX + GPIO_DOUT + GPIO_OFFSET(gpio), \ + GPIO_DOUT_MASK << GPIO_SHIFT(gpio), \ + ((gpo) & GPIO_DOUT_MASK) << GPIO_SHIFT(gpio)) + +#define SYS_IOMUX_DIN(gpio, gpi)\ + clrsetbits_le32(JH7110_SYS_IOMUX + GPIO_DIN + GPIO_OFFSET(gpi), \ + GPIO_DIN_MASK << GPIO_SHIFT(gpi), \ + ((gpio + 2) & GPIO_DIN_MASK) << GPIO_SHIFT(gpi)) + +#define SYS_IOMUX_SET_DS(gpio, ds) \ + clrsetbits_le32(JH7110_SYS_IOMUX + GPIO_CONFIG + gpio * 4, \ + GPIO_DS_MASK, (ds) << GPIO_DS_SHIFT) + +#define SYS_IOMUX_SET_SLEW(gpio, slew) \ + clrsetbits_le32(JH7110_SYS_IOMUX + GPIO_CONFIG + gpio * 4, \ + GPIO_SLEW_MASK, (slew) << GPIO_SLEW_SHIFT) + +#define SYS_IOMUX_SET_PULL(gpio, pull) \ + clrsetbits_le32(JH7110_SYS_IOMUX + GPIO_CONFIG + gpio * 4, \ + GPIO_PULL_MASK, (pull) << GPIO_PULL_SHIFT) + +#define SYS_IOMUX_COMPLEX(gpio, gpi, gpo, oen) \ + do { \ + SYS_IOMUX_DOEN(gpio, oen); \ + SYS_IOMUX_DOUT(gpio, gpo); \ + SYS_IOMUX_DIN(gpio, gpi); \ + } while (0) + +#endif /* _GPIO_STARFIVE_H_ */ From b8a902b81462a1fa6bd4fc8614cdc386fa7849d4 Mon Sep 17 00:00:00 2001 From: Chanho Park Date: Tue, 31 Oct 2023 17:56:00 +0900 Subject: [PATCH 07/14] board: starfive: spl: Support jtag for VisionFive2 board JTAG pins are mapped as below. To access the JTAG pins, we need to control the GPIO pins from SPL which seems to be the earliest stage for JTAG. - JTAG nTRST: GPIO36 / Input - JTAG TDI: GPIO61 / Input - JTAG TMS: GPIO63 / Input - JTAG TCK: GPIO60 / Input - JTAG TDO: GPIO44 / Output Signed-off-by: Chanho Park Reviewed-by: Leo Yu-Chi Liang --- board/starfive/visionfive2/spl.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/board/starfive/visionfive2/spl.c b/board/starfive/visionfive2/spl.c index ad5f71a2018..336f0cdfc90 100644 --- a/board/starfive/visionfive2/spl.c +++ b/board/starfive/visionfive2/spl.c @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -172,10 +173,32 @@ void spl_perform_fixups(struct spl_image_info *spl_image) /* Update the memory size which read form eeprom or DT */ fdt_fixup_memory(spl_image->fdt_addr, 0x40000000, gd->ram_size); } + +static void jh7110_jtag_init(void) +{ + /* nTRST: GPIO36 */ + SYS_IOMUX_DOEN(36, HIGH); + SYS_IOMUX_DIN(36, 4); + /* TDI: GPIO61 */ + SYS_IOMUX_DOEN(61, HIGH); + SYS_IOMUX_DIN(61, 19); + /* TMS: GPIO63 */ + SYS_IOMUX_DOEN(63, HIGH); + SYS_IOMUX_DIN(63, 20); + /* TCK: GPIO60 */ + SYS_IOMUX_DOEN(60, HIGH); + SYS_IOMUX_DIN(60, 29); + /* TDO: GPIO44 */ + SYS_IOMUX_DOEN(44, 8); + SYS_IOMUX_DOUT(44, 22); +} + int spl_board_init_f(void) { int ret; + jh7110_jtag_init(); + ret = spl_soc_init(); if (ret) { debug("JH7110 SPL init failed: %d\n", ret); From 9757cae991669f9a3d2b981b77231ee891d0597d Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Tue, 31 Oct 2023 14:55:51 +0200 Subject: [PATCH 08/14] riscv: allow resume after exception If CSRs like seed are readable by S-mode, may not be determinable by S-mode. For safe driver probing allow to resume via a longjmp after an exception. Signed-off-by: Heinrich Schuchardt Reviewed-by: Leo Yu-Chi Liang --- arch/riscv/lib/interrupts.c | 13 +++++++++++ doc/api/index.rst | 1 + doc/api/interrupt.rst | 6 +++++ include/interrupt.h | 45 +++++++++++++++++++++++++++++++++++++ 4 files changed, 65 insertions(+) create mode 100644 doc/api/interrupt.rst create mode 100644 include/interrupt.h diff --git a/arch/riscv/lib/interrupts.c b/arch/riscv/lib/interrupts.c index 02dbcfd4238..a26ccc721fd 100644 --- a/arch/riscv/lib/interrupts.c +++ b/arch/riscv/lib/interrupts.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -21,6 +22,13 @@ DECLARE_GLOBAL_DATA_PTR; +static struct resume_data *resume; + +void set_resume(struct resume_data *data) +{ + resume = data; +} + static void show_efi_loaded_images(uintptr_t epc) { efi_print_image_infos((void *)epc); @@ -105,6 +113,11 @@ static void _exit_trap(ulong code, ulong epc, ulong tval, struct pt_regs *regs) "Store/AMO page fault", }; + if (resume) { + resume->code = code; + longjmp(resume->jump, 1); + } + if (code < ARRAY_SIZE(exception_code)) printf("Unhandled exception: %s\n", exception_code[code]); else diff --git a/doc/api/index.rst b/doc/api/index.rst index 2f0218c47a3..51b2013af36 100644 --- a/doc/api/index.rst +++ b/doc/api/index.rst @@ -12,6 +12,7 @@ U-Boot API documentation efi event getopt + interrupt linker_lists lmb logging diff --git a/doc/api/interrupt.rst b/doc/api/interrupt.rst new file mode 100644 index 00000000000..5721231d919 --- /dev/null +++ b/doc/api/interrupt.rst @@ -0,0 +1,6 @@ +.. SPDX-License-Identifier: GPL-2.0+ + +Interrupt API +============= + +.. kernel-doc:: include/interrupt.h diff --git a/include/interrupt.h b/include/interrupt.h new file mode 100644 index 00000000000..46ef2e196d4 --- /dev/null +++ b/include/interrupt.h @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include + +/** + * struct resume_data - data for resume after interrupt + */ +struct resume_data { + /** @jump: longjmp buffer */ + jmp_buf jump; + /** @code: exception code */ + ulong code; +}; + +/** + * set_resume() - set longjmp buffer for resuming after exception + * + * By calling this function it is possible to use a long jump to catch an + * exception. The caller sets the long jump buffer with set_resume() and then + * executes setjmp(). If an exception occurs, the code will return to the + * setjmp caller(). The exception code will be returned in @data->code. + * + * After the critical operation call set_resume(NULL) so that an exception in + * another part of the code will not accidently invoke the long jump. + * + * .. code-block:: c + * + * // This example shows how to use set_resume(). + * + * struct resume_data resume; + * int ret; + * + * set_resume(&resume); + * ret = setjmp(resume.jump); + * if (ret) { + * printf("An exception %ld occurred\n", resume.code); + * } else { + * // Do what might raise an exception here. + * } + * set_resume(NULL); + * + * @data: pointer to structure with longjmp address + * Return: 0 before an exception, 1 after an exception occurred + */ +void set_resume(struct resume_data *data); From ceec977ba1a994df423cd8558f72d6582e63da08 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Tue, 31 Oct 2023 14:55:52 +0200 Subject: [PATCH 09/14] rng: Provide a RNG based on the RISC-V Zkr ISA extension The Zkr ISA extension (ratified Nov 2021) introduced the seed CSR. It provides an interface to a physical entropy source. A RNG driver based on the seed CSR is provided. It depends on mseccfg.sseed being set in the SBI firmware. Signed-off-by: Heinrich Schuchardt Reviewed-by: Leo Yu-Chi Liang --- drivers/rng/Kconfig | 8 +++ drivers/rng/Makefile | 1 + drivers/rng/riscv_zkr_rng.c | 116 ++++++++++++++++++++++++++++++++++++ 3 files changed, 125 insertions(+) create mode 100644 drivers/rng/riscv_zkr_rng.c diff --git a/drivers/rng/Kconfig b/drivers/rng/Kconfig index 994cc35b274..4f6e367169c 100644 --- a/drivers/rng/Kconfig +++ b/drivers/rng/Kconfig @@ -48,6 +48,14 @@ config RNG_OPTEE accessible to normal world but reserved and used by the OP-TEE to avoid the weakness of a software PRNG. +config RNG_RISCV_ZKR + bool "RISC-V Zkr random number generator" + depends on RISCV_SMODE + help + This driver provides a Random Number Generator based on the + Zkr RISC-V ISA extension which provides an interface to an + NIST SP 800-90B or BSI AIS-31 compliant physical entropy source. + config RNG_STM32 bool "Enable random number generator for STM32" depends on ARCH_STM32 || ARCH_STM32MP diff --git a/drivers/rng/Makefile b/drivers/rng/Makefile index 47b323e61ee..a5d3ca41308 100644 --- a/drivers/rng/Makefile +++ b/drivers/rng/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_RNG_MSM) += msm_rng.o obj-$(CONFIG_RNG_NPCM) += npcm_rng.o obj-$(CONFIG_RNG_OPTEE) += optee_rng.o obj-$(CONFIG_RNG_STM32) += stm32_rng.o +obj-$(CONFIG_RNG_RISCV_ZKR) += riscv_zkr_rng.o obj-$(CONFIG_RNG_ROCKCHIP) += rockchip_rng.o obj-$(CONFIG_RNG_IPROC200) += iproc_rng200.o obj-$(CONFIG_RNG_SMCCC_TRNG) += smccc_trng.o diff --git a/drivers/rng/riscv_zkr_rng.c b/drivers/rng/riscv_zkr_rng.c new file mode 100644 index 00000000000..8c9e111e2e0 --- /dev/null +++ b/drivers/rng/riscv_zkr_rng.c @@ -0,0 +1,116 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * The RISC-V Zkr extension provides CSR seed which provides access to a + * random number generator. + */ + +#define LOG_CATEGORY UCLASS_RNG + +#include +#include +#include +#include + +#define DRIVER_NAME "riscv_zkr" + +enum opst { + /** @BIST: built in self test running */ + BIST = 0b00, + /** @WAIT: sufficient amount of entropy is not yet available */ + WAIT = 0b01, + /** @ES16: 16bits of entropy available */ + ES16 = 0b10, + /** @DEAD: unrecoverable self-test error */ + DEAD = 0b11, +}; + +static unsigned long read_seed(void) +{ + unsigned long ret; + + __asm__ __volatile__("csrrw %0, seed, x0" : "=r" (ret) : : "memory"); + + return ret; +} + +static int riscv_zkr_read(struct udevice *dev, void *data, size_t len) +{ + u8 *ptr = data; + + while (len) { + u32 val; + + val = read_seed(); + + switch (val >> 30) { + case BIST: + continue; + case WAIT: + continue; + case ES16: + *ptr++ = val & 0xff; + if (--len) { + *ptr++ = val >> 8; + --len; + } + break; + case DEAD: + return -ENODEV; + } + } + + return 0; +} + +/** + * riscv_zkr_probe() - check if the seed register is available + * + * If the SBI software has not set mseccfg.sseed=1 or the Zkr + * extension is not available this probe function will result + * in an exception. Currently we cannot recover from this. + * + * @dev: RNG device + * Return: 0 if successfully probed + */ +static int riscv_zkr_probe(struct udevice *dev) +{ + struct resume_data resume; + int ret; + u32 val; + + /* Check if reading seed leads to interrupt */ + set_resume(&resume); + ret = setjmp(resume.jump); + if (ret) + log_debug("Exception %ld reading seed CSR\n", resume.code); + else + val = read_seed(); + set_resume(NULL); + if (ret) + return -ENODEV; + + do { + val = read_seed(); + val >>= 30; + } while (val == BIST || val == WAIT); + + if (val == DEAD) + return -ENODEV; + + return 0; +} + +static const struct dm_rng_ops riscv_zkr_ops = { + .read = riscv_zkr_read, +}; + +U_BOOT_DRIVER(riscv_zkr) = { + .name = DRIVER_NAME, + .id = UCLASS_RNG, + .ops = &riscv_zkr_ops, + .probe = riscv_zkr_probe, +}; + +U_BOOT_DRVINFO(cpu_riscv_zkr) = { + .name = DRIVER_NAME, +}; From 83b443df26c6f812e4cf053bad39d6dfe55342c2 Mon Sep 17 00:00:00 2001 From: Chanho Park Date: Wed, 1 Nov 2023 21:16:48 +0900 Subject: [PATCH 10/14] riscv: import read/write_relaxed functions This imports mmio functions from Linux's arch/riscv/include/asm/mmio.h to use read/write[b|w|l|q]_relaxed functions. Signed-off-by: Chanho Park Reviewed-by: Leo Yu-Chi Liang --- arch/riscv/include/asm/io.h | 45 +++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/arch/riscv/include/asm/io.h b/arch/riscv/include/asm/io.h index b16e6dfa376..4170877a1ae 100644 --- a/arch/riscv/include/asm/io.h +++ b/arch/riscv/include/asm/io.h @@ -323,6 +323,51 @@ static inline void writesl(unsigned int *addr, const void *data, int longlen) #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 + #include #endif /* __ASM_RISCV_IO_H */ From 88af85cf9266a0f29a610126f9c836ee7266c375 Mon Sep 17 00:00:00 2001 From: Chanho Park Date: Wed, 1 Nov 2023 21:16:49 +0900 Subject: [PATCH 11/14] clk: starfive: jh7110: Add security clocks Add STGCLK_SEC_HCLK and STGCLK_SEC_MISCAHB clocks for JH7110 TRNG device. Signed-off-by: Chanho Park Reviewed-by: Leo Yu-Chi Liang --- drivers/clk/starfive/clk-jh7110.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/clk/starfive/clk-jh7110.c b/drivers/clk/starfive/clk-jh7110.c index 31aaf3340f9..a835541e48e 100644 --- a/drivers/clk/starfive/clk-jh7110.c +++ b/drivers/clk/starfive/clk-jh7110.c @@ -539,6 +539,16 @@ static int jh7110_stgcrg_init(struct udevice *dev) "pcie1_tl", "stg_axiahb", OFFSET(JH7110_STGCLK_PCIE1_TL))); + /* Security clocks */ + clk_dm(JH7110_STG_ID_TRANS(JH7110_STGCLK_SEC_HCLK), + starfive_clk_gate(priv->reg, + "sec_ahb", "stg_axiahb", + OFFSET(JH7110_STGCLK_SEC_HCLK))); + clk_dm(JH7110_STG_ID_TRANS(JH7110_STGCLK_SEC_MISCAHB), + starfive_clk_gate(priv->reg, + "sec_misc_ahb", "stg_axiahb", + OFFSET(JH7110_STGCLK_SEC_MISCAHB))); + return 0; } From ebaee701a6a370b7566107d495db87ba653cc7c4 Mon Sep 17 00:00:00 2001 From: Chanho Park Date: Wed, 1 Nov 2023 21:16:50 +0900 Subject: [PATCH 12/14] rng: Add StarFive JH7110 RNG driver Adds to support JH7110 TRNG driver which is based on linux kernel's jh7110-trng.c. This can support to generate 256-bit random numbers and 128-bit but this makes 256-bit default for convenience. Signed-off-by: Chanho Park Reviewed-by: Leo Yu-Chi Liang --- drivers/rng/Kconfig | 6 + drivers/rng/Makefile | 1 + drivers/rng/jh7110_rng.c | 274 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 281 insertions(+) create mode 100644 drivers/rng/jh7110_rng.c diff --git a/drivers/rng/Kconfig b/drivers/rng/Kconfig index 4f6e367169c..a89c8995682 100644 --- a/drivers/rng/Kconfig +++ b/drivers/rng/Kconfig @@ -99,4 +99,10 @@ config TPM_RNG functionality. Enable random number generator on TPM devices. +config RNG_JH7110 + bool "StarFive JH7110 Random Number Generator support" + depends on DM_RNG && STARFIVE_JH7110 + help + Enable True Random Number Generator in StarFive JH7110 SoCs. + endif diff --git a/drivers/rng/Makefile b/drivers/rng/Makefile index a5d3ca41308..7e64c4cdfc3 100644 --- a/drivers/rng/Makefile +++ b/drivers/rng/Makefile @@ -16,3 +16,4 @@ obj-$(CONFIG_RNG_IPROC200) += iproc_rng200.o obj-$(CONFIG_RNG_SMCCC_TRNG) += smccc_trng.o obj-$(CONFIG_RNG_ARM_RNDR) += arm_rndr.o obj-$(CONFIG_TPM_RNG) += tpm_rng.o +obj-$(CONFIG_RNG_JH7110) += jh7110_rng.o diff --git a/drivers/rng/jh7110_rng.c b/drivers/rng/jh7110_rng.c new file mode 100644 index 00000000000..eb21afe4e7c --- /dev/null +++ b/drivers/rng/jh7110_rng.c @@ -0,0 +1,274 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * TRNG driver for the StarFive JH7110 SoC + * + */ + +#include +#include +#include +#include +#include +#include + +/* trng register offset */ +#define STARFIVE_CTRL 0x00 +#define STARFIVE_STAT 0x04 +#define STARFIVE_MODE 0x08 +#define STARFIVE_SMODE 0x0C +#define STARFIVE_IE 0x10 +#define STARFIVE_ISTAT 0x14 +#define STARFIVE_RAND0 0x20 +#define STARFIVE_RAND1 0x24 +#define STARFIVE_RAND2 0x28 +#define STARFIVE_RAND3 0x2C +#define STARFIVE_RAND4 0x30 +#define STARFIVE_RAND5 0x34 +#define STARFIVE_RAND6 0x38 +#define STARFIVE_RAND7 0x3C +#define STARFIVE_AUTO_RQSTS 0x60 +#define STARFIVE_AUTO_AGE 0x64 + +/* CTRL CMD */ +#define STARFIVE_CTRL_EXEC_NOP 0x0 +#define STARFIVE_CTRL_GENE_RANDNUM 0x1 +#define STARFIVE_CTRL_EXEC_RANDRESEED 0x2 + +/* STAT */ +#define STARFIVE_STAT_NONCE_MODE BIT(2) +#define STARFIVE_STAT_R256 BIT(3) +#define STARFIVE_STAT_MISSION_MODE BIT(8) +#define STARFIVE_STAT_SEEDED BIT(9) +#define STARFIVE_STAT_LAST_RESEED(x) ((x) << 16) +#define STARFIVE_STAT_SRVC_RQST BIT(27) +#define STARFIVE_STAT_RAND_GENERATING BIT(30) +#define STARFIVE_STAT_RAND_SEEDING BIT(31) +#define STARFIVE_STAT_RUNNING (STARFIVE_STAT_RAND_GENERATING | \ + STARFIVE_STAT_RAND_SEEDING) + +/* MODE */ +#define STARFIVE_MODE_R256 BIT(3) + +/* SMODE */ +#define STARFIVE_SMODE_NONCE_MODE BIT(2) +#define STARFIVE_SMODE_MISSION_MODE BIT(8) +#define STARFIVE_SMODE_MAX_REJECTS(x) ((x) << 16) + +/* IE */ +#define STARFIVE_IE_RAND_RDY_EN BIT(0) +#define STARFIVE_IE_SEED_DONE_EN BIT(1) +#define STARFIVE_IE_LFSR_LOCKUP_EN BIT(4) +#define STARFIVE_IE_GLBL_EN BIT(31) + +#define STARFIVE_IE_ALL (STARFIVE_IE_GLBL_EN | \ + STARFIVE_IE_RAND_RDY_EN | \ + STARFIVE_IE_SEED_DONE_EN | \ + STARFIVE_IE_LFSR_LOCKUP_EN) + +/* ISTAT */ +#define STARFIVE_ISTAT_RAND_RDY BIT(0) +#define STARFIVE_ISTAT_SEED_DONE BIT(1) +#define STARFIVE_ISTAT_LFSR_LOCKUP BIT(4) + +#define STARFIVE_RAND_LEN sizeof(u32) + +enum mode { + PRNG_128BIT, + PRNG_256BIT, +}; + +struct starfive_trng_plat { + void *base; + struct clk *hclk; + struct clk *ahb; + struct reset_ctl *rst; + u32 mode; +}; + +static inline int starfive_trng_wait_idle(struct starfive_trng_plat *trng) +{ + u32 stat; + + return readl_relaxed_poll_timeout(trng->base + STARFIVE_STAT, stat, + !(stat & STARFIVE_STAT_RUNNING), + 100000); +} + +static inline void starfive_trng_irq_mask_clear(struct starfive_trng_plat *trng) +{ + /* clear register: ISTAT */ + u32 data = readl(trng->base + STARFIVE_ISTAT); + + writel(data, trng->base + STARFIVE_ISTAT); +} + +static int starfive_trng_cmd(struct starfive_trng_plat *trng, u32 cmd) +{ + u32 stat, flg; + int ret; + + switch (cmd) { + case STARFIVE_CTRL_GENE_RANDNUM: + writel(cmd, trng->base + STARFIVE_CTRL); + flg = STARFIVE_ISTAT_RAND_RDY; + break; + case STARFIVE_CTRL_EXEC_RANDRESEED: + writel(cmd, trng->base + STARFIVE_CTRL); + flg = STARFIVE_ISTAT_SEED_DONE; + break; + default: + return -EINVAL; + } + + ret = readl_relaxed_poll_timeout(trng->base + STARFIVE_ISTAT, stat, + (stat & flg), 1000); + writel(flg, trng->base + STARFIVE_ISTAT); + + return ret; +} + +static int starfive_trng_read(struct udevice *dev, void *data, size_t len) +{ + struct starfive_trng_plat *trng = dev_get_plat(dev); + u8 *buffer = data; + int iter_mask; + + if (trng->mode == PRNG_256BIT) + iter_mask = 7; + else + iter_mask = 3; + + for (int i = 0; len; ++i, i &= iter_mask) { + u32 val; + size_t step; + int ret; + + if (!i) { + ret = starfive_trng_cmd(trng, + STARFIVE_CTRL_GENE_RANDNUM); + if (ret) + return ret; + } + + val = readl(trng->base + STARFIVE_RAND0 + + (i * STARFIVE_RAND_LEN)); + step = min_t(size_t, len, STARFIVE_RAND_LEN); + memcpy(buffer, &val, step); + buffer += step; + len -= step; + } + + return 0; +} + +static int starfive_trng_init(struct starfive_trng_plat *trng) +{ + u32 mode, intr = 0; + + /* setup Auto Request/Age register */ + writel(0, trng->base + STARFIVE_AUTO_AGE); + writel(0, trng->base + STARFIVE_AUTO_RQSTS); + + /* clear register: ISTAT */ + starfive_trng_irq_mask_clear(trng); + + intr |= STARFIVE_IE_ALL; + writel(intr, trng->base + STARFIVE_IE); + + mode = readl(trng->base + STARFIVE_MODE); + + switch (trng->mode) { + case PRNG_128BIT: + mode &= ~STARFIVE_MODE_R256; + break; + case PRNG_256BIT: + mode |= STARFIVE_MODE_R256; + break; + default: + mode |= STARFIVE_MODE_R256; + break; + } + + writel(mode, trng->base + STARFIVE_MODE); + + return starfive_trng_cmd(trng, STARFIVE_CTRL_EXEC_RANDRESEED); +} + +static int starfive_trng_probe(struct udevice *dev) +{ + struct starfive_trng_plat *pdata = dev_get_plat(dev); + int err; + + err = clk_enable(pdata->hclk); + if (err) + return err; + + err = clk_enable(pdata->ahb); + if (err) + goto err_ahb; + + err = reset_deassert(pdata->rst); + if (err) + goto err_reset; + + pdata->mode = PRNG_256BIT; + + err = starfive_trng_init(pdata); + if (err) + goto err_trng_init; + + return 0; + +err_trng_init: + reset_assert(pdata->rst); +err_reset: + clk_disable(pdata->ahb); +err_ahb: + clk_disable(pdata->hclk); + + return err; +} + +static int starfive_trng_of_to_plat(struct udevice *dev) +{ + struct starfive_trng_plat *pdata = dev_get_plat(dev); + + pdata->base = (void *)dev_read_addr(dev); + if (!pdata->base) + return -ENODEV; + + pdata->hclk = devm_clk_get(dev, "hclk"); + if (IS_ERR(pdata->hclk)) + return -ENODEV; + + pdata->ahb = devm_clk_get(dev, "ahb"); + if (IS_ERR(pdata->ahb)) + return -ENODEV; + + pdata->rst = devm_reset_control_get(dev, NULL); + if (IS_ERR(pdata->rst)) + return -ENODEV; + + return 0; +} + +static const struct dm_rng_ops starfive_trng_ops = { + .read = starfive_trng_read, +}; + +static const struct udevice_id starfive_trng_match[] = { + { + .compatible = "starfive,jh7110-trng", + }, + {}, +}; + +U_BOOT_DRIVER(starfive_trng) = { + .name = "jh7110-trng", + .id = UCLASS_RNG, + .of_match = starfive_trng_match, + .probe = starfive_trng_probe, + .ops = &starfive_trng_ops, + .plat_auto = sizeof(struct starfive_trng_plat), + .of_to_plat = starfive_trng_of_to_plat, +}; From 30b0f58dc79d734684a0f1fae99179ee29fe18d3 Mon Sep 17 00:00:00 2001 From: Chanho Park Date: Wed, 1 Nov 2023 21:16:51 +0900 Subject: [PATCH 13/14] riscv: dts: jh7110: Add rng device tree node Adds jh7110 trng device tree node. Signed-off-by: Chanho Park Reviewed-by: Leo Yu-Chi Liang --- arch/riscv/dts/jh7110.dtsi | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/riscv/dts/jh7110.dtsi b/arch/riscv/dts/jh7110.dtsi index ec237a46ffb..13c47f7caa3 100644 --- a/arch/riscv/dts/jh7110.dtsi +++ b/arch/riscv/dts/jh7110.dtsi @@ -627,6 +627,16 @@ status = "disabled"; }; + rng: rng@1600c000 { + compatible = "starfive,jh7110-trng"; + reg = <0x0 0x1600C000 0x0 0x4000>; + clocks = <&stgcrg JH7110_STGCLK_SEC_HCLK>, + <&stgcrg JH7110_STGCLK_SEC_MISCAHB>; + clock-names = "hclk", "ahb"; + resets = <&stgcrg JH7110_STGRST_SEC_TOP_HRESETN>; + interrupts = <30>; + }; + aoncrg: clock-controller@17000000 { compatible = "starfive,jh7110-aoncrg"; reg = <0x0 0x17000000 0x0 0x10000>; From 9d22d4a7cef7f2fdaf5c060b71574e6f82ea5ff0 Mon Sep 17 00:00:00 2001 From: Chanho Park Date: Wed, 1 Nov 2023 21:16:52 +0900 Subject: [PATCH 14/14] configs: visionfive2: Enable JH7110 RNG driver Enables JH7110 RNG driver to visionfive2 board. Signed-off-by: Chanho Park Reviewed-by: Heinrich Schuchardt --- configs/starfive_visionfive2_defconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/configs/starfive_visionfive2_defconfig b/configs/starfive_visionfive2_defconfig index b21754feafc..b15e7d24db1 100644 --- a/configs/starfive_visionfive2_defconfig +++ b/configs/starfive_visionfive2_defconfig @@ -120,6 +120,8 @@ CONFIG_SPL_PINCTRL_STARFIVE=y CONFIG_SPL_PINCTRL_STARFIVE_JH7110=y CONFIG_PINCTRL_STARFIVE=y # CONFIG_RAM_SIFIVE is not set +CONFIG_DM_RNG=y +CONFIG_RNG_JH7110=y CONFIG_SYS_NS16550=y CONFIG_CADENCE_QSPI=y CONFIG_TIMER_EARLY=y