Re: [PATCHv6 6/9] OMAP: Powerdomains: Add support for checking if pwrdm/clkdm can idle
Tero Kristo tero.kri...@nokia.com writes: From: Tero Kristo tero.kri...@nokia.com pwrdm_can_idle(pwrdm) will check if the specified powerdomain can enter idle. This is done by checking all clockdomains under the powerdomain if they can idle also. omap2_clkdm_can_idle(clkdm) will check if the specified clockdomain can enter idle. This checks the functional clocks and idle status bits of the domain according to following rules: 1) functional clock check * get FCLK register content * ignore all clocks defined in idle_def.fclk_ignore * if any active functional clocks remain, domain can't idle 2) idle status check * get IDLEST register content * inverse it (any non-idle blocks are now as 1) * mask against idle_def.idlest_mask * if any bits remain high, domain can't idle These calls can be used e.g. inside cpuidle to decide which power states core and mpu should enter during idle, as there are certain dependencies between wakeup capabilities and reset logic. Signed-off-by: Tero Kristo tero.kri...@nokia.com I'm OK with this version. Paul? Kevin --- arch/arm/mach-omap2/clockdomain.c | 32 arch/arm/mach-omap2/clockdomains.h| 106 + arch/arm/mach-omap2/powerdomain.c | 20 + arch/arm/plat-omap/include/plat/clockdomain.h | 17 arch/arm/plat-omap/include/plat/powerdomain.h |1 + 5 files changed, 176 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-omap2/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c index a38a615..9ebff51 100644 --- a/arch/arm/mach-omap2/clockdomain.c +++ b/arch/arm/mach-omap2/clockdomain.c @@ -867,6 +867,38 @@ int omap2_clkdm_wakeup(struct clockdomain *clkdm) return 0; } + +/** + * omap2_clkdm_can_idle - check if clockdomain has any active clocks or not + * @clkdm: struct clockdomain * + * + * Checks if the clockdomain has any active clock or not, i.e. whether it + * can enter idle. Returns -EINVAL if clkdm is NULL; 0 if unable to idle; + * 1 if can idle. + */ +int omap2_clkdm_can_idle(struct clockdomain *clkdm) +{ + int i; + + if (!clkdm) + return -EINVAL; + + for (i = 0; i clkdm-clk_reg_num; i++) { + u32 idlest, fclk; + + fclk = cm_read_mod_reg(clkdm-pwrdm.ptr-prcm_offs, + CM_FCLKEN + 4 * i); + if (fclk ~clkdm-idle_def[i].fclk_ignore) + return 0; + + idlest = cm_read_mod_reg(clkdm-pwrdm.ptr-prcm_offs, + CM_IDLEST + 4 * i); + if (~idlest clkdm-idle_def[i].idlest_mask) + return 0; + } + return 1; +} + /** * omap2_clkdm_allow_idle - enable hwsup idle transitions for clkdm * @clkdm: struct clockdomain * diff --git a/arch/arm/mach-omap2/clockdomains.h b/arch/arm/mach-omap2/clockdomains.h index 8fc19ff..5e29de8 100644 --- a/arch/arm/mach-omap2/clockdomains.h +++ b/arch/arm/mach-omap2/clockdomains.h @@ -663,6 +663,12 @@ static struct clockdomain iva2_clkdm = { .wkdep_srcs = iva2_wkdeps, .clktrctrl_mask = OMAP3430_CLKTRCTRL_IVA2_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), + .clk_reg_num= 1, + .idle_def = { + [0] = { + .idlest_mask = OMAP3430_ST_IVA2, + }, + }, }; static struct clockdomain gfx_3430es1_clkdm = { @@ -686,6 +692,12 @@ static struct clockdomain sgx_clkdm = { .sleepdep_srcs = gfx_sgx_sleepdeps, .clktrctrl_mask = OMAP3430ES2_CLKTRCTRL_SGX_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_GE_OMAP3430ES2), + .clk_reg_num= 1, + .idle_def = { + [0] = { + .idlest_mask = OMAP3430ES2_ST_SGX_SHIFT, + }, + }, }; /* @@ -717,6 +729,57 @@ static struct clockdomain core_l3_3xxx_clkdm = { .dep_bit= OMAP3430_EN_CORE_SHIFT, .clktrctrl_mask = OMAP3430_CLKTRCTRL_L3_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), + .clk_reg_num= 3, + .idle_def = { + [0] = { + /* UARTs are controlled by idle loop so ignore */ + .fclk_ignore = OMAP3430_EN_UART2 | + OMAP3430_EN_UART1, + /* + * Reason for IDLEST ignores: + * - SDRC and OMAPCTRL controlled by HW + * - HSOTGUSB_IDLE bit is autoidled by HW + * - MAILBOX is controlled by HW + */ + .idlest_mask = + OMAP3430ES2_ST_MMC3_MASK | + OMAP3430_ST_ICR_MASK | + OMAP3430_ST_AES2_MASK | + OMAP3430_ST_SHA12_MASK | + OMAP3430_ST_DES2_MASK
[PATCHv6 6/9] OMAP: Powerdomains: Add support for checking if pwrdm/clkdm can idle
From: Tero Kristo tero.kri...@nokia.com pwrdm_can_idle(pwrdm) will check if the specified powerdomain can enter idle. This is done by checking all clockdomains under the powerdomain if they can idle also. omap2_clkdm_can_idle(clkdm) will check if the specified clockdomain can enter idle. This checks the functional clocks and idle status bits of the domain according to following rules: 1) functional clock check * get FCLK register content * ignore all clocks defined in idle_def.fclk_ignore * if any active functional clocks remain, domain can't idle 2) idle status check * get IDLEST register content * inverse it (any non-idle blocks are now as 1) * mask against idle_def.idlest_mask * if any bits remain high, domain can't idle These calls can be used e.g. inside cpuidle to decide which power states core and mpu should enter during idle, as there are certain dependencies between wakeup capabilities and reset logic. Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/clockdomain.c | 32 arch/arm/mach-omap2/clockdomains.h| 106 + arch/arm/mach-omap2/powerdomain.c | 20 + arch/arm/plat-omap/include/plat/clockdomain.h | 17 arch/arm/plat-omap/include/plat/powerdomain.h |1 + 5 files changed, 176 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-omap2/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c index a38a615..9ebff51 100644 --- a/arch/arm/mach-omap2/clockdomain.c +++ b/arch/arm/mach-omap2/clockdomain.c @@ -867,6 +867,38 @@ int omap2_clkdm_wakeup(struct clockdomain *clkdm) return 0; } + +/** + * omap2_clkdm_can_idle - check if clockdomain has any active clocks or not + * @clkdm: struct clockdomain * + * + * Checks if the clockdomain has any active clock or not, i.e. whether it + * can enter idle. Returns -EINVAL if clkdm is NULL; 0 if unable to idle; + * 1 if can idle. + */ +int omap2_clkdm_can_idle(struct clockdomain *clkdm) +{ + int i; + + if (!clkdm) + return -EINVAL; + + for (i = 0; i clkdm-clk_reg_num; i++) { + u32 idlest, fclk; + + fclk = cm_read_mod_reg(clkdm-pwrdm.ptr-prcm_offs, + CM_FCLKEN + 4 * i); + if (fclk ~clkdm-idle_def[i].fclk_ignore) + return 0; + + idlest = cm_read_mod_reg(clkdm-pwrdm.ptr-prcm_offs, + CM_IDLEST + 4 * i); + if (~idlest clkdm-idle_def[i].idlest_mask) + return 0; + } + return 1; +} + /** * omap2_clkdm_allow_idle - enable hwsup idle transitions for clkdm * @clkdm: struct clockdomain * diff --git a/arch/arm/mach-omap2/clockdomains.h b/arch/arm/mach-omap2/clockdomains.h index 8fc19ff..5e29de8 100644 --- a/arch/arm/mach-omap2/clockdomains.h +++ b/arch/arm/mach-omap2/clockdomains.h @@ -663,6 +663,12 @@ static struct clockdomain iva2_clkdm = { .wkdep_srcs = iva2_wkdeps, .clktrctrl_mask = OMAP3430_CLKTRCTRL_IVA2_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), + .clk_reg_num= 1, + .idle_def = { + [0] = { + .idlest_mask = OMAP3430_ST_IVA2, + }, + }, }; static struct clockdomain gfx_3430es1_clkdm = { @@ -686,6 +692,12 @@ static struct clockdomain sgx_clkdm = { .sleepdep_srcs = gfx_sgx_sleepdeps, .clktrctrl_mask = OMAP3430ES2_CLKTRCTRL_SGX_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_GE_OMAP3430ES2), + .clk_reg_num= 1, + .idle_def = { + [0] = { + .idlest_mask = OMAP3430ES2_ST_SGX_SHIFT, + }, + }, }; /* @@ -717,6 +729,57 @@ static struct clockdomain core_l3_3xxx_clkdm = { .dep_bit= OMAP3430_EN_CORE_SHIFT, .clktrctrl_mask = OMAP3430_CLKTRCTRL_L3_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), + .clk_reg_num= 3, + .idle_def = { + [0] = { + /* UARTs are controlled by idle loop so ignore */ + .fclk_ignore = OMAP3430_EN_UART2 | + OMAP3430_EN_UART1, + /* +* Reason for IDLEST ignores: +* - SDRC and OMAPCTRL controlled by HW +* - HSOTGUSB_IDLE bit is autoidled by HW +* - MAILBOX is controlled by HW +*/ + .idlest_mask = + OMAP3430ES2_ST_MMC3_MASK | + OMAP3430_ST_ICR_MASK | + OMAP3430_ST_AES2_MASK | + OMAP3430_ST_SHA12_MASK | + OMAP3430_ST_DES2_MASK | + OMAP3430_ST_MMC2_MASK | +