Thara Gopinath <thara@xxxxxx> writes: > OMAP3430 uses the 65nm version of the smartreflex IP where as > OMAP3630 and OMAP4430 uses the 45nm updated IP. > > This patch adds support for the updated smartreflex IP used > in OMAP3630 and OMAP4 in the smartreflex driver. > > Major changes between the two versions of IP involve: > 1. Change in offset position for ERRCONFIG and SENERROR registers > 2. Change in bit positions for VP bound interrupt enable and status > in ERRCONFIG register. > 3. Change in bit positions and width of SENNENABLE and SENPENABLE > bits in SRCONFIG registers. > 4. Introduction of separate irq registers for MCU bound interrupts. > 5. Removal of clockactivity bits in ERRCONFIG and introduction of > idlemode and wakeupenable bits in ERRCONFIG. > > Signed-off-by: Thara Gopinath <thara@xxxxxx> > --- > arch/arm/mach-omap2/smartreflex.c | 218 ++++++++++++++++++++++++++++--------- > arch/arm/mach-omap2/smartreflex.h | 51 +++++++-- > 2 files changed, 208 insertions(+), 61 deletions(-) > > diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c > index 7aa84ab..2b1c529 100644 > --- a/arch/arm/mach-omap2/smartreflex.c > +++ b/arch/arm/mach-omap2/smartreflex.c > @@ -58,6 +58,18 @@ static struct omap_smartreflex_class_data *sr_class; > > #define SR_REGADDR(offs) (sr->srbase_addr + offset) > > +static inline int sr_type(void) > +{ > + if (cpu_is_omap3630()) what about OMAP4? > + return SR_TYPE_V2; > + else if (cpu_is_omap343x()) > + return SR_TYPE_V1; > + else { > + pr_err("Trying to enable SR for Chip not support SR! \n"); > + return 0; > + } > +} Instead of calling a function to check the type each time. How about adding a 'type' field to sr_info, setting the type once at init and checking the flag at runtime. > static inline void sr_write_reg(struct omap_sr *sr, unsigned offset, u32 value) > { > __raw_writel(value, SR_REGADDR(offset)); > @@ -67,9 +79,11 @@ static inline void sr_modify_reg(struct omap_sr *sr, unsigned offset, u32 mask, > u32 value) > { > u32 reg_val; > + u32 errconfig_offs, errconfig_mask; > > reg_val = __raw_readl(SR_REGADDR(offset)); > reg_val &= ~mask; > + > /* > * Smartreflex error config register is special as it contains > * certain status bits which if written a 1 into means a clear > @@ -78,8 +92,16 @@ static inline void sr_modify_reg(struct omap_sr *sr, unsigned offset, u32 mask, > * value. Now if there is an actual reguest to write to these bits > * they will be set in the nex step. > */ > - if (offset == ERRCONFIG) > - reg_val &= ~ERRCONFIG_STATUS_MASK; > + if (sr_type() == SR_TYPE_V1) { > + errconfig_offs = ERRCONFIG_V1; > + errconfig_mask = ERRCONFIG_STATUS_V1_MASK; > + } else if (sr_type() == SR_TYPE_V2) { > + errconfig_offs = ERRCONFIG_V2; > + errconfig_mask = ERRCONFIG_VPBOUNDINTST_V2; > + } > + > + if (offset == errconfig_offs) > + reg_val &= ~errconfig_mask; > > reg_val |= value; > __raw_writel(reg_val, SR_REGADDR(offset)); > @@ -135,13 +157,21 @@ static void sr_clk_disable(struct omap_sr *sr) > static irqreturn_t sr_omap_isr(int irq, void *data) > { > struct omap_sr *sr_info = (struct omap_sr *)data; > - u32 status; > + u32 status = 0; > > - /* Read the status bits */ > - status = sr_read_reg(sr_info, ERRCONFIG); > + if (sr_type() == SR_TYPE_V1) { > + /* Read the status bits */ > + status = sr_read_reg(sr_info, ERRCONFIG_V1); > > - /* Clear them by writing back */ > - sr_write_reg(sr_info, ERRCONFIG, status); > + /* Clear them by writing back */ > + sr_write_reg(sr_info, ERRCONFIG_V1, status); > + } else if (sr_type() == SR_TYPE_V2) { > + /* Read the status bits */ > + sr_read_reg(sr_info, IRQSTATUS); > + > + /* Clear them by writing back */ > + sr_write_reg(sr_info, IRQSTATUS, status); > + } > > /* Call the class driver notify function if registered*/ > if (sr_class->class_type == SR_CLASS2 && sr_class->notify) > @@ -208,6 +238,7 @@ static void sr_configure(struct omap_sr *sr) > { > u32 sr_config; > u32 senp_en , senn_en; > + u8 senp_shift, senn_shift; > struct omap_smartreflex_data *pdata = sr->pdev->dev.platform_data; > > /* Common settings for SR Class3 and SR Class2 */ > @@ -218,8 +249,16 @@ static void sr_configure(struct omap_sr *sr) > senn_en = pdata->senn_mod; > > sr_config = (sr->clk_length << SRCONFIG_SRCLKLENGTH_SHIFT) | > - SRCONFIG_SENENABLE | (senn_en << SRCONFIG_SENNENABLE_SHIFT) | > - (senp_en << SRCONFIG_SENPENABLE_SHIFT) | SRCONFIG_DELAYCTRL; > + SRCONFIG_SENENABLE; > + if (sr_type() == SR_TYPE_V1) { > + sr_config |= SRCONFIG_DELAYCTRL; > + senn_shift = SRCONFIG_SENNENABLE_V1_SHIFT; > + senp_shift = SRCONFIG_SENPENABLE_V1_SHIFT; > + } else if (sr_type() == SR_TYPE_V2) { > + senn_shift = SRCONFIG_SENNENABLE_V2_SHIFT; > + senp_shift = SRCONFIG_SENPENABLE_V2_SHIFT; > + } > + sr_config |= ((senn_en << senn_shift) | (senp_en << senp_shift)); > sr_write_reg(sr, SRCONFIG, sr_config); > > if ((sr_class->class_type == SR_CLASS3) || (sr_class->class_type == > @@ -230,20 +269,30 @@ static void sr_configure(struct omap_sr *sr) > * SR CLASS 2 can choose between ERROR module and MINMAXAVG > * module. > */ > - u32 sr_errconfig; > + u32 sr_errconfig, errconfig_offs; > + u32 vpboundint_en, vpboundint_st; > + > + if (sr_type() == SR_TYPE_V1) { > + errconfig_offs = ERRCONFIG_V1; > + vpboundint_en = ERRCONFIG_VPBOUNDINTEN_V1; > + vpboundint_st = ERRCONFIG_VPBOUNDINTST_V1; > + } else if (sr_type() == SR_TYPE_V2) { > + errconfig_offs = ERRCONFIG_V2; > + vpboundint_en = ERRCONFIG_VPBOUNDINTEN_V2; > + vpboundint_st = ERRCONFIG_VPBOUNDINTST_V2; > + } > > sr_modify_reg(sr, SRCONFIG, SRCONFIG_ERRGEN_EN, > SRCONFIG_ERRGEN_EN); > sr_errconfig = (sr->err_weight << ERRCONFIG_ERRWEIGHT_SHIFT) | > (sr->err_maxlimit << ERRCONFIG_ERRMAXLIMIT_SHIFT) | > (sr->err_minlimit << ERRCONFIG_ERRMiNLIMIT_SHIFT); > - sr_modify_reg(sr, ERRCONFIG, (SR_ERRWEIGHT_MASK | > + sr_modify_reg(sr, errconfig_offs, (SR_ERRWEIGHT_MASK | > SR_ERRMAXLIMIT_MASK | SR_ERRMINLIMIT_MASK), > sr_errconfig); > /* Enabling the interrupts if the ERROR module is used */ > - sr_modify_reg(sr, ERRCONFIG, > - (ERRCONFIG_VPBOUNDINTEN), > - (ERRCONFIG_VPBOUNDINTEN | ERRCONFIG_VPBOUNDINTST)); > + sr_modify_reg(sr, errconfig_offs, > + vpboundint_en, (vpboundint_en | vpboundint_st)); > } else if ((sr_class->class_type == SR_CLASS2) && > (sr_class->mod_use == SR_USE_ERROR_MOD)) { > /* > @@ -263,12 +312,27 @@ static void sr_configure(struct omap_sr *sr) > * Enabling the interrupts if MINMAXAVG module is used. > * TODO: check if all the interrupts are mandatory > */ > - sr_modify_reg(sr, ERRCONFIG, > - (ERRCONFIG_MCUACCUMINTEN | ERRCONFIG_MCUVALIDINTEN | > - ERRCONFIG_MCUBOUNDINTEN), > - (ERRCONFIG_MCUACCUMINTEN | ERRCONFIG_MCUACCUMINTST | > - ERRCONFIG_MCUVALIDINTEN | ERRCONFIG_MCUVALIDINTST | > - ERRCONFIG_MCUBOUNDINTEN | ERRCONFIG_MCUBOUNDINTST)); > + if (sr_type() == SR_TYPE_V1) { > + sr_modify_reg(sr, ERRCONFIG_V1, > + (ERRCONFIG_MCUACCUMINTEN | > + ERRCONFIG_MCUVALIDINTEN | > + ERRCONFIG_MCUBOUNDINTEN), > + (ERRCONFIG_MCUACCUMINTEN | > + ERRCONFIG_MCUACCUMINTST | > + ERRCONFIG_MCUVALIDINTEN | > + ERRCONFIG_MCUVALIDINTST | > + ERRCONFIG_MCUBOUNDINTEN | > + ERRCONFIG_MCUBOUNDINTST)); > + } else if (sr_type() == SR_TYPE_V2) { > + sr_write_reg(sr, IRQSTATUS, > + IRQSTATUS_MCUACCUMINT | IRQSTATUS_MCVALIDINT | > + IRQSTATUS_MCBOUNDSINT | > + IRQSTATUS_MCUDISABLEACKINT); > + sr_write_reg(sr, IRQENABLE_SET, > + IRQENABLE_MCUACCUMINT | IRQENABLE_MCUVALIDINT | > + IRQENABLE_MCUBOUNDSINT | > + IRQENABLE_MCUDISABLEACKINT); > + } > } > } > > @@ -318,6 +382,81 @@ static void sr_stop_vddautocomap(int srid) > > } > > +static void sr_v1_disable(struct omap_sr *sr) > +{ > + int timeout = 0; > + > + /* Enable MCUDisableAcknowledge interrupt */ > + sr_modify_reg(sr, ERRCONFIG_V1, > + ERRCONFIG_MCUDISACKINTEN, ERRCONFIG_MCUDISACKINTEN); > + > + /* SRCONFIG - disable SR */ > + sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, 0x0); > + > + /* Disable all other SR interrupts and clear the status */ > + sr_modify_reg(sr, ERRCONFIG_V1, > + (ERRCONFIG_MCUACCUMINTEN | ERRCONFIG_MCUVALIDINTEN | > + ERRCONFIG_MCUBOUNDINTEN | ERRCONFIG_VPBOUNDINTEN_V1), > + (ERRCONFIG_MCUACCUMINTST | ERRCONFIG_MCUVALIDINTST | > + ERRCONFIG_MCUBOUNDINTST | > + ERRCONFIG_VPBOUNDINTST_V1)); > + > + /* Wait for SR to be disabled. > + * wait until ERRCONFIG.MCUDISACKINTST = 1. Typical latency is 1us. > + */ > + while ((timeout < SR_DISABLE_TIMEOUT) && > + (!(sr_read_reg(sr, ERRCONFIG_V1) & > + ERRCONFIG_MCUDISACKINTST))) { > + udelay(1); > + timeout++; > + } > + > + if (timeout == SR_DISABLE_TIMEOUT) > + pr_warning("SR%d disable timedout\n", sr->srid); > + > + /* Disable MCUDisableAcknowledge interrupt & clear pending interrupt */ > + sr_modify_reg(sr, ERRCONFIG_V1, ERRCONFIG_MCUDISACKINTEN, > + ERRCONFIG_MCUDISACKINTST); > +} > + > +static void sr_v2_disable(struct omap_sr *sr) > +{ > + int timeout = 0; > + > + /* Enable MCUDisableAcknowledge interrupt */ > + sr_write_reg(sr, IRQENABLE_SET, IRQENABLE_MCUDISABLEACKINT); > + > + /* SRCONFIG - disable SR */ > + sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, 0x0); > + > + /* Disable all other SR interrupts and clear the status */ > + sr_modify_reg(sr, ERRCONFIG_V2, ERRCONFIG_VPBOUNDINTEN_V2, > + ERRCONFIG_VPBOUNDINTST_V2); > + sr_write_reg(sr, IRQENABLE_CLR, (IRQENABLE_MCUACCUMINT | > + IRQENABLE_MCUVALIDINT | > + IRQENABLE_MCUBOUNDSINT)); > + sr_write_reg(sr, IRQSTATUS, (IRQSTATUS_MCUACCUMINT | > + IRQSTATUS_MCVALIDINT | > + IRQSTATUS_MCBOUNDSINT)); > + > + /* Wait for SR to be disabled. > + * wait until IRQSTATUS.MCUDISACKINTST = 1. Typical latency is 1us. > + */ multi-line comment style > + while ((timeout < SR_DISABLE_TIMEOUT) && > + (!(sr_read_reg(sr, IRQSTATUS) & > + IRQSTATUS_MCUDISABLEACKINT))) { > + udelay(1); > + timeout++; > + } use omap_test_timeout() > + if (timeout == SR_DISABLE_TIMEOUT) > + pr_warning("SR%d disable timedout\n", sr->srid); > + > + /* Disable MCUDisableAcknowledge interrupt & clear pending interrupt */ > + sr_write_reg(sr, IRQENABLE_CLR, IRQENABLE_MCUDISABLEACKINT); > + sr_write_reg(sr, IRQSTATUS, IRQSTATUS_MCUDISABLEACKINT); > +} > + > /* Public Functions */ > > /** > @@ -373,6 +512,7 @@ int sr_enable(int srid, u32 target_opp_no) > sr_configure(sr); > > nvalue_reciprocal = pdata->sr_nvalue[target_opp_no - 1]; > + stray whitespace change > if (nvalue_reciprocal == 0) { > pr_notice("OPP%d doesn't support SmartReflex\n", > target_opp_no); > @@ -395,44 +535,18 @@ int sr_enable(int srid, u32 target_opp_no) > void sr_disable(int srid) > { > struct omap_sr *sr = _sr_lookup(srid); > - int timeout = 0; > > /* Check if SR is already disabled. If yes do nothing */ > if (!(sr_read_reg(sr, SRCONFIG) & SRCONFIG_SRENABLE)) > return; > > - /* Enable MCUDisableAcknowledge interrupt */ > - sr_modify_reg(sr, ERRCONFIG, > - ERRCONFIG_MCUDISACKINTEN, ERRCONFIG_MCUDISACKINTEN); > + if (sr_type() == SR_TYPE_V1) > + sr_v1_disable(sr); > > - /* SRCONFIG - disable SR */ > - sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, 0x0); > - > - /* Disable all other SR interrupts and clear the status */ > - sr_modify_reg(sr, ERRCONFIG, > - (ERRCONFIG_MCUACCUMINTEN | ERRCONFIG_MCUVALIDINTEN | > - ERRCONFIG_MCUBOUNDINTEN | ERRCONFIG_VPBOUNDINTEN), > - (ERRCONFIG_MCUACCUMINTST | ERRCONFIG_MCUVALIDINTST | > - ERRCONFIG_MCUBOUNDINTST | ERRCONFIG_VPBOUNDINTST)); > - > - /* Wait for SR to be disabled. > - * wait until ERRCONFIG.MCUDISACKINTST = 1. Typical latency is 1us. > - */ > - while ((timeout < SR_DISABLE_TIMEOUT) && > - (!(sr_read_reg(sr, ERRCONFIG) & ERRCONFIG_MCUDISACKINTST))) { > - > - udelay(1); > - timeout++; > - } > - > - if (timeout == SR_DISABLE_TIMEOUT) > - pr_warning("SR%d disable timedout\n", srid); > - > - /* Disable MCUDisableAcknowledge interrupt & clear pending interrupt > - * Also enable VPBOUND interrrupt > - */ > - sr_modify_reg(sr, ERRCONFIG, ERRCONFIG_MCUDISACKINTEN, > - ERRCONFIG_MCUDISACKINTST); > + else if (sr_type() == SR_TYPE_V2) > + sr_v2_disable(sr); > + else > + return; Rather than the if-else, how about adding a ->disable hook to sr_info set at init time and called here. Kevin -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html