Author: manu
Date: Fri Dec  9 20:52:48 2016
New Revision: 309767
URL: https://svnweb.freebsd.org/changeset/base/309767

Log:
  MFC r304796, r308233 (jmcneill)
  
  r304796:
  Switch parent clock when setting frequency if a new parent is a better
  candidate for the target rate.
  
  Reviewed by:  andrew, manu
  
  r308233:
  The DTS may report fewer than 4 parents for a module clock. Avoid setting
  the module clock parent to an out-of-range index in these cases.

Modified:
  stable/11/sys/arm/allwinner/clk/aw_modclk.c
Directory Properties:
  stable/11/   (props changed)

Modified: stable/11/sys/arm/allwinner/clk/aw_modclk.c
==============================================================================
--- stable/11/sys/arm/allwinner/clk/aw_modclk.c Fri Dec  9 20:50:35 2016        
(r309766)
+++ stable/11/sys/arm/allwinner/clk/aw_modclk.c Fri Dec  9 20:52:48 2016        
(r309767)
@@ -53,7 +53,6 @@ __FBSDID("$FreeBSD$");
 #define        SCLK_GATING             (1 << 31)
 #define        CLK_SRC_SEL             (0x3 << 24)
 #define        CLK_SRC_SEL_SHIFT       24
-#define        CLK_SRC_SEL_MAX         0x3
 #define        CLK_RATIO_N             (0x3 << 16)
 #define        CLK_RATIO_N_SHIFT       16
 #define        CLK_RATIO_N_MAX         0x3
@@ -69,6 +68,7 @@ static struct ofw_compat_data compat_dat
 struct aw_modclk_sc {
        device_t        clkdev;
        bus_addr_t      reg;
+       u_int           parent_cnt;
 };
 
 #define        MODCLK_READ(sc, val)    CLKDEV_READ_4((sc)->clkdev, (sc)->reg, 
(val))
@@ -102,7 +102,7 @@ aw_modclk_set_mux(struct clknode *clk, i
 
        sc = clknode_get_softc(clk);
 
-       if (index < 0 || index > CLK_SRC_SEL_MAX)
+       if (index < 0 || index >= sc->parent_cnt)
                return (ERANGE);
 
        DEVICE_LOCK(sc);
@@ -160,28 +160,47 @@ aw_modclk_set_freq(struct clknode *clk, 
     int flags, int *stop)
 {
        struct aw_modclk_sc *sc;
-       uint32_t val, m, n, best_m, best_n;
+       uint32_t val, m, n, src, best_m, best_n, best_src;
        uint64_t cur_freq;
        int64_t best_diff, cur_diff;
+       int error;
 
        sc = clknode_get_softc(clk);
        best_n = best_m = 0;
        best_diff = (int64_t)*fout; 
+       best_src = 0;
 
-       for (n = 0; n <= CLK_RATIO_N_MAX; n++)
-               for (m = 0; m <= CLK_RATIO_M_MAX; m++) {
-                       cur_freq = fin / (1 << n) / (m + 1);
-                       cur_diff = (int64_t)*fout - cur_freq;
-                       if (cur_diff >= 0 && cur_diff < best_diff) {
-                               best_diff = cur_diff;
-                               best_m = m;
-                               best_n = n;
+       for (src = 0; src < sc->parent_cnt; src++) {
+               error = clknode_set_parent_by_idx(clk, src);
+               if (error != 0)
+                       continue;
+               error = clknode_get_freq(clknode_get_parent(clk), &fin);
+               if (error != 0)
+                       continue;
+
+               for (n = 0; n <= CLK_RATIO_N_MAX; n++)
+                       for (m = 0; m <= CLK_RATIO_M_MAX; m++) {
+                               cur_freq = fin / (1 << n) / (m + 1);
+                               cur_diff = (int64_t)*fout - cur_freq;
+                               if (cur_diff >= 0 && cur_diff < best_diff) {
+                                       best_src = src;
+                                       best_diff = cur_diff;
+                                       best_m = m;
+                                       best_n = n;
+                               }
                        }
-               }
+       }
 
        if (best_diff == (int64_t)*fout)
                return (ERANGE);
 
+       error = clknode_set_parent_by_idx(clk, best_src);
+       if (error != 0)
+               return (error);
+       error = clknode_get_freq(clknode_get_parent(clk), &fin);
+       if (error != 0)
+               return (error);
+
        DEVICE_LOCK(sc);
        MODCLK_READ(sc, &val);
        val &= ~(CLK_RATIO_N | CLK_RATIO_M);
@@ -280,6 +299,7 @@ aw_modclk_attach(device_t dev)
        sc = clknode_get_softc(clk);
        sc->reg = paddr;
        sc->clkdev = device_get_parent(dev);
+       sc->parent_cnt = def.parent_cnt;
 
        clknode_register(clkdom, clk);
 
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to