Hi all!
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...
Regards!
http://permalink.gmane.org/gmane.linux.ports.arm.omap/53604
Part 1/2:
Code:
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 */
> > +}
> > +
Part 2/2:
Code:
> > +#if CONFIG_OMAP_SR_CLASS1P5_RECALIBRATION_DELAY
> > +/**
> > + * do_recalibrate() - work which actually does the calibration
> > + * @work: pointer to the work
> > + *
> > + * on a periodic basis, we come and reset our calibration setup
> > + * so that a recalibration of the OPPs take place. This takes
> > + * care of aging factor in the system.
> > + */
> > +static void do_recalibrate(struct work_struct *work)
> > +{
> > + struct voltagedomain *voltdm;
> > + int idx;
> > + static struct sr_class1p5_work_data *work_data;
> > +
> > + for (idx = 0; idx < MAX_VDDS; idx++) {
> > + work_data = &class_1p5_data.work_data[idx];
> > + voltdm = work_data->voltdm;
> > + if (voltdm) {
> > + /* if sr is not enabled, we check later */
> > + if (!is_sr_enabled(voltdm))
> > + continue;
> > + /* TODO: Pause the dvfs transitions */
> > + /* if sr is not enabled, we check later */
> > +
> > + /* Reset and force a recalibration for current opp */
> > + sr_class1p5_reset_calib(voltdm, true, true);
> > +
> > + /* TODO: unpause DVFS transitions */
> > + }
> > + }
> > + /* We come back again after time the usual delay */
> > + schedule_delayed_work(&recal_work,
> > + msecs_to_jiffies(CONFIG_OMAP_SR_CLASS1P5_RECALIBRATION_DELAY));
> > +}
> > +#endif /* CONFIG_OMAP_SR_CLASS1P5_RECALIBRATION_DELAY */
> > +
> > +/**
> > + * sr_class1p5_enable() - class 1.5 mode of enable
> > + * @voltdm: voltage domain to enable SR for
> > + * @volt_data: voltdata to the voltage transition taking place
> > + *
> > + * when this gets called, we use the h/w loop to setup our voltages
> > + * to an calibrated voltage, detect any oscillations, recover from the same
> > + * and finally store the optimized voltage as the calibrated voltage in the
> > + * system
> > + */
> > +static int sr_class1p5_enable(struct voltagedomain *voltdm,
> > + struct omap_volt_data *volt_data)
> > +{
> > + int r;
> > + struct sr_class1p5_work_data *work_data;
> > + /* if already calibrated, nothing to do here.. */
> > + if (volt_data->volt_calibrated)
> > + return 0;
> > +
> > + work_data = get_sr1p5_work(voltdm);
> > + if (unlikely(!work_data)) {
> > + pr_err("%s: aieeee.. bad work data??\n", __func__);
> > + return -EINVAL;
> > + }
> > +
> > + if (work_data->work_active)
> > + return 0;
> > +
> > + omap_vp_enable(voltdm);
> > + r = sr_enable(voltdm, volt_data);
> > + if (r) {
> > + pr_err("%s: sr[%s] failed\n", __func__, voltdm->name);
> > + omap_vp_disable(voltdm);
> > + return r;
> > + }
> > + work_data->vdata = volt_data;
> > + work_data->work_active = true;
> > + work_data->num_calib_triggers = 0;
> > + /* program the workqueue and leave it to calibrate offline.. */
> > + schedule_delayed_work(&work_data->work,
> > + msecs_to_jiffies(SR1P5_SAMPLING_DELAY_MS *
> > + SR1P5_STABLE_SAMPLES));
> > +
> > + return 0;
> > +}
> > +
> > +/**
> > + * sr_class1p5_disable() - disable for class 1p5
> > + * @voltdm: voltage domain for the sr which needs disabling
> > + * @volt_data: voltagedata to disable
> > + * @is_volt_reset: reset the voltage?
> > + *
> > + * we dont do anything if the class 1p5 is being used. this is because we
> > + * already disable sr at the end of calibration and no h/w loop is actually
> > + * active when this is called.
> > + */
> > +static int sr_class1p5_disable(struct voltagedomain *voltdm,
> > + struct omap_volt_data *volt_data,
> > + int is_volt_reset)
> > +{
> > + struct sr_class1p5_work_data *work_data;
> > +
> > + work_data = get_sr1p5_work(voltdm);
> > + if (work_data->work_active) {
> > + /* if volt reset and work is active, we dont allow this */
> > + if (is_volt_reset)
> > + return -EBUSY;
> > + /* flag work is dead and remove the old work */
> > + work_data->work_active = false;
> > + cancel_delayed_work_sync(&work_data->work);
> > + sr_notifier_control(voltdm, false);
> > + omap_vp_disable(voltdm);
> > + sr_disable(voltdm);
> > + }
> > +
> > + /* if already calibrated, nothin special to do here.. */
> > + if (volt_data->volt_calibrated)
> > + return 0;
> > +
> > + if (is_volt_reset)
> > + omap_voltage_reset(voltdm);
> > + return 0;
> > +}
> > +
> > +/**
> > + * sr_class1p5_configure() - configuration function
> > + * @voldm: configure for which voltage domain
> > + *
> > + * we dont do much here other than setup some registers for
> > + * the sr module involved.
> > + */
> > +static int sr_class1p5_configure(struct voltagedomain *voltdm)
> > +{
> > + return sr_configure_errgen(voltdm);
> > +}
> > +
> > +/**
> > + * sr_class1p5_reset_calib() - reset all calibrated voltages
> > + * @srid: srid to reset the calibration for
> > + * @reset: reset voltage before we recal?
> > + * @recal: should I recalibrate my current opp?
> > + *
> > + * if we call this, it means either periodic calibration trigger was
> > + * fired(either from sysfs or other mechanisms) or we have disabled class 1p5,
> > + * meaning we cant trust the calib voltages anymore, it is better to use
> > + * nominal in the system
> > + */
> > +static void sr_class1p5_reset_calib(struct voltagedomain *voltdm, bool reset,
> > + bool recal)
> > +{
> > + struct sr_class1p5_work_data *work_data;
> > +
> > + /* I dont need to go further if sr is not present */
> > + if (!is_sr_enabled(voltdm))
> > + return;
> > +
> > + work_data = get_sr1p5_work(voltdm);
> > +
> > + if (work_data->work_active)
> > + sr_class1p5_disable(voltdm, work_data->vdata, 0);
> > +
> > + omap_voltage_calib_reset(voltdm);
> > +
> > + /*
> > + * I should now reset the voltages to my nominal to be safe
> > + */
> > + if (reset)
> > + omap_voltage_reset(voltdm);
> > +
> > + /*
> > + * I should fire a recalibration for current opp if needed
> > + * Note: i have just reset my calibrated voltages, and if
> > + * i call sr_enable equivalent, I will cause a recalibration
> > + * loop, even though the function is called sr_enable.. we
> > + * are in class 1.5 ;)
> > + */
> > + if (reset && recal)
> > + sr_class1p5_enable(voltdm, work_data->vdata);
> > +}
> > +
> > +/**
> > + * sr_class1p5_cinit() - class 1p5 init
> > + * @voltdm: sr voltage domain
> > + * @class_priv_data: private data for the class
> > + *
> > + * we do class specific initialization like creating sysfs/debugfs entries
> > + * needed, spawning of a kthread if needed etc.
> > + */
> > +static int sr_class1p5_cinit(struct voltagedomain *voltdm,
> > + void *class_priv_data)
> > +{
> > + struct sr_class1p5_work_data *work_data;
> > + int idx;
> > +
> > + if (!class_priv_data) {
> > + pr_err("%s: bad param? no priv data!\n", __func__);
> > + return -EINVAL;
> > + }
> > +
> > + /* setup our work params */
> > + work_data = get_sr1p5_work(voltdm);
> > + if (!IS_ERR_OR_NULL(work_data)) {
> > + pr_err("%s: ooopps.. class already initialized for %s! bug??\n",
> > + __func__, voltdm->name);
> > + return -EINVAL;
> > + }
> > + work_data = NULL;
> > + /* get the next spare work_data */
> > + for (idx = 0; idx < MAX_VDDS; idx++) {
> > + if (!class_1p5_data.work_data[idx].voltdm) {
> > + work_data = &class_1p5_data.work_data[idx];
> > + break;
> > + }
> > + }
> > + if (!work_data) {
> > + pr_err("%s: no more space for work data for domains!\n",
> > + __func__);
> > + return -ENOMEM;
> > + }
> > + work_data->voltdm = voltdm;
> > + INIT_DELAYED_WORK_DEFERRABLE(&work_data->work, do_calibrate);
> > + return 0;
> > +}
> > +
> > +/**
> > + * sr_class1p5_cdeinit() - class 1p5 deinitialization
> > + * @voltdm: voltage domain for which to do this.
> > + * @class_priv_data: class private data for deinitialiation
> > + *
> > + * currently only resets the calibrated voltage forcing dvfs voltages
> > + * to be used in the system
> > + */
> > +static int sr_class1p5_cdeinit(struct voltagedomain *voltdm,
> > + void *class_priv_data)
> > +{
> > + struct sr_class1p5_work_data *work_data;
> > +
> > + /* setup our work params */
> > + work_data = get_sr1p5_work(voltdm);
> > + if (IS_ERR_OR_NULL(work_data)) {
> > + pr_err("%s: ooopps.. class not initialized for %s! bug??\n",
> > + __func__, voltdm->name);
> > + return -EINVAL;
> > + }
> > +
> > + /*
> > + * we dont have SR periodic calib anymore.. so reset calibs
> > + * we are already protected by sr debugfs lock, so no lock needed
> > + * here.
> > + */
> > + sr_class1p5_reset_calib(voltdm, true, false);
> > +
> > + /* reset all data for this work data */
> > + memset(work_data, 0, sizeof(*work_data));
> > +
> > + return 0;
> > +}
> > +
> > +/* SR class1p5 structure */
> > +static struct omap_sr_class_data class1p5_data = {
> > + .enable = sr_class1p5_enable,
> > + .disable = sr_class1p5_disable,
> > + .configure = sr_class1p5_configure,
> > + .class_type = SR_CLASS1P5,
> > + .class_init = sr_class1p5_cinit,
> > + .class_deinit = sr_class1p5_cdeinit,
> > + .notify = sr_class1p5_notify,
> > + /*
> > + * trigger for bound - this tells VP that SR has a voltage
> > + * change. we should ensure transdone is set before reading
> > + * vp voltage.
> > + */
> > + .notify_flags = SR_NOTIFY_MCUBOUND,
> > + .class_priv_data = (void *)&class_1p5_data,
> > +};
> > +
> > +/**
> > + * sr_class1p5_init() - register class 1p5 as default
> > + *
> > + * board files call this function to use class 1p5, we register with the
> > + * smartreflex subsystem
> > + */
> > +static int __init sr_class1p5_init(void)
> > +{
> > + int r;
> > +
> > + /* Enable this class only for OMAP3630 and OMAP4 */
> > + if (!(cpu_is_omap3630() || cpu_is_omap44xx()))
> > + return -EINVAL;
> > +
> > + r = sr_register_class(&class1p5_data);
> > + if (r) {
> > + pr_err("SmartReflex class 1.5 driver: "
> > + "failed to register with %d\n", r);
> > + } else {
> > +#if CONFIG_OMAP_SR_CLASS1P5_RECALIBRATION_DELAY
> > + INIT_DELAYED_WORK_DEFERRABLE(&recal_work, do_recalibrate);
> > + schedule_delayed_work(&recal_work, msecs_to_jiffies(
> > + CONFIG_OMAP_SR_CLASS1P5_RECALIBRATION_DELAY));
> > +#endif
> > + pr_info("SmartReflex class 1.5 driver: initialized (%dms)\n",
> > + CONFIG_OMAP_SR_CLASS1P5_RECALIBRATION_DELAY);
> > + }
> > + return r;
> > +}
> > +late_initcall(sr_class1p5_init);
> > diff --git a/arch/arm/mach-omap2/smartreflex-class3.c b/arch/arm/mach-omap2/smartreflex-class3.c
> > index 7ac88da..5f7a33e 100644
> > --- a/arch/arm/mach-omap2/smartreflex-class3.c
> > +++ b/arch/arm/mach-omap2/smartreflex-class3.c
> > @@ -21,7 +21,9 @@ static int sr_class3_enable(struct voltagedomain *voltdm,
> > return sr_enable(voltdm, volt_data);
> > }
> >
> > -static int sr_class3_disable(struct voltagedomain *voltdm, int is_volt_reset)
> > +static int sr_class3_disable(struct voltagedomain *voltdm,
> > + struct omap_volt_data *vdata,
> > + int is_volt_reset)
> > {
> > omap_vp_disable(voltdm);
> > sr_disable(voltdm);
> > diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c
> > index 3a5f2f6..bb55b65 100644
> > --- a/arch/arm/mach-omap2/smartreflex.c
> > +++ b/arch/arm/mach-omap2/smartreflex.c
> > @@ -317,7 +317,9 @@ static void sr_stop_vddautocomp(struct omap_sr *sr)
> > }
> >
> > if (sr->autocomp_active) {
> > - sr_class->disable(sr->voltdm, 1);
> > + sr_class->disable(sr->voltdm,
> > + omap_voltage_get_nom_volt(sr->voltdm),
> > + 1);
> > if (sr_class->class_deinit &&
> > sr_class->class_deinit(sr->voltdm,
> > sr_class->class_priv_data)) {
> > @@ -471,6 +473,28 @@ static u32 sr_retrieve_nvalue(struct omap_sr *sr, u32 efuse_offs)
> > /* Public Functions */
> >
> > /**
> > + * is_sr_enabled() - is Smart reflex enabled for this domain?
> > + * @voltdm: voltage domain to check
> > + *
> > + * Returns 0 if SR is enabled for this domain, else returns err
> > + */
> > +bool is_sr_enabled(struct voltagedomain *voltdm)
> > +{
> > + struct omap_sr *sr;
> > + if (IS_ERR_OR_NULL(voltdm)) {
> > + pr_warning("%s: invalid param voltdm\n", __func__);
> > + return false;
> > + }
> > + sr = _sr_lookup(voltdm);
> > + if (IS_ERR(sr)) {
> > + pr_warning("%s: omap_sr struct for sr_%s not found\n",
> > + __func__, voltdm->name);
> > + return false;
> > + }
> > + return sr->autocomp_active;
> > +}
> > +
> > +/**
> > * sr_configure_errgen() - Configures the smrtreflex to perform AVS using the
> > * error generator module.
> > * @voltdm: VDD pointer to which the SR module to be configured belongs to.
> > @@ -839,6 +863,7 @@ void omap_sr_enable(struct voltagedomain *voltdm,
> > * omap_sr_disable() - API to disable SR without resetting the voltage
> > * processor voltage
> > * @voltdm: VDD pointer to which the SR module to be configured belongs to.
> > + * @volt_data: Voltage data to go to
> > *
> > * This API is to be called from the kernel in order to disable
> > * a particular smartreflex module. This API will in turn call
> > @@ -846,7 +871,8 @@ void omap_sr_enable(struct voltagedomain *voltdm,
> > * the smartreflex class disable not to reset the VP voltage after
> > * disabling smartreflex.
> > */
> > -void omap_sr_disable(struct voltagedomain *voltdm)
> > +void omap_sr_disable(struct voltagedomain *voltdm,
> > + struct omap_volt_data *vdata)
> > {
> > struct omap_sr *sr = _sr_lookup(voltdm);
> >
> > @@ -865,7 +891,7 @@ void omap_sr_disable(struct voltagedomain *voltdm)
> > return;
> > }
> >
> > - sr_class->disable(voltdm, 0);
> > + sr_class->disable(voltdm, vdata, 0);
> > }
> >
> > /**
> > @@ -898,7 +924,7 @@ void omap_sr_disable_reset_volt(struct voltagedomain *voltdm)
> > return;
> > }
> >
> > - sr_class->disable(voltdm, 1);
> > + sr_class->disable(voltdm, omap_voltage_get_nom_volt(voltdm), 1);
> > }
> >
> > /**
> > diff --git a/arch/arm/mach-omap2/voltage.c b/arch/arm/mach-omap2/voltage.c
> > index 77cb0cd..c451835 100644
> > --- a/arch/arm/mach-omap2/voltage.c
> > +++ b/arch/arm/mach-omap2/voltage.c
> > @@ -374,9 +374,45 @@ static int nom_volt_debug_get(void *data, u64 *val)
> > return 0;
> > }
> >
> > +static int dyn_volt_debug_get(void *data, u64 *val)
> > +{
> > + struct omap_vdd_info *vdd = (struct omap_vdd_info *) data;
> > + struct omap_volt_data *volt_data;
> > +
> > + if (!vdd) {
> > + pr_warning("Wrong paramater passed\n");
> > + return -EINVAL;
> > + }
> > + volt_data = omap_voltage_get_nom_volt(&vdd->voltdm);
> > +
> > + *val = volt_data->volt_dynamic_nominal;
> > +
> > + return 0;
> > +}
> > +
> > +static int calib_volt_debug_get(void *data, u64 *val)
> > +{
> > + struct omap_vdd_info *vdd = (struct omap_vdd_info *) data;
> > + struct omap_volt_data *volt_data;
> > +
> > + if (!vdd) {
> > + pr_warning("Wrong paramater passed\n");
> > + return -EINVAL;
> > + }
> > + volt_data = omap_voltage_get_nom_volt(&vdd->voltdm);
> > +
> > + *val = volt_data->volt_calibrated;
> > +
> > + return 0;
> > +}
> > +
> > DEFINE_SIMPLE_ATTRIBUTE(vp_volt_debug_fops, vp_volt_debug_get, NULL, "%llu\n");
> > DEFINE_SIMPLE_ATTRIBUTE(nom_volt_debug_fops, nom_volt_debug_get, NULL,
> > "%llu\n");
> > +DEFINE_SIMPLE_ATTRIBUTE(dyn_volt_debug_fops, dyn_volt_debug_get, NULL,
> > + "%llu\n");
> > +DEFINE_SIMPLE_ATTRIBUTE(calib_volt_debug_fops, calib_volt_debug_get, NULL,
> > + "%llu\n");
> > static void vp_latch_vsel(struct omap_vdd_info *vdd)
> > {
> > u32 vpconfig;
> > @@ -504,6 +540,12 @@ static void __init vdd_debugfs_init(struct omap_vdd_info *vdd)
> > (void) debugfs_create_file("curr_nominal_volt", S_IRUGO,
> > vdd->debug_dir, (void *) vdd,
> > &nom_volt_debug_fops);
> > + (void) debugfs_create_file("curr_dyn_nominal_volt", S_IRUGO,
> > + vdd->debug_dir, (void *) vdd,
> > + &dyn_volt_debug_fops);
> > + (void) debugfs_create_file("curr_calibrated_volt", S_IRUGO,
> > + vdd->debug_dir, (void *) vdd,
> > + &calib_volt_debug_fops);
> > }
> >
> > /* Voltage scale and accessory APIs */
> > @@ -1132,6 +1174,33 @@ struct omap_volt_data *omap_voltage_get_nom_volt(struct voltagedomain *voltdm)
> > }
> >
> > /**
> > + * omap_voltage_calib_reset() - reset the calibrated voltage entries
> > + * @voltdm: voltage domain to reset the entries for
> > + *
> > + * when the calibrated entries are no longer valid, this api allows
> > + * the calibrated voltages to be reset.
> > + */
> > +int omap_voltage_calib_reset(struct voltagedomain *voltdm)
> > +{
> > + struct omap_vdd_info *vdd;
> > + struct omap_volt_data *volt_data;
> > +
> > + if (IS_ERR_OR_NULL(voltdm)) {
> > + pr_warning("%s: VDD specified does not exist!\n", __func__);
> > + return -EINVAL;
> > + }
> > +
> > + vdd = container_of(voltdm, struct omap_vdd_info, voltdm);
> > + volt_data = vdd->volt_data;
> > + /* reset the calibrated voltages as 0 */
> > + while (volt_data->volt_nominal) {
> > + volt_data->volt_calibrated = 0;
> > + volt_data++;
> > + }
> > + return 0;
> > +}
> > +
> > +/**
> > * omap_vp_get_curr_volt() - API to get the current vp voltage.
> > * @voltdm: pointer to the VDD.
> > *
> > diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig
> > index b6333ae..dba7939 100644
> > --- a/arch/arm/plat-omap/Kconfig
> > +++ b/arch/arm/plat-omap/Kconfig
> > @@ -67,6 +67,23 @@ config OMAP_SMARTREFLEX_CLASS3
> > Class 3 implementation of Smartreflex employs continuous hardware
> > voltage calibration.
> >
> > +config OMAP_SMARTREFLEX_CLASS1P5
> > + bool "Class 1.5 mode of Smartreflex Implementation"
> > + depends on OMAP_SMARTREFLEX && TWL4030_CORE
> > + help
> > + Say Y to enable Class 1.5 implementation of Smartreflex
> > + Class 1.5 implementation of Smartreflex employs software controlled
> > + hardware voltage calibration.
> > +
> > +config OMAP_SR_CLASS1P5_RECALIBRATION_DELAY
> > + int "Class 1.5 mode recalibration recalibration delay(ms)"
> > + depends on OMAP_SMARTREFLEX_CLASS1P5
> > + default 86400000
> > + help
> > + Setup the recalibration delay in milliseconds. Use 0 for never doing
> > + a recalibration. Defaults to recommended recalibration every 24hrs.
> > + If you do not understand this, use the default.
> > +
> > config OMAP_RESET_CLOCKS
> > bool "Reset unused clocks during boot"
> > depends on ARCH_OMAP
> > diff --git a/arch/arm/plat-omap/include/plat/smartreflex.h b/arch/arm/plat-omap/include/plat/smartreflex.h
> > index 07f35b2..ee5c58f 100644
> > --- a/arch/arm/plat-omap/include/plat/smartreflex.h
> > +++ b/arch/arm/plat-omap/include/plat/smartreflex.h
> > @@ -167,6 +167,7 @@ struct omap_sr_pmic_data {
> > #define SR_CLASS1 0x1
> > #define SR_CLASS2 0x2
> > #define SR_CLASS3 0x3
> > +#define SR_CLASS1P5 0x4
> >
> > /**
> > * struct omap_sr_class_data - Smartreflex class driver info
> > @@ -187,7 +188,9 @@ struct omap_sr_pmic_data {
> > struct omap_sr_class_data {
> > int (*enable)(struct voltagedomain *voltdm,
> > struct omap_volt_data *volt_data);
> > - int (*disable)(struct voltagedomain *voltdm, int is_volt_reset);
> > + int (*disable)(struct voltagedomain *voltdm,
> > + struct omap_volt_data *volt_data,
> > + int is_volt_reset);
> > int (*class_init)(struct voltagedomain *voltdm, void *class_priv_data);
> > int (*class_deinit)(struct voltagedomain *voltdm,
> > void *class_priv_data);
> > @@ -235,7 +238,8 @@ struct omap_sr_data {
> > /* Smartreflex module enable/disable interface */
> > void omap_sr_enable(struct voltagedomain *voltdm,
> > struct omap_volt_data *volt_data);
> > -void omap_sr_disable(struct voltagedomain *voltdm);
> > +void omap_sr_disable(struct voltagedomain *voltdm,
> > + struct omap_volt_data *volt_data);
> > void omap_sr_disable_reset_volt(struct voltagedomain *voltdm);
> >
> > /* API to register the pmic specific data with the smartreflex driver. */
> > @@ -250,6 +254,7 @@ int sr_configure_minmax(struct voltagedomain *voltdm);
> >
> > /* API to register the smartreflex class driver with the smartreflex driver */
> > int sr_register_class(struct omap_sr_class_data *class_data);
> > +bool is_sr_enabled(struct voltagedomain *voltdm);
> > #else
> > static inline void omap_sr_enable(struct voltagedomain *voltdm) {}
> > static inline void omap_sr_disable(struct voltagedomain *voltdm) {}
> > @@ -264,5 +269,9 @@ static inline void omap_sr_disable_reset_volt(
> > struct voltagedomain *voltdm) {}
> > static inline void omap_sr_register_pmic(
> > struct omap_sr_pmic_data *pmic_data) {}
> > +static inline bool is_sr_enabled(struct voltagedomain *voltdm)
> > +{
> > + return false;
> > +}
> > #endif
> > #endif
> > diff --git a/arch/arm/plat-omap/include/plat/voltage.h b/arch/arm/plat-omap/include/plat/voltage.h
> > index 332c581..54445f0 100644
> > --- a/arch/arm/plat-omap/include/plat/voltage.h
> > +++ b/arch/arm/plat-omap/include/plat/voltage.h
> > @@ -58,6 +58,8 @@
> > #define OMAP4430_VDD_CORE_OPP50_UV 930000
> > #define OMAP4430_VDD_CORE_OPP100_UV 1100000
> >
> > +#define OMAP3PLUS_DYNAMIC_NOMINAL_MARGIN_UV 50000
> > +
> > /**
> > * struct voltagedomain - omap voltage domain global structure.
> > * @name: Name of the voltage domain which can be used as a unique
> > @@ -81,6 +83,8 @@ struct voltagedomain {
> > */
> > struct omap_volt_data {
> > u32 volt_nominal;
> > + u32 volt_calibrated;
> > + u32 volt_dynamic_nominal;
> > u32 sr_efuse_offs;
> > u8 sr_errminlimit;
> > u8 vp_errgain;
> > @@ -127,6 +131,7 @@ struct omap_volt_data *omap_voltage_get_nom_volt(struct voltagedomain *voltdm);
> > bool omap_vp_is_transdone(struct voltagedomain *voltdm);
> > bool omap_vp_clear_transdone(struct voltagedomain *voltdm);
> > struct dentry *omap_voltage_get_dbgdir(struct voltagedomain *voltdm);
> > +int omap_voltage_calib_reset(struct voltagedomain *voltdm);
> > #ifdef CONFIG_PM
> > int omap_voltage_register_pmic(struct voltagedomain *voltdm,
> > struct omap_volt_pmic_info *pmic_info);
> > @@ -160,7 +165,23 @@ static inline unsigned long omap_get_operation_voltage(
> > {
> > if (IS_ERR_OR_NULL(vdata))
> > return 0;
> > - return vdata->volt_nominal;
> > + return (vdata->volt_calibrated) ? vdata->volt_calibrated :
> > + (vdata->volt_dynamic_nominal) ? vdata->volt_dynamic_nominal :
> > + vdata->volt_nominal;
> > }
> >
> > +/* what is my dynamic nominal? */
> > +static inline unsigned long omap_get_dyn_nominal(struct omap_volt_data *vdata)
> > +{
> > + if (IS_ERR_OR_NULL(vdata))
> > + return 0;
> > + if (vdata->volt_calibrated) {
> > + unsigned long v = vdata->volt_calibrated +
> > + OMAP3PLUS_DYNAMIC_NOMINAL_MARGIN_UV;
> > + if (v > vdata->volt_nominal)
> > + return vdata->volt_nominal;
> > + return v;
> > + }
> > + return vdata->volt_nominal;
> > +}
> > #endif
> > --
> > 1.7.1
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-omap" in
> > the body of a message to majordomo <at> vger.kernel.org
> > More majordomo info at http://vger.kernel.org/majordomo-info.html
> >
> I have tested this Patch Series on OMAP 3630 SDP, for MPU and IVA Powerdomains
Could you clarify on null pointer issue: on SDP3630? or OMAP4SDP? I
see there is a risk with OMAP4 where there is a bug in the following
scenario:
bootloader setups the OPP frequency for an OPP(e.g. 1GHz) which is
disabled by default on OPP table in kernel. this needs to be cleanly
fixed in pm.c, at the same time, the exposed functions in class1p5
needs parameter validation as well.
> it throws error log "Unable to refer to NULL pointer" if
> curr_nominal_volt, curr_calibrated_volt
> or curr_dynamical_volt is accessed through debugfs.
> Could you please provide fix for this.
Regards,
Nishanth Menon
mark...later to look into it
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
knzo said:
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
Click to expand...
Click to collapse
- 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.
I'll try.
I wasnt talking about the oc module but kernel itself.
Sent from my LG-P970 using XDA App
knzo said:
I wasnt talking about the oc module but kernel itself.
Sent from my LG-P970 using XDA App
Click to expand...
Click to collapse
Uhm....
Maybe modifying the source?... some tweaks here or there...
I already said I tried to disable smartreflex in the kernel but it wont compile.
Sent from my LG-P970 using XDA App
IMO, OMAP procs are already running undervolted. Thats the whole point of SmartReflex. Any easy way to undervolt further than the calibration thinks is stable is to select a very low nominal voltage. SmartReflex has a window around the nominal voltage to choose while calibrating. Move the nominal voltage low enough and the calibrated voltage must also be lower.
Another way to get around SmartReflex is to forcefully remove the e-fuse value. SmartReflex looks at hardware registers to determine whether the CPU supports a particular OPP. If it doesn't detect support then it does not calibrate the voltage and uses the nominal value.
Yet again another way to control SmartReflex is to force to use test N-values. This gives you control over the "window" around the nominal voltage that SmartReflex uses when calibrating.
dalingrin said:
IMO, OMAP procs are already running undervolted. Thats the whole point of SmartReflex. Any easy way to undervolt further than the calibration thinks is stable is to select a very low nominal voltage. SmartReflex has a window around the nominal voltage to choose while calibrating. Move the nominal voltage low enough and the calibrated voltage must also be lower.
Another way to get around SmartReflex is to forcefully remove the e-fuse value. SmartReflex looks at hardware registers to determine whether the CPU supports a particular OPP. If it doesn't detect support then it does not calibrate the voltage and uses the nominal value.
Yet again another way to control SmartReflex is to force to use test N-values. This gives you control over the "window" around the nominal voltage that SmartReflex uses when calibrating.
Click to expand...
Click to collapse
Many thanks for the answer.. you seem to know a lot into the matter.
I already suspected that smartreflex itself is a safe undervolt system.
To forcefully remove e-fuse is not the wat IMHO. I see very useful to set the voltajes taking into account hardware sensors like temp, aging, etc... To manually set fixed voltajes can end into unstabilities under different contexts.
To use test n-values seem a better way but I think that with the first method we can archieve the same.
IMHO, the best way could be to modify smartreflex from sources in order to get certain user defined undervolting. I mean, let smartreflex run by itself but when it's going to set the calibrated values, force-low them by a certain ammount contained into certain user-changeable file.
To begin with it, i'm developing a script that will do your first method.
If someone wants to try without SmartReflex, it's easy to deactivate it:
Code:
echo -n 0 > /sys/power/sr_vdd1_autocomp
echo -n 0 > /sys/power/sr_vdd2_autocomp
vdd1 and vdd2 respectively stands for mpu and l3 voltajes. Deactivating it we already know how to set mpu voltaje... but l3?
Regards!
Ok, I've created the script and experimented with it.
The script takes the actual calibrated voltajes and push them as vsel to recalibrate.
Then begind a loop where decrements 1 by 1 the vsel values and try to calibrate them.
After 14 iterations, my OB has locked up and I've to take out the battery.
Here are the results:
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
Smartreflex seems to have a very big interval around vsel to set the voltajes, because try to mantain the original calibrated voltaje (or a few lower) even with very low vsels. Also there are several times where SR fails to calibrate the voltaje and vsel = calib.
Looking at the table, I've seen a way to UV a bit our OB without problems. If we extract our actual calibrated voltajes and we decrement them only by 1, pushing them and recalibrating we obtain a bit lower recalibrated voltage that is what I'm looking for.
I'm going to create a script to try this method and give the possibility to set it on autoboot like nova script.
Regards.
Well, I've have a preliminary version of my script for test purpouses.
Assuming that the possible users will be power users, it isn't inside any flashable zip.
- Download it from here.
- Push it to phone.
- Move it to /system/xbin.
- Set its permissions to rwxr-xr-x (0755).
- Launch it at terminal typing first 'su' and then 'uv'.
This script will take your actual freq/volt config and will modify only the voltages, keeping your setled frequencies.
Please, post feedback into this post with the numerical results: freqs, actual voltages and new voltages, and if the config runs well.
Regards.
I've created another post for the uv script testing.
Then, use it to post your feedback, please.
http://forum.xda-developers.com/showthread.php?p=17213869#post17213869
Regards.
Smartreflex is a holy ****...
Well, I've probed by myself that smartreflex is a good system but is VERY LIMITED.
- Using stock frequencies with stock voltages (1000,800,600,300 and 60,56,45,32) I've obtained the following calibrated voltages (51,41,32,22).
- Using high frequencies with higher voltages (1200,1000,800,600 and 66,60,56,45) I've obtained the following calibrated voltages (51,41,32,22).
- Using ultralow frequencies with lower voltages (600,500,400,300 with 45,42,37,32) I've obtained the following calibrated voltages (49,41,32,22).
What class of **** is this stuff?
The smartreflex system calculates the same voltage whatever be the freqs! It's fixed to default freqs!!!!
I'm going to try deactivate smartreflex and test.
Regards!
More **** to come... I've tried to deactivate SR but I can't...
/sys/power/sr_vdd1_autocomp remains unchanged with value 1...
You can't disable it like that probably, it's already a working built-in kernel module.
I also can't seem to disable it in the kernel, too much entwined.
However, this isn't a problem since SmartReflex is actually a quite good feature on this chipset for power management.
In fact, we may even be ****ing up the battery by messing with it.
Some people report better battery on v4.5. Maybe that's because UV wasn't working.
Either way, for gingerbread it will be class 3 instead of froyo's class 1.5.
We can anticipate some improvements.
knzo said:
In fact, we may even be ****ing up the battery by messing with it.
Some people report better battery on v4.5. Maybe that's because UV wasn't working.
Click to expand...
Click to collapse
I don't think so... the situation it's the same IMHO because of the behaviour of SR... The drain must be in other part ejeje
knzo said:
Either way, for gingerbread it will be class 3 instead of froyo's class 1.5.
We can anticipate some improvements.
Click to expand...
Click to collapse
These are good news!
Huexxx said:
I don't think so... the situation it's the same IMHO because of the behaviour of SR... The drain must be in other part ejeje
Click to expand...
Click to collapse
SBT forces SR vsel to stay down.
Anyway I'll disable UV in next version.
SmartReflex is good enough.
Sent from my LG-P970 using XDA App
Related
How can I overclock GPU by 400MHz?I have heart about that the SGX540 may actually clocked at 400MHZ。http://forum.xda-developers.com/showthread.php?p=15107363
How to improve 3D performance ?How to get more than 5000 in antutu?
Does the below sript have any proplem?
#!/system/bin/sh
###
##
#
busybox cp /system/.nomedia /d/
busybox cp /system/.nomedia /data/
busybox cp /system/.nomedia /dbdata/
busybox cp /system/.nomedia /dev/
busybox cp /system/.nomedia /etc/
busybox cp /system/.nomedia /lib/
busybox cp /system/.nomedia /mnt/
busybox cp /system/.nomedia /sys/
insmod /lib/modules/deadline-iosched.ko
mmc=`ls -d /sys/block/mmc*`; stl=`ls -d /sys/block/stl*`
for a in $mmc $stl; do
echo deadline > $a/queue/scheduler
echo 8 > $a/queue/iosched/fifo_batch
echo 400 > $a/queue/iosched/read_expire
echo 4 > $a/queue/iosched/writes_starved
echo 0 > $a/queue/iostats
echo 4 > $a/queue/nr_requests
echo 0 > $i/queue/rotational
done
busybox sysctl -w kernel.sched_latency_ns="600000"
busybox sysctl -w kernel.sched_wakeup_granularity_ns="3000000"
#busybox sysctl -w kernel.sched_min_granularity_ns="1500000"
#echo "2048" > /proc/sys/kernel/msgmni;
#echo "64000" > /proc/sys/kernel/msgmax;
#echo "10" > /proc/sys/fs/lease-break-time;
#echo "NO_NORMALIZED_SLEEPER" > /sys/kernel/debug/sched_features
#echo "NO_FAIR_SLEEPERS" > /sys/kernel/debug/sched_features
#echo "NO_GENTLE_FAIR_SLEEPERS" > /sys/kernel/debug/sched_features
#echo "2000" > /proc/sys/vm/dirty_writeback_centisecs
#echo "1000" > /proc/sys/vm/dirty_expire_centisecs
echo "90" > /proc/sys/vm/dirty_ratio
echo "60" > /proc/sys/vm/dirty_background_ratio
echo "1" > /proc/sys/vm/vfs_cache_pressure
echo "0" > /proc/sys/vm/swappiness
echo 80 > /sys/devices/system/cpu/cpufreq/ondemand/up_threshold
echo "0" > /proc/sys/net/ipv4/tcp_timestamps;
echo "1" > /proc/sys/net/ipv4/tcp_tw_reuse;
echo "1" > /proc/sys/net/ipv4/tcp_sack;
echo "1" > /proc/sys/net/ipv4/tcp_tw_recycle;
echo "1" > /proc/sys/net/ipv4/tcp_window_scaling;
echo "5" > /proc/sys/net/ipv4/tcp_keepalive_probes;
echo "30" > /proc/sys/net/ipv4/tcp_keepalive_intvl;
echo "30" > /proc/sys/net/ipv4/tcp_fin_timeout;
echo "404480" > /proc/sys/net/core/wmem_max;
echo "404480" > /proc/sys/net/core/rmem_max;
echo "256960" > /proc/sys/net/core/rmem_default;
echo "256960" > /proc/sys/net/core/wmem_default;
echo "4096,16384,404480" > /proc/sys/net/ipv4/tcp_wmem;
setprop debug.sf.hw 1; # HARDWARE RENDERING (GPU)
setprop video.accelerate.hw 1;
setprop debug.performance.tuning 1;
if [ -e /sys/module/pm_hotplug/parameters/loadl ]; then
echo 40 > /sys/module/pm_hotplug/parameters/loadl;
echo 90 > /sys/module/pm_hotplug/parameters/loadh;
echo 50 > /sys/module/pm_hotplug/parameters/loadl_scroff;
echo 100 > /sys/module/pm_hotplug/parameters/loadh_scroff;
echo 200 > /sys/module/pm_hotplug/parameters/rate;
echo 800 > /sys/module/pm_hotplug/parameters/rate_cpuon;
echo 800 > /sys/module/pm_hotplug/parameters/rate_scroff;
echo 500000 > /sys/module/pm_hotplug/parameters/freq_cpu1on;
fi;
if [ -e /sys/devices/system/cpu/cpu0/cpufreq/smooth_target ]; then
echo 0 > /sys/devices/system/cpu/cpu0/cpufreq/smooth_target;
echo 0 > /sys/devices/system/cpu/cpu0/cpufreq/smooth_offset;
echo 0 > /sys/devices/system/cpu/cpu0/cpufreq/smooth_step;
fi;
if [ -e /sys/devices/system/cpu/sched_mc_power_savings ]; then
echo 1 > /sys/devices/system/cpu/sched_mc_power_savings;
fi;
if [ -e /sys/module/cpuidle/parameters/enable_mask ]; then
echo 3 > /sys/module/cpuidle/parameters/enable_mask;
fi;
if [ -e /sys/class/misc/brightness_curve/min_bl ]; then
echo 20 > /sys/class/misc/brightness_curve/min_bl;
echo 1 > /sys/class/misc/brightness_curve/min_gamma;
echo 24 > /sys/class/misc/brightness_curve/max_gamma;
fi;
#echo 4 > /sys/devices/system/cpu/cpu0/cpufreq/deepsleep_cpulevel;
#echo 1 > /sys/devices/system/cpu/cpu0/cpufreq/deepsleep_buslevel;
echo "1300000" > /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq
echo "0 0 0 0 0 0 0 " > /sys/devices/system/cpu/cpu0/cpufreq/UV_mV_table
echo "1 1 1 1 1 1 " > /sys/devices/system/cpu/cpu0/cpufreq/states_enabled_table
echo "300 400 300 400 300 400 300 300 267 267 200 100 " > /sys/devices/system/cpu/cpu0/cpufreq/gpu_clock_table
echo 85 > /sys/devices/system/cpu/cpufreq/ondemand/up_threshold
echo "500" > /proc/sys/vm/dirty_expire_centisecs
echo "1000" > /proc/sys/vm/dirty_writeback_centisecs
# CFS options moved elsewhere!
#if [ -e /proc/sys/kernel/rr_interval ];
#then
# BFS;
# echo 6 > /proc/sys/kernel/rr_interval;
# echo 75 > /proc/sys/kernel/iso_cpu;
#else
# CFS
# following 2 settings are to be handled with care - could lead to bootlooping phone or other issues if too low !
#echo 100000 > /proc/sys/kernel/sched_latency_ns; # 1000000 # 18000000 # 1000000 # 100000 ## new
#echo 500000 > /proc/sys/kernel/sched_wakeup_granularity_ns ; # 500000 # 3000000 # 25000 # 0 (?)
#echo 750000 > /proc/sys/kernel/sched_min_granularity_ns; # 1000000 # 1500000 # 100000 # 1000000 ## 750000 (upstream)
#echo 200000 > /proc/sys/kernel/sched_min_granularity_ns; # 1000000 # 1500000 # 100000 # 1000000 ## 750000 (upstream)
#echo 400000 > /proc/sys/kernel/sched_latency_ns; # 1000000 # 18000000 # 1000000 # 100000 ## new
#echo 100000 > /proc/sys/kernel/sched_wakeup_granularity_ns ; # 500000 # 3000000 # 25000 # 0 (?)
#echo -1 > /proc/sys/kernel/sched_rt_runtime_us;
#echo 100000 > /proc/sys/kernel/sched_rt_period_us;
#echo 95000 > /proc/sys/kernel/sched_rt_runtime_us; # default: 950000; very small values in sched_rt_runtime_us can result in an unstable system when the runtime is so small
# the system has difficulty making forward progress (the migration thread and kstopmachine both are real-time processes)
#fi;
insmod /lib/modules/deadline-iosched.ko
mmc=`ls -d /sys/block/mmc*`; stl=`ls -d /sys/block/stl*`; bml=`ls -d /sys/block/bml*`; tsfr=`ls -d /sys/block/tfsr*`;
for a in $mmc $stl $bml $tsfr; do
echo deadline > $a/queue/scheduler
echo 8 > $a/queue/iosched/fifo_batch
echo 400 > $a/queue/iosched/read_expire
echo 4 > $a/queue/iosched/writes_starved
echo 0 > $a/queue/iostats
echo 4 > $a/queue/nr_requests
echo 0 > $i/queue/rotational
done
#echo "2000" > /proc/sys/vm/dirty_writeback_centisecs
#echo "1000" > /proc/sys/vm/dirty_expire_centisecs
echo "90" > /proc/sys/vm/dirty_ratio
echo "55" > /proc/sys/vm/dirty_background_ratio
echo "1" > /proc/sys/vm/vfs_cache_pressure
echo "0" > /proc/sys/vm/swappiness
echo "0" > /proc/sys/net/ipv4/tcp_timestamps;
echo "1" > /proc/sys/net/ipv4/tcp_tw_reuse;
echo "1" > /proc/sys/net/ipv4/tcp_sack;
echo "1" > /proc/sys/net/ipv4/tcp_tw_recycle;
echo "1" > /proc/sys/net/ipv4/tcp_window_scaling;
echo "5" > /proc/sys/net/ipv4/tcp_keepalive_probes;
echo "30" > /proc/sys/net/ipv4/tcp_keepalive_intvl;
echo "30" > /proc/sys/net/ipv4/tcp_fin_timeout;
echo "404480" > /proc/sys/net/core/wmem_max;
echo "404480" > /proc/sys/net/core/rmem_max;
echo "256960" > /proc/sys/net/core/rmem_default;
echo "256960" > /proc/sys/net/core/wmem_default;
echo "4096,16384,404480" > /proc/sys/net/ipv4/tcp_wmem;
echo 1 > /sys/class/misc/backlightnotification/enabled
sync
echo 3 > /proc/sys/vm/drop_caches
setprop ro.ril.disable.power.collapse = 1
#MAX_PHONE()
#{
#pidphone=`pidof com.android.phone`;
#if [ $pidphone ]; # Wait for com.android.phone to start;
#then#
# echo -17 > /proc/$pidphone/oom_adj; # exclude com.android.phone from oom-killer;
# renice -20 $pidphone; # set highest nice level for com.android.phone;
## log -p i -t SSSwitch_v0.8 "*** MAX phone *** set oom_adj(-17) and nice(-20) for com.android.phone";
# exit;
#else
# sleep 5;
# MAX_PHONE;
#fi;
#}
echo 1 > /sys/class/misc/backlightnotification/enabled
sleep 10
sync
echo 3 > /proc/sys/vm/drop_caches
Sorry for my weak English。
In order to improve the sound ,I write a script.
as below,the script doesn't work.
Can you tell me,what's wrong in the script?
sorry from my bad English!
#!/system/bin/sh
# by liweichu
echo 1 > /sys/class/misc/voodoo_sound_control/enable
echo 1 > /sys/class/misc/voodoo_sound/headphone_eq
echo -10000 > /sys/class/misc/voodoo_sound/digital_gain
echo 50 > /sys/class/misc/voodoo_sound/headphone_amplifier_level
echo 1 > /sys/class/misc/voodoo_sound/fll_tuning
echo 1 > /sys/class/misc/voodoo_sound/dac_osr128
echo 1 > /sys/class/misc/voodoo_sound/adc_osr128
echo 1 > /sys/class/misc/voodoo_sound/dac_direct
echo 0 > /sys/class/misc/voodoo_sound/mono_downmix
echo 1 > /sys/class/misc/voodoo_sound/fm_radio_headset_normalize_gain
echo 1 > /sys/class/misc/voodoo_sound/fm_radio_headset_restore_bass
echo 1 > /sys/class/misc/voodoo_sound/fm_radio_headset_restore_highs
echo 10 > /sys/class/misc/voodoo_sound/headphone_eq_b1_gain
echo -2 > /sys/class/misc/voodoo_sound/headphone_eq_b2_gain
echo -9 > /sys/class/misc/voodoo_sound/headphone_eq_b3_gain
echo 4 > /sys/class/misc/voodoo_sound/headphone_eq_b4_gain
echo 8 > /sys/class/misc/voodoo_sound/headphone_eq_b5_gain
echo 1 > /sys/class/misc/voodoo_sound/recording_preset
Hi,
Looking for the web i found this tweaks for lg touch for nexus 4 ?
It will work with the lg optimus 4x HD (P880) ?
I have some issues with the touch accuracy..
Code:
####################################################################
# TOUCHSCREEN ACCURACY FILTER
####################################################################
if [ $TOUCH_TWEAK_EN = "y" ]
then
echo "Touch Control enable status *before* running the script"
cat /sys/devices/virtual/input/lge_touch/accuracy_filter_enable
#Turn on
echo "$touch_force_en" > /sys/devices/virtual/input/lge_touch/accuracy_filter_enable
#Adjust the params
echo 5 > /sys/devices/virtual/input/lge_touch/ignore_pressure_gap
echo 4 > /sys/devices/virtual/input/lge_touch/touch_max_count
echo 50 > /sys/devices/virtual/input/lge_touch/delta_max
echo 8 > /sys/devices/virtual/input/lge_touch/direction_count
echo 1 > /sys/devices/virtual/input/lge_touch/time_to_max_pressure
echo 55 > /sys/devices/virtual/input/lge_touch/max_pressure
echo "Touch Control enable status *after* running the script"
cat /sys/devices/virtual/input/lge_touch/accuracy_filter_enable
echo ""
fi # end of [ $TOUCH_TWEAK_EN = "y" ]
Web : http://www.veyka.co.uk/other/motley/91motleytweaks
Thanks!!
Won't work as the echoed files aren't in the directory it's trying to change
I think with a little file path change/ file name change it would work but I'm not that much into it
Sent from my LG Optimus 4X HD
These are different usb modes you can force from a adb shell (needs root)
This is just a fyi for information.
echo 1 > /sys/devices/virtual/android_usb/android0/f_diag/on
echo 1 > /sys/devices/virtual/android_usb/android0/f_diag_mdm/on
echo 1 > /sys/devices/virtual/android_usb/android0/f_rndis/on
echo 1 > /sys/devices/virtual/android_usb/android0/f_modem/on
echo 1 > /sys/devices/virtual/android_usb/android0/f_serial/on
echo 1 > /sys/devices/virtual/android_usb/android0/f_acm/on
echo 1 > /sys/devices/virtual/android_usb/android0/f_ccid/on
echo 1 > /sys/devices/virtual/android_usb/android0/f_accessory/on
echo 1 > /sys/devices/virtual/android_usb/android0/f_adb/on
echo 1 > /sys/devices/virtual/android_usb/android0/f_audio_source/on
echo 1 > /sys/devices/virtual/android_usb/android0/f_cdc_ethernet/on
echo 1 > /sys/devices/virtual/android_usb/android0/f_cdc_network/on
echo 1 > /sys/devices/virtual/android_usb/android0/f_mass_storage/on
echo 1 > /sys/devices/virtual/android_usb/android0/f_mtp/on
echo 1 > /sys/devices/virtual/android_usb/android0/f_projector/on
echo 1 > /sys/devices/virtual/android_usb/android0/f_projector2/on
echo 1 > /sys/devices/virtual/android_usb/android0/f_ptp/on
echo 1 > /sys/devices/virtual/android_usb/android0/f_rmnet/on
echo 1 > /sys/devices/virtual/android_usb/android0/f_rmnet_sdio/on
echo 1 > /sys/devices/virtual/android_usb/android0/f_rmnet_smd/on
echo 1 > /sys/devices/virtual/android_usb/android0/f_rmnet_smd_sdio/on
echo 1 > /sys/devices/virtual/android_usb/android0/f_rmnet/on
cdc_ether
Hi I am trying to connect a cdc_ether device into the LG Nexus5 usb port. I have cross compiled kernel for 3.4.0 hammerhead for this devices and enabled the cdc_ether module on it. But when I looked at the /sys/devices/virtual/android_usb/android0/f_cdc_ethernet/on, the f_cdc_ethernet directory doesnt exist. Does that mean the kernel was compiled wrong?
I try, through the Kernel Adjutor, to set the minimum frequency of the big / little cores, but they are reset. If I understand correctly, this is due to the "System Modes" setting in the "Battery" section. The maximum frequency can be lowered and maintained, but the minimum is reset each time. Is there a way to stop this behavior?
Probably not. Your only option is to use a custom ROM I think.
Solved with script
#!/system/bin/sh
until [ "$(getprop sys.boot_completed)" ]
do
sleep 2
done
echo "0:300000" > /sys/module/msm_performance/parameters/cpu_min_freq
echo "1:300000" > /sys/module/msm_performance/parameters/cpu_min_freq
echo "2:300000" > /sys/module/msm_performance/parameters/cpu_min_freq
echo "3:300000" > /sys/module/msm_performance/parameters/cpu_min_freq
echo "4:710400" > /sys/module/msm_performance/parameters/cpu_min_freq
echo "5:710400" > /sys/module/msm_performance/parameters/cpu_min_freq
echo "6:710400" > /sys/module/msm_performance/parameters/cpu_min_freq
echo "7:844000" > /sys/module/msm_performance/parameters/cpu_min_freq
chmod 444 /sys/module/msm_performance/parameters/cpu_min_freq