Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   3)  *  CPU frequency scaling for OMAP using OPP information
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5)  *  Copyright (C) 2005 Nokia Corporation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6)  *  Written by Tony Lindgren <tony@atomide.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8)  *  Based on cpu-sa1110.c, Copyright (C) 2001 Russell King
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10)  * Copyright (C) 2007-2011 Texas Instruments, Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11)  * - OMAP3/4 support by Rajendra Nayak, Santosh Shilimkar
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14) #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  18) #include <linux/sched.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19) #include <linux/cpufreq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23) #include <linux/clk.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25) #include <linux/pm_opp.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26) #include <linux/cpu.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29) #include <linux/regulator/consumer.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31) #include <asm/smp_plat.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32) #include <asm/cpu.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34) /* OPP tolerance in percentage */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35) #define	OPP_TOLERANCE	4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37) static struct cpufreq_frequency_table *freq_table;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38) static atomic_t freq_table_users = ATOMIC_INIT(0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39) static struct device *mpu_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40) static struct regulator *mpu_reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42) static int omap_target(struct cpufreq_policy *policy, unsigned int index)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44) 	int r, ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45) 	struct dev_pm_opp *opp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46) 	unsigned long freq, volt = 0, volt_old = 0, tol = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47) 	unsigned int old_freq, new_freq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49) 	old_freq = policy->cur;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50) 	new_freq = freq_table[index].frequency;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52) 	freq = new_freq * 1000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53) 	ret = clk_round_rate(policy->clk, freq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54) 	if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55) 		dev_warn(mpu_dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56) 			 "CPUfreq: Cannot find matching frequency for %lu\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57) 			 freq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60) 	freq = ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  61) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62) 	if (mpu_reg) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63) 		opp = dev_pm_opp_find_freq_ceil(mpu_dev, &freq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64) 		if (IS_ERR(opp)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65) 			dev_err(mpu_dev, "%s: unable to find MPU OPP for %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66) 				__func__, new_freq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67) 			return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69) 		volt = dev_pm_opp_get_voltage(opp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70) 		dev_pm_opp_put(opp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71) 		tol = volt * OPP_TOLERANCE / 100;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72) 		volt_old = regulator_get_voltage(mpu_reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75) 	dev_dbg(mpu_dev, "cpufreq-omap: %u MHz, %ld mV --> %u MHz, %ld mV\n", 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76) 		old_freq / 1000, volt_old ? volt_old / 1000 : -1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77) 		new_freq / 1000, volt ? volt / 1000 : -1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79) 	/* scaling up?  scale voltage before frequency */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  80) 	if (mpu_reg && (new_freq > old_freq)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  81) 		r = regulator_set_voltage(mpu_reg, volt - tol, volt + tol);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  82) 		if (r < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83) 			dev_warn(mpu_dev, "%s: unable to scale voltage up.\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84) 				 __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85) 			return r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89) 	ret = clk_set_rate(policy->clk, new_freq * 1000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91) 	/* scaling down?  scale voltage after frequency */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92) 	if (mpu_reg && (new_freq < old_freq)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93) 		r = regulator_set_voltage(mpu_reg, volt - tol, volt + tol);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94) 		if (r < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95) 			dev_warn(mpu_dev, "%s: unable to scale voltage down.\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96) 				 __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97) 			clk_set_rate(policy->clk, old_freq * 1000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98) 			return r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) 	return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) static inline void freq_table_free(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) 	if (atomic_dec_and_test(&freq_table_users))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) 		dev_pm_opp_free_cpufreq_table(mpu_dev, &freq_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) static int omap_cpu_init(struct cpufreq_policy *policy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) 	int result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) 	policy->clk = clk_get(NULL, "cpufreq_ck");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) 	if (IS_ERR(policy->clk))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) 		return PTR_ERR(policy->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) 	if (!freq_table) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) 		result = dev_pm_opp_init_cpufreq_table(mpu_dev, &freq_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) 		if (result) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) 			dev_err(mpu_dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) 				"%s: cpu%d: failed creating freq table[%d]\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) 				__func__, policy->cpu, result);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) 			clk_put(policy->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) 			return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) 	atomic_inc_return(&freq_table_users);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) 	/* FIXME: what's the actual transition time? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) 	cpufreq_generic_init(policy, freq_table, 300 * 1000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) 	dev_pm_opp_of_register_em(mpu_dev, policy->cpus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) static int omap_cpu_exit(struct cpufreq_policy *policy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) 	freq_table_free();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) 	clk_put(policy->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) static struct cpufreq_driver omap_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) 	.flags		= CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) 	.verify		= cpufreq_generic_frequency_table_verify,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) 	.target_index	= omap_target,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) 	.get		= cpufreq_generic_get,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) 	.init		= omap_cpu_init,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) 	.exit		= omap_cpu_exit,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) 	.name		= "omap",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) 	.attr		= cpufreq_generic_attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) static int omap_cpufreq_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) 	mpu_dev = get_cpu_device(0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) 	if (!mpu_dev) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) 		pr_warn("%s: unable to get the MPU device\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) 	mpu_reg = regulator_get(mpu_dev, "vcc");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) 	if (IS_ERR(mpu_reg)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) 		pr_warn("%s: unable to get MPU regulator\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) 		mpu_reg = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) 	} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) 		/* 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) 		 * Ensure physical regulator is present.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) 		 * (e.g. could be dummy regulator.)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) 		 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) 		if (regulator_get_voltage(mpu_reg) < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) 			pr_warn("%s: physical regulator not present for MPU\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) 				__func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) 			regulator_put(mpu_reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) 			mpu_reg = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) 	return cpufreq_register_driver(&omap_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) static int omap_cpufreq_remove(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) 	return cpufreq_unregister_driver(&omap_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) static struct platform_driver omap_cpufreq_platdrv = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) 	.driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) 		.name	= "omap-cpufreq",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) 	.probe		= omap_cpufreq_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) 	.remove		= omap_cpufreq_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) module_platform_driver(omap_cpufreq_platdrv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) MODULE_DESCRIPTION("cpufreq driver for OMAP SoCs");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) MODULE_LICENSE("GPL");