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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. From f7a00ea959be31f9b742042294a359d508edce94 Mon Sep 17 00:00:00 2001
  2. From: Stephen Boyd <sboyd@codeaurora.org>
  3. Date: Fri, 20 Mar 2015 23:45:23 -0700
  4. Subject: [PATCH] clk: Add safe switch hook
  5. Sometimes clocks can't accept their parent source turning off
  6. while the source is reprogrammed to a different rate. Most
  7. notably CPU clocks require a way to switch away from the current
  8. PLL they're running on, reprogram that PLL to a new rate, and
  9. then switch back to the PLL with the new rate once they're done.
  10. Add a hook that drivers can implement allowing them to return a
  11. 'safe parent' that they can switch their parent to while the
  12. upstream source is reprogrammed to support this.
  13. Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
  14. Signed-off-by: Ram Chandra Jangir <rjangi@codeaurora.org>
  15. ---
  16. drivers/clk/clk.c | 61 ++++++++++++++++++++++++++++++++++++++------
  17. include/linux/clk-provider.h | 1 +
  18. 2 files changed, 54 insertions(+), 8 deletions(-)
  19. --- a/drivers/clk/clk.c
  20. +++ b/drivers/clk/clk.c
  21. @@ -51,9 +51,12 @@ struct clk_core {
  22. struct clk_core **parents;
  23. u8 num_parents;
  24. u8 new_parent_index;
  25. + u8 safe_parent_index;
  26. unsigned long rate;
  27. unsigned long req_rate;
  28. + unsigned long old_rate;
  29. unsigned long new_rate;
  30. + struct clk_core *safe_parent;
  31. struct clk_core *new_parent;
  32. struct clk_core *new_child;
  33. unsigned long flags;
  34. @@ -1271,7 +1274,8 @@ out:
  35. static void clk_calc_subtree(struct clk_core *core, unsigned long new_rate,
  36. struct clk_core *new_parent, u8 p_index)
  37. {
  38. - struct clk_core *child;
  39. + struct clk_core *child, *parent;
  40. + struct clk_hw *parent_hw;
  41. core->new_rate = new_rate;
  42. core->new_parent = new_parent;
  43. @@ -1281,6 +1285,18 @@ static void clk_calc_subtree(struct clk_
  44. if (new_parent && new_parent != core->parent)
  45. new_parent->new_child = core;
  46. + if (core->ops->get_safe_parent) {
  47. + parent_hw = core->ops->get_safe_parent(core->hw);
  48. + if (parent_hw) {
  49. + parent = parent_hw->core;
  50. + p_index = clk_fetch_parent_index(core, parent);
  51. + core->safe_parent_index = p_index;
  52. + core->safe_parent = parent;
  53. + }
  54. + } else {
  55. + core->safe_parent = NULL;
  56. + }
  57. +
  58. hlist_for_each_entry(child, &core->children, child_node) {
  59. child->new_rate = clk_recalc(child, new_rate);
  60. clk_calc_subtree(child, child->new_rate, NULL, 0);
  61. @@ -1393,14 +1409,43 @@ static struct clk_core *clk_propagate_ra
  62. unsigned long event)
  63. {
  64. struct clk_core *child, *tmp_clk, *fail_clk = NULL;
  65. + struct clk_core *old_parent;
  66. int ret = NOTIFY_DONE;
  67. - if (core->rate == core->new_rate)
  68. + if (core->rate == core->new_rate && event != POST_RATE_CHANGE)
  69. return NULL;
  70. + switch (event) {
  71. + case PRE_RATE_CHANGE:
  72. + if (core->safe_parent)
  73. + core->ops->set_parent(core->hw, core->safe_parent_index);
  74. + core->old_rate = core->rate;
  75. + break;
  76. + case POST_RATE_CHANGE:
  77. + if (core->safe_parent) {
  78. + old_parent = __clk_set_parent_before(core,
  79. + core->new_parent);
  80. + if (core->ops->set_rate_and_parent) {
  81. + core->ops->set_rate_and_parent(core->hw,
  82. + core->new_rate,
  83. + core->new_parent ?
  84. + core->new_parent->rate : 0,
  85. + core->new_parent_index);
  86. + } else if (core->ops->set_parent) {
  87. + core->ops->set_parent(core->hw,
  88. + core->new_parent_index);
  89. + }
  90. + __clk_set_parent_after(core, core->new_parent,
  91. + old_parent);
  92. + }
  93. + break;
  94. + }
  95. +
  96. if (core->notifier_count) {
  97. - ret = __clk_notify(core, event, core->rate, core->new_rate);
  98. - if (ret & NOTIFY_STOP_MASK)
  99. + if (event != POST_RATE_CHANGE || core->old_rate != core->rate)
  100. + ret = __clk_notify(core, event, core->old_rate,
  101. + core->new_rate);
  102. + if (ret & NOTIFY_STOP_MASK && event != POST_RATE_CHANGE)
  103. fail_clk = core;
  104. }
  105. @@ -1446,7 +1491,8 @@ clk_change_rate(struct clk_core *core, u
  106. old_rate = core->rate;
  107. - if (core->new_parent && core->new_parent != core->parent) {
  108. + if (core->new_parent && core->new_parent != core->parent &&
  109. + !core->safe_parent) {
  110. old_parent = __clk_set_parent_before(core, core->new_parent);
  111. trace_clk_set_parent(core, core->new_parent);
  112. @@ -1472,9 +1518,6 @@ clk_change_rate(struct clk_core *core, u
  113. core->rate = core->new_rate;
  114. - if (core->notifier_count && old_rate != core->rate)
  115. - __clk_notify(core, POST_RATE_CHANGE, old_rate, core->rate);
  116. -
  117. if (core->flags & CLK_RECALC_NEW_RATES)
  118. (void)clk_calc_new_rates(core, core->new_rate);
  119. @@ -1537,6 +1580,8 @@ static int clk_core_set_rate_nolock(stru
  120. core->req_rate = req_rate;
  121. + clk_propagate_rate_change(top, POST_RATE_CHANGE);
  122. +
  123. return ret;
  124. }
  125. --- a/include/linux/clk-provider.h
  126. +++ b/include/linux/clk-provider.h
  127. @@ -202,6 +202,7 @@ struct clk_ops {
  128. struct clk_rate_request *req);
  129. int (*set_parent)(struct clk_hw *hw, u8 index);
  130. u8 (*get_parent)(struct clk_hw *hw);
  131. + struct clk_hw *(*get_safe_parent)(struct clk_hw *hw);
  132. int (*set_rate)(struct clk_hw *hw, unsigned long rate,
  133. unsigned long parent_rate);
  134. int (*set_rate_and_parent)(struct clk_hw *hw,