10f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar/* 20f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar * pcc-cpufreq.c - Processor Clocking Control firmware cpufreq interface 30f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar * 40f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar * Copyright (C) 2009 Red Hat, Matthew Garrett <mjg@redhat.com> 50f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar * Copyright (C) 2009 Hewlett-Packard Development Company, L.P. 60f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar * Nagananda Chumbalkar <nagananda.chumbalkar@hp.com> 70f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar * 80f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 90f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar * 100f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar * This program is free software; you can redistribute it and/or modify 110f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar * it under the terms of the GNU General Public License as published by 120f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar * the Free Software Foundation; version 2 of the License. 130f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar * 140f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar * This program is distributed in the hope that it will be useful, but 150f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar * WITHOUT ANY WARRANTY; without even the implied warranty of 160f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or NON 170f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar * INFRINGEMENT. See the GNU General Public License for more details. 180f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar * 190f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar * You should have received a copy of the GNU General Public License along 200f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar * with this program; if not, write to the Free Software Foundation, Inc., 210f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar * 675 Mass Ave, Cambridge, MA 02139, USA. 220f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar * 230f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 240f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar */ 250f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 260f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar#include <linux/kernel.h> 270f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar#include <linux/module.h> 280f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar#include <linux/init.h> 290f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar#include <linux/smp.h> 300f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar#include <linux/sched.h> 310f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar#include <linux/cpufreq.h> 320f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar#include <linux/compiler.h> 335a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 340f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 350f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar#include <linux/acpi.h> 360f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar#include <linux/io.h> 370f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar#include <linux/spinlock.h> 380f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar#include <linux/uaccess.h> 390f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 400f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar#include <acpi/processor.h> 410f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 42904cc1e637a00dba1b58e7752f485f90ebf2a568Naga Chumbalkar#define PCC_VERSION "1.10.00" 430f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar#define POLL_LOOPS 300 440f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 450f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar#define CMD_COMPLETE 0x1 460f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar#define CMD_GET_FREQ 0x0 470f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar#define CMD_SET_FREQ 0x1 480f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 490f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar#define BUF_SZ 4 500f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 510f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkarstruct pcc_register_resource { 520f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar u8 descriptor; 530f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar u16 length; 540f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar u8 space_id; 550f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar u8 bit_width; 560f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar u8 bit_offset; 570f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar u8 access_size; 580f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar u64 address; 590f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar} __attribute__ ((packed)); 600f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 610f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkarstruct pcc_memory_resource { 620f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar u8 descriptor; 630f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar u16 length; 640f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar u8 space_id; 650f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar u8 resource_usage; 660f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar u8 type_specific; 670f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar u64 granularity; 680f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar u64 minimum; 690f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar u64 maximum; 700f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar u64 translation_offset; 710f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar u64 address_length; 720f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar} __attribute__ ((packed)); 730f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 740f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkarstatic struct cpufreq_driver pcc_cpufreq_driver; 750f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 760f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkarstruct pcc_header { 770f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar u32 signature; 780f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar u16 length; 790f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar u8 major; 800f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar u8 minor; 810f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar u32 features; 820f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar u16 command; 830f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar u16 status; 840f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar u32 latency; 850f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar u32 minimum_time; 860f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar u32 maximum_time; 870f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar u32 nominal; 880f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar u32 throttled_frequency; 890f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar u32 minimum_frequency; 900f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar}; 910f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 920f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkarstatic void __iomem *pcch_virt_addr; 930f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkarstatic struct pcc_header __iomem *pcch_hdr; 940f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 950f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkarstatic DEFINE_SPINLOCK(pcc_lock); 960f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 970f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkarstatic struct acpi_generic_address doorbell; 980f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 990f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkarstatic u64 doorbell_preserve; 1000f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkarstatic u64 doorbell_write; 1010f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 102904cc1e637a00dba1b58e7752f485f90ebf2a568Naga Chumbalkarstatic u8 OSC_UUID[16] = {0x9F, 0x2C, 0x9B, 0x63, 0x91, 0x70, 0x1f, 0x49, 1030f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 0xBB, 0x4F, 0xA5, 0x98, 0x2F, 0xA1, 0xB5, 0x46}; 1040f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 1050f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkarstruct pcc_cpu { 1060f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar u32 input_offset; 1070f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar u32 output_offset; 1080f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar}; 1090f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 110a3da323420d5aa6f7bd15efc7bf34cd6d19e1f1aNamhyung Kimstatic struct pcc_cpu __percpu *pcc_cpu_info; 1110f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 1120f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkarstatic int pcc_cpufreq_verify(struct cpufreq_policy *policy) 1130f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar{ 1140f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, 1150f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar policy->cpuinfo.max_freq); 1160f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar return 0; 1170f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar} 1180f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 1190f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkarstatic inline void pcc_cmd(void) 1200f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar{ 1210f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar u64 doorbell_value; 1220f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar int i; 1230f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 1240f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar acpi_read(&doorbell_value, &doorbell); 1250f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar acpi_write((doorbell_value & doorbell_preserve) | doorbell_write, 1260f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar &doorbell); 1270f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 1280f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar for (i = 0; i < POLL_LOOPS; i++) { 1290f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar if (ioread16(&pcch_hdr->status) & CMD_COMPLETE) 1300f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar break; 1310f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar } 1320f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar} 1330f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 1340f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkarstatic inline void pcc_clear_mapping(void) 1350f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar{ 1360f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar if (pcch_virt_addr) 1370f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar iounmap(pcch_virt_addr); 1380f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar pcch_virt_addr = NULL; 1390f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar} 1400f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 1410f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkarstatic unsigned int pcc_get_freq(unsigned int cpu) 1420f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar{ 1430f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar struct pcc_cpu *pcc_cpu_data; 1440f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar unsigned int curr_freq; 1450f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar unsigned int freq_limit; 1460f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar u16 status; 1470f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar u32 input_buffer; 1480f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar u32 output_buffer; 1490f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 1500f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar spin_lock(&pcc_lock); 1510f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 1522d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski pr_debug("get: get_freq for CPU %d\n", cpu); 1530f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar pcc_cpu_data = per_cpu_ptr(pcc_cpu_info, cpu); 1540f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 1550f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar input_buffer = 0x1; 1560f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar iowrite32(input_buffer, 1570f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar (pcch_virt_addr + pcc_cpu_data->input_offset)); 1580f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar iowrite16(CMD_GET_FREQ, &pcch_hdr->command); 1590f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 1600f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar pcc_cmd(); 1610f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 1620f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar output_buffer = 1630f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar ioread32(pcch_virt_addr + pcc_cpu_data->output_offset); 1640f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 1650f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar /* Clear the input buffer - we are done with the current command */ 1660f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar memset_io((pcch_virt_addr + pcc_cpu_data->input_offset), 0, BUF_SZ); 1670f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 1680f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar status = ioread16(&pcch_hdr->status); 1690f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar if (status != CMD_COMPLETE) { 1702d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski pr_debug("get: FAILED: for CPU %d, status is %d\n", 1710f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar cpu, status); 1720f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar goto cmd_incomplete; 1730f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar } 1740f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar iowrite16(0, &pcch_hdr->status); 1750f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar curr_freq = (((ioread32(&pcch_hdr->nominal) * (output_buffer & 0xff)) 1760f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar / 100) * 1000); 1770f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 1782d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski pr_debug("get: SUCCESS: (virtual) output_offset for cpu %d is " 1792d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski "0x%p, contains a value of: 0x%x. Speed is: %d MHz\n", 1800f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar cpu, (pcch_virt_addr + pcc_cpu_data->output_offset), 1810f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar output_buffer, curr_freq); 1820f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 1830f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar freq_limit = (output_buffer >> 8) & 0xff; 1840f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar if (freq_limit != 0xff) { 1852d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski pr_debug("get: frequency for cpu %d is being temporarily" 1860f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar " capped at %d\n", cpu, curr_freq); 1870f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar } 1880f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 1890f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar spin_unlock(&pcc_lock); 1900f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar return curr_freq; 1910f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 1920f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkarcmd_incomplete: 1930f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar iowrite16(0, &pcch_hdr->status); 1940f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar spin_unlock(&pcc_lock); 1951f858ef2fbabdc5e645644010a31a40c32e397c9Naga Chumbalkar return 0; 1960f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar} 1970f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 1980f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkarstatic int pcc_cpufreq_target(struct cpufreq_policy *policy, 1990f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar unsigned int target_freq, 2000f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar unsigned int relation) 2010f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar{ 2020f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar struct pcc_cpu *pcc_cpu_data; 2030f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar struct cpufreq_freqs freqs; 2040f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar u16 status; 2050f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar u32 input_buffer; 2060f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar int cpu; 2070f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 2080f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar spin_lock(&pcc_lock); 2090f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar cpu = policy->cpu; 2100f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar pcc_cpu_data = per_cpu_ptr(pcc_cpu_info, cpu); 2110f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 2122d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski pr_debug("target: CPU %d should go to target freq: %d " 2132d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski "(virtual) input_offset is 0x%p\n", 2140f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar cpu, target_freq, 2150f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar (pcch_virt_addr + pcc_cpu_data->input_offset)); 2160f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 2170f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar freqs.new = target_freq; 2180f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar freqs.cpu = cpu; 2190f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); 2200f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 2210f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar input_buffer = 0x1 | (((target_freq * 100) 2220f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar / (ioread32(&pcch_hdr->nominal) * 1000)) << 8); 2230f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar iowrite32(input_buffer, 2240f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar (pcch_virt_addr + pcc_cpu_data->input_offset)); 2250f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar iowrite16(CMD_SET_FREQ, &pcch_hdr->command); 2260f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 2270f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar pcc_cmd(); 2280f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 2290f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar /* Clear the input buffer - we are done with the current command */ 2300f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar memset_io((pcch_virt_addr + pcc_cpu_data->input_offset), 0, BUF_SZ); 2310f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 2320f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar status = ioread16(&pcch_hdr->status); 2330f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar if (status != CMD_COMPLETE) { 2342d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski pr_debug("target: FAILED for cpu %d, with status: 0x%x\n", 2350f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar cpu, status); 2360f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar goto cmd_incomplete; 2370f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar } 2380f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar iowrite16(0, &pcch_hdr->status); 2390f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 2400f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); 2412d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski pr_debug("target: was SUCCESSFUL for cpu %d\n", cpu); 2420f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar spin_unlock(&pcc_lock); 2430f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 2440f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar return 0; 2450f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 2460f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkarcmd_incomplete: 2470f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar iowrite16(0, &pcch_hdr->status); 2480f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar spin_unlock(&pcc_lock); 2490f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar return -EINVAL; 2500f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar} 2510f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 2520f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkarstatic int pcc_get_offset(int cpu) 2530f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar{ 2540f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar acpi_status status; 2550f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; 2560f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar union acpi_object *pccp, *offset; 2570f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar struct pcc_cpu *pcc_cpu_data; 2580f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar struct acpi_processor *pr; 2590f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar int ret = 0; 2600f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 2610f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar pr = per_cpu(processors, cpu); 2620f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar pcc_cpu_data = per_cpu_ptr(pcc_cpu_info, cpu); 2630f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 264e71f5cc402ecb42b407ae52add7b173bf1c53daaNaga Chumbalkar if (!pr) 265e71f5cc402ecb42b407ae52add7b173bf1c53daaNaga Chumbalkar return -ENODEV; 266e71f5cc402ecb42b407ae52add7b173bf1c53daaNaga Chumbalkar 2670f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar status = acpi_evaluate_object(pr->handle, "PCCP", NULL, &buffer); 2680f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar if (ACPI_FAILURE(status)) 2690f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar return -ENODEV; 2700f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 2710f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar pccp = buffer.pointer; 2720f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar if (!pccp || pccp->type != ACPI_TYPE_PACKAGE) { 2730f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar ret = -ENODEV; 2740f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar goto out_free; 2750f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar }; 2760f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 2770f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar offset = &(pccp->package.elements[0]); 2780f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar if (!offset || offset->type != ACPI_TYPE_INTEGER) { 2790f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar ret = -ENODEV; 2800f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar goto out_free; 2810f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar } 2820f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 2830f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar pcc_cpu_data->input_offset = offset->integer.value; 2840f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 2850f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar offset = &(pccp->package.elements[1]); 2860f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar if (!offset || offset->type != ACPI_TYPE_INTEGER) { 2870f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar ret = -ENODEV; 2880f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar goto out_free; 2890f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar } 2900f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 2910f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar pcc_cpu_data->output_offset = offset->integer.value; 2920f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 2930f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar memset_io((pcch_virt_addr + pcc_cpu_data->input_offset), 0, BUF_SZ); 2940f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar memset_io((pcch_virt_addr + pcc_cpu_data->output_offset), 0, BUF_SZ); 2950f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 2962d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski pr_debug("pcc_get_offset: for CPU %d: pcc_cpu_data " 2970f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar "input_offset: 0x%x, pcc_cpu_data output_offset: 0x%x\n", 2980f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar cpu, pcc_cpu_data->input_offset, pcc_cpu_data->output_offset); 2990f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkarout_free: 3000f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar kfree(buffer.pointer); 3010f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar return ret; 3020f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar} 3030f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 3040f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkarstatic int __init pcc_cpufreq_do_osc(acpi_handle *handle) 3050f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar{ 3060f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar acpi_status status; 3070f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar struct acpi_object_list input; 3080f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL}; 3090f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar union acpi_object in_params[4]; 3100f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar union acpi_object *out_obj; 3110f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar u32 capabilities[2]; 3120f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar u32 errors; 3130f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar u32 supported; 3140f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar int ret = 0; 3150f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 3160f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar input.count = 4; 3170f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar input.pointer = in_params; 3180f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar in_params[0].type = ACPI_TYPE_BUFFER; 3190f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar in_params[0].buffer.length = 16; 3200f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar in_params[0].buffer.pointer = OSC_UUID; 3210f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar in_params[1].type = ACPI_TYPE_INTEGER; 3220f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar in_params[1].integer.value = 1; 3230f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar in_params[2].type = ACPI_TYPE_INTEGER; 3240f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar in_params[2].integer.value = 2; 3250f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar in_params[3].type = ACPI_TYPE_BUFFER; 3260f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar in_params[3].buffer.length = 8; 3270f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar in_params[3].buffer.pointer = (u8 *)&capabilities; 3280f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 3290f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar capabilities[0] = OSC_QUERY_ENABLE; 3300f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar capabilities[1] = 0x1; 3310f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 3320f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar status = acpi_evaluate_object(*handle, "_OSC", &input, &output); 3330f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar if (ACPI_FAILURE(status)) 3340f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar return -ENODEV; 3350f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 3360f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar if (!output.length) 3370f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar return -ENODEV; 3380f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 3390f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar out_obj = output.pointer; 3400f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar if (out_obj->type != ACPI_TYPE_BUFFER) { 3410f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar ret = -ENODEV; 3420f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar goto out_free; 3430f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar } 3440f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 3450f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar errors = *((u32 *)out_obj->buffer.pointer) & ~(1 << 0); 3460f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar if (errors) { 3470f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar ret = -ENODEV; 3480f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar goto out_free; 3490f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar } 3500f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 3510f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar supported = *((u32 *)(out_obj->buffer.pointer + 4)); 3520f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar if (!(supported & 0x1)) { 3530f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar ret = -ENODEV; 3540f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar goto out_free; 3550f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar } 3560f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 3570f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar kfree(output.pointer); 3580f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar capabilities[0] = 0x0; 3590f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar capabilities[1] = 0x1; 3600f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 3610f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar status = acpi_evaluate_object(*handle, "_OSC", &input, &output); 3620f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar if (ACPI_FAILURE(status)) 3630f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar return -ENODEV; 3640f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 3650f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar if (!output.length) 3660f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar return -ENODEV; 3670f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 3680f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar out_obj = output.pointer; 3693682930623f63c693845d9620c6bcdf5598c9bbbPekka Enberg if (out_obj->type != ACPI_TYPE_BUFFER) { 3703682930623f63c693845d9620c6bcdf5598c9bbbPekka Enberg ret = -ENODEV; 3713682930623f63c693845d9620c6bcdf5598c9bbbPekka Enberg goto out_free; 3723682930623f63c693845d9620c6bcdf5598c9bbbPekka Enberg } 3730f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 3740f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar errors = *((u32 *)out_obj->buffer.pointer) & ~(1 << 0); 3753682930623f63c693845d9620c6bcdf5598c9bbbPekka Enberg if (errors) { 3763682930623f63c693845d9620c6bcdf5598c9bbbPekka Enberg ret = -ENODEV; 3773682930623f63c693845d9620c6bcdf5598c9bbbPekka Enberg goto out_free; 3783682930623f63c693845d9620c6bcdf5598c9bbbPekka Enberg } 3790f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 3800f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar supported = *((u32 *)(out_obj->buffer.pointer + 4)); 3813682930623f63c693845d9620c6bcdf5598c9bbbPekka Enberg if (!(supported & 0x1)) { 3823682930623f63c693845d9620c6bcdf5598c9bbbPekka Enberg ret = -ENODEV; 3833682930623f63c693845d9620c6bcdf5598c9bbbPekka Enberg goto out_free; 3843682930623f63c693845d9620c6bcdf5598c9bbbPekka Enberg } 3850f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 3860f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkarout_free: 3870f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar kfree(output.pointer); 3880f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar return ret; 3890f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar} 3900f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 3910f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkarstatic int __init pcc_cpufreq_probe(void) 3920f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar{ 3930f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar acpi_status status; 3940f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL}; 3950f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar struct pcc_memory_resource *mem_resource; 3960f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar struct pcc_register_resource *reg_resource; 3970f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar union acpi_object *out_obj, *member; 39847f8bcf362410b631a4d99ff5c79ec6b9dd3ace6Matthew Garrett acpi_handle handle, osc_handle, pcch_handle; 3990f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar int ret = 0; 4000f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 4010f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar status = acpi_get_handle(NULL, "\\_SB", &handle); 4020f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar if (ACPI_FAILURE(status)) 4030f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar return -ENODEV; 4040f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 40547f8bcf362410b631a4d99ff5c79ec6b9dd3ace6Matthew Garrett status = acpi_get_handle(handle, "PCCH", &pcch_handle); 40647f8bcf362410b631a4d99ff5c79ec6b9dd3ace6Matthew Garrett if (ACPI_FAILURE(status)) 40747f8bcf362410b631a4d99ff5c79ec6b9dd3ace6Matthew Garrett return -ENODEV; 40847f8bcf362410b631a4d99ff5c79ec6b9dd3ace6Matthew Garrett 4090f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar status = acpi_get_handle(handle, "_OSC", &osc_handle); 4100f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar if (ACPI_SUCCESS(status)) { 4110f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar ret = pcc_cpufreq_do_osc(&osc_handle); 4120f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar if (ret) 4132d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski pr_debug("probe: _OSC evaluation did not succeed\n"); 4140f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar /* Firmware's use of _OSC is optional */ 4150f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar ret = 0; 4160f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar } 4170f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 4180f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar status = acpi_evaluate_object(handle, "PCCH", NULL, &output); 4190f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar if (ACPI_FAILURE(status)) 4200f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar return -ENODEV; 4210f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 4220f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar out_obj = output.pointer; 4230f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar if (out_obj->type != ACPI_TYPE_PACKAGE) { 4240f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar ret = -ENODEV; 4250f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar goto out_free; 4260f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar } 4270f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 4280f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar member = &out_obj->package.elements[0]; 4290f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar if (member->type != ACPI_TYPE_BUFFER) { 4300f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar ret = -ENODEV; 4310f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar goto out_free; 4320f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar } 4330f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 4340f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar mem_resource = (struct pcc_memory_resource *)member->buffer.pointer; 4350f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 4362d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski pr_debug("probe: mem_resource descriptor: 0x%x," 4370f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar " length: %d, space_id: %d, resource_usage: %d," 4380f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar " type_specific: %d, granularity: 0x%llx," 4390f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar " minimum: 0x%llx, maximum: 0x%llx," 4400f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar " translation_offset: 0x%llx, address_length: 0x%llx\n", 4410f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar mem_resource->descriptor, mem_resource->length, 4420f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar mem_resource->space_id, mem_resource->resource_usage, 4430f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar mem_resource->type_specific, mem_resource->granularity, 4440f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar mem_resource->minimum, mem_resource->maximum, 4450f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar mem_resource->translation_offset, 4460f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar mem_resource->address_length); 4470f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 4480f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar if (mem_resource->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) { 4490f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar ret = -ENODEV; 4500f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar goto out_free; 4510f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar } 4520f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 4530f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar pcch_virt_addr = ioremap_nocache(mem_resource->minimum, 4540f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar mem_resource->address_length); 4550f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar if (pcch_virt_addr == NULL) { 4562d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski pr_debug("probe: could not map shared mem region\n"); 4570f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar goto out_free; 4580f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar } 4590f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar pcch_hdr = pcch_virt_addr; 4600f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 4612d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski pr_debug("probe: PCCH header (virtual) addr: 0x%p\n", pcch_hdr); 4622d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski pr_debug("probe: PCCH header is at physical address: 0x%llx," 4630f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar " signature: 0x%x, length: %d bytes, major: %d, minor: %d," 4640f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar " supported features: 0x%x, command field: 0x%x," 4650f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar " status field: 0x%x, nominal latency: %d us\n", 4660f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar mem_resource->minimum, ioread32(&pcch_hdr->signature), 4670f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar ioread16(&pcch_hdr->length), ioread8(&pcch_hdr->major), 4680f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar ioread8(&pcch_hdr->minor), ioread32(&pcch_hdr->features), 4690f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar ioread16(&pcch_hdr->command), ioread16(&pcch_hdr->status), 4700f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar ioread32(&pcch_hdr->latency)); 4710f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 4722d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski pr_debug("probe: min time between commands: %d us," 4730f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar " max time between commands: %d us," 4740f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar " nominal CPU frequency: %d MHz," 4750f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar " minimum CPU frequency: %d MHz," 4760f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar " minimum CPU frequency without throttling: %d MHz\n", 4770f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar ioread32(&pcch_hdr->minimum_time), 4780f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar ioread32(&pcch_hdr->maximum_time), 4790f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar ioread32(&pcch_hdr->nominal), 4800f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar ioread32(&pcch_hdr->throttled_frequency), 4810f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar ioread32(&pcch_hdr->minimum_frequency)); 4820f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 4830f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar member = &out_obj->package.elements[1]; 4840f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar if (member->type != ACPI_TYPE_BUFFER) { 4850f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar ret = -ENODEV; 4860f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar goto pcch_free; 4870f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar } 4880f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 4890f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar reg_resource = (struct pcc_register_resource *)member->buffer.pointer; 4900f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 4910f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar doorbell.space_id = reg_resource->space_id; 4920f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar doorbell.bit_width = reg_resource->bit_width; 4930f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar doorbell.bit_offset = reg_resource->bit_offset; 4940f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar doorbell.access_width = 64; 4950f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar doorbell.address = reg_resource->address; 4960f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 4972d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski pr_debug("probe: doorbell: space_id is %d, bit_width is %d, " 4980f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar "bit_offset is %d, access_width is %d, address is 0x%llx\n", 4990f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar doorbell.space_id, doorbell.bit_width, doorbell.bit_offset, 5000f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar doorbell.access_width, reg_resource->address); 5010f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 5020f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar member = &out_obj->package.elements[2]; 5030f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar if (member->type != ACPI_TYPE_INTEGER) { 5040f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar ret = -ENODEV; 5050f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar goto pcch_free; 5060f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar } 5070f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 5080f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar doorbell_preserve = member->integer.value; 5090f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 5100f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar member = &out_obj->package.elements[3]; 5110f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar if (member->type != ACPI_TYPE_INTEGER) { 5120f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar ret = -ENODEV; 5130f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar goto pcch_free; 5140f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar } 5150f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 5160f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar doorbell_write = member->integer.value; 5170f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 5182d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski pr_debug("probe: doorbell_preserve: 0x%llx," 5190f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar " doorbell_write: 0x%llx\n", 5200f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar doorbell_preserve, doorbell_write); 5210f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 5220f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar pcc_cpu_info = alloc_percpu(struct pcc_cpu); 5230f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar if (!pcc_cpu_info) { 5240f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar ret = -ENOMEM; 5250f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar goto pcch_free; 5260f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar } 5270f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 5280f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar printk(KERN_DEBUG "pcc-cpufreq: (v%s) driver loaded with frequency" 5290f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar " limits: %d MHz, %d MHz\n", PCC_VERSION, 5300f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar ioread32(&pcch_hdr->minimum_frequency), 5310f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar ioread32(&pcch_hdr->nominal)); 5320f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar kfree(output.pointer); 5330f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar return ret; 5340f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkarpcch_free: 5350f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar pcc_clear_mapping(); 5360f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkarout_free: 5370f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar kfree(output.pointer); 5380f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar return ret; 5390f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar} 5400f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 5410f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkarstatic int pcc_cpufreq_cpu_init(struct cpufreq_policy *policy) 5420f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar{ 5430f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar unsigned int cpu = policy->cpu; 5440f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar unsigned int result = 0; 5450f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 5460f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar if (!pcch_virt_addr) { 5470f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar result = -1; 548179ee43465343d1f8f2a4af25ead4ae15e43fa6eMatthew Garrett goto out; 5490f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar } 5500f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 5510f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar result = pcc_get_offset(cpu); 5520f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar if (result) { 5532d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski pr_debug("init: PCCP evaluation failed\n"); 554179ee43465343d1f8f2a4af25ead4ae15e43fa6eMatthew Garrett goto out; 5550f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar } 5560f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 5570f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar policy->max = policy->cpuinfo.max_freq = 5580f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar ioread32(&pcch_hdr->nominal) * 1000; 5590f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar policy->min = policy->cpuinfo.min_freq = 5600f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar ioread32(&pcch_hdr->minimum_frequency) * 1000; 5610f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar policy->cur = pcc_get_freq(cpu); 5620f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 563179ee43465343d1f8f2a4af25ead4ae15e43fa6eMatthew Garrett if (!policy->cur) { 5642d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski pr_debug("init: Unable to get current CPU frequency\n"); 565179ee43465343d1f8f2a4af25ead4ae15e43fa6eMatthew Garrett result = -EINVAL; 566179ee43465343d1f8f2a4af25ead4ae15e43fa6eMatthew Garrett goto out; 567179ee43465343d1f8f2a4af25ead4ae15e43fa6eMatthew Garrett } 568179ee43465343d1f8f2a4af25ead4ae15e43fa6eMatthew Garrett 5692d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski pr_debug("init: policy->max is %d, policy->min is %d\n", 5700f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar policy->max, policy->min); 571179ee43465343d1f8f2a4af25ead4ae15e43fa6eMatthew Garrettout: 5720f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar return result; 5730f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar} 5740f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 5750f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkarstatic int pcc_cpufreq_cpu_exit(struct cpufreq_policy *policy) 5760f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar{ 5770f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar return 0; 5780f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar} 5790f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 5800f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkarstatic struct cpufreq_driver pcc_cpufreq_driver = { 5810f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar .flags = CPUFREQ_CONST_LOOPS, 5820f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar .get = pcc_get_freq, 5830f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar .verify = pcc_cpufreq_verify, 5840f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar .target = pcc_cpufreq_target, 5850f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar .init = pcc_cpufreq_cpu_init, 5860f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar .exit = pcc_cpufreq_cpu_exit, 5870f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar .name = "pcc-cpufreq", 5880f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar .owner = THIS_MODULE, 5890f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar}; 5900f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 5910f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkarstatic int __init pcc_cpufreq_init(void) 5920f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar{ 5930f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar int ret; 5940f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 5950f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar if (acpi_disabled) 5960f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar return 0; 5970f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 5980f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar ret = pcc_cpufreq_probe(); 5990f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar if (ret) { 6002d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski pr_debug("pcc_cpufreq_init: PCCH evaluation failed\n"); 6010f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar return ret; 6020f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar } 6030f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 6040f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar ret = cpufreq_register_driver(&pcc_cpufreq_driver); 6050f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 6060f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar return ret; 6070f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar} 6080f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 6090f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkarstatic void __exit pcc_cpufreq_exit(void) 6100f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar{ 6110f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar cpufreq_unregister_driver(&pcc_cpufreq_driver); 6120f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 6130f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar pcc_clear_mapping(); 6140f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 6150f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar free_percpu(pcc_cpu_info); 6160f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar} 6170f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 6180f1d683fb35d6c6f49ef696c95757f3970682a0eNaga ChumbalkarMODULE_AUTHOR("Matthew Garrett, Naga Chumbalkar"); 6190f1d683fb35d6c6f49ef696c95757f3970682a0eNaga ChumbalkarMODULE_VERSION(PCC_VERSION); 6200f1d683fb35d6c6f49ef696c95757f3970682a0eNaga ChumbalkarMODULE_DESCRIPTION("Processor Clocking Control interface driver"); 6210f1d683fb35d6c6f49ef696c95757f3970682a0eNaga ChumbalkarMODULE_LICENSE("GPL"); 6220f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkar 6230f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkarlate_initcall(pcc_cpufreq_init); 6240f1d683fb35d6c6f49ef696c95757f3970682a0eNaga Chumbalkarmodule_exit(pcc_cpufreq_exit); 625