For upcoming notifier support, modify the rate recalculation code to
take parent rate and rate storage parameters. The goal here is to
allow the clock code to determine what the clock's rate would be after
a parent change or a rate change, without actually changing the
hardware registers. This is used by the upcoming notifier patches to
pass a clock's current and planned rates to the notifier callbacks.
Also add a new clock flag, RECALC_ON_ENABLE, which causes the clock
framework code to recalculate the current clock's rate and propagate
down the tree after a clk_enable() or clk_disable(). This is used by
the OMAP3 DPLLs, which change rates when they enable or disable, unlike
most clocks.
Signed-off-by: Paul Walmsley <paul@pwsan.com>
Signed-off-by: Tony Lindgren <tony@atomide.com>
* Omap1 specific clock functions
*-------------------------------------------------------------------------*/
* Omap1 specific clock functions
*-------------------------------------------------------------------------*/
-static void omap1_watchdog_recalc(struct clk * clk)
+static void omap1_watchdog_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage)
- clk->rate = clk->parent->rate / 14;
+ unsigned long new_rate;
+
+ new_rate = parent_rate / 14;
+
+ if (rate_storage == CURRENT_RATE)
+ clk->rate = new_rate;
+ else if (rate_storage == TEMP_RATE)
+ clk->temp_rate = new_rate;
-static void omap1_uart_recalc(struct clk * clk)
+static void omap1_uart_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage)
+ unsigned long new_rate;
unsigned int val = __raw_readl(clk->enable_reg);
unsigned int val = __raw_readl(clk->enable_reg);
if (val & clk->enable_bit)
if (val & clk->enable_bit)
+ new_rate = 12000000;
+
+ if (rate_storage == CURRENT_RATE)
+ clk->rate = new_rate;
+ else if (rate_storage == TEMP_RATE)
+ clk->temp_rate = new_rate;
-static void omap1_sossi_recalc(struct clk *clk)
+static void omap1_sossi_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage)
+ unsigned long new_rate;
u32 div = omap_readl(MOD_CONF_CTRL_1);
div = (div >> 17) & 0x7;
div++;
u32 div = omap_readl(MOD_CONF_CTRL_1);
div = (div >> 17) & 0x7;
div++;
- clk->rate = clk->parent->rate / div;
+ new_rate = clk->parent->rate / div;
+
+ if (rate_storage == CURRENT_RATE)
+ clk->rate = new_rate;
+ else if (rate_storage == TEMP_RATE)
+ clk->temp_rate = new_rate;
}
static int omap1_clk_enable_dsp_domain(struct clk *clk)
}
static int omap1_clk_enable_dsp_domain(struct clk *clk)
-static void omap1_ckctl_recalc(struct clk * clk)
+static void omap1_ckctl_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage)
+ unsigned long new_rate;
/* Calculate divisor encoded as 2-bit exponent */
dsor = 1 << (3 & (omap_readw(ARM_CKCTL) >> clk->rate_offset));
/* Calculate divisor encoded as 2-bit exponent */
dsor = 1 << (3 & (omap_readw(ARM_CKCTL) >> clk->rate_offset));
- if (unlikely(clk->rate == clk->parent->rate / dsor))
+ new_rate = parent_rate / dsor;
+
+ if (unlikely(clk->rate == new_rate))
return; /* No change, quick exit */
return; /* No change, quick exit */
- clk->rate = clk->parent->rate / dsor;
+
+ if (rate_storage == CURRENT_RATE)
+ clk->rate = new_rate;
+ else if (rate_storage == TEMP_RATE)
+ clk->temp_rate = new_rate;
-static void omap1_ckctl_recalc_dsp_domain(struct clk * clk)
+static void omap1_ckctl_recalc_dsp_domain(struct clk *clk,
+ unsigned long parent_rate,
+ u8 rate_storage)
+ unsigned long new_rate;
/* Calculate divisor encoded as 2-bit exponent
*
/* Calculate divisor encoded as 2-bit exponent
*
dsor = 1 << (3 & (__raw_readw(DSP_CKCTL) >> clk->rate_offset));
omap1_clk_disable(&api_ck.clk);
dsor = 1 << (3 & (__raw_readw(DSP_CKCTL) >> clk->rate_offset));
omap1_clk_disable(&api_ck.clk);
- if (unlikely(clk->rate == clk->parent->rate / dsor))
+ new_rate = parent_rate / dsor;
+
+ if (unlikely(clk->rate == new_rate))
return; /* No change, quick exit */
return; /* No change, quick exit */
- clk->rate = clk->parent->rate / dsor;
+
+ if (rate_storage == CURRENT_RATE)
+ clk->rate = new_rate;
+ else if (rate_storage == TEMP_RATE)
+ clk->temp_rate = new_rate;
}
/* MPU virtual clock functions */
}
/* MPU virtual clock functions */
omap_sram_reprogram_clock(ptr->dpllctl_val, ptr->ckctl_val);
ck_dpll1.rate = ptr->pll_rate;
omap_sram_reprogram_clock(ptr->dpllctl_val, ptr->ckctl_val);
ck_dpll1.rate = ptr->pll_rate;
- propagate_rate(&ck_dpll1);
+ propagate_rate(&ck_dpll1, CURRENT_RATE);
- propagate_rate(&ck_dpll1);
+ propagate_rate(&ck_dpll1, CURRENT_RATE);
#else
/* Find the highest supported frequency and enable it */
if (omap1_select_table_rate(&virtual_ck_mpu, ~0)) {
#else
/* Find the highest supported frequency and enable it */
if (omap1_select_table_rate(&virtual_ck_mpu, ~0)) {
omap_writew(0x2290, DPLL_CTL);
omap_writew(cpu_is_omap730() ? 0x3005 : 0x1005, ARM_CKCTL);
ck_dpll1.rate = 60000000;
omap_writew(0x2290, DPLL_CTL);
omap_writew(cpu_is_omap730() ? 0x3005 : 0x1005, ARM_CKCTL);
ck_dpll1.rate = 60000000;
- propagate_rate(&ck_dpll1);
+ propagate_rate(&ck_dpll1, CURRENT_RATE);
}
#endif
/* Cache rates for clocks connected to ck_ref (not dpll1) */
}
#endif
/* Cache rates for clocks connected to ck_ref (not dpll1) */
- propagate_rate(&ck_ref);
+ propagate_rate(&ck_ref, CURRENT_RATE);
printk(KERN_INFO "Clocking rate (xtal/DPLL1/MPU): "
"%ld.%01ld/%ld.%01ld/%ld.%01ld MHz\n",
ck_ref.rate / 1000000, (ck_ref.rate / 100000) % 10,
printk(KERN_INFO "Clocking rate (xtal/DPLL1/MPU): "
"%ld.%01ld/%ld.%01ld/%ld.%01ld MHz\n",
ck_ref.rate / 1000000, (ck_ref.rate / 100000) % 10,
static int omap1_clk_enable_generic(struct clk * clk);
static void omap1_clk_disable_generic(struct clk * clk);
static int omap1_clk_enable_generic(struct clk * clk);
static void omap1_clk_disable_generic(struct clk * clk);
-static void omap1_ckctl_recalc(struct clk * clk);
-static void omap1_watchdog_recalc(struct clk * clk);
+static void omap1_ckctl_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage);
+static void omap1_watchdog_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage);
static int omap1_set_sossi_rate(struct clk *clk, unsigned long rate);
static int omap1_set_sossi_rate(struct clk *clk, unsigned long rate);
-static void omap1_sossi_recalc(struct clk *clk);
-static void omap1_ckctl_recalc_dsp_domain(struct clk * clk);
+static void omap1_sossi_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage);
+static void omap1_ckctl_recalc_dsp_domain(struct clk *clk,
+ unsigned long parent_rate,
+ u8 rate_storage);
static int omap1_clk_enable_dsp_domain(struct clk * clk);
static int omap1_clk_set_rate_dsp_domain(struct clk * clk, unsigned long rate);
static void omap1_clk_disable_dsp_domain(struct clk * clk);
static int omap1_set_uart_rate(struct clk * clk, unsigned long rate);
static int omap1_clk_enable_dsp_domain(struct clk * clk);
static int omap1_clk_set_rate_dsp_domain(struct clk * clk, unsigned long rate);
static void omap1_clk_disable_dsp_domain(struct clk * clk);
static int omap1_set_uart_rate(struct clk * clk, unsigned long rate);
-static void omap1_uart_recalc(struct clk * clk);
+static void omap1_uart_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage);
static int omap1_clk_enable_uart_functional(struct clk * clk);
static void omap1_clk_disable_uart_functional(struct clk * clk);
static int omap1_set_ext_clk_rate(struct clk * clk, unsigned long rate);
static int omap1_clk_enable_uart_functional(struct clk * clk);
static void omap1_clk_disable_uart_functional(struct clk * clk);
static int omap1_set_ext_clk_rate(struct clk * clk, unsigned long rate);
/**
* omap2_get_dpll_rate - returns the current DPLL CLKOUT rate
* @clk: struct clk * of a DPLL
/**
* omap2_get_dpll_rate - returns the current DPLL CLKOUT rate
* @clk: struct clk * of a DPLL
+ * @parent_rate: rate of the parent of the DPLL clock
*
* DPLLs can be locked or bypassed - basically, enabled or disabled.
* When locked, the DPLL output depends on the M and N values. When
*
* DPLLs can be locked or bypassed - basically, enabled or disabled.
* When locked, the DPLL output depends on the M and N values. When
* locked, or the appropriate bypass rate if the DPLL is bypassed, or 0
* if the clock @clk is not a DPLL.
*/
* locked, or the appropriate bypass rate if the DPLL is bypassed, or 0
* if the clock @clk is not a DPLL.
*/
-u32 omap2_get_dpll_rate(struct clk *clk)
+u32 omap2_get_dpll_rate(struct clk *clk, unsigned long parent_rate)
{
long long dpll_clk;
u32 dpll_mult, dpll_div, v;
{
long long dpll_clk;
u32 dpll_mult, dpll_div, v;
if (v == OMAP2XXX_EN_DPLL_LPBYPASS ||
v == OMAP2XXX_EN_DPLL_FRBYPASS)
if (v == OMAP2XXX_EN_DPLL_LPBYPASS ||
v == OMAP2XXX_EN_DPLL_FRBYPASS)
- return clk->parent->rate;
} else if (cpu_is_omap34xx()) {
} else if (cpu_is_omap34xx()) {
dpll_div = v & dd->div1_mask;
dpll_div >>= __ffs(dd->div1_mask);
dpll_div = v & dd->div1_mask;
dpll_div >>= __ffs(dd->div1_mask);
- dpll_clk = (long long)clk->parent->rate * dpll_mult;
+ dpll_clk = (long long)parent_rate * dpll_mult;
do_div(dpll_clk, dpll_div + 1);
return dpll_clk;
do_div(dpll_clk, dpll_div + 1);
return dpll_clk;
* Used for clocks that have the same value as the parent clock,
* divided by some factor
*/
* Used for clocks that have the same value as the parent clock,
* divided by some factor
*/
-void omap2_fixed_divisor_recalc(struct clk *clk)
+void omap2_fixed_divisor_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage)
- WARN_ON(!clk->fixed_div);
- clk->rate = clk->parent->rate / clk->fixed_div;
+ WARN_ON(!clk->fixed_div); /* XXX move this to init */
+
+ rate = parent_rate / clk->fixed_div;
+
+ if (rate_storage == CURRENT_RATE)
+ clk->rate = rate;
+ else if (rate_storage == TEMP_RATE)
+ clk->temp_rate = rate;
* Used for clocks that are part of CLKSEL_xyz governed clocks.
* REVISIT: Maybe change to use clk->enable() functions like on omap1?
*/
* Used for clocks that are part of CLKSEL_xyz governed clocks.
* REVISIT: Maybe change to use clk->enable() functions like on omap1?
*/
-void omap2_clksel_recalc(struct clk *clk)
+void omap2_clksel_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage)
pr_debug("clock: recalc'ing clksel clk %s\n", clk->name);
pr_debug("clock: recalc'ing clksel clk %s\n", clk->name);
- if (clk->rate == (clk->parent->rate / div))
- return;
- clk->rate = clk->parent->rate / div;
+ rate = parent_rate / div;
+
+ if (rate_storage == CURRENT_RATE)
+ clk->rate = rate;
+ else if (rate_storage == TEMP_RATE)
+ clk->temp_rate = rate;
pr_debug("clock: new clock rate is %ld (div %d)\n", clk->rate, div);
}
pr_debug("clock: new clock rate is %ld (div %d)\n", clk->rate, div);
}
#define omap2_clk_disable_unused NULL
#endif
#define omap2_clk_disable_unused NULL
#endif
-void omap2_clksel_recalc(struct clk *clk);
+void omap2_clksel_recalc(struct clk *clk, unsigned long new_parent_rate,
+ u8 rate_storage);
void omap2_init_clk_clkdm(struct clk *clk);
void omap2_init_clksel_parent(struct clk *clk);
u32 omap2_clksel_get_divisor(struct clk *clk);
void omap2_init_clk_clkdm(struct clk *clk);
void omap2_init_clksel_parent(struct clk *clk);
u32 omap2_clksel_get_divisor(struct clk *clk);
u32 *new_div);
u32 omap2_clksel_to_divisor(struct clk *clk, u32 field_val);
u32 omap2_divisor_to_clksel(struct clk *clk, u32 div);
u32 *new_div);
u32 omap2_clksel_to_divisor(struct clk *clk, u32 field_val);
u32 omap2_divisor_to_clksel(struct clk *clk, u32 div);
-void omap2_fixed_divisor_recalc(struct clk *clk);
+void omap2_fixed_divisor_recalc(struct clk *clk, unsigned long new_parent_rate,
+ u8 rate_storage);
long omap2_clksel_round_rate(struct clk *clk, unsigned long target_rate);
int omap2_clksel_set_rate(struct clk *clk, unsigned long rate);
long omap2_clksel_round_rate(struct clk *clk, unsigned long target_rate);
int omap2_clksel_set_rate(struct clk *clk, unsigned long rate);
-u32 omap2_get_dpll_rate(struct clk *clk);
+u32 omap2_get_dpll_rate(struct clk *clk, unsigned long parent_rate);
int omap2_wait_clock_ready(s16 prcm_mod, u16 idlest_reg, u32 cval,
const char *name);
void omap2_clk_prepare_for_reboot(void);
int omap2_wait_clock_ready(s16 prcm_mod, u16 idlest_reg, u32 cval,
const char *name);
void omap2_clk_prepare_for_reboot(void);
/**
* omap2xxx_clk_get_core_rate - return the CORE_CLK rate
* @clk: pointer to the combined dpll_ck + core_ck (currently "dpll_ck")
/**
* omap2xxx_clk_get_core_rate - return the CORE_CLK rate
* @clk: pointer to the combined dpll_ck + core_ck (currently "dpll_ck")
+ * @parent_rate: rate of the parent of the 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
*
* Returns the CORE_CLK rate. CORE_CLK can have one of three rate
* sources on OMAP2xxx: the DPLL CLKOUT rate, DPLL CLKOUTX2, or 32KHz
* struct clk *dpll_ck, which is a composite clock of dpll_ck and
* core_ck.
*/
* struct clk *dpll_ck, which is a composite clock of dpll_ck and
* core_ck.
*/
-static u32 omap2xxx_clk_get_core_rate(struct clk *clk)
+static u32 omap2xxx_clk_get_core_rate(struct clk *clk,
+ unsigned long parent_rate)
{
long long core_clk;
u32 v;
{
long long core_clk;
u32 v;
- core_clk = omap2_get_dpll_rate(clk);
+ core_clk = omap2_get_dpll_rate(clk, parent_rate);
v = cm_read_mod_reg(PLL_MOD, CM_CLKSEL2);
v &= OMAP24XX_CORE_CLK_SRC_MASK;
v = cm_read_mod_reg(PLL_MOD, CM_CLKSEL2);
v &= OMAP24XX_CORE_CLK_SRC_MASK;
+static unsigned long omap2xxx_clk_find_oppset_by_mpurate(unsigned long mpu_speed,
+ struct prcm_config **prcm)
+{
+ unsigned long found_speed = 0;
+ struct prcm_config *p;
+
+ p = *prcm;
+
+ for (p = rate_table; p->mpu_speed; p++) {
+ if (!(p->flags & cpu_mask))
+ continue;
+
+ if (p->xtal_speed != sys_ck.rate)
+ continue;
+
+ if (p->mpu_speed <= mpu_speed) {
+ found_speed = p->mpu_speed;
+ break;
+ }
+ }
+
+ return found_speed;
+}
+
static int omap2_enable_osc_ck(struct clk *clk)
{
prm_rmw_mod_reg_bits(OMAP_AUTOEXTCLKMODE_MASK, 0,
static int omap2_enable_osc_ck(struct clk *clk)
{
prm_rmw_mod_reg_bits(OMAP_AUTOEXTCLKMODE_MASK, 0,
-static void omap2_dpllcore_recalc(struct clk *clk)
+static void omap2_dpllcore_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage)
- clk->rate = omap2xxx_clk_get_core_rate(clk);
+ unsigned long rate;
+
+ rate = omap2xxx_clk_get_core_rate(clk, parent_rate);
+
+ if (rate_storage == CURRENT_RATE)
+ clk->rate = rate;
+ else if (rate_storage == TEMP_RATE)
+ clk->temp_rate = rate;
}
static int omap2_reprogram_dpllcore(struct clk *clk, unsigned long rate)
}
static int omap2_reprogram_dpllcore(struct clk *clk, unsigned long rate)
int ret = -EINVAL;
local_irq_save(flags);
int ret = -EINVAL;
local_irq_save(flags);
- cur_rate = omap2xxx_clk_get_core_rate(&dpll_ck);
+ cur_rate = omap2xxx_clk_get_core_rate(&dpll_ck, dpll_ck.parent->rate);
mult = cm_read_mod_reg(PLL_MOD, CM_CLKSEL2);
mult &= OMAP24XX_CORE_CLK_SRC_MASK;
mult = cm_read_mod_reg(PLL_MOD, CM_CLKSEL2);
mult &= OMAP24XX_CORE_CLK_SRC_MASK;
*
* Set virt_prcm_set's rate to the mpu_speed field of the current PRCM set.
*/
*
* Set virt_prcm_set's rate to the mpu_speed field of the current PRCM set.
*/
-static void omap2_table_mpu_recalc(struct clk *clk)
+static void omap2_table_mpu_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage)
- clk->rate = curr_prcm_set->mpu_speed;
+ struct prcm_config *prcm;
+ unsigned long mpurate;
+
+ mpurate = omap2xxx_clk_find_oppset_by_mpurate(parent_rate, &prcm);
+
+ if (rate_storage == CURRENT_RATE)
+ clk->rate = mpurate;
+ else if (rate_storage == TEMP_RATE)
+ clk->temp_rate = mpurate;
{
u32 cur_rate, done_rate, bypass = 0, tmp;
struct prcm_config *prcm;
{
u32 cur_rate, done_rate, bypass = 0, tmp;
struct prcm_config *prcm;
- unsigned long found_speed = 0;
- unsigned long flags;
+ unsigned long flags, found_speed;
if (clk != &virt_prcm_set)
return -EINVAL;
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;
- }
- }
-
+ found_speed = omap2xxx_clk_find_oppset_by_mpurate(rate, &prcm);
if (!found_speed) {
printk(KERN_INFO "Could not set MPU rate to %luMHz\n",
rate / 1000000);
if (!found_speed) {
printk(KERN_INFO "Could not set MPU rate to %luMHz\n",
rate / 1000000);
- cur_rate = omap2xxx_clk_get_core_rate(&dpll_ck);
+ cur_rate = omap2xxx_clk_get_core_rate(&dpll_ck, dpll_ck.parent->rate);
if (prcm->dpll_speed == cur_rate / 2) {
omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL, 1);
if (prcm->dpll_speed == cur_rate / 2) {
omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL, 1);
-static void omap2_osc_clk_recalc(struct clk *clk)
+static void omap2_osc_clk_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage)
- clk->rate = omap2_get_apll_clkin() * omap2_get_sysclkdiv();
+ unsigned long rate;
+
+ /* XXX osc_ck on 2xxx currently is parentless */
+ rate = omap2_get_apll_clkin() * omap2_get_sysclkdiv();
+
+ if (rate_storage == CURRENT_RATE)
+ clk->rate = rate;
+ else if (rate_storage == TEMP_RATE)
+ clk->temp_rate = rate;
-static void omap2_sys_clk_recalc(struct clk *clk)
+static void omap2_sys_clk_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage)
- clk->rate = clk->parent->rate / omap2_get_sysclkdiv();
+ unsigned long rate;
+
+ rate = parent_rate / omap2_get_sysclkdiv();
+
+ if (rate_storage == CURRENT_RATE)
+ clk->rate = rate;
+ else if (rate_storage == TEMP_RATE)
+ clk->temp_rate = rate;
clk_init(&omap2_clk_functions);
clk_init(&omap2_clk_functions);
- omap2_osc_clk_recalc(&osc_ck);
- omap2_sys_clk_recalc(&sys_ck);
+ omap2_osc_clk_recalc(&osc_ck, 0, CURRENT_RATE);
+ omap2_sys_clk_recalc(&sys_ck, sys_ck.parent->rate, CURRENT_RATE);
for (clkp = onchip_24xx_clks;
clkp < onchip_24xx_clks + ARRAY_SIZE(onchip_24xx_clks);
for (clkp = onchip_24xx_clks;
clkp < onchip_24xx_clks + ARRAY_SIZE(onchip_24xx_clks);
}
/* Check the MPU rate set by bootloader */
}
/* Check the MPU rate set by bootloader */
- clkrate = omap2xxx_clk_get_core_rate(&dpll_ck);
+ clkrate = omap2xxx_clk_get_core_rate(&dpll_ck, dpll_ck.parent->rate);
for (prcm = rate_table; prcm->mpu_speed; prcm++) {
if (!(prcm->flags & cpu_mask))
continue;
for (prcm = rate_table; prcm->mpu_speed; prcm++) {
if (!(prcm->flags & cpu_mask))
continue;
#include "cm-regbits-24xx.h"
#include "sdrc.h"
#include "cm-regbits-24xx.h"
#include "sdrc.h"
-static void omap2_table_mpu_recalc(struct clk *clk);
+static void omap2_table_mpu_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage);
static int omap2_select_table_rate(struct clk *clk, unsigned long rate);
static long omap2_round_to_table_rate(struct clk *clk, unsigned long rate);
static int omap2_select_table_rate(struct clk *clk, unsigned long rate);
static long omap2_round_to_table_rate(struct clk *clk, unsigned long rate);
-static void omap2_sys_clk_recalc(struct clk *clk);
-static void omap2_osc_clk_recalc(struct clk *clk);
-static void omap2_sys_clk_recalc(struct clk *clk);
-static void omap2_dpllcore_recalc(struct clk *clk);
+static void omap2_sys_clk_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage);
+static void omap2_osc_clk_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage);
+static void omap2_dpllcore_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage);
static int omap2_clk_fixed_enable(struct clk *clk);
static void omap2_clk_fixed_disable(struct clk *clk);
static int omap2_enable_osc_ck(struct clk *clk);
static int omap2_clk_fixed_enable(struct clk *clk);
static void omap2_clk_fixed_disable(struct clk *clk);
static int omap2_enable_osc_ck(struct clk *clk);
/**
* omap3_dpll_recalc - recalculate DPLL rate
* @clk: DPLL struct clk
/**
* 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.
*/
*
* Recalculate and propagate the DPLL rate.
*/
-static void omap3_dpll_recalc(struct clk *clk)
+static void omap3_dpll_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage)
- clk->rate = omap2_get_dpll_rate(clk);
+ 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;
}
/* _omap3_dpll_write_clken - write clken_bits arg to a DPLL's enable bits */
}
/* _omap3_dpll_write_clken - write clken_bits arg to a DPLL's enable bits */
else
r = _omap3_noncore_dpll_lock(clk);
else
r = _omap3_noncore_dpll_lock(clk);
- if (!r)
- clk->rate = omap2_get_dpll_rate(clk);
-
- if (rate == omap2_get_dpll_rate(clk))
+ if (rate == omap2_get_dpll_rate(clk, clk->parent->rate))
return 0;
if (dd->bypass_clk->rate == rate &&
return 0;
if (dd->bypass_clk->rate == rate &&
/**
* omap3_clkoutx2_recalc - recalculate DPLL X2 output virtual clock rate
* @clk: DPLL output struct clk
/**
* 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.
*/
*
* 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)
+static void omap3_clkoutx2_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage)
{
const struct dpll_data *dd;
u32 v;
{
const struct dpll_data *dd;
u32 v;
struct clk *pclk;
/* Walk up the parents of clk, looking for a DPLL */
struct clk *pclk;
/* Walk up the parents of clk, looking for a DPLL */
WARN_ON(!dd->enable_mask);
WARN_ON(!dd->enable_mask);
v = cm_read_mod_reg(pclk->prcm_mod, dd->control_reg) & dd->enable_mask;
v >>= __ffs(dd->enable_mask);
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)
- clk->rate = clk->parent->rate;
- else
- clk->rate = clk->parent->rate * 2;
+ 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;
}
/* Common clock code */
}
/* Common clock code */
#include "prm.h"
#include "prm-regbits-34xx.h"
#include "prm.h"
#include "prm-regbits-34xx.h"
-static void omap3_dpll_recalc(struct clk *clk);
-static void omap3_clkoutx2_recalc(struct clk *clk);
+static void omap3_dpll_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage);
+static void omap3_clkoutx2_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage);
static void omap3_dpll_allow_idle(struct clk *clk);
static void omap3_dpll_deny_idle(struct clk *clk);
static u32 omap3_dpll_autoidle_read(struct clk *clk);
static void omap3_dpll_allow_idle(struct clk *clk);
static void omap3_dpll_deny_idle(struct clk *clk);
static u32 omap3_dpll_autoidle_read(struct clk *clk);
.parent = &sys_ck,
.prcm_mod = MPU_MOD,
.dpll_data = &dpll1_dd,
.parent = &sys_ck,
.prcm_mod = MPU_MOD,
.dpll_data = &dpll1_dd,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES | ALWAYS_ENABLED,
+ .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
+ ALWAYS_ENABLED | RECALC_ON_ENABLE,
.round_rate = &omap2_dpll_round_rate,
.set_rate = &omap3_noncore_dpll_set_rate,
.clkdm = { .name = "dpll1_clkdm" },
.round_rate = &omap2_dpll_round_rate,
.set_rate = &omap3_noncore_dpll_set_rate,
.clkdm = { .name = "dpll1_clkdm" },
.parent = &sys_ck,
.prcm_mod = OMAP3430_IVA2_MOD,
.dpll_data = &dpll2_dd,
.parent = &sys_ck,
.prcm_mod = OMAP3430_IVA2_MOD,
.dpll_data = &dpll2_dd,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES,
+ .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
+ RECALC_ON_ENABLE,
.enable = &omap3_noncore_dpll_enable,
.disable = &omap3_noncore_dpll_disable,
.round_rate = &omap2_dpll_round_rate,
.enable = &omap3_noncore_dpll_enable,
.disable = &omap3_noncore_dpll_disable,
.round_rate = &omap2_dpll_round_rate,
.parent = &sys_ck,
.prcm_mod = PLL_MOD,
.dpll_data = &dpll3_dd,
.parent = &sys_ck,
.prcm_mod = PLL_MOD,
.dpll_data = &dpll3_dd,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES | ALWAYS_ENABLED,
+ .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
+ ALWAYS_ENABLED | RECALC_ON_ENABLE,
.round_rate = &omap2_dpll_round_rate,
.clkdm = { .name = "dpll3_clkdm" },
.recalc = &omap3_dpll_recalc,
.round_rate = &omap2_dpll_round_rate,
.clkdm = { .name = "dpll3_clkdm" },
.recalc = &omap3_dpll_recalc,
.parent = &sys_ck,
.prcm_mod = PLL_MOD,
.dpll_data = &dpll4_dd,
.parent = &sys_ck,
.prcm_mod = PLL_MOD,
.dpll_data = &dpll4_dd,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES,
+ .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
+ RECALC_ON_ENABLE,
.enable = &omap3_noncore_dpll_enable,
.disable = &omap3_noncore_dpll_disable,
.round_rate = &omap2_dpll_round_rate,
.enable = &omap3_noncore_dpll_enable,
.disable = &omap3_noncore_dpll_disable,
.round_rate = &omap2_dpll_round_rate,
.parent = &sys_ck,
.prcm_mod = PLL_MOD,
.dpll_data = &dpll5_dd,
.parent = &sys_ck,
.prcm_mod = PLL_MOD,
.dpll_data = &dpll5_dd,
- .flags = CLOCK_IN_OMAP3430ES2 | RATE_PROPAGATES,
+ .flags = CLOCK_IN_OMAP3430ES2 | RATE_PROPAGATES |
+ RECALC_ON_ENABLE,
.enable = &omap3_noncore_dpll_enable,
.disable = &omap3_noncore_dpll_disable,
.round_rate = &omap2_dpll_round_rate,
.enable = &omap3_noncore_dpll_enable,
.disable = &omap3_noncore_dpll_disable,
.round_rate = &omap2_dpll_round_rate,
return -EINVAL;
spin_lock_irqsave(&clockfw_lock, flags);
return -EINVAL;
spin_lock_irqsave(&clockfw_lock, flags);
- if (arch_clock->clk_enable)
+ if (arch_clock->clk_enable) {
ret = arch_clock->clk_enable(clk);
ret = arch_clock->clk_enable(clk);
+ if (ret == 0 && clk->flags & RECALC_ON_ENABLE) {
+ if (clk->recalc)
+ (*clk->recalc)(clk, clk->parent->rate,
+ CURRENT_RATE);
+ if (clk->flags & RATE_PROPAGATES)
+ propagate_rate(clk, CURRENT_RATE);
+ }
+ }
+
spin_unlock_irqrestore(&clockfw_lock, flags);
return ret;
spin_unlock_irqrestore(&clockfw_lock, flags);
return ret;
- if (arch_clock->clk_disable)
+ if (arch_clock->clk_disable) {
arch_clock->clk_disable(clk);
arch_clock->clk_disable(clk);
+ if (clk->flags & RECALC_ON_ENABLE) {
+ if (clk->recalc)
+ (*clk->recalc)(clk, clk->parent->rate,
+ CURRENT_RATE);
+ if (clk->flags & RATE_PROPAGATES)
+ propagate_rate(clk, CURRENT_RATE);
+ }
+ }
out:
spin_unlock_irqrestore(&clockfw_lock, flags);
out:
spin_unlock_irqrestore(&clockfw_lock, flags);
ret = arch_clock->clk_set_rate(clk, rate);
if (ret == 0) {
if (clk->recalc)
ret = arch_clock->clk_set_rate(clk, rate);
if (ret == 0) {
if (clk->recalc)
+ (*clk->recalc)(clk, clk->parent->rate,
+ CURRENT_RATE);
if (clk->flags & RATE_PROPAGATES)
if (clk->flags & RATE_PROPAGATES)
+ propagate_rate(clk, CURRENT_RATE);
ret = arch_clock->clk_set_parent(clk, parent);
if (ret == 0) {
if (clk->recalc)
ret = arch_clock->clk_set_parent(clk, parent);
if (ret == 0) {
if (clk->recalc)
+ (*clk->recalc)(clk, clk->parent->rate,
+ CURRENT_RATE);
if (clk->flags & RATE_PROPAGATES)
if (clk->flags & RATE_PROPAGATES)
+ propagate_rate(clk, CURRENT_RATE);
__setup("mpurate=", omap_clk_setup);
/* Used for clocks that always have same value as the parent clock */
__setup("mpurate=", omap_clk_setup);
/* Used for clocks that always have same value as the parent clock */
-void followparent_recalc(struct clk *clk)
+void followparent_recalc(struct clk *clk, unsigned long new_parent_rate,
+ u8 rate_storage)
- if (clk == NULL || IS_ERR(clk))
- return;
-
- clk->rate = clk->parent->rate;
+ if (rate_storage == CURRENT_RATE)
+ clk->rate = new_parent_rate;
+ else if (rate_storage == TEMP_RATE)
+ clk->temp_rate = new_parent_rate;
}
/* Propagate rate to children */
}
/* Propagate rate to children */
-void propagate_rate(struct clk * tclk)
+void propagate_rate(struct clk *tclk, u8 rate_storage)
+ unsigned long parent_rate = 0;
if (tclk == NULL || IS_ERR(tclk))
return;
if (tclk == NULL || IS_ERR(tclk))
return;
list_for_each_entry(clkp, &clocks, node) {
if (likely(clkp->parent != tclk))
continue;
list_for_each_entry(clkp, &clocks, node) {
if (likely(clkp->parent != tclk))
continue;
+
+ if (rate_storage == CURRENT_RATE)
+ parent_rate = tclk->rate;
+ else if (rate_storage == TEMP_RATE)
+ parent_rate = tclk->temp_rate;
+
+ clkp->recalc(clkp, parent_rate, rate_storage);
if (clkp->flags & RATE_PROPAGATES)
if (clkp->flags & RATE_PROPAGATES)
+ propagate_rate(clkp, rate_storage);
list_for_each_entry(clkp, &clocks, node) {
if (unlikely(!clkp->parent)) {
if (clkp->recalc)
list_for_each_entry(clkp, &clocks, node) {
if (unlikely(!clkp->parent)) {
if (clkp->recalc)
+ clkp->recalc(clkp, 0, CURRENT_RATE);
if (clkp->flags & RATE_PROPAGATES)
if (clkp->flags & RATE_PROPAGATES)
+ propagate_rate(clkp, CURRENT_RATE);
int id;
struct clk *parent;
unsigned long rate;
int id;
struct clk *parent;
unsigned long rate;
+ unsigned long temp_rate;
__u32 flags;
u32 enable_reg;
__u8 enable_bit;
__s8 usecount;
u8 idlest_bit;
__u32 flags;
u32 enable_reg;
__u8 enable_bit;
__s8 usecount;
u8 idlest_bit;
- void (*recalc)(struct clk *);
+ void (*recalc)(struct clk *, unsigned long, u8);
int (*set_rate)(struct clk *, unsigned long);
long (*round_rate)(struct clk *, unsigned long);
void (*init)(struct clk *);
int (*set_rate)(struct clk *, unsigned long);
long (*round_rate)(struct clk *, unsigned long);
void (*init)(struct clk *);
extern int clk_init(struct clk_functions *custom_clocks);
extern int clk_register(struct clk *clk);
extern void clk_unregister(struct clk *clk);
extern int clk_init(struct clk_functions *custom_clocks);
extern int clk_register(struct clk *clk);
extern void clk_unregister(struct clk *clk);
-extern void propagate_rate(struct clk *clk);
+extern void propagate_rate(struct clk *clk, u8 rate_storage);
extern void recalculate_root_clocks(void);
extern void recalculate_root_clocks(void);
-extern void followparent_recalc(struct clk *clk);
+extern void followparent_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage);
extern void clk_allow_idle(struct clk *clk);
extern void clk_deny_idle(struct clk *clk);
extern int clk_get_usecount(struct clk *clk);
extern void clk_allow_idle(struct clk *clk);
extern void clk_deny_idle(struct clk *clk);
extern int clk_get_usecount(struct clk *clk);
#define ENABLE_ON_INIT (1 << 11) /* Enable upon framework init */
#define INVERT_ENABLE (1 << 12) /* 0 enables, 1 disables */
#define WAIT_READY (1 << 13) /* wait for dev to leave idle */
#define ENABLE_ON_INIT (1 << 11) /* Enable upon framework init */
#define INVERT_ENABLE (1 << 12) /* 0 enables, 1 disables */
#define WAIT_READY (1 << 13) /* wait for dev to leave idle */
-/* bits 14-20 are currently free */
+#define RECALC_ON_ENABLE (1 << 14) /* recalc/prop on ena/disa */
+/* bits 15-20 are currently free */
#define CLOCK_IN_OMAP310 (1 << 21)
#define CLOCK_IN_OMAP730 (1 << 22)
#define CLOCK_IN_OMAP1510 (1 << 23)
#define CLOCK_IN_OMAP310 (1 << 21)
#define CLOCK_IN_OMAP730 (1 << 22)
#define CLOCK_IN_OMAP1510 (1 << 23)
#define RATE_IN_24XX (RATE_IN_242X | RATE_IN_243X)
#define RATE_IN_24XX (RATE_IN_242X | RATE_IN_243X)
+/* rate_storage parameter flags */
+#define CURRENT_RATE 0
+#define TEMP_RATE 1
+
/*
* clk.prcm_mod flags (possible since only the top byte in clk.prcm_mod
* is significant)
/*
* clk.prcm_mod flags (possible since only the top byte in clk.prcm_mod
* is significant)