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-imx6q.c (2010B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (C) 2012 Freescale Semiconductor, Inc.
      4 */
      5
      6#include <linux/cpuidle.h>
      7#include <linux/module.h>
      8#include <asm/cpuidle.h>
      9
     10#include <soc/imx/cpuidle.h>
     11
     12#include "common.h"
     13#include "cpuidle.h"
     14#include "hardware.h"
     15
     16static int num_idle_cpus = 0;
     17static DEFINE_RAW_SPINLOCK(cpuidle_lock);
     18
     19static int imx6q_enter_wait(struct cpuidle_device *dev,
     20			    struct cpuidle_driver *drv, int index)
     21{
     22	raw_spin_lock(&cpuidle_lock);
     23	if (++num_idle_cpus == num_online_cpus())
     24		imx6_set_lpm(WAIT_UNCLOCKED);
     25	raw_spin_unlock(&cpuidle_lock);
     26
     27	rcu_idle_enter();
     28	cpu_do_idle();
     29	rcu_idle_exit();
     30
     31	raw_spin_lock(&cpuidle_lock);
     32	if (num_idle_cpus-- == num_online_cpus())
     33		imx6_set_lpm(WAIT_CLOCKED);
     34	raw_spin_unlock(&cpuidle_lock);
     35
     36	return index;
     37}
     38
     39static struct cpuidle_driver imx6q_cpuidle_driver = {
     40	.name = "imx6q_cpuidle",
     41	.owner = THIS_MODULE,
     42	.states = {
     43		/* WFI */
     44		ARM_CPUIDLE_WFI_STATE,
     45		/* WAIT */
     46		{
     47			.exit_latency = 50,
     48			.target_residency = 75,
     49			.flags = CPUIDLE_FLAG_TIMER_STOP | CPUIDLE_FLAG_RCU_IDLE,
     50			.enter = imx6q_enter_wait,
     51			.name = "WAIT",
     52			.desc = "Clock off",
     53		},
     54	},
     55	.state_count = 2,
     56	.safe_state_index = 0,
     57};
     58
     59/*
     60 * i.MX6 Q/DL has an erratum (ERR006687) that prevents the FEC from waking the
     61 * CPUs when they are in wait(unclocked) state. As the hardware workaround isn't
     62 * applicable to all boards, disable the deeper idle state when the workaround
     63 * isn't present and the FEC is in use.
     64 */
     65void imx6q_cpuidle_fec_irqs_used(void)
     66{
     67	cpuidle_driver_state_disabled(&imx6q_cpuidle_driver, 1, true);
     68}
     69EXPORT_SYMBOL_GPL(imx6q_cpuidle_fec_irqs_used);
     70
     71void imx6q_cpuidle_fec_irqs_unused(void)
     72{
     73	cpuidle_driver_state_disabled(&imx6q_cpuidle_driver, 1, false);
     74}
     75EXPORT_SYMBOL_GPL(imx6q_cpuidle_fec_irqs_unused);
     76
     77int __init imx6q_cpuidle_init(void)
     78{
     79	/* Set INT_MEM_CLK_LPM bit to get a reliable WAIT mode support */
     80	imx6_set_int_mem_clk_lpm(true);
     81
     82	return cpuidle_register(&imx6q_cpuidle_driver, NULL);
     83}