/** * 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; }