[U-Boot] [PATCH 0/4] OMAP3+: Fix voltage bringup sequence

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
Nishanth Menon (4): OMAP3+: Introduce generic logic for OMAP voltage controller OMAP4460: TPS Ensure SET1 is selected after voltage configuration OMAP4: scale voltage of core before MPU scales OMAP5: scale voltage of core before MPU scales
arch/arm/cpu/armv7/omap-common/Makefile | 1 + arch/arm/cpu/armv7/omap-common/clocks-common.c | 67 ++++-------- arch/arm/cpu/armv7/omap-common/vc.c | 138 ++++++++++++++++++++++++ arch/arm/cpu/armv7/omap4/clocks.c | 64 ++++++----- arch/arm/cpu/armv7/omap5/clocks.c | 10 +- arch/arm/include/asm/arch-omap4/clocks.h | 17 +--- arch/arm/include/asm/arch-omap4/sys_proto.h | 2 + arch/arm/include/asm/arch-omap5/clocks.h | 17 +--- arch/arm/include/asm/arch-omap5/sys_proto.h | 2 + board/ti/panda/panda_mux_data.h | 2 +- board/ti/sdp4430/sdp4430_mux_data.h | 2 +- 11 files changed, 211 insertions(+), 111 deletions(-) create mode 100644 arch/arm/cpu/armv7/omap-common/vc.c
Regards, Nishanth Menon

OMAP Voltage controller is used to generically talk to PMICs on OMAP3,4,5 over I2C_SR. Instead of replicating code in multiple SoC code, introduce a common voltage controller logic which can be re-used from elsewhere.
With this change, we replace setup_sri2c with omap_vc_init which has the same functionality, and replace the voltage scale replication in do_scale_vcore and do_scale_tps62361 with omap_vc_bypass_send_value. omap_vc_bypass_send_value can also now be used with any configuration of PMIC.
NOTE: Voltage controller controlling I2C_SR is a write-only data path, so no register read operation can be implemented.
Reported-by: Isabelle Gros i-gros@ti.com Reported-by: Jerome Angeloni j-angeloni@ti.com Signed-off-by: Nishanth Menon nm@ti.com --- arch/arm/cpu/armv7/omap-common/Makefile | 1 + arch/arm/cpu/armv7/omap-common/clocks-common.c | 48 +-------- arch/arm/cpu/armv7/omap-common/vc.c | 138 ++++++++++++++++++++++++ arch/arm/cpu/armv7/omap4/clocks.c | 2 +- arch/arm/cpu/armv7/omap5/clocks.c | 2 +- arch/arm/include/asm/arch-omap4/clocks.h | 15 --- arch/arm/include/asm/arch-omap4/sys_proto.h | 2 + arch/arm/include/asm/arch-omap5/clocks.h | 15 --- arch/arm/include/asm/arch-omap5/sys_proto.h | 2 + 9 files changed, 150 insertions(+), 75 deletions(-) create mode 100644 arch/arm/cpu/armv7/omap-common/vc.c
diff --git a/arch/arm/cpu/armv7/omap-common/Makefile b/arch/arm/cpu/armv7/omap-common/Makefile index 3f7a0b2..c318669 100644 --- a/arch/arm/cpu/armv7/omap-common/Makefile +++ b/arch/arm/cpu/armv7/omap-common/Makefile @@ -37,6 +37,7 @@ ifneq ($(CONFIG_OMAP44XX)$(CONFIG_OMAP54XX),) COBJS += hwinit-common.o COBJS += clocks-common.o COBJS += emif-common.o +COBJS += vc.o endif
ifneq ($(CONFIG_AM33XX)$(CONFIG_OMAP44XX)$(CONFIG_OMAP54XX),) diff --git a/arch/arm/cpu/armv7/omap-common/clocks-common.c b/arch/arm/cpu/armv7/omap-common/clocks-common.c index 4cfe119..207c278 100644 --- a/arch/arm/cpu/armv7/omap-common/clocks-common.c +++ b/arch/arm/cpu/armv7/omap-common/clocks-common.c @@ -364,27 +364,19 @@ static void setup_non_essential_dplls(void)
void do_scale_tps62361(u32 reg, u32 volt_mv) { - u32 temp, step; + u32 step;
step = volt_mv - TPS62361_BASE_VOLT_MV; step /= 10;
- 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"); - } }
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;
@@ -402,16 +394,9 @@ 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); - } }
static inline void enable_clock_domain(u32 *const clkctrl_reg, u32 enable_mode) @@ -531,29 +516,6 @@ void setup_clocks_for_console(void) CD_CLKCTRL_CLKTRCTRL_SHIFT); }
-void setup_sri2c(void) -{ - u32 sys_clk_khz, cycles_hi, cycles_low, temp; - - sys_clk_khz = get_sys_clk_freq() / 1000; - - /* - * Setup the dedicated I2C controller for Voltage Control - * I2C clk - high period 40% low period 60% - */ - 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); -} - void do_enable_clocks(u32 *const *clk_domains, u32 *const *clk_modules_hw_auto, u32 *const *clk_modules_explicit_en, 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 0000000..a045b77 --- /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 e2189f7..976cfd5 100644 --- a/arch/arm/cpu/armv7/omap4/clocks.c +++ b/arch/arm/cpu/armv7/omap4/clocks.c @@ -275,7 +275,7 @@ void scale_vcores(void) { u32 volt, omap_rev;
- setup_sri2c(); + omap_vc_init(PRM_VC_I2C_CHANNEL_FREQ_KHZ);
omap_rev = omap_revision(); /* TPS - supplies vdd_mpu on 4460 */ diff --git a/arch/arm/cpu/armv7/omap5/clocks.c b/arch/arm/cpu/armv7/omap5/clocks.c index dd882a2..0a614f0 100644 --- a/arch/arm/cpu/armv7/omap5/clocks.c +++ b/arch/arm/cpu/armv7/omap5/clocks.c @@ -243,7 +243,7 @@ void scale_vcores(void) { u32 volt;
- setup_sri2c(); + omap_vc_init(PRM_VC_I2C_CHANNEL_FREQ_KHZ);
/* Enable 1.22V from TPS for vdd_mpu */ volt = 1220; diff --git a/arch/arm/include/asm/arch-omap4/clocks.h b/arch/arm/include/asm/arch-omap4/clocks.h index cd304e8..4e93950 100644 --- a/arch/arm/include/asm/arch-omap4/clocks.h +++ b/arch/arm/include/asm/arch-omap4/clocks.h @@ -652,23 +652,9 @@ struct omap4_scrm_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 @@ -757,7 +743,6 @@ void scale_vcores(void); void do_scale_tps62361(u32 reg, u32 volt_mv); u32 omap_ddr_clk(void); void do_scale_vcore(u32 vcore_reg, u32 volt_mv); -void setup_sri2c(void); void setup_post_dividers(u32 *const base, const struct dpll_params *params); u32 get_sys_clk_index(void); void enable_basic_clocks(void); diff --git a/arch/arm/include/asm/arch-omap4/sys_proto.h b/arch/arm/include/asm/arch-omap4/sys_proto.h index b8dbc2c..101eb46 100644 --- a/arch/arm/include/asm/arch-omap4/sys_proto.h +++ b/arch/arm/include/asm/arch-omap4/sys_proto.h @@ -55,6 +55,8 @@ u32 omap_sdram_size(void); u32 cortex_rev(void); void init_omap_revision(void); void do_io_settings(void); +void omap_vc_init(u16 speed_khz); +int omap_vc_bypass_send_value(u8 sa, u8 reg_addr, u8 reg_data); /* * This is used to verify if the configuration header * was executed by Romcode prior to control of transfer diff --git a/arch/arm/include/asm/arch-omap5/clocks.h b/arch/arm/include/asm/arch-omap5/clocks.h index d0e6dd6..28b9ff7 100644 --- a/arch/arm/include/asm/arch-omap5/clocks.h +++ b/arch/arm/include/asm/arch-omap5/clocks.h @@ -615,23 +615,9 @@ struct omap5_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 @@ -703,7 +689,6 @@ void scale_vcores(void); void do_scale_tps62361(u32 reg, u32 volt_mv); u32 omap_ddr_clk(void); void do_scale_vcore(u32 vcore_reg, u32 volt_mv); -void setup_sri2c(void); void setup_post_dividers(u32 *const base, const struct dpll_params *params); u32 get_sys_clk_index(void); void enable_basic_clocks(void); diff --git a/arch/arm/include/asm/arch-omap5/sys_proto.h b/arch/arm/include/asm/arch-omap5/sys_proto.h index 40a7c57..3b39dbd 100644 --- a/arch/arm/include/asm/arch-omap5/sys_proto.h +++ b/arch/arm/include/asm/arch-omap5/sys_proto.h @@ -55,6 +55,8 @@ u32 omap_sdram_size(void); u32 cortex_rev(void); void init_omap_revision(void); void do_io_settings(void); +void omap_vc_init(u16 speed_khz); +int omap_vc_bypass_send_value(u8 sa, u8 reg_addr, u8 reg_data);
/* * This is used to verify if the configuration header

TPS SET0/SET1 register is selected by a GPIO pin on OMAP4460 platforms. Currently we control this pin with a mux configuration as part of boot sequence. Current configuration results in the following voltage waveform: |---------------| (SET1 default 1.4V) | --------(programmed voltage) | <- (This switch happens on mux7,pullup) vdd_mpu(TPS) -----/ (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.
By using GPIO as recommended as standard procedure by TI, the sequence changes to: -------- (programmed voltage) vdd_mpu(TPS) ------------/ (Opp boot voltage) --------- (programmed voltage) vdd_core(TWL6030) -------------/ (OPP boot voltage)
NOTE: This does not attempt to address OMAP5 - Aneesh please confirm
Reported-by: Isabelle Gros i-gros@ti.com Reported-by: Jerome Angeloni j-angeloni@ti.com Signed-off-by: Nishanth Menon nm@ti.com --- arch/arm/cpu/armv7/omap-common/clocks-common.c | 19 ++++++++++++++++++- arch/arm/cpu/armv7/omap4/clocks.c | 3 ++- arch/arm/cpu/armv7/omap5/clocks.c | 2 +- arch/arm/include/asm/arch-omap4/clocks.h | 2 +- arch/arm/include/asm/arch-omap5/clocks.h | 2 +- board/ti/panda/panda_mux_data.h | 2 +- board/ti/sdp4430/sdp4430_mux_data.h | 2 +- 7 files changed, 25 insertions(+), 7 deletions(-)
diff --git a/arch/arm/cpu/armv7/omap-common/clocks-common.c b/arch/arm/cpu/armv7/omap-common/clocks-common.c index 207c278..e4454b5 100644 --- a/arch/arm/cpu/armv7/omap-common/clocks-common.c +++ b/arch/arm/cpu/armv7/omap-common/clocks-common.c @@ -362,9 +362,22 @@ static void setup_non_essential_dplls(void) } #endif
-void do_scale_tps62361(u32 reg, u32 volt_mv) +void do_scale_tps62361(int gpio, u32 reg, u32 volt_mv) { u32 step; + int ret = 0; + + /* See if we can first get the GPIO if needed */ + if (gpio >= 0) + ret = gpio_request(gpio, "TPS62361_VSEL0_GPIO"); + if (ret < 0) { + printf("%s: gpio %d request failed %d\n", __func__, gpio, ret); + gpio = -1; + } + + /* Pull the GPIO low to select SET0 register, while we program SET1 */ + if (gpio >= 0) + gpio_direction_output(gpio, 0);
step = volt_mv - TPS62361_BASE_VOLT_MV; step /= 10; @@ -372,6 +385,10 @@ void do_scale_tps62361(u32 reg, u32 volt_mv) debug("do_scale_tps62361: volt - %d step - 0x%x\n", volt_mv, step); if (omap_vc_bypass_send_value(TPS62361_I2C_SLAVE_ADDR, reg, step)) puts("Scaling voltage failed for vdd_mpu from TPS\n"); + + /* Pull the GPIO high to select SET1 register */ + if (gpio >= 0) + gpio_direction_output(gpio, 1); }
void do_scale_vcore(u32 vcore_reg, u32 volt_mv) diff --git a/arch/arm/cpu/armv7/omap4/clocks.c b/arch/arm/cpu/armv7/omap4/clocks.c index 976cfd5..1431312 100644 --- a/arch/arm/cpu/armv7/omap4/clocks.c +++ b/arch/arm/cpu/armv7/omap4/clocks.c @@ -281,7 +281,8 @@ void scale_vcores(void) /* TPS - supplies vdd_mpu on 4460 */ if (omap_rev >= OMAP4460_ES1_0) { volt = 1203; - do_scale_tps62361(TPS62361_REG_ADDR_SET1, volt); + do_scale_tps62361(TPS62361_VSEL0_GPIO, + TPS62361_REG_ADDR_SET1, volt); }
/* diff --git a/arch/arm/cpu/armv7/omap5/clocks.c b/arch/arm/cpu/armv7/omap5/clocks.c index 0a614f0..07a7556 100644 --- a/arch/arm/cpu/armv7/omap5/clocks.c +++ b/arch/arm/cpu/armv7/omap5/clocks.c @@ -247,7 +247,7 @@ void scale_vcores(void)
/* Enable 1.22V from TPS for vdd_mpu */ volt = 1220; - do_scale_tps62361(TPS62361_REG_ADDR_SET1, volt); + do_scale_tps62361(-1, TPS62361_REG_ADDR_SET1, volt);
/* VCORE 1 - for vdd_core */ volt = 1000; diff --git a/arch/arm/include/asm/arch-omap4/clocks.h b/arch/arm/include/asm/arch-omap4/clocks.h index 4e93950..62a339f 100644 --- a/arch/arm/include/asm/arch-omap4/clocks.h +++ b/arch/arm/include/asm/arch-omap4/clocks.h @@ -740,7 +740,7 @@ extern struct omap4_prcm_regs *const prcm; extern const u32 sys_clk_array[8];
void scale_vcores(void); -void do_scale_tps62361(u32 reg, u32 volt_mv); +void do_scale_tps62361(int gpio, u32 reg, u32 volt_mv); u32 omap_ddr_clk(void); void do_scale_vcore(u32 vcore_reg, u32 volt_mv); void setup_post_dividers(u32 *const base, const struct dpll_params *params); diff --git a/arch/arm/include/asm/arch-omap5/clocks.h b/arch/arm/include/asm/arch-omap5/clocks.h index 28b9ff7..55145bb 100644 --- a/arch/arm/include/asm/arch-omap5/clocks.h +++ b/arch/arm/include/asm/arch-omap5/clocks.h @@ -686,7 +686,7 @@ extern struct omap5_prcm_regs *const prcm; extern const u32 sys_clk_array[8];
void scale_vcores(void); -void do_scale_tps62361(u32 reg, u32 volt_mv); +void do_scale_tps62361(int gpio, u32 reg, u32 volt_mv); u32 omap_ddr_clk(void); void do_scale_vcore(u32 vcore_reg, u32 volt_mv); void setup_post_dividers(u32 *const base, const struct dpll_params *params); diff --git a/board/ti/panda/panda_mux_data.h b/board/ti/panda/panda_mux_data.h index 5b66a14..3efc22a 100644 --- a/board/ti/panda/panda_mux_data.h +++ b/board/ti/panda/panda_mux_data.h @@ -76,7 +76,7 @@ const struct pad_conf_entry wkup_padconf_array_essential[] = {
const struct pad_conf_entry wkup_padconf_array_essential_4460[] = {
-{PAD1_FREF_CLK4_REQ, (PTU | M7)}, /* gpio_wk7 for TPS: safe mode + pull up */ +{PAD1_FREF_CLK4_REQ, (M3)}, /* gpio_wk7 for TPS: Mode 3 */
};
diff --git a/board/ti/sdp4430/sdp4430_mux_data.h b/board/ti/sdp4430/sdp4430_mux_data.h index 0a20968..6140b99 100644 --- a/board/ti/sdp4430/sdp4430_mux_data.h +++ b/board/ti/sdp4430/sdp4430_mux_data.h @@ -67,7 +67,7 @@ const struct pad_conf_entry wkup_padconf_array_essential[] = {
const struct pad_conf_entry wkup_padconf_array_essential_4460[] = {
-{PAD1_FREF_CLK4_REQ, (PTU | M7)}, /* gpio_wk7 for TPS: safe mode + pull up */ +{PAD1_FREF_CLK4_REQ, (M3)}, /* gpio_wk7 for TPS: Mode 3 */
};

OMAP4 requires that parent domains scale ahead of dependent domains. This is due to the restrictions in timing closure. To ensure a consistent behavior across all OMAP4 SoC, ensure that vdd_core scale first, then vdd_mpu and finally vdd_iva.
As part of doing this refactor the logic to allow for future addition of OMAP4470 without much ado. OMAP4470 uses different SMPS addresses and cannot be introduced in the current code without major rewrite.
Reported-by: Isabelle Gros i-gros@ti.com Reported-by: Jerome Angeloni j-angeloni@ti.com Signed-off-by: Nishanth Menon nm@ti.com --- arch/arm/cpu/armv7/omap4/clocks.c | 63 ++++++++++++++++++++---------------- 1 files changed, 35 insertions(+), 28 deletions(-)
diff --git a/arch/arm/cpu/armv7/omap4/clocks.c b/arch/arm/cpu/armv7/omap4/clocks.c index 1431312..b6b3f7e 100644 --- a/arch/arm/cpu/armv7/omap4/clocks.c +++ b/arch/arm/cpu/armv7/omap4/clocks.c @@ -278,44 +278,51 @@ void scale_vcores(void) omap_vc_init(PRM_VC_I2C_CHANNEL_FREQ_KHZ);
omap_rev = omap_revision(); - /* TPS - supplies vdd_mpu on 4460 */ - if (omap_rev >= OMAP4460_ES1_0) { - volt = 1203; - do_scale_tps62361(TPS62361_VSEL0_GPIO, - TPS62361_REG_ADDR_SET1, 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 + * Scale Voltage rails: + * 1. VDD_CORE + * 3. VDD_MPU + * 3. VDD_IVA */ if (omap_rev < OMAP4460_ES1_0) { + /* + * OMAP4430: + * VDD_CORE = TWL6030 VCORE3 + * VDD_MPU = TWL6030 VCORE1 + * VDD_IVA = TWL6030 VCORE2 + */ + volt = 1200; + do_scale_vcore(SMPS_REG_ADDR_VCORE3, volt); + + /* + * note on 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. + */ volt = 1325; do_scale_vcore(SMPS_REG_ADDR_VCORE1, volt); + volt = 1200; + do_scale_vcore(SMPS_REG_ADDR_VCORE2, volt); + } else { + /* + * OMAP4460: + * VDD_CORE = TWL6030 VCORE1 + * VDD_MPU = TPS62361 + * VDD_IVA = TWL6030 VCORE2 + */ volt = 1200; do_scale_vcore(SMPS_REG_ADDR_VCORE1, volt); - } - - /* VCORE 2 - supplies vdd_iva */ - volt = 1200; - do_scale_vcore(SMPS_REG_ADDR_VCORE2, volt); - - /* - * VCORE 3 - * 4430 : supplies vdd_core - * 4460 : not connected - */ - if (omap_rev < OMAP4460_ES1_0) { + /* TPS62361 */ + volt = 1203; + do_scale_tps62361(TPS62361_VSEL0_GPIO, + TPS62361_REG_ADDR_SET1, volt); + /* VCORE 2 - supplies vdd_iva */ volt = 1200; - do_scale_vcore(SMPS_REG_ADDR_VCORE3, volt); + do_scale_vcore(SMPS_REG_ADDR_VCORE2, volt); } }

OMAP5 requires that parent domains scale ahead of dependent domains. This is due to the restrictions in timing closure. To ensure a consistent behavior accross all OMAP5 SoCs, ensure that vdd_core scale first, then vdd_mpu and finally vdd_iva.
Reported-by: Isabelle Gros i-gros@ti.com Reported-by: Jerome Angeloni j-angeloni@ti.com Signed-off-by: Nishanth Menon nm@ti.com --- arch/arm/cpu/armv7/omap5/clocks.c | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/arch/arm/cpu/armv7/omap5/clocks.c b/arch/arm/cpu/armv7/omap5/clocks.c index 07a7556..5e12231 100644 --- a/arch/arm/cpu/armv7/omap5/clocks.c +++ b/arch/arm/cpu/armv7/omap5/clocks.c @@ -245,14 +245,14 @@ void scale_vcores(void)
omap_vc_init(PRM_VC_I2C_CHANNEL_FREQ_KHZ);
- /* Enable 1.22V from TPS for vdd_mpu */ - volt = 1220; - do_scale_tps62361(-1, TPS62361_REG_ADDR_SET1, volt); - /* VCORE 1 - for vdd_core */ volt = 1000; do_scale_vcore(SMPS_REG_ADDR_VCORE1, volt);
+ /* Enable 1.22V from TPS for vdd_mpu */ + volt = 1220; + do_scale_tps62361(-1, TPS62361_REG_ADDR_SET1, volt); + /* VCORE 2 - for vdd_MM */ volt = 1125; do_scale_vcore(SMPS_REG_ADDR_VCORE2, volt);
participants (1)
-
Nishanth Menon