--- a/arch/arm/mach-omap/Kconfig	2005-05-06 11:27:58.000000000 -0700
+++ b/arch/arm/mach-omap/Kconfig	2005-05-06 11:27:26.000000000 -0700
@@ -21,6 +21,19 @@
 
 comment "OMAP Feature Selections"
 
+config OMAP_RESET_CLOCKS
+	bool "Reset unused clocks during boot"
+	depends on ARCH_OMAP
+	default n
+	help
+	  Say Y if you want to reset unused clocks during boot.
+	  This option saves power, but assumes all drivers are
+	  using the clock framework. Broken drivers that do not
+	  yet use clock framework may not work with this option.
+	  If you are booting from another operating system, you
+	  probably do not want this option enabled until your
+	  device drivers work properly.
+
 config OMAP_MUX
 	bool "OMAP multiplexing support"
         depends on ARCH_OMAP
diff -Nru a/arch/arm/mach-omap/clock.c b/arch/arm/mach-omap/clock.c
--- a/arch/arm/mach-omap/clock.c	2005-05-04 11:13:52 -07:00
+++ b/arch/arm/mach-omap/clock.c	2005-05-04 11:13:53 -07:00
@@ -25,6 +25,8 @@
 static DECLARE_MUTEX(clocks_sem);
 static DEFINE_SPINLOCK(clockfw_lock);
 static void propagate_rate(struct clk *  clk);
+/* UART clock function */
+static int set_uart_rate(struct clk * clk, unsigned long rate);
 /* External clock (MCLK & BCLK) functions */
 static int set_ext_clk_rate(struct clk *  clk, unsigned long rate);
 static long round_ext_clk_rate(struct clk *  clk, unsigned long rate);
@@ -34,7 +36,7 @@
 static long round_to_table_rate(struct clk *  clk, unsigned long rate);
 void clk_setdpll(__u16, __u16);
 
-struct mpu_rate rate_table[] = {
+static struct mpu_rate rate_table[] = {
 	/* MPU MHz, xtal MHz, dpll1 MHz, CKCTL, DPLL_CTL
 	 * armdiv, dspdiv, dspmmu, tcdiv, perdiv, lcddiv
 	 */
@@ -58,7 +60,7 @@
 	{ 168000000, 12000000, 168000000, 0x010f, 0x2710 }, /* 1/1/1/2/8/8 */
 #endif
 #if defined(CONFIG_OMAP_ARM_150MHZ)
-	{ 150000000, 12000000, 150000000, 0x150a, 0x2cb0 }, /* 0/0/1/1/2/2 */
+	{ 150000000, 12000000, 150000000, 0x010a, 0x2cb0 }, /* 1/1/1/2/4/4 */
 #endif
 #if defined(CONFIG_OMAP_ARM_120MHZ)
 	{ 120000000, 12000000, 120000000, 0x010a, 0x2510 }, /* 1/1/1/2/4/4 */
@@ -76,19 +78,11 @@
 };
 
 
-static void ckctl_recalc(struct clk *  clk)
-{
-	int dsor;
-
-	/* Calculate divisor encoded as 2-bit exponent */
-	dsor = 1 << (3 & (omap_readw(ARM_CKCTL) >> clk->rate_offset));
-	if (unlikely(clk->rate == clk->parent->rate / dsor))
-		return; /* No change, quick exit */
-	clk->rate = clk->parent->rate / dsor;
-
-	if (unlikely(clk->flags & RATE_PROPAGATES))
-		propagate_rate(clk);
-}
+static void ckctl_recalc(struct clk *  clk);
+int __clk_enable(struct clk *clk);
+void __clk_disable(struct clk *clk);
+void __clk_unuse(struct clk *clk);
+int __clk_use(struct clk *clk);
 
 
 static void followparent_recalc(struct clk *  clk)
@@ -102,6 +96,14 @@
 	clk->rate = clk->parent->rate / 14;
 }
 
+static void uart_recalc(struct clk * clk)
+{
+	unsigned int val = omap_readl(clk->enable_reg);
+	if (val & clk->enable_bit)
+		clk->rate = 48000000;
+	else
+		clk->rate = 12000000;
+}
 
 static struct clk ck_ref = {
 	.name		= "ck_ref",
@@ -185,7 +187,7 @@
 static struct clk arminth_ck16xx = {
 	.name		= "arminth_ck",
 	.parent		= &arm_ck,
-	.flags		= CLOCK_IN_OMAP16XX,
+	.flags		= CLOCK_IN_OMAP16XX | ALWAYS_ENABLED,
 	.recalc		= &followparent_recalc,
 	/* Note: On 16xx the frequency can be divided by 2 by programming
 	 * ARM_CKCTL:ARM_INTHCK_SEL(14) to 1
@@ -214,6 +216,38 @@
 	.recalc		= &ckctl_recalc,
 };
 
+static struct clk dspper_ck = {
+	.name		= "dspper_ck",
+	.parent		= &ck_dpll1,
+	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+			  RATE_CKCTL | DSP_DOMAIN_CLOCK,
+	.enable_reg	= DSP_IDLECT2,
+	.enable_bit	= EN_PERCK,
+	.rate_offset	= CKCTL_PERDIV_OFFSET,
+	.recalc		= &followparent_recalc,
+	//.recalc		= &ckctl_recalc,
+};
+
+static struct clk dspxor_ck = {
+	.name		= "dspxor_ck",
+	.parent		= &ck_ref,
+	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+			  DSP_DOMAIN_CLOCK,
+	.enable_reg	= DSP_IDLECT2,
+	.enable_bit	= EN_XORPCK,
+	.recalc		= &followparent_recalc,
+};
+
+static struct clk dsptim_ck = {
+	.name		= "dsptim_ck",
+	.parent		= &ck_ref,
+	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+			  DSP_DOMAIN_CLOCK,
+	.enable_reg	= DSP_IDLECT2,
+	.enable_bit	= EN_DSPTIMCK,
+	.recalc		= &followparent_recalc,
+};
+
 static struct clk tc_ck = {
 	.name		= "tc_ck",
 	.parent		= &ck_dpll1,
@@ -226,7 +260,7 @@
 static struct clk arminth_ck1510 = {
 	.name		= "arminth_ck",
 	.parent		= &tc_ck,
-	.flags		= CLOCK_IN_OMAP1510,
+	.flags		= CLOCK_IN_OMAP1510 | ALWAYS_ENABLED,
 	.recalc		= &followparent_recalc,
 	/* Note: On 1510 the frequency follows TC_CK
 	 *
@@ -237,7 +271,7 @@
 static struct clk tipb_ck = {
 	.name		= "tibp_ck",
 	.parent		= &tc_ck,
-	.flags		= CLOCK_IN_OMAP1510,
+	.flags		= CLOCK_IN_OMAP1510 | ALWAYS_ENABLED,
 	.recalc		= &followparent_recalc,
 };
 
@@ -271,14 +305,15 @@
 static struct clk dma_ck = {
 	.name		= "dma_ck",
 	.parent		= &tc_ck,
-	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
+	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+			  ALWAYS_ENABLED,
 	.recalc		= &followparent_recalc,
 };
 
 static struct clk dma_lcdfree_ck = {
 	.name		= "dma_lcdfree_ck",
 	.parent		= &tc_ck,
-	.flags		= CLOCK_IN_OMAP16XX,
+	.flags		= CLOCK_IN_OMAP16XX | ALWAYS_ENABLED,
 	.recalc		= &followparent_recalc,
 };
 
@@ -303,14 +338,14 @@
 static struct clk rhea1_ck = {
 	.name		= "rhea1_ck",
 	.parent		= &tc_ck,
-	.flags		= CLOCK_IN_OMAP16XX,
+	.flags		= CLOCK_IN_OMAP16XX | ALWAYS_ENABLED,
 	.recalc		= &followparent_recalc,
 };
 
 static struct clk rhea2_ck = {
 	.name		= "rhea2_ck",
 	.parent		= &tc_ck,
-	.flags		= CLOCK_IN_OMAP16XX,
+	.flags		= CLOCK_IN_OMAP16XX | ALWAYS_ENABLED,
 	.recalc		= &followparent_recalc,
 };
 
@@ -325,43 +360,56 @@
 	.recalc		= &ckctl_recalc,
 };
 
-static struct clk uart1_ck = {
+static struct clk uart1_1510 = {
+	.name		= "uart1_ck",
+	/* Direct from ULPD, no parent */
+	.rate		= 12000000,
+	.flags		= CLOCK_IN_OMAP1510 | ENABLE_REG_32BIT | ALWAYS_ENABLED,
+	.enable_reg	= MOD_CONF_CTRL_0,
+	.enable_bit	= 29,	/* Chooses between 12MHz and 48MHz */
+	.set_rate	= &set_uart_rate,
+	.recalc		= &uart_recalc,
+};
+
+static struct clk uart1_16xx = {
 	.name		= "uart1_ck",
 	/* Direct from ULPD, no parent */
 	.rate		= 48000000,
-	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
-			  RATE_FIXED | ENABLE_REG_32BIT,
+	.flags		= CLOCK_IN_OMAP16XX | RATE_FIXED | ENABLE_REG_32BIT,
 	.enable_reg	= MOD_CONF_CTRL_0,
 	.enable_bit	= 29,
-	/* (Only on 1510)
-	 * The "enable bit" actually chooses between 48MHz and 12MHz.
-	 */
 };
 
 static struct clk uart2_ck = {
 	.name		= "uart2_ck",
 	/* Direct from ULPD, no parent */
-	.rate		= 48000000,
-	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
-			  RATE_FIXED | ENABLE_REG_32BIT,
+	.rate		= 12000000,
+	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | ENABLE_REG_32BIT |
+			  ALWAYS_ENABLED,
 	.enable_reg	= MOD_CONF_CTRL_0,
-	.enable_bit	= 30,
-	/* (for both 1510 and 16xx)
-	 * The "enable bit" actually chooses between 48MHz and 12MHz/32kHz.
-	 */
+	.enable_bit	= 30,	/* Chooses between 12MHz and 48MHz */
+	.set_rate	= &set_uart_rate,
+	.recalc		= &uart_recalc,
+};
+
+static struct clk uart3_1510 = {
+	.name		= "uart3_ck",
+	/* Direct from ULPD, no parent */
+	.rate		= 12000000,
+	.flags		= CLOCK_IN_OMAP1510 | ENABLE_REG_32BIT | ALWAYS_ENABLED,
+	.enable_reg	= MOD_CONF_CTRL_0,
+	.enable_bit	= 31,	/* Chooses between 12MHz and 48MHz */
+	.set_rate	= &set_uart_rate,
+	.recalc		= &uart_recalc,
 };
 
-static struct clk uart3_ck = {
+static struct clk uart3_16xx = {
 	.name		= "uart3_ck",
 	/* Direct from ULPD, no parent */
 	.rate		= 48000000,
-	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
-			  RATE_FIXED | ENABLE_REG_32BIT,
+	.flags		= CLOCK_IN_OMAP16XX | RATE_FIXED | ENABLE_REG_32BIT,
 	.enable_reg	= MOD_CONF_CTRL_0,
 	.enable_bit	= 31,
-	/* (Only on 1510)
-	 * The "enable bit" actually chooses between 48MHz and 12MHz.
-	 */
 };
 
 static struct clk usb_clko = {	/* 6 MHz output on W4_USB_CLKO */
@@ -480,6 +528,9 @@
 	/* CK_GEN2 clocks */
 	&dsp_ck,
 	&dspmmu_ck,
+	&dspper_ck,
+	&dspxor_ck,
+	&dsptim_ck,
 	/* CK_GEN3 clocks */
 	&tc_ck,
 	&tipb_ck,
@@ -494,9 +545,11 @@
 	&rhea2_ck,
 	&lcd_ck,
 	/* ULPD clocks */
-	&uart1_ck,
+	&uart1_1510,
+	&uart1_16xx,
 	&uart2_ck,
-	&uart3_ck,
+	&uart3_1510,
+	&uart3_16xx,
 	&usb_clko,
 	&usb_hhc_ck1510, &usb_hhc_ck16xx,
 	&mclk_1510,  &mclk_16xx,
@@ -547,6 +600,10 @@
 		return 0;
 	}
 
+	if (clk->flags & DSP_DOMAIN_CLOCK) {
+		__clk_use(&api_ck);
+	}
+
 	if (clk->flags & ENABLE_REG_32BIT) {
 		regval32 = omap_readl(clk->enable_reg);
 		regval32 |= (1 << clk->enable_bit);
@@ -557,6 +614,10 @@
 		omap_writew(regval16, clk->enable_reg);
 	}
 
+	if (clk->flags & DSP_DOMAIN_CLOCK) {
+		__clk_unuse(&api_ck);
+	}
+
 	return 0;
 }
 
@@ -569,6 +630,10 @@
 	if (clk->enable_reg == 0)
 		return;
 
+	if (clk->flags & DSP_DOMAIN_CLOCK) {
+		__clk_use(&api_ck);
+	}
+
 	if (clk->flags & ENABLE_REG_32BIT) {
 		regval32 = omap_readl(clk->enable_reg);
 		regval32 &= ~(1 << clk->enable_bit);
@@ -578,6 +643,10 @@
 		regval16 &= ~(1 << clk->enable_bit);
 		omap_writew(regval16, clk->enable_reg);
 	}
+
+	if (clk->flags & DSP_DOMAIN_CLOCK) {
+		__clk_unuse(&api_ck);
+	}
 }
 
 
@@ -766,6 +835,31 @@
 	return dsor_exp;
 }
 
+
+static void ckctl_recalc(struct clk *  clk)
+{
+	int dsor;
+
+	/* Calculate divisor encoded as 2-bit exponent */
+	if (clk->flags & DSP_DOMAIN_CLOCK) {
+		/* The clock control bits are in DSP domain,
+		 * so api_ck is needed for access
+		 */
+		__clk_use(&api_ck);
+		dsor = 1 << (3 & (omap_readw(DSP_CKCTL) >> clk->rate_offset));
+		__clk_unuse(&api_ck);
+	} else {
+		dsor = 1 << (3 & (omap_readw(ARM_CKCTL) >> clk->rate_offset));
+	}
+	if (unlikely(clk->rate == clk->parent->rate / dsor))
+		return; /* No change, quick exit */
+	clk->rate = clk->parent->rate / dsor;
+
+	if (unlikely(clk->flags & RATE_PROPAGATES))
+		propagate_rate(clk);
+}
+
+
 long clk_round_rate(struct clk *clk, unsigned long rate)
 {
 	int dsor_exp;
@@ -826,7 +920,13 @@
 	if (!ptr->rate)
 		return -EINVAL;
 
+	/*
+	 * If ARM_TIM_CK is coming from CK_GEN1, reset it and set
+	 * safe values for dividers in ARM_CKCTL.
+	 * Otherwise system may hang when reprogramming DPLL_CTL.
+	 */
 	if (unlikely(ck_dpll1.rate == 0)) {
+		omap_writew(0x03ff, ARM_CKCTL);
 		omap_writew(ptr->dpllctl_val, DPLL_CTL);
 		ck_dpll1.rate = ptr->pll_rate;
 	}
@@ -921,6 +1021,23 @@
 	return dsor;
 }
 
+/* Only needed on 1510 */
+static int set_uart_rate(struct clk * clk, unsigned long rate)
+{
+	unsigned int val;
+
+	val = omap_readl(clk->enable_reg);
+	if (rate == 12000000)
+		val &= ~(1 << clk->enable_bit);
+	else if (rate == 48000000)
+		val |= (1 << clk->enable_bit);
+	else
+		return -EINVAL;
+	omap_writel(val, clk->enable_reg);
+	clk->rate = rate;
+
+	return 0;
+}
 
 static int set_ext_clk_rate(struct clk *  clk, unsigned long rate)
 {
@@ -1023,9 +1140,42 @@
 		ck_ref.rate = 19200000;
 #endif
 
+	printk("Clocks: ARM_SYSST: 0x%04x DPLL_CTL: 0x%04x ARM_CKCTL: 0x%04x\n",
+	       omap_readw(ARM_SYSST), omap_readw(DPLL_CTL),
+	       omap_readw(ARM_CKCTL));
+
 	/* We want to be in syncronous scalable mode */
 	omap_writew(0x1000, ARM_SYSST);
 
+#ifdef CONFIG_OMAP_CLOCKS_SET_BY_BOOTLOADER
+	/* Use values set by bootloader. Determine PLL rate and recalculate
+	 * dependent clocks as if kernel had changed PLL or divisors.
+	 */
+	{
+		unsigned pll_ctl_val = omap_readw(DPLL_CTL);
+
+		ck_dpll1.rate = ck_ref.rate; /* Base xtal rate */
+		if (pll_ctl_val & 0x10) {
+			/* PLL enabled, apply multiplier and divisor */
+			if (pll_ctl_val & 0xf80)
+				ck_dpll1.rate *= (pll_ctl_val & 0xf80) >> 7;
+			ck_dpll1.rate /= ((pll_ctl_val & 0x60) >> 5) + 1;
+		} else {
+			/* PLL disabled, apply bypass divisor */
+			switch (pll_ctl_val & 0xc) {
+			case 0:
+				break;
+			case 0x4:
+				ck_dpll1.rate /= 2;
+				break;
+			default:
+				ck_dpll1.rate /= 4;
+				break;
+			}
+		}
+	}
+	propagate_rate(&ck_dpll1);
+#else
 	/* Find the highest supported frequency and enable it */
 	if (select_table_rate(&virtual_ck_mpu, ~0)) {
 		printk(KERN_ERR "System frequencies not set. Check your config.\n");
@@ -1034,12 +1184,13 @@
 		omap_writew(0x1005, ARM_CKCTL);
 		ck_dpll1.rate = 60000000;
 		propagate_rate(&ck_dpll1);
-		printk(KERN_INFO "Clocking rate (xtal/DPLL1/MPU): %ld/%ld/%ld\n",
-		       ck_ref.rate, ck_dpll1.rate, arm_ck.rate);
 	}
-
+#endif
 	/* Cache rates for clocks connected to ck_ref (not dpll1) */
 	propagate_rate(&ck_ref);
+	printk(KERN_INFO "Clocking rate (xtal/DPLL1/MPU): %ld.%01ld/%ld/%ld MHz\n",
+	       ck_ref.rate / 1000000, (ck_ref.rate / 100000) % 10,
+	       ck_dpll1.rate, arm_ck.rate);
 
 #ifdef CONFIG_MACH_OMAP_PERSEUS2
 	/* Select slicer output as OMAP input clock */
@@ -1074,3 +1225,56 @@
 
 	return 0;
 }
+
+
+#ifdef CONFIG_OMAP_RESET_CLOCKS
+
+static int __init omap_clk_reset(void)
+{
+	/* Turn off all unused clocks */
+	struct clk *p;
+	__u32 regval32;
+
+	omap_writew(0, SOFT_REQ_REG);
+	omap_writew(0, SOFT_REQ_REG2);
+
+	list_for_each_entry(p, &clocks, node) {
+		if (p->usecount > 0 || (p->flags & ALWAYS_ENABLED) ||
+			p->enable_reg == 0)
+			continue;
+
+		/* Assume no DSP clocks have been activated by bootloader */
+		if (p->flags & DSP_DOMAIN_CLOCK)
+			continue;
+
+		/* Is the clock already disabled? */
+		if (p->flags & ENABLE_REG_32BIT)
+			regval32 = omap_readl(p->enable_reg);
+		else
+			regval32 = omap_readw(p->enable_reg);
+
+		if ((regval32 & (1 << p->enable_bit)) == 0)
+			continue;
+
+		/* FIXME: This clock seems to be necessary but no-one
+		 * has asked for its activation. */
+		if (p == &tc2_ck         // FIX: pm.c (SRAM), CCP, Camera
+		    || p == &ck_dpll1out // FIX: SoSSI, SSR
+		    || p == &arm_gpio_ck // FIX: GPIO code for 1510
+		    ) {
+			printk(KERN_INFO "FIXME: Clock \"%s\" seems unused\n",
+			       p->name);
+			continue;
+		}
+
+		printk(KERN_INFO "Disabling unused clock \"%s\"... ", p->name);
+		__clk_disable(p);
+		printk(" done\n");
+	}
+
+	return 0;
+}
+
+late_initcall(omap_clk_reset);
+
+#endif
diff -Nru a/arch/arm/mach-omap/clock.h b/arch/arm/mach-omap/clock.h
--- a/arch/arm/mach-omap/clock.h	2005-05-04 11:13:53 -07:00
+++ b/arch/arm/mach-omap/clock.h	2005-05-04 11:13:53 -07:00
@@ -52,6 +52,7 @@
 #define CLOCK_IN_OMAP16XX	64
 #define CLOCK_IN_OMAP1510	128
 #define CLOCK_IN_OMAP730	256
+#define DSP_DOMAIN_CLOCK	512
 
 /* ARM_CKCTL bit shifts */
 #define CKCTL_PERDIV_OFFSET	0
@@ -63,6 +64,8 @@
 /*#define ARM_TIMXO		12*/
 #define EN_DSPCK		13
 /*#define ARM_INTHCK_SEL	14*/ /* Divide-by-2 for mpu inth_ck */
+/* DSP_CKCTL bit shifts */
+#define CKCTL_DSPPERDIV_OFFSET	0
 
 /* ARM_IDLECT1 bit shifts */
 /*#define IDLWDT_ARM	0*/
@@ -96,6 +99,9 @@
 #define EN_TC1_CK	2
 #define EN_TC2_CK	4
 
+/* DSP_IDLECT2 bit shifts (0,1,2 are same as for ARM_IDLECT2) */
+#define EN_DSPTIMCK	5
+
 /* Various register defines for clock controls scattered around OMAP chip */
 #define USB_MCLK_EN_BIT		4	/* In ULPD_CLKC_CTRL */
 #define USB_HOST_HHC_UHOST_EN	9	/* In MOD_CONF_CTRL_0 */
@@ -103,7 +109,8 @@
 #define COM_ULPD_PLL_CLK_REQ	1	/* In COM_CLK_DIV_CTRL_SEL */
 #define SWD_CLK_DIV_CTRL_SEL	0xfffe0874
 #define COM_CLK_DIV_CTRL_SEL	0xfffe0878
-
+#define SOFT_REQ_REG		0xfffe0834
+#define SOFT_REQ_REG2		0xfffe0880
 
 int clk_register(struct clk *clk);
 void clk_unregister(struct clk *clk);
