xref: /openbmc/u-boot/drivers/firmware/ti_sci.c (revision dcfc52ad)
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Texas Instruments System Control Interface Protocol Driver
4  * Based on drivers/firmware/ti_sci.c from Linux.
5  *
6  * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
7  *	Lokesh Vutla <lokeshvutla@ti.com>
8  */
9 
10 #include <common.h>
11 #include <dm.h>
12 #include <errno.h>
13 #include <mailbox.h>
14 #include <dm/device.h>
15 #include <linux/err.h>
16 #include <linux/soc/ti/k3-sec-proxy.h>
17 #include <linux/soc/ti/ti_sci_protocol.h>
18 
19 #include "ti_sci.h"
20 
21 /* List of all TI SCI devices active in system */
22 static LIST_HEAD(ti_sci_list);
23 
24 /**
25  * struct ti_sci_xfer - Structure representing a message flow
26  * @tx_message:	Transmit message
27  * @rx_len:	Receive message length
28  */
29 struct ti_sci_xfer {
30 	struct k3_sec_proxy_msg tx_message;
31 	u8 rx_len;
32 };
33 
34 /**
35  * struct ti_sci_desc - Description of SoC integration
36  * @host_id:		Host identifier representing the compute entity
37  * @max_rx_timeout_us:	Timeout for communication with SoC (in Microseconds)
38  * @max_msg_size:	Maximum size of data per message that can be handled.
39  */
40 struct ti_sci_desc {
41 	u8 host_id;
42 	int max_rx_timeout_us;
43 	int max_msg_size;
44 };
45 
46 /**
47  * struct ti_sci_info - Structure representing a TI SCI instance
48  * @dev:	Device pointer
49  * @desc:	SoC description for this instance
50  * @handle:	Instance of TI SCI handle to send to clients.
51  * @chan_tx:	Transmit mailbox channel
52  * @chan_rx:	Receive mailbox channel
53  * @xfer:	xfer info
54  * @list:	list head
55  * @is_secure:	Determines if the communication is through secure threads.
56  * @host_id:	Host identifier representing the compute entity
57  * @seq:	Seq id used for verification for tx and rx message.
58  */
59 struct ti_sci_info {
60 	struct udevice *dev;
61 	const struct ti_sci_desc *desc;
62 	struct ti_sci_handle handle;
63 	struct mbox_chan chan_tx;
64 	struct mbox_chan chan_rx;
65 	struct mbox_chan chan_notify;
66 	struct ti_sci_xfer xfer;
67 	struct list_head list;
68 	bool is_secure;
69 	u8 host_id;
70 	u8 seq;
71 };
72 
73 #define handle_to_ti_sci_info(h) container_of(h, struct ti_sci_info, handle)
74 
75 /**
76  * ti_sci_setup_one_xfer() - Setup one message type
77  * @info:	Pointer to SCI entity information
78  * @msg_type:	Message type
79  * @msg_flags:	Flag to set for the message
80  * @buf:	Buffer to be send to mailbox channel
81  * @tx_message_size: transmit message size
82  * @rx_message_size: receive message size
83  *
84  * Helper function which is used by various command functions that are
85  * exposed to clients of this driver for allocating a message traffic event.
86  *
87  * Return: Corresponding ti_sci_xfer pointer if all went fine,
88  *	   else appropriate error pointer.
89  */
90 static struct ti_sci_xfer *ti_sci_setup_one_xfer(struct ti_sci_info *info,
91 						 u16 msg_type, u32 msg_flags,
92 						 u32 *buf,
93 						 size_t tx_message_size,
94 						 size_t rx_message_size)
95 {
96 	struct ti_sci_xfer *xfer = &info->xfer;
97 	struct ti_sci_msg_hdr *hdr;
98 
99 	/* Ensure we have sane transfer sizes */
100 	if (rx_message_size > info->desc->max_msg_size ||
101 	    tx_message_size > info->desc->max_msg_size ||
102 	    rx_message_size < sizeof(*hdr) || tx_message_size < sizeof(*hdr))
103 		return ERR_PTR(-ERANGE);
104 
105 	info->seq = ~info->seq;
106 	xfer->tx_message.buf = buf;
107 	xfer->tx_message.len = tx_message_size;
108 	xfer->rx_len = (u8)rx_message_size;
109 
110 	hdr = (struct ti_sci_msg_hdr *)buf;
111 	hdr->seq = info->seq;
112 	hdr->type = msg_type;
113 	hdr->host = info->host_id;
114 	hdr->flags = msg_flags;
115 
116 	return xfer;
117 }
118 
119 /**
120  * ti_sci_get_response() - Receive response from mailbox channel
121  * @info:	Pointer to SCI entity information
122  * @xfer:	Transfer to initiate and wait for response
123  * @chan:	Channel to receive the response
124  *
125  * Return: -ETIMEDOUT in case of no response, if transmit error,
126  *	   return corresponding error, else if all goes well,
127  *	   return 0.
128  */
129 static inline int ti_sci_get_response(struct ti_sci_info *info,
130 				      struct ti_sci_xfer *xfer,
131 				      struct mbox_chan *chan)
132 {
133 	struct k3_sec_proxy_msg *msg = &xfer->tx_message;
134 	struct ti_sci_secure_msg_hdr *secure_hdr;
135 	struct ti_sci_msg_hdr *hdr;
136 	int ret;
137 
138 	/* Receive the response */
139 	ret = mbox_recv(chan, msg, info->desc->max_rx_timeout_us);
140 	if (ret) {
141 		dev_err(info->dev, "%s: Message receive failed. ret = %d\n",
142 			__func__, ret);
143 		return ret;
144 	}
145 
146 	/* ToDo: Verify checksum */
147 	if (info->is_secure) {
148 		secure_hdr = (struct ti_sci_secure_msg_hdr *)msg->buf;
149 		msg->buf = (u32 *)((void *)msg->buf + sizeof(*secure_hdr));
150 	}
151 
152 	/* msg is updated by mailbox driver */
153 	hdr = (struct ti_sci_msg_hdr *)msg->buf;
154 
155 	/* Sanity check for message response */
156 	if (hdr->seq != info->seq) {
157 		dev_dbg(info->dev, "%s: Message for %d is not expected\n",
158 			__func__, hdr->seq);
159 		return ret;
160 	}
161 
162 	if (msg->len > info->desc->max_msg_size) {
163 		dev_err(info->dev, "%s: Unable to handle %zu xfer (max %d)\n",
164 			__func__, msg->len, info->desc->max_msg_size);
165 		return -EINVAL;
166 	}
167 
168 	if (msg->len < xfer->rx_len) {
169 		dev_err(info->dev, "%s: Recv xfer %zu < expected %d length\n",
170 			__func__, msg->len, xfer->rx_len);
171 	}
172 
173 	return ret;
174 }
175 
176 /**
177  * ti_sci_do_xfer() - Do one transfer
178  * @info:	Pointer to SCI entity information
179  * @xfer:	Transfer to initiate and wait for response
180  *
181  * Return: 0 if all went fine, else return appropriate error.
182  */
183 static inline int ti_sci_do_xfer(struct ti_sci_info *info,
184 				 struct ti_sci_xfer *xfer)
185 {
186 	struct k3_sec_proxy_msg *msg = &xfer->tx_message;
187 	u8 secure_buf[info->desc->max_msg_size];
188 	struct ti_sci_secure_msg_hdr secure_hdr;
189 	int ret;
190 
191 	if (info->is_secure) {
192 		/* ToDo: get checksum of the entire message */
193 		secure_hdr.checksum = 0;
194 		secure_hdr.reserved = 0;
195 		memcpy(&secure_buf[sizeof(secure_hdr)], xfer->tx_message.buf,
196 		       xfer->tx_message.len);
197 
198 		xfer->tx_message.buf = (u32 *)secure_buf;
199 		xfer->tx_message.len += sizeof(secure_hdr);
200 		xfer->rx_len += sizeof(secure_hdr);
201 	}
202 
203 	/* Send the message */
204 	ret = mbox_send(&info->chan_tx, msg);
205 	if (ret) {
206 		dev_err(info->dev, "%s: Message sending failed. ret = %d\n",
207 			__func__, ret);
208 		return ret;
209 	}
210 
211 	return ti_sci_get_response(info, xfer, &info->chan_rx);
212 }
213 
214 /**
215  * ti_sci_cmd_get_revision() - command to get the revision of the SCI entity
216  * @handle:	pointer to TI SCI handle
217  *
218  * Updates the SCI information in the internal data structure.
219  *
220  * Return: 0 if all went fine, else return appropriate error.
221  */
222 static int ti_sci_cmd_get_revision(struct ti_sci_handle *handle)
223 {
224 	struct ti_sci_msg_resp_version *rev_info;
225 	struct ti_sci_version_info *ver;
226 	struct ti_sci_msg_hdr hdr;
227 	struct ti_sci_info *info;
228 	struct ti_sci_xfer *xfer;
229 	int ret;
230 
231 	if (IS_ERR(handle))
232 		return PTR_ERR(handle);
233 	if (!handle)
234 		return -EINVAL;
235 
236 	info = handle_to_ti_sci_info(handle);
237 
238 	xfer = ti_sci_setup_one_xfer(info, TI_SCI_MSG_VERSION, 0x0,
239 				     (u32 *)&hdr, sizeof(struct ti_sci_msg_hdr),
240 				     sizeof(*rev_info));
241 	if (IS_ERR(xfer)) {
242 		ret = PTR_ERR(xfer);
243 		dev_err(info->dev, "Message alloc failed(%d)\n", ret);
244 		return ret;
245 	}
246 
247 	ret = ti_sci_do_xfer(info, xfer);
248 	if (ret) {
249 		dev_err(info->dev, "Mbox communication fail %d\n", ret);
250 		return ret;
251 	}
252 
253 	rev_info = (struct ti_sci_msg_resp_version *)xfer->tx_message.buf;
254 
255 	ver = &handle->version;
256 	ver->abi_major = rev_info->abi_major;
257 	ver->abi_minor = rev_info->abi_minor;
258 	ver->firmware_revision = rev_info->firmware_revision;
259 	strncpy(ver->firmware_description, rev_info->firmware_description,
260 		sizeof(ver->firmware_description));
261 
262 	return 0;
263 }
264 
265 /**
266  * ti_sci_is_response_ack() - Generic ACK/NACK message checkup
267  * @r:	pointer to response buffer
268  *
269  * Return: true if the response was an ACK, else returns false.
270  */
271 static inline bool ti_sci_is_response_ack(void *r)
272 {
273 	struct ti_sci_msg_hdr *hdr = r;
274 
275 	return hdr->flags & TI_SCI_FLAG_RESP_GENERIC_ACK ? true : false;
276 }
277 
278 /**
279  * cmd_set_board_config_using_msg() - Common command to send board configuration
280  *                                    message
281  * @handle:	pointer to TI SCI handle
282  * @msg_type:	One of the TISCI message types to set board configuration
283  * @addr:	Address where the board config structure is located
284  * @size:	Size of the board config structure
285  *
286  * Return: 0 if all went well, else returns appropriate error value.
287  */
288 static int cmd_set_board_config_using_msg(const struct ti_sci_handle *handle,
289 					  u16 msg_type, u64 addr, u32 size)
290 {
291 	struct ti_sci_msg_board_config req;
292 	struct ti_sci_msg_hdr *resp;
293 	struct ti_sci_info *info;
294 	struct ti_sci_xfer *xfer;
295 	int ret = 0;
296 
297 	if (IS_ERR(handle))
298 		return PTR_ERR(handle);
299 	if (!handle)
300 		return -EINVAL;
301 
302 	info = handle_to_ti_sci_info(handle);
303 
304 	xfer = ti_sci_setup_one_xfer(info, msg_type,
305 				     TI_SCI_FLAG_REQ_ACK_ON_PROCESSED,
306 				     (u32 *)&req, sizeof(req), sizeof(*resp));
307 	if (IS_ERR(xfer)) {
308 		ret = PTR_ERR(xfer);
309 		dev_err(info->dev, "Message alloc failed(%d)\n", ret);
310 		return ret;
311 	}
312 	req.boardcfgp_high = (addr >> 32) & 0xffffffff;
313 	req.boardcfgp_low = addr & 0xffffffff;
314 	req.boardcfg_size = size;
315 
316 	ret = ti_sci_do_xfer(info, xfer);
317 	if (ret) {
318 		dev_err(info->dev, "Mbox send fail %d\n", ret);
319 		return ret;
320 	}
321 
322 	resp = (struct ti_sci_msg_hdr *)xfer->tx_message.buf;
323 
324 	if (!ti_sci_is_response_ack(resp))
325 		return -ENODEV;
326 
327 	return ret;
328 }
329 
330 /**
331  * ti_sci_cmd_set_board_config() - Command to send board configuration message
332  * @handle:	pointer to TI SCI handle
333  * @addr:	Address where the board config structure is located
334  * @size:	Size of the board config structure
335  *
336  * Return: 0 if all went well, else returns appropriate error value.
337  */
338 static int ti_sci_cmd_set_board_config(const struct ti_sci_handle *handle,
339 				       u64 addr, u32 size)
340 {
341 	return cmd_set_board_config_using_msg(handle,
342 					      TI_SCI_MSG_BOARD_CONFIG,
343 					      addr, size);
344 }
345 
346 /**
347  * ti_sci_cmd_set_board_config_rm() - Command to send board resource
348  *				      management configuration
349  * @handle:	pointer to TI SCI handle
350  * @addr:	Address where the board RM config structure is located
351  * @size:	Size of the RM config structure
352  *
353  * Return: 0 if all went well, else returns appropriate error value.
354  */
355 static
356 int ti_sci_cmd_set_board_config_rm(const struct ti_sci_handle *handle,
357 				   u64 addr, u32 size)
358 {
359 	return cmd_set_board_config_using_msg(handle,
360 					      TI_SCI_MSG_BOARD_CONFIG_RM,
361 					      addr, size);
362 }
363 
364 /**
365  * ti_sci_cmd_set_board_config_security() - Command to send board security
366  *					    configuration message
367  * @handle:	pointer to TI SCI handle
368  * @addr:	Address where the board security config structure is located
369  * @size:	Size of the security config structure
370  *
371  * Return: 0 if all went well, else returns appropriate error value.
372  */
373 static
374 int ti_sci_cmd_set_board_config_security(const struct ti_sci_handle *handle,
375 					 u64 addr, u32 size)
376 {
377 	return cmd_set_board_config_using_msg(handle,
378 					      TI_SCI_MSG_BOARD_CONFIG_SECURITY,
379 					      addr, size);
380 }
381 
382 /**
383  * ti_sci_cmd_set_board_config_pm() - Command to send board power and clock
384  *				      configuration message
385  * @handle:	pointer to TI SCI handle
386  * @addr:	Address where the board PM config structure is located
387  * @size:	Size of the PM config structure
388  *
389  * Return: 0 if all went well, else returns appropriate error value.
390  */
391 static int ti_sci_cmd_set_board_config_pm(const struct ti_sci_handle *handle,
392 					  u64 addr, u32 size)
393 {
394 	return cmd_set_board_config_using_msg(handle,
395 					      TI_SCI_MSG_BOARD_CONFIG_PM,
396 					      addr, size);
397 }
398 
399 /*
400  * ti_sci_setup_ops() - Setup the operations structures
401  * @info:	pointer to TISCI pointer
402  */
403 static void ti_sci_setup_ops(struct ti_sci_info *info)
404 {
405 	struct ti_sci_ops *ops = &info->handle.ops;
406 	struct ti_sci_board_ops *bops = &ops->board_ops;
407 
408 	bops->board_config = ti_sci_cmd_set_board_config;
409 	bops->board_config_rm = ti_sci_cmd_set_board_config_rm;
410 	bops->board_config_security = ti_sci_cmd_set_board_config_security;
411 	bops->board_config_pm = ti_sci_cmd_set_board_config_pm;
412 }
413 
414 /**
415  * ti_sci_get_handle_from_sysfw() - Get the TI SCI handle of the SYSFW
416  * @dev:	Pointer to the SYSFW device
417  *
418  * Return: pointer to handle if successful, else EINVAL if invalid conditions
419  *         are encountered.
420  */
421 const
422 struct ti_sci_handle *ti_sci_get_handle_from_sysfw(struct udevice *sci_dev)
423 {
424 	if (!sci_dev)
425 		return ERR_PTR(-EINVAL);
426 
427 	struct ti_sci_info *info = dev_get_priv(sci_dev);
428 
429 	if (!info)
430 		return ERR_PTR(-EINVAL);
431 
432 	struct ti_sci_handle *handle = &info->handle;
433 
434 	if (!handle)
435 		return ERR_PTR(-EINVAL);
436 
437 	return handle;
438 }
439 
440 /**
441  * ti_sci_get_handle() - Get the TI SCI handle for a device
442  * @dev:	Pointer to device for which we want SCI handle
443  *
444  * Return: pointer to handle if successful, else EINVAL if invalid conditions
445  *         are encountered.
446  */
447 const struct ti_sci_handle *ti_sci_get_handle(struct udevice *dev)
448 {
449 	if (!dev)
450 		return ERR_PTR(-EINVAL);
451 
452 	struct udevice *sci_dev = dev_get_parent(dev);
453 
454 	return ti_sci_get_handle_from_sysfw(sci_dev);
455 }
456 
457 /**
458  * ti_sci_get_by_phandle() - Get the TI SCI handle using DT phandle
459  * @dev:	device node
460  * @propname:	property name containing phandle on TISCI node
461  *
462  * Return: pointer to handle if successful, else appropriate error value.
463  */
464 const struct ti_sci_handle *ti_sci_get_by_phandle(struct udevice *dev,
465 						  const char *property)
466 {
467 	struct ti_sci_info *entry, *info = NULL;
468 	u32 phandle, err;
469 	ofnode node;
470 
471 	err = ofnode_read_u32(dev_ofnode(dev), property, &phandle);
472 	if (err)
473 		return ERR_PTR(err);
474 
475 	node = ofnode_get_by_phandle(phandle);
476 	if (!ofnode_valid(node))
477 		return ERR_PTR(-EINVAL);
478 
479 	list_for_each_entry(entry, &ti_sci_list, list)
480 		if (ofnode_equal(dev_ofnode(entry->dev), node)) {
481 			info = entry;
482 			break;
483 		}
484 
485 	if (!info)
486 		return ERR_PTR(-ENODEV);
487 
488 	return &info->handle;
489 }
490 
491 /**
492  * ti_sci_of_to_info() - generate private data from device tree
493  * @dev:	corresponding system controller interface device
494  * @info:	pointer to driver specific private data
495  *
496  * Return: 0 if all goes good, else appropriate error message.
497  */
498 static int ti_sci_of_to_info(struct udevice *dev, struct ti_sci_info *info)
499 {
500 	int ret;
501 
502 	ret = mbox_get_by_name(dev, "tx", &info->chan_tx);
503 	if (ret) {
504 		dev_err(dev, "%s: Acquiring Tx channel failed. ret = %d\n",
505 			__func__, ret);
506 		return ret;
507 	}
508 
509 	ret = mbox_get_by_name(dev, "rx", &info->chan_rx);
510 	if (ret) {
511 		dev_err(dev, "%s: Acquiring Rx channel failed. ret = %d\n",
512 			__func__, ret);
513 		return ret;
514 	}
515 
516 	/* Notify channel is optional. Enable only if populated */
517 	ret = mbox_get_by_name(dev, "notify", &info->chan_notify);
518 	if (ret) {
519 		dev_dbg(dev, "%s: Acquiring notify channel failed. ret = %d\n",
520 			__func__, ret);
521 	}
522 
523 	info->host_id = dev_read_u32_default(dev, "ti,host-id",
524 					     info->desc->host_id);
525 
526 	info->is_secure = dev_read_bool(dev, "ti,secure-host");
527 
528 	return 0;
529 }
530 
531 /**
532  * ti_sci_probe() - Basic probe
533  * @dev:	corresponding system controller interface device
534  *
535  * Return: 0 if all goes good, else appropriate error message.
536  */
537 static int ti_sci_probe(struct udevice *dev)
538 {
539 	struct ti_sci_info *info;
540 	int ret;
541 
542 	debug("%s(dev=%p)\n", __func__, dev);
543 
544 	info = dev_get_priv(dev);
545 	info->desc = (void *)dev_get_driver_data(dev);
546 
547 	ret = ti_sci_of_to_info(dev, info);
548 	if (ret) {
549 		dev_err(dev, "%s: Probe failed with error %d\n", __func__, ret);
550 		return ret;
551 	}
552 
553 	info->dev = dev;
554 	info->seq = 0xA;
555 
556 	list_add_tail(&info->list, &ti_sci_list);
557 	ti_sci_setup_ops(info);
558 
559 	ret = ti_sci_cmd_get_revision(&info->handle);
560 
561 	return ret;
562 }
563 
564 /* Description for AM654 */
565 static const struct ti_sci_desc ti_sci_sysfw_am654_desc = {
566 	.host_id = 4,
567 	.max_rx_timeout_us = 1000000,
568 	.max_msg_size = 60,
569 };
570 
571 static const struct udevice_id ti_sci_ids[] = {
572 	{
573 		.compatible = "ti,k2g-sci",
574 		.data = (ulong)&ti_sci_sysfw_am654_desc
575 	},
576 	{ /* Sentinel */ },
577 };
578 
579 U_BOOT_DRIVER(ti_sci) = {
580 	.name = "ti_sci",
581 	.id = UCLASS_FIRMWARE,
582 	.of_match = ti_sci_ids,
583 	.probe = ti_sci_probe,
584 	.priv_auto_alloc_size = sizeof(struct ti_sci_info),
585 };
586