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 * struct sec_msg_hdr - Message header for secure messages and responses 107 * @checksum: CRC of message for integrity checking 108 */ 109 union sec_msg_hdr { 110 struct { 111 uint16_t checksum; 112 uint16_t reserved; 113 } __packed; 114 uint32_t data; 115 }; 116 117 /** 118 * k3_sec_proxy_verify_thread() - Verify thread status before 119 * sending/receiving data 120 * @spt: Pointer to Secure Proxy thread description 121 * @dir: Direction of the thread 122 * 123 * Return: 0 if all goes well, else appropriate error message 124 */ 125 static int k3_sec_proxy_verify_thread(struct k3_sec_proxy_thread *spt, 126 uint32_t dir) 127 { 128 /* Check for any errors already available */ 129 if (mmio_read_32(spt->rt + RT_THREAD_STATUS) & 130 RT_THREAD_STATUS_ERROR_MASK) { 131 ERROR("Thread %s is corrupted, cannot send data\n", spt->name); 132 return -EINVAL; 133 } 134 135 /* Make sure thread is configured for right direction */ 136 if ((mmio_read_32(spt->scfg + SCFG_THREAD_CTRL) & SCFG_THREAD_CTRL_DIR_MASK) 137 != (dir << SCFG_THREAD_CTRL_DIR_SHIFT)) { 138 if (dir == THREAD_IS_TX) 139 ERROR("Trying to send data on RX Thread %s\n", 140 spt->name); 141 else 142 ERROR("Trying to receive data on TX Thread %s\n", 143 spt->name); 144 return -EINVAL; 145 } 146 147 /* Check the message queue before sending/receiving data */ 148 uint32_t tick_start = (uint32_t)read_cntpct_el0(); 149 uint32_t ticks_per_us = SYS_COUNTER_FREQ_IN_TICKS / 1000000; 150 while (!(mmio_read_32(spt->rt + RT_THREAD_STATUS) & RT_THREAD_STATUS_CUR_CNT_MASK)) { 151 VERBOSE("Waiting for thread %s to %s\n", 152 spt->name, (dir == THREAD_IS_TX) ? "empty" : "fill"); 153 if (((uint32_t)read_cntpct_el0() - tick_start) > 154 (spm.desc.timeout_us * ticks_per_us)) { 155 ERROR("Timeout waiting for thread %s to %s\n", 156 spt->name, (dir == THREAD_IS_TX) ? "empty" : "fill"); 157 return -ETIMEDOUT; 158 } 159 } 160 161 return 0; 162 } 163 164 /** 165 * ti_sci_transport_clear_rx_thread() - Clear Secure Proxy thread 166 * 167 * @id: Channel Identifier 168 * 169 * Return: 0 if all goes well, else appropriate error message 170 */ 171 int ti_sci_transport_clear_rx_thread(enum ti_sci_transport_chan_id id) 172 { 173 struct k3_sec_proxy_thread *spt = &spm.threads[id]; 174 175 /* Check for any errors already available */ 176 if (mmio_read_32(spt->rt + RT_THREAD_STATUS) & 177 RT_THREAD_STATUS_ERROR_MASK) { 178 ERROR("Thread %s is corrupted, cannot send data\n", spt->name); 179 return -EINVAL; 180 } 181 182 /* Make sure thread is configured for right direction */ 183 if (!(mmio_read_32(spt->scfg + SCFG_THREAD_CTRL) & SCFG_THREAD_CTRL_DIR_MASK)) { 184 ERROR("Cannot clear a transmit thread %s\n", spt->name); 185 return -EINVAL; 186 } 187 188 /* Read off messages from thread until empty */ 189 uint32_t try_count = 10; 190 while (mmio_read_32(spt->rt + RT_THREAD_STATUS) & RT_THREAD_STATUS_CUR_CNT_MASK) { 191 if (!(try_count--)) { 192 ERROR("Could not clear all messages from thread %s\n", spt->name); 193 return -ETIMEDOUT; 194 } 195 WARN("Clearing message from thread %s\n", spt->name); 196 mmio_read_32(spt->data + spm.desc.data_end_offset); 197 } 198 199 return 0; 200 } 201 202 /** 203 * ti_sci_transport_send() - Send data over a Secure Proxy thread 204 * @id: Channel Identifier 205 * @msg: Pointer to ti_sci_msg 206 * 207 * Return: 0 if all goes well, else appropriate error message 208 */ 209 int ti_sci_transport_send(enum ti_sci_transport_chan_id id, const struct ti_sci_msg *msg) 210 { 211 struct k3_sec_proxy_thread *spt = &spm.threads[id]; 212 union sec_msg_hdr secure_header; 213 int num_words, trail_bytes, i, ret; 214 uintptr_t data_reg; 215 216 ret = k3_sec_proxy_verify_thread(spt, THREAD_IS_TX); 217 if (ret) { 218 ERROR("Thread %s verification failed (%d)\n", spt->name, ret); 219 return ret; 220 } 221 222 /* Check the message size */ 223 if (msg->len + sizeof(secure_header) > spm.desc.max_msg_size) { 224 ERROR("Thread %s message length %lu > max msg size\n", 225 spt->name, msg->len); 226 return -EINVAL; 227 } 228 229 /* TODO: Calculate checksum */ 230 secure_header.checksum = 0; 231 232 /* Send the secure header */ 233 data_reg = spm.desc.data_start_offset; 234 mmio_write_32(spt->data + data_reg, secure_header.data); 235 data_reg += sizeof(uint32_t); 236 237 /* Send whole words */ 238 num_words = msg->len / sizeof(uint32_t); 239 for (i = 0; i < num_words; i++) { 240 mmio_write_32(spt->data + data_reg, ((uint32_t *)msg->buf)[i]); 241 data_reg += sizeof(uint32_t); 242 } 243 244 /* Send remaining bytes */ 245 trail_bytes = msg->len % sizeof(uint32_t); 246 if (trail_bytes) { 247 uint32_t data_trail = 0; 248 249 i = msg->len - trail_bytes; 250 while (trail_bytes--) { 251 data_trail <<= 8; 252 data_trail |= msg->buf[i++]; 253 } 254 255 mmio_write_32(spt->data + data_reg, data_trail); 256 data_reg += sizeof(uint32_t); 257 } 258 /* 259 * 'data_reg' indicates next register to write. If we did not already 260 * write on tx complete reg(last reg), we must do so for transmit 261 * In addition, we also need to make sure all intermediate data 262 * registers(if any required), are reset to 0 for TISCI backward 263 * compatibility to be maintained. 264 */ 265 while (data_reg <= spm.desc.data_end_offset) { 266 mmio_write_32(spt->data + data_reg, 0); 267 data_reg += sizeof(uint32_t); 268 } 269 270 VERBOSE("Message successfully sent on thread %s\n", spt->name); 271 272 return 0; 273 } 274 275 /** 276 * ti_sci_transport_recv() - Receive data from a Secure Proxy thread 277 * @id: Channel Identifier 278 * @msg: Pointer to ti_sci_msg 279 * 280 * Return: 0 if all goes well, else appropriate error message 281 */ 282 int ti_sci_transport_recv(enum ti_sci_transport_chan_id id, struct ti_sci_msg *msg) 283 { 284 struct k3_sec_proxy_thread *spt = &spm.threads[id]; 285 union sec_msg_hdr secure_header; 286 uintptr_t data_reg; 287 int num_words, trail_bytes, i, ret; 288 289 ret = k3_sec_proxy_verify_thread(spt, THREAD_IS_RX); 290 if (ret) { 291 ERROR("Thread %s verification failed (%d)\n", spt->name, ret); 292 return ret; 293 } 294 295 /* Read secure header */ 296 data_reg = spm.desc.data_start_offset; 297 secure_header.data = mmio_read_32(spt->data + data_reg); 298 data_reg += sizeof(uint32_t); 299 300 /* Read whole words */ 301 num_words = msg->len / sizeof(uint32_t); 302 for (i = 0; i < num_words; i++) { 303 ((uint32_t *)msg->buf)[i] = mmio_read_32(spt->data + data_reg); 304 data_reg += sizeof(uint32_t); 305 } 306 307 /* Read remaining bytes */ 308 trail_bytes = msg->len % sizeof(uint32_t); 309 if (trail_bytes) { 310 uint32_t data_trail = mmio_read_32(spt->data + data_reg); 311 data_reg += sizeof(uint32_t); 312 313 i = msg->len - trail_bytes; 314 while (trail_bytes--) { 315 msg->buf[i++] = data_trail & 0xff; 316 data_trail >>= 8; 317 } 318 } 319 320 /* 321 * 'data_reg' indicates next register to read. If we did not already 322 * read on rx complete reg(last reg), we must do so for receive 323 */ 324 if (data_reg <= spm.desc.data_end_offset) 325 mmio_read_32(spt->data + spm.desc.data_end_offset); 326 327 /* TODO: Verify checksum */ 328 (void)secure_header.checksum; 329 330 VERBOSE("Message successfully received from thread %s\n", spt->name); 331 332 return 0; 333 } 334