Skip to content

Commit

Permalink
Merge tag 'tc2-pm' of git://git.linaro.org/people/pawelmoll/linux int…
Browse files Browse the repository at this point in the history
…o next/soc

From Pawel Moll and Nicolas Pitre:
- Fixes to the existing Vexpress DCSCB backend.

- Lorenzo's minimal SPC driver required by the TC2 MCPM backend.

- The MCPM backend enabling SMP secondary boot and CPU hotplug
  on the VExpress TC2 big.LITTLE platform.

- MCPM suspend method to the TC2 backend allowing basic CPU
  idle/suspend.  The cpuidle driver that hooks into this will be
  submitted separately.

* tag 'tc2-pm' of git://git.linaro.org/people/pawelmoll/linux:
  ARM: vexpress/TC2: implement PM suspend method
  ARM: vexpress/TC2: basic PM support
  ARM: vexpress: Add SCC to V2P-CA15_A7's device tree
  ARM: vexpress/TC2: add Serial Power Controller (SPC) support
  ARM: vexpress/dcscb: fix cache disabling sequences

Signed-off-by: Olof Johansson <olof@lixom.net>
  • Loading branch information
Olof Johansson committed Aug 14, 2013
2 parents 3b2f64d + e607b0f commit e0bb396
Show file tree
Hide file tree
Showing 8 changed files with 633 additions and 21 deletions.
33 changes: 33 additions & 0 deletions Documentation/devicetree/bindings/arm/vexpress-scc.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
ARM Versatile Express Serial Configuration Controller
-----------------------------------------------------

Test chips for ARM Versatile Express platform implement SCC (Serial
Configuration Controller) interface, used to set initial conditions
for the test chip.

In some cases its registers are also mapped in normal address space
and can be used to obtain runtime information about the chip internals
(like silicon temperature sensors) and as interface to other subsystems
like platform configuration control and power management.

Required properties:

- compatible value: "arm,vexpress-scc,<model>", "arm,vexpress-scc";
where <model> is the full tile model name (as used
in the tile's Technical Reference Manual),
eg. for Coretile Express A15x2 A7x3 (V2P-CA15_A7):
compatible = "arm,vexpress-scc,v2p-ca15_a7", "arm,vexpress-scc";

Optional properties:

- reg: when the SCC is memory mapped, physical address and size of the
registers window
- interrupts: when the SCC can generate a system-level interrupt

Example:

scc@7fff0000 {
compatible = "arm,vexpress-scc,v2p-ca15_a7", "arm,vexpress-scc";
reg = <0 0x7fff0000 0 0x1000>;
interrupts = <0 95 4>;
};
6 changes: 6 additions & 0 deletions arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,12 @@
clock-names = "apb_pclk";
};

scc@7fff0000 {
compatible = "arm,vexpress-scc,v2p-ca15_a7", "arm,vexpress-scc";
reg = <0 0x7fff0000 0 0x1000>;
interrupts = <0 95 4>;
};

timer {
compatible = "arm,armv7-timer";
interrupts = <1 13 0xf08>,
Expand Down
8 changes: 8 additions & 0 deletions arch/arm/mach-vexpress/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -66,4 +66,12 @@ config ARCH_VEXPRESS_DCSCB
This is needed to provide CPU and cluster power management
on RTSM implementing big.LITTLE.

config ARCH_VEXPRESS_TC2_PM
bool "Versatile Express TC2 power management"
depends on MCPM
select ARM_CCI
help
Support for CPU and cluster power management on Versatile Express
with a TC2 (A15x2 A7x3) big.LITTLE core tile.

endmenu
1 change: 1 addition & 0 deletions arch/arm/mach-vexpress/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include \
obj-y := v2m.o
obj-$(CONFIG_ARCH_VEXPRESS_CA9X4) += ct-ca9x4.o
obj-$(CONFIG_ARCH_VEXPRESS_DCSCB) += dcscb.o dcscb_setup.o
obj-$(CONFIG_ARCH_VEXPRESS_TC2_PM) += tc2_pm.o spc.o
obj-$(CONFIG_SMP) += platsmp.o
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
58 changes: 37 additions & 21 deletions arch/arm/mach-vexpress/dcscb.c
Original file line number Diff line number Diff line change
Expand Up @@ -136,14 +136,29 @@ static void dcscb_power_down(void)
/*
* Flush all cache levels for this cluster.
*
* 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 (to be investigated).
* To do so we do:
* - Clear the SCTLR.C bit to prevent further cache allocations
* - Flush the whole cache
* - Clear the ACTLR "SMP" bit to disable local coherency
*
* Let's do it in the safest possible way i.e. with
* no memory access within the following sequence
* including to the stack.
*/
flush_cache_all();
set_cr(get_cr() & ~CR_C);
flush_cache_all();
asm volatile(
"mrc p15, 0, r0, c1, c0, 0 @ get CR \n\t"
"bic r0, r0, #"__stringify(CR_C)" \n\t"
"mcr p15, 0, r0, c1, c0, 0 @ set CR \n\t"
"isb \n\t"
"bl v7_flush_dcache_all \n\t"
"clrex \n\t"
"mrc p15, 0, r0, c1, c0, 1 @ get AUXCR \n\t"
"bic r0, r0, #(1 << 6) @ disable local coherency \n\t"
"mcr p15, 0, r0, c1, c0, 1 @ set AUXCR \n\t"
"isb \n\t"
"dsb "
: : : "r0","r1","r2","r3","r4","r5","r6","r7",
"r9","r10","r11","lr","memory");

/*
* This is a harmless no-op. On platforms with a real
Expand All @@ -152,9 +167,6 @@ static void dcscb_power_down(void)
*/
outer_flush_all();

/* Disable local coherency by clearing the ACTLR "SMP" bit: */
set_auxcr(get_auxcr() & ~(1 << 6));

/*
* Disable cluster-level coherency by masking
* incoming snoops and DVM messages:
Expand All @@ -167,18 +179,22 @@ static void dcscb_power_down(void)

/*
* Flush the local CPU cache.
*
* 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 (to be investigated).
* Let's do it in the safest possible way as above.
*/
flush_cache_louis();
set_cr(get_cr() & ~CR_C);
flush_cache_louis();

/* Disable local coherency by clearing the ACTLR "SMP" bit: */
set_auxcr(get_auxcr() & ~(1 << 6));
asm volatile(
"mrc p15, 0, r0, c1, c0, 0 @ get CR \n\t"
"bic r0, r0, #"__stringify(CR_C)" \n\t"
"mcr p15, 0, r0, c1, c0, 0 @ set CR \n\t"
"isb \n\t"
"bl v7_flush_dcache_louis \n\t"
"clrex \n\t"
"mrc p15, 0, r0, c1, c0, 1 @ get AUXCR \n\t"
"bic r0, r0, #(1 << 6) @ disable local coherency \n\t"
"mcr p15, 0, r0, c1, c0, 1 @ set AUXCR \n\t"
"isb \n\t"
"dsb "
: : : "r0","r1","r2","r3","r4","r5","r6","r7",
"r9","r10","r11","lr","memory");
}

__mcpm_cpu_down(cpu, cluster);
Expand Down
180 changes: 180 additions & 0 deletions arch/arm/mach-vexpress/spc.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
/*
* Versatile Express Serial Power Controller (SPC) support
*
* Copyright (C) 2013 ARM Ltd.
*
* Authors: Sudeep KarkadaNagesha <sudeep.karkadanagesha@arm.com>
* Achin Gupta <achin.gupta@arm.com>
* Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
*
* 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 <linux/err.h>
#include <linux/io.h>
#include <linux/slab.h>

#include <asm/cacheflush.h>

#define SPCLOG "vexpress-spc: "

/* 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_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);
}

int __init ve_spc_init(void __iomem *baseaddr, u32 a15_clusid)
{
info = kzalloc(sizeof(*info), GFP_KERNEL);
if (!info) {
pr_err(SPCLOG "unable to allocate mem\n");
return -ENOMEM;
}

info->baseaddr = baseaddr;
info->a15_clusid = a15_clusid;

/*
* 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;
}
24 changes: 24 additions & 0 deletions arch/arm/mach-vexpress/spc.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* 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 __iomem *base, u32 a15_clusid);
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);
void ve_spc_powerdown(u32 cluster, bool enable);

#endif
Loading

0 comments on commit e0bb396

Please sign in to comment.