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-head mailing list