hwspinlock-uclass.c 2.8 KB

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