* [PATCH v7 0/2] firmware: ti_sci: Partial-IO support
@ 2025-08-12 9:19 Markus Schneider-Pargmann
2025-08-12 9:19 ` [PATCH v7 1/2] firmware: ti_sci: Support transfers without response Markus Schneider-Pargmann
2025-08-12 9:19 ` [PATCH v7 2/2] firmware: ti_sci: Partial-IO support Markus Schneider-Pargmann
0 siblings, 2 replies; 6+ messages in thread
From: Markus Schneider-Pargmann @ 2025-08-12 9:19 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
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. m_can driver series: Implements device-specific wakeup functionality
for m_can devices, allowing them to be set as wakeup sources.
https://gitlab.baylibre.com/msp8/linux/-/tree/topic/mcan-wakeup-source/v6.17?ref_type=heads
https://lore.kernel.org/r/20250812-topic-mcan-wakeup-source-v6-12-v8-0-6972a810d63b@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.17?ref_type=heads
https://lore.kernel.org/r/20250812-topic-am62-dt-partialio-v6-15-v2-0-25352364a0ac@baylibre.com
3. This series (TI-SCI firmware): Implements the firmware interface to enter
Partial-IO mode when appropriate wakeup sources are enabled.
Devicetree Bindings
-------------------
This series depends on the dt-schema pull request that adds bindings for
system-idle-states and updates the binding for wakeup-source:
https://github.com/devicetree-org/dt-schema/pull/150
This is now merged. These new bindings allow the ti-sci driver to
identify devices that can act as wakeup sources for specific system
states like Partial-IO.
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.17?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
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 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 <msp@baylibre.com>
---
Markus Schneider-Pargmann (2):
firmware: ti_sci: Support transfers without response
firmware: ti_sci: Partial-IO support
drivers/firmware/ti_sci.c | 138 +++++++++++++++++++++++++++++++++++++++++++++-
drivers/firmware/ti_sci.h | 5 ++
2 files changed, 140 insertions(+), 3 deletions(-)
---
base-commit: 062b3e4a1f880f104a8d4b90b767788786aa7b78
change-id: 20241008-topic-am62-partialio-v6-12-b4-c273fbac4447
prerequisite-change-id: 20241009-topic-mcan-wakeup-source-v6-12-8c1d69931bd8:v8
prerequisite-patch-id: 02b7142f56c849c9a3faab2d2871805febd647aa
prerequisite-patch-id: 830b339ea452edd750b04f719da91e721be630cb
prerequisite-patch-id: 2c9142d2bc47e64c49b7b8a7ca20a62a0be14870
prerequisite-patch-id: f7652a616dca17fd5e4a7e5cba59de6a6a36079f
prerequisite-change-id: 20250415-topic-am62-dt-partialio-v6-15-327dd1ff17da:v2
prerequisite-patch-id: 33c717bb60c1d01f8cc7118916c23c7c0b2199a8
prerequisite-patch-id: 707e4619d7b844e1b67ccde28b4484b7b0d27daa
prerequisite-patch-id: 412feb5d3fc125e489d11b726c0b2d8fd5ff36f3
prerequisite-patch-id: 4e3ed635267f9548b9ac7a9e440971bb1e54a5ee
prerequisite-patch-id: e0330ef081affbe91e02b2e9b5a76ebab59e6ea6
prerequisite-patch-id: 8ed14e4861cf2fb4ce2dc2712222ad4d956746d7
prerequisite-patch-id: 7b961aadd7a3298eb8ad245f173e1c5e47b37be9
Best regards,
--
Markus Schneider-Pargmann <msp@baylibre.com>
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v7 1/2] firmware: ti_sci: Support transfers without response
2025-08-12 9:19 [PATCH v7 0/2] firmware: ti_sci: Partial-IO support Markus Schneider-Pargmann
@ 2025-08-12 9:19 ` Markus Schneider-Pargmann
2025-09-23 16:38 ` Kendall Willis
2025-08-12 9:19 ` [PATCH v7 2/2] firmware: ti_sci: Partial-IO support Markus Schneider-Pargmann
1 sibling, 1 reply; 6+ messages in thread
From: Markus Schneider-Pargmann @ 2025-08-12 9:19 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
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.
Signed-off-by: Markus Schneider-Pargmann <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 ae5fd1936ad322e5e3a94897cc042f6548f919e6..c187fb714b3a4c658d0593c844716d4b160e4fa9 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.50.1
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v7 2/2] firmware: ti_sci: Partial-IO support
2025-08-12 9:19 [PATCH v7 0/2] firmware: ti_sci: Partial-IO support Markus Schneider-Pargmann
2025-08-12 9:19 ` [PATCH v7 1/2] firmware: ti_sci: Support transfers without response Markus Schneider-Pargmann
@ 2025-08-12 9:19 ` Markus Schneider-Pargmann
2025-09-23 17:49 ` Kendall Willis
1 sibling, 1 reply; 6+ messages in thread
From: Markus Schneider-Pargmann @ 2025-08-12 9:19 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
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 <msp@baylibre.com>
---
drivers/firmware/ti_sci.c | 131 +++++++++++++++++++++++++++++++++++++++++++++-
drivers/firmware/ti_sci.h | 5 ++
2 files changed, 135 insertions(+), 1 deletion(-)
diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c
index c187fb714b3a4c658d0593c844716d4b160e4fa9..fb6f3d7f7413917cf9534ba65f0a9786d1183c71 100644
--- a/drivers/firmware/ti_sci.c
+++ b/drivers/firmware/ti_sci.c
@@ -3750,6 +3750,116 @@ static const struct dev_pm_ops ti_sci_pm_ops = {
#endif
};
+/*
+ * 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;
+
+ dev_info(dev, "Entering Partial-IO because a powered wakeup-enabled device was found.\n");
+
+ 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;
+
+ 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;
+}
+
/* Description for K2G */
static const struct ti_sci_desc ti_sci_pmmc_k2g_desc = {
.default_host_id = 2,
@@ -3893,6 +4003,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,
@@ -3902,7 +4025,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 053387d7baa064498e6a208daa7f70040ef87281..006a3d40ba040f12d0b2dff7fce49b4eefa52517 100644
--- a/drivers/firmware/ti_sci.h
+++ b/drivers/firmware/ti_sci.h
@@ -592,6 +592,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.50.1
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v7 1/2] firmware: ti_sci: Support transfers without response
2025-08-12 9:19 ` [PATCH v7 1/2] firmware: ti_sci: Support transfers without response Markus Schneider-Pargmann
@ 2025-09-23 16:38 ` Kendall Willis
0 siblings, 0 replies; 6+ messages in thread
From: Kendall Willis @ 2025-09-23 16:38 UTC (permalink / raw)
To: Markus Schneider-Pargmann
Cc: Nishanth Menon, Tero Kristo, Santosh Shilimkar, Vishal Mahaveer,
Kevin Hilman, Dhruva Gole, Sebin Francis, Akashdeep Kaur,
linux-arm-kernel, linux-kernel
On 11:19-20250812, Markus Schneider-Pargmann wrote:
> 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.
>
> Signed-off-by: Markus Schneider-Pargmann <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 ae5fd1936ad322e5e3a94897cc042f6548f919e6..c187fb714b3a4c658d0593c844716d4b160e4fa9 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.50.1
>
Reviewed-by: Kendall Willis <k-willis@ti.com>
Best,
Kendall Willis
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v7 2/2] firmware: ti_sci: Partial-IO support
2025-08-12 9:19 ` [PATCH v7 2/2] firmware: ti_sci: Partial-IO support Markus Schneider-Pargmann
@ 2025-09-23 17:49 ` Kendall Willis
2025-09-26 9:24 ` Markus Schneider-Pargmann
0 siblings, 1 reply; 6+ messages in thread
From: Kendall Willis @ 2025-09-23 17:49 UTC (permalink / raw)
To: Markus Schneider-Pargmann
Cc: Nishanth Menon, Tero Kristo, Santosh Shilimkar, Vishal Mahaveer,
Kevin Hilman, Dhruva Gole, Sebin Francis, Akashdeep Kaur,
linux-arm-kernel, linux-kernel
Hi Markus,
On 11:19-20250812, Markus Schneider-Pargmann 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 <msp@baylibre.com>
> ---
> drivers/firmware/ti_sci.c | 131 +++++++++++++++++++++++++++++++++++++++++++++-
> drivers/firmware/ti_sci.h | 5 ++
> 2 files changed, 135 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c
> index c187fb714b3a4c658d0593c844716d4b160e4fa9..fb6f3d7f7413917cf9534ba65f0a9786d1183c71 100644
> --- a/drivers/firmware/ti_sci.c
> +++ b/drivers/firmware/ti_sci.c
> @@ -3750,6 +3750,116 @@ static const struct dev_pm_ops ti_sci_pm_ops = {
> #endif
> };
>
> +/*
> + * 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;
> +
> + dev_info(dev, "Entering Partial-IO because a powered wakeup-enabled device was found.\n");
> +
IMO this print should be in the ti_sci_sys_off_handler since that is
where the check is to find the wakeup-enabled device.
> + 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;
> +}
> +
Just something to think about: another way to implement this function
would be to change ti_sci_cmd_prepare_sleep to add a parameter of flags
for ti_sci_get_one_xfer in order to be able to choose if the
TI_SCI_FLAG_REQ_GENERIC_NORESPONSE or TI_SCI_FLAG_REQ_ACK_ON_PROCESSED
is used. This would make it so there's not duplicated code and
ti_sci_cmd_prepare_sleep could be used to enter partial IO.
> +/*
> + * 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;
> +
> + 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;
> +}
> +
> /* Description for K2G */
nit: Might be nicer to move code before 'static const struct dev_pm_ops
ti_sci_pm_ops' to keep all the 'static const struct's together.
> static const struct ti_sci_desc ti_sci_pmmc_k2g_desc = {
> .default_host_id = 2,
> @@ -3893,6 +4003,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,
> @@ -3902,7 +4025,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;
> +
Should this be a separate commit since it doesn't have anything to do
with the Partial IO functionality? This looks like a bug fix.
Best,
Kendall Willis
> 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 053387d7baa064498e6a208daa7f70040ef87281..006a3d40ba040f12d0b2dff7fce49b4eefa52517 100644
> --- a/drivers/firmware/ti_sci.h
> +++ b/drivers/firmware/ti_sci.h
> @@ -592,6 +592,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.50.1
>
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v7 2/2] firmware: ti_sci: Partial-IO support
2025-09-23 17:49 ` Kendall Willis
@ 2025-09-26 9:24 ` Markus Schneider-Pargmann
0 siblings, 0 replies; 6+ messages in thread
From: Markus Schneider-Pargmann @ 2025-09-26 9:24 UTC (permalink / raw)
To: Kendall Willis, Markus Schneider-Pargmann
Cc: Nishanth Menon, Tero Kristo, Santosh Shilimkar, Vishal Mahaveer,
Kevin Hilman, Dhruva Gole, Sebin Francis, Akashdeep Kaur,
linux-arm-kernel, linux-kernel
[-- Attachment #1: Type: text/plain, Size: 4405 bytes --]
Hi Kendall,
On Tue Sep 23, 2025 at 7:49 PM CEST, Kendall Willis wrote:
> Hi Markus,
>
> On 11:19-20250812, Markus Schneider-Pargmann 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 <msp@baylibre.com>
>> ---
>> drivers/firmware/ti_sci.c | 131 +++++++++++++++++++++++++++++++++++++++++++++-
>> drivers/firmware/ti_sci.h | 5 ++
>> 2 files changed, 135 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c
>> index c187fb714b3a4c658d0593c844716d4b160e4fa9..fb6f3d7f7413917cf9534ba65f0a9786d1183c71 100644
>> --- a/drivers/firmware/ti_sci.c
>> +++ b/drivers/firmware/ti_sci.c
>> @@ -3750,6 +3750,116 @@ static const struct dev_pm_ops ti_sci_pm_ops = {
>> #endif
>> };
>>
>> +/*
>> + * 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;
>> +
>> + dev_info(dev, "Entering Partial-IO because a powered wakeup-enabled device was found.\n");
>> +
>
> IMO this print should be in the ti_sci_sys_off_handler since that is
> where the check is to find the wakeup-enabled device.
>
>> + 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;
>> +}
>> +
>
> Just something to think about: another way to implement this function
> would be to change ti_sci_cmd_prepare_sleep to add a parameter of flags
> for ti_sci_get_one_xfer in order to be able to choose if the
> TI_SCI_FLAG_REQ_GENERIC_NORESPONSE or TI_SCI_FLAG_REQ_ACK_ON_PROCESSED
> is used. This would make it so there's not duplicated code and
> ti_sci_cmd_prepare_sleep could be used to enter partial IO.
Thanks for the suggestion, I just tried your approach and I personally
prefer the code as it is. I needed two additional ifs to switch to a
different rx_message_size and handle or not handle a response. In the
end there is not much common code left. Also the pattern is quite common
between many of the functions doing transfers.
Thanks for your review, I fixed the rest.
Best
Markus
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 289 bytes --]
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2025-09-26 9:25 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-08-12 9:19 [PATCH v7 0/2] firmware: ti_sci: Partial-IO support Markus Schneider-Pargmann
2025-08-12 9:19 ` [PATCH v7 1/2] firmware: ti_sci: Support transfers without response Markus Schneider-Pargmann
2025-09-23 16:38 ` Kendall Willis
2025-08-12 9:19 ` [PATCH v7 2/2] firmware: ti_sci: Partial-IO support Markus Schneider-Pargmann
2025-09-23 17:49 ` Kendall Willis
2025-09-26 9:24 ` Markus Schneider-Pargmann
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®