blob: 92414b9050f0ae1d82be1e5e08a28a3ffc7ce4be [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
10#include <arch_helpers.h>
11#include <debug.h>
12#include <errno.h>
13#include <mmio.h>
14#include <platform_def.h>
15#include <stdlib.h>
16#include <utils.h>
17#include <utils_def.h>
18
19#include "sec_proxy.h"
20
21/* SEC PROXY RT THREAD STATUS */
22#define RT_THREAD_STATUS (0x0)
23#define RT_THREAD_STATUS_ERROR_SHIFT (31)
24#define RT_THREAD_STATUS_ERROR_MASK BIT(31)
25#define RT_THREAD_STATUS_CUR_CNT_SHIFT (0)
26#define RT_THREAD_STATUS_CUR_CNT_MASK GENMASK(7, 0)
27
28/* SEC PROXY SCFG THREAD CTRL */
29#define SCFG_THREAD_CTRL (0x1000)
30#define SCFG_THREAD_CTRL_DIR_SHIFT (31)
31#define SCFG_THREAD_CTRL_DIR_MASK BIT(31)
32
33#define SEC_PROXY_THREAD(base, x) ((base) + (0x1000 * (x)))
34#define THREAD_IS_RX (1)
35#define THREAD_IS_TX (0)
36
37/**
38 * struct k3_sec_proxy_desc - Description of secure proxy integration
39 * @timeout_us: Timeout for communication (in Microseconds)
40 * @max_msg_size: Message size in bytes
41 * @data_start_offset: Offset of the First data register of the thread
42 * @data_end_offset: Offset of the Last data register of the thread
43 */
44struct k3_sec_proxy_desc {
45 uint32_t timeout_us;
46 uint16_t max_msg_size;
47 uint16_t data_start_offset;
48 uint16_t data_end_offset;
49};
50
51/**
52 * struct k3_sec_proxy_thread - Description of a secure proxy Thread
53 * @id: Thread ID
54 * @data: Thread Data path region for target
55 * @scfg: Secure Config Region for Thread
56 * @rt: RealTime Region for Thread
57 */
58struct k3_sec_proxy_thread {
59 uint32_t id;
60 uintptr_t data;
61 uintptr_t scfg;
62 uintptr_t rt;
63};
64
65/**
66 * struct k3_sec_proxy_mbox - Description of a Secure Proxy Instance
67 * @desc: Description of the SoC integration
68 * @chans: Array for valid thread instances
69 */
70struct k3_sec_proxy_mbox {
71 const struct k3_sec_proxy_desc desc;
72 struct k3_sec_proxy_thread threads[];
73};
74
75/*
76 * Thread ID #0: DMSC notify
77 * Thread ID #1: DMSC request response
78 * Thread ID #2: DMSC request high priority
79 * Thread ID #3: DMSC request low priority
80 * Thread ID #4: DMSC notify response
81 */
82#define SP_THREAD(_x) \
83 [_x] = { \
84 .id = _x, \
85 .data = SEC_PROXY_THREAD(SEC_PROXY_DATA_BASE, _x), \
86 .scfg = SEC_PROXY_THREAD(SEC_PROXY_SCFG_BASE, _x), \
87 .rt = SEC_PROXY_THREAD(SEC_PROXY_RT_BASE, _x), \
88 }
89
90static struct k3_sec_proxy_mbox spm = {
91 .desc = {
92 .timeout_us = SEC_PROXY_TIMEOUT_US,
93 .max_msg_size = SEC_PROXY_MAX_MESSAGE_SIZE,
94 .data_start_offset = 0x4,
95 .data_end_offset = 0x3C,
96 },
97 .threads = {
98 SP_THREAD(SP_NOTIFY),
99 SP_THREAD(SP_RESPONSE),
100 SP_THREAD(SP_HIGH_PRIORITY),
101 SP_THREAD(SP_LOW_PRIORITY),
102 SP_THREAD(SP_NOTIFY_RESP),
103 },
104};
105
106/**
107 * struct sec_msg_hdr - Message header for secure messages and responses
108 * @checksum: CRC of message for integrity checking
109 */
110union sec_msg_hdr {
111 struct {
112 uint16_t checksum;
113 uint16_t reserved;
114 } __packed;
115 uint32_t data;
116};
117
118/**
119 * k3_sec_proxy_verify_thread() - Verify thread status before
120 * sending/receiving data
121 * @spt: Pointer to Secure Proxy thread description
122 * @dir: Direction of the thread
123 *
124 * Return: 0 if all goes well, else appropriate error message
125 */
126static inline int k3_sec_proxy_verify_thread(struct k3_sec_proxy_thread *spt,
127 uint32_t dir)
128{
129 /* Check for any errors already available */
130 if (mmio_read_32(spt->rt + RT_THREAD_STATUS) &
131 RT_THREAD_STATUS_ERROR_MASK) {
132 ERROR("Thread %d is corrupted, cannot send data\n", spt->id);
133 return -EINVAL;
134 }
135
136 /* Make sure thread is configured for right direction */
137 if ((mmio_read_32(spt->scfg + SCFG_THREAD_CTRL) & SCFG_THREAD_CTRL_DIR_MASK)
138 != (dir << SCFG_THREAD_CTRL_DIR_SHIFT)) {
139 if (dir)
140 ERROR("Trying to receive data on tx Thread %d\n",
141 spt->id);
142 else
143 ERROR("Trying to send data on rx Thread %d\n",
144 spt->id);
145 return -EINVAL;
146 }
147
148 /* Check the message queue before sending/receiving data */
149 uint32_t tick_start = (uint32_t)read_cntpct_el0();
150 uint32_t ticks_per_us = SYS_COUNTER_FREQ_IN_TICKS / 1000000;
151 while (!(mmio_read_32(spt->rt + RT_THREAD_STATUS) & RT_THREAD_STATUS_CUR_CNT_MASK)) {
152 VERBOSE("Waiting for thread %d to clear\n", spt->id);
153 if (((uint32_t)read_cntpct_el0() - tick_start) >
154 (spm.desc.timeout_us * ticks_per_us)) {
155 ERROR("Timeout waiting for thread %d to clear\n", spt->id);
156 return -ETIMEDOUT;
157 }
158 }
159
160 return 0;
161}
162
163/**
164 * k3_sec_proxy_send() - Send data over a Secure Proxy thread
165 * @id: Channel Identifier
166 * @msg: Pointer to k3_sec_proxy_msg
167 *
168 * Return: 0 if all goes well, else appropriate error message
169 */
170int k3_sec_proxy_send(enum k3_sec_proxy_chan_id id, const struct k3_sec_proxy_msg *msg)
171{
172 struct k3_sec_proxy_thread *spt = &spm.threads[id];
173 union sec_msg_hdr secure_header;
174 int num_words, trail_bytes, i, ret;
175 uintptr_t data_reg;
176
177 ret = k3_sec_proxy_verify_thread(spt, THREAD_IS_TX);
178 if (ret) {
179 ERROR("Thread %d verification failed (%d)\n", spt->id, ret);
180 return ret;
181 }
182
183 /* Check the message size */
184 if (msg->len + sizeof(secure_header) > spm.desc.max_msg_size) {
185 ERROR("Thread %d message length %lu > max msg size\n",
186 spt->id, msg->len);
187 return -EINVAL;
188 }
189
190 /* TODO: Calculate checksum */
191 secure_header.checksum = 0;
192
193 /* Send the secure header */
194 data_reg = spm.desc.data_start_offset;
195 mmio_write_32(spt->data + data_reg, secure_header.data);
196 data_reg += sizeof(uint32_t);
197
198 /* Send whole words */
199 num_words = msg->len / sizeof(uint32_t);
200 for (i = 0; i < num_words; i++) {
201 mmio_write_32(spt->data + data_reg, ((uint32_t *)msg->buf)[i]);
202 data_reg += sizeof(uint32_t);
203 }
204
205 /* Send remaining bytes */
206 trail_bytes = msg->len % sizeof(uint32_t);
207 if (trail_bytes) {
208 uint32_t data_trail = 0;
209
210 i = msg->len - trail_bytes;
211 while (trail_bytes--) {
212 data_trail <<= 8;
213 data_trail |= msg->buf[i++];
214 }
215
216 mmio_write_32(spt->data + data_reg, data_trail);
217 data_reg += sizeof(uint32_t);
218 }
219 /*
220 * 'data_reg' indicates next register to write. If we did not already
221 * write on tx complete reg(last reg), we must do so for transmit
222 */
223 if (data_reg <= spm.desc.data_end_offset)
224 mmio_write_32(spt->data + spm.desc.data_end_offset, 0);
225
226 VERBOSE("Message successfully sent on thread %ud\n", id);
227
228 return 0;
229}
230
231/**
232 * k3_sec_proxy_recv() - Receive data from a Secure Proxy thread
233 * @id: Channel Identifier
234 * @msg: Pointer to k3_sec_proxy_msg
235 *
236 * Return: 0 if all goes well, else appropriate error message
237 */
238int k3_sec_proxy_recv(uint32_t id, struct k3_sec_proxy_msg *msg)
239{
240 struct k3_sec_proxy_thread *spt = &spm.threads[id];
241 union sec_msg_hdr secure_header;
242 uintptr_t data_reg;
243 int num_words, trail_bytes, i, ret;
244
245 ret = k3_sec_proxy_verify_thread(spt, THREAD_IS_RX);
246 if (ret) {
247 ERROR("Thread %d verification failed (%d)\n", spt->id, ret);
248 return ret;
249 }
250
251 /* Read secure header */
252 data_reg = spm.desc.data_start_offset;
253 secure_header.data = mmio_read_32(spt->data + data_reg);
254 data_reg += sizeof(uint32_t);
255
256 /* Read whole words */
257 num_words = msg->len / sizeof(uint32_t);
258 for (i = 0; i < num_words; i++) {
259 ((uint32_t *)msg->buf)[i] = mmio_read_32(spt->data + data_reg);
260 data_reg += sizeof(uint32_t);
261 }
262
263 /* Read remaining bytes */
264 trail_bytes = msg->len % sizeof(uint32_t);
265 if (trail_bytes) {
266 uint32_t data_trail = mmio_read_32(spt->data + data_reg);
267 data_reg += sizeof(uint32_t);
268
269 i = msg->len - trail_bytes;
270 while (trail_bytes--) {
271 msg->buf[i] = data_trail & 0xff;
272 data_trail >>= 8;
273 }
274 }
275
276 /*
277 * 'data_reg' indicates next register to read. If we did not already
278 * read on rx complete reg(last reg), we must do so for receive
279 */
280 if (data_reg <= spm.desc.data_end_offset)
281 mmio_read_32(spt->data + spm.desc.data_end_offset);
282
283 /* TODO: Verify checksum */
284 (void)secure_header.checksum;
285
286 VERBOSE("Message successfully received from thread %ud\n", id);
287
288 return 0;
289}