diff mbox

[v4,10/10] davinci: DA850/OMAP-L138: add CPUFreq support

Message ID 1251713887-2824-10-git-send-email-nsekhar@ti.com (mailing list archive)
State Changes Requested
Headers show

Commit Message

Sekhar Nori Aug. 31, 2009, 10:18 a.m. UTC
Adds basic CPUFreq support for DA850/OMAP-L138.

Currently, frequency scaling only on PLL0 is supported. No scaling of PLL1
or voltage levels as yet.

Peripherals like MMC/SD which have a clock input synchronous with
ARM clock will not work well since the clock will change behind their backs.
Support for notification to such devices to adjust themselves to the
new frequency will be added in later patches. Current defconfigs keep
CPUFreq disabled so it will not affect normal operation.

The OPP defintions assume clock input of 24MHz to the SoC. This is inline
with hardcoding of input frequency in the <soc>.c files. At some point
this will need to move into board dependent code as new boards appear with
a different reference clock.

Tested on OMAP-L138 EVM with ondemand governer and a shell script to
vary processor load.

Boot tested on DA830, DM6446, DM6467, DM355 and DM365 EVMs.

Signed-off-by: Sekhar Nori <nsekhar@ti.com>
---
 arch/arm/mach-davinci/da850.c              |  157 ++++++++++++++++++++++++++++
 arch/arm/mach-davinci/include/mach/da8xx.h |    1 +
 2 files changed, 158 insertions(+), 0 deletions(-)

Comments

jameswhetstone@comcast.net Aug. 31, 2009, 7:12 p.m. UTC | #1
Does anyone know if there are plans to support framebuffer graphics rendering on the dm6467? 


TIA, 
James
Steve Chen Aug. 31, 2009, 7:22 p.m. UTC | #2
On Mon, 2009-08-31 at 19:12 +0000, jameswhetstone@comcast.net wrote:
> Does anyone know if there are plans to support framebuffer graphics
> rendering on the  dm6467?  

No support are planned... since dm6467 has no frame buffer hardware.

Regards,

Steve
jameswhetstone@comcast.net Aug. 31, 2009, 7:26 p.m. UTC | #3
Understood---thanks for your response. Unless I'm mistaken, most of the third party windowing frameworks like Microwindows and QT are all based on framebuffer architectures. What do you recommend, other than DMAI, for developing a user interface on the dm6467? 



Best Regards, 
James 

----- Original Message ----- 
From: "Steve Chen" <schen@mvista.com> 
To: jameswhetstone@comcast.net 
Cc: davinci-linux-open-source@linux.davincidsp.com 
Sent: Monday, August 31, 2009 12:22:37 PM GMT -08:00 US/Canada Pacific 
Subject: Re: Framebuffer support on dm6467 

On Mon, 2009-08-31 at 19:12 +0000, jameswhetstone@comcast.net wrote: 
> Does anyone know if there are plans to support framebuffer graphics 
> rendering on the dm6467? 

No support are planned... since dm6467 has no frame buffer hardware. 

Regards, 

Steve
Steve Chen Sept. 1, 2009, 11:35 a.m. UTC | #4
On Mon, 2009-08-31 at 19:26 +0000, jameswhetstone@comcast.net wrote:
> Understood---thanks for your response.   Unless I'm mistaken, most of
> the third party windowing frameworks like Microwindows and QT are all
> based on framebuffer architectures.  What do you recommend, other than
> DMAI, for developing a user interface on the  dm6467?
> 

I'm not familiar with this area, so I can not comment.  Hopefully,
experts on the mailing list can provide some inputs.

Regards,

Steve
diff mbox

Patch

diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c
index 2162b86..b1b590e 100644
--- a/arch/arm/mach-davinci/da850.c
+++ b/arch/arm/mach-davinci/da850.c
@@ -15,6 +15,7 @@ 
 #include <linux/init.h>
 #include <linux/clk.h>
 #include <linux/platform_device.h>
+#include <linux/cpufreq.h>
 
 #include <asm/mach/map.h>
 
@@ -40,6 +41,11 @@ 
 #define DA850_REF_FREQ		24000000
 
 #define CFGCHIP3_ASYNC3_CLKSRC	BIT(4)
+#define CFGCHIP0_PLL_MASTER_LOCK	BIT(4)
+
+static int da850_set_armrate(struct clk *clk, unsigned long rate);
+static int da850_round_armrate(struct clk *clk, unsigned long rate);
+static int da850_set_pll0rate(struct clk *clk, unsigned long armrate);
 
 static struct pll_data pll0_data = {
 	.num		= 1,
@@ -57,6 +63,7 @@  static struct clk pll0_clk = {
 	.parent		= &ref_clk,
 	.pll_data	= &pll0_data,
 	.flags		= CLK_PLL,
+	.set_rate	= da850_set_pll0rate,
 };
 
 static struct clk pll0_aux_clk = {
@@ -283,6 +290,8 @@  static struct clk arm_clk = {
 	.parent		= &pll0_sysclk6,
 	.lpsc		= DA8XX_LPSC0_ARM,
 	.flags		= ALWAYS_ENABLED,
+	.set_rate	= da850_set_armrate,
+	.round_rate	= da850_round_armrate,
 };
 
 static struct clk rmii_clk = {
@@ -821,6 +830,153 @@  static void da850_set_async3_src(int pllnum)
 	__raw_writel(v, DA8XX_SYSCFG_VIRT(DA8XX_CFGCHIP3_REG));
 }
 
+#ifdef CONFIG_CPU_FREQ
+/*
+ * Notes:
+ * According to the TRM, minimum PLLM results in maximum power savings.
+ * The OPP definitions below should keep the PLLM as low as possible.
+ *
+ * The output of the PLLM must be between 400 to 600 MHz.
+ * This rules out prediv of anything but divide-by-one for 24Mhz OSC input.
+ */
+struct da850_opp {
+	unsigned int	freq;	/* in KHz */
+	unsigned int	prediv;
+	unsigned int	mult;
+	unsigned int	postdiv;
+};
+
+static const struct da850_opp da850_opp_300 = {
+	.freq		= 300000,
+	.prediv		= 1,
+	.mult		= 25,
+	.postdiv	= 2,
+};
+
+static const struct da850_opp da850_opp_200 = {
+	.freq		= 200000,
+	.prediv		= 1,
+	.mult		= 25,
+	.postdiv	= 3,
+};
+
+static const struct da850_opp da850_opp_96 = {
+	.freq		= 96000,
+	.prediv		= 1,
+	.mult		= 20,
+	.postdiv	= 5,
+};
+
+#define OPP(freq) 		\
+	{				\
+		.index = (unsigned int) &da850_opp_##freq,	\
+		.frequency = freq * 1000, \
+	}
+
+static struct cpufreq_frequency_table da850_freq_table[] = {
+	OPP(300),
+	OPP(200),
+	OPP(96),
+	{
+		.index		= 0,
+		.frequency	= CPUFREQ_TABLE_END,
+	},
+};
+
+static void da850_init_cpufreq_table(struct cpufreq_frequency_table **table)
+{
+	*table = &da850_freq_table[0];
+}
+
+static int da850_round_armrate(struct clk *clk, unsigned long rate)
+{
+	int i, ret = 0, diff;
+	unsigned int best = (unsigned int) -1;
+
+	rate /= 1000; /* convert to kHz */
+
+	for (i = 0; da850_freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
+		diff = da850_freq_table[i].frequency - rate;
+		if (diff < 0)
+			diff = -diff;
+
+		if (diff < best) {
+			best = diff;
+			ret = da850_freq_table[i].frequency;
+		}
+	}
+
+	return ret * 1000;
+}
+
+static int da850_set_armrate(struct clk *clk, unsigned long armrate)
+{
+	struct clk *pllclk = &pll0_clk;
+
+	return clk_set_rate(pllclk, armrate);
+}
+
+static int da850_set_pll0rate(struct clk *clk, unsigned long armrate)
+{
+	int i;
+	unsigned int prediv, mult, postdiv;
+	struct da850_opp *opp;
+	struct pll_data *pll = clk->pll_data;
+	unsigned int v;
+	int ret;
+
+	/* convert to KHz */
+	armrate /= 1000;
+
+	for (i = 0; da850_freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
+		if (armrate == da850_freq_table[i].frequency)
+			break;
+	}
+
+	if (da850_freq_table[i].frequency == CPUFREQ_TABLE_END) {
+		printk(KERN_WARNING "%s: Unsupported ARM clock rate %ld\n",
+							__func__, armrate);
+		return -EINVAL;
+	}
+
+	opp = (struct da850_opp *) da850_freq_table[i].index;
+	prediv = opp->prediv;
+	mult = opp->mult;
+	postdiv = opp->postdiv;
+
+	/* Unlock writing to PLL registers */
+	v = __raw_readl(DA8XX_SYSCFG_VIRT(DA8XX_CFGCHIP0_REG));
+	v &= ~CFGCHIP0_PLL_MASTER_LOCK;
+	__raw_writel(v, DA8XX_SYSCFG_VIRT(DA8XX_CFGCHIP0_REG));
+
+	ret = davinci_set_pllrate(pll, prediv, mult, postdiv);
+	if (WARN_ON(ret))
+		return ret;
+
+	return 0;
+}
+#else
+static void da850_init_cpufreq_table(struct cpufreq_frequency_table **table)
+{
+	*table = NULL;
+}
+
+static int da850_set_armrate(struct clk *clk, unsigned long rate)
+{
+	return -EINVAL;
+}
+
+static int da850_set_pll0rate(struct clk *clk, unsigned long armrate)
+{
+	return -EINVAL;
+}
+
+static int da850_round_armrate(struct clk *clk, unsigned long rate)
+{
+	return clk->rate;
+}
+#endif
+
 static struct davinci_soc_info davinci_soc_info_da850 = {
 	.io_desc		= da850_io_desc,
 	.io_desc_num		= ARRAY_SIZE(da850_io_desc),
@@ -841,6 +997,7 @@  static struct davinci_soc_info davinci_soc_info_da850 = {
 	.gpio_irq		= IRQ_DA8XX_GPIO0,
 	.serial_dev		= &da8xx_serial_device,
 	.emac_pdata		= &da8xx_emac_pdata,
+	.init_cpufreq_table	= da850_init_cpufreq_table,
 };
 
 void __init da850_init(void)
diff --git a/arch/arm/mach-davinci/include/mach/da8xx.h b/arch/arm/mach-davinci/include/mach/da8xx.h
index 325c15e..bc98a92 100644
--- a/arch/arm/mach-davinci/include/mach/da8xx.h
+++ b/arch/arm/mach-davinci/include/mach/da8xx.h
@@ -34,6 +34,7 @@  extern void __iomem *da8xx_syscfg_base;
 #define DA8XX_SYSCFG_BASE	(IO_PHYS + 0x14000)
 #define DA8XX_SYSCFG_VIRT(x)	(da8xx_syscfg_base + (x))
 #define DA8XX_JTAG_ID_REG	0x18
+#define DA8XX_CFGCHIP0_REG	0x17c
 #define DA8XX_CFGCHIP3_REG	0x188
 
 #define DA8XX_PSC0_BASE		0x01c10000