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 { 114be49e346SViresh Kumar cpufreq_verify_within_cpu_limits(policy); 115bb0a56ecSDave Jones return 0; 116bb0a56ecSDave Jones } 117bb0a56ecSDave Jones 118bb0a56ecSDave Jones static inline void pcc_cmd(void) 119bb0a56ecSDave Jones { 120bb0a56ecSDave Jones u64 doorbell_value; 121bb0a56ecSDave Jones int i; 122bb0a56ecSDave Jones 123bb0a56ecSDave Jones acpi_read(&doorbell_value, &doorbell); 124bb0a56ecSDave Jones acpi_write((doorbell_value & doorbell_preserve) | doorbell_write, 125bb0a56ecSDave Jones &doorbell); 126bb0a56ecSDave Jones 127bb0a56ecSDave Jones for (i = 0; i < POLL_LOOPS; i++) { 128bb0a56ecSDave Jones if (ioread16(&pcch_hdr->status) & CMD_COMPLETE) 129bb0a56ecSDave Jones break; 130bb0a56ecSDave Jones } 131bb0a56ecSDave Jones } 132bb0a56ecSDave Jones 133bb0a56ecSDave Jones static inline void pcc_clear_mapping(void) 134bb0a56ecSDave Jones { 135bb0a56ecSDave Jones if (pcch_virt_addr) 136bb0a56ecSDave Jones iounmap(pcch_virt_addr); 137bb0a56ecSDave Jones pcch_virt_addr = NULL; 138bb0a56ecSDave Jones } 139bb0a56ecSDave Jones 140bb0a56ecSDave Jones static unsigned int pcc_get_freq(unsigned int cpu) 141bb0a56ecSDave Jones { 142bb0a56ecSDave Jones struct pcc_cpu *pcc_cpu_data; 143bb0a56ecSDave Jones unsigned int curr_freq; 144bb0a56ecSDave Jones unsigned int freq_limit; 145bb0a56ecSDave Jones u16 status; 146bb0a56ecSDave Jones u32 input_buffer; 147bb0a56ecSDave Jones u32 output_buffer; 148bb0a56ecSDave Jones 149bb0a56ecSDave Jones spin_lock(&pcc_lock); 150bb0a56ecSDave Jones 151bb0a56ecSDave Jones pr_debug("get: get_freq for CPU %d\n", cpu); 152bb0a56ecSDave Jones pcc_cpu_data = per_cpu_ptr(pcc_cpu_info, cpu); 153bb0a56ecSDave Jones 154bb0a56ecSDave Jones input_buffer = 0x1; 155bb0a56ecSDave Jones iowrite32(input_buffer, 156bb0a56ecSDave Jones (pcch_virt_addr + pcc_cpu_data->input_offset)); 157bb0a56ecSDave Jones iowrite16(CMD_GET_FREQ, &pcch_hdr->command); 158bb0a56ecSDave Jones 159bb0a56ecSDave Jones pcc_cmd(); 160bb0a56ecSDave Jones 161bb0a56ecSDave Jones output_buffer = 162bb0a56ecSDave Jones ioread32(pcch_virt_addr + pcc_cpu_data->output_offset); 163bb0a56ecSDave Jones 164bb0a56ecSDave Jones /* Clear the input buffer - we are done with the current command */ 165bb0a56ecSDave Jones memset_io((pcch_virt_addr + pcc_cpu_data->input_offset), 0, BUF_SZ); 166bb0a56ecSDave Jones 167bb0a56ecSDave Jones status = ioread16(&pcch_hdr->status); 168bb0a56ecSDave Jones if (status != CMD_COMPLETE) { 169bb0a56ecSDave Jones pr_debug("get: FAILED: for CPU %d, status is %d\n", 170bb0a56ecSDave Jones cpu, status); 171bb0a56ecSDave Jones goto cmd_incomplete; 172bb0a56ecSDave Jones } 173bb0a56ecSDave Jones iowrite16(0, &pcch_hdr->status); 174bb0a56ecSDave Jones curr_freq = (((ioread32(&pcch_hdr->nominal) * (output_buffer & 0xff)) 175bb0a56ecSDave Jones / 100) * 1000); 176bb0a56ecSDave Jones 177bb0a56ecSDave Jones pr_debug("get: SUCCESS: (virtual) output_offset for cpu %d is " 178bb0a56ecSDave Jones "0x%p, contains a value of: 0x%x. Speed is: %d MHz\n", 179bb0a56ecSDave Jones cpu, (pcch_virt_addr + pcc_cpu_data->output_offset), 180bb0a56ecSDave Jones output_buffer, curr_freq); 181bb0a56ecSDave Jones 182bb0a56ecSDave Jones freq_limit = (output_buffer >> 8) & 0xff; 183bb0a56ecSDave Jones if (freq_limit != 0xff) { 184bb0a56ecSDave Jones pr_debug("get: frequency for cpu %d is being temporarily" 185bb0a56ecSDave Jones " capped at %d\n", cpu, curr_freq); 186bb0a56ecSDave Jones } 187bb0a56ecSDave Jones 188bb0a56ecSDave Jones spin_unlock(&pcc_lock); 189bb0a56ecSDave Jones return curr_freq; 190bb0a56ecSDave Jones 191bb0a56ecSDave Jones cmd_incomplete: 192bb0a56ecSDave Jones iowrite16(0, &pcch_hdr->status); 193bb0a56ecSDave Jones spin_unlock(&pcc_lock); 194bb0a56ecSDave Jones return 0; 195bb0a56ecSDave Jones } 196bb0a56ecSDave Jones 197bb0a56ecSDave Jones static int pcc_cpufreq_target(struct cpufreq_policy *policy, 198bb0a56ecSDave Jones unsigned int target_freq, 199bb0a56ecSDave Jones unsigned int relation) 200bb0a56ecSDave Jones { 201bb0a56ecSDave Jones struct pcc_cpu *pcc_cpu_data; 202bb0a56ecSDave Jones struct cpufreq_freqs freqs; 203bb0a56ecSDave Jones u16 status; 204bb0a56ecSDave Jones u32 input_buffer; 205bb0a56ecSDave Jones int cpu; 206bb0a56ecSDave Jones 207bb0a56ecSDave Jones cpu = policy->cpu; 208bb0a56ecSDave Jones pcc_cpu_data = per_cpu_ptr(pcc_cpu_info, cpu); 209bb0a56ecSDave Jones 210bb0a56ecSDave Jones pr_debug("target: CPU %d should go to target freq: %d " 211bb0a56ecSDave Jones "(virtual) input_offset is 0x%p\n", 212bb0a56ecSDave Jones cpu, target_freq, 213bb0a56ecSDave Jones (pcch_virt_addr + pcc_cpu_data->input_offset)); 214bb0a56ecSDave Jones 215ab1b1c4eSViresh Kumar freqs.old = policy->cur; 216bb0a56ecSDave Jones freqs.new = target_freq; 2178fec051eSViresh Kumar cpufreq_freq_transition_begin(policy, &freqs); 218e65b5ddbSRafael J. Wysocki spin_lock(&pcc_lock); 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); 232ab1b1c4eSViresh Kumar iowrite16(0, &pcch_hdr->status); 233ab1b1c4eSViresh Kumar 2348fec051eSViresh Kumar cpufreq_freq_transition_end(policy, &freqs, status != CMD_COMPLETE); 235ab1b1c4eSViresh Kumar spin_unlock(&pcc_lock); 236ab1b1c4eSViresh Kumar 237bb0a56ecSDave Jones if (status != CMD_COMPLETE) { 238bb0a56ecSDave Jones pr_debug("target: FAILED for cpu %d, with status: 0x%x\n", 239bb0a56ecSDave Jones cpu, status); 240ab1b1c4eSViresh Kumar return -EINVAL; 241bb0a56ecSDave Jones } 242bb0a56ecSDave Jones 243bb0a56ecSDave Jones pr_debug("target: was SUCCESSFUL for cpu %d\n", cpu); 244bb0a56ecSDave Jones 245bb0a56ecSDave Jones return 0; 246bb0a56ecSDave Jones } 247bb0a56ecSDave Jones 248bb0a56ecSDave Jones static int pcc_get_offset(int cpu) 249bb0a56ecSDave Jones { 250bb0a56ecSDave Jones acpi_status status; 251bb0a56ecSDave Jones struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; 252bb0a56ecSDave Jones union acpi_object *pccp, *offset; 253bb0a56ecSDave Jones struct pcc_cpu *pcc_cpu_data; 254bb0a56ecSDave Jones struct acpi_processor *pr; 255bb0a56ecSDave Jones int ret = 0; 256bb0a56ecSDave Jones 257bb0a56ecSDave Jones pr = per_cpu(processors, cpu); 258bb0a56ecSDave Jones pcc_cpu_data = per_cpu_ptr(pcc_cpu_info, cpu); 259bb0a56ecSDave Jones 260e71f5cc4SNaga Chumbalkar if (!pr) 261e71f5cc4SNaga Chumbalkar return -ENODEV; 262e71f5cc4SNaga Chumbalkar 263bb0a56ecSDave Jones status = acpi_evaluate_object(pr->handle, "PCCP", NULL, &buffer); 264bb0a56ecSDave Jones if (ACPI_FAILURE(status)) 265bb0a56ecSDave Jones return -ENODEV; 266bb0a56ecSDave Jones 267bb0a56ecSDave Jones pccp = buffer.pointer; 268bb0a56ecSDave Jones if (!pccp || pccp->type != ACPI_TYPE_PACKAGE) { 269bb0a56ecSDave Jones ret = -ENODEV; 270bb0a56ecSDave Jones goto out_free; 271bb0a56ecSDave Jones }; 272bb0a56ecSDave Jones 273bb0a56ecSDave Jones offset = &(pccp->package.elements[0]); 274bb0a56ecSDave Jones if (!offset || offset->type != ACPI_TYPE_INTEGER) { 275bb0a56ecSDave Jones ret = -ENODEV; 276bb0a56ecSDave Jones goto out_free; 277bb0a56ecSDave Jones } 278bb0a56ecSDave Jones 279bb0a56ecSDave Jones pcc_cpu_data->input_offset = offset->integer.value; 280bb0a56ecSDave Jones 281bb0a56ecSDave Jones offset = &(pccp->package.elements[1]); 282bb0a56ecSDave Jones if (!offset || offset->type != ACPI_TYPE_INTEGER) { 283bb0a56ecSDave Jones ret = -ENODEV; 284bb0a56ecSDave Jones goto out_free; 285bb0a56ecSDave Jones } 286bb0a56ecSDave Jones 287bb0a56ecSDave Jones pcc_cpu_data->output_offset = offset->integer.value; 288bb0a56ecSDave Jones 289bb0a56ecSDave Jones memset_io((pcch_virt_addr + pcc_cpu_data->input_offset), 0, BUF_SZ); 290bb0a56ecSDave Jones memset_io((pcch_virt_addr + pcc_cpu_data->output_offset), 0, BUF_SZ); 291bb0a56ecSDave Jones 292bb0a56ecSDave Jones pr_debug("pcc_get_offset: for CPU %d: pcc_cpu_data " 293bb0a56ecSDave Jones "input_offset: 0x%x, pcc_cpu_data output_offset: 0x%x\n", 294bb0a56ecSDave Jones cpu, pcc_cpu_data->input_offset, pcc_cpu_data->output_offset); 295bb0a56ecSDave Jones out_free: 296bb0a56ecSDave Jones kfree(buffer.pointer); 297bb0a56ecSDave Jones return ret; 298bb0a56ecSDave Jones } 299bb0a56ecSDave Jones 300bb0a56ecSDave Jones static int __init pcc_cpufreq_do_osc(acpi_handle *handle) 301bb0a56ecSDave Jones { 302bb0a56ecSDave Jones acpi_status status; 303bb0a56ecSDave Jones struct acpi_object_list input; 304bb0a56ecSDave Jones struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL}; 305bb0a56ecSDave Jones union acpi_object in_params[4]; 306bb0a56ecSDave Jones union acpi_object *out_obj; 307bb0a56ecSDave Jones u32 capabilities[2]; 308bb0a56ecSDave Jones u32 errors; 309bb0a56ecSDave Jones u32 supported; 310bb0a56ecSDave Jones int ret = 0; 311bb0a56ecSDave Jones 312bb0a56ecSDave Jones input.count = 4; 313bb0a56ecSDave Jones input.pointer = in_params; 314bb0a56ecSDave Jones in_params[0].type = ACPI_TYPE_BUFFER; 315bb0a56ecSDave Jones in_params[0].buffer.length = 16; 316bb0a56ecSDave Jones in_params[0].buffer.pointer = OSC_UUID; 317bb0a56ecSDave Jones in_params[1].type = ACPI_TYPE_INTEGER; 318bb0a56ecSDave Jones in_params[1].integer.value = 1; 319bb0a56ecSDave Jones in_params[2].type = ACPI_TYPE_INTEGER; 320bb0a56ecSDave Jones in_params[2].integer.value = 2; 321bb0a56ecSDave Jones in_params[3].type = ACPI_TYPE_BUFFER; 322bb0a56ecSDave Jones in_params[3].buffer.length = 8; 323bb0a56ecSDave Jones in_params[3].buffer.pointer = (u8 *)&capabilities; 324bb0a56ecSDave Jones 325bb0a56ecSDave Jones capabilities[0] = OSC_QUERY_ENABLE; 326bb0a56ecSDave Jones capabilities[1] = 0x1; 327bb0a56ecSDave Jones 328bb0a56ecSDave Jones status = acpi_evaluate_object(*handle, "_OSC", &input, &output); 329bb0a56ecSDave Jones if (ACPI_FAILURE(status)) 330bb0a56ecSDave Jones return -ENODEV; 331bb0a56ecSDave Jones 332bb0a56ecSDave Jones if (!output.length) 333bb0a56ecSDave Jones return -ENODEV; 334bb0a56ecSDave Jones 335bb0a56ecSDave Jones out_obj = output.pointer; 336bb0a56ecSDave Jones if (out_obj->type != ACPI_TYPE_BUFFER) { 337bb0a56ecSDave Jones ret = -ENODEV; 338bb0a56ecSDave Jones goto out_free; 339bb0a56ecSDave Jones } 340bb0a56ecSDave Jones 341bb0a56ecSDave Jones errors = *((u32 *)out_obj->buffer.pointer) & ~(1 << 0); 342bb0a56ecSDave Jones if (errors) { 343bb0a56ecSDave Jones ret = -ENODEV; 344bb0a56ecSDave Jones goto out_free; 345bb0a56ecSDave Jones } 346bb0a56ecSDave Jones 347bb0a56ecSDave Jones supported = *((u32 *)(out_obj->buffer.pointer + 4)); 348bb0a56ecSDave Jones if (!(supported & 0x1)) { 349bb0a56ecSDave Jones ret = -ENODEV; 350bb0a56ecSDave Jones goto out_free; 351bb0a56ecSDave Jones } 352bb0a56ecSDave Jones 353bb0a56ecSDave Jones kfree(output.pointer); 354bb0a56ecSDave Jones capabilities[0] = 0x0; 355bb0a56ecSDave Jones capabilities[1] = 0x1; 356bb0a56ecSDave Jones 357bb0a56ecSDave Jones status = acpi_evaluate_object(*handle, "_OSC", &input, &output); 358bb0a56ecSDave Jones if (ACPI_FAILURE(status)) 359bb0a56ecSDave Jones return -ENODEV; 360bb0a56ecSDave Jones 361bb0a56ecSDave Jones if (!output.length) 362bb0a56ecSDave Jones return -ENODEV; 363bb0a56ecSDave Jones 364bb0a56ecSDave Jones out_obj = output.pointer; 365bb0a56ecSDave Jones if (out_obj->type != ACPI_TYPE_BUFFER) { 366bb0a56ecSDave Jones ret = -ENODEV; 367bb0a56ecSDave Jones goto out_free; 368bb0a56ecSDave Jones } 369bb0a56ecSDave Jones 370bb0a56ecSDave Jones errors = *((u32 *)out_obj->buffer.pointer) & ~(1 << 0); 371bb0a56ecSDave Jones if (errors) { 372bb0a56ecSDave Jones ret = -ENODEV; 373bb0a56ecSDave Jones goto out_free; 374bb0a56ecSDave Jones } 375bb0a56ecSDave Jones 376bb0a56ecSDave Jones supported = *((u32 *)(out_obj->buffer.pointer + 4)); 377bb0a56ecSDave Jones if (!(supported & 0x1)) { 378bb0a56ecSDave Jones ret = -ENODEV; 379bb0a56ecSDave Jones goto out_free; 380bb0a56ecSDave Jones } 381bb0a56ecSDave Jones 382bb0a56ecSDave Jones out_free: 383bb0a56ecSDave Jones kfree(output.pointer); 384bb0a56ecSDave Jones return ret; 385bb0a56ecSDave Jones } 386bb0a56ecSDave Jones 387bb0a56ecSDave Jones static int __init pcc_cpufreq_probe(void) 388bb0a56ecSDave Jones { 389bb0a56ecSDave Jones acpi_status status; 390bb0a56ecSDave Jones struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL}; 391bb0a56ecSDave Jones struct pcc_memory_resource *mem_resource; 392bb0a56ecSDave Jones struct pcc_register_resource *reg_resource; 393bb0a56ecSDave Jones union acpi_object *out_obj, *member; 3947ca9b574SZhang Rui acpi_handle handle, osc_handle; 395bb0a56ecSDave Jones int ret = 0; 396bb0a56ecSDave Jones 397bb0a56ecSDave Jones status = acpi_get_handle(NULL, "\\_SB", &handle); 398bb0a56ecSDave Jones if (ACPI_FAILURE(status)) 399bb0a56ecSDave Jones return -ENODEV; 400bb0a56ecSDave Jones 4017ca9b574SZhang Rui if (!acpi_has_method(handle, "PCCH")) 402bb0a56ecSDave Jones return -ENODEV; 403bb0a56ecSDave Jones 404bb0a56ecSDave Jones status = acpi_get_handle(handle, "_OSC", &osc_handle); 405bb0a56ecSDave Jones if (ACPI_SUCCESS(status)) { 406bb0a56ecSDave Jones ret = pcc_cpufreq_do_osc(&osc_handle); 407bb0a56ecSDave Jones if (ret) 408bb0a56ecSDave Jones pr_debug("probe: _OSC evaluation did not succeed\n"); 409bb0a56ecSDave Jones /* Firmware's use of _OSC is optional */ 410bb0a56ecSDave Jones ret = 0; 411bb0a56ecSDave Jones } 412bb0a56ecSDave Jones 413bb0a56ecSDave Jones status = acpi_evaluate_object(handle, "PCCH", NULL, &output); 414bb0a56ecSDave Jones if (ACPI_FAILURE(status)) 415bb0a56ecSDave Jones return -ENODEV; 416bb0a56ecSDave Jones 417bb0a56ecSDave Jones out_obj = output.pointer; 418bb0a56ecSDave Jones if (out_obj->type != ACPI_TYPE_PACKAGE) { 419bb0a56ecSDave Jones ret = -ENODEV; 420bb0a56ecSDave Jones goto out_free; 421bb0a56ecSDave Jones } 422bb0a56ecSDave Jones 423bb0a56ecSDave Jones member = &out_obj->package.elements[0]; 424bb0a56ecSDave Jones if (member->type != ACPI_TYPE_BUFFER) { 425bb0a56ecSDave Jones ret = -ENODEV; 426bb0a56ecSDave Jones goto out_free; 427bb0a56ecSDave Jones } 428bb0a56ecSDave Jones 429bb0a56ecSDave Jones mem_resource = (struct pcc_memory_resource *)member->buffer.pointer; 430bb0a56ecSDave Jones 431bb0a56ecSDave Jones pr_debug("probe: mem_resource descriptor: 0x%x," 432bb0a56ecSDave Jones " length: %d, space_id: %d, resource_usage: %d," 433bb0a56ecSDave Jones " type_specific: %d, granularity: 0x%llx," 434bb0a56ecSDave Jones " minimum: 0x%llx, maximum: 0x%llx," 435bb0a56ecSDave Jones " translation_offset: 0x%llx, address_length: 0x%llx\n", 436bb0a56ecSDave Jones mem_resource->descriptor, mem_resource->length, 437bb0a56ecSDave Jones mem_resource->space_id, mem_resource->resource_usage, 438bb0a56ecSDave Jones mem_resource->type_specific, mem_resource->granularity, 439bb0a56ecSDave Jones mem_resource->minimum, mem_resource->maximum, 440bb0a56ecSDave Jones mem_resource->translation_offset, 441bb0a56ecSDave Jones mem_resource->address_length); 442bb0a56ecSDave Jones 443bb0a56ecSDave Jones if (mem_resource->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) { 444bb0a56ecSDave Jones ret = -ENODEV; 445bb0a56ecSDave Jones goto out_free; 446bb0a56ecSDave Jones } 447bb0a56ecSDave Jones 448bb0a56ecSDave Jones pcch_virt_addr = ioremap_nocache(mem_resource->minimum, 449bb0a56ecSDave Jones mem_resource->address_length); 450bb0a56ecSDave Jones if (pcch_virt_addr == NULL) { 451bb0a56ecSDave Jones pr_debug("probe: could not map shared mem region\n"); 452d06a8a4fSJulia Lawall ret = -ENOMEM; 453bb0a56ecSDave Jones goto out_free; 454bb0a56ecSDave Jones } 455bb0a56ecSDave Jones pcch_hdr = pcch_virt_addr; 456bb0a56ecSDave Jones 457bb0a56ecSDave Jones pr_debug("probe: PCCH header (virtual) addr: 0x%p\n", pcch_hdr); 458bb0a56ecSDave Jones pr_debug("probe: PCCH header is at physical address: 0x%llx," 459bb0a56ecSDave Jones " signature: 0x%x, length: %d bytes, major: %d, minor: %d," 460bb0a56ecSDave Jones " supported features: 0x%x, command field: 0x%x," 461bb0a56ecSDave Jones " status field: 0x%x, nominal latency: %d us\n", 462bb0a56ecSDave Jones mem_resource->minimum, ioread32(&pcch_hdr->signature), 463bb0a56ecSDave Jones ioread16(&pcch_hdr->length), ioread8(&pcch_hdr->major), 464bb0a56ecSDave Jones ioread8(&pcch_hdr->minor), ioread32(&pcch_hdr->features), 465bb0a56ecSDave Jones ioread16(&pcch_hdr->command), ioread16(&pcch_hdr->status), 466bb0a56ecSDave Jones ioread32(&pcch_hdr->latency)); 467bb0a56ecSDave Jones 468bb0a56ecSDave Jones pr_debug("probe: min time between commands: %d us," 469bb0a56ecSDave Jones " max time between commands: %d us," 470bb0a56ecSDave Jones " nominal CPU frequency: %d MHz," 471bb0a56ecSDave Jones " minimum CPU frequency: %d MHz," 472bb0a56ecSDave Jones " minimum CPU frequency without throttling: %d MHz\n", 473bb0a56ecSDave Jones ioread32(&pcch_hdr->minimum_time), 474bb0a56ecSDave Jones ioread32(&pcch_hdr->maximum_time), 475bb0a56ecSDave Jones ioread32(&pcch_hdr->nominal), 476bb0a56ecSDave Jones ioread32(&pcch_hdr->throttled_frequency), 477bb0a56ecSDave Jones ioread32(&pcch_hdr->minimum_frequency)); 478bb0a56ecSDave Jones 479bb0a56ecSDave Jones member = &out_obj->package.elements[1]; 480bb0a56ecSDave Jones if (member->type != ACPI_TYPE_BUFFER) { 481bb0a56ecSDave Jones ret = -ENODEV; 482bb0a56ecSDave Jones goto pcch_free; 483bb0a56ecSDave Jones } 484bb0a56ecSDave Jones 485bb0a56ecSDave Jones reg_resource = (struct pcc_register_resource *)member->buffer.pointer; 486bb0a56ecSDave Jones 487bb0a56ecSDave Jones doorbell.space_id = reg_resource->space_id; 488bb0a56ecSDave Jones doorbell.bit_width = reg_resource->bit_width; 489bb0a56ecSDave Jones doorbell.bit_offset = reg_resource->bit_offset; 490bb0a56ecSDave Jones doorbell.access_width = 64; 491bb0a56ecSDave Jones doorbell.address = reg_resource->address; 492bb0a56ecSDave Jones 493bb0a56ecSDave Jones pr_debug("probe: doorbell: space_id is %d, bit_width is %d, " 494bb0a56ecSDave Jones "bit_offset is %d, access_width is %d, address is 0x%llx\n", 495bb0a56ecSDave Jones doorbell.space_id, doorbell.bit_width, doorbell.bit_offset, 496bb0a56ecSDave Jones doorbell.access_width, reg_resource->address); 497bb0a56ecSDave Jones 498bb0a56ecSDave Jones member = &out_obj->package.elements[2]; 499bb0a56ecSDave Jones if (member->type != ACPI_TYPE_INTEGER) { 500bb0a56ecSDave Jones ret = -ENODEV; 501bb0a56ecSDave Jones goto pcch_free; 502bb0a56ecSDave Jones } 503bb0a56ecSDave Jones 504bb0a56ecSDave Jones doorbell_preserve = member->integer.value; 505bb0a56ecSDave Jones 506bb0a56ecSDave Jones member = &out_obj->package.elements[3]; 507bb0a56ecSDave Jones if (member->type != ACPI_TYPE_INTEGER) { 508bb0a56ecSDave Jones ret = -ENODEV; 509bb0a56ecSDave Jones goto pcch_free; 510bb0a56ecSDave Jones } 511bb0a56ecSDave Jones 512bb0a56ecSDave Jones doorbell_write = member->integer.value; 513bb0a56ecSDave Jones 514bb0a56ecSDave Jones pr_debug("probe: doorbell_preserve: 0x%llx," 515bb0a56ecSDave Jones " doorbell_write: 0x%llx\n", 516bb0a56ecSDave Jones doorbell_preserve, doorbell_write); 517bb0a56ecSDave Jones 518bb0a56ecSDave Jones pcc_cpu_info = alloc_percpu(struct pcc_cpu); 519bb0a56ecSDave Jones if (!pcc_cpu_info) { 520bb0a56ecSDave Jones ret = -ENOMEM; 521bb0a56ecSDave Jones goto pcch_free; 522bb0a56ecSDave Jones } 523bb0a56ecSDave Jones 524bb0a56ecSDave Jones printk(KERN_DEBUG "pcc-cpufreq: (v%s) driver loaded with frequency" 525bb0a56ecSDave Jones " limits: %d MHz, %d MHz\n", PCC_VERSION, 526bb0a56ecSDave Jones ioread32(&pcch_hdr->minimum_frequency), 527bb0a56ecSDave Jones ioread32(&pcch_hdr->nominal)); 528bb0a56ecSDave Jones kfree(output.pointer); 529bb0a56ecSDave Jones return ret; 530bb0a56ecSDave Jones pcch_free: 531bb0a56ecSDave Jones pcc_clear_mapping(); 532bb0a56ecSDave Jones out_free: 533bb0a56ecSDave Jones kfree(output.pointer); 534bb0a56ecSDave Jones return ret; 535bb0a56ecSDave Jones } 536bb0a56ecSDave Jones 537bb0a56ecSDave Jones static int pcc_cpufreq_cpu_init(struct cpufreq_policy *policy) 538bb0a56ecSDave Jones { 539bb0a56ecSDave Jones unsigned int cpu = policy->cpu; 540bb0a56ecSDave Jones unsigned int result = 0; 541bb0a56ecSDave Jones 542bb0a56ecSDave Jones if (!pcch_virt_addr) { 543bb0a56ecSDave Jones result = -1; 544bb0a56ecSDave Jones goto out; 545bb0a56ecSDave Jones } 546bb0a56ecSDave Jones 547bb0a56ecSDave Jones result = pcc_get_offset(cpu); 548bb0a56ecSDave Jones if (result) { 549bb0a56ecSDave Jones pr_debug("init: PCCP evaluation failed\n"); 550bb0a56ecSDave Jones goto out; 551bb0a56ecSDave Jones } 552bb0a56ecSDave Jones 553bb0a56ecSDave Jones policy->max = policy->cpuinfo.max_freq = 554bb0a56ecSDave Jones ioread32(&pcch_hdr->nominal) * 1000; 555bb0a56ecSDave Jones policy->min = policy->cpuinfo.min_freq = 556bb0a56ecSDave Jones ioread32(&pcch_hdr->minimum_frequency) * 1000; 557bb0a56ecSDave Jones 558bb0a56ecSDave Jones pr_debug("init: policy->max is %d, policy->min is %d\n", 559bb0a56ecSDave Jones policy->max, policy->min); 560bb0a56ecSDave Jones out: 561bb0a56ecSDave Jones return result; 562bb0a56ecSDave Jones } 563bb0a56ecSDave Jones 564bb0a56ecSDave Jones static int pcc_cpufreq_cpu_exit(struct cpufreq_policy *policy) 565bb0a56ecSDave Jones { 566bb0a56ecSDave Jones return 0; 567bb0a56ecSDave Jones } 568bb0a56ecSDave Jones 569bb0a56ecSDave Jones static struct cpufreq_driver pcc_cpufreq_driver = { 570bb0a56ecSDave Jones .flags = CPUFREQ_CONST_LOOPS, 571bb0a56ecSDave Jones .get = pcc_get_freq, 572bb0a56ecSDave Jones .verify = pcc_cpufreq_verify, 573bb0a56ecSDave Jones .target = pcc_cpufreq_target, 574bb0a56ecSDave Jones .init = pcc_cpufreq_cpu_init, 575bb0a56ecSDave Jones .exit = pcc_cpufreq_cpu_exit, 576bb0a56ecSDave Jones .name = "pcc-cpufreq", 577bb0a56ecSDave Jones }; 578bb0a56ecSDave Jones 579bb0a56ecSDave Jones static int __init pcc_cpufreq_init(void) 580bb0a56ecSDave Jones { 581bb0a56ecSDave Jones int ret; 582bb0a56ecSDave Jones 583bb0a56ecSDave Jones if (acpi_disabled) 584bb0a56ecSDave Jones return 0; 585bb0a56ecSDave Jones 586bb0a56ecSDave Jones ret = pcc_cpufreq_probe(); 587bb0a56ecSDave Jones if (ret) { 588bb0a56ecSDave Jones pr_debug("pcc_cpufreq_init: PCCH evaluation failed\n"); 589bb0a56ecSDave Jones return ret; 590bb0a56ecSDave Jones } 591bb0a56ecSDave Jones 592bb0a56ecSDave Jones ret = cpufreq_register_driver(&pcc_cpufreq_driver); 593bb0a56ecSDave Jones 594bb0a56ecSDave Jones return ret; 595bb0a56ecSDave Jones } 596bb0a56ecSDave Jones 597bb0a56ecSDave Jones static void __exit pcc_cpufreq_exit(void) 598bb0a56ecSDave Jones { 599bb0a56ecSDave Jones cpufreq_unregister_driver(&pcc_cpufreq_driver); 600bb0a56ecSDave Jones 601bb0a56ecSDave Jones pcc_clear_mapping(); 602bb0a56ecSDave Jones 603bb0a56ecSDave Jones free_percpu(pcc_cpu_info); 604bb0a56ecSDave Jones } 605bb0a56ecSDave Jones 606bb0a56ecSDave Jones MODULE_AUTHOR("Matthew Garrett, Naga Chumbalkar"); 607bb0a56ecSDave Jones MODULE_VERSION(PCC_VERSION); 608bb0a56ecSDave Jones MODULE_DESCRIPTION("Processor Clocking Control interface driver"); 609bb0a56ecSDave Jones MODULE_LICENSE("GPL"); 610bb0a56ecSDave Jones 611bb0a56ecSDave Jones late_initcall(pcc_cpufreq_init); 612bb0a56ecSDave Jones module_exit(pcc_cpufreq_exit); 613