I've been researching a bit onto UVolting our machines and I think I've drawn certain conclusions.
Since discovered the way to put some nominal voltajes and then let the overclock module to calculate the calibrated ones, I've done some tests and the tale is far different from the reality.
Trying with different values of vsel and calibrating them, the result was allways the same calibrated voltajes. Pushing a 20 vsel value resulted in a 20 sr_adjust_vsel value too (this is what makes me think that SBT wasn't running fine..), but the fact is that pushing values from 20 to 35 resulted in almost the same calibrated voltaje (values between 20 and 22).
Doing the samo with all frequencies, the results were the same; the calibrated values don't change with vsel.
Looking into the matter and doing some googling, I've found the following explanation about the different voltajes refered in /sys/power/sr_adjust_vsel:
Nominal Voltage - The maximum voltage needed for a worst possible device in the worst possible conditions. This is the voltage we choose as the starting point for the h/w loop to optimize for the first time calibration on system bootup.
Dynamic Nominal Voltage - Worst case voltage for a specific device in considering the system aging on the worst process device.
Calibrated Voltage - Best voltage for the current device at a given point of time.
This voltaje values applies to Smartreflex Class 1.5 that seems to be the class implemented for OMAP 3630. There are several Smartreflex Classes that determine the way and time how the voltajes are recalibrated.
Conclusion: No matter the voltaje you put into vsel, it will allow the adecuate calibrated voltaje, being this last the effective actual voltaje suppling your processor. Even setting a lower than calibrated vsel, mpu_opps and sr_adjust_vsel shows the same calibrated voltaje, higher than vsel, but according to definition, vsel is the highest archievable voltaje. In that situation, which is the real voltaje applied? This is the key...
On Tue, Mar 1, 2011 at 15:23, Gulati, Shweta <shweta.gulati <at> ti.com> wrote:
>
> Hi,
>
> On Sat, Feb 19, 2011 at 5:31 PM, Nishanth Menon <nm <at> ti.com> wrote:
> > Traditional SmartReflex AVS(Automatic Voltage Scaling) classes are:
> > * Class 0 - Product test calibration
> > Silicon is calibration at production floor and fused with voltages
> > for each OPP
> > * Class 1 - Boot time calibration
> > Silicon is calibrated once at boot time and voltages are stored for
> > the lifetime of operation.
> > * Class 2 - continuous s/w calibration
> > SR module notifies s/w for any change in the system which is desired
> > and the s/w makes runtime decisions in terms of setting the voltage,
> > this mechanism could be used in the system which does not have PMIC
> > capable of SR without using the voltage controller and voltage
> > processor blocks.
> > * Class 3 - continuous h/w calibration
> > SR module is switch on after reaching a voltage level and SR
> > continuously monitors the system and makes runtime adjustments without
> > s/w involvement.
> >
> > OMAP3430 has used SmartReflex AVS and with a a PMIC which understands the SR
> > protocol, Class 3 has been used. With OMAP3630 onwards, a new SmartReflex AVS
> > class of operation Class 1.5 was introduced.
> > * Class 1.5 - periodic s/w calibration
> > This uses the h/w calibration loop and at the end of calibration
> > stores the voltages to be used run time, periodic recalibration is
> > performed as well.
> >
> > The operational mode is describes as the following:
> > * SmartReflex AVS h/w calibration loop is essential to identify the optimal
> > voltage for a given OPP.
> > * Once this optimal voltage is detected, SmartReflex AVS loop is disabled in
> > class 1.5 mode of operation.
> > * Until there is a need for a recalibration, any further transition to an OPP
> > voltage which is calibrated can use the calibrated voltage and does not
> > require enabling the SR AVS h/w loop.
> > * On a periodic basis (recommendation being once approximately every 24 hours),
> > software is expected to perform a recalibration to find a new optimal
> > voltage which is compensated for device aging.
> > - For performing this recalibration, the start voltage does not need to
> > be the nominal voltage anymore. instead, the system can start with a
> > voltage which is 50mV higher than the previously calibrated voltage to
> > identify the new optimal voltage as the aging factor within a period of
> > 1 day is not going to be anywhere close to 50mV.
> > - This "new starting point" for recalibration is called a dynamic
> > nominal voltage for that voltage point.
> > In short, with the introduction of SmartReflex class 1.5, there are three new
> > voltages possible in a system's dvfs transition:
> > * Nominal Voltage - The maximum voltage needed for a worst possible device
> > in the worst possible conditions. This is the voltage we choose as
> > the starting point for the h/w loop to optimize for the first time
> > calibration on system bootup.
> > * Dynamic Nominal Voltage - Worst case voltage for a specific device in
> > considering the system aging on the worst process device.
> > * Calibrated Voltage - Best voltage for the current device at a given point
> > of time.
> >
> > In terms of the implementation, doing calibration involves waiting for the
> > smartreflex h/w loop to settle down, and doing this as part of the dvfs flow
> > itself is to increase the latency of dvfs transition when there is a need to
> > calibrate that opp. instead, the calibration is performed "out of path" using
> > a workqueue statemachine. The workqueue waits for the system stabilization,
> > then enables VP interrupts to monitor for system instability interms of voltage
> > oscillations that are reported back to the system as interrupts, in case of
> > prolonged system oscillations, nominal voltage is chosen as a safe voltage and
> > this event is logged in the system log for developer debug and fixing.
> >
> > For the recalibration, a common workqueue for all domains is started at the
> > start of the class initialization and it resets the calibrated voltages
> > on a periodic basis. For distros that may choose not to do the recommended
> > periodic recalibration, instead choose to perform boot time calibration,
> > kconfig configuration option is provided to do so.
> >
> > TODO:
> > a) Cpuidle and suspend paths are not integrated with SmartReflex driver at
> > this point.
> > b) Since the SR registers are accessed and controlled in parallel to DVFS
> > some sort of mechanism is necessary to be introduced along with OMAP
> > dvfs layer to ensure mutual exclusivity
> > c) Additional debug interfaces for vmin analysis for platform characterization
> > and addition of system margin needs to be introduced from smartreflex
> > perspective.
> >
> > This implementation also includes the following contributors:
> > Tony Lindgren for suggestion on using interrupt based mechanism instead of
> > polling to detect voltage oscillations.
> > Peter 'p2' De Schrijver for debating alternatives on recalibration mechanisms
> > Paul Walmsey, Eduardo Valentin, Ambresh K, Igor Dmitriev and quiet a few others
> > for patient review, testing and reporting of issues of a previous incarnation
> > of this implemenation. Last, but not the least, the TI H/w team in introducing
> > this new SR AVS class and patiently debating it's various facets.
> >
> > Cc: Ambresh K <ambresh <at> ti.com>
> > Cc: Eduardo Valentin <eduardo.valentin <at> nokia.com>
> > Cc: Igor Dmitriev <ext-dmitriev.igor <at> nokia.com>
> > Cc: Paul <paul <at> pwsan.com>
> > Cc: Peter 'p2' De Schrijver <Peter.De-Schrijver <at> nokia.com>
> > Cc: Tony Lindgren <tony <at> atomide.com>
> >
> > Signed-off-by: Nishanth Menon <nm <at> ti.com>
> > ---
> > arch/arm/mach-omap2/Makefile | 1 +
> > arch/arm/mach-omap2/smartreflex-class1p5.c | 556 +++++++++++++++++++++++++
> > arch/arm/mach-omap2/smartreflex-class3.c | 4 +-
> > arch/arm/mach-omap2/smartreflex.c | 34 ++-
> > arch/arm/mach-omap2/voltage.c | 69 +++
> > arch/arm/plat-omap/Kconfig | 17 +
> > arch/arm/plat-omap/include/plat/smartreflex.h | 13 +-
> > arch/arm/plat-omap/include/plat/voltage.h | 23 +-
> > 8 files changed, 709 insertions(+), 8 deletions(-)
> > create mode 100644 arch/arm/mach-omap2/smartreflex-class1p5.c
> >
> > diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
> > index 1c0c2b0..1a82e6d 100644
> > --- a/arch/arm/mach-omap2/Makefile
> > +++ b/arch/arm/mach-omap2/Makefile
> > @@ -66,6 +66,7 @@ obj-$(CONFIG_ARCH_OMAP4) += pm44xx.o voltage.o pm_bus.o
> > obj-$(CONFIG_PM_DEBUG) += pm-debug.o
> > obj-$(CONFIG_OMAP_SMARTREFLEX) += sr_device.o smartreflex.o
> > obj-$(CONFIG_OMAP_SMARTREFLEX_CLASS3) += smartreflex-class3.o
> > +obj-$(CONFIG_OMAP_SMARTREFLEX_CLASS1P5) += smartreflex-class1p5.o
> >
> > AFLAGS_sleep24xx.o :=-Wa,-march=armv6
> > AFLAGS_sleep34xx.o :=-Wa,-march=armv7-a
> > diff --git a/arch/arm/mach-omap2/smartreflex-class1p5.c b/arch/arm/mach-omap2/smartreflex-class1p5.c
> > new file mode 100644
> > index 0000000..832f10b
> > --- /dev/null
> > +++ b/arch/arm/mach-omap2/smartreflex-class1p5.c
> > @@ -0,0 +1,556 @@
> > +/*
> > + * Smart reflex Class 1.5 specific implementations
> > + *
> > + * Copyright (C) 2010-2011 Texas Instruments, Inc.
> > + * Nishanth Menon <nm <at> ti.com>
> > + *
> > + * Smart reflex class 1.5 is also called periodic SW Calibration
> > + * Some of the highlights are as follows:
> > + * – Host CPU triggers OPP calibration when transitioning to non calibrated
> > + * OPP
> > + * – SR-AVS + VP modules are used to perform calibration
> > + * – Once completed, the SmartReflex-AVS module can be disabled
> > + * – Enables savings based on process, supply DC accuracy and aging
> > + *
> > + * 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/delay.h>
> > +#include <linux/err.h>
> > +#include <linux/io.h>
> > +#include <linux/fs.h>
> > +#include <linux/string.h>
> > +#include <linux/uaccess.h>
> > +#include <linux/kobject.h>
> > +#include <linux/workqueue.h>
> > +#include <linux/opp.h>
> > +
> > +#include <plat/smartreflex.h>
> > +#include <plat/voltage.h>
> > +
> > +#define MAX_VDDS 3
> > +#define SR1P5_SAMPLING_DELAY_MS 1
> > +#define SR1P5_STABLE_SAMPLES 5
> > +#define SR1P5_MAX_TRIGGERS 5
> > +
> > +/*
> > + * we expect events in 10uS, if we dont get 2wice times as much,
> > + * we could kind of ignore this as a missed event.
> > + */
> > +#define MAX_CHECK_VPTRANS_US 20
> > +
> > +/**
> > + * struct sr_class1p5_work_data - data meant to be used by calibration work
> > + * @work: calibration work
> > + * @voltdm: voltage domain for which we are triggering
> > + * @vdata: voltage data we are calibrating
> > + * @num_calib_triggers: number of triggers from calibration loop
> > + * @num_osc_samples: number of samples collected by isr
> > + * @work_active: have we scheduled a work item?
> > + */
> > +struct sr_class1p5_work_data {
> > + struct delayed_work work;
> > + struct voltagedomain *voltdm;
> > + struct omap_volt_data *vdata;
> > + u8 num_calib_triggers;
> > + u8 num_osc_samples;
> > + bool work_active;
> > +};
> > +
> > +#if CONFIG_OMAP_SR_CLASS1P5_RECALIBRATION_DELAY
> > +/* recal_work: recalibration calibration work */
> > +static struct delayed_work recal_work;
> > +#endif
> > +
> > +/**
> > + * struct sr_class1p5_data - private data for class 1p5
> > + * @work_data: work item data per voltage domain
> > + */
> > +struct sr_class1p5_data {
> > + struct sr_class1p5_work_data work_data[MAX_VDDS];
> > +};
> > +
> > +static void sr_class1p5_reset_calib(struct voltagedomain *voltdm, bool reset,
> > + bool recal);
> > +
> > +/* our instance of class 1p5 private data */
> > +static struct sr_class1p5_data class_1p5_data;
> > +
> > +static struct sr_class1p5_work_data *get_sr1p5_work(struct voltagedomain
> > + *voltdm)
> > +{
> > + int idx;
> > + for (idx = 0; idx < MAX_VDDS; idx++) {
> > + if (class_1p5_data.work_data[idx].voltdm && !strcmp
> > + (class_1p5_data.work_data[idx].voltdm->name, voltdm->name))
> > + return &class_1p5_data.work_data[idx];
> > + }
> > + return ERR_PTR(-ENODATA);
> > +}
> > +
> > +/**
> > + * sr_class1p5_notify() - isr notifier for status events
> > + * @voltdm: voltage domain for which we were triggered
> > + * @status: notifier event to use
> > + *
> > + * This basically collects data for the work to use.
> > + */
> > +static int sr_class1p5_notify(struct voltagedomain *voltdm, u32 status)
> > +{
> > + struct sr_class1p5_work_data *work_data;
> > + int idx = 0;
> > + work_data = get_sr1p5_work(voltdm);
> > +
> > + if (unlikely(!work_data)) {
> > + pr_err("%s:%s no work data!!\n", __func__, voltdm->name);
> > + return -EINVAL;
> > + }
> > +
> > + /* Wait for transdone so that we know the voltage to read */
> > + do {
> > + if (omap_vp_is_transdone(voltdm))
> > + break;
> > + idx++;
> > + /* get some constant delay */
> > + udelay(1);
> > + } while (idx < MAX_CHECK_VPTRANS_US);
> > +
> > + /*
> > + * If we timeout, we still read the data,
> > + * if we are oscillating+irq latencies are too high, we could
> > + * have scenarios where we miss transdone event. since
> > + * we waited long enough, it is still safe to read the voltage
> > + * as we would have waited long enough - still flag it..
> > + */
> > + if (idx >= MAX_CHECK_VPTRANS_US)
> > + pr_warning("%s: timed out waiting for transdone!!\n", __func__);
> > +
> > + omap_vp_clear_transdone(voltdm);
> > +
> > + idx = (work_data->num_osc_samples) % SR1P5_STABLE_SAMPLES;
> > + work_data->num_osc_samples++;
> > +
> > + return 0;
> > +}
> > +
> > +/**
> > + * do_calibrate() - work which actually does the calibration
> > + * @work: pointer to the work
> > + *
> > + * calibration routine uses the following logic:
> > + * on the first trigger, we start the isr to collect sr voltages
> > + * wait for stabilization delay (reschdule self instead of sleeping)
> > + * after the delay, see if we collected any isr events
> > + * if none, we have calibrated voltage.
> > + * if there are any, we retry untill we giveup.
> > + * on retry timeout, select a voltage to use as safe voltage.
> > + */
> > +static void do_calibrate(struct work_struct *work)
> > +{
> > + struct sr_class1p5_work_data *work_data =
> > + container_of(work, struct sr_class1p5_work_data, work.work);
> > + unsigned long u_volt_safe = 0, u_volt_current = 0;
> > + struct omap_volt_data *volt_data;
> > + struct voltagedomain *voltdm;
> > +
> > + if (unlikely(!work_data)) {
> > + pr_err("%s: ooops.. null work_data?\n", __func__);
> > + return;
> > + }
> > +
> > + /*
> > + * TODO:Handle the case where we might have just been scheduled AND
> > + * 1.5 disable was called. check and HOLD dvfs
> > + */
> > +
> > + voltdm = work_data->voltdm;
> > + /*
> > + * In the unlikely case that we did get through when unplanned,
> > + * flag and return.
> > + */
> > + if (unlikely(!work_data->work_active)) {
> > + pr_err("%s:%s unplanned work invocation!\n", __func__,
> > + voltdm->name);
> > + /* TODO release the dvfs */
> > + return;
> > + }
> > +
> > + work_data->num_calib_triggers++;
> > + /* if we are triggered first time, we need to start isr to sample */
> > + if (work_data->num_calib_triggers == 1)
> > + goto start_sampling;
> > +
> > + /* Stop isr from interrupting our measurements :) */
> > + sr_notifier_control(voltdm, false);
> > +
> > + volt_data = work_data->vdata;
> > +
> > + /* if there are no samples captured.. SR is silent, aka stability! */
> > + if (!work_data->num_osc_samples) {
> > + u_volt_safe = omap_vp_get_curr_volt(voltdm);
> > + u_volt_current = u_volt_safe;
> > + goto done_calib;
> > + }
> > + if (work_data->num_calib_triggers == SR1P5_MAX_TRIGGERS) {
> > + pr_warning("%s: %s recalib timeout!\n", __func__,
> > + work_data->voltdm->name);
> > + goto oscillating_calib;
> > + }
> > +
> > + /* we have potential oscillations/first sample */
> > +start_sampling:
> > + work_data->num_osc_samples = 0;
> > + /* Clear pending events */
> > + sr_notifier_control(voltdm, false);
> > + /* Clear all transdones */
> > + while (omap_vp_is_transdone(voltdm))
> > + omap_vp_clear_transdone(voltdm);
> > + /* trigger sampling */
> > + sr_notifier_control(voltdm, true);
> > + schedule_delayed_work(&work_data->work,
> > + msecs_to_jiffies(SR1P5_SAMPLING_DELAY_MS *
> > + SR1P5_STABLE_SAMPLES));
> > + /* TODO: release dvfs */
> > + return;
> > +
> > +oscillating_calib:
> > + /* Use the nominal voltage as the safe voltage */
> > + u_volt_safe = volt_data->volt_nominal;
> > + /* pick up current voltage to switch if needed */
> > + u_volt_current = omap_vp_get_curr_volt(voltdm);
> > +
> > + /* Fall through to close up common stuff */
> > +done_calib:
> > + omap_vp_disable(voltdm);
> > + sr_disable(voltdm);
> > +
> > + volt_data->volt_calibrated = u_volt_safe;
> > + /* Setup my dynamic voltage for the next calibration for this opp */
> > + volt_data->volt_dynamic_nominal = omap_get_dyn_nominal(volt_data);
> > +
> > + /*
> > + * if the voltage we decided as safe is not the current voltage,
> > + * switch
> > + */
> > + if (volt_data->volt_calibrated != u_volt_current) {
> > + pr_debug("%s:%s reconfiguring to voltage %d\n",
> > + __func__, voltdm->name, volt_data->volt_calibrated);
> > + omap_voltage_scale_vdd(voltdm, volt_data);
> > + }
> > +
> > + /*
> > + * TODO: Setup my wakeup voltage to allow immediate going to OFF and
> > + * on - Pending twl and voltage layer cleanups.
> > + * This is necessary, as this is not done as part of regular
> > + * Dvfs flow.
> > + * vc_setup_on_voltage(voltdm, volt_data->volt_calibrated);
> > + */
> > + work_data->work_active = false;
> > + /* TODO: release dvfs */
> > +}
> > +
Taking into account that the recalibration happens on boot or between large interval (several hour even complete days)... I'm going to launch a question:
Is sr_adjust_vsel allways the suppling voltaje to processor... or it varies during the time between calibration intervals?
Please, look into the matter and let discuss how our machines behave.
If you're feeling manly enough, I can compile the kernel without smartreflex.
Just for the UV lulz.
Edit, it doesn't let me.
Code:
arch/arm/mach-omap2/resource34xx.o: In function `sr_recalibrate':
resource34xx.c:(.text+0x684): multiple definition of `sr_recalibrate'
arch/arm/mach-omap2/pm34xx.o:pm34xx.c:(.text+0x498): first defined here
make[1]: *** [arch/arm/mach-omap2/built-in.o] Error 1
If you're feeling manly enough, I can compile the kernel without smartreflex.
Just for the UV lulz.
Edit, it doesn't let me.
Code:
arch/arm/mach-omap2/resource34xx.o: In function `sr_recalibrate':
resource34xx.c:(.text+0x684): multiple definition of `sr_recalibrate'
arch/arm/mach-omap2/pm34xx.o:pm34xx.c:(.text+0x498): first defined here
make[1]: *** [arch/arm/mach-omap2/built-in.o] Error 1
- I think that the proper way to use milestone overclock is with smartreflex flag since our 3630 runs with smartreflex.
- Even without this module, OB should control the processor's voltages with smartreflex, because is a intrinsic characteristic of 3630.
- I've seen that UV without smartreflex flag doesn't run, I had probe it with a ultramegalow voltages running flawlessly. Maybe you are thinking about compile module without smartreflex but pushing the 'echo 0 > sr_adjust_vsel', but I think this is part of smartreflex feature because of the sr_ ....
- I'm thinking about a way to UV... If we push freq and voltage values but don't make the 'echo 0 > sr_adjust_vsel', freqs seems to change but voltajes don't... Maybe if we adjust some ultralow frequencies and we calibrate their voltages, those ones will be lower than normal because of low freq voltage requirements. Then, push again new freqs with vsel = last calibrated values but DO NOT recalibrate it. Then we will theoretically have the wanted freqs with the lowfreq voltajes until next driver autocalibrate.
After reading about Dan Rosenberg’s bootloader exploit for the Samsung Galaxy S 4,I … more
XDA Developers was founded by developers, for developers. It is now a valuable resource for people who want to make the most of their mobile devices, from customizing the look and feel to adding new functionality. Are you a developer?