diff options
author | Stephen Boyd <sboyd@codeaurora.org> | 2014-05-16 19:07:11 -0400 |
---|---|---|
committer | Mike Turquette <mturquette@linaro.org> | 2014-05-29 12:30:23 -0400 |
commit | 99cbd064b059f222c8839ba433a68b2d6ee33066 (patch) | |
tree | e45375a22761beaf6570cac95ba558692cbe27cf /drivers/clk | |
parent | 9d011f3b71f635ff8e664e7e32bb764918cb1e8e (diff) |
clk: qcom: Support display RCG clocks
Add support for the DSI/EDP/HDMI RCG clocks. With the proper
display driver in place this should allow us to support display
clocks on msm8974 based devices.
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
Signed-off-by: Mike Turquette <mturquette@linaro.org>
Diffstat (limited to 'drivers/clk')
-rw-r--r-- | drivers/clk/qcom/clk-rcg.h | 3 | ||||
-rw-r--r-- | drivers/clk/qcom/clk-rcg2.c | 299 |
2 files changed, 287 insertions, 15 deletions
diff --git a/drivers/clk/qcom/clk-rcg.h b/drivers/clk/qcom/clk-rcg.h index 1d6b6dece328..b9ec11dfd1b4 100644 --- a/drivers/clk/qcom/clk-rcg.h +++ b/drivers/clk/qcom/clk-rcg.h | |||
@@ -155,5 +155,8 @@ struct clk_rcg2 { | |||
155 | #define to_clk_rcg2(_hw) container_of(to_clk_regmap(_hw), struct clk_rcg2, clkr) | 155 | #define to_clk_rcg2(_hw) container_of(to_clk_regmap(_hw), struct clk_rcg2, clkr) |
156 | 156 | ||
157 | extern const struct clk_ops clk_rcg2_ops; | 157 | extern const struct clk_ops clk_rcg2_ops; |
158 | extern const struct clk_ops clk_edp_pixel_ops; | ||
159 | extern const struct clk_ops clk_byte_ops; | ||
160 | extern const struct clk_ops clk_pixel_ops; | ||
158 | 161 | ||
159 | #endif | 162 | #endif |
diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c index cbecaec30562..cd185d5cc67a 100644 --- a/drivers/clk/qcom/clk-rcg2.c +++ b/drivers/clk/qcom/clk-rcg2.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/clk-provider.h> | 19 | #include <linux/clk-provider.h> |
20 | #include <linux/delay.h> | 20 | #include <linux/delay.h> |
21 | #include <linux/regmap.h> | 21 | #include <linux/regmap.h> |
22 | #include <linux/math64.h> | ||
22 | 23 | ||
23 | #include <asm/div64.h> | 24 | #include <asm/div64.h> |
24 | 25 | ||
@@ -225,31 +226,25 @@ static long clk_rcg2_determine_rate(struct clk_hw *hw, unsigned long rate, | |||
225 | return _freq_tbl_determine_rate(hw, rcg->freq_tbl, rate, p_rate, p); | 226 | return _freq_tbl_determine_rate(hw, rcg->freq_tbl, rate, p_rate, p); |
226 | } | 227 | } |
227 | 228 | ||
228 | static int __clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate) | 229 | static int clk_rcg2_configure(struct clk_rcg2 *rcg, const struct freq_tbl *f) |
229 | { | 230 | { |
230 | struct clk_rcg2 *rcg = to_clk_rcg2(hw); | ||
231 | const struct freq_tbl *f; | ||
232 | u32 cfg, mask; | 231 | u32 cfg, mask; |
233 | int ret; | 232 | int ret; |
234 | 233 | ||
235 | f = find_freq(rcg->freq_tbl, rate); | ||
236 | if (!f) | ||
237 | return -EINVAL; | ||
238 | |||
239 | if (rcg->mnd_width && f->n) { | 234 | if (rcg->mnd_width && f->n) { |
240 | mask = BIT(rcg->mnd_width) - 1; | 235 | mask = BIT(rcg->mnd_width) - 1; |
241 | ret = regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + M_REG, | 236 | ret = regmap_update_bits(rcg->clkr.regmap, |
242 | mask, f->m); | 237 | rcg->cmd_rcgr + M_REG, mask, f->m); |
243 | if (ret) | 238 | if (ret) |
244 | return ret; | 239 | return ret; |
245 | 240 | ||
246 | ret = regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + N_REG, | 241 | ret = regmap_update_bits(rcg->clkr.regmap, |
247 | mask, ~(f->n - f->m)); | 242 | rcg->cmd_rcgr + N_REG, mask, ~(f->n - f->m)); |
248 | if (ret) | 243 | if (ret) |
249 | return ret; | 244 | return ret; |
250 | 245 | ||
251 | ret = regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + D_REG, | 246 | ret = regmap_update_bits(rcg->clkr.regmap, |
252 | mask, ~f->n); | 247 | rcg->cmd_rcgr + D_REG, mask, ~f->n); |
253 | if (ret) | 248 | if (ret) |
254 | return ret; | 249 | return ret; |
255 | } | 250 | } |
@@ -260,14 +255,26 @@ static int __clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate) | |||
260 | cfg |= rcg->parent_map[f->src] << CFG_SRC_SEL_SHIFT; | 255 | cfg |= rcg->parent_map[f->src] << CFG_SRC_SEL_SHIFT; |
261 | if (rcg->mnd_width && f->n) | 256 | if (rcg->mnd_width && f->n) |
262 | cfg |= CFG_MODE_DUAL_EDGE; | 257 | cfg |= CFG_MODE_DUAL_EDGE; |
263 | ret = regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, mask, | 258 | ret = regmap_update_bits(rcg->clkr.regmap, |
264 | cfg); | 259 | rcg->cmd_rcgr + CFG_REG, mask, cfg); |
265 | if (ret) | 260 | if (ret) |
266 | return ret; | 261 | return ret; |
267 | 262 | ||
268 | return update_config(rcg); | 263 | return update_config(rcg); |
269 | } | 264 | } |
270 | 265 | ||
266 | static int __clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate) | ||
267 | { | ||
268 | struct clk_rcg2 *rcg = to_clk_rcg2(hw); | ||
269 | const struct freq_tbl *f; | ||
270 | |||
271 | f = find_freq(rcg->freq_tbl, rate); | ||
272 | if (!f) | ||
273 | return -EINVAL; | ||
274 | |||
275 | return clk_rcg2_configure(rcg, f); | ||
276 | } | ||
277 | |||
271 | static int clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate, | 278 | static int clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate, |
272 | unsigned long parent_rate) | 279 | unsigned long parent_rate) |
273 | { | 280 | { |
@@ -290,3 +297,265 @@ const struct clk_ops clk_rcg2_ops = { | |||
290 | .set_rate_and_parent = clk_rcg2_set_rate_and_parent, | 297 | .set_rate_and_parent = clk_rcg2_set_rate_and_parent, |
291 | }; | 298 | }; |
292 | EXPORT_SYMBOL_GPL(clk_rcg2_ops); | 299 | EXPORT_SYMBOL_GPL(clk_rcg2_ops); |
300 | |||
301 | struct frac_entry { | ||
302 | int num; | ||
303 | int den; | ||
304 | }; | ||
305 | |||
306 | static const struct frac_entry frac_table_675m[] = { /* link rate of 270M */ | ||
307 | { 52, 295 }, /* 119 M */ | ||
308 | { 11, 57 }, /* 130.25 M */ | ||
309 | { 63, 307 }, /* 138.50 M */ | ||
310 | { 11, 50 }, /* 148.50 M */ | ||
311 | { 47, 206 }, /* 154 M */ | ||
312 | { 31, 100 }, /* 205.25 M */ | ||
313 | { 107, 269 }, /* 268.50 M */ | ||
314 | { }, | ||
315 | }; | ||
316 | |||
317 | static struct frac_entry frac_table_810m[] = { /* Link rate of 162M */ | ||
318 | { 31, 211 }, /* 119 M */ | ||
319 | { 32, 199 }, /* 130.25 M */ | ||
320 | { 63, 307 }, /* 138.50 M */ | ||
321 | { 11, 60 }, /* 148.50 M */ | ||
322 | { 50, 263 }, /* 154 M */ | ||
323 | { 31, 120 }, /* 205.25 M */ | ||
324 | { 119, 359 }, /* 268.50 M */ | ||
325 | { }, | ||
326 | }; | ||
327 | |||
328 | static int clk_edp_pixel_set_rate(struct clk_hw *hw, unsigned long rate, | ||
329 | unsigned long parent_rate) | ||
330 | { | ||
331 | struct clk_rcg2 *rcg = to_clk_rcg2(hw); | ||
332 | struct freq_tbl f = *rcg->freq_tbl; | ||
333 | const struct frac_entry *frac; | ||
334 | int delta = 100000; | ||
335 | s64 src_rate = parent_rate; | ||
336 | s64 request; | ||
337 | u32 mask = BIT(rcg->hid_width) - 1; | ||
338 | u32 hid_div; | ||
339 | |||
340 | if (src_rate == 810000000) | ||
341 | frac = frac_table_810m; | ||
342 | else | ||
343 | frac = frac_table_675m; | ||
344 | |||
345 | for (; frac->num; frac++) { | ||
346 | request = rate; | ||
347 | request *= frac->den; | ||
348 | request = div_s64(request, frac->num); | ||
349 | if ((src_rate < (request - delta)) || | ||
350 | (src_rate > (request + delta))) | ||
351 | continue; | ||
352 | |||
353 | regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, | ||
354 | &hid_div); | ||
355 | f.pre_div = hid_div; | ||
356 | f.pre_div >>= CFG_SRC_DIV_SHIFT; | ||
357 | f.pre_div &= mask; | ||
358 | f.m = frac->num; | ||
359 | f.n = frac->den; | ||
360 | |||
361 | return clk_rcg2_configure(rcg, &f); | ||
362 | } | ||
363 | |||
364 | return -EINVAL; | ||
365 | } | ||
366 | |||
367 | static int clk_edp_pixel_set_rate_and_parent(struct clk_hw *hw, | ||
368 | unsigned long rate, unsigned long parent_rate, u8 index) | ||
369 | { | ||
370 | /* Parent index is set statically in frequency table */ | ||
371 | return clk_edp_pixel_set_rate(hw, rate, parent_rate); | ||
372 | } | ||
373 | |||
374 | static long clk_edp_pixel_determine_rate(struct clk_hw *hw, unsigned long rate, | ||
375 | unsigned long *p_rate, struct clk **p) | ||
376 | { | ||
377 | struct clk_rcg2 *rcg = to_clk_rcg2(hw); | ||
378 | const struct freq_tbl *f = rcg->freq_tbl; | ||
379 | const struct frac_entry *frac; | ||
380 | int delta = 100000; | ||
381 | s64 src_rate = *p_rate; | ||
382 | s64 request; | ||
383 | u32 mask = BIT(rcg->hid_width) - 1; | ||
384 | u32 hid_div; | ||
385 | |||
386 | /* Force the correct parent */ | ||
387 | *p = clk_get_parent_by_index(hw->clk, f->src); | ||
388 | |||
389 | if (src_rate == 810000000) | ||
390 | frac = frac_table_810m; | ||
391 | else | ||
392 | frac = frac_table_675m; | ||
393 | |||
394 | for (; frac->num; frac++) { | ||
395 | request = rate; | ||
396 | request *= frac->den; | ||
397 | request = div_s64(request, frac->num); | ||
398 | if ((src_rate < (request - delta)) || | ||
399 | (src_rate > (request + delta))) | ||
400 | continue; | ||
401 | |||
402 | regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, | ||
403 | &hid_div); | ||
404 | hid_div >>= CFG_SRC_DIV_SHIFT; | ||
405 | hid_div &= mask; | ||
406 | |||
407 | return calc_rate(src_rate, frac->num, frac->den, !!frac->den, | ||
408 | hid_div); | ||
409 | } | ||
410 | |||
411 | return -EINVAL; | ||
412 | } | ||
413 | |||
414 | const struct clk_ops clk_edp_pixel_ops = { | ||
415 | .is_enabled = clk_rcg2_is_enabled, | ||
416 | .get_parent = clk_rcg2_get_parent, | ||
417 | .set_parent = clk_rcg2_set_parent, | ||
418 | .recalc_rate = clk_rcg2_recalc_rate, | ||
419 | .set_rate = clk_edp_pixel_set_rate, | ||
420 | .set_rate_and_parent = clk_edp_pixel_set_rate_and_parent, | ||
421 | .determine_rate = clk_edp_pixel_determine_rate, | ||
422 | }; | ||
423 | EXPORT_SYMBOL_GPL(clk_edp_pixel_ops); | ||
424 | |||
425 | static long clk_byte_determine_rate(struct clk_hw *hw, unsigned long rate, | ||
426 | unsigned long *p_rate, struct clk **p) | ||
427 | { | ||
428 | struct clk_rcg2 *rcg = to_clk_rcg2(hw); | ||
429 | const struct freq_tbl *f = rcg->freq_tbl; | ||
430 | unsigned long parent_rate, div; | ||
431 | u32 mask = BIT(rcg->hid_width) - 1; | ||
432 | |||
433 | if (rate == 0) | ||
434 | return -EINVAL; | ||
435 | |||
436 | *p = clk_get_parent_by_index(hw->clk, f->src); | ||
437 | *p_rate = parent_rate = __clk_round_rate(*p, rate); | ||
438 | |||
439 | div = DIV_ROUND_UP((2 * parent_rate), rate) - 1; | ||
440 | div = min_t(u32, div, mask); | ||
441 | |||
442 | return calc_rate(parent_rate, 0, 0, 0, div); | ||
443 | } | ||
444 | |||
445 | static int clk_byte_set_rate(struct clk_hw *hw, unsigned long rate, | ||
446 | unsigned long parent_rate) | ||
447 | { | ||
448 | struct clk_rcg2 *rcg = to_clk_rcg2(hw); | ||
449 | struct freq_tbl f = *rcg->freq_tbl; | ||
450 | unsigned long div; | ||
451 | u32 mask = BIT(rcg->hid_width) - 1; | ||
452 | |||
453 | div = DIV_ROUND_UP((2 * parent_rate), rate) - 1; | ||
454 | div = min_t(u32, div, mask); | ||
455 | |||
456 | f.pre_div = div; | ||
457 | |||
458 | return clk_rcg2_configure(rcg, &f); | ||
459 | } | ||
460 | |||
461 | static int clk_byte_set_rate_and_parent(struct clk_hw *hw, | ||
462 | unsigned long rate, unsigned long parent_rate, u8 index) | ||
463 | { | ||
464 | /* Parent index is set statically in frequency table */ | ||
465 | return clk_byte_set_rate(hw, rate, parent_rate); | ||
466 | } | ||
467 | |||
468 | const struct clk_ops clk_byte_ops = { | ||
469 | .is_enabled = clk_rcg2_is_enabled, | ||
470 | .get_parent = clk_rcg2_get_parent, | ||
471 | .set_parent = clk_rcg2_set_parent, | ||
472 | .recalc_rate = clk_rcg2_recalc_rate, | ||
473 | .set_rate = clk_byte_set_rate, | ||
474 | .set_rate_and_parent = clk_byte_set_rate_and_parent, | ||
475 | .determine_rate = clk_byte_determine_rate, | ||
476 | }; | ||
477 | EXPORT_SYMBOL_GPL(clk_byte_ops); | ||
478 | |||
479 | static const struct frac_entry frac_table_pixel[] = { | ||
480 | { 3, 8 }, | ||
481 | { 2, 9 }, | ||
482 | { 4, 9 }, | ||
483 | { 1, 1 }, | ||
484 | { } | ||
485 | }; | ||
486 | |||
487 | static long clk_pixel_determine_rate(struct clk_hw *hw, unsigned long rate, | ||
488 | unsigned long *p_rate, struct clk **p) | ||
489 | { | ||
490 | struct clk_rcg2 *rcg = to_clk_rcg2(hw); | ||
491 | unsigned long request, src_rate; | ||
492 | int delta = 100000; | ||
493 | const struct freq_tbl *f = rcg->freq_tbl; | ||
494 | const struct frac_entry *frac = frac_table_pixel; | ||
495 | struct clk *parent = *p = clk_get_parent_by_index(hw->clk, f->src); | ||
496 | |||
497 | for (; frac->num; frac++) { | ||
498 | request = (rate * frac->den) / frac->num; | ||
499 | |||
500 | src_rate = __clk_round_rate(parent, request); | ||
501 | if ((src_rate < (request - delta)) || | ||
502 | (src_rate > (request + delta))) | ||
503 | continue; | ||
504 | |||
505 | *p_rate = src_rate; | ||
506 | return (src_rate * frac->num) / frac->den; | ||
507 | } | ||
508 | |||
509 | return -EINVAL; | ||
510 | } | ||
511 | |||
512 | static int clk_pixel_set_rate(struct clk_hw *hw, unsigned long rate, | ||
513 | unsigned long parent_rate) | ||
514 | { | ||
515 | struct clk_rcg2 *rcg = to_clk_rcg2(hw); | ||
516 | struct freq_tbl f = *rcg->freq_tbl; | ||
517 | const struct frac_entry *frac = frac_table_pixel; | ||
518 | unsigned long request, src_rate; | ||
519 | int delta = 100000; | ||
520 | u32 mask = BIT(rcg->hid_width) - 1; | ||
521 | u32 hid_div; | ||
522 | struct clk *parent = clk_get_parent_by_index(hw->clk, f.src); | ||
523 | |||
524 | for (; frac->num; frac++) { | ||
525 | request = (rate * frac->den) / frac->num; | ||
526 | |||
527 | src_rate = __clk_round_rate(parent, request); | ||
528 | if ((src_rate < (request - delta)) || | ||
529 | (src_rate > (request + delta))) | ||
530 | continue; | ||
531 | |||
532 | regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, | ||
533 | &hid_div); | ||
534 | f.pre_div = hid_div; | ||
535 | f.pre_div >>= CFG_SRC_DIV_SHIFT; | ||
536 | f.pre_div &= mask; | ||
537 | f.m = frac->num; | ||
538 | f.n = frac->den; | ||
539 | |||
540 | return clk_rcg2_configure(rcg, &f); | ||
541 | } | ||
542 | return -EINVAL; | ||
543 | } | ||
544 | |||
545 | static int clk_pixel_set_rate_and_parent(struct clk_hw *hw, unsigned long rate, | ||
546 | unsigned long parent_rate, u8 index) | ||
547 | { | ||
548 | /* Parent index is set statically in frequency table */ | ||
549 | return clk_pixel_set_rate(hw, rate, parent_rate); | ||
550 | } | ||
551 | |||
552 | const struct clk_ops clk_pixel_ops = { | ||
553 | .is_enabled = clk_rcg2_is_enabled, | ||
554 | .get_parent = clk_rcg2_get_parent, | ||
555 | .set_parent = clk_rcg2_set_parent, | ||
556 | .recalc_rate = clk_rcg2_recalc_rate, | ||
557 | .set_rate = clk_pixel_set_rate, | ||
558 | .set_rate_and_parent = clk_pixel_set_rate_and_parent, | ||
559 | .determine_rate = clk_pixel_determine_rate, | ||
560 | }; | ||
561 | EXPORT_SYMBOL_GPL(clk_pixel_ops); | ||