From patchwork Tue Mar 26 17:43:42 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michal Simek X-Patchwork-Id: 2342511 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) by patchwork1.kernel.org (Postfix) with ESMTP id 527793FD40 for ; Tue, 26 Mar 2013 17:51:04 +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 1UKXyP-0001hA-HH; Tue, 26 Mar 2013 17:47:50 +0000 Received: from mail-wi0-x22a.google.com ([2a00:1450:400c:c05::22a]) by merlin.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1UKXuw-0000B9-I8 for linux-arm-kernel@lists.infradead.org; Tue, 26 Mar 2013 17:44:17 +0000 Received: by mail-wi0-f170.google.com with SMTP id hm11so1306404wib.1 for ; Tue, 26 Mar 2013 10:44:13 -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:in-reply-to:references:x-gm-message-state; bh=3RCM68SrMRRhWyk/f9tRuPAa2rsb6pRb5+RDH2rcgks=; b=EzC/H+TvtyO9LwqKjVjBZaVeIJXMueQTtIO6hwjFHAo+hge0hLfj6wXM16OArMK+kJ PIsJu84LV1ic5MhjFdBkvNp+kjUYvfCWrPqCJAzH1V3sXyjpUr0GPJUIf/ZBXue82tO6 Qp3yYsCfVRecYiFHotFoWYLQVOvM5djD5SI4WI4MNqgh4zshoAk9xip01veqfziE2zqL HcamRWCfUx2IcIq4EK2ZUVWZmO6Wt7KTr8QK9oyRMtLDkfJznf2rbyZ+qgN0hO6qlAVo iD4bl/SkomRLQ6SaglD2ZTfqHI8YZn2WaODkwUmsopBQacp3cZqiuZ2V097OsCybKkwW sxDg== X-Received: by 10.194.157.42 with SMTP id wj10mr26529498wjb.12.1364319853140; Tue, 26 Mar 2013 10:44:13 -0700 (PDT) Received: from localhost (nat-63.starnet.cz. [178.255.168.63]) by mx.google.com with ESMTPS id fv2sm4781211wib.6.2013.03.26.10.44.11 (version=TLSv1.1 cipher=RC4-SHA bits=128/128); Tue, 26 Mar 2013 10:44:12 -0700 (PDT) From: Michal Simek To: linux-arm-kernel@lists.infradead.org, monstr@monstr.eu, Josh Cartwright , Steffen Trumtrar , Rob Herring Subject: [PATCH v2 10/10] arm: zynq: Add cpuidle support Date: Tue, 26 Mar 2013 18:43:42 +0100 Message-Id: <3395757de41837ecc1d84aac1a06ebcc23fe1367.1364319776.git.michal.simek@xilinx.com> X-Mailer: git-send-email 1.7.9.7 In-Reply-To: <1364319822-5504-1-git-send-email-michal.simek@xilinx.com> References: <1364319822-5504-1-git-send-email-michal.simek@xilinx.com> In-Reply-To: References: X-Gm-Message-State: ALoCoQm95Yd645GVgrIANYXK8DoBgfD7yRDw+K1TLSLzZbUWrB8xJUh8jrzx+VD8pSrBw4Jd0rvp X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20130326_134414_762511_0AC4C6A4 X-CRM114-Status: GOOD ( 19.05 ) X-Spam-Score: -1.9 (-) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-1.9 points) pts rule name description ---- ---------------------- -------------------------------------------------- -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 --- v2: Fix file header --- arch/arm/mach-zynq/Makefile | 1 + arch/arm/mach-zynq/cpuidle.c | 133 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 134 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 1b25d92..238b8f9 100644 --- a/arch/arm/mach-zynq/Makefile +++ b/arch/arm/mach-zynq/Makefile @@ -7,4 +7,5 @@ obj-y := common.o slcr.o CFLAGS_REMOVE_hotplug.o =-march=armv6k CFLAGS_hotplug.o =-Wa,-march=armv7-a -mcpu=cortex-a9 obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o +obj-$(CONFIG_CPU_IDLE) += cpuidle.o obj-$(CONFIG_SMP) += headsmp.o platsmp.o diff --git a/arch/arm/mach-zynq/cpuidle.c b/arch/arm/mach-zynq/cpuidle.c new file mode 100644 index 0000000..4ed8855 --- /dev/null +++ b/arch/arm/mach-zynq/cpuidle.c @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2012-2013 Xilinx + * + * CPU idle support for Xilinx + * + * based on arch/arm/mach-at91/cpuidle.c + * + * 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);