18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2012-2013 Xilinx
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * CPU idle support for Xilinx Zynq
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * based on arch/arm/mach-at91/cpuidle.c
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * The cpu idle uses wait-for-interrupt and RAM self refresh in order
108c2ecf20Sopenharmony_ci * to implement two idle states -
118c2ecf20Sopenharmony_ci * #1 wait-for-interrupt
128c2ecf20Sopenharmony_ci * #2 wait-for-interrupt and RAM self refresh
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci * Maintainer: Michal Simek <michal.simek@xilinx.com>
158c2ecf20Sopenharmony_ci */
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#include <linux/init.h>
188c2ecf20Sopenharmony_ci#include <linux/cpuidle.h>
198c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
208c2ecf20Sopenharmony_ci#include <asm/cpuidle.h>
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#define ZYNQ_MAX_STATES		2
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci/* Actual code that puts the SoC in different idle states */
258c2ecf20Sopenharmony_cistatic int zynq_enter_idle(struct cpuidle_device *dev,
268c2ecf20Sopenharmony_ci			   struct cpuidle_driver *drv, int index)
278c2ecf20Sopenharmony_ci{
288c2ecf20Sopenharmony_ci	/* Add code for DDR self refresh start */
298c2ecf20Sopenharmony_ci	cpu_do_idle();
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci	return index;
328c2ecf20Sopenharmony_ci}
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cistatic struct cpuidle_driver zynq_idle_driver = {
358c2ecf20Sopenharmony_ci	.name = "zynq_idle",
368c2ecf20Sopenharmony_ci	.owner = THIS_MODULE,
378c2ecf20Sopenharmony_ci	.states = {
388c2ecf20Sopenharmony_ci		ARM_CPUIDLE_WFI_STATE,
398c2ecf20Sopenharmony_ci		{
408c2ecf20Sopenharmony_ci			.enter			= zynq_enter_idle,
418c2ecf20Sopenharmony_ci			.exit_latency		= 10,
428c2ecf20Sopenharmony_ci			.target_residency	= 10000,
438c2ecf20Sopenharmony_ci			.name			= "RAM_SR",
448c2ecf20Sopenharmony_ci			.desc			= "WFI and RAM Self Refresh",
458c2ecf20Sopenharmony_ci		},
468c2ecf20Sopenharmony_ci	},
478c2ecf20Sopenharmony_ci	.safe_state_index = 0,
488c2ecf20Sopenharmony_ci	.state_count = ZYNQ_MAX_STATES,
498c2ecf20Sopenharmony_ci};
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci/* Initialize CPU idle by registering the idle states */
528c2ecf20Sopenharmony_cistatic int zynq_cpuidle_probe(struct platform_device *pdev)
538c2ecf20Sopenharmony_ci{
548c2ecf20Sopenharmony_ci	pr_info("Xilinx Zynq CpuIdle Driver started\n");
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	return cpuidle_register(&zynq_idle_driver, NULL);
578c2ecf20Sopenharmony_ci}
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_cistatic struct platform_driver zynq_cpuidle_driver = {
608c2ecf20Sopenharmony_ci	.driver = {
618c2ecf20Sopenharmony_ci		.name = "cpuidle-zynq",
628c2ecf20Sopenharmony_ci	},
638c2ecf20Sopenharmony_ci	.probe = zynq_cpuidle_probe,
648c2ecf20Sopenharmony_ci};
658c2ecf20Sopenharmony_cibuiltin_platform_driver(zynq_cpuidle_driver);
66