1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3 * Texas Instruments K3 Secure Proxy Driver
4 *
5 * Copyright (C) 2022 Texas Instruments Incorporated - https://www.ti.com/
6 * Manorit Chawdhry <m-chawdhry@ti.com>
7 */
8
9 #include <io.h>
10 #include <kernel/delay.h>
11 #include <mm/core_memprot.h>
12 #include <mm/core_mmu.h>
13 #include <platform_config.h>
14 #include <stddef.h>
15 #include <stdint.h>
16 #include <string.h>
17 #include <trace.h>
18
19 #include "ti_sci_transport.h"
20
21 /* SEC PROXY RT THREAD STATUS */
22 #define RT_THREAD_STATUS_REG 0x0
23 #define RT_THREAD_STATUS_ERROR_MASK BIT(31)
24 #define RT_THREAD_STATUS_CUR_CNT_MASK GENMASK_32(7, 0)
25
26 /* SEC PROXY SCFG THREAD CTRL */
27 #define SCFG_THREAD_CTRL_REG 0x1000
28 #define SCFG_THREAD_CTRL_DIR_SHIFT 31
29 #define SCFG_THREAD_CTRL_DIR_MASK BIT(31)
30
31 /* SECURE PROXY GENERIC HELPERS */
32 enum threads {
33 SEC_PROXY_TX_THREAD,
34 SEC_PROXY_RX_THREAD,
35 SEC_PROXY_MAX_THREADS
36 };
37
38 #define SEC_PROXY_THREAD(base, x) ((base) + (0x1000 * (x)))
39 #define SEC_PROXY_DATA_START_OFFS 0x4
40 #define SEC_PROXY_DATA_END_OFFS 0x3c
41
42 #define THREAD_DIR_TX (0)
43 #define THREAD_DIR_RX (1)
44
45 #define SEC_PROXY_MAX_MSG_SIZE 56
46
47 /**
48 * struct k3_sec_proxy_thread - Description of a Secure Proxy Thread
49 * @id: Thread ID
50 * @data: Thread Data path region for target
51 * @scfg: Secure Config Region for Thread
52 * @rt: RealTime Region for Thread
53 */
54 struct k3_sec_proxy_thread {
55 const char *name;
56 vaddr_t data;
57 vaddr_t scfg;
58 vaddr_t rt;
59 } spts[SEC_PROXY_MAX_THREADS];
60
61 /**
62 * k3_sec_proxy_verify_thread() - Verify thread status before
63 * sending/receiving data
64 * @dir: Direction of the thread
65 */
k3_sec_proxy_verify_thread(uint32_t dir)66 static TEE_Result k3_sec_proxy_verify_thread(uint32_t dir)
67 {
68 struct k3_sec_proxy_thread *spt = &spts[dir];
69 uint64_t timeout = 0;
70 uint32_t val = 0;
71 unsigned int retry = 2;
72
73 FMSG("Check for thread corruption");
74 val = io_read32(spt->rt + RT_THREAD_STATUS_REG);
75
76 /* Check for any errors already available */
77 while ((val & RT_THREAD_STATUS_ERROR_MASK) && retry--) {
78 if (!retry) {
79 EMSG("Thread %s is corrupted, cannot send data.",
80 spt->name);
81 return TEE_ERROR_BAD_STATE;
82 }
83
84 /* Write Bit 0 to this location */
85 IMSG("Resetting proxy thread %s", spt->name);
86 val ^= RT_THREAD_STATUS_ERROR_MASK;
87 io_write32(spt->rt + RT_THREAD_STATUS_REG, val);
88 }
89
90 FMSG("Check for thread direction");
91 /* Make sure thread is configured for right direction */
92 if ((io_read32(spt->scfg + SCFG_THREAD_CTRL_REG) &
93 SCFG_THREAD_CTRL_DIR_MASK) >> SCFG_THREAD_CTRL_DIR_SHIFT != dir) {
94 if (dir == SEC_PROXY_TX_THREAD)
95 EMSG("Trying to receive data on tx Thread %s",
96 spt->name);
97 else
98 EMSG("Trying to send data on rx Thread %s", spt->name);
99 return TEE_ERROR_COMMUNICATION;
100 }
101
102 FMSG("Check for thread queue");
103 /* Check the message queue before sending/receiving data */
104 timeout = timeout_init_us(SEC_PROXY_TIMEOUT_US);
105 while (!(io_read32(spt->rt + RT_THREAD_STATUS_REG) &
106 RT_THREAD_STATUS_CUR_CNT_MASK)) {
107 DMSG("Waiting for thread %s to %s", spt->name,
108 (dir == THREAD_DIR_TX) ? "empty" : "fill");
109 if (timeout_elapsed(timeout)) {
110 EMSG("Queue is busy");
111 return TEE_ERROR_BUSY;
112 }
113 }
114
115 FMSG("Success");
116 return TEE_SUCCESS;
117 }
118
119 /**
120 * ti_sci_transport_send() - Send data over a TISCI transport
121 * @msg: Pointer to ti_sci_msg
122 */
ti_sci_transport_send(const struct ti_sci_msg * msg)123 TEE_Result ti_sci_transport_send(const struct ti_sci_msg *msg)
124 {
125 struct k3_sec_proxy_thread *spt = &spts[SEC_PROXY_TX_THREAD];
126 int num_words = 0;
127 int trail_bytes = 0;
128 int i = 0;
129 uintptr_t data_reg = 0;
130 uint32_t data_word = 0;
131 TEE_Result ret = TEE_SUCCESS;
132
133 FMSG("Verifying the thread");
134 ret = k3_sec_proxy_verify_thread(THREAD_DIR_TX);
135 if (ret) {
136 EMSG("Thread %s verification failed. ret = %d", spt->name, ret);
137 return ret;
138 }
139
140 /* Check the message size. */
141 if (msg->len > SEC_PROXY_MAX_MSG_SIZE) {
142 EMSG("Thread %s message length %zu > max msg size %d",
143 spt->name, msg->len, SEC_PROXY_MAX_MSG_SIZE);
144 return TEE_ERROR_BAD_STATE;
145 }
146
147 /* Send the message */
148 data_reg = spt->data + SEC_PROXY_DATA_START_OFFS;
149 num_words = msg->len / sizeof(uint32_t);
150 for (i = 0; i < num_words; i++) {
151 memcpy(&data_word, &msg->buf[i * 4], sizeof(uint32_t));
152 io_write32(data_reg, data_word);
153 data_reg += sizeof(uint32_t);
154 }
155
156 trail_bytes = msg->len % sizeof(uint32_t);
157 if (trail_bytes) {
158 uint32_t data_trail = 0;
159
160 i = msg->len - trail_bytes;
161 while (trail_bytes--) {
162 data_trail <<= 8;
163 data_trail |= msg->buf[i++];
164 }
165
166 io_write32(data_reg, data_trail);
167 data_reg += sizeof(uint32_t);
168 }
169
170 /*
171 * 'data_reg' indicates next register to write. If we did not already
172 * write on tx complete reg(last reg), we must do so for transmit
173 */
174 if (data_reg <= (spt->data + SEC_PROXY_DATA_END_OFFS))
175 io_write32(spt->data + SEC_PROXY_DATA_END_OFFS, 0);
176
177 return TEE_SUCCESS;
178 }
179
180 /**
181 * ti_sci_transport_recv() - Receive data from a TISCI transport
182 * @msg: Pointer to ti_sci_msg
183 */
ti_sci_transport_recv(struct ti_sci_msg * msg)184 TEE_Result ti_sci_transport_recv(struct ti_sci_msg *msg)
185 {
186 struct k3_sec_proxy_thread *spt = &spts[SEC_PROXY_RX_THREAD];
187 int num_words = 0;
188 int i = 0;
189 int trail_bytes = 0;
190 uint32_t data_trail = 0;
191 uint32_t data_word = 0;
192 uintptr_t data_reg = 0;
193 TEE_Result ret = TEE_SUCCESS;
194
195 FMSG("Verifying thread");
196 ret = k3_sec_proxy_verify_thread(THREAD_DIR_RX);
197 if (ret) {
198 EMSG("Thread %s verification failed. ret = %d", spt->name, ret);
199 return ret;
200 }
201
202 /* Receive the message */
203 data_reg = spt->data + SEC_PROXY_DATA_START_OFFS;
204 num_words = msg->len / sizeof(uint32_t);
205 for (i = 0; i < num_words; i++) {
206 data_word = io_read32(data_reg);
207 memcpy(&msg->buf[i * 4], &data_word, sizeof(uint32_t));
208 data_reg += sizeof(uint32_t);
209 }
210
211 trail_bytes = msg->len % sizeof(uint32_t);
212 if (trail_bytes) {
213 data_trail = io_read32(data_reg);
214 data_reg += sizeof(uint32_t);
215
216 i = msg->len - trail_bytes;
217 while (trail_bytes--) {
218 msg->buf[i++] = data_trail & 0xff;
219 data_trail >>= 8;
220 }
221 }
222
223 /*
224 * 'data_reg' indicates next register to read. If we did not already
225 * read on rx complete reg(last reg), we must do so for receive
226 */
227 if (data_reg <= (spt->data + SEC_PROXY_DATA_END_OFFS))
228 io_read32(spt->data + SEC_PROXY_DATA_END_OFFS);
229
230 return TEE_SUCCESS;
231 }
232
233 /**
234 * ti_sci_transport_init() - Initialize the TISCI transport threads
235 */
ti_sci_transport_init(void)236 TEE_Result ti_sci_transport_init(void)
237 {
238 struct k3_sec_proxy_thread *thread;
239 int rx_thread = SEC_PROXY_RESPONSE_THREAD;
240 int tx_thread = SEC_PROXY_REQUEST_THREAD;
241 uint32_t target_data = 0;
242 uint32_t cfg_scfg = 0;
243 uint32_t cfg_rt = 0;
244
245 DMSG("tx_thread: %d, rx_thread: %d", tx_thread, rx_thread);
246
247 /* TX_THREAD */
248 target_data = SEC_PROXY_THREAD(SEC_PROXY_DATA_BASE, tx_thread);
249 cfg_scfg = SEC_PROXY_THREAD(SEC_PROXY_SCFG_BASE, tx_thread);
250 cfg_rt = SEC_PROXY_THREAD(SEC_PROXY_RT_BASE, tx_thread);
251
252 thread = &spts[SEC_PROXY_TX_THREAD];
253 thread->name = "SEC_PROXY_LOW_PRIORITY_THREAD";
254
255 thread->data = core_mmu_get_va(target_data, MEM_AREA_IO_SEC,
256 SEC_PROXY_DATA_SIZE);
257 if (!thread->data)
258 return TEE_ERROR_OUT_OF_MEMORY;
259
260 thread->scfg = core_mmu_get_va(cfg_scfg, MEM_AREA_IO_SEC,
261 SEC_PROXY_SCFG_SIZE);
262 if (!thread->scfg)
263 return TEE_ERROR_OUT_OF_MEMORY;
264
265 thread->rt = core_mmu_get_va(cfg_rt, MEM_AREA_IO_SEC,
266 SEC_PROXY_RT_SIZE);
267 if (!thread->rt)
268 return TEE_ERROR_OUT_OF_MEMORY;
269
270 /* RX_THREAD */
271 target_data = SEC_PROXY_THREAD(SEC_PROXY_DATA_BASE, rx_thread);
272 cfg_scfg = SEC_PROXY_THREAD(SEC_PROXY_SCFG_BASE, rx_thread);
273 cfg_rt = SEC_PROXY_THREAD(SEC_PROXY_RT_BASE, rx_thread);
274
275 thread = &spts[SEC_PROXY_RX_THREAD];
276 thread->name = "SEC_PROXY_RESPONSE_THREAD";
277
278 thread->data = core_mmu_get_va(target_data, MEM_AREA_IO_SEC,
279 SEC_PROXY_DATA_SIZE);
280 if (!thread->data)
281 return TEE_ERROR_OUT_OF_MEMORY;
282
283 thread->scfg = core_mmu_get_va(cfg_scfg, MEM_AREA_IO_SEC,
284 SEC_PROXY_SCFG_SIZE);
285 if (!thread->scfg)
286 return TEE_ERROR_OUT_OF_MEMORY;
287
288 thread->rt = core_mmu_get_va(cfg_rt, MEM_AREA_IO_SEC,
289 SEC_PROXY_RT_SIZE);
290 if (!thread->rt)
291 return TEE_ERROR_OUT_OF_MEMORY;
292
293 return TEE_SUCCESS;
294 }
295