ARM: tegra: clock: fix PLLD/PLLD2 related clock calculations
While PLLD/D2 is the nominal parent clock, all derived clocks are generated from its single output, plld_out0, which is PLLD/D2 divided by two. Direct use of PLLD/D2 is absent in peripheral clock configurations. Therefore, clock derivation formulas must take in account this division. Signed-off-by: Jonas Schwöbel <jonasschwoebel@yahoo.de> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
This commit is contained in:

committed by
Svyatoslav Ryhel

parent
8fb7ed59a8
commit
dbc27c2462
@@ -358,6 +358,13 @@ unsigned long clock_get_periph_rate(enum periph_id periph_id,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PLLD/PLLD2 raw clock rate is never used, instead plld_out0 is used
|
||||||
|
* that is PLLD/PLLD2 halved.
|
||||||
|
*/
|
||||||
|
if (parent == CLOCK_ID_DISPLAY || parent == CLOCK_ID_DISPLAY2)
|
||||||
|
parent_rate /= 2;
|
||||||
|
|
||||||
return get_rate_from_divider(parent_rate, div);
|
return get_rate_from_divider(parent_rate, div);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -449,6 +456,7 @@ unsigned clock_adjust_periph_pll_div(enum periph_id periph_id,
|
|||||||
enum clock_id parent, unsigned rate, int *extra_div)
|
enum clock_id parent, unsigned rate, int *extra_div)
|
||||||
{
|
{
|
||||||
unsigned effective_rate;
|
unsigned effective_rate;
|
||||||
|
unsigned int parent_rate;
|
||||||
int mux_bits, divider_bits, source;
|
int mux_bits, divider_bits, source;
|
||||||
int divider;
|
int divider;
|
||||||
int xdiv = 0;
|
int xdiv = 0;
|
||||||
@@ -457,7 +465,17 @@ unsigned clock_adjust_periph_pll_div(enum periph_id periph_id,
|
|||||||
source = get_periph_clock_source(periph_id, parent, &mux_bits,
|
source = get_periph_clock_source(periph_id, parent, &mux_bits,
|
||||||
÷r_bits);
|
÷r_bits);
|
||||||
|
|
||||||
divider = find_best_divider(divider_bits, pll_rate[parent],
|
/*
|
||||||
|
* Clocks derived from PLLD/D2 are actually sourced from its halved
|
||||||
|
* output, plld_out0/plld2_out0. No peripheral clocks use the raw
|
||||||
|
* PLLD/D2 frequency. This halving must be accounted for in derived
|
||||||
|
* clock calculations.
|
||||||
|
*/
|
||||||
|
parent_rate = pll_rate[parent];
|
||||||
|
if (parent == CLOCK_ID_DISPLAY || parent == CLOCK_ID_DISPLAY2)
|
||||||
|
parent_rate /= 2;
|
||||||
|
|
||||||
|
divider = find_best_divider(divider_bits, parent_rate,
|
||||||
rate, &xdiv);
|
rate, &xdiv);
|
||||||
if (extra_div)
|
if (extra_div)
|
||||||
*extra_div = xdiv;
|
*extra_div = xdiv;
|
||||||
@@ -685,6 +703,16 @@ int clock_set_rate(enum clock_id clkid, u32 n, u32 m, u32 p, u32 cpcon)
|
|||||||
else
|
else
|
||||||
writel(base_reg, &simple_pll->pll_base);
|
writel(base_reg, &simple_pll->pll_base);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Changing clocks was never intended in the U-Boot for Tegra.
|
||||||
|
* If a clock is changed after clock_init() the parent rate is wrong.
|
||||||
|
* Usually there is no reason to change peripheral clocks, but Display
|
||||||
|
* PLLs which needs to generate a precise pixelclock might be adjusted.
|
||||||
|
* Especially in the case of HDMI display with changing and prior
|
||||||
|
* unknown resolution.
|
||||||
|
*/
|
||||||
|
pll_rate[clkid] = clock_get_rate(clkid);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user