blob: d04d80596032a32c30862edf8178217109b50868 [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);
Andrew Davisaf38ab22023-10-31 10:18:35 -0500158 goto unlock;
Andrew F. Davis18d371d2019-01-04 12:49:16 -0600159 }
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);
Andrew Davisaf38ab22023-10-31 10:18:35 -0500165 goto unlock;
Andrew F. Davisa513b2a2018-05-04 19:06:09 +0000166 }
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);
Andrew Davisaf38ab22023-10-31 10:18:35 -0500173 goto unlock;
Andrew Davise0a676c2022-05-16 13:17:02 -0500174 }
Andrew F. Davisa513b2a2018-05-04 19:06:09 +0000175 }
176
Andrew Davisaf38ab22023-10-31 10:18:35 -0500177unlock:
Andrew Davis617d0352023-03-13 13:56:27 -0500178 bakery_lock_release(&ti_sci_xfer_lock);
179
Andrew Davisaf38ab22023-10-31 10:18:35 -0500180 return ret;
Andrew F. Davisa513b2a2018-05-04 19:06:09 +0000181}
182
183/**
184 * ti_sci_get_revision() - Get the revision of the SCI entity
185 *
186 * Updates the SCI information in the internal data structure.
187 *
188 * Return: 0 if all goes well, else appropriate error message
189 */
190int ti_sci_get_revision(struct ti_sci_msg_resp_version *rev_info)
191{
192 struct ti_sci_msg_hdr hdr;
193 struct ti_sci_xfer xfer;
194 int ret;
195
196 ret = ti_sci_setup_one_xfer(TI_SCI_MSG_VERSION, 0x0,
197 &hdr, sizeof(hdr),
198 rev_info, sizeof(*rev_info),
199 &xfer);
200 if (ret) {
201 ERROR("Message alloc failed (%d)\n", ret);
202 return ret;
203 }
204
205 ret = ti_sci_do_xfer(&xfer);
206 if (ret) {
207 ERROR("Transfer send failed (%d)\n", ret);
208 return ret;
209 }
210
211 return 0;
212}
213
214/**
Andrew Davis10d67f92023-06-26 12:49:17 -0500215 * ti_sci_query_fw_caps() - Get the FW/SoC capabilities
216 * @handle: Pointer to TI SCI handle
217 * @fw_caps: Each bit in fw_caps indicating one FW/SOC capability
218 *
219 * Return: 0 if all went well, else returns appropriate error value.
220 */
221int ti_sci_query_fw_caps(uint64_t *fw_caps)
222{
223 struct ti_sci_msg_hdr req;
224 struct ti_sci_msg_resp_query_fw_caps resp;
225
226 struct ti_sci_xfer xfer;
227 int ret;
228
229 ret = ti_sci_setup_one_xfer(TI_SCI_MSG_QUERY_FW_CAPS, 0,
230 &req, sizeof(req),
231 &resp, sizeof(resp),
232 &xfer);
233 if (ret != 0U) {
234 ERROR("Message alloc failed (%d)\n", ret);
235 return ret;
236 }
237
238 ret = ti_sci_do_xfer(&xfer);
239 if (ret != 0U) {
240 ERROR("Transfer send failed (%d)\n", ret);
241 return ret;
242 }
243
244 if (fw_caps)
245 *fw_caps = resp.fw_caps;
246
247 return 0;
248}
249
250/**
Andrew F. Davis4f2a0552018-05-04 19:06:10 +0000251 * ti_sci_device_set_state() - Set device state
252 *
253 * @id: Device identifier
254 * @flags: flags to setup for the device
255 * @state: State to move the device to
256 *
257 * Return: 0 if all goes well, else appropriate error message
258 */
Andrew F. Davis8335bc22019-02-11 12:55:25 -0600259static int ti_sci_device_set_state(uint32_t id, uint32_t flags, uint8_t state)
Andrew F. Davis4f2a0552018-05-04 19:06:10 +0000260{
261 struct ti_sci_msg_req_set_device_state req;
262 struct ti_sci_msg_hdr resp;
263
264 struct ti_sci_xfer xfer;
265 int ret;
266
Andrew F. Davis06b30522019-02-11 13:44:31 -0600267 ret = ti_sci_setup_one_xfer(TI_SCI_MSG_SET_DEVICE_STATE, flags,
Andrew F. Davis4f2a0552018-05-04 19:06:10 +0000268 &req, sizeof(req),
269 &resp, sizeof(resp),
270 &xfer);
271 if (ret) {
272 ERROR("Message alloc failed (%d)\n", ret);
273 return ret;
274 }
275
276 req.id = id;
277 req.state = state;
278
279 ret = ti_sci_do_xfer(&xfer);
280 if (ret) {
281 ERROR("Transfer send failed (%d)\n", ret);
282 return ret;
283 }
284
Andrew F. Davis4f2a0552018-05-04 19:06:10 +0000285 return 0;
286}
287
288/**
289 * ti_sci_device_get_state() - Get device state
290 *
291 * @id: Device Identifier
292 * @clcnt: Pointer to Context Loss Count
293 * @resets: pointer to resets
294 * @p_state: pointer to p_state
295 * @c_state: pointer to c_state
296 *
297 * Return: 0 if all goes well, else appropriate error message
298 */
Andrew F. Davis8335bc22019-02-11 12:55:25 -0600299static int ti_sci_device_get_state(uint32_t id, uint32_t *clcnt,
300 uint32_t *resets, uint8_t *p_state,
301 uint8_t *c_state)
Andrew F. Davis4f2a0552018-05-04 19:06:10 +0000302{
303 struct ti_sci_msg_req_get_device_state req;
304 struct ti_sci_msg_resp_get_device_state resp;
305
306 struct ti_sci_xfer xfer;
307 int ret;
308
309 if (!clcnt && !resets && !p_state && !c_state)
310 return -EINVAL;
311
312 ret = ti_sci_setup_one_xfer(TI_SCI_MSG_GET_DEVICE_STATE, 0,
313 &req, sizeof(req),
314 &resp, sizeof(resp),
315 &xfer);
316 if (ret) {
317 ERROR("Message alloc failed (%d)\n", ret);
318 return ret;
319 }
320
321 req.id = id;
322
323 ret = ti_sci_do_xfer(&xfer);
324 if (ret) {
325 ERROR("Transfer send failed (%d)\n", ret);
326 return ret;
327 }
328
Andrew F. Davis4f2a0552018-05-04 19:06:10 +0000329 if (clcnt)
330 *clcnt = resp.context_loss_count;
331 if (resets)
332 *resets = resp.resets;
333 if (p_state)
334 *p_state = resp.programmed_state;
335 if (c_state)
336 *c_state = resp.current_state;
337
338 return 0;
339}
340
341/**
342 * ti_sci_device_get() - Request for device managed by TISCI
343 *
344 * @id: Device Identifier
345 *
346 * Request for the device - NOTE: the client MUST maintain integrity of
347 * usage count by balancing get_device with put_device. No refcounting is
348 * managed by driver for that purpose.
349 *
Andrew F. Davis4f2a0552018-05-04 19:06:10 +0000350 * Return: 0 if all goes well, else appropriate error message
351 */
352int ti_sci_device_get(uint32_t id)
353{
Andrew F. Davisfbe6c062019-02-11 12:58:32 -0600354 return ti_sci_device_set_state(id, 0, MSG_DEVICE_SW_STATE_ON);
355}
356
357/**
358 * ti_sci_device_get_exclusive() - Exclusive request for device managed by TISCI
359 *
360 * @id: Device Identifier
361 *
362 * Request for the device - NOTE: the client MUST maintain integrity of
363 * usage count by balancing get_device with put_device. No refcounting is
364 * managed by driver for that purpose.
365 *
366 * NOTE: This _exclusive version of the get API is for exclusive access to the
367 * device. Any other host in the system will fail to get this device after this
368 * call until exclusive access is released with device_put or a non-exclusive
369 * set call.
370 *
371 * Return: 0 if all goes well, else appropriate error message
372 */
373int ti_sci_device_get_exclusive(uint32_t id)
374{
Andrew F. Davis4f2a0552018-05-04 19:06:10 +0000375 return ti_sci_device_set_state(id,
376 MSG_FLAG_DEVICE_EXCLUSIVE,
377 MSG_DEVICE_SW_STATE_ON);
378}
379
380/**
381 * ti_sci_device_idle() - Idle a device managed by TISCI
382 *
383 * @id: Device Identifier
384 *
385 * Request for the device - NOTE: the client MUST maintain integrity of
386 * usage count by balancing get_device with put_device. No refcounting is
387 * managed by driver for that purpose.
388 *
389 * Return: 0 if all goes well, else appropriate error message
390 */
391int ti_sci_device_idle(uint32_t id)
392{
Andrew F. Davisfbe6c062019-02-11 12:58:32 -0600393 return ti_sci_device_set_state(id, 0, MSG_DEVICE_SW_STATE_RETENTION);
394}
395
396/**
397 * ti_sci_device_idle_exclusive() - Exclusive idle a device managed by TISCI
398 *
399 * @id: Device Identifier
400 *
401 * Request for the device - NOTE: the client MUST maintain integrity of
402 * usage count by balancing get_device with put_device. No refcounting is
403 * managed by driver for that purpose.
404 *
405 * NOTE: This _exclusive version of the idle API is for exclusive access to
406 * the device. Any other host in the system will fail to get this device after
407 * this call until exclusive access is released with device_put or a
408 * non-exclusive set call.
409 *
410 * Return: 0 if all goes well, else appropriate error message
411 */
412int ti_sci_device_idle_exclusive(uint32_t id)
413{
Andrew F. Davis4f2a0552018-05-04 19:06:10 +0000414 return ti_sci_device_set_state(id,
415 MSG_FLAG_DEVICE_EXCLUSIVE,
416 MSG_DEVICE_SW_STATE_RETENTION);
417}
418
419/**
420 * ti_sci_device_put() - Release a device managed by TISCI
421 *
422 * @id: Device Identifier
423 *
424 * Request for the device - NOTE: the client MUST maintain integrity of
425 * usage count by balancing get_device with put_device. No refcounting is
426 * managed by driver for that purpose.
427 *
428 * Return: 0 if all goes well, else appropriate error message
429 */
430int ti_sci_device_put(uint32_t id)
431{
432 return ti_sci_device_set_state(id, 0, MSG_DEVICE_SW_STATE_AUTO_OFF);
433}
434
435/**
Andrew F. Davisa29578d2019-02-11 14:18:53 -0600436 * ti_sci_device_put_no_wait() - Release a device without requesting or waiting
437 * for a response.
438 *
439 * @id: Device Identifier
440 *
441 * Request for the device - NOTE: the client MUST maintain integrity of
442 * usage count by balancing get_device with put_device. No refcounting is
443 * managed by driver for that purpose.
444 *
445 * Return: 0 if all goes well, else appropriate error message
446 */
447int ti_sci_device_put_no_wait(uint32_t id)
448{
449 struct ti_sci_msg_req_set_device_state req;
Andrew Davise0a676c2022-05-16 13:17:02 -0500450 struct ti_sci_xfer xfer;
Andrew F. Davisa29578d2019-02-11 14:18:53 -0600451 int ret;
452
Manorit Chawdhry24993b52023-08-22 16:15:40 +0530453 ret = ti_sci_setup_one_xfer(TI_SCI_MSG_SET_DEVICE_STATE, 0,
Andrew Davise0a676c2022-05-16 13:17:02 -0500454 &req, sizeof(req),
455 NULL, 0,
456 &xfer);
457 if (ret != 0U) {
458 ERROR("Message alloc failed (%d)\n", ret);
459 return ret;
460 }
Andrew F. Davisa29578d2019-02-11 14:18:53 -0600461
462 req.id = id;
463 req.state = MSG_DEVICE_SW_STATE_AUTO_OFF;
464
Andrew Davise0a676c2022-05-16 13:17:02 -0500465 ret = ti_sci_do_xfer(&xfer);
466 if (ret != 0U) {
467 ERROR("Transfer send failed (%d)\n", ret);
Andrew F. Davisa29578d2019-02-11 14:18:53 -0600468 return ret;
469 }
470
Andrew F. Davisa29578d2019-02-11 14:18:53 -0600471 return 0;
472}
473
474/**
Andrew F. Davis4f2a0552018-05-04 19:06:10 +0000475 * ti_sci_device_is_valid() - Is the device valid
476 *
477 * @id: Device Identifier
478 *
479 * Return: 0 if all goes well and the device ID is valid, else return
480 * appropriate error
481 */
482int ti_sci_device_is_valid(uint32_t id)
483{
484 uint8_t unused;
485
486 /* check the device state which will also tell us if the ID is valid */
487 return ti_sci_device_get_state(id, NULL, NULL, NULL, &unused);
488}
489
490/**
491 * ti_sci_device_get_clcnt() - Get context loss counter
492 *
493 * @id: Device Identifier
494 * @count: Pointer to Context Loss counter to populate
495 *
496 * Return: 0 if all goes well, else appropriate error message
497 */
498int ti_sci_device_get_clcnt(uint32_t id, uint32_t *count)
499{
500 return ti_sci_device_get_state(id, count, NULL, NULL, NULL);
501}
502
503/**
504 * ti_sci_device_is_idle() - Check if the device is requested to be idle
505 *
506 * @id: Device Identifier
507 * @r_state: true if requested to be idle
508 *
509 * Return: 0 if all goes well, else appropriate error message
510 */
511int ti_sci_device_is_idle(uint32_t id, bool *r_state)
512{
513 int ret;
514 uint8_t state;
515
516 if (!r_state)
517 return -EINVAL;
518
519 ret = ti_sci_device_get_state(id, NULL, NULL, &state, NULL);
520 if (ret)
521 return ret;
522
523 *r_state = (state == MSG_DEVICE_SW_STATE_RETENTION);
524
525 return 0;
526}
527
528/**
529 * ti_sci_device_is_stop() - Check if the device is requested to be stopped
530 *
531 * @id: Device Identifier
532 * @r_state: true if requested to be stopped
533 * @curr_state: true if currently stopped
534 *
535 * Return: 0 if all goes well, else appropriate error message
536 */
537int ti_sci_device_is_stop(uint32_t id, bool *r_state, bool *curr_state)
538{
539 int ret;
540 uint8_t p_state, c_state;
541
542 if (!r_state && !curr_state)
543 return -EINVAL;
544
545 ret = ti_sci_device_get_state(id, NULL, NULL, &p_state, &c_state);
546 if (ret)
547 return ret;
548
549 if (r_state)
550 *r_state = (p_state == MSG_DEVICE_SW_STATE_AUTO_OFF);
551 if (curr_state)
552 *curr_state = (c_state == MSG_DEVICE_HW_STATE_OFF);
553
554 return 0;
555}
556
557/**
558 * ti_sci_device_is_on() - Check if the device is requested to be ON
559 *
560 * @id: Device Identifier
561 * @r_state: true if requested to be ON
562 * @curr_state: true if currently ON and active
563 *
564 * Return: 0 if all goes well, else appropriate error message
565 */
566int ti_sci_device_is_on(uint32_t id, bool *r_state, bool *curr_state)
567{
568 int ret;
569 uint8_t p_state, c_state;
570
571 if (!r_state && !curr_state)
572 return -EINVAL;
573
574 ret =
575 ti_sci_device_get_state(id, NULL, NULL, &p_state, &c_state);
576 if (ret)
577 return ret;
578
579 if (r_state)
580 *r_state = (p_state == MSG_DEVICE_SW_STATE_ON);
581 if (curr_state)
582 *curr_state = (c_state == MSG_DEVICE_HW_STATE_ON);
583
584 return 0;
585}
586
587/**
588 * ti_sci_device_is_trans() - Check if the device is currently transitioning
589 *
590 * @id: Device Identifier
591 * @curr_state: true if currently transitioning
592 *
593 * Return: 0 if all goes well, else appropriate error message
594 */
595int ti_sci_device_is_trans(uint32_t id, bool *curr_state)
596{
597 int ret;
598 uint8_t state;
599
600 if (!curr_state)
601 return -EINVAL;
602
603 ret = ti_sci_device_get_state(id, NULL, NULL, NULL, &state);
604 if (ret)
605 return ret;
606
607 *curr_state = (state == MSG_DEVICE_HW_STATE_TRANS);
608
609 return 0;
610}
611
612/**
613 * ti_sci_device_set_resets() - Set resets for device managed by TISCI
614 *
615 * @id: Device Identifier
616 * @reset_state: Device specific reset bit field
617 *
618 * Return: 0 if all goes well, else appropriate error message
619 */
620int ti_sci_device_set_resets(uint32_t id, uint32_t reset_state)
621{
622 struct ti_sci_msg_req_set_device_resets req;
623 struct ti_sci_msg_hdr resp;
624
625 struct ti_sci_xfer xfer;
626 int ret;
627
Andrew F. Davis06b30522019-02-11 13:44:31 -0600628 ret = ti_sci_setup_one_xfer(TI_SCI_MSG_SET_DEVICE_RESETS, 0,
Andrew F. Davis4f2a0552018-05-04 19:06:10 +0000629 &req, sizeof(req),
630 &resp, sizeof(resp),
631 &xfer);
632 if (ret) {
633 ERROR("Message alloc failed (%d)\n", ret);
634 return ret;
635 }
636
637 req.id = id;
638 req.resets = reset_state;
639
640 ret = ti_sci_do_xfer(&xfer);
641 if (ret) {
642 ERROR("Transfer send failed (%d)\n", ret);
643 return ret;
644 }
645
Andrew F. Davis4f2a0552018-05-04 19:06:10 +0000646 return 0;
647}
648
649/**
650 * ti_sci_device_get_resets() - Get reset state for device managed by TISCI
651 *
652 * @id: Device Identifier
653 * @reset_state: Pointer to reset state to populate
654 *
655 * Return: 0 if all goes well, else appropriate error message
656 */
657int ti_sci_device_get_resets(uint32_t id, uint32_t *reset_state)
658{
659 return ti_sci_device_get_state(id, NULL, reset_state, NULL, NULL);
660}
661
662/**
Andrew F. Davisdc08adf2018-05-04 19:06:11 +0000663 * ti_sci_clock_set_state() - Set clock state helper
664 *
665 * @dev_id: Device identifier this request is for
666 * @clk_id: Clock identifier for the device for this request,
667 * Each device has its own set of clock inputs, This indexes
668 * which clock input to modify
669 * @flags: Header flags as needed
670 * @state: State to request for the clock
671 *
672 * Return: 0 if all goes well, else appropriate error message
673 */
674int ti_sci_clock_set_state(uint32_t dev_id, uint8_t clk_id,
675 uint32_t flags, uint8_t state)
676{
677 struct ti_sci_msg_req_set_clock_state req;
678 struct ti_sci_msg_hdr resp;
679
680 struct ti_sci_xfer xfer;
681 int ret;
682
Andrew F. Davis06b30522019-02-11 13:44:31 -0600683 ret = ti_sci_setup_one_xfer(TI_SCI_MSG_SET_CLOCK_STATE, flags,
Andrew F. Davisdc08adf2018-05-04 19:06:11 +0000684 &req, sizeof(req),
685 &resp, sizeof(resp),
686 &xfer);
687 if (ret) {
688 ERROR("Message alloc failed (%d)\n", ret);
689 return ret;
690 }
691
692 req.dev_id = dev_id;
693 req.clk_id = clk_id;
694 req.request_state = state;
695
696 ret = ti_sci_do_xfer(&xfer);
697 if (ret) {
698 ERROR("Transfer send failed (%d)\n", ret);
699 return ret;
700 }
701
Andrew F. Davisdc08adf2018-05-04 19:06:11 +0000702 return 0;
703}
704
705/**
706 * ti_sci_clock_get_state() - Get clock state helper
707 *
708 * @dev_id: Device identifier this request is for
709 * @clk_id: Clock identifier for the device for this request.
710 * Each device has its own set of clock inputs. This indexes
711 * which clock input to modify.
712 * @programmed_state: State requested for clock to move to
713 * @current_state: State that the clock is currently in
714 *
715 * Return: 0 if all goes well, else appropriate error message
716 */
717int ti_sci_clock_get_state(uint32_t dev_id, uint8_t clk_id,
718 uint8_t *programmed_state,
719 uint8_t *current_state)
720{
721 struct ti_sci_msg_req_get_clock_state req;
722 struct ti_sci_msg_resp_get_clock_state resp;
723
724 struct ti_sci_xfer xfer;
725 int ret;
726
727 if (!programmed_state && !current_state)
728 return -EINVAL;
729
Andrew F. Davis06b30522019-02-11 13:44:31 -0600730 ret = ti_sci_setup_one_xfer(TI_SCI_MSG_GET_CLOCK_STATE, 0,
Andrew F. Davisdc08adf2018-05-04 19:06:11 +0000731 &req, sizeof(req),
732 &resp, sizeof(resp),
733 &xfer);
734 if (ret) {
735 ERROR("Message alloc failed (%d)\n", ret);
736 return ret;
737 }
738
739 req.dev_id = dev_id;
740 req.clk_id = clk_id;
741
742 ret = ti_sci_do_xfer(&xfer);
743 if (ret) {
744 ERROR("Transfer send failed (%d)\n", ret);
745 return ret;
746 }
747
Andrew F. Davisdc08adf2018-05-04 19:06:11 +0000748 if (programmed_state)
749 *programmed_state = resp.programmed_state;
750 if (current_state)
751 *current_state = resp.current_state;
752
753 return 0;
754}
755
756/**
757 * ti_sci_clock_get() - Get control of a clock from TI SCI
758
759 * @dev_id: Device identifier this request is for
760 * @clk_id: Clock identifier for the device for this request.
761 * Each device has its own set of clock inputs. This indexes
762 * which clock input to modify.
763 * @needs_ssc: 'true' iff Spread Spectrum clock is desired
764 * @can_change_freq: 'true' iff frequency change is desired
765 * @enable_input_term: 'true' iff input termination is desired
766 *
767 * Return: 0 if all goes well, else appropriate error message
768 */
769int ti_sci_clock_get(uint32_t dev_id, uint8_t clk_id,
770 bool needs_ssc, bool can_change_freq,
771 bool enable_input_term)
772{
773 uint32_t flags = 0;
774
775 flags |= needs_ssc ? MSG_FLAG_CLOCK_ALLOW_SSC : 0;
776 flags |= can_change_freq ? MSG_FLAG_CLOCK_ALLOW_FREQ_CHANGE : 0;
777 flags |= enable_input_term ? MSG_FLAG_CLOCK_INPUT_TERM : 0;
778
779 return ti_sci_clock_set_state(dev_id, clk_id, flags,
780 MSG_CLOCK_SW_STATE_REQ);
781}
782
783/**
784 * ti_sci_clock_idle() - Idle a clock which is in our control
785
786 * @dev_id: Device identifier this request is for
787 * @clk_id: Clock identifier for the device for this request.
788 * Each device has its own set of clock inputs. This indexes
789 * which clock input to modify.
790 *
791 * NOTE: This clock must have been requested by get_clock previously.
792 *
793 * Return: 0 if all goes well, else appropriate error message
794 */
795int ti_sci_clock_idle(uint32_t dev_id, uint8_t clk_id)
796{
797 return ti_sci_clock_set_state(dev_id, clk_id, 0,
798 MSG_CLOCK_SW_STATE_UNREQ);
799}
800
801/**
802 * ti_sci_clock_put() - Release a clock from our control
803 *
804 * @dev_id: Device identifier this request is for
805 * @clk_id: Clock identifier for the device for this request.
806 * Each device has its own set of clock inputs. This indexes
807 * which clock input to modify.
808 *
809 * NOTE: This clock must have been requested by get_clock previously.
810 *
811 * Return: 0 if all goes well, else appropriate error message
812 */
813int ti_sci_clock_put(uint32_t dev_id, uint8_t clk_id)
814{
815 return ti_sci_clock_set_state(dev_id, clk_id, 0,
816 MSG_CLOCK_SW_STATE_AUTO);
817}
818
819/**
820 * ti_sci_clock_is_auto() - Is the clock being auto managed
821 *
822 * @dev_id: Device identifier this request is for
823 * @clk_id: Clock identifier for the device for this request.
824 * Each device has its own set of clock inputs. This indexes
825 * which clock input to modify.
826 * @req_state: state indicating if the clock is auto managed
827 *
828 * Return: 0 if all goes well, else appropriate error message
829 */
830int ti_sci_clock_is_auto(uint32_t dev_id, uint8_t clk_id, bool *req_state)
831{
832 uint8_t state = 0;
833 int ret;
834
835 if (!req_state)
836 return -EINVAL;
837
838 ret = ti_sci_clock_get_state(dev_id, clk_id, &state, NULL);
839 if (ret)
840 return ret;
841
842 *req_state = (state == MSG_CLOCK_SW_STATE_AUTO);
843
844 return 0;
845}
846
847/**
848 * ti_sci_clock_is_on() - Is the clock ON
849 *
850 * @dev_id: Device identifier this request is for
851 * @clk_id: Clock identifier for the device for this request.
852 * Each device has its own set of clock inputs. This indexes
853 * which clock input to modify.
854 * @req_state: state indicating if the clock is managed by us and enabled
855 * @curr_state: state indicating if the clock is ready for operation
856 *
857 * Return: 0 if all goes well, else appropriate error message
858 */
859int ti_sci_clock_is_on(uint32_t dev_id, uint8_t clk_id,
860 bool *req_state, bool *curr_state)
861{
862 uint8_t c_state = 0, r_state = 0;
863 int ret;
864
865 if (!req_state && !curr_state)
866 return -EINVAL;
867
868 ret = ti_sci_clock_get_state(dev_id, clk_id, &r_state, &c_state);
869 if (ret)
870 return ret;
871
872 if (req_state)
873 *req_state = (r_state == MSG_CLOCK_SW_STATE_REQ);
874 if (curr_state)
875 *curr_state = (c_state == MSG_CLOCK_HW_STATE_READY);
876
877 return 0;
878}
879
880/**
881 * ti_sci_clock_is_off() - Is the clock OFF
882 *
883 * @dev_id: Device identifier this request is for
884 * @clk_id: Clock identifier for the device for this request.
885 * Each device has its own set of clock inputs. This indexes
886 * which clock input to modify.
887 * @req_state: state indicating if the clock is managed by us and disabled
888 * @curr_state: state indicating if the clock is NOT ready for operation
889 *
890 * Return: 0 if all goes well, else appropriate error message
891 */
892int ti_sci_clock_is_off(uint32_t dev_id, uint8_t clk_id,
893 bool *req_state, bool *curr_state)
894{
895 uint8_t c_state = 0, r_state = 0;
896 int ret;
897
898 if (!req_state && !curr_state)
899 return -EINVAL;
900
901 ret = ti_sci_clock_get_state(dev_id, clk_id, &r_state, &c_state);
902 if (ret)
903 return ret;
904
905 if (req_state)
906 *req_state = (r_state == MSG_CLOCK_SW_STATE_UNREQ);
907 if (curr_state)
908 *curr_state = (c_state == MSG_CLOCK_HW_STATE_NOT_READY);
909
910 return 0;
911}
912
913/**
914 * ti_sci_clock_set_parent() - Set the clock source of a specific device clock
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: Parent clock identifier to set
921 *
922 * Return: 0 if all goes well, else appropriate error message
923 */
924int ti_sci_clock_set_parent(uint32_t dev_id, uint8_t clk_id, uint8_t parent_id)
925{
926 struct ti_sci_msg_req_set_clock_parent req;
927 struct ti_sci_msg_hdr 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_SET_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 req.parent_id = parent_id;
944
945 ret = ti_sci_do_xfer(&xfer);
946 if (ret) {
947 ERROR("Transfer send failed (%d)\n", ret);
948 return ret;
949 }
950
Andrew F. Davisdc08adf2018-05-04 19:06:11 +0000951 return 0;
952}
953
954/**
955 * ti_sci_clock_get_parent() - Get current parent clock source
956 *
957 * @dev_id: Device identifier this request is for
958 * @clk_id: Clock identifier for the device for this request.
959 * Each device has its own set of clock inputs. This indexes
960 * which clock input to modify.
961 * @parent_id: Current clock parent
962 *
963 * Return: 0 if all goes well, else appropriate error message
964 */
965int ti_sci_clock_get_parent(uint32_t dev_id, uint8_t clk_id, uint8_t *parent_id)
966{
967 struct ti_sci_msg_req_get_clock_parent req;
968 struct ti_sci_msg_resp_get_clock_parent resp;
969
970 struct ti_sci_xfer xfer;
971 int ret;
972
Andrew F. Davis06b30522019-02-11 13:44:31 -0600973 ret = ti_sci_setup_one_xfer(TI_SCI_MSG_GET_CLOCK_PARENT, 0,
Andrew F. Davisdc08adf2018-05-04 19:06:11 +0000974 &req, sizeof(req),
975 &resp, sizeof(resp),
976 &xfer);
977 if (ret) {
978 ERROR("Message alloc failed (%d)\n", ret);
979 return ret;
980 }
981
982 req.dev_id = dev_id;
983 req.clk_id = clk_id;
984
985 ret = ti_sci_do_xfer(&xfer);
986 if (ret) {
987 ERROR("Transfer send failed (%d)\n", ret);
988 return ret;
989 }
990
Andrew F. Davisdc08adf2018-05-04 19:06:11 +0000991 *parent_id = resp.parent_id;
992
993 return 0;
994}
995
996/**
997 * ti_sci_clock_get_num_parents() - Get num parents of the current clk source
998 *
999 * @dev_id: Device identifier this request is for
1000 * @clk_id: Clock identifier for the device for this request.
1001 * Each device has its own set of clock inputs. This indexes
1002 * which clock input to modify.
1003 * @num_parents: Returns he number of parents to the current clock.
1004 *
1005 * Return: 0 if all goes well, else appropriate error message
1006 */
1007int ti_sci_clock_get_num_parents(uint32_t dev_id, uint8_t clk_id,
1008 uint8_t *num_parents)
1009{
1010 struct ti_sci_msg_req_get_clock_num_parents req;
1011 struct ti_sci_msg_resp_get_clock_num_parents resp;
1012
1013 struct ti_sci_xfer xfer;
1014 int ret;
1015
Andrew F. Davis06b30522019-02-11 13:44:31 -06001016 ret = ti_sci_setup_one_xfer(TI_SCI_MSG_GET_NUM_CLOCK_PARENTS, 0,
Andrew F. Davisdc08adf2018-05-04 19:06:11 +00001017 &req, sizeof(req),
1018 &resp, sizeof(resp),
1019 &xfer);
1020 if (ret) {
1021 ERROR("Message alloc failed (%d)\n", ret);
1022 return ret;
1023 }
1024
1025 req.dev_id = dev_id;
1026 req.clk_id = clk_id;
1027
1028 ret = ti_sci_do_xfer(&xfer);
1029 if (ret) {
1030 ERROR("Transfer send failed (%d)\n", ret);
1031 return ret;
1032 }
1033
Andrew F. Davisdc08adf2018-05-04 19:06:11 +00001034 *num_parents = resp.num_parents;
1035
1036 return 0;
1037}
1038
1039/**
1040 * ti_sci_clock_get_match_freq() - Find a good match for frequency
1041 *
1042 * @dev_id: Device identifier this request is for
1043 * @clk_id: Clock identifier for the device for this request.
1044 * Each device has its own set of clock inputs. This indexes
1045 * which clock input to modify.
1046 * @min_freq: The minimum allowable frequency in Hz. This is the minimum
1047 * allowable programmed frequency and does not account for clock
1048 * tolerances and jitter.
1049 * @target_freq: The target clock frequency in Hz. A frequency will be
1050 * processed as close to this target frequency as possible.
1051 * @max_freq: The maximum allowable frequency in Hz. This is the maximum
1052 * allowable programmed frequency and does not account for clock
1053 * tolerances and jitter.
1054 * @match_freq: Frequency match in Hz response.
1055 *
1056 * Return: 0 if all goes well, else appropriate error message
1057 */
1058int ti_sci_clock_get_match_freq(uint32_t dev_id, uint8_t clk_id,
1059 uint64_t min_freq, uint64_t target_freq,
1060 uint64_t max_freq, uint64_t *match_freq)
1061{
1062 struct ti_sci_msg_req_query_clock_freq req;
1063 struct ti_sci_msg_resp_query_clock_freq resp;
1064
1065 struct ti_sci_xfer xfer;
1066 int ret;
1067
Andrew F. Davis06b30522019-02-11 13:44:31 -06001068 ret = ti_sci_setup_one_xfer(TI_SCI_MSG_QUERY_CLOCK_FREQ, 0,
Andrew F. Davisdc08adf2018-05-04 19:06:11 +00001069 &req, sizeof(req),
1070 &resp, sizeof(resp),
1071 &xfer);
1072 if (ret) {
1073 ERROR("Message alloc failed (%d)\n", ret);
1074 return ret;
1075 }
1076
1077 req.dev_id = dev_id;
1078 req.clk_id = clk_id;
1079 req.min_freq_hz = min_freq;
1080 req.target_freq_hz = target_freq;
1081 req.max_freq_hz = max_freq;
1082
1083 ret = ti_sci_do_xfer(&xfer);
1084 if (ret) {
1085 ERROR("Transfer send failed (%d)\n", ret);
1086 return ret;
1087 }
1088
Andrew F. Davisdc08adf2018-05-04 19:06:11 +00001089 *match_freq = resp.freq_hz;
1090
1091 return 0;
1092}
1093
1094/**
1095 * ti_sci_clock_set_freq() - Set a frequency for clock
1096 *
1097 * @dev_id: Device identifier this request is for
1098 * @clk_id: Clock identifier for the device for this request.
1099 * Each device has its own set of clock inputs. This indexes
1100 * which clock input to modify.
1101 * @min_freq: The minimum allowable frequency in Hz. This is the minimum
1102 * allowable programmed frequency and does not account for clock
1103 * tolerances and jitter.
1104 * @target_freq: The target clock frequency in Hz. A frequency will be
1105 * processed as close to this target frequency as possible.
1106 * @max_freq: The maximum allowable frequency in Hz. This is the maximum
1107 * allowable programmed frequency and does not account for clock
1108 * tolerances and jitter.
1109 *
1110 * Return: 0 if all goes well, else appropriate error message
1111 */
1112int ti_sci_clock_set_freq(uint32_t dev_id, uint8_t clk_id, uint64_t min_freq,
1113 uint64_t target_freq, uint64_t max_freq)
1114{
1115 struct ti_sci_msg_req_set_clock_freq req;
1116 struct ti_sci_msg_hdr resp;
1117
1118 struct ti_sci_xfer xfer;
1119 int ret;
1120
Andrew F. Davis06b30522019-02-11 13:44:31 -06001121 ret = ti_sci_setup_one_xfer(TI_SCI_MSG_SET_CLOCK_FREQ, 0,
Andrew F. Davisdc08adf2018-05-04 19:06:11 +00001122 &req, sizeof(req),
1123 &resp, sizeof(resp),
1124 &xfer);
1125 if (ret) {
1126 ERROR("Message alloc failed (%d)\n", ret);
1127 return ret;
1128 }
1129 req.dev_id = dev_id;
1130 req.clk_id = clk_id;
1131 req.min_freq_hz = min_freq;
1132 req.target_freq_hz = target_freq;
1133 req.max_freq_hz = max_freq;
1134
1135 ret = ti_sci_do_xfer(&xfer);
1136 if (ret) {
1137 ERROR("Transfer send failed (%d)\n", ret);
1138 return ret;
1139 }
1140
Andrew F. Davisdc08adf2018-05-04 19:06:11 +00001141 return 0;
1142}
1143
1144/**
1145 * ti_sci_clock_get_freq() - Get current frequency
1146 *
1147 * @dev_id: Device identifier this request is for
1148 * @clk_id: Clock identifier for the device for this request.
1149 * Each device has its own set of clock inputs. This indexes
1150 * which clock input to modify.
1151 * @freq: Currently frequency in Hz
1152 *
1153 * Return: 0 if all goes well, else appropriate error message
1154 */
1155int ti_sci_clock_get_freq(uint32_t dev_id, uint8_t clk_id, uint64_t *freq)
1156{
1157 struct ti_sci_msg_req_get_clock_freq req;
1158 struct ti_sci_msg_resp_get_clock_freq resp;
1159
1160 struct ti_sci_xfer xfer;
1161 int ret;
1162
Andrew F. Davis06b30522019-02-11 13:44:31 -06001163 ret = ti_sci_setup_one_xfer(TI_SCI_MSG_GET_CLOCK_FREQ, 0,
Andrew F. Davisdc08adf2018-05-04 19:06:11 +00001164 &req, sizeof(req),
1165 &resp, sizeof(resp),
1166 &xfer);
1167 if (ret) {
1168 ERROR("Message alloc failed (%d)\n", ret);
1169 return ret;
1170 }
1171
1172 req.dev_id = dev_id;
1173 req.clk_id = clk_id;
1174
1175 ret = ti_sci_do_xfer(&xfer);
1176 if (ret) {
1177 ERROR("Transfer send failed (%d)\n", ret);
1178 return ret;
1179 }
1180
Andrew F. Davisdc08adf2018-05-04 19:06:11 +00001181 *freq = resp.freq_hz;
1182
1183 return 0;
1184}
1185
1186/**
Andrew F. Davis0d449302018-05-04 19:06:12 +00001187 * ti_sci_core_reboot() - Command to request system reset
1188 *
1189 * Return: 0 if all goes well, else appropriate error message
1190 */
1191int ti_sci_core_reboot(void)
1192{
1193 struct ti_sci_msg_req_reboot req;
1194 struct ti_sci_msg_hdr resp;
1195
1196 struct ti_sci_xfer xfer;
1197 int ret;
1198
Andrew F. Davis06b30522019-02-11 13:44:31 -06001199 ret = ti_sci_setup_one_xfer(TI_SCI_MSG_SYS_RESET, 0,
Andrew F. Davis0d449302018-05-04 19:06:12 +00001200 &req, sizeof(req),
1201 &resp, sizeof(resp),
1202 &xfer);
1203 if (ret) {
1204 ERROR("Message alloc failed (%d)\n", ret);
1205 return ret;
1206 }
Suman Anna0cb2bb12020-10-24 01:28:54 +00001207 req.domain = TI_SCI_DOMAIN_FULL_SOC_RESET;
Andrew F. Davis0d449302018-05-04 19:06:12 +00001208
1209 ret = ti_sci_do_xfer(&xfer);
1210 if (ret) {
1211 ERROR("Transfer send failed (%d)\n", ret);
1212 return ret;
1213 }
1214
Andrew F. Davis0d449302018-05-04 19:06:12 +00001215 return 0;
1216}
1217
1218/**
Andrew F. Davisd92fdfb2018-05-04 19:06:13 +00001219 * ti_sci_proc_request() - Request a physical processor control
1220 *
1221 * @proc_id: Processor ID this request is for
1222 *
1223 * Return: 0 if all goes well, else appropriate error message
1224 */
1225int ti_sci_proc_request(uint8_t proc_id)
1226{
1227 struct ti_sci_msg_req_proc_request req;
1228 struct ti_sci_msg_hdr resp;
1229
1230 struct ti_sci_xfer xfer;
1231 int ret;
1232
Andrew F. Davis06b30522019-02-11 13:44:31 -06001233 ret = ti_sci_setup_one_xfer(TISCI_MSG_PROC_REQUEST, 0,
Andrew F. Davisd92fdfb2018-05-04 19:06:13 +00001234 &req, sizeof(req),
1235 &resp, sizeof(resp),
1236 &xfer);
1237 if (ret) {
1238 ERROR("Message alloc failed (%d)\n", ret);
1239 return ret;
1240 }
1241
1242 req.processor_id = proc_id;
1243
1244 ret = ti_sci_do_xfer(&xfer);
1245 if (ret) {
1246 ERROR("Transfer send failed (%d)\n", ret);
1247 return ret;
1248 }
1249
Andrew F. Davisd92fdfb2018-05-04 19:06:13 +00001250 return 0;
1251}
1252
1253/**
1254 * ti_sci_proc_release() - Release a physical processor control
1255 *
1256 * @proc_id: Processor ID this request is for
1257 *
1258 * Return: 0 if all goes well, else appropriate error message
1259 */
1260int ti_sci_proc_release(uint8_t proc_id)
1261{
1262 struct ti_sci_msg_req_proc_release 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_RELEASE, 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
1279 ret = ti_sci_do_xfer(&xfer);
1280 if (ret) {
1281 ERROR("Transfer send failed (%d)\n", ret);
1282 return ret;
1283 }
1284
Andrew F. Davisd92fdfb2018-05-04 19:06:13 +00001285 return 0;
1286}
1287
1288/**
1289 * ti_sci_proc_handover() - Handover a physical processor control to a host in
1290 * the processor's access control list.
1291 *
1292 * @proc_id: Processor ID this request is for
1293 * @host_id: Host ID to get the control of the processor
1294 *
1295 * Return: 0 if all goes well, else appropriate error message
1296 */
1297int ti_sci_proc_handover(uint8_t proc_id, uint8_t host_id)
1298{
1299 struct ti_sci_msg_req_proc_handover req;
1300 struct ti_sci_msg_hdr resp;
1301
1302 struct ti_sci_xfer xfer;
1303 int ret;
1304
Andrew F. Davis06b30522019-02-11 13:44:31 -06001305 ret = ti_sci_setup_one_xfer(TISCI_MSG_PROC_HANDOVER, 0,
Andrew F. Davisd92fdfb2018-05-04 19:06:13 +00001306 &req, sizeof(req),
1307 &resp, sizeof(resp),
1308 &xfer);
1309 if (ret) {
1310 ERROR("Message alloc failed (%d)\n", ret);
1311 return ret;
1312 }
1313
1314 req.processor_id = proc_id;
1315 req.host_id = host_id;
1316
1317 ret = ti_sci_do_xfer(&xfer);
1318 if (ret) {
1319 ERROR("Transfer send failed (%d)\n", ret);
1320 return ret;
1321 }
1322
Andrew F. Davisd92fdfb2018-05-04 19:06:13 +00001323 return 0;
1324}
1325
1326/**
1327 * ti_sci_proc_set_boot_cfg() - Set the processor boot configuration flags
1328 *
1329 * @proc_id: Processor ID this request is for
1330 * @config_flags_set: Configuration flags to be set
1331 * @config_flags_clear: Configuration flags to be cleared
1332 *
1333 * Return: 0 if all goes well, else appropriate error message
1334 */
1335int ti_sci_proc_set_boot_cfg(uint8_t proc_id, uint64_t bootvector,
1336 uint32_t config_flags_set,
1337 uint32_t config_flags_clear)
1338{
1339 struct ti_sci_msg_req_set_proc_boot_config req;
1340 struct ti_sci_msg_hdr resp;
1341
1342 struct ti_sci_xfer xfer;
1343 int ret;
1344
Andrew F. Davis06b30522019-02-11 13:44:31 -06001345 ret = ti_sci_setup_one_xfer(TISCI_MSG_SET_PROC_BOOT_CONFIG, 0,
Andrew F. Davisd92fdfb2018-05-04 19:06:13 +00001346 &req, sizeof(req),
1347 &resp, sizeof(resp),
1348 &xfer);
1349 if (ret) {
1350 ERROR("Message alloc failed (%d)\n", ret);
1351 return ret;
1352 }
1353
1354 req.processor_id = proc_id;
1355 req.bootvector_low = bootvector & TISCI_ADDR_LOW_MASK;
1356 req.bootvector_high = (bootvector & TISCI_ADDR_HIGH_MASK) >>
1357 TISCI_ADDR_HIGH_SHIFT;
1358 req.config_flags_set = config_flags_set;
1359 req.config_flags_clear = config_flags_clear;
1360
1361 ret = ti_sci_do_xfer(&xfer);
1362 if (ret) {
1363 ERROR("Transfer send failed (%d)\n", ret);
1364 return ret;
1365 }
1366
Andrew F. Davisd92fdfb2018-05-04 19:06:13 +00001367 return 0;
1368}
1369
1370/**
1371 * ti_sci_proc_set_boot_ctrl() - Set the processor boot control flags
1372 *
1373 * @proc_id: Processor ID this request is for
1374 * @control_flags_set: Control flags to be set
1375 * @control_flags_clear: Control flags to be cleared
1376 *
1377 * Return: 0 if all goes well, else appropriate error message
1378 */
1379int ti_sci_proc_set_boot_ctrl(uint8_t proc_id, uint32_t control_flags_set,
1380 uint32_t control_flags_clear)
1381{
1382 struct ti_sci_msg_req_set_proc_boot_ctrl req;
1383 struct ti_sci_msg_hdr resp;
1384
1385 struct ti_sci_xfer xfer;
1386 int ret;
1387
Andrew F. Davis06b30522019-02-11 13:44:31 -06001388 ret = ti_sci_setup_one_xfer(TISCI_MSG_SET_PROC_BOOT_CTRL, 0,
Andrew F. Davisd92fdfb2018-05-04 19:06:13 +00001389 &req, sizeof(req),
1390 &resp, sizeof(resp),
1391 &xfer);
1392 if (ret) {
1393 ERROR("Message alloc failed (%d)\n", ret);
1394 return ret;
1395 }
1396
1397 req.processor_id = proc_id;
1398 req.control_flags_set = control_flags_set;
1399 req.control_flags_clear = control_flags_clear;
1400
1401 ret = ti_sci_do_xfer(&xfer);
1402 if (ret) {
1403 ERROR("Transfer send failed (%d)\n", ret);
1404 return ret;
1405 }
1406
Andrew F. Davisd92fdfb2018-05-04 19:06:13 +00001407 return 0;
1408}
1409
1410/**
Andrew F. Davisa29578d2019-02-11 14:18:53 -06001411 * ti_sci_proc_set_boot_ctrl_no_wait() - Set the processor boot control flags
1412 * without requesting or waiting for a
1413 * response.
1414 *
1415 * @proc_id: Processor ID this request is for
1416 * @control_flags_set: Control flags to be set
1417 * @control_flags_clear: Control flags to be cleared
1418 *
1419 * Return: 0 if all goes well, else appropriate error message
1420 */
1421int ti_sci_proc_set_boot_ctrl_no_wait(uint8_t proc_id,
1422 uint32_t control_flags_set,
1423 uint32_t control_flags_clear)
1424{
1425 struct ti_sci_msg_req_set_proc_boot_ctrl req;
Andrew Davise0a676c2022-05-16 13:17:02 -05001426 struct ti_sci_xfer xfer;
Andrew F. Davisa29578d2019-02-11 14:18:53 -06001427 int ret;
1428
Manorit Chawdhry24993b52023-08-22 16:15:40 +05301429 ret = ti_sci_setup_one_xfer(TISCI_MSG_SET_PROC_BOOT_CTRL, 0,
Andrew Davise0a676c2022-05-16 13:17:02 -05001430 &req, sizeof(req),
1431 NULL, 0,
1432 &xfer);
1433 if (ret != 0U) {
1434 ERROR("Message alloc failed (%d)\n", ret);
1435 return ret;
1436 }
Andrew F. Davisa29578d2019-02-11 14:18:53 -06001437
1438 req.processor_id = proc_id;
1439 req.control_flags_set = control_flags_set;
1440 req.control_flags_clear = control_flags_clear;
1441
Andrew Davise0a676c2022-05-16 13:17:02 -05001442 ret = ti_sci_do_xfer(&xfer);
1443 if (ret != 0U) {
1444 ERROR("Transfer send failed (%d)\n", ret);
Andrew F. Davisa29578d2019-02-11 14:18:53 -06001445 return ret;
1446 }
1447
Andrew F. Davisa29578d2019-02-11 14:18:53 -06001448 return 0;
1449}
1450
1451/**
Andrew F. Davisd92fdfb2018-05-04 19:06:13 +00001452 * ti_sci_proc_auth_boot_image() - Authenticate and load image and then set the
1453 * processor configuration flags
1454 *
1455 * @proc_id: Processor ID this request is for
1456 * @cert_addr: Memory address at which payload image certificate is located
1457 *
1458 * Return: 0 if all goes well, else appropriate error message
1459 */
1460int ti_sci_proc_auth_boot_image(uint8_t proc_id, uint64_t cert_addr)
1461{
1462 struct ti_sci_msg_req_proc_auth_boot_image req;
1463 struct ti_sci_msg_hdr resp;
1464
1465 struct ti_sci_xfer xfer;
1466 int ret;
1467
Andrew Davisc39841f2023-01-10 12:34:20 -06001468 ret = ti_sci_setup_one_xfer(TISCI_MSG_PROC_AUTH_BOOT_IMAGE, 0,
Andrew F. Davisd92fdfb2018-05-04 19:06:13 +00001469 &req, sizeof(req),
1470 &resp, sizeof(resp),
1471 &xfer);
1472 if (ret) {
1473 ERROR("Message alloc failed (%d)\n", ret);
1474 return ret;
1475 }
1476
1477 req.processor_id = proc_id;
1478 req.cert_addr_low = cert_addr & TISCI_ADDR_LOW_MASK;
1479 req.cert_addr_high = (cert_addr & TISCI_ADDR_HIGH_MASK) >>
1480 TISCI_ADDR_HIGH_SHIFT;
1481
1482 ret = ti_sci_do_xfer(&xfer);
1483 if (ret) {
1484 ERROR("Transfer send failed (%d)\n", ret);
1485 return ret;
1486 }
1487
Andrew F. Davisd92fdfb2018-05-04 19:06:13 +00001488 return 0;
1489}
1490
1491/**
1492 * ti_sci_proc_get_boot_status() - Get the processor boot status
1493 *
1494 * @proc_id: Processor ID this request is for
1495 *
1496 * Return: 0 if all goes well, else appropriate error message
1497 */
1498int ti_sci_proc_get_boot_status(uint8_t proc_id, uint64_t *bv,
1499 uint32_t *cfg_flags,
1500 uint32_t *ctrl_flags,
1501 uint32_t *sts_flags)
1502{
1503 struct ti_sci_msg_req_get_proc_boot_status req;
1504 struct ti_sci_msg_resp_get_proc_boot_status resp;
1505
1506 struct ti_sci_xfer xfer;
1507 int ret;
1508
Andrew F. Davis06b30522019-02-11 13:44:31 -06001509 ret = ti_sci_setup_one_xfer(TISCI_MSG_GET_PROC_BOOT_STATUS, 0,
Andrew F. Davisd92fdfb2018-05-04 19:06:13 +00001510 &req, sizeof(req),
1511 &resp, sizeof(resp),
1512 &xfer);
1513 if (ret) {
1514 ERROR("Message alloc failed (%d)\n", ret);
1515 return ret;
1516 }
1517
1518 req.processor_id = proc_id;
1519
1520 ret = ti_sci_do_xfer(&xfer);
1521 if (ret) {
1522 ERROR("Transfer send failed (%d)\n", ret);
1523 return ret;
1524 }
1525
Andrew F. Davisd92fdfb2018-05-04 19:06:13 +00001526 *bv = (resp.bootvector_low & TISCI_ADDR_LOW_MASK) |
1527 (((uint64_t)resp.bootvector_high << TISCI_ADDR_HIGH_SHIFT) &
1528 TISCI_ADDR_HIGH_MASK);
1529 *cfg_flags = resp.config_flags;
1530 *ctrl_flags = resp.control_flags;
1531 *sts_flags = resp.status_flags;
1532
1533 return 0;
1534}
1535
1536/**
Andrew F. Davisb62cc1e2018-12-18 13:21:12 -06001537 * ti_sci_proc_wait_boot_status() - Wait for a processor boot status
1538 *
1539 * @proc_id: Processor ID this request is for
1540 * @num_wait_iterations Total number of iterations we will check before
1541 * we will timeout and give up
1542 * @num_match_iterations How many iterations should we have continued
1543 * status to account for status bits glitching.
1544 * This is to make sure that match occurs for
1545 * consecutive checks. This implies that the
1546 * worst case should consider that the stable
1547 * time should at the worst be num_wait_iterations
1548 * num_match_iterations to prevent timeout.
1549 * @delay_per_iteration_us Specifies how long to wait (in micro seconds)
1550 * between each status checks. This is the minimum
1551 * duration, and overhead of register reads and
1552 * checks are on top of this and can vary based on
1553 * varied conditions.
1554 * @delay_before_iterations_us Specifies how long to wait (in micro seconds)
1555 * before the very first check in the first
1556 * iteration of status check loop. This is the
1557 * minimum duration, and overhead of register
1558 * reads and checks are.
1559 * @status_flags_1_set_all_wait If non-zero, Specifies that all bits of the
1560 * status matching this field requested MUST be 1.
1561 * @status_flags_1_set_any_wait If non-zero, Specifies that at least one of the
1562 * bits matching this field requested MUST be 1.
1563 * @status_flags_1_clr_all_wait If non-zero, Specifies that all bits of the
1564 * status matching this field requested MUST be 0.
1565 * @status_flags_1_clr_any_wait If non-zero, Specifies that at least one of the
1566 * bits matching this field requested MUST be 0.
1567 *
1568 * Return: 0 if all goes well, else appropriate error message
1569 */
1570int ti_sci_proc_wait_boot_status(uint8_t proc_id, uint8_t num_wait_iterations,
1571 uint8_t num_match_iterations,
1572 uint8_t delay_per_iteration_us,
1573 uint8_t delay_before_iterations_us,
1574 uint32_t status_flags_1_set_all_wait,
1575 uint32_t status_flags_1_set_any_wait,
1576 uint32_t status_flags_1_clr_all_wait,
1577 uint32_t status_flags_1_clr_any_wait)
1578{
1579 struct ti_sci_msg_req_wait_proc_boot_status req;
1580 struct ti_sci_msg_hdr resp;
1581
1582 struct ti_sci_xfer xfer;
1583 int ret;
1584
Andrew F. Davis06b30522019-02-11 13:44:31 -06001585 ret = ti_sci_setup_one_xfer(TISCI_MSG_WAIT_PROC_BOOT_STATUS, 0,
Andrew F. Davisb62cc1e2018-12-18 13:21:12 -06001586 &req, sizeof(req),
1587 &resp, sizeof(resp),
1588 &xfer);
1589 if (ret) {
1590 ERROR("Message alloc failed (%d)\n", ret);
1591 return ret;
1592 }
1593
1594 req.processor_id = proc_id;
1595 req.num_wait_iterations = num_wait_iterations;
1596 req.num_match_iterations = num_match_iterations;
1597 req.delay_per_iteration_us = delay_per_iteration_us;
1598 req.delay_before_iterations_us = delay_before_iterations_us;
1599 req.status_flags_1_set_all_wait = status_flags_1_set_all_wait;
1600 req.status_flags_1_set_any_wait = status_flags_1_set_any_wait;
1601 req.status_flags_1_clr_all_wait = status_flags_1_clr_all_wait;
1602 req.status_flags_1_clr_any_wait = status_flags_1_clr_any_wait;
1603
1604 ret = ti_sci_do_xfer(&xfer);
1605 if (ret) {
1606 ERROR("Transfer send failed (%d)\n", ret);
1607 return ret;
1608 }
1609
Andrew F. Davisa29578d2019-02-11 14:18:53 -06001610 return 0;
1611}
1612
1613/**
1614 * ti_sci_proc_wait_boot_status_no_wait() - Wait for a processor boot status
1615 * without requesting or waiting for
1616 * a response.
1617 *
1618 * @proc_id: Processor ID this request is for
1619 * @num_wait_iterations Total number of iterations we will check before
1620 * we will timeout and give up
1621 * @num_match_iterations How many iterations should we have continued
1622 * status to account for status bits glitching.
1623 * This is to make sure that match occurs for
1624 * consecutive checks. This implies that the
1625 * worst case should consider that the stable
1626 * time should at the worst be num_wait_iterations
1627 * num_match_iterations to prevent timeout.
1628 * @delay_per_iteration_us Specifies how long to wait (in micro seconds)
1629 * between each status checks. This is the minimum
1630 * duration, and overhead of register reads and
1631 * checks are on top of this and can vary based on
1632 * varied conditions.
1633 * @delay_before_iterations_us Specifies how long to wait (in micro seconds)
1634 * before the very first check in the first
1635 * iteration of status check loop. This is the
1636 * minimum duration, and overhead of register
1637 * reads and checks are.
1638 * @status_flags_1_set_all_wait If non-zero, Specifies that all bits of the
1639 * status matching this field requested MUST be 1.
1640 * @status_flags_1_set_any_wait If non-zero, Specifies that at least one of the
1641 * bits matching this field requested MUST be 1.
1642 * @status_flags_1_clr_all_wait If non-zero, Specifies that all bits of the
1643 * status matching this field requested MUST be 0.
1644 * @status_flags_1_clr_any_wait If non-zero, Specifies that at least one of the
1645 * bits matching this field requested MUST be 0.
1646 *
1647 * Return: 0 if all goes well, else appropriate error message
1648 */
1649int ti_sci_proc_wait_boot_status_no_wait(uint8_t proc_id,
1650 uint8_t num_wait_iterations,
1651 uint8_t num_match_iterations,
1652 uint8_t delay_per_iteration_us,
1653 uint8_t delay_before_iterations_us,
1654 uint32_t status_flags_1_set_all_wait,
1655 uint32_t status_flags_1_set_any_wait,
1656 uint32_t status_flags_1_clr_all_wait,
1657 uint32_t status_flags_1_clr_any_wait)
1658{
1659 struct ti_sci_msg_req_wait_proc_boot_status req;
Andrew Davise0a676c2022-05-16 13:17:02 -05001660 struct ti_sci_xfer xfer;
Andrew F. Davisa29578d2019-02-11 14:18:53 -06001661 int ret;
1662
Manorit Chawdhry24993b52023-08-22 16:15:40 +05301663 ret = ti_sci_setup_one_xfer(TISCI_MSG_WAIT_PROC_BOOT_STATUS, 0,
Andrew Davise0a676c2022-05-16 13:17:02 -05001664 &req, sizeof(req),
1665 NULL, 0,
1666 &xfer);
1667 if (ret != 0U) {
1668 ERROR("Message alloc failed (%d)\n", ret);
1669 return ret;
1670 }
Andrew F. Davisa29578d2019-02-11 14:18:53 -06001671
1672 req.processor_id = proc_id;
1673 req.num_wait_iterations = num_wait_iterations;
1674 req.num_match_iterations = num_match_iterations;
1675 req.delay_per_iteration_us = delay_per_iteration_us;
1676 req.delay_before_iterations_us = delay_before_iterations_us;
1677 req.status_flags_1_set_all_wait = status_flags_1_set_all_wait;
1678 req.status_flags_1_set_any_wait = status_flags_1_set_any_wait;
1679 req.status_flags_1_clr_all_wait = status_flags_1_clr_all_wait;
1680 req.status_flags_1_clr_any_wait = status_flags_1_clr_any_wait;
1681
Andrew Davise0a676c2022-05-16 13:17:02 -05001682 ret = ti_sci_do_xfer(&xfer);
1683 if (ret != 0U) {
1684 ERROR("Transfer send failed (%d)\n", ret);
Andrew F. Davisa29578d2019-02-11 14:18:53 -06001685 return ret;
1686 }
1687
Andrew F. Davisb62cc1e2018-12-18 13:21:12 -06001688 return 0;
1689}
1690
1691/**
Dave Gerlach7a94ce82021-11-30 15:35:08 -06001692 * ti_sci_enter_sleep - Command to initiate system transition into suspend.
1693 *
1694 * @proc_id: Processor ID.
1695 * @mode: Low power mode to enter.
1696 * @core_resume_addr: Address that core should be
1697 * resumed from after low power transition.
1698 *
1699 * Return: 0 if all goes well, else appropriate error message
1700 */
1701int ti_sci_enter_sleep(uint8_t proc_id,
1702 uint8_t mode,
1703 uint64_t core_resume_addr)
1704{
1705 struct ti_sci_msg_req_enter_sleep req;
Andrew Davise0a676c2022-05-16 13:17:02 -05001706 struct ti_sci_xfer xfer;
Dave Gerlach7a94ce82021-11-30 15:35:08 -06001707 int ret;
1708
Manorit Chawdhry24993b52023-08-22 16:15:40 +05301709 ret = ti_sci_setup_one_xfer(TI_SCI_MSG_ENTER_SLEEP, 0,
Andrew Davise0a676c2022-05-16 13:17:02 -05001710 &req, sizeof(req),
1711 NULL, 0,
1712 &xfer);
1713 if (ret != 0U) {
1714 ERROR("Message alloc failed (%d)\n", ret);
1715 return ret;
Dave Gerlach7a94ce82021-11-30 15:35:08 -06001716 }
1717
Dave Gerlach7a94ce82021-11-30 15:35:08 -06001718 req.processor_id = proc_id;
1719 req.mode = mode;
1720 req.core_resume_lo = core_resume_addr & TISCI_ADDR_LOW_MASK;
1721 req.core_resume_hi = (core_resume_addr & TISCI_ADDR_HIGH_MASK) >>
1722 TISCI_ADDR_HIGH_SHIFT;
1723
Andrew Davise0a676c2022-05-16 13:17:02 -05001724 ret = ti_sci_do_xfer(&xfer);
1725 if (ret != 0U) {
1726 ERROR("Transfer send failed (%d)\n", ret);
Dave Gerlach7a94ce82021-11-30 15:35:08 -06001727 return ret;
1728 }
1729
Dave Gerlach7a94ce82021-11-30 15:35:08 -06001730 return 0;
1731}
1732
1733/**
Andrew F. Davisa513b2a2018-05-04 19:06:09 +00001734 * ti_sci_init() - Basic initialization
1735 *
1736 * Return: 0 if all goes well, else appropriate error message
1737 */
1738int ti_sci_init(void)
1739{
1740 struct ti_sci_msg_resp_version rev_info;
1741 int ret;
1742
1743 ret = ti_sci_get_revision(&rev_info);
1744 if (ret) {
1745 ERROR("Unable to communicate with control firmware (%d)\n", ret);
1746 return ret;
1747 }
1748
1749 INFO("SYSFW ABI: %d.%d (firmware rev 0x%04x '%s')\n",
1750 rev_info.abi_major, rev_info.abi_minor,
1751 rev_info.firmware_revision,
1752 rev_info.firmware_description);
1753
1754 return 0;
1755}