summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
authorVishwanath BS <vishwanath.bs@ti.com>2011-03-30 12:07:55 +0530
committerNicolas Pitre <nicolas.pitre@linaro.org>2011-04-01 23:02:59 -0400
commitdab3ad92582725092a8e530f94d7019e7dd5ae36 (patch)
treecc8be175240fe6270f61c4bcea7abe7b8003a2aa /arch
parentc9b60d24805b7b1b0a49551bb0646b866852c47a (diff)
OMAP: Introduce dependent voltage domain support
There could be dependencies between various voltage domains for maintaining system performance or hardware limitation reasons like VDD<X> should be at voltage v1 when VDD<Y> is at voltage v2. This patch introduce dependent vdd information structures in the voltage layer which can be used to populate these dependencies for a voltage domain. This patch also adds support to scale the dependent vdd and the scalable devices belonging to it during the scaling of a main vdd through omap_voltage_scale. As part of this, some of the voltage layer structure definitions are moved from voltage.c to voltage.h as it needs to be used in the dvfs layer for dependency voltage handling. Based on original patch from Thara. Signed-off-by: Vishwanath BS <vishwanath.bs@ti.com> Cc: Thara Gopinath <thara@ti.com>
Diffstat (limited to 'arch')
-rwxr-xr-xarch/arm/mach-omap2/dvfs.c87
-rw-r--r--arch/arm/plat-omap/include/plat/voltage.h110
2 files changed, 197 insertions, 0 deletions
diff --git a/arch/arm/mach-omap2/dvfs.c b/arch/arm/mach-omap2/dvfs.c
index 704c8fe5a68..6279f642444 100755
--- a/arch/arm/mach-omap2/dvfs.c
+++ b/arch/arm/mach-omap2/dvfs.c
@@ -84,6 +84,7 @@ struct omap_vdd_dvfs_info {
struct mutex scaling_mutex; /* dvfs mutex */
struct voltagedomain *voltdm;
struct list_head dev_list;
+ struct device vdd_device;
};
static struct omap_vdd_dvfs_info *omap_dvfs_info_list;
@@ -97,6 +98,7 @@ static struct voltagedomain omap3_vdd[] = {
.name = "core",
},
};
+static int omap_dvfs_voltage_scale(struct omap_vdd_dvfs_info *dvfs_info);
static int __init omap_dvfs_init(void);
@@ -411,6 +413,79 @@ static int omap_dvfs_remove_freq_request(struct omap_vdd_dvfs_info *dvfs_info,
return ret;
}
+/* Calculate dependency vdd voltage for given vdd voltage */
+static int calc_dep_vdd_volt(struct device *dev,
+ struct omap_vdd_info *main_vdd, unsigned long main_volt)
+{
+ struct omap_vdd_dep_info *dep_vdds;
+ int i, ret = 0;
+
+ if (!main_vdd->dep_vdd_info) {
+ pr_debug("%s: No dependent VDD's for vdd_%s\n",
+ __func__, main_vdd->voltdm.name);
+ return 0;
+ }
+
+ dep_vdds = main_vdd->dep_vdd_info;
+
+ for (i = 0; i < main_vdd->nr_dep_vdd; i++) {
+ struct omap_vdd_dep_volt *volt_table = dep_vdds[i].dep_table;
+ int nr_volt = 0;
+ unsigned long dep_volt = 0, act_volt = 0;
+
+ while (volt_table[nr_volt].main_vdd_volt != 0) {
+ if (volt_table[nr_volt].main_vdd_volt == main_volt) {
+ dep_volt = volt_table[nr_volt].dep_vdd_volt;
+ break;
+ }
+ nr_volt++;
+ }
+ if (!dep_volt) {
+ pr_warning("%s: Not able to find a matching volt for"
+ "vdd_%s corresponding to vdd_%s %ld volt\n",
+ __func__, dep_vdds[i].name,
+ main_vdd->voltdm.name, main_volt);
+ ret = -EINVAL;
+ continue;
+ }
+
+ if (!dep_vdds[i].voltdm)
+ dep_vdds[i].voltdm =
+ omap_voltage_domain_lookup(dep_vdds[i].name);
+
+ act_volt = dep_volt;
+
+ /* See if dep_volt is possible for the vdd*/
+ ret = omap_dvfs_add_vdd_user(get_dvfs_info(dep_vdds[i].voltdm),
+ dev, act_volt);
+ }
+
+ return ret;
+}
+
+/* Scale dependent VDD */
+static int scale_dep_vdd(struct omap_vdd_dvfs_info *vdd_info)
+{
+ struct omap_vdd_dep_info *dep_vdds;
+ int i;
+ struct omap_vdd_info *main_vdd;
+ struct voltagedomain *voltdm = vdd_info->voltdm;
+ main_vdd = container_of(voltdm, struct omap_vdd_info, voltdm);
+
+ if (!main_vdd->dep_vdd_info) {
+ pr_debug("%s: No dependent VDD's for vdd_%s\n",
+ __func__, main_vdd->voltdm.name);
+ return 0;
+ }
+
+ dep_vdds = main_vdd->dep_vdd_info;
+
+ for (i = 0; i < main_vdd->nr_dep_vdd; i++)
+ omap_dvfs_voltage_scale(get_dvfs_info(dep_vdds[i].voltdm));
+
+ return 0;
+}
+
/**
* omap_dvfs_voltage_scale() : API to scale the devices associated with a
* voltage domain vdd voltage.
@@ -434,6 +509,7 @@ static int omap_dvfs_voltage_scale(struct omap_vdd_dvfs_info *dvfs_info)
int ret = 0;
struct voltagedomain *voltdm;
unsigned long volt;
+ struct omap_vdd_info *vdd;
if (!dvfs_info || IS_ERR(dvfs_info)) {
pr_warning("%s: VDD specified does not exist!\n", __func__);
@@ -441,6 +517,7 @@ static int omap_dvfs_voltage_scale(struct omap_vdd_dvfs_info *dvfs_info)
}
voltdm = dvfs_info->voltdm;
+ vdd = container_of(voltdm, struct omap_vdd_info, voltdm);
mutex_lock(&dvfs_info->scaling_mutex);
@@ -493,6 +570,16 @@ static int omap_dvfs_voltage_scale(struct omap_vdd_dvfs_info *dvfs_info)
mutex_unlock(&dvfs_info->scaling_mutex);
+ /* calculate the voltages for dependent vdd's */
+ if (calc_dep_vdd_volt(&dvfs_info->vdd_device, vdd, volt)) {
+ pr_warning("%s: Error in calculating dependent vdd voltages"
+ "for vdd_%s\n", __func__, voltdm->name);
+ return -EINVAL;
+ }
+
+ /* Scale dependent vdds */
+ scale_dep_vdd(dvfs_info);
+
return 0;
}
diff --git a/arch/arm/plat-omap/include/plat/voltage.h b/arch/arm/plat-omap/include/plat/voltage.h
index e9f5408244e..6e2a69614d4 100644
--- a/arch/arm/plat-omap/include/plat/voltage.h
+++ b/arch/arm/plat-omap/include/plat/voltage.h
@@ -103,6 +103,114 @@ struct omap_volt_pmic_info {
u8 (*uv_to_vsel) (unsigned long uV);
};
+
+/* Voltage processor register offsets */
+struct vp_reg_offs {
+ u8 vpconfig;
+ u8 vstepmin;
+ u8 vstepmax;
+ u8 vlimitto;
+ u8 vstatus;
+ u8 voltage;
+};
+
+/* Voltage Processor bit field values, shifts and masks */
+struct vp_reg_val {
+ /* PRM module */
+ u16 prm_mod;
+ /* VPx_VPCONFIG */
+ u32 vpconfig_erroroffset;
+ u16 vpconfig_errorgain;
+ u32 vpconfig_errorgain_mask;
+ u8 vpconfig_errorgain_shift;
+ u32 vpconfig_initvoltage_mask;
+ u8 vpconfig_initvoltage_shift;
+ u32 vpconfig_timeouten;
+ u32 vpconfig_initvdd;
+ u32 vpconfig_forceupdate;
+ u32 vpconfig_vpenable;
+ /* VPx_VSTEPMIN */
+ u8 vstepmin_stepmin;
+ u16 vstepmin_smpswaittimemin;
+ u8 vstepmin_stepmin_shift;
+ u8 vstepmin_smpswaittimemin_shift;
+ /* VPx_VSTEPMAX */
+ u8 vstepmax_stepmax;
+ u16 vstepmax_smpswaittimemax;
+ u8 vstepmax_stepmax_shift;
+ u8 vstepmax_smpswaittimemax_shift;
+ /* VPx_VLIMITTO */
+ u8 vlimitto_vddmin;
+ u8 vlimitto_vddmax;
+ u16 vlimitto_timeout;
+ u8 vlimitto_vddmin_shift;
+ u8 vlimitto_vddmax_shift;
+ u8 vlimitto_timeout_shift;
+ /* PRM_IRQSTATUS*/
+ u32 tranxdone_status;
+};
+
+/* Voltage controller registers and offsets */
+struct vc_reg_info {
+ /* PRM module */
+ u16 prm_mod;
+ /* VC register offsets */
+ u8 smps_sa_reg;
+ u8 smps_volra_reg;
+ u8 bypass_val_reg;
+ u8 cmdval_reg;
+ u8 voltsetup_reg;
+ /*VC_SMPS_SA*/
+ u8 smps_sa_shift;
+ u32 smps_sa_mask;
+ /* VC_SMPS_VOL_RA */
+ u8 smps_volra_shift;
+ u32 smps_volra_mask;
+ /* VC_BYPASS_VAL */
+ u8 data_shift;
+ u8 slaveaddr_shift;
+ u8 regaddr_shift;
+ u32 valid;
+ /* VC_CMD_VAL */
+ u8 cmd_on_shift;
+ u8 cmd_onlp_shift;
+ u8 cmd_ret_shift;
+ u8 cmd_off_shift;
+ u32 cmd_on_mask;
+ /* PRM_VOLTSETUP */
+ u8 voltsetup_shift;
+ u32 voltsetup_mask;
+};
+
+
+/**
+ * omap_vdd_dep_volt - Table containing the parent vdd voltage and the
+ * dependent vdd voltage corresponding to it.
+ *
+ * @main_vdd_volt : The main vdd voltage
+ * @dep_vdd_volt : The voltage at which the dependent vdd should be
+ * when the main vdd is at <main_vdd_volt> voltage
+ */
+struct omap_vdd_dep_volt {
+ u32 main_vdd_volt;
+ u32 dep_vdd_volt;
+};
+
+/**
+ * omap_vdd_dep_info - Dependent vdd info
+ *
+ * @name : Dependent vdd name
+ * @voltdm : Dependent vdd pointer
+ * @dep_table : Table containing the dependent vdd voltage
+ * corresponding to every main vdd voltage.
+ */
+struct omap_vdd_dep_info {
+ char *name;
+ struct voltagedomain *voltdm;
+ struct omap_vdd_dep_volt *dep_table;
+};
+
+
/**
* omap_vdd_info - Per Voltage Domain info
*
@@ -130,6 +238,8 @@ struct omap_vdd_info {
struct omap_vc_instance_data *vc_data;
const struct omap_vfsm_instance_data *vfsm;
struct voltagedomain voltdm;
+ struct omap_vdd_dep_info *dep_vdd_info;
+ int nr_dep_vdd;
struct dentry *debug_dir;
u32 curr_volt;
bool vp_enabled;