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