From patchwork Fri Jan 22 17:55:50 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tero Kristo X-Patchwork-Id: 74686 X-Patchwork-Delegate: khilman@deeprootsystems.com Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter.kernel.org (8.14.3/8.14.2) with ESMTP id o0MG5lSQ022637 for ; Fri, 22 Jan 2010 16:05:47 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755795Ab0AVQFo (ORCPT ); Fri, 22 Jan 2010 11:05:44 -0500 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1755811Ab0AVQFn (ORCPT ); Fri, 22 Jan 2010 11:05:43 -0500 Received: from smtp.nokia.com ([192.100.105.134]:59872 "EHLO mgw-mx09.nokia.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755795Ab0AVQFm (ORCPT ); Fri, 22 Jan 2010 11:05:42 -0500 Received: from esebh105.NOE.Nokia.com (esebh105.ntc.nokia.com [172.21.138.211]) by mgw-mx09.nokia.com (Switch-3.3.3/Switch-3.3.3) with ESMTP id o0MG5DV6020487 for ; Fri, 22 Jan 2010 10:05:41 -0600 Received: from vaebh104.NOE.Nokia.com ([10.160.244.30]) by esebh105.NOE.Nokia.com with Microsoft SMTPSVC(6.0.3790.3959); Fri, 22 Jan 2010 18:05:13 +0200 Received: from mgw-da01.ext.nokia.com ([147.243.128.24]) by vaebh104.NOE.Nokia.com over TLS secured channel with Microsoft SMTPSVC(6.0.3790.3959); Fri, 22 Jan 2010 18:05:11 +0200 Received: from localhost.localdomain (sokoban.nmp.nokia.com [172.22.215.13]) by mgw-da01.ext.nokia.com (Switch-3.3.3/Switch-3.3.3) with ESMTP id o0MG51XP002591 for ; Fri, 22 Jan 2010 18:05:09 +0200 From: Tero Kristo To: linux-omap@vger.kernel.org Subject: [PATCHv4 7/8] OMAP: Powerdomains: Add support for checking if pwrdm/clkdm can idle Date: Fri, 22 Jan 2010 19:55:50 +0200 Message-Id: <1264182951-9205-8-git-send-email-tero.kristo@nokia.com> X-Mailer: git-send-email 1.5.4.3 In-Reply-To: <1264182951-9205-7-git-send-email-tero.kristo@nokia.com> References: <> <1264182951-9205-1-git-send-email-tero.kristo@nokia.com> <1264182951-9205-2-git-send-email-tero.kristo@nokia.com> <1264182951-9205-3-git-send-email-tero.kristo@nokia.com> <1264182951-9205-4-git-send-email-tero.kristo@nokia.com> <1264182951-9205-5-git-send-email-tero.kristo@nokia.com> <1264182951-9205-6-git-send-email-tero.kristo@nokia.com> <1264182951-9205-7-git-send-email-tero.kristo@nokia.com> X-OriginalArrivalTime: 22 Jan 2010 16:05:12.0527 (UTC) FILETIME=[ADA915F0:01CA9B7C] X-Nokia-AV: Clean Sender: linux-omap-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-omap@vger.kernel.org diff --git a/arch/arm/mach-omap2/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c index 728d1b0..5665755 100644 --- a/arch/arm/mach-omap2/clockdomain.c +++ b/arch/arm/mach-omap2/clockdomain.c @@ -499,6 +499,38 @@ int omap2_clkdm_get_hwsup(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 c4ee076..91efc60 100644 --- a/arch/arm/mach-omap2/clockdomains.h +++ b/arch/arm/mach-omap2/clockdomains.h @@ -167,6 +167,12 @@ static struct clockdomain iva2_clkdm = { .flags = CLKDM_CAN_HWSUP_SWSUP, .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 = { @@ -183,6 +189,12 @@ static struct clockdomain sgx_clkdm = { .flags = CLKDM_CAN_HWSUP_SWSUP, .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, + }, + }, }; /* @@ -206,6 +218,57 @@ static struct clockdomain core_l3_34xx_clkdm = { .flags = CLKDM_CAN_HWSUP, .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 + */ + .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 | + OMAP3430_ST_MMC1_MASK | + OMAP3430_ST_MSPRO_MASK | + OMAP3430_ST_HDQ_MASK | + OMAP3430_ST_MCSPI4_MASK | + OMAP3430_ST_MCSPI3_MASK | + OMAP3430_ST_MCSPI2_MASK | + OMAP3430_ST_MCSPI1_MASK | + OMAP3430_ST_I2C3_MASK | + OMAP3430_ST_I2C2_MASK | + OMAP3430_ST_I2C1_MASK | + OMAP3430_ST_GPT11_MASK | + OMAP3430_ST_GPT10_MASK | + OMAP3430_ST_MCBSP5_MASK | + OMAP3430_ST_MCBSP1_MASK | + OMAP3430ES2_ST_SSI_IDLE_MASK | + OMAP3430_ST_MAILBOXES_MASK | + OMAP3430ES2_ST_HSOTGUSB_STDBY_MASK | + OMAP3430_ST_D2D_MASK | + OMAP3430_ST_SDMA_MASK | + OMAP3430_ST_SSI_STDBY_MASK, + }, + [1] = { + .idlest_mask = OMAP3430_ST_PKA_MASK | + OMAP3430_ST_AES1_MASK | + OMAP3430_ST_RNG_MASK | + OMAP3430_ST_SHA11_MASK | + OMAP3430_ST_DES1_MASK, + }, + [2] = { + .idlest_mask = OMAP3430ES2_ST_USBTLL_MASK | + OMAP3430ES2_ST_CPEFUSE_MASK, + }, + }, }; static struct clockdomain core_l4_34xx_clkdm = { @@ -222,6 +285,13 @@ static struct clockdomain dss_34xx_clkdm = { .flags = CLKDM_CAN_HWSUP_SWSUP, .clktrctrl_mask = OMAP3430_CLKTRCTRL_DSS_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), + .clk_reg_num = 1, + .idle_def = { + [0] = { + .idlest_mask = OMAP3430ES2_ST_DSS_IDLE_MASK | + OMAP3430ES2_ST_DSS_STDBY_MASK, + }, + }, }; static struct clockdomain cam_clkdm = { @@ -230,6 +300,12 @@ static struct clockdomain cam_clkdm = { .flags = CLKDM_CAN_HWSUP_SWSUP, .clktrctrl_mask = OMAP3430_CLKTRCTRL_CAM_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), + .clk_reg_num = 1, + .idle_def = { + [0] = { + .idlest_mask = OMAP3430_ST_CAM, + }, + }, }; static struct clockdomain usbhost_clkdm = { @@ -238,6 +314,13 @@ static struct clockdomain usbhost_clkdm = { .flags = CLKDM_CAN_HWSUP_SWSUP, .clktrctrl_mask = OMAP3430ES2_CLKTRCTRL_USBHOST_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_GE_OMAP3430ES2), + .clk_reg_num = 1, + .idle_def = { + [0] = { + .idlest_mask = OMAP3430ES2_ST_USBHOST_IDLE_MASK | + OMAP3430ES2_ST_USBHOST_STDBY_MASK, + }, + }, }; static struct clockdomain per_clkdm = { @@ -246,6 +329,29 @@ static struct clockdomain per_clkdm = { .flags = CLKDM_CAN_HWSUP_SWSUP, .clktrctrl_mask = OMAP3430_CLKTRCTRL_PER_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), + .clk_reg_num = 1, + .idle_def = { + [0] = { + .fclk_ignore = OMAP3430_ST_UART3_MASK, + /* + * GPIO2...6 are dropped out from this mask + * as they are always non-idle, UART3 is also + * out as it is handled by idle loop + * */ + .idlest_mask = OMAP3430_ST_WDT3_MASK | + OMAP3430_ST_GPT9_MASK | + OMAP3430_ST_GPT8_MASK | + OMAP3430_ST_GPT7_MASK | + OMAP3430_ST_GPT6_MASK | + OMAP3430_ST_GPT5_MASK | + OMAP3430_ST_GPT4_MASK | + OMAP3430_ST_GPT3_MASK | + OMAP3430_ST_GPT2_MASK | + OMAP3430_ST_MCBSP4_MASK | + OMAP3430_ST_MCBSP3_MASK | + OMAP3430_ST_MCBSP2_MASK, + }, + }, }; /* diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c index bdfbbea..2cefa2d 100644 --- a/arch/arm/mach-omap2/powerdomain.c +++ b/arch/arm/mach-omap2/powerdomain.c @@ -1224,6 +1224,31 @@ int pwrdm_wait_transition(struct powerdomain *pwrdm) return 0; } +/** + * pwrdm_can_idle - check if the powerdomain can enter idle + * @pwrdm: struct powerdomain * the powerdomain to check status of + * + * Checks all associated clockdomains if they can idle or not. + * Returns 1 if the powerdomain can idle, 0 if not. + */ +int pwrdm_can_idle(struct powerdomain *pwrdm) +{ + unsigned long flags; + int i; + int ret = 1; + + read_lock_irqsave(&pwrdm_rwlock, flags); + + for (i = 0; i < PWRDM_MAX_CLKDMS; i++) + if (pwrdm->pwrdm_clkdms[i] && + !omap2_clkdm_can_idle(pwrdm->pwrdm_clkdms[i])) + ret = 0; + + read_unlock_irqrestore(&pwrdm_rwlock, flags); + + return ret; +} + int pwrdm_state_switch(struct powerdomain *pwrdm) { return _pwrdm_state_switch(pwrdm, PWRDM_STATE_NOW); diff --git a/arch/arm/plat-omap/include/plat/clockdomain.h b/arch/arm/plat-omap/include/plat/clockdomain.h index 9127459..804d962 100644 --- a/arch/arm/plat-omap/include/plat/clockdomain.h +++ b/arch/arm/plat-omap/include/plat/clockdomain.h @@ -30,6 +30,12 @@ #define CLKDM_CAN_SWSUP (CLKDM_CAN_FORCE_SLEEP | CLKDM_CAN_FORCE_WAKEUP) #define CLKDM_CAN_HWSUP_SWSUP (CLKDM_CAN_SWSUP | CLKDM_CAN_HWSUP) +/* + * Maximum number of FCLK register masks that can be associated with a + * clockdomain. CORE powerdomain on OMAP3 is the worst case + */ +#define CLKDM_MAX_CLK_REGS 3 + /* OMAP24XX CM_CLKSTCTRL_*.AUTOSTATE_* register bit values */ #define OMAP24XX_CLKSTCTRL_DISABLE_AUTO 0x0 #define OMAP24XX_CLKSTCTRL_ENABLE_AUTO 0x1 @@ -61,6 +67,11 @@ struct clkdm_pwrdm_autodep { }; +struct clkdm_idle_def { + u32 fclk_ignore; + u32 idlest_mask; +}; + struct clockdomain { /* Clockdomain name */ @@ -83,6 +94,10 @@ struct clockdomain { /* OMAP chip types that this clockdomain is valid on */ const struct omap_chip_id omap_chip; + /* For idle checks */ + u8 clk_reg_num; + struct clkdm_idle_def idle_def[CLKDM_MAX_CLK_REGS]; + /* Usecount tracking */ atomic_t usecount; @@ -109,4 +124,6 @@ int omap2_clkdm_sleep(struct clockdomain *clkdm); int omap2_clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk); int omap2_clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk); +int omap2_clkdm_can_idle(struct clockdomain *clkdm); + #endif diff --git a/arch/arm/plat-omap/include/plat/powerdomain.h b/arch/arm/plat-omap/include/plat/powerdomain.h index 17377c3..bf7c41b 100644 --- a/arch/arm/plat-omap/include/plat/powerdomain.h +++ b/arch/arm/plat-omap/include/plat/powerdomain.h @@ -183,6 +183,7 @@ int pwrdm_disable_hdwr_sar(struct powerdomain *pwrdm); bool pwrdm_has_hdwr_sar(struct powerdomain *pwrdm); int pwrdm_wait_transition(struct powerdomain *pwrdm); +int pwrdm_can_idle(struct powerdomain *pwrdm); int pwrdm_state_switch(struct powerdomain *pwrdm); int pwrdm_clkdm_state_switch(struct clockdomain *clkdm);