Beispiel #1
0
/*
 * _omap3_noncore_dpll_lock - instruct a DPLL to lock and wait for readiness
 * @clk: pointer to a DPLL struct clk
 *
 * Instructs a non-CORE DPLL to lock.  Waits for the DPLL to report
 * readiness before returning.  Will save and restore the DPLL's
 * autoidle state across the enable, per the CDP code.  If the DPLL
 * locked successfully, return 0; if the DPLL did not lock in the time
 * allotted, or DPLL3 was passed in, return -EINVAL.
 */
static int _omap3_noncore_dpll_lock(struct clk *clk)
{
    const struct dpll_data *dd;
    u8 ai;
    u8 state = 1;
    int r = 0;

    pr_debug("clock: locking DPLL %s\n", clk->name);

    dd = clk->dpll_data;
    state <<= __ffs(dd->idlest_mask);

    /* Check if already locked */
    if ((__raw_readl(dd->idlest_reg) & dd->idlest_mask) == state)
        goto done;

    ai = omap3_dpll_autoidle_read(clk);

    omap3_dpll_deny_idle(clk);

    _omap3_dpll_write_clken(clk, DPLL_LOCKED);

    r = _omap3_wait_dpll_status(clk, 1);

    if (ai)
        omap3_dpll_allow_idle(clk);

done:
    return r;
}
/*
 * _omap3_noncore_dpll_bypass - instruct a DPLL to bypass and wait for readiness
 * @clk: pointer to a DPLL struct clk
 *
 * Instructs a non-CORE DPLL to enter low-power bypass mode.  In
 * bypass mode, the DPLL's rate is set equal to its parent clock's
 * rate.  Waits for the DPLL to report readiness before returning.
 * Will save and restore the DPLL's autoidle state across the enable,
 * per the CDP code.  If the DPLL entered bypass mode successfully,
 * return 0; if the DPLL did not enter bypass in the time allotted, or
 * DPLL3 was passed in, or the DPLL does not support low-power bypass,
 * return -EINVAL.
 */
static int _omap3_noncore_dpll_bypass(struct clk *clk)
{
	int r;
	u8 ai;

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

	if (!(clk->dpll_data->modes & (1 << DPLL_LOW_POWER_BYPASS)))
		return -EINVAL;

	pr_debug("clock: configuring DPLL %s for low-power bypass\n",
		 clk->name);

	ai = omap3_dpll_autoidle_read(clk);

	_omap3_dpll_write_clken(clk, DPLL_LOW_POWER_BYPASS);

	r = _omap3_wait_dpll_status(clk, 0);

	if (ai)
		omap3_dpll_allow_idle(clk);
	else
		omap3_dpll_deny_idle(clk);

	return r;
}
/*
 * _omap3_noncore_dpll_stop - instruct a DPLL to stop
 * @clk: pointer to a DPLL struct clk
 *
 * Instructs a non-CORE DPLL to enter low-power stop. Will save and
 * restore the DPLL's autoidle state across the stop, per the CDP
 * code.  If DPLL3 was passed in, or the DPLL does not support
 * low-power stop, return -EINVAL; otherwise, return 0.
 */
static int _omap3_noncore_dpll_stop(struct clk_hw_omap *clk)
{
	u8 ai;

	if (!(clk->dpll_data->modes & (1 << DPLL_LOW_POWER_STOP)))
		return -EINVAL;

	pr_debug("clock: stopping DPLL %s\n", __clk_get_name(clk->hw.clk));

	ai = omap3_dpll_autoidle_read(clk);

	_omap3_dpll_write_clken(clk, DPLL_LOW_POWER_STOP);

	if (ai)
		omap3_dpll_allow_idle(clk);

	return 0;
}
Beispiel #4
0
/*
 * _omap3_noncore_dpll_lock - instruct a DPLL to lock and wait for readiness
 * @clk: pointer to a DPLL struct clk
 *
 * Instructs a non-CORE DPLL to lock.  Waits for the DPLL to report
 * readiness before returning.  Will save and restore the DPLL's
 * autoidle state across the enable, per the CDP code.  If the DPLL
 * locked successfully, return 0; if the DPLL did not lock in the time
 * allotted, or DPLL3 was passed in, return -EINVAL.
 */
static int _omap3_noncore_dpll_lock(struct clk *clk)
{
	u8 ai;
	int r;

	pr_debug("clock: locking DPLL %s\n", clk->name);

	ai = omap3_dpll_autoidle_read(clk);

	omap3_dpll_deny_idle(clk);

	_omap3_dpll_write_clken(clk, DPLL_LOCKED);

	r = _omap3_wait_dpll_status(clk, 1);

	if (ai)
		omap3_dpll_allow_idle(clk);

	return r;
}
/*
 * _omap3_noncore_dpll_stop - instruct a DPLL to stop
 * @clk: pointer to a DPLL struct clk
 *
 * Instructs a non-CORE DPLL to enter low-power stop. Will save and
 * restore the DPLL's autoidle state across the stop, per the CDP
 * code.  If DPLL3 was passed in, or the DPLL does not support
 * low-power stop, return -EINVAL; otherwise, return 0.
 */
static int _omap3_noncore_dpll_stop(struct clk *clk)
{
	u8 ai;

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

	if (!(clk->dpll_data->modes & (1 << DPLL_LOW_POWER_STOP)))
		return -EINVAL;

	pr_debug("clock: stopping DPLL %s\n", clk->name);

	ai = omap3_dpll_autoidle_read(clk);

	_omap3_dpll_write_clken(clk, DPLL_LOW_POWER_STOP);

	if (ai)
		omap3_dpll_allow_idle(clk);
	else
		omap3_dpll_deny_idle(clk);

	return 0;
}
Beispiel #6
0
/* _omap3_wait_dpll_status: wait for a DPLL to enter a specific state */
static int _omap3_wait_dpll_status(struct clk *clk, u8 state)
{
    const struct dpll_data *dd;
    int i;
    int ret = -EINVAL;
    bool first_time = true;
    u32 reg;
    /* LGE_SJIT 2012-02-08 [[email protected]] fix the warning */
    u32 orig_cm_div_m2_dpll_usb = 0;
    u32 orig_cm_clkdcoldo_dpll_usb = 0;

retry:
    dd = clk->dpll_data;

    state <<= __ffs(dd->idlest_mask);

    i = 0;
    while (((__raw_readl(dd->idlest_reg) & dd->idlest_mask) != state) &&
            i < MAX_DPLL_WAIT_TRIES) {
        i++;
        udelay(1);
    }

    /* restore back old values if hit work-around */
    if (!first_time) {
        __raw_writel(orig_cm_div_m2_dpll_usb,
                     OMAP4430_CM_DIV_M2_DPLL_USB);
        __raw_writel(orig_cm_clkdcoldo_dpll_usb,
                     OMAP4430_CM_CLKDCOLDO_DPLL_USB);
    }

    if (i == MAX_DPLL_WAIT_TRIES) {
        printk(KERN_ERR "clock: %s failed transition to '%s'\n",
               clk->name, (state) ? "locked" : "bypassed");

        /* Try Error Recovery: for failing usbdpll locking */
        if (!strcmp(clk->name, "dpll_usb_ck")) {

            reg = __raw_readl(dd->mult_div1_reg);

            /* Put in MN bypass */
            _omap3_dpll_write_clken(clk, DPLL_MN_BYPASS);
            i = 0;
            while (!(__raw_readl(dd->idlest_reg) & (1 << OMAP4430_ST_MN_BYPASS_SHIFT)) &&
                    i < MAX_DPLL_WAIT_TRIES) {
                i++;
                udelay(1);
            }

            /* MN bypass looses contents of CM_CLKSEL_DPLL_USB */
            __raw_writel(reg, dd->mult_div1_reg);

            /* Force generate request to PRCM: put in Force mode */

            /* a) CM_DIV_M2_DPLL_USB.DPLL_CLKOUT_GATE_CTRL = 1 */
            orig_cm_div_m2_dpll_usb = __raw_readl(OMAP4430_CM_DIV_M2_DPLL_USB);
            __raw_writel(orig_cm_div_m2_dpll_usb |
                         (1 << OMAP4430_DPLL_CLKOUT_GATE_CTRL_SHIFT),
                         OMAP4430_CM_DIV_M2_DPLL_USB);

            /* b) CM_CLKDCOLDO_DPLL_USB.DPLL_CLKDCOLDO_GATE_CTRL = 1 */
            orig_cm_clkdcoldo_dpll_usb = __raw_readl(OMAP4430_CM_CLKDCOLDO_DPLL_USB);
            __raw_writel(orig_cm_clkdcoldo_dpll_usb |
                         (1 << OMAP4430_DPLL_CLKDCOLDO_GATE_CTRL_SHIFT),
                         OMAP4430_CM_CLKDCOLDO_DPLL_USB);

            /* Put back to locked mode */
            _omap3_dpll_write_clken(clk, DPLL_LOCKED);

            if (first_time) {
                first_time = false;
                goto retry;
            }
        }
    } else {
        pr_debug("clock: %s transition to '%s' in %d loops\n",
                 clk->name, (state) ? "locked" : "bypassed", i);

        ret = 0;
    }

    return ret;
}
Beispiel #7
0
/* _omap3_wait_dpll_status: wait for a DPLL to enter a specific state */
static int _omap3_wait_dpll_status(struct clk *clk, u8 state)
{
	const struct dpll_data *dd;
	int i;
	int ret = -EINVAL;
	bool first_time = true;
	u32 reg;
	u32 orig_cm_div_m2_dpll_usb;
	u32 orig_cm_clkdcoldo_dpll_usb;

retry:
	dd = clk->dpll_data;

	state <<= __ffs(dd->idlest_mask);

	i = 0;
	while (((__raw_readl(dd->idlest_reg) & dd->idlest_mask) != state) &&
	       i < MAX_DPLL_WAIT_TRIES) {
		i++;
		udelay(1);
	}

	/* restore back old values if hit work-around */
	if (!first_time) {
		__raw_writel(orig_cm_div_m2_dpll_usb,
				OMAP4430_CM_DIV_M2_DPLL_USB);
		__raw_writel(orig_cm_clkdcoldo_dpll_usb,
				OMAP4430_CM_CLKDCOLDO_DPLL_USB);
	}

	if (i == MAX_DPLL_WAIT_TRIES) {
		printk(KERN_ERR "clock: %s failed transition to '%s'\n",
		       clk->name, (state) ? "locked" : "bypassed");

		/* Try Error Recovery: for failing usbdpll locking */
		if (!strcmp(clk->name, "dpll_usb_ck")) {
			reg = __raw_readl(dd->mult_div1_reg);

			/* Put in MN bypass */
			_omap3_dpll_write_clken(clk, DPLL_MN_BYPASS);
			i = 0;
			while (!(__raw_readl(dd->idlest_reg) & (1 << OMAP4430_ST_MN_BYPASS_SHIFT)) &&
					i < MAX_DPLL_WAIT_TRIES) {
				i++;
				udelay(1);
			}

			/* MN bypass looses contents of CM_CLKSEL_DPLL_USB */
			__raw_writel(reg, dd->mult_div1_reg);

			/* Force generate request to PRCM: put in Force mode */

			/* a) CM_DIV_M2_DPLL_USB.DPLL_CLKOUT_GATE_CTRL = 1 */
			orig_cm_div_m2_dpll_usb = __raw_readl(OMAP4430_CM_DIV_M2_DPLL_USB);
			__raw_writel(orig_cm_div_m2_dpll_usb |
					(1 << OMAP4430_DPLL_CLKOUT_GATE_CTRL_SHIFT),
					OMAP4430_CM_DIV_M2_DPLL_USB);

			/* b) CM_CLKDCOLDO_DPLL_USB.DPLL_CLKDCOLDO_GATE_CTRL = 1 */
			orig_cm_clkdcoldo_dpll_usb = __raw_readl(OMAP4430_CM_CLKDCOLDO_DPLL_USB);
			__raw_writel(orig_cm_clkdcoldo_dpll_usb |
					(1 << OMAP4430_DPLL_CLKDCOLDO_GATE_CTRL_SHIFT),
					OMAP4430_CM_CLKDCOLDO_DPLL_USB);

			/* Put back to locked mode */
			_omap3_dpll_write_clken(clk, DPLL_LOCKED);

			if (first_time) {
				first_time = false;
				goto retry;
			}

			pr_info("\n========== USB DPLL DUMP ===========\n");
			pr_info("CM_CLKMODE_DPLL_USB         :%08x\n", omap_readl(0x4A008180));
			pr_info("CM_IDLEST_DPLL_USB          :%08x\n", omap_readl(0x4A008184));
			pr_info("CM_AUTOIDLE_DPLL_USB        :%08x\n", omap_readl(0x4A008188));
			pr_info("CM_CLKSEL_DPLL_USB          :%08x\n", omap_readl(0x4A00818C));
			pr_info("CM_DIV_M2_DPLL_USB          :%08x\n", omap_readl(0x4A008190));
			pr_info("CM_SSC_DELTAMSTEP_DPLL_USB  :%08x\n", omap_readl(0x4A0081A8));
			pr_info("CM_SSC_MODFREQDIV_DPLL_USB  :%08x\n", omap_readl(0x4A0081AC));
			pr_info("CM_CLKDCOLDO_DPLL_USB       :%08x\n", omap_readl(0x4A0081B4));
			pr_info("========== USB DPLL DUMP: End ===========\n");
		}
	} else {
		pr_debug("clock: %s transition to '%s' in %d loops\n",
			 clk->name, (state) ? "locked" : "bypassed", i);

		ret = 0;
	}

	return ret;
}