From 6b84217227e81cdcefdc849e626a3e143beb2f62 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Wed, 3 Nov 2021 22:55:11 -0500 Subject: [PATCH 1/6] sysreset: Add uclass Kconfig dependency to drivers None of the sysreset drivers do anything beyond providing sysreset uclass ops. They should depend on the sysreset uclass. Reviewed-by: Heinrich Schuchardt Signed-off-by: Samuel Holland Reviewed-by: Stefan Roese --- drivers/sysreset/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/sysreset/Kconfig b/drivers/sysreset/Kconfig index 43a948cfcd..de75c9cccc 100644 --- a/drivers/sysreset/Kconfig +++ b/drivers/sysreset/Kconfig @@ -118,8 +118,6 @@ config SYSRESET_TI_SCI This enables the system reset driver support over TI System Control Interface available on some new TI's SoCs. -endif - config SYSRESET_SYSCON bool "Enable support for mfd syscon reboot driver" select REGMAP @@ -162,4 +160,6 @@ config SYSRESET_MPC83XX help Reboot support for NXP MPC83xx SoCs. +endif + endmenu From 30ba45dbd6f3a470c739bd5db0663bee86b4cbf6 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Wed, 3 Nov 2021 22:55:12 -0500 Subject: [PATCH 2/6] sysreset: Mark driver probe functions as static These driver probe functions are not (and should not be) called from outside the respective driver source files. Therefore, the functions should be marked static. Reviewed-by: Heinrich Schuchardt Signed-off-by: Samuel Holland Reviewed-by: Stefan Roese --- drivers/sysreset/sysreset_gpio.c | 2 +- drivers/sysreset/sysreset_resetctl.c | 2 +- drivers/sysreset/sysreset_syscon.c | 2 +- drivers/sysreset/sysreset_watchdog.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/sysreset/sysreset_gpio.c b/drivers/sysreset/sysreset_gpio.c index 680b759eb3..dfca10ccc8 100644 --- a/drivers/sysreset/sysreset_gpio.c +++ b/drivers/sysreset/sysreset_gpio.c @@ -33,7 +33,7 @@ static struct sysreset_ops gpio_reboot_ops = { .request = gpio_reboot_request, }; -int gpio_reboot_probe(struct udevice *dev) +static int gpio_reboot_probe(struct udevice *dev) { struct gpio_reboot_priv *priv = dev_get_priv(dev); diff --git a/drivers/sysreset/sysreset_resetctl.c b/drivers/sysreset/sysreset_resetctl.c index c039521eb4..25bd5c9a7f 100644 --- a/drivers/sysreset/sysreset_resetctl.c +++ b/drivers/sysreset/sysreset_resetctl.c @@ -26,7 +26,7 @@ static struct sysreset_ops resetctl_reboot_ops = { .request = resetctl_reboot_request, }; -int resetctl_reboot_probe(struct udevice *dev) +static int resetctl_reboot_probe(struct udevice *dev) { struct resetctl_reboot_priv *priv = dev_get_priv(dev); diff --git a/drivers/sysreset/sysreset_syscon.c b/drivers/sysreset/sysreset_syscon.c index 28fdfb0978..525faf2f89 100644 --- a/drivers/sysreset/sysreset_syscon.c +++ b/drivers/sysreset/sysreset_syscon.c @@ -39,7 +39,7 @@ static struct sysreset_ops syscon_reboot_ops = { .request = syscon_reboot_request, }; -int syscon_reboot_probe(struct udevice *dev) +static int syscon_reboot_probe(struct udevice *dev) { struct syscon_reboot_priv *priv = dev_get_priv(dev); int err; diff --git a/drivers/sysreset/sysreset_watchdog.c b/drivers/sysreset/sysreset_watchdog.c index 0dc2d8b9b6..c7ae368d41 100644 --- a/drivers/sysreset/sysreset_watchdog.c +++ b/drivers/sysreset/sysreset_watchdog.c @@ -29,7 +29,7 @@ static struct sysreset_ops wdt_reboot_ops = { .request = wdt_reboot_request, }; -int wdt_reboot_probe(struct udevice *dev) +static int wdt_reboot_probe(struct udevice *dev) { struct wdt_reboot_priv *priv = dev_get_priv(dev); int err; From 5544a0114258ec4eba2a361fc975e91c419b227e Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Wed, 3 Nov 2021 22:55:13 -0500 Subject: [PATCH 3/6] sysreset: watchdog: Move watchdog reference to plat data Currently, the wdt_reboot driver always gets its watchdog device reference from an OF node. This prevents selecting a watchdog at runtime. Move the watchdog device reference to the plat data, so the driver can be bound with the reference pre-provided. The reference will still be acquired from the OF node if it is not already provided. Reviewed-by: Heinrich Schuchardt Reviewed-by: Simon Glass Signed-off-by: Samuel Holland Reviewed-by: Stefan Roese --- drivers/sysreset/sysreset_watchdog.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/sysreset/sysreset_watchdog.c b/drivers/sysreset/sysreset_watchdog.c index c7ae368d41..b723f5647c 100644 --- a/drivers/sysreset/sysreset_watchdog.c +++ b/drivers/sysreset/sysreset_watchdog.c @@ -9,16 +9,16 @@ #include #include -struct wdt_reboot_priv { +struct wdt_reboot_plat { struct udevice *wdt; }; static int wdt_reboot_request(struct udevice *dev, enum sysreset_t type) { - struct wdt_reboot_priv *priv = dev_get_priv(dev); + struct wdt_reboot_plat *plat = dev_get_plat(dev); int ret; - ret = wdt_expire_now(priv->wdt, 0); + ret = wdt_expire_now(plat->wdt, 0); if (ret) return ret; @@ -29,13 +29,13 @@ static struct sysreset_ops wdt_reboot_ops = { .request = wdt_reboot_request, }; -static int wdt_reboot_probe(struct udevice *dev) +static int wdt_reboot_of_to_plat(struct udevice *dev) { - struct wdt_reboot_priv *priv = dev_get_priv(dev); + struct wdt_reboot_plat *plat = dev_get_plat(dev); int err; err = uclass_get_device_by_phandle(UCLASS_WDT, dev, - "wdt", &priv->wdt); + "wdt", &plat->wdt); if (err) { pr_err("unable to find wdt device\n"); return err; @@ -53,7 +53,7 @@ U_BOOT_DRIVER(wdt_reboot) = { .name = "wdt_reboot", .id = UCLASS_SYSRESET, .of_match = wdt_reboot_ids, + .of_to_plat = wdt_reboot_of_to_plat, + .plat_auto = sizeof(struct wdt_reboot_plat), .ops = &wdt_reboot_ops, - .priv_auto = sizeof(struct wdt_reboot_priv), - .probe = wdt_reboot_probe, }; From a8f63d18bbb0a3e1456ac833e748d68f0ea1eece Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Wed, 3 Nov 2021 22:55:14 -0500 Subject: [PATCH 4/6] watchdog: Automatically register device with sysreset Add an option to automatically register watchdog devices with the wdt_reboot driver for use with sysreset. This allows sysreset to be a drop-in replacement for platform-specific watchdog reset code, without needing any device tree changes. Signed-off-by: Samuel Holland Reviewed-by: Stefan Roese --- drivers/sysreset/Kconfig | 7 +++++++ drivers/sysreset/sysreset_watchdog.c | 24 ++++++++++++++++++++++++ drivers/watchdog/wdt-uclass.c | 8 ++++++++ include/sysreset.h | 10 ++++++++++ 4 files changed, 49 insertions(+) diff --git a/drivers/sysreset/Kconfig b/drivers/sysreset/Kconfig index de75c9cccc..f6d60038b8 100644 --- a/drivers/sysreset/Kconfig +++ b/drivers/sysreset/Kconfig @@ -131,6 +131,13 @@ config SYSRESET_WATCHDOG help Reboot support for generic watchdog reset. +config SYSRESET_WATCHDOG_AUTO + bool "Automatically register first watchdog with sysreset" + depends on SYSRESET_WATCHDOG + help + If enabled, the first watchdog (as selected by the watchdog uclass) + will automatically be registered with the watchdog reboot driver. + config SYSRESET_RESETCTL bool "Enable support for reset controller reboot driver" select DM_RESET diff --git a/drivers/sysreset/sysreset_watchdog.c b/drivers/sysreset/sysreset_watchdog.c index b723f5647c..35efcac59d 100644 --- a/drivers/sysreset/sysreset_watchdog.c +++ b/drivers/sysreset/sysreset_watchdog.c @@ -5,7 +5,9 @@ #include #include +#include #include +#include #include #include @@ -57,3 +59,25 @@ U_BOOT_DRIVER(wdt_reboot) = { .plat_auto = sizeof(struct wdt_reboot_plat), .ops = &wdt_reboot_ops, }; + +#if IS_ENABLED(CONFIG_SYSRESET_WATCHDOG_AUTO) +int sysreset_register_wdt(struct udevice *dev) +{ + struct wdt_reboot_plat *plat = malloc(sizeof(*plat)); + int ret; + + if (!plat) + return -ENOMEM; + + plat->wdt = dev; + + ret = device_bind(dev, DM_DRIVER_GET(wdt_reboot), + dev->name, plat, ofnode_null(), NULL); + if (ret) { + free(plat); + return ret; + } + + return 0; +} +#endif diff --git a/drivers/watchdog/wdt-uclass.c b/drivers/watchdog/wdt-uclass.c index 7570710c4d..6d0f473867 100644 --- a/drivers/watchdog/wdt-uclass.c +++ b/drivers/watchdog/wdt-uclass.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -44,6 +45,13 @@ static void init_watchdog_dev(struct udevice *dev) priv = dev_get_uclass_priv(dev); + if (IS_ENABLED(CONFIG_SYSRESET_WATCHDOG_AUTO)) { + ret = sysreset_register_wdt(dev); + if (ret) + printf("WDT: Failed to register %s for sysreset\n", + dev->name); + } + if (!IS_ENABLED(CONFIG_WATCHDOG_AUTOSTART)) { printf("WDT: Not starting %s\n", dev->name); return; diff --git a/include/sysreset.h b/include/sysreset.h index 9d4ed87cea..ff20abdeed 100644 --- a/include/sysreset.h +++ b/include/sysreset.h @@ -133,4 +133,14 @@ void sysreset_walk_halt(enum sysreset_t type); */ void reset_cpu(void); +/** + * sysreset_register_wdt() - register a watchdog for use with sysreset + * + * This registers the given watchdog timer to be used to reset the system. + * + * @dev: WDT device + * @return: 0 if OK, -errno if error + */ +int sysreset_register_wdt(struct udevice *dev); + #endif From 6e19dc84c14b3407dfc02d218244d1b3a9fbca3e Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Wed, 3 Nov 2021 22:55:15 -0500 Subject: [PATCH 5/6] sunxi: Avoid duplicate reset_cpu with SYSRESET enabled The sysreset uclass unconditionally provides a definition of the reset_cpu() function. So does the sunxi board code. Fix the build with SYSRESET enabled by omitting the function from the board code in that case. The code still needs to be kept around for use in SPL. Reviewed-by: Heinrich Schuchardt Signed-off-by: Samuel Holland Reviewed-by: Stefan Roese --- arch/arm/mach-sunxi/board.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/mach-sunxi/board.c b/arch/arm/mach-sunxi/board.c index b4ba2a72c4..3ef179742c 100644 --- a/arch/arm/mach-sunxi/board.c +++ b/arch/arm/mach-sunxi/board.c @@ -346,6 +346,7 @@ void board_init_f(ulong dummy) } #endif +#if !CONFIG_IS_ENABLED(SYSRESET) void reset_cpu(void) { #if defined(CONFIG_SUNXI_GEN_SUN4I) || defined(CONFIG_MACH_SUN8I_R40) @@ -376,6 +377,7 @@ void reset_cpu(void) while (1) { } #endif } +#endif #if !CONFIG_IS_ENABLED(SYS_DCACHE_OFF) && !defined(CONFIG_ARM64) void enable_caches(void) From 40edc320b16271a725876b1b6f875cbd342c6582 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Wed, 3 Nov 2021 22:55:16 -0500 Subject: [PATCH 6/6] sunxi: Use sysreset framework for poweroff/reset Instead of hardcoding the watchdog for reset, and the PMIC for poweroff, use the sysreset framework to manage the available poweroff/reset backends. This allows (as examples) using the PMIC to do a cold reset, and using a GPIO to power off H3/H5 boards lacking a PMIC. Furthermore, it removes the need to hardcode watchdog MMIO addresses, since the sysreset backends can be discovered using the device tree. Reviewed-by: Heinrich Schuchardt Signed-off-by: Samuel Holland Reviewed-by: Stefan Roese --- arch/arm/Kconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index b4808d4c75..ae911d6e35 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1084,6 +1084,9 @@ config ARCH_SUNXI imply SPL_MMC if MMC imply SPL_POWER imply SPL_SERIAL + imply SYSRESET + imply SYSRESET_WATCHDOG + imply SYSRESET_WATCHDOG_AUTO imply USB_GADGET imply WDT