svn commit: r314329 - head/sys/arm/allwinner/clkng
Emmanuel Vadot
manu at FreeBSD.org
Mon Feb 27 08:58:28 UTC 2017
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 */
More information about the svn-src-all
mailing list