[U-Boot] [PATCH v2 2/7] firmware: ti_sci: Add processor shutdown API method

Lokesh Vutla lokeshvutla at ti.com
Wed May 22 04:32:19 UTC 2019


From: Andreas Dannenberg <dannenberg at ti.com>

Add and expose a new processor shutdown API that wraps the two TISCI
messages involved in initiating a core shutdown. The API will first
queue a message to have the DMSC wait for a certain processor boot
status to happen followed by a message to trigger the actual shutdown-
with both messages being sent without waiting or requesting for a
response. Note that the processor shutdown API call will need to be
followed up by user software placing the respective core into either
WFE or WFI mode.

Signed-off-by: Andreas Dannenberg <dannenberg at ti.com>
---
 drivers/firmware/ti_sci.c              | 191 ++++++++++++++++++++++++-
 drivers/firmware/ti_sci.h              |  50 +++++++
 include/linux/soc/ti/ti_sci_protocol.h |   4 +
 3 files changed, 241 insertions(+), 4 deletions(-)

diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c
index eadb91e107..8c68f98788 100644
--- a/drivers/firmware/ti_sci.c
+++ b/drivers/firmware/ti_sci.c
@@ -101,7 +101,8 @@ struct ti_sci_info {
  * @msg_flags:	Flag to set for the message
  * @buf:	Buffer to be send to mailbox channel
  * @tx_message_size: transmit message size
- * @rx_message_size: receive message size
+ * @rx_message_size: receive message size. may be set to zero for send-only
+ *		     transactions.
  *
  * Helper function which is used by various command functions that are
  * exposed to clients of this driver for allocating a message traffic event.
@@ -121,7 +122,8 @@ static struct ti_sci_xfer *ti_sci_setup_one_xfer(struct ti_sci_info *info,
 	/* Ensure we have sane transfer sizes */
 	if (rx_message_size > info->desc->max_msg_size ||
 	    tx_message_size > info->desc->max_msg_size ||
-	    rx_message_size < sizeof(*hdr) || tx_message_size < sizeof(*hdr))
+	    (rx_message_size > 0 && rx_message_size < sizeof(*hdr)) ||
+	    tx_message_size < sizeof(*hdr))
 		return ERR_PTR(-ERANGE);
 
 	info->seq = ~info->seq;
@@ -219,7 +221,9 @@ static inline int ti_sci_do_xfer(struct ti_sci_info *info,
 
 		xfer->tx_message.buf = (u32 *)secure_buf;
 		xfer->tx_message.len += sizeof(secure_hdr);
-		xfer->rx_len += sizeof(secure_hdr);
+
+		if (xfer->rx_len)
+			xfer->rx_len += sizeof(secure_hdr);
 	}
 
 	/* Send the message */
@@ -230,7 +234,11 @@ static inline int ti_sci_do_xfer(struct ti_sci_info *info,
 		return ret;
 	}
 
-	return ti_sci_get_response(info, xfer, &info->chan_rx);
+	/* Get response if requested */
+	if (xfer->rx_len)
+		ret = ti_sci_get_response(info, xfer, &info->chan_rx);
+
+	return ret;
 }
 
 /**
@@ -469,6 +477,49 @@ static int ti_sci_set_device_state(const struct ti_sci_handle *handle,
 	return ret;
 }
 
+/**
+ * ti_sci_set_device_state_no_wait() - Set device state helper without
+ *				       requesting or waiting for a response.
+ * @handle:	pointer to TI SCI handle
+ * @id:		Device identifier
+ * @flags:	flags to setup for the device
+ * @state:	State to move the device to
+ *
+ * Return: 0 if all went well, else returns appropriate error value.
+ */
+static int ti_sci_set_device_state_no_wait(const struct ti_sci_handle *handle,
+					   u32 id, u32 flags, u8 state)
+{
+	struct ti_sci_msg_req_set_device_state req;
+	struct ti_sci_info *info;
+	struct ti_sci_xfer *xfer;
+	int ret = 0;
+
+	if (IS_ERR(handle))
+		return PTR_ERR(handle);
+	if (!handle)
+		return -EINVAL;
+
+	info = handle_to_ti_sci_info(handle);
+
+	xfer = ti_sci_setup_one_xfer(info, TI_SCI_MSG_SET_DEVICE_STATE,
+				     flags | TI_SCI_FLAG_REQ_GENERIC_NORESPONSE,
+				     (u32 *)&req, sizeof(req), 0);
+	if (IS_ERR(xfer)) {
+		ret = PTR_ERR(xfer);
+		dev_err(info->dev, "Message alloc failed(%d)\n", ret);
+		return ret;
+	}
+	req.id = id;
+	req.state = state;
+
+	ret = ti_sci_do_xfer(info, xfer);
+	if (ret)
+		dev_err(info->dev, "Mbox send fail %d\n", ret);
+
+	return ret;
+}
+
 /**
  * ti_sci_get_device_state() - Get device state helper
  * @handle:	Handle to the device
@@ -2039,6 +2090,137 @@ static int ti_sci_cmd_get_proc_boot_status(const struct ti_sci_handle *handle,
 	return ret;
 }
 
+/**
+ * ti_sci_proc_wait_boot_status_no_wait() - Helper function to wait for a
+ *				processor boot status without requesting or
+ *				waiting for a response.
+ * @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
+ */
+static int
+ti_sci_proc_wait_boot_status_no_wait(const struct ti_sci_handle *handle,
+				     u8 proc_id,
+				     u8 num_wait_iterations,
+				     u8 num_match_iterations,
+				     u8 delay_per_iteration_us,
+				     u8 delay_before_iterations_us,
+				     u32 status_flags_1_set_all_wait,
+				     u32 status_flags_1_set_any_wait,
+				     u32 status_flags_1_clr_all_wait,
+				     u32 status_flags_1_clr_any_wait)
+{
+	struct ti_sci_msg_req_wait_proc_boot_status req;
+	struct ti_sci_info *info;
+	struct ti_sci_xfer *xfer;
+	int ret = 0;
+
+	if (IS_ERR(handle))
+		return PTR_ERR(handle);
+	if (!handle)
+		return -EINVAL;
+
+	info = handle_to_ti_sci_info(handle);
+
+	xfer = ti_sci_setup_one_xfer(info, TISCI_MSG_WAIT_PROC_BOOT_STATUS,
+				     TI_SCI_FLAG_REQ_GENERIC_NORESPONSE,
+				     (u32 *)&req, sizeof(req), 0);
+	if (IS_ERR(xfer)) {
+		ret = PTR_ERR(xfer);
+		dev_err(info->dev, "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(info, xfer);
+	if (ret)
+		dev_err(info->dev, "Mbox send fail %d\n", ret);
+
+	return ret;
+}
+
+/**
+ * ti_sci_cmd_proc_shutdown_no_wait() - Command to shutdown a core without
+ *		requesting or waiting for a response. Note that this API call
+ *		should be followed by placing the respective processor into
+ *		either WFE or WFI mode.
+ * @handle:	Pointer to TI SCI handle
+ * @proc_id:	Processor ID this request is for
+ *
+ * Return: 0 if all went well, else returns appropriate error value.
+ */
+static int ti_sci_cmd_proc_shutdown_no_wait(const struct ti_sci_handle *handle,
+					    u8 proc_id)
+{
+	int ret;
+
+	/*
+	 * Send the core boot status wait message waiting for either WFE or
+	 * WFI without requesting or waiting for a TISCI response with the
+	 * maximum wait time to give us the best chance to get to the WFE/WFI
+	 * command that should follow the invocation of this API before the
+	 * DMSC-internal processing of this command times out. Note that
+	 * waiting for the R5 WFE/WFI flags will also work on an ARMV8 type
+	 * core as the related flag bit positions are the same.
+	 */
+	ret = ti_sci_proc_wait_boot_status_no_wait(handle, proc_id,
+		U8_MAX, 100, U8_MAX, U8_MAX,
+		0, PROC_BOOT_STATUS_FLAG_R5_WFE | PROC_BOOT_STATUS_FLAG_R5_WFI,
+		0, 0);
+	if (ret) {
+		dev_err(info->dev, "Sending core %u wait message fail %d\n",
+			proc_id, ret);
+		return ret;
+	}
+
+	/*
+	 * Release a processor managed by TISCI without requesting or waiting
+	 * for a response.
+	 */
+	ret = ti_sci_set_device_state_no_wait(handle, proc_id, 0,
+					      MSG_DEVICE_SW_STATE_AUTO_OFF);
+	if (ret)
+		dev_err(info->dev, "Sending core %u shutdown message fail %d\n",
+			proc_id, ret);
+
+	return ret;
+}
+
 /**
  * ti_sci_cmd_ring_config() - configure RA ring
  * @handle:	pointer to TI SCI handle
@@ -2687,6 +2869,7 @@ static void ti_sci_setup_ops(struct ti_sci_info *info)
 	pops->set_proc_boot_ctrl = ti_sci_cmd_set_proc_boot_ctrl;
 	pops->proc_auth_boot_image = ti_sci_cmd_proc_auth_boot_image;
 	pops->get_proc_boot_status = ti_sci_cmd_get_proc_boot_status;
+	pops->proc_shutdown_no_wait = ti_sci_cmd_proc_shutdown_no_wait;
 
 	rops->config = ti_sci_cmd_ring_config;
 	rops->get_config = ti_sci_cmd_ring_get_config;
diff --git a/drivers/firmware/ti_sci.h b/drivers/firmware/ti_sci.h
index a484b1fa40..69ff74d6a9 100644
--- a/drivers/firmware/ti_sci.h
+++ b/drivers/firmware/ti_sci.h
@@ -50,6 +50,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
 
 /* Resource Management Requests */
 #define TI_SCI_MSG_GET_RESOURCE_RANGE	0x1500
@@ -772,6 +773,55 @@ struct ti_sci_msg_resp_get_proc_boot_status {
 	u32 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;
+	u8 processor_id;
+	u8 num_wait_iterations;
+	u8 num_match_iterations;
+	u8 delay_per_iteration_us;
+	u8 delay_before_iterations_us;
+	u32 status_flags_1_set_all_wait;
+	u32 status_flags_1_set_any_wait;
+	u32 status_flags_1_clr_all_wait;
+	u32 status_flags_1_clr_any_wait;
+} __packed;
+
 /**
  * struct ti_sci_msg_rm_ring_cfg_req - Configure a Navigator Subsystem ring
  *
diff --git a/include/linux/soc/ti/ti_sci_protocol.h b/include/linux/soc/ti/ti_sci_protocol.h
index 842fb596f7..cd6e5853b4 100644
--- a/include/linux/soc/ti/ti_sci_protocol.h
+++ b/include/linux/soc/ti/ti_sci_protocol.h
@@ -266,6 +266,8 @@ struct ti_sci_core_ops {
  * @set_proc_boot_ctrl: Setup limited control flags in specific cases.
  * @proc_auth_boot_image:
  * @get_proc_boot_status: Get the state of physical processor
+ * @proc_shutdown_no_wait: Shutdown a core without requesting or waiting for a
+ *			   response.
  *
  * NOTE: for all these functions, the following parameters are generic in
  * nature:
@@ -287,6 +289,8 @@ struct ti_sci_proc_ops {
 	int (*get_proc_boot_status)(const struct ti_sci_handle *handle, u8 pid,
 				    u64 *bv, u32 *cfg_flags, u32 *ctrl_flags,
 				    u32 *sts_flags);
+	int (*proc_shutdown_no_wait)(const struct ti_sci_handle *handle,
+				     u8 pid);
 };
 
 #define TI_SCI_RING_MODE_RING			(0)
-- 
2.17.1



More information about the U-Boot mailing list