All of lore.kernel.org
 help / color / mirror / Atom feed
From: Lokesh Vutla <lokeshvutla@ti.com>
To: u-boot@lists.denx.de
Subject: [U-Boot] [PATCH v2 2/7] firmware: ti_sci: Add processor shutdown API method
Date: Tue, 21 May 2019 23:32:19 -0500	[thread overview]
Message-ID: <20190522043224.14986-3-lokeshvutla@ti.com> (raw)
In-Reply-To: <20190522043224.14986-1-lokeshvutla@ti.com>

From: Andreas Dannenberg <dannenberg@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@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

  parent reply	other threads:[~2019-05-22  4:32 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-05-22  4:32 [U-Boot] [PATCH v2 0/7] arm: k3: Allow for exclusive and shared device requests Lokesh Vutla
2019-05-22  4:32 ` [U-Boot] [PATCH v2 1/7] firmware: ti_sci: Allow for device shared and exclusive requests Lokesh Vutla
2019-05-22  4:32 ` Lokesh Vutla [this message]
2019-05-22  4:32 ` [U-Boot] [PATCH v2 3/7] armv7R: K3: am654: Shut down R5 core after ATF startup on A53 Lokesh Vutla
2019-05-22  4:32 ` [U-Boot] [PATCH v2 4/7] power-domain: Add private data to power domain Lokesh Vutla
2019-05-22  4:32 ` [U-Boot] [PATCH v2 5/7] dt-bindings: ti_sci_pm_domains: Add support for exclusive and shared access Lokesh Vutla
2019-05-22  4:32 ` [U-Boot] [PATCH v2 6/7] power: domain: ti_sci_power_domains: " Lokesh Vutla
2019-05-22  4:32 ` [U-Boot] [PATCH v2 7/7] armv7R: dts: k3-am654: Update power-domains property for each node Lokesh Vutla

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20190522043224.14986-3-lokeshvutla@ti.com \
    --to=lokeshvutla@ti.com \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.