xref: /rk3399_ARM-atf/drivers/ti/ipc/sec_proxy.c (revision 52e486f6a6192bd18d36cdcbc35c59092eefc810)
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  * k3_sec_proxy_verify_thread() - Verify thread status before
107  *				  sending/receiving data
108  * @spt: Pointer to Secure Proxy thread description
109  * @dir: Direction of the thread
110  *
111  * Return: 0 if all goes well, else appropriate error message
112  */
113 static int k3_sec_proxy_verify_thread(struct k3_sec_proxy_thread *spt,
114 					     uint32_t dir)
115 {
116 	/* Check for any errors already available */
117 	if (mmio_read_32(spt->rt + RT_THREAD_STATUS) &
118 	    RT_THREAD_STATUS_ERROR_MASK) {
119 		ERROR("Thread %s is corrupted, cannot send data\n", spt->name);
120 		return -EINVAL;
121 	}
122 
123 	/* Make sure thread is configured for right direction */
124 	if ((mmio_read_32(spt->scfg + SCFG_THREAD_CTRL) & SCFG_THREAD_CTRL_DIR_MASK)
125 	    != (dir << SCFG_THREAD_CTRL_DIR_SHIFT)) {
126 		if (dir == THREAD_IS_TX)
127 			ERROR("Trying to send data on RX Thread %s\n",
128 			      spt->name);
129 		else
130 			ERROR("Trying to receive data on TX Thread %s\n",
131 			      spt->name);
132 		return -EINVAL;
133 	}
134 
135 	/* Check the message queue before sending/receiving data */
136 	uint32_t tick_start = (uint32_t)read_cntpct_el0();
137 	uint32_t ticks_per_us = SYS_COUNTER_FREQ_IN_TICKS / 1000000;
138 	while (!(mmio_read_32(spt->rt + RT_THREAD_STATUS) & RT_THREAD_STATUS_CUR_CNT_MASK)) {
139 		VERBOSE("Waiting for thread %s to %s\n",
140 			spt->name, (dir == THREAD_IS_TX) ? "empty" : "fill");
141 		if (((uint32_t)read_cntpct_el0() - tick_start) >
142 		    (spm.desc.timeout_us * ticks_per_us)) {
143 			ERROR("Timeout waiting for thread %s to %s\n",
144 				spt->name, (dir == THREAD_IS_TX) ? "empty" : "fill");
145 			return -ETIMEDOUT;
146 		}
147 	}
148 
149 	return 0;
150 }
151 
152 /**
153  * ti_sci_transport_clear_rx_thread() - Clear Secure Proxy thread
154  *
155  * @id: Channel Identifier
156  *
157  * Return: 0 if all goes well, else appropriate error message
158  */
159 int ti_sci_transport_clear_rx_thread(enum ti_sci_transport_chan_id id)
160 {
161 	struct k3_sec_proxy_thread *spt = &spm.threads[id];
162 
163 	/* Check for any errors already available */
164 	if (mmio_read_32(spt->rt + RT_THREAD_STATUS) &
165 	    RT_THREAD_STATUS_ERROR_MASK) {
166 		ERROR("Thread %s is corrupted, cannot send data\n", spt->name);
167 		return -EINVAL;
168 	}
169 
170 	/* Make sure thread is configured for right direction */
171 	if (!(mmio_read_32(spt->scfg + SCFG_THREAD_CTRL) & SCFG_THREAD_CTRL_DIR_MASK)) {
172 		ERROR("Cannot clear a transmit thread %s\n", spt->name);
173 		return -EINVAL;
174 	}
175 
176 	/* Read off messages from thread until empty */
177 	uint32_t try_count = 10;
178 	while (mmio_read_32(spt->rt + RT_THREAD_STATUS) & RT_THREAD_STATUS_CUR_CNT_MASK) {
179 		if (!(try_count--)) {
180 			ERROR("Could not clear all messages from thread %s\n", spt->name);
181 			return -ETIMEDOUT;
182 		}
183 		WARN("Clearing message from thread %s\n", spt->name);
184 		mmio_read_32(spt->data + spm.desc.data_end_offset);
185 	}
186 
187 	return 0;
188 }
189 
190 /**
191  * ti_sci_transport_send() - Send data over a Secure Proxy thread
192  * @id: Channel Identifier
193  * @msg: Pointer to ti_sci_msg
194  *
195  * Return: 0 if all goes well, else appropriate error message
196  */
197 int ti_sci_transport_send(enum ti_sci_transport_chan_id id, const struct ti_sci_msg *msg)
198 {
199 	struct k3_sec_proxy_thread *spt = &spm.threads[id];
200 	int num_words, trail_bytes, i, ret;
201 	uintptr_t data_reg;
202 
203 	ret = k3_sec_proxy_verify_thread(spt, THREAD_IS_TX);
204 	if (ret) {
205 		ERROR("Thread %s verification failed (%d)\n", spt->name, ret);
206 		return ret;
207 	}
208 
209 	/* Check the message size */
210 	if (msg->len > spm.desc.max_msg_size) {
211 		ERROR("Thread %s message length %lu > max msg size\n",
212 		      spt->name, msg->len);
213 		return -EINVAL;
214 	}
215 
216 	data_reg = spm.desc.data_start_offset;
217 
218 	/* Send whole words */
219 	num_words = msg->len / sizeof(uint32_t);
220 	for (i = 0; i < num_words; i++) {
221 		mmio_write_32(spt->data + data_reg, ((uint32_t *)msg->buf)[i]);
222 		data_reg += sizeof(uint32_t);
223 	}
224 
225 	/* Send remaining bytes */
226 	trail_bytes = msg->len % sizeof(uint32_t);
227 	if (trail_bytes) {
228 		uint32_t data_trail = 0;
229 
230 		i = msg->len - trail_bytes;
231 		while (trail_bytes--) {
232 			data_trail <<= 8;
233 			data_trail |= msg->buf[i++];
234 		}
235 
236 		mmio_write_32(spt->data + data_reg, data_trail);
237 		data_reg += sizeof(uint32_t);
238 	}
239 	/*
240 	 * 'data_reg' indicates next register to write. If we did not already
241 	 * write on tx complete reg(last reg), we must do so for transmit
242 	 * In addition, we also need to make sure all intermediate data
243 	 * registers(if any required), are reset to 0 for TISCI backward
244 	 * compatibility to be maintained.
245 	 */
246 	while (data_reg <= spm.desc.data_end_offset) {
247 		mmio_write_32(spt->data + data_reg, 0);
248 		data_reg += sizeof(uint32_t);
249 	}
250 
251 	VERBOSE("Message successfully sent on thread %s\n", spt->name);
252 
253 	return 0;
254 }
255 
256 /**
257  * ti_sci_transport_recv() - Receive data from a Secure Proxy thread
258  * @id: Channel Identifier
259  * @msg: Pointer to ti_sci_msg
260  *
261  * Return: 0 if all goes well, else appropriate error message
262  */
263 int ti_sci_transport_recv(enum ti_sci_transport_chan_id id, struct ti_sci_msg *msg)
264 {
265 	struct k3_sec_proxy_thread *spt = &spm.threads[id];
266 	uintptr_t data_reg;
267 	int num_words, trail_bytes, i, ret;
268 
269 	ret = k3_sec_proxy_verify_thread(spt, THREAD_IS_RX);
270 	if (ret) {
271 		ERROR("Thread %s verification failed (%d)\n", spt->name, ret);
272 		return ret;
273 	}
274 
275 	data_reg = spm.desc.data_start_offset;
276 
277 	/* Read whole words */
278 	num_words = msg->len / sizeof(uint32_t);
279 	for (i = 0; i < num_words; i++) {
280 		((uint32_t *)msg->buf)[i] = mmio_read_32(spt->data + data_reg);
281 		data_reg += sizeof(uint32_t);
282 	}
283 
284 	/* Read remaining bytes */
285 	trail_bytes = msg->len % sizeof(uint32_t);
286 	if (trail_bytes) {
287 		uint32_t data_trail = mmio_read_32(spt->data + data_reg);
288 		data_reg += sizeof(uint32_t);
289 
290 		i = msg->len - trail_bytes;
291 		while (trail_bytes--) {
292 			msg->buf[i++] = data_trail & 0xff;
293 			data_trail >>= 8;
294 		}
295 	}
296 
297 	/*
298 	 * 'data_reg' indicates next register to read. If we did not already
299 	 * read on rx complete reg(last reg), we must do so for receive
300 	 */
301 	if (data_reg <= spm.desc.data_end_offset)
302 		mmio_read_32(spt->data + spm.desc.data_end_offset);
303 
304 	VERBOSE("Message successfully received from thread %s\n", spt->name);
305 
306 	return 0;
307 }
308