summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/clk/clk_kendryte.c134
-rw-r--r--drivers/serial/Kconfig10
-rw-r--r--drivers/serial/Makefile1
-rw-r--r--drivers/serial/serial_sbi.c16
-rw-r--r--drivers/sysreset/Kconfig12
-rw-r--r--drivers/sysreset/Makefile1
-rw-r--r--drivers/sysreset/sysreset_sbi.c51
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,
+};