[coreboot-gerrit] New patch to review for coreboot: b3ca3db tegra124: clock: Enforce PLL constraints for VCO and CF

Marc Jones (marc.jones@se-eng.com) gerrit at coreboot.org
Wed Dec 10 04:20:27 CET 2014


Marc Jones (marc.jones at se-eng.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/7768

-gerrit

commit b3ca3db5d95f770e67534c05611726300f7691f1
Author: Julius Werner <jwerner at chromium.org>
Date:   Fri Apr 11 18:23:12 2014 -0700

    tegra124: clock: Enforce PLL constraints for VCO and CF
    
    This patch adds some documentation to the additional PLL divisor
    constraints on the intermediary VCO and CF values that we just found out
    about. PLLC divisors for some oscillators had to be adjusted
    accordingly.
    
    It also adds a new clock_get_pll_input_khz() function to replace
    clock_get_osc_khz() in cases where you want to factor in the built-in
    predivider for 38.4 and 48 MHz oscillators.
    
    BUG=None
    TEST=Still boots.
    
    Original-Change-Id: Ib6e026dbab9fcc50d6d81a884774ad07c7b0dbc3
    Original-Signed-off-by: Julius Werner <jwerner at chromium.org>
    Original-Reviewed-on: https://chromium-review.googlesource.com/194474
    Original-Reviewed-by: Hung-Te Lin <hungte at chromium.org>
    (cherry picked from commit 3f1f565baf100edcd486055e4317c675c882396f)
    Signed-off-by: Marc Jones <marc.jones at se-eng.com>
    
    Change-Id: I091f42bf952a4b58ef2c30586baa5bf7496fa599
---
 src/soc/nvidia/tegra/usb.c                  |  2 +-
 src/soc/nvidia/tegra124/clk_rst.h           | 38 ++++++------
 src/soc/nvidia/tegra124/clock.c             | 90 ++++++++++++++---------------
 src/soc/nvidia/tegra124/include/soc/clock.h |  1 +
 src/soc/nvidia/tegra124/sdram.c             |  2 +-
 5 files changed, 67 insertions(+), 66 deletions(-)

diff --git a/src/soc/nvidia/tegra/usb.c b/src/soc/nvidia/tegra/usb.c
index 39477e1..e0455ed 100644
--- a/src/soc/nvidia/tegra/usb.c
+++ b/src/soc/nvidia/tegra/usb.c
@@ -28,7 +28,7 @@
 void usb_setup_utmip(struct usb_ctlr *usb)
 {
 	/* KHz formulas were guessed from U-Boot constants. Formats unclear. */
-	int khz = clock_get_osc_khz();
+	int khz = clock_get_pll_input_khz();
 
 	/* Stop UTMI+ crystal clock while we mess with its settings */
 	clrbits_le32(&usb->utmip.misc1, 1 << 30);	/* PHY_XTAL_CLKEN */
diff --git a/src/soc/nvidia/tegra124/clk_rst.h b/src/soc/nvidia/tegra124/clk_rst.h
index efceec5..d2249f7 100644
--- a/src/soc/nvidia/tegra124/clk_rst.h
+++ b/src/soc/nvidia/tegra124/clk_rst.h
@@ -325,15 +325,25 @@ check_member(clk_rst_ctlr, clk_src_soc_therm, 0x644);
 #define CPU0_CLK_STP_MASK		(1U << CPU0_CLK_STP_SHIFT)
 
 /* CRC_OSC_CTRL_0 0x50 */
-#define OSC_CTRL_OSC_FREQ		(0xf << 28)
-#define OSC_CTRL_OSC_FREQ_SHIFT		28
-#define OSC_FREQ_OSC13			0	/* 13.0MHz */
-#define OSC_FREQ_OSC19P2		4	/* 19.2MHz */
-#define OSC_FREQ_OSC12			8	/* 12.0MHz */
-#define OSC_FREQ_OSC26			12	/* 26.0MHz */
-#define OSC_FREQ_OSC16P8		1	/* 16.8MHz */
-#define OSC_FREQ_OSC38P4		5	/* 38.4MHz */
-#define OSC_FREQ_OSC48			9	/* 48.0MHz */
+#define OSC_FREQ_SHIFT			28
+#define OSC_FREQ_MASK			(0xf << OSC_FREQ_SHIFT)
+#define OSC_PREDIV_SHIFT		26
+#define OSC_PREDIV_MASK			(0x3 << OSC_PREDIV_SHIFT)
+#define OSC_XOFS_SHIFT			4
+#define OSC_XOFS_MASK			(0x3F << OSC_XOFS_SHIFT)
+#define OSC_DRIVE_STRENGTH		7
+#define OSC_XOBP			(1 << 1)
+#define OSC_XOE				(1 << 0)
+
+enum {
+	OSC_FREQ_12	= 8,	/* 12.0MHz */
+	OSC_FREQ_13	= 0,	/* 13.0MHz */
+	OSC_FREQ_16P8	= 1,	/* 16.8MHz */
+	OSC_FREQ_19P2	= 4,	/* 19.2MHz */
+	OSC_FREQ_26	= 12,	/* 26.0MHz */
+	OSC_FREQ_38P4	= 5,	/* 38.4MHz */
+	OSC_FREQ_48	= 9,	/* 48.0MHz */
+};
 
 /* CLK_RST_CONTROLLER_PLL*_BASE_0 */
 #define PLL_BASE_BYPASS			(1U << 31)
@@ -409,16 +419,6 @@ check_member(clk_rst_ctlr, clk_src_soc_therm, 0x644);
 #define PLLX_IDDQ_SHIFT			3
 #define PLLX_IDDQ_MASK			(1U << PLLX_IDDQ_SHIFT)
 
-/* CLK_RST_CONTROLLER_OSC_CTRL_0 0x50 */
-#define OSC_XOE_SHIFT			0
-#define OSC_XOE_MASK			(1 << OSC_XOE_SHIFT)
-#define OSC_XOE_ENABLE			(1 << OSC_XOE_SHIFT)
-#define OSC_XOBP_SHIFT			1
-#define OSC_XOBP_MASK			(1U << OSC_XOBP_SHIFT)
-#define OSC_XOFS_SHIFT			4
-#define OSC_XOFS_MASK			(0x3F << OSC_XOFS_SHIFT)
-#define OSC_DRIVE_STRENGTH		7
-
 #define CLK_DIVISOR_MASK		(0xffff)
 
 #define CLK_SOURCE_SHIFT		29
diff --git a/src/soc/nvidia/tegra124/clock.c b/src/soc/nvidia/tegra124/clock.c
index d12c4b2..765e447 100644
--- a/src/soc/nvidia/tegra124/clock.c
+++ b/src/soc/nvidia/tegra124/clock.c
@@ -81,75 +81,77 @@ union __attribute__((transparent_union)) pll_fields {
 
 /* This table defines the frequency dividers for every PLL to turn the external
  * OSC clock into the frequencies defined by TEGRA_PLL*_KHZ in soc/clock.h.
- * All PLLs have three dividers (N, M and P), with the governing formula for
- * the output frequency being OUT = (IN / m) * N / (2^P).
- * Yes, it really is one equation with three unknowns ... */
+ * All PLLs have three dividers (n, m and p), with the governing formula for
+ * the output frequency being CF = (IN / m), VCO = CF * n and OUT = VCO / (2^p).
+ * All divisor configurations must meet the PLL's constraints for VCO and CF:
+ * PLLX:  12 MHz < CF < 50 MHz, 700 MHz < VCO < 3000 MHz
+ * PLLC:  12 MHz < CF < 50 MHz, 600 MHz < VCO < 1400 MHz
+ * PLLM:  12 MHz < CF < 50 MHz, 400 MHz < VCO < 1066 MHz
+ * PLLP:   1 MHz < CF <  6 MHz, 200 MHz < VCO <  700 MHz
+ * PLLD:   1 MHz < CF <  6 MHz, 500 MHz < VCO < 1000 MHz
+ * PLLU:   1 MHz < CF <  6 MHz, 480 MHz < VCO <  960 MHz
+ * PLLDP: 12 MHz < CF < 38 MHz, 600 MHz < VCO < 1200 MHz
+ * (values taken from Linux' drivers/clk/tegra/clk-tegra124.c). */
 struct {
 	int khz;
 	struct pllcx_dividers	pllx;	/* target:  CONFIG_PLLX_KHZ */
 	struct pllcx_dividers	pllc;	/* target:  600 MHz */
+	/* PLLM is set up dynamically by clock_sdram(). */
+	/* PLLP is hardwired to 408 MHz in HW (unless we set BASE_OVRD). */
 	struct pllu_dividers	pllu;	/* target;  960 MHz */
 	struct pllcx_dividers	plldp;	/* target;  270 MHz */
-	/* Based on T124 TRM (to be updatd), PLLP is set to 408MHz in HW.
-	 * Unless configuring PLLP to a frequency other than 408MHz,
-	 * software configuration on PLLP is unneeded. */
+	/* PLLDP treats p differently (OUT = VCO / (p + 1) for p < 6). */
 } static const osc_table[16] = {
-	[OSC_FREQ_OSC12]{
+	[OSC_FREQ_12]{
 		.khz = 12000,
 		.pllx = {.n = TEGRA_PLLX_KHZ / 12000, .m =  1, .p = 0},
 		.pllc = {.n =  50, .m =  1, .p = 0},
 		.pllu = {.n = 960, .m = 12, .p = 0, .cpcon = 12, .lfcon = 2},
 		.plldp = {.n = 90, .m =  1, .p = 3},
 	},
-	[OSC_FREQ_OSC13]{
+	[OSC_FREQ_13]{
 		.khz = 13000,
 		.pllx = {.n = TEGRA_PLLX_KHZ / 13000, .m =  1, .p = 0},
-		.pllc = {.n = 231, .m =  5, .p = 0},		/* 600.6 MHz */
+		.pllc = {.n =  46, .m =  1, .p = 0},		 /* 598.0 MHz */
 		.pllu = {.n = 960, .m = 13, .p = 0, .cpcon = 12, .lfcon = 2},
-		.plldp = {.n = 83, .m =  1, .p = 3},		/* 269.75 MHz */
+		.plldp = {.n = 83, .m =  1, .p = 3},		 /* 269.8 MHz */
 	},
-	[OSC_FREQ_OSC16P8]{
+	[OSC_FREQ_16P8]{
 		.khz = 16800,
 		.pllx = {.n = TEGRA_PLLX_KHZ / 16800, .m =  1, .p = 0},
-		.pllc = {.n = 250, .m =  7, .p = 0},
+		.pllc = {.n =  71, .m =  1, .p = 1},		 /* 596.4 MHz */
 		.pllu = {.n = 400, .m =  7, .p = 0, .cpcon = 5, .lfcon = 2},
-		.plldp = {.n = 64, .m =  1, .p = 3},		/* 268.8 MHz */
+		.plldp = {.n = 64, .m =  1, .p = 3},		 /* 268.8 MHz */
 	},
-	[OSC_FREQ_OSC19P2]{
+	[OSC_FREQ_19P2]{
 		.khz = 19200,
 		.pllx = {.n = TEGRA_PLLX_KHZ / 19200, .m =  1, .p = 0},
-		.pllc = {.n = 125, .m =  4, .p = 0},
+		.pllc = {.n =  62, .m =  1, .p = 1},		 /* 595.2 MHz */
 		.pllu = {.n = 200, .m =  4, .p = 0, .cpcon = 3, .lfcon = 2},
-		.plldp = {.n = 56, .m =  1, .p = 3},		/* 270.75 MHz */
+		.plldp = {.n = 56, .m =  1, .p = 3},		 /* 268.8 MHz */
 	},
-	[OSC_FREQ_OSC26]{
+	[OSC_FREQ_26]{
 		.khz = 26000,
 		.pllx = {.n = TEGRA_PLLX_KHZ / 26000, .m =  1, .p = 0},
-		.pllc = {.n =  23, .m =  1, .p = 0},		   /* 598 MHz */
+		.pllc = {.n =  23, .m =  1, .p = 0},		 /* 598.0 MHz */
 		.pllu = {.n = 960, .m = 26, .p = 0, .cpcon = 12, .lfcon = 2},
-		.plldp = {.n = 83, .m =  2, .p = 3},		/* 266.50 MHz */
+		.plldp = {.n = 83, .m =  2, .p = 3},		 /* 269.8 MHz */
 	},
-	[OSC_FREQ_OSC38P4]{
+	/* These oscillators get predivided as PLL inputs... n/m/p divisors for
+	 * 38.4 should always match 19.2, and 48 should always match 12. */
+	[OSC_FREQ_38P4]{
 		.khz = 38400,
-		/*
-		 * There is a predivide by 2 before this PLL. Its values
-		 * should match the 19.2MHz values.
-		 */
 		.pllx = {.n = TEGRA_PLLX_KHZ / 19200, .m =  1, .p = 0},
-		.pllc = {.n = 125, .m =  4, .p = 0},
+		.pllc = {.n =  62, .m =  1, .p = 1},		 /* 595.2 MHz */
 		.pllu = {.n = 200, .m =  4, .p = 0, .cpcon = 3, .lfcon = 2},
-		.plldp = {.n = 56, .m =  2, .p = 3},		/* 268 MHz */
+		.plldp = {.n = 56, .m =  1, .p = 3},		 /* 268.8 MHz */
 	},
-	[OSC_FREQ_OSC48]{
+	[OSC_FREQ_48]{
 		.khz = 48000,
-		/*
-		 * There is a predivide by 4 before this PLL. Its values
-		 * should match the 12MHz values.
-		 */
 		.pllx = {.n = TEGRA_PLLX_KHZ / 12000, .m =  1, .p = 0},
 		.pllc = {.n =  50, .m =  1, .p = 0},
 		.pllu = {.n = 960, .m = 12, .p = 0, .cpcon = 12, .lfcon = 2},
-		.plldp = {.n = 90, .m =  4, .p = 3},		/* 264 MHz */
+		.plldp = {.n = 90, .m =  1, .p = 3},
 	},
 };
 
@@ -159,7 +161,7 @@ struct {
  */
 static u32 clock_get_osc_bits(void)
 {
-	return readl(&clk_rst->osc_ctrl) >> OSC_CTRL_OSC_FREQ_SHIFT;
+	return (readl(&clk_rst->osc_ctrl) & OSC_FREQ_MASK) >> OSC_FREQ_SHIFT;
 }
 
 int clock_get_osc_khz(void)
@@ -167,6 +169,14 @@ int clock_get_osc_khz(void)
 	return osc_table[clock_get_osc_bits()].khz;
 }
 
+int clock_get_pll_input_khz(void)
+{
+	u32 osc_ctrl = readl(&clk_rst->osc_ctrl);
+	u32 osc_bits = (osc_ctrl & OSC_FREQ_MASK) >> OSC_FREQ_SHIFT;
+	u32 pll_ref_div = (osc_ctrl & OSC_PREDIV_MASK) >> OSC_PREDIV_SHIFT;
+	return osc_table[osc_bits].khz >> pll_ref_div;
+}
+
 void clock_init_arm_generic_timer(void)
 {
 	uint32_t freq = clock_get_osc_khz() * 1000;
@@ -225,7 +235,7 @@ static void init_pll(u32 *base, u32 *misc, const union pll_fields pll, u32 lock)
 
 static void init_utmip_pll(void)
 {
-	int khz = clock_get_osc_khz();
+	int khz = clock_get_pll_input_khz();
 
 	/* Shut off PLL crystal clock while we mess with it */
 	clrbits_le32(&clk_rst->utmip_pll_cfg2, 1 << 30); /* PHY_XTAL_CLKEN */
@@ -304,22 +314,12 @@ clock_display(u32 frequency)
 	 */
 
 	struct pllpad_dividers plld = { 0 };
-	u32 ref = clock_get_osc_khz() * 1000, m, n;
+	u32 ref = clock_get_pll_input_khz() * 1000, m, n;
 	u32 cf, vco = frequency;
 	const u32 max_m = 1 << 5, max_n = 1 << 10, mhz = 1000 * 1000,
 		  min_vco = 500 * mhz, max_vco = 1000 * mhz,
 		  min_cf = 1 * mhz, max_cf = 6 * mhz;
 
-	/* TODO(hungte) Replace this by clock_get_pll_input_khz */
-	switch (clock_get_osc_bits()) {
-	case OSC_FREQ_OSC48:
-		ref /= 4;
-		break;
-	case OSC_FREQ_OSC38P4:
-		ref /= 2;
-		break;
-	}
-
 	if (vco < min_vco || vco > max_vco) {
 		printk(BIOS_ERR, "%s: VCO (%d) out of range. Cannot support.\n",
 		       __func__, vco);
diff --git a/src/soc/nvidia/tegra124/include/soc/clock.h b/src/soc/nvidia/tegra124/include/soc/clock.h
index aff6abe..73274a5 100644
--- a/src/soc/nvidia/tegra124/include/soc/clock.h
+++ b/src/soc/nvidia/tegra124/include/soc/clock.h
@@ -278,6 +278,7 @@ enum clock_source {  /* Careful: Not true for all sources, always check TRM! */
 #define TEGRA_PLLU_KHZ   (960000)
 
 int clock_get_osc_khz(void);
+int clock_get_pll_input_khz(void);
 int clock_display(u32 frequency);
 void clock_early_uart(void);
 void clock_external_output(int clk_id);
diff --git a/src/soc/nvidia/tegra124/sdram.c b/src/soc/nvidia/tegra124/sdram.c
index 1854e1d..f0797db 100644
--- a/src/soc/nvidia/tegra124/sdram.c
+++ b/src/soc/nvidia/tegra124/sdram.c
@@ -570,7 +570,7 @@ void sdram_init(const struct sdram_params *param)
 	struct tegra_emc_regs *emc = (struct tegra_emc_regs*)TEGRA_EMC_BASE;
 
 	printk(BIOS_DEBUG, "Initializing SDRAM of type %d with %dKHz\n",
-		param->MemoryType, clock_get_osc_khz() *
+		param->MemoryType, clock_get_pll_input_khz() *
 		param->PllMFeedbackDivider / param->PllMInputDivider /
 		(1 + param->PllMSelectDiv2));
 	if (param->MemoryType != NvBootMemoryType_Ddr3)



More information about the coreboot-gerrit mailing list