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 Lunnstatic 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 Lunnstatic 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 Lunnstatic 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 Dooksvoid __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