847b4809a3b6ff3d2111a01727212d5ae5605ef0
[openwrt/staging/dedeckeh.git] /
1 From 77612720a2362230af726baa4149c40ec7a7fb05 Mon Sep 17 00:00:00 2001
2 From: Sricharan R <sricharan@codeaurora.org>
3 Date: Tue, 14 Aug 2018 17:42:31 +0530
4 Subject: [PATCH 12/12] clk: qcom: Add safe switch hook for krait mux clocks
5
6 When the Hfplls are reprogrammed during the rate change,
7 the primary muxes which are sourced from the same hfpll
8 for higher frequencies, needs to be switched to the 'safe
9 secondary mux' as the parent for that small window. This
10 is done by registering a clk notifier for the muxes and
11 switching to the safe parent in the PRE_RATE_CHANGE notifier
12 and back to the original parent in the POST_RATE_CHANGE notifier.
13
14 Signed-off-by: Sricharan R <sricharan@codeaurora.org>
15 Tested-by: Craig Tatlor <ctatlor97@gmail.com>
16 Signed-off-by: Stephen Boyd <sboyd@kernel.org>
17 ---
18 drivers/clk/qcom/clk-krait.c | 2 ++
19 drivers/clk/qcom/clk-krait.h | 3 ++
20 drivers/clk/qcom/krait-cc.c | 56 ++++++++++++++++++++++++++++++++++++
21 3 files changed, 61 insertions(+)
22
23 --- a/drivers/clk/qcom/clk-krait.c
24 +++ b/drivers/clk/qcom/clk-krait.c
25 @@ -50,6 +50,8 @@ static int krait_mux_set_parent(struct c
26 if (__clk_is_enabled(hw->clk))
27 __krait_mux_set_sel(mux, sel);
28
29 + mux->reparent = true;
30 +
31 return 0;
32 }
33
34 --- a/drivers/clk/qcom/clk-krait.h
35 +++ b/drivers/clk/qcom/clk-krait.h
36 @@ -12,6 +12,9 @@ struct krait_mux_clk {
37 u32 shift;
38 u32 en_mask;
39 bool lpl;
40 + u8 safe_sel;
41 + u8 old_index;
42 + bool reparent;
43
44 struct clk_hw hw;
45 struct notifier_block clk_nb;
46 --- a/drivers/clk/qcom/krait-cc.c
47 +++ b/drivers/clk/qcom/krait-cc.c
48 @@ -26,6 +26,49 @@ static unsigned int pri_mux_map[] = {
49 0,
50 };
51
52 +/*
53 + * Notifier function for switching the muxes to safe parent
54 + * while the hfpll is getting reprogrammed.
55 + */
56 +static int krait_notifier_cb(struct notifier_block *nb,
57 + unsigned long event,
58 + void *data)
59 +{
60 + int ret = 0;
61 + struct krait_mux_clk *mux = container_of(nb, struct krait_mux_clk,
62 + clk_nb);
63 + /* Switch to safe parent */
64 + if (event == PRE_RATE_CHANGE) {
65 + mux->old_index = krait_mux_clk_ops.get_parent(&mux->hw);
66 + ret = krait_mux_clk_ops.set_parent(&mux->hw, mux->safe_sel);
67 + mux->reparent = false;
68 + /*
69 + * By the time POST_RATE_CHANGE notifier is called,
70 + * clk framework itself would have changed the parent for the new rate.
71 + * Only otherwise, put back to the old parent.
72 + */
73 + } else if (event == POST_RATE_CHANGE) {
74 + if (!mux->reparent)
75 + ret = krait_mux_clk_ops.set_parent(&mux->hw,
76 + mux->old_index);
77 + }
78 +
79 + return notifier_from_errno(ret);
80 +}
81 +
82 +static int krait_notifier_register(struct device *dev, struct clk *clk,
83 + struct krait_mux_clk *mux)
84 +{
85 + int ret = 0;
86 +
87 + mux->clk_nb.notifier_call = krait_notifier_cb;
88 + ret = clk_notifier_register(clk, &mux->clk_nb);
89 + if (ret)
90 + dev_err(dev, "failed to register clock notifier: %d\n", ret);
91 +
92 + return ret;
93 +}
94 +
95 static int
96 krait_add_div(struct device *dev, int id, const char *s, unsigned int offset)
97 {
98 @@ -70,6 +113,7 @@ static int
99 krait_add_sec_mux(struct device *dev, int id, const char *s,
100 unsigned int offset, bool unique_aux)
101 {
102 + int ret;
103 struct krait_mux_clk *mux;
104 static const char *sec_mux_list[] = {
105 "acpu_aux",
106 @@ -93,6 +137,7 @@ krait_add_sec_mux(struct device *dev, in
107 mux->shift = 2;
108 mux->parent_map = sec_mux_map;
109 mux->hw.init = &init;
110 + mux->safe_sel = 0;
111
112 init.name = kasprintf(GFP_KERNEL, "krait%s_sec_mux", s);
113 if (!init.name)
114 @@ -108,6 +153,11 @@ krait_add_sec_mux(struct device *dev, in
115
116 clk = devm_clk_register(dev, &mux->hw);
117
118 + ret = krait_notifier_register(dev, clk, mux);
119 + if (ret)
120 + goto unique_aux;
121 +
122 +unique_aux:
123 if (unique_aux)
124 kfree(sec_mux_list[0]);
125 err_aux:
126 @@ -119,6 +169,7 @@ static struct clk *
127 krait_add_pri_mux(struct device *dev, int id, const char *s,
128 unsigned int offset)
129 {
130 + int ret;
131 struct krait_mux_clk *mux;
132 const char *p_names[3];
133 struct clk_init_data init = {
134 @@ -139,6 +190,7 @@ krait_add_pri_mux(struct device *dev, in
135 mux->lpl = id >= 0;
136 mux->parent_map = pri_mux_map;
137 mux->hw.init = &init;
138 + mux->safe_sel = 2;
139
140 init.name = kasprintf(GFP_KERNEL, "krait%s_pri_mux", s);
141 if (!init.name)
142 @@ -164,6 +216,10 @@ krait_add_pri_mux(struct device *dev, in
143
144 clk = devm_clk_register(dev, &mux->hw);
145
146 + ret = krait_notifier_register(dev, clk, mux);
147 + if (ret)
148 + goto err_p3;
149 +err_p3:
150 kfree(p_names[2]);
151 err_p2:
152 kfree(p_names[1]);