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