linux/drivers/firmware/arm_scmi/mailbox.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * System Control and Management Interface (SCMI) Message Mailbox Transport
   4 * driver.
   5 *
   6 * Copyright (C) 2019 ARM Ltd.
   7 */
   8
   9#include <linux/err.h>
  10#include <linux/device.h>
  11#include <linux/mailbox_client.h>
  12#include <linux/of.h>
  13#include <linux/of_address.h>
  14#include <linux/slab.h>
  15
  16#include "common.h"
  17
  18/**
  19 * struct scmi_mailbox - Structure representing a SCMI mailbox transport
  20 *
  21 * @cl: Mailbox Client
  22 * @chan: Transmit/Receive mailbox channel
  23 * @cinfo: SCMI channel info
  24 * @shmem: Transmit/Receive shared memory area
  25 */
  26struct scmi_mailbox {
  27        struct mbox_client cl;
  28        struct mbox_chan *chan;
  29        struct scmi_chan_info *cinfo;
  30        struct scmi_shared_mem __iomem *shmem;
  31};
  32
  33#define client_to_scmi_mailbox(c) container_of(c, struct scmi_mailbox, cl)
  34
  35static void tx_prepare(struct mbox_client *cl, void *m)
  36{
  37        struct scmi_mailbox *smbox = client_to_scmi_mailbox(cl);
  38
  39        shmem_tx_prepare(smbox->shmem, m);
  40}
  41
  42static void rx_callback(struct mbox_client *cl, void *m)
  43{
  44        struct scmi_mailbox *smbox = client_to_scmi_mailbox(cl);
  45
  46        scmi_rx_callback(smbox->cinfo, shmem_read_header(smbox->shmem));
  47}
  48
  49static bool mailbox_chan_available(struct device *dev, int idx)
  50{
  51        return !of_parse_phandle_with_args(dev->of_node, "mboxes",
  52                                           "#mbox-cells", idx, NULL);
  53}
  54
  55static int mailbox_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,
  56                              bool tx)
  57{
  58        const char *desc = tx ? "Tx" : "Rx";
  59        struct device *cdev = cinfo->dev;
  60        struct scmi_mailbox *smbox;
  61        struct device_node *shmem;
  62        int ret, idx = tx ? 0 : 1;
  63        struct mbox_client *cl;
  64        resource_size_t size;
  65        struct resource res;
  66
  67        smbox = devm_kzalloc(dev, sizeof(*smbox), GFP_KERNEL);
  68        if (!smbox)
  69                return -ENOMEM;
  70
  71        shmem = of_parse_phandle(cdev->of_node, "shmem", idx);
  72        ret = of_address_to_resource(shmem, 0, &res);
  73        of_node_put(shmem);
  74        if (ret) {
  75                dev_err(cdev, "failed to get SCMI %s shared memory\n", desc);
  76                return ret;
  77        }
  78
  79        size = resource_size(&res);
  80        smbox->shmem = devm_ioremap(dev, res.start, size);
  81        if (!smbox->shmem) {
  82                dev_err(dev, "failed to ioremap SCMI %s shared memory\n", desc);
  83                return -EADDRNOTAVAIL;
  84        }
  85
  86        cl = &smbox->cl;
  87        cl->dev = cdev;
  88        cl->tx_prepare = tx ? tx_prepare : NULL;
  89        cl->rx_callback = rx_callback;
  90        cl->tx_block = false;
  91        cl->knows_txdone = tx;
  92
  93        smbox->chan = mbox_request_channel(cl, tx ? 0 : 1);
  94        if (IS_ERR(smbox->chan)) {
  95                ret = PTR_ERR(smbox->chan);
  96                if (ret != -EPROBE_DEFER)
  97                        dev_err(cdev, "failed to request SCMI %s mailbox\n",
  98                                tx ? "Tx" : "Rx");
  99                return ret;
 100        }
 101
 102        cinfo->transport_info = smbox;
 103        smbox->cinfo = cinfo;
 104
 105        return 0;
 106}
 107
 108static int mailbox_chan_free(int id, void *p, void *data)
 109{
 110        struct scmi_chan_info *cinfo = p;
 111        struct scmi_mailbox *smbox = cinfo->transport_info;
 112
 113        if (!IS_ERR(smbox->chan)) {
 114                mbox_free_channel(smbox->chan);
 115                cinfo->transport_info = NULL;
 116                smbox->chan = NULL;
 117                smbox->cinfo = NULL;
 118        }
 119
 120        scmi_free_channel(cinfo, data, id);
 121
 122        return 0;
 123}
 124
 125static int mailbox_send_message(struct scmi_chan_info *cinfo,
 126                                struct scmi_xfer *xfer)
 127{
 128        struct scmi_mailbox *smbox = cinfo->transport_info;
 129        int ret;
 130
 131        ret = mbox_send_message(smbox->chan, xfer);
 132
 133        /* mbox_send_message returns non-negative value on success, so reset */
 134        if (ret > 0)
 135                ret = 0;
 136
 137        return ret;
 138}
 139
 140static void mailbox_mark_txdone(struct scmi_chan_info *cinfo, int ret)
 141{
 142        struct scmi_mailbox *smbox = cinfo->transport_info;
 143
 144        /*
 145         * NOTE: we might prefer not to need the mailbox ticker to manage the
 146         * transfer queueing since the protocol layer queues things by itself.
 147         * Unfortunately, we have to kick the mailbox framework after we have
 148         * received our message.
 149         */
 150        mbox_client_txdone(smbox->chan, ret);
 151}
 152
 153static void mailbox_fetch_response(struct scmi_chan_info *cinfo,
 154                                   struct scmi_xfer *xfer)
 155{
 156        struct scmi_mailbox *smbox = cinfo->transport_info;
 157
 158        shmem_fetch_response(smbox->shmem, xfer);
 159}
 160
 161static void mailbox_fetch_notification(struct scmi_chan_info *cinfo,
 162                                       size_t max_len, struct scmi_xfer *xfer)
 163{
 164        struct scmi_mailbox *smbox = cinfo->transport_info;
 165
 166        shmem_fetch_notification(smbox->shmem, max_len, xfer);
 167}
 168
 169static void mailbox_clear_channel(struct scmi_chan_info *cinfo)
 170{
 171        struct scmi_mailbox *smbox = cinfo->transport_info;
 172
 173        shmem_clear_channel(smbox->shmem);
 174}
 175
 176static bool
 177mailbox_poll_done(struct scmi_chan_info *cinfo, struct scmi_xfer *xfer)
 178{
 179        struct scmi_mailbox *smbox = cinfo->transport_info;
 180
 181        return shmem_poll_done(smbox->shmem, xfer);
 182}
 183
 184static struct scmi_transport_ops scmi_mailbox_ops = {
 185        .chan_available = mailbox_chan_available,
 186        .chan_setup = mailbox_chan_setup,
 187        .chan_free = mailbox_chan_free,
 188        .send_message = mailbox_send_message,
 189        .mark_txdone = mailbox_mark_txdone,
 190        .fetch_response = mailbox_fetch_response,
 191        .fetch_notification = mailbox_fetch_notification,
 192        .clear_channel = mailbox_clear_channel,
 193        .poll_done = mailbox_poll_done,
 194};
 195
 196const struct scmi_desc scmi_mailbox_desc = {
 197        .ops = &scmi_mailbox_ops,
 198        .max_rx_timeout_ms = 30, /* We may increase this if required */
 199        .max_msg = 20, /* Limited by MBOX_TX_QUEUE_LEN */
 200        .max_msg_size = 128,
 201};
 202