Ejemplo n.º 1
0
/**
 * omap3_noncore_dpll_enable - instruct a DPLL to enter bypass or lock mode
 * @clk: pointer to a DPLL struct clk
 *
 * Instructs a non-CORE DPLL to enable, e.g., to enter bypass or lock.
 * The choice of modes depends on the DPLL's programmed rate: if it is
 * the same as the DPLL's parent clock, it will enter bypass;
 * otherwise, it will enter lock.  This code will wait for the DPLL to
 * indicate readiness before returning, unless the DPLL takes too long
 * to enter the target state.  Intended to be used as the struct clk's
 * enable function.  If DPLL3 was passed in, or the DPLL does not
 * support low-power stop, or if the DPLL took too long to enter
 * bypass or lock, return -EINVAL; otherwise, return 0.
 */
int omap3_noncore_dpll_enable(struct clk *clk)
{
	int r;
	struct dpll_data *dd;

	dd = clk->dpll_data;
	if (!dd)
		return -EINVAL;

	if (clk->rate == dd->clk_bypass->rate) {
		WARN_ON(clk->parent != dd->clk_bypass);
		r = _omap3_noncore_dpll_bypass(clk);
	} else {
		WARN_ON(clk->parent != dd->clk_ref);
		r = _omap3_noncore_dpll_lock(clk);
	}
	/*
	 *FIXME: this is dubious - if clk->rate has changed, what about
	 * propagating?
	 */
	if (!r)
		clk->rate = omap2_get_dpll_rate(clk);

	return r;
}
/**
 * omap3_noncore_dpll_enable - instruct a DPLL to enter bypass or lock mode
 * @clk: pointer to a DPLL struct clk
 *
 * Instructs a non-CORE DPLL to enable, e.g., to enter bypass or lock.
 * The choice of modes depends on the DPLL's programmed rate: if it is
 * the same as the DPLL's parent clock, it will enter bypass;
 * otherwise, it will enter lock.  This code will wait for the DPLL to
 * indicate readiness before returning, unless the DPLL takes too long
 * to enter the target state.  Intended to be used as the struct clk's
 * enable function.  If DPLL3 was passed in, or the DPLL does not
 * support low-power stop, or if the DPLL took too long to enter
 * bypass or lock, return -EINVAL; otherwise, return 0.
 */
static int omap3_noncore_dpll_enable(struct clk *clk)
{
	int r;
	struct dpll_data *dd;

	if (clk == &dpll3_ck)
		return -EINVAL;

	dd = clk->dpll_data;
	if (!dd)
		return -EINVAL;
	/*
	 * Ensure M/N register is confgured before
	 * Enable it, otherwise DPLL will fail to lock
	 */
	if (clk->rate == 0) {
		WARN_ON(dd->default_rate == 0);
		r = omap3_noncore_dpll_set_rate(clk, dd->default_rate);
		if (r)
			return r;
	}

	if (clk->rate == dd->clk_bypass->rate) {
		WARN_ON(clk->parent != dd->clk_bypass);
		r = _omap3_noncore_dpll_bypass(clk);
	} else {
		WARN_ON(clk->parent != dd->clk_ref);
		r = _omap3_noncore_dpll_lock(clk);
	}
	/* FIXME: this is dubious - if clk->rate has changed, what about propagating? */
	if (!r)
		clk->rate = omap2_get_dpll_rate(clk);

	return r;
}
Ejemplo n.º 3
0
static int omap3_noncore_dpll_enable(struct clk *clk)
{
	int r;
	struct dpll_data *dd;

	if (clk == &dpll3_ck)
		return -EINVAL;

	dd = clk->dpll_data;
	if (!dd)
		return -EINVAL;

	if (clk->rate == dd->clk_bypass->rate) {
		WARN_ON(clk->parent != dd->clk_bypass);
		r = _omap3_noncore_dpll_bypass(clk);
	} else {
		WARN_ON(clk->parent != dd->clk_ref);
		r = _omap3_noncore_dpll_lock(clk);
	}
	
	if (!r)
		clk->rate = omap2_get_dpll_rate(clk);

	return r;
}
unsigned long omap4460_mpu_dpll_recalc(struct clk *clk)
{
    struct dpll_data *dd;
    u32 v;

    if (!clk || !clk->parent)
        return -EINVAL;

    dd = clk->parent->dpll_data;

    if (!dd)
        return -EINVAL;

    v = __raw_readl(dd->mult_div1_reg);
    if (v & OMAP4460_DCC_EN_MASK)
        return omap2_get_dpll_rate(clk->parent) * 2;
    else
        return omap2_get_dpll_rate(clk->parent);
}
Ejemplo n.º 5
0
/**
 * omap3_dpll_recalc - recalculate DPLL rate
 * @clk: DPLL struct clk
 * @parent_rate: rate of the DPLL's parent clock
 * @rate_storage: flag indicating whether current or temporary rate is changing
 *
 * Recalculate and propagate the DPLL rate.
 */
static void omap3_dpll_recalc(struct clk *clk, unsigned long parent_rate,
			      u8 rate_storage)
{
	unsigned long rate;

	rate = omap2_get_dpll_rate(clk, parent_rate);

	if (rate_storage == CURRENT_RATE)
		clk->rate = rate;
	else if (rate_storage == TEMP_RATE)
		clk->temp_rate = rate;
}
Ejemplo n.º 6
0
/* This actually returns the rate of core_ck, not dpll_ck. */
static u32 omap2_get_dpll_rate_24xx(struct clk *tclk)
{
    long long dpll_clk;
    u8 amult;

    dpll_clk = omap2_get_dpll_rate(tclk);

    amult = cm_read_mod_reg(PLL_MOD, CM_CLKSEL2);
    amult &= OMAP24XX_CORE_CLK_SRC_MASK;
    dpll_clk *= amult;

    return dpll_clk;
}
Ejemplo n.º 7
0
/**
 * omap3_noncore_dpll_set_rate - set non-core DPLL rate
 * @clk: struct clk * of DPLL to set
 * @rate: rounded target rate
 *
 * Set the DPLL CLKOUT to the target rate.  If the DPLL can enter
 * low-power bypass, and the target rate is the bypass source clock
 * rate, then configure the DPLL for bypass.  Otherwise, round the
 * target rate if it hasn't been done already, then program and lock
 * the DPLL.  Returns -EINVAL upon error, or 0 upon success.
 */
static int omap3_noncore_dpll_set_rate(struct clk *clk, unsigned long rate)
{
	u16 freqsel;
	struct dpll_data *dd;
	int ret;

	if (!clk || !rate)
		return -EINVAL;

	dd = clk->dpll_data;
	if (!dd)
		return -EINVAL;

	if (rate == omap2_get_dpll_rate(clk, clk->parent->rate))
		return 0;

	if (dd->bypass_clk->rate == rate &&
	    (clk->dpll_data->modes & (1 << DPLL_LOW_POWER_BYPASS))) {

		pr_debug("clock: %s: set rate: entering bypass.\n", clk->name);

		ret = _omap3_noncore_dpll_bypass(clk);
		if (!ret)
			clk->rate = rate;

	} else {

		if (dd->last_rounded_rate != rate)
			omap2_dpll_round_rate(clk, rate);

		if (dd->last_rounded_rate == 0)
			return -EINVAL;

		freqsel = _omap3_dpll_compute_freqsel(clk, dd->last_rounded_n);
		if (!freqsel)
			WARN_ON(1);

		pr_debug("clock: %s: set rate: locking rate to %lu.\n",
			 clk->name, rate);

		ret = omap3_noncore_dpll_program(clk, dd->last_rounded_m,
						 dd->last_rounded_n, freqsel);

		if (!ret)
			clk->rate = rate;

	}

	return 0;
}
/**
 * omap2xxx_clk_get_core_rate - return the CORE_CLK rate
 * @clk: pointer to the combined dpll_ck + core_ck (currently "dpll_ck")
 *
 * Returns the CORE_CLK rate.  CORE_CLK can have one of three rate
 * sources on OMAP2xxx: the DPLL CLKOUT rate, DPLL CLKOUTX2, or 32KHz
 * (the latter is unusual).  This currently should be called with
 * struct clk *dpll_ck, which is a composite clock of dpll_ck and
 * core_ck.
 */
unsigned long omap2xxx_clk_get_core_rate(struct clk *clk)
{
	long long core_clk;
	u32 v;

	core_clk = omap2_get_dpll_rate(clk);

	v = omap2_cm_read_mod_reg(PLL_MOD, CM_CLKSEL2);
	v &= OMAP24XX_CORE_CLK_SRC_MASK;

	if (v == CORE_CLK_SRC_32K)
		core_clk = 32768;
	else
		core_clk *= v;

	return core_clk;
}
Ejemplo n.º 9
0
/**
 * omap2xxx_clk_get_core_rate - return the CORE_CLK rate
 *
 * Returns the CORE_CLK rate.  CORE_CLK can have one of three rate
 * sources on OMAP2xxx: the DPLL CLKOUT rate, DPLL CLKOUTX2, or 32KHz
 * (the latter is unusual).  This currently should be called with
 * struct clk *dpll_ck, which is a composite clock of dpll_ck and
 * core_ck.
 */
unsigned long omap2xxx_clk_get_core_rate(void)
{
	long long core_clk;
	u32 v;

	WARN_ON(!dpll_core_ck);

	core_clk = omap2_get_dpll_rate(dpll_core_ck);

	v = omap2xxx_cm_get_core_clk_src();

	if (v == CORE_CLK_SRC_32K)
		core_clk = 32768;
	else
		core_clk *= v;

	return core_clk;
}
Ejemplo n.º 10
0
/**
 * omap4_dpll_regm4xen_recalc - compute DPLL rate, considering REGM4XEN bit
 * @clk: struct clk * of the DPLL to compute the rate for
 *
 * Compute the output rate for the OMAP4 DPLL represented by @clk.
 * Takes the REGM4XEN bit into consideration, which is needed for the
 * OMAP4 ABE DPLL.  Returns the DPLL's output rate (before M-dividers)
 * upon success, or 0 upon error.
 */
unsigned long omap4_dpll_regm4xen_recalc(struct clk *clk)
{
	u32 v;
	unsigned long rate;
	struct dpll_data *dd;

	if (!clk || !clk->dpll_data)
		return 0;

	dd = clk->dpll_data;

	rate = omap2_get_dpll_rate(clk);

	/* regm4xen adds a multiplier of 4 to DPLL calculations */
	v = __raw_readl(dd->control_reg);
	if (v & OMAP4430_DPLL_REGM4XEN_MASK)
		rate *= OMAP4430_REGM4XEN_MULT;

	return rate;
}
Ejemplo n.º 11
0
unsigned long omap4_dpll_regm4xen_recalc(struct clk *clk)
{
	unsigned long rate;
	u32 reg;
	struct dpll_data *dd;

	if (!clk || !clk->dpll_data)
		return -EINVAL;

	dd = clk->dpll_data;

	rate = omap2_get_dpll_rate(clk);

	/* regm4xen adds a multiplier of 4 to DPLL calculations */
	reg = __raw_readl(dd->control_reg);
	if (reg & (DPLL_REGM4XEN_ENABLE << OMAP4430_DPLL_REGM4XEN_SHIFT))
		rate *= OMAP4430_REGM4XEN_MULT;

	return rate;
}
Ejemplo n.º 12
0
/**
 * omap4_dpll_regm4xen_recalc - compute DPLL rate, considering REGM4XEN bit
 * @clk: struct clk * of the DPLL to compute the rate for
 *
 * Compute the output rate for the OMAP4 DPLL represented by @clk.
 * Takes the REGM4XEN bit into consideration, which is needed for the
 * OMAP4 ABE DPLL.  Returns the DPLL's output rate (before M-dividers)
 * upon success, or 0 upon error.
 */
unsigned long omap4_dpll_regm4xen_recalc(struct clk_hw *hw,
					 unsigned long parent_rate)
{
	struct clk_hw_omap *clk = to_clk_hw_omap(hw);
	u32 v;
	unsigned long rate;
	struct dpll_data *dd;

	if (!clk || !clk->dpll_data)
		return 0;

	dd = clk->dpll_data;

	rate = omap2_get_dpll_rate(clk);

	/* regm4xen adds a multiplier of 4 to DPLL calculations */
	v = ti_clk_ll_ops->clk_readl(dd->control_reg);
	if (v & OMAP4430_DPLL_REGM4XEN_MASK)
		rate *= OMAP4430_REGM4XEN_MULT;

	return rate;
}
Ejemplo n.º 13
0
/**
 * omap3_dpll_recalc - recalculate DPLL rate
 * @clk: DPLL struct clk
 *
 * Recalculate and propagate the DPLL rate.
 */
static void omap3_dpll_recalc(struct clk *clk)
{
    clk->rate = omap2_get_dpll_rate(clk);

    propagate_rate(clk);
}
Ejemplo n.º 14
0
/**
 * omap3_dpll_recalc - recalculate DPLL rate
 * @clk: DPLL struct clk
 *
 * Recalculate and propagate the DPLL rate.
 */
unsigned long omap3_dpll_recalc(struct clk_hw *hw, unsigned long parent_rate)
{
	struct clk_hw_omap *clk = to_clk_hw_omap(hw);

	return omap2_get_dpll_rate(clk);
}
Ejemplo n.º 15
0
/**
 * omap3_noncore_dpll_set_rate - set non-core DPLL rate
 * @clk: struct clk * of DPLL to set
 * @rate: rounded target rate
 *
 * Set the DPLL CLKOUT to the target rate.  If the DPLL can enter
 * low-power bypass, and the target rate is the bypass source clock
 * rate, then configure the DPLL for bypass.  Otherwise, round the
 * target rate if it hasn't been done already, then program and lock
 * the DPLL.  Returns -EINVAL upon error, or 0 upon success.
 */
int omap3_noncore_dpll_set_rate(struct clk *clk, unsigned long rate)
{
	struct clk *new_parent = NULL;
	u16 freqsel = 0;
	struct dpll_data *dd;
	int ret;
	unsigned long orig_rate = 0;

	if (!clk || !rate)
		return -EINVAL;

	dd = clk->dpll_data;
	if (!dd)
		return -EINVAL;

	if (rate == omap2_get_dpll_rate(clk))
		return 0;

	/*
	 * Ensure both the bypass and ref clocks are enabled prior to
	 * doing anything; we need the bypass clock running to reprogram
	 * the DPLL.
	 */
	omap2_clk_enable(dd->clk_bypass);
	omap2_clk_enable(dd->clk_ref);

	if (dd->clk_bypass->rate == rate &&
	    (clk->dpll_data->modes & (1 << DPLL_LOW_POWER_BYPASS))) {
		pr_debug("clock: %s: set rate: entering bypass.\n", clk->name);

		ret = _omap3_noncore_dpll_bypass(clk);
		if (!ret)
			new_parent = dd->clk_bypass;
	} else {
		/*
		 * On 4460, the MPU clk for frequencies higher than 1Ghz
		 * is sourced from CLKOUTX2_M3, instead of CLKOUT_M2, while
		 * value of M3 is fixed to 1. Hence for frequencies higher
		 * than 1 Ghz, lock the DPLL at half the rate so the
		 * CLKOUTX2_M3 then matches the requested rate.
		 */
		if (cpu_is_omap4460() && !strcmp(clk->name, "dpll_mpu_ck")
					&& (rate > 1000000000)) {
			orig_rate = rate;
			rate = rate/2;
		}
		if (dd->last_rounded_rate != rate)
			rate = clk->round_rate(clk, rate);

		if (dd->last_rounded_rate == 0)
			return -EINVAL;

		/* No freqsel on OMAP4 and OMAP3630 */
		if (!cpu_is_omap44xx() && !cpu_is_omap3630()) {
			freqsel = _omap3_dpll_compute_freqsel(clk,
						dd->last_rounded_n);
			if (!freqsel)
				WARN_ON(1);
		}

		/* Set the rate back to original for book keeping*/
		if (orig_rate)
			rate = orig_rate;
		pr_debug("clock: %s: set rate: locking rate to %lu.\n",
			 clk->name, rate);

		ret = omap3_noncore_dpll_program(clk, dd->last_rounded_m,
				 dd->last_rounded_n, freqsel, orig_rate);
		if (!ret)
			new_parent = dd->clk_ref;
	}
	if (!ret) {
		/*
		 * Switch the parent clock in the heirarchy, and make sure
		 * that the new parent's usecount is correct.  Note: we
		 * enable the new parent before disabling the old to avoid
		 * any unnecessary hardware disable->enable transitions.
		 */
		if (clk->usecount) {
			omap2_clk_enable(new_parent);
			omap2_clk_disable(clk->parent);
		}
		clk_reparent(clk, new_parent);
		clk->rate = rate;
	}
	omap2_clk_disable(dd->clk_ref);
	omap2_clk_disable(dd->clk_bypass);

	return 0;
}
Ejemplo n.º 16
0
/**
 * omap3_dpll_recalc - recalculate DPLL rate
 * @clk: DPLL struct clk
 *
 * Recalculate and propagate the DPLL rate.
 */
unsigned long omap3_dpll_recalc(struct clk *clk)
{
	return omap2_get_dpll_rate(clk);
}
Ejemplo n.º 17
0
static int omap3_noncore_dpll_set_rate(struct clk *clk, unsigned long rate)
{
	struct clk *new_parent = NULL;
	u16 freqsel;
	struct dpll_data *dd;
	int ret;

	if (!clk || !rate)
		return -EINVAL;

	dd = clk->dpll_data;
	if (!dd)
		return -EINVAL;

	if (rate == omap2_get_dpll_rate(clk))
		return 0;

	
	omap2_clk_enable(dd->clk_bypass);
	omap2_clk_enable(dd->clk_ref);

	if (dd->clk_bypass->rate == rate &&
	    (clk->dpll_data->modes & (1 << DPLL_LOW_POWER_BYPASS))) {
		pr_debug("clock: %s: set rate: entering bypass.\n", clk->name);

		ret = _omap3_noncore_dpll_bypass(clk);
		if (!ret)
			new_parent = dd->clk_bypass;
	} else {
		if (dd->last_rounded_rate != rate)
			omap2_dpll_round_rate(clk, rate);

		if (dd->last_rounded_rate == 0)
			return -EINVAL;

		freqsel = _omap3_dpll_compute_freqsel(clk, dd->last_rounded_n);
		if (!freqsel)
			WARN_ON(1);

		pr_debug("clock: %s: set rate: locking rate to %lu.\n",
			 clk->name, rate);

		ret = omap3_noncore_dpll_program(clk, dd->last_rounded_m,
						 dd->last_rounded_n, freqsel);
		if (!ret)
			new_parent = dd->clk_ref;
	}
	if (!ret) {
		
		if (clk->usecount) {
			omap2_clk_enable(new_parent);
			omap2_clk_disable(clk->parent);
		}
		clk_reparent(clk, new_parent);
		clk->rate = rate;
	}
	omap2_clk_disable(dd->clk_ref);
	omap2_clk_disable(dd->clk_bypass);

	return 0;
}
Ejemplo n.º 18
0
/**
 * omap3_noncore_dpll_set_rate - set non-core DPLL rate
 * @clk: struct clk * of DPLL to set
 * @rate: rounded target rate
 *
 * Set the DPLL CLKOUT to the target rate.  If the DPLL can enter
 * low-power bypass, and the target rate is the bypass source clock
 * rate, then configure the DPLL for bypass.  Otherwise, round the
 * target rate if it hasn't been done already, then program and lock
 * the DPLL.  Returns -EINVAL upon error, or 0 upon success.
 */
int omap3_noncore_dpll_set_rate(struct clk *clk, unsigned long rate)
{
    struct clk *new_parent = NULL;
    u16 freqsel = 0;
    struct dpll_data *dd;
    int ret;

    if (!clk || !rate)
        return -EINVAL;

    dd = clk->dpll_data;
    if (!dd)
        return -EINVAL;

    if (rate == omap2_get_dpll_rate(clk))
        return 0;

    /*
     * Ensure both the bypass and ref clocks are enabled prior to
     * doing anything; we need the bypass clock running to reprogram
     * the DPLL.
     */
    omap2_clk_enable(dd->clk_bypass);
    omap2_clk_enable(dd->clk_ref);

    if (dd->clk_bypass->rate == rate &&
            (clk->dpll_data->modes & (1 << DPLL_LOW_POWER_BYPASS))) {
        pr_debug("clock: %s: set rate: entering bypass.\n", clk->name);

        ret = _omap3_noncore_dpll_bypass(clk);
        if (!ret)
            new_parent = dd->clk_bypass;
    } else {
        if (dd->last_rounded_rate != rate)
            rate = clk->round_rate(clk, rate);

        if (dd->last_rounded_rate == 0)
            return -EINVAL;

        /* No freqsel on OMAP4 and OMAP3630 */
        if (!cpu_is_omap44xx() && !cpu_is_omap3630()) {
            freqsel = _omap3_dpll_compute_freqsel(clk,
                                                  dd->last_rounded_n);
            if (!freqsel)
                WARN_ON(1);
        }

        pr_debug("clock: %s: set rate: locking rate to %lu.\n",
                 clk->name, rate);

        ret = omap3_noncore_dpll_program(clk, dd->last_rounded_m,
                                         dd->last_rounded_n, freqsel);
        if (!ret)
            new_parent = dd->clk_ref;
    }
    if (!ret) {
        /*
         * Switch the parent clock in the hierarchy, and make sure
         * that the new parent's usecount is correct.  Note: we
         * enable the new parent before disabling the old to avoid
         * any unnecessary hardware disable->enable transitions.
         */
        if (clk->usecount) {
            omap2_clk_enable(new_parent);
            omap2_clk_disable(clk->parent);
        }
        clk_reparent(clk, new_parent);
        clk->rate = rate;
    }
    omap2_clk_disable(dd->clk_ref);
    omap2_clk_disable(dd->clk_bypass);

    return 0;
}
int omap4460_mpu_dpll_set_rate(struct clk *clk, unsigned long rate)
{
    struct dpll_data *dd;
    u32 v;
    unsigned long dpll_rate;

    if (!clk || !rate || !clk->parent)
        return -EINVAL;

    dd = clk->parent->dpll_data;

    if (!dd)
        return -EINVAL;

    if (!clk->parent->set_rate)
        return -EINVAL;

    if (rate > clk->rate)
        omap4460_mpu_dpll_update_children(rate);

    /*
     * On OMAP4460, to obtain MPU DPLL frequency higher
     * than 1GHz, DCC (Duty Cycle Correction) needs to
     * be enabled.
     * And needs to be kept disabled for < 1 Ghz.
     */
    dpll_rate = omap2_get_dpll_rate(clk->parent);
    if (rate <= OMAP_1_5GHz) {
        /* If DCC is enabled, disable it */
        v = __raw_readl(dd->mult_div1_reg);
        if (v & OMAP4460_DCC_EN_MASK) {
            v &= ~OMAP4460_DCC_EN_MASK;
            __raw_writel(v, dd->mult_div1_reg);
        }

        if (rate != dpll_rate)
            clk->parent->set_rate(clk->parent, rate);
    } else {
        /*
         * On 4460, the MPU clk for frequencies higher than 1Ghz
         * is sourced from CLKOUTX2_M3, instead of CLKOUT_M2, while
         * value of M3 is fixed to 1. Hence for frequencies higher
         * than 1 Ghz, lock the DPLL at half the rate so the
         * CLKOUTX2_M3 then matches the requested rate.
         */
        if (rate != dpll_rate * 2)
            clk->parent->set_rate(clk->parent, rate / 2);

        v = __raw_readl(dd->mult_div1_reg);
        v &= ~OMAP4460_DCC_COUNT_MAX_MASK;
        v |= (5 << OMAP4460_DCC_COUNT_MAX_SHIFT);
        __raw_writel(v, dd->mult_div1_reg);

        v |= OMAP4460_DCC_EN_MASK;
        __raw_writel(v, dd->mult_div1_reg);
    }

    if (rate < clk->rate)
        omap4460_mpu_dpll_update_children(rate);

    clk->rate = rate;

    return 0;
}