xref: /openbmc/linux/arch/arm/mach-mvebu/kirkwood-pm.c (revision 75bf465f0bc33e9b776a46d6a1b9b990f5fb7c37)
1*0b0191aeSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2ba5a37e5SAndrew Lunn /*
3ba5a37e5SAndrew Lunn  * Power Management driver for Marvell Kirkwood SoCs
4ba5a37e5SAndrew Lunn  *
5ba5a37e5SAndrew Lunn  * Copyright (C) 2013 Ezequiel Garcia <ezequiel@free-electrons.com>
6ba5a37e5SAndrew Lunn  * Copyright (C) 2010 Simon Guinot <sguinot@lacie.com>
7ba5a37e5SAndrew Lunn  */
8ba5a37e5SAndrew Lunn 
9ba5a37e5SAndrew Lunn #include <linux/kernel.h>
10ba5a37e5SAndrew Lunn #include <linux/suspend.h>
11ba5a37e5SAndrew Lunn #include <linux/io.h>
12c3f08d0dSAndrew Lunn #include "kirkwood.h"
13d705c1a6SBen Dooks #include "kirkwood-pm.h"
14ba5a37e5SAndrew Lunn 
15ba5a37e5SAndrew Lunn static void __iomem *ddr_operation_base;
16ba5a37e5SAndrew Lunn static void __iomem *memory_pm_ctrl;
17ba5a37e5SAndrew Lunn 
kirkwood_low_power(void)18ba5a37e5SAndrew Lunn static void kirkwood_low_power(void)
19ba5a37e5SAndrew Lunn {
20ba5a37e5SAndrew Lunn 	u32 mem_pm_ctrl;
21ba5a37e5SAndrew Lunn 
22ba5a37e5SAndrew Lunn 	mem_pm_ctrl = readl(memory_pm_ctrl);
23ba5a37e5SAndrew Lunn 
24ba5a37e5SAndrew Lunn 	/* Set peripherals to low-power mode */
25ba5a37e5SAndrew Lunn 	writel_relaxed(~0, memory_pm_ctrl);
26ba5a37e5SAndrew Lunn 
27ba5a37e5SAndrew Lunn 	/* Set DDR in self-refresh */
28ba5a37e5SAndrew Lunn 	writel_relaxed(0x7, ddr_operation_base);
29ba5a37e5SAndrew Lunn 
30ba5a37e5SAndrew Lunn 	/*
31ba5a37e5SAndrew Lunn 	 * Set CPU in wait-for-interrupt state.
32ba5a37e5SAndrew Lunn 	 * This disables the CPU core clocks,
33ba5a37e5SAndrew Lunn 	 * the array clocks, and also the L2 controller.
34ba5a37e5SAndrew Lunn 	 */
35ba5a37e5SAndrew Lunn 	cpu_do_idle();
36ba5a37e5SAndrew Lunn 
37ba5a37e5SAndrew Lunn 	writel_relaxed(mem_pm_ctrl, memory_pm_ctrl);
38ba5a37e5SAndrew Lunn }
39ba5a37e5SAndrew Lunn 
kirkwood_suspend_enter(suspend_state_t state)40ba5a37e5SAndrew Lunn static int kirkwood_suspend_enter(suspend_state_t state)
41ba5a37e5SAndrew Lunn {
42ba5a37e5SAndrew Lunn 	switch (state) {
43ba5a37e5SAndrew Lunn 	case PM_SUSPEND_STANDBY:
44ba5a37e5SAndrew Lunn 		kirkwood_low_power();
45ba5a37e5SAndrew Lunn 		break;
46ba5a37e5SAndrew Lunn 	default:
47ba5a37e5SAndrew Lunn 		return -EINVAL;
48ba5a37e5SAndrew Lunn 	}
49ba5a37e5SAndrew Lunn 	return 0;
50ba5a37e5SAndrew Lunn }
51ba5a37e5SAndrew Lunn 
kirkwood_pm_valid_standby(suspend_state_t state)52ba5a37e5SAndrew Lunn static int kirkwood_pm_valid_standby(suspend_state_t state)
53ba5a37e5SAndrew Lunn {
54ba5a37e5SAndrew Lunn 	return state == PM_SUSPEND_STANDBY;
55ba5a37e5SAndrew Lunn }
56ba5a37e5SAndrew Lunn 
57ba5a37e5SAndrew Lunn static const struct platform_suspend_ops kirkwood_suspend_ops = {
58ba5a37e5SAndrew Lunn 	.enter = kirkwood_suspend_enter,
59ba5a37e5SAndrew Lunn 	.valid = kirkwood_pm_valid_standby,
60ba5a37e5SAndrew Lunn };
61ba5a37e5SAndrew Lunn 
kirkwood_pm_init(void)62d705c1a6SBen Dooks void __init kirkwood_pm_init(void)
63ba5a37e5SAndrew Lunn {
64ba5a37e5SAndrew Lunn 	ddr_operation_base = ioremap(DDR_OPERATION_BASE, 4);
65ba5a37e5SAndrew Lunn 	memory_pm_ctrl = ioremap(MEMORY_PM_CTRL_PHYS, 4);
66ba5a37e5SAndrew Lunn 
67ba5a37e5SAndrew Lunn 	suspend_set_ops(&kirkwood_suspend_ops);
68ba5a37e5SAndrew Lunn }
69