summaryrefslogtreecommitdiff
path: root/drivers/sysreset
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/sysreset')
-rw-r--r--drivers/sysreset/Kconfig240
-rw-r--r--drivers/sysreset/Makefile31
-rw-r--r--drivers/sysreset/poweroff_gpio.c92
-rw-r--r--drivers/sysreset/sysreset-ti-sci.c75
-rw-r--r--drivers/sysreset/sysreset-uclass.c164
-rw-r--r--drivers/sysreset/sysreset_ast.c58
-rw-r--r--drivers/sysreset/sysreset_at91.c64
-rw-r--r--drivers/sysreset/sysreset_gpio.c65
-rw-r--r--drivers/sysreset/sysreset_max77663.c52
-rw-r--r--drivers/sysreset/sysreset_microblaze.c32
-rw-r--r--drivers/sysreset/sysreset_mpc83xx.c216
-rw-r--r--drivers/sysreset/sysreset_mpc83xx.h103
-rw-r--r--drivers/sysreset/sysreset_octeon.c52
-rw-r--r--drivers/sysreset/sysreset_palmas.c52
-rw-r--r--drivers/sysreset/sysreset_psci.c44
-rw-r--r--drivers/sysreset/sysreset_raa215300.c58
-rw-r--r--drivers/sysreset/sysreset_resetctl.c48
-rw-r--r--drivers/sysreset/sysreset_rockchip.c45
-rw-r--r--drivers/sysreset/sysreset_sandbox.c140
-rw-r--r--drivers/sysreset/sysreset_sbi.c51
-rw-r--r--drivers/sysreset/sysreset_socfpga.c57
-rw-r--r--drivers/sysreset/sysreset_socfpga_soc64.c29
-rw-r--r--drivers/sysreset/sysreset_sti.c85
-rw-r--r--drivers/sysreset/sysreset_syscon.c93
-rw-r--r--drivers/sysreset/sysreset_tegra.c45
-rw-r--r--drivers/sysreset/sysreset_tps65910.c54
-rw-r--r--drivers/sysreset/sysreset_tps80031.c40
-rw-r--r--drivers/sysreset/sysreset_watchdog.c91
-rw-r--r--drivers/sysreset/sysreset_x86.c160
-rw-r--r--drivers/sysreset/sysreset_xtfpga.c36
30 files changed, 2372 insertions, 0 deletions
diff --git a/drivers/sysreset/Kconfig b/drivers/sysreset/Kconfig
new file mode 100644
index 00000000000..49c0787b26d
--- /dev/null
+++ b/drivers/sysreset/Kconfig
@@ -0,0 +1,240 @@
+#
+# System reset devices
+#
+
+menu "System reset device drivers"
+
+config SYSRESET
+ bool "Enable support for system reset drivers"
+ depends on DM
+ help
+ Enable system reset drivers which can be used to reset the CPU or
+ board. Each driver can provide a reset method which will be called
+ to effect a reset. The uclass will try all available drivers when
+ reset_walk() is called.
+
+config SPL_SYSRESET
+ bool "Enable support for system reset drivers in SPL mode"
+ depends on SYSRESET && SPL_DM
+ help
+ Enable system reset drivers which can be used to reset the CPU or
+ board. Each driver can provide a reset method which will be called
+ to effect a reset. The uclass will try all available drivers when
+ reset_walk() is called.
+
+config TPL_SYSRESET
+ bool "Enable support for system reset drivers in TPL mode"
+ depends on SYSRESET && TPL_DM
+ help
+ Enable system reset drivers which can be used to reset the CPU or
+ board. Each driver can provide a reset method which will be called
+ to effect a reset. The uclass will try all available drivers when
+ reset_walk() is called.
+
+config VPL_SYSRESET
+ bool "Enable support for system reset drivers in VPL mode"
+ depends on SYSRESET && VPL_DM
+ default y if TPL_SYSRESET
+ help
+ Enable system reset drivers which can be used to reset the CPU or
+ board. Each driver can provide a reset method which will be called
+ to effect a reset. The uclass will try all available drivers when
+ reset_walk() is called.
+
+if SYSRESET
+
+config SYSRESET_CMD_RESET
+ bool "sysreset implementation of the reset command"
+ default y
+ help
+ Enable sysreset implementation of the reset command.
+
+if CMD_POWEROFF
+
+config SYSRESET_CMD_POWEROFF
+ bool "sysreset implementation of the poweroff command"
+ help
+ This should be selected by the appropriate PMIC driver if
+ the poweroff command is enabled.
+
+endif
+
+config POWEROFF_GPIO
+ bool "Enable support for GPIO poweroff driver"
+ depends on DM_GPIO
+ help
+ Support for system poweroff using a GPIO pin. This can be used
+ for systems having a single GPIO to trigger a system poweroff.
+
+config SYSRESET_GPIO
+ bool "Enable support for GPIO reset driver"
+ depends on DM_GPIO
+ help
+ Reset support via GPIO pin connected reset logic. This is used for
+ example on Microblaze where reset logic can be controlled via GPIO
+ pin which triggers cpu reset.
+
+config SYSRESET_MAX77663
+ bool "Enable support for MAX77663 PMIC System Reset"
+ depends on DM_PMIC_MAX77663
+ select SYSRESET_CMD_POWEROFF if CMD_POWEROFF
+ help
+ Enable system power management functions found in MAX77663 PMIC.
+
+config SYSRESET_MICROBLAZE
+ bool "Enable support for Microblaze soft reset"
+ depends on MICROBLAZE
+ help
+ This is soft reset on Microblaze which does jump to 0x0 address.
+
+config SYSRESET_OCTEON
+ bool "Enable support for Marvell Octeon SoC family"
+ depends on ARCH_OCTEON
+ help
+ This enables the system reset driver support for Marvell Octeon
+ SoCs.
+
+config SYSRESET_AT91
+ bool "Enable support for Microchip/Atmel reset driver"
+ depends on ARCH_AT91
+ select SYSRESET_SPL_AT91 if SPL && SPL_SYSRESET
+ help
+ This enables the system reset driver support for Microchip/Atmel
+ SoCs.
+
+config SYSRESET_SPL_AT91
+ bool "Enable support for Microchip/Atmel reset driver in SPL"
+ depends on ARCH_AT91
+ help
+ This enables the system reset driver support for Microchip/Atmel
+ SoCs in SPL.
+
+config SYSRESET_PALMAS
+ bool "Enable support for PALMAS System Reset"
+ depends on PMIC_PALMAS
+ select SYSRESET_CMD_POWEROFF if CMD_POWEROFF
+ help
+ Enable system power management functions found in PLAMAS PMIC family.
+
+config SYSRESET_PSCI
+ bool "Enable support for PSCI System Reset"
+ depends on ARM_PSCI_FW
+ select SPL_ARM_PSCI_FW if SPL
+ help
+ 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
+ default y
+ 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)
+ help
+ This enables the system reset driver support for Intel SOCFPGA SoCs
+ (Cyclone 5, Arria 5 and Arria 10).
+
+config SYSRESET_SOCFPGA_SOC64
+ bool "Enable support for Intel SOCFPGA SoC64 family (Stratix10/Agilex)"
+ depends on ARCH_SOCFPGA && TARGET_SOCFPGA_SOC64
+ help
+ This enables the system reset driver support for Intel SOCFPGA
+ SoC64 SoCs.
+
+config SYSRESET_TEGRA
+ bool "Tegra PMC system reset driver"
+ depends on ARCH_TEGRA
+ help
+ This enables the system reset ability of PMC used in Tegra SoCs.
+
+config SYSRESET_TI_SCI
+ bool "TI System Control Interface (TI SCI) system reset driver"
+ depends on TI_SCI_PROTOCOL
+ help
+ This enables the system reset driver support over TI System Control
+ Interface available on some new TI's SoCs.
+
+config SYSRESET_TPS65910
+ bool "Enable support for TPS65910/TPS65911 PMIC System Reset"
+ depends on DM_PMIC_TPS65910
+ select SYSRESET_CMD_POWEROFF if CMD_POWEROFF
+ help
+ Enable system power management functions found in TPS65910/TPS65911
+ PMICs.
+
+config SYSRESET_TPS80031
+ bool "Enable support for TPS80031/TPS80032 PMIC System Reset"
+ depends on DM_PMIC_TPS80031
+ select SYSRESET_CMD_POWEROFF if CMD_POWEROFF
+ help
+ Enable system power management functions found in TPS80031/TPS80032
+ PMICs.
+
+config SYSRESET_SYSCON
+ bool "Enable support for mfd syscon reboot driver"
+ select REGMAP
+ select SYSCON
+ help
+ Reboot support for generic SYSCON mapped register reset.
+
+config SYSRESET_WATCHDOG
+ bool "Enable support for watchdog reboot driver"
+ select WDT
+ 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
+ help
+ Reboot support using generic reset controller.
+
+config SYSRESET_X86
+ bool "Enable support for x86 processor reboot driver"
+ depends on X86
+ help
+ Reboot support for generic x86 processor reset.
+
+config SYSRESET_SPL_X86
+ bool "Enable support for x86 processor reboot driver in SPL"
+ depends on X86
+ help
+ Reboot support for generic x86 processor reset in SPL.
+
+config SYSRESET_TPL_X86
+ bool "Enable support for x86 processor reboot driver in TPL"
+ depends on X86
+ help
+ Reboot support for generic x86 processor reset in TPL.
+
+config SYSRESET_MPC83XX
+ bool "Enable support MPC83xx SoC family reboot driver"
+ help
+ Reboot support for NXP MPC83xx SoCs.
+
+config SYSRESET_RAA215300
+ bool "Support sysreset via Renesas RAA215300 PMIC"
+ depends on PMIC_RAA215300
+ help
+ Add support for the system reboot via the Renesas RAA215300 PMIC.
+
+endif
+
+endmenu
diff --git a/drivers/sysreset/Makefile b/drivers/sysreset/Makefile
new file mode 100644
index 00000000000..e0e732205df
--- /dev/null
+++ b/drivers/sysreset/Makefile
@@ -0,0 +1,31 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# (C) Copyright 2016 Cadence Design Systems Inc.
+
+obj-$(CONFIG_$(SPL_TPL_)SYSRESET) += sysreset-uclass.o
+obj-$(CONFIG_ARCH_ASPEED) += sysreset_ast.o
+obj-$(CONFIG_ARCH_ROCKCHIP) += sysreset_rockchip.o
+obj-$(CONFIG_ARCH_STI) += sysreset_sti.o
+obj-$(CONFIG_SANDBOX) += sysreset_sandbox.o
+obj-$(CONFIG_POWEROFF_GPIO) += poweroff_gpio.o
+obj-$(CONFIG_SYSRESET_GPIO) += sysreset_gpio.o
+obj-$(CONFIG_$(SPL_TPL_)SYSRESET_MAX77663) += sysreset_max77663.o
+obj-$(CONFIG_SYSRESET_MPC83XX) += sysreset_mpc83xx.o
+obj-$(CONFIG_SYSRESET_MICROBLAZE) += sysreset_microblaze.o
+obj-$(CONFIG_SYSRESET_OCTEON) += sysreset_octeon.o
+obj-$(CONFIG_$(SPL_TPL_)SYSRESET_PALMAS) += sysreset_palmas.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_TEGRA) += sysreset_tegra.o
+obj-$(CONFIG_SYSRESET_TI_SCI) += sysreset-ti-sci.o
+obj-$(CONFIG_$(SPL_TPL_)SYSRESET_TPS65910) += sysreset_tps65910.o
+obj-$(CONFIG_$(SPL_TPL_)SYSRESET_TPS80031) += sysreset_tps80031.o
+obj-$(CONFIG_SYSRESET_SYSCON) += sysreset_syscon.o
+obj-$(CONFIG_SYSRESET_WATCHDOG) += sysreset_watchdog.o
+obj-$(CONFIG_SYSRESET_RESETCTL) += sysreset_resetctl.o
+obj-$(CONFIG_$(SPL_TPL_)SYSRESET_AT91) += sysreset_at91.o
+obj-$(CONFIG_$(SPL_TPL_)SYSRESET_X86) += sysreset_x86.o
+obj-$(CONFIG_SYSRESET_RAA215300) += sysreset_raa215300.o
+obj-$(CONFIG_TARGET_XTFPGA) += sysreset_xtfpga.o
diff --git a/drivers/sysreset/poweroff_gpio.c b/drivers/sysreset/poweroff_gpio.c
new file mode 100644
index 00000000000..ad04e4b1a85
--- /dev/null
+++ b/drivers/sysreset/poweroff_gpio.c
@@ -0,0 +1,92 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Toggles a GPIO pin to power down a device
+ *
+ * Created using the Linux driver as reference, which
+ * has been written by:
+ *
+ * Jamie Lentin <jm@lentin.co.uk>
+ * Andrew Lunn <andrew@lunn.ch>
+ *
+ * Copyright (C) 2012 Jamie Lentin
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <log.h>
+#include <sysreset.h>
+
+#include <asm/gpio.h>
+#include <linux/delay.h>
+
+struct poweroff_gpio_info {
+ struct gpio_desc gpio;
+ u32 active_delay_ms;
+ u32 inactive_delay_ms;
+ u32 timeout_ms;
+};
+
+static int poweroff_gpio_request(struct udevice *dev, enum sysreset_t type)
+{
+ struct poweroff_gpio_info *priv = dev_get_priv(dev);
+ int r;
+
+ if (type != SYSRESET_POWER_OFF)
+ return -EPROTONOSUPPORT;
+
+ debug("GPIO poweroff\n");
+
+ /* drive it active, also inactive->active edge */
+ r = dm_gpio_set_value(&priv->gpio, 1);
+ if (r < 0)
+ return r;
+ mdelay(priv->active_delay_ms);
+
+ /* drive inactive, also active->inactive edge */
+ r = dm_gpio_set_value(&priv->gpio, 0);
+ if (r < 0)
+ return r;
+ mdelay(priv->inactive_delay_ms);
+
+ /* drive it active, also inactive->active edge */
+ r = dm_gpio_set_value(&priv->gpio, 1);
+ if (r < 0)
+ return r;
+
+ /* give it some time */
+ mdelay(priv->timeout_ms);
+
+ return -EINPROGRESS;
+}
+
+static int poweroff_gpio_probe(struct udevice *dev)
+{
+ struct poweroff_gpio_info *priv = dev_get_priv(dev);
+ int flags;
+
+ flags = dev_read_bool(dev, "input") ? GPIOD_IS_IN : GPIOD_IS_OUT;
+ priv->active_delay_ms = dev_read_u32_default(dev, "active-delay-ms", 100);
+ priv->inactive_delay_ms = dev_read_u32_default(dev, "inactive-delay-ms", 100);
+ priv->timeout_ms = dev_read_u32_default(dev, "timeout-ms", 3000);
+
+ return gpio_request_by_name(dev, "gpios", 0, &priv->gpio, flags);
+}
+
+static struct sysreset_ops poweroff_gpio_ops = {
+ .request = poweroff_gpio_request,
+};
+
+static const struct udevice_id poweroff_gpio_ids[] = {
+ { .compatible = "gpio-poweroff", },
+ {},
+};
+
+U_BOOT_DRIVER(poweroff_gpio) = {
+ .name = "poweroff-gpio",
+ .id = UCLASS_SYSRESET,
+ .ops = &poweroff_gpio_ops,
+ .probe = poweroff_gpio_probe,
+ .priv_auto = sizeof(struct poweroff_gpio_info),
+ .of_match = poweroff_gpio_ids,
+};
diff --git a/drivers/sysreset/sysreset-ti-sci.c b/drivers/sysreset/sysreset-ti-sci.c
new file mode 100644
index 00000000000..5fc05c46cb0
--- /dev/null
+++ b/drivers/sysreset/sysreset-ti-sci.c
@@ -0,0 +1,75 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Texas Instruments System Control Interface (TI SCI) system reset driver
+ *
+ * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/
+ * Andreas Dannenberg <dannenberg@ti.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <log.h>
+#include <sysreset.h>
+#include <dm/device_compat.h>
+#include <linux/err.h>
+#include <linux/soc/ti/ti_sci_protocol.h>
+
+/**
+ * struct ti_sci_sysreset_data - sysreset controller information structure
+ * @sci: TI SCI handle used for communication with system controller
+ */
+struct ti_sci_sysreset_data {
+ const struct ti_sci_handle *sci;
+};
+
+static int ti_sci_sysreset_probe(struct udevice *dev)
+{
+ struct ti_sci_sysreset_data *data = dev_get_priv(dev);
+
+ debug("%s(dev=%p)\n", __func__, dev);
+
+ if (!data)
+ return -ENOMEM;
+
+ /* Store handle for communication with the system controller */
+ data->sci = ti_sci_get_handle(dev);
+ if (IS_ERR(data->sci))
+ return PTR_ERR(data->sci);
+
+ return 0;
+}
+
+static int ti_sci_sysreset_request(struct udevice *dev, enum sysreset_t type)
+{
+ struct ti_sci_sysreset_data *data = dev_get_priv(dev);
+ const struct ti_sci_handle *sci = data->sci;
+ const struct ti_sci_core_ops *cops = &sci->ops.core_ops;
+ int ret;
+
+ debug("%s(dev=%p, type=%d)\n", __func__, dev, type);
+
+ ret = cops->reboot_device(sci);
+ if (ret)
+ dev_err(dev, "%s: reboot_device failed (%d)\n", __func__, ret);
+
+ return ret;
+}
+
+static struct sysreset_ops ti_sci_sysreset_ops = {
+ .request = ti_sci_sysreset_request,
+};
+
+static const struct udevice_id ti_sci_sysreset_of_match[] = {
+ { .compatible = "ti,sci-sysreset", },
+ { /* sentinel */ },
+};
+
+U_BOOT_DRIVER(ti_sci_sysreset) = {
+ .name = "ti-sci-sysreset",
+ .id = UCLASS_SYSRESET,
+ .of_match = ti_sci_sysreset_of_match,
+ .probe = ti_sci_sysreset_probe,
+ .priv_auto = sizeof(struct ti_sci_sysreset_data),
+ .ops = &ti_sci_sysreset_ops,
+};
diff --git a/drivers/sysreset/sysreset-uclass.c b/drivers/sysreset/sysreset-uclass.c
new file mode 100644
index 00000000000..6151b5fe03e
--- /dev/null
+++ b/drivers/sysreset/sysreset-uclass.c
@@ -0,0 +1,164 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#define LOG_CATEGORY UCLASS_SYSRESET
+
+#include <common.h>
+#include <command.h>
+#include <cpu_func.h>
+#include <dm.h>
+#include <errno.h>
+#include <hang.h>
+#include <log.h>
+#include <regmap.h>
+#include <spl.h>
+#include <sysreset.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <dm/root.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <asm/global_data.h>
+
+int sysreset_request(struct udevice *dev, enum sysreset_t type)
+{
+ struct sysreset_ops *ops = sysreset_get_ops(dev);
+
+ if (!ops->request)
+ return -ENOSYS;
+
+ return ops->request(dev, type);
+}
+
+int sysreset_get_status(struct udevice *dev, char *buf, int size)
+{
+ struct sysreset_ops *ops = sysreset_get_ops(dev);
+
+ if (!ops->get_status)
+ return -ENOSYS;
+
+ return ops->get_status(dev, buf, size);
+}
+
+int sysreset_get_last(struct udevice *dev)
+{
+ struct sysreset_ops *ops = sysreset_get_ops(dev);
+
+ if (!ops->get_last)
+ return -ENOSYS;
+
+ return ops->get_last(dev);
+}
+
+int sysreset_walk(enum sysreset_t type)
+{
+ struct udevice *dev;
+ int ret = -ENOSYS;
+
+ while (ret != -EINPROGRESS && type < SYSRESET_COUNT) {
+ for (uclass_first_device(UCLASS_SYSRESET, &dev);
+ dev;
+ uclass_next_device(&dev)) {
+ ret = sysreset_request(dev, type);
+ if (ret == -EINPROGRESS)
+ break;
+ }
+ type++;
+ }
+
+ return ret;
+}
+
+int sysreset_get_last_walk(void)
+{
+ struct udevice *dev;
+ int value = -ENOENT;
+
+ for (uclass_first_device(UCLASS_SYSRESET, &dev);
+ dev;
+ uclass_next_device(&dev)) {
+ int ret;
+
+ ret = sysreset_get_last(dev);
+ if (ret >= 0) {
+ value = ret;
+ break;
+ }
+ }
+
+ return value;
+}
+
+void sysreset_walk_halt(enum sysreset_t type)
+{
+ int ret;
+
+ ret = sysreset_walk(type);
+
+ /* Wait for the reset to take effect */
+ if (ret == -EINPROGRESS)
+ mdelay(100);
+
+ /* Still no reset? Give up */
+ if (spl_phase() <= PHASE_SPL)
+ log_err("no sysreset\n");
+ else
+ log_err("System reset not supported on this platform\n");
+ hang();
+}
+
+/**
+ * reset_cpu() - calls sysreset_walk(SYSRESET_WARM)
+ */
+void reset_cpu(void)
+{
+ sysreset_walk_halt(SYSRESET_WARM);
+}
+
+
+#if IS_ENABLED(CONFIG_SYSRESET_CMD_RESET)
+int do_reset(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
+{
+ enum sysreset_t reset_type = SYSRESET_COLD;
+
+ if (argc > 2)
+ return CMD_RET_USAGE;
+
+ if (argc == 2 && argv[1][0] == '-' && argv[1][1] == 'w') {
+ reset_type = SYSRESET_WARM;
+ }
+
+ printf("resetting ...\n");
+ mdelay(100);
+
+ sysreset_walk_halt(reset_type);
+
+ return 0;
+}
+#endif
+
+#if IS_ENABLED(CONFIG_SYSRESET_CMD_POWEROFF)
+int do_poweroff(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
+{
+ int ret;
+
+ puts("poweroff ...\n");
+ mdelay(100);
+
+ ret = sysreset_walk(SYSRESET_POWER_OFF);
+
+ if (ret == -EINPROGRESS)
+ mdelay(1000);
+
+ /*NOTREACHED when power off*/
+ return CMD_RET_FAILURE;
+}
+#endif
+
+UCLASS_DRIVER(sysreset) = {
+ .id = UCLASS_SYSRESET,
+ .name = "sysreset",
+};
diff --git a/drivers/sysreset/sysreset_ast.c b/drivers/sysreset/sysreset_ast.c
new file mode 100644
index 00000000000..92fad96871b
--- /dev/null
+++ b/drivers/sysreset/sysreset_ast.c
@@ -0,0 +1,58 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * (C) Copyright 2016 Google, Inc
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <log.h>
+#include <sysreset.h>
+#include <wdt.h>
+#include <asm/io.h>
+#include <asm/arch/wdt.h>
+#include <linux/err.h>
+#include <hang.h>
+
+static int ast_sysreset_request(struct udevice *dev, enum sysreset_t type)
+{
+ struct udevice *wdt;
+ u32 reset_mode;
+ int ret = uclass_first_device_err(UCLASS_WDT, &wdt);
+
+ if (ret)
+ return ret;
+
+ switch (type) {
+ case SYSRESET_WARM:
+ reset_mode = WDT_CTRL_RESET_CPU;
+ break;
+ case SYSRESET_COLD:
+ reset_mode = WDT_CTRL_RESET_CHIP;
+ break;
+ default:
+ return -EPROTONOSUPPORT;
+ }
+
+#if !defined(CONFIG_SPL_BUILD)
+ ret = wdt_expire_now(wdt, reset_mode);
+ if (ret) {
+ debug("Sysreset failed: %d", ret);
+ return ret;
+ }
+#else
+ hang();
+#endif
+
+ return -EINPROGRESS;
+}
+
+static struct sysreset_ops ast_sysreset = {
+ .request = ast_sysreset_request,
+};
+
+U_BOOT_DRIVER(sysreset_ast) = {
+ .name = "ast_sysreset",
+ .id = UCLASS_SYSRESET,
+ .ops = &ast_sysreset,
+};
diff --git a/drivers/sysreset/sysreset_at91.c b/drivers/sysreset/sysreset_at91.c
new file mode 100644
index 00000000000..fc85f31ebf0
--- /dev/null
+++ b/drivers/sysreset/sysreset_at91.c
@@ -0,0 +1,64 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2022 Microchip Technology, Inc. and its subsidiaries
+ */
+
+#include <asm/arch/hardware.h>
+#include <asm/io.h>
+#include <asm/arch/at91_rstc.h>
+#include <clk.h>
+#include <common.h>
+#include <cpu_func.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <dm/device-internal.h>
+#include <sysreset.h>
+
+static int at91_sysreset_request(struct udevice *dev, enum sysreset_t type)
+{
+ at91_rstc_t *rstc = (at91_rstc_t *)dev_get_priv(dev);
+
+ writel(AT91_RSTC_KEY
+ | AT91_RSTC_CR_PROCRST /* Processor Reset */
+ | AT91_RSTC_CR_PERRST /* Peripheral Reset */
+#ifdef CONFIG_AT91RESET_EXTRST
+ | AT91_RSTC_CR_EXTRST /* External Reset (assert nRST pin) */
+#endif
+ , &rstc->cr);
+
+ return -EINPROGRESS;
+}
+
+static int at91_sysreset_probe(struct udevice *dev)
+{
+ struct clk slck;
+ void *priv;
+ int ret;
+
+ priv = dev_remap_addr(dev);
+ if (!priv)
+ return -EINVAL;
+
+ dev_set_priv(dev, priv);
+
+ ret = clk_get_by_index(dev, 0, &slck);
+ if (ret)
+ return ret;
+
+ ret = clk_prepare_enable(&slck);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static struct sysreset_ops at91_sysreset = {
+ .request = at91_sysreset_request,
+};
+
+U_BOOT_DRIVER(sysreset_at91) = {
+ .id = UCLASS_SYSRESET,
+ .name = "at91_sysreset",
+ .ops = &at91_sysreset,
+ .probe = at91_sysreset_probe,
+};
diff --git a/drivers/sysreset/sysreset_gpio.c b/drivers/sysreset/sysreset_gpio.c
new file mode 100644
index 00000000000..de42b593542
--- /dev/null
+++ b/drivers/sysreset/sysreset_gpio.c
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 Xilinx, Inc. - Michal Simek
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <log.h>
+#include <sysreset.h>
+#include <asm/gpio.h>
+
+struct gpio_reboot_priv {
+ struct gpio_desc gpio;
+};
+
+static int gpio_reboot_request(struct udevice *dev, enum sysreset_t type)
+{
+ struct gpio_reboot_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ /*
+ * When debug log is enabled please make sure that chars won't end up
+ * in output fifo. Or you can append udelay(); to get enough time
+ * to HW to emit output fifo.
+ */
+ debug("GPIO reset\n");
+
+ /* Writing 1 respects polarity (active high/low) based on gpio->flags */
+ ret = dm_gpio_set_value(&priv->gpio, 1);
+ if (ret < 0)
+ return ret;
+
+ return -EINPROGRESS;
+}
+
+static struct sysreset_ops gpio_reboot_ops = {
+ .request = gpio_reboot_request,
+};
+
+static int gpio_reboot_probe(struct udevice *dev)
+{
+ struct gpio_reboot_priv *priv = dev_get_priv(dev);
+
+ /*
+ * Linux kernel DT binding contain others optional properties
+ * which are not supported now
+ */
+
+ return gpio_request_by_name(dev, "gpios", 0, &priv->gpio, GPIOD_IS_OUT);
+}
+
+static const struct udevice_id led_gpio_ids[] = {
+ { .compatible = "gpio-restart" },
+ { }
+};
+
+U_BOOT_DRIVER(gpio_reboot) = {
+ .id = UCLASS_SYSRESET,
+ .name = "gpio_restart",
+ .of_match = led_gpio_ids,
+ .ops = &gpio_reboot_ops,
+ .priv_auto = sizeof(struct gpio_reboot_priv),
+ .probe = gpio_reboot_probe,
+};
diff --git a/drivers/sysreset/sysreset_max77663.c b/drivers/sysreset/sysreset_max77663.c
new file mode 100644
index 00000000000..8febcf8de6c
--- /dev/null
+++ b/drivers/sysreset/sysreset_max77663.c
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright(C) 2023 Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#include <dm.h>
+#include <i2c.h>
+#include <errno.h>
+#include <sysreset.h>
+#include <power/pmic.h>
+#include <power/max77663.h>
+
+static int max77663_sysreset_request(struct udevice *dev,
+ enum sysreset_t type)
+{
+ int val;
+
+ val = pmic_reg_read(dev->parent, MAX77663_REG_ONOFF_CFG1);
+ if (val < 0)
+ return val;
+
+ /* clear both bits */
+ val &= ~ONOFF_SFT_RST;
+ val &= ~ONOFF_PWR_OFF;
+
+ switch (type) {
+ case SYSRESET_POWER:
+ /* MAX77663: SFT_RST > ONOFF_CFG1 */
+ pmic_reg_write(dev->parent, MAX77663_REG_ONOFF_CFG1,
+ val | ONOFF_SFT_RST);
+ break;
+ case SYSRESET_POWER_OFF:
+ /* MAX77663: PWR_OFF > ONOFF_CFG1 */
+ pmic_reg_write(dev->parent, MAX77663_REG_ONOFF_CFG1,
+ val | ONOFF_PWR_OFF);
+ break;
+ default:
+ return -EPROTONOSUPPORT;
+ }
+
+ return -EINPROGRESS;
+}
+
+static struct sysreset_ops max77663_sysreset = {
+ .request = max77663_sysreset_request,
+};
+
+U_BOOT_DRIVER(sysreset_max77663) = {
+ .id = UCLASS_SYSRESET,
+ .name = MAX77663_RST_DRIVER,
+ .ops = &max77663_sysreset,
+};
diff --git a/drivers/sysreset/sysreset_microblaze.c b/drivers/sysreset/sysreset_microblaze.c
new file mode 100644
index 00000000000..83a7f77ac41
--- /dev/null
+++ b/drivers/sysreset/sysreset_microblaze.c
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 Xilinx, Inc. - Michal Simek
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <sysreset.h>
+#include <linux/err.h>
+#include <linux/stringify.h>
+
+static int microblaze_sysreset_request(struct udevice *dev,
+ enum sysreset_t type)
+{
+ puts("Microblaze soft reset sysreset\n");
+ __asm__ __volatile__ (
+ "mts rmsr, r0;" \
+ "brai " __stringify(CONFIG_XILINX_MICROBLAZE0_VECTOR_BASE_ADDR));
+
+ return -EINPROGRESS;
+}
+
+static struct sysreset_ops microblaze_sysreset = {
+ .request = microblaze_sysreset_request,
+};
+
+U_BOOT_DRIVER(sysreset_microblaze) = {
+ .id = UCLASS_SYSRESET,
+ .name = "mb_soft_reset",
+ .ops = &microblaze_sysreset,
+};
diff --git a/drivers/sysreset/sysreset_mpc83xx.c b/drivers/sysreset/sysreset_mpc83xx.c
new file mode 100644
index 00000000000..ca48328f7b5
--- /dev/null
+++ b/drivers/sysreset/sysreset_mpc83xx.c
@@ -0,0 +1,216 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2018
+ * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
+ */
+
+#include <common.h>
+#include <command.h>
+#include <dm.h>
+#include <log.h>
+#include <sysreset.h>
+#include <wait_bit.h>
+#include <linux/delay.h>
+#include <asm/global_data.h>
+
+#include "sysreset_mpc83xx.h"
+
+/* Magic 4-byte word to enable reset ('RSTE' in ASCII) */
+static const u32 RPR_MAGIC = 0x52535445;
+/* Wait at most 2000ms for reset control enable bit */
+static const uint RESET_WAIT_TIMEOUT = 2000;
+
+/**
+ * __do_reset() - Execute the system reset
+ *
+ * Return: The functions resets the system, and never returns.
+ */
+static int __do_reset(void)
+{
+ ulong msr;
+ int res;
+
+ immap_t *immap = (immap_t *)CONFIG_SYS_IMMR;
+
+ puts("Resetting the board.\n");
+
+ /* Interrupts and MMU off */
+ msr = mfmsr();
+ msr &= ~(MSR_EE | MSR_IR | MSR_DR);
+ mtmsr(msr);
+
+ /* Enable Reset Control Reg */
+ out_be32(&immap->reset.rpr, RPR_MAGIC);
+ sync();
+ isync();
+
+ /* Confirm Reset Control Reg is enabled */
+ res = wait_for_bit_be32(&immap->reset.rcer, RCER_CRE, true,
+ RESET_WAIT_TIMEOUT, false);
+ if (res) {
+ debug("%s: Timed out waiting for reset control to be set\n",
+ __func__);
+ return res;
+ }
+
+ udelay(200);
+
+ /* Perform reset, only one bit */
+ out_be32(&immap->reset.rcr, RCR_SWHR);
+
+ /* Never executes */
+ return 0;
+}
+
+static int mpc83xx_sysreset_request(struct udevice *dev, enum sysreset_t type)
+{
+ switch (type) {
+ case SYSRESET_WARM:
+ case SYSRESET_COLD:
+ return __do_reset();
+ default:
+ return -EPROTONOSUPPORT;
+ }
+
+ return -EINPROGRESS;
+}
+
+/**
+ * print_83xx_arb_event() - Print arbiter events to buffer
+ * @force: Print arbiter events, even if none are indicated by the system
+ * @buf: The buffer to receive the printed arbiter event information
+ * @size: The size of the buffer to receive the printed arbiter event
+ * information in bytes
+ *
+ * Return: Number of bytes printed to buffer, -ve on error
+ */
+static int print_83xx_arb_event(bool force, char *buf, int size)
+{
+ int etype = (gd->arch.arbiter_event_attributes & AEATR_EVENT)
+ >> AEATR_EVENT_SHIFT;
+ int mstr_id = (gd->arch.arbiter_event_attributes & AEATR_MSTR_ID)
+ >> AEATR_MSTR_ID_SHIFT;
+ int tbst = (gd->arch.arbiter_event_attributes & AEATR_TBST)
+ >> AEATR_TBST_SHIFT;
+ int tsize = (gd->arch.arbiter_event_attributes & AEATR_TSIZE)
+ >> AEATR_TSIZE_SHIFT;
+ int ttype = (gd->arch.arbiter_event_attributes & AEATR_TTYPE)
+ >> AEATR_TTYPE_SHIFT;
+ int tsize_val = (tbst << 3) | tsize;
+ int tsize_bytes = tbst ? (tsize ? tsize : 8) : 16 + 8 * tsize;
+ int res = 0;
+
+ /*
+ * If we don't force output, and there is no event (event address ==
+ * 0), then don't print anything
+ */
+ if (!force && !gd->arch.arbiter_event_address)
+ return 0;
+
+ if (IS_ENABLED(CONFIG_DISPLAY_AER_FULL)) {
+ res = snprintf(buf, size,
+ "Arbiter Event Status:\n"
+ " %s: 0x%08lX\n"
+ " %s: 0x%1x = %s\n"
+ " %s: 0x%02x = %s\n"
+ " %s: 0x%1x = %d bytes\n"
+ " %s: 0x%02x = %s\n",
+ "Event Address", gd->arch.arbiter_event_address,
+ "Event Type", etype, event[etype],
+ "Master ID", mstr_id, master[mstr_id],
+ "Transfer Size", tsize_val, tsize_bytes,
+ "Transfer Type", ttype, transfer[ttype]);
+ } else if (IS_ENABLED(CONFIG_DISPLAY_AER_BRIEF)) {
+ res = snprintf(buf, size,
+ "Arbiter Event Status: AEATR=0x%08lX, AEADR=0x%08lX\n",
+ gd->arch.arbiter_event_attributes,
+ gd->arch.arbiter_event_address);
+ }
+
+ return res;
+}
+
+static int mpc83xx_sysreset_get_status(struct udevice *dev, char *buf, int size)
+{
+ /* Ad-hoc data structure to map RSR bit values to their descriptions */
+ static const struct {
+ /* Bit mask for the bit in question */
+ ulong mask;
+ /* Description of the bitmask in question */
+ char *desc;
+ } bits[] = {
+ {
+ RSR_SWSR, "Software Soft"}, {
+ RSR_SWHR, "Software Hard"}, {
+ RSR_JSRS, "JTAG Soft"}, {
+ RSR_CSHR, "Check Stop"}, {
+ RSR_SWRS, "Software Watchdog"}, {
+ RSR_BMRS, "Bus Monitor"}, {
+ RSR_SRS, "External/Internal Soft"}, {
+ RSR_HRS, "External/Internal Hard"}
+ };
+ int res;
+ ulong rsr = gd->arch.reset_status;
+ int i;
+ char *sep;
+
+ res = snprintf(buf, size, "Reset Status:");
+ if (res < 0) {
+ debug("%s: Could not write reset status message (err = %d)\n",
+ dev->name, res);
+ return -EIO;
+ }
+
+ buf += res;
+ size -= res;
+
+ sep = " ";
+ for (i = 0; i < ARRAY_SIZE(bits); i++)
+ /* Print description of set bits */
+ if (rsr & bits[i].mask) {
+ res = snprintf(buf, size, "%s%s%s", sep, bits[i].desc,
+ (i == ARRAY_SIZE(bits) - 1) ? "\n" : "");
+ if (res < 0) {
+ debug("%s: Could not write reset status message (err = %d)\n",
+ dev->name, res);
+ return -EIO;
+ }
+ buf += res;
+ size -= res;
+ sep = ", ";
+ }
+
+ /*
+ * TODO(mario.six@gdsys.cc): Move this into a dedicated
+ * arbiter driver
+ */
+ if (IS_ENABLED(CONFIG_DISPLAY_AER_FULL) ||
+ IS_ENABLED(CONFIG_DISPLAY_AER_BRIEF)) {
+ /*
+ * If there was a bus monitor reset event, we force the arbiter
+ * event to be printed
+ */
+ res = print_83xx_arb_event(rsr & RSR_BMRS, buf, size);
+ if (res < 0) {
+ debug("%s: Could not write arbiter event message (err = %d)\n",
+ dev->name, res);
+ return -EIO;
+ }
+ buf += res;
+ size -= res;
+ }
+ snprintf(buf, size, "\n");
+
+ return 0;
+}
+
+static struct sysreset_ops mpc83xx_sysreset = {
+ .request = mpc83xx_sysreset_request,
+ .get_status = mpc83xx_sysreset_get_status,
+};
+
+U_BOOT_DRIVER(sysreset_mpc83xx) = {
+ .name = "mpc83xx_sysreset",
+ .id = UCLASS_SYSRESET,
+ .ops = &mpc83xx_sysreset,
+};
diff --git a/drivers/sysreset/sysreset_mpc83xx.h b/drivers/sysreset/sysreset_mpc83xx.h
new file mode 100644
index 00000000000..dc3c05921f2
--- /dev/null
+++ b/drivers/sysreset/sysreset_mpc83xx.h
@@ -0,0 +1,103 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (C) Copyright 2018
+ * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
+ */
+
+#ifndef _SYSRESET_MPC83XX_H_
+#define _SYSRESET_MPC83XX_H_
+
+/*
+ * String array for all possible event types; indexed by the EVENT field of the
+ * AEATR register.
+ */
+static const char * const event[] = {
+ "Address Time Out",
+ "Data Time Out",
+ "Address Only Transfer Type",
+ "External Control Word Transfer Type",
+ "Reserved Transfer Type",
+ "Transfer Error",
+ "reserved",
+ "reserved"
+};
+
+/*
+ * String array for all possible master IDs, which reflects the source of the
+ * transaction that caused the error; indexed by the MSTR_ID field of the AEATR
+ * register.
+ */
+static const char * const master[] = {
+ "e300 Core Data Transaction",
+ "reserved",
+ "e300 Core Instruction Fetch",
+ "reserved",
+ "TSEC1",
+ "TSEC2",
+ "USB MPH",
+ "USB DR",
+ "Encryption Core",
+ "I2C Boot Sequencer",
+ "JTAG",
+ "reserved",
+ "eSDHC",
+ "PCI1",
+ "PCI2",
+ "DMA",
+ "QUICC Engine 00",
+ "QUICC Engine 01",
+ "QUICC Engine 10",
+ "QUICC Engine 11",
+ "reserved",
+ "reserved",
+ "reserved",
+ "reserved",
+ "SATA1",
+ "SATA2",
+ "SATA3",
+ "SATA4",
+ "reserved",
+ "PCI Express 1",
+ "PCI Express 2",
+ "TDM-DMAC"
+};
+
+/*
+ * String array for all possible transfer types; indexed by the TTYPE field of
+ * the AEATR register.
+ */
+static const char * const transfer[] = {
+ "Address-only, Clean Block",
+ "Address-only, lwarx reservation set",
+ "Single-beat or Burst write",
+ "reserved",
+ "Address-only, Flush Block",
+ "reserved",
+ "Burst write",
+ "reserved",
+ "Address-only, sync",
+ "Address-only, tlbsync",
+ "Single-beat or Burst read",
+ "Single-beat or Burst read",
+ "Address-only, Kill Block",
+ "Address-only, icbi",
+ "Burst read",
+ "reserved",
+ "Address-only, eieio",
+ "reserved",
+ "Single-beat write",
+ "reserved",
+ "ecowx - Illegal single-beat write",
+ "reserved",
+ "reserved",
+ "reserved",
+ "Address-only, TLB Invalidate",
+ "reserved",
+ "Single-beat or Burst read",
+ "reserved",
+ "eciwx - Illegal single-beat read",
+ "reserved",
+ "Burst read",
+ "reserved"
+};
+#endif /* _SYSRESET_MPC83XX_H_ */
diff --git a/drivers/sysreset/sysreset_octeon.c b/drivers/sysreset/sysreset_octeon.c
new file mode 100644
index 00000000000..ebdea6ab66e
--- /dev/null
+++ b/drivers/sysreset/sysreset_octeon.c
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2020 Stefan Roese <sr@denx.de>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <sysreset.h>
+#include <asm/io.h>
+
+#define RST_SOFT_RST 0x0080
+
+struct octeon_sysreset_data {
+ void __iomem *base;
+};
+
+static int octeon_sysreset_request(struct udevice *dev, enum sysreset_t type)
+{
+ struct octeon_sysreset_data *data = dev_get_priv(dev);
+
+ writeq(1, data->base + RST_SOFT_RST);
+
+ return -EINPROGRESS;
+}
+
+static int octeon_sysreset_probe(struct udevice *dev)
+{
+ struct octeon_sysreset_data *data = dev_get_priv(dev);
+
+ data->base = dev_remap_addr(dev);
+
+ return 0;
+}
+
+static struct sysreset_ops octeon_sysreset = {
+ .request = octeon_sysreset_request,
+};
+
+static const struct udevice_id octeon_sysreset_ids[] = {
+ { .compatible = "mrvl,cn7xxx-rst" },
+ { }
+};
+
+U_BOOT_DRIVER(sysreset_octeon) = {
+ .id = UCLASS_SYSRESET,
+ .name = "octeon_sysreset",
+ .priv_auto = sizeof(struct octeon_sysreset_data),
+ .ops = &octeon_sysreset,
+ .probe = octeon_sysreset_probe,
+ .of_match = octeon_sysreset_ids,
+};
diff --git a/drivers/sysreset/sysreset_palmas.c b/drivers/sysreset/sysreset_palmas.c
new file mode 100644
index 00000000000..9e3aa403488
--- /dev/null
+++ b/drivers/sysreset/sysreset_palmas.c
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright(C) 2023 Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#include <dm.h>
+#include <i2c.h>
+#include <errno.h>
+#include <sysreset.h>
+#include <power/pmic.h>
+#include <power/palmas.h>
+
+static int palmas_sysreset_request(struct udevice *dev,
+ enum sysreset_t type)
+{
+ struct palmas_priv *priv = dev_get_priv(dev->parent);
+ int ret;
+
+ /*
+ * Mask INT3 on second page which detects vbus
+ * or device will immediately turn on.
+ */
+ ret = dm_i2c_reg_clrset(priv->chip2, PALMAS_INT3_MASK,
+ MASK_VBUS, MASK_VBUS);
+ if (ret < 0)
+ return ret;
+
+ switch (type) {
+ case SYSRESET_POWER:
+ /* PALMAS: SW_RST > DEV_CTRL */
+ pmic_reg_write(dev->parent, PALMAS_DEV_CTRL, SW_RST);
+ break;
+ case SYSRESET_POWER_OFF:
+ /* PALMAS: DEV_OFF > DEV_CTRL */
+ pmic_reg_write(dev->parent, PALMAS_DEV_CTRL, DEV_OFF);
+ break;
+ default:
+ return -EPROTONOSUPPORT;
+ }
+
+ return -EINPROGRESS;
+}
+
+static struct sysreset_ops palmas_sysreset = {
+ .request = palmas_sysreset_request,
+};
+
+U_BOOT_DRIVER(sysreset_palmas) = {
+ .id = UCLASS_SYSRESET,
+ .name = PALMAS_RST_DRIVER,
+ .ops = &palmas_sysreset,
+};
diff --git a/drivers/sysreset/sysreset_psci.c b/drivers/sysreset/sysreset_psci.c
new file mode 100644
index 00000000000..aa09d0b8827
--- /dev/null
+++ b/drivers/sysreset/sysreset_psci.c
@@ -0,0 +1,44 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2017 Masahiro Yamada <yamada.masahiro@socionext.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <sysreset.h>
+#include <linux/errno.h>
+#include <linux/psci.h>
+
+__weak int psci_sysreset_get_status(struct udevice *dev, char *buf, int size)
+{
+ return -EOPNOTSUPP;
+}
+
+static int psci_sysreset_request(struct udevice *dev, enum sysreset_t type)
+{
+ switch (type) {
+ case SYSRESET_WARM:
+ case SYSRESET_COLD:
+ psci_sys_reset(type);
+ break;
+ case SYSRESET_POWER_OFF:
+ psci_sys_poweroff();
+ break;
+ default:
+ return -EPROTONOSUPPORT;
+ }
+
+ return -EINPROGRESS;
+}
+
+static struct sysreset_ops psci_sysreset_ops = {
+ .request = psci_sysreset_request,
+ .get_status = psci_sysreset_get_status,
+};
+
+U_BOOT_DRIVER(psci_sysreset) = {
+ .name = "psci-sysreset",
+ .id = UCLASS_SYSRESET,
+ .ops = &psci_sysreset_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/sysreset/sysreset_raa215300.c b/drivers/sysreset/sysreset_raa215300.c
new file mode 100644
index 00000000000..32dfcb0aec8
--- /dev/null
+++ b/drivers/sysreset/sysreset_raa215300.c
@@ -0,0 +1,58 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2023 Renesas Electronics Corporation
+ */
+
+#include <dm.h>
+#include <power/pmic.h>
+#include <sysreset.h>
+
+#define RAA215300_REG_SWRESET 0x6D
+#define RAA215300_COLD_RESET BIT(0)
+#define RAA215300_WARM_RESET BIT(1)
+
+static int raa215300_sysreset_request(struct udevice *dev, enum sysreset_t type)
+{
+ struct udevice *pmic = dev_get_parent(dev);
+ int ret;
+ u8 val;
+
+ /*
+ * The RAA215300 documentation names the available reset types
+ * differently to u-boot:
+ *
+ * - A "warm" reset via the RAA215300 PMIC will fully reset the SoC
+ * (CPU & GPIOs), so this corresponds to SYSRESET_COLD.
+ *
+ * - A "cold" reset via the RAA215300 PMIC will cycle all power supply
+ * rails, so this corresponds to SYSRESET_POWER.
+ */
+ switch (type) {
+ case SYSRESET_COLD:
+ val = RAA215300_WARM_RESET;
+ break;
+
+ case SYSRESET_POWER:
+ val = RAA215300_COLD_RESET;
+ break;
+
+ default:
+ return -EPROTONOSUPPORT;
+ }
+
+ ret = pmic_reg_write(pmic, RAA215300_REG_SWRESET, val);
+ if (ret)
+ return ret;
+
+ return -EINPROGRESS;
+}
+
+static struct sysreset_ops raa215300_sysreset_ops = {
+ .request = raa215300_sysreset_request,
+};
+
+U_BOOT_DRIVER(raa215300_sysreset) = {
+ .name = "raa215300_sysreset",
+ .id = UCLASS_SYSRESET,
+ .ops = &raa215300_sysreset_ops,
+};
diff --git a/drivers/sysreset/sysreset_resetctl.c b/drivers/sysreset/sysreset_resetctl.c
new file mode 100644
index 00000000000..25bd5c9a7ff
--- /dev/null
+++ b/drivers/sysreset/sysreset_resetctl.c
@@ -0,0 +1,48 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2020 MediaTek Inc.
+ *
+ * Author: Weijie Gao <weijie.gao@mediatek.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <sysreset.h>
+#include <reset.h>
+
+struct resetctl_reboot_priv {
+ struct reset_ctl_bulk resets;
+};
+
+static int resetctl_reboot_request(struct udevice *dev, enum sysreset_t type)
+{
+ struct resetctl_reboot_priv *priv = dev_get_priv(dev);
+
+ return reset_assert_bulk(&priv->resets);
+}
+
+static struct sysreset_ops resetctl_reboot_ops = {
+ .request = resetctl_reboot_request,
+};
+
+static int resetctl_reboot_probe(struct udevice *dev)
+{
+ struct resetctl_reboot_priv *priv = dev_get_priv(dev);
+
+ return reset_get_bulk(dev, &priv->resets);
+}
+
+static const struct udevice_id resetctl_reboot_ids[] = {
+ { .compatible = "resetctl-reboot" },
+ { }
+};
+
+U_BOOT_DRIVER(resetctl_reboot) = {
+ .id = UCLASS_SYSRESET,
+ .name = "resetctl_reboot",
+ .of_match = resetctl_reboot_ids,
+ .ops = &resetctl_reboot_ops,
+ .priv_auto = sizeof(struct resetctl_reboot_priv),
+ .probe = resetctl_reboot_probe,
+};
diff --git a/drivers/sysreset/sysreset_rockchip.c b/drivers/sysreset/sysreset_rockchip.c
new file mode 100644
index 00000000000..f353f9b4c79
--- /dev/null
+++ b/drivers/sysreset/sysreset_rockchip.c
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * (C) Copyright 2017 Rockchip Electronics Co., Ltd
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <sysreset.h>
+#include <asm/arch-rockchip/clock.h>
+#include <asm/arch-rockchip/cru_rk3328.h>
+#include <asm/arch-rockchip/hardware.h>
+#include <linux/err.h>
+
+int rockchip_sysreset_request(struct udevice *dev, enum sysreset_t type)
+{
+ struct sysreset_reg *offset = dev_get_priv(dev);
+ unsigned long cru_base = (unsigned long)rockchip_get_cru();
+
+ if (IS_ERR_VALUE(cru_base))
+ return (int)cru_base;
+
+ switch (type) {
+ case SYSRESET_WARM:
+ writel(0xeca8, cru_base + offset->glb_srst_snd_value);
+ break;
+ case SYSRESET_COLD:
+ writel(0xfdb9, cru_base + offset->glb_srst_fst_value);
+ break;
+ default:
+ return -EPROTONOSUPPORT;
+ }
+
+ return -EINPROGRESS;
+}
+
+static struct sysreset_ops rockchip_sysreset = {
+ .request = rockchip_sysreset_request,
+};
+
+U_BOOT_DRIVER(sysreset_rockchip) = {
+ .name = "rockchip_sysreset",
+ .id = UCLASS_SYSRESET,
+ .ops = &rockchip_sysreset,
+};
diff --git a/drivers/sysreset/sysreset_sandbox.c b/drivers/sysreset/sysreset_sandbox.c
new file mode 100644
index 00000000000..c12eda81d03
--- /dev/null
+++ b/drivers/sysreset/sysreset_sandbox.c
@@ -0,0 +1,140 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <sysreset.h>
+#include <asm/state.h>
+#include <asm/test.h>
+
+static int sandbox_warm_sysreset_request(struct udevice *dev,
+ enum sysreset_t type)
+{
+ struct sandbox_state *state = state_get_current();
+
+ switch (type) {
+ case SYSRESET_WARM:
+ state->last_sysreset = type;
+ break;
+ default:
+ return -EPROTONOSUPPORT;
+ }
+ if (!state->sysreset_allowed[type])
+ return -EACCES;
+
+ return -EINPROGRESS;
+}
+
+int sandbox_warm_sysreset_get_status(struct udevice *dev, char *buf, int size)
+{
+ strlcpy(buf, "Reset Status: WARM", size);
+
+ return 0;
+}
+
+int sandbox_warm_sysreset_get_last(struct udevice *dev)
+{
+ return SYSRESET_WARM;
+}
+
+static int sandbox_sysreset_request(struct udevice *dev, enum sysreset_t type)
+{
+ struct sandbox_state *state = state_get_current();
+
+ /*
+ * If we have a device tree, the device we created from platform data
+ * (see the U_BOOT_DRVINFO() declaration below) should not do anything.
+ * If we are that device, return an error.
+ */
+ if (state->fdt_fname && !dev_has_ofnode(dev))
+ return -ENODEV;
+
+ switch (type) {
+ case SYSRESET_COLD:
+ state->last_sysreset = type;
+ if (!state->sysreset_allowed[type])
+ return -EACCES;
+ sandbox_reset();
+ break;
+ case SYSRESET_POWER_OFF:
+ state->last_sysreset = type;
+ if (!state->sysreset_allowed[type])
+ return -EACCES;
+ sandbox_exit();
+ case SYSRESET_POWER:
+ if (!state->sysreset_allowed[type])
+ return -EACCES;
+ sandbox_exit();
+ default:
+ return -EPROTONOSUPPORT;
+ }
+ if (!state->sysreset_allowed[type])
+ return -EACCES;
+
+ return -EINPROGRESS;
+}
+
+int sandbox_sysreset_get_status(struct udevice *dev, char *buf, int size)
+{
+ strlcpy(buf, "Reset Status: COLD", size);
+
+ return 0;
+}
+
+int sandbox_sysreset_get_last(struct udevice *dev)
+{
+ struct sandbox_state *state = state_get_current();
+
+ /*
+ * The first phase is a power reset, after that we assume we don't
+ * know.
+ */
+ return state->jumped_fname ? SYSRESET_WARM : SYSRESET_POWER;
+}
+
+static struct sysreset_ops sandbox_sysreset_ops = {
+ .request = sandbox_sysreset_request,
+ .get_status = sandbox_sysreset_get_status,
+ .get_last = sandbox_sysreset_get_last,
+};
+
+static const struct udevice_id sandbox_sysreset_ids[] = {
+ { .compatible = "sandbox,reset" },
+ { }
+};
+
+U_BOOT_DRIVER(sysreset_sandbox) = {
+ .name = "sysreset_sandbox",
+ .id = UCLASS_SYSRESET,
+ .of_match = sandbox_sysreset_ids,
+ .ops = &sandbox_sysreset_ops,
+};
+
+static struct sysreset_ops sandbox_warm_sysreset_ops = {
+ .request = sandbox_warm_sysreset_request,
+ .get_status = sandbox_warm_sysreset_get_status,
+ .get_last = sandbox_warm_sysreset_get_last,
+};
+
+static const struct udevice_id sandbox_warm_sysreset_ids[] = {
+ { .compatible = "sandbox,warm-reset" },
+ { }
+};
+
+U_BOOT_DRIVER(warm_sysreset_sandbox) = {
+ .name = "warm_sysreset_sandbox",
+ .id = UCLASS_SYSRESET,
+ .of_match = sandbox_warm_sysreset_ids,
+ .ops = &sandbox_warm_sysreset_ops,
+};
+
+#if CONFIG_IS_ENABLED(OF_REAL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
+/* This is here in case we don't have a device tree */
+U_BOOT_DRVINFO(sysreset_sandbox_non_fdt) = {
+ .name = "sysreset_sandbox",
+};
+#endif
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,
+};
diff --git a/drivers/sysreset/sysreset_socfpga.c b/drivers/sysreset/sysreset_socfpga.c
new file mode 100644
index 00000000000..9b62dd5eab0
--- /dev/null
+++ b/drivers/sysreset/sysreset_socfpga.c
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 Pepperl+Fuchs
+ * Simon Goldschmidt <simon.k.r.goldschmidt@gmail.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <sysreset.h>
+#include <asm/io.h>
+#include <asm/arch/reset_manager.h>
+#include <linux/bitops.h>
+
+struct socfpga_sysreset_data {
+ void __iomem *rstmgr_base;
+};
+
+static int socfpga_sysreset_request(struct udevice *dev,
+ enum sysreset_t type)
+{
+ struct socfpga_sysreset_data *data = dev_get_priv(dev);
+
+ switch (type) {
+ case SYSRESET_WARM:
+ writel(BIT(RSTMGR_CTRL_SWWARMRSTREQ_LSB),
+ data->rstmgr_base + RSTMGR_CTRL);
+ break;
+ case SYSRESET_COLD:
+ writel(BIT(RSTMGR_CTRL_SWCOLDRSTREQ_LSB),
+ data->rstmgr_base + RSTMGR_CTRL);
+ break;
+ default:
+ return -EPROTONOSUPPORT;
+ }
+ return -EINPROGRESS;
+}
+
+static int socfpga_sysreset_probe(struct udevice *dev)
+{
+ struct socfpga_sysreset_data *data = dev_get_priv(dev);
+
+ data->rstmgr_base = dev_read_addr_ptr(dev_get_parent(dev));
+ return 0;
+}
+
+static struct sysreset_ops socfpga_sysreset = {
+ .request = socfpga_sysreset_request,
+};
+
+U_BOOT_DRIVER(sysreset_socfpga) = {
+ .id = UCLASS_SYSRESET,
+ .name = "socfpga_sysreset",
+ .priv_auto = sizeof(struct socfpga_sysreset_data),
+ .ops = &socfpga_sysreset,
+ .probe = socfpga_sysreset_probe,
+};
diff --git a/drivers/sysreset/sysreset_socfpga_soc64.c b/drivers/sysreset/sysreset_socfpga_soc64.c
new file mode 100644
index 00000000000..9837aadf64b
--- /dev/null
+++ b/drivers/sysreset/sysreset_socfpga_soc64.c
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 Pepperl+Fuchs
+ * Simon Goldschmidt <simon.k.r.goldschmidt@gmail.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <sysreset.h>
+#include <asm/arch/mailbox_s10.h>
+
+static int socfpga_sysreset_request(struct udevice *dev,
+ enum sysreset_t type)
+{
+ puts("Mailbox: Issuing mailbox cmd REBOOT_HPS\n");
+ mbox_reset_cold();
+ return -EINPROGRESS;
+}
+
+static struct sysreset_ops socfpga_sysreset = {
+ .request = socfpga_sysreset_request,
+};
+
+U_BOOT_DRIVER(sysreset_socfpga) = {
+ .id = UCLASS_SYSRESET,
+ .name = "socfpga_sysreset",
+ .ops = &socfpga_sysreset,
+};
diff --git a/drivers/sysreset/sysreset_sti.c b/drivers/sysreset/sysreset_sti.c
new file mode 100644
index 00000000000..edd90aab061
--- /dev/null
+++ b/drivers/sysreset/sysreset_sti.c
@@ -0,0 +1,85 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2017, STMicroelectronics - All Rights Reserved
+ * Author(s): Patrice Chotard, <patrice.chotard@foss.st.com> for STMicroelectronics.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <regmap.h>
+#include <syscon.h>
+#include <sysreset.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <linux/bitops.h>
+#include <linux/printk.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct sti_sysreset_priv {
+ phys_addr_t base;
+};
+
+static int sti_sysreset_request(struct udevice *dev, enum sysreset_t type)
+{
+ struct sti_sysreset_priv *priv = dev_get_priv(dev);
+
+ generic_clear_bit(0, (void __iomem *)priv->base);
+
+ return -EINPROGRESS;
+}
+
+static int sti_sysreset_probe(struct udevice *dev)
+{
+ struct sti_sysreset_priv *priv = dev_get_priv(dev);
+ struct udevice *syscon;
+ struct regmap *regmap;
+ struct fdtdec_phandle_args syscfg_phandle;
+ int ret;
+
+ /* get corresponding syscon phandle */
+ ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, dev_of_offset(dev),
+ "st,syscfg", NULL, 0, 0,
+ &syscfg_phandle);
+ if (ret < 0) {
+ pr_err("Can't get syscfg phandle: %d\n", ret);
+ return ret;
+ }
+
+ ret = uclass_get_device_by_of_offset(UCLASS_SYSCON,
+ syscfg_phandle.node,
+ &syscon);
+ if (ret) {
+ pr_err("%s: uclass_get_device_by_of_offset failed: %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ regmap = syscon_get_regmap(syscon);
+ if (!regmap) {
+ pr_err("unable to get regmap for %s\n", syscon->name);
+ return -ENODEV;
+ }
+
+ priv->base = regmap->ranges[0].start;
+
+ return 0;
+}
+
+static struct sysreset_ops sti_sysreset = {
+ .request = sti_sysreset_request,
+};
+
+static const struct udevice_id sti_sysreset_ids[] = {
+ { .compatible = "st,stih407-restart" },
+ { }
+};
+
+U_BOOT_DRIVER(sysreset_sti) = {
+ .name = "sysreset_sti",
+ .id = UCLASS_SYSRESET,
+ .ops = &sti_sysreset,
+ .probe = sti_sysreset_probe,
+ .of_match = sti_sysreset_ids,
+ .priv_auto = sizeof(struct sti_sysreset_priv),
+};
diff --git a/drivers/sysreset/sysreset_syscon.c b/drivers/sysreset/sysreset_syscon.c
new file mode 100644
index 00000000000..e468dac0e90
--- /dev/null
+++ b/drivers/sysreset/sysreset_syscon.c
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2017 Álvaro Fernández Rojas <noltari@gmail.com>
+ *
+ * Derived from linux/drivers/power/reset/syscon-reboot.c:
+ * Copyright (C) 2013, Applied Micro Circuits Corporation
+ * Author: Feng Kan <fkan@apm.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <regmap.h>
+#include <sysreset.h>
+#include <syscon.h>
+#include <linux/err.h>
+#include <linux/printk.h>
+
+struct syscon_reboot_priv {
+ struct regmap *regmap;
+ unsigned int offset;
+ unsigned int mask;
+ unsigned int value;
+};
+
+static int syscon_reboot_request(struct udevice *dev, enum sysreset_t type)
+{
+ struct syscon_reboot_priv *priv = dev_get_priv(dev);
+ ulong driver_data = dev_get_driver_data(dev);
+
+ if (type != driver_data)
+ return -EPROTONOSUPPORT;
+
+ regmap_update_bits(priv->regmap, priv->offset, priv->mask, priv->value);
+
+ return -EINPROGRESS;
+}
+
+static struct sysreset_ops syscon_reboot_ops = {
+ .request = syscon_reboot_request,
+};
+
+static int syscon_reboot_probe(struct udevice *dev)
+{
+ struct syscon_reboot_priv *priv = dev_get_priv(dev);
+ int err;
+ int mask_err, value_err;
+
+ priv->regmap = syscon_regmap_lookup_by_phandle(dev, "regmap");
+ if (IS_ERR(priv->regmap)) {
+ pr_err("unable to find regmap\n");
+ return -ENODEV;
+ }
+
+ err = dev_read_u32(dev, "offset", &priv->offset);
+ if (err) {
+ pr_err("unable to find offset\n");
+ return -ENOENT;
+ }
+
+ mask_err = dev_read_u32(dev, "mask", &priv->mask);
+ value_err = dev_read_u32(dev, "value", &priv->value);
+ if (mask_err && value_err) {
+ pr_err("unable to find mask and value\n");
+ return -EINVAL;
+ }
+
+ if (value_err) {
+ /* support old binding */
+ priv->value = priv->mask;
+ priv->mask = 0xffffffff;
+ } else if (mask_err) {
+ /* support value without mask*/
+ priv->mask = 0xffffffff;
+ }
+
+ return 0;
+}
+
+static const struct udevice_id syscon_reboot_ids[] = {
+ { .compatible = "syscon-reboot", .data = SYSRESET_COLD },
+ { .compatible = "syscon-poweroff", .data = SYSRESET_POWER_OFF },
+ { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(syscon_reboot) = {
+ .name = "syscon_reboot",
+ .id = UCLASS_SYSRESET,
+ .of_match = syscon_reboot_ids,
+ .probe = syscon_reboot_probe,
+ .priv_auto = sizeof(struct syscon_reboot_priv),
+ .ops = &syscon_reboot_ops,
+};
diff --git a/drivers/sysreset/sysreset_tegra.c b/drivers/sysreset/sysreset_tegra.c
new file mode 100644
index 00000000000..10bcd3a1873
--- /dev/null
+++ b/drivers/sysreset/sysreset_tegra.c
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright(C) 2023 Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#include <dm.h>
+#include <errno.h>
+#include <sysreset.h>
+#include <linux/err.h>
+#include <asm/arch-tegra/pmc.h>
+
+static int tegra_sysreset_request(struct udevice *dev,
+ enum sysreset_t type)
+{
+ u32 value;
+
+ switch (type) {
+ case SYSRESET_WARM:
+ case SYSRESET_COLD:
+ /* resets everything but scratch 0 and reset status */
+ value = tegra_pmc_readl(PMC_CNTRL);
+ value |= PMC_CNTRL_MAIN_RST;
+ tegra_pmc_writel(value, PMC_CNTRL);
+ break;
+ default:
+ return -EPROTONOSUPPORT;
+ }
+
+ return -EINPROGRESS;
+}
+
+static struct sysreset_ops tegra_sysreset = {
+ .request = tegra_sysreset_request,
+};
+
+U_BOOT_DRIVER(sysreset_tegra) = {
+ .id = UCLASS_SYSRESET,
+ .name = "sysreset_tegra",
+ .ops = &tegra_sysreset,
+};
+
+/* Link to Tegra PMC once there is a driver */
+U_BOOT_DRVINFO(sysreset_tegra) = {
+ .name = "sysreset_tegra"
+};
diff --git a/drivers/sysreset/sysreset_tps65910.c b/drivers/sysreset/sysreset_tps65910.c
new file mode 100644
index 00000000000..98da56661c0
--- /dev/null
+++ b/drivers/sysreset/sysreset_tps65910.c
@@ -0,0 +1,54 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright(C) 2023 Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#include <dm.h>
+#include <i2c.h>
+#include <errno.h>
+#include <sysreset.h>
+#include <power/pmic.h>
+#include <power/tps65910_pmic.h>
+
+static int tps65910_sysreset_request(struct udevice *dev,
+ enum sysreset_t type)
+{
+ int val;
+
+ val = pmic_reg_read(dev->parent, TPS65910_REG_DEVICE_CTRL);
+ if (val < 0)
+ return val;
+
+ /* define power-off to be sequential */
+ val |= PWR_OFF_SEQ;
+ pmic_reg_write(dev->parent, TPS65910_REG_DEVICE_CTRL, val);
+
+ val &= ~DEV_ON;
+
+ switch (type) {
+ case SYSRESET_POWER:
+ /* TPS65910: DEV_OFF_RST > DEVICE_CTRL */
+ pmic_reg_write(dev->parent, TPS65910_REG_DEVICE_CTRL,
+ val | DEV_OFF_RST);
+ break;
+ case SYSRESET_POWER_OFF:
+ /* TPS65910: DEV_OFF > DEVICE_CTRL */
+ pmic_reg_write(dev->parent, TPS65910_REG_DEVICE_CTRL,
+ val | DEV_OFF);
+ break;
+ default:
+ return -EPROTONOSUPPORT;
+ }
+
+ return -EINPROGRESS;
+}
+
+static struct sysreset_ops tps65910_sysreset = {
+ .request = tps65910_sysreset_request,
+};
+
+U_BOOT_DRIVER(sysreset_tps65910) = {
+ .id = UCLASS_SYSRESET,
+ .name = TPS65910_RST_DRIVER,
+ .ops = &tps65910_sysreset,
+};
diff --git a/drivers/sysreset/sysreset_tps80031.c b/drivers/sysreset/sysreset_tps80031.c
new file mode 100644
index 00000000000..50024fe4e79
--- /dev/null
+++ b/drivers/sysreset/sysreset_tps80031.c
@@ -0,0 +1,40 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright(C) 2023 Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#include <dm.h>
+#include <i2c.h>
+#include <errno.h>
+#include <sysreset.h>
+#include <power/pmic.h>
+#include <power/tps80031.h>
+
+static int tps80031_sysreset_request(struct udevice *dev,
+ enum sysreset_t type)
+{
+ switch (type) {
+ case SYSRESET_POWER:
+ /* TPS80031: SW_RESET > PHOENIX_DEV_ON */
+ pmic_reg_write(dev->parent, TPS80031_PHOENIX_DEV_ON, SW_RESET);
+ break;
+ case SYSRESET_POWER_OFF:
+ /* TPS80031: DEVOFF > PHOENIX_DEV_ON */
+ pmic_reg_write(dev->parent, TPS80031_PHOENIX_DEV_ON, DEVOFF);
+ break;
+ default:
+ return -EPROTONOSUPPORT;
+ }
+
+ return -EINPROGRESS;
+}
+
+static struct sysreset_ops tps80031_sysreset = {
+ .request = tps80031_sysreset_request,
+};
+
+U_BOOT_DRIVER(sysreset_tps80031) = {
+ .id = UCLASS_SYSRESET,
+ .name = TPS80031_RST_DRIVER,
+ .ops = &tps80031_sysreset,
+};
diff --git a/drivers/sysreset/sysreset_watchdog.c b/drivers/sysreset/sysreset_watchdog.c
new file mode 100644
index 00000000000..6db5aa75b54
--- /dev/null
+++ b/drivers/sysreset/sysreset_watchdog.c
@@ -0,0 +1,91 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2017 Álvaro Fernández Rojas <noltari@gmail.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <dm/device-internal.h>
+#include <errno.h>
+#include <malloc.h>
+#include <sysreset.h>
+#include <wdt.h>
+#include <linux/printk.h>
+
+struct wdt_reboot_plat {
+ struct udevice *wdt;
+};
+
+static int wdt_reboot_request(struct udevice *dev, enum sysreset_t type)
+{
+ struct wdt_reboot_plat *plat = dev_get_plat(dev);
+ int ret;
+
+ switch (type) {
+ case SYSRESET_COLD:
+ case SYSRESET_WARM:
+ ret = wdt_expire_now(plat->wdt, 0);
+ if (ret)
+ return ret;
+ break;
+ default:
+ return -EPROTONOSUPPORT;
+ }
+
+ return -EINPROGRESS;
+}
+
+static struct sysreset_ops wdt_reboot_ops = {
+ .request = wdt_reboot_request,
+};
+
+static int wdt_reboot_of_to_plat(struct udevice *dev)
+{
+ struct wdt_reboot_plat *plat = dev_get_plat(dev);
+ int err;
+
+ err = uclass_get_device_by_phandle(UCLASS_WDT, dev,
+ "wdt", &plat->wdt);
+ if (err) {
+ pr_err("unable to find wdt device\n");
+ return err;
+ }
+
+ return 0;
+}
+
+static const struct udevice_id wdt_reboot_ids[] = {
+ { .compatible = "wdt-reboot" },
+ { /* sentinel */ }
+};
+
+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,
+};
+
+#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/sysreset/sysreset_x86.c b/drivers/sysreset/sysreset_x86.c
new file mode 100644
index 00000000000..dc772b5ff9e
--- /dev/null
+++ b/drivers/sysreset/sysreset_x86.c
@@ -0,0 +1,160 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
+ *
+ * Generic reset driver for x86 processor
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <efi_loader.h>
+#include <pch.h>
+#include <sysreset.h>
+#include <acpi/acpi_s3.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/sysreset.h>
+
+/*
+ * Power down the machine by using the power management sleep control
+ * of the chipset. This will currently only work on Intel chipsets.
+ * However, adapting it to new chipsets is fairly simple. You will
+ * have to find the IO address of the power management register block
+ * in your southbridge, and look up the appropriate SLP_TYP_S5 value
+ * from your southbridge's data sheet.
+ *
+ * This function never returns.
+ */
+int pch_sysreset_power_off(struct udevice *dev)
+{
+ struct x86_sysreset_plat *plat = dev_get_plat(dev);
+ struct pch_pmbase_info pm;
+ u32 reg32;
+ int ret;
+
+ if (!plat->pch)
+ return -ENOENT;
+ ret = pch_ioctl(plat->pch, PCH_REQ_PMBASE_INFO, &pm, sizeof(pm));
+ if (ret)
+ return ret;
+
+ /*
+ * Mask interrupts or system might stay in a coma, not executing code
+ * anymore, but not powered off either.
+ */
+ asm("cli");
+
+ /*
+ * Avoid any GPI waking the system from S5* or the system might stay in
+ * a coma
+ */
+ outl(0x00000000, pm.base + pm.gpio0_en_ofs);
+
+ /* Clear Power Button Status */
+ outw(PWRBTN_STS, pm.base + pm.pm1_sts_ofs);
+
+ /* PMBASE + 4, Bit 10-12, Sleeping Type, * set to 111 -> S5, soft_off */
+ reg32 = inl(pm.base + pm.pm1_cnt_ofs);
+
+ /* Set Sleeping Type to S5 (poweroff) */
+ reg32 &= ~(SLP_EN | SLP_TYP);
+ reg32 |= SLP_TYP_S5;
+ outl(reg32, pm.base + pm.pm1_cnt_ofs);
+
+ /* Now set the Sleep Enable bit */
+ reg32 |= SLP_EN;
+ outl(reg32, pm.base + pm.pm1_cnt_ofs);
+
+ for (;;)
+ asm("hlt");
+}
+
+static int x86_sysreset_request(struct udevice *dev, enum sysreset_t type)
+{
+ int value;
+ int ret;
+
+ switch (type) {
+ case SYSRESET_WARM:
+ value = SYS_RST | RST_CPU;
+ break;
+ case SYSRESET_COLD:
+ value = SYS_RST | RST_CPU | FULL_RST;
+ break;
+ case SYSRESET_POWER_OFF:
+ ret = pch_sysreset_power_off(dev);
+ if (ret)
+ return ret;
+ return -EINPROGRESS;
+ default:
+ return -EPROTONOSUPPORT;
+ }
+
+ outb(value, IO_PORT_RESET);
+
+ return -EINPROGRESS;
+}
+
+static int x86_sysreset_get_last(struct udevice *dev)
+{
+ return SYSRESET_POWER;
+}
+
+#ifdef CONFIG_EFI_LOADER
+void __efi_runtime EFIAPI efi_reset_system(
+ enum efi_reset_type reset_type,
+ efi_status_t reset_status,
+ unsigned long data_size, void *reset_data)
+{
+ int value;
+
+ /*
+ * inline this code since we are not caused in the context of a
+ * udevice and passing NULL to x86_sysreset_request() is too horrible.
+ */
+ if (reset_type == EFI_RESET_COLD ||
+ reset_type == EFI_RESET_PLATFORM_SPECIFIC)
+ value = SYS_RST | RST_CPU | FULL_RST;
+ else /* assume EFI_RESET_WARM since we cannot return an error */
+ value = SYS_RST | RST_CPU;
+ outb(value, IO_PORT_RESET);
+
+ /* TODO EFI_RESET_SHUTDOWN */
+
+ while (1) { }
+}
+#endif
+
+static int x86_sysreset_probe(struct udevice *dev)
+{
+ struct x86_sysreset_plat *plat = dev_get_plat(dev);
+
+ /*
+ * Locate the PCH if there is one. It isn't essential. Avoid this before
+ * relocation as we shouldn't need reset then and it needs a lot of
+ * memory for PCI enumeration.
+ */
+ if (gd->flags & GD_FLG_RELOC)
+ uclass_first_device(UCLASS_PCH, &plat->pch);
+
+ return 0;
+}
+
+static const struct udevice_id x86_sysreset_ids[] = {
+ { .compatible = "x86,reset" },
+ { }
+};
+
+static struct sysreset_ops x86_sysreset_ops = {
+ .request = x86_sysreset_request,
+ .get_last = x86_sysreset_get_last,
+};
+
+U_BOOT_DRIVER(x86_reset) = {
+ .name = "x86_reset",
+ .id = UCLASS_SYSRESET,
+ .of_match = x86_sysreset_ids,
+ .ops = &x86_sysreset_ops,
+ .probe = x86_sysreset_probe,
+ .plat_auto = sizeof(struct x86_sysreset_plat),
+};
diff --git a/drivers/sysreset/sysreset_xtfpga.c b/drivers/sysreset/sysreset_xtfpga.c
new file mode 100644
index 00000000000..84fbc79016a
--- /dev/null
+++ b/drivers/sysreset/sysreset_xtfpga.c
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Cadence Tensilica xtfpga system reset driver.
+ *
+ * (C) Copyright 2016 Cadence Design Systems Inc.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <sysreset.h>
+#include <asm/io.h>
+
+static int xtfpga_reset_request(struct udevice *dev, enum sysreset_t type)
+{
+ switch (type) {
+ case SYSRESET_COLD:
+ writel(CFG_SYS_FPGAREG_RESET_CODE,
+ CFG_SYS_FPGAREG_RESET);
+ break;
+ default:
+ return -EPROTONOSUPPORT;
+ }
+
+ return -EINPROGRESS;
+}
+
+static struct sysreset_ops xtfpga_sysreset_ops = {
+ .request = xtfpga_reset_request,
+};
+
+U_BOOT_DRIVER(xtfpga_sysreset) = {
+ .name = "xtfpga_sysreset",
+ .id = UCLASS_SYSRESET,
+ .ops = &xtfpga_sysreset_ops,
+};