From patchwork Mon Mar 25 13:53:16 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michal Simek X-Patchwork-Id: 2331531 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork2.kernel.org Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) by patchwork2.kernel.org (Postfix) with ESMTP id CA1F1DF24C for ; Mon, 25 Mar 2013 14:03:21 +0000 (UTC) Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1UK7wK-0006Gq-Np; Mon, 25 Mar 2013 13:59:56 +0000 Received: from mail-wg0-f43.google.com ([74.125.82.43]) by merlin.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1UK7qS-0003Dw-VQ for linux-arm-kernel@lists.infradead.org; Mon, 25 Mar 2013 13:53:54 +0000 Received: by mail-wg0-f43.google.com with SMTP id e12so937898wge.34 for ; Mon, 25 Mar 2013 06:53:49 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=x-received:sender:from:to:subject:date:message-id:x-mailer :in-reply-to:references:x-gm-message-state; bh=FASej0YyUk/+BAVTFcB5qTj6bDN8xD3O0YrFtqNAWAE=; b=h90N25kbuZQdBsUvnwv7vbynuRbDv30w6EwEElJkHYmTu6cW0xUQTddZLtM8YFT/Lf GTTVoREaxWyj/iwfgv1gjijQR6RqOeVLHswBJM4wmF46uUMZ49GDSUyk3YBVkoqe30Iw AjeuqYEuTXpG+RzoRVRhG3C9TCnQ/fP3SYMZFx5cvSY5YwGERtq5BcwoOqCipz1Jy2jB DJLMWe5fuVCoA5cfHpOL/wqib6ju1gmBNlJrBoV3Zzv1hnOSL9jYjVgISxbFMa8yYE3I 6gaZdUzG9yFnT3qRkUJ8metYvwjPlZE9rO0GE1kCfThi5YfUCENKZZC0u2JYYDJk3PjR 145g== X-Received: by 10.194.20.40 with SMTP id k8mr18322433wje.16.1364219629586; Mon, 25 Mar 2013 06:53:49 -0700 (PDT) Received: from localhost (nat-63.starnet.cz. [178.255.168.63]) by mx.google.com with ESMTPS id n2sm28081515wiy.6.2013.03.25.06.53.47 (version=TLSv1.1 cipher=RC4-SHA bits=128/128); Mon, 25 Mar 2013 06:53:48 -0700 (PDT) From: Michal Simek To: linux-arm-kernel@lists.infradead.org, monstr@monstr.eu, Josh Cartwright , Steffen Trumtrar Subject: [PATCH 10/10] arm: zynq: Add cpuidle support Date: Mon, 25 Mar 2013 14:53:16 +0100 Message-Id: <1364219596-4954-10-git-send-email-michal.simek@xilinx.com> X-Mailer: git-send-email 1.7.9.7 In-Reply-To: <1364219596-4954-1-git-send-email-michal.simek@xilinx.com> References: <1364219596-4954-1-git-send-email-michal.simek@xilinx.com> X-Gm-Message-State: ALoCoQnHrpAZKRG/3/TkIABMYfFxDcRBLuP3/SoLgpR1125KatvuMC3w+RfLbGjVOktAZ5mx75EK X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20130325_095353_175556_0698AD6A X-CRM114-Status: GOOD ( 19.51 ) X-Spam-Score: -2.6 (--) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-2.6 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.7 RCVD_IN_DNSWL_LOW RBL: Sender listed at http://www.dnswl.org/, low trust [74.125.82.43 listed in list.dnswl.org] -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org Add support for cpuidle. Signed-off-by: Michal Simek --- arch/arm/mach-zynq/Makefile | 1 + arch/arm/mach-zynq/cpuidle.c | 131 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 132 insertions(+) create mode 100644 arch/arm/mach-zynq/cpuidle.c diff --git a/arch/arm/mach-zynq/Makefile b/arch/arm/mach-zynq/Makefile index 8e75490..a085d86 100644 --- a/arch/arm/mach-zynq/Makefile +++ b/arch/arm/mach-zynq/Makefile @@ -4,5 +4,6 @@ # Common support obj-y := common.o slcr.o +obj-$(CONFIG_CPU_IDLE) += cpuidle.o obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o obj-$(CONFIG_SMP) += platsmp.o diff --git a/arch/arm/mach-zynq/cpuidle.c b/arch/arm/mach-zynq/cpuidle.c new file mode 100644 index 0000000..24f0333 --- /dev/null +++ b/arch/arm/mach-zynq/cpuidle.c @@ -0,0 +1,131 @@ +/* + * based on arch/arm/mach-at91/cpuidle.c + * + * CPU idle support for Xilinx + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + * + * The cpu idle uses wait-for-interrupt and RAM self refresh in order + * to implement two idle states - + * #1 wait-for-interrupt + * #2 wait-for-interrupt and RAM self refresh + * + * Note that this code is only intended as a prototype and is not tested + * well yet, or tuned for the Xilinx Cortex A9. Also note that for a + * tickless kernel, high res timers must not be turned on. The cpuidle + * framework must also be turned on in the kernel. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define XILINX_MAX_STATES 1 + +static DEFINE_PER_CPU(struct cpuidle_device, xilinx_cpuidle_device); + +/* Actual code that puts the SoC in different idle states */ +static int xilinx_enter_idle(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int index) +{ + struct timeval before, after; + int idle_time; + + local_irq_disable(); + do_gettimeofday(&before); + + if (index == 0) + /* Wait for interrupt state */ + cpu_do_idle(); + + else if (index == 1) { + unsigned int cpu_id = smp_processor_id(); + + clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu_id); + + /* Devices must be stopped here */ + cpu_pm_enter(); + + /* Add code for DDR self refresh start */ + + cpu_do_idle(); + /*cpu_suspend(foo, bar);*/ + + /* Add code for DDR self refresh stop */ + + cpu_pm_exit(); + + clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu_id); + } + + do_gettimeofday(&after); + local_irq_enable(); + idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC + + (after.tv_usec - before.tv_usec); + + dev->last_residency = idle_time; + return index; +} + +static struct cpuidle_driver xilinx_idle_driver = { + .name = "xilinx_idle", + .owner = THIS_MODULE, + .state_count = XILINX_MAX_STATES, + /* Wait for interrupt state */ + .states[0] = { + .enter = xilinx_enter_idle, + .exit_latency = 1, + .target_residency = 10000, + .flags = CPUIDLE_FLAG_TIME_VALID, + .name = "WFI", + .desc = "Wait for interrupt", + }, + /* Wait for interrupt and RAM self refresh state */ + .states[1] = { + .enter = xilinx_enter_idle, + .exit_latency = 10, + .target_residency = 10000, + .flags = CPUIDLE_FLAG_TIME_VALID, + .name = "RAM_SR", + .desc = "WFI and RAM Self Refresh", + }, +}; + +/* Initialize CPU idle by registering the idle states */ +static int xilinx_init_cpuidle(void) +{ + unsigned int cpu; + struct cpuidle_device *device; + int ret; + + ret = cpuidle_register_driver(&xilinx_idle_driver); + if (ret) { + pr_err("Registering Xilinx CpuIdle Driver failed.\n"); + return ret; + } + + for_each_possible_cpu(cpu) { + device = &per_cpu(xilinx_cpuidle_device, cpu); + device->state_count = XILINX_MAX_STATES; + device->cpu = cpu; + ret = cpuidle_register_device(device); + if (ret) { + pr_err("xilinx_init_cpuidle: Failed registering\n"); + return ret; + } + } + + pr_info("Xilinx CpuIdle Driver started\n"); + return 0; +} +device_initcall(xilinx_init_cpuidle);