diff options
author | Tom Rini <trini@konsulko.com> | 2023-11-02 09:30:34 -0400 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2023-11-02 09:30:34 -0400 |
commit | b0c391ce0c01064a96711965e22f5d745e73edc3 (patch) | |
tree | fd9655433e4af8ee818e80267ff42713ff8d2290 | |
parent | 658caf0bf14e163be78b6fc063d883d1252163a2 (diff) | |
parent | 9d22d4a7cef7f2fdaf5c060b71574e6f82ea5ff0 (diff) |
Merge https://source.denx.de/u-boot/custodians/u-boot-riscv
+ CI: Use OpenSBI 1.3.1 release for testing
+ riscv: Support resume after exception
+ rng: Support RNG provided by RISC-V Zkr ISA extension
+ board: starfive VF2: Support jtag
+ board: starfive VF2: Support TRNG driver
+ board: sifive unmatched: Move kernel load address
-rw-r--r-- | .azure-pipelines.yml | 8 | ||||
-rw-r--r-- | .gitlab-ci.yml | 8 | ||||
-rw-r--r-- | arch/riscv/Kconfig | 18 | ||||
-rw-r--r-- | arch/riscv/cpu/mtrap.S | 2 | ||||
-rw-r--r-- | arch/riscv/dts/jh7110.dtsi | 10 | ||||
-rw-r--r-- | arch/riscv/include/asm/arch-jh7110/gpio.h | 85 | ||||
-rw-r--r-- | arch/riscv/include/asm/io.h | 45 | ||||
-rw-r--r-- | arch/riscv/lib/cache.c | 2 | ||||
-rw-r--r-- | arch/riscv/lib/interrupts.c | 13 | ||||
-rw-r--r-- | board/starfive/visionfive2/spl.c | 23 | ||||
-rw-r--r-- | configs/starfive_visionfive2_defconfig | 2 | ||||
-rw-r--r-- | doc/api/index.rst | 1 | ||||
-rw-r--r-- | doc/api/interrupt.rst | 6 | ||||
-rw-r--r-- | drivers/clk/starfive/clk-jh7110.c | 10 | ||||
-rw-r--r-- | drivers/rng/Kconfig | 14 | ||||
-rw-r--r-- | drivers/rng/Makefile | 2 | ||||
-rw-r--r-- | drivers/rng/jh7110_rng.c | 274 | ||||
-rw-r--r-- | drivers/rng/riscv_zkr_rng.c | 116 | ||||
-rw-r--r-- | include/configs/sifive-unmatched.h | 2 | ||||
-rw-r--r-- | include/interrupt.h | 45 |
20 files changed, 666 insertions, 20 deletions
diff --git a/.azure-pipelines.yml b/.azure-pipelines.yml index eb9353fc3d..d6f3fa423c 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 1e11b5a6fe..fee165198a 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: diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 8fc81fb284..6d0d812ddb 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" diff --git a/arch/riscv/cpu/mtrap.S b/arch/riscv/cpu/mtrap.S index 6eb3ed1d5a..5cad7b41ff 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 diff --git a/arch/riscv/dts/jh7110.dtsi b/arch/riscv/dts/jh7110.dtsi index ec237a46ff..13c47f7caa 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>; 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 0000000000..90aa2f8a9e --- /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 <yanhong.wang@starfivetech.com> + * + */ + +#ifndef _GPIO_STARFIVE_H_ +#define _GPIO_STARFIVE_H_ + +#include <asm/arch/regs.h> + +#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_ */ diff --git a/arch/riscv/include/asm/io.h b/arch/riscv/include/asm/io.h index b16e6dfa37..4170877a1a 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 <asm-generic/io.h> #endif /* __ASM_RISCV_IO_H */ diff --git a/arch/riscv/lib/cache.c b/arch/riscv/lib/cache.c index c46b49eb0a..afad7e117f 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 diff --git a/arch/riscv/lib/interrupts.c b/arch/riscv/lib/interrupts.c index 02dbcfd423..a26ccc721f 100644 --- a/arch/riscv/lib/interrupts.c +++ b/arch/riscv/lib/interrupts.c @@ -12,6 +12,7 @@ #include <linux/compat.h> #include <efi_loader.h> #include <hang.h> +#include <interrupt.h> #include <irq_func.h> #include <asm/global_data.h> #include <asm/ptrace.h> @@ -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/board/starfive/visionfive2/spl.c b/board/starfive/visionfive2/spl.c index ad5f71a201..336f0cdfc9 100644 --- a/board/starfive/visionfive2/spl.c +++ b/board/starfive/visionfive2/spl.c @@ -6,6 +6,7 @@ #include <common.h> #include <asm/arch/eeprom.h> +#include <asm/arch/gpio.h> #include <asm/arch/regs.h> #include <asm/arch/spl.h> #include <asm/io.h> @@ -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); diff --git a/configs/starfive_visionfive2_defconfig b/configs/starfive_visionfive2_defconfig index b21754feaf..b15e7d24db 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 diff --git a/doc/api/index.rst b/doc/api/index.rst index 2f0218c47a..51b2013af3 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 0000000000..5721231d91 --- /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/drivers/clk/starfive/clk-jh7110.c b/drivers/clk/starfive/clk-jh7110.c index 31aaf3340f..a835541e48 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; } diff --git a/drivers/rng/Kconfig b/drivers/rng/Kconfig index 994cc35b27..a89c899568 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 @@ -91,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 47b323e61e..7e64c4cdfc 100644 --- a/drivers/rng/Makefile +++ b/drivers/rng/Makefile @@ -10,8 +10,10 @@ 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 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 0000000000..eb21afe4e7 --- /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 <clk.h> +#include <dm.h> +#include <reset.h> +#include <rng.h> +#include <asm/io.h> +#include <linux/iopoll.h> + +/* 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, +}; diff --git a/drivers/rng/riscv_zkr_rng.c b/drivers/rng/riscv_zkr_rng.c new file mode 100644 index 0000000000..8c9e111e2e --- /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 <dm.h> +#include <interrupt.h> +#include <log.h> +#include <rng.h> + +#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, +}; diff --git a/include/configs/sifive-unmatched.h b/include/configs/sifive-unmatched.h index 74150b7d4b..de8bfc1123 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" \ diff --git a/include/interrupt.h b/include/interrupt.h new file mode 100644 index 0000000000..46ef2e196d --- /dev/null +++ b/include/interrupt.h @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include <asm/setjmp.h> + +/** + * 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); |