/* * PRCM Interrupt Handler Helper Function * * The purpose of this function is to clear any wake-up events latched * in the PRCM PM_WKST_x registers. It is possible that a wake-up event * may occur whilst attempting to clear a PM_WKST_x register and thus * set another bit in this register. A while loop is used to ensure * that any peripheral wake-up events occurring while attempting to * clear the PM_WKST_x are detected and cleared. */ static int prcm_clear_mod_irqs(s16 module, u8 regs) { u32 wkst, fclk, iclk, clken; u16 wkst_off = (regs == 3) ? OMAP3430ES2_PM_WKST3 : PM_WKST1; u16 fclk_off = (regs == 3) ? OMAP3430ES2_CM_FCLKEN3 : CM_FCLKEN1; u16 iclk_off = (regs == 3) ? CM_ICLKEN3 : CM_ICLKEN1; u16 grpsel_off = (regs == 3) ? OMAP3430ES2_PM_MPUGRPSEL3 : OMAP3430_PM_MPUGRPSEL; int c = 0; wkst = prm_read_mod_reg(module, wkst_off); wkst &= prm_read_mod_reg(module, grpsel_off); if (wkst) { iclk = cm_read_mod_reg(module, iclk_off); fclk = cm_read_mod_reg(module, fclk_off); while (wkst) { clken = wkst; cm_set_mod_reg_bits(clken, module, iclk_off); /* * For USBHOST, we don't know whether HOST1 or * HOST2 woke us up, so enable both f-clocks */ if (module == OMAP3430ES2_USBHOST_MOD) clken |= 1 << OMAP3430ES2_EN_USBHOST2_SHIFT; cm_set_mod_reg_bits(clken, module, fclk_off); prm_write_mod_reg(wkst, module, wkst_off); wkst = prm_read_mod_reg(module, wkst_off); c++; } cm_write_mod_reg(iclk, module, iclk_off); cm_write_mod_reg(fclk, module, fclk_off); } return c; }
/* * omap3_noncore_dpll_program - set non-core DPLL M,N values directly * @clk: struct clk * of DPLL to set * @m: DPLL multiplier to set * @n: DPLL divider to set * @freqsel: FREQSEL value to set * * Program the DPLL with the supplied M, N values, and wait for the DPLL to * lock.. Returns -EINVAL upon error, or 0 upon success. */ static int omap3_noncore_dpll_program(struct clk *clk, u16 m, u8 n, u16 freqsel) { struct dpll_data *dd; u32 v; if (!clk) return -EINVAL; dd = clk->dpll_data; if (!dd) return -EINVAL; /* * According to the 12-5 CDP code from TI, "Limitation 2.5" * on 3430ES1 prevents us from changing DPLL multipliers or dividers * on DPLL4. */ if (omap_rev() == OMAP3430_REV_ES1_0 && !strcmp("dpll4_ck", clk->name)) { printk(KERN_ERR "clock: DPLL4 cannot change rate due to " "silicon 'Limitation 2.5' on 3430ES1.\n"); return -EINVAL; } /* 3430 ES2 TRM: 4.7.6.9 DPLL Programming Sequence */ _omap3_noncore_dpll_bypass(clk); /* Set jitter correction */ v = cm_read_mod_reg(clk->prcm_mod, dd->control_reg); v &= ~dd->freqsel_mask; v |= freqsel << __ffs(dd->freqsel_mask); cm_write_mod_reg(v, clk->prcm_mod, dd->control_reg); /* Set DPLL multiplier, divider */ v = cm_read_mod_reg(clk->prcm_mod, dd->mult_div1_reg); v &= ~(dd->mult_mask | dd->div1_mask); v |= m << __ffs(dd->mult_mask); v |= (n - 1) << __ffs(dd->div1_mask); if (dd->jtype) { u8 dco, sd_div; lookup_dco_sddiv(clk, &dco, &sd_div, m, n); v &= ~(dd->dco_sel_mask | dd->sd_div_mask); v |= dco << __ffs(dd->dco_sel_mask); v |= sd_div << __ffs(dd->sd_div_mask); } cm_write_mod_reg(v, clk->prcm_mod, dd->mult_div1_reg); /* We let the clock framework set the other output dividers later */ /* REVISIT: Set ramp-up delay? */ _omap3_noncore_dpll_lock(clk); return 0; }
static int omap2_fclks_active(void) { u32 f1, f2; f1 = cm_read_mod_reg(CORE_MOD, CM_FCLKEN1); f2 = cm_read_mod_reg(CORE_MOD, OMAP24XX_CM_FCLKEN2); serial_console_fclk_mask(&f1, &f2); if (f1 | f2) return 1; return 0; }
static int omap2_fclks_active(void) { u32 f1, f2; f1 = cm_read_mod_reg(CORE_MOD, CM_FCLKEN1); f2 = cm_read_mod_reg(CORE_MOD, OMAP24XX_CM_FCLKEN2); /* Ignore UART clocks. These are handled by UART core (serial.c) */ f1 &= ~(OMAP24XX_EN_UART1 | OMAP24XX_EN_UART2); f2 &= ~OMAP24XX_EN_UART3; if (f1 | f2) return 1; return 0; }
static int omap2_i2c_active(void) { u32 l; l = cm_read_mod_reg(CORE_MOD, CM_FCLKEN1); return l & (OMAP2420_EN_I2C2 | OMAP2420_EN_I2C1); }
/** * omap2_cm_wait_idlest_ready - wait for a module to leave idle or standby * @prcm_mod: PRCM module offset * @idlest_id: CM_IDLESTx register ID (i.e., x = 1, 2, 3) * @idlest_shift: shift of the bit in the CM_IDLEST* register to check * * XXX document */ int omap2_cm_wait_module_ready(s16 prcm_mod, u8 idlest_id, u8 idlest_shift) { int ena = 0, i = 0; u8 cm_idlest_reg; u32 mask; if (!idlest_id || (idlest_id > ARRAY_SIZE(cm_idlest_offs))) return -EINVAL; cm_idlest_reg = cm_idlest_offs[idlest_id - 1]; if (cpu_is_omap24xx()) ena = idlest_shift; else if (cpu_is_omap34xx()) ena = 0; else BUG(); mask = 1 << idlest_shift; /* XXX should be OMAP2 CM */ while (((cm_read_mod_reg(prcm_mod, cm_idlest_reg) & mask) != ena) && (i++ < MAX_MODULE_READY_TIME)) udelay(1); return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY; }
/** * omap3_clkoutx2_recalc - recalculate DPLL X2 output virtual clock rate * @clk: DPLL output struct clk * @parent_rate: rate of the parent clock of @clk * @rate_storage: flag indicating whether current or temporary rate is changing * * Using parent clock DPLL data, look up DPLL state. If locked, set our * rate to the dpll_clk * 2; otherwise, just use dpll_clk. */ static void omap3_clkoutx2_recalc(struct clk *clk, unsigned long parent_rate, u8 rate_storage) { const struct dpll_data *dd; u32 v; unsigned long rate; struct clk *pclk; /* Walk up the parents of clk, looking for a DPLL */ pclk = clk->parent; while (pclk && !pclk->dpll_data) pclk = pclk->parent; /* clk does not have a DPLL as a parent? */ WARN_ON(!pclk); dd = pclk->dpll_data; WARN_ON(!dd->enable_mask); rate = parent_rate; v = cm_read_mod_reg(pclk->prcm_mod, dd->control_reg) & dd->enable_mask; v >>= __ffs(dd->enable_mask); if (v == OMAP3XXX_EN_DPLL_LOCKED) rate *= 2; if (rate_storage == CURRENT_RATE) clk->rate = rate; else if (rate_storage == TEMP_RATE) clk->temp_rate = rate; }
/* Enable an APLL if off */ static int omap2_clk_fixed_enable(struct clk *clk) { u32 cval, apll_mask; apll_mask = EN_APLL_LOCKED << clk->enable_bit; cval = cm_read_mod_reg(PLL_MOD, CM_CLKEN); if ((cval & apll_mask) == apll_mask) return 0; /* apll already enabled */ cval &= ~apll_mask; cval |= apll_mask; cm_write_mod_reg(cval, PLL_MOD, CM_CLKEN); if (clk == &apll96_ck) cval = OMAP24XX_ST_96M_APLL; else if (clk == &apll54_ck) cval = OMAP24XX_ST_54M_APLL; omap2_wait_clock_ready(OMAP_CM_REGADDR(PLL_MOD, CM_IDLEST), cval, clk->name); /* * REVISIT: Should we return an error code if omap2_wait_clock_ready() * fails? */ return 0; }
/* * Uses the current prcm set to tell if a rate is valid. * You can go slower, but not faster within a given rate set. */ static u32 omap2_dpll_round_rate(unsigned long target_rate) { u32 high, low, core_clk_src; core_clk_src = cm_read_mod_reg(PLL_MOD, CM_CLKSEL2); core_clk_src &= OMAP24XX_CORE_CLK_SRC_MASK; if (core_clk_src == CORE_CLK_SRC_DPLL) { /* DPLL clockout */ high = curr_prcm_set->dpll_speed * 2; low = curr_prcm_set->dpll_speed; } else { /* DPLL clockout x 2 */ high = curr_prcm_set->dpll_speed; low = curr_prcm_set->dpll_speed / 2; } #ifdef DOWN_VARIABLE_DPLL if (target_rate > high) return high; else return target_rate; #else if (target_rate > low) return high; else return low; #endif }
/* _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 = 0; int ret = -EINVAL; dd = clk->dpll_data; state <<= __ffs(dd->idlest_mask); while (((cm_read_mod_reg(clk->prcm_mod, dd->idlest_reg) & dd->idlest_mask) != state) && i < MAX_DPLL_WAIT_TRIES) { i++; udelay(1); } if (i == MAX_DPLL_WAIT_TRIES) { printk(KERN_ERR "clock: %s failed transition to '%s'\n", clk->name, (state) ? "locked" : "bypassed"); } else { pr_debug("clock: %s transition to '%s' in %d loops\n", clk->name, (state) ? "locked" : "bypassed", i); ret = 0; } return ret; }
/* Stop APLL */ static void omap2_clk_fixed_disable(struct clk *clk) { u32 cval; cval = cm_read_mod_reg(PLL_MOD, CM_CLKEN); cval &= ~(EN_APLL_LOCKED << clk->enable_bit); cm_write_mod_reg(cval, PLL_MOD, CM_CLKEN); }
static unsigned long omap3_l3_get_rate(struct device *dev) { int l3_div; l3_div = cm_read_mod_reg(CORE_MOD, CM_CLKSEL) & OMAP3430_CLKSEL_L3_MASK; return dpll3_clk->rate / l3_div; }
static int omap3_l3_set_rate(struct device *dev, unsigned long rate) { int l3_div; l3_div = cm_read_mod_reg(CORE_MOD, CM_CLKSEL) & OMAP3430_CLKSEL_L3_MASK; return clk_set_rate(dpll3_clk, rate * l3_div); }
static int omap2_allow_mpu_retention(void) { u32 l; /* Check for MMC, UART2, UART1, McSPI2, McSPI1 and DSS1. */ l = cm_read_mod_reg(CORE_MOD, CM_FCLKEN1); if (l & (OMAP2420_EN_MMC_MASK | OMAP24XX_EN_UART2_MASK | OMAP24XX_EN_UART1_MASK | OMAP24XX_EN_MCSPI2_MASK | OMAP24XX_EN_MCSPI1_MASK | OMAP24XX_EN_DSS1_MASK)) return 0; /* Check for UART3. */ l = cm_read_mod_reg(CORE_MOD, OMAP24XX_CM_FCLKEN2); if (l & OMAP24XX_EN_UART3_MASK) return 0; if (sti_console_enabled) return 0; return 1; }
static int omap_ohci_bus_check_ctrl_standby(void) { u32 val; val = cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD, CM_IDLEST); if (val & OMAP3430ES2_ST_USBHOST_STDBY_MASK) return 1; else return 0; }
/* Read-modify-write a register in a CM module. Caller must lock */ u32 cm_rmw_mod_reg_bits(u32 mask, u32 bits, s16 module, s16 idx) { u32 v; v = cm_read_mod_reg(module, idx); v &= ~mask; v |= bits; cm_write_mod_reg(v, module, idx); return v; }
/* _omap3_dpll_write_clken - write clken_bits arg to a DPLL's enable bits */ static void _omap3_dpll_write_clken(struct clk *clk, u8 clken_bits) { const struct dpll_data *dd; u32 v; dd = clk->dpll_data; v = cm_read_mod_reg(clk->prcm_mod, dd->control_reg); v &= ~dd->enable_mask; v |= clken_bits << __ffs(dd->enable_mask); cm_write_mod_reg(v, clk->prcm_mod, dd->control_reg); }
static int omap4_sar_enable_check(void) { u32 usbhost_state, usbtll_state; /* Make sure that USB host and TLL modules are not * enabled before attempting to save the context * registers, otherwise this will trigger an exception. */ usbhost_state = cm_read_mod_reg(OMAP4430_CM2_L3INIT_MOD, OMAP4_CM_L3INIT_USB_HOST_CLKCTRL_OFFSET) & (OMAP4430_STBYST_MASK | OMAP4430_IDLEST_MASK); usbtll_state = cm_read_mod_reg(OMAP4430_CM2_L3INIT_MOD, OMAP4_CM_L3INIT_USB_TLL_CLKCTRL_OFFSET) & OMAP4430_IDLEST_MASK; if ((usbhost_state == (OMAP4430_STBYST_MASK | OMAP4430_IDLEST_MASK)) && (usbtll_state == (OMAP4430_IDLEST_MASK))) return 0; else return -EBUSY; }
/* 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; }
static int omap2_allow_mpu_retention(void) { u32 l; if (atomic_read(&sleep_block)) return 0; /* Check for MMC, UART2, UART1, McSPI2, McSPI1 and DSS1. */ l = cm_read_mod_reg(CORE_MOD, CM_FCLKEN1); if (l & (OMAP2420_EN_MMC | OMAP24XX_EN_UART2 | OMAP24XX_EN_UART1 | OMAP24XX_EN_MCSPI2 | OMAP24XX_EN_MCSPI1 | OMAP24XX_EN_DSS1)) return 0; /* Check for UART3. */ l = cm_read_mod_reg(CORE_MOD, OMAP24XX_CM_FCLKEN2); if (l & OMAP24XX_EN_UART3) return 0; if (sti_console_enabled) return 0; return 1; }
/** * omap3_dpll_deny_idle - prevent DPLL from automatically idling * @clk: struct clk * of the DPLL to operate on * * Disable DPLL automatic idle control. No return value. */ static void omap3_dpll_deny_idle(struct clk *clk) { const struct dpll_data *dd; u32 v; if (!clk || !clk->dpll_data) return; dd = clk->dpll_data; v = cm_read_mod_reg(clk->prcm_mod, dd->autoidle_reg); v &= ~dd->autoidle_mask; v |= DPLL_AUTOIDLE_DISABLE << __ffs(dd->autoidle_mask); cm_write_mod_reg(v, clk->prcm_mod, dd->autoidle_reg); }
/** * omap3_dpll_autoidle_read - read a DPLL's autoidle bits * @clk: struct clk * of the DPLL to read * * Return the DPLL's autoidle bits, shifted down to bit 0. Returns * -EINVAL if passed a null pointer or if the struct clk does not * appear to refer to a DPLL. */ static u32 omap3_dpll_autoidle_read(struct clk *clk) { const struct dpll_data *dd; u32 v; if (!clk || !clk->dpll_data) return -EINVAL; dd = clk->dpll_data; v = cm_read_mod_reg(clk->prcm_mod, dd->autoidle_reg); v &= dd->autoidle_mask; v >>= __ffs(dd->autoidle_mask); return v; }
unsigned long omap2xxx_clk_get_core_rate(struct clk *clk) { long long core_clk; u32 v; core_clk = omap2_get_dpll_rate(clk); v = 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; }
static u32 omap2_get_apll_clkin(void) { u32 aplls, sclk = 0; aplls = cm_read_mod_reg(PLL_MOD, CM_CLKSEL1); aplls &= OMAP24XX_APLLS_CLKIN_MASK; aplls >>= OMAP24XX_APLLS_CLKIN_SHIFT; if (aplls == APLLS_CLKIN_19_2MHZ) sclk = 19200000; else if (aplls == APLLS_CLKIN_13MHZ) sclk = 13000000; else if (aplls == APLLS_CLKIN_12MHZ) sclk = 12000000; return sclk; }
/** * omap3_dpll_allow_idle - enable DPLL autoidle bits * @clk: struct clk * of the DPLL to operate on * * Enable DPLL automatic idle control. This automatic idle mode * switching takes effect only when the DPLL is locked, at least on * OMAP3430. The DPLL will enter low-power stop when its downstream * clocks are gated. No return value. */ static void omap3_dpll_allow_idle(struct clk *clk) { const struct dpll_data *dd; u32 v; if (!clk || !clk->dpll_data) return; dd = clk->dpll_data; /* * REVISIT: CORE DPLL can optionally enter low-power bypass * by writing 0x5 instead of 0x1. Add some mechanism to * optionally enter this mode. */ v = cm_read_mod_reg(clk->prcm_mod, dd->autoidle_reg); v &= ~dd->autoidle_mask; v |= DPLL_AUTOIDLE_LOW_POWER_STOP << __ffs(dd->autoidle_mask); cm_write_mod_reg(v, clk->prcm_mod, dd->autoidle_reg); }
/* Enable an APLL if off */ static int omap2_clk_apll_enable(struct clk *clk, u32 status_mask) { u32 cval, apll_mask; apll_mask = EN_APLL_LOCKED << clk->enable_bit; cval = cm_read_mod_reg(PLL_MOD, CM_CLKEN); if ((cval & apll_mask) == apll_mask) return 0; /* apll already enabled */ cval &= ~apll_mask; cval |= apll_mask; cm_write_mod_reg(cval, PLL_MOD, CM_CLKEN); omap2_cm_wait_idlest(cm_idlest_pll, status_mask, OMAP24XX_CM_IDLEST_VAL, clk->name); /* * REVISIT: Should we return an error code if omap2_wait_clock_ready() * fails? */ return 0; }
/* Sets basic clocks based on the specified rate */ static int omap2_select_table_rate(struct clk *clk, unsigned long rate) { u32 cur_rate, done_rate, bypass = 0, tmp; struct prcm_config *prcm; unsigned long found_speed = 0; unsigned long flags; if (clk != &virt_prcm_set) return -EINVAL; for (prcm = rate_table; prcm->mpu_speed; prcm++) { if (!(prcm->flags & cpu_mask)) continue; if (prcm->xtal_speed != sys_ck.rate) continue; if (prcm->mpu_speed <= rate) { found_speed = prcm->mpu_speed; break; } } if (!found_speed) { printk(KERN_INFO "Could not set MPU rate to %luMHz\n", rate / 1000000); return -EINVAL; } curr_prcm_set = prcm; cur_rate = omap2_get_dpll_rate_24xx(&dpll_ck); if (prcm->dpll_speed == cur_rate / 2) { omap2_reprogram_sdrc(CORE_CLK_SRC_DPLL, 1); } else if (prcm->dpll_speed == cur_rate * 2) { omap2_reprogram_sdrc(CORE_CLK_SRC_DPLL_X2, 1); } else if (prcm->dpll_speed != cur_rate) { local_irq_save(flags); if (prcm->dpll_speed == prcm->xtal_speed) bypass = 1; if ((prcm->cm_clksel2_pll & OMAP24XX_CORE_CLK_SRC_MASK) == CORE_CLK_SRC_DPLL_X2) done_rate = CORE_CLK_SRC_DPLL_X2; else done_rate = CORE_CLK_SRC_DPLL; /* MPU divider */ cm_write_mod_reg(prcm->cm_clksel_mpu, MPU_MOD, CM_CLKSEL); /* dsp + iva1 div(2420), iva2.1(2430) */ cm_write_mod_reg(prcm->cm_clksel_dsp, OMAP24XX_DSP_MOD, CM_CLKSEL); cm_write_mod_reg(prcm->cm_clksel_gfx, GFX_MOD, CM_CLKSEL); /* Major subsystem dividers */ tmp = cm_read_mod_reg(CORE_MOD, CM_CLKSEL1) & OMAP24XX_CLKSEL_DSS2_MASK; cm_write_mod_reg(prcm->cm_clksel1_core | tmp, CORE_MOD, CM_CLKSEL1); if (cpu_is_omap2430()) cm_write_mod_reg(prcm->cm_clksel_mdm, OMAP2430_MDM_MOD, CM_CLKSEL); /* x2 to enter init_mem */ omap2_reprogram_sdrc(CORE_CLK_SRC_DPLL_X2, 1); omap2_set_prcm(prcm->cm_clksel1_pll, prcm->base_sdrc_rfr, bypass); omap2_init_memory_params(omap2_dll_force_needed()); omap2_reprogram_sdrc(done_rate, 0); local_irq_restore(flags); } omap2_dpll_recalc(&dpll_ck); return 0; }
static int omap2_reprogram_dpll(struct clk *clk, unsigned long rate) { u32 cur_rate, low, mult, div, valid_rate, done_rate; u32 bypass = 0; struct prcm_config tmpset; const struct dpll_data *dd; unsigned long flags; int ret = -EINVAL; local_irq_save(flags); cur_rate = omap2_get_dpll_rate_24xx(&dpll_ck); mult = cm_read_mod_reg(PLL_MOD, CM_CLKSEL2); mult &= OMAP24XX_CORE_CLK_SRC_MASK; if ((rate == (cur_rate / 2)) && (mult == 2)) { omap2_reprogram_sdrc(CORE_CLK_SRC_DPLL, 1); } else if ((rate == (cur_rate * 2)) && (mult == 1)) { omap2_reprogram_sdrc(CORE_CLK_SRC_DPLL_X2, 1); } else if (rate != cur_rate) { valid_rate = omap2_dpll_round_rate(rate); if (valid_rate != rate) goto dpll_exit; if (mult == 1) low = curr_prcm_set->dpll_speed; else low = curr_prcm_set->dpll_speed / 2; dd = clk->dpll_data; if (!dd) goto dpll_exit; tmpset.cm_clksel1_pll = __raw_readl(dd->mult_div1_reg); tmpset.cm_clksel1_pll &= ~(dd->mult_mask | dd->div1_mask); div = ((curr_prcm_set->xtal_speed / 1000000) - 1); tmpset.cm_clksel2_pll = cm_read_mod_reg(PLL_MOD, CM_CLKSEL2); tmpset.cm_clksel2_pll &= ~OMAP24XX_CORE_CLK_SRC_MASK; if (rate > low) { tmpset.cm_clksel2_pll |= CORE_CLK_SRC_DPLL_X2; mult = ((rate / 2) / 1000000); done_rate = CORE_CLK_SRC_DPLL_X2; } else { tmpset.cm_clksel2_pll |= CORE_CLK_SRC_DPLL; mult = (rate / 1000000); done_rate = CORE_CLK_SRC_DPLL; } tmpset.cm_clksel1_pll |= (div << __ffs(dd->mult_mask)); tmpset.cm_clksel1_pll |= (mult << __ffs(dd->div1_mask)); /* Worst case */ tmpset.base_sdrc_rfr = SDRC_RFR_CTRL_BYPASS; if (rate == curr_prcm_set->xtal_speed) /* If asking for 1-1 */ bypass = 1; omap2_reprogram_sdrc(CORE_CLK_SRC_DPLL_X2, 1); /* For init_mem */ /* Force dll lock mode */ omap2_set_prcm(tmpset.cm_clksel1_pll, tmpset.base_sdrc_rfr, bypass); /* Errata: ret dll entry state */ omap2_init_memory_params(omap2_dll_force_needed()); omap2_reprogram_sdrc(done_rate, 0); } omap2_dpll_recalc(&dpll_ck); ret = 0; dpll_exit: local_irq_restore(flags); return(ret); }
int omap2_reprogram_dpllcore(struct clk *clk, unsigned long rate) { u32 cur_rate, low, mult, div, valid_rate, done_rate; u32 bypass = 0; struct prcm_config tmpset; const struct dpll_data *dd; cur_rate = omap2xxx_clk_get_core_rate(dclk); mult = cm_read_mod_reg(PLL_MOD, CM_CLKSEL2); mult &= OMAP24XX_CORE_CLK_SRC_MASK; if ((rate == (cur_rate / 2)) && (mult == 2)) { omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL, 1); } else if ((rate == (cur_rate * 2)) && (mult == 1)) { omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL_X2, 1); } else if (rate != cur_rate) { valid_rate = omap2_dpllcore_round_rate(rate); if (valid_rate != rate) return -EINVAL; if (mult == 1) low = curr_prcm_set->dpll_speed; else low = curr_prcm_set->dpll_speed / 2; dd = clk->dpll_data; if (!dd) return -EINVAL; tmpset.cm_clksel1_pll = __raw_readl(dd->mult_div1_reg); tmpset.cm_clksel1_pll &= ~(dd->mult_mask | dd->div1_mask); div = ((curr_prcm_set->xtal_speed / 1000000) - 1); tmpset.cm_clksel2_pll = cm_read_mod_reg(PLL_MOD, CM_CLKSEL2); tmpset.cm_clksel2_pll &= ~OMAP24XX_CORE_CLK_SRC_MASK; if (rate > low) { tmpset.cm_clksel2_pll |= CORE_CLK_SRC_DPLL_X2; mult = ((rate / 2) / 1000000); done_rate = CORE_CLK_SRC_DPLL_X2; } else { tmpset.cm_clksel2_pll |= CORE_CLK_SRC_DPLL; mult = (rate / 1000000); done_rate = CORE_CLK_SRC_DPLL; } tmpset.cm_clksel1_pll |= (div << __ffs(dd->mult_mask)); tmpset.cm_clksel1_pll |= (mult << __ffs(dd->div1_mask)); /* Worst case */ tmpset.base_sdrc_rfr = SDRC_RFR_CTRL_BYPASS; if (rate == curr_prcm_set->xtal_speed) /* If asking for 1-1 */ bypass = 1; /* For omap2xxx_sdrc_init_params() */ omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL_X2, 1); /* Force dll lock mode */ omap2_set_prcm(tmpset.cm_clksel1_pll, tmpset.base_sdrc_rfr, bypass); /* Errata: ret dll entry state */ omap2xxx_sdrc_init_params(omap2xxx_sdrc_dll_is_unlocked()); omap2xxx_sdrc_reprogram(done_rate, 0); } return 0; }
void omap3_prcm_save_context(void) { prcm_context.control_padconf_sys_nirq = omap_ctrl_readl(OMAP343X_CONTROL_PADCONF_SYSNIRQ); prcm_context.iva2_cm_clksel1 = cm_read_mod_reg(OMAP3430_IVA2_MOD, CM_CLKSEL1); prcm_context.iva2_cm_clksel2 = cm_read_mod_reg(OMAP3430_IVA2_MOD, CM_CLKSEL2); prcm_context.cm_sysconfig = __raw_readl(OMAP3430_CM_SYSCONFIG); prcm_context.sgx_cm_clksel = cm_read_mod_reg(OMAP3430ES2_SGX_MOD, CM_CLKSEL); prcm_context.dss_cm_clksel = cm_read_mod_reg(OMAP3430_DSS_MOD, CM_CLKSEL); prcm_context.cam_cm_clksel = cm_read_mod_reg(OMAP3430_CAM_MOD, CM_CLKSEL); prcm_context.per_cm_clksel = cm_read_mod_reg(OMAP3430_PER_MOD, CM_CLKSEL); prcm_context.emu_cm_clksel = cm_read_mod_reg(OMAP3430_EMU_MOD, CM_CLKSEL1); prcm_context.emu_cm_clkstctrl = cm_read_mod_reg(OMAP3430_EMU_MOD, OMAP2_CM_CLKSTCTRL); prcm_context.pll_cm_autoidle2 = cm_read_mod_reg(PLL_MOD, CM_AUTOIDLE2); prcm_context.pll_cm_clksel4 = cm_read_mod_reg(PLL_MOD, OMAP3430ES2_CM_CLKSEL4); prcm_context.pll_cm_clksel5 = cm_read_mod_reg(PLL_MOD, OMAP3430ES2_CM_CLKSEL5); prcm_context.pll_cm_clken2 = cm_read_mod_reg(PLL_MOD, OMAP3430ES2_CM_CLKEN2); prcm_context.cm_polctrl = __raw_readl(OMAP3430_CM_POLCTRL); prcm_context.iva2_cm_fclken = cm_read_mod_reg(OMAP3430_IVA2_MOD, CM_FCLKEN); prcm_context.iva2_cm_clken_pll = cm_read_mod_reg(OMAP3430_IVA2_MOD, OMAP3430_CM_CLKEN_PLL); prcm_context.core_cm_fclken1 = cm_read_mod_reg(CORE_MOD, CM_FCLKEN1); prcm_context.core_cm_fclken3 = cm_read_mod_reg(CORE_MOD, OMAP3430ES2_CM_FCLKEN3); prcm_context.sgx_cm_fclken = cm_read_mod_reg(OMAP3430ES2_SGX_MOD, CM_FCLKEN); prcm_context.wkup_cm_fclken = cm_read_mod_reg(WKUP_MOD, CM_FCLKEN); prcm_context.dss_cm_fclken = cm_read_mod_reg(OMAP3430_DSS_MOD, CM_FCLKEN); prcm_context.cam_cm_fclken = cm_read_mod_reg(OMAP3430_CAM_MOD, CM_FCLKEN); prcm_context.per_cm_fclken = cm_read_mod_reg(OMAP3430_PER_MOD, CM_FCLKEN); prcm_context.usbhost_cm_fclken = cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD, CM_FCLKEN); prcm_context.core_cm_iclken1 = cm_read_mod_reg(CORE_MOD, CM_ICLKEN1); prcm_context.core_cm_iclken2 = cm_read_mod_reg(CORE_MOD, CM_ICLKEN2); prcm_context.core_cm_iclken3 = cm_read_mod_reg(CORE_MOD, CM_ICLKEN3); prcm_context.sgx_cm_iclken = cm_read_mod_reg(OMAP3430ES2_SGX_MOD, CM_ICLKEN); prcm_context.wkup_cm_iclken = cm_read_mod_reg(WKUP_MOD, CM_ICLKEN); prcm_context.dss_cm_iclken = cm_read_mod_reg(OMAP3430_DSS_MOD, CM_ICLKEN); prcm_context.cam_cm_iclken = cm_read_mod_reg(OMAP3430_CAM_MOD, CM_ICLKEN); prcm_context.per_cm_iclken = cm_read_mod_reg(OMAP3430_PER_MOD, CM_ICLKEN); prcm_context.usbhost_cm_iclken = cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD, CM_ICLKEN); prcm_context.iva2_cm_autiidle2 = cm_read_mod_reg(OMAP3430_IVA2_MOD, CM_AUTOIDLE2); prcm_context.mpu_cm_autoidle2 = cm_read_mod_reg(MPU_MOD, CM_AUTOIDLE2); prcm_context.iva2_cm_clkstctrl = cm_read_mod_reg(OMAP3430_IVA2_MOD, OMAP2_CM_CLKSTCTRL); prcm_context.mpu_cm_clkstctrl = cm_read_mod_reg(MPU_MOD, OMAP2_CM_CLKSTCTRL); prcm_context.core_cm_clkstctrl = cm_read_mod_reg(CORE_MOD, OMAP2_CM_CLKSTCTRL); prcm_context.sgx_cm_clkstctrl = cm_read_mod_reg(OMAP3430ES2_SGX_MOD, OMAP2_CM_CLKSTCTRL); prcm_context.dss_cm_clkstctrl = cm_read_mod_reg(OMAP3430_DSS_MOD, OMAP2_CM_CLKSTCTRL); prcm_context.cam_cm_clkstctrl = cm_read_mod_reg(OMAP3430_CAM_MOD, OMAP2_CM_CLKSTCTRL); prcm_context.per_cm_clkstctrl = cm_read_mod_reg(OMAP3430_PER_MOD, OMAP2_CM_CLKSTCTRL); prcm_context.neon_cm_clkstctrl = cm_read_mod_reg(OMAP3430_NEON_MOD, OMAP2_CM_CLKSTCTRL); prcm_context.usbhost_cm_clkstctrl = cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD, OMAP2_CM_CLKSTCTRL); prcm_context.core_cm_autoidle1 = cm_read_mod_reg(CORE_MOD, CM_AUTOIDLE1); prcm_context.core_cm_autoidle2 = cm_read_mod_reg(CORE_MOD, CM_AUTOIDLE2); prcm_context.core_cm_autoidle3 = cm_read_mod_reg(CORE_MOD, CM_AUTOIDLE3); prcm_context.wkup_cm_autoidle = cm_read_mod_reg(WKUP_MOD, CM_AUTOIDLE); prcm_context.dss_cm_autoidle = cm_read_mod_reg(OMAP3430_DSS_MOD, CM_AUTOIDLE); prcm_context.cam_cm_autoidle = cm_read_mod_reg(OMAP3430_CAM_MOD, CM_AUTOIDLE); prcm_context.per_cm_autoidle = cm_read_mod_reg(OMAP3430_PER_MOD, CM_AUTOIDLE); prcm_context.usbhost_cm_autoidle = cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD, CM_AUTOIDLE); prcm_context.sgx_cm_sleepdep = cm_read_mod_reg(OMAP3430ES2_SGX_MOD, OMAP3430_CM_SLEEPDEP); prcm_context.dss_cm_sleepdep = cm_read_mod_reg(OMAP3430_DSS_MOD, OMAP3430_CM_SLEEPDEP); prcm_context.cam_cm_sleepdep = cm_read_mod_reg(OMAP3430_CAM_MOD, OMAP3430_CM_SLEEPDEP); prcm_context.per_cm_sleepdep = cm_read_mod_reg(OMAP3430_PER_MOD, OMAP3430_CM_SLEEPDEP); prcm_context.usbhost_cm_sleepdep = cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD, OMAP3430_CM_SLEEPDEP); prcm_context.cm_clkout_ctrl = cm_read_mod_reg(OMAP3430_CCR_MOD, OMAP3_CM_CLKOUT_CTRL_OFFSET); prcm_context.prm_clkout_ctrl = prm_read_mod_reg(OMAP3430_CCR_MOD, OMAP3_PRM_CLKOUT_CTRL_OFFSET); prcm_context.sgx_pm_wkdep = prm_read_mod_reg(OMAP3430ES2_SGX_MOD, PM_WKDEP); prcm_context.dss_pm_wkdep = prm_read_mod_reg(OMAP3430_DSS_MOD, PM_WKDEP); prcm_context.cam_pm_wkdep = prm_read_mod_reg(OMAP3430_CAM_MOD, PM_WKDEP); prcm_context.per_pm_wkdep = prm_read_mod_reg(OMAP3430_PER_MOD, PM_WKDEP); prcm_context.neon_pm_wkdep = prm_read_mod_reg(OMAP3430_NEON_MOD, PM_WKDEP); prcm_context.usbhost_pm_wkdep = prm_read_mod_reg(OMAP3430ES2_USBHOST_MOD, PM_WKDEP); prcm_context.core_pm_mpugrpsel1 = prm_read_mod_reg(CORE_MOD, OMAP3430_PM_MPUGRPSEL1); prcm_context.iva2_pm_ivagrpsel1 = prm_read_mod_reg(OMAP3430_IVA2_MOD, OMAP3430_PM_IVAGRPSEL1); prcm_context.core_pm_mpugrpsel3 = prm_read_mod_reg(CORE_MOD, OMAP3430ES2_PM_MPUGRPSEL3); prcm_context.core_pm_ivagrpsel3 = prm_read_mod_reg(CORE_MOD, OMAP3430ES2_PM_IVAGRPSEL3); prcm_context.wkup_pm_mpugrpsel = prm_read_mod_reg(WKUP_MOD, OMAP3430_PM_MPUGRPSEL); prcm_context.wkup_pm_ivagrpsel = prm_read_mod_reg(WKUP_MOD, OMAP3430_PM_IVAGRPSEL); prcm_context.per_pm_mpugrpsel = prm_read_mod_reg(OMAP3430_PER_MOD, OMAP3430_PM_MPUGRPSEL); prcm_context.per_pm_ivagrpsel = prm_read_mod_reg(OMAP3430_PER_MOD, OMAP3430_PM_IVAGRPSEL); prcm_context.wkup_pm_wken = prm_read_mod_reg(WKUP_MOD, PM_WKEN); return; }