• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6.36/arch/x86/kernel/cpu/cpufreq/
1/*
2 *  pcc-cpufreq.c - Processor Clocking Control firmware cpufreq interface
3 *
4 *  Copyright (C) 2009 Red Hat, Matthew Garrett <mjg@redhat.com>
5 *  Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
6 *	Nagananda Chumbalkar <nagananda.chumbalkar@hp.com>
7 *
8 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
9 *
10 *  This program is free software; you can redistribute it and/or modify
11 *  it under the terms of the GNU General Public License as published by
12 *  the Free Software Foundation; version 2 of the License.
13 *
14 *  This program is distributed in the hope that it will be useful, but
15 *  WITHOUT ANY WARRANTY; without even the implied warranty of
16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or NON
17 *  INFRINGEMENT. See the GNU General Public License for more details.
18 *
19 *  You should have received a copy of the GNU General Public License along
20 *  with this program; if not, write to the Free Software Foundation, Inc.,
21 *  675 Mass Ave, Cambridge, MA 02139, USA.
22 *
23 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
24 */
25
26#include <linux/kernel.h>
27#include <linux/module.h>
28#include <linux/init.h>
29#include <linux/smp.h>
30#include <linux/sched.h>
31#include <linux/cpufreq.h>
32#include <linux/compiler.h>
33#include <linux/slab.h>
34
35#include <linux/acpi.h>
36#include <linux/io.h>
37#include <linux/spinlock.h>
38#include <linux/uaccess.h>
39
40#include <acpi/processor.h>
41
42#define PCC_VERSION 	"1.00.00"
43#define POLL_LOOPS 	300
44
45#define CMD_COMPLETE 	0x1
46#define CMD_GET_FREQ 	0x0
47#define CMD_SET_FREQ 	0x1
48
49#define BUF_SZ		4
50
51#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER,	\
52					     "pcc-cpufreq", msg)
53
54struct pcc_register_resource {
55	u8 descriptor;
56	u16 length;
57	u8 space_id;
58	u8 bit_width;
59	u8 bit_offset;
60	u8 access_size;
61	u64 address;
62} __attribute__ ((packed));
63
64struct pcc_memory_resource {
65	u8 descriptor;
66	u16 length;
67	u8 space_id;
68	u8 resource_usage;
69	u8 type_specific;
70	u64 granularity;
71	u64 minimum;
72	u64 maximum;
73	u64 translation_offset;
74	u64 address_length;
75} __attribute__ ((packed));
76
77static struct cpufreq_driver pcc_cpufreq_driver;
78
79struct pcc_header {
80	u32 signature;
81	u16 length;
82	u8 major;
83	u8 minor;
84	u32 features;
85	u16 command;
86	u16 status;
87	u32 latency;
88	u32 minimum_time;
89	u32 maximum_time;
90	u32 nominal;
91	u32 throttled_frequency;
92	u32 minimum_frequency;
93};
94
95static void __iomem *pcch_virt_addr;
96static struct pcc_header __iomem *pcch_hdr;
97
98static DEFINE_SPINLOCK(pcc_lock);
99
100static struct acpi_generic_address doorbell;
101
102static u64 doorbell_preserve;
103static u64 doorbell_write;
104
105static u8 OSC_UUID[16] = {0x63, 0x9B, 0x2C, 0x9F, 0x70, 0x91, 0x49, 0x1f,
106			  0xBB, 0x4F, 0xA5, 0x98, 0x2F, 0xA1, 0xB5, 0x46};
107
108struct pcc_cpu {
109	u32 input_offset;
110	u32 output_offset;
111};
112
113static struct pcc_cpu __percpu *pcc_cpu_info;
114
115static int pcc_cpufreq_verify(struct cpufreq_policy *policy)
116{
117	cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
118				     policy->cpuinfo.max_freq);
119	return 0;
120}
121
122static inline void pcc_cmd(void)
123{
124	u64 doorbell_value;
125	int i;
126
127	acpi_read(&doorbell_value, &doorbell);
128	acpi_write((doorbell_value & doorbell_preserve) | doorbell_write,
129		   &doorbell);
130
131	for (i = 0; i < POLL_LOOPS; i++) {
132		if (ioread16(&pcch_hdr->status) & CMD_COMPLETE)
133			break;
134	}
135}
136
137static inline void pcc_clear_mapping(void)
138{
139	if (pcch_virt_addr)
140		iounmap(pcch_virt_addr);
141	pcch_virt_addr = NULL;
142}
143
144static unsigned int pcc_get_freq(unsigned int cpu)
145{
146	struct pcc_cpu *pcc_cpu_data;
147	unsigned int curr_freq;
148	unsigned int freq_limit;
149	u16 status;
150	u32 input_buffer;
151	u32 output_buffer;
152
153	spin_lock(&pcc_lock);
154
155	dprintk("get: get_freq for CPU %d\n", cpu);
156	pcc_cpu_data = per_cpu_ptr(pcc_cpu_info, cpu);
157
158	input_buffer = 0x1;
159	iowrite32(input_buffer,
160			(pcch_virt_addr + pcc_cpu_data->input_offset));
161	iowrite16(CMD_GET_FREQ, &pcch_hdr->command);
162
163	pcc_cmd();
164
165	output_buffer =
166		ioread32(pcch_virt_addr + pcc_cpu_data->output_offset);
167
168	/* Clear the input buffer - we are done with the current command */
169	memset_io((pcch_virt_addr + pcc_cpu_data->input_offset), 0, BUF_SZ);
170
171	status = ioread16(&pcch_hdr->status);
172	if (status != CMD_COMPLETE) {
173		dprintk("get: FAILED: for CPU %d, status is %d\n",
174			cpu, status);
175		goto cmd_incomplete;
176	}
177	iowrite16(0, &pcch_hdr->status);
178	curr_freq = (((ioread32(&pcch_hdr->nominal) * (output_buffer & 0xff))
179			/ 100) * 1000);
180
181	dprintk("get: SUCCESS: (virtual) output_offset for cpu %d is "
182		"0x%x, contains a value of: 0x%x. Speed is: %d MHz\n",
183		cpu, (pcch_virt_addr + pcc_cpu_data->output_offset),
184		output_buffer, curr_freq);
185
186	freq_limit = (output_buffer >> 8) & 0xff;
187	if (freq_limit != 0xff) {
188		dprintk("get: frequency for cpu %d is being temporarily"
189			" capped at %d\n", cpu, curr_freq);
190	}
191
192	spin_unlock(&pcc_lock);
193	return curr_freq;
194
195cmd_incomplete:
196	iowrite16(0, &pcch_hdr->status);
197	spin_unlock(&pcc_lock);
198	return -EINVAL;
199}
200
201static int pcc_cpufreq_target(struct cpufreq_policy *policy,
202			      unsigned int target_freq,
203			      unsigned int relation)
204{
205	struct pcc_cpu *pcc_cpu_data;
206	struct cpufreq_freqs freqs;
207	u16 status;
208	u32 input_buffer;
209	int cpu;
210
211	spin_lock(&pcc_lock);
212	cpu = policy->cpu;
213	pcc_cpu_data = per_cpu_ptr(pcc_cpu_info, cpu);
214
215	dprintk("target: CPU %d should go to target freq: %d "
216		"(virtual) input_offset is 0x%x\n",
217		cpu, target_freq,
218		(pcch_virt_addr + pcc_cpu_data->input_offset));
219
220	freqs.new = target_freq;
221	freqs.cpu = cpu;
222	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
223
224	input_buffer = 0x1 | (((target_freq * 100)
225			       / (ioread32(&pcch_hdr->nominal) * 1000)) << 8);
226	iowrite32(input_buffer,
227			(pcch_virt_addr + pcc_cpu_data->input_offset));
228	iowrite16(CMD_SET_FREQ, &pcch_hdr->command);
229
230	pcc_cmd();
231
232	/* Clear the input buffer - we are done with the current command */
233	memset_io((pcch_virt_addr + pcc_cpu_data->input_offset), 0, BUF_SZ);
234
235	status = ioread16(&pcch_hdr->status);
236	if (status != CMD_COMPLETE) {
237		dprintk("target: FAILED for cpu %d, with status: 0x%x\n",
238			cpu, status);
239		goto cmd_incomplete;
240	}
241	iowrite16(0, &pcch_hdr->status);
242
243	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
244	dprintk("target: was SUCCESSFUL for cpu %d\n", cpu);
245	spin_unlock(&pcc_lock);
246
247	return 0;
248
249cmd_incomplete:
250	iowrite16(0, &pcch_hdr->status);
251	spin_unlock(&pcc_lock);
252	return -EINVAL;
253}
254
255static int pcc_get_offset(int cpu)
256{
257	acpi_status status;
258	struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
259	union acpi_object *pccp, *offset;
260	struct pcc_cpu *pcc_cpu_data;
261	struct acpi_processor *pr;
262	int ret = 0;
263
264	pr = per_cpu(processors, cpu);
265	pcc_cpu_data = per_cpu_ptr(pcc_cpu_info, cpu);
266
267	status = acpi_evaluate_object(pr->handle, "PCCP", NULL, &buffer);
268	if (ACPI_FAILURE(status))
269		return -ENODEV;
270
271	pccp = buffer.pointer;
272	if (!pccp || pccp->type != ACPI_TYPE_PACKAGE) {
273		ret = -ENODEV;
274		goto out_free;
275	};
276
277	offset = &(pccp->package.elements[0]);
278	if (!offset || offset->type != ACPI_TYPE_INTEGER) {
279		ret = -ENODEV;
280		goto out_free;
281	}
282
283	pcc_cpu_data->input_offset = offset->integer.value;
284
285	offset = &(pccp->package.elements[1]);
286	if (!offset || offset->type != ACPI_TYPE_INTEGER) {
287		ret = -ENODEV;
288		goto out_free;
289	}
290
291	pcc_cpu_data->output_offset = offset->integer.value;
292
293	memset_io((pcch_virt_addr + pcc_cpu_data->input_offset), 0, BUF_SZ);
294	memset_io((pcch_virt_addr + pcc_cpu_data->output_offset), 0, BUF_SZ);
295
296	dprintk("pcc_get_offset: for CPU %d: pcc_cpu_data "
297		"input_offset: 0x%x, pcc_cpu_data output_offset: 0x%x\n",
298		cpu, pcc_cpu_data->input_offset, pcc_cpu_data->output_offset);
299out_free:
300	kfree(buffer.pointer);
301	return ret;
302}
303
304static int __init pcc_cpufreq_do_osc(acpi_handle *handle)
305{
306	acpi_status status;
307	struct acpi_object_list input;
308	struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL};
309	union acpi_object in_params[4];
310	union acpi_object *out_obj;
311	u32 capabilities[2];
312	u32 errors;
313	u32 supported;
314	int ret = 0;
315
316	input.count = 4;
317	input.pointer = in_params;
318	input.count = 4;
319	input.pointer = in_params;
320	in_params[0].type               = ACPI_TYPE_BUFFER;
321	in_params[0].buffer.length      = 16;
322	in_params[0].buffer.pointer     = OSC_UUID;
323	in_params[1].type               = ACPI_TYPE_INTEGER;
324	in_params[1].integer.value      = 1;
325	in_params[2].type               = ACPI_TYPE_INTEGER;
326	in_params[2].integer.value      = 2;
327	in_params[3].type               = ACPI_TYPE_BUFFER;
328	in_params[3].buffer.length      = 8;
329	in_params[3].buffer.pointer     = (u8 *)&capabilities;
330
331	capabilities[0] = OSC_QUERY_ENABLE;
332	capabilities[1] = 0x1;
333
334	status = acpi_evaluate_object(*handle, "_OSC", &input, &output);
335	if (ACPI_FAILURE(status))
336		return -ENODEV;
337
338	if (!output.length)
339		return -ENODEV;
340
341	out_obj = output.pointer;
342	if (out_obj->type != ACPI_TYPE_BUFFER) {
343		ret = -ENODEV;
344		goto out_free;
345	}
346
347	errors = *((u32 *)out_obj->buffer.pointer) & ~(1 << 0);
348	if (errors) {
349		ret = -ENODEV;
350		goto out_free;
351	}
352
353	supported = *((u32 *)(out_obj->buffer.pointer + 4));
354	if (!(supported & 0x1)) {
355		ret = -ENODEV;
356		goto out_free;
357	}
358
359	kfree(output.pointer);
360	capabilities[0] = 0x0;
361	capabilities[1] = 0x1;
362
363	status = acpi_evaluate_object(*handle, "_OSC", &input, &output);
364	if (ACPI_FAILURE(status))
365		return -ENODEV;
366
367	if (!output.length)
368		return -ENODEV;
369
370	out_obj = output.pointer;
371	if (out_obj->type != ACPI_TYPE_BUFFER) {
372		ret = -ENODEV;
373		goto out_free;
374	}
375
376	errors = *((u32 *)out_obj->buffer.pointer) & ~(1 << 0);
377	if (errors) {
378		ret = -ENODEV;
379		goto out_free;
380	}
381
382	supported = *((u32 *)(out_obj->buffer.pointer + 4));
383	if (!(supported & 0x1)) {
384		ret = -ENODEV;
385		goto out_free;
386	}
387
388out_free:
389	kfree(output.pointer);
390	return ret;
391}
392
393static int __init pcc_cpufreq_probe(void)
394{
395	acpi_status status;
396	struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL};
397	struct pcc_memory_resource *mem_resource;
398	struct pcc_register_resource *reg_resource;
399	union acpi_object *out_obj, *member;
400	acpi_handle handle, osc_handle, pcch_handle;
401	int ret = 0;
402
403	status = acpi_get_handle(NULL, "\\_SB", &handle);
404	if (ACPI_FAILURE(status))
405		return -ENODEV;
406
407	status = acpi_get_handle(handle, "PCCH", &pcch_handle);
408	if (ACPI_FAILURE(status))
409		return -ENODEV;
410
411	status = acpi_get_handle(handle, "_OSC", &osc_handle);
412	if (ACPI_SUCCESS(status)) {
413		ret = pcc_cpufreq_do_osc(&osc_handle);
414		if (ret)
415			dprintk("probe: _OSC evaluation did not succeed\n");
416		/* Firmware's use of _OSC is optional */
417		ret = 0;
418	}
419
420	status = acpi_evaluate_object(handle, "PCCH", NULL, &output);
421	if (ACPI_FAILURE(status))
422		return -ENODEV;
423
424	out_obj = output.pointer;
425	if (out_obj->type != ACPI_TYPE_PACKAGE) {
426		ret = -ENODEV;
427		goto out_free;
428	}
429
430	member = &out_obj->package.elements[0];
431	if (member->type != ACPI_TYPE_BUFFER) {
432		ret = -ENODEV;
433		goto out_free;
434	}
435
436	mem_resource = (struct pcc_memory_resource *)member->buffer.pointer;
437
438	dprintk("probe: mem_resource descriptor: 0x%x,"
439		" length: %d, space_id: %d, resource_usage: %d,"
440		" type_specific: %d, granularity: 0x%llx,"
441		" minimum: 0x%llx, maximum: 0x%llx,"
442		" translation_offset: 0x%llx, address_length: 0x%llx\n",
443		mem_resource->descriptor, mem_resource->length,
444		mem_resource->space_id, mem_resource->resource_usage,
445		mem_resource->type_specific, mem_resource->granularity,
446		mem_resource->minimum, mem_resource->maximum,
447		mem_resource->translation_offset,
448		mem_resource->address_length);
449
450	if (mem_resource->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) {
451		ret = -ENODEV;
452		goto out_free;
453	}
454
455	pcch_virt_addr = ioremap_nocache(mem_resource->minimum,
456					mem_resource->address_length);
457	if (pcch_virt_addr == NULL) {
458		dprintk("probe: could not map shared mem region\n");
459		goto out_free;
460	}
461	pcch_hdr = pcch_virt_addr;
462
463	dprintk("probe: PCCH header (virtual) addr: 0x%p\n", pcch_hdr);
464	dprintk("probe: PCCH header is at physical address: 0x%llx,"
465		" signature: 0x%x, length: %d bytes, major: %d, minor: %d,"
466		" supported features: 0x%x, command field: 0x%x,"
467		" status field: 0x%x, nominal latency: %d us\n",
468		mem_resource->minimum, ioread32(&pcch_hdr->signature),
469		ioread16(&pcch_hdr->length), ioread8(&pcch_hdr->major),
470		ioread8(&pcch_hdr->minor), ioread32(&pcch_hdr->features),
471		ioread16(&pcch_hdr->command), ioread16(&pcch_hdr->status),
472		ioread32(&pcch_hdr->latency));
473
474	dprintk("probe: min time between commands: %d us,"
475		" max time between commands: %d us,"
476		" nominal CPU frequency: %d MHz,"
477		" minimum CPU frequency: %d MHz,"
478		" minimum CPU frequency without throttling: %d MHz\n",
479		ioread32(&pcch_hdr->minimum_time),
480		ioread32(&pcch_hdr->maximum_time),
481		ioread32(&pcch_hdr->nominal),
482		ioread32(&pcch_hdr->throttled_frequency),
483		ioread32(&pcch_hdr->minimum_frequency));
484
485	member = &out_obj->package.elements[1];
486	if (member->type != ACPI_TYPE_BUFFER) {
487		ret = -ENODEV;
488		goto pcch_free;
489	}
490
491	reg_resource = (struct pcc_register_resource *)member->buffer.pointer;
492
493	doorbell.space_id = reg_resource->space_id;
494	doorbell.bit_width = reg_resource->bit_width;
495	doorbell.bit_offset = reg_resource->bit_offset;
496	doorbell.access_width = 64;
497	doorbell.address = reg_resource->address;
498
499	dprintk("probe: doorbell: space_id is %d, bit_width is %d, "
500		"bit_offset is %d, access_width is %d, address is 0x%llx\n",
501		doorbell.space_id, doorbell.bit_width, doorbell.bit_offset,
502		doorbell.access_width, reg_resource->address);
503
504	member = &out_obj->package.elements[2];
505	if (member->type != ACPI_TYPE_INTEGER) {
506		ret = -ENODEV;
507		goto pcch_free;
508	}
509
510	doorbell_preserve = member->integer.value;
511
512	member = &out_obj->package.elements[3];
513	if (member->type != ACPI_TYPE_INTEGER) {
514		ret = -ENODEV;
515		goto pcch_free;
516	}
517
518	doorbell_write = member->integer.value;
519
520	dprintk("probe: doorbell_preserve: 0x%llx,"
521		" doorbell_write: 0x%llx\n",
522		doorbell_preserve, doorbell_write);
523
524	pcc_cpu_info = alloc_percpu(struct pcc_cpu);
525	if (!pcc_cpu_info) {
526		ret = -ENOMEM;
527		goto pcch_free;
528	}
529
530	printk(KERN_DEBUG "pcc-cpufreq: (v%s) driver loaded with frequency"
531	       " limits: %d MHz, %d MHz\n", PCC_VERSION,
532	       ioread32(&pcch_hdr->minimum_frequency),
533	       ioread32(&pcch_hdr->nominal));
534	kfree(output.pointer);
535	return ret;
536pcch_free:
537	pcc_clear_mapping();
538out_free:
539	kfree(output.pointer);
540	return ret;
541}
542
543static int pcc_cpufreq_cpu_init(struct cpufreq_policy *policy)
544{
545	unsigned int cpu = policy->cpu;
546	unsigned int result = 0;
547
548	if (!pcch_virt_addr) {
549		result = -1;
550		goto out;
551	}
552
553	result = pcc_get_offset(cpu);
554	if (result) {
555		dprintk("init: PCCP evaluation failed\n");
556		goto out;
557	}
558
559	policy->max = policy->cpuinfo.max_freq =
560		ioread32(&pcch_hdr->nominal) * 1000;
561	policy->min = policy->cpuinfo.min_freq =
562		ioread32(&pcch_hdr->minimum_frequency) * 1000;
563	policy->cur = pcc_get_freq(cpu);
564
565	if (!policy->cur) {
566		dprintk("init: Unable to get current CPU frequency\n");
567		result = -EINVAL;
568		goto out;
569	}
570
571	dprintk("init: policy->max is %d, policy->min is %d\n",
572		policy->max, policy->min);
573out:
574	return result;
575}
576
577static int pcc_cpufreq_cpu_exit(struct cpufreq_policy *policy)
578{
579	return 0;
580}
581
582static struct cpufreq_driver pcc_cpufreq_driver = {
583	.flags = CPUFREQ_CONST_LOOPS,
584	.get = pcc_get_freq,
585	.verify = pcc_cpufreq_verify,
586	.target = pcc_cpufreq_target,
587	.init = pcc_cpufreq_cpu_init,
588	.exit = pcc_cpufreq_cpu_exit,
589	.name = "pcc-cpufreq",
590	.owner = THIS_MODULE,
591};
592
593static int __init pcc_cpufreq_init(void)
594{
595	int ret;
596
597	if (acpi_disabled)
598		return 0;
599
600	ret = pcc_cpufreq_probe();
601	if (ret) {
602		dprintk("pcc_cpufreq_init: PCCH evaluation failed\n");
603		return ret;
604	}
605
606	ret = cpufreq_register_driver(&pcc_cpufreq_driver);
607
608	return ret;
609}
610
611static void __exit pcc_cpufreq_exit(void)
612{
613	cpufreq_unregister_driver(&pcc_cpufreq_driver);
614
615	pcc_clear_mapping();
616
617	free_percpu(pcc_cpu_info);
618}
619
620MODULE_AUTHOR("Matthew Garrett, Naga Chumbalkar");
621MODULE_VERSION(PCC_VERSION);
622MODULE_DESCRIPTION("Processor Clocking Control interface driver");
623MODULE_LICENSE("GPL");
624
625late_initcall(pcc_cpufreq_init);
626module_exit(pcc_cpufreq_exit);
627