2 * pcc-cpufreq.c - Processor Clocking Control firmware cpufreq interface
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>
8 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
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.
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.
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.
23 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
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 #include <linux/platform_device.h>
36 #include <linux/acpi.h>
38 #include <linux/spinlock.h>
39 #include <linux/uaccess.h>
41 #include <acpi/processor.h>
43 #define PCC_VERSION "1.10.00"
44 #define POLL_LOOPS 300
46 #define CMD_COMPLETE 0x1
47 #define CMD_GET_FREQ 0x0
48 #define CMD_SET_FREQ 0x1
52 struct pcc_register_resource
{
60 } __attribute__ ((packed
));
62 struct pcc_memory_resource
{
71 u64 translation_offset
;
73 } __attribute__ ((packed
));
75 static struct cpufreq_driver pcc_cpufreq_driver
;
89 u32 throttled_frequency
;
90 u32 minimum_frequency
;
93 static void __iomem
*pcch_virt_addr
;
94 static struct pcc_header __iomem
*pcch_hdr
;
96 static DEFINE_SPINLOCK(pcc_lock
);
98 static struct acpi_generic_address doorbell
;
100 static u64 doorbell_preserve
;
101 static u64 doorbell_write
;
103 static u8 OSC_UUID
[16] = {0x9F, 0x2C, 0x9B, 0x63, 0x91, 0x70, 0x1f, 0x49,
104 0xBB, 0x4F, 0xA5, 0x98, 0x2F, 0xA1, 0xB5, 0x46};
111 static struct pcc_cpu __percpu
*pcc_cpu_info
;
113 static int pcc_cpufreq_verify(struct cpufreq_policy_data
*policy
)
115 cpufreq_verify_within_cpu_limits(policy
);
119 static inline void pcc_cmd(void)
124 acpi_read(&doorbell_value
, &doorbell
);
125 acpi_write((doorbell_value
& doorbell_preserve
) | doorbell_write
,
128 for (i
= 0; i
< POLL_LOOPS
; i
++) {
129 if (ioread16(&pcch_hdr
->status
) & CMD_COMPLETE
)
134 static inline void pcc_clear_mapping(void)
137 iounmap(pcch_virt_addr
);
138 pcch_virt_addr
= NULL
;
141 static unsigned int pcc_get_freq(unsigned int cpu
)
143 struct pcc_cpu
*pcc_cpu_data
;
144 unsigned int curr_freq
;
145 unsigned int freq_limit
;
150 spin_lock(&pcc_lock
);
152 pr_debug("get: get_freq for CPU %d\n", cpu
);
153 pcc_cpu_data
= per_cpu_ptr(pcc_cpu_info
, cpu
);
156 iowrite32(input_buffer
,
157 (pcch_virt_addr
+ pcc_cpu_data
->input_offset
));
158 iowrite16(CMD_GET_FREQ
, &pcch_hdr
->command
);
163 ioread32(pcch_virt_addr
+ pcc_cpu_data
->output_offset
);
165 /* Clear the input buffer - we are done with the current command */
166 memset_io((pcch_virt_addr
+ pcc_cpu_data
->input_offset
), 0, BUF_SZ
);
168 status
= ioread16(&pcch_hdr
->status
);
169 if (status
!= CMD_COMPLETE
) {
170 pr_debug("get: FAILED: for CPU %d, status is %d\n",
174 iowrite16(0, &pcch_hdr
->status
);
175 curr_freq
= (((ioread32(&pcch_hdr
->nominal
) * (output_buffer
& 0xff))
178 pr_debug("get: SUCCESS: (virtual) output_offset for cpu %d is "
179 "0x%p, contains a value of: 0x%x. Speed is: %d MHz\n",
180 cpu
, (pcch_virt_addr
+ pcc_cpu_data
->output_offset
),
181 output_buffer
, curr_freq
);
183 freq_limit
= (output_buffer
>> 8) & 0xff;
184 if (freq_limit
!= 0xff) {
185 pr_debug("get: frequency for cpu %d is being temporarily"
186 " capped at %d\n", cpu
, curr_freq
);
189 spin_unlock(&pcc_lock
);
193 iowrite16(0, &pcch_hdr
->status
);
194 spin_unlock(&pcc_lock
);
198 static int pcc_cpufreq_target(struct cpufreq_policy
*policy
,
199 unsigned int target_freq
,
200 unsigned int relation
)
202 struct pcc_cpu
*pcc_cpu_data
;
203 struct cpufreq_freqs freqs
;
209 pcc_cpu_data
= per_cpu_ptr(pcc_cpu_info
, cpu
);
211 pr_debug("target: CPU %d should go to target freq: %d "
212 "(virtual) input_offset is 0x%p\n",
214 (pcch_virt_addr
+ pcc_cpu_data
->input_offset
));
216 freqs
.old
= policy
->cur
;
217 freqs
.new = target_freq
;
218 cpufreq_freq_transition_begin(policy
, &freqs
);
219 spin_lock(&pcc_lock
);
221 input_buffer
= 0x1 | (((target_freq
* 100)
222 / (ioread32(&pcch_hdr
->nominal
) * 1000)) << 8);
223 iowrite32(input_buffer
,
224 (pcch_virt_addr
+ pcc_cpu_data
->input_offset
));
225 iowrite16(CMD_SET_FREQ
, &pcch_hdr
->command
);
229 /* Clear the input buffer - we are done with the current command */
230 memset_io((pcch_virt_addr
+ pcc_cpu_data
->input_offset
), 0, BUF_SZ
);
232 status
= ioread16(&pcch_hdr
->status
);
233 iowrite16(0, &pcch_hdr
->status
);
235 spin_unlock(&pcc_lock
);
236 cpufreq_freq_transition_end(policy
, &freqs
, status
!= CMD_COMPLETE
);
238 if (status
!= CMD_COMPLETE
) {
239 pr_debug("target: FAILED for cpu %d, with status: 0x%x\n",
244 pr_debug("target: was SUCCESSFUL for cpu %d\n", cpu
);
249 static int pcc_get_offset(int cpu
)
252 struct acpi_buffer buffer
= {ACPI_ALLOCATE_BUFFER
, NULL
};
253 union acpi_object
*pccp
, *offset
;
254 struct pcc_cpu
*pcc_cpu_data
;
255 struct acpi_processor
*pr
;
258 pr
= per_cpu(processors
, cpu
);
259 pcc_cpu_data
= per_cpu_ptr(pcc_cpu_info
, cpu
);
264 status
= acpi_evaluate_object(pr
->handle
, "PCCP", NULL
, &buffer
);
265 if (ACPI_FAILURE(status
))
268 pccp
= buffer
.pointer
;
269 if (!pccp
|| pccp
->type
!= ACPI_TYPE_PACKAGE
) {
274 offset
= &(pccp
->package
.elements
[0]);
275 if (!offset
|| offset
->type
!= ACPI_TYPE_INTEGER
) {
280 pcc_cpu_data
->input_offset
= offset
->integer
.value
;
282 offset
= &(pccp
->package
.elements
[1]);
283 if (!offset
|| offset
->type
!= ACPI_TYPE_INTEGER
) {
288 pcc_cpu_data
->output_offset
= offset
->integer
.value
;
290 memset_io((pcch_virt_addr
+ pcc_cpu_data
->input_offset
), 0, BUF_SZ
);
291 memset_io((pcch_virt_addr
+ pcc_cpu_data
->output_offset
), 0, BUF_SZ
);
293 pr_debug("pcc_get_offset: for CPU %d: pcc_cpu_data "
294 "input_offset: 0x%x, pcc_cpu_data output_offset: 0x%x\n",
295 cpu
, pcc_cpu_data
->input_offset
, pcc_cpu_data
->output_offset
);
297 kfree(buffer
.pointer
);
301 static int __init
pcc_cpufreq_do_osc(acpi_handle
*handle
)
304 struct acpi_object_list input
;
305 struct acpi_buffer output
= {ACPI_ALLOCATE_BUFFER
, NULL
};
306 union acpi_object in_params
[4];
307 union acpi_object
*out_obj
;
314 input
.pointer
= in_params
;
315 in_params
[0].type
= ACPI_TYPE_BUFFER
;
316 in_params
[0].buffer
.length
= 16;
317 in_params
[0].buffer
.pointer
= OSC_UUID
;
318 in_params
[1].type
= ACPI_TYPE_INTEGER
;
319 in_params
[1].integer
.value
= 1;
320 in_params
[2].type
= ACPI_TYPE_INTEGER
;
321 in_params
[2].integer
.value
= 2;
322 in_params
[3].type
= ACPI_TYPE_BUFFER
;
323 in_params
[3].buffer
.length
= 8;
324 in_params
[3].buffer
.pointer
= (u8
*)&capabilities
;
326 capabilities
[0] = OSC_QUERY_ENABLE
;
327 capabilities
[1] = 0x1;
329 status
= acpi_evaluate_object(*handle
, "_OSC", &input
, &output
);
330 if (ACPI_FAILURE(status
))
336 out_obj
= output
.pointer
;
337 if (out_obj
->type
!= ACPI_TYPE_BUFFER
) {
342 errors
= *((u32
*)out_obj
->buffer
.pointer
) & ~(1 << 0);
348 supported
= *((u32
*)(out_obj
->buffer
.pointer
+ 4));
349 if (!(supported
& 0x1)) {
354 kfree(output
.pointer
);
355 capabilities
[0] = 0x0;
356 capabilities
[1] = 0x1;
358 status
= acpi_evaluate_object(*handle
, "_OSC", &input
, &output
);
359 if (ACPI_FAILURE(status
))
365 out_obj
= output
.pointer
;
366 if (out_obj
->type
!= ACPI_TYPE_BUFFER
) {
371 errors
= *((u32
*)out_obj
->buffer
.pointer
) & ~(1 << 0);
377 supported
= *((u32
*)(out_obj
->buffer
.pointer
+ 4));
378 if (!(supported
& 0x1)) {
384 kfree(output
.pointer
);
388 static int __init
pcc_cpufreq_evaluate(void)
391 struct acpi_buffer output
= {ACPI_ALLOCATE_BUFFER
, NULL
};
392 struct pcc_memory_resource
*mem_resource
;
393 struct pcc_register_resource
*reg_resource
;
394 union acpi_object
*out_obj
, *member
;
395 acpi_handle handle
, osc_handle
;
398 status
= acpi_get_handle(NULL
, "\\_SB", &handle
);
399 if (ACPI_FAILURE(status
))
402 if (!acpi_has_method(handle
, "PCCH"))
405 status
= acpi_get_handle(handle
, "_OSC", &osc_handle
);
406 if (ACPI_SUCCESS(status
)) {
407 ret
= pcc_cpufreq_do_osc(&osc_handle
);
409 pr_debug("probe: _OSC evaluation did not succeed\n");
410 /* Firmware's use of _OSC is optional */
414 status
= acpi_evaluate_object(handle
, "PCCH", NULL
, &output
);
415 if (ACPI_FAILURE(status
))
418 out_obj
= output
.pointer
;
419 if (out_obj
->type
!= ACPI_TYPE_PACKAGE
) {
424 member
= &out_obj
->package
.elements
[0];
425 if (member
->type
!= ACPI_TYPE_BUFFER
) {
430 mem_resource
= (struct pcc_memory_resource
*)member
->buffer
.pointer
;
432 pr_debug("probe: mem_resource descriptor: 0x%x,"
433 " length: %d, space_id: %d, resource_usage: %d,"
434 " type_specific: %d, granularity: 0x%llx,"
435 " minimum: 0x%llx, maximum: 0x%llx,"
436 " translation_offset: 0x%llx, address_length: 0x%llx\n",
437 mem_resource
->descriptor
, mem_resource
->length
,
438 mem_resource
->space_id
, mem_resource
->resource_usage
,
439 mem_resource
->type_specific
, mem_resource
->granularity
,
440 mem_resource
->minimum
, mem_resource
->maximum
,
441 mem_resource
->translation_offset
,
442 mem_resource
->address_length
);
444 if (mem_resource
->space_id
!= ACPI_ADR_SPACE_SYSTEM_MEMORY
) {
449 pcch_virt_addr
= ioremap(mem_resource
->minimum
,
450 mem_resource
->address_length
);
451 if (pcch_virt_addr
== NULL
) {
452 pr_debug("probe: could not map shared mem region\n");
456 pcch_hdr
= pcch_virt_addr
;
458 pr_debug("probe: PCCH header (virtual) addr: 0x%p\n", pcch_hdr
);
459 pr_debug("probe: PCCH header is at physical address: 0x%llx,"
460 " signature: 0x%x, length: %d bytes, major: %d, minor: %d,"
461 " supported features: 0x%x, command field: 0x%x,"
462 " status field: 0x%x, nominal latency: %d us\n",
463 mem_resource
->minimum
, ioread32(&pcch_hdr
->signature
),
464 ioread16(&pcch_hdr
->length
), ioread8(&pcch_hdr
->major
),
465 ioread8(&pcch_hdr
->minor
), ioread32(&pcch_hdr
->features
),
466 ioread16(&pcch_hdr
->command
), ioread16(&pcch_hdr
->status
),
467 ioread32(&pcch_hdr
->latency
));
469 pr_debug("probe: min time between commands: %d us,"
470 " max time between commands: %d us,"
471 " nominal CPU frequency: %d MHz,"
472 " minimum CPU frequency: %d MHz,"
473 " minimum CPU frequency without throttling: %d MHz\n",
474 ioread32(&pcch_hdr
->minimum_time
),
475 ioread32(&pcch_hdr
->maximum_time
),
476 ioread32(&pcch_hdr
->nominal
),
477 ioread32(&pcch_hdr
->throttled_frequency
),
478 ioread32(&pcch_hdr
->minimum_frequency
));
480 member
= &out_obj
->package
.elements
[1];
481 if (member
->type
!= ACPI_TYPE_BUFFER
) {
486 reg_resource
= (struct pcc_register_resource
*)member
->buffer
.pointer
;
488 doorbell
.space_id
= reg_resource
->space_id
;
489 doorbell
.bit_width
= reg_resource
->bit_width
;
490 doorbell
.bit_offset
= reg_resource
->bit_offset
;
491 doorbell
.access_width
= 4;
492 doorbell
.address
= reg_resource
->address
;
494 pr_debug("probe: doorbell: space_id is %d, bit_width is %d, "
495 "bit_offset is %d, access_width is %d, address is 0x%llx\n",
496 doorbell
.space_id
, doorbell
.bit_width
, doorbell
.bit_offset
,
497 doorbell
.access_width
, reg_resource
->address
);
499 member
= &out_obj
->package
.elements
[2];
500 if (member
->type
!= ACPI_TYPE_INTEGER
) {
505 doorbell_preserve
= member
->integer
.value
;
507 member
= &out_obj
->package
.elements
[3];
508 if (member
->type
!= ACPI_TYPE_INTEGER
) {
513 doorbell_write
= member
->integer
.value
;
515 pr_debug("probe: doorbell_preserve: 0x%llx,"
516 " doorbell_write: 0x%llx\n",
517 doorbell_preserve
, doorbell_write
);
519 pcc_cpu_info
= alloc_percpu(struct pcc_cpu
);
525 printk(KERN_DEBUG
"pcc-cpufreq: (v%s) driver loaded with frequency"
526 " limits: %d MHz, %d MHz\n", PCC_VERSION
,
527 ioread32(&pcch_hdr
->minimum_frequency
),
528 ioread32(&pcch_hdr
->nominal
));
529 kfree(output
.pointer
);
534 kfree(output
.pointer
);
538 static int pcc_cpufreq_cpu_init(struct cpufreq_policy
*policy
)
540 unsigned int cpu
= policy
->cpu
;
541 unsigned int result
= 0;
543 if (!pcch_virt_addr
) {
548 result
= pcc_get_offset(cpu
);
550 pr_debug("init: PCCP evaluation failed\n");
554 policy
->max
= policy
->cpuinfo
.max_freq
=
555 ioread32(&pcch_hdr
->nominal
) * 1000;
556 policy
->min
= policy
->cpuinfo
.min_freq
=
557 ioread32(&pcch_hdr
->minimum_frequency
) * 1000;
559 pr_debug("init: policy->max is %d, policy->min is %d\n",
560 policy
->max
, policy
->min
);
565 static struct cpufreq_driver pcc_cpufreq_driver
= {
566 .flags
= CPUFREQ_CONST_LOOPS
,
568 .verify
= pcc_cpufreq_verify
,
569 .target
= pcc_cpufreq_target
,
570 .init
= pcc_cpufreq_cpu_init
,
571 .name
= "pcc-cpufreq",
574 static int __init
pcc_cpufreq_probe(struct platform_device
*pdev
)
578 /* Skip initialization if another cpufreq driver is there. */
579 if (cpufreq_get_current_driver())
585 ret
= pcc_cpufreq_evaluate();
587 pr_debug("pcc_cpufreq_probe: PCCH evaluation failed\n");
591 if (num_present_cpus() > 4) {
592 pcc_cpufreq_driver
.flags
|= CPUFREQ_NO_AUTO_DYNAMIC_SWITCHING
;
593 pr_err("%s: Too many CPUs, dynamic performance scaling disabled\n",
595 pr_err("%s: Try to enable another scaling driver through BIOS settings\n",
597 pr_err("%s: and complain to the system vendor\n", __func__
);
600 ret
= cpufreq_register_driver(&pcc_cpufreq_driver
);
605 static void pcc_cpufreq_remove(struct platform_device
*pdev
)
607 cpufreq_unregister_driver(&pcc_cpufreq_driver
);
611 free_percpu(pcc_cpu_info
);
614 static struct platform_driver pcc_cpufreq_platdrv
= {
616 .name
= "pcc-cpufreq",
618 .remove
= pcc_cpufreq_remove
,
621 static int __init
pcc_cpufreq_init(void)
623 return platform_driver_probe(&pcc_cpufreq_platdrv
, pcc_cpufreq_probe
);
626 static void __exit
pcc_cpufreq_exit(void)
628 platform_driver_unregister(&pcc_cpufreq_platdrv
);
631 MODULE_ALIAS("platform:pcc-cpufreq");
633 MODULE_AUTHOR("Matthew Garrett, Naga Chumbalkar");
634 MODULE_VERSION(PCC_VERSION
);
635 MODULE_DESCRIPTION("Processor Clocking Control interface driver");
636 MODULE_LICENSE("GPL");
638 late_initcall(pcc_cpufreq_init
);
639 module_exit(pcc_cpufreq_exit
);