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