Date: Thu, 28 Nov 2019 17:30:17 +0000 (UTC) From: Emmanuel Vadot <manu@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-12@freebsd.org Subject: svn commit: r355174 - in stable/12/sys: arm/allwinner arm/allwinner/a20 arm/allwinner/clkng conf dev/extres/clk Message-ID: <201911281730.xASHUH1x056531@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: manu Date: Thu Nov 28 17:30:16 2019 New Revision: 355174 URL: https://svnweb.freebsd.org/changeset/base/355174 Log: MFC r350842, r350844-r350846, r351099, r352848, r352859 r350842: allwinner: Rework the BUS_PASS on drivers - Put all clock and control unit driver in BUS_PASS_RESOURCE except for the DE2 CCU as it needs the main CCU to be available. - Use BUS_PASS_CPU for a20_cpu_cfg as it makes more sense. - For aw_syscon use SCHEDULER pass as we need it early for drivers that attach in BUS_PASS_SUPPORTDEV - For the rest we can use BUS_PASS_SUPPORTDEV r350844: allwinner: Add a new clock aw_clk_m We used the aw_clk_nm clock for clock with only one divider factor and used a fake multiplier factor. This cannot work properly as we end up writing the "fake" factor to the register (and so always set the LSB to 1). Create a new clock for those. The reason for not using the clk_div clock is because those clocks are a bit special. Since they are (almost) all related to video we also need to set the parent clock (the main PLL) to a frequency that they can support. As the main PLL have some minimal frequency that they can support we need to be able to set the main PLL to a multiple of the desired frequency. Let say you want to have a 71Mhz pixel clock (typical for a 1280x800 display) and the main PLL cannot go under 192Mhz, you need to set it to 3 times the desired frequency and set the divider to 3 on the hdmi clock. So this also introduce the CLK_SET_ROUND_MULTIPLE flag that allow for this kind of scenario. r350845: Remove some duplicate code that end up in r350844 r350846: allwinner: Add support to min/max in aw_clk_frac The Fractionals clock in Allwinner device have some min/max frequencies that they can do. Add support for it. r351099: arm: allwinner: Set aw_ccu to BUS_PASS_BUS In r350842 I've switched the bus pass to resource so it matches the other clock drivers but this cannot work as this drivers is meant to match the dts node '/clocks' and if we don't do it at this pass simplebus is catching this node and we cannot attach. This solve booting on Allwinner boards that are still using /clocks (A20 SoC) r352848: arm64: allwinner: a64: Add PLL_MIPI PLL_MIPI is the last important PLL that we missed. Add support for it. Since it's one of the possible parent for TCON0 also add this clock now that we can. While here add some info about what video related clocks should be enabled at boot and with what frequency. r352859: arm: allwinner: Add pll_mipi to the files Added: stable/12/sys/arm/allwinner/clkng/aw_clk_m.c - copied unchanged from r350846, head/sys/arm/allwinner/clkng/aw_clk_m.c stable/12/sys/arm/allwinner/clkng/aw_clk_m.h - copied unchanged from r350846, head/sys/arm/allwinner/clkng/aw_clk_m.h stable/12/sys/arm/allwinner/clkng/aw_clk_mipi.c - copied unchanged from r352848, head/sys/arm/allwinner/clkng/aw_clk_mipi.c stable/12/sys/arm/allwinner/clkng/aw_clk_mipi.h - copied unchanged from r352848, head/sys/arm/allwinner/clkng/aw_clk_mipi.h Modified: stable/12/sys/arm/allwinner/a10_sramc.c stable/12/sys/arm/allwinner/a20/a20_cpu_cfg.c stable/12/sys/arm/allwinner/aw_gmacclk.c stable/12/sys/arm/allwinner/aw_reset.c stable/12/sys/arm/allwinner/aw_rsb.c stable/12/sys/arm/allwinner/aw_rtc.c stable/12/sys/arm/allwinner/aw_sid.c stable/12/sys/arm/allwinner/aw_syscon.c stable/12/sys/arm/allwinner/clkng/aw_ccung.c stable/12/sys/arm/allwinner/clkng/aw_ccung.h stable/12/sys/arm/allwinner/clkng/aw_clk.h stable/12/sys/arm/allwinner/clkng/aw_clk_frac.c stable/12/sys/arm/allwinner/clkng/aw_clk_frac.h stable/12/sys/arm/allwinner/clkng/ccu_a10.c stable/12/sys/arm/allwinner/clkng/ccu_a13.c stable/12/sys/arm/allwinner/clkng/ccu_a31.c stable/12/sys/arm/allwinner/clkng/ccu_a64.c stable/12/sys/arm/allwinner/clkng/ccu_a83t.c stable/12/sys/arm/allwinner/clkng/ccu_de2.c stable/12/sys/arm/allwinner/clkng/ccu_h3.c stable/12/sys/arm/allwinner/clkng/ccu_sun8i_r.c stable/12/sys/arm/allwinner/files.allwinner stable/12/sys/conf/files.arm64 stable/12/sys/dev/extres/clk/clk.h Directory Properties: stable/12/ (props changed) Modified: stable/12/sys/arm/allwinner/a10_sramc.c ============================================================================== --- stable/12/sys/arm/allwinner/a10_sramc.c Thu Nov 28 17:01:31 2019 (r355173) +++ stable/12/sys/arm/allwinner/a10_sramc.c Thu Nov 28 17:30:16 2019 (r355174) @@ -116,7 +116,7 @@ static driver_t a10_sramc_driver = { static devclass_t a10_sramc_devclass; EARLY_DRIVER_MODULE(a10_sramc, simplebus, a10_sramc_driver, a10_sramc_devclass, - 0, 0, BUS_PASS_RESOURCE + BUS_PASS_ORDER_EARLY); + 0, 0, BUS_PASS_SUPPORTDEV + BUS_PASS_ORDER_FIRST); int a10_map_to_emac(void) Modified: stable/12/sys/arm/allwinner/a20/a20_cpu_cfg.c ============================================================================== --- stable/12/sys/arm/allwinner/a20/a20_cpu_cfg.c Thu Nov 28 17:01:31 2019 (r355173) +++ stable/12/sys/arm/allwinner/a20/a20_cpu_cfg.c Thu Nov 28 17:30:16 2019 (r355174) @@ -119,7 +119,7 @@ static driver_t a20_cpu_cfg_driver = { static devclass_t a20_cpu_cfg_devclass; EARLY_DRIVER_MODULE(a20_cpu_cfg, simplebus, a20_cpu_cfg_driver, a20_cpu_cfg_devclass, 0, 0, - BUS_PASS_RESOURCE + BUS_PASS_ORDER_MIDDLE); + BUS_PASS_CPU + BUS_PASS_ORDER_FIRST); uint64_t a20_read_counter64(void) Modified: stable/12/sys/arm/allwinner/aw_gmacclk.c ============================================================================== --- stable/12/sys/arm/allwinner/aw_gmacclk.c Thu Nov 28 17:01:31 2019 (r355173) +++ stable/12/sys/arm/allwinner/aw_gmacclk.c Thu Nov 28 17:30:16 2019 (r355174) @@ -277,4 +277,4 @@ static driver_t aw_gmacclk_driver = { static devclass_t aw_gmacclk_devclass; EARLY_DRIVER_MODULE(aw_gmacclk, simplebus, aw_gmacclk_driver, - aw_gmacclk_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); + aw_gmacclk_devclass, 0, 0, BUS_PASS_RESOURCE + BUS_PASS_ORDER_MIDDLE); Modified: stable/12/sys/arm/allwinner/aw_reset.c ============================================================================== --- stable/12/sys/arm/allwinner/aw_reset.c Thu Nov 28 17:01:31 2019 (r355173) +++ stable/12/sys/arm/allwinner/aw_reset.c Thu Nov 28 17:30:16 2019 (r355174) @@ -160,5 +160,5 @@ static driver_t aw_reset_driver = { static devclass_t aw_reset_devclass; EARLY_DRIVER_MODULE(aw_reset, simplebus, aw_reset_driver, aw_reset_devclass, - 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); + 0, 0, BUS_PASS_RESOURCE + BUS_PASS_ORDER_MIDDLE); MODULE_VERSION(aw_reset, 1); Modified: stable/12/sys/arm/allwinner/aw_rsb.c ============================================================================== --- stable/12/sys/arm/allwinner/aw_rsb.c Thu Nov 28 17:01:31 2019 (r355173) +++ stable/12/sys/arm/allwinner/aw_rsb.c Thu Nov 28 17:30:16 2019 (r355174) @@ -492,9 +492,9 @@ static driver_t rsb_driver = { static devclass_t rsb_devclass; EARLY_DRIVER_MODULE(iicbus, rsb, iicbus_driver, iicbus_devclass, 0, 0, - BUS_PASS_RESOURCE + BUS_PASS_ORDER_MIDDLE); + BUS_PASS_SUPPORTDEV + BUS_PASS_ORDER_MIDDLE); EARLY_DRIVER_MODULE(rsb, simplebus, rsb_driver, rsb_devclass, 0, 0, - BUS_PASS_RESOURCE + BUS_PASS_ORDER_MIDDLE); + BUS_PASS_SUPPORTDEV + BUS_PASS_ORDER_MIDDLE); MODULE_VERSION(rsb, 1); MODULE_DEPEND(rsb, iicbus, 1, 1, 1); SIMPLEBUS_PNP_INFO(compat_data); Modified: stable/12/sys/arm/allwinner/aw_rtc.c ============================================================================== --- stable/12/sys/arm/allwinner/aw_rtc.c Thu Nov 28 17:01:31 2019 (r355173) +++ stable/12/sys/arm/allwinner/aw_rtc.c Thu Nov 28 17:30:16 2019 (r355174) @@ -185,7 +185,7 @@ static driver_t aw_rtc_driver = { static devclass_t aw_rtc_devclass; EARLY_DRIVER_MODULE(aw_rtc, simplebus, aw_rtc_driver, aw_rtc_devclass, 0, 0, - BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); + BUS_PASS_RESOURCE + BUS_PASS_ORDER_FIRST); MODULE_VERSION(aw_rtc, 1); SIMPLEBUS_PNP_INFO(compat_data); Modified: stable/12/sys/arm/allwinner/aw_sid.c ============================================================================== --- stable/12/sys/arm/allwinner/aw_sid.c Thu Nov 28 17:01:31 2019 (r355173) +++ stable/12/sys/arm/allwinner/aw_sid.c Thu Nov 28 17:30:16 2019 (r355174) @@ -412,6 +412,6 @@ static driver_t aw_sid_driver = { static devclass_t aw_sid_devclass; EARLY_DRIVER_MODULE(aw_sid, simplebus, aw_sid_driver, aw_sid_devclass, 0, 0, - BUS_PASS_RESOURCE + BUS_PASS_ORDER_FIRST); + BUS_PASS_SUPPORTDEV + BUS_PASS_ORDER_FIRST); MODULE_VERSION(aw_sid, 1); SIMPLEBUS_PNP_INFO(compat_data); Modified: stable/12/sys/arm/allwinner/aw_syscon.c ============================================================================== --- stable/12/sys/arm/allwinner/aw_syscon.c Thu Nov 28 17:01:31 2019 (r355173) +++ stable/12/sys/arm/allwinner/aw_syscon.c Thu Nov 28 17:30:16 2019 (r355174) @@ -82,5 +82,5 @@ DEFINE_CLASS_1(aw_syscon, aw_syscon_driver, aw_syscon_ static devclass_t aw_syscon_devclass; /* aw_syscon needs to attach prior to if_awg */ EARLY_DRIVER_MODULE(aw_syscon, simplebus, aw_syscon_driver, aw_syscon_devclass, - 0, 0, BUS_PASS_SUPPORTDEV + BUS_PASS_ORDER_MIDDLE); + 0, 0, BUS_PASS_SCHEDULER + BUS_PASS_ORDER_LAST); MODULE_VERSION(aw_syscon, 1); Modified: stable/12/sys/arm/allwinner/clkng/aw_ccung.c ============================================================================== --- stable/12/sys/arm/allwinner/clkng/aw_ccung.c Thu Nov 28 17:01:31 2019 (r355173) +++ stable/12/sys/arm/allwinner/clkng/aw_ccung.c Thu Nov 28 17:30:16 2019 (r355174) @@ -299,6 +299,9 @@ aw_ccung_attach(device_t dev) case AW_CLK_NM: aw_clk_nm_register(sc->clkdom, sc->clks[i].clk.nm); break; + case AW_CLK_M: + aw_clk_m_register(sc->clkdom, sc->clks[i].clk.m); + break; case AW_CLK_PREDIV_MUX: aw_clk_prediv_mux_register(sc->clkdom, sc->clks[i].clk.prediv_mux); @@ -306,6 +309,8 @@ aw_ccung_attach(device_t dev) case AW_CLK_FRAC: aw_clk_frac_register(sc->clkdom, sc->clks[i].clk.frac); break; + case AW_CLK_MIPI: + aw_clk_mipi_register(sc->clkdom, sc->clks[i].clk.mipi); } } Modified: stable/12/sys/arm/allwinner/clkng/aw_ccung.h ============================================================================== --- stable/12/sys/arm/allwinner/clkng/aw_ccung.h Thu Nov 28 17:01:31 2019 (r355173) +++ stable/12/sys/arm/allwinner/clkng/aw_ccung.h Thu Nov 28 17:30:16 2019 (r355174) @@ -31,6 +31,8 @@ #define __CCU_NG_H__ #include <arm/allwinner/clkng/aw_clk.h> +#include <arm/allwinner/clkng/aw_clk_m.h> +#include <arm/allwinner/clkng/aw_clk_mipi.h> #include <arm/allwinner/clkng/aw_clk_nkmp.h> #include <arm/allwinner/clkng/aw_clk_nm.h> #include <arm/allwinner/clkng/aw_clk_prediv_mux.h> @@ -48,6 +50,8 @@ enum aw_ccung_clk_type { AW_CLK_NM, AW_CLK_PREDIV_MUX, AW_CLK_FRAC, + AW_CLK_M, + AW_CLK_MIPI, }; struct aw_ccung_clk { @@ -60,6 +64,8 @@ struct aw_ccung_clk { struct aw_clk_nm_def *nm; struct aw_clk_prediv_mux_def *prediv_mux; struct aw_clk_frac_def *frac; + struct aw_clk_m_def *m; + struct aw_clk_mipi_def *mipi; } clk; }; Modified: stable/12/sys/arm/allwinner/clkng/aw_clk.h ============================================================================== --- stable/12/sys/arm/allwinner/clkng/aw_clk.h Thu Nov 28 17:01:31 2019 (r355173) +++ stable/12/sys/arm/allwinner/clkng/aw_clk.h Thu Nov 28 17:30:16 2019 (r355174) @@ -66,12 +66,15 @@ struct aw_clk_init { #define AW_CLK_SCALE_CHANGE 0x0010 #define AW_CLK_HAS_UPDATE 0x0040 #define AW_CLK_HAS_PREDIV 0x0080 +#define AW_CLK_SET_PARENT 0x0100 #define AW_CLK_FACTOR_POWER_OF_TWO 0x0001 #define AW_CLK_FACTOR_ZERO_BASED 0x0002 #define AW_CLK_FACTOR_HAS_COND 0x0004 #define AW_CLK_FACTOR_FIXED 0x0008 #define AW_CLK_FACTOR_ZERO_IS_ONE 0x0010 +#define AW_CLK_FACTOR_MIN_VALUE 0x0020 +#define AW_CLK_FACTOR_MAX_VALUE 0x0040 struct aw_clk_factor { uint32_t shift; /* Shift bits for the factor */ @@ -84,6 +87,9 @@ struct aw_clk_factor { uint32_t cond_width; uint32_t cond_value; + uint32_t min_value; + uint32_t max_value; + uint32_t flags; /* Flags */ }; @@ -146,6 +152,8 @@ aw_clk_factor_get_min(struct aw_clk_factor *factor) min = factor->value; else if (factor->flags & AW_CLK_FACTOR_ZERO_BASED) min = 0; + else if (factor->flags & AW_CLK_FACTOR_MIN_VALUE) + min = factor->min_value; else min = 1; @@ -165,7 +173,9 @@ aw_clk_factor_get_value(struct aw_clk_factor *factor, else if (factor->flags & AW_CLK_FACTOR_POWER_OF_TWO) { for (val = 0; raw != 1; val++) raw >>= 1; - } else + } else if (factor->flags & AW_CLK_FACTOR_MAX_VALUE) + val = factor->max_value; + else val = raw - 1; return (val); @@ -313,13 +323,15 @@ aw_clk_factor_get_value(struct aw_clk_factor *factor, _nshift, _nwidth, _nvalue, _nflags, \ _mshift, _mwidth, _mvalue, _mflags, \ _gate_shift, _lock_shift,_lock_retries, \ - _flags, _freq0, _freq1, _mode_sel, _freq_sel) \ + _flags, _freq0, _freq1, _mode_sel, _freq_sel, \ + _min_freq, _max_freq) \ static struct aw_clk_frac_def _clkname = { \ .clkdef = { \ .id = _id, \ .name = _name, \ .parent_names = _pnames, \ .parent_cnt = nitems(_pnames), \ + .flags = CLK_NODE_GLITCH_FREE, \ }, \ .offset = _offset, \ .n.shift = _nshift, \ @@ -338,8 +350,34 @@ aw_clk_factor_get_value(struct aw_clk_factor *factor, .frac.freq1 = _freq1, \ .frac.mode_sel = _mode_sel, \ .frac.freq_sel = _freq_sel, \ + .min_freq = _min_freq, \ + .max_freq = _max_freq, \ } +#define M_CLK(_clkname, _id, _name, _pnames, \ + _offset, \ + _mshift, _mwidth, _mvalue, _mflags, \ + _mux_shift, _mux_width, \ + _gate_shift, \ + _flags) \ + static struct aw_clk_m_def _clkname = { \ + .clkdef = { \ + .id = _id, \ + .name = _name, \ + .parent_names = _pnames, \ + .parent_cnt = nitems(_pnames), \ + }, \ + .offset = _offset, \ + .mux_shift = _mux_shift, \ + .m.shift = _mshift, \ + .m.width = _mwidth, \ + .m.value = _mvalue, \ + .m.flags = _mflags, \ + .mux_width = _mux_width, \ + .gate_shift = _gate_shift, \ + .flags = _flags, \ + } + #define NM_CLK(_clkname, _id, _name, _pnames, \ _offset, \ _nshift, _nwidth, _nvalue, _nflags, \ @@ -427,6 +465,32 @@ aw_clk_factor_get_value(struct aw_clk_factor *factor, .prediv.cond_mask = _prediv_cond_mask, \ .prediv.cond_value = _prediv_cond_value, \ } + +#define MIPI_CLK(_clkname, _id, _name, _pnames, \ + _offset, \ + _kshift, _kwidth, _kflags, _kmin, \ + _mshift, _mwidth, \ + _nshift, _nwidth, \ + _gate_shift, _lock_shift) \ + static struct aw_clk_mipi_def _clkname = { \ + .clkdef = { \ + .id = _id, \ + .name = _name, \ + .parent_names = _pnames, \ + .parent_cnt = nitems(_pnames) \ + }, \ + .offset = _offset, \ + .k.shift = _kshift, \ + .k.width = _kwidth, \ + .k.flags = _kflags, \ + .k.min_value = _kmin, \ + .m.shift = _mshift, \ + .m.width = _mwidth, \ + .n.shift = _nshift, \ + .n.width = _nwidth, \ + .gate_shift = _gate_shift, \ + .lock_shift = _lock_shift, \ + } #define MUX_CLK(_clkname, _id, _name, _pnames, \ _offset, _shift, _width) \ Modified: stable/12/sys/arm/allwinner/clkng/aw_clk_frac.c ============================================================================== --- stable/12/sys/arm/allwinner/clkng/aw_clk_frac.c Thu Nov 28 17:01:31 2019 (r355173) +++ stable/12/sys/arm/allwinner/clkng/aw_clk_frac.c Thu Nov 28 17:30:16 2019 (r355174) @@ -39,6 +39,9 @@ __FBSDID("$FreeBSD$"); #include "clkdev_if.h" +/* #define dprintf(format, arg...) printf("%s:(%s)" format, __func__, clknode_get_name(clk), arg) */ +#define dprintf(format, arg...) + /* * clknode for clocks matching the formula : * @@ -54,6 +57,9 @@ struct aw_clk_frac_sc { struct aw_clk_factor n; struct aw_clk_frac frac; + uint64_t min_freq; + uint64_t max_freq; + uint32_t mux_shift; uint32_t mux_mask; uint32_t gate_shift; @@ -89,6 +95,7 @@ aw_clk_frac_init(struct clknode *clk, device_t dev) idx = (val & sc->mux_mask) >> sc->mux_shift; } + dprintf("init parent idx %d\n", idx); clknode_init_parent_idx(clk, idx); return (0); } @@ -104,6 +111,7 @@ aw_clk_frac_set_gate(struct clknode *clk, bool enable) if ((sc->flags & AW_CLK_HAS_GATE) == 0) return (0); + dprintf("%sabling gate\n", enable ? "En" : "Dis"); DEVICE_LOCK(clk); READ4(clk, sc->offset, &val); if (enable) @@ -127,6 +135,7 @@ aw_clk_frac_set_mux(struct clknode *clk, int index) if ((sc->flags & AW_CLK_HAS_MUX) == 0) return (0); + dprintf("Set mux to %d\n", index); DEVICE_LOCK(clk); READ4(clk, sc->offset, &val); val &= ~sc->mux_mask; @@ -138,7 +147,7 @@ aw_clk_frac_set_mux(struct clknode *clk, int index) } static uint64_t -aw_clk_frac_find_best(struct aw_clk_frac_sc *sc, uint64_t fparent, uint64_t *fout, +aw_clk_frac_find_best(struct aw_clk_frac_sc *sc, uint64_t fparent, uint64_t fout, uint32_t *factor_n, uint32_t *factor_m) { uint64_t cur, best; @@ -150,18 +159,27 @@ aw_clk_frac_find_best(struct aw_clk_frac_sc *sc, uint6 max_m = aw_clk_factor_get_max(&sc->m); max_n = aw_clk_factor_get_max(&sc->n); min_m = aw_clk_factor_get_min(&sc->m); - min_n = aw_clk_factor_get_min(&sc->n); + min_n = sc->min_freq / fparent; for (n = min_n; n <= max_n; n++) { for (m = min_m; m <= max_m; m++) { cur = fparent * n / m; - if ((*fout - cur) < (*fout - best)) { + if (cur < sc->min_freq) { + continue; + } + if (cur > sc->max_freq) { + continue; + } + if (cur == fout) { + *factor_n = n; + *factor_m = m; + return (cur); + } + if (abs((fout - cur)) < abs((fout - best))) { best = cur; *factor_n = n; *factor_m = m; } - if (best == *fout) - return (best); } } @@ -175,32 +193,73 @@ aw_clk_frac_set_freq(struct clknode *clk, uint64_t fpa struct aw_clk_frac_sc *sc; uint64_t cur, best, best_frac; uint32_t val, m, n, best_m, best_n; - int retry; + int retry, multiple, max_mult, best_mult; sc = clknode_get_softc(clk); best = best_frac = cur = 0; + best_mult = 0; + max_mult = 1; - if (*fout == sc->frac.freq0) - best = best_frac = sc->frac.freq0; - else if (*fout == sc->frac.freq1) - best = best_frac = sc->frac.freq1; - else - best = aw_clk_frac_find_best(sc, fparent, fout, - &best_n, &best_m); + dprintf("Trying to find freq %ju with parent %ju\n", *fout, fparent); + if ((flags & CLK_SET_ROUND_MULTIPLE) != 0) + max_mult = 10; + for (multiple = 1; multiple <= max_mult; multiple++) { + /* First test the fractional frequencies */ + dprintf("Testing with multiple %d\n", multiple); + if (*fout * multiple == sc->frac.freq0) { + best = best_frac = sc->frac.freq0; + best_mult = multiple; + dprintf("Found with using frac.freq0 and multiple %d\n", multiple); + break; + } + else if (*fout * multiple == sc->frac.freq1) { + best = best_frac = sc->frac.freq1; + best_mult = multiple; + dprintf("Found with using frac.freq1 and multiple %d\n", multiple); + break; + } + else { + cur = aw_clk_frac_find_best(sc, fparent, *fout * multiple, + &n, &m); + dprintf("Got %ju with n=%d, m=%d\n", cur, n, m); + if (cur == (*fout * multiple)) { + best = cur; + best_mult = multiple; + best_n = n; + best_m = m; + dprintf("This is the one: n=%d m=%d mult=%d\n", best_n, best_m, best_mult); + break; + } + if (abs(((*fout * multiple) - cur)) < abs(((*fout * multiple) - best))) { + best = cur; + best_mult = multiple; + best_n = n; + best_m = m; + dprintf("This is the best for now: n=%d m=%d mult=%d\n", best_n, best_m, best_mult); + } + } + } + if (best < sc->min_freq || + best > sc->max_freq) { + printf("%s: Cannot set %ju for %s (min=%ju max=%ju)\n", + __func__, best, clknode_get_name(clk), + sc->min_freq, sc->max_freq); + return (ERANGE); + } if ((flags & CLK_SET_DRYRUN) != 0) { *fout = best; *stop = 1; return (0); } - if ((best < *fout) && + if ((best < (*fout * best_mult)) && ((flags & CLK_SET_ROUND_DOWN) == 0)) { *stop = 1; return (ERANGE); } - if ((best > *fout) && + if ((best > *fout * best_mult) && ((flags & CLK_SET_ROUND_UP) == 0)) { *stop = 1; return (ERANGE); @@ -271,7 +330,6 @@ aw_clk_frac_recalc(struct clknode *clk, uint64_t *freq } else { m = aw_clk_get_factor(val, &sc->m); n = aw_clk_get_factor(val, &sc->n); - *freq = *freq * n / m; } @@ -321,6 +379,9 @@ aw_clk_frac_register(struct clkdom *clkdom, struct aw_ 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->min_freq = clkdef->min_freq; + sc->max_freq = clkdef->max_freq; sc->mux_shift = clkdef->mux_shift; sc->mux_mask = ((1 << clkdef->mux_width) - 1) << sc->mux_shift; Modified: stable/12/sys/arm/allwinner/clkng/aw_clk_frac.h ============================================================================== --- stable/12/sys/arm/allwinner/clkng/aw_clk_frac.h Thu Nov 28 17:01:31 2019 (r355173) +++ stable/12/sys/arm/allwinner/clkng/aw_clk_frac.h Thu Nov 28 17:30:16 2019 (r355174) @@ -38,6 +38,9 @@ struct aw_clk_frac_def { struct aw_clk_factor n; struct aw_clk_frac frac; + uint64_t min_freq; + uint64_t max_freq; + uint32_t mux_shift; uint32_t mux_width; uint32_t gate_shift; Copied: stable/12/sys/arm/allwinner/clkng/aw_clk_m.c (from r350846, head/sys/arm/allwinner/clkng/aw_clk_m.c) ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ stable/12/sys/arm/allwinner/clkng/aw_clk_m.c Thu Nov 28 17:30:16 2019 (r355174, copy of r350846, head/sys/arm/allwinner/clkng/aw_clk_m.c) @@ -0,0 +1,290 @@ +/*- + * Copyright (c) 2019 Emmanuel Vadot <manu@freebsd.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/bus.h> + +#include <dev/extres/clk/clk.h> + +#include <arm/allwinner/clkng/aw_clk.h> +#include <arm/allwinner/clkng/aw_clk_m.h> + +#include "clkdev_if.h" + +/* + * clknode for clocks matching the formula : + * + * clk = clkin / m + * And that needs to potentially : + * 1) Set the parent freq + * 2) Support Setting the parent to a multiple + * + */ + +struct aw_clk_m_sc { + uint32_t offset; + + struct aw_clk_factor m; + + uint32_t mux_shift; + uint32_t mux_mask; + uint32_t gate_shift; + + uint32_t flags; +}; + +#define WRITE4(_clk, off, val) \ + CLKDEV_WRITE_4(clknode_get_device(_clk), off, val) +#define READ4(_clk, off, val) \ + CLKDEV_READ_4(clknode_get_device(_clk), off, val) +#define DEVICE_LOCK(_clk) \ + CLKDEV_DEVICE_LOCK(clknode_get_device(_clk)) +#define DEVICE_UNLOCK(_clk) \ + CLKDEV_DEVICE_UNLOCK(clknode_get_device(_clk)) + +static int +aw_clk_m_init(struct clknode *clk, device_t dev) +{ + struct aw_clk_m_sc *sc; + uint32_t val, idx; + + sc = clknode_get_softc(clk); + + idx = 0; + if ((sc->flags & AW_CLK_HAS_MUX) != 0) { + DEVICE_LOCK(clk); + READ4(clk, sc->offset, &val); + DEVICE_UNLOCK(clk); + + idx = (val & sc->mux_mask) >> sc->mux_shift; + } + + clknode_init_parent_idx(clk, idx); + return (0); +} + +static int +aw_clk_m_set_gate(struct clknode *clk, bool enable) +{ + struct aw_clk_m_sc *sc; + uint32_t val; + + sc = clknode_get_softc(clk); + + if ((sc->flags & AW_CLK_HAS_GATE) == 0) + return (0); + + DEVICE_LOCK(clk); + READ4(clk, sc->offset, &val); + if (enable) + val |= (1 << sc->gate_shift); + else + val &= ~(1 << sc->gate_shift); + WRITE4(clk, sc->offset, val); + DEVICE_UNLOCK(clk); + + return (0); +} + +static int +aw_clk_m_set_mux(struct clknode *clk, int index) +{ + struct aw_clk_m_sc *sc; + uint32_t val; + + sc = clknode_get_softc(clk); + + if ((sc->flags & AW_CLK_HAS_MUX) == 0) + return (0); + + DEVICE_LOCK(clk); + READ4(clk, sc->offset, &val); + val &= ~sc->mux_mask; + val |= index << sc->mux_shift; + WRITE4(clk, sc->offset, val); + DEVICE_UNLOCK(clk); + + return (0); +} + +static uint64_t +aw_clk_m_find_best(struct aw_clk_m_sc *sc, uint64_t fparent, uint64_t *fout, + uint32_t *factor_m) +{ + uint64_t cur, best; + uint32_t m, max_m, min_m; + + *factor_m = 0; + + max_m = aw_clk_factor_get_max(&sc->m); + min_m = aw_clk_factor_get_min(&sc->m); + + for (m = min_m; m <= max_m; ) { + cur = fparent / m; + if (abs(*fout - cur) < abs(*fout - best)) { + best = cur; + *factor_m = m; + } + if ((sc->m.flags & AW_CLK_FACTOR_POWER_OF_TWO) != 0) + m <<= 1; + else + m++; + } + + return (best); +} + +static int +aw_clk_m_set_freq(struct clknode *clk, uint64_t fparent, uint64_t *fout, + int flags, int *stop) +{ + struct aw_clk_m_sc *sc; + struct clknode *p_clk; + uint64_t cur, best; + uint32_t val, m, best_m; + + sc = clknode_get_softc(clk); + + best = cur = 0; + + if ((sc->flags & AW_CLK_SET_PARENT) != 0) { + p_clk = clknode_get_parent(clk); + if (p_clk == NULL) { + printf("%s: Cannot get parent for clock %s\n", + __func__, + clknode_get_name(clk)); + return (ENXIO); + } + clknode_set_freq(p_clk, *fout, CLK_SET_ROUND_MULTIPLE, 0); + clknode_get_freq(p_clk, &fparent); + best = aw_clk_m_find_best(sc, fparent, fout, + &best_m); + } else { + best = aw_clk_m_find_best(sc, fparent, fout, + &best_m); + } + + if ((flags & CLK_SET_DRYRUN) != 0) { + *fout = best; + *stop = 1; + return (0); + } + + if ((best < *fout) && + ((flags & CLK_SET_ROUND_DOWN) == 0)) { + *stop = 1; + return (ERANGE); + } + if ((best > *fout) && + ((flags & CLK_SET_ROUND_UP) == 0)) { + *stop = 1; + return (ERANGE); + } + + DEVICE_LOCK(clk); + READ4(clk, sc->offset, &val); + + m = aw_clk_factor_get_value(&sc->m, best_m); + val &= ~sc->m.mask; + val |= m << sc->m.shift; + + WRITE4(clk, sc->offset, val); + DEVICE_UNLOCK(clk); + + *fout = best; + *stop = 1; + + return (0); +} + +static int +aw_clk_m_recalc(struct clknode *clk, uint64_t *freq) +{ + struct aw_clk_m_sc *sc; + uint32_t val, m; + + sc = clknode_get_softc(clk); + + DEVICE_LOCK(clk); + READ4(clk, sc->offset, &val); + DEVICE_UNLOCK(clk); + + m = aw_clk_get_factor(val, &sc->m); + + *freq = *freq / m; + + return (0); +} + +static clknode_method_t aw_m_clknode_methods[] = { + /* Device interface */ + CLKNODEMETHOD(clknode_init, aw_clk_m_init), + CLKNODEMETHOD(clknode_set_gate, aw_clk_m_set_gate), + CLKNODEMETHOD(clknode_set_mux, aw_clk_m_set_mux), + CLKNODEMETHOD(clknode_recalc_freq, aw_clk_m_recalc), + CLKNODEMETHOD(clknode_set_freq, aw_clk_m_set_freq), + CLKNODEMETHOD_END +}; + +DEFINE_CLASS_1(aw_m_clknode, aw_m_clknode_class, aw_m_clknode_methods, + sizeof(struct aw_clk_m_sc), clknode_class); + +int +aw_clk_m_register(struct clkdom *clkdom, struct aw_clk_m_def *clkdef) +{ + struct clknode *clk; + struct aw_clk_m_sc *sc; + + clk = clknode_create(clkdom, &aw_m_clknode_class, &clkdef->clkdef); + if (clk == NULL) + return (1); + + sc = clknode_get_softc(clk); + + sc->offset = clkdef->offset; + + sc->m.shift = clkdef->m.shift; + sc->m.width = clkdef->m.width; + sc->m.mask = ((1 << sc->m.width) - 1) << sc->m.shift; + sc->m.value = clkdef->m.value; + sc->m.flags = clkdef->m.flags; + + sc->mux_shift = clkdef->mux_shift; + sc->mux_mask = ((1 << clkdef->mux_width) - 1) << sc->mux_shift; + + sc->gate_shift = clkdef->gate_shift; + + sc->flags = clkdef->flags; + + clknode_register(clkdom, clk); + + return (0); +} Copied: stable/12/sys/arm/allwinner/clkng/aw_clk_m.h (from r350846, head/sys/arm/allwinner/clkng/aw_clk_m.h) ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ stable/12/sys/arm/allwinner/clkng/aw_clk_m.h Thu Nov 28 17:30:16 2019 (r355174, copy of r350846, head/sys/arm/allwinner/clkng/aw_clk_m.h) @@ -0,0 +1,48 @@ +/*- + * Copyright (c) 2019 Emmanuel Vadot <manu@freebsd.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef __AW_CLK_M_H__ +#define __AW_CLK_M_H__ + +#include <dev/extres/clk/clk.h> + +struct aw_clk_m_def { + struct clknode_init_def clkdef; + uint32_t offset; + + struct aw_clk_factor m; + + uint32_t mux_shift; + uint32_t mux_width; + uint32_t gate_shift; + + uint32_t flags; +}; + +int aw_clk_m_register(struct clkdom *clkdom, struct aw_clk_m_def *clkdef); + +#endif /* __AW_CLK_M_H__ */ Copied: stable/12/sys/arm/allwinner/clkng/aw_clk_mipi.c (from r352848, head/sys/arm/allwinner/clkng/aw_clk_mipi.c) ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ stable/12/sys/arm/allwinner/clkng/aw_clk_mipi.c Thu Nov 28 17:30:16 2019 (r355174, copy of r352848, head/sys/arm/allwinner/clkng/aw_clk_mipi.c) @@ -0,0 +1,300 @@ +/*- + * Copyright (c) 2019 Emmanuel Vadot <manu@freebsd.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/bus.h> + +#include <dev/extres/clk/clk.h> + +#include <arm/allwinner/clkng/aw_clk.h> +#include <arm/allwinner/clkng/aw_clk_mipi.h> + +#include "clkdev_if.h" + +/* #define dprintf(format, arg...) printf("%s:(%s)" format, __func__, clknode_get_name(clk), arg) */ +#define dprintf(format, arg...) + +/* + * clknode for PLL_MIPI : + * + * clk = (pll_video0 * n * k) / m when vfb_sel=0 + * clk depend on sint_frac, sdiv2, s6p25_7p5, pll_feedback_div when vfb_sel=1 + * + */ + +struct aw_clk_mipi_sc { + uint32_t offset; + + struct aw_clk_factor k; + struct aw_clk_factor m; + struct aw_clk_factor n; + + uint64_t min_freq; + uint64_t max_freq; + + uint32_t gate_shift; + uint32_t lock_shift; + uint32_t lock_retries; + + uint32_t flags; +}; + +#define WRITE4(_clk, off, val) \ + CLKDEV_WRITE_4(clknode_get_device(_clk), off, val) +#define READ4(_clk, off, val) \ + CLKDEV_READ_4(clknode_get_device(_clk), off, val) +#define DEVICE_LOCK(_clk) \ + CLKDEV_DEVICE_LOCK(clknode_get_device(_clk)) +#define DEVICE_UNLOCK(_clk) \ + CLKDEV_DEVICE_UNLOCK(clknode_get_device(_clk)) + +#define LDO1_EN_SHIFT 23 +#define LDO2_EN_SHIFT 22 +#define VFB_SEL_SHIFT 16 + +static int +aw_clk_mipi_init(struct clknode *clk, device_t dev) +{ + struct aw_clk_mipi_sc *sc; + + sc = clknode_get_softc(clk); + + clknode_init_parent_idx(clk, 0); + return (0); +} + +static int +aw_clk_mipi_set_gate(struct clknode *clk, bool enable) +{ + struct aw_clk_mipi_sc *sc; + uint32_t val; + + sc = clknode_get_softc(clk); + + dprintf("%sabling gate\n", enable ? "En" : "Dis"); + DEVICE_LOCK(clk); + READ4(clk, sc->offset, &val); + if (enable) { + val |= (1 << sc->gate_shift); + val |= (1 << LDO1_EN_SHIFT); + val |= (1 << LDO2_EN_SHIFT); + } else { + val &= ~(1 << sc->gate_shift); + val &= ~(1 << LDO1_EN_SHIFT); + val &= ~(1 << LDO2_EN_SHIFT); + } + WRITE4(clk, sc->offset, val); + DEVICE_UNLOCK(clk); + + return (0); +} + +static uint64_t +aw_clk_mipi_find_best(struct aw_clk_mipi_sc *sc, uint64_t fparent, uint64_t *fout, + uint32_t *factor_k, uint32_t *factor_m, uint32_t *factor_n) +{ + uint64_t cur, best; + uint32_t n, k, m; + + best = 0; + *factor_n = 0; + *factor_k = 0; + *factor_m = 0; + + for (n = aw_clk_factor_get_min(&sc->n); n <= aw_clk_factor_get_max(&sc->n); ) { + for (k = aw_clk_factor_get_min(&sc->k); k <= aw_clk_factor_get_max(&sc->k); ) { + for (m = aw_clk_factor_get_min(&sc->m); m <= aw_clk_factor_get_max(&sc->m); ) { + cur = (fparent * n * k) / m; + if ((*fout - cur) < (*fout - best)) { + best = cur; + *factor_n = n; + *factor_k = k; + *factor_m = m; + } + if (best == *fout) + return (best); + m++; + } + k++; + } + n++; + } + + return best; +} + +static int +aw_clk_mipi_set_freq(struct clknode *clk, uint64_t fparent, uint64_t *fout, + int flags, int *stop) +{ + struct aw_clk_mipi_sc *sc; + uint64_t best = 0; + uint32_t best_k, best_m, best_n; + uint32_t k, m, n; + uint32_t val; + uint32_t retry; + + sc = clknode_get_softc(clk); + + best = aw_clk_mipi_find_best(sc, fparent, fout, &best_k, &best_m, &best_n); + + if (best < sc->min_freq || + best > sc->max_freq) { + printf("%s: Cannot set %ju for %s (min=%ju max=%ju)\n", + __func__, best, clknode_get_name(clk), + sc->min_freq, sc->max_freq); + return (ERANGE); + } + if ((flags & CLK_SET_DRYRUN) != 0) { + *fout = best; + *stop = 1; + return (0); + } + + DEVICE_LOCK(clk); + READ4(clk, sc->offset, &val); + /* Disable clock during freq changes */ + val &= ~(1 << sc->gate_shift); + WRITE4(clk, sc->offset, val); *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201911281730.xASHUH1x056531>