xref: /arm-trusted-firmware/plat/ti/k3/common/drivers/sec_proxy/sec_proxy.c (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
1*91f16700Schasinglulu /*
2*91f16700Schasinglulu  * Texas Instruments K3 Secure Proxy Driver
3*91f16700Schasinglulu  *   Based on Linux and U-Boot implementation
4*91f16700Schasinglulu  *
5*91f16700Schasinglulu  * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
6*91f16700Schasinglulu  *
7*91f16700Schasinglulu  * SPDX-License-Identifier: BSD-3-Clause
8*91f16700Schasinglulu  */
9*91f16700Schasinglulu 
10*91f16700Schasinglulu #include <errno.h>
11*91f16700Schasinglulu #include <stdlib.h>
12*91f16700Schasinglulu 
13*91f16700Schasinglulu #include <platform_def.h>
14*91f16700Schasinglulu 
15*91f16700Schasinglulu #include <arch_helpers.h>
16*91f16700Schasinglulu #include <common/debug.h>
17*91f16700Schasinglulu #include <lib/mmio.h>
18*91f16700Schasinglulu #include <lib/utils.h>
19*91f16700Schasinglulu #include <lib/utils_def.h>
20*91f16700Schasinglulu 
21*91f16700Schasinglulu #include "sec_proxy.h"
22*91f16700Schasinglulu 
23*91f16700Schasinglulu /* SEC PROXY RT THREAD STATUS */
24*91f16700Schasinglulu #define RT_THREAD_STATUS			(0x0)
25*91f16700Schasinglulu #define RT_THREAD_STATUS_ERROR_SHIFT		(31)
26*91f16700Schasinglulu #define RT_THREAD_STATUS_ERROR_MASK		BIT(31)
27*91f16700Schasinglulu #define RT_THREAD_STATUS_CUR_CNT_SHIFT		(0)
28*91f16700Schasinglulu #define RT_THREAD_STATUS_CUR_CNT_MASK		GENMASK(7, 0)
29*91f16700Schasinglulu 
30*91f16700Schasinglulu /* SEC PROXY SCFG THREAD CTRL */
31*91f16700Schasinglulu #define SCFG_THREAD_CTRL			(0x1000)
32*91f16700Schasinglulu #define SCFG_THREAD_CTRL_DIR_SHIFT		(31)
33*91f16700Schasinglulu #define SCFG_THREAD_CTRL_DIR_MASK		BIT(31)
34*91f16700Schasinglulu 
35*91f16700Schasinglulu #define SEC_PROXY_THREAD(base, x)		((base) + (0x1000 * (x)))
36*91f16700Schasinglulu #define THREAD_IS_RX				(1)
37*91f16700Schasinglulu #define THREAD_IS_TX				(0)
38*91f16700Schasinglulu 
39*91f16700Schasinglulu /**
40*91f16700Schasinglulu  * struct k3_sec_proxy_desc - Description of secure proxy integration
41*91f16700Schasinglulu  * @timeout_us:		Timeout for communication (in Microseconds)
42*91f16700Schasinglulu  * @max_msg_size:	Message size in bytes
43*91f16700Schasinglulu  * @data_start_offset:	Offset of the First data register of the thread
44*91f16700Schasinglulu  * @data_end_offset:	Offset of the Last data register of the thread
45*91f16700Schasinglulu  */
46*91f16700Schasinglulu struct k3_sec_proxy_desc {
47*91f16700Schasinglulu 	uint32_t timeout_us;
48*91f16700Schasinglulu 	uint16_t max_msg_size;
49*91f16700Schasinglulu 	uint16_t data_start_offset;
50*91f16700Schasinglulu 	uint16_t data_end_offset;
51*91f16700Schasinglulu };
52*91f16700Schasinglulu 
53*91f16700Schasinglulu /**
54*91f16700Schasinglulu  * struct k3_sec_proxy_thread - Description of a Secure Proxy Thread
55*91f16700Schasinglulu  * @name:	Thread Name
56*91f16700Schasinglulu  * @data:	Thread Data path region for target
57*91f16700Schasinglulu  * @scfg:	Secure Config Region for Thread
58*91f16700Schasinglulu  * @rt:		RealTime Region for Thread
59*91f16700Schasinglulu  */
60*91f16700Schasinglulu struct k3_sec_proxy_thread {
61*91f16700Schasinglulu 	const char *name;
62*91f16700Schasinglulu 	uintptr_t data;
63*91f16700Schasinglulu 	uintptr_t scfg;
64*91f16700Schasinglulu 	uintptr_t rt;
65*91f16700Schasinglulu };
66*91f16700Schasinglulu 
67*91f16700Schasinglulu /**
68*91f16700Schasinglulu  * struct k3_sec_proxy_mbox - Description of a Secure Proxy Instance
69*91f16700Schasinglulu  * @desc:	Description of the SoC integration
70*91f16700Schasinglulu  * @chans:	Array for valid thread instances
71*91f16700Schasinglulu  */
72*91f16700Schasinglulu struct k3_sec_proxy_mbox {
73*91f16700Schasinglulu 	const struct k3_sec_proxy_desc desc;
74*91f16700Schasinglulu 	struct k3_sec_proxy_thread threads[];
75*91f16700Schasinglulu };
76*91f16700Schasinglulu 
77*91f16700Schasinglulu /*
78*91f16700Schasinglulu  * Thread ID #0: DMSC notify
79*91f16700Schasinglulu  * Thread ID #1: DMSC request response
80*91f16700Schasinglulu  * Thread ID #2: DMSC request high priority
81*91f16700Schasinglulu  * Thread ID #3: DMSC request low priority
82*91f16700Schasinglulu  * Thread ID #4: DMSC notify response
83*91f16700Schasinglulu  */
84*91f16700Schasinglulu #define SP_THREAD(_x) \
85*91f16700Schasinglulu 	[_x] = { \
86*91f16700Schasinglulu 		.name = #_x, \
87*91f16700Schasinglulu 		.data = SEC_PROXY_THREAD(SEC_PROXY_DATA_BASE, _x), \
88*91f16700Schasinglulu 		.scfg = SEC_PROXY_THREAD(SEC_PROXY_SCFG_BASE, _x), \
89*91f16700Schasinglulu 		.rt = SEC_PROXY_THREAD(SEC_PROXY_RT_BASE, _x), \
90*91f16700Schasinglulu 	}
91*91f16700Schasinglulu 
92*91f16700Schasinglulu static struct k3_sec_proxy_mbox spm = {
93*91f16700Schasinglulu 	.desc = {
94*91f16700Schasinglulu 		.timeout_us = SEC_PROXY_TIMEOUT_US,
95*91f16700Schasinglulu 		.max_msg_size = SEC_PROXY_MAX_MESSAGE_SIZE,
96*91f16700Schasinglulu 		.data_start_offset = 0x4,
97*91f16700Schasinglulu 		.data_end_offset = 0x3C,
98*91f16700Schasinglulu 	},
99*91f16700Schasinglulu 	.threads = {
100*91f16700Schasinglulu #if !K3_SEC_PROXY_LITE
101*91f16700Schasinglulu 		SP_THREAD(SP_NOTIFY),
102*91f16700Schasinglulu 		SP_THREAD(SP_RESPONSE),
103*91f16700Schasinglulu 		SP_THREAD(SP_HIGH_PRIORITY),
104*91f16700Schasinglulu 		SP_THREAD(SP_LOW_PRIORITY),
105*91f16700Schasinglulu 		SP_THREAD(SP_NOTIFY_RESP),
106*91f16700Schasinglulu #else
107*91f16700Schasinglulu 		SP_THREAD(SP_RESPONSE),
108*91f16700Schasinglulu 		SP_THREAD(SP_HIGH_PRIORITY),
109*91f16700Schasinglulu #endif /* K3_SEC_PROXY_LITE */
110*91f16700Schasinglulu 	},
111*91f16700Schasinglulu };
112*91f16700Schasinglulu 
113*91f16700Schasinglulu /**
114*91f16700Schasinglulu  * struct sec_msg_hdr - Message header for secure messages and responses
115*91f16700Schasinglulu  * @checksum:	CRC of message for integrity checking
116*91f16700Schasinglulu  */
117*91f16700Schasinglulu union sec_msg_hdr {
118*91f16700Schasinglulu 	struct {
119*91f16700Schasinglulu 		uint16_t checksum;
120*91f16700Schasinglulu 		uint16_t reserved;
121*91f16700Schasinglulu 	} __packed;
122*91f16700Schasinglulu 	uint32_t data;
123*91f16700Schasinglulu };
124*91f16700Schasinglulu 
125*91f16700Schasinglulu /**
126*91f16700Schasinglulu  * k3_sec_proxy_verify_thread() - Verify thread status before
127*91f16700Schasinglulu  *				  sending/receiving data
128*91f16700Schasinglulu  * @spt: Pointer to Secure Proxy thread description
129*91f16700Schasinglulu  * @dir: Direction of the thread
130*91f16700Schasinglulu  *
131*91f16700Schasinglulu  * Return: 0 if all goes well, else appropriate error message
132*91f16700Schasinglulu  */
133*91f16700Schasinglulu static int k3_sec_proxy_verify_thread(struct k3_sec_proxy_thread *spt,
134*91f16700Schasinglulu 					     uint32_t dir)
135*91f16700Schasinglulu {
136*91f16700Schasinglulu 	/* Check for any errors already available */
137*91f16700Schasinglulu 	if (mmio_read_32(spt->rt + RT_THREAD_STATUS) &
138*91f16700Schasinglulu 	    RT_THREAD_STATUS_ERROR_MASK) {
139*91f16700Schasinglulu 		ERROR("Thread %s is corrupted, cannot send data\n", spt->name);
140*91f16700Schasinglulu 		return -EINVAL;
141*91f16700Schasinglulu 	}
142*91f16700Schasinglulu 
143*91f16700Schasinglulu 	/* Make sure thread is configured for right direction */
144*91f16700Schasinglulu 	if ((mmio_read_32(spt->scfg + SCFG_THREAD_CTRL) & SCFG_THREAD_CTRL_DIR_MASK)
145*91f16700Schasinglulu 	    != (dir << SCFG_THREAD_CTRL_DIR_SHIFT)) {
146*91f16700Schasinglulu 		if (dir == THREAD_IS_TX)
147*91f16700Schasinglulu 			ERROR("Trying to send data on RX Thread %s\n",
148*91f16700Schasinglulu 			      spt->name);
149*91f16700Schasinglulu 		else
150*91f16700Schasinglulu 			ERROR("Trying to receive data on TX Thread %s\n",
151*91f16700Schasinglulu 			      spt->name);
152*91f16700Schasinglulu 		return -EINVAL;
153*91f16700Schasinglulu 	}
154*91f16700Schasinglulu 
155*91f16700Schasinglulu 	/* Check the message queue before sending/receiving data */
156*91f16700Schasinglulu 	uint32_t tick_start = (uint32_t)read_cntpct_el0();
157*91f16700Schasinglulu 	uint32_t ticks_per_us = SYS_COUNTER_FREQ_IN_TICKS / 1000000;
158*91f16700Schasinglulu 	while (!(mmio_read_32(spt->rt + RT_THREAD_STATUS) & RT_THREAD_STATUS_CUR_CNT_MASK)) {
159*91f16700Schasinglulu 		VERBOSE("Waiting for thread %s to %s\n",
160*91f16700Schasinglulu 			spt->name, (dir == THREAD_IS_TX) ? "empty" : "fill");
161*91f16700Schasinglulu 		if (((uint32_t)read_cntpct_el0() - tick_start) >
162*91f16700Schasinglulu 		    (spm.desc.timeout_us * ticks_per_us)) {
163*91f16700Schasinglulu 			ERROR("Timeout waiting for thread %s to %s\n",
164*91f16700Schasinglulu 				spt->name, (dir == THREAD_IS_TX) ? "empty" : "fill");
165*91f16700Schasinglulu 			return -ETIMEDOUT;
166*91f16700Schasinglulu 		}
167*91f16700Schasinglulu 	}
168*91f16700Schasinglulu 
169*91f16700Schasinglulu 	return 0;
170*91f16700Schasinglulu }
171*91f16700Schasinglulu 
172*91f16700Schasinglulu /**
173*91f16700Schasinglulu  * k3_sec_proxy_clear_rx_thread() - Clear Secure Proxy thread
174*91f16700Schasinglulu  *
175*91f16700Schasinglulu  * @id: Channel Identifier
176*91f16700Schasinglulu  *
177*91f16700Schasinglulu  * Return: 0 if all goes well, else appropriate error message
178*91f16700Schasinglulu  */
179*91f16700Schasinglulu int k3_sec_proxy_clear_rx_thread(enum k3_sec_proxy_chan_id id)
180*91f16700Schasinglulu {
181*91f16700Schasinglulu 	struct k3_sec_proxy_thread *spt = &spm.threads[id];
182*91f16700Schasinglulu 
183*91f16700Schasinglulu 	/* Check for any errors already available */
184*91f16700Schasinglulu 	if (mmio_read_32(spt->rt + RT_THREAD_STATUS) &
185*91f16700Schasinglulu 	    RT_THREAD_STATUS_ERROR_MASK) {
186*91f16700Schasinglulu 		ERROR("Thread %s is corrupted, cannot send data\n", spt->name);
187*91f16700Schasinglulu 		return -EINVAL;
188*91f16700Schasinglulu 	}
189*91f16700Schasinglulu 
190*91f16700Schasinglulu 	/* Make sure thread is configured for right direction */
191*91f16700Schasinglulu 	if (!(mmio_read_32(spt->scfg + SCFG_THREAD_CTRL) & SCFG_THREAD_CTRL_DIR_MASK)) {
192*91f16700Schasinglulu 		ERROR("Cannot clear a transmit thread %s\n", spt->name);
193*91f16700Schasinglulu 		return -EINVAL;
194*91f16700Schasinglulu 	}
195*91f16700Schasinglulu 
196*91f16700Schasinglulu 	/* Read off messages from thread until empty */
197*91f16700Schasinglulu 	uint32_t try_count = 10;
198*91f16700Schasinglulu 	while (mmio_read_32(spt->rt + RT_THREAD_STATUS) & RT_THREAD_STATUS_CUR_CNT_MASK) {
199*91f16700Schasinglulu 		if (!(try_count--)) {
200*91f16700Schasinglulu 			ERROR("Could not clear all messages from thread %s\n", spt->name);
201*91f16700Schasinglulu 			return -ETIMEDOUT;
202*91f16700Schasinglulu 		}
203*91f16700Schasinglulu 		WARN("Clearing message from thread %s\n", spt->name);
204*91f16700Schasinglulu 		mmio_read_32(spt->data + spm.desc.data_end_offset);
205*91f16700Schasinglulu 	}
206*91f16700Schasinglulu 
207*91f16700Schasinglulu 	return 0;
208*91f16700Schasinglulu }
209*91f16700Schasinglulu 
210*91f16700Schasinglulu /**
211*91f16700Schasinglulu  * k3_sec_proxy_send() - Send data over a Secure Proxy thread
212*91f16700Schasinglulu  * @id: Channel Identifier
213*91f16700Schasinglulu  * @msg: Pointer to k3_sec_proxy_msg
214*91f16700Schasinglulu  *
215*91f16700Schasinglulu  * Return: 0 if all goes well, else appropriate error message
216*91f16700Schasinglulu  */
217*91f16700Schasinglulu int k3_sec_proxy_send(enum k3_sec_proxy_chan_id id, const struct k3_sec_proxy_msg *msg)
218*91f16700Schasinglulu {
219*91f16700Schasinglulu 	struct k3_sec_proxy_thread *spt = &spm.threads[id];
220*91f16700Schasinglulu 	union sec_msg_hdr secure_header;
221*91f16700Schasinglulu 	int num_words, trail_bytes, i, ret;
222*91f16700Schasinglulu 	uintptr_t data_reg;
223*91f16700Schasinglulu 
224*91f16700Schasinglulu 	ret = k3_sec_proxy_verify_thread(spt, THREAD_IS_TX);
225*91f16700Schasinglulu 	if (ret) {
226*91f16700Schasinglulu 		ERROR("Thread %s verification failed (%d)\n", spt->name, ret);
227*91f16700Schasinglulu 		return ret;
228*91f16700Schasinglulu 	}
229*91f16700Schasinglulu 
230*91f16700Schasinglulu 	/* Check the message size */
231*91f16700Schasinglulu 	if (msg->len + sizeof(secure_header) > spm.desc.max_msg_size) {
232*91f16700Schasinglulu 		ERROR("Thread %s message length %lu > max msg size\n",
233*91f16700Schasinglulu 		      spt->name, msg->len);
234*91f16700Schasinglulu 		return -EINVAL;
235*91f16700Schasinglulu 	}
236*91f16700Schasinglulu 
237*91f16700Schasinglulu 	/* TODO: Calculate checksum */
238*91f16700Schasinglulu 	secure_header.checksum = 0;
239*91f16700Schasinglulu 
240*91f16700Schasinglulu 	/* Send the secure header */
241*91f16700Schasinglulu 	data_reg = spm.desc.data_start_offset;
242*91f16700Schasinglulu 	mmio_write_32(spt->data + data_reg, secure_header.data);
243*91f16700Schasinglulu 	data_reg += sizeof(uint32_t);
244*91f16700Schasinglulu 
245*91f16700Schasinglulu 	/* Send whole words */
246*91f16700Schasinglulu 	num_words = msg->len / sizeof(uint32_t);
247*91f16700Schasinglulu 	for (i = 0; i < num_words; i++) {
248*91f16700Schasinglulu 		mmio_write_32(spt->data + data_reg, ((uint32_t *)msg->buf)[i]);
249*91f16700Schasinglulu 		data_reg += sizeof(uint32_t);
250*91f16700Schasinglulu 	}
251*91f16700Schasinglulu 
252*91f16700Schasinglulu 	/* Send remaining bytes */
253*91f16700Schasinglulu 	trail_bytes = msg->len % sizeof(uint32_t);
254*91f16700Schasinglulu 	if (trail_bytes) {
255*91f16700Schasinglulu 		uint32_t data_trail = 0;
256*91f16700Schasinglulu 
257*91f16700Schasinglulu 		i = msg->len - trail_bytes;
258*91f16700Schasinglulu 		while (trail_bytes--) {
259*91f16700Schasinglulu 			data_trail <<= 8;
260*91f16700Schasinglulu 			data_trail |= msg->buf[i++];
261*91f16700Schasinglulu 		}
262*91f16700Schasinglulu 
263*91f16700Schasinglulu 		mmio_write_32(spt->data + data_reg, data_trail);
264*91f16700Schasinglulu 		data_reg += sizeof(uint32_t);
265*91f16700Schasinglulu 	}
266*91f16700Schasinglulu 	/*
267*91f16700Schasinglulu 	 * 'data_reg' indicates next register to write. If we did not already
268*91f16700Schasinglulu 	 * write on tx complete reg(last reg), we must do so for transmit
269*91f16700Schasinglulu 	 * In addition, we also need to make sure all intermediate data
270*91f16700Schasinglulu 	 * registers(if any required), are reset to 0 for TISCI backward
271*91f16700Schasinglulu 	 * compatibility to be maintained.
272*91f16700Schasinglulu 	 */
273*91f16700Schasinglulu 	while (data_reg <= spm.desc.data_end_offset) {
274*91f16700Schasinglulu 		mmio_write_32(spt->data + data_reg, 0);
275*91f16700Schasinglulu 		data_reg += sizeof(uint32_t);
276*91f16700Schasinglulu 	}
277*91f16700Schasinglulu 
278*91f16700Schasinglulu 	VERBOSE("Message successfully sent on thread %s\n", spt->name);
279*91f16700Schasinglulu 
280*91f16700Schasinglulu 	return 0;
281*91f16700Schasinglulu }
282*91f16700Schasinglulu 
283*91f16700Schasinglulu /**
284*91f16700Schasinglulu  * k3_sec_proxy_recv() - Receive data from a Secure Proxy thread
285*91f16700Schasinglulu  * @id: Channel Identifier
286*91f16700Schasinglulu  * @msg: Pointer to k3_sec_proxy_msg
287*91f16700Schasinglulu  *
288*91f16700Schasinglulu  * Return: 0 if all goes well, else appropriate error message
289*91f16700Schasinglulu  */
290*91f16700Schasinglulu int k3_sec_proxy_recv(enum k3_sec_proxy_chan_id id, struct k3_sec_proxy_msg *msg)
291*91f16700Schasinglulu {
292*91f16700Schasinglulu 	struct k3_sec_proxy_thread *spt = &spm.threads[id];
293*91f16700Schasinglulu 	union sec_msg_hdr secure_header;
294*91f16700Schasinglulu 	uintptr_t data_reg;
295*91f16700Schasinglulu 	int num_words, trail_bytes, i, ret;
296*91f16700Schasinglulu 
297*91f16700Schasinglulu 	ret = k3_sec_proxy_verify_thread(spt, THREAD_IS_RX);
298*91f16700Schasinglulu 	if (ret) {
299*91f16700Schasinglulu 		ERROR("Thread %s verification failed (%d)\n", spt->name, ret);
300*91f16700Schasinglulu 		return ret;
301*91f16700Schasinglulu 	}
302*91f16700Schasinglulu 
303*91f16700Schasinglulu 	/* Read secure header */
304*91f16700Schasinglulu 	data_reg = spm.desc.data_start_offset;
305*91f16700Schasinglulu 	secure_header.data = mmio_read_32(spt->data + data_reg);
306*91f16700Schasinglulu 	data_reg += sizeof(uint32_t);
307*91f16700Schasinglulu 
308*91f16700Schasinglulu 	/* Read whole words */
309*91f16700Schasinglulu 	num_words = msg->len / sizeof(uint32_t);
310*91f16700Schasinglulu 	for (i = 0; i < num_words; i++) {
311*91f16700Schasinglulu 		((uint32_t *)msg->buf)[i] = mmio_read_32(spt->data + data_reg);
312*91f16700Schasinglulu 		data_reg += sizeof(uint32_t);
313*91f16700Schasinglulu 	}
314*91f16700Schasinglulu 
315*91f16700Schasinglulu 	/* Read remaining bytes */
316*91f16700Schasinglulu 	trail_bytes = msg->len % sizeof(uint32_t);
317*91f16700Schasinglulu 	if (trail_bytes) {
318*91f16700Schasinglulu 		uint32_t data_trail = mmio_read_32(spt->data + data_reg);
319*91f16700Schasinglulu 		data_reg += sizeof(uint32_t);
320*91f16700Schasinglulu 
321*91f16700Schasinglulu 		i = msg->len - trail_bytes;
322*91f16700Schasinglulu 		while (trail_bytes--) {
323*91f16700Schasinglulu 			msg->buf[i] = data_trail & 0xff;
324*91f16700Schasinglulu 			data_trail >>= 8;
325*91f16700Schasinglulu 		}
326*91f16700Schasinglulu 	}
327*91f16700Schasinglulu 
328*91f16700Schasinglulu 	/*
329*91f16700Schasinglulu 	 * 'data_reg' indicates next register to read. If we did not already
330*91f16700Schasinglulu 	 * read on rx complete reg(last reg), we must do so for receive
331*91f16700Schasinglulu 	 */
332*91f16700Schasinglulu 	if (data_reg <= spm.desc.data_end_offset)
333*91f16700Schasinglulu 		mmio_read_32(spt->data + spm.desc.data_end_offset);
334*91f16700Schasinglulu 
335*91f16700Schasinglulu 	/* TODO: Verify checksum */
336*91f16700Schasinglulu 	(void)secure_header.checksum;
337*91f16700Schasinglulu 
338*91f16700Schasinglulu 	VERBOSE("Message successfully received from thread %s\n", spt->name);
339*91f16700Schasinglulu 
340*91f16700Schasinglulu 	return 0;
341*91f16700Schasinglulu }
342