xref: /openbmc/u-boot/drivers/firmware/ti_sci.c (revision 7bc330452c38db9c01357623eb6785b7ac8866b2)
132cd2512SLokesh Vutla // SPDX-License-Identifier: GPL-2.0+
232cd2512SLokesh Vutla /*
332cd2512SLokesh Vutla  * Texas Instruments System Control Interface Protocol Driver
432cd2512SLokesh Vutla  * Based on drivers/firmware/ti_sci.c from Linux.
532cd2512SLokesh Vutla  *
632cd2512SLokesh Vutla  * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
732cd2512SLokesh Vutla  *	Lokesh Vutla <lokeshvutla@ti.com>
832cd2512SLokesh Vutla  */
932cd2512SLokesh Vutla 
1032cd2512SLokesh Vutla #include <common.h>
1132cd2512SLokesh Vutla #include <dm.h>
1232cd2512SLokesh Vutla #include <errno.h>
1332cd2512SLokesh Vutla #include <mailbox.h>
1432cd2512SLokesh Vutla #include <dm/device.h>
1532cd2512SLokesh Vutla #include <linux/err.h>
1632cd2512SLokesh Vutla #include <linux/soc/ti/k3-sec-proxy.h>
1732cd2512SLokesh Vutla #include <linux/soc/ti/ti_sci_protocol.h>
1832cd2512SLokesh Vutla 
1932cd2512SLokesh Vutla #include "ti_sci.h"
2032cd2512SLokesh Vutla 
2132cd2512SLokesh Vutla /* List of all TI SCI devices active in system */
2232cd2512SLokesh Vutla static LIST_HEAD(ti_sci_list);
2332cd2512SLokesh Vutla 
2432cd2512SLokesh Vutla /**
2532cd2512SLokesh Vutla  * struct ti_sci_xfer - Structure representing a message flow
2632cd2512SLokesh Vutla  * @tx_message:	Transmit message
2732cd2512SLokesh Vutla  * @rx_len:	Receive message length
2832cd2512SLokesh Vutla  */
2932cd2512SLokesh Vutla struct ti_sci_xfer {
3032cd2512SLokesh Vutla 	struct k3_sec_proxy_msg tx_message;
3132cd2512SLokesh Vutla 	u8 rx_len;
3232cd2512SLokesh Vutla };
3332cd2512SLokesh Vutla 
3432cd2512SLokesh Vutla /**
3532cd2512SLokesh Vutla  * struct ti_sci_desc - Description of SoC integration
3632cd2512SLokesh Vutla  * @host_id:		Host identifier representing the compute entity
3732cd2512SLokesh Vutla  * @max_rx_timeout_us:	Timeout for communication with SoC (in Microseconds)
3832cd2512SLokesh Vutla  * @max_msg_size:	Maximum size of data per message that can be handled.
3932cd2512SLokesh Vutla  */
4032cd2512SLokesh Vutla struct ti_sci_desc {
4132cd2512SLokesh Vutla 	u8 host_id;
4232cd2512SLokesh Vutla 	int max_rx_timeout_us;
4332cd2512SLokesh Vutla 	int max_msg_size;
4432cd2512SLokesh Vutla };
4532cd2512SLokesh Vutla 
4632cd2512SLokesh Vutla /**
4732cd2512SLokesh Vutla  * struct ti_sci_info - Structure representing a TI SCI instance
4832cd2512SLokesh Vutla  * @dev:	Device pointer
4932cd2512SLokesh Vutla  * @desc:	SoC description for this instance
5032cd2512SLokesh Vutla  * @handle:	Instance of TI SCI handle to send to clients.
5132cd2512SLokesh Vutla  * @chan_tx:	Transmit mailbox channel
5232cd2512SLokesh Vutla  * @chan_rx:	Receive mailbox channel
5332cd2512SLokesh Vutla  * @xfer:	xfer info
5432cd2512SLokesh Vutla  * @list:	list head
5532cd2512SLokesh Vutla  * @is_secure:	Determines if the communication is through secure threads.
5632cd2512SLokesh Vutla  * @host_id:	Host identifier representing the compute entity
5732cd2512SLokesh Vutla  * @seq:	Seq id used for verification for tx and rx message.
5832cd2512SLokesh Vutla  */
5932cd2512SLokesh Vutla struct ti_sci_info {
6032cd2512SLokesh Vutla 	struct udevice *dev;
6132cd2512SLokesh Vutla 	const struct ti_sci_desc *desc;
6232cd2512SLokesh Vutla 	struct ti_sci_handle handle;
6332cd2512SLokesh Vutla 	struct mbox_chan chan_tx;
6432cd2512SLokesh Vutla 	struct mbox_chan chan_rx;
6532cd2512SLokesh Vutla 	struct mbox_chan chan_notify;
6632cd2512SLokesh Vutla 	struct ti_sci_xfer xfer;
6732cd2512SLokesh Vutla 	struct list_head list;
6832cd2512SLokesh Vutla 	bool is_secure;
6932cd2512SLokesh Vutla 	u8 host_id;
7032cd2512SLokesh Vutla 	u8 seq;
7132cd2512SLokesh Vutla };
7232cd2512SLokesh Vutla 
7332cd2512SLokesh Vutla #define handle_to_ti_sci_info(h) container_of(h, struct ti_sci_info, handle)
7432cd2512SLokesh Vutla 
7532cd2512SLokesh Vutla /**
7632cd2512SLokesh Vutla  * ti_sci_setup_one_xfer() - Setup one message type
7732cd2512SLokesh Vutla  * @info:	Pointer to SCI entity information
7832cd2512SLokesh Vutla  * @msg_type:	Message type
7932cd2512SLokesh Vutla  * @msg_flags:	Flag to set for the message
8032cd2512SLokesh Vutla  * @buf:	Buffer to be send to mailbox channel
8132cd2512SLokesh Vutla  * @tx_message_size: transmit message size
8232cd2512SLokesh Vutla  * @rx_message_size: receive message size
8332cd2512SLokesh Vutla  *
8432cd2512SLokesh Vutla  * Helper function which is used by various command functions that are
8532cd2512SLokesh Vutla  * exposed to clients of this driver for allocating a message traffic event.
8632cd2512SLokesh Vutla  *
8732cd2512SLokesh Vutla  * Return: Corresponding ti_sci_xfer pointer if all went fine,
8832cd2512SLokesh Vutla  *	   else appropriate error pointer.
8932cd2512SLokesh Vutla  */
9032cd2512SLokesh Vutla static struct ti_sci_xfer *ti_sci_setup_one_xfer(struct ti_sci_info *info,
9132cd2512SLokesh Vutla 						 u16 msg_type, u32 msg_flags,
9232cd2512SLokesh Vutla 						 u32 *buf,
9332cd2512SLokesh Vutla 						 size_t tx_message_size,
9432cd2512SLokesh Vutla 						 size_t rx_message_size)
9532cd2512SLokesh Vutla {
9632cd2512SLokesh Vutla 	struct ti_sci_xfer *xfer = &info->xfer;
9732cd2512SLokesh Vutla 	struct ti_sci_msg_hdr *hdr;
9832cd2512SLokesh Vutla 
9932cd2512SLokesh Vutla 	/* Ensure we have sane transfer sizes */
10032cd2512SLokesh Vutla 	if (rx_message_size > info->desc->max_msg_size ||
10132cd2512SLokesh Vutla 	    tx_message_size > info->desc->max_msg_size ||
10232cd2512SLokesh Vutla 	    rx_message_size < sizeof(*hdr) || tx_message_size < sizeof(*hdr))
10332cd2512SLokesh Vutla 		return ERR_PTR(-ERANGE);
10432cd2512SLokesh Vutla 
10532cd2512SLokesh Vutla 	info->seq = ~info->seq;
10632cd2512SLokesh Vutla 	xfer->tx_message.buf = buf;
10732cd2512SLokesh Vutla 	xfer->tx_message.len = tx_message_size;
10832cd2512SLokesh Vutla 	xfer->rx_len = (u8)rx_message_size;
10932cd2512SLokesh Vutla 
11032cd2512SLokesh Vutla 	hdr = (struct ti_sci_msg_hdr *)buf;
11132cd2512SLokesh Vutla 	hdr->seq = info->seq;
11232cd2512SLokesh Vutla 	hdr->type = msg_type;
11332cd2512SLokesh Vutla 	hdr->host = info->host_id;
11432cd2512SLokesh Vutla 	hdr->flags = msg_flags;
11532cd2512SLokesh Vutla 
11632cd2512SLokesh Vutla 	return xfer;
11732cd2512SLokesh Vutla }
11832cd2512SLokesh Vutla 
11932cd2512SLokesh Vutla /**
12032cd2512SLokesh Vutla  * ti_sci_get_response() - Receive response from mailbox channel
12132cd2512SLokesh Vutla  * @info:	Pointer to SCI entity information
12232cd2512SLokesh Vutla  * @xfer:	Transfer to initiate and wait for response
12332cd2512SLokesh Vutla  * @chan:	Channel to receive the response
12432cd2512SLokesh Vutla  *
12532cd2512SLokesh Vutla  * Return: -ETIMEDOUT in case of no response, if transmit error,
12632cd2512SLokesh Vutla  *	   return corresponding error, else if all goes well,
12732cd2512SLokesh Vutla  *	   return 0.
12832cd2512SLokesh Vutla  */
12932cd2512SLokesh Vutla static inline int ti_sci_get_response(struct ti_sci_info *info,
13032cd2512SLokesh Vutla 				      struct ti_sci_xfer *xfer,
13132cd2512SLokesh Vutla 				      struct mbox_chan *chan)
13232cd2512SLokesh Vutla {
13332cd2512SLokesh Vutla 	struct k3_sec_proxy_msg *msg = &xfer->tx_message;
13432cd2512SLokesh Vutla 	struct ti_sci_secure_msg_hdr *secure_hdr;
13532cd2512SLokesh Vutla 	struct ti_sci_msg_hdr *hdr;
13632cd2512SLokesh Vutla 	int ret;
13732cd2512SLokesh Vutla 
13832cd2512SLokesh Vutla 	/* Receive the response */
13932cd2512SLokesh Vutla 	ret = mbox_recv(chan, msg, info->desc->max_rx_timeout_us);
14032cd2512SLokesh Vutla 	if (ret) {
14132cd2512SLokesh Vutla 		dev_err(info->dev, "%s: Message receive failed. ret = %d\n",
14232cd2512SLokesh Vutla 			__func__, ret);
14332cd2512SLokesh Vutla 		return ret;
14432cd2512SLokesh Vutla 	}
14532cd2512SLokesh Vutla 
14632cd2512SLokesh Vutla 	/* ToDo: Verify checksum */
14732cd2512SLokesh Vutla 	if (info->is_secure) {
14832cd2512SLokesh Vutla 		secure_hdr = (struct ti_sci_secure_msg_hdr *)msg->buf;
14932cd2512SLokesh Vutla 		msg->buf = (u32 *)((void *)msg->buf + sizeof(*secure_hdr));
15032cd2512SLokesh Vutla 	}
15132cd2512SLokesh Vutla 
15232cd2512SLokesh Vutla 	/* msg is updated by mailbox driver */
15332cd2512SLokesh Vutla 	hdr = (struct ti_sci_msg_hdr *)msg->buf;
15432cd2512SLokesh Vutla 
15532cd2512SLokesh Vutla 	/* Sanity check for message response */
15632cd2512SLokesh Vutla 	if (hdr->seq != info->seq) {
15732cd2512SLokesh Vutla 		dev_dbg(info->dev, "%s: Message for %d is not expected\n",
15832cd2512SLokesh Vutla 			__func__, hdr->seq);
15932cd2512SLokesh Vutla 		return ret;
16032cd2512SLokesh Vutla 	}
16132cd2512SLokesh Vutla 
16232cd2512SLokesh Vutla 	if (msg->len > info->desc->max_msg_size) {
16332cd2512SLokesh Vutla 		dev_err(info->dev, "%s: Unable to handle %zu xfer (max %d)\n",
16432cd2512SLokesh Vutla 			__func__, msg->len, info->desc->max_msg_size);
16532cd2512SLokesh Vutla 		return -EINVAL;
16632cd2512SLokesh Vutla 	}
16732cd2512SLokesh Vutla 
16832cd2512SLokesh Vutla 	if (msg->len < xfer->rx_len) {
16932cd2512SLokesh Vutla 		dev_err(info->dev, "%s: Recv xfer %zu < expected %d length\n",
17032cd2512SLokesh Vutla 			__func__, msg->len, xfer->rx_len);
17132cd2512SLokesh Vutla 	}
17232cd2512SLokesh Vutla 
17332cd2512SLokesh Vutla 	return ret;
17432cd2512SLokesh Vutla }
17532cd2512SLokesh Vutla 
17632cd2512SLokesh Vutla /**
17732cd2512SLokesh Vutla  * ti_sci_do_xfer() - Do one transfer
17832cd2512SLokesh Vutla  * @info:	Pointer to SCI entity information
17932cd2512SLokesh Vutla  * @xfer:	Transfer to initiate and wait for response
18032cd2512SLokesh Vutla  *
18132cd2512SLokesh Vutla  * Return: 0 if all went fine, else return appropriate error.
18232cd2512SLokesh Vutla  */
18332cd2512SLokesh Vutla static inline int ti_sci_do_xfer(struct ti_sci_info *info,
18432cd2512SLokesh Vutla 				 struct ti_sci_xfer *xfer)
18532cd2512SLokesh Vutla {
18632cd2512SLokesh Vutla 	struct k3_sec_proxy_msg *msg = &xfer->tx_message;
18732cd2512SLokesh Vutla 	u8 secure_buf[info->desc->max_msg_size];
18832cd2512SLokesh Vutla 	struct ti_sci_secure_msg_hdr secure_hdr;
18932cd2512SLokesh Vutla 	int ret;
19032cd2512SLokesh Vutla 
19132cd2512SLokesh Vutla 	if (info->is_secure) {
19232cd2512SLokesh Vutla 		/* ToDo: get checksum of the entire message */
19332cd2512SLokesh Vutla 		secure_hdr.checksum = 0;
19432cd2512SLokesh Vutla 		secure_hdr.reserved = 0;
19532cd2512SLokesh Vutla 		memcpy(&secure_buf[sizeof(secure_hdr)], xfer->tx_message.buf,
19632cd2512SLokesh Vutla 		       xfer->tx_message.len);
19732cd2512SLokesh Vutla 
19832cd2512SLokesh Vutla 		xfer->tx_message.buf = (u32 *)secure_buf;
19932cd2512SLokesh Vutla 		xfer->tx_message.len += sizeof(secure_hdr);
20032cd2512SLokesh Vutla 		xfer->rx_len += sizeof(secure_hdr);
20132cd2512SLokesh Vutla 	}
20232cd2512SLokesh Vutla 
20332cd2512SLokesh Vutla 	/* Send the message */
20432cd2512SLokesh Vutla 	ret = mbox_send(&info->chan_tx, msg);
20532cd2512SLokesh Vutla 	if (ret) {
20632cd2512SLokesh Vutla 		dev_err(info->dev, "%s: Message sending failed. ret = %d\n",
20732cd2512SLokesh Vutla 			__func__, ret);
20832cd2512SLokesh Vutla 		return ret;
20932cd2512SLokesh Vutla 	}
21032cd2512SLokesh Vutla 
21132cd2512SLokesh Vutla 	return ti_sci_get_response(info, xfer, &info->chan_rx);
21232cd2512SLokesh Vutla }
21332cd2512SLokesh Vutla 
21432cd2512SLokesh Vutla /**
21532cd2512SLokesh Vutla  * ti_sci_cmd_get_revision() - command to get the revision of the SCI entity
21632cd2512SLokesh Vutla  * @handle:	pointer to TI SCI handle
21732cd2512SLokesh Vutla  *
21832cd2512SLokesh Vutla  * Updates the SCI information in the internal data structure.
21932cd2512SLokesh Vutla  *
22032cd2512SLokesh Vutla  * Return: 0 if all went fine, else return appropriate error.
22132cd2512SLokesh Vutla  */
22232cd2512SLokesh Vutla static int ti_sci_cmd_get_revision(struct ti_sci_handle *handle)
22332cd2512SLokesh Vutla {
22432cd2512SLokesh Vutla 	struct ti_sci_msg_resp_version *rev_info;
22532cd2512SLokesh Vutla 	struct ti_sci_version_info *ver;
22632cd2512SLokesh Vutla 	struct ti_sci_msg_hdr hdr;
22732cd2512SLokesh Vutla 	struct ti_sci_info *info;
22832cd2512SLokesh Vutla 	struct ti_sci_xfer *xfer;
22932cd2512SLokesh Vutla 	int ret;
23032cd2512SLokesh Vutla 
23132cd2512SLokesh Vutla 	if (IS_ERR(handle))
23232cd2512SLokesh Vutla 		return PTR_ERR(handle);
23332cd2512SLokesh Vutla 	if (!handle)
23432cd2512SLokesh Vutla 		return -EINVAL;
23532cd2512SLokesh Vutla 
23632cd2512SLokesh Vutla 	info = handle_to_ti_sci_info(handle);
23732cd2512SLokesh Vutla 
23832cd2512SLokesh Vutla 	xfer = ti_sci_setup_one_xfer(info, TI_SCI_MSG_VERSION, 0x0,
23932cd2512SLokesh Vutla 				     (u32 *)&hdr, sizeof(struct ti_sci_msg_hdr),
24032cd2512SLokesh Vutla 				     sizeof(*rev_info));
24132cd2512SLokesh Vutla 	if (IS_ERR(xfer)) {
24232cd2512SLokesh Vutla 		ret = PTR_ERR(xfer);
24332cd2512SLokesh Vutla 		dev_err(info->dev, "Message alloc failed(%d)\n", ret);
24432cd2512SLokesh Vutla 		return ret;
24532cd2512SLokesh Vutla 	}
24632cd2512SLokesh Vutla 
24732cd2512SLokesh Vutla 	ret = ti_sci_do_xfer(info, xfer);
24832cd2512SLokesh Vutla 	if (ret) {
24932cd2512SLokesh Vutla 		dev_err(info->dev, "Mbox communication fail %d\n", ret);
25032cd2512SLokesh Vutla 		return ret;
25132cd2512SLokesh Vutla 	}
25232cd2512SLokesh Vutla 
25332cd2512SLokesh Vutla 	rev_info = (struct ti_sci_msg_resp_version *)xfer->tx_message.buf;
25432cd2512SLokesh Vutla 
25532cd2512SLokesh Vutla 	ver = &handle->version;
25632cd2512SLokesh Vutla 	ver->abi_major = rev_info->abi_major;
25732cd2512SLokesh Vutla 	ver->abi_minor = rev_info->abi_minor;
25832cd2512SLokesh Vutla 	ver->firmware_revision = rev_info->firmware_revision;
25932cd2512SLokesh Vutla 	strncpy(ver->firmware_description, rev_info->firmware_description,
26032cd2512SLokesh Vutla 		sizeof(ver->firmware_description));
26132cd2512SLokesh Vutla 
26232cd2512SLokesh Vutla 	return 0;
26332cd2512SLokesh Vutla }
26432cd2512SLokesh Vutla 
26532cd2512SLokesh Vutla /**
26632cd2512SLokesh Vutla  * ti_sci_is_response_ack() - Generic ACK/NACK message checkup
26732cd2512SLokesh Vutla  * @r:	pointer to response buffer
26832cd2512SLokesh Vutla  *
26932cd2512SLokesh Vutla  * Return: true if the response was an ACK, else returns false.
27032cd2512SLokesh Vutla  */
27132cd2512SLokesh Vutla static inline bool ti_sci_is_response_ack(void *r)
27232cd2512SLokesh Vutla {
27332cd2512SLokesh Vutla 	struct ti_sci_msg_hdr *hdr = r;
27432cd2512SLokesh Vutla 
27532cd2512SLokesh Vutla 	return hdr->flags & TI_SCI_FLAG_RESP_GENERIC_ACK ? true : false;
27632cd2512SLokesh Vutla }
27732cd2512SLokesh Vutla 
27832cd2512SLokesh Vutla /**
279dcfc52adSAndreas Dannenberg  * cmd_set_board_config_using_msg() - Common command to send board configuration
280dcfc52adSAndreas Dannenberg  *                                    message
281dcfc52adSAndreas Dannenberg  * @handle:	pointer to TI SCI handle
282dcfc52adSAndreas Dannenberg  * @msg_type:	One of the TISCI message types to set board configuration
283dcfc52adSAndreas Dannenberg  * @addr:	Address where the board config structure is located
284dcfc52adSAndreas Dannenberg  * @size:	Size of the board config structure
285dcfc52adSAndreas Dannenberg  *
286dcfc52adSAndreas Dannenberg  * Return: 0 if all went well, else returns appropriate error value.
287dcfc52adSAndreas Dannenberg  */
288dcfc52adSAndreas Dannenberg static int cmd_set_board_config_using_msg(const struct ti_sci_handle *handle,
289dcfc52adSAndreas Dannenberg 					  u16 msg_type, u64 addr, u32 size)
290dcfc52adSAndreas Dannenberg {
291dcfc52adSAndreas Dannenberg 	struct ti_sci_msg_board_config req;
292dcfc52adSAndreas Dannenberg 	struct ti_sci_msg_hdr *resp;
293dcfc52adSAndreas Dannenberg 	struct ti_sci_info *info;
294dcfc52adSAndreas Dannenberg 	struct ti_sci_xfer *xfer;
295dcfc52adSAndreas Dannenberg 	int ret = 0;
296dcfc52adSAndreas Dannenberg 
297dcfc52adSAndreas Dannenberg 	if (IS_ERR(handle))
298dcfc52adSAndreas Dannenberg 		return PTR_ERR(handle);
299dcfc52adSAndreas Dannenberg 	if (!handle)
300dcfc52adSAndreas Dannenberg 		return -EINVAL;
301dcfc52adSAndreas Dannenberg 
302dcfc52adSAndreas Dannenberg 	info = handle_to_ti_sci_info(handle);
303dcfc52adSAndreas Dannenberg 
304dcfc52adSAndreas Dannenberg 	xfer = ti_sci_setup_one_xfer(info, msg_type,
305dcfc52adSAndreas Dannenberg 				     TI_SCI_FLAG_REQ_ACK_ON_PROCESSED,
306dcfc52adSAndreas Dannenberg 				     (u32 *)&req, sizeof(req), sizeof(*resp));
307dcfc52adSAndreas Dannenberg 	if (IS_ERR(xfer)) {
308dcfc52adSAndreas Dannenberg 		ret = PTR_ERR(xfer);
309dcfc52adSAndreas Dannenberg 		dev_err(info->dev, "Message alloc failed(%d)\n", ret);
310dcfc52adSAndreas Dannenberg 		return ret;
311dcfc52adSAndreas Dannenberg 	}
312dcfc52adSAndreas Dannenberg 	req.boardcfgp_high = (addr >> 32) & 0xffffffff;
313dcfc52adSAndreas Dannenberg 	req.boardcfgp_low = addr & 0xffffffff;
314dcfc52adSAndreas Dannenberg 	req.boardcfg_size = size;
315dcfc52adSAndreas Dannenberg 
316dcfc52adSAndreas Dannenberg 	ret = ti_sci_do_xfer(info, xfer);
317dcfc52adSAndreas Dannenberg 	if (ret) {
318dcfc52adSAndreas Dannenberg 		dev_err(info->dev, "Mbox send fail %d\n", ret);
319dcfc52adSAndreas Dannenberg 		return ret;
320dcfc52adSAndreas Dannenberg 	}
321dcfc52adSAndreas Dannenberg 
322dcfc52adSAndreas Dannenberg 	resp = (struct ti_sci_msg_hdr *)xfer->tx_message.buf;
323dcfc52adSAndreas Dannenberg 
324dcfc52adSAndreas Dannenberg 	if (!ti_sci_is_response_ack(resp))
325dcfc52adSAndreas Dannenberg 		return -ENODEV;
326dcfc52adSAndreas Dannenberg 
327dcfc52adSAndreas Dannenberg 	return ret;
328dcfc52adSAndreas Dannenberg }
329dcfc52adSAndreas Dannenberg 
330dcfc52adSAndreas Dannenberg /**
331dcfc52adSAndreas Dannenberg  * ti_sci_cmd_set_board_config() - Command to send board configuration message
332dcfc52adSAndreas Dannenberg  * @handle:	pointer to TI SCI handle
333dcfc52adSAndreas Dannenberg  * @addr:	Address where the board config structure is located
334dcfc52adSAndreas Dannenberg  * @size:	Size of the board config structure
335dcfc52adSAndreas Dannenberg  *
336dcfc52adSAndreas Dannenberg  * Return: 0 if all went well, else returns appropriate error value.
337dcfc52adSAndreas Dannenberg  */
338dcfc52adSAndreas Dannenberg static int ti_sci_cmd_set_board_config(const struct ti_sci_handle *handle,
339dcfc52adSAndreas Dannenberg 				       u64 addr, u32 size)
340dcfc52adSAndreas Dannenberg {
341dcfc52adSAndreas Dannenberg 	return cmd_set_board_config_using_msg(handle,
342dcfc52adSAndreas Dannenberg 					      TI_SCI_MSG_BOARD_CONFIG,
343dcfc52adSAndreas Dannenberg 					      addr, size);
344dcfc52adSAndreas Dannenberg }
345dcfc52adSAndreas Dannenberg 
346dcfc52adSAndreas Dannenberg /**
347dcfc52adSAndreas Dannenberg  * ti_sci_cmd_set_board_config_rm() - Command to send board resource
348dcfc52adSAndreas Dannenberg  *				      management configuration
349dcfc52adSAndreas Dannenberg  * @handle:	pointer to TI SCI handle
350dcfc52adSAndreas Dannenberg  * @addr:	Address where the board RM config structure is located
351dcfc52adSAndreas Dannenberg  * @size:	Size of the RM config structure
352dcfc52adSAndreas Dannenberg  *
353dcfc52adSAndreas Dannenberg  * Return: 0 if all went well, else returns appropriate error value.
354dcfc52adSAndreas Dannenberg  */
355dcfc52adSAndreas Dannenberg static
356dcfc52adSAndreas Dannenberg int ti_sci_cmd_set_board_config_rm(const struct ti_sci_handle *handle,
357dcfc52adSAndreas Dannenberg 				   u64 addr, u32 size)
358dcfc52adSAndreas Dannenberg {
359dcfc52adSAndreas Dannenberg 	return cmd_set_board_config_using_msg(handle,
360dcfc52adSAndreas Dannenberg 					      TI_SCI_MSG_BOARD_CONFIG_RM,
361dcfc52adSAndreas Dannenberg 					      addr, size);
362dcfc52adSAndreas Dannenberg }
363dcfc52adSAndreas Dannenberg 
364dcfc52adSAndreas Dannenberg /**
365dcfc52adSAndreas Dannenberg  * ti_sci_cmd_set_board_config_security() - Command to send board security
366dcfc52adSAndreas Dannenberg  *					    configuration message
367dcfc52adSAndreas Dannenberg  * @handle:	pointer to TI SCI handle
368dcfc52adSAndreas Dannenberg  * @addr:	Address where the board security config structure is located
369dcfc52adSAndreas Dannenberg  * @size:	Size of the security config structure
370dcfc52adSAndreas Dannenberg  *
371dcfc52adSAndreas Dannenberg  * Return: 0 if all went well, else returns appropriate error value.
372dcfc52adSAndreas Dannenberg  */
373dcfc52adSAndreas Dannenberg static
374dcfc52adSAndreas Dannenberg int ti_sci_cmd_set_board_config_security(const struct ti_sci_handle *handle,
375dcfc52adSAndreas Dannenberg 					 u64 addr, u32 size)
376dcfc52adSAndreas Dannenberg {
377dcfc52adSAndreas Dannenberg 	return cmd_set_board_config_using_msg(handle,
378dcfc52adSAndreas Dannenberg 					      TI_SCI_MSG_BOARD_CONFIG_SECURITY,
379dcfc52adSAndreas Dannenberg 					      addr, size);
380dcfc52adSAndreas Dannenberg }
381dcfc52adSAndreas Dannenberg 
382dcfc52adSAndreas Dannenberg /**
383dcfc52adSAndreas Dannenberg  * ti_sci_cmd_set_board_config_pm() - Command to send board power and clock
384dcfc52adSAndreas Dannenberg  *				      configuration message
385dcfc52adSAndreas Dannenberg  * @handle:	pointer to TI SCI handle
386dcfc52adSAndreas Dannenberg  * @addr:	Address where the board PM config structure is located
387dcfc52adSAndreas Dannenberg  * @size:	Size of the PM config structure
388dcfc52adSAndreas Dannenberg  *
389dcfc52adSAndreas Dannenberg  * Return: 0 if all went well, else returns appropriate error value.
390dcfc52adSAndreas Dannenberg  */
391dcfc52adSAndreas Dannenberg static int ti_sci_cmd_set_board_config_pm(const struct ti_sci_handle *handle,
392dcfc52adSAndreas Dannenberg 					  u64 addr, u32 size)
393dcfc52adSAndreas Dannenberg {
394dcfc52adSAndreas Dannenberg 	return cmd_set_board_config_using_msg(handle,
395dcfc52adSAndreas Dannenberg 					      TI_SCI_MSG_BOARD_CONFIG_PM,
396dcfc52adSAndreas Dannenberg 					      addr, size);
397dcfc52adSAndreas Dannenberg }
398dcfc52adSAndreas Dannenberg 
399*7bc33045SAndreas Dannenberg /**
400*7bc33045SAndreas Dannenberg  * ti_sci_set_device_state() - Set device state helper
401*7bc33045SAndreas Dannenberg  * @handle:	pointer to TI SCI handle
402*7bc33045SAndreas Dannenberg  * @id:		Device identifier
403*7bc33045SAndreas Dannenberg  * @flags:	flags to setup for the device
404*7bc33045SAndreas Dannenberg  * @state:	State to move the device to
405*7bc33045SAndreas Dannenberg  *
406*7bc33045SAndreas Dannenberg  * Return: 0 if all went well, else returns appropriate error value.
407*7bc33045SAndreas Dannenberg  */
408*7bc33045SAndreas Dannenberg static int ti_sci_set_device_state(const struct ti_sci_handle *handle,
409*7bc33045SAndreas Dannenberg 				   u32 id, u32 flags, u8 state)
410*7bc33045SAndreas Dannenberg {
411*7bc33045SAndreas Dannenberg 	struct ti_sci_msg_req_set_device_state req;
412*7bc33045SAndreas Dannenberg 	struct ti_sci_msg_hdr *resp;
413*7bc33045SAndreas Dannenberg 	struct ti_sci_info *info;
414*7bc33045SAndreas Dannenberg 	struct ti_sci_xfer *xfer;
415*7bc33045SAndreas Dannenberg 	int ret = 0;
416*7bc33045SAndreas Dannenberg 
417*7bc33045SAndreas Dannenberg 	if (IS_ERR(handle))
418*7bc33045SAndreas Dannenberg 		return PTR_ERR(handle);
419*7bc33045SAndreas Dannenberg 	if (!handle)
420*7bc33045SAndreas Dannenberg 		return -EINVAL;
421*7bc33045SAndreas Dannenberg 
422*7bc33045SAndreas Dannenberg 	info = handle_to_ti_sci_info(handle);
423*7bc33045SAndreas Dannenberg 
424*7bc33045SAndreas Dannenberg 	xfer = ti_sci_setup_one_xfer(info, TI_SCI_MSG_SET_DEVICE_STATE,
425*7bc33045SAndreas Dannenberg 				     flags | TI_SCI_FLAG_REQ_ACK_ON_PROCESSED,
426*7bc33045SAndreas Dannenberg 				     (u32 *)&req, sizeof(req), sizeof(*resp));
427*7bc33045SAndreas Dannenberg 	if (IS_ERR(xfer)) {
428*7bc33045SAndreas Dannenberg 		ret = PTR_ERR(xfer);
429*7bc33045SAndreas Dannenberg 		dev_err(info->dev, "Message alloc failed(%d)\n", ret);
430*7bc33045SAndreas Dannenberg 		return ret;
431*7bc33045SAndreas Dannenberg 	}
432*7bc33045SAndreas Dannenberg 	req.id = id;
433*7bc33045SAndreas Dannenberg 	req.state = state;
434*7bc33045SAndreas Dannenberg 
435*7bc33045SAndreas Dannenberg 	ret = ti_sci_do_xfer(info, xfer);
436*7bc33045SAndreas Dannenberg 	if (ret) {
437*7bc33045SAndreas Dannenberg 		dev_err(info->dev, "Mbox send fail %d\n", ret);
438*7bc33045SAndreas Dannenberg 		return ret;
439*7bc33045SAndreas Dannenberg 	}
440*7bc33045SAndreas Dannenberg 
441*7bc33045SAndreas Dannenberg 	resp = (struct ti_sci_msg_hdr *)xfer->tx_message.buf;
442*7bc33045SAndreas Dannenberg 
443*7bc33045SAndreas Dannenberg 	if (!ti_sci_is_response_ack(resp))
444*7bc33045SAndreas Dannenberg 		return -ENODEV;
445*7bc33045SAndreas Dannenberg 
446*7bc33045SAndreas Dannenberg 	return ret;
447*7bc33045SAndreas Dannenberg }
448*7bc33045SAndreas Dannenberg 
449*7bc33045SAndreas Dannenberg /**
450*7bc33045SAndreas Dannenberg  * ti_sci_get_device_state() - Get device state helper
451*7bc33045SAndreas Dannenberg  * @handle:	Handle to the device
452*7bc33045SAndreas Dannenberg  * @id:		Device Identifier
453*7bc33045SAndreas Dannenberg  * @clcnt:	Pointer to Context Loss Count
454*7bc33045SAndreas Dannenberg  * @resets:	pointer to resets
455*7bc33045SAndreas Dannenberg  * @p_state:	pointer to p_state
456*7bc33045SAndreas Dannenberg  * @c_state:	pointer to c_state
457*7bc33045SAndreas Dannenberg  *
458*7bc33045SAndreas Dannenberg  * Return: 0 if all went fine, else return appropriate error.
459*7bc33045SAndreas Dannenberg  */
460*7bc33045SAndreas Dannenberg static int ti_sci_get_device_state(const struct ti_sci_handle *handle,
461*7bc33045SAndreas Dannenberg 				   u32 id,  u32 *clcnt,  u32 *resets,
462*7bc33045SAndreas Dannenberg 				   u8 *p_state,  u8 *c_state)
463*7bc33045SAndreas Dannenberg {
464*7bc33045SAndreas Dannenberg 	struct ti_sci_msg_resp_get_device_state *resp;
465*7bc33045SAndreas Dannenberg 	struct ti_sci_msg_req_get_device_state req;
466*7bc33045SAndreas Dannenberg 	struct ti_sci_info *info;
467*7bc33045SAndreas Dannenberg 	struct ti_sci_xfer *xfer;
468*7bc33045SAndreas Dannenberg 	int ret = 0;
469*7bc33045SAndreas Dannenberg 
470*7bc33045SAndreas Dannenberg 	if (IS_ERR(handle))
471*7bc33045SAndreas Dannenberg 		return PTR_ERR(handle);
472*7bc33045SAndreas Dannenberg 	if (!handle)
473*7bc33045SAndreas Dannenberg 		return -EINVAL;
474*7bc33045SAndreas Dannenberg 
475*7bc33045SAndreas Dannenberg 	if (!clcnt && !resets && !p_state && !c_state)
476*7bc33045SAndreas Dannenberg 		return -EINVAL;
477*7bc33045SAndreas Dannenberg 
478*7bc33045SAndreas Dannenberg 	info = handle_to_ti_sci_info(handle);
479*7bc33045SAndreas Dannenberg 
480*7bc33045SAndreas Dannenberg 	/* Response is expected, so need of any flags */
481*7bc33045SAndreas Dannenberg 	xfer = ti_sci_setup_one_xfer(info, TI_SCI_MSG_GET_DEVICE_STATE, 0,
482*7bc33045SAndreas Dannenberg 				     (u32 *)&req, sizeof(req), sizeof(*resp));
483*7bc33045SAndreas Dannenberg 	if (IS_ERR(xfer)) {
484*7bc33045SAndreas Dannenberg 		ret = PTR_ERR(xfer);
485*7bc33045SAndreas Dannenberg 		dev_err(info->dev, "Message alloc failed(%d)\n", ret);
486*7bc33045SAndreas Dannenberg 		return ret;
487*7bc33045SAndreas Dannenberg 	}
488*7bc33045SAndreas Dannenberg 	req.id = id;
489*7bc33045SAndreas Dannenberg 
490*7bc33045SAndreas Dannenberg 	ret = ti_sci_do_xfer(info, xfer);
491*7bc33045SAndreas Dannenberg 	if (ret) {
492*7bc33045SAndreas Dannenberg 		dev_err(dev, "Mbox send fail %d\n", ret);
493*7bc33045SAndreas Dannenberg 		return ret;
494*7bc33045SAndreas Dannenberg 	}
495*7bc33045SAndreas Dannenberg 
496*7bc33045SAndreas Dannenberg 	resp = (struct ti_sci_msg_resp_get_device_state *)xfer->tx_message.buf;
497*7bc33045SAndreas Dannenberg 	if (!ti_sci_is_response_ack(resp))
498*7bc33045SAndreas Dannenberg 		return -ENODEV;
499*7bc33045SAndreas Dannenberg 
500*7bc33045SAndreas Dannenberg 	if (clcnt)
501*7bc33045SAndreas Dannenberg 		*clcnt = resp->context_loss_count;
502*7bc33045SAndreas Dannenberg 	if (resets)
503*7bc33045SAndreas Dannenberg 		*resets = resp->resets;
504*7bc33045SAndreas Dannenberg 	if (p_state)
505*7bc33045SAndreas Dannenberg 		*p_state = resp->programmed_state;
506*7bc33045SAndreas Dannenberg 	if (c_state)
507*7bc33045SAndreas Dannenberg 		*c_state = resp->current_state;
508*7bc33045SAndreas Dannenberg 
509*7bc33045SAndreas Dannenberg 	return ret;
510*7bc33045SAndreas Dannenberg }
511*7bc33045SAndreas Dannenberg 
512*7bc33045SAndreas Dannenberg /**
513*7bc33045SAndreas Dannenberg  * ti_sci_cmd_get_device() - command to request for device managed by TISCI
514*7bc33045SAndreas Dannenberg  * @handle:	Pointer to TISCI handle as retrieved by *ti_sci_get_handle
515*7bc33045SAndreas Dannenberg  * @id:		Device Identifier
516*7bc33045SAndreas Dannenberg  *
517*7bc33045SAndreas Dannenberg  * Request for the device - NOTE: the client MUST maintain integrity of
518*7bc33045SAndreas Dannenberg  * usage count by balancing get_device with put_device. No refcounting is
519*7bc33045SAndreas Dannenberg  * managed by driver for that purpose.
520*7bc33045SAndreas Dannenberg  *
521*7bc33045SAndreas Dannenberg  * NOTE: The request is for exclusive access for the processor.
522*7bc33045SAndreas Dannenberg  *
523*7bc33045SAndreas Dannenberg  * Return: 0 if all went fine, else return appropriate error.
524*7bc33045SAndreas Dannenberg  */
525*7bc33045SAndreas Dannenberg static int ti_sci_cmd_get_device(const struct ti_sci_handle *handle, u32 id)
526*7bc33045SAndreas Dannenberg {
527*7bc33045SAndreas Dannenberg 	return ti_sci_set_device_state(handle, id,
528*7bc33045SAndreas Dannenberg 				       MSG_FLAG_DEVICE_EXCLUSIVE,
529*7bc33045SAndreas Dannenberg 				       MSG_DEVICE_SW_STATE_ON);
530*7bc33045SAndreas Dannenberg }
531*7bc33045SAndreas Dannenberg 
532*7bc33045SAndreas Dannenberg /**
533*7bc33045SAndreas Dannenberg  * ti_sci_cmd_idle_device() - Command to idle a device managed by TISCI
534*7bc33045SAndreas Dannenberg  * @handle:	Pointer to TISCI handle as retrieved by *ti_sci_get_handle
535*7bc33045SAndreas Dannenberg  * @id:		Device Identifier
536*7bc33045SAndreas Dannenberg  *
537*7bc33045SAndreas Dannenberg  * Request for the device - NOTE: the client MUST maintain integrity of
538*7bc33045SAndreas Dannenberg  * usage count by balancing get_device with put_device. No refcounting is
539*7bc33045SAndreas Dannenberg  * managed by driver for that purpose.
540*7bc33045SAndreas Dannenberg  *
541*7bc33045SAndreas Dannenberg  * Return: 0 if all went fine, else return appropriate error.
542*7bc33045SAndreas Dannenberg  */
543*7bc33045SAndreas Dannenberg static int ti_sci_cmd_idle_device(const struct ti_sci_handle *handle, u32 id)
544*7bc33045SAndreas Dannenberg {
545*7bc33045SAndreas Dannenberg 	return ti_sci_set_device_state(handle, id,
546*7bc33045SAndreas Dannenberg 				       MSG_FLAG_DEVICE_EXCLUSIVE,
547*7bc33045SAndreas Dannenberg 				       MSG_DEVICE_SW_STATE_RETENTION);
548*7bc33045SAndreas Dannenberg }
549*7bc33045SAndreas Dannenberg 
550*7bc33045SAndreas Dannenberg /**
551*7bc33045SAndreas Dannenberg  * ti_sci_cmd_put_device() - command to release a device managed by TISCI
552*7bc33045SAndreas Dannenberg  * @handle:	Pointer to TISCI handle as retrieved by *ti_sci_get_handle
553*7bc33045SAndreas Dannenberg  * @id:		Device Identifier
554*7bc33045SAndreas Dannenberg  *
555*7bc33045SAndreas Dannenberg  * Request for the device - NOTE: the client MUST maintain integrity of
556*7bc33045SAndreas Dannenberg  * usage count by balancing get_device with put_device. No refcounting is
557*7bc33045SAndreas Dannenberg  * managed by driver for that purpose.
558*7bc33045SAndreas Dannenberg  *
559*7bc33045SAndreas Dannenberg  * Return: 0 if all went fine, else return appropriate error.
560*7bc33045SAndreas Dannenberg  */
561*7bc33045SAndreas Dannenberg static int ti_sci_cmd_put_device(const struct ti_sci_handle *handle, u32 id)
562*7bc33045SAndreas Dannenberg {
563*7bc33045SAndreas Dannenberg 	return ti_sci_set_device_state(handle, id,
564*7bc33045SAndreas Dannenberg 				       0, MSG_DEVICE_SW_STATE_AUTO_OFF);
565*7bc33045SAndreas Dannenberg }
566*7bc33045SAndreas Dannenberg 
567*7bc33045SAndreas Dannenberg /**
568*7bc33045SAndreas Dannenberg  * ti_sci_cmd_dev_is_valid() - Is the device valid
569*7bc33045SAndreas Dannenberg  * @handle:	Pointer to TISCI handle as retrieved by *ti_sci_get_handle
570*7bc33045SAndreas Dannenberg  * @id:		Device Identifier
571*7bc33045SAndreas Dannenberg  *
572*7bc33045SAndreas Dannenberg  * Return: 0 if all went fine and the device ID is valid, else return
573*7bc33045SAndreas Dannenberg  * appropriate error.
574*7bc33045SAndreas Dannenberg  */
575*7bc33045SAndreas Dannenberg static int ti_sci_cmd_dev_is_valid(const struct ti_sci_handle *handle, u32 id)
576*7bc33045SAndreas Dannenberg {
577*7bc33045SAndreas Dannenberg 	u8 unused;
578*7bc33045SAndreas Dannenberg 
579*7bc33045SAndreas Dannenberg 	/* check the device state which will also tell us if the ID is valid */
580*7bc33045SAndreas Dannenberg 	return ti_sci_get_device_state(handle, id, NULL, NULL, NULL, &unused);
581*7bc33045SAndreas Dannenberg }
582*7bc33045SAndreas Dannenberg 
583*7bc33045SAndreas Dannenberg /**
584*7bc33045SAndreas Dannenberg  * ti_sci_cmd_dev_get_clcnt() - Get context loss counter
585*7bc33045SAndreas Dannenberg  * @handle:	Pointer to TISCI handle
586*7bc33045SAndreas Dannenberg  * @id:		Device Identifier
587*7bc33045SAndreas Dannenberg  * @count:	Pointer to Context Loss counter to populate
588*7bc33045SAndreas Dannenberg  *
589*7bc33045SAndreas Dannenberg  * Return: 0 if all went fine, else return appropriate error.
590*7bc33045SAndreas Dannenberg  */
591*7bc33045SAndreas Dannenberg static int ti_sci_cmd_dev_get_clcnt(const struct ti_sci_handle *handle, u32 id,
592*7bc33045SAndreas Dannenberg 				    u32 *count)
593*7bc33045SAndreas Dannenberg {
594*7bc33045SAndreas Dannenberg 	return ti_sci_get_device_state(handle, id, count, NULL, NULL, NULL);
595*7bc33045SAndreas Dannenberg }
596*7bc33045SAndreas Dannenberg 
597*7bc33045SAndreas Dannenberg /**
598*7bc33045SAndreas Dannenberg  * ti_sci_cmd_dev_is_idle() - Check if the device is requested to be idle
599*7bc33045SAndreas Dannenberg  * @handle:	Pointer to TISCI handle
600*7bc33045SAndreas Dannenberg  * @id:		Device Identifier
601*7bc33045SAndreas Dannenberg  * @r_state:	true if requested to be idle
602*7bc33045SAndreas Dannenberg  *
603*7bc33045SAndreas Dannenberg  * Return: 0 if all went fine, else return appropriate error.
604*7bc33045SAndreas Dannenberg  */
605*7bc33045SAndreas Dannenberg static int ti_sci_cmd_dev_is_idle(const struct ti_sci_handle *handle, u32 id,
606*7bc33045SAndreas Dannenberg 				  bool *r_state)
607*7bc33045SAndreas Dannenberg {
608*7bc33045SAndreas Dannenberg 	int ret;
609*7bc33045SAndreas Dannenberg 	u8 state;
610*7bc33045SAndreas Dannenberg 
611*7bc33045SAndreas Dannenberg 	if (!r_state)
612*7bc33045SAndreas Dannenberg 		return -EINVAL;
613*7bc33045SAndreas Dannenberg 
614*7bc33045SAndreas Dannenberg 	ret = ti_sci_get_device_state(handle, id, NULL, NULL, &state, NULL);
615*7bc33045SAndreas Dannenberg 	if (ret)
616*7bc33045SAndreas Dannenberg 		return ret;
617*7bc33045SAndreas Dannenberg 
618*7bc33045SAndreas Dannenberg 	*r_state = (state == MSG_DEVICE_SW_STATE_RETENTION);
619*7bc33045SAndreas Dannenberg 
620*7bc33045SAndreas Dannenberg 	return 0;
621*7bc33045SAndreas Dannenberg }
622*7bc33045SAndreas Dannenberg 
623*7bc33045SAndreas Dannenberg /**
624*7bc33045SAndreas Dannenberg  * ti_sci_cmd_dev_is_stop() - Check if the device is requested to be stopped
625*7bc33045SAndreas Dannenberg  * @handle:	Pointer to TISCI handle
626*7bc33045SAndreas Dannenberg  * @id:		Device Identifier
627*7bc33045SAndreas Dannenberg  * @r_state:	true if requested to be stopped
628*7bc33045SAndreas Dannenberg  * @curr_state:	true if currently stopped.
629*7bc33045SAndreas Dannenberg  *
630*7bc33045SAndreas Dannenberg  * Return: 0 if all went fine, else return appropriate error.
631*7bc33045SAndreas Dannenberg  */
632*7bc33045SAndreas Dannenberg static int ti_sci_cmd_dev_is_stop(const struct ti_sci_handle *handle, u32 id,
633*7bc33045SAndreas Dannenberg 				  bool *r_state,  bool *curr_state)
634*7bc33045SAndreas Dannenberg {
635*7bc33045SAndreas Dannenberg 	int ret;
636*7bc33045SAndreas Dannenberg 	u8 p_state, c_state;
637*7bc33045SAndreas Dannenberg 
638*7bc33045SAndreas Dannenberg 	if (!r_state && !curr_state)
639*7bc33045SAndreas Dannenberg 		return -EINVAL;
640*7bc33045SAndreas Dannenberg 
641*7bc33045SAndreas Dannenberg 	ret =
642*7bc33045SAndreas Dannenberg 	    ti_sci_get_device_state(handle, id, NULL, NULL, &p_state, &c_state);
643*7bc33045SAndreas Dannenberg 	if (ret)
644*7bc33045SAndreas Dannenberg 		return ret;
645*7bc33045SAndreas Dannenberg 
646*7bc33045SAndreas Dannenberg 	if (r_state)
647*7bc33045SAndreas Dannenberg 		*r_state = (p_state == MSG_DEVICE_SW_STATE_AUTO_OFF);
648*7bc33045SAndreas Dannenberg 	if (curr_state)
649*7bc33045SAndreas Dannenberg 		*curr_state = (c_state == MSG_DEVICE_HW_STATE_OFF);
650*7bc33045SAndreas Dannenberg 
651*7bc33045SAndreas Dannenberg 	return 0;
652*7bc33045SAndreas Dannenberg }
653*7bc33045SAndreas Dannenberg 
654*7bc33045SAndreas Dannenberg /**
655*7bc33045SAndreas Dannenberg  * ti_sci_cmd_dev_is_on() - Check if the device is requested to be ON
656*7bc33045SAndreas Dannenberg  * @handle:	Pointer to TISCI handle
657*7bc33045SAndreas Dannenberg  * @id:		Device Identifier
658*7bc33045SAndreas Dannenberg  * @r_state:	true if requested to be ON
659*7bc33045SAndreas Dannenberg  * @curr_state:	true if currently ON and active
660*7bc33045SAndreas Dannenberg  *
661*7bc33045SAndreas Dannenberg  * Return: 0 if all went fine, else return appropriate error.
662*7bc33045SAndreas Dannenberg  */
663*7bc33045SAndreas Dannenberg static int ti_sci_cmd_dev_is_on(const struct ti_sci_handle *handle, u32 id,
664*7bc33045SAndreas Dannenberg 				bool *r_state,  bool *curr_state)
665*7bc33045SAndreas Dannenberg {
666*7bc33045SAndreas Dannenberg 	int ret;
667*7bc33045SAndreas Dannenberg 	u8 p_state, c_state;
668*7bc33045SAndreas Dannenberg 
669*7bc33045SAndreas Dannenberg 	if (!r_state && !curr_state)
670*7bc33045SAndreas Dannenberg 		return -EINVAL;
671*7bc33045SAndreas Dannenberg 
672*7bc33045SAndreas Dannenberg 	ret =
673*7bc33045SAndreas Dannenberg 	    ti_sci_get_device_state(handle, id, NULL, NULL, &p_state, &c_state);
674*7bc33045SAndreas Dannenberg 	if (ret)
675*7bc33045SAndreas Dannenberg 		return ret;
676*7bc33045SAndreas Dannenberg 
677*7bc33045SAndreas Dannenberg 	if (r_state)
678*7bc33045SAndreas Dannenberg 		*r_state = (p_state == MSG_DEVICE_SW_STATE_ON);
679*7bc33045SAndreas Dannenberg 	if (curr_state)
680*7bc33045SAndreas Dannenberg 		*curr_state = (c_state == MSG_DEVICE_HW_STATE_ON);
681*7bc33045SAndreas Dannenberg 
682*7bc33045SAndreas Dannenberg 	return 0;
683*7bc33045SAndreas Dannenberg }
684*7bc33045SAndreas Dannenberg 
685*7bc33045SAndreas Dannenberg /**
686*7bc33045SAndreas Dannenberg  * ti_sci_cmd_dev_is_trans() - Check if the device is currently transitioning
687*7bc33045SAndreas Dannenberg  * @handle:	Pointer to TISCI handle
688*7bc33045SAndreas Dannenberg  * @id:		Device Identifier
689*7bc33045SAndreas Dannenberg  * @curr_state:	true if currently transitioning.
690*7bc33045SAndreas Dannenberg  *
691*7bc33045SAndreas Dannenberg  * Return: 0 if all went fine, else return appropriate error.
692*7bc33045SAndreas Dannenberg  */
693*7bc33045SAndreas Dannenberg static int ti_sci_cmd_dev_is_trans(const struct ti_sci_handle *handle, u32 id,
694*7bc33045SAndreas Dannenberg 				   bool *curr_state)
695*7bc33045SAndreas Dannenberg {
696*7bc33045SAndreas Dannenberg 	int ret;
697*7bc33045SAndreas Dannenberg 	u8 state;
698*7bc33045SAndreas Dannenberg 
699*7bc33045SAndreas Dannenberg 	if (!curr_state)
700*7bc33045SAndreas Dannenberg 		return -EINVAL;
701*7bc33045SAndreas Dannenberg 
702*7bc33045SAndreas Dannenberg 	ret = ti_sci_get_device_state(handle, id, NULL, NULL, NULL, &state);
703*7bc33045SAndreas Dannenberg 	if (ret)
704*7bc33045SAndreas Dannenberg 		return ret;
705*7bc33045SAndreas Dannenberg 
706*7bc33045SAndreas Dannenberg 	*curr_state = (state == MSG_DEVICE_HW_STATE_TRANS);
707*7bc33045SAndreas Dannenberg 
708*7bc33045SAndreas Dannenberg 	return 0;
709*7bc33045SAndreas Dannenberg }
710*7bc33045SAndreas Dannenberg 
711*7bc33045SAndreas Dannenberg /**
712*7bc33045SAndreas Dannenberg  * ti_sci_cmd_set_device_resets() - command to set resets for device managed
713*7bc33045SAndreas Dannenberg  *				    by TISCI
714*7bc33045SAndreas Dannenberg  * @handle:	Pointer to TISCI handle as retrieved by *ti_sci_get_handle
715*7bc33045SAndreas Dannenberg  * @id:		Device Identifier
716*7bc33045SAndreas Dannenberg  * @reset_state: Device specific reset bit field
717*7bc33045SAndreas Dannenberg  *
718*7bc33045SAndreas Dannenberg  * Return: 0 if all went fine, else return appropriate error.
719*7bc33045SAndreas Dannenberg  */
720*7bc33045SAndreas Dannenberg static int ti_sci_cmd_set_device_resets(const struct ti_sci_handle *handle,
721*7bc33045SAndreas Dannenberg 					u32 id, u32 reset_state)
722*7bc33045SAndreas Dannenberg {
723*7bc33045SAndreas Dannenberg 	struct ti_sci_msg_req_set_device_resets req;
724*7bc33045SAndreas Dannenberg 	struct ti_sci_msg_hdr *resp;
725*7bc33045SAndreas Dannenberg 	struct ti_sci_info *info;
726*7bc33045SAndreas Dannenberg 	struct ti_sci_xfer *xfer;
727*7bc33045SAndreas Dannenberg 	int ret = 0;
728*7bc33045SAndreas Dannenberg 
729*7bc33045SAndreas Dannenberg 	if (IS_ERR(handle))
730*7bc33045SAndreas Dannenberg 		return PTR_ERR(handle);
731*7bc33045SAndreas Dannenberg 	if (!handle)
732*7bc33045SAndreas Dannenberg 		return -EINVAL;
733*7bc33045SAndreas Dannenberg 
734*7bc33045SAndreas Dannenberg 	info = handle_to_ti_sci_info(handle);
735*7bc33045SAndreas Dannenberg 
736*7bc33045SAndreas Dannenberg 	xfer = ti_sci_setup_one_xfer(info, TI_SCI_MSG_SET_DEVICE_RESETS,
737*7bc33045SAndreas Dannenberg 				     TI_SCI_FLAG_REQ_ACK_ON_PROCESSED,
738*7bc33045SAndreas Dannenberg 				     (u32 *)&req, sizeof(req), sizeof(*resp));
739*7bc33045SAndreas Dannenberg 	if (IS_ERR(xfer)) {
740*7bc33045SAndreas Dannenberg 		ret = PTR_ERR(xfer);
741*7bc33045SAndreas Dannenberg 		dev_err(info->dev, "Message alloc failed(%d)\n", ret);
742*7bc33045SAndreas Dannenberg 		return ret;
743*7bc33045SAndreas Dannenberg 	}
744*7bc33045SAndreas Dannenberg 	req.id = id;
745*7bc33045SAndreas Dannenberg 	req.resets = reset_state;
746*7bc33045SAndreas Dannenberg 
747*7bc33045SAndreas Dannenberg 	ret = ti_sci_do_xfer(info, xfer);
748*7bc33045SAndreas Dannenberg 	if (ret) {
749*7bc33045SAndreas Dannenberg 		dev_err(info->dev, "Mbox send fail %d\n", ret);
750*7bc33045SAndreas Dannenberg 		return ret;
751*7bc33045SAndreas Dannenberg 	}
752*7bc33045SAndreas Dannenberg 
753*7bc33045SAndreas Dannenberg 	resp = (struct ti_sci_msg_hdr *)xfer->tx_message.buf;
754*7bc33045SAndreas Dannenberg 
755*7bc33045SAndreas Dannenberg 	if (!ti_sci_is_response_ack(resp))
756*7bc33045SAndreas Dannenberg 		return -ENODEV;
757*7bc33045SAndreas Dannenberg 
758*7bc33045SAndreas Dannenberg 	return ret;
759*7bc33045SAndreas Dannenberg }
760*7bc33045SAndreas Dannenberg 
761*7bc33045SAndreas Dannenberg /**
762*7bc33045SAndreas Dannenberg  * ti_sci_cmd_get_device_resets() - Get reset state for device managed
763*7bc33045SAndreas Dannenberg  *				    by TISCI
764*7bc33045SAndreas Dannenberg  * @handle:		Pointer to TISCI handle
765*7bc33045SAndreas Dannenberg  * @id:			Device Identifier
766*7bc33045SAndreas Dannenberg  * @reset_state:	Pointer to reset state to populate
767*7bc33045SAndreas Dannenberg  *
768*7bc33045SAndreas Dannenberg  * Return: 0 if all went fine, else return appropriate error.
769*7bc33045SAndreas Dannenberg  */
770*7bc33045SAndreas Dannenberg static int ti_sci_cmd_get_device_resets(const struct ti_sci_handle *handle,
771*7bc33045SAndreas Dannenberg 					u32 id, u32 *reset_state)
772*7bc33045SAndreas Dannenberg {
773*7bc33045SAndreas Dannenberg 	return ti_sci_get_device_state(handle, id, NULL, reset_state, NULL,
774*7bc33045SAndreas Dannenberg 				       NULL);
775*7bc33045SAndreas Dannenberg }
776*7bc33045SAndreas Dannenberg 
777dcfc52adSAndreas Dannenberg /*
778dcfc52adSAndreas Dannenberg  * ti_sci_setup_ops() - Setup the operations structures
779dcfc52adSAndreas Dannenberg  * @info:	pointer to TISCI pointer
780dcfc52adSAndreas Dannenberg  */
781dcfc52adSAndreas Dannenberg static void ti_sci_setup_ops(struct ti_sci_info *info)
782dcfc52adSAndreas Dannenberg {
783dcfc52adSAndreas Dannenberg 	struct ti_sci_ops *ops = &info->handle.ops;
784dcfc52adSAndreas Dannenberg 	struct ti_sci_board_ops *bops = &ops->board_ops;
785*7bc33045SAndreas Dannenberg 	struct ti_sci_dev_ops *dops = &ops->dev_ops;
786dcfc52adSAndreas Dannenberg 
787dcfc52adSAndreas Dannenberg 	bops->board_config = ti_sci_cmd_set_board_config;
788dcfc52adSAndreas Dannenberg 	bops->board_config_rm = ti_sci_cmd_set_board_config_rm;
789dcfc52adSAndreas Dannenberg 	bops->board_config_security = ti_sci_cmd_set_board_config_security;
790dcfc52adSAndreas Dannenberg 	bops->board_config_pm = ti_sci_cmd_set_board_config_pm;
791*7bc33045SAndreas Dannenberg 
792*7bc33045SAndreas Dannenberg 	dops->get_device = ti_sci_cmd_get_device;
793*7bc33045SAndreas Dannenberg 	dops->idle_device = ti_sci_cmd_idle_device;
794*7bc33045SAndreas Dannenberg 	dops->put_device = ti_sci_cmd_put_device;
795*7bc33045SAndreas Dannenberg 	dops->is_valid = ti_sci_cmd_dev_is_valid;
796*7bc33045SAndreas Dannenberg 	dops->get_context_loss_count = ti_sci_cmd_dev_get_clcnt;
797*7bc33045SAndreas Dannenberg 	dops->is_idle = ti_sci_cmd_dev_is_idle;
798*7bc33045SAndreas Dannenberg 	dops->is_stop = ti_sci_cmd_dev_is_stop;
799*7bc33045SAndreas Dannenberg 	dops->is_on = ti_sci_cmd_dev_is_on;
800*7bc33045SAndreas Dannenberg 	dops->is_transitioning = ti_sci_cmd_dev_is_trans;
801*7bc33045SAndreas Dannenberg 	dops->set_device_resets = ti_sci_cmd_set_device_resets;
802*7bc33045SAndreas Dannenberg 	dops->get_device_resets = ti_sci_cmd_get_device_resets;
803dcfc52adSAndreas Dannenberg }
804dcfc52adSAndreas Dannenberg 
805dcfc52adSAndreas Dannenberg /**
80632cd2512SLokesh Vutla  * ti_sci_get_handle_from_sysfw() - Get the TI SCI handle of the SYSFW
80732cd2512SLokesh Vutla  * @dev:	Pointer to the SYSFW device
80832cd2512SLokesh Vutla  *
80932cd2512SLokesh Vutla  * Return: pointer to handle if successful, else EINVAL if invalid conditions
81032cd2512SLokesh Vutla  *         are encountered.
81132cd2512SLokesh Vutla  */
81232cd2512SLokesh Vutla const
81332cd2512SLokesh Vutla struct ti_sci_handle *ti_sci_get_handle_from_sysfw(struct udevice *sci_dev)
81432cd2512SLokesh Vutla {
81532cd2512SLokesh Vutla 	if (!sci_dev)
81632cd2512SLokesh Vutla 		return ERR_PTR(-EINVAL);
81732cd2512SLokesh Vutla 
81832cd2512SLokesh Vutla 	struct ti_sci_info *info = dev_get_priv(sci_dev);
81932cd2512SLokesh Vutla 
82032cd2512SLokesh Vutla 	if (!info)
82132cd2512SLokesh Vutla 		return ERR_PTR(-EINVAL);
82232cd2512SLokesh Vutla 
82332cd2512SLokesh Vutla 	struct ti_sci_handle *handle = &info->handle;
82432cd2512SLokesh Vutla 
82532cd2512SLokesh Vutla 	if (!handle)
82632cd2512SLokesh Vutla 		return ERR_PTR(-EINVAL);
82732cd2512SLokesh Vutla 
82832cd2512SLokesh Vutla 	return handle;
82932cd2512SLokesh Vutla }
83032cd2512SLokesh Vutla 
83132cd2512SLokesh Vutla /**
83232cd2512SLokesh Vutla  * ti_sci_get_handle() - Get the TI SCI handle for a device
83332cd2512SLokesh Vutla  * @dev:	Pointer to device for which we want SCI handle
83432cd2512SLokesh Vutla  *
83532cd2512SLokesh Vutla  * Return: pointer to handle if successful, else EINVAL if invalid conditions
83632cd2512SLokesh Vutla  *         are encountered.
83732cd2512SLokesh Vutla  */
83832cd2512SLokesh Vutla const struct ti_sci_handle *ti_sci_get_handle(struct udevice *dev)
83932cd2512SLokesh Vutla {
84032cd2512SLokesh Vutla 	if (!dev)
84132cd2512SLokesh Vutla 		return ERR_PTR(-EINVAL);
84232cd2512SLokesh Vutla 
84332cd2512SLokesh Vutla 	struct udevice *sci_dev = dev_get_parent(dev);
84432cd2512SLokesh Vutla 
84532cd2512SLokesh Vutla 	return ti_sci_get_handle_from_sysfw(sci_dev);
84632cd2512SLokesh Vutla }
84732cd2512SLokesh Vutla 
84832cd2512SLokesh Vutla /**
84932cd2512SLokesh Vutla  * ti_sci_get_by_phandle() - Get the TI SCI handle using DT phandle
85032cd2512SLokesh Vutla  * @dev:	device node
85132cd2512SLokesh Vutla  * @propname:	property name containing phandle on TISCI node
85232cd2512SLokesh Vutla  *
85332cd2512SLokesh Vutla  * Return: pointer to handle if successful, else appropriate error value.
85432cd2512SLokesh Vutla  */
85532cd2512SLokesh Vutla const struct ti_sci_handle *ti_sci_get_by_phandle(struct udevice *dev,
85632cd2512SLokesh Vutla 						  const char *property)
85732cd2512SLokesh Vutla {
85832cd2512SLokesh Vutla 	struct ti_sci_info *entry, *info = NULL;
85932cd2512SLokesh Vutla 	u32 phandle, err;
86032cd2512SLokesh Vutla 	ofnode node;
86132cd2512SLokesh Vutla 
86232cd2512SLokesh Vutla 	err = ofnode_read_u32(dev_ofnode(dev), property, &phandle);
86332cd2512SLokesh Vutla 	if (err)
86432cd2512SLokesh Vutla 		return ERR_PTR(err);
86532cd2512SLokesh Vutla 
86632cd2512SLokesh Vutla 	node = ofnode_get_by_phandle(phandle);
86732cd2512SLokesh Vutla 	if (!ofnode_valid(node))
86832cd2512SLokesh Vutla 		return ERR_PTR(-EINVAL);
86932cd2512SLokesh Vutla 
87032cd2512SLokesh Vutla 	list_for_each_entry(entry, &ti_sci_list, list)
87132cd2512SLokesh Vutla 		if (ofnode_equal(dev_ofnode(entry->dev), node)) {
87232cd2512SLokesh Vutla 			info = entry;
87332cd2512SLokesh Vutla 			break;
87432cd2512SLokesh Vutla 		}
87532cd2512SLokesh Vutla 
87632cd2512SLokesh Vutla 	if (!info)
87732cd2512SLokesh Vutla 		return ERR_PTR(-ENODEV);
87832cd2512SLokesh Vutla 
87932cd2512SLokesh Vutla 	return &info->handle;
88032cd2512SLokesh Vutla }
88132cd2512SLokesh Vutla 
88232cd2512SLokesh Vutla /**
88332cd2512SLokesh Vutla  * ti_sci_of_to_info() - generate private data from device tree
88432cd2512SLokesh Vutla  * @dev:	corresponding system controller interface device
88532cd2512SLokesh Vutla  * @info:	pointer to driver specific private data
88632cd2512SLokesh Vutla  *
88732cd2512SLokesh Vutla  * Return: 0 if all goes good, else appropriate error message.
88832cd2512SLokesh Vutla  */
88932cd2512SLokesh Vutla static int ti_sci_of_to_info(struct udevice *dev, struct ti_sci_info *info)
89032cd2512SLokesh Vutla {
89132cd2512SLokesh Vutla 	int ret;
89232cd2512SLokesh Vutla 
89332cd2512SLokesh Vutla 	ret = mbox_get_by_name(dev, "tx", &info->chan_tx);
89432cd2512SLokesh Vutla 	if (ret) {
89532cd2512SLokesh Vutla 		dev_err(dev, "%s: Acquiring Tx channel failed. ret = %d\n",
89632cd2512SLokesh Vutla 			__func__, ret);
89732cd2512SLokesh Vutla 		return ret;
89832cd2512SLokesh Vutla 	}
89932cd2512SLokesh Vutla 
90032cd2512SLokesh Vutla 	ret = mbox_get_by_name(dev, "rx", &info->chan_rx);
90132cd2512SLokesh Vutla 	if (ret) {
90232cd2512SLokesh Vutla 		dev_err(dev, "%s: Acquiring Rx channel failed. ret = %d\n",
90332cd2512SLokesh Vutla 			__func__, ret);
90432cd2512SLokesh Vutla 		return ret;
90532cd2512SLokesh Vutla 	}
90632cd2512SLokesh Vutla 
90732cd2512SLokesh Vutla 	/* Notify channel is optional. Enable only if populated */
90832cd2512SLokesh Vutla 	ret = mbox_get_by_name(dev, "notify", &info->chan_notify);
90932cd2512SLokesh Vutla 	if (ret) {
91032cd2512SLokesh Vutla 		dev_dbg(dev, "%s: Acquiring notify channel failed. ret = %d\n",
91132cd2512SLokesh Vutla 			__func__, ret);
91232cd2512SLokesh Vutla 	}
91332cd2512SLokesh Vutla 
91432cd2512SLokesh Vutla 	info->host_id = dev_read_u32_default(dev, "ti,host-id",
91532cd2512SLokesh Vutla 					     info->desc->host_id);
91632cd2512SLokesh Vutla 
91732cd2512SLokesh Vutla 	info->is_secure = dev_read_bool(dev, "ti,secure-host");
91832cd2512SLokesh Vutla 
91932cd2512SLokesh Vutla 	return 0;
92032cd2512SLokesh Vutla }
92132cd2512SLokesh Vutla 
92232cd2512SLokesh Vutla /**
92332cd2512SLokesh Vutla  * ti_sci_probe() - Basic probe
92432cd2512SLokesh Vutla  * @dev:	corresponding system controller interface device
92532cd2512SLokesh Vutla  *
92632cd2512SLokesh Vutla  * Return: 0 if all goes good, else appropriate error message.
92732cd2512SLokesh Vutla  */
92832cd2512SLokesh Vutla static int ti_sci_probe(struct udevice *dev)
92932cd2512SLokesh Vutla {
93032cd2512SLokesh Vutla 	struct ti_sci_info *info;
93132cd2512SLokesh Vutla 	int ret;
93232cd2512SLokesh Vutla 
93332cd2512SLokesh Vutla 	debug("%s(dev=%p)\n", __func__, dev);
93432cd2512SLokesh Vutla 
93532cd2512SLokesh Vutla 	info = dev_get_priv(dev);
93632cd2512SLokesh Vutla 	info->desc = (void *)dev_get_driver_data(dev);
93732cd2512SLokesh Vutla 
93832cd2512SLokesh Vutla 	ret = ti_sci_of_to_info(dev, info);
93932cd2512SLokesh Vutla 	if (ret) {
94032cd2512SLokesh Vutla 		dev_err(dev, "%s: Probe failed with error %d\n", __func__, ret);
94132cd2512SLokesh Vutla 		return ret;
94232cd2512SLokesh Vutla 	}
94332cd2512SLokesh Vutla 
94432cd2512SLokesh Vutla 	info->dev = dev;
94532cd2512SLokesh Vutla 	info->seq = 0xA;
94632cd2512SLokesh Vutla 
94732cd2512SLokesh Vutla 	list_add_tail(&info->list, &ti_sci_list);
948dcfc52adSAndreas Dannenberg 	ti_sci_setup_ops(info);
94932cd2512SLokesh Vutla 
95032cd2512SLokesh Vutla 	ret = ti_sci_cmd_get_revision(&info->handle);
95132cd2512SLokesh Vutla 
95232cd2512SLokesh Vutla 	return ret;
95332cd2512SLokesh Vutla }
95432cd2512SLokesh Vutla 
95532cd2512SLokesh Vutla /* Description for AM654 */
95632cd2512SLokesh Vutla static const struct ti_sci_desc ti_sci_sysfw_am654_desc = {
95732cd2512SLokesh Vutla 	.host_id = 4,
95832cd2512SLokesh Vutla 	.max_rx_timeout_us = 1000000,
95932cd2512SLokesh Vutla 	.max_msg_size = 60,
96032cd2512SLokesh Vutla };
96132cd2512SLokesh Vutla 
96232cd2512SLokesh Vutla static const struct udevice_id ti_sci_ids[] = {
96332cd2512SLokesh Vutla 	{
96432cd2512SLokesh Vutla 		.compatible = "ti,k2g-sci",
96532cd2512SLokesh Vutla 		.data = (ulong)&ti_sci_sysfw_am654_desc
96632cd2512SLokesh Vutla 	},
96732cd2512SLokesh Vutla 	{ /* Sentinel */ },
96832cd2512SLokesh Vutla };
96932cd2512SLokesh Vutla 
97032cd2512SLokesh Vutla U_BOOT_DRIVER(ti_sci) = {
97132cd2512SLokesh Vutla 	.name = "ti_sci",
97232cd2512SLokesh Vutla 	.id = UCLASS_FIRMWARE,
97332cd2512SLokesh Vutla 	.of_match = ti_sci_ids,
97432cd2512SLokesh Vutla 	.probe = ti_sci_probe,
97532cd2512SLokesh Vutla 	.priv_auto_alloc_size = sizeof(struct ti_sci_info),
97632cd2512SLokesh Vutla };
977