aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm
diff options
context:
space:
mode:
authorPaul Walmsley <paul@pwsan.com>2011-02-25 17:49:53 -0500
committerPaul Walmsley <paul@pwsan.com>2011-03-07 22:02:05 -0500
commit0fd0c21be71293d8a54d9075b18b5a25a1868057 (patch)
treeebf500cb2d7b0c104fc1e1c190aa3b2457d987c8 /arch/arm
parentc6461f5c5970833cf28c5096cdfc7a095eb3bbb5 (diff)
OMAP2: clock: add DPLL autoidle support
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>
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/mach-omap2/Makefile3
-rw-r--r--arch/arm/mach-omap2/clkt2xxx_dpll.c63
-rw-r--r--arch/arm/mach-omap2/clock.h1
-rw-r--r--arch/arm/mach-omap2/clock2420_data.c2
-rw-r--r--arch/arm/mach-omap2/clock2430_data.c2
-rw-r--r--arch/arm/mach-omap2/cm2xxx_3xxx.c27
-rw-r--r--arch/arm/mach-omap2/cm2xxx_3xxx.h3
-rw-r--r--arch/arm/mach-omap2/pm24xx.c12
8 files changed, 105 insertions, 8 deletions
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index 89274a9f0357..ae44645551c2 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -115,7 +115,8 @@ obj-$(CONFIG_ARCH_OMAP2) += $(clock-common) clock2xxx.o \
115 clkt2xxx_sys.o \ 115 clkt2xxx_sys.o \
116 clkt2xxx_dpllcore.o \ 116 clkt2xxx_dpllcore.o \
117 clkt2xxx_virt_prcm_set.o \ 117 clkt2xxx_virt_prcm_set.o \
118 clkt2xxx_apll.o clkt2xxx_osc.o 118 clkt2xxx_apll.o clkt2xxx_osc.o \
119 clkt2xxx_dpll.o
119obj-$(CONFIG_SOC_OMAP2420) += clock2420_data.o 120obj-$(CONFIG_SOC_OMAP2420) += clock2420_data.o
120obj-$(CONFIG_SOC_OMAP2430) += clock2430.o clock2430_data.o 121obj-$(CONFIG_SOC_OMAP2430) += clock2430.o clock2430_data.o
121obj-$(CONFIG_ARCH_OMAP3) += $(clock-common) clock3xxx.o \ 122obj-$(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
index 000000000000..1502a7bc20bb
--- /dev/null
+++ b/arch/arm/mach-omap2/clkt2xxx_dpll.c
@@ -0,0 +1,63 @@
1/*
2 * OMAP2-specific DPLL control functions
3 *
4 * Copyright (C) 2011 Nokia Corporation
5 * Paul Walmsley
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11
12#include <linux/kernel.h>
13#include <linux/errno.h>
14#include <linux/clk.h>
15#include <linux/io.h>
16
17#include <plat/clock.h>
18
19#include "clock.h"
20#include "cm2xxx_3xxx.h"
21#include "cm-regbits-24xx.h"
22
23/* Private functions */
24
25/**
26 * _allow_idle - enable DPLL autoidle bits
27 * @clk: struct clk * of the DPLL to operate on
28 *
29 * Enable DPLL automatic idle control. The DPLL will enter low-power
30 * stop when its downstream clocks are gated. No return value.
31 * REVISIT: DPLL can optionally enter low-power bypass by writing 0x1
32 * instead. Add some mechanism to optionally enter this mode.
33 */
34static void _allow_idle(struct clk *clk)
35{
36 if (!clk || !clk->dpll_data)
37 return;
38
39 omap2xxx_cm_set_dpll_auto_low_power_stop();
40}
41
42/**
43 * _deny_idle - prevent DPLL from automatically idling
44 * @clk: struct clk * of the DPLL to operate on
45 *
46 * Disable DPLL automatic idle control. No return value.
47 */
48static void _deny_idle(struct clk *clk)
49{
50 if (!clk || !clk->dpll_data)
51 return;
52
53 omap2xxx_cm_set_dpll_disable_autoidle();
54}
55
56
57/* Public data */
58
59const struct clkops clkops_omap2xxx_dpll_ops = {
60 .allow_idle = _allow_idle,
61 .deny_idle = _deny_idle,
62};
63
diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h
index 0725a6ad8b46..9972d892a4af 100644
--- a/arch/arm/mach-omap2/clock.h
+++ b/arch/arm/mach-omap2/clock.h
@@ -148,6 +148,7 @@ extern void omap2_clk_exit_cpufreq_table(struct cpufreq_frequency_table **table)
148#define omap2_clk_exit_cpufreq_table 0 148#define omap2_clk_exit_cpufreq_table 0
149#endif 149#endif
150 150
151extern const struct clkops clkops_omap2xxx_dpll_ops;
151extern const struct clkops clkops_omap3_noncore_dpll_ops; 152extern const struct clkops clkops_omap3_noncore_dpll_ops;
152extern const struct clkops clkops_omap3_core_dpll_ops; 153extern const struct clkops clkops_omap3_core_dpll_ops;
153extern const struct clkops clkops_omap4_dpllmx_ops; 154extern const struct clkops clkops_omap4_dpllmx_ops;
diff --git a/arch/arm/mach-omap2/clock2420_data.c b/arch/arm/mach-omap2/clock2420_data.c
index ee73e14ac3c8..30fbcbd0ed81 100644
--- a/arch/arm/mach-omap2/clock2420_data.c
+++ b/arch/arm/mach-omap2/clock2420_data.c
@@ -125,7 +125,7 @@ static struct dpll_data dpll_dd = {
125 */ 125 */
126static struct clk dpll_ck = { 126static struct clk dpll_ck = {
127 .name = "dpll_ck", 127 .name = "dpll_ck",
128 .ops = &clkops_null, 128 .ops = &clkops_omap2xxx_dpll_ops,
129 .parent = &sys_ck, /* Can be func_32k also */ 129 .parent = &sys_ck, /* Can be func_32k also */
130 .dpll_data = &dpll_dd, 130 .dpll_data = &dpll_dd,
131 .clkdm_name = "wkup_clkdm", 131 .clkdm_name = "wkup_clkdm",
diff --git a/arch/arm/mach-omap2/clock2430_data.c b/arch/arm/mach-omap2/clock2430_data.c
index a1298e55d915..1ff150a0f304 100644
--- a/arch/arm/mach-omap2/clock2430_data.c
+++ b/arch/arm/mach-omap2/clock2430_data.c
@@ -125,7 +125,7 @@ static struct dpll_data dpll_dd = {
125 */ 125 */
126static struct clk dpll_ck = { 126static struct clk dpll_ck = {
127 .name = "dpll_ck", 127 .name = "dpll_ck",
128 .ops = &clkops_null, 128 .ops = &clkops_omap2xxx_dpll_ops,
129 .parent = &sys_ck, /* Can be func_32k also */ 129 .parent = &sys_ck, /* Can be func_32k also */
130 .dpll_data = &dpll_dd, 130 .dpll_data = &dpll_dd,
131 .clkdm_name = "wkup_clkdm", 131 .clkdm_name = "wkup_clkdm",
diff --git a/arch/arm/mach-omap2/cm2xxx_3xxx.c b/arch/arm/mach-omap2/cm2xxx_3xxx.c
index 96954aa48671..6b0c7c85ef53 100644
--- a/arch/arm/mach-omap2/cm2xxx_3xxx.c
+++ b/arch/arm/mach-omap2/cm2xxx_3xxx.c
@@ -25,6 +25,10 @@
25#include "cm-regbits-24xx.h" 25#include "cm-regbits-24xx.h"
26#include "cm-regbits-34xx.h" 26#include "cm-regbits-34xx.h"
27 27
28/* CM_AUTOIDLE_PLL.AUTO_* bit values */
29#define DPLL_AUTOIDLE_DISABLE 0x0
30#define OMAP2XXX_DPLL_AUTOIDLE_LOW_POWER_STOP 0x3
31
28static const u8 cm_idlest_offs[] = { 32static const u8 cm_idlest_offs[] = {
29 CM_IDLEST1, CM_IDLEST2, OMAP2430_CM_IDLEST3 33 CM_IDLEST1, CM_IDLEST2, OMAP2430_CM_IDLEST3
30}; 34};
@@ -125,6 +129,29 @@ void omap3xxx_cm_clkdm_force_wakeup(s16 module, u32 mask)
125 _write_clktrctrl(OMAP34XX_CLKSTCTRL_FORCE_WAKEUP, module, mask); 129 _write_clktrctrl(OMAP34XX_CLKSTCTRL_FORCE_WAKEUP, module, mask);
126} 130}
127 131
132/*
133 * DPLL autoidle control
134 */
135
136static void _omap2xxx_set_dpll_autoidle(u8 m)
137{
138 u32 v;
139
140 v = omap2_cm_read_mod_reg(PLL_MOD, CM_AUTOIDLE);
141 v &= ~OMAP24XX_AUTO_DPLL_MASK;
142 v |= m << OMAP24XX_AUTO_DPLL_SHIFT;
143 omap2_cm_write_mod_reg(v, PLL_MOD, CM_AUTOIDLE);
144}
145
146void omap2xxx_cm_set_dpll_disable_autoidle(void)
147{
148 _omap2xxx_set_dpll_autoidle(OMAP2XXX_DPLL_AUTOIDLE_LOW_POWER_STOP);
149}
150
151void omap2xxx_cm_set_dpll_auto_low_power_stop(void)
152{
153 _omap2xxx_set_dpll_autoidle(DPLL_AUTOIDLE_DISABLE);
154}
128 155
129/* 156/*
130 * 157 *
diff --git a/arch/arm/mach-omap2/cm2xxx_3xxx.h b/arch/arm/mach-omap2/cm2xxx_3xxx.h
index 5e9ea5bd60b9..5f4df1ceafad 100644
--- a/arch/arm/mach-omap2/cm2xxx_3xxx.h
+++ b/arch/arm/mach-omap2/cm2xxx_3xxx.h
@@ -122,6 +122,9 @@ extern void omap3xxx_cm_clkdm_disable_hwsup(s16 module, u32 mask);
122extern void omap3xxx_cm_clkdm_force_sleep(s16 module, u32 mask); 122extern void omap3xxx_cm_clkdm_force_sleep(s16 module, u32 mask);
123extern void omap3xxx_cm_clkdm_force_wakeup(s16 module, u32 mask); 123extern void omap3xxx_cm_clkdm_force_wakeup(s16 module, u32 mask);
124 124
125extern void omap2xxx_cm_set_dpll_disable_autoidle(void);
126extern void omap2xxx_cm_set_dpll_auto_low_power_stop(void);
127
125#endif 128#endif
126 129
127/* CM register bits shared between 24XX and 3430 */ 130/* CM register bits shared between 24XX and 3430 */
diff --git a/arch/arm/mach-omap2/pm24xx.c b/arch/arm/mach-omap2/pm24xx.c
index e983c8301f55..297bb21061b8 100644
--- a/arch/arm/mach-omap2/pm24xx.c
+++ b/arch/arm/mach-omap2/pm24xx.c
@@ -378,6 +378,7 @@ static void __init prcm_setup_regs(void)
378{ 378{
379 int i, num_mem_banks; 379 int i, num_mem_banks;
380 struct powerdomain *pwrdm; 380 struct powerdomain *pwrdm;
381 u32 v;
381 382
382 /* Enable autoidle */ 383 /* Enable autoidle */
383 omap2_prm_write_mod_reg(OMAP24XX_AUTOIDLE_MASK, OCP_MOD, 384 omap2_prm_write_mod_reg(OMAP24XX_AUTOIDLE_MASK, OCP_MOD,
@@ -468,11 +469,12 @@ static void __init prcm_setup_regs(void)
468 omap2_cm_write_mod_reg(OMAP2420_AUTO_DSP_IPI_MASK, OMAP24XX_DSP_MOD, 469 omap2_cm_write_mod_reg(OMAP2420_AUTO_DSP_IPI_MASK, OMAP24XX_DSP_MOD,
469 CM_AUTOIDLE); 470 CM_AUTOIDLE);
470 471
471 /* Put DPLL and both APLLs into autoidle mode */ 472 /* Put both APLLs into autoidle mode */
472 omap2_cm_write_mod_reg((0x03 << OMAP24XX_AUTO_DPLL_SHIFT) | 473 v = omap2_cm_read_mod_reg(PLL_MOD, CM_AUTOIDLE);
473 (0x03 << OMAP24XX_AUTO_96M_SHIFT) | 474 v &= ~(OMAP24XX_AUTO_96M_MASK | OMAP24XX_AUTO_54M_SHIFT);
474 (0x03 << OMAP24XX_AUTO_54M_SHIFT), 475 v |= (0x03 << OMAP24XX_AUTO_96M_SHIFT) |
475 PLL_MOD, CM_AUTOIDLE); 476 (0x03 << OMAP24XX_AUTO_54M_SHIFT);
477 omap2_cm_write_mod_reg(v, PLL_MOD, CM_AUTOIDLE);
476 478
477 omap2_cm_write_mod_reg(OMAP24XX_AUTO_OMAPCTRL_MASK | 479 omap2_cm_write_mod_reg(OMAP24XX_AUTO_OMAPCTRL_MASK |
478 OMAP24XX_AUTO_WDT1_MASK | 480 OMAP24XX_AUTO_WDT1_MASK |