* [RFC] PoweOP, OMAP1 CpuFreq PowerOP integration 3/3
@ 2006-08-08 1:36 Eugeny S. Mints
0 siblings, 0 replies; only message in thread
From: Eugeny S. Mints @ 2006-08-08 1:36 UTC (permalink / raw)
To: linux-pm
[-- Attachment #1: Type: text/plain, Size: 337 bytes --]
A minimal example of modifying cpufreq to use PowerOP on OMAP1710.
cpufreq utilizes 2 power parameters out of 8 available on omap1 platform.
The are two patches attached. The patch order is :
mpu.clock.reference.count.fix.patch
omap1.cpufreq.powerop.patch
mpu.clock.reference.count.fix.patch is just a trivial fix for a
minor issue.
[-- Attachment #2: mpu.clock.reference.count.fix.patch --]
[-- Type: text/x-patch, Size: 619 bytes --]
diff --git a/arch/arm/plat-omap/cpu-omap.c b/arch/arm/plat-omap/cpu-omap.c
index a0c71dc..9c74729 100644
--- a/arch/arm/plat-omap/cpu-omap.c
+++ b/arch/arm/plat-omap/cpu-omap.c
@@ -101,12 +101,13 @@ static int __init omap_cpu_init(struct c
{
struct clk * mpu_clk;
+ if (policy->cpu != 0)
+ return -EINVAL;
+
mpu_clk = clk_get(NULL, MPU_CLK);
if (IS_ERR(mpu_clk))
return PTR_ERR(mpu_clk);
- if (policy->cpu != 0)
- return -EINVAL;
policy->cur = policy->min = policy->max = omap_getspeed(0);
policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
policy->cpuinfo.min_freq = clk_round_rate(mpu_clk, 0) / 1000;
[-- Attachment #3: omap1.cpufreq.powerop.patch --]
[-- Type: text/x-patch, Size: 5533 bytes --]
diff --git a/arch/arm/plat-omap/cpu-omap.c b/arch/arm/plat-omap/cpu-omap.c
index 9c74729..ca2061f 100644
--- a/arch/arm/plat-omap/cpu-omap.c
+++ b/arch/arm/plat-omap/cpu-omap.c
@@ -3,6 +3,8 @@
*
* CPU frequency scaling for OMAP
*
+ * PowerOP support by Eugeny S. Mints <eugeny.mints@gmail.com>
+ *
* Copyright (C) 2005 Nokia Corporation
* Written by Tony Lindgren <tony@atomide.com>
*
@@ -20,6 +22,7 @@ #include <linux/delay.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/clk.h>
+#include <linux/powerop.h>
#include <asm/hardware.h>
#include <asm/io.h>
@@ -33,42 +36,83 @@ #else
#define MPU_CLK "virt_prcm_set"
#endif
+
+static char *names[] = {"192", "96", "48", "24"};
+
+#define OP(khz, mv) \
+ { \
+ .frequency = khz, \
+ .index = mv \
+ }
+
+/*
+ * this is representation of operatin points on cpufreq layer: cpufreq
+ * knows and operates on only two power parameters (while an omap1 platform
+ * provides wider range of power parameters)
+ */
+static struct cpufreq_frequency_table opoints[] = {
+#ifdef CONFIG_OMAP_ARM_192MHZ
+ OP(192000, 1300),
+ OP(96000, 1300),
+ OP(48000, 1300),
+ OP(24000, 1300),
+ { .frequency = CPUFREQ_TABLE_END }
+#else
+#error "please choose OMAP 192MHZ option (exlusively)"
+#endif /* CONFIG_OMAP_ARM_192MHZ */
+};
+
+#define MAX_OP_INDEX (ARRAY_SIZE(opoints) - 2)
+
+/*
+ * returns index in opoint array of operating point with closest cpu rate
+ * which(rate) is <= requested rate or EINVAL
+ */
+static long
+round_max_rate(long rate)
+{
+ int i;
+ for (i = 0; i <= MAX_OP_INDEX; i++)
+ if (opoints[i].frequency <= rate)
+ return i;
+ return -EINVAL;
+}
+/*
+ * returns index in opoint array of operating point with closest cpu rate
+ * which(rate) is >= requested rate or EINVAL
+ */
+static long
+round_min_rate(long rate)
+{
+ int i;
+ for (i = MAX_OP_INDEX; i >= 0; i--)
+ if (opoints[i].frequency >= rate)
+ return i;
+ return -EINVAL;
+}
+#
+
/* TODO: Add support for SDRAM timing changes */
int omap_verify_speed(struct cpufreq_policy *policy)
{
- struct clk * mpu_clk;
-
if (policy->cpu)
return -EINVAL;
-
- cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
- policy->cpuinfo.max_freq);
- mpu_clk = clk_get(NULL, MPU_CLK);
- if (IS_ERR(mpu_clk))
- return PTR_ERR(mpu_clk);
- policy->min = clk_round_rate(mpu_clk, policy->min * 1000) / 1000;
- policy->max = clk_round_rate(mpu_clk, policy->max * 1000) / 1000;
+
cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
policy->cpuinfo.max_freq);
- clk_put(mpu_clk);
-
- return 0;
+ return cpufreq_frequency_table_verify(policy, opoints);
}
unsigned int omap_getspeed(unsigned int cpu)
{
- struct clk * mpu_clk;
unsigned long rate;
if (cpu)
return 0;
- mpu_clk = clk_get(NULL, MPU_CLK);
- if (IS_ERR(mpu_clk))
+ if (powerop_get_point(NULL, "cpu ", &rate))
return 0;
- rate = clk_get_rate(mpu_clk) / 1000;
- clk_put(mpu_clk);
return rate;
}
@@ -77,43 +121,57 @@ static int omap_target(struct cpufreq_po
unsigned int target_freq,
unsigned int relation)
{
- struct clk * mpu_clk;
struct cpufreq_freqs freqs;
int ret = 0;
+ unsigned int idx;
- mpu_clk = clk_get(NULL, MPU_CLK);
- if (IS_ERR(mpu_clk))
- return PTR_ERR(mpu_clk);
-
+ /*FIXME: check 0 as error */
freqs.old = omap_getspeed(0);
- freqs.new = clk_round_rate(mpu_clk, target_freq * 1000) / 1000;
+
+ /*
+ * doing w/o error checking since assuming ->target is called
+ * withing limits
+ */
+ if (relation == CPUFREQ_RELATION_L)
+ idx = round_min_rate(target_freq);
+ else if (relation == CPUFREQ_RELATION_H)
+ idx = round_max_rate(target_freq);
+ else
+ return -EINVAL;
+ freqs.new = opoints[idx].frequency;
freqs.cpu = 0;
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
- ret = clk_set_rate(mpu_clk, target_freq * 1000);
+
+ ret = powerop_set_point(names[idx]);
+
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
- clk_put(mpu_clk);
return ret;
}
static int __init omap_cpu_init(struct cpufreq_policy *policy)
{
- struct clk * mpu_clk;
-
if (policy->cpu != 0)
return -EINVAL;
- mpu_clk = clk_get(NULL, MPU_CLK);
- if (IS_ERR(mpu_clk))
- return PTR_ERR(mpu_clk);
-
policy->cur = policy->min = policy->max = omap_getspeed(0);
+
+ /* omap_getspeed returns 0 on error */
+ if (policy->cur == 0)
+ return -EIO;
+
policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
- policy->cpuinfo.min_freq = clk_round_rate(mpu_clk, 0) / 1000;
- policy->cpuinfo.max_freq = clk_round_rate(mpu_clk, VERY_HI_RATE) / 1000;
policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
- clk_put(mpu_clk);
+
+ /*
+ * FIXME: it's hardcoded for this example having the assumption that
+ * operating points in opoints array are sorted out in descending
+ * order. May be improved by fetching the values from the opoints
+ * array with necessary algo
+ */
+ policy->cpuinfo.min_freq = opoints[MAX_OP_INDEX].frequency;
+ policy->cpuinfo.max_freq = opoints[0].frequency;
return 0;
}
@@ -129,7 +187,19 @@ static struct cpufreq_driver omap_driver
static int __init omap_cpufreq_init(void)
{
+ int i = 0;
+ /*
+ * map cpufreq layer representation of power control to
+ * omap1 platform operating points
+ */
+ for (i = 0; i <=MAX_OP_INDEX; i++ )
+ if (powerop_register_point(names[i], "cpu_vltg cpu ",
+ opoints[i].index,
+ opoints[i].frequency))
+ return -EINVAL;
+
return cpufreq_register_driver(&omap_driver);
}
arch_initcall(omap_cpufreq_init);
+
[-- Attachment #4: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2006-08-08 1:36 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-08-08 1:36 [RFC] PoweOP, OMAP1 CpuFreq PowerOP integration 3/3 Eugeny S. Mints
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox