|
@@ -101,6 +101,7 @@ int clock_ll_read_pll(enum clock_id clkid, u32 *divm, u32 *divn,
|
|
|
u32 *divp, u32 *cpcon, u32 *lfcon)
|
|
|
{
|
|
|
struct clk_pll *pll = get_pll(clkid);
|
|
|
+ struct clk_pll_info *pllinfo = &tegra_pll_info_table[clkid];
|
|
|
u32 data;
|
|
|
|
|
|
assert(clkid != CLOCK_ID_USB);
|
|
@@ -109,17 +110,14 @@ int clock_ll_read_pll(enum clock_id clkid, u32 *divm, u32 *divn,
|
|
|
if (!clock_id_is_pll(clkid) || clkid == CLOCK_ID_USB)
|
|
|
return -1;
|
|
|
data = readl(&pll->pll_base);
|
|
|
- *divm = (data & PLL_DIVM_MASK) >> PLL_DIVM_SHIFT;
|
|
|
- *divn = (data & PLL_DIVN_MASK) >> PLL_DIVN_SHIFT;
|
|
|
- *divp = (data & PLL_DIVP_MASK) >> PLL_DIVP_SHIFT;
|
|
|
+ *divm = (data >> pllinfo->m_shift) & pllinfo->m_mask;
|
|
|
+ *divn = (data >> pllinfo->n_shift) & pllinfo->n_mask;
|
|
|
+ *divp = (data >> pllinfo->p_shift) & pllinfo->p_mask;
|
|
|
data = readl(&pll->pll_misc);
|
|
|
- *cpcon = (data & PLL_CPCON_MASK) >> PLL_CPCON_SHIFT;
|
|
|
- *lfcon = (data & PLL_LFCON_MASK) >> PLL_LFCON_SHIFT;
|
|
|
-#if defined(CONFIG_TEGRA210)
|
|
|
- /* T210 PLLU uses KCP/KVCO instead of CPCON/LFCON */
|
|
|
- *cpcon = (data & PLLU_KCP_MASK) >> PLLU_KCP_SHIFT;
|
|
|
- *lfcon = (data & PLLU_KVCO_MASK) >> PLLU_KVCO_SHIFT;
|
|
|
-#endif
|
|
|
+ /* NOTE: On T210, cpcon/lfcon no longer exist, moved to KCP/KVCO */
|
|
|
+ *cpcon = (data >> pllinfo->kcp_shift) & pllinfo->kcp_mask;
|
|
|
+ *lfcon = (data >> pllinfo->kvco_shift) & pllinfo->kvco_mask;
|
|
|
+
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -127,41 +125,25 @@ unsigned long clock_start_pll(enum clock_id clkid, u32 divm, u32 divn,
|
|
|
u32 divp, u32 cpcon, u32 lfcon)
|
|
|
{
|
|
|
struct clk_pll *pll = NULL;
|
|
|
+ struct clk_pll_info *pllinfo = &tegra_pll_info_table[clkid];
|
|
|
u32 misc_data, data;
|
|
|
|
|
|
if (clkid < (enum clock_id)TEGRA_CLK_PLLS)
|
|
|
pll = get_pll(clkid);
|
|
|
|
|
|
/*
|
|
|
- * We cheat by treating all PLL (except PLLU) in the same fashion.
|
|
|
- * This works only because:
|
|
|
- * - same fields are always mapped at same offsets, except DCCON
|
|
|
- * - DCCON is always 0, doesn't conflict
|
|
|
- * - M,N, P of PLLP values are ignored for PLLP
|
|
|
- * NOTE: Above is no longer true with T210 - TBD: FIX THIS
|
|
|
+ * pllinfo has the m/n/p and kcp/kvco mask and shift
|
|
|
+ * values for all of the PLLs used in U-Boot, with any
|
|
|
+ * SoC differences accounted for.
|
|
|
*/
|
|
|
- misc_data = (cpcon << PLL_CPCON_SHIFT) | (lfcon << PLL_LFCON_SHIFT);
|
|
|
-
|
|
|
-#if defined(CONFIG_TEGRA210)
|
|
|
- /* T210 PLLU uses KCP/KVCO instead of cpcon/lfcon */
|
|
|
- if (clkid == CLOCK_ID_USB) {
|
|
|
- /* preserve EN_LOCKDET, set by default */
|
|
|
- misc_data = readl(&pll->pll_misc);
|
|
|
- misc_data |= (cpcon << PLLU_KCP_SHIFT) |
|
|
|
- (lfcon << PLLU_KVCO_SHIFT);
|
|
|
- }
|
|
|
-#endif
|
|
|
- data = (divm << PLL_DIVM_SHIFT) | (divn << PLL_DIVN_SHIFT) |
|
|
|
- (0 << PLL_BYPASS_SHIFT) | (1 << PLL_ENABLE_SHIFT);
|
|
|
-
|
|
|
- if (clkid == CLOCK_ID_USB)
|
|
|
-#if defined(CONFIG_TEGRA210)
|
|
|
- data |= divp << PLLU_DIVP_SHIFT;
|
|
|
-#else
|
|
|
- data |= divp << PLLU_VCO_FREQ_SHIFT;
|
|
|
-#endif
|
|
|
- else
|
|
|
- data |= divp << PLL_DIVP_SHIFT;
|
|
|
+ misc_data = readl(&pll->pll_misc); /* preserve EN_LOCKDET, etc. */
|
|
|
+ misc_data &= ~(pllinfo->kcp_mask << pllinfo->kcp_shift) | (cpcon << pllinfo->kcp_shift);
|
|
|
+ misc_data &= ~(pllinfo->kvco_mask << pllinfo->kvco_shift) | (lfcon << pllinfo->kvco_shift);
|
|
|
+
|
|
|
+ data = (divm << pllinfo->m_shift) | (divn << pllinfo->n_shift);
|
|
|
+ data |= divp << pllinfo->p_shift;
|
|
|
+ data |= (1 << PLL_ENABLE_SHIFT); /* BYPASS s/b 0 already */
|
|
|
+
|
|
|
if (pll) {
|
|
|
writel(misc_data, &pll->pll_misc);
|
|
|
writel(data, &pll->pll_base);
|
|
@@ -473,10 +455,9 @@ void reset_cmplx_set_enable(int cpu, int which, int reset)
|
|
|
unsigned clock_get_rate(enum clock_id clkid)
|
|
|
{
|
|
|
struct clk_pll *pll;
|
|
|
- u32 base;
|
|
|
- u32 divm;
|
|
|
- u64 parent_rate;
|
|
|
- u64 rate;
|
|
|
+ u32 base, divm;
|
|
|
+ u64 parent_rate, rate;
|
|
|
+ struct clk_pll_info *pllinfo = &tegra_pll_info_table[clkid];
|
|
|
|
|
|
parent_rate = osc_freq[clock_get_osc_freq()];
|
|
|
if (clkid == CLOCK_ID_OSC)
|
|
@@ -487,13 +468,13 @@ unsigned clock_get_rate(enum clock_id clkid)
|
|
|
return 0;
|
|
|
base = readl(&pll->pll_base);
|
|
|
|
|
|
- /* Oh for bf_unpack()... */
|
|
|
- rate = parent_rate * ((base & PLL_DIVN_MASK) >> PLL_DIVN_SHIFT);
|
|
|
- divm = (base & PLL_DIVM_MASK) >> PLL_DIVM_SHIFT;
|
|
|
- if (clkid == CLOCK_ID_USB)
|
|
|
- divm <<= (base & PLLU_VCO_FREQ_MASK) >> PLLU_VCO_FREQ_SHIFT;
|
|
|
- else
|
|
|
- divm <<= (base & PLL_DIVP_MASK) >> PLL_DIVP_SHIFT;
|
|
|
+ rate = parent_rate * ((base >> pllinfo->n_shift) & pllinfo->n_mask);
|
|
|
+ divm = (base >> pllinfo->m_shift) & pllinfo->m_mask;
|
|
|
+ /*
|
|
|
+ * PLLU uses p_mask/p_shift for VCO on all but T210,
|
|
|
+ * T210 uses normal DIVP. Handled in pllinfo table.
|
|
|
+ */
|
|
|
+ divm <<= (base >> pllinfo->p_shift) & pllinfo->p_mask;
|
|
|
do_div(rate, divm);
|
|
|
return rate;
|
|
|
}
|
|
@@ -517,23 +498,23 @@ unsigned clock_get_rate(enum clock_id clkid)
|
|
|
*/
|
|
|
int clock_set_rate(enum clock_id clkid, u32 n, u32 m, u32 p, u32 cpcon)
|
|
|
{
|
|
|
- u32 base_reg;
|
|
|
- u32 misc_reg;
|
|
|
+ u32 base_reg, misc_reg;
|
|
|
struct clk_pll *pll;
|
|
|
+ struct clk_pll_info *pllinfo = &tegra_pll_info_table[clkid];
|
|
|
|
|
|
pll = get_pll(clkid);
|
|
|
|
|
|
base_reg = readl(&pll->pll_base);
|
|
|
|
|
|
/* Set BYPASS, m, n and p to PLL_BASE */
|
|
|
- base_reg &= ~PLL_DIVM_MASK;
|
|
|
- base_reg |= m << PLL_DIVM_SHIFT;
|
|
|
+ base_reg &= ~(pllinfo->m_mask << pllinfo->m_shift);
|
|
|
+ base_reg |= m << pllinfo->m_shift;
|
|
|
|
|
|
- base_reg &= ~PLL_DIVN_MASK;
|
|
|
- base_reg |= n << PLL_DIVN_SHIFT;
|
|
|
+ base_reg &= ~(pllinfo->n_mask << pllinfo->n_shift);
|
|
|
+ base_reg |= n << pllinfo->n_shift;
|
|
|
|
|
|
- base_reg &= ~PLL_DIVP_MASK;
|
|
|
- base_reg |= p << PLL_DIVP_SHIFT;
|
|
|
+ base_reg &= ~(pllinfo->p_mask << pllinfo->p_shift);
|
|
|
+ base_reg |= p << pllinfo->p_shift;
|
|
|
|
|
|
if (clkid == CLOCK_ID_PERIPH) {
|
|
|
/*
|
|
@@ -552,17 +533,10 @@ int clock_set_rate(enum clock_id clkid, u32 n, u32 m, u32 p, u32 cpcon)
|
|
|
base_reg |= PLL_BYPASS_MASK;
|
|
|
writel(base_reg, &pll->pll_base);
|
|
|
|
|
|
- /* Set cpcon to PLL_MISC */
|
|
|
+ /* Set cpcon (KCP) to PLL_MISC */
|
|
|
misc_reg = readl(&pll->pll_misc);
|
|
|
-#if !defined(CONFIG_TEGRA210)
|
|
|
- misc_reg &= ~PLL_CPCON_MASK;
|
|
|
- misc_reg |= cpcon << PLL_CPCON_SHIFT;
|
|
|
-#else
|
|
|
- /* T210 uses KCP instead, use the most common bit shift (PLLA/U/D2) */
|
|
|
- misc_reg &= ~PLLU_KCP_MASK;
|
|
|
- misc_reg |= cpcon << PLLU_KCP_SHIFT;
|
|
|
-#endif
|
|
|
-
|
|
|
+ misc_reg &= ~(pllinfo->kcp_mask << pllinfo->kcp_shift);
|
|
|
+ misc_reg |= cpcon << pllinfo->kcp_shift;
|
|
|
writel(misc_reg, &pll->pll_misc);
|
|
|
|
|
|
/* Enable PLL */
|