|
@@ -130,3 +130,180 @@ static __u16 verify_ckctl_value(__u16 newval)
|
|
|
newval |= dspmmu_exp << CKCTL_DSPMMUDIV_OFFSET;
|
|
|
|
|
|
return newval;
|
|
|
+}
|
|
|
+
|
|
|
+static int calc_dsor_exp(struct clk *clk, unsigned long rate)
|
|
|
+{
|
|
|
+ /* Note: If target frequency is too low, this function will return 4,
|
|
|
+ * which is invalid value. Caller must check for this value and act
|
|
|
+ * accordingly.
|
|
|
+ *
|
|
|
+ * Note: This function does not check for following limitations set
|
|
|
+ * by the hardware (all conditions must be true):
|
|
|
+ * DSPMMU_CK == DSP_CK or DSPMMU_CK == DSP_CK/2
|
|
|
+ * ARM_CK >= TC_CK
|
|
|
+ * DSP_CK >= TC_CK
|
|
|
+ * DSPMMU_CK >= TC_CK
|
|
|
+ */
|
|
|
+ unsigned long realrate;
|
|
|
+ struct clk * parent;
|
|
|
+ unsigned dsor_exp;
|
|
|
+
|
|
|
+ parent = clk->parent;
|
|
|
+ if (unlikely(parent == NULL))
|
|
|
+ return -EIO;
|
|
|
+
|
|
|
+ realrate = parent->rate;
|
|
|
+ for (dsor_exp=0; dsor_exp<4; dsor_exp++) {
|
|
|
+ if (realrate <= rate)
|
|
|
+ break;
|
|
|
+
|
|
|
+ realrate /= 2;
|
|
|
+ }
|
|
|
+
|
|
|
+ return dsor_exp;
|
|
|
+}
|
|
|
+
|
|
|
+unsigned long omap1_ckctl_recalc(struct clk *clk)
|
|
|
+{
|
|
|
+ /* Calculate divisor encoded as 2-bit exponent */
|
|
|
+ int dsor = 1 << (3 & (omap_readw(ARM_CKCTL) >> clk->rate_offset));
|
|
|
+
|
|
|
+ return clk->parent->rate / dsor;
|
|
|
+}
|
|
|
+
|
|
|
+unsigned long omap1_ckctl_recalc_dsp_domain(struct clk *clk)
|
|
|
+{
|
|
|
+ int dsor;
|
|
|
+
|
|
|
+ /* Calculate divisor encoded as 2-bit exponent
|
|
|
+ *
|
|
|
+ * The clock control bits are in DSP domain,
|
|
|
+ * so api_ck is needed for access.
|
|
|
+ * Note that DSP_CKCTL virt addr = phys addr, so
|
|
|
+ * we must use __raw_readw() instead of omap_readw().
|
|
|
+ */
|
|
|
+ omap1_clk_enable(api_ck_p);
|
|
|
+ dsor = 1 << (3 & (__raw_readw(DSP_CKCTL) >> clk->rate_offset));
|
|
|
+ omap1_clk_disable(api_ck_p);
|
|
|
+
|
|
|
+ return clk->parent->rate / dsor;
|
|
|
+}
|
|
|
+
|
|
|
+/* MPU virtual clock functions */
|
|
|
+int omap1_select_table_rate(struct clk *clk, unsigned long rate)
|
|
|
+{
|
|
|
+ /* Find the highest supported frequency <= rate and switch to it */
|
|
|
+ struct mpu_rate * ptr;
|
|
|
+ unsigned long ref_rate;
|
|
|
+
|
|
|
+ ref_rate = ck_ref_p->rate;
|
|
|
+
|
|
|
+ for (ptr = omap1_rate_table; ptr->rate; ptr++) {
|
|
|
+ if (!(ptr->flags & cpu_mask))
|
|
|
+ continue;
|
|
|
+
|
|
|
+ if (ptr->xtal != ref_rate)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ /* Can check only after xtal frequency check */
|
|
|
+ if (ptr->rate <= rate)
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!ptr->rate)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * In most cases we should not need to reprogram DPLL.
|
|
|
+ * Reprogramming the DPLL is tricky, it must be done from SRAM.
|
|
|
+ */
|
|
|
+ omap_sram_reprogram_clock(ptr->dpllctl_val, ptr->ckctl_val);
|
|
|
+
|
|
|
+ /* XXX Do we need to recalculate the tree below DPLL1 at this point? */
|
|
|
+ ck_dpll1_p->rate = ptr->pll_rate;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+int omap1_clk_set_rate_dsp_domain(struct clk *clk, unsigned long rate)
|
|
|
+{
|
|
|
+ int dsor_exp;
|
|
|
+ u16 regval;
|
|
|
+
|
|
|
+ dsor_exp = calc_dsor_exp(clk, rate);
|
|
|
+ if (dsor_exp > 3)
|
|
|
+ dsor_exp = -EINVAL;
|
|
|
+ if (dsor_exp < 0)
|
|
|
+ return dsor_exp;
|
|
|
+
|
|
|
+ regval = __raw_readw(DSP_CKCTL);
|
|
|
+ regval &= ~(3 << clk->rate_offset);
|
|
|
+ regval |= dsor_exp << clk->rate_offset;
|
|
|
+ __raw_writew(regval, DSP_CKCTL);
|
|
|
+ clk->rate = clk->parent->rate / (1 << dsor_exp);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+long omap1_clk_round_rate_ckctl_arm(struct clk *clk, unsigned long rate)
|
|
|
+{
|
|
|
+ int dsor_exp = calc_dsor_exp(clk, rate);
|
|
|
+ if (dsor_exp < 0)
|
|
|
+ return dsor_exp;
|
|
|
+ if (dsor_exp > 3)
|
|
|
+ dsor_exp = 3;
|
|
|
+ return clk->parent->rate / (1 << dsor_exp);
|
|
|
+}
|
|
|
+
|
|
|
+int omap1_clk_set_rate_ckctl_arm(struct clk *clk, unsigned long rate)
|
|
|
+{
|
|
|
+ int dsor_exp;
|
|
|
+ u16 regval;
|
|
|
+
|
|
|
+ dsor_exp = calc_dsor_exp(clk, rate);
|
|
|
+ if (dsor_exp > 3)
|
|
|
+ dsor_exp = -EINVAL;
|
|
|
+ if (dsor_exp < 0)
|
|
|
+ return dsor_exp;
|
|
|
+
|
|
|
+ regval = omap_readw(ARM_CKCTL);
|
|
|
+ regval &= ~(3 << clk->rate_offset);
|
|
|
+ regval |= dsor_exp << clk->rate_offset;
|
|
|
+ regval = verify_ckctl_value(regval);
|
|
|
+ omap_writew(regval, ARM_CKCTL);
|
|
|
+ clk->rate = clk->parent->rate / (1 << dsor_exp);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+long omap1_round_to_table_rate(struct clk *clk, unsigned long rate)
|
|
|
+{
|
|
|
+ /* Find the highest supported frequency <= rate */
|
|
|
+ struct mpu_rate * ptr;
|
|
|
+ long highest_rate;
|
|
|
+ unsigned long ref_rate;
|
|
|
+
|
|
|
+ ref_rate = ck_ref_p->rate;
|
|
|
+
|
|
|
+ highest_rate = -EINVAL;
|
|
|
+
|
|
|
+ for (ptr = omap1_rate_table; ptr->rate; ptr++) {
|
|
|
+ if (!(ptr->flags & cpu_mask))
|
|
|
+ continue;
|
|
|
+
|
|
|
+ if (ptr->xtal != ref_rate)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ highest_rate = ptr->rate;
|
|
|
+
|
|
|
+ /* Can check only after xtal frequency check */
|
|
|
+ if (ptr->rate <= rate)
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ return highest_rate;
|
|
|
+}
|
|
|
+
|
|
|
+static unsigned calc_ext_dsor(unsigned long rate)
|
|
|
+{
|
|
|
+ unsigned dsor;
|