aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap2
diff options
context:
space:
mode:
authorMichael Turquette <mturquette@linaro.org>2014-12-15 16:30:05 -0500
committerMichael Turquette <mturquette@linaro.org>2014-12-15 20:05:07 -0500
commitb1924c2ec1db98278100010ef87b54406d5ce612 (patch)
treee8cab2230cdf0e85920075bf2489b04030d4a78e /arch/arm/mach-omap2
parent89f7e9de59bf3e3cda2e00de12c66db22675a7cf (diff)
parent79005fbd3e1d671d08c45c9140ee9826efdc367c (diff)
Merge tag 'for-v3.19/omap-a' of git://git.kernel.org/pub/scm/linux/kernel/git/pjw/omap-pending into tmp
Some OMAP clock/hwmod patches for v3.19. Most of the patches are clock-related. The DPLL implementation is changed to better align to the common clock framework. There is also a patch that removes a few lines from the hwmod code - this patch should have no functional effect. Basic build, boot, and PM test logs for these patches can be found here: http://www.pwsan.com/omap/testlogs/omap-a-for-v3.19/20141113094101/
Diffstat (limited to 'arch/arm/mach-omap2')
-rw-r--r--arch/arm/mach-omap2/cclock3xxx_data.c6
-rw-r--r--arch/arm/mach-omap2/clock.c4
-rw-r--r--arch/arm/mach-omap2/clock.h1
-rw-r--r--arch/arm/mach-omap2/clock3xxx.c38
-rw-r--r--arch/arm/mach-omap2/dpll3xxx.c179
-rw-r--r--arch/arm/mach-omap2/dpll44xx.c41
-rw-r--r--arch/arm/mach-omap2/omap_hwmod.c2
7 files changed, 208 insertions, 63 deletions
diff --git a/arch/arm/mach-omap2/cclock3xxx_data.c b/arch/arm/mach-omap2/cclock3xxx_data.c
index eb8c75ec3b1a..5c5ebb4db5f7 100644
--- a/arch/arm/mach-omap2/cclock3xxx_data.c
+++ b/arch/arm/mach-omap2/cclock3xxx_data.c
@@ -257,6 +257,9 @@ static const struct clk_ops dpll1_ck_ops = {
257 .get_parent = &omap2_init_dpll_parent, 257 .get_parent = &omap2_init_dpll_parent,
258 .recalc_rate = &omap3_dpll_recalc, 258 .recalc_rate = &omap3_dpll_recalc,
259 .set_rate = &omap3_noncore_dpll_set_rate, 259 .set_rate = &omap3_noncore_dpll_set_rate,
260 .set_parent = &omap3_noncore_dpll_set_parent,
261 .set_rate_and_parent = &omap3_noncore_dpll_set_rate_and_parent,
262 .determine_rate = &omap3_noncore_dpll_determine_rate,
260 .round_rate = &omap2_dpll_round_rate, 263 .round_rate = &omap2_dpll_round_rate,
261}; 264};
262 265
@@ -367,6 +370,9 @@ static const struct clk_ops dpll4_ck_ops = {
367 .get_parent = &omap2_init_dpll_parent, 370 .get_parent = &omap2_init_dpll_parent,
368 .recalc_rate = &omap3_dpll_recalc, 371 .recalc_rate = &omap3_dpll_recalc,
369 .set_rate = &omap3_dpll4_set_rate, 372 .set_rate = &omap3_dpll4_set_rate,
373 .set_parent = &omap3_noncore_dpll_set_parent,
374 .set_rate_and_parent = &omap3_dpll4_set_rate_and_parent,
375 .determine_rate = &omap3_noncore_dpll_determine_rate,
370 .round_rate = &omap2_dpll_round_rate, 376 .round_rate = &omap2_dpll_round_rate,
371}; 377};
372 378
diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c
index 500530d1364a..c2b239857cc4 100644
--- a/arch/arm/mach-omap2/clock.c
+++ b/arch/arm/mach-omap2/clock.c
@@ -771,4 +771,8 @@ void __init ti_clk_init_features(void)
771 ti_clk_features.cm_idlest_val = OMAP24XX_CM_IDLEST_VAL; 771 ti_clk_features.cm_idlest_val = OMAP24XX_CM_IDLEST_VAL;
772 else if (cpu_is_omap34xx()) 772 else if (cpu_is_omap34xx())
773 ti_clk_features.cm_idlest_val = OMAP34XX_CM_IDLEST_VAL; 773 ti_clk_features.cm_idlest_val = OMAP34XX_CM_IDLEST_VAL;
774
775 /* On OMAP3430 ES1.0, DPLL4 can't be re-programmed */
776 if (omap_rev() == OMAP3430_REV_ES1_0)
777 ti_clk_features.flags |= TI_CLK_DPLL4_DENY_REPROGRAM;
774} 778}
diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h
index 4592a2762592..641337c6cde9 100644
--- a/arch/arm/mach-omap2/clock.h
+++ b/arch/arm/mach-omap2/clock.h
@@ -234,6 +234,7 @@ struct ti_clk_features {
234}; 234};
235 235
236#define TI_CLK_DPLL_HAS_FREQSEL (1 << 0) 236#define TI_CLK_DPLL_HAS_FREQSEL (1 << 0)
237#define TI_CLK_DPLL4_DENY_REPROGRAM (1 << 1)
237 238
238extern struct ti_clk_features ti_clk_features; 239extern struct ti_clk_features ti_clk_features;
239 240
diff --git a/arch/arm/mach-omap2/clock3xxx.c b/arch/arm/mach-omap2/clock3xxx.c
index 0b02b4161d71..a9e86db5daf9 100644
--- a/arch/arm/mach-omap2/clock3xxx.c
+++ b/arch/arm/mach-omap2/clock3xxx.c
@@ -38,6 +38,18 @@
38 38
39/* needed by omap3_core_dpll_m2_set_rate() */ 39/* needed by omap3_core_dpll_m2_set_rate() */
40struct clk *sdrc_ick_p, *arm_fck_p; 40struct clk *sdrc_ick_p, *arm_fck_p;
41
42/**
43 * omap3_dpll4_set_rate - set rate for omap3 per-dpll
44 * @hw: clock to change
45 * @rate: target rate for clock
46 * @parent_rate: rate of the parent clock
47 *
48 * Check if the current SoC supports the per-dpll reprogram operation
49 * or not, and then do the rate change if supported. Returns -EINVAL
50 * if not supported, 0 for success, and potential error codes from the
51 * clock rate change.
52 */
41int omap3_dpll4_set_rate(struct clk_hw *hw, unsigned long rate, 53int omap3_dpll4_set_rate(struct clk_hw *hw, unsigned long rate,
42 unsigned long parent_rate) 54 unsigned long parent_rate)
43{ 55{
@@ -46,7 +58,7 @@ int omap3_dpll4_set_rate(struct clk_hw *hw, unsigned long rate,
46 * on 3430ES1 prevents us from changing DPLL multipliers or dividers 58 * on 3430ES1 prevents us from changing DPLL multipliers or dividers
47 * on DPLL4. 59 * on DPLL4.
48 */ 60 */
49 if (omap_rev() == OMAP3430_REV_ES1_0) { 61 if (ti_clk_features.flags & TI_CLK_DPLL4_DENY_REPROGRAM) {
50 pr_err("clock: DPLL4 cannot change rate due to silicon 'Limitation 2.5' on 3430ES1.\n"); 62 pr_err("clock: DPLL4 cannot change rate due to silicon 'Limitation 2.5' on 3430ES1.\n");
51 return -EINVAL; 63 return -EINVAL;
52 } 64 }
@@ -54,6 +66,30 @@ int omap3_dpll4_set_rate(struct clk_hw *hw, unsigned long rate,
54 return omap3_noncore_dpll_set_rate(hw, rate, parent_rate); 66 return omap3_noncore_dpll_set_rate(hw, rate, parent_rate);
55} 67}
56 68
69/**
70 * omap3_dpll4_set_rate_and_parent - set rate and parent for omap3 per-dpll
71 * @hw: clock to change
72 * @rate: target rate for clock
73 * @parent_rate: rate of the parent clock
74 * @index: parent index, 0 - reference clock, 1 - bypass clock
75 *
76 * Check if the current SoC support the per-dpll reprogram operation
77 * or not, and then do the rate + parent change if supported. Returns
78 * -EINVAL if not supported, 0 for success, and potential error codes
79 * from the clock rate change.
80 */
81int omap3_dpll4_set_rate_and_parent(struct clk_hw *hw, unsigned long rate,
82 unsigned long parent_rate, u8 index)
83{
84 if (ti_clk_features.flags & TI_CLK_DPLL4_DENY_REPROGRAM) {
85 pr_err("clock: DPLL4 cannot change rate due to silicon 'Limitation 2.5' on 3430ES1.\n");
86 return -EINVAL;
87 }
88
89 return omap3_noncore_dpll_set_rate_and_parent(hw, rate, parent_rate,
90 index);
91}
92
57void __init omap3_clk_lock_dpll5(void) 93void __init omap3_clk_lock_dpll5(void)
58{ 94{
59 struct clk *dpll5_clk; 95 struct clk *dpll5_clk;
diff --git a/arch/arm/mach-omap2/dpll3xxx.c b/arch/arm/mach-omap2/dpll3xxx.c
index ac3d789ac3cd..20e120d071dd 100644
--- a/arch/arm/mach-omap2/dpll3xxx.c
+++ b/arch/arm/mach-omap2/dpll3xxx.c
@@ -460,25 +460,24 @@ void omap3_noncore_dpll_disable(struct clk_hw *hw)
460/* Non-CORE DPLL rate set code */ 460/* Non-CORE DPLL rate set code */
461 461
462/** 462/**
463 * omap3_noncore_dpll_set_rate - set non-core DPLL rate 463 * omap3_noncore_dpll_determine_rate - determine rate for a DPLL
464 * @clk: struct clk * of DPLL to set 464 * @hw: pointer to the clock to determine rate for
465 * @rate: rounded target rate 465 * @rate: target rate for the DPLL
466 * @best_parent_rate: pointer for returning best parent rate
467 * @best_parent_clk: pointer for returning best parent clock
466 * 468 *
467 * Set the DPLL CLKOUT to the target rate. If the DPLL can enter 469 * Determines which DPLL mode to use for reaching a desired target rate.
468 * low-power bypass, and the target rate is the bypass source clock 470 * Checks whether the DPLL shall be in bypass or locked mode, and if
469 * rate, then configure the DPLL for bypass. Otherwise, round the 471 * locked, calculates the M,N values for the DPLL via round-rate.
470 * target rate if it hasn't been done already, then program and lock 472 * Returns a positive clock rate with success, negative error value
471 * the DPLL. Returns -EINVAL upon error, or 0 upon success. 473 * in failure.
472 */ 474 */
473int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate, 475long omap3_noncore_dpll_determine_rate(struct clk_hw *hw, unsigned long rate,
474 unsigned long parent_rate) 476 unsigned long *best_parent_rate,
477 struct clk **best_parent_clk)
475{ 478{
476 struct clk_hw_omap *clk = to_clk_hw_omap(hw); 479 struct clk_hw_omap *clk = to_clk_hw_omap(hw);
477 struct clk *new_parent = NULL;
478 unsigned long rrate;
479 u16 freqsel = 0;
480 struct dpll_data *dd; 480 struct dpll_data *dd;
481 int ret;
482 481
483 if (!hw || !rate) 482 if (!hw || !rate)
484 return -EINVAL; 483 return -EINVAL;
@@ -489,61 +488,121 @@ int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate,
489 488
490 if (__clk_get_rate(dd->clk_bypass) == rate && 489 if (__clk_get_rate(dd->clk_bypass) == rate &&
491 (dd->modes & (1 << DPLL_LOW_POWER_BYPASS))) { 490 (dd->modes & (1 << DPLL_LOW_POWER_BYPASS))) {
492 pr_debug("%s: %s: set rate: entering bypass.\n", 491 *best_parent_clk = dd->clk_bypass;
493 __func__, __clk_get_name(hw->clk)); 492 } else {
493 rate = omap2_dpll_round_rate(hw, rate, best_parent_rate);
494 *best_parent_clk = dd->clk_ref;
495 }
496
497 *best_parent_rate = rate;
498
499 return rate;
500}
501
502/**
503 * omap3_noncore_dpll_set_parent - set parent for a DPLL clock
504 * @hw: pointer to the clock to set parent for
505 * @index: parent index to select
506 *
507 * Sets parent for a DPLL clock. This sets the DPLL into bypass or
508 * locked mode. Returns 0 with success, negative error value otherwise.
509 */
510int omap3_noncore_dpll_set_parent(struct clk_hw *hw, u8 index)
511{
512 struct clk_hw_omap *clk = to_clk_hw_omap(hw);
513 int ret;
494 514
495 __clk_prepare(dd->clk_bypass); 515 if (!hw)
496 clk_enable(dd->clk_bypass); 516 return -EINVAL;
517
518 if (index)
497 ret = _omap3_noncore_dpll_bypass(clk); 519 ret = _omap3_noncore_dpll_bypass(clk);
498 if (!ret) 520 else
499 new_parent = dd->clk_bypass; 521 ret = _omap3_noncore_dpll_lock(clk);
500 clk_disable(dd->clk_bypass);
501 __clk_unprepare(dd->clk_bypass);
502 } else {
503 __clk_prepare(dd->clk_ref);
504 clk_enable(dd->clk_ref);
505
506 /* XXX this check is probably pointless in the CCF context */
507 if (dd->last_rounded_rate != rate) {
508 rrate = __clk_round_rate(hw->clk, rate);
509 if (rrate != rate) {
510 pr_warn("%s: %s: final rate %lu does not match desired rate %lu\n",
511 __func__, __clk_get_name(hw->clk),
512 rrate, rate);
513 rate = rrate;
514 }
515 }
516 522
517 if (dd->last_rounded_rate == 0) 523 return ret;
518 return -EINVAL; 524}
519 525
520 /* Freqsel is available only on OMAP343X devices */ 526/**
521 if (ti_clk_features.flags & TI_CLK_DPLL_HAS_FREQSEL) { 527 * omap3_noncore_dpll_set_rate - set rate for a DPLL clock
522 freqsel = _omap3_dpll_compute_freqsel(clk, 528 * @hw: pointer to the clock to set parent for
523 dd->last_rounded_n); 529 * @rate: target rate for the clock
524 WARN_ON(!freqsel); 530 * @parent_rate: rate of the parent clock
525 } 531 *
532 * Sets rate for a DPLL clock. First checks if the clock parent is
533 * reference clock (in bypass mode, the rate of the clock can't be
534 * changed) and proceeds with the rate change operation. Returns 0
535 * with success, negative error value otherwise.
536 */
537int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate,
538 unsigned long parent_rate)
539{
540 struct clk_hw_omap *clk = to_clk_hw_omap(hw);
541 struct dpll_data *dd;
542 u16 freqsel = 0;
543 int ret;
544
545 if (!hw || !rate)
546 return -EINVAL;
547
548 dd = clk->dpll_data;
549 if (!dd)
550 return -EINVAL;
526 551
527 pr_debug("%s: %s: set rate: locking rate to %lu.\n", 552 if (__clk_get_parent(hw->clk) != dd->clk_ref)
528 __func__, __clk_get_name(hw->clk), rate); 553 return -EINVAL;
554
555 if (dd->last_rounded_rate == 0)
556 return -EINVAL;
529 557
530 ret = omap3_noncore_dpll_program(clk, freqsel); 558 /* Freqsel is available only on OMAP343X devices */
531 if (!ret) 559 if (ti_clk_features.flags & TI_CLK_DPLL_HAS_FREQSEL) {
532 new_parent = dd->clk_ref; 560 freqsel = _omap3_dpll_compute_freqsel(clk, dd->last_rounded_n);
533 clk_disable(dd->clk_ref); 561 WARN_ON(!freqsel);
534 __clk_unprepare(dd->clk_ref);
535 } 562 }
536 /*
537 * FIXME - this is all wrong. common code handles reparenting and
538 * migrating prepare/enable counts. dplls should be a multiplexer
539 * clock and this should be a set_parent operation so that all of that
540 * stuff is inherited for free
541 */
542 563
543 if (!ret && clk_get_parent(hw->clk) != new_parent) 564 pr_debug("%s: %s: set rate: locking rate to %lu.\n", __func__,
544 __clk_reparent(hw->clk, new_parent); 565 __clk_get_name(hw->clk), rate);
545 566
546 return 0; 567 ret = omap3_noncore_dpll_program(clk, freqsel);
568
569 return ret;
570}
571
572/**
573 * omap3_noncore_dpll_set_rate_and_parent - set rate and parent for a DPLL clock
574 * @hw: pointer to the clock to set rate and parent for
575 * @rate: target rate for the DPLL
576 * @parent_rate: clock rate of the DPLL parent
577 * @index: new parent index for the DPLL, 0 - reference, 1 - bypass
578 *
579 * Sets rate and parent for a DPLL clock. If new parent is the bypass
580 * clock, only selects the parent. Otherwise proceeds with a rate
581 * change, as this will effectively also change the parent as the
582 * DPLL is put into locked mode. Returns 0 with success, negative error
583 * value otherwise.
584 */
585int omap3_noncore_dpll_set_rate_and_parent(struct clk_hw *hw,
586 unsigned long rate,
587 unsigned long parent_rate,
588 u8 index)
589{
590 int ret;
591
592 if (!hw || !rate)
593 return -EINVAL;
594
595 /*
596 * clk-ref at index[0], in which case we only need to set rate,
597 * the parent will be changed automatically with the lock sequence.
598 * With clk-bypass case we only need to change parent.
599 */
600 if (index)
601 ret = omap3_noncore_dpll_set_parent(hw, index);
602 else
603 ret = omap3_noncore_dpll_set_rate(hw, rate, parent_rate);
604
605 return ret;
547} 606}
548 607
549/* DPLL autoidle read/set code */ 608/* DPLL autoidle read/set code */
diff --git a/arch/arm/mach-omap2/dpll44xx.c b/arch/arm/mach-omap2/dpll44xx.c
index 4613f1e86988..535822fcf4bb 100644
--- a/arch/arm/mach-omap2/dpll44xx.c
+++ b/arch/arm/mach-omap2/dpll44xx.c
@@ -207,3 +207,44 @@ out:
207 207
208 return dd->last_rounded_rate; 208 return dd->last_rounded_rate;
209} 209}
210
211/**
212 * omap4_dpll_regm4xen_determine_rate - determine rate for a DPLL
213 * @hw: pointer to the clock to determine rate for
214 * @rate: target rate for the DPLL
215 * @best_parent_rate: pointer for returning best parent rate
216 * @best_parent_clk: pointer for returning best parent clock
217 *
218 * Determines which DPLL mode to use for reaching a desired rate.
219 * Checks whether the DPLL shall be in bypass or locked mode, and if
220 * locked, calculates the M,N values for the DPLL via round-rate.
221 * Returns a positive clock rate with success, negative error value
222 * in failure.
223 */
224long omap4_dpll_regm4xen_determine_rate(struct clk_hw *hw, unsigned long rate,
225 unsigned long *best_parent_rate,
226 struct clk **best_parent_clk)
227{
228 struct clk_hw_omap *clk = to_clk_hw_omap(hw);
229 struct dpll_data *dd;
230
231 if (!hw || !rate)
232 return -EINVAL;
233
234 dd = clk->dpll_data;
235 if (!dd)
236 return -EINVAL;
237
238 if (__clk_get_rate(dd->clk_bypass) == rate &&
239 (dd->modes & (1 << DPLL_LOW_POWER_BYPASS))) {
240 *best_parent_clk = dd->clk_bypass;
241 } else {
242 rate = omap4_dpll_regm4xen_round_rate(hw, rate,
243 best_parent_rate);
244 *best_parent_clk = dd->clk_ref;
245 }
246
247 *best_parent_rate = rate;
248
249 return rate;
250}
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index 716247ed9e0c..acae6d5d1151 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -2832,12 +2832,10 @@ static int __init _add_link(struct omap_hwmod_ocp_if *oi)
2832 _alloc_links(&ml, &sl); 2832 _alloc_links(&ml, &sl);
2833 2833
2834 ml->ocp_if = oi; 2834 ml->ocp_if = oi;
2835 INIT_LIST_HEAD(&ml->node);
2836 list_add(&ml->node, &oi->master->master_ports); 2835 list_add(&ml->node, &oi->master->master_ports);
2837 oi->master->masters_cnt++; 2836 oi->master->masters_cnt++;
2838 2837
2839 sl->ocp_if = oi; 2838 sl->ocp_if = oi;
2840 INIT_LIST_HEAD(&sl->node);
2841 list_add(&sl->node, &oi->slave->slave_ports); 2839 list_add(&sl->node, &oi->slave->slave_ports);
2842 oi->slave->slaves_cnt++; 2840 oi->slave->slaves_cnt++;
2843 2841