uboot/drivers/firmware/scmi/mailbox_agent.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2020 Linaro Limited.
   4 */
   5
   6#define LOG_CATEGORY UCLASS_SCMI_AGENT
   7
   8#include <common.h>
   9#include <dm.h>
  10#include <errno.h>
  11#include <mailbox.h>
  12#include <scmi_agent.h>
  13#include <scmi_agent-uclass.h>
  14#include <dm/device_compat.h>
  15#include <dm/devres.h>
  16#include <linux/compat.h>
  17
  18#include "smt.h"
  19
  20#define TIMEOUT_US_10MS                 10000
  21
  22/**
  23 * struct scmi_mbox_channel - Description of an SCMI mailbox transport
  24 * @smt:        Shared memory buffer
  25 * @mbox:       Mailbox channel description
  26 * @timeout_us: Timeout in microseconds for the mailbox transfer
  27 */
  28struct scmi_mbox_channel {
  29        struct scmi_smt smt;
  30        struct mbox_chan mbox;
  31        ulong timeout_us;
  32};
  33
  34/**
  35 * struct scmi_channel - Channel instance referenced in SCMI drivers
  36 * @ref: Reference to local channel instance
  37 **/
  38struct scmi_channel {
  39        struct scmi_mbox_channel ref;
  40};
  41
  42static int scmi_mbox_process_msg(struct udevice *dev,
  43                                 struct scmi_channel *channel,
  44                                 struct scmi_msg *msg)
  45{
  46        struct scmi_mbox_channel *chan = &channel->ref;
  47        int ret;
  48
  49        ret = scmi_write_msg_to_smt(dev, &chan->smt, msg);
  50        if (ret)
  51                return ret;
  52
  53        /* Give shm addr to mbox in case it is meaningful */
  54        ret = mbox_send(&chan->mbox, chan->smt.buf);
  55        if (ret) {
  56                dev_err(dev, "Message send failed: %d\n", ret);
  57                goto out;
  58        }
  59
  60        /* Receive the response */
  61        ret = mbox_recv(&chan->mbox, chan->smt.buf, chan->timeout_us);
  62        if (ret) {
  63                dev_err(dev, "Response failed: %d, abort\n", ret);
  64                goto out;
  65        }
  66
  67        ret = scmi_read_resp_from_smt(dev, &chan->smt, msg);
  68
  69out:
  70        scmi_clear_smt_channel(&chan->smt);
  71
  72        return ret;
  73}
  74
  75static int setup_channel(struct udevice *dev, struct scmi_mbox_channel *chan)
  76{
  77        int ret;
  78
  79        ret = mbox_get_by_index(dev, 0, &chan->mbox);
  80        if (ret) {
  81                dev_err(dev, "Failed to find mailbox: %d\n", ret);
  82                return ret;
  83        }
  84
  85        ret = scmi_dt_get_smt_buffer(dev, &chan->smt);
  86        if (ret) {
  87                dev_err(dev, "Failed to get shm resources: %d\n", ret);
  88                return ret;
  89        }
  90
  91        chan->timeout_us = TIMEOUT_US_10MS;
  92
  93        return 0;
  94}
  95
  96static int scmi_mbox_get_channel(struct udevice *dev,
  97                                 struct scmi_channel **channel)
  98{
  99        struct scmi_mbox_channel *base_chan = dev_get_plat(dev);
 100        struct scmi_mbox_channel *chan;
 101        int ret;
 102
 103        if (!dev_read_prop(dev, "shmem", NULL)) {
 104                /* Uses agent base channel */
 105                *channel = container_of(base_chan, struct scmi_channel, ref);
 106
 107                return 0;
 108        }
 109
 110        chan = calloc(1, sizeof(*chan));
 111        if (!chan)
 112                return -ENOMEM;
 113
 114        /* Setup a dedicated channel for the protocol */
 115        ret = setup_channel(dev, chan);
 116        if (ret) {
 117                free(chan);
 118                return ret;
 119        }
 120
 121        *channel = (void *)chan;
 122
 123        return 0;
 124}
 125
 126int scmi_mbox_of_to_plat(struct udevice *dev)
 127{
 128        struct scmi_mbox_channel *chan = dev_get_plat(dev);
 129
 130        return setup_channel(dev, chan);
 131}
 132
 133static const struct udevice_id scmi_mbox_ids[] = {
 134        { .compatible = "arm,scmi" },
 135        { }
 136};
 137
 138static const struct scmi_agent_ops scmi_mbox_ops = {
 139        .of_get_channel = scmi_mbox_get_channel,
 140        .process_msg = scmi_mbox_process_msg,
 141};
 142
 143U_BOOT_DRIVER(scmi_mbox) = {
 144        .name           = "scmi-over-mailbox",
 145        .id             = UCLASS_SCMI_AGENT,
 146        .of_match       = scmi_mbox_ids,
 147        .plat_auto      = sizeof(struct scmi_mbox_channel),
 148        .of_to_plat     = scmi_mbox_of_to_plat,
 149        .ops            = &scmi_mbox_ops,
 150};
 151