PowerOP Take 2 1/3: ARM OMAP1 platform support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



PowerOP support for OMAP1 platforms.  Currently handles these power
parameters:

   dpllmult	DPLL_CTL reg PLL MULT bits
   dplldiv	DPLL_CTL reg PLL DIV bits
   armdiv	ARM_CKCTL reg ARMDIV bits
   dspdiv	ARM_CKCTL reg DSPDIV bits
   tcdiv	ARM_CKCTL reg TCDIV bits
   lowpwr	1 = assert ULPD LOW_PWR, voltage scale low

Other parameters such as DSPMMUDIV, LCDDIV, and ARM_PERDIV might also be
useful.

Example usage will be shown with a follow-on sysfs UI patch.

Index: linux-2.6.13-rc4/arch/arm/mach-omap1/powerop.c
===================================================================
--- /dev/null
+++ linux-2.6.13-rc4/arch/arm/mach-omap1/powerop.c
@@ -0,0 +1,157 @@
+/*
+ * PowerOP support for OMAP1
+ *
+ * Based on DPM OMAP code by Matthew Locke, Dmitry Chigirev, Vladimir
+ * Barinov, and Todd Poynor.
+ *
+ * 2005 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+
+#include <asm/arch/powerop.h>
+#include <asm/hardware.h>
+#include <asm/arch/pm.h>
+
+/* ARM_CKCTL bit shifts */
+#define CKCTL_PERDIV_OFFSET	0
+#define CKCTL_LCDDIV_OFFSET	2
+#define CKCTL_ARMDIV_OFFSET	4
+#define CKCTL_DSPDIV_OFFSET	6
+#define CKCTL_TCDIV_OFFSET	8
+#define CKCTL_DSPMMUDIV_OFFSET	10
+
+#define DPLL_CTL_MASK	0xfe0
+
+#define ULPD_MIN_MAX_REG (1 << 11)
+#define ULPD_DVS_ENABLE  (1 << 10)
+#define ULPD_LOW_PWR_REQ (1 << 1)
+#define LOW_POWER (ULPD_MIN_MAX_REG | ULPD_DVS_ENABLE | ULPD_LOW_PWR_REQ | \
+		   ULPD_LOW_PWR_EN)
+
+int
+powerop_get_point(struct powerop_point *point)
+{
+	unsigned long flags;
+	int dpll_ctl, arm_cktl;
+
+	local_irq_save(flags);
+	dpll_ctl = omap_readw(DPLL_CTL);
+	arm_cktl = omap_readw(ARM_CKCTL);
+
+	point->dpllmult = dpll_ctl >> 7 & 0x1f;
+	point->dplldiv = dpll_ctl >> 5 & 0x3;
+	point->armdiv = arm_cktl >> CKCTL_ARMDIV_OFFSET & 0x3;
+	point->dspdiv = arm_cktl >> CKCTL_DSPDIV_OFFSET & 0x3;
+	point->tcdiv = arm_cktl >> CKCTL_TCDIV_OFFSET & 0x3;
+	point->lowpwr = (omap_readw(ULPD_POWER_CTRL) & (ULPD_LOW_PWR_REQ)) ?
+		1 : 0;
+	local_irq_restore(flags);
+	return 0;
+}
+
+static void scale_dpll(int dpll_ctl)
+{
+	int i;
+
+	omap_writew((omap_readw(DPLL_CTL) & ~DPLL_CTL_MASK) | dpll_ctl,
+		    DPLL_CTL);
+
+	for (i = 0; i < 0x1FF; i++)
+		nop();
+
+	/*
+	 * Wait for PLL relock.
+	 */
+
+	while ((omap_readw(DPLL_CTL) & 0x1) == 0);
+}
+
+static void set_low_pwr(int lowpwr)
+{
+	int cur_lowpwr;
+
+	if (lowpwr == -1)
+		return;
+
+	cur_lowpwr = (omap_readw(ULPD_POWER_CTRL) & (ULPD_LOW_PWR_REQ)) ?
+		1 : 0;
+
+	if (cur_lowpwr != lowpwr) {
+		if (lowpwr)
+			omap_writew(omap_readw(ULPD_POWER_CTRL) | LOW_POWER,
+				    ULPD_POWER_CTRL);
+		else
+			omap_writew(omap_readw(ULPD_POWER_CTRL) & ~LOW_POWER,
+				    ULPD_POWER_CTRL);
+	}
+}
+
+int
+powerop_set_point(struct powerop_point *point)
+{
+	int dpll_ctl = 0;
+	int dpll_mod = 0;
+	int arm_ctl = 0;
+	int arm_msk = 0;
+	int cur_dpll_ctl;
+	unsigned long flags;
+
+	if ((point->dpllmult != -1) && (point->dplldiv != -1)) {
+		dpll_ctl = (point->dpllmult << 7) |
+			(point->dplldiv << 5);
+		dpll_mod = 1;
+	}
+
+	if (point->armdiv != -1) {
+		arm_ctl |= (point->armdiv << CKCTL_ARMDIV_OFFSET);
+		arm_msk |= (3 << CKCTL_ARMDIV_OFFSET);
+	}
+
+	if (point->dspdiv != -1) {
+		arm_ctl |= (point->dspdiv << CKCTL_DSPDIV_OFFSET);
+		arm_msk |= (3 << CKCTL_DSPDIV_OFFSET);
+	}
+
+	if (point->tcdiv != -1) {
+		arm_ctl |= (point->tcdiv << CKCTL_TCDIV_OFFSET);
+		arm_msk |= (3 << CKCTL_TCDIV_OFFSET);
+	}
+
+	local_irq_save(flags);
+	cur_dpll_ctl = omap_readw(DPLL_CTL) & DPLL_CTL_MASK;
+
+	if (dpll_mod && (dpll_ctl < cur_dpll_ctl))
+		scale_dpll(dpll_ctl);
+
+	if (arm_msk != 0)
+		omap_writew((omap_readw(ARM_CKCTL) & ~arm_msk) | arm_ctl,
+			    ARM_CKCTL);
+
+	if (dpll_mod && (dpll_ctl > cur_dpll_ctl))
+		scale_dpll(dpll_ctl);
+
+	set_low_pwr(point->lowpwr);
+	local_irq_restore(flags);
+	return 0;
+}
+
+EXPORT_SYMBOL_GPL(powerop_get_point);
+EXPORT_SYMBOL_GPL(powerop_set_point);
+
+static int __init powerop_init(void)
+{
+	return 0;
+}
+
+static void __exit powerop_exit(void)
+{
+}
+
+module_init(powerop_init);
+module_exit(powerop_exit);
Index: linux-2.6.13-rc4/include/asm-arm/arch-omap/powerop.h
===================================================================
--- /dev/null
+++ linux-2.6.13-rc4/include/asm-arm/arch-omap/powerop.h
@@ -0,0 +1,27 @@
+/*
+ * PowerOP support for OMAP1
+ *
+ * Based on DPM OMAP code by Matthew Locke, Dmitry Chigirev, Vladimir
+ * Barinov, and Todd Poynor.
+ *
+ * 2005 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#ifndef __ASM_ARCH_OMAP_POWEROP_H
+#define __ASM_ARCH_OMAP_POWEROP_H
+
+/* -1 for any following fields indicates no change from current op */
+
+struct powerop_point {
+        int lowpwr;	/* 1 = assert ULPD DVS LOW_PWR */
+	int dpllmult;	/* DPLL_CTL PLL MULT 0..31 */
+	int dplldiv;	/* DPLL_CTL PLL DIV 0..3 */
+	int armdiv;	/* ARM_CKCTL ARMDIV 0..3 */
+	int dspdiv;	/* ARM_CKCTL DSPDIV 0..3 */
+	int tcdiv;	/* ARM_CKCTL TCDIV 0..3 */
+};
+
+#endif /* __ASM_ARCH_OMAP_POWEROP_H */
Index: linux-2.6.13-rc4/arch/arm/mach-omap1/Kconfig
===================================================================
--- linux-2.6.13-rc4.orig/arch/arm/mach-omap1/Kconfig
+++ linux-2.6.13-rc4/arch/arm/mach-omap1/Kconfig
@@ -152,3 +152,6 @@ config OMAP_ARM_30MHZ
 
 source "arch/arm/plat-omap/dsp/Kconfig"
 
+config	POWEROP
+	bool "PowerOP Platform Core Power Management for OMAP1"
+	help
Index: linux-2.6.13-rc4/arch/arm/mach-omap1/Makefile
===================================================================
--- linux-2.6.13-rc4.orig/arch/arm/mach-omap1/Makefile
+++ linux-2.6.13-rc4/arch/arm/mach-omap1/Makefile
@@ -29,3 +29,4 @@ led-$(CONFIG_MACH_OMAP_PERSEUS2)	+= leds
 led-$(CONFIG_MACH_OMAP_OSK)		+= leds-osk.o
 obj-$(CONFIG_LEDS)			+= $(led-y)
 
+obj-$(CONFIG_POWEROP)			+= powerop.o
Index: linux-2.6.13-rc4/include/asm-arm/powerop.h
===================================================================
--- /dev/null
+++ linux-2.6.13-rc4/include/asm-arm/powerop.h
@@ -0,0 +1,18 @@
+/*
+ * PowerOP support for ARM
+ *
+ * 2005 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#ifndef __ASM_POWEROP_H
+#define __ASM_POWEROP_H
+
+#include <asm/arch/powerop.h>
+
+extern int powerop_get_point(struct powerop_point *point);
+extern int powerop_set_point(struct powerop_point *point);
+
+#endif /* __ASM_POWEROP_H */
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]
  Powered by Linux