diff options
author | Nishanth Menon <nm@ti.com> | 2011-02-13 21:27:30 +0530 |
---|---|---|
committer | Todd Poynor <toddpoynor@google.com> | 2011-11-30 15:26:41 -0800 |
commit | d3388088b3e0e96df70bc726ce875085b801cf8c (patch) | |
tree | 04408fedc1db0697326f9227b09ba53447689bbd | |
parent | 190f287f035885b34ff08b7e4c88d6c9c32d06d6 (diff) | |
download | kernel_samsung_tuna-d3388088b3e0e96df70bc726ce875085b801cf8c.zip kernel_samsung_tuna-d3388088b3e0e96df70bc726ce875085b801cf8c.tar.gz kernel_samsung_tuna-d3388088b3e0e96df70bc726ce875085b801cf8c.tar.bz2 |
OMAP3+: voltage: use volt_data pointer instead values
Voltage values can get confusing in meaning with various SmartReflex
classes being active. Depending on the class used, the actual voltage
selected might be a variant. For example:
With SmartReflex AVS class 3:
a) If we don't have SR enabled, we will go to volt_nominal.
b) If have SR enabled, we go to volt_nominal, then enable SR and
expect it to adjust voltage. We don't really care about the
resultant voltage.
Essentially, when we ask voltage layer to scale to voltage x for OPP
y, it always means x is the nominal voltage for OPP y.
Now, once we introduce SmartReflex AVS class 1.5:
a) If you are booting for the first time OR if you never enabled SR
before, we always go to volt_nominal.
b) If you enable SR and the OPP is calibrated, we will not enable SR
again when that OPP is accessed anymore, but when we set voltage for
an OPP, the voltage achieved will be volt_calibrated.
c) If recalibration timeout triggers or SR is disabled after a
calibration, the calibrated values are not valid anymore, at this point,
setting the voltage will mean volt_dynamic_nominal.
So, depending on which state the system is at, voltage for that OPP
we are setting has not 1 single value anymore, but 3 possible valid
values.
For upper layers(DVFS/cpufreq OMAP SoC layers) to use voltage values, it
will need to know which type of voltage AVS strategy is being used and
the corresponding system state from voltage layer perspective. This
would replicate the role of voltage layer, SmartReflex AVS in the upper
layers and make the corresponding implementations complex.
Since each voltage domain contains a set of volt_data structs representing
a voltage point that is supported for that domain, volt_data is a more
accurate representation of the voltage point we are interested in going to,
and the actual translation of this voltage point to the voltage value is
done inside the voltage layer. Doing this allows the users of the voltage
layer to be blissfully ignorant of any complexity of the underneath
layers and simplify the implementation of dependent layers.
As part of this change, omap_voltage_get_nom_volt has been renamed to
omap_voltage_get_curr_vdata to better represent it's behavior.
Change-Id: Idc171b6c64224c017280e0b29eb4ffb54f702194
Signed-off-by: Nishanth Menon <nm@ti.com>
-rw-r--r-- | arch/arm/mach-omap2/dvfs.c | 21 | ||||
-rw-r--r-- | arch/arm/mach-omap2/pm.c | 6 | ||||
-rw-r--r-- | arch/arm/mach-omap2/prm44xx.c | 1 | ||||
-rw-r--r-- | arch/arm/mach-omap2/smartreflex-class3.c | 6 | ||||
-rw-r--r-- | arch/arm/mach-omap2/vc.c | 9 | ||||
-rw-r--r-- | arch/arm/mach-omap2/vc.h | 3 | ||||
-rw-r--r-- | arch/arm/mach-omap2/voltage.c | 32 | ||||
-rw-r--r-- | arch/arm/mach-omap2/voltage.h | 20 | ||||
-rw-r--r-- | arch/arm/mach-omap2/vp.c | 19 | ||||
-rw-r--r-- | arch/arm/mach-omap2/vp.h | 2 |
10 files changed, 87 insertions, 32 deletions
diff --git a/arch/arm/mach-omap2/dvfs.c b/arch/arm/mach-omap2/dvfs.c index 953ed9b..4659e92 100644 --- a/arch/arm/mach-omap2/dvfs.c +++ b/arch/arm/mach-omap2/dvfs.c @@ -729,6 +729,8 @@ static int _dvfs_scale(struct device *req_dev, struct device *target_dev, int ret = 0; struct voltagedomain *voltdm; struct omap_vdd_info *vdd; + struct omap_volt_data *new_vdata; + struct omap_volt_data *curr_vdata; voltdm = tdvfs_info->voltdm; if (IS_ERR_OR_NULL(voltdm)) { @@ -741,9 +743,22 @@ static int _dvfs_scale(struct device *req_dev, struct device *target_dev, node = plist_last(&tdvfs_info->vdd_user_list); new_volt = node->prio; + new_vdata = omap_voltage_get_voltdata(voltdm, new_volt); + if (IS_ERR_OR_NULL(new_vdata)) { + pr_err("%s:%s: Bad New voltage data for %ld\n", + __func__, voltdm->name, new_volt); + return PTR_ERR(new_vdata); + } + new_volt = omap_get_operation_voltage(new_vdata); + curr_vdata = omap_voltage_get_curr_vdata(voltdm); + if (IS_ERR_OR_NULL(curr_vdata)) { + pr_err("%s:%s: Bad Current voltage data\n", + __func__, voltdm->name); + return PTR_ERR(curr_vdata); + } curr_volt = omap_vp_get_curr_volt(voltdm); if (!curr_volt) - curr_volt = omap_voltage_get_nom_volt(voltdm); + curr_volt = omap_get_operation_voltage(curr_vdata); /* Disable smartreflex module across voltage and frequency scaling */ omap_sr_disable(voltdm); @@ -760,7 +775,7 @@ static int _dvfs_scale(struct device *req_dev, struct device *target_dev, goto fail; } - ret = voltdm_scale(voltdm, new_volt); + ret = voltdm_scale(voltdm, new_vdata); if (ret) { dev_err(target_dev, "%s: Unable to scale the %s to %ld volt\n", @@ -817,7 +832,7 @@ static int _dvfs_scale(struct device *req_dev, struct device *target_dev, goto fail; if (DVFS_VOLT_SCALE_DOWN == volt_scale_dir) { - voltdm_scale(voltdm, new_volt); + voltdm_scale(voltdm, new_vdata); _dep_scale_domains(target_dev, vdd); } diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c index 9cba649..1afb2f6 100644 --- a/arch/arm/mach-omap2/pm.c +++ b/arch/arm/mach-omap2/pm.c @@ -370,7 +370,8 @@ static int __init omap2_set_init_voltage(char *vdd_name, char *clk_name, */ if (freq_cur < freq_valid) { - ret = voltdm_scale(voltdm, bootup_volt); + ret = voltdm_scale(voltdm, + omap_voltage_get_voltdata(voltdm, bootup_volt)); if (ret) { pr_err("%s: Fail set voltage-%s(f=%ld v=%ld)on vdd%s\n", __func__, vdd_name, freq_valid, @@ -391,7 +392,8 @@ static int __init omap2_set_init_voltage(char *vdd_name, char *clk_name, } if (freq_cur >= freq_valid) { - ret = voltdm_scale(voltdm, bootup_volt); + ret = voltdm_scale(voltdm, + omap_voltage_get_voltdata(voltdm, bootup_volt)); if (ret) { pr_err("%s: Fail set voltage-%s(f=%ld v=%ld)on vdd%s\n", __func__, clk_name, freq_valid, diff --git a/arch/arm/mach-omap2/prm44xx.c b/arch/arm/mach-omap2/prm44xx.c index ffc79ee4..6f011e0 100644 --- a/arch/arm/mach-omap2/prm44xx.c +++ b/arch/arm/mach-omap2/prm44xx.c @@ -21,6 +21,7 @@ #include <plat/cpu.h> #include <plat/prcm.h> +#include "voltage.h" #include "vp.h" #include "prm44xx.h" #include "prm-regbits-44xx.h" diff --git a/arch/arm/mach-omap2/smartreflex-class3.c b/arch/arm/mach-omap2/smartreflex-class3.c index 5bc7ef0..44be57a 100644 --- a/arch/arm/mach-omap2/smartreflex-class3.c +++ b/arch/arm/mach-omap2/smartreflex-class3.c @@ -15,13 +15,15 @@ static int sr_class3_enable(struct voltagedomain *voltdm) { - unsigned long volt = omap_voltage_get_nom_volt(voltdm); + struct omap_volt_data *v = omap_voltage_get_curr_vdata(voltdm); + unsigned long volt; - if (!volt) { + if (IS_ERR_OR_NULL(v)) { pr_warning("%s: Curr voltage unknown. Cannot enable sr_%s\n", __func__, voltdm->name); return -ENODATA; } + volt = omap_get_operation_voltage(v); omap_vp_enable(voltdm); return sr_enable(voltdm, volt); diff --git a/arch/arm/mach-omap2/vc.c b/arch/arm/mach-omap2/vc.c index cbf9a3b..162ee9f 100644 --- a/arch/arm/mach-omap2/vc.c +++ b/arch/arm/mach-omap2/vc.c @@ -197,6 +197,7 @@ int omap_vc_set_auto_trans(struct voltagedomain *voltdm, u8 flag) void omap_vc_post_scale(struct voltagedomain *voltdm, unsigned long target_volt, + struct omap_volt_data *target_vdata, u8 target_vsel, u8 current_vsel) { struct omap_vc_channel *vc; @@ -221,7 +222,7 @@ void omap_vc_post_scale(struct voltagedomain *voltdm, voltdm->pmic->slew_rate) + 2; udelay(smps_delay); - voltdm->curr_volt = target_volt; + voltdm->curr_volt = target_vdata; /* Set up the on voltage for wakeup from lp and OFF */ on_vsel = voltdm->pmic->uv_to_vsel(target_volt); @@ -281,11 +282,12 @@ static int omap_vc_bypass_send_value(struct voltagedomain *voltdm, /* vc_bypass_scale_voltage - VC bypass method of voltage scaling */ int omap_vc_bypass_scale_voltage(struct voltagedomain *voltdm, - unsigned long target_volt) + struct omap_volt_data *target_v) { struct omap_vc_channel *vc; u8 target_vsel, current_vsel; int ret; + unsigned long target_volt = omap_get_operation_voltage(target_v); if (IS_ERR_OR_NULL(voltdm)) { pr_err("%s bad voldm\n", __func__); @@ -308,7 +310,8 @@ int omap_vc_bypass_scale_voltage(struct voltagedomain *voltdm, if (ret) return ret; - omap_vc_post_scale(voltdm, target_volt, target_vsel, current_vsel); + omap_vc_post_scale(voltdm, target_volt, target_v, target_vsel, + current_vsel); return 0; } diff --git a/arch/arm/mach-omap2/vc.h b/arch/arm/mach-omap2/vc.h index a5f25fa..473375f 100644 --- a/arch/arm/mach-omap2/vc.h +++ b/arch/arm/mach-omap2/vc.h @@ -144,6 +144,7 @@ int omap_vc_pre_scale(struct voltagedomain *voltdm, u8 *target_vsel, u8 *current_vsel); void omap_vc_post_scale(struct voltagedomain *voltdm, unsigned long target_volt, + struct omap_volt_data *target_vdata, u8 target_vsel, u8 current_vsel); /* Auto transition flags for users */ @@ -155,7 +156,7 @@ void omap_vc_post_scale(struct voltagedomain *voltdm, #define OMAP_VC_CHANNEL_AUTO_TRANSITION_UNSUPPORTED 0xff int omap_vc_set_auto_trans(struct voltagedomain *voltdm, u8 flag); int omap_vc_bypass_scale_voltage(struct voltagedomain *voltdm, - unsigned long target_volt); + struct omap_volt_data *target_volt); int omap_vc_bypass_send_i2c_msg(struct voltagedomain *voltdm, u8 slave_addr, u8 reg_addr, u8 data); #endif diff --git a/arch/arm/mach-omap2/voltage.c b/arch/arm/mach-omap2/voltage.c index 57a153c..60fcdae 100644 --- a/arch/arm/mach-omap2/voltage.c +++ b/arch/arm/mach-omap2/voltage.c @@ -88,17 +88,16 @@ ovdc_out: /* Public functions */ /** - * omap_voltage_get_nom_volt() - Gets the current non-auto-compensated voltage + * omap_voltage_get_curr_vdata() - Gets the current voltage data * @voltdm: pointer to the VDD for which current voltage info is needed * - * API to get the current non-auto-compensated voltage for a VDD. - * Returns 0 in case of error else returns the current voltage for the VDD. + * API to get the current voltage data pointer for a VDD, returns NULL on error */ -unsigned long omap_voltage_get_nom_volt(struct voltagedomain *voltdm) +struct omap_volt_data *omap_voltage_get_curr_vdata(struct voltagedomain *voltdm) { if (!voltdm || IS_ERR(voltdm)) { pr_warning("%s: VDD specified does not exist!\n", __func__); - return 0; + return NULL; } return voltdm->curr_volt; @@ -113,10 +112,11 @@ unsigned long omap_voltage_get_nom_volt(struct voltagedomain *voltdm) * for a particular voltage domain during DVFS. */ int voltdm_scale(struct voltagedomain *voltdm, - unsigned long target_volt) + struct omap_volt_data *target_v) { int ret = 0; struct omap_voltage_notifier notify; + unsigned long target_volt = omap_get_operation_voltage(target_v); if (!voltdm || IS_ERR(voltdm)) { pr_warning("%s: VDD specified does not exist!\n", __func__); @@ -145,14 +145,15 @@ int voltdm_scale(struct voltagedomain *voltdm, } if (!ret) { - ret = voltdm->scale(voltdm, target_volt); + ret = voltdm->scale(voltdm, target_v); if (ret) pr_err("%s: voltage scale failed for vdd%s: %d\n", __func__, voltdm->name, ret); if (voltdm->abb) { - ret = omap_ldo_abb_post_scale(voltdm, - voltdm->curr_volt); + unsigned long cv; + cv = omap_get_operation_voltage(voltdm->curr_volt); + ret = omap_ldo_abb_post_scale(voltdm, cv); if (ret) pr_err("%s: ABB postscale fail for vdd%s:%d\n", __func__, voltdm->name, ret); @@ -179,14 +180,14 @@ int voltdm_scale(struct voltagedomain *voltdm, */ void voltdm_reset(struct voltagedomain *voltdm) { - unsigned long target_volt; + struct omap_volt_data *target_volt; if (!voltdm || IS_ERR(voltdm)) { pr_warning("%s: VDD specified does not exist!\n", __func__); return; } - target_volt = omap_voltage_get_nom_volt(voltdm); + target_volt = omap_voltage_get_curr_vdata(voltdm); if (!target_volt) { pr_err("%s: unable to find current voltage for vdd_%s\n", __func__, voltdm->name); @@ -339,13 +340,20 @@ DEFINE_SIMPLE_ATTRIBUTE(vp_volt_debug_fops, vp_volt_debug_get, NULL, "%llu\n"); static int nom_volt_debug_get(void *data, u64 *val) { struct voltagedomain *voltdm = (struct voltagedomain *) data; + struct omap_volt_data *vdata; if (!voltdm) { pr_warning("Wrong paramater passed\n"); return -EINVAL; } - *val = omap_voltage_get_nom_volt(voltdm); + vdata = omap_voltage_get_curr_vdata(voltdm); + if (IS_ERR_OR_NULL(vdata)) { + pr_warning("%s: unable to get volt for vdd_%s\n", + __func__, voltdm->name); + return -ENODEV; + } + *val = vdata->volt_nominal; return 0; } diff --git a/arch/arm/mach-omap2/voltage.h b/arch/arm/mach-omap2/voltage.h index 0a9f529..2931983 100644 --- a/arch/arm/mach-omap2/voltage.h +++ b/arch/arm/mach-omap2/voltage.h @@ -17,6 +17,8 @@ #include <linux/notifier.h> #include <linux/err.h> +struct omap_volt_data; + #include "vc.h" #include "vp.h" #include "ldo.h" @@ -90,8 +92,8 @@ struct voltagedomain { } sys_clk; int (*scale) (struct voltagedomain *voltdm, - unsigned long target_volt); - u32 curr_volt; + struct omap_volt_data *target_volt); + struct omap_volt_data *curr_volt; struct omap_vdd_info *vdd; struct srcu_notifier_head change_notify_list; @@ -266,7 +268,7 @@ void omap_voltage_get_volttable(struct voltagedomain *voltdm, struct omap_volt_data **volt_data); struct omap_volt_data *omap_voltage_get_voltdata(struct voltagedomain *voltdm, unsigned long volt); -unsigned long omap_voltage_get_nom_volt(struct voltagedomain *voltdm); +struct omap_volt_data *omap_voltage_get_curr_vdata(struct voltagedomain *voldm); #ifdef CONFIG_PM int omap_voltage_register_pmic(struct voltagedomain *voltdm, struct omap_voltdm_pmic *pmic); @@ -299,7 +301,8 @@ int voltdm_for_each(int (*fn)(struct voltagedomain *voltdm, void *user), int voltdm_for_each_pwrdm(struct voltagedomain *voltdm, int (*fn)(struct voltagedomain *voltdm, struct powerdomain *pwrdm)); -int voltdm_scale(struct voltagedomain *voltdm, unsigned long target_volt); +int voltdm_scale(struct voltagedomain *voltdm, + struct omap_volt_data *target_volt); void voltdm_reset(struct voltagedomain *voltdm); static inline int voltdm_register_notifier(struct voltagedomain *voltdm, @@ -314,4 +317,13 @@ static inline int voltdm_unregister_notifier(struct voltagedomain *voltdm, return srcu_notifier_chain_unregister(&voltdm->change_notify_list, nb); } +/* convert volt data to the voltage for the voltage data */ +static inline unsigned long omap_get_operation_voltage( + struct omap_volt_data *vdata) +{ + if (!vdata) + return 0; + return vdata->volt_nominal; +} + #endif diff --git a/arch/arm/mach-omap2/vp.c b/arch/arm/mach-omap2/vp.c index d3d9791..7ccf0a3 100644 --- a/arch/arm/mach-omap2/vp.c +++ b/arch/arm/mach-omap2/vp.c @@ -13,11 +13,17 @@ static void vp_latch_vsel(struct voltagedomain *voltdm) { struct omap_vp_instance *vp = voltdm->vp; + struct omap_volt_data *v = omap_voltage_get_curr_vdata(voltdm); u32 vpconfig; unsigned long uvdc; char vsel; - uvdc = omap_voltage_get_nom_volt(voltdm); + if (IS_ERR_OR_NULL(v)) { + pr_warning("%s: unable to get voltage for vdd_%s\n", + __func__, voltdm->name); + return; + } + uvdc = omap_get_operation_voltage(v); if (!uvdc) { pr_warning("%s: unable to find current voltage for vdd_%s\n", __func__, voltdm->name); @@ -106,8 +112,11 @@ int omap_vp_update_errorgain(struct voltagedomain *voltdm, /* Get volt_data corresponding to target_volt */ volt_data = omap_voltage_get_voltdata(voltdm, target_volt); - if (IS_ERR(volt_data)) + if (IS_ERR(volt_data)) { + pr_err("%s: vdm %s no voltage data for %ld\n", __func__, + voltdm->name, target_volt); return -EINVAL; + } /* Setting vp errorgain based on the voltage */ voltdm->rmw(voltdm->vp->common->vpconfig_errorgain_mask, @@ -143,12 +152,13 @@ static u8 __vp_recover_count = _MAX_RETRIES_BEFORE_RECOVER; /* VP force update method of voltage scaling */ int omap_vp_forceupdate_scale(struct voltagedomain *voltdm, - unsigned long target_volt) + struct omap_volt_data *target_v) { struct omap_vp_instance *vp = voltdm->vp; u32 vpconfig; u8 target_vsel, current_vsel; int ret, timeout = 0; + unsigned long target_volt = omap_get_operation_voltage(target_v); /* * Wait for VP idle Typical latency is <2us. Maximum latency is ~100us @@ -220,7 +230,8 @@ int omap_vp_forceupdate_scale(struct voltagedomain *voltdm, __func__, voltdm->name, target_volt, target_vsel, current_vsel); - omap_vc_post_scale(voltdm, target_volt, target_vsel, current_vsel); + omap_vc_post_scale(voltdm, target_volt, target_v, + target_vsel, current_vsel); /* * Disable TransactionDone interrupt , clear all status, clear diff --git a/arch/arm/mach-omap2/vp.h b/arch/arm/mach-omap2/vp.h index e5f65fd..c3a1e69 100644 --- a/arch/arm/mach-omap2/vp.h +++ b/arch/arm/mach-omap2/vp.h @@ -114,7 +114,7 @@ void omap_vp_enable(struct voltagedomain *voltdm); void omap_vp_disable(struct voltagedomain *voltdm); unsigned long omap_vp_get_curr_volt(struct voltagedomain *voltdm); int omap_vp_forceupdate_scale(struct voltagedomain *voltdm, - unsigned long target_volt); + struct omap_volt_data *target_v); int omap_vp_update_errorgain(struct voltagedomain *voltdm, unsigned long target_volt); |