|
@@ -1,11 +1,14 @@
|
|
|
/*
|
|
|
* OMAP3/4 - specific DPLL control functions
|
|
|
*
|
|
|
- * Copyright (C) 2009 Texas Instruments, Inc.
|
|
|
- * Copyright (C) 2009 Nokia Corporation
|
|
|
+ * Copyright (C) 2009-2010 Texas Instruments, Inc.
|
|
|
+ * Copyright (C) 2009-2010 Nokia Corporation
|
|
|
*
|
|
|
* Written by Paul Walmsley
|
|
|
- * Testing and integration fixes by Jouni Högander
|
|
|
+ * Testing and integration fixes by Jouni Högander
|
|
|
+ *
|
|
|
+ * 36xx support added by Vishwanath BS, Richard Woodruff, and Nishanth
|
|
|
+ * Menon
|
|
|
*
|
|
|
* Parts of this code are based on code written by
|
|
|
* Richard Woodruff, Tony Lindgren, Tuukka Tikkanen, Karthik Dasu
|
|
@@ -225,6 +228,47 @@ static int _omap3_noncore_dpll_stop(struct clk *clk)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * lookup_dco_sddiv - Set j-type DPLL4 compensation variables
|
|
|
+ * @clk: pointer to a DPLL struct clk
|
|
|
+ * @dco: digital control oscillator selector
|
|
|
+ * @sd_div: target sigma-delta divider
|
|
|
+ * @m: DPLL multiplier to set
|
|
|
+ * @n: DPLL divider to set
|
|
|
+ *
|
|
|
+ * See 36xx TRM section 3.5.3.3.3.2 "Type B DPLL (Low-Jitter)"
|
|
|
+ *
|
|
|
+ * XXX This code is not needed for 3430/AM35xx; can it be optimized
|
|
|
+ * out in non-multi-OMAP builds for those chips?
|
|
|
+ */
|
|
|
+static void lookup_dco_sddiv(struct clk *clk, u8 *dco, u8 *sd_div, u16 m,
|
|
|
+ u8 n)
|
|
|
+{
|
|
|
+ unsigned long fint, clkinp, sd; /* watch out for overflow */
|
|
|
+ int mod1, mod2;
|
|
|
+
|
|
|
+ clkinp = clk->parent->rate;
|
|
|
+ fint = (clkinp / n) * m;
|
|
|
+
|
|
|
+ if (fint < 1000000000)
|
|
|
+ *dco = 2;
|
|
|
+ else
|
|
|
+ *dco = 4;
|
|
|
+ /*
|
|
|
+ * target sigma-delta to near 250MHz
|
|
|
+ * sd = ceil[(m/(n+1)) * (clkinp_MHz / 250)]
|
|
|
+ */
|
|
|
+ clkinp /= 100000; /* shift from MHz to 10*Hz for 38.4 and 19.2 */
|
|
|
+ mod1 = (clkinp * m) % (250 * n);
|
|
|
+ sd = (clkinp * m) / (250 * n);
|
|
|
+ mod2 = sd % 10;
|
|
|
+ sd /= 10;
|
|
|
+
|
|
|
+ if (mod1 || mod2)
|
|
|
+ sd++;
|
|
|
+ *sd_div = sd;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* _omap3_noncore_dpll_program - set non-core DPLL M,N values directly
|
|
|
* @clk: struct clk * of DPLL to set
|
|
@@ -259,6 +303,21 @@ static int omap3_noncore_dpll_program(struct clk *clk, u16 m, u8 n, u16 freqsel)
|
|
|
v &= ~(dd->mult_mask | dd->div1_mask);
|
|
|
v |= m << __ffs(dd->mult_mask);
|
|
|
v |= (n - 1) << __ffs(dd->div1_mask);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * XXX This code is not needed for 3430/AM35XX; can it be optimized
|
|
|
+ * out in non-multi-OMAP builds for those chips?
|
|
|
+ */
|
|
|
+ if ((dd->flags & DPLL_J_TYPE) && !(dd->flags & DPLL_NO_DCO_SEL)) {
|
|
|
+ u8 dco, sd_div;
|
|
|
+ lookup_dco_sddiv(clk, &dco, &sd_div, m, n);
|
|
|
+ /* XXX This probably will need revision for OMAP4 */
|
|
|
+ v &= ~(OMAP3630_PERIPH_DPLL_DCO_SEL_MASK
|
|
|
+ | OMAP3630_PERIPH_DPLL_SD_DIV_MASK);
|
|
|
+ v |= dco << __ffs(OMAP3630_PERIPH_DPLL_DCO_SEL_MASK);
|
|
|
+ v |= sd_div << __ffs(OMAP3630_PERIPH_DPLL_SD_DIV_MASK);
|
|
|
+ }
|
|
|
+
|
|
|
__raw_writel(v, dd->mult_div1_reg);
|
|
|
|
|
|
/* We let the clock framework set the other output dividers later */
|
|
@@ -536,7 +595,7 @@ unsigned long omap3_clkoutx2_recalc(struct clk *clk)
|
|
|
|
|
|
v = __raw_readl(dd->control_reg) & dd->enable_mask;
|
|
|
v >>= __ffs(dd->enable_mask);
|
|
|
- if (v != OMAP3XXX_EN_DPLL_LOCKED)
|
|
|
+ if ((v != OMAP3XXX_EN_DPLL_LOCKED) || (dd->flags & DPLL_J_TYPE))
|
|
|
rate = clk->parent->rate;
|
|
|
else
|
|
|
rate = clk->parent->rate * 2;
|