feat(ti): implement DM_MANAGED suspend
DM_MANAGED is the new mode to support a model where DM chooses the
suspend mode. Previously suspend always chose deep sleep. Now DM may
also choose other modes like IO+DDR or other modes in the future. DM has
more knowledge about constraints regarding wakeup latency or which parts
of the system need to work continuously, so it is better able to decide
what suspend mode should be used.
To support DM_MANAGED in TF-A the next system mode needs to be fetched
and passed to the enter sleep message. The new ti_sci command to fetch
the next system mode is added which is ti_sci_lpm_get_next_sys_mode().
DM_MANAGED is only enabled if the firmware capability is supported.
Change-Id: I7244e27793cc60e1673271990d7cd840294d6cc3
Signed-off-by: Markus Schneider-Pargmann <msp@baylibre.com>
diff --git a/plat/ti/k3/common/drivers/ti_sci/ti_sci.c b/plat/ti/k3/common/drivers/ti_sci/ti_sci.c
index 8b77050..5c6ba6b 100644
--- a/plat/ti/k3/common/drivers/ti_sci/ti_sci.c
+++ b/plat/ti/k3/common/drivers/ti_sci/ti_sci.c
@@ -1740,3 +1740,41 @@
return 0;
}
+
+/**
+ * ti_sci_lpm_get_next_sys_mode() - Get next LPM system mode
+ *
+ * @next_mode: pointer to a variable that will store the next mode
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int ti_sci_lpm_get_next_sys_mode(uint8_t *next_mode)
+{
+ struct ti_sci_msg_req_lpm_get_next_sys_mode req;
+ struct ti_sci_msg_resp_lpm_get_next_sys_mode resp;
+ struct ti_sci_xfer xfer;
+ int ret;
+
+ if (next_mode == NULL) {
+ return -EINVAL;
+ }
+
+ ret = ti_sci_setup_one_xfer(TI_SCI_MSG_LPM_GET_NEXT_SYS_MODE, 0,
+ &req, sizeof(req),
+ &resp, sizeof(resp),
+ &xfer);
+ if (ret != 0) {
+ ERROR("Message alloc failed (%d)\n", ret);
+ return ret;
+ }
+
+ ret = ti_sci_do_xfer(&xfer);
+ if (ret != 0) {
+ ERROR("Transfer send failed (%d)\n", ret);
+ return ret;
+ }
+
+ *next_mode = resp.mode;
+
+ return 0;
+}
diff --git a/plat/ti/k3/common/drivers/ti_sci/ti_sci.h b/plat/ti/k3/common/drivers/ti_sci/ti_sci.h
index acaca4d..06d1f8d 100644
--- a/plat/ti/k3/common/drivers/ti_sci/ti_sci.h
+++ b/plat/ti/k3/common/drivers/ti_sci/ti_sci.h
@@ -252,6 +252,11 @@
* @mode: Low power mode to enter.
* @core_resume_addr: Address that core should be resumed from
* after low power transition.
+ * - ti_sci_lpm_get_next_sys_mode - Get next LPM system mode
+ *
+ * @next_mode: pointer to a variable that will store the next mode
+ *
+ * Return: 0 if all goes well, else appropriate error message
*
* NOTE: for all these functions, the following are generic in nature:
* Returns 0 for successful request, else returns corresponding error message.
@@ -259,5 +264,6 @@
int ti_sci_enter_sleep(uint8_t proc_id,
uint8_t mode,
uint64_t core_resume_addr);
+int ti_sci_lpm_get_next_sys_mode(uint8_t *next_mode);
#endif /* TI_SCI_H */
diff --git a/plat/ti/k3/common/drivers/ti_sci/ti_sci_protocol.h b/plat/ti/k3/common/drivers/ti_sci/ti_sci_protocol.h
index 7f1c368..cc71eac 100644
--- a/plat/ti/k3/common/drivers/ti_sci/ti_sci_protocol.h
+++ b/plat/ti/k3/common/drivers/ti_sci/ti_sci_protocol.h
@@ -31,6 +31,7 @@
/* Low Power Mode Requests */
#define TI_SCI_MSG_ENTER_SLEEP 0x0301
+#define TI_SCI_MSG_LPM_GET_NEXT_SYS_MODE 0x030d
/* Clock requests */
#define TI_SCI_MSG_SET_CLOCK_STATE 0x0100
@@ -133,6 +134,7 @@
* MSG_FLAG_CAPS_LPM_MCU_ONLY: MCU only LPM
* MSG_FLAG_CAPS_LPM_STANDBY: Standby LPM
* MSG_FLAG_CAPS_LPM_PARTIAL_IO: Partial IO in LPM
+ * MSG_FLAG_CAPS_LPM_DM_MANAGED: LPM can be managed by DM
*
* Response to a generic message with message type TI_SCI_MSG_QUERY_FW_CAPS
* providing currently available SOC/firmware capabilities. SoC that don't
@@ -145,6 +147,7 @@
#define MSG_FLAG_CAPS_LPM_MCU_ONLY TI_SCI_MSG_FLAG(2)
#define MSG_FLAG_CAPS_LPM_STANDBY TI_SCI_MSG_FLAG(3)
#define MSG_FLAG_CAPS_LPM_PARTIAL_IO TI_SCI_MSG_FLAG(4)
+#define MSG_FLAG_CAPS_LPM_DM_MANAGED TI_SCI_MSG_FLAG(5)
uint64_t fw_caps;
} __packed;
@@ -764,10 +767,35 @@
*/
struct ti_sci_msg_req_enter_sleep {
struct ti_sci_msg_hdr hdr;
+#define MSG_VALUE_SLEEP_MODE_DEEP_SLEEP 0x0
uint8_t mode;
uint8_t processor_id;
uint32_t core_resume_lo;
uint32_t core_resume_hi;
} __packed;
+/**
+ * struct ti_sci_msg_req_lpm_get_next_sys_mode - Request for TI_SCI_MSG_LPM_GET_NEXT_SYS_MODE.
+ *
+ * @hdr Generic Header
+ *
+ * This message is used to enquire DM for selected system wide low power mode.
+ */
+struct ti_sci_msg_req_lpm_get_next_sys_mode {
+ struct ti_sci_msg_hdr hdr;
+} __packed;
+
+/**
+ * struct ti_sci_msg_resp_lpm_get_next_sys_mode - Response for TI_SCI_MSG_LPM_GET_NEXT_SYS_MODE.
+ *
+ * @hdr Generic Header
+ * @mode The selected system wide low power mode.
+ *
+ * Note: If the mode selection is not yet locked, this API returns "not selected" mode.
+ */
+struct ti_sci_msg_resp_lpm_get_next_sys_mode {
+ struct ti_sci_msg_hdr hdr;
+ uint8_t mode;
+} __packed;
+
#endif /* TI_SCI_PROTOCOL_H */
diff --git a/plat/ti/k3/common/k3_psci.c b/plat/ti/k3/common/k3_psci.c
index e8d73db..df49f48 100644
--- a/plat/ti/k3/common/k3_psci.c
+++ b/plat/ti/k3/common/k3_psci.c
@@ -234,7 +234,7 @@
return PSCI_E_SUCCESS;
}
-static void k3_pwr_domain_suspend(const psci_power_state_t *target_state)
+static void k3_pwr_domain_suspend_to_mode(const psci_power_state_t *target_state, uint8_t mode)
{
unsigned int core, proc_id;
@@ -247,7 +247,25 @@
k3_pwr_domain_off(target_state);
+ ti_sci_enter_sleep(proc_id, mode, k3_sec_entrypoint);
+}
+
+static void k3_pwr_domain_suspend_dm_managed(const psci_power_state_t *target_state)
+{
+ uint8_t mode = MSG_VALUE_SLEEP_MODE_DEEP_SLEEP;
+ int ret;
+
- ti_sci_enter_sleep(proc_id, 0, k3_sec_entrypoint);
+ ret = ti_sci_lpm_get_next_sys_mode(&mode);
+ if (ret != 0) {
+ ERROR("Failed to fetch next system mode\n");
+ }
+
+ k3_pwr_domain_suspend_to_mode(target_state, mode);
+}
+
+static void k3_pwr_domain_suspend(const psci_power_state_t *target_state)
+{
+ k3_pwr_domain_suspend_to_mode(target_state, MSG_VALUE_SLEEP_MODE_DEEP_SLEEP);
}
static void k3_pwr_domain_suspend_finish(const psci_power_state_t *target_state)
@@ -301,6 +319,8 @@
k3_plat_psci_ops.pwr_domain_suspend = NULL;
k3_plat_psci_ops.pwr_domain_suspend_finish = NULL;
k3_plat_psci_ops.get_sys_suspend_power_state = NULL;
+ } else if (fw_caps & MSG_FLAG_CAPS_LPM_DM_MANAGED) {
+ k3_plat_psci_ops.pwr_domain_suspend = k3_pwr_domain_suspend_dm_managed;
}
*psci_ops = &k3_plat_psci_ops;