File Index
Files and directories
Sign in
FILE

cpuidle-imx6sx.c

File preview with syntax highlighting.

linux-6.19.14/arch/arm/mach-imx/cpuidle-imx6sx.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Copyright (C) 2014 Freescale Semiconductor, Inc.
  4 */
  5
  6#include <linux/cpuidle.h>
  7#include <linux/cpu_pm.h>
  8#include <linux/module.h>
  9#include <asm/cacheflush.h>
 10#include <asm/cpuidle.h>
 11#include <asm/suspend.h>
 12
 13#include "common.h"
 14#include "cpuidle.h"
 15#include "hardware.h"
 16
 17static int imx6sx_idle_finish(unsigned long val)
 18{
 19	/*
 20	 * for Cortex-A7 which has an internal L2
 21	 * cache, need to flush it before powering
 22	 * down ARM platform, since flushing L1 cache
 23	 * here again has very small overhead, compared
 24	 * to adding conditional code for L2 cache type,
 25	 * just call flush_cache_all() is fine.
 26	 */
 27	flush_cache_all();
 28	cpu_do_idle();
 29
 30	return 0;
 31}
 32
 33static __cpuidle int imx6sx_enter_wait(struct cpuidle_device *dev,
 34				       struct cpuidle_driver *drv, int index)
 35{
 36	imx6_set_lpm(WAIT_UNCLOCKED);
 37
 38	switch (index) {
 39	case 1:
 40		cpu_do_idle();
 41		break;
 42	case 2:
 43		imx6_enable_rbc(true);
 44		imx_gpc_set_arm_power_in_lpm(true);
 45		imx_set_cpu_jump(0, v7_cpu_resume);
 46		/* Need to notify there is a cpu pm operation. */
 47		cpu_pm_enter();
 48		cpu_cluster_pm_enter();
 49
 50		ct_cpuidle_enter();
 51		cpu_suspend(0, imx6sx_idle_finish);
 52		ct_cpuidle_exit();
 53
 54		cpu_cluster_pm_exit();
 55		cpu_pm_exit();
 56		imx_gpc_set_arm_power_in_lpm(false);
 57		imx6_enable_rbc(false);
 58		break;
 59	default:
 60		break;
 61	}
 62
 63	imx6_set_lpm(WAIT_CLOCKED);
 64
 65	return index;
 66}
 67
 68static struct cpuidle_driver imx6sx_cpuidle_driver = {
 69	.name = "imx6sx_cpuidle",
 70	.owner = THIS_MODULE,
 71	.states = {
 72		/* WFI */
 73		ARM_CPUIDLE_WFI_STATE,
 74		/* WAIT */
 75		{
 76			.exit_latency = 50,
 77			.target_residency = 75,
 78			.flags = CPUIDLE_FLAG_TIMER_STOP,
 79			.enter = imx6sx_enter_wait,
 80			.name = "WAIT",
 81			.desc = "Clock off",
 82		},
 83		/* WAIT + ARM power off  */
 84		{
 85			/*
 86			 * ARM gating 31us * 5 + RBC clear 65us
 87			 * and some margin for SW execution, here set it
 88			 * to 300us.
 89			 */
 90			.exit_latency = 300,
 91			.target_residency = 500,
 92			.flags = CPUIDLE_FLAG_TIMER_STOP |
 93				 CPUIDLE_FLAG_RCU_IDLE,
 94			.enter = imx6sx_enter_wait,
 95			.name = "LOW-POWER-IDLE",
 96			.desc = "ARM power off",
 97		},
 98	},
 99	.state_count = 3,
100	.safe_state_index = 0,
101};
102
103int __init imx6sx_cpuidle_init(void)
104{
105	imx6_set_int_mem_clk_lpm(true);
106	imx6_enable_rbc(false);
107	imx_gpc_set_l2_mem_power_in_lpm(false);
108	/*
109	 * set ARM power up/down timing to the fastest,
110	 * sw2iso and sw can be set to one 32K cycle = 31us
111	 * except for power up sw2iso which need to be
112	 * larger than LDO ramp up time.
113	 */
114	imx_gpc_set_arm_power_up_timing(cpu_is_imx6sx() ? 0xf : 0x2, 1);
115	imx_gpc_set_arm_power_down_timing(1, 1);
116
117	return cpuidle_register(&imx6sx_cpuidle_driver, NULL);
118}
~/ Read-only file preview.