ti: k3: drivers: Add Secure Proxy driver
authorAndrew F. Davis <afd@ti.com>
Fri, 4 May 2018 19:06:08 +0000 (19:06 +0000)
committerAndrew F. Davis <afd@ti.com>
Wed, 22 Aug 2018 15:33:09 +0000 (10:33 -0500)
Secure Proxy module manages hardware threads that are meant
for communication between the processor entities. Add support
for this here.

Signed-off-by: Andrew F. Davis <afd@ti.com>
plat/ti/k3/common/drivers/sec_proxy/sec_proxy.c [new file with mode: 0644]
plat/ti/k3/common/drivers/sec_proxy/sec_proxy.h [new file with mode: 0644]
plat/ti/k3/common/k3_bl31_setup.c
plat/ti/k3/common/plat_common.mk
plat/ti/k3/include/platform_def.h

diff --git a/plat/ti/k3/common/drivers/sec_proxy/sec_proxy.c b/plat/ti/k3/common/drivers/sec_proxy/sec_proxy.c
new file mode 100644 (file)
index 0000000..92414b9
--- /dev/null
@@ -0,0 +1,289 @@
+/*
+ * Texas Instruments K3 Secure Proxy Driver
+ *   Based on Linux and U-Boot implementation
+ *
+ * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <debug.h>
+#include <errno.h>
+#include <mmio.h>
+#include <platform_def.h>
+#include <stdlib.h>
+#include <utils.h>
+#include <utils_def.h>
+
+#include "sec_proxy.h"
+
+/* SEC PROXY RT THREAD STATUS */
+#define RT_THREAD_STATUS                       (0x0)
+#define RT_THREAD_STATUS_ERROR_SHIFT           (31)
+#define RT_THREAD_STATUS_ERROR_MASK            BIT(31)
+#define RT_THREAD_STATUS_CUR_CNT_SHIFT         (0)
+#define RT_THREAD_STATUS_CUR_CNT_MASK          GENMASK(7, 0)
+
+/* SEC PROXY SCFG THREAD CTRL */
+#define SCFG_THREAD_CTRL                       (0x1000)
+#define SCFG_THREAD_CTRL_DIR_SHIFT             (31)
+#define SCFG_THREAD_CTRL_DIR_MASK              BIT(31)
+
+#define SEC_PROXY_THREAD(base, x)              ((base) + (0x1000 * (x)))
+#define THREAD_IS_RX                           (1)
+#define THREAD_IS_TX                           (0)
+
+/**
+ * struct k3_sec_proxy_desc - Description of secure proxy integration
+ * @timeout_us:                Timeout for communication (in Microseconds)
+ * @max_msg_size:      Message size in bytes
+ * @data_start_offset: Offset of the First data register of the thread
+ * @data_end_offset:   Offset of the Last data register of the thread
+ */
+struct k3_sec_proxy_desc {
+       uint32_t timeout_us;
+       uint16_t max_msg_size;
+       uint16_t data_start_offset;
+       uint16_t data_end_offset;
+};
+
+/**
+ * struct k3_sec_proxy_thread - Description of a secure proxy Thread
+ * @id:                Thread ID
+ * @data:      Thread Data path region for target
+ * @scfg:      Secure Config Region for Thread
+ * @rt:                RealTime Region for Thread
+ */
+struct k3_sec_proxy_thread {
+       uint32_t id;
+       uintptr_t data;
+       uintptr_t scfg;
+       uintptr_t rt;
+};
+
+/**
+ * struct k3_sec_proxy_mbox - Description of a Secure Proxy Instance
+ * @desc:      Description of the SoC integration
+ * @chans:     Array for valid thread instances
+ */
+struct k3_sec_proxy_mbox {
+       const struct k3_sec_proxy_desc desc;
+       struct k3_sec_proxy_thread threads[];
+};
+
+/*
+ * Thread ID #0: DMSC notify
+ * Thread ID #1: DMSC request response
+ * Thread ID #2: DMSC request high priority
+ * Thread ID #3: DMSC request low priority
+ * Thread ID #4: DMSC notify response
+ */
+#define SP_THREAD(_x) \
+       [_x] = { \
+               .id = _x, \
+               .data = SEC_PROXY_THREAD(SEC_PROXY_DATA_BASE, _x), \
+               .scfg = SEC_PROXY_THREAD(SEC_PROXY_SCFG_BASE, _x), \
+               .rt = SEC_PROXY_THREAD(SEC_PROXY_RT_BASE, _x), \
+       }
+
+static struct k3_sec_proxy_mbox spm = {
+       .desc = {
+               .timeout_us = SEC_PROXY_TIMEOUT_US,
+               .max_msg_size = SEC_PROXY_MAX_MESSAGE_SIZE,
+               .data_start_offset = 0x4,
+               .data_end_offset = 0x3C,
+       },
+       .threads = {
+               SP_THREAD(SP_NOTIFY),
+               SP_THREAD(SP_RESPONSE),
+               SP_THREAD(SP_HIGH_PRIORITY),
+               SP_THREAD(SP_LOW_PRIORITY),
+               SP_THREAD(SP_NOTIFY_RESP),
+       },
+};
+
+/**
+ * struct sec_msg_hdr - Message header for secure messages and responses
+ * @checksum:  CRC of message for integrity checking
+ */
+union sec_msg_hdr {
+       struct {
+               uint16_t checksum;
+               uint16_t reserved;
+       } __packed;
+       uint32_t data;
+};
+
+/**
+ * k3_sec_proxy_verify_thread() - Verify thread status before
+ *                               sending/receiving data
+ * @spt: Pointer to Secure Proxy thread description
+ * @dir: Direction of the thread
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+static inline int k3_sec_proxy_verify_thread(struct k3_sec_proxy_thread *spt,
+                                            uint32_t dir)
+{
+       /* Check for any errors already available */
+       if (mmio_read_32(spt->rt + RT_THREAD_STATUS) &
+           RT_THREAD_STATUS_ERROR_MASK) {
+               ERROR("Thread %d is corrupted, cannot send data\n", spt->id);
+               return -EINVAL;
+       }
+
+       /* Make sure thread is configured for right direction */
+       if ((mmio_read_32(spt->scfg + SCFG_THREAD_CTRL) & SCFG_THREAD_CTRL_DIR_MASK)
+           != (dir << SCFG_THREAD_CTRL_DIR_SHIFT)) {
+               if (dir)
+                       ERROR("Trying to receive data on tx Thread %d\n",
+                             spt->id);
+               else
+                       ERROR("Trying to send data on rx Thread %d\n",
+                             spt->id);
+               return -EINVAL;
+       }
+
+       /* Check the message queue before sending/receiving data */
+       uint32_t tick_start = (uint32_t)read_cntpct_el0();
+       uint32_t ticks_per_us = SYS_COUNTER_FREQ_IN_TICKS / 1000000;
+       while (!(mmio_read_32(spt->rt + RT_THREAD_STATUS) & RT_THREAD_STATUS_CUR_CNT_MASK)) {
+               VERBOSE("Waiting for thread %d to clear\n", spt->id);
+               if (((uint32_t)read_cntpct_el0() - tick_start) >
+                   (spm.desc.timeout_us * ticks_per_us)) {
+                       ERROR("Timeout waiting for thread %d to clear\n", spt->id);
+                       return -ETIMEDOUT;
+               }
+       }
+
+       return 0;
+}
+
+/**
+ * k3_sec_proxy_send() - Send data over a Secure Proxy thread
+ * @id: Channel Identifier
+ * @msg: Pointer to k3_sec_proxy_msg
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int k3_sec_proxy_send(enum k3_sec_proxy_chan_id id, const struct k3_sec_proxy_msg *msg)
+{
+       struct k3_sec_proxy_thread *spt = &spm.threads[id];
+       union sec_msg_hdr secure_header;
+       int num_words, trail_bytes, i, ret;
+       uintptr_t data_reg;
+
+       ret = k3_sec_proxy_verify_thread(spt, THREAD_IS_TX);
+       if (ret) {
+               ERROR("Thread %d verification failed (%d)\n", spt->id, ret);
+               return ret;
+       }
+
+       /* Check the message size */
+       if (msg->len + sizeof(secure_header) > spm.desc.max_msg_size) {
+               ERROR("Thread %d message length %lu > max msg size\n",
+                     spt->id, msg->len);
+               return -EINVAL;
+       }
+
+       /* TODO: Calculate checksum */
+       secure_header.checksum = 0;
+
+       /* Send the secure header */
+       data_reg = spm.desc.data_start_offset;
+       mmio_write_32(spt->data + data_reg, secure_header.data);
+       data_reg += sizeof(uint32_t);
+
+       /* Send whole words */
+       num_words = msg->len / sizeof(uint32_t);
+       for (i = 0; i < num_words; i++) {
+               mmio_write_32(spt->data + data_reg, ((uint32_t *)msg->buf)[i]);
+               data_reg += sizeof(uint32_t);
+       }
+
+       /* Send remaining bytes */
+       trail_bytes = msg->len % sizeof(uint32_t);
+       if (trail_bytes) {
+               uint32_t data_trail = 0;
+
+               i = msg->len - trail_bytes;
+               while (trail_bytes--) {
+                       data_trail <<= 8;
+                       data_trail |= msg->buf[i++];
+               }
+
+               mmio_write_32(spt->data + data_reg, data_trail);
+               data_reg += sizeof(uint32_t);
+       }
+       /*
+        * 'data_reg' indicates next register to write. If we did not already
+        * write on tx complete reg(last reg), we must do so for transmit
+        */
+       if (data_reg <= spm.desc.data_end_offset)
+               mmio_write_32(spt->data + spm.desc.data_end_offset, 0);
+
+       VERBOSE("Message successfully sent on thread %ud\n", id);
+
+       return 0;
+}
+
+/**
+ * k3_sec_proxy_recv() - Receive data from a Secure Proxy thread
+ * @id: Channel Identifier
+ * @msg: Pointer to k3_sec_proxy_msg
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int k3_sec_proxy_recv(uint32_t id, struct k3_sec_proxy_msg *msg)
+{
+       struct k3_sec_proxy_thread *spt = &spm.threads[id];
+       union sec_msg_hdr secure_header;
+       uintptr_t data_reg;
+       int num_words, trail_bytes, i, ret;
+
+       ret = k3_sec_proxy_verify_thread(spt, THREAD_IS_RX);
+       if (ret) {
+               ERROR("Thread %d verification failed (%d)\n", spt->id, ret);
+               return ret;
+       }
+
+       /* Read secure header */
+       data_reg = spm.desc.data_start_offset;
+       secure_header.data = mmio_read_32(spt->data + data_reg);
+       data_reg += sizeof(uint32_t);
+
+       /* Read whole words */
+       num_words = msg->len / sizeof(uint32_t);
+       for (i = 0; i < num_words; i++) {
+               ((uint32_t *)msg->buf)[i] = mmio_read_32(spt->data + data_reg);
+               data_reg += sizeof(uint32_t);
+       }
+
+       /* Read remaining bytes */
+       trail_bytes = msg->len % sizeof(uint32_t);
+       if (trail_bytes) {
+               uint32_t data_trail = mmio_read_32(spt->data + data_reg);
+               data_reg += sizeof(uint32_t);
+
+               i = msg->len - trail_bytes;
+               while (trail_bytes--) {
+                       msg->buf[i] = data_trail & 0xff;
+                       data_trail >>= 8;
+               }
+       }
+
+       /*
+        * 'data_reg' indicates next register to read. If we did not already
+        * read on rx complete reg(last reg), we must do so for receive
+        */
+       if (data_reg <= spm.desc.data_end_offset)
+               mmio_read_32(spt->data + spm.desc.data_end_offset);
+
+       /* TODO: Verify checksum */
+       (void)secure_header.checksum;
+
+       VERBOSE("Message successfully received from thread %ud\n", id);
+
+       return 0;
+}
diff --git a/plat/ti/k3/common/drivers/sec_proxy/sec_proxy.h b/plat/ti/k3/common/drivers/sec_proxy/sec_proxy.h
new file mode 100644 (file)
index 0000000..facfd19
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Texas Instruments K3 Secure Proxy Driver
+ *   Based on Linux and U-Boot implementation
+ *
+ * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef K3_SEC_PROXY_H
+#define K3_SEC_PROXY_H
+
+#include <stdint.h>
+
+/**
+ * enum k3_sec_proxy_chan_id - Secure Proxy thread IDs
+ *
+ * These the available IDs used in k3_sec_proxy_{send,recv}()
+ */
+enum k3_sec_proxy_chan_id {
+       SP_NOTIFY = 0,
+       SP_RESPONSE,
+       SP_HIGH_PRIORITY,
+       SP_LOW_PRIORITY,
+       SP_NOTIFY_RESP,
+};
+
+/**
+ * struct k3_sec_proxy_msg - Secure proxy message structure
+ * @len: Length of data in the Buffer
+ * @buf: Buffer pointer
+ *
+ * This is the structure for data used in k3_sec_proxy_{send,recv}()
+ */
+struct k3_sec_proxy_msg {
+       size_t len;
+       uint8_t *buf;
+};
+
+/**
+ * k3_sec_proxy_send() - Send data over a Secure Proxy thread
+ * @id: Channel Identifier
+ * @msg: Pointer to k3_sec_proxy_msg
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int k3_sec_proxy_send(enum k3_sec_proxy_chan_id id, const struct k3_sec_proxy_msg *msg);
+
+/**
+ * k3_sec_proxy_recv() - Receive data from a Secure Proxy thread
+ * @id: Channel Identifier
+ * @msg: Pointer to k3_sec_proxy_msg
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int k3_sec_proxy_recv(enum k3_sec_proxy_chan_id id, struct k3_sec_proxy_msg *msg);
+
+#endif /* K3_SEC_PROXY_H */
index 3de57a7c4f61786cb435f0917115838123426320..19816a71b2aa99d499143b6c8c9da57af0096a6c 100644 (file)
@@ -21,6 +21,9 @@ const mmap_region_t plat_arm_mmap[] = {
        MAP_REGION_FLAT(K3_USART_BASE_ADDRESS, K3_USART_SIZE, MT_DEVICE | MT_RW | MT_SECURE),
        MAP_REGION_FLAT(K3_GICD_BASE, K3_GICD_SIZE, MT_DEVICE | MT_RW | MT_SECURE),
        MAP_REGION_FLAT(K3_GICR_BASE, K3_GICR_SIZE, MT_DEVICE | MT_RW | MT_SECURE),
+       MAP_REGION_FLAT(SEC_PROXY_RT_BASE, SEC_PROXY_RT_SIZE, MT_DEVICE | MT_RW | MT_SECURE),
+       MAP_REGION_FLAT(SEC_PROXY_SCFG_BASE, SEC_PROXY_SCFG_SIZE, MT_DEVICE | MT_RW | MT_SECURE),
+       MAP_REGION_FLAT(SEC_PROXY_DATA_BASE, SEC_PROXY_DATA_SIZE, MT_DEVICE | MT_RW | MT_SECURE),
        { /* sentinel */ }
 };
 
index 7cb6eb78ef982dd97311486752309576c6c8cfbf..5f19127d0ed2a24f519df7660c8bc05cf9d99c39 100644 (file)
@@ -36,6 +36,7 @@ PLAT_INCLUDES         +=      \
                                -I${PLAT_PATH}/include                  \
                                -Iinclude/plat/arm/common/              \
                                -Iinclude/plat/arm/common/aarch64/      \
+                               -I${PLAT_PATH}/common/drivers/sec_proxy \
 
 K3_CONSOLE_SOURCES     +=      \
                                drivers/console/aarch64/console.S       \
@@ -53,6 +54,9 @@ K3_PSCI_SOURCES               +=      \
                                plat/common/plat_psci_common.c          \
                                ${PLAT_PATH}/common/k3_psci.c           \
 
+K3_SEC_PROXY_SOURCES   +=      \
+                               ${PLAT_PATH}/common/drivers/sec_proxy/sec_proxy.c \
+
 PLAT_BL_COMMON_SOURCES +=      \
                                plat/arm/common/arm_common.c            \
                                lib/cpus/aarch64/cortex_a53.S           \
@@ -65,3 +69,4 @@ BL31_SOURCES          +=      \
                                ${PLAT_PATH}/common/k3_topology.c       \
                                ${K3_GIC_SOURCES}                       \
                                ${K3_PSCI_SOURCES}                      \
+                               ${K3_SEC_PROXY_SOURCES}                 \
index ebc9c477091a96e413f7d2afa00938295b3aed63..7159328aca2c46637c58928ce8f52a08b2493047 100644 (file)
  * runtime memory used, choose the smallest value needed to register the
  * required regions for each BL stage.
  */
-#define MAX_MMAP_REGIONS       8
+#define MAX_MMAP_REGIONS       11
 
 /*
  * Defines the total size of the address space in bytes. For example, for a 32
 #define K3_GICR_BASE  0x01880000
 #define K3_GICR_SIZE  0x100000
 
+#define SEC_PROXY_DATA_BASE    0x32C00000
+#define SEC_PROXY_DATA_SIZE    0x80000
+#define SEC_PROXY_SCFG_BASE    0x32800000
+#define SEC_PROXY_SCFG_SIZE    0x80000
+#define SEC_PROXY_RT_BASE      0x32400000
+#define SEC_PROXY_RT_SIZE      0x80000
+
+#define SEC_PROXY_TIMEOUT_US           1000000
+#define SEC_PROXY_MAX_MESSAGE_SIZE     56
+
 #endif /* __PLATFORM_DEF_H__ */