summaryrefslogtreecommitdiff
path: root/arch/arm
diff options
context:
space:
mode:
authorMarcel Ziswiler <marcel.ziswiler@toradex.com>2015-08-18 10:51:00 +0200
committerMarcel Ziswiler <marcel.ziswiler@toradex.com>2015-08-18 10:51:00 +0200
commitf7c3186985ebb244d075b04ed7c055f39f485670 (patch)
tree92f9b896ae3e5073e4cf9f47c82626e3d27f77b7 /arch/arm
parentf9e7649338178f823e291386dde5086ad636b703 (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.
Diffstat (limited to 'arch/arm')
-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 67f49d7756..1a74499946 100644
--- a/arch/arm/mach-tegra/tegra20/cpu.c
+++ b/arch/arm/mach-tegra/tegra20/cpu.c
@@ -15,16 +15,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);
@@ -38,8 +88,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();