hwspinlock-uclass.c 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. // SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
  2. /*
  3. * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
  4. */
  5. #include <common.h>
  6. #include <dm.h>
  7. #include <errno.h>
  8. #include <hwspinlock.h>
  9. #include <dm/device-internal.h>
  10. #include <dm/device_compat.h>
  11. #include <linux/compat.h>
  12. static inline const struct hwspinlock_ops *
  13. hwspinlock_dev_ops(struct udevice *dev)
  14. {
  15. return (const struct hwspinlock_ops *)dev->driver->ops;
  16. }
  17. static int hwspinlock_of_xlate_default(struct hwspinlock *hws,
  18. struct ofnode_phandle_args *args)
  19. {
  20. if (args->args_count > 1) {
  21. debug("Invaild args_count: %d\n", args->args_count);
  22. return -EINVAL;
  23. }
  24. if (args->args_count)
  25. hws->id = args->args[0];
  26. else
  27. hws->id = 0;
  28. return 0;
  29. }
  30. int hwspinlock_get_by_index(struct udevice *dev, int index,
  31. struct hwspinlock *hws)
  32. {
  33. int ret;
  34. struct ofnode_phandle_args args;
  35. struct udevice *dev_hws;
  36. const struct hwspinlock_ops *ops;
  37. assert(hws);
  38. hws->dev = NULL;
  39. ret = dev_read_phandle_with_args(dev, "hwlocks", "#hwlock-cells", 1,
  40. index, &args);
  41. if (ret) {
  42. dev_dbg(dev, "%s: dev_read_phandle_with_args: err=%d\n",
  43. __func__, ret);
  44. return ret;
  45. }
  46. ret = uclass_get_device_by_ofnode(UCLASS_HWSPINLOCK,
  47. args.node, &dev_hws);
  48. if (ret) {
  49. dev_dbg(dev,
  50. "%s: uclass_get_device_by_of_offset failed: err=%d\n",
  51. __func__, ret);
  52. return ret;
  53. }
  54. hws->dev = dev_hws;
  55. ops = hwspinlock_dev_ops(dev_hws);
  56. if (ops->of_xlate)
  57. ret = ops->of_xlate(hws, &args);
  58. else
  59. ret = hwspinlock_of_xlate_default(hws, &args);
  60. if (ret)
  61. dev_dbg(dev, "of_xlate() failed: %d\n", ret);
  62. return ret;
  63. }
  64. int hwspinlock_lock_timeout(struct hwspinlock *hws, unsigned int timeout)
  65. {
  66. const struct hwspinlock_ops *ops;
  67. ulong start;
  68. int ret;
  69. assert(hws);
  70. if (!hws->dev)
  71. return -EINVAL;
  72. ops = hwspinlock_dev_ops(hws->dev);
  73. if (!ops->lock)
  74. return -ENOSYS;
  75. start = get_timer(0);
  76. do {
  77. ret = ops->lock(hws->dev, hws->id);
  78. if (!ret)
  79. return ret;
  80. if (ops->relax)
  81. ops->relax(hws->dev);
  82. } while (get_timer(start) < timeout);
  83. return -ETIMEDOUT;
  84. }
  85. int hwspinlock_unlock(struct hwspinlock *hws)
  86. {
  87. const struct hwspinlock_ops *ops;
  88. assert(hws);
  89. if (!hws->dev)
  90. return -EINVAL;
  91. ops = hwspinlock_dev_ops(hws->dev);
  92. if (!ops->unlock)
  93. return -ENOSYS;
  94. return ops->unlock(hws->dev, hws->id);
  95. }
  96. static int hwspinlock_post_bind(struct udevice *dev)
  97. {
  98. #if defined(CONFIG_NEEDS_MANUAL_RELOC)
  99. struct hwspinlock_ops *ops = device_get_ops(dev);
  100. static int reloc_done;
  101. if (!reloc_done) {
  102. if (ops->lock)
  103. ops->lock += gd->reloc_off;
  104. if (ops->unlock)
  105. ops->unlock += gd->reloc_off;
  106. if (ops->relax)
  107. ops->relax += gd->reloc_off;
  108. reloc_done++;
  109. }
  110. #endif
  111. return 0;
  112. }
  113. UCLASS_DRIVER(hwspinlock) = {
  114. .id = UCLASS_HWSPINLOCK,
  115. .name = "hwspinlock",
  116. .post_bind = hwspinlock_post_bind,
  117. };