From patchwork Fri Jan 15 12:46:56 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tero Kristo X-Patchwork-Id: 73137 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 o0FAtXPB023068 for ; Fri, 15 Jan 2010 10:55:33 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754849Ab0AOKzc (ORCPT ); Fri, 15 Jan 2010 05:55:32 -0500 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1754445Ab0AOKzb (ORCPT ); Fri, 15 Jan 2010 05:55:31 -0500 Received: from smtp.nokia.com ([192.100.122.230]:22092 "EHLO mgw-mx03.nokia.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752192Ab0AOKza (ORCPT ); Fri, 15 Jan 2010 05:55:30 -0500 Received: from vaebh106.NOE.Nokia.com (vaebh106.europe.nokia.com [10.160.244.32]) by mgw-mx03.nokia.com (Switch-3.3.3/Switch-3.3.3) with ESMTP id o0FAtHos025583; Fri, 15 Jan 2010 12:55:26 +0200 Received: from vaebh104.NOE.Nokia.com ([10.160.244.30]) by vaebh106.NOE.Nokia.com with Microsoft SMTPSVC(6.0.3790.3959); Fri, 15 Jan 2010 12:55:24 +0200 Received: from mgw-sa02.ext.nokia.com ([147.243.1.48]) by vaebh104.NOE.Nokia.com over TLS secured channel with Microsoft SMTPSVC(6.0.3790.3959); Fri, 15 Jan 2010 12:55:23 +0200 Received: from localhost.localdomain (sokoban.nmp.nokia.com [172.22.215.13]) by mgw-sa02.ext.nokia.com (Switch-3.3.3/Switch-3.3.3) with ESMTP id o0FAtE8O003555; Fri, 15 Jan 2010 12:55:22 +0200 From: Tero Kristo To: linux-omap@vger.kernel.org Cc: khilman@deeprootsystems.com Subject: [PATCHv3 5/6] OMAP: Powerdomains: Add support for checking if pwrdm/clkdm can idle Date: Fri, 15 Jan 2010 14:46:56 +0200 Message-Id: <1263559617-663-6-git-send-email-tero.kristo@nokia.com> X-Mailer: git-send-email 1.5.4.3 In-Reply-To: <1263559617-663-5-git-send-email-tero.kristo@nokia.com> References: <> <1263559617-663-1-git-send-email-tero.kristo@nokia.com> <1263559617-663-2-git-send-email-tero.kristo@nokia.com> <1263559617-663-3-git-send-email-tero.kristo@nokia.com> <1263559617-663-4-git-send-email-tero.kristo@nokia.com> <1263559617-663-5-git-send-email-tero.kristo@nokia.com> X-OriginalArrivalTime: 15 Jan 2010 10:55:23.0922 (UTC) FILETIME=[3D18CF20:01CA95D1] 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 dd285f0..f42111a 100644 --- a/arch/arm/mach-omap2/clockdomain.c +++ b/arch/arm/mach-omap2/clockdomain.c @@ -472,6 +472,33 @@ 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_amt; i++) + if (((~cm_read_mod_reg(clkdm->pwrdm.ptr->prcm_offs, + CM_IDLEST + 4 * i) & + clkdm->idle_def[i].mask) | + cm_read_mod_reg(clkdm->pwrdm.ptr->prcm_offs, + CM_FCLKEN + 4 * i)) & + ~clkdm->idle_def[i].ignore) + 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..2c1f2eb 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_amt = 1, + .idle_def = { + [0] = { + .mask = 0x1, + }, + }, }; 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_amt = 1, + .idle_def = { + [0] = { + .mask = 0x1, + }, + }, }; /* @@ -206,6 +218,23 @@ 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_amt = 3, + .idle_def = { + [0] = { + .ignore = OMAP3430_ST_UART2_MASK | + OMAP3430_ST_UART1_MASK | + OMAP3430_ST_SDRC_MASK | + OMAP3430_ST_OMAPCTRL_MASK | + OMAP3430ES2_ST_HSOTGUSB_IDLE_MASK, + .mask = 0xffffffff, + }, + [1] = { + .mask = 0x1f, + }, + [2] = { + .mask = 0x4, + }, + }, }; static struct clockdomain core_l4_34xx_clkdm = { @@ -222,6 +251,12 @@ 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_amt = 1, + .idle_def = { + [0] = { + .mask = 0x1, + }, + }, }; static struct clockdomain cam_clkdm = { @@ -230,6 +265,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_amt = 1, + .idle_def = { + [0] = { + .mask = 0x1, + }, + }, }; static struct clockdomain usbhost_clkdm = { @@ -238,6 +279,12 @@ 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_amt = 1, + .idle_def = { + [0] = { + .mask = 0x1, + }, + }, }; static struct clockdomain per_clkdm = { @@ -246,6 +293,13 @@ 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_amt = 1, + .idle_def = { + [0] = { + .ignore = OMAP3430_ST_UART3_MASK, + .mask = 0x1fff, + }, + }, }; /* diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c index a08d596..46090bc 100644 --- a/arch/arm/mach-omap2/powerdomain.c +++ b/arch/arm/mach-omap2/powerdomain.c @@ -1219,6 +1219,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 eb73482..71cbc5c 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 ignore; + u32 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_amt; + struct clkdm_idle_def idle_def[CLKDM_MAX_CLK_REGS]; + /* Usecount tracking */ atomic_t usecount; @@ -108,4 +123,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 159e4ad..42f5f88 100644 --- a/arch/arm/plat-omap/include/plat/powerdomain.h +++ b/arch/arm/plat-omap/include/plat/powerdomain.h @@ -182,6 +182,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);