Merge pull request #1771 from glneo/core-shutdown

TI K3 Core shutdown changes
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 b211bdf..81488a1 100644
--- a/plat/ti/k3/common/drivers/ti_sci/ti_sci.c
+++ b/plat/ti/k3/common/drivers/ti_sci/ti_sci.c
@@ -1459,6 +1459,169 @@
 }
 
 /**
+ * ti_sci_proc_wait_boot_status() - Wait for a processor boot status
+ *
+ * @proc_id:			Processor ID this request is for
+ * @num_wait_iterations		Total number of iterations we will check before
+ *				we will timeout and give up
+ * @num_match_iterations	How many iterations should we have continued
+ *				status to account for status bits glitching.
+ *				This is to make sure that match occurs for
+ *				consecutive checks. This implies that the
+ *				worst case should consider that the stable
+ *				time should at the worst be num_wait_iterations
+ *				num_match_iterations to prevent timeout.
+ * @delay_per_iteration_us	Specifies how long to wait (in micro seconds)
+ *				between each status checks. This is the minimum
+ *				duration, and overhead of register reads and
+ *				checks are on top of this and can vary based on
+ *				varied conditions.
+ * @delay_before_iterations_us	Specifies how long to wait (in micro seconds)
+ *				before the very first check in the first
+ *				iteration of status check loop. This is the
+ *				minimum duration, and overhead of register
+ *				reads and checks are.
+ * @status_flags_1_set_all_wait	If non-zero, Specifies that all bits of the
+ *				status matching this field requested MUST be 1.
+ * @status_flags_1_set_any_wait	If non-zero, Specifies that at least one of the
+ *				bits matching this field requested MUST be 1.
+ * @status_flags_1_clr_all_wait	If non-zero, Specifies that all bits of the
+ *				status matching this field requested MUST be 0.
+ * @status_flags_1_clr_any_wait	If non-zero, Specifies that at least one of the
+ *				bits matching this field requested MUST be 0.
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int ti_sci_proc_wait_boot_status(uint8_t proc_id, uint8_t num_wait_iterations,
+				 uint8_t num_match_iterations,
+				 uint8_t delay_per_iteration_us,
+				 uint8_t delay_before_iterations_us,
+				 uint32_t status_flags_1_set_all_wait,
+				 uint32_t status_flags_1_set_any_wait,
+				 uint32_t status_flags_1_clr_all_wait,
+				 uint32_t status_flags_1_clr_any_wait)
+{
+	struct ti_sci_msg_req_wait_proc_boot_status req;
+	struct ti_sci_msg_hdr resp;
+
+	struct ti_sci_xfer xfer;
+	int ret;
+
+	ret = ti_sci_setup_one_xfer(TISCI_MSG_WAIT_PROC_BOOT_STATUS,
+				    TI_SCI_FLAG_REQ_ACK_ON_PROCESSED,
+				    &req, sizeof(req),
+				    &resp, sizeof(resp),
+				    &xfer);
+	if (ret) {
+		ERROR("Message alloc failed (%d)\n", ret);
+		return ret;
+	}
+
+	req.processor_id = proc_id;
+	req.num_wait_iterations = num_wait_iterations;
+	req.num_match_iterations = num_match_iterations;
+	req.delay_per_iteration_us = delay_per_iteration_us;
+	req.delay_before_iterations_us = delay_before_iterations_us;
+	req.status_flags_1_set_all_wait = status_flags_1_set_all_wait;
+	req.status_flags_1_set_any_wait = status_flags_1_set_any_wait;
+	req.status_flags_1_clr_all_wait = status_flags_1_clr_all_wait;
+	req.status_flags_1_clr_any_wait = status_flags_1_clr_any_wait;
+
+	ret = ti_sci_do_xfer(&xfer);
+	if (ret) {
+		ERROR("Transfer send failed (%d)\n", ret);
+		return ret;
+	}
+
+	if (!ti_sci_is_response_ack(&resp))
+		return -ENODEV;
+
+	return 0;
+}
+
+/**
+ * ti_sci_proc_shutdown() - Shutdown Processor without waiting for ACKs
+ *
+ * @proc_id:	Processor ID this request is for
+ * @dev_id:	Device identifier this request is for
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int ti_sci_proc_shutdown(uint8_t proc_id, uint32_t dev_id)
+{
+	struct ti_sci_msg_req_wait_proc_boot_status wait_req;
+	struct ti_sci_msg_req_set_device_state set_req;
+	/*
+	 * We will not be waiting for this response, but declare one anyway
+	 * to pass to the setup function so the checks will still pass
+	 */
+	struct ti_sci_msg_hdr resp;
+
+	struct ti_sci_xfer xfer;
+	int ret;
+
+	/* Start by sending wait command */
+
+	/* Setup with NORESPONSE flag to keep response queue clean */
+	ret = ti_sci_setup_one_xfer(TISCI_MSG_WAIT_PROC_BOOT_STATUS,
+				    TI_SCI_FLAG_REQ_GENERIC_NORESPONSE,
+				    &wait_req, sizeof(wait_req),
+				    &resp, sizeof(resp),
+				    &xfer);
+	if (ret) {
+		ERROR("Message alloc failed (%d)\n", ret);
+		return ret;
+	}
+
+	wait_req.processor_id = proc_id;
+	/*
+	 * Wait maximum time to give us the best chance to get
+	 * to WFI before this command timeouts
+	 */
+	wait_req.delay_before_iterations_us = UINT8_MAX;
+	wait_req.num_wait_iterations = UINT8_MAX;
+	wait_req.delay_per_iteration_us = UINT8_MAX;  /* TODO: optimize time */
+	wait_req.num_match_iterations = 2;
+	wait_req.status_flags_1_set_all_wait = 0;
+	/* Wait for either WFE or WFI */
+	wait_req.status_flags_1_set_any_wait = PROC_BOOT_STATUS_FLAG_ARMV8_WFE |
+					       PROC_BOOT_STATUS_FLAG_ARMV8_WFI;
+	wait_req.status_flags_1_clr_all_wait = 0;
+	wait_req.status_flags_1_clr_any_wait = 0;
+
+	/* Send wait message */
+	ret = k3_sec_proxy_send(SP_HIGH_PRIORITY, &xfer.tx_message);
+	if (ret) {
+		ERROR("Message sending failed (%d)\n", ret);
+		return ret;
+	}
+
+	/* Now queue up the shutdown request */
+	ret = ti_sci_setup_one_xfer(TI_SCI_MSG_SET_DEVICE_STATE,
+				    TI_SCI_FLAG_REQ_GENERIC_NORESPONSE,
+				    &set_req, sizeof(set_req),
+				    &resp, sizeof(resp),
+				    &xfer);
+	if (ret) {
+		ERROR("Message alloc failed (%d)\n", ret);
+		return ret;
+	}
+
+	set_req.id = dev_id;
+	set_req.state = MSG_DEVICE_SW_STATE_AUTO_OFF;
+
+	/* Send shutdown message */
+	ret = k3_sec_proxy_send(SP_HIGH_PRIORITY, &xfer.tx_message);
+	if (ret) {
+		ERROR("Message sending failed (%d)\n", ret);
+		return ret;
+	}
+
+	/* Return without waiting for responses */
+	return 0;
+}
+
+/**
  * ti_sci_init() - Basic initialization
  *
  * Return: 0 if all goes well, else appropriate error message
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 1176b00..d07ee61 100644
--- a/plat/ti/k3/common/drivers/ti_sci/ti_sci.h
+++ b/plat/ti/k3/common/drivers/ti_sci/ti_sci.h
@@ -179,6 +179,7 @@
  *                                 and then set the processor configuration flags.
  *              @cert_addr: Memory address at which payload image certificate is located.
  * - ti_sci_proc_get_boot_status - Command to get the processor boot status
+ * - ti_sci_proc_wait_boot_status - Command to wait for a processor boot status
  *
  * NOTE: for all these functions, the following are generic in nature:
  * @proc_id:	Processor ID
@@ -197,6 +198,15 @@
 				uint32_t *cfg_flags,
 				uint32_t *ctrl_flags,
 				uint32_t *sts_flags);
+int ti_sci_proc_wait_boot_status(uint8_t proc_id, uint8_t num_wait_iterations,
+				 uint8_t num_match_iterations,
+				 uint8_t delay_per_iteration_us,
+				 uint8_t delay_before_iterations_us,
+				 uint32_t status_flags_1_set_all_wait,
+				 uint32_t status_flags_1_set_any_wait,
+				 uint32_t status_flags_1_clr_all_wait,
+				 uint32_t status_flags_1_clr_any_wait);
+int ti_sci_proc_shutdown(uint8_t proc_id, uint32_t dev_id);
 
 /**
  * ti_sci_init() - Basic initialization
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 c6d76d7..a921e51 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
@@ -46,6 +46,7 @@
 #define TISCI_MSG_SET_PROC_BOOT_CTRL	0xc101
 #define TISCI_MSG_PROC_AUTH_BOOT_IMIAGE	0xc120
 #define TISCI_MSG_GET_PROC_BOOT_STATUS	0xc400
+#define TISCI_MSG_WAIT_PROC_BOOT_STATUS	0xc401
 
 /**
  * struct ti_sci_msg_hdr - Generic Message Header for All messages and responses
@@ -647,4 +648,52 @@
 	uint32_t status_flags;
 } __packed;
 
+/**
+ * struct ti_sci_msg_req_wait_proc_boot_status - Wait for a processor boot status
+ * @hdr:			Generic Header
+ * @processor_id:		ID of processor
+ * @num_wait_iterations		Total number of iterations we will check before
+ *				we will timeout and give up
+ * @num_match_iterations	How many iterations should we have continued
+ *				status to account for status bits glitching.
+ *				This is to make sure that match occurs for
+ *				consecutive checks. This implies that the
+ *				worst case should consider that the stable
+ *				time should at the worst be num_wait_iterations
+ *				num_match_iterations to prevent timeout.
+ * @delay_per_iteration_us	Specifies how long to wait (in micro seconds)
+ *				between each status checks. This is the minimum
+ *				duration, and overhead of register reads and
+ *				checks are on top of this and can vary based on
+ *				varied conditions.
+ * @delay_before_iterations_us	Specifies how long to wait (in micro seconds)
+ *				before the very first check in the first
+ *				iteration of status check loop. This is the
+ *				minimum duration, and overhead of register
+ *				reads and checks are.
+ * @status_flags_1_set_all_wait	If non-zero, Specifies that all bits of the
+ *				status matching this field requested MUST be 1.
+ * @status_flags_1_set_any_wait	If non-zero, Specifies that at least one of the
+ *				bits matching this field requested MUST be 1.
+ * @status_flags_1_clr_all_wait	If non-zero, Specifies that all bits of the
+ *				status matching this field requested MUST be 0.
+ * @status_flags_1_clr_any_wait	If non-zero, Specifies that at least one of the
+ *				bits matching this field requested MUST be 0.
+ *
+ * Request type is TISCI_MSG_WAIT_PROC_BOOT_STATUS, response is appropriate
+ * message, or NACK in case of inability to satisfy request.
+ */
+struct ti_sci_msg_req_wait_proc_boot_status {
+	struct ti_sci_msg_hdr hdr;
+	uint8_t processor_id;
+	uint8_t num_wait_iterations;
+	uint8_t num_match_iterations;
+	uint8_t delay_per_iteration_us;
+	uint8_t delay_before_iterations_us;
+	uint32_t status_flags_1_set_all_wait;
+	uint32_t status_flags_1_set_any_wait;
+	uint32_t status_flags_1_clr_all_wait;
+	uint32_t status_flags_1_clr_any_wait;
+} __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 cb75bf6..235e639 100644
--- a/plat/ti/k3/common/k3_psci.c
+++ b/plat/ti/k3/common/k3_psci.c
@@ -81,15 +81,16 @@
 
 void k3_pwr_domain_off(const psci_power_state_t *target_state)
 {
-	int core_id, device, ret;
+	int core_id, proc, device, ret;
 
 	/* Prevent interrupts from spuriously waking up this cpu */
 	k3_gic_cpuif_disable();
 
 	core_id = plat_my_core_pos();
+	proc = PLAT_PROC_START_ID + core_id;
 	device = PLAT_PROC_DEVICE_START_ID + core_id;
 
-	ret = ti_sci_device_put(device);
+	ret = ti_sci_proc_shutdown(proc, device);
 	if (ret) {
 		ERROR("Request to stop core failed: %d\n", ret);
 		return;