Signed-off-by: Tero Kristo <t-kristo@xxxxxx> --- arch/arm/mach-omap2/vc.c | 166 ++++++++++++++++++++++++++++++++++++++-------- 1 files changed, 138 insertions(+), 28 deletions(-) diff --git a/arch/arm/mach-omap2/vc.c b/arch/arm/mach-omap2/vc.c index 16fa912..c50e598 100644 --- a/arch/arm/mach-omap2/vc.c +++ b/arch/arm/mach-omap2/vc.c @@ -1,14 +1,18 @@ #include <linux/kernel.h> #include <linux/delay.h> #include <linux/init.h> +#include <linux/clk.h> +#include <linux/io.h> #include <plat/cpu.h> +#include <plat/prcm.h> #include "voltage.h" #include "vc.h" #include "prm-regbits-34xx.h" #include "prm-regbits-44xx.h" #include "prm44xx.h" +#include "scrm44xx.h" /** * struct omap_vc_channel_cfg - describe the cfg_channel bitfield @@ -194,44 +198,156 @@ int omap_vc_bypass_scale(struct voltagedomain *voltdm, return 0; } -static void __init omap3_vfsm_init(struct voltagedomain *voltdm) +static void omap3_set_ret_timings(struct voltagedomain *voltdm) { - /* - * Voltage Manager FSM parameters init - * XXX This data should be passed in from the board file - */ - voltdm->write(OMAP3_CLKSETUP, OMAP3_PRM_CLKSETUP_OFFSET); - voltdm->write(OMAP3_VOLTOFFSET, OMAP3_PRM_VOLTOFFSET_OFFSET); - voltdm->write(OMAP3_VOLTSETUP2, OMAP3_PRM_VOLTSETUP2_OFFSET); + unsigned long voltsetup1; + struct clk *sys_ck; + u32 sys_clk_rate; + + sys_ck = clk_get(NULL, "sys_ck"); + if (IS_ERR(sys_ck)) { + pr_warning("%s: unable to get sys_ck to calculate " + "vdd_%s timings\n", __func__, voltdm->name); + return; + } + sys_clk_rate = clk_get_rate(sys_ck); + clk_put(sys_ck); + + voltsetup1 = (voltdm->vc_param->on - voltdm->vc_param->ret) / + voltdm->pmic->slew_rate; + + voltsetup1 = voltsetup1 * sys_clk_rate / 8 / 1000000 + 1; + voltdm->rmw(voltdm->vfsm->voltsetup_mask, + voltsetup1 << __ffs(voltdm->vfsm->voltsetup_mask), + voltdm->vfsm->voltsetup_reg); + + /* set voltsetup 2 to 0 */ + voltdm->write(0, OMAP3_PRM_VOLTSETUP2_OFFSET); +} + +static void omap3_set_off_timings(struct voltagedomain *voltdm) +{ + unsigned long clksetup; + unsigned long voltsetup2; + + 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 = voltsetup2 * 32768 / 1000000 + 1; + + voltdm->write(voltsetup2, OMAP3_PRM_VOLTSETUP2_OFFSET); + + /* set voltsetup1 to 0 */ + voltdm->rmw(voltdm->vfsm->voltsetup_mask, 0, + voltdm->vfsm->voltsetup_reg); + + /* set voltoffset */ + voltdm->write(clksetup - voltsetup2, OMAP3_PRM_VOLTOFFSET_OFFSET); } static void __init omap3_vc_init_channel(struct voltagedomain *voltdm) { - static bool is_initialized; + omap3_set_off_timings(voltdm); +} - if (is_initialized) - return; +static u32 omap4_calc_volt_ramp(struct voltagedomain *voltdm, u32 voltage_diff, + u32 clk_rate) +{ + u32 prescaler; + u32 cycles; + u32 time; + + time = voltage_diff / voltdm->pmic->slew_rate; + + cycles = clk_rate / 1000 * time; + + 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_warning("%s: invalid setuptime for vdd_%s\n", __func__, + voltdm->name); + return 0; + } - omap3_vfsm_init(voltdm); + cycles++; - is_initialized = true; + return (prescaler << OMAP4430_RAMP_UP_PRESCAL_SHIFT) | + (cycles << OMAP4430_RAMP_UP_COUNT_SHIFT); } +static void omap4_set_timings(struct voltagedomain *voltdm, bool off_mode) +{ + struct clk *sys_ck; + u32 sys_clk_rate; + u32 val; + u32 ramp; + + sys_ck = clk_get(NULL, "sys_clkin_ck"); + if (IS_ERR(sys_ck)) { + pr_warning("%s: unable to get sys_ck to calculate " + "vdd_%s timings\n", __func__, voltdm->name); + return; + } + sys_clk_rate = clk_get_rate(sys_ck); + clk_put(sys_ck); + + /* configure the setup times */ + val = voltdm->read(voltdm->vfsm->voltsetup_reg); + + if (off_mode) + ramp = omap4_calc_volt_ramp(voltdm, + voltdm->vc_param->on - voltdm->vc_param->off, + sys_clk_rate); + else + ramp = omap4_calc_volt_ramp(voltdm, + voltdm->vc_param->on - voltdm->vc_param->ret, + sys_clk_rate); + + if (!ramp) + return; + + val |= ramp << OMAP4430_RAMP_DOWN_COUNT_SHIFT; + + val |= ramp << OMAP4430_RAMP_UP_COUNT_SHIFT; + + voltdm->write(val, voltdm->vfsm->voltsetup_reg); +} /* OMAP4 specific voltage init functions */ static void __init omap4_vc_init_channel(struct voltagedomain *voltdm) { - static bool is_initialized; u32 vc_val; - if (is_initialized) - return; + omap4_set_timings(voltdm, true); /* 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; } /** @@ -305,7 +421,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, @@ -329,10 +444,10 @@ 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 = voltdm->pmic->uv_to_vsel(voltdm->vc_param->on); + onlp_vsel = voltdm->pmic->uv_to_vsel(voltdm->vc_param->onlp); + ret_vsel = voltdm->pmic->uv_to_vsel(voltdm->vc_param->ret); + off_vsel = voltdm->pmic->uv_to_vsel(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) | @@ -343,11 +458,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()) -- 1.7.4.1 Texas Instruments Oy, Porkkalankatu 22, 00180 Helsinki, Finland. Business ID: 0115040-6. Domicile: Helsinki -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html