From patchwork Sat Feb 19 10:42:35 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Santosh Shilimkar X-Patchwork-Id: 574671 X-Patchwork-Delegate: khilman@deeprootsystems.com Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id p1JAguIo032649 for ; Sat, 19 Feb 2011 10:43:20 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754176Ab1BSKnK (ORCPT ); Sat, 19 Feb 2011 05:43:10 -0500 Received: from devils.ext.ti.com ([198.47.26.153]:48725 "EHLO devils.ext.ti.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753997Ab1BSKnE (ORCPT ); Sat, 19 Feb 2011 05:43:04 -0500 Received: from dbdp31.itg.ti.com ([172.24.170.98]) by devils.ext.ti.com (8.13.7/8.13.7) with ESMTP id p1JAghj3025992 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Sat, 19 Feb 2011 04:42:45 -0600 Received: from linfarm476.india.ti.com (localhost [127.0.0.1]) by dbdp31.itg.ti.com (8.13.8/8.13.8) with ESMTP id p1JAggwK013958; Sat, 19 Feb 2011 16:12:42 +0530 (IST) Received: from linfarm476.india.ti.com (localhost [127.0.0.1]) by linfarm476.india.ti.com (8.12.11/8.12.11) with ESMTP id p1JAggcX028619; Sat, 19 Feb 2011 16:12:42 +0530 Received: (from a0393909@localhost) by linfarm476.india.ti.com (8.12.11/8.12.11/Submit) id p1JAgg3Q028616; Sat, 19 Feb 2011 16:12:42 +0530 From: Santosh Shilimkar To: linux-omap@vger.kernel.org Cc: khilman@ti.com, linux-arm-kernel@lists.infradead.org, Santosh Shilimkar , Rajendra Nayak Subject: [PATCH 14/17] omap4: cpuidle: Add MPUSS RET OFF states Date: Sat, 19 Feb 2011 16:12:35 +0530 Message-Id: <1298112158-28469-15-git-send-email-santosh.shilimkar@ti.com> X-Mailer: git-send-email 1.5.6.6 In-Reply-To: <1298112158-28469-1-git-send-email-santosh.shilimkar@ti.com> References: <1298112158-28469-1-git-send-email-santosh.shilimkar@ti.com> Sender: linux-omap-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-omap@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter1.kernel.org [140.211.167.41]); Sat, 19 Feb 2011 10:43:21 +0000 (UTC) diff --git a/arch/arm/mach-omap2/cpuidle44xx.c b/arch/arm/mach-omap2/cpuidle44xx.c index 6c3c69d..aa1584e 100644 --- a/arch/arm/mach-omap2/cpuidle44xx.c +++ b/arch/arm/mach-omap2/cpuidle44xx.c @@ -3,6 +3,7 @@ * * Copyright (C) 2011 Texas Instruments, Inc. * Rajendra Nayak + * Santosh Shilimkar * * 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 @@ -17,12 +18,21 @@ #include #include "pm.h" +#include "prm.h" #ifdef CONFIG_CPU_IDLE -#define OMAP4_MAX_STATES 1 -/* C1 - CPUx wfi + MPU inactive + CORE inactive */ +#define CPUIDLE_FLAG_CHECK_BM 0x10000 /* use omap4_enter_idle_bm() */ +#define OMAP4_MAX_STATES 4 + +/* C1 - CPU0 ON + CPU1 ON/OFF + MPU ON + CORE ON */ #define OMAP4_STATE_C1 0 +/* C2 - CPU0 ON + CPU1 OFF + MPU ON + CORE ON */ +#define OMAP4_STATE_C2 1 +/* C3 - CPU0 OFF + CPU1 OFF + MPU CSWR + CORE ON */ +#define OMAP4_STATE_C3 2 +/* C4 - CPU0 OFF + CPU1 OFF + MPU OFF + CORE ON */ +#define OMAP4_STATE_C4 3 struct omap4_processor_cx { u8 valid; @@ -32,19 +42,44 @@ struct omap4_processor_cx { u32 cpu0_state; u32 cpu1_state; u32 mpu_state; + u32 mpu_logic_state; u32 core_state; + u32 core_logic_state; u32 threshold; u32 flags; + const char *desc; }; -struct omap4_processor_cx omap4_power_states[OMAP4_MAX_STATES]; -struct omap4_processor_cx current_cx_state; +static struct omap4_processor_cx omap4_power_states[OMAP4_MAX_STATES]; +static struct powerdomain *mpu_pd, *cpu1_pd, *core_pd; +/* + * FIXME: Full latenecy numbers needs to be updated as part of + * cpuidle CORE retention support. + * Currently only MPUSS latency numbers are added based on + * measurements done internally. The numbers for MPUSS are + * not board dependent and hence set directly here instead of + * passing it from board files. + */ static struct cpuidle_params cpuidle_params_table[] = { - /* C1 */ - {1, 2, 2, 5}, + /* C1 - CPU0 WFI + CPU1 ON/OFF + MPU ON + CORE ON */ + {1, 2, 2, 5}, + /* C2 - CPU0 ON + CPU1 OFF + MPU ON + CORE ON */ + {1, 140, 160, 300}, + /* C3 - CPU0 OFF + CPU1 OFF + MPU CSWR + CORE ON */ + {1, 200, 300, 700}, + /* C4 - CPU0 OFF + CPU1 OFF + MPU OFF + CORE ON */ + {1, 1400, 600, 5000}, }; +DEFINE_PER_CPU(struct cpuidle_device, omap4_idle_dev); + +static int omap4_idle_bm_check(void) +{ + /* FIXME: Populate this with CORE retention support */ + return 0; +} + /** * omap4_enter_idle - Programs OMAP4 to enter the specified state * @dev: cpuidle device @@ -57,7 +92,9 @@ static struct cpuidle_params cpuidle_params_table[] = { static int omap4_enter_idle(struct cpuidle_device *dev, struct cpuidle_state *state) { + struct omap4_processor_cx *cx = cpuidle_get_statedata(state); struct timespec ts_preidle, ts_postidle, ts_idle; + u32 cpu1_state; /* Used to keep track of the total time in idle */ getnstimeofday(&ts_preidle); @@ -65,28 +102,74 @@ static int omap4_enter_idle(struct cpuidle_device *dev, local_irq_disable(); local_fiq_disable(); - cpu_do_idle(); + /* + * Special hardware/software considerations: + * 1. Do only WFI for secondary CPU(non-boot - CPU1). + * Secondary cores are taken down only via hotplug path. + * 2. Do only a WFI as long as in SMP mode. + * 3. Continue to do only WFI till CPU1 hits OFF state. + * This is necessary to honour hardware recommondation + * of triggeing all the possible low power modes once CPU1 is + * out of coherency and in OFF mode. + * Update dev->last_state so that governor stats reflects right + * data. + */ + cpu1_state = pwrdm_read_pwrst(cpu1_pd); + if ((dev->cpu) || (num_online_cpus() > 1) || + (cpu1_state != PWRDM_POWER_OFF)) { + dev->last_state = dev->safe_state; + cpu_do_idle(); + goto return_sleep_time; + } + pwrdm_set_logic_retst(mpu_pd, cx->mpu_logic_state); + omap_set_pwrdm_state(mpu_pd, cx->mpu_state); + pwrdm_set_logic_retst(core_pd, cx->core_logic_state); + omap_set_pwrdm_state(core_pd, cx->core_state); + + omap4_enter_lowpower(dev->cpu, cx->cpu0_state); + +return_sleep_time: getnstimeofday(&ts_postidle); ts_idle = timespec_sub(ts_postidle, ts_preidle); local_irq_enable(); local_fiq_enable(); + return ts_idle.tv_nsec / NSEC_PER_USEC + ts_idle.tv_sec * USEC_PER_SEC; } -DEFINE_PER_CPU(struct cpuidle_device, omap4_idle_dev); +/** + * omap4_enter_idle_bm - Checks for any bus activity + * @dev: cpuidle device + * @state: The target state to be programmed + * + * Used for C states with CPUIDLE_FLAG_CHECK_BM flag set. This + * function checks for any pending activity and then programs the + * device to the specified or a safer state. + */ +static int omap4_enter_idle_bm(struct cpuidle_device *dev, + struct cpuidle_state *state) +{ + if ((state->flags & CPUIDLE_FLAG_CHECK_BM) && omap4_idle_bm_check()) { + BUG_ON(!dev->safe_state); + state = dev->safe_state; + } + + dev->last_state = state; + return omap4_enter_idle(dev, state); +} /** * omap4_init_power_states - Initialises the OMAP4 specific C states. * - * Below is the desciption of each C state. - * C1 : CPUx wfi + MPU inative + Core inactive */ -void omap_init_power_states(void) +void omap4_init_power_states(void) { - /* C1 . CPUx wfi + MPU inactive + Core inactive */ + /* + * C1 - CPU0 WFI + CPU1 OFF + MPU ON + CORE ON + */ omap4_power_states[OMAP4_STATE_C1].valid = cpuidle_params_table[OMAP4_STATE_C1].valid; omap4_power_states[OMAP4_STATE_C1].type = OMAP4_STATE_C1; @@ -96,9 +179,80 @@ void omap_init_power_states(void) cpuidle_params_table[OMAP4_STATE_C1].wake_latency; omap4_power_states[OMAP4_STATE_C1].threshold = cpuidle_params_table[OMAP4_STATE_C1].threshold; + omap4_power_states[OMAP4_STATE_C1].cpu0_state = PWRDM_POWER_ON; + omap4_power_states[OMAP4_STATE_C1].cpu1_state = PWRDM_POWER_OFF; omap4_power_states[OMAP4_STATE_C1].mpu_state = PWRDM_POWER_ON; + omap4_power_states[OMAP4_STATE_C1].mpu_logic_state = PWRDM_POWER_RET; omap4_power_states[OMAP4_STATE_C1].core_state = PWRDM_POWER_ON; + omap4_power_states[OMAP4_STATE_C1].core_logic_state = PWRDM_POWER_RET; omap4_power_states[OMAP4_STATE_C1].flags = CPUIDLE_FLAG_TIME_VALID; + omap4_power_states[OMAP4_STATE_C1].desc = "MPU ON + CORE ON"; + + /* + * C2 - CPU0 ON + CPU1 OFF + MPU ON + CORE ON + */ + omap4_power_states[OMAP4_STATE_C2].valid = + cpuidle_params_table[OMAP4_STATE_C2].valid; + omap4_power_states[OMAP4_STATE_C2].type = OMAP4_STATE_C2; + omap4_power_states[OMAP4_STATE_C2].sleep_latency = + cpuidle_params_table[OMAP4_STATE_C2].sleep_latency; + omap4_power_states[OMAP4_STATE_C2].wakeup_latency = + cpuidle_params_table[OMAP4_STATE_C2].wake_latency; + omap4_power_states[OMAP4_STATE_C2].threshold = + cpuidle_params_table[OMAP4_STATE_C2].threshold; + omap4_power_states[OMAP4_STATE_C2].cpu0_state = PWRDM_POWER_ON; + omap4_power_states[OMAP4_STATE_C2].cpu1_state = PWRDM_POWER_OFF; + omap4_power_states[OMAP4_STATE_C2].mpu_state = PWRDM_POWER_ON; + omap4_power_states[OMAP4_STATE_C2].mpu_logic_state = PWRDM_POWER_RET; + omap4_power_states[OMAP4_STATE_C2].core_state = PWRDM_POWER_ON; + omap4_power_states[OMAP4_STATE_C2].core_logic_state = PWRDM_POWER_RET; + omap4_power_states[OMAP4_STATE_C2].flags = CPUIDLE_FLAG_TIME_VALID | + CPUIDLE_FLAG_CHECK_BM; + omap4_power_states[OMAP4_STATE_C2].desc = "MPU ON + CORE ON"; + + /* + * C3 - CPU0 OFF + CPU1 OFF + MPU CSWR + CORE ON + */ + omap4_power_states[OMAP4_STATE_C3].valid = + cpuidle_params_table[OMAP4_STATE_C3].valid; + omap4_power_states[OMAP4_STATE_C3].type = OMAP4_STATE_C3; + omap4_power_states[OMAP4_STATE_C3].sleep_latency = + cpuidle_params_table[OMAP4_STATE_C3].sleep_latency; + omap4_power_states[OMAP4_STATE_C3].wakeup_latency = + cpuidle_params_table[OMAP4_STATE_C3].wake_latency; + omap4_power_states[OMAP4_STATE_C3].threshold = + cpuidle_params_table[OMAP4_STATE_C3].threshold; + omap4_power_states[OMAP4_STATE_C3].cpu0_state = PWRDM_POWER_OFF; + omap4_power_states[OMAP4_STATE_C3].cpu1_state = PWRDM_POWER_OFF; + omap4_power_states[OMAP4_STATE_C3].mpu_state = PWRDM_POWER_RET; + omap4_power_states[OMAP4_STATE_C3].mpu_logic_state = PWRDM_POWER_RET; + omap4_power_states[OMAP4_STATE_C3].core_state = PWRDM_POWER_ON; + omap4_power_states[OMAP4_STATE_C3].core_logic_state = PWRDM_POWER_RET; + omap4_power_states[OMAP4_STATE_C3].flags = CPUIDLE_FLAG_TIME_VALID | + CPUIDLE_FLAG_CHECK_BM; + omap4_power_states[OMAP4_STATE_C3].desc = "MPU CSWR + CORE ON"; + + /* + * C4 - CPU0 OFF + CPU1 OFF + MPU OFF + CORE ON + */ + omap4_power_states[OMAP4_STATE_C4].valid = + cpuidle_params_table[OMAP4_STATE_C4].valid; + omap4_power_states[OMAP4_STATE_C4].type = OMAP4_STATE_C4; + omap4_power_states[OMAP4_STATE_C4].sleep_latency = + cpuidle_params_table[OMAP4_STATE_C4].sleep_latency; + omap4_power_states[OMAP4_STATE_C4].wakeup_latency = + cpuidle_params_table[OMAP4_STATE_C4].wake_latency; + omap4_power_states[OMAP4_STATE_C4].threshold = + cpuidle_params_table[OMAP4_STATE_C4].threshold; + omap4_power_states[OMAP4_STATE_C4].cpu0_state = PWRDM_POWER_OFF; + omap4_power_states[OMAP4_STATE_C4].cpu1_state = PWRDM_POWER_OFF; + omap4_power_states[OMAP4_STATE_C4].mpu_state = PWRDM_POWER_OFF; + omap4_power_states[OMAP4_STATE_C4].mpu_logic_state = PWRDM_POWER_OFF; + omap4_power_states[OMAP4_STATE_C4].core_state = PWRDM_POWER_ON; + omap4_power_states[OMAP4_STATE_C4].core_logic_state = PWRDM_POWER_RET; + omap4_power_states[OMAP4_STATE_C4].flags = CPUIDLE_FLAG_TIME_VALID | + CPUIDLE_FLAG_CHECK_BM; + omap4_power_states[OMAP4_STATE_C4].desc = "MPU OFF + CORE ON"; } @@ -120,7 +274,11 @@ int __init omap4_idle_init(void) struct cpuidle_state *state; struct cpuidle_device *dev; - omap_init_power_states(); + mpu_pd = pwrdm_lookup("mpu_pwrdm"); + cpu1_pd = pwrdm_lookup("cpu1_pwrdm"); + core_pd = pwrdm_lookup("core_pwrdm"); + + omap4_init_power_states(); cpuidle_register_driver(&omap4_idle_driver); for_each_cpu(cpu_id, cpu_online_mask) { @@ -139,8 +297,12 @@ int __init omap4_idle_init(void) cx->wakeup_latency; state->target_residency = cx->threshold; state->flags = cx->flags; - state->enter = omap4_enter_idle; + if (cx->type == OMAP4_STATE_C1) + dev->safe_state = state; + state->enter = (state->flags & CPUIDLE_FLAG_CHECK_BM) ? + omap4_enter_idle_bm : omap4_enter_idle; sprintf(state->name, "C%d", count+1); + strncpy(state->desc, cx->desc, CPUIDLE_DESC_LEN); count++; }