From patchwork Mon Feb 4 04:39:44 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nicolas Pitre X-Patchwork-Id: 2089121 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 8EF2C3FC23 for ; Mon, 4 Feb 2013 04:43:42 +0000 (UTC) Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1U2DqS-0004kC-Hy; Mon, 04 Feb 2013 04:39:52 +0000 Received: from mail-vb0-f43.google.com ([209.85.212.43]) by merlin.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1U2DqO-0004jf-T6 for linux-arm-kernel@lists.infradead.org; Mon, 04 Feb 2013 04:39:49 +0000 Received: by mail-vb0-f43.google.com with SMTP id fs19so622998vbb.30 for ; Sun, 03 Feb 2013 20:39:47 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=x-received:date:from:to:cc:subject:in-reply-to:message-id :references:user-agent:mime-version:content-type:x-gm-message-state; bh=TfYh/Z1VJAidkn8PV9fVvaTb8CEBDLKCJjDrGoN6Wdc=; b=GVVCMmnryQC+3fRUMjmpniRd9YLc1YpJWm5skSQuG//Iqw9QG4VGVSBTGInFp/RAbf 6hoxgDEd8twV8qXP66qiha5Tg34sY3mp2wzjkBZ0xG/ep9QzKavACCrKtn0ewu8YyBPA gEnE8XTgwJIaCYZVpQMYIgRMFDCtXCxLkNrwgMteAsN4cbBzJmduKXJBaJBI6XQKL/iM h+sq6fPPLt1xoY2nZbjpJ71Oaeq0otcTOX7ZFpo204d/zznUEf8I2rG0DxK4VfV8mp8y 7t7jBBzLBv+X3+0UVSPy3rRoQW0miIGLwO7TvJjRRHRdQ3L5TcdWEPH5L1zl7LlPOMKe W7XA== X-Received: by 10.52.90.140 with SMTP id bw12mr18023548vdb.50.1359952787244; Sun, 03 Feb 2013 20:39:47 -0800 (PST) Received: from xanadu.home (modemcable203.213-202-24.mc.videotron.ca. [24.202.213.203]) by mx.google.com with ESMTPS id h11sm18507165vdj.12.2013.02.03.20.39.45 (version=TLSv1 cipher=RC4-SHA bits=128/128); Sun, 03 Feb 2013 20:39:46 -0800 (PST) Date: Sun, 3 Feb 2013 23:39:44 -0500 (EST) From: Nicolas Pitre To: Dave Martin Subject: Re: [PATCH v3 15/15] ARM: vexpress/dcscb: probe via device tree In-Reply-To: <20130131105436.GA2091@linaro.org> Message-ID: References: <1359445870-18925-1-git-send-email-nicolas.pitre@linaro.org> <1359445870-18925-16-git-send-email-nicolas.pitre@linaro.org> <510838AD.6040700@gmail.com> <20130131105436.GA2091@linaro.org> User-Agent: Alpine 2.02 (LFD 1266 2009-07-14) MIME-Version: 1.0 X-Gm-Message-State: ALoCoQkGc94CFm5XrDK7jgU+3a5zBKwk4na9OlHtlX25j/3ZPRZd4WSxiKTZfz42E76El1QPf46l X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20130203_233949_023237_57DC69A6 X-CRM114-Status: GOOD ( 31.90 ) 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 [209.85.212.43 listed in list.dnswl.org] -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] Cc: Lorenzo Pieralisi , Pawel Moll , Catalin Marinas , Achin Gupta , Will Deacon , Santosh Shilimkar , linux-arm-kernel@lists.infradead.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: linux-arm-kernel-bounces@lists.infradead.org Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org On Thu, 31 Jan 2013, Dave Martin wrote: > On Wed, Jan 30, 2013 at 12:43:29PM -0500, Nicolas Pitre wrote: > > On Wed, 30 Jan 2013, Achin Gupta wrote: > > > > > On Tue, Jan 29, 2013 at 9:41 PM, Nicolas Pitre wrote: > > > > On Tue, 29 Jan 2013, Rob Herring wrote: > > > > > > > >> On 01/29/2013 01:51 AM, Nicolas Pitre wrote: > > > >> > + node = of_find_compatible_node(NULL, NULL, "arm,dcscb"); > > > >> > > > >> This needs binding documentation and should be a more specific name. Not > > > >> knowing what dcscb is, I don't have a suggestion. > > The name is 100% specific. The real problem seems to be that it's also > very cryptic, and undocumented. OK, here's my attempt at documenting it, folded with the latest fixes in the patch that introduced DCSCB support. ACK? ---------- >8 From: Nicolas Pitre Date: Wed, 2 May 2012 20:56:52 -0400 Subject: [PATCH] ARM: vexpress: introduce DCSCB support This adds basic CPU and cluster reset controls on RTSM for the A15x4-A7x4 model configuration using the Dual Cluster System Configuration Block (DCSCB). The cache coherency interconnect (CCI) is not handled yet. Signed-off-by: Nicolas Pitre --- .../devicetree/bindings/arm/rtsm-dcscb.txt | 19 +++ arch/arm/mach-vexpress/Kconfig | 8 + arch/arm/mach-vexpress/Makefile | 1 + arch/arm/mach-vexpress/dcscb.c | 162 +++++++++++++++++++++ 4 files changed, 190 insertions(+) diff --git a/Documentation/devicetree/bindings/arm/rtsm-dcscb.txt b/Documentation/devicetree/bindings/arm/rtsm-dcscb.txt new file mode 100644 index 0000000000..3b8fbf3c00 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/rtsm-dcscb.txt @@ -0,0 +1,19 @@ +ARM Dual Cluster System Configuration Block +------------------------------------------- + +The Dual Cluster System Configuration Block (DCSCB) provides basic +functionality for controlling clocks, resets and configuration pins in +the Dual Cluster System implemented by the Real-Time System Model (RTSM). + +Required properties: + +- compatible : should be "arm,rtsm,dcscb" + +- reg : physical base address and the size of the registers window + +Example: + + dcscb@60000000 { + compatible = "arm,rtsm,dcscb"; + reg = <0x60000000 0x1000>; + }; diff --git a/arch/arm/mach-vexpress/Kconfig b/arch/arm/mach-vexpress/Kconfig index 52d315b792..f3f92b120a 100644 --- a/arch/arm/mach-vexpress/Kconfig +++ b/arch/arm/mach-vexpress/Kconfig @@ -52,4 +52,12 @@ config ARCH_VEXPRESS_CORTEX_A5_A9_ERRATA config ARCH_VEXPRESS_CA9X4 bool "Versatile Express Cortex-A9x4 tile" +config ARCH_VEXPRESS_DCSCB + bool "Dual Cluster System Control Block (DCSCB) support" + depends on CLUSTER_PM + help + Support for the Dual Cluster System Configuration Block (DCSCB). + This is needed to provide CPU and cluster power management + on RTSM. + endmenu diff --git a/arch/arm/mach-vexpress/Makefile b/arch/arm/mach-vexpress/Makefile index 80b64971fb..2253644054 100644 --- a/arch/arm/mach-vexpress/Makefile +++ b/arch/arm/mach-vexpress/Makefile @@ -6,5 +6,6 @@ ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include \ obj-y := v2m.o reset.o obj-$(CONFIG_ARCH_VEXPRESS_CA9X4) += ct-ca9x4.o +obj-$(CONFIG_ARCH_VEXPRESS_DCSCB) += dcscb.o obj-$(CONFIG_SMP) += platsmp.o obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o diff --git a/arch/arm/mach-vexpress/dcscb.c b/arch/arm/mach-vexpress/dcscb.c new file mode 100644 index 0000000000..07e835cb72 --- /dev/null +++ b/arch/arm/mach-vexpress/dcscb.c @@ -0,0 +1,162 @@ +/* + * arch/arm/mach-vexpress/dcscb.c - Dual Cluster System Configuration Block + * + * Created by: Nicolas Pitre, May 2012 + * Copyright: (C) 2012-2013 Linaro Limited + * + * 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 + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +#define RST_HOLD0 0x0 +#define RST_HOLD1 0x4 +#define SYS_SWRESET 0x8 +#define RST_STAT0 0xc +#define RST_STAT1 0x10 +#define EAG_CFG_R 0x20 +#define EAG_CFG_W 0x24 +#define KFC_CFG_R 0x28 +#define KFC_CFG_W 0x2c +#define DCS_CFG_R 0x30 + +/* + * We can't use regular spinlocks. In the switcher case, it is possible + * for an outbound CPU to call power_down() after its inbound counterpart + * is already live using the same logical CPU number which trips lockdep + * debugging. + */ +static arch_spinlock_t dcscb_lock = __ARCH_SPIN_LOCK_UNLOCKED; + +static void __iomem *dcscb_base; + +static int dcscb_power_up(unsigned int cpu, unsigned int cluster) +{ + unsigned int rst_hold, cpumask = (1 << cpu); + + pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster); + if (cpu >= 4 || cluster >= 2) + return -EINVAL; + + /* + * Since this is called with IRQs enabled, and no arch_spin_lock_irq + * variant exists, we need to disable IRQs manually here. + */ + local_irq_disable(); + arch_spin_lock(&dcscb_lock); + + rst_hold = readl_relaxed(dcscb_base + RST_HOLD0 + cluster * 4); + if (rst_hold & (1 << 8)) { + /* remove cluster reset and add individual CPU's reset */ + rst_hold &= ~(1 << 8); + rst_hold |= 0xf; + } + rst_hold &= ~(cpumask | (cpumask << 4)); + writel(rst_hold, dcscb_base + RST_HOLD0 + cluster * 4); + + arch_spin_unlock(&dcscb_lock); + local_irq_enable(); + + return 0; +} + +static void dcscb_power_down(void) +{ + unsigned int mpidr, cpu, cluster, rst_hold, cpumask, last_man; + + mpidr = read_cpuid_mpidr(); + cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0); + cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1); + cpumask = (1 << cpu); + + pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster); + BUG_ON(cpu >= 4 || cluster >= 2); + + arch_spin_lock(&dcscb_lock); + rst_hold = readl_relaxed(dcscb_base + RST_HOLD0 + cluster * 4); + rst_hold |= cpumask; + if (((rst_hold | (rst_hold >> 4)) & 0xf) == 0xf) + rst_hold |= (1 << 8); + writel(rst_hold, dcscb_base + RST_HOLD0 + cluster * 4); + arch_spin_unlock(&dcscb_lock); + last_man = (rst_hold & (1 << 8)); + + /* + * Now let's clean our L1 cache and shut ourself down. + * If we're the last CPU in this cluster then clean L2 too. + */ + + /* + * A15/A7 can hit in the cache with SCTLR.C=0, so we don't need + * a preliminary flush here for those CPUs. At least, that's + * the theory -- without the extra flush, Linux explodes on + * RTSM (maybe not needed anymore, to be investigated).. + */ + flush_cache_louis(); + set_cr(get_cr() & ~CR_C); + + if (!last_man) { + flush_cache_louis(); + } else { + flush_cache_all(); + outer_flush_all(); + } + + /* Disable local coherency by clearing the ACTLR "SMP" bit: */ + set_auxcr(get_auxcr() & ~(1 << 6)); + + /* Now we are prepared for power-down, do it: */ + dsb(); + wfi(); + + /* Not dead at this point? Let our caller cope. */ +} + +static const struct mcpm_platform_ops dcscb_power_ops = { + .power_up = dcscb_power_up, + .power_down = dcscb_power_down, +}; + +static int __init dcscb_init(void) +{ + struct device_node *node; + int ret; + + node = of_find_compatible_node(NULL, NULL, "arm,rtsm,dcscb"); + if (!node) + return -ENODEV; + dcscb_base= of_iomap(node, 0); + if (!dcscb_base) + return -EADDRNOTAVAIL; + + ret = mcpm_platform_register(&dcscb_power_ops); + if (ret) { + iounmap(dcscb_base); + return ret; + } + + /* + * Future entries into the kernel can now go + * through the cluster entry vectors. + */ + vexpress_flags_set(virt_to_phys(mcpm_entry_point)); + + return 0; +} + +early_initcall(dcscb_init);