summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-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)