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