18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Power Management driver for Marvell Kirkwood SoCs 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2013 Ezequiel Garcia <ezequiel@free-electrons.com> 68c2ecf20Sopenharmony_ci * Copyright (C) 2010 Simon Guinot <sguinot@lacie.com> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/kernel.h> 108c2ecf20Sopenharmony_ci#include <linux/suspend.h> 118c2ecf20Sopenharmony_ci#include <linux/io.h> 128c2ecf20Sopenharmony_ci#include "kirkwood.h" 138c2ecf20Sopenharmony_ci#include "kirkwood-pm.h" 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_cistatic void __iomem *ddr_operation_base; 168c2ecf20Sopenharmony_cistatic void __iomem *memory_pm_ctrl; 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_cistatic void kirkwood_low_power(void) 198c2ecf20Sopenharmony_ci{ 208c2ecf20Sopenharmony_ci u32 mem_pm_ctrl; 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci mem_pm_ctrl = readl(memory_pm_ctrl); 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci /* Set peripherals to low-power mode */ 258c2ecf20Sopenharmony_ci writel_relaxed(~0, memory_pm_ctrl); 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci /* Set DDR in self-refresh */ 288c2ecf20Sopenharmony_ci writel_relaxed(0x7, ddr_operation_base); 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci /* 318c2ecf20Sopenharmony_ci * Set CPU in wait-for-interrupt state. 328c2ecf20Sopenharmony_ci * This disables the CPU core clocks, 338c2ecf20Sopenharmony_ci * the array clocks, and also the L2 controller. 348c2ecf20Sopenharmony_ci */ 358c2ecf20Sopenharmony_ci cpu_do_idle(); 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci writel_relaxed(mem_pm_ctrl, memory_pm_ctrl); 388c2ecf20Sopenharmony_ci} 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistatic int kirkwood_suspend_enter(suspend_state_t state) 418c2ecf20Sopenharmony_ci{ 428c2ecf20Sopenharmony_ci switch (state) { 438c2ecf20Sopenharmony_ci case PM_SUSPEND_STANDBY: 448c2ecf20Sopenharmony_ci kirkwood_low_power(); 458c2ecf20Sopenharmony_ci break; 468c2ecf20Sopenharmony_ci default: 478c2ecf20Sopenharmony_ci return -EINVAL; 488c2ecf20Sopenharmony_ci } 498c2ecf20Sopenharmony_ci return 0; 508c2ecf20Sopenharmony_ci} 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cistatic int kirkwood_pm_valid_standby(suspend_state_t state) 538c2ecf20Sopenharmony_ci{ 548c2ecf20Sopenharmony_ci return state == PM_SUSPEND_STANDBY; 558c2ecf20Sopenharmony_ci} 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistatic const struct platform_suspend_ops kirkwood_suspend_ops = { 588c2ecf20Sopenharmony_ci .enter = kirkwood_suspend_enter, 598c2ecf20Sopenharmony_ci .valid = kirkwood_pm_valid_standby, 608c2ecf20Sopenharmony_ci}; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_civoid __init kirkwood_pm_init(void) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci ddr_operation_base = ioremap(DDR_OPERATION_BASE, 4); 658c2ecf20Sopenharmony_ci memory_pm_ctrl = ioremap(MEMORY_PM_CTRL_PHYS, 4); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci suspend_set_ops(&kirkwood_suspend_ops); 688c2ecf20Sopenharmony_ci} 69