* [PATCH 0/2 v3] OMAP3: PM: refactor Smart Reflex [not found] <OMAP3:PM:SR: SmartReflex Refactor Rev3.0> @ 2009-10-24 5:15 ` Nishanth Menon 2009-10-24 5:15 ` [PATCH 1/2 v3] OMAP3: PM: SR: prepare: remove old SR code Nishanth Menon 0 siblings, 1 reply; 16+ messages in thread From: Nishanth Menon @ 2009-10-24 5:15 UTC (permalink / raw) To: "linux-omap <linux-omap" Cc: Imberton Guilhem, Mike Chan, Rajendra Nayak, Roger Quadros, Kalle Jokiniemi, Teerth Reddy, Kevin Hilman, Paul Walmsley, Hogander Jouni, Nishanth Menon Hi, Based on linux-omap PM branch(kevin's tree) commit 25c7b64bf80176463aa741407318e0e6b21cfd71 V4 - More changes: * Guilhem's review comments for timeout return value * Changes to make sr_list and OPP table dynamic selection based on cpu_type * vsel dbgfs entry added for folks who like to see voltage decisions made by OMAP Voltage processor (e.g. without a scope) * nvalue_opp is a variable array * omapsr_list introduced, initialized runtime based on type of omap - currently omap3430 only- but makes 3630 possible * all opp searches are isolated to opp accessor functions V3 - Bunch of changes: * Introduce debugfs entries for SR - since these are variable updates, you can essentially do what we do with test values, change things but without a rebuild! * Removed the test values altogether * srid is standardised to u8 and it is not a bit field * Guilhem's changes for non-twl5030 PMIC incorporated * uses ioremap V2 - made possible to work with non twl5030 PMICs V1 - original rewrite Requesting as much testing as possible and all comments welcome. Nishanth Menon (2): OMAP3: PM: SR: prepare: remove old SR code OMAP3: PM: SR: SmartReflex Refactor Rev4.0 arch/arm/mach-omap2/pm-debug.c | 3 + arch/arm/mach-omap2/resource34xx.c | 8 +- arch/arm/mach-omap2/smartreflex.c | 2180 +++++++++++++++++++++++------------- arch/arm/mach-omap2/smartreflex.h | 280 +++--- arch/arm/plat-omap/Kconfig | 15 +- 5 files changed, 1544 insertions(+), 942 deletions(-) Regards, Nishanth Menon ^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH 1/2 v3] OMAP3: PM: SR: prepare: remove old SR code 2009-10-24 5:15 ` [PATCH 0/2 v3] OMAP3: PM: refactor Smart Reflex Nishanth Menon @ 2009-10-24 5:15 ` Nishanth Menon 2009-10-24 5:15 ` [PATCH 2/2 v3] OMAP3: PM: SR: SmartReflex Refactor Rev4.0 Nishanth Menon 0 siblings, 1 reply; 16+ messages in thread From: Nishanth Menon @ 2009-10-24 5:15 UTC (permalink / raw) To: "linux-omap <linux-omap" Cc: Imberton Guilhem, Mike Chan, Rajendra Nayak, Roger Quadros, Kalle Jokiniemi, Teerth Reddy, Kevin Hilman, Paul Walmsley, Hogander Jouni, Nishanth Menon Preparation: remove original smart reflex code base. This prevents the refactor appearing as a confusing diff and hindering patch review process. Signed-off-by: Nishanth Menon <nm@ti.com> Cc: Rajendra Nayak <rnayak@ti.com> Cc: Roger Quadros <ext-roger.quadros@nokia.com> Cc: Kalle Jokiniemi <ext-kalle.jokiniemi@nokia.com> Cc: Teerth Reddy <teerth@ti.com> Cc: Kevin Hilman <khilman@deeprootsystems.com> Cc: Paul Walmsley <paul@pwsan.com> Cc: Högander Jouni <jouni.hogander@nokia.com> Cc: Imberton Guilhem <guilhem.imberton@motorola.com> Cc: Mike Chan <mikechan@google.com> --- arch/arm/mach-omap2/smartreflex.c | 1024 ------------------------------------- arch/arm/mach-omap2/smartreflex.h | 256 --------- 2 files changed, 0 insertions(+), 1280 deletions(-) delete mode 100644 arch/arm/mach-omap2/smartreflex.c delete mode 100644 arch/arm/mach-omap2/smartreflex.h diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c deleted file mode 100644 index be3a1da..0000000 --- a/arch/arm/mach-omap2/smartreflex.c +++ /dev/null @@ -1,1024 +0,0 @@ -/* - * linux/arch/arm/mach-omap3/smartreflex.c - * - * OMAP34XX SmartReflex Voltage Control - * - * Copyright (C) 2008 Nokia Corporation - * Kalle Jokiniemi - * - * Copyright (C) 2007 Texas Instruments, Inc. - * Lesly A M <x0080970@ti.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - - -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/module.h> -#include <linux/delay.h> -#include <linux/err.h> -#include <linux/clk.h> -#include <linux/sysfs.h> -#include <linux/kobject.h> -#include <linux/i2c/twl4030.h> -#include <linux/io.h> - -#include <plat/omap34xx.h> -#include <plat/control.h> -#include <plat/clock.h> -#include <plat/omap-pm.h> - -#include "prm.h" -#include "smartreflex.h" -#include "prm-regbits-34xx.h" - -#define MAX_TRIES 100 - -struct omap_sr { - int srid; - int is_sr_reset; - int is_autocomp_active; - struct clk *clk; - struct clk *vdd_opp_clk; - u32 clk_length; - u32 req_opp_no; - u32 opp1_nvalue, opp2_nvalue, opp3_nvalue, opp4_nvalue; - u32 opp5_nvalue; - u32 senp_mod, senn_mod; - void __iomem *srbase_addr; - void __iomem *vpbase_addr; -}; - -#define SR_REGADDR(offs) (sr->srbase_addr + offset) - -static inline void sr_write_reg(struct omap_sr *sr, unsigned offset, u32 value) -{ - __raw_writel(value, SR_REGADDR(offset)); -} - -static inline void sr_modify_reg(struct omap_sr *sr, unsigned offset, u32 mask, - u32 value) -{ - u32 reg_val; - - reg_val = __raw_readl(SR_REGADDR(offset)); - reg_val &= ~mask; - reg_val |= value; - - __raw_writel(reg_val, SR_REGADDR(offset)); -} - -static inline u32 sr_read_reg(struct omap_sr *sr, unsigned offset) -{ - return __raw_readl(SR_REGADDR(offset)); -} - -static int sr_clk_enable(struct omap_sr *sr) -{ - if (clk_enable(sr->clk) != 0) { - pr_err("Could not enable %s\n", sr->clk->name); - return -1; - } - - /* set fclk- active , iclk- idle */ - sr_modify_reg(sr, ERRCONFIG, SR_CLKACTIVITY_MASK, - SR_CLKACTIVITY_IOFF_FON); - - return 0; -} - -static void sr_clk_disable(struct omap_sr *sr) -{ - /* set fclk, iclk- idle */ - sr_modify_reg(sr, ERRCONFIG, SR_CLKACTIVITY_MASK, - SR_CLKACTIVITY_IOFF_FOFF); - - clk_disable(sr->clk); - sr->is_sr_reset = 1; -} - -static struct omap_sr sr1 = { - .srid = SR1, - .is_sr_reset = 1, - .is_autocomp_active = 0, - .clk_length = 0, - .srbase_addr = OMAP2_L4_IO_ADDRESS(OMAP34XX_SR1_BASE), -}; - -static struct omap_sr sr2 = { - .srid = SR2, - .is_sr_reset = 1, - .is_autocomp_active = 0, - .clk_length = 0, - .srbase_addr = OMAP2_L4_IO_ADDRESS(OMAP34XX_SR2_BASE), -}; - -static void cal_reciprocal(u32 sensor, u32 *sengain, u32 *rnsen) -{ - u32 gn, rn, mul; - - for (gn = 0; gn < GAIN_MAXLIMIT; gn++) { - mul = 1 << (gn + 8); - rn = mul / sensor; - if (rn < R_MAXLIMIT) { - *sengain = gn; - *rnsen = rn; - } - } -} - -static u32 cal_test_nvalue(u32 sennval, u32 senpval) -{ - u32 senpgain, senngain; - u32 rnsenp, rnsenn; - - /* Calculating the gain and reciprocal of the SenN and SenP values */ - cal_reciprocal(senpval, &senpgain, &rnsenp); - cal_reciprocal(sennval, &senngain, &rnsenn); - - return (senpgain << NVALUERECIPROCAL_SENPGAIN_SHIFT) | - (senngain << NVALUERECIPROCAL_SENNGAIN_SHIFT) | - (rnsenp << NVALUERECIPROCAL_RNSENP_SHIFT) | - (rnsenn << NVALUERECIPROCAL_RNSENN_SHIFT); -} - -/* determine the current OPP from the frequency - * we need to give this function last element of OPP rate table - * and the frequency - */ -static u16 get_opp(struct omap_opp *opp_freq_table, - unsigned long freq) -{ - struct omap_opp *prcm_config; - - prcm_config = opp_freq_table; - - if (prcm_config->rate <= freq) - return prcm_config->opp_id; /* Return the Highest OPP */ - for (; prcm_config->rate; prcm_config--) - if (prcm_config->rate < freq) - return (prcm_config+1)->opp_id; - else if (prcm_config->rate == freq) - return prcm_config->opp_id; - /* Return the least OPP */ - return (prcm_config+1)->opp_id; -} - -static u16 get_vdd1_opp(void) -{ - u16 opp; - - if (sr1.vdd_opp_clk == NULL || IS_ERR(sr1.vdd_opp_clk) || - mpu_opps == NULL) - return 0; - - opp = get_opp(mpu_opps + MAX_VDD1_OPP, sr1.vdd_opp_clk->rate); - return opp; -} - -static u16 get_vdd2_opp(void) -{ - u16 opp; - - if (sr2.vdd_opp_clk == NULL || IS_ERR(sr2.vdd_opp_clk) || - l3_opps == NULL) - return 0; - - opp = get_opp(l3_opps + MAX_VDD2_OPP, sr2.vdd_opp_clk->rate); - return opp; -} - - -static void sr_set_clk_length(struct omap_sr *sr) -{ - struct clk *sys_ck; - u32 sys_clk_speed; - - sys_ck = clk_get(NULL, "sys_ck"); - sys_clk_speed = clk_get_rate(sys_ck); - clk_put(sys_ck); - - switch (sys_clk_speed) { - 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: - pr_err("Invalid sysclk value: %d\n", sys_clk_speed); - 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) -{ - if (sr->srid == SR1) { - sr->senp_mod = 0x03; /* SenN-M5 enabled */ - sr->senn_mod = 0x03; - - /* calculate nvalues for each opp */ - sr->opp5_nvalue = cal_test_nvalue(0xacd + 0x330, 0x848 + 0x330); - sr->opp4_nvalue = cal_test_nvalue(0x964 + 0x2a0, 0x727 + 0x2a0); - sr->opp3_nvalue = cal_test_nvalue(0x85b + 0x200, 0x655 + 0x200); - sr->opp2_nvalue = cal_test_nvalue(0x506 + 0x1a0, 0x3be + 0x1a0); - sr->opp1_nvalue = cal_test_nvalue(0x373 + 0x100, 0x28c + 0x100); - } else if (sr->srid == SR2) { - sr->senp_mod = 0x03; - sr->senn_mod = 0x03; - - sr->opp3_nvalue = cal_test_nvalue(0x76f + 0x200, 0x579 + 0x200); - sr->opp2_nvalue = cal_test_nvalue(0x4f5 + 0x1c0, 0x390 + 0x1c0); - sr->opp1_nvalue = cal_test_nvalue(0x359, 0x25d); - } - -} - -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; - u32 vsel; - u32 target_opp_no; - - if (srid == SR1) { - target_opp_no = get_vdd1_opp(); - if (!target_opp_no) - /* Assume Nominal OPP as current OPP unknown */ - vsel = mpu_opps[VDD1_OPP3].vsel; - else - vsel = mpu_opps[target_opp_no].vsel; - - vpconfig = PRM_VP1_CONFIG_ERROROFFSET | - PRM_VP1_CONFIG_ERRORGAIN | - PRM_VP1_CONFIG_TIMEOUTEN | - vsel << OMAP3430_INITVOLTAGE_SHIFT; - - 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); - - /* Force update of voltage */ - prm_set_mod_reg_bits(OMAP3430_FORCEUPDATE, OMAP3430_GR_MOD, - OMAP3_PRM_VP1_CONFIG_OFFSET); - /* Clear force bit */ - prm_clear_mod_reg_bits(OMAP3430_FORCEUPDATE, OMAP3430_GR_MOD, - OMAP3_PRM_VP1_CONFIG_OFFSET); - - } else if (srid == SR2) { - target_opp_no = get_vdd2_opp(); - if (!target_opp_no) - /* Assume Nominal OPP */ - vsel = l3_opps[VDD2_OPP3].vsel; - else - vsel = l3_opps[target_opp_no].vsel; - - vpconfig = PRM_VP2_CONFIG_ERROROFFSET | - PRM_VP2_CONFIG_ERRORGAIN | - PRM_VP2_CONFIG_TIMEOUTEN | - vsel << OMAP3430_INITVOLTAGE_SHIFT; - - 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_VP1_CONFIG_INITVDD, OMAP3430_GR_MOD, - OMAP3_PRM_VP2_CONFIG_OFFSET); - - /* Clear initVDD copy trigger bit */ - prm_clear_mod_reg_bits(PRM_VP1_CONFIG_INITVDD, OMAP3430_GR_MOD, - OMAP3_PRM_VP2_CONFIG_OFFSET); - - /* Force update of voltage */ - prm_set_mod_reg_bits(OMAP3430_FORCEUPDATE, OMAP3430_GR_MOD, - OMAP3_PRM_VP2_CONFIG_OFFSET); - /* Clear force bit */ - prm_clear_mod_reg_bits(OMAP3430_FORCEUPDATE, OMAP3430_GR_MOD, - OMAP3_PRM_VP2_CONFIG_OFFSET); - - } -} - -static void sr_configure(struct omap_sr *sr) -{ - 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; - if (sr->srid == SR1) { - sr_config = SR1_SRCONFIG_ACCUMDATA | - (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; - - sr_write_reg(sr, SRCONFIG, sr_config); - sr_write_reg(sr, AVGWEIGHT, SR1_AVGWEIGHT_SENPAVGWEIGHT | - SR1_AVGWEIGHT_SENNAVGWEIGHT); - - sr_modify_reg(sr, ERRCONFIG, (SR_ERRWEIGHT_MASK | - SR_ERRMAXLIMIT_MASK | SR_ERRMINLIMIT_MASK), - (SR1_ERRWEIGHT | SR1_ERRMAXLIMIT | SR1_ERRMINLIMIT)); - - } else if (sr->srid == SR2) { - sr_config = SR2_SRCONFIG_ACCUMDATA | - (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; - - 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)); - - } - sr->is_sr_reset = 0; -} - -static int sr_reset_voltage(int srid) -{ - u32 target_opp_no, vsel = 0; - u32 reg_addr = 0; - u32 loop_cnt = 0, retries_cnt = 0; - u32 vc_bypass_value; - u32 t2_smps_steps = 0; - u32 t2_smps_delay = 0; - u32 prm_vp1_voltage, prm_vp2_voltage; - - if (srid == SR1) { - target_opp_no = get_vdd1_opp(); - if (!target_opp_no) { - pr_info("Current OPP unknown: Cannot reset voltage\n"); - return 1; - } - vsel = mpu_opps[target_opp_no].vsel; - reg_addr = R_VDD1_SR_CONTROL; - prm_vp1_voltage = prm_read_mod_reg(OMAP3430_GR_MOD, - OMAP3_PRM_VP1_VOLTAGE_OFFSET); - t2_smps_steps = abs(vsel - prm_vp1_voltage); - } else if (srid == SR2) { - target_opp_no = get_vdd2_opp(); - if (!target_opp_no) { - pr_info("Current OPP unknown: Cannot reset voltage\n"); - return 1; - } - vsel = l3_opps[target_opp_no].vsel; - reg_addr = R_VDD2_SR_CONTROL; - prm_vp2_voltage = prm_read_mod_reg(OMAP3430_GR_MOD, - OMAP3_PRM_VP2_VOLTAGE_OFFSET); - t2_smps_steps = abs(vsel - prm_vp2_voltage); - } - - vc_bypass_value = (vsel << OMAP3430_DATA_SHIFT) | - (reg_addr << OMAP3430_REGADDR_SHIFT) | - (R_SRI2C_SLAVE_ADDR << OMAP3430_SLAVEADDR_SHIFT); - - prm_write_mod_reg(vc_bypass_value, OMAP3430_GR_MOD, - OMAP3_PRM_VC_BYPASS_VAL_OFFSET); - - vc_bypass_value = prm_set_mod_reg_bits(OMAP3430_VALID, OMAP3430_GR_MOD, - OMAP3_PRM_VC_BYPASS_VAL_OFFSET); - - while ((vc_bypass_value & OMAP3430_VALID) != 0x0) { - loop_cnt++; - if (retries_cnt > 10) { - pr_info("Loop count exceeded in check SR I2C" - "write\n"); - return 1; - } - 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); - } - - /* - * T2 SMPS slew rate (min) 4mV/uS, step size 12.5mV, - * 2us added as buffer. - */ - t2_smps_delay = ((t2_smps_steps * 125) / 40) + 2; - udelay(t2_smps_delay); - - return 0; -} - -static int sr_enable(struct omap_sr *sr, u32 target_opp_no) -{ - u32 nvalue_reciprocal, v; - - if (!(mpu_opps && l3_opps)) { - pr_notice("VSEL values not found\n"); - return false; - } - - sr->req_opp_no = target_opp_no; - - if (sr->srid == SR1) { - switch (target_opp_no) { - case 5: - nvalue_reciprocal = sr->opp5_nvalue; - break; - case 4: - nvalue_reciprocal = sr->opp4_nvalue; - break; - case 3: - nvalue_reciprocal = sr->opp3_nvalue; - break; - case 2: - nvalue_reciprocal = sr->opp2_nvalue; - break; - case 1: - nvalue_reciprocal = sr->opp1_nvalue; - break; - default: - nvalue_reciprocal = sr->opp3_nvalue; - break; - } - } else { - switch (target_opp_no) { - case 3: - nvalue_reciprocal = sr->opp3_nvalue; - break; - case 2: - nvalue_reciprocal = sr->opp2_nvalue; - break; - case 1: - nvalue_reciprocal = sr->opp1_nvalue; - break; - default: - nvalue_reciprocal = sr->opp3_nvalue; - break; - } - } - - if (nvalue_reciprocal == 0) { - pr_notice("OPP%d doesn't support SmartReflex\n", - target_opp_no); - return false; - } - - sr_write_reg(sr, NVALUERECIPROCAL, nvalue_reciprocal); - - /* Enable the interrupt */ - sr_modify_reg(sr, ERRCONFIG, - (ERRCONFIG_VPBOUNDINTEN | ERRCONFIG_VPBOUNDINTST), - (ERRCONFIG_VPBOUNDINTEN | ERRCONFIG_VPBOUNDINTST)); - - if (sr->srid == SR1) { - /* set/latch init voltage */ - v = prm_read_mod_reg(OMAP3430_GR_MOD, - OMAP3_PRM_VP1_CONFIG_OFFSET); - v &= ~(OMAP3430_INITVOLTAGE_MASK | OMAP3430_INITVDD); - v |= mpu_opps[target_opp_no].vsel << - OMAP3430_INITVOLTAGE_SHIFT; - prm_write_mod_reg(v, OMAP3430_GR_MOD, - OMAP3_PRM_VP1_CONFIG_OFFSET); - /* write1 to latch */ - prm_set_mod_reg_bits(OMAP3430_INITVDD, OMAP3430_GR_MOD, - OMAP3_PRM_VP1_CONFIG_OFFSET); - /* write2 clear */ - prm_clear_mod_reg_bits(OMAP3430_INITVDD, OMAP3430_GR_MOD, - OMAP3_PRM_VP1_CONFIG_OFFSET); - /* Enable VP1 */ - prm_set_mod_reg_bits(PRM_VP1_CONFIG_VPENABLE, OMAP3430_GR_MOD, - OMAP3_PRM_VP1_CONFIG_OFFSET); - } else if (sr->srid == SR2) { - /* set/latch init voltage */ - v = prm_read_mod_reg(OMAP3430_GR_MOD, - OMAP3_PRM_VP2_CONFIG_OFFSET); - v &= ~(OMAP3430_INITVOLTAGE_MASK | OMAP3430_INITVDD); - v |= l3_opps[target_opp_no].vsel << - OMAP3430_INITVOLTAGE_SHIFT; - prm_write_mod_reg(v, OMAP3430_GR_MOD, - OMAP3_PRM_VP2_CONFIG_OFFSET); - /* write1 to latch */ - prm_set_mod_reg_bits(OMAP3430_INITVDD, OMAP3430_GR_MOD, - OMAP3_PRM_VP2_CONFIG_OFFSET); - /* write2 clear */ - prm_clear_mod_reg_bits(OMAP3430_INITVDD, OMAP3430_GR_MOD, - OMAP3_PRM_VP2_CONFIG_OFFSET); - /* Enable VP2 */ - 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 true; -} - -static void sr_disable(struct omap_sr *sr) -{ - u32 i = 0; - - sr->is_sr_reset = 1; - - /* SRCONFIG - disable SR */ - sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, ~SRCONFIG_SRENABLE); - - if (sr->srid == SR1) { - /* Wait for VP idle before disabling VP */ - while ((!prm_read_mod_reg(OMAP3430_GR_MOD, - OMAP3_PRM_VP1_STATUS_OFFSET)) - && i++ < MAX_TRIES) - udelay(1); - - if (i >= MAX_TRIES) - pr_warning("VP1 not idle, still going ahead with \ - VP1 disable\n"); - - /* Disable VP1 */ - prm_clear_mod_reg_bits(PRM_VP1_CONFIG_VPENABLE, OMAP3430_GR_MOD, - OMAP3_PRM_VP1_CONFIG_OFFSET); - - } else if (sr->srid == SR2) { - /* Wait for VP idle before disabling VP */ - while ((!prm_read_mod_reg(OMAP3430_GR_MOD, - OMAP3_PRM_VP2_STATUS_OFFSET)) - && i++ < MAX_TRIES) - udelay(1); - - if (i >= MAX_TRIES) - pr_warning("VP2 not idle, still going ahead with \ - VP2 disable\n"); - - /* Disable VP2 */ - prm_clear_mod_reg_bits(PRM_VP2_CONFIG_VPENABLE, OMAP3430_GR_MOD, - OMAP3_PRM_VP2_CONFIG_OFFSET); - } -} - - -void sr_start_vddautocomap(int srid, u32 target_opp_no) -{ - struct omap_sr *sr = NULL; - - if (srid == SR1) - sr = &sr1; - else if (srid == SR2) - sr = &sr2; - else - return; - - if (sr->is_sr_reset == 1) { - sr_clk_enable(sr); - sr_configure(sr); - } - - if (sr->is_autocomp_active == 1) - pr_warning("SR%d: VDD autocomp is already active\n", - srid); - - sr->is_autocomp_active = 1; - if (!sr_enable(sr, target_opp_no)) { - pr_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); - -int sr_stop_vddautocomap(int srid) -{ - struct omap_sr *sr = NULL; - - if (srid == SR1) - sr = &sr1; - else if (srid == SR2) - sr = &sr2; - else - return -EINVAL; - - if (sr->is_autocomp_active == 1) { - sr_disable(sr); - sr_clk_disable(sr); - sr->is_autocomp_active = 0; - /* Reset the volatage for current OPP */ - sr_reset_voltage(srid); - return true; - } else { - pr_warning("SR%d: VDD autocomp is not active\n", - srid); - return false; - } - -} -EXPORT_SYMBOL(sr_stop_vddautocomap); - -void enable_smartreflex(int srid) -{ - u32 target_opp_no = 0; - struct omap_sr *sr = NULL; - - if (srid == SR1) - sr = &sr1; - else if (srid == SR2) - sr = &sr2; - else - return; - - if (sr->is_autocomp_active == 1) { - if (sr->is_sr_reset == 1) { - /* Enable SR clks */ - sr_clk_enable(sr); - - if (srid == SR1) - target_opp_no = get_vdd1_opp(); - else if (srid == SR2) - target_opp_no = get_vdd2_opp(); - - if (!target_opp_no) { - pr_info("Current OPP unknown \ - Cannot configure SR\n"); - } - - sr_configure(sr); - - if (!sr_enable(sr, target_opp_no)) - sr_clk_disable(sr); - } - } -} - -void disable_smartreflex(int srid) -{ - u32 i = 0; - - struct omap_sr *sr = NULL; - - if (srid == SR1) - sr = &sr1; - else if (srid == SR2) - sr = &sr2; - else - return; - - if (sr->is_autocomp_active == 1) { - if (sr->is_sr_reset == 0) { - - sr->is_sr_reset = 1; - /* SRCONFIG - disable SR */ - sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, - ~SRCONFIG_SRENABLE); - - /* Disable SR clk */ - sr_clk_disable(sr); - if (sr->srid == SR1) { - /* Wait for VP idle before disabling VP */ - while ((!prm_read_mod_reg(OMAP3430_GR_MOD, - OMAP3_PRM_VP1_STATUS_OFFSET)) - && i++ < MAX_TRIES) - udelay(1); - - if (i >= MAX_TRIES) - pr_warning("VP1 not idle, still going \ - ahead with VP1 disable\n"); - - /* Disable VP1 */ - prm_clear_mod_reg_bits(PRM_VP1_CONFIG_VPENABLE, - OMAP3430_GR_MOD, - OMAP3_PRM_VP1_CONFIG_OFFSET); - } else if (sr->srid == SR2) { - /* Wait for VP idle before disabling VP */ - while ((!prm_read_mod_reg(OMAP3430_GR_MOD, - OMAP3_PRM_VP2_STATUS_OFFSET)) - && i++ < MAX_TRIES) - udelay(1); - - if (i >= MAX_TRIES) - pr_warning("VP2 not idle, still going \ - ahead with VP2 disable\n"); - - /* Disable VP2 */ - prm_clear_mod_reg_bits(PRM_VP2_CONFIG_VPENABLE, - OMAP3430_GR_MOD, - OMAP3_PRM_VP2_CONFIG_OFFSET); - } - /* Reset the volatage for current OPP */ - sr_reset_voltage(srid); - } - } -} - -/* Voltage Scaling using SR VCBYPASS */ -int sr_voltagescale_vcbypass(u32 target_opp, u32 current_opp, - u8 target_vsel, u8 current_vsel) -{ - int sr_status = 0; - u32 vdd, target_opp_no, current_opp_no; - u32 vc_bypass_value; - u32 reg_addr = 0; - u32 loop_cnt = 0, retries_cnt = 0; - u32 t2_smps_steps = 0; - u32 t2_smps_delay = 0; - - vdd = get_vdd(target_opp); - target_opp_no = get_opp_no(target_opp); - current_opp_no = get_opp_no(current_opp); - - if (vdd == VDD1_OPP) { - sr_status = sr_stop_vddautocomap(SR1); - t2_smps_steps = abs(target_vsel - current_vsel); - - prm_rmw_mod_reg_bits(OMAP3430_VC_CMD_ON_MASK, - (target_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 == VDD2_OPP) { - sr_status = sr_stop_vddautocomap(SR2); - t2_smps_steps = abs(target_vsel - current_vsel); - - prm_rmw_mod_reg_bits(OMAP3430_VC_CMD_ON_MASK, - (target_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 = (target_vsel << OMAP3430_DATA_SHIFT) | - (reg_addr << OMAP3430_REGADDR_SHIFT) | - (R_SRI2C_SLAVE_ADDR << OMAP3430_SLAVEADDR_SHIFT); - - prm_write_mod_reg(vc_bypass_value, OMAP3430_GR_MOD, - OMAP3_PRM_VC_BYPASS_VAL_OFFSET); - - vc_bypass_value = prm_set_mod_reg_bits(OMAP3430_VALID, OMAP3430_GR_MOD, - OMAP3_PRM_VC_BYPASS_VAL_OFFSET); - - while ((vc_bypass_value & OMAP3430_VALID) != 0x0) { - loop_cnt++; - if (retries_cnt > 10) { - pr_info("Loop count exceeded in check SR I2C" - "write\n"); - return 1; - } - 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); - } - - /* - * T2 SMPS slew rate (min) 4mV/uS, step size 12.5mV, - * 2us added as buffer. - */ - t2_smps_delay = ((t2_smps_steps * 125) / 40) + 2; - udelay(t2_smps_delay); - - if (sr_status) { - if (vdd == VDD1_OPP) - sr_start_vddautocomap(SR1, target_opp_no); - else if (vdd == VDD2_OPP) - sr_start_vddautocomap(SR2, target_opp_no); - } - - return 0; -} - -/* Sysfs interface to select SR VDD1 auto compensation */ -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 kobject *kobj, - struct kobj_attribute *attr, - const char *buf, size_t n) -{ - unsigned short value; - - if (sscanf(buf, "%hu", &value) != 1 || (value > 1)) { - pr_err("sr_vdd1_autocomp: Invalid value\n"); - return -EINVAL; - } - - if (value == 0) { - sr_stop_vddautocomap(SR1); - } else { - u32 current_vdd1opp_no = get_vdd1_opp(); - if (!current_vdd1opp_no) { - pr_err("sr_vdd1_autocomp: Current VDD1 opp unknown\n"); - return -EINVAL; - } - sr_start_vddautocomap(SR1, current_vdd1opp_no); - } - return n; -} - -static struct kobj_attribute sr_vdd1_autocomp = { - .attr = { - .name = __stringify(sr_vdd1_autocomp), - .mode = 0644, - }, - .show = omap_sr_vdd1_autocomp_show, - .store = omap_sr_vdd1_autocomp_store, -}; - -/* Sysfs interface to select SR VDD2 auto compensation */ -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 kobject *kobj, - struct kobj_attribute *attr, - const char *buf, size_t n) -{ - unsigned short value; - - if (sscanf(buf, "%hu", &value) != 1 || (value > 1)) { - pr_err("sr_vdd2_autocomp: Invalid value\n"); - return -EINVAL; - } - - if (value == 0) { - sr_stop_vddautocomap(SR2); - } else { - u32 current_vdd2opp_no = get_vdd2_opp(); - if (!current_vdd2opp_no) { - pr_err("sr_vdd2_autocomp: Current VDD2 opp unknown\n"); - return -EINVAL; - } - sr_start_vddautocomap(SR2, current_vdd2opp_no); - } - return n; -} - -static struct kobj_attribute sr_vdd2_autocomp = { - .attr = { - .name = __stringify(sr_vdd2_autocomp), - .mode = 0644, - }, - .show = omap_sr_vdd2_autocomp_show, - .store = omap_sr_vdd2_autocomp_store, -}; - - - -static int __init omap3_sr_init(void) -{ - int ret = 0; - u8 RdReg; - - /* Exit if OPP tables are not defined */ - if (!(mpu_opps && l3_opps)) { - pr_err("SR: OPP rate tables not defined for platform, not enabling SmartReflex\n"); - return -ENODEV; - } - - /* Enable SR on T2 */ - 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); - - if (cpu_is_omap34xx()) { - sr1.clk = clk_get(NULL, "sr1_fck"); - sr2.clk = clk_get(NULL, "sr2_fck"); - } - sr1.vdd_opp_clk = clk_get(NULL, "dpll1_ck"); - sr2.vdd_opp_clk = clk_get(NULL, "l3_ick"); - sr_set_clk_length(&sr1); - sr_set_clk_length(&sr2); - - /* Call the VPConfig, VCConfig, set N Values. */ - sr_set_nvalues(&sr1); - sr_configure_vp(SR1); - - sr_set_nvalues(&sr2); - sr_configure_vp(SR2); - - pr_info("SmartReflex driver initialized\n"); - - ret = sysfs_create_file(power_kobj, &sr_vdd1_autocomp.attr); - if (ret) - pr_err("sysfs_create_file failed: %d\n", ret); - - ret = sysfs_create_file(power_kobj, &sr_vdd2_autocomp.attr); - if (ret) - pr_err("sysfs_create_file failed: %d\n", ret); - - return 0; -} - -late_initcall(omap3_sr_init); diff --git a/arch/arm/mach-omap2/smartreflex.h b/arch/arm/mach-omap2/smartreflex.h deleted file mode 100644 index 2a0e823..0000000 --- a/arch/arm/mach-omap2/smartreflex.h +++ /dev/null @@ -1,256 +0,0 @@ -#ifndef __ARCH_ARM_MACH_OMAP3_SMARTREFLEX_H -#define __ARCH_ARM_MACH_OMAP3_SMARTREFLEX_H -/* - * linux/arch/arm/mach-omap2/smartreflex.h - * - * Copyright (C) 2008 Nokia Corporation - * Kalle Jokiniemi - * - * Copyright (C) 2007 Texas Instruments, Inc. - * Lesly A M <x0080970@ti.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#define PHY_TO_OFF_PM_MASTER(p) (p - 0x36) -#define PHY_TO_OFF_PM_RECIEVER(p) (p - 0x5b) -#define PHY_TO_OFF_PM_INT(p) (p - 0x2e) - -/* SMART REFLEX REG ADDRESS OFFSET */ -#define SRCONFIG 0x00 -#define SRSTATUS 0x04 -#define SENVAL 0x08 -#define SENMIN 0x0C -#define SENMAX 0x10 -#define SENAVG 0x14 -#define AVGWEIGHT 0x18 -#define NVALUERECIPROCAL 0x1C -#define SENERROR 0x20 -#define ERRCONFIG 0x24 - -/* SR Modules */ -#define SR1 1 -#define SR2 2 - -#define SR_FAIL 1 -#define SR_PASS 0 - -#define SR_TRUE 1 -#define SR_FALSE 0 - -#define GAIN_MAXLIMIT 16 -#define R_MAXLIMIT 256 - -#define SR1_CLK_ENABLE BIT(6) -#define SR2_CLK_ENABLE BIT(7) - -/* PRM_VP1_CONFIG */ -#define PRM_VP1_CONFIG_ERROROFFSET (0x00 << 24) -#define PRM_VP1_CONFIG_ERRORGAIN (0x20 << 16) - -#define PRM_VP1_CONFIG_INITVOLTAGE (0x30 << 8) /* 1.2 volt */ -#define PRM_VP1_CONFIG_TIMEOUTEN BIT(3) -#define PRM_VP1_CONFIG_INITVDD BIT(2) -#define PRM_VP1_CONFIG_FORCEUPDATE BIT(1) -#define PRM_VP1_CONFIG_VPENABLE BIT(0) - -/* PRM_VP1_VSTEPMIN */ -#define PRM_VP1_VSTEPMIN_SMPSWAITTIMEMIN (0x01F4 << 8) -#define PRM_VP1_VSTEPMIN_VSTEPMIN BIT(0) - -/* PRM_VP1_VSTEPMAX */ -#define PRM_VP1_VSTEPMAX_SMPSWAITTIMEMAX (0x01F4 << 8) -#define PRM_VP1_VSTEPMAX_VSTEPMAX (0x04 << 0) - -/* PRM_VP1_VLIMITTO */ -#define PRM_VP1_VLIMITTO_VDDMAX (0x3C << 24) -#define PRM_VP1_VLIMITTO_VDDMIN (0x0 << 16) -#define PRM_VP1_VLIMITTO_TIMEOUT (0xFFFF << 0) - -/* PRM_VP2_CONFIG */ -#define PRM_VP2_CONFIG_ERROROFFSET (0x00 << 24) -#define PRM_VP2_CONFIG_ERRORGAIN (0x20 << 16) - -#define PRM_VP2_CONFIG_INITVOLTAGE (0x30 << 8) /* 1.2 volt */ -#define PRM_VP2_CONFIG_TIMEOUTEN BIT(3) -#define PRM_VP2_CONFIG_INITVDD BIT(2) -#define PRM_VP2_CONFIG_FORCEUPDATE BIT(1) -#define PRM_VP2_CONFIG_VPENABLE BIT(0) - -/* PRM_VP2_VSTEPMIN */ -#define PRM_VP2_VSTEPMIN_SMPSWAITTIMEMIN (0x01F4 << 8) -#define PRM_VP2_VSTEPMIN_VSTEPMIN BIT(0) - -/* PRM_VP2_VSTEPMAX */ -#define PRM_VP2_VSTEPMAX_SMPSWAITTIMEMAX (0x01F4 << 8) -#define PRM_VP2_VSTEPMAX_VSTEPMAX (0x04 << 0) - -/* PRM_VP2_VLIMITTO */ -#define PRM_VP2_VLIMITTO_VDDMAX (0x2C << 24) -#define PRM_VP2_VLIMITTO_VDDMIN (0x0 << 16) -#define PRM_VP2_VLIMITTO_TIMEOUT (0xFFFF << 0) - -/* SRCONFIG */ -#define SR1_SRCONFIG_ACCUMDATA (0x1F4 << 22) -#define SR2_SRCONFIG_ACCUMDATA (0x1F4 << 22) - -#define SRCLKLENGTH_12MHZ_SYSCLK 0x3C -#define SRCLKLENGTH_13MHZ_SYSCLK 0x41 -#define SRCLKLENGTH_19MHZ_SYSCLK 0x60 -#define SRCLKLENGTH_26MHZ_SYSCLK 0x82 -#define SRCLKLENGTH_38MHZ_SYSCLK 0xC0 - -#define SRCONFIG_SRCLKLENGTH_SHIFT 12 -#define SRCONFIG_SENNENABLE_SHIFT 5 -#define SRCONFIG_SENPENABLE_SHIFT 3 - -#define SRCONFIG_SRENABLE BIT(11) -#define SRCONFIG_SENENABLE BIT(10) -#define SRCONFIG_ERRGEN_EN BIT(9) -#define SRCONFIG_MINMAXAVG_EN BIT(8) - -#define SRCONFIG_DELAYCTRL BIT(2) -#define SRCONFIG_CLKCTRL (0x00 << 0) - -/* AVGWEIGHT */ -#define SR1_AVGWEIGHT_SENPAVGWEIGHT (0x03 << 2) -#define SR1_AVGWEIGHT_SENNAVGWEIGHT (0x03 << 0) - -#define SR2_AVGWEIGHT_SENPAVGWEIGHT BIT(2) -#define SR2_AVGWEIGHT_SENNAVGWEIGHT BIT(0) - -/* NVALUERECIPROCAL */ -#define NVALUERECIPROCAL_SENPGAIN_SHIFT 20 -#define NVALUERECIPROCAL_SENNGAIN_SHIFT 16 -#define NVALUERECIPROCAL_RNSENP_SHIFT 8 -#define NVALUERECIPROCAL_RNSENN_SHIFT 0 - -/* ERRCONFIG */ -#define SR_CLKACTIVITY_MASK (0x03 << 20) -#define SR_ERRWEIGHT_MASK (0x07 << 16) -#define SR_ERRMAXLIMIT_MASK (0xFF << 8) -#define SR_ERRMINLIMIT_MASK (0xFF << 0) - -#define SR_CLKACTIVITY_IOFF_FOFF (0x00 << 20) -#define SR_CLKACTIVITY_IOFF_FON (0x02 << 20) - -#define ERRCONFIG_VPBOUNDINTEN BIT(31) -#define ERRCONFIG_VPBOUNDINTST BIT(30) - -#define SR1_ERRWEIGHT (0x07 << 16) -#define SR1_ERRMAXLIMIT (0x02 << 8) -#define SR1_ERRMINLIMIT (0xFA << 0) - -#define SR2_ERRWEIGHT (0x07 << 16) -#define SR2_ERRMAXLIMIT (0x02 << 8) -#define SR2_ERRMINLIMIT (0xF9 << 0) - -/* T2 SMART REFLEX */ -#define R_SRI2C_SLAVE_ADDR 0x12 -#define R_VDD1_SR_CONTROL 0x00 -#define R_VDD2_SR_CONTROL 0x01 -#define T2_SMPS_UPDATE_DELAY 360 /* In uSec */ - -/* Vmode control */ -#define R_DCDC_GLOBAL_CFG PHY_TO_OFF_PM_RECIEVER(0x61) - -#define R_VDD1_VSEL PHY_TO_OFF_PM_RECIEVER(0xb9) -#define R_VDD1_VMODE_CFG PHY_TO_OFF_PM_RECIEVER(0xba) -#define R_VDD1_VFLOOR PHY_TO_OFF_PM_RECIEVER(0xbb) -#define R_VDD1_VROOF PHY_TO_OFF_PM_RECIEVER(0xbc) -#define R_VDD1_STEP PHY_TO_OFF_PM_RECIEVER(0xbd) - -#define R_VDD2_VSEL PHY_TO_OFF_PM_RECIEVER(0xc7) -#define R_VDD2_VMODE_CFG PHY_TO_OFF_PM_RECIEVER(0xc8) -#define R_VDD2_VFLOOR PHY_TO_OFF_PM_RECIEVER(0xc9) -#define R_VDD2_VROOF PHY_TO_OFF_PM_RECIEVER(0xca) -#define R_VDD2_STEP PHY_TO_OFF_PM_RECIEVER(0xcb) - -/* R_DCDC_GLOBAL_CFG register, SMARTREFLEX_ENABLE values */ -#define DCDC_GLOBAL_CFG_ENABLE_SRFLX 0x08 - -#define PRCM_MAX_SYSC_REGS 30 - -/* - * XXX: These should be removed/moved from here once we have a working DVFS - * implementation in place - */ -#define AT_3430 1 /*3430 ES 1.0 */ -#define AT_3430_ES2 2 /*3430 ES 2.0 */ - -#define ID_OPP 0xE2 /*OPP*/ - -/* DEVICE ID/DPLL ID/CLOCK ID: bits 28-31 for OMAP type */ -#define OMAP_TYPE_SHIFT 28 -#define OMAP_TYPE_MASK 0xF -/* OPP ID: bits: 0-4 for OPP number */ -#define OPP_NO_POS 0 -#define OPP_NO_MASK 0x1F -/* OPP ID: bits: 5-6 for VDD */ -#define VDD_NO_POS 5 -#define VDD_NO_MASK 0x3 -/* Other IDs: bits 20-27 for ID type */ -/* These IDs have bits 25,26,27 as 1 */ -#define OTHER_ID_TYPE_SHIFT 20 -#define OTHER_ID_TYPE_MASK 0xFF - -#define OTHER_ID_TYPE(X) ((X & OTHER_ID_TYPE_MASK) << OTHER_ID_TYPE_SHIFT) -#define ID_OPP_NO(X) ((X & OPP_NO_MASK) << OPP_NO_POS) -#define ID_VDD(X) ((X & VDD_NO_MASK) << VDD_NO_POS) -#define OMAP(X) ((X >> OMAP_TYPE_SHIFT) & OMAP_TYPE_MASK) -#define get_opp_no(X) ((X >> OPP_NO_POS) & OPP_NO_MASK) -#define get_vdd(X) ((X >> VDD_NO_POS) & VDD_NO_MASK) - -/* VDD1 OPPs */ -#define PRCM_VDD1_OPP1 (OMAP(AT_3430_ES2) | OTHER_ID_TYPE(ID_OPP) | \ - ID_VDD(PRCM_VDD1) | ID_OPP_NO(0x1)) -#define PRCM_VDD1_OPP2 (OMAP(AT_3430_ES2) | OTHER_ID_TYPE(ID_OPP) | \ - ID_VDD(PRCM_VDD1) | ID_OPP_NO(0x2)) -#define PRCM_VDD1_OPP3 (OMAP(AT_3430_ES2) | OTHER_ID_TYPE(ID_OPP) | \ - ID_VDD(PRCM_VDD1) | ID_OPP_NO(0x3)) -#define PRCM_VDD1_OPP4 (OMAP(AT_3430_ES2) | OTHER_ID_TYPE(ID_OPP) | \ - ID_VDD(PRCM_VDD1) | ID_OPP_NO(0x4)) -#define PRCM_VDD1_OPP5 (OMAP(AT_3430_ES2) | OTHER_ID_TYPE(ID_OPP) | \ - ID_VDD(PRCM_VDD1) | ID_OPP_NO(0x5)) -#define PRCM_NO_VDD1_OPPS 5 - - -/* VDD2 OPPs */ -#define PRCM_VDD2_OPP1 (OMAP(AT_3430_ES2) | OTHER_ID_TYPE(ID_OPP) | \ - ID_VDD(PRCM_VDD2) | ID_OPP_NO(0x1)) -#define PRCM_VDD2_OPP2 (OMAP(AT_3430_ES2) | OTHER_ID_TYPE(ID_OPP) | \ - ID_VDD(PRCM_VDD2) | ID_OPP_NO(0x2)) -#define PRCM_VDD2_OPP3 (OMAP(AT_3430_ES2) | OTHER_ID_TYPE(ID_OPP) | \ - ID_VDD(PRCM_VDD2) | ID_OPP_NO(0x3)) -#define PRCM_NO_VDD2_OPPS 3 -/* XXX: end remove/move */ - -/* XXX: find more appropriate place for these once DVFS is in place */ -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. - */ -#ifdef CONFIG_OMAP_SMARTREFLEX -void enable_smartreflex(int srid); -void disable_smartreflex(int srid); -int sr_voltagescale_vcbypass(u32 t_opp, u32 c_opp, u8 t_vsel, u8 c_vsel); -void sr_start_vddautocomap(int srid, u32 target_opp_no); -int sr_stop_vddautocomap(int srid); -#else -static inline void enable_smartreflex(int srid) {} -static inline void disable_smartreflex(int srid) {} -#endif - -#endif -- 1.6.3.3 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH 2/2 v3] OMAP3: PM: SR: SmartReflex Refactor Rev4.0 2009-10-24 5:15 ` [PATCH 1/2 v3] OMAP3: PM: SR: prepare: remove old SR code Nishanth Menon @ 2009-10-24 5:15 ` Nishanth Menon 2009-10-25 22:12 ` Cousson, Benoit ` (3 more replies) 0 siblings, 4 replies; 16+ messages in thread From: Nishanth Menon @ 2009-10-24 5:15 UTC (permalink / raw) To: "linux-omap <linux-omap" Cc: Imberton Guilhem, Mike Chan, Rajendra Nayak, Roger Quadros, Kalle Jokiniemi, Teerth Reddy, Kevin Hilman, Paul Walmsley, Hogander Jouni, Nishanth Menon Refactor the smart reflex implementation. Original implementation summary: Eduardo Valentin (1): OMAP3: PM: SmartReflex: Fix scheduled while atomic problem Kalle Jokiniemi (1): OMAP3: PM: SmartReflex driver integration Kevin Hilman (1): temp: SR: IO_ADDRESS conversion Phil Carmody (2): OMAP3: PM: Don't do unnecessary searches in omap_sr_vdd*_autocomp_store OMAP3: PM: Early exit on invalid parameters Rajendra Nayak (10): OMAP3: SR: Fix init voltage on OPP change OMAP3: SR: Update VDD1/2 voltages at boot OMAP3: SR: Use sysclk for SR CLKLENGTH calc OMAP3: SR: Reset voltage level on SR disable OMAP3: SR: Replace printk's with pr_* calls OMAP3: SR: Remove redundant defines OMAP3: SR: Replace (0x1 << n) with BIT(n) OMAP3: SR: Fix SR driver to check for omap-pm return values OMAP3: PM: Put optimal SMPS stabilization delay OMAP3: SR: Wait for VP idle before a VP disable Roger Quadros (4): OMAP3: PM: Fix Smartreflex when used with PM_NOOP layer OMAP3: PM: Make Smartreflex driver independent of SRF OMAP3: PM: Do not Enable SmartReflex if OPP tables not defined OMAP3: PM: Smartreflex: Fix VDD2 OPP determining logic Teerth Reddy (1): OMAP3: SR: Replace SR_PASS/FAIL,SR_TRUE/FALSE This patch introduces the following changes in addition to refactoring the implementation: a) changes the DVFS transition sequences from: freq, voltage(SR+vp) and viceversa TO: disable_vp,SR; freq, voltage(SR+vp) and viceversa; enable_vp,SR [NOTE: sequence change for disable path - was sr_dis,vp_dis] This change prevents spikes and unexpected voltage changes as a result of SR being left enabled at wrong times b) Major rewrite of smartreflex.c to do the following: 1) Support VCbypass style of voltage configuration as optional introduce and support forceupdate default as recommended by OMAP3430 TRM. 2) Centralize operations to allow for simpler and predictable code flows 3) Modification to SR configured values to be inline with silicon characterization results 4) cleanup of header 5) Introduce a few omap_pmic weak functions which can be overridden by platforms implementing PMICs which are different from TWL4030 derivatives 6) srid is standardised to u8 and it is not a bit field c) Fix ERRCONFIG access to prevent unplanned cleanup of interrupt status registers - this is done using a interrupt status mask d) Test nvalues removed instead use debugfs entries to set any values you like - no more Kconfig option either.. e) Setup h/w timeout based on cpu sysclk and not hardcoded values g) finegrained with raw register values available over debugfs in <debugfs mount point>/<pm_debug mount point>/ smartreflex/{srid}/ nvalue_opp[1-5] - nvalues for all 5 opps Following register tweakability: VP register values: vplimito_value vpstepmax_value vpstepmin_value vpconfig_value SR Register values: sr_errconfig_value sr_config_value Advice: disable SR before hitting them, no checks at this point. The following ReadONLY entry is provided: vsel - this provides the voltage processor decided voltage value and translated back to voltage based on the type of chip. typical equation is: voltage(mV) = (vsel*12.5) + 600 test value equivalent userspace bash script would be: mount -t debugfs none /dbg mount -t sysfs none /sys #vdd1: #0x00AAB48A - OPP3 echo -n "11187338" >/dbg/pm_debug/smartreflex/1/nvalue_opp3 #0x00ABA2E6 - OPP4 echo -n "11248358" >/dbg/pm_debug/smartreflex/1/nvalue_opp4 # 0x00AB90D3 - OPP5 echo -n "11243731" >/dbg/pm_debug/smartreflex/1/nvalue_opp5 #setup senn and senp value (essentially +120) x=`cat /dbg/pm_debug/smartreflex/1/sr_config_value` y=$((x + 120)) echo -n $y>/dbg/pm_debug/smartreflex/1/sr_config_value #and enable it.. echo -n "1" >/sys/power/sr_vdd1_autocomp #vdd2 #0x00AAC695 -OPP3 echo -n "11191957" > /dbg/pm_debug/smartreflex/2/nvalue_opp3 #setup senn and senp value (essentially +120) x=`cat /dbg/pm_debug/smartreflex/2/sr_config_value` y=$((x + 120)) echo -n $y>/dbg/pm_debug/smartreflex/2/sr_config_value #and enable it.. echo -n "1" >/sys/power/sr_vdd2_autocomp Tested on: SDP3430 with test N values as above and with ES3.1 silicon TODO: a) Handle scenarios for multiple OMAP variants with differing SR capabilities (e.g. varying OPP levels - e.g. 3630, 4430 etc..) [IMMEDIATE ISSUE - partly done] b) Handling OMAP variants with different tuning values c) Handling different SR capable PMIC with different tuning values d) A proper handling of locking mechanism b/w dvfs and userspace access of sr[x]_vddautocomp e) A more robust error handling f) using SR on larger number of boards and any tuning parameters which may be needed additionally (HS/FS I2C4 ops etc..) g) Wider testing and and bug fixes h) Analyse how to use SR decided voltages for OPP1 as retention voltage. some systems may choose to disable OPP1, what do we do then? Cc: Rajendra Nayak <rnayak@ti.com> Cc: Roger Quadros <ext-roger.quadros@nokia.com> Cc: Kalle Jokiniemi <ext-kalle.jokiniemi@nokia.com> Cc: Teerth Reddy <teerth@ti.com> Cc: Kevin Hilman <khilman@deeprootsystems.com> Cc: Paul Walmsley <paul@pwsan.com> Cc: Högander Jouni <jouni.hogander@nokia.com> Cc: Mike Chan <mikechan@google.com> Signed-off-by: Imberton Guilhem <guilhem.imberton@motorola.com> Signed-off-by: Nishanth Menon <nm@ti.com> --- arch/arm/mach-omap2/pm-debug.c | 3 + arch/arm/mach-omap2/resource34xx.c | 8 +- arch/arm/mach-omap2/smartreflex.c | 1604 ++++++++++++++++++++++++++++++++++++ arch/arm/mach-omap2/smartreflex.h | 274 ++++++ arch/arm/plat-omap/Kconfig | 15 +- 5 files changed, 1893 insertions(+), 11 deletions(-) create mode 100644 arch/arm/mach-omap2/smartreflex.c create mode 100644 arch/arm/mach-omap2/smartreflex.h diff --git a/arch/arm/mach-omap2/pm-debug.c b/arch/arm/mach-omap2/pm-debug.c index 767ebbc..34ff068 100644 --- a/arch/arm/mach-omap2/pm-debug.c +++ b/arch/arm/mach-omap2/pm-debug.c @@ -35,6 +35,7 @@ #include "cm.h" #include "pm.h" #include "prm-regbits-34xx.h" +#include "smartreflex.h" int omap2_pm_debug; @@ -617,6 +618,8 @@ static int __init pm_dbg_init(void) &voltage_off_while_idle, &pm_dbg_option_fops); + (void)sr_debugfs_create_entries(d); + pm_dbg_init_done = 1; return 0; diff --git a/arch/arm/mach-omap2/resource34xx.c b/arch/arm/mach-omap2/resource34xx.c index 04be4d2..3789f88 100644 --- a/arch/arm/mach-omap2/resource34xx.c +++ b/arch/arm/mach-omap2/resource34xx.c @@ -294,17 +294,23 @@ static int program_opp(int res, struct omap_opp *opp, int target_level, else raise = 0; +#ifdef CONFIG_OMAP_SMARTREFLEX + sr_vp_disable_both(t_opp, c_opp); +#endif for (i = 0; i < 2; i++) { if (i == raise) ret = program_opp_freq(res, target_level, current_level); #ifdef CONFIG_OMAP_SMARTREFLEX else - sr_voltagescale_vcbypass(t_opp, c_opp, + sr_voltage_set(t_opp, c_opp, opp[target_level].vsel, opp[current_level].vsel); #endif } +#ifdef CONFIG_OMAP_SMARTREFLEX + sr_vp_enable_both(t_opp, c_opp); +#endif return ret; } diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c new file mode 100644 index 0000000..d506896 --- /dev/null +++ b/arch/arm/mach-omap2/smartreflex.c @@ -0,0 +1,1604 @@ +/* + * linux/arch/arm/mach-omap3/smartreflex.c + * + * OMAP34XX SmartReflex Voltage Control + * + * Copyright (C) 2009 Texas Instruments, Inc. + * Nishanth Menon + * + * Copyright (C) 2008 Nokia Corporation + * Kalle Jokiniemi + * + * Copyright (C) 2007 Texas Instruments, Inc. + * Lesly A M <x0080970@ti.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/clk.h> +#include <linux/sysfs.h> +#include <linux/kobject.h> +#include <linux/i2c/twl4030.h> +#include <linux/io.h> +#include <linux/debugfs.h> + +#include <plat/omap34xx.h> +#include <plat/control.h> +#include <plat/clock.h> +#include <plat/omap-pm.h> +#include <plat/resource.h> +#include <plat/powerdomain.h> + +#include "prm.h" +#include "smartreflex.h" +#include "prm-regbits-34xx.h" + +/* MCUDISACK is expected to happen within 1uSec. */ +#define COUNT_TIMEOUT_MCUDISACK 200 + +/* VPINIDLE is expected to happen within 100uSec. Typical is 2uSec */ +#define COUNT_TIMEOUT_VPINIDLE 200 + +/* Time taken for setting the device - worst case as FS I2C + * Depends on SMPSWAITIME MIN/MAX Typical is 200uSec + */ +#define COUNT_TIMEOUT_TRANSDONE_SET 400 + +/* Time to clear out multiple transdone events typical is 3uSec */ +#define COUNT_TIMEOUT_TRANSDONE_CLR 50 + +/* Time For VCBypass mode for TWL4030 derivative chip. */ +#define COUNT_TIMEOUT_TWL4030_VCBYPASS 500 + +/* How many retries to do for I2C errors seen on bus for Forceupdate? */ +#define COUNT_RETRY_SMPSNOACK 4 + +#define SR_REGADDR(offset) (sr->srbase_addr + (offset)) + +/* Which function to use for setting voltage */ +#ifdef CONFIG_OMAP_VC_BYPASS_UPDATE +#define SR_CHOSEN_VOLTAGE_UPDATE_MECH sr_vc_bypass +#else +#define SR_CHOSEN_VOLTAGE_UPDATE_MECH sr_vp_forceupdate +#endif + +#ifdef CONFIG_OMAP_PM_NONE +struct omap_opp *mpu_opps; +struct omap_opp *dsp_opps; +struct omap_opp *l3_opps; +#endif + +static ssize_t omap_sr_vdd_autocomp_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf); +static ssize_t omap_sr_vdd_autocomp_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t n); +/* Structure for Voltage processor */ +struct omap_sr_vp { + /* Store the commonly used register offsets. + * this saves a if condition decision + */ + u16 prm_vpx_status_offset; + u16 prm_vpx_config_offset; + u16 prm_vpx_stepmin_offset; + u16 prm_vpx_stepmax_offset; + u16 prm_vpx_limito_offset; + u32 prm_vpx_vlimito_timeout; + u8 prm_vpx_vlimito_shift; + u16 prm_vpx_voltage_offset; + u16 prm_vc_cmd_val_offset; + /* Store the defaults + * allowing us to save OCP read + * operation + */ + u32 vpconfig_value; + u32 vpstepmin_value; + u32 vpstepmax_value; + u32 vplimito_value; + u32 vpenable_mask; + u32 irqmask_trans_done; + u32 irqmask_smps_noack; +}; + +/* Structure for Smart Reflex */ +struct omap_sr { + u8 srid; + u8 prcm_vdd; + char *vdd_name; + struct kobj_attribute autocom_attr; + struct omap_opp **omap_opp; + /* SR activity marker */ + u8 is_sr_reset; + u8 is_autocomp_active; + u32 req_opp_no; + u32 sr_config_value; + u32 sr_errconfig_value; + u32 sr_n_mod_mask; + u8 sr_n_mod_shift; + u32 sr_p_mod_mask; + u8 sr_p_mod_shift; + struct clk *fclk; + struct clk *iclk; + void __iomem *srbase_addr; + char *iclk_name; + char *fclk_name; + /* Voltage processor for the specific SR module */ + struct omap_sr_vp vp; + /* This will contain the register offset on + * boot, replaced with the actual value + * as part of init routine + */ + u8 num_opp; + u8 opp_boundary; + u32 opp_nvalue[]; +}; + +/* A superset of all SRs in the system ordered by SRID */ +struct omap_sr_list { + u8 num_sr; + struct omap_sr *sr_list[]; +}; + +/* Definitions for 3430 Silicon */ +/* Smart Reflex 1 structure */ +static __initdata struct omap_sr omap34xx_sr1 = { + /* *INDENT-OFF* */ + .srid = SR1, + .prcm_vdd = PRCM_VDD1, + .vdd_name = "vdd1_opp", + .omap_opp = &mpu_opps, + .autocom_attr = { + .attr = { + .name = __stringify(sr_vdd1_autocomp), + .mode = 0644, + }, + .show = omap_sr_vdd_autocomp_show, + .store = omap_sr_vdd_autocomp_store, + }, + .is_sr_reset = 1, + .is_autocomp_active = 0, + .srbase_addr = (void *)OMAP34XX_SR1_BASE, + .fclk_name = "sr1_fck", + .iclk_name = "sr_l4_ick", + .sr_errconfig_value = SR1_ERRWEIGHT | SR1_ERRMAXLIMIT | + ERRCONFIG_VPBOUNDINTEN | ERRCONFIG_VPBOUNDINTST | + SR_CLKACTIVITY_IOFF_FON, + .sr_n_mod_mask = OMAP343X_SR1_SENNENABLE_MASK, + .sr_n_mod_shift = OMAP343X_SR1_SENNENABLE_SHIFT, + .sr_p_mod_mask = OMAP343X_SR1_SENPENABLE_MASK, + .sr_p_mod_shift = OMAP343X_SR1_SENPENABLE_SHIFT, + .vp = { + .prm_vpx_status_offset = OMAP3_PRM_VP1_STATUS_OFFSET, + .prm_vpx_config_offset = OMAP3_PRM_VP1_CONFIG_OFFSET, + .prm_vpx_stepmin_offset = OMAP3_PRM_VP1_VSTEPMIN_OFFSET, + .prm_vpx_stepmax_offset = OMAP3_PRM_VP1_VSTEPMAX_OFFSET, + .prm_vpx_limito_offset = OMAP3_PRM_VP1_VLIMITTO_OFFSET, + .prm_vpx_vlimito_timeout = PRM_VP1_VLIMITTO_TIMEOUT_US, + .prm_vpx_vlimito_shift = PRM_VP1_VLIMITTO_TIMEOUT_SHIFT, + .prm_vpx_voltage_offset = OMAP3_PRM_VP1_VOLTAGE_OFFSET, + .prm_vc_cmd_val_offset = OMAP3_PRM_VC_CMD_VAL_0_OFFSET, + .vpconfig_value = PRM_VP1_CONFIG_ERROROFFSET | + PRM_VP1_CONFIG_TIMEOUTEN, + .vpstepmin_value = PRM_VP1_VSTEPMIN_SMPSWAITTIMEMIN | + PRM_VP1_VSTEPMIN_VSTEPMIN, + .vpstepmax_value = PRM_VP1_VSTEPMAX_SMPSWAITTIMEMAX | + PRM_VP1_VSTEPMAX_VSTEPMAX, + .vplimito_value = PRM_VP1_VLIMITTO_VDDMAX | + PRM_VP1_VLIMITTO_VDDMIN, + .vpenable_mask = PRM_VP1_CONFIG_VPENABLE, + .irqmask_trans_done = VP1_IRQMASK_TRANSDONE, + .irqmask_smps_noack = OMAP3430_VP1_NOSMPSACK_ST, + }, + .num_opp = 5, + .opp_boundary = 3, + .opp_nvalue = { + OMAP343X_CONTROL_FUSE_OPP1_VDD1, + OMAP343X_CONTROL_FUSE_OPP2_VDD1, + OMAP343X_CONTROL_FUSE_OPP3_VDD1, + OMAP343X_CONTROL_FUSE_OPP4_VDD1, + OMAP343X_CONTROL_FUSE_OPP5_VDD1, + }, + /* *INDENT-ON* */ +}; + +/* Smart Reflex 2 structure */ +static __initdata struct omap_sr omap34xx_sr2 = { + /* *INDENT-OFF* */ + .srid = SR2, + .prcm_vdd = PRCM_VDD2, + .vdd_name = "vdd2_opp", + .omap_opp = &l3_opps, + .autocom_attr = { + .attr = { + .name = __stringify(sr_vdd2_autocomp), + .mode = 0644, + }, + .show = omap_sr_vdd_autocomp_show, + .store = omap_sr_vdd_autocomp_store, + }, + .is_sr_reset = 1, + .is_autocomp_active = 0, + .srbase_addr = (void *)OMAP34XX_SR2_BASE, + .fclk_name = "sr2_fck", + .iclk_name = "sr_l4_ick", + .sr_errconfig_value = SR2_ERRWEIGHT | SR2_ERRMAXLIMIT | + ERRCONFIG_VPBOUNDINTEN | ERRCONFIG_VPBOUNDINTST | + SR_CLKACTIVITY_IOFF_FON, + .sr_n_mod_mask = OMAP343X_SR2_SENNENABLE_MASK, + .sr_n_mod_shift = OMAP343X_SR2_SENNENABLE_SHIFT, + .sr_p_mod_mask = OMAP343X_SR2_SENPENABLE_MASK, + .sr_p_mod_shift = OMAP343X_SR2_SENPENABLE_SHIFT, + .vp = { + .prm_vpx_status_offset = OMAP3_PRM_VP2_STATUS_OFFSET, + .prm_vpx_config_offset = OMAP3_PRM_VP2_CONFIG_OFFSET, + .prm_vpx_stepmin_offset = OMAP3_PRM_VP2_VSTEPMIN_OFFSET, + .prm_vpx_stepmax_offset = OMAP3_PRM_VP2_VSTEPMAX_OFFSET, + .prm_vpx_limito_offset = OMAP3_PRM_VP2_VLIMITTO_OFFSET, + .prm_vpx_vlimito_timeout = PRM_VP2_VLIMITTO_TIMEOUT_US, + .prm_vpx_vlimito_shift = PRM_VP2_VLIMITTO_TIMEOUT_SHIFT, + .prm_vpx_voltage_offset = OMAP3_PRM_VP1_VOLTAGE_OFFSET, + .prm_vc_cmd_val_offset = OMAP3_PRM_VC_CMD_VAL_1_OFFSET, + .vpconfig_value = PRM_VP2_CONFIG_ERROROFFSET | + PRM_VP2_CONFIG_TIMEOUTEN, + .vpstepmin_value = PRM_VP2_VSTEPMIN_SMPSWAITTIMEMIN | + PRM_VP2_VSTEPMIN_VSTEPMIN, + .vpstepmax_value = PRM_VP2_VSTEPMAX_SMPSWAITTIMEMAX | + PRM_VP2_VSTEPMAX_VSTEPMAX, + .vplimito_value = PRM_VP2_VLIMITTO_VDDMAX | + PRM_VP2_VLIMITTO_VDDMIN, + .vpenable_mask = PRM_VP2_CONFIG_VPENABLE, + .irqmask_trans_done = VP2_IRQMASK_TRANSDONE, + .irqmask_smps_noack = OMAP3430_VP2_NOSMPSACK_ST, + }, + .num_opp = 3, + .opp_boundary = 3, + .opp_nvalue = { + OMAP343X_CONTROL_FUSE_OPP1_VDD2, + OMAP343X_CONTROL_FUSE_OPP2_VDD2, + OMAP343X_CONTROL_FUSE_OPP3_VDD2, + }, + /* *INDENT-ON* */ +}; + +/* SR list for 3430 */ +static __initdata struct omap_sr_list omap34xx_srlist = { + .num_sr = 2, + .sr_list = {&omap34xx_sr1, &omap34xx_sr2} +}; + +/* The final SR list */ +static struct omap_sr_list *omap_srlist; + +/*********************** OPP Accessor functions ****************************/ + +/** + * @brief *get_sr - get SR pointer from an SRID + * + * @param srid - vddid + * + * @return struct pointer if found, else BUG()s + */ +static inline struct omap_sr *get_sr(u8 srid) +{ + BUG_ON(srid > omap_srlist->num_sr); + return omap_srlist->sr_list[srid - 1]; +} + +/** + * @brief *get_sr_from_vdd - get the SR structure indexed by + * VDD ID + * + * @param vddid - vddid + * + * @return struct pointer if found, else BUG()s + */ +static inline struct omap_sr *get_sr_from_vdd(u8 vddid) +{ + /* Currently, the SRID and VDDID are the same, misusing it */ + return get_sr(vddid); +} + +/** + * @brief *get_sr_from_vdd_name - get the SR structure from + * sysfs name + * + * @param name -sysfs entry name + * + * @return sr struct pointer if found else NULL + */ +static struct omap_sr *get_sr_from_vdd_name(char *name) +{ + int i; + struct omap_sr *sr; + for (i = 0; i < omap_srlist->num_sr; i++) { + sr = omap_srlist->sr_list[i]; + if (!strcmp(name, sr->autocom_attr.attr.name)) + return sr; + } + /* Nothin found, BUG!! */ + BUG(); + return NULL; +} + +/** + * @brief get_current_opp_number_from_sr - get the current active OPP number + * from SR pointer + * + * @param sr struct pointer + * + * @return current OPP ID + */ +static inline int get_current_opp_number_from_sr(struct omap_sr *sr) +{ + return (*sr->omap_opp)[resource_get_level(sr->vdd_name)].opp_id; +} + +/** + * @brief get_vsel_for_opp - get the VSEL value for the SR/OPP combination + * + * @param sr struct pointer + * @param opp opp number desired for + * + * @return vsel value, if bad opp number is given, this will BUG() + */ +static inline u8 get_vsel_for_opp(struct omap_sr *sr, int opp) +{ + /* Dont ask me to derefence nonexistant OPPs! + * TODO: add check for valid OPPs here + */ + BUG_ON(opp > sr->num_opp); + return (*sr->omap_opp)[opp].vsel; +} + +/****************** SMART REFLEX DEBUGFS ENTRIES *************************/ + +#ifdef __SR_DEBUG + +/** + * @brief sr_debugfs_set - set variable with value + * + * @param data - variable pointer + * @param val - value to set + * + * @return - 0 + */ +static int sr_debugfs_set(void *data, u64 val) +{ + u32 *option = data; + + *option = val; + + return 0; +} + +/** + * @brief sr_debugfs_get - setup the params + * + * @param data - variable to set + * @param val - value to return + * + * @return - 0 + */ +static int sr_debugfs_get(void *data, u64 *val) +{ + u32 *option = data; + + *val = *option; + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(sr_debugfs_option_fops, sr_debugfs_get, sr_debugfs_set, + "%llu\n"); + +/** + * @brief sr_debugfs_vselget - return the vsel value + * + * @param data - pointer to vp + * @param val - value we read back + * + * @return + */ +static int sr_debugfs_vselget(void *data, u64 *val) +{ + struct omap_sr_vp *vp = (struct omap_sr_vp *)data; + + *val = prm_read_mod_reg(OMAP3430_GR_MOD, vp->prm_vpx_voltage_offset); + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(sr_debugfs_option_vsel_fops, sr_debugfs_vselget, NULL, + "%llu\n"); + +/* Temporary store of pm_debug directory entry */ +static __initdata struct dentry *stored_pm_d; + +/** + * @brief sr_debugfs_create_entries - create the Smart Reflex entries + * called from pm-debug, this just stores it for SR to use in late_init + * + * @param d - parent directory tree + * + * @return 0 if all ok, else returns with error + */ +int sr_debugfs_create_entries(struct dentry *d) +{ + stored_pm_d = d; + return 0; +} + +/** + * @brief sr_debugfs_create_entries_late - create the Smart Reflex entries - + * called as part of init sequence of SR uses the dentry registered early + * + * @param d - parent directory tree + * + * @return 0 if all ok, else returns with error + */ +static __init int sr_debugfs_create_entries_late(void) +{ + struct dentry *sr_dir; + struct dentry *sr_sub_dir; + int count; + + sr_dir = debugfs_create_dir("smartreflex", stored_pm_d); + if (IS_ERR(sr_dir)) + return PTR_ERR(sr_dir); + for (count = 0; count < omap_srlist->num_sr; count++) { + int i; + struct omap_sr *sr = get_sr(count + 1); + char name[] = "0"; + char nval_name[] = "nvalue_opp0"; + name[0] += sr->srid; + sr_sub_dir = debugfs_create_dir(name, sr_dir); + if (IS_ERR(sr_sub_dir)) + continue; + for (i = 0; i < sr->num_opp; i++) { + nval_name[strlen(nval_name) - 1]++; + (void)debugfs_create_file(nval_name, S_IRUGO | S_IWUGO, + sr_sub_dir, + &(sr->opp_nvalue[i]), + &sr_debugfs_option_fops); + } + (void)debugfs_create_file("sr_errconfig_value", + S_IRUGO | S_IWUGO, sr_sub_dir, + &(sr->sr_errconfig_value), + &sr_debugfs_option_fops); + (void)debugfs_create_file("sr_config_value", S_IRUGO | S_IWUGO, + sr_sub_dir, &(sr->sr_config_value), + &sr_debugfs_option_fops); + (void)debugfs_create_file("vpconfig_value", S_IRUGO | S_IWUGO, + sr_sub_dir, &(sr->vp.vpconfig_value), + &sr_debugfs_option_fops); + (void)debugfs_create_file("vpstepmin_value", S_IRUGO | S_IWUGO, + sr_sub_dir, &(sr->vp.vpstepmin_value), + &sr_debugfs_option_fops); + (void)debugfs_create_file("vpstepmax_value", S_IRUGO | S_IWUGO, + sr_sub_dir, &(sr->vp.vpstepmax_value), + &sr_debugfs_option_fops); + (void)debugfs_create_file("vplimito_value", S_IRUGO | S_IWUGO, + sr_sub_dir, &(sr->vp.vplimito_value), + &sr_debugfs_option_fops); + (void)debugfs_create_file("vplimito_value", S_IRUGO | S_IWUGO, + sr_sub_dir, &(sr->vp.vplimito_value), + &sr_debugfs_option_fops); + (void)debugfs_create_file("vsel", S_IRUGO, sr_sub_dir, + &(sr->vp), &sr_debugfs_option_vsel_fops); + } + + return 0; +} + +#else + +static inline int sr_debugfs_create_entries_late(void) +{ + return 0; +} +#endif /* __SR_DEBUG */ + +/****************** PMIC WEAK FUNCTIONS FOR TWL4030 derivatives **********/ + +/** + * @brief pmic_srinit - Power management IC initialization + * for smart reflex. The current code is written for TWL4030 + * derivatives, replace in board file if PMIC requires + * a different sequence + * + * @return result of operation + */ +int __weak __init omap_pmic_srinit(void) +{ + int ret = -ENODEV; +#ifdef CONFIG_TWL4030_CORE + u8 reg; + /* Enable SR on T2 */ + ret = twl4030_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, ®, + R_DCDC_GLOBAL_CFG); + + reg |= DCDC_GLOBAL_CFG_ENABLE_SRFLX; + ret |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, reg, + R_DCDC_GLOBAL_CFG); +#endif /* End of CONFIG_TWL4030_CORE */ + return ret; +} + +/** + * @brief omap_pmic_voltage_ramp_delay - how much should this pmic ramp delay + * Various PMICs have different ramp up and down delays. choose to implement + * in required pmic file to override this function. + * On TWL4030 derivatives: + * T2 SMPS slew rate (min) 4mV/uS, step size 12.5mV, + * 2us added as buffer. + * + * @param srid - which SR is this for? + * @param target_vsel - targetted voltage selction + * @param current_vsel - current voltage selection + * + * @return delay in uSeconds + */ +u32 __weak omap_pmic_voltage_ramp_delay(u8 srid, u8 target_vsel, + u8 current_vsel) +{ + u32 t2_smps_steps = abs(target_vsel - current_vsel); + u32 t2_smps_delay = ((t2_smps_steps * 125) / 40) + 2; + return t2_smps_delay; +} + +#ifdef CONFIG_OMAP_VC_BYPASS_UPDATE +/** + * @brief omap_pmic_voltage_cmds - hook for pmic command sequence + * to be send out which are specific to pmic to set a specific voltage. + * this should inturn call vc_send_command with the required sequence + * The current implementation is for TWL4030 derivatives + * + * @param srid - which SR is this for? + * @param target_vsel - what voltage is desired to be set? + * + * @return specific value to set. + */ +int __weak omap_pmic_voltage_cmds(u8 srid, u8 target_vsel) +{ + u8 reg_addr = (srid == SR1) ? R_VDD1_SR_CONTROL : R_VDD2_SR_CONTROL; + u16 timeout = COUNT_TIMEOUT_TWL4030_VCBYPASS; + return vc_send_command(R_SRI2C_SLAVE_ADDR, reg_addr, target_vsel, + &timeout); +} +#endif /* ifdef CONFIG_OMAP_VC_BYPASS_UPDATE */ + +/*********************** Voltage Controller functions *************************/ + +/** + * @brief vc_send_command - The actual command transmission using + * Voltage controller on I2C4 + * + * @param slave_addr - what is the PMIC slave address + * @param reg_addr - what is the register address I should be using? + * @param data - what value do you want to write here? + * @param timeout_us timeout in uSeconds - returns actual time left + * + * @return 0 if all ok, else error value + */ +int vc_send_command(u8 slave_addr, u8 reg_addr, u8 data, u16 *timeout_us) +{ + u32 value; + u32 count; + + if (unlikely(!timeout_us)) + return -EINVAL; + + /* timeout = timeout_us/10 -> each udelay event + * 1 udelay event every 50 iteration, assuming + * each iteration is instaneous, + * count = (timeout_us/10) * 50 or timeout_us * 5 + */ + count = *timeout_us * 5; + + value = (data << OMAP3430_DATA_SHIFT) | + (reg_addr << OMAP3430_REGADDR_SHIFT) | + (slave_addr << OMAP3430_SLAVEADDR_SHIFT); + + prm_write_mod_reg(value, OMAP3430_GR_MOD, + OMAP3_PRM_VC_BYPASS_VAL_OFFSET); + + value = prm_set_mod_reg_bits(OMAP3430_VALID, OMAP3430_GR_MOD, + OMAP3_PRM_VC_BYPASS_VAL_OFFSET); + /* + * Do continous 50 checks then follow with a 10usec delay, + * then check again + */ + do { + value = prm_read_mod_reg(OMAP3430_GR_MOD, + OMAP3_PRM_VC_BYPASS_VAL_OFFSET) + & OMAP3430_VALID; + /* should i wait? */ + if (value && (count % 50)) { + udelay(10); + *timeout_us -= 10; + } + count--; + } while (value && count); + if (!count) { + pr_err("VC:Command Timedout! slave_addr=0x%02X," + "reg=0x%02X, value=0x%02X", slave_addr, reg_addr, data); + return -ETIMEDOUT; + } + return 0; +} +EXPORT_SYMBOL(vc_send_command); + +/** + * @brief sr_vc_bypass - setup voltage using VC Bypass technique + * + * @param target_opp - target opp to go to + * @param current_opp - current opp + * @param target_vsel - which voltage to go to? + * @param current_vsel - current voltage + * + * @return -success or failure + */ +#ifdef CONFIG_OMAP_VC_BYPASS_UPDATE +static int sr_vc_bypass(struct omap_sr *sr, + u32 target_opp_no, u8 target_vsel, u8 current_vsel) +{ + int ret = 0; + struct omap_sr_vp *vp = &sr->vp; + u32 vpconfig_value; + + vpconfig_value = vp->vpconfig_value; + vpconfig_value |= + ((target_opp_no < + sr->opp_boundary) ? SR_ERRGAIN_LOWOP : SR_ERRGAIN_HIGHOPP) << + OMAP3430_ERRORGAIN_SHIFT; + vpconfig_value |= target_vsel << OMAP3430_INITVOLTAGE_SHIFT; + prm_write_mod_reg(vpconfig_value, OMAP3430_GR_MOD, + vp->prm_vpx_config_offset); + + prm_rmw_mod_reg_bits(OMAP3430_VC_CMD_ON_MASK, + (target_vsel << OMAP3430_VC_CMD_ON_SHIFT), + OMAP3430_GR_MOD, vp->prm_vc_cmd_val_offset); + + /* + * Various PMIC might need a set of commands + * provide hooks for specific PMICs to implement + */ + ret = omap_pmic_voltage_cmds(sr->srid, target_vsel); + + /* delay based on pmic */ + if (!ret) + udelay(omap_pmic_voltage_ramp_delay(sr->srid, + target_vsel, current_vsel)); + + WARN_ON(ret); + + return ret; +} +#endif /* ifdef CONFIG_OMAP_VC_BYPASS_UPDATE */ + +/********************* SR Private functions ***************************/ + +/** + * @brief sr_write_reg - write to Smart Reflex Register + * + * @param sr - pointer to SR structure + * @param offset - SR reg offset to write to + * @param value - value to write with + */ +static inline void sr_write_reg(struct omap_sr *sr, unsigned offset, u32 value) +{ + __raw_writel(value, SR_REGADDR(offset)); +} + +/** + * @brief sr_modify_reg - Modify a register and write a new value to a field + * + * @param sr -pointer to SR structure + * @param offset -register offset + * @param mask -mask to clear out + * @param value -value to write there + */ +static inline void sr_modify_reg(struct omap_sr *sr, unsigned offset, u32 mask, + u32 value) +{ + u32 reg_val; + + reg_val = __raw_readl(SR_REGADDR(offset)); + reg_val &= ~mask; + reg_val |= value; + + __raw_writel(reg_val, SR_REGADDR(offset)); +} + +/** + * @brief sr_read_reg - read a SR register + * + * @param sr - pointer to SR structure + * @param offset - register offset + * + * @return value in that register + */ +static inline u32 sr_read_reg(struct omap_sr *sr, unsigned offset) +{ + return __raw_readl(SR_REGADDR(offset)); +} + +/** + * @brief sr_vplimito_value -return the timeout value based on sysclk + * and desired timeout uSec + * + * @param sys_clk_speed - internal sysclk freq in hz + * @param timeout_us - timeout in uSec + * + * @return timeout value to use in VPLIMITTO:TIMEOUT reg + */ +static inline u32 sr_vplimito_value(u32 sys_clk_speed, u16 timeout_us) +{ + u32 timeout_val; + /* prevent round off errors, we will divide by 10 later */ + timeout_val = (sys_clk_speed / 100000); + timeout_val *= timeout_us; + timeout_val /= 10; + return timeout_val; +} + +/** + * @brief sr_clk_enable - SR clock enable + * + * @param sr - Structure to SR structure + * + * @return - result + */ +static int sr_clk_enable(struct omap_sr *sr) +{ + if (clk_enable(sr->iclk) != 0) { + pr_crit("SR:Could not enable %s for [%d]\n", + sr->iclk->name, sr->srid); + return -EINVAL; + } + if (clk_enable(sr->fclk) != 0) { + pr_crit("SR:Could not enable %s for [%d]\n", + sr->fclk->name, sr->srid); + clk_disable(sr->iclk); + return -EINVAL; + } + sr_modify_reg(sr, ERRCONFIG, + SR_CLKACTIVITY_MASK | ERRCONFIG_INTERRUPT_STATUS_MASK, + SR_CLKACTIVITY_IOFF_FON); + sr->is_sr_reset = 0; + + return 0; +} + +/** + * @brief sr_clk_disable - SR func clock disable + * + * @param sr - pointer to SR structure + */ +static void sr_clk_disable(struct omap_sr *sr) +{ + /* set fclk, iclk- idle */ + sr_modify_reg(sr, ERRCONFIG, + SR_CLKACTIVITY_MASK | ERRCONFIG_INTERRUPT_STATUS_MASK, + SR_CLKACTIVITY_IOFF_FOFF); + + clk_disable(sr->fclk); + clk_disable(sr->iclk); + sr->is_sr_reset = 1; +} + +/****************** Voltage processor functions ***************************/ + +/** + * @brief sr_vp_clear_vptransdone - clear vptrans_done event + * + * @param sr - sr pointer + * + * @return 0 if cleared ok, else 1 if timedout! + */ +static int sr_vp_clear_vptransdone(struct omap_sr *sr) +{ + struct omap_sr_vp *vp = &sr->vp; + u32 irqstat; + u32 count = COUNT_TIMEOUT_TRANSDONE_CLR; + do { + prm_write_mod_reg(vp->irqmask_trans_done, OCP_MOD, + OMAP3_PRM_IRQSTATUS_MPU_OFFSET); + irqstat = prm_read_mod_reg(OCP_MOD, + OMAP3_PRM_IRQSTATUS_MPU_OFFSET) & + vp->irqmask_trans_done; + if (irqstat) + udelay(1); + count--; + } while (count && irqstat); + if (!count) { + pr_crit("SR:VPTransdone[%d]:Timedout\n", sr->srid); + return -ETIMEDOUT; + } + return 0; +} + +/** + * @brief sr_vp_forceupdate - do a forceupdate method + * to update the voltage level + * + * @param sr - pointer to sr structure + * @param target_opp_no - targetted opp number + * @param target_vsel - targetted voltage level + * @param current_vsel - current voltage level + * + * @return 0 if all worked out, else 1 + */ +#ifndef CONFIG_OMAP_VC_BYPASS_UPDATE +static int sr_vp_forceupdate(struct omap_sr *sr, u32 target_opp_no, + u8 target_vsel, u8 current_vsel) +{ + u32 count; + u32 irqstat; + u32 vpconfig_value; + u32 retry_counter = COUNT_RETRY_SMPSNOACK; + + struct omap_sr_vp *vp = &sr->vp; + +retry_forceupdate: + /* First clear any pending events in the system */ + if (sr_vp_clear_vptransdone(sr)) { + pr_crit("SR:forceupdate-transdone1[%d]:timedout\n", sr->srid); + return -ETIMEDOUT; + } + + vpconfig_value = vp->vpconfig_value; + vpconfig_value |= + ((target_opp_no < + sr->opp_boundary) ? SR_ERRGAIN_LOWOP : SR_ERRGAIN_HIGHOPP) << + OMAP3430_ERRORGAIN_SHIFT; + vpconfig_value |= target_vsel << OMAP3430_INITVOLTAGE_SHIFT; + + prm_write_mod_reg(vpconfig_value, OMAP3430_GR_MOD, + vp->prm_vpx_config_offset); + + /* Trigger initVDD value copy to voltage processor */ + prm_set_mod_reg_bits(OMAP3430_INITVDD, OMAP3430_GR_MOD, + vp->prm_vpx_config_offset); + + /* Force update of voltage */ + prm_set_mod_reg_bits(OMAP3430_FORCEUPDATE, OMAP3430_GR_MOD, + vp->prm_vpx_config_offset); + + /* Clear initVDD copy trigger bit */ + prm_clear_mod_reg_bits(OMAP3430_INITVDD, OMAP3430_GR_MOD, + vp->prm_vpx_config_offset); + /* Clear force bit */ + prm_clear_mod_reg_bits(OMAP3430_FORCEUPDATE, OMAP3430_GR_MOD, + vp->prm_vpx_config_offset); + + /* Now wait for the i2c transactions to complete */ + count = COUNT_TIMEOUT_TRANSDONE_SET; + irqstat = 0; + do { + irqstat = prm_read_mod_reg(OCP_MOD, + OMAP3_PRM_IRQSTATUS_MPU_OFFSET) & + vp->irqmask_trans_done; + if (!irqstat) + udelay(1); + count--; + } while (count && !irqstat); + if (!count) { + irqstat = prm_read_mod_reg(OCP_MOD, + OMAP3_PRM_IRQSTATUS_MPU_OFFSET); + if (irqstat & vp->irqmask_smps_noack) { + WARN(irqstat, "SMPS NO ACK DETECTED[0x%08X]!!" + "ATTEMPTING RECOVERY [%d left]\n", + irqstat, retry_counter); + prm_write_mod_reg(irqstat, OCP_MOD, + OMAP3_PRM_IRQSTATUS_MPU_OFFSET); + retry_counter--; + if (retry_counter) + goto retry_forceupdate; + } + pr_crit("SR:forceupdate-transdone[%d]:timedout-" + "irqstat=0x%08X\n", sr->srid, irqstat); + BUG(); + return -ETIMEDOUT; + } + + /* + * Now we wait for voltage to rise on PMIC + */ + udelay(omap_pmic_voltage_ramp_delay(sr->srid, target_vsel, + current_vsel)); + + /* clear that event */ + if (sr_vp_clear_vptransdone(sr)) { + pr_crit("SR:forceupdate-transdone2[%d]:timedout\n", sr->srid); + BUG(); + return -ETIMEDOUT; + } + return 0; +} +#endif /* ifndef CONFIG_OMAP_VC_BYPASS_UPDATE */ + +/** + * @brief sr_vp_enable - enable VP enable code + * + * @param sr + */ +static int sr_vp_enable(struct omap_sr *sr, u32 target_opp_no) +{ + u32 vpconfig_value; + struct omap_sr_vp *vp = &sr->vp; + + /* Disable VP */ + prm_clear_mod_reg_bits(vp->vpenable_mask, OMAP3430_GR_MOD, + vp->prm_vpx_config_offset); + /* Clear INITVDD */ + prm_clear_mod_reg_bits(OMAP3430_INITVDD, OMAP3430_GR_MOD, + vp->prm_vpx_config_offset); + + vpconfig_value = vp->vpconfig_value; + vpconfig_value |= get_vsel_for_opp(sr, target_opp_no) << + OMAP3430_INITVOLTAGE_SHIFT; + vpconfig_value |= + ((target_opp_no < + sr->opp_boundary) ? SR_ERRGAIN_LOWOP : SR_ERRGAIN_HIGHOPP) << + OMAP3430_ERRORGAIN_SHIFT; + + prm_write_mod_reg(vpconfig_value, OMAP3430_GR_MOD, + vp->prm_vpx_config_offset); + + prm_write_mod_reg(vp->vpstepmin_value, OMAP3430_GR_MOD, + vp->prm_vpx_stepmin_offset); + prm_write_mod_reg(vp->vpstepmax_value, OMAP3430_GR_MOD, + vp->prm_vpx_stepmax_offset); + prm_write_mod_reg(vp->vplimito_value, OMAP3430_GR_MOD, + vp->prm_vpx_limito_offset); + + /* write1 to latch */ + prm_set_mod_reg_bits(OMAP3430_INITVDD, OMAP3430_GR_MOD, + vp->prm_vpx_config_offset); + /* write2 clear */ + prm_clear_mod_reg_bits(OMAP3430_INITVDD, OMAP3430_GR_MOD, + vp->prm_vpx_config_offset); + /* Enable VP */ + prm_set_mod_reg_bits(vp->vpenable_mask, OMAP3430_GR_MOD, + vp->prm_vpx_config_offset); + return 0; +} + +/** + * @brief sr_vp_disable - disbale Voltage processor + * + * @param sr - sr structure + * + * @return 0 if all ok, else return -ETIMEDOUT + */ +static int sr_vp_disable(struct omap_sr *sr) +{ + int count; + u32 v; + struct omap_sr_vp *vp = &sr->vp; + + v = prm_read_mod_reg(OMAP3430_GR_MOD, + vp->prm_vpx_config_offset) & vp->vpenable_mask; + /* Am i already disabled? */ + if (!v) { + pr_info("SR[%d] attempt to disable VP when already disabled!\n", + sr->srid); + return 0; + } + + /* Disable VP */ + prm_clear_mod_reg_bits(vp->vpenable_mask, OMAP3430_GR_MOD, + vp->prm_vpx_config_offset); + + /* Wait for vp to get idle - clear any events pending */ + count = COUNT_TIMEOUT_MCUDISACK; + do { + v = prm_read_mod_reg(OMAP3430_GR_MOD, + vp->prm_vpx_status_offset) & + PRM_VP_STATUS_VPINIDLE; + if (!v) + udelay(1); + count--; + } while (count && !v); + if (unlikely(!count)) { + v = prm_read_mod_reg(OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET); + pr_warning("SR[%d]:vpdisable-vpinidle[opp=%d]:timedout-" + "irqstat=0x%08X\n", sr->srid, sr->req_opp_no, v); + return -ETIMEDOUT; + } + return 0; +} + +/** + * @brief sr_vp_configure - configure the basic SR structure + * + * @param sr - pointer to SR structure + */ +static void sr_vp_configure(struct omap_sr *sr) +{ + u32 target_opp_no; + u32 target_vsel; + u32 prm_vpx_voltage; + + target_opp_no = get_current_opp_number_from_sr(sr); + target_vsel = get_vsel_for_opp(sr, target_opp_no); + prm_vpx_voltage = prm_read_mod_reg(OMAP3430_GR_MOD, + sr->vp.prm_vpx_voltage_offset); + sr_vp_enable(sr, target_opp_no); + if (SR_CHOSEN_VOLTAGE_UPDATE_MECH + (sr, target_opp_no, target_vsel, prm_vpx_voltage)) + pr_crit("SR[%d] CONFIGURE VP failed!!\n", sr->srid); +} + +/** + * @brief sr_vp_reset_voltage - reset the voltages back to DVFS values + * + * @param srid -SRID + * + * @return 0 if ok, else result + */ +static int sr_vp_reset_voltage(u8 srid) +{ + u32 target_opp_no; + u32 target_vsel; + u32 prm_vpx_voltage; + struct omap_sr *sr; + + sr = get_sr(srid); + target_opp_no = sr->req_opp_no; + target_vsel = get_vsel_for_opp(sr, target_opp_no); + prm_vpx_voltage = prm_read_mod_reg(OMAP3430_GR_MOD, + sr->vp.prm_vpx_voltage_offset); + return SR_CHOSEN_VOLTAGE_UPDATE_MECH(sr, target_opp_no, + target_vsel, prm_vpx_voltage); + +} + +/*********************** SR functions *************************/ + +/** + * @brief sr_enable - enable smart reflex + * + * @param sr - smartreflex structure we are interest + * @param target_opp_no - target opp we want to switch to + * + * @return 0 if all went right, else return err val + */ +static int sr_enable(struct omap_sr *sr, u32 target_opp_no) +{ + u32 value; + + if (!sr->is_sr_reset) { + pr_info("SR[%d]already enabled\n", sr->srid); + return -EINVAL; + } + + sr->req_opp_no = target_opp_no; + + value = sr->opp_nvalue[target_opp_no - 1]; + if (value == 0) { + pr_info("SR[%d]:OPP%d doesn't support SmartReflex\n", + sr->srid, target_opp_no); + return -EINVAL; + } + + sr_clk_enable(sr); + /* Start with setting SREnable as 0 */ + sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, 0); + + sr_write_reg(sr, SRCONFIG, sr->sr_config_value); + + sr_write_reg(sr, NVALUERECIPROCAL, value); + + value = sr->sr_errconfig_value | + ((target_opp_no < sr->opp_boundary) ? SR_ERRMINLIMIT_LOWOPP : + SR_ERRMINLIMIT_HIGHOPP); + + sr_write_reg(sr, ERRCONFIG, value); + + /* SRCONFIG - enable SR */ + sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, SRCONFIG_SRENABLE); + + return 0; +} + +/** + * @brief sr_disable - disable Smart Reflex + * + * @param sr - pointer to sr structure of interest + * + * @return 0 if all went right, else return INVAL/TIMEDOUT + */ +int sr_disable(struct omap_sr *sr) +{ + int count; + u32 stat; + u32 value; + + if (sr->is_sr_reset) { + pr_info("SR[%d]-disable:already Disabled\n", sr->srid); + return -EINVAL; + } + value = sr_read_reg(sr, SRCONFIG) & SRCONFIG_SRENABLE; + if (!value) { + pr_info("SR[%d] attempt to disable SR when already disabled!\n", + sr->srid); + return 0; + } + value = sr->opp_nvalue[sr->req_opp_no - 1]; + if (value == 0) { + pr_info("SR[%d]-disable:" + "OPP%d doesn't support SmartReflex\n", + sr->srid, sr->req_opp_no); + return -EINVAL; + } + /* Enable the MCUDISACKINST */ + sr_modify_reg(sr, ERRCONFIG, ERRCONFIG_MCUDISACKINTEN | + ERRCONFIG_INTERRUPT_STATUS_MASK, + ERRCONFIG_MCUDISACKINTEN); + + /* SRCONFIG - disable SR */ + sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, 0); + + /* Disable VPBOUND interrupt and clear any status + * before actually waiting for disack + * should be done after sr is disabled + */ + sr_modify_reg(sr, ERRCONFIG, ERRCONFIG_VPBOUNDINTEN | + ERRCONFIG_INTERRUPT_STATUS_MASK, ERRCONFIG_VPBOUNDINTST); + + /* Wait for MCUDISACKINTST to be set */ + count = COUNT_TIMEOUT_MCUDISACK; + do { + stat = sr_read_reg(sr, ERRCONFIG) & ERRCONFIG_MCUDISACKINTST; + if (!stat) + udelay(1); + count--; + } while (count && !stat); + /* Clear the event and disable MCUDISACKINST */ + sr_modify_reg(sr, ERRCONFIG, ERRCONFIG_MCUDISACKINTEN | + ERRCONFIG_INTERRUPT_STATUS_MASK, + ERRCONFIG_MCUDISACKINTST); + + if (!count) { + pr_crit("SR[%d]-disable:MCUDIS timedout\n", sr->srid); + return -ETIMEDOUT; + } + sr_clk_disable(sr); + return 0; +} + +/**************** Common enable/disable functionality *********************/ + +/** + * @brief srvp_disable - disable SR and VP + * These functions are based on h/w timeouts and should ideally not fail. + * + * @param sr -sr struct + * + * @return result + */ +static int srvp_disable(struct omap_sr *sr) +{ + int ret; + /* If we dont have an nvalue, dont bother.. */ + if (!sr->opp_nvalue[sr->req_opp_no - 1]) { + pr_warning("SR[%d]: OPP%d does not support SR to disable\n", + sr->srid, sr->req_opp_no); + return -EINVAL; + } + ret = sr_vp_disable(sr); + if (unlikely(ret)) { + pr_err("SR[%d]: failed to disable vp:%d\n", sr->srid, ret); + } else { + ret = sr_disable(sr); + if (unlikely(ret)) + pr_err("SR[%d]: failed to disable sr:%d\n", + sr->srid, ret); + } + /* + * Does not make much sense renabling SR as + * system is going to be in an invalid state + */ + WARN_ON(ret); + return ret; +} + +/** + * @brief srvp_enable - enable SR and VP + * These functions are based on h/w timeouts and should ideally not fail. + * + * @param sr -sr struct + * @param target_opp -opp to go to + * + * @return result + */ +static int srvp_enable(struct omap_sr *sr, u32 target_opp) +{ + int ret; + + /* If we dont have an nvalue, dont bother.. */ + if (!sr->opp_nvalue[target_opp - 1]) { + pr_warning("SR[%d]: OPP%d does not support SR to enable\n", + sr->srid, target_opp); + return -EINVAL; + } + ret = sr_vp_enable(sr, target_opp); + if (unlikely(ret)) { + pr_err("SR[%d]: failed to enable vp:%d\n", sr->srid, ret); + } else { + ret = sr_enable(sr, target_opp); + /* Attempt to recover */ + if (unlikely(ret)) { + pr_err("SR[%d]: failed to enable sr:%d\n", sr->srid, + ret); + /* nothing we can do if vp_disable fails */ + (void)sr_vp_disable(sr); + } + } + /* + * potentially system in an invalid state - warn.. + */ + WARN_ON(ret); + return ret; +} + +/*********************** DVFS Entry POINTS **********************************/ + +/** + * @brief sr_vp_enable_both - enable both vp and sr + * + * @param target_opp - targetted op + * @param current_opp - current opp + * + * @return 0 if ok, 1 if not ok + */ +int sr_vp_enable_both(u32 target_opp, u32 current_opp) +{ + struct omap_sr *sr; + u32 vdd, target_opp_no; + int ret = 0; + + vdd = get_vdd(target_opp); + target_opp_no = get_opp_no(target_opp); + sr = get_sr_from_vdd(vdd); + + if (sr->is_autocomp_active && sr->is_sr_reset) { + ret = srvp_enable(sr, target_opp_no); + if (ret) { + pr_err("SR[%d]:enableboth:" + "failed enable SR\n", sr->srid); + } + } + return ret; +} +EXPORT_SYMBOL(sr_vp_enable_both); + +/** + * @brief sr_vp_disable_both - disable both vp and sr + * + * @param target_opp - targetted opp + * @param current_opp - current opp + * + * @return 0 if ok, 1 if not ok + */ +int sr_vp_disable_both(u32 target_opp, u32 current_opp) +{ + struct omap_sr *sr; + u32 vdd; + int ret = 0; + + vdd = get_vdd(target_opp); + sr = get_sr_from_vdd(vdd); + + if (sr->is_autocomp_active && !sr->is_sr_reset) { + ret = srvp_disable(sr); + if (ret) { + pr_err("SR[%d]:disableboth:" + "failed disable SR\n", sr->srid); + } + } + + return ret; + +} +EXPORT_SYMBOL(sr_vp_disable_both); + +/** + * @brief sr_voltage_set - setup a voltage requested + * + * @param target_opp - targetted opp + * @param current_opp - current opp + * @param target_vsel - targeted voltage + * @param current_vsel - current voltage + * + * @return - result of op -0 if ok, else value + */ +int sr_voltage_set(u32 target_opp, u32 current_opp, + u8 target_vsel, u8 current_vsel) +{ + struct omap_sr *sr; + u8 vdd, target_opp_no; + int ret; + + vdd = get_vdd(target_opp); + target_opp_no = get_opp_no(target_opp); + sr = get_sr_from_vdd(vdd); + + ret = + SR_CHOSEN_VOLTAGE_UPDATE_MECH(sr, target_opp_no, target_vsel, + current_vsel); + + return ret; +} +EXPORT_SYMBOL(sr_voltage_set); + +/*********************** CPUIDLE ENTRY POINTS *********************************/ + +/** + * @brief disable_smartreflex - disable SmartReflex before WFI + * + * @param srid SRID + */ +void disable_smartreflex(u8 srid) +{ + struct omap_sr *sr = NULL; + int ret; + u32 current_opp_no; + + /* I want to be in irq_disabled context.. + * else I will die.. find the rootcause and fix it instead + */ + BUG_ON(!irqs_disabled()); + + sr = get_sr(srid); + + current_opp_no = get_current_opp_number_from_sr(sr); + + if (sr->is_autocomp_active && !sr->is_sr_reset) { + sr->req_opp_no = current_opp_no; + ret = srvp_disable(sr); + if (ret) + pr_err("SR[%d]:disable_smartreflex:" + "failed disable SR\n", sr->srid); + } + + /* Reset the voltage for current OPP to nominal if SR was enabled */ + if (sr->is_autocomp_active) + sr_vp_reset_voltage(srid); +} +EXPORT_SYMBOL(disable_smartreflex); + +/** + * @brief enable_smartreflex - enable smart reflex after WFI is hit + * + * @param srid -SR ID to hit + */ +void enable_smartreflex(u8 srid) +{ + struct omap_sr *sr; + int ret; + u32 current_opp_no; + + /* I want to be in irq_disabled context.. + * else I will die.. find the rootcause and fix it instead + */ + BUG_ON(!irqs_disabled()); + + sr = get_sr(srid); + current_opp_no = get_current_opp_number_from_sr(sr); + + if (sr->is_autocomp_active && sr->is_sr_reset) { + ret = srvp_enable(sr, current_opp_no); + if (ret) + pr_err("SR[%d]:enable_smartreflex:" + "failed enable SR\n", sr->srid); + } +} +EXPORT_SYMBOL(enable_smartreflex); + +/*********************** SYSFS ENTRY POINTS *********************************/ +/** + * @brief omap_sr_vdd_autocomp_show - Sysfs entry for showing SR status + * + */ +static ssize_t omap_sr_vdd_autocomp_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct omap_sr *sr; + sr = get_sr_from_vdd_name((char *)attr->attr.name); + return sprintf(buf, "%d\n", sr->is_autocomp_active); +} + +/** + * @brief omap_sr_vdd_autocomp_store - enable/disable SR + * + */ +static ssize_t omap_sr_vdd_autocomp_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t n) +{ + unsigned short value; + struct omap_sr *sr; + int ret = 0; + char *name; + + name = (char *)attr->attr.name; + + sr = get_sr_from_vdd_name(name); + + if (sscanf(buf, "%hu", &value) != 1 || (value > 1)) { + pr_err("%s: Invalid value[%d]. Use 0 or 1\n", name, value); + return -EINVAL; + } + if (sr->is_autocomp_active == value) { + pr_info("%s: Already set to %d \n", name, value); + return n; + } + /* + * Sanity check-might happen if SR and dvfs/idle paths collide + * but unlikely though.. + */ + if (unlikely(value ^ sr->is_sr_reset)) { + pr_warning("%s: Is already set %d Vs %d.\n", name, value, + sr->is_sr_reset); + return n; + } + + if (value) { + u32 current_vddopp_no = get_current_opp_number_from_sr(sr); + ret = srvp_enable(sr, current_vddopp_no); + } else { + ret = srvp_disable(sr); + /* reset the voltage back to nominal */ + sr_vp_configure(sr); + } + if (!ret) { + sr->is_autocomp_active = value; + ret = n; + } + + return ret; +} + +/*********************** INIT FUNCTIONS *************************************/ + +/** + * @brief srvp_init - configure smart reflex and VP params + * + * @param sr - structure of sr of interest + */ +static void __init srvp_init(struct omap_sr *sr) +{ + struct clk *sys_ck; + u32 sys_clk_speed; + u32 clk_len; + u32 senn_mod, senp_mod; + u8 opp_count; + + /* Grab the clock speed */ + sys_ck = clk_get(NULL, "sys_ck"); + sys_clk_speed = clk_get_rate(sys_ck); + clk_put(sys_ck); + + switch (sys_clk_speed) { + case 12000000: + clk_len = SRCLKLENGTH_12MHZ_SYSCLK; + break; + case 13000000: + clk_len = SRCLKLENGTH_13MHZ_SYSCLK; + break; + case 19200000: + clk_len = SRCLKLENGTH_19MHZ_SYSCLK; + break; + case 26000000: + clk_len = SRCLKLENGTH_26MHZ_SYSCLK; + break; + case 38400000: + clk_len = SRCLKLENGTH_38MHZ_SYSCLK; + break; + default: + pr_err("SR[%d]:Invalid sysclk value: %d\n", sr->srid, + sys_clk_speed); + BUG(); + return; + } + /* The original nvalue contents were the register offsets + * now we replace them with the nvalue to be used elsewhere + */ + for (opp_count = 0; opp_count < sr->num_opp; opp_count++) + sr->opp_nvalue[opp_count] = + omap_ctrl_readl(sr->opp_nvalue[opp_count]); + + sr->vp.vplimito_value |= sr_vplimito_value(sys_clk_speed, + sr->vp.prm_vpx_vlimito_timeout) + << sr->vp.prm_vpx_vlimito_shift; + senn_mod = (omap_ctrl_readl(OMAP343X_CONTROL_FUSE_SR) & + sr->sr_n_mod_mask) >> sr->sr_n_mod_shift; + senp_mod = (omap_ctrl_readl(OMAP343X_CONTROL_FUSE_SR) & + sr->sr_p_mod_mask) >> sr->sr_p_mod_shift; + sr->sr_config_value = + (clk_len << SRCONFIG_SRCLKLENGTH_SHIFT) | SRCONFIG_ERRGEN_EN | + SRCONFIG_SENENABLE | (senn_mod << SRCONFIG_SENNENABLE_SHIFT) | + (senp_mod << SRCONFIG_SENPENABLE_SHIFT) | SRCONFIG_DELAYCTRL; + + /* Set up nominal voltage */ + sr_vp_configure(sr); +} + +/** + * @brief omap_sr_init - SR initialization + * + * @return 0 + */ +static int __init omap_sr_init(void) +{ + int ret = 0; + int i; + ret = omap_pmic_srinit(); + if (ret) { + pr_crit("PMIC init failed during SmartReflex initilization." + "connectivity issues?: %d\n", ret); + return ret; + } + if (cpu_is_omap3430()) { + omap_srlist = kzalloc(sizeof(omap34xx_srlist), GFP_KERNEL); + if (!omap_srlist) { + ret = -ENOMEM; + goto fail_cleanup; + } + omap_srlist->num_sr = omap34xx_srlist.num_sr; + for (i = 0; i < omap_srlist->num_sr; i++) { + int size = sizeof(*omap34xx_srlist.sr_list[i]); + size += + sizeof(u32) * omap34xx_srlist.sr_list[i]->num_opp; + omap_srlist->sr_list[i] = kzalloc(size, GFP_KERNEL); + if (!omap_srlist->sr_list[i]) { + ret = -ENOMEM; + goto fail_cleanup; + } + memcpy(omap_srlist->sr_list[i], + omap34xx_srlist.sr_list[i], size); + } + } else { + pr_warning("SmartReflex is not supported on this OMAP\n"); + return -ENODEV; + } + + /* Create the userspace control knobs */ + for (i = 0; i < omap_srlist->num_sr; i++) { + struct omap_sr *sr = get_sr(i + 1); + sr->fclk = clk_get(NULL, sr->fclk_name); + sr->iclk = clk_get(NULL, sr->iclk_name); + sr->srbase_addr = ioremap((u32) sr->srbase_addr, SZ_4K); + srvp_init(sr); + if (sysfs_create_file(power_kobj, &sr->autocom_attr.attr)) + pr_warning("SR: sysfs_create_file failed[%d]: %d\n", i, + ret); + } + if (sr_debugfs_create_entries_late()) + pr_warning("SR: debugfs_create_file failed\n"); + + pr_info("SmartReflex driver initialized\n"); + return 0; +fail_cleanup: + pr_warning("Out of memory..SmartReflex not initialized\n"); + if (omap_srlist) { + /* kfree is nullsafe */ + for (i = 0; i < omap_srlist->num_sr; i++) + kfree(omap_srlist->sr_list[i]); + kfree(omap_srlist); + } + return ret; +} +late_initcall(omap_sr_init); diff --git a/arch/arm/mach-omap2/smartreflex.h b/arch/arm/mach-omap2/smartreflex.h new file mode 100644 index 0000000..421f8b6 --- /dev/null +++ b/arch/arm/mach-omap2/smartreflex.h @@ -0,0 +1,274 @@ +#ifndef __ARCH_ARM_MACH_OMAP3_SMARTREFLEX_H +#define __ARCH_ARM_MACH_OMAP3_SMARTREFLEX_H +/* + * linux/arch/arm/mach-omap2/smartreflex.h + * + * Copyright (C) 2009 Texas Instruments, Inc. + * Nishanth Menon + * + * Copyright (C) 2008 Nokia Corporation + * Kalle Jokiniemi + * + * Copyright (C) 2007 Texas Instruments, Inc. + * Lesly A M <x0080970@ti.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* SMART REFLEX REG ADDRESS OFFSET */ +#define SRCONFIG 0x00 +#define SRSTATUS 0x04 +#define SENVAL 0x08 +#define SENMIN 0x0C +#define SENMAX 0x10 +#define SENAVG 0x14 +#define AVGWEIGHT 0x18 +#define NVALUERECIPROCAL 0x1C +#define SENERROR 0x20 +#define ERRCONFIG 0x24 + +/* SR Modules */ +#define SR1 1 +#define SR2 2 + +#define VP1_IRQMASK_TRANSDONE (0x1 << 15) +#define VP2_IRQMASK_TRANSDONE (0x1 << 21) + +/* PRM_VP1_CONFIG */ +#define PRM_VP1_CONFIG_ERROROFFSET (0x00 << 24) +#define PRM_VP1_CONFIG_ERRORGAIN (0x18 << 16) +#define SR_ERRGAIN_LOWOP (0x0C) +#define SR_ERRGAIN_HIGHOPP (0x18) +#define SR_ERRMINLIMIT_LOWOPP (0xF4 << 0) +#define SR_ERRMINLIMIT_HIGHOPP (0xF9 << 0) +#define PRM_VP_STATUS_VPINIDLE (0x1 << 0) + +#define PRM_VP1_CONFIG_INITVOLTAGE (0x30 << 8) /* 1.2 volt */ +#define PRM_VP1_CONFIG_TIMEOUTEN (0x1 << 3) +#define PRM_VP1_CONFIG_INITVDD (0x1 << 2) +#define PRM_VP1_CONFIG_FORCEUPDATE (0x1 << 1) +#define PRM_VP1_CONFIG_VPENABLE (0x1 << 0) + +/* PRM_VP1_VSTEPMIN */ +#define PRM_VP1_VSTEPMIN_SMPSWAITTIMEMIN (0x03C << 8) +#define PRM_VP1_VSTEPMIN_VSTEPMIN (0x01 << 0) + +/* PRM_VP1_VSTEPMAX */ +#define PRM_VP1_VSTEPMAX_SMPSWAITTIMEMAX (0x003C << 8) +#define PRM_VP1_VSTEPMAX_VSTEPMAX (0x08 << 0) + +/* PRM_VP1_VLIMITTO */ +#define PRM_VP1_VLIMITTO_VDDMAX (0x44 << 24) +#define PRM_VP1_VLIMITTO_VDDMIN (0x14 << 16) +#define PRM_VP1_VLIMITTO_TIMEOUT_US (200) +#define PRM_VP1_VLIMITTO_TIMEOUT_SHIFT (0) + +/* PRM_VP2_CONFIG */ +#define PRM_VP2_CONFIG_ERROROFFSET (0x00 << 24) +#define PRM_VP2_CONFIG_ERRORGAIN (0x18 << 16) + +#define PRM_VP2_CONFIG_INITVOLTAGE (0x30 << 8) /* 1.2 volt */ +#define PRM_VP2_CONFIG_TIMEOUTEN (0x1 << 3) +#define PRM_VP2_CONFIG_INITVDD (0x1 << 2) +#define PRM_VP2_CONFIG_FORCEUPDATE (0x1 << 1) +#define PRM_VP2_CONFIG_VPENABLE (0x1 << 0) + +/* PRM_VP2_VSTEPMIN */ +#define PRM_VP2_VSTEPMIN_SMPSWAITTIMEMIN (0x03C << 8) +#define PRM_VP2_VSTEPMIN_VSTEPMIN (0x01 << 0) + +/* PRM_VP2_VSTEPMAX */ +#define PRM_VP2_VSTEPMAX_SMPSWAITTIMEMAX (0x003C << 8) +#define PRM_VP2_VSTEPMAX_VSTEPMAX (0x08 << 0) + +/* PRM_VP2_VLIMITTO */ +#define PRM_VP2_VLIMITTO_VDDMAX (0x42 << 24) +#define PRM_VP2_VLIMITTO_VDDMIN (0x18 << 16) +#define PRM_VP2_VLIMITTO_TIMEOUT_US (200) +#define PRM_VP2_VLIMITTO_TIMEOUT_SHIFT (0) + +/* SRCONFIG */ +#define SRCLKLENGTH_12MHZ_SYSCLK 0x3C +#define SRCLKLENGTH_13MHZ_SYSCLK 0x41 +#define SRCLKLENGTH_19MHZ_SYSCLK 0x60 +#define SRCLKLENGTH_26MHZ_SYSCLK 0x82 +#define SRCLKLENGTH_38MHZ_SYSCLK 0xC0 + +#define SRCONFIG_SRCLKLENGTH_SHIFT 12 +#define SRCONFIG_SENNENABLE_SHIFT 5 +#define SRCONFIG_SENPENABLE_SHIFT 3 + +#define SRCONFIG_SRENABLE (0x01 << 11) +#define SRCONFIG_SENENABLE (0x01 << 10) +#define SRCONFIG_ERRGEN_EN (0x01 << 9) +#define SRCONFIG_MINMAXAVG_EN (0x01 << 8) + +#define SRCONFIG_DELAYCTRL (0x01 << 2) +#define SRCONFIG_CLKCTRL (0x00 << 0) + +/* NVALUERECIPROCAL */ +#define NVALUERECIPROCAL_SENPGAIN_SHIFT 20 +#define NVALUERECIPROCAL_SENNGAIN_SHIFT 16 +#define NVALUERECIPROCAL_RNSENP_SHIFT 8 +#define NVALUERECIPROCAL_RNSENN_SHIFT 0 + +/* ERRCONFIG */ +#define SR_CLKACTIVITY_MASK (0x03 << 20) +#define SR_ERRWEIGHT_MASK (0x07 << 16) +#define SR_ERRMAXLIMIT_MASK (0xFF << 8) +#define SR_ERRMINLIMIT_MASK (0xFF << 0) + +#define SR_CLKACTIVITY_IOFF_FOFF (0x00 << 20) +#define SR_CLKACTIVITY_IOFF_FON (0x02 << 20) + +#define ERRCONFIG_VPBOUNDINTEN (0x1 << 31) +#define ERRCONFIG_MCUDISACKINTEN (0x1 << 23) + +/* Status Bits */ +#define ERRCONFIG_VPBOUNDINTST (0x1 << 30) +#define ERRCONFIG_MCUACCUMINTST (0x1 << 28) +#define ERRCONFIG_MCUVALIDINTST (0x1 << 26) +#define ERRCONFIG_MCUBOUNDINTST (0x1 << 24) +#define ERRCONFIG_MCUDISACKINTST (0x1 << 22) + +/* WARNING: Ensure all access to errconfig register skips + * clearing intst bits to ensure that we dont clear status + * bits unwantedly.. esp vpbound + */ +#define ERRCONFIG_INTERRUPT_STATUS_MASK (ERRCONFIG_VPBOUNDINTST |\ + ERRCONFIG_MCUACCUMINTST |\ + ERRCONFIG_MCUVALIDINTST |\ + ERRCONFIG_MCUBOUNDINTST |\ + ERRCONFIG_MCUDISACKINTST | (0X1<<19)) + +#define SR1_ERRWEIGHT (0x04 << 16) +#define SR1_ERRMAXLIMIT (0x02 << 8) +#define SR1_ERRMINLIMIT (0xFA << 0) + +#define SR2_ERRWEIGHT (0x04 << 16) +#define SR2_ERRMAXLIMIT (0x02 << 8) +#define SR2_ERRMINLIMIT (0xFA << 0) + +/* T2 SMART REFLEX */ +#define R_SRI2C_SLAVE_ADDR 0x12 +#define R_VDD1_SR_CONTROL 0x00 +#define R_VDD2_SR_CONTROL 0x01 + +/* VDDs*/ +#define PRCM_VDD1 1 +#define PRCM_VDD2 2 + +/* + * XXX: These should be removed/moved from here once we have a working DVFS + * implementation in place + */ +#define PHY_TO_OFF_PM_MASTER(p) (p - 0x36) +#define PHY_TO_OFF_PM_RECIEVER(p) (p - 0x5b) +#define PHY_TO_OFF_PM_INT(p) (p - 0x2e) + +/* Vmode control */ +#define R_DCDC_GLOBAL_CFG PHY_TO_OFF_PM_RECIEVER(0x61) +/* R_DCDC_GLOBAL_CFG register, SMARTREFLEX_ENABLE values */ +#define DCDC_GLOBAL_CFG_ENABLE_SRFLX 0x08 + +/* DEVICE ID/DPLL ID/CLOCK ID: bits 28-31 for OMAP type */ +#define OMAP_TYPE_SHIFT 28 +#define OMAP_TYPE_MASK 0xF +/* OPP ID: bits: 0-4 for OPP number */ +#define OPP_NO_POS 0 +#define OPP_NO_MASK 0x1F +/* OPP ID: bits: 5-6 for VDD */ +#define VDD_NO_POS 5 +#define VDD_NO_MASK 0x3 +/* Other IDs: bits 20-27 for ID type */ +/* These IDs have bits 25,26,27 as 1 */ +#define OTHER_ID_TYPE_SHIFT 20 +#define OTHER_ID_TYPE_MASK 0xFF + +#define OTHER_ID_TYPE(X) ((X & OTHER_ID_TYPE_MASK) << OTHER_ID_TYPE_SHIFT) +#define ID_OPP_NO(X) ((X & OPP_NO_MASK) << OPP_NO_POS) +#define ID_VDD(X) ((X & VDD_NO_MASK) << VDD_NO_POS) +#define OMAP(X) ((X >> OMAP_TYPE_SHIFT) & OMAP_TYPE_MASK) +#define get_opp_no(X) ((X >> OPP_NO_POS) & OPP_NO_MASK) +#define get_vdd(X) ((X >> VDD_NO_POS) & VDD_NO_MASK) + +/* XXX: end remove/move */ + +/* XXX: find more appropriate place for these once DVFS is in place */ +extern u32 current_vdd1_opp; +extern u32 current_vdd2_opp; + +/* + * Smartreflex module enable/disable interface. + * NOTE: if smartreflex is not enabled from sysfs, these functions will not + * do anything. + */ +#ifdef CONFIG_OMAP_SMARTREFLEX +void enable_smartreflex(u8 srid); +void disable_smartreflex(u8 srid); +int sr_voltage_set(u32 target_opp, u32 current_opp, + u8 target_vsel, u8 current_vsel); +int sr_vp_disable_both(u32 target_opp, u32 current_opp); +int sr_vp_enable_both(u32 target_opp, u32 current_opp); +int vc_send_command(u8 slave_addr, u8 reg_addr, u8 data, u16 *timeout_us); +int omap_pmic_srinit(void); +u32 omap_pmic_voltage_ramp_delay(u8 srid, u8 target_vsel, u8 current_vsel); +#ifdef CONFIG_OMAP_VC_BYPASS_UPDATE +int omap_pmic_voltage_cmds(u8 srid, u8 target_vsel); +#endif + +#ifdef CONFIG_PM_DEBUG +#define __SR_DEBUG +#endif + +#else +static inline void enable_smartreflex(u8 srid) +{ +} + +static inline void disable_smartreflex(u8 srid) +{ +} + +static inline int sr_voltage_set(u32 target_opp, u32 current_opp, + u8 target_vsel, u8 current_vsel) +{ + return -EINVAL; +} + +static inline int sr_vp_disable_both(u32 target_opp, u32 current_opp) +{ + return -EINVAL; +} + +static inline int sr_vp_enable_both(u32 target_opp, u32 current_opp) +{ + return -EINVAL; +} + +static inline int vc_send_command(u8 slave_addr, u8 reg_addr, u8 data, + u16 *timeout_us) +{ + return -EINVAL; +} + +#ifdef CONFIG_OMAP_VC_BYPASS_UPDATE +static inline int omap_pmic_voltage_cmds(u8 srid, u8 target_vsel) +{ + return -EINVAL; +} +#endif +#endif + +#ifdef __SR_DEBUG +int sr_debugfs_create_entries(struct dentry *d); +#else +static inline int sr_debugfs_create_entries(struct dentry *d) +{ + return -EINVAL; +} +#endif + +#endif /* __ARCH_ARM_MACH_OMAP3_SMARTREFLEX_H */ diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig index 2143db5..6a3302c 100644 --- a/arch/arm/plat-omap/Kconfig +++ b/arch/arm/plat-omap/Kconfig @@ -81,19 +81,14 @@ config OMAP_SMARTREFLEX 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" +config OMAP_VC_BYPASS_UPDATE + bool "Use VC Bypass method of updating voltage" 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! + Say Y if you would like to use VC Bypass method of + update. If this is disabled, the default + VP forceupdate method is used. config OMAP_RESET_CLOCKS bool "Reset unused clocks during boot" -- 1.6.3.3 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply related [flat|nested] 16+ messages in thread
* RE: [PATCH 2/2 v3] OMAP3: PM: SR: SmartReflex Refactor Rev4.0 2009-10-24 5:15 ` [PATCH 2/2 v3] OMAP3: PM: SR: SmartReflex Refactor Rev4.0 Nishanth Menon @ 2009-10-25 22:12 ` Cousson, Benoit 2009-10-25 22:59 ` Nishanth Menon [not found] ` <E0D41E29EB0DAC4E9F3FF173962E9E940253EFE01B@dbde02.ent.ti.com> ` (2 subsequent siblings) 3 siblings, 1 reply; 16+ messages in thread From: Cousson, Benoit @ 2009-10-25 22:12 UTC (permalink / raw) To: Menon, Nishanth, linux-omap@vger.kernel.org Cc: Imberton Guilhem, Mike Chan, Nayak, Rajendra, Roger Quadros, Kalle Jokiniemi, Reddy, Teerth, Kevin Hilman, Paul Walmsley, Hogander Jouni, Sabatier, Sebastien Hi Nishanth, > From: linux-omap-owner@vger.kernel.org [mailto:linux-omap- > owner@vger.kernel.org] On Behalf Of Menon, Nishanth > > Refactor the smart reflex implementation. [snip] > diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach- > omap2/smartreflex.c > new file mode 100644 > index 0000000..d506896 > --- /dev/null > +++ b/arch/arm/mach-omap2/smartreflex.c > @@ -0,0 +1,1604 @@ > +/* > + * linux/arch/arm/mach-omap3/smartreflex.c > + * > + * OMAP34XX SmartReflex Voltage Control > + * > + * Copyright (C) 2009 Texas Instruments, Inc. > + * Nishanth Menon > + * > + * Copyright (C) 2008 Nokia Corporation > + * Kalle Jokiniemi > + * > + * Copyright (C) 2007 Texas Instruments, Inc. > + * Lesly A M <x0080970@ti.com> > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License version 2 as > + * published by the Free Software Foundation. > + */ > + > +#include <linux/kernel.h> > +#include <linux/init.h> > +#include <linux/interrupt.h> > +#include <linux/module.h> > +#include <linux/delay.h> > +#include <linux/err.h> > +#include <linux/clk.h> > +#include <linux/sysfs.h> > +#include <linux/kobject.h> > +#include <linux/i2c/twl4030.h> > +#include <linux/io.h> > +#include <linux/debugfs.h> > + > +#include <plat/omap34xx.h> > +#include <plat/control.h> > +#include <plat/clock.h> > +#include <plat/omap-pm.h> > +#include <plat/resource.h> > +#include <plat/powerdomain.h> > + > +#include "prm.h" > +#include "smartreflex.h" > +#include "prm-regbits-34xx.h" > + > +/* MCUDISACK is expected to happen within 1uSec. */ > +#define COUNT_TIMEOUT_MCUDISACK 200 > + > +/* VPINIDLE is expected to happen within 100uSec. Typical is 2uSec */ > +#define COUNT_TIMEOUT_VPINIDLE 200 > + > +/* Time taken for setting the device - worst case as FS I2C > + * Depends on SMPSWAITIME MIN/MAX Typical is 200uSec > + */ > +#define COUNT_TIMEOUT_TRANSDONE_SET 400 > + > +/* Time to clear out multiple transdone events typical is 3uSec */ > +#define COUNT_TIMEOUT_TRANSDONE_CLR 50 > + > +/* Time For VCBypass mode for TWL4030 derivative chip. */ > +#define COUNT_TIMEOUT_TWL4030_VCBYPASS 500 > + > +/* How many retries to do for I2C errors seen on bus for Forceupdate? */ > +#define COUNT_RETRY_SMPSNOACK 4 > + > +#define SR_REGADDR(offset) (sr->srbase_addr + (offset)) > + > +/* Which function to use for setting voltage */ > +#ifdef CONFIG_OMAP_VC_BYPASS_UPDATE > +#define SR_CHOSEN_VOLTAGE_UPDATE_MECH sr_vc_bypass > +#else > +#define SR_CHOSEN_VOLTAGE_UPDATE_MECH sr_vp_forceupdate > +#endif > + > +#ifdef CONFIG_OMAP_PM_NONE > +struct omap_opp *mpu_opps; > +struct omap_opp *dsp_opps; > +struct omap_opp *l3_opps; > +#endif > + > +static ssize_t omap_sr_vdd_autocomp_show(struct kobject *kobj, > + struct kobj_attribute *attr, > + char *buf); > +static ssize_t omap_sr_vdd_autocomp_store(struct kobject *kobj, > + struct kobj_attribute *attr, > + const char *buf, size_t n); > +/* Structure for Voltage processor */ > +struct omap_sr_vp { > + /* Store the commonly used register offsets. > + * this saves a if condition decision > + */ > + u16 prm_vpx_status_offset; > + u16 prm_vpx_config_offset; > + u16 prm_vpx_stepmin_offset; > + u16 prm_vpx_stepmax_offset; > + u16 prm_vpx_limito_offset; > + u32 prm_vpx_vlimito_timeout; > + u8 prm_vpx_vlimito_shift; > + u16 prm_vpx_voltage_offset; > + u16 prm_vc_cmd_val_offset; > + /* Store the defaults > + * allowing us to save OCP read > + * operation > + */ > + u32 vpconfig_value; > + u32 vpstepmin_value; > + u32 vpstepmax_value; > + u32 vplimito_value; > + u32 vpenable_mask; > + u32 irqmask_trans_done; > + u32 irqmask_smps_noack; > +}; > + > +/* Structure for Smart Reflex */ > +struct omap_sr { > + u8 srid; > + u8 prcm_vdd; > + char *vdd_name; > + struct kobj_attribute autocom_attr; > + struct omap_opp **omap_opp; > + /* SR activity marker */ > + u8 is_sr_reset; > + u8 is_autocomp_active; > + u32 req_opp_no; > + u32 sr_config_value; > + u32 sr_errconfig_value; > + u32 sr_n_mod_mask; > + u8 sr_n_mod_shift; > + u32 sr_p_mod_mask; > + u8 sr_p_mod_shift; > + struct clk *fclk; > + struct clk *iclk; > + void __iomem *srbase_addr; > + char *iclk_name; > + char *fclk_name; > + /* Voltage processor for the specific SR module */ > + struct omap_sr_vp vp; > + /* This will contain the register offset on > + * boot, replaced with the actual value > + * as part of init routine > + */ > + u8 num_opp; > + u8 opp_boundary; > + u32 opp_nvalue[]; > +}; > + > +/* A superset of all SRs in the system ordered by SRID */ > +struct omap_sr_list { > + u8 num_sr; > + struct omap_sr *sr_list[]; > +}; > + > +/* Definitions for 3430 Silicon */ > +/* Smart Reflex 1 structure */ > +static __initdata struct omap_sr omap34xx_sr1 = { > + /* *INDENT-OFF* */ > + .srid = SR1, > + .prcm_vdd = PRCM_VDD1, > + .vdd_name = "vdd1_opp", > + .omap_opp = &mpu_opps, > + .autocom_attr = { > + .attr = { > + .name = __stringify(sr_vdd1_autocomp), > + .mode = 0644, > + }, > + .show = omap_sr_vdd_autocomp_show, > + .store = omap_sr_vdd_autocomp_store, > + }, > + .is_sr_reset = 1, > + .is_autocomp_active = 0, > + .srbase_addr = (void *)OMAP34XX_SR1_BASE, > + .fclk_name = "sr1_fck", > + .iclk_name = "sr_l4_ick", > + .sr_errconfig_value = SR1_ERRWEIGHT | SR1_ERRMAXLIMIT | > + ERRCONFIG_VPBOUNDINTEN | ERRCONFIG_VPBOUNDINTST | > + SR_CLKACTIVITY_IOFF_FON, > + .sr_n_mod_mask = OMAP343X_SR1_SENNENABLE_MASK, > + .sr_n_mod_shift = OMAP343X_SR1_SENNENABLE_SHIFT, > + .sr_p_mod_mask = OMAP343X_SR1_SENPENABLE_MASK, > + .sr_p_mod_shift = OMAP343X_SR1_SENPENABLE_SHIFT, > + .vp = { > + .prm_vpx_status_offset = OMAP3_PRM_VP1_STATUS_OFFSET, > + .prm_vpx_config_offset = OMAP3_PRM_VP1_CONFIG_OFFSET, > + .prm_vpx_stepmin_offset = OMAP3_PRM_VP1_VSTEPMIN_OFFSET, > + .prm_vpx_stepmax_offset = OMAP3_PRM_VP1_VSTEPMAX_OFFSET, > + .prm_vpx_limito_offset = OMAP3_PRM_VP1_VLIMITTO_OFFSET, > + .prm_vpx_vlimito_timeout = PRM_VP1_VLIMITTO_TIMEOUT_US, > + .prm_vpx_vlimito_shift = PRM_VP1_VLIMITTO_TIMEOUT_SHIFT, > + .prm_vpx_voltage_offset = OMAP3_PRM_VP1_VOLTAGE_OFFSET, > + .prm_vc_cmd_val_offset = OMAP3_PRM_VC_CMD_VAL_0_OFFSET, > + .vpconfig_value = PRM_VP1_CONFIG_ERROROFFSET | > + PRM_VP1_CONFIG_TIMEOUTEN, > + .vpstepmin_value = PRM_VP1_VSTEPMIN_SMPSWAITTIMEMIN | > + PRM_VP1_VSTEPMIN_VSTEPMIN, > + .vpstepmax_value = PRM_VP1_VSTEPMAX_SMPSWAITTIMEMAX | > + PRM_VP1_VSTEPMAX_VSTEPMAX, > + .vplimito_value = PRM_VP1_VLIMITTO_VDDMAX | > + PRM_VP1_VLIMITTO_VDDMIN, > + .vpenable_mask = PRM_VP1_CONFIG_VPENABLE, > + .irqmask_trans_done = VP1_IRQMASK_TRANSDONE, > + .irqmask_smps_noack = OMAP3430_VP1_NOSMPSACK_ST, > + }, > + .num_opp = 5, > + .opp_boundary = 3, > + .opp_nvalue = { > + OMAP343X_CONTROL_FUSE_OPP1_VDD1, > + OMAP343X_CONTROL_FUSE_OPP2_VDD1, > + OMAP343X_CONTROL_FUSE_OPP3_VDD1, > + OMAP343X_CONTROL_FUSE_OPP4_VDD1, > + OMAP343X_CONTROL_FUSE_OPP5_VDD1, > + }, > + /* *INDENT-ON* */ > +}; > + > +/* Smart Reflex 2 structure */ > +static __initdata struct omap_sr omap34xx_sr2 = { > + /* *INDENT-OFF* */ > + .srid = SR2, > + .prcm_vdd = PRCM_VDD2, > + .vdd_name = "vdd2_opp", > + .omap_opp = &l3_opps, > + .autocom_attr = { > + .attr = { > + .name = __stringify(sr_vdd2_autocomp), > + .mode = 0644, > + }, > + .show = omap_sr_vdd_autocomp_show, > + .store = omap_sr_vdd_autocomp_store, > + }, > + .is_sr_reset = 1, > + .is_autocomp_active = 0, > + .srbase_addr = (void *)OMAP34XX_SR2_BASE, > + .fclk_name = "sr2_fck", > + .iclk_name = "sr_l4_ick", > + .sr_errconfig_value = SR2_ERRWEIGHT | SR2_ERRMAXLIMIT | > + ERRCONFIG_VPBOUNDINTEN | ERRCONFIG_VPBOUNDINTST | > + SR_CLKACTIVITY_IOFF_FON, > + .sr_n_mod_mask = OMAP343X_SR2_SENNENABLE_MASK, > + .sr_n_mod_shift = OMAP343X_SR2_SENNENABLE_SHIFT, > + .sr_p_mod_mask = OMAP343X_SR2_SENPENABLE_MASK, > + .sr_p_mod_shift = OMAP343X_SR2_SENPENABLE_SHIFT, > + .vp = { > + .prm_vpx_status_offset = OMAP3_PRM_VP2_STATUS_OFFSET, > + .prm_vpx_config_offset = OMAP3_PRM_VP2_CONFIG_OFFSET, > + .prm_vpx_stepmin_offset = OMAP3_PRM_VP2_VSTEPMIN_OFFSET, > + .prm_vpx_stepmax_offset = OMAP3_PRM_VP2_VSTEPMAX_OFFSET, > + .prm_vpx_limito_offset = OMAP3_PRM_VP2_VLIMITTO_OFFSET, > + .prm_vpx_vlimito_timeout = PRM_VP2_VLIMITTO_TIMEOUT_US, > + .prm_vpx_vlimito_shift = PRM_VP2_VLIMITTO_TIMEOUT_SHIFT, > + .prm_vpx_voltage_offset = OMAP3_PRM_VP1_VOLTAGE_OFFSET, > + .prm_vc_cmd_val_offset = OMAP3_PRM_VC_CMD_VAL_1_OFFSET, > + .vpconfig_value = PRM_VP2_CONFIG_ERROROFFSET | > + PRM_VP2_CONFIG_TIMEOUTEN, > + .vpstepmin_value = PRM_VP2_VSTEPMIN_SMPSWAITTIMEMIN | > + PRM_VP2_VSTEPMIN_VSTEPMIN, > + .vpstepmax_value = PRM_VP2_VSTEPMAX_SMPSWAITTIMEMAX | > + PRM_VP2_VSTEPMAX_VSTEPMAX, > + .vplimito_value = PRM_VP2_VLIMITTO_VDDMAX | > + PRM_VP2_VLIMITTO_VDDMIN, > + .vpenable_mask = PRM_VP2_CONFIG_VPENABLE, > + .irqmask_trans_done = VP2_IRQMASK_TRANSDONE, > + .irqmask_smps_noack = OMAP3430_VP2_NOSMPSACK_ST, > + }, > + .num_opp = 3, > + .opp_boundary = 3, > + .opp_nvalue = { > + OMAP343X_CONTROL_FUSE_OPP1_VDD2, > + OMAP343X_CONTROL_FUSE_OPP2_VDD2, > + OMAP343X_CONTROL_FUSE_OPP3_VDD2, > + }, > + /* *INDENT-ON* */ > +}; > + > +/* SR list for 3430 */ > +static __initdata struct omap_sr_list omap34xx_srlist = { > + .num_sr = 2, > + .sr_list = {&omap34xx_sr1, &omap34xx_sr2} > +}; > + > +/* The final SR list */ > +static struct omap_sr_list *omap_srlist; I have a couple a suggestions regarding the code partitioning: - SmartReflex is one IP with several instances; it means that only the base address will change between SR1 and SR2. There is no need to duplicate the mask and shift defines per SR. Moreover, SR being an IP, I think we can encode the one IP / several instance in a platform_device / platform_driver code. It will allow the support of several drivers for the same devices in order to implement for example class3, class2 or class1 drivers. SR can even be represented by an HWMOD. - The smartreflex.c file contains 34xx specifics code; it should not be there, only SR specific code should be there. - If we want to go further, I think that the VP/VC code should not be in SR code either. It is located in the PRM, and can be used independently of SR. - In a SR class 2 mode, the smartreflex driver will not use the direct connection to the VP. - If we don't want SR we can still use the VP/VC for device voltage control. [snip] > +/****************** PMIC WEAK FUNCTIONS FOR TWL4030 derivatives > **********/ > + > +/** > + * @brief pmic_srinit - Power management IC initialization > + * for smart reflex. The current code is written for TWL4030 > + * derivatives, replace in board file if PMIC requires > + * a different sequence > + * > + * @return result of operation > + */ > +int __weak __init omap_pmic_srinit(void) > +{ > + int ret = -ENODEV; > +#ifdef CONFIG_TWL4030_CORE > + u8 reg; > + /* Enable SR on T2 */ > + ret = twl4030_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, ®, > + R_DCDC_GLOBAL_CFG); > + > + reg |= DCDC_GLOBAL_CFG_ENABLE_SRFLX; > + ret |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, reg, > + R_DCDC_GLOBAL_CFG); > +#endif /* End of CONFIG_TWL4030_CORE */ > + return ret; > +} > + > +/** > + * @brief omap_pmic_voltage_ramp_delay - how much should this pmic ramp > delay > + * Various PMICs have different ramp up and down delays. choose to > implement > + * in required pmic file to override this function. > + * On TWL4030 derivatives: > + * T2 SMPS slew rate (min) 4mV/uS, step size 12.5mV, > + * 2us added as buffer. > + * > + * @param srid - which SR is this for? > + * @param target_vsel - targetted voltage selction > + * @param current_vsel - current voltage selection > + * > + * @return delay in uSeconds > + */ > +u32 __weak omap_pmic_voltage_ramp_delay(u8 srid, u8 target_vsel, > + u8 current_vsel) > +{ > + u32 t2_smps_steps = abs(target_vsel - current_vsel); > + u32 t2_smps_delay = ((t2_smps_steps * 125) / 40) + 2; > + return t2_smps_delay; > +} > + > +#ifdef CONFIG_OMAP_VC_BYPASS_UPDATE > +/** > + * @brief omap_pmic_voltage_cmds - hook for pmic command sequence > + * to be send out which are specific to pmic to set a specific voltage. > + * this should inturn call vc_send_command with the required sequence > + * The current implementation is for TWL4030 derivatives > + * > + * @param srid - which SR is this for? > + * @param target_vsel - what voltage is desired to be set? > + * > + * @return specific value to set. > + */ > +int __weak omap_pmic_voltage_cmds(u8 srid, u8 target_vsel) > +{ > + u8 reg_addr = (srid == SR1) ? R_VDD1_SR_CONTROL : R_VDD2_SR_CONTROL; > + u16 timeout = COUNT_TIMEOUT_TWL4030_VCBYPASS; > + return vc_send_command(R_SRI2C_SLAVE_ADDR, reg_addr, target_vsel, > + &timeout); > +} > +#endif /* ifdef CONFIG_OMAP_VC_BYPASS_UPDATE */ > + The TWL4030 specific code should not be there even if this is the default PMIC, it should be in TWL4030 driver code. The usage of weak functions will prevent a multiple OMAP build with different PMIC to work. The mapping between omap and TWL4030 should be done in the board specific code. [snip] > +/*********************** DVFS Entry POINTS > **********************************/ > + > +/** > + * @brief sr_vp_enable_both - enable both vp and sr > + * > + * @param target_opp - targetted op > + * @param current_opp - current opp > + * > + * @return 0 if ok, 1 if not ok > + */ > +int sr_vp_enable_both(u32 target_opp, u32 current_opp) It thinks that it not obvious from the name to understand what this API is doing, especially if we consider the other enable_smartreflex API. Maybe smartreflex_change_opp or sr_change_opp will more explicit. In any case the vp should be removed. The fact that VP is used internally is implementation dependent. > +{ > + struct omap_sr *sr; > + u32 vdd, target_opp_no; > + int ret = 0; > + > + vdd = get_vdd(target_opp); > + target_opp_no = get_opp_no(target_opp); > + sr = get_sr_from_vdd(vdd); > + > + if (sr->is_autocomp_active && sr->is_sr_reset) { > + ret = srvp_enable(sr, target_opp_no); > + if (ret) { > + pr_err("SR[%d]:enableboth:" > + "failed enable SR\n", sr->srid); > + } > + } > + return ret; > +} > +EXPORT_SYMBOL(sr_vp_enable_both); > + > +/** > + * @brief sr_vp_disable_both - disable both vp and sr > + * > + * @param target_opp - targetted opp > + * @param current_opp - current opp > + * > + * @return 0 if ok, 1 if not ok > + */ > +int sr_vp_disable_both(u32 target_opp, u32 current_opp) > +{ > + struct omap_sr *sr; > + u32 vdd; > + int ret = 0; > + > + vdd = get_vdd(target_opp); > + sr = get_sr_from_vdd(vdd); > + > + if (sr->is_autocomp_active && !sr->is_sr_reset) { > + ret = srvp_disable(sr); > + if (ret) { > + pr_err("SR[%d]:disableboth:" > + "failed disable SR\n", sr->srid); > + } > + } > + > + return ret; > + > +} > +EXPORT_SYMBOL(sr_vp_disable_both); > + > +/** > + * @brief sr_voltage_set - setup a voltage requested > + * > + * @param target_opp - targetted opp > + * @param current_opp - current opp > + * @param target_vsel - targeted voltage > + * @param current_vsel - current voltage > + * > + * @return - result of op -0 if ok, else value > + */ > +int sr_voltage_set(u32 target_opp, u32 current_opp, > + u8 target_vsel, u8 current_vsel) > +{ > + struct omap_sr *sr; > + u8 vdd, target_opp_no; > + int ret; > + > + vdd = get_vdd(target_opp); > + target_opp_no = get_opp_no(target_opp); > + sr = get_sr_from_vdd(vdd); > + > + ret = > + SR_CHOSEN_VOLTAGE_UPDATE_MECH(sr, target_opp_no, target_vsel, > + current_vsel); > + > + return ret; > +} > +EXPORT_SYMBOL(sr_voltage_set); > + > +/*********************** CPUIDLE ENTRY POINTS > *********************************/ > + > +/** > + * @brief disable_smartreflex - disable SmartReflex before WFI > + * > + * @param srid SRID > + */ > +void disable_smartreflex(u8 srid) > +{ > + struct omap_sr *sr = NULL; > + int ret; > + u32 current_opp_no; > + > + /* I want to be in irq_disabled context.. > + * else I will die.. find the rootcause and fix it instead > + */ > + BUG_ON(!irqs_disabled()); > + > + sr = get_sr(srid); > + > + current_opp_no = get_current_opp_number_from_sr(sr); > + > + if (sr->is_autocomp_active && !sr->is_sr_reset) { > + sr->req_opp_no = current_opp_no; > + ret = srvp_disable(sr); > + if (ret) > + pr_err("SR[%d]:disable_smartreflex:" > + "failed disable SR\n", sr->srid); > + } > + > + /* Reset the voltage for current OPP to nominal if SR was enabled */ > + if (sr->is_autocomp_active) > + sr_vp_reset_voltage(srid); > +} > +EXPORT_SYMBOL(disable_smartreflex); > + > +/** > + * @brief enable_smartreflex - enable smart reflex after WFI is hit > + * > + * @param srid -SR ID to hit > + */ > +void enable_smartreflex(u8 srid) The naming is not coherent with previous API name sr_vp_enable_both. You should use the same denomination for smartreflex everywhere. > +{ > + struct omap_sr *sr; > + int ret; > + u32 current_opp_no; > + > + /* I want to be in irq_disabled context.. > + * else I will die.. find the rootcause and fix it instead > + */ > + BUG_ON(!irqs_disabled()); > + > + sr = get_sr(srid); > + current_opp_no = get_current_opp_number_from_sr(sr); > + > + if (sr->is_autocomp_active && sr->is_sr_reset) { > + ret = srvp_enable(sr, current_opp_no); > + if (ret) > + pr_err("SR[%d]:enable_smartreflex:" > + "failed enable SR\n", sr->srid); > + } > +} > +EXPORT_SYMBOL(enable_smartreflex); > + [snip] For my point of view, this code should be dispatched into several files: smartreflex.c (pure SR IP driver), vp_vc.c (voltage processor and control), pmic driver, omap specific code and board initialization code. Regards, Benoit Texas Instruments France SA, 821 Avenue Jack Kilby, 06270 Villeneuve Loubet. 036 420 040 R.C.S Antibes. Capital de EUR 753.920 ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 2/2 v3] OMAP3: PM: SR: SmartReflex Refactor Rev4.0 2009-10-25 22:12 ` Cousson, Benoit @ 2009-10-25 22:59 ` Nishanth Menon 2009-10-26 13:05 ` Cousson, Benoit 0 siblings, 1 reply; 16+ messages in thread From: Nishanth Menon @ 2009-10-25 22:59 UTC (permalink / raw) To: Cousson, Benoit Cc: linux-omap@vger.kernel.org, Imberton Guilhem, Mike Chan, Nayak, Rajendra, Roger Quadros, Kalle Jokiniemi, Reddy, Teerth, Kevin Hilman, Paul Walmsley, Hogander Jouni, Sabatier, Sebastien Cousson, Benoit said the following on 10/25/2009 05:12 PM: >> diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach- >> [...] >> + }, >> + /* *INDENT-ON* */ >> +}; >> + >> +/* SR list for 3430 */ >> +static __initdata struct omap_sr_list omap34xx_srlist = { >> + .num_sr = 2, >> + .sr_list = {&omap34xx_sr1, &omap34xx_sr2} >> +}; >> + >> +/* The final SR list */ >> +static struct omap_sr_list *omap_srlist; >> > > I have a couple a suggestions regarding the code partitioning: > > - SmartReflex is one IP with several instances; it means that only the base address will change between SR1 and SR2. There is no need to duplicate the mask and shift defines per SR. > might have been easier with a standard OCP wrapper and standard INT/INTSTATUS regs for SR instead of the current integration.... but yeah, I had been thinking of that- if O4/beyond could have the same IP wrapped in a different register mapping, i should handle it then, not dream about it now.. I get your point here.. there are a few places we can kick it out and some places your are stuck with them! > Moreover, SR being an IP, I think we can encode the one IP / several instance in a platform_device / platform_driver code. It will allow the support of several drivers for the same devices in order to implement for example class3, class2 or class1 drivers. SR can even be represented by an HWMOD. > what is your intention in misusing platform_device for a SOC specific code? I think you have an idea here that I am completely missing. can you care to elaborate? > - The smartreflex.c file contains 34xx specifics code; it should not be there, only SR specific code should be there. > read the TODO. which specific 3430 code does it have? other than using macros which have 34xx prefix - that should be killed -yep. > - If we want to go further, I think that the VP/VC code should not be in SR code either. It is located in the PRM, and can be used independently of SR. > - In a SR class 2 mode, the smartreflex driver will not use the direct > connection to the VP. > - If we don't want SR we can still use the VP/VC for device voltage > control. > - How about adding - Smart reflex should actually fit in a voltage control infrastructure so that the system can manipulate and set voltage with and without SR.. that is what is really missing in our code base today -> SR and VP comes plugged in close as buddies in all silicons, so if your recommendation has an silicon example where OMAP SR talks not to VP, let me know and I will second splitting the code :D. till then sorry.. you dont have a case. now, it is a different case where you want to use SR as a pure monitoring engine -> that is not an implementation that is exactly better than class 3 operation.. why support it at all? > [snip] > > >> +/****************** PMIC WEAK FUNCTIONS FOR TWL4030 derivatives >> **********/ >> + >> +/** >> + * @brief pmic_srinit - Power management IC initialization >> + * for smart reflex. The current code is written for TWL4030 >> + * derivatives, replace in board file if PMIC requires >> + * a different sequence >> + * >> + * @return result of operation >> + */ >> +int __weak __init omap_pmic_srinit(void) >> +{ >> + int ret = -ENODEV; >> +#ifdef CONFIG_TWL4030_CORE >> + u8 reg; >> + /* Enable SR on T2 */ >> + ret = twl4030_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, ®, >> + R_DCDC_GLOBAL_CFG); >> + >> + reg |= DCDC_GLOBAL_CFG_ENABLE_SRFLX; >> + ret |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, reg, >> + R_DCDC_GLOBAL_CFG); >> +#endif /* End of CONFIG_TWL4030_CORE */ >> + return ret; >> +} >> + >> +/** >> + * @brief omap_pmic_voltage_ramp_delay - how much should this pmic ramp >> delay >> + * Various PMICs have different ramp up and down delays. choose to >> implement >> + * in required pmic file to override this function. >> + * On TWL4030 derivatives: >> + * T2 SMPS slew rate (min) 4mV/uS, step size 12.5mV, >> + * 2us added as buffer. >> + * >> + * @param srid - which SR is this for? >> + * @param target_vsel - targetted voltage selction >> + * @param current_vsel - current voltage selection >> + * >> + * @return delay in uSeconds >> + */ >> +u32 __weak omap_pmic_voltage_ramp_delay(u8 srid, u8 target_vsel, >> + u8 current_vsel) >> +{ >> + u32 t2_smps_steps = abs(target_vsel - current_vsel); >> + u32 t2_smps_delay = ((t2_smps_steps * 125) / 40) + 2; >> + return t2_smps_delay; >> +} >> + >> +#ifdef CONFIG_OMAP_VC_BYPASS_UPDATE >> +/** >> + * @brief omap_pmic_voltage_cmds - hook for pmic command sequence >> + * to be send out which are specific to pmic to set a specific voltage. >> + * this should inturn call vc_send_command with the required sequence >> + * The current implementation is for TWL4030 derivatives >> + * >> + * @param srid - which SR is this for? >> + * @param target_vsel - what voltage is desired to be set? >> + * >> + * @return specific value to set. >> + */ >> +int __weak omap_pmic_voltage_cmds(u8 srid, u8 target_vsel) >> +{ >> + u8 reg_addr = (srid == SR1) ? R_VDD1_SR_CONTROL : R_VDD2_SR_CONTROL; >> + u16 timeout = COUNT_TIMEOUT_TWL4030_VCBYPASS; >> + return vc_send_command(R_SRI2C_SLAVE_ADDR, reg_addr, target_vsel, >> + &timeout); >> +} >> +#endif /* ifdef CONFIG_OMAP_VC_BYPASS_UPDATE */ >> + >> > > The TWL4030 specific code should not be there even if this is the default PMIC, it should be in TWL4030 driver code. > The usage of weak functions will prevent a multiple OMAP build with different PMIC to work. > The mapping between omap and TWL4030 should be done in the board specific code. > hmm good point.. have a recommendation here? > [snip] > > > >> +/*********************** DVFS Entry POINTS >> **********************************/ >> + >> +/** >> + * @brief sr_vp_enable_both - enable both vp and sr >> + * >> + * @param target_opp - targetted op >> + * @param current_opp - current opp >> + * >> + * @return 0 if ok, 1 if not ok >> + */ >> +int sr_vp_enable_both(u32 target_opp, u32 current_opp) >> > > It thinks that it not obvious from the name to understand what this API is doing, especially if we consider the other enable_smartreflex API. > Maybe smartreflex_change_opp or sr_change_opp will more explicit. In any case the vp should be removed. The fact that VP is used internally is implementation dependent. > I dont see a reason why VP should need independent consideration as SR. today SR talks to VP and there is no usage of SR sticking it's data else where.. but on the naming -> yeah sr_vp_enable both --> explained in the comment above - enable both SR and VP.. now, if you state DVFS entry point should state stop_auto_voltage_change() you have a case there.. I accept.. I also point you to my TODO above: a better voltage setting infrastructure is needed than hacking our voltage code on top of current code. > >> +{ >> + struct omap_sr *sr; >> + u32 vdd, target_opp_no; >> + int ret = 0; >> + >> + vdd = get_vdd(target_opp); >> + target_opp_no = get_opp_no(target_opp); >> + sr = get_sr_from_vdd(vdd); >> + >> + if (sr->is_autocomp_active && sr->is_sr_reset) { >> + ret = srvp_enable(sr, target_opp_no); >> + if (ret) { >> + pr_err("SR[%d]:enableboth:" >> + "failed enable SR\n", sr->srid); >> + } >> + } >> + return ret; >> +} >> +EXPORT_SYMBOL(sr_vp_enable_both); >> + >> +/** >> + * @brief sr_vp_disable_both - disable both vp and sr >> + * >> + * @param target_opp - targetted opp >> + * @param current_opp - current opp >> + * >> + * @return 0 if ok, 1 if not ok >> + */ >> +int sr_vp_disable_both(u32 target_opp, u32 current_opp) >> +{ >> + struct omap_sr *sr; >> + u32 vdd; >> + int ret = 0; >> + >> + vdd = get_vdd(target_opp); >> + sr = get_sr_from_vdd(vdd); >> + >> + if (sr->is_autocomp_active && !sr->is_sr_reset) { >> + ret = srvp_disable(sr); >> + if (ret) { >> + pr_err("SR[%d]:disableboth:" >> + "failed disable SR\n", sr->srid); >> + } >> + } >> + >> + return ret; >> + >> +} >> +EXPORT_SYMBOL(sr_vp_disable_both); >> + >> +/** >> + * @brief sr_voltage_set - setup a voltage requested >> + * >> + * @param target_opp - targetted opp >> + * @param current_opp - current opp >> + * @param target_vsel - targeted voltage >> + * @param current_vsel - current voltage >> + * >> + * @return - result of op -0 if ok, else value >> + */ >> +int sr_voltage_set(u32 target_opp, u32 current_opp, >> + u8 target_vsel, u8 current_vsel) >> +{ >> + struct omap_sr *sr; >> + u8 vdd, target_opp_no; >> + int ret; >> + >> + vdd = get_vdd(target_opp); >> + target_opp_no = get_opp_no(target_opp); >> + sr = get_sr_from_vdd(vdd); >> + >> + ret = >> + SR_CHOSEN_VOLTAGE_UPDATE_MECH(sr, target_opp_no, target_vsel, >> + current_vsel); >> + >> + return ret; >> +} >> +EXPORT_SYMBOL(sr_voltage_set); >> + >> +/*********************** CPUIDLE ENTRY POINTS >> *********************************/ >> + >> +/** >> + * @brief disable_smartreflex - disable SmartReflex before WFI >> + * >> + * @param srid SRID >> + */ >> +void disable_smartreflex(u8 srid) >> +{ >> + struct omap_sr *sr = NULL; >> + int ret; >> + u32 current_opp_no; >> + >> + /* I want to be in irq_disabled context.. >> + * else I will die.. find the rootcause and fix it instead >> + */ >> + BUG_ON(!irqs_disabled()); >> + >> + sr = get_sr(srid); >> + >> + current_opp_no = get_current_opp_number_from_sr(sr); >> + >> + if (sr->is_autocomp_active && !sr->is_sr_reset) { >> + sr->req_opp_no = current_opp_no; >> + ret = srvp_disable(sr); >> + if (ret) >> + pr_err("SR[%d]:disable_smartreflex:" >> + "failed disable SR\n", sr->srid); >> + } >> + >> + /* Reset the voltage for current OPP to nominal if SR was enabled */ >> + if (sr->is_autocomp_active) >> + sr_vp_reset_voltage(srid); >> +} >> +EXPORT_SYMBOL(disable_smartreflex); >> + >> +/** >> + * @brief enable_smartreflex - enable smart reflex after WFI is hit >> + * >> + * @param srid -SR ID to hit >> + */ >> +void enable_smartreflex(u8 srid) >> > > The naming is not coherent with previous API name sr_vp_enable_both. You should use the same denomination for smartreflex everywhere. > NAK - read the context please before you comment -> the call is from cpu_idle perspective.. > >> +{ >> + struct omap_sr *sr; >> + int ret; >> + u32 current_opp_no; >> + >> + /* I want to be in irq_disabled context.. >> + * else I will die.. find the rootcause and fix it instead >> + */ >> + BUG_ON(!irqs_disabled()); >> + >> + sr = get_sr(srid); >> + current_opp_no = get_current_opp_number_from_sr(sr); >> + >> + if (sr->is_autocomp_active && sr->is_sr_reset) { >> + ret = srvp_enable(sr, current_opp_no); >> + if (ret) >> + pr_err("SR[%d]:enable_smartreflex:" >> + "failed enable SR\n", sr->srid); >> + } >> +} >> +EXPORT_SYMBOL(enable_smartreflex); >> + >> > > [snip] > > For my point of view, this code should be dispatched into several files: smartreflex.c (pure SR IP driver), vp_vc.c (voltage processor and control), pmic driver, omap specific code and board initialization code. > come up with a clean proposal that can have code attached to it, or better still a patch and I will gladly back my patch out. Regards, Nishanth Menon ^ permalink raw reply [flat|nested] 16+ messages in thread
* RE: [PATCH 2/2 v3] OMAP3: PM: SR: SmartReflex Refactor Rev4.0 2009-10-25 22:59 ` Nishanth Menon @ 2009-10-26 13:05 ` Cousson, Benoit 2009-10-26 13:19 ` Menon, Nishanth 0 siblings, 1 reply; 16+ messages in thread From: Cousson, Benoit @ 2009-10-26 13:05 UTC (permalink / raw) To: Nishanth Menon Cc: linux-omap@vger.kernel.org, Imberton Guilhem, Mike Chan, Nayak, Rajendra, Roger Quadros, Kalle Jokiniemi, Reddy, Teerth, Kevin Hilman, Paul Walmsley, Hogander Jouni, Sabatier, Sebastien > From: Nishanth Menon [mailto:menon.nishanth@gmail.com] > > Cousson, Benoit said the following on 10/25/2009 05:12 PM: > >> diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach- > >> > [...] > >> + }, > >> + /* *INDENT-ON* */ > >> +}; > >> + > >> +/* SR list for 3430 */ > >> +static __initdata struct omap_sr_list omap34xx_srlist = { > >> + .num_sr = 2, > >> + .sr_list = {&omap34xx_sr1, &omap34xx_sr2} > >> +}; > >> + > >> +/* The final SR list */ > >> +static struct omap_sr_list *omap_srlist; > >> > > > > I have a couple a suggestions regarding the code partitioning: > > > > - SmartReflex is one IP with several instances; it means that only the > base address will change between SR1 and SR2. There is no need to > duplicate the mask and shift defines per SR. > > > might have been easier with a standard OCP wrapper and standard > INT/INTSTATUS regs for SR instead of the current integration.... but > yeah, I had been thinking of that- if O4/beyond could have the same IP > wrapped in a different register mapping, i should handle it then, not > dream about it now.. I get your point here.. there are a few places we > can kick it out and some places your are stuck with them! SR is a regular IP, with a dedicated PD, dedicated fclk and bound to the L4... VP/VC is not, that why I was proposing to separated them. > > Moreover, SR being an IP, I think we can encode the one IP / several > instance in a platform_device / platform_driver code. It will allow the > support of several drivers for the same devices in order to implement for > example class3, class2 or class1 drivers. SR can even be represented by an > HWMOD. > > > what is your intention in misusing platform_device for a SOC specific > code? I think you have an idea here that I am completely missing. can > you care to elaborate? AFAIK, platform_device is there in order to deal with SoC devices??? Considering that SR is an IP that can be in several SoC, it looks to me the perfect candidate for platform_device/platform_driver. Am I missing something? > > - The smartreflex.c file contains 34xx specifics code; it should not be > there, only SR specific code should be there. > > > read the TODO. which specific 3430 code does it have? other than using > macros which have 34xx prefix - that should be killed -yep. omap34xx_sr1, omap34xx_sr2, omap34xx_srlist... seem to be quite OMAP34xx specifics... > > - If we want to go further, I think that the VP/VC code should not be in > SR code either. It is located in the PRM, and can be used independently of > SR. > > - In a SR class 2 mode, the smartreflex driver will not use the direct > > connection to the VP. > > - If we don't want SR we can still use the VP/VC for device voltage > > control. > > > - How about adding - Smart reflex should actually fit in a > voltage control infrastructure so that the system can manipulate and set > voltage with and without SR.. Fully agree, that was one of the proposals I had in mind, but since it will require some more works, it should be done in a second pass. > that is what is really missing in our code base today -> SR and VP comes > plugged in close as buddies in all silicons, so if your recommendation > has an silicon example where OMAP SR talks not to VP, let me know and I > will second splitting the code :D. till then sorry.. you dont have a case. We had the case in several chips that unfortunately are not there anymore :-( The SR IP was done to handle several config, having SR tied to VP/VC is a chip dependant implementation. > now, it is a different case where you want to use SR as a pure > monitoring engine -> that is not an implementation that is exactly > better than class 3 operation.. why support it at all? It is not a matter or being better, it is just having HW vs. SW implementation. The point is Class 3 is not usable with non SR compliant power IC. In that case you should rely on a Class 2 implementation. > > [snip] > > > > > >> +/****************** PMIC WEAK FUNCTIONS FOR TWL4030 derivatives > >> **********/ > >> + > >> +/** > >> + * @brief pmic_srinit - Power management IC initialization > >> + * for smart reflex. The current code is written for TWL4030 > >> + * derivatives, replace in board file if PMIC requires > >> + * a different sequence > >> + * > >> + * @return result of operation > >> + */ > >> +int __weak __init omap_pmic_srinit(void) > >> +{ > >> + int ret = -ENODEV; > >> +#ifdef CONFIG_TWL4030_CORE > >> + u8 reg; > >> + /* Enable SR on T2 */ > >> + ret = twl4030_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, ®, > >> + R_DCDC_GLOBAL_CFG); > >> + > >> + reg |= DCDC_GLOBAL_CFG_ENABLE_SRFLX; > >> + ret |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, reg, > >> + R_DCDC_GLOBAL_CFG); > >> +#endif /* End of CONFIG_TWL4030_CORE */ > >> + return ret; > >> +} > >> + > >> +/** > >> + * @brief omap_pmic_voltage_ramp_delay - how much should this pmic > ramp > >> delay > >> + * Various PMICs have different ramp up and down delays. choose to > >> implement > >> + * in required pmic file to override this function. > >> + * On TWL4030 derivatives: > >> + * T2 SMPS slew rate (min) 4mV/uS, step size 12.5mV, > >> + * 2us added as buffer. > >> + * > >> + * @param srid - which SR is this for? > >> + * @param target_vsel - targetted voltage selction > >> + * @param current_vsel - current voltage selection > >> + * > >> + * @return delay in uSeconds > >> + */ > >> +u32 __weak omap_pmic_voltage_ramp_delay(u8 srid, u8 target_vsel, > >> + u8 current_vsel) > >> +{ > >> + u32 t2_smps_steps = abs(target_vsel - current_vsel); > >> + u32 t2_smps_delay = ((t2_smps_steps * 125) / 40) + 2; > >> + return t2_smps_delay; > >> +} > >> + > >> +#ifdef CONFIG_OMAP_VC_BYPASS_UPDATE > >> +/** > >> + * @brief omap_pmic_voltage_cmds - hook for pmic command sequence > >> + * to be send out which are specific to pmic to set a specific voltage. > >> + * this should inturn call vc_send_command with the required sequence > >> + * The current implementation is for TWL4030 derivatives > >> + * > >> + * @param srid - which SR is this for? > >> + * @param target_vsel - what voltage is desired to be set? > >> + * > >> + * @return specific value to set. > >> + */ > >> +int __weak omap_pmic_voltage_cmds(u8 srid, u8 target_vsel) > >> +{ > >> + u8 reg_addr = (srid == SR1) ? R_VDD1_SR_CONTROL : > R_VDD2_SR_CONTROL; > >> + u16 timeout = COUNT_TIMEOUT_TWL4030_VCBYPASS; > >> + return vc_send_command(R_SRI2C_SLAVE_ADDR, reg_addr, target_vsel, > >> + &timeout); > >> +} > >> +#endif /* ifdef > CONFIG_OMAP_VC_BYPASS_UPDATE */ > >> + > >> > > > > The TWL4030 specific code should not be there even if this is the > default PMIC, it should be in TWL4030 driver code. > > The usage of weak functions will prevent a multiple OMAP build with > different PMIC to work. > > The mapping between omap and TWL4030 should be done in the board > specific code. > > > hmm good point.. have a recommendation here? We can define a struct with these methods. The struct will be implemented inside the PMIC code. The binding will be done in the board setup code. The SR driver will use the struct pointer to dereference the methods. > > [snip] > > > > > > > >> +/*********************** DVFS Entry POINTS > >> **********************************/ > >> + > >> +/** > >> + * @brief sr_vp_enable_both - enable both vp and sr > >> + * > >> + * @param target_opp - targetted op > >> + * @param current_opp - current opp > >> + * > >> + * @return 0 if ok, 1 if not ok > >> + */ > >> +int sr_vp_enable_both(u32 target_opp, u32 current_opp) > >> > > > > It thinks that it not obvious from the name to understand what this API > is doing, especially if we consider the other enable_smartreflex API. > > Maybe smartreflex_change_opp or sr_change_opp will more explicit. In any > case the vp should be removed. The fact that VP is used internally is > implementation dependent. > > > I dont see a reason why VP should need independent consideration as SR. > today SR talks to VP and there is no usage of SR sticking it's data else > where.. VP is used for device voltage control as well from the PRM. If you don't need SR you can still use the PRM control for OFF/RET/IDLE voltage change. Have a look at the TRM to see how it is connected. > > but on the naming -> yeah sr_vp_enable both --> explained in the comment > above - enable both SR and VP.. now, if you state DVFS entry point > should state stop_auto_voltage_change() you have a case there.. I > accept.. Yep, this is the point, that API is exposed to the upper layer, that should not have to know the details of the implementation or having an API that will change in the case of different SR implementation. > I also point you to my TODO above: a better voltage setting > infrastructure is needed than hacking our voltage code on top of current > code. Sure, but that should not prevent us of providing better naming today if it is easily doable. Regards, Benoit > > > >> +{ > >> + struct omap_sr *sr; > >> + u32 vdd, target_opp_no; > >> + int ret = 0; > >> + > >> + vdd = get_vdd(target_opp); > >> + target_opp_no = get_opp_no(target_opp); > >> + sr = get_sr_from_vdd(vdd); > >> + > >> + if (sr->is_autocomp_active && sr->is_sr_reset) { > >> + ret = srvp_enable(sr, target_opp_no); > >> + if (ret) { > >> + pr_err("SR[%d]:enableboth:" > >> + "failed enable SR\n", sr->srid); > >> + } > >> + } > >> + return ret; > >> +} > >> +EXPORT_SYMBOL(sr_vp_enable_both); > >> + > >> +/** > >> + * @brief sr_vp_disable_both - disable both vp and sr > >> + * > >> + * @param target_opp - targetted opp > >> + * @param current_opp - current opp > >> + * > >> + * @return 0 if ok, 1 if not ok > >> + */ > >> +int sr_vp_disable_both(u32 target_opp, u32 current_opp) > >> +{ > >> + struct omap_sr *sr; > >> + u32 vdd; > >> + int ret = 0; > >> + > >> + vdd = get_vdd(target_opp); > >> + sr = get_sr_from_vdd(vdd); > >> + > >> + if (sr->is_autocomp_active && !sr->is_sr_reset) { > >> + ret = srvp_disable(sr); > >> + if (ret) { > >> + pr_err("SR[%d]:disableboth:" > >> + "failed disable SR\n", sr->srid); > >> + } > >> + } > >> + > >> + return ret; > >> + > >> +} > >> +EXPORT_SYMBOL(sr_vp_disable_both); > >> + > >> +/** > >> + * @brief sr_voltage_set - setup a voltage requested > >> + * > >> + * @param target_opp - targetted opp > >> + * @param current_opp - current opp > >> + * @param target_vsel - targeted voltage > >> + * @param current_vsel - current voltage > >> + * > >> + * @return - result of op -0 if ok, else value > >> + */ > >> +int sr_voltage_set(u32 target_opp, u32 current_opp, > >> + u8 target_vsel, u8 current_vsel) > >> +{ > >> + struct omap_sr *sr; > >> + u8 vdd, target_opp_no; > >> + int ret; > >> + > >> + vdd = get_vdd(target_opp); > >> + target_opp_no = get_opp_no(target_opp); > >> + sr = get_sr_from_vdd(vdd); > >> + > >> + ret = > >> + SR_CHOSEN_VOLTAGE_UPDATE_MECH(sr, target_opp_no, target_vsel, > >> + current_vsel); > >> + > >> + return ret; > >> +} > >> +EXPORT_SYMBOL(sr_voltage_set); > >> + > >> +/*********************** CPUIDLE ENTRY POINTS > >> *********************************/ > >> + > >> +/** > >> + * @brief disable_smartreflex - disable SmartReflex before WFI > >> + * > >> + * @param srid SRID > >> + */ > >> +void disable_smartreflex(u8 srid) > >> +{ > >> + struct omap_sr *sr = NULL; > >> + int ret; > >> + u32 current_opp_no; > >> + > >> + /* I want to be in irq_disabled context.. > >> + * else I will die.. find the rootcause and fix it instead > >> + */ > >> + BUG_ON(!irqs_disabled()); > >> + > >> + sr = get_sr(srid); > >> + > >> + current_opp_no = get_current_opp_number_from_sr(sr); > >> + > >> + if (sr->is_autocomp_active && !sr->is_sr_reset) { > >> + sr->req_opp_no = current_opp_no; > >> + ret = srvp_disable(sr); > >> + if (ret) > >> + pr_err("SR[%d]:disable_smartreflex:" > >> + "failed disable SR\n", sr->srid); > >> + } > >> + > >> + /* Reset the voltage for current OPP to nominal if SR was enabled > */ > >> + if (sr->is_autocomp_active) > >> + sr_vp_reset_voltage(srid); > >> +} > >> +EXPORT_SYMBOL(disable_smartreflex); > >> + > >> +/** > >> + * @brief enable_smartreflex - enable smart reflex after WFI is hit > >> + * > >> + * @param srid -SR ID to hit > >> + */ > >> +void enable_smartreflex(u8 srid) > >> > > > > The naming is not coherent with previous API name sr_vp_enable_both. You > should use the same denomination for smartreflex everywhere. > > > NAK - read the context please before you comment -> the call is from > cpu_idle perspective.. > > > >> +{ > >> + struct omap_sr *sr; > >> + int ret; > >> + u32 current_opp_no; > >> + > >> + /* I want to be in irq_disabled context.. > >> + * else I will die.. find the rootcause and fix it instead > >> + */ > >> + BUG_ON(!irqs_disabled()); > >> + > >> + sr = get_sr(srid); > >> + current_opp_no = get_current_opp_number_from_sr(sr); > >> + > >> + if (sr->is_autocomp_active && sr->is_sr_reset) { > >> + ret = srvp_enable(sr, current_opp_no); > >> + if (ret) > >> + pr_err("SR[%d]:enable_smartreflex:" > >> + "failed enable SR\n", sr->srid); > >> + } > >> +} > >> +EXPORT_SYMBOL(enable_smartreflex); > >> + > >> > > > > [snip] > > > > For my point of view, this code should be dispatched into several files: > smartreflex.c (pure SR IP driver), vp_vc.c (voltage processor and control), > pmic driver, omap specific code and board initialization code. > > > come up with a clean proposal that can have code attached to it, or > better still a patch and I will gladly back my patch out. > > Regards, > Nishanth Menon Texas Instruments France SA, 821 Avenue Jack Kilby, 06270 Villeneuve Loubet. 036 420 040 R.C.S Antibes. Capital de EUR 753.920 ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 2/2 v3] OMAP3: PM: SR: SmartReflex Refactor Rev4.0 2009-10-26 13:05 ` Cousson, Benoit @ 2009-10-26 13:19 ` Menon, Nishanth 2009-10-26 17:06 ` Cousson, Benoit 0 siblings, 1 reply; 16+ messages in thread From: Menon, Nishanth @ 2009-10-26 13:19 UTC (permalink / raw) To: Cousson, Benoit Cc: linux-omap@vger.kernel.org, Imberton Guilhem, Mike Chan, Nayak, Rajendra, Roger Quadros, Kalle Jokiniemi, Reddy, Teerth, Kevin Hilman, Paul Walmsley, Hogander Jouni, Sabatier, Sebastien Benoit, thanks.. overall good discussion that is nice to take in.. more comments follow: Cousson, Benoit said the following on 10/26/2009 08:05 AM: >> From: Nishanth Menon [mailto:menon.nishanth@gmail.com] >> >> Cousson, Benoit said the following on 10/25/2009 05:12 PM: >> >>>> diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach- >>>> >>>> >> [...] >> >>>> + }, >>>> + /* *INDENT-ON* */ >>>> +}; >>>> + >>>> +/* SR list for 3430 */ >>>> +static __initdata struct omap_sr_list omap34xx_srlist = { >>>> + .num_sr = 2, >>>> + .sr_list = {&omap34xx_sr1, &omap34xx_sr2} >>>> +}; >>>> + >>>> +/* The final SR list */ >>>> +static struct omap_sr_list *omap_srlist; >>>> >>>> >>> I have a couple a suggestions regarding the code partitioning: >>> >>> - SmartReflex is one IP with several instances; it means that only the >>> >> base address will change between SR1 and SR2. There is no need to >> duplicate the mask and shift defines per SR. >> >> might have been easier with a standard OCP wrapper and standard >> INT/INTSTATUS regs for SR instead of the current integration.... but >> yeah, I had been thinking of that- if O4/beyond could have the same IP >> wrapped in a different register mapping, i should handle it then, not >> dream about it now.. I get your point here.. there are a few places we >> can kick it out and some places your are stuck with them! >> > > SR is a regular IP, with a dedicated PD, dedicated fclk and bound to the L4... > VP/VC is not, that why I was proposing to separated them. > I am not denying it, but VP/VC functions are already separated out where I could do it (note the seperation of function names), only they dont have a new file perse.. but that is not needed at the moment. > >>> Moreover, SR being an IP, I think we can encode the one IP / several >>> >> instance in a platform_device / platform_driver code. It will allow the >> support of several drivers for the same devices in order to implement for >> example class3, class2 or class1 drivers. SR can even be represented by an >> HWMOD. >> >> what is your intention in misusing platform_device for a SOC specific >> code? I think you have an idea here that I am completely missing. can >> you care to elaborate? >> > > AFAIK, platform_device is there in order to deal with SoC devices??? > Considering that SR is an IP that can be in several SoC, it looks to me the perfect candidate for platform_device/platform_driver. > Am I missing something? > Everything abstracted is a perfect candidate for device-driver model, but that is beside the point. platform_device traditionally has been platform aka board specific info, not SOC specific info.. > >>> - The smartreflex.c file contains 34xx specifics code; it should not be >>> >> there, only SR specific code should be there. >> >> read the TODO. which specific 3430 code does it have? other than using >> macros which have 34xx prefix - that should be killed -yep. >> > > omap34xx_sr1, omap34xx_sr2, omap34xx_srlist... seem to be quite OMAP34xx specifics... > please read the code carefully next time, look at how it is copied based on cpu_is_ api in in __init?? yes, there are specific paramaters to SOC, you cannot avoid that. but you can make the handling independent of the SOC. that is what I have done.. let me know if you have a better idea.. :D.. > >>> - If we want to go further, I think that the VP/VC code should not be in >>> >> SR code either. It is located in the PRM, and can be used independently of >> SR. >> >>> - In a SR class 2 mode, the smartreflex driver will not use the direct >>> connection to the VP. >>> - If we don't want SR we can still use the VP/VC for device voltage >>> control. >>> >>> >> - How about adding - Smart reflex should actually fit in a >> voltage control infrastructure so that the system can manipulate and set >> voltage with and without SR.. >> > > Fully agree, that was one of the proposals I had in mind, but since it will require some more works, it should be done in a second pass. > > >> that is what is really missing in our code base today -> SR and VP comes >> plugged in close as buddies in all silicons, so if your recommendation >> has an silicon example where OMAP SR talks not to VP, let me know and I >> will second splitting the code :D. till then sorry.. you dont have a case. >> > > We had the case in several chips that unfortunately are not there anymore > :-( > The SR IP was done to handle several config, having SR tied to VP/VC is a chip dependant implementation. > lets bring in a proper voltage control infrastructure then worry about SR class2/class3 implementation. class2 is inferior to class 3 and the overhead of cpu intervention should be balanced with a proper latency heuristics, the infrastructure is sadly missing at this point of time.. > >> now, it is a different case where you want to use SR as a pure >> monitoring engine -> that is not an implementation that is exactly >> better than class 3 operation.. why support it at all? >> > > It is not a matter or being better, it is just having HW vs. SW implementation. The point is Class 3 is not usable with non SR compliant power IC. In that case you should rely on a Class 2 implementation. > yep, I am aware of it.. but see my previous comment -> just thinking PMIC is not enough, there is a tradeoff involved for Class 2 operation - for continuous monitoring - hwmod etc might be a better option in that case.. but most of the folks do use PMICs and can benefit.. for proper values, you need NVALUES - dont forget that NOT all ICs have them burnt in.. and cant use SR anyways properly.. > >>> [snip] >>> >>> >>> >>>> +/****************** PMIC WEAK FUNCTIONS FOR TWL4030 derivatives >>>> **********/ >>>> + >>>> +/** >>>> + * @brief pmic_srinit - Power management IC initialization >>>> + * for smart reflex. The current code is written for TWL4030 >>>> + * derivatives, replace in board file if PMIC requires >>>> + * a different sequence >>>> + * >>>> + * @return result of operation >>>> + */ >>>> +int __weak __init omap_pmic_srinit(void) >>>> +{ >>>> + int ret = -ENODEV; >>>> +#ifdef CONFIG_TWL4030_CORE >>>> + u8 reg; >>>> + /* Enable SR on T2 */ >>>> + ret = twl4030_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, ®, >>>> + R_DCDC_GLOBAL_CFG); >>>> + >>>> + reg |= DCDC_GLOBAL_CFG_ENABLE_SRFLX; >>>> + ret |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, reg, >>>> + R_DCDC_GLOBAL_CFG); >>>> +#endif /* End of CONFIG_TWL4030_CORE */ >>>> + return ret; >>>> +} >>>> + >>>> +/** >>>> + * @brief omap_pmic_voltage_ramp_delay - how much should this pmic >>>> >> ramp >> >>>> delay >>>> + * Various PMICs have different ramp up and down delays. choose to >>>> implement >>>> + * in required pmic file to override this function. >>>> + * On TWL4030 derivatives: >>>> + * T2 SMPS slew rate (min) 4mV/uS, step size 12.5mV, >>>> + * 2us added as buffer. >>>> + * >>>> + * @param srid - which SR is this for? >>>> + * @param target_vsel - targetted voltage selction >>>> + * @param current_vsel - current voltage selection >>>> + * >>>> + * @return delay in uSeconds >>>> + */ >>>> +u32 __weak omap_pmic_voltage_ramp_delay(u8 srid, u8 target_vsel, >>>> + u8 current_vsel) >>>> +{ >>>> + u32 t2_smps_steps = abs(target_vsel - current_vsel); >>>> + u32 t2_smps_delay = ((t2_smps_steps * 125) / 40) + 2; >>>> + return t2_smps_delay; >>>> +} >>>> + >>>> +#ifdef CONFIG_OMAP_VC_BYPASS_UPDATE >>>> +/** >>>> + * @brief omap_pmic_voltage_cmds - hook for pmic command sequence >>>> + * to be send out which are specific to pmic to set a specific voltage. >>>> + * this should inturn call vc_send_command with the required sequence >>>> + * The current implementation is for TWL4030 derivatives >>>> + * >>>> + * @param srid - which SR is this for? >>>> + * @param target_vsel - what voltage is desired to be set? >>>> + * >>>> + * @return specific value to set. >>>> + */ >>>> +int __weak omap_pmic_voltage_cmds(u8 srid, u8 target_vsel) >>>> +{ >>>> + u8 reg_addr = (srid == SR1) ? R_VDD1_SR_CONTROL : >>>> >> R_VDD2_SR_CONTROL; >> >>>> + u16 timeout = COUNT_TIMEOUT_TWL4030_VCBYPASS; >>>> + return vc_send_command(R_SRI2C_SLAVE_ADDR, reg_addr, target_vsel, >>>> + &timeout); >>>> +} >>>> +#endif /* ifdef >>>> >> CONFIG_OMAP_VC_BYPASS_UPDATE */ >> >>>> + >>>> >>>> >>> The TWL4030 specific code should not be there even if this is the >>> >> default PMIC, it should be in TWL4030 driver code. >> >>> The usage of weak functions will prevent a multiple OMAP build with >>> >> different PMIC to work. >> >>> The mapping between omap and TWL4030 should be done in the board >>> >> specific code. >> >> hmm good point.. have a recommendation here? >> > > We can define a struct with these methods. The struct will be implemented inside the PMIC code. The binding will be done in the board setup code. The SR driver will use the struct pointer to dereference the methods. > I like words, but prefer a patch instead ;).. This is not something I want to do over my lunch hour ;).. maybe we should take it up as a follow up patch? Regards, NM ^ permalink raw reply [flat|nested] 16+ messages in thread
* RE: [PATCH 2/2 v3] OMAP3: PM: SR: SmartReflex Refactor Rev4.0 2009-10-26 13:19 ` Menon, Nishanth @ 2009-10-26 17:06 ` Cousson, Benoit 0 siblings, 0 replies; 16+ messages in thread From: Cousson, Benoit @ 2009-10-26 17:06 UTC (permalink / raw) To: Menon, Nishanth Cc: linux-omap@vger.kernel.org, Imberton Guilhem, Mike Chan, Nayak, Rajendra, Roger Quadros, Kalle Jokiniemi, Reddy, Teerth, Kevin Hilman, Paul Walmsley, Hogander Jouni, Sabatier, Sebastien > From: Nishanth Menon [mailto:menon.nishanth@gmail.com] On Behalf Of Menon, > Nishanth > > Benoit, > thanks.. overall good discussion that is nice to take in.. more comments You're welcome! My pleasure. > follow: > > Cousson, Benoit said the following on 10/26/2009 08:05 AM: > >> From: Nishanth Menon [mailto:menon.nishanth@gmail.com] > >> > >> Cousson, Benoit said the following on 10/25/2009 05:12 PM: > >> > >>>> diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach- > >>>> > >>>> > >> [...] > >> > >>>> + }, > >>>> + /* *INDENT-ON* */ > >>>> +}; > >>>> + > >>>> +/* SR list for 3430 */ > >>>> +static __initdata struct omap_sr_list omap34xx_srlist = { > >>>> + .num_sr = 2, > >>>> + .sr_list = {&omap34xx_sr1, &omap34xx_sr2} > >>>> +}; > >>>> + > >>>> +/* The final SR list */ > >>>> +static struct omap_sr_list *omap_srlist; > >>>> > >>>> > >>> I have a couple a suggestions regarding the code partitioning: > >>> > >>> - SmartReflex is one IP with several instances; it means that only the > >>> > >> base address will change between SR1 and SR2. There is no need to > >> duplicate the mask and shift defines per SR. > >> > >> might have been easier with a standard OCP wrapper and standard > >> INT/INTSTATUS regs for SR instead of the current integration.... but > >> yeah, I had been thinking of that- if O4/beyond could have the same IP > >> wrapped in a different register mapping, i should handle it then, not > >> dream about it now.. I get your point here.. there are a few places we > >> can kick it out and some places your are stuck with them! > >> > > > > SR is a regular IP, with a dedicated PD, dedicated fclk and bound to the > L4... > > VP/VC is not, that why I was proposing to separated them. > > > I am not denying it, but VP/VC functions are already separated out where > I could do it (note the seperation of function names), only they dont > have a new file perse.. but that is not needed at the moment. > > > >>> Moreover, SR being an IP, I think we can encode the one IP / several > >>> > >> instance in a platform_device / platform_driver code. It will allow the > >> support of several drivers for the same devices in order to implement > for > >> example class3, class2 or class1 drivers. SR can even be represented by > an > >> HWMOD. > >> > >> what is your intention in misusing platform_device for a SOC specific > >> code? I think you have an idea here that I am completely missing. can > >> you care to elaborate? > >> > > > > AFAIK, platform_device is there in order to deal with SoC devices??? > > Considering that SR is an IP that can be in several SoC, it looks to me > the perfect candidate for platform_device/platform_driver. > > Am I missing something? > > > Everything abstracted is a perfect candidate for device-driver model, > but that is beside the point. platform_device traditionally has been > platform aka board specific info, not SOC specific info.. Are you sure about that? The definition does not seem to be that strict. Extract from Documentation/driver-model/platform.txt Platform Devices and Drivers ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [snip] This pseudo-bus is used to connect devices on busses with minimal infrastructure, like those used to integrate peripherals on many system-on-chip processors, or some "legacy" PC interconnects; as opposed to large formally specified ones like PCI or USB. [snip] Moreover, in the current l-o tree, the platform_device is used for DSP, MCBSP, MMC, uWIRE, UART, USB, ISP, bangap sensor, toaster... > > > >>> - The smartreflex.c file contains 34xx specifics code; it should not > be > >>> > >> there, only SR specific code should be there. > >> > >> read the TODO. which specific 3430 code does it have? other than using > >> macros which have 34xx prefix - that should be killed -yep. > >> > > > > omap34xx_sr1, omap34xx_sr2, omap34xx_srlist... seem to be quite OMAP34xx > specifics... > > > please read the code carefully next time, look at how it is copied based > on cpu_is_ api in in __init?? I did, and... My opinion is that smartreflex.c should contain the code for the smartreflex IP... that's all. The omap34xx implementation with two SR IP is SoC specific. And the next time, I will still think the same. > yes, there are specific paramaters to SOC, you cannot avoid that. but > you can make the handling independent of the SOC. that is what I have > done.. let me know if you have a better idea.. :D.. I think I already did. Please read again. > > > >>> - If we want to go further, I think that the VP/VC code should not be > in > >>> > >> SR code either. It is located in the PRM, and can be used independently > of > >> SR. > >> > >>> - In a SR class 2 mode, the smartreflex driver will not use the > direct > >>> connection to the VP. > >>> - If we don't want SR we can still use the VP/VC for device voltage > >>> control. > >>> > >>> > >> - How about adding - Smart reflex should actually fit in a > >> voltage control infrastructure so that the system can manipulate and > set > >> voltage with and without SR.. > >> > > > > Fully agree, that was one of the proposals I had in mind, but since it > will require some more works, it should be done in a second pass. > > > > > >> that is what is really missing in our code base today -> SR and VP > comes > >> plugged in close as buddies in all silicons, so if your recommendation > >> has an silicon example where OMAP SR talks not to VP, let me know and I > >> will second splitting the code :D. till then sorry.. you dont have a > case. > >> > > > > We had the case in several chips that unfortunately are not there > anymore > > :-( > > The SR IP was done to handle several config, having SR tied to VP/VC is > a chip dependant implementation. > > > lets bring in a proper voltage control infrastructure then worry about > SR class2/class3 implementation. You should not worry about class2 implementation; you should just provide a way to handle that properly knowing that someone will have to do it eventually. > class2 is inferior to class 3 Wow, that's a strong statement! Not even politically correct. Class 2 is different that Class3, that's all. > and the > overhead of cpu intervention should be balanced with a proper latency > heuristics, the infrastructure is sadly missing at this point of time.. No need to have a complex infrastructure to handle that. The overhead will be negligible and will probably not impact drastically the power. Moreover if you don't have the SR enable PMIC you don't have the choice. > > > >> now, it is a different case where you want to use SR as a pure > >> monitoring engine -> that is not an implementation that is exactly > >> better than class 3 operation.. why support it at all? > >> > > > > It is not a matter or being better, it is just having HW vs. SW > implementation. The point is Class 3 is not usable with non SR compliant > power IC. In that case you should rely on a Class 2 implementation. > > > yep, I am aware of it.. but see my previous comment -> just thinking > PMIC is not enough, there is a tradeoff involved for Class 2 operation - > for continuous monitoring - hwmod etc might be a better option in that > case.. What is hwmod doing in this situation? I'm confused... There is no tradeoff possible when you do not have a PMIC with SR I2C. > but most of the folks do use PMICs and can benefit.. for proper > values, you need NVALUES - dont forget that NOT all ICs have them burnt > in.. and cant use SR anyways properly.. > > > >>> [snip] > >>> > >>> > >>> > >>>> +/****************** PMIC WEAK FUNCTIONS FOR TWL4030 derivatives > >>>> **********/ > >>>> + > >>>> +/** > >>>> + * @brief pmic_srinit - Power management IC initialization > >>>> + * for smart reflex. The current code is written for TWL4030 > >>>> + * derivatives, replace in board file if PMIC requires > >>>> + * a different sequence > >>>> + * > >>>> + * @return result of operation > >>>> + */ > >>>> +int __weak __init omap_pmic_srinit(void) > >>>> +{ > >>>> + int ret = -ENODEV; > >>>> +#ifdef CONFIG_TWL4030_CORE > >>>> + u8 reg; > >>>> + /* Enable SR on T2 */ > >>>> + ret = twl4030_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, ®, > >>>> + R_DCDC_GLOBAL_CFG); > >>>> + > >>>> + reg |= DCDC_GLOBAL_CFG_ENABLE_SRFLX; > >>>> + ret |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, reg, > >>>> + R_DCDC_GLOBAL_CFG); > >>>> +#endif /* End of CONFIG_TWL4030_CORE > */ > >>>> + return ret; > >>>> +} > >>>> + > >>>> +/** > >>>> + * @brief omap_pmic_voltage_ramp_delay - how much should this pmic > >>>> > >> ramp > >> > >>>> delay > >>>> + * Various PMICs have different ramp up and down delays. choose to > >>>> implement > >>>> + * in required pmic file to override this function. > >>>> + * On TWL4030 derivatives: > >>>> + * T2 SMPS slew rate (min) 4mV/uS, step size 12.5mV, > >>>> + * 2us added as buffer. > >>>> + * > >>>> + * @param srid - which SR is this for? > >>>> + * @param target_vsel - targetted voltage selction > >>>> + * @param current_vsel - current voltage selection > >>>> + * > >>>> + * @return delay in uSeconds > >>>> + */ > >>>> +u32 __weak omap_pmic_voltage_ramp_delay(u8 srid, u8 target_vsel, > >>>> + u8 current_vsel) > >>>> +{ > >>>> + u32 t2_smps_steps = abs(target_vsel - current_vsel); > >>>> + u32 t2_smps_delay = ((t2_smps_steps * 125) / 40) + 2; > >>>> + return t2_smps_delay; > >>>> +} > >>>> + > >>>> +#ifdef CONFIG_OMAP_VC_BYPASS_UPDATE > >>>> +/** > >>>> + * @brief omap_pmic_voltage_cmds - hook for pmic command sequence > >>>> + * to be send out which are specific to pmic to set a specific > voltage. > >>>> + * this should inturn call vc_send_command with the required > sequence > >>>> + * The current implementation is for TWL4030 derivatives > >>>> + * > >>>> + * @param srid - which SR is this for? > >>>> + * @param target_vsel - what voltage is desired to be set? > >>>> + * > >>>> + * @return specific value to set. > >>>> + */ > >>>> +int __weak omap_pmic_voltage_cmds(u8 srid, u8 target_vsel) > >>>> +{ > >>>> + u8 reg_addr = (srid == SR1) ? R_VDD1_SR_CONTROL : > >>>> > >> R_VDD2_SR_CONTROL; > >> > >>>> + u16 timeout = COUNT_TIMEOUT_TWL4030_VCBYPASS; > >>>> + return vc_send_command(R_SRI2C_SLAVE_ADDR, reg_addr, > target_vsel, > >>>> + &timeout); > >>>> +} > >>>> +#endif /* ifdef > >>>> > >> CONFIG_OMAP_VC_BYPASS_UPDATE */ > >> > >>>> + > >>>> > >>>> > >>> The TWL4030 specific code should not be there even if this is the > >>> > >> default PMIC, it should be in TWL4030 driver code. > >> > >>> The usage of weak functions will prevent a multiple OMAP build with > >>> > >> different PMIC to work. > >> > >>> The mapping between omap and TWL4030 should be done in the board > >>> > >> specific code. > >> > >> hmm good point.. have a recommendation here? > >> > > > > We can define a struct with these methods. The struct will be > implemented inside the PMIC code. The binding will be done in the board > setup code. The SR driver will use the struct pointer to dereference the > methods. > > > I like words, but prefer a patch instead ;).. This is not something I > want to do over my lunch hour ;).. maybe we should take it up as a > follow up patch? I'm just providing you some suggestion, take it or leave it. What we've got here is failure to communicate... Regards, Benoit > Regards, > NM Texas Instruments France SA, 821 Avenue Jack Kilby, 06270 Villeneuve Loubet. 036 420 040 R.C.S Antibes. Capital de EUR 753.920 ^ permalink raw reply [flat|nested] 16+ messages in thread
[parent not found: <E0D41E29EB0DAC4E9F3FF173962E9E940253EFE01B@dbde02.ent.ti.com>]
* RE: [PATCH 2/2 v3] OMAP3: PM: SR: SmartReflex Refactor Rev4.0 [not found] ` <E0D41E29EB0DAC4E9F3FF173962E9E940253EFE01B@dbde02.ent.ti.com> @ 2009-10-26 10:18 ` Menon, Nishanth 2009-10-26 15:09 ` G, Manjunath Kondaiah 2009-10-27 23:36 ` Paul Walmsley 0 siblings, 2 replies; 16+ messages in thread From: Menon, Nishanth @ 2009-10-26 10:18 UTC (permalink / raw) To: G, Manjunath Kondaiah, linux-omap@vger.kernel.org Cc: Imberton Guilhem, Mike Chan, Nayak, Rajendra, Roger Quadros, Kalle Jokiniemi, Reddy, Teerth, Kevin Hilman, Paul Walmsley, Hogander Jouni > -----Original Message----- > From: G, Manjunath Kondaiah > Sent: Monday, October 26, 2009 3:40 AM > To: Menon, Nishanth; linux-omap@vger.kernel.org > Cc: Imberton Guilhem; Mike Chan; Nayak, Rajendra; Roger Quadros; Kalle > Jokiniemi; Reddy, Teerth; Kevin Hilman; Paul Walmsley; Hogander Jouni > Subject: RE: [PATCH 2/2 v3] OMAP3: PM: SR: SmartReflex Refactor Rev4.0 > > > As per your comments for other patches when ever there is udelay usage, > cpu_relax is the better option. I see there are lot of udelay(...) calls > used in this patch. Why can't you use cpu_relax() or schedule(). > Any specific reason? > Don’t really want to do cpu_relax in irq_locked context.. if you look at the code flow, the call from cpu_idle is in irq_locked.. Further this delay is part of bring up form saved context where there is nothing else scheduled + we don’t want anything else scheduled (and causing a change in scheduling decision). So unfortunately, unlike standard drivers, this cannot use the same reasoning. Regards, Nishanth Menon ^ permalink raw reply [flat|nested] 16+ messages in thread
* RE: [PATCH 2/2 v3] OMAP3: PM: SR: SmartReflex Refactor Rev4.0 2009-10-26 10:18 ` Menon, Nishanth @ 2009-10-26 15:09 ` G, Manjunath Kondaiah 2009-10-27 23:36 ` Paul Walmsley 1 sibling, 0 replies; 16+ messages in thread From: G, Manjunath Kondaiah @ 2009-10-26 15:09 UTC (permalink / raw) To: Menon, Nishanth, linux-omap@vger.kernel.org Cc: Imberton Guilhem, Mike Chan, Nayak, Rajendra, Roger Quadros, Kalle Jokiniemi, Reddy, Teerth, Kevin Hilman, Paul Walmsley, Hogander Jouni > -----Original Message----- > From: Menon, Nishanth > Sent: Monday, October 26, 2009 3:48 PM > To: G, Manjunath Kondaiah; linux-omap@vger.kernel.org > Cc: Imberton Guilhem; Mike Chan; Nayak, Rajendra; Roger > Quadros; Kalle Jokiniemi; Reddy, Teerth; Kevin Hilman; Paul > Walmsley; Hogander Jouni > Subject: RE: [PATCH 2/2 v3] OMAP3: PM: SR: SmartReflex Refactor Rev4.0 > > > -----Original Message----- > > From: G, Manjunath Kondaiah > > Sent: Monday, October 26, 2009 3:40 AM > > To: Menon, Nishanth; linux-omap@vger.kernel.org > > Cc: Imberton Guilhem; Mike Chan; Nayak, Rajendra; Roger > Quadros; Kalle > > Jokiniemi; Reddy, Teerth; Kevin Hilman; Paul Walmsley; > Hogander Jouni > > Subject: RE: [PATCH 2/2 v3] OMAP3: PM: SR: SmartReflex > Refactor Rev4.0 > > > > > > As per your comments for other patches when ever there is > udelay usage, > > cpu_relax is the better option. I see there are lot of > udelay(...) calls > > used in this patch. Why can't you use cpu_relax() or schedule(). > > Any specific reason? > > > Don’t really want to do cpu_relax in irq_locked context.. if > you look at the code flow, the call from cpu_idle is in > irq_locked.. Further this delay is part of bring up form > saved context where there is nothing else scheduled + we > don’t want anything else scheduled (and causing a change in > scheduling decision). So unfortunately, unlike standard > drivers, this cannot use the same reasoning. > NAK. My understanding is that, SR functions will be called during voltage scaling also. Voltage scaling will happen in non IRQ locked context. Please clarify if I am wrong. -Manjunath ^ permalink raw reply [flat|nested] 16+ messages in thread
* RE: [PATCH 2/2 v3] OMAP3: PM: SR: SmartReflex Refactor Rev4.0 2009-10-26 10:18 ` Menon, Nishanth 2009-10-26 15:09 ` G, Manjunath Kondaiah @ 2009-10-27 23:36 ` Paul Walmsley 2009-10-28 5:17 ` Menon, Nishanth 1 sibling, 1 reply; 16+ messages in thread From: Paul Walmsley @ 2009-10-27 23:36 UTC (permalink / raw) To: Menon, Nishanth Cc: G, Manjunath Kondaiah, linux-omap@vger.kernel.org, Imberton Guilhem, Mike Chan, Nayak, Rajendra, Roger Quadros, Kalle Jokiniemi, Reddy, Teerth, Kevin Hilman, Hogander Jouni [-- Attachment #1: Type: TEXT/PLAIN, Size: 1498 bytes --] Hello Nishanth, Manjunath, a comment on cpu_relax() and udelay(). On Mon, 26 Oct 2009, Menon, Nishanth wrote: > > -----Original Message----- > > From: G, Manjunath Kondaiah > > > > As per your comments for other patches when ever there is udelay usage, > > cpu_relax is the better option. I see there are lot of udelay(...) calls > > used in this patch. Why can't you use cpu_relax() or schedule(). > > Any specific reason? > > > Don’t really want to do cpu_relax in irq_locked context.. There are no restrictions on the calling context for cpu_relax(). [ schedule(), of course, does have restrictions. ] I don't understand the use of the udelay(10). Could you please explain this further? Is it the case that if the register bit doesn't change within 50 reads, that it is then not likely to change for 10 microseconds? If that isn't how the device works, then using udelay(10) will just waste power busy-looping in the CPU. I would rather see this code using udelay(1) between each register read if you want to ensure that you read the register for at least 50 microseconds. This would also simplify your timeout loops considerably, which seem unnecessarily complicated. But if the scenario above is how the device is expected to respond, then these loops should have some comments to explain why the extra complexity and power consumption of a 10 microsecond busy-loop after every 50 reads is the right thing to do. regards, - Paul ^ permalink raw reply [flat|nested] 16+ messages in thread
* RE: [PATCH 2/2 v3] OMAP3: PM: SR: SmartReflex Refactor Rev4.0 2009-10-27 23:36 ` Paul Walmsley @ 2009-10-28 5:17 ` Menon, Nishanth 0 siblings, 0 replies; 16+ messages in thread From: Menon, Nishanth @ 2009-10-28 5:17 UTC (permalink / raw) To: Paul Walmsley Cc: G, Manjunath Kondaiah, linux-omap@vger.kernel.org, Imberton Guilhem, Mike Chan, Nayak, Rajendra, Roger Quadros, Kalle Jokiniemi, Reddy, Teerth, Kevin Hilman, Hogander Jouni > -----Original Message----- > owner@vger.kernel.org] On Behalf Of Paul Walmsley > Sent: Wednesday, October 28, 2009 1:37 AM > [..] > a comment on cpu_relax() and udelay(). > > On Mon, 26 Oct 2009, Menon, Nishanth wrote: > > > > -----Original Message----- > > > From: G, Manjunath Kondaiah > > > > > > As per your comments for other patches when ever there is udelay usage, > > > cpu_relax is the better option. I see there are lot of udelay(...) > calls > > > used in this patch. Why can't you use cpu_relax() or schedule(). > > > Any specific reason? > > > > > Don’t really want to do cpu_relax in irq_locked context.. > > There are no restrictions on the calling context for cpu_relax(). > [ schedule(), of course, does have restrictions. ] Thanks.. > > I don't understand the use of the udelay(10). Could you please explain > this further? Is it the case that if the register bit doesn't change > within 50 reads, that it is then not likely to change for 10 microseconds? The delay of 10 used is in vcbypass command -> the loop actually waits for the i2c command to get thru.. depending on the speed of the bus configured and cpu speed, 50 iterations might not be enough, but yes, a udelay(1) loop in addition to cpu_relax might be better.. > > If that isn't how the device works, then using udelay(10) will just waste > power busy-looping in the CPU. I would rather see this code using > udelay(1) between each register read if you want to ensure that you read > the register for at least 50 microseconds. This would also simplify your > timeout loops considerably, which seem unnecessarily complicated. Ack. Regards, Nishanth Menon -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 16+ messages in thread
[parent not found: <74583B8642AB8841B30447520659FCA9DDDFCC3A@dnce01.ent.ti.com>]
* RE: [PATCH 2/2 v3] OMAP3: PM: SR: SmartReflex Refactor Rev4.0 [not found] ` <74583B8642AB8841B30447520659FCA9DDDFCC3A@dnce01.ent.ti.com> @ 2009-10-27 11:46 ` Imberton Guilhem-gimb01 0 siblings, 0 replies; 16+ messages in thread From: Imberton Guilhem-gimb01 @ 2009-10-27 11:46 UTC (permalink / raw) To: Menon, Nishanth, linux-omap Cc: Mike Chan, Nayak, Rajendra, Roger Quadros, Kalle Jokiniemi, Reddy, Teerth, Kevin Hilman, Paul Walmsley, Hogander Jouni, Sabatier, Sebastien Hi Nishanth, After some testing I have found a little problem with the init > From: linux-omap-owner@vger.kernel.org [mailto:linux-omap- > owner@vger.kernel.org] On Behalf Of Menon, Nishanth > > Refactor the smart reflex implementation. [snip] > + return ret; > +} > +late_initcall(omap_sr_init); It seem that with late_initcall we are initializing SR after SGX init. This SGX init call DVFS to change opp and we are not yet initialized this cause the device to hang (Panic Joined) One solution will be to change from late_initcall to device_initcall so SR will be initialized before SGX + return ret; +} +device_initcall(omap_sr_init); Is there any objections or constraint with this ? Or maybe there is another way to fix this ? BR Guilhem -----[Panic]------ [ 8.128723] Unable to handle kernel NULL pointer dereference at virtual address 00000000 [ 8.137329] pgd = c0004000 [ 8.140289] [00000000] *pgd=00000000 [ 8.144042] Internal error: Oops: 5 [#1] PREEMPT [ 8.148895] Modules linked in: [ 8.152099] CPU: 0 Not tainted (2.6.29-omap1 #43) [ 8.157409] PC is at sr_vp_disable_both+0x18/0x80 [ 8.162322] LR is at program_opp+0x80/0x1d0 [ 8.166717] pc : [<c004e23c>] lr : [<c004f544>] psr: 60000013 [ 8.166717] sp : cec1fce0 ip : cec1fcf8 fp : cec1fcf4 [ 8.178741] r10: c050d3d8 r9 : 00000003 r8 : 00000000 [ 8.184204] r7 : 00000000 r6 : 00000010 r5 : 00000002 r4 : cec1e000 [ 8.191040] r3 : 00000000 r2 : 00000042 r1 : 00000043 r0 : 00000002 [ 8.197875] Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment kernel [ 8.205535] Control: 10c5387d Table: 80c04019 DAC: 00000017 [ 8.211578] [ 8.211578] PC: 0xc004e1bc: [ 8.216033] e1bc eb0df5ab ea000011 ebfffe8f e2504000 15d51000 11a02004 159f003c 1a000006 [ 8.224639] e1dc e1a00005 ebffff8f e2504000 0a000007 e5d51000 e1a02004 e59f0020 eb0df59c [ 8.233245] e1fc e59f001c e30014bd e3a02000 eb0083d7 e1a00004 e89da830 c04632b6 c04632e7 [ 8.241851] e21c c046330b c046316a e1a0c00d e92dd830 e24cb004 e59f3064 e7e102d0 e5933000 [ 8.250457] e23c e5d32000 e1520000 2a000002 e3a03000 e5833000 eafffffd e7935100 e5d53021 [ 8.259033] e25c e3530000 0a00000a e5d53020 e3530000 1a000007 e1a00005 ebffffc4 e2504000 [ 8.267639] e27c 0a000004 e5d51000 e59f0014 eb0df578 ea000000 e3a04000 e1a00004 e89da830 [ 8.276245] e29c c050d3a0 c046332f e1a0c00d e92dddf0 e24cb004 e2535000 e1a06000 e1a07001 [ 8.284851] [ 8.284851] LR: 0xc004f4c4: [ 8.289306] f4c4 e1a0c00d e92ddff0 e24cb004 e24dd024 e50b0040 e1a06182 e0810183 e0811006 [ 8.297912] f4e4 e50b103c e1a05002 e50b0038 e1a09003 e5d01004 e1a0c00d e51b003c e3cc4d7f [ 8.306518] f504 e51b2040 e3a08000 e59fa168 e201101f e2023003 e5d02004 e3c4403f e1a07008 [ 8.315124] f524 e1a03283 e202201f e1832002 e1831001 e1a00002 e50b2034 e50b1030 ebfffb37 [ 8.323730] f544 e1550009 d3a02000 c3a02001 e50b2044 e51b3044 e1570003 1a000036 e51bc040 [ 8.332336] f564 e35c0001 1a00000c e59f010c e5903000 e59a0210 e7931006 eb000a65 e59f20fc [ 8.340942] f584 e59a0214 e5923000 e7931006 eb000a60 ebffdd91 e59f30e8 ea000023 e3a01040 [ 8.349517] f5a4 e3a00c02 ebffdf20 e10f8000 f10c0080 e5943004 e2833001 e5843004 e50b004c [ 8.358123] [ 8.358123] SP: 0xcec1fc60: [ 8.362609] fc60 ffffffff 000002c7 00000000 cedc0720 cec1fc94 cec1fc80 ffffffff cec1fccc [ 8.371215] fc80 00000010 00000000 cec1fcf4 cec1fc98 c003c9ac c003c200 00000002 00000043 [ 8.379821] fca0 00000042 00000000 cec1e000 00000002 00000010 00000000 00000000 00000003 [ 8.388397] fcc0 c050d3d8 cec1fcf4 cec1fcf8 cec1fce0 c004f544 c004e23c 60000013 ffffffff [ 8.397003] fce0 cec1e000 00000002 cec1fd44 cec1fcf8 c004f544 c004e230 22222222 22222222 [ 8.405609] fd00 22222222 00000002 c04db200 c04db208 00000042 00000043 00000000 c04da0a8 [ 8.414215] fd20 00000002 00000002 00000000 00000001 00000000 00000003 cec1fd7c cec1fd48 [ 8.422821] fd40 c004f7d4 c004f4d0 c04da0cc 60000013 cec1fda4 cec1fd60 c03ccc74 00000000 [ 8.431427] [ 8.431427] IP: 0xcec1fc78: [ 8.435882] fc78 ffffffff cec1fccc 00000010 00000000 cec1fcf4 cec1fc98 c003c9ac c003c200 [ 8.444488] fc98 00000002 00000043 00000042 00000000 cec1e000 00000002 00000010 00000000 [ 8.453094] fcb8 00000000 00000003 c050d3d8 cec1fcf4 cec1fcf8 cec1fce0 c004f544 c004e23c [ 8.461700] fcd8 60000013 ffffffff cec1e000 00000002 cec1fd44 cec1fcf8 c004f544 c004e230 [ 8.470275] fcf8 22222222 22222222 22222222 00000002 c04db200 c04db208 00000042 00000043 [ 8.478881] fd18 00000000 c04da0a8 00000002 00000002 00000000 00000001 00000000 00000003 [ 8.487487] fd38 cec1fd7c cec1fd48 c004f7d4 c004f4d0 c04da0cc 60000013 cec1fda4 cec1fd60 [ 8.496093] fd58 c03ccc74 00000000 00000000 c04da0a8 00000002 00000001 cec1fd94 cec1fd80 [ 8.504699] [ 8.504699] FP: 0xcec1fc74: [ 8.509155] fc74 cec1fc80 ffffffff cec1fccc 00000010 00000000 cec1fcf4 cec1fc98 c003c9ac [ 8.517761] fc94 c003c200 00000002 00000043 00000042 00000000 cec1e000 00000002 00000010 [ 8.526367] fcb4 00000000 00000000 00000003 c050d3d8 cec1fcf4 cec1fcf8 cec1fce0 c004f544 [ 8.534973] fcd4 c004e23c 60000013 ffffffff cec1e000 00000002 cec1fd44 cec1fcf8 c004f544 [ 8.543579] fcf4 c004e230 22222222 22222222 22222222 00000002 c04db200 c04db208 00000042 [ 8.552154] fd14 00000043 00000000 c04da0a8 00000002 00000002 00000000 00000001 00000000 [ 8.560760] fd34 00000003 cec1fd7c cec1fd48 c004f7d4 c004f4d0 c04da0cc 60000013 cec1fda4 [ 8.569366] fd54 cec1fd60 c03ccc74 00000000 00000000 c04da0a8 00000002 00000001 cec1fd94 [ 8.577972] [ 8.577972] R4: 0xcec1df80: [ 8.582427] df80 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 [ 8.591033] dfa0 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 [ 8.599639] dfc0 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 [ 8.608245] dfe0 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 [ 8.616851] e000 00000002 00000003 00000000 cec13c00 c04df86c 00000000 00000017 cec13c00 [ 8.625427] e020 c050e3c0 cec1e000 00000420 cec13e74 c04d0d48 cec1a800 cec1fdb4 cec1fd70 [ 8.634033] e040 c03cbd70 00000000 00000000 00000000 00000000 00000000 00000000 00000000 [ 8.642639] e060 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 [ 8.651245] [ 8.651245] R10: 0xc050d358: [ 8.655822] d358 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 [ 8.664398] d378 00000000 00000000 00000000 00000000 cec52e00 c05761c0 c04e1808 00000100 [ 8.673004] d398 c0462f97 00000000 00000000 00000000 00000000 00000000 00000000 00000000 [ 8.681610] d3b8 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 [ 8.690216] d3d8 00000000 00000000 00000004 00000000 00000000 00000000 00000000 00000000 [ 8.698822] d3f8 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 [ 8.707397] d418 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 [ 8.716003] d438 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 [ 8.724609] Process swapper (pid: 1, stack limit = 0xcec1e2e0) [ 8.730712] Stack: (0xcec1fce0 to 0xcec20000) [ 8.735260] fce0: cec1e000 00000002 cec1fd44 cec1fcf8 c004f544 c004e230 22222222 22222222 [ 8.743957] fd00: 22222222 00000002 c04db200 c04db208 00000042 00000043 00000000 c04da0a8 [ 8.752655] fd20: 00000002 00000002 00000000 00000001 00000000 00000003 cec1fd7c cec1fd48 [ 8.761352] fd40: c004f7d4 c004f4d0 c04da0cc 60000013 cec1fda4 cec1fd60 c03ccc74 00000000 [ 8.770019] fd60: 00000000 c04da0a8 00000002 00000001 cec1fd94 cec1fd80 c004f89c c004f6a0 [ 8.778717] fd80: c04da0a8 00000000 cec1fdb4 cec1fd98 c0058d44 c004f80c c04da0a8 c04da0cc [ 8.787414] fda0: c04dac68 00000002 cec1fdd4 cec1fdb8 c0059294 c0058cf4 c0558be8 00000000 [ 8.796112] fdc0: 00000000 00000002 cec1fde4 cec1fdd8 c0058ae8 c00591f0 cec1fdfc cec1fde8 [ 8.804779] fde0: c01b7dc8 c0058aa8 c0558bb8 00000000 cec1fe34 cec1fe00 c01b7928 c01b7dac [ 8.813476] fe00: c0558c98 c04dac68 c04dacac 00000001 c04dac68 c04f23ac c04f23ac 00000000 [ 8.822174] fe20: 00000000 00000000 cec1fe44 cec1fe38 c01a2e98 c01b7630 cec1fe54 cec1fe48 [ 8.830841] fe40: c01cc618 c01a2e7c cec1fe74 cec1fe58 c01cb880 c01cc604 c04dac68 c04dacf0 [ 8.839538] fe60: c04f23ac 00000000 cec1fe94 cec1fe78 c01cb990 c01cb7bc c04f23ac cec1fe98 [ 8.848236] fe80: c01cb928 00000000 cec1febc cec1fe98 c01cb0bc c01cb934 cec03a58 c04dac98 [ 8.856933] fea0: c04f23ac ced4d180 c04f28b8 00000000 cec1fecc cec1fec0 c01cb6c8 c01cb078 [ 8.865600] fec0: cec1fefc cec1fed0 c01ca9e0 c01cb6b4 c04643e0 c05583e8 00000000 c04f23ac [ 8.874298] fee0: c05583e8 00000000 00000001 00000000 cec1ff24 cec1ff00 c01cbbbc c01ca944 [ 8.882995] ff00: c0030fec c05583e8 00000000 00000001 00000000 00000000 cec1ff34 cec1ff28 [ 8.891693] ff20: c01cca94 c01cbb30 cec1ff5c cec1ff38 c001d360 c01cca34 c01cca94 c01cbb30 [ 8.900360] ff40: cec1ff5c c0030fec c001d30c 00000000 cec1ffd4 cec1ff60 c003c2ec c001d318 [ 8.909057] ff60: cec1ff8c cec1ff70 c0113f78 c0113c28 cec1ff00 cec409c0 c0114078 c04e757c [ 8.917755] ff80: cec1ffbc cec1ff90 c00a38f4 c0113f00 c01ca39c 00313533 00000000 c0030000 [ 8.926452] ffa0: 00000170 c04e7978 00000000 00000000 c0030fec c00313e0 00000000 00000000 [ 8.935119] ffc0: 00000000 00000000 cec1fff4 cec1ffd8 c0008424 c003c29c 00000000 00000001 [ 8.943817] ffe0: 00000000 00000000 00000000 cec1fff8 c0072738 c00083a4 00000000 00000000 [ 8.952514] Backtrace: [ 8.955078] [<c004e224>] (sr_vp_disable_both+0x0/0x80) from [<c004f544>] (program_opp+0x80/0x1d0) [ 8.964385] r5:00000002 r4:cec1e000 [ 8.968139] [<c004f4c4>] (program_opp+0x0/0x1d0) from [<c004f7d4>] (resource_set_opp_level+0x140/0x16c) [ 8.977996] [<c004f694>] (resource_set_opp_level+0x0/0x16c) from [<c004f89c>] (set_opp+0x9c/0xb8) [ 8.987304] r8:00000001 r7:00000002 r6:c04da0a8 r5:00000000 r4:00000000 [ 8.994354] [<c004f800>] (set_opp+0x0/0xb8) from [<c0058d44>] (update_resource_level+0x5c/0x80) [ 9.003479] r5:00000000 r4:c04da0a8 [ 9.007232] [<c0058ce8>] (update_resource_level+0x0/0x80) from [<c0059294>] (resource_release+0xb0/0xd0) [ 9.017181] r7:00000002 r6:c04dac68 r5:c04da0cc r4:c04da0a8 [ 9.023132] [<c00591e4>] (resource_release+0x0/0xd0) from [<c0058ae8>] (omap_pm_set_min_bus_tput+0x4c/0x68) [ 9.033355] r7:00000002 r6:00000000 r5:00000000 r4:c0558be8 [ 9.039306] [<c0058a9c>] (omap_pm_set_min_bus_tput+0x0/0x68) from [<c01b7dc8>] (DisableSGXClocks+0x28/0x90) [ 9.049530] [<c01b7da0>] (DisableSGXClocks+0x0/0x90) from [<c01b7928>] (SysInitialise+0x304/0x33c) [ 9.058929] r5:00000000 r4:c0558bb8 [ 9.062683] [<c01b7624>] (SysInitialise+0x0/0x33c) from [<c01a2e98>] (PVRSRVDriverProbe+0x28/0x44) [ 9.072082] [<c01a2e70>] (PVRSRVDriverProbe+0x0/0x44) from [<c01cc618>] (platform_drv_probe+0x20/0x24) [ 9.081848] [<c01cc5f8>] (platform_drv_probe+0x0/0x24) from [<c01cb880>] (driver_probe_device+0xd0/0x178) [ 9.091888] [<c01cb7b0>] (driver_probe_device+0x0/0x178) from [<c01cb990>] (__driver_attach+0x68/0x8c) [ 9.101654] r7:00000000 r6:c04f23ac r5:c04dacf0 r4:c04dac68 [ 9.107604] [<c01cb928>] (__driver_attach+0x0/0x8c) from [<c01cb0bc>] (bus_for_each_dev+0x50/0x8c) [ 9.117004] r7:00000000 r6:c01cb928 r5:cec1fe98 r4:c04f23ac [ 9.122955] [<c01cb06c>] (bus_for_each_dev+0x0/0x8c) from [<c01cb6c8>] (driver_attach+0x20/0x28) [ 9.132171] r7:00000000 r6:c04f28b8 r5:ced4d180 r4:c04f23ac [ 9.138122] [<c01cb6a8>] (driver_attach+0x0/0x28) from [<c01ca9e0>] (bus_add_driver+0xa8/0x208) [ 9.147247] [<c01ca938>] (bus_add_driver+0x0/0x208) from [<c01cbbbc>] (driver_register+0x98/0x120) [ 9.156646] r8:00000000 r7:00000001 r6:00000000 r5:c05583e8 r4:c04f23ac [ 9.163696] [<c01cbb24>] (driver_register+0x0/0x120) from [<c01cca94>] (platform_driver_register+0x6c/0x88) [ 9.173919] r9:00000000 r8:00000000 r7:00000001 r6:00000000 r5:c05583e8 [ 9.180755] r4:c0030fec [ 9.183502] [<c01cca28>] (platform_driver_register+0x0/0x88) from [<c001d360>] (PVRCore_Init+0x54/0x1a0) [ 9.193481] [<c001d30c>] (PVRCore_Init+0x0/0x1a0) from [<c003c2ec>] (__exception_text_end+0x5c/0x194) [ 9.203155] r6:00000000 r5:c001d30c r4:c0030fec [ 9.208007] [<c003c290>] (__exception_text_end+0x0/0x194) from [<c0008424>] (kernel_init+0x8c/0xfc) [ 9.217498] r9:00000000 r8:00000000 r7:00000000 r6:00000000 r5:c00313e0 [ 9.224334] r4:c0030fec [ 9.227081] [<c0008398>] (kernel_init+0x0/0xfc) from [<c0072738>] (do_exit+0x0/0x784) [ 9.235321] r5:00000000 r4:00000000 [ 9.239074] Code: e24cb004 e59f3064 e7e102d0 e5933000 (e5d32000) [ 9.245574] ---[ end trace 712ea8b08e905fc9 ]--- ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 2/2 v3] OMAP3: PM: SR: SmartReflex Refactor Rev4.0 2009-10-24 5:15 ` [PATCH 2/2 v3] OMAP3: PM: SR: SmartReflex Refactor Rev4.0 Nishanth Menon ` (2 preceding siblings ...) [not found] ` <74583B8642AB8841B30447520659FCA9DDDFCC3A@dnce01.ent.ti.com> @ 2009-10-27 15:13 ` Kalle Jokiniemi 2009-10-28 5:05 ` Menon, Nishanth 3 siblings, 1 reply; 16+ messages in thread From: Kalle Jokiniemi @ 2009-10-27 15:13 UTC (permalink / raw) To: Nishanth Menon Cc: linux-omap@vger.kernel.org, Imberton Guilhem, Mike Chan, Rajendra Nayak, Roger Quadros, Kalle Jokiniemi, Teerth Reddy, Kevin Hilman, Paul Walmsley, Hogander Jouni Hi Nishanth, Found some dead code, see below: On Sat, 2009-10-24 at 08:15 +0300, Nishanth Menon wrote: > Refactor the smart reflex implementation. > > Original implementation summary: > Eduardo Valentin (1): > OMAP3: PM: SmartReflex: Fix scheduled while atomic problem > > Kalle Jokiniemi (1): > OMAP3: PM: SmartReflex driver integration > > Kevin Hilman (1): > temp: SR: IO_ADDRESS conversion > > Phil Carmody (2): > OMAP3: PM: Don't do unnecessary searches in omap_sr_vdd*_autocomp_store > OMAP3: PM: Early exit on invalid parameters > > Rajendra Nayak (10): > OMAP3: SR: Fix init voltage on OPP change > OMAP3: SR: Update VDD1/2 voltages at boot > OMAP3: SR: Use sysclk for SR CLKLENGTH calc > OMAP3: SR: Reset voltage level on SR disable > OMAP3: SR: Replace printk's with pr_* calls > OMAP3: SR: Remove redundant defines > OMAP3: SR: Replace (0x1 << n) with BIT(n) > OMAP3: SR: Fix SR driver to check for omap-pm return values > OMAP3: PM: Put optimal SMPS stabilization delay > OMAP3: SR: Wait for VP idle before a VP disable > > Roger Quadros (4): > OMAP3: PM: Fix Smartreflex when used with PM_NOOP layer > OMAP3: PM: Make Smartreflex driver independent of SRF > OMAP3: PM: Do not Enable SmartReflex if OPP tables not defined > OMAP3: PM: Smartreflex: Fix VDD2 OPP determining logic > > Teerth Reddy (1): > OMAP3: SR: Replace SR_PASS/FAIL,SR_TRUE/FALSE > > This patch introduces the following changes in addition to refactoring > the implementation: > a) changes the DVFS transition sequences from: > freq, voltage(SR+vp) and viceversa > TO: > disable_vp,SR; freq, voltage(SR+vp) and viceversa; enable_vp,SR > [NOTE: sequence change for disable path - was sr_dis,vp_dis] > This change prevents spikes and unexpected voltage changes > as a result of SR being left enabled at wrong times > b) Major rewrite of smartreflex.c to do the following: > > 1) Support VCbypass style of voltage configuration as optional > introduce and support forceupdate default as recommended by > OMAP3430 TRM. > 2) Centralize operations to allow for simpler and predictable code > flows > 3) Modification to SR configured values to be inline with > silicon characterization results > 4) cleanup of header > 5) Introduce a few omap_pmic weak functions which can be overridden > by platforms implementing PMICs which are different from TWL4030 > derivatives > 6) srid is standardised to u8 and it is not a bit field > > c) Fix ERRCONFIG access to prevent unplanned cleanup of interrupt > status registers - this is done using a interrupt status mask > d) Test nvalues removed instead use debugfs entries to set any values > you like - no more Kconfig option either.. > e) Setup h/w timeout based on cpu sysclk and not hardcoded values > g) finegrained with raw register values available over > debugfs in <debugfs mount point>/<pm_debug mount point>/ > smartreflex/{srid}/ > nvalue_opp[1-5] - nvalues for all 5 opps > Following register tweakability: > VP register values: > vplimito_value > vpstepmax_value > vpstepmin_value > vpconfig_value > SR Register values: > sr_errconfig_value > sr_config_value > Advice: disable SR before hitting them, no checks at this point. > > The following ReadONLY entry is provided: > vsel - this provides the voltage processor decided voltage value > and translated back to voltage based on the type of chip. > typical equation is: > voltage(mV) = (vsel*12.5) + 600 > > test value equivalent userspace bash script would be: > mount -t debugfs none /dbg > mount -t sysfs none /sys > #vdd1: > #0x00AAB48A - OPP3 > echo -n "11187338" >/dbg/pm_debug/smartreflex/1/nvalue_opp3 > #0x00ABA2E6 - OPP4 > echo -n "11248358" >/dbg/pm_debug/smartreflex/1/nvalue_opp4 > # 0x00AB90D3 - OPP5 > echo -n "11243731" >/dbg/pm_debug/smartreflex/1/nvalue_opp5 > > #setup senn and senp value (essentially +120) > x=`cat /dbg/pm_debug/smartreflex/1/sr_config_value` > y=$((x + 120)) > echo -n $y>/dbg/pm_debug/smartreflex/1/sr_config_value > #and enable it.. > echo -n "1" >/sys/power/sr_vdd1_autocomp > > #vdd2 > #0x00AAC695 -OPP3 > echo -n "11191957" > /dbg/pm_debug/smartreflex/2/nvalue_opp3 > #setup senn and senp value (essentially +120) > x=`cat /dbg/pm_debug/smartreflex/2/sr_config_value` > y=$((x + 120)) > echo -n $y>/dbg/pm_debug/smartreflex/2/sr_config_value > #and enable it.. > echo -n "1" >/sys/power/sr_vdd2_autocomp > > Tested on: > SDP3430 with test N values as above and with ES3.1 silicon > > TODO: > a) Handle scenarios for multiple OMAP variants with differing > SR capabilities (e.g. varying OPP levels - e.g. 3630, 4430 etc..) > [IMMEDIATE ISSUE - partly done] > b) Handling OMAP variants with different tuning values > c) Handling different SR capable PMIC with different tuning values > d) A proper handling of locking mechanism b/w dvfs and userspace access of > sr[x]_vddautocomp > e) A more robust error handling > f) using SR on larger number of boards and any tuning parameters > which may be needed additionally (HS/FS I2C4 ops etc..) > g) Wider testing and and bug fixes > h) Analyse how to use SR decided voltages for OPP1 as retention voltage. > some systems may choose to disable OPP1, what do we do then? > > Cc: Rajendra Nayak <rnayak@ti.com> > Cc: Roger Quadros <ext-roger.quadros@nokia.com> > Cc: Kalle Jokiniemi <ext-kalle.jokiniemi@nokia.com> > Cc: Teerth Reddy <teerth@ti.com> > Cc: Kevin Hilman <khilman@deeprootsystems.com> > Cc: Paul Walmsley <paul@pwsan.com> > Cc: Högander Jouni <jouni.hogander@nokia.com> > Cc: Mike Chan <mikechan@google.com> > Signed-off-by: Imberton Guilhem <guilhem.imberton@motorola.com> > Signed-off-by: Nishanth Menon <nm@ti.com> > --- > arch/arm/mach-omap2/pm-debug.c | 3 + > arch/arm/mach-omap2/resource34xx.c | 8 +- > arch/arm/mach-omap2/smartreflex.c | 1604 ++++++++++++++++++++++++++++++++++++ > arch/arm/mach-omap2/smartreflex.h | 274 ++++++ > arch/arm/plat-omap/Kconfig | 15 +- > 5 files changed, 1893 insertions(+), 11 deletions(-) > create mode 100644 arch/arm/mach-omap2/smartreflex.c > create mode 100644 arch/arm/mach-omap2/smartreflex.h > > diff --git a/arch/arm/mach-omap2/pm-debug.c b/arch/arm/mach-omap2/pm-debug.c > index 767ebbc..34ff068 100644 > --- a/arch/arm/mach-omap2/pm-debug.c > +++ b/arch/arm/mach-omap2/pm-debug.c > @@ -35,6 +35,7 @@ > #include "cm.h" > #include "pm.h" > #include "prm-regbits-34xx.h" > +#include "smartreflex.h" > > int omap2_pm_debug; > > @@ -617,6 +618,8 @@ static int __init pm_dbg_init(void) > &voltage_off_while_idle, > &pm_dbg_option_fops); > > + (void)sr_debugfs_create_entries(d); > + > pm_dbg_init_done = 1; > > return 0; > diff --git a/arch/arm/mach-omap2/resource34xx.c b/arch/arm/mach-omap2/resource34xx.c > index 04be4d2..3789f88 100644 > --- a/arch/arm/mach-omap2/resource34xx.c > +++ b/arch/arm/mach-omap2/resource34xx.c > @@ -294,17 +294,23 @@ static int program_opp(int res, struct omap_opp *opp, int target_level, > else > raise = 0; > > +#ifdef CONFIG_OMAP_SMARTREFLEX > + sr_vp_disable_both(t_opp, c_opp); > +#endif > for (i = 0; i < 2; i++) { > if (i == raise) > ret = program_opp_freq(res, target_level, > current_level); > #ifdef CONFIG_OMAP_SMARTREFLEX > else > - sr_voltagescale_vcbypass(t_opp, c_opp, > + sr_voltage_set(t_opp, c_opp, > opp[target_level].vsel, > opp[current_level].vsel); > #endif > } > +#ifdef CONFIG_OMAP_SMARTREFLEX > + sr_vp_enable_both(t_opp, c_opp); > +#endif > > return ret; > } > diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c > new file mode 100644 > index 0000000..d506896 > --- /dev/null > +++ b/arch/arm/mach-omap2/smartreflex.c > @@ -0,0 +1,1604 @@ > +/* > + * linux/arch/arm/mach-omap3/smartreflex.c > + * > + * OMAP34XX SmartReflex Voltage Control > + * > + * Copyright (C) 2009 Texas Instruments, Inc. > + * Nishanth Menon > + * > + * Copyright (C) 2008 Nokia Corporation > + * Kalle Jokiniemi > + * > + * Copyright (C) 2007 Texas Instruments, Inc. > + * Lesly A M <x0080970@ti.com> > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License version 2 as > + * published by the Free Software Foundation. > + */ > + > +#include <linux/kernel.h> > +#include <linux/init.h> > +#include <linux/interrupt.h> > +#include <linux/module.h> > +#include <linux/delay.h> > +#include <linux/err.h> > +#include <linux/clk.h> > +#include <linux/sysfs.h> > +#include <linux/kobject.h> > +#include <linux/i2c/twl4030.h> > +#include <linux/io.h> > +#include <linux/debugfs.h> > + > +#include <plat/omap34xx.h> > +#include <plat/control.h> > +#include <plat/clock.h> > +#include <plat/omap-pm.h> > +#include <plat/resource.h> > +#include <plat/powerdomain.h> > + > +#include "prm.h" > +#include "smartreflex.h" > +#include "prm-regbits-34xx.h" > + > +/* MCUDISACK is expected to happen within 1uSec. */ > +#define COUNT_TIMEOUT_MCUDISACK 200 > + > +/* VPINIDLE is expected to happen within 100uSec. Typical is 2uSec */ > +#define COUNT_TIMEOUT_VPINIDLE 200 > + > +/* Time taken for setting the device - worst case as FS I2C > + * Depends on SMPSWAITIME MIN/MAX Typical is 200uSec > + */ > +#define COUNT_TIMEOUT_TRANSDONE_SET 400 > + > +/* Time to clear out multiple transdone events typical is 3uSec */ > +#define COUNT_TIMEOUT_TRANSDONE_CLR 50 > + > +/* Time For VCBypass mode for TWL4030 derivative chip. */ > +#define COUNT_TIMEOUT_TWL4030_VCBYPASS 500 > + > +/* How many retries to do for I2C errors seen on bus for Forceupdate? */ > +#define COUNT_RETRY_SMPSNOACK 4 > + > +#define SR_REGADDR(offset) (sr->srbase_addr + (offset)) > + > +/* Which function to use for setting voltage */ > +#ifdef CONFIG_OMAP_VC_BYPASS_UPDATE > +#define SR_CHOSEN_VOLTAGE_UPDATE_MECH sr_vc_bypass > +#else > +#define SR_CHOSEN_VOLTAGE_UPDATE_MECH sr_vp_forceupdate > +#endif > + > +#ifdef CONFIG_OMAP_PM_NONE > +struct omap_opp *mpu_opps; > +struct omap_opp *dsp_opps; > +struct omap_opp *l3_opps; > +#endif > + > +static ssize_t omap_sr_vdd_autocomp_show(struct kobject *kobj, > + struct kobj_attribute *attr, > + char *buf); > +static ssize_t omap_sr_vdd_autocomp_store(struct kobject *kobj, > + struct kobj_attribute *attr, > + const char *buf, size_t n); > +/* Structure for Voltage processor */ > +struct omap_sr_vp { > + /* Store the commonly used register offsets. > + * this saves a if condition decision > + */ > + u16 prm_vpx_status_offset; > + u16 prm_vpx_config_offset; > + u16 prm_vpx_stepmin_offset; > + u16 prm_vpx_stepmax_offset; > + u16 prm_vpx_limito_offset; > + u32 prm_vpx_vlimito_timeout; > + u8 prm_vpx_vlimito_shift; > + u16 prm_vpx_voltage_offset; > + u16 prm_vc_cmd_val_offset; > + /* Store the defaults > + * allowing us to save OCP read > + * operation > + */ > + u32 vpconfig_value; > + u32 vpstepmin_value; > + u32 vpstepmax_value; > + u32 vplimito_value; > + u32 vpenable_mask; > + u32 irqmask_trans_done; > + u32 irqmask_smps_noack; > +}; > + > +/* Structure for Smart Reflex */ > +struct omap_sr { > + u8 srid; > + u8 prcm_vdd; > + char *vdd_name; > + struct kobj_attribute autocom_attr; > + struct omap_opp **omap_opp; > + /* SR activity marker */ > + u8 is_sr_reset; > + u8 is_autocomp_active; > + u32 req_opp_no; > + u32 sr_config_value; > + u32 sr_errconfig_value; > + u32 sr_n_mod_mask; > + u8 sr_n_mod_shift; > + u32 sr_p_mod_mask; > + u8 sr_p_mod_shift; > + struct clk *fclk; > + struct clk *iclk; > + void __iomem *srbase_addr; > + char *iclk_name; > + char *fclk_name; > + /* Voltage processor for the specific SR module */ > + struct omap_sr_vp vp; > + /* This will contain the register offset on > + * boot, replaced with the actual value > + * as part of init routine > + */ > + u8 num_opp; > + u8 opp_boundary; > + u32 opp_nvalue[]; > +}; > + > +/* A superset of all SRs in the system ordered by SRID */ > +struct omap_sr_list { > + u8 num_sr; > + struct omap_sr *sr_list[]; > +}; > + > +/* Definitions for 3430 Silicon */ > +/* Smart Reflex 1 structure */ > +static __initdata struct omap_sr omap34xx_sr1 = { > + /* *INDENT-OFF* */ > + .srid = SR1, > + .prcm_vdd = PRCM_VDD1, > + .vdd_name = "vdd1_opp", > + .omap_opp = &mpu_opps, > + .autocom_attr = { > + .attr = { > + .name = __stringify(sr_vdd1_autocomp), > + .mode = 0644, > + }, > + .show = omap_sr_vdd_autocomp_show, > + .store = omap_sr_vdd_autocomp_store, > + }, > + .is_sr_reset = 1, > + .is_autocomp_active = 0, > + .srbase_addr = (void *)OMAP34XX_SR1_BASE, > + .fclk_name = "sr1_fck", > + .iclk_name = "sr_l4_ick", > + .sr_errconfig_value = SR1_ERRWEIGHT | SR1_ERRMAXLIMIT | > + ERRCONFIG_VPBOUNDINTEN | ERRCONFIG_VPBOUNDINTST | > + SR_CLKACTIVITY_IOFF_FON, > + .sr_n_mod_mask = OMAP343X_SR1_SENNENABLE_MASK, > + .sr_n_mod_shift = OMAP343X_SR1_SENNENABLE_SHIFT, > + .sr_p_mod_mask = OMAP343X_SR1_SENPENABLE_MASK, > + .sr_p_mod_shift = OMAP343X_SR1_SENPENABLE_SHIFT, > + .vp = { > + .prm_vpx_status_offset = OMAP3_PRM_VP1_STATUS_OFFSET, > + .prm_vpx_config_offset = OMAP3_PRM_VP1_CONFIG_OFFSET, > + .prm_vpx_stepmin_offset = OMAP3_PRM_VP1_VSTEPMIN_OFFSET, > + .prm_vpx_stepmax_offset = OMAP3_PRM_VP1_VSTEPMAX_OFFSET, > + .prm_vpx_limito_offset = OMAP3_PRM_VP1_VLIMITTO_OFFSET, > + .prm_vpx_vlimito_timeout = PRM_VP1_VLIMITTO_TIMEOUT_US, > + .prm_vpx_vlimito_shift = PRM_VP1_VLIMITTO_TIMEOUT_SHIFT, > + .prm_vpx_voltage_offset = OMAP3_PRM_VP1_VOLTAGE_OFFSET, > + .prm_vc_cmd_val_offset = OMAP3_PRM_VC_CMD_VAL_0_OFFSET, > + .vpconfig_value = PRM_VP1_CONFIG_ERROROFFSET | > + PRM_VP1_CONFIG_TIMEOUTEN, > + .vpstepmin_value = PRM_VP1_VSTEPMIN_SMPSWAITTIMEMIN | > + PRM_VP1_VSTEPMIN_VSTEPMIN, > + .vpstepmax_value = PRM_VP1_VSTEPMAX_SMPSWAITTIMEMAX | > + PRM_VP1_VSTEPMAX_VSTEPMAX, > + .vplimito_value = PRM_VP1_VLIMITTO_VDDMAX | > + PRM_VP1_VLIMITTO_VDDMIN, > + .vpenable_mask = PRM_VP1_CONFIG_VPENABLE, > + .irqmask_trans_done = VP1_IRQMASK_TRANSDONE, > + .irqmask_smps_noack = OMAP3430_VP1_NOSMPSACK_ST, > + }, > + .num_opp = 5, > + .opp_boundary = 3, > + .opp_nvalue = { > + OMAP343X_CONTROL_FUSE_OPP1_VDD1, > + OMAP343X_CONTROL_FUSE_OPP2_VDD1, > + OMAP343X_CONTROL_FUSE_OPP3_VDD1, > + OMAP343X_CONTROL_FUSE_OPP4_VDD1, > + OMAP343X_CONTROL_FUSE_OPP5_VDD1, > + }, > + /* *INDENT-ON* */ > +}; > + > +/* Smart Reflex 2 structure */ > +static __initdata struct omap_sr omap34xx_sr2 = { > + /* *INDENT-OFF* */ > + .srid = SR2, > + .prcm_vdd = PRCM_VDD2, > + .vdd_name = "vdd2_opp", > + .omap_opp = &l3_opps, > + .autocom_attr = { > + .attr = { > + .name = __stringify(sr_vdd2_autocomp), > + .mode = 0644, > + }, > + .show = omap_sr_vdd_autocomp_show, > + .store = omap_sr_vdd_autocomp_store, > + }, > + .is_sr_reset = 1, > + .is_autocomp_active = 0, > + .srbase_addr = (void *)OMAP34XX_SR2_BASE, > + .fclk_name = "sr2_fck", > + .iclk_name = "sr_l4_ick", > + .sr_errconfig_value = SR2_ERRWEIGHT | SR2_ERRMAXLIMIT | > + ERRCONFIG_VPBOUNDINTEN | ERRCONFIG_VPBOUNDINTST | > + SR_CLKACTIVITY_IOFF_FON, > + .sr_n_mod_mask = OMAP343X_SR2_SENNENABLE_MASK, > + .sr_n_mod_shift = OMAP343X_SR2_SENNENABLE_SHIFT, > + .sr_p_mod_mask = OMAP343X_SR2_SENPENABLE_MASK, > + .sr_p_mod_shift = OMAP343X_SR2_SENPENABLE_SHIFT, > + .vp = { > + .prm_vpx_status_offset = OMAP3_PRM_VP2_STATUS_OFFSET, > + .prm_vpx_config_offset = OMAP3_PRM_VP2_CONFIG_OFFSET, > + .prm_vpx_stepmin_offset = OMAP3_PRM_VP2_VSTEPMIN_OFFSET, > + .prm_vpx_stepmax_offset = OMAP3_PRM_VP2_VSTEPMAX_OFFSET, > + .prm_vpx_limito_offset = OMAP3_PRM_VP2_VLIMITTO_OFFSET, > + .prm_vpx_vlimito_timeout = PRM_VP2_VLIMITTO_TIMEOUT_US, > + .prm_vpx_vlimito_shift = PRM_VP2_VLIMITTO_TIMEOUT_SHIFT, > + .prm_vpx_voltage_offset = OMAP3_PRM_VP1_VOLTAGE_OFFSET, > + .prm_vc_cmd_val_offset = OMAP3_PRM_VC_CMD_VAL_1_OFFSET, > + .vpconfig_value = PRM_VP2_CONFIG_ERROROFFSET | > + PRM_VP2_CONFIG_TIMEOUTEN, > + .vpstepmin_value = PRM_VP2_VSTEPMIN_SMPSWAITTIMEMIN | > + PRM_VP2_VSTEPMIN_VSTEPMIN, > + .vpstepmax_value = PRM_VP2_VSTEPMAX_SMPSWAITTIMEMAX | > + PRM_VP2_VSTEPMAX_VSTEPMAX, > + .vplimito_value = PRM_VP2_VLIMITTO_VDDMAX | > + PRM_VP2_VLIMITTO_VDDMIN, > + .vpenable_mask = PRM_VP2_CONFIG_VPENABLE, > + .irqmask_trans_done = VP2_IRQMASK_TRANSDONE, > + .irqmask_smps_noack = OMAP3430_VP2_NOSMPSACK_ST, > + }, > + .num_opp = 3, > + .opp_boundary = 3, > + .opp_nvalue = { > + OMAP343X_CONTROL_FUSE_OPP1_VDD2, > + OMAP343X_CONTROL_FUSE_OPP2_VDD2, > + OMAP343X_CONTROL_FUSE_OPP3_VDD2, > + }, > + /* *INDENT-ON* */ > +}; > + > +/* SR list for 3430 */ > +static __initdata struct omap_sr_list omap34xx_srlist = { > + .num_sr = 2, > + .sr_list = {&omap34xx_sr1, &omap34xx_sr2} > +}; > + > +/* The final SR list */ > +static struct omap_sr_list *omap_srlist; > + > +/*********************** OPP Accessor functions ****************************/ > + > +/** > + * @brief *get_sr - get SR pointer from an SRID > + * > + * @param srid - vddid > + * > + * @return struct pointer if found, else BUG()s > + */ > +static inline struct omap_sr *get_sr(u8 srid) > +{ > + BUG_ON(srid > omap_srlist->num_sr); > + return omap_srlist->sr_list[srid - 1]; > +} > + > +/** > + * @brief *get_sr_from_vdd - get the SR structure indexed by > + * VDD ID > + * > + * @param vddid - vddid > + * > + * @return struct pointer if found, else BUG()s > + */ > +static inline struct omap_sr *get_sr_from_vdd(u8 vddid) > +{ > + /* Currently, the SRID and VDDID are the same, misusing it */ > + return get_sr(vddid); > +} > + > +/** > + * @brief *get_sr_from_vdd_name - get the SR structure from > + * sysfs name > + * > + * @param name -sysfs entry name > + * > + * @return sr struct pointer if found else NULL > + */ > +static struct omap_sr *get_sr_from_vdd_name(char *name) > +{ > + int i; > + struct omap_sr *sr; > + for (i = 0; i < omap_srlist->num_sr; i++) { > + sr = omap_srlist->sr_list[i]; > + if (!strcmp(name, sr->autocom_attr.attr.name)) > + return sr; > + } > + /* Nothin found, BUG!! */ > + BUG(); > + return NULL; > +} > + > +/** > + * @brief get_current_opp_number_from_sr - get the current active OPP number > + * from SR pointer > + * > + * @param sr struct pointer > + * > + * @return current OPP ID > + */ > +static inline int get_current_opp_number_from_sr(struct omap_sr *sr) > +{ > + return (*sr->omap_opp)[resource_get_level(sr->vdd_name)].opp_id; > +} > + > +/** > + * @brief get_vsel_for_opp - get the VSEL value for the SR/OPP combination > + * > + * @param sr struct pointer > + * @param opp opp number desired for > + * > + * @return vsel value, if bad opp number is given, this will BUG() > + */ > +static inline u8 get_vsel_for_opp(struct omap_sr *sr, int opp) > +{ > + /* Dont ask me to derefence nonexistant OPPs! > + * TODO: add check for valid OPPs here > + */ > + BUG_ON(opp > sr->num_opp); > + return (*sr->omap_opp)[opp].vsel; > +} > + > +/****************** SMART REFLEX DEBUGFS ENTRIES *************************/ > + > +#ifdef __SR_DEBUG > + > +/** > + * @brief sr_debugfs_set - set variable with value > + * > + * @param data - variable pointer > + * @param val - value to set > + * > + * @return - 0 > + */ > +static int sr_debugfs_set(void *data, u64 val) > +{ > + u32 *option = data; > + > + *option = val; > + > + return 0; > +} > + > +/** > + * @brief sr_debugfs_get - setup the params > + * > + * @param data - variable to set > + * @param val - value to return > + * > + * @return - 0 > + */ > +static int sr_debugfs_get(void *data, u64 *val) > +{ > + u32 *option = data; > + > + *val = *option; > + > + return 0; > +} > + > +DEFINE_SIMPLE_ATTRIBUTE(sr_debugfs_option_fops, sr_debugfs_get, sr_debugfs_set, > + "%llu\n"); > + > +/** > + * @brief sr_debugfs_vselget - return the vsel value > + * > + * @param data - pointer to vp > + * @param val - value we read back > + * > + * @return > + */ > +static int sr_debugfs_vselget(void *data, u64 *val) > +{ > + struct omap_sr_vp *vp = (struct omap_sr_vp *)data; > + > + *val = prm_read_mod_reg(OMAP3430_GR_MOD, vp->prm_vpx_voltage_offset); > + > + return 0; > +} > + > +DEFINE_SIMPLE_ATTRIBUTE(sr_debugfs_option_vsel_fops, sr_debugfs_vselget, NULL, > + "%llu\n"); > + > +/* Temporary store of pm_debug directory entry */ > +static __initdata struct dentry *stored_pm_d; > + > +/** > + * @brief sr_debugfs_create_entries - create the Smart Reflex entries > + * called from pm-debug, this just stores it for SR to use in late_init > + * > + * @param d - parent directory tree > + * > + * @return 0 if all ok, else returns with error > + */ > +int sr_debugfs_create_entries(struct dentry *d) > +{ > + stored_pm_d = d; > + return 0; > +} > + > +/** > + * @brief sr_debugfs_create_entries_late - create the Smart Reflex entries - > + * called as part of init sequence of SR uses the dentry registered early > + * > + * @param d - parent directory tree > + * > + * @return 0 if all ok, else returns with error > + */ > +static __init int sr_debugfs_create_entries_late(void) > +{ > + struct dentry *sr_dir; > + struct dentry *sr_sub_dir; > + int count; > + > + sr_dir = debugfs_create_dir("smartreflex", stored_pm_d); > + if (IS_ERR(sr_dir)) > + return PTR_ERR(sr_dir); > + for (count = 0; count < omap_srlist->num_sr; count++) { > + int i; > + struct omap_sr *sr = get_sr(count + 1); > + char name[] = "0"; > + char nval_name[] = "nvalue_opp0"; > + name[0] += sr->srid; > + sr_sub_dir = debugfs_create_dir(name, sr_dir); > + if (IS_ERR(sr_sub_dir)) > + continue; > + for (i = 0; i < sr->num_opp; i++) { > + nval_name[strlen(nval_name) - 1]++; > + (void)debugfs_create_file(nval_name, S_IRUGO | S_IWUGO, > + sr_sub_dir, > + &(sr->opp_nvalue[i]), > + &sr_debugfs_option_fops); > + } > + (void)debugfs_create_file("sr_errconfig_value", > + S_IRUGO | S_IWUGO, sr_sub_dir, > + &(sr->sr_errconfig_value), > + &sr_debugfs_option_fops); > + (void)debugfs_create_file("sr_config_value", S_IRUGO | S_IWUGO, > + sr_sub_dir, &(sr->sr_config_value), > + &sr_debugfs_option_fops); > + (void)debugfs_create_file("vpconfig_value", S_IRUGO | S_IWUGO, > + sr_sub_dir, &(sr->vp.vpconfig_value), > + &sr_debugfs_option_fops); > + (void)debugfs_create_file("vpstepmin_value", S_IRUGO | S_IWUGO, > + sr_sub_dir, &(sr->vp.vpstepmin_value), > + &sr_debugfs_option_fops); > + (void)debugfs_create_file("vpstepmax_value", S_IRUGO | S_IWUGO, > + sr_sub_dir, &(sr->vp.vpstepmax_value), > + &sr_debugfs_option_fops); > + (void)debugfs_create_file("vplimito_value", S_IRUGO | S_IWUGO, > + sr_sub_dir, &(sr->vp.vplimito_value), > + &sr_debugfs_option_fops); > + (void)debugfs_create_file("vplimito_value", S_IRUGO | S_IWUGO, > + sr_sub_dir, &(sr->vp.vplimito_value), > + &sr_debugfs_option_fops); > + (void)debugfs_create_file("vsel", S_IRUGO, sr_sub_dir, > + &(sr->vp), &sr_debugfs_option_vsel_fops); > + } > + > + return 0; > +} > + > +#else > + > +static inline int sr_debugfs_create_entries_late(void) > +{ > + return 0; > +} > +#endif /* __SR_DEBUG */ > + > +/****************** PMIC WEAK FUNCTIONS FOR TWL4030 derivatives **********/ > + > +/** > + * @brief pmic_srinit - Power management IC initialization > + * for smart reflex. The current code is written for TWL4030 > + * derivatives, replace in board file if PMIC requires > + * a different sequence > + * > + * @return result of operation > + */ > +int __weak __init omap_pmic_srinit(void) > +{ > + int ret = -ENODEV; > +#ifdef CONFIG_TWL4030_CORE > + u8 reg; > + /* Enable SR on T2 */ > + ret = twl4030_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, ®, > + R_DCDC_GLOBAL_CFG); > + > + reg |= DCDC_GLOBAL_CFG_ENABLE_SRFLX; > + ret |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, reg, > + R_DCDC_GLOBAL_CFG); > +#endif /* End of CONFIG_TWL4030_CORE */ > + return ret; > +} > + > +/** > + * @brief omap_pmic_voltage_ramp_delay - how much should this pmic ramp delay > + * Various PMICs have different ramp up and down delays. choose to implement > + * in required pmic file to override this function. > + * On TWL4030 derivatives: > + * T2 SMPS slew rate (min) 4mV/uS, step size 12.5mV, > + * 2us added as buffer. > + * > + * @param srid - which SR is this for? > + * @param target_vsel - targetted voltage selction > + * @param current_vsel - current voltage selection > + * > + * @return delay in uSeconds > + */ > +u32 __weak omap_pmic_voltage_ramp_delay(u8 srid, u8 target_vsel, > + u8 current_vsel) > +{ > + u32 t2_smps_steps = abs(target_vsel - current_vsel); > + u32 t2_smps_delay = ((t2_smps_steps * 125) / 40) + 2; > + return t2_smps_delay; > +} > + > +#ifdef CONFIG_OMAP_VC_BYPASS_UPDATE > +/** > + * @brief omap_pmic_voltage_cmds - hook for pmic command sequence > + * to be send out which are specific to pmic to set a specific voltage. > + * this should inturn call vc_send_command with the required sequence > + * The current implementation is for TWL4030 derivatives > + * > + * @param srid - which SR is this for? > + * @param target_vsel - what voltage is desired to be set? > + * > + * @return specific value to set. > + */ > +int __weak omap_pmic_voltage_cmds(u8 srid, u8 target_vsel) > +{ > + u8 reg_addr = (srid == SR1) ? R_VDD1_SR_CONTROL : R_VDD2_SR_CONTROL; > + u16 timeout = COUNT_TIMEOUT_TWL4030_VCBYPASS; > + return vc_send_command(R_SRI2C_SLAVE_ADDR, reg_addr, target_vsel, > + &timeout); > +} > +#endif /* ifdef CONFIG_OMAP_VC_BYPASS_UPDATE */ > + > +/*********************** Voltage Controller functions *************************/ > + > +/** > + * @brief vc_send_command - The actual command transmission using > + * Voltage controller on I2C4 > + * > + * @param slave_addr - what is the PMIC slave address > + * @param reg_addr - what is the register address I should be using? > + * @param data - what value do you want to write here? > + * @param timeout_us timeout in uSeconds - returns actual time left > + * > + * @return 0 if all ok, else error value > + */ > +int vc_send_command(u8 slave_addr, u8 reg_addr, u8 data, u16 *timeout_us) > +{ > + u32 value; > + u32 count; > + > + if (unlikely(!timeout_us)) > + return -EINVAL; > + > + /* timeout = timeout_us/10 -> each udelay event > + * 1 udelay event every 50 iteration, assuming > + * each iteration is instaneous, > + * count = (timeout_us/10) * 50 or timeout_us * 5 > + */ > + count = *timeout_us * 5; > + > + value = (data << OMAP3430_DATA_SHIFT) | > + (reg_addr << OMAP3430_REGADDR_SHIFT) | > + (slave_addr << OMAP3430_SLAVEADDR_SHIFT); > + > + prm_write_mod_reg(value, OMAP3430_GR_MOD, > + OMAP3_PRM_VC_BYPASS_VAL_OFFSET); > + > + value = prm_set_mod_reg_bits(OMAP3430_VALID, OMAP3430_GR_MOD, > + OMAP3_PRM_VC_BYPASS_VAL_OFFSET); > + /* > + * Do continous 50 checks then follow with a 10usec delay, > + * then check again > + */ > + do { > + value = prm_read_mod_reg(OMAP3430_GR_MOD, > + OMAP3_PRM_VC_BYPASS_VAL_OFFSET) > + & OMAP3430_VALID; > + /* should i wait? */ > + if (value && (count % 50)) { > + udelay(10); > + *timeout_us -= 10; > + } > + count--; > + } while (value && count); > + if (!count) { > + pr_err("VC:Command Timedout! slave_addr=0x%02X," > + "reg=0x%02X, value=0x%02X", slave_addr, reg_addr, data); > + return -ETIMEDOUT; > + } > + return 0; > +} > +EXPORT_SYMBOL(vc_send_command); > + > +/** > + * @brief sr_vc_bypass - setup voltage using VC Bypass technique > + * > + * @param target_opp - target opp to go to > + * @param current_opp - current opp > + * @param target_vsel - which voltage to go to? > + * @param current_vsel - current voltage > + * > + * @return -success or failure > + */ > +#ifdef CONFIG_OMAP_VC_BYPASS_UPDATE > +static int sr_vc_bypass(struct omap_sr *sr, > + u32 target_opp_no, u8 target_vsel, u8 current_vsel) > +{ > + int ret = 0; > + struct omap_sr_vp *vp = &sr->vp; > + u32 vpconfig_value; > + > + vpconfig_value = vp->vpconfig_value; > + vpconfig_value |= > + ((target_opp_no < > + sr->opp_boundary) ? SR_ERRGAIN_LOWOP : SR_ERRGAIN_HIGHOPP) << > + OMAP3430_ERRORGAIN_SHIFT; > + vpconfig_value |= target_vsel << OMAP3430_INITVOLTAGE_SHIFT; > + prm_write_mod_reg(vpconfig_value, OMAP3430_GR_MOD, > + vp->prm_vpx_config_offset); > + > + prm_rmw_mod_reg_bits(OMAP3430_VC_CMD_ON_MASK, > + (target_vsel << OMAP3430_VC_CMD_ON_SHIFT), > + OMAP3430_GR_MOD, vp->prm_vc_cmd_val_offset); > + > + /* > + * Various PMIC might need a set of commands > + * provide hooks for specific PMICs to implement > + */ > + ret = omap_pmic_voltage_cmds(sr->srid, target_vsel); > + > + /* delay based on pmic */ > + if (!ret) > + udelay(omap_pmic_voltage_ramp_delay(sr->srid, > + target_vsel, current_vsel)); > + > + WARN_ON(ret); > + > + return ret; > +} > +#endif /* ifdef CONFIG_OMAP_VC_BYPASS_UPDATE */ > + > +/********************* SR Private functions ***************************/ > + > +/** > + * @brief sr_write_reg - write to Smart Reflex Register > + * > + * @param sr - pointer to SR structure > + * @param offset - SR reg offset to write to > + * @param value - value to write with > + */ > +static inline void sr_write_reg(struct omap_sr *sr, unsigned offset, u32 value) > +{ > + __raw_writel(value, SR_REGADDR(offset)); > +} > + > +/** > + * @brief sr_modify_reg - Modify a register and write a new value to a field > + * > + * @param sr -pointer to SR structure > + * @param offset -register offset > + * @param mask -mask to clear out > + * @param value -value to write there > + */ > +static inline void sr_modify_reg(struct omap_sr *sr, unsigned offset, u32 mask, > + u32 value) > +{ > + u32 reg_val; > + > + reg_val = __raw_readl(SR_REGADDR(offset)); > + reg_val &= ~mask; > + reg_val |= value; > + > + __raw_writel(reg_val, SR_REGADDR(offset)); > +} > + > +/** > + * @brief sr_read_reg - read a SR register > + * > + * @param sr - pointer to SR structure > + * @param offset - register offset > + * > + * @return value in that register > + */ > +static inline u32 sr_read_reg(struct omap_sr *sr, unsigned offset) > +{ > + return __raw_readl(SR_REGADDR(offset)); > +} > + > +/** > + * @brief sr_vplimito_value -return the timeout value based on sysclk > + * and desired timeout uSec > + * > + * @param sys_clk_speed - internal sysclk freq in hz > + * @param timeout_us - timeout in uSec > + * > + * @return timeout value to use in VPLIMITTO:TIMEOUT reg > + */ > +static inline u32 sr_vplimito_value(u32 sys_clk_speed, u16 timeout_us) > +{ > + u32 timeout_val; > + /* prevent round off errors, we will divide by 10 later */ > + timeout_val = (sys_clk_speed / 100000); > + timeout_val *= timeout_us; > + timeout_val /= 10; > + return timeout_val; > +} > + > +/** > + * @brief sr_clk_enable - SR clock enable > + * > + * @param sr - Structure to SR structure > + * > + * @return - result > + */ > +static int sr_clk_enable(struct omap_sr *sr) > +{ > + if (clk_enable(sr->iclk) != 0) { > + pr_crit("SR:Could not enable %s for [%d]\n", > + sr->iclk->name, sr->srid); > + return -EINVAL; > + } > + if (clk_enable(sr->fclk) != 0) { > + pr_crit("SR:Could not enable %s for [%d]\n", > + sr->fclk->name, sr->srid); > + clk_disable(sr->iclk); > + return -EINVAL; > + } > + sr_modify_reg(sr, ERRCONFIG, > + SR_CLKACTIVITY_MASK | ERRCONFIG_INTERRUPT_STATUS_MASK, > + SR_CLKACTIVITY_IOFF_FON); > + sr->is_sr_reset = 0; > + > + return 0; > +} > + > +/** > + * @brief sr_clk_disable - SR func clock disable > + * > + * @param sr - pointer to SR structure > + */ > +static void sr_clk_disable(struct omap_sr *sr) > +{ > + /* set fclk, iclk- idle */ > + sr_modify_reg(sr, ERRCONFIG, > + SR_CLKACTIVITY_MASK | ERRCONFIG_INTERRUPT_STATUS_MASK, > + SR_CLKACTIVITY_IOFF_FOFF); > + > + clk_disable(sr->fclk); > + clk_disable(sr->iclk); > + sr->is_sr_reset = 1; > +} > + > +/****************** Voltage processor functions ***************************/ > + > +/** > + * @brief sr_vp_clear_vptransdone - clear vptrans_done event > + * > + * @param sr - sr pointer > + * > + * @return 0 if cleared ok, else 1 if timedout! > + */ > +static int sr_vp_clear_vptransdone(struct omap_sr *sr) > +{ > + struct omap_sr_vp *vp = &sr->vp; > + u32 irqstat; > + u32 count = COUNT_TIMEOUT_TRANSDONE_CLR; > + do { > + prm_write_mod_reg(vp->irqmask_trans_done, OCP_MOD, > + OMAP3_PRM_IRQSTATUS_MPU_OFFSET); > + irqstat = prm_read_mod_reg(OCP_MOD, > + OMAP3_PRM_IRQSTATUS_MPU_OFFSET) & > + vp->irqmask_trans_done; > + if (irqstat) > + udelay(1); > + count--; > + } while (count && irqstat); > + if (!count) { > + pr_crit("SR:VPTransdone[%d]:Timedout\n", sr->srid); > + return -ETIMEDOUT; > + } > + return 0; > +} > + > +/** > + * @brief sr_vp_forceupdate - do a forceupdate method > + * to update the voltage level > + * > + * @param sr - pointer to sr structure > + * @param target_opp_no - targetted opp number > + * @param target_vsel - targetted voltage level > + * @param current_vsel - current voltage level > + * > + * @return 0 if all worked out, else 1 > + */ > +#ifndef CONFIG_OMAP_VC_BYPASS_UPDATE > +static int sr_vp_forceupdate(struct omap_sr *sr, u32 target_opp_no, > + u8 target_vsel, u8 current_vsel) > +{ > + u32 count; > + u32 irqstat; > + u32 vpconfig_value; > + u32 retry_counter = COUNT_RETRY_SMPSNOACK; > + > + struct omap_sr_vp *vp = &sr->vp; > + > +retry_forceupdate: > + /* First clear any pending events in the system */ > + if (sr_vp_clear_vptransdone(sr)) { > + pr_crit("SR:forceupdate-transdone1[%d]:timedout\n", sr->srid); > + return -ETIMEDOUT; > + } > + > + vpconfig_value = vp->vpconfig_value; > + vpconfig_value |= > + ((target_opp_no < > + sr->opp_boundary) ? SR_ERRGAIN_LOWOP : SR_ERRGAIN_HIGHOPP) << > + OMAP3430_ERRORGAIN_SHIFT; > + vpconfig_value |= target_vsel << OMAP3430_INITVOLTAGE_SHIFT; > + > + prm_write_mod_reg(vpconfig_value, OMAP3430_GR_MOD, > + vp->prm_vpx_config_offset); > + > + /* Trigger initVDD value copy to voltage processor */ > + prm_set_mod_reg_bits(OMAP3430_INITVDD, OMAP3430_GR_MOD, > + vp->prm_vpx_config_offset); > + > + /* Force update of voltage */ > + prm_set_mod_reg_bits(OMAP3430_FORCEUPDATE, OMAP3430_GR_MOD, > + vp->prm_vpx_config_offset); > + > + /* Clear initVDD copy trigger bit */ > + prm_clear_mod_reg_bits(OMAP3430_INITVDD, OMAP3430_GR_MOD, > + vp->prm_vpx_config_offset); > + /* Clear force bit */ > + prm_clear_mod_reg_bits(OMAP3430_FORCEUPDATE, OMAP3430_GR_MOD, > + vp->prm_vpx_config_offset); > + > + /* Now wait for the i2c transactions to complete */ > + count = COUNT_TIMEOUT_TRANSDONE_SET; > + irqstat = 0; > + do { > + irqstat = prm_read_mod_reg(OCP_MOD, > + OMAP3_PRM_IRQSTATUS_MPU_OFFSET) & > + vp->irqmask_trans_done; > + if (!irqstat) > + udelay(1); > + count--; > + } while (count && !irqstat); > + if (!count) { > + irqstat = prm_read_mod_reg(OCP_MOD, > + OMAP3_PRM_IRQSTATUS_MPU_OFFSET); > + if (irqstat & vp->irqmask_smps_noack) { > + WARN(irqstat, "SMPS NO ACK DETECTED[0x%08X]!!" > + "ATTEMPTING RECOVERY [%d left]\n", > + irqstat, retry_counter); > + prm_write_mod_reg(irqstat, OCP_MOD, > + OMAP3_PRM_IRQSTATUS_MPU_OFFSET); > + retry_counter--; > + if (retry_counter) > + goto retry_forceupdate; > + } > + pr_crit("SR:forceupdate-transdone[%d]:timedout-" > + "irqstat=0x%08X\n", sr->srid, irqstat); > + BUG(); > + return -ETIMEDOUT; > + } > + > + /* > + * Now we wait for voltage to rise on PMIC > + */ > + udelay(omap_pmic_voltage_ramp_delay(sr->srid, target_vsel, > + current_vsel)); > + > + /* clear that event */ > + if (sr_vp_clear_vptransdone(sr)) { > + pr_crit("SR:forceupdate-transdone2[%d]:timedout\n", sr->srid); > + BUG(); > + return -ETIMEDOUT; > + } > + return 0; > +} > +#endif /* ifndef CONFIG_OMAP_VC_BYPASS_UPDATE */ > + > +/** > + * @brief sr_vp_enable - enable VP enable code > + * > + * @param sr > + */ > +static int sr_vp_enable(struct omap_sr *sr, u32 target_opp_no) > +{ > + u32 vpconfig_value; > + struct omap_sr_vp *vp = &sr->vp; > + > + /* Disable VP */ > + prm_clear_mod_reg_bits(vp->vpenable_mask, OMAP3430_GR_MOD, > + vp->prm_vpx_config_offset); > + /* Clear INITVDD */ > + prm_clear_mod_reg_bits(OMAP3430_INITVDD, OMAP3430_GR_MOD, > + vp->prm_vpx_config_offset); > + > + vpconfig_value = vp->vpconfig_value; > + vpconfig_value |= get_vsel_for_opp(sr, target_opp_no) << > + OMAP3430_INITVOLTAGE_SHIFT; > + vpconfig_value |= > + ((target_opp_no < > + sr->opp_boundary) ? SR_ERRGAIN_LOWOP : SR_ERRGAIN_HIGHOPP) << > + OMAP3430_ERRORGAIN_SHIFT; > + > + prm_write_mod_reg(vpconfig_value, OMAP3430_GR_MOD, > + vp->prm_vpx_config_offset); > + > + prm_write_mod_reg(vp->vpstepmin_value, OMAP3430_GR_MOD, > + vp->prm_vpx_stepmin_offset); > + prm_write_mod_reg(vp->vpstepmax_value, OMAP3430_GR_MOD, > + vp->prm_vpx_stepmax_offset); > + prm_write_mod_reg(vp->vplimito_value, OMAP3430_GR_MOD, > + vp->prm_vpx_limito_offset); > + > + /* write1 to latch */ > + prm_set_mod_reg_bits(OMAP3430_INITVDD, OMAP3430_GR_MOD, > + vp->prm_vpx_config_offset); > + /* write2 clear */ > + prm_clear_mod_reg_bits(OMAP3430_INITVDD, OMAP3430_GR_MOD, > + vp->prm_vpx_config_offset); > + /* Enable VP */ > + prm_set_mod_reg_bits(vp->vpenable_mask, OMAP3430_GR_MOD, > + vp->prm_vpx_config_offset); > + return 0; > +} > + > +/** > + * @brief sr_vp_disable - disbale Voltage processor > + * > + * @param sr - sr structure > + * > + * @return 0 if all ok, else return -ETIMEDOUT > + */ > +static int sr_vp_disable(struct omap_sr *sr) > +{ > + int count; > + u32 v; > + struct omap_sr_vp *vp = &sr->vp; > + > + v = prm_read_mod_reg(OMAP3430_GR_MOD, > + vp->prm_vpx_config_offset) & vp->vpenable_mask; > + /* Am i already disabled? */ > + if (!v) { > + pr_info("SR[%d] attempt to disable VP when already disabled!\n", > + sr->srid); > + return 0; > + } > + > + /* Disable VP */ > + prm_clear_mod_reg_bits(vp->vpenable_mask, OMAP3430_GR_MOD, > + vp->prm_vpx_config_offset); > + > + /* Wait for vp to get idle - clear any events pending */ > + count = COUNT_TIMEOUT_MCUDISACK; > + do { > + v = prm_read_mod_reg(OMAP3430_GR_MOD, > + vp->prm_vpx_status_offset) & > + PRM_VP_STATUS_VPINIDLE; > + if (!v) > + udelay(1); > + count--; > + } while (count && !v); > + if (unlikely(!count)) { > + v = prm_read_mod_reg(OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET); > + pr_warning("SR[%d]:vpdisable-vpinidle[opp=%d]:timedout-" > + "irqstat=0x%08X\n", sr->srid, sr->req_opp_no, v); > + return -ETIMEDOUT; > + } > + return 0; > +} > + > +/** > + * @brief sr_vp_configure - configure the basic SR structure > + * > + * @param sr - pointer to SR structure > + */ > +static void sr_vp_configure(struct omap_sr *sr) > +{ > + u32 target_opp_no; > + u32 target_vsel; > + u32 prm_vpx_voltage; > + > + target_opp_no = get_current_opp_number_from_sr(sr); > + target_vsel = get_vsel_for_opp(sr, target_opp_no); > + prm_vpx_voltage = prm_read_mod_reg(OMAP3430_GR_MOD, > + sr->vp.prm_vpx_voltage_offset); > + sr_vp_enable(sr, target_opp_no); > + if (SR_CHOSEN_VOLTAGE_UPDATE_MECH > + (sr, target_opp_no, target_vsel, prm_vpx_voltage)) > + pr_crit("SR[%d] CONFIGURE VP failed!!\n", sr->srid); > +} > + > +/** > + * @brief sr_vp_reset_voltage - reset the voltages back to DVFS values > + * > + * @param srid -SRID > + * > + * @return 0 if ok, else result > + */ > +static int sr_vp_reset_voltage(u8 srid) > +{ > + u32 target_opp_no; > + u32 target_vsel; > + u32 prm_vpx_voltage; > + struct omap_sr *sr; > + > + sr = get_sr(srid); > + target_opp_no = sr->req_opp_no; > + target_vsel = get_vsel_for_opp(sr, target_opp_no); > + prm_vpx_voltage = prm_read_mod_reg(OMAP3430_GR_MOD, > + sr->vp.prm_vpx_voltage_offset); > + return SR_CHOSEN_VOLTAGE_UPDATE_MECH(sr, target_opp_no, > + target_vsel, prm_vpx_voltage); > + > +} > + > +/*********************** SR functions *************************/ > + > +/** > + * @brief sr_enable - enable smart reflex > + * > + * @param sr - smartreflex structure we are interest > + * @param target_opp_no - target opp we want to switch to > + * > + * @return 0 if all went right, else return err val > + */ > +static int sr_enable(struct omap_sr *sr, u32 target_opp_no) > +{ > + u32 value; > + > + if (!sr->is_sr_reset) { > + pr_info("SR[%d]already enabled\n", sr->srid); > + return -EINVAL; > + } > + > + sr->req_opp_no = target_opp_no; > + > + value = sr->opp_nvalue[target_opp_no - 1]; > + if (value == 0) { > + pr_info("SR[%d]:OPP%d doesn't support SmartReflex\n", > + sr->srid, target_opp_no); > + return -EINVAL; > + } > + > + sr_clk_enable(sr); > + /* Start with setting SREnable as 0 */ > + sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, 0); > + > + sr_write_reg(sr, SRCONFIG, sr->sr_config_value); > + > + sr_write_reg(sr, NVALUERECIPROCAL, value); > + > + value = sr->sr_errconfig_value | > + ((target_opp_no < sr->opp_boundary) ? SR_ERRMINLIMIT_LOWOPP : > + SR_ERRMINLIMIT_HIGHOPP); > + > + sr_write_reg(sr, ERRCONFIG, value); > + > + /* SRCONFIG - enable SR */ > + sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, SRCONFIG_SRENABLE); > + > + return 0; > +} > + > +/** > + * @brief sr_disable - disable Smart Reflex > + * > + * @param sr - pointer to sr structure of interest > + * > + * @return 0 if all went right, else return INVAL/TIMEDOUT > + */ > +int sr_disable(struct omap_sr *sr) > +{ > + int count; > + u32 stat; > + u32 value; > + > + if (sr->is_sr_reset) { > + pr_info("SR[%d]-disable:already Disabled\n", sr->srid); > + return -EINVAL; > + } > + value = sr_read_reg(sr, SRCONFIG) & SRCONFIG_SRENABLE; > + if (!value) { > + pr_info("SR[%d] attempt to disable SR when already disabled!\n", > + sr->srid); > + return 0; > + } > + value = sr->opp_nvalue[sr->req_opp_no - 1]; > + if (value == 0) { > + pr_info("SR[%d]-disable:" > + "OPP%d doesn't support SmartReflex\n", > + sr->srid, sr->req_opp_no); > + return -EINVAL; > + } > + /* Enable the MCUDISACKINST */ > + sr_modify_reg(sr, ERRCONFIG, ERRCONFIG_MCUDISACKINTEN | > + ERRCONFIG_INTERRUPT_STATUS_MASK, > + ERRCONFIG_MCUDISACKINTEN); > + > + /* SRCONFIG - disable SR */ > + sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, 0); > + > + /* Disable VPBOUND interrupt and clear any status > + * before actually waiting for disack > + * should be done after sr is disabled > + */ > + sr_modify_reg(sr, ERRCONFIG, ERRCONFIG_VPBOUNDINTEN | > + ERRCONFIG_INTERRUPT_STATUS_MASK, ERRCONFIG_VPBOUNDINTST); > + > + /* Wait for MCUDISACKINTST to be set */ > + count = COUNT_TIMEOUT_MCUDISACK; > + do { > + stat = sr_read_reg(sr, ERRCONFIG) & ERRCONFIG_MCUDISACKINTST; > + if (!stat) > + udelay(1); > + count--; > + } while (count && !stat); > + /* Clear the event and disable MCUDISACKINST */ > + sr_modify_reg(sr, ERRCONFIG, ERRCONFIG_MCUDISACKINTEN | > + ERRCONFIG_INTERRUPT_STATUS_MASK, > + ERRCONFIG_MCUDISACKINTST); > + > + if (!count) { > + pr_crit("SR[%d]-disable:MCUDIS timedout\n", sr->srid); > + return -ETIMEDOUT; > + } > + sr_clk_disable(sr); > + return 0; > +} > + > +/**************** Common enable/disable functionality *********************/ > + > +/** > + * @brief srvp_disable - disable SR and VP > + * These functions are based on h/w timeouts and should ideally not fail. > + * > + * @param sr -sr struct > + * > + * @return result > + */ > +static int srvp_disable(struct omap_sr *sr) > +{ > + int ret; > + /* If we dont have an nvalue, dont bother.. */ > + if (!sr->opp_nvalue[sr->req_opp_no - 1]) { > + pr_warning("SR[%d]: OPP%d does not support SR to disable\n", > + sr->srid, sr->req_opp_no); > + return -EINVAL; > + } > + ret = sr_vp_disable(sr); > + if (unlikely(ret)) { > + pr_err("SR[%d]: failed to disable vp:%d\n", sr->srid, ret); > + } else { > + ret = sr_disable(sr); > + if (unlikely(ret)) > + pr_err("SR[%d]: failed to disable sr:%d\n", > + sr->srid, ret); > + } > + /* > + * Does not make much sense renabling SR as > + * system is going to be in an invalid state > + */ > + WARN_ON(ret); > + return ret; > +} > + > +/** > + * @brief srvp_enable - enable SR and VP > + * These functions are based on h/w timeouts and should ideally not fail. > + * > + * @param sr -sr struct > + * @param target_opp -opp to go to > + * > + * @return result > + */ > +static int srvp_enable(struct omap_sr *sr, u32 target_opp) > +{ > + int ret; > + > + /* If we dont have an nvalue, dont bother.. */ > + if (!sr->opp_nvalue[target_opp - 1]) { > + pr_warning("SR[%d]: OPP%d does not support SR to enable\n", > + sr->srid, target_opp); > + return -EINVAL; > + } > + ret = sr_vp_enable(sr, target_opp); > + if (unlikely(ret)) { > + pr_err("SR[%d]: failed to enable vp:%d\n", sr->srid, ret); > + } else { > + ret = sr_enable(sr, target_opp); > + /* Attempt to recover */ > + if (unlikely(ret)) { > + pr_err("SR[%d]: failed to enable sr:%d\n", sr->srid, > + ret); > + /* nothing we can do if vp_disable fails */ > + (void)sr_vp_disable(sr); > + } > + } > + /* > + * potentially system in an invalid state - warn.. > + */ > + WARN_ON(ret); > + return ret; > +} > + > +/*********************** DVFS Entry POINTS **********************************/ > + > +/** > + * @brief sr_vp_enable_both - enable both vp and sr > + * > + * @param target_opp - targetted op > + * @param current_opp - current opp > + * > + * @return 0 if ok, 1 if not ok > + */ > +int sr_vp_enable_both(u32 target_opp, u32 current_opp) > +{ > + struct omap_sr *sr; > + u32 vdd, target_opp_no; > + int ret = 0; > + > + vdd = get_vdd(target_opp); > + target_opp_no = get_opp_no(target_opp); > + sr = get_sr_from_vdd(vdd); > + > + if (sr->is_autocomp_active && sr->is_sr_reset) { > + ret = srvp_enable(sr, target_opp_no); > + if (ret) { > + pr_err("SR[%d]:enableboth:" > + "failed enable SR\n", sr->srid); > + } > + } > + return ret; > +} > +EXPORT_SYMBOL(sr_vp_enable_both); > + > +/** > + * @brief sr_vp_disable_both - disable both vp and sr > + * > + * @param target_opp - targetted opp > + * @param current_opp - current opp > + * > + * @return 0 if ok, 1 if not ok > + */ > +int sr_vp_disable_both(u32 target_opp, u32 current_opp) > +{ > + struct omap_sr *sr; > + u32 vdd; > + int ret = 0; > + > + vdd = get_vdd(target_opp); > + sr = get_sr_from_vdd(vdd); > + > + if (sr->is_autocomp_active && !sr->is_sr_reset) { > + ret = srvp_disable(sr); > + if (ret) { > + pr_err("SR[%d]:disableboth:" > + "failed disable SR\n", sr->srid); > + } > + } > + > + return ret; > + > +} > +EXPORT_SYMBOL(sr_vp_disable_both); > + > +/** > + * @brief sr_voltage_set - setup a voltage requested > + * > + * @param target_opp - targetted opp > + * @param current_opp - current opp > + * @param target_vsel - targeted voltage > + * @param current_vsel - current voltage > + * > + * @return - result of op -0 if ok, else value > + */ > +int sr_voltage_set(u32 target_opp, u32 current_opp, > + u8 target_vsel, u8 current_vsel) > +{ > + struct omap_sr *sr; > + u8 vdd, target_opp_no; > + int ret; > + > + vdd = get_vdd(target_opp); > + target_opp_no = get_opp_no(target_opp); > + sr = get_sr_from_vdd(vdd); > + > + ret = > + SR_CHOSEN_VOLTAGE_UPDATE_MECH(sr, target_opp_no, target_vsel, > + current_vsel); > + > + return ret; > +} > +EXPORT_SYMBOL(sr_voltage_set); > + > +/*********************** CPUIDLE ENTRY POINTS *********************************/ > + > +/** > + * @brief disable_smartreflex - disable SmartReflex before WFI > + * > + * @param srid SRID > + */ > +void disable_smartreflex(u8 srid) > +{ > + struct omap_sr *sr = NULL; > + int ret; > + u32 current_opp_no; > + > + /* I want to be in irq_disabled context.. > + * else I will die.. find the rootcause and fix it instead > + */ > + BUG_ON(!irqs_disabled()); > + > + sr = get_sr(srid); > + > + current_opp_no = get_current_opp_number_from_sr(sr); > + > + if (sr->is_autocomp_active && !sr->is_sr_reset) { > + sr->req_opp_no = current_opp_no; > + ret = srvp_disable(sr); > + if (ret) > + pr_err("SR[%d]:disable_smartreflex:" > + "failed disable SR\n", sr->srid); > + } > + > + /* Reset the voltage for current OPP to nominal if SR was enabled */ > + if (sr->is_autocomp_active) > + sr_vp_reset_voltage(srid); > +} > +EXPORT_SYMBOL(disable_smartreflex); > + > +/** > + * @brief enable_smartreflex - enable smart reflex after WFI is hit > + * > + * @param srid -SR ID to hit > + */ > +void enable_smartreflex(u8 srid) > +{ > + struct omap_sr *sr; > + int ret; > + u32 current_opp_no; > + > + /* I want to be in irq_disabled context.. > + * else I will die.. find the rootcause and fix it instead > + */ > + BUG_ON(!irqs_disabled()); > + > + sr = get_sr(srid); > + current_opp_no = get_current_opp_number_from_sr(sr); > + > + if (sr->is_autocomp_active && sr->is_sr_reset) { > + ret = srvp_enable(sr, current_opp_no); > + if (ret) > + pr_err("SR[%d]:enable_smartreflex:" > + "failed enable SR\n", sr->srid); > + } > +} > +EXPORT_SYMBOL(enable_smartreflex); > + > +/*********************** SYSFS ENTRY POINTS *********************************/ > +/** > + * @brief omap_sr_vdd_autocomp_show - Sysfs entry for showing SR status > + * > + */ > +static ssize_t omap_sr_vdd_autocomp_show(struct kobject *kobj, > + struct kobj_attribute *attr, char *buf) > +{ > + struct omap_sr *sr; > + sr = get_sr_from_vdd_name((char *)attr->attr.name); > + return sprintf(buf, "%d\n", sr->is_autocomp_active); > +} > + > +/** > + * @brief omap_sr_vdd_autocomp_store - enable/disable SR > + * > + */ > +static ssize_t omap_sr_vdd_autocomp_store(struct kobject *kobj, > + struct kobj_attribute *attr, > + const char *buf, size_t n) > +{ > + unsigned short value; > + struct omap_sr *sr; > + int ret = 0; > + char *name; > + > + name = (char *)attr->attr.name; > + > + sr = get_sr_from_vdd_name(name); > + > + if (sscanf(buf, "%hu", &value) != 1 || (value > 1)) { > + pr_err("%s: Invalid value[%d]. Use 0 or 1\n", name, value); > + return -EINVAL; > + } > + if (sr->is_autocomp_active == value) { > + pr_info("%s: Already set to %d \n", name, value); > + return n; > + } > + /* > + * Sanity check-might happen if SR and dvfs/idle paths collide > + * but unlikely though.. > + */ > + if (unlikely(value ^ sr->is_sr_reset)) { > + pr_warning("%s: Is already set %d Vs %d.\n", name, value, > + sr->is_sr_reset); > + return n; > + } > + > + if (value) { > + u32 current_vddopp_no = get_current_opp_number_from_sr(sr); > + ret = srvp_enable(sr, current_vddopp_no); > + } else { > + ret = srvp_disable(sr); > + /* reset the voltage back to nominal */ > + sr_vp_configure(sr); > + } > + if (!ret) { > + sr->is_autocomp_active = value; > + ret = n; > + } > + > + return ret; > +} > + > +/*********************** INIT FUNCTIONS *************************************/ > + > +/** > + * @brief srvp_init - configure smart reflex and VP params > + * > + * @param sr - structure of sr of interest > + */ > +static void __init srvp_init(struct omap_sr *sr) > +{ > + struct clk *sys_ck; > + u32 sys_clk_speed; > + u32 clk_len; > + u32 senn_mod, senp_mod; > + u8 opp_count; > + > + /* Grab the clock speed */ > + sys_ck = clk_get(NULL, "sys_ck"); > + sys_clk_speed = clk_get_rate(sys_ck); > + clk_put(sys_ck); > + > + switch (sys_clk_speed) { > + case 12000000: > + clk_len = SRCLKLENGTH_12MHZ_SYSCLK; > + break; > + case 13000000: > + clk_len = SRCLKLENGTH_13MHZ_SYSCLK; > + break; > + case 19200000: > + clk_len = SRCLKLENGTH_19MHZ_SYSCLK; > + break; > + case 26000000: > + clk_len = SRCLKLENGTH_26MHZ_SYSCLK; > + break; > + case 38400000: > + clk_len = SRCLKLENGTH_38MHZ_SYSCLK; > + break; > + default: > + pr_err("SR[%d]:Invalid sysclk value: %d\n", sr->srid, > + sys_clk_speed); > + BUG(); > + return; > + } > + /* The original nvalue contents were the register offsets > + * now we replace them with the nvalue to be used elsewhere > + */ > + for (opp_count = 0; opp_count < sr->num_opp; opp_count++) > + sr->opp_nvalue[opp_count] = > + omap_ctrl_readl(sr->opp_nvalue[opp_count]); > + > + sr->vp.vplimito_value |= sr_vplimito_value(sys_clk_speed, > + sr->vp.prm_vpx_vlimito_timeout) > + << sr->vp.prm_vpx_vlimito_shift; > + senn_mod = (omap_ctrl_readl(OMAP343X_CONTROL_FUSE_SR) & > + sr->sr_n_mod_mask) >> sr->sr_n_mod_shift; > + senp_mod = (omap_ctrl_readl(OMAP343X_CONTROL_FUSE_SR) & > + sr->sr_p_mod_mask) >> sr->sr_p_mod_shift; > + sr->sr_config_value = > + (clk_len << SRCONFIG_SRCLKLENGTH_SHIFT) | SRCONFIG_ERRGEN_EN | > + SRCONFIG_SENENABLE | (senn_mod << SRCONFIG_SENNENABLE_SHIFT) | > + (senp_mod << SRCONFIG_SENPENABLE_SHIFT) | SRCONFIG_DELAYCTRL; > + > + /* Set up nominal voltage */ > + sr_vp_configure(sr); > +} > + > +/** > + * @brief omap_sr_init - SR initialization > + * > + * @return 0 > + */ > +static int __init omap_sr_init(void) > +{ > + int ret = 0; > + int i; > + ret = omap_pmic_srinit(); > + if (ret) { > + pr_crit("PMIC init failed during SmartReflex initilization." > + "connectivity issues?: %d\n", ret); > + return ret; > + } > + if (cpu_is_omap3430()) { > + omap_srlist = kzalloc(sizeof(omap34xx_srlist), GFP_KERNEL); > + if (!omap_srlist) { > + ret = -ENOMEM; > + goto fail_cleanup; > + } > + omap_srlist->num_sr = omap34xx_srlist.num_sr; > + for (i = 0; i < omap_srlist->num_sr; i++) { > + int size = sizeof(*omap34xx_srlist.sr_list[i]); > + size += > + sizeof(u32) * omap34xx_srlist.sr_list[i]->num_opp; > + omap_srlist->sr_list[i] = kzalloc(size, GFP_KERNEL); > + if (!omap_srlist->sr_list[i]) { > + ret = -ENOMEM; > + goto fail_cleanup; > + } > + memcpy(omap_srlist->sr_list[i], > + omap34xx_srlist.sr_list[i], size); > + } > + } else { > + pr_warning("SmartReflex is not supported on this OMAP\n"); > + return -ENODEV; > + } > + > + /* Create the userspace control knobs */ > + for (i = 0; i < omap_srlist->num_sr; i++) { > + struct omap_sr *sr = get_sr(i + 1); > + sr->fclk = clk_get(NULL, sr->fclk_name); > + sr->iclk = clk_get(NULL, sr->iclk_name); > + sr->srbase_addr = ioremap((u32) sr->srbase_addr, SZ_4K); > + srvp_init(sr); > + if (sysfs_create_file(power_kobj, &sr->autocom_attr.attr)) > + pr_warning("SR: sysfs_create_file failed[%d]: %d\n", i, > + ret); > + } > + if (sr_debugfs_create_entries_late()) > + pr_warning("SR: debugfs_create_file failed\n"); > + > + pr_info("SmartReflex driver initialized\n"); > + return 0; > +fail_cleanup: > + pr_warning("Out of memory..SmartReflex not initialized\n"); > + if (omap_srlist) { > + /* kfree is nullsafe */ > + for (i = 0; i < omap_srlist->num_sr; i++) > + kfree(omap_srlist->sr_list[i]); > + kfree(omap_srlist); > + } > + return ret; > +} > +late_initcall(omap_sr_init); > diff --git a/arch/arm/mach-omap2/smartreflex.h b/arch/arm/mach-omap2/smartreflex.h > new file mode 100644 > index 0000000..421f8b6 > --- /dev/null > +++ b/arch/arm/mach-omap2/smartreflex.h > @@ -0,0 +1,274 @@ > +#ifndef __ARCH_ARM_MACH_OMAP3_SMARTREFLEX_H > +#define __ARCH_ARM_MACH_OMAP3_SMARTREFLEX_H > +/* > + * linux/arch/arm/mach-omap2/smartreflex.h > + * > + * Copyright (C) 2009 Texas Instruments, Inc. > + * Nishanth Menon > + * > + * Copyright (C) 2008 Nokia Corporation > + * Kalle Jokiniemi > + * > + * Copyright (C) 2007 Texas Instruments, Inc. > + * Lesly A M <x0080970@ti.com> > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License version 2 as > + * published by the Free Software Foundation. > + */ > + > +/* SMART REFLEX REG ADDRESS OFFSET */ > +#define SRCONFIG 0x00 > +#define SRSTATUS 0x04 > +#define SENVAL 0x08 > +#define SENMIN 0x0C > +#define SENMAX 0x10 > +#define SENAVG 0x14 > +#define AVGWEIGHT 0x18 > +#define NVALUERECIPROCAL 0x1C > +#define SENERROR 0x20 > +#define ERRCONFIG 0x24 > + > +/* SR Modules */ > +#define SR1 1 > +#define SR2 2 > + > +#define VP1_IRQMASK_TRANSDONE (0x1 << 15) > +#define VP2_IRQMASK_TRANSDONE (0x1 << 21) > + > +/* PRM_VP1_CONFIG */ > +#define PRM_VP1_CONFIG_ERROROFFSET (0x00 << 24) > +#define PRM_VP1_CONFIG_ERRORGAIN (0x18 << 16) > +#define SR_ERRGAIN_LOWOP (0x0C) > +#define SR_ERRGAIN_HIGHOPP (0x18) > +#define SR_ERRMINLIMIT_LOWOPP (0xF4 << 0) > +#define SR_ERRMINLIMIT_HIGHOPP (0xF9 << 0) > +#define PRM_VP_STATUS_VPINIDLE (0x1 << 0) > + > +#define PRM_VP1_CONFIG_INITVOLTAGE (0x30 << 8) /* 1.2 volt */ > +#define PRM_VP1_CONFIG_TIMEOUTEN (0x1 << 3) > +#define PRM_VP1_CONFIG_INITVDD (0x1 << 2) > +#define PRM_VP1_CONFIG_FORCEUPDATE (0x1 << 1) > +#define PRM_VP1_CONFIG_VPENABLE (0x1 << 0) > + > +/* PRM_VP1_VSTEPMIN */ > +#define PRM_VP1_VSTEPMIN_SMPSWAITTIMEMIN (0x03C << 8) > +#define PRM_VP1_VSTEPMIN_VSTEPMIN (0x01 << 0) > + > +/* PRM_VP1_VSTEPMAX */ > +#define PRM_VP1_VSTEPMAX_SMPSWAITTIMEMAX (0x003C << 8) > +#define PRM_VP1_VSTEPMAX_VSTEPMAX (0x08 << 0) > + > +/* PRM_VP1_VLIMITTO */ > +#define PRM_VP1_VLIMITTO_VDDMAX (0x44 << 24) > +#define PRM_VP1_VLIMITTO_VDDMIN (0x14 << 16) > +#define PRM_VP1_VLIMITTO_TIMEOUT_US (200) > +#define PRM_VP1_VLIMITTO_TIMEOUT_SHIFT (0) > + > +/* PRM_VP2_CONFIG */ > +#define PRM_VP2_CONFIG_ERROROFFSET (0x00 << 24) > +#define PRM_VP2_CONFIG_ERRORGAIN (0x18 << 16) > + > +#define PRM_VP2_CONFIG_INITVOLTAGE (0x30 << 8) /* 1.2 volt */ > +#define PRM_VP2_CONFIG_TIMEOUTEN (0x1 << 3) > +#define PRM_VP2_CONFIG_INITVDD (0x1 << 2) > +#define PRM_VP2_CONFIG_FORCEUPDATE (0x1 << 1) > +#define PRM_VP2_CONFIG_VPENABLE (0x1 << 0) > + > +/* PRM_VP2_VSTEPMIN */ > +#define PRM_VP2_VSTEPMIN_SMPSWAITTIMEMIN (0x03C << 8) > +#define PRM_VP2_VSTEPMIN_VSTEPMIN (0x01 << 0) > + > +/* PRM_VP2_VSTEPMAX */ > +#define PRM_VP2_VSTEPMAX_SMPSWAITTIMEMAX (0x003C << 8) > +#define PRM_VP2_VSTEPMAX_VSTEPMAX (0x08 << 0) > + > +/* PRM_VP2_VLIMITTO */ > +#define PRM_VP2_VLIMITTO_VDDMAX (0x42 << 24) > +#define PRM_VP2_VLIMITTO_VDDMIN (0x18 << 16) > +#define PRM_VP2_VLIMITTO_TIMEOUT_US (200) > +#define PRM_VP2_VLIMITTO_TIMEOUT_SHIFT (0) > + > +/* SRCONFIG */ > +#define SRCLKLENGTH_12MHZ_SYSCLK 0x3C > +#define SRCLKLENGTH_13MHZ_SYSCLK 0x41 > +#define SRCLKLENGTH_19MHZ_SYSCLK 0x60 > +#define SRCLKLENGTH_26MHZ_SYSCLK 0x82 > +#define SRCLKLENGTH_38MHZ_SYSCLK 0xC0 > + > +#define SRCONFIG_SRCLKLENGTH_SHIFT 12 > +#define SRCONFIG_SENNENABLE_SHIFT 5 > +#define SRCONFIG_SENPENABLE_SHIFT 3 > + > +#define SRCONFIG_SRENABLE (0x01 << 11) > +#define SRCONFIG_SENENABLE (0x01 << 10) > +#define SRCONFIG_ERRGEN_EN (0x01 << 9) > +#define SRCONFIG_MINMAXAVG_EN (0x01 << 8) > + > +#define SRCONFIG_DELAYCTRL (0x01 << 2) > +#define SRCONFIG_CLKCTRL (0x00 << 0) > + > +/* NVALUERECIPROCAL */ > +#define NVALUERECIPROCAL_SENPGAIN_SHIFT 20 > +#define NVALUERECIPROCAL_SENNGAIN_SHIFT 16 > +#define NVALUERECIPROCAL_RNSENP_SHIFT 8 > +#define NVALUERECIPROCAL_RNSENN_SHIFT 0 > + > +/* ERRCONFIG */ > +#define SR_CLKACTIVITY_MASK (0x03 << 20) > +#define SR_ERRWEIGHT_MASK (0x07 << 16) > +#define SR_ERRMAXLIMIT_MASK (0xFF << 8) > +#define SR_ERRMINLIMIT_MASK (0xFF << 0) > + > +#define SR_CLKACTIVITY_IOFF_FOFF (0x00 << 20) > +#define SR_CLKACTIVITY_IOFF_FON (0x02 << 20) > + > +#define ERRCONFIG_VPBOUNDINTEN (0x1 << 31) > +#define ERRCONFIG_MCUDISACKINTEN (0x1 << 23) > + > +/* Status Bits */ > +#define ERRCONFIG_VPBOUNDINTST (0x1 << 30) > +#define ERRCONFIG_MCUACCUMINTST (0x1 << 28) > +#define ERRCONFIG_MCUVALIDINTST (0x1 << 26) > +#define ERRCONFIG_MCUBOUNDINTST (0x1 << 24) > +#define ERRCONFIG_MCUDISACKINTST (0x1 << 22) > + > +/* WARNING: Ensure all access to errconfig register skips > + * clearing intst bits to ensure that we dont clear status > + * bits unwantedly.. esp vpbound > + */ > +#define ERRCONFIG_INTERRUPT_STATUS_MASK (ERRCONFIG_VPBOUNDINTST |\ > + ERRCONFIG_MCUACCUMINTST |\ > + ERRCONFIG_MCUVALIDINTST |\ > + ERRCONFIG_MCUBOUNDINTST |\ > + ERRCONFIG_MCUDISACKINTST | (0X1<<19)) > + > +#define SR1_ERRWEIGHT (0x04 << 16) > +#define SR1_ERRMAXLIMIT (0x02 << 8) > +#define SR1_ERRMINLIMIT (0xFA << 0) > + > +#define SR2_ERRWEIGHT (0x04 << 16) > +#define SR2_ERRMAXLIMIT (0x02 << 8) > +#define SR2_ERRMINLIMIT (0xFA << 0) > + > +/* T2 SMART REFLEX */ > +#define R_SRI2C_SLAVE_ADDR 0x12 > +#define R_VDD1_SR_CONTROL 0x00 > +#define R_VDD2_SR_CONTROL 0x01 > + > +/* VDDs*/ > +#define PRCM_VDD1 1 > +#define PRCM_VDD2 2 > + This comment below can be removed, provided that you apply my other comments. > +/* > + * XXX: These should be removed/moved from here once we have a working DVFS > + * implementation in place > + */ > +#define PHY_TO_OFF_PM_MASTER(p) (p - 0x36) No need for PHY_TO_OFF_PM_MASTER definition. Remove that. > +#define PHY_TO_OFF_PM_RECIEVER(p) (p - 0x5b) > +#define PHY_TO_OFF_PM_INT(p) (p - 0x2e) No need for PHY_TO_OFF_PM_INT def. Remove. > + > +/* Vmode control */ > +#define R_DCDC_GLOBAL_CFG PHY_TO_OFF_PM_RECIEVER(0x61) > +/* R_DCDC_GLOBAL_CFG register, SMARTREFLEX_ENABLE values */ > +#define DCDC_GLOBAL_CFG_ENABLE_SRFLX 0x08 As we now have other ways of determining opp, remove code from here... > + > +/* DEVICE ID/DPLL ID/CLOCK ID: bits 28-31 for OMAP type */ > +#define OMAP_TYPE_SHIFT 28 > +#define OMAP_TYPE_MASK 0xF > +/* OPP ID: bits: 0-4 for OPP number */ > +#define OPP_NO_POS 0 > +#define OPP_NO_MASK 0x1F > +/* OPP ID: bits: 5-6 for VDD */ > +#define VDD_NO_POS 5 > +#define VDD_NO_MASK 0x3 > +/* Other IDs: bits 20-27 for ID type */ > +/* These IDs have bits 25,26,27 as 1 */ > +#define OTHER_ID_TYPE_SHIFT 20 > +#define OTHER_ID_TYPE_MASK 0xFF > + > +#define OTHER_ID_TYPE(X) ((X & OTHER_ID_TYPE_MASK) << OTHER_ID_TYPE_SHIFT) > +#define ID_OPP_NO(X) ((X & OPP_NO_MASK) << OPP_NO_POS) > +#define ID_VDD(X) ((X & VDD_NO_MASK) << VDD_NO_POS) > +#define OMAP(X) ((X >> OMAP_TYPE_SHIFT) & OMAP_TYPE_MASK) > +#define get_opp_no(X) ((X >> OPP_NO_POS) & OPP_NO_MASK) > +#define get_vdd(X) ((X >> VDD_NO_POS) & VDD_NO_MASK) > + > +/* XXX: end remove/move */ > + > +/* XXX: find more appropriate place for these once DVFS is in place */ > +extern u32 current_vdd1_opp; > +extern u32 current_vdd2_opp; ...to here. At least with a quick glance, it seems the above defs are not in use. Your compiler should tell if I missed something ;) - Kalle > + > +/* > + * Smartreflex module enable/disable interface. > + * NOTE: if smartreflex is not enabled from sysfs, these functions will not > + * do anything. > + */ > +#ifdef CONFIG_OMAP_SMARTREFLEX > +void enable_smartreflex(u8 srid); > +void disable_smartreflex(u8 srid); > +int sr_voltage_set(u32 target_opp, u32 current_opp, > + u8 target_vsel, u8 current_vsel); > +int sr_vp_disable_both(u32 target_opp, u32 current_opp); > +int sr_vp_enable_both(u32 target_opp, u32 current_opp); > +int vc_send_command(u8 slave_addr, u8 reg_addr, u8 data, u16 *timeout_us); > +int omap_pmic_srinit(void); > +u32 omap_pmic_voltage_ramp_delay(u8 srid, u8 target_vsel, u8 current_vsel); > +#ifdef CONFIG_OMAP_VC_BYPASS_UPDATE > +int omap_pmic_voltage_cmds(u8 srid, u8 target_vsel); > +#endif > + > +#ifdef CONFIG_PM_DEBUG > +#define __SR_DEBUG > +#endif > + > +#else > +static inline void enable_smartreflex(u8 srid) > +{ > +} > + > +static inline void disable_smartreflex(u8 srid) > +{ > +} > + > +static inline int sr_voltage_set(u32 target_opp, u32 current_opp, > + u8 target_vsel, u8 current_vsel) > +{ > + return -EINVAL; > +} > + > +static inline int sr_vp_disable_both(u32 target_opp, u32 current_opp) > +{ > + return -EINVAL; > +} > + > +static inline int sr_vp_enable_both(u32 target_opp, u32 current_opp) > +{ > + return -EINVAL; > +} > + > +static inline int vc_send_command(u8 slave_addr, u8 reg_addr, u8 data, > + u16 *timeout_us) > +{ > + return -EINVAL; > +} > + > +#ifdef CONFIG_OMAP_VC_BYPASS_UPDATE > +static inline int omap_pmic_voltage_cmds(u8 srid, u8 target_vsel) > +{ > + return -EINVAL; > +} > +#endif > +#endif > + > +#ifdef __SR_DEBUG > +int sr_debugfs_create_entries(struct dentry *d); > +#else > +static inline int sr_debugfs_create_entries(struct dentry *d) > +{ > + return -EINVAL; > +} > +#endif > + > +#endif /* __ARCH_ARM_MACH_OMAP3_SMARTREFLEX_H */ > diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig > index 2143db5..6a3302c 100644 > --- a/arch/arm/plat-omap/Kconfig > +++ b/arch/arm/plat-omap/Kconfig > @@ -81,19 +81,14 @@ config OMAP_SMARTREFLEX > 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" > +config OMAP_VC_BYPASS_UPDATE > + bool "Use VC Bypass method of updating voltage" > 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! > + Say Y if you would like to use VC Bypass method of > + update. If this is disabled, the default > + VP forceupdate method is used. > > config OMAP_RESET_CLOCKS > bool "Reset unused clocks during boot" > -- > 1.6.3.3 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-omap" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 16+ messages in thread
* RE: [PATCH 2/2 v3] OMAP3: PM: SR: SmartReflex Refactor Rev4.0 2009-10-27 15:13 ` Kalle Jokiniemi @ 2009-10-28 5:05 ` Menon, Nishanth 0 siblings, 0 replies; 16+ messages in thread From: Menon, Nishanth @ 2009-10-28 5:05 UTC (permalink / raw) To: Kalle Jokiniemi Cc: linux-omap@vger.kernel.org, Imberton Guilhem, Mike Chan, Nayak, Rajendra, Roger Quadros, Kalle Jokiniemi, Reddy, Teerth, Kevin Hilman, Paul Walmsley, Hogander Jouni > owner@vger.kernel.org] On Behalf Of Kalle Jokiniemi > Sent: Tuesday, October 27, 2009 5:14 PM > > Hi Nishanth, > > Found some dead code, see below: [...] > > +/* T2 SMART REFLEX */ > > +#define R_SRI2C_SLAVE_ADDR 0x12 > > +#define R_VDD1_SR_CONTROL 0x00 > > +#define R_VDD2_SR_CONTROL 0x01 > > + > > +/* VDDs*/ > > +#define PRCM_VDD1 1 > > +#define PRCM_VDD2 2 > > + > > This comment below can be removed, provided that you apply my other > comments. > > > +/* > > + * XXX: These should be removed/moved from here once we have a working > DVFS > > + * implementation in place > > + */ > > +#define PHY_TO_OFF_PM_MASTER(p) (p - 0x36) > > No need for PHY_TO_OFF_PM_MASTER definition. Remove that. > > > > +#define PHY_TO_OFF_PM_RECIEVER(p) (p - 0x5b) > > +#define PHY_TO_OFF_PM_INT(p) (p - 0x2e) > > No need for PHY_TO_OFF_PM_INT def. Remove. > > > + > > +/* Vmode control */ > > +#define R_DCDC_GLOBAL_CFG PHY_TO_OFF_PM_RECIEVER(0x61) > > +/* R_DCDC_GLOBAL_CFG register, SMARTREFLEX_ENABLE values */ > > +#define DCDC_GLOBAL_CFG_ENABLE_SRFLX 0x08 > > > As we now have other ways of determining opp, remove code from here... > > > + > > +/* DEVICE ID/DPLL ID/CLOCK ID: bits 28-31 for OMAP type */ > > +#define OMAP_TYPE_SHIFT 28 > > +#define OMAP_TYPE_MASK 0xF > > +/* OPP ID: bits: 0-4 for OPP number */ > > +#define OPP_NO_POS 0 > > +#define OPP_NO_MASK 0x1F > > +/* OPP ID: bits: 5-6 for VDD */ > > +#define VDD_NO_POS 5 > > +#define VDD_NO_MASK 0x3 > > +/* Other IDs: bits 20-27 for ID type */ > > +/* These IDs have bits 25,26,27 as 1 */ > > +#define OTHER_ID_TYPE_SHIFT 20 > > +#define OTHER_ID_TYPE_MASK 0xFF > > + > > +#define OTHER_ID_TYPE(X) ((X & OTHER_ID_TYPE_MASK) << > OTHER_ID_TYPE_SHIFT) > > +#define ID_OPP_NO(X) ((X & OPP_NO_MASK) << OPP_NO_POS) > > +#define ID_VDD(X) ((X & VDD_NO_MASK) << VDD_NO_POS) > > +#define OMAP(X) ((X >> OMAP_TYPE_SHIFT) & > OMAP_TYPE_MASK) > > +#define get_opp_no(X) ((X >> OPP_NO_POS) & OPP_NO_MASK) > > +#define get_vdd(X) ((X >> VDD_NO_POS) & VDD_NO_MASK) > > + > > +/* XXX: end remove/move */ > > + > > +/* XXX: find more appropriate place for these once DVFS is in place */ > > +extern u32 current_vdd1_opp; > > +extern u32 current_vdd2_opp; > > ...to here. > > At least with a quick glance, it seems the above defs are not in use. > Your compiler should tell if I missed something ;) Thanks... will fix in my rev 5. Regards, Nishanth Menon ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 2/2 v3] OMAP3: PM: SR: SmartReflex Refactor Rev4.0
@ 2009-10-26 15:13 Menon, Nishanth
0 siblings, 0 replies; 16+ messages in thread
From: Menon, Nishanth @ 2009-10-26 15:13 UTC (permalink / raw)
To: G, Manjunath Kondaiah, 'linux-omap@vger.kernel.org'
Cc: 'guilhem.imberton@motorola.com',
'mikechan@google.com', Nayak, Rajendra,
'ext-roger.quadros@nokia.com',
'ext-kalle.jokiniemi@nokia.com', Reddy, Teerth,
'khilman@deeprootsystems.com', 'paul@pwsan.com',
'jouni.hogander@nokia.com'
Trying not to top post.. Apologies before hand on my client restrictions. Anyways..
Manjunath,
Yes, the call sequences are common. We may consider using cpu_relax() in the context of dvfs calls.. Except it could result in race connditions not in intrest.
Do me a favor and flag the udelays u'd like to convert and send a patch for fix pls.
Regards,
Nishanth Menon
----- Original Message -----
From: G, Manjunath Kondaiah
To: Menon, Nishanth; linux-omap@vger.kernel.org <linux-omap@vger.kernel.org>
Cc: Imberton Guilhem <guilhem.imberton@motorola.com>; Mike Chan <mikechan@google.com>; Nayak, Rajendra; Roger Quadros <ext-roger.quadros@nokia.com>; Kalle Jokiniemi <ext-kalle.jokiniemi@nokia.com>; Reddy, Teerth; Kevin Hilman <khilman@deeprootsystems.com>; Paul Walmsley <paul@pwsan.com>; Hogander Jouni <jouni.hogander@nokia.com>
Sent: Mon Oct 26 10:09:07 2009
Subject: RE: [PATCH 2/2 v3] OMAP3: PM: SR: SmartReflex Refactor Rev4.0
> -----Original Message-----
> From: Menon, Nishanth
> Sent: Monday, October 26, 2009 3:48 PM
> To: G, Manjunath Kondaiah; linux-omap@vger.kernel.org
> Cc: Imberton Guilhem; Mike Chan; Nayak, Rajendra; Roger
> Quadros; Kalle Jokiniemi; Reddy, Teerth; Kevin Hilman; Paul
> Walmsley; Hogander Jouni
> Subject: RE: [PATCH 2/2 v3] OMAP3: PM: SR: SmartReflex Refactor Rev4.0
>
> > -----Original Message-----
> > From: G, Manjunath Kondaiah
> > Sent: Monday, October 26, 2009 3:40 AM
> > To: Menon, Nishanth; linux-omap@vger.kernel.org
> > Cc: Imberton Guilhem; Mike Chan; Nayak, Rajendra; Roger
> Quadros; Kalle
> > Jokiniemi; Reddy, Teerth; Kevin Hilman; Paul Walmsley;
> Hogander Jouni
> > Subject: RE: [PATCH 2/2 v3] OMAP3: PM: SR: SmartReflex
> Refactor Rev4.0
> >
> >
> > As per your comments for other patches when ever there is
> udelay usage,
> > cpu_relax is the better option. I see there are lot of
> udelay(...) calls
> > used in this patch. Why can't you use cpu_relax() or schedule().
> > Any specific reason?
> >
> Don’t really want to do cpu_relax in irq_locked context.. if
> you look at the code flow, the call from cpu_idle is in
> irq_locked.. Further this delay is part of bring up form
> saved context where there is nothing else scheduled + we
> don’t want anything else scheduled (and causing a change in
> scheduling decision). So unfortunately, unlike standard
> drivers, this cannot use the same reasoning.
>
NAK. My understanding is that, SR functions will be called during voltage
scaling also. Voltage scaling will happen in non IRQ locked context.
Please clarify if I am wrong.
-Manjunath
^ permalink raw reply [flat|nested] 16+ messages in threadend of thread, other threads:[~2009-10-28 5:17 UTC | newest]
Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <OMAP3:PM:SR: SmartReflex Refactor Rev3.0>
2009-10-24 5:15 ` [PATCH 0/2 v3] OMAP3: PM: refactor Smart Reflex Nishanth Menon
2009-10-24 5:15 ` [PATCH 1/2 v3] OMAP3: PM: SR: prepare: remove old SR code Nishanth Menon
2009-10-24 5:15 ` [PATCH 2/2 v3] OMAP3: PM: SR: SmartReflex Refactor Rev4.0 Nishanth Menon
2009-10-25 22:12 ` Cousson, Benoit
2009-10-25 22:59 ` Nishanth Menon
2009-10-26 13:05 ` Cousson, Benoit
2009-10-26 13:19 ` Menon, Nishanth
2009-10-26 17:06 ` Cousson, Benoit
[not found] ` <E0D41E29EB0DAC4E9F3FF173962E9E940253EFE01B@dbde02.ent.ti.com>
2009-10-26 10:18 ` Menon, Nishanth
2009-10-26 15:09 ` G, Manjunath Kondaiah
2009-10-27 23:36 ` Paul Walmsley
2009-10-28 5:17 ` Menon, Nishanth
[not found] ` <74583B8642AB8841B30447520659FCA9DDDFCC3A@dnce01.ent.ti.com>
2009-10-27 11:46 ` Imberton Guilhem-gimb01
2009-10-27 15:13 ` Kalle Jokiniemi
2009-10-28 5:05 ` Menon, Nishanth
2009-10-26 15:13 Menon, Nishanth
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox