xref: /linux/drivers/cpufreq/longrun.c (revision ead5d1f4d877e92c051e1a1ade623d0d30e71619)
14f19048fSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2bb0a56ecSDave Jones /*
3bb0a56ecSDave Jones  * (C) 2002 - 2003  Dominik Brodowski <linux@brodo.de>
4bb0a56ecSDave Jones  *
5bb0a56ecSDave Jones  *  BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous*
6bb0a56ecSDave Jones  */
7bb0a56ecSDave Jones 
8bb0a56ecSDave Jones #include <linux/kernel.h>
9bb0a56ecSDave Jones #include <linux/module.h>
10bb0a56ecSDave Jones #include <linux/init.h>
11bb0a56ecSDave Jones #include <linux/cpufreq.h>
12bb0a56ecSDave Jones #include <linux/timex.h>
13bb0a56ecSDave Jones 
14bb0a56ecSDave Jones #include <asm/msr.h>
15bb0a56ecSDave Jones #include <asm/processor.h>
16fa8031aeSAndi Kleen #include <asm/cpu_device_id.h>
17bb0a56ecSDave Jones 
18bb0a56ecSDave Jones static struct cpufreq_driver	longrun_driver;
19bb0a56ecSDave Jones 
20bb0a56ecSDave Jones /**
21bb0a56ecSDave Jones  * longrun_{low,high}_freq is needed for the conversion of cpufreq kHz
22bb0a56ecSDave Jones  * values into per cent values. In TMTA microcode, the following is valid:
23bb0a56ecSDave Jones  * performance_pctg = (current_freq - low_freq)/(high_freq - low_freq)
24bb0a56ecSDave Jones  */
25bb0a56ecSDave Jones static unsigned int longrun_low_freq, longrun_high_freq;
26bb0a56ecSDave Jones 
27bb0a56ecSDave Jones 
28bb0a56ecSDave Jones /**
29bb0a56ecSDave Jones  * longrun_get_policy - get the current LongRun policy
30bb0a56ecSDave Jones  * @policy: struct cpufreq_policy where current policy is written into
31bb0a56ecSDave Jones  *
32bb0a56ecSDave Jones  * Reads the current LongRun policy by access to MSR_TMTA_LONGRUN_FLAGS
33bb0a56ecSDave Jones  * and MSR_TMTA_LONGRUN_CTRL
34bb0a56ecSDave Jones  */
longrun_get_policy(struct cpufreq_policy * policy)352760984fSPaul Gortmaker static void longrun_get_policy(struct cpufreq_policy *policy)
36bb0a56ecSDave Jones {
37bb0a56ecSDave Jones 	u32 msr_lo, msr_hi;
38bb0a56ecSDave Jones 
39bb0a56ecSDave Jones 	rdmsr(MSR_TMTA_LONGRUN_FLAGS, msr_lo, msr_hi);
40bb0a56ecSDave Jones 	pr_debug("longrun flags are %x - %x\n", msr_lo, msr_hi);
41bb0a56ecSDave Jones 	if (msr_lo & 0x01)
42bb0a56ecSDave Jones 		policy->policy = CPUFREQ_POLICY_PERFORMANCE;
43bb0a56ecSDave Jones 	else
44bb0a56ecSDave Jones 		policy->policy = CPUFREQ_POLICY_POWERSAVE;
45bb0a56ecSDave Jones 
46bb0a56ecSDave Jones 	rdmsr(MSR_TMTA_LONGRUN_CTRL, msr_lo, msr_hi);
47bb0a56ecSDave Jones 	pr_debug("longrun ctrl is %x - %x\n", msr_lo, msr_hi);
48bb0a56ecSDave Jones 	msr_lo &= 0x0000007F;
49bb0a56ecSDave Jones 	msr_hi &= 0x0000007F;
50bb0a56ecSDave Jones 
51bb0a56ecSDave Jones 	if (longrun_high_freq <= longrun_low_freq) {
52bb0a56ecSDave Jones 		/* Assume degenerate Longrun table */
53bb0a56ecSDave Jones 		policy->min = policy->max = longrun_high_freq;
54bb0a56ecSDave Jones 	} else {
55bb0a56ecSDave Jones 		policy->min = longrun_low_freq + msr_lo *
56bb0a56ecSDave Jones 			((longrun_high_freq - longrun_low_freq) / 100);
57bb0a56ecSDave Jones 		policy->max = longrun_low_freq + msr_hi *
58bb0a56ecSDave Jones 			((longrun_high_freq - longrun_low_freq) / 100);
59bb0a56ecSDave Jones 	}
60bb0a56ecSDave Jones 	policy->cpu = 0;
61bb0a56ecSDave Jones }
62bb0a56ecSDave Jones 
63bb0a56ecSDave Jones 
64bb0a56ecSDave Jones /**
65bb0a56ecSDave Jones  * longrun_set_policy - sets a new CPUFreq policy
66bb0a56ecSDave Jones  * @policy: new policy
67bb0a56ecSDave Jones  *
68bb0a56ecSDave Jones  * Sets a new CPUFreq policy on LongRun-capable processors. This function
69bb0a56ecSDave Jones  * has to be called with cpufreq_driver locked.
70bb0a56ecSDave Jones  */
longrun_set_policy(struct cpufreq_policy * policy)71bb0a56ecSDave Jones static int longrun_set_policy(struct cpufreq_policy *policy)
72bb0a56ecSDave Jones {
73bb0a56ecSDave Jones 	u32 msr_lo, msr_hi;
74bb0a56ecSDave Jones 	u32 pctg_lo, pctg_hi;
75bb0a56ecSDave Jones 
76bb0a56ecSDave Jones 	if (!policy)
77bb0a56ecSDave Jones 		return -EINVAL;
78bb0a56ecSDave Jones 
79bb0a56ecSDave Jones 	if (longrun_high_freq <= longrun_low_freq) {
80bb0a56ecSDave Jones 		/* Assume degenerate Longrun table */
81bb0a56ecSDave Jones 		pctg_lo = pctg_hi = 100;
82bb0a56ecSDave Jones 	} else {
83bb0a56ecSDave Jones 		pctg_lo = (policy->min - longrun_low_freq) /
84bb0a56ecSDave Jones 			((longrun_high_freq - longrun_low_freq) / 100);
85bb0a56ecSDave Jones 		pctg_hi = (policy->max - longrun_low_freq) /
86bb0a56ecSDave Jones 			((longrun_high_freq - longrun_low_freq) / 100);
87bb0a56ecSDave Jones 	}
88bb0a56ecSDave Jones 
89bb0a56ecSDave Jones 	if (pctg_hi > 100)
90bb0a56ecSDave Jones 		pctg_hi = 100;
91bb0a56ecSDave Jones 	if (pctg_lo > pctg_hi)
92bb0a56ecSDave Jones 		pctg_lo = pctg_hi;
93bb0a56ecSDave Jones 
94bb0a56ecSDave Jones 	/* performance or economy mode */
95bb0a56ecSDave Jones 	rdmsr(MSR_TMTA_LONGRUN_FLAGS, msr_lo, msr_hi);
96bb0a56ecSDave Jones 	msr_lo &= 0xFFFFFFFE;
97bb0a56ecSDave Jones 	switch (policy->policy) {
98bb0a56ecSDave Jones 	case CPUFREQ_POLICY_PERFORMANCE:
99bb0a56ecSDave Jones 		msr_lo |= 0x00000001;
100bb0a56ecSDave Jones 		break;
101bb0a56ecSDave Jones 	case CPUFREQ_POLICY_POWERSAVE:
102bb0a56ecSDave Jones 		break;
103bb0a56ecSDave Jones 	}
104bb0a56ecSDave Jones 	wrmsr(MSR_TMTA_LONGRUN_FLAGS, msr_lo, msr_hi);
105bb0a56ecSDave Jones 
106bb0a56ecSDave Jones 	/* lower and upper boundary */
107bb0a56ecSDave Jones 	rdmsr(MSR_TMTA_LONGRUN_CTRL, msr_lo, msr_hi);
108bb0a56ecSDave Jones 	msr_lo &= 0xFFFFFF80;
109bb0a56ecSDave Jones 	msr_hi &= 0xFFFFFF80;
110bb0a56ecSDave Jones 	msr_lo |= pctg_lo;
111bb0a56ecSDave Jones 	msr_hi |= pctg_hi;
112bb0a56ecSDave Jones 	wrmsr(MSR_TMTA_LONGRUN_CTRL, msr_lo, msr_hi);
113bb0a56ecSDave Jones 
114bb0a56ecSDave Jones 	return 0;
115bb0a56ecSDave Jones }
116bb0a56ecSDave Jones 
117bb0a56ecSDave Jones 
118bb0a56ecSDave Jones /**
119bb0a56ecSDave Jones  * longrun_verify_poliy - verifies a new CPUFreq policy
120bb0a56ecSDave Jones  * @policy: the policy to verify
121bb0a56ecSDave Jones  *
122bb0a56ecSDave Jones  * Validates a new CPUFreq policy. This function has to be called with
123bb0a56ecSDave Jones  * cpufreq_driver locked.
124bb0a56ecSDave Jones  */
longrun_verify_policy(struct cpufreq_policy_data * policy)1251e4f63aeSRafael J. Wysocki static int longrun_verify_policy(struct cpufreq_policy_data *policy)
126bb0a56ecSDave Jones {
127bb0a56ecSDave Jones 	if (!policy)
128bb0a56ecSDave Jones 		return -EINVAL;
129bb0a56ecSDave Jones 
130bb0a56ecSDave Jones 	policy->cpu = 0;
131be49e346SViresh Kumar 	cpufreq_verify_within_cpu_limits(policy);
132bb0a56ecSDave Jones 
133bb0a56ecSDave Jones 	return 0;
134bb0a56ecSDave Jones }
135bb0a56ecSDave Jones 
longrun_get(unsigned int cpu)136bb0a56ecSDave Jones static unsigned int longrun_get(unsigned int cpu)
137bb0a56ecSDave Jones {
138bb0a56ecSDave Jones 	u32 eax, ebx, ecx, edx;
139bb0a56ecSDave Jones 
140bb0a56ecSDave Jones 	if (cpu)
141bb0a56ecSDave Jones 		return 0;
142bb0a56ecSDave Jones 
143bb0a56ecSDave Jones 	cpuid(0x80860007, &eax, &ebx, &ecx, &edx);
144bb0a56ecSDave Jones 	pr_debug("cpuid eax is %u\n", eax);
145bb0a56ecSDave Jones 
146bb0a56ecSDave Jones 	return eax * 1000;
147bb0a56ecSDave Jones }
148bb0a56ecSDave Jones 
149bb0a56ecSDave Jones /**
150bb0a56ecSDave Jones  * longrun_determine_freqs - determines the lowest and highest possible core frequency
151bb0a56ecSDave Jones  * @low_freq: an int to put the lowest frequency into
152bb0a56ecSDave Jones  * @high_freq: an int to put the highest frequency into
153bb0a56ecSDave Jones  *
154bb0a56ecSDave Jones  * Determines the lowest and highest possible core frequencies on this CPU.
155bb0a56ecSDave Jones  * This is necessary to calculate the performance percentage according to
156bb0a56ecSDave Jones  * TMTA rules:
157bb0a56ecSDave Jones  * performance_pctg = (target_freq - low_freq)/(high_freq - low_freq)
158bb0a56ecSDave Jones  */
longrun_determine_freqs(unsigned int * low_freq,unsigned int * high_freq)1592760984fSPaul Gortmaker static int longrun_determine_freqs(unsigned int *low_freq,
160bb0a56ecSDave Jones 						      unsigned int *high_freq)
161bb0a56ecSDave Jones {
162bb0a56ecSDave Jones 	u32 msr_lo, msr_hi;
163bb0a56ecSDave Jones 	u32 save_lo, save_hi;
164bb0a56ecSDave Jones 	u32 eax, ebx, ecx, edx;
165bb0a56ecSDave Jones 	u32 try_hi;
166bb0a56ecSDave Jones 	struct cpuinfo_x86 *c = &cpu_data(0);
167bb0a56ecSDave Jones 
168bb0a56ecSDave Jones 	if (!low_freq || !high_freq)
169bb0a56ecSDave Jones 		return -EINVAL;
170bb0a56ecSDave Jones 
171bb0a56ecSDave Jones 	if (cpu_has(c, X86_FEATURE_LRTI)) {
172bb0a56ecSDave Jones 		/* if the LongRun Table Interface is present, the
173bb0a56ecSDave Jones 		 * detection is a bit easier:
174bb0a56ecSDave Jones 		 * For minimum frequency, read out the maximum
175bb0a56ecSDave Jones 		 * level (msr_hi), write that into "currently
176bb0a56ecSDave Jones 		 * selected level", and read out the frequency.
177bb0a56ecSDave Jones 		 * For maximum frequency, read out level zero.
178bb0a56ecSDave Jones 		 */
179bb0a56ecSDave Jones 		/* minimum */
180bb0a56ecSDave Jones 		rdmsr(MSR_TMTA_LRTI_READOUT, msr_lo, msr_hi);
181bb0a56ecSDave Jones 		wrmsr(MSR_TMTA_LRTI_READOUT, msr_hi, msr_hi);
182bb0a56ecSDave Jones 		rdmsr(MSR_TMTA_LRTI_VOLT_MHZ, msr_lo, msr_hi);
183bb0a56ecSDave Jones 		*low_freq = msr_lo * 1000; /* to kHz */
184bb0a56ecSDave Jones 
185bb0a56ecSDave Jones 		/* maximum */
186bb0a56ecSDave Jones 		wrmsr(MSR_TMTA_LRTI_READOUT, 0, msr_hi);
187bb0a56ecSDave Jones 		rdmsr(MSR_TMTA_LRTI_VOLT_MHZ, msr_lo, msr_hi);
188bb0a56ecSDave Jones 		*high_freq = msr_lo * 1000; /* to kHz */
189bb0a56ecSDave Jones 
190bb0a56ecSDave Jones 		pr_debug("longrun table interface told %u - %u kHz\n",
191bb0a56ecSDave Jones 				*low_freq, *high_freq);
192bb0a56ecSDave Jones 
193bb0a56ecSDave Jones 		if (*low_freq > *high_freq)
194bb0a56ecSDave Jones 			*low_freq = *high_freq;
195bb0a56ecSDave Jones 		return 0;
196bb0a56ecSDave Jones 	}
197bb0a56ecSDave Jones 
198bb0a56ecSDave Jones 	/* set the upper border to the value determined during TSC init */
199bb0a56ecSDave Jones 	*high_freq = (cpu_khz / 1000);
200bb0a56ecSDave Jones 	*high_freq = *high_freq * 1000;
201bb0a56ecSDave Jones 	pr_debug("high frequency is %u kHz\n", *high_freq);
202bb0a56ecSDave Jones 
203bb0a56ecSDave Jones 	/* get current borders */
204bb0a56ecSDave Jones 	rdmsr(MSR_TMTA_LONGRUN_CTRL, msr_lo, msr_hi);
205bb0a56ecSDave Jones 	save_lo = msr_lo & 0x0000007F;
206bb0a56ecSDave Jones 	save_hi = msr_hi & 0x0000007F;
207bb0a56ecSDave Jones 
208bb0a56ecSDave Jones 	/* if current perf_pctg is larger than 90%, we need to decrease the
209bb0a56ecSDave Jones 	 * upper limit to make the calculation more accurate.
210bb0a56ecSDave Jones 	 */
211bb0a56ecSDave Jones 	cpuid(0x80860007, &eax, &ebx, &ecx, &edx);
212bb0a56ecSDave Jones 	/* try decreasing in 10% steps, some processors react only
213bb0a56ecSDave Jones 	 * on some barrier values */
214bb0a56ecSDave Jones 	for (try_hi = 80; try_hi > 0 && ecx > 90; try_hi -= 10) {
215bb0a56ecSDave Jones 		/* set to 0 to try_hi perf_pctg */
216bb0a56ecSDave Jones 		msr_lo &= 0xFFFFFF80;
217bb0a56ecSDave Jones 		msr_hi &= 0xFFFFFF80;
218bb0a56ecSDave Jones 		msr_hi |= try_hi;
219bb0a56ecSDave Jones 		wrmsr(MSR_TMTA_LONGRUN_CTRL, msr_lo, msr_hi);
220bb0a56ecSDave Jones 
221bb0a56ecSDave Jones 		/* read out current core MHz and current perf_pctg */
222bb0a56ecSDave Jones 		cpuid(0x80860007, &eax, &ebx, &ecx, &edx);
223bb0a56ecSDave Jones 
224bb0a56ecSDave Jones 		/* restore values */
225bb0a56ecSDave Jones 		wrmsr(MSR_TMTA_LONGRUN_CTRL, save_lo, save_hi);
226bb0a56ecSDave Jones 	}
227bb0a56ecSDave Jones 	pr_debug("percentage is %u %%, freq is %u MHz\n", ecx, eax);
228bb0a56ecSDave Jones 
229bb0a56ecSDave Jones 	/* performance_pctg = (current_freq - low_freq)/(high_freq - low_freq)
230bb0a56ecSDave Jones 	 * eqals
231bb0a56ecSDave Jones 	 * low_freq * (1 - perf_pctg) = (cur_freq - high_freq * perf_pctg)
232bb0a56ecSDave Jones 	 *
233bb0a56ecSDave Jones 	 * high_freq * perf_pctg is stored tempoarily into "ebx".
234bb0a56ecSDave Jones 	 */
235bb0a56ecSDave Jones 	ebx = (((cpu_khz / 1000) * ecx) / 100); /* to MHz */
236bb0a56ecSDave Jones 
237bb0a56ecSDave Jones 	if ((ecx > 95) || (ecx == 0) || (eax < ebx))
238bb0a56ecSDave Jones 		return -EIO;
239bb0a56ecSDave Jones 
240bb0a56ecSDave Jones 	edx = ((eax - ebx) * 100) / (100 - ecx);
241bb0a56ecSDave Jones 	*low_freq = edx * 1000; /* back to kHz */
242bb0a56ecSDave Jones 
243bb0a56ecSDave Jones 	pr_debug("low frequency is %u kHz\n", *low_freq);
244bb0a56ecSDave Jones 
245bb0a56ecSDave Jones 	if (*low_freq > *high_freq)
246bb0a56ecSDave Jones 		*low_freq = *high_freq;
247bb0a56ecSDave Jones 
248bb0a56ecSDave Jones 	return 0;
249bb0a56ecSDave Jones }
250bb0a56ecSDave Jones 
251bb0a56ecSDave Jones 
longrun_cpu_init(struct cpufreq_policy * policy)2522760984fSPaul Gortmaker static int longrun_cpu_init(struct cpufreq_policy *policy)
253bb0a56ecSDave Jones {
254bb0a56ecSDave Jones 	int result = 0;
255bb0a56ecSDave Jones 
256bb0a56ecSDave Jones 	/* capability check */
257bb0a56ecSDave Jones 	if (policy->cpu != 0)
258bb0a56ecSDave Jones 		return -ENODEV;
259bb0a56ecSDave Jones 
260bb0a56ecSDave Jones 	/* detect low and high frequency */
261bb0a56ecSDave Jones 	result = longrun_determine_freqs(&longrun_low_freq, &longrun_high_freq);
262bb0a56ecSDave Jones 	if (result)
263bb0a56ecSDave Jones 		return result;
264bb0a56ecSDave Jones 
265bb0a56ecSDave Jones 	/* cpuinfo and default policy values */
266bb0a56ecSDave Jones 	policy->cpuinfo.min_freq = longrun_low_freq;
267bb0a56ecSDave Jones 	policy->cpuinfo.max_freq = longrun_high_freq;
268bb0a56ecSDave Jones 	longrun_get_policy(policy);
269bb0a56ecSDave Jones 
270bb0a56ecSDave Jones 	return 0;
271bb0a56ecSDave Jones }
272bb0a56ecSDave Jones 
273bb0a56ecSDave Jones 
274bb0a56ecSDave Jones static struct cpufreq_driver longrun_driver = {
275bb0a56ecSDave Jones 	.flags		= CPUFREQ_CONST_LOOPS,
276bb0a56ecSDave Jones 	.verify		= longrun_verify_policy,
277bb0a56ecSDave Jones 	.setpolicy	= longrun_set_policy,
278bb0a56ecSDave Jones 	.get		= longrun_get,
279bb0a56ecSDave Jones 	.init		= longrun_cpu_init,
280bb0a56ecSDave Jones 	.name		= "longrun",
281bb0a56ecSDave Jones };
282bb0a56ecSDave Jones 
283fa8031aeSAndi Kleen static const struct x86_cpu_id longrun_ids[] = {
284*b11d77faSThomas Gleixner 	X86_MATCH_VENDOR_FEATURE(TRANSMETA, X86_FEATURE_LONGRUN, NULL),
285fa8031aeSAndi Kleen 	{}
286fa8031aeSAndi Kleen };
287fa8031aeSAndi Kleen MODULE_DEVICE_TABLE(x86cpu, longrun_ids);
288bb0a56ecSDave Jones 
289bb0a56ecSDave Jones /**
290bb0a56ecSDave Jones  * longrun_init - initializes the Transmeta Crusoe LongRun CPUFreq driver
291bb0a56ecSDave Jones  *
292bb0a56ecSDave Jones  * Initializes the LongRun support.
293bb0a56ecSDave Jones  */
longrun_init(void)294bb0a56ecSDave Jones static int __init longrun_init(void)
295bb0a56ecSDave Jones {
296fa8031aeSAndi Kleen 	if (!x86_match_cpu(longrun_ids))
297bb0a56ecSDave Jones 		return -ENODEV;
298bb0a56ecSDave Jones 	return cpufreq_register_driver(&longrun_driver);
299bb0a56ecSDave Jones }
300bb0a56ecSDave Jones 
301bb0a56ecSDave Jones 
302bb0a56ecSDave Jones /**
303bb0a56ecSDave Jones  * longrun_exit - unregisters LongRun support
304bb0a56ecSDave Jones  */
longrun_exit(void)305bb0a56ecSDave Jones static void __exit longrun_exit(void)
306bb0a56ecSDave Jones {
307bb0a56ecSDave Jones 	cpufreq_unregister_driver(&longrun_driver);
308bb0a56ecSDave Jones }
309bb0a56ecSDave Jones 
310bb0a56ecSDave Jones 
311bb0a56ecSDave Jones MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>");
312bb0a56ecSDave Jones MODULE_DESCRIPTION("LongRun driver for Transmeta Crusoe and "
313bb0a56ecSDave Jones 		"Efficeon processors.");
314bb0a56ecSDave Jones MODULE_LICENSE("GPL");
315bb0a56ecSDave Jones 
316bb0a56ecSDave Jones module_init(longrun_init);
317bb0a56ecSDave Jones module_exit(longrun_exit);
318