* [PATCH 0/4] power: sys-off: fix Pixel C shutdown via MAX77620
@ 2026-05-14 14:47 Diogo Ivo
2026-05-14 14:47 ` [PATCH 1/4] firmware: psci: switch SYSTEM_OFF to sys-off handler API Diogo Ivo
` (3 more replies)
0 siblings, 4 replies; 7+ messages in thread
From: Diogo Ivo @ 2026-05-14 14:47 UTC (permalink / raw)
To: Mark Rutland, Lorenzo Pieralisi, Lee Jones, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Thierry Reding,
Jonathan Hunter
Cc: linux-arm-kernel, linux-kernel, devicetree, linux-tegra,
Diogo Ivo
This series migrates PSCI and MAX77620 poweroff handling to the
sys-off framework and fixes shutdown on the Pixel C (Smaug).
The first two patches replace legacy pm_power_off usage in the PSCI
and MAX77620 drivers with sys-off handlers. Besides aligning both
drivers with the modern poweroff infrastructure, this removes the
global callback dependency and allows multiple handlers to coexist
with explicit priorities.
The remaining patches address shutdown on the Pixel C. Although the
platform exposes PSCI firmware, its SYSTEM_OFF implementation is not
functional:
__dead2 void tegra_system_off(void)
{
ERROR("Tegra System Off: operation not handled.\n");
panic();
}
Downstream kernels instead rely on the MAX77620 PMIC to perform the
shutdown sequence. To mirror that behavior upstream, register the
MAX77620 handler with higher priority than PSCI on Smaug systems and
mark the PMIC as the system power controller in device tree.
Patch overview:
1. firmware: psci: switch SYSTEM_OFF to sys-off handler API
2. mfd: max77620: convert poweroff support to sys-off API
3. mfd: max77620: override PSCI poweroff handler on Smaug
4. arm64: dts: tegra: smaug: mark MAX77620 as system power controller
Tested on a Pixel C, where poweroff now completes successfully
instead of hanging in PSCI firmware.
Signed-off-by: Diogo Ivo <diogo.ivo@tecnico.ulisboa.pt>
---
Diogo Ivo (4):
firmware: psci: switch SYSTEM_OFF to sys-off handler API
mfd: max77620: convert poweroff support to sys-off API
mfd: max77620: override PSCI poweroff handler on Pixel C
arm64: tegra: smaug: mark MAX77620 as system power controller
arch/arm64/boot/dts/nvidia/tegra210-smaug.dts | 2 ++
drivers/firmware/psci/psci.c | 8 +++---
drivers/mfd/max77620.c | 36 ++++++++++++++++++++-------
3 files changed, 34 insertions(+), 12 deletions(-)
---
base-commit: f327c8ef8a6905ee97b62e42d808603c5b759418
change-id: 20260514-smaug-poweroff-9626c5501bbc
Best regards,
--
Diogo Ivo <diogo.ivo@tecnico.ulisboa.pt>
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 1/4] firmware: psci: switch SYSTEM_OFF to sys-off handler API
2026-05-14 14:47 [PATCH 0/4] power: sys-off: fix Pixel C shutdown via MAX77620 Diogo Ivo
@ 2026-05-14 14:47 ` Diogo Ivo
2026-05-14 19:48 ` sashiko-bot
2026-05-14 14:47 ` [PATCH 2/4] mfd: max77620: convert poweroff support to sys-off API Diogo Ivo
` (2 subsequent siblings)
3 siblings, 1 reply; 7+ messages in thread
From: Diogo Ivo @ 2026-05-14 14:47 UTC (permalink / raw)
To: Mark Rutland, Lorenzo Pieralisi, Lee Jones, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Thierry Reding,
Jonathan Hunter
Cc: linux-arm-kernel, linux-kernel, devicetree, linux-tegra,
Diogo Ivo
Replace the legacy pm_power_off hook with the generic sys-off
handler infrastructure.
Convert psci_sys_poweroff() to the sys-off callback prototype and
register it through register_sys_off_handler() with firmware
priority. This removes the direct dependency on pm_power_off and
drops the now-unused <linux/pm.h> include.
This aligns the PSCI poweroff path with the modern system-off
framework used by other firmware and platform drivers.
Signed-off-by: Diogo Ivo <diogo.ivo@tecnico.ulisboa.pt>
---
drivers/firmware/psci/psci.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/drivers/firmware/psci/psci.c b/drivers/firmware/psci/psci.c
index 38ca190d4a22..d6e9721d11e5 100644
--- a/drivers/firmware/psci/psci.c
+++ b/drivers/firmware/psci/psci.c
@@ -13,7 +13,6 @@
#include <linux/errno.h>
#include <linux/linkage.h>
#include <linux/of.h>
-#include <linux/pm.h>
#include <linux/printk.h>
#include <linux/psci.h>
#include <linux/reboot.h>
@@ -329,9 +328,11 @@ static struct notifier_block psci_sys_reset_nb = {
.priority = 129,
};
-static void psci_sys_poweroff(void)
+static int psci_sys_poweroff(struct sys_off_data *data)
{
invoke_psci_fn(PSCI_0_2_FN_SYSTEM_OFF, 0, 0, 0);
+
+ return NOTIFY_DONE;
}
#ifdef CONFIG_HIBERNATION
@@ -671,7 +672,8 @@ static void __init psci_0_2_set_functions(void)
register_restart_handler(&psci_sys_reset_nb);
- pm_power_off = psci_sys_poweroff;
+ register_sys_off_handler(SYS_OFF_MODE_POWER_OFF, SYS_OFF_PRIO_FIRMWARE,
+ psci_sys_poweroff, NULL);
}
/*
--
2.54.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 2/4] mfd: max77620: convert poweroff support to sys-off API
2026-05-14 14:47 [PATCH 0/4] power: sys-off: fix Pixel C shutdown via MAX77620 Diogo Ivo
2026-05-14 14:47 ` [PATCH 1/4] firmware: psci: switch SYSTEM_OFF to sys-off handler API Diogo Ivo
@ 2026-05-14 14:47 ` Diogo Ivo
2026-05-14 20:05 ` sashiko-bot
2026-05-14 14:47 ` [PATCH 3/4] mfd: max77620: override PSCI poweroff handler on Pixel C Diogo Ivo
2026-05-14 14:47 ` [PATCH 4/4] arm64: tegra: smaug: mark MAX77620 as system power controller Diogo Ivo
3 siblings, 1 reply; 7+ messages in thread
From: Diogo Ivo @ 2026-05-14 14:47 UTC (permalink / raw)
To: Mark Rutland, Lorenzo Pieralisi, Lee Jones, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Thierry Reding,
Jonathan Hunter
Cc: linux-arm-kernel, linux-kernel, devicetree, linux-tegra,
Diogo Ivo
Convert max77620_pm_power_off() to the sys-off callback prototype and
register it with the sys-off API when the device tree marks the PMIC as
a system power controller. This also removes the global max77620_scratch
pointer by passing the chip instance through the callback data.
This modernizes the driver's poweroff handling and aligns it with
the kernel sys-off infrastructure.
Signed-off-by: Diogo Ivo <diogo.ivo@tecnico.ulisboa.pt>
---
drivers/mfd/max77620.c | 22 +++++++++++++---------
1 file changed, 13 insertions(+), 9 deletions(-)
diff --git a/drivers/mfd/max77620.c b/drivers/mfd/max77620.c
index 3af2974b3023..c4f89a9681f3 100644
--- a/drivers/mfd/max77620.c
+++ b/drivers/mfd/max77620.c
@@ -31,11 +31,10 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/reboot.h>
#include <linux/regmap.h>
#include <linux/slab.h>
-static struct max77620_chip *max77620_scratch;
-
static const struct resource gpio_resources[] = {
DEFINE_RES_IRQ(MAX77620_IRQ_TOP_GPIO),
};
@@ -484,13 +483,15 @@ static int max77620_read_es_version(struct max77620_chip *chip)
return ret;
}
-static void max77620_pm_power_off(void)
+static int max77620_pm_power_off(struct sys_off_data *data)
{
- struct max77620_chip *chip = max77620_scratch;
+ struct max77620_chip *chip = data->cb_data;
regmap_update_bits(chip->rmap, MAX77620_REG_ONOFFCNFG1,
MAX77620_ONOFFCNFG1_SFT_RST,
MAX77620_ONOFFCNFG1_SFT_RST);
+
+ return NOTIFY_DONE;
}
static int max77620_probe(struct i2c_client *client)
@@ -501,7 +502,6 @@ static int max77620_probe(struct i2c_client *client)
struct regmap_irq_chip *chip_desc;
const struct mfd_cell *mfd_cells;
int n_mfd_cells;
- bool pm_off;
int ret;
chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
@@ -573,10 +573,14 @@ static int max77620_probe(struct i2c_client *client)
return ret;
}
- pm_off = of_device_is_system_power_controller(client->dev.of_node);
- if (pm_off && !pm_power_off) {
- max77620_scratch = chip;
- pm_power_off = max77620_pm_power_off;
+ if (of_device_is_system_power_controller(client->dev.of_node)) {
+ ret = devm_register_sys_off_handler(&client->dev,
+ SYS_OFF_MODE_POWER_OFF,
+ SYS_OFF_PRIO_DEFAULT,
+ max77620_pm_power_off, chip);
+ if (ret)
+ return dev_err_probe(&client->dev, ret,
+ "failed to register power-off handler\n");
}
return 0;
--
2.54.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 3/4] mfd: max77620: override PSCI poweroff handler on Pixel C
2026-05-14 14:47 [PATCH 0/4] power: sys-off: fix Pixel C shutdown via MAX77620 Diogo Ivo
2026-05-14 14:47 ` [PATCH 1/4] firmware: psci: switch SYSTEM_OFF to sys-off handler API Diogo Ivo
2026-05-14 14:47 ` [PATCH 2/4] mfd: max77620: convert poweroff support to sys-off API Diogo Ivo
@ 2026-05-14 14:47 ` Diogo Ivo
2026-05-14 14:47 ` [PATCH 4/4] arm64: tegra: smaug: mark MAX77620 as system power controller Diogo Ivo
3 siblings, 0 replies; 7+ messages in thread
From: Diogo Ivo @ 2026-05-14 14:47 UTC (permalink / raw)
To: Mark Rutland, Lorenzo Pieralisi, Lee Jones, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Thierry Reding,
Jonathan Hunter
Cc: linux-arm-kernel, linux-kernel, devicetree, linux-tegra,
Diogo Ivo
On Pixel C, shutdown must be handled by the MAX77620 PMIC rather
than the PSCI SYSTEM_OFF call, whose firmware implementation is:
__dead2 void tegra_system_off(void)
{
ERROR("Tegra System Off: operation not handled.\n");
panic();
}
Raise the MAX77620 sys-off handler priority above SYS_OFF_PRIO_FIRMWARE
on Pixel C systems so it takes precedence over the PSCI poweroff handler.
Other systems continue to use the default sys-off priority.
Signed-off-by: Diogo Ivo <diogo.ivo@tecnico.ulisboa.pt>
---
drivers/mfd/max77620.c | 18 ++++++++++++++++--
1 file changed, 16 insertions(+), 2 deletions(-)
diff --git a/drivers/mfd/max77620.c b/drivers/mfd/max77620.c
index c4f89a9681f3..3b1f3a2f3566 100644
--- a/drivers/mfd/max77620.c
+++ b/drivers/mfd/max77620.c
@@ -494,6 +494,18 @@ static int max77620_pm_power_off(struct sys_off_data *data)
return NOTIFY_DONE;
}
+static int max77620_power_off_priority(void)
+{
+ /*
+ * For Smaug we need to override the PSCI poweroff handler
+ * which is registered at priority SYS_OFF_PRIO_FIRMWARE.
+ */
+ if (of_machine_is_compatible("google,smaug"))
+ return SYS_OFF_PRIO_FIRMWARE + 1;
+
+ return SYS_OFF_PRIO_DEFAULT;
+}
+
static int max77620_probe(struct i2c_client *client)
{
const struct i2c_device_id *id = i2c_client_get_device_id(client);
@@ -502,6 +514,7 @@ static int max77620_probe(struct i2c_client *client)
struct regmap_irq_chip *chip_desc;
const struct mfd_cell *mfd_cells;
int n_mfd_cells;
+ int priority;
int ret;
chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
@@ -574,10 +587,11 @@ static int max77620_probe(struct i2c_client *client)
}
if (of_device_is_system_power_controller(client->dev.of_node)) {
+ priority = max77620_power_off_priority();
ret = devm_register_sys_off_handler(&client->dev,
SYS_OFF_MODE_POWER_OFF,
- SYS_OFF_PRIO_DEFAULT,
- max77620_pm_power_off, chip);
+ priority, max77620_pm_power_off,
+ chip);
if (ret)
return dev_err_probe(&client->dev, ret,
"failed to register power-off handler\n");
--
2.54.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 4/4] arm64: tegra: smaug: mark MAX77620 as system power controller
2026-05-14 14:47 [PATCH 0/4] power: sys-off: fix Pixel C shutdown via MAX77620 Diogo Ivo
` (2 preceding siblings ...)
2026-05-14 14:47 ` [PATCH 3/4] mfd: max77620: override PSCI poweroff handler on Pixel C Diogo Ivo
@ 2026-05-14 14:47 ` Diogo Ivo
3 siblings, 0 replies; 7+ messages in thread
From: Diogo Ivo @ 2026-05-14 14:47 UTC (permalink / raw)
To: Mark Rutland, Lorenzo Pieralisi, Lee Jones, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Thierry Reding,
Jonathan Hunter
Cc: linux-arm-kernel, linux-kernel, devicetree, linux-tegra,
Diogo Ivo
Register the MAX77620 PMIC as the system power controller on
Pixel C so the driver can install its sys-off handler.
This allows the PMIC poweroff sequence to override the non-working
PSCI SYSTEM_OFF implementation on this platform.
Signed-off-by: Diogo Ivo <diogo.ivo@tecnico.ulisboa.pt>
---
arch/arm64/boot/dts/nvidia/tegra210-smaug.dts | 2 ++
1 file changed, 2 insertions(+)
diff --git a/arch/arm64/boot/dts/nvidia/tegra210-smaug.dts b/arch/arm64/boot/dts/nvidia/tegra210-smaug.dts
index f0b8c2c80aa5..1791b47f0a73 100644
--- a/arch/arm64/boot/dts/nvidia/tegra210-smaug.dts
+++ b/arch/arm64/boot/dts/nvidia/tegra210-smaug.dts
@@ -1467,6 +1467,8 @@ pmic: pmic@3c {
gpio-controller;
#gpio-cells = <2>;
+ system-power-controller;
+
pinctrl-names = "default";
pinctrl-0 = <&max77620_default>;
--
2.54.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH 1/4] firmware: psci: switch SYSTEM_OFF to sys-off handler API
2026-05-14 14:47 ` [PATCH 1/4] firmware: psci: switch SYSTEM_OFF to sys-off handler API Diogo Ivo
@ 2026-05-14 19:48 ` sashiko-bot
0 siblings, 0 replies; 7+ messages in thread
From: sashiko-bot @ 2026-05-14 19:48 UTC (permalink / raw)
To: Diogo Ivo; +Cc: devicetree, robh, conor+dt, krzk+dt
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] Premature memory allocation during early boot causing kernel panic
--
commit ef783d7ffab1683b74c28865d23fcb00064437a6
Author: Diogo Ivo <diogo.ivo@tecnico.ulisboa.pt>
firmware: psci: switch SYSTEM_OFF to sys-off handler API
This commit replaces the legacy pm_power_off hook with the generic sys-off
handler infrastructure. It converts psci_sys_poweroff to the sys-off callback
prototype and registers it through register_sys_off_handler.
> diff --git a/drivers/firmware/psci/psci.c b/drivers/firmware/psci/psci.c
> index 38ca190d4a22d..d6e9721d11e54 100644
> --- a/drivers/firmware/psci/psci.c
> +++ b/drivers/firmware/psci/psci.c
[ ... ]
> @@ -671,7 +672,8 @@ static void __init psci_0_2_set_functions(void)
>
> register_restart_handler(&psci_sys_reset_nb);
>
> - pm_power_off = psci_sys_poweroff;
> + register_sys_off_handler(SYS_OFF_MODE_POWER_OFF, SYS_OFF_PRIO_FIRMWARE,
> + psci_sys_poweroff, NULL);
> }
Can this cause a regression during early boot?
The function psci_0_2_set_functions() is called extremely early via
psci_dt_init() or psci_acpi_init() from setup_arch(). This happens before
mm_core_init() brings up the slab memory allocator.
Because the priority passed is SYS_OFF_PRIO_FIRMWARE, alloc_sys_off_handler()
falls back to dynamically allocating the handler using kzalloc().
Could calling kzalloc() before the slab allocator is initialized result in a
kernel panic?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260514-smaug-poweroff-v1-0-30f9a4688966@tecnico.ulisboa.pt?part=1
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 2/4] mfd: max77620: convert poweroff support to sys-off API
2026-05-14 14:47 ` [PATCH 2/4] mfd: max77620: convert poweroff support to sys-off API Diogo Ivo
@ 2026-05-14 20:05 ` sashiko-bot
0 siblings, 0 replies; 7+ messages in thread
From: sashiko-bot @ 2026-05-14 20:05 UTC (permalink / raw)
To: Diogo Ivo; +Cc: conor+dt, devicetree, robh, krzk+dt
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] max77620_pm_power_off() acquires a mutex inside an atomic context (RCU read-side critical section and disabled IRQs), leading to a potential deadlock during system power-off.
--
commit b3bd2ca1c0c28ed17c99ae76d84c114260a5a844
Author: Diogo Ivo <diogo.ivo@tecnico.ulisboa.pt>
mfd: max77620: convert poweroff support to sys-off API
This commit converts max77620_pm_power_off() to the sys-off callback prototype
and registers it with the sys-off API when the device tree marks the PMIC as
a system power controller. It also removes the global max77620_scratch pointer
by passing the chip instance through the callback data.
> diff --git a/drivers/mfd/max77620.c b/drivers/mfd/max77620.c
> --- a/drivers/mfd/max77620.c
> +++ b/drivers/mfd/max77620.c
[ ... ]
> @@ -484,13 +483,15 @@ static int max77620_read_es_version(struct max77620_chip *chip)
> return ret;
> }
>
> -static void max77620_pm_power_off(void)
> +static int max77620_pm_power_off(struct sys_off_data *data)
> {
> - struct max77620_chip *chip = max77620_scratch;
> + struct max77620_chip *chip = data->cb_data;
>
> regmap_update_bits(chip->rmap, MAX77620_REG_ONOFFCNFG1,
> MAX77620_ONOFFCNFG1_SFT_RST,
> MAX77620_ONOFFCNFG1_SFT_RST);
> +
> + return NOTIFY_DONE;
> }
[ ... ]
> @@ -573,10 +573,14 @@ static int max77620_probe(struct i2c_client *client)
> return ret;
> }
>
> - pm_off = of_device_is_system_power_controller(client->dev.of_node);
> - if (pm_off && !pm_power_off) {
> - max77620_scratch = chip;
> - pm_power_off = max77620_pm_power_off;
> + if (of_device_is_system_power_controller(client->dev.of_node)) {
> + ret = devm_register_sys_off_handler(&client->dev,
> + SYS_OFF_MODE_POWER_OFF,
Does this code risk deadlocking during system power-off?
Handlers registered with SYS_OFF_MODE_POWER_OFF execute via an atomic
notifier call chain inside do_kernel_power_off() holding rcu_read_lock(),
and with local IRQs completely disabled.
However, the max77620_pm_power_off() callback invokes regmap_update_bits()
on an I2C regmap, which relies on a standard mutex.
If another CPU held this PMIC regmap mutex when smp_send_stop() was issued,
attempting to acquire it here will hang the power-off sequence indefinitely.
Would it be safer to register this handler using
SYS_OFF_MODE_POWER_OFF_PREPARE instead? That mode uses a blocking notifier
call chain and executes before CPUs are stopped and IRQs are disabled.
> + SYS_OFF_PRIO_DEFAULT,
> + max77620_pm_power_off, chip);
> + if (ret)
> + return dev_err_probe(&client->dev, ret,
> + "failed to register power-off handler\n");
> }
>
> return 0;
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260514-smaug-poweroff-v1-0-30f9a4688966@tecnico.ulisboa.pt?part=2
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-05-14 20:05 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-14 14:47 [PATCH 0/4] power: sys-off: fix Pixel C shutdown via MAX77620 Diogo Ivo
2026-05-14 14:47 ` [PATCH 1/4] firmware: psci: switch SYSTEM_OFF to sys-off handler API Diogo Ivo
2026-05-14 19:48 ` sashiko-bot
2026-05-14 14:47 ` [PATCH 2/4] mfd: max77620: convert poweroff support to sys-off API Diogo Ivo
2026-05-14 20:05 ` sashiko-bot
2026-05-14 14:47 ` [PATCH 3/4] mfd: max77620: override PSCI poweroff handler on Pixel C Diogo Ivo
2026-05-14 14:47 ` [PATCH 4/4] arm64: tegra: smaug: mark MAX77620 as system power controller Diogo Ivo
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox