1 /* 2 * Texas Instruments K3 Secure Proxy Driver 3 * Based on Linux and U-Boot implementation 4 * 5 * Copyright (C) 2018-2025 Texas Instruments Incorporated - http://www.ti.com/ 6 * 7 * SPDX-License-Identifier: BSD-3-Clause 8 */ 9 10 #include <errno.h> 11 #include <stdlib.h> 12 13 #include <platform_def.h> 14 15 #include <arch_helpers.h> 16 #include <common/debug.h> 17 #include <lib/mmio.h> 18 #include <lib/utils.h> 19 #include <lib/utils_def.h> 20 21 #include <ti_sci_transport.h> 22 23 /* SEC PROXY RT THREAD STATUS */ 24 #define RT_THREAD_STATUS (0x0) 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 * @timeout_us: Timeout for communication (in Microseconds) 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 */ 46 struct k3_sec_proxy_desc { 47 uint32_t timeout_us; 48 uint16_t max_msg_size; 49 uint16_t data_start_offset; 50 uint16_t data_end_offset; 51 }; 52 53 /** 54 * struct k3_sec_proxy_thread - Description of a Secure Proxy Thread 55 * @name: Thread Name 56 * @data: Thread Data path region for target 57 * @scfg: Secure Config Region for Thread 58 * @rt: RealTime Region for Thread 59 */ 60 struct k3_sec_proxy_thread { 61 const char *name; 62 uintptr_t data; 63 uintptr_t scfg; 64 uintptr_t rt; 65 }; 66 67 /** 68 * struct k3_sec_proxy_mbox - Description of a Secure Proxy Instance 69 * @desc: Description of the SoC integration 70 * @chans: Array for valid thread instances 71 */ 72 struct k3_sec_proxy_mbox { 73 const struct k3_sec_proxy_desc desc; 74 struct k3_sec_proxy_thread threads[]; 75 }; 76 77 /* 78 * Thread ID #0: DMSC notify 79 * Thread ID #1: DMSC request response 80 * Thread ID #2: DMSC request high priority 81 * Thread ID #3: DMSC request low priority 82 * Thread ID #4: DMSC notify response 83 */ 84 #define SP_THREAD(_x) \ 85 [_x] = { \ 86 .name = #_x, \ 87 .data = SEC_PROXY_THREAD(SEC_PROXY_DATA_BASE, _x), \ 88 .scfg = SEC_PROXY_THREAD(SEC_PROXY_SCFG_BASE, _x), \ 89 .rt = SEC_PROXY_THREAD(SEC_PROXY_RT_BASE, _x), \ 90 } 91 92 static struct k3_sec_proxy_mbox spm = { 93 .desc = { 94 .timeout_us = SEC_PROXY_TIMEOUT_US, 95 .max_msg_size = SEC_PROXY_MAX_MESSAGE_SIZE, 96 .data_start_offset = 0x4, 97 .data_end_offset = 0x3C, 98 }, 99 .threads = { 100 SP_THREAD(RX_SECURE_TRANSPORT_CHANNEL_ID), 101 SP_THREAD(TX_SECURE_TRANSPORT_CHANNEL_ID), 102 }, 103 }; 104 105 /** 106 * k3_sec_proxy_verify_thread() - Verify thread status before 107 * sending/receiving data 108 * @spt: Pointer to Secure Proxy thread description 109 * @dir: Direction of the thread 110 * 111 * Return: 0 if all goes well, else appropriate error message 112 */ 113 static int k3_sec_proxy_verify_thread(struct k3_sec_proxy_thread *spt, 114 uint32_t dir) 115 { 116 /* Check for any errors already available */ 117 if (mmio_read_32(spt->rt + RT_THREAD_STATUS) & 118 RT_THREAD_STATUS_ERROR_MASK) { 119 ERROR("Thread %s is corrupted, cannot send data\n", spt->name); 120 return -EINVAL; 121 } 122 123 /* Make sure thread is configured for right direction */ 124 if ((mmio_read_32(spt->scfg + SCFG_THREAD_CTRL) & SCFG_THREAD_CTRL_DIR_MASK) 125 != (dir << SCFG_THREAD_CTRL_DIR_SHIFT)) { 126 if (dir == THREAD_IS_TX) 127 ERROR("Trying to send data on RX Thread %s\n", 128 spt->name); 129 else 130 ERROR("Trying to receive data on TX Thread %s\n", 131 spt->name); 132 return -EINVAL; 133 } 134 135 /* Check the message queue before sending/receiving data */ 136 uint32_t tick_start = (uint32_t)read_cntpct_el0(); 137 uint32_t ticks_per_us = SYS_COUNTER_FREQ_IN_TICKS / 1000000; 138 while (!(mmio_read_32(spt->rt + RT_THREAD_STATUS) & RT_THREAD_STATUS_CUR_CNT_MASK)) { 139 VERBOSE("Waiting for thread %s to %s\n", 140 spt->name, (dir == THREAD_IS_TX) ? "empty" : "fill"); 141 if (((uint32_t)read_cntpct_el0() - tick_start) > 142 (spm.desc.timeout_us * ticks_per_us)) { 143 ERROR("Timeout waiting for thread %s to %s\n", 144 spt->name, (dir == THREAD_IS_TX) ? "empty" : "fill"); 145 return -ETIMEDOUT; 146 } 147 } 148 149 return 0; 150 } 151 152 /** 153 * ti_sci_transport_clear_rx_thread() - Clear Secure Proxy thread 154 * 155 * @id: Channel Identifier 156 * 157 * Return: 0 if all goes well, else appropriate error message 158 */ 159 int ti_sci_transport_clear_rx_thread(enum ti_sci_transport_chan_id id) 160 { 161 struct k3_sec_proxy_thread *spt = &spm.threads[id]; 162 163 /* Check for any errors already available */ 164 if (mmio_read_32(spt->rt + RT_THREAD_STATUS) & 165 RT_THREAD_STATUS_ERROR_MASK) { 166 ERROR("Thread %s is corrupted, cannot send data\n", spt->name); 167 return -EINVAL; 168 } 169 170 /* Make sure thread is configured for right direction */ 171 if (!(mmio_read_32(spt->scfg + SCFG_THREAD_CTRL) & SCFG_THREAD_CTRL_DIR_MASK)) { 172 ERROR("Cannot clear a transmit thread %s\n", spt->name); 173 return -EINVAL; 174 } 175 176 /* Read off messages from thread until empty */ 177 uint32_t try_count = 10; 178 while (mmio_read_32(spt->rt + RT_THREAD_STATUS) & RT_THREAD_STATUS_CUR_CNT_MASK) { 179 if (!(try_count--)) { 180 ERROR("Could not clear all messages from thread %s\n", spt->name); 181 return -ETIMEDOUT; 182 } 183 WARN("Clearing message from thread %s\n", spt->name); 184 mmio_read_32(spt->data + spm.desc.data_end_offset); 185 } 186 187 return 0; 188 } 189 190 /** 191 * ti_sci_transport_send() - Send data over a Secure Proxy thread 192 * @id: Channel Identifier 193 * @msg: Pointer to ti_sci_msg 194 * 195 * Return: 0 if all goes well, else appropriate error message 196 */ 197 int ti_sci_transport_send(enum ti_sci_transport_chan_id id, const struct ti_sci_msg *msg) 198 { 199 struct k3_sec_proxy_thread *spt = &spm.threads[id]; 200 int num_words, trail_bytes, i, ret; 201 uintptr_t data_reg; 202 203 ret = k3_sec_proxy_verify_thread(spt, THREAD_IS_TX); 204 if (ret) { 205 ERROR("Thread %s verification failed (%d)\n", spt->name, ret); 206 return ret; 207 } 208 209 /* Check the message size */ 210 if (msg->len > spm.desc.max_msg_size) { 211 ERROR("Thread %s message length %lu > max msg size\n", 212 spt->name, msg->len); 213 return -EINVAL; 214 } 215 216 data_reg = spm.desc.data_start_offset; 217 218 /* Send whole words */ 219 num_words = msg->len / sizeof(uint32_t); 220 for (i = 0; i < num_words; i++) { 221 mmio_write_32(spt->data + data_reg, ((uint32_t *)msg->buf)[i]); 222 data_reg += sizeof(uint32_t); 223 } 224 225 /* Send remaining bytes */ 226 trail_bytes = msg->len % sizeof(uint32_t); 227 if (trail_bytes) { 228 uint32_t data_trail = 0; 229 230 i = msg->len - trail_bytes; 231 while (trail_bytes--) { 232 data_trail <<= 8; 233 data_trail |= msg->buf[i++]; 234 } 235 236 mmio_write_32(spt->data + data_reg, data_trail); 237 data_reg += sizeof(uint32_t); 238 } 239 /* 240 * 'data_reg' indicates next register to write. If we did not already 241 * write on tx complete reg(last reg), we must do so for transmit 242 * In addition, we also need to make sure all intermediate data 243 * registers(if any required), are reset to 0 for TISCI backward 244 * compatibility to be maintained. 245 */ 246 while (data_reg <= spm.desc.data_end_offset) { 247 mmio_write_32(spt->data + data_reg, 0); 248 data_reg += sizeof(uint32_t); 249 } 250 251 VERBOSE("Message successfully sent on thread %s\n", spt->name); 252 253 return 0; 254 } 255 256 /** 257 * ti_sci_transport_recv() - Receive data from a Secure Proxy thread 258 * @id: Channel Identifier 259 * @msg: Pointer to ti_sci_msg 260 * 261 * Return: 0 if all goes well, else appropriate error message 262 */ 263 int ti_sci_transport_recv(enum ti_sci_transport_chan_id id, struct ti_sci_msg *msg) 264 { 265 struct k3_sec_proxy_thread *spt = &spm.threads[id]; 266 uintptr_t data_reg; 267 int num_words, trail_bytes, i, ret; 268 269 ret = k3_sec_proxy_verify_thread(spt, THREAD_IS_RX); 270 if (ret) { 271 ERROR("Thread %s verification failed (%d)\n", spt->name, ret); 272 return ret; 273 } 274 275 data_reg = spm.desc.data_start_offset; 276 277 /* Read whole words */ 278 num_words = msg->len / sizeof(uint32_t); 279 for (i = 0; i < num_words; i++) { 280 ((uint32_t *)msg->buf)[i] = mmio_read_32(spt->data + data_reg); 281 data_reg += sizeof(uint32_t); 282 } 283 284 /* Read remaining bytes */ 285 trail_bytes = msg->len % sizeof(uint32_t); 286 if (trail_bytes) { 287 uint32_t data_trail = mmio_read_32(spt->data + data_reg); 288 data_reg += sizeof(uint32_t); 289 290 i = msg->len - trail_bytes; 291 while (trail_bytes--) { 292 msg->buf[i++] = data_trail & 0xff; 293 data_trail >>= 8; 294 } 295 } 296 297 /* 298 * 'data_reg' indicates next register to read. If we did not already 299 * read on rx complete reg(last reg), we must do so for receive 300 */ 301 if (data_reg <= spm.desc.data_end_offset) 302 mmio_read_32(spt->data + spm.desc.data_end_offset); 303 304 VERBOSE("Message successfully received from thread %s\n", spt->name); 305 306 return 0; 307 } 308