SoC related changes for omaps. Mostly to make PM easier to use for
omap4 and later, and to fix clock DPLL fixes by adding determine_rate and set_rate_and_parent. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJUZm0BAAoJEBvUPslcq6Vzpv4QALpopUWu91kXgiXBulKkmQ2d PF0P4XqTH4wtJtSImkWVMahtSv04NVKFHeq4zxnZOPLDjg1km3ZumRpxVUI9v4V3 JqK2bRZRYtfgUU4bzPp8n09Yb2MJCmwOeXi2RFg7FPhRW+2Y9HbQFfGYU7fGbd83 Uihg8Ss4l0Je03kp+sMHadh1Mzka0sRMuAStVKJhp/+awt1E6zQkGKCUzZdCaXIH 7rIuPylv1usS+ZwkOQGPS0odBTOxIstkimIMK3kbSkuJteLgXCEzZ9ACwxGLkjNh 5JZyMI/D6m4uMmSzVySxK3yq3VEHjI5IBGHa4nFPpXhxUl86/gtIG/FxNfcf2DKF hoDrlkfzDwLETchOF9Wd3pBRNSFCatDbwQcEYi/6AzY/eKoPZo3mDBTErctWD8Ds LKFVUTzLxw90UQ0KnhYYaNATsqFUEbXOTL7iSN/diddAuBHkcLJC1yLx6xEUWQ+G Qn6EvQvNb6ddx/01Ag8dOwDjJET4GD0XTLZ9T1DBSQ8+scd5pXE+NARRGgtPWAY7 RfsnU+x6UxKizVs3ibjU+2Eej7XA35Z3lgs36ve8iQtM7c72UK5pK8X7FMi5cVSA tgpLQ1/xd7+oUZdzggBHjJtt9SoyKizjL+JKxD699yMP0i9qJezSDrD35nDzUvAA oHd1ZuOlIadCyEOtNm5q =R6s9 -----END PGP SIGNATURE----- Merge tag 'omap-for-v3.19/clocks-and-pm' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap into next/soc Pull "omap soc changes for v3.19" from Tony Lindgren: SoC related changes for omaps. Mostly to make PM easier to use for omap4 and later, and to fix clock DPLL fixes by adding determine_rate and set_rate_and_parent. * tag 'omap-for-v3.19/clocks-and-pm' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap: ARM: OMAP2+: hwmod: drop unnecessary list initialization ARM: OMAP3+: DPLL: use determine_rate() and set_rate_and_parent() ARM: OMAP3: clock: add support for dpll4_set_rate_and_parent ARM: OMAP4: clock: add support for determine_rate for omap4 regm4xen DPLL ARM: OMAP3: clock: add new rate changing logic support for noncore DPLLs ARM: OMAP3: clock: use clk_features flags for omap3 DPLL4 checks ARM: OMAP4+: PM: Program CPU logic power state ARM: OMAP4+: PM: Centralize static dependency mapping table ARM: OMAP4: PM: Only do static dependency configuration in omap4_init_static_deps Signed-off-by: Arnd Bergmann <arnd@arndb.de>
This commit is contained in:
commit
3cb0df93bc
|
@ -257,6 +257,9 @@ static const struct clk_ops dpll1_ck_ops = {
|
|||
.get_parent = &omap2_init_dpll_parent,
|
||||
.recalc_rate = &omap3_dpll_recalc,
|
||||
.set_rate = &omap3_noncore_dpll_set_rate,
|
||||
.set_parent = &omap3_noncore_dpll_set_parent,
|
||||
.set_rate_and_parent = &omap3_noncore_dpll_set_rate_and_parent,
|
||||
.determine_rate = &omap3_noncore_dpll_determine_rate,
|
||||
.round_rate = &omap2_dpll_round_rate,
|
||||
};
|
||||
|
||||
|
@ -367,6 +370,9 @@ static const struct clk_ops dpll4_ck_ops = {
|
|||
.get_parent = &omap2_init_dpll_parent,
|
||||
.recalc_rate = &omap3_dpll_recalc,
|
||||
.set_rate = &omap3_dpll4_set_rate,
|
||||
.set_parent = &omap3_noncore_dpll_set_parent,
|
||||
.set_rate_and_parent = &omap3_dpll4_set_rate_and_parent,
|
||||
.determine_rate = &omap3_noncore_dpll_determine_rate,
|
||||
.round_rate = &omap2_dpll_round_rate,
|
||||
};
|
||||
|
||||
|
|
|
@ -771,4 +771,8 @@ void __init ti_clk_init_features(void)
|
|||
ti_clk_features.cm_idlest_val = OMAP24XX_CM_IDLEST_VAL;
|
||||
else if (cpu_is_omap34xx())
|
||||
ti_clk_features.cm_idlest_val = OMAP34XX_CM_IDLEST_VAL;
|
||||
|
||||
/* On OMAP3430 ES1.0, DPLL4 can't be re-programmed */
|
||||
if (omap_rev() == OMAP3430_REV_ES1_0)
|
||||
ti_clk_features.flags |= TI_CLK_DPLL4_DENY_REPROGRAM;
|
||||
}
|
||||
|
|
|
@ -234,6 +234,7 @@ struct ti_clk_features {
|
|||
};
|
||||
|
||||
#define TI_CLK_DPLL_HAS_FREQSEL (1 << 0)
|
||||
#define TI_CLK_DPLL4_DENY_REPROGRAM (1 << 1)
|
||||
|
||||
extern struct ti_clk_features ti_clk_features;
|
||||
|
||||
|
|
|
@ -38,6 +38,18 @@
|
|||
|
||||
/* needed by omap3_core_dpll_m2_set_rate() */
|
||||
struct clk *sdrc_ick_p, *arm_fck_p;
|
||||
|
||||
/**
|
||||
* omap3_dpll4_set_rate - set rate for omap3 per-dpll
|
||||
* @hw: clock to change
|
||||
* @rate: target rate for clock
|
||||
* @parent_rate: rate of the parent clock
|
||||
*
|
||||
* Check if the current SoC supports the per-dpll reprogram operation
|
||||
* or not, and then do the rate change if supported. Returns -EINVAL
|
||||
* if not supported, 0 for success, and potential error codes from the
|
||||
* clock rate change.
|
||||
*/
|
||||
int omap3_dpll4_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
|
@ -46,7 +58,7 @@ int omap3_dpll4_set_rate(struct clk_hw *hw, unsigned long rate,
|
|||
* on 3430ES1 prevents us from changing DPLL multipliers or dividers
|
||||
* on DPLL4.
|
||||
*/
|
||||
if (omap_rev() == OMAP3430_REV_ES1_0) {
|
||||
if (ti_clk_features.flags & TI_CLK_DPLL4_DENY_REPROGRAM) {
|
||||
pr_err("clock: DPLL4 cannot change rate due to silicon 'Limitation 2.5' on 3430ES1.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -54,6 +66,30 @@ int omap3_dpll4_set_rate(struct clk_hw *hw, unsigned long rate,
|
|||
return omap3_noncore_dpll_set_rate(hw, rate, parent_rate);
|
||||
}
|
||||
|
||||
/**
|
||||
* omap3_dpll4_set_rate_and_parent - set rate and parent for omap3 per-dpll
|
||||
* @hw: clock to change
|
||||
* @rate: target rate for clock
|
||||
* @parent_rate: rate of the parent clock
|
||||
* @index: parent index, 0 - reference clock, 1 - bypass clock
|
||||
*
|
||||
* Check if the current SoC support the per-dpll reprogram operation
|
||||
* or not, and then do the rate + parent change if supported. Returns
|
||||
* -EINVAL if not supported, 0 for success, and potential error codes
|
||||
* from the clock rate change.
|
||||
*/
|
||||
int omap3_dpll4_set_rate_and_parent(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate, u8 index)
|
||||
{
|
||||
if (ti_clk_features.flags & TI_CLK_DPLL4_DENY_REPROGRAM) {
|
||||
pr_err("clock: DPLL4 cannot change rate due to silicon 'Limitation 2.5' on 3430ES1.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return omap3_noncore_dpll_set_rate_and_parent(hw, rate, parent_rate,
|
||||
index);
|
||||
}
|
||||
|
||||
void __init omap3_clk_lock_dpll5(void)
|
||||
{
|
||||
struct clk *dpll5_clk;
|
||||
|
|
|
@ -460,25 +460,24 @@ void omap3_noncore_dpll_disable(struct clk_hw *hw)
|
|||
/* Non-CORE DPLL rate set code */
|
||||
|
||||
/**
|
||||
* omap3_noncore_dpll_set_rate - set non-core DPLL rate
|
||||
* @clk: struct clk * of DPLL to set
|
||||
* @rate: rounded target rate
|
||||
* omap3_noncore_dpll_determine_rate - determine rate for a DPLL
|
||||
* @hw: pointer to the clock to determine rate for
|
||||
* @rate: target rate for the DPLL
|
||||
* @best_parent_rate: pointer for returning best parent rate
|
||||
* @best_parent_clk: pointer for returning best parent clock
|
||||
*
|
||||
* Set the DPLL CLKOUT to the target rate. If the DPLL can enter
|
||||
* low-power bypass, and the target rate is the bypass source clock
|
||||
* rate, then configure the DPLL for bypass. Otherwise, round the
|
||||
* target rate if it hasn't been done already, then program and lock
|
||||
* the DPLL. Returns -EINVAL upon error, or 0 upon success.
|
||||
* Determines which DPLL mode to use for reaching a desired target rate.
|
||||
* Checks whether the DPLL shall be in bypass or locked mode, and if
|
||||
* locked, calculates the M,N values for the DPLL via round-rate.
|
||||
* Returns a positive clock rate with success, negative error value
|
||||
* in failure.
|
||||
*/
|
||||
int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
long omap3_noncore_dpll_determine_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *best_parent_rate,
|
||||
struct clk **best_parent_clk)
|
||||
{
|
||||
struct clk_hw_omap *clk = to_clk_hw_omap(hw);
|
||||
struct clk *new_parent = NULL;
|
||||
unsigned long rrate;
|
||||
u16 freqsel = 0;
|
||||
struct dpll_data *dd;
|
||||
int ret;
|
||||
|
||||
if (!hw || !rate)
|
||||
return -EINVAL;
|
||||
|
@ -489,61 +488,121 @@ int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate,
|
|||
|
||||
if (__clk_get_rate(dd->clk_bypass) == rate &&
|
||||
(dd->modes & (1 << DPLL_LOW_POWER_BYPASS))) {
|
||||
pr_debug("%s: %s: set rate: entering bypass.\n",
|
||||
__func__, __clk_get_name(hw->clk));
|
||||
|
||||
__clk_prepare(dd->clk_bypass);
|
||||
clk_enable(dd->clk_bypass);
|
||||
ret = _omap3_noncore_dpll_bypass(clk);
|
||||
if (!ret)
|
||||
new_parent = dd->clk_bypass;
|
||||
clk_disable(dd->clk_bypass);
|
||||
__clk_unprepare(dd->clk_bypass);
|
||||
*best_parent_clk = dd->clk_bypass;
|
||||
} else {
|
||||
__clk_prepare(dd->clk_ref);
|
||||
clk_enable(dd->clk_ref);
|
||||
|
||||
/* XXX this check is probably pointless in the CCF context */
|
||||
if (dd->last_rounded_rate != rate) {
|
||||
rrate = __clk_round_rate(hw->clk, rate);
|
||||
if (rrate != rate) {
|
||||
pr_warn("%s: %s: final rate %lu does not match desired rate %lu\n",
|
||||
__func__, __clk_get_name(hw->clk),
|
||||
rrate, rate);
|
||||
rate = rrate;
|
||||
}
|
||||
}
|
||||
|
||||
if (dd->last_rounded_rate == 0)
|
||||
return -EINVAL;
|
||||
|
||||
/* Freqsel is available only on OMAP343X devices */
|
||||
if (ti_clk_features.flags & TI_CLK_DPLL_HAS_FREQSEL) {
|
||||
freqsel = _omap3_dpll_compute_freqsel(clk,
|
||||
dd->last_rounded_n);
|
||||
WARN_ON(!freqsel);
|
||||
}
|
||||
|
||||
pr_debug("%s: %s: set rate: locking rate to %lu.\n",
|
||||
__func__, __clk_get_name(hw->clk), rate);
|
||||
|
||||
ret = omap3_noncore_dpll_program(clk, freqsel);
|
||||
if (!ret)
|
||||
new_parent = dd->clk_ref;
|
||||
clk_disable(dd->clk_ref);
|
||||
__clk_unprepare(dd->clk_ref);
|
||||
rate = omap2_dpll_round_rate(hw, rate, best_parent_rate);
|
||||
*best_parent_clk = dd->clk_ref;
|
||||
}
|
||||
|
||||
*best_parent_rate = rate;
|
||||
|
||||
return rate;
|
||||
}
|
||||
|
||||
/**
|
||||
* omap3_noncore_dpll_set_parent - set parent for a DPLL clock
|
||||
* @hw: pointer to the clock to set parent for
|
||||
* @index: parent index to select
|
||||
*
|
||||
* Sets parent for a DPLL clock. This sets the DPLL into bypass or
|
||||
* locked mode. Returns 0 with success, negative error value otherwise.
|
||||
*/
|
||||
int omap3_noncore_dpll_set_parent(struct clk_hw *hw, u8 index)
|
||||
{
|
||||
struct clk_hw_omap *clk = to_clk_hw_omap(hw);
|
||||
int ret;
|
||||
|
||||
if (!hw)
|
||||
return -EINVAL;
|
||||
|
||||
if (index)
|
||||
ret = _omap3_noncore_dpll_bypass(clk);
|
||||
else
|
||||
ret = _omap3_noncore_dpll_lock(clk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* omap3_noncore_dpll_set_rate - set rate for a DPLL clock
|
||||
* @hw: pointer to the clock to set parent for
|
||||
* @rate: target rate for the clock
|
||||
* @parent_rate: rate of the parent clock
|
||||
*
|
||||
* Sets rate for a DPLL clock. First checks if the clock parent is
|
||||
* reference clock (in bypass mode, the rate of the clock can't be
|
||||
* changed) and proceeds with the rate change operation. Returns 0
|
||||
* with success, negative error value otherwise.
|
||||
*/
|
||||
int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_hw_omap *clk = to_clk_hw_omap(hw);
|
||||
struct dpll_data *dd;
|
||||
u16 freqsel = 0;
|
||||
int ret;
|
||||
|
||||
if (!hw || !rate)
|
||||
return -EINVAL;
|
||||
|
||||
dd = clk->dpll_data;
|
||||
if (!dd)
|
||||
return -EINVAL;
|
||||
|
||||
if (__clk_get_parent(hw->clk) != dd->clk_ref)
|
||||
return -EINVAL;
|
||||
|
||||
if (dd->last_rounded_rate == 0)
|
||||
return -EINVAL;
|
||||
|
||||
/* Freqsel is available only on OMAP343X devices */
|
||||
if (ti_clk_features.flags & TI_CLK_DPLL_HAS_FREQSEL) {
|
||||
freqsel = _omap3_dpll_compute_freqsel(clk, dd->last_rounded_n);
|
||||
WARN_ON(!freqsel);
|
||||
}
|
||||
|
||||
pr_debug("%s: %s: set rate: locking rate to %lu.\n", __func__,
|
||||
__clk_get_name(hw->clk), rate);
|
||||
|
||||
ret = omap3_noncore_dpll_program(clk, freqsel);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* omap3_noncore_dpll_set_rate_and_parent - set rate and parent for a DPLL clock
|
||||
* @hw: pointer to the clock to set rate and parent for
|
||||
* @rate: target rate for the DPLL
|
||||
* @parent_rate: clock rate of the DPLL parent
|
||||
* @index: new parent index for the DPLL, 0 - reference, 1 - bypass
|
||||
*
|
||||
* Sets rate and parent for a DPLL clock. If new parent is the bypass
|
||||
* clock, only selects the parent. Otherwise proceeds with a rate
|
||||
* change, as this will effectively also change the parent as the
|
||||
* DPLL is put into locked mode. Returns 0 with success, negative error
|
||||
* value otherwise.
|
||||
*/
|
||||
int omap3_noncore_dpll_set_rate_and_parent(struct clk_hw *hw,
|
||||
unsigned long rate,
|
||||
unsigned long parent_rate,
|
||||
u8 index)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!hw || !rate)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* FIXME - this is all wrong. common code handles reparenting and
|
||||
* migrating prepare/enable counts. dplls should be a multiplexer
|
||||
* clock and this should be a set_parent operation so that all of that
|
||||
* stuff is inherited for free
|
||||
*/
|
||||
* clk-ref at index[0], in which case we only need to set rate,
|
||||
* the parent will be changed automatically with the lock sequence.
|
||||
* With clk-bypass case we only need to change parent.
|
||||
*/
|
||||
if (index)
|
||||
ret = omap3_noncore_dpll_set_parent(hw, index);
|
||||
else
|
||||
ret = omap3_noncore_dpll_set_rate(hw, rate, parent_rate);
|
||||
|
||||
if (!ret && clk_get_parent(hw->clk) != new_parent)
|
||||
__clk_reparent(hw->clk, new_parent);
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* DPLL autoidle read/set code */
|
||||
|
|
|
@ -207,3 +207,44 @@ out:
|
|||
|
||||
return dd->last_rounded_rate;
|
||||
}
|
||||
|
||||
/**
|
||||
* omap4_dpll_regm4xen_determine_rate - determine rate for a DPLL
|
||||
* @hw: pointer to the clock to determine rate for
|
||||
* @rate: target rate for the DPLL
|
||||
* @best_parent_rate: pointer for returning best parent rate
|
||||
* @best_parent_clk: pointer for returning best parent clock
|
||||
*
|
||||
* Determines which DPLL mode to use for reaching a desired rate.
|
||||
* Checks whether the DPLL shall be in bypass or locked mode, and if
|
||||
* locked, calculates the M,N values for the DPLL via round-rate.
|
||||
* Returns a positive clock rate with success, negative error value
|
||||
* in failure.
|
||||
*/
|
||||
long omap4_dpll_regm4xen_determine_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *best_parent_rate,
|
||||
struct clk **best_parent_clk)
|
||||
{
|
||||
struct clk_hw_omap *clk = to_clk_hw_omap(hw);
|
||||
struct dpll_data *dd;
|
||||
|
||||
if (!hw || !rate)
|
||||
return -EINVAL;
|
||||
|
||||
dd = clk->dpll_data;
|
||||
if (!dd)
|
||||
return -EINVAL;
|
||||
|
||||
if (__clk_get_rate(dd->clk_bypass) == rate &&
|
||||
(dd->modes & (1 << DPLL_LOW_POWER_BYPASS))) {
|
||||
*best_parent_clk = dd->clk_bypass;
|
||||
} else {
|
||||
rate = omap4_dpll_regm4xen_round_rate(hw, rate,
|
||||
best_parent_rate);
|
||||
*best_parent_clk = dd->clk_ref;
|
||||
}
|
||||
|
||||
*best_parent_rate = rate;
|
||||
|
||||
return rate;
|
||||
}
|
||||
|
|
|
@ -227,7 +227,7 @@ static void __init save_l2x0_context(void)
|
|||
int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
|
||||
{
|
||||
struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu);
|
||||
unsigned int save_state = 0;
|
||||
unsigned int save_state = 0, cpu_logic_state = PWRDM_POWER_RET;
|
||||
unsigned int wakeup_cpu;
|
||||
|
||||
if (omap_rev() == OMAP4430_REV_ES1_0)
|
||||
|
@ -239,6 +239,7 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
|
|||
save_state = 0;
|
||||
break;
|
||||
case PWRDM_POWER_OFF:
|
||||
cpu_logic_state = PWRDM_POWER_OFF;
|
||||
save_state = 1;
|
||||
break;
|
||||
case PWRDM_POWER_RET:
|
||||
|
@ -270,6 +271,7 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
|
|||
|
||||
cpu_clear_prev_logic_pwrst(cpu);
|
||||
pwrdm_set_next_pwrst(pm_info->pwrdm, power_state);
|
||||
pwrdm_set_logic_retst(pm_info->pwrdm, cpu_logic_state);
|
||||
set_cpu_wakeup_addr(cpu, virt_to_phys(omap_pm_ops.resume));
|
||||
omap_pm_ops.scu_prepare(cpu, power_state);
|
||||
l2x0_pwrst_prepare(cpu, save_state);
|
||||
|
|
|
@ -2832,12 +2832,10 @@ static int __init _add_link(struct omap_hwmod_ocp_if *oi)
|
|||
_alloc_links(&ml, &sl);
|
||||
|
||||
ml->ocp_if = oi;
|
||||
INIT_LIST_HEAD(&ml->node);
|
||||
list_add(&ml->node, &oi->master->master_ports);
|
||||
oi->master->masters_cnt++;
|
||||
|
||||
sl->ocp_if = oi;
|
||||
INIT_LIST_HEAD(&sl->node);
|
||||
list_add(&sl->node, &oi->slave->slave_ports);
|
||||
oi->slave->slaves_cnt++;
|
||||
|
||||
|
|
|
@ -37,6 +37,16 @@ struct power_state {
|
|||
struct list_head node;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct static_dep_map - Static dependency map
|
||||
* @from: from clockdomain
|
||||
* @to: to clockdomain
|
||||
*/
|
||||
struct static_dep_map {
|
||||
const char *from;
|
||||
const char *to;
|
||||
};
|
||||
|
||||
static u32 cpu_suspend_state = PWRDM_POWER_OFF;
|
||||
|
||||
static LIST_HEAD(pwrst_list);
|
||||
|
@ -148,94 +158,61 @@ static void omap_default_idle(void)
|
|||
omap_do_wfi();
|
||||
}
|
||||
|
||||
/**
|
||||
* omap4_init_static_deps - Add OMAP4 static dependencies
|
||||
*
|
||||
* Add needed static clockdomain dependencies on OMAP4 devices.
|
||||
* Return: 0 on success or 'err' on failures
|
||||
/*
|
||||
* The dynamic dependency between MPUSS -> MEMIF and
|
||||
* MPUSS -> L4_PER/L3_* and DUCATI -> L3_* doesn't work as
|
||||
* expected. The hardware recommendation is to enable static
|
||||
* dependencies for these to avoid system lock ups or random crashes.
|
||||
* The L4 wakeup depedency is added to workaround the OCP sync hardware
|
||||
* BUG with 32K synctimer which lead to incorrect timer value read
|
||||
* from the 32K counter. The BUG applies for GPTIMER1 and WDT2 which
|
||||
* are part of L4 wakeup clockdomain.
|
||||
*/
|
||||
static inline int omap4_init_static_deps(void)
|
||||
{
|
||||
struct clockdomain *emif_clkdm, *mpuss_clkdm, *l3_1_clkdm;
|
||||
struct clockdomain *ducati_clkdm, *l3_2_clkdm;
|
||||
int ret = 0;
|
||||
static const struct static_dep_map omap4_static_dep_map[] = {
|
||||
{.from = "mpuss_clkdm", .to = "l3_emif_clkdm"},
|
||||
{.from = "mpuss_clkdm", .to = "l3_1_clkdm"},
|
||||
{.from = "mpuss_clkdm", .to = "l3_2_clkdm"},
|
||||
{.from = "ducati_clkdm", .to = "l3_1_clkdm"},
|
||||
{.from = "ducati_clkdm", .to = "l3_2_clkdm"},
|
||||
{.from = NULL} /* TERMINATION */
|
||||
};
|
||||
|
||||
if (omap_rev() == OMAP4430_REV_ES1_0) {
|
||||
WARN(1, "Power Management not supported on OMAP4430 ES1.0\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
pr_err("Power Management for TI OMAP4.\n");
|
||||
/*
|
||||
* OMAP4 chip PM currently works only with certain (newer)
|
||||
* versions of bootloaders. This is due to missing code in the
|
||||
* kernel to properly reset and initialize some devices.
|
||||
* http://www.spinics.net/lists/arm-kernel/msg218641.html
|
||||
*/
|
||||
pr_warn("OMAP4 PM: u-boot >= v2012.07 is required for full PM support\n");
|
||||
|
||||
ret = pwrdm_for_each(pwrdms_setup, NULL);
|
||||
if (ret) {
|
||||
pr_err("Failed to setup powerdomains\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* The dynamic dependency between MPUSS -> MEMIF and
|
||||
* MPUSS -> L4_PER/L3_* and DUCATI -> L3_* doesn't work as
|
||||
* expected. The hardware recommendation is to enable static
|
||||
* dependencies for these to avoid system lock ups or random crashes.
|
||||
* The L4 wakeup depedency is added to workaround the OCP sync hardware
|
||||
* BUG with 32K synctimer which lead to incorrect timer value read
|
||||
* from the 32K counter. The BUG applies for GPTIMER1 and WDT2 which
|
||||
* are part of L4 wakeup clockdomain.
|
||||
*/
|
||||
mpuss_clkdm = clkdm_lookup("mpuss_clkdm");
|
||||
emif_clkdm = clkdm_lookup("l3_emif_clkdm");
|
||||
l3_1_clkdm = clkdm_lookup("l3_1_clkdm");
|
||||
l3_2_clkdm = clkdm_lookup("l3_2_clkdm");
|
||||
ducati_clkdm = clkdm_lookup("ducati_clkdm");
|
||||
if ((!mpuss_clkdm) || (!emif_clkdm) || (!l3_1_clkdm) ||
|
||||
(!l3_2_clkdm) || (!ducati_clkdm))
|
||||
return -EINVAL;
|
||||
|
||||
ret = clkdm_add_wkdep(mpuss_clkdm, emif_clkdm);
|
||||
ret |= clkdm_add_wkdep(mpuss_clkdm, l3_1_clkdm);
|
||||
ret |= clkdm_add_wkdep(mpuss_clkdm, l3_2_clkdm);
|
||||
ret |= clkdm_add_wkdep(ducati_clkdm, l3_1_clkdm);
|
||||
ret |= clkdm_add_wkdep(ducati_clkdm, l3_2_clkdm);
|
||||
if (ret) {
|
||||
pr_err("Failed to add MPUSS -> L3/EMIF/L4PER, DUCATI -> L3 wakeup dependency\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
static const struct static_dep_map omap5_dra7_static_dep_map[] = {
|
||||
{.from = "mpu_clkdm", .to = "emif_clkdm"},
|
||||
{.from = NULL} /* TERMINATION */
|
||||
};
|
||||
|
||||
/**
|
||||
* omap5_dra7_init_static_deps - Init static clkdm dependencies on OMAP5 and
|
||||
* DRA7
|
||||
*
|
||||
* The dynamic dependency between MPUSS -> EMIF is broken and has
|
||||
* not worked as expected. The hardware recommendation is to
|
||||
* enable static dependencies for these to avoid system
|
||||
* lock ups or random crashes.
|
||||
* omap4plus_init_static_deps() - Initialize a static dependency map
|
||||
* @map: Mapping of clock domains
|
||||
*/
|
||||
static inline int omap5_dra7_init_static_deps(void)
|
||||
static inline int omap4plus_init_static_deps(const struct static_dep_map *map)
|
||||
{
|
||||
struct clockdomain *mpuss_clkdm, *emif_clkdm;
|
||||
int ret;
|
||||
struct clockdomain *from, *to;
|
||||
|
||||
mpuss_clkdm = clkdm_lookup("mpu_clkdm");
|
||||
emif_clkdm = clkdm_lookup("emif_clkdm");
|
||||
if (!mpuss_clkdm || !emif_clkdm)
|
||||
return -EINVAL;
|
||||
if (!map)
|
||||
return 0;
|
||||
|
||||
ret = clkdm_add_wkdep(mpuss_clkdm, emif_clkdm);
|
||||
if (ret)
|
||||
pr_err("Failed to add MPUSS -> EMIF wakeup dependency\n");
|
||||
while (map->from) {
|
||||
from = clkdm_lookup(map->from);
|
||||
to = clkdm_lookup(map->to);
|
||||
if (!from || !to) {
|
||||
pr_err("Failed lookup %s or %s for wakeup dependency\n",
|
||||
map->from, map->to);
|
||||
return -EINVAL;
|
||||
}
|
||||
ret = clkdm_add_wkdep(from, to);
|
||||
if (ret) {
|
||||
pr_err("Failed to add %s -> %s wakeup dependency(%d)\n",
|
||||
map->from, map->to, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
map++;
|
||||
};
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -272,6 +249,15 @@ int __init omap4_pm_init(void)
|
|||
|
||||
pr_info("Power Management for TI OMAP4+ devices.\n");
|
||||
|
||||
/*
|
||||
* OMAP4 chip PM currently works only with certain (newer)
|
||||
* versions of bootloaders. This is due to missing code in the
|
||||
* kernel to properly reset and initialize some devices.
|
||||
* http://www.spinics.net/lists/arm-kernel/msg218641.html
|
||||
*/
|
||||
if (cpu_is_omap44xx())
|
||||
pr_warn("OMAP4 PM: u-boot >= v2012.07 is required for full PM support\n");
|
||||
|
||||
ret = pwrdm_for_each(pwrdms_setup, NULL);
|
||||
if (ret) {
|
||||
pr_err("Failed to setup powerdomains.\n");
|
||||
|
@ -279,9 +265,9 @@ int __init omap4_pm_init(void)
|
|||
}
|
||||
|
||||
if (cpu_is_omap44xx())
|
||||
ret = omap4_init_static_deps();
|
||||
ret = omap4plus_init_static_deps(omap4_static_dep_map);
|
||||
else if (soc_is_omap54xx() || soc_is_dra7xx())
|
||||
ret = omap5_dra7_init_static_deps();
|
||||
ret = omap4plus_init_static_deps(omap5_dra7_static_dep_map);
|
||||
|
||||
if (ret) {
|
||||
pr_err("Failed to initialise static dependencies.\n");
|
||||
|
|
|
@ -33,6 +33,9 @@ static const struct clk_ops dpll_m4xen_ck_ops = {
|
|||
.recalc_rate = &omap4_dpll_regm4xen_recalc,
|
||||
.round_rate = &omap4_dpll_regm4xen_round_rate,
|
||||
.set_rate = &omap3_noncore_dpll_set_rate,
|
||||
.set_parent = &omap3_noncore_dpll_set_parent,
|
||||
.set_rate_and_parent = &omap3_noncore_dpll_set_rate_and_parent,
|
||||
.determine_rate = &omap4_dpll_regm4xen_determine_rate,
|
||||
.get_parent = &omap2_init_dpll_parent,
|
||||
};
|
||||
#else
|
||||
|
@ -53,6 +56,9 @@ static const struct clk_ops dpll_ck_ops = {
|
|||
.recalc_rate = &omap3_dpll_recalc,
|
||||
.round_rate = &omap2_dpll_round_rate,
|
||||
.set_rate = &omap3_noncore_dpll_set_rate,
|
||||
.set_parent = &omap3_noncore_dpll_set_parent,
|
||||
.set_rate_and_parent = &omap3_noncore_dpll_set_rate_and_parent,
|
||||
.determine_rate = &omap3_noncore_dpll_determine_rate,
|
||||
.get_parent = &omap2_init_dpll_parent,
|
||||
};
|
||||
|
||||
|
@ -61,6 +67,9 @@ static const struct clk_ops dpll_no_gate_ck_ops = {
|
|||
.get_parent = &omap2_init_dpll_parent,
|
||||
.round_rate = &omap2_dpll_round_rate,
|
||||
.set_rate = &omap3_noncore_dpll_set_rate,
|
||||
.set_parent = &omap3_noncore_dpll_set_parent,
|
||||
.set_rate_and_parent = &omap3_noncore_dpll_set_rate_and_parent,
|
||||
.determine_rate = &omap3_noncore_dpll_determine_rate,
|
||||
};
|
||||
#else
|
||||
static const struct clk_ops dpll_core_ck_ops = {};
|
||||
|
@ -97,6 +106,9 @@ static const struct clk_ops omap3_dpll_ck_ops = {
|
|||
.get_parent = &omap2_init_dpll_parent,
|
||||
.recalc_rate = &omap3_dpll_recalc,
|
||||
.set_rate = &omap3_noncore_dpll_set_rate,
|
||||
.set_parent = &omap3_noncore_dpll_set_parent,
|
||||
.set_rate_and_parent = &omap3_noncore_dpll_set_rate_and_parent,
|
||||
.determine_rate = &omap3_noncore_dpll_determine_rate,
|
||||
.round_rate = &omap2_dpll_round_rate,
|
||||
};
|
||||
|
||||
|
@ -106,6 +118,9 @@ static const struct clk_ops omap3_dpll_per_ck_ops = {
|
|||
.get_parent = &omap2_init_dpll_parent,
|
||||
.recalc_rate = &omap3_dpll_recalc,
|
||||
.set_rate = &omap3_dpll4_set_rate,
|
||||
.set_parent = &omap3_noncore_dpll_set_parent,
|
||||
.set_rate_and_parent = &omap3_dpll4_set_rate_and_parent,
|
||||
.determine_rate = &omap3_noncore_dpll_determine_rate,
|
||||
.round_rate = &omap2_dpll_round_rate,
|
||||
};
|
||||
#endif
|
||||
|
|
|
@ -254,13 +254,26 @@ extern const struct clk_ops ti_clk_mux_ops;
|
|||
void omap2_init_clk_hw_omap_clocks(struct clk *clk);
|
||||
int omap3_noncore_dpll_enable(struct clk_hw *hw);
|
||||
void omap3_noncore_dpll_disable(struct clk_hw *hw);
|
||||
int omap3_noncore_dpll_set_parent(struct clk_hw *hw, u8 index);
|
||||
int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate);
|
||||
int omap3_noncore_dpll_set_rate_and_parent(struct clk_hw *hw,
|
||||
unsigned long rate,
|
||||
unsigned long parent_rate,
|
||||
u8 index);
|
||||
long omap3_noncore_dpll_determine_rate(struct clk_hw *hw,
|
||||
unsigned long rate,
|
||||
unsigned long *best_parent_rate,
|
||||
struct clk **best_parent_clk);
|
||||
unsigned long omap4_dpll_regm4xen_recalc(struct clk_hw *hw,
|
||||
unsigned long parent_rate);
|
||||
long omap4_dpll_regm4xen_round_rate(struct clk_hw *hw,
|
||||
unsigned long target_rate,
|
||||
unsigned long *parent_rate);
|
||||
long omap4_dpll_regm4xen_determine_rate(struct clk_hw *hw,
|
||||
unsigned long rate,
|
||||
unsigned long *best_parent_rate,
|
||||
struct clk **best_parent_clk);
|
||||
u8 omap2_init_dpll_parent(struct clk_hw *hw);
|
||||
unsigned long omap3_dpll_recalc(struct clk_hw *hw, unsigned long parent_rate);
|
||||
long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate,
|
||||
|
@ -278,6 +291,8 @@ int omap2_clk_disable_autoidle_all(void);
|
|||
void omap2_clk_enable_init_clocks(const char **clk_names, u8 num_clocks);
|
||||
int omap3_dpll4_set_rate(struct clk_hw *clk, unsigned long rate,
|
||||
unsigned long parent_rate);
|
||||
int omap3_dpll4_set_rate_and_parent(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate, u8 index);
|
||||
int omap2_dflt_clk_enable(struct clk_hw *hw);
|
||||
void omap2_dflt_clk_disable(struct clk_hw *hw);
|
||||
int omap2_dflt_clk_is_enabled(struct clk_hw *hw);
|
||||
|
|
Loading…
Reference in New Issue