blob: dacef74204972c31862ee46c0a5d5a6c44039ca7 [file] [log] [blame]
Andrew F. Davisa513b2a2018-05-04 19:06:09 +00001/*
2 * Texas Instruments System Control Interface Driver
3 * Based on Linux and U-Boot implementation
4 *
Dave Gerlach7a94ce82021-11-30 15:35:08 -06005 * Copyright (C) 2018-2022 Texas Instruments Incorporated - https://www.ti.com/
Andrew F. Davisa513b2a2018-05-04 19:06:09 +00006 *
7 * SPDX-License-Identifier: BSD-3-Clause
8 */
9
Andrew F. Davisa513b2a2018-05-04 19:06:09 +000010#include <errno.h>
Andrew F. Davisa513b2a2018-05-04 19:06:09 +000011#include <stdbool.h>
12#include <stddef.h>
13#include <string.h>
14
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000015#include <platform_def.h>
Andrew Davis617d0352023-03-13 13:56:27 -050016#include <lib/bakery_lock.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000017
18#include <common/debug.h>
Andrew F. Davisa513b2a2018-05-04 19:06:09 +000019#include <sec_proxy.h>
20
21#include "ti_sci_protocol.h"
22#include "ti_sci.h"
23
Andrew F. Davise1bcbd42020-01-16 15:58:34 -060024#if USE_COHERENT_MEM
Chris Kay33bfc5e2023-02-14 11:30:04 +000025__section(".tzfw_coherent_mem")
Andrew F. Davise1bcbd42020-01-16 15:58:34 -060026#endif
Andrew F. Davis5daafa12020-01-16 15:34:31 -060027static uint8_t message_sequence;
Andrew F. Davisa513b2a2018-05-04 19:06:09 +000028
Andrew Davis617d0352023-03-13 13:56:27 -050029DEFINE_BAKERY_LOCK(ti_sci_xfer_lock);
30
Andrew F. Davisa513b2a2018-05-04 19:06:09 +000031/**
32 * struct ti_sci_xfer - Structure representing a message flow
33 * @tx_message: Transmit message
34 * @rx_message: Receive message
35 */
36struct ti_sci_xfer {
37 struct k3_sec_proxy_msg tx_message;
38 struct k3_sec_proxy_msg rx_message;
39};
40
41/**
42 * ti_sci_setup_one_xfer() - Setup one message type
43 *
44 * @msg_type: Message type
45 * @msg_flags: Flag to set for the message
46 * @tx_buf: Buffer to be sent to mailbox channel
47 * @tx_message_size: transmit message size
48 * @rx_buf: Buffer to be received from mailbox channel
49 * @rx_message_size: receive message size
50 *
51 * Helper function which is used by various command functions that are
52 * exposed to clients of this driver for allocating a message traffic event.
53 *
54 * Return: 0 if all goes well, else appropriate error message
55 */
56static int ti_sci_setup_one_xfer(uint16_t msg_type, uint32_t msg_flags,
57 void *tx_buf,
58 size_t tx_message_size,
59 void *rx_buf,
60 size_t rx_message_size,
61 struct ti_sci_xfer *xfer)
62{
63 struct ti_sci_msg_hdr *hdr;
64
65 /* Ensure we have sane transfer sizes */
Andrew F. Davis5daafa12020-01-16 15:34:31 -060066 if (rx_message_size > TI_SCI_MAX_MESSAGE_SIZE ||
67 tx_message_size > TI_SCI_MAX_MESSAGE_SIZE ||
Andrew F. Davisa513b2a2018-05-04 19:06:09 +000068 tx_message_size < sizeof(*hdr))
69 return -ERANGE;
70
Andrew F. Davisa513b2a2018-05-04 19:06:09 +000071 hdr = (struct ti_sci_msg_hdr *)tx_buf;
Andrew F. Davis5daafa12020-01-16 15:34:31 -060072 hdr->seq = ++message_sequence;
Andrew F. Davisa513b2a2018-05-04 19:06:09 +000073 hdr->type = msg_type;
Andrew F. Davis5daafa12020-01-16 15:34:31 -060074 hdr->host = TI_SCI_HOST_ID;
Andrew Davise0a676c2022-05-16 13:17:02 -050075 hdr->flags = msg_flags;
76 /* Request a response if rx_message_size is non-zero */
77 if (rx_message_size != 0U) {
78 hdr->flags |= TI_SCI_FLAG_REQ_ACK_ON_PROCESSED;
79 }
Andrew F. Davisa513b2a2018-05-04 19:06:09 +000080
81 xfer->tx_message.buf = tx_buf;
82 xfer->tx_message.len = tx_message_size;
83
84 xfer->rx_message.buf = rx_buf;
85 xfer->rx_message.len = rx_message_size;
86
87 return 0;
88}
89
90/**
91 * ti_sci_get_response() - Receive response from mailbox channel
92 *
93 * @xfer: Transfer to initiate and wait for response
94 * @chan: Channel to receive the response
95 *
96 * Return: 0 if all goes well, else appropriate error message
97 */
Andrew Davis817bdbb2022-11-11 12:49:38 -060098static int ti_sci_get_response(struct k3_sec_proxy_msg *msg,
99 enum k3_sec_proxy_chan_id chan)
Andrew F. Davisa513b2a2018-05-04 19:06:09 +0000100{
Andrew F. Davisa513b2a2018-05-04 19:06:09 +0000101 struct ti_sci_msg_hdr *hdr;
Andrew F. Davisdff11822019-04-10 12:40:12 -0400102 unsigned int retry = 5;
Andrew F. Davisa513b2a2018-05-04 19:06:09 +0000103 int ret;
104
Andrew F. Davisdff11822019-04-10 12:40:12 -0400105 for (; retry > 0; retry--) {
106 /* Receive the response */
107 ret = k3_sec_proxy_recv(chan, msg);
108 if (ret) {
109 ERROR("Message receive failed (%d)\n", ret);
110 return ret;
111 }
Andrew F. Davisa513b2a2018-05-04 19:06:09 +0000112
Andrew F. Davisdff11822019-04-10 12:40:12 -0400113 /* msg is updated by Secure Proxy driver */
114 hdr = (struct ti_sci_msg_hdr *)msg->buf;
Andrew F. Davisa513b2a2018-05-04 19:06:09 +0000115
Andrew F. Davisdff11822019-04-10 12:40:12 -0400116 /* Sanity check for message response */
Andrew F. Davis5daafa12020-01-16 15:34:31 -0600117 if (hdr->seq == message_sequence)
Andrew F. Davisdff11822019-04-10 12:40:12 -0400118 break;
119 else
120 WARN("Message with sequence ID %u is not expected\n", hdr->seq);
121 }
122 if (!retry) {
123 ERROR("Timed out waiting for message\n");
Andrew F. Davisa513b2a2018-05-04 19:06:09 +0000124 return -EINVAL;
125 }
126
Andrew F. Davis5daafa12020-01-16 15:34:31 -0600127 if (msg->len > TI_SCI_MAX_MESSAGE_SIZE) {
Andrew F. Davisa513b2a2018-05-04 19:06:09 +0000128 ERROR("Unable to handle %lu xfer (max %d)\n",
Andrew F. Davis5daafa12020-01-16 15:34:31 -0600129 msg->len, TI_SCI_MAX_MESSAGE_SIZE);
Andrew F. Davisa513b2a2018-05-04 19:06:09 +0000130 return -EINVAL;
131 }
132
Andrew F. Davis06b30522019-02-11 13:44:31 -0600133 if (!(hdr->flags & TI_SCI_FLAG_RESP_GENERIC_ACK))
134 return -ENODEV;
135
Andrew F. Davisa513b2a2018-05-04 19:06:09 +0000136 return 0;
137}
138
139/**
140 * ti_sci_do_xfer() - Do one transfer
141 *
142 * @xfer: Transfer to initiate and wait for response
143 *
144 * Return: 0 if all goes well, else appropriate error message
145 */
Andrew Davis817bdbb2022-11-11 12:49:38 -0600146static int ti_sci_do_xfer(struct ti_sci_xfer *xfer)
Andrew F. Davisa513b2a2018-05-04 19:06:09 +0000147{
Andrew Davise0a676c2022-05-16 13:17:02 -0500148 struct k3_sec_proxy_msg *tx_msg = &xfer->tx_message;
149 struct k3_sec_proxy_msg *rx_msg = &xfer->rx_message;
Andrew F. Davisa513b2a2018-05-04 19:06:09 +0000150 int ret;
151
Andrew Davis617d0352023-03-13 13:56:27 -0500152 bakery_lock_get(&ti_sci_xfer_lock);
153
Andrew F. Davis18d371d2019-01-04 12:49:16 -0600154 /* Clear any spurious messages in receive queue */
155 ret = k3_sec_proxy_clear_rx_thread(SP_RESPONSE);
156 if (ret) {
157 ERROR("Could not clear response queue (%d)\n", ret);
158 return ret;
159 }
160
Andrew F. Davisa513b2a2018-05-04 19:06:09 +0000161 /* Send the message */
Andrew Davise0a676c2022-05-16 13:17:02 -0500162 ret = k3_sec_proxy_send(SP_HIGH_PRIORITY, tx_msg);
Andrew F. Davisa513b2a2018-05-04 19:06:09 +0000163 if (ret) {
164 ERROR("Message sending failed (%d)\n", ret);
165 return ret;
166 }
167
Andrew Davise0a676c2022-05-16 13:17:02 -0500168 /* Get the response if requested */
169 if (rx_msg->len != 0U) {
170 ret = ti_sci_get_response(rx_msg, SP_RESPONSE);
171 if (ret != 0U) {
172 ERROR("Failed to get response (%d)\n", ret);
173 return ret;
174 }
Andrew F. Davisa513b2a2018-05-04 19:06:09 +0000175 }
176
Andrew Davis617d0352023-03-13 13:56:27 -0500177 bakery_lock_release(&ti_sci_xfer_lock);
178
Andrew F. Davisa513b2a2018-05-04 19:06:09 +0000179 return 0;
180}
181
182/**
183 * ti_sci_get_revision() - Get the revision of the SCI entity
184 *
185 * Updates the SCI information in the internal data structure.
186 *
187 * Return: 0 if all goes well, else appropriate error message
188 */
189int ti_sci_get_revision(struct ti_sci_msg_resp_version *rev_info)
190{
191 struct ti_sci_msg_hdr hdr;
192 struct ti_sci_xfer xfer;
193 int ret;
194
195 ret = ti_sci_setup_one_xfer(TI_SCI_MSG_VERSION, 0x0,
196 &hdr, sizeof(hdr),
197 rev_info, sizeof(*rev_info),
198 &xfer);
199 if (ret) {
200 ERROR("Message alloc failed (%d)\n", ret);
201 return ret;
202 }
203
204 ret = ti_sci_do_xfer(&xfer);
205 if (ret) {
206 ERROR("Transfer send failed (%d)\n", ret);
207 return ret;
208 }
209
210 return 0;
211}
212
213/**
Andrew F. Davis4f2a0552018-05-04 19:06:10 +0000214 * ti_sci_device_set_state() - Set device state
215 *
216 * @id: Device identifier
217 * @flags: flags to setup for the device
218 * @state: State to move the device to
219 *
220 * Return: 0 if all goes well, else appropriate error message
221 */
Andrew F. Davis8335bc22019-02-11 12:55:25 -0600222static int ti_sci_device_set_state(uint32_t id, uint32_t flags, uint8_t state)
Andrew F. Davis4f2a0552018-05-04 19:06:10 +0000223{
224 struct ti_sci_msg_req_set_device_state req;
225 struct ti_sci_msg_hdr resp;
226
227 struct ti_sci_xfer xfer;
228 int ret;
229
Andrew F. Davis06b30522019-02-11 13:44:31 -0600230 ret = ti_sci_setup_one_xfer(TI_SCI_MSG_SET_DEVICE_STATE, flags,
Andrew F. Davis4f2a0552018-05-04 19:06:10 +0000231 &req, sizeof(req),
232 &resp, sizeof(resp),
233 &xfer);
234 if (ret) {
235 ERROR("Message alloc failed (%d)\n", ret);
236 return ret;
237 }
238
239 req.id = id;
240 req.state = state;
241
242 ret = ti_sci_do_xfer(&xfer);
243 if (ret) {
244 ERROR("Transfer send failed (%d)\n", ret);
245 return ret;
246 }
247
Andrew F. Davis4f2a0552018-05-04 19:06:10 +0000248 return 0;
249}
250
251/**
252 * ti_sci_device_get_state() - Get device state
253 *
254 * @id: Device Identifier
255 * @clcnt: Pointer to Context Loss Count
256 * @resets: pointer to resets
257 * @p_state: pointer to p_state
258 * @c_state: pointer to c_state
259 *
260 * Return: 0 if all goes well, else appropriate error message
261 */
Andrew F. Davis8335bc22019-02-11 12:55:25 -0600262static int ti_sci_device_get_state(uint32_t id, uint32_t *clcnt,
263 uint32_t *resets, uint8_t *p_state,
264 uint8_t *c_state)
Andrew F. Davis4f2a0552018-05-04 19:06:10 +0000265{
266 struct ti_sci_msg_req_get_device_state req;
267 struct ti_sci_msg_resp_get_device_state resp;
268
269 struct ti_sci_xfer xfer;
270 int ret;
271
272 if (!clcnt && !resets && !p_state && !c_state)
273 return -EINVAL;
274
275 ret = ti_sci_setup_one_xfer(TI_SCI_MSG_GET_DEVICE_STATE, 0,
276 &req, sizeof(req),
277 &resp, sizeof(resp),
278 &xfer);
279 if (ret) {
280 ERROR("Message alloc failed (%d)\n", ret);
281 return ret;
282 }
283
284 req.id = id;
285
286 ret = ti_sci_do_xfer(&xfer);
287 if (ret) {
288 ERROR("Transfer send failed (%d)\n", ret);
289 return ret;
290 }
291
Andrew F. Davis4f2a0552018-05-04 19:06:10 +0000292 if (clcnt)
293 *clcnt = resp.context_loss_count;
294 if (resets)
295 *resets = resp.resets;
296 if (p_state)
297 *p_state = resp.programmed_state;
298 if (c_state)
299 *c_state = resp.current_state;
300
301 return 0;
302}
303
304/**
305 * ti_sci_device_get() - Request for device managed by TISCI
306 *
307 * @id: Device Identifier
308 *
309 * Request for the device - NOTE: the client MUST maintain integrity of
310 * usage count by balancing get_device with put_device. No refcounting is
311 * managed by driver for that purpose.
312 *
Andrew F. Davis4f2a0552018-05-04 19:06:10 +0000313 * Return: 0 if all goes well, else appropriate error message
314 */
315int ti_sci_device_get(uint32_t id)
316{
Andrew F. Davisfbe6c062019-02-11 12:58:32 -0600317 return ti_sci_device_set_state(id, 0, MSG_DEVICE_SW_STATE_ON);
318}
319
320/**
321 * ti_sci_device_get_exclusive() - Exclusive request for device managed by TISCI
322 *
323 * @id: Device Identifier
324 *
325 * Request for the device - NOTE: the client MUST maintain integrity of
326 * usage count by balancing get_device with put_device. No refcounting is
327 * managed by driver for that purpose.
328 *
329 * NOTE: This _exclusive version of the get API is for exclusive access to the
330 * device. Any other host in the system will fail to get this device after this
331 * call until exclusive access is released with device_put or a non-exclusive
332 * set call.
333 *
334 * Return: 0 if all goes well, else appropriate error message
335 */
336int ti_sci_device_get_exclusive(uint32_t id)
337{
Andrew F. Davis4f2a0552018-05-04 19:06:10 +0000338 return ti_sci_device_set_state(id,
339 MSG_FLAG_DEVICE_EXCLUSIVE,
340 MSG_DEVICE_SW_STATE_ON);
341}
342
343/**
344 * ti_sci_device_idle() - Idle a device managed by TISCI
345 *
346 * @id: Device Identifier
347 *
348 * Request for the device - NOTE: the client MUST maintain integrity of
349 * usage count by balancing get_device with put_device. No refcounting is
350 * managed by driver for that purpose.
351 *
352 * Return: 0 if all goes well, else appropriate error message
353 */
354int ti_sci_device_idle(uint32_t id)
355{
Andrew F. Davisfbe6c062019-02-11 12:58:32 -0600356 return ti_sci_device_set_state(id, 0, MSG_DEVICE_SW_STATE_RETENTION);
357}
358
359/**
360 * ti_sci_device_idle_exclusive() - Exclusive idle a device managed by TISCI
361 *
362 * @id: Device Identifier
363 *
364 * Request for the device - NOTE: the client MUST maintain integrity of
365 * usage count by balancing get_device with put_device. No refcounting is
366 * managed by driver for that purpose.
367 *
368 * NOTE: This _exclusive version of the idle API is for exclusive access to
369 * the device. Any other host in the system will fail to get this device after
370 * this call until exclusive access is released with device_put or a
371 * non-exclusive set call.
372 *
373 * Return: 0 if all goes well, else appropriate error message
374 */
375int ti_sci_device_idle_exclusive(uint32_t id)
376{
Andrew F. Davis4f2a0552018-05-04 19:06:10 +0000377 return ti_sci_device_set_state(id,
378 MSG_FLAG_DEVICE_EXCLUSIVE,
379 MSG_DEVICE_SW_STATE_RETENTION);
380}
381
382/**
383 * ti_sci_device_put() - Release a device managed by TISCI
384 *
385 * @id: Device Identifier
386 *
387 * Request for the device - NOTE: the client MUST maintain integrity of
388 * usage count by balancing get_device with put_device. No refcounting is
389 * managed by driver for that purpose.
390 *
391 * Return: 0 if all goes well, else appropriate error message
392 */
393int ti_sci_device_put(uint32_t id)
394{
395 return ti_sci_device_set_state(id, 0, MSG_DEVICE_SW_STATE_AUTO_OFF);
396}
397
398/**
Andrew F. Davisa29578d2019-02-11 14:18:53 -0600399 * ti_sci_device_put_no_wait() - Release a device without requesting or waiting
400 * for a response.
401 *
402 * @id: Device Identifier
403 *
404 * Request for the device - NOTE: the client MUST maintain integrity of
405 * usage count by balancing get_device with put_device. No refcounting is
406 * managed by driver for that purpose.
407 *
408 * Return: 0 if all goes well, else appropriate error message
409 */
410int ti_sci_device_put_no_wait(uint32_t id)
411{
412 struct ti_sci_msg_req_set_device_state req;
Andrew Davise0a676c2022-05-16 13:17:02 -0500413 struct ti_sci_xfer xfer;
Andrew F. Davisa29578d2019-02-11 14:18:53 -0600414 int ret;
415
Andrew Davise0a676c2022-05-16 13:17:02 -0500416 ret = ti_sci_setup_one_xfer(TI_SCI_MSG_GET_DEVICE_STATE, 0,
417 &req, sizeof(req),
418 NULL, 0,
419 &xfer);
420 if (ret != 0U) {
421 ERROR("Message alloc failed (%d)\n", ret);
422 return ret;
423 }
Andrew F. Davisa29578d2019-02-11 14:18:53 -0600424
425 req.id = id;
426 req.state = MSG_DEVICE_SW_STATE_AUTO_OFF;
427
Andrew Davise0a676c2022-05-16 13:17:02 -0500428 ret = ti_sci_do_xfer(&xfer);
429 if (ret != 0U) {
430 ERROR("Transfer send failed (%d)\n", ret);
Andrew F. Davisa29578d2019-02-11 14:18:53 -0600431 return ret;
432 }
433
Andrew F. Davisa29578d2019-02-11 14:18:53 -0600434 return 0;
435}
436
437/**
Andrew F. Davis4f2a0552018-05-04 19:06:10 +0000438 * ti_sci_device_is_valid() - Is the device valid
439 *
440 * @id: Device Identifier
441 *
442 * Return: 0 if all goes well and the device ID is valid, else return
443 * appropriate error
444 */
445int ti_sci_device_is_valid(uint32_t id)
446{
447 uint8_t unused;
448
449 /* check the device state which will also tell us if the ID is valid */
450 return ti_sci_device_get_state(id, NULL, NULL, NULL, &unused);
451}
452
453/**
454 * ti_sci_device_get_clcnt() - Get context loss counter
455 *
456 * @id: Device Identifier
457 * @count: Pointer to Context Loss counter to populate
458 *
459 * Return: 0 if all goes well, else appropriate error message
460 */
461int ti_sci_device_get_clcnt(uint32_t id, uint32_t *count)
462{
463 return ti_sci_device_get_state(id, count, NULL, NULL, NULL);
464}
465
466/**
467 * ti_sci_device_is_idle() - Check if the device is requested to be idle
468 *
469 * @id: Device Identifier
470 * @r_state: true if requested to be idle
471 *
472 * Return: 0 if all goes well, else appropriate error message
473 */
474int ti_sci_device_is_idle(uint32_t id, bool *r_state)
475{
476 int ret;
477 uint8_t state;
478
479 if (!r_state)
480 return -EINVAL;
481
482 ret = ti_sci_device_get_state(id, NULL, NULL, &state, NULL);
483 if (ret)
484 return ret;
485
486 *r_state = (state == MSG_DEVICE_SW_STATE_RETENTION);
487
488 return 0;
489}
490
491/**
492 * ti_sci_device_is_stop() - Check if the device is requested to be stopped
493 *
494 * @id: Device Identifier
495 * @r_state: true if requested to be stopped
496 * @curr_state: true if currently stopped
497 *
498 * Return: 0 if all goes well, else appropriate error message
499 */
500int ti_sci_device_is_stop(uint32_t id, bool *r_state, bool *curr_state)
501{
502 int ret;
503 uint8_t p_state, c_state;
504
505 if (!r_state && !curr_state)
506 return -EINVAL;
507
508 ret = ti_sci_device_get_state(id, NULL, NULL, &p_state, &c_state);
509 if (ret)
510 return ret;
511
512 if (r_state)
513 *r_state = (p_state == MSG_DEVICE_SW_STATE_AUTO_OFF);
514 if (curr_state)
515 *curr_state = (c_state == MSG_DEVICE_HW_STATE_OFF);
516
517 return 0;
518}
519
520/**
521 * ti_sci_device_is_on() - Check if the device is requested to be ON
522 *
523 * @id: Device Identifier
524 * @r_state: true if requested to be ON
525 * @curr_state: true if currently ON and active
526 *
527 * Return: 0 if all goes well, else appropriate error message
528 */
529int ti_sci_device_is_on(uint32_t id, bool *r_state, bool *curr_state)
530{
531 int ret;
532 uint8_t p_state, c_state;
533
534 if (!r_state && !curr_state)
535 return -EINVAL;
536
537 ret =
538 ti_sci_device_get_state(id, NULL, NULL, &p_state, &c_state);
539 if (ret)
540 return ret;
541
542 if (r_state)
543 *r_state = (p_state == MSG_DEVICE_SW_STATE_ON);
544 if (curr_state)
545 *curr_state = (c_state == MSG_DEVICE_HW_STATE_ON);
546
547 return 0;
548}
549
550/**
551 * ti_sci_device_is_trans() - Check if the device is currently transitioning
552 *
553 * @id: Device Identifier
554 * @curr_state: true if currently transitioning
555 *
556 * Return: 0 if all goes well, else appropriate error message
557 */
558int ti_sci_device_is_trans(uint32_t id, bool *curr_state)
559{
560 int ret;
561 uint8_t state;
562
563 if (!curr_state)
564 return -EINVAL;
565
566 ret = ti_sci_device_get_state(id, NULL, NULL, NULL, &state);
567 if (ret)
568 return ret;
569
570 *curr_state = (state == MSG_DEVICE_HW_STATE_TRANS);
571
572 return 0;
573}
574
575/**
576 * ti_sci_device_set_resets() - Set resets for device managed by TISCI
577 *
578 * @id: Device Identifier
579 * @reset_state: Device specific reset bit field
580 *
581 * Return: 0 if all goes well, else appropriate error message
582 */
583int ti_sci_device_set_resets(uint32_t id, uint32_t reset_state)
584{
585 struct ti_sci_msg_req_set_device_resets req;
586 struct ti_sci_msg_hdr resp;
587
588 struct ti_sci_xfer xfer;
589 int ret;
590
Andrew F. Davis06b30522019-02-11 13:44:31 -0600591 ret = ti_sci_setup_one_xfer(TI_SCI_MSG_SET_DEVICE_RESETS, 0,
Andrew F. Davis4f2a0552018-05-04 19:06:10 +0000592 &req, sizeof(req),
593 &resp, sizeof(resp),
594 &xfer);
595 if (ret) {
596 ERROR("Message alloc failed (%d)\n", ret);
597 return ret;
598 }
599
600 req.id = id;
601 req.resets = reset_state;
602
603 ret = ti_sci_do_xfer(&xfer);
604 if (ret) {
605 ERROR("Transfer send failed (%d)\n", ret);
606 return ret;
607 }
608
Andrew F. Davis4f2a0552018-05-04 19:06:10 +0000609 return 0;
610}
611
612/**
613 * ti_sci_device_get_resets() - Get reset state for device managed by TISCI
614 *
615 * @id: Device Identifier
616 * @reset_state: Pointer to reset state to populate
617 *
618 * Return: 0 if all goes well, else appropriate error message
619 */
620int ti_sci_device_get_resets(uint32_t id, uint32_t *reset_state)
621{
622 return ti_sci_device_get_state(id, NULL, reset_state, NULL, NULL);
623}
624
625/**
Andrew F. Davisdc08adf2018-05-04 19:06:11 +0000626 * ti_sci_clock_set_state() - Set clock state helper
627 *
628 * @dev_id: Device identifier this request is for
629 * @clk_id: Clock identifier for the device for this request,
630 * Each device has its own set of clock inputs, This indexes
631 * which clock input to modify
632 * @flags: Header flags as needed
633 * @state: State to request for the clock
634 *
635 * Return: 0 if all goes well, else appropriate error message
636 */
637int ti_sci_clock_set_state(uint32_t dev_id, uint8_t clk_id,
638 uint32_t flags, uint8_t state)
639{
640 struct ti_sci_msg_req_set_clock_state req;
641 struct ti_sci_msg_hdr resp;
642
643 struct ti_sci_xfer xfer;
644 int ret;
645
Andrew F. Davis06b30522019-02-11 13:44:31 -0600646 ret = ti_sci_setup_one_xfer(TI_SCI_MSG_SET_CLOCK_STATE, flags,
Andrew F. Davisdc08adf2018-05-04 19:06:11 +0000647 &req, sizeof(req),
648 &resp, sizeof(resp),
649 &xfer);
650 if (ret) {
651 ERROR("Message alloc failed (%d)\n", ret);
652 return ret;
653 }
654
655 req.dev_id = dev_id;
656 req.clk_id = clk_id;
657 req.request_state = state;
658
659 ret = ti_sci_do_xfer(&xfer);
660 if (ret) {
661 ERROR("Transfer send failed (%d)\n", ret);
662 return ret;
663 }
664
Andrew F. Davisdc08adf2018-05-04 19:06:11 +0000665 return 0;
666}
667
668/**
669 * ti_sci_clock_get_state() - Get clock state helper
670 *
671 * @dev_id: Device identifier this request is for
672 * @clk_id: Clock identifier for the device for this request.
673 * Each device has its own set of clock inputs. This indexes
674 * which clock input to modify.
675 * @programmed_state: State requested for clock to move to
676 * @current_state: State that the clock is currently in
677 *
678 * Return: 0 if all goes well, else appropriate error message
679 */
680int ti_sci_clock_get_state(uint32_t dev_id, uint8_t clk_id,
681 uint8_t *programmed_state,
682 uint8_t *current_state)
683{
684 struct ti_sci_msg_req_get_clock_state req;
685 struct ti_sci_msg_resp_get_clock_state resp;
686
687 struct ti_sci_xfer xfer;
688 int ret;
689
690 if (!programmed_state && !current_state)
691 return -EINVAL;
692
Andrew F. Davis06b30522019-02-11 13:44:31 -0600693 ret = ti_sci_setup_one_xfer(TI_SCI_MSG_GET_CLOCK_STATE, 0,
Andrew F. Davisdc08adf2018-05-04 19:06:11 +0000694 &req, sizeof(req),
695 &resp, sizeof(resp),
696 &xfer);
697 if (ret) {
698 ERROR("Message alloc failed (%d)\n", ret);
699 return ret;
700 }
701
702 req.dev_id = dev_id;
703 req.clk_id = clk_id;
704
705 ret = ti_sci_do_xfer(&xfer);
706 if (ret) {
707 ERROR("Transfer send failed (%d)\n", ret);
708 return ret;
709 }
710
Andrew F. Davisdc08adf2018-05-04 19:06:11 +0000711 if (programmed_state)
712 *programmed_state = resp.programmed_state;
713 if (current_state)
714 *current_state = resp.current_state;
715
716 return 0;
717}
718
719/**
720 * ti_sci_clock_get() - Get control of a clock from TI SCI
721
722 * @dev_id: Device identifier this request is for
723 * @clk_id: Clock identifier for the device for this request.
724 * Each device has its own set of clock inputs. This indexes
725 * which clock input to modify.
726 * @needs_ssc: 'true' iff Spread Spectrum clock is desired
727 * @can_change_freq: 'true' iff frequency change is desired
728 * @enable_input_term: 'true' iff input termination is desired
729 *
730 * Return: 0 if all goes well, else appropriate error message
731 */
732int ti_sci_clock_get(uint32_t dev_id, uint8_t clk_id,
733 bool needs_ssc, bool can_change_freq,
734 bool enable_input_term)
735{
736 uint32_t flags = 0;
737
738 flags |= needs_ssc ? MSG_FLAG_CLOCK_ALLOW_SSC : 0;
739 flags |= can_change_freq ? MSG_FLAG_CLOCK_ALLOW_FREQ_CHANGE : 0;
740 flags |= enable_input_term ? MSG_FLAG_CLOCK_INPUT_TERM : 0;
741
742 return ti_sci_clock_set_state(dev_id, clk_id, flags,
743 MSG_CLOCK_SW_STATE_REQ);
744}
745
746/**
747 * ti_sci_clock_idle() - Idle a clock which is in our control
748
749 * @dev_id: Device identifier this request is for
750 * @clk_id: Clock identifier for the device for this request.
751 * Each device has its own set of clock inputs. This indexes
752 * which clock input to modify.
753 *
754 * NOTE: This clock must have been requested by get_clock previously.
755 *
756 * Return: 0 if all goes well, else appropriate error message
757 */
758int ti_sci_clock_idle(uint32_t dev_id, uint8_t clk_id)
759{
760 return ti_sci_clock_set_state(dev_id, clk_id, 0,
761 MSG_CLOCK_SW_STATE_UNREQ);
762}
763
764/**
765 * ti_sci_clock_put() - Release a clock from our control
766 *
767 * @dev_id: Device identifier this request is for
768 * @clk_id: Clock identifier for the device for this request.
769 * Each device has its own set of clock inputs. This indexes
770 * which clock input to modify.
771 *
772 * NOTE: This clock must have been requested by get_clock previously.
773 *
774 * Return: 0 if all goes well, else appropriate error message
775 */
776int ti_sci_clock_put(uint32_t dev_id, uint8_t clk_id)
777{
778 return ti_sci_clock_set_state(dev_id, clk_id, 0,
779 MSG_CLOCK_SW_STATE_AUTO);
780}
781
782/**
783 * ti_sci_clock_is_auto() - Is the clock being auto managed
784 *
785 * @dev_id: Device identifier this request is for
786 * @clk_id: Clock identifier for the device for this request.
787 * Each device has its own set of clock inputs. This indexes
788 * which clock input to modify.
789 * @req_state: state indicating if the clock is auto managed
790 *
791 * Return: 0 if all goes well, else appropriate error message
792 */
793int ti_sci_clock_is_auto(uint32_t dev_id, uint8_t clk_id, bool *req_state)
794{
795 uint8_t state = 0;
796 int ret;
797
798 if (!req_state)
799 return -EINVAL;
800
801 ret = ti_sci_clock_get_state(dev_id, clk_id, &state, NULL);
802 if (ret)
803 return ret;
804
805 *req_state = (state == MSG_CLOCK_SW_STATE_AUTO);
806
807 return 0;
808}
809
810/**
811 * ti_sci_clock_is_on() - Is the clock ON
812 *
813 * @dev_id: Device identifier this request is for
814 * @clk_id: Clock identifier for the device for this request.
815 * Each device has its own set of clock inputs. This indexes
816 * which clock input to modify.
817 * @req_state: state indicating if the clock is managed by us and enabled
818 * @curr_state: state indicating if the clock is ready for operation
819 *
820 * Return: 0 if all goes well, else appropriate error message
821 */
822int ti_sci_clock_is_on(uint32_t dev_id, uint8_t clk_id,
823 bool *req_state, bool *curr_state)
824{
825 uint8_t c_state = 0, r_state = 0;
826 int ret;
827
828 if (!req_state && !curr_state)
829 return -EINVAL;
830
831 ret = ti_sci_clock_get_state(dev_id, clk_id, &r_state, &c_state);
832 if (ret)
833 return ret;
834
835 if (req_state)
836 *req_state = (r_state == MSG_CLOCK_SW_STATE_REQ);
837 if (curr_state)
838 *curr_state = (c_state == MSG_CLOCK_HW_STATE_READY);
839
840 return 0;
841}
842
843/**
844 * ti_sci_clock_is_off() - Is the clock OFF
845 *
846 * @dev_id: Device identifier this request is for
847 * @clk_id: Clock identifier for the device for this request.
848 * Each device has its own set of clock inputs. This indexes
849 * which clock input to modify.
850 * @req_state: state indicating if the clock is managed by us and disabled
851 * @curr_state: state indicating if the clock is NOT ready for operation
852 *
853 * Return: 0 if all goes well, else appropriate error message
854 */
855int ti_sci_clock_is_off(uint32_t dev_id, uint8_t clk_id,
856 bool *req_state, bool *curr_state)
857{
858 uint8_t c_state = 0, r_state = 0;
859 int ret;
860
861 if (!req_state && !curr_state)
862 return -EINVAL;
863
864 ret = ti_sci_clock_get_state(dev_id, clk_id, &r_state, &c_state);
865 if (ret)
866 return ret;
867
868 if (req_state)
869 *req_state = (r_state == MSG_CLOCK_SW_STATE_UNREQ);
870 if (curr_state)
871 *curr_state = (c_state == MSG_CLOCK_HW_STATE_NOT_READY);
872
873 return 0;
874}
875
876/**
877 * ti_sci_clock_set_parent() - Set the clock source of a specific device clock
878 *
879 * @dev_id: Device identifier this request is for
880 * @clk_id: Clock identifier for the device for this request.
881 * Each device has its own set of clock inputs. This indexes
882 * which clock input to modify.
883 * @parent_id: Parent clock identifier to set
884 *
885 * Return: 0 if all goes well, else appropriate error message
886 */
887int ti_sci_clock_set_parent(uint32_t dev_id, uint8_t clk_id, uint8_t parent_id)
888{
889 struct ti_sci_msg_req_set_clock_parent req;
890 struct ti_sci_msg_hdr resp;
891
892 struct ti_sci_xfer xfer;
893 int ret;
894
Andrew F. Davis06b30522019-02-11 13:44:31 -0600895 ret = ti_sci_setup_one_xfer(TI_SCI_MSG_SET_CLOCK_PARENT, 0,
Andrew F. Davisdc08adf2018-05-04 19:06:11 +0000896 &req, sizeof(req),
897 &resp, sizeof(resp),
898 &xfer);
899 if (ret) {
900 ERROR("Message alloc failed (%d)\n", ret);
901 return ret;
902 }
903
904 req.dev_id = dev_id;
905 req.clk_id = clk_id;
906 req.parent_id = parent_id;
907
908 ret = ti_sci_do_xfer(&xfer);
909 if (ret) {
910 ERROR("Transfer send failed (%d)\n", ret);
911 return ret;
912 }
913
Andrew F. Davisdc08adf2018-05-04 19:06:11 +0000914 return 0;
915}
916
917/**
918 * ti_sci_clock_get_parent() - Get current parent clock source
919 *
920 * @dev_id: Device identifier this request is for
921 * @clk_id: Clock identifier for the device for this request.
922 * Each device has its own set of clock inputs. This indexes
923 * which clock input to modify.
924 * @parent_id: Current clock parent
925 *
926 * Return: 0 if all goes well, else appropriate error message
927 */
928int ti_sci_clock_get_parent(uint32_t dev_id, uint8_t clk_id, uint8_t *parent_id)
929{
930 struct ti_sci_msg_req_get_clock_parent req;
931 struct ti_sci_msg_resp_get_clock_parent resp;
932
933 struct ti_sci_xfer xfer;
934 int ret;
935
Andrew F. Davis06b30522019-02-11 13:44:31 -0600936 ret = ti_sci_setup_one_xfer(TI_SCI_MSG_GET_CLOCK_PARENT, 0,
Andrew F. Davisdc08adf2018-05-04 19:06:11 +0000937 &req, sizeof(req),
938 &resp, sizeof(resp),
939 &xfer);
940 if (ret) {
941 ERROR("Message alloc failed (%d)\n", ret);
942 return ret;
943 }
944
945 req.dev_id = dev_id;
946 req.clk_id = clk_id;
947
948 ret = ti_sci_do_xfer(&xfer);
949 if (ret) {
950 ERROR("Transfer send failed (%d)\n", ret);
951 return ret;
952 }
953
Andrew F. Davisdc08adf2018-05-04 19:06:11 +0000954 *parent_id = resp.parent_id;
955
956 return 0;
957}
958
959/**
960 * ti_sci_clock_get_num_parents() - Get num parents of the current clk source
961 *
962 * @dev_id: Device identifier this request is for
963 * @clk_id: Clock identifier for the device for this request.
964 * Each device has its own set of clock inputs. This indexes
965 * which clock input to modify.
966 * @num_parents: Returns he number of parents to the current clock.
967 *
968 * Return: 0 if all goes well, else appropriate error message
969 */
970int ti_sci_clock_get_num_parents(uint32_t dev_id, uint8_t clk_id,
971 uint8_t *num_parents)
972{
973 struct ti_sci_msg_req_get_clock_num_parents req;
974 struct ti_sci_msg_resp_get_clock_num_parents resp;
975
976 struct ti_sci_xfer xfer;
977 int ret;
978
Andrew F. Davis06b30522019-02-11 13:44:31 -0600979 ret = ti_sci_setup_one_xfer(TI_SCI_MSG_GET_NUM_CLOCK_PARENTS, 0,
Andrew F. Davisdc08adf2018-05-04 19:06:11 +0000980 &req, sizeof(req),
981 &resp, sizeof(resp),
982 &xfer);
983 if (ret) {
984 ERROR("Message alloc failed (%d)\n", ret);
985 return ret;
986 }
987
988 req.dev_id = dev_id;
989 req.clk_id = clk_id;
990
991 ret = ti_sci_do_xfer(&xfer);
992 if (ret) {
993 ERROR("Transfer send failed (%d)\n", ret);
994 return ret;
995 }
996
Andrew F. Davisdc08adf2018-05-04 19:06:11 +0000997 *num_parents = resp.num_parents;
998
999 return 0;
1000}
1001
1002/**
1003 * ti_sci_clock_get_match_freq() - Find a good match for frequency
1004 *
1005 * @dev_id: Device identifier this request is for
1006 * @clk_id: Clock identifier for the device for this request.
1007 * Each device has its own set of clock inputs. This indexes
1008 * which clock input to modify.
1009 * @min_freq: The minimum allowable frequency in Hz. This is the minimum
1010 * allowable programmed frequency and does not account for clock
1011 * tolerances and jitter.
1012 * @target_freq: The target clock frequency in Hz. A frequency will be
1013 * processed as close to this target frequency as possible.
1014 * @max_freq: The maximum allowable frequency in Hz. This is the maximum
1015 * allowable programmed frequency and does not account for clock
1016 * tolerances and jitter.
1017 * @match_freq: Frequency match in Hz response.
1018 *
1019 * Return: 0 if all goes well, else appropriate error message
1020 */
1021int ti_sci_clock_get_match_freq(uint32_t dev_id, uint8_t clk_id,
1022 uint64_t min_freq, uint64_t target_freq,
1023 uint64_t max_freq, uint64_t *match_freq)
1024{
1025 struct ti_sci_msg_req_query_clock_freq req;
1026 struct ti_sci_msg_resp_query_clock_freq resp;
1027
1028 struct ti_sci_xfer xfer;
1029 int ret;
1030
Andrew F. Davis06b30522019-02-11 13:44:31 -06001031 ret = ti_sci_setup_one_xfer(TI_SCI_MSG_QUERY_CLOCK_FREQ, 0,
Andrew F. Davisdc08adf2018-05-04 19:06:11 +00001032 &req, sizeof(req),
1033 &resp, sizeof(resp),
1034 &xfer);
1035 if (ret) {
1036 ERROR("Message alloc failed (%d)\n", ret);
1037 return ret;
1038 }
1039
1040 req.dev_id = dev_id;
1041 req.clk_id = clk_id;
1042 req.min_freq_hz = min_freq;
1043 req.target_freq_hz = target_freq;
1044 req.max_freq_hz = max_freq;
1045
1046 ret = ti_sci_do_xfer(&xfer);
1047 if (ret) {
1048 ERROR("Transfer send failed (%d)\n", ret);
1049 return ret;
1050 }
1051
Andrew F. Davisdc08adf2018-05-04 19:06:11 +00001052 *match_freq = resp.freq_hz;
1053
1054 return 0;
1055}
1056
1057/**
1058 * ti_sci_clock_set_freq() - Set a frequency for clock
1059 *
1060 * @dev_id: Device identifier this request is for
1061 * @clk_id: Clock identifier for the device for this request.
1062 * Each device has its own set of clock inputs. This indexes
1063 * which clock input to modify.
1064 * @min_freq: The minimum allowable frequency in Hz. This is the minimum
1065 * allowable programmed frequency and does not account for clock
1066 * tolerances and jitter.
1067 * @target_freq: The target clock frequency in Hz. A frequency will be
1068 * processed as close to this target frequency as possible.
1069 * @max_freq: The maximum allowable frequency in Hz. This is the maximum
1070 * allowable programmed frequency and does not account for clock
1071 * tolerances and jitter.
1072 *
1073 * Return: 0 if all goes well, else appropriate error message
1074 */
1075int ti_sci_clock_set_freq(uint32_t dev_id, uint8_t clk_id, uint64_t min_freq,
1076 uint64_t target_freq, uint64_t max_freq)
1077{
1078 struct ti_sci_msg_req_set_clock_freq req;
1079 struct ti_sci_msg_hdr resp;
1080
1081 struct ti_sci_xfer xfer;
1082 int ret;
1083
Andrew F. Davis06b30522019-02-11 13:44:31 -06001084 ret = ti_sci_setup_one_xfer(TI_SCI_MSG_SET_CLOCK_FREQ, 0,
Andrew F. Davisdc08adf2018-05-04 19:06:11 +00001085 &req, sizeof(req),
1086 &resp, sizeof(resp),
1087 &xfer);
1088 if (ret) {
1089 ERROR("Message alloc failed (%d)\n", ret);
1090 return ret;
1091 }
1092 req.dev_id = dev_id;
1093 req.clk_id = clk_id;
1094 req.min_freq_hz = min_freq;
1095 req.target_freq_hz = target_freq;
1096 req.max_freq_hz = max_freq;
1097
1098 ret = ti_sci_do_xfer(&xfer);
1099 if (ret) {
1100 ERROR("Transfer send failed (%d)\n", ret);
1101 return ret;
1102 }
1103
Andrew F. Davisdc08adf2018-05-04 19:06:11 +00001104 return 0;
1105}
1106
1107/**
1108 * ti_sci_clock_get_freq() - Get current frequency
1109 *
1110 * @dev_id: Device identifier this request is for
1111 * @clk_id: Clock identifier for the device for this request.
1112 * Each device has its own set of clock inputs. This indexes
1113 * which clock input to modify.
1114 * @freq: Currently frequency in Hz
1115 *
1116 * Return: 0 if all goes well, else appropriate error message
1117 */
1118int ti_sci_clock_get_freq(uint32_t dev_id, uint8_t clk_id, uint64_t *freq)
1119{
1120 struct ti_sci_msg_req_get_clock_freq req;
1121 struct ti_sci_msg_resp_get_clock_freq resp;
1122
1123 struct ti_sci_xfer xfer;
1124 int ret;
1125
Andrew F. Davis06b30522019-02-11 13:44:31 -06001126 ret = ti_sci_setup_one_xfer(TI_SCI_MSG_GET_CLOCK_FREQ, 0,
Andrew F. Davisdc08adf2018-05-04 19:06:11 +00001127 &req, sizeof(req),
1128 &resp, sizeof(resp),
1129 &xfer);
1130 if (ret) {
1131 ERROR("Message alloc failed (%d)\n", ret);
1132 return ret;
1133 }
1134
1135 req.dev_id = dev_id;
1136 req.clk_id = clk_id;
1137
1138 ret = ti_sci_do_xfer(&xfer);
1139 if (ret) {
1140 ERROR("Transfer send failed (%d)\n", ret);
1141 return ret;
1142 }
1143
Andrew F. Davisdc08adf2018-05-04 19:06:11 +00001144 *freq = resp.freq_hz;
1145
1146 return 0;
1147}
1148
1149/**
Andrew F. Davis0d449302018-05-04 19:06:12 +00001150 * ti_sci_core_reboot() - Command to request system reset
1151 *
1152 * Return: 0 if all goes well, else appropriate error message
1153 */
1154int ti_sci_core_reboot(void)
1155{
1156 struct ti_sci_msg_req_reboot req;
1157 struct ti_sci_msg_hdr resp;
1158
1159 struct ti_sci_xfer xfer;
1160 int ret;
1161
Andrew F. Davis06b30522019-02-11 13:44:31 -06001162 ret = ti_sci_setup_one_xfer(TI_SCI_MSG_SYS_RESET, 0,
Andrew F. Davis0d449302018-05-04 19:06:12 +00001163 &req, sizeof(req),
1164 &resp, sizeof(resp),
1165 &xfer);
1166 if (ret) {
1167 ERROR("Message alloc failed (%d)\n", ret);
1168 return ret;
1169 }
Suman Anna0cb2bb12020-10-24 01:28:54 +00001170 req.domain = TI_SCI_DOMAIN_FULL_SOC_RESET;
Andrew F. Davis0d449302018-05-04 19:06:12 +00001171
1172 ret = ti_sci_do_xfer(&xfer);
1173 if (ret) {
1174 ERROR("Transfer send failed (%d)\n", ret);
1175 return ret;
1176 }
1177
Andrew F. Davis0d449302018-05-04 19:06:12 +00001178 return 0;
1179}
1180
1181/**
Andrew F. Davisd92fdfb2018-05-04 19:06:13 +00001182 * ti_sci_proc_request() - Request a physical processor control
1183 *
1184 * @proc_id: Processor ID this request is for
1185 *
1186 * Return: 0 if all goes well, else appropriate error message
1187 */
1188int ti_sci_proc_request(uint8_t proc_id)
1189{
1190 struct ti_sci_msg_req_proc_request req;
1191 struct ti_sci_msg_hdr resp;
1192
1193 struct ti_sci_xfer xfer;
1194 int ret;
1195
Andrew F. Davis06b30522019-02-11 13:44:31 -06001196 ret = ti_sci_setup_one_xfer(TISCI_MSG_PROC_REQUEST, 0,
Andrew F. Davisd92fdfb2018-05-04 19:06:13 +00001197 &req, sizeof(req),
1198 &resp, sizeof(resp),
1199 &xfer);
1200 if (ret) {
1201 ERROR("Message alloc failed (%d)\n", ret);
1202 return ret;
1203 }
1204
1205 req.processor_id = proc_id;
1206
1207 ret = ti_sci_do_xfer(&xfer);
1208 if (ret) {
1209 ERROR("Transfer send failed (%d)\n", ret);
1210 return ret;
1211 }
1212
Andrew F. Davisd92fdfb2018-05-04 19:06:13 +00001213 return 0;
1214}
1215
1216/**
1217 * ti_sci_proc_release() - Release a physical processor control
1218 *
1219 * @proc_id: Processor ID this request is for
1220 *
1221 * Return: 0 if all goes well, else appropriate error message
1222 */
1223int ti_sci_proc_release(uint8_t proc_id)
1224{
1225 struct ti_sci_msg_req_proc_release req;
1226 struct ti_sci_msg_hdr resp;
1227
1228 struct ti_sci_xfer xfer;
1229 int ret;
1230
Andrew F. Davis06b30522019-02-11 13:44:31 -06001231 ret = ti_sci_setup_one_xfer(TISCI_MSG_PROC_RELEASE, 0,
Andrew F. Davisd92fdfb2018-05-04 19:06:13 +00001232 &req, sizeof(req),
1233 &resp, sizeof(resp),
1234 &xfer);
1235 if (ret) {
1236 ERROR("Message alloc failed (%d)\n", ret);
1237 return ret;
1238 }
1239
1240 req.processor_id = proc_id;
1241
1242 ret = ti_sci_do_xfer(&xfer);
1243 if (ret) {
1244 ERROR("Transfer send failed (%d)\n", ret);
1245 return ret;
1246 }
1247
Andrew F. Davisd92fdfb2018-05-04 19:06:13 +00001248 return 0;
1249}
1250
1251/**
1252 * ti_sci_proc_handover() - Handover a physical processor control to a host in
1253 * the processor's access control list.
1254 *
1255 * @proc_id: Processor ID this request is for
1256 * @host_id: Host ID to get the control of the processor
1257 *
1258 * Return: 0 if all goes well, else appropriate error message
1259 */
1260int ti_sci_proc_handover(uint8_t proc_id, uint8_t host_id)
1261{
1262 struct ti_sci_msg_req_proc_handover req;
1263 struct ti_sci_msg_hdr resp;
1264
1265 struct ti_sci_xfer xfer;
1266 int ret;
1267
Andrew F. Davis06b30522019-02-11 13:44:31 -06001268 ret = ti_sci_setup_one_xfer(TISCI_MSG_PROC_HANDOVER, 0,
Andrew F. Davisd92fdfb2018-05-04 19:06:13 +00001269 &req, sizeof(req),
1270 &resp, sizeof(resp),
1271 &xfer);
1272 if (ret) {
1273 ERROR("Message alloc failed (%d)\n", ret);
1274 return ret;
1275 }
1276
1277 req.processor_id = proc_id;
1278 req.host_id = host_id;
1279
1280 ret = ti_sci_do_xfer(&xfer);
1281 if (ret) {
1282 ERROR("Transfer send failed (%d)\n", ret);
1283 return ret;
1284 }
1285
Andrew F. Davisd92fdfb2018-05-04 19:06:13 +00001286 return 0;
1287}
1288
1289/**
1290 * ti_sci_proc_set_boot_cfg() - Set the processor boot configuration flags
1291 *
1292 * @proc_id: Processor ID this request is for
1293 * @config_flags_set: Configuration flags to be set
1294 * @config_flags_clear: Configuration flags to be cleared
1295 *
1296 * Return: 0 if all goes well, else appropriate error message
1297 */
1298int ti_sci_proc_set_boot_cfg(uint8_t proc_id, uint64_t bootvector,
1299 uint32_t config_flags_set,
1300 uint32_t config_flags_clear)
1301{
1302 struct ti_sci_msg_req_set_proc_boot_config req;
1303 struct ti_sci_msg_hdr resp;
1304
1305 struct ti_sci_xfer xfer;
1306 int ret;
1307
Andrew F. Davis06b30522019-02-11 13:44:31 -06001308 ret = ti_sci_setup_one_xfer(TISCI_MSG_SET_PROC_BOOT_CONFIG, 0,
Andrew F. Davisd92fdfb2018-05-04 19:06:13 +00001309 &req, sizeof(req),
1310 &resp, sizeof(resp),
1311 &xfer);
1312 if (ret) {
1313 ERROR("Message alloc failed (%d)\n", ret);
1314 return ret;
1315 }
1316
1317 req.processor_id = proc_id;
1318 req.bootvector_low = bootvector & TISCI_ADDR_LOW_MASK;
1319 req.bootvector_high = (bootvector & TISCI_ADDR_HIGH_MASK) >>
1320 TISCI_ADDR_HIGH_SHIFT;
1321 req.config_flags_set = config_flags_set;
1322 req.config_flags_clear = config_flags_clear;
1323
1324 ret = ti_sci_do_xfer(&xfer);
1325 if (ret) {
1326 ERROR("Transfer send failed (%d)\n", ret);
1327 return ret;
1328 }
1329
Andrew F. Davisd92fdfb2018-05-04 19:06:13 +00001330 return 0;
1331}
1332
1333/**
1334 * ti_sci_proc_set_boot_ctrl() - Set the processor boot control flags
1335 *
1336 * @proc_id: Processor ID this request is for
1337 * @control_flags_set: Control flags to be set
1338 * @control_flags_clear: Control flags to be cleared
1339 *
1340 * Return: 0 if all goes well, else appropriate error message
1341 */
1342int ti_sci_proc_set_boot_ctrl(uint8_t proc_id, uint32_t control_flags_set,
1343 uint32_t control_flags_clear)
1344{
1345 struct ti_sci_msg_req_set_proc_boot_ctrl req;
1346 struct ti_sci_msg_hdr resp;
1347
1348 struct ti_sci_xfer xfer;
1349 int ret;
1350
Andrew F. Davis06b30522019-02-11 13:44:31 -06001351 ret = ti_sci_setup_one_xfer(TISCI_MSG_SET_PROC_BOOT_CTRL, 0,
Andrew F. Davisd92fdfb2018-05-04 19:06:13 +00001352 &req, sizeof(req),
1353 &resp, sizeof(resp),
1354 &xfer);
1355 if (ret) {
1356 ERROR("Message alloc failed (%d)\n", ret);
1357 return ret;
1358 }
1359
1360 req.processor_id = proc_id;
1361 req.control_flags_set = control_flags_set;
1362 req.control_flags_clear = control_flags_clear;
1363
1364 ret = ti_sci_do_xfer(&xfer);
1365 if (ret) {
1366 ERROR("Transfer send failed (%d)\n", ret);
1367 return ret;
1368 }
1369
Andrew F. Davisd92fdfb2018-05-04 19:06:13 +00001370 return 0;
1371}
1372
1373/**
Andrew F. Davisa29578d2019-02-11 14:18:53 -06001374 * ti_sci_proc_set_boot_ctrl_no_wait() - Set the processor boot control flags
1375 * without requesting or waiting for a
1376 * response.
1377 *
1378 * @proc_id: Processor ID this request is for
1379 * @control_flags_set: Control flags to be set
1380 * @control_flags_clear: Control flags to be cleared
1381 *
1382 * Return: 0 if all goes well, else appropriate error message
1383 */
1384int ti_sci_proc_set_boot_ctrl_no_wait(uint8_t proc_id,
1385 uint32_t control_flags_set,
1386 uint32_t control_flags_clear)
1387{
1388 struct ti_sci_msg_req_set_proc_boot_ctrl req;
Andrew Davise0a676c2022-05-16 13:17:02 -05001389 struct ti_sci_xfer xfer;
Andrew F. Davisa29578d2019-02-11 14:18:53 -06001390 int ret;
1391
Andrew Davise0a676c2022-05-16 13:17:02 -05001392 ret = ti_sci_setup_one_xfer(TI_SCI_MSG_GET_DEVICE_STATE, 0,
1393 &req, sizeof(req),
1394 NULL, 0,
1395 &xfer);
1396 if (ret != 0U) {
1397 ERROR("Message alloc failed (%d)\n", ret);
1398 return ret;
1399 }
Andrew F. Davisa29578d2019-02-11 14:18:53 -06001400
1401 req.processor_id = proc_id;
1402 req.control_flags_set = control_flags_set;
1403 req.control_flags_clear = control_flags_clear;
1404
Andrew Davise0a676c2022-05-16 13:17:02 -05001405 ret = ti_sci_do_xfer(&xfer);
1406 if (ret != 0U) {
1407 ERROR("Transfer send failed (%d)\n", ret);
Andrew F. Davisa29578d2019-02-11 14:18:53 -06001408 return ret;
1409 }
1410
Andrew F. Davisa29578d2019-02-11 14:18:53 -06001411 return 0;
1412}
1413
1414/**
Andrew F. Davisd92fdfb2018-05-04 19:06:13 +00001415 * ti_sci_proc_auth_boot_image() - Authenticate and load image and then set the
1416 * processor configuration flags
1417 *
1418 * @proc_id: Processor ID this request is for
1419 * @cert_addr: Memory address at which payload image certificate is located
1420 *
1421 * Return: 0 if all goes well, else appropriate error message
1422 */
1423int ti_sci_proc_auth_boot_image(uint8_t proc_id, uint64_t cert_addr)
1424{
1425 struct ti_sci_msg_req_proc_auth_boot_image req;
1426 struct ti_sci_msg_hdr resp;
1427
1428 struct ti_sci_xfer xfer;
1429 int ret;
1430
Andrew Davisc39841f2023-01-10 12:34:20 -06001431 ret = ti_sci_setup_one_xfer(TISCI_MSG_PROC_AUTH_BOOT_IMAGE, 0,
Andrew F. Davisd92fdfb2018-05-04 19:06:13 +00001432 &req, sizeof(req),
1433 &resp, sizeof(resp),
1434 &xfer);
1435 if (ret) {
1436 ERROR("Message alloc failed (%d)\n", ret);
1437 return ret;
1438 }
1439
1440 req.processor_id = proc_id;
1441 req.cert_addr_low = cert_addr & TISCI_ADDR_LOW_MASK;
1442 req.cert_addr_high = (cert_addr & TISCI_ADDR_HIGH_MASK) >>
1443 TISCI_ADDR_HIGH_SHIFT;
1444
1445 ret = ti_sci_do_xfer(&xfer);
1446 if (ret) {
1447 ERROR("Transfer send failed (%d)\n", ret);
1448 return ret;
1449 }
1450
Andrew F. Davisd92fdfb2018-05-04 19:06:13 +00001451 return 0;
1452}
1453
1454/**
1455 * ti_sci_proc_get_boot_status() - Get the processor boot status
1456 *
1457 * @proc_id: Processor ID this request is for
1458 *
1459 * Return: 0 if all goes well, else appropriate error message
1460 */
1461int ti_sci_proc_get_boot_status(uint8_t proc_id, uint64_t *bv,
1462 uint32_t *cfg_flags,
1463 uint32_t *ctrl_flags,
1464 uint32_t *sts_flags)
1465{
1466 struct ti_sci_msg_req_get_proc_boot_status req;
1467 struct ti_sci_msg_resp_get_proc_boot_status resp;
1468
1469 struct ti_sci_xfer xfer;
1470 int ret;
1471
Andrew F. Davis06b30522019-02-11 13:44:31 -06001472 ret = ti_sci_setup_one_xfer(TISCI_MSG_GET_PROC_BOOT_STATUS, 0,
Andrew F. Davisd92fdfb2018-05-04 19:06:13 +00001473 &req, sizeof(req),
1474 &resp, sizeof(resp),
1475 &xfer);
1476 if (ret) {
1477 ERROR("Message alloc failed (%d)\n", ret);
1478 return ret;
1479 }
1480
1481 req.processor_id = proc_id;
1482
1483 ret = ti_sci_do_xfer(&xfer);
1484 if (ret) {
1485 ERROR("Transfer send failed (%d)\n", ret);
1486 return ret;
1487 }
1488
Andrew F. Davisd92fdfb2018-05-04 19:06:13 +00001489 *bv = (resp.bootvector_low & TISCI_ADDR_LOW_MASK) |
1490 (((uint64_t)resp.bootvector_high << TISCI_ADDR_HIGH_SHIFT) &
1491 TISCI_ADDR_HIGH_MASK);
1492 *cfg_flags = resp.config_flags;
1493 *ctrl_flags = resp.control_flags;
1494 *sts_flags = resp.status_flags;
1495
1496 return 0;
1497}
1498
1499/**
Andrew F. Davisb62cc1e2018-12-18 13:21:12 -06001500 * ti_sci_proc_wait_boot_status() - Wait for a processor boot status
1501 *
1502 * @proc_id: Processor ID this request is for
1503 * @num_wait_iterations Total number of iterations we will check before
1504 * we will timeout and give up
1505 * @num_match_iterations How many iterations should we have continued
1506 * status to account for status bits glitching.
1507 * This is to make sure that match occurs for
1508 * consecutive checks. This implies that the
1509 * worst case should consider that the stable
1510 * time should at the worst be num_wait_iterations
1511 * num_match_iterations to prevent timeout.
1512 * @delay_per_iteration_us Specifies how long to wait (in micro seconds)
1513 * between each status checks. This is the minimum
1514 * duration, and overhead of register reads and
1515 * checks are on top of this and can vary based on
1516 * varied conditions.
1517 * @delay_before_iterations_us Specifies how long to wait (in micro seconds)
1518 * before the very first check in the first
1519 * iteration of status check loop. This is the
1520 * minimum duration, and overhead of register
1521 * reads and checks are.
1522 * @status_flags_1_set_all_wait If non-zero, Specifies that all bits of the
1523 * status matching this field requested MUST be 1.
1524 * @status_flags_1_set_any_wait If non-zero, Specifies that at least one of the
1525 * bits matching this field requested MUST be 1.
1526 * @status_flags_1_clr_all_wait If non-zero, Specifies that all bits of the
1527 * status matching this field requested MUST be 0.
1528 * @status_flags_1_clr_any_wait If non-zero, Specifies that at least one of the
1529 * bits matching this field requested MUST be 0.
1530 *
1531 * Return: 0 if all goes well, else appropriate error message
1532 */
1533int ti_sci_proc_wait_boot_status(uint8_t proc_id, uint8_t num_wait_iterations,
1534 uint8_t num_match_iterations,
1535 uint8_t delay_per_iteration_us,
1536 uint8_t delay_before_iterations_us,
1537 uint32_t status_flags_1_set_all_wait,
1538 uint32_t status_flags_1_set_any_wait,
1539 uint32_t status_flags_1_clr_all_wait,
1540 uint32_t status_flags_1_clr_any_wait)
1541{
1542 struct ti_sci_msg_req_wait_proc_boot_status req;
1543 struct ti_sci_msg_hdr resp;
1544
1545 struct ti_sci_xfer xfer;
1546 int ret;
1547
Andrew F. Davis06b30522019-02-11 13:44:31 -06001548 ret = ti_sci_setup_one_xfer(TISCI_MSG_WAIT_PROC_BOOT_STATUS, 0,
Andrew F. Davisb62cc1e2018-12-18 13:21:12 -06001549 &req, sizeof(req),
1550 &resp, sizeof(resp),
1551 &xfer);
1552 if (ret) {
1553 ERROR("Message alloc failed (%d)\n", ret);
1554 return ret;
1555 }
1556
1557 req.processor_id = proc_id;
1558 req.num_wait_iterations = num_wait_iterations;
1559 req.num_match_iterations = num_match_iterations;
1560 req.delay_per_iteration_us = delay_per_iteration_us;
1561 req.delay_before_iterations_us = delay_before_iterations_us;
1562 req.status_flags_1_set_all_wait = status_flags_1_set_all_wait;
1563 req.status_flags_1_set_any_wait = status_flags_1_set_any_wait;
1564 req.status_flags_1_clr_all_wait = status_flags_1_clr_all_wait;
1565 req.status_flags_1_clr_any_wait = status_flags_1_clr_any_wait;
1566
1567 ret = ti_sci_do_xfer(&xfer);
1568 if (ret) {
1569 ERROR("Transfer send failed (%d)\n", ret);
1570 return ret;
1571 }
1572
Andrew F. Davisa29578d2019-02-11 14:18:53 -06001573 return 0;
1574}
1575
1576/**
1577 * ti_sci_proc_wait_boot_status_no_wait() - Wait for a processor boot status
1578 * without requesting or waiting for
1579 * a response.
1580 *
1581 * @proc_id: Processor ID this request is for
1582 * @num_wait_iterations Total number of iterations we will check before
1583 * we will timeout and give up
1584 * @num_match_iterations How many iterations should we have continued
1585 * status to account for status bits glitching.
1586 * This is to make sure that match occurs for
1587 * consecutive checks. This implies that the
1588 * worst case should consider that the stable
1589 * time should at the worst be num_wait_iterations
1590 * num_match_iterations to prevent timeout.
1591 * @delay_per_iteration_us Specifies how long to wait (in micro seconds)
1592 * between each status checks. This is the minimum
1593 * duration, and overhead of register reads and
1594 * checks are on top of this and can vary based on
1595 * varied conditions.
1596 * @delay_before_iterations_us Specifies how long to wait (in micro seconds)
1597 * before the very first check in the first
1598 * iteration of status check loop. This is the
1599 * minimum duration, and overhead of register
1600 * reads and checks are.
1601 * @status_flags_1_set_all_wait If non-zero, Specifies that all bits of the
1602 * status matching this field requested MUST be 1.
1603 * @status_flags_1_set_any_wait If non-zero, Specifies that at least one of the
1604 * bits matching this field requested MUST be 1.
1605 * @status_flags_1_clr_all_wait If non-zero, Specifies that all bits of the
1606 * status matching this field requested MUST be 0.
1607 * @status_flags_1_clr_any_wait If non-zero, Specifies that at least one of the
1608 * bits matching this field requested MUST be 0.
1609 *
1610 * Return: 0 if all goes well, else appropriate error message
1611 */
1612int ti_sci_proc_wait_boot_status_no_wait(uint8_t proc_id,
1613 uint8_t num_wait_iterations,
1614 uint8_t num_match_iterations,
1615 uint8_t delay_per_iteration_us,
1616 uint8_t delay_before_iterations_us,
1617 uint32_t status_flags_1_set_all_wait,
1618 uint32_t status_flags_1_set_any_wait,
1619 uint32_t status_flags_1_clr_all_wait,
1620 uint32_t status_flags_1_clr_any_wait)
1621{
1622 struct ti_sci_msg_req_wait_proc_boot_status req;
Andrew Davise0a676c2022-05-16 13:17:02 -05001623 struct ti_sci_xfer xfer;
Andrew F. Davisa29578d2019-02-11 14:18:53 -06001624 int ret;
1625
Andrew Davise0a676c2022-05-16 13:17:02 -05001626 ret = ti_sci_setup_one_xfer(TI_SCI_MSG_GET_DEVICE_STATE, 0,
1627 &req, sizeof(req),
1628 NULL, 0,
1629 &xfer);
1630 if (ret != 0U) {
1631 ERROR("Message alloc failed (%d)\n", ret);
1632 return ret;
1633 }
Andrew F. Davisa29578d2019-02-11 14:18:53 -06001634
1635 req.processor_id = proc_id;
1636 req.num_wait_iterations = num_wait_iterations;
1637 req.num_match_iterations = num_match_iterations;
1638 req.delay_per_iteration_us = delay_per_iteration_us;
1639 req.delay_before_iterations_us = delay_before_iterations_us;
1640 req.status_flags_1_set_all_wait = status_flags_1_set_all_wait;
1641 req.status_flags_1_set_any_wait = status_flags_1_set_any_wait;
1642 req.status_flags_1_clr_all_wait = status_flags_1_clr_all_wait;
1643 req.status_flags_1_clr_any_wait = status_flags_1_clr_any_wait;
1644
Andrew Davise0a676c2022-05-16 13:17:02 -05001645 ret = ti_sci_do_xfer(&xfer);
1646 if (ret != 0U) {
1647 ERROR("Transfer send failed (%d)\n", ret);
Andrew F. Davisa29578d2019-02-11 14:18:53 -06001648 return ret;
1649 }
1650
Andrew F. Davisb62cc1e2018-12-18 13:21:12 -06001651 return 0;
1652}
1653
1654/**
Dave Gerlach7a94ce82021-11-30 15:35:08 -06001655 * ti_sci_enter_sleep - Command to initiate system transition into suspend.
1656 *
1657 * @proc_id: Processor ID.
1658 * @mode: Low power mode to enter.
1659 * @core_resume_addr: Address that core should be
1660 * resumed from after low power transition.
1661 *
1662 * Return: 0 if all goes well, else appropriate error message
1663 */
1664int ti_sci_enter_sleep(uint8_t proc_id,
1665 uint8_t mode,
1666 uint64_t core_resume_addr)
1667{
1668 struct ti_sci_msg_req_enter_sleep req;
Andrew Davise0a676c2022-05-16 13:17:02 -05001669 struct ti_sci_xfer xfer;
Dave Gerlach7a94ce82021-11-30 15:35:08 -06001670 int ret;
1671
Andrew Davise0a676c2022-05-16 13:17:02 -05001672 ret = ti_sci_setup_one_xfer(TI_SCI_MSG_GET_DEVICE_STATE, 0,
1673 &req, sizeof(req),
1674 NULL, 0,
1675 &xfer);
1676 if (ret != 0U) {
1677 ERROR("Message alloc failed (%d)\n", ret);
1678 return ret;
Dave Gerlach7a94ce82021-11-30 15:35:08 -06001679 }
1680
Dave Gerlach7a94ce82021-11-30 15:35:08 -06001681 req.processor_id = proc_id;
1682 req.mode = mode;
1683 req.core_resume_lo = core_resume_addr & TISCI_ADDR_LOW_MASK;
1684 req.core_resume_hi = (core_resume_addr & TISCI_ADDR_HIGH_MASK) >>
1685 TISCI_ADDR_HIGH_SHIFT;
1686
Andrew Davise0a676c2022-05-16 13:17:02 -05001687 ret = ti_sci_do_xfer(&xfer);
1688 if (ret != 0U) {
1689 ERROR("Transfer send failed (%d)\n", ret);
Dave Gerlach7a94ce82021-11-30 15:35:08 -06001690 return ret;
1691 }
1692
Dave Gerlach7a94ce82021-11-30 15:35:08 -06001693 return 0;
1694}
1695
1696/**
Andrew F. Davisa513b2a2018-05-04 19:06:09 +00001697 * ti_sci_init() - Basic initialization
1698 *
1699 * Return: 0 if all goes well, else appropriate error message
1700 */
1701int ti_sci_init(void)
1702{
1703 struct ti_sci_msg_resp_version rev_info;
1704 int ret;
1705
1706 ret = ti_sci_get_revision(&rev_info);
1707 if (ret) {
1708 ERROR("Unable to communicate with control firmware (%d)\n", ret);
1709 return ret;
1710 }
1711
1712 INFO("SYSFW ABI: %d.%d (firmware rev 0x%04x '%s')\n",
1713 rev_info.abi_major, rev_info.abi_minor,
1714 rev_info.firmware_revision,
1715 rev_info.firmware_description);
1716
1717 return 0;
1718}