diff options
author | Tom Rini <trini@konsulko.com> | 2023-12-18 08:31:50 -0500 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2023-12-18 09:55:32 -0500 |
commit | 1373ffde52e16af83fb14a1d228508a8caaa9996 (patch) | |
tree | 03bb09d38a260233e3f5b9493d14c82dbd267299 /drivers | |
parent | fdefb4e194c65777fa11479119adaa71651f41d4 (diff) | |
parent | 97a897444235921ce19b4f8a3b27de6f5a9ab367 (diff) | |
download | u-boot-1373ffde52e16af83fb14a1d228508a8caaa9996.zip u-boot-1373ffde52e16af83fb14a1d228508a8caaa9996.tar.gz u-boot-1373ffde52e16af83fb14a1d228508a8caaa9996.tar.bz2 |
Merge tag 'v2024.01-rc5' into next
Prepare v2024.01-rc5
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/clk/clk-composite.c | 2 | ||||
-rw-r--r-- | drivers/clk/clk-uclass.c | 2 | ||||
-rw-r--r-- | drivers/clk/clk.c | 18 | ||||
-rw-r--r-- | drivers/clk/clk_sandbox_ccf.c | 1 | ||||
-rw-r--r-- | drivers/clk/clk_sandbox_test.c | 1 | ||||
-rw-r--r-- | drivers/clk/starfive/clk-jh7110.c | 9 | ||||
-rw-r--r-- | drivers/ddr/imx/phy/ddrphy_utils.c | 5 | ||||
-rw-r--r-- | drivers/misc/Kconfig | 2 | ||||
-rw-r--r-- | drivers/mtd/spi/Kconfig | 5 | ||||
-rw-r--r-- | drivers/mtd/spi/spi-nor-ids.c | 5 | ||||
-rw-r--r-- | drivers/power/Kconfig | 1 | ||||
-rw-r--r-- | drivers/watchdog/Kconfig | 7 | ||||
-rw-r--r-- | drivers/watchdog/Makefile | 1 | ||||
-rw-r--r-- | drivers/watchdog/starfive_wdt.c | 329 |
14 files changed, 377 insertions, 11 deletions
diff --git a/drivers/clk/clk-composite.c b/drivers/clk/clk-composite.c index 6eb2b81..d2e5a1a 100644 --- a/drivers/clk/clk-composite.c +++ b/drivers/clk/clk-composite.c @@ -66,7 +66,7 @@ static ulong clk_composite_set_rate(struct clk *clk, unsigned long rate) const struct clk_ops *rate_ops = composite->rate_ops; struct clk *clk_rate = composite->rate; - if (rate && rate_ops) + if (rate && rate_ops && rate_ops->set_rate) return rate_ops->set_rate(clk_rate, rate); else return clk_get_rate(clk); diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c index 3b5e3f9..3e9d68f 100644 --- a/drivers/clk/clk-uclass.c +++ b/drivers/clk/clk-uclass.c @@ -640,6 +640,7 @@ int clk_enable(struct clk *clk) if (CONFIG_IS_ENABLED(CLK_CCF)) { /* Take id 0 as a non-valid clk, such as dummy */ if (clk->id && !clk_get_by_id(clk->id, &clkp)) { + ops = clk_dev_ops(clkp->dev); if (clkp->enable_count) { clkp->enable_count++; return 0; @@ -699,6 +700,7 @@ int clk_disable(struct clk *clk) if (CONFIG_IS_ENABLED(CLK_CCF)) { if (clk->id && !clk_get_by_id(clk->id, &clkp)) { + ops = clk_dev_ops(clkp->dev); if (clkp->flags & CLK_IS_CRITICAL) return 0; diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index a5a3461..6ede1b4 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -18,17 +18,19 @@ int clk_register(struct clk *clk, const char *drv_name, const char *name, const char *parent_name) { - struct udevice *parent; + struct udevice *parent = NULL; struct driver *drv; int ret; - ret = uclass_get_device_by_name(UCLASS_CLK, parent_name, &parent); - if (ret) { - log_err("%s: failed to get %s device (parent of %s)\n", - __func__, parent_name, name); - } else { - log_debug("%s: name: %s parent: %s [0x%p]\n", __func__, name, - parent->name, parent); + if (parent_name) { + ret = uclass_get_device_by_name(UCLASS_CLK, parent_name, &parent); + if (ret) { + log_err("%s: failed to get %s device (parent of %s)\n", + __func__, parent_name, name); + } else { + log_debug("%s: name: %s parent: %s [0x%p]\n", __func__, name, + parent->name, parent); + } } drv = lists_driver_lookup_name(drv_name); diff --git a/drivers/clk/clk_sandbox_ccf.c b/drivers/clk/clk_sandbox_ccf.c index fedcdd4..38184e2 100644 --- a/drivers/clk/clk_sandbox_ccf.c +++ b/drivers/clk/clk_sandbox_ccf.c @@ -284,6 +284,7 @@ static int sandbox_clk_ccf_probe(struct udevice *dev) U_BOOT_DRIVER(sandbox_clk_ccf) = { .name = "sandbox_clk_ccf", .id = UCLASS_CLK, + .ops = &ccf_clk_ops, .probe = sandbox_clk_ccf_probe, .of_match = sandbox_clk_ccf_test_ids, }; diff --git a/drivers/clk/clk_sandbox_test.c b/drivers/clk/clk_sandbox_test.c index 5807a45..c695b69 100644 --- a/drivers/clk/clk_sandbox_test.c +++ b/drivers/clk/clk_sandbox_test.c @@ -15,6 +15,7 @@ static const char * const sandbox_clk_test_names[] = { [SANDBOX_CLK_TEST_ID_FIXED] = "fixed", [SANDBOX_CLK_TEST_ID_SPI] = "spi", [SANDBOX_CLK_TEST_ID_I2C] = "i2c", + [SANDBOX_CLK_TEST_ID_I2C_ROOT] = "i2c_root", }; int sandbox_clk_test_get(struct udevice *dev) diff --git a/drivers/clk/starfive/clk-jh7110.c b/drivers/clk/starfive/clk-jh7110.c index a835541..a386948 100644 --- a/drivers/clk/starfive/clk-jh7110.c +++ b/drivers/clk/starfive/clk-jh7110.c @@ -434,6 +434,15 @@ static int jh7110_syscrg_init(struct udevice *dev) starfive_clk_gate(priv->reg, "i2c5_apb", "apb0", OFFSET(JH7110_SYSCLK_I2C5_APB))); + /* Watchdog clocks */ + clk_dm(JH7110_SYS_ID_TRANS(JH7110_SYSCLK_WDT_APB), + starfive_clk_gate(priv->reg, + "wdt_apb", "apb0", + OFFSET(JH7110_SYSCLK_WDT_APB))); + clk_dm(JH7110_SYS_ID_TRANS(JH7110_SYSCLK_WDT_CORE), + starfive_clk_gate(priv->reg, + "wdt_core", "oscillator", + OFFSET(JH7110_SYSCLK_WDT_CORE))); /* enable noc_bus_stg_axi clock */ if (!clk_get_by_id(JH7110_SYSCLK_NOC_BUS_STG_AXI, &pclk)) diff --git a/drivers/ddr/imx/phy/ddrphy_utils.c b/drivers/ddr/imx/phy/ddrphy_utils.c index fd8b411..45e1a70 100644 --- a/drivers/ddr/imx/phy/ddrphy_utils.c +++ b/drivers/ddr/imx/phy/ddrphy_utils.c @@ -111,11 +111,16 @@ void ddrphy_init_set_dfi_clk(unsigned int drate) dram_pll_init(MHZ(1000)); dram_disable_bypass(); break; + case 3734: case 3733: case 3732: dram_pll_init(MHZ(933)); dram_disable_bypass(); break; + case 3600: + dram_pll_init(MHZ(900)); + dram_disable_bypass(); + break; case 3200: dram_pll_init(MHZ(800)); dram_disable_bypass(); diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 97057de..ed7eced 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -615,7 +615,7 @@ config FS_LOADER ie. the FPGA device. config SPL_FS_LOADER - bool "Enable loader driver for file system" + bool "Enable loader driver for file system in SPL" depends on SPL help This is file system generic loader which can be used to load diff --git a/drivers/mtd/spi/Kconfig b/drivers/mtd/spi/Kconfig index 732b076..abed392 100644 --- a/drivers/mtd/spi/Kconfig +++ b/drivers/mtd/spi/Kconfig @@ -224,6 +224,11 @@ config SPI_FLASH_XTX Add support for various XTX (XTX Technology Limited) SPI flash chips (XT25xxx). +config SPI_FLASH_ZBIT + bool "ZBIT SPI flash support" + help + Add support for Zbit Semiconductor Inc. SPI flash chips (ZB25xxx). + endif config SPI_FLASH_USE_4K_SECTORS diff --git a/drivers/mtd/spi/spi-nor-ids.c b/drivers/mtd/spi/spi-nor-ids.c index 3cb132d..f86e7ff 100644 --- a/drivers/mtd/spi/spi-nor-ids.c +++ b/drivers/mtd/spi/spi-nor-ids.c @@ -572,5 +572,10 @@ const struct flash_info spi_nor_ids[] = { { INFO("xt25w01g", 0x0b651B, 0, 64 * 1024, 2048, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, #endif +#ifdef CONFIG_SPI_FLASH_ZBIT + /* Zbit Semiconductor Inc. */ + { INFO("zb25vq128", 0x5e4018, 0, 64 * 1024, 256, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, +#endif { }, }; diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index 2395720..33b8bc1 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -56,7 +56,6 @@ choice depends on ARCH_SUNXI default AXP209_POWER if MACH_SUN4I || MACH_SUN5I || MACH_SUN7I default AXP221_POWER if MACH_SUN6I || MACH_SUN8I_A23 || MACH_SUN8I_A33 || MACH_SUN8I_R40 - default AXP305_POWER if MACH_SUN50I_H616 default AXP818_POWER if MACH_SUN8I_A83T default SUNXI_NO_PMIC if MACH_SUNXI_H3_H5 || MACH_SUN50I || MACH_SUN8I_V3S diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 07fc494..5697261 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -344,6 +344,13 @@ config WDT_STM32MP Enable the STM32 watchdog (IWDG) driver. Enable support to configure STM32's on-SoC watchdog. +config WDT_STARFIVE + bool "StarFive watchdog timer support" + depends on WDT + imply WATCHDOG + help + Enable support for the watchdog timer of StarFive JH7110 SoC. + config WDT_SUNXI bool "Allwinner sunxi watchdog timer support" depends on WDT && ARCH_SUNXI diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index eef786f..5520d3d 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -44,6 +44,7 @@ obj-$(CONFIG_WDT_SBSA) += sbsa_gwdt.o obj-$(CONFIG_WDT_K3_RTI) += rti_wdt.o obj-$(CONFIG_WDT_SL28CPLD) += sl28cpld-wdt.o obj-$(CONFIG_WDT_SP805) += sp805_wdt.o +obj-$(CONFIG_WDT_STARFIVE) += starfive_wdt.o obj-$(CONFIG_WDT_STM32MP) += stm32mp_wdt.o obj-$(CONFIG_WDT_SUNXI) += sunxi_wdt.o obj-$(CONFIG_WDT_TANGIER) += tangier_wdt.o diff --git a/drivers/watchdog/starfive_wdt.c b/drivers/watchdog/starfive_wdt.c new file mode 100644 index 0000000..ee9ec4c --- /dev/null +++ b/drivers/watchdog/starfive_wdt.c @@ -0,0 +1,329 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Starfive Watchdog driver + * + * Copyright (C) 2022 StarFive Technology Co., Ltd. + */ + +#include <clk.h> +#include <dm.h> +#include <reset.h> +#include <wdt.h> +#include <linux/iopoll.h> + +/* JH7110 Watchdog register define */ +#define STARFIVE_WDT_JH7110_LOAD 0x000 +#define STARFIVE_WDT_JH7110_VALUE 0x004 +#define STARFIVE_WDT_JH7110_CONTROL 0x008 /* + * [0]: reset enable; + * [1]: interrupt enable && watchdog enable + * [31:2]: reserved. + */ +#define STARFIVE_WDT_JH7110_INTCLR 0x00c /* clear intterupt and reload the counter */ +#define STARFIVE_WDT_JH7110_IMS 0x014 +#define STARFIVE_WDT_JH7110_LOCK 0xc00 /* write 0x1ACCE551 to unlock */ + +/* WDOGCONTROL */ +#define STARFIVE_WDT_ENABLE 0x1 +#define STARFIVE_WDT_EN_SHIFT 0 +#define STARFIVE_WDT_RESET_EN 0x1 +#define STARFIVE_WDT_JH7110_RST_EN_SHIFT 1 + +/* WDOGLOCK */ +#define STARFIVE_WDT_JH7110_UNLOCK_KEY 0x1acce551 + +/* WDOGINTCLR */ +#define STARFIVE_WDT_INTCLR 0x1 +#define STARFIVE_WDT_JH7100_INTCLR_AVA_SHIFT 1 /* Watchdog can clear interrupt when 0 */ + +#define STARFIVE_WDT_MAXCNT 0xffffffff +#define STARFIVE_WDT_DEFAULT_TIME (15) +#define STARFIVE_WDT_DELAY_US 0 +#define STARFIVE_WDT_TIMEOUT_US 10000 + +/* module parameter */ +#define STARFIVE_WDT_EARLY_ENA 0 + +struct starfive_wdt_variant { + unsigned int control; /* Watchdog Control Resgister for reset enable */ + unsigned int load; /* Watchdog Load register */ + unsigned int reload; /* Watchdog Reload Control register */ + unsigned int enable; /* Watchdog Enable Register */ + unsigned int value; /* Watchdog Counter Value Register */ + unsigned int int_clr; /* Watchdog Interrupt Clear Register */ + unsigned int unlock; /* Watchdog Lock Register */ + unsigned int int_status; /* Watchdog Interrupt Status Register */ + + u32 unlock_key; + char enrst_shift; + char en_shift; + bool intclr_check; /* whether need to check it before clearing interrupt */ + char intclr_ava_shift; + bool double_timeout; /* The watchdog need twice timeout to reboot */ +}; + +struct starfive_wdt_priv { + void __iomem *base; + struct clk *core_clk; + struct clk *apb_clk; + struct reset_ctl_bulk *rst; + const struct starfive_wdt_variant *variant; + unsigned long freq; + u32 count; /* count of timeout */ + u32 reload; /* restore the count */ +}; + +/* Register layout and configuration for the JH7110 */ +static const struct starfive_wdt_variant starfive_wdt_jh7110_variant = { + .control = STARFIVE_WDT_JH7110_CONTROL, + .load = STARFIVE_WDT_JH7110_LOAD, + .enable = STARFIVE_WDT_JH7110_CONTROL, + .value = STARFIVE_WDT_JH7110_VALUE, + .int_clr = STARFIVE_WDT_JH7110_INTCLR, + .unlock = STARFIVE_WDT_JH7110_LOCK, + .unlock_key = STARFIVE_WDT_JH7110_UNLOCK_KEY, + .int_status = STARFIVE_WDT_JH7110_IMS, + .enrst_shift = STARFIVE_WDT_JH7110_RST_EN_SHIFT, + .en_shift = STARFIVE_WDT_EN_SHIFT, + .intclr_check = false, + .double_timeout = true, +}; + +static int starfive_wdt_enable_clock(struct starfive_wdt_priv *wdt) +{ + int ret; + + ret = clk_enable(wdt->apb_clk); + if (ret) + return ret; + + ret = clk_enable(wdt->core_clk); + if (ret) { + clk_disable(wdt->apb_clk); + return ret; + } + + return 0; +} + +static void starfive_wdt_disable_clock(struct starfive_wdt_priv *wdt) +{ + clk_disable(wdt->core_clk); + clk_disable(wdt->apb_clk); +} + +/* Write unlock-key to unlock. Write other value to lock. */ +static void starfive_wdt_unlock(struct starfive_wdt_priv *wdt) +{ + writel(wdt->variant->unlock_key, wdt->base + wdt->variant->unlock); +} + +static void starfive_wdt_lock(struct starfive_wdt_priv *wdt) +{ + writel(~wdt->variant->unlock_key, wdt->base + wdt->variant->unlock); +} + +/* enable watchdog interrupt to reset/reboot */ +static void starfive_wdt_enable_reset(struct starfive_wdt_priv *wdt) +{ + u32 val; + + val = readl(wdt->base + wdt->variant->control); + val |= STARFIVE_WDT_RESET_EN << wdt->variant->enrst_shift; + writel(val, wdt->base + wdt->variant->control); +} + +/* waiting interrupt can be free to clear */ +static int starfive_wdt_wait_int_free(struct starfive_wdt_priv *wdt) +{ + u32 value; + + return readl_poll_timeout(wdt->base + wdt->variant->int_clr, value, + !(value & BIT(wdt->variant->intclr_ava_shift)), + STARFIVE_WDT_TIMEOUT_US); +} + +/* clear interrupt signal before initialization or reload */ +static int starfive_wdt_int_clr(struct starfive_wdt_priv *wdt) +{ + int ret; + + if (wdt->variant->intclr_check) { + ret = starfive_wdt_wait_int_free(wdt); + if (ret) + return ret; + } + writel(STARFIVE_WDT_INTCLR, wdt->base + wdt->variant->int_clr); + + return 0; +} + +static inline void starfive_wdt_set_count(struct starfive_wdt_priv *wdt, + u32 val) +{ + writel(val, wdt->base + wdt->variant->load); +} + +/* enable watchdog */ +static inline void starfive_wdt_enable(struct starfive_wdt_priv *wdt) +{ + u32 val; + + val = readl(wdt->base + wdt->variant->enable); + val |= STARFIVE_WDT_ENABLE << wdt->variant->en_shift; + writel(val, wdt->base + wdt->variant->enable); +} + +/* disable watchdog */ +static inline void starfive_wdt_disable(struct starfive_wdt_priv *wdt) +{ + u32 val; + + val = readl(wdt->base + wdt->variant->enable); + val &= ~(STARFIVE_WDT_ENABLE << wdt->variant->en_shift); + writel(val, wdt->base + wdt->variant->enable); +} + +static inline void starfive_wdt_set_reload_count(struct starfive_wdt_priv *wdt, + u32 count) +{ + starfive_wdt_set_count(wdt, count); + + /* 7100 need set any value to reload register and could reload value to counter */ + if (wdt->variant->reload) + writel(0x1, wdt->base + wdt->variant->reload); +} + +static int starfive_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags) +{ + int ret; + struct starfive_wdt_priv *wdt = dev_get_priv(dev); + + starfive_wdt_unlock(wdt); + /* disable watchdog, to be safe */ + starfive_wdt_disable(wdt); + + starfive_wdt_enable_reset(wdt); + ret = starfive_wdt_int_clr(wdt); + if (ret) + goto exit; + + wdt->count = (timeout_ms / 1000) * wdt->freq; + if (wdt->variant->double_timeout) + wdt->count /= 2; + + starfive_wdt_set_count(wdt, wdt->count); + starfive_wdt_enable(wdt); + +exit: + starfive_wdt_lock(wdt); + return ret; +} + +static int starfive_wdt_stop(struct udevice *dev) +{ + struct starfive_wdt_priv *wdt = dev_get_priv(dev); + + starfive_wdt_unlock(wdt); + starfive_wdt_disable(wdt); + starfive_wdt_lock(wdt); + + return 0; +} + +static int starfive_wdt_reset(struct udevice *dev) +{ + int ret; + struct starfive_wdt_priv *wdt = dev_get_priv(dev); + + starfive_wdt_unlock(wdt); + ret = starfive_wdt_int_clr(wdt); + if (ret) + goto exit; + + starfive_wdt_set_reload_count(wdt, wdt->count); + +exit: + starfive_wdt_lock(wdt); + + return ret; +} + +static const struct wdt_ops starfive_wdt_ops = { + .start = starfive_wdt_start, + .stop = starfive_wdt_stop, + .reset = starfive_wdt_reset, +}; + +static int starfive_wdt_probe(struct udevice *dev) +{ + struct starfive_wdt_priv *wdt = dev_get_priv(dev); + int ret; + + ret = starfive_wdt_enable_clock(wdt); + if (ret) + return ret; + + ret = reset_deassert_bulk(wdt->rst); + if (ret) + goto err_reset; + + wdt->variant = (const struct starfive_wdt_variant *)dev_get_driver_data(dev); + + wdt->freq = clk_get_rate(wdt->core_clk); + if (!wdt->freq) { + ret = -EINVAL; + goto err_get_freq; + } + + return 0; + +err_get_freq: + reset_assert_bulk(wdt->rst); +err_reset: + starfive_wdt_disable_clock(wdt); + + return ret; +} + +static int starfive_wdt_of_to_plat(struct udevice *dev) +{ + struct starfive_wdt_priv *wdt = dev_get_priv(dev); + + wdt->base = (void *)dev_read_addr(dev); + if (!wdt->base) + return -ENODEV; + + wdt->apb_clk = devm_clk_get(dev, "apb"); + if (IS_ERR(wdt->apb_clk)) + return -ENODEV; + + wdt->core_clk = devm_clk_get(dev, "core"); + if (IS_ERR(wdt->core_clk)) + return -ENODEV; + + wdt->rst = devm_reset_bulk_get(dev); + if (IS_ERR(wdt->rst)) + return -ENODEV; + + return 0; +} + +static const struct udevice_id starfive_wdt_ids[] = { + { + .compatible = "starfive,jh7110-wdt", + .data = (ulong)&starfive_wdt_jh7110_variant + }, { + /* sentinel */ + } +}; + +U_BOOT_DRIVER(starfive_wdt) = { + .name = "starfive_wdt", + .id = UCLASS_WDT, + .of_match = starfive_wdt_ids, + .priv_auto = sizeof(struct starfive_wdt_priv), + .probe = starfive_wdt_probe, + .of_to_plat = starfive_wdt_of_to_plat, + .ops = &starfive_wdt_ops, +}; |