blob: 49cecd44cabbc57eea711097b605069d5665cb13 [file] [log] [blame]
Andrew F. Davis537d3ff2018-05-04 19:06:08 +00001/*
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
Andrew F. Davis537d3ff2018-05-04 19:06:08 +000010#include <errno.h>
Andrew F. Davis537d3ff2018-05-04 19:06:08 +000011#include <stdlib.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000012
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>
Andrew F. Davis537d3ff2018-05-04 19:06:08 +000020
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 */
46struct 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 * @id: Thread ID
56 * @data: Thread Data path region for target
57 * @scfg: Secure Config Region for Thread
58 * @rt: RealTime Region for Thread
59 */
60struct k3_sec_proxy_thread {
61 uint32_t id;
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 */
72struct 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 .id = _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
92static 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(SP_NOTIFY),
101 SP_THREAD(SP_RESPONSE),
102 SP_THREAD(SP_HIGH_PRIORITY),
103 SP_THREAD(SP_LOW_PRIORITY),
104 SP_THREAD(SP_NOTIFY_RESP),
105 },
106};
107
108/**
109 * struct sec_msg_hdr - Message header for secure messages and responses
110 * @checksum: CRC of message for integrity checking
111 */
112union sec_msg_hdr {
113 struct {
114 uint16_t checksum;
115 uint16_t reserved;
116 } __packed;
117 uint32_t data;
118};
119
120/**
121 * k3_sec_proxy_verify_thread() - Verify thread status before
122 * sending/receiving data
123 * @spt: Pointer to Secure Proxy thread description
124 * @dir: Direction of the thread
125 *
126 * Return: 0 if all goes well, else appropriate error message
127 */
128static inline int k3_sec_proxy_verify_thread(struct k3_sec_proxy_thread *spt,
129 uint32_t dir)
130{
131 /* Check for any errors already available */
132 if (mmio_read_32(spt->rt + RT_THREAD_STATUS) &
133 RT_THREAD_STATUS_ERROR_MASK) {
134 ERROR("Thread %d is corrupted, cannot send data\n", spt->id);
135 return -EINVAL;
136 }
137
138 /* Make sure thread is configured for right direction */
139 if ((mmio_read_32(spt->scfg + SCFG_THREAD_CTRL) & SCFG_THREAD_CTRL_DIR_MASK)
140 != (dir << SCFG_THREAD_CTRL_DIR_SHIFT)) {
141 if (dir)
Andrew F. Davisc9c67a52019-01-04 12:39:54 -0600142 ERROR("Trying to send data on RX Thread %d\n",
Andrew F. Davis537d3ff2018-05-04 19:06:08 +0000143 spt->id);
144 else
Andrew F. Davisc9c67a52019-01-04 12:39:54 -0600145 ERROR("Trying to receive data on TX Thread %d\n",
Andrew F. Davis537d3ff2018-05-04 19:06:08 +0000146 spt->id);
147 return -EINVAL;
148 }
149
150 /* Check the message queue before sending/receiving data */
151 uint32_t tick_start = (uint32_t)read_cntpct_el0();
152 uint32_t ticks_per_us = SYS_COUNTER_FREQ_IN_TICKS / 1000000;
153 while (!(mmio_read_32(spt->rt + RT_THREAD_STATUS) & RT_THREAD_STATUS_CUR_CNT_MASK)) {
154 VERBOSE("Waiting for thread %d to clear\n", spt->id);
155 if (((uint32_t)read_cntpct_el0() - tick_start) >
156 (spm.desc.timeout_us * ticks_per_us)) {
157 ERROR("Timeout waiting for thread %d to clear\n", spt->id);
158 return -ETIMEDOUT;
159 }
160 }
161
162 return 0;
163}
164
165/**
Andrew F. Davis82a3c1d2019-01-04 12:44:00 -0600166 * k3_sec_proxy_clear_rx_thread() - Clear Secure Proxy thread
167 *
168 * @id: Channel Identifier
169 *
170 * Return: 0 if all goes well, else appropriate error message
171 */
172int k3_sec_proxy_clear_rx_thread(enum k3_sec_proxy_chan_id id)
173{
174 struct k3_sec_proxy_thread *spt = &spm.threads[id];
175
176 /* Check for any errors already available */
177 if (mmio_read_32(spt->rt + RT_THREAD_STATUS) &
178 RT_THREAD_STATUS_ERROR_MASK) {
179 ERROR("Thread %d is corrupted, cannot send data\n", spt->id);
180 return -EINVAL;
181 }
182
183 /* Make sure thread is configured for right direction */
184 if (!(mmio_read_32(spt->scfg + SCFG_THREAD_CTRL) & SCFG_THREAD_CTRL_DIR_MASK)) {
185 ERROR("Cannot clear a transmit thread %d\n", spt->id);
186 return -EINVAL;
187 }
188
189 /* Read off messages from thread until empty */
190 uint32_t try_count = 10;
191 while (mmio_read_32(spt->rt + RT_THREAD_STATUS) & RT_THREAD_STATUS_CUR_CNT_MASK) {
192 if (!(try_count--)) {
193 ERROR("Could not clear all messages from thread %d\n", spt->id);
194 return -ETIMEDOUT;
195 }
196 WARN("Clearing message from thread %d\n", spt->id);
197 mmio_read_32(spt->data + spm.desc.data_end_offset);
198 }
199
200 return 0;
201}
202
203/**
Andrew F. Davis537d3ff2018-05-04 19:06:08 +0000204 * k3_sec_proxy_send() - Send data over a Secure Proxy thread
205 * @id: Channel Identifier
206 * @msg: Pointer to k3_sec_proxy_msg
207 *
208 * Return: 0 if all goes well, else appropriate error message
209 */
210int k3_sec_proxy_send(enum k3_sec_proxy_chan_id id, const struct k3_sec_proxy_msg *msg)
211{
212 struct k3_sec_proxy_thread *spt = &spm.threads[id];
213 union sec_msg_hdr secure_header;
214 int num_words, trail_bytes, i, ret;
215 uintptr_t data_reg;
216
217 ret = k3_sec_proxy_verify_thread(spt, THREAD_IS_TX);
218 if (ret) {
219 ERROR("Thread %d verification failed (%d)\n", spt->id, ret);
220 return ret;
221 }
222
223 /* Check the message size */
224 if (msg->len + sizeof(secure_header) > spm.desc.max_msg_size) {
225 ERROR("Thread %d message length %lu > max msg size\n",
226 spt->id, msg->len);
227 return -EINVAL;
228 }
229
230 /* TODO: Calculate checksum */
231 secure_header.checksum = 0;
232
233 /* Send the secure header */
234 data_reg = spm.desc.data_start_offset;
235 mmio_write_32(spt->data + data_reg, secure_header.data);
236 data_reg += sizeof(uint32_t);
237
238 /* Send whole words */
239 num_words = msg->len / sizeof(uint32_t);
240 for (i = 0; i < num_words; i++) {
241 mmio_write_32(spt->data + data_reg, ((uint32_t *)msg->buf)[i]);
242 data_reg += sizeof(uint32_t);
243 }
244
245 /* Send remaining bytes */
246 trail_bytes = msg->len % sizeof(uint32_t);
247 if (trail_bytes) {
248 uint32_t data_trail = 0;
249
250 i = msg->len - trail_bytes;
251 while (trail_bytes--) {
252 data_trail <<= 8;
253 data_trail |= msg->buf[i++];
254 }
255
256 mmio_write_32(spt->data + data_reg, data_trail);
257 data_reg += sizeof(uint32_t);
258 }
259 /*
260 * 'data_reg' indicates next register to write. If we did not already
261 * write on tx complete reg(last reg), we must do so for transmit
262 */
263 if (data_reg <= spm.desc.data_end_offset)
264 mmio_write_32(spt->data + spm.desc.data_end_offset, 0);
265
266 VERBOSE("Message successfully sent on thread %ud\n", id);
267
268 return 0;
269}
270
271/**
272 * k3_sec_proxy_recv() - Receive data from a Secure Proxy thread
273 * @id: Channel Identifier
274 * @msg: Pointer to k3_sec_proxy_msg
275 *
276 * Return: 0 if all goes well, else appropriate error message
277 */
278int k3_sec_proxy_recv(uint32_t id, struct k3_sec_proxy_msg *msg)
279{
280 struct k3_sec_proxy_thread *spt = &spm.threads[id];
281 union sec_msg_hdr secure_header;
282 uintptr_t data_reg;
283 int num_words, trail_bytes, i, ret;
284
285 ret = k3_sec_proxy_verify_thread(spt, THREAD_IS_RX);
286 if (ret) {
287 ERROR("Thread %d verification failed (%d)\n", spt->id, ret);
288 return ret;
289 }
290
291 /* Read secure header */
292 data_reg = spm.desc.data_start_offset;
293 secure_header.data = mmio_read_32(spt->data + data_reg);
294 data_reg += sizeof(uint32_t);
295
296 /* Read whole words */
297 num_words = msg->len / sizeof(uint32_t);
298 for (i = 0; i < num_words; i++) {
299 ((uint32_t *)msg->buf)[i] = mmio_read_32(spt->data + data_reg);
300 data_reg += sizeof(uint32_t);
301 }
302
303 /* Read remaining bytes */
304 trail_bytes = msg->len % sizeof(uint32_t);
305 if (trail_bytes) {
306 uint32_t data_trail = mmio_read_32(spt->data + data_reg);
307 data_reg += sizeof(uint32_t);
308
309 i = msg->len - trail_bytes;
310 while (trail_bytes--) {
311 msg->buf[i] = data_trail & 0xff;
312 data_trail >>= 8;
313 }
314 }
315
316 /*
317 * 'data_reg' indicates next register to read. If we did not already
318 * read on rx complete reg(last reg), we must do so for receive
319 */
320 if (data_reg <= spm.desc.data_end_offset)
321 mmio_read_32(spt->data + spm.desc.data_end_offset);
322
323 /* TODO: Verify checksum */
324 (void)secure_header.checksum;
325
326 VERBOSE("Message successfully received from thread %ud\n", id);
327
328 return 0;
329}