From f2a0dfefec5fac797a5c6defa7e29db933a67a80 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Tue, 25 Sep 2012 19:33:33 +0300 Subject: [PATCH 01/15] ARM: OMAP3+: PM: VP: use uV for max and min voltage limits Every PMIC has it's own eccentricities, For example, one of the PMIC has MSB set to 1 for a specific function - voltage enable! using an hardcoded value specific for TWL when copied over to such an implementation causes the system to crash as the MSB bit was 0 and the voltage got disabled!. Instead we use actual values and depend on the convertion routines to abstract out the eccentricities of each PMIC. With this, we can now move the voltages to a common location in voltage.h as they are no longer dependent on PMICs and expect the PMIC's conversion routines to set a cap if the voltage is out of reach for the PMIC. Reported-by: Jon Hunter Signed-off-by: Nishanth Menon Signed-off-by: Vishwanath BS Signed-off-by: Tero Kristo Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/omap_twl.c | 17 ----------------- arch/arm/mach-omap2/voltage.h | 22 ++++++++++++++++++++-- arch/arm/mach-omap2/vp.c | 4 ++-- 3 files changed, 22 insertions(+), 21 deletions(-) diff --git a/arch/arm/mach-omap2/omap_twl.c b/arch/arm/mach-omap2/omap_twl.c index f515a1a056d5..df4e7c38f7c6 100644 --- a/arch/arm/mach-omap2/omap_twl.c +++ b/arch/arm/mach-omap2/omap_twl.c @@ -30,16 +30,6 @@ #define OMAP3_VP_VSTEPMAX_VSTEPMAX 0x04 #define OMAP3_VP_VLIMITTO_TIMEOUT_US 200 -#define OMAP3430_VP1_VLIMITTO_VDDMIN 0x14 -#define OMAP3430_VP1_VLIMITTO_VDDMAX 0x42 -#define OMAP3430_VP2_VLIMITTO_VDDMIN 0x18 -#define OMAP3430_VP2_VLIMITTO_VDDMAX 0x2c - -#define OMAP3630_VP1_VLIMITTO_VDDMIN 0x18 -#define OMAP3630_VP1_VLIMITTO_VDDMAX 0x3c -#define OMAP3630_VP2_VLIMITTO_VDDMIN 0x18 -#define OMAP3630_VP2_VLIMITTO_VDDMAX 0x30 - #define OMAP4_SRI2C_SLAVE_ADDR 0x12 #define OMAP4_VDD_MPU_SR_VOLT_REG 0x55 #define OMAP4_VDD_MPU_SR_CMD_REG 0x56 @@ -53,13 +43,6 @@ #define OMAP4_VP_VSTEPMAX_VSTEPMAX 0x04 #define OMAP4_VP_VLIMITTO_TIMEOUT_US 200 -#define OMAP4_VP_MPU_VLIMITTO_VDDMIN 0xA -#define OMAP4_VP_MPU_VLIMITTO_VDDMAX 0x39 -#define OMAP4_VP_IVA_VLIMITTO_VDDMIN 0xA -#define OMAP4_VP_IVA_VLIMITTO_VDDMAX 0x2D -#define OMAP4_VP_CORE_VLIMITTO_VDDMIN 0xA -#define OMAP4_VP_CORE_VLIMITTO_VDDMAX 0x28 - static bool is_offset_valid; static u8 smps_offset; /* diff --git a/arch/arm/mach-omap2/voltage.h b/arch/arm/mach-omap2/voltage.h index 7283b7ed7de8..700469561b4d 100644 --- a/arch/arm/mach-omap2/voltage.h +++ b/arch/arm/mach-omap2/voltage.h @@ -92,6 +92,24 @@ struct voltagedomain { struct omap_volt_data *volt_data; }; +/* Min and max voltages from OMAP perspective */ +#define OMAP3430_VP1_VLIMITTO_VDDMIN 850000 +#define OMAP3430_VP1_VLIMITTO_VDDMAX 1425000 +#define OMAP3430_VP2_VLIMITTO_VDDMIN 900000 +#define OMAP3430_VP2_VLIMITTO_VDDMAX 1150000 + +#define OMAP3630_VP1_VLIMITTO_VDDMIN 900000 +#define OMAP3630_VP1_VLIMITTO_VDDMAX 1350000 +#define OMAP3630_VP2_VLIMITTO_VDDMIN 900000 +#define OMAP3630_VP2_VLIMITTO_VDDMAX 1200000 + +#define OMAP4_VP_MPU_VLIMITTO_VDDMIN 830000 +#define OMAP4_VP_MPU_VLIMITTO_VDDMAX 1410000 +#define OMAP4_VP_IVA_VLIMITTO_VDDMIN 830000 +#define OMAP4_VP_IVA_VLIMITTO_VDDMAX 1260000 +#define OMAP4_VP_CORE_VLIMITTO_VDDMIN 830000 +#define OMAP4_VP_CORE_VLIMITTO_VDDMAX 1200000 + /** * struct omap_voltdm_pmic - PMIC specific data required by voltage driver. * @slew_rate: PMIC slew rate (in uv/us) @@ -118,8 +136,8 @@ struct omap_voltdm_pmic { u8 vp_erroroffset; u8 vp_vstepmin; u8 vp_vstepmax; - u8 vp_vddmin; - u8 vp_vddmax; + u32 vp_vddmin; + u32 vp_vddmax; u8 vp_timeout_us; bool i2c_high_speed; u8 i2c_mcode; diff --git a/arch/arm/mach-omap2/vp.c b/arch/arm/mach-omap2/vp.c index 85241b828c02..47c89eba57ca 100644 --- a/arch/arm/mach-omap2/vp.c +++ b/arch/arm/mach-omap2/vp.c @@ -58,8 +58,8 @@ void __init omap_vp_init(struct voltagedomain *voltdm) sys_clk_rate = voltdm->sys_clk.rate / 1000; timeout = (sys_clk_rate * voltdm->pmic->vp_timeout_us) / 1000; - vddmin = voltdm->pmic->vp_vddmin; - vddmax = voltdm->pmic->vp_vddmax; + vddmin = voltdm->pmic->uv_to_vsel(voltdm->pmic->vp_vddmin); + vddmax = voltdm->pmic->uv_to_vsel(voltdm->pmic->vp_vddmax); waittime = DIV_ROUND_UP(voltdm->pmic->step_size * sys_clk_rate, 1000 * voltdm->pmic->slew_rate); From b254012b21e3f0dec798de8d12e3ce009d1c09e0 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Tue, 25 Sep 2012 19:33:34 +0300 Subject: [PATCH 02/15] ARM: OMAP: voltage: renamed vp_vddmin and vp_vddmax fields These are now called vddmin and vddmax, as these fields will be used globally for selecting voltage ranges for a pmic channel, and not only for voltage processor. Signed-off-by: Tero Kristo Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/omap_twl.c | 28 ++++++++++++++-------------- arch/arm/mach-omap2/voltage.h | 4 ++-- arch/arm/mach-omap2/vp.c | 4 ++-- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/arch/arm/mach-omap2/omap_twl.c b/arch/arm/mach-omap2/omap_twl.c index df4e7c38f7c6..c38a530a7f47 100644 --- a/arch/arm/mach-omap2/omap_twl.c +++ b/arch/arm/mach-omap2/omap_twl.c @@ -149,8 +149,8 @@ static struct omap_voltdm_pmic omap3_mpu_pmic = { .vp_erroroffset = OMAP3_VP_CONFIG_ERROROFFSET, .vp_vstepmin = OMAP3_VP_VSTEPMIN_VSTEPMIN, .vp_vstepmax = OMAP3_VP_VSTEPMAX_VSTEPMAX, - .vp_vddmin = OMAP3430_VP1_VLIMITTO_VDDMIN, - .vp_vddmax = OMAP3430_VP1_VLIMITTO_VDDMAX, + .vddmin = OMAP3430_VP1_VLIMITTO_VDDMIN, + .vddmax = OMAP3430_VP1_VLIMITTO_VDDMAX, .vp_timeout_us = OMAP3_VP_VLIMITTO_TIMEOUT_US, .i2c_slave_addr = OMAP3_SRI2C_SLAVE_ADDR, .volt_reg_addr = OMAP3_VDD_MPU_SR_CONTROL_REG, @@ -170,8 +170,8 @@ static struct omap_voltdm_pmic omap3_core_pmic = { .vp_erroroffset = OMAP3_VP_CONFIG_ERROROFFSET, .vp_vstepmin = OMAP3_VP_VSTEPMIN_VSTEPMIN, .vp_vstepmax = OMAP3_VP_VSTEPMAX_VSTEPMAX, - .vp_vddmin = OMAP3430_VP2_VLIMITTO_VDDMIN, - .vp_vddmax = OMAP3430_VP2_VLIMITTO_VDDMAX, + .vddmin = OMAP3430_VP2_VLIMITTO_VDDMIN, + .vddmax = OMAP3430_VP2_VLIMITTO_VDDMAX, .vp_timeout_us = OMAP3_VP_VLIMITTO_TIMEOUT_US, .i2c_slave_addr = OMAP3_SRI2C_SLAVE_ADDR, .volt_reg_addr = OMAP3_VDD_CORE_SR_CONTROL_REG, @@ -191,8 +191,8 @@ static struct omap_voltdm_pmic omap4_mpu_pmic = { .vp_erroroffset = OMAP4_VP_CONFIG_ERROROFFSET, .vp_vstepmin = OMAP4_VP_VSTEPMIN_VSTEPMIN, .vp_vstepmax = OMAP4_VP_VSTEPMAX_VSTEPMAX, - .vp_vddmin = OMAP4_VP_MPU_VLIMITTO_VDDMIN, - .vp_vddmax = OMAP4_VP_MPU_VLIMITTO_VDDMAX, + .vddmin = OMAP4_VP_MPU_VLIMITTO_VDDMIN, + .vddmax = OMAP4_VP_MPU_VLIMITTO_VDDMAX, .vp_timeout_us = OMAP4_VP_VLIMITTO_TIMEOUT_US, .i2c_slave_addr = OMAP4_SRI2C_SLAVE_ADDR, .volt_reg_addr = OMAP4_VDD_MPU_SR_VOLT_REG, @@ -213,8 +213,8 @@ static struct omap_voltdm_pmic omap4_iva_pmic = { .vp_erroroffset = OMAP4_VP_CONFIG_ERROROFFSET, .vp_vstepmin = OMAP4_VP_VSTEPMIN_VSTEPMIN, .vp_vstepmax = OMAP4_VP_VSTEPMAX_VSTEPMAX, - .vp_vddmin = OMAP4_VP_IVA_VLIMITTO_VDDMIN, - .vp_vddmax = OMAP4_VP_IVA_VLIMITTO_VDDMAX, + .vddmin = OMAP4_VP_IVA_VLIMITTO_VDDMIN, + .vddmax = OMAP4_VP_IVA_VLIMITTO_VDDMAX, .vp_timeout_us = OMAP4_VP_VLIMITTO_TIMEOUT_US, .i2c_slave_addr = OMAP4_SRI2C_SLAVE_ADDR, .volt_reg_addr = OMAP4_VDD_IVA_SR_VOLT_REG, @@ -235,8 +235,8 @@ static struct omap_voltdm_pmic omap4_core_pmic = { .vp_erroroffset = OMAP4_VP_CONFIG_ERROROFFSET, .vp_vstepmin = OMAP4_VP_VSTEPMIN_VSTEPMIN, .vp_vstepmax = OMAP4_VP_VSTEPMAX_VSTEPMAX, - .vp_vddmin = OMAP4_VP_CORE_VLIMITTO_VDDMIN, - .vp_vddmax = OMAP4_VP_CORE_VLIMITTO_VDDMAX, + .vddmin = OMAP4_VP_CORE_VLIMITTO_VDDMIN, + .vddmax = OMAP4_VP_CORE_VLIMITTO_VDDMAX, .vp_timeout_us = OMAP4_VP_VLIMITTO_TIMEOUT_US, .i2c_slave_addr = OMAP4_SRI2C_SLAVE_ADDR, .volt_reg_addr = OMAP4_VDD_CORE_SR_VOLT_REG, @@ -272,10 +272,10 @@ int __init omap3_twl_init(void) return -ENODEV; if (cpu_is_omap3630()) { - omap3_mpu_pmic.vp_vddmin = OMAP3630_VP1_VLIMITTO_VDDMIN; - omap3_mpu_pmic.vp_vddmax = OMAP3630_VP1_VLIMITTO_VDDMAX; - omap3_core_pmic.vp_vddmin = OMAP3630_VP2_VLIMITTO_VDDMIN; - omap3_core_pmic.vp_vddmax = OMAP3630_VP2_VLIMITTO_VDDMAX; + omap3_mpu_pmic.vddmin = OMAP3630_VP1_VLIMITTO_VDDMIN; + omap3_mpu_pmic.vddmax = OMAP3630_VP1_VLIMITTO_VDDMAX; + omap3_core_pmic.vddmin = OMAP3630_VP2_VLIMITTO_VDDMIN; + omap3_core_pmic.vddmax = OMAP3630_VP2_VLIMITTO_VDDMAX; } /* diff --git a/arch/arm/mach-omap2/voltage.h b/arch/arm/mach-omap2/voltage.h index 700469561b4d..a3607b83790d 100644 --- a/arch/arm/mach-omap2/voltage.h +++ b/arch/arm/mach-omap2/voltage.h @@ -136,8 +136,8 @@ struct omap_voltdm_pmic { u8 vp_erroroffset; u8 vp_vstepmin; u8 vp_vstepmax; - u32 vp_vddmin; - u32 vp_vddmax; + u32 vddmin; + u32 vddmax; u8 vp_timeout_us; bool i2c_high_speed; u8 i2c_mcode; diff --git a/arch/arm/mach-omap2/vp.c b/arch/arm/mach-omap2/vp.c index 47c89eba57ca..c7e0507bfbd3 100644 --- a/arch/arm/mach-omap2/vp.c +++ b/arch/arm/mach-omap2/vp.c @@ -58,8 +58,8 @@ void __init omap_vp_init(struct voltagedomain *voltdm) sys_clk_rate = voltdm->sys_clk.rate / 1000; timeout = (sys_clk_rate * voltdm->pmic->vp_timeout_us) / 1000; - vddmin = voltdm->pmic->uv_to_vsel(voltdm->pmic->vp_vddmin); - vddmax = voltdm->pmic->uv_to_vsel(voltdm->pmic->vp_vddmax); + vddmin = voltdm->pmic->uv_to_vsel(voltdm->pmic->vddmin); + vddmax = voltdm->pmic->uv_to_vsel(voltdm->pmic->vddmax); waittime = DIV_ROUND_UP(voltdm->pmic->step_size * sys_clk_rate, 1000 * voltdm->pmic->slew_rate); From 8b5d8c0d718379ce29dad74b4bda8b669fc1f1c2 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Tue, 25 Sep 2012 19:33:35 +0300 Subject: [PATCH 03/15] ARM: OMAP3+: voltage: introduce omap vc / vp params for voltagedomains These new structs will hold the sleep voltage levels (omap_vc_params) and voltage processor min / max voltages (omap_vp_params.) Previously these were part of the PMIC struct, but they do not really belong there, as they are OMAP chip specific, not PMIC specific parameters. voltdm code is also changed to use the new structs. Signed-off-by: Tero Kristo Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/omap_twl.c | 20 ----------- arch/arm/mach-omap2/vc.c | 35 ++++++++++++++++--- arch/arm/mach-omap2/vc.h | 7 ++++ arch/arm/mach-omap2/vc3xxx_data.c | 22 ++++++++++++ arch/arm/mach-omap2/vc44xx_data.c | 28 +++++++++++++++ arch/arm/mach-omap2/voltage.h | 18 +++++++--- arch/arm/mach-omap2/voltagedomains3xxx_data.c | 5 +++ arch/arm/mach-omap2/voltagedomains44xx_data.c | 8 +++++ arch/arm/mach-omap2/vp.h | 7 ++++ arch/arm/mach-omap2/vp3xxx_data.c | 10 ++++++ arch/arm/mach-omap2/vp44xx_data.c | 15 ++++++++ 11 files changed, 147 insertions(+), 28 deletions(-) diff --git a/arch/arm/mach-omap2/omap_twl.c b/arch/arm/mach-omap2/omap_twl.c index c38a530a7f47..dca1d662d5e0 100644 --- a/arch/arm/mach-omap2/omap_twl.c +++ b/arch/arm/mach-omap2/omap_twl.c @@ -141,10 +141,6 @@ static u8 twl6030_uv_to_vsel(unsigned long uv) static struct omap_voltdm_pmic omap3_mpu_pmic = { .slew_rate = 4000, .step_size = 12500, - .on_volt = 1200000, - .onlp_volt = 1000000, - .ret_volt = 975000, - .off_volt = 600000, .volt_setup_time = 0xfff, .vp_erroroffset = OMAP3_VP_CONFIG_ERROROFFSET, .vp_vstepmin = OMAP3_VP_VSTEPMIN_VSTEPMIN, @@ -162,10 +158,6 @@ static struct omap_voltdm_pmic omap3_mpu_pmic = { static struct omap_voltdm_pmic omap3_core_pmic = { .slew_rate = 4000, .step_size = 12500, - .on_volt = 1200000, - .onlp_volt = 1000000, - .ret_volt = 975000, - .off_volt = 600000, .volt_setup_time = 0xfff, .vp_erroroffset = OMAP3_VP_CONFIG_ERROROFFSET, .vp_vstepmin = OMAP3_VP_VSTEPMIN_VSTEPMIN, @@ -183,10 +175,6 @@ static struct omap_voltdm_pmic omap3_core_pmic = { static struct omap_voltdm_pmic omap4_mpu_pmic = { .slew_rate = 4000, .step_size = 12660, - .on_volt = 1375000, - .onlp_volt = 1375000, - .ret_volt = 830000, - .off_volt = 0, .volt_setup_time = 0, .vp_erroroffset = OMAP4_VP_CONFIG_ERROROFFSET, .vp_vstepmin = OMAP4_VP_VSTEPMIN_VSTEPMIN, @@ -205,10 +193,6 @@ static struct omap_voltdm_pmic omap4_mpu_pmic = { static struct omap_voltdm_pmic omap4_iva_pmic = { .slew_rate = 4000, .step_size = 12660, - .on_volt = 1188000, - .onlp_volt = 1188000, - .ret_volt = 830000, - .off_volt = 0, .volt_setup_time = 0, .vp_erroroffset = OMAP4_VP_CONFIG_ERROROFFSET, .vp_vstepmin = OMAP4_VP_VSTEPMIN_VSTEPMIN, @@ -227,10 +211,6 @@ static struct omap_voltdm_pmic omap4_iva_pmic = { static struct omap_voltdm_pmic omap4_core_pmic = { .slew_rate = 4000, .step_size = 12660, - .on_volt = 1200000, - .onlp_volt = 1200000, - .ret_volt = 830000, - .off_volt = 0, .volt_setup_time = 0, .vp_erroroffset = OMAP4_VP_CONFIG_ERROROFFSET, .vp_vstepmin = OMAP4_VP_VSTEPMIN_VSTEPMIN, diff --git a/arch/arm/mach-omap2/vc.c b/arch/arm/mach-omap2/vc.c index 880249b17012..4c3c41fd2637 100644 --- a/arch/arm/mach-omap2/vc.c +++ b/arch/arm/mach-omap2/vc.c @@ -135,6 +135,8 @@ int omap_vc_pre_scale(struct voltagedomain *voltdm, vc_cmdval |= (*target_vsel << vc->common->cmd_on_shift); voltdm->write(vc_cmdval, vc->cmdval_reg); + voltdm->vc_param->on = target_volt; + omap_vp_update_errorgain(voltdm, target_volt); return 0; @@ -284,6 +286,30 @@ static void __init omap_vc_i2c_init(struct voltagedomain *voltdm) initialized = true; } +/** + * omap_vc_calc_vsel - calculate vsel value for a channel + * @voltdm: channel to calculate value for + * @uvolt: microvolt value to convert to vsel + * + * Converts a microvolt value to vsel value for the used PMIC. + * This checks whether the microvolt value is out of bounds, and + * adjusts the value accordingly. If unsupported value detected, + * warning is thrown. + */ +static u8 omap_vc_calc_vsel(struct voltagedomain *voltdm, u32 uvolt) +{ + if (voltdm->pmic->vddmin > uvolt) + uvolt = voltdm->pmic->vddmin; + if (voltdm->pmic->vddmax < uvolt) { + WARN(1, "%s: voltage not supported by pmic: %u vs max %u\n", + __func__, uvolt, voltdm->pmic->vddmax); + /* Lets try maximum value anyway */ + uvolt = voltdm->pmic->vddmax; + } + + return voltdm->pmic->uv_to_vsel(uvolt); +} + void __init omap_vc_init_channel(struct voltagedomain *voltdm) { struct omap_vc_channel *vc = voltdm->vc; @@ -335,10 +361,11 @@ void __init omap_vc_init_channel(struct voltagedomain *voltdm) } /* Set up the on, inactive, retention and off voltage */ - on_vsel = voltdm->pmic->uv_to_vsel(voltdm->pmic->on_volt); - onlp_vsel = voltdm->pmic->uv_to_vsel(voltdm->pmic->onlp_volt); - ret_vsel = voltdm->pmic->uv_to_vsel(voltdm->pmic->ret_volt); - off_vsel = voltdm->pmic->uv_to_vsel(voltdm->pmic->off_volt); + on_vsel = omap_vc_calc_vsel(voltdm, voltdm->vc_param->on); + onlp_vsel = omap_vc_calc_vsel(voltdm, voltdm->vc_param->onlp); + ret_vsel = omap_vc_calc_vsel(voltdm, voltdm->vc_param->ret); + off_vsel = omap_vc_calc_vsel(voltdm, voltdm->vc_param->off); + val = ((on_vsel << vc->common->cmd_on_shift) | (onlp_vsel << vc->common->cmd_onlp_shift) | (ret_vsel << vc->common->cmd_ret_shift) | diff --git a/arch/arm/mach-omap2/vc.h b/arch/arm/mach-omap2/vc.h index 478bf6b432c4..7618b69811d0 100644 --- a/arch/arm/mach-omap2/vc.h +++ b/arch/arm/mach-omap2/vc.h @@ -111,6 +111,13 @@ extern struct omap_vc_channel omap4_vc_mpu; extern struct omap_vc_channel omap4_vc_iva; extern struct omap_vc_channel omap4_vc_core; +extern struct omap_vc_param omap3_mpu_vc_data; +extern struct omap_vc_param omap3_core_vc_data; + +extern struct omap_vc_param omap4_mpu_vc_data; +extern struct omap_vc_param omap4_iva_vc_data; +extern struct omap_vc_param omap4_core_vc_data; + void omap_vc_init_channel(struct voltagedomain *voltdm); int omap_vc_pre_scale(struct voltagedomain *voltdm, unsigned long target_volt, diff --git a/arch/arm/mach-omap2/vc3xxx_data.c b/arch/arm/mach-omap2/vc3xxx_data.c index 5d8eaf31569c..75bc4aa22b3a 100644 --- a/arch/arm/mach-omap2/vc3xxx_data.c +++ b/arch/arm/mach-omap2/vc3xxx_data.c @@ -71,3 +71,25 @@ struct omap_vc_channel omap3_vc_core = { .smps_cmdra_mask = OMAP3430_CMDRA1_MASK, .cfg_channel_sa_shift = OMAP3430_PRM_VC_SMPS_SA_SA1_SHIFT, }; + +/* + * Voltage levels for different operating modes: on, sleep, retention and off + */ +#define OMAP3_ON_VOLTAGE_UV 1200000 +#define OMAP3_ONLP_VOLTAGE_UV 1000000 +#define OMAP3_RET_VOLTAGE_UV 975000 +#define OMAP3_OFF_VOLTAGE_UV 600000 + +struct omap_vc_param omap3_mpu_vc_data = { + .on = OMAP3_ON_VOLTAGE_UV, + .onlp = OMAP3_ONLP_VOLTAGE_UV, + .ret = OMAP3_RET_VOLTAGE_UV, + .off = OMAP3_OFF_VOLTAGE_UV, +}; + +struct omap_vc_param omap3_core_vc_data = { + .on = OMAP3_ON_VOLTAGE_UV, + .onlp = OMAP3_ONLP_VOLTAGE_UV, + .ret = OMAP3_RET_VOLTAGE_UV, + .off = OMAP3_OFF_VOLTAGE_UV, +}; diff --git a/arch/arm/mach-omap2/vc44xx_data.c b/arch/arm/mach-omap2/vc44xx_data.c index d70b930f2739..085e5d6a04fd 100644 --- a/arch/arm/mach-omap2/vc44xx_data.c +++ b/arch/arm/mach-omap2/vc44xx_data.c @@ -87,3 +87,31 @@ struct omap_vc_channel omap4_vc_core = { .cfg_channel_sa_shift = OMAP4430_SA_VDD_CORE_L_SHIFT, }; +/* + * Voltage levels for different operating modes: on, sleep, retention and off + */ +#define OMAP4_ON_VOLTAGE_UV 1375000 +#define OMAP4_ONLP_VOLTAGE_UV 1375000 +#define OMAP4_RET_VOLTAGE_UV 837500 +#define OMAP4_OFF_VOLTAGE_UV 0 + +struct omap_vc_param omap4_mpu_vc_data = { + .on = OMAP4_ON_VOLTAGE_UV, + .onlp = OMAP4_ONLP_VOLTAGE_UV, + .ret = OMAP4_RET_VOLTAGE_UV, + .off = OMAP4_OFF_VOLTAGE_UV, +}; + +struct omap_vc_param omap4_iva_vc_data = { + .on = OMAP4_ON_VOLTAGE_UV, + .onlp = OMAP4_ONLP_VOLTAGE_UV, + .ret = OMAP4_RET_VOLTAGE_UV, + .off = OMAP4_OFF_VOLTAGE_UV, +}; + +struct omap_vc_param omap4_core_vc_data = { + .on = OMAP4_ON_VOLTAGE_UV, + .onlp = OMAP4_ONLP_VOLTAGE_UV, + .ret = OMAP4_RET_VOLTAGE_UV, + .off = OMAP4_OFF_VOLTAGE_UV, +}; diff --git a/arch/arm/mach-omap2/voltage.h b/arch/arm/mach-omap2/voltage.h index a3607b83790d..697095551bb6 100644 --- a/arch/arm/mach-omap2/voltage.h +++ b/arch/arm/mach-omap2/voltage.h @@ -74,6 +74,8 @@ struct voltagedomain { const struct omap_vfsm_instance *vfsm; struct omap_vp_instance *vp; struct omap_voltdm_pmic *pmic; + struct omap_vp_param *vp_param; + struct omap_vc_param *vc_param; /* VC/VP register access functions: SoC specific */ u32 (*read) (u8 offset); @@ -125,10 +127,6 @@ struct voltagedomain { struct omap_voltdm_pmic { int slew_rate; int step_size; - u32 on_volt; - u32 onlp_volt; - u32 ret_volt; - u32 off_volt; u16 volt_setup_time; u16 i2c_slave_addr; u16 volt_reg_addr; @@ -145,6 +143,18 @@ struct omap_voltdm_pmic { u8 (*uv_to_vsel) (unsigned long uV); }; +struct omap_vp_param { + u32 vddmax; + u32 vddmin; +}; + +struct omap_vc_param { + u32 on; + u32 onlp; + u32 ret; + u32 off; +}; + void omap_voltage_get_volttable(struct voltagedomain *voltdm, struct omap_volt_data **volt_data); struct omap_volt_data *omap_voltage_get_voltdata(struct voltagedomain *voltdm, diff --git a/arch/arm/mach-omap2/voltagedomains3xxx_data.c b/arch/arm/mach-omap2/voltagedomains3xxx_data.c index 63afbfed3cbc..261bb7cb4e60 100644 --- a/arch/arm/mach-omap2/voltagedomains3xxx_data.c +++ b/arch/arm/mach-omap2/voltagedomains3xxx_data.c @@ -117,6 +117,11 @@ void __init omap3xxx_voltagedomains_init(void) } #endif + omap3_voltdm_mpu.vp_param = &omap3_mpu_vp_data; + omap3_voltdm_core.vp_param = &omap3_core_vp_data; + omap3_voltdm_mpu.vc_param = &omap3_mpu_vc_data; + omap3_voltdm_core.vc_param = &omap3_core_vc_data; + if (soc_is_am35xx()) voltdms = voltagedomains_am35xx; else diff --git a/arch/arm/mach-omap2/voltagedomains44xx_data.c b/arch/arm/mach-omap2/voltagedomains44xx_data.c index c3115f6853d4..a2d7d9ca2380 100644 --- a/arch/arm/mach-omap2/voltagedomains44xx_data.c +++ b/arch/arm/mach-omap2/voltagedomains44xx_data.c @@ -106,6 +106,14 @@ void __init omap44xx_voltagedomains_init(void) omap4_voltdm_core.volt_data = omap44xx_vdd_core_volt_data; #endif + omap4_voltdm_mpu.vp_param = &omap4_mpu_vp_data; + omap4_voltdm_iva.vp_param = &omap4_iva_vp_data; + omap4_voltdm_core.vp_param = &omap4_core_vp_data; + + omap4_voltdm_mpu.vc_param = &omap4_mpu_vc_data; + omap4_voltdm_iva.vc_param = &omap4_iva_vc_data; + omap4_voltdm_core.vc_param = &omap4_core_vc_data; + for (i = 0; voltdm = voltagedomains_omap4[i], voltdm; i++) voltdm->sys_clk.name = sys_clk_name; diff --git a/arch/arm/mach-omap2/vp.h b/arch/arm/mach-omap2/vp.h index 7c155d248aa3..0fdf7080e4a6 100644 --- a/arch/arm/mach-omap2/vp.h +++ b/arch/arm/mach-omap2/vp.h @@ -117,6 +117,13 @@ extern struct omap_vp_instance omap4_vp_mpu; extern struct omap_vp_instance omap4_vp_iva; extern struct omap_vp_instance omap4_vp_core; +extern struct omap_vp_param omap3_mpu_vp_data; +extern struct omap_vp_param omap3_core_vp_data; + +extern struct omap_vp_param omap4_mpu_vp_data; +extern struct omap_vp_param omap4_iva_vp_data; +extern struct omap_vp_param omap4_core_vp_data; + void omap_vp_init(struct voltagedomain *voltdm); void omap_vp_enable(struct voltagedomain *voltdm); void omap_vp_disable(struct voltagedomain *voltdm); diff --git a/arch/arm/mach-omap2/vp3xxx_data.c b/arch/arm/mach-omap2/vp3xxx_data.c index bd89f80089f5..1914e026245e 100644 --- a/arch/arm/mach-omap2/vp3xxx_data.c +++ b/arch/arm/mach-omap2/vp3xxx_data.c @@ -77,3 +77,13 @@ struct omap_vp_instance omap3_vp_core = { .vstatus = OMAP3_PRM_VP2_STATUS_OFFSET, .voltage = OMAP3_PRM_VP2_VOLTAGE_OFFSET, }; + +struct omap_vp_param omap3_mpu_vp_data = { + .vddmin = OMAP3430_VP1_VLIMITTO_VDDMIN, + .vddmax = OMAP3430_VP1_VLIMITTO_VDDMAX, +}; + +struct omap_vp_param omap3_core_vp_data = { + .vddmin = OMAP3430_VP2_VLIMITTO_VDDMIN, + .vddmax = OMAP3430_VP2_VLIMITTO_VDDMAX, +}; diff --git a/arch/arm/mach-omap2/vp44xx_data.c b/arch/arm/mach-omap2/vp44xx_data.c index 8c031d16879e..e62f6b018beb 100644 --- a/arch/arm/mach-omap2/vp44xx_data.c +++ b/arch/arm/mach-omap2/vp44xx_data.c @@ -87,3 +87,18 @@ struct omap_vp_instance omap4_vp_core = { .vstatus = OMAP4_PRM_VP_CORE_STATUS_OFFSET, .voltage = OMAP4_PRM_VP_CORE_VOLTAGE_OFFSET, }; + +struct omap_vp_param omap4_mpu_vp_data = { + .vddmin = OMAP4_VP_MPU_VLIMITTO_VDDMIN, + .vddmax = OMAP4_VP_MPU_VLIMITTO_VDDMAX, +}; + +struct omap_vp_param omap4_iva_vp_data = { + .vddmin = OMAP4_VP_IVA_VLIMITTO_VDDMIN, + .vddmax = OMAP4_VP_IVA_VLIMITTO_VDDMAX, +}; + +struct omap_vp_param omap4_core_vp_data = { + .vddmin = OMAP4_VP_CORE_VLIMITTO_VDDMIN, + .vddmax = OMAP4_VP_CORE_VLIMITTO_VDDMAX, +}; From c589eb3869a8ad6185669f5477bf72d6d46068de Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Tue, 25 Sep 2012 19:33:36 +0300 Subject: [PATCH 04/15] ARM: OMAP3: VC: calculate ramp times OMAP3 VC code now uses voltage deltas + slew rates for calculating actual ramp times for voltage changes. Previously a static value was used. Two calculation methods are provided: i2c_timings and off_timings. I2C timings are used during retention or off mode transition which is initiated over I2C, and OFF timings are used if PMIC signal (nsleep) is used to control all the off mode voltages at the same time. Signed-off-by: Tero Kristo Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/vc.c | 116 ++++++++++++++++++++++++++++++++------- arch/arm/mach-omap2/vc.h | 1 - 2 files changed, 95 insertions(+), 22 deletions(-) diff --git a/arch/arm/mach-omap2/vc.c b/arch/arm/mach-omap2/vc.c index 4c3c41fd2637..73b4bcd67023 100644 --- a/arch/arm/mach-omap2/vc.c +++ b/arch/arm/mach-omap2/vc.c @@ -204,30 +204,110 @@ int omap_vc_bypass_scale(struct voltagedomain *voltdm, return 0; } -static void __init omap3_vfsm_init(struct voltagedomain *voltdm) +/** + * omap3_set_i2c_timings - sets i2c sleep timings for a channel + * @voltdm: channel to configure + * @off_mode: select whether retention or off mode values used + * + * Calculates and sets up voltage controller to use I2C based + * voltage scaling for sleep modes. This can be used for either off mode + * or retention. Off mode has additionally an option to use sys_off_mode + * pad, which uses a global signal to program the whole power IC to + * off-mode. + */ +static void omap3_set_i2c_timings(struct voltagedomain *voltdm, bool off_mode) { + unsigned long voltsetup1; + u32 tgt_volt; + + if (off_mode) + tgt_volt = voltdm->vc_param->off; + else + tgt_volt = voltdm->vc_param->ret; + + voltsetup1 = (voltdm->vc_param->on - tgt_volt) / + voltdm->pmic->slew_rate; + + voltsetup1 = voltsetup1 * voltdm->sys_clk.rate / 8 / 1000000 + 1; + + voltdm->rmw(voltdm->vfsm->voltsetup_mask, + voltsetup1 << __ffs(voltdm->vfsm->voltsetup_mask), + voltdm->vfsm->voltsetup_reg); + /* - * Voltage Manager FSM parameters init - * XXX This data should be passed in from the board file + * pmic is not controlling the voltage scaling during retention, + * thus set voltsetup2 to 0 */ - voltdm->write(OMAP3_CLKSETUP, OMAP3_PRM_CLKSETUP_OFFSET); - voltdm->write(OMAP3_VOLTOFFSET, OMAP3_PRM_VOLTOFFSET_OFFSET); - voltdm->write(OMAP3_VOLTSETUP2, OMAP3_PRM_VOLTSETUP2_OFFSET); + voltdm->write(0, OMAP3_PRM_VOLTSETUP2_OFFSET); +} + +/** + * omap3_set_off_timings - sets off-mode timings for a channel + * @voltdm: channel to configure + * + * Calculates and sets up off-mode timings for a channel. Off-mode + * can use either I2C based voltage scaling, or alternatively + * sys_off_mode pad can be used to send a global command to power IC. + * This function first checks which mode is being used, and calls + * omap3_set_i2c_timings() if the system is using I2C control mode. + * sys_off_mode has the additional benefit that voltages can be + * scaled to zero volt level with TWL4030 / TWL5030, I2C can only + * scale to 600mV. + */ +static void omap3_set_off_timings(struct voltagedomain *voltdm) +{ + unsigned long clksetup; + unsigned long voltsetup2; + unsigned long voltsetup2_old; + u32 val; + + /* check if sys_off_mode is used to control off-mode voltages */ + val = voltdm->read(OMAP3_PRM_VOLTCTRL_OFFSET); + if (!(val & OMAP3430_SEL_OFF_MASK)) { + /* No, omap is controlling them over I2C */ + omap3_set_i2c_timings(voltdm, true); + return; + } + + clksetup = voltdm->read(OMAP3_PRM_CLKSETUP_OFFSET); + + /* voltsetup 2 in us */ + voltsetup2 = voltdm->vc_param->on / voltdm->pmic->slew_rate; + + /* convert to 32k clk cycles */ + voltsetup2 = DIV_ROUND_UP(voltsetup2 * 32768, 1000000); + + voltsetup2_old = voltdm->read(OMAP3_PRM_VOLTSETUP2_OFFSET); + + /* + * Update voltsetup2 if higher than current value (needed because + * we have multiple channels with different ramp times), also + * update voltoffset always to value recommended by TRM + */ + if (voltsetup2 > voltsetup2_old) { + voltdm->write(voltsetup2, OMAP3_PRM_VOLTSETUP2_OFFSET); + voltdm->write(clksetup - voltsetup2, + OMAP3_PRM_VOLTOFFSET_OFFSET); + } else + voltdm->write(clksetup - voltsetup2_old, + OMAP3_PRM_VOLTOFFSET_OFFSET); + + /* + * omap is not controlling voltage scaling during off-mode, + * thus set voltsetup1 to 0 + */ + voltdm->rmw(voltdm->vfsm->voltsetup_mask, 0, + voltdm->vfsm->voltsetup_reg); + + /* voltoffset must be clksetup minus voltsetup2 according to TRM */ + voltdm->write(clksetup - voltsetup2, OMAP3_PRM_VOLTOFFSET_OFFSET); } static void __init omap3_vc_init_channel(struct voltagedomain *voltdm) { - static bool is_initialized; - - if (is_initialized) - return; - - omap3_vfsm_init(voltdm); - - is_initialized = true; + omap3_set_off_timings(voltdm); } - /* OMAP4 specific voltage init functions */ static void __init omap4_vc_init_channel(struct voltagedomain *voltdm) { @@ -337,7 +417,6 @@ 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; /* Configure the i2c slave address for this VC */ voltdm->rmw(vc->smps_sa_mask, @@ -376,11 +455,6 @@ void __init omap_vc_init_channel(struct voltagedomain *voltdm) /* Channel configuration */ omap_vc_config_channel(voltdm); - /* Configure the setup times */ - voltdm->rmw(voltdm->vfsm->voltsetup_mask, - vc->setup_time << __ffs(voltdm->vfsm->voltsetup_mask), - voltdm->vfsm->voltsetup_reg); - omap_vc_i2c_init(voltdm); if (cpu_is_omap34xx()) diff --git a/arch/arm/mach-omap2/vc.h b/arch/arm/mach-omap2/vc.h index 7618b69811d0..91c8d75bf2ea 100644 --- a/arch/arm/mach-omap2/vc.h +++ b/arch/arm/mach-omap2/vc.h @@ -86,7 +86,6 @@ struct omap_vc_channel { u16 i2c_slave_addr; u16 volt_reg_addr; u16 cmd_reg_addr; - u16 setup_time; u8 cfg_channel; bool i2c_high_speed; From 27c16b7026a9ca6455dd319fb00a28c5bb2023b6 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Tue, 25 Sep 2012 19:33:37 +0300 Subject: [PATCH 05/15] ARM: OMAP4: voltage: add support for VOLTSETUP_x_OFF register OMAP4 has two VOLTSETUP registers. One is controlling retention and sleep voltage setup times, the other one off mode setup times. Both of these need to be setup for stable behavior of the device. The code setting up the new register will be added in the next patch. Signed-off-by: Tero Kristo Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/voltage.h | 2 ++ arch/arm/mach-omap2/voltagedomains44xx_data.c | 3 +++ 2 files changed, 5 insertions(+) diff --git a/arch/arm/mach-omap2/voltage.h b/arch/arm/mach-omap2/voltage.h index 697095551bb6..990c440d5c51 100644 --- a/arch/arm/mach-omap2/voltage.h +++ b/arch/arm/mach-omap2/voltage.h @@ -40,12 +40,14 @@ struct powerdomain; * data * @voltsetup_mask: SETUP_TIME* bitmask in the PRM_VOLTSETUP* register * @voltsetup_reg: register offset of PRM_VOLTSETUP from PRM base + * @voltsetup_off_reg: register offset of PRM_VOLTSETUP_OFF from PRM base * * XXX What about VOLTOFFSET/VOLTCTRL? */ struct omap_vfsm_instance { u32 voltsetup_mask; u8 voltsetup_reg; + u8 voltsetup_off_reg; }; /** diff --git a/arch/arm/mach-omap2/voltagedomains44xx_data.c b/arch/arm/mach-omap2/voltagedomains44xx_data.c index a2d7d9ca2380..7da35a67c988 100644 --- a/arch/arm/mach-omap2/voltagedomains44xx_data.c +++ b/arch/arm/mach-omap2/voltagedomains44xx_data.c @@ -34,14 +34,17 @@ static const struct omap_vfsm_instance omap4_vdd_mpu_vfsm = { .voltsetup_reg = OMAP4_PRM_VOLTSETUP_MPU_RET_SLEEP_OFFSET, + .voltsetup_off_reg = OMAP4_PRM_VOLTSETUP_MPU_OFF_OFFSET, }; static const struct omap_vfsm_instance omap4_vdd_iva_vfsm = { .voltsetup_reg = OMAP4_PRM_VOLTSETUP_IVA_RET_SLEEP_OFFSET, + .voltsetup_off_reg = OMAP4_PRM_VOLTSETUP_IVA_OFF_OFFSET, }; static const struct omap_vfsm_instance omap4_vdd_core_vfsm = { .voltsetup_reg = OMAP4_PRM_VOLTSETUP_CORE_RET_SLEEP_OFFSET, + .voltsetup_off_reg = OMAP4_PRM_VOLTSETUP_CORE_OFF_OFFSET, }; static struct voltagedomain omap4_voltdm_mpu = { From 9a1729cbaaf1a9d1fd27f80cd488ef182fe033a0 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Tue, 25 Sep 2012 19:33:38 +0300 Subject: [PATCH 06/15] ARM: OMAP4: VC: calculate ramp times OMAP4 VC code now uses voltage deltas + slew rates for calculating actual ramp times for voltage changes. Both retention / sleep + off mode voltage ramp times are setup at the same time during initialization. Signed-off-by: Tero Kristo Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/vc.c | 94 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/arch/arm/mach-omap2/vc.c b/arch/arm/mach-omap2/vc.c index 73b4bcd67023..07e2090d7119 100644 --- a/arch/arm/mach-omap2/vc.c +++ b/arch/arm/mach-omap2/vc.c @@ -308,12 +308,106 @@ static void __init omap3_vc_init_channel(struct voltagedomain *voltdm) omap3_set_off_timings(voltdm); } +/** + * omap4_calc_volt_ramp - calculates voltage ramping delays on omap4 + * @voltdm: channel to calculate values for + * @voltage_diff: voltage difference in microvolts + * + * Calculates voltage ramp prescaler + counter values for a voltage + * difference on omap4. Returns a field value suitable for writing to + * VOLTSETUP register for a channel in following format: + * bits[8:9] prescaler ... bits[0:5] counter. See OMAP4 TRM for reference. + */ +static u32 omap4_calc_volt_ramp(struct voltagedomain *voltdm, u32 voltage_diff) +{ + u32 prescaler; + u32 cycles; + u32 time; + + time = voltage_diff / voltdm->pmic->slew_rate; + + cycles = voltdm->sys_clk.rate / 1000 * time / 1000; + + cycles /= 64; + prescaler = 0; + + /* shift to next prescaler until no overflow */ + + /* scale for div 256 = 64 * 4 */ + if (cycles > 63) { + cycles /= 4; + prescaler++; + } + + /* scale for div 512 = 256 * 2 */ + if (cycles > 63) { + cycles /= 2; + prescaler++; + } + + /* scale for div 2048 = 512 * 4 */ + if (cycles > 63) { + cycles /= 4; + prescaler++; + } + + /* check for overflow => invalid ramp time */ + if (cycles > 63) { + pr_warn("%s: invalid setuptime for vdd_%s\n", __func__, + voltdm->name); + return 0; + } + + cycles++; + + return (prescaler << OMAP4430_RAMP_UP_PRESCAL_SHIFT) | + (cycles << OMAP4430_RAMP_UP_COUNT_SHIFT); +} + +/** + * omap4_set_timings - set voltage ramp timings for a channel + * @voltdm: channel to configure + * @off_mode: whether off-mode values are used + * + * Calculates and sets the voltage ramp up / down values for a channel. + */ +static void omap4_set_timings(struct voltagedomain *voltdm, bool off_mode) +{ + u32 val; + u32 ramp; + int offset; + + if (off_mode) { + ramp = omap4_calc_volt_ramp(voltdm, + voltdm->vc_param->on - voltdm->vc_param->off); + offset = voltdm->vfsm->voltsetup_off_reg; + } else { + ramp = omap4_calc_volt_ramp(voltdm, + voltdm->vc_param->on - voltdm->vc_param->ret); + offset = voltdm->vfsm->voltsetup_reg; + } + + if (!ramp) + return; + + val = voltdm->read(offset); + + val |= ramp << OMAP4430_RAMP_DOWN_COUNT_SHIFT; + + val |= ramp << OMAP4430_RAMP_UP_COUNT_SHIFT; + + voltdm->write(val, offset); +} + /* OMAP4 specific voltage init functions */ static void __init omap4_vc_init_channel(struct voltagedomain *voltdm) { static bool is_initialized; u32 vc_val; + omap4_set_timings(voltdm, true); + omap4_set_timings(voltdm, false); + if (is_initialized) return; From 908b75e850c4a6130b680ea7e59b00f80d4cd2d2 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Tue, 25 Sep 2012 19:33:39 +0300 Subject: [PATCH 07/15] ARM: OMAP: add support for oscillator setup This contains startup and shutdown times for the oscillator. By default use ULONG_MAX. Oscillator setup is used for calculating and setting up latencies for sleep modes that disable oscillator. Based on a patch from Nishanth Menon . Signed-off-by: Tero Kristo Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/pm.c | 30 ++++++++++++++++++++++++++++++ arch/arm/mach-omap2/pm.h | 8 ++++++++ 2 files changed, 38 insertions(+) diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c index ea61c32957bd..109a02e02d72 100644 --- a/arch/arm/mach-omap2/pm.c +++ b/arch/arm/mach-omap2/pm.c @@ -39,6 +39,36 @@ static struct omap_device_pm_latency *pm_lats; */ int (*omap_pm_suspend)(void); +/** + * struct omap2_oscillator - Describe the board main oscillator latencies + * @startup_time: oscillator startup latency + * @shutdown_time: oscillator shutdown latency + */ +struct omap2_oscillator { + u32 startup_time; + u32 shutdown_time; +}; + +static struct omap2_oscillator oscillator = { + .startup_time = ULONG_MAX, + .shutdown_time = ULONG_MAX, +}; + +void omap_pm_setup_oscillator(u32 tstart, u32 tshut) +{ + oscillator.startup_time = tstart; + oscillator.shutdown_time = tshut; +} + +void omap_pm_get_oscillator(u32 *tstart, u32 *tshut) +{ + if (!tstart || !tshut) + return; + + *tstart = oscillator.startup_time; + *tshut = oscillator.shutdown_time; +} + static int __init _init_omap_device(char *name) { struct omap_hwmod *oh; diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h index 67d66131cfa7..429028852103 100644 --- a/arch/arm/mach-omap2/pm.h +++ b/arch/arm/mach-omap2/pm.h @@ -129,4 +129,12 @@ static inline int omap4_twl_init(void) } #endif +#ifdef CONFIG_PM +extern void omap_pm_setup_oscillator(u32 tstart, u32 tshut); +extern void omap_pm_get_oscillator(u32 *tstart, u32 *tshut); +#else +static inline void omap_pm_setup_oscillator(u32 tstart, u32 tshut) { } +static inline void omap_pm_get_oscillator(u32 *tstart, u32 *tshut) { } +#endif + #endif From 085b30250041cd485555f547f625ec03341592dd Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Tue, 25 Sep 2012 19:33:40 +0300 Subject: [PATCH 08/15] ARM: OMAP3+: vp: use new vp_params for calculating vddmin and vddmax Now we select the vddmin and vddmax values based on both pmic and voltage processor data, this allows usage of different power ICs. Signed-off-by: Tero Kristo Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/vp.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-omap2/vp.c b/arch/arm/mach-omap2/vp.c index c7e0507bfbd3..394a253c4cd4 100644 --- a/arch/arm/mach-omap2/vp.c +++ b/arch/arm/mach-omap2/vp.c @@ -58,8 +58,10 @@ void __init omap_vp_init(struct voltagedomain *voltdm) sys_clk_rate = voltdm->sys_clk.rate / 1000; timeout = (sys_clk_rate * voltdm->pmic->vp_timeout_us) / 1000; - vddmin = voltdm->pmic->uv_to_vsel(voltdm->pmic->vddmin); - vddmax = voltdm->pmic->uv_to_vsel(voltdm->pmic->vddmax); + vddmin = max(voltdm->vp_param->vddmin, voltdm->pmic->vddmin); + vddmax = min(voltdm->vp_param->vddmax, voltdm->pmic->vddmax); + vddmin = voltdm->pmic->uv_to_vsel(vddmin); + vddmax = voltdm->pmic->uv_to_vsel(vddmax); waittime = DIV_ROUND_UP(voltdm->pmic->step_size * sys_clk_rate, 1000 * voltdm->pmic->slew_rate); From d68ff977b82954fed8e3f4bde8431517455c2003 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Tue, 25 Sep 2012 19:33:41 +0300 Subject: [PATCH 09/15] ARM: OMAP3+: voltage: use oscillator data to calculate setup times We now use the previously defined oscillator setup / shutdown times to calculate the register values for CLKSETUP. Signed-off-by: Tero Kristo Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/vc.c | 62 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/arch/arm/mach-omap2/vc.c b/arch/arm/mach-omap2/vc.c index 07e2090d7119..5d5f9e52f89f 100644 --- a/arch/arm/mach-omap2/vc.c +++ b/arch/arm/mach-omap2/vc.c @@ -11,13 +11,19 @@ #include #include #include +#include +#include + +#include "iomap.h" #include "soc.h" #include "voltage.h" #include "vc.h" #include "prm-regbits-34xx.h" #include "prm-regbits-44xx.h" #include "prm44xx.h" +#include "pm.h" +#include "scrm44xx.h" /** * struct omap_vc_channel_cfg - describe the cfg_channel bitfield @@ -204,6 +210,18 @@ int omap_vc_bypass_scale(struct voltagedomain *voltdm, return 0; } +/* Convert microsecond value to number of 32kHz clock cycles */ +static inline u32 omap_usec_to_32k(u32 usec) +{ + return DIV_ROUND_UP_ULL(32768ULL * (u64)usec, 1000000ULL); +} + +/* Set oscillator setup time for omap3 */ +static void omap3_set_clksetup(u32 usec, struct voltagedomain *voltdm) +{ + voltdm->write(omap_usec_to_32k(usec), OMAP3_PRM_CLKSETUP_OFFSET); +} + /** * omap3_set_i2c_timings - sets i2c sleep timings for a channel * @voltdm: channel to configure @@ -220,6 +238,12 @@ static void omap3_set_i2c_timings(struct voltagedomain *voltdm, bool off_mode) unsigned long voltsetup1; u32 tgt_volt; + /* + * Oscillator is shut down only if we are using sys_off_mode pad, + * thus we set a minimal setup time here + */ + omap3_set_clksetup(1, voltdm); + if (off_mode) tgt_volt = voltdm->vc_param->off; else @@ -260,6 +284,7 @@ static void omap3_set_off_timings(struct voltagedomain *voltdm) unsigned long voltsetup2; unsigned long voltsetup2_old; u32 val; + u32 tstart, tshut; /* check if sys_off_mode is used to control off-mode voltages */ val = voltdm->read(OMAP3_PRM_VOLTCTRL_OFFSET); @@ -269,6 +294,9 @@ static void omap3_set_off_timings(struct voltagedomain *voltdm) return; } + omap_pm_get_oscillator(&tstart, &tshut); + omap3_set_clksetup(tstart, voltdm); + clksetup = voltdm->read(OMAP3_PRM_CLKSETUP_OFFSET); /* voltsetup 2 in us */ @@ -364,6 +392,30 @@ static u32 omap4_calc_volt_ramp(struct voltagedomain *voltdm, u32 voltage_diff) (cycles << OMAP4430_RAMP_UP_COUNT_SHIFT); } +/** + * omap4_usec_to_val_scrm - convert microsecond value to SCRM module bitfield + * @usec: microseconds + * @shift: number of bits to shift left + * @mask: bitfield mask + * + * Converts microsecond value to OMAP4 SCRM bitfield. Bitfield is + * shifted to requested position, and checked agains the mask value. + * If larger, forced to the max value of the field (i.e. the mask itself.) + * Returns the SCRM bitfield value. + */ +static u32 omap4_usec_to_val_scrm(u32 usec, int shift, u32 mask) +{ + u32 val; + + val = omap_usec_to_32k(usec) << shift; + + /* Check for overflow, if yes, force to max value */ + if (val > mask) + val = mask; + + return val; +} + /** * omap4_set_timings - set voltage ramp timings for a channel * @voltdm: channel to configure @@ -376,6 +428,7 @@ static void omap4_set_timings(struct voltagedomain *voltdm, bool off_mode) u32 val; u32 ramp; int offset; + u32 tstart, tshut; if (off_mode) { ramp = omap4_calc_volt_ramp(voltdm, @@ -397,6 +450,15 @@ static void omap4_set_timings(struct voltagedomain *voltdm, bool off_mode) val |= ramp << OMAP4430_RAMP_UP_COUNT_SHIFT; voltdm->write(val, offset); + + omap_pm_get_oscillator(&tstart, &tshut); + + val = omap4_usec_to_val_scrm(tstart, OMAP4_SETUPTIME_SHIFT, + OMAP4_SETUPTIME_MASK); + val |= omap4_usec_to_val_scrm(tshut, OMAP4_DOWNTIME_SHIFT, + OMAP4_DOWNTIME_MASK); + + __raw_writel(val, OMAP4_SCRM_CLKSETUPTIME); } /* OMAP4 specific voltage init functions */ From 5a84dc5bc5d7d35d3788f4d1a9c928912c3ad41b Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Tue, 25 Sep 2012 19:33:42 +0300 Subject: [PATCH 10/15] ARM: OMAP: TWL: change the vddmin / vddmax voltages to spec As vddmin / vddmax voltages for the pmic only describe the pmic capabilities now, change the voltages to be according to spec. TWL data manuals give following values: TWL4030 (SWCS019L) : VDD1: 600mV ... 1450mV, VDD2: 600mV ... 1500mV TWL5030 (SWCS030E) : VDD1: 600mV ... 1450mV, VDD2: 600mV ... 1500mV TWL6030 (SWCS045A) : 0V ... 2100mV Signed-off-by: Tero Kristo Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/omap_twl.c | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/arch/arm/mach-omap2/omap_twl.c b/arch/arm/mach-omap2/omap_twl.c index dca1d662d5e0..188f21027c9a 100644 --- a/arch/arm/mach-omap2/omap_twl.c +++ b/arch/arm/mach-omap2/omap_twl.c @@ -145,8 +145,8 @@ static struct omap_voltdm_pmic omap3_mpu_pmic = { .vp_erroroffset = OMAP3_VP_CONFIG_ERROROFFSET, .vp_vstepmin = OMAP3_VP_VSTEPMIN_VSTEPMIN, .vp_vstepmax = OMAP3_VP_VSTEPMAX_VSTEPMAX, - .vddmin = OMAP3430_VP1_VLIMITTO_VDDMIN, - .vddmax = OMAP3430_VP1_VLIMITTO_VDDMAX, + .vddmin = 600000, + .vddmax = 1450000, .vp_timeout_us = OMAP3_VP_VLIMITTO_TIMEOUT_US, .i2c_slave_addr = OMAP3_SRI2C_SLAVE_ADDR, .volt_reg_addr = OMAP3_VDD_MPU_SR_CONTROL_REG, @@ -162,8 +162,8 @@ static struct omap_voltdm_pmic omap3_core_pmic = { .vp_erroroffset = OMAP3_VP_CONFIG_ERROROFFSET, .vp_vstepmin = OMAP3_VP_VSTEPMIN_VSTEPMIN, .vp_vstepmax = OMAP3_VP_VSTEPMAX_VSTEPMAX, - .vddmin = OMAP3430_VP2_VLIMITTO_VDDMIN, - .vddmax = OMAP3430_VP2_VLIMITTO_VDDMAX, + .vddmin = 600000, + .vddmax = 1450000, .vp_timeout_us = OMAP3_VP_VLIMITTO_TIMEOUT_US, .i2c_slave_addr = OMAP3_SRI2C_SLAVE_ADDR, .volt_reg_addr = OMAP3_VDD_CORE_SR_CONTROL_REG, @@ -179,8 +179,8 @@ static struct omap_voltdm_pmic omap4_mpu_pmic = { .vp_erroroffset = OMAP4_VP_CONFIG_ERROROFFSET, .vp_vstepmin = OMAP4_VP_VSTEPMIN_VSTEPMIN, .vp_vstepmax = OMAP4_VP_VSTEPMAX_VSTEPMAX, - .vddmin = OMAP4_VP_MPU_VLIMITTO_VDDMIN, - .vddmax = OMAP4_VP_MPU_VLIMITTO_VDDMAX, + .vddmin = 0, + .vddmax = 2100000, .vp_timeout_us = OMAP4_VP_VLIMITTO_TIMEOUT_US, .i2c_slave_addr = OMAP4_SRI2C_SLAVE_ADDR, .volt_reg_addr = OMAP4_VDD_MPU_SR_VOLT_REG, @@ -197,8 +197,8 @@ static struct omap_voltdm_pmic omap4_iva_pmic = { .vp_erroroffset = OMAP4_VP_CONFIG_ERROROFFSET, .vp_vstepmin = OMAP4_VP_VSTEPMIN_VSTEPMIN, .vp_vstepmax = OMAP4_VP_VSTEPMAX_VSTEPMAX, - .vddmin = OMAP4_VP_IVA_VLIMITTO_VDDMIN, - .vddmax = OMAP4_VP_IVA_VLIMITTO_VDDMAX, + .vddmin = 0, + .vddmax = 2100000, .vp_timeout_us = OMAP4_VP_VLIMITTO_TIMEOUT_US, .i2c_slave_addr = OMAP4_SRI2C_SLAVE_ADDR, .volt_reg_addr = OMAP4_VDD_IVA_SR_VOLT_REG, @@ -215,8 +215,8 @@ static struct omap_voltdm_pmic omap4_core_pmic = { .vp_erroroffset = OMAP4_VP_CONFIG_ERROROFFSET, .vp_vstepmin = OMAP4_VP_VSTEPMIN_VSTEPMIN, .vp_vstepmax = OMAP4_VP_VSTEPMAX_VSTEPMAX, - .vddmin = OMAP4_VP_CORE_VLIMITTO_VDDMIN, - .vddmax = OMAP4_VP_CORE_VLIMITTO_VDDMAX, + .vddmin = 0, + .vddmax = 2100000, .vp_timeout_us = OMAP4_VP_VLIMITTO_TIMEOUT_US, .i2c_slave_addr = OMAP4_SRI2C_SLAVE_ADDR, .volt_reg_addr = OMAP4_VDD_CORE_SR_VOLT_REG, @@ -251,13 +251,6 @@ int __init omap3_twl_init(void) if (!cpu_is_omap34xx()) return -ENODEV; - if (cpu_is_omap3630()) { - omap3_mpu_pmic.vddmin = OMAP3630_VP1_VLIMITTO_VDDMIN; - omap3_mpu_pmic.vddmax = OMAP3630_VP1_VLIMITTO_VDDMAX; - omap3_core_pmic.vddmin = OMAP3630_VP2_VLIMITTO_VDDMIN; - omap3_core_pmic.vddmax = OMAP3630_VP2_VLIMITTO_VDDMAX; - } - /* * The smartreflex bit on twl4030 specifies if the setting of voltage * is done over the I2C_SR path. Since this setting is independent of From d3965191a4d28fa6eb875c06e5cfaffa5a8aef29 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Tue, 25 Sep 2012 19:33:46 +0300 Subject: [PATCH 11/15] ARM: OMAP3+: voltage: remove unused volt_setup_time parameter This is no longer needed as the ramp times are calculated from voltage deltas + slew rates. Signed-off-by: Tero Kristo Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/omap_twl.c | 5 ----- arch/arm/mach-omap2/voltage.h | 1 - 2 files changed, 6 deletions(-) diff --git a/arch/arm/mach-omap2/omap_twl.c b/arch/arm/mach-omap2/omap_twl.c index 188f21027c9a..ecae9890f0f2 100644 --- a/arch/arm/mach-omap2/omap_twl.c +++ b/arch/arm/mach-omap2/omap_twl.c @@ -141,7 +141,6 @@ static u8 twl6030_uv_to_vsel(unsigned long uv) static struct omap_voltdm_pmic omap3_mpu_pmic = { .slew_rate = 4000, .step_size = 12500, - .volt_setup_time = 0xfff, .vp_erroroffset = OMAP3_VP_CONFIG_ERROROFFSET, .vp_vstepmin = OMAP3_VP_VSTEPMIN_VSTEPMIN, .vp_vstepmax = OMAP3_VP_VSTEPMAX_VSTEPMAX, @@ -158,7 +157,6 @@ static struct omap_voltdm_pmic omap3_mpu_pmic = { static struct omap_voltdm_pmic omap3_core_pmic = { .slew_rate = 4000, .step_size = 12500, - .volt_setup_time = 0xfff, .vp_erroroffset = OMAP3_VP_CONFIG_ERROROFFSET, .vp_vstepmin = OMAP3_VP_VSTEPMIN_VSTEPMIN, .vp_vstepmax = OMAP3_VP_VSTEPMAX_VSTEPMAX, @@ -175,7 +173,6 @@ static struct omap_voltdm_pmic omap3_core_pmic = { static struct omap_voltdm_pmic omap4_mpu_pmic = { .slew_rate = 4000, .step_size = 12660, - .volt_setup_time = 0, .vp_erroroffset = OMAP4_VP_CONFIG_ERROROFFSET, .vp_vstepmin = OMAP4_VP_VSTEPMIN_VSTEPMIN, .vp_vstepmax = OMAP4_VP_VSTEPMAX_VSTEPMAX, @@ -193,7 +190,6 @@ static struct omap_voltdm_pmic omap4_mpu_pmic = { static struct omap_voltdm_pmic omap4_iva_pmic = { .slew_rate = 4000, .step_size = 12660, - .volt_setup_time = 0, .vp_erroroffset = OMAP4_VP_CONFIG_ERROROFFSET, .vp_vstepmin = OMAP4_VP_VSTEPMIN_VSTEPMIN, .vp_vstepmax = OMAP4_VP_VSTEPMAX_VSTEPMAX, @@ -211,7 +207,6 @@ static struct omap_voltdm_pmic omap4_iva_pmic = { static struct omap_voltdm_pmic omap4_core_pmic = { .slew_rate = 4000, .step_size = 12660, - .volt_setup_time = 0, .vp_erroroffset = OMAP4_VP_CONFIG_ERROROFFSET, .vp_vstepmin = OMAP4_VP_VSTEPMIN_VSTEPMIN, .vp_vstepmax = OMAP4_VP_VSTEPMAX_VSTEPMAX, diff --git a/arch/arm/mach-omap2/voltage.h b/arch/arm/mach-omap2/voltage.h index 990c440d5c51..78923f93efde 100644 --- a/arch/arm/mach-omap2/voltage.h +++ b/arch/arm/mach-omap2/voltage.h @@ -129,7 +129,6 @@ struct voltagedomain { struct omap_voltdm_pmic { int slew_rate; int step_size; - u16 volt_setup_time; u16 i2c_slave_addr; u16 volt_reg_addr; u16 cmd_reg_addr; From 2ceec7b25c3cde53c68e49d64950f2ad1cab307d Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Tue, 25 Sep 2012 19:33:47 +0300 Subject: [PATCH 12/15] ARM: OMAP4: vc: fix channel configuration RACEN bit should only be set if the voltage and command register addresses are the same. Signed-off-by: Tero Kristo Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/vc.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-omap2/vc.c b/arch/arm/mach-omap2/vc.c index 5d5f9e52f89f..d72b787a0d83 100644 --- a/arch/arm/mach-omap2/vc.c +++ b/arch/arm/mach-omap2/vc.c @@ -592,9 +592,12 @@ void __init omap_vc_init_channel(struct voltagedomain *voltdm) voltdm->rmw(vc->smps_cmdra_mask, vc->cmd_reg_addr << __ffs(vc->smps_cmdra_mask), vc->smps_cmdra_reg); - vc->cfg_channel |= vc_cfg_bits->rac | vc_cfg_bits->racen; + vc->cfg_channel |= vc_cfg_bits->rac; } + if (vc->cmd_reg_addr == vc->volt_reg_addr) + vc->cfg_channel |= vc_cfg_bits->racen; + /* Set up the on, inactive, retention and off voltage */ on_vsel = omap_vc_calc_vsel(voltdm, voltdm->vc_param->on); onlp_vsel = omap_vc_calc_vsel(voltdm, voltdm->vc_param->onlp); From 00bd228ea9f7aad23f7933fa62a13d975d4b213a Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Tue, 25 Sep 2012 19:33:48 +0300 Subject: [PATCH 13/15] ARM: OMAP4: VC: setup I2C parameters based on board data VC code now provides a table of pre-calculated I2C setup parameters, which will be used based on the capacitance value calculated for the I2C trace on the PCB. A default trace length of 6.3cm is used unless board defines its own value during init. The parameters set will be the I2C internal pull setup and the I2C timing parameters for high speed use mode. Full speed mode is not supported as of now. Signed-off-by: Tero Kristo Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/omap_twl.c | 3 + arch/arm/mach-omap2/pm.h | 2 + arch/arm/mach-omap2/vc.c | 157 ++++++++++++++++++++++++++++++--- arch/arm/mach-omap2/voltage.h | 1 + 4 files changed, 151 insertions(+), 12 deletions(-) diff --git a/arch/arm/mach-omap2/omap_twl.c b/arch/arm/mach-omap2/omap_twl.c index ecae9890f0f2..611cb63d5ce6 100644 --- a/arch/arm/mach-omap2/omap_twl.c +++ b/arch/arm/mach-omap2/omap_twl.c @@ -183,6 +183,7 @@ static struct omap_voltdm_pmic omap4_mpu_pmic = { .volt_reg_addr = OMAP4_VDD_MPU_SR_VOLT_REG, .cmd_reg_addr = OMAP4_VDD_MPU_SR_CMD_REG, .i2c_high_speed = true, + .i2c_pad_load = 3, .vsel_to_uv = twl6030_vsel_to_uv, .uv_to_vsel = twl6030_uv_to_vsel, }; @@ -200,6 +201,7 @@ static struct omap_voltdm_pmic omap4_iva_pmic = { .volt_reg_addr = OMAP4_VDD_IVA_SR_VOLT_REG, .cmd_reg_addr = OMAP4_VDD_IVA_SR_CMD_REG, .i2c_high_speed = true, + .i2c_pad_load = 3, .vsel_to_uv = twl6030_vsel_to_uv, .uv_to_vsel = twl6030_uv_to_vsel, }; @@ -216,6 +218,7 @@ static struct omap_voltdm_pmic omap4_core_pmic = { .i2c_slave_addr = OMAP4_SRI2C_SLAVE_ADDR, .volt_reg_addr = OMAP4_VDD_CORE_SR_VOLT_REG, .cmd_reg_addr = OMAP4_VDD_CORE_SR_CMD_REG, + .i2c_pad_load = 3, .vsel_to_uv = twl6030_vsel_to_uv, .uv_to_vsel = twl6030_uv_to_vsel, }; diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h index 429028852103..4db7b238a0d5 100644 --- a/arch/arm/mach-omap2/pm.h +++ b/arch/arm/mach-omap2/pm.h @@ -132,9 +132,11 @@ static inline int omap4_twl_init(void) #ifdef CONFIG_PM extern void omap_pm_setup_oscillator(u32 tstart, u32 tshut); extern void omap_pm_get_oscillator(u32 *tstart, u32 *tshut); +extern void omap_pm_setup_sr_i2c_pcb_length(u32 mm); #else static inline void omap_pm_setup_oscillator(u32 tstart, u32 tshut) { } static inline void omap_pm_get_oscillator(u32 *tstart, u32 *tshut) { } +static inline void omap_pm_setup_sr_i2c_pcb_length(u32 mm) { } #endif #endif diff --git a/arch/arm/mach-omap2/vc.c b/arch/arm/mach-omap2/vc.c index d72b787a0d83..687aa86c0d5e 100644 --- a/arch/arm/mach-omap2/vc.c +++ b/arch/arm/mach-omap2/vc.c @@ -24,6 +24,7 @@ #include "prm44xx.h" #include "pm.h" #include "scrm44xx.h" +#include "control.h" /** * struct omap_vc_channel_cfg - describe the cfg_channel bitfield @@ -69,6 +70,9 @@ static struct omap_vc_channel_cfg vc_mutant_channel_cfg = { }; static struct omap_vc_channel_cfg *vc_cfg_bits; + +/* Default I2C trace length on pcb, 6.3cm. Used for capacitance calculations. */ +static u32 sr_i2c_pcb_length = 63; #define CFG_CHANNEL_MASK 0x1f /** @@ -464,22 +468,135 @@ static void omap4_set_timings(struct voltagedomain *voltdm, bool off_mode) /* OMAP4 specific voltage init functions */ static void __init omap4_vc_init_channel(struct voltagedomain *voltdm) { - static bool is_initialized; - u32 vc_val; - omap4_set_timings(voltdm, true); omap4_set_timings(voltdm, false); - - if (is_initialized) - return; - - /* XXX These are magic numbers and do not belong! */ - vc_val = (0x60 << OMAP4430_SCLL_SHIFT | 0x26 << OMAP4430_SCLH_SHIFT); - voltdm->write(vc_val, OMAP4_PRM_VC_CFG_I2C_CLK_OFFSET); - - is_initialized = true; } +struct i2c_init_data { + u8 loadbits; + u8 load; + u8 hsscll_38_4; + u8 hsscll_26; + u8 hsscll_19_2; + u8 hsscll_16_8; + u8 hsscll_12; +}; + +static const __initdata struct i2c_init_data omap4_i2c_timing_data[] = { + { + .load = 50, + .loadbits = 0x3, + .hsscll_38_4 = 13, + .hsscll_26 = 11, + .hsscll_19_2 = 9, + .hsscll_16_8 = 9, + .hsscll_12 = 8, + }, + { + .load = 25, + .loadbits = 0x2, + .hsscll_38_4 = 13, + .hsscll_26 = 11, + .hsscll_19_2 = 9, + .hsscll_16_8 = 9, + .hsscll_12 = 8, + }, + { + .load = 12, + .loadbits = 0x1, + .hsscll_38_4 = 11, + .hsscll_26 = 10, + .hsscll_19_2 = 9, + .hsscll_16_8 = 9, + .hsscll_12 = 8, + }, + { + .load = 0, + .loadbits = 0x0, + .hsscll_38_4 = 12, + .hsscll_26 = 10, + .hsscll_19_2 = 9, + .hsscll_16_8 = 8, + .hsscll_12 = 8, + }, +}; + +/** + * omap4_vc_i2c_timing_init - sets up board I2C timing parameters + * @voltdm: voltagedomain pointer to get data from + * + * Use PMIC + board supplied settings for calculating the total I2C + * channel capacitance and set the timing parameters based on this. + * Pre-calculated values are provided in data tables, as it is not + * too straightforward to calculate these runtime. + */ +static void __init omap4_vc_i2c_timing_init(struct voltagedomain *voltdm) +{ + u32 capacitance; + u32 val; + u16 hsscll; + const struct i2c_init_data *i2c_data; + + if (!voltdm->pmic->i2c_high_speed) { + pr_warn("%s: only high speed supported!\n", __func__); + return; + } + + /* PCB trace capacitance, 0.125pF / mm => mm / 8 */ + capacitance = DIV_ROUND_UP(sr_i2c_pcb_length, 8); + + /* OMAP pad capacitance */ + capacitance += 4; + + /* PMIC pad capacitance */ + capacitance += voltdm->pmic->i2c_pad_load; + + /* Search for capacitance match in the table */ + i2c_data = omap4_i2c_timing_data; + + while (i2c_data->load > capacitance) + i2c_data++; + + /* Select proper values based on sysclk frequency */ + switch (voltdm->sys_clk.rate) { + case 38400000: + hsscll = i2c_data->hsscll_38_4; + break; + case 26000000: + hsscll = i2c_data->hsscll_26; + break; + case 19200000: + hsscll = i2c_data->hsscll_19_2; + break; + case 16800000: + hsscll = i2c_data->hsscll_16_8; + break; + case 12000000: + hsscll = i2c_data->hsscll_12; + break; + default: + pr_warn("%s: unsupported sysclk rate: %d!\n", __func__, + voltdm->sys_clk.rate); + return; + } + + /* Loadbits define pull setup for the I2C channels */ + val = i2c_data->loadbits << 25 | i2c_data->loadbits << 29; + + /* Write to SYSCTRL_PADCONF_WKUP_CTRL_I2C_2 to setup I2C pull */ + __raw_writel(val, OMAP2_L4_IO_ADDRESS(OMAP4_CTRL_MODULE_PAD_WKUP + + OMAP4_CTRL_MODULE_PAD_WKUP_CONTROL_I2C_2)); + + /* HSSCLH can always be zero */ + val = hsscll << OMAP4430_HSSCLL_SHIFT; + val |= (0x28 << OMAP4430_SCLL_SHIFT | 0x2c << OMAP4430_SCLH_SHIFT); + + /* Write setup times to I2C config register */ + voltdm->write(val, OMAP4_PRM_VC_CFG_I2C_CLK_OFFSET); +} + + + /** * omap_vc_i2c_init - initialize I2C interface to PMIC * @voltdm: voltage domain containing VC data @@ -519,6 +636,9 @@ static void __init omap_vc_i2c_init(struct voltagedomain *voltdm) mcode << __ffs(vc->common->i2c_mcode_mask), vc->common->i2c_cfg_reg); + if (cpu_is_omap44xx()) + omap4_vc_i2c_timing_init(voltdm); + initialized = true; } @@ -546,6 +666,19 @@ static u8 omap_vc_calc_vsel(struct voltagedomain *voltdm, u32 uvolt) return voltdm->pmic->uv_to_vsel(uvolt); } +/** + * omap_pm_setup_sr_i2c_pcb_length - set length of SR I2C traces on PCB + * @mm: length of the PCB trace in millimetres + * + * Sets the PCB trace length for the I2C channel. By default uses 63mm. + * This is needed for properly calculating the capacitance value for + * the PCB trace, and for setting the SR I2C channel timing parameters. + */ +void __init omap_pm_setup_sr_i2c_pcb_length(u32 mm) +{ + sr_i2c_pcb_length = mm; +} + void __init omap_vc_init_channel(struct voltagedomain *voltdm) { struct omap_vc_channel *vc = voltdm->vc; diff --git a/arch/arm/mach-omap2/voltage.h b/arch/arm/mach-omap2/voltage.h index 78923f93efde..a0ce4f10ff13 100644 --- a/arch/arm/mach-omap2/voltage.h +++ b/arch/arm/mach-omap2/voltage.h @@ -139,6 +139,7 @@ struct omap_voltdm_pmic { u32 vddmax; u8 vp_timeout_us; bool i2c_high_speed; + u32 i2c_pad_load; u8 i2c_mcode; unsigned long (*vsel_to_uv) (const u8 vsel); u8 (*uv_to_vsel) (unsigned long uV); From 83b5b5519c24c2af3e31c723573fbfbf9ba1bbdb Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Tue, 25 Sep 2012 19:33:49 +0300 Subject: [PATCH 14/15] ARM: OMAP4: TWL: enable high speed mode for PMIC communication With the new parameters, I2C can now be put to high speed mode for better performance. Signed-off-by: Tero Kristo Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/omap_twl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/mach-omap2/omap_twl.c b/arch/arm/mach-omap2/omap_twl.c index 611cb63d5ce6..7ff9667d9761 100644 --- a/arch/arm/mach-omap2/omap_twl.c +++ b/arch/arm/mach-omap2/omap_twl.c @@ -218,6 +218,7 @@ static struct omap_voltdm_pmic omap4_core_pmic = { .i2c_slave_addr = OMAP4_SRI2C_SLAVE_ADDR, .volt_reg_addr = OMAP4_VDD_CORE_SR_VOLT_REG, .cmd_reg_addr = OMAP4_VDD_CORE_SR_CMD_REG, + .i2c_high_speed = true, .i2c_pad_load = 3, .vsel_to_uv = twl6030_vsel_to_uv, .uv_to_vsel = twl6030_uv_to_vsel, From df7cded30ced539d3b4e6bae9f3011d98c069d41 Mon Sep 17 00:00:00 2001 From: Vishwanath Sripathy Date: Tue, 25 Sep 2012 19:33:50 +0300 Subject: [PATCH 15/15] ARM: OMAP4: OPP: add OMAP4460 definitions Add OMAP4460 OPP definitions for voltage and frequencies based on OMAP4460 ES1.0 DM Operating Condition Addendum Version 0.1 The following exceptions are present: * Smartreflex support is still on experimental mode: the gains and min limits are currently pending characterization data. Currently OMAP4430 values are used. * Efuse offset for core OPP100-OV setting is not clear in documentation. * IVA OPPs beyond OPP100 are disabled due to the delta between max OMAP4460 current requirements and Phoenix Max supply on VCORE2 in the default configuration - boards which have supply which can support this should explicitly call opp_enable and enable the same. * MPU OPPs > OPPTURBO can easily be detected using a efuse burnt - currently disabled pending clock changes to support DCC feature. [nm@ti.com: cleanups and updates from Datamanual] Signed-off-by: Nishanth Menon Signed-off-by: Vishwanath BS [t-kristo@ti.com: rebased to linux-3.6-rc5] Signed-off-by: Tero Kristo Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/control.h | 1 + arch/arm/mach-omap2/omap_opp_data.h | 9 +- arch/arm/mach-omap2/opp4xxx_data.c | 98 ++++++++++++++++--- arch/arm/mach-omap2/voltagedomains44xx_data.c | 12 ++- 4 files changed, 103 insertions(+), 17 deletions(-) diff --git a/arch/arm/mach-omap2/control.h b/arch/arm/mach-omap2/control.h index a89e8256fd0e..d236257626bf 100644 --- a/arch/arm/mach-omap2/control.h +++ b/arch/arm/mach-omap2/control.h @@ -201,6 +201,7 @@ #define OMAP44XX_CONTROL_FUSE_MPU_OPPNITRO 0x249 #define OMAP44XX_CONTROL_FUSE_CORE_OPP50 0x254 #define OMAP44XX_CONTROL_FUSE_CORE_OPP100 0x257 +#define OMAP44XX_CONTROL_FUSE_CORE_OPP100OV 0x25A /* AM35XX only CONTROL_GENERAL register offsets */ #define AM35XX_CONTROL_MSUSPENDMUX_6 (OMAP2_CONTROL_GENERAL + 0x0038) diff --git a/arch/arm/mach-omap2/omap_opp_data.h b/arch/arm/mach-omap2/omap_opp_data.h index c784c12f98a1..18a750e296a8 100644 --- a/arch/arm/mach-omap2/omap_opp_data.h +++ b/arch/arm/mach-omap2/omap_opp_data.h @@ -89,8 +89,11 @@ extern struct omap_volt_data omap34xx_vddcore_volt_data[]; extern struct omap_volt_data omap36xx_vddmpu_volt_data[]; extern struct omap_volt_data omap36xx_vddcore_volt_data[]; -extern struct omap_volt_data omap44xx_vdd_mpu_volt_data[]; -extern struct omap_volt_data omap44xx_vdd_iva_volt_data[]; -extern struct omap_volt_data omap44xx_vdd_core_volt_data[]; +extern struct omap_volt_data omap443x_vdd_mpu_volt_data[]; +extern struct omap_volt_data omap443x_vdd_iva_volt_data[]; +extern struct omap_volt_data omap443x_vdd_core_volt_data[]; +extern struct omap_volt_data omap446x_vdd_mpu_volt_data[]; +extern struct omap_volt_data omap446x_vdd_iva_volt_data[]; +extern struct omap_volt_data omap446x_vdd_core_volt_data[]; #endif /* __ARCH_ARM_MACH_OMAP2_OMAP_OPP_DATA_H */ diff --git a/arch/arm/mach-omap2/opp4xxx_data.c b/arch/arm/mach-omap2/opp4xxx_data.c index a9fd6d5fe79e..d470b728e720 100644 --- a/arch/arm/mach-omap2/opp4xxx_data.c +++ b/arch/arm/mach-omap2/opp4xxx_data.c @@ -1,7 +1,7 @@ /* * OMAP4 OPP table definitions. * - * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (C) 2010-2012 Texas Instruments Incorporated - http://www.ti.com/ * Nishanth Menon * Kevin Hilman * Thara Gopinath @@ -35,7 +35,7 @@ #define OMAP4430_VDD_MPU_OPPTURBO_UV 1313000 #define OMAP4430_VDD_MPU_OPPNITRO_UV 1375000 -struct omap_volt_data omap44xx_vdd_mpu_volt_data[] = { +struct omap_volt_data omap443x_vdd_mpu_volt_data[] = { VOLT_DATA_DEFINE(OMAP4430_VDD_MPU_OPP50_UV, OMAP44XX_CONTROL_FUSE_MPU_OPP50, 0xf4, 0x0c), VOLT_DATA_DEFINE(OMAP4430_VDD_MPU_OPP100_UV, OMAP44XX_CONTROL_FUSE_MPU_OPP100, 0xf9, 0x16), VOLT_DATA_DEFINE(OMAP4430_VDD_MPU_OPPTURBO_UV, OMAP44XX_CONTROL_FUSE_MPU_OPPTURBO, 0xfa, 0x23), @@ -47,7 +47,7 @@ struct omap_volt_data omap44xx_vdd_mpu_volt_data[] = { #define OMAP4430_VDD_IVA_OPP100_UV 1188000 #define OMAP4430_VDD_IVA_OPPTURBO_UV 1300000 -struct omap_volt_data omap44xx_vdd_iva_volt_data[] = { +struct omap_volt_data omap443x_vdd_iva_volt_data[] = { VOLT_DATA_DEFINE(OMAP4430_VDD_IVA_OPP50_UV, OMAP44XX_CONTROL_FUSE_IVA_OPP50, 0xf4, 0x0c), VOLT_DATA_DEFINE(OMAP4430_VDD_IVA_OPP100_UV, OMAP44XX_CONTROL_FUSE_IVA_OPP100, 0xf9, 0x16), VOLT_DATA_DEFINE(OMAP4430_VDD_IVA_OPPTURBO_UV, OMAP44XX_CONTROL_FUSE_IVA_OPPTURBO, 0xfa, 0x23), @@ -57,14 +57,14 @@ struct omap_volt_data omap44xx_vdd_iva_volt_data[] = { #define OMAP4430_VDD_CORE_OPP50_UV 1025000 #define OMAP4430_VDD_CORE_OPP100_UV 1200000 -struct omap_volt_data omap44xx_vdd_core_volt_data[] = { +struct omap_volt_data omap443x_vdd_core_volt_data[] = { VOLT_DATA_DEFINE(OMAP4430_VDD_CORE_OPP50_UV, OMAP44XX_CONTROL_FUSE_CORE_OPP50, 0xf4, 0x0c), VOLT_DATA_DEFINE(OMAP4430_VDD_CORE_OPP100_UV, OMAP44XX_CONTROL_FUSE_CORE_OPP100, 0xf9, 0x16), VOLT_DATA_DEFINE(0, 0, 0, 0), }; -static struct omap_opp_def __initdata omap44xx_opp_def_list[] = { +static struct omap_opp_def __initdata omap443x_opp_def_list[] = { /* MPU OPP1 - OPP50 */ OPP_INITIALIZER("mpu", true, 300000000, OMAP4430_VDD_MPU_OPP50_UV), /* MPU OPP2 - OPP100 */ @@ -86,6 +86,82 @@ static struct omap_opp_def __initdata omap44xx_opp_def_list[] = { /* TODO: add DSP, aess, fdif, gpu */ }; +#define OMAP4460_VDD_MPU_OPP50_UV 1025000 +#define OMAP4460_VDD_MPU_OPP100_UV 1200000 +#define OMAP4460_VDD_MPU_OPPTURBO_UV 1313000 +#define OMAP4460_VDD_MPU_OPPNITRO_UV 1375000 + +struct omap_volt_data omap446x_vdd_mpu_volt_data[] = { + VOLT_DATA_DEFINE(OMAP4460_VDD_MPU_OPP50_UV, OMAP44XX_CONTROL_FUSE_MPU_OPP50, 0xf4, 0x0c), + VOLT_DATA_DEFINE(OMAP4460_VDD_MPU_OPP100_UV, OMAP44XX_CONTROL_FUSE_MPU_OPP100, 0xf9, 0x16), + VOLT_DATA_DEFINE(OMAP4460_VDD_MPU_OPPTURBO_UV, OMAP44XX_CONTROL_FUSE_MPU_OPPTURBO, 0xfa, 0x23), + VOLT_DATA_DEFINE(OMAP4460_VDD_MPU_OPPNITRO_UV, OMAP44XX_CONTROL_FUSE_MPU_OPPNITRO, 0xfa, 0x27), + VOLT_DATA_DEFINE(0, 0, 0, 0), +}; + +#define OMAP4460_VDD_IVA_OPP50_UV 1025000 +#define OMAP4460_VDD_IVA_OPP100_UV 1200000 +#define OMAP4460_VDD_IVA_OPPTURBO_UV 1313000 +#define OMAP4460_VDD_IVA_OPPNITRO_UV 1375000 + +struct omap_volt_data omap446x_vdd_iva_volt_data[] = { + VOLT_DATA_DEFINE(OMAP4460_VDD_IVA_OPP50_UV, OMAP44XX_CONTROL_FUSE_IVA_OPP50, 0xf4, 0x0c), + VOLT_DATA_DEFINE(OMAP4460_VDD_IVA_OPP100_UV, OMAP44XX_CONTROL_FUSE_IVA_OPP100, 0xf9, 0x16), + VOLT_DATA_DEFINE(OMAP4460_VDD_IVA_OPPTURBO_UV, OMAP44XX_CONTROL_FUSE_IVA_OPPTURBO, 0xfa, 0x23), + VOLT_DATA_DEFINE(OMAP4460_VDD_IVA_OPPNITRO_UV, OMAP44XX_CONTROL_FUSE_IVA_OPPNITRO, 0xfa, 0x23), + VOLT_DATA_DEFINE(0, 0, 0, 0), +}; + +#define OMAP4460_VDD_CORE_OPP50_UV 1025000 +#define OMAP4460_VDD_CORE_OPP100_UV 1200000 +#define OMAP4460_VDD_CORE_OPP100_OV_UV 1250000 + +struct omap_volt_data omap446x_vdd_core_volt_data[] = { + VOLT_DATA_DEFINE(OMAP4460_VDD_CORE_OPP50_UV, OMAP44XX_CONTROL_FUSE_CORE_OPP50, 0xf4, 0x0c), + VOLT_DATA_DEFINE(OMAP4460_VDD_CORE_OPP100_UV, OMAP44XX_CONTROL_FUSE_CORE_OPP100, 0xf9, 0x16), + VOLT_DATA_DEFINE(OMAP4460_VDD_CORE_OPP100_OV_UV, OMAP44XX_CONTROL_FUSE_CORE_OPP100OV, 0xf9, 0x16), + VOLT_DATA_DEFINE(0, 0, 0, 0), +}; + +static struct omap_opp_def __initdata omap446x_opp_def_list[] = { + /* MPU OPP1 - OPP50 */ + OPP_INITIALIZER("mpu", true, 350000000, OMAP4460_VDD_MPU_OPP50_UV), + /* MPU OPP2 - OPP100 */ + OPP_INITIALIZER("mpu", true, 700000000, OMAP4460_VDD_MPU_OPP100_UV), + /* MPU OPP3 - OPP-Turbo */ + OPP_INITIALIZER("mpu", true, 920000000, OMAP4460_VDD_MPU_OPPTURBO_UV), + /* + * MPU OPP4 - OPP-Nitro + Disabled as the reference schematics + * recommends TPS623631 - confirm and enable the opp in board file + * XXX: May be we should enable these based on mpu capability and + * Exception board files disable it... + */ + OPP_INITIALIZER("mpu", false, 1200000000, OMAP4460_VDD_MPU_OPPNITRO_UV), + /* MPU OPP4 - OPP-Nitro SpeedBin */ + OPP_INITIALIZER("mpu", false, 1500000000, OMAP4460_VDD_MPU_OPPNITRO_UV), + /* L3 OPP1 - OPP50 */ + OPP_INITIALIZER("l3_main_1", true, 100000000, OMAP4460_VDD_CORE_OPP50_UV), + /* L3 OPP2 - OPP100 */ + OPP_INITIALIZER("l3_main_1", true, 200000000, OMAP4460_VDD_CORE_OPP100_UV), + /* IVA OPP1 - OPP50 */ + OPP_INITIALIZER("iva", true, 133000000, OMAP4460_VDD_IVA_OPP50_UV), + /* IVA OPP2 - OPP100 */ + OPP_INITIALIZER("iva", true, 266100000, OMAP4460_VDD_IVA_OPP100_UV), + /* + * IVA OPP3 - OPP-Turbo + Disabled as the reference schematics + * recommends Phoenix VCORE2 which can supply only 600mA - so the ones + * above this OPP frequency, even though OMAP is capable, should be + * enabled by board file which is sure of the chip power capability + */ + OPP_INITIALIZER("iva", false, 332000000, OMAP4460_VDD_IVA_OPPTURBO_UV), + /* IVA OPP4 - OPP-Nitro */ + OPP_INITIALIZER("iva", false, 430000000, OMAP4460_VDD_IVA_OPPNITRO_UV), + /* IVA OPP5 - OPP-Nitro SpeedBin*/ + OPP_INITIALIZER("iva", false, 500000000, OMAP4460_VDD_IVA_OPPNITRO_UV), + + /* TODO: add DSP, aess, fdif, gpu */ +}; + /** * omap4_opp_init() - initialize omap4 opp table */ @@ -93,12 +169,12 @@ int __init omap4_opp_init(void) { int r = -ENODEV; - if (!cpu_is_omap443x()) - return r; - - r = omap_init_opp_table(omap44xx_opp_def_list, - ARRAY_SIZE(omap44xx_opp_def_list)); - + if (cpu_is_omap443x()) + r = omap_init_opp_table(omap443x_opp_def_list, + ARRAY_SIZE(omap443x_opp_def_list)); + else if (cpu_is_omap446x()) + r = omap_init_opp_table(omap446x_opp_def_list, + ARRAY_SIZE(omap446x_opp_def_list)); return r; } device_initcall(omap4_opp_init); diff --git a/arch/arm/mach-omap2/voltagedomains44xx_data.c b/arch/arm/mach-omap2/voltagedomains44xx_data.c index 7da35a67c988..b893c8e6f88f 100644 --- a/arch/arm/mach-omap2/voltagedomains44xx_data.c +++ b/arch/arm/mach-omap2/voltagedomains44xx_data.c @@ -104,9 +104,15 @@ void __init omap44xx_voltagedomains_init(void) * for the currently-running IC */ #ifdef CONFIG_PM_OPP - omap4_voltdm_mpu.volt_data = omap44xx_vdd_mpu_volt_data; - omap4_voltdm_iva.volt_data = omap44xx_vdd_iva_volt_data; - omap4_voltdm_core.volt_data = omap44xx_vdd_core_volt_data; + if (cpu_is_omap443x()) { + omap4_voltdm_mpu.volt_data = omap443x_vdd_mpu_volt_data; + omap4_voltdm_iva.volt_data = omap443x_vdd_iva_volt_data; + omap4_voltdm_core.volt_data = omap443x_vdd_core_volt_data; + } else if (cpu_is_omap446x()) { + omap4_voltdm_mpu.volt_data = omap446x_vdd_mpu_volt_data; + omap4_voltdm_iva.volt_data = omap446x_vdd_iva_volt_data; + omap4_voltdm_core.volt_data = omap446x_vdd_core_volt_data; + } #endif omap4_voltdm_mpu.vp_param = &omap4_mpu_vp_data;