ARM: kirkwood: Add standby support

Implements standby support for Kirkwood SoC. When the SoC enters
standby state the memory PM units are disabled, the DDR is set
in self-refresh mode, and the CPU is set in WFI.

At this point there's no clock gating, as that is considered each
driver's task.

Signed-off-by: Simon Guinot <sguinot@lacie.com>
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
Signed-off-by: Jason Cooper <jason@lakedaemon.net>
This commit is contained in:
Ezequiel Garcia 2013-08-22 12:49:07 -03:00 committed by Jason Cooper
parent 272b98c645
commit e1cb367de2
6 changed files with 85 additions and 0 deletions

View File

@ -1,5 +1,7 @@
obj-y += common.o pcie.o obj-y += common.o pcie.o
obj-$(CONFIG_KIRKWOOD_LEGACY) += irq.o mpp.o obj-$(CONFIG_KIRKWOOD_LEGACY) += irq.o mpp.o
obj-$(CONFIG_PM) += pm.o
obj-$(CONFIG_MACH_D2NET_V2) += d2net_v2-setup.o lacie_v2-common.o obj-$(CONFIG_MACH_D2NET_V2) += d2net_v2-setup.o lacie_v2-common.o
obj-$(CONFIG_MACH_NET2BIG_V2) += netxbig_v2-setup.o lacie_v2-common.o obj-$(CONFIG_MACH_NET2BIG_V2) += netxbig_v2-setup.o lacie_v2-common.o
obj-$(CONFIG_MACH_NET5BIG_V2) += netxbig_v2-setup.o lacie_v2-common.o obj-$(CONFIG_MACH_NET5BIG_V2) += netxbig_v2-setup.o lacie_v2-common.o

View File

@ -101,6 +101,7 @@ static void __init kirkwood_dt_init(void)
/* Setup clocks for legacy devices */ /* Setup clocks for legacy devices */
kirkwood_legacy_clk_init(); kirkwood_legacy_clk_init();
kirkwood_pm_init();
kirkwood_cpuidle_init(); kirkwood_cpuidle_init();
#ifdef CONFIG_KEXEC #ifdef CONFIG_KEXEC

View File

@ -721,6 +721,7 @@ void __init kirkwood_init(void)
kirkwood_xor1_init(); kirkwood_xor1_init();
kirkwood_crypto_init(); kirkwood_crypto_init();
kirkwood_pm_init();
kirkwood_cpuidle_init(); kirkwood_cpuidle_init();
#ifdef CONFIG_KEXEC #ifdef CONFIG_KEXEC
kexec_reinit = kirkwood_enable_pcie; kexec_reinit = kirkwood_enable_pcie;

View File

@ -58,6 +58,12 @@ void kirkwood_cpufreq_init(void);
void kirkwood_restart(enum reboot_mode, const char *); void kirkwood_restart(enum reboot_mode, const char *);
void kirkwood_clk_init(void); void kirkwood_clk_init(void);
#ifdef CONFIG_PM
void kirkwood_pm_init(void);
#else
static inline void kirkwood_pm_init(void) {};
#endif
/* board init functions for boards not fully converted to fdt */ /* board init functions for boards not fully converted to fdt */
#ifdef CONFIG_MACH_MV88F6281GTW_GE_DT #ifdef CONFIG_MACH_MV88F6281GTW_GE_DT
void mv88f6281gtw_ge_init(void); void mv88f6281gtw_ge_init(void);

View File

@ -78,4 +78,6 @@
#define CGC_TDM (1 << 20) #define CGC_TDM (1 << 20)
#define CGC_RESERVED (0x6 << 21) #define CGC_RESERVED (0x6 << 21)
#define MEMORY_PM_CTRL (BRIDGE_VIRT_BASE + 0x118)
#endif #endif

View File

@ -0,0 +1,73 @@
/*
* Power Management driver for Marvell Kirkwood SoCs
*
* Copyright (C) 2013 Ezequiel Garcia <ezequiel@free-electrons.com>
* Copyright (C) 2010 Simon Guinot <sguinot@lacie.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 of the License.
*
* 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/kernel.h>
#include <linux/suspend.h>
#include <linux/io.h>
#include <mach/bridge-regs.h>
static void __iomem *ddr_operation_base;
static void kirkwood_low_power(void)
{
u32 mem_pm_ctrl;
mem_pm_ctrl = readl(MEMORY_PM_CTRL);
/* Set peripherals to low-power mode */
writel_relaxed(~0, MEMORY_PM_CTRL);
/* Set DDR in self-refresh */
writel_relaxed(0x7, ddr_operation_base);
/*
* Set CPU in wait-for-interrupt state.
* This disables the CPU core clocks,
* the array clocks, and also the L2 controller.
*/
cpu_do_idle();
writel_relaxed(mem_pm_ctrl, MEMORY_PM_CTRL);
}
static int kirkwood_suspend_enter(suspend_state_t state)
{
switch (state) {
case PM_SUSPEND_STANDBY:
kirkwood_low_power();
break;
default:
return -EINVAL;
}
return 0;
}
static int kirkwood_pm_valid_standby(suspend_state_t state)
{
return state == PM_SUSPEND_STANDBY;
}
static const struct platform_suspend_ops kirkwood_suspend_ops = {
.enter = kirkwood_suspend_enter,
.valid = kirkwood_pm_valid_standby,
};
int __init kirkwood_pm_init(void)
{
ddr_operation_base = ioremap(DDR_OPERATION_BASE, 4);
suspend_set_ops(&kirkwood_suspend_ops);
return 0;
}