]>
Commit | Line | Data |
---|---|---|
f9aa4102 LV |
1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* | |
3 | * Texas Instruments' K3 Secure proxy Driver | |
4 | * | |
5 | * Copyright (C) 2017-2018 Texas Instruments Incorporated - http://www.ti.com/ | |
6 | * Lokesh Vutla <[email protected]> | |
7 | */ | |
8 | ||
9 | #include <common.h> | |
f7ae49fc | 10 | #include <log.h> |
336d4615 | 11 | #include <malloc.h> |
f9aa4102 | 12 | #include <asm/io.h> |
336d4615 | 13 | #include <dm/device_compat.h> |
f9aa4102 LV |
14 | #include <linux/types.h> |
15 | #include <linux/bitops.h> | |
16 | #include <linux/soc/ti/k3-sec-proxy.h> | |
17 | #include <dm.h> | |
18 | #include <mailbox-uclass.h> | |
19 | ||
20 | DECLARE_GLOBAL_DATA_PTR; | |
21 | ||
22 | /* SEC PROXY RT THREAD STATUS */ | |
23 | #define RT_THREAD_STATUS 0x0 | |
24 | #define RT_THREAD_THRESHOLD 0x4 | |
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 | * @thread_count: Number of Threads. | |
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 | * @valid_threads: List of Valid threads that the processor can access | |
46 | * @num_valid_threads: Number of valid threads. | |
47 | */ | |
48 | struct k3_sec_proxy_desc { | |
49 | u16 thread_count; | |
50 | u16 max_msg_size; | |
51 | u16 data_start_offset; | |
52 | u16 data_end_offset; | |
53 | const u32 *valid_threads; | |
54 | u32 num_valid_threads; | |
55 | }; | |
56 | ||
57 | /** | |
58 | * struct k3_sec_proxy_thread - Description of a secure proxy Thread | |
59 | * @id: Thread ID | |
60 | * @data: Thread Data path region for target | |
61 | * @scfg: Secure Config Region for Thread | |
62 | * @rt: RealTime Region for Thread | |
63 | * @rx_buf: Receive buffer data, max message size. | |
64 | */ | |
65 | struct k3_sec_proxy_thread { | |
66 | u32 id; | |
67 | void __iomem *data; | |
68 | void __iomem *scfg; | |
69 | void __iomem *rt; | |
70 | u32 *rx_buf; | |
71 | }; | |
72 | ||
73 | /** | |
74 | * struct k3_sec_proxy_mbox - Description of a Secure Proxy Instance | |
75 | * @chan: Mailbox Channel | |
76 | * @desc: Description of the SoC integration | |
77 | * @chans: Array for valid thread instances | |
78 | * @target_data: Secure Proxy region for Target Data | |
79 | * @scfg: Secure Proxy Region for Secure configuration. | |
80 | * @rt: Secure proxy Region for Real Time Region. | |
81 | */ | |
82 | struct k3_sec_proxy_mbox { | |
83 | struct mbox_chan chan; | |
84 | struct k3_sec_proxy_desc *desc; | |
85 | struct k3_sec_proxy_thread *chans; | |
86 | phys_addr_t target_data; | |
87 | phys_addr_t scfg; | |
88 | phys_addr_t rt; | |
89 | }; | |
90 | ||
91 | static inline u32 sp_readl(void __iomem *addr, unsigned int offset) | |
92 | { | |
93 | return readl(addr + offset); | |
94 | } | |
95 | ||
96 | static inline void sp_writel(void __iomem *addr, unsigned int offset, u32 data) | |
97 | { | |
98 | writel(data, addr + offset); | |
99 | } | |
100 | ||
101 | /** | |
102 | * k3_sec_proxy_of_xlate() - Translation of phandle to channel | |
103 | * @chan: Mailbox channel | |
104 | * @args: Phandle Pointer | |
105 | * | |
106 | * Translates the phandle args and fills up the Mailbox channel from client. | |
107 | * Return: 0 if all goes good, else return corresponding error message. | |
108 | */ | |
109 | static int k3_sec_proxy_of_xlate(struct mbox_chan *chan, | |
110 | struct ofnode_phandle_args *args) | |
111 | { | |
112 | struct k3_sec_proxy_mbox *spm = dev_get_priv(chan->dev); | |
113 | int ind, i; | |
114 | ||
115 | debug("%s(chan=%p)\n", __func__, chan); | |
116 | ||
117 | if (args->args_count != 1) { | |
118 | debug("Invaild args_count: %d\n", args->args_count); | |
119 | return -EINVAL; | |
120 | } | |
121 | ind = args->args[0]; | |
122 | ||
123 | for (i = 0; i < spm->desc->num_valid_threads; i++) | |
124 | if (spm->chans[i].id == ind) { | |
125 | chan->id = ind; | |
126 | chan->con_priv = &spm->chans[i]; | |
127 | return 0; | |
128 | } | |
129 | ||
130 | dev_err(chan->dev, "%s: Invalid Thread ID %d\n", __func__, ind); | |
131 | return -ENOENT; | |
132 | } | |
133 | ||
134 | /** | |
135 | * k3_sec_proxy_request() - Request for mailbox channel | |
136 | * @chan: Channel Pointer | |
137 | */ | |
138 | static int k3_sec_proxy_request(struct mbox_chan *chan) | |
139 | { | |
140 | debug("%s(chan=%p)\n", __func__, chan); | |
141 | ||
142 | return 0; | |
143 | } | |
144 | ||
145 | /** | |
146 | * k3_sec_proxy_free() - Free the mailbox channel | |
147 | * @chan: Channel Pointer | |
148 | */ | |
149 | static int k3_sec_proxy_free(struct mbox_chan *chan) | |
150 | { | |
151 | debug("%s(chan=%p)\n", __func__, chan); | |
152 | ||
153 | return 0; | |
154 | } | |
155 | ||
156 | /** | |
157 | * k3_sec_proxy_verify_thread() - Verify thread status before | |
158 | * sending/receiving data. | |
159 | * @spt: pointer to secure proxy thread description | |
160 | * @dir: Direction of the thread | |
161 | * | |
162 | * Return: 0 if all goes good, else appropriate error message. | |
163 | */ | |
164 | static inline int k3_sec_proxy_verify_thread(struct k3_sec_proxy_thread *spt, | |
165 | u8 dir) | |
166 | { | |
167 | /* Check for any errors already available */ | |
168 | if (sp_readl(spt->rt, RT_THREAD_STATUS) & | |
169 | RT_THREAD_STATUS_ERROR_MASK) { | |
170 | printf("%s: Thread %d is corrupted, cannot send data.\n", | |
171 | __func__, spt->id); | |
172 | return -EINVAL; | |
173 | } | |
174 | ||
175 | /* Make sure thread is configured for right direction */ | |
176 | if ((sp_readl(spt->scfg, SCFG_THREAD_CTRL) | |
177 | & SCFG_THREAD_CTRL_DIR_MASK) >> SCFG_THREAD_CTRL_DIR_SHIFT != dir) { | |
178 | if (dir) | |
179 | printf("%s: Trying to receive data on tx Thread %d\n", | |
180 | __func__, spt->id); | |
181 | else | |
182 | printf("%s: Trying to send data on rx Thread %d\n", | |
183 | __func__, spt->id); | |
184 | return -EINVAL; | |
185 | } | |
186 | ||
187 | /* Check the message queue before sending/receiving data */ | |
188 | if (!(sp_readl(spt->rt, RT_THREAD_STATUS) & | |
189 | RT_THREAD_STATUS_CUR_CNT_MASK)) | |
190 | return -ENODATA; | |
191 | ||
192 | return 0; | |
193 | } | |
194 | ||
195 | /** | |
196 | * k3_sec_proxy_send() - Send data via mailbox channel | |
197 | * @chan: Channel Pointer | |
198 | * @data: Pointer to k3_sec_proxy_msg | |
199 | * | |
200 | * Return: 0 if all goes good, else appropriate error message. | |
201 | */ | |
202 | static int k3_sec_proxy_send(struct mbox_chan *chan, const void *data) | |
203 | { | |
204 | const struct k3_sec_proxy_msg *msg = (struct k3_sec_proxy_msg *)data; | |
205 | struct k3_sec_proxy_mbox *spm = dev_get_priv(chan->dev); | |
206 | struct k3_sec_proxy_thread *spt = chan->con_priv; | |
207 | int num_words, trail_bytes, ret; | |
208 | void __iomem *data_reg; | |
209 | u32 *word_data; | |
210 | ||
211 | debug("%s(chan=%p, data=%p)\n", __func__, chan, data); | |
212 | ||
213 | ret = k3_sec_proxy_verify_thread(spt, THREAD_IS_TX); | |
214 | if (ret) { | |
215 | dev_err(dev, "%s: Thread%d verification failed. ret = %d\n", | |
216 | __func__, spt->id, ret); | |
217 | return ret; | |
218 | } | |
219 | ||
220 | /* Check the message size. */ | |
221 | if (msg->len > spm->desc->max_msg_size) { | |
222 | printf("%s: Thread %ld message length %zu > max msg size %d\n", | |
223 | __func__, chan->id, msg->len, spm->desc->max_msg_size); | |
224 | return -EINVAL; | |
225 | } | |
226 | ||
227 | /* Send the message */ | |
228 | data_reg = spt->data + spm->desc->data_start_offset; | |
229 | for (num_words = msg->len / sizeof(u32), word_data = (u32 *)msg->buf; | |
230 | num_words; | |
231 | num_words--, data_reg += sizeof(u32), word_data++) | |
232 | writel(*word_data, data_reg); | |
233 | ||
234 | trail_bytes = msg->len % sizeof(u32); | |
235 | if (trail_bytes) { | |
236 | u32 data_trail = *word_data; | |
237 | ||
238 | /* Ensure all unused data is 0 */ | |
239 | data_trail &= 0xFFFFFFFF >> (8 * (sizeof(u32) - trail_bytes)); | |
240 | writel(data_trail, data_reg); | |
241 | data_reg++; | |
242 | } | |
243 | ||
244 | /* | |
245 | * 'data_reg' indicates next register to write. If we did not already | |
246 | * write on tx complete reg(last reg), we must do so for transmit | |
247 | */ | |
248 | if (data_reg <= (spt->data + spm->desc->data_end_offset)) | |
249 | sp_writel(spt->data, spm->desc->data_end_offset, 0); | |
250 | ||
251 | debug("%s: Message successfully sent on thread %ld\n", | |
252 | __func__, chan->id); | |
253 | ||
254 | return 0; | |
255 | } | |
256 | ||
257 | /** | |
258 | * k3_sec_proxy_recv() - Receive data via mailbox channel | |
259 | * @chan: Channel Pointer | |
260 | * @data: Pointer to k3_sec_proxy_msg | |
261 | * | |
262 | * Return: 0 if all goes good, else appropriate error message. | |
263 | */ | |
264 | static int k3_sec_proxy_recv(struct mbox_chan *chan, void *data) | |
265 | { | |
266 | struct k3_sec_proxy_mbox *spm = dev_get_priv(chan->dev); | |
267 | struct k3_sec_proxy_thread *spt = chan->con_priv; | |
268 | struct k3_sec_proxy_msg *msg = data; | |
269 | void __iomem *data_reg; | |
270 | int num_words, ret; | |
271 | u32 *word_data; | |
272 | ||
273 | debug("%s(chan=%p, data=%p)\n", __func__, chan, data); | |
274 | ||
275 | ret = k3_sec_proxy_verify_thread(spt, THREAD_IS_RX); | |
276 | if (ret) | |
277 | return ret; | |
278 | ||
279 | msg->len = spm->desc->max_msg_size; | |
280 | msg->buf = spt->rx_buf; | |
281 | data_reg = spt->data + spm->desc->data_start_offset; | |
282 | word_data = spt->rx_buf; | |
283 | for (num_words = spm->desc->max_msg_size / sizeof(u32); | |
284 | num_words; | |
285 | num_words--, data_reg += sizeof(u32), word_data++) | |
286 | *word_data = readl(data_reg); | |
287 | ||
288 | debug("%s: Message successfully received from thread %ld\n", | |
289 | __func__, chan->id); | |
290 | ||
291 | return 0; | |
292 | } | |
293 | ||
294 | struct mbox_ops k3_sec_proxy_mbox_ops = { | |
295 | .of_xlate = k3_sec_proxy_of_xlate, | |
296 | .request = k3_sec_proxy_request, | |
cc92c3cc | 297 | .rfree = k3_sec_proxy_free, |
f9aa4102 LV |
298 | .send = k3_sec_proxy_send, |
299 | .recv = k3_sec_proxy_recv, | |
300 | }; | |
301 | ||
302 | /** | |
303 | * k3_sec_proxy_of_to_priv() - generate private data from device tree | |
304 | * @dev: corresponding k3 secure proxy device | |
305 | * @spm: pointer to driver specific private data | |
306 | * | |
307 | * Return: 0 if all went ok, else corresponding error message. | |
308 | */ | |
309 | static int k3_sec_proxy_of_to_priv(struct udevice *dev, | |
310 | struct k3_sec_proxy_mbox *spm) | |
311 | { | |
312 | const void *blob = gd->fdt_blob; | |
313 | ||
314 | if (!blob) { | |
315 | debug("'%s' no dt?\n", dev->name); | |
316 | return -ENODEV; | |
317 | } | |
318 | ||
319 | spm->target_data = devfdt_get_addr_name(dev, "target_data"); | |
320 | if (spm->target_data == FDT_ADDR_T_NONE) { | |
321 | dev_err(dev, "No reg property for target data base\n"); | |
322 | return -EINVAL; | |
323 | } | |
324 | ||
325 | spm->scfg = devfdt_get_addr_name(dev, "scfg"); | |
326 | if (spm->rt == FDT_ADDR_T_NONE) { | |
327 | dev_err(dev, "No reg property for Secure Cfg base\n"); | |
328 | return -EINVAL; | |
329 | } | |
330 | ||
331 | spm->rt = devfdt_get_addr_name(dev, "rt"); | |
332 | if (spm->rt == FDT_ADDR_T_NONE) { | |
333 | dev_err(dev, "No reg property for Real Time Cfg base\n"); | |
334 | return -EINVAL; | |
335 | } | |
336 | ||
337 | return 0; | |
338 | } | |
339 | ||
340 | /** | |
341 | * k3_sec_proxy_thread_setup - Initialize the parameters for all valid threads | |
342 | * @spm: Mailbox instance for which threads needs to be initialized | |
343 | * | |
344 | * Return: 0 if all went ok, else corresponding error message | |
345 | */ | |
346 | static int k3_sec_proxy_thread_setup(struct k3_sec_proxy_mbox *spm) | |
347 | { | |
348 | struct k3_sec_proxy_thread *spt; | |
349 | int i, ind; | |
350 | ||
351 | for (i = 0; i < spm->desc->num_valid_threads; i++) { | |
352 | spt = &spm->chans[i]; | |
353 | ind = spm->desc->valid_threads[i]; | |
354 | spt->id = ind; | |
355 | spt->data = (void *)SEC_PROXY_THREAD(spm->target_data, ind); | |
356 | spt->scfg = (void *)SEC_PROXY_THREAD(spm->scfg, ind); | |
357 | spt->rt = (void *)SEC_PROXY_THREAD(spm->rt, ind); | |
358 | spt->rx_buf = calloc(1, spm->desc->max_msg_size); | |
359 | if (!spt->rx_buf) | |
360 | return -ENOMEM; | |
361 | } | |
362 | ||
363 | return 0; | |
364 | } | |
365 | ||
366 | /** | |
367 | * k3_sec_proxy_probe() - Basic probe | |
368 | * @dev: corresponding mailbox device | |
369 | * | |
370 | * Return: 0 if all went ok, else corresponding error message | |
371 | */ | |
372 | static int k3_sec_proxy_probe(struct udevice *dev) | |
373 | { | |
374 | struct k3_sec_proxy_mbox *spm = dev_get_priv(dev); | |
375 | int ret; | |
376 | ||
377 | debug("%s(dev=%p)\n", __func__, dev); | |
378 | ||
379 | ret = k3_sec_proxy_of_to_priv(dev, spm); | |
380 | if (ret) | |
381 | return ret; | |
382 | ||
383 | spm->desc = (void *)dev_get_driver_data(dev); | |
384 | spm->chans = calloc(spm->desc->num_valid_threads, | |
385 | sizeof(struct k3_sec_proxy_thread)); | |
386 | if (!spm->chans) | |
387 | return -ENOMEM; | |
388 | ||
389 | ret = k3_sec_proxy_thread_setup(spm); | |
390 | if (ret) { | |
391 | debug("%s: secure proxy thread setup failed\n", __func__); | |
392 | return ret; | |
393 | } | |
394 | ||
395 | return 0; | |
396 | } | |
397 | ||
398 | static int k3_sec_proxy_remove(struct udevice *dev) | |
399 | { | |
400 | struct k3_sec_proxy_mbox *spm = dev_get_priv(dev); | |
401 | ||
402 | debug("%s(dev=%p)\n", __func__, dev); | |
403 | ||
404 | free(spm->chans); | |
405 | ||
406 | return 0; | |
407 | } | |
408 | ||
409 | /* | |
410 | * Thread ID #4: ROM request | |
411 | * Thread ID #5: ROM response, SYSFW notify | |
412 | * Thread ID #6: SYSFW request response | |
413 | * Thread ID #7: SYSFW request high priority | |
414 | * Thread ID #8: SYSFW request low priority | |
415 | * Thread ID #9: SYSFW notify response | |
416 | */ | |
417 | static const u32 am6x_valid_threads[] = { 4, 5, 6, 7, 8, 9, 11, 13 }; | |
418 | ||
419 | static const struct k3_sec_proxy_desc am654_desc = { | |
420 | .thread_count = 90, | |
421 | .max_msg_size = 60, | |
422 | .data_start_offset = 0x4, | |
423 | .data_end_offset = 0x3C, | |
424 | .valid_threads = am6x_valid_threads, | |
425 | .num_valid_threads = ARRAY_SIZE(am6x_valid_threads), | |
426 | }; | |
427 | ||
428 | static const struct udevice_id k3_sec_proxy_ids[] = { | |
429 | { .compatible = "ti,am654-secure-proxy", .data = (ulong)&am654_desc}, | |
430 | { } | |
431 | }; | |
432 | ||
433 | U_BOOT_DRIVER(k3_sec_proxy) = { | |
434 | .name = "k3-secure-proxy", | |
435 | .id = UCLASS_MAILBOX, | |
436 | .of_match = k3_sec_proxy_ids, | |
437 | .probe = k3_sec_proxy_probe, | |
438 | .remove = k3_sec_proxy_remove, | |
439 | .priv_auto_alloc_size = sizeof(struct k3_sec_proxy_mbox), | |
440 | .ops = &k3_sec_proxy_mbox_ops, | |
441 | }; |