@@ -679,6 +679,41 @@ static void omap3_noncore_dpll_disable(struct clk *clk)
_omap3_noncore_dpll_stop(clk);
}
+/**
+ * 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
+ */
+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;
+}
/* Non-CORE DPLL rate set code */
@@ -711,6 +746,13 @@ 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);
+ if (dd->jtype) {
+ u8 dco, sd_div;
+ lookup_dco_sddiv(clk, &dco, &sd_div, m, n);
+ v &= ~(dd->dco_sel_mask | dd->sd_div_mask);
+ v |= dco << __ffs(dd->dco_sel_mask);
+ v |= sd_div << __ffs(dd->sd_div_mask);
+ }
__raw_writel(v, dd->mult_div1_reg);
/* We let the clock framework set the other output dividers later */
@@ -1026,7 +1068,7 @@ static 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->jtype))
rate = clk->parent->rate;
else
rate = clk->parent->rate * 2;
@@ -1174,6 +1216,13 @@ int __init omap2_clk_init(void)
cpu_mask |= RATE_IN_3430ES2;
cpu_clkflg |= CK_3430ES2;
}
+ if (omap3_has_jtype_dpll4()) {
+ dpll4_ck.dpll_data->jtype = 1;
+ dpll4_ck.dpll_data->dco_sel_mask =
+ OMAP3630_PERIPH_DPLL_DCO_SEL_MASK;
+ dpll4_ck.dpll_data->sd_div_mask =
+ OMAP3630_PERIPH_DPLL_SD_DIV_MASK;
+ }
}
clk_init(&omap2_clk_functions);
@@ -516,9 +516,13 @@
/* CM_CLKSEL2_PLL */
#define OMAP3430_PERIPH_DPLL_MULT_SHIFT 8
-#define OMAP3430_PERIPH_DPLL_MULT_MASK (0x7ff << 8)
+#define OMAP3430_PERIPH_DPLL_MULT_MASK (0xfff << 8)
#define OMAP3430_PERIPH_DPLL_DIV_SHIFT 0
#define OMAP3430_PERIPH_DPLL_DIV_MASK (0x7f << 0)
+#define OMAP3630_PERIPH_DPLL_DCO_SEL_SHIFT 21
+#define OMAP3630_PERIPH_DPLL_DCO_SEL_MASK (0x7 << 21)
+#define OMAP3630_PERIPH_DPLL_SD_DIV_SHIFT 24
+#define OMAP3630_PERIPH_DPLL_SD_DIV_MASK (0xff << 24)
/* CM_CLKSEL3_PLL */
#define OMAP3430_DIV_96M_SHIFT 0
@@ -176,6 +176,8 @@ void __init omap3_check_features(void)
OMAP3_CHECK_FEATURE(status, NEON);
OMAP3_CHECK_FEATURE(status, ISP);
+ if (cpu_is_omap3630())
+ omap3_features |= OMAP3_HAS_JTYPE_DPLL4;
/*
* TODO: Get additional info (where applicable)
* e.g. Size of L2 cache.
@@ -316,7 +318,7 @@ void __init omap3_cpuinfo(void)
OMAP3_SHOW_FEATURE(sgx);
OMAP3_SHOW_FEATURE(neon);
OMAP3_SHOW_FEATURE(isp);
-
+ OMAP3_SHOW_FEATURE(jtype_dpll4);
printk(")\n");
}
@@ -60,6 +60,9 @@ struct dpll_data {
void __iomem *idlest_reg;
u32 autoidle_mask;
u32 freqsel_mask;
+ u32 dco_sel_mask;
+ u32 sd_div_mask;
+ u8 jtype;
u32 idlest_mask;
u8 auto_recal_bit;
u8 recal_en_bit;
@@ -497,6 +497,7 @@ extern u32 omap3_features;
#define OMAP3_HAS_SGX BIT(2)
#define OMAP3_HAS_NEON BIT(3)
#define OMAP3_HAS_ISP BIT(4)
+#define OMAP3_HAS_JTYPE_DPLL4 BIT(5)
#define OMAP3_HAS_FEATURE(feat,flag) \
static inline unsigned int omap3_has_ ##feat(void) \
@@ -509,5 +510,5 @@ OMAP3_HAS_FEATURE(sgx, SGX)
OMAP3_HAS_FEATURE(iva, IVA)
OMAP3_HAS_FEATURE(neon, NEON)
OMAP3_HAS_FEATURE(isp, ISP)
-
+OMAP3_HAS_FEATURE(jtype_dpll4, JTYPE_DPLL4)
#endif