From 54d5d2d56bb6c46c996a4d249dbae3b12a7a4fac Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Sat, 11 Sep 2021 13:20:00 -0400 Subject: 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 31487569686..2caa21aec9e 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); -- cgit v1.3.1 From 49708749701d957dacb2b01ea3d71e457804f7eb Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Sat, 11 Sep 2021 13:20:01 -0400 Subject: 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 | 107 ++++++++++++++++++++++----------------------- 1 file changed, 53 insertions(+), 54 deletions(-) diff --git a/drivers/clk/clk_kendryte.c b/drivers/clk/clk_kendryte.c index 2caa21aec9e..69691c4a04c 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; } -- cgit v1.3.1 From 6e23c9f0c1ebe9b93077b6901733cd01d3848208 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Sat, 11 Sep 2021 13:20:02 -0400 Subject: 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 | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/test/dm/k210_pll.c b/test/dm/k210_pll.c index 54764f269c5..5574ac96fa3 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)); - - 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)); +#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) + + compare(390000000, 26000000); + compare(26000000, 390000000); + compare(400000000, 26000000); + compare(27000000, 26000000); + compare(26000000, 27000000); return 0; } -- cgit v1.3.1 From 425c08faa8a2d6af5d9c1d83a97572f6401137bf Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Sat, 11 Sep 2021 13:20:03 -0400 Subject: 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 69691c4a04c..97efda5b6f0 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 5574ac96fa3..f55379f3365 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; } -- cgit v1.3.1 From 41f7be733444b9221c828ee9c7c22cddfac5a28c Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sun, 12 Sep 2021 10:56:09 -0500 Subject: 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 3bb5b02eabb..122a39789cb 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 3cbea8156f8..4edd2aa9458 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 00000000000..b9f35ed36e6 --- /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 -- cgit v1.3.1 From 0d625f400bcab5361484a5446aa54133fd6fe213 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sun, 12 Sep 2021 11:05:47 -0500 Subject: 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 f636b284497..61cf8935269 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"); } -- cgit v1.3.1 From dd573b6b213e859b9d705aabee3ba09e7e7012d2 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sun, 12 Sep 2021 11:26:45 -0500 Subject: 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 e199d61a4c3..8ac57081fdd 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; -- cgit v1.3.1 From 3fbcfaa6f38c7549553fb8bf31896f205a7bf93a Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 12 Sep 2021 21:11:44 +0200 Subject: 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 53ca316180e..34a115afc39 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 -- cgit v1.3.1 From 09d7cc3369fcb9a6c86996ae8a58ff5dc34b3798 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 12 Sep 2021 21:11:45 +0200 Subject: 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 90c0811e14c..65a2c932905 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, -- cgit v1.3.1 From 24ed5317d427bfe278a1329abbf4522dba1025a3 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 12 Sep 2021 21:11:46 +0200 Subject: 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 31b49c0a95f..71f468c00a8 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 c894ac10b53..8e49b6d7364 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 34a115afc39..5030892b479 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 77845a73ca3..2b53896b8a3 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 ac77ffbc8be..43a948cfcde 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 de81c399d79..8e00be07794 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 00000000000..5e8090d62bf --- /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, +}; -- cgit v1.3.1 From b11f42015f82904f72cbd5a25032c0d82402a423 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 12 Sep 2021 21:11:47 +0200 Subject: 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 f13661e2ed7..a009f623694 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 da7a4d2c809..aac6f389a79 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 63b205d2a75..db2f21d8dbc 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 96f2e3ae5d1..cf33870135d 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 -- cgit v1.3.1 From 1b2b52f29402b5aaccccadfe4ba11bd3f29bd414 Mon Sep 17 00:00:00 2001 From: Leo Yu-Chi Liang Date: Thu, 23 Sep 2021 10:34:29 +0800 Subject: 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 f092600e14d..c4c2de2ef05 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); + } + } +} -- cgit v1.3.1