From 54d5d2d56bb6c46c996a4d249dbae3b12a7a4fac Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Sat, 11 Sep 2021 13:20:00 -0400 Subject: [PATCH 01/12] clk: k210: Fix checking if ulongs are less than 0 The PLL functions take ulong arguments for rate, but still check if that rate is negative (which is never true). The correct way to handle this is to use IS_ERR_VALUE (like is already done in k210_clk_set_rate). While we're at it, we can move the error checking up into the caller of the pll set/get rate functions. This also protects our other calculations from using bogus values for rate. Fixes: 609bd60b94 ("clk: k210: Rewrite to remove CCF") Reported-by: Coverity Scan Signed-off-by: Sean Anderson Reviewed-by: Leo Yu-Chi Liang --- drivers/clk/clk_kendryte.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/clk/clk_kendryte.c b/drivers/clk/clk_kendryte.c index 3148756968..2caa21aec9 100644 --- a/drivers/clk/clk_kendryte.c +++ b/drivers/clk/clk_kendryte.c @@ -849,9 +849,6 @@ static ulong k210_pll_set_rate(struct k210_clk_priv *priv, int id, ulong rate, u32 reg; ulong calc_rate; - if (rate_in < 0) - return rate_in; - err = k210_pll_calc_config(rate, rate_in, &config); if (err) return err; @@ -895,7 +892,7 @@ static ulong k210_pll_get_rate(struct k210_clk_priv *priv, int id, u64 r, f, od; u32 reg = readl(priv->base + k210_plls[id].off); - if (rate_in < 0 || (reg & K210_PLL_BYPASS)) + if (reg & K210_PLL_BYPASS) return rate_in; if (!(reg & K210_PLL_PWRD)) @@ -1029,6 +1026,8 @@ static ulong do_k210_clk_get_rate(struct k210_clk_priv *priv, int id) parent = k210_clk_get_parent(priv, id); parent_rate = do_k210_clk_get_rate(priv, parent); + if (IS_ERR_VALUE(parent_rate)) + return parent_rate; if (k210_clks[id].flags & K210_CLKF_PLL) return k210_pll_get_rate(priv, k210_clks[id].pll, parent_rate); @@ -1099,6 +1098,8 @@ static ulong k210_clk_set_rate(struct clk *clk, unsigned long rate) parent = k210_clk_get_parent(priv, clk->id); rate_in = do_k210_clk_get_rate(priv, parent); + if (IS_ERR_VALUE(rate_in)) + return rate_in; log_debug("id=%ld rate=%lu rate_in=%lu\n", clk->id, rate, rate_in); From 49708749701d957dacb2b01ea3d71e457804f7eb Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Sat, 11 Sep 2021 13:20:01 -0400 Subject: [PATCH 02/12] k210: clk: Refactor out_of_spec tests Everything here sits in a while (true) loop. However, this introduces a couple of layers of indentation. We can simplify the code by introducing a single goto instead of using continue/break. This will also make adding loops in the next patch easier. Signed-off-by: Sean Anderson Reviewed-by: Leo Yu-Chi Liang --- drivers/clk/clk_kendryte.c | 105 ++++++++++++++++++------------------- 1 file changed, 52 insertions(+), 53 deletions(-) diff --git a/drivers/clk/clk_kendryte.c b/drivers/clk/clk_kendryte.c index 2caa21aec9..69691c4a04 100644 --- a/drivers/clk/clk_kendryte.c +++ b/drivers/clk/clk_kendryte.c @@ -709,6 +709,10 @@ TEST_STATIC int k210_pll_calc_config(u32 rate, u32 rate_in, * Whether we swapped r and od while enforcing frequency limits */ bool swapped = false; + /* + * Whether the intermediate frequencies are out-of-spec + */ + bool out_of_spec; u64 last_od = od; u64 last_r = r; @@ -767,76 +771,71 @@ TEST_STATIC int k210_pll_calc_config(u32 rate, u32 rate_in, * aren't in spec, try swapping r and od. If everything is * in-spec, calculate the relative error. */ - while (true) { +again: + out_of_spec = false; + if (r > max_r) { + out_of_spec = true; + } else { /* - * Whether the intermediate frequencies are out-of-spec + * There is no way to only divide once; we need + * to examine the frequency with and without the + * effect of od. */ - bool out_of_spec = false; + u64 vco = DIV_ROUND_CLOSEST_ULL(rate_in * f, r); - if (r > max_r) { + if (vco > 1750000000 || vco < 340000000) out_of_spec = true; - } else { - /* - * There is no way to only divide once; we need - * to examine the frequency with and without the - * effect of od. - */ - u64 vco = DIV_ROUND_CLOSEST_ULL(rate_in * f, r); + } - if (vco > 1750000000 || vco < 340000000) - out_of_spec = true; + if (out_of_spec) { + u64 new_r, new_od; + + if (!swapped) { + u64 tmp = r; + + r = od; + od = tmp; + swapped = true; + goto again; } - if (out_of_spec) { - if (!swapped) { - u64 tmp = r; - - r = od; - od = tmp; - swapped = true; - continue; - } else { - /* - * Try looking ahead to see if there are - * additional factors for the same - * product. - */ - if (i + 1 < ARRAY_SIZE(factors)) { - u64 new_r, new_od; - - i++; - new_r = UNPACK_R(factors[i]); - new_od = UNPACK_OD(factors[i]); - if (r * od == new_r * new_od) { - r = new_r; - od = new_od; - swapped = false; - continue; - } - i--; - } - break; + /* + * Try looking ahead to see if there are additional + * factors for the same product. + */ + if (i + 1 < ARRAY_SIZE(factors)) { + i++; + new_r = UNPACK_R(factors[i]); + new_od = UNPACK_OD(factors[i]); + if (r * od == new_r * new_od) { + r = new_r; + od = new_od; + swapped = false; + goto again; } + i--; } - error = DIV_ROUND_CLOSEST_ULL(f * inv_ratio, r * od); - /* The lower 16 bits are spurious */ - error = abs((error - BIT(32))) >> 16; + /* We ran out of things to try */ + continue; + } - if (error < best_error) { - best->r = r; - best->f = f; - best->od = od; - best_error = error; - } - break; + error = DIV_ROUND_CLOSEST_ULL(f * inv_ratio, r * od); + /* The lower 16 bits are spurious */ + error = abs((error - BIT(32))) >> 16; + + if (error < best_error) { + best->r = r; + best->f = f; + best->od = od; + best_error = error; } } while (f < 64 && i + 1 < ARRAY_SIZE(factors) && error != 0); + log_debug("best error %lld\n", best_error); if (best_error == S64_MAX) return -EINVAL; - log_debug("best error %lld\n", best_error); return 0; } From 6e23c9f0c1ebe9b93077b6901733cd01d3848208 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Sat, 11 Sep 2021 13:20:02 -0400 Subject: [PATCH 03/12] test: dm: k210: Reduce duplication in test cases Having to copy-paste the same 3 lines makes adding new test cases error-prone. Use a macro. Signed-off-by: Sean Anderson Reviewed-by: Simon Glass Reviewed-by: Leo Yu-Chi Liang --- test/dm/k210_pll.c | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/test/dm/k210_pll.c b/test/dm/k210_pll.c index 54764f269c..5574ac96fa 100644 --- a/test/dm/k210_pll.c +++ b/test/dm/k210_pll.c @@ -69,27 +69,21 @@ static int dm_test_k210_pll(struct unit_test_state *uts) &theirs)); ut_asserteq(-EINVAL, k210_pll_calc_config(1500000000, 20000000, &theirs)); + ut_asserteq(-EINVAL, k210_pll_calc_config(1750000000, 13300000, + &theirs)); /* Verify we get the same output with brute-force */ - ut_assertok(dm_test_k210_pll_calc_config(390000000, 26000000, &ours)); - ut_assertok(k210_pll_calc_config(390000000, 26000000, &theirs)); - ut_assertok(dm_test_k210_pll_compare(&ours, &theirs)); +#define compare(rate, rate_in) do { \ + ut_assertok(dm_test_k210_pll_calc_config(rate, rate_in, &ours)); \ + ut_assertok(k210_pll_calc_config(rate, rate_in, &theirs)); \ + ut_assertok(dm_test_k210_pll_compare(&ours, &theirs)); \ +} while (0) - ut_assertok(dm_test_k210_pll_calc_config(26000000, 390000000, &ours)); - ut_assertok(k210_pll_calc_config(26000000, 390000000, &theirs)); - ut_assertok(dm_test_k210_pll_compare(&ours, &theirs)); - - ut_assertok(dm_test_k210_pll_calc_config(400000000, 26000000, &ours)); - ut_assertok(k210_pll_calc_config(400000000, 26000000, &theirs)); - ut_assertok(dm_test_k210_pll_compare(&ours, &theirs)); - - ut_assertok(dm_test_k210_pll_calc_config(27000000, 26000000, &ours)); - ut_assertok(k210_pll_calc_config(27000000, 26000000, &theirs)); - ut_assertok(dm_test_k210_pll_compare(&ours, &theirs)); - - ut_assertok(dm_test_k210_pll_calc_config(26000000, 27000000, &ours)); - ut_assertok(k210_pll_calc_config(26000000, 27000000, &theirs)); - ut_assertok(dm_test_k210_pll_compare(&ours, &theirs)); + compare(390000000, 26000000); + compare(26000000, 390000000); + compare(400000000, 26000000); + compare(27000000, 26000000); + compare(26000000, 27000000); return 0; } From 425c08faa8a2d6af5d9c1d83a97572f6401137bf Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Sat, 11 Sep 2021 13:20:03 -0400 Subject: [PATCH 04/12] clk: k210: Try harder to get the best config In some cases, the best config cannot be used because the VCO would be out-of-spec. In these cases, we may need to try a worse combination of r/od in order to find the best representable config. This also adds a few test cases to catch this and other (possible) unlikely errors. Signed-off-by: Sean Anderson Reviewed-by: Simon Glass --- drivers/clk/clk_kendryte.c | 24 ++++++++++++++++++++++++ test/dm/k210_pll.c | 4 ++++ 2 files changed, 28 insertions(+) diff --git a/drivers/clk/clk_kendryte.c b/drivers/clk/clk_kendryte.c index 69691c4a04..97efda5b6f 100644 --- a/drivers/clk/clk_kendryte.c +++ b/drivers/clk/clk_kendryte.c @@ -816,6 +816,30 @@ again: i--; } + /* + * Try looking back to see if there is a worse ratio + * that we could try anyway + */ + while (i > 0) { + i--; + new_r = UNPACK_R(factors[i]); + new_od = UNPACK_OD(factors[i]); + /* + * Don't loop over factors for the same product + * to avoid getting stuck because of the above + * clause + */ + if (r * od != new_r * new_od) { + if (new_r * new_od > last_r * last_od) { + r = new_r; + od = new_od; + swapped = false; + goto again; + } + break; + } + } + /* We ran out of things to try */ continue; } diff --git a/test/dm/k210_pll.c b/test/dm/k210_pll.c index 5574ac96fa..f55379f336 100644 --- a/test/dm/k210_pll.c +++ b/test/dm/k210_pll.c @@ -84,6 +84,10 @@ static int dm_test_k210_pll(struct unit_test_state *uts) compare(400000000, 26000000); compare(27000000, 26000000); compare(26000000, 27000000); + compare(13300000 * 64, 13300000); + compare(21250000, 21250000 * 70); + compare(21250000, 1750000000); + compare(1750000000, 1750000000); return 0; } From 41f7be733444b9221c828ee9c7c22cddfac5a28c Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sun, 12 Sep 2021 10:56:09 -0500 Subject: [PATCH 05/12] serial: Add a debug console using the RISC-V SBI interface The RISC-V SBI interface v0.1 provides a function for printing a character to the console. Even though SBI v0.1 functions are deprecated, the SBI console is quite useful for early debugging, because it works without any dcache, memory, or MMIO access in S mode. Signed-off-by: Samuel Holland Reviewed-by: Sean Anderson Reviewed-by: Bin Meng --- drivers/serial/Kconfig | 10 ++++++++++ drivers/serial/Makefile | 1 + drivers/serial/serial_sbi.c | 16 ++++++++++++++++ 3 files changed, 27 insertions(+) create mode 100644 drivers/serial/serial_sbi.c diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 3bb5b02eab..122a39789c 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -280,6 +280,14 @@ config DEBUG_EFI_CONSOLE U-Boot when running on top of EFI (Extensive Firmware Interface). This is a type of BIOS used by PCs. +config DEBUG_SBI_CONSOLE + bool "SBI" + depends on SBI_V01 + help + Select this to enable a debug console which calls back to SBI to + output to the console. This can be useful for early debugging of + U-Boot when running on top of SBI (Supervisor Binary Interface). + config DEBUG_UART_S5P bool "Samsung S5P" depends on ARCH_EXYNOS || ARCH_S5PC1XX @@ -442,6 +450,7 @@ endchoice config DEBUG_UART_BASE hex "Base address of UART" depends on DEBUG_UART + default 0 if DEBUG_SBI_CONSOLE default 0 if DEBUG_UART_SANDBOX help This is the base address of your UART for memory-mapped UARTs. @@ -452,6 +461,7 @@ config DEBUG_UART_BASE config DEBUG_UART_CLOCK int "UART input clock" depends on DEBUG_UART + default 0 if DEBUG_SBI_CONSOLE default 0 if DEBUG_UART_SANDBOX default 0 if DEBUG_MVEBU_A3700_UART help diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index 3cbea8156f..4edd2aa945 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -36,6 +36,7 @@ obj-$(CONFIG_ATMEL_USART) += atmel_usart.o obj-$(CONFIG_BCM6345_SERIAL) += serial_bcm6345.o obj-$(CONFIG_COREBOOT_SERIAL) += serial_coreboot.o obj-$(CONFIG_CORTINA_UART) += serial_cortina.o +obj-$(CONFIG_DEBUG_SBI_CONSOLE) += serial_sbi.o obj-$(CONFIG_EFI_APP) += serial_efi.o obj-$(CONFIG_LPC32XX_HSUART) += lpc32xx_hsuart.o obj-$(CONFIG_MCFUART) += serial_mcf.o diff --git a/drivers/serial/serial_sbi.c b/drivers/serial/serial_sbi.c new file mode 100644 index 0000000000..b9f35ed36e --- /dev/null +++ b/drivers/serial/serial_sbi.c @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#include +#include + +static inline void _debug_uart_init(void) +{ +} + +static inline void _debug_uart_putc(int c) +{ + if (CONFIG_IS_ENABLED(RISCV_SMODE)) + sbi_console_putchar(c); +} + +DEBUG_UART_FUNCS From 0d625f400bcab5361484a5446aa54133fd6fe213 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sun, 12 Sep 2021 11:05:47 -0500 Subject: [PATCH 06/12] riscv: Fix setting no-map in reserved memory nodes The no-map property is wrongly skipped if a no-map reserved memory node follows one without that property. Fix this by not remembering the absence of a no-map property across loop iterations. Fixes: d4ea649f179a ("riscv: Provide a mechanism to fix DT for reserved memory") Signed-off-by: Samuel Holland Reviewed-by: Bin Meng Reviewed-by: Rick Chen Reviewed-by: Atish Patra --- arch/riscv/lib/fdt_fixup.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/arch/riscv/lib/fdt_fixup.c b/arch/riscv/lib/fdt_fixup.c index f636b28449..61cf893526 100644 --- a/arch/riscv/lib/fdt_fixup.c +++ b/arch/riscv/lib/fdt_fixup.c @@ -31,7 +31,6 @@ int riscv_fdt_copy_resv_mem_node(const void *src, void *dst) fdt_addr_t addr; fdt_size_t size; int offset, node, err, rmem_offset; - bool nomap = true; char basename[32] = {0}; int bname_len; int max_len = sizeof(basename); @@ -81,9 +80,7 @@ int riscv_fdt_copy_resv_mem_node(const void *src, void *dst) log_err("failed to add reserved memory: %d\n", err); return err; } - if (!fdt_getprop(src, node, "no-map", NULL)) - nomap = false; - if (nomap) { + if (fdt_getprop(src, node, "no-map", NULL)) { rmem_offset = fdt_node_offset_by_phandle(dst, phandle); fdt_setprop_empty(dst, rmem_offset, "no-map"); } From dd573b6b213e859b9d705aabee3ba09e7e7012d2 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sun, 12 Sep 2021 11:26:45 -0500 Subject: [PATCH 07/12] riscv: image: Use the first DRAM bank for bootm_low bootm_low is used as a base address is used to allocate space for the FDT blob, initrd, cmdline, etc. when booting Linux. Set the default value for RISC-V to the start of the first DRAM bank, so platforms can get their DRAM layout from the device tree, and do not need to define CONFIG_SYS_SDRAM_BASE. Signed-off-by: Samuel Holland Reviewed-by: Leo Yu-Chi Liang --- common/image.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/image.c b/common/image.c index e199d61a4c..8ac57081fd 100644 --- a/common/image.c +++ b/common/image.c @@ -684,7 +684,7 @@ ulong env_get_bootm_low(void) #if defined(CONFIG_SYS_SDRAM_BASE) return CONFIG_SYS_SDRAM_BASE; -#elif defined(CONFIG_ARM) || defined(CONFIG_MICROBLAZE) +#elif defined(CONFIG_ARM) || defined(CONFIG_MICROBLAZE) || defined(CONFIG_RISCV) return gd->bd->bi_dram[0].start; #else return 0; From 3fbcfaa6f38c7549553fb8bf31896f205a7bf93a Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 12 Sep 2021 21:11:44 +0200 Subject: [PATCH 08/12] riscv: add missing SBI extension definitions Add the System Reset Extension and the Hart State Management Extension definitions. Add missing RFENCE Extension enum values. The SBI 0.1 extension constants are needed for the sbi command. Remove an #ifdef. Cf. https://github.com/riscv/riscv-sbi-doc/blob/master/riscv-sbi.adoc Signed-off-by: Heinrich Schuchardt Reviewed-by: Leo Yu-Chi Liang Reviewed-by: Sean Anderson Reviewed-by: Bin Meng --- arch/riscv/include/asm/sbi.h | 39 ++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/arch/riscv/include/asm/sbi.h b/arch/riscv/include/asm/sbi.h index 53ca316180..34a115afc3 100644 --- a/arch/riscv/include/asm/sbi.h +++ b/arch/riscv/include/asm/sbi.h @@ -12,7 +12,6 @@ #include enum sbi_ext_id { -#ifdef CONFIG_SBI_V01 SBI_EXT_0_1_SET_TIMER = 0x0, SBI_EXT_0_1_CONSOLE_PUTCHAR = 0x1, SBI_EXT_0_1_CONSOLE_GETCHAR = 0x2, @@ -22,11 +21,12 @@ enum sbi_ext_id { SBI_EXT_0_1_REMOTE_SFENCE_VMA = 0x6, SBI_EXT_0_1_REMOTE_SFENCE_VMA_ASID = 0x7, SBI_EXT_0_1_SHUTDOWN = 0x8, -#endif SBI_EXT_BASE = 0x10, SBI_EXT_TIME = 0x54494D45, SBI_EXT_IPI = 0x735049, SBI_EXT_RFENCE = 0x52464E43, + SBI_EXT_HSM = 0x48534D, + SBI_EXT_SRST = 0x53525354, }; enum sbi_ext_base_fid { @@ -51,6 +51,41 @@ enum sbi_ext_rfence_fid { SBI_EXT_RFENCE_REMOTE_FENCE_I = 0, SBI_EXT_RFENCE_REMOTE_SFENCE_VMA, SBI_EXT_RFENCE_REMOTE_SFENCE_VMA_ASID, + SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA_VMID, + SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA, + SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA_ASID, + SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA, +}; + +enum sbi_ext_hsm_fid { + SBI_EXT_HSM_HART_START = 0, + SBI_EXT_HSM_HART_STOP, + SBI_EXT_HSM_HART_STATUS, + SBI_EXT_HSM_HART_SUSPEND, +}; + +enum sbi_hsm_hart_status { + SBI_HSM_HART_STATUS_STARTED = 0, + SBI_HSM_HART_STATUS_STOPPED, + SBI_HSM_HART_STATUS_START_PENDING, + SBI_HSM_HART_STATUS_STOP_PENDING, + SBI_HSM_HART_STATUS_SUSPEND_PENDING, + SBI_HSM_HART_STATUS_RESUME_PENDING, +}; + +enum sbi_ext_srst_fid { + SBI_EXT_SRST_RESET = 0, +}; + +enum sbi_srst_reset_type { + SBI_SRST_RESET_TYPE_SHUTDOWN = 0, + SBI_SRST_RESET_TYPE_COLD_REBOOT, + SBI_SRST_RESET_TYPE_WARM_REBOOT, +}; + +enum sbi_srst_reset_reason { + SBI_SRST_RESET_REASON_NONE = 0, + SBI_SRST_RESET_REASON_SYS_FAILURE, }; #ifdef CONFIG_SBI_V01 From 09d7cc3369fcb9a6c86996ae8a58ff5dc34b3798 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 12 Sep 2021 21:11:45 +0200 Subject: [PATCH 09/12] cmd/sbi: use constants instead of numerical values Use constants for extension IDs. Signed-off-by: Heinrich Schuchardt Reviewed-by: Sean Anderson Reviewed-by: Leo Yu-Chi Liang Reviewed-by: Bin Meng --- cmd/riscv/sbi.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/cmd/riscv/sbi.c b/cmd/riscv/sbi.c index 90c0811e14..65a2c93290 100644 --- a/cmd/riscv/sbi.c +++ b/cmd/riscv/sbi.c @@ -29,21 +29,21 @@ static struct sbi_imp implementations[] = { }; static struct sbi_ext extensions[] = { - { 0x00000000, "sbi_set_timer" }, - { 0x00000001, "sbi_console_putchar" }, - { 0x00000002, "sbi_console_getchar" }, - { 0x00000003, "sbi_clear_ipi" }, - { 0x00000004, "sbi_send_ipi" }, - { 0x00000005, "sbi_remote_fence_i" }, - { 0x00000006, "sbi_remote_sfence_vma" }, - { 0x00000007, "sbi_remote_sfence_vma_asid" }, - { 0x00000008, "sbi_shutdown" }, - { 0x00000010, "SBI Base Functionality" }, - { 0x54494D45, "Timer Extension" }, - { 0x00735049, "IPI Extension" }, - { 0x52464E43, "RFENCE Extension" }, - { 0x0048534D, "Hart State Management Extension" }, - { 0x53525354, "System Reset Extension" }, + { SBI_EXT_0_1_SET_TIMER, "sbi_set_timer" }, + { SBI_EXT_0_1_CONSOLE_PUTCHAR, "sbi_console_putchar" }, + { SBI_EXT_0_1_CONSOLE_GETCHAR, "sbi_console_getchar" }, + { SBI_EXT_0_1_CLEAR_IPI, "sbi_clear_ipi" }, + { SBI_EXT_0_1_SEND_IPI, "sbi_send_ipi" }, + { SBI_EXT_0_1_REMOTE_FENCE_I, "sbi_remote_fence_i" }, + { SBI_EXT_0_1_REMOTE_SFENCE_VMA, "sbi_remote_sfence_vma" }, + { SBI_EXT_0_1_REMOTE_SFENCE_VMA_ASID, "sbi_remote_sfence_vma_asid" }, + { SBI_EXT_0_1_SHUTDOWN, "sbi_shutdown" }, + { SBI_EXT_BASE, "SBI Base Functionality" }, + { SBI_EXT_TIME, "Timer Extension" }, + { SBI_EXT_IPI, "IPI Extension" }, + { SBI_EXT_RFENCE, "RFENCE Extension" }, + { SBI_EXT_HSM, "Hart State Management Extension" }, + { SBI_EXT_SRST, "System Reset Extension" }, }; static int do_sbi(struct cmd_tbl *cmdtp, int flag, int argc, From 24ed5317d427bfe278a1329abbf4522dba1025a3 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 12 Sep 2021 21:11:46 +0200 Subject: [PATCH 10/12] sysreset: provide SBI based sysreset driver Provide sysreset driver using the SBI system reset extension. Signed-off-by: Heinrich Schuchardt Reviewed-by: Sean Anderson Reviewed-by: Bin Meng Tested-by: Samuel Holland --- MAINTAINERS | 1 + arch/riscv/cpu/cpu.c | 13 ++++++++- arch/riscv/include/asm/sbi.h | 1 + arch/riscv/lib/sbi.c | 12 ++++++++ drivers/sysreset/Kconfig | 12 ++++++++ drivers/sysreset/Makefile | 1 + drivers/sysreset/sysreset_sbi.c | 51 +++++++++++++++++++++++++++++++++ 7 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 drivers/sysreset/sysreset_sbi.c diff --git a/MAINTAINERS b/MAINTAINERS index 31b49c0a95..71f468c00a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1026,6 +1026,7 @@ T: git https://source.denx.de/u-boot/custodians/u-boot-riscv.git F: arch/riscv/ F: cmd/riscv/ F: doc/usage/sbi.rst +F: drivers/sysreset/sysreset_sbi.c F: drivers/timer/andes_plmt_timer.c F: drivers/timer/sifive_clint_timer.c F: tools/prelink-riscv.c diff --git a/arch/riscv/cpu/cpu.c b/arch/riscv/cpu/cpu.c index c894ac10b5..8e49b6d736 100644 --- a/arch/riscv/cpu/cpu.c +++ b/arch/riscv/cpu/cpu.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -138,7 +139,17 @@ int arch_cpu_init_dm(void) int arch_early_init_r(void) { - return riscv_cpu_probe(); + int ret; + + ret = riscv_cpu_probe(); + if (ret) + return ret; + + if (IS_ENABLED(CONFIG_SYSRESET_SBI)) + device_bind_driver(gd->dm_root, "sbi-sysreset", + "sbi-sysreset", NULL); + + return 0; } /** diff --git a/arch/riscv/include/asm/sbi.h b/arch/riscv/include/asm/sbi.h index 34a115afc3..5030892b47 100644 --- a/arch/riscv/include/asm/sbi.h +++ b/arch/riscv/include/asm/sbi.h @@ -153,5 +153,6 @@ void sbi_set_timer(uint64_t stime_value); long sbi_get_spec_version(void); int sbi_get_impl_id(void); int sbi_probe_extension(int ext); +void sbi_srst_reset(unsigned long type, unsigned long reason); #endif diff --git a/arch/riscv/lib/sbi.c b/arch/riscv/lib/sbi.c index 77845a73ca..2b53896b8a 100644 --- a/arch/riscv/lib/sbi.c +++ b/arch/riscv/lib/sbi.c @@ -108,6 +108,18 @@ int sbi_probe_extension(int extid) return -ENOTSUPP; } +/** + * sbi_srst_reset() - invoke system reset extension + * + * @type: type of reset + * @reason: reason for reset + */ +void sbi_srst_reset(unsigned long type, unsigned long reason) +{ + sbi_ecall(SBI_EXT_SRST, SBI_EXT_SRST_RESET, type, reason, + 0, 0, 0, 0); +} + #ifdef CONFIG_SBI_V01 /** diff --git a/drivers/sysreset/Kconfig b/drivers/sysreset/Kconfig index ac77ffbc8b..43a948cfcd 100644 --- a/drivers/sysreset/Kconfig +++ b/drivers/sysreset/Kconfig @@ -85,6 +85,18 @@ config SYSRESET_PSCI Enable PSCI SYSTEM_RESET function call. To use this, PSCI firmware must be running on your system. +config SYSRESET_SBI + bool "Enable support for SBI System Reset" + depends on RISCV_SMODE && SBI_V02 + select SYSRESET_CMD_POWEROFF if CMD_POWEROFF + help + Enable system reset and poweroff via the SBI system reset extension. + The extension was introduced in version 0.3 of the SBI specification. + + If the SBI implementation provides the extension, is board specific. + The RISC-V platform specification mandates the extension for rich + operating system platforms. + config SYSRESET_SOCFPGA bool "Enable support for Intel SOCFPGA family" depends on ARCH_SOCFPGA && (TARGET_SOCFPGA_GEN5 || TARGET_SOCFPGA_ARRIA10) diff --git a/drivers/sysreset/Makefile b/drivers/sysreset/Makefile index de81c399d7..8e00be0779 100644 --- a/drivers/sysreset/Makefile +++ b/drivers/sysreset/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_SYSRESET_MPC83XX) += sysreset_mpc83xx.o obj-$(CONFIG_SYSRESET_MICROBLAZE) += sysreset_microblaze.o obj-$(CONFIG_SYSRESET_OCTEON) += sysreset_octeon.o obj-$(CONFIG_SYSRESET_PSCI) += sysreset_psci.o +obj-$(CONFIG_SYSRESET_SBI) += sysreset_sbi.o obj-$(CONFIG_SYSRESET_SOCFPGA) += sysreset_socfpga.o obj-$(CONFIG_SYSRESET_SOCFPGA_SOC64) += sysreset_socfpga_soc64.o obj-$(CONFIG_SYSRESET_TI_SCI) += sysreset-ti-sci.o diff --git a/drivers/sysreset/sysreset_sbi.c b/drivers/sysreset/sysreset_sbi.c new file mode 100644 index 0000000000..5e8090d62b --- /dev/null +++ b/drivers/sysreset/sysreset_sbi.c @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2021, Heinrich Schuchardt + */ + +#include +#include +#include +#include +#include +#include + +static enum sbi_srst_reset_type reset_type_map[SYSRESET_COUNT] = { + [SYSRESET_WARM] = SBI_SRST_RESET_TYPE_WARM_REBOOT, + [SYSRESET_COLD] = SBI_SRST_RESET_TYPE_COLD_REBOOT, + [SYSRESET_POWER] = SBI_SRST_RESET_TYPE_COLD_REBOOT, + [SYSRESET_POWER_OFF] = SBI_SRST_RESET_TYPE_SHUTDOWN, +}; + +static int sbi_sysreset_request(struct udevice *dev, enum sysreset_t type) +{ + enum sbi_srst_reset_type reset_type; + + reset_type = reset_type_map[type]; + sbi_srst_reset(reset_type, SBI_SRST_RESET_REASON_NONE); + + return -EINPROGRESS; +} + +static int sbi_sysreset_probe(struct udevice *dev) +{ + long have_reset; + + have_reset = sbi_probe_extension(SBI_EXT_SRST); + if (have_reset) + return 0; + + log_warning("SBI has no system reset extension\n"); + return -ENOENT; +} + +static struct sysreset_ops sbi_sysreset_ops = { + .request = sbi_sysreset_request, +}; + +U_BOOT_DRIVER(sbi_sysreset) = { + .name = "sbi-sysreset", + .id = UCLASS_SYSRESET, + .ops = &sbi_sysreset_ops, + .probe = sbi_sysreset_probe, +}; From b11f42015f82904f72cbd5a25032c0d82402a423 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 12 Sep 2021 21:11:47 +0200 Subject: [PATCH 11/12] configs: enable SYSRESET_SBI on qemu-riscvXX_smode_defconfig There should be a platform compiled with the new driver. Enable CONFIG_SYSRESET_SBI for all QEMU boards using SBI. If you want to test the SBI sysreset driver, disable CONFIG_SYSRESET_SYSCON. Signed-off-by: Heinrich Schuchardt Reviewed-by: Leo Yu-Chi Liang --- configs/qemu-riscv32_smode_defconfig | 1 + configs/qemu-riscv32_spl_defconfig | 1 + configs/qemu-riscv64_smode_defconfig | 1 + configs/qemu-riscv64_spl_defconfig | 1 + 4 files changed, 4 insertions(+) diff --git a/configs/qemu-riscv32_smode_defconfig b/configs/qemu-riscv32_smode_defconfig index f13661e2ed..a009f62369 100644 --- a/configs/qemu-riscv32_smode_defconfig +++ b/configs/qemu-riscv32_smode_defconfig @@ -15,3 +15,4 @@ CONFIG_CMD_NVEDIT_EFI=y CONFIG_OF_PRIOR_STAGE=y CONFIG_SYS_RELOC_GD_ENV_ADDR=y CONFIG_DM_MTD=y +CONFIG_SYSRESET_SBI=y diff --git a/configs/qemu-riscv32_spl_defconfig b/configs/qemu-riscv32_spl_defconfig index da7a4d2c80..aac6f389a7 100644 --- a/configs/qemu-riscv32_spl_defconfig +++ b/configs/qemu-riscv32_spl_defconfig @@ -17,3 +17,4 @@ CONFIG_CMD_SBI=y CONFIG_OF_PRIOR_STAGE=y CONFIG_SYS_RELOC_GD_ENV_ADDR=y CONFIG_DM_MTD=y +CONFIG_SYSRESET_SBI=y diff --git a/configs/qemu-riscv64_smode_defconfig b/configs/qemu-riscv64_smode_defconfig index 63b205d2a7..db2f21d8db 100644 --- a/configs/qemu-riscv64_smode_defconfig +++ b/configs/qemu-riscv64_smode_defconfig @@ -18,3 +18,4 @@ CONFIG_CMD_NVEDIT_EFI=y CONFIG_OF_PRIOR_STAGE=y CONFIG_SYS_RELOC_GD_ENV_ADDR=y CONFIG_DM_MTD=y +CONFIG_SYSRESET_SBI=y diff --git a/configs/qemu-riscv64_spl_defconfig b/configs/qemu-riscv64_spl_defconfig index 96f2e3ae5d..cf33870135 100644 --- a/configs/qemu-riscv64_spl_defconfig +++ b/configs/qemu-riscv64_spl_defconfig @@ -18,3 +18,4 @@ CONFIG_CMD_SBI=y CONFIG_OF_PRIOR_STAGE=y CONFIG_SYS_RELOC_GD_ENV_ADDR=y CONFIG_DM_MTD=y +CONFIG_SYSRESET_SBI=y From 1b2b52f29402b5aaccccadfe4ba11bd3f29bd414 Mon Sep 17 00:00:00 2001 From: Leo Yu-Chi Liang Date: Thu, 23 Sep 2021 10:34:29 +0800 Subject: [PATCH 12/12] riscv: ae350: enable Coherence Manager for ae350 If Coherence Manager were not set in the beginning, u-boot-spl would sometimes fail to boot to u-boot proper. Enable CM and I/D cache at the same time in harts_early_init Signed-off-by: Leo Yu-Chi Liang Reviewed-by: Rick Chen --- arch/riscv/cpu/ax25/cpu.c | 42 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/arch/riscv/cpu/ax25/cpu.c b/arch/riscv/cpu/ax25/cpu.c index f092600e14..c4c2de2ef0 100644 --- a/arch/riscv/cpu/ax25/cpu.c +++ b/arch/riscv/cpu/ax25/cpu.c @@ -9,6 +9,22 @@ #include #include #include +#include + +#define CSR_MCACHE_CTL 0x7ca +#define CSR_MMISC_CTL 0x7d0 +#define CSR_MARCHID 0xf12 + +#define V5_MCACHE_CTL_IC_EN_OFFSET 0 +#define V5_MCACHE_CTL_DC_EN_OFFSET 1 +#define V5_MCACHE_CTL_DC_COHEN_OFFSET 19 +#define V5_MCACHE_CTL_DC_COHSTA_OFFSET 20 + +#define V5_MCACHE_CTL_IC_EN BIT(V5_MCACHE_CTL_IC_EN_OFFSET) +#define V5_MCACHE_CTL_DC_EN BIT(V5_MCACHE_CTL_DC_EN_OFFSET) +#define V5_MCACHE_CTL_DC_COHEN_EN BIT(V5_MCACHE_CTL_DC_COHEN_OFFSET) +#define V5_MCACHE_CTL_DC_COHSTA_EN BIT(V5_MCACHE_CTL_DC_COHSTA_OFFSET) + /* * cleanup_before_linux() is called just before we call linux @@ -27,3 +43,29 @@ int cleanup_before_linux(void) return 0; } + +void harts_early_init(void) +{ + if (CONFIG_IS_ENABLED(RISCV_MMODE)) { + unsigned long long mcache_ctl_val = csr_read(CSR_MCACHE_CTL); + + if (!(mcache_ctl_val & V5_MCACHE_CTL_DC_COHEN_EN)) + mcache_ctl_val |= V5_MCACHE_CTL_DC_COHEN_EN; + if (!(mcache_ctl_val & V5_MCACHE_CTL_IC_EN)) + mcache_ctl_val |= V5_MCACHE_CTL_IC_EN; + if (!(mcache_ctl_val & V5_MCACHE_CTL_DC_EN)) + mcache_ctl_val |= V5_MCACHE_CTL_DC_EN; + csr_write(CSR_MCACHE_CTL, mcache_ctl_val); + + /* + * Check DC_COHEN_EN, if cannot write to mcache_ctl, + * we assume this bitmap not support L2 CM + */ + mcache_ctl_val = csr_read(CSR_MCACHE_CTL); + if ((mcache_ctl_val & V5_MCACHE_CTL_DC_COHEN_EN)) { + /* Wait for DC_COHSTA bit be set */ + while (!(mcache_ctl_val & V5_MCACHE_CTL_DC_COHSTA_EN)) + mcache_ctl_val = csr_read(CSR_MCACHE_CTL); + } + } +}