diff mbox

[2/2] davinci: DA850/OMAP-L138: add cpufreq support

Message ID 1246886001-2285-2-git-send-email-nsekhar@ti.com (mailing list archive)
State Superseded
Headers show

Commit Message

Sekhar Nori July 6, 2009, 1:13 p.m. UTC
add basic cpufreq support for DA850/OMAP-L138

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

This patch also moves Async3 clock source to PLL1 so that frequency scaling
on PLL0 does not affect those peripherals. Without this the console on UART2
goes for a toss the moment CPUFreq kicks in.

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 boards appear with

Comments

Sergei Shtylyov July 6, 2009, 3:53 p.m. UTC | #1
Hello.

Sekhar Nori wrote:

> add basic cpufreq support for DA850/OMAP-L138

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

> This patch also moves Async3 clock source to PLL1 so that frequency scaling
> on PLL0 does not affect those peripherals. Without this the console on UART2
> goes for a toss the moment CPUFreq kicks in.

> 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 boards appear with
> different input clock.

> Tested with ondemand governer and a shell script to vary processor load.

> Signed-off-by: Sekhar Nori <nsekhar@ti.com>

> diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c
> index 274f004..7a3a376 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>
>  
> @@ -32,14 +33,20 @@
>  
>  #define DA850_PSC0_BASE		0x01c10000
>  #define DA850_PLL0_BASE		0x01c11000
> -#define DA850_JTAG_ID_REG	0x01c14018
>  #define DA850_TIMER64P0_BASE	0x01c20000
>  #define DA850_TIMER64P1_BASE	0x01c21000
>  #define DA850_GPIO_BASE		0x01e26000
>  #define DA850_PSC1_BASE		0x01e27000
>  #define DA850_PLL1_BASE		0x01e1a000

    Please don't duplicate these #define's which are not specific to DA850 
and are the same for DA830. Could you move them into soime header file 
instead -- probably <mach/hardware.h>?

> +#define DA850_SYSCFG_BASE	0x01c14000
> +#define DA850_CFGCHIP0_REG	(DA850_SYSCFG_BASE + 0x17c)
> +#define DA850_CFGCHIP3_REG	(DA850_SYSCFG_BASE + 0x188)
> +#define DA850_JTAG_ID_REG	(DA850_SYSCFG_BASE + 0x18)

    These registers are the same b/w DA830 and DA850.  Place them into some 
header file instead.
    Note that I'll also need CHIPCFG2 #define for the USB platfrom code.

WBR, Sergei
Sergei Shtylyov July 6, 2009, 3:56 p.m. UTC | #2
Hello, I wrote:

>> add basic cpufreq support for DA850/OMAP-L138

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

>> This patch also moves Async3 clock source to PLL1 so that frequency 
>> scaling
>> on PLL0 does not affect those peripherals. Without this the console on 
>> UART2
>> goes for a toss the moment CPUFreq kicks in.

>> 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 boards appear with
>> different input clock.

>> Tested with ondemand governer and a shell script to vary processor load.

>> Signed-off-by: Sekhar Nori <nsekhar@ti.com>

>> diff --git a/arch/arm/mach-davinci/da850.c 
>> b/arch/arm/mach-davinci/da850.c
>> index 274f004..7a3a376 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>

>> @@ -32,14 +33,20 @@

>>  #define DA850_PSC0_BASE        0x01c10000
>>  #define DA850_PLL0_BASE        0x01c11000
>> -#define DA850_JTAG_ID_REG    0x01c14018
>>  #define DA850_TIMER64P0_BASE    0x01c20000
>>  #define DA850_TIMER64P1_BASE    0x01c21000
>>  #define DA850_GPIO_BASE        0x01e26000
>>  #define DA850_PSC1_BASE        0x01e27000
>>  #define DA850_PLL1_BASE        0x01e1a000

>    Please don't duplicate these #define's which are not specific to 
> DA850 and are the same for DA830. Could you move them into soime header 
> file instead -- probably <mach/hardware.h>?

    No, actually there's <mach/da8xx.h> for exactly that purpose.

>> +#define DA850_SYSCFG_BASE    0x01c14000
>> +#define DA850_CFGCHIP0_REG    (DA850_SYSCFG_BASE + 0x17c)
>> +#define DA850_CFGCHIP3_REG    (DA850_SYSCFG_BASE + 0x188)
>> +#define DA850_JTAG_ID_REG    (DA850_SYSCFG_BASE + 0x18)

>    These registers are the same b/w DA830 and DA850.  Place them into 
> some header file instead.
>    Note that I'll also need CHIPCFG2 #define for the USB platfrom code.

WBR, Sergei
Rajashekhara, Sudhakar July 8, 2009, 11:44 a.m. UTC | #3
On Mon, Jul 06, 2009 at 21:23:47, Sergei Shtylyov wrote:
> Hello.
> 
> Sekhar Nori wrote:
> 
> > add basic cpufreq support for DA850/OMAP-L138
> 
> > Currently, frequency scaling only on PLL0 is supported. No scaling of PLL1
> > or voltage levels as yet.
> 
> > This patch also moves Async3 clock source to PLL1 so that frequency scaling
> > on PLL0 does not affect those peripherals. Without this the console on UART2
> > goes for a toss the moment CPUFreq kicks in.
> 
> > 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 boards appear with
> > different input clock.
> 
> > Tested with ondemand governer and a shell script to vary processor load.
> 
> > Signed-off-by: Sekhar Nori <nsekhar@ti.com>
> 
> > diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c
> > index 274f004..7a3a376 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>
> >  
> > @@ -32,14 +33,20 @@
> >  
> >  #define DA850_PSC0_BASE		0x01c10000
> >  #define DA850_PLL0_BASE		0x01c11000
> > -#define DA850_JTAG_ID_REG	0x01c14018
> >  #define DA850_TIMER64P0_BASE	0x01c20000
> >  #define DA850_TIMER64P1_BASE	0x01c21000
> >  #define DA850_GPIO_BASE		0x01e26000
> >  #define DA850_PSC1_BASE		0x01e27000
> >  #define DA850_PLL1_BASE		0x01e1a000
> 
>     Please don't duplicate these #define's which are not specific to DA850 
> and are the same for DA830. Could you move them into soime header file 
> instead -- probably <mach/hardware.h>?
> 

Sergei,
The above lines were added by my DA850/OMAP-L138 SoC and EVM patches.
I'll move them to mach/da8xx.h file when I submit my next version of
the patches.

Kevin,
Do you have any objections to moving these #defines to mach/da8xx.h file
as they'll be common across DA830/OMAP-L137 and DA850/OMAP-L138?

Regards,
Sudhakar
Kevin Hilman July 8, 2009, 1:29 p.m. UTC | #4
"Rajashekhara, Sudhakar" <sudhakar.raj@ti.com> writes:

> On Mon, Jul 06, 2009 at 21:23:47, Sergei Shtylyov wrote:
>> Hello.
>> 
>> Sekhar Nori wrote:
>> 
>> > add basic cpufreq support for DA850/OMAP-L138
>> 
>> > Currently, frequency scaling only on PLL0 is supported. No scaling of PLL1
>> > or voltage levels as yet.
>> 
>> > This patch also moves Async3 clock source to PLL1 so that frequency scaling
>> > on PLL0 does not affect those peripherals. Without this the console on UART2
>> > goes for a toss the moment CPUFreq kicks in.
>> 
>> > 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 boards appear with
>> > different input clock.
>> 
>> > Tested with ondemand governer and a shell script to vary processor load.
>> 
>> > Signed-off-by: Sekhar Nori <nsekhar@ti.com>
>> 
>> > diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c
>> > index 274f004..7a3a376 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>
>> >  
>> > @@ -32,14 +33,20 @@
>> >  
>> >  #define DA850_PSC0_BASE		0x01c10000
>> >  #define DA850_PLL0_BASE		0x01c11000
>> > -#define DA850_JTAG_ID_REG	0x01c14018
>> >  #define DA850_TIMER64P0_BASE	0x01c20000
>> >  #define DA850_TIMER64P1_BASE	0x01c21000
>> >  #define DA850_GPIO_BASE		0x01e26000
>> >  #define DA850_PSC1_BASE		0x01e27000
>> >  #define DA850_PLL1_BASE		0x01e1a000
>> 
>>     Please don't duplicate these #define's which are not specific to DA850 
>> and are the same for DA830. Could you move them into soime header file 
>> instead -- probably <mach/hardware.h>?
>> 
>
> Sergei,
> The above lines were added by my DA850/OMAP-L138 SoC and EVM patches.
> I'll move them to mach/da8xx.h file when I submit my next version of
> the patches.
>
> Kevin,
> Do you have any objections to moving these #defines to mach/da8xx.h file
> as they'll be common across DA830/OMAP-L137 and DA850/OMAP-L138?

I think that is a good idea.

Thanks,

Kevin
diff mbox

Patch

different input clock.

Tested with ondemand governer and a shell script to vary processor load.

Signed-off-by: Sekhar Nori <nsekhar@ti.com>
---
 arch/arm/mach-davinci/da850.c |  152 ++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 149 insertions(+), 3 deletions(-)

diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c
index 274f004..7a3a376 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>
 
@@ -32,14 +33,20 @@ 
 
 #define DA850_PSC0_BASE		0x01c10000
 #define DA850_PLL0_BASE		0x01c11000
-#define DA850_JTAG_ID_REG	0x01c14018
 #define DA850_TIMER64P0_BASE	0x01c20000
 #define DA850_TIMER64P1_BASE	0x01c21000
 #define DA850_GPIO_BASE		0x01e26000
 #define DA850_PSC1_BASE		0x01e27000
 #define DA850_PLL1_BASE		0x01e1a000
 
+#define DA850_SYSCFG_BASE	0x01c14000
+#define DA850_CFGCHIP0_REG	(DA850_SYSCFG_BASE + 0x17c)
+#define DA850_CFGCHIP3_REG	(DA850_SYSCFG_BASE + 0x188)
+#define DA850_JTAG_ID_REG	(DA850_SYSCFG_BASE + 0x18)
+
 #define DA850_REF_FREQ		24000000
+static int da850_set_armrate(struct clk *clk, unsigned long rate);
+static int da850_round_armrate(struct clk *clk, unsigned long rate);
 
 static struct pll_data pll0_data = {
 	.num		= 1,
@@ -235,14 +242,14 @@  static struct clk uart0_clk = {
 
 static struct clk uart1_clk = {
 	.name		= "uart1",
-	.parent		= &pll0_sysclk2,
+	.parent		= &pll1_sysclk2,
 	.lpsc		= DA8XX_LPSC1_UART1,
 	.psc_ctlr	= 1,
 };
 
 static struct clk uart2_clk = {
 	.name		= "uart2",
-	.parent		= &pll0_sysclk2,
+	.parent		= &pll1_sysclk2,
 	.lpsc		= DA8XX_LPSC1_UART2,
 	.psc_ctlr	= 1,
 };
@@ -281,6 +288,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 = {
@@ -600,6 +609,65 @@  static struct davinci_timer_info da850_timer_info = {
 	.clocksource_id	= T0_TOP,
 };
 
+#define MAX_NUM_OPP	3
+
+/*
+ * Notes:
+ * According to the TRM, minimum PLLM results in max 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[MAX_NUM_OPP+1] = {
+	OPP(300),
+	OPP(200),
+	OPP(96),
+	{
+		.index		= 0,
+		.frequency	= CPUFREQ_TABLE_END,
+	},
+};
+
+void da850_init_cpufreq_table(struct cpufreq_frequency_table **table)
+{
+	*table = &da850_freq_table[0];
+}
+
 static struct davinci_soc_info davinci_soc_info_da850 = {
 	.io_desc		= da850_io_desc,
 	.io_desc_num		= ARRAY_SIZE(da850_io_desc),
@@ -622,9 +690,87 @@  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,
 };
 
+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 rate)
+{
+	int i, ret;
+	unsigned int prediv, mult, postdiv;
+	struct da850_opp *opp;
+	struct clk *pllclk = &pll0_clk;
+	struct pll_data *pll = pllclk->pll_data;
+
+	/* convert to KHz */
+	rate /= 1000;
+
+	for (i = 0; da850_freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
+		if (rate == 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__, rate);
+		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 */
+	__raw_writel(__raw_readl(IO_ADDRESS(DA850_CFGCHIP0_REG)) & ~BIT(4),
+			IO_ADDRESS(DA850_CFGCHIP0_REG));
+
+	ret = davinci_set_pllrate(pll, prediv, mult, postdiv);
+	if (ret)
+		return ret;
+
+	/* Propogate new rate */
+	pllclk->rate = pllclk->parent->rate;
+	pllclk->rate /= prediv;
+	pllclk->rate *= mult;
+	pllclk->rate /= postdiv;
+
+	/* FIXME: unnecessarily re-calculates rates for PLL1 as well */
+	davinci_clk_recalc_rates(da850_clks);
+
+	return 0;
+}
+
 void __init da850_init(void)
 {
 	davinci_common_init(&davinci_soc_info_da850);
+
+	/*
+	 * set Async3 clock source to come from PLL1 so PLL0 frequency changes
+	 * dont affect as many peripherals as possible.
+	 * Note: This changes the clock source for UART1/2. So, low level debug
+	 * will garble beyond this point if the source rate changes.
+	 */
+	__raw_writel(__raw_readl(IO_ADDRESS(DA850_CFGCHIP3_REG)) | BIT(4),
+						IO_ADDRESS(DA850_CFGCHIP3_REG));
 }