blob: 569e60c16f2f3ac61ebf5242a3f12baeef264c1e [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>
16
17#include <common/debug.h>
Andrew F. Davisa513b2a2018-05-04 19:06:09 +000018#include <sec_proxy.h>
19
20#include "ti_sci_protocol.h"
21#include "ti_sci.h"
22
Andrew F. Davise1bcbd42020-01-16 15:58:34 -060023#if USE_COHERENT_MEM
24__section("tzfw_coherent_mem")
25#endif
Andrew F. Davis5daafa12020-01-16 15:34:31 -060026static uint8_t message_sequence;
Andrew F. Davisa513b2a2018-05-04 19:06:09 +000027
28/**
29 * struct ti_sci_xfer - Structure representing a message flow
30 * @tx_message: Transmit message
31 * @rx_message: Receive message
32 */
33struct ti_sci_xfer {
34 struct k3_sec_proxy_msg tx_message;
35 struct k3_sec_proxy_msg rx_message;
36};
37
38/**
39 * ti_sci_setup_one_xfer() - Setup one message type
40 *
41 * @msg_type: Message type
42 * @msg_flags: Flag to set for the message
43 * @tx_buf: Buffer to be sent to mailbox channel
44 * @tx_message_size: transmit message size
45 * @rx_buf: Buffer to be received from mailbox channel
46 * @rx_message_size: receive message size
47 *
48 * Helper function which is used by various command functions that are
49 * exposed to clients of this driver for allocating a message traffic event.
50 *
51 * Return: 0 if all goes well, else appropriate error message
52 */
53static int ti_sci_setup_one_xfer(uint16_t msg_type, uint32_t msg_flags,
54 void *tx_buf,
55 size_t tx_message_size,
56 void *rx_buf,
57 size_t rx_message_size,
58 struct ti_sci_xfer *xfer)
59{
60 struct ti_sci_msg_hdr *hdr;
61
62 /* Ensure we have sane transfer sizes */
Andrew F. Davis5daafa12020-01-16 15:34:31 -060063 if (rx_message_size > TI_SCI_MAX_MESSAGE_SIZE ||
64 tx_message_size > TI_SCI_MAX_MESSAGE_SIZE ||
Andrew F. Davisa513b2a2018-05-04 19:06:09 +000065 rx_message_size < sizeof(*hdr) ||
66 tx_message_size < sizeof(*hdr))
67 return -ERANGE;
68
Andrew F. Davisa513b2a2018-05-04 19:06:09 +000069 hdr = (struct ti_sci_msg_hdr *)tx_buf;
Andrew F. Davis5daafa12020-01-16 15:34:31 -060070 hdr->seq = ++message_sequence;
Andrew F. Davisa513b2a2018-05-04 19:06:09 +000071 hdr->type = msg_type;
Andrew F. Davis5daafa12020-01-16 15:34:31 -060072 hdr->host = TI_SCI_HOST_ID;
Andrew F. Davis06b30522019-02-11 13:44:31 -060073 hdr->flags = msg_flags | TI_SCI_FLAG_REQ_ACK_ON_PROCESSED;
Andrew F. Davisa513b2a2018-05-04 19:06:09 +000074
75 xfer->tx_message.buf = tx_buf;
76 xfer->tx_message.len = tx_message_size;
77
78 xfer->rx_message.buf = rx_buf;
79 xfer->rx_message.len = rx_message_size;
80
81 return 0;
82}
83
84/**
85 * ti_sci_get_response() - Receive response from mailbox channel
86 *
87 * @xfer: Transfer to initiate and wait for response
88 * @chan: Channel to receive the response
89 *
90 * Return: 0 if all goes well, else appropriate error message
91 */
92static inline int ti_sci_get_response(struct ti_sci_xfer *xfer,
93 enum k3_sec_proxy_chan_id chan)
94{
95 struct k3_sec_proxy_msg *msg = &xfer->rx_message;
96 struct ti_sci_msg_hdr *hdr;
Andrew F. Davisdff11822019-04-10 12:40:12 -040097 unsigned int retry = 5;
Andrew F. Davisa513b2a2018-05-04 19:06:09 +000098 int ret;
99
Andrew F. Davisdff11822019-04-10 12:40:12 -0400100 for (; retry > 0; retry--) {
101 /* Receive the response */
102 ret = k3_sec_proxy_recv(chan, msg);
103 if (ret) {
104 ERROR("Message receive failed (%d)\n", ret);
105 return ret;
106 }
Andrew F. Davisa513b2a2018-05-04 19:06:09 +0000107
Andrew F. Davisdff11822019-04-10 12:40:12 -0400108 /* msg is updated by Secure Proxy driver */
109 hdr = (struct ti_sci_msg_hdr *)msg->buf;
Andrew F. Davisa513b2a2018-05-04 19:06:09 +0000110
Andrew F. Davisdff11822019-04-10 12:40:12 -0400111 /* Sanity check for message response */
Andrew F. Davis5daafa12020-01-16 15:34:31 -0600112 if (hdr->seq == message_sequence)
Andrew F. Davisdff11822019-04-10 12:40:12 -0400113 break;
114 else
115 WARN("Message with sequence ID %u is not expected\n", hdr->seq);
116 }
117 if (!retry) {
118 ERROR("Timed out waiting for message\n");
Andrew F. Davisa513b2a2018-05-04 19:06:09 +0000119 return -EINVAL;
120 }
121
Andrew F. Davis5daafa12020-01-16 15:34:31 -0600122 if (msg->len > TI_SCI_MAX_MESSAGE_SIZE) {
Andrew F. Davisa513b2a2018-05-04 19:06:09 +0000123 ERROR("Unable to handle %lu xfer (max %d)\n",
Andrew F. Davis5daafa12020-01-16 15:34:31 -0600124 msg->len, TI_SCI_MAX_MESSAGE_SIZE);
Andrew F. Davisa513b2a2018-05-04 19:06:09 +0000125 return -EINVAL;
126 }
127
Andrew F. Davis06b30522019-02-11 13:44:31 -0600128 if (!(hdr->flags & TI_SCI_FLAG_RESP_GENERIC_ACK))
129 return -ENODEV;
130
Andrew F. Davisa513b2a2018-05-04 19:06:09 +0000131 return 0;
132}
133
134/**
135 * ti_sci_do_xfer() - Do one transfer
136 *
137 * @xfer: Transfer to initiate and wait for response
138 *
139 * Return: 0 if all goes well, else appropriate error message
140 */
141static inline int ti_sci_do_xfer(struct ti_sci_xfer *xfer)
142{
143 struct k3_sec_proxy_msg *msg = &xfer->tx_message;
144 int ret;
145
Andrew F. Davis18d371d2019-01-04 12:49:16 -0600146 /* Clear any spurious messages in receive queue */
147 ret = k3_sec_proxy_clear_rx_thread(SP_RESPONSE);
148 if (ret) {
149 ERROR("Could not clear response queue (%d)\n", ret);
150 return ret;
151 }
152
Andrew F. Davisa513b2a2018-05-04 19:06:09 +0000153 /* Send the message */
154 ret = k3_sec_proxy_send(SP_HIGH_PRIORITY, msg);
155 if (ret) {
156 ERROR("Message sending failed (%d)\n", ret);
157 return ret;
158 }
159
Andrew F. Davis18d371d2019-01-04 12:49:16 -0600160 /* Get the response */
Andrew F. Davisa513b2a2018-05-04 19:06:09 +0000161 ret = ti_sci_get_response(xfer, SP_RESPONSE);
162 if (ret) {
163 ERROR("Failed to get response (%d)\n", ret);
164 return ret;
165 }
166
167 return 0;
168}
169
170/**
171 * ti_sci_get_revision() - Get the revision of the SCI entity
172 *
173 * Updates the SCI information in the internal data structure.
174 *
175 * Return: 0 if all goes well, else appropriate error message
176 */
177int ti_sci_get_revision(struct ti_sci_msg_resp_version *rev_info)
178{
179 struct ti_sci_msg_hdr hdr;
180 struct ti_sci_xfer xfer;
181 int ret;
182
183 ret = ti_sci_setup_one_xfer(TI_SCI_MSG_VERSION, 0x0,
184 &hdr, sizeof(hdr),
185 rev_info, sizeof(*rev_info),
186 &xfer);
187 if (ret) {
188 ERROR("Message alloc failed (%d)\n", ret);
189 return ret;
190 }
191
192 ret = ti_sci_do_xfer(&xfer);
193 if (ret) {
194 ERROR("Transfer send failed (%d)\n", ret);
195 return ret;
196 }
197
198 return 0;
199}
200
201/**
Andrew F. Davis4f2a0552018-05-04 19:06:10 +0000202 * ti_sci_device_set_state() - Set device state
203 *
204 * @id: Device identifier
205 * @flags: flags to setup for the device
206 * @state: State to move the device to
207 *
208 * Return: 0 if all goes well, else appropriate error message
209 */
Andrew F. Davis8335bc22019-02-11 12:55:25 -0600210static int ti_sci_device_set_state(uint32_t id, uint32_t flags, uint8_t state)
Andrew F. Davis4f2a0552018-05-04 19:06:10 +0000211{
212 struct ti_sci_msg_req_set_device_state req;
213 struct ti_sci_msg_hdr resp;
214
215 struct ti_sci_xfer xfer;
216 int ret;
217
Andrew F. Davis06b30522019-02-11 13:44:31 -0600218 ret = ti_sci_setup_one_xfer(TI_SCI_MSG_SET_DEVICE_STATE, flags,
Andrew F. Davis4f2a0552018-05-04 19:06:10 +0000219 &req, sizeof(req),
220 &resp, sizeof(resp),
221 &xfer);
222 if (ret) {
223 ERROR("Message alloc failed (%d)\n", ret);
224 return ret;
225 }
226
227 req.id = id;
228 req.state = state;
229
230 ret = ti_sci_do_xfer(&xfer);
231 if (ret) {
232 ERROR("Transfer send failed (%d)\n", ret);
233 return ret;
234 }
235
Andrew F. Davis4f2a0552018-05-04 19:06:10 +0000236 return 0;
237}
238
239/**
240 * ti_sci_device_get_state() - Get device state
241 *
242 * @id: Device Identifier
243 * @clcnt: Pointer to Context Loss Count
244 * @resets: pointer to resets
245 * @p_state: pointer to p_state
246 * @c_state: pointer to c_state
247 *
248 * Return: 0 if all goes well, else appropriate error message
249 */
Andrew F. Davis8335bc22019-02-11 12:55:25 -0600250static int ti_sci_device_get_state(uint32_t id, uint32_t *clcnt,
251 uint32_t *resets, uint8_t *p_state,
252 uint8_t *c_state)
Andrew F. Davis4f2a0552018-05-04 19:06:10 +0000253{
254 struct ti_sci_msg_req_get_device_state req;
255 struct ti_sci_msg_resp_get_device_state resp;
256
257 struct ti_sci_xfer xfer;
258 int ret;
259
260 if (!clcnt && !resets && !p_state && !c_state)
261 return -EINVAL;
262
263 ret = ti_sci_setup_one_xfer(TI_SCI_MSG_GET_DEVICE_STATE, 0,
264 &req, sizeof(req),
265 &resp, sizeof(resp),
266 &xfer);
267 if (ret) {
268 ERROR("Message alloc failed (%d)\n", ret);
269 return ret;
270 }
271
272 req.id = id;
273
274 ret = ti_sci_do_xfer(&xfer);
275 if (ret) {
276 ERROR("Transfer send failed (%d)\n", ret);
277 return ret;
278 }
279
Andrew F. Davis4f2a0552018-05-04 19:06:10 +0000280 if (clcnt)
281 *clcnt = resp.context_loss_count;
282 if (resets)
283 *resets = resp.resets;
284 if (p_state)
285 *p_state = resp.programmed_state;
286 if (c_state)
287 *c_state = resp.current_state;
288
289 return 0;
290}
291
292/**
293 * ti_sci_device_get() - Request for device managed by TISCI
294 *
295 * @id: Device Identifier
296 *
297 * Request for the device - NOTE: the client MUST maintain integrity of
298 * usage count by balancing get_device with put_device. No refcounting is
299 * managed by driver for that purpose.
300 *
Andrew F. Davis4f2a0552018-05-04 19:06:10 +0000301 * Return: 0 if all goes well, else appropriate error message
302 */
303int ti_sci_device_get(uint32_t id)
304{
Andrew F. Davisfbe6c062019-02-11 12:58:32 -0600305 return ti_sci_device_set_state(id, 0, MSG_DEVICE_SW_STATE_ON);
306}
307
308/**
309 * ti_sci_device_get_exclusive() - Exclusive request for device managed by TISCI
310 *
311 * @id: Device Identifier
312 *
313 * Request for the device - NOTE: the client MUST maintain integrity of
314 * usage count by balancing get_device with put_device. No refcounting is
315 * managed by driver for that purpose.
316 *
317 * NOTE: This _exclusive version of the get API is for exclusive access to the
318 * device. Any other host in the system will fail to get this device after this
319 * call until exclusive access is released with device_put or a non-exclusive
320 * set call.
321 *
322 * Return: 0 if all goes well, else appropriate error message
323 */
324int ti_sci_device_get_exclusive(uint32_t id)
325{
Andrew F. Davis4f2a0552018-05-04 19:06:10 +0000326 return ti_sci_device_set_state(id,
327 MSG_FLAG_DEVICE_EXCLUSIVE,
328 MSG_DEVICE_SW_STATE_ON);
329}
330
331/**
332 * ti_sci_device_idle() - Idle a device managed by TISCI
333 *
334 * @id: Device Identifier
335 *
336 * Request for the device - NOTE: the client MUST maintain integrity of
337 * usage count by balancing get_device with put_device. No refcounting is
338 * managed by driver for that purpose.
339 *
340 * Return: 0 if all goes well, else appropriate error message
341 */
342int ti_sci_device_idle(uint32_t id)
343{
Andrew F. Davisfbe6c062019-02-11 12:58:32 -0600344 return ti_sci_device_set_state(id, 0, MSG_DEVICE_SW_STATE_RETENTION);
345}
346
347/**
348 * ti_sci_device_idle_exclusive() - Exclusive idle a device managed by TISCI
349 *
350 * @id: Device Identifier
351 *
352 * Request for the device - NOTE: the client MUST maintain integrity of
353 * usage count by balancing get_device with put_device. No refcounting is
354 * managed by driver for that purpose.
355 *
356 * NOTE: This _exclusive version of the idle API is for exclusive access to
357 * the device. Any other host in the system will fail to get this device after
358 * this call until exclusive access is released with device_put or a
359 * non-exclusive set call.
360 *
361 * Return: 0 if all goes well, else appropriate error message
362 */
363int ti_sci_device_idle_exclusive(uint32_t id)
364{
Andrew F. Davis4f2a0552018-05-04 19:06:10 +0000365 return ti_sci_device_set_state(id,
366 MSG_FLAG_DEVICE_EXCLUSIVE,
367 MSG_DEVICE_SW_STATE_RETENTION);
368}
369
370/**
371 * ti_sci_device_put() - Release a device managed by TISCI
372 *
373 * @id: Device Identifier
374 *
375 * Request for the device - NOTE: the client MUST maintain integrity of
376 * usage count by balancing get_device with put_device. No refcounting is
377 * managed by driver for that purpose.
378 *
379 * Return: 0 if all goes well, else appropriate error message
380 */
381int ti_sci_device_put(uint32_t id)
382{
383 return ti_sci_device_set_state(id, 0, MSG_DEVICE_SW_STATE_AUTO_OFF);
384}
385
386/**
Andrew F. Davisa29578d2019-02-11 14:18:53 -0600387 * ti_sci_device_put_no_wait() - Release a device without requesting or waiting
388 * for a response.
389 *
390 * @id: Device Identifier
391 *
392 * Request for the device - NOTE: the client MUST maintain integrity of
393 * usage count by balancing get_device with put_device. No refcounting is
394 * managed by driver for that purpose.
395 *
396 * Return: 0 if all goes well, else appropriate error message
397 */
398int ti_sci_device_put_no_wait(uint32_t id)
399{
400 struct ti_sci_msg_req_set_device_state req;
401 struct ti_sci_msg_hdr *hdr;
402 struct k3_sec_proxy_msg tx_message;
403 int ret;
404
405 /* Ensure we have sane transfer size */
Andrew F. Davis5daafa12020-01-16 15:34:31 -0600406 if (sizeof(req) > TI_SCI_MAX_MESSAGE_SIZE)
Andrew F. Davisa29578d2019-02-11 14:18:53 -0600407 return -ERANGE;
408
409 hdr = (struct ti_sci_msg_hdr *)&req;
Andrew F. Davis5daafa12020-01-16 15:34:31 -0600410 hdr->seq = ++message_sequence;
Andrew F. Davisa29578d2019-02-11 14:18:53 -0600411 hdr->type = TI_SCI_MSG_SET_DEVICE_STATE;
Andrew F. Davis5daafa12020-01-16 15:34:31 -0600412 hdr->host = TI_SCI_HOST_ID;
Andrew F. Davisa29578d2019-02-11 14:18:53 -0600413 /* Setup with NORESPONSE flag to keep response queue clean */
414 hdr->flags = TI_SCI_FLAG_REQ_GENERIC_NORESPONSE;
415
416 req.id = id;
417 req.state = MSG_DEVICE_SW_STATE_AUTO_OFF;
418
419 tx_message.buf = (uint8_t *)&req;
420 tx_message.len = sizeof(req);
421
422 /* Send message */
423 ret = k3_sec_proxy_send(SP_HIGH_PRIORITY, &tx_message);
424 if (ret) {
425 ERROR("Message sending failed (%d)\n", ret);
426 return ret;
427 }
428
429 /* Return without waiting for response */
430 return 0;
431}
432
433/**
Andrew F. Davis4f2a0552018-05-04 19:06:10 +0000434 * ti_sci_device_is_valid() - Is the device valid
435 *
436 * @id: Device Identifier
437 *
438 * Return: 0 if all goes well and the device ID is valid, else return
439 * appropriate error
440 */
441int ti_sci_device_is_valid(uint32_t id)
442{
443 uint8_t unused;
444
445 /* check the device state which will also tell us if the ID is valid */
446 return ti_sci_device_get_state(id, NULL, NULL, NULL, &unused);
447}
448
449/**
450 * ti_sci_device_get_clcnt() - Get context loss counter
451 *
452 * @id: Device Identifier
453 * @count: Pointer to Context Loss counter to populate
454 *
455 * Return: 0 if all goes well, else appropriate error message
456 */
457int ti_sci_device_get_clcnt(uint32_t id, uint32_t *count)
458{
459 return ti_sci_device_get_state(id, count, NULL, NULL, NULL);
460}
461
462/**
463 * ti_sci_device_is_idle() - Check if the device is requested to be idle
464 *
465 * @id: Device Identifier
466 * @r_state: true if requested to be idle
467 *
468 * Return: 0 if all goes well, else appropriate error message
469 */
470int ti_sci_device_is_idle(uint32_t id, bool *r_state)
471{
472 int ret;
473 uint8_t state;
474
475 if (!r_state)
476 return -EINVAL;
477
478 ret = ti_sci_device_get_state(id, NULL, NULL, &state, NULL);
479 if (ret)
480 return ret;
481
482 *r_state = (state == MSG_DEVICE_SW_STATE_RETENTION);
483
484 return 0;
485}
486
487/**
488 * ti_sci_device_is_stop() - Check if the device is requested to be stopped
489 *
490 * @id: Device Identifier
491 * @r_state: true if requested to be stopped
492 * @curr_state: true if currently stopped
493 *
494 * Return: 0 if all goes well, else appropriate error message
495 */
496int ti_sci_device_is_stop(uint32_t id, bool *r_state, bool *curr_state)
497{
498 int ret;
499 uint8_t p_state, c_state;
500
501 if (!r_state && !curr_state)
502 return -EINVAL;
503
504 ret = ti_sci_device_get_state(id, NULL, NULL, &p_state, &c_state);
505 if (ret)
506 return ret;
507
508 if (r_state)
509 *r_state = (p_state == MSG_DEVICE_SW_STATE_AUTO_OFF);
510 if (curr_state)
511 *curr_state = (c_state == MSG_DEVICE_HW_STATE_OFF);
512
513 return 0;
514}
515
516/**
517 * ti_sci_device_is_on() - Check if the device is requested to be ON
518 *
519 * @id: Device Identifier
520 * @r_state: true if requested to be ON
521 * @curr_state: true if currently ON and active
522 *
523 * Return: 0 if all goes well, else appropriate error message
524 */
525int ti_sci_device_is_on(uint32_t id, bool *r_state, bool *curr_state)
526{
527 int ret;
528 uint8_t p_state, c_state;
529
530 if (!r_state && !curr_state)
531 return -EINVAL;
532
533 ret =
534 ti_sci_device_get_state(id, NULL, NULL, &p_state, &c_state);
535 if (ret)
536 return ret;
537
538 if (r_state)
539 *r_state = (p_state == MSG_DEVICE_SW_STATE_ON);
540 if (curr_state)
541 *curr_state = (c_state == MSG_DEVICE_HW_STATE_ON);
542
543 return 0;
544}
545
546/**
547 * ti_sci_device_is_trans() - Check if the device is currently transitioning
548 *
549 * @id: Device Identifier
550 * @curr_state: true if currently transitioning
551 *
552 * Return: 0 if all goes well, else appropriate error message
553 */
554int ti_sci_device_is_trans(uint32_t id, bool *curr_state)
555{
556 int ret;
557 uint8_t state;
558
559 if (!curr_state)
560 return -EINVAL;
561
562 ret = ti_sci_device_get_state(id, NULL, NULL, NULL, &state);
563 if (ret)
564 return ret;
565
566 *curr_state = (state == MSG_DEVICE_HW_STATE_TRANS);
567
568 return 0;
569}
570
571/**
572 * ti_sci_device_set_resets() - Set resets for device managed by TISCI
573 *
574 * @id: Device Identifier
575 * @reset_state: Device specific reset bit field
576 *
577 * Return: 0 if all goes well, else appropriate error message
578 */
579int ti_sci_device_set_resets(uint32_t id, uint32_t reset_state)
580{
581 struct ti_sci_msg_req_set_device_resets req;
582 struct ti_sci_msg_hdr resp;
583
584 struct ti_sci_xfer xfer;
585 int ret;
586
Andrew F. Davis06b30522019-02-11 13:44:31 -0600587 ret = ti_sci_setup_one_xfer(TI_SCI_MSG_SET_DEVICE_RESETS, 0,
Andrew F. Davis4f2a0552018-05-04 19:06:10 +0000588 &req, sizeof(req),
589 &resp, sizeof(resp),
590 &xfer);
591 if (ret) {
592 ERROR("Message alloc failed (%d)\n", ret);
593 return ret;
594 }
595
596 req.id = id;
597 req.resets = reset_state;
598
599 ret = ti_sci_do_xfer(&xfer);
600 if (ret) {
601 ERROR("Transfer send failed (%d)\n", ret);
602 return ret;
603 }
604
Andrew F. Davis4f2a0552018-05-04 19:06:10 +0000605 return 0;
606}
607
608/**
609 * ti_sci_device_get_resets() - Get reset state for device managed by TISCI
610 *
611 * @id: Device Identifier
612 * @reset_state: Pointer to reset state to populate
613 *
614 * Return: 0 if all goes well, else appropriate error message
615 */
616int ti_sci_device_get_resets(uint32_t id, uint32_t *reset_state)
617{
618 return ti_sci_device_get_state(id, NULL, reset_state, NULL, NULL);
619}
620
621/**
Andrew F. Davisdc08adf2018-05-04 19:06:11 +0000622 * ti_sci_clock_set_state() - Set clock state helper
623 *
624 * @dev_id: Device identifier this request is for
625 * @clk_id: Clock identifier for the device for this request,
626 * Each device has its own set of clock inputs, This indexes
627 * which clock input to modify
628 * @flags: Header flags as needed
629 * @state: State to request for the clock
630 *
631 * Return: 0 if all goes well, else appropriate error message
632 */
633int ti_sci_clock_set_state(uint32_t dev_id, uint8_t clk_id,
634 uint32_t flags, uint8_t state)
635{
636 struct ti_sci_msg_req_set_clock_state req;
637 struct ti_sci_msg_hdr resp;
638
639 struct ti_sci_xfer xfer;
640 int ret;
641
Andrew F. Davis06b30522019-02-11 13:44:31 -0600642 ret = ti_sci_setup_one_xfer(TI_SCI_MSG_SET_CLOCK_STATE, flags,
Andrew F. Davisdc08adf2018-05-04 19:06:11 +0000643 &req, sizeof(req),
644 &resp, sizeof(resp),
645 &xfer);
646 if (ret) {
647 ERROR("Message alloc failed (%d)\n", ret);
648 return ret;
649 }
650
651 req.dev_id = dev_id;
652 req.clk_id = clk_id;
653 req.request_state = state;
654
655 ret = ti_sci_do_xfer(&xfer);
656 if (ret) {
657 ERROR("Transfer send failed (%d)\n", ret);
658 return ret;
659 }
660
Andrew F. Davisdc08adf2018-05-04 19:06:11 +0000661 return 0;
662}
663
664/**
665 * ti_sci_clock_get_state() - Get clock state helper
666 *
667 * @dev_id: Device identifier this request is for
668 * @clk_id: Clock identifier for the device for this request.
669 * Each device has its own set of clock inputs. This indexes
670 * which clock input to modify.
671 * @programmed_state: State requested for clock to move to
672 * @current_state: State that the clock is currently in
673 *
674 * Return: 0 if all goes well, else appropriate error message
675 */
676int ti_sci_clock_get_state(uint32_t dev_id, uint8_t clk_id,
677 uint8_t *programmed_state,
678 uint8_t *current_state)
679{
680 struct ti_sci_msg_req_get_clock_state req;
681 struct ti_sci_msg_resp_get_clock_state resp;
682
683 struct ti_sci_xfer xfer;
684 int ret;
685
686 if (!programmed_state && !current_state)
687 return -EINVAL;
688
Andrew F. Davis06b30522019-02-11 13:44:31 -0600689 ret = ti_sci_setup_one_xfer(TI_SCI_MSG_GET_CLOCK_STATE, 0,
Andrew F. Davisdc08adf2018-05-04 19:06:11 +0000690 &req, sizeof(req),
691 &resp, sizeof(resp),
692 &xfer);
693 if (ret) {
694 ERROR("Message alloc failed (%d)\n", ret);
695 return ret;
696 }
697
698 req.dev_id = dev_id;
699 req.clk_id = clk_id;
700
701 ret = ti_sci_do_xfer(&xfer);
702 if (ret) {
703 ERROR("Transfer send failed (%d)\n", ret);
704 return ret;
705 }
706
Andrew F. Davisdc08adf2018-05-04 19:06:11 +0000707 if (programmed_state)
708 *programmed_state = resp.programmed_state;
709 if (current_state)
710 *current_state = resp.current_state;
711
712 return 0;
713}
714
715/**
716 * ti_sci_clock_get() - Get control of a clock from TI SCI
717
718 * @dev_id: Device identifier this request is for
719 * @clk_id: Clock identifier for the device for this request.
720 * Each device has its own set of clock inputs. This indexes
721 * which clock input to modify.
722 * @needs_ssc: 'true' iff Spread Spectrum clock is desired
723 * @can_change_freq: 'true' iff frequency change is desired
724 * @enable_input_term: 'true' iff input termination is desired
725 *
726 * Return: 0 if all goes well, else appropriate error message
727 */
728int ti_sci_clock_get(uint32_t dev_id, uint8_t clk_id,
729 bool needs_ssc, bool can_change_freq,
730 bool enable_input_term)
731{
732 uint32_t flags = 0;
733
734 flags |= needs_ssc ? MSG_FLAG_CLOCK_ALLOW_SSC : 0;
735 flags |= can_change_freq ? MSG_FLAG_CLOCK_ALLOW_FREQ_CHANGE : 0;
736 flags |= enable_input_term ? MSG_FLAG_CLOCK_INPUT_TERM : 0;
737
738 return ti_sci_clock_set_state(dev_id, clk_id, flags,
739 MSG_CLOCK_SW_STATE_REQ);
740}
741
742/**
743 * ti_sci_clock_idle() - Idle a clock which is in our control
744
745 * @dev_id: Device identifier this request is for
746 * @clk_id: Clock identifier for the device for this request.
747 * Each device has its own set of clock inputs. This indexes
748 * which clock input to modify.
749 *
750 * NOTE: This clock must have been requested by get_clock previously.
751 *
752 * Return: 0 if all goes well, else appropriate error message
753 */
754int ti_sci_clock_idle(uint32_t dev_id, uint8_t clk_id)
755{
756 return ti_sci_clock_set_state(dev_id, clk_id, 0,
757 MSG_CLOCK_SW_STATE_UNREQ);
758}
759
760/**
761 * ti_sci_clock_put() - Release a clock from our control
762 *
763 * @dev_id: Device identifier this request is for
764 * @clk_id: Clock identifier for the device for this request.
765 * Each device has its own set of clock inputs. This indexes
766 * which clock input to modify.
767 *
768 * NOTE: This clock must have been requested by get_clock previously.
769 *
770 * Return: 0 if all goes well, else appropriate error message
771 */
772int ti_sci_clock_put(uint32_t dev_id, uint8_t clk_id)
773{
774 return ti_sci_clock_set_state(dev_id, clk_id, 0,
775 MSG_CLOCK_SW_STATE_AUTO);
776}
777
778/**
779 * ti_sci_clock_is_auto() - Is the clock being auto managed
780 *
781 * @dev_id: Device identifier this request is for
782 * @clk_id: Clock identifier for the device for this request.
783 * Each device has its own set of clock inputs. This indexes
784 * which clock input to modify.
785 * @req_state: state indicating if the clock is auto managed
786 *
787 * Return: 0 if all goes well, else appropriate error message
788 */
789int ti_sci_clock_is_auto(uint32_t dev_id, uint8_t clk_id, bool *req_state)
790{
791 uint8_t state = 0;
792 int ret;
793
794 if (!req_state)
795 return -EINVAL;
796
797 ret = ti_sci_clock_get_state(dev_id, clk_id, &state, NULL);
798 if (ret)
799 return ret;
800
801 *req_state = (state == MSG_CLOCK_SW_STATE_AUTO);
802
803 return 0;
804}
805
806/**
807 * ti_sci_clock_is_on() - Is the clock ON
808 *
809 * @dev_id: Device identifier this request is for
810 * @clk_id: Clock identifier for the device for this request.
811 * Each device has its own set of clock inputs. This indexes
812 * which clock input to modify.
813 * @req_state: state indicating if the clock is managed by us and enabled
814 * @curr_state: state indicating if the clock is ready for operation
815 *
816 * Return: 0 if all goes well, else appropriate error message
817 */
818int ti_sci_clock_is_on(uint32_t dev_id, uint8_t clk_id,
819 bool *req_state, bool *curr_state)
820{
821 uint8_t c_state = 0, r_state = 0;
822 int ret;
823
824 if (!req_state && !curr_state)
825 return -EINVAL;
826
827 ret = ti_sci_clock_get_state(dev_id, clk_id, &r_state, &c_state);
828 if (ret)
829 return ret;
830
831 if (req_state)
832 *req_state = (r_state == MSG_CLOCK_SW_STATE_REQ);
833 if (curr_state)
834 *curr_state = (c_state == MSG_CLOCK_HW_STATE_READY);
835
836 return 0;
837}
838
839/**
840 * ti_sci_clock_is_off() - Is the clock OFF
841 *
842 * @dev_id: Device identifier this request is for
843 * @clk_id: Clock identifier for the device for this request.
844 * Each device has its own set of clock inputs. This indexes
845 * which clock input to modify.
846 * @req_state: state indicating if the clock is managed by us and disabled
847 * @curr_state: state indicating if the clock is NOT ready for operation
848 *
849 * Return: 0 if all goes well, else appropriate error message
850 */
851int ti_sci_clock_is_off(uint32_t dev_id, uint8_t clk_id,
852 bool *req_state, bool *curr_state)
853{
854 uint8_t c_state = 0, r_state = 0;
855 int ret;
856
857 if (!req_state && !curr_state)
858 return -EINVAL;
859
860 ret = ti_sci_clock_get_state(dev_id, clk_id, &r_state, &c_state);
861 if (ret)
862 return ret;
863
864 if (req_state)
865 *req_state = (r_state == MSG_CLOCK_SW_STATE_UNREQ);
866 if (curr_state)
867 *curr_state = (c_state == MSG_CLOCK_HW_STATE_NOT_READY);
868
869 return 0;
870}
871
872/**
873 * ti_sci_clock_set_parent() - Set the clock source of a specific device clock
874 *
875 * @dev_id: Device identifier this request is for
876 * @clk_id: Clock identifier for the device for this request.
877 * Each device has its own set of clock inputs. This indexes
878 * which clock input to modify.
879 * @parent_id: Parent clock identifier to set
880 *
881 * Return: 0 if all goes well, else appropriate error message
882 */
883int ti_sci_clock_set_parent(uint32_t dev_id, uint8_t clk_id, uint8_t parent_id)
884{
885 struct ti_sci_msg_req_set_clock_parent req;
886 struct ti_sci_msg_hdr resp;
887
888 struct ti_sci_xfer xfer;
889 int ret;
890
Andrew F. Davis06b30522019-02-11 13:44:31 -0600891 ret = ti_sci_setup_one_xfer(TI_SCI_MSG_SET_CLOCK_PARENT, 0,
Andrew F. Davisdc08adf2018-05-04 19:06:11 +0000892 &req, sizeof(req),
893 &resp, sizeof(resp),
894 &xfer);
895 if (ret) {
896 ERROR("Message alloc failed (%d)\n", ret);
897 return ret;
898 }
899
900 req.dev_id = dev_id;
901 req.clk_id = clk_id;
902 req.parent_id = parent_id;
903
904 ret = ti_sci_do_xfer(&xfer);
905 if (ret) {
906 ERROR("Transfer send failed (%d)\n", ret);
907 return ret;
908 }
909
Andrew F. Davisdc08adf2018-05-04 19:06:11 +0000910 return 0;
911}
912
913/**
914 * ti_sci_clock_get_parent() - Get current parent clock source
915 *
916 * @dev_id: Device identifier this request is for
917 * @clk_id: Clock identifier for the device for this request.
918 * Each device has its own set of clock inputs. This indexes
919 * which clock input to modify.
920 * @parent_id: Current clock parent
921 *
922 * Return: 0 if all goes well, else appropriate error message
923 */
924int ti_sci_clock_get_parent(uint32_t dev_id, uint8_t clk_id, uint8_t *parent_id)
925{
926 struct ti_sci_msg_req_get_clock_parent req;
927 struct ti_sci_msg_resp_get_clock_parent resp;
928
929 struct ti_sci_xfer xfer;
930 int ret;
931
Andrew F. Davis06b30522019-02-11 13:44:31 -0600932 ret = ti_sci_setup_one_xfer(TI_SCI_MSG_GET_CLOCK_PARENT, 0,
Andrew F. Davisdc08adf2018-05-04 19:06:11 +0000933 &req, sizeof(req),
934 &resp, sizeof(resp),
935 &xfer);
936 if (ret) {
937 ERROR("Message alloc failed (%d)\n", ret);
938 return ret;
939 }
940
941 req.dev_id = dev_id;
942 req.clk_id = clk_id;
943
944 ret = ti_sci_do_xfer(&xfer);
945 if (ret) {
946 ERROR("Transfer send failed (%d)\n", ret);
947 return ret;
948 }
949
Andrew F. Davisdc08adf2018-05-04 19:06:11 +0000950 *parent_id = resp.parent_id;
951
952 return 0;
953}
954
955/**
956 * ti_sci_clock_get_num_parents() - Get num parents of the current clk source
957 *
958 * @dev_id: Device identifier this request is for
959 * @clk_id: Clock identifier for the device for this request.
960 * Each device has its own set of clock inputs. This indexes
961 * which clock input to modify.
962 * @num_parents: Returns he number of parents to the current clock.
963 *
964 * Return: 0 if all goes well, else appropriate error message
965 */
966int ti_sci_clock_get_num_parents(uint32_t dev_id, uint8_t clk_id,
967 uint8_t *num_parents)
968{
969 struct ti_sci_msg_req_get_clock_num_parents req;
970 struct ti_sci_msg_resp_get_clock_num_parents resp;
971
972 struct ti_sci_xfer xfer;
973 int ret;
974
Andrew F. Davis06b30522019-02-11 13:44:31 -0600975 ret = ti_sci_setup_one_xfer(TI_SCI_MSG_GET_NUM_CLOCK_PARENTS, 0,
Andrew F. Davisdc08adf2018-05-04 19:06:11 +0000976 &req, sizeof(req),
977 &resp, sizeof(resp),
978 &xfer);
979 if (ret) {
980 ERROR("Message alloc failed (%d)\n", ret);
981 return ret;
982 }
983
984 req.dev_id = dev_id;
985 req.clk_id = clk_id;
986
987 ret = ti_sci_do_xfer(&xfer);
988 if (ret) {
989 ERROR("Transfer send failed (%d)\n", ret);
990 return ret;
991 }
992
Andrew F. Davisdc08adf2018-05-04 19:06:11 +0000993 *num_parents = resp.num_parents;
994
995 return 0;
996}
997
998/**
999 * ti_sci_clock_get_match_freq() - Find a good match for frequency
1000 *
1001 * @dev_id: Device identifier this request is for
1002 * @clk_id: Clock identifier for the device for this request.
1003 * Each device has its own set of clock inputs. This indexes
1004 * which clock input to modify.
1005 * @min_freq: The minimum allowable frequency in Hz. This is the minimum
1006 * allowable programmed frequency and does not account for clock
1007 * tolerances and jitter.
1008 * @target_freq: The target clock frequency in Hz. A frequency will be
1009 * processed as close to this target frequency as possible.
1010 * @max_freq: The maximum allowable frequency in Hz. This is the maximum
1011 * allowable programmed frequency and does not account for clock
1012 * tolerances and jitter.
1013 * @match_freq: Frequency match in Hz response.
1014 *
1015 * Return: 0 if all goes well, else appropriate error message
1016 */
1017int ti_sci_clock_get_match_freq(uint32_t dev_id, uint8_t clk_id,
1018 uint64_t min_freq, uint64_t target_freq,
1019 uint64_t max_freq, uint64_t *match_freq)
1020{
1021 struct ti_sci_msg_req_query_clock_freq req;
1022 struct ti_sci_msg_resp_query_clock_freq resp;
1023
1024 struct ti_sci_xfer xfer;
1025 int ret;
1026
Andrew F. Davis06b30522019-02-11 13:44:31 -06001027 ret = ti_sci_setup_one_xfer(TI_SCI_MSG_QUERY_CLOCK_FREQ, 0,
Andrew F. Davisdc08adf2018-05-04 19:06:11 +00001028 &req, sizeof(req),
1029 &resp, sizeof(resp),
1030 &xfer);
1031 if (ret) {
1032 ERROR("Message alloc failed (%d)\n", ret);
1033 return ret;
1034 }
1035
1036 req.dev_id = dev_id;
1037 req.clk_id = clk_id;
1038 req.min_freq_hz = min_freq;
1039 req.target_freq_hz = target_freq;
1040 req.max_freq_hz = max_freq;
1041
1042 ret = ti_sci_do_xfer(&xfer);
1043 if (ret) {
1044 ERROR("Transfer send failed (%d)\n", ret);
1045 return ret;
1046 }
1047
Andrew F. Davisdc08adf2018-05-04 19:06:11 +00001048 *match_freq = resp.freq_hz;
1049
1050 return 0;
1051}
1052
1053/**
1054 * ti_sci_clock_set_freq() - Set a frequency for clock
1055 *
1056 * @dev_id: Device identifier this request is for
1057 * @clk_id: Clock identifier for the device for this request.
1058 * Each device has its own set of clock inputs. This indexes
1059 * which clock input to modify.
1060 * @min_freq: The minimum allowable frequency in Hz. This is the minimum
1061 * allowable programmed frequency and does not account for clock
1062 * tolerances and jitter.
1063 * @target_freq: The target clock frequency in Hz. A frequency will be
1064 * processed as close to this target frequency as possible.
1065 * @max_freq: The maximum allowable frequency in Hz. This is the maximum
1066 * allowable programmed frequency and does not account for clock
1067 * tolerances and jitter.
1068 *
1069 * Return: 0 if all goes well, else appropriate error message
1070 */
1071int ti_sci_clock_set_freq(uint32_t dev_id, uint8_t clk_id, uint64_t min_freq,
1072 uint64_t target_freq, uint64_t max_freq)
1073{
1074 struct ti_sci_msg_req_set_clock_freq req;
1075 struct ti_sci_msg_hdr resp;
1076
1077 struct ti_sci_xfer xfer;
1078 int ret;
1079
Andrew F. Davis06b30522019-02-11 13:44:31 -06001080 ret = ti_sci_setup_one_xfer(TI_SCI_MSG_SET_CLOCK_FREQ, 0,
Andrew F. Davisdc08adf2018-05-04 19:06:11 +00001081 &req, sizeof(req),
1082 &resp, sizeof(resp),
1083 &xfer);
1084 if (ret) {
1085 ERROR("Message alloc failed (%d)\n", ret);
1086 return ret;
1087 }
1088 req.dev_id = dev_id;
1089 req.clk_id = clk_id;
1090 req.min_freq_hz = min_freq;
1091 req.target_freq_hz = target_freq;
1092 req.max_freq_hz = max_freq;
1093
1094 ret = ti_sci_do_xfer(&xfer);
1095 if (ret) {
1096 ERROR("Transfer send failed (%d)\n", ret);
1097 return ret;
1098 }
1099
Andrew F. Davisdc08adf2018-05-04 19:06:11 +00001100 return 0;
1101}
1102
1103/**
1104 * ti_sci_clock_get_freq() - Get current frequency
1105 *
1106 * @dev_id: Device identifier this request is for
1107 * @clk_id: Clock identifier for the device for this request.
1108 * Each device has its own set of clock inputs. This indexes
1109 * which clock input to modify.
1110 * @freq: Currently frequency in Hz
1111 *
1112 * Return: 0 if all goes well, else appropriate error message
1113 */
1114int ti_sci_clock_get_freq(uint32_t dev_id, uint8_t clk_id, uint64_t *freq)
1115{
1116 struct ti_sci_msg_req_get_clock_freq req;
1117 struct ti_sci_msg_resp_get_clock_freq resp;
1118
1119 struct ti_sci_xfer xfer;
1120 int ret;
1121
Andrew F. Davis06b30522019-02-11 13:44:31 -06001122 ret = ti_sci_setup_one_xfer(TI_SCI_MSG_GET_CLOCK_FREQ, 0,
Andrew F. Davisdc08adf2018-05-04 19:06:11 +00001123 &req, sizeof(req),
1124 &resp, sizeof(resp),
1125 &xfer);
1126 if (ret) {
1127 ERROR("Message alloc failed (%d)\n", ret);
1128 return ret;
1129 }
1130
1131 req.dev_id = dev_id;
1132 req.clk_id = clk_id;
1133
1134 ret = ti_sci_do_xfer(&xfer);
1135 if (ret) {
1136 ERROR("Transfer send failed (%d)\n", ret);
1137 return ret;
1138 }
1139
Andrew F. Davisdc08adf2018-05-04 19:06:11 +00001140 *freq = resp.freq_hz;
1141
1142 return 0;
1143}
1144
1145/**
Andrew F. Davis0d449302018-05-04 19:06:12 +00001146 * ti_sci_core_reboot() - Command to request system reset
1147 *
1148 * Return: 0 if all goes well, else appropriate error message
1149 */
1150int ti_sci_core_reboot(void)
1151{
1152 struct ti_sci_msg_req_reboot req;
1153 struct ti_sci_msg_hdr resp;
1154
1155 struct ti_sci_xfer xfer;
1156 int ret;
1157
Andrew F. Davis06b30522019-02-11 13:44:31 -06001158 ret = ti_sci_setup_one_xfer(TI_SCI_MSG_SYS_RESET, 0,
Andrew F. Davis0d449302018-05-04 19:06:12 +00001159 &req, sizeof(req),
1160 &resp, sizeof(resp),
1161 &xfer);
1162 if (ret) {
1163 ERROR("Message alloc failed (%d)\n", ret);
1164 return ret;
1165 }
Suman Anna0cb2bb12020-10-24 01:28:54 +00001166 req.domain = TI_SCI_DOMAIN_FULL_SOC_RESET;
Andrew F. Davis0d449302018-05-04 19:06:12 +00001167
1168 ret = ti_sci_do_xfer(&xfer);
1169 if (ret) {
1170 ERROR("Transfer send failed (%d)\n", ret);
1171 return ret;
1172 }
1173
Andrew F. Davis0d449302018-05-04 19:06:12 +00001174 return 0;
1175}
1176
1177/**
Andrew F. Davisd92fdfb2018-05-04 19:06:13 +00001178 * ti_sci_proc_request() - Request a physical processor control
1179 *
1180 * @proc_id: Processor ID this request is for
1181 *
1182 * Return: 0 if all goes well, else appropriate error message
1183 */
1184int ti_sci_proc_request(uint8_t proc_id)
1185{
1186 struct ti_sci_msg_req_proc_request req;
1187 struct ti_sci_msg_hdr resp;
1188
1189 struct ti_sci_xfer xfer;
1190 int ret;
1191
Andrew F. Davis06b30522019-02-11 13:44:31 -06001192 ret = ti_sci_setup_one_xfer(TISCI_MSG_PROC_REQUEST, 0,
Andrew F. Davisd92fdfb2018-05-04 19:06:13 +00001193 &req, sizeof(req),
1194 &resp, sizeof(resp),
1195 &xfer);
1196 if (ret) {
1197 ERROR("Message alloc failed (%d)\n", ret);
1198 return ret;
1199 }
1200
1201 req.processor_id = proc_id;
1202
1203 ret = ti_sci_do_xfer(&xfer);
1204 if (ret) {
1205 ERROR("Transfer send failed (%d)\n", ret);
1206 return ret;
1207 }
1208
Andrew F. Davisd92fdfb2018-05-04 19:06:13 +00001209 return 0;
1210}
1211
1212/**
1213 * ti_sci_proc_release() - Release a physical processor control
1214 *
1215 * @proc_id: Processor ID this request is for
1216 *
1217 * Return: 0 if all goes well, else appropriate error message
1218 */
1219int ti_sci_proc_release(uint8_t proc_id)
1220{
1221 struct ti_sci_msg_req_proc_release req;
1222 struct ti_sci_msg_hdr resp;
1223
1224 struct ti_sci_xfer xfer;
1225 int ret;
1226
Andrew F. Davis06b30522019-02-11 13:44:31 -06001227 ret = ti_sci_setup_one_xfer(TISCI_MSG_PROC_RELEASE, 0,
Andrew F. Davisd92fdfb2018-05-04 19:06:13 +00001228 &req, sizeof(req),
1229 &resp, sizeof(resp),
1230 &xfer);
1231 if (ret) {
1232 ERROR("Message alloc failed (%d)\n", ret);
1233 return ret;
1234 }
1235
1236 req.processor_id = proc_id;
1237
1238 ret = ti_sci_do_xfer(&xfer);
1239 if (ret) {
1240 ERROR("Transfer send failed (%d)\n", ret);
1241 return ret;
1242 }
1243
Andrew F. Davisd92fdfb2018-05-04 19:06:13 +00001244 return 0;
1245}
1246
1247/**
1248 * ti_sci_proc_handover() - Handover a physical processor control to a host in
1249 * the processor's access control list.
1250 *
1251 * @proc_id: Processor ID this request is for
1252 * @host_id: Host ID to get the control of the processor
1253 *
1254 * Return: 0 if all goes well, else appropriate error message
1255 */
1256int ti_sci_proc_handover(uint8_t proc_id, uint8_t host_id)
1257{
1258 struct ti_sci_msg_req_proc_handover req;
1259 struct ti_sci_msg_hdr resp;
1260
1261 struct ti_sci_xfer xfer;
1262 int ret;
1263
Andrew F. Davis06b30522019-02-11 13:44:31 -06001264 ret = ti_sci_setup_one_xfer(TISCI_MSG_PROC_HANDOVER, 0,
Andrew F. Davisd92fdfb2018-05-04 19:06:13 +00001265 &req, sizeof(req),
1266 &resp, sizeof(resp),
1267 &xfer);
1268 if (ret) {
1269 ERROR("Message alloc failed (%d)\n", ret);
1270 return ret;
1271 }
1272
1273 req.processor_id = proc_id;
1274 req.host_id = host_id;
1275
1276 ret = ti_sci_do_xfer(&xfer);
1277 if (ret) {
1278 ERROR("Transfer send failed (%d)\n", ret);
1279 return ret;
1280 }
1281
Andrew F. Davisd92fdfb2018-05-04 19:06:13 +00001282 return 0;
1283}
1284
1285/**
1286 * ti_sci_proc_set_boot_cfg() - Set the processor boot configuration flags
1287 *
1288 * @proc_id: Processor ID this request is for
1289 * @config_flags_set: Configuration flags to be set
1290 * @config_flags_clear: Configuration flags to be cleared
1291 *
1292 * Return: 0 if all goes well, else appropriate error message
1293 */
1294int ti_sci_proc_set_boot_cfg(uint8_t proc_id, uint64_t bootvector,
1295 uint32_t config_flags_set,
1296 uint32_t config_flags_clear)
1297{
1298 struct ti_sci_msg_req_set_proc_boot_config req;
1299 struct ti_sci_msg_hdr resp;
1300
1301 struct ti_sci_xfer xfer;
1302 int ret;
1303
Andrew F. Davis06b30522019-02-11 13:44:31 -06001304 ret = ti_sci_setup_one_xfer(TISCI_MSG_SET_PROC_BOOT_CONFIG, 0,
Andrew F. Davisd92fdfb2018-05-04 19:06:13 +00001305 &req, sizeof(req),
1306 &resp, sizeof(resp),
1307 &xfer);
1308 if (ret) {
1309 ERROR("Message alloc failed (%d)\n", ret);
1310 return ret;
1311 }
1312
1313 req.processor_id = proc_id;
1314 req.bootvector_low = bootvector & TISCI_ADDR_LOW_MASK;
1315 req.bootvector_high = (bootvector & TISCI_ADDR_HIGH_MASK) >>
1316 TISCI_ADDR_HIGH_SHIFT;
1317 req.config_flags_set = config_flags_set;
1318 req.config_flags_clear = config_flags_clear;
1319
1320 ret = ti_sci_do_xfer(&xfer);
1321 if (ret) {
1322 ERROR("Transfer send failed (%d)\n", ret);
1323 return ret;
1324 }
1325
Andrew F. Davisd92fdfb2018-05-04 19:06:13 +00001326 return 0;
1327}
1328
1329/**
1330 * ti_sci_proc_set_boot_ctrl() - Set the processor boot control flags
1331 *
1332 * @proc_id: Processor ID this request is for
1333 * @control_flags_set: Control flags to be set
1334 * @control_flags_clear: Control flags to be cleared
1335 *
1336 * Return: 0 if all goes well, else appropriate error message
1337 */
1338int ti_sci_proc_set_boot_ctrl(uint8_t proc_id, uint32_t control_flags_set,
1339 uint32_t control_flags_clear)
1340{
1341 struct ti_sci_msg_req_set_proc_boot_ctrl req;
1342 struct ti_sci_msg_hdr resp;
1343
1344 struct ti_sci_xfer xfer;
1345 int ret;
1346
Andrew F. Davis06b30522019-02-11 13:44:31 -06001347 ret = ti_sci_setup_one_xfer(TISCI_MSG_SET_PROC_BOOT_CTRL, 0,
Andrew F. Davisd92fdfb2018-05-04 19:06:13 +00001348 &req, sizeof(req),
1349 &resp, sizeof(resp),
1350 &xfer);
1351 if (ret) {
1352 ERROR("Message alloc failed (%d)\n", ret);
1353 return ret;
1354 }
1355
1356 req.processor_id = proc_id;
1357 req.control_flags_set = control_flags_set;
1358 req.control_flags_clear = control_flags_clear;
1359
1360 ret = ti_sci_do_xfer(&xfer);
1361 if (ret) {
1362 ERROR("Transfer send failed (%d)\n", ret);
1363 return ret;
1364 }
1365
Andrew F. Davisd92fdfb2018-05-04 19:06:13 +00001366 return 0;
1367}
1368
1369/**
Andrew F. Davisa29578d2019-02-11 14:18:53 -06001370 * ti_sci_proc_set_boot_ctrl_no_wait() - Set the processor boot control flags
1371 * without requesting or waiting for a
1372 * response.
1373 *
1374 * @proc_id: Processor ID this request is for
1375 * @control_flags_set: Control flags to be set
1376 * @control_flags_clear: Control flags to be cleared
1377 *
1378 * Return: 0 if all goes well, else appropriate error message
1379 */
1380int ti_sci_proc_set_boot_ctrl_no_wait(uint8_t proc_id,
1381 uint32_t control_flags_set,
1382 uint32_t control_flags_clear)
1383{
1384 struct ti_sci_msg_req_set_proc_boot_ctrl req;
1385 struct ti_sci_msg_hdr *hdr;
1386 struct k3_sec_proxy_msg tx_message;
1387 int ret;
1388
1389 /* Ensure we have sane transfer size */
Andrew F. Davis5daafa12020-01-16 15:34:31 -06001390 if (sizeof(req) > TI_SCI_MAX_MESSAGE_SIZE)
Andrew F. Davisa29578d2019-02-11 14:18:53 -06001391 return -ERANGE;
1392
1393 hdr = (struct ti_sci_msg_hdr *)&req;
Andrew F. Davis5daafa12020-01-16 15:34:31 -06001394 hdr->seq = ++message_sequence;
Andrew F. Davisa29578d2019-02-11 14:18:53 -06001395 hdr->type = TISCI_MSG_SET_PROC_BOOT_CTRL;
Andrew F. Davis5daafa12020-01-16 15:34:31 -06001396 hdr->host = TI_SCI_HOST_ID;
Andrew F. Davisa29578d2019-02-11 14:18:53 -06001397 /* Setup with NORESPONSE flag to keep response queue clean */
1398 hdr->flags = TI_SCI_FLAG_REQ_GENERIC_NORESPONSE;
1399
1400 req.processor_id = proc_id;
1401 req.control_flags_set = control_flags_set;
1402 req.control_flags_clear = control_flags_clear;
1403
1404 tx_message.buf = (uint8_t *)&req;
1405 tx_message.len = sizeof(req);
1406
1407 /* Send message */
1408 ret = k3_sec_proxy_send(SP_HIGH_PRIORITY, &tx_message);
1409 if (ret) {
1410 ERROR("Message sending failed (%d)\n", ret);
1411 return ret;
1412 }
1413
1414 /* Return without waiting for response */
1415 return 0;
1416}
1417
1418/**
Andrew F. Davisd92fdfb2018-05-04 19:06:13 +00001419 * ti_sci_proc_auth_boot_image() - Authenticate and load image and then set the
1420 * processor configuration flags
1421 *
1422 * @proc_id: Processor ID this request is for
1423 * @cert_addr: Memory address at which payload image certificate is located
1424 *
1425 * Return: 0 if all goes well, else appropriate error message
1426 */
1427int ti_sci_proc_auth_boot_image(uint8_t proc_id, uint64_t cert_addr)
1428{
1429 struct ti_sci_msg_req_proc_auth_boot_image req;
1430 struct ti_sci_msg_hdr resp;
1431
1432 struct ti_sci_xfer xfer;
1433 int ret;
1434
Andrew Davisc39841f2023-01-10 12:34:20 -06001435 ret = ti_sci_setup_one_xfer(TISCI_MSG_PROC_AUTH_BOOT_IMAGE, 0,
Andrew F. Davisd92fdfb2018-05-04 19:06:13 +00001436 &req, sizeof(req),
1437 &resp, sizeof(resp),
1438 &xfer);
1439 if (ret) {
1440 ERROR("Message alloc failed (%d)\n", ret);
1441 return ret;
1442 }
1443
1444 req.processor_id = proc_id;
1445 req.cert_addr_low = cert_addr & TISCI_ADDR_LOW_MASK;
1446 req.cert_addr_high = (cert_addr & TISCI_ADDR_HIGH_MASK) >>
1447 TISCI_ADDR_HIGH_SHIFT;
1448
1449 ret = ti_sci_do_xfer(&xfer);
1450 if (ret) {
1451 ERROR("Transfer send failed (%d)\n", ret);
1452 return ret;
1453 }
1454
Andrew F. Davisd92fdfb2018-05-04 19:06:13 +00001455 return 0;
1456}
1457
1458/**
1459 * ti_sci_proc_get_boot_status() - Get the processor boot status
1460 *
1461 * @proc_id: Processor ID this request is for
1462 *
1463 * Return: 0 if all goes well, else appropriate error message
1464 */
1465int ti_sci_proc_get_boot_status(uint8_t proc_id, uint64_t *bv,
1466 uint32_t *cfg_flags,
1467 uint32_t *ctrl_flags,
1468 uint32_t *sts_flags)
1469{
1470 struct ti_sci_msg_req_get_proc_boot_status req;
1471 struct ti_sci_msg_resp_get_proc_boot_status resp;
1472
1473 struct ti_sci_xfer xfer;
1474 int ret;
1475
Andrew F. Davis06b30522019-02-11 13:44:31 -06001476 ret = ti_sci_setup_one_xfer(TISCI_MSG_GET_PROC_BOOT_STATUS, 0,
Andrew F. Davisd92fdfb2018-05-04 19:06:13 +00001477 &req, sizeof(req),
1478 &resp, sizeof(resp),
1479 &xfer);
1480 if (ret) {
1481 ERROR("Message alloc failed (%d)\n", ret);
1482 return ret;
1483 }
1484
1485 req.processor_id = proc_id;
1486
1487 ret = ti_sci_do_xfer(&xfer);
1488 if (ret) {
1489 ERROR("Transfer send failed (%d)\n", ret);
1490 return ret;
1491 }
1492
Andrew F. Davisd92fdfb2018-05-04 19:06:13 +00001493 *bv = (resp.bootvector_low & TISCI_ADDR_LOW_MASK) |
1494 (((uint64_t)resp.bootvector_high << TISCI_ADDR_HIGH_SHIFT) &
1495 TISCI_ADDR_HIGH_MASK);
1496 *cfg_flags = resp.config_flags;
1497 *ctrl_flags = resp.control_flags;
1498 *sts_flags = resp.status_flags;
1499
1500 return 0;
1501}
1502
1503/**
Andrew F. Davisb62cc1e2018-12-18 13:21:12 -06001504 * ti_sci_proc_wait_boot_status() - Wait for a processor boot status
1505 *
1506 * @proc_id: Processor ID this request is for
1507 * @num_wait_iterations Total number of iterations we will check before
1508 * we will timeout and give up
1509 * @num_match_iterations How many iterations should we have continued
1510 * status to account for status bits glitching.
1511 * This is to make sure that match occurs for
1512 * consecutive checks. This implies that the
1513 * worst case should consider that the stable
1514 * time should at the worst be num_wait_iterations
1515 * num_match_iterations to prevent timeout.
1516 * @delay_per_iteration_us Specifies how long to wait (in micro seconds)
1517 * between each status checks. This is the minimum
1518 * duration, and overhead of register reads and
1519 * checks are on top of this and can vary based on
1520 * varied conditions.
1521 * @delay_before_iterations_us Specifies how long to wait (in micro seconds)
1522 * before the very first check in the first
1523 * iteration of status check loop. This is the
1524 * minimum duration, and overhead of register
1525 * reads and checks are.
1526 * @status_flags_1_set_all_wait If non-zero, Specifies that all bits of the
1527 * status matching this field requested MUST be 1.
1528 * @status_flags_1_set_any_wait If non-zero, Specifies that at least one of the
1529 * bits matching this field requested MUST be 1.
1530 * @status_flags_1_clr_all_wait If non-zero, Specifies that all bits of the
1531 * status matching this field requested MUST be 0.
1532 * @status_flags_1_clr_any_wait If non-zero, Specifies that at least one of the
1533 * bits matching this field requested MUST be 0.
1534 *
1535 * Return: 0 if all goes well, else appropriate error message
1536 */
1537int ti_sci_proc_wait_boot_status(uint8_t proc_id, uint8_t num_wait_iterations,
1538 uint8_t num_match_iterations,
1539 uint8_t delay_per_iteration_us,
1540 uint8_t delay_before_iterations_us,
1541 uint32_t status_flags_1_set_all_wait,
1542 uint32_t status_flags_1_set_any_wait,
1543 uint32_t status_flags_1_clr_all_wait,
1544 uint32_t status_flags_1_clr_any_wait)
1545{
1546 struct ti_sci_msg_req_wait_proc_boot_status req;
1547 struct ti_sci_msg_hdr resp;
1548
1549 struct ti_sci_xfer xfer;
1550 int ret;
1551
Andrew F. Davis06b30522019-02-11 13:44:31 -06001552 ret = ti_sci_setup_one_xfer(TISCI_MSG_WAIT_PROC_BOOT_STATUS, 0,
Andrew F. Davisb62cc1e2018-12-18 13:21:12 -06001553 &req, sizeof(req),
1554 &resp, sizeof(resp),
1555 &xfer);
1556 if (ret) {
1557 ERROR("Message alloc failed (%d)\n", ret);
1558 return ret;
1559 }
1560
1561 req.processor_id = proc_id;
1562 req.num_wait_iterations = num_wait_iterations;
1563 req.num_match_iterations = num_match_iterations;
1564 req.delay_per_iteration_us = delay_per_iteration_us;
1565 req.delay_before_iterations_us = delay_before_iterations_us;
1566 req.status_flags_1_set_all_wait = status_flags_1_set_all_wait;
1567 req.status_flags_1_set_any_wait = status_flags_1_set_any_wait;
1568 req.status_flags_1_clr_all_wait = status_flags_1_clr_all_wait;
1569 req.status_flags_1_clr_any_wait = status_flags_1_clr_any_wait;
1570
1571 ret = ti_sci_do_xfer(&xfer);
1572 if (ret) {
1573 ERROR("Transfer send failed (%d)\n", ret);
1574 return ret;
1575 }
1576
Andrew F. Davisa29578d2019-02-11 14:18:53 -06001577 return 0;
1578}
1579
1580/**
1581 * ti_sci_proc_wait_boot_status_no_wait() - Wait for a processor boot status
1582 * without requesting or waiting for
1583 * a response.
1584 *
1585 * @proc_id: Processor ID this request is for
1586 * @num_wait_iterations Total number of iterations we will check before
1587 * we will timeout and give up
1588 * @num_match_iterations How many iterations should we have continued
1589 * status to account for status bits glitching.
1590 * This is to make sure that match occurs for
1591 * consecutive checks. This implies that the
1592 * worst case should consider that the stable
1593 * time should at the worst be num_wait_iterations
1594 * num_match_iterations to prevent timeout.
1595 * @delay_per_iteration_us Specifies how long to wait (in micro seconds)
1596 * between each status checks. This is the minimum
1597 * duration, and overhead of register reads and
1598 * checks are on top of this and can vary based on
1599 * varied conditions.
1600 * @delay_before_iterations_us Specifies how long to wait (in micro seconds)
1601 * before the very first check in the first
1602 * iteration of status check loop. This is the
1603 * minimum duration, and overhead of register
1604 * reads and checks are.
1605 * @status_flags_1_set_all_wait If non-zero, Specifies that all bits of the
1606 * status matching this field requested MUST be 1.
1607 * @status_flags_1_set_any_wait If non-zero, Specifies that at least one of the
1608 * bits matching this field requested MUST be 1.
1609 * @status_flags_1_clr_all_wait If non-zero, Specifies that all bits of the
1610 * status matching this field requested MUST be 0.
1611 * @status_flags_1_clr_any_wait If non-zero, Specifies that at least one of the
1612 * bits matching this field requested MUST be 0.
1613 *
1614 * Return: 0 if all goes well, else appropriate error message
1615 */
1616int ti_sci_proc_wait_boot_status_no_wait(uint8_t proc_id,
1617 uint8_t num_wait_iterations,
1618 uint8_t num_match_iterations,
1619 uint8_t delay_per_iteration_us,
1620 uint8_t delay_before_iterations_us,
1621 uint32_t status_flags_1_set_all_wait,
1622 uint32_t status_flags_1_set_any_wait,
1623 uint32_t status_flags_1_clr_all_wait,
1624 uint32_t status_flags_1_clr_any_wait)
1625{
1626 struct ti_sci_msg_req_wait_proc_boot_status req;
1627 struct ti_sci_msg_hdr *hdr;
1628 struct k3_sec_proxy_msg tx_message;
1629 int ret;
1630
1631 /* Ensure we have sane transfer size */
Andrew F. Davis5daafa12020-01-16 15:34:31 -06001632 if (sizeof(req) > TI_SCI_MAX_MESSAGE_SIZE)
Andrew F. Davisa29578d2019-02-11 14:18:53 -06001633 return -ERANGE;
1634
1635 hdr = (struct ti_sci_msg_hdr *)&req;
Andrew F. Davis5daafa12020-01-16 15:34:31 -06001636 hdr->seq = ++message_sequence;
Andrew F. Davisa29578d2019-02-11 14:18:53 -06001637 hdr->type = TISCI_MSG_WAIT_PROC_BOOT_STATUS;
Andrew F. Davis5daafa12020-01-16 15:34:31 -06001638 hdr->host = TI_SCI_HOST_ID;
Andrew F. Davisa29578d2019-02-11 14:18:53 -06001639 /* Setup with NORESPONSE flag to keep response queue clean */
1640 hdr->flags = TI_SCI_FLAG_REQ_GENERIC_NORESPONSE;
1641
1642 req.processor_id = proc_id;
1643 req.num_wait_iterations = num_wait_iterations;
1644 req.num_match_iterations = num_match_iterations;
1645 req.delay_per_iteration_us = delay_per_iteration_us;
1646 req.delay_before_iterations_us = delay_before_iterations_us;
1647 req.status_flags_1_set_all_wait = status_flags_1_set_all_wait;
1648 req.status_flags_1_set_any_wait = status_flags_1_set_any_wait;
1649 req.status_flags_1_clr_all_wait = status_flags_1_clr_all_wait;
1650 req.status_flags_1_clr_any_wait = status_flags_1_clr_any_wait;
1651
1652 tx_message.buf = (uint8_t *)&req;
1653 tx_message.len = sizeof(req);
1654
1655 /* Send message */
1656 ret = k3_sec_proxy_send(SP_HIGH_PRIORITY, &tx_message);
1657 if (ret) {
1658 ERROR("Message sending failed (%d)\n", ret);
1659 return ret;
1660 }
1661
1662 /* Return without waiting for response */
Andrew F. Davisb62cc1e2018-12-18 13:21:12 -06001663 return 0;
1664}
1665
1666/**
Dave Gerlach7a94ce82021-11-30 15:35:08 -06001667 * ti_sci_enter_sleep - Command to initiate system transition into suspend.
1668 *
1669 * @proc_id: Processor ID.
1670 * @mode: Low power mode to enter.
1671 * @core_resume_addr: Address that core should be
1672 * resumed from after low power transition.
1673 *
1674 * Return: 0 if all goes well, else appropriate error message
1675 */
1676int ti_sci_enter_sleep(uint8_t proc_id,
1677 uint8_t mode,
1678 uint64_t core_resume_addr)
1679{
1680 struct ti_sci_msg_req_enter_sleep req;
1681 struct ti_sci_msg_hdr *hdr;
1682 struct k3_sec_proxy_msg tx_message;
1683 int ret;
1684
1685 /* Ensure we have sane transfer size */
1686 if (sizeof(req) > TI_SCI_MAX_MESSAGE_SIZE) {
1687 return -ERANGE;
1688 }
1689
1690 hdr = (struct ti_sci_msg_hdr *)&req;
1691 hdr->seq = ++message_sequence;
1692 hdr->type = TI_SCI_MSG_ENTER_SLEEP;
1693 hdr->host = TI_SCI_HOST_ID;
1694 /* Setup with NORESPONSE flag to keep response queue clean */
1695 hdr->flags = TI_SCI_FLAG_REQ_GENERIC_NORESPONSE;
1696
1697 req.processor_id = proc_id;
1698 req.mode = mode;
1699 req.core_resume_lo = core_resume_addr & TISCI_ADDR_LOW_MASK;
1700 req.core_resume_hi = (core_resume_addr & TISCI_ADDR_HIGH_MASK) >>
1701 TISCI_ADDR_HIGH_SHIFT;
1702
1703 tx_message.buf = (uint8_t *)&req;
1704 tx_message.len = sizeof(req);
1705
1706 /* Send message */
1707 ret = k3_sec_proxy_send(SP_HIGH_PRIORITY, &tx_message);
1708 if (ret != 0) {
1709 ERROR("Message sending failed (%d)\n", ret);
1710 return ret;
1711 }
1712
1713 /* Return without waiting for response */
1714 return 0;
1715}
1716
1717/**
Andrew F. Davisa513b2a2018-05-04 19:06:09 +00001718 * ti_sci_init() - Basic initialization
1719 *
1720 * Return: 0 if all goes well, else appropriate error message
1721 */
1722int ti_sci_init(void)
1723{
1724 struct ti_sci_msg_resp_version rev_info;
1725 int ret;
1726
1727 ret = ti_sci_get_revision(&rev_info);
1728 if (ret) {
1729 ERROR("Unable to communicate with control firmware (%d)\n", ret);
1730 return ret;
1731 }
1732
1733 INFO("SYSFW ABI: %d.%d (firmware rev 0x%04x '%s')\n",
1734 rev_info.abi_major, rev_info.abi_minor,
1735 rev_info.firmware_revision,
1736 rev_info.firmware_description);
1737
1738 return 0;
1739}