summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra/tegra_cl_dvfs.c
diff options
context:
space:
mode:
authorAlex Frid <afrid@nvidia.com>2013-07-09 18:53:06 -0700
committerDan Willemsen <dwillemsen@nvidia.com>2013-09-14 13:32:54 -0700
commit824999ffa32a8aee3301cf78ac411ff07e351d2b (patch)
tree61bd6395f644566acf09d6b826936af9527dcf42 /arch/arm/mach-tegra/tegra_cl_dvfs.c
parent4a5d228ee980592dd9a0b70cafd8c1a9847c45e9 (diff)
ARM: tegra: dvfs: Modify cl-dvfs monitor control
- Dropped concept of "default monitor selection" (was - frequency). Explicitly select monitor mux each time data is read. - Restricted monitor debugfs node to frequency only (removed the option to read other possible outputs - this is still available via debugfs access to CL-DVFS registers) - Added output_mv debugfs node to read last output value Change-Id: Idca7500279d8c035e1f38ff99dd486ca79a3419d Signed-off-by: Alex Frid <afrid@nvidia.com> Reviewed-on: http://git-master/r/251605 Reviewed-by: Yu-Huan Hsu <yhsu@nvidia.com>
Diffstat (limited to 'arch/arm/mach-tegra/tegra_cl_dvfs.c')
-rw-r--r--arch/arm/mach-tegra/tegra_cl_dvfs.c69
1 files changed, 44 insertions, 25 deletions
diff --git a/arch/arm/mach-tegra/tegra_cl_dvfs.c b/arch/arm/mach-tegra/tegra_cl_dvfs.c
index 00d35a915416..e04c2c1cef4b 100644
--- a/arch/arm/mach-tegra/tegra_cl_dvfs.c
+++ b/arch/arm/mach-tegra/tegra_cl_dvfs.c
@@ -256,6 +256,14 @@ static inline void cl_dvfs_wmb(struct tegra_cl_dvfs *cld)
cl_dvfs_readl(cld, CL_DVFS_CTRL);
}
+static inline void switch_monitor(struct tegra_cl_dvfs *cld, u32 selector)
+{
+ /* delay to make sure selector has switched */
+ cl_dvfs_writel(cld, selector, CL_DVFS_MONITOR_CTRL);
+ cl_dvfs_wmb(cld);
+ udelay(1);
+}
+
static inline void invalidate_request(struct tegra_cl_dvfs *cld)
{
u32 val = cl_dvfs_readl(cld, CL_DVFS_FREQ_REQ);
@@ -662,12 +670,8 @@ static void cl_dvfs_calibrate(struct tegra_cl_dvfs *cld)
return;
cld->last_calibration = now;
- if (cl_dvfs_readl(cld, CL_DVFS_MONITOR_CTRL) !=
- CL_DVFS_MONITOR_CTRL_FREQ)
- cl_dvfs_writel(cld, CL_DVFS_MONITOR_CTRL_FREQ,
- CL_DVFS_MONITOR_CTRL);
-
/* Synchronize with sample period, and get rate measurements */
+ switch_monitor(cld, CL_DVFS_MONITOR_CTRL_FREQ);
data = cl_dvfs_readl(cld, CL_DVFS_MONITOR_DATA);
do {
data = cl_dvfs_readl(cld, CL_DVFS_MONITOR_DATA);
@@ -684,14 +688,10 @@ static void cl_dvfs_calibrate(struct tegra_cl_dvfs *cld)
return;
}
} else {
- /* Get last output, then restore default frequency monitoring */
- cl_dvfs_writel(cld, CL_DVFS_MONITOR_CTRL_OUT,
- CL_DVFS_MONITOR_CTRL);
- cl_dvfs_wmb(cld);
+ /* Get last output (there is no such thing as pending PWM) */
+ switch_monitor(cld, CL_DVFS_MONITOR_CTRL_OUT);
val = cl_dvfs_readl(cld, CL_DVFS_MONITOR_DATA) &
CL_DVFS_MONITOR_DATA_MASK;
- cl_dvfs_writel(cld, CL_DVFS_MONITOR_CTRL_FREQ,
- CL_DVFS_MONITOR_CTRL);
}
/* Adjust minimum rate */
@@ -1778,30 +1778,45 @@ static int monitor_get(void *data, u64 *val)
struct tegra_cl_dvfs *cld = ((struct clk *)data)->u.dfll.cl_dvfs;
clk_enable(cld->soc_clk);
-
clk_lock_save(c, &flags);
+
+ switch_monitor(cld, CL_DVFS_MONITOR_CTRL_FREQ);
+
v = cl_dvfs_readl(cld, CL_DVFS_MONITOR_DATA) &
CL_DVFS_MONITOR_DATA_MASK;
+ v = GET_MONITORED_RATE(v, cld->ref_rate);
+ s = cl_dvfs_readl(cld, CL_DVFS_FREQ_REQ);
+ s = (s & CL_DVFS_FREQ_REQ_SCALE_MASK) >> CL_DVFS_FREQ_REQ_SCALE_SHIFT;
+ *val = (u64)v * (s + 1) / 256;
- if (cl_dvfs_readl(cld, CL_DVFS_MONITOR_CTRL) ==
- CL_DVFS_MONITOR_CTRL_FREQ) {
- v = GET_MONITORED_RATE(v, cld->ref_rate);
- s = cl_dvfs_readl(cld, CL_DVFS_FREQ_REQ);
- s = (s & CL_DVFS_FREQ_REQ_SCALE_MASK) >>
- CL_DVFS_FREQ_REQ_SCALE_SHIFT;
- *val = (u64)v * (s + 1) / 256;
+ clk_unlock_restore(c, &flags);
+ clk_disable(cld->soc_clk);
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(monitor_fops, monitor_get, NULL, "%llu\n");
- clk_unlock_restore(c, &flags);
- clk_disable(cld->soc_clk);
- return 0;
- }
- *val = v;
+static int output_get(void *data, u64 *val)
+{
+ u32 v;
+ unsigned long flags;
+ struct clk *c = (struct clk *)data;
+ struct tegra_cl_dvfs *cld = ((struct clk *)data)->u.dfll.cl_dvfs;
+
+ clk_enable(cld->soc_clk);
+ clk_lock_save(c, &flags);
+
+ switch_monitor(cld, CL_DVFS_MONITOR_CTRL_OUT);
+
+ v = cl_dvfs_readl(cld, CL_DVFS_MONITOR_DATA) &
+ CL_DVFS_MONITOR_DATA_MASK;
+ *val = is_i2c(cld) ? cld->out_map[v]->reg_uV / 1000 :
+ cld->p_data->vdd_map[v].reg_uV / 1000;
clk_unlock_restore(c, &flags);
clk_disable(cld->soc_clk);
return 0;
}
-DEFINE_SIMPLE_ATTRIBUTE(monitor_fops, monitor_get, NULL, "%llu\n");
+DEFINE_SIMPLE_ATTRIBUTE(output_fops, output_get, NULL, "%llu\n");
static int vmax_get(void *data, u64 *val)
{
@@ -2042,6 +2057,10 @@ int __init tegra_cl_dvfs_debug_init(struct clk *dfll_clk)
cl_dvfs_dentry, dfll_clk, &monitor_fops))
goto err_out;
+ if (!debugfs_create_file("output_mv", S_IRUGO,
+ cl_dvfs_dentry, dfll_clk, &output_fops))
+ goto err_out;
+
if (!debugfs_create_file("vmax_mv", S_IRUGO,
cl_dvfs_dentry, dfll_clk, &vmax_fops))
goto err_out;