mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v9 0/3] firmware: ti_sci: Partial-IO support
@ 2025-10-30  9:26 Markus Schneider-Pargmann (TI.com)
  2025-10-30  9:26 ` [PATCH v9 1/3] firmware: ti_sci: Remove constant 0 function arguments Markus Schneider-Pargmann (TI.com)
                   ` (2 more replies)
  0 siblings, 3 replies; 10+ messages in thread
From: Markus Schneider-Pargmann (TI.com) @ 2025-10-30  9:26 UTC (permalink / raw)
  To: Nishanth Menon, Tero Kristo, Santosh Shilimkar
  Cc: Vishal Mahaveer, Kevin Hilman, Dhruva Gole, Sebin Francis,
	Kendall Willis, Akashdeep Kaur, linux-arm-kernel, linux-kernel,
	Markus Schneider-Pargmann (TI.com)

Hi,

This series adds support for Partial-IO to the ti-sci driver,
implementing the firmware interface necessary to enter this low power
state. It processes the wakeup-source properties from the devicetree and
communicates with the system firmware to enter Partial-IO mode when
appropriate wakeup sources are enabled.

Partial-IO Overview
------------------
Partial-IO is a low power system state in which nearly everything is
turned off except the pins of the CANUART group (mcu_mcan0, mcu_mcan1,
wkup_uart0 and mcu_uart0). These devices can trigger a wakeup of the
system on pin activity. Note that this does not resume the system as the
DDR is off as well. So this state can be considered a power-off state
with wakeup capabilities.

A documentation can also be found in section 6.2.4 in the TRM:
  https://www.ti.com/lit/pdf/spruiv7

Implementation Details
----------------------
The complete Partial-IO feature requires three coordinated series, each
handling a different aspect of the implementation:

1. [MERGED] m_can driver series: Implements device-specific wakeup functionality
   for m_can devices, allowing them to be set as wakeup sources. This is
   now available in linux-next.
   https://lore.kernel.org/r/20251001-topic-mcan-wakeup-source-v6-12-v10-0-4ab508ac5d1e@baylibre.com

2. Devicetree series: Defines system states and wakeup sources in the
   devicetree for am62, am62a and am62p.
   https://gitlab.baylibre.com/msp8/linux/-/tree/topic/am62-dt-partialio/v6.18?ref_type=heads
   https://lore.kernel.org/r/20251030-topic-am62-dt-partialio-v6-15-v4-0-6b520dfa8591@baylibre.com

3. This series (TI-SCI firmware): Implements the firmware interface to
   enter Partial-IO mode when appropriate wakeup sources are enabled.

Testing
-------
A test branch is available here that includes all patches required to
test Partial-IO:

https://gitlab.baylibre.com/msp8/linux/-/tree/integration/am62-partialio/v6.18?ref_type=heads

After enabling Wake-on-LAN the system can be powered off and will enter
the Partial-IO state in which it can be woken up by activity on the
specific pins:
    ethtool -s can0 wol p
    ethtool -s can1 wol p
    poweroff

These patches are tested on am62-lp-sk.

Best,
Markus

Previous versions "firmware: ti_sci: Partial-IO support":
 v1: https://lore.kernel.org/lkml/20240523080225.1288617-1-msp@baylibre.com/
 v2: https://lore.kernel.org/lkml/20240729080101.3859701-1-msp@baylibre.com/
 v3: https://lore.kernel.org/r/20241012-topic-am62-partialio-v6-13-b4-v3-0-f7c6c2739681@baylibre.com
 v4: https://lore.kernel.org/r/20241219-topic-am62-partialio-v6-12-b4-v4-0-1cb8eabd407e@baylibre.com
 v5: https://lore.kernel.org/r/20250306-topic-am62-partialio-v6-12-b4-v5-0-f9323d3744a2@baylibre.com
 v6: https://lore.kernel.org/r/20250421-topic-am62-partialio-v6-12-b4-v6-0-3b5cefab1339@baylibre.com
 v7: https://lore.kernel.org/r/20250812-topic-am62-partialio-v6-12-b4-v7-0-ac10865c2d87@baylibre.com
 v8: https://lore.kernel.org/r/20251001-topic-am62-partialio-v6-12-b4-v8-0-76a742605110@baylibre.com

Previous versions "can: m_can: Add am62 wakeup support":
 v1: https://lore.kernel.org/lkml/20240523075347.1282395-1-msp@baylibre.com/
 v2: https://lore.kernel.org/lkml/20240729074135.3850634-1-msp@baylibre.com/
 v3: https://lore.kernel.org/lkml/20241011-topic-mcan-wakeup-source-v6-12-v3-0-9752c714ad12@baylibre.com
 v4: https://lore.kernel.org/r/20241015-topic-mcan-wakeup-source-v6-12-v4-0-fdac1d1e7aa6@baylibre.com
 v5: https://lore.kernel.org/r/20241028-topic-mcan-wakeup-source-v6-12-v5-0-33edc0aba629@baylibre.com
 v6: https://lore.kernel.org/r/20241219-topic-mcan-wakeup-source-v6-12-v6-0-1356c7f7cfda@baylibre.com

Changes in v9:
- Rebased to next-20251029

Changes in v8:
 - Add a patch to remove constant 0 argument passing to
   ti_sci_cmd_prepare_sleep
 - Move partial-io functions further up in the file before the first
   static const initializations

Changes in v7:
 - Rebase to v6.17-rc1
 - Update the idle-state-name used to off-wake as introduced in
   dt-schema

Changes in v6:
 - Narrowed down the wakeup-source binding to phandle lists
 - Split off the mcan and DT changes into separate series

Changes in v5:
 - Rebased to v6.14-rc1
 - Merged m_can and ti_sci series to avoid conflicts and show
   dependencies more easily
 - Added definitions of system-states for am62/am62a/am62p
 - Moved wakeup-source definitions into board dts files as they require
   a bit of support on the board.
 - Updated ti_sci support to walk through the wakeup-source phandle
   lists
 - Added pinctrl settings for mcu_mcan0/1 on all boards
 - Minor style updates for ti_sci support for transfers without response
 - Update and move the dt-binding for wakeup-source from the m_can
   binding to the dt-schema repository

Changes in v4:
 - Rebased to v6.13-rc1
 - Removed all regulator related structures from patches and implemented
   the wakeup-source property use instead.

Changes in v3:
 - Remove other modes declared for PREPARE_SLEEP as they probably won't
   ever be used in upstream.
 - Replace the wait loop after sending PREPARE_SLEEP with msleep and do
   an emergency_restart if it exits
 - Remove uarts from DT wakeup sources
 - Split no response handling in ti_sci_do_xfer() into a separate patch
   and use goto instead of if ()
 - Remove DT binding parital-io-wakeup-sources. Instead I am modeling
   the devices that are in the relevant group that are powered during
   Partial-IO with the power supplies that are externally provided to
   the SoC. In this case they are provided through 'vddshv_canuart'. All
   devices using this regulator can be considered a potential wakeup
   source if they are wakeup capable and wakeup enabled.
 - Added devicetree patches adding vcc_3v3_sys regulator and
   vddshv_canuart for am62-lp-sk
 - Add pinctrl entries for am62-lp-sk to add WKUP_EN for mcu_mcan0 and
   mcu_mcan1

Changes in v2:
 - Rebase to v6.11-rc1
 - dt-binding:
    - Update commit message
    - Add more verbose description of the new binding for a better
      explanation.
 - ti_sci driver:
    - Combine ti_sci_do_send() into ti_sci_do_xfer and only wait on a
      response if a flag is set.
    - On failure to enter Partial-IO, do emergency_restart()
    - Add comments
    - Fix small things

Signed-off-by: Markus Schneider-Pargmann (TI.com) <msp@baylibre.com>
---
Markus Schneider-Pargmann (TI.com) (3):
      firmware: ti_sci: Remove constant 0 function arguments
      firmware: ti_sci: Support transfers without response
      firmware: ti_sci: Partial-IO support

 drivers/firmware/ti_sci.c | 154 ++++++++++++++++++++++++++++++++++++++++++----
 drivers/firmware/ti_sci.h |   5 ++
 2 files changed, 146 insertions(+), 13 deletions(-)
---
base-commit: c9a389ffad27e7847c69f4d2b67ba56b77190209
change-id: 20241008-topic-am62-partialio-v6-12-b4-c273fbac4447

Best regards,
-- 
Markus Schneider-Pargmann (TI.com) <msp@baylibre.com>


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v9 1/3] firmware: ti_sci: Remove constant 0 function arguments
  2025-10-30  9:26 [PATCH v9 0/3] firmware: ti_sci: Partial-IO support Markus Schneider-Pargmann (TI.com)
@ 2025-10-30  9:26 ` Markus Schneider-Pargmann (TI.com)
  2025-10-30 14:13   ` Andrew Davis
  2025-10-30  9:26 ` [PATCH v9 2/3] firmware: ti_sci: Support transfers without response Markus Schneider-Pargmann (TI.com)
  2025-10-30  9:26 ` [PATCH v9 3/3] firmware: ti_sci: Partial-IO support Markus Schneider-Pargmann (TI.com)
  2 siblings, 1 reply; 10+ messages in thread
From: Markus Schneider-Pargmann (TI.com) @ 2025-10-30  9:26 UTC (permalink / raw)
  To: Nishanth Menon, Tero Kristo, Santosh Shilimkar
  Cc: Vishal Mahaveer, Kevin Hilman, Dhruva Gole, Sebin Francis,
	Kendall Willis, Akashdeep Kaur, linux-arm-kernel, linux-kernel,
	Markus Schneider-Pargmann (TI.com)

ti_sci_cmd_prepare_sleep takes three arguments ctx_lo, ctx_hi and
debug_flags which are always 0 for the caller. Remove these arguments as
they are basically unused.

Signed-off-by: Markus Schneider-Pargmann (TI.com) <msp@baylibre.com>
---
 drivers/firmware/ti_sci.c | 15 +++++----------
 1 file changed, 5 insertions(+), 10 deletions(-)

diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c
index 49fd2ae01055d0f425062147422471f0fd49e4bd..24ab392b4a5d0460153de76fe382371e319d8f2e 100644
--- a/drivers/firmware/ti_sci.c
+++ b/drivers/firmware/ti_sci.c
@@ -1661,14 +1661,10 @@ static int ti_sci_cmd_clk_get_freq(const struct ti_sci_handle *handle,
  * ti_sci_cmd_prepare_sleep() - Prepare system for system suspend
  * @handle:		pointer to TI SCI handle
  * @mode:		Device identifier
- * @ctx_lo:		Low part of address for context save
- * @ctx_hi:		High part of address for context save
- * @debug_flags:	Debug flags to pass to firmware
  *
  * Return: 0 if all went well, else returns appropriate error value.
  */
-static int ti_sci_cmd_prepare_sleep(const struct ti_sci_handle *handle, u8 mode,
-				    u32 ctx_lo, u32 ctx_hi, u32 debug_flags)
+static int ti_sci_cmd_prepare_sleep(const struct ti_sci_handle *handle, u8 mode)
 {
 	struct ti_sci_info *info;
 	struct ti_sci_msg_req_prepare_sleep *req;
@@ -1696,9 +1692,9 @@ static int ti_sci_cmd_prepare_sleep(const struct ti_sci_handle *handle, u8 mode,
 
 	req = (struct ti_sci_msg_req_prepare_sleep *)xfer->xfer_buf;
 	req->mode = mode;
-	req->ctx_lo = ctx_lo;
-	req->ctx_hi = ctx_hi;
-	req->debug_flags = debug_flags;
+	req->ctx_lo = 0;
+	req->ctx_hi = 0;
+	req->debug_flags = 0;
 
 	ret = ti_sci_do_xfer(info, xfer);
 	if (ret) {
@@ -3689,8 +3685,7 @@ static int ti_sci_prepare_system_suspend(struct ti_sci_info *info)
 			 * internal use and can be 0
 			 */
 			return ti_sci_cmd_prepare_sleep(&info->handle,
-							TISCI_MSG_VALUE_SLEEP_MODE_DM_MANAGED,
-							0, 0, 0);
+							TISCI_MSG_VALUE_SLEEP_MODE_DM_MANAGED);
 		} else {
 			/* DM Managed is not supported by the firmware. */
 			dev_err(info->dev, "Suspend to memory is not supported by the firmware\n");

-- 
2.51.0


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v9 2/3] firmware: ti_sci: Support transfers without response
  2025-10-30  9:26 [PATCH v9 0/3] firmware: ti_sci: Partial-IO support Markus Schneider-Pargmann (TI.com)
  2025-10-30  9:26 ` [PATCH v9 1/3] firmware: ti_sci: Remove constant 0 function arguments Markus Schneider-Pargmann (TI.com)
@ 2025-10-30  9:26 ` Markus Schneider-Pargmann (TI.com)
  2025-10-30  9:26 ` [PATCH v9 3/3] firmware: ti_sci: Partial-IO support Markus Schneider-Pargmann (TI.com)
  2 siblings, 0 replies; 10+ messages in thread
From: Markus Schneider-Pargmann (TI.com) @ 2025-10-30  9:26 UTC (permalink / raw)
  To: Nishanth Menon, Tero Kristo, Santosh Shilimkar
  Cc: Vishal Mahaveer, Kevin Hilman, Dhruva Gole, Sebin Francis,
	Kendall Willis, Akashdeep Kaur, linux-arm-kernel, linux-kernel,
	Markus Schneider-Pargmann (TI.com)

Check the header flags if an response is expected or not. If it is not
expected skip the receive part of ti_sci_do_xfer(). This prepares the
driver for one-way messages as prepare_sleep for Partial-IO.

Reviewed-by: Kendall Willis <k-willis@ti.com>
Signed-off-by: Markus Schneider-Pargmann (TI.com) <msp@baylibre.com>
---
 drivers/firmware/ti_sci.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c
index 24ab392b4a5d0460153de76fe382371e319d8f2e..4db84a92a517b0aa7bb8d47e809d9848a16e2cc4 100644
--- a/drivers/firmware/ti_sci.c
+++ b/drivers/firmware/ti_sci.c
@@ -398,6 +398,9 @@ static void ti_sci_put_one_xfer(struct ti_sci_xfers_info *minfo,
 static inline int ti_sci_do_xfer(struct ti_sci_info *info,
 				 struct ti_sci_xfer *xfer)
 {
+	struct ti_sci_msg_hdr *hdr = (struct ti_sci_msg_hdr *)xfer->tx_message.buf;
+	bool response_expected = !!(hdr->flags & (TI_SCI_FLAG_REQ_ACK_ON_PROCESSED |
+						  TI_SCI_FLAG_REQ_ACK_ON_RECEIVED));
 	int ret;
 	int timeout;
 	struct device *dev = info->dev;
@@ -409,12 +412,12 @@ static inline int ti_sci_do_xfer(struct ti_sci_info *info,
 
 	ret = 0;
 
-	if (system_state <= SYSTEM_RUNNING) {
+	if (response_expected && system_state <= SYSTEM_RUNNING) {
 		/* And we wait for the response. */
 		timeout = msecs_to_jiffies(info->desc->max_rx_timeout_ms);
 		if (!wait_for_completion_timeout(&xfer->done, timeout))
 			ret = -ETIMEDOUT;
-	} else {
+	} else if (response_expected) {
 		/*
 		 * If we are !running, we cannot use wait_for_completion_timeout
 		 * during noirq phase, so we must manually poll the completion.

-- 
2.51.0


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v9 3/3] firmware: ti_sci: Partial-IO support
  2025-10-30  9:26 [PATCH v9 0/3] firmware: ti_sci: Partial-IO support Markus Schneider-Pargmann (TI.com)
  2025-10-30  9:26 ` [PATCH v9 1/3] firmware: ti_sci: Remove constant 0 function arguments Markus Schneider-Pargmann (TI.com)
  2025-10-30  9:26 ` [PATCH v9 2/3] firmware: ti_sci: Support transfers without response Markus Schneider-Pargmann (TI.com)
@ 2025-10-30  9:26 ` Markus Schneider-Pargmann (TI.com)
  2025-10-30 14:24   ` Andrew Davis
  2025-11-01 16:25   ` kernel test robot
  2 siblings, 2 replies; 10+ messages in thread
From: Markus Schneider-Pargmann (TI.com) @ 2025-10-30  9:26 UTC (permalink / raw)
  To: Nishanth Menon, Tero Kristo, Santosh Shilimkar
  Cc: Vishal Mahaveer, Kevin Hilman, Dhruva Gole, Sebin Francis,
	Kendall Willis, Akashdeep Kaur, linux-arm-kernel, linux-kernel,
	Markus Schneider-Pargmann (TI.com)

Add support for Partial-IO poweroff. In Partial-IO pins of a few
hardware units can generate system wakeups while DDR memory is not
powered resulting in a fresh boot of the system. These hardware units in
the SoC are always powered so that some logic can detect pin activity.

If the system supports Partial-IO as described in the fw capabilities, a
sys_off handler is added. This sys_off handler decides if the poweroff
is executed by entering normal poweroff or Partial-IO instead. The
decision is made by checking if wakeup is enabled on all devices that
may wake up the SoC from Partial-IO.

The possible wakeup devices are found by checking which devices
reference a "Partial-IO" system state in the list of wakeup-source
system states. Only devices that are actually enabled by the user will
be considered as an active wakeup source. If none of the wakeup sources
is enabled the system will do a normal poweroff. If at least one wakeup
source is enabled it will instead send a TI_SCI_MSG_PREPARE_SLEEP
message from the sys_off handler. Sending this message will result in an
immediate shutdown of the system. No execution is expected after this
point. The code will wait for 5s and do an emergency_restart afterwards
if Partial-IO wasn't entered at that point.

A short documentation about Partial-IO can be found in section 6.2.4.5
of the TRM at
  https://www.ti.com/lit/pdf/spruiv7

Signed-off-by: Markus Schneider-Pargmann (TI.com) <msp@baylibre.com>
---
 drivers/firmware/ti_sci.c | 132 +++++++++++++++++++++++++++++++++++++++++++++-
 drivers/firmware/ti_sci.h |   5 ++
 2 files changed, 136 insertions(+), 1 deletion(-)

diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c
index 4db84a92a517b0aa7bb8d47e809d9848a16e2cc4..f2922fccfbe748a436cb9aa0a8c8e5f48db02ef9 100644
--- a/drivers/firmware/ti_sci.c
+++ b/drivers/firmware/ti_sci.c
@@ -6,6 +6,7 @@
  *	Nishanth Menon
  */
 
+#include "linux/dev_printk.h"
 #define pr_fmt(fmt) "%s: " fmt, __func__
 
 #include <linux/bitmap.h>
@@ -3663,6 +3664,116 @@ devm_ti_sci_get_resource(const struct ti_sci_handle *handle, struct device *dev,
 }
 EXPORT_SYMBOL_GPL(devm_ti_sci_get_resource);
 
+/*
+ * Enter Partial-IO, which disables everything including DDR with only a small
+ * logic being active for wakeup.
+ */
+static int ti_sci_enter_partial_io(struct ti_sci_info *info)
+{
+	struct ti_sci_msg_req_prepare_sleep *req;
+	struct ti_sci_xfer *xfer;
+	struct device *dev = info->dev;
+	int ret = 0;
+
+	xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_PREPARE_SLEEP,
+				   TI_SCI_FLAG_REQ_GENERIC_NORESPONSE,
+				   sizeof(*req), sizeof(struct ti_sci_msg_hdr));
+	if (IS_ERR(xfer)) {
+		ret = PTR_ERR(xfer);
+		dev_err(dev, "Message alloc failed(%d)\n", ret);
+		return ret;
+	}
+
+	req = (struct ti_sci_msg_req_prepare_sleep *)xfer->xfer_buf;
+	req->mode = TISCI_MSG_VALUE_SLEEP_MODE_PARTIAL_IO;
+	req->ctx_lo = 0;
+	req->ctx_hi = 0;
+	req->debug_flags = 0;
+
+	ret = ti_sci_do_xfer(info, xfer);
+	if (ret) {
+		dev_err(dev, "Mbox send fail %d\n", ret);
+		goto fail;
+	}
+
+fail:
+	ti_sci_put_one_xfer(&info->minfo, xfer);
+
+	return ret;
+}
+
+/*
+ * Iterate all device nodes that have a wakeup-source property and check if one
+ * of the possible phandles points to a Partial-IO system state. If it
+ * does resolve the device node to an actual device and check if wakeup is
+ * enabled.
+ */
+static bool ti_sci_partial_io_wakeup_enabled(struct ti_sci_info *info)
+{
+	struct device_node *wakeup_node = NULL;
+
+	for_each_node_with_property(wakeup_node, "wakeup-source") {
+		struct of_phandle_iterator it;
+		int err;
+
+		of_for_each_phandle(&it, err, wakeup_node, "wakeup-source", NULL, 0) {
+			struct platform_device *pdev;
+			bool may_wakeup;
+
+			/*
+			 * Continue if idle-state-name is not off-wake. Return
+			 * value is the index of the string which should be 0 if
+			 * off-wake is present.
+			 */
+			if (of_property_match_string(it.node, "idle-state-name", "off-wake"))
+				continue;
+
+			pdev = of_find_device_by_node(wakeup_node);
+			if (!pdev)
+				continue;
+
+			may_wakeup = device_may_wakeup(&pdev->dev);
+			put_device(&pdev->dev);
+
+			if (may_wakeup) {
+				dev_dbg(info->dev, "%pOF identified as wakeup source for Partial-IO\n",
+					wakeup_node);
+				of_node_put(it.node);
+				of_node_put(wakeup_node);
+				return true;
+			}
+		}
+	}
+
+	return false;
+}
+
+static int ti_sci_sys_off_handler(struct sys_off_data *data)
+{
+	struct ti_sci_info *info = data->cb_data;
+	bool enter_partial_io = ti_sci_partial_io_wakeup_enabled(info);
+	int ret;
+
+	if (!enter_partial_io)
+		return NOTIFY_DONE;
+
+	dev_info(info->dev, "Entering Partial-IO because a powered wakeup-enabled device was found.\n");
+
+	ret = ti_sci_enter_partial_io(info);
+
+	if (ret) {
+		dev_err(info->dev,
+			"Failed to enter Partial-IO %pe, trying to do an emergency restart\n",
+			ERR_PTR(ret));
+		emergency_restart();
+	}
+
+	mdelay(5000);
+	emergency_restart();
+
+	return NOTIFY_DONE;
+}
+
 static int tisci_reboot_handler(struct sys_off_data *data)
 {
 	struct ti_sci_info *info = data->cb_data;
@@ -3941,6 +4052,19 @@ static int ti_sci_probe(struct platform_device *pdev)
 		goto out;
 	}
 
+	if (info->fw_caps & MSG_FLAG_CAPS_LPM_PARTIAL_IO) {
+		ret = devm_register_sys_off_handler(dev,
+						    SYS_OFF_MODE_POWER_OFF,
+						    SYS_OFF_PRIO_FIRMWARE,
+						    ti_sci_sys_off_handler,
+						    info);
+		if (ret) {
+			dev_err(dev, "Failed to register sys_off_handler %pe\n",
+				ERR_PTR(ret));
+			goto out;
+		}
+	}
+
 	dev_info(dev, "ABI: %d.%d (firmware rev 0x%04x '%s')\n",
 		 info->handle.version.abi_major, info->handle.version.abi_minor,
 		 info->handle.version.firmware_revision,
@@ -3950,7 +4074,13 @@ static int ti_sci_probe(struct platform_device *pdev)
 	list_add_tail(&info->node, &ti_sci_list);
 	mutex_unlock(&ti_sci_list_mutex);
 
-	return of_platform_populate(dev->of_node, NULL, NULL, dev);
+	ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
+	if (ret) {
+		dev_err(dev, "platform_populate failed %pe\n", ERR_PTR(ret));
+		goto out;
+	}
+	return 0;
+
 out:
 	if (!IS_ERR(info->chan_tx))
 		mbox_free_channel(info->chan_tx);
diff --git a/drivers/firmware/ti_sci.h b/drivers/firmware/ti_sci.h
index 701c416b2e78f8ef20ce6741a88ffa6fd4853b2d..09eaea54dd5cabce72dd1652c9603e3ab446b60c 100644
--- a/drivers/firmware/ti_sci.h
+++ b/drivers/firmware/ti_sci.h
@@ -595,6 +595,11 @@ struct ti_sci_msg_resp_get_clock_freq {
 struct ti_sci_msg_req_prepare_sleep {
 	struct ti_sci_msg_hdr	hdr;
 
+/*
+ * When sending prepare_sleep with MODE_PARTIAL_IO no response will be sent,
+ * no further steps are required.
+ */
+#define TISCI_MSG_VALUE_SLEEP_MODE_PARTIAL_IO				0x03
 #define TISCI_MSG_VALUE_SLEEP_MODE_DM_MANAGED				0xfd
 	u8			mode;
 	u32			ctx_lo;

-- 
2.51.0


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v9 1/3] firmware: ti_sci: Remove constant 0 function arguments
  2025-10-30  9:26 ` [PATCH v9 1/3] firmware: ti_sci: Remove constant 0 function arguments Markus Schneider-Pargmann (TI.com)
@ 2025-10-30 14:13   ` Andrew Davis
  2025-10-30 16:57     ` Markus Schneider-Pargmann
  0 siblings, 1 reply; 10+ messages in thread
From: Andrew Davis @ 2025-10-30 14:13 UTC (permalink / raw)
  To: Markus Schneider-Pargmann (TI.com),
	Nishanth Menon, Tero Kristo, Santosh Shilimkar
  Cc: Vishal Mahaveer, Kevin Hilman, Dhruva Gole, Sebin Francis,
	Kendall Willis, Akashdeep Kaur, linux-arm-kernel, linux-kernel

On 10/30/25 4:26 AM, Markus Schneider-Pargmann (TI.com) wrote:
> ti_sci_cmd_prepare_sleep takes three arguments ctx_lo, ctx_hi and
> debug_flags which are always 0 for the caller. Remove these arguments as
> they are basically unused.
> 

They might not be used today, but the TI-SCI command does support
passing them, so why remove that ability from the wrapper function?

Andrew

> Signed-off-by: Markus Schneider-Pargmann (TI.com) <msp@baylibre.com>
> ---
>   drivers/firmware/ti_sci.c | 15 +++++----------
>   1 file changed, 5 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c
> index 49fd2ae01055d0f425062147422471f0fd49e4bd..24ab392b4a5d0460153de76fe382371e319d8f2e 100644
> --- a/drivers/firmware/ti_sci.c
> +++ b/drivers/firmware/ti_sci.c
> @@ -1661,14 +1661,10 @@ static int ti_sci_cmd_clk_get_freq(const struct ti_sci_handle *handle,
>    * ti_sci_cmd_prepare_sleep() - Prepare system for system suspend
>    * @handle:		pointer to TI SCI handle
>    * @mode:		Device identifier
> - * @ctx_lo:		Low part of address for context save
> - * @ctx_hi:		High part of address for context save
> - * @debug_flags:	Debug flags to pass to firmware
>    *
>    * Return: 0 if all went well, else returns appropriate error value.
>    */
> -static int ti_sci_cmd_prepare_sleep(const struct ti_sci_handle *handle, u8 mode,
> -				    u32 ctx_lo, u32 ctx_hi, u32 debug_flags)
> +static int ti_sci_cmd_prepare_sleep(const struct ti_sci_handle *handle, u8 mode)
>   {
>   	struct ti_sci_info *info;
>   	struct ti_sci_msg_req_prepare_sleep *req;
> @@ -1696,9 +1692,9 @@ static int ti_sci_cmd_prepare_sleep(const struct ti_sci_handle *handle, u8 mode,
>   
>   	req = (struct ti_sci_msg_req_prepare_sleep *)xfer->xfer_buf;
>   	req->mode = mode;
> -	req->ctx_lo = ctx_lo;
> -	req->ctx_hi = ctx_hi;
> -	req->debug_flags = debug_flags;
> +	req->ctx_lo = 0;
> +	req->ctx_hi = 0;
> +	req->debug_flags = 0;
>   
>   	ret = ti_sci_do_xfer(info, xfer);
>   	if (ret) {
> @@ -3689,8 +3685,7 @@ static int ti_sci_prepare_system_suspend(struct ti_sci_info *info)
>   			 * internal use and can be 0
>   			 */
>   			return ti_sci_cmd_prepare_sleep(&info->handle,
> -							TISCI_MSG_VALUE_SLEEP_MODE_DM_MANAGED,
> -							0, 0, 0);
> +							TISCI_MSG_VALUE_SLEEP_MODE_DM_MANAGED);
>   		} else {
>   			/* DM Managed is not supported by the firmware. */
>   			dev_err(info->dev, "Suspend to memory is not supported by the firmware\n");
> 


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v9 3/3] firmware: ti_sci: Partial-IO support
  2025-10-30  9:26 ` [PATCH v9 3/3] firmware: ti_sci: Partial-IO support Markus Schneider-Pargmann (TI.com)
@ 2025-10-30 14:24   ` Andrew Davis
  2025-11-03 10:31     ` Markus Schneider-Pargmann
  2025-11-01 16:25   ` kernel test robot
  1 sibling, 1 reply; 10+ messages in thread
From: Andrew Davis @ 2025-10-30 14:24 UTC (permalink / raw)
  To: Markus Schneider-Pargmann (TI.com),
	Nishanth Menon, Tero Kristo, Santosh Shilimkar
  Cc: Vishal Mahaveer, Kevin Hilman, Dhruva Gole, Sebin Francis,
	Kendall Willis, Akashdeep Kaur, linux-arm-kernel, linux-kernel

On 10/30/25 4:26 AM, Markus Schneider-Pargmann (TI.com) wrote:
> Add support for Partial-IO poweroff. In Partial-IO pins of a few
> hardware units can generate system wakeups while DDR memory is not
> powered resulting in a fresh boot of the system. These hardware units in
> the SoC are always powered so that some logic can detect pin activity.
> 
> If the system supports Partial-IO as described in the fw capabilities, a
> sys_off handler is added. This sys_off handler decides if the poweroff
> is executed by entering normal poweroff or Partial-IO instead. The
> decision is made by checking if wakeup is enabled on all devices that
> may wake up the SoC from Partial-IO.
> 
> The possible wakeup devices are found by checking which devices
> reference a "Partial-IO" system state in the list of wakeup-source
> system states. Only devices that are actually enabled by the user will
> be considered as an active wakeup source. If none of the wakeup sources
> is enabled the system will do a normal poweroff. If at least one wakeup
> source is enabled it will instead send a TI_SCI_MSG_PREPARE_SLEEP
> message from the sys_off handler. Sending this message will result in an
> immediate shutdown of the system. No execution is expected after this
> point. The code will wait for 5s and do an emergency_restart afterwards
> if Partial-IO wasn't entered at that point.
> 
> A short documentation about Partial-IO can be found in section 6.2.4.5
> of the TRM at
>    https://www.ti.com/lit/pdf/spruiv7
> 
> Signed-off-by: Markus Schneider-Pargmann (TI.com) <msp@baylibre.com>
> ---
>   drivers/firmware/ti_sci.c | 132 +++++++++++++++++++++++++++++++++++++++++++++-
>   drivers/firmware/ti_sci.h |   5 ++
>   2 files changed, 136 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c
> index 4db84a92a517b0aa7bb8d47e809d9848a16e2cc4..f2922fccfbe748a436cb9aa0a8c8e5f48db02ef9 100644
> --- a/drivers/firmware/ti_sci.c
> +++ b/drivers/firmware/ti_sci.c
> @@ -6,6 +6,7 @@
>    *	Nishanth Menon
>    */
>   
> +#include "linux/dev_printk.h"
>   #define pr_fmt(fmt) "%s: " fmt, __func__
>   
>   #include <linux/bitmap.h>
> @@ -3663,6 +3664,116 @@ devm_ti_sci_get_resource(const struct ti_sci_handle *handle, struct device *dev,
>   }
>   EXPORT_SYMBOL_GPL(devm_ti_sci_get_resource);
>   
> +/*
> + * Enter Partial-IO, which disables everything including DDR with only a small
> + * logic being active for wakeup.
> + */
> +static int ti_sci_enter_partial_io(struct ti_sci_info *info)
> +{
> +	struct ti_sci_msg_req_prepare_sleep *req;
> +	struct ti_sci_xfer *xfer;
> +	struct device *dev = info->dev;
> +	int ret = 0;
> +
> +	xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_PREPARE_SLEEP,
> +				   TI_SCI_FLAG_REQ_GENERIC_NORESPONSE,
> +				   sizeof(*req), sizeof(struct ti_sci_msg_hdr));
> +	if (IS_ERR(xfer)) {
> +		ret = PTR_ERR(xfer);
> +		dev_err(dev, "Message alloc failed(%d)\n", ret);
> +		return ret;
> +	}
> +
> +	req = (struct ti_sci_msg_req_prepare_sleep *)xfer->xfer_buf;
> +	req->mode = TISCI_MSG_VALUE_SLEEP_MODE_PARTIAL_IO;

This whole function is almost identical to ti_sci_cmd_prepare_sleep() other
than you use a different mode here, which this different mode can be passed
into ti_sci_cmd_prepare_sleep() just the same. Only other difference would
be the NORESPONSE flag which you could just check "mode" passed in and
use the right flag for the mode.

> +	req->ctx_lo = 0;
> +	req->ctx_hi = 0;
> +	req->debug_flags = 0;
> +
> +	ret = ti_sci_do_xfer(info, xfer);
> +	if (ret) {
> +		dev_err(dev, "Mbox send fail %d\n", ret);
> +		goto fail;
> +	}
> +
> +fail:
> +	ti_sci_put_one_xfer(&info->minfo, xfer);
> +
> +	return ret;
> +}
> +
> +/*
> + * Iterate all device nodes that have a wakeup-source property and check if one
> + * of the possible phandles points to a Partial-IO system state. If it
> + * does resolve the device node to an actual device and check if wakeup is
> + * enabled.
> + */
> +static bool ti_sci_partial_io_wakeup_enabled(struct ti_sci_info *info)
> +{
> +	struct device_node *wakeup_node = NULL;
> +
> +	for_each_node_with_property(wakeup_node, "wakeup-source") {
> +		struct of_phandle_iterator it;
> +		int err;
> +
> +		of_for_each_phandle(&it, err, wakeup_node, "wakeup-source", NULL, 0) {
> +			struct platform_device *pdev;
> +			bool may_wakeup;
> +
> +			/*
> +			 * Continue if idle-state-name is not off-wake. Return
> +			 * value is the index of the string which should be 0 if
> +			 * off-wake is present.
> +			 */
> +			if (of_property_match_string(it.node, "idle-state-name", "off-wake"))
> +				continue;
> +
> +			pdev = of_find_device_by_node(wakeup_node);
> +			if (!pdev)
> +				continue;
> +
> +			may_wakeup = device_may_wakeup(&pdev->dev);
> +			put_device(&pdev->dev);
> +
> +			if (may_wakeup) {
> +				dev_dbg(info->dev, "%pOF identified as wakeup source for Partial-IO\n",
> +					wakeup_node);
> +				of_node_put(it.node);
> +				of_node_put(wakeup_node);
> +				return true;
> +			}
> +		}
> +	}
> +
> +	return false;
> +}
> +
> +static int ti_sci_sys_off_handler(struct sys_off_data *data)
> +{
> +	struct ti_sci_info *info = data->cb_data;
> +	bool enter_partial_io = ti_sci_partial_io_wakeup_enabled(info);
> +	int ret;
> +
> +	if (!enter_partial_io)
> +		return NOTIFY_DONE;
> +
> +	dev_info(info->dev, "Entering Partial-IO because a powered wakeup-enabled device was found.\n");
> +
> +	ret = ti_sci_enter_partial_io(info);
> +

No need for newline here.

> +	if (ret) {
> +		dev_err(info->dev,
> +			"Failed to enter Partial-IO %pe, trying to do an emergency restart\n",
> +			ERR_PTR(ret));

Why cast this int to a pointer before printing it out?

Andrew

> +		emergency_restart();
> +	}
> +
> +	mdelay(5000);
> +	emergency_restart();
> +
> +	return NOTIFY_DONE;
> +}
> +
>   static int tisci_reboot_handler(struct sys_off_data *data)
>   {
>   	struct ti_sci_info *info = data->cb_data;
> @@ -3941,6 +4052,19 @@ static int ti_sci_probe(struct platform_device *pdev)
>   		goto out;
>   	}
>   
> +	if (info->fw_caps & MSG_FLAG_CAPS_LPM_PARTIAL_IO) {
> +		ret = devm_register_sys_off_handler(dev,
> +						    SYS_OFF_MODE_POWER_OFF,
> +						    SYS_OFF_PRIO_FIRMWARE,
> +						    ti_sci_sys_off_handler,
> +						    info);
> +		if (ret) {
> +			dev_err(dev, "Failed to register sys_off_handler %pe\n",
> +				ERR_PTR(ret));
> +			goto out;
> +		}
> +	}
> +
>   	dev_info(dev, "ABI: %d.%d (firmware rev 0x%04x '%s')\n",
>   		 info->handle.version.abi_major, info->handle.version.abi_minor,
>   		 info->handle.version.firmware_revision,
> @@ -3950,7 +4074,13 @@ static int ti_sci_probe(struct platform_device *pdev)
>   	list_add_tail(&info->node, &ti_sci_list);
>   	mutex_unlock(&ti_sci_list_mutex);
>   
> -	return of_platform_populate(dev->of_node, NULL, NULL, dev);
> +	ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
> +	if (ret) {
> +		dev_err(dev, "platform_populate failed %pe\n", ERR_PTR(ret));
> +		goto out;
> +	}
> +	return 0;
> +
>   out:
>   	if (!IS_ERR(info->chan_tx))
>   		mbox_free_channel(info->chan_tx);
> diff --git a/drivers/firmware/ti_sci.h b/drivers/firmware/ti_sci.h
> index 701c416b2e78f8ef20ce6741a88ffa6fd4853b2d..09eaea54dd5cabce72dd1652c9603e3ab446b60c 100644
> --- a/drivers/firmware/ti_sci.h
> +++ b/drivers/firmware/ti_sci.h
> @@ -595,6 +595,11 @@ struct ti_sci_msg_resp_get_clock_freq {
>   struct ti_sci_msg_req_prepare_sleep {
>   	struct ti_sci_msg_hdr	hdr;
>   
> +/*
> + * When sending prepare_sleep with MODE_PARTIAL_IO no response will be sent,
> + * no further steps are required.
> + */
> +#define TISCI_MSG_VALUE_SLEEP_MODE_PARTIAL_IO				0x03
>   #define TISCI_MSG_VALUE_SLEEP_MODE_DM_MANAGED				0xfd
>   	u8			mode;
>   	u32			ctx_lo;
> 


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v9 1/3] firmware: ti_sci: Remove constant 0 function arguments
  2025-10-30 14:13   ` Andrew Davis
@ 2025-10-30 16:57     ` Markus Schneider-Pargmann
  0 siblings, 0 replies; 10+ messages in thread
From: Markus Schneider-Pargmann @ 2025-10-30 16:57 UTC (permalink / raw)
  To: Andrew Davis, Markus Schneider-Pargmann (TI.com),
	Nishanth Menon, Tero Kristo, Santosh Shilimkar
  Cc: Vishal Mahaveer, Kevin Hilman, Dhruva Gole, Sebin Francis,
	Kendall Willis, Akashdeep Kaur, linux-arm-kernel, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 3302 bytes --]

Hi Andrew,

On Thu Oct 30, 2025 at 3:13 PM CET, Andrew Davis wrote:
> On 10/30/25 4:26 AM, Markus Schneider-Pargmann (TI.com) wrote:
>> ti_sci_cmd_prepare_sleep takes three arguments ctx_lo, ctx_hi and
>> debug_flags which are always 0 for the caller. Remove these arguments as
>> they are basically unused.
>> 
>
> They might not be used today, but the TI-SCI command does support
> passing them, so why remove that ability from the wrapper function?

Thank you. I removed the arguments as I prefer something like

  return ti_sci_cmd_prepare_sleep(&info->handle,
                                  TISCI_MSG_VALUE_SLEEP_MODE_DM_MANAGED);

over

  return ti_sci_cmd_prepare_sleep(&info->handle,
                                  TISCI_MSG_VALUE_SLEEP_MODE_DM_MANAGED,
                                  0, 0, 0);

As this function is not part of any API and only used by
ti_sci_prepare_system_suspend I didn't see a problem in removing it.
Also I don't know of any code that will be using these arguments.

If you prefer I can drop this patch.

Best
Markus

>
> Andrew
>
>> Signed-off-by: Markus Schneider-Pargmann (TI.com) <msp@baylibre.com>
>> ---
>>   drivers/firmware/ti_sci.c | 15 +++++----------
>>   1 file changed, 5 insertions(+), 10 deletions(-)
>> 
>> diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c
>> index 49fd2ae01055d0f425062147422471f0fd49e4bd..24ab392b4a5d0460153de76fe382371e319d8f2e 100644
>> --- a/drivers/firmware/ti_sci.c
>> +++ b/drivers/firmware/ti_sci.c
>> @@ -1661,14 +1661,10 @@ static int ti_sci_cmd_clk_get_freq(const struct ti_sci_handle *handle,
>>    * ti_sci_cmd_prepare_sleep() - Prepare system for system suspend
>>    * @handle:		pointer to TI SCI handle
>>    * @mode:		Device identifier
>> - * @ctx_lo:		Low part of address for context save
>> - * @ctx_hi:		High part of address for context save
>> - * @debug_flags:	Debug flags to pass to firmware
>>    *
>>    * Return: 0 if all went well, else returns appropriate error value.
>>    */
>> -static int ti_sci_cmd_prepare_sleep(const struct ti_sci_handle *handle, u8 mode,
>> -				    u32 ctx_lo, u32 ctx_hi, u32 debug_flags)
>> +static int ti_sci_cmd_prepare_sleep(const struct ti_sci_handle *handle, u8 mode)
>>   {
>>   	struct ti_sci_info *info;
>>   	struct ti_sci_msg_req_prepare_sleep *req;
>> @@ -1696,9 +1692,9 @@ static int ti_sci_cmd_prepare_sleep(const struct ti_sci_handle *handle, u8 mode,
>>   
>>   	req = (struct ti_sci_msg_req_prepare_sleep *)xfer->xfer_buf;
>>   	req->mode = mode;
>> -	req->ctx_lo = ctx_lo;
>> -	req->ctx_hi = ctx_hi;
>> -	req->debug_flags = debug_flags;
>> +	req->ctx_lo = 0;
>> +	req->ctx_hi = 0;
>> +	req->debug_flags = 0;
>>   
>>   	ret = ti_sci_do_xfer(info, xfer);
>>   	if (ret) {
>> @@ -3689,8 +3685,7 @@ static int ti_sci_prepare_system_suspend(struct ti_sci_info *info)
>>   			 * internal use and can be 0
>>   			 */
>>   			return ti_sci_cmd_prepare_sleep(&info->handle,
>> -							TISCI_MSG_VALUE_SLEEP_MODE_DM_MANAGED,
>> -							0, 0, 0);
>> +							TISCI_MSG_VALUE_SLEEP_MODE_DM_MANAGED);
>>   		} else {
>>   			/* DM Managed is not supported by the firmware. */
>>   			dev_err(info->dev, "Suspend to memory is not supported by the firmware\n");
>> 


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 289 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v9 3/3] firmware: ti_sci: Partial-IO support
  2025-10-30  9:26 ` [PATCH v9 3/3] firmware: ti_sci: Partial-IO support Markus Schneider-Pargmann (TI.com)
  2025-10-30 14:24   ` Andrew Davis
@ 2025-11-01 16:25   ` kernel test robot
  1 sibling, 0 replies; 10+ messages in thread
From: kernel test robot @ 2025-11-01 16:25 UTC (permalink / raw)
  To: Markus Schneider-Pargmann (TI.com),
	Nishanth Menon, Tero Kristo, Santosh Shilimkar
  Cc: llvm, oe-kbuild-all, Vishal Mahaveer, Kevin Hilman, Dhruva Gole,
	Sebin Francis, Kendall Willis, Akashdeep Kaur, linux-arm-kernel,
	linux-kernel, Markus Schneider-Pargmann (TI.com)

Hi Markus,

kernel test robot noticed the following build warnings:

[auto build test WARNING on c9a389ffad27e7847c69f4d2b67ba56b77190209]

url:    https://github.com/intel-lab-lkp/linux/commits/Markus-Schneider-Pargmann-TI-com/firmware-ti_sci-Remove-constant-0-function-arguments/20251030-173054
base:   c9a389ffad27e7847c69f4d2b67ba56b77190209
patch link:    https://lore.kernel.org/r/20251030-topic-am62-partialio-v6-12-b4-v9-3-074f55d9c16b%40baylibre.com
patch subject: [PATCH v9 3/3] firmware: ti_sci: Partial-IO support
config: arm-randconfig-002-20251101 (https://download.01.org/0day-ci/archive/20251102/202511020037.8sAseAYs-lkp@intel.com/config)
compiler: clang version 22.0.0git (https://github.com/llvm/llvm-project d2625a438020ad35330cda29c3def102c1687b1b)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251102/202511020037.8sAseAYs-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202511020037.8sAseAYs-lkp@intel.com/

All warnings (new ones prefixed by >>):

>> drivers/firmware/ti_sci.c:10:9: warning: 'pr_fmt' macro redefined [-Wmacro-redefined]
      10 | #define pr_fmt(fmt) "%s: " fmt, __func__
         |         ^
   include/linux/printk.h:402:9: note: previous definition is here
     402 | #define pr_fmt(fmt) fmt
         |         ^
   1 warning generated.


vim +/pr_fmt +10 drivers/firmware/ti_sci.c

aa276781a64a5f Nishanth Menon 2016-10-18 @10  #define pr_fmt(fmt) "%s: " fmt, __func__
aa276781a64a5f Nishanth Menon 2016-10-18  11  

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v9 3/3] firmware: ti_sci: Partial-IO support
  2025-10-30 14:24   ` Andrew Davis
@ 2025-11-03 10:31     ` Markus Schneider-Pargmann
  2025-11-03 14:10       ` Andrew Davis
  0 siblings, 1 reply; 10+ messages in thread
From: Markus Schneider-Pargmann @ 2025-11-03 10:31 UTC (permalink / raw)
  To: Andrew Davis, Markus Schneider-Pargmann (TI.com),
	Nishanth Menon, Tero Kristo, Santosh Shilimkar
  Cc: Vishal Mahaveer, Kevin Hilman, Dhruva Gole, Sebin Francis,
	Kendall Willis, Akashdeep Kaur, linux-arm-kernel, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 6358 bytes --]

On Thu Oct 30, 2025 at 3:24 PM CET, Andrew Davis wrote:
> On 10/30/25 4:26 AM, Markus Schneider-Pargmann (TI.com) wrote:
>> Add support for Partial-IO poweroff. In Partial-IO pins of a few
>> hardware units can generate system wakeups while DDR memory is not
>> powered resulting in a fresh boot of the system. These hardware units in
>> the SoC are always powered so that some logic can detect pin activity.
>> 
>> If the system supports Partial-IO as described in the fw capabilities, a
>> sys_off handler is added. This sys_off handler decides if the poweroff
>> is executed by entering normal poweroff or Partial-IO instead. The
>> decision is made by checking if wakeup is enabled on all devices that
>> may wake up the SoC from Partial-IO.
>> 
>> The possible wakeup devices are found by checking which devices
>> reference a "Partial-IO" system state in the list of wakeup-source
>> system states. Only devices that are actually enabled by the user will
>> be considered as an active wakeup source. If none of the wakeup sources
>> is enabled the system will do a normal poweroff. If at least one wakeup
>> source is enabled it will instead send a TI_SCI_MSG_PREPARE_SLEEP
>> message from the sys_off handler. Sending this message will result in an
>> immediate shutdown of the system. No execution is expected after this
>> point. The code will wait for 5s and do an emergency_restart afterwards
>> if Partial-IO wasn't entered at that point.
>> 
>> A short documentation about Partial-IO can be found in section 6.2.4.5
>> of the TRM at
>>    https://www.ti.com/lit/pdf/spruiv7
>> 
>> Signed-off-by: Markus Schneider-Pargmann (TI.com) <msp@baylibre.com>
>> ---
>>   drivers/firmware/ti_sci.c | 132 +++++++++++++++++++++++++++++++++++++++++++++-
>>   drivers/firmware/ti_sci.h |   5 ++
>>   2 files changed, 136 insertions(+), 1 deletion(-)
>> 
>> diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c
>> index 4db84a92a517b0aa7bb8d47e809d9848a16e2cc4..f2922fccfbe748a436cb9aa0a8c8e5f48db02ef9 100644
>> --- a/drivers/firmware/ti_sci.c
>> +++ b/drivers/firmware/ti_sci.c
>> @@ -6,6 +6,7 @@
>>    *	Nishanth Menon
>>    */
>>   
>> +#include "linux/dev_printk.h"
>>   #define pr_fmt(fmt) "%s: " fmt, __func__
>>   
>>   #include <linux/bitmap.h>
>> @@ -3663,6 +3664,116 @@ devm_ti_sci_get_resource(const struct ti_sci_handle *handle, struct device *dev,
>>   }
>>   EXPORT_SYMBOL_GPL(devm_ti_sci_get_resource);
>>   
>> +/*
>> + * Enter Partial-IO, which disables everything including DDR with only a small
>> + * logic being active for wakeup.
>> + */
>> +static int ti_sci_enter_partial_io(struct ti_sci_info *info)
>> +{
>> +	struct ti_sci_msg_req_prepare_sleep *req;
>> +	struct ti_sci_xfer *xfer;
>> +	struct device *dev = info->dev;
>> +	int ret = 0;
>> +
>> +	xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_PREPARE_SLEEP,
>> +				   TI_SCI_FLAG_REQ_GENERIC_NORESPONSE,
>> +				   sizeof(*req), sizeof(struct ti_sci_msg_hdr));
>> +	if (IS_ERR(xfer)) {
>> +		ret = PTR_ERR(xfer);
>> +		dev_err(dev, "Message alloc failed(%d)\n", ret);
>> +		return ret;
>> +	}
>> +
>> +	req = (struct ti_sci_msg_req_prepare_sleep *)xfer->xfer_buf;
>> +	req->mode = TISCI_MSG_VALUE_SLEEP_MODE_PARTIAL_IO;
>
> This whole function is almost identical to ti_sci_cmd_prepare_sleep() other
> than you use a different mode here, which this different mode can be passed
> into ti_sci_cmd_prepare_sleep() just the same. Only other difference would
> be the NORESPONSE flag which you could just check "mode" passed in and
> use the right flag for the mode.

I thought this to be nicer as it avoided ifs, but as Kendall and you
both requested this, I changed it for the next version.

>
>> +	req->ctx_lo = 0;
>> +	req->ctx_hi = 0;
>> +	req->debug_flags = 0;
>> +
>> +	ret = ti_sci_do_xfer(info, xfer);
>> +	if (ret) {
>> +		dev_err(dev, "Mbox send fail %d\n", ret);
>> +		goto fail;
>> +	}
>> +
>> +fail:
>> +	ti_sci_put_one_xfer(&info->minfo, xfer);
>> +
>> +	return ret;
>> +}
>> +
>> +/*
>> + * Iterate all device nodes that have a wakeup-source property and check if one
>> + * of the possible phandles points to a Partial-IO system state. If it
>> + * does resolve the device node to an actual device and check if wakeup is
>> + * enabled.
>> + */
>> +static bool ti_sci_partial_io_wakeup_enabled(struct ti_sci_info *info)
>> +{
>> +	struct device_node *wakeup_node = NULL;
>> +
>> +	for_each_node_with_property(wakeup_node, "wakeup-source") {
>> +		struct of_phandle_iterator it;
>> +		int err;
>> +
>> +		of_for_each_phandle(&it, err, wakeup_node, "wakeup-source", NULL, 0) {
>> +			struct platform_device *pdev;
>> +			bool may_wakeup;
>> +
>> +			/*
>> +			 * Continue if idle-state-name is not off-wake. Return
>> +			 * value is the index of the string which should be 0 if
>> +			 * off-wake is present.
>> +			 */
>> +			if (of_property_match_string(it.node, "idle-state-name", "off-wake"))
>> +				continue;
>> +
>> +			pdev = of_find_device_by_node(wakeup_node);
>> +			if (!pdev)
>> +				continue;
>> +
>> +			may_wakeup = device_may_wakeup(&pdev->dev);
>> +			put_device(&pdev->dev);
>> +
>> +			if (may_wakeup) {
>> +				dev_dbg(info->dev, "%pOF identified as wakeup source for Partial-IO\n",
>> +					wakeup_node);
>> +				of_node_put(it.node);
>> +				of_node_put(wakeup_node);
>> +				return true;
>> +			}
>> +		}
>> +	}
>> +
>> +	return false;
>> +}
>> +
>> +static int ti_sci_sys_off_handler(struct sys_off_data *data)
>> +{
>> +	struct ti_sci_info *info = data->cb_data;
>> +	bool enter_partial_io = ti_sci_partial_io_wakeup_enabled(info);
>> +	int ret;
>> +
>> +	if (!enter_partial_io)
>> +		return NOTIFY_DONE;
>> +
>> +	dev_info(info->dev, "Entering Partial-IO because a powered wakeup-enabled device was found.\n");
>> +
>> +	ret = ti_sci_enter_partial_io(info);
>> +
>
> No need for newline here.
>
>> +	if (ret) {
>> +		dev_err(info->dev,
>> +			"Failed to enter Partial-IO %pe, trying to do an emergency restart\n",
>> +			ERR_PTR(ret));
>
> Why cast this int to a pointer before printing it out?

I am casting this to an error pointer to get the resolution of the error
value to a symbolic name with %pe. This will print 'EBUSY' etc.

Thanks!

Best
Markus

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 289 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v9 3/3] firmware: ti_sci: Partial-IO support
  2025-11-03 10:31     ` Markus Schneider-Pargmann
@ 2025-11-03 14:10       ` Andrew Davis
  0 siblings, 0 replies; 10+ messages in thread
From: Andrew Davis @ 2025-11-03 14:10 UTC (permalink / raw)
  To: Markus Schneider-Pargmann, Nishanth Menon, Tero Kristo,
	Santosh Shilimkar
  Cc: Vishal Mahaveer, Kevin Hilman, Dhruva Gole, Sebin Francis,
	Kendall Willis, Akashdeep Kaur, linux-arm-kernel, linux-kernel

On 11/3/25 4:31 AM, Markus Schneider-Pargmann wrote:
> On Thu Oct 30, 2025 at 3:24 PM CET, Andrew Davis wrote:
>> On 10/30/25 4:26 AM, Markus Schneider-Pargmann (TI.com) wrote:
>>> Add support for Partial-IO poweroff. In Partial-IO pins of a few
>>> hardware units can generate system wakeups while DDR memory is not
>>> powered resulting in a fresh boot of the system. These hardware units in
>>> the SoC are always powered so that some logic can detect pin activity.
>>>
>>> If the system supports Partial-IO as described in the fw capabilities, a
>>> sys_off handler is added. This sys_off handler decides if the poweroff
>>> is executed by entering normal poweroff or Partial-IO instead. The
>>> decision is made by checking if wakeup is enabled on all devices that
>>> may wake up the SoC from Partial-IO.
>>>
>>> The possible wakeup devices are found by checking which devices
>>> reference a "Partial-IO" system state in the list of wakeup-source
>>> system states. Only devices that are actually enabled by the user will
>>> be considered as an active wakeup source. If none of the wakeup sources
>>> is enabled the system will do a normal poweroff. If at least one wakeup
>>> source is enabled it will instead send a TI_SCI_MSG_PREPARE_SLEEP
>>> message from the sys_off handler. Sending this message will result in an
>>> immediate shutdown of the system. No execution is expected after this
>>> point. The code will wait for 5s and do an emergency_restart afterwards
>>> if Partial-IO wasn't entered at that point.
>>>
>>> A short documentation about Partial-IO can be found in section 6.2.4.5
>>> of the TRM at
>>>     https://www.ti.com/lit/pdf/spruiv7
>>>
>>> Signed-off-by: Markus Schneider-Pargmann (TI.com) <msp@baylibre.com>
>>> ---
>>>    drivers/firmware/ti_sci.c | 132 +++++++++++++++++++++++++++++++++++++++++++++-
>>>    drivers/firmware/ti_sci.h |   5 ++
>>>    2 files changed, 136 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c
>>> index 4db84a92a517b0aa7bb8d47e809d9848a16e2cc4..f2922fccfbe748a436cb9aa0a8c8e5f48db02ef9 100644
>>> --- a/drivers/firmware/ti_sci.c
>>> +++ b/drivers/firmware/ti_sci.c
>>> @@ -6,6 +6,7 @@
>>>     *	Nishanth Menon
>>>     */
>>>    
>>> +#include "linux/dev_printk.h"
>>>    #define pr_fmt(fmt) "%s: " fmt, __func__
>>>    
>>>    #include <linux/bitmap.h>
>>> @@ -3663,6 +3664,116 @@ devm_ti_sci_get_resource(const struct ti_sci_handle *handle, struct device *dev,
>>>    }
>>>    EXPORT_SYMBOL_GPL(devm_ti_sci_get_resource);
>>>    
>>> +/*
>>> + * Enter Partial-IO, which disables everything including DDR with only a small
>>> + * logic being active for wakeup.
>>> + */
>>> +static int ti_sci_enter_partial_io(struct ti_sci_info *info)
>>> +{
>>> +	struct ti_sci_msg_req_prepare_sleep *req;
>>> +	struct ti_sci_xfer *xfer;
>>> +	struct device *dev = info->dev;
>>> +	int ret = 0;
>>> +
>>> +	xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_PREPARE_SLEEP,
>>> +				   TI_SCI_FLAG_REQ_GENERIC_NORESPONSE,
>>> +				   sizeof(*req), sizeof(struct ti_sci_msg_hdr));
>>> +	if (IS_ERR(xfer)) {
>>> +		ret = PTR_ERR(xfer);
>>> +		dev_err(dev, "Message alloc failed(%d)\n", ret);
>>> +		return ret;
>>> +	}
>>> +
>>> +	req = (struct ti_sci_msg_req_prepare_sleep *)xfer->xfer_buf;
>>> +	req->mode = TISCI_MSG_VALUE_SLEEP_MODE_PARTIAL_IO;
>>
>> This whole function is almost identical to ti_sci_cmd_prepare_sleep() other
>> than you use a different mode here, which this different mode can be passed
>> into ti_sci_cmd_prepare_sleep() just the same. Only other difference would
>> be the NORESPONSE flag which you could just check "mode" passed in and
>> use the right flag for the mode.
> 
> I thought this to be nicer as it avoided ifs, but as Kendall and you
> both requested this, I changed it for the next version.
> 
>>
>>> +	req->ctx_lo = 0;
>>> +	req->ctx_hi = 0;
>>> +	req->debug_flags = 0;
>>> +
>>> +	ret = ti_sci_do_xfer(info, xfer);
>>> +	if (ret) {
>>> +		dev_err(dev, "Mbox send fail %d\n", ret);
>>> +		goto fail;
>>> +	}
>>> +
>>> +fail:
>>> +	ti_sci_put_one_xfer(&info->minfo, xfer);
>>> +
>>> +	return ret;
>>> +}
>>> +
>>> +/*
>>> + * Iterate all device nodes that have a wakeup-source property and check if one
>>> + * of the possible phandles points to a Partial-IO system state. If it
>>> + * does resolve the device node to an actual device and check if wakeup is
>>> + * enabled.
>>> + */
>>> +static bool ti_sci_partial_io_wakeup_enabled(struct ti_sci_info *info)
>>> +{
>>> +	struct device_node *wakeup_node = NULL;
>>> +
>>> +	for_each_node_with_property(wakeup_node, "wakeup-source") {
>>> +		struct of_phandle_iterator it;
>>> +		int err;
>>> +
>>> +		of_for_each_phandle(&it, err, wakeup_node, "wakeup-source", NULL, 0) {
>>> +			struct platform_device *pdev;
>>> +			bool may_wakeup;
>>> +
>>> +			/*
>>> +			 * Continue if idle-state-name is not off-wake. Return
>>> +			 * value is the index of the string which should be 0 if
>>> +			 * off-wake is present.
>>> +			 */
>>> +			if (of_property_match_string(it.node, "idle-state-name", "off-wake"))
>>> +				continue;
>>> +
>>> +			pdev = of_find_device_by_node(wakeup_node);
>>> +			if (!pdev)
>>> +				continue;
>>> +
>>> +			may_wakeup = device_may_wakeup(&pdev->dev);
>>> +			put_device(&pdev->dev);
>>> +
>>> +			if (may_wakeup) {
>>> +				dev_dbg(info->dev, "%pOF identified as wakeup source for Partial-IO\n",
>>> +					wakeup_node);
>>> +				of_node_put(it.node);
>>> +				of_node_put(wakeup_node);
>>> +				return true;
>>> +			}
>>> +		}
>>> +	}
>>> +
>>> +	return false;
>>> +}
>>> +
>>> +static int ti_sci_sys_off_handler(struct sys_off_data *data)
>>> +{
>>> +	struct ti_sci_info *info = data->cb_data;
>>> +	bool enter_partial_io = ti_sci_partial_io_wakeup_enabled(info);
>>> +	int ret;
>>> +
>>> +	if (!enter_partial_io)
>>> +		return NOTIFY_DONE;
>>> +
>>> +	dev_info(info->dev, "Entering Partial-IO because a powered wakeup-enabled device was found.\n");
>>> +
>>> +	ret = ti_sci_enter_partial_io(info);
>>> +
>>
>> No need for newline here.
>>
>>> +	if (ret) {
>>> +		dev_err(info->dev,
>>> +			"Failed to enter Partial-IO %pe, trying to do an emergency restart\n",
>>> +			ERR_PTR(ret));
>>
>> Why cast this int to a pointer before printing it out?
> 
> I am casting this to an error pointer to get the resolution of the error
> value to a symbolic name with %pe. This will print 'EBUSY' etc.
> 

Ah I see, but why not use errname() directly? I see dev_err_probe() also goes though
a ERR_PTR() cast, so maybe there is some reason I'm not seeing, so I'm fine either way.

Thanks,
Andrew

> Thanks!
> 
> Best
> Markus


^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2025-11-03 14:10 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-10-30  9:26 [PATCH v9 0/3] firmware: ti_sci: Partial-IO support Markus Schneider-Pargmann (TI.com)
2025-10-30  9:26 ` [PATCH v9 1/3] firmware: ti_sci: Remove constant 0 function arguments Markus Schneider-Pargmann (TI.com)
2025-10-30 14:13   ` Andrew Davis
2025-10-30 16:57     ` Markus Schneider-Pargmann
2025-10-30  9:26 ` [PATCH v9 2/3] firmware: ti_sci: Support transfers without response Markus Schneider-Pargmann (TI.com)
2025-10-30  9:26 ` [PATCH v9 3/3] firmware: ti_sci: Partial-IO support Markus Schneider-Pargmann (TI.com)
2025-10-30 14:24   ` Andrew Davis
2025-11-03 10:31     ` Markus Schneider-Pargmann
2025-11-03 14:10       ` Andrew Davis
2025-11-01 16:25   ` kernel test robot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®