Skip to content

Commit e0431ff

Browse files
scosunmenon
authored andcommitted
firmware: ti_sci: Partial-IO support
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> Reviewed-by: Dhruva Gole <d-gole@ti.com> Reviewed-by: Kendall Willis <k-willis@ti.com> Reviewed-by: Sebin Francis <sebin.francis@ti.com> Link: https://patch.msgid.link/20251103-topic-am62-partialio-v6-12-b4-v10-2-0557e858d747@baylibre.com Signed-off-by: Nishanth Menon <nm@ti.com>
1 parent 170a3ef commit e0431ff

2 files changed

Lines changed: 107 additions & 7 deletions

File tree

drivers/firmware/ti_sci.c

Lines changed: 102 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1673,6 +1673,9 @@ static int ti_sci_cmd_clk_get_freq(const struct ti_sci_handle *handle,
16731673
static int ti_sci_cmd_prepare_sleep(const struct ti_sci_handle *handle, u8 mode,
16741674
u32 ctx_lo, u32 ctx_hi, u32 debug_flags)
16751675
{
1676+
u32 msg_flags = mode == TISCI_MSG_VALUE_SLEEP_MODE_PARTIAL_IO ?
1677+
TI_SCI_FLAG_REQ_GENERIC_NORESPONSE :
1678+
TI_SCI_FLAG_REQ_ACK_ON_PROCESSED;
16761679
struct ti_sci_info *info;
16771680
struct ti_sci_msg_req_prepare_sleep *req;
16781681
struct ti_sci_msg_hdr *resp;
@@ -1689,7 +1692,7 @@ static int ti_sci_cmd_prepare_sleep(const struct ti_sci_handle *handle, u8 mode,
16891692
dev = info->dev;
16901693

16911694
xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_PREPARE_SLEEP,
1692-
TI_SCI_FLAG_REQ_ACK_ON_PROCESSED,
1695+
msg_flags,
16931696
sizeof(*req), sizeof(*resp));
16941697
if (IS_ERR(xfer)) {
16951698
ret = PTR_ERR(xfer);
@@ -1709,11 +1712,12 @@ static int ti_sci_cmd_prepare_sleep(const struct ti_sci_handle *handle, u8 mode,
17091712
goto fail;
17101713
}
17111714

1712-
resp = (struct ti_sci_msg_hdr *)xfer->xfer_buf;
1713-
1714-
if (!ti_sci_is_response_ack(resp)) {
1715-
dev_err(dev, "Failed to prepare sleep\n");
1716-
ret = -ENODEV;
1715+
if (msg_flags == TI_SCI_FLAG_REQ_ACK_ON_PROCESSED) {
1716+
resp = (struct ti_sci_msg_hdr *)xfer->xfer_buf;
1717+
if (!ti_sci_is_response_ack(resp)) {
1718+
dev_err(dev, "Failed to prepare sleep\n");
1719+
ret = -ENODEV;
1720+
}
17171721
}
17181722

17191723
fail:
@@ -3667,6 +3671,78 @@ devm_ti_sci_get_resource(const struct ti_sci_handle *handle, struct device *dev,
36673671
}
36683672
EXPORT_SYMBOL_GPL(devm_ti_sci_get_resource);
36693673

3674+
/*
3675+
* Iterate all device nodes that have a wakeup-source property and check if one
3676+
* of the possible phandles points to a Partial-IO system state. If it
3677+
* does resolve the device node to an actual device and check if wakeup is
3678+
* enabled.
3679+
*/
3680+
static bool ti_sci_partial_io_wakeup_enabled(struct ti_sci_info *info)
3681+
{
3682+
struct device_node *wakeup_node = NULL;
3683+
3684+
for_each_node_with_property(wakeup_node, "wakeup-source") {
3685+
struct of_phandle_iterator it;
3686+
int err;
3687+
3688+
of_for_each_phandle(&it, err, wakeup_node, "wakeup-source", NULL, 0) {
3689+
struct platform_device *pdev;
3690+
bool may_wakeup;
3691+
3692+
/*
3693+
* Continue if idle-state-name is not off-wake. Return
3694+
* value is the index of the string which should be 0 if
3695+
* off-wake is present.
3696+
*/
3697+
if (of_property_match_string(it.node, "idle-state-name", "off-wake"))
3698+
continue;
3699+
3700+
pdev = of_find_device_by_node(wakeup_node);
3701+
if (!pdev)
3702+
continue;
3703+
3704+
may_wakeup = device_may_wakeup(&pdev->dev);
3705+
put_device(&pdev->dev);
3706+
3707+
if (may_wakeup) {
3708+
dev_dbg(info->dev, "%pOF identified as wakeup source for Partial-IO\n",
3709+
wakeup_node);
3710+
of_node_put(it.node);
3711+
of_node_put(wakeup_node);
3712+
return true;
3713+
}
3714+
}
3715+
}
3716+
3717+
return false;
3718+
}
3719+
3720+
static int ti_sci_sys_off_handler(struct sys_off_data *data)
3721+
{
3722+
struct ti_sci_info *info = data->cb_data;
3723+
const struct ti_sci_handle *handle = &info->handle;
3724+
bool enter_partial_io = ti_sci_partial_io_wakeup_enabled(info);
3725+
int ret;
3726+
3727+
if (!enter_partial_io)
3728+
return NOTIFY_DONE;
3729+
3730+
dev_info(info->dev, "Entering Partial-IO because a powered wakeup-enabled device was found.\n");
3731+
3732+
ret = ti_sci_cmd_prepare_sleep(handle, TISCI_MSG_VALUE_SLEEP_MODE_PARTIAL_IO, 0, 0, 0);
3733+
if (ret) {
3734+
dev_err(info->dev,
3735+
"Failed to enter Partial-IO %pe, trying to do an emergency restart\n",
3736+
ERR_PTR(ret));
3737+
emergency_restart();
3738+
}
3739+
3740+
mdelay(5000);
3741+
emergency_restart();
3742+
3743+
return NOTIFY_DONE;
3744+
}
3745+
36703746
static int tisci_reboot_handler(struct sys_off_data *data)
36713747
{
36723748
struct ti_sci_info *info = data->cb_data;
@@ -3949,6 +4025,19 @@ static int ti_sci_probe(struct platform_device *pdev)
39494025
goto out;
39504026
}
39514027

4028+
if (info->fw_caps & MSG_FLAG_CAPS_LPM_PARTIAL_IO) {
4029+
ret = devm_register_sys_off_handler(dev,
4030+
SYS_OFF_MODE_POWER_OFF,
4031+
SYS_OFF_PRIO_FIRMWARE,
4032+
ti_sci_sys_off_handler,
4033+
info);
4034+
if (ret) {
4035+
dev_err(dev, "Failed to register sys_off_handler %pe\n",
4036+
ERR_PTR(ret));
4037+
goto out;
4038+
}
4039+
}
4040+
39524041
dev_info(dev, "ABI: %d.%d (firmware rev 0x%04x '%s')\n",
39534042
info->handle.version.abi_major, info->handle.version.abi_minor,
39544043
info->handle.version.firmware_revision,
@@ -3958,7 +4047,13 @@ static int ti_sci_probe(struct platform_device *pdev)
39584047
list_add_tail(&info->node, &ti_sci_list);
39594048
mutex_unlock(&ti_sci_list_mutex);
39604049

3961-
return of_platform_populate(dev->of_node, NULL, NULL, dev);
4050+
ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
4051+
if (ret) {
4052+
dev_err(dev, "platform_populate failed %pe\n", ERR_PTR(ret));
4053+
goto out;
4054+
}
4055+
return 0;
4056+
39624057
out:
39634058
if (!IS_ERR(info->chan_tx))
39644059
mbox_free_channel(info->chan_tx);

drivers/firmware/ti_sci.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -597,6 +597,11 @@ struct ti_sci_msg_resp_get_clock_freq {
597597
struct ti_sci_msg_req_prepare_sleep {
598598
struct ti_sci_msg_hdr hdr;
599599

600+
/*
601+
* When sending prepare_sleep with MODE_PARTIAL_IO no response will be sent,
602+
* no further steps are required.
603+
*/
604+
#define TISCI_MSG_VALUE_SLEEP_MODE_PARTIAL_IO 0x03
600605
#define TISCI_MSG_VALUE_SLEEP_MODE_DM_MANAGED 0xfd
601606
u8 mode;
602607
u32 ctx_lo;

0 commit comments

Comments
 (0)