1 // SPDX-License-Identifier: GPL-2.0+
3 * Texas Instruments' K3 Secure proxy Driver
5 * Copyright (C) 2017-2018 Texas Instruments Incorporated - http://www.ti.com/
6 * Lokesh Vutla <lokeshvutla@ti.com>
12 #include <dm/device_compat.h>
13 #include <linux/types.h>
14 #include <linux/bitops.h>
15 #include <linux/soc/ti/k3-sec-proxy.h>
17 #include <mailbox-uclass.h>
19 DECLARE_GLOBAL_DATA_PTR
;
21 /* SEC PROXY RT THREAD STATUS */
22 #define RT_THREAD_STATUS 0x0
23 #define RT_THREAD_THRESHOLD 0x4
24 #define RT_THREAD_STATUS_ERROR_SHIFT 31
25 #define RT_THREAD_STATUS_ERROR_MASK BIT(31)
26 #define RT_THREAD_STATUS_CUR_CNT_SHIFT 0
27 #define RT_THREAD_STATUS_CUR_CNT_MASK GENMASK(7, 0)
29 /* SEC PROXY SCFG THREAD CTRL */
30 #define SCFG_THREAD_CTRL 0x1000
31 #define SCFG_THREAD_CTRL_DIR_SHIFT 31
32 #define SCFG_THREAD_CTRL_DIR_MASK BIT(31)
34 #define SEC_PROXY_THREAD(base, x) ((base) + (0x1000 * (x)))
35 #define THREAD_IS_RX 1
36 #define THREAD_IS_TX 0
39 * struct k3_sec_proxy_desc - Description of secure proxy integration.
40 * @thread_count: Number of Threads.
41 * @max_msg_size: Message size in bytes.
42 * @data_start_offset: Offset of the First data register of the thread
43 * @data_end_offset: Offset of the Last data register of the thread
44 * @valid_threads: List of Valid threads that the processor can access
45 * @num_valid_threads: Number of valid threads.
47 struct k3_sec_proxy_desc
{
50 u16 data_start_offset
;
52 const u32
*valid_threads
;
53 u32 num_valid_threads
;
57 * struct k3_sec_proxy_thread - Description of a secure proxy Thread
59 * @data: Thread Data path region for target
60 * @scfg: Secure Config Region for Thread
61 * @rt: RealTime Region for Thread
62 * @rx_buf: Receive buffer data, max message size.
64 struct k3_sec_proxy_thread
{
73 * struct k3_sec_proxy_mbox - Description of a Secure Proxy Instance
74 * @chan: Mailbox Channel
75 * @desc: Description of the SoC integration
76 * @chans: Array for valid thread instances
77 * @target_data: Secure Proxy region for Target Data
78 * @scfg: Secure Proxy Region for Secure configuration.
79 * @rt: Secure proxy Region for Real Time Region.
81 struct k3_sec_proxy_mbox
{
82 struct mbox_chan chan
;
83 struct k3_sec_proxy_desc
*desc
;
84 struct k3_sec_proxy_thread
*chans
;
85 phys_addr_t target_data
;
90 static inline u32
sp_readl(void __iomem
*addr
, unsigned int offset
)
92 return readl(addr
+ offset
);
95 static inline void sp_writel(void __iomem
*addr
, unsigned int offset
, u32 data
)
97 writel(data
, addr
+ offset
);
101 * k3_sec_proxy_of_xlate() - Translation of phandle to channel
102 * @chan: Mailbox channel
103 * @args: Phandle Pointer
105 * Translates the phandle args and fills up the Mailbox channel from client.
106 * Return: 0 if all goes good, else return corresponding error message.
108 static int k3_sec_proxy_of_xlate(struct mbox_chan
*chan
,
109 struct ofnode_phandle_args
*args
)
111 struct k3_sec_proxy_mbox
*spm
= dev_get_priv(chan
->dev
);
114 debug("%s(chan=%p)\n", __func__
, chan
);
116 if (args
->args_count
!= 1) {
117 debug("Invaild args_count: %d\n", args
->args_count
);
122 for (i
= 0; i
< spm
->desc
->num_valid_threads
; i
++)
123 if (spm
->chans
[i
].id
== ind
) {
125 chan
->con_priv
= &spm
->chans
[i
];
129 dev_err(chan
->dev
, "%s: Invalid Thread ID %d\n", __func__
, ind
);
134 * k3_sec_proxy_request() - Request for mailbox channel
135 * @chan: Channel Pointer
137 static int k3_sec_proxy_request(struct mbox_chan
*chan
)
139 debug("%s(chan=%p)\n", __func__
, chan
);
145 * k3_sec_proxy_free() - Free the mailbox channel
146 * @chan: Channel Pointer
148 static int k3_sec_proxy_free(struct mbox_chan
*chan
)
150 debug("%s(chan=%p)\n", __func__
, chan
);
156 * k3_sec_proxy_verify_thread() - Verify thread status before
157 * sending/receiving data.
158 * @spt: pointer to secure proxy thread description
159 * @dir: Direction of the thread
161 * Return: 0 if all goes good, else appropriate error message.
163 static inline int k3_sec_proxy_verify_thread(struct k3_sec_proxy_thread
*spt
,
166 /* Check for any errors already available */
167 if (sp_readl(spt
->rt
, RT_THREAD_STATUS
) &
168 RT_THREAD_STATUS_ERROR_MASK
) {
169 printf("%s: Thread %d is corrupted, cannot send data.\n",
174 /* Make sure thread is configured for right direction */
175 if ((sp_readl(spt
->scfg
, SCFG_THREAD_CTRL
)
176 & SCFG_THREAD_CTRL_DIR_MASK
) >> SCFG_THREAD_CTRL_DIR_SHIFT
!= dir
) {
178 printf("%s: Trying to receive data on tx Thread %d\n",
181 printf("%s: Trying to send data on rx Thread %d\n",
186 /* Check the message queue before sending/receiving data */
187 if (!(sp_readl(spt
->rt
, RT_THREAD_STATUS
) &
188 RT_THREAD_STATUS_CUR_CNT_MASK
))
195 * k3_sec_proxy_send() - Send data via mailbox channel
196 * @chan: Channel Pointer
197 * @data: Pointer to k3_sec_proxy_msg
199 * Return: 0 if all goes good, else appropriate error message.
201 static int k3_sec_proxy_send(struct mbox_chan
*chan
, const void *data
)
203 const struct k3_sec_proxy_msg
*msg
= (struct k3_sec_proxy_msg
*)data
;
204 struct k3_sec_proxy_mbox
*spm
= dev_get_priv(chan
->dev
);
205 struct k3_sec_proxy_thread
*spt
= chan
->con_priv
;
206 int num_words
, trail_bytes
, ret
;
207 void __iomem
*data_reg
;
210 debug("%s(chan=%p, data=%p)\n", __func__
, chan
, data
);
212 ret
= k3_sec_proxy_verify_thread(spt
, THREAD_IS_TX
);
214 dev_err(dev
, "%s: Thread%d verification failed. ret = %d\n",
215 __func__
, spt
->id
, ret
);
219 /* Check the message size. */
220 if (msg
->len
> spm
->desc
->max_msg_size
) {
221 printf("%s: Thread %ld message length %zu > max msg size %d\n",
222 __func__
, chan
->id
, msg
->len
, spm
->desc
->max_msg_size
);
226 /* Send the message */
227 data_reg
= spt
->data
+ spm
->desc
->data_start_offset
;
228 for (num_words
= msg
->len
/ sizeof(u32
), word_data
= (u32
*)msg
->buf
;
230 num_words
--, data_reg
+= sizeof(u32
), word_data
++)
231 writel(*word_data
, data_reg
);
233 trail_bytes
= msg
->len
% sizeof(u32
);
235 u32 data_trail
= *word_data
;
237 /* Ensure all unused data is 0 */
238 data_trail
&= 0xFFFFFFFF >> (8 * (sizeof(u32
) - trail_bytes
));
239 writel(data_trail
, data_reg
);
244 * 'data_reg' indicates next register to write. If we did not already
245 * write on tx complete reg(last reg), we must do so for transmit
247 if (data_reg
<= (spt
->data
+ spm
->desc
->data_end_offset
))
248 sp_writel(spt
->data
, spm
->desc
->data_end_offset
, 0);
250 debug("%s: Message successfully sent on thread %ld\n",
257 * k3_sec_proxy_recv() - Receive data via mailbox channel
258 * @chan: Channel Pointer
259 * @data: Pointer to k3_sec_proxy_msg
261 * Return: 0 if all goes good, else appropriate error message.
263 static int k3_sec_proxy_recv(struct mbox_chan
*chan
, void *data
)
265 struct k3_sec_proxy_mbox
*spm
= dev_get_priv(chan
->dev
);
266 struct k3_sec_proxy_thread
*spt
= chan
->con_priv
;
267 struct k3_sec_proxy_msg
*msg
= data
;
268 void __iomem
*data_reg
;
272 debug("%s(chan=%p, data=%p)\n", __func__
, chan
, data
);
274 ret
= k3_sec_proxy_verify_thread(spt
, THREAD_IS_RX
);
278 msg
->len
= spm
->desc
->max_msg_size
;
279 msg
->buf
= spt
->rx_buf
;
280 data_reg
= spt
->data
+ spm
->desc
->data_start_offset
;
281 word_data
= spt
->rx_buf
;
282 for (num_words
= spm
->desc
->max_msg_size
/ sizeof(u32
);
284 num_words
--, data_reg
+= sizeof(u32
), word_data
++)
285 *word_data
= readl(data_reg
);
287 debug("%s: Message successfully received from thread %ld\n",
293 struct mbox_ops k3_sec_proxy_mbox_ops
= {
294 .of_xlate
= k3_sec_proxy_of_xlate
,
295 .request
= k3_sec_proxy_request
,
296 .rfree
= k3_sec_proxy_free
,
297 .send
= k3_sec_proxy_send
,
298 .recv
= k3_sec_proxy_recv
,
302 * k3_sec_proxy_of_to_priv() - generate private data from device tree
303 * @dev: corresponding k3 secure proxy device
304 * @spm: pointer to driver specific private data
306 * Return: 0 if all went ok, else corresponding error message.
308 static int k3_sec_proxy_of_to_priv(struct udevice
*dev
,
309 struct k3_sec_proxy_mbox
*spm
)
311 const void *blob
= gd
->fdt_blob
;
314 debug("'%s' no dt?\n", dev
->name
);
318 spm
->target_data
= devfdt_get_addr_name(dev
, "target_data");
319 if (spm
->target_data
== FDT_ADDR_T_NONE
) {
320 dev_err(dev
, "No reg property for target data base\n");
324 spm
->scfg
= devfdt_get_addr_name(dev
, "scfg");
325 if (spm
->rt
== FDT_ADDR_T_NONE
) {
326 dev_err(dev
, "No reg property for Secure Cfg base\n");
330 spm
->rt
= devfdt_get_addr_name(dev
, "rt");
331 if (spm
->rt
== FDT_ADDR_T_NONE
) {
332 dev_err(dev
, "No reg property for Real Time Cfg base\n");
340 * k3_sec_proxy_thread_setup - Initialize the parameters for all valid threads
341 * @spm: Mailbox instance for which threads needs to be initialized
343 * Return: 0 if all went ok, else corresponding error message
345 static int k3_sec_proxy_thread_setup(struct k3_sec_proxy_mbox
*spm
)
347 struct k3_sec_proxy_thread
*spt
;
350 for (i
= 0; i
< spm
->desc
->num_valid_threads
; i
++) {
351 spt
= &spm
->chans
[i
];
352 ind
= spm
->desc
->valid_threads
[i
];
354 spt
->data
= (void *)SEC_PROXY_THREAD(spm
->target_data
, ind
);
355 spt
->scfg
= (void *)SEC_PROXY_THREAD(spm
->scfg
, ind
);
356 spt
->rt
= (void *)SEC_PROXY_THREAD(spm
->rt
, ind
);
357 spt
->rx_buf
= calloc(1, spm
->desc
->max_msg_size
);
366 * k3_sec_proxy_probe() - Basic probe
367 * @dev: corresponding mailbox device
369 * Return: 0 if all went ok, else corresponding error message
371 static int k3_sec_proxy_probe(struct udevice
*dev
)
373 struct k3_sec_proxy_mbox
*spm
= dev_get_priv(dev
);
376 debug("%s(dev=%p)\n", __func__
, dev
);
378 ret
= k3_sec_proxy_of_to_priv(dev
, spm
);
382 spm
->desc
= (void *)dev_get_driver_data(dev
);
383 spm
->chans
= calloc(spm
->desc
->num_valid_threads
,
384 sizeof(struct k3_sec_proxy_thread
));
388 ret
= k3_sec_proxy_thread_setup(spm
);
390 debug("%s: secure proxy thread setup failed\n", __func__
);
397 static int k3_sec_proxy_remove(struct udevice
*dev
)
399 struct k3_sec_proxy_mbox
*spm
= dev_get_priv(dev
);
401 debug("%s(dev=%p)\n", __func__
, dev
);
409 * Thread ID #4: ROM request
410 * Thread ID #5: ROM response, SYSFW notify
411 * Thread ID #6: SYSFW request response
412 * Thread ID #7: SYSFW request high priority
413 * Thread ID #8: SYSFW request low priority
414 * Thread ID #9: SYSFW notify response
416 static const u32 am6x_valid_threads
[] = { 4, 5, 6, 7, 8, 9, 11, 13 };
418 static const struct k3_sec_proxy_desc am654_desc
= {
421 .data_start_offset
= 0x4,
422 .data_end_offset
= 0x3C,
423 .valid_threads
= am6x_valid_threads
,
424 .num_valid_threads
= ARRAY_SIZE(am6x_valid_threads
),
427 static const struct udevice_id k3_sec_proxy_ids
[] = {
428 { .compatible
= "ti,am654-secure-proxy", .data
= (ulong
)&am654_desc
},
432 U_BOOT_DRIVER(k3_sec_proxy
) = {
433 .name
= "k3-secure-proxy",
434 .id
= UCLASS_MAILBOX
,
435 .of_match
= k3_sec_proxy_ids
,
436 .probe
= k3_sec_proxy_probe
,
437 .remove
= k3_sec_proxy_remove
,
438 .priv_auto_alloc_size
= sizeof(struct k3_sec_proxy_mbox
),
439 .ops
= &k3_sec_proxy_mbox_ops
,