diff options
author | Stephen Boyd <sboyd@codeaurora.org> | 2014-04-28 18:59:16 -0400 |
---|---|---|
committer | Stephen Boyd <sboyd@codeaurora.org> | 2014-09-22 18:16:54 -0400 |
commit | 229fd4a505553c3a475b90e9aa8e452f5d78eb3b (patch) | |
tree | 5f4b5b22574558f9d41e93f3d9f01f7290695cb2 | |
parent | ae3669ac5c09fa8dfc8d8a294ccb5f265b8929be (diff) |
clk: qcom: Add support for banked MD RCGs
The banked MD RCGs in global clock control have a different
register layout than the ones implemented in multimedia clock
control. Add support for these types of clocks so we can change
the rates of the UBI32 clocks.
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
-rw-r--r-- | drivers/clk/qcom/clk-rcg.c | 99 | ||||
-rw-r--r-- | drivers/clk/qcom/clk-rcg.h | 6 | ||||
-rw-r--r-- | drivers/clk/qcom/mmcc-msm8960.c | 28 |
3 files changed, 77 insertions, 56 deletions
diff --git a/drivers/clk/qcom/clk-rcg.c b/drivers/clk/qcom/clk-rcg.c index 3db106b74934..b6e6959e89aa 100644 --- a/drivers/clk/qcom/clk-rcg.c +++ b/drivers/clk/qcom/clk-rcg.c | |||
@@ -68,16 +68,16 @@ static u8 clk_dyn_rcg_get_parent(struct clk_hw *hw) | |||
68 | { | 68 | { |
69 | struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw); | 69 | struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw); |
70 | int num_parents = __clk_get_num_parents(hw->clk); | 70 | int num_parents = __clk_get_num_parents(hw->clk); |
71 | u32 ns, ctl; | 71 | u32 ns, reg; |
72 | int bank; | 72 | int bank; |
73 | int i; | 73 | int i; |
74 | struct src_sel *s; | 74 | struct src_sel *s; |
75 | 75 | ||
76 | regmap_read(rcg->clkr.regmap, rcg->clkr.enable_reg, &ctl); | 76 | regmap_read(rcg->clkr.regmap, rcg->bank_reg, ®); |
77 | bank = reg_to_bank(rcg, ctl); | 77 | bank = reg_to_bank(rcg, reg); |
78 | s = &rcg->s[bank]; | 78 | s = &rcg->s[bank]; |
79 | 79 | ||
80 | regmap_read(rcg->clkr.regmap, rcg->ns_reg, &ns); | 80 | regmap_read(rcg->clkr.regmap, rcg->ns_reg[bank], &ns); |
81 | ns = ns_to_src(s, ns); | 81 | ns = ns_to_src(s, ns); |
82 | 82 | ||
83 | for (i = 0; i < num_parents; i++) | 83 | for (i = 0; i < num_parents; i++) |
@@ -193,90 +193,93 @@ static u32 mn_to_reg(struct mn *mn, u32 m, u32 n, u32 val) | |||
193 | 193 | ||
194 | static void configure_bank(struct clk_dyn_rcg *rcg, const struct freq_tbl *f) | 194 | static void configure_bank(struct clk_dyn_rcg *rcg, const struct freq_tbl *f) |
195 | { | 195 | { |
196 | u32 ns, md, ctl, *regp; | 196 | u32 ns, md, reg; |
197 | int bank, new_bank; | 197 | int bank, new_bank; |
198 | struct mn *mn; | 198 | struct mn *mn; |
199 | struct pre_div *p; | 199 | struct pre_div *p; |
200 | struct src_sel *s; | 200 | struct src_sel *s; |
201 | bool enabled; | 201 | bool enabled; |
202 | u32 md_reg; | 202 | u32 md_reg, ns_reg; |
203 | u32 bank_reg; | ||
204 | bool banked_mn = !!rcg->mn[1].width; | 203 | bool banked_mn = !!rcg->mn[1].width; |
204 | bool banked_p = !!rcg->p[1].pre_div_width; | ||
205 | struct clk_hw *hw = &rcg->clkr.hw; | 205 | struct clk_hw *hw = &rcg->clkr.hw; |
206 | 206 | ||
207 | enabled = __clk_is_enabled(hw->clk); | 207 | enabled = __clk_is_enabled(hw->clk); |
208 | 208 | ||
209 | regmap_read(rcg->clkr.regmap, rcg->ns_reg, &ns); | 209 | regmap_read(rcg->clkr.regmap, rcg->bank_reg, ®); |
210 | regmap_read(rcg->clkr.regmap, rcg->clkr.enable_reg, &ctl); | 210 | bank = reg_to_bank(rcg, reg); |
211 | |||
212 | if (banked_mn) { | ||
213 | regp = &ctl; | ||
214 | bank_reg = rcg->clkr.enable_reg; | ||
215 | } else { | ||
216 | regp = &ns; | ||
217 | bank_reg = rcg->ns_reg; | ||
218 | } | ||
219 | |||
220 | bank = reg_to_bank(rcg, *regp); | ||
221 | new_bank = enabled ? !bank : bank; | 211 | new_bank = enabled ? !bank : bank; |
222 | 212 | ||
213 | ns_reg = rcg->ns_reg[new_bank]; | ||
214 | regmap_read(rcg->clkr.regmap, ns_reg, &ns); | ||
215 | |||
223 | if (banked_mn) { | 216 | if (banked_mn) { |
224 | mn = &rcg->mn[new_bank]; | 217 | mn = &rcg->mn[new_bank]; |
225 | md_reg = rcg->md_reg[new_bank]; | 218 | md_reg = rcg->md_reg[new_bank]; |
226 | 219 | ||
227 | ns |= BIT(mn->mnctr_reset_bit); | 220 | ns |= BIT(mn->mnctr_reset_bit); |
228 | regmap_write(rcg->clkr.regmap, rcg->ns_reg, ns); | 221 | regmap_write(rcg->clkr.regmap, ns_reg, ns); |
229 | 222 | ||
230 | regmap_read(rcg->clkr.regmap, md_reg, &md); | 223 | regmap_read(rcg->clkr.regmap, md_reg, &md); |
231 | md = mn_to_md(mn, f->m, f->n, md); | 224 | md = mn_to_md(mn, f->m, f->n, md); |
232 | regmap_write(rcg->clkr.regmap, md_reg, md); | 225 | regmap_write(rcg->clkr.regmap, md_reg, md); |
233 | 226 | ||
234 | ns = mn_to_ns(mn, f->m, f->n, ns); | 227 | ns = mn_to_ns(mn, f->m, f->n, ns); |
235 | regmap_write(rcg->clkr.regmap, rcg->ns_reg, ns); | 228 | regmap_write(rcg->clkr.regmap, ns_reg, ns); |
236 | 229 | ||
237 | ctl = mn_to_reg(mn, f->m, f->n, ctl); | 230 | /* Two NS registers means mode control is in NS register */ |
238 | regmap_write(rcg->clkr.regmap, rcg->clkr.enable_reg, ctl); | 231 | if (rcg->ns_reg[0] != rcg->ns_reg[1]) { |
232 | ns = mn_to_reg(mn, f->m, f->n, ns); | ||
233 | regmap_write(rcg->clkr.regmap, ns_reg, ns); | ||
234 | } else { | ||
235 | reg = mn_to_reg(mn, f->m, f->n, reg); | ||
236 | regmap_write(rcg->clkr.regmap, rcg->bank_reg, reg); | ||
237 | } | ||
239 | 238 | ||
240 | ns &= ~BIT(mn->mnctr_reset_bit); | 239 | ns &= ~BIT(mn->mnctr_reset_bit); |
241 | regmap_write(rcg->clkr.regmap, rcg->ns_reg, ns); | 240 | regmap_write(rcg->clkr.regmap, ns_reg, ns); |
242 | } else { | 241 | } |
242 | |||
243 | if (banked_p) { | ||
243 | p = &rcg->p[new_bank]; | 244 | p = &rcg->p[new_bank]; |
244 | ns = pre_div_to_ns(p, f->pre_div - 1, ns); | 245 | ns = pre_div_to_ns(p, f->pre_div - 1, ns); |
245 | } | 246 | } |
246 | 247 | ||
247 | s = &rcg->s[new_bank]; | 248 | s = &rcg->s[new_bank]; |
248 | ns = src_to_ns(s, s->parent_map[f->src], ns); | 249 | ns = src_to_ns(s, s->parent_map[f->src], ns); |
249 | regmap_write(rcg->clkr.regmap, rcg->ns_reg, ns); | 250 | regmap_write(rcg->clkr.regmap, ns_reg, ns); |
250 | 251 | ||
251 | if (enabled) { | 252 | if (enabled) { |
252 | *regp ^= BIT(rcg->mux_sel_bit); | 253 | regmap_read(rcg->clkr.regmap, rcg->bank_reg, ®); |
253 | regmap_write(rcg->clkr.regmap, bank_reg, *regp); | 254 | reg ^= BIT(rcg->mux_sel_bit); |
255 | regmap_write(rcg->clkr.regmap, rcg->bank_reg, reg); | ||
254 | } | 256 | } |
255 | } | 257 | } |
256 | 258 | ||
257 | static int clk_dyn_rcg_set_parent(struct clk_hw *hw, u8 index) | 259 | static int clk_dyn_rcg_set_parent(struct clk_hw *hw, u8 index) |
258 | { | 260 | { |
259 | struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw); | 261 | struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw); |
260 | u32 ns, ctl, md, reg; | 262 | u32 ns, md, reg; |
261 | int bank; | 263 | int bank; |
262 | struct freq_tbl f = { 0 }; | 264 | struct freq_tbl f = { 0 }; |
263 | bool banked_mn = !!rcg->mn[1].width; | 265 | bool banked_mn = !!rcg->mn[1].width; |
266 | bool banked_p = !!rcg->p[1].pre_div_width; | ||
264 | 267 | ||
265 | regmap_read(rcg->clkr.regmap, rcg->ns_reg, &ns); | 268 | regmap_read(rcg->clkr.regmap, rcg->bank_reg, ®); |
266 | regmap_read(rcg->clkr.regmap, rcg->clkr.enable_reg, &ctl); | ||
267 | reg = banked_mn ? ctl : ns; | ||
268 | |||
269 | bank = reg_to_bank(rcg, reg); | 269 | bank = reg_to_bank(rcg, reg); |
270 | 270 | ||
271 | regmap_read(rcg->clkr.regmap, rcg->ns_reg[bank], &ns); | ||
272 | |||
271 | if (banked_mn) { | 273 | if (banked_mn) { |
272 | regmap_read(rcg->clkr.regmap, rcg->md_reg[bank], &md); | 274 | regmap_read(rcg->clkr.regmap, rcg->md_reg[bank], &md); |
273 | f.m = md_to_m(&rcg->mn[bank], md); | 275 | f.m = md_to_m(&rcg->mn[bank], md); |
274 | f.n = ns_m_to_n(&rcg->mn[bank], ns, f.m); | 276 | f.n = ns_m_to_n(&rcg->mn[bank], ns, f.m); |
275 | } else { | ||
276 | f.pre_div = ns_to_pre_div(&rcg->p[bank], ns) + 1; | ||
277 | } | 277 | } |
278 | f.src = index; | ||
279 | 278 | ||
279 | if (banked_p) | ||
280 | f.pre_div = ns_to_pre_div(&rcg->p[bank], ns) + 1; | ||
281 | |||
282 | f.src = index; | ||
280 | configure_bank(rcg, &f); | 283 | configure_bank(rcg, &f); |
281 | 284 | ||
282 | return 0; | 285 | return 0; |
@@ -337,28 +340,30 @@ clk_dyn_rcg_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) | |||
337 | u32 m, n, pre_div, ns, md, mode, reg; | 340 | u32 m, n, pre_div, ns, md, mode, reg; |
338 | int bank; | 341 | int bank; |
339 | struct mn *mn; | 342 | struct mn *mn; |
343 | bool banked_p = !!rcg->p[1].pre_div_width; | ||
340 | bool banked_mn = !!rcg->mn[1].width; | 344 | bool banked_mn = !!rcg->mn[1].width; |
341 | 345 | ||
342 | regmap_read(rcg->clkr.regmap, rcg->ns_reg, &ns); | 346 | regmap_read(rcg->clkr.regmap, rcg->bank_reg, ®); |
343 | |||
344 | if (banked_mn) | ||
345 | regmap_read(rcg->clkr.regmap, rcg->clkr.enable_reg, ®); | ||
346 | else | ||
347 | reg = ns; | ||
348 | |||
349 | bank = reg_to_bank(rcg, reg); | 347 | bank = reg_to_bank(rcg, reg); |
350 | 348 | ||
349 | regmap_read(rcg->clkr.regmap, rcg->ns_reg[bank], &ns); | ||
350 | m = n = pre_div = mode = 0; | ||
351 | |||
351 | if (banked_mn) { | 352 | if (banked_mn) { |
352 | mn = &rcg->mn[bank]; | 353 | mn = &rcg->mn[bank]; |
353 | regmap_read(rcg->clkr.regmap, rcg->md_reg[bank], &md); | 354 | regmap_read(rcg->clkr.regmap, rcg->md_reg[bank], &md); |
354 | m = md_to_m(mn, md); | 355 | m = md_to_m(mn, md); |
355 | n = ns_m_to_n(mn, ns, m); | 356 | n = ns_m_to_n(mn, ns, m); |
357 | /* Two NS registers means mode control is in NS register */ | ||
358 | if (rcg->ns_reg[0] != rcg->ns_reg[1]) | ||
359 | reg = ns; | ||
356 | mode = reg_to_mnctr_mode(mn, reg); | 360 | mode = reg_to_mnctr_mode(mn, reg); |
357 | return calc_rate(parent_rate, m, n, mode, 0); | ||
358 | } else { | ||
359 | pre_div = ns_to_pre_div(&rcg->p[bank], ns); | ||
360 | return calc_rate(parent_rate, 0, 0, 0, pre_div); | ||
361 | } | 361 | } |
362 | |||
363 | if (banked_p) | ||
364 | pre_div = ns_to_pre_div(&rcg->p[bank], ns); | ||
365 | |||
366 | return calc_rate(parent_rate, m, n, mode, pre_div); | ||
362 | } | 367 | } |
363 | 368 | ||
364 | static long _freq_tbl_determine_rate(struct clk_hw *hw, | 369 | static long _freq_tbl_determine_rate(struct clk_hw *hw, |
diff --git a/drivers/clk/qcom/clk-rcg.h b/drivers/clk/qcom/clk-rcg.h index ba0523cefd2e..687e41f91d7c 100644 --- a/drivers/clk/qcom/clk-rcg.h +++ b/drivers/clk/qcom/clk-rcg.h | |||
@@ -103,8 +103,9 @@ extern const struct clk_ops clk_rcg_bypass_ops; | |||
103 | * struct clk_dyn_rcg - root clock generator with glitch free mux | 103 | * struct clk_dyn_rcg - root clock generator with glitch free mux |
104 | * | 104 | * |
105 | * @mux_sel_bit: bit to switch glitch free mux | 105 | * @mux_sel_bit: bit to switch glitch free mux |
106 | * @ns_reg: NS register | 106 | * @ns_reg: NS0 and NS1 register |
107 | * @md_reg: MD0 and MD1 register | 107 | * @md_reg: MD0 and MD1 register |
108 | * @bank_reg: register to XOR @mux_sel_bit into to switch glitch free mux | ||
108 | * @mn: mn counter (banked) | 109 | * @mn: mn counter (banked) |
109 | * @s: source selector (banked) | 110 | * @s: source selector (banked) |
110 | * @freq_tbl: frequency table | 111 | * @freq_tbl: frequency table |
@@ -113,8 +114,9 @@ extern const struct clk_ops clk_rcg_bypass_ops; | |||
113 | * | 114 | * |
114 | */ | 115 | */ |
115 | struct clk_dyn_rcg { | 116 | struct clk_dyn_rcg { |
116 | u32 ns_reg; | 117 | u32 ns_reg[2]; |
117 | u32 md_reg[2]; | 118 | u32 md_reg[2]; |
119 | u32 bank_reg; | ||
118 | 120 | ||
119 | u8 mux_sel_bit; | 121 | u8 mux_sel_bit; |
120 | 122 | ||
diff --git a/drivers/clk/qcom/mmcc-msm8960.c b/drivers/clk/qcom/mmcc-msm8960.c index 2e80a219b8ea..775e00dbcbc8 100644 --- a/drivers/clk/qcom/mmcc-msm8960.c +++ b/drivers/clk/qcom/mmcc-msm8960.c | |||
@@ -773,9 +773,11 @@ static struct freq_tbl clk_tbl_gfx2d[] = { | |||
773 | }; | 773 | }; |
774 | 774 | ||
775 | static struct clk_dyn_rcg gfx2d0_src = { | 775 | static struct clk_dyn_rcg gfx2d0_src = { |
776 | .ns_reg = 0x0070, | 776 | .ns_reg[0] = 0x0070, |
777 | .ns_reg[1] = 0x0070, | ||
777 | .md_reg[0] = 0x0064, | 778 | .md_reg[0] = 0x0064, |
778 | .md_reg[1] = 0x0068, | 779 | .md_reg[1] = 0x0068, |
780 | .bank_reg = 0x0060, | ||
779 | .mn[0] = { | 781 | .mn[0] = { |
780 | .mnctr_en_bit = 8, | 782 | .mnctr_en_bit = 8, |
781 | .mnctr_reset_bit = 25, | 783 | .mnctr_reset_bit = 25, |
@@ -831,9 +833,11 @@ static struct clk_branch gfx2d0_clk = { | |||
831 | }; | 833 | }; |
832 | 834 | ||
833 | static struct clk_dyn_rcg gfx2d1_src = { | 835 | static struct clk_dyn_rcg gfx2d1_src = { |
834 | .ns_reg = 0x007c, | 836 | .ns_reg[0] = 0x007c, |
837 | .ns_reg[1] = 0x007c, | ||
835 | .md_reg[0] = 0x0078, | 838 | .md_reg[0] = 0x0078, |
836 | .md_reg[1] = 0x006c, | 839 | .md_reg[1] = 0x006c, |
840 | .bank_reg = 0x0074, | ||
837 | .mn[0] = { | 841 | .mn[0] = { |
838 | .mnctr_en_bit = 8, | 842 | .mnctr_en_bit = 8, |
839 | .mnctr_reset_bit = 25, | 843 | .mnctr_reset_bit = 25, |
@@ -930,9 +934,11 @@ static struct freq_tbl clk_tbl_gfx3d_8064[] = { | |||
930 | }; | 934 | }; |
931 | 935 | ||
932 | static struct clk_dyn_rcg gfx3d_src = { | 936 | static struct clk_dyn_rcg gfx3d_src = { |
933 | .ns_reg = 0x008c, | 937 | .ns_reg[0] = 0x008c, |
938 | .ns_reg[1] = 0x008c, | ||
934 | .md_reg[0] = 0x0084, | 939 | .md_reg[0] = 0x0084, |
935 | .md_reg[1] = 0x0088, | 940 | .md_reg[1] = 0x0088, |
941 | .bank_reg = 0x0080, | ||
936 | .mn[0] = { | 942 | .mn[0] = { |
937 | .mnctr_en_bit = 8, | 943 | .mnctr_en_bit = 8, |
938 | .mnctr_reset_bit = 25, | 944 | .mnctr_reset_bit = 25, |
@@ -1006,9 +1012,11 @@ static struct freq_tbl clk_tbl_vcap[] = { | |||
1006 | }; | 1012 | }; |
1007 | 1013 | ||
1008 | static struct clk_dyn_rcg vcap_src = { | 1014 | static struct clk_dyn_rcg vcap_src = { |
1009 | .ns_reg = 0x021c, | 1015 | .ns_reg[0] = 0x021c, |
1016 | .ns_reg[1] = 0x021c, | ||
1010 | .md_reg[0] = 0x01ec, | 1017 | .md_reg[0] = 0x01ec, |
1011 | .md_reg[1] = 0x0218, | 1018 | .md_reg[1] = 0x0218, |
1019 | .bank_reg = 0x0178, | ||
1012 | .mn[0] = { | 1020 | .mn[0] = { |
1013 | .mnctr_en_bit = 8, | 1021 | .mnctr_en_bit = 8, |
1014 | .mnctr_reset_bit = 23, | 1022 | .mnctr_reset_bit = 23, |
@@ -1211,9 +1219,11 @@ static struct freq_tbl clk_tbl_mdp[] = { | |||
1211 | }; | 1219 | }; |
1212 | 1220 | ||
1213 | static struct clk_dyn_rcg mdp_src = { | 1221 | static struct clk_dyn_rcg mdp_src = { |
1214 | .ns_reg = 0x00d0, | 1222 | .ns_reg[0] = 0x00d0, |
1223 | .ns_reg[1] = 0x00d0, | ||
1215 | .md_reg[0] = 0x00c4, | 1224 | .md_reg[0] = 0x00c4, |
1216 | .md_reg[1] = 0x00c8, | 1225 | .md_reg[1] = 0x00c8, |
1226 | .bank_reg = 0x00c0, | ||
1217 | .mn[0] = { | 1227 | .mn[0] = { |
1218 | .mnctr_en_bit = 8, | 1228 | .mnctr_en_bit = 8, |
1219 | .mnctr_reset_bit = 31, | 1229 | .mnctr_reset_bit = 31, |
@@ -1318,7 +1328,9 @@ static struct freq_tbl clk_tbl_rot[] = { | |||
1318 | }; | 1328 | }; |
1319 | 1329 | ||
1320 | static struct clk_dyn_rcg rot_src = { | 1330 | static struct clk_dyn_rcg rot_src = { |
1321 | .ns_reg = 0x00e8, | 1331 | .ns_reg[0] = 0x00e8, |
1332 | .ns_reg[1] = 0x00e8, | ||
1333 | .bank_reg = 0x00e8, | ||
1322 | .p[0] = { | 1334 | .p[0] = { |
1323 | .pre_div_shift = 22, | 1335 | .pre_div_shift = 22, |
1324 | .pre_div_width = 4, | 1336 | .pre_div_width = 4, |
@@ -1542,9 +1554,11 @@ static struct freq_tbl clk_tbl_vcodec[] = { | |||
1542 | }; | 1554 | }; |
1543 | 1555 | ||
1544 | static struct clk_dyn_rcg vcodec_src = { | 1556 | static struct clk_dyn_rcg vcodec_src = { |
1545 | .ns_reg = 0x0100, | 1557 | .ns_reg[0] = 0x0100, |
1558 | .ns_reg[1] = 0x0100, | ||
1546 | .md_reg[0] = 0x00fc, | 1559 | .md_reg[0] = 0x00fc, |
1547 | .md_reg[1] = 0x0128, | 1560 | .md_reg[1] = 0x0128, |
1561 | .bank_reg = 0x00f8, | ||
1548 | .mn[0] = { | 1562 | .mn[0] = { |
1549 | .mnctr_en_bit = 5, | 1563 | .mnctr_en_bit = 5, |
1550 | .mnctr_reset_bit = 31, | 1564 | .mnctr_reset_bit = 31, |