From patchwork Tue Aug 6 18:54:21 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pawel Moll X-Patchwork-Id: 2839550 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id F33F2BF535 for ; Tue, 6 Aug 2013 18:57:13 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 71B0E2022F for ; Tue, 6 Aug 2013 18:57:12 +0000 (UTC) Received: from casper.infradead.org (casper.infradead.org [85.118.1.10]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 3E97520220 for ; Tue, 6 Aug 2013 18:57:10 +0000 (UTC) Received: from merlin.infradead.org ([2001:4978:20e::2]) by casper.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1V6mQM-0003yh-GI; Tue, 06 Aug 2013 18:56:03 +0000 Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1V6mPy-0006dY-K4; Tue, 06 Aug 2013 18:55:38 +0000 Received: from service87.mimecast.com ([91.220.42.44]) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1V6mPJ-0006X7-Gg for linux-arm-kernel@lists.infradead.org; Tue, 06 Aug 2013 18:55:03 +0000 Received: from cam-owa2.Emea.Arm.com (fw-tnat.cambridge.arm.com [217.140.96.21]) by service87.mimecast.com; Tue, 06 Aug 2013 19:54:33 +0100 Received: from hornet.Cambridge.Arm.com ([10.1.255.212]) by cam-owa2.Emea.Arm.com with Microsoft SMTPSVC(6.0.3790.3959); Tue, 6 Aug 2013 19:54:30 +0100 From: Pawel Moll To: Olof Johansson , Lorenzo Pieralisi Subject: [PATCH 2/5] ARM: vexpress/TC2: add Serial Power Controller (SPC) support Date: Tue, 6 Aug 2013 19:54:21 +0100 Message-Id: <1375815264-29414-3-git-send-email-pawel.moll@arm.com> X-Mailer: git-send-email 1.8.1.2 In-Reply-To: <1375815264-29414-1-git-send-email-pawel.moll@arm.com> References: <1375815264-29414-1-git-send-email-pawel.moll@arm.com> X-OriginalArrivalTime: 06 Aug 2013 18:54:30.0682 (UTC) FILETIME=[621987A0:01CE92D6] X-MC-Unique: 113080619543302601 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20130806_145457_949565_DAA13C50 X-CRM114-Status: GOOD ( 24.92 ) X-Spam-Score: -2.6 (--) Cc: Jon Medhurst , Lorenzo Pieralisi , Pawel Moll , nico@linaro.org, Sudeep KarkadaNagesha , Achin Gupta , Amit Kucheria , linux-arm-kernel@lists.infradead.org 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 X-Spam-Status: No, score=-4.2 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Lorenzo Pieralisi The TC2 versatile express core tile integrates a logic block that provides the interface between the dual cluster test-chip and the M3 microcontroller that carries out power management. The logic block, called Serial Power Controller (SPC), contains several memory mapped registers to control among other things low-power states, wake-up irqs and per-CPU jump addresses registers. This patch provides a driver that enables run-time control of features implemented by the SPC power management control logic with an API to be used by different subsystem drivers on top. The SPC control logic is required to be programmed very early in the boot process to reset secondary CPUs on the TC2 testchip, set-up jump addresses and wake-up IRQs for power management. Hence, waiting for core changes to be made in the device core code to enable early registration of platform devices, the driver puts in place an early init scheme that allows kernel drivers to initialize the SPC driver directly from the components requiring it, if their initialization routine is called before this driver init function during the boot process. Device tree bindings documentation for the SPC component is also provided. Cc: Olof Johansson Cc: Amit Kucheria Cc: Jon Medhurst Signed-off-by: Achin Gupta Signed-off-by: Lorenzo Pieralisi Signed-off-by: Sudeep KarkadaNagesha Acked-by: Pawel Moll [ np: moved from drivers/mfd/ to drivers/platform/vexpress/ ] Signed-off-by: Nicolas Pitre [ PM: moved again to arch/arm/mach-vexpress, requested by Olof ] [ PM: removed generic compatible value and useless printk, from Olof ] [ PM: removed SPC_BASE so the driver only uses SPC registers ] Signed-off-by: Pawel Moll --- .../devicetree/bindings/arm/vexpress-spc.txt | 30 +++ arch/arm/mach-vexpress/spc.c | 246 +++++++++++++++++++++ arch/arm/mach-vexpress/spc.h | 25 +++ drivers/platform/Kconfig | 1 - 4 files changed, 301 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/arm/vexpress-spc.txt create mode 100644 arch/arm/mach-vexpress/spc.c create mode 100644 arch/arm/mach-vexpress/spc.h diff --git a/Documentation/devicetree/bindings/arm/vexpress-spc.txt b/Documentation/devicetree/bindings/arm/vexpress-spc.txt new file mode 100644 index 0000000..c2e0e6b --- /dev/null +++ b/Documentation/devicetree/bindings/arm/vexpress-spc.txt @@ -0,0 +1,30 @@ +* ARM Versatile Express Serial Power Controller device tree bindings + +Latest ARM development boards implement a power management interface (serial +power controller - SPC) that is capable of managing power states transitions, +wake-up IRQs and resume addresses for ARM multiprocessor testchips. +The serial controller can be programmed through a memory mapped interface +that enables communication between firmware running on the microcontroller +managing power states and the application processors. + +The SPC DT bindings are defined as follows: + +- spc node + + - compatible: + Usage: required + Value type: + Definition: must be + "arm,vexpress-spc,v2p-ca15_a7", "arm,vexpress-spc" + - reg: + Usage: required + Value type: + Definition: A standard property that specifies the base address + and the size of the SPC address space + +Example: + +spc@7fff0b00 { + compatible = "arm,vexpress-spc,v2p-ca15_a7", "arm,vexpress-spc"; + reg = <0x7fff0b00 0x100>; +}; diff --git a/arch/arm/mach-vexpress/spc.c b/arch/arm/mach-vexpress/spc.c new file mode 100644 index 0000000..bd6d4f2 --- /dev/null +++ b/arch/arm/mach-vexpress/spc.c @@ -0,0 +1,246 @@ +/* + * Versatile Express Serial Power Controller (SPC) support + * + * Copyright (C) 2013 ARM Ltd. + * + * Authors: Sudeep KarkadaNagesha + * Achin Gupta + * Lorenzo Pieralisi + * + * 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. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include + +#include + +#define SPCLOG "vexpress-spc: " + +/* SCC conf registers */ +#define A15_CONF 0x400 +#define SYS_INFO 0x700 + +/* SPC wake-up IRQs status and mask */ +#define WAKE_INT_MASK 0x24 +#define WAKE_INT_RAW 0x28 +#define WAKE_INT_STAT 0x2c +/* SPC power down registers */ +#define A15_PWRDN_EN 0x30 +#define A7_PWRDN_EN 0x34 +/* SPC per-CPU mailboxes */ +#define A15_BX_ADDR0 0x68 +#define A7_BX_ADDR0 0x78 + +/* wake-up interrupt masks */ +#define GBL_WAKEUP_INT_MSK (0x3 << 10) + +/* TC2 static dual-cluster configuration */ +#define MAX_CLUSTERS 2 + +struct ve_spc_drvdata { + void __iomem *baseaddr; + /* + * A15s cluster identifier + * It corresponds to A15 processors MPIDR[15:8] bitfield + */ + u32 a15_clusid; +}; + +static struct ve_spc_drvdata *info; + +static inline bool cluster_is_a15(u32 cluster) +{ + return cluster == info->a15_clusid; +} + +/** + * ve_spc_global_wakeup_irq() + * + * Function to set/clear global wakeup IRQs. Not protected by locking since + * it might be used in code paths where normal cacheable locks are not + * working. Locking must be provided by the caller to ensure atomicity. + * + * @set: if true, global wake-up IRQs are set, if false they are cleared + */ +void ve_spc_global_wakeup_irq(bool set) +{ + u32 reg; + + reg = readl_relaxed(info->baseaddr + WAKE_INT_MASK); + + if (set) + reg |= GBL_WAKEUP_INT_MSK; + else + reg &= ~GBL_WAKEUP_INT_MSK; + + writel_relaxed(reg, info->baseaddr + WAKE_INT_MASK); +} + +/** + * ve_spc_cpu_wakeup_irq() + * + * Function to set/clear per-CPU wake-up IRQs. Not protected by locking since + * it might be used in code paths where normal cacheable locks are not + * working. Locking must be provided by the caller to ensure atomicity. + * + * @cluster: mpidr[15:8] bitfield describing cluster affinity level + * @cpu: mpidr[7:0] bitfield describing cpu affinity level + * @set: if true, wake-up IRQs are set, if false they are cleared + */ +void ve_spc_cpu_wakeup_irq(u32 cluster, u32 cpu, bool set) +{ + u32 mask, reg; + + if (cluster >= MAX_CLUSTERS) + return; + + mask = 1 << cpu; + + if (!cluster_is_a15(cluster)) + mask <<= 4; + + reg = readl_relaxed(info->baseaddr + WAKE_INT_MASK); + + if (set) + reg |= mask; + else + reg &= ~mask; + + writel_relaxed(reg, info->baseaddr + WAKE_INT_MASK); +} + +/** + * ve_spc_set_resume_addr() - set the jump address used for warm boot + * + * @cluster: mpidr[15:8] bitfield describing cluster affinity level + * @cpu: mpidr[7:0] bitfield describing cpu affinity level + * @addr: physical resume address + */ +void ve_spc_set_resume_addr(u32 cluster, u32 cpu, u32 addr) +{ + void __iomem *baseaddr; + + if (cluster >= MAX_CLUSTERS) + return; + + if (cluster_is_a15(cluster)) + baseaddr = info->baseaddr + A15_BX_ADDR0 + (cpu << 2); + else + baseaddr = info->baseaddr + A7_BX_ADDR0 + (cpu << 2); + + writel_relaxed(addr, baseaddr); +} + +/** + * ve_spc_get_nr_cpus() - get number of cpus in a cluster + * + * @cluster: mpidr[15:8] bitfield describing cluster affinity level + * + * Return: > 0 number of cpus in the cluster + * or 0 if cluster number invalid + */ +u32 ve_spc_get_nr_cpus(u32 cluster) +{ + u32 val; + + if (cluster >= MAX_CLUSTERS) + return 0; + + val = readl_relaxed(info->baseaddr + SYS_INFO); + val = cluster_is_a15(cluster) ? (val >> 16) : (val >> 20); + return val & 0xf; +} + +/** + * ve_spc_powerdown() + * + * Function to enable/disable cluster powerdown. Not protected by locking + * since it might be used in code paths where normal cacheable locks are not + * working. Locking must be provided by the caller to ensure atomicity. + * + * @cluster: mpidr[15:8] bitfield describing cluster affinity level + * @enable: if true enables powerdown, if false disables it + */ +void ve_spc_powerdown(u32 cluster, bool enable) +{ + u32 pwdrn_reg; + + if (cluster >= MAX_CLUSTERS) + return; + + pwdrn_reg = cluster_is_a15(cluster) ? A15_PWRDN_EN : A7_PWRDN_EN; + writel_relaxed(enable, info->baseaddr + pwdrn_reg); +} + +static int __init ve_spc_probe(void) +{ + int ret; + struct device_node *dn; + + dn = of_find_compatible_node(NULL, NULL, + "arm,vexpress-scc,v2p-ca15_a7"); + + if (!dn) + return -ENODEV; + + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) { + pr_err(SPCLOG "unable to allocate mem\n"); + return -ENOMEM; + } + + info->baseaddr = of_iomap(dn, 0); + if (!info->baseaddr) { + pr_err(SPCLOG "unable to ioremap memory\n"); + ret = -ENXIO; + goto mem_free; + } + + info->a15_clusid = readl_relaxed(info->baseaddr + A15_CONF) & 0xf; + + /* + * Multi-cluster systems may need this data when non-coherent, during + * cluster power-up/power-down. Make sure driver info reaches main + * memory. + */ + sync_cache_w(info); + sync_cache_w(&info); + + return 0; + +mem_free: + kfree(info); + return ret; +} + +/** + * ve_spc_init() + * + * Function exported to manage pre early_initcall initialization. + * SPC code is needed very early in the boot process to bring CPUs out of + * reset and initialize power management back-end so an init interface is + * provided to platform code to allow early initialization. The init + * interface can be removed as soon as the DT layer and platform bus allow + * platform device creation and probing before SMP boot. + */ +int __init ve_spc_init(void) +{ + static int ve_spc_init_status __initdata = -EAGAIN; + + if (ve_spc_init_status == -EAGAIN) + ve_spc_init_status = ve_spc_probe(); + + return ve_spc_init_status; +} diff --git a/arch/arm/mach-vexpress/spc.h b/arch/arm/mach-vexpress/spc.h new file mode 100644 index 0000000..f6b87fc --- /dev/null +++ b/arch/arm/mach-vexpress/spc.h @@ -0,0 +1,25 @@ +/* + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Copyright (C) 2012 ARM Limited + */ + + +#ifndef __SPC_H_ +#define __SPC_H_ + +int __init ve_spc_init(void); +void ve_spc_global_wakeup_irq(bool set); +void ve_spc_cpu_wakeup_irq(u32 cluster, u32 cpu, bool set); +void ve_spc_set_resume_addr(u32 cluster, u32 cpu, u32 addr); +u32 ve_spc_get_nr_cpus(u32 cluster); +void ve_spc_powerdown(u32 cluster, bool enable); + +#endif diff --git a/drivers/platform/Kconfig b/drivers/platform/Kconfig index 69616ae..57811ea 100644 --- a/drivers/platform/Kconfig +++ b/drivers/platform/Kconfig @@ -4,4 +4,3 @@ endif if GOLDFISH source "drivers/platform/goldfish/Kconfig" endif -