aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorAvinash.H.M <avinashhm@ti.com>2011-07-07 19:20:10 -0700
committerNishanth Menon <nm@ti.com>2011-07-10 23:26:56 -0700
commit9726f4dba459bffe9603b537aec94f3964378d28 (patch)
treee0862a92994ba06669715a7e2ecca9ae1f9580fb /arch
parent6a2b03494e9cab723836442dc7f31e5b905a0009 (diff)
downloadkernel_samsung_tuna-9726f4dba459bffe9603b537aec94f3964378d28.zip
kernel_samsung_tuna-9726f4dba459bffe9603b537aec94f3964378d28.tar.gz
kernel_samsung_tuna-9726f4dba459bffe9603b537aec94f3964378d28.tar.bz2
OMAP3+: VC: calculate the setup times dynamically
To scale to the voltage during states such as retention, the PMIC requires some voltage stabilization time. This depends on the worst case ramp voltage and the sysclk. Support is added to dynamically calculate the ramp counts and update the appropriate registers due to the impact of Errata Id: i623(Retention/Sleep Voltage Transitions Ramp Time) on OMAP4430 silicon alone. This errata states that the ramp time configuration in the PRM_VOLTSETUP_<VD name>_OFF and PRM_VOLTSETUP_<VD name>_RET_SLEEP is 64, 256, 512, 2048 instead of the expected 16, 64, 128, 512 sysclk cycles for the values 0, 1, 2 3 configured in the register field. Since sysclk is a variant on OMAP4, dynamic computation allows us to support multiple silicon variants runtime. Acked-by: Todd Poynor <toddpoynor@google.com> Signed-off-by: Ambresh K <ambresh@ti.com> [Ported to 3.0 and cleanup] Signed-off-by: Avinash.H.M. <avinashhm@ti.com> Signed-off-by: Rajendra Nayak <rnayak@ti.com> Signed-off-by: Nicole Chalhoub <n-chalhoub@ti.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/mach-omap2/vc.c85
-rw-r--r--arch/arm/mach-omap2/vc.h20
-rw-r--r--arch/arm/mach-omap2/vc44xx_data.c7
-rw-r--r--arch/arm/mach-omap2/voltagedomains44xx_data.c15
4 files changed, 124 insertions, 3 deletions
diff --git a/arch/arm/mach-omap2/vc.c b/arch/arm/mach-omap2/vc.c
index 1b0562a..2debb1f 100644
--- a/arch/arm/mach-omap2/vc.c
+++ b/arch/arm/mach-omap2/vc.c
@@ -1,6 +1,7 @@
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/init.h>
+#include <linux/clk.h>
#include <plat/cpu.h>
@@ -10,6 +11,8 @@
#include "prm-regbits-44xx.h"
#include "prm44xx.h"
+#define OMAP_VC_I2C_ACK_DELAY 3
+
/**
* struct omap_vc_channel_cfg - describe the cfg_channel bitfield
* @sa: bit for slave address
@@ -413,6 +416,84 @@ static void __init omap_vc_i2c_init(struct voltagedomain *voltdm)
initialized = true;
}
+/**
+ * omap_vc_setup_lp_time() - configure the voltage ramp time for low states.
+ * @voltdm: voltagedomain we are interested in.
+ *
+ * The ramp times are calculated based on the worst case voltage drop,
+ * which is the difference of on_volt and the ret_volt. This time is used
+ * for computing the duration necessary for low power states such as retention.
+ */
+static int __init omap_vc_setup_lp_time(struct voltagedomain *voltdm)
+{
+ u32 volt_drop = 0, volt_ramptime = 0, volt_rampcount;
+ u32 sys_clk_mhz = 0, sysclk_cycles = 0, max_latency_for_prescaler = 0;
+ struct clk *sys_ck;
+ u8 pre_scaler = 0;
+ struct omap_voltdm_pmic *pmic = voltdm->pmic;
+ struct omap_vc_channel *vc = voltdm->vc;
+ const struct setup_time_ramp_params *params;
+
+ params = vc->common->setup_time_params;
+ /* If the VC data does not have params for us, return PMIC's value */
+ if (!params)
+ return pmic->volt_setup_time;
+ if (!params->pre_scaler_to_sysclk_cycles_count)
+ return pmic->volt_setup_time;
+
+ /* No of sys_clk cycles for pre_scaler 0 */
+ sysclk_cycles = params->pre_scaler_to_sysclk_cycles[0];
+
+ sys_ck = clk_get(NULL, "sys_clkin_ck");
+ if (IS_ERR_OR_NULL(sys_ck)) {
+ WARN_ONCE(1, "%s: unable to get sys_clkin_ck (voldm %s)\n",
+ __func__, voltdm->name);
+ return pmic->volt_setup_time;
+ }
+ sys_clk_mhz = clk_get_rate(sys_ck) / 1000000;
+ clk_put(sys_ck);
+
+ /*
+ * If we chose prescaler 0x0, then we have a limit on the maximum
+ * latency for which we can chose a correct count. This is because,
+ * the count field is limited to 6 bits and max value can be 63 and
+ * for prescaler 0, ramp up/down counter is incremented every
+ * 64 system clock cycles.
+ * for eg, max latency for prescaler for 38.4Mhz sys clk would be
+ * 105 = (63 * 64) / 38.4
+ */
+ max_latency_for_prescaler = (63 * sysclk_cycles) / sys_clk_mhz;
+
+ volt_drop = pmic->on_volt - pmic->ret_volt;
+ volt_ramptime = DIV_ROUND_UP(volt_drop, pmic->slew_rate);
+ volt_ramptime += OMAP_VC_I2C_ACK_DELAY;
+
+ if (volt_ramptime < max_latency_for_prescaler)
+ pre_scaler = 0x0;
+ else
+ pre_scaler = 0x1;
+
+ /*
+ * IF we mess up values, then try to have some form of recovery using
+ * PMIC's value.
+ */
+ if (pre_scaler > params->pre_scaler_to_sysclk_cycles_count) {
+ pr_err("%s: prescaler idx %d > available %d on domain %s\n",
+ __func__, pre_scaler,
+ params->pre_scaler_to_sysclk_cycles_count, voltdm->name);
+ return pmic->volt_setup_time;
+ }
+
+ sysclk_cycles = params->pre_scaler_to_sysclk_cycles[pre_scaler];
+
+ volt_rampcount = ((volt_ramptime * sys_clk_mhz) / sysclk_cycles) + 1;
+
+ return (pre_scaler << OMAP4430_RAMP_DOWN_PRESCAL_SHIFT) |
+ (pre_scaler << OMAP4430_RAMP_UP_PRESCAL_SHIFT) |
+ (volt_rampcount << OMAP4430_RAMP_DOWN_COUNT_SHIFT) |
+ (volt_rampcount << OMAP4430_RAMP_UP_COUNT_SHIFT);
+}
+
void __init omap_vc_init_channel(struct voltagedomain *voltdm)
{
struct omap_vc_channel *vc = voltdm->vc;
@@ -442,7 +523,8 @@ void __init omap_vc_init_channel(struct voltagedomain *voltdm)
vc->i2c_slave_addr = voltdm->pmic->i2c_slave_addr;
vc->volt_reg_addr = voltdm->pmic->volt_reg_addr;
vc->cmd_reg_addr = voltdm->pmic->cmd_reg_addr;
- vc->setup_time = voltdm->pmic->volt_setup_time;
+ /* Calculate the RET voltage setup time and update volt_setup_time */
+ vc->setup_time = omap_vc_setup_lp_time(voltdm);
if ((vc->flags & OMAP_VC_CHANNEL_DEFAULT) &&
((vc->i2c_slave_addr == USE_DEFAULT_CHANNEL_I2C_PARAM) ||
@@ -511,4 +593,3 @@ void __init omap_vc_init_channel(struct voltagedomain *voltdm)
else if (cpu_is_omap44xx())
omap4_vc_init_channel(voltdm);
}
-
diff --git a/arch/arm/mach-omap2/vc.h b/arch/arm/mach-omap2/vc.h
index fc042e4..139c04c 100644
--- a/arch/arm/mach-omap2/vc.h
+++ b/arch/arm/mach-omap2/vc.h
@@ -22,6 +22,22 @@
struct voltagedomain;
/**
+ * struct setup_time_ramp_params - ramp time parameters
+ * @pre_scaler_to_sysclk_cycles: The array represents correlation of prescaler
+ * to the number of system clock cycles, for which rampdown counter is
+ * incremented or decremented in PRM_VOLTSETUP_XXX_RET_SLEEP registers.
+ * This is to handle variances in defined values due to conditions such
+ * as "Errata Id: i623: Retention/Sleep Voltage Transitions Ramp Time"
+ * @pre_scaler_to_sysclk_cycles_count: number of entries available
+ *
+ * Add parameters that allow us to compute the ramp time for the device
+ */
+struct setup_time_ramp_params {
+ u16 *pre_scaler_to_sysclk_cycles;
+ u8 pre_scaler_to_sysclk_cycles_count;
+};
+
+/**
* struct omap_vc_common - per-VC register/bitfield data
* @cmd_on_mask: ON bitmask in PRM_VC_CMD_VAL* register
* @valid: VALID bitmask in PRM_VC_BYPASS_VAL register
@@ -38,6 +54,7 @@ struct voltagedomain;
* @i2c_cfg_reg: I2C configuration register offset
* @i2c_cfg_hsen_mask: high-speed mode bit field mask in I2C config register
* @i2c_mcode_mask: MCODE field mask for I2C config register
+ * @setup_time_params: setup time parameters
*
* XXX One of cmd_on_mask and cmd_on_shift are not needed
* XXX VALID should probably be a shift, not a mask
@@ -60,6 +77,7 @@ struct omap_vc_common {
u8 i2c_cfg_reg;
u8 i2c_cfg_hsen_mask;
u8 i2c_mcode_mask;
+ struct setup_time_ramp_params *setup_time_params;
};
/**
@@ -97,7 +115,7 @@ struct omap_vc_channel {
u16 volt_reg_addr;
u16 cmd_reg_addr;
u8 cfg_channel;
- u16 setup_time;
+ u32 setup_time;
bool i2c_high_speed;
/* register access data */
diff --git a/arch/arm/mach-omap2/vc44xx_data.c b/arch/arm/mach-omap2/vc44xx_data.c
index 3757d4f..08f845b 100644
--- a/arch/arm/mach-omap2/vc44xx_data.c
+++ b/arch/arm/mach-omap2/vc44xx_data.c
@@ -26,6 +26,12 @@
#include "vc.h"
+static u16 pre_scaler_to_sysclk_cycles_44xx[] = {16, 64, 128, 512};
+static struct setup_time_ramp_params omap4_vc_setuptime_params = {
+ .pre_scaler_to_sysclk_cycles = pre_scaler_to_sysclk_cycles_44xx,
+ .pre_scaler_to_sysclk_cycles_count = 4,
+};
+
/*
* VC data common to 44xx chips
* XXX This stuff presumably belongs in the vc3xxx.c or vc.c file.
@@ -48,6 +54,7 @@ static const struct omap_vc_common omap4_vc_common = {
.i2c_cfg_reg = OMAP4_PRM_VC_CFG_I2C_MODE_OFFSET,
.i2c_cfg_hsen_mask = OMAP4430_HSMODEEN_MASK,
.i2c_mcode_mask = OMAP4430_HSMCODE_MASK,
+ .setup_time_params = &omap4_vc_setuptime_params,
};
/* VC auto transition settings for OMAP4. */
diff --git a/arch/arm/mach-omap2/voltagedomains44xx_data.c b/arch/arm/mach-omap2/voltagedomains44xx_data.c
index e9975ac..8b75f86 100644
--- a/arch/arm/mach-omap2/voltagedomains44xx_data.c
+++ b/arch/arm/mach-omap2/voltagedomains44xx_data.c
@@ -102,6 +102,14 @@ static struct voltagedomain *voltagedomains_omap4[] __initdata = {
NULL,
};
+/*
+ * Handle Mutant pre_scalar to sysclk cycles map:
+ * Due to "Errata Id: i623: Retention/Sleep Voltage Transitions Ramp Time"
+ * on OMAP4430 specifically, the maps is 64, 256, 512, 2048 cycles.
+ * Handle this condition dynamically from version detection logic
+ */
+static u16 pre_scaler_to_sysclk_cycles_443x[] = {64, 256, 512, 2048};
+
static const char *sys_clk_name __initdata = "sys_clkin_ck";
void __init omap44xx_voltagedomains_init(void)
@@ -114,6 +122,13 @@ void __init omap44xx_voltagedomains_init(void)
* for the currently-running IC
*/
if (cpu_is_omap443x()) {
+ struct setup_time_ramp_params *params =
+ omap4_vc_core.common->setup_time_params;
+
+ if (params) {
+ params->pre_scaler_to_sysclk_cycles =
+ pre_scaler_to_sysclk_cycles_443x;
+ }
omap4_vdd_mpu_info.volt_data = omap443x_vdd_mpu_volt_data;
omap4_vdd_iva_info.volt_data = omap443x_vdd_iva_volt_data;
omap4_vdd_core_info.volt_data = omap443x_vdd_core_volt_data;