clk-ti-sci.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Texas Instruments System Control Interface (TI SCI) clock driver
  4. *
  5. * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
  6. * Andreas Dannenberg <dannenberg@ti.com>
  7. *
  8. * Loosely based on Linux kernel sci-clk.c...
  9. */
  10. #include <common.h>
  11. #include <dm.h>
  12. #include <errno.h>
  13. #include <clk-uclass.h>
  14. #include <linux/err.h>
  15. #include <linux/soc/ti/ti_sci_protocol.h>
  16. #include <k3-avs.h>
  17. /**
  18. * struct ti_sci_clk_data - clock controller information structure
  19. * @sci: TI SCI handle used for communication with system controller
  20. */
  21. struct ti_sci_clk_data {
  22. const struct ti_sci_handle *sci;
  23. };
  24. static int ti_sci_clk_probe(struct udevice *dev)
  25. {
  26. struct ti_sci_clk_data *data = dev_get_priv(dev);
  27. debug("%s(dev=%p)\n", __func__, dev);
  28. if (!data)
  29. return -ENOMEM;
  30. /* Store handle for communication with the system controller */
  31. data->sci = ti_sci_get_handle(dev);
  32. if (IS_ERR(data->sci))
  33. return PTR_ERR(data->sci);
  34. return 0;
  35. }
  36. static int ti_sci_clk_of_xlate(struct clk *clk,
  37. struct ofnode_phandle_args *args)
  38. {
  39. debug("%s(clk=%p, args_count=%d)\n", __func__, clk, args->args_count);
  40. if (args->args_count != 2) {
  41. debug("Invalid args_count: %d\n", args->args_count);
  42. return -EINVAL;
  43. }
  44. /*
  45. * On TI SCI-based devices, the clock provider id field is used as a
  46. * device ID, and the data field is used as the associated sub-ID.
  47. */
  48. clk->id = args->args[0];
  49. clk->data = args->args[1];
  50. return 0;
  51. }
  52. static int ti_sci_clk_request(struct clk *clk)
  53. {
  54. debug("%s(clk=%p)\n", __func__, clk);
  55. return 0;
  56. }
  57. static int ti_sci_clk_free(struct clk *clk)
  58. {
  59. debug("%s(clk=%p)\n", __func__, clk);
  60. return 0;
  61. }
  62. static ulong ti_sci_clk_get_rate(struct clk *clk)
  63. {
  64. struct ti_sci_clk_data *data = dev_get_priv(clk->dev);
  65. const struct ti_sci_handle *sci = data->sci;
  66. const struct ti_sci_clk_ops *cops = &sci->ops.clk_ops;
  67. u64 current_freq;
  68. int ret;
  69. debug("%s(clk=%p)\n", __func__, clk);
  70. ret = cops->get_freq(sci, clk->id, clk->data, &current_freq);
  71. if (ret) {
  72. dev_err(clk->dev, "%s: get_freq failed (%d)\n", __func__, ret);
  73. return ret;
  74. }
  75. debug("%s(current_freq=%llu)\n", __func__, current_freq);
  76. return current_freq;
  77. }
  78. static ulong ti_sci_clk_set_rate(struct clk *clk, ulong rate)
  79. {
  80. struct ti_sci_clk_data *data = dev_get_priv(clk->dev);
  81. const struct ti_sci_handle *sci = data->sci;
  82. const struct ti_sci_clk_ops *cops = &sci->ops.clk_ops;
  83. int ret;
  84. debug("%s(clk=%p, rate=%lu)\n", __func__, clk, rate);
  85. #ifdef CONFIG_K3_AVS0
  86. k3_avs_notify_freq(clk->id, clk->data, rate);
  87. #endif
  88. ret = cops->set_freq(sci, clk->id, clk->data, 0, rate, ULONG_MAX);
  89. if (ret)
  90. dev_err(clk->dev, "%s: set_freq failed (%d)\n", __func__, ret);
  91. return ret;
  92. }
  93. static int ti_sci_clk_set_parent(struct clk *clk, struct clk *parent)
  94. {
  95. struct ti_sci_clk_data *data = dev_get_priv(clk->dev);
  96. const struct ti_sci_handle *sci = data->sci;
  97. const struct ti_sci_clk_ops *cops = &sci->ops.clk_ops;
  98. u8 num_parents;
  99. u8 parent_cid;
  100. int ret;
  101. debug("%s(clk=%p, parent=%p)\n", __func__, clk, parent);
  102. /* Make sure the clock parent is valid for a given device ID */
  103. if (clk->id != parent->id)
  104. return -EINVAL;
  105. /* Make sure clock has parents that can be set */
  106. ret = cops->get_num_parents(sci, clk->id, clk->data, &num_parents);
  107. if (ret) {
  108. dev_err(clk->dev, "%s: get_num_parents failed (%d)\n",
  109. __func__, ret);
  110. return ret;
  111. }
  112. if (num_parents < 2) {
  113. dev_err(clk->dev, "%s: clock has no settable parents!\n",
  114. __func__);
  115. return -EINVAL;
  116. }
  117. /* Make sure parent clock ID is valid */
  118. parent_cid = parent->data - clk->data - 1;
  119. if (parent_cid >= num_parents) {
  120. dev_err(clk->dev, "%s: invalid parent clock!\n", __func__);
  121. return -EINVAL;
  122. }
  123. /* Ready to proceed to configure the new clock parent */
  124. ret = cops->set_parent(sci, clk->id, clk->data, parent->data);
  125. if (ret)
  126. dev_err(clk->dev, "%s: set_parent failed (%d)\n", __func__,
  127. ret);
  128. return ret;
  129. }
  130. static int ti_sci_clk_enable(struct clk *clk)
  131. {
  132. struct ti_sci_clk_data *data = dev_get_priv(clk->dev);
  133. const struct ti_sci_handle *sci = data->sci;
  134. const struct ti_sci_clk_ops *cops = &sci->ops.clk_ops;
  135. int ret;
  136. debug("%s(clk=%p)\n", __func__, clk);
  137. /*
  138. * Allow the System Controller to automatically manage the state of
  139. * this clock. If the device is enabled, then the clock is enabled.
  140. */
  141. ret = cops->put_clock(sci, clk->id, clk->data);
  142. if (ret)
  143. dev_err(clk->dev, "%s: put_clock failed (%d)\n", __func__, ret);
  144. return ret;
  145. }
  146. static int ti_sci_clk_disable(struct clk *clk)
  147. {
  148. struct ti_sci_clk_data *data = dev_get_priv(clk->dev);
  149. const struct ti_sci_handle *sci = data->sci;
  150. const struct ti_sci_clk_ops *cops = &sci->ops.clk_ops;
  151. int ret;
  152. debug("%s(clk=%p)\n", __func__, clk);
  153. /* Unconditionally disable clock, regardless of state of the device */
  154. ret = cops->idle_clock(sci, clk->id, clk->data);
  155. if (ret)
  156. dev_err(clk->dev, "%s: idle_clock failed (%d)\n", __func__,
  157. ret);
  158. return ret;
  159. }
  160. static const struct udevice_id ti_sci_clk_of_match[] = {
  161. { .compatible = "ti,k2g-sci-clk" },
  162. { /* sentinel */ },
  163. };
  164. static struct clk_ops ti_sci_clk_ops = {
  165. .of_xlate = ti_sci_clk_of_xlate,
  166. .request = ti_sci_clk_request,
  167. .rfree = ti_sci_clk_free,
  168. .get_rate = ti_sci_clk_get_rate,
  169. .set_rate = ti_sci_clk_set_rate,
  170. .set_parent = ti_sci_clk_set_parent,
  171. .enable = ti_sci_clk_enable,
  172. .disable = ti_sci_clk_disable,
  173. };
  174. U_BOOT_DRIVER(ti_sci_clk) = {
  175. .name = "ti-sci-clk",
  176. .id = UCLASS_CLK,
  177. .of_match = ti_sci_clk_of_match,
  178. .probe = ti_sci_clk_probe,
  179. .priv_auto_alloc_size = sizeof(struct ti_sci_clk_data),
  180. .ops = &ti_sci_clk_ops,
  181. };