162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2012-2013 Xilinx
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * CPU idle support for Xilinx Zynq
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * based on arch/arm/mach-at91/cpuidle.c
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * The cpu idle uses wait-for-interrupt and RAM self refresh in order
1062306a36Sopenharmony_ci * to implement two idle states -
1162306a36Sopenharmony_ci * #1 wait-for-interrupt
1262306a36Sopenharmony_ci * #2 wait-for-interrupt and RAM self refresh
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci * Maintainer: Michal Simek <michal.simek@xilinx.com>
1562306a36Sopenharmony_ci */
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include <linux/init.h>
1862306a36Sopenharmony_ci#include <linux/cpuidle.h>
1962306a36Sopenharmony_ci#include <linux/platform_device.h>
2062306a36Sopenharmony_ci#include <asm/cpuidle.h>
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#define ZYNQ_MAX_STATES		2
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci/* Actual code that puts the SoC in different idle states */
2562306a36Sopenharmony_cistatic int zynq_enter_idle(struct cpuidle_device *dev,
2662306a36Sopenharmony_ci			   struct cpuidle_driver *drv, int index)
2762306a36Sopenharmony_ci{
2862306a36Sopenharmony_ci	/* Add code for DDR self refresh start */
2962306a36Sopenharmony_ci	cpu_do_idle();
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci	return index;
3262306a36Sopenharmony_ci}
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_cistatic struct cpuidle_driver zynq_idle_driver = {
3562306a36Sopenharmony_ci	.name = "zynq_idle",
3662306a36Sopenharmony_ci	.owner = THIS_MODULE,
3762306a36Sopenharmony_ci	.states = {
3862306a36Sopenharmony_ci		ARM_CPUIDLE_WFI_STATE,
3962306a36Sopenharmony_ci		{
4062306a36Sopenharmony_ci			.enter			= zynq_enter_idle,
4162306a36Sopenharmony_ci			.exit_latency		= 10,
4262306a36Sopenharmony_ci			.target_residency	= 10000,
4362306a36Sopenharmony_ci			.name			= "RAM_SR",
4462306a36Sopenharmony_ci			.desc			= "WFI and RAM Self Refresh",
4562306a36Sopenharmony_ci		},
4662306a36Sopenharmony_ci	},
4762306a36Sopenharmony_ci	.safe_state_index = 0,
4862306a36Sopenharmony_ci	.state_count = ZYNQ_MAX_STATES,
4962306a36Sopenharmony_ci};
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci/* Initialize CPU idle by registering the idle states */
5262306a36Sopenharmony_cistatic int zynq_cpuidle_probe(struct platform_device *pdev)
5362306a36Sopenharmony_ci{
5462306a36Sopenharmony_ci	pr_info("Xilinx Zynq CpuIdle Driver started\n");
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	return cpuidle_register(&zynq_idle_driver, NULL);
5762306a36Sopenharmony_ci}
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_cistatic struct platform_driver zynq_cpuidle_driver = {
6062306a36Sopenharmony_ci	.driver = {
6162306a36Sopenharmony_ci		.name = "cpuidle-zynq",
6262306a36Sopenharmony_ci	},
6362306a36Sopenharmony_ci	.probe = zynq_cpuidle_probe,
6462306a36Sopenharmony_ci};
6562306a36Sopenharmony_cibuiltin_platform_driver(zynq_cpuidle_driver);
66