Date: Sun, 16 Apr 2017 08:21:14 +0000 (UTC) From: Michal Meloun <mmel@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-11@freebsd.org Subject: svn commit: r317013 - stable/11/sys/arm/nvidia/tegra124 Message-ID: <201704160821.v3G8LEHM003575@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: mmel Date: Sun Apr 16 08:21:14 2017 New Revision: 317013 URL: https://svnweb.freebsd.org/changeset/base/317013 Log: MFC r309538: Fixes for NVIDIA Tegra124 clocks: - EMC clock have standard peripheral clock block. Use it. - Implement full frequency set method for PLLD2. This PLL is used as HDMI pixel clock so we must be able to set it to wide range of frequencies, within 5% tolerance allowed by HDMI specification. Due to this, full state space search (over m, n, p fields) is necessary. Modified: stable/11/sys/arm/nvidia/tegra124/tegra124_car.c stable/11/sys/arm/nvidia/tegra124/tegra124_clk_per.c stable/11/sys/arm/nvidia/tegra124/tegra124_clk_pll.c Directory Properties: stable/11/ (props changed) Modified: stable/11/sys/arm/nvidia/tegra124/tegra124_car.c ============================================================================== --- stable/11/sys/arm/nvidia/tegra124/tegra124_car.c Sun Apr 16 08:18:37 2017 (r317012) +++ stable/11/sys/arm/nvidia/tegra124/tegra124_car.c Sun Apr 16 08:21:14 2017 (r317013) @@ -189,8 +189,6 @@ PLIST(mux_pll_srcs) = {"osc_div_clk", NU PLIST(mux_plle_src1) = {"osc_div_clk", "pllP_out0"}; PLIST(mux_plle_src) = {"pllE_src1", "pllREFE_out"}; PLIST(mux_plld_out0_plld2_out0) = {"pllD_out0", "pllD2_out0"}; -PLIST(mux_pllmcp_clkm) = {"pllM_out0", "pllC_out0", "pllP_out0", "clk_m", - "pllM_UD", "pllC2_out0", "pllC3_out0", "pllC_UD"}; PLIST(mux_xusb_hs) = {"xusb_ss_div2", "pllU_60"}; PLIST(mux_xusb_ss) = {"pc_xusb_ss", "osc_div_clk"}; @@ -240,7 +238,6 @@ static struct clk_mux_def tegra124_mux_c /* Base peripheral clocks. */ MUX(0, "dsia_mux", mux_plld_out0_plld2_out0, PLLD_BASE, 25, 1), MUX(0, "dsib_mux", mux_plld_out0_plld2_out0, PLLD2_BASE, 25, 1), - MUX(0, "emc_mux", mux_pllmcp_clkm, CLK_SOURCE_EMC, 29, 3), /* USB. */ MUX(TEGRA124_CLK_XUSB_HS_SRC, "xusb_hs", mux_xusb_hs, CLK_SOURCE_XUSB_SS, 25, 1), Modified: stable/11/sys/arm/nvidia/tegra124/tegra124_clk_per.c ============================================================================== --- stable/11/sys/arm/nvidia/tegra124/tegra124_clk_per.c Sun Apr 16 08:18:37 2017 (r317012) +++ stable/11/sys/arm/nvidia/tegra124/tegra124_clk_per.c Sun Apr 16 08:21:14 2017 (r317013) @@ -126,6 +126,10 @@ PLIST(mux_m_c_p_a_c2_c3_clkm_c4) = PLIST(mux_m_c_p_clkm_mud_c2_c3) = {"pllM_out0", "pllC_out0", "pllP_out0", "clk_m", "pllM_UD", "pllC2_out0", "pllC3_out0"}; +PLIST(mux_m_c_p_clkm_mud_c2_c3_cud) = + {"pllM_out0", "pllC_out0", "pllP_out0", "clk_m", + "pllM_UD", "pllC2_out0", "pllC3_out0", "pllC_UD"}; + PLIST(mux_m_c2_c_c3_p_N_a) = {"pllM_out0", "pllC2_out0", "pllC_out0", "pllC3_out0", "pllP_out0", NULL, "pllA_out0"}; @@ -260,7 +264,7 @@ static struct pgate_def pgate_def[] = { GATE(I2C2, "i2c2", "pc_i2c2", H(22)), GATE(UARTC, "uartc", "pc_uartc", H(23)), GATE(MIPI_CAL, "mipi_cal", "clk_m", H(24)), - GATE(EMC, "emc", "emc_mux", H(25)), + GATE(EMC, "emc", "pc_emc_2x", H(25)), GATE(USB2, "usb2", "clk_m", H(26)), GATE(USB3, "usb3", "clk_m", H(27)), GATE(VDE, "vde", "pc_vde", H(29)), @@ -356,7 +360,7 @@ static struct pgate_def pgate_def[] = { /* GATE(CAM_MCLK, "CAM_MCLK", "clk_m", X(4)), */ /* GATE(CAM_MCLK2, "CAM_MCLK2", "clk_m", X(5)), */ GATE(I2C6, "i2c6", "pc_i2c6", X(6)), - /* GATE(VIM2_CLK, "vim2_clk", clk_m, X(11)), */ + GATE(VIM2_CLK, "vim2_clk", "clk_m", X(11)), /* GATE(EMC_DLL, "emc_dll", "pc_emc_dll", X(14)), */ GATE(HDMI_AUDIO, "hdmi_audio", "pc_hdmi_audio", X(16)), GATE(CLK72MHZ, "clk72mhz", "pc_clk72mhz", X(17)), @@ -373,17 +377,18 @@ static struct pgate_def pgate_def[] = { #define DCF_HAVE_ENA 0x0200 /* Block with enable bit */ #define DCF_HAVE_DIV 0x0400 /* Block with divider */ -/* Mark block with additional bis / functionality. */ +/* Mark block with additional bits / functionality. */ #define DCF_IS_MASK 0x00FF #define DCF_IS_UART 0x0001 #define DCF_IS_VI 0x0002 #define DCF_IS_HOST1X 0x0003 #define DCF_IS_XUSB_SS 0x0004 #define DCF_IS_EMC_DLL 0x0005 -#define FDS_IS_SATA 0x0006 +#define DCF_IS_SATA 0x0006 #define DCF_IS_VIC 0x0007 #define DCF_IS_AUDIO 0x0008 #define DCF_IS_SOR0 0x0009 +#define DCF_IS_EMC 0x000A /* Basic pheripheral clock */ #define PER_CLK(_id, cn, pl, r, diw, fiw, f) \ @@ -438,7 +443,7 @@ static struct periph_def periph_def[] = CLK_8_1(0, "pc_host1x", mux_p_c2_c_c3_m_N_clkm, CLK_SOURCE_HOST1X, DCF_IS_HOST1X), CLK_8_1(0, "pc_hdmi", mux_p_m_d_a_c_d2_clkm, CLK_SOURCE_HDMI, 0), CLK16_0(0, "pc_i2c2", mux_p_c2_c_c3_m_N_clkm, CLK_SOURCE_I2C2, 0), -/* EMC 8 */ + CLK_8_1(0, "pc_emc_2x", mux_m_c_p_clkm_mud_c2_c3_cud, CLK_SOURCE_EMC, DCF_IS_EMC), CLK16_1(0, "pc_uartc", mux_p_c2_c_c3_m_N_clkm, CLK_SOURCE_UARTC, DCF_IS_UART), CLK_8_1(0, "pc_vi_sensor", mux_m_c2_c_c3_p_N_a, CLK_SOURCE_VI_SENSOR, 0), CLK_8_1(0, "pc_spi4", mux_p_c2_c_c3_m_N_clkm, CLK_SOURCE_SPI4, 0), @@ -476,7 +481,7 @@ static struct periph_def periph_def[] = /* SYS */ CLK_8_1(0, "pc_sor0", mux_p_m_d_a_c_d2_clkm, CLK_SOURCE_SOR0, DCF_IS_SOR0), CLK_8_1(0, "pc_sata_oob", mux_p_N_c_N_m_N_clkm, CLK_SOURCE_SATA_OOB, 0), - CLK_8_1(0, "pc_sata", mux_p_N_c_N_m_N_clkm, CLK_SOURCE_SATA, FDS_IS_SATA), + CLK_8_1(0, "pc_sata", mux_p_N_c_N_m_N_clkm, CLK_SOURCE_SATA, DCF_IS_SATA), CLK_8_1(0, "pc_hda", mux_p_c2_c_c3_m_N_clkm, CLK_SOURCE_HDA, 0), CLK_8_1(TEGRA124_CLK_XUSB_HOST_SRC, "pc_xusb_core_host", mux_clkm_p_c2_c_c3_refre, CLK_SOURCE_XUSB_CORE_HOST, 0), Modified: stable/11/sys/arm/nvidia/tegra124/tegra124_clk_pll.c ============================================================================== --- stable/11/sys/arm/nvidia/tegra124/tegra124_clk_pll.c Sun Apr 16 08:18:37 2017 (r317012) +++ stable/11/sys/arm/nvidia/tegra124/tegra124_clk_pll.c Sun Apr 16 08:21:14 2017 (r317013) @@ -713,6 +713,7 @@ pll_set_std(struct pll_sc *sc, uint64_t return (ERANGE); *fout = ((fin / m) * n) /p; + return (0); } @@ -771,7 +772,6 @@ pllc_set_freq(struct pll_sc *sc, uint64_ { uint32_t m, n, p; - p = 2; m = 1; n = (*fout * p * m + fin / 2)/ fin; @@ -779,19 +779,88 @@ pllc_set_freq(struct pll_sc *sc, uint64_ return (pll_set_std( sc, fin, fout, flags, m, n, p)); } +/* + * PLLD2 is used as source for pixel clock for HDMI. + * We must be able to set it frequency very flexibly and + * precisely (within 5% tolerance limit allowed by HDMI specs). + * + * For this reason, it is necessary to search the full state space. + * Fortunately, thanks to early cycle terminations, performance + * is within acceptable limits. + */ +#define PLLD2_PFD_MIN 12000000 /* 12 MHz */ +#define PLLD2_PFD_MAX 38000000 /* 38 MHz */ +#define PLLD2_VCO_MIN 600000000 /* 600 MHz */ +#define PLLD2_VCO_MAX 1200000000 /* 1.2 GHz */ + static int plld2_set_freq(struct pll_sc *sc, uint64_t fin, uint64_t *fout, int flags) { uint32_t m, n, p; + uint32_t best_m, best_n, best_p; + uint64_t vco, pfd; + int64_t err, best_err; + struct mnp_bits *mnp_bits; + struct pdiv_table *tbl; + int p_idx, rv; - p = 2; - m = 1; - n = (*fout * p * m + fin / 2)/ fin; - dprintf("%s: m: %d, n: %d, p: %d\n", __func__, m, n, p); - return (pll_set_std(sc, fin, fout, flags, m, n, p)); -} + mnp_bits = &sc->mnp_bits; + tbl = sc->pdiv_table; + best_err = INT64_MAX; + for (p_idx = 0; tbl[p_idx].divider != 0; p_idx++) { + p = tbl[p_idx].divider; + /* Check constraints */ + vco = *fout * p; + if (vco < PLLD2_VCO_MIN) + continue; + if (vco > PLLD2_VCO_MAX) + break; + + for (m = 1; m < (1 << mnp_bits->m_width); m++) { + n = (*fout * p * m + fin / 2) / fin; + + /* Check constraints */ + if (n == 0) + continue; + if (n >= (1 << mnp_bits->n_width)) + break; + vco = (fin * n) / m; + if (vco > PLLD2_VCO_MAX || vco < PLLD2_VCO_MIN) + continue; + pfd = fin / m; + if (pfd > PLLD2_PFD_MAX || vco < PLLD2_PFD_MIN) + continue; + + /* Constraints passed, save best result */ + err = *fout - vco / p; + if (err < 0) + err = -err; + if (err < best_err) { + best_err = err; + best_p = p; + best_m = m; + best_n = n; + } + if (err == 0) + goto done; + } + } +done: + /* + * HDMI specification allows 5% pixel clock tolerance, + * we will by a slightly stricter + */ + if (best_err > ((*fout * 100) / 4)) + return (ERANGE); + + if (flags & CLK_SET_DRYRUN) + return (0); + rv = pll_set_std(sc, fin, fout, flags, best_m, best_n, best_p); + /* XXXX Panic for rv == ERANGE ? */ + return (rv); +} static int pllrefe_set_freq(struct pll_sc *sc, uint64_t fin, uint64_t *fout, int flags) @@ -883,8 +952,8 @@ tegra124_pll_set_freq(struct clknode *cl struct pll_sc *sc; sc = clknode_get_softc(clknode); - dprintf("%s: Requested freq: %llu, input freq: %llu\n", __func__, - *fout, fin); + dprintf("%s: %s requested freq: %llu, input freq: %llu\n", __func__, + clknode_get_name(clknode), *fout, fin); switch (sc->type) { case PLL_A: rv = plla_set_freq(sc, fin, fout, flags);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201704160821.v3G8LEHM003575>