clk-ti-sci.c 5.5 KB

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