136-clk-Add-safe-switch-hook.patch 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. Content-Type: text/plain; charset="utf-8"
  2. MIME-Version: 1.0
  3. Content-Transfer-Encoding: 7bit
  4. Subject: [v3,04/13] clk: Add safe switch hook
  5. From: Stephen Boyd <sboyd@codeaurora.org>
  6. X-Patchwork-Id: 6063211
  7. Message-Id: <1426920332-9340-5-git-send-email-sboyd@codeaurora.org>
  8. To: Mike Turquette <mturquette@linaro.org>, Stephen Boyd <sboyd@codeaurora.org>
  9. Cc: linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org,
  10. linux-pm@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
  11. Viresh Kumar <viresh.kumar@linaro.org>
  12. Date: Fri, 20 Mar 2015 23:45:23 -0700
  13. Sometimes clocks can't accept their parent source turning off
  14. while the source is reprogrammed to a different rate. Most
  15. notably CPU clocks require a way to switch away from the current
  16. PLL they're running on, reprogram that PLL to a new rate, and
  17. then switch back to the PLL with the new rate once they're done.
  18. Add a hook that drivers can implement allowing them to return a
  19. 'safe parent' that they can switch their parent to while the
  20. upstream source is reprogrammed to support this.
  21. Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
  22. ---
  23. This patch is good enough for Krait, but soon I'll need to
  24. support a "safe rate" where we ask a clock what rate it needs to be running
  25. at to be sure it's within voltage constraints. Right now safe parent
  26. handles that problem on Krait, but on other platforms it won't work.
  27. drivers/clk/clk.c | 61 ++++++++++++++++++++++++++++++++++++++------
  28. include/linux/clk-provider.h | 1 +
  29. 2 files changed, 54 insertions(+), 8 deletions(-)
  30. --- a/drivers/clk/clk.c
  31. +++ b/drivers/clk/clk.c
  32. @@ -1350,7 +1350,8 @@ out:
  33. static void clk_calc_subtree(struct clk *clk, unsigned long new_rate,
  34. struct clk *new_parent, u8 p_index)
  35. {
  36. - struct clk *child;
  37. + struct clk *child, *parent;
  38. + struct clk_hw *parent_hw;
  39. clk->new_rate = new_rate;
  40. clk->new_parent = new_parent;
  41. @@ -1360,6 +1361,18 @@ static void clk_calc_subtree(struct clk
  42. if (new_parent && new_parent != clk->parent)
  43. new_parent->new_child = clk;
  44. + if (clk->ops->get_safe_parent) {
  45. + parent_hw = clk->ops->get_safe_parent(clk->hw);
  46. + if (parent_hw) {
  47. + parent = parent_hw->clk;
  48. + p_index = clk_fetch_parent_index(clk, parent);
  49. + clk->safe_parent_index = p_index;
  50. + clk->safe_parent = parent;
  51. + }
  52. + } else {
  53. + clk->safe_parent = NULL;
  54. + }
  55. +
  56. hlist_for_each_entry(child, &clk->children, child_node) {
  57. child->new_rate = clk_recalc(child, new_rate);
  58. clk_calc_subtree(child, child->new_rate, NULL, 0);
  59. @@ -1439,17 +1452,47 @@ out:
  60. * so that in case of an error we can walk down the whole tree again and
  61. * abort the change.
  62. */
  63. -static struct clk *clk_propagate_rate_change(struct clk *clk, unsigned long event)
  64. +static struct clk *clk_propagate_rate_change(struct clk *clk,
  65. + unsigned long event)
  66. {
  67. struct clk *child, *tmp_clk, *fail_clk = NULL;
  68. + struct clk *old_parent;
  69. int ret = NOTIFY_DONE;
  70. - if (clk->rate == clk->new_rate)
  71. + if (clk->rate == clk->new_rate && event != POST_RATE_CHANGE)
  72. return NULL;
  73. + switch (event) {
  74. + case PRE_RATE_CHANGE:
  75. + if (clk->safe_parent)
  76. + clk->ops->set_parent(clk->hw, clk->safe_parent_index);
  77. + clk->old_rate = clk->rate;
  78. + break;
  79. + case POST_RATE_CHANGE:
  80. + if (clk->safe_parent) {
  81. + old_parent = __clk_set_parent_before(clk,
  82. + clk->new_parent);
  83. + if (clk->ops->set_rate_and_parent) {
  84. + clk->ops->set_rate_and_parent(clk->hw,
  85. + clk->new_rate,
  86. + clk->new_parent ?
  87. + clk->new_parent->rate : 0,
  88. + clk->new_parent_index);
  89. + } else if (clk->ops->set_parent) {
  90. + clk->ops->set_parent(clk->hw,
  91. + clk->new_parent_index);
  92. + }
  93. + __clk_set_parent_after(clk, clk->new_parent,
  94. + old_parent);
  95. + }
  96. + break;
  97. + }
  98. +
  99. if (clk->notifier_count) {
  100. - ret = __clk_notify(clk, event, clk->rate, clk->new_rate);
  101. - if (ret & NOTIFY_STOP_MASK)
  102. + if (event != POST_RATE_CHANGE || clk->old_rate != clk->rate)
  103. + ret = __clk_notify(clk, event, clk->old_rate,
  104. + clk->new_rate);
  105. + if (ret & NOTIFY_STOP_MASK && event != POST_RATE_CHANGE)
  106. fail_clk = clk;
  107. }
  108. @@ -1494,7 +1537,8 @@ static void clk_change_rate(struct clk *
  109. old_rate = clk->rate;
  110. - if (clk->new_parent && clk->new_parent != clk->parent) {
  111. + if (clk->new_parent && clk->new_parent != clk->parent &&
  112. + !clk->safe_parent) {
  113. old_parent = __clk_set_parent_before(clk, clk->new_parent);
  114. if (clk->ops->set_rate_and_parent) {
  115. @@ -1514,9 +1558,6 @@ static void clk_change_rate(struct clk *
  116. clk->rate = clk->new_rate;
  117. - if (clk->notifier_count && old_rate != clk->rate)
  118. - __clk_notify(clk, POST_RATE_CHANGE, old_rate, clk->rate);
  119. -
  120. /*
  121. * Use safe iteration, as change_rate can actually swap parents
  122. * for certain clock types.
  123. @@ -1601,6 +1642,8 @@ int clk_set_rate(struct clk *clk, unsign
  124. /* change the rates */
  125. clk_change_rate(top, parent_rate);
  126. + clk_propagate_rate_change(top, POST_RATE_CHANGE);
  127. +
  128. out:
  129. clk_prepare_unlock();
  130. --- a/include/linux/clk-provider.h
  131. +++ b/include/linux/clk-provider.h
  132. @@ -179,6 +179,7 @@ struct clk_ops {
  133. struct clk **best_parent_clk);
  134. int (*set_parent)(struct clk_hw *hw, u8 index);
  135. u8 (*get_parent)(struct clk_hw *hw);
  136. + struct clk_hw *(*get_safe_parent)(struct clk_hw *hw);
  137. int (*set_rate)(struct clk_hw *hw, unsigned long rate,
  138. unsigned long parent_rate);
  139. int (*set_rate_and_parent)(struct clk_hw *hw,
  140. --- a/include/linux/clk-private.h
  141. +++ b/include/linux/clk-private.h
  142. @@ -38,8 +38,11 @@ struct clk {
  143. struct clk **parents;
  144. u8 num_parents;
  145. u8 new_parent_index;
  146. + u8 safe_parent_index;
  147. unsigned long rate;
  148. + unsigned long old_rate;
  149. unsigned long new_rate;
  150. + struct clk *safe_parent;
  151. struct clk *new_parent;
  152. struct clk *new_child;
  153. unsigned long flags;