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