Skip to content

Commit ec24643

Browse files
Vibhore Vardhannmenon
authored andcommitted
firmware: ti_sci: Add system suspend and resume call
Introduce system suspend call that enables the ti_sci driver to support low power mode when the user space issues a suspend to mem. The following power management operations defined in the TISCI Low Power Mode API [1] are implemented to support suspend and resume: 1) TISCI_MSG_PREPARE_SLEEP Prepare the SOC for entering into a low power mode and provide details to firmware about the state being entered. 2) TISCI_MSG_SET_IO_ISOLATION Control the IO isolation for Low Power Mode. Also, write a ti_sci_prepare_system_suspend call to be used in the driver suspend handler to allow the system to identify the low power mode being entered and if necessary, send TISCI_MSG_PREPARE_SLEEP with information about the mode being entered. Sysfw version >= 10.00.04 support LPM_DM_MANAGED capability [2], where Device Mgr firmware now manages which low power mode is chosen. Going forward, this is the default configuration supported for TI AM62 family of devices. The state chosen by the DM can be influenced by sending constraints using the new LPM constraint APIs. In case the firmware does not support LPM_DM_MANAGED mode, the mode selection logic can be extended as needed. If no suspend-to-RAM modes are supported, return without taking any action. We're using "pm_suspend_target_state" to map the kernel's target suspend state to SysFW low power mode. Make sure this is available only when CONFIG_SUSPEND is enabled. Suspend has to be split into two parts, ti_sci_suspend() will send the prepare sleep message to prepare suspend. ti_sci_suspend_noirq() sets IO isolation which needs to be done as late as possible to avoid any issues. On resume this has to be done as early as possible. [1] https://software-dl.ti.com/tisci/esd/latest/2_tisci_msgs/pm/lpm.html Co-developed-by: Dave Gerlach <[email protected]> Signed-off-by: Dave Gerlach <[email protected]> Signed-off-by: Georgi Vlaev <[email protected]> Signed-off-by: Dhruva Gole <[email protected]> Signed-off-by: Vibhore Vardhan <[email protected]> Signed-off-by: Kevin Hilman <[email protected]> Tested-by: Dhruva Gole <[email protected]> Signed-off-by: Markus Schneider-Pargmann <[email protected]> Tested-by: Roger Quadros <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Nishanth Menon <[email protected]>
1 parent 055b6cf commit ec24643

File tree

3 files changed

+242
-1
lines changed

3 files changed

+242
-1
lines changed

drivers/firmware/ti_sci.c

Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include <linux/slab.h>
2525
#include <linux/soc/ti/ti-msgmgr.h>
2626
#include <linux/soc/ti/ti_sci_protocol.h>
27+
#include <linux/suspend.h>
2728
#include <linux/sys_soc.h>
2829
#include <linux/reboot.h>
2930

@@ -1654,6 +1655,68 @@ static int ti_sci_cmd_clk_get_freq(const struct ti_sci_handle *handle,
16541655
return ret;
16551656
}
16561657

1658+
/**
1659+
* ti_sci_cmd_prepare_sleep() - Prepare system for system suspend
1660+
* @handle: pointer to TI SCI handle
1661+
* @mode: Device identifier
1662+
* @ctx_lo: Low part of address for context save
1663+
* @ctx_hi: High part of address for context save
1664+
* @debug_flags: Debug flags to pass to firmware
1665+
*
1666+
* Return: 0 if all went well, else returns appropriate error value.
1667+
*/
1668+
static int ti_sci_cmd_prepare_sleep(const struct ti_sci_handle *handle, u8 mode,
1669+
u32 ctx_lo, u32 ctx_hi, u32 debug_flags)
1670+
{
1671+
struct ti_sci_info *info;
1672+
struct ti_sci_msg_req_prepare_sleep *req;
1673+
struct ti_sci_msg_hdr *resp;
1674+
struct ti_sci_xfer *xfer;
1675+
struct device *dev;
1676+
int ret = 0;
1677+
1678+
if (IS_ERR(handle))
1679+
return PTR_ERR(handle);
1680+
if (!handle)
1681+
return -EINVAL;
1682+
1683+
info = handle_to_ti_sci_info(handle);
1684+
dev = info->dev;
1685+
1686+
xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_PREPARE_SLEEP,
1687+
TI_SCI_FLAG_REQ_ACK_ON_PROCESSED,
1688+
sizeof(*req), sizeof(*resp));
1689+
if (IS_ERR(xfer)) {
1690+
ret = PTR_ERR(xfer);
1691+
dev_err(dev, "Message alloc failed(%d)\n", ret);
1692+
return ret;
1693+
}
1694+
1695+
req = (struct ti_sci_msg_req_prepare_sleep *)xfer->xfer_buf;
1696+
req->mode = mode;
1697+
req->ctx_lo = ctx_lo;
1698+
req->ctx_hi = ctx_hi;
1699+
req->debug_flags = debug_flags;
1700+
1701+
ret = ti_sci_do_xfer(info, xfer);
1702+
if (ret) {
1703+
dev_err(dev, "Mbox send fail %d\n", ret);
1704+
goto fail;
1705+
}
1706+
1707+
resp = (struct ti_sci_msg_hdr *)xfer->xfer_buf;
1708+
1709+
if (!ti_sci_is_response_ack(resp)) {
1710+
dev_err(dev, "Failed to prepare sleep\n");
1711+
ret = -ENODEV;
1712+
}
1713+
1714+
fail:
1715+
ti_sci_put_one_xfer(&info->minfo, xfer);
1716+
1717+
return ret;
1718+
}
1719+
16571720
/**
16581721
* ti_sci_msg_cmd_query_fw_caps() - Get the FW/SoC capabilities
16591722
* @handle: Pointer to TI SCI handle
@@ -1715,6 +1778,61 @@ static int ti_sci_msg_cmd_query_fw_caps(const struct ti_sci_handle *handle,
17151778
return ret;
17161779
}
17171780

1781+
/**
1782+
* ti_sci_cmd_set_io_isolation() - Enable IO isolation in LPM
1783+
* @handle: Pointer to TI SCI handle
1784+
* @state: The desired state of the IO isolation
1785+
*
1786+
* Return: 0 if all went well, else returns appropriate error value.
1787+
*/
1788+
static int ti_sci_cmd_set_io_isolation(const struct ti_sci_handle *handle,
1789+
u8 state)
1790+
{
1791+
struct ti_sci_info *info;
1792+
struct ti_sci_msg_req_set_io_isolation *req;
1793+
struct ti_sci_msg_hdr *resp;
1794+
struct ti_sci_xfer *xfer;
1795+
struct device *dev;
1796+
int ret = 0;
1797+
1798+
if (IS_ERR(handle))
1799+
return PTR_ERR(handle);
1800+
if (!handle)
1801+
return -EINVAL;
1802+
1803+
info = handle_to_ti_sci_info(handle);
1804+
dev = info->dev;
1805+
1806+
xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_SET_IO_ISOLATION,
1807+
TI_SCI_FLAG_REQ_ACK_ON_PROCESSED,
1808+
sizeof(*req), sizeof(*resp));
1809+
if (IS_ERR(xfer)) {
1810+
ret = PTR_ERR(xfer);
1811+
dev_err(dev, "Message alloc failed(%d)\n", ret);
1812+
return ret;
1813+
}
1814+
req = (struct ti_sci_msg_req_set_io_isolation *)xfer->xfer_buf;
1815+
req->state = state;
1816+
1817+
ret = ti_sci_do_xfer(info, xfer);
1818+
if (ret) {
1819+
dev_err(dev, "Mbox send fail %d\n", ret);
1820+
goto fail;
1821+
}
1822+
1823+
resp = (struct ti_sci_msg_hdr *)xfer->xfer_buf;
1824+
1825+
if (!ti_sci_is_response_ack(resp)) {
1826+
dev_err(dev, "Failed to set IO isolation\n");
1827+
ret = -ENODEV;
1828+
}
1829+
1830+
fail:
1831+
ti_sci_put_one_xfer(&info->minfo, xfer);
1832+
1833+
return ret;
1834+
}
1835+
17181836
static int ti_sci_cmd_core_reboot(const struct ti_sci_handle *handle)
17191837
{
17201838
struct ti_sci_info *info;
@@ -3326,6 +3444,81 @@ static int tisci_reboot_handler(struct sys_off_data *data)
33263444
return NOTIFY_BAD;
33273445
}
33283446

3447+
static int ti_sci_prepare_system_suspend(struct ti_sci_info *info)
3448+
{
3449+
/*
3450+
* Map and validate the target Linux suspend state to TISCI LPM.
3451+
* Default is to let Device Manager select the low power mode.
3452+
*/
3453+
switch (pm_suspend_target_state) {
3454+
case PM_SUSPEND_MEM:
3455+
if (info->fw_caps & MSG_FLAG_CAPS_LPM_DM_MANAGED) {
3456+
/*
3457+
* For the DM_MANAGED mode the context is reserved for
3458+
* internal use and can be 0
3459+
*/
3460+
return ti_sci_cmd_prepare_sleep(&info->handle,
3461+
TISCI_MSG_VALUE_SLEEP_MODE_DM_MANAGED,
3462+
0, 0, 0);
3463+
} else {
3464+
/* DM Managed is not supported by the firmware. */
3465+
dev_err(info->dev, "Suspend to memory is not supported by the firmware\n");
3466+
return -EOPNOTSUPP;
3467+
}
3468+
break;
3469+
default:
3470+
/*
3471+
* Do not fail if we don't have action to take for a
3472+
* specific suspend mode.
3473+
*/
3474+
return 0;
3475+
}
3476+
}
3477+
3478+
static int __maybe_unused ti_sci_suspend(struct device *dev)
3479+
{
3480+
struct ti_sci_info *info = dev_get_drvdata(dev);
3481+
int ret;
3482+
3483+
ret = ti_sci_prepare_system_suspend(info);
3484+
if (ret)
3485+
return ret;
3486+
3487+
return 0;
3488+
}
3489+
3490+
static int __maybe_unused ti_sci_suspend_noirq(struct device *dev)
3491+
{
3492+
struct ti_sci_info *info = dev_get_drvdata(dev);
3493+
int ret = 0;
3494+
3495+
ret = ti_sci_cmd_set_io_isolation(&info->handle, TISCI_MSG_VALUE_IO_ENABLE);
3496+
if (ret)
3497+
return ret;
3498+
3499+
return 0;
3500+
}
3501+
3502+
static int __maybe_unused ti_sci_resume_noirq(struct device *dev)
3503+
{
3504+
struct ti_sci_info *info = dev_get_drvdata(dev);
3505+
int ret = 0;
3506+
3507+
ret = ti_sci_cmd_set_io_isolation(&info->handle, TISCI_MSG_VALUE_IO_DISABLE);
3508+
if (ret)
3509+
return ret;
3510+
3511+
return 0;
3512+
}
3513+
3514+
static const struct dev_pm_ops ti_sci_pm_ops = {
3515+
#ifdef CONFIG_PM_SLEEP
3516+
.suspend = ti_sci_suspend,
3517+
.suspend_noirq = ti_sci_suspend_noirq,
3518+
.resume_noirq = ti_sci_resume_noirq,
3519+
#endif
3520+
};
3521+
33293522
/* Description for K2G */
33303523
static const struct ti_sci_desc ti_sci_pmmc_k2g_desc = {
33313524
.default_host_id = 2,
@@ -3494,6 +3687,7 @@ static struct platform_driver ti_sci_driver = {
34943687
.name = "ti-sci",
34953688
.of_match_table = of_match_ptr(ti_sci_of_match),
34963689
.suppress_bind_attrs = true,
3690+
.pm = &ti_sci_pm_ops,
34973691
},
34983692
};
34993693
module_platform_driver(ti_sci_driver);

drivers/firmware/ti_sci.h

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* The system works in a message response protocol
77
* See: https://software-dl.ti.com/tisci/esd/latest/index.html for details
88
*
9-
* Copyright (C) 2015-2016 Texas Instruments Incorporated - https://www.ti.com/
9+
* Copyright (C) 2015-2024 Texas Instruments Incorporated - https://www.ti.com/
1010
*/
1111

1212
#ifndef __TI_SCI_H
@@ -36,6 +36,10 @@
3636
#define TI_SCI_MSG_QUERY_CLOCK_FREQ 0x010d
3737
#define TI_SCI_MSG_GET_CLOCK_FREQ 0x010e
3838

39+
/* Low Power Mode Requests */
40+
#define TI_SCI_MSG_PREPARE_SLEEP 0x0300
41+
#define TI_SCI_MSG_SET_IO_ISOLATION 0x0307
42+
3943
/* Resource Management Requests */
4044
#define TI_SCI_MSG_GET_RESOURCE_RANGE 0x1500
4145

@@ -567,6 +571,45 @@ struct ti_sci_msg_resp_get_clock_freq {
567571
u64 freq_hz;
568572
} __packed;
569573

574+
/**
575+
* struct tisci_msg_req_prepare_sleep - Request for TISCI_MSG_PREPARE_SLEEP.
576+
*
577+
* @hdr TISCI header to provide ACK/NAK flags to the host.
578+
* @mode Low power mode to enter.
579+
* @ctx_lo Low 32-bits of physical pointer to address to use for context save.
580+
* @ctx_hi High 32-bits of physical pointer to address to use for context save.
581+
* @debug_flags Flags that can be set to halt the sequence during suspend or
582+
* resume to allow JTAG connection and debug.
583+
*
584+
* This message is used as the first step of entering a low power mode. It
585+
* allows configurable information, including which state to enter to be
586+
* easily shared from the application, as this is a non-secure message and
587+
* therefore can be sent by anyone.
588+
*/
589+
struct ti_sci_msg_req_prepare_sleep {
590+
struct ti_sci_msg_hdr hdr;
591+
592+
#define TISCI_MSG_VALUE_SLEEP_MODE_DM_MANAGED 0xfd
593+
u8 mode;
594+
u32 ctx_lo;
595+
u32 ctx_hi;
596+
u32 debug_flags;
597+
} __packed;
598+
599+
/**
600+
* struct tisci_msg_set_io_isolation_req - Request for TI_SCI_MSG_SET_IO_ISOLATION.
601+
*
602+
* @hdr: Generic header
603+
* @state: The deseared state of the IO isolation.
604+
*
605+
* This message is used to enable/disable IO isolation for low power modes.
606+
* Response is generic ACK / NACK message.
607+
*/
608+
struct ti_sci_msg_req_set_io_isolation {
609+
struct ti_sci_msg_hdr hdr;
610+
u8 state;
611+
} __packed;
612+
570613
#define TI_SCI_IRQ_SECONDARY_HOST_INVALID 0xff
571614

572615
/**

include/linux/soc/ti/ti_sci_protocol.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,10 @@ struct ti_sci_clk_ops {
195195
u64 *current_freq);
196196
};
197197

198+
/* TISCI LPM IO isolation control values */
199+
#define TISCI_MSG_VALUE_IO_ENABLE 1
200+
#define TISCI_MSG_VALUE_IO_DISABLE 0
201+
198202
/**
199203
* struct ti_sci_resource_desc - Description of TI SCI resource instance range.
200204
* @start: Start index of the first resource range.

0 commit comments

Comments
 (0)