Example #1
0
/**
 * omap4_prcm_freq_update - set freq_update bit
 *
 * Programs the CM shadow registers to update EMIF
 * parametrs. Few usecase only few registers needs to
 * be updated using prcm freq update sequence.
 * EMIF read-idle control and zq-config needs to be
 * updated for temprature alerts and voltage change
 * Returns -1 on error and 0 on success.
 */
int omap4_prcm_freq_update(void)
{
	u32 shadow_freq_cfg1;
	int i = 0;
	unsigned long flags;

	if (!l3_emif_clkdm) {
		pr_err("%s: clockdomain lookup failed\n", __func__);
		return -EINVAL;
	}

	spin_lock_irqsave(&l3_emif_lock, flags);
	/* Configures MEMIF domain in SW_WKUP */
	clkdm_wakeup(l3_emif_clkdm);

	/* Disable DDR self refresh (Errata ID: i728) */
	omap_emif_frequency_pre_notify();

	/*
	 * FREQ_UPDATE sequence:
	 * - DLL_OVERRIDE=0 (DLL lock & code must not be overridden
	 *	after CORE DPLL lock)
	 * - FREQ_UPDATE=1 (to start HW sequence)
	 */
	shadow_freq_cfg1 = __raw_readl(OMAP4430_CM_SHADOW_FREQ_CONFIG1);
	shadow_freq_cfg1 |= (1 << OMAP4430_DLL_RESET_SHIFT) |
			   (1 << OMAP4430_FREQ_UPDATE_SHIFT);
	shadow_freq_cfg1 &= ~OMAP4430_DLL_OVERRIDE_MASK;
	__raw_writel(shadow_freq_cfg1, OMAP4430_CM_SHADOW_FREQ_CONFIG1);

	/* wait for the configuration to be applied */
	omap_test_timeout(((__raw_readl(OMAP4430_CM_SHADOW_FREQ_CONFIG1)
				& OMAP4430_FREQ_UPDATE_MASK) == 0),
				MAX_FREQ_UPDATE_TIMEOUT, i);

	/* Re-enable DDR self refresh */
	omap_emif_frequency_post_notify();

	/* Configures MEMIF domain back to HW_WKUP */
	clkdm_allow_idle(l3_emif_clkdm);

	spin_unlock_irqrestore(&l3_emif_lock, flags);

	if (i == MAX_FREQ_UPDATE_TIMEOUT) {
		pr_err("%s: Frequency update failed (call from %pF)\n",
			__func__, (void *)_RET_IP_);
		pr_err("CLKCTRL: EMIF_1=0x%x EMIF_2=0x%x DMM=0x%x\n",
		       __raw_readl(OMAP4430_CM_MEMIF_EMIF_1_CLKCTRL),
		       __raw_readl(OMAP4430_CM_MEMIF_EMIF_2_CLKCTRL),
		       __raw_readl(OMAP4430_CM_MEMIF_DMM_CLKCTRL));
		emif_dump(0);
		emif_dump(1);
		return -1;
	}

	return 0;
}
/**
 * omap4_core_dpll_m2_set_rate - set CORE DPLL M2 divider
 * @clk: struct clk * of DPLL to set
 * @rate: rounded target rate
 *
 * Programs the CM shadow registers to update CORE DPLL M2
 * divider. M2 divider is used to clock external DDR and its
 * reconfiguration on frequency change is managed through a
 * hardware sequencer. This is managed by the PRCM with EMIF
 * uding shadow registers.
 * Returns -EINVAL/-1 on error and 0 on success.
 */
int omap4_core_dpll_m2_set_rate(struct clk *clk, unsigned long rate)
{
    int i = 0;
    u32 validrate = 0, shadow_freq_cfg1 = 0, new_div = 0;
    unsigned long flags;

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

    validrate = omap2_clksel_round_rate_div(clk, rate, &new_div);
    if (validrate != rate)
        return -EINVAL;

    /* Just to avoid look-up on every call to speed up */
    if (!l3_emif_clkdm) {
        l3_emif_clkdm = clkdm_lookup("l3_emif_clkdm");
        if (!l3_emif_clkdm) {
            pr_err("%s: clockdomain lookup failed\n", __func__);
            return -EINVAL;
        }
    }

    spin_lock_irqsave(&l3_emif_lock, flags);

    /*
     * Errata ID: i728
     *
     * DESCRIPTION:
     *
     * If during a small window the following three events occur:
     *
     * 1) The EMIF_PWR_MGMT_CTRL[7:4] REG_SR_TIM SR_TIMING counter expires
     * 2) Frequency change update is requested CM_SHADOW_FREQ_CONFIG1
     *    FREQ_UPDATE set to 1
     * 3) OCP access is requested
     *
     * There will be instable clock on the DDR interface.
     *
     * WORKAROUND:
     *
     * Prevent event 1) while event 2) is happening.
     *
     * Disable the self-refresh when requesting a frequency change.
     * Before requesting a frequency change, program
     * EMIF_PWR_MGMT_CTRL[10:8] REG_LP_MODE to 0x0
     * (omap_emif_frequency_pre_notify)
     *
     * When the frequency change is completed, reprogram
     * EMIF_PWR_MGMT_CTRL[10:8] REG_LP_MODE to 0x2.
     * (omap_emif_frequency_post_notify)
     */
    omap_emif_frequency_pre_notify();

    /* Configures MEMIF domain in SW_WKUP */
    clkdm_wakeup(l3_emif_clkdm);

    /*
     * Program EMIF timing parameters in EMIF shadow registers
     * for targetted DRR clock.
     * DDR Clock = core_dpll_m2 / 2
     */
    omap_emif_setup_registers(validrate >> 1, LPDDR2_VOLTAGE_STABLE);

    /*
     * FREQ_UPDATE sequence:
     * - DLL_OVERRIDE=0 (DLL lock & code must not be overridden
     *	after CORE DPLL lock)
     * - DLL_RESET=1 (DLL must be reset upon frequency change)
     * - DPLL_CORE_M2_DIV with same value as the one already
     *	in direct register
     * - DPLL_CORE_DPLL_EN=0x7 (to make CORE DPLL lock)
     * - FREQ_UPDATE=1 (to start HW sequence)
     */
    shadow_freq_cfg1 = (1 << OMAP4430_DLL_RESET_SHIFT) |
                       (new_div << OMAP4430_DPLL_CORE_M2_DIV_SHIFT) |
                       (DPLL_LOCKED << OMAP4430_DPLL_CORE_DPLL_EN_SHIFT) |
                       (1 << OMAP4430_FREQ_UPDATE_SHIFT);
    shadow_freq_cfg1 &= ~OMAP4430_DLL_OVERRIDE_MASK;
    __raw_writel(shadow_freq_cfg1, OMAP4430_CM_SHADOW_FREQ_CONFIG1);

    /* wait for the configuration to be applied */
    omap_test_timeout(((__raw_readl(OMAP4430_CM_SHADOW_FREQ_CONFIG1)
                        & OMAP4430_FREQ_UPDATE_MASK) == 0),
                      MAX_FREQ_UPDATE_TIMEOUT, i);

    /* Configures MEMIF domain back to HW_WKUP */
    clkdm_allow_idle(l3_emif_clkdm);

    /* Re-enable DDR self refresh */
    omap_emif_frequency_post_notify();

    spin_unlock_irqrestore(&l3_emif_lock, flags);

    if (i == MAX_FREQ_UPDATE_TIMEOUT) {
        pr_err("%s: Frequency update for CORE DPLL M2 change failed\n",
               __func__);
        return -1;
    }

    /* Update the clock change */
    clk->rate = validrate;

    return 0;
}
/**
 * omap4_prcm_freq_update - set freq_update bit
 *
 * Programs the CM shadow registers to update EMIF
 * parametrs. Few usecase only few registers needs to
 * be updated using prcm freq update sequence.
 * EMIF read-idle control and zq-config needs to be
 * updated for temprature alerts and voltage change
 * Returns -1 on error and 0 on success.
 */
int omap4_prcm_freq_update(void)
{
    u32 shadow_freq_cfg1;
    int i = 0;
    unsigned long flags;

    if (!l3_emif_clkdm) {
        pr_err("%s: clockdomain lookup failed\n", __func__);
        return -EINVAL;
    }

    spin_lock_irqsave(&l3_emif_lock, flags);

    /*
     * Errata ID: i728
     *
     * DESCRIPTION:
     *
     * If during a small window the following three events occur:
     *
     * 1) The EMIF_PWR_MGMT_CTRL[7:4] REG_SR_TIM SR_TIMING counter expires
     * 2) Frequency change update is requested CM_SHADOW_FREQ_CONFIG1
     *    FREQ_UPDATE set to 1
     * 3) OCP access is requested
     *
     * There will be instable clock on the DDR interface.
     *
     * WORKAROUND:
     *
     * Prevent event 1) while event 2) is happening.
     *
     * Disable the self-refresh when requesting a frequency change.
     * Before requesting a frequency change, program
     * EMIF_PWR_MGMT_CTRL[10:8] REG_LP_MODE to 0x0
     * (omap_emif_frequency_pre_notify)
     *
     * When the frequency change is completed, reprogram
     * EMIF_PWR_MGMT_CTRL[10:8] REG_LP_MODE to 0x2.
     * (omap_emif_frequency_post_notify)
     */
    omap_emif_frequency_pre_notify();

    /* Configures MEMIF domain in SW_WKUP */
    clkdm_wakeup(l3_emif_clkdm);

    /*
     * FREQ_UPDATE sequence:
     * - DLL_OVERRIDE=0 (DLL lock & code must not be overridden
     *	after CORE DPLL lock)
     * - FREQ_UPDATE=1 (to start HW sequence)
     */
    shadow_freq_cfg1 = __raw_readl(OMAP4430_CM_SHADOW_FREQ_CONFIG1);
    shadow_freq_cfg1 |= (1 << OMAP4430_DLL_RESET_SHIFT) |
                        (1 << OMAP4430_FREQ_UPDATE_SHIFT);
    shadow_freq_cfg1 &= ~OMAP4430_DLL_OVERRIDE_MASK;
    __raw_writel(shadow_freq_cfg1, OMAP4430_CM_SHADOW_FREQ_CONFIG1);

    /* wait for the configuration to be applied */
    omap_test_timeout(((__raw_readl(OMAP4430_CM_SHADOW_FREQ_CONFIG1)
                        & OMAP4430_FREQ_UPDATE_MASK) == 0),
                      MAX_FREQ_UPDATE_TIMEOUT, i);

    /* Configures MEMIF domain back to HW_WKUP */
    clkdm_allow_idle(l3_emif_clkdm);

    /* Re-enable DDR self refresh */
    omap_emif_frequency_post_notify();

    spin_unlock_irqrestore(&l3_emif_lock, flags);

    if (i == MAX_FREQ_UPDATE_TIMEOUT) {
        pr_err("%s: Frequency update failed (call from %pF)\n",
               __func__, (void *)_RET_IP_);
        pr_err("CLKCTRL: EMIF_1=0x%x EMIF_2=0x%x DMM=0x%x\n",
               __raw_readl(OMAP4430_CM_MEMIF_EMIF_1_CLKCTRL),
               __raw_readl(OMAP4430_CM_MEMIF_EMIF_2_CLKCTRL),
               __raw_readl(OMAP4430_CM_MEMIF_DMM_CLKCTRL));
        emif_dump(0);
        emif_dump(1);
        return -1;
    }

    return 0;
}