mailbox-uclass.c 2.9 KB

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