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