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