different input clock.

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

Note: This patch also does an off-topic change of making the JTAG id register
definition derive from SYSCFG base address.

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

diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c
index 4a43ae2..fe71f13 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>
 
@@ -35,6 +36,8 @@
 #define DA850_TIMER64P3_BASE	0x01f0d000
 
 #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,
@@ -230,14 +233,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,
 };
@@ -276,6 +279,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 = {
@@ -601,6 +606,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),
@@ -623,9 +687,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(DA8XX_CFGCHIP0_REG)) & ~BIT(4),
+			IO_ADDRESS(DA8XX_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(DA8XX_CFGCHIP3_REG)) | BIT(4),
+						IO_ADDRESS(DA8XX_CFGCHIP3_REG));
 }
diff --git a/arch/arm/mach-davinci/include/mach/da8xx.h b/arch/arm/mach-davinci/include/mach/da8xx.h
index a8cb570..41ab824 100644
--- a/arch/arm/mach-davinci/include/mach/da8xx.h
+++ b/arch/arm/mach-davinci/include/mach/da8xx.h
@@ -28,10 +28,12 @@
 #define DA8XX_CP_INTC_VIRT	(IO_VIRT - DA8XX_CP_INTC_SIZE - SZ_4K)
 
 #define DA8XX_BOOT_CFG_BASE	(IO_PHYS + 0x14000)
+#define DA8XX_JTAG_ID_REG	(DA8XX_BOOT_CFG_BASE + 0x18)
+#define DA8XX_CFGCHIP0_REG	(DA8XX_BOOT_CFG_BASE + 0x17c)
+#define DA8XX_CFGCHIP3_REG	(DA8XX_BOOT_CFG_BASE + 0x188)
 
 #define DA8XX_PSC0_BASE		0x01c10000
 #define DA8XX_PLL0_BASE		0x01c11000
-#define DA8XX_JTAG_ID_REG	0x01c14018
 #define DA8XX_TIMER64P0_BASE	0x01c20000
 #define DA8XX_TIMER64P1_BASE	0x01c21000
 #define DA8XX_GPIO_BASE		0x01e26000
