From: "Gulati, Shweta" <shweta.gulati@ti.com>
To: "Turquette, Mike" <mturquette@ti.com>
Cc: linux-omap@vger.kernel.org
Subject: Re: [PATCH 4/4] OMAP: Voltage: Adaptive Body-Bias handlers
Date: Fri, 4 Mar 2011 10:23:14 +0530 [thread overview]
Message-ID: <AANLkTikR3wpaffhpm=exZS27G1i9kGP8N=scVnFF1UZq@mail.gmail.com> (raw)
In-Reply-To: <AANLkTimY1Yx4F37xY0b8OxaK0n=yR7s2edHWQQco=uRi@mail.gmail.com>
Hi,
On Tue, Mar 1, 2011 at 11:00 PM, Turquette, Mike <mturquette@ti.com> wrote:
> On Mon, Feb 28, 2011 at 3:35 AM, Gulati, Shweta <shweta.gulati@ti.com> wrote:
>> Hi,
>>
>> On Tue, Feb 22, 2011 at 1:17 AM, Turquette, Mike <mturquette@ti.com> wrote:
>>> On Mon, Feb 21, 2011 at 4:31 AM, Gulati, Shweta <shweta.gulati@ti.com> wrote:
>>>> Hi,
>>>>
>>>> On Fri, Feb 18, 2011 at 2:50 PM, Mike Turquette <mturquette@ti.com> wrote:
>>>>> Introduce voltage transition notification handlers for Adaptive Body-Bias
>>>>> LDOs. There is an ABB LDO for VDD_MPU on OMAP3630 and an ABB_LDO on VDD_MPU
>>>>> and VDD_IVA on OMAP4430.
>>>>>
>>>>> All of these LDOs are handled similary. Initial configuration is to enable
>>>>> the possibility of going into Forward Body-Bias (which boosts voltage at
>>>>> high OPPs). This feature was designed for weak silicon, and eFuse values
>>>>> exist to control whether or not this feature should be turned on. However
>>>>> recommendations from hardware folks always say to leave it on regardless of
>>>>> eFuse values, so we don't bother checking them. For all other OPPs the LDO
>>>>> is in bypass and will follow the voltage of it's corresponding VDD_xxx.
>>>>> Reverse Body-Bias exists but we never use this in practice (for saving power
>>>>> on strongly characterised silicon).
>>>> Would RBB be never enabled in future for any of the OPPs or any platforms
>>>> that way SLOW_OPP should also be added in OPP types
>>>
>>> Will do this in next version. RBB is a possibility.
>>>
>>>>> Upon a DVFS transition the notifiers handle the sequencing of voltage
>>>>> scaling and ABB LDO transitions. When moving to a higher OPP that needs
>>>>> FBB, raise voltage first and then enable FBB. When moving down to an OPP
>>>>> that bypasses ABB, first bypass the LDO then lower voltage.
>>>>>
>>>>> Signed-off-by: Mike Turquette <mturquette@ti.com>
>>>>> ---
>>>>> arch/arm/mach-omap2/voltage.c | 379 ++++++++++++++++++++++++++++-
>>>>> arch/arm/plat-omap/include/plat/voltage.h | 6 +-
>>>>> 2 files changed, 370 insertions(+), 15 deletions(-)
>>>>>
>>>>> diff --git a/arch/arm/mach-omap2/voltage.c b/arch/arm/mach-omap2/voltage.c
>>>>> index 6ede092..644a45f 100644
>>>>> --- a/arch/arm/mach-omap2/voltage.c
>>>>> +++ b/arch/arm/mach-omap2/voltage.c
>>>>> @@ -43,6 +43,16 @@
>>>>> #define FAST_OPP 0x1
>>>>> #define NOMINAL_OPP 0x0
>>>>>
>>>>> +/* prototypes used by ABB function pointers */
>>>>> +static int omap_abb_notify_voltage(struct notifier_block *nb,
>>>>> + unsigned long val, void *data);
>>>>> +
>>>>> +static int omap3_abb_configure(struct omap_abb_info *abb);
>>>>> +static int omap3_abb_set_opp(struct omap_abb_info *abb, int opp_type);
>>>>> +
>>>>> +static int omap4_abb_configure(struct omap_abb_info *abb);
>>>>> +static int omap4_abb_set_opp(struct omap_abb_info *abb, int opp_type);
>>>>> +
>>>>> static struct omap_vdd_info *vdd_info;
>>>>> /*
>>>>> * Number of scalable voltage domains.
>>>>> @@ -70,9 +80,11 @@ static struct omap_vdd_info omap3_vdd_info[] = {
>>>>> = OMAP3_PRM_IRQSTATUS_MPU_OFFSET,
>>>>> .done_st_shift = OMAP3630_ABB_LDO_TRANXDONE_ST_SHIFT,
>>>>> .done_st_mask = OMAP3630_ABB_LDO_TRANXDONE_ST_MASK,
>>>>> - .configure = NULL,
>>>>> - .nb_handler = NULL,
>>>>> - .set_opp = NULL,
>>>>> + .nb = {
>>>>> + .notifier_call = omap_abb_notify_voltage,
>>>>> + },
>>>>> + .configure = omap3_abb_configure,
>>>>> + .set_opp = omap3_abb_set_opp,
>>>>> },
>>>>> },
>>>>> {
>>>>> @@ -113,9 +125,11 @@ static struct omap_vdd_info omap4_vdd_info[] = {
>>>>> = OMAP4_PRM_IRQSTATUS_MPU_2_OFFSET,
>>>>> .done_st_shift = OMAP4430_ABB_MPU_DONE_ST_SHIFT,
>>>>> .done_st_mask = OMAP4430_ABB_MPU_DONE_ST_MASK,
>>>>> - .configure = NULL,
>>>>> - .nb_handler = NULL,
>>>>> - .set_opp = NULL,
>>>>> + .nb = {
>>>>> + .notifier_call = omap_abb_notify_voltage,
>>>>> + },
>>>>> + .configure = omap4_abb_configure,
>>>>> + .set_opp = omap4_abb_set_opp,
>>>>> },
>>>>> },
>>>>> {
>>>>> @@ -137,9 +151,11 @@ static struct omap_vdd_info omap4_vdd_info[] = {
>>>>> = OMAP4_PRM_IRQSTATUS_MPU_OFFSET,
>>>>> .done_st_shift = OMAP4430_ABB_IVA_DONE_ST_SHIFT,
>>>>> .done_st_mask = OMAP4430_ABB_IVA_DONE_ST_MASK,
>>>>> - .configure = NULL,
>>>>> - .nb_handler = NULL,
>>>>> - .set_opp = NULL,
>>>>> + .nb = {
>>>>> + .notifier_call = omap_abb_notify_voltage,
>>>>> + },
>>>>> + .configure = omap4_abb_configure,
>>>>> + .set_opp = omap4_abb_set_opp,
>>>>> },
>>>>> },
>>>>> {
>>>>> @@ -194,7 +210,7 @@ static struct omap_volt_data omap36xx_vddmpu_volt_data[] = {
>>>>> NOMINAL_OPP),
>>>>> VOLT_DATA_DEFINE(OMAP3630_VDD_MPU_OPP100_UV,
>>>>> OMAP3630_CONTROL_FUSE_OPP100_VDD1, 0xf9, 0x16,
>>>>> - NOMINAL_OPP),
>>>>> + FAST_OPP),
>>>>> VOLT_DATA_DEFINE(OMAP3630_VDD_MPU_OPP120_UV,
>>>>> OMAP3630_CONTROL_FUSE_OPP120_VDD1, 0xfa, 0x23,
>>>>> NOMINAL_OPP),
>>>>> @@ -493,6 +509,74 @@ static void __init vdd_debugfs_init(struct omap_vdd_info *vdd)
>>>>> &nom_volt_debug_fops);
>>>>> }
>>>>>
>> What about OMAP4, there volt_data should also be updated.
>> One think more, for IVA ABB should not be enabled by default rather
>> there should be Kconfig
>> option to Enable/Disable it.
Comments on the point of adding Kconfig options for OMAP4 IVA ABB,
which should not be enabled by default.
> You caught a bug, but not the one you think ;-)
Yes OMAP3630_VDD_MPU_OPP1Ghz_VDD1 should be FAST OPP
> The NOMINAL_OPP/FAST_OPP definitions are done in patch 3 of this
> series (including OMAP4). However to test that this was done
> correctly on a scope I set OPP120 to use FAST_OPP since the higher
> OPPs were disabled. This line is a bug and I'll remove in v2.
>
>>>>> +/* voltage transition notification handlers */
>>>>> +
>>>>> +/**
>>>>> + * omap_abb_notify_voltage - voltage change notifier handler for ABB
>>>>> + * @nb : notifier block
>>>>> + * @val : VOLTSCALE_PRECHANGE or VOLTSCALE_POSTCHANGE
>>>>> + * @data : struct omap_volt_change_info for a given voltage domain
>>>>> + *
>>>>> + * Sets ABB LDO to either bypass or Forward Body-Bias whenever a voltage
>>>>> + * change notification is generated. Voltages marked as FAST will result in
>>>>> + * FBB operation of ABB LDO and voltages marked as NOMINAL will bypass the
>>>>> + * LDO. Does not handle Reverse Body-Bias since there is not benefit for it
>>>>> + * on any existing silicon. Returns 0 upon success, negative error code
>>>>> + * otherwise.
>>>>> + */
>>>>> +static int omap_abb_notify_voltage(struct notifier_block *nb,
>>>>> + unsigned long val, void *data)
>>>>> +{
>>>>> + struct omap_volt_change_info *v_info;
>>>>> + struct omap_vdd_info *vdd;
>>>>> + struct omap_volt_data *curr_volt_data, *target_volt_data;
>>>>> + int ret = 0;
>>>>> +
>>>>> + if (!nb || IS_ERR(nb) || !data || IS_ERR(data)) {
>>>>> + pr_warning("%s: invalid data specified\n", __func__);
>>>>> + ret = -EINVAL;
>>>>> + goto out;
>>>>> + }
>>>>> +
>>>>> + v_info = (struct omap_volt_change_info *)data;
>>>>> + vdd = v_info->vdd;
>>>>> +
>>>>> + /* get the voltdata structures for the current & target voltage */
>>>>> + target_volt_data = omap_voltage_get_voltdata(&vdd->voltdm,
>>>>> + v_info->target_volt);
>>>>> + curr_volt_data = omap_voltage_get_voltdata(&vdd->voltdm,
>>>>> + v_info->curr_volt);
>>>>> +
>>>>> + /* nothing to do here */
>>>>> + if (target_volt_data->abb_opp == curr_volt_data->abb_opp)
>>>>> + goto out;
>>>>> +
>>>>> + /*
>>>>> + * When the VDD drops from a voltage requiring the ABB LDO to be in
>>>>> + * FBB mode to a voltage requiring bypass mode, we must bypass the LDO
>>>>> + * before the voltage transition.
>>>>> + */
>>>>> + if (val == VOLTSCALE_PRECHANGE &&
>>>>> + target_volt_data->abb_opp == NOMINAL_OPP) {
>>>>> + ret = vdd->abb.set_opp(&vdd->abb, NOMINAL_OPP);
>> what I meant is, at this place you can write into OPP_SEL bits of
>> SETUP register rather than passing argument of opp_type.
>
> This defeats the point of abstraction! In my previous implementation
> of this for Android I did directly write into the registers here.
> However I only supported OMAP4 and when it came time to add OMAP3 the
> code had yet another ugly cpu_is_omapxxxx() check.
>
> The goal is to completely abstract away the version-specific bits from
> this generic notification handler which we rely on the function
> pointer to do for us. I'll group the register addresses/offsets
> together in the ABB struct, but I won't be changing the set_opp
> function signature in v2.
>
>>> +
>>>>> + /*
>>>>> + * When moving from a voltage requiring the ABB LDO to be bypassed to
>>>>> + * a voltage requiring FBB mode, we must change the LDO operation
>>>>> + * after the voltage transition.
>>>>> + */
>>>>> + } else if (val == VOLTSCALE_POSTCHANGE &&
>>>>> + target_volt_data->abb_opp == FAST_OPP) {
>>>>> + ret = vdd->abb.set_opp(&vdd->abb, FAST_OPP);
>>>>> +
>> Same
>
> Same
>
>>>>> + /* invalid combination, bail out */
>>>>> + } else
>>>>> + ret = -EINVAL;
>>>>> +
>>>>> +out:
>>>>> + return ret;
>>>>> +}
>>>>> +
>>>>> /* Voltage scale and accessory APIs */
>>>>> static int _pre_volt_scale(struct omap_vdd_info *vdd,
>>>>> unsigned long target_volt, u8 *target_vsel, u8 *current_vsel)
>>>>> @@ -717,6 +801,142 @@ static int vp_forceupdate_scale_voltage(struct omap_vdd_info *vdd,
>>>>> return 0;
>>>>> }
>>>>>
>>>>> +/**
>>>>> + * omap3_abb_set_opp - program ABB LDO upon a voltage transition
>>>>> + *
>>>>> + * @abb : ABB instance being programmed
>>>>> + * @opp_type : flag for NOMINAL or FAST OPP
>>>>> + */
>>>>> +static int omap3_abb_set_opp(struct omap_abb_info *abb, int opp_type)
>>>>> +{
>>>>> + int ret = 0;
>>>>> + int timeout;
>>>>> +
>>>>> + /* program for NOMINAL OPP or FAST OPP */
>>>>> + omap2_prm_rmw_mod_reg_bits(OMAP3630_OPP_SEL_MASK,
>>>>> + (opp_type << OMAP3630_OPP_SEL_SHIFT),
>>>>> + OMAP3430_GR_MOD, abb->setup_offs);
>>>> Rather than passing a parameter 'opp_type' u can set OPP_SEL bit in
>>>> SETUP Register in API
>>>
>>> I'm not sure I follow. The opp_type corresponds to the voltage we're
>>> transitioning to, so that data must be passed in to this generic
>>> set_opp function.
>>>
>>>> omap_abb_notify_voltage where if-else are used to check whether ABB
>>>> needs to transition or not.
>>>
>>> The notifier handles this... it will not execute call set_opp function
>>> if there is no need to change ABB registers.
>> Answered above.
>
> Again, I won't be changing this in v2. I'll abstract the register
> offsets away so that OMAP3 and OMAP4 can use the same notification
> handler.
>
>>>>> +
>>>>> + /* clear ABB ldo interrupt status */
>>>>> + omap2_prm_clear_mod_reg_bits(abb->done_st_mask, OCP_MOD,
>>>>> + abb->irqstatus_mpu_offs);
>>>>> +
>>>>> + /* enable ABB LDO OPP change */
>>>>> + omap2_prm_set_mod_reg_bits(OMAP3630_OPP_CHANGE_MASK, OMAP3430_GR_MOD,
>>>>> + abb->setup_offs);
>>>>> +
>>>>> + timeout = 0;
>>>>> +
>>>>> + /* wait until OPP change completes */
>>>>> + while ((timeout < ABB_TRANXDONE_TIMEOUT) &&
>>>>> + (!(omap2_prm_read_mod_reg(OCP_MOD,
>>>>> + abb->irqstatus_mpu_offs) &
>>>>> + abb->done_st_mask))) {
>>>>> + udelay(1);
>>>>> + timeout++;
>>>>> + }
>>>>> +
>>>>> + if (timeout == ABB_TRANXDONE_TIMEOUT)
>>>>> + pr_warning("%s: TRANXDONE timed out waiting for OPP change\n",
>>>>> + __func__);
>>>>> +
>>>>> + timeout = 0;
>>>>> +
>>>>> + /* Clear all pending TRANXDONE interrupts/status */
>>>>> + while (timeout < ABB_TRANXDONE_TIMEOUT) {
>>>>> + omap2_prm_write_mod_reg((1 << abb->done_st_shift), OCP_MOD,
>>>>> + abb->irqstatus_mpu_offs);
>>>>> +
>>>>> + if (!(omap2_prm_read_mod_reg(OCP_MOD, abb->irqstatus_mpu_offs)
>>>>> + & abb->done_st_mask))
>>>>> + break;
>>>>> +
>>>>> + udelay(1);
>>>>> + timeout++;
>>>>> + }
>>>>> +
>>>>> + if (timeout == ABB_TRANXDONE_TIMEOUT) {
>>>>> + pr_warning("%s: TRANXDONE timed out trying to clear status\n",
>>>>> + __func__);
>>>>> + ret = -EBUSY;
>>>>> + }
>>>>> +
>>>>> + return ret;
>>>>> +}
>>>>> +
>>>>> +/**
>>>>> + * omap4_abb_set_opp - program ABB LDO upon a voltage transition
>>>>> + *
>>>>> + * @abb : ABB instance being programmed
>>>>> + * @opp_type : flag for NOMINAL or FAST OPP
>>>>> + */
>>>>> +static int omap4_abb_set_opp(struct omap_abb_info *abb, int opp_type)
>>>>> +{
>>>>> + int ret = 0;
>>>>> + int timeout;
>>>>> +
>>>>> + /* program for NOMINAL OPP or FAST OPP */
>>>>> + omap4_prminst_rmw_inst_reg_bits(OMAP4430_OPP_SEL_MASK,
>>>>> + (opp_type << OMAP4430_OPP_SEL_SHIFT),
>>>>> + OMAP4430_PRM_PARTITION, OMAP4430_PRM_DEVICE_INST,
>>>>> + abb->ctrl_offs);
>>>>> +
>>>>> + /* clear ABB ldo interrupt status */
>>>>> + omap4_prminst_rmw_inst_reg_bits(abb->done_st_mask,
>>>>> + (0x0 << abb->done_st_shift), OMAP4430_PRM_PARTITION,
>>>>> + OMAP4430_PRM_DEVICE_INST, abb->ctrl_offs);
>>>>> +
>>>>> + /* enable ABB LDO OPP change */
>>>>> + omap4_prminst_rmw_inst_reg_bits(OMAP4430_OPP_CHANGE_MASK,
>>>>> + (0x1 << OMAP4430_OPP_CHANGE_SHIFT),
>>>>> + OMAP4430_PRM_PARTITION, OMAP4430_PRM_DEVICE_INST,
>>>>> + abb->ctrl_offs);
>>>>> +
>>>> A generic struct can be created which has Masks and shifts of all
>>>> register offsets like OMAP4430_OPP_CHANGE_MASK
>>>> and OMAP3630_ACTIVE_FBB_SEL_MASK whose objects for OMAP3 and OMAP4 can be used.
>>>
>>> True. I chose to have the struct differentiate between VDDs, not OMAP
>>> chips. Do others have an opinion on this? I guess it comes down to
>>> whether we should have OMAP-specific ABB set_opp functions, and that
>>> struct data should be per-VDD (like it is in my patch)... OR if we
>>> should have a generic ABB set_opp function only that works across all
>>> OMAPs and all data is in the struct whether it is VDD- or
>>> OMAP-specific. My problem with the latter solution is that it assumes
>>> the programming model will not change from OMAP to OMAP...
>>>
>>>>> + timeout = 0;
>>>>> +
>>>>> + /* wait until OPP change completes */
>>>>> + while ((timeout < ABB_TRANXDONE_TIMEOUT) &&
>>>>> + (!(omap4_prminst_read_inst_reg(OMAP4430_PRM_PARTITION,
>>>>> + OMAP4430_PRM_DEVICE_INST,
>>>>> + abb->irqstatus_mpu_offs)
>>>>> + & abb->done_st_mask))) {
>>>>> + udelay(1);
>>>>> + timeout++;
>>>>> + }
>>>>> +
>>>>> + if (timeout == ABB_TRANXDONE_TIMEOUT)
>>>>> + pr_warning("%s: TRANXDONE timed out waiting for OPP change\n",
>>>>> + __func__);
>>>>> +
>>>>> + timeout = 0;
>>>>> +
>>>>> + /* Clear all pending TRANXDONE interrupts/status */
>>>>> + while (timeout < ABB_TRANXDONE_TIMEOUT) {
>>>>> + omap4_prminst_write_inst_reg((1 << abb->done_st_shift),
>>>>> + OMAP4430_PRM_PARTITION,
>>>>> + OMAP4430_PRM_DEVICE_INST,
>>>>> + abb->irqstatus_mpu_offs);
>>>>> +
>>>>> + if (!(omap4_prminst_read_inst_reg(OMAP4430_PRM_PARTITION,
>>>>> + OMAP4430_PRM_DEVICE_INST,
>>>>> + abb->irqstatus_mpu_offs)
>>>>> + & abb->done_st_mask)) {
>>>>> + break;
>>>>> +
>>>>> + udelay(1);
>>>>> + timeout++;
>>>>> + }
>>>>> + }
>>>>> +
>>>>> + if (timeout == ABB_TRANXDONE_TIMEOUT) {
>>>>> + pr_warning("%s: TRANXDONE timed out trying to clear status\n",
>>>>> + __func__);
>>>>> + ret = -EBUSY;
>>>>> + }
>>>>> +
>>>>> + return ret;
>>>>> +}
>>>>> +
>>>>> /* OMAP3 specific voltage init functions */
>>>>>
>>>>> /*
>>>>> @@ -789,6 +1009,64 @@ static void __init omap3_vc_init(struct omap_vdd_info *vdd)
>>>>> is_initialized = true;
>>>>> }
>>>>>
>>>>> +/**
>>>>> + * omap3_abb_configure - per-VDD configuration of ABB
>>>>> + *
>>>>> + * @abb : abb instance being initialized
>>>>> + */
>>>>> +static int omap3_abb_configure(struct omap_abb_info *abb)
>>>>> +{
>>>>> + int ret = 0;
>>>>> + u32 sr2_wt_cnt_val;
>>>>> + struct clk *sys_ck;
>>>>> + struct omap_vdd_info *vdd;
>>>>> +
>>>>> + if (!abb || IS_ERR(abb)) {
>>>>> + pr_warning("%s: invalid abb\n", __func__);
>>>>> + ret = -EINVAL;
>>>>> + goto out;
>>>>> + }
>>>>> +
>>>>> + sys_ck = clk_get(NULL, "sys_ck");
>>>>> + if (IS_ERR(sys_ck)) {
>>>>> + pr_warning("%s: unable to fetch SYS_CK\n", __func__);
>>>>> + ret = -ENODEV;
>>>>> + goto out;
>>>>> + }
>>>>> +
>>>>> + vdd = container_of(abb, struct omap_vdd_info, abb);
>>>>> +
>>>>> + /* LDO settling time */
>>>>> + sr2_wt_cnt_val = clk_get_rate(sys_ck);
>>>>> + sr2_wt_cnt_val = sr2_wt_cnt_val / 1000000 / 16;
>>>>> +
>>>>> + omap2_prm_rmw_mod_reg_bits(OMAP3630_SR2_WTCNT_VALUE_MASK,
>>>>> + (sr2_wt_cnt_val << OMAP3630_SR2_WTCNT_VALUE_SHIFT),
>>>>> + OMAP3430_GR_MOD, abb->setup_offs);
>>>>> +
>>>>> + /* allow FBB operation */
>>>>> + omap2_prm_set_mod_reg_bits(OMAP3630_ACTIVE_FBB_SEL_MASK,
>>>>> + OMAP3430_GR_MOD, abb->setup_offs);
>>>>> +
>>>>> + /* do not allow ACTIVE RBB operation */
>>>>> + omap2_prm_set_mod_reg_bits(OMAP3630_ACTIVE_RBB_SEL_MASK,
>>>>> + OMAP3430_GR_MOD, abb->setup_offs);
>>>>> +
>>>>> + /* do not allow SLEEP RBB operation */
>>>>> + omap2_prm_set_mod_reg_bits(OMAP3630_SLEEP_RBB_SEL_MASK,
>>>>> + OMAP3430_GR_MOD, abb->setup_offs);
>>>>> +
>>>>> + /* enable ABB LDO */
>>>>> + omap2_prm_set_mod_reg_bits(OMAP3630_SR2EN_MASK,
>>>>> + OMAP3430_GR_MOD, abb->ctrl_offs);
>>>> ABB should n't be enabled in this API rather it should be enabled only
>>>> when it goes to FBB/RBB mode
>>>
>>> I disagree. I've verified with hw team that this is perfectly safe as
>>> it leaves ABB ldo in bypass and will follow VDD_xxx voltage. No
>>> reason to complicate notifier code with some "if
>>> (!abb_already_enabled)" check.
>>>
>>>>> +
>>>>> + /* register the notifier handler */
>>>>> + omap_voltage_register_notifier(vdd, &abb->nb);
>>>>> +
>>>>> +out:
>>>>> + return ret;
>>>>> +}
>>>>> +
>>>>> /* Sets up all the VDD related info for OMAP3 */
>>>>> static int __init omap3_vdd_data_configure(struct omap_vdd_info *vdd)
>>>>> {
>>>>> @@ -824,6 +1102,9 @@ static int __init omap3_vdd_data_configure(struct omap_vdd_info *vdd)
>>>>> vdd->vc_reg.smps_volra_mask = OMAP3430_VOLRA0_MASK;
>>>>> vdd->vc_reg.voltsetup_shift = OMAP3430_SETUP_TIME1_SHIFT;
>>>>> vdd->vc_reg.voltsetup_mask = OMAP3430_SETUP_TIME1_MASK;
>>>>> +
>>>>> + /* configure ABB */
>>>>> + vdd->abb.configure(&vdd->abb);
>>>>> } else if (!strcmp(vdd->voltdm.name, "core")) {
>>>>> if (cpu_is_omap3630())
>>>>> vdd->volt_data = omap36xx_vddcore_volt_data;
>>>>> @@ -975,6 +1256,73 @@ static void __init omap4_vc_init(struct omap_vdd_info *vdd)
>>>>> is_initialized = true;
>>>>> }
>>>>>
>>>> To remove code repetition rather than having 2 APIs for abb_configure,
>>>> I believe 1 API which has generic register offsets struct objects for
>>>> all platforms
>>>> (OMAP3 and OMAP4 for now) can be used.
>>>> This would be scalable for OMAP5+ also.
>>>
>>> This is the same as what I've stated above for the ABB set_opp
>>> function. We can't be sure what the programming model will be for
>>> future OMAPs, so should we really do it as your suggest? It is
>>> possible that we retain the same set_opp function pointer, and only
>>> implemenet it once since it can be used by both OMAP3 and OMAP4 using
>>> more verbose struct data. OMAP5 might have a different programming
>>> model altogether, so we will need to retain the set_opp function
>>> pointer just to be safe. Thoughts on this?
>> I have checked OMAP5 ABB Transition Sequences, they are same in sequence
>> of setting/clearing registers bits, so I think a structure of
>> registers offsets and masks generic
>> across VDDs and OMAPs should be used and 1 API should be there to
>> remove code repetition
>
> OK, thanks for checking on the OMAP5 programming model. I'll add
> register bits to the abb struct and consolidate the notification
> handler into a single generic function (will keep "omap3" in the
> function name).
>
> Regards,
> Mike
>
>>>>
>>>>> +/**
>>>>> + * omap4_abb_configure - per-VDD configuration of ABB
>>>>> + *
>>>>> + * @abb : abb instance being initialized
>>>>> + */
>>>>> +static int omap4_abb_configure(struct omap_abb_info *abb)
>>>>> +{
>>>>> + int ret = 0;
>>>>> + u32 sr2_wt_cnt_val;
>>>>> + struct clk *sys_ck;
>>>>> + struct omap_vdd_info *vdd;
>>>>> +
>>>>> + if (!abb || IS_ERR(abb)) {
>>>>> + pr_warning("%s: invalid abb\n", __func__);
>>>>> + ret = -EINVAL;
>>>>> + goto out;
>>>>> + }
>>>>> +
>>>>> + sys_ck = clk_get(NULL, "sys_clkin_ck");
>>>>> + if (IS_ERR(sys_ck)) {
>>>>> + pr_warning("%s: unable to fetch SYS_CK", __func__);
>>>>> + ret = -ENODEV;
>>>>> + goto out;
>>>>> + }
>>>>> +
>>>>> + vdd = container_of(abb, struct omap_vdd_info, abb);
>>>>> +
>>>>> + /* LDO settling time */
>>>>> + sr2_wt_cnt_val = clk_get_rate(sys_ck);
>>>>> + sr2_wt_cnt_val = sr2_wt_cnt_val / 1000000 / 16;
>>>>> +
>>>>> + omap4_prminst_rmw_inst_reg_bits(OMAP4430_SR2_WTCNT_VALUE_MASK,
>>>>> + (sr2_wt_cnt_val << OMAP4430_SR2_WTCNT_VALUE_SHIFT),
>>>>> + OMAP4430_PRM_PARTITION, OMAP4430_PRM_DEVICE_INST,
>>>>> + abb->setup_offs);
>>>>> +
>>>>> + /* allow FBB operation */
>>>>> + omap4_prminst_rmw_inst_reg_bits(OMAP4430_ACTIVE_FBB_SEL_MASK,
>>>>> + (1 << OMAP4430_ACTIVE_FBB_SEL_SHIFT),
>>>>> + OMAP4430_PRM_PARTITION, OMAP4430_PRM_DEVICE_INST,
>>>>> + abb->setup_offs);
>>>>> +
>>>>> + /* do not allow ACTIVE RBB operation */
>>>>> + omap4_prminst_rmw_inst_reg_bits(OMAP4430_ACTIVE_RBB_SEL_MASK,
>>>>> + (0 << OMAP4430_ACTIVE_RBB_SEL_SHIFT),
>>>>> + OMAP4430_PRM_PARTITION, OMAP4430_PRM_DEVICE_INST,
>>>>> + abb->setup_offs);
>>>>> +
>>>>> + /* do not allow SLEEP RBB operation */
>>>>> + omap4_prminst_rmw_inst_reg_bits(OMAP4430_SLEEP_RBB_SEL_MASK,
>>>>> + (0 << OMAP4430_SLEEP_RBB_SEL_SHIFT),
>>>>> + OMAP4430_PRM_PARTITION, OMAP4430_PRM_DEVICE_INST,
>>>>> + abb->setup_offs);
>>>>> +
>>>>> + /* enable ABB LDO */
>>>>> + omap4_prminst_rmw_inst_reg_bits(OMAP4430_SR2EN_MASK,
>>>>> + (1 << OMAP4430_SR2EN_SHIFT),
>>>>> + OMAP4430_PRM_PARTITION, OMAP4430_PRM_DEVICE_INST,
>>>>> + abb->setup_offs);
>>>> Same as above.
>>>
>>> Same as my above comment ;-) This is safe and there is no reason to change it.
>>>
>>> Regards,
>>> Mike
>>>
>>>>> + /* register the notifier handler */
>>>>> + omap_voltage_register_notifier(vdd, &abb->nb);
>>>>> +
>>>>> +out:
>>>>> + return ret;
>>>>> +}
>>>>> +
>>>>> /* Sets up all the VDD related info for OMAP4 */
>>>>> static int __init omap4_vdd_data_configure(struct omap_vdd_info *vdd)
>>>>> {
>>>>> @@ -983,8 +1331,8 @@ static int __init omap4_vdd_data_configure(struct omap_vdd_info *vdd)
>>>>>
>>>>> if (!vdd->pmic_info) {
>>>>> pr_err("%s: PMIC info requried to configure vdd_%s not"
>>>>> - "populated.Hence cannot initialize vdd_%s\n",
>>>>> - __func__, vdd->voltdm.name, vdd->voltdm.name);
>>>>> + "populated.Hence cannot initialize vdd_%s\n",
>>>>> + __func__, vdd->voltdm.name, vdd->voltdm.name);
>>>>> return -EINVAL;
>>>>> }
>>>>>
>>>>> @@ -1005,6 +1353,9 @@ static int __init omap4_vdd_data_configure(struct omap_vdd_info *vdd)
>>>>> vdd->vc_reg.voltsetup_reg =
>>>>> OMAP4_PRM_VOLTSETUP_MPU_RET_SLEEP_OFFSET;
>>>>> vdd->prm_irqst_reg = OMAP4_PRM_IRQSTATUS_MPU_2_OFFSET;
>>>>> +
>>>>> + /* configure ABB */
>>>>> + vdd->abb.configure(&vdd->abb);
>>>>> } else if (!strcmp(vdd->voltdm.name, "core")) {
>>>>> vdd->volt_data = omap44xx_vdd_core_volt_data;
>>>>> vdd->vp_reg.tranxdone_status =
>>>>> @@ -1032,6 +1383,9 @@ static int __init omap4_vdd_data_configure(struct omap_vdd_info *vdd)
>>>>> vdd->vc_reg.voltsetup_reg =
>>>>> OMAP4_PRM_VOLTSETUP_IVA_RET_SLEEP_OFFSET;
>>>>> vdd->prm_irqst_reg = OMAP4_PRM_IRQSTATUS_MPU_OFFSET;
>>>>> +
>>>>> + /* configure ABB */
>>>>> + vdd->abb.configure(&vdd->abb);
>>>>> } else {
>>>>> pr_warning("%s: vdd_%s does not exisit in OMAP4\n",
>>>>> __func__, vdd->voltdm.name);
>>>>> @@ -1299,6 +1653,7 @@ int omap_voltage_scale_vdd(struct voltagedomain *voltdm,
>>>>>
>>>>> /* load notifier chain data */
>>>>> v_info.target_volt = target_volt;
>>>>> + v_info.curr_volt = vdd->curr_volt;
>>>>> v_info.vdd = vdd;
>>>>>
>>>>> srcu_notifier_call_chain(&vdd->volt_change_notify_chain,
>>>>> diff --git a/arch/arm/plat-omap/include/plat/voltage.h b/arch/arm/plat-omap/include/plat/voltage.h
>>>>> index af790bf..07997f7 100644
>>>>> --- a/arch/arm/plat-omap/include/plat/voltage.h
>>>>> +++ b/arch/arm/plat-omap/include/plat/voltage.h
>>>>> @@ -235,8 +235,8 @@ struct omap_vdd_dep_info {
>>>>> * @irqstatus_mpu_offs : PRM_IRQSTATUS_MPU* register offset
>>>>> * @done_st_shift : ABB_vdd_DONE_ST shift
>>>>> * @done_st_mask : ABB_vdd_DONE_ST bit mask
>>>>> + * @nb : voltage transition notifier block
>>>>> * @configure : boot-time configuration
>>>>> - * @nb_handler : voltage transition notification handler
>>>>> * @set_opp : transition function called from nb_handler
>>>>> */
>>>>> struct omap_abb_info {
>>>>> @@ -245,9 +245,8 @@ struct omap_abb_info {
>>>>> u8 irqstatus_mpu_offs;
>>>>> u8 done_st_shift;
>>>>> u32 done_st_mask;
>>>>> + struct notifier_block nb;
>>>>> int (*configure) (struct omap_abb_info *abb);
>>>>> - int (*nb_handler) (struct notifier_block *nb, unsigned long val,
>>>>> - void *data);
>>>>> int (*set_opp) (struct omap_abb_info *abb, int opp_type);
>>>>> };
>>>>>
>>>>> @@ -302,6 +301,7 @@ struct omap_vdd_info {
>>>>> */
>>>>> struct omap_volt_change_info {
>>>>> unsigned long target_volt;
>>>>> + unsigned long curr_volt;
>>>>> struct omap_vdd_info *vdd;
>>>>> };
>>>>>
>>>>> --
>>>>> 1.7.1
>>>>>
>>>>> --
>>>>> 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
>>>>>
>>>>
>>>>
>>>>
>>>> --
>>>> Thanks,
>>>> Regards,
>>>> Shweta
>>>>
>>>
>>
>>
>>
>> --
>> Thanks,
>> Regards,
>> Shweta
>>
>
--
Thanks,
Regards,
Shweta
--
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
next prev parent reply other threads:[~2011-03-04 4:53 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-02-18 9:20 [PATCH 1/4] OMAP: voltage: pre- and post-transition notifiers Mike Turquette
2011-02-18 9:20 ` [PATCH 2/4] OMAP3630: add missing ABB PRM register definitions Mike Turquette
2011-02-18 9:20 ` [PATCH 3/4] OMAP: Voltage: add ABB structures and data Mike Turquette
2011-03-01 22:05 ` Kevin Hilman
2011-02-18 9:20 ` [PATCH 4/4] OMAP: Voltage: Adaptive Body-Bias handlers Mike Turquette
2011-02-19 0:29 ` David Cohen
2011-02-21 10:31 ` Gulati, Shweta
2011-02-21 19:47 ` Turquette, Mike
2011-02-21 23:01 ` Cousson, Benoit
2011-02-28 9:35 ` Gulati, Shweta
2011-03-01 17:30 ` Turquette, Mike
2011-03-04 4:53 ` Gulati, Shweta [this message]
2011-03-01 22:06 ` [PATCH 1/4] OMAP: voltage: pre- and post-transition notifiers Kevin Hilman
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to='AANLkTikR3wpaffhpm=exZS27G1i9kGP8N=scVnFF1UZq@mail.gmail.com' \
--to=shweta.gulati@ti.com \
--cc=linux-omap@vger.kernel.org \
--cc=mturquette@ti.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).