uboot/drivers/remoteproc/k3_system_controller.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Texas Instruments' K3 System Controller 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 <dm.h>
  11#include <remoteproc.h>
  12#include <errno.h>
  13#include <mailbox.h>
  14#include <linux/soc/ti/k3-sec-proxy.h>
  15
  16#define K3_MSG_R5_TO_M3_M3FW                    0x8105
  17#define K3_MSG_M3_TO_R5_CERT_RESULT             0x8805
  18#define K3_MSG_M3_TO_R5_BOOT_NOTIFICATION       0x000A
  19
  20#define K3_FLAGS_MSG_CERT_AUTH_PASS             0x555555
  21#define K3_FLAGS_MSG_CERT_AUTH_FAIL             0xffffff
  22
  23/**
  24 * struct k3_sysctrler_msg_hdr - Generic Header for Messages and responses.
  25 * @cmd_id:     Message ID. One of K3_MSG_*
  26 * @host_id:    Host ID of the message
  27 * @seq_ne:     Message identifier indicating a transfer sequence.
  28 * @flags:      Flags for the message.
  29 */
  30struct k3_sysctrler_msg_hdr {
  31        u16 cmd_id;
  32        u8 host_id;
  33        u8 seq_nr;
  34        u32 flags;
  35} __packed;
  36
  37/**
  38 * struct k3_sysctrler_load_msg - Message format for Firmware loading
  39 * @hdr:                Generic message hdr
  40 * @buffer_address:     Address at which firmware is located.
  41 * @buffer_size:        Size of the firmware.
  42 */
  43struct k3_sysctrler_load_msg {
  44        struct k3_sysctrler_msg_hdr hdr;
  45        u32 buffer_address;
  46        u32 buffer_size;
  47} __packed;
  48
  49/**
  50 * struct k3_sysctrler_boot_notification_msg - Message format for boot
  51 *                                             notification
  52 * @checksum:           Checksum for the entire message
  53 * @reserved:           Reserved for future use.
  54 * @hdr:                Generic message hdr
  55 */
  56struct k3_sysctrler_boot_notification_msg {
  57        u16 checksum;
  58        u16 reserved;
  59        struct k3_sysctrler_msg_hdr hdr;
  60} __packed;
  61
  62/**
  63 * struct k3_sysctrler_desc - Description of SoC integration.
  64 * @host_id:    Host identifier representing the compute entity
  65 * @max_rx_timeout_ms:  Timeout for communication with SoC (in Milliseconds)
  66 * @max_msg_size: Maximum size of data per message that can be handled.
  67 */
  68struct k3_sysctrler_desc {
  69        u8 host_id;
  70        int max_rx_timeout_us;
  71        int max_msg_size;
  72};
  73
  74/**
  75 * struct k3_sysctrler_privdata - Structure representing System Controller data.
  76 * @chan_tx:    Transmit mailbox channel
  77 * @chan_rx:    Receive mailbox channel
  78 * @desc:       SoC description for this instance
  79 * @seq_nr:     Counter for number of messages sent.
  80 */
  81struct k3_sysctrler_privdata {
  82        struct mbox_chan chan_tx;
  83        struct mbox_chan chan_rx;
  84        struct k3_sysctrler_desc *desc;
  85        u32 seq_nr;
  86};
  87
  88static inline
  89void k3_sysctrler_load_msg_setup(struct k3_sysctrler_load_msg *fw,
  90                                 struct k3_sysctrler_privdata *priv,
  91                                 ulong addr, ulong size)
  92{
  93        fw->hdr.cmd_id = K3_MSG_R5_TO_M3_M3FW;
  94        fw->hdr.host_id = priv->desc->host_id;
  95        fw->hdr.seq_nr = priv->seq_nr++;
  96        fw->hdr.flags = 0x0;
  97        fw->buffer_address = addr;
  98        fw->buffer_size = size;
  99}
 100
 101static int k3_sysctrler_load_response(u32 *buf)
 102{
 103        struct k3_sysctrler_load_msg *fw;
 104
 105        fw = (struct k3_sysctrler_load_msg *)buf;
 106
 107        /* Check for proper response ID */
 108        if (fw->hdr.cmd_id != K3_MSG_M3_TO_R5_CERT_RESULT) {
 109                dev_err(dev, "%s: Command expected 0x%x, but received 0x%x\n",
 110                        __func__, K3_MSG_M3_TO_R5_CERT_RESULT, fw->hdr.cmd_id);
 111                return -EINVAL;
 112        }
 113
 114        /* Check for certificate authentication result */
 115        if (fw->hdr.flags == K3_FLAGS_MSG_CERT_AUTH_FAIL) {
 116                dev_err(dev, "%s: Firmware certificate authentication failed\n",
 117                        __func__);
 118                return -EINVAL;
 119        } else if (fw->hdr.flags != K3_FLAGS_MSG_CERT_AUTH_PASS) {
 120                dev_err(dev, "%s: Firmware Load response Invalid %d\n",
 121                        __func__, fw->hdr.flags);
 122                return -EINVAL;
 123        }
 124
 125        debug("%s: Firmware authentication passed\n", __func__);
 126
 127        return 0;
 128}
 129
 130static int k3_sysctrler_boot_notification_response(u32 *buf)
 131{
 132        struct k3_sysctrler_boot_notification_msg *boot;
 133
 134        boot = (struct k3_sysctrler_boot_notification_msg *)buf;
 135
 136        /* ToDo: Verify checksum */
 137
 138        /* Check for proper response ID */
 139        if (boot->hdr.cmd_id != K3_MSG_M3_TO_R5_BOOT_NOTIFICATION) {
 140                dev_err(dev, "%s: Command expected 0x%x, but received 0x%x\n",
 141                        __func__, K3_MSG_M3_TO_R5_BOOT_NOTIFICATION,
 142                        boot->hdr.cmd_id);
 143                return -EINVAL;
 144        }
 145
 146        debug("%s: Boot notification received\n", __func__);
 147
 148        return 0;
 149}
 150
 151/**
 152 * k3_sysctrler_load() - Loadup the K3 remote processor
 153 * @dev:        corresponding K3 remote processor device
 154 * @addr:       Address in memory where image binary is stored
 155 * @size:       Size in bytes of the image binary
 156 *
 157 * Return: 0 if all goes good, else appropriate error message.
 158 */
 159static int k3_sysctrler_load(struct udevice *dev, ulong addr, ulong size)
 160{
 161        struct k3_sysctrler_privdata *priv = dev_get_priv(dev);
 162        struct k3_sysctrler_load_msg firmware;
 163        struct k3_sec_proxy_msg msg;
 164        int ret;
 165
 166        debug("%s: Loading binary from 0x%08lX, size 0x%08lX\n",
 167              __func__, addr, size);
 168
 169        memset(&firmware, 0, sizeof(firmware));
 170        memset(&msg, 0, sizeof(msg));
 171
 172        /* Setup the message */
 173        k3_sysctrler_load_msg_setup(&firmware, priv, addr, size);
 174        msg.len = sizeof(firmware);
 175        msg.buf = (u32 *)&firmware;
 176
 177        /* Send the message */
 178        ret = mbox_send(&priv->chan_tx, &msg);
 179        if (ret) {
 180                dev_err(dev, "%s: Firmware Loading failed. ret = %d\n",
 181                        __func__, ret);
 182                return ret;
 183        }
 184
 185        /* Receive the response */
 186        ret = mbox_recv(&priv->chan_rx, &msg, priv->desc->max_rx_timeout_us);
 187        if (ret) {
 188                dev_err(dev, "%s: Firmware Load response failed. ret = %d\n",
 189                        __func__, ret);
 190                return ret;
 191        }
 192
 193        /* Process the response */
 194        ret = k3_sysctrler_load_response(msg.buf);
 195        if (ret)
 196                return ret;
 197
 198        debug("%s: Firmware Loaded successfully on dev %s\n",
 199              __func__, dev->name);
 200
 201        return 0;
 202}
 203
 204/**
 205 * k3_sysctrler_start() - Start the remote processor
 206 *              Note that while technically the K3 system controller starts up
 207 *              automatically after its firmware got loaded we still want to
 208 *              utilize the rproc start operation for other startup-related
 209 *              tasks.
 210 * @dev:        device to operate upon
 211 *
 212 * Return: 0 if all went ok, else return appropriate error
 213 */
 214static int k3_sysctrler_start(struct udevice *dev)
 215{
 216        struct k3_sysctrler_privdata *priv = dev_get_priv(dev);
 217        struct k3_sec_proxy_msg msg;
 218        int ret;
 219
 220        debug("%s(dev=%p)\n", __func__, dev);
 221
 222        /* Receive the boot notification. Note that it is sent only once. */
 223        ret = mbox_recv(&priv->chan_rx, &msg, priv->desc->max_rx_timeout_us);
 224        if (ret) {
 225                dev_err(dev, "%s: Boot Notification response failed. ret = %d\n",
 226                        __func__, ret);
 227                return ret;
 228        }
 229
 230        /* Process the response */
 231        ret = k3_sysctrler_boot_notification_response(msg.buf);
 232        if (ret)
 233                return ret;
 234
 235        debug("%s: Boot notification received successfully on dev %s\n",
 236              __func__, dev->name);
 237
 238        return 0;
 239}
 240
 241static const struct dm_rproc_ops k3_sysctrler_ops = {
 242        .load = k3_sysctrler_load,
 243        .start = k3_sysctrler_start,
 244};
 245
 246/**
 247 * k3_of_to_priv() - generate private data from device tree
 248 * @dev:        corresponding k3 remote processor device
 249 * @priv:       pointer to driver specific private data
 250 *
 251 * Return: 0 if all goes good, else appropriate error message.
 252 */
 253static int k3_of_to_priv(struct udevice *dev,
 254                         struct k3_sysctrler_privdata *priv)
 255{
 256        int ret;
 257
 258        ret = mbox_get_by_name(dev, "tx", &priv->chan_tx);
 259        if (ret) {
 260                dev_err(dev, "%s: Acquiring Tx channel failed. ret = %d\n",
 261                        __func__, ret);
 262                return ret;
 263        }
 264
 265        ret = mbox_get_by_name(dev, "rx", &priv->chan_rx);
 266        if (ret) {
 267                dev_err(dev, "%s: Acquiring Rx channel failed. ret = %d\n",
 268                        __func__, ret);
 269                return ret;
 270        }
 271
 272        return 0;
 273}
 274
 275/**
 276 * k3_sysctrler_probe() - Basic probe
 277 * @dev:        corresponding k3 remote processor device
 278 *
 279 * Return: 0 if all goes good, else appropriate error message.
 280 */
 281static int k3_sysctrler_probe(struct udevice *dev)
 282{
 283        struct k3_sysctrler_privdata *priv;
 284        int ret;
 285
 286        debug("%s(dev=%p)\n", __func__, dev);
 287
 288        priv = dev_get_priv(dev);
 289
 290        ret = k3_of_to_priv(dev, priv);
 291        if (ret) {
 292                dev_err(dev, "%s: Probe failed with error %d\n", __func__, ret);
 293                return ret;
 294        }
 295
 296        priv->desc = (void *)dev_get_driver_data(dev);
 297        priv->seq_nr = 0;
 298
 299        return 0;
 300}
 301
 302static const struct k3_sysctrler_desc k3_sysctrler_am654_desc = {
 303        .host_id = 4,                           /* HOST_ID_R5_1 */
 304        .max_rx_timeout_us = 800000,
 305        .max_msg_size = 60,
 306};
 307
 308static const struct udevice_id k3_sysctrler_ids[] = {
 309        {
 310                .compatible = "ti,am654-system-controller",
 311                .data = (ulong)&k3_sysctrler_am654_desc,
 312        },
 313        {}
 314};
 315
 316U_BOOT_DRIVER(k3_sysctrler) = {
 317        .name = "k3_system_controller",
 318        .of_match = k3_sysctrler_ids,
 319        .id = UCLASS_REMOTEPROC,
 320        .ops = &k3_sysctrler_ops,
 321        .probe = k3_sysctrler_probe,
 322        .priv_auto_alloc_size = sizeof(struct k3_sysctrler_privdata),
 323};
 324