1 /*
2 * K3 Secure proxy driver
3 *
4 * Copyright (C) 2019 Texas Instruments Incorporated - http://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 /* Physical address for AM6 NAVSS 256 Main domain */
74 #define SEC_PROXY0_CFG_MMRS 0x31140000
75 #define SEC_PROXY0_SRC_TARGET_DATA 0x32C00000
76 #define SEC_PROXY0_CFG_SCFG 0x32800000
77 #define SEC_PROXY0_CFG_RT 0x32400000
79 struct k3_sec_proxy_thread {
80 uint32_t id;
81 uintptr_t data;
82 uintptr_t scfg;
83 uintptr_t rt;
84 } spts[SEC_PROXY_MAX_THREADS];
86 static inline uint32_t sp_readl(uintptr_t addr)
87 {
88 return mmio_read_32(addr);
89 }
91 static inline void sp_writel(uintptr_t addr, uint32_t data)
92 {
93 mmio_write_32(addr, data);
94 }
96 static int k3_sec_proxy_verify_thread(uint32_t dir)
97 {
98 struct k3_sec_proxy_thread *spt = &spts[dir];
100 /* Check for any errors already available */
101 if (sp_readl(spt->rt + RT_THREAD_STATUS) &
102 RT_THREAD_STATUS_ERROR_MASK) {
103 fprintf(stderr, "%s: Thread %d is corrupted, cannot send data.\n",
104 __func__, spt->id);
105 return -1;
106 }
108 /* Make sure thread is configured for right direction */
109 if ((sp_readl(spt->scfg + SCFG_THREAD_CTRL)
110 & SCFG_THREAD_CTRL_DIR_MASK) >> SCFG_THREAD_CTRL_DIR_SHIFT != dir) {
111 if (dir)
112 fprintf(stderr, "%s: Trying to receive data on tx Thread %d\n",
113 __func__, spt->id);
114 else
115 fprintf(stderr, "%s: Trying to send data on rx Thread %d\n",
116 __func__, spt->id);
117 return -1;
118 }
120 /* Check the message queue before sending/receiving data */
121 if (!(sp_readl(spt->rt + RT_THREAD_STATUS) &
122 RT_THREAD_STATUS_CUR_CNT_MASK))
123 return -2;
125 return 0;
126 }
128 int k3_sec_proxy_send(struct k3_sec_proxy_msg *msg)
129 {
130 struct k3_sec_proxy_thread *spt = &spts[SEC_PROXY_TX_THREAD];
131 int num_words, trail_bytes, ret;
132 uint32_t *word_data;
133 uintptr_t data_reg;
135 ret = k3_sec_proxy_verify_thread(SEC_PROXY_TX_THREAD);
136 if (ret) {
137 fprintf(stderr, "%s: Thread%d verification failed. ret = %d\n",
138 __func__, spt->id, ret);
139 return ret;
140 }
142 /* Check the message size. */
143 if (msg->len > SEC_PROXY_MAX_MSG_SIZE) {
144 fprintf(stderr, "%s: Thread %u message length %zu > max msg size %d\n",
145 __func__, spt->id, msg->len, SEC_PROXY_MAX_MSG_SIZE);
146 return -1;
147 }
149 /* Send the message */
150 data_reg = spt->data + SEC_PROXY_DATA_START_OFFS;
151 word_data = (uint32_t *)msg->buf;
152 for (num_words = msg->len / sizeof(uint32_t);
153 num_words;
154 num_words--, data_reg += sizeof(uint32_t), word_data++)
155 sp_writel(data_reg, *word_data);
157 trail_bytes = msg->len % sizeof(uint32_t);
158 if (trail_bytes) {
159 uint32_t data_trail = *word_data;
161 /* Ensure all unused data is 0 */
162 data_trail &= 0xFFFFFFFF >> (8 * (sizeof(uint32_t) - trail_bytes));
163 sp_writel(data_reg, data_trail);
164 data_reg++;
165 }
167 /*
168 * 'data_reg' indicates next register to write. If we did not already
169 * write on tx complete reg(last reg), we must do so for transmit
170 */
171 if (data_reg <= (spt->data + SEC_PROXY_DATA_END_OFFS))
172 sp_writel(spt->data + SEC_PROXY_DATA_END_OFFS, 0);
174 return 0;
175 }
177 int k3_sec_proxy_recv(struct k3_sec_proxy_msg *msg)
178 {
179 struct k3_sec_proxy_thread *spt = &spts[SEC_PROXY_RX_THREAD];
180 int num_words, ret = -1, retry = 10000;
181 uint32_t *word_data;
182 uintptr_t data_reg;
184 while (retry-- && ret) {
185 ret = k3_sec_proxy_verify_thread(SEC_PROXY_RX_THREAD);
186 if ((ret && ret != -2) || !retry) {
187 fprintf(stderr, "%s: Thread%d verification failed. ret = %d\n",
188 __func__, spt->id, ret);
189 return ret;
190 }
191 }
193 data_reg = spt->data + SEC_PROXY_DATA_START_OFFS;
194 word_data = (uint32_t *)(uintptr_t)msg->buf;
195 for (num_words = SEC_PROXY_MAX_MSG_SIZE / sizeof(uint32_t);
196 num_words;
197 num_words--, data_reg += sizeof(uint32_t), word_data++)
198 *word_data = sp_readl(data_reg);
200 return 0;
201 }
203 static int get_thread_id(char *host_name, char *function)
204 {
205 struct ti_sci_info *sci_info = &soc_info.sci_info;
206 uint32_t i;
208 for (i = 0; i < sci_info->num_sp_threads[MAIN_SEC_PROXY]; i++)
209 if (!strcmp(host_name,
210 sci_info->sp_info[MAIN_SEC_PROXY][i].host) &&
211 !strcmp(function,
212 sci_info->sp_info[MAIN_SEC_PROXY][i].host_function))
213 return sci_info->sp_info[MAIN_SEC_PROXY][i].sp_id;
215 return -1;
217 }
219 static char* get_host_name(uint32_t host_id)
220 {
221 struct ti_sci_info *sci_info = &soc_info.sci_info;
222 uint32_t i;
224 for (i = 0; i < sci_info->num_hosts; i++)
225 if (host_id == sci_info->host_info[i].host_id)
226 return sci_info->host_info[i].host_name;
228 return NULL;
229 }
231 int k3_sec_proxy_init(void)
232 {
233 int rx_thread, tx_thread;
234 char *host_name;
236 host_name = get_host_name(soc_info.host_id);
237 if (!host_name) {
238 fprintf(stderr, "Invalid host id %d, using default host_id %d\n",
239 soc_info.host_id, DEFAULT_HOST_ID);
240 soc_info.host_id = DEFAULT_HOST_ID;
241 host_name = get_host_name(soc_info.host_id);
242 }
244 rx_thread = get_thread_id(host_name, "response");
245 if (rx_thread < 0) {
246 fprintf(stderr, "Invalid host id %d, using default host_id %d\n",
247 soc_info.host_id, DEFAULT_HOST_ID);
248 soc_info.host_id = DEFAULT_HOST_ID;
249 host_name = get_host_name(soc_info.host_id);
250 rx_thread = get_thread_id(host_name, "response");
251 }
252 tx_thread = get_thread_id(host_name, "low_priority");
253 dprintf("host_name = %s, tx_thread = %d, rx_thread = %d\n",
254 host_name, tx_thread, rx_thread);
256 spts[SEC_PROXY_TX_THREAD].id = tx_thread;
257 spts[SEC_PROXY_TX_THREAD].data = SEC_PROXY_THREAD(SEC_PROXY0_SRC_TARGET_DATA, tx_thread);
258 spts[SEC_PROXY_TX_THREAD].scfg = SEC_PROXY_THREAD(SEC_PROXY0_CFG_SCFG, tx_thread);
259 spts[SEC_PROXY_TX_THREAD].rt = SEC_PROXY_THREAD(SEC_PROXY0_CFG_RT, tx_thread);
261 spts[SEC_PROXY_RX_THREAD].id = rx_thread;
262 spts[SEC_PROXY_RX_THREAD].data = SEC_PROXY_THREAD(SEC_PROXY0_SRC_TARGET_DATA, rx_thread);
263 spts[SEC_PROXY_RX_THREAD].scfg = SEC_PROXY_THREAD(SEC_PROXY0_CFG_SCFG, rx_thread);
264 spts[SEC_PROXY_RX_THREAD].rt = SEC_PROXY_THREAD(SEC_PROXY0_CFG_RT, rx_thread);
266 return 0;
267 }