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