浏览代码

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>
Arnd Bergmann 10 年之前
父节点
当前提交
3cb0df93bc

+ 6 - 0
arch/arm/mach-omap2/cclock3xxx_data.c

@@ -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,
 };
 

+ 4 - 0
arch/arm/mach-omap2/clock.c

@@ -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;
 }

+ 1 - 0
arch/arm/mach-omap2/clock.h

@@ -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;
 

+ 37 - 1
arch/arm/mach-omap2/clock3xxx.c

@@ -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;

+ 119 - 60
arch/arm/mach-omap2/dpll3xxx.c

@@ -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));
+		*best_parent_clk = dd->clk_bypass;
+	} else {
+		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;
 
-		__clk_prepare(dd->clk_bypass);
-		clk_enable(dd->clk_bypass);
+	if (!hw)
+		return -EINVAL;
+
+	if (index)
 		ret = _omap3_noncore_dpll_bypass(clk);
-		if (!ret)
-			new_parent = dd->clk_bypass;
-		clk_disable(dd->clk_bypass);
-		__clk_unprepare(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;
-			}
-		}
+	else
+		ret = _omap3_noncore_dpll_lock(clk);
 
-		if (dd->last_rounded_rate == 0)
-			return -EINVAL;
+	return ret;
+}
 
-		/* 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);
-		}
+/**
+ * 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;
 
-		pr_debug("%s: %s: set rate: locking rate to %lu.\n",
-			 __func__, __clk_get_name(hw->clk), rate);
+	if (__clk_get_parent(hw->clk) != dd->clk_ref)
+		return -EINVAL;
+
+	if (dd->last_rounded_rate == 0)
+		return -EINVAL;
 
-		ret = omap3_noncore_dpll_program(clk, freqsel);
-		if (!ret)
-			new_parent = dd->clk_ref;
-		clk_disable(dd->clk_ref);
-		__clk_unprepare(dd->clk_ref);
+	/* 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);
 	}
-	/*
-	* 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
-	*/
 
-	if (!ret && clk_get_parent(hw->clk) != new_parent)
-		__clk_reparent(hw->clk, new_parent);
+	pr_debug("%s: %s: set rate: locking rate to %lu.\n", __func__,
+		 __clk_get_name(hw->clk), rate);
 
-	return 0;
+	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;
+
+	/*
+	 * 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);
+
+	return ret;
 }
 
 /* DPLL autoidle read/set code */

+ 41 - 0
arch/arm/mach-omap2/dpll44xx.c

@@ -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;
+}

+ 3 - 1
arch/arm/mach-omap2/omap-mpuss-lowpower.c

@@ -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);

+ 0 - 2
arch/arm/mach-omap2/omap_hwmod.c

@@ -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++;
 

+ 66 - 80
arch/arm/mach-omap2/pm44xx.c

@@ -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;
-
-	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;
-	}
+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 */
+};
 
-	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;
+
+	if (!map)
+		return 0;
 
-	mpuss_clkdm = clkdm_lookup("mpu_clkdm");
-	emif_clkdm = clkdm_lookup("emif_clkdm");
-	if (!mpuss_clkdm || !emif_clkdm)
-		return -EINVAL;
+	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;
+		}
 
-	ret = clkdm_add_wkdep(mpuss_clkdm, emif_clkdm);
-	if (ret)
-		pr_err("Failed to add MPUSS -> EMIF wakeup dependency\n");
+		map++;
+	};
 
-	return ret;
+	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");

+ 15 - 0
drivers/clk/ti/dpll.c

@@ -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

+ 15 - 0
include/linux/clk/ti.h

@@ -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);