VisionFive2 Linux kernel

StarFive Tech Linux Kernel for VisionFive (JH7110) boards (mirror)

More than 9999 Commits   33 Branches   57 Tags
2874c5fd28426 (Thomas Gleixner   2019-05-27 08:55:01 +0200   1) // SPDX-License-Identifier: GPL-2.0-or-later
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100   2) /*
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100   3)  * Copyright (C) 2014 Imagination Technologies
fb615d61b5583 (Paul Burton       2017-10-25 17:04:33 -0700   4)  * Author: Paul Burton <paul.burton@mips.com>
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100   5)  */
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100   6) 
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100   7) #include <linux/cpu_pm.h>
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100   8) #include <linux/cpuidle.h>
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100   9) #include <linux/init.h>
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  10) 
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  11) #include <asm/idle.h>
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  12) #include <asm/pm-cps.h>
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  13) 
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  14) /* Enumeration of the various idle states this driver may enter */
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  15) enum cps_idle_state {
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  16) 	STATE_WAIT = 0,		/* MIPS wait instruction, coherent */
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  17) 	STATE_NC_WAIT,		/* MIPS wait instruction, non-coherent */
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  18) 	STATE_CLOCK_GATED,	/* Core clock gated */
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  19) 	STATE_POWER_GATED,	/* Core power gated */
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  20) 	STATE_COUNT
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  21) };
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  22) 
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  23) static int cps_nc_enter(struct cpuidle_device *dev,
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  24) 			struct cpuidle_driver *drv, int index)
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  25) {
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  26) 	enum cps_pm_state pm_state;
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  27) 	int err;
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  28) 
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  29) 	/*
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  30) 	 * At least one core must remain powered up & clocked in order for the
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  31) 	 * system to have any hope of functioning.
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  32) 	 *
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  33) 	 * TODO: don't treat core 0 specially, just prevent the final core
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  34) 	 * TODO: remap interrupt affinity temporarily
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  35) 	 */
fe7a38c625a2e (Paul Burton       2017-08-12 19:49:37 -0700  36) 	if (cpus_are_siblings(0, dev->cpu) && (index > STATE_NC_WAIT))
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  37) 		index = STATE_NC_WAIT;
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  38) 
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  39) 	/* Select the appropriate cps_pm_state */
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  40) 	switch (index) {
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  41) 	case STATE_NC_WAIT:
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  42) 		pm_state = CPS_PM_NC_WAIT;
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  43) 		break;
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  44) 	case STATE_CLOCK_GATED:
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  45) 		pm_state = CPS_PM_CLOCK_GATED;
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  46) 		break;
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  47) 	case STATE_POWER_GATED:
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  48) 		pm_state = CPS_PM_POWER_GATED;
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  49) 		break;
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  50) 	default:
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  51) 		BUG();
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  52) 		return -EINVAL;
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  53) 	}
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  54) 
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  55) 	/* Notify listeners the CPU is about to power down */
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  56) 	if ((pm_state == CPS_PM_POWER_GATED) && cpu_pm_enter())
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  57) 		return -EINTR;
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  58) 
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  59) 	/* Enter that state */
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  60) 	err = cps_pm_enter_state(pm_state);
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  61) 
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  62) 	/* Notify listeners the CPU is back up */
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  63) 	if (pm_state == CPS_PM_POWER_GATED)
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  64) 		cpu_pm_exit();
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  65) 
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  66) 	return err ?: index;
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  67) }
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  68) 
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  69) static struct cpuidle_driver cps_driver = {
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  70) 	.name			= "cpc_cpuidle",
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  71) 	.owner			= THIS_MODULE,
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  72) 	.states = {
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  73) 		[STATE_WAIT] = MIPS_CPUIDLE_WAIT_STATE,
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  74) 		[STATE_NC_WAIT] = {
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  75) 			.enter	= cps_nc_enter,
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  76) 			.exit_latency		= 200,
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  77) 			.target_residency	= 450,
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  78) 			.name	= "nc-wait",
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  79) 			.desc	= "non-coherent MIPS wait",
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  80) 		},
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  81) 		[STATE_CLOCK_GATED] = {
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  82) 			.enter	= cps_nc_enter,
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  83) 			.exit_latency		= 300,
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  84) 			.target_residency	= 700,
b82b6cca48807 (Daniel Lezcano    2014-11-12 16:03:50 +0100  85) 			.flags	= CPUIDLE_FLAG_TIMER_STOP,
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  86) 			.name	= "clock-gated",
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  87) 			.desc	= "core clock gated",
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  88) 		},
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  89) 		[STATE_POWER_GATED] = {
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  90) 			.enter	= cps_nc_enter,
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  91) 			.exit_latency		= 600,
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  92) 			.target_residency	= 1000,
b82b6cca48807 (Daniel Lezcano    2014-11-12 16:03:50 +0100  93) 			.flags	= CPUIDLE_FLAG_TIMER_STOP,
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  94) 			.name	= "power-gated",
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  95) 			.desc	= "core power gated",
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  96) 		},
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  97) 	},
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  98) 	.state_count		= STATE_COUNT,
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100  99) 	.safe_state_index	= 0,
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 100) };
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 101) 
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 102) static void __init cps_cpuidle_unregister(void)
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 103) {
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 104) 	int cpu;
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 105) 	struct cpuidle_device *device;
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 106) 
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 107) 	for_each_possible_cpu(cpu) {
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 108) 		device = &per_cpu(cpuidle_dev, cpu);
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 109) 		cpuidle_unregister_device(device);
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 110) 	}
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 111) 
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 112) 	cpuidle_unregister_driver(&cps_driver);
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 113) }
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 114) 
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 115) static int __init cps_cpuidle_init(void)
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 116) {
02018b3929a23 (Marcin Nowakowski 2017-04-19 13:20:54 +0200 117) 	int err, cpu, i;
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 118) 	struct cpuidle_device *device;
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 119) 
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 120) 	/* Detect supported states */
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 121) 	if (!cps_pm_support_state(CPS_PM_POWER_GATED))
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 122) 		cps_driver.state_count = STATE_CLOCK_GATED + 1;
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 123) 	if (!cps_pm_support_state(CPS_PM_CLOCK_GATED))
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 124) 		cps_driver.state_count = STATE_NC_WAIT + 1;
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 125) 	if (!cps_pm_support_state(CPS_PM_NC_WAIT))
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 126) 		cps_driver.state_count = STATE_WAIT + 1;
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 127) 
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 128) 	/* Inform the user if some states are unavailable */
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 129) 	if (cps_driver.state_count < STATE_COUNT) {
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 130) 		pr_info("cpuidle-cps: limited to ");
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 131) 		switch (cps_driver.state_count - 1) {
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 132) 		case STATE_WAIT:
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 133) 			pr_cont("coherent wait\n");
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 134) 			break;
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 135) 		case STATE_NC_WAIT:
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 136) 			pr_cont("non-coherent wait\n");
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 137) 			break;
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 138) 		case STATE_CLOCK_GATED:
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 139) 			pr_cont("clock gating\n");
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 140) 			break;
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 141) 		}
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 142) 	}
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 143) 
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 144) 	/*
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 145) 	 * Set the coupled flag on the appropriate states if this system
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 146) 	 * requires it.
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 147) 	 */
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 148) 	if (coupled_coherence)
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 149) 		for (i = STATE_NC_WAIT; i < cps_driver.state_count; i++)
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 150) 			cps_driver.states[i].flags |= CPUIDLE_FLAG_COUPLED;
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 151) 
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 152) 	err = cpuidle_register_driver(&cps_driver);
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 153) 	if (err) {
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 154) 		pr_err("Failed to register CPS cpuidle driver\n");
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 155) 		return err;
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 156) 	}
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 157) 
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 158) 	for_each_possible_cpu(cpu) {
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 159) 		device = &per_cpu(cpuidle_dev, cpu);
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 160) 		device->cpu = cpu;
72bc8c75eaf72 (Matt Redfearn     2016-09-07 10:45:20 +0100 161) #ifdef CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 162) 		cpumask_copy(&device->coupled_cpus, &cpu_sibling_map[cpu]);
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 163) #endif
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 164) 
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 165) 		err = cpuidle_register_device(device);
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 166) 		if (err) {
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 167) 			pr_err("Failed to register CPU%d cpuidle device\n",
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 168) 			       cpu);
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 169) 			goto err_out;
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 170) 		}
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 171) 	}
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 172) 
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 173) 	return 0;
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 174) err_out:
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 175) 	cps_cpuidle_unregister();
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 176) 	return err;
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 177) }
d050894435cdc (Paul Burton       2014-04-14 16:25:29 +0100 178) device_initcall(cps_cpuidle_init);