OMAP2: clock: add DPLL autoidle support
authorPaul Walmsley <paul@pwsan.com>
Fri, 25 Feb 2011 22:49:53 +0000 (15:49 -0700)
committerPaul Walmsley <paul@pwsan.com>
Tue, 8 Mar 2011 03:02:05 +0000 (20:02 -0700)
Add the necessary code and data to allow the clock framework to enable
and disable the OMAP2 DPLL autoidle state.  This is so the direct
register access can be moved out of the mach-omap2/pm24xx.c code, and other
code that needs to control this (e.g., CPUIdle) can do so via an API.
As part of this patch, remove the pm24xx.c code that formerly wrote
directly to the autoidle bits.

Signed-off-by: Paul Walmsley <paul@pwsan.com>
Cc: Kevin Hilman <khilman@ti.com>
Tested-by: Rajendra Nayak <rnayak@ti.com>
Reviewed-by: Kevin Hilman <khilman@ti.com>
arch/arm/mach-omap2/Makefile
arch/arm/mach-omap2/clkt2xxx_dpll.c [new file with mode: 0644]
arch/arm/mach-omap2/clock.h
arch/arm/mach-omap2/clock2420_data.c
arch/arm/mach-omap2/clock2430_data.c
arch/arm/mach-omap2/cm2xxx_3xxx.c
arch/arm/mach-omap2/cm2xxx_3xxx.h
arch/arm/mach-omap2/pm24xx.c

index 89274a9f0357e7235bf9e516b79acd0ff3ed2d6c..ae44645551c24385ced515b8a24c4972b8e4b636 100644 (file)
@@ -115,7 +115,8 @@ obj-$(CONFIG_ARCH_OMAP2)            += $(clock-common) clock2xxx.o \
                                           clkt2xxx_sys.o \
                                           clkt2xxx_dpllcore.o \
                                           clkt2xxx_virt_prcm_set.o \
-                                          clkt2xxx_apll.o clkt2xxx_osc.o
+                                          clkt2xxx_apll.o clkt2xxx_osc.o \
+                                          clkt2xxx_dpll.o
 obj-$(CONFIG_SOC_OMAP2420)             += clock2420_data.o
 obj-$(CONFIG_SOC_OMAP2430)             += clock2430.o clock2430_data.o
 obj-$(CONFIG_ARCH_OMAP3)               += $(clock-common) clock3xxx.o \
diff --git a/arch/arm/mach-omap2/clkt2xxx_dpll.c b/arch/arm/mach-omap2/clkt2xxx_dpll.c
new file mode 100644 (file)
index 0000000..1502a7b
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * OMAP2-specific DPLL control functions
+ *
+ * Copyright (C) 2011 Nokia Corporation
+ * Paul Walmsley
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <plat/clock.h>
+
+#include "clock.h"
+#include "cm2xxx_3xxx.h"
+#include "cm-regbits-24xx.h"
+
+/* Private functions */
+
+/**
+ * _allow_idle - enable DPLL autoidle bits
+ * @clk: struct clk * of the DPLL to operate on
+ *
+ * Enable DPLL automatic idle control.  The DPLL will enter low-power
+ * stop when its downstream clocks are gated.  No return value.
+ * REVISIT: DPLL can optionally enter low-power bypass by writing 0x1
+ * instead.  Add some mechanism to optionally enter this mode.
+ */
+static void _allow_idle(struct clk *clk)
+{
+       if (!clk || !clk->dpll_data)
+               return;
+
+       omap2xxx_cm_set_dpll_auto_low_power_stop();
+}
+
+/**
+ * _deny_idle - prevent DPLL from automatically idling
+ * @clk: struct clk * of the DPLL to operate on
+ *
+ * Disable DPLL automatic idle control.  No return value.
+ */
+static void _deny_idle(struct clk *clk)
+{
+       if (!clk || !clk->dpll_data)
+               return;
+
+       omap2xxx_cm_set_dpll_disable_autoidle();
+}
+
+
+/* Public data */
+
+const struct clkops clkops_omap2xxx_dpll_ops = {
+       .allow_idle     = _allow_idle,
+       .deny_idle      = _deny_idle,
+};
+
index 0725a6ad8b46190785c6cbb6979fab25b9b75608..9972d892a4af7868243173ed3de7797a6576ac21 100644 (file)
@@ -148,6 +148,7 @@ extern void omap2_clk_exit_cpufreq_table(struct cpufreq_frequency_table **table)
 #define omap2_clk_exit_cpufreq_table   0
 #endif
 
+extern const struct clkops clkops_omap2xxx_dpll_ops;
 extern const struct clkops clkops_omap3_noncore_dpll_ops;
 extern const struct clkops clkops_omap3_core_dpll_ops;
 extern const struct clkops clkops_omap4_dpllmx_ops;
index ee73e14ac3c8fa52836c3c363ee115a0a271e6e1..30fbcbd0ed815218da289c0b512420411f754bbc 100644 (file)
@@ -125,7 +125,7 @@ static struct dpll_data dpll_dd = {
  */
 static struct clk dpll_ck = {
        .name           = "dpll_ck",
-       .ops            = &clkops_null,
+       .ops            = &clkops_omap2xxx_dpll_ops,
        .parent         = &sys_ck,              /* Can be func_32k also */
        .dpll_data      = &dpll_dd,
        .clkdm_name     = "wkup_clkdm",
index a1298e55d91577001e6fc6aeab3ea356be917da4..1ff150a0f304275cd44c5d1bc80a295239996083 100644 (file)
@@ -125,7 +125,7 @@ static struct dpll_data dpll_dd = {
  */
 static struct clk dpll_ck = {
        .name           = "dpll_ck",
-       .ops            = &clkops_null,
+       .ops            = &clkops_omap2xxx_dpll_ops,
        .parent         = &sys_ck,              /* Can be func_32k also */
        .dpll_data      = &dpll_dd,
        .clkdm_name     = "wkup_clkdm",
index 96954aa486714e42fc57f710d386356a99946b9c..6b0c7c85ef530269d50e9f4578ca7cbf3b0ea2de 100644 (file)
 #include "cm-regbits-24xx.h"
 #include "cm-regbits-34xx.h"
 
+/* CM_AUTOIDLE_PLL.AUTO_* bit values */
+#define DPLL_AUTOIDLE_DISABLE                          0x0
+#define OMAP2XXX_DPLL_AUTOIDLE_LOW_POWER_STOP          0x3
+
 static const u8 cm_idlest_offs[] = {
        CM_IDLEST1, CM_IDLEST2, OMAP2430_CM_IDLEST3
 };
@@ -125,6 +129,29 @@ void omap3xxx_cm_clkdm_force_wakeup(s16 module, u32 mask)
        _write_clktrctrl(OMAP34XX_CLKSTCTRL_FORCE_WAKEUP, module, mask);
 }
 
+/*
+ * DPLL autoidle control
+ */
+
+static void _omap2xxx_set_dpll_autoidle(u8 m)
+{
+       u32 v;
+
+       v = omap2_cm_read_mod_reg(PLL_MOD, CM_AUTOIDLE);
+       v &= ~OMAP24XX_AUTO_DPLL_MASK;
+       v |= m << OMAP24XX_AUTO_DPLL_SHIFT;
+       omap2_cm_write_mod_reg(v, PLL_MOD, CM_AUTOIDLE);
+}
+
+void omap2xxx_cm_set_dpll_disable_autoidle(void)
+{
+       _omap2xxx_set_dpll_autoidle(OMAP2XXX_DPLL_AUTOIDLE_LOW_POWER_STOP);
+}
+
+void omap2xxx_cm_set_dpll_auto_low_power_stop(void)
+{
+       _omap2xxx_set_dpll_autoidle(DPLL_AUTOIDLE_DISABLE);
+}
 
 /*
  *
index 5e9ea5bd60b9dab0cb2f91d61d33ffb1295efedb..5f4df1ceafad7280dc3d7ff54d9ca3e8fc0c0a7f 100644 (file)
@@ -122,6 +122,9 @@ extern void omap3xxx_cm_clkdm_disable_hwsup(s16 module, u32 mask);
 extern void omap3xxx_cm_clkdm_force_sleep(s16 module, u32 mask);
 extern void omap3xxx_cm_clkdm_force_wakeup(s16 module, u32 mask);
 
+extern void omap2xxx_cm_set_dpll_disable_autoidle(void);
+extern void omap2xxx_cm_set_dpll_auto_low_power_stop(void);
+
 #endif
 
 /* CM register bits shared between 24XX and 3430 */
index e983c8301f553142e88fc634de034d060f16f635..297bb21061b8890ccaf235b481091789f48dfc86 100644 (file)
@@ -378,6 +378,7 @@ static void __init prcm_setup_regs(void)
 {
        int i, num_mem_banks;
        struct powerdomain *pwrdm;
+       u32 v;
 
        /* Enable autoidle */
        omap2_prm_write_mod_reg(OMAP24XX_AUTOIDLE_MASK, OCP_MOD,
@@ -468,11 +469,12 @@ static void __init prcm_setup_regs(void)
        omap2_cm_write_mod_reg(OMAP2420_AUTO_DSP_IPI_MASK, OMAP24XX_DSP_MOD,
                               CM_AUTOIDLE);
 
-       /* Put DPLL and both APLLs into autoidle mode */
-       omap2_cm_write_mod_reg((0x03 << OMAP24XX_AUTO_DPLL_SHIFT) |
-                              (0x03 << OMAP24XX_AUTO_96M_SHIFT) |
-                              (0x03 << OMAP24XX_AUTO_54M_SHIFT),
-                              PLL_MOD, CM_AUTOIDLE);
+       /* Put both APLLs into autoidle mode */
+       v = omap2_cm_read_mod_reg(PLL_MOD, CM_AUTOIDLE);
+       v &= ~(OMAP24XX_AUTO_96M_MASK | OMAP24XX_AUTO_54M_SHIFT);
+       v |= (0x03 << OMAP24XX_AUTO_96M_SHIFT) |
+               (0x03 << OMAP24XX_AUTO_54M_SHIFT);
+       omap2_cm_write_mod_reg(v, PLL_MOD, CM_AUTOIDLE);
 
        omap2_cm_write_mod_reg(OMAP24XX_AUTO_OMAPCTRL_MASK |
                               OMAP24XX_AUTO_WDT1_MASK |