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