Merge tag 'armsoc-soc' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc

Pull ARM SoC platform updates from Olof Johansson:
 "Our SoC branch usually contains expanded support for new SoCs and
  other core platform code.  In this case, that includes:

   - support for the new Annapurna Labs "Alpine" platform

   - a rework greatly simplifying adding new platform support to the
     MCPM subsystem (Multi-cluster power management)

   - cpuidle and PM improvements for Exynos3250

   - misc updates for Renesas, OMAP, Meson, i.MX.  Some of these could
     have gone in other branches but ended up here for various reasons"

* tag 'armsoc-soc' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (53 commits)
  ARM: alpine: add support for generic pci
  ARM: Exynos: migrate DCSCB to the new MCPM backend abstraction
  ARM: vexpress: migrate DCSCB to the new MCPM backend abstraction
  ARM: vexpress: DCSCB: tighten CPU validity assertion
  ARM: vexpress: migrate TC2 to the new MCPM backend abstraction
  ARM: MCPM: move the algorithmic complexity to the core code
  ARM: EXYNOS: allow cpuidle driver usage on Exynos3250 SoC
  ARM: EXYNOS: add AFTR mode support for Exynos3250
  ARM: EXYNOS: add code for setting/clearing boot flag
  ARM: EXYNOS: fix CPU1 hotplug on Exynos3250
  ARM: S3C64XX: Use fixed IRQ bases to avoid conflicts on Cragganmore
  ARM: cygnus: fix const declaration bcm_cygnus_dt_compat
  ARM: DRA7: hwmod: Fix the hwmod class for GPTimer4
  ARM: DRA7: hwmod: Add data for GPTimers 13 through 16
  ARM: EXYNOS: Remove left over 'extra_save'
  ARM: EXYNOS: Constify exynos_pm_data array
  ARM: EXYNOS: use static in suspend.c
  ARM: EXYNOS: Use platform device name as power domain name
  ARM: EXYNOS: add support for async-bridge clocks for pm_domains
  ARM: omap-device: add missed callback for suspend-to-disk
  ...
This commit is contained in:
Linus Torvalds
2015-04-22 09:08:39 -07:00
60 changed files with 1642 additions and 634 deletions
+5
View File
@@ -96,6 +96,11 @@ EBU Armada family
88F6820
88F6828
Armada 390/398 Flavors:
88F6920
88F6928
Product infos: http://www.marvell.com/embedded-processors/armada-39x/
Armada XP Flavors:
MV78230
MV78260
@@ -0,0 +1,88 @@
Annapurna Labs Alpine Platform Device Tree Bindings
---------------------------------------------------------------
Boards in the Alpine family shall have the following properties:
* Required root node properties:
compatible: must contain "al,alpine"
* Example:
/ {
model = "Annapurna Labs Alpine Dev Board";
compatible = "al,alpine";
...
}
* CPU node:
The Alpine platform includes cortex-a15 cores.
enable-method: must be "al,alpine-smp" to allow smp [1]
Example:
cpus {
#address-cells = <1>;
#size-cells = <0>;
enable-method = "al,alpine-smp";
cpu@0 {
compatible = "arm,cortex-a15";
device_type = "cpu";
reg = <0>;
};
cpu@1 {
compatible = "arm,cortex-a15";
device_type = "cpu";
reg = <1>;
};
cpu@2 {
compatible = "arm,cortex-a15";
device_type = "cpu";
reg = <2>;
};
cpu@3 {
compatible = "arm,cortex-a15";
device_type = "cpu";
reg = <3>;
};
};
* Alpine CPU resume registers
The CPU resume register are used to define required resume address after
reset.
Properties:
- compatible : Should contain "al,alpine-cpu-resume".
- reg : Offset and length of the register set for the device
Example:
cpu_resume {
compatible = "al,alpine-cpu-resume";
reg = <0xfbff5ed0 0x30>;
};
* Alpine System-Fabric Service Registers
The System-Fabric Service Registers allow various operation on CPU and
system fabric, like powering CPUs off.
Properties:
- compatible : Should contain "al,alpine-sysfabric-service" and "syscon".
- reg : Offset and length of the register set for the device
Example:
nb_service {
compatible = "al,alpine-sysfabric-service", "syscon";
reg = <0xfb070000 0x10000>;
};
[1] arm/cpu-enable-method/al,alpine-smp
@@ -8,3 +8,7 @@ Boards with the Amlogic Meson6 SoC shall have the following properties:
Boards with the Amlogic Meson8 SoC shall have the following properties:
Required root node property:
compatible: "amlogic,meson8";
Board compatible values:
- "geniatech,atv1200"
- "minix,neo-x8"
@@ -0,0 +1,20 @@
Marvell Armada 39x Platforms Device Tree Bindings
-------------------------------------------------
Boards with a SoC of the Marvell Armada 39x family shall have the
following property:
Required root node property:
- compatible: must contain "marvell,armada390"
In addition, boards using the Marvell Armada 398 SoC shall have the
following property before the previous one:
Required root node property:
compatible: must contain "marvell,armada398"
Example:
compatible = "marvell,a398-db", "marvell,armada398", "marvell,armada390";
@@ -0,0 +1,52 @@
========================================================
Secondary CPU enable-method "al,alpine-smp" binding
========================================================
This document describes the "al,alpine-smp" method for
enabling secondary CPUs. To apply to all CPUs, a single
"al,alpine-smp" enable method should be defined in the
"cpus" node.
Enable method name: "al,alpine-smp"
Compatible machines: "al,alpine"
Compatible CPUs: "arm,cortex-a15"
Related properties: (none)
Note:
This enable method requires valid nodes compatible with
"al,alpine-cpu-resume" and "al,alpine-nb-service"[1].
Example:
cpus {
#address-cells = <1>;
#size-cells = <0>;
enable-method = "al,alpine-smp";
cpu@0 {
compatible = "arm,cortex-a15";
device_type = "cpu";
reg = <0>;
};
cpu@1 {
compatible = "arm,cortex-a15";
device_type = "cpu";
reg = <1>;
};
cpu@2 {
compatible = "arm,cortex-a15";
device_type = "cpu";
reg = <2>;
};
cpu@3 {
compatible = "arm,cortex-a15";
device_type = "cpu";
reg = <3>;
};
};
--
[1] arm/al,alpine.txt
@@ -192,6 +192,7 @@ nodes to be present and contain the properties described below.
"brcm,brahma-b15"
"marvell,armada-375-smp"
"marvell,armada-380-smp"
"marvell,armada-390-smp"
"marvell,armada-xp-smp"
"qcom,gcc-msm8660"
"qcom,kpss-acc-v1"
@@ -1,5 +0,0 @@
Geniatech platforms device tree bindings
-------------------------------------------
Geniatech ATV1200
- compatible = "geniatech,atv1200"
@@ -0,0 +1,59 @@
Freescale i.MX General Power Controller
=======================================
The i.MX6Q General Power Control (GPC) block contains DVFS load tracking
counters and Power Gating Control (PGC) for the CPU and PU (GPU/VPU) power
domains.
Required properties:
- compatible: Should be "fsl,imx6q-gpc" or "fsl,imx6sl-gpc"
- reg: should be register base and length as documented in the
datasheet
- interrupts: Should contain GPC interrupt request 1
- pu-supply: Link to the LDO regulator powering the PU power domain
- clocks: Clock phandles to devices in the PU power domain that need
to be enabled during domain power-up for reset propagation.
- #power-domain-cells: Should be 1, see below:
The gpc node is a power-controller as documented by the generic power domain
bindings in Documentation/devicetree/bindings/power/power_domain.txt.
Example:
gpc: gpc@020dc000 {
compatible = "fsl,imx6q-gpc";
reg = <0x020dc000 0x4000>;
interrupts = <0 89 IRQ_TYPE_LEVEL_HIGH>,
<0 90 IRQ_TYPE_LEVEL_HIGH>;
pu-supply = <&reg_pu>;
clocks = <&clks IMX6QDL_CLK_GPU3D_CORE>,
<&clks IMX6QDL_CLK_GPU3D_SHADER>,
<&clks IMX6QDL_CLK_GPU2D_CORE>,
<&clks IMX6QDL_CLK_GPU2D_AXI>,
<&clks IMX6QDL_CLK_OPENVG_AXI>,
<&clks IMX6QDL_CLK_VPU_AXI>;
#power-domain-cells = <1>;
};
Specifying power domain for IP modules
======================================
IP cores belonging to a power domain should contain a 'power-domains' property
that is a phandle pointing to the gpc device node and a DOMAIN_INDEX specifying
the power domain the device belongs to.
Example of a device that is part of the PU power domain:
vpu: vpu@02040000 {
reg = <0x02040000 0x3c000>;
/* ... */
power-domains = <&gpc 1>;
/* ... */
};
The following DOMAIN_INDEX values are valid for i.MX6Q:
ARM_DOMAIN 0
PU_DOMAIN 1
The following additional DOMAIN_INDEX value is valid for i.MX6SL:
DISPLAY_DOMAIN 2
@@ -11,6 +11,7 @@ adapteva Adapteva, Inc.
adh AD Holdings Plc.
adi Analog Devices, Inc.
aeroflexgaisler Aeroflex Gaisler AB
al Annapurna Labs
allwinner Allwinner Technology Co., Ltd.
alphascale AlphaScale Integrated Circuits Systems, Inc.
altr Altera Corp.
@@ -118,6 +119,7 @@ merrii Merrii Technology Co., Ltd.
micrel Micrel Inc.
microchip Microchip Technology Inc.
micron Micron Technology Inc.
minix MINIX Technology Ltd.
mitsubishi Mitsubishi Electric Corporation
mosaixtech Mosaix Technologies, Inc.
moxa Moxa
+5
View File
@@ -886,6 +886,11 @@ S: Maintained
F: drivers/media/rc/meson-ir.c
N: meson[x68]
ARM/Annapurna Labs ALPINE ARCHITECTURE
M: Tsahee Zidenberg <tsahee@annapurnalabs.com>
S: Maintained
F: arch/arm/mach-alpine/
ARM/ATMEL AT91RM9200 AND AT91SAM ARM ARCHITECTURES
M: Andrew Victor <linux@maxim.org.za>
M: Nicolas Ferre <nicolas.ferre@atmel.com>
+2
View File
@@ -839,6 +839,8 @@ config ARCH_VIRT
#
source "arch/arm/mach-mvebu/Kconfig"
source "arch/arm/mach-alpine/Kconfig"
source "arch/arm/mach-asm9260/Kconfig"
source "arch/arm/mach-at91/Kconfig"
+11 -1
View File
@@ -93,6 +93,14 @@ choice
prompt "Kernel low-level debugging port"
depends on DEBUG_LL
config DEBUG_ALPINE_UART0
bool "Kernel low-level debugging messages via Alpine UART0"
depends on ARCH_ALPINE
select DEBUG_UART_8250
help
Say Y here if you want kernel low-level debugging support
on Alpine based platforms.
config DEBUG_ASM9260_UART
bool "Kernel low-level debugging via asm9260 UART"
depends on MACH_ASM9260
@@ -1397,6 +1405,7 @@ config DEBUG_UART_PHYS
default 0xf8b00000 if DEBUG_HIX5HD2_UART
default 0xf991e000 if DEBUG_QCOM_UARTDM
default 0xfcb00000 if DEBUG_HI3620_UART
default 0xfd883000 if DEBUG_ALPINE_UART0
default 0xfe800000 if ARCH_IOP32X
default 0xff690000 if DEBUG_RK32_UART2
default 0xffc02000 if DEBUG_SOCFPGA_UART
@@ -1462,6 +1471,7 @@ config DEBUG_UART_VIRT
default 0xfd000000 if ARCH_SPEAR3XX || ARCH_SPEAR6XX
default 0xfd000000 if ARCH_SPEAR13XX
default 0xfd012000 if ARCH_MV78XX0
default 0xfd883000 if DEBUG_ALPINE_UART0
default 0xfde12000 if ARCH_DOVE
default 0xfe012000 if ARCH_ORION5X
default 0xf31004c0 if DEBUG_MESON_UARTAO
@@ -1522,7 +1532,7 @@ config DEBUG_UART_8250_WORD
depends on DEBUG_LL_UART_8250 || DEBUG_UART_8250
depends on DEBUG_UART_8250_SHIFT >= 2
default y if DEBUG_PICOXCELL_UART || DEBUG_SOCFPGA_UART || \
ARCH_KEYSTONE || \
ARCH_KEYSTONE || DEBUG_ALPINE_UART0 || \
DEBUG_DAVINCI_DMx_UART0 || DEBUG_DAVINCI_DA8XX_UART1 || \
DEBUG_DAVINCI_DA8XX_UART2 || \
DEBUG_BCM_KONA_UART || DEBUG_RK32_UART2 || \
+1
View File
@@ -142,6 +142,7 @@ textofs-$(CONFIG_ARCH_AXXIA) := 0x00308000
# Machine directory name. This list is sorted alphanumerically
# by CONFIG_* macro name.
machine-$(CONFIG_ARCH_ALPINE) += alpine
machine-$(CONFIG_ARCH_AT91) += at91
machine-$(CONFIG_ARCH_AXXIA) += axxia
machine-$(CONFIG_ARCH_BCM) += bcm
+18
View File
@@ -513,9 +513,27 @@
pinctrl-0 = <&iic3_pins>;
status = "okay";
pmic@58 {
compatible = "dlg,da9063";
reg = <0x58>;
interrupt-parent = <&irqc0>;
interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
interrupt-controller;
rtc {
compatible = "dlg,da9063-rtc";
};
wdt {
compatible = "dlg,da9063-watchdog";
};
};
vdd_dvfs: regulator@68 {
compatible = "dlg,da9210";
reg = <0x68>;
interrupt-parent = <&irqc0>;
interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <1000000>;
+18
View File
@@ -517,9 +517,27 @@
status = "okay";
clock-frequency = <100000>;
pmic@58 {
compatible = "dlg,da9063";
reg = <0x58>;
interrupt-parent = <&irqc0>;
interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
interrupt-controller;
rtc {
compatible = "dlg,da9063-rtc";
};
wdt {
compatible = "dlg,da9063-watchdog";
};
};
vdd_dvfs: regulator@68 {
compatible = "dlg,da9210";
reg = <0x68>;
interrupt-parent = <&irqc0>;
interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <1000000>;
+170 -32
View File
@@ -55,22 +55,81 @@ bool mcpm_is_available(void)
return (platform_ops) ? true : false;
}
/*
* 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 mcpm_lock = __ARCH_SPIN_LOCK_UNLOCKED;
static int mcpm_cpu_use_count[MAX_NR_CLUSTERS][MAX_CPUS_PER_CLUSTER];
static inline bool mcpm_cluster_unused(unsigned int cluster)
{
int i, cnt;
for (i = 0, cnt = 0; i < MAX_CPUS_PER_CLUSTER; i++)
cnt |= mcpm_cpu_use_count[cluster][i];
return !cnt;
}
int mcpm_cpu_power_up(unsigned int cpu, unsigned int cluster)
{
bool cpu_is_down, cluster_is_down;
int ret = 0;
if (!platform_ops)
return -EUNATCH; /* try not to shadow power_up errors */
might_sleep();
return platform_ops->power_up(cpu, cluster);
/* backward compatibility callback */
if (platform_ops->power_up)
return platform_ops->power_up(cpu, cluster);
pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
/*
* 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(&mcpm_lock);
cpu_is_down = !mcpm_cpu_use_count[cluster][cpu];
cluster_is_down = mcpm_cluster_unused(cluster);
mcpm_cpu_use_count[cluster][cpu]++;
/*
* The only possible values are:
* 0 = CPU down
* 1 = CPU (still) up
* 2 = CPU requested to be up before it had a chance
* to actually make itself down.
* Any other value is a bug.
*/
BUG_ON(mcpm_cpu_use_count[cluster][cpu] != 1 &&
mcpm_cpu_use_count[cluster][cpu] != 2);
if (cluster_is_down)
ret = platform_ops->cluster_powerup(cluster);
if (cpu_is_down && !ret)
ret = platform_ops->cpu_powerup(cpu, cluster);
arch_spin_unlock(&mcpm_lock);
local_irq_enable();
return ret;
}
typedef void (*phys_reset_t)(unsigned long);
void mcpm_cpu_power_down(void)
{
unsigned int mpidr, cpu, cluster;
bool cpu_going_down, last_man;
phys_reset_t phys_reset;
if (WARN_ON_ONCE(!platform_ops || !platform_ops->power_down))
return;
if (WARN_ON_ONCE(!platform_ops))
return;
BUG_ON(!irqs_disabled());
/*
@@ -79,28 +138,65 @@ void mcpm_cpu_power_down(void)
*/
setup_mm_for_reboot();
platform_ops->power_down();
/* backward compatibility callback */
if (platform_ops->power_down) {
platform_ops->power_down();
goto not_dead;
}
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);
__mcpm_cpu_going_down(cpu, cluster);
arch_spin_lock(&mcpm_lock);
BUG_ON(__mcpm_cluster_state(cluster) != CLUSTER_UP);
mcpm_cpu_use_count[cluster][cpu]--;
BUG_ON(mcpm_cpu_use_count[cluster][cpu] != 0 &&
mcpm_cpu_use_count[cluster][cpu] != 1);
cpu_going_down = !mcpm_cpu_use_count[cluster][cpu];
last_man = mcpm_cluster_unused(cluster);
if (last_man && __mcpm_outbound_enter_critical(cpu, cluster)) {
platform_ops->cpu_powerdown_prepare(cpu, cluster);
platform_ops->cluster_powerdown_prepare(cluster);
arch_spin_unlock(&mcpm_lock);
platform_ops->cluster_cache_disable();
__mcpm_outbound_leave_critical(cluster, CLUSTER_DOWN);
} else {
if (cpu_going_down)
platform_ops->cpu_powerdown_prepare(cpu, cluster);
arch_spin_unlock(&mcpm_lock);
/*
* If cpu_going_down is false here, that means a power_up
* request raced ahead of us. Even if we do not want to
* shut this CPU down, the caller still expects execution
* to return through the system resume entry path, like
* when the WFI is aborted due to a new IRQ or the like..
* So let's continue with cache cleaning in all cases.
*/
platform_ops->cpu_cache_disable();
}
__mcpm_cpu_down(cpu, cluster);
/* Now we are prepared for power-down, do it: */
if (cpu_going_down)
wfi();
not_dead:
/*
* It is possible for a power_up request to happen concurrently
* with a power_down request for the same CPU. In this case the
* power_down method might not be able to actually enter a
* powered down state with the WFI instruction if the power_up
* method has removed the required reset condition. The
* power_down method is then allowed to return. We must perform
* a re-entry in the kernel as if the power_up method just had
* deasserted reset on the CPU.
*
* To simplify race issues, the platform specific implementation
* must accommodate for the possibility of unordered calls to
* power_down and power_up with a usage count. Therefore, if a
* call to power_up is issued for a CPU that is not down, then
* the next call to power_down must not attempt a full shutdown
* but only do the minimum (normally disabling L1 cache and CPU
* coherency) and return just as if a concurrent power_up request
* had happened as described above.
* CPU might not be able to actually enter a powered down state
* with the WFI instruction if the power_up request has removed
* the required reset condition. We must perform a re-entry in
* the kernel as if the power_up method just had deasserted reset
* on the CPU.
*/
phys_reset = (phys_reset_t)(unsigned long)virt_to_phys(cpu_reset);
phys_reset(virt_to_phys(mcpm_entry_point));
@@ -125,26 +221,66 @@ int mcpm_wait_for_cpu_powerdown(unsigned int cpu, unsigned int cluster)
void mcpm_cpu_suspend(u64 expected_residency)
{
phys_reset_t phys_reset;
if (WARN_ON_ONCE(!platform_ops || !platform_ops->suspend))
if (WARN_ON_ONCE(!platform_ops))
return;
BUG_ON(!irqs_disabled());
/* Very similar to mcpm_cpu_power_down() */
setup_mm_for_reboot();
platform_ops->suspend(expected_residency);
phys_reset = (phys_reset_t)(unsigned long)virt_to_phys(cpu_reset);
phys_reset(virt_to_phys(mcpm_entry_point));
BUG();
/* backward compatibility callback */
if (platform_ops->suspend) {
phys_reset_t phys_reset;
BUG_ON(!irqs_disabled());
setup_mm_for_reboot();
platform_ops->suspend(expected_residency);
phys_reset = (phys_reset_t)(unsigned long)virt_to_phys(cpu_reset);
phys_reset(virt_to_phys(mcpm_entry_point));
BUG();
}
/* Some platforms might have to enable special resume modes, etc. */
if (platform_ops->cpu_suspend_prepare) {
unsigned int mpidr = read_cpuid_mpidr();
unsigned int cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
unsigned int cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
arch_spin_lock(&mcpm_lock);
platform_ops->cpu_suspend_prepare(cpu, cluster);
arch_spin_unlock(&mcpm_lock);
}
mcpm_cpu_power_down();
}
int mcpm_cpu_powered_up(void)
{
unsigned int mpidr, cpu, cluster;
bool cpu_was_down, first_man;
unsigned long flags;
if (!platform_ops)
return -EUNATCH;
if (platform_ops->powered_up)
/* backward compatibility callback */
if (platform_ops->powered_up) {
platform_ops->powered_up();
return 0;
}
mpidr = read_cpuid_mpidr();
cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
local_irq_save(flags);
arch_spin_lock(&mcpm_lock);
cpu_was_down = !mcpm_cpu_use_count[cluster][cpu];
first_man = mcpm_cluster_unused(cluster);
if (first_man && platform_ops->cluster_is_up)
platform_ops->cluster_is_up(cluster);
if (cpu_was_down)
mcpm_cpu_use_count[cluster][cpu] = 1;
if (platform_ops->cpu_is_up)
platform_ops->cpu_is_up(cpu, cluster);
arch_spin_unlock(&mcpm_lock);
local_irq_restore(flags);
return 0;
}
@@ -334,8 +470,10 @@ int __init mcpm_sync_init(
}
mpidr = read_cpuid_mpidr();
this_cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
for_each_online_cpu(i)
for_each_online_cpu(i) {
mcpm_cpu_use_count[this_cluster][i] = 1;
mcpm_sync.clusters[this_cluster].cpus[i].cpu = CPU_UP;
}
mcpm_sync.clusters[this_cluster].cluster = CLUSTER_UP;
sync_cache_w(&mcpm_sync);
+63 -2
View File
@@ -171,12 +171,73 @@ void mcpm_cpu_suspend(u64 expected_residency);
int mcpm_cpu_powered_up(void);
/*
* Platform specific methods used in the implementation of the above API.
* Platform specific callbacks used in the implementation of the above API.
*
* cpu_powerup:
* Make given CPU runable. Called with MCPM lock held and IRQs disabled.
* The given cluster is assumed to be set up (cluster_powerup would have
* been called beforehand). Must return 0 for success or negative error code.
*
* cluster_powerup:
* Set up power for given cluster. Called with MCPM lock held and IRQs
* disabled. Called before first cpu_powerup when cluster is down. Must
* return 0 for success or negative error code.
*
* cpu_suspend_prepare:
* Special suspend configuration. Called on target CPU with MCPM lock held
* and IRQs disabled. This callback is optional. If provided, it is called
* before cpu_powerdown_prepare.
*
* cpu_powerdown_prepare:
* Configure given CPU for power down. Called on target CPU with MCPM lock
* held and IRQs disabled. Power down must be effective only at the next WFI instruction.
*
* cluster_powerdown_prepare:
* Configure given cluster for power down. Called on one CPU from target
* cluster with MCPM lock held and IRQs disabled. A cpu_powerdown_prepare
* for each CPU in the cluster has happened when this occurs.
*
* cpu_cache_disable:
* Clean and disable CPU level cache for the calling CPU. Called on with IRQs
* disabled only. The CPU is no longer cache coherent with the rest of the
* system when this returns.
*
* cluster_cache_disable:
* Clean and disable the cluster wide cache as well as the CPU level cache
* for the calling CPU. No call to cpu_cache_disable will happen for this
* CPU. Called with IRQs disabled and only when all the other CPUs are done
* with their own cpu_cache_disable. The cluster is no longer cache coherent
* with the rest of the system when this returns.
*
* cpu_is_up:
* Called on given CPU after it has been powered up or resumed. The MCPM lock
* is held and IRQs disabled. This callback is optional.
*
* cluster_is_up:
* Called by the first CPU to be powered up or resumed in given cluster.
* The MCPM lock is held and IRQs disabled. This callback is optional. If
* provided, it is called before cpu_is_up for that CPU.
*
* wait_for_powerdown:
* Wait until given CPU is powered down. This is called in sleeping context.
* Some reasonable timeout must be considered. Must return 0 for success or
* negative error code.
*/
struct mcpm_platform_ops {
int (*cpu_powerup)(unsigned int cpu, unsigned int cluster);
int (*cluster_powerup)(unsigned int cluster);
void (*cpu_suspend_prepare)(unsigned int cpu, unsigned int cluster);
void (*cpu_powerdown_prepare)(unsigned int cpu, unsigned int cluster);
void (*cluster_powerdown_prepare)(unsigned int cluster);
void (*cpu_cache_disable)(void);
void (*cluster_cache_disable)(void);
void (*cpu_is_up)(unsigned int cpu, unsigned int cluster);
void (*cluster_is_up)(unsigned int cluster);
int (*wait_for_powerdown)(unsigned int cpu, unsigned int cluster);
/* deprecated callbacks */
int (*power_up)(unsigned int cpu, unsigned int cluster);
void (*power_down)(void);
int (*wait_for_powerdown)(unsigned int cpu, unsigned int cluster);
void (*suspend)(u64);
void (*powered_up)(void);
};
+12
View File
@@ -0,0 +1,12 @@
config ARCH_ALPINE
bool "Annapurna Labs Alpine platform" if ARCH_MULTI_V7
select ARM_AMBA
select ARM_GIC
select GENERIC_IRQ_CHIP
select HAVE_ARM_ARCH_TIMER
select HAVE_SMP
select MFD_SYSCON
select PCI
select PCI_HOST_GENERIC
help
This enables support for the Annapurna Labs Alpine V1 boards.
+2
View File
@@ -0,0 +1,2 @@
obj-y += alpine_machine.o
obj-$(CONFIG_SMP) += platsmp.o alpine_cpu_pm.o
+70
View File
@@ -0,0 +1,70 @@
/*
* Low-level power-management support for Alpine platform.
*
* Copyright (C) 2015 Annapurna Labs Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*/
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/regmap.h>
#include <linux/mfd/syscon.h>
#include "alpine_cpu_pm.h"
#include "alpine_cpu_resume.h"
/* NB registers */
#define AL_SYSFAB_POWER_CONTROL(cpu) (0x2000 + (cpu)*0x100 + 0x20)
static struct regmap *al_sysfabric;
static struct al_cpu_resume_regs __iomem *al_cpu_resume_regs;
static int wakeup_supported;
int alpine_cpu_wakeup(unsigned int phys_cpu, uint32_t phys_resume_addr)
{
if (!wakeup_supported)
return -ENOSYS;
/*
* Set CPU resume address -
* secure firmware running on boot will jump to this address
* after setting proper CPU mode, and initialiing e.g. secure
* regs (the same mode all CPUs are booted to - usually HYP)
*/
writel(phys_resume_addr,
&al_cpu_resume_regs->per_cpu[phys_cpu].resume_addr);
/* Power-up the CPU */
regmap_write(al_sysfabric, AL_SYSFAB_POWER_CONTROL(phys_cpu), 0);
return 0;
}
void __init alpine_cpu_pm_init(void)
{
struct device_node *np;
uint32_t watermark;
al_sysfabric = syscon_regmap_lookup_by_compatible("al,alpine-sysfabric-service");
np = of_find_compatible_node(NULL, NULL, "al,alpine-cpu-resume");
al_cpu_resume_regs = of_iomap(np, 0);
wakeup_supported = !IS_ERR(al_sysfabric) && al_cpu_resume_regs;
if (wakeup_supported) {
watermark = readl(&al_cpu_resume_regs->watermark);
wakeup_supported = (watermark & AL_CPU_RESUME_MAGIC_NUM_MASK)
== AL_CPU_RESUME_MAGIC_NUM;
}
}

Some files were not shown because too many files have changed in this diff Show More