aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike J. Chen <mjchen@google.com>2012-03-01 15:28:46 -0800
committerMike J. Chen <mjchen@google.com>2012-03-03 17:29:39 -0800
commitf6354519c3fe82f4c3c406093212c6fcf3f7f083 (patch)
tree91cc7417137eccaa5def73fe678758aebfeeff9e
parent4ae13cf1682ea5a56ef1a40123d539c3b2868962 (diff)
downloaduboot-f6354519c3fe82f4c3c406093212c6fcf3f7f083.tar.gz
ARMV7: OMAP3+ Fix voltage bringup sequence
This is a patch from TI, backported from patches sent by Nishanth Menon <nm@ti.com> to u-boot upstream from us. I made some changes to make it apply to our older version of u-boot. For OMAP4460, the main impact is that IVA voltage is now scaled after MPU. We already had MPU come up after CORE. Current configuration results in the following voltage waveform (example 4460 Panda ES): |---------------| (SET1 default 1.4V) | --------(programmed voltage) | <- (This switch happens on mux7,pullup) vdd_mpu(TPS) -----/ (OPP boot voltage) --------- (programmed voltage) vdd_IVA(TWL6030) -------------------------/ (OPP boot voltage) --------- (programmed voltage) vdd_core(TWL6030) -----------------------/ (OPP boot voltage) Problem 1) |<----- Tx ------>| timing violation for a duration Tx close to few milliseconds. Problem 2) voltage of MPU goes beyond spec for even the highest of MPU OPP. Problem 3) All SoCs are doing MPU, CORE, IVA - which is a timing violation Oscilloscope picture: http://goo.gl/SykHb By using GPIO as recommended as standard procedure by TI and fixing the sequence in this series changes this to: --------- (programmed voltage) vdd_IVA(TWL6030) ------------------/ (OPP boot voltage) -------- (programmed voltage) vdd_mpu(TPS) ----------------/ (Opp boot voltage) --------- (programmed voltage) vdd_core(TWL6030) -------------/ (OPP boot voltage) Oscilloscope Picture: http://goo.gl/PgyKt Why is this critical: without the voltage sequence fixes, certain intermediate circuitry inside OMAP behaves in often unpredictable manner as they are operating out of spec. This in production line(extreme example of OMAP4460) translates close to ~5% devices failing to boot up and shows all kind of random untraceable crashes in production kernel. NOTE: 1. Clock sequences need to be fixed as well 2. kernel.org support for PandaBoard ES(OMAP4460) depends on the current wrong setup of u-boot to allow kernel boot to take place. This can and must be fixed. Merging this series breaks k.org, as a temporary WA: run: mw.w 0x4A31E05A 0x1f on u-boot prompt prior to booting the kernel to replicate old broken logic. Tested on: Pandaboard vanilla - OMAP4430 Pandaboard ES - OMAP4460 OMAP5 EVM Change-Id: I368a78e05da53133d4453d21bce3c53ccdfc3a18 Signed-off-by: Mike J. Chen <mjchen@google.com>
-rw-r--r--arch/arm/cpu/armv7/omap-common/Makefile1
-rw-r--r--arch/arm/cpu/armv7/omap-common/vc.c138
-rw-r--r--arch/arm/cpu/armv7/omap4/clocks.c115
-rw-r--r--arch/arm/include/asm/arch-omap4/clocks.h14
-rw-r--r--arch/arm/include/asm/arch-omap4/sys_proto.h3
5 files changed, 186 insertions, 85 deletions
diff --git a/arch/arm/cpu/armv7/omap-common/Makefile b/arch/arm/cpu/armv7/omap-common/Makefile
index eb4d25031..02055c4b7 100644
--- a/arch/arm/cpu/armv7/omap-common/Makefile
+++ b/arch/arm/cpu/armv7/omap-common/Makefile
@@ -30,6 +30,7 @@ SOBJS := reset.o
COBJS := timer.o
COBJS += utils.o
COBJS += gpio.o
+COBJS += vc.o
ifdef CONFIG_SPL_BUILD
COBJS += spl.o
diff --git a/arch/arm/cpu/armv7/omap-common/vc.c b/arch/arm/cpu/armv7/omap-common/vc.c
new file mode 100644
index 000000000..a045b7718
--- /dev/null
+++ b/arch/arm/cpu/armv7/omap-common/vc.c
@@ -0,0 +1,138 @@
+/*
+ * Voltage Controller implementation for OMAP
+ *
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ * Nishanth Menon
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <common.h>
+#include <asm/omap_common.h>
+#include <asm/arch/sys_proto.h>
+
+/*
+ * Define Master code if there are multiple masters on the I2C_SR bus.
+ * Normally not required
+ */
+#ifndef CONFIG_OMAP_VC_I2C_HS_MCODE
+#define CONFIG_OMAP_VC_I2C_HS_MCODE 0x0
+#endif
+
+/* Register defines and masks for VC IP Block */
+/* PRM_VC_CFG_I2C_MODE */
+#define PRM_VC_CFG_I2C_MODE_DFILTEREN_BIT (0x1 << 6)
+#define PRM_VC_CFG_I2C_MODE_SRMODEEN_BIT (0x1 << 4)
+#define PRM_VC_CFG_I2C_MODE_HSMODEEN_BIT (0x1 << 3)
+#define PRM_VC_CFG_I2C_MODE_HSMCODE_SHIFT 0x0
+#define PRM_VC_CFG_I2C_MODE_HSMCODE_MASK 0x3
+
+/* PRM_VC_CFG_I2C_CLK */
+#define PRM_VC_CFG_I2C_CLK_HSCLL_SHIFT 24
+#define PRM_VC_CFG_I2C_CLK_HSCLL_MASK 0xFF
+#define PRM_VC_CFG_I2C_CLK_HSCLH_SHIFT 16
+#define PRM_VC_CFG_I2C_CLK_HSCLH_MASK 0xFF
+#define PRM_VC_CFG_I2C_CLK_SCLH_SHIFT 0
+#define PRM_VC_CFG_I2C_CLK_SCLH_MASK 0xFF
+#define PRM_VC_CFG_I2C_CLK_SCLL_SHIFT 8
+#define PRM_VC_CFG_I2C_CLK_SCLL_MASK (0xFF << 8)
+
+/* PRM_VC_VAL_BYPASS */
+#define PRM_VC_VAL_BYPASS_VALID_BIT (0x1 << 24)
+#define PRM_VC_VAL_BYPASS_SLAVEADDR_SHIFT 0
+#define PRM_VC_VAL_BYPASS_SLAVEADDR_MASK 0x7F
+#define PRM_VC_VAL_BYPASS_REGADDR_SHIFT 8
+#define PRM_VC_VAL_BYPASS_REGADDR_MASK 0xFF
+#define PRM_VC_VAL_BYPASS_DATA_SHIFT 16
+#define PRM_VC_VAL_BYPASS_DATA_MASK 0xFF
+
+/**
+ * omap_vc_init() - Initialization for Voltage controller
+ * @speed_khz: I2C buspeed in KHz
+ */
+void omap_vc_init(u16 speed_khz)
+{
+ u32 val;
+ u32 sys_clk_khz, cycles_hi, cycles_low;
+
+ sys_clk_khz = get_sys_clk_freq() / 1000;
+
+ if (speed_khz > 400) {
+ puts("higher speed requested - throttle to 400Khz\n");
+ speed_khz = 400;
+ }
+
+ /*
+ * Setup the dedicated I2C controller for Voltage Control
+ * I2C clk - high period 40% low period 60%
+ */
+ speed_khz /= 10;
+ cycles_hi = sys_clk_khz * 4 / speed_khz;
+ cycles_low = sys_clk_khz * 6 / speed_khz;
+ /* values to be set in register - less by 5 & 7 respectively */
+ cycles_hi -= 5;
+ cycles_low -= 7;
+ val = (cycles_hi << PRM_VC_CFG_I2C_CLK_SCLH_SHIFT) |
+ (cycles_low << PRM_VC_CFG_I2C_CLK_SCLL_SHIFT);
+ writel(val, &prcm->prm_vc_cfg_i2c_clk);
+
+ val = CONFIG_OMAP_VC_I2C_HS_MCODE <<
+ PRM_VC_CFG_I2C_MODE_HSMCODE_SHIFT;
+ /* No HS mode for now */
+ val &= ~PRM_VC_CFG_I2C_MODE_HSMODEEN_BIT;
+ writel(val, &prcm->prm_vc_cfg_i2c_mode);
+}
+
+/**
+ * omap_vc_bypass_send_value() - Send a data using VC Bypass command
+ * @sa: 7 bit I2C slave address of the PMIC
+ * @reg_addr: I2C register address(8 bit) address in PMIC
+ * @reg_data: what 8 bit data to write
+ */
+int omap_vc_bypass_send_value(u8 sa, u8 reg_addr, u8 reg_data)
+{
+ /*
+ * Unfortunately we need to loop here instead of a defined time
+ * use arbitary large value
+ */
+ u32 timeout = 0xFFFF;
+ u32 reg_val;
+
+ sa &= PRM_VC_VAL_BYPASS_SLAVEADDR_MASK;
+ reg_addr &= PRM_VC_VAL_BYPASS_REGADDR_MASK;
+ reg_data &= PRM_VC_VAL_BYPASS_DATA_MASK;
+
+ /* program VC to send data */
+ reg_val = sa << PRM_VC_VAL_BYPASS_SLAVEADDR_SHIFT |
+ reg_addr << PRM_VC_VAL_BYPASS_REGADDR_SHIFT |
+ reg_data << PRM_VC_VAL_BYPASS_DATA_SHIFT;
+ writel(reg_val, &prcm->prm_vc_val_bypass);
+
+ /* Signal VC to send data */
+ writel(reg_val | PRM_VC_VAL_BYPASS_VALID_BIT, &prcm->prm_vc_val_bypass);
+
+ /* Wait on VC to complete transmission */
+ do {
+ reg_val = readl(&prcm->prm_vc_val_bypass) &
+ PRM_VC_VAL_BYPASS_VALID_BIT;
+ if (!reg_val)
+ break;
+
+ sdelay(100);
+ } while (--timeout);
+
+ /* Optional: cleanup PRM_IRQSTATUS_Ax */
+ /* In case we can do something about it in future.. */
+ if (!timeout)
+ return -1;
+
+ /* All good.. */
+ return 0;
+}
diff --git a/arch/arm/cpu/armv7/omap4/clocks.c b/arch/arm/cpu/armv7/omap4/clocks.c
index 0738fce55..355cb5a53 100644
--- a/arch/arm/cpu/armv7/omap4/clocks.c
+++ b/arch/arm/cpu/armv7/omap4/clocks.c
@@ -525,7 +525,7 @@ static void setup_non_essential_dplls(void)
static void do_scale_tps62361(u32 reg, u32 volt_mv)
{
- u32 temp, step;
+ u32 step;
step = volt_mv - TPS62361_BASE_VOLT_MV;
step /= 10;
@@ -537,17 +537,8 @@ static void do_scale_tps62361(u32 reg, u32 volt_mv)
*/
gpio_direction_output(TPS62361_VSEL0_GPIO, 0);
- temp = TPS62361_I2C_SLAVE_ADDR |
- (reg << PRM_VC_VAL_BYPASS_REGADDR_SHIFT) |
- (step << PRM_VC_VAL_BYPASS_DATA_SHIFT) |
- PRM_VC_VAL_BYPASS_VALID_BIT;
- debug("do_scale_tps62361: volt - %d step - 0x%x\n", volt_mv, step);
-
- writel(temp, &prcm->prm_vc_val_bypass);
- if (!wait_on_value(PRM_VC_VAL_BYPASS_VALID_BIT, 0,
- &prcm->prm_vc_val_bypass, LDELAY)) {
+ if (omap_vc_bypass_send_value(TPS62361_I2C_SLAVE_ADDR, reg, step))
puts("Scaling voltage failed for vdd_mpu from TPS\n");
- }
/*
* SET1 register default is 1.4V which is higher than OPPNITROSB
@@ -559,7 +550,7 @@ static void do_scale_tps62361(u32 reg, u32 volt_mv)
static void do_scale_vcore(u32 vcore_reg, u32 volt_mv)
{
- u32 temp, offset_code;
+ u32 offset_code;
u32 step = 12660; /* 12.66 mV represented in uV */
u32 offset = volt_mv;
@@ -578,15 +569,9 @@ static void do_scale_vcore(u32 vcore_reg, u32 volt_mv)
debug("do_scale_vcore: volt - %d offset_code - 0x%x\n", volt_mv,
offset_code);
- temp = SMPS_I2C_SLAVE_ADDR |
- (vcore_reg << PRM_VC_VAL_BYPASS_REGADDR_SHIFT) |
- (offset_code << PRM_VC_VAL_BYPASS_DATA_SHIFT) |
- PRM_VC_VAL_BYPASS_VALID_BIT;
- writel(temp, &prcm->prm_vc_val_bypass);
- if (!wait_on_value(PRM_VC_VAL_BYPASS_VALID_BIT, 0,
- &prcm->prm_vc_val_bypass, LDELAY)) {
+ if (omap_vc_bypass_send_value(SMPS_I2C_SLAVE_ADDR,
+ vcore_reg, offset_code))
printf("Scaling voltage failed for 0x%x\n", vcore_reg);
- }
}
/* Since this code runs in spl, and spl currently doesn't link
@@ -609,83 +594,71 @@ int use_tps62361(void)
*/
static void scale_vcores(void)
{
- u32 volt, sys_clk_khz, cycles_hi, cycles_low, temp, omap4_rev;
+ u32 volt;
- sys_clk_khz = get_sys_clk_freq() / 1000;
+ omap_vc_init(PRM_VC_I2C_CHANNEL_FREQ_KHZ);
- /*
- * Setup the dedicated I2C controller for Voltage Control
- * I2C clk - high period 40% low period 60%
+ /* Scale Voltage rails in order:
+ * 1. VDD_CORE
+ * 2. VDD_MPU
+ * 3. VDD_IVA
+ *
+ * If tps62361 is not in use (generally OMAP4430):
+ * VDD_CORE = TWL6030 VCORE3
+ * VDD_MPU = TWL6030 VCORE1
+ * VDD_IVA = TWL6030 VCORE2
+ *
+ * If tps62361 is in use (OMAP4460, or a board designed
+ * for OMAP4460 but with a OMAP4430 SOC):
+ * VDD_CORE = TWL6030 VCORE1
+ * VDD_MPU = TPS62361
+ * VDD_IVA = TWL6030 VCORE2
*/
- cycles_hi = sys_clk_khz * 4 / PRM_VC_I2C_CHANNEL_FREQ_KHZ / 10;
- cycles_low = sys_clk_khz * 6 / PRM_VC_I2C_CHANNEL_FREQ_KHZ / 10;
- /* values to be set in register - less by 5 & 7 respectively */
- cycles_hi -= 5;
- cycles_low -= 7;
- temp = (cycles_hi << PRM_VC_CFG_I2C_CLK_SCLH_SHIFT) |
- (cycles_low << PRM_VC_CFG_I2C_CLK_SCLL_SHIFT);
- writel(temp, &prcm->prm_vc_cfg_i2c_clk);
-
- /* Disable high speed mode and all advanced features */
- writel(0x0, &prcm->prm_vc_cfg_i2c_mode);
- omap4_rev = omap_revision();
-
- /*
- * VCORE 3
- * 4430 : supplies vdd_core, must come up before vdd_mpu
- * 4460 : not connected
- */
if (!use_tps62361()) {
+ /* 1. VDD_CORE */
/* For OMAP4430, according to DM, for OPP100,
* VDD MPU = 1.127v
*/
volt = 1127;
do_scale_vcore(SMPS_REG_ADDR_VCORE3, volt);
- }
- /*
- * VCORE 1
- *
- * 4430 : supplies vdd_mpu
- * Setting a high voltage for Nitro mode as smart reflex is not enabled.
- * We use the maximum possible value in the AVS range because the next
- * higher voltage in the discrete range (code >= 0b111010) is way too
- * high
- *
- * 4460 : supplies vdd_core
- */
- if (!use_tps62361()) {
- /* For OMAP4460, according to DM, for OPP100,
+ /* 2. VDD_MPU */
+ /* For OMAP4430, according to DM, for OPP100,
* VDD MPU = 1.200v
*/
volt = 1200;
+ do_scale_vcore(SMPS_REG_ADDR_VCORE1, volt);
+
+ /* 3. VDD_IVA */
+ /* For OMAP4430, according to DM, for OPP100,
+ * VDD IVA = 1.114v
+ */
+ volt = 1114;
+ do_scale_vcore(SMPS_REG_ADDR_VCORE2, volt);
+
} else {
+ /* 1. VDD_CORE */
/* For OMAP4460, according to DM, for OPP100,
* VDD CORE = 1.127v
*/
volt = 1127;
- }
- do_scale_vcore(SMPS_REG_ADDR_VCORE1, volt);
-
- /* VCORE 2 - supplies vdd_iva */
- /* For OMAP4430 & OMAP4460, according to DM, for OPP100,
- * VDD IVA = 1.114v
- */
- volt = 1114;
- do_scale_vcore(SMPS_REG_ADDR_VCORE2, volt);
+ do_scale_vcore(SMPS_REG_ADDR_VCORE1, volt);
- /* TPS - supplies vdd_mpu on 4460. MPU power domain
- * depends on the core voltage domain, so do this after
- * core voltage domain scaling is done.
- */
- if (use_tps62361()) {
+ /* 2. VDD_MPU */
/* For OMAP4460, according to DM, for OPP100,
* VDD MPU = 1.203v, but round up for TPS to 1.21v
*/
volt = 1210;
printf("Setting TPS to %dmV\n", volt);
do_scale_tps62361(TPS62361_REG_ADDR_SET1, volt);
+
+ /* 3. VDD_IVA */
+ /* For OMAP4460, according to DM, for OPP100,
+ * VDD IVA = 1.114v
+ */
+ volt = 1114;
+ do_scale_vcore(SMPS_REG_ADDR_VCORE2, volt);
}
}
diff --git a/arch/arm/include/asm/arch-omap4/clocks.h b/arch/arm/include/asm/arch-omap4/clocks.h
index 9f012c5e6..afb450fd9 100644
--- a/arch/arm/include/asm/arch-omap4/clocks.h
+++ b/arch/arm/include/asm/arch-omap4/clocks.h
@@ -606,23 +606,9 @@ struct omap4_prcm_regs {
#define OMAP_SYS_CLK_IND_38_4_MHZ 6
#define OMAP_32K_CLK_FREQ 32768
-/* PRM_VC_CFG_I2C_CLK */
-#define PRM_VC_CFG_I2C_CLK_SCLH_SHIFT 0
-#define PRM_VC_CFG_I2C_CLK_SCLH_MASK 0xFF
-#define PRM_VC_CFG_I2C_CLK_SCLL_SHIFT 8
-#define PRM_VC_CFG_I2C_CLK_SCLL_MASK (0xFF << 8)
-
/* PRM_VC_VAL_BYPASS */
#define PRM_VC_I2C_CHANNEL_FREQ_KHZ 400
-#define PRM_VC_VAL_BYPASS_VALID_BIT 0x1000000
-#define PRM_VC_VAL_BYPASS_SLAVEADDR_SHIFT 0
-#define PRM_VC_VAL_BYPASS_SLAVEADDR_MASK 0x7F
-#define PRM_VC_VAL_BYPASS_REGADDR_SHIFT 8
-#define PRM_VC_VAL_BYPASS_REGADDR_MASK 0xFF
-#define PRM_VC_VAL_BYPASS_DATA_SHIFT 16
-#define PRM_VC_VAL_BYPASS_DATA_MASK 0xFF
-
/* SMPS */
#define SMPS_I2C_SLAVE_ADDR 0x12
#define SMPS_REG_ADDR_VCORE1 0x55
diff --git a/arch/arm/include/asm/arch-omap4/sys_proto.h b/arch/arm/include/asm/arch-omap4/sys_proto.h
index 1f213a9f0..dbd598109 100644
--- a/arch/arm/include/asm/arch-omap4/sys_proto.h
+++ b/arch/arm/include/asm/arch-omap4/sys_proto.h
@@ -53,6 +53,9 @@ u32 omap4_ddr_clk(void);
void cancel_out(u32 *num, u32 *den, u32 den_limit);
void sdram_init(void);
u32 omap4_sdram_size(void);
+void omap_vc_init(u16 speed_khz);
+int omap_vc_bypass_send_value(u8 sa, u8 reg_addr, u8 reg_data);
+
int use_tps62361(void);
void dieid_num_r(void);