Author: manu
Date: Mon Feb 27 08:58:27 2017
New Revision: 314329
URL: https://svnweb.freebsd.org/changeset/base/314329

Log:
  allwinner: Add support for lock and fractional mode on NM clock
  
  Some PLL have a fractional mode and a lock bit.
  Add support for it on the NM clock and export the clocks in the clkdom.

Modified:
  head/sys/arm/allwinner/clkng/aw_clk.h
  head/sys/arm/allwinner/clkng/aw_clk_nm.c
  head/sys/arm/allwinner/clkng/aw_clk_nm.h
  head/sys/arm/allwinner/clkng/ccu_h3.c

Modified: head/sys/arm/allwinner/clkng/aw_clk.h
==============================================================================
--- head/sys/arm/allwinner/clkng/aw_clk.h       Mon Feb 27 08:36:51 2017        
(r314328)
+++ head/sys/arm/allwinner/clkng/aw_clk.h       Mon Feb 27 08:58:27 2017        
(r314329)
@@ -63,6 +63,7 @@ struct aw_clk_init {
 #define        AW_CLK_HAS_MUX          0x0004
 #define        AW_CLK_REPARENT         0x0008
 #define        AW_CLK_SCALE_CHANGE     0x0010
+#define        AW_CLK_HAS_FRAC         0x0020
 
 #define        AW_CLK_FACTOR_POWER_OF_TWO      0x0001
 #define        AW_CLK_FACTOR_ZERO_BASED        0x0002
@@ -83,6 +84,13 @@ struct aw_clk_factor {
        uint32_t        flags;          /* Flags */
 };
 
+struct aw_clk_frac {
+       uint64_t        freq0;
+       uint64_t        freq1;
+       uint32_t        mode_sel;
+       uint32_t        freq_sel;
+};
+
 static inline uint32_t
 aw_clk_get_factor(uint32_t val, struct aw_clk_factor *factor)
 {
@@ -238,6 +246,38 @@ aw_clk_factor_get_value(struct aw_clk_fa
                .flags = _flags,                        \
        },
 
+#define NM_CLK_WITH_FRAC(_id, _name, _pnames,          \
+     _offset,                                          \
+     _nshift, _nwidth, _nvalue, _nflags,               \
+     _mshift, _mwidth, _mvalue, _mflags,               \
+     _gate_shift, _lock_shift,_lock_retries,           \
+    _flags, _freq0, _freq1, _mode_sel, _freq_sel)      \
+       {                                               \
+               .clkdef = {                             \
+                       .id = _id,                      \
+                       .name = _name,                  \
+                       .parent_names = _pnames,        \
+                       .parent_cnt = nitems(_pnames),  \
+               },                                      \
+               .offset = _offset,                      \
+               .n.shift = _nshift,                     \
+               .n.width = _nwidth,                     \
+               .n.value = _nvalue,                     \
+               .n.flags = _nflags,                     \
+               .m.shift = _mshift,                     \
+               .m.width = _mwidth,                     \
+               .m.value = _mvalue,                     \
+               .m.flags = _mflags,                     \
+               .gate_shift = _gate_shift,              \
+               .lock_shift = _lock_shift,              \
+               .lock_retries = _lock_retries,          \
+               .flags = _flags | AW_CLK_HAS_FRAC,      \
+               .frac.freq0 = _freq0,                   \
+               .frac.freq1 = _freq1,                   \
+               .frac.mode_sel = _mode_sel,             \
+               .frac.freq_sel = _freq_sel,             \
+       },
+
 #define PREDIV_CLK(_id, _name, _pnames,                \
   _offset,     \
   _mux_shift, _mux_width,      \

Modified: head/sys/arm/allwinner/clkng/aw_clk_nm.c
==============================================================================
--- head/sys/arm/allwinner/clkng/aw_clk_nm.c    Mon Feb 27 08:36:51 2017        
(r314328)
+++ head/sys/arm/allwinner/clkng/aw_clk_nm.c    Mon Feb 27 08:58:27 2017        
(r314329)
@@ -52,10 +52,13 @@ struct aw_clk_nm_sc {
 
        struct aw_clk_factor    m;
        struct aw_clk_factor    n;
+       struct aw_clk_frac      frac;
 
        uint32_t        mux_shift;
        uint32_t        mux_mask;
        uint32_t        gate_shift;
+       uint32_t        lock_shift;
+       uint32_t        lock_retries;
 
        uint32_t        flags;
 };
@@ -178,13 +181,13 @@ aw_clk_nm_set_freq(struct clknode *clk, 
        struct aw_clk_nm_sc *sc;
        struct clknode *p_clk;
        const char **p_names;
-       uint64_t cur, best;
+       uint64_t cur, best, best_frac;
        uint32_t val, m, n, best_m, best_n;
-       int p_idx, best_parent;
+       int p_idx, best_parent, retry;
 
        sc = clknode_get_softc(clk);
 
-       best = cur = 0;
+       best = best_frac = cur = 0;
        best_parent = 0;
 
        if ((sc->flags & AW_CLK_REPARENT) != 0) {
@@ -205,8 +208,15 @@ aw_clk_nm_set_freq(struct clknode *clk, 
                p_idx = clknode_get_parent_idx(clk);
                p_clk = clknode_get_parent(clk);
                clknode_get_freq(p_clk, &fparent);
-       } else
-               best = aw_clk_nm_find_best(sc, fparent, fout, &best_n, &best_m);
+       } else {
+               if (sc->flags & AW_CLK_HAS_FRAC &&
+                   (*fout == sc->frac.freq0 || *fout == sc->frac.freq1))
+                       best = best_frac = *fout;
+
+               if (best == 0)
+                       best = aw_clk_nm_find_best(sc, fparent, fout,
+                           &best_n, &best_m);
+       }
 
        if ((flags & CLK_SET_DRYRUN) != 0) {
                *fout = best;
@@ -228,17 +238,36 @@ aw_clk_nm_set_freq(struct clknode *clk, 
        if (p_idx != best_parent)
                clknode_set_parent_by_idx(clk, best_parent);
 
-       n = aw_clk_factor_get_value(&sc->n, best_n);
-       m = aw_clk_factor_get_value(&sc->m, best_m);
        DEVICE_LOCK(clk);
        READ4(clk, sc->offset, &val);
-       val &= ~sc->n.mask;
-       val &= ~sc->m.mask;
-       val |= n << sc->n.shift;
-       val |= m << sc->m.shift;
+
+       if (best_frac != 0) {
+               val &= ~sc->frac.mode_sel;
+               if (best_frac == sc->frac.freq0)
+                       val &= ~sc->frac.freq_sel;
+               else
+                       val |= sc->frac.freq_sel;
+       } else {
+               n = aw_clk_factor_get_value(&sc->n, best_n);
+               m = aw_clk_factor_get_value(&sc->m, best_m);
+               val &= ~sc->n.mask;
+               val &= ~sc->m.mask;
+               val |= n << sc->n.shift;
+               val |= m << sc->m.shift;
+       }
+
        WRITE4(clk, sc->offset, val);
        DEVICE_UNLOCK(clk);
 
+       if ((sc->flags & AW_CLK_HAS_LOCK) != 0) {
+               for (retry = 0; retry < sc->lock_retries; retry++) {
+                       READ4(clk, sc->offset, &val);
+                       if ((val & (1 << sc->lock_shift)) != 0)
+                               break;
+                       DELAY(1000);
+               }
+       }
+
        *fout = best;
        *stop = 1;
 
@@ -257,10 +286,17 @@ aw_clk_nm_recalc(struct clknode *clk, ui
        READ4(clk, sc->offset, &val);
        DEVICE_UNLOCK(clk);
 
-       m = aw_clk_get_factor(val, &sc->m);
-       n = aw_clk_get_factor(val, &sc->n);
+       if (sc->flags & AW_CLK_HAS_FRAC && ((val & sc->frac.mode_sel) == 0)) {
+               if (val & sc->frac.freq_sel)
+                       *freq = sc->frac.freq1;
+               else
+                       *freq = sc->frac.freq0;
+       } else {
+               m = aw_clk_get_factor(val, &sc->m);
+               n = aw_clk_get_factor(val, &sc->n);
 
-       *freq = *freq / n / m;
+               *freq = *freq / n / m;
+       }
 
        return (0);
 }
@@ -302,11 +338,19 @@ aw_clk_nm_register(struct clkdom *clkdom
        sc->n.mask = ((1 << sc->n.width) - 1) << sc->n.shift;
        sc->n.flags = clkdef->n.flags;
 
+       sc->frac.freq0 = clkdef->frac.freq0;
+       sc->frac.freq1 = clkdef->frac.freq1;
+       sc->frac.mode_sel = 1 << clkdef->frac.mode_sel;
+       sc->frac.freq_sel = 1 << clkdef->frac.freq_sel;
+
        sc->mux_shift = clkdef->mux_shift;
        sc->mux_mask = ((1 << clkdef->mux_width) - 1) << sc->mux_shift;
 
        sc->gate_shift = clkdef->gate_shift;
 
+       sc->lock_shift = clkdef->lock_shift;
+       sc->lock_retries = clkdef->lock_retries;
+
        sc->flags = clkdef->flags;
 
        clknode_register(clkdom, clk);

Modified: head/sys/arm/allwinner/clkng/aw_clk_nm.h
==============================================================================
--- head/sys/arm/allwinner/clkng/aw_clk_nm.h    Mon Feb 27 08:36:51 2017        
(r314328)
+++ head/sys/arm/allwinner/clkng/aw_clk_nm.h    Mon Feb 27 08:58:27 2017        
(r314329)
@@ -37,10 +37,13 @@ struct aw_clk_nm_def {
 
        struct aw_clk_factor    m;
        struct aw_clk_factor    n;
+       struct aw_clk_frac      frac;
 
        uint32_t                mux_shift;
        uint32_t                mux_width;
        uint32_t                gate_shift;
+       uint32_t                lock_shift;
+       uint32_t                lock_retries;
 
        uint32_t                flags;
 };

Modified: head/sys/arm/allwinner/clkng/ccu_h3.c
==============================================================================
--- head/sys/arm/allwinner/clkng/ccu_h3.c       Mon Feb 27 08:36:51 2017        
(r314328)
+++ head/sys/arm/allwinner/clkng/ccu_h3.c       Mon Feb 27 08:58:27 2017        
(r314329)
@@ -182,28 +182,12 @@ static const char *pll_cpux_parents[] = 
 static const char *pll_audio_parents[] = {"osc24M"};
 static const char *pll_audio_mult_parents[] = {"pll_audio"};
 /*
- * Need fractional mode on nkmp or a NM fract
-static const char *pll_video_parents[] = {"osc24M"};
- */
-/*
- * Need fractional mode on nkmp or a NM fract
-static const char *pll_ve_parents[] = {"osc24M"};
- */
-/*
  * Needs a update bit on nkmp or special clk
 static const char *pll_ddr_parents[] = {"osc24M"};
  */
 static const char *pll_periph0_parents[] = {"osc24M"};
 static const char *pll_periph0_2x_parents[] = {"pll_periph0"};
-/*
- * Need fractional mode on nkmp or a NM fract
-static const char *pll_gpu_parents[] = {"osc24M"};
- */
 static const char *pll_periph1_parents[] = {"osc24M"};
-/*
- * Need fractional mode on nkmp or a NM fract
-static const char *pll_de_parents[] = {"osc24M"};
- */
 
 static struct aw_clk_nkmp_def nkmp_clks[] = {
        NKMP_CLK(H3_CLK_PLL_CPUX,                       /* id */
@@ -268,6 +252,10 @@ static struct aw_clk_prediv_mux_def pred
            0, 2, 1)                                                    /* 
prediv condition */
 };
 
+static const char *pll_video_parents[] = {"osc24M"};
+static const char *pll_ve_parents[] = {"osc24M"};
+static const char *pll_gpu_parents[] = {"osc24M"};
+static const char *pll_de_parents[] = {"osc24M"};
 static const char *apb2_parents[] = {"osc32k", "osc24M", "pll_periph0", 
"pll_periph0"};
 static const char *mod_parents[] = {"osc24M", "pll_periph0", "pll_periph1"};
 static const char *ts_parents[] = {"osc24M", "pll_periph0"};
@@ -275,6 +263,42 @@ static const char *spdif_parents[] = {"p
 static const char *i2s_parents[] = {"pll_audio-8x", "pll_audio-4x", 
"pll_audio-2x", "pll_audio"};
 
 static struct aw_clk_nm_def nm_clks[] = {
+       NM_CLK_WITH_FRAC(H3_CLK_PLL_VIDEO,              /* id */
+           "pll_video", pll_video_parents,             /* name, parents */
+           0x10,                                       /* offset */
+           8, 7, 0, 0,                                 /* n factor */
+           0, 4, 0, 0,                                 /* m factor */
+           31, 28, 1000,                               /* gate, lock, lock 
retries */
+           AW_CLK_HAS_LOCK,                            /* flags */
+           270000000, 297000000,                       /* freq0, freq1 */
+           24, 25)                                     /* mode sel, freq sel */
+       NM_CLK_WITH_FRAC(H3_CLK_PLL_VE,                 /* id */
+           "pll_ve", pll_ve_parents,                   /* name, parents */
+           0x18,                                       /* offset */
+           8, 7, 0, 0,                                 /* n factor */
+           0, 4, 0, 0,                                 /* m factor */
+           31, 28, 1000,                               /* gate, lock, lock 
retries */
+           AW_CLK_HAS_LOCK,                            /* flags */
+           270000000, 297000000,                       /* freq0, freq1 */
+           24, 25)                                     /* mode sel, freq sel */
+       NM_CLK_WITH_FRAC(H3_CLK_PLL_GPU,                /* id */
+           "pll_gpu", pll_gpu_parents,                 /* name, parents */
+           0x38,                                       /* offset */
+           8, 7, 0, 0,                                 /* n factor */
+           0, 4, 0, 0,                                 /* m factor */
+           31, 28, 1000,                               /* gate, lock, lock 
retries */
+           AW_CLK_HAS_LOCK,                            /* flags */
+           270000000, 297000000,                       /* freq0, freq1 */
+           24, 25)                                     /* mode sel, freq sel */
+       NM_CLK_WITH_FRAC(H3_CLK_PLL_DE,                 /* id */
+           "pll_de", pll_de_parents,                   /* name, parents */
+           0x48,                                       /* offset */
+           8, 7, 0, 0,                                 /* n factor */
+           0, 4, 0, 0,                                 /* m factor */
+           31, 28, 1000,                               /* gate, lock, lock 
retries */
+           AW_CLK_HAS_LOCK,                            /* flags */
+           270000000, 297000000,                       /* freq0, freq1 */
+           24, 25)                                     /* mode sel, freq sel */
        NM_CLK(H3_CLK_APB2,                             /* id */
            "apb2", apb2_parents,                       /* name, parents */
            0x58,                                       /* offset */
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to