if (iclk->no_idle_count++ == 0)
arm_idlect1_mask &= ~(1 << iclk->idlect_shift);
}
static __u16 verify_ckctl_value(__u16 newval)
{ /* This function checks 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 * * In addition following rules are enforced: * LCD_CK <= TC_CK * ARMPER_CK <= TC_CK * * However, maximum frequencies are not checked for!
*/
__u8 per_exp;
__u8 lcd_exp;
__u8 arm_exp;
__u8 dsp_exp;
__u8 tc_exp;
__u8 dspmmu_exp;
staticint calc_dsor_exp(unsignedlong rate, unsignedlong realrate)
{ /* 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 dsor_exp;
if (unlikely(realrate == 0)) return -EIO;
for (dsor_exp=0; dsor_exp<4; dsor_exp++) { if (realrate <= rate) break;
/* 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().
*/
api_ck_was_enabled = omap1_clk_is_enabled(&api_ck_p->hw); if (!api_ck_was_enabled)
api_ck_p->ops->enable(api_ck_p);
dsor = 1 << (3 & (__raw_readw(DSP_CKCTL) >> clk->rate_offset)); if (!api_ck_was_enabled)
api_ck_p->ops->disable(api_ck_p);
return p_rate / dsor;
}
/* MPU virtual clock functions */ int omap1_select_table_rate(struct omap1_clk *clk, unsignedlong rate, unsignedlong p_rate)
{ /* Find the highest supported frequency <= rate and switch to it */ struct mpu_rate * ptr; unsignedlong 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 omap1_clk *clk, unsignedlong rate, unsignedlong p_rate)
{ int dsor_exp;
u16 regval;
dsor_exp = calc_dsor_exp(rate, p_rate); if (dsor_exp > 3)
dsor_exp = -EINVAL; if (dsor_exp < 0) return dsor_exp;
int omap1_init_ext_clk(struct omap1_clk *clk)
{ unsigned dsor;
__u16 ratio_bits;
/* Determine current rate and ensure clock is based on 96MHz APLL */
ratio_bits = __raw_readw(clk->enable_reg) & ~1;
__raw_writew(ratio_bits, clk->enable_reg);
/* XXX SYSC register handling does not belong in the clock framework */ staticint omap1_clk_enable_uart_functional_16xx(struct omap1_clk *clk)
{ int ret; struct uart_clk *uclk;
ret = omap1_clk_enable_generic(clk); if (ret == 0) { /* Set smart idle acknowledgement mode */
uclk = (struct uart_clk *)clk;
omap_writeb((omap_readb(uclk->sysc_addr) & ~0x10) | 8,
uclk->sysc_addr);
}
return ret;
}
/* XXX SYSC register handling does not belong in the clock framework */ staticvoid omap1_clk_disable_uart_functional_16xx(struct omap1_clk *clk)
{ struct uart_clk *uclk;
/* Set force idle acknowledgement mode */
uclk = (struct uart_clk *)clk;
omap_writeb((omap_readb(uclk->sysc_addr) & ~0x18), uclk->sysc_addr);
omap1_clk_disable_generic(clk);
}
/* XXX SYSC register handling does not belong in the clock framework */ conststruct clkops clkops_uart_16xx = {
.enable = omap1_clk_enable_uart_functional_16xx,
.disable = omap1_clk_disable_uart_functional_16xx,
};
/* Clocks in the DSP domain need api_ck. Just assume bootloader
* has not enabled any DSP clocks */ if (clk->enable_reg == DSP_IDLECT2) {
pr_info("Skipping reset check for DSP domain clock \"%s\"\n", name); return;
}
/* * OMAP specific clock functions shared between omap1 and omap2
*/
/* Used for clocks that always have same value as the parent clock */ unsignedlong followparent_recalc(struct omap1_clk *clk, unsignedlong p_rate)
{ return p_rate;
}
/* * Used for clocks that have the same value as the parent clock, * divided by some factor
*/ unsignedlong omap_fixed_divisor_recalc(struct omap1_clk *clk, unsignedlong p_rate)
{
WARN_ON(!clk->fixed_div);
return p_rate / clk->fixed_div;
}
/* Propagate rate to children */ void propagate_rate(struct omap1_clk *tclk)
{ struct clk *clkp;
/* depend on CCF ability to recalculate new rates across whole clock subtree */ if (WARN_ON(!(clk_hw_get_flags(&tclk->hw) & CLK_GET_RATE_NOCACHE))) return;
clkp = clk_get_sys(NULL, clk_hw_get_name(&tclk->hw)); if (WARN_ON(!clkp)) return;
clk_get_rate(clkp);
clk_put(clkp);
}
conststruct clk_ops omap1_clk_null_ops = {
};
/* * Dummy clock * * Used for clock aliases that are needed on some OMAPs, but not others
*/ struct omap1_clk dummy_ck __refdata = {
.hw.init = CLK_HW_INIT_NO_PARENT("dummy", &omap1_clk_null_ops, 0),
};
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.