summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
authorMarcel Ziswiler <marcel.ziswiler@toradex.com>2015-08-18 10:51:00 +0200
committerMarcel Ziswiler <marcel.ziswiler@toradex.com>2017-01-11 21:27:15 +0100
commitd74c47c3647f9c11154e1d0bdcfabab819266d5c (patch)
tree1ebae3da9bf8cec7f5f1c8103e619295a7ecaf9f /arch
parentea16d8f07e828ea00cfac4c07c75f62723ffbb25 (diff)
colibri_t20: implement early pmic rail configuration
Implement early TPS6586X PMIC rail configuration setting SM0 being VDD_CORE_1.2V to 1.2 volts and SM1 being VDD_CPU_1.0V to 1.0 volts. While those are PMIC power-up defaults the SoC might have been reset separately with certain rails being left at lower DVFS states which is e.g. the case upon watchdog reset while otherwise nearly idling. (cherry picked from commit f7c3186985ebb244d075b04ed7c055f39f485670)
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/mach-tegra/tegra20/cpu.c78
1 files changed, 77 insertions, 1 deletions
diff --git a/arch/arm/mach-tegra/tegra20/cpu.c b/arch/arm/mach-tegra/tegra20/cpu.c
index 7fbc2e2865..3a0587b41c 100644
--- a/arch/arm/mach-tegra/tegra20/cpu.c
+++ b/arch/arm/mach-tegra/tegra20/cpu.c
@@ -5,16 +5,66 @@
*/
#include <common.h>
-#include <asm/io.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/pmu.h>
#include <asm/arch/tegra.h>
+#include <asm/arch-tegra/clk_rst.h>
#include <asm/arch-tegra/pmc.h>
+#include <asm/arch-tegra/tegra_i2c.h>
+#include <asm/io.h>
#include "../cpu.h"
+#define I2C_SEND_2_BYTES 0x0a02
+#define TPS6586X_I2C_ADDR (0x34<<1)
+#define TPS6586X_VCC1_REG 0x20
+#define TPS6586X_SM1V1_REG 0x23
+#define TPS6586X_SM0V1_REG 0x26
+
+/* Tegra20-specific DVC init code */
+void tegra_i2c_ll_init(void)
+{
+ struct dvc_ctlr *reg = (struct dvc_ctlr *)TEGRA_DVC_BASE;
+
+ writel(DVC_CTRL_REG3_I2C_HW_SW_PROG_MASK, &reg->ctrl3);
+}
+
+void tegra_i2c_ll_write(uint offset, uint8_t data)
+{
+ struct dvc_ctlr *reg = (struct dvc_ctlr *)TEGRA_DVC_BASE;
+
+ writel(TPS6586X_I2C_ADDR, &reg->cmd_addr0);
+ writel(2, &reg->cnfg);
+
+ writel((data << 8) | (offset & 0xff), &reg->cmd_data1);
+ writel(I2C_SEND_2_BYTES, &reg->cnfg);
+}
+
static void enable_cpu_power_rail(void)
{
struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
u32 reg;
+ debug("enable_cpu_power_rail entry\n");
+
+#ifdef CONFIG_TEGRA_EARLY_TPS6586X
+ tegra_i2c_ll_init();
+
+ /* Set SM0 being VDD_CORE_1.2V to 1.2 volts */
+ tegra_i2c_ll_write(TPS6586X_SM0V1_REG, 0x13);
+
+ udelay(1000);
+
+ /* Set SM1 being VDD_CPU_1.0V to 1.0 volts */
+ tegra_i2c_ll_write(TPS6586X_SM1V1_REG, 0x0b);
+
+ udelay(1000);
+
+ /* Make sure primary voltages are selected and ramped towards */
+ tegra_i2c_ll_write(TPS6586X_VCC1_REG, 0x05);
+
+ udelay(10 * 1000);
+#endif
+
reg = readl(&pmc->pmc_cntrl);
reg |= CPUPWRREQ_OE;
writel(reg, &pmc->pmc_cntrl);
@@ -28,8 +78,34 @@ static void enable_cpu_power_rail(void)
udelay(3750);
}
+/* T20 requires some special clock initialization, incl. setting up DVC I2C */
+void t20_init_clocks(void)
+{
+ debug("t20_init_clocks entry\n");
+
+ /* Put i2c in reset and enable clocks */
+ reset_set_enable(PERIPH_ID_DVC_I2C, 1);
+ clock_set_enable(PERIPH_ID_DVC_I2C, 1);
+
+ /*
+ * Our high-level clock routines are not available prior to
+ * relocation. We use the low-level functions which require a
+ * hard-coded divisor. Use CLK_M with divide by (n + 1 = 16)
+ */
+ clock_ll_set_source_divisor(PERIPH_ID_DVC_I2C, 3, 15);
+
+ /* Give clocks time to stabilize, then take i2c out of reset */
+ udelay(1000);
+
+ reset_set_enable(PERIPH_ID_DVC_I2C, 0);
+}
+
void start_cpu(u32 reset_vector)
{
+ debug("%s entry, reset_vector = %x\n", __func__, reset_vector);
+
+ t20_init_clocks();
+
/* Enable VDD_CPU */
enable_cpu_power_rail();