1 /*
2 * Texas Instruments K3 Secure Proxy Driver
3 * Based on Linux and U-Boot implementation
4 *
5 * Copyright (C) 2018 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 "sec_proxy.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 #if !K3_SEC_PROXY_LITE
101 SP_THREAD(SP_NOTIFY),
102 SP_THREAD(SP_RESPONSE),
103 SP_THREAD(SP_HIGH_PRIORITY),
104 SP_THREAD(SP_LOW_PRIORITY),
105 SP_THREAD(SP_NOTIFY_RESP),
106 #else
107 SP_THREAD(SP_RESPONSE),
108 SP_THREAD(SP_HIGH_PRIORITY),
109 #endif /* K3_SEC_PROXY_LITE */
110 },
111 };
112
113 /**
114 * struct sec_msg_hdr - Message header for secure messages and responses
115 * @checksum: CRC of message for integrity checking
116 */
117 union sec_msg_hdr {
118 struct {
119 uint16_t checksum;
120 uint16_t reserved;
121 } __packed;
122 uint32_t data;
123 };
124
125 /**
126 * k3_sec_proxy_verify_thread() - Verify thread status before
127 * sending/receiving data
128 * @spt: Pointer to Secure Proxy thread description
129 * @dir: Direction of the thread
130 *
131 * Return: 0 if all goes well, else appropriate error message
132 */
k3_sec_proxy_verify_thread(struct k3_sec_proxy_thread * spt,uint32_t dir)133 static inline int k3_sec_proxy_verify_thread(struct k3_sec_proxy_thread *spt,
134 uint32_t dir)
135 {
136 /* Check for any errors already available */
137 if (mmio_read_32(spt->rt + RT_THREAD_STATUS) &
138 RT_THREAD_STATUS_ERROR_MASK) {
139 ERROR("Thread %s is corrupted, cannot send data\n", spt->name);
140 return -EINVAL;
141 }
142
143 /* Make sure thread is configured for right direction */
144 if ((mmio_read_32(spt->scfg + SCFG_THREAD_CTRL) & SCFG_THREAD_CTRL_DIR_MASK)
145 != (dir << SCFG_THREAD_CTRL_DIR_SHIFT)) {
146 if (dir == THREAD_IS_TX)
147 ERROR("Trying to send data on RX Thread %s\n",
148 spt->name);
149 else
150 ERROR("Trying to receive data on TX Thread %s\n",
151 spt->name);
152 return -EINVAL;
153 }
154
155 /* Check the message queue before sending/receiving data */
156 uint32_t tick_start = (uint32_t)read_cntpct_el0();
157 uint32_t ticks_per_us = SYS_COUNTER_FREQ_IN_TICKS / 1000000;
158 while (!(mmio_read_32(spt->rt + RT_THREAD_STATUS) & RT_THREAD_STATUS_CUR_CNT_MASK)) {
159 VERBOSE("Waiting for thread %s to %s\n",
160 spt->name, (dir == THREAD_IS_TX) ? "empty" : "fill");
161 if (((uint32_t)read_cntpct_el0() - tick_start) >
162 (spm.desc.timeout_us * ticks_per_us)) {
163 ERROR("Timeout waiting for thread %s to %s\n",
164 spt->name, (dir == THREAD_IS_TX) ? "empty" : "fill");
165 return -ETIMEDOUT;
166 }
167 }
168
169 return 0;
170 }
171
172 /**
173 * k3_sec_proxy_clear_rx_thread() - Clear Secure Proxy thread
174 *
175 * @id: Channel Identifier
176 *
177 * Return: 0 if all goes well, else appropriate error message
178 */
k3_sec_proxy_clear_rx_thread(enum k3_sec_proxy_chan_id id)179 int k3_sec_proxy_clear_rx_thread(enum k3_sec_proxy_chan_id id)
180 {
181 struct k3_sec_proxy_thread *spt = &spm.threads[id];
182
183 /* Check for any errors already available */
184 if (mmio_read_32(spt->rt + RT_THREAD_STATUS) &
185 RT_THREAD_STATUS_ERROR_MASK) {
186 ERROR("Thread %s is corrupted, cannot send data\n", spt->name);
187 return -EINVAL;
188 }
189
190 /* Make sure thread is configured for right direction */
191 if (!(mmio_read_32(spt->scfg + SCFG_THREAD_CTRL) & SCFG_THREAD_CTRL_DIR_MASK)) {
192 ERROR("Cannot clear a transmit thread %s\n", spt->name);
193 return -EINVAL;
194 }
195
196 /* Read off messages from thread until empty */
197 uint32_t try_count = 10;
198 while (mmio_read_32(spt->rt + RT_THREAD_STATUS) & RT_THREAD_STATUS_CUR_CNT_MASK) {
199 if (!(try_count--)) {
200 ERROR("Could not clear all messages from thread %s\n", spt->name);
201 return -ETIMEDOUT;
202 }
203 WARN("Clearing message from thread %s\n", spt->name);
204 mmio_read_32(spt->data + spm.desc.data_end_offset);
205 }
206
207 return 0;
208 }
209
210 /**
211 * k3_sec_proxy_send() - Send data over a Secure Proxy thread
212 * @id: Channel Identifier
213 * @msg: Pointer to k3_sec_proxy_msg
214 *
215 * Return: 0 if all goes well, else appropriate error message
216 */
k3_sec_proxy_send(enum k3_sec_proxy_chan_id id,const struct k3_sec_proxy_msg * msg)217 int k3_sec_proxy_send(enum k3_sec_proxy_chan_id id, const struct k3_sec_proxy_msg *msg)
218 {
219 struct k3_sec_proxy_thread *spt = &spm.threads[id];
220 union sec_msg_hdr secure_header;
221 int num_words, trail_bytes, i, ret;
222 uintptr_t data_reg;
223
224 ret = k3_sec_proxy_verify_thread(spt, THREAD_IS_TX);
225 if (ret) {
226 ERROR("Thread %s verification failed (%d)\n", spt->name, ret);
227 return ret;
228 }
229
230 /* Check the message size */
231 if (msg->len + sizeof(secure_header) > spm.desc.max_msg_size) {
232 ERROR("Thread %s message length %lu > max msg size\n",
233 spt->name, msg->len);
234 return -EINVAL;
235 }
236
237 /* TODO: Calculate checksum */
238 secure_header.checksum = 0;
239
240 /* Send the secure header */
241 data_reg = spm.desc.data_start_offset;
242 mmio_write_32(spt->data + data_reg, secure_header.data);
243 data_reg += sizeof(uint32_t);
244
245 /* Send whole words */
246 num_words = msg->len / sizeof(uint32_t);
247 for (i = 0; i < num_words; i++) {
248 mmio_write_32(spt->data + data_reg, ((uint32_t *)msg->buf)[i]);
249 data_reg += sizeof(uint32_t);
250 }
251
252 /* Send remaining bytes */
253 trail_bytes = msg->len % sizeof(uint32_t);
254 if (trail_bytes) {
255 uint32_t data_trail = 0;
256
257 i = msg->len - trail_bytes;
258 while (trail_bytes--) {
259 data_trail <<= 8;
260 data_trail |= msg->buf[i++];
261 }
262
263 mmio_write_32(spt->data + data_reg, data_trail);
264 data_reg += sizeof(uint32_t);
265 }
266 /*
267 * 'data_reg' indicates next register to write. If we did not already
268 * write on tx complete reg(last reg), we must do so for transmit
269 * In addition, we also need to make sure all intermediate data
270 * registers(if any required), are reset to 0 for TISCI backward
271 * compatibility to be maintained.
272 */
273 while (data_reg <= spm.desc.data_end_offset) {
274 mmio_write_32(spt->data + data_reg, 0);
275 data_reg += sizeof(uint32_t);
276 }
277
278 VERBOSE("Message successfully sent on thread %s\n", spt->name);
279
280 return 0;
281 }
282
283 /**
284 * k3_sec_proxy_recv() - Receive data from a Secure Proxy thread
285 * @id: Channel Identifier
286 * @msg: Pointer to k3_sec_proxy_msg
287 *
288 * Return: 0 if all goes well, else appropriate error message
289 */
k3_sec_proxy_recv(enum k3_sec_proxy_chan_id id,struct k3_sec_proxy_msg * msg)290 int k3_sec_proxy_recv(enum k3_sec_proxy_chan_id id, struct k3_sec_proxy_msg *msg)
291 {
292 struct k3_sec_proxy_thread *spt = &spm.threads[id];
293 union sec_msg_hdr secure_header;
294 uintptr_t data_reg;
295 int num_words, trail_bytes, i, ret;
296
297 ret = k3_sec_proxy_verify_thread(spt, THREAD_IS_RX);
298 if (ret) {
299 ERROR("Thread %s verification failed (%d)\n", spt->name, ret);
300 return ret;
301 }
302
303 /* Read secure header */
304 data_reg = spm.desc.data_start_offset;
305 secure_header.data = mmio_read_32(spt->data + data_reg);
306 data_reg += sizeof(uint32_t);
307
308 /* Read whole words */
309 num_words = msg->len / sizeof(uint32_t);
310 for (i = 0; i < num_words; i++) {
311 ((uint32_t *)msg->buf)[i] = mmio_read_32(spt->data + data_reg);
312 data_reg += sizeof(uint32_t);
313 }
314
315 /* Read remaining bytes */
316 trail_bytes = msg->len % sizeof(uint32_t);
317 if (trail_bytes) {
318 uint32_t data_trail = mmio_read_32(spt->data + data_reg);
319 data_reg += sizeof(uint32_t);
320
321 i = msg->len - trail_bytes;
322 while (trail_bytes--) {
323 msg->buf[i] = data_trail & 0xff;
324 data_trail >>= 8;
325 }
326 }
327
328 /*
329 * 'data_reg' indicates next register to read. If we did not already
330 * read on rx complete reg(last reg), we must do so for receive
331 */
332 if (data_reg <= spm.desc.data_end_offset)
333 mmio_read_32(spt->data + spm.desc.data_end_offset);
334
335 /* TODO: Verify checksum */
336 (void)secure_header.checksum;
337
338 VERBOSE("Message successfully received from thread %s\n", spt->name);
339
340 return 0;
341 }
342