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>
This commit is contained in:
parent
c6461f5c59
commit
0fd0c21be7
|
@ -115,7 +115,8 @@ obj-$(CONFIG_ARCH_OMAP2) += $(clock-common) clock2xxx.o \
|
||||||
clkt2xxx_sys.o \
|
clkt2xxx_sys.o \
|
||||||
clkt2xxx_dpllcore.o \
|
clkt2xxx_dpllcore.o \
|
||||||
clkt2xxx_virt_prcm_set.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_OMAP2420) += clock2420_data.o
|
||||||
obj-$(CONFIG_SOC_OMAP2430) += clock2430.o clock2430_data.o
|
obj-$(CONFIG_SOC_OMAP2430) += clock2430.o clock2430_data.o
|
||||||
obj-$(CONFIG_ARCH_OMAP3) += $(clock-common) clock3xxx.o \
|
obj-$(CONFIG_ARCH_OMAP3) += $(clock-common) clock3xxx.o \
|
||||||
|
|
|
@ -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,
|
||||||
|
};
|
||||||
|
|
|
@ -148,6 +148,7 @@ extern void omap2_clk_exit_cpufreq_table(struct cpufreq_frequency_table **table)
|
||||||
#define omap2_clk_exit_cpufreq_table 0
|
#define omap2_clk_exit_cpufreq_table 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
extern const struct clkops clkops_omap2xxx_dpll_ops;
|
||||||
extern const struct clkops clkops_omap3_noncore_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_omap3_core_dpll_ops;
|
||||||
extern const struct clkops clkops_omap4_dpllmx_ops;
|
extern const struct clkops clkops_omap4_dpllmx_ops;
|
||||||
|
|
|
@ -125,7 +125,7 @@ static struct dpll_data dpll_dd = {
|
||||||
*/
|
*/
|
||||||
static struct clk dpll_ck = {
|
static struct clk dpll_ck = {
|
||||||
.name = "dpll_ck",
|
.name = "dpll_ck",
|
||||||
.ops = &clkops_null,
|
.ops = &clkops_omap2xxx_dpll_ops,
|
||||||
.parent = &sys_ck, /* Can be func_32k also */
|
.parent = &sys_ck, /* Can be func_32k also */
|
||||||
.dpll_data = &dpll_dd,
|
.dpll_data = &dpll_dd,
|
||||||
.clkdm_name = "wkup_clkdm",
|
.clkdm_name = "wkup_clkdm",
|
||||||
|
|
|
@ -125,7 +125,7 @@ static struct dpll_data dpll_dd = {
|
||||||
*/
|
*/
|
||||||
static struct clk dpll_ck = {
|
static struct clk dpll_ck = {
|
||||||
.name = "dpll_ck",
|
.name = "dpll_ck",
|
||||||
.ops = &clkops_null,
|
.ops = &clkops_omap2xxx_dpll_ops,
|
||||||
.parent = &sys_ck, /* Can be func_32k also */
|
.parent = &sys_ck, /* Can be func_32k also */
|
||||||
.dpll_data = &dpll_dd,
|
.dpll_data = &dpll_dd,
|
||||||
.clkdm_name = "wkup_clkdm",
|
.clkdm_name = "wkup_clkdm",
|
||||||
|
|
|
@ -25,6 +25,10 @@
|
||||||
#include "cm-regbits-24xx.h"
|
#include "cm-regbits-24xx.h"
|
||||||
#include "cm-regbits-34xx.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[] = {
|
static const u8 cm_idlest_offs[] = {
|
||||||
CM_IDLEST1, CM_IDLEST2, OMAP2430_CM_IDLEST3
|
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);
|
_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);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
|
|
|
@ -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_sleep(s16 module, u32 mask);
|
||||||
extern void omap3xxx_cm_clkdm_force_wakeup(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
|
#endif
|
||||||
|
|
||||||
/* CM register bits shared between 24XX and 3430 */
|
/* CM register bits shared between 24XX and 3430 */
|
||||||
|
|
|
@ -378,6 +378,7 @@ static void __init prcm_setup_regs(void)
|
||||||
{
|
{
|
||||||
int i, num_mem_banks;
|
int i, num_mem_banks;
|
||||||
struct powerdomain *pwrdm;
|
struct powerdomain *pwrdm;
|
||||||
|
u32 v;
|
||||||
|
|
||||||
/* Enable autoidle */
|
/* Enable autoidle */
|
||||||
omap2_prm_write_mod_reg(OMAP24XX_AUTOIDLE_MASK, OCP_MOD,
|
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,
|
omap2_cm_write_mod_reg(OMAP2420_AUTO_DSP_IPI_MASK, OMAP24XX_DSP_MOD,
|
||||||
CM_AUTOIDLE);
|
CM_AUTOIDLE);
|
||||||
|
|
||||||
/* Put DPLL and both APLLs into autoidle mode */
|
/* Put both APLLs into autoidle mode */
|
||||||
omap2_cm_write_mod_reg((0x03 << OMAP24XX_AUTO_DPLL_SHIFT) |
|
v = omap2_cm_read_mod_reg(PLL_MOD, CM_AUTOIDLE);
|
||||||
(0x03 << OMAP24XX_AUTO_96M_SHIFT) |
|
v &= ~(OMAP24XX_AUTO_96M_MASK | OMAP24XX_AUTO_54M_SHIFT);
|
||||||
(0x03 << OMAP24XX_AUTO_54M_SHIFT),
|
v |= (0x03 << OMAP24XX_AUTO_96M_SHIFT) |
|
||||||
PLL_MOD, CM_AUTOIDLE);
|
(0x03 << OMAP24XX_AUTO_54M_SHIFT);
|
||||||
|
omap2_cm_write_mod_reg(v, PLL_MOD, CM_AUTOIDLE);
|
||||||
|
|
||||||
omap2_cm_write_mod_reg(OMAP24XX_AUTO_OMAPCTRL_MASK |
|
omap2_cm_write_mod_reg(OMAP24XX_AUTO_OMAPCTRL_MASK |
|
||||||
OMAP24XX_AUTO_WDT1_MASK |
|
OMAP24XX_AUTO_WDT1_MASK |
|
||||||
|
|
Loading…
Reference in New Issue