uboot/drivers/mailbox/k3-sec-proxy.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Texas Instruments' K3 Secure proxy Driver
   4 *
   5 * Copyright (C) 2017-2018 Texas Instruments Incorporated - http://www.ti.com/
   6 *      Lokesh Vutla <lokeshvutla@ti.com>
   7 */
   8
   9#include <common.h>
  10#include <asm/io.h>
  11#include <linux/types.h>
  12#include <linux/bitops.h>
  13#include <linux/soc/ti/k3-sec-proxy.h>
  14#include <dm.h>
  15#include <mailbox-uclass.h>
  16
  17DECLARE_GLOBAL_DATA_PTR;
  18
  19/* SEC PROXY RT THREAD STATUS */
  20#define RT_THREAD_STATUS                        0x0
  21#define RT_THREAD_THRESHOLD                     0x4
  22#define RT_THREAD_STATUS_ERROR_SHIFT            31
  23#define RT_THREAD_STATUS_ERROR_MASK             BIT(31)
  24#define RT_THREAD_STATUS_CUR_CNT_SHIFT          0
  25#define RT_THREAD_STATUS_CUR_CNT_MASK           GENMASK(7, 0)
  26
  27/* SEC PROXY SCFG THREAD CTRL */
  28#define SCFG_THREAD_CTRL                        0x1000
  29#define SCFG_THREAD_CTRL_DIR_SHIFT              31
  30#define SCFG_THREAD_CTRL_DIR_MASK               BIT(31)
  31
  32#define SEC_PROXY_THREAD(base, x)               ((base) + (0x1000 * (x)))
  33#define THREAD_IS_RX                            1
  34#define THREAD_IS_TX                            0
  35
  36/**
  37 * struct k3_sec_proxy_desc - Description of secure proxy integration.
  38 * @thread_count:       Number of Threads.
  39 * @max_msg_size:       Message size in bytes.
  40 * @data_start_offset:  Offset of the First data register of the thread
  41 * @data_end_offset:    Offset of the Last data register of the thread
  42 * @valid_threads:      List of Valid threads that the processor can access
  43 * @num_valid_threads:  Number of valid threads.
  44 */
  45struct k3_sec_proxy_desc {
  46        u16 thread_count;
  47        u16 max_msg_size;
  48        u16 data_start_offset;
  49        u16 data_end_offset;
  50        const u32 *valid_threads;
  51        u32 num_valid_threads;
  52};
  53
  54/**
  55 * struct k3_sec_proxy_thread - Description of a secure proxy Thread
  56 * @id:         Thread ID
  57 * @data:       Thread Data path region for target
  58 * @scfg:       Secure Config Region for Thread
  59 * @rt:         RealTime Region for Thread
  60 * @rx_buf:     Receive buffer data, max message size.
  61 */
  62struct k3_sec_proxy_thread {
  63        u32 id;
  64        void __iomem *data;
  65        void __iomem *scfg;
  66        void __iomem *rt;
  67        u32 *rx_buf;
  68};
  69
  70/**
  71 * struct k3_sec_proxy_mbox - Description of a Secure Proxy Instance
  72 * @chan:               Mailbox Channel
  73 * @desc:               Description of the SoC integration
  74 * @chans:              Array for valid thread instances
  75 * @target_data:        Secure Proxy region for Target Data
  76 * @scfg:               Secure Proxy Region for Secure configuration.
  77 * @rt:                 Secure proxy Region for Real Time Region.
  78 */
  79struct k3_sec_proxy_mbox {
  80        struct mbox_chan chan;
  81        struct k3_sec_proxy_desc *desc;
  82        struct k3_sec_proxy_thread *chans;
  83        phys_addr_t target_data;
  84        phys_addr_t scfg;
  85        phys_addr_t rt;
  86};
  87
  88static inline u32 sp_readl(void __iomem *addr, unsigned int offset)
  89{
  90        return readl(addr + offset);
  91}
  92
  93static inline void sp_writel(void __iomem *addr, unsigned int offset, u32 data)
  94{
  95        writel(data, addr + offset);
  96}
  97
  98/**
  99 * k3_sec_proxy_of_xlate() - Translation of phandle to channel
 100 * @chan:       Mailbox channel
 101 * @args:       Phandle Pointer
 102 *
 103 * Translates the phandle args and fills up the Mailbox channel from client.
 104 * Return: 0 if all goes good, else return corresponding error message.
 105 */
 106static int k3_sec_proxy_of_xlate(struct mbox_chan *chan,
 107                                 struct ofnode_phandle_args *args)
 108{
 109        struct k3_sec_proxy_mbox *spm = dev_get_priv(chan->dev);
 110        int ind, i;
 111
 112        debug("%s(chan=%p)\n", __func__, chan);
 113
 114        if (args->args_count != 1) {
 115                debug("Invaild args_count: %d\n", args->args_count);
 116                return -EINVAL;
 117        }
 118        ind = args->args[0];
 119
 120        for (i = 0; i < spm->desc->num_valid_threads; i++)
 121                if (spm->chans[i].id == ind) {
 122                        chan->id = ind;
 123                        chan->con_priv = &spm->chans[i];
 124                        return 0;
 125                }
 126
 127        dev_err(chan->dev, "%s: Invalid Thread ID %d\n", __func__, ind);
 128        return -ENOENT;
 129}
 130
 131/**
 132 * k3_sec_proxy_request() - Request for mailbox channel
 133 * @chan:       Channel Pointer
 134 */
 135static int k3_sec_proxy_request(struct mbox_chan *chan)
 136{
 137        debug("%s(chan=%p)\n", __func__, chan);
 138
 139        return 0;
 140}
 141
 142/**
 143 * k3_sec_proxy_free() - Free the mailbox channel
 144 * @chan:       Channel Pointer
 145 */
 146static int k3_sec_proxy_free(struct mbox_chan *chan)
 147{
 148        debug("%s(chan=%p)\n", __func__, chan);
 149
 150        return 0;
 151}
 152
 153/**
 154 * k3_sec_proxy_verify_thread() - Verify thread status before
 155 *                                sending/receiving data.
 156 * @spt:        pointer to secure proxy thread description
 157 * @dir:        Direction of the thread
 158 *
 159 * Return: 0 if all goes good, else appropriate error message.
 160 */
 161static inline int k3_sec_proxy_verify_thread(struct k3_sec_proxy_thread *spt,
 162                                             u8 dir)
 163{
 164        /* Check for any errors already available */
 165        if (sp_readl(spt->rt, RT_THREAD_STATUS) &
 166            RT_THREAD_STATUS_ERROR_MASK) {
 167                printf("%s: Thread %d is corrupted, cannot send data.\n",
 168                       __func__, spt->id);
 169                return -EINVAL;
 170        }
 171
 172        /* Make sure thread is configured for right direction */
 173        if ((sp_readl(spt->scfg, SCFG_THREAD_CTRL)
 174            & SCFG_THREAD_CTRL_DIR_MASK) >> SCFG_THREAD_CTRL_DIR_SHIFT != dir) {
 175                if (dir)
 176                        printf("%s: Trying to receive data on tx Thread %d\n",
 177                               __func__, spt->id);
 178                else
 179                        printf("%s: Trying to send data on rx Thread %d\n",
 180                               __func__, spt->id);
 181                return -EINVAL;
 182        }
 183
 184        /* Check the message queue before sending/receiving data */
 185        if (!(sp_readl(spt->rt, RT_THREAD_STATUS) &
 186              RT_THREAD_STATUS_CUR_CNT_MASK))
 187                return -ENODATA;
 188
 189        return 0;
 190}
 191
 192/**
 193 * k3_sec_proxy_send() - Send data via mailbox channel
 194 * @chan:       Channel Pointer
 195 * @data:       Pointer to k3_sec_proxy_msg
 196 *
 197 * Return: 0 if all goes good, else appropriate error message.
 198 */
 199static int k3_sec_proxy_send(struct mbox_chan *chan, const void *data)
 200{
 201        const struct k3_sec_proxy_msg *msg = (struct k3_sec_proxy_msg *)data;
 202        struct k3_sec_proxy_mbox *spm = dev_get_priv(chan->dev);
 203        struct k3_sec_proxy_thread *spt = chan->con_priv;
 204        int num_words, trail_bytes, ret;
 205        void __iomem *data_reg;
 206        u32 *word_data;
 207
 208        debug("%s(chan=%p, data=%p)\n", __func__, chan, data);
 209
 210        ret = k3_sec_proxy_verify_thread(spt, THREAD_IS_TX);
 211        if (ret) {
 212                dev_err(dev, "%s: Thread%d verification failed. ret = %d\n",
 213                        __func__, spt->id, ret);
 214                return ret;
 215        }
 216
 217        /* Check the message size. */
 218        if (msg->len > spm->desc->max_msg_size) {
 219                printf("%s: Thread %ld message length %zu > max msg size %d\n",
 220                       __func__, chan->id, msg->len, spm->desc->max_msg_size);
 221                return -EINVAL;
 222        }
 223
 224        /* Send the message */
 225        data_reg = spt->data + spm->desc->data_start_offset;
 226        for (num_words = msg->len / sizeof(u32), word_data = (u32 *)msg->buf;
 227             num_words;
 228             num_words--, data_reg += sizeof(u32), word_data++)
 229                writel(*word_data, data_reg);
 230
 231        trail_bytes = msg->len % sizeof(u32);
 232        if (trail_bytes) {
 233                u32 data_trail = *word_data;
 234
 235                /* Ensure all unused data is 0 */
 236                data_trail &= 0xFFFFFFFF >> (8 * (sizeof(u32) - trail_bytes));
 237                writel(data_trail, data_reg);
 238                data_reg++;
 239        }
 240
 241        /*
 242         * 'data_reg' indicates next register to write. If we did not already
 243         * write on tx complete reg(last reg), we must do so for transmit
 244         */
 245        if (data_reg <= (spt->data + spm->desc->data_end_offset))
 246                sp_writel(spt->data, spm->desc->data_end_offset, 0);
 247
 248        debug("%s: Message successfully sent on thread %ld\n",
 249              __func__, chan->id);
 250
 251        return 0;
 252}
 253
 254/**
 255 * k3_sec_proxy_recv() - Receive data via mailbox channel
 256 * @chan:       Channel Pointer
 257 * @data:       Pointer to k3_sec_proxy_msg
 258 *
 259 * Return: 0 if all goes good, else appropriate error message.
 260 */
 261static int k3_sec_proxy_recv(struct mbox_chan *chan, void *data)
 262{
 263        struct k3_sec_proxy_mbox *spm = dev_get_priv(chan->dev);
 264        struct k3_sec_proxy_thread *spt = chan->con_priv;
 265        struct k3_sec_proxy_msg *msg = data;
 266        void __iomem *data_reg;
 267        int num_words, ret;
 268        u32 *word_data;
 269
 270        debug("%s(chan=%p, data=%p)\n", __func__, chan, data);
 271
 272        ret = k3_sec_proxy_verify_thread(spt, THREAD_IS_RX);
 273        if (ret)
 274                return ret;
 275
 276        msg->len = spm->desc->max_msg_size;
 277        msg->buf = spt->rx_buf;
 278        data_reg = spt->data + spm->desc->data_start_offset;
 279        word_data = spt->rx_buf;
 280        for (num_words = spm->desc->max_msg_size / sizeof(u32);
 281             num_words;
 282             num_words--, data_reg += sizeof(u32), word_data++)
 283                *word_data = readl(data_reg);
 284
 285        debug("%s: Message successfully received from thread %ld\n",
 286              __func__, chan->id);
 287
 288        return 0;
 289}
 290
 291struct mbox_ops k3_sec_proxy_mbox_ops = {
 292        .of_xlate = k3_sec_proxy_of_xlate,
 293        .request = k3_sec_proxy_request,
 294        .free = k3_sec_proxy_free,
 295        .send = k3_sec_proxy_send,
 296        .recv = k3_sec_proxy_recv,
 297};
 298
 299/**
 300 * k3_sec_proxy_of_to_priv() - generate private data from device tree
 301 * @dev:        corresponding k3 secure proxy device
 302 * @spm:        pointer to driver specific private data
 303 *
 304 * Return: 0 if all went ok, else corresponding error message.
 305 */
 306static int k3_sec_proxy_of_to_priv(struct udevice *dev,
 307                                   struct k3_sec_proxy_mbox *spm)
 308{
 309        const void *blob = gd->fdt_blob;
 310
 311        if (!blob) {
 312                debug("'%s' no dt?\n", dev->name);
 313                return -ENODEV;
 314        }
 315
 316        spm->target_data = devfdt_get_addr_name(dev, "target_data");
 317        if (spm->target_data == FDT_ADDR_T_NONE) {
 318                dev_err(dev, "No reg property for target data base\n");
 319                return -EINVAL;
 320        }
 321
 322        spm->scfg = devfdt_get_addr_name(dev, "scfg");
 323        if (spm->rt == FDT_ADDR_T_NONE) {
 324                dev_err(dev, "No reg property for Secure Cfg base\n");
 325                return -EINVAL;
 326        }
 327
 328        spm->rt = devfdt_get_addr_name(dev, "rt");
 329        if (spm->rt == FDT_ADDR_T_NONE) {
 330                dev_err(dev, "No reg property for Real Time Cfg base\n");
 331                return -EINVAL;
 332        }
 333
 334        return 0;
 335}
 336
 337/**
 338 * k3_sec_proxy_thread_setup - Initialize the parameters for all valid threads
 339 * @spm:        Mailbox instance for which threads needs to be initialized
 340 *
 341 * Return: 0 if all went ok, else corresponding error message
 342 */
 343static int k3_sec_proxy_thread_setup(struct k3_sec_proxy_mbox *spm)
 344{
 345        struct k3_sec_proxy_thread *spt;
 346        int i, ind;
 347
 348        for (i = 0; i < spm->desc->num_valid_threads; i++) {
 349                spt = &spm->chans[i];
 350                ind = spm->desc->valid_threads[i];
 351                spt->id = ind;
 352                spt->data = (void *)SEC_PROXY_THREAD(spm->target_data, ind);
 353                spt->scfg = (void *)SEC_PROXY_THREAD(spm->scfg, ind);
 354                spt->rt = (void *)SEC_PROXY_THREAD(spm->rt, ind);
 355                spt->rx_buf = calloc(1, spm->desc->max_msg_size);
 356                if (!spt->rx_buf)
 357                        return -ENOMEM;
 358        }
 359
 360        return 0;
 361}
 362
 363/**
 364 * k3_sec_proxy_probe() - Basic probe
 365 * @dev:        corresponding mailbox device
 366 *
 367 * Return: 0 if all went ok, else corresponding error message
 368 */
 369static int k3_sec_proxy_probe(struct udevice *dev)
 370{
 371        struct k3_sec_proxy_mbox *spm = dev_get_priv(dev);
 372        int ret;
 373
 374        debug("%s(dev=%p)\n", __func__, dev);
 375
 376        ret = k3_sec_proxy_of_to_priv(dev, spm);
 377        if (ret)
 378                return ret;
 379
 380        spm->desc = (void *)dev_get_driver_data(dev);
 381        spm->chans = calloc(spm->desc->num_valid_threads,
 382                            sizeof(struct k3_sec_proxy_thread));
 383        if (!spm->chans)
 384                return -ENOMEM;
 385
 386        ret = k3_sec_proxy_thread_setup(spm);
 387        if (ret) {
 388                debug("%s: secure proxy thread setup failed\n", __func__);
 389                return ret;
 390        }
 391
 392        return 0;
 393}
 394
 395static int k3_sec_proxy_remove(struct udevice *dev)
 396{
 397        struct k3_sec_proxy_mbox *spm = dev_get_priv(dev);
 398
 399        debug("%s(dev=%p)\n", __func__, dev);
 400
 401        free(spm->chans);
 402
 403        return 0;
 404}
 405
 406/*
 407 * Thread ID #4: ROM request
 408 * Thread ID #5: ROM response, SYSFW notify
 409 * Thread ID #6: SYSFW request response
 410 * Thread ID #7: SYSFW request high priority
 411 * Thread ID #8: SYSFW request low priority
 412 * Thread ID #9: SYSFW notify response
 413 */
 414static const u32 am6x_valid_threads[] = { 4, 5, 6, 7, 8, 9, 11, 13 };
 415
 416static const struct k3_sec_proxy_desc am654_desc = {
 417        .thread_count = 90,
 418        .max_msg_size = 60,
 419        .data_start_offset = 0x4,
 420        .data_end_offset = 0x3C,
 421        .valid_threads = am6x_valid_threads,
 422        .num_valid_threads = ARRAY_SIZE(am6x_valid_threads),
 423};
 424
 425static const struct udevice_id k3_sec_proxy_ids[] = {
 426        { .compatible = "ti,am654-secure-proxy", .data = (ulong)&am654_desc},
 427        { }
 428};
 429
 430U_BOOT_DRIVER(k3_sec_proxy) = {
 431        .name = "k3-secure-proxy",
 432        .id = UCLASS_MAILBOX,
 433        .of_match = k3_sec_proxy_ids,
 434        .probe = k3_sec_proxy_probe,
 435        .remove = k3_sec_proxy_remove,
 436        .priv_auto_alloc_size = sizeof(struct k3_sec_proxy_mbox),
 437        .ops = &k3_sec_proxy_mbox_ops,
 438};
 439