1 /*
2 * K3 Secure proxy driver
3 *
4 * Copyright (C) 2019 Texas Instruments Incorporated - https://www.ti.com/
5 * Lokesh Vutla <lokeshvutla@ti.com>
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 *
14 * Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the
17 * distribution.
18 *
19 * Neither the name of Texas Instruments Incorporated nor the names of
20 * its contributors may be used to endorse or promote products derived
21 * from this software without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
36 #include <stdio.h>
37 #include <stdint.h>
38 #include <sec_proxy.h>
39 #include <mmio.h>
40 #include <error.h>
41 #include <socinfo.h>
42 #include <string.h>
44 #ifdef DEBUG
45 #define dprintf(format, ...) printf(format, ## __VA_ARGS__)
46 #else
47 #define dprintf(format, ...)
48 #endif
50 /* SEC PROXY RT THREAD STATUS */
51 #define RT_THREAD_STATUS 0x0
52 #define RT_THREAD_THRESHOLD 0x4
53 #define RT_THREAD_STATUS_ERROR_SHIFT 31
54 #define RT_THREAD_STATUS_ERROR_MASK (1 << 31)
55 #define RT_THREAD_STATUS_CUR_CNT_SHIFT 0
56 #define RT_THREAD_STATUS_CUR_CNT_MASK 0xff
58 /* SEC PROXY SCFG THREAD CTRL */
59 #define SCFG_THREAD_CTRL 0x1000
60 #define SCFG_THREAD_CTRL_DIR_SHIFT 31
61 #define SCFG_THREAD_CTRL_DIR_MASK (1 << 31)
63 #define SEC_PROXY_THREAD(base, x) ((base) + (0x1000 * (x)))
64 #define SEC_PROXY_TX_THREAD 0
65 #define SEC_PROXY_RX_THREAD 1
66 #define SEC_PROXY_MAX_THREADS 2
68 #define SEC_PROXY_TIMEOUT_US 1000000
70 #define SEC_PROXY_DATA_START_OFFS 0x4
71 #define SEC_PROXY_DATA_END_OFFS 0x3c
73 struct k3_sec_proxy_base k3_generic_sec_proxy_base = {
74 .src_target_data = 0x32c00000,
75 .cfg_scfg = 0x32800000,
76 .cfg_rt = 0x32400000,
77 };
79 struct k3_sec_proxy_base k3_lite_sec_proxy_base = {
80 .src_target_data = 0x4d000000,
81 .cfg_scfg = 0x4a400000,
82 .cfg_rt = 0x4a600000,
83 };
85 struct k3_sec_proxy_thread {
86 uint32_t id;
87 uintptr_t data;
88 uintptr_t scfg;
89 uintptr_t rt;
90 } spts[SEC_PROXY_MAX_THREADS];
92 static inline uint32_t sp_readl(uintptr_t addr)
93 {
94 return mmio_read_32(addr);
95 }
97 static inline void sp_writel(uintptr_t addr, uint32_t data)
98 {
99 mmio_write_32(addr, data);
100 }
102 static int k3_sec_proxy_verify_thread(uint32_t dir)
103 {
104 struct k3_sec_proxy_thread *spt = &spts[dir];
106 /* Check for any errors already available */
107 if (sp_readl(spt->rt + RT_THREAD_STATUS) &
108 RT_THREAD_STATUS_ERROR_MASK) {
109 fprintf(stderr, "%s: Thread %d is corrupted, cannot send data.\n",
110 __func__, spt->id);
111 return -1;
112 }
114 /* Make sure thread is configured for right direction */
115 if ((sp_readl(spt->scfg + SCFG_THREAD_CTRL)
116 & SCFG_THREAD_CTRL_DIR_MASK) >> SCFG_THREAD_CTRL_DIR_SHIFT != dir) {
117 if (dir)
118 fprintf(stderr, "%s: Trying to receive data on tx Thread %d\n",
119 __func__, spt->id);
120 else
121 fprintf(stderr, "%s: Trying to send data on rx Thread %d\n",
122 __func__, spt->id);
123 return -1;
124 }
126 /* Check the message queue before sending/receiving data */
127 if (!(sp_readl(spt->rt + RT_THREAD_STATUS) &
128 RT_THREAD_STATUS_CUR_CNT_MASK))
129 return -2;
131 return 0;
132 }
134 int k3_sec_proxy_send(struct k3_sec_proxy_msg *msg)
135 {
136 struct k3_sec_proxy_thread *spt = &spts[SEC_PROXY_TX_THREAD];
137 int num_words, trail_bytes, ret;
138 uint32_t *word_data;
139 uintptr_t data_reg;
141 ret = k3_sec_proxy_verify_thread(SEC_PROXY_TX_THREAD);
142 if (ret) {
143 fprintf(stderr, "%s: Thread%d verification failed. ret = %d\n",
144 __func__, spt->id, ret);
145 return ret;
146 }
148 /* Check the message size. */
149 if (msg->len > SEC_PROXY_MAX_MSG_SIZE) {
150 fprintf(stderr, "%s: Thread %u message length %zu > max msg size %d\n",
151 __func__, spt->id, msg->len, SEC_PROXY_MAX_MSG_SIZE);
152 return -1;
153 }
155 /* Send the message */
156 data_reg = spt->data + SEC_PROXY_DATA_START_OFFS;
157 word_data = (uint32_t *)msg->buf;
158 for (num_words = msg->len / sizeof(uint32_t);
159 num_words;
160 num_words--, data_reg += sizeof(uint32_t), word_data++)
161 sp_writel(data_reg, *word_data);
163 trail_bytes = msg->len % sizeof(uint32_t);
164 if (trail_bytes) {
165 uint32_t data_trail = *word_data;
167 /* Ensure all unused data is 0 */
168 data_trail &= 0xFFFFFFFF >> (8 * (sizeof(uint32_t) - trail_bytes));
169 sp_writel(data_reg, data_trail);
170 data_reg++;
171 }
173 /*
174 * 'data_reg' indicates next register to write. If we did not already
175 * write on tx complete reg(last reg), we must do so for transmit
176 */
177 if (data_reg <= (spt->data + SEC_PROXY_DATA_END_OFFS))
178 sp_writel(spt->data + SEC_PROXY_DATA_END_OFFS, 0);
180 return 0;
181 }
183 int k3_sec_proxy_recv(struct k3_sec_proxy_msg *msg)
184 {
185 struct k3_sec_proxy_thread *spt = &spts[SEC_PROXY_RX_THREAD];
186 int num_words, ret = -1, retry = 10000;
187 uint32_t *word_data;
188 uintptr_t data_reg;
190 while (retry-- && ret) {
191 ret = k3_sec_proxy_verify_thread(SEC_PROXY_RX_THREAD);
192 if ((ret && ret != -2) || !retry) {
193 fprintf(stderr, "%s: Thread%d verification failed. ret = %d\n",
194 __func__, spt->id, ret);
195 return ret;
196 }
197 }
199 data_reg = spt->data + SEC_PROXY_DATA_START_OFFS;
200 word_data = (uint32_t *)(uintptr_t)msg->buf;
201 for (num_words = SEC_PROXY_MAX_MSG_SIZE / sizeof(uint32_t);
202 num_words;
203 num_words--, data_reg += sizeof(uint32_t), word_data++)
204 *word_data = sp_readl(data_reg);
206 return 0;
207 }
209 static int get_thread_id(char *host_name, char *function)
210 {
211 struct ti_sci_info *sci_info = &soc_info.sci_info;
212 uint32_t i;
214 for (i = 0; i < sci_info->num_sp_threads[MAIN_SEC_PROXY]; i++)
215 if (!strcmp(host_name,
216 sci_info->sp_info[MAIN_SEC_PROXY][i].host) &&
217 !strcmp(function,
218 sci_info->sp_info[MAIN_SEC_PROXY][i].host_function))
219 return sci_info->sp_info[MAIN_SEC_PROXY][i].sp_id;
221 return -1;
223 }
225 static char* get_host_name(uint32_t host_id)
226 {
227 struct ti_sci_info *sci_info = &soc_info.sci_info;
228 uint32_t i;
230 for (i = 0; i < sci_info->num_hosts; i++)
231 if (host_id == sci_info->host_info[i].host_id)
232 return sci_info->host_info[i].host_name;
234 return NULL;
235 }
237 int k3_sec_proxy_init(void)
238 {
239 struct k3_sec_proxy_base *spb = soc_info.sec_proxy;
240 int rx_thread, tx_thread;
241 char *host_name;
243 host_name = get_host_name(soc_info.host_id);
244 if (!host_name) {
245 fprintf(stderr, "Invalid host id %d, using default host_id %d\n",
246 soc_info.host_id, DEFAULT_HOST_ID);
247 soc_info.host_id = DEFAULT_HOST_ID;
248 host_name = get_host_name(soc_info.host_id);
249 }
251 rx_thread = get_thread_id(host_name, "response");
252 if (rx_thread < 0) {
253 fprintf(stderr, "Invalid host id %d, using default host_id %d\n",
254 soc_info.host_id, DEFAULT_HOST_ID);
255 soc_info.host_id = DEFAULT_HOST_ID;
256 host_name = get_host_name(soc_info.host_id);
257 rx_thread = get_thread_id(host_name, "response");
258 }
259 tx_thread = get_thread_id(host_name, "low_priority");
260 dprintf("host_name = %s, tx_thread = %d, rx_thread = %d\n",
261 host_name, tx_thread, rx_thread);
263 spts[SEC_PROXY_TX_THREAD].id = tx_thread;
264 spts[SEC_PROXY_TX_THREAD].data = SEC_PROXY_THREAD(spb->src_target_data, tx_thread);
265 spts[SEC_PROXY_TX_THREAD].scfg = SEC_PROXY_THREAD(spb->cfg_scfg, tx_thread);
266 spts[SEC_PROXY_TX_THREAD].rt = SEC_PROXY_THREAD(spb->cfg_rt, tx_thread);
268 spts[SEC_PROXY_RX_THREAD].id = rx_thread;
269 spts[SEC_PROXY_RX_THREAD].data = SEC_PROXY_THREAD(spb->src_target_data, rx_thread);
270 spts[SEC_PROXY_RX_THREAD].scfg = SEC_PROXY_THREAD(spb->cfg_scfg, rx_thread);
271 spts[SEC_PROXY_RX_THREAD].rt = SEC_PROXY_THREAD(spb->cfg_rt, rx_thread);
273 return 0;
274 }