From patchwork Wed Jan 24 12:21:57 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Oleksij Rempel X-Patchwork-Id: 13529155 Received: from metis.whiteo.stw.pengutronix.de (metis.whiteo.stw.pengutronix.de [185.203.201.7]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 657A2634F8 for ; Wed, 24 Jan 2024 12:22:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.203.201.7 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706098950; cv=none; b=PO0XTp0GIp7sgvSwtjr/Kwq2+MSkYFC87IlAJWHKGbTz++oBbPAj7IYDn72TZXFqEa1oClV7SdirUVm5tp0rg6z1jLk55D7JnIxWeZHATjUY+3KM5IC95xcvER5IsHmL1ufICxNan/PLHGh9fLBvulZkL9LnbNecXngtx+sqr3A= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706098950; c=relaxed/simple; bh=qJyZABOkVgOrJuobub1GO0uw86ox/Ky9FOo5Kw77m4E=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=FsVEYxBm+7i2Abx5m3pZsevu33qTRuYitOzddTP9eRqacP25FK95Ac/8SuVNRslNH0t1RiOrcaCCobcPl7aXWhBGJ4bjAQnOANuW0hVivij96VHWenVWLzlJKsgr9TovoWYjUuU7t/vu1Xwzf9T7AIOjY8Epz/IpYOrjcnif6RI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=pengutronix.de; spf=pass smtp.mailfrom=pengutronix.de; arc=none smtp.client-ip=185.203.201.7 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=pengutronix.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pengutronix.de Received: from drehscheibe.grey.stw.pengutronix.de ([2a0a:edc0:0:c01:1d::a2]) by metis.whiteo.stw.pengutronix.de with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1rScGd-0007o5-1B; Wed, 24 Jan 2024 13:22:07 +0100 Received: from [2a0a:edc0:0:1101:1d::ac] (helo=dude04.red.stw.pengutronix.de) by drehscheibe.grey.stw.pengutronix.de with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1rScGb-0023Zb-Ux; Wed, 24 Jan 2024 13:22:05 +0100 Received: from ore by dude04.red.stw.pengutronix.de with local (Exim 4.96) (envelope-from ) id 1rScGb-00340u-2t; Wed, 24 Jan 2024 13:22:05 +0100 From: Oleksij Rempel To: Sebastian Reichel , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Srinivas Kandagatla Cc: Oleksij Rempel , kernel@pengutronix.de, linux-kernel@vger.kernel.org, Liam Girdwood , Mark Brown , "Rafael J. Wysocki" , Daniel Lezcano , Zhang Rui , Lukasz Luba , linux-pm@vger.kernel.org, devicetree@vger.kernel.org, =?utf-8?q?S=C3=B8ren_Andersen?= Subject: [PATCH v2 1/8] power: Extend power_on_reason.h for upcoming PSCRR framework Date: Wed, 24 Jan 2024 13:21:57 +0100 Message-Id: <20240124122204.730370-2-o.rempel@pengutronix.de> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20240124122204.730370-1-o.rempel@pengutronix.de> References: <20240124122204.730370-1-o.rempel@pengutronix.de> Precedence: bulk X-Mailing-List: linux-pm@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-SA-Exim-Connect-IP: 2a0a:edc0:0:c01:1d::a2 X-SA-Exim-Mail-From: ore@pengutronix.de X-SA-Exim-Scanned: No (on metis.whiteo.stw.pengutronix.de); SAEximRunCond expanded to false X-PTX-Original-Recipient: linux-pm@vger.kernel.org Prepare for the introduction of the Power State Change Reason Recorder (PSCRR) framework by expanding the power_on_reason.h header. This extension includes new power-on reasons: - POWER_ON_REASON_OVER_CURRENT for over-current conditions. - POWER_ON_REASON_REGULATOR_FAILURE for regulator failures. - POWER_ON_REASON_OVERTEMPERATURE for over temperature situations. Signed-off-by: Oleksij Rempel --- include/linux/power/power_on_reason.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/linux/power/power_on_reason.h b/include/linux/power/power_on_reason.h index 95a1ec0c403c..f2446cece277 100644 --- a/include/linux/power/power_on_reason.h +++ b/include/linux/power/power_on_reason.h @@ -15,5 +15,8 @@ #define POWER_ON_REASON_XTAL_FAIL "crystal oscillator failure" #define POWER_ON_REASON_BROWN_OUT "brown-out reset" #define POWER_ON_REASON_UNKNOWN "unknown reason" +#define POWER_ON_REASON_OVER_CURRENT "over current" +#define POWER_ON_REASON_REGULATOR_FAILURE "regulator failure" +#define POWER_ON_REASON_OVERTEMPERATURE "overtemperature" #endif /* POWER_ON_REASON_H */ From patchwork Wed Jan 24 12:21:58 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Oleksij Rempel X-Patchwork-Id: 13529162 Received: from metis.whiteo.stw.pengutronix.de (metis.whiteo.stw.pengutronix.de [185.203.201.7]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6F27F63502 for ; Wed, 24 Jan 2024 12:22:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.203.201.7 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706098951; cv=none; b=NSCjVTIZ9WMq3rHZDnE4erP6sR/s2flwjJuepZ7ChY5Tmf8Nqxjw/iaLMLaYw8JB+hmqTf1M4jWbYizOAoN1ZwsNUXgvdY21fJH07g0GA6scP2FWLEazhCChEFAJScS0cY9UckbvBFAr8cpi1IDEeiTgLaMutmb3AAMm8OexPeg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706098951; c=relaxed/simple; bh=IQtFllAeAbEnjjWov46KcbIiLiSA2S5/+KtiKXOriws=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=RYkh42d6h1cWm6JsLKLdqXu/pIrgKGEIcgHlH+8DE2lqU/RMNgaJ5NcDaypV7HHpM3CuBY0FbAoAK+Xzpb+wJ6qGlCHPv0DT0Z/42l85W114xnOcqpBDD7WcrGZsQmB2rDSV7jF3cYXP0DMnyCoRJByeOOrrcE1NcXHmI7CHKMY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=pengutronix.de; spf=pass smtp.mailfrom=pengutronix.de; arc=none smtp.client-ip=185.203.201.7 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=pengutronix.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pengutronix.de Received: from drehscheibe.grey.stw.pengutronix.de ([2a0a:edc0:0:c01:1d::a2]) by metis.whiteo.stw.pengutronix.de with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1rScGd-0007o6-1B; Wed, 24 Jan 2024 13:22:07 +0100 Received: from [2a0a:edc0:0:1101:1d::ac] (helo=dude04.red.stw.pengutronix.de) by drehscheibe.grey.stw.pengutronix.de with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1rScGb-0023Zc-Vt; Wed, 24 Jan 2024 13:22:05 +0100 Received: from ore by dude04.red.stw.pengutronix.de with local (Exim 4.96) (envelope-from ) id 1rScGb-003414-2x; Wed, 24 Jan 2024 13:22:05 +0100 From: Oleksij Rempel To: Sebastian Reichel , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Srinivas Kandagatla Cc: Oleksij Rempel , kernel@pengutronix.de, linux-kernel@vger.kernel.org, Liam Girdwood , Mark Brown , "Rafael J. Wysocki" , Daniel Lezcano , Zhang Rui , Lukasz Luba , linux-pm@vger.kernel.org, devicetree@vger.kernel.org, =?utf-8?q?S=C3=B8ren_Andersen?= Subject: [PATCH v2 2/8] dt-bindings: power: reset: add generic PSCRR binding trackers Date: Wed, 24 Jan 2024 13:21:58 +0100 Message-Id: <20240124122204.730370-3-o.rempel@pengutronix.de> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20240124122204.730370-1-o.rempel@pengutronix.de> References: <20240124122204.730370-1-o.rempel@pengutronix.de> Precedence: bulk X-Mailing-List: linux-pm@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-SA-Exim-Connect-IP: 2a0a:edc0:0:c01:1d::a2 X-SA-Exim-Mail-From: ore@pengutronix.de X-SA-Exim-Scanned: No (on metis.whiteo.stw.pengutronix.de); SAEximRunCond expanded to false X-PTX-Original-Recipient: linux-pm@vger.kernel.org Add binding for Power State Change Reason Recording (PSCRR) subsystem Signed-off-by: Oleksij Rempel --- .../bindings/power/reset/pscrr.yaml | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 Documentation/devicetree/bindings/power/reset/pscrr.yaml diff --git a/Documentation/devicetree/bindings/power/reset/pscrr.yaml b/Documentation/devicetree/bindings/power/reset/pscrr.yaml new file mode 100644 index 000000000000..c8738b4930fe --- /dev/null +++ b/Documentation/devicetree/bindings/power/reset/pscrr.yaml @@ -0,0 +1,44 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/power/reset/pscrr.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Power State Change Reason (PSCR) + +maintainers: + - Oleksij Rempel + +description: Binding for devices responsible to store reasons for power state + changes such as reboot and power-off. Reasons like unknown, under voltage, + and over temperature are captured for diagnostic or automatic recovery + purposes. + +properties: + pscr-under-voltage: + $ref: /schemas/types.yaml#/definitions/uint32 + description: | + Value to indicate an under-voltage condition of a system critical + regulator as the reason for the power state change. + + pscr-over-current: + $ref: /schemas/types.yaml#/definitions/uint32 + description: | + Value to indicate an over-current condition of a system ctitical regulator + as the reason for the power state change. + + pscr-regulator-failure: + $ref: /schemas/types.yaml#/definitions/uint32 + description: | + Value to indicate an unknown, system ctitical regulator related failure + as the reason for the power state change. + + pscr-over-temperature: + $ref: /schemas/types.yaml#/definitions/uint32 + description: | + Value to indicate a system critical over-temperature condition as the + reason for the power state change. + +additionalProperties: true + +... From patchwork Wed Jan 24 12:21:59 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Oleksij Rempel X-Patchwork-Id: 13529163 Received: from metis.whiteo.stw.pengutronix.de (metis.whiteo.stw.pengutronix.de [185.203.201.7]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id EAABF64AA8 for ; Wed, 24 Jan 2024 12:22:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.203.201.7 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706098952; cv=none; b=OeHzt5Ywh9kdaWtZ/A4b7aUJmWYWEyUEbDWh7JSKrrsgxhhzzXJSQkLxPxg4/uGrHzpF8IXLzaApx/SuJV4rRW/Uu7SeQG+CsFqdroGMxhEHv1GbJnS3ckczM9FFSvdBcXPzd3E1KHPi76X8W8j5RSbCTdOt2XcUjEBEBvUFXV4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706098952; c=relaxed/simple; bh=Q7CJ22s7cVnisV7JjfaOll6mFN9dCNJwXRW0hKY8Xlg=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=EDeAeErmdQwo4pgsaFEGkKIhLCsNzrJoSJ2Yz9DfmBgKhEZYoVY0att641nEd9GG0B+YH5nwZoZ8dzKIvukw2DFCugzizF8kDTBOWc4JhXmOpl0jRSXh2v9TbFJP9KAVnndnFlpK/dplJL63KCCBjzBEjVjdvyC72RY/q0ANfTo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=pengutronix.de; spf=pass smtp.mailfrom=pengutronix.de; arc=none smtp.client-ip=185.203.201.7 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=pengutronix.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pengutronix.de Received: from drehscheibe.grey.stw.pengutronix.de ([2a0a:edc0:0:c01:1d::a2]) by metis.whiteo.stw.pengutronix.de with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1rScGd-0007o7-1C; Wed, 24 Jan 2024 13:22:07 +0100 Received: from [2a0a:edc0:0:1101:1d::ac] (helo=dude04.red.stw.pengutronix.de) by drehscheibe.grey.stw.pengutronix.de with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1rScGc-0023Zd-0H; Wed, 24 Jan 2024 13:22:06 +0100 Received: from ore by dude04.red.stw.pengutronix.de with local (Exim 4.96) (envelope-from ) id 1rScGb-00341E-30; Wed, 24 Jan 2024 13:22:05 +0100 From: Oleksij Rempel To: Sebastian Reichel , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Srinivas Kandagatla Cc: Oleksij Rempel , kernel@pengutronix.de, linux-kernel@vger.kernel.org, Liam Girdwood , Mark Brown , "Rafael J. Wysocki" , Daniel Lezcano , Zhang Rui , Lukasz Luba , linux-pm@vger.kernel.org, devicetree@vger.kernel.org, =?utf-8?q?S=C3=B8ren_Andersen?= Subject: [PATCH v2 3/8] power: reset: Introduce PSCR Recording Framework for Non-Volatile Storage Date: Wed, 24 Jan 2024 13:21:59 +0100 Message-Id: <20240124122204.730370-4-o.rempel@pengutronix.de> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20240124122204.730370-1-o.rempel@pengutronix.de> References: <20240124122204.730370-1-o.rempel@pengutronix.de> Precedence: bulk X-Mailing-List: linux-pm@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-SA-Exim-Connect-IP: 2a0a:edc0:0:c01:1d::a2 X-SA-Exim-Mail-From: ore@pengutronix.de X-SA-Exim-Scanned: No (on metis.whiteo.stw.pengutronix.de); SAEximRunCond expanded to false X-PTX-Original-Recipient: linux-pm@vger.kernel.org This commit introduces the Power State Change Reasons Recording (PSCRR) framework into the kernel. The framework is vital for systems where PMICs or watchdogs cannot provide information on power state changes. It stores reasons for system shutdowns and reboots, like under-voltage or software-triggered events, in non-volatile hardware storage. This approach is essential for postmortem analysis in scenarios where traditional storage methods (block devices, RAM) are not feasible. The framework aids bootloaders and early-stage system components in recovery decision-making, although it does not cover resets caused by hardware issues like system freezes or watchdog timeouts. Signed-off-by: Oleksij Rempel --- drivers/power/reset/Kconfig | 19 ++ drivers/power/reset/Makefile | 1 + drivers/power/reset/pscrr.c | 353 +++++++++++++++++++++++++++++++++++ include/linux/pscrr.h | 73 ++++++++ 4 files changed, 446 insertions(+) create mode 100644 drivers/power/reset/pscrr.c create mode 100644 include/linux/pscrr.h diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig index fece990af4a7..c6ce7e647048 100644 --- a/drivers/power/reset/Kconfig +++ b/drivers/power/reset/Kconfig @@ -305,3 +305,22 @@ config POWER_MLXBF This driver supports reset or low power mode handling for Mellanox BlueField. endif + +menuconfig PSCRR + bool "Power State Change Reasons (PSCR) Recording Framework" + help + Enables the Power State Change Reasons (PSCR) Recording framework. + + This framework is designed to store reasons for system shutdowns or + reboots, like under voltage or software-triggered events, in non-volatile + hardware storage. It is particularly useful for postmortem analysis, where + traditional storage methods (like block devices or RAM) are not feasible + due to immediate power-down requirements or insufficient power to retain + data. + + This is useful for bootloaders or other early-stage system components to + make recovery decisions based on the last known system state. Note that it + does not cover hardware-induced resets like system freezes or watchdog + timeouts. + + If unsure, say N. diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile index a95d1bd275d1..e618c34a30f9 100644 --- a/drivers/power/reset/Makefile +++ b/drivers/power/reset/Makefile @@ -31,6 +31,7 @@ obj-$(CONFIG_POWER_RESET_KEYSTONE) += keystone-reset.o obj-$(CONFIG_POWER_RESET_SYSCON) += syscon-reboot.o obj-$(CONFIG_POWER_RESET_SYSCON_POWEROFF) += syscon-poweroff.o obj-$(CONFIG_POWER_RESET_RMOBILE) += rmobile-reset.o +obj-$(CONFIG_PSCRR) += pscrr.o obj-$(CONFIG_REBOOT_MODE) += reboot-mode.o obj-$(CONFIG_SYSCON_REBOOT_MODE) += syscon-reboot-mode.o obj-$(CONFIG_POWER_RESET_SC27XX) += sc27xx-poweroff.o diff --git a/drivers/power/reset/pscrr.c b/drivers/power/reset/pscrr.c new file mode 100644 index 000000000000..651fc210878d --- /dev/null +++ b/drivers/power/reset/pscrr.c @@ -0,0 +1,353 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2016, Fuzhou Rockchip Electronics Co., Ltd +// Copyright (c) 2024 Pengutronix, Oleksij Rempel +/* + * Based on drivers/power/reset/reboot-mode.c + * Copyright (c) 2016, Fuzhou Rockchip Electronics Co., Ltd + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define PREFIX "pscr-" + +enum pscr system_pscr; + +/* + * struct pscr_to_magic_entry - Entry for mapping PSCR to magic values. + * + * This structure represents a single entry in a list that maps Power State + * Change Reason (PSCR) values to corresponding magic values. Each entry + * associates a specific PSCR with a unique magic value, facilitating easy + * translation between the two. + * + * @pscr: The PSCR value. + * @magic: The corresponding magic value. + * @list: List head for chaining multiple such entries. + */ +struct pscr_to_magic_entry { + enum pscr pscr; + u32 magic; + struct list_head list; +}; + +/* + * struct pscr_map - Maps device tree property names to PSCR values. + * + * @dt_prop_name: Device tree property name without the "pscr-" prefix. + * @pscr: The corresponding PSCR enum value for the given property name. + */ +struct pscr_map { + const char *dt_prop_name; + enum pscr pscr; +}; + +/* + * struct pscr_map - Maps shortened DT property names to PSCR values. + * + * This structure maps device tree property names, with the "pscr-" prefix + * omitted, to their corresponding Power State Change Reason (PSCR) values. + */ +struct pscr_map pscr_map_table[] = { + { "under-voltage", PSCR_UNDER_VOLTAGE }, + { "over-current", PSCR_OVER_CURRENT }, + { "regulator-failure", PSCR_REGULATOR_FAILURE }, + { "over-temperature", PSCR_OVERTEMPERATURE }, +}; + +/* + * pscr_find_from_dt_name - Finds the PSCR value for a given DT property name. + * + * @dt_prop_name: The device tree property name, without the "pscr-" prefix, to + * look up. + * Returns the corresponding PSCR value or -ENOENT if not found. + */ +static int find_pscr_by_string(const char *dt_prop_name) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(pscr_map_table); i++) { + if (!strcmp(dt_prop_name, pscr_map_table[i].dt_prop_name)) + return pscr_map_table[i].pscr; + } + + return -ENOENT; +} + +static enum pscr get_pscr_by_magic(struct pscrr_device *pscrr_dev, u32 magic) +{ + struct pscr_to_magic_entry *map_entry; + + list_for_each_entry(map_entry, &pscrr_dev->pscr_map_list, list) { + if (map_entry->magic == magic) + return map_entry->pscr; + } + + return 0; +} + +static u32 get_magic_by_pscr(struct pscrr_device *pscrr_dev, enum pscr pscr) +{ + struct pscr_to_magic_entry *map_entry; + + list_for_each_entry(map_entry, &pscrr_dev->pscr_map_list, list) { + if (map_entry->pscr == pscr) + return map_entry->magic; + } + + return 0; +} + +/** + * set_power_state_change_reason() - Set the system's power state change reason + * @pscr: The enum value representing the power state change reason + * + * This function sets the system's power state change reason based on the + * provided enum value. + */ +void set_power_state_change_reason(enum pscr pscr) +{ + system_pscr = pscr; +} +EXPORT_SYMBOL_GPL(set_power_state_change_reason); + +static const char *pscr_to_por_string(enum pscr pscr) +{ + switch (pscr) { + case PSCR_UNDER_VOLTAGE: + return POWER_ON_REASON_BROWN_OUT; + case PSCR_OVER_CURRENT: + return POWER_ON_REASON_OVER_CURRENT; + case PSCR_REGULATOR_FAILURE: + return POWER_ON_REASON_REGULATOR_FAILURE; + case PSCR_OVERTEMPERATURE: + return POWER_ON_REASON_OVERTEMPERATURE; + default: + } + + return POWER_ON_REASON_UNKNOWN; +} + +static ssize_t power_state_change_reason_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct pscrr_device *pscrr_dev = dev_get_drvdata(dev); + + return sprintf(buf, "%s\n", pscr_to_por_string(pscrr_dev->last_pscr)); +} +static DEVICE_ATTR_RO(power_state_change_reason); + +int handle_last_pscr(struct pscrr_device *pscrr_dev) +{ + u32 magic; + int ret; + + ret = pscrr_dev->read(pscrr_dev, &magic); + if (ret) + return ret; + + pscrr_dev->last_pscr = get_pscr_by_magic(pscrr_dev, magic); + + dev_info(pscrr_dev->dev, "Last recorded power state change reason: %s\n", + pscr_to_por_string(pscrr_dev->last_pscr)); + + ret = pscrr_dev->write(pscrr_dev, 0); + if (ret) + dev_err(pscrr_dev->dev, "Failed to clear power state change reason\n"); + + return ret; +} + +static int pscrr_notify(struct notifier_block *this, unsigned long x, void *c) +{ + struct pscrr_device *pscrr_dev = container_of(this, struct pscrr_device, + reboot_notifier); + u32 magic; + + magic = get_magic_by_pscr(pscrr_dev, system_pscr); + pscrr_dev->write(pscrr_dev, magic); + + return NOTIFY_DONE; +} + +/** + * pscrr_process_property() - Process a power state change reason property + * @pscrr_dev: Pointer to the pscrr_device structure + * @prop: Pointer to the property structure to be processed + * + * This function processes a device tree property representing a power state + * change reason and initializes the relevant data structures. + * + * Returns: 0 on success, -ENOMEM on memory allocation failure. + */ +static int pscrr_process_property(struct pscrr_device *pscrr_dev, + struct property *prop) +{ + struct pscr_to_magic_entry *map_entry; + struct device *dev = pscrr_dev->dev; + size_t len = strlen(PREFIX); + int ret; + + if (strncmp(prop->name, PREFIX, len)) + return 0; + + map_entry = devm_kzalloc(dev, sizeof(*map_entry), GFP_KERNEL); + if (!map_entry) + return -ENOMEM; + + ret = of_property_read_u32(dev->of_node, prop->name, &map_entry->magic); + if (ret) { + dev_err(dev, "Can't read magic number for %s: %pe\n", + prop->name, ERR_PTR(ret)); + devm_kfree(dev, map_entry); + return 0; + } + + if (!map_entry->magic) { + dev_err(dev, "%s with magic number == 0\n", prop->name); + devm_kfree(dev, map_entry); + return 0; + } + + map_entry->pscr = find_pscr_by_string(prop->name + len); + if (map_entry->pscr < 0) { + dev_err(dev, "unsupported reason name(%s): %pe\n", + prop->name, ERR_PTR(map_entry->pscr)); + devm_kfree(dev, map_entry); + return 0; + } + + if (map_entry->magic > pscrr_dev->max_magic_val) + pscrr_dev->max_magic_val = map_entry->magic; + + dev_dbg(dev, "registering reason = %s, magic = %d, pscr = %d\n", + prop->name, map_entry->magic, map_entry->pscr); + list_add_tail(&map_entry->list, &pscrr_dev->pscr_map_list); + + return 0; +} + +/* + * pscrr_register() - Register the pscr driver and initialize power state change + * reasons + * @pscrr_dev: Pointer to the pscrr_device structure + * + * This function registers the pscr driver and initializes power state change + * reasons based on device tree properties. + * + * Returns: 0 on success, -ENOMEM on memory allocation failure + */ +int pscrr_register(struct pscrr_device *pscrr_dev) +{ + struct device_node *np = pscrr_dev->dev->of_node; + struct property *prop; + int ret; + + INIT_LIST_HEAD(&pscrr_dev->pscr_map_list); + + for_each_property_of_node(np, prop) { + ret = pscrr_process_property(pscrr_dev, prop); + if (ret) + return ret; + } + + pscrr_dev->reboot_notifier.notifier_call = pscrr_notify; + register_reboot_notifier(&pscrr_dev->reboot_notifier); + + dev_set_drvdata(pscrr_dev->dev, pscrr_dev); + + ret = device_create_file(pscrr_dev->dev, &dev_attr_power_state_change_reason); + if (ret) + dev_err(pscrr_dev->dev, "Could not create sysfs entry\n"); + + return ret; +} +EXPORT_SYMBOL_GPL(pscrr_register); + +/* + * pscrr_unregister() - Unregister the pscr driver's reboot notifier + * @pscrr_dev: Pointer to the pscrr_device structure + * + * This function unregisters the reboot notifier for the pscr driver. + */ +void pscrr_unregister(struct pscrr_device *pscrr_dev) +{ + unregister_reboot_notifier(&pscrr_dev->reboot_notifier); +} +EXPORT_SYMBOL_GPL(pscrr_unregister); + +static void devm_pscrr_release(struct device *dev, void *res) +{ + pscrr_unregister(*(struct pscrr_device **)res); +} + +/** + * devm_pscrr_register - Register a device-managed PSCR driver + * @dev: Device to associate the PSCR driver with + * @pscrr_dev: Pointer to the PSCR driver to be registered + * + * Registers a Power State Change Reason (PSCR) driver as a device-managed + * resource. + * + * Returns: 0 on successful registration or a negative error code on failure. + */ +int devm_pscrr_register(struct device *dev, struct pscrr_device *pscrr_dev) +{ + struct pscrr_device **dr; + int rc; + + dr = devres_alloc(devm_pscrr_release, sizeof(*dr), GFP_KERNEL); + if (!dr) + return -ENOMEM; + + rc = pscrr_register(pscrr_dev); + if (rc) { + devres_free(dr); + return rc; + } + + *dr = pscrr_dev; + devres_add(dev, dr); + + return 0; +} +EXPORT_SYMBOL_GPL(devm_pscrr_register); + +static int devm_pscrr_match(struct device *dev, void *res, void *data) +{ + struct pscrr_device **p = res; + + if (WARN_ON(!p || !*p)) + return 0; + + return *p == data; +} + +/** + * devm_pscrr_unregister - Unregister a managed PSCR driver + * @dev: Device associated with the PSCR driver + * @pscrr_dev: Pointer to the PSCR driver to unregister + * + * Unregisters a device-managed Power State Change Reason (PSCR) driver. + * It handles the cleanup and release of resources associated with the PSCR + * driver which was previously registered. + */ +void devm_pscrr_unregister(struct device *dev, + struct pscrr_device *pscrr_dev) +{ + WARN_ON(devres_release(dev, + devm_pscrr_release, + devm_pscrr_match, pscrr_dev)); +} +EXPORT_SYMBOL_GPL(devm_pscrr_unregister); + +MODULE_AUTHOR("Oleksij Rempel "); +MODULE_DESCRIPTION("Power State Change Reason (PSCR) Recording framework"); +MODULE_LICENSE("GPL"); diff --git a/include/linux/pscrr.h b/include/linux/pscrr.h new file mode 100644 index 000000000000..2de9d9bc9aeb --- /dev/null +++ b/include/linux/pscrr.h @@ -0,0 +1,73 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __PSCRR_H__ +#define __PSCRR_H__ + +/* + * enum pscr - Enumerates reasons for power state changes. + * + * This enum lists the various reasons why a power state change might + * occur in a system. Each value represents a specific condition that + * could trigger a change in power state, such as shutdown or reboot. + * + * PSCR_UNKNOWN: Represents an unknown or unspecified reason. + * PSCR_UNDER_VOLTAGE: Indicates a power state change due to under-voltage. + * PSCR_OVER_CURRENT: Indicates a power state change due to over-current. + * PSCR_REGULATOR_FAILURE: Indicates a failure in a voltage regulator. + * PSCR_OVERTEMPERATURE: Indicates an over-temperature condition. + */ +enum pscr { + PSCR_UNKNOWN, + PSCR_UNDER_VOLTAGE, + PSCR_OVER_CURRENT, + PSCR_REGULATOR_FAILURE, + PSCR_OVERTEMPERATURE, +}; + +/* + * struct pscrr_device - Manages a Power State Change Reason Recorder device. + * + * This structure is utilized for controlling a device responsible for + * recording reasons for power state changes (PSCR). It includes mechanisms + * for mapping PSCR values to specific magic codes, storing these mappings, + * and recovering the last PSCR value from storage during system start-up. + * + * @dev: Device structure pointer. + * @pscr_map_list: List head for structs holding PSCR to magic code mappings. + * @write: Function pointer to write a new mapped PSCR value. + * @read: Function pointer to read the current mapped PSCR value. + * @reboot_notifier: Notifier block for recording PSCR at reboot. + * @max_magic_val: Maximum permissible magic code, used for verifying storage + * capacity and mapping integrity. + * @last_pscr: Last PSCR value recovered from storage at system start, + * representing the reason for the last system power cycle. + */ +struct pscrr_device { + struct device *dev; + struct list_head pscr_map_list; + int (*write)(struct pscrr_device *pscrr_dev, u32 magic); + int (*read)(struct pscrr_device *pscrr_dev, u32 *magic); + struct notifier_block reboot_notifier; + u32 max_magic_val; + enum pscr last_pscr; +}; + +int pscrr_register(struct pscrr_device *pscrr_dev); +void pscrr_unregister(struct pscrr_device *pscrr_dev); +int devm_pscrr_register(struct device *dev, + struct pscrr_device *pscrr_dev); +void devm_pscrr_unregister(struct device *dev, + struct pscrr_device *pscrr_dev); +int handle_last_pscr(struct pscrr_device *pscrr_dev); + +#if IS_ENABLED(CONFIG_PSCRR) + +void set_power_state_change_reason(enum pscr pscr); + +#else + +static inline void set_power_state_change_reason(enum pscr pscr) +{ +} +#endif + +#endif From patchwork Wed Jan 24 12:22:00 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Oleksij Rempel X-Patchwork-Id: 13529159 Received: from metis.whiteo.stw.pengutronix.de (metis.whiteo.stw.pengutronix.de [185.203.201.7]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6570F634F5 for ; Wed, 24 Jan 2024 12:22:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.203.201.7 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706098950; cv=none; b=PHWtJ+MNowufh4ObxLgORDhIMiwf1F7gieIjUa4p3M7A1qfsFBrKUIlBQqSU+ecnTJNghwHL2Be5IozxSYv903F3WzDIe0FXZj/pF5oOp7MmGxSzcpmnd42zamQIaRoVH2AVHKONcrBdrIZagwQcmwkurmEz7+Yhil2XqZGRoDg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706098950; c=relaxed/simple; bh=HHxbDfRuHjBw0BBMrvLJdWgyYMSpJ3v1+tlxqNpDDsA=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=hjHEkfo8jvjusqMbQE4ML0KDkUkPylKxHNh/8i3i+a7sc6Kill/ElWfv1GrSjQhwaCVUVFu3op8WgI+VfhzDTPbJFf4u/BkOZCJFtuYLnd7K2gwRFv+6YOVM4i8qfXkKtIDrWOEZD/BOjxX+Z0DGECg5GDgELqmdsdsmKrNUmNw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=pengutronix.de; spf=pass smtp.mailfrom=pengutronix.de; arc=none smtp.client-ip=185.203.201.7 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=pengutronix.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pengutronix.de Received: from drehscheibe.grey.stw.pengutronix.de ([2a0a:edc0:0:c01:1d::a2]) by metis.whiteo.stw.pengutronix.de with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1rScGd-0007o8-1C; Wed, 24 Jan 2024 13:22:07 +0100 Received: from [2a0a:edc0:0:1101:1d::ac] (helo=dude04.red.stw.pengutronix.de) by drehscheibe.grey.stw.pengutronix.de with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1rScGc-0023Ze-1P; Wed, 24 Jan 2024 13:22:06 +0100 Received: from ore by dude04.red.stw.pengutronix.de with local (Exim 4.96) (envelope-from ) id 1rScGb-00341O-34; Wed, 24 Jan 2024 13:22:05 +0100 From: Oleksij Rempel To: Sebastian Reichel , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Srinivas Kandagatla Cc: Oleksij Rempel , kernel@pengutronix.de, linux-kernel@vger.kernel.org, Liam Girdwood , Mark Brown , "Rafael J. Wysocki" , Daniel Lezcano , Zhang Rui , Lukasz Luba , linux-pm@vger.kernel.org, devicetree@vger.kernel.org, =?utf-8?q?S=C3=B8ren_Andersen?= Subject: [PATCH v2 4/8] dt-bindings: power: reset: add bindings for NVMEM hardware storing PSCR Data Date: Wed, 24 Jan 2024 13:22:00 +0100 Message-Id: <20240124122204.730370-5-o.rempel@pengutronix.de> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20240124122204.730370-1-o.rempel@pengutronix.de> References: <20240124122204.730370-1-o.rempel@pengutronix.de> Precedence: bulk X-Mailing-List: linux-pm@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-SA-Exim-Connect-IP: 2a0a:edc0:0:c01:1d::a2 X-SA-Exim-Mail-From: ore@pengutronix.de X-SA-Exim-Scanned: No (on metis.whiteo.stw.pengutronix.de); SAEximRunCond expanded to false X-PTX-Original-Recipient: linux-pm@vger.kernel.org Add device tree bindings that describe hardware implementations of Non-Volatile Memory (NVMEM) used for storing Power State Change Reasons (PSCR). Signed-off-by: Oleksij Rempel --- .../bindings/power/reset/pscrr-nvmem.yaml | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 Documentation/devicetree/bindings/power/reset/pscrr-nvmem.yaml diff --git a/Documentation/devicetree/bindings/power/reset/pscrr-nvmem.yaml b/Documentation/devicetree/bindings/power/reset/pscrr-nvmem.yaml new file mode 100644 index 000000000000..779920dea283 --- /dev/null +++ b/Documentation/devicetree/bindings/power/reset/pscrr-nvmem.yaml @@ -0,0 +1,53 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/power/reset/pscrr-nvmem.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Generic NVMEM Power State Change Reason Recorder + +maintainers: + - Oleksij Rempel + +description: This binding describes the Non-Volatile Memory (NVMEM) hardware + that stores Power State Change Reasons (PSCR). + +allOf: + - $ref: pscrr.yaml# + +properties: + compatible: + const: pscrr-nvmem + + nvmem-cells: + description: | + A phandle pointing to the nvmem-cells node where the power state change + reasons are stored. + maxItems: 1 + + nvmem-cell-names: + items: + - const: pscr + + pscr-under-voltage: true + pscr-over-current: true + pscr-regulator-failure: true + pscr-over-temperature: true + +required: + - compatible + - nvmem-cells + - nvmem-cell-names + +additionalProperties: false + +examples: + - | + power-state-change-reason { + compatible = "pscrr-nvmem"; + nvmem-cells = <&pscr_cell>; + nvmem-cell-names = "pscr"; + pscr-under-voltage = <1>; + pscr-over-temperature = <2>; + }; +... From patchwork Wed Jan 24 12:22:01 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Oleksij Rempel X-Patchwork-Id: 13529157 Received: from metis.whiteo.stw.pengutronix.de (metis.whiteo.stw.pengutronix.de [185.203.201.7]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6F51763503 for ; Wed, 24 Jan 2024 12:22:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.203.201.7 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706098950; cv=none; b=pQQd88fG9+xd5gVaHK3vYIfot0N7cVGWZdckc6PUEICQl8zpN3QYStHljnrXCJyCtHyyLd5bjM3Q61EvGqlIpibwbikUJvblSDHnDMrFBXCbDzrGpBA8DVhTfdxc8yPcLbfplyexhgX5rpkRfA6m8AtBLxauj2mbZQhopSk46yk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706098950; c=relaxed/simple; bh=viEuHOnCMvFs1FiV9peHFb17kutxKUU/HIZcjaimZ5g=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=o65p2TnrsaU0nsWcRBIu1XaF1zKT1pMRHWNpDqfFs6/siCd5B7gM1acYysef2YwtH1qlKUt41Z1KCkj1SRTtOBuOjV4CYaQO5/cI+rcFFLeBq65bZZKGazBUhpQZKJK1XsUIvXpM2Lk6bgQuC6JdKOsxpeUUm+gqXzu/1ly5iVs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=pengutronix.de; spf=pass smtp.mailfrom=pengutronix.de; arc=none smtp.client-ip=185.203.201.7 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=pengutronix.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pengutronix.de Received: from drehscheibe.grey.stw.pengutronix.de ([2a0a:edc0:0:c01:1d::a2]) by metis.whiteo.stw.pengutronix.de with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1rScGd-0007o9-1C; Wed, 24 Jan 2024 13:22:07 +0100 Received: from [2a0a:edc0:0:1101:1d::ac] (helo=dude04.red.stw.pengutronix.de) by drehscheibe.grey.stw.pengutronix.de with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1rScGc-0023Zg-2a; Wed, 24 Jan 2024 13:22:06 +0100 Received: from ore by dude04.red.stw.pengutronix.de with local (Exim 4.96) (envelope-from ) id 1rScGb-00341Y-37; Wed, 24 Jan 2024 13:22:05 +0100 From: Oleksij Rempel To: Sebastian Reichel , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Srinivas Kandagatla Cc: Oleksij Rempel , kernel@pengutronix.de, linux-kernel@vger.kernel.org, Liam Girdwood , Mark Brown , "Rafael J. Wysocki" , Daniel Lezcano , Zhang Rui , Lukasz Luba , linux-pm@vger.kernel.org, devicetree@vger.kernel.org, =?utf-8?q?S=C3=B8ren_Andersen?= Subject: [PATCH v2 5/8] nvmem: provide consumer access to cell size metrics Date: Wed, 24 Jan 2024 13:22:01 +0100 Message-Id: <20240124122204.730370-6-o.rempel@pengutronix.de> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20240124122204.730370-1-o.rempel@pengutronix.de> References: <20240124122204.730370-1-o.rempel@pengutronix.de> Precedence: bulk X-Mailing-List: linux-pm@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-SA-Exim-Connect-IP: 2a0a:edc0:0:c01:1d::a2 X-SA-Exim-Mail-From: ore@pengutronix.de X-SA-Exim-Scanned: No (on metis.whiteo.stw.pengutronix.de); SAEximRunCond expanded to false X-PTX-Original-Recipient: linux-pm@vger.kernel.org Add nvmem_cell_get_size() function to provide access to cell size metrics. In some cases we may get cell size less as consumer would expect it. So, nvmem_cell_write() would fail with incorrect buffer size. Signed-off-by: Oleksij Rempel --- drivers/nvmem/core.c | 25 +++++++++++++++++++++++++ include/linux/nvmem-consumer.h | 7 +++++++ 2 files changed, 32 insertions(+) diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index 980123fb4dde..a21e5649fcda 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -1790,6 +1790,31 @@ int nvmem_cell_write(struct nvmem_cell *cell, void *buf, size_t len) EXPORT_SYMBOL_GPL(nvmem_cell_write); +/** + * nvmem_cell_get_size() - Get the size of a given nvmem cell + * @cell: nvmem cell to be queried. + * @bytes: Pointer to store the size of the cell in bytes. Can be NULL. + * @bits: Pointer to store the size of the cell in bits. Can be NULL. + * + * Return: 0 on success or negative on failure. + */ +int nvmem_cell_get_size(struct nvmem_cell *cell, size_t *bytes, size_t *bits) +{ + struct nvmem_cell_entry *entry = cell->entry; + + if (!entry->nvmem) + return -EINVAL; + + if (bytes) + *bytes = entry->bytes; + + if (bits) + *bits = entry->nbits; + + return 0; +} +EXPORT_SYMBOL_GPL(nvmem_cell_get_size); + static int nvmem_cell_read_common(struct device *dev, const char *cell_id, void *val, size_t count) { diff --git a/include/linux/nvmem-consumer.h b/include/linux/nvmem-consumer.h index 34c0e58dfa26..bcb0e17e415d 100644 --- a/include/linux/nvmem-consumer.h +++ b/include/linux/nvmem-consumer.h @@ -56,6 +56,7 @@ void nvmem_cell_put(struct nvmem_cell *cell); void devm_nvmem_cell_put(struct device *dev, struct nvmem_cell *cell); void *nvmem_cell_read(struct nvmem_cell *cell, size_t *len); int nvmem_cell_write(struct nvmem_cell *cell, void *buf, size_t len); +int nvmem_cell_get_size(struct nvmem_cell *cell, size_t *bytes, size_t *bits); int nvmem_cell_read_u8(struct device *dev, const char *cell_id, u8 *val); int nvmem_cell_read_u16(struct device *dev, const char *cell_id, u16 *val); int nvmem_cell_read_u32(struct device *dev, const char *cell_id, u32 *val); @@ -128,6 +129,12 @@ static inline int nvmem_cell_write(struct nvmem_cell *cell, return -EOPNOTSUPP; } +static inline int nvmem_cell_get_size(struct nvmem_cell *cell, size_t *bytes, + size_t *bits) +{ + return -EOPNOTSUPP; +} + static inline int nvmem_cell_read_u8(struct device *dev, const char *cell_id, u8 *val) { From patchwork Wed Jan 24 12:22:02 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Oleksij Rempel X-Patchwork-Id: 13529161 Received: from metis.whiteo.stw.pengutronix.de (metis.whiteo.stw.pengutronix.de [185.203.201.7]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8D2D264A94 for ; Wed, 24 Jan 2024 12:22:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.203.201.7 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706098950; cv=none; b=OGx1RXvbrEV6k3SwDfv2Albs2TUOOV877lb5q0rqMoWqiJgVM1wKsRjJSoVPVmrtxvklWuCYgeyz5YAwUzASyBqSfNTcOVt/bi+hyZVsylzMzCf5NS441PdLD7MfuRJNJSSPXQkLJlypg2OvmBDJ88GmdjX61pwE3FZM7r/iX4c= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706098950; c=relaxed/simple; bh=20N1VN4Z4ICpskuEnxLNHaytZDaOloomTZFu/N940iA=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=RaezDMc6w97Atw4u1jUlmxrk4DvRau3DE7jJCm32BmW164jqq1y/UWvjVGxMRWriNVo1ZbHWjdVZOvF4VUxhG4cKOU5Fa+SCPD1pDvFYGLhPbW75mfrlkPBMUsSSs9Rhx6l3qmel0eDi6vBReX9eVeV5AydD8LEImPLUo1OeAb4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=pengutronix.de; spf=pass smtp.mailfrom=pengutronix.de; arc=none smtp.client-ip=185.203.201.7 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=pengutronix.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pengutronix.de Received: from drehscheibe.grey.stw.pengutronix.de ([2a0a:edc0:0:c01:1d::a2]) by metis.whiteo.stw.pengutronix.de with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1rScGd-0007oA-1C; Wed, 24 Jan 2024 13:22:07 +0100 Received: from [2a0a:edc0:0:1101:1d::ac] (helo=dude04.red.stw.pengutronix.de) by drehscheibe.grey.stw.pengutronix.de with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1rScGc-0023Zi-2q; Wed, 24 Jan 2024 13:22:06 +0100 Received: from ore by dude04.red.stw.pengutronix.de with local (Exim 4.96) (envelope-from ) id 1rScGb-00341i-3B; Wed, 24 Jan 2024 13:22:05 +0100 From: Oleksij Rempel To: Sebastian Reichel , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Srinivas Kandagatla Cc: Oleksij Rempel , kernel@pengutronix.de, linux-kernel@vger.kernel.org, Liam Girdwood , Mark Brown , "Rafael J. Wysocki" , Daniel Lezcano , Zhang Rui , Lukasz Luba , linux-pm@vger.kernel.org, devicetree@vger.kernel.org, =?utf-8?q?S=C3=B8ren_Andersen?= Subject: [PATCH v2 6/8] power: reset: add PSCR NVMEM Driver for Recording Power State Change Reasons Date: Wed, 24 Jan 2024 13:22:02 +0100 Message-Id: <20240124122204.730370-7-o.rempel@pengutronix.de> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20240124122204.730370-1-o.rempel@pengutronix.de> References: <20240124122204.730370-1-o.rempel@pengutronix.de> Precedence: bulk X-Mailing-List: linux-pm@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-SA-Exim-Connect-IP: 2a0a:edc0:0:c01:1d::a2 X-SA-Exim-Mail-From: ore@pengutronix.de X-SA-Exim-Scanned: No (on metis.whiteo.stw.pengutronix.de); SAEximRunCond expanded to false X-PTX-Original-Recipient: linux-pm@vger.kernel.org This driver utilizes the Power State Change Reasons Recording (PSCRR) framework to store specific power state change information, such as shutdown or reboot reasons, into a designated non-volatile memory (NVMEM) cell. Signed-off-by: Oleksij Rempel --- drivers/power/reset/Kconfig | 11 +++ drivers/power/reset/Makefile | 1 + drivers/power/reset/pscrr-nvmem.c | 121 ++++++++++++++++++++++++++++++ 3 files changed, 133 insertions(+) create mode 100644 drivers/power/reset/pscrr-nvmem.c diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig index c6ce7e647048..8e50e495ef98 100644 --- a/drivers/power/reset/Kconfig +++ b/drivers/power/reset/Kconfig @@ -324,3 +324,14 @@ menuconfig PSCRR timeouts. If unsure, say N. + +if PSCRR + +config PSCRR_NVMEM + tristate "Generic NVMEM-based Power State Change Reason Recorder" + depends on OF + help + Enabling this option adds support for recording power state change + reasons in a NVMEM cell. + +endif diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile index e618c34a30f9..3860dbbacb23 100644 --- a/drivers/power/reset/Makefile +++ b/drivers/power/reset/Makefile @@ -32,6 +32,7 @@ obj-$(CONFIG_POWER_RESET_SYSCON) += syscon-reboot.o obj-$(CONFIG_POWER_RESET_SYSCON_POWEROFF) += syscon-poweroff.o obj-$(CONFIG_POWER_RESET_RMOBILE) += rmobile-reset.o obj-$(CONFIG_PSCRR) += pscrr.o +obj-$(CONFIG_PSCRR_NVMEM) += pscrr-nvmem.o obj-$(CONFIG_REBOOT_MODE) += reboot-mode.o obj-$(CONFIG_SYSCON_REBOOT_MODE) += syscon-reboot-mode.o obj-$(CONFIG_POWER_RESET_SC27XX) += sc27xx-poweroff.o diff --git a/drivers/power/reset/pscrr-nvmem.c b/drivers/power/reset/pscrr-nvmem.c new file mode 100644 index 000000000000..fe9053b78b79 --- /dev/null +++ b/drivers/power/reset/pscrr-nvmem.c @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) Vaisala Oyj. All rights reserved. +// Copyright (c) 2024 Pengutronix, Oleksij Rempel +/* + * Based on drivers/power/reset/nvmem-reboot-mode.c + * Copyright (c) Vaisala Oyj. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include + +struct pscrr_nvmem { + struct pscrr_device pscrr_dev; + struct nvmem_cell *cell; + size_t max_magic_bytes; +}; + +static int pscrr_nvmem_write(struct pscrr_device *pscrr_dev, u32 magic) +{ + struct pscrr_nvmem *priv = container_of(pscrr_dev, struct pscrr_nvmem, + pscrr_dev); + size_t size = min(priv->max_magic_bytes, sizeof(magic)); + int ret; + + ret = nvmem_cell_write(priv->cell, &magic, size); + if (ret < 0) { + dev_err(pscrr_dev->dev, "update reason bits failed: %pe\n", + ERR_PTR(ret)); + return ret; + } + + return 0; +} + +static int pscrr_nvmem_read(struct pscrr_device *pscrr_dev, u32 *magic) +{ + struct pscrr_nvmem *priv = container_of(pscrr_dev, struct pscrr_nvmem, + pscrr_dev); + size_t len; + void *buf; + + buf = nvmem_cell_read(priv->cell, &len); + if (IS_ERR(buf)) + return PTR_ERR(buf); + + *magic = 0; + memcpy(magic, buf, min(len, sizeof(*magic))); + kfree(buf); + + return 0; +} + +static int pscrr_nvmem_probe(struct platform_device *pdev) +{ + size_t bytes, bits, magic_bits; + struct pscrr_nvmem *priv; + const char *pscr = "pscr"; + int ret; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->pscrr_dev.dev = &pdev->dev; + priv->pscrr_dev.write = pscrr_nvmem_write; + priv->pscrr_dev.read = pscrr_nvmem_read; + + priv->cell = devm_nvmem_cell_get(&pdev->dev, pscr); + if (IS_ERR(priv->cell)) + return dev_err_probe(&pdev->dev, PTR_ERR(priv->cell), + "failed to get the nvmem %s cell\n", pscr); + + ret = nvmem_cell_get_size(priv->cell, &bytes, &bits); + if (ret < 0) + return dev_err_probe(&pdev->dev, ret, "failed to get the nvmem %s size\n", + pscr); + + if (!bytes || bytes > sizeof(u32) || bits > 32) + return dev_err_probe(&pdev->dev, -EINVAL, "invalid nvmem %s size. bytes: %zu, bits: %zu\n", + pscr, bytes, bits); + + ret = devm_pscrr_register(&pdev->dev, &priv->pscrr_dev); + if (ret) + return dev_err_probe(&pdev->dev, ret, "failed to register pscr driver\n"); + + magic_bits = fls(priv->pscrr_dev.max_magic_val); + priv->max_magic_bytes = DIV_ROUND_UP(magic_bits, 8); + + if (!bits) + bits = bytes * 8; + + if (magic_bits > bits) + return dev_err_probe(&pdev->dev, -EINVAL, "provided magic can't fit into nvmem %s. bytes: %zu, bits: %zu, magic_bits: %zu\n", + pscr, bytes, bits, magic_bits); + + return handle_last_pscr(&priv->pscrr_dev); +} + +static const struct of_device_id pscrr_nvmem_of_match[] = { + { .compatible = "pscrr-nvmem" }, + {} +}; +MODULE_DEVICE_TABLE(of, pscrr_nvmem_of_match); + +static struct platform_driver pscrr_nvmem_driver = { + .probe = pscrr_nvmem_probe, + .driver = { + .name = "pscrr-nvmem", + .of_match_table = pscrr_nvmem_of_match, + }, +}; +module_platform_driver(pscrr_nvmem_driver); + +MODULE_AUTHOR("Oleksij Rempel "); +MODULE_DESCRIPTION("NVMEM Driver for Power State Change Reason Recording"); +MODULE_LICENSE("GPL"); From patchwork Wed Jan 24 12:22:03 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Oleksij Rempel X-Patchwork-Id: 13529156 Received: from metis.whiteo.stw.pengutronix.de (metis.whiteo.stw.pengutronix.de [185.203.201.7]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6614C634FC for ; Wed, 24 Jan 2024 12:22:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.203.201.7 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706098950; cv=none; b=OV3IDmZV+8320RGChtbYsAgEKD3DgbHStpBZAuQho1/q+CLVLyb42waHc+1OrJphMaLn+oiZ3RjDcntKuKbOhgfpz2bPu/0TNINsjLFiQcMhgTzY49dDWdE+rrFpeqWh6szvQ7RtqjWEP5snnioivWEw7Ag+YtMfl7iOZh3Fttk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706098950; c=relaxed/simple; bh=aGoYIr6WP6qwdiccu6/EeWFB5o3ysjwmHOnTwOOjDkQ=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=gj17KBUjK3Ijbw2LSRYqCyEvKFLMW4Aha0ceClTJ6uPLMvBUkvXjOW7Vk9wIkbiC2cmLYGyURhmDB3JQOlCO8H+xVebBBnC5Nc0gmVw9usIG4Z6f2cpWNLj7PEX7Bj8kH1KCe942KCgaGr9O8oNfKPXLrOymQwoduE+oKePwbIc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=pengutronix.de; spf=pass smtp.mailfrom=pengutronix.de; arc=none smtp.client-ip=185.203.201.7 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=pengutronix.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pengutronix.de Received: from drehscheibe.grey.stw.pengutronix.de ([2a0a:edc0:0:c01:1d::a2]) by metis.whiteo.stw.pengutronix.de with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1rScGd-0007oB-1C; Wed, 24 Jan 2024 13:22:07 +0100 Received: from [2a0a:edc0:0:1101:1d::ac] (helo=dude04.red.stw.pengutronix.de) by drehscheibe.grey.stw.pengutronix.de with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1rScGc-0023Zk-2z; Wed, 24 Jan 2024 13:22:06 +0100 Received: from ore by dude04.red.stw.pengutronix.de with local (Exim 4.96) (envelope-from ) id 1rScGc-00341u-00; Wed, 24 Jan 2024 13:22:06 +0100 From: Oleksij Rempel To: Sebastian Reichel , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Srinivas Kandagatla Cc: Oleksij Rempel , Mark Brown , kernel@pengutronix.de, linux-kernel@vger.kernel.org, Liam Girdwood , "Rafael J. Wysocki" , Daniel Lezcano , Zhang Rui , Lukasz Luba , linux-pm@vger.kernel.org, devicetree@vger.kernel.org, =?utf-8?q?S=C3=B8ren_Andersen?= Subject: [PATCH v2 7/8] regulator: set Power State Change Reason before hw_protection_shutdown() Date: Wed, 24 Jan 2024 13:22:03 +0100 Message-Id: <20240124122204.730370-8-o.rempel@pengutronix.de> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20240124122204.730370-1-o.rempel@pengutronix.de> References: <20240124122204.730370-1-o.rempel@pengutronix.de> Precedence: bulk X-Mailing-List: linux-pm@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-SA-Exim-Connect-IP: 2a0a:edc0:0:c01:1d::a2 X-SA-Exim-Mail-From: ore@pengutronix.de X-SA-Exim-Scanned: No (on metis.whiteo.stw.pengutronix.de); SAEximRunCond expanded to false X-PTX-Original-Recipient: linux-pm@vger.kernel.org Store the state change reason to some black box, for later investigation. Signed-off-by: Oleksij Rempel Reviewed-by: Mark Brown --- drivers/regulator/core.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index a968dabb48f5..a811a5ff2273 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -5095,6 +5096,7 @@ EXPORT_SYMBOL_GPL(regulator_bulk_free); static void regulator_handle_critical(struct regulator_dev *rdev, unsigned long event) { + enum pscr pscr; const char *reason = NULL; if (!rdev->constraints->system_critical) @@ -5103,17 +5105,21 @@ static void regulator_handle_critical(struct regulator_dev *rdev, switch (event) { case REGULATOR_EVENT_UNDER_VOLTAGE: reason = "System critical regulator: voltage drop detected"; + pscr = PSCR_UNDER_VOLTAGE; break; case REGULATOR_EVENT_OVER_CURRENT: reason = "System critical regulator: over-current detected"; + pscr = PSCR_OVER_CURRENT; break; case REGULATOR_EVENT_FAIL: reason = "System critical regulator: unknown error"; + pscr = PSCR_REGULATOR_FAILURE; } if (!reason) return; + set_power_state_change_reason(pscr); hw_protection_shutdown(reason, rdev->constraints->uv_less_critical_window_ms); } From patchwork Wed Jan 24 12:22:04 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Oleksij Rempel X-Patchwork-Id: 13529158 Received: from metis.whiteo.stw.pengutronix.de (metis.whiteo.stw.pengutronix.de [185.203.201.7]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6572D634F6 for ; Wed, 24 Jan 2024 12:22:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.203.201.7 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706098950; cv=none; b=XDgA5m50PM0zoe1gpbzRwr3RxodXsWWGr3j/DBOCBmUIzn3TNZY9gO/iiWGCFrW5lTAvKn8WL3IfGI4/K2MVkiVinyLt3A2afUz137gacy7EUO0jrshs+QZiQ6p91u2QP0xNLeak2h8HlA+I1Jl1Am2bekVVOCOrEVEFVYaemq0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706098950; c=relaxed/simple; bh=HDAeY4bWfoe9Y+7OHDYHhF+4G8dpj+H9p3pWeswLx5k=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=P110x6owebO3FguGtxMXp0U1cMXu3bnooUXypEyW/suttZ7NdW+9xd71ovkQbyQlu11QHGEWLYGsHtmlyiqU46Ujeop9A7MfBE1rjn0tVIE8sEM1ygHuLjUCcG3SJpP8WFke9xnoj6f/PPEyjrYVIiPKzE9BBFtdWBqEXxGdgqE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=pengutronix.de; spf=pass smtp.mailfrom=pengutronix.de; arc=none smtp.client-ip=185.203.201.7 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=pengutronix.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pengutronix.de Received: from drehscheibe.grey.stw.pengutronix.de ([2a0a:edc0:0:c01:1d::a2]) by metis.whiteo.stw.pengutronix.de with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1rScGd-0007oC-1C; Wed, 24 Jan 2024 13:22:07 +0100 Received: from [2a0a:edc0:0:1101:1d::ac] (helo=dude04.red.stw.pengutronix.de) by drehscheibe.grey.stw.pengutronix.de with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1rScGc-0023Zn-46; Wed, 24 Jan 2024 13:22:06 +0100 Received: from ore by dude04.red.stw.pengutronix.de with local (Exim 4.96) (envelope-from ) id 1rScGc-003424-03; Wed, 24 Jan 2024 13:22:06 +0100 From: Oleksij Rempel To: Sebastian Reichel , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Srinivas Kandagatla Cc: Oleksij Rempel , kernel@pengutronix.de, linux-kernel@vger.kernel.org, Liam Girdwood , Mark Brown , "Rafael J. Wysocki" , Daniel Lezcano , Zhang Rui , Lukasz Luba , linux-pm@vger.kernel.org, devicetree@vger.kernel.org, =?utf-8?q?S=C3=B8ren_Andersen?= Subject: [PATCH v2 8/8] thermal: core: Record PSCR before hw_protection_shutdown() Date: Wed, 24 Jan 2024 13:22:04 +0100 Message-Id: <20240124122204.730370-9-o.rempel@pengutronix.de> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20240124122204.730370-1-o.rempel@pengutronix.de> References: <20240124122204.730370-1-o.rempel@pengutronix.de> Precedence: bulk X-Mailing-List: linux-pm@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-SA-Exim-Connect-IP: 2a0a:edc0:0:c01:1d::a2 X-SA-Exim-Mail-From: ore@pengutronix.de X-SA-Exim-Scanned: No (on metis.whiteo.stw.pengutronix.de); SAEximRunCond expanded to false X-PTX-Original-Recipient: linux-pm@vger.kernel.org Enhance the thermal core to record the Power State Change Reason (PSCR) prior to invoking hw_protection_shutdown(). This change integrates the PSCR framework with the thermal subsystem, ensuring that reasons for power state changes, such as overtemperature events, are stored in a dedicated non-volatile memory (NVMEM) cell. This 'black box' recording is crucial for post-mortem analysis, enabling a deeper understanding of system failures and abrupt shutdowns, especially in scenarios where PMICs or watchdog timers are incapable of logging such events. The recorded data can be utilized during system recovery routines in the bootloader or early kernel stages of subsequent boots, significantly enhancing system diagnostics, reliability, and debugging capabilities. Signed-off-by: Oleksij Rempel --- drivers/thermal/thermal_core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index dfaa6341694a..0511d82351c5 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -329,6 +330,8 @@ static void thermal_zone_device_halt(struct thermal_zone_device *tz, bool shutdo dev_emerg(&tz->device, "%s: critical temperature reached\n", tz->type); + set_power_state_change_reason(PSCR_OVERTEMPERATURE); + if (shutdown) hw_protection_shutdown(msg, poweroff_delay_ms); else