]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
Merge tag 'for-v3.19/omap-a' of git://git.kernel.org/pub/scm/linux/kernel/git/pjw...
authorMichael Turquette <mturquette@linaro.org>
Mon, 15 Dec 2014 21:30:05 +0000 (13:30 -0800)
committerMichael Turquette <mturquette@linaro.org>
Tue, 16 Dec 2014 01:05:07 +0000 (17:05 -0800)
Some OMAP clock/hwmod patches for v3.19.

Most of the patches are clock-related.  The DPLL implementation is
changed to better align to the common clock framework.
There is also a patch that removes a few lines from the hwmod code -
this patch should have no functional effect.

Basic build, boot, and PM test logs for these patches can be found here:

http://www.pwsan.com/omap/testlogs/omap-a-for-v3.19/20141113094101/

arch/arm/mach-omap2/cclock3xxx_data.c
arch/arm/mach-omap2/clock.c
arch/arm/mach-omap2/clock.h
arch/arm/mach-omap2/clock3xxx.c
arch/arm/mach-omap2/dpll3xxx.c
arch/arm/mach-omap2/dpll44xx.c
arch/arm/mach-omap2/omap_hwmod.c
drivers/clk/ti/dpll.c
include/linux/clk/ti.h

index eb8c75ec3b1ac28ad121969fdbbd586bfca69b20..5c5ebb4db5f73031b5ba25a960e8efee5ec885fb 100644 (file)
@@ -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,
 };
 
index 500530d1364a384859a6720c783ef1394545b983..c2b239857cc470b9176e6dff369b7b9376795091 100644 (file)
@@ -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;
 }
index 4592a2762592fef88c69be32aa1ce42cc6f18a4a..641337c6cde9a43fdfb24e589b9946464924ec01 100644 (file)
@@ -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;
 
index 0b02b4161d71f9806fd10acea364d3dbfe005505..a9e86db5daf9f08de3137dd04ed8b52e6f979c59 100644 (file)
 
 /* 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;
index ac3d789ac3cd8b2ec5de9d4870bae6b0b65f2693..20e120d071dd5853b228106d1164c0e251b2cf45 100644 (file)
@@ -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 */
index 4613f1e86988751072826fb549a0f920d7df25e8..535822fcf4bbbd1e57a1211d122449d0a8a5807d 100644 (file)
@@ -207,3 +207,44 @@ long omap4_dpll_regm4xen_round_rate(struct clk_hw *hw,
 
        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;
+}
index 716247ed9e0c3a9b419f84332b97ee83aab28371..acae6d5d1151cd4936f4bb24853cf86f11f6f94a 100644 (file)
@@ -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++;
 
index 79791e1bf2824814e67b7c3e40d0dc2cbbec28a7..85ac0dd501dea5fff98801ba47edabbf972492a5 100644 (file)
@@ -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
index f75acbf70e9630631e03bd49e43414d7b3b4b9e3..74e5341463c91d06c1d5578d93f722358e340929 100644 (file)
@@ -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);