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"