26 #include <linux/kernel.h>
27 #include <linux/module.h>
30 #include <linux/sched.h>
32 #include <linux/compiler.h>
33 #include <linux/slab.h>
42 #define PCC_VERSION "1.10.00"
43 #define POLL_LOOPS 300
45 #define CMD_COMPLETE 0x1
46 #define CMD_GET_FREQ 0x0
47 #define CMD_SET_FREQ 0x1
92 static void __iomem *pcch_virt_addr;
99 static u64 doorbell_preserve;
100 static u64 doorbell_write;
102 static u8 OSC_UUID[16] = {0x9F, 0x2C, 0x9B, 0x63, 0x91, 0x70, 0x1f, 0x49,
103 0xBB, 0x4F, 0xA5, 0x98, 0x2F, 0xA1, 0xB5, 0x46};
114 cpufreq_verify_within_limits(policy, policy->
cpuinfo.min_freq,
119 static inline void pcc_cmd(
void)
125 acpi_write((doorbell_value & doorbell_preserve) | doorbell_write,
134 static inline void pcc_clear_mapping(
void)
138 pcch_virt_addr =
NULL;
141 static unsigned int pcc_get_freq(
unsigned int cpu)
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);
170 pr_debug(
"get: FAILED: for CPU %d, status is %d\n",
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",
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);
194 spin_unlock(&pcc_lock);
199 unsigned int target_freq,
200 unsigned int relation)
208 spin_lock(&pcc_lock);
212 pr_debug(
"target: CPU %d should go to target freq: %d "
213 "(virtual) input_offset is 0x%p\n",
217 freqs.new = target_freq;
221 input_buffer = 0x1 | (((target_freq * 100)
234 pr_debug(
"target: FAILED for cpu %d, with status: 0x%x\n",
241 pr_debug(
"target: was SUCCESSFUL for cpu %d\n", cpu);
242 spin_unlock(&pcc_lock);
248 spin_unlock(&pcc_lock);
252 static int pcc_get_offset(
int cpu)
277 offset = &(pccp->
package.elements[0]);
285 offset = &(pccp->
package.elements[1]);
296 pr_debug(
"pcc_get_offset: for CPU %d: pcc_cpu_data "
297 "input_offset: 0x%x, pcc_cpu_data output_offset: 0x%x\n",
317 input.pointer = in_params;
319 in_params[0].buffer.length = 16;
320 in_params[0].buffer.pointer = OSC_UUID;
322 in_params[1].integer.value = 1;
324 in_params[2].integer.value = 2;
326 in_params[3].buffer.length = 8;
327 in_params[3].buffer.pointer = (
u8 *)&capabilities;
329 capabilities[0] = OSC_QUERY_ENABLE;
330 capabilities[1] = 0x1;
345 errors = *((
u32 *)out_obj->
buffer.pointer) & ~(1 << 0);
351 supported = *((
u32 *)(out_obj->
buffer.pointer + 4));
352 if (!(supported & 0x1)) {
358 capabilities[0] = 0x0;
359 capabilities[1] = 0x1;
374 errors = *((
u32 *)out_obj->
buffer.pointer) & ~(1 << 0);
380 supported = *((
u32 *)(out_obj->
buffer.pointer + 4));
381 if (!(supported & 0x1)) {
391 static int __init pcc_cpufreq_probe(
void)
411 ret = pcc_cpufreq_do_osc(&osc_handle);
413 pr_debug(
"probe: _OSC evaluation did not succeed\n");
428 member = &out_obj->
package.elements[0];
436 pr_debug(
"probe: mem_resource descriptor: 0x%x,"
437 " length: %d, space_id: %d, resource_usage: %d,"
438 " type_specific: %d, granularity: 0x%llx,"
439 " minimum: 0x%llx, maximum: 0x%llx,"
440 " translation_offset: 0x%llx, address_length: 0x%llx\n",
455 if (pcch_virt_addr ==
NULL) {
456 pr_debug(
"probe: could not map shared mem region\n");
460 pcch_hdr = pcch_virt_addr;
462 pr_debug(
"probe: PCCH header (virtual) addr: 0x%p\n", pcch_hdr);
463 pr_debug(
"probe: PCCH header is at physical address: 0x%llx,"
464 " signature: 0x%x, length: %d bytes, major: %d, minor: %d,"
465 " supported features: 0x%x, command field: 0x%x,"
466 " status field: 0x%x, nominal latency: %d us\n",
473 pr_debug(
"probe: min time between commands: %d us,"
474 " max time between commands: %d us,"
475 " nominal CPU frequency: %d MHz,"
476 " minimum CPU frequency: %d MHz,"
477 " minimum CPU frequency without throttling: %d MHz\n",
484 member = &out_obj->
package.elements[1];
498 pr_debug(
"probe: doorbell: space_id is %d, bit_width is %d, "
499 "bit_offset is %d, access_width is %d, address is 0x%llx\n",
503 member = &out_obj->
package.elements[2];
509 doorbell_preserve = member->
integer.value;
511 member = &out_obj->
package.elements[3];
517 doorbell_write = member->
integer.value;
519 pr_debug(
"probe: doorbell_preserve: 0x%llx,"
520 " doorbell_write: 0x%llx\n",
521 doorbell_preserve, doorbell_write);
544 unsigned int cpu = policy->
cpu;
547 if (!pcch_virt_addr) {
552 result = pcc_get_offset(cpu);
554 pr_debug(
"init: PCCP evaluation failed\n");
562 policy->
cur = pcc_get_freq(cpu);
565 pr_debug(
"init: Unable to get current CPU frequency\n");
570 pr_debug(
"init: policy->max is %d, policy->min is %d\n",
571 policy->
max, policy->
min);
584 .verify = pcc_cpufreq_verify,
585 .target = pcc_cpufreq_target,
586 .init = pcc_cpufreq_cpu_init,
587 .exit = pcc_cpufreq_cpu_exit,
588 .name =
"pcc-cpufreq",
592 static int __init pcc_cpufreq_init(
void)
599 ret = pcc_cpufreq_probe();
601 pr_debug(
"pcc_cpufreq_init: PCCH evaluation failed\n");
610 static void __exit pcc_cpufreq_exit(
void)