This patch adds support for DPLL autoidle control to the OMAP3 clock framework. These functions will be used by the noncore DPLL enable and disable code - this is because, according to the CDP code, the DPLL autoidle status must be saved and restored across DPLL lock/bypass/off transitions. N.B.: the CORE DPLL (DPLL3) has three autoidle mode options, rather than just two. This code currently does not support the third option, low-power bypass autoidle. Signed-off-by: Paul Walmsley <paul@xxxxxxxxx> --- arch/arm/mach-omap2/clock34xx.c | 79 ++++++++++++++++++++++++++++++++++ arch/arm/mach-omap2/clock34xx.h | 14 ++++++ arch/arm/mach-omap2/cm-regbits-34xx.h | 4 + arch/arm/mach-omap2/cm.h | 1 include/asm-arm/arch-omap/clock.h | 2 5 files changed, 100 insertions(+) Index: linux-omap/arch/arm/mach-omap2/clock34xx.c =================================================================== --- linux-omap.orig/arch/arm/mach-omap2/clock34xx.c 2008-03-28 00:40:23.000000000 -0600 +++ linux-omap/arch/arm/mach-omap2/clock34xx.c 2008-03-28 00:42:11.000000000 -0600 @@ -37,6 +37,10 @@ #include "cm.h" #include "cm-regbits-34xx.h" +/* CM_AUTOIDLE_PLL*.AUTO_* bit values */ +#define DPLL_AUTOIDLE_DISABLE 0x0 +#define DPLL_AUTOIDLE_LOW_POWER_STOP 0x1 + /* CM_CLKEN_PLL*.EN* bit values */ #define DPLL_LOCKED 0x7 @@ -54,6 +58,81 @@ } /** + * omap3_dpll_autoidle_read - read a DPLL's autoidle bits + * @clk: struct clk * of the DPLL to read + * + * Return the DPLL's autoidle bits, shifted down to bit 0. Returns + * -EINVAL if passed a null pointer or if the struct clk does not + * appear to refer to a DPLL. + */ +static u32 omap3_dpll_autoidle_read(struct clk *clk) +{ + const struct dpll_data *dd; + u32 v; + + if (!clk || !clk->dpll_data) + return -EINVAL; + + dd = clk->dpll_data; + + v = cm_read_reg(dd->autoidle_reg); + v &= dd->autoidle_mask; + v >>= __ffs(dd->autoidle_mask); + + return v; +} + +/** + * omap3_dpll_allow_idle - enable DPLL autoidle bits + * @clk: struct clk * of the DPLL to operate on + * + * Enable DPLL automatic idle control. This automatic idle mode + * switching takes effect only when the DPLL is locked, at least on + * OMAP3430. The DPLL will enter low-power stop when its downstream + * clocks are gated. No return value. + */ +static void omap3_dpll_allow_idle(struct clk *clk) +{ + const struct dpll_data *dd; + + if (!clk || !clk->dpll_data) + return; + + dd = clk->dpll_data; + + /* + * REVISIT: CORE DPLL can optionally enter low-power bypass + * by writing 0x5 instead of 0x1. Add some mechanism to + * optionally enter this mode. + */ + cm_rmw_reg_bits(dd->autoidle_mask, + DPLL_AUTOIDLE_LOW_POWER_STOP << __ffs(dd->autoidle_mask), + dd->autoidle_reg); +} + +/** + * omap3_dpll_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 omap3_dpll_deny_idle(struct clk *clk) +{ + const struct dpll_data *dd; + + if (!clk || !clk->dpll_data) + return; + + dd = clk->dpll_data; + + cm_rmw_reg_bits(dd->autoidle_mask, + DPLL_AUTOIDLE_DISABLE << __ffs(dd->autoidle_mask), + dd->autoidle_reg); +} + + + +/** * omap3_clkoutx2_recalc - recalculate DPLL X2 output virtual clock rate * @clk: DPLL output struct clk * Index: linux-omap/arch/arm/mach-omap2/clock34xx.h =================================================================== --- linux-omap.orig/arch/arm/mach-omap2/clock34xx.h 2008-03-28 00:42:08.000000000 -0600 +++ linux-omap/arch/arm/mach-omap2/clock34xx.h 2008-03-28 00:42:11.000000000 -0600 @@ -29,6 +29,9 @@ static void omap3_dpll_recalc(struct clk *clk); static void omap3_clkoutx2_recalc(struct clk *clk); +static void omap3_dpll_allow_idle(struct clk *clk); +static void omap3_dpll_deny_idle(struct clk *clk); +static u32 omap3_dpll_autoidle_read(struct clk *clk); /* * DPLL1 supplies clock to the MPU. @@ -254,6 +257,8 @@ .auto_recal_bit = OMAP3430_EN_MPU_DPLL_DRIFTGUARD_SHIFT, .recal_en_bit = OMAP3430_MPU_DPLL_RECAL_EN_SHIFT, .recal_st_bit = OMAP3430_MPU_DPLL_ST_SHIFT, + .autoidle_reg = OMAP_CM_REGADDR(MPU_MOD, OMAP3430_CM_AUTOIDLE_PLL), + .autoidle_mask = OMAP3430_AUTO_MPU_DPLL_MASK, }; static struct clk dpll1_ck = { @@ -311,6 +316,9 @@ .auto_recal_bit = OMAP3430_EN_IVA2_DPLL_DRIFTGUARD_SHIFT, .recal_en_bit = OMAP3430_PRM_IRQENABLE_MPU_IVA2_DPLL_RECAL_EN_SHIFT, .recal_st_bit = OMAP3430_PRM_IRQSTATUS_MPU_IVA2_DPLL_ST_SHIFT, + .autoidle_reg = OMAP_CM_REGADDR(OMAP3430_IVA2_MOD, OMAP3430_CM_AUTOIDLE_PLL), + .autoidle_mask = OMAP3430_AUTO_IVA2_DPLL_MASK, + }; static struct clk dpll2_ck = { @@ -355,6 +363,8 @@ .auto_recal_bit = OMAP3430_EN_CORE_DPLL_DRIFTGUARD_SHIFT, .recal_en_bit = OMAP3430_CORE_DPLL_RECAL_EN_SHIFT, .recal_st_bit = OMAP3430_CORE_DPLL_ST_SHIFT, + .autoidle_reg = OMAP_CM_REGADDR(PLL_MOD, CM_AUTOIDLE), + .autoidle_mask = OMAP3430_AUTO_CORE_DPLL_MASK, }; static struct clk dpll3_ck = { @@ -527,6 +537,8 @@ .auto_recal_bit = OMAP3430_EN_PERIPH_DPLL_DRIFTGUARD_SHIFT, .recal_en_bit = OMAP3430_PERIPH_DPLL_RECAL_EN_SHIFT, .recal_st_bit = OMAP3430_PERIPH_DPLL_ST_SHIFT, + .autoidle_reg = OMAP_CM_REGADDR(PLL_MOD, CM_AUTOIDLE), + .autoidle_mask = OMAP3430_AUTO_PERIPH_DPLL_MASK, }; static struct clk dpll4_ck = { @@ -818,6 +830,8 @@ .auto_recal_bit = OMAP3430ES2_EN_PERIPH2_DPLL_DRIFTGUARD_SHIFT, .recal_en_bit = OMAP3430ES2_SND_PERIPH_DPLL_RECAL_EN_SHIFT, .recal_st_bit = OMAP3430ES2_SND_PERIPH_DPLL_ST_SHIFT, + .autoidle_reg = OMAP_CM_REGADDR(PLL_MOD, OMAP3430ES2_CM_AUTOIDLE2_PLL), + .autoidle_mask = OMAP3430ES2_AUTO_PERIPH2_DPLL_MASK, }; static struct clk dpll5_ck = { Index: linux-omap/arch/arm/mach-omap2/cm-regbits-34xx.h =================================================================== --- linux-omap.orig/arch/arm/mach-omap2/cm-regbits-34xx.h 2008-03-28 00:40:23.000000000 -0600 +++ linux-omap/arch/arm/mach-omap2/cm-regbits-34xx.h 2008-03-28 00:42:11.000000000 -0600 @@ -422,6 +422,10 @@ #define OMAP3430_AUTO_CORE_DPLL_SHIFT 0 #define OMAP3430_AUTO_CORE_DPLL_MASK (0x7 << 0) +/* CM_AUTOIDLE2_PLL */ +#define OMAP3430ES2_AUTO_PERIPH2_DPLL_SHIFT 0 +#define OMAP3430ES2_AUTO_PERIPH2_DPLL_MASK (0x7 << 0) + /* CM_CLKSEL1_PLL */ /* Note that OMAP3430_CORE_DPLL_CLKOUT_DIV_MASK was (0x3 << 27) on 3430ES1 */ #define OMAP3430_CORE_DPLL_CLKOUT_DIV_SHIFT 27 Index: linux-omap/arch/arm/mach-omap2/cm.h =================================================================== --- linux-omap.orig/arch/arm/mach-omap2/cm.h 2008-03-28 00:40:23.000000000 -0600 +++ linux-omap/arch/arm/mach-omap2/cm.h 2008-03-28 00:42:11.000000000 -0600 @@ -112,6 +112,7 @@ #define OMAP3430ES2_CM_FCLKEN3 0x0008 #define OMAP3430_CM_IDLEST_PLL CM_IDLEST2 #define OMAP3430_CM_AUTOIDLE_PLL CM_AUTOIDLE2 +#define OMAP3430ES2_CM_AUTOIDLE2_PLL CM_AUTOIDLE2 #define OMAP3430_CM_CLKSEL1 CM_CLKSEL #define OMAP3430_CM_CLKSEL1_PLL CM_CLKSEL #define OMAP3430_CM_CLKSEL2_PLL CM_CLKSEL2 Index: linux-omap/include/asm-arm/arch-omap/clock.h =================================================================== --- linux-omap.orig/include/asm-arm/arch-omap/clock.h 2008-03-28 00:40:23.000000000 -0600 +++ linux-omap/include/asm-arm/arch-omap/clock.h 2008-03-28 00:42:11.000000000 -0600 @@ -41,6 +41,8 @@ u8 auto_recal_bit; u8 recal_en_bit; u8 recal_st_bit; + void __iomem *autoidle_reg; + u32 autoidle_mask; # endif }; -- -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html