]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
firmware: ti_sci: Enable abort handling of entry to LPM
authorKendall Willis <k-willis@ti.com>
Tue, 19 Aug 2025 19:54:53 +0000 (14:54 -0500)
committerNishanth Menon <nm@ti.com>
Fri, 22 Aug 2025 18:22:00 +0000 (13:22 -0500)
The PM co-processor (device manager or DM) adds the ability to abort
entry to a low power mode by clearing the mode selection in the
latest version of its firmware (11.01.09) [1].

Enable the ti_sci driver to support the LPM abort call which clears the
low power mode selection of the DM. This fixes an issue where failed
system suspend attempts would cause subsequent suspends to fail.

After system suspend completes, regardless of if system suspend succeeds
or fails, the ->complete() hook in TI SCI will be called. In the
->complete() hook, a message will be sent to the DM to clear the current
low power mode selection. Clearing the low power mode selection
unconditionally will not cause any error in the DM.

[1] https://software-dl.ti.com/tisci/esd/latest/2_tisci_msgs/pm/lpm.html

Signed-off-by: Kendall Willis <k-willis@ti.com>
Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org>
Link: https://patch.msgid.link/20250819195453.1094520-1-k-willis@ti.com
Signed-off-by: Nishanth Menon <nm@ti.com>
drivers/firmware/ti_sci.c
drivers/firmware/ti_sci.h

index ae5fd1936ad322e5e3a94897cc042f6548f919e6..49fd2ae01055d0f425062147422471f0fd49e4bd 100644 (file)
@@ -2015,6 +2015,47 @@ fail:
        return ret;
 }
 
+/**
+ * ti_sci_cmd_lpm_abort() - Abort entry to LPM by clearing selection of LPM to enter
+ * @dev:       Device pointer corresponding to the SCI entity
+ *
+ * Return: 0 if all went well, else returns appropriate error value.
+ */
+static int ti_sci_cmd_lpm_abort(struct device *dev)
+{
+       struct ti_sci_info *info = dev_get_drvdata(dev);
+       struct ti_sci_msg_hdr *req;
+       struct ti_sci_msg_hdr *resp;
+       struct ti_sci_xfer *xfer;
+       int ret = 0;
+
+       xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_LPM_ABORT,
+                                  TI_SCI_FLAG_REQ_ACK_ON_PROCESSED,
+                                  sizeof(*req), sizeof(*resp));
+       if (IS_ERR(xfer)) {
+               ret = PTR_ERR(xfer);
+               dev_err(dev, "Message alloc failed(%d)\n", ret);
+               return ret;
+       }
+       req = (struct ti_sci_msg_hdr *)xfer->xfer_buf;
+
+       ret = ti_sci_do_xfer(info, xfer);
+       if (ret) {
+               dev_err(dev, "Mbox send fail %d\n", ret);
+               goto fail;
+       }
+
+       resp = (struct ti_sci_msg_hdr *)xfer->xfer_buf;
+
+       if (!ti_sci_is_response_ack(resp))
+               ret = -ENODEV;
+
+fail:
+       ti_sci_put_one_xfer(&info->minfo, xfer);
+
+       return ret;
+}
+
 static int ti_sci_cmd_core_reboot(const struct ti_sci_handle *handle)
 {
        struct ti_sci_info *info;
@@ -3739,11 +3780,22 @@ static int __maybe_unused ti_sci_resume_noirq(struct device *dev)
        return 0;
 }
 
+static void __maybe_unused ti_sci_pm_complete(struct device *dev)
+{
+       struct ti_sci_info *info = dev_get_drvdata(dev);
+
+       if (info->fw_caps & MSG_FLAG_CAPS_LPM_ABORT) {
+               if (ti_sci_cmd_lpm_abort(dev))
+                       dev_err(dev, "LPM clear selection failed.\n");
+       }
+}
+
 static const struct dev_pm_ops ti_sci_pm_ops = {
 #ifdef CONFIG_PM_SLEEP
        .suspend = ti_sci_suspend,
        .suspend_noirq = ti_sci_suspend_noirq,
        .resume_noirq = ti_sci_resume_noirq,
+       .complete = ti_sci_pm_complete,
 #endif
 };
 
@@ -3876,10 +3928,11 @@ static int ti_sci_probe(struct platform_device *pdev)
        }
 
        ti_sci_msg_cmd_query_fw_caps(&info->handle, &info->fw_caps);
-       dev_dbg(dev, "Detected firmware capabilities: %s%s%s\n",
+       dev_dbg(dev, "Detected firmware capabilities: %s%s%s%s\n",
                info->fw_caps & MSG_FLAG_CAPS_GENERIC ? "Generic" : "",
                info->fw_caps & MSG_FLAG_CAPS_LPM_PARTIAL_IO ? " Partial-IO" : "",
-               info->fw_caps & MSG_FLAG_CAPS_LPM_DM_MANAGED ? " DM-Managed" : ""
+               info->fw_caps & MSG_FLAG_CAPS_LPM_DM_MANAGED ? " DM-Managed" : "",
+               info->fw_caps & MSG_FLAG_CAPS_LPM_ABORT ? " LPM-Abort" : ""
        );
 
        ti_sci_setup_ops(info);
index 053387d7baa064498e6a208daa7f70040ef87281..701c416b2e78f8ef20ce6741a88ffa6fd4853b2d 100644 (file)
@@ -42,6 +42,7 @@
 #define TI_SCI_MSG_SET_IO_ISOLATION    0x0307
 #define TI_SCI_MSG_LPM_SET_DEVICE_CONSTRAINT   0x0309
 #define TI_SCI_MSG_LPM_SET_LATENCY_CONSTRAINT  0x030A
+#define TI_SCI_MSG_LPM_ABORT   0x0311
 
 /* Resource Management Requests */
 #define TI_SCI_MSG_GET_RESOURCE_RANGE  0x1500
@@ -147,6 +148,7 @@ struct ti_sci_msg_req_reboot {
  *             MSG_FLAG_CAPS_GENERIC: Generic capability (LPM not supported)
  *             MSG_FLAG_CAPS_LPM_PARTIAL_IO: Partial IO in LPM
  *             MSG_FLAG_CAPS_LPM_DM_MANAGED: LPM can be managed by DM
+ *             MSG_FLAG_CAPS_LPM_ABORT: Abort entry to LPM
  *
  * Response to a generic message with message type TI_SCI_MSG_QUERY_FW_CAPS
  * providing currently available SOC/firmware capabilities. SoC that don't
@@ -157,6 +159,7 @@ struct ti_sci_msg_resp_query_fw_caps {
 #define MSG_FLAG_CAPS_GENERIC          TI_SCI_MSG_FLAG(0)
 #define MSG_FLAG_CAPS_LPM_PARTIAL_IO   TI_SCI_MSG_FLAG(4)
 #define MSG_FLAG_CAPS_LPM_DM_MANAGED   TI_SCI_MSG_FLAG(5)
+#define MSG_FLAG_CAPS_LPM_ABORT                TI_SCI_MSG_FLAG(9)
 #define MSG_MASK_CAPS_LPM              GENMASK_ULL(4, 1)
        u64 fw_caps;
 } __packed;