16238935dSStephen Warren /* 26238935dSStephen Warren * Copyright (c) 2016, NVIDIA CORPORATION. 36238935dSStephen Warren * 46238935dSStephen Warren * SPDX-License-Identifier: GPL-2.0 56238935dSStephen Warren */ 66238935dSStephen Warren 76238935dSStephen Warren #include <common.h> 86238935dSStephen Warren #include <dm.h> 96238935dSStephen Warren #include <fdtdec.h> 10*769d52efSStephen Warren #include <mailbox.h> 11*769d52efSStephen Warren #include <mailbox-uclass.h> 126238935dSStephen Warren 136238935dSStephen Warren DECLARE_GLOBAL_DATA_PTR; 146238935dSStephen Warren 156238935dSStephen Warren static inline struct mbox_ops *mbox_dev_ops(struct udevice *dev) 166238935dSStephen Warren { 176238935dSStephen Warren return (struct mbox_ops *)dev->driver->ops; 186238935dSStephen Warren } 196238935dSStephen Warren 206238935dSStephen Warren static int mbox_of_xlate_default(struct mbox_chan *chan, 216238935dSStephen Warren struct fdtdec_phandle_args *args) 226238935dSStephen Warren { 236238935dSStephen Warren debug("%s(chan=%p)\n", __func__, chan); 246238935dSStephen Warren 256238935dSStephen Warren if (args->args_count != 1) { 266238935dSStephen Warren debug("Invaild args_count: %d\n", args->args_count); 276238935dSStephen Warren return -EINVAL; 286238935dSStephen Warren } 296238935dSStephen Warren 306238935dSStephen Warren chan->id = args->args[0]; 316238935dSStephen Warren 326238935dSStephen Warren return 0; 336238935dSStephen Warren } 346238935dSStephen Warren 356238935dSStephen Warren int mbox_get_by_index(struct udevice *dev, int index, struct mbox_chan *chan) 366238935dSStephen Warren { 376238935dSStephen Warren struct fdtdec_phandle_args args; 386238935dSStephen Warren int ret; 396238935dSStephen Warren struct udevice *dev_mbox; 406238935dSStephen Warren struct mbox_ops *ops; 416238935dSStephen Warren 426238935dSStephen Warren debug("%s(dev=%p, index=%d, chan=%p)\n", __func__, dev, index, chan); 436238935dSStephen Warren 446238935dSStephen Warren ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, dev->of_offset, 456238935dSStephen Warren "mboxes", "#mbox-cells", 0, 466238935dSStephen Warren index, &args); 476238935dSStephen Warren if (ret) { 486238935dSStephen Warren debug("%s: fdtdec_parse_phandle_with_args failed: %d\n", 496238935dSStephen Warren __func__, ret); 506238935dSStephen Warren return ret; 516238935dSStephen Warren } 526238935dSStephen Warren 536238935dSStephen Warren ret = uclass_get_device_by_of_offset(UCLASS_MAILBOX, args.node, 546238935dSStephen Warren &dev_mbox); 556238935dSStephen Warren if (ret) { 566238935dSStephen Warren debug("%s: uclass_get_device_by_of_offset failed: %d\n", 576238935dSStephen Warren __func__, ret); 586238935dSStephen Warren return ret; 596238935dSStephen Warren } 606238935dSStephen Warren ops = mbox_dev_ops(dev_mbox); 616238935dSStephen Warren 626238935dSStephen Warren chan->dev = dev_mbox; 636238935dSStephen Warren if (ops->of_xlate) 646238935dSStephen Warren ret = ops->of_xlate(chan, &args); 656238935dSStephen Warren else 666238935dSStephen Warren ret = mbox_of_xlate_default(chan, &args); 676238935dSStephen Warren if (ret) { 686238935dSStephen Warren debug("of_xlate() failed: %d\n", ret); 696238935dSStephen Warren return ret; 706238935dSStephen Warren } 716238935dSStephen Warren 726238935dSStephen Warren ret = ops->request(chan); 736238935dSStephen Warren if (ret) { 746238935dSStephen Warren debug("ops->request() failed: %d\n", ret); 756238935dSStephen Warren return ret; 766238935dSStephen Warren } 776238935dSStephen Warren 786238935dSStephen Warren return 0; 796238935dSStephen Warren } 806238935dSStephen Warren 816238935dSStephen Warren int mbox_get_by_name(struct udevice *dev, const char *name, 826238935dSStephen Warren struct mbox_chan *chan) 836238935dSStephen Warren { 846238935dSStephen Warren int index; 856238935dSStephen Warren 866238935dSStephen Warren debug("%s(dev=%p, name=%s, chan=%p)\n", __func__, dev, name, chan); 876238935dSStephen Warren 886238935dSStephen Warren index = fdt_find_string(gd->fdt_blob, dev->of_offset, "mbox-names", 896238935dSStephen Warren name); 906238935dSStephen Warren if (index < 0) { 916238935dSStephen Warren debug("fdt_find_string() failed: %d\n", index); 926238935dSStephen Warren return index; 936238935dSStephen Warren } 946238935dSStephen Warren 956238935dSStephen Warren return mbox_get_by_index(dev, index, chan); 966238935dSStephen Warren } 976238935dSStephen Warren 986238935dSStephen Warren int mbox_free(struct mbox_chan *chan) 996238935dSStephen Warren { 1006238935dSStephen Warren struct mbox_ops *ops = mbox_dev_ops(chan->dev); 1016238935dSStephen Warren 1026238935dSStephen Warren debug("%s(chan=%p)\n", __func__, chan); 1036238935dSStephen Warren 1046238935dSStephen Warren return ops->free(chan); 1056238935dSStephen Warren } 1066238935dSStephen Warren 1076238935dSStephen Warren int mbox_send(struct mbox_chan *chan, const void *data) 1086238935dSStephen Warren { 1096238935dSStephen Warren struct mbox_ops *ops = mbox_dev_ops(chan->dev); 1106238935dSStephen Warren 1116238935dSStephen Warren debug("%s(chan=%p, data=%p)\n", __func__, chan, data); 1126238935dSStephen Warren 1136238935dSStephen Warren return ops->send(chan, data); 1146238935dSStephen Warren } 1156238935dSStephen Warren 1166238935dSStephen Warren int mbox_recv(struct mbox_chan *chan, void *data, ulong timeout_us) 1176238935dSStephen Warren { 1186238935dSStephen Warren struct mbox_ops *ops = mbox_dev_ops(chan->dev); 1196238935dSStephen Warren ulong start_time; 1206238935dSStephen Warren int ret; 1216238935dSStephen Warren 1226238935dSStephen Warren debug("%s(chan=%p, data=%p, timeout_us=%ld)\n", __func__, chan, data, 1236238935dSStephen Warren timeout_us); 1246238935dSStephen Warren 1256238935dSStephen Warren start_time = timer_get_us(); 1266238935dSStephen Warren /* 1276238935dSStephen Warren * Account for partial us ticks, but if timeout_us is 0, ensure we 1286238935dSStephen Warren * still don't wait at all. 1296238935dSStephen Warren */ 1306238935dSStephen Warren if (timeout_us) 1316238935dSStephen Warren timeout_us++; 1326238935dSStephen Warren 1336238935dSStephen Warren for (;;) { 1346238935dSStephen Warren ret = ops->recv(chan, data); 1356238935dSStephen Warren if (ret != -ENODATA) 1366238935dSStephen Warren return ret; 1376238935dSStephen Warren if ((timer_get_us() - start_time) >= timeout_us) 1386238935dSStephen Warren return -ETIMEDOUT; 1396238935dSStephen Warren } 1406238935dSStephen Warren } 1416238935dSStephen Warren 1426238935dSStephen Warren UCLASS_DRIVER(mailbox) = { 1436238935dSStephen Warren .id = UCLASS_MAILBOX, 1446238935dSStephen Warren .name = "mailbox", 1456238935dSStephen Warren }; 146