summaryrefslogtreecommitdiff
path: root/arch/arm/cpu/tegra20-common/clock.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/cpu/tegra20-common/clock.c')
-rw-r--r--arch/arm/cpu/tegra20-common/clock.c141
1 files changed, 139 insertions, 2 deletions
diff --git a/arch/arm/cpu/tegra20-common/clock.c b/arch/arm/cpu/tegra20-common/clock.c
index 0c4f5fb..7b9e10c 100644
--- a/arch/arm/cpu/tegra20-common/clock.c
+++ b/arch/arm/cpu/tegra20-common/clock.c
@@ -7,6 +7,7 @@
/* Tegra20 Clock control functions */
#include <common.h>
+#include <errno.h>
#include <asm/io.h>
#include <asm/arch/clock.h>
#include <asm/arch/tegra.h>
@@ -332,7 +333,7 @@ static s8 periph_id_to_internal_id[PERIPH_ID_COUNT] = {
/* 0x48 */
NONE(AFI),
NONE(CORESIGHT),
- NONE(RESERVED74),
+ NONE(PCIEXCLK),
NONE(AVPUCQ),
NONE(RESERVED76),
NONE(RESERVED77),
@@ -494,7 +495,7 @@ enum periph_id clk_id_to_periph_id(int clk_id)
case PERIPH_ID_RESERVED30:
case PERIPH_ID_RESERVED35:
case PERIPH_ID_RESERVED56:
- case PERIPH_ID_RESERVED74:
+ case PERIPH_ID_PCIEXCLK:
case PERIPH_ID_RESERVED76:
case PERIPH_ID_RESERVED77:
case PERIPH_ID_RESERVED78:
@@ -548,3 +549,139 @@ void clock_early_init(void)
void arch_timer_init(void)
{
}
+
+#define PMC_SATA_PWRGT 0x1ac
+#define PMC_SATA_PWRGT_PLLE_IDDQ_OVERRIDE (1 << 5)
+#define PMC_SATA_PWRGT_PLLE_IDDQ_SWCTL (1 << 4)
+
+#define PLLE_SS_CNTL 0x68
+#define PLLE_SS_CNTL_SSCINCINTRV(x) (((x) & 0x3f) << 24)
+#define PLLE_SS_CNTL_SSCINC(x) (((x) & 0xff) << 16)
+#define PLLE_SS_CNTL_SSCBYP (1 << 12)
+#define PLLE_SS_CNTL_INTERP_RESET (1 << 11)
+#define PLLE_SS_CNTL_BYPASS_SS (1 << 10)
+#define PLLE_SS_CNTL_SSCMAX(x) (((x) & 0x1ff) << 0)
+
+#define PLLE_BASE 0x0e8
+#define PLLE_BASE_ENABLE_CML (1 << 31)
+#define PLLE_BASE_ENABLE (1 << 30)
+#define PLLE_BASE_PLDIV_CML(x) (((x) & 0xf) << 24)
+#define PLLE_BASE_PLDIV(x) (((x) & 0x3f) << 16)
+#define PLLE_BASE_NDIV(x) (((x) & 0xff) << 8)
+#define PLLE_BASE_MDIV(x) (((x) & 0xff) << 0)
+
+#define PLLE_MISC 0x0ec
+#define PLLE_MISC_SETUP_BASE(x) (((x) & 0xffff) << 16)
+#define PLLE_MISC_PLL_READY (1 << 15)
+#define PLLE_MISC_LOCK (1 << 11)
+#define PLLE_MISC_LOCK_ENABLE (1 << 9)
+#define PLLE_MISC_SETUP_EXT(x) (((x) & 0x3) << 2)
+
+static int tegra_plle_train(void)
+{
+ unsigned int timeout = 2000;
+ unsigned long value;
+
+ value = readl(NV_PA_PMC_BASE + PMC_SATA_PWRGT);
+ value |= PMC_SATA_PWRGT_PLLE_IDDQ_OVERRIDE;
+ writel(value, NV_PA_PMC_BASE + PMC_SATA_PWRGT);
+
+ value = readl(NV_PA_PMC_BASE + PMC_SATA_PWRGT);
+ value |= PMC_SATA_PWRGT_PLLE_IDDQ_SWCTL;
+ writel(value, NV_PA_PMC_BASE + PMC_SATA_PWRGT);
+
+ value = readl(NV_PA_PMC_BASE + PMC_SATA_PWRGT);
+ value &= ~PMC_SATA_PWRGT_PLLE_IDDQ_OVERRIDE;
+ writel(value, NV_PA_PMC_BASE + PMC_SATA_PWRGT);
+
+ do {
+ value = readl(NV_PA_CLK_RST_BASE + PLLE_MISC);
+ if (value & PLLE_MISC_PLL_READY)
+ break;
+
+ udelay(100);
+ } while (--timeout);
+
+ if (timeout == 0) {
+ error("timeout waiting for PLLE to become ready");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+int tegra_plle_enable(void)
+{
+ unsigned int timeout = 1000;
+ u32 value;
+ int err;
+
+ /* disable PLLE clock */
+ value = readl(NV_PA_CLK_RST_BASE + PLLE_BASE);
+ value &= ~PLLE_BASE_ENABLE_CML;
+ value &= ~PLLE_BASE_ENABLE;
+ writel(value, NV_PA_CLK_RST_BASE + PLLE_BASE);
+
+ /* clear lock enable and setup field */
+ value = readl(NV_PA_CLK_RST_BASE + PLLE_MISC);
+ value &= ~PLLE_MISC_LOCK_ENABLE;
+ value &= ~PLLE_MISC_SETUP_BASE(0xffff);
+ value &= ~PLLE_MISC_SETUP_EXT(0x3);
+ writel(value, NV_PA_CLK_RST_BASE + PLLE_MISC);
+
+ value = readl(NV_PA_CLK_RST_BASE + PLLE_MISC);
+ if ((value & PLLE_MISC_PLL_READY) == 0) {
+ err = tegra_plle_train();
+ if (err < 0) {
+ error("failed to train PLLE: %d", err);
+ return err;
+ }
+ }
+
+ value = readl(NV_PA_CLK_RST_BASE + PLLE_MISC);
+ value |= PLLE_MISC_SETUP_BASE(0x7);
+ value |= PLLE_MISC_LOCK_ENABLE;
+ value |= PLLE_MISC_SETUP_EXT(0);
+ writel(value, NV_PA_CLK_RST_BASE + PLLE_MISC);
+
+ value = readl(NV_PA_CLK_RST_BASE + PLLE_SS_CNTL);
+ value |= PLLE_SS_CNTL_SSCBYP | PLLE_SS_CNTL_INTERP_RESET |
+ PLLE_SS_CNTL_BYPASS_SS;
+ writel(value, NV_PA_CLK_RST_BASE + PLLE_SS_CNTL);
+
+ value = readl(NV_PA_CLK_RST_BASE + PLLE_BASE);
+ value |= PLLE_BASE_ENABLE_CML | PLLE_BASE_ENABLE;
+ writel(value, NV_PA_CLK_RST_BASE + PLLE_BASE);
+
+ do {
+ value = readl(NV_PA_CLK_RST_BASE + PLLE_MISC);
+ if (value & PLLE_MISC_LOCK)
+ break;
+
+ udelay(2);
+ } while (--timeout);
+
+ if (timeout == 0) {
+ error("timeout waiting for PLLE to lock");
+ return -ETIMEDOUT;
+ }
+
+ udelay(50);
+
+ value = readl(NV_PA_CLK_RST_BASE + PLLE_SS_CNTL);
+ value &= ~PLLE_SS_CNTL_SSCINCINTRV(0x3f);
+ value |= PLLE_SS_CNTL_SSCINCINTRV(0x18);
+
+ value &= ~PLLE_SS_CNTL_SSCINC(0xff);
+ value |= PLLE_SS_CNTL_SSCINC(0x01);
+
+ value &= ~PLLE_SS_CNTL_SSCBYP;
+ value &= ~PLLE_SS_CNTL_INTERP_RESET;
+ value &= ~PLLE_SS_CNTL_BYPASS_SS;
+
+ value &= ~PLLE_SS_CNTL_SSCMAX(0x1ff);
+ value |= PLLE_SS_CNTL_SSCMAX(0x24);
+ writel(value, NV_PA_CLK_RST_BASE + PLLE_SS_CNTL);
+
+ return 0;
+}