svn commit: r317013 - stable/11/sys/arm/nvidia/tegra124
Michal Meloun
mmel at FreeBSD.org
Sun Apr 16 08:21:16 UTC 2017
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);
More information about the svn-src-stable-11
mailing list