From d7100bcd5899eea0bf1eb45e9bccd3fd783ae252 Mon Sep 17 00:00:00 2001 From: Achin Gupta Date: Sun, 10 Mar 2013 22:36:51 +0000 Subject: ARM: TC2: replace hard coded cluster and cpu values with constants This patch adds constants in a tc2 specific header file to prevent use of hard coded values for specifying the number of cpus and clusters. Signed-off-by: Achin Gupta Signed-off-by: Liviu Dudau --- arch/arm/mach-vexpress/include/mach/tc2.h | 10 ++++++++++ arch/arm/mach-vexpress/tc2_pm.c | 16 +++++++++++----- 2 files changed, 21 insertions(+), 5 deletions(-) create mode 100644 arch/arm/mach-vexpress/include/mach/tc2.h diff --git a/arch/arm/mach-vexpress/include/mach/tc2.h b/arch/arm/mach-vexpress/include/mach/tc2.h new file mode 100644 index 00000000000..d3b5a2225a0 --- /dev/null +++ b/arch/arm/mach-vexpress/include/mach/tc2.h @@ -0,0 +1,10 @@ +#ifndef __MACH_TC2_H +#define __MACH_TC2_H + +/* + * cpu and cluster limits + */ +#define TC2_MAX_CPUS 3 +#define TC2_MAX_CLUSTERS 2 + +#endif diff --git a/arch/arm/mach-vexpress/tc2_pm.c b/arch/arm/mach-vexpress/tc2_pm.c index 54757301ca5..52173568d6c 100644 --- a/arch/arm/mach-vexpress/tc2_pm.c +++ b/arch/arm/mach-vexpress/tc2_pm.c @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -37,12 +38,13 @@ */ static arch_spinlock_t tc2_pm_lock = __ARCH_SPIN_LOCK_UNLOCKED; -static int tc2_pm_use_count[3][2]; +static int tc2_pm_use_count[TC2_MAX_CPUS][TC2_MAX_CLUSTERS]; static int tc2_pm_power_up(unsigned int cpu, unsigned int cluster) { pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster); - if (cluster >= 2 || cpu >= vexpress_spc_get_nb_cpus(cluster)) + if (cluster >= TC2_MAX_CLUSTERS || + cpu >= vexpress_spc_get_nb_cpus(cluster)) return -EINVAL; /* @@ -90,7 +92,8 @@ static void tc2_pm_down(u64 residency) cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1); pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster); - BUG_ON(cluster >= 2 || cpu >= vexpress_spc_get_nb_cpus(cluster)); + BUG_ON(cluster >= TC2_MAX_CLUSTERS || + cpu >= vexpress_spc_get_nb_cpus(cluster)); __mcpm_cpu_going_down(cpu, cluster); @@ -194,7 +197,8 @@ static void tc2_pm_powered_up(void) cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1); pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster); - BUG_ON(cluster >= 2 || cpu >= vexpress_spc_get_nb_cpus(cluster)); + BUG_ON(cluster >= TC2_MAX_CLUSTERS || + cpu >= vexpress_spc_get_nb_cpus(cluster)); local_irq_save(flags); arch_spin_lock(&tc2_pm_lock); @@ -232,7 +236,9 @@ static void __init tc2_pm_usage_count_init(void) cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1); pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster); - BUG_ON(cpu >= 3 || cluster >= 2); + BUG_ON(cluster >= TC2_MAX_CLUSTERS || + cpu >= vexpress_spc_get_nb_cpus(cluster)); + tc2_pm_use_count[cpu][cluster] = 1; } -- cgit v1.2.3 From 6724719f02a04223c2223914f30821e191d9a064 Mon Sep 17 00:00:00 2001 From: Achin Gupta Date: Mon, 17 Dec 2012 00:15:00 +0000 Subject: ARM: vexpress: allow native pm ops backends to probe for psci suppport This patch allows the vexpress 'tc2' native backend to probe the dt for presence of the psci backend. If present then the native implementation of the 'bL_platform_power_ops' is not used. Signed-off-by: Achin Gupta Signed-off-by: Liviu Dudau --- arch/arm/mach-vexpress/tc2_pm.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/arm/mach-vexpress/tc2_pm.c b/arch/arm/mach-vexpress/tc2_pm.c index 52173568d6c..f2e9959fb26 100644 --- a/arch/arm/mach-vexpress/tc2_pm.c +++ b/arch/arm/mach-vexpress/tc2_pm.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -248,6 +249,12 @@ static int __init tc2_pm_init(void) { int ret; + ret = psci_probe(); + if (!ret) { + pr_debug("psci found. Aborting native init\n"); + return -ENODEV; + } + if (!vexpress_spc_check_loaded()) return -ENODEV; -- cgit v1.2.3 From 7fbc765bf7225910d4a0e04173ec378add122634 Mon Sep 17 00:00:00 2001 From: Achin Gupta Date: Tue, 26 Feb 2013 15:33:25 +0000 Subject: ARM: vexpress: add shim layer for psci backend on TC2 This patch introduces a shim layer for the TC2 platform which converts 'bL_platform_power_ops' routines to their psci counterparts. The psci counterparts are implemented by the secure firmware. The shim layer is used only when Linux is running in non-secure world and the secure firmware implements psci. It also introduces the use of a reference count to allow a power up call to go ahead of a power down call. Signed-off-by: Achin Gupta Signed-off-by: Liviu Dudau --- arch/arm/mach-vexpress/Makefile | 4 + arch/arm/mach-vexpress/tc2_pm_psci.c | 179 +++++++++++++++++++++++++++++++++++ 2 files changed, 183 insertions(+) create mode 100644 arch/arm/mach-vexpress/tc2_pm_psci.c diff --git a/arch/arm/mach-vexpress/Makefile b/arch/arm/mach-vexpress/Makefile index a95282125eb..4dbc5891275 100644 --- a/arch/arm/mach-vexpress/Makefile +++ b/arch/arm/mach-vexpress/Makefile @@ -8,5 +8,9 @@ obj-y := v2m.o reset.o obj-$(CONFIG_ARCH_VEXPRESS_CA9X4) += ct-ca9x4.o obj-$(CONFIG_ARCH_VEXPRESS_TC2) += tc2_pm.o tc2_pm_setup.o CFLAGS_REMOVE_tc2_pm.o = -pg +ifeq ($(CONFIG_ARCH_VEXPRESS_TC2),y) +obj-$(CONFIG_ARM_PSCI) += tc2_pm_psci.o +CFLAGS_REMOVE_tc2_pm_psci.o = -pg +endif obj-$(CONFIG_SMP) += platsmp.o obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o diff --git a/arch/arm/mach-vexpress/tc2_pm_psci.c b/arch/arm/mach-vexpress/tc2_pm_psci.c new file mode 100644 index 00000000000..c9715b8137e --- /dev/null +++ b/arch/arm/mach-vexpress/tc2_pm_psci.c @@ -0,0 +1,179 @@ +/* + * arch/arm/mach-vexpress/tc2_pm_psci.c - TC2 PSCI support + * + * Created by: Achin Gupta, December 2012 + * Copyright: (C) 2012 ARM Limited + * + * Some portions of this file were originally written by Nicolas Pitre + * Copyright: (C) 2012 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 + +#include + +/* + * Platform specific state id understood by the firmware and used to + * program the power controller + */ +#define PSCI_POWER_STATE_ID 0 + +static atomic_t tc2_pm_use_count[TC2_MAX_CPUS][TC2_MAX_CLUSTERS]; + +static int tc2_pm_psci_power_up(unsigned int cpu, unsigned int cluster) +{ + unsigned int mpidr = (cluster << 8) | cpu; + int ret = 0; + + BUG_ON(!psci_ops.cpu_on); + + switch (atomic_inc_return(&tc2_pm_use_count[cpu][cluster])) { + case 1: + /* + * This is a request to power up a cpu that linux thinks has + * been powered down. Retries are needed if the firmware has + * seen the power down request as yet. + */ + do + ret = psci_ops.cpu_on(mpidr, + virt_to_phys(bL_entry_point)); + while (ret == -EAGAIN); + + return ret; + case 2: + /* This power up request has overtaken a power down request */ + return ret; + default: + /* Any other value is a bug */ + BUG(); + } +} + +static void tc2_pm_psci_power_down(void) +{ + struct psci_power_state power_state; + unsigned int mpidr, cpu, cluster; + + mpidr = read_cpuid_mpidr(); + cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0); + cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1); + + BUG_ON(!psci_ops.cpu_off); + + switch (atomic_dec_return(&tc2_pm_use_count[cpu][cluster])) { + case 1: + /* + * Overtaken by a power up. Flush caches, exit coherency, + * return & fake a reset + */ + asm volatile ( + "mrc p15, 0, ip, c1, c0, 0 \n\t" + "bic ip, ip, #(1 << 2) @ clear C bit \n\t" + "mcr p15, 0, ip, c1, c0, 0 \n\t" + "dsb \n\t" + "isb" + : : : "ip" ); + + flush_cache_louis(); + + asm volatile ( + "clrex \n\t" + "mrc p15, 0, ip, c1, c0, 1 \n\t" + "bic ip, ip, #(1 << 6) @ clear SMP bit \n\t" + "mcr p15, 0, ip, c1, c0, 1 \n\t" + "isb \n\t" + "dsb" + : : : "ip" ); + + return; + case 0: + /* A normal request to possibly power down the cluster */ + power_state.id = PSCI_POWER_STATE_ID; + power_state.type = PSCI_POWER_STATE_TYPE_POWER_DOWN; + power_state.affinity_level = PSCI_POWER_STATE_AFFINITY_LEVEL1; + + psci_ops.cpu_off(power_state); + + /* On success this function never returns */ + default: + /* Any other value is a bug */ + BUG(); + } +} + +static void tc2_pm_psci_suspend(u64 unused) +{ + struct psci_power_state power_state; + + BUG_ON(!psci_ops.cpu_suspend); + + /* On TC2 always attempt to power down the cluster */ + power_state.id = PSCI_POWER_STATE_ID; + power_state.type = PSCI_POWER_STATE_TYPE_POWER_DOWN; + power_state.affinity_level = PSCI_POWER_STATE_AFFINITY_LEVEL1; + + psci_ops.cpu_suspend(power_state, virt_to_phys(bL_entry_point)); + + /* On success this function never returns */ + BUG(); +} + +static const struct bL_platform_power_ops tc2_pm_power_ops = { + .power_up = tc2_pm_psci_power_up, + .power_down = tc2_pm_psci_power_down, + .suspend = tc2_pm_psci_suspend, +}; + +static void __init tc2_pm_usage_count_init(void) +{ + unsigned int mpidr, cpu, cluster; + + mpidr = read_cpuid_mpidr(); + cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0); + cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1); + + pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster); + BUG_ON(cluster >= TC2_MAX_CLUSTERS || + cpu >= vexpress_spc_get_nb_cpus(cluster)); + + atomic_set(&tc2_pm_use_count[cpu][cluster], 1); +} + +static int __init tc2_pm_psci_init(void) +{ + int ret; + + ret = psci_probe(); + if (ret) { + pr_debug("psci not found. Aborting psci init\n"); + return -ENODEV; + } + + tc2_pm_usage_count_init(); + + ret = bL_platform_power_register(&tc2_pm_power_ops); + if (!ret) + ret = bL_cluster_sync_init(NULL); + if (!ret) + pr_info("TC2 power management initialized\n"); + return ret; +} + +early_initcall(tc2_pm_psci_init); -- cgit v1.2.3 From 4381de74eda146afcac791c4eb557f4645f981d8 Mon Sep 17 00:00:00 2001 From: Achin Gupta Date: Sun, 16 Dec 2012 22:41:02 +0000 Subject: ARM: vexpress: add psci support in TC2 device tree This patch adds a psci device node to allow the ospm subsystems on the TC2 to work with a psci backend implemented in the secure firmware. The function offsets start from 1 instead of 0 as thats whats the current secure firmware implements. Signed-off-by: Achin Gupta Signed-off-by: Liviu Dudau --- arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts b/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts index 972a56bc1d3..597d196292a 100644 --- a/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts +++ b/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts @@ -147,6 +147,15 @@ clock-output-names = "oscclk6a"; }; + psci { + compatible = "arm,psci"; + method = "smc"; + cpu_suspend = <0x80100001>; + cpu_off = <0x80100002>; + cpu_on = <0x80100003>; + migrate = <0x80100004>; + }; + dcc { compatible = "arm,vexpress,config-bus"; arm,vexpress,config-bridge = <&v2m_sysreg>; -- cgit v1.2.3 From 338f41e8b36bc29c862af83a0be30d6944ed6929 Mon Sep 17 00:00:00 2001 From: Jon Medhurst Date: Thu, 21 Mar 2013 11:15:56 +0000 Subject: ARM: vexpress: Fixup tc2_pm_psci.c for mcpm APIs Signed-off-by: Jon Medhurst --- arch/arm/mach-vexpress/tc2_pm_psci.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/arm/mach-vexpress/tc2_pm_psci.c b/arch/arm/mach-vexpress/tc2_pm_psci.c index c9715b8137e..04d83d2965f 100644 --- a/arch/arm/mach-vexpress/tc2_pm_psci.c +++ b/arch/arm/mach-vexpress/tc2_pm_psci.c @@ -17,7 +17,7 @@ #include #include -#include +#include #include #include #include @@ -53,7 +53,7 @@ static int tc2_pm_psci_power_up(unsigned int cpu, unsigned int cluster) */ do ret = psci_ops.cpu_on(mpidr, - virt_to_phys(bL_entry_point)); + virt_to_phys(mcpm_entry_point)); while (ret == -EAGAIN); return ret; @@ -129,13 +129,13 @@ static void tc2_pm_psci_suspend(u64 unused) power_state.type = PSCI_POWER_STATE_TYPE_POWER_DOWN; power_state.affinity_level = PSCI_POWER_STATE_AFFINITY_LEVEL1; - psci_ops.cpu_suspend(power_state, virt_to_phys(bL_entry_point)); + psci_ops.cpu_suspend(power_state, virt_to_phys(mcpm_entry_point)); /* On success this function never returns */ BUG(); } -static const struct bL_platform_power_ops tc2_pm_power_ops = { +static const struct mcpm_platform_ops tc2_pm_power_ops = { .power_up = tc2_pm_psci_power_up, .power_down = tc2_pm_psci_power_down, .suspend = tc2_pm_psci_suspend, @@ -168,9 +168,9 @@ static int __init tc2_pm_psci_init(void) tc2_pm_usage_count_init(); - ret = bL_platform_power_register(&tc2_pm_power_ops); + ret = mcpm_platform_register(&tc2_pm_power_ops); if (!ret) - ret = bL_cluster_sync_init(NULL); + ret = mcpm_sync_init(NULL); if (!ret) pr_info("TC2 power management initialized\n"); return ret; -- cgit v1.2.3 From 42ef096d399170367f55a37c126c67eb846c381b Mon Sep 17 00:00:00 2001 From: Jon Medhurst Date: Thu, 21 Mar 2013 12:00:09 +0000 Subject: ARM: vexpress: Get tc2_pm_psci.c to use common CP15 accessor functions Signed-off-by: Jon Medhurst --- arch/arm/mach-vexpress/tc2_pm_psci.c | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/arch/arm/mach-vexpress/tc2_pm_psci.c b/arch/arm/mach-vexpress/tc2_pm_psci.c index 04d83d2965f..5a5e4f56849 100644 --- a/arch/arm/mach-vexpress/tc2_pm_psci.c +++ b/arch/arm/mach-vexpress/tc2_pm_psci.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -83,24 +84,12 @@ static void tc2_pm_psci_power_down(void) * Overtaken by a power up. Flush caches, exit coherency, * return & fake a reset */ - asm volatile ( - "mrc p15, 0, ip, c1, c0, 0 \n\t" - "bic ip, ip, #(1 << 2) @ clear C bit \n\t" - "mcr p15, 0, ip, c1, c0, 0 \n\t" - "dsb \n\t" - "isb" - : : : "ip" ); + set_cr(get_cr() & ~CR_C); flush_cache_louis(); - asm volatile ( - "clrex \n\t" - "mrc p15, 0, ip, c1, c0, 1 \n\t" - "bic ip, ip, #(1 << 6) @ clear SMP bit \n\t" - "mcr p15, 0, ip, c1, c0, 1 \n\t" - "isb \n\t" - "dsb" - : : : "ip" ); + asm volatile ("clrex"); + set_auxcr(get_auxcr() & ~(1 << 6)); return; case 0: -- cgit v1.2.3