xref: /openbmc/u-boot/drivers/firmware/ti_sci.c (revision dcfc52ad69db29118bc6658f716d0480d18a0651)
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 /**
279*dcfc52adSAndreas Dannenberg  * cmd_set_board_config_using_msg() - Common command to send board configuration
280*dcfc52adSAndreas Dannenberg  *                                    message
281*dcfc52adSAndreas Dannenberg  * @handle:	pointer to TI SCI handle
282*dcfc52adSAndreas Dannenberg  * @msg_type:	One of the TISCI message types to set board configuration
283*dcfc52adSAndreas Dannenberg  * @addr:	Address where the board config structure is located
284*dcfc52adSAndreas Dannenberg  * @size:	Size of the board config structure
285*dcfc52adSAndreas Dannenberg  *
286*dcfc52adSAndreas Dannenberg  * Return: 0 if all went well, else returns appropriate error value.
287*dcfc52adSAndreas Dannenberg  */
288*dcfc52adSAndreas Dannenberg static int cmd_set_board_config_using_msg(const struct ti_sci_handle *handle,
289*dcfc52adSAndreas Dannenberg 					  u16 msg_type, u64 addr, u32 size)
290*dcfc52adSAndreas Dannenberg {
291*dcfc52adSAndreas Dannenberg 	struct ti_sci_msg_board_config req;
292*dcfc52adSAndreas Dannenberg 	struct ti_sci_msg_hdr *resp;
293*dcfc52adSAndreas Dannenberg 	struct ti_sci_info *info;
294*dcfc52adSAndreas Dannenberg 	struct ti_sci_xfer *xfer;
295*dcfc52adSAndreas Dannenberg 	int ret = 0;
296*dcfc52adSAndreas Dannenberg 
297*dcfc52adSAndreas Dannenberg 	if (IS_ERR(handle))
298*dcfc52adSAndreas Dannenberg 		return PTR_ERR(handle);
299*dcfc52adSAndreas Dannenberg 	if (!handle)
300*dcfc52adSAndreas Dannenberg 		return -EINVAL;
301*dcfc52adSAndreas Dannenberg 
302*dcfc52adSAndreas Dannenberg 	info = handle_to_ti_sci_info(handle);
303*dcfc52adSAndreas Dannenberg 
304*dcfc52adSAndreas Dannenberg 	xfer = ti_sci_setup_one_xfer(info, msg_type,
305*dcfc52adSAndreas Dannenberg 				     TI_SCI_FLAG_REQ_ACK_ON_PROCESSED,
306*dcfc52adSAndreas Dannenberg 				     (u32 *)&req, sizeof(req), sizeof(*resp));
307*dcfc52adSAndreas Dannenberg 	if (IS_ERR(xfer)) {
308*dcfc52adSAndreas Dannenberg 		ret = PTR_ERR(xfer);
309*dcfc52adSAndreas Dannenberg 		dev_err(info->dev, "Message alloc failed(%d)\n", ret);
310*dcfc52adSAndreas Dannenberg 		return ret;
311*dcfc52adSAndreas Dannenberg 	}
312*dcfc52adSAndreas Dannenberg 	req.boardcfgp_high = (addr >> 32) & 0xffffffff;
313*dcfc52adSAndreas Dannenberg 	req.boardcfgp_low = addr & 0xffffffff;
314*dcfc52adSAndreas Dannenberg 	req.boardcfg_size = size;
315*dcfc52adSAndreas Dannenberg 
316*dcfc52adSAndreas Dannenberg 	ret = ti_sci_do_xfer(info, xfer);
317*dcfc52adSAndreas Dannenberg 	if (ret) {
318*dcfc52adSAndreas Dannenberg 		dev_err(info->dev, "Mbox send fail %d\n", ret);
319*dcfc52adSAndreas Dannenberg 		return ret;
320*dcfc52adSAndreas Dannenberg 	}
321*dcfc52adSAndreas Dannenberg 
322*dcfc52adSAndreas Dannenberg 	resp = (struct ti_sci_msg_hdr *)xfer->tx_message.buf;
323*dcfc52adSAndreas Dannenberg 
324*dcfc52adSAndreas Dannenberg 	if (!ti_sci_is_response_ack(resp))
325*dcfc52adSAndreas Dannenberg 		return -ENODEV;
326*dcfc52adSAndreas Dannenberg 
327*dcfc52adSAndreas Dannenberg 	return ret;
328*dcfc52adSAndreas Dannenberg }
329*dcfc52adSAndreas Dannenberg 
330*dcfc52adSAndreas Dannenberg /**
331*dcfc52adSAndreas Dannenberg  * ti_sci_cmd_set_board_config() - Command to send board configuration message
332*dcfc52adSAndreas Dannenberg  * @handle:	pointer to TI SCI handle
333*dcfc52adSAndreas Dannenberg  * @addr:	Address where the board config structure is located
334*dcfc52adSAndreas Dannenberg  * @size:	Size of the board config structure
335*dcfc52adSAndreas Dannenberg  *
336*dcfc52adSAndreas Dannenberg  * Return: 0 if all went well, else returns appropriate error value.
337*dcfc52adSAndreas Dannenberg  */
338*dcfc52adSAndreas Dannenberg static int ti_sci_cmd_set_board_config(const struct ti_sci_handle *handle,
339*dcfc52adSAndreas Dannenberg 				       u64 addr, u32 size)
340*dcfc52adSAndreas Dannenberg {
341*dcfc52adSAndreas Dannenberg 	return cmd_set_board_config_using_msg(handle,
342*dcfc52adSAndreas Dannenberg 					      TI_SCI_MSG_BOARD_CONFIG,
343*dcfc52adSAndreas Dannenberg 					      addr, size);
344*dcfc52adSAndreas Dannenberg }
345*dcfc52adSAndreas Dannenberg 
346*dcfc52adSAndreas Dannenberg /**
347*dcfc52adSAndreas Dannenberg  * ti_sci_cmd_set_board_config_rm() - Command to send board resource
348*dcfc52adSAndreas Dannenberg  *				      management configuration
349*dcfc52adSAndreas Dannenberg  * @handle:	pointer to TI SCI handle
350*dcfc52adSAndreas Dannenberg  * @addr:	Address where the board RM config structure is located
351*dcfc52adSAndreas Dannenberg  * @size:	Size of the RM config structure
352*dcfc52adSAndreas Dannenberg  *
353*dcfc52adSAndreas Dannenberg  * Return: 0 if all went well, else returns appropriate error value.
354*dcfc52adSAndreas Dannenberg  */
355*dcfc52adSAndreas Dannenberg static
356*dcfc52adSAndreas Dannenberg int ti_sci_cmd_set_board_config_rm(const struct ti_sci_handle *handle,
357*dcfc52adSAndreas Dannenberg 				   u64 addr, u32 size)
358*dcfc52adSAndreas Dannenberg {
359*dcfc52adSAndreas Dannenberg 	return cmd_set_board_config_using_msg(handle,
360*dcfc52adSAndreas Dannenberg 					      TI_SCI_MSG_BOARD_CONFIG_RM,
361*dcfc52adSAndreas Dannenberg 					      addr, size);
362*dcfc52adSAndreas Dannenberg }
363*dcfc52adSAndreas Dannenberg 
364*dcfc52adSAndreas Dannenberg /**
365*dcfc52adSAndreas Dannenberg  * ti_sci_cmd_set_board_config_security() - Command to send board security
366*dcfc52adSAndreas Dannenberg  *					    configuration message
367*dcfc52adSAndreas Dannenberg  * @handle:	pointer to TI SCI handle
368*dcfc52adSAndreas Dannenberg  * @addr:	Address where the board security config structure is located
369*dcfc52adSAndreas Dannenberg  * @size:	Size of the security config structure
370*dcfc52adSAndreas Dannenberg  *
371*dcfc52adSAndreas Dannenberg  * Return: 0 if all went well, else returns appropriate error value.
372*dcfc52adSAndreas Dannenberg  */
373*dcfc52adSAndreas Dannenberg static
374*dcfc52adSAndreas Dannenberg int ti_sci_cmd_set_board_config_security(const struct ti_sci_handle *handle,
375*dcfc52adSAndreas Dannenberg 					 u64 addr, u32 size)
376*dcfc52adSAndreas Dannenberg {
377*dcfc52adSAndreas Dannenberg 	return cmd_set_board_config_using_msg(handle,
378*dcfc52adSAndreas Dannenberg 					      TI_SCI_MSG_BOARD_CONFIG_SECURITY,
379*dcfc52adSAndreas Dannenberg 					      addr, size);
380*dcfc52adSAndreas Dannenberg }
381*dcfc52adSAndreas Dannenberg 
382*dcfc52adSAndreas Dannenberg /**
383*dcfc52adSAndreas Dannenberg  * ti_sci_cmd_set_board_config_pm() - Command to send board power and clock
384*dcfc52adSAndreas Dannenberg  *				      configuration message
385*dcfc52adSAndreas Dannenberg  * @handle:	pointer to TI SCI handle
386*dcfc52adSAndreas Dannenberg  * @addr:	Address where the board PM config structure is located
387*dcfc52adSAndreas Dannenberg  * @size:	Size of the PM config structure
388*dcfc52adSAndreas Dannenberg  *
389*dcfc52adSAndreas Dannenberg  * Return: 0 if all went well, else returns appropriate error value.
390*dcfc52adSAndreas Dannenberg  */
391*dcfc52adSAndreas Dannenberg static int ti_sci_cmd_set_board_config_pm(const struct ti_sci_handle *handle,
392*dcfc52adSAndreas Dannenberg 					  u64 addr, u32 size)
393*dcfc52adSAndreas Dannenberg {
394*dcfc52adSAndreas Dannenberg 	return cmd_set_board_config_using_msg(handle,
395*dcfc52adSAndreas Dannenberg 					      TI_SCI_MSG_BOARD_CONFIG_PM,
396*dcfc52adSAndreas Dannenberg 					      addr, size);
397*dcfc52adSAndreas Dannenberg }
398*dcfc52adSAndreas Dannenberg 
399*dcfc52adSAndreas Dannenberg /*
400*dcfc52adSAndreas Dannenberg  * ti_sci_setup_ops() - Setup the operations structures
401*dcfc52adSAndreas Dannenberg  * @info:	pointer to TISCI pointer
402*dcfc52adSAndreas Dannenberg  */
403*dcfc52adSAndreas Dannenberg static void ti_sci_setup_ops(struct ti_sci_info *info)
404*dcfc52adSAndreas Dannenberg {
405*dcfc52adSAndreas Dannenberg 	struct ti_sci_ops *ops = &info->handle.ops;
406*dcfc52adSAndreas Dannenberg 	struct ti_sci_board_ops *bops = &ops->board_ops;
407*dcfc52adSAndreas Dannenberg 
408*dcfc52adSAndreas Dannenberg 	bops->board_config = ti_sci_cmd_set_board_config;
409*dcfc52adSAndreas Dannenberg 	bops->board_config_rm = ti_sci_cmd_set_board_config_rm;
410*dcfc52adSAndreas Dannenberg 	bops->board_config_security = ti_sci_cmd_set_board_config_security;
411*dcfc52adSAndreas Dannenberg 	bops->board_config_pm = ti_sci_cmd_set_board_config_pm;
412*dcfc52adSAndreas Dannenberg }
413*dcfc52adSAndreas Dannenberg 
414*dcfc52adSAndreas Dannenberg /**
41532cd2512SLokesh Vutla  * ti_sci_get_handle_from_sysfw() - Get the TI SCI handle of the SYSFW
41632cd2512SLokesh Vutla  * @dev:	Pointer to the SYSFW device
41732cd2512SLokesh Vutla  *
41832cd2512SLokesh Vutla  * Return: pointer to handle if successful, else EINVAL if invalid conditions
41932cd2512SLokesh Vutla  *         are encountered.
42032cd2512SLokesh Vutla  */
42132cd2512SLokesh Vutla const
42232cd2512SLokesh Vutla struct ti_sci_handle *ti_sci_get_handle_from_sysfw(struct udevice *sci_dev)
42332cd2512SLokesh Vutla {
42432cd2512SLokesh Vutla 	if (!sci_dev)
42532cd2512SLokesh Vutla 		return ERR_PTR(-EINVAL);
42632cd2512SLokesh Vutla 
42732cd2512SLokesh Vutla 	struct ti_sci_info *info = dev_get_priv(sci_dev);
42832cd2512SLokesh Vutla 
42932cd2512SLokesh Vutla 	if (!info)
43032cd2512SLokesh Vutla 		return ERR_PTR(-EINVAL);
43132cd2512SLokesh Vutla 
43232cd2512SLokesh Vutla 	struct ti_sci_handle *handle = &info->handle;
43332cd2512SLokesh Vutla 
43432cd2512SLokesh Vutla 	if (!handle)
43532cd2512SLokesh Vutla 		return ERR_PTR(-EINVAL);
43632cd2512SLokesh Vutla 
43732cd2512SLokesh Vutla 	return handle;
43832cd2512SLokesh Vutla }
43932cd2512SLokesh Vutla 
44032cd2512SLokesh Vutla /**
44132cd2512SLokesh Vutla  * ti_sci_get_handle() - Get the TI SCI handle for a device
44232cd2512SLokesh Vutla  * @dev:	Pointer to device for which we want SCI handle
44332cd2512SLokesh Vutla  *
44432cd2512SLokesh Vutla  * Return: pointer to handle if successful, else EINVAL if invalid conditions
44532cd2512SLokesh Vutla  *         are encountered.
44632cd2512SLokesh Vutla  */
44732cd2512SLokesh Vutla const struct ti_sci_handle *ti_sci_get_handle(struct udevice *dev)
44832cd2512SLokesh Vutla {
44932cd2512SLokesh Vutla 	if (!dev)
45032cd2512SLokesh Vutla 		return ERR_PTR(-EINVAL);
45132cd2512SLokesh Vutla 
45232cd2512SLokesh Vutla 	struct udevice *sci_dev = dev_get_parent(dev);
45332cd2512SLokesh Vutla 
45432cd2512SLokesh Vutla 	return ti_sci_get_handle_from_sysfw(sci_dev);
45532cd2512SLokesh Vutla }
45632cd2512SLokesh Vutla 
45732cd2512SLokesh Vutla /**
45832cd2512SLokesh Vutla  * ti_sci_get_by_phandle() - Get the TI SCI handle using DT phandle
45932cd2512SLokesh Vutla  * @dev:	device node
46032cd2512SLokesh Vutla  * @propname:	property name containing phandle on TISCI node
46132cd2512SLokesh Vutla  *
46232cd2512SLokesh Vutla  * Return: pointer to handle if successful, else appropriate error value.
46332cd2512SLokesh Vutla  */
46432cd2512SLokesh Vutla const struct ti_sci_handle *ti_sci_get_by_phandle(struct udevice *dev,
46532cd2512SLokesh Vutla 						  const char *property)
46632cd2512SLokesh Vutla {
46732cd2512SLokesh Vutla 	struct ti_sci_info *entry, *info = NULL;
46832cd2512SLokesh Vutla 	u32 phandle, err;
46932cd2512SLokesh Vutla 	ofnode node;
47032cd2512SLokesh Vutla 
47132cd2512SLokesh Vutla 	err = ofnode_read_u32(dev_ofnode(dev), property, &phandle);
47232cd2512SLokesh Vutla 	if (err)
47332cd2512SLokesh Vutla 		return ERR_PTR(err);
47432cd2512SLokesh Vutla 
47532cd2512SLokesh Vutla 	node = ofnode_get_by_phandle(phandle);
47632cd2512SLokesh Vutla 	if (!ofnode_valid(node))
47732cd2512SLokesh Vutla 		return ERR_PTR(-EINVAL);
47832cd2512SLokesh Vutla 
47932cd2512SLokesh Vutla 	list_for_each_entry(entry, &ti_sci_list, list)
48032cd2512SLokesh Vutla 		if (ofnode_equal(dev_ofnode(entry->dev), node)) {
48132cd2512SLokesh Vutla 			info = entry;
48232cd2512SLokesh Vutla 			break;
48332cd2512SLokesh Vutla 		}
48432cd2512SLokesh Vutla 
48532cd2512SLokesh Vutla 	if (!info)
48632cd2512SLokesh Vutla 		return ERR_PTR(-ENODEV);
48732cd2512SLokesh Vutla 
48832cd2512SLokesh Vutla 	return &info->handle;
48932cd2512SLokesh Vutla }
49032cd2512SLokesh Vutla 
49132cd2512SLokesh Vutla /**
49232cd2512SLokesh Vutla  * ti_sci_of_to_info() - generate private data from device tree
49332cd2512SLokesh Vutla  * @dev:	corresponding system controller interface device
49432cd2512SLokesh Vutla  * @info:	pointer to driver specific private data
49532cd2512SLokesh Vutla  *
49632cd2512SLokesh Vutla  * Return: 0 if all goes good, else appropriate error message.
49732cd2512SLokesh Vutla  */
49832cd2512SLokesh Vutla static int ti_sci_of_to_info(struct udevice *dev, struct ti_sci_info *info)
49932cd2512SLokesh Vutla {
50032cd2512SLokesh Vutla 	int ret;
50132cd2512SLokesh Vutla 
50232cd2512SLokesh Vutla 	ret = mbox_get_by_name(dev, "tx", &info->chan_tx);
50332cd2512SLokesh Vutla 	if (ret) {
50432cd2512SLokesh Vutla 		dev_err(dev, "%s: Acquiring Tx channel failed. ret = %d\n",
50532cd2512SLokesh Vutla 			__func__, ret);
50632cd2512SLokesh Vutla 		return ret;
50732cd2512SLokesh Vutla 	}
50832cd2512SLokesh Vutla 
50932cd2512SLokesh Vutla 	ret = mbox_get_by_name(dev, "rx", &info->chan_rx);
51032cd2512SLokesh Vutla 	if (ret) {
51132cd2512SLokesh Vutla 		dev_err(dev, "%s: Acquiring Rx channel failed. ret = %d\n",
51232cd2512SLokesh Vutla 			__func__, ret);
51332cd2512SLokesh Vutla 		return ret;
51432cd2512SLokesh Vutla 	}
51532cd2512SLokesh Vutla 
51632cd2512SLokesh Vutla 	/* Notify channel is optional. Enable only if populated */
51732cd2512SLokesh Vutla 	ret = mbox_get_by_name(dev, "notify", &info->chan_notify);
51832cd2512SLokesh Vutla 	if (ret) {
51932cd2512SLokesh Vutla 		dev_dbg(dev, "%s: Acquiring notify channel failed. ret = %d\n",
52032cd2512SLokesh Vutla 			__func__, ret);
52132cd2512SLokesh Vutla 	}
52232cd2512SLokesh Vutla 
52332cd2512SLokesh Vutla 	info->host_id = dev_read_u32_default(dev, "ti,host-id",
52432cd2512SLokesh Vutla 					     info->desc->host_id);
52532cd2512SLokesh Vutla 
52632cd2512SLokesh Vutla 	info->is_secure = dev_read_bool(dev, "ti,secure-host");
52732cd2512SLokesh Vutla 
52832cd2512SLokesh Vutla 	return 0;
52932cd2512SLokesh Vutla }
53032cd2512SLokesh Vutla 
53132cd2512SLokesh Vutla /**
53232cd2512SLokesh Vutla  * ti_sci_probe() - Basic probe
53332cd2512SLokesh Vutla  * @dev:	corresponding system controller interface device
53432cd2512SLokesh Vutla  *
53532cd2512SLokesh Vutla  * Return: 0 if all goes good, else appropriate error message.
53632cd2512SLokesh Vutla  */
53732cd2512SLokesh Vutla static int ti_sci_probe(struct udevice *dev)
53832cd2512SLokesh Vutla {
53932cd2512SLokesh Vutla 	struct ti_sci_info *info;
54032cd2512SLokesh Vutla 	int ret;
54132cd2512SLokesh Vutla 
54232cd2512SLokesh Vutla 	debug("%s(dev=%p)\n", __func__, dev);
54332cd2512SLokesh Vutla 
54432cd2512SLokesh Vutla 	info = dev_get_priv(dev);
54532cd2512SLokesh Vutla 	info->desc = (void *)dev_get_driver_data(dev);
54632cd2512SLokesh Vutla 
54732cd2512SLokesh Vutla 	ret = ti_sci_of_to_info(dev, info);
54832cd2512SLokesh Vutla 	if (ret) {
54932cd2512SLokesh Vutla 		dev_err(dev, "%s: Probe failed with error %d\n", __func__, ret);
55032cd2512SLokesh Vutla 		return ret;
55132cd2512SLokesh Vutla 	}
55232cd2512SLokesh Vutla 
55332cd2512SLokesh Vutla 	info->dev = dev;
55432cd2512SLokesh Vutla 	info->seq = 0xA;
55532cd2512SLokesh Vutla 
55632cd2512SLokesh Vutla 	list_add_tail(&info->list, &ti_sci_list);
557*dcfc52adSAndreas Dannenberg 	ti_sci_setup_ops(info);
55832cd2512SLokesh Vutla 
55932cd2512SLokesh Vutla 	ret = ti_sci_cmd_get_revision(&info->handle);
56032cd2512SLokesh Vutla 
56132cd2512SLokesh Vutla 	return ret;
56232cd2512SLokesh Vutla }
56332cd2512SLokesh Vutla 
56432cd2512SLokesh Vutla /* Description for AM654 */
56532cd2512SLokesh Vutla static const struct ti_sci_desc ti_sci_sysfw_am654_desc = {
56632cd2512SLokesh Vutla 	.host_id = 4,
56732cd2512SLokesh Vutla 	.max_rx_timeout_us = 1000000,
56832cd2512SLokesh Vutla 	.max_msg_size = 60,
56932cd2512SLokesh Vutla };
57032cd2512SLokesh Vutla 
57132cd2512SLokesh Vutla static const struct udevice_id ti_sci_ids[] = {
57232cd2512SLokesh Vutla 	{
57332cd2512SLokesh Vutla 		.compatible = "ti,k2g-sci",
57432cd2512SLokesh Vutla 		.data = (ulong)&ti_sci_sysfw_am654_desc
57532cd2512SLokesh Vutla 	},
57632cd2512SLokesh Vutla 	{ /* Sentinel */ },
57732cd2512SLokesh Vutla };
57832cd2512SLokesh Vutla 
57932cd2512SLokesh Vutla U_BOOT_DRIVER(ti_sci) = {
58032cd2512SLokesh Vutla 	.name = "ti_sci",
58132cd2512SLokesh Vutla 	.id = UCLASS_FIRMWARE,
58232cd2512SLokesh Vutla 	.of_match = ti_sci_ids,
58332cd2512SLokesh Vutla 	.probe = ti_sci_probe,
58432cd2512SLokesh Vutla 	.priv_auto_alloc_size = sizeof(struct ti_sci_info),
58532cd2512SLokesh Vutla };
586