cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

cpuidle-imx6sx.c (2558B)


      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 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		cpu_suspend(0, imx6sx_idle_finish);
     51
     52		cpu_cluster_pm_exit();
     53		cpu_pm_exit();
     54		imx_gpc_set_arm_power_in_lpm(false);
     55		imx6_enable_rbc(false);
     56		break;
     57	default:
     58		break;
     59	}
     60
     61	imx6_set_lpm(WAIT_CLOCKED);
     62
     63	return index;
     64}
     65
     66static struct cpuidle_driver imx6sx_cpuidle_driver = {
     67	.name = "imx6sx_cpuidle",
     68	.owner = THIS_MODULE,
     69	.states = {
     70		/* WFI */
     71		ARM_CPUIDLE_WFI_STATE,
     72		/* WAIT */
     73		{
     74			.exit_latency = 50,
     75			.target_residency = 75,
     76			.flags = CPUIDLE_FLAG_TIMER_STOP,
     77			.enter = imx6sx_enter_wait,
     78			.name = "WAIT",
     79			.desc = "Clock off",
     80		},
     81		/* WAIT + ARM power off  */
     82		{
     83			/*
     84			 * ARM gating 31us * 5 + RBC clear 65us
     85			 * and some margin for SW execution, here set it
     86			 * to 300us.
     87			 */
     88			.exit_latency = 300,
     89			.target_residency = 500,
     90			.flags = CPUIDLE_FLAG_TIMER_STOP,
     91			.enter = imx6sx_enter_wait,
     92			.name = "LOW-POWER-IDLE",
     93			.desc = "ARM power off",
     94		},
     95	},
     96	.state_count = 3,
     97	.safe_state_index = 0,
     98};
     99
    100int __init imx6sx_cpuidle_init(void)
    101{
    102	imx6_set_int_mem_clk_lpm(true);
    103	imx6_enable_rbc(false);
    104	imx_gpc_set_l2_mem_power_in_lpm(false);
    105	/*
    106	 * set ARM power up/down timing to the fastest,
    107	 * sw2iso and sw can be set to one 32K cycle = 31us
    108	 * except for power up sw2iso which need to be
    109	 * larger than LDO ramp up time.
    110	 */
    111	imx_gpc_set_arm_power_up_timing(cpu_is_imx6sx() ? 0xf : 0x2, 1);
    112	imx_gpc_set_arm_power_down_timing(1, 1);
    113
    114	return cpuidle_register(&imx6sx_cpuidle_driver, NULL);
    115}