[PATCH v2 0/6] Implement proper sysreset ability for Tegra SoCs and some PMICs

This patchset converts do_reset from mach-tegra function to a proper sysreset dm driver with saving all its previous abilities.
Additionally implement do_poweroff (since Tegra sysreset can only reset) by making sysreset drivers for the most widely used PMICs on Tegra devices. This includes sysreset cells for MAX77663, TPS80031/TPS80032, TPS65910/TPS65911 and PALMAS PMIC family.
All drivers are tested on actual hardware and confirmed to work as expected.
These patches require "Add support for PMICs used on Tegra 3 devices" patches to be merged first for proper work.
https://patchwork.ozlabs.org/project/uboot/list/?series=369756
--- Changes from v1: - move variable declaration from switch ---
Svyatoslav Ryhel (6): sysreset: tegra: create arch specific sysreset driver arm: mach-tegra: enable sysreset driver sysreset: implement MAX77663 sysreset functions sysreset: implement TPS80031 sysreset functions sysreset: implement TPS65910 sysreset functions sysreset: implement PALMAS sysreset functions
arch/arm/mach-tegra/Kconfig | 3 ++ arch/arm/mach-tegra/pmc.c | 9 ----- drivers/power/pmic/max77663.c | 12 +++++- drivers/power/pmic/palmas.c | 33 +++++++++++++++- drivers/power/pmic/pmic_tps65910_dm.c | 12 +++++- drivers/power/pmic/tps80031.c | 12 +++++- drivers/sysreset/Kconfig | 36 ++++++++++++++++++ drivers/sysreset/Makefile | 5 +++ drivers/sysreset/sysreset_max77663.c | 53 ++++++++++++++++++++++++++ drivers/sysreset/sysreset_palmas.c | 53 ++++++++++++++++++++++++++ drivers/sysreset/sysreset_tegra.c | 46 ++++++++++++++++++++++ drivers/sysreset/sysreset_tps65910.c | 55 +++++++++++++++++++++++++++ drivers/sysreset/sysreset_tps80031.c | 41 ++++++++++++++++++++ include/power/max77663.h | 5 +++ include/power/palmas.h | 11 ++++++ include/power/tps65910_pmic.h | 7 ++++ include/power/tps80031.h | 5 +++ 17 files changed, 384 insertions(+), 14 deletions(-) create mode 100644 drivers/sysreset/sysreset_max77663.c create mode 100644 drivers/sysreset/sysreset_palmas.c create mode 100644 drivers/sysreset/sysreset_tegra.c create mode 100644 drivers/sysreset/sysreset_tps65910.c create mode 100644 drivers/sysreset/sysreset_tps80031.c

Tegra uses built in Power Management Controller (PMC) to perform CPU reset. Code to perform this was located in mach-tegra, so lest create DM driver to handle this.
Signed-off-by: Svyatoslav Ryhel clamor95@gmail.com --- drivers/sysreset/Kconfig | 6 ++++ drivers/sysreset/Makefile | 1 + drivers/sysreset/sysreset_tegra.c | 46 +++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+) create mode 100644 drivers/sysreset/sysreset_tegra.c
diff --git a/drivers/sysreset/Kconfig b/drivers/sysreset/Kconfig index bdbe2a9536..eab556c349 100644 --- a/drivers/sysreset/Kconfig +++ b/drivers/sysreset/Kconfig @@ -137,6 +137,12 @@ config SYSRESET_SOCFPGA_SOC64 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 diff --git a/drivers/sysreset/Makefile b/drivers/sysreset/Makefile index 40c876764a..a9ac123754 100644 --- a/drivers/sysreset/Makefile +++ b/drivers/sysreset/Makefile @@ -16,6 +16,7 @@ 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_SYSRESET_SYSCON) += sysreset_syscon.o obj-$(CONFIG_SYSRESET_WATCHDOG) += sysreset_watchdog.o diff --git a/drivers/sysreset/sysreset_tegra.c b/drivers/sysreset/sysreset_tegra.c new file mode 100644 index 0000000000..ee95826a29 --- /dev/null +++ b/drivers/sysreset/sysreset_tegra.c @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright(C) 2023 Svyatoslav Ryhel clamor95@gmail.com + */ + +#include <common.h> +#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" +};

Signed-off-by: Svyatoslav Ryhel clamor95@gmail.com --- arch/arm/mach-tegra/Kconfig | 3 +++ arch/arm/mach-tegra/pmc.c | 9 --------- 2 files changed, 3 insertions(+), 9 deletions(-)
diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig index 464bd0798f..453f94bcf2 100644 --- a/arch/arm/mach-tegra/Kconfig +++ b/arch/arm/mach-tegra/Kconfig @@ -61,6 +61,9 @@ config TEGRA_COMMON select MISC select OF_CONTROL select SPI + select SYSRESET + select SPL_SYSRESET + select SYSRESET_TEGRA imply CMD_DM imply CRC32_VERIFY
diff --git a/arch/arm/mach-tegra/pmc.c b/arch/arm/mach-tegra/pmc.c index 8d617bee63..c4f5106750 100644 --- a/arch/arm/mach-tegra/pmc.c +++ b/arch/arm/mach-tegra/pmc.c @@ -84,12 +84,3 @@ void tegra_pmc_writel(u32 value, unsigned long offset)
writel(value, NV_PA_PMC_BASE + offset); } - -void reset_cpu(void) -{ - u32 value; - - value = tegra_pmc_readl(PMC_CNTRL); - value |= PMC_CNTRL_MAIN_RST; - tegra_pmc_writel(value, PMC_CNTRL); -}

нд, 27 серп. 2023 р. о 11:21 Svyatoslav Ryhel clamor95@gmail.com пише:
Signed-off-by: Svyatoslav Ryhel clamor95@gmail.com
arch/arm/mach-tegra/Kconfig | 3 +++ arch/arm/mach-tegra/pmc.c | 9 --------- 2 files changed, 3 insertions(+), 9 deletions(-)
diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig index 464bd0798f..453f94bcf2 100644 --- a/arch/arm/mach-tegra/Kconfig +++ b/arch/arm/mach-tegra/Kconfig @@ -61,6 +61,9 @@ config TEGRA_COMMON select MISC select OF_CONTROL select SPI
select SYSRESET
select SPL_SYSRESET
select SYSRESET_TEGRA imply CMD_DM imply CRC32_VERIFY
Hello, Thierry! This causes buildman warnings on aarch64 (t184 and t210)
+ WARNING: unmet direct dependencies detected for SPL_SYSRESET + Depends on [n]: SYSRESET [=y] && SPL_DM [=n] + Selected by [y]: + - TEGRA_COMMON [=y] && ARM [=y] && ARCH_TEGRA [=y] aarch64: w+ p2771-0000-000
It lacks SPL_DM and since aarch64 is your main area of maintenance, may you help setting it in a way which does not break anything from aarch64 perspective?
Context is next: I am trying to convert tegra PMC reset ability to DM sysreset driver. Reason is to be able to use do_poweroff in DM sysreset form and it stated that OR both do_reset and do_poweroff are in DM driver form or none. Assume at some point this convertation will be requested anyway, like with timer driver.
diff --git a/arch/arm/mach-tegra/pmc.c b/arch/arm/mach-tegra/pmc.c index 8d617bee63..c4f5106750 100644 --- a/arch/arm/mach-tegra/pmc.c +++ b/arch/arm/mach-tegra/pmc.c @@ -84,12 +84,3 @@ void tegra_pmc_writel(u32 value, unsigned long offset)
writel(value, NV_PA_PMC_BASE + offset);
}
-void reset_cpu(void) -{
u32 value;
value = tegra_pmc_readl(PMC_CNTRL);
value |= PMC_CNTRL_MAIN_RST;
tegra_pmc_writel(value, PMC_CNTRL);
-}
2.39.2

MAX77663 PMIC has embedded poweroff function used by some device to initiane device power off. Implement it as sysreset driver.
Signed-off-by: Svyatoslav Ryhel clamor95@gmail.com --- drivers/power/pmic/max77663.c | 12 ++++++- drivers/sysreset/Kconfig | 7 ++++ drivers/sysreset/Makefile | 1 + drivers/sysreset/sysreset_max77663.c | 53 ++++++++++++++++++++++++++++ include/power/max77663.h | 5 +++ 5 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 drivers/sysreset/sysreset_max77663.c
diff --git a/drivers/power/pmic/max77663.c b/drivers/power/pmic/max77663.c index 4070235d3c..e333c8dcf5 100644 --- a/drivers/power/pmic/max77663.c +++ b/drivers/power/pmic/max77663.c @@ -9,6 +9,7 @@ #include <dm.h> #include <i2c.h> #include <log.h> +#include <dm/lists.h> #include <power/pmic.h> #include <power/regulator.h> #include <power/max77663.h> @@ -49,7 +50,16 @@ static int max77663_read(struct udevice *dev, uint reg, uint8_t *buff, int len) static int max77663_bind(struct udevice *dev) { ofnode regulators_node; - int children; + int children, ret; + + if (IS_ENABLED(CONFIG_SYSRESET_MAX77663)) { + ret = device_bind_driver(dev, MAX77663_RST_DRIVER, + "sysreset", NULL); + if (ret) { + log_err("cannot bind SYSRESET (ret = %d)\n", ret); + return ret; + } + }
regulators_node = dev_read_subnode(dev, "regulators"); if (!ofnode_valid(regulators_node)) { diff --git a/drivers/sysreset/Kconfig b/drivers/sysreset/Kconfig index eab556c349..bc35896101 100644 --- a/drivers/sysreset/Kconfig +++ b/drivers/sysreset/Kconfig @@ -74,6 +74,13 @@ config SYSRESET_GPIO 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 diff --git a/drivers/sysreset/Makefile b/drivers/sysreset/Makefile index a9ac123754..c31f51c581 100644 --- a/drivers/sysreset/Makefile +++ b/drivers/sysreset/Makefile @@ -9,6 +9,7 @@ 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 diff --git a/drivers/sysreset/sysreset_max77663.c b/drivers/sysreset/sysreset_max77663.c new file mode 100644 index 0000000000..4a2a2275df --- /dev/null +++ b/drivers/sysreset/sysreset_max77663.c @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright(C) 2023 Svyatoslav Ryhel clamor95@gmail.com + */ + +#include <common.h> +#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/include/power/max77663.h b/include/power/max77663.h index 0f764bcbcc..b3ae3dabf4 100644 --- a/include/power/max77663.h +++ b/include/power/max77663.h @@ -12,6 +12,7 @@ /* Drivers name */ #define MAX77663_LDO_DRIVER "max77663_ldo" #define MAX77663_SD_DRIVER "max77663_sd" +#define MAX77663_RST_DRIVER "max77663_rst"
/* Step-Down (SD) Regulator calculations */ #define SD_STATUS_MASK 0x30 @@ -39,4 +40,8 @@
#define LDO_VOLT_BASE 800000
+#define MAX77663_REG_ONOFF_CFG1 0x41 +#define ONOFF_SFT_RST BIT(7) +#define ONOFF_PWR_OFF BIT(1) + #endif /* _MAX77663_H_ */

TPS80031/TPS80032 PMICs have embedded power control functions used by some device to initiane device power off. Implement it as sysreset driver.
Signed-off-by: Svyatoslav Ryhel clamor95@gmail.com --- drivers/power/pmic/tps80031.c | 12 +++++++- drivers/sysreset/Kconfig | 8 ++++++ drivers/sysreset/Makefile | 1 + drivers/sysreset/sysreset_tps80031.c | 41 ++++++++++++++++++++++++++++ include/power/tps80031.h | 5 ++++ 5 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 drivers/sysreset/sysreset_tps80031.c
diff --git a/drivers/power/pmic/tps80031.c b/drivers/power/pmic/tps80031.c index c2b04fffdf..45e89ba5c9 100644 --- a/drivers/power/pmic/tps80031.c +++ b/drivers/power/pmic/tps80031.c @@ -9,6 +9,7 @@ #include <dm.h> #include <i2c.h> #include <log.h> +#include <dm/lists.h> #include <power/pmic.h> #include <power/regulator.h> #include <power/tps80031.h> @@ -49,7 +50,16 @@ static int tps80031_read(struct udevice *dev, uint reg, uint8_t *buff, int len) static int tps80031_bind(struct udevice *dev) { ofnode regulators_node; - int children; + int children, ret; + + if (IS_ENABLED(CONFIG_SYSRESET_TPS80031)) { + ret = device_bind_driver(dev, TPS80031_RST_DRIVER, + "sysreset", NULL); + if (ret) { + log_err("cannot bind SYSRESET (ret = %d)\n", ret); + return ret; + } + }
regulators_node = dev_read_subnode(dev, "regulators"); if (!ofnode_valid(regulators_node)) { diff --git a/drivers/sysreset/Kconfig b/drivers/sysreset/Kconfig index bc35896101..cdb4ae2bb1 100644 --- a/drivers/sysreset/Kconfig +++ b/drivers/sysreset/Kconfig @@ -157,6 +157,14 @@ config SYSRESET_TI_SCI This enables the system reset driver support over TI System Control Interface available on some new TI's SoCs.
+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 diff --git a/drivers/sysreset/Makefile b/drivers/sysreset/Makefile index c31f51c581..f62db899da 100644 --- a/drivers/sysreset/Makefile +++ b/drivers/sysreset/Makefile @@ -19,6 +19,7 @@ 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_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 diff --git a/drivers/sysreset/sysreset_tps80031.c b/drivers/sysreset/sysreset_tps80031.c new file mode 100644 index 0000000000..ea35f48ebd --- /dev/null +++ b/drivers/sysreset/sysreset_tps80031.c @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright(C) 2023 Svyatoslav Ryhel clamor95@gmail.com + */ + +#include <common.h> +#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/include/power/tps80031.h b/include/power/tps80031.h index c80692a8af..983c841bfe 100644 --- a/include/power/tps80031.h +++ b/include/power/tps80031.h @@ -12,6 +12,7 @@ /* Drivers name */ #define TPS80031_LDO_DRIVER "tps80031_ldo" #define TPS80031_SMPS_DRIVER "tps80031_smps" +#define TPS80031_RST_DRIVER "tps80031_rst"
#define TPS80031_SMPS_OFFSET 0xe0 #define TPS80031_OFFSET_FLAG BIT(0) @@ -35,6 +36,10 @@ #define LDO_VOLT_MIN 1018000 #define LDO_VOLT_BASE 916000
+#define TPS80031_PHOENIX_DEV_ON 0x25 +#define SW_RESET BIT(6) +#define DEVOFF BIT(0) + /* register groups */ enum { CTRL,

TPS65910/TPS65911 PMICs have embedded power control functions used by some device to initiane device power off. Implement it as sysreset driver.
Signed-off-by: Svyatoslav Ryhel clamor95@gmail.com --- drivers/power/pmic/pmic_tps65910_dm.c | 12 +++++- drivers/sysreset/Kconfig | 8 ++++ drivers/sysreset/Makefile | 1 + drivers/sysreset/sysreset_tps65910.c | 55 +++++++++++++++++++++++++++ include/power/tps65910_pmic.h | 7 ++++ 5 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 drivers/sysreset/sysreset_tps65910.c
diff --git a/drivers/power/pmic/pmic_tps65910_dm.c b/drivers/power/pmic/pmic_tps65910_dm.c index 53af3171cc..b9c2326d5b 100644 --- a/drivers/power/pmic/pmic_tps65910_dm.c +++ b/drivers/power/pmic/pmic_tps65910_dm.c @@ -7,6 +7,7 @@ #include <dm.h> #include <i2c.h> #include <log.h> +#include <dm/lists.h> #include <power/pmic.h> #include <power/regulator.h> #include <power/tps65910_pmic.h> @@ -58,7 +59,16 @@ static int pmic_tps65910_bind(struct udevice *dev) const struct pmic_child_info *tps6591x_children_info = (struct pmic_child_info *)dev_get_driver_data(dev); ofnode regulators_node; - int children; + int children, ret; + + if (IS_ENABLED(CONFIG_SYSRESET_TPS65910)) { + ret = device_bind_driver(dev, TPS65910_RST_DRIVER, + "sysreset", NULL); + if (ret) { + log_err("cannot bind SYSRESET (ret = %d)\n", ret); + return ret; + } + }
regulators_node = dev_read_subnode(dev, "regulators"); if (!ofnode_valid(regulators_node)) { diff --git a/drivers/sysreset/Kconfig b/drivers/sysreset/Kconfig index cdb4ae2bb1..659170d156 100644 --- a/drivers/sysreset/Kconfig +++ b/drivers/sysreset/Kconfig @@ -157,6 +157,14 @@ config SYSRESET_TI_SCI 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 diff --git a/drivers/sysreset/Makefile b/drivers/sysreset/Makefile index f62db899da..0d96a204a9 100644 --- a/drivers/sysreset/Makefile +++ b/drivers/sysreset/Makefile @@ -19,6 +19,7 @@ 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 diff --git a/drivers/sysreset/sysreset_tps65910.c b/drivers/sysreset/sysreset_tps65910.c new file mode 100644 index 0000000000..1a362dea0d --- /dev/null +++ b/drivers/sysreset/sysreset_tps65910.c @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright(C) 2023 Svyatoslav Ryhel clamor95@gmail.com + */ + +#include <common.h> +#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/include/power/tps65910_pmic.h b/include/power/tps65910_pmic.h index 7d6545abdf..2026ec2f42 100644 --- a/include/power/tps65910_pmic.h +++ b/include/power/tps65910_pmic.h @@ -17,6 +17,12 @@ #define TPS65910_SUPPLY_STATE_OFF 0x0 #define TPS65910_SUPPLY_STATE_ON 0x1
+/* TPS65910 DEVICE_CTRL bits */ +#define PWR_OFF_SEQ BIT(7) +#define DEV_OFF_RST BIT(3) +#define DEV_ON BIT(2) +#define DEV_OFF BIT(0) + /* i2c registers */ enum { TPS65910_REG_RTC_SEC = 0x00, @@ -125,6 +131,7 @@ struct tps65910_regulator_pdata { #define TPS65910_BUCK_DRIVER "tps65910_buck" #define TPS65910_BOOST_DRIVER "tps65910_boost" #define TPS65910_LDO_DRIVER "tps65910_ldo" +#define TPS65910_RST_DRIVER "tps65910_rst"
/* tps65911 i2c registers */ enum {

PALMAS PMIC family has embedded poweroff function used by some device to initiane device power off. Implement it as sysreset driver.
Signed-off-by: Svyatoslav Ryhel clamor95@gmail.com --- drivers/power/pmic/palmas.c | 33 +++++++++++++++++-- drivers/sysreset/Kconfig | 7 ++++ drivers/sysreset/Makefile | 1 + drivers/sysreset/sysreset_palmas.c | 53 ++++++++++++++++++++++++++++++ include/power/palmas.h | 11 +++++++ 5 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 drivers/sysreset/sysreset_palmas.c
diff --git a/drivers/power/pmic/palmas.c b/drivers/power/pmic/palmas.c index d6eb9cb433..eaa323ef8f 100644 --- a/drivers/power/pmic/palmas.c +++ b/drivers/power/pmic/palmas.c @@ -10,10 +10,10 @@ #include <dm.h> #include <i2c.h> #include <log.h> +#include <dm/lists.h> #include <power/pmic.h> #include <power/regulator.h> #include <power/palmas.h> -#include <dm/device.h>
static const struct pmic_child_info pmic_children_info[] = { { .prefix = "ldo", .driver = PALMAS_LDO_DRIVER }, @@ -46,7 +46,16 @@ static int palmas_bind(struct udevice *dev) { ofnode pmic_node = ofnode_null(), regulators_node; ofnode subnode; - int children; + int children, ret; + + if (IS_ENABLED(CONFIG_SYSRESET_PALMAS)) { + ret = device_bind_driver(dev, PALMAS_RST_DRIVER, + "sysreset", NULL); + if (ret) { + log_err("cannot bind SYSRESET (ret = %d)\n", ret); + return ret; + } + }
dev_for_each_subnode(subnode, dev) { const char *name; @@ -80,6 +89,24 @@ static int palmas_bind(struct udevice *dev) return 0; }
+static int palmas_probe(struct udevice *dev) +{ + struct dm_i2c_chip *chip = dev_get_parent_plat(dev); + struct palmas_priv *priv = dev_get_priv(dev); + struct udevice *bus = dev_get_parent(dev); + u32 chip2_addr = chip->chip_addr + 1; + int ret; + + /* Palmas PMIC is multi chip and chips are located in a row */ + ret = i2c_get_chip(bus, chip2_addr, 1, &priv->chip2); + if (ret) { + log_err("cannot get second PMIC I2C chip (err %d)\n", ret); + return ret; + } + + return 0; +} + static struct dm_pmic_ops palmas_ops = { .read = palmas_read, .write = palmas_write, @@ -97,5 +124,7 @@ U_BOOT_DRIVER(pmic_palmas) = { .id = UCLASS_PMIC, .of_match = palmas_ids, .bind = palmas_bind, + .probe = palmas_probe, .ops = &palmas_ops, + .priv_auto = sizeof(struct palmas_priv), }; diff --git a/drivers/sysreset/Kconfig b/drivers/sysreset/Kconfig index 659170d156..0e52f99628 100644 --- a/drivers/sysreset/Kconfig +++ b/drivers/sysreset/Kconfig @@ -109,6 +109,13 @@ config SYSRESET_SPL_AT91 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 diff --git a/drivers/sysreset/Makefile b/drivers/sysreset/Makefile index 0d96a204a9..c9f1c625ae 100644 --- a/drivers/sysreset/Makefile +++ b/drivers/sysreset/Makefile @@ -13,6 +13,7 @@ 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 diff --git a/drivers/sysreset/sysreset_palmas.c b/drivers/sysreset/sysreset_palmas.c new file mode 100644 index 0000000000..d853c33504 --- /dev/null +++ b/drivers/sysreset/sysreset_palmas.c @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright(C) 2023 Svyatoslav Ryhel clamor95@gmail.com + */ + +#include <common.h> +#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/include/power/palmas.h b/include/power/palmas.h index df5f15c5bd..0a612052f0 100644 --- a/include/power/palmas.h +++ b/include/power/palmas.h @@ -2,6 +2,10 @@ #define TPS659038 0x1 #define TPS65917 0x2
+struct palmas_priv { + struct udevice *chip2; +}; + /* I2C device address for pmic palmas */ #define PALMAS_I2C_ADDR (0x12 >> 1) #define PALMAS_LDO_NUM 11 @@ -10,6 +14,7 @@ /* Drivers name */ #define PALMAS_LDO_DRIVER "palmas_ldo" #define PALMAS_SMPS_DRIVER "palmas_smps" +#define PALMAS_RST_DRIVER "palmas_rst"
#define PALMAS_SMPS_VOLT_MASK 0x7F #define PALMAS_SMPS_RANGE_MASK 0x80 @@ -24,3 +29,9 @@ #define PALMAS_LDO_MODE_MASK 0x1 #define PALMAS_LDO_STATUS_MASK 0x10 #define PALMAS_LDO_BYPASS_EN 0x40 + +#define PALMAS_DEV_CTRL 0xA0 +#define SW_RST BIT(1) +#define DEV_OFF 0x00 +#define PALMAS_INT3_MASK 0x1B +#define MASK_VBUS BIT(7)
participants (1)
-
Svyatoslav Ryhel