From: Kalle Jokiniemi To: linux-omap@vger.kernel.org Cc: Kalle Jokiniemi Subject: [PATCH 3/3] ARM: OMAP: SmartReflex driver: integration to linux-omap Date: Fri, 6 Jun 2008 12:49:49 +0300 Message-Id: <1212745789-13926-3-git-send-email-ext-kalle.jokiniemi@nokia.com> - Changed register accesses to use prm_{read,write}_mod_reg and prm_{set,clear,rmw}_mod_reg_bits() functions instread of "REG_X = REG_Y" type accesses. - Changed direct register clock enables/disables to clockframework calls. - replaced cpu-related #ifdefs with if (cpu_is_xxxx()) calls. - Added E-fuse support: Use silicon characteristics parameters from E-fuse - added smartreflex_disable/enable calls to pm34xx.c suspend function. - Added "SmartReflex support" entry into Kconfig under "System type->TI OMAP Implementations". It depends on ARCH_OMAP34XX and TWL4030_CORE. - Added "SmartReflex testing support" Kconfig option for using hard coded software parameters instead of E-fuse parameters. Signed-off-by: Kalle Jokiniemi --- arch/arm/mach-omap2/Makefile | 3 + arch/arm/mach-omap2/pm34xx.c | 9 + arch/arm/mach-omap2/smartreflex.c | 531 +++++++++++++++++++++++-------------- arch/arm/mach-omap2/smartreflex.h | 9 +- arch/arm/plat-omap/Kconfig | 31 +++ 5 files changed, 385 insertions(+), 198 deletions(-) diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index 50c6657..f645b6e 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -25,6 +25,9 @@ obj-$(CONFIG_ARCH_OMAP3) += pm34xx.o sleep34xx.o obj-$(CONFIG_PM_DEBUG) += pm-debug.o endif +# SmartReflex driver +obj-$(CONFIG_OMAP_SMARTREFLEX) += smartreflex.o + # Clock framework obj-$(CONFIG_ARCH_OMAP2) += clock24xx.o obj-$(CONFIG_ARCH_OMAP3) += clock34xx.o diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 7e775cc..3da4f47 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -36,6 +36,7 @@ #include "prm.h" #include "pm.h" +#include "smartreflex.h" struct power_state { struct powerdomain *pwrdm; @@ -256,6 +257,10 @@ static int omap3_pm_suspend(void) struct power_state *pwrst; int state, ret = 0; + /* XXX Disable smartreflex before entering suspend */ + disable_smartreflex(SR1); + disable_smartreflex(SR2); + /* Read current next_pwrsts */ list_for_each_entry(pwrst, &pwrst_list, node) pwrst->saved_state = pwrdm_read_next_pwrst(pwrst->pwrdm); @@ -287,6 +292,10 @@ restore: printk(KERN_INFO "Successfully put all powerdomains " "to target state\n"); + /* XXX Enable smartreflex after suspend */ + enable_smartreflex(SR1); + enable_smartreflex(SR2); + return ret; } diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c index dae7460..0b10a5d 100644 --- a/arch/arm/mach-omap2/smartreflex.c +++ b/arch/arm/mach-omap2/smartreflex.c @@ -3,6 +3,9 @@ * * OMAP34XX SmartReflex Voltage Control * + * Copyright (C) 2008 Nokia Corporation + * Kalle Jokiniemi + * * Copyright (C) 2007 Texas Instruments, Inc. * Lesly A M * @@ -20,13 +23,16 @@ #include #include #include - -#include -#include +#include +#include #include -#include "prcm-regs.h" +#include +#include + +#include "prm.h" #include "smartreflex.h" +#include "prm-regbits-34xx.h" /* #define DEBUG_SR 1 */ @@ -37,11 +43,16 @@ # define DPRINTK(fmt, args...) #endif +/* XXX: These should be relocated where-ever the OPP implementation will be */ +u32 current_vdd1_opp; +u32 current_vdd2_opp; + struct omap_sr{ int srid; int is_sr_reset; int is_autocomp_active; struct clk *fck; + u32 clk_length; u32 req_opp_no; u32 opp1_nvalue, opp2_nvalue, opp3_nvalue, opp4_nvalue, opp5_nvalue; u32 senp_mod, senn_mod; @@ -53,6 +64,7 @@ static struct omap_sr sr1 = { .srid = SR1, .is_sr_reset = 1, .is_autocomp_active = 0, + .clk_length = 0, .srbase_addr = OMAP34XX_SR1_BASE, }; @@ -60,6 +72,7 @@ static struct omap_sr sr2 = { .srid = SR2, .is_sr_reset = 1, .is_autocomp_active = 0, + .clk_length = 0, .srbase_addr = OMAP34XX_SR2_BASE, }; @@ -85,8 +98,6 @@ static inline u32 sr_read_reg(struct omap_sr *sr, int offset) return omap_readl(sr->srbase_addr + offset); } - -#ifndef USE_EFUSE_VALUES static void cal_reciprocal(u32 sensor, u32 *sengain, u32 *rnsen) { u32 gn, rn, mul; @@ -100,7 +111,21 @@ static void cal_reciprocal(u32 sensor, u32 *sengain, u32 *rnsen) } } } -#endif + +static void sr_clk_get(struct omap_sr *sr) +{ + if (sr->srid == SR1) { + sr->fck = clk_get(NULL, "sr1_fck"); + if (IS_ERR(sr->fck)) + printk(KERN_ERR "Could not get sr1_fck\n"); + + } else if (sr->srid == SR2) { + sr->fck = clk_get(NULL, "sr2_fck"); + if (IS_ERR(sr->fck)) + printk(KERN_ERR "Could not get sr2_fck\n"); + + } +} static int sr_clk_enable(struct omap_sr *sr) { @@ -131,22 +156,86 @@ static int sr_clk_disable(struct omap_sr *sr) return 0; } -static void sr_set_nvalues(struct omap_sr *sr) +static void sr_set_clk_length(struct omap_sr *sr) +{ + struct clk *osc_sys_ck; + u32 sys_clk = 0; + + osc_sys_ck = clk_get(NULL, "osc_sys_ck"); + sys_clk = clk_get_rate(osc_sys_ck); + clk_put(osc_sys_ck); + + switch (sys_clk) { + case 12000000: + sr->clk_length = SRCLKLENGTH_12MHZ_SYSCLK; + break; + case 13000000: + sr->clk_length = SRCLKLENGTH_13MHZ_SYSCLK; + break; + case 19200000: + sr->clk_length = SRCLKLENGTH_19MHZ_SYSCLK; + break; + case 26000000: + sr->clk_length = SRCLKLENGTH_26MHZ_SYSCLK; + break; + case 38400000: + sr->clk_length = SRCLKLENGTH_38MHZ_SYSCLK; + break; + default : + printk(KERN_ERR "Invalid sysclk value: %d\n", sys_clk); + break; + } +} + +static void sr_set_efuse_nvalues(struct omap_sr *sr) +{ + if (sr->srid == SR1) { + sr->senn_mod = (omap_ctrl_readl(OMAP343X_CONTROL_FUSE_SR) & + OMAP343X_SR1_SENNENABLE_MASK) >> + OMAP343X_SR1_SENNENABLE_SHIFT; + + sr->senp_mod = (omap_ctrl_readl(OMAP343X_CONTROL_FUSE_SR) & + OMAP343X_SR1_SENPENABLE_MASK) >> + OMAP343X_SR1_SENPENABLE_SHIFT; + + sr->opp5_nvalue = omap_ctrl_readl( + OMAP343X_CONTROL_FUSE_OPP5_VDD1); + sr->opp4_nvalue = omap_ctrl_readl( + OMAP343X_CONTROL_FUSE_OPP4_VDD1); + sr->opp3_nvalue = omap_ctrl_readl( + OMAP343X_CONTROL_FUSE_OPP3_VDD1); + sr->opp2_nvalue = omap_ctrl_readl( + OMAP343X_CONTROL_FUSE_OPP2_VDD1); + sr->opp1_nvalue = omap_ctrl_readl( + OMAP343X_CONTROL_FUSE_OPP1_VDD1); + } else if (sr->srid == SR2) { + sr->senn_mod = (omap_ctrl_readl(OMAP343X_CONTROL_FUSE_SR) & + OMAP343X_SR2_SENNENABLE_MASK) >> + OMAP343X_SR2_SENNENABLE_SHIFT; + + sr->senp_mod = (omap_ctrl_readl(OMAP343X_CONTROL_FUSE_SR) & + OMAP343X_SR2_SENPENABLE_MASK) >> + OMAP343X_SR2_SENPENABLE_SHIFT; + + sr->opp3_nvalue = omap_ctrl_readl( + OMAP343X_CONTROL_FUSE_OPP3_VDD2); + sr->opp2_nvalue = omap_ctrl_readl( + OMAP343X_CONTROL_FUSE_OPP2_VDD2); + sr->opp1_nvalue = omap_ctrl_readl( + OMAP343X_CONTROL_FUSE_OPP1_VDD2); + } +} + +/* Hard coded nvalues for testing purposes, may cause device to hang! */ +static void sr_set_testing_nvalues(struct omap_sr *sr) { -#ifdef USE_EFUSE_VALUES - u32 n1, n2; -#else u32 senpval, sennval; u32 senpgain, senngain; u32 rnsenp, rnsenn; -#endif if (sr->srid == SR1) { -#ifdef USE_EFUSE_VALUES - /* Read values for VDD1 from EFUSE */ -#else - /* since E-Fuse Values are not available, calculating the - * reciprocal of the SenN and SenP values for SR1 + /* Calculating the reciprocal of the SenN and SenP values + * for SR1 */ sr->senp_mod = 0x03; /* SenN-M5 enabled */ sr->senn_mod = 0x03; @@ -216,15 +305,16 @@ static void sr_set_nvalues(struct omap_sr *sr) (rnsenp << NVALUERECIPROCAL_RNSENP_SHIFT) | (rnsenn << NVALUERECIPROCAL_RNSENN_SHIFT)); + /* XXX The clocks are enabled in the startup and NVALUE is + * set also there. Disabling this for now, but this could + * be related to dynamic sleep during boot */ +#if 0 sr_clk_enable(sr); sr_write_reg(sr, NVALUERECIPROCAL, sr->opp3_nvalue); sr_clk_disable(sr); - #endif + } else if (sr->srid == SR2) { -#ifdef USE_EFUSE_VALUES - /* Read values for VDD2 from EFUSE */ -#else /* since E-Fuse Values are not available, calculating the * reciprocal of the SenN and SenP values for SR2 */ @@ -269,134 +359,163 @@ static void sr_set_nvalues(struct omap_sr *sr) (senngain << NVALUERECIPROCAL_SENNGAIN_SHIFT) | (rnsenp << NVALUERECIPROCAL_RNSENP_SHIFT) | (rnsenn << NVALUERECIPROCAL_RNSENN_SHIFT)); - -#endif } } +static void sr_set_nvalues(struct omap_sr *sr) +{ + if (SR_TESTING_NVALUES) + sr_set_testing_nvalues(sr); + else + sr_set_efuse_nvalues(sr); +} + static void sr_configure_vp(int srid) { u32 vpconfig; if (srid == SR1) { vpconfig = PRM_VP1_CONFIG_ERROROFFSET | PRM_VP1_CONFIG_ERRORGAIN - | PRM_VP1_CONFIG_INITVOLTAGE | PRM_VP1_CONFIG_TIMEOUTEN; - - PRM_VP1_CONFIG = vpconfig; - PRM_VP1_VSTEPMIN = PRM_VP1_VSTEPMIN_SMPSWAITTIMEMIN | - PRM_VP1_VSTEPMIN_VSTEPMIN; - - PRM_VP1_VSTEPMAX = PRM_VP1_VSTEPMAX_SMPSWAITTIMEMAX | - PRM_VP1_VSTEPMAX_VSTEPMAX; - - PRM_VP1_VLIMITTO = PRM_VP1_VLIMITTO_VDDMAX | - PRM_VP1_VLIMITTO_VDDMIN | PRM_VP1_VLIMITTO_TIMEOUT; - - PRM_VP1_CONFIG |= PRM_VP1_CONFIG_INITVDD; - PRM_VP1_CONFIG &= ~PRM_VP1_CONFIG_INITVDD; + | PRM_VP1_CONFIG_INITVOLTAGE + | PRM_VP1_CONFIG_TIMEOUTEN; + + prm_write_mod_reg(vpconfig, OMAP3430_GR_MOD, + OMAP3_PRM_VP1_CONFIG_OFFSET); + prm_write_mod_reg(PRM_VP1_VSTEPMIN_SMPSWAITTIMEMIN | + PRM_VP1_VSTEPMIN_VSTEPMIN, + OMAP3430_GR_MOD, + OMAP3_PRM_VP1_VSTEPMIN_OFFSET); + + prm_write_mod_reg(PRM_VP1_VSTEPMAX_SMPSWAITTIMEMAX | + PRM_VP1_VSTEPMAX_VSTEPMAX, + OMAP3430_GR_MOD, + OMAP3_PRM_VP1_VSTEPMAX_OFFSET); + + prm_write_mod_reg(PRM_VP1_VLIMITTO_VDDMAX | + PRM_VP1_VLIMITTO_VDDMIN | + PRM_VP1_VLIMITTO_TIMEOUT, + OMAP3430_GR_MOD, + OMAP3_PRM_VP1_VLIMITTO_OFFSET); + + /* Trigger initVDD value copy to voltage processor */ + prm_set_mod_reg_bits(PRM_VP1_CONFIG_INITVDD, OMAP3430_GR_MOD, + OMAP3_PRM_VP1_CONFIG_OFFSET); + /* Clear initVDD copy trigger bit */ + prm_clear_mod_reg_bits(PRM_VP1_CONFIG_INITVDD, OMAP3430_GR_MOD, + OMAP3_PRM_VP1_CONFIG_OFFSET); } else if (srid == SR2) { vpconfig = PRM_VP2_CONFIG_ERROROFFSET | PRM_VP2_CONFIG_ERRORGAIN - | PRM_VP2_CONFIG_INITVOLTAGE | PRM_VP2_CONFIG_TIMEOUTEN; - - PRM_VP2_CONFIG = vpconfig; - PRM_VP2_VSTEPMIN = PRM_VP2_VSTEPMIN_SMPSWAITTIMEMIN | - PRM_VP2_VSTEPMIN_VSTEPMIN; - - PRM_VP2_VSTEPMAX = PRM_VP2_VSTEPMAX_SMPSWAITTIMEMAX | - PRM_VP2_VSTEPMAX_VSTEPMAX; - - PRM_VP2_VLIMITTO = PRM_VP2_VLIMITTO_VDDMAX | - PRM_VP2_VLIMITTO_VDDMIN | PRM_VP2_VLIMITTO_TIMEOUT; - - PRM_VP2_CONFIG |= PRM_VP2_CONFIG_INITVDD; - PRM_VP2_CONFIG &= ~PRM_VP2_CONFIG_INITVDD; + | PRM_VP2_CONFIG_INITVOLTAGE + | PRM_VP2_CONFIG_TIMEOUTEN; + + prm_write_mod_reg(vpconfig, OMAP3430_GR_MOD, + OMAP3_PRM_VP2_CONFIG_OFFSET); + prm_write_mod_reg(PRM_VP2_VSTEPMIN_SMPSWAITTIMEMIN | + PRM_VP2_VSTEPMIN_VSTEPMIN, + OMAP3430_GR_MOD, + OMAP3_PRM_VP2_VSTEPMIN_OFFSET); + + prm_write_mod_reg(PRM_VP2_VSTEPMAX_SMPSWAITTIMEMAX | + PRM_VP2_VSTEPMAX_VSTEPMAX, + OMAP3430_GR_MOD, + OMAP3_PRM_VP2_VSTEPMAX_OFFSET); + + prm_write_mod_reg(PRM_VP2_VLIMITTO_VDDMAX | + PRM_VP2_VLIMITTO_VDDMIN | + PRM_VP2_VLIMITTO_TIMEOUT, + OMAP3430_GR_MOD, + OMAP3_PRM_VP2_VLIMITTO_OFFSET); + + /* Trigger initVDD value copy to voltage processor */ + prm_set_mod_reg_bits(PRM_VP2_CONFIG_INITVDD, OMAP3430_GR_MOD, + OMAP3_PRM_VP2_CONFIG_OFFSET); + /* Reset initVDD copy trigger bit */ + prm_clear_mod_reg_bits(PRM_VP2_CONFIG_INITVDD, OMAP3430_GR_MOD, + OMAP3_PRM_VP2_CONFIG_OFFSET); } } static void sr_configure_vc(void) { - PRM_VC_SMPS_SA = - (R_SRI2C_SLAVE_ADDR << PRM_VC_SMPS_SA1_SHIFT) | - (R_SRI2C_SLAVE_ADDR << PRM_VC_SMPS_SA0_SHIFT); - - PRM_VC_SMPS_VOL_RA = (R_VDD2_SR_CONTROL << PRM_VC_SMPS_VOLRA1_SHIFT) | - (R_VDD1_SR_CONTROL << PRM_VC_SMPS_VOLRA0_SHIFT); - - PRM_VC_CMD_VAL_0 = (PRM_VC_CMD_VAL0_ON << PRM_VC_CMD_ON_SHIFT) | - (PRM_VC_CMD_VAL0_ONLP << PRM_VC_CMD_ONLP_SHIFT) | - (PRM_VC_CMD_VAL0_RET << PRM_VC_CMD_RET_SHIFT) | - (PRM_VC_CMD_VAL0_OFF << PRM_VC_CMD_OFF_SHIFT); - - PRM_VC_CMD_VAL_1 = (PRM_VC_CMD_VAL1_ON << PRM_VC_CMD_ON_SHIFT) | - (PRM_VC_CMD_VAL1_ONLP << PRM_VC_CMD_ONLP_SHIFT) | - (PRM_VC_CMD_VAL1_RET << PRM_VC_CMD_RET_SHIFT) | - (PRM_VC_CMD_VAL1_OFF << PRM_VC_CMD_OFF_SHIFT); - - PRM_VC_CH_CONF = PRM_VC_CH_CONF_CMD1 | PRM_VC_CH_CONF_RAV1; - - PRM_VC_I2C_CFG = PRM_VC_I2C_CFG_MCODE | PRM_VC_I2C_CFG_HSEN - | PRM_VC_I2C_CFG_SREN; + prm_write_mod_reg((R_SRI2C_SLAVE_ADDR << OMAP3430_SMPS_SA1_SHIFT) | + (R_SRI2C_SLAVE_ADDR << OMAP3430_SMPS_SA0_SHIFT), + OMAP3430_GR_MOD, OMAP3_PRM_VC_SMPS_SA_OFFSET); + + prm_write_mod_reg((R_VDD2_SR_CONTROL << OMAP3430_VOLRA1_SHIFT) | + (R_VDD1_SR_CONTROL << OMAP3430_VOLRA0_SHIFT), + OMAP3430_GR_MOD, OMAP3_PRM_VC_SMPS_VOL_RA_OFFSET); + + prm_write_mod_reg((OMAP3430_VC_CMD_VAL0_ON << + OMAP3430_VC_CMD_ON_SHIFT) | + (OMAP3430_VC_CMD_VAL0_ONLP << OMAP3430_VC_CMD_ONLP_SHIFT) | + (OMAP3430_VC_CMD_VAL0_RET << OMAP3430_VC_CMD_RET_SHIFT) | + (OMAP3430_VC_CMD_VAL0_OFF << OMAP3430_VC_CMD_OFF_SHIFT), + OMAP3430_GR_MOD, OMAP3_PRM_VC_CMD_VAL_0_OFFSET); + + prm_write_mod_reg((OMAP3430_VC_CMD_VAL1_ON << + OMAP3430_VC_CMD_ON_SHIFT) | + (OMAP3430_VC_CMD_VAL1_ONLP << OMAP3430_VC_CMD_ONLP_SHIFT) | + (OMAP3430_VC_CMD_VAL1_RET << OMAP3430_VC_CMD_RET_SHIFT) | + (OMAP3430_VC_CMD_VAL1_OFF << OMAP3430_VC_CMD_OFF_SHIFT), + OMAP3430_GR_MOD, OMAP3_PRM_VC_CMD_VAL_1_OFFSET); + + prm_write_mod_reg(OMAP3430_CMD1 | OMAP3430_RAV1, + OMAP3430_GR_MOD, + OMAP3_PRM_VC_CH_CONF_OFFSET); + + prm_write_mod_reg(OMAP3430_MCODE_SHIFT | OMAP3430_HSEN | OMAP3430_SREN, + OMAP3430_GR_MOD, + OMAP3_PRM_VC_I2C_CFG_OFFSET); /* Setup voltctrl and other setup times */ + /* XXX CONFIG_SYSOFFMODE has not been implemented yet */ #ifdef CONFIG_SYSOFFMODE - PRM_VOLTCTRL = PRM_VOLTCTRL_AUTO_OFF | PRM_VOLTCTRL_AUTO_RET; - PRM_CLKSETUP = PRM_CLKSETUP_DURATION; - PRM_VOLTSETUP1 = (PRM_VOLTSETUP_TIME2 << PRM_VOLTSETUP_TIME2_OFFSET) | - (PRM_VOLTSETUP_TIME1 << PRM_VOLTSETUP_TIME1_OFFSET); - PRM_VOLTOFFSET = PRM_VOLTOFFSET_DURATION; - PRM_VOLTSETUP2 = PRM_VOLTSETUP2_DURATION; + prm_write_mod_reg(OMAP3430_AUTO_OFF | OMAP3430_AUTO_RET, + OMAP3430_GR_MOD, + OMAP3_PRM_VOLTCTRL_OFFSET); + + prm_write_mod_reg(OMAP3430_CLKSETUP_DURATION, OMAP3430_GR_MOD, + OMAP3_PRM_CLKSETUP_OFFSET); + prm_write_mod_reg((OMAP3430_VOLTSETUP_TIME2 << + OMAP3430_VOLTSETUP_TIME2_OFFSET) | + (OMAP3430_VOLTSETUP_TIME1 << + OMAP3430_VOLTSETUP_TIME1_OFFSET), + OMAP3430_GR_MOD, OMAP3_PRM_VOLTSETUP1_OFFSET); + + prm_write_mod_reg(OMAP3430_VOLTOFFSET_DURATION, OMAP3430_GR_MOD, + OMAP3_PRM_VOLTOFFSET_OFFSET); + prm_write_mod_reg(OMAP3430_VOLTSETUP2_DURATION, OMAP3430_GR_MOD, + OMAP3_PRM_VOLTSETUP2_OFFSET); #else - PRM_VOLTCTRL |= PRM_VOLTCTRL_AUTO_RET; + prm_set_mod_reg_bits(OMAP3430_AUTO_RET, OMAP3430_GR_MOD, + OMAP3_PRM_VOLTCTRL_OFFSET); #endif } - static void sr_configure(struct omap_sr *sr) { - u32 sys_clk, sr_clk_length = 0; u32 sr_config; u32 senp_en , senn_en; + if (sr->clk_length == 0) + sr_set_clk_length(sr); + senp_en = sr->senp_mod; senn_en = sr->senn_mod; - - sys_clk = prcm_get_system_clock_speed(); - - switch (sys_clk) { - case 12000: - sr_clk_length = SRCLKLENGTH_12MHZ_SYSCLK; - break; - case 13000: - sr_clk_length = SRCLKLENGTH_13MHZ_SYSCLK; - break; - case 19200: - sr_clk_length = SRCLKLENGTH_19MHZ_SYSCLK; - break; - case 26000: - sr_clk_length = SRCLKLENGTH_26MHZ_SYSCLK; - break; - case 38400: - sr_clk_length = SRCLKLENGTH_38MHZ_SYSCLK; - break; - default : - printk(KERN_ERR "Invalid sysclk value\n"); - break; - } - - DPRINTK(KERN_DEBUG "SR : sys clk %lu\n", sys_clk); if (sr->srid == SR1) { sr_config = SR1_SRCONFIG_ACCUMDATA | - (sr_clk_length << SRCONFIG_SRCLKLENGTH_SHIFT) | + (sr->clk_length << SRCONFIG_SRCLKLENGTH_SHIFT) | SRCONFIG_SENENABLE | SRCONFIG_ERRGEN_EN | SRCONFIG_MINMAXAVG_EN | (senn_en << SRCONFIG_SENNENABLE_SHIFT) | (senp_en << SRCONFIG_SENPENABLE_SHIFT) | SRCONFIG_DELAYCTRL; - + DPRINTK(KERN_DEBUG "setting SRCONFIG1 to 0x%08lx\n", + (unsigned long int) sr_config); sr_write_reg(sr, SRCONFIG, sr_config); sr_write_reg(sr, AVGWEIGHT, SR1_AVGWEIGHT_SENPAVGWEIGHT | @@ -408,18 +527,18 @@ static void sr_configure(struct omap_sr *sr) } else if (sr->srid == SR2) { sr_config = SR2_SRCONFIG_ACCUMDATA | - (sr_clk_length << SRCONFIG_SRCLKLENGTH_SHIFT) | + (sr->clk_length << SRCONFIG_SRCLKLENGTH_SHIFT) | SRCONFIG_SENENABLE | SRCONFIG_ERRGEN_EN | SRCONFIG_MINMAXAVG_EN | (senn_en << SRCONFIG_SENNENABLE_SHIFT) | (senp_en << SRCONFIG_SENPENABLE_SHIFT) | SRCONFIG_DELAYCTRL; + DPRINTK(KERN_DEBUG "setting SRCONFIG2 to 0x%08lx\n", + (unsigned long int) sr_config); sr_write_reg(sr, SRCONFIG, sr_config); - sr_write_reg(sr, AVGWEIGHT, SR2_AVGWEIGHT_SENPAVGWEIGHT | SR2_AVGWEIGHT_SENNAVGWEIGHT); - sr_modify_reg(sr, ERRCONFIG, (SR_ERRWEIGHT_MASK | SR_ERRMAXLIMIT_MASK | SR_ERRMINLIMIT_MASK), (SR2_ERRWEIGHT | SR2_ERRMAXLIMIT | SR2_ERRMINLIMIT)); @@ -428,9 +547,9 @@ static void sr_configure(struct omap_sr *sr) sr->is_sr_reset = 0; } -static void sr_enable(struct omap_sr *sr, u32 target_opp_no) +static int sr_enable(struct omap_sr *sr, u32 target_opp_no) { - u32 nvalue_reciprocal, current_nvalue; + u32 nvalue_reciprocal; sr->req_opp_no = target_opp_no; @@ -472,11 +591,10 @@ static void sr_enable(struct omap_sr *sr, u32 target_opp_no) } } - current_nvalue = sr_read_reg(sr, NVALUERECIPROCAL); - - if (current_nvalue == nvalue_reciprocal) { - DPRINTK("System is already at the desired voltage level\n"); - return; + if (nvalue_reciprocal == 0) { + printk(KERN_NOTICE "OPP%d doesn't support SmartReflex\n", + target_opp_no); + return SR_FALSE; } sr_write_reg(sr, NVALUERECIPROCAL, nvalue_reciprocal); @@ -485,18 +603,19 @@ static void sr_enable(struct omap_sr *sr, u32 target_opp_no) sr_modify_reg(sr, ERRCONFIG, (ERRCONFIG_VPBOUNDINTEN | ERRCONFIG_VPBOUNDINTST), (ERRCONFIG_VPBOUNDINTEN | ERRCONFIG_VPBOUNDINTST)); - if (sr->srid == SR1) { /* Enable VP1 */ - PRM_VP1_CONFIG |= PRM_VP1_CONFIG_VPENABLE; + prm_set_mod_reg_bits(PRM_VP1_CONFIG_VPENABLE, OMAP3430_GR_MOD, + OMAP3_PRM_VP1_CONFIG_OFFSET); } else if (sr->srid == SR2) { /* Enable VP2 */ - PRM_VP2_CONFIG |= PRM_VP2_CONFIG_VPENABLE; + prm_set_mod_reg_bits(PRM_VP2_CONFIG_VPENABLE, OMAP3430_GR_MOD, + OMAP3_PRM_VP2_CONFIG_OFFSET); } /* SRCONFIG - enable SR */ sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, SRCONFIG_SRENABLE); - + return SR_TRUE; } static void sr_disable(struct omap_sr *sr) @@ -507,11 +626,13 @@ static void sr_disable(struct omap_sr *sr) sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, ~SRCONFIG_SRENABLE); if (sr->srid == SR1) { - /* Enable VP1 */ - PRM_VP1_CONFIG &= ~PRM_VP1_CONFIG_VPENABLE; + /* Disable VP1 */ + prm_clear_mod_reg_bits(PRM_VP1_CONFIG_VPENABLE, OMAP3430_GR_MOD, + OMAP3_PRM_VP1_CONFIG_OFFSET); } else if (sr->srid == SR2) { - /* Enable VP2 */ - PRM_VP2_CONFIG &= ~PRM_VP2_CONFIG_VPENABLE; + /* Disable VP2 */ + prm_clear_mod_reg_bits(PRM_VP2_CONFIG_VPENABLE, OMAP3430_GR_MOD, + OMAP3_PRM_VP2_CONFIG_OFFSET); } } @@ -535,7 +656,12 @@ void sr_start_vddautocomap(int srid, u32 target_opp_no) srid); sr->is_autocomp_active = 1; - sr_enable(sr, target_opp_no); + if (!sr_enable(sr, target_opp_no)) { + printk(KERN_WARNING "SR%d: VDD autocomp not activated\n", srid); + sr->is_autocomp_active = 0; + if (sr->is_sr_reset == 1) + sr_clk_disable(sr); + } } EXPORT_SYMBOL(sr_start_vddautocomap); @@ -574,20 +700,18 @@ void enable_smartreflex(int srid) if (sr->is_autocomp_active == 1) { if (sr->is_sr_reset == 1) { - if (srid == SR1) { - /* Enable SR clks */ - CM_FCLKEN_WKUP |= SR1_CLK_ENABLE; - target_opp_no = get_opp_no(current_vdd1_opp); + /* Enable SR clks */ + sr_clk_enable(sr); - } else if (srid == SR2) { - /* Enable SR clks */ - CM_FCLKEN_WKUP |= SR2_CLK_ENABLE; + if (srid == SR1) + target_opp_no = get_opp_no(current_vdd1_opp); + else if (srid == SR2) target_opp_no = get_opp_no(current_vdd2_opp); - } sr_configure(sr); - sr_enable(sr, target_opp_no); + if (!sr_enable(sr, target_opp_no)) + sr_clk_disable(sr); } } } @@ -602,15 +726,6 @@ void disable_smartreflex(int srid) sr = &sr2; if (sr->is_autocomp_active == 1) { - if (srid == SR1) { - /* Enable SR clk */ - CM_FCLKEN_WKUP |= SR1_CLK_ENABLE; - - } else if (srid == SR2) { - /* Enable SR clk */ - CM_FCLKEN_WKUP |= SR2_CLK_ENABLE; - } - if (sr->is_sr_reset == 0) { sr->is_sr_reset = 1; @@ -618,17 +733,18 @@ void disable_smartreflex(int srid) sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, ~SRCONFIG_SRENABLE); + /* Disable SR clk */ + sr_clk_disable(sr); if (sr->srid == SR1) { - /* Disable SR clk */ - CM_FCLKEN_WKUP &= ~SR1_CLK_ENABLE; - /* Enable VP1 */ - PRM_VP1_CONFIG &= ~PRM_VP1_CONFIG_VPENABLE; - + /* Disable VP1 */ + prm_clear_mod_reg_bits(PRM_VP1_CONFIG_VPENABLE, + OMAP3430_GR_MOD, + OMAP3_PRM_VP1_CONFIG_OFFSET); } else if (sr->srid == SR2) { - /* Disable SR clk */ - CM_FCLKEN_WKUP &= ~SR2_CLK_ENABLE; - /* Enable VP2 */ - PRM_VP2_CONFIG &= ~PRM_VP2_CONFIG_VPENABLE; + /* Disable VP2 */ + prm_clear_mod_reg_bits(PRM_VP2_CONFIG_VPENABLE, + OMAP3430_GR_MOD, + OMAP3_PRM_VP2_CONFIG_OFFSET); } } } @@ -638,7 +754,6 @@ void disable_smartreflex(int srid) /* Voltage Scaling using SR VCBYPASS */ int sr_voltagescale_vcbypass(u32 target_opp, u8 vsel) { - int ret; int sr_status = 0; u32 vdd, target_opp_no; u32 vc_bypass_value; @@ -651,39 +766,53 @@ int sr_voltagescale_vcbypass(u32 target_opp, u8 vsel) if (vdd == PRCM_VDD1) { sr_status = sr_stop_vddautocomap(SR1); - PRM_VC_CMD_VAL_0 = (PRM_VC_CMD_VAL_0 & ~PRM_VC_CMD_ON_MASK) | - (vsel << PRM_VC_CMD_ON_SHIFT); + prm_rmw_mod_reg_bits(OMAP3430_VC_CMD_ON_MASK, + (vsel << OMAP3430_VC_CMD_ON_SHIFT), + OMAP3430_GR_MOD, + OMAP3_PRM_VC_CMD_VAL_0_OFFSET); reg_addr = R_VDD1_SR_CONTROL; } else if (vdd == PRCM_VDD2) { sr_status = sr_stop_vddautocomap(SR2); - PRM_VC_CMD_VAL_1 = (PRM_VC_CMD_VAL_1 & ~PRM_VC_CMD_ON_MASK) | - (vsel << PRM_VC_CMD_ON_SHIFT); + prm_rmw_mod_reg_bits(OMAP3430_VC_CMD_ON_MASK, + (vsel << OMAP3430_VC_CMD_ON_SHIFT), + OMAP3430_GR_MOD, + OMAP3_PRM_VC_CMD_VAL_1_OFFSET); reg_addr = R_VDD2_SR_CONTROL; } - vc_bypass_value = (vsel << PRM_VC_BYPASS_DATA_SHIFT) | - (reg_addr << PRM_VC_BYPASS_REGADDR_SHIFT) | - (R_SRI2C_SLAVE_ADDR << PRM_VC_BYPASS_SLAVEADDR_SHIFT); + vc_bypass_value = (vsel << OMAP3430_DATA_SHIFT) | + (reg_addr << OMAP3430_REGADDR_SHIFT) | + (R_SRI2C_SLAVE_ADDR << OMAP3430_SLAVEADDR_SHIFT); - PRM_VC_BYPASS_VAL = vc_bypass_value; + prm_write_mod_reg(vc_bypass_value, OMAP3430_GR_MOD, + OMAP3_PRM_VC_BYPASS_VAL_OFFSET); - PRM_VC_BYPASS_VAL |= PRM_VC_BYPASS_VALID; + vc_bypass_value = prm_set_mod_reg_bits(OMAP3430_VALID, OMAP3430_GR_MOD, + OMAP3_PRM_VC_BYPASS_VAL_OFFSET); - DPRINTK("%s : PRM_VC_BYPASS_VAL %X\n", __func__, PRM_VC_BYPASS_VAL); - DPRINTK("PRM_IRQST_MPU %X\n", PRM_IRQSTATUS_MPU); + DPRINTK("%s : PRM_VC_BYPASS_VAL %X\n", __func__, vc_bypass_value); + DPRINTK("PRM_IRQST_MPU %X\n", prm_read_mod_reg(OCP_MOD, + OMAP3_PRM_IRQSTATUS_MPU_OFFSET)); - while ((PRM_VC_BYPASS_VAL & PRM_VC_BYPASS_VALID) != 0x0) { - ret = loop_wait(&loop_cnt, &retries_cnt, 10); - if (ret != PRCM_PASS) { + while ((vc_bypass_value & OMAP3430_VALID) != 0x0) { + loop_cnt++; + if (retries_cnt > 10) { printk(KERN_INFO "Loop count exceeded in check SR I2C" "write\n"); - return ret; + return SR_FAIL; + } + if (loop_cnt > 50) { + retries_cnt++; + loop_cnt = 0; + udelay(10); } + vc_bypass_value = prm_read_mod_reg(OMAP3430_GR_MOD, + OMAP3_PRM_VC_BYPASS_VAL_OFFSET); } - omap_udelay(T2_SMPS_UPDATE_DELAY); + udelay(T2_SMPS_UPDATE_DELAY); if (sr_status) { if (vdd == PRCM_VDD1) @@ -696,13 +825,15 @@ int sr_voltagescale_vcbypass(u32 target_opp, u8 vsel) } /* Sysfs interface to select SR VDD1 auto compensation */ -static ssize_t omap_sr_vdd1_autocomp_show(struct kset *subsys, char *buf) +static ssize_t omap_sr_vdd1_autocomp_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) { return sprintf(buf, "%d\n", sr1.is_autocomp_active); } -static ssize_t omap_sr_vdd1_autocomp_store(struct kset *subsys, - const char *buf, size_t n) +static ssize_t omap_sr_vdd1_autocomp_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t n) { u32 current_vdd1opp_no; unsigned short value; @@ -722,7 +853,7 @@ static ssize_t omap_sr_vdd1_autocomp_store(struct kset *subsys, return n; } -static struct subsys_attribute sr_vdd1_autocomp = { +static struct kobj_attribute sr_vdd1_autocomp = { .attr = { .name = __stringify(sr_vdd1_autocomp), .mode = 0644, @@ -732,13 +863,15 @@ static struct subsys_attribute sr_vdd1_autocomp = { }; /* Sysfs interface to select SR VDD2 auto compensation */ -static ssize_t omap_sr_vdd2_autocomp_show(struct kset *subsys, char *buf) +static ssize_t omap_sr_vdd2_autocomp_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) { return sprintf(buf, "%d\n", sr2.is_autocomp_active); } -static ssize_t omap_sr_vdd2_autocomp_store(struct kset *subsys, - const char *buf, size_t n) +static ssize_t omap_sr_vdd2_autocomp_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t n) { u32 current_vdd2opp_no; unsigned short value; @@ -758,7 +891,7 @@ static ssize_t omap_sr_vdd2_autocomp_store(struct kset *subsys, return n; } -static struct subsys_attribute sr_vdd2_autocomp = { +static struct kobj_attribute sr_vdd2_autocomp = { .attr = { .name = __stringify(sr_vdd2_autocomp), .mode = 0644, @@ -774,15 +907,19 @@ static int __init omap3_sr_init(void) int ret = 0; u8 RdReg; -#ifdef CONFIG_ARCH_OMAP34XX - sr1.fck = clk_get(NULL, "sr1_fck"); - if (IS_ERR(sr1.fck)) - printk(KERN_ERR "Could not get sr1_fck\n"); - - sr2.fck = clk_get(NULL, "sr2_fck"); - if (IS_ERR(sr2.fck)) - printk(KERN_ERR "Could not get sr2_fck\n"); -#endif /* #ifdef CONFIG_ARCH_OMAP34XX */ + if (is_sil_rev_greater_than(OMAP3430_REV_ES1_0)) { + current_vdd1_opp = PRCM_VDD1_OPP3; + current_vdd2_opp = PRCM_VDD2_OPP3; + } else { + current_vdd1_opp = PRCM_VDD1_OPP1; + current_vdd2_opp = PRCM_VDD1_OPP1; + } + if (cpu_is_omap34xx()) { + sr_clk_get(&sr1); + sr_clk_get(&sr2); + } + sr_set_clk_length(&sr1); + sr_set_clk_length(&sr2); /* Call the VPConfig, VCConfig, set N Values. */ sr_set_nvalues(&sr1); @@ -794,22 +931,24 @@ static int __init omap3_sr_init(void) sr_configure_vc(); /* Enable SR on T2 */ - ret = t2_in(PM_RECEIVER, &RdReg, R_DCDC_GLOBAL_CFG); - RdReg |= DCDC_GLOBAL_CFG_ENABLE_SRFLX; - ret |= t2_out(PM_RECEIVER, RdReg, R_DCDC_GLOBAL_CFG); + ret = twl4030_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &RdReg, + R_DCDC_GLOBAL_CFG); + RdReg |= DCDC_GLOBAL_CFG_ENABLE_SRFLX; + ret |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, RdReg, + R_DCDC_GLOBAL_CFG); printk(KERN_INFO "SmartReflex driver initialized\n"); - ret = subsys_create_file(&power_subsys, &sr_vdd1_autocomp); + ret = sysfs_create_file(power_kobj, &sr_vdd1_autocomp.attr); if (ret) - printk(KERN_ERR "subsys_create_file failed: %d\n", ret); + printk(KERN_ERR "sysfs_create_file failed: %d\n", ret); - ret = subsys_create_file(&power_subsys, &sr_vdd2_autocomp); + ret = sysfs_create_file(power_kobj, &sr_vdd2_autocomp.attr); if (ret) - printk(KERN_ERR "subsys_create_file failed: %d\n", ret); + printk(KERN_ERR "sysfs_create_file failed: %d\n", ret); return 0; } -arch_initcall(omap3_sr_init); +late_initcall(omap3_sr_init); diff --git a/arch/arm/mach-omap2/smartreflex.h b/arch/arm/mach-omap2/smartreflex.h index 2091a15..194429e 100644 --- a/arch/arm/mach-omap2/smartreflex.h +++ b/arch/arm/mach-omap2/smartreflex.h @@ -233,12 +233,18 @@ extern u32 current_vdd1_opp; extern u32 current_vdd2_opp; +#ifdef CONFIG_OMAP_SMARTREFLEX_TESTING +#define SR_TESTING_NVALUES 1 +#else +#define SR_TESTING_NVALUES 0 +#endif + /* * Smartreflex module enable/disable interface. * NOTE: if smartreflex is not enabled from sysfs, these functions will not * do anything. */ -#if defined(CONFIG_ARCH_OMAP34XX) && defined(CONFIG_TWL4030_CORE) +#ifdef CONFIG_OMAP_SMARTREFLEX void enable_smartreflex(int srid); void disable_smartreflex(int srid); #else @@ -246,7 +252,6 @@ static inline void enable_smartreflex(int srid) {} static inline void disable_smartreflex(int srid) {} #endif - #endif diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig index b085b07..960c13f 100644 --- a/arch/arm/plat-omap/Kconfig +++ b/arch/arm/plat-omap/Kconfig @@ -56,6 +56,37 @@ config OMAP_DEBUG_CLOCKDOMAIN for every clockdomain register write. However, the extra detail costs some memory. +config OMAP_SMARTREFLEX + bool "SmartReflex support" + depends on ARCH_OMAP34XX && TWL4030_CORE + help + Say Y if you want to enable SmartReflex. + + SmartReflex can perform continuous dynamic voltage + scaling around the nominal operating point voltage + according to silicon characteristics and operating + conditions. Enabling SmartReflex reduces power + consumption. + + Please note, that by default SmartReflex is only + initialized. To enable the automatic voltage + compensation for VDD1 and VDD2, user must write 1 to + /sys/power/sr_vddX_autocomp, where X is 1 or 2. + +config OMAP_SMARTREFLEX_TESTING + bool "Smartreflex testing support" + depends on OMAP_SMARTREFLEX + default n + help + Say Y if you want to enable SmartReflex testing with SW hardcoded + NVALUES intead of E-fuse NVALUES set in factory silicon testing. + + In some devices the E-fuse values have not been set, even though + SmartReflex modules are included. Using these hardcoded values set + in software, one can test the SmartReflex features without E-fuse. + + WARNING: Enabling this option may cause your device to hang! + config OMAP_RESET_CLOCKS bool "Reset unused clocks during boot" depends on ARCH_OMAP -- 1.5.4.3