xref: /optee_os/core/arch/arm/plat-k3/drivers/ti_sci.c (revision 40baeb58144dd846de2f94e1736df55178c34062)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Texas Instruments System Control Interface Driver
4  *   Based on TF-A implementation
5  *
6  * Copyright (C) 2022 Texas Instruments Incorporated - https://www.ti.com/
7  *	Manorit Chawdhry <m-chawdhry@ti.com>
8  */
9 
10 #include <assert.h>
11 #include <kernel/mutex.h>
12 #include <malloc.h>
13 #include <platform_config.h>
14 #include <string.h>
15 #include <string_ext.h>
16 #include <tee_api_defines.h>
17 #include <trace.h>
18 
19 #include "ti_sci.h"
20 #include "ti_sci_protocol.h"
21 #include "ti_sci_transport.h"
22 
23 /**
24  * struct ti_sci_xfer - Structure representing a message flow
25  * @tx_message:	Transmit message
26  * @rx_message:	Receive message
27  */
28 struct ti_sci_xfer {
29 	struct ti_sci_msg tx_message;
30 	struct ti_sci_msg rx_message;
31 };
32 
33 /**
34  * ti_sci_setup_xfer() - Setup message transfer
35  *
36  * @msg_type:	Message type
37  * @msg_flags:	Flag to set for the message
38  * @tx_buf:	Buffer to be sent to mailbox channel
39  * @tx_message_size: transmit message size
40  * @rx_buf:	Buffer to be received from mailbox channel
41  * @rx_message_size: receive message size
42  * @xfer:	Transfer message
43  *
44  * Helper function which is used by various command functions that are
45  * exposed to clients of this driver for allocating a message traffic event.
46  *
47  * Return: 0 if all goes well, else appropriate error message
48  */
ti_sci_setup_xfer(uint16_t msg_type,uint32_t msg_flags,void * tx_buf,size_t tx_message_size,void * rx_buf,size_t rx_message_size,struct ti_sci_xfer * xfer)49 static int ti_sci_setup_xfer(uint16_t msg_type, uint32_t msg_flags,
50 			     void *tx_buf,
51 			     size_t tx_message_size,
52 			     void *rx_buf,
53 			     size_t rx_message_size,
54 			     struct ti_sci_xfer *xfer)
55 {
56 	struct ti_sci_msg_hdr *hdr = NULL;
57 
58 	/* Ensure we have sane transfer sizes */
59 	if (rx_message_size > TI_SCI_MAX_MESSAGE_SIZE ||
60 	    tx_message_size > TI_SCI_MAX_MESSAGE_SIZE ||
61 	    rx_message_size < sizeof(*hdr) ||
62 	    tx_message_size < sizeof(*hdr)) {
63 		EMSG("Message transfer size not sane");
64 		return TEE_ERROR_SHORT_BUFFER;
65 	}
66 
67 	hdr = (struct ti_sci_msg_hdr *)tx_buf;
68 	hdr->type = msg_type;
69 	hdr->host = OPTEE_HOST_ID;
70 	hdr->flags = msg_flags | TI_SCI_FLAG_REQ_ACK_ON_PROCESSED;
71 
72 	xfer->tx_message.buf = tx_buf;
73 	xfer->tx_message.len = tx_message_size;
74 
75 	xfer->rx_message.buf = rx_buf;
76 	xfer->rx_message.len = rx_message_size;
77 
78 	return 0;
79 }
80 
81 /**
82  * ti_sci_do_xfer() - Do one transfer
83  *
84  * @xfer: Transfer to initiate and wait for response
85  *
86  * Return: 0 if all goes well, else appropriate error message
87  */
ti_sci_do_xfer(struct ti_sci_xfer * xfer)88 static int ti_sci_do_xfer(struct ti_sci_xfer *xfer)
89 {
90 	struct ti_sci_msg *txmsg = &xfer->tx_message;
91 	struct ti_sci_msg *rxmsg = &xfer->rx_message;
92 	struct ti_sci_msg_hdr *txhdr = (struct ti_sci_msg_hdr *)txmsg->buf;
93 	struct ti_sci_msg_hdr *rxhdr = (struct ti_sci_msg_hdr *)rxmsg->buf;
94 	static uint8_t message_sequence;
95 	static struct mutex ti_sci_mutex_lock = MUTEX_INITIALIZER;
96 	unsigned int retry = 5;
97 	TEE_Result ret = 0;
98 
99 	mutex_lock(&ti_sci_mutex_lock);
100 
101 	message_sequence++;
102 	txhdr->seq = message_sequence;
103 
104 	/* Send the message */
105 	ret = ti_sci_transport_send(txmsg);
106 	if (ret) {
107 		EMSG("Message sending failed (%d)", ret);
108 		goto unlock;
109 	}
110 
111 	FMSG("Sending %"PRIx16" with seq %"PRIu8" host %"PRIu8,
112 	     txhdr->type, txhdr->seq, txhdr->host);
113 
114 	/* Get the response */
115 	for (; retry > 0; retry--) {
116 		/* Receive the response */
117 		ret = ti_sci_transport_recv(rxmsg);
118 		if (ret) {
119 			EMSG("Message receive failed (%d)", ret);
120 			goto unlock;
121 		}
122 
123 		/* Sanity check for message response */
124 		if (rxhdr->seq == message_sequence)
125 			break;
126 
127 		IMSG("Message with sequence ID %"PRIu8" is not expected",
128 		     rxhdr->seq);
129 	}
130 	if (!retry) {
131 		EMSG("Timed out waiting for message");
132 		ret = TEE_ERROR_BUSY;
133 		goto unlock;
134 	}
135 
136 	if (!(rxhdr->flags & TI_SCI_FLAG_RESP_GENERIC_ACK)) {
137 		DMSG("Message not acknowledged");
138 		ret = TEE_ERROR_ACCESS_DENIED;
139 		goto unlock;
140 	}
141 
142 	FMSG("Receive %"PRIx16" with seq %"PRIu8" host %"PRIu8,
143 	     rxhdr->type, rxhdr->seq, rxhdr->host);
144 
145 unlock:
146 	mutex_unlock(&ti_sci_mutex_lock);
147 	return ret;
148 }
149 
ti_sci_get_revision(struct ti_sci_msg_resp_version * rev_info)150 int ti_sci_get_revision(struct ti_sci_msg_resp_version *rev_info)
151 {
152 	struct ti_sci_msg_req_version req = { };
153 	struct ti_sci_xfer xfer = { };
154 	int ret = 0;
155 
156 	ret = ti_sci_setup_xfer(TI_SCI_MSG_VERSION, 0x0,
157 				&req, sizeof(req),
158 				rev_info, sizeof(*rev_info),
159 				&xfer);
160 	if (ret)
161 		return ret;
162 
163 	ret = ti_sci_do_xfer(&xfer);
164 	if (ret)
165 		return ret;
166 
167 	return 0;
168 }
169 
ti_sci_device_set_state(uint32_t id,uint32_t flags,uint8_t state)170 static int ti_sci_device_set_state(uint32_t id, uint32_t flags, uint8_t state)
171 {
172 	struct ti_sci_msg_req_set_device_state req = { };
173 	struct ti_sci_msg_resp_set_device_state resp = { };
174 	struct ti_sci_xfer xfer = { };
175 	int ret = 0;
176 
177 	ret = ti_sci_setup_xfer(TI_SCI_MSG_SET_DEVICE_STATE, flags,
178 				&req, sizeof(req),
179 				&resp, sizeof(resp),
180 				&xfer);
181 	if (ret)
182 		return ret;
183 
184 	req.id = id;
185 	req.state = state;
186 
187 	ret = ti_sci_do_xfer(&xfer);
188 	if (ret)
189 		return ret;
190 
191 	return 0;
192 }
193 
ti_sci_device_get(uint32_t id)194 int ti_sci_device_get(uint32_t id)
195 {
196 	return ti_sci_device_set_state(id, 0, MSG_DEVICE_SW_STATE_ON);
197 }
198 
ti_sci_device_put(uint32_t id)199 int ti_sci_device_put(uint32_t id)
200 {
201 	return ti_sci_device_set_state(id, 0, MSG_DEVICE_SW_STATE_AUTO_OFF);
202 }
203 
ti_sci_set_fwl_region(uint16_t fwl_id,uint16_t region,uint32_t n_permission_regs,uint32_t control,const uint32_t permissions[FWL_MAX_PRIVID_SLOTS],uint64_t start_address,uint64_t end_address)204 int ti_sci_set_fwl_region(uint16_t fwl_id, uint16_t region,
205 			  uint32_t n_permission_regs, uint32_t control,
206 			  const uint32_t permissions[FWL_MAX_PRIVID_SLOTS],
207 			  uint64_t start_address, uint64_t end_address)
208 {
209 	struct ti_sci_msg_req_fwl_set_firewall_region req = { };
210 	struct ti_sci_msg_resp_fwl_set_firewall_region resp = { };
211 	struct ti_sci_xfer xfer = { };
212 	unsigned int i = 0;
213 	int ret = 0;
214 
215 	assert(n_permission_regs <= FWL_MAX_PRIVID_SLOTS);
216 
217 	ret = ti_sci_setup_xfer(TI_SCI_MSG_FWL_SET, 0,
218 				&req, sizeof(req),
219 				&resp, sizeof(resp),
220 				&xfer);
221 	if (ret)
222 		return ret;
223 
224 	req.fwl_id = fwl_id;
225 	req.region = region;
226 	req.n_permission_regs = n_permission_regs;
227 	req.control = control;
228 	for (i = 0; i < n_permission_regs; i++)
229 		req.permissions[i] = permissions[i];
230 	req.start_address = start_address;
231 	req.end_address = end_address;
232 
233 	ret = ti_sci_do_xfer(&xfer);
234 	if (ret)
235 		return ret;
236 
237 	return 0;
238 }
239 
ti_sci_get_fwl_region(uint16_t fwl_id,uint16_t region,uint32_t n_permission_regs,uint32_t * control,uint32_t permissions[FWL_MAX_PRIVID_SLOTS],uint64_t * start_address,uint64_t * end_address)240 int ti_sci_get_fwl_region(uint16_t fwl_id, uint16_t region,
241 			  uint32_t n_permission_regs, uint32_t *control,
242 			  uint32_t permissions[FWL_MAX_PRIVID_SLOTS],
243 			  uint64_t *start_address, uint64_t *end_address)
244 {
245 	struct ti_sci_msg_req_fwl_get_firewall_region req = { };
246 	struct ti_sci_msg_resp_fwl_get_firewall_region resp = { };
247 	struct ti_sci_xfer xfer = { };
248 	unsigned int i = 0;
249 	int ret = 0;
250 
251 	assert(n_permission_regs <= FWL_MAX_PRIVID_SLOTS);
252 
253 	ret = ti_sci_setup_xfer(TI_SCI_MSG_FWL_GET, 0,
254 				&req, sizeof(req),
255 				&resp, sizeof(resp),
256 				&xfer);
257 	if (ret)
258 		return ret;
259 
260 	req.fwl_id = fwl_id;
261 	req.region = region;
262 	req.n_permission_regs = n_permission_regs;
263 
264 	ret = ti_sci_do_xfer(&xfer);
265 	if (ret)
266 		return ret;
267 
268 	*control = resp.control;
269 	for (i = 0; i < n_permission_regs; i++)
270 		permissions[i] = resp.permissions[i];
271 	*start_address = resp.start_address;
272 	*end_address = resp.end_address;
273 
274 	return 0;
275 }
276 
ti_sci_change_fwl_owner(uint16_t fwl_id,uint16_t region,uint8_t owner_index,uint8_t * owner_privid,uint16_t * owner_permission_bits)277 int ti_sci_change_fwl_owner(uint16_t fwl_id, uint16_t region,
278 			    uint8_t owner_index, uint8_t *owner_privid,
279 			    uint16_t *owner_permission_bits)
280 {
281 	struct ti_sci_msg_req_fwl_change_owner_info req = { };
282 	struct ti_sci_msg_resp_fwl_change_owner_info resp = { };
283 	struct ti_sci_xfer xfer = { };
284 	int ret = 0;
285 
286 	ret = ti_sci_setup_xfer(TI_SCI_MSG_FWL_CHANGE_OWNER, 0,
287 				&req, sizeof(req),
288 				&resp, sizeof(resp),
289 				&xfer);
290 	if (ret)
291 		return ret;
292 
293 	req.fwl_id = fwl_id;
294 	req.region = region;
295 	req.owner_index = owner_index;
296 
297 	ret = ti_sci_do_xfer(&xfer);
298 	if (ret)
299 		return ret;
300 
301 	*owner_privid = resp.owner_privid;
302 	*owner_permission_bits = resp.owner_permission_bits;
303 
304 	return 0;
305 }
306 
ti_sci_get_dkek(uint8_t sa2ul_instance,const char * context,const char * label,uint8_t dkek[SA2UL_DKEK_KEY_LEN])307 int ti_sci_get_dkek(uint8_t sa2ul_instance,
308 		    const char *context, const char *label,
309 		    uint8_t dkek[SA2UL_DKEK_KEY_LEN])
310 {
311 	struct ti_sci_msg_req_sa2ul_get_dkek req = { };
312 	struct ti_sci_msg_resp_sa2ul_get_dkek resp = { };
313 	struct ti_sci_xfer xfer = { };
314 	int ret = 0;
315 
316 	ret = ti_sci_setup_xfer(TI_SCI_MSG_SA2UL_GET_DKEK, 0,
317 				&req, sizeof(req), &resp, sizeof(resp), &xfer);
318 	if (ret)
319 		return ret;
320 
321 	req.sa2ul_instance = sa2ul_instance;
322 	req.kdf_label_len = strlen(label);
323 	req.kdf_context_len = strlen(context);
324 	if (req.kdf_label_len + req.kdf_context_len >
325 	    KDF_LABEL_AND_CONTEXT_LEN_MAX) {
326 		EMSG("Context and Label too long");
327 		return TEE_ERROR_BAD_PARAMETERS;
328 	}
329 	memcpy(req.kdf_label_and_context, label, strlen(label));
330 	memcpy(req.kdf_label_and_context + strlen(label), context,
331 	       strlen(context));
332 
333 	ret = ti_sci_do_xfer(&xfer);
334 	if (ret)
335 		return ret;
336 
337 	memcpy(dkek, resp.dkek, sizeof(resp.dkek));
338 	memzero_explicit(&resp, sizeof(resp));
339 	return 0;
340 }
341 
ti_sci_read_otp_mmr(uint8_t mmr_idx,uint32_t * val)342 int ti_sci_read_otp_mmr(uint8_t mmr_idx, uint32_t *val)
343 {
344 	struct ti_sci_msg_req_read_otp_mmr req = { };
345 	struct ti_sci_msg_resp_read_otp_mmr resp = { };
346 	struct ti_sci_xfer xfer = { };
347 	int ret = 0;
348 
349 	ret = ti_sci_setup_xfer(TI_SCI_MSG_READ_OTP_MMR, 0,
350 				&req, sizeof(req), &resp, sizeof(resp), &xfer);
351 	if (ret)
352 		goto exit;
353 
354 	req.mmr_idx = mmr_idx;
355 
356 	ret = ti_sci_do_xfer(&xfer);
357 	if (ret)
358 		goto exit;
359 
360 	*val = resp.mmr_val;
361 
362 exit:
363 	memzero_explicit(&resp, sizeof(resp));
364 	return ret;
365 }
366 
ti_sci_write_otp_row(uint8_t row_idx,uint32_t row_val,uint32_t row_mask)367 int ti_sci_write_otp_row(uint8_t row_idx, uint32_t row_val, uint32_t row_mask)
368 {
369 	struct ti_sci_msg_req_write_otp_row req = { };
370 	struct ti_sci_msg_resp_write_otp_row resp = { };
371 	struct ti_sci_xfer xfer = { };
372 	int ret = 0;
373 
374 	ret = ti_sci_setup_xfer(TI_SCI_MSG_WRITE_OTP_ROW, 0,
375 				&req, sizeof(req), &resp, sizeof(resp), &xfer);
376 	if (ret)
377 		goto exit;
378 
379 	req.row_idx = row_idx;
380 	req.row_val = row_val;
381 	req.row_mask = row_mask;
382 
383 	ret = ti_sci_do_xfer(&xfer);
384 	if (ret)
385 		goto exit;
386 
387 	DMSG("resp.row_val: 0x%08x", resp.row_val);
388 
389 	if (resp.row_val != (req.row_val & req.row_mask)) {
390 		EMSG("Value not written correctly");
391 		DMSG("req.row_val : 0x%08"PRIx32, req.row_val);
392 		DMSG("req.row_mask: 0x%08"PRIx32, req.row_mask);
393 		ret = TEE_ERROR_BAD_STATE;
394 	}
395 
396 exit:
397 	memzero_explicit(&resp, sizeof(resp));
398 	memzero_explicit(&req, sizeof(req));
399 	return ret;
400 }
401 
ti_sci_lock_otp_row(uint8_t row_idx,uint8_t hw_write_lock,uint8_t hw_read_lock,uint8_t row_soft_lock)402 int ti_sci_lock_otp_row(uint8_t row_idx, uint8_t hw_write_lock,
403 			uint8_t hw_read_lock, uint8_t row_soft_lock)
404 {
405 	struct ti_sci_msg_req_lock_otp_row req = { };
406 	struct ti_sci_msg_resp_lock_otp_row resp = { };
407 	struct ti_sci_xfer xfer = { };
408 	int ret = 0;
409 
410 	ret = ti_sci_setup_xfer(TI_SCI_MSG_LOCK_OTP_ROW, 0,
411 				&req, sizeof(req), &resp, sizeof(resp), &xfer);
412 	if (ret)
413 		return ret;
414 
415 	req.row_idx = row_idx;
416 	req.hw_write_lock = hw_write_lock;
417 	req.hw_read_lock = hw_read_lock;
418 	req.row_soft_lock = row_soft_lock;
419 
420 	ret = ti_sci_do_xfer(&xfer);
421 	if (ret)
422 		return ret;
423 
424 	return 0;
425 }
426 
ti_sci_set_swrev(uint8_t identifier,uint32_t swrev)427 int ti_sci_set_swrev(uint8_t identifier, uint32_t swrev)
428 {
429 	struct ti_sci_msq_req_set_swrev req = { };
430 	struct ti_sci_msq_resp_set_swrev resp = { };
431 	struct ti_sci_xfer xfer = { };
432 	int ret = 0;
433 
434 	ret = ti_sci_setup_xfer(TI_SCI_MSG_WRITE_SWREV, 0,
435 				&req, sizeof(req),
436 				&resp, sizeof(resp),
437 				&xfer);
438 	if (ret)
439 		return ret;
440 
441 	req.identifier = identifier;
442 	req.swrev = swrev;
443 
444 	ret = ti_sci_do_xfer(&xfer);
445 	if (ret)
446 		return ret;
447 
448 	memzero_explicit(&req, sizeof(req));
449 	return 0;
450 }
451 
ti_sci_get_swrev(uint32_t * swrev)452 int ti_sci_get_swrev(uint32_t *swrev)
453 {
454 	struct ti_sci_msq_req_get_swrev req = { };
455 	struct ti_sci_msq_resp_get_swrev resp = { };
456 	struct ti_sci_xfer xfer = { };
457 	int ret = 0;
458 
459 	ret = ti_sci_setup_xfer(TI_SCI_MSG_READ_SWREV, 0,
460 				&req, sizeof(req), &resp, sizeof(resp), &xfer);
461 	if (ret)
462 		return ret;
463 
464 	req.identifier = OTP_REV_ID_SEC_BRDCFG;
465 
466 	ret = ti_sci_do_xfer(&xfer);
467 	if (ret)
468 		return ret;
469 
470 	*swrev = resp.swrev;
471 	memzero_explicit(&resp, sizeof(resp));
472 	return 0;
473 }
474 
ti_sci_get_keycnt_keyrev(uint32_t * key_cnt,uint32_t * key_rev)475 int ti_sci_get_keycnt_keyrev(uint32_t *key_cnt, uint32_t *key_rev)
476 {
477 	struct ti_sci_msq_req_get_keycnt_keyrev req = { };
478 	struct ti_sci_msq_resp_get_keycnt_keyrev resp = { };
479 	struct ti_sci_xfer xfer = { };
480 	int ret = 0;
481 
482 	ret = ti_sci_setup_xfer(TI_SCI_MSG_READ_KEYCNT_KEYREV, 0,
483 				&req, sizeof(req), &resp, sizeof(resp), &xfer);
484 	if (ret)
485 		return ret;
486 
487 	ret = ti_sci_do_xfer(&xfer);
488 	if (ret)
489 		return ret;
490 
491 	*key_cnt = resp.keycnt;
492 	*key_rev = resp.keyrev;
493 	memzero_explicit(&resp, sizeof(resp));
494 	return 0;
495 }
496 
ti_sci_set_keyrev(uint32_t keyrev,uint32_t cert_addr_lo,uint32_t cert_addr_hi)497 int ti_sci_set_keyrev(uint32_t keyrev,
498 		      uint32_t cert_addr_lo,
499 		      uint32_t cert_addr_hi)
500 {
501 	struct ti_sci_msq_req_set_keyrev req = { };
502 	struct ti_sci_msq_resp_set_keyrev resp = { };
503 	struct ti_sci_xfer xfer = { };
504 	int ret = 0;
505 
506 	ret = ti_sci_setup_xfer(TI_SCI_MSG_WRITE_KEYREV, 0,
507 				&req, sizeof(req),
508 				&resp, sizeof(resp),
509 				&xfer);
510 	if (ret)
511 		return ret;
512 
513 	req.value = keyrev;
514 	req.cert_addr_lo = cert_addr_lo;
515 	req.cert_addr_hi = cert_addr_hi;
516 
517 	ret = ti_sci_do_xfer(&xfer);
518 	if (ret)
519 		return ret;
520 
521 	memzero_explicit(&req, sizeof(req));
522 	return 0;
523 }
524 
ti_sci_init(void)525 int ti_sci_init(void)
526 {
527 	struct ti_sci_msg_resp_version rev_info = { };
528 	int ret = 0;
529 
530 	ret = ti_sci_get_revision(&rev_info);
531 	if (ret) {
532 		EMSG("Unable to communicate with control firmware (%d)", ret);
533 		return ret;
534 	}
535 
536 	IMSG("SYSFW ABI: %d.%d (firmware rev 0x%04x '%s')",
537 	     rev_info.abi_major, rev_info.abi_minor,
538 	     rev_info.firmware_revision,
539 	     rev_info.firmware_description);
540 
541 	return 0;
542 }
543