[PATCH v2 20/22] firmware: ti: ti_sci_pm: Move pm ops into its own file
From: Beleswar Padhi
Date: Wed Sep 30 2026 - 13:31:22 EST
From: Andrew Davis <afd@xxxxxx>
Extract the power management operations related functions and services
from ti_sci_core.c into its own file. This breaks down the single
large file into smaller logical files for better readability and
maintenance.
The pm ops need access to the TI SCI instance to get the device used for
error reporting. Move struct ti_sci_xfer, struct ti_sci_xfers_info,
struct ti_sci_desc, struct ti_sci_info and handle_to_ti_sci_info() from
ti_sci_core.c into ti_sci.h, along with the includes they need, so that
they can be shared with the split files. Upcoming splits also need
access to the instance state, so this is done once here.
Signed-off-by: Andrew Davis <afd@xxxxxx>
Co-developed-by: Beleswar Padhi <b-padhi@xxxxxx>
Signed-off-by: Beleswar Padhi <b-padhi@xxxxxx>
---
v2: Changelog:
1. None to this patch.
Link to v1:
https://lore.kernel.org/all/20260929201746.4078803-21-b-padhi@xxxxxx/
drivers/firmware/ti/Makefile | 1 +
drivers/firmware/ti/ti_sci.h | 100 ++++++++++++++
drivers/firmware/ti/ti_sci_core.c | 220 +-----------------------------
drivers/firmware/ti/ti_sci_pm.c | 145 ++++++++++++++++++++
4 files changed, 247 insertions(+), 219 deletions(-)
create mode 100644 drivers/firmware/ti/ti_sci_pm.c
diff --git a/drivers/firmware/ti/Makefile b/drivers/firmware/ti/Makefile
index c4233542ad57d..bbfe73587a3c7 100644
--- a/drivers/firmware/ti/Makefile
+++ b/drivers/firmware/ti/Makefile
@@ -3,4 +3,5 @@
ti_sci-y := ti_sci_core.o
ti_sci-y += ti_sci_clock.o
ti_sci-y += ti_sci_device.o
+ti_sci-y += ti_sci_pm.o
obj-$(CONFIG_TI_SCI_PROTOCOL) += ti_sci.o
diff --git a/drivers/firmware/ti/ti_sci.h b/drivers/firmware/ti/ti_sci.h
index cce59cac35ed6..7a707c632276e 100644
--- a/drivers/firmware/ti/ti_sci.h
+++ b/drivers/firmware/ti/ti_sci.h
@@ -13,8 +13,107 @@
#define __TI_SCI_H
#include <linux/compiler_types.h>
+#include <linux/completion.h>
+#include <linux/container_of.h>
+#include <linux/hashtable.h>
+#include <linux/mailbox_client.h>
+#include <linux/mutex.h>
+#include <linux/semaphore.h>
+#include <linux/soc/ti/ti-msgmgr.h>
+#include <linux/soc/ti/ti_sci_protocol.h>
+#include <linux/spinlock.h>
#include <linux/types.h>
+/**
+ * struct ti_sci_xfer - Structure representing a message flow
+ * @tx_message: Transmit message
+ * @rx_buf: Pointer to store received message
+ * @rx_len: Receive message length
+ * @done: completion event
+ */
+struct ti_sci_xfer {
+ struct ti_msgmgr_message tx_message;
+ void *rx_buf;
+ u8 rx_len;
+ struct completion done;
+};
+
+/**
+ * struct ti_sci_xfers_info - Structure to manage transfer information
+ * @sem_xfer_count: Counting Semaphore for managing max simultaneous
+ * Messages.
+ * @xfer_block: Preallocated Message array
+ * @xfer_alloc_table: Bitmap table for allocated messages.
+ * Index of this bitmap table is also used for message
+ * sequence identifier.
+ * @xfer_lock: Protection for message allocation
+ */
+struct ti_sci_xfers_info {
+ struct semaphore sem_xfer_count;
+ struct ti_sci_xfer *xfer_block;
+ unsigned long *xfer_alloc_table;
+ /* protect transfer allocation */
+ spinlock_t xfer_lock;
+};
+
+/**
+ * struct ti_sci_desc - Description of SoC integration
+ * @default_host_id: Host identifier representing the compute entity
+ * @max_rx_timeout_ms: Timeout for communication with SoC (in Milliseconds)
+ * @max_msgs: Maximum number of messages that can be pending
+ * simultaneously in the system
+ * @max_msg_size: Maximum size of data per message that can be handled.
+ */
+struct ti_sci_desc {
+ u8 default_host_id;
+ int max_rx_timeout_ms;
+ int max_msgs;
+ int max_msg_size;
+};
+
+/**
+ * struct ti_sci_info - Structure representing a TI SCI instance
+ * @dev: Device pointer
+ * @desc: SoC description for this instance
+ * @d: Debugfs file entry
+ * @debug_region: Memory region where the debug message are available
+ * @debug_region_size: Debug region size
+ * @debug_buffer: Buffer allocated to copy debug messages.
+ * @handle: Instance of TI SCI handle to send to clients.
+ * @cl: Mailbox Client
+ * @chan_tx: Transmit mailbox channel
+ * @chan_rx: Receive mailbox channel
+ * @minfo: Message info
+ * @node: list head
+ * @irqs: List of allocated irqs
+ * @irq_lock: Protection for irq hash list
+ * @host_id: Host ID
+ * @fw_caps: FW/SoC low power capabilities
+ * @users: Number of users of this instance
+ */
+struct ti_sci_info {
+ struct device *dev;
+ const struct ti_sci_desc *desc;
+ struct dentry *d;
+ void __iomem *debug_region;
+ char *debug_buffer;
+ size_t debug_region_size;
+ struct ti_sci_handle handle;
+ struct mbox_client cl;
+ struct mbox_chan *chan_tx;
+ struct mbox_chan *chan_rx;
+ struct ti_sci_xfers_info minfo;
+ struct list_head node;
+ DECLARE_HASHTABLE(irqs, 8);
+ struct mutex irq_lock;
+ u8 host_id;
+ u64 fw_caps;
+ /* protected by ti_sci_list_mutex */
+ int users;
+};
+
+#define handle_to_ti_sci_info(h) container_of(h, struct ti_sci_info, handle)
+
/* Generic Messages */
#define TI_SCI_MSG_ENABLE_WDT 0x0000
#define TI_SCI_MSG_WAKE_RESET 0x0001
@@ -1567,5 +1666,6 @@ int ti_sci_do_xfer(const struct ti_sci_handle *handle,
void ti_sci_setup_device_ops(struct ti_sci_dev_ops *dops);
void ti_sci_setup_clock_ops(struct ti_sci_clk_ops *cops);
+void ti_sci_setup_pm_ops(struct ti_sci_pm_ops *pmops);
#endif /* __TI_SCI_H */
diff --git a/drivers/firmware/ti/ti_sci_core.c b/drivers/firmware/ti/ti_sci_core.c
index 848c040f598e0..60d0d64ac4ae8 100644
--- a/drivers/firmware/ti/ti_sci_core.c
+++ b/drivers/firmware/ti/ti_sci_core.c
@@ -13,11 +13,9 @@
#include <linux/cpu.h>
#include <linux/debugfs.h>
#include <linux/export.h>
-#include <linux/hashtable.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/kernel.h>
-#include <linux/mailbox_client.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
@@ -25,10 +23,7 @@
#include <linux/platform_device.h>
#include <linux/pm_qos.h>
#include <linux/property.h>
-#include <linux/semaphore.h>
#include <linux/slab.h>
-#include <linux/soc/ti/ti-msgmgr.h>
-#include <linux/soc/ti/ti_sci_protocol.h>
#include <linux/suspend.h>
#include <linux/sys_soc.h>
#include <linux/reboot.h>
@@ -40,53 +35,6 @@ static LIST_HEAD(ti_sci_list);
/* Protection for the entire list */
static DEFINE_MUTEX(ti_sci_list_mutex);
-/**
- * struct ti_sci_xfer - Structure representing a message flow
- * @tx_message: Transmit message
- * @rx_buf: Pointer to store received message
- * @rx_len: Receive message length
- * @done: completion event
- */
-struct ti_sci_xfer {
- struct ti_msgmgr_message tx_message;
- void *rx_buf;
- u8 rx_len;
- struct completion done;
-};
-
-/**
- * struct ti_sci_xfers_info - Structure to manage transfer information
- * @sem_xfer_count: Counting Semaphore for managing max simultaneous
- * Messages.
- * @xfer_block: Preallocated Message array
- * @xfer_alloc_table: Bitmap table for allocated messages.
- * Index of this bitmap table is also used for message
- * sequence identifier.
- * @xfer_lock: Protection for message allocation
- */
-struct ti_sci_xfers_info {
- struct semaphore sem_xfer_count;
- struct ti_sci_xfer *xfer_block;
- unsigned long *xfer_alloc_table;
- /* protect transfer allocation */
- spinlock_t xfer_lock;
-};
-
-/**
- * struct ti_sci_desc - Description of SoC integration
- * @default_host_id: Host identifier representing the compute entity
- * @max_rx_timeout_ms: Timeout for communication with SoC (in Milliseconds)
- * @max_msgs: Maximum number of messages that can be pending
- * simultaneously in the system
- * @max_msg_size: Maximum size of data per message that can be handled.
- */
-struct ti_sci_desc {
- u8 default_host_id;
- int max_rx_timeout_ms;
- int max_msgs;
- int max_msg_size;
-};
-
/**
* struct ti_sci_irq - Description of allocated irqs
* @node: Link to hash table
@@ -97,49 +45,7 @@ struct ti_sci_irq {
struct ti_sci_msg_req_manage_irq desc;
};
-/**
- * struct ti_sci_info - Structure representing a TI SCI instance
- * @dev: Device pointer
- * @desc: SoC description for this instance
- * @d: Debugfs file entry
- * @debug_region: Memory region where the debug message are available
- * @debug_region_size: Debug region size
- * @debug_buffer: Buffer allocated to copy debug messages.
- * @handle: Instance of TI SCI handle to send to clients.
- * @cl: Mailbox Client
- * @chan_tx: Transmit mailbox channel
- * @chan_rx: Receive mailbox channel
- * @minfo: Message info
- * @node: list head
- * @irqs: List of allocated irqs
- * @irq_lock: Protection for irq hash list
- * @host_id: Host ID
- * @fw_caps: FW/SoC low power capabilities
- * @users: Number of users of this instance
- */
-struct ti_sci_info {
- struct device *dev;
- const struct ti_sci_desc *desc;
- struct dentry *d;
- void __iomem *debug_region;
- char *debug_buffer;
- size_t debug_region_size;
- struct ti_sci_handle handle;
- struct mbox_client cl;
- struct mbox_chan *chan_tx;
- struct mbox_chan *chan_rx;
- struct ti_sci_xfers_info minfo;
- struct list_head node;
- DECLARE_HASHTABLE(irqs, 8);
- struct mutex irq_lock;
- u8 host_id;
- u64 fw_caps;
- /* protected by ti_sci_list_mutex */
- int users;
-};
-
#define cl_to_ti_sci_info(c) container_of(c, struct ti_sci_info, cl)
-#define handle_to_ti_sci_info(h) container_of(h, struct ti_sci_info, handle)
#ifdef CONFIG_DEBUG_FS
@@ -687,128 +593,6 @@ static int ti_sci_cmd_set_io_isolation(const struct ti_sci_handle *handle,
return 0;
}
-/**
- * ti_sci_msg_cmd_lpm_wake_reason() - Get the wakeup source from LPM
- * @handle: Pointer to TI SCI handle
- * @source: The wakeup source that woke the SoC from LPM
- * @timestamp: Timestamp of the wakeup event
- * @pin: The pin that has triggered wake up
- * @mode: The last entered low power mode
- *
- * Return: 0 if all went well, else returns appropriate error value.
- */
-static int ti_sci_msg_cmd_lpm_wake_reason(const struct ti_sci_handle *handle,
- u32 *source, u64 *timestamp, u8 *pin, u8 *mode)
-{
- struct ti_sci_msg_hdr req;
- struct ti_sci_msg_resp_lpm_wake_reason resp;
- struct device *dev;
- int ret = 0;
-
- if (IS_ERR(handle))
- return PTR_ERR(handle);
- if (!handle)
- return -EINVAL;
-
- dev = handle_to_ti_sci_info(handle)->dev;
-
- ret = ti_sci_do_xfer(handle, TI_SCI_MSG_LPM_WAKE_REASON,
- TI_SCI_FLAG_REQ_ACK_ON_PROCESSED,
- &req, sizeof(req),
- &resp, sizeof(resp));
- if (ret) {
- dev_err(dev, "Failed to get wake reason\n");
- return ret;
- }
-
- if (source)
- *source = resp.wake_source;
- if (timestamp)
- *timestamp = resp.wake_timestamp;
- if (pin)
- *pin = resp.wake_pin;
- if (mode)
- *mode = resp.mode;
-
- return 0;
-}
-
-/**
- * ti_sci_cmd_set_device_constraint() - Set LPM constraint on behalf of a device
- * @handle: pointer to TI SCI handle
- * @id: Device identifier
- * @state: The desired state of device constraint: set or clear
- *
- * Return: 0 if all went well, else returns appropriate error value.
- */
-static int ti_sci_cmd_set_device_constraint(const struct ti_sci_handle *handle,
- u32 id, u8 state)
-{
- struct ti_sci_msg_req_lpm_set_device_constraint req;
- struct ti_sci_msg_hdr resp;
- struct device *dev;
- int ret = 0;
-
- if (IS_ERR(handle))
- return PTR_ERR(handle);
- if (!handle)
- return -EINVAL;
-
- dev = handle_to_ti_sci_info(handle)->dev;
-
- req.id = id;
- req.state = state;
-
- ret = ti_sci_do_xfer(handle, TI_SCI_MSG_LPM_SET_DEVICE_CONSTRAINT,
- TI_SCI_FLAG_REQ_ACK_ON_PROCESSED,
- &req, sizeof(req),
- &resp, sizeof(resp));
- if (ret) {
- dev_err(dev, "Failed to set device constraint\n");
- return ret;
- }
-
- return 0;
-}
-
-/**
- * ti_sci_cmd_set_latency_constraint() - Set LPM resume latency constraint
- * @handle: pointer to TI SCI handle
- * @latency: maximum acceptable latency (in ms) to wake up from LPM
- * @state: The desired state of latency constraint: set or clear
- *
- * Return: 0 if all went well, else returns appropriate error value.
- */
-static int ti_sci_cmd_set_latency_constraint(const struct ti_sci_handle *handle,
- u16 latency, u8 state)
-{
- struct ti_sci_msg_req_lpm_set_latency_constraint req;
- struct ti_sci_msg_hdr resp;
- struct device *dev;
- int ret = 0;
-
- if (IS_ERR(handle))
- return PTR_ERR(handle);
- if (!handle)
- return -EINVAL;
-
- dev = handle_to_ti_sci_info(handle)->dev;
-
- req.latency = latency;
- req.state = state;
-
- ret = ti_sci_do_xfer(handle, TI_SCI_MSG_LPM_SET_LATENCY_CONSTRAINT,
- TI_SCI_FLAG_REQ_ACK_ON_PROCESSED,
- &req, sizeof(req),
- &resp, sizeof(resp));
- if (ret) {
- dev_err(dev, "Failed to set device constraint\n");
- return ret;
- }
-
- return 0;
-}
-
/**
* ti_sci_cmd_lpm_abort() - Abort entry to LPM by clearing selection of LPM to enter
* @dev: Device pointer corresponding to the SCI entity
@@ -1708,9 +1492,7 @@ static void ti_sci_setup_ops(struct ti_sci_info *info)
if (info->fw_caps & MSG_FLAG_CAPS_LPM_DM_MANAGED) {
pr_debug("detected DM managed LPM in fw_caps\n");
- pmops->lpm_wake_reason = ti_sci_msg_cmd_lpm_wake_reason;
- pmops->set_device_constraint = ti_sci_cmd_set_device_constraint;
- pmops->set_latency_constraint = ti_sci_cmd_set_latency_constraint;
+ ti_sci_setup_pm_ops(pmops);
}
rm_core_ops->get_range = ti_sci_cmd_get_resource_range;
diff --git a/drivers/firmware/ti/ti_sci_pm.c b/drivers/firmware/ti/ti_sci_pm.c
new file mode 100644
index 0000000000000..6ea09a7e342e7
--- /dev/null
+++ b/drivers/firmware/ti/ti_sci_pm.c
@@ -0,0 +1,145 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Texas Instruments System Control Interface Protocol Driver
+ *
+ * Copyright (C) 2015-2026 Texas Instruments Incorporated - https://www.ti.com/
+ * Nishanth Menon
+ */
+
+#include <linux/errno.h>
+#include <linux/soc/ti/ti_sci_protocol.h>
+
+#include "ti_sci.h"
+
+/**
+ * ti_sci_msg_cmd_lpm_wake_reason() - Get the wakeup source from LPM
+ * @handle: Pointer to TI SCI handle
+ * @source: The wakeup source that woke the SoC from LPM
+ * @timestamp: Timestamp of the wakeup event
+ * @pin: The pin that has triggered wake up
+ * @mode: The last entered low power mode
+ *
+ * Return: 0 if all went well, else returns appropriate error value.
+ */
+static int ti_sci_msg_cmd_lpm_wake_reason(const struct ti_sci_handle *handle,
+ u32 *source, u64 *timestamp, u8 *pin, u8 *mode)
+{
+ struct ti_sci_msg_hdr req;
+ struct ti_sci_msg_resp_lpm_wake_reason resp;
+ struct device *dev;
+ int ret = 0;
+
+ if (IS_ERR(handle))
+ return PTR_ERR(handle);
+ if (!handle)
+ return -EINVAL;
+
+ dev = handle_to_ti_sci_info(handle)->dev;
+
+ ret = ti_sci_do_xfer(handle, TI_SCI_MSG_LPM_WAKE_REASON,
+ TI_SCI_FLAG_REQ_ACK_ON_PROCESSED,
+ &req, sizeof(req),
+ &resp, sizeof(resp));
+ if (ret) {
+ dev_err(dev, "Failed to get wake reason\n");
+ return ret;
+ }
+
+ if (source)
+ *source = resp.wake_source;
+ if (timestamp)
+ *timestamp = resp.wake_timestamp;
+ if (pin)
+ *pin = resp.wake_pin;
+ if (mode)
+ *mode = resp.mode;
+
+ return 0;
+}
+
+/**
+ * ti_sci_cmd_set_device_constraint() - Set LPM constraint on behalf of a device
+ * @handle: pointer to TI SCI handle
+ * @id: Device identifier
+ * @state: The desired state of device constraint: set or clear
+ *
+ * Return: 0 if all went well, else returns appropriate error value.
+ */
+static int ti_sci_cmd_set_device_constraint(const struct ti_sci_handle *handle,
+ u32 id, u8 state)
+{
+ struct ti_sci_msg_req_lpm_set_device_constraint req;
+ struct ti_sci_msg_hdr resp;
+ struct device *dev;
+ int ret = 0;
+
+ if (IS_ERR(handle))
+ return PTR_ERR(handle);
+ if (!handle)
+ return -EINVAL;
+
+ dev = handle_to_ti_sci_info(handle)->dev;
+
+ req.id = id;
+ req.state = state;
+
+ ret = ti_sci_do_xfer(handle, TI_SCI_MSG_LPM_SET_DEVICE_CONSTRAINT,
+ TI_SCI_FLAG_REQ_ACK_ON_PROCESSED,
+ &req, sizeof(req),
+ &resp, sizeof(resp));
+ if (ret) {
+ dev_err(dev, "Failed to set device constraint\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * ti_sci_cmd_set_latency_constraint() - Set LPM resume latency constraint
+ * @handle: pointer to TI SCI handle
+ * @latency: maximum acceptable latency (in ms) to wake up from LPM
+ * @state: The desired state of latency constraint: set or clear
+ *
+ * Return: 0 if all went well, else returns appropriate error value.
+ */
+static int ti_sci_cmd_set_latency_constraint(const struct ti_sci_handle *handle,
+ u16 latency, u8 state)
+{
+ struct ti_sci_msg_req_lpm_set_latency_constraint req;
+ struct ti_sci_msg_hdr resp;
+ struct device *dev;
+ int ret = 0;
+
+ if (IS_ERR(handle))
+ return PTR_ERR(handle);
+ if (!handle)
+ return -EINVAL;
+
+ dev = handle_to_ti_sci_info(handle)->dev;
+
+ req.latency = latency;
+ req.state = state;
+
+ ret = ti_sci_do_xfer(handle, TI_SCI_MSG_LPM_SET_LATENCY_CONSTRAINT,
+ TI_SCI_FLAG_REQ_ACK_ON_PROCESSED,
+ &req, sizeof(req),
+ &resp, sizeof(resp));
+ if (ret) {
+ dev_err(dev, "Failed to set device constraint\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+/*
+ * ti_sci_setup_pm_ops() - Setup the pm operations structures
+ * @pmops: pointer to TISCI pm ops structure
+ */
+void ti_sci_setup_pm_ops(struct ti_sci_pm_ops *pmops)
+{
+ pmops->lpm_wake_reason = ti_sci_msg_cmd_lpm_wake_reason;
+ pmops->set_device_constraint = ti_sci_cmd_set_device_constraint;
+ pmops->set_latency_constraint = ti_sci_cmd_set_latency_constraint;
+}
--
2.34.1