summaryrefslogtreecommitdiff
path: root/src/soc/nvidia
diff options
context:
space:
mode:
authorJulius Werner <jwerner@chromium.org>2014-04-11 18:23:12 -0700
committerMarc Jones <marc.jones@se-eng.com>2014-12-16 23:29:16 +0100
commite57c30315309a82de64da21dd83bba79864033c9 (patch)
tree1d312f055a981d5a9c5e077b2a783e5525b0cfda /src/soc/nvidia
parentd712ec47d48f765dbc9008d94b58842d6c24b544 (diff)
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@chromium.org> Original-Reviewed-on: https://chromium-review.googlesource.com/194474 Original-Reviewed-by: Hung-Te Lin <hungte@chromium.org> (cherry picked from commit 3f1f565baf100edcd486055e4317c675c882396f) Signed-off-by: Marc Jones <marc.jones@se-eng.com> Change-Id: I091f42bf952a4b58ef2c30586baa5bf7496fa599 Reviewed-on: http://review.coreboot.org/7768 Reviewed-by: Paul Menzel <paulepanter@users.sourceforge.net> Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org> Tested-by: build bot (Jenkins)
Diffstat (limited to 'src/soc/nvidia')
-rw-r--r--src/soc/nvidia/tegra/usb.c2
-rw-r--r--src/soc/nvidia/tegra124/clk_rst.h38
-rw-r--r--src/soc/nvidia/tegra124/clock.c90
-rw-r--r--src/soc/nvidia/tegra124/include/soc/clock.h1
-rw-r--r--src/soc/nvidia/tegra124/sdram.c2
5 files changed, 67 insertions, 66 deletions
diff --git a/src/soc/nvidia/tegra/usb.c b/src/soc/nvidia/tegra/usb.c
index 39477e17d3..e0455ed05c 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 efceec5f31..d2249f7669 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 d12c4b2e89..765e447ecb 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 aff6abe505..73274a5c71 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 1854e1dbd9..f0797db652 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)