uboot/drivers/mailbox/mailbox-uclass.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (c) 2016, NVIDIA CORPORATION.
   4 */
   5
   6#define LOG_CATEGORY UCLASS_MAILBOX
   7
   8#include <common.h>
   9#include <dm.h>
  10#include <log.h>
  11#include <mailbox.h>
  12#include <mailbox-uclass.h>
  13#include <malloc.h>
  14#include <time.h>
  15
  16static inline struct mbox_ops *mbox_dev_ops(struct udevice *dev)
  17{
  18        return (struct mbox_ops *)dev->driver->ops;
  19}
  20
  21static int mbox_of_xlate_default(struct mbox_chan *chan,
  22                                 struct ofnode_phandle_args *args)
  23{
  24        debug("%s(chan=%p)\n", __func__, chan);
  25
  26        if (args->args_count != 1) {
  27                debug("Invaild args_count: %d\n", args->args_count);
  28                return -EINVAL;
  29        }
  30
  31        chan->id = args->args[0];
  32
  33        return 0;
  34}
  35
  36int mbox_get_by_index(struct udevice *dev, int index, struct mbox_chan *chan)
  37{
  38        struct ofnode_phandle_args args;
  39        int ret;
  40        struct udevice *dev_mbox;
  41        struct mbox_ops *ops;
  42
  43        debug("%s(dev=%p, index=%d, chan=%p)\n", __func__, dev, index, chan);
  44
  45        ret = dev_read_phandle_with_args(dev, "mboxes", "#mbox-cells", 0, index,
  46                                         &args);
  47        if (ret) {
  48                debug("%s: dev_read_phandle_with_args failed: %d\n", __func__,
  49                      ret);
  50                return ret;
  51        }
  52
  53        ret = uclass_get_device_by_ofnode(UCLASS_MAILBOX, args.node, &dev_mbox);
  54        if (ret) {
  55                debug("%s: uclass_get_device_by_of_offset failed: %d\n",
  56                      __func__, ret);
  57
  58                /* Test with parent node */
  59                ret = uclass_get_device_by_ofnode(UCLASS_MAILBOX,
  60                                                  ofnode_get_parent(args.node),
  61                                                  &dev_mbox);
  62                if (ret) {
  63                        debug("%s: mbox node from parent failed: %d\n",
  64                              __func__, ret);
  65                        return ret;
  66                };
  67        }
  68        ops = mbox_dev_ops(dev_mbox);
  69
  70        chan->dev = dev_mbox;
  71        if (ops->of_xlate)
  72                ret = ops->of_xlate(chan, &args);
  73        else
  74                ret = mbox_of_xlate_default(chan, &args);
  75        if (ret) {
  76                debug("of_xlate() failed: %d\n", ret);
  77                return ret;
  78        }
  79
  80        if (ops->request)
  81                ret = ops->request(chan);
  82        if (ret) {
  83                debug("ops->request() failed: %d\n", ret);
  84                return ret;
  85        }
  86
  87        return 0;
  88}
  89
  90int mbox_get_by_name(struct udevice *dev, const char *name,
  91                     struct mbox_chan *chan)
  92{
  93        int index;
  94
  95        debug("%s(dev=%p, name=%s, chan=%p)\n", __func__, dev, name, chan);
  96
  97        index = dev_read_stringlist_search(dev, "mbox-names", name);
  98        if (index < 0) {
  99                debug("fdt_stringlist_search() failed: %d\n", index);
 100                return index;
 101        }
 102
 103        return mbox_get_by_index(dev, index, chan);
 104}
 105
 106int mbox_free(struct mbox_chan *chan)
 107{
 108        struct mbox_ops *ops = mbox_dev_ops(chan->dev);
 109
 110        debug("%s(chan=%p)\n", __func__, chan);
 111
 112        if (ops->rfree)
 113                return ops->rfree(chan);
 114
 115        return 0;
 116}
 117
 118int mbox_send(struct mbox_chan *chan, const void *data)
 119{
 120        struct mbox_ops *ops = mbox_dev_ops(chan->dev);
 121
 122        debug("%s(chan=%p, data=%p)\n", __func__, chan, data);
 123
 124        return ops->send(chan, data);
 125}
 126
 127int mbox_recv(struct mbox_chan *chan, void *data, ulong timeout_us)
 128{
 129        struct mbox_ops *ops = mbox_dev_ops(chan->dev);
 130        ulong start_time;
 131        int ret;
 132
 133        debug("%s(chan=%p, data=%p, timeout_us=%ld)\n", __func__, chan, data,
 134              timeout_us);
 135
 136        start_time = timer_get_us();
 137        /*
 138         * Account for partial us ticks, but if timeout_us is 0, ensure we
 139         * still don't wait at all.
 140         */
 141        if (timeout_us)
 142                timeout_us++;
 143
 144        for (;;) {
 145                ret = ops->recv(chan, data);
 146                if (ret != -ENODATA)
 147                        return ret;
 148                if ((timer_get_us() - start_time) >= timeout_us)
 149                        return -ETIMEDOUT;
 150        }
 151}
 152
 153UCLASS_DRIVER(mailbox) = {
 154        .id             = UCLASS_MAILBOX,
 155        .name           = "mailbox",
 156};
 157