aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter De Schrijver <pdeschrijver@nvidia.com>2013-04-03 10:40:39 -0400
committerStephen Warren <swarren@nvidia.com>2013-04-04 18:10:45 -0400
commit0b6525acd13f2d33cd3be86d0dbd2ddd1ffeda8f (patch)
tree989c920b532d4d5d7372c275ed828356cff9c581
parent7ba28813b41120dd67329fd04dc732ea7fef05a0 (diff)
clk: tegra: Add PLL post divider table
Some PLLs in Tegra114 don't use a power of 2 mapping for the post divider. Introduce a table based approach and switch PLLU to it. Signed-off-by: Peter De Schrijver <pdeschrijver@nvidia.com> Acked-by: Mike Turquette <mturquette@linaro.org> Signed-off-by: Stephen Warren <swarren@nvidia.com>
-rw-r--r--drivers/clk/tegra/clk-pll.c38
-rw-r--r--drivers/clk/tegra/clk-tegra20.c7
-rw-r--r--drivers/clk/tegra/clk-tegra30.c7
-rw-r--r--drivers/clk/tegra/clk.h13
4 files changed, 59 insertions, 6 deletions
diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c
index eaab060cda24..ccb367ee7e78 100644
--- a/drivers/clk/tegra/clk-pll.c
+++ b/drivers/clk/tegra/clk-pll.c
@@ -266,6 +266,7 @@ static int _calc_rate(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg,
266 unsigned long rate, unsigned long parent_rate) 266 unsigned long rate, unsigned long parent_rate)
267{ 267{
268 struct tegra_clk_pll *pll = to_clk_pll(hw); 268 struct tegra_clk_pll *pll = to_clk_pll(hw);
269 struct pdiv_map *p_tohw = pll->params->pdiv_tohw;
269 unsigned long cfreq; 270 unsigned long cfreq;
270 u32 p_div = 0; 271 u32 p_div = 0;
271 272
@@ -299,7 +300,6 @@ static int _calc_rate(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg,
299 cfg->output_rate <<= 1) 300 cfg->output_rate <<= 1)
300 p_div++; 301 p_div++;
301 302
302 cfg->p = p_div;
303 cfg->m = parent_rate / cfreq; 303 cfg->m = parent_rate / cfreq;
304 cfg->n = cfg->output_rate / cfreq; 304 cfg->n = cfg->output_rate / cfreq;
305 cfg->cpcon = OUT_OF_TABLE_CPCON; 305 cfg->cpcon = OUT_OF_TABLE_CPCON;
@@ -312,8 +312,19 @@ static int _calc_rate(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg,
312 return -EINVAL; 312 return -EINVAL;
313 } 313 }
314 314
315 if (pll->flags & TEGRA_PLLU) 315 if (p_tohw) {
316 cfg->p ^= 1; 316 p_div = 1 << p_div;
317 while (p_tohw->pdiv) {
318 if (p_div <= p_tohw->pdiv) {
319 cfg->p = p_tohw->hw_val;
320 break;
321 }
322 p_tohw++;
323 }
324 if (!p_tohw->pdiv)
325 return -EINVAL;
326 } else
327 cfg->p = p_div;
317 328
318 return 0; 329 return 0;
319} 330}
@@ -460,8 +471,10 @@ static unsigned long clk_pll_recalc_rate(struct clk_hw *hw,
460{ 471{
461 struct tegra_clk_pll *pll = to_clk_pll(hw); 472 struct tegra_clk_pll *pll = to_clk_pll(hw);
462 struct tegra_clk_pll_freq_table cfg; 473 struct tegra_clk_pll_freq_table cfg;
474 struct pdiv_map *p_tohw = pll->params->pdiv_tohw;
463 u32 val; 475 u32 val;
464 u64 rate = parent_rate; 476 u64 rate = parent_rate;
477 int pdiv;
465 478
466 val = pll_readl_base(pll); 479 val = pll_readl_base(pll);
467 480
@@ -480,10 +493,23 @@ static unsigned long clk_pll_recalc_rate(struct clk_hw *hw,
480 493
481 _get_pll_mnp(pll, &cfg); 494 _get_pll_mnp(pll, &cfg);
482 495
483 if (pll->flags & TEGRA_PLLU) 496 if (p_tohw) {
484 cfg.p ^= 1; 497 while (p_tohw->pdiv) {
498 if (cfg.p == p_tohw->hw_val) {
499 pdiv = p_tohw->pdiv;
500 break;
501 }
502 p_tohw++;
503 }
504
505 if (!p_tohw->pdiv) {
506 WARN_ON(1);
507 pdiv = 1;
508 }
509 } else
510 pdiv = 1 << cfg.p;
485 511
486 cfg.m *= 1 << cfg.p; 512 cfg.m *= pdiv;
487 513
488 rate *= cfg.n; 514 rate *= cfg.n;
489 do_div(rate, cfg.m); 515 do_div(rate, cfg.m);
diff --git a/drivers/clk/tegra/clk-tegra20.c b/drivers/clk/tegra/clk-tegra20.c
index c2a1c4cae47c..f215bf10c9ff 100644
--- a/drivers/clk/tegra/clk-tegra20.c
+++ b/drivers/clk/tegra/clk-tegra20.c
@@ -441,6 +441,12 @@ static struct tegra_clk_pll_params pll_d_params = {
441 .lock_delay = 1000, 441 .lock_delay = 1000,
442}; 442};
443 443
444static struct pdiv_map pllu_p[] = {
445 { .pdiv = 1, .hw_val = 1 },
446 { .pdiv = 2, .hw_val = 0 },
447 { .pdiv = 0, .hw_val = 0 },
448};
449
444static struct tegra_clk_pll_params pll_u_params = { 450static struct tegra_clk_pll_params pll_u_params = {
445 .input_min = 2000000, 451 .input_min = 2000000,
446 .input_max = 40000000, 452 .input_max = 40000000,
@@ -453,6 +459,7 @@ static struct tegra_clk_pll_params pll_u_params = {
453 .lock_bit_idx = PLL_BASE_LOCK, 459 .lock_bit_idx = PLL_BASE_LOCK,
454 .lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE, 460 .lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE,
455 .lock_delay = 1000, 461 .lock_delay = 1000,
462 .pdiv_tohw = pllu_p,
456}; 463};
457 464
458static struct tegra_clk_pll_params pll_x_params = { 465static struct tegra_clk_pll_params pll_x_params = {
diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c
index 02609d125e0e..fe768fe769b2 100644
--- a/drivers/clk/tegra/clk-tegra30.c
+++ b/drivers/clk/tegra/clk-tegra30.c
@@ -467,6 +467,12 @@ static struct tegra_clk_pll_freq_table pll_d_freq_table[] = {
467 { 0, 0, 0, 0, 0, 0 }, 467 { 0, 0, 0, 0, 0, 0 },
468}; 468};
469 469
470static struct pdiv_map pllu_p[] = {
471 { .pdiv = 1, .hw_val = 1 },
472 { .pdiv = 2, .hw_val = 0 },
473 { .pdiv = 0, .hw_val = 0 },
474};
475
470static struct tegra_clk_pll_freq_table pll_u_freq_table[] = { 476static struct tegra_clk_pll_freq_table pll_u_freq_table[] = {
471 { 12000000, 480000000, 960, 12, 0, 12}, 477 { 12000000, 480000000, 960, 12, 0, 12},
472 { 13000000, 480000000, 960, 13, 0, 12}, 478 { 13000000, 480000000, 960, 13, 0, 12},
@@ -640,6 +646,7 @@ static struct tegra_clk_pll_params pll_u_params = {
640 .lock_bit_idx = PLL_BASE_LOCK, 646 .lock_bit_idx = PLL_BASE_LOCK,
641 .lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE, 647 .lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE,
642 .lock_delay = 1000, 648 .lock_delay = 1000,
649 .pdiv_tohw = pllu_p,
643}; 650};
644 651
645static struct tegra_clk_pll_params pll_x_params = { 652static struct tegra_clk_pll_params pll_x_params = {
diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
index 17ddb22f7a50..925da451bd19 100644
--- a/drivers/clk/tegra/clk.h
+++ b/drivers/clk/tegra/clk.h
@@ -117,6 +117,17 @@ struct tegra_clk_pll_freq_table {
117}; 117};
118 118
119/** 119/**
120 * struct pdiv_map - map post divider to hw value
121 *
122 * @pdiv: post divider
123 * @hw_val: value to be written to the PLL hw
124 */
125struct pdiv_map {
126 u8 pdiv;
127 u8 hw_val;
128};
129
130/**
120 * struct clk_pll_params - PLL parameters 131 * struct clk_pll_params - PLL parameters
121 * 132 *
122 * @input_min: Minimum input frequency 133 * @input_min: Minimum input frequency
@@ -146,6 +157,8 @@ struct tegra_clk_pll_params {
146 u32 lock_bit_idx; 157 u32 lock_bit_idx;
147 u32 lock_enable_bit_idx; 158 u32 lock_enable_bit_idx;
148 int lock_delay; 159 int lock_delay;
160 int max_p;
161 struct pdiv_map *pdiv_tohw;
149}; 162};
150 163
151/** 164/**