diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/clk/clk_kendryte.c | 134 | ||||
-rw-r--r-- | drivers/serial/Kconfig | 10 | ||||
-rw-r--r-- | drivers/serial/Makefile | 1 | ||||
-rw-r--r-- | drivers/serial/serial_sbi.c | 16 | ||||
-rw-r--r-- | drivers/sysreset/Kconfig | 12 | ||||
-rw-r--r-- | drivers/sysreset/Makefile | 1 | ||||
-rw-r--r-- | drivers/sysreset/sysreset_sbi.c | 51 |
7 files changed, 170 insertions, 55 deletions
diff --git a/drivers/clk/clk_kendryte.c b/drivers/clk/clk_kendryte.c index 31487569686..97efda5b6f0 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,95 @@ 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 (out_of_spec) { + u64 new_r, new_od; + + if (!swapped) { + u64 tmp = r; - if (vco > 1750000000 || vco < 340000000) - out_of_spec = true; + 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--; + /* + * 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--; + } + + /* + * 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; } } - 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; } @@ -849,9 +872,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 +915,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 +1049,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 +1121,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); 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 <debug_uart.h> +#include <asm/sbi.h> + +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 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 <heinrich.schuchardt@canonical.com> + */ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <log.h> +#include <sysreset.h> +#include <asm/sbi.h> + +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, +}; |