Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  *  pcc-cpufreq.c - Processor Clocking Control firmware cpufreq interface
0003  *
0004  *  Copyright (C) 2009 Red Hat, Matthew Garrett <mjg@redhat.com>
0005  *  Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
0006  *  Nagananda Chumbalkar <nagananda.chumbalkar@hp.com>
0007  *
0008  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0009  *
0010  *  This program is free software; you can redistribute it and/or modify
0011  *  it under the terms of the GNU General Public License as published by
0012  *  the Free Software Foundation; version 2 of the License.
0013  *
0014  *  This program is distributed in the hope that it will be useful, but
0015  *  WITHOUT ANY WARRANTY; without even the implied warranty of
0016  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or NON
0017  *  INFRINGEMENT. See the GNU General Public License for more details.
0018  *
0019  *  You should have received a copy of the GNU General Public License along
0020  *  with this program; if not, write to the Free Software Foundation, Inc.,
0021  *  675 Mass Ave, Cambridge, MA 02139, USA.
0022  *
0023  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0024  */
0025 
0026 #include <linux/kernel.h>
0027 #include <linux/module.h>
0028 #include <linux/init.h>
0029 #include <linux/smp.h>
0030 #include <linux/sched.h>
0031 #include <linux/cpufreq.h>
0032 #include <linux/compiler.h>
0033 #include <linux/slab.h>
0034 
0035 #include <linux/acpi.h>
0036 #include <linux/io.h>
0037 #include <linux/spinlock.h>
0038 #include <linux/uaccess.h>
0039 
0040 #include <acpi/processor.h>
0041 
0042 #define PCC_VERSION "1.10.00"
0043 #define POLL_LOOPS  300
0044 
0045 #define CMD_COMPLETE    0x1
0046 #define CMD_GET_FREQ    0x0
0047 #define CMD_SET_FREQ    0x1
0048 
0049 #define BUF_SZ      4
0050 
0051 struct pcc_register_resource {
0052     u8 descriptor;
0053     u16 length;
0054     u8 space_id;
0055     u8 bit_width;
0056     u8 bit_offset;
0057     u8 access_size;
0058     u64 address;
0059 } __attribute__ ((packed));
0060 
0061 struct pcc_memory_resource {
0062     u8 descriptor;
0063     u16 length;
0064     u8 space_id;
0065     u8 resource_usage;
0066     u8 type_specific;
0067     u64 granularity;
0068     u64 minimum;
0069     u64 maximum;
0070     u64 translation_offset;
0071     u64 address_length;
0072 } __attribute__ ((packed));
0073 
0074 static struct cpufreq_driver pcc_cpufreq_driver;
0075 
0076 struct pcc_header {
0077     u32 signature;
0078     u16 length;
0079     u8 major;
0080     u8 minor;
0081     u32 features;
0082     u16 command;
0083     u16 status;
0084     u32 latency;
0085     u32 minimum_time;
0086     u32 maximum_time;
0087     u32 nominal;
0088     u32 throttled_frequency;
0089     u32 minimum_frequency;
0090 };
0091 
0092 static void __iomem *pcch_virt_addr;
0093 static struct pcc_header __iomem *pcch_hdr;
0094 
0095 static DEFINE_SPINLOCK(pcc_lock);
0096 
0097 static struct acpi_generic_address doorbell;
0098 
0099 static u64 doorbell_preserve;
0100 static u64 doorbell_write;
0101 
0102 static u8 OSC_UUID[16] = {0x9F, 0x2C, 0x9B, 0x63, 0x91, 0x70, 0x1f, 0x49,
0103               0xBB, 0x4F, 0xA5, 0x98, 0x2F, 0xA1, 0xB5, 0x46};
0104 
0105 struct pcc_cpu {
0106     u32 input_offset;
0107     u32 output_offset;
0108 };
0109 
0110 static struct pcc_cpu __percpu *pcc_cpu_info;
0111 
0112 static int pcc_cpufreq_verify(struct cpufreq_policy_data *policy)
0113 {
0114     cpufreq_verify_within_cpu_limits(policy);
0115     return 0;
0116 }
0117 
0118 static inline void pcc_cmd(void)
0119 {
0120     u64 doorbell_value;
0121     int i;
0122 
0123     acpi_read(&doorbell_value, &doorbell);
0124     acpi_write((doorbell_value & doorbell_preserve) | doorbell_write,
0125            &doorbell);
0126 
0127     for (i = 0; i < POLL_LOOPS; i++) {
0128         if (ioread16(&pcch_hdr->status) & CMD_COMPLETE)
0129             break;
0130     }
0131 }
0132 
0133 static inline void pcc_clear_mapping(void)
0134 {
0135     if (pcch_virt_addr)
0136         iounmap(pcch_virt_addr);
0137     pcch_virt_addr = NULL;
0138 }
0139 
0140 static unsigned int pcc_get_freq(unsigned int cpu)
0141 {
0142     struct pcc_cpu *pcc_cpu_data;
0143     unsigned int curr_freq;
0144     unsigned int freq_limit;
0145     u16 status;
0146     u32 input_buffer;
0147     u32 output_buffer;
0148 
0149     spin_lock(&pcc_lock);
0150 
0151     pr_debug("get: get_freq for CPU %d\n", cpu);
0152     pcc_cpu_data = per_cpu_ptr(pcc_cpu_info, cpu);
0153 
0154     input_buffer = 0x1;
0155     iowrite32(input_buffer,
0156             (pcch_virt_addr + pcc_cpu_data->input_offset));
0157     iowrite16(CMD_GET_FREQ, &pcch_hdr->command);
0158 
0159     pcc_cmd();
0160 
0161     output_buffer =
0162         ioread32(pcch_virt_addr + pcc_cpu_data->output_offset);
0163 
0164     /* Clear the input buffer - we are done with the current command */
0165     memset_io((pcch_virt_addr + pcc_cpu_data->input_offset), 0, BUF_SZ);
0166 
0167     status = ioread16(&pcch_hdr->status);
0168     if (status != CMD_COMPLETE) {
0169         pr_debug("get: FAILED: for CPU %d, status is %d\n",
0170             cpu, status);
0171         goto cmd_incomplete;
0172     }
0173     iowrite16(0, &pcch_hdr->status);
0174     curr_freq = (((ioread32(&pcch_hdr->nominal) * (output_buffer & 0xff))
0175             / 100) * 1000);
0176 
0177     pr_debug("get: SUCCESS: (virtual) output_offset for cpu %d is "
0178         "0x%p, contains a value of: 0x%x. Speed is: %d MHz\n",
0179         cpu, (pcch_virt_addr + pcc_cpu_data->output_offset),
0180         output_buffer, curr_freq);
0181 
0182     freq_limit = (output_buffer >> 8) & 0xff;
0183     if (freq_limit != 0xff) {
0184         pr_debug("get: frequency for cpu %d is being temporarily"
0185             " capped at %d\n", cpu, curr_freq);
0186     }
0187 
0188     spin_unlock(&pcc_lock);
0189     return curr_freq;
0190 
0191 cmd_incomplete:
0192     iowrite16(0, &pcch_hdr->status);
0193     spin_unlock(&pcc_lock);
0194     return 0;
0195 }
0196 
0197 static int pcc_cpufreq_target(struct cpufreq_policy *policy,
0198                   unsigned int target_freq,
0199                   unsigned int relation)
0200 {
0201     struct pcc_cpu *pcc_cpu_data;
0202     struct cpufreq_freqs freqs;
0203     u16 status;
0204     u32 input_buffer;
0205     int cpu;
0206 
0207     cpu = policy->cpu;
0208     pcc_cpu_data = per_cpu_ptr(pcc_cpu_info, cpu);
0209 
0210     pr_debug("target: CPU %d should go to target freq: %d "
0211         "(virtual) input_offset is 0x%p\n",
0212         cpu, target_freq,
0213         (pcch_virt_addr + pcc_cpu_data->input_offset));
0214 
0215     freqs.old = policy->cur;
0216     freqs.new = target_freq;
0217     cpufreq_freq_transition_begin(policy, &freqs);
0218     spin_lock(&pcc_lock);
0219 
0220     input_buffer = 0x1 | (((target_freq * 100)
0221                    / (ioread32(&pcch_hdr->nominal) * 1000)) << 8);
0222     iowrite32(input_buffer,
0223             (pcch_virt_addr + pcc_cpu_data->input_offset));
0224     iowrite16(CMD_SET_FREQ, &pcch_hdr->command);
0225 
0226     pcc_cmd();
0227 
0228     /* Clear the input buffer - we are done with the current command */
0229     memset_io((pcch_virt_addr + pcc_cpu_data->input_offset), 0, BUF_SZ);
0230 
0231     status = ioread16(&pcch_hdr->status);
0232     iowrite16(0, &pcch_hdr->status);
0233 
0234     cpufreq_freq_transition_end(policy, &freqs, status != CMD_COMPLETE);
0235     spin_unlock(&pcc_lock);
0236 
0237     if (status != CMD_COMPLETE) {
0238         pr_debug("target: FAILED for cpu %d, with status: 0x%x\n",
0239             cpu, status);
0240         return -EINVAL;
0241     }
0242 
0243     pr_debug("target: was SUCCESSFUL for cpu %d\n", cpu);
0244 
0245     return 0;
0246 }
0247 
0248 static int pcc_get_offset(int cpu)
0249 {
0250     acpi_status status;
0251     struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
0252     union acpi_object *pccp, *offset;
0253     struct pcc_cpu *pcc_cpu_data;
0254     struct acpi_processor *pr;
0255     int ret = 0;
0256 
0257     pr = per_cpu(processors, cpu);
0258     pcc_cpu_data = per_cpu_ptr(pcc_cpu_info, cpu);
0259 
0260     if (!pr)
0261         return -ENODEV;
0262 
0263     status = acpi_evaluate_object(pr->handle, "PCCP", NULL, &buffer);
0264     if (ACPI_FAILURE(status))
0265         return -ENODEV;
0266 
0267     pccp = buffer.pointer;
0268     if (!pccp || pccp->type != ACPI_TYPE_PACKAGE) {
0269         ret = -ENODEV;
0270         goto out_free;
0271     }
0272 
0273     offset = &(pccp->package.elements[0]);
0274     if (!offset || offset->type != ACPI_TYPE_INTEGER) {
0275         ret = -ENODEV;
0276         goto out_free;
0277     }
0278 
0279     pcc_cpu_data->input_offset = offset->integer.value;
0280 
0281     offset = &(pccp->package.elements[1]);
0282     if (!offset || offset->type != ACPI_TYPE_INTEGER) {
0283         ret = -ENODEV;
0284         goto out_free;
0285     }
0286 
0287     pcc_cpu_data->output_offset = offset->integer.value;
0288 
0289     memset_io((pcch_virt_addr + pcc_cpu_data->input_offset), 0, BUF_SZ);
0290     memset_io((pcch_virt_addr + pcc_cpu_data->output_offset), 0, BUF_SZ);
0291 
0292     pr_debug("pcc_get_offset: for CPU %d: pcc_cpu_data "
0293         "input_offset: 0x%x, pcc_cpu_data output_offset: 0x%x\n",
0294         cpu, pcc_cpu_data->input_offset, pcc_cpu_data->output_offset);
0295 out_free:
0296     kfree(buffer.pointer);
0297     return ret;
0298 }
0299 
0300 static int __init pcc_cpufreq_do_osc(acpi_handle *handle)
0301 {
0302     acpi_status status;
0303     struct acpi_object_list input;
0304     struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL};
0305     union acpi_object in_params[4];
0306     union acpi_object *out_obj;
0307     u32 capabilities[2];
0308     u32 errors;
0309     u32 supported;
0310     int ret = 0;
0311 
0312     input.count = 4;
0313     input.pointer = in_params;
0314     in_params[0].type               = ACPI_TYPE_BUFFER;
0315     in_params[0].buffer.length      = 16;
0316     in_params[0].buffer.pointer     = OSC_UUID;
0317     in_params[1].type               = ACPI_TYPE_INTEGER;
0318     in_params[1].integer.value      = 1;
0319     in_params[2].type               = ACPI_TYPE_INTEGER;
0320     in_params[2].integer.value      = 2;
0321     in_params[3].type               = ACPI_TYPE_BUFFER;
0322     in_params[3].buffer.length      = 8;
0323     in_params[3].buffer.pointer     = (u8 *)&capabilities;
0324 
0325     capabilities[0] = OSC_QUERY_ENABLE;
0326     capabilities[1] = 0x1;
0327 
0328     status = acpi_evaluate_object(*handle, "_OSC", &input, &output);
0329     if (ACPI_FAILURE(status))
0330         return -ENODEV;
0331 
0332     if (!output.length)
0333         return -ENODEV;
0334 
0335     out_obj = output.pointer;
0336     if (out_obj->type != ACPI_TYPE_BUFFER) {
0337         ret = -ENODEV;
0338         goto out_free;
0339     }
0340 
0341     errors = *((u32 *)out_obj->buffer.pointer) & ~(1 << 0);
0342     if (errors) {
0343         ret = -ENODEV;
0344         goto out_free;
0345     }
0346 
0347     supported = *((u32 *)(out_obj->buffer.pointer + 4));
0348     if (!(supported & 0x1)) {
0349         ret = -ENODEV;
0350         goto out_free;
0351     }
0352 
0353     kfree(output.pointer);
0354     capabilities[0] = 0x0;
0355     capabilities[1] = 0x1;
0356 
0357     status = acpi_evaluate_object(*handle, "_OSC", &input, &output);
0358     if (ACPI_FAILURE(status))
0359         return -ENODEV;
0360 
0361     if (!output.length)
0362         return -ENODEV;
0363 
0364     out_obj = output.pointer;
0365     if (out_obj->type != ACPI_TYPE_BUFFER) {
0366         ret = -ENODEV;
0367         goto out_free;
0368     }
0369 
0370     errors = *((u32 *)out_obj->buffer.pointer) & ~(1 << 0);
0371     if (errors) {
0372         ret = -ENODEV;
0373         goto out_free;
0374     }
0375 
0376     supported = *((u32 *)(out_obj->buffer.pointer + 4));
0377     if (!(supported & 0x1)) {
0378         ret = -ENODEV;
0379         goto out_free;
0380     }
0381 
0382 out_free:
0383     kfree(output.pointer);
0384     return ret;
0385 }
0386 
0387 static int __init pcc_cpufreq_probe(void)
0388 {
0389     acpi_status status;
0390     struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL};
0391     struct pcc_memory_resource *mem_resource;
0392     struct pcc_register_resource *reg_resource;
0393     union acpi_object *out_obj, *member;
0394     acpi_handle handle, osc_handle;
0395     int ret = 0;
0396 
0397     status = acpi_get_handle(NULL, "\\_SB", &handle);
0398     if (ACPI_FAILURE(status))
0399         return -ENODEV;
0400 
0401     if (!acpi_has_method(handle, "PCCH"))
0402         return -ENODEV;
0403 
0404     status = acpi_get_handle(handle, "_OSC", &osc_handle);
0405     if (ACPI_SUCCESS(status)) {
0406         ret = pcc_cpufreq_do_osc(&osc_handle);
0407         if (ret)
0408             pr_debug("probe: _OSC evaluation did not succeed\n");
0409         /* Firmware's use of _OSC is optional */
0410         ret = 0;
0411     }
0412 
0413     status = acpi_evaluate_object(handle, "PCCH", NULL, &output);
0414     if (ACPI_FAILURE(status))
0415         return -ENODEV;
0416 
0417     out_obj = output.pointer;
0418     if (out_obj->type != ACPI_TYPE_PACKAGE) {
0419         ret = -ENODEV;
0420         goto out_free;
0421     }
0422 
0423     member = &out_obj->package.elements[0];
0424     if (member->type != ACPI_TYPE_BUFFER) {
0425         ret = -ENODEV;
0426         goto out_free;
0427     }
0428 
0429     mem_resource = (struct pcc_memory_resource *)member->buffer.pointer;
0430 
0431     pr_debug("probe: mem_resource descriptor: 0x%x,"
0432         " length: %d, space_id: %d, resource_usage: %d,"
0433         " type_specific: %d, granularity: 0x%llx,"
0434         " minimum: 0x%llx, maximum: 0x%llx,"
0435         " translation_offset: 0x%llx, address_length: 0x%llx\n",
0436         mem_resource->descriptor, mem_resource->length,
0437         mem_resource->space_id, mem_resource->resource_usage,
0438         mem_resource->type_specific, mem_resource->granularity,
0439         mem_resource->minimum, mem_resource->maximum,
0440         mem_resource->translation_offset,
0441         mem_resource->address_length);
0442 
0443     if (mem_resource->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) {
0444         ret = -ENODEV;
0445         goto out_free;
0446     }
0447 
0448     pcch_virt_addr = ioremap(mem_resource->minimum,
0449                     mem_resource->address_length);
0450     if (pcch_virt_addr == NULL) {
0451         pr_debug("probe: could not map shared mem region\n");
0452         ret = -ENOMEM;
0453         goto out_free;
0454     }
0455     pcch_hdr = pcch_virt_addr;
0456 
0457     pr_debug("probe: PCCH header (virtual) addr: 0x%p\n", pcch_hdr);
0458     pr_debug("probe: PCCH header is at physical address: 0x%llx,"
0459         " signature: 0x%x, length: %d bytes, major: %d, minor: %d,"
0460         " supported features: 0x%x, command field: 0x%x,"
0461         " status field: 0x%x, nominal latency: %d us\n",
0462         mem_resource->minimum, ioread32(&pcch_hdr->signature),
0463         ioread16(&pcch_hdr->length), ioread8(&pcch_hdr->major),
0464         ioread8(&pcch_hdr->minor), ioread32(&pcch_hdr->features),
0465         ioread16(&pcch_hdr->command), ioread16(&pcch_hdr->status),
0466         ioread32(&pcch_hdr->latency));
0467 
0468     pr_debug("probe: min time between commands: %d us,"
0469         " max time between commands: %d us,"
0470         " nominal CPU frequency: %d MHz,"
0471         " minimum CPU frequency: %d MHz,"
0472         " minimum CPU frequency without throttling: %d MHz\n",
0473         ioread32(&pcch_hdr->minimum_time),
0474         ioread32(&pcch_hdr->maximum_time),
0475         ioread32(&pcch_hdr->nominal),
0476         ioread32(&pcch_hdr->throttled_frequency),
0477         ioread32(&pcch_hdr->minimum_frequency));
0478 
0479     member = &out_obj->package.elements[1];
0480     if (member->type != ACPI_TYPE_BUFFER) {
0481         ret = -ENODEV;
0482         goto pcch_free;
0483     }
0484 
0485     reg_resource = (struct pcc_register_resource *)member->buffer.pointer;
0486 
0487     doorbell.space_id = reg_resource->space_id;
0488     doorbell.bit_width = reg_resource->bit_width;
0489     doorbell.bit_offset = reg_resource->bit_offset;
0490     doorbell.access_width = 4;
0491     doorbell.address = reg_resource->address;
0492 
0493     pr_debug("probe: doorbell: space_id is %d, bit_width is %d, "
0494         "bit_offset is %d, access_width is %d, address is 0x%llx\n",
0495         doorbell.space_id, doorbell.bit_width, doorbell.bit_offset,
0496         doorbell.access_width, reg_resource->address);
0497 
0498     member = &out_obj->package.elements[2];
0499     if (member->type != ACPI_TYPE_INTEGER) {
0500         ret = -ENODEV;
0501         goto pcch_free;
0502     }
0503 
0504     doorbell_preserve = member->integer.value;
0505 
0506     member = &out_obj->package.elements[3];
0507     if (member->type != ACPI_TYPE_INTEGER) {
0508         ret = -ENODEV;
0509         goto pcch_free;
0510     }
0511 
0512     doorbell_write = member->integer.value;
0513 
0514     pr_debug("probe: doorbell_preserve: 0x%llx,"
0515         " doorbell_write: 0x%llx\n",
0516         doorbell_preserve, doorbell_write);
0517 
0518     pcc_cpu_info = alloc_percpu(struct pcc_cpu);
0519     if (!pcc_cpu_info) {
0520         ret = -ENOMEM;
0521         goto pcch_free;
0522     }
0523 
0524     printk(KERN_DEBUG "pcc-cpufreq: (v%s) driver loaded with frequency"
0525            " limits: %d MHz, %d MHz\n", PCC_VERSION,
0526            ioread32(&pcch_hdr->minimum_frequency),
0527            ioread32(&pcch_hdr->nominal));
0528     kfree(output.pointer);
0529     return ret;
0530 pcch_free:
0531     pcc_clear_mapping();
0532 out_free:
0533     kfree(output.pointer);
0534     return ret;
0535 }
0536 
0537 static int pcc_cpufreq_cpu_init(struct cpufreq_policy *policy)
0538 {
0539     unsigned int cpu = policy->cpu;
0540     unsigned int result = 0;
0541 
0542     if (!pcch_virt_addr) {
0543         result = -1;
0544         goto out;
0545     }
0546 
0547     result = pcc_get_offset(cpu);
0548     if (result) {
0549         pr_debug("init: PCCP evaluation failed\n");
0550         goto out;
0551     }
0552 
0553     policy->max = policy->cpuinfo.max_freq =
0554         ioread32(&pcch_hdr->nominal) * 1000;
0555     policy->min = policy->cpuinfo.min_freq =
0556         ioread32(&pcch_hdr->minimum_frequency) * 1000;
0557 
0558     pr_debug("init: policy->max is %d, policy->min is %d\n",
0559         policy->max, policy->min);
0560 out:
0561     return result;
0562 }
0563 
0564 static int pcc_cpufreq_cpu_exit(struct cpufreq_policy *policy)
0565 {
0566     return 0;
0567 }
0568 
0569 static struct cpufreq_driver pcc_cpufreq_driver = {
0570     .flags = CPUFREQ_CONST_LOOPS,
0571     .get = pcc_get_freq,
0572     .verify = pcc_cpufreq_verify,
0573     .target = pcc_cpufreq_target,
0574     .init = pcc_cpufreq_cpu_init,
0575     .exit = pcc_cpufreq_cpu_exit,
0576     .name = "pcc-cpufreq",
0577 };
0578 
0579 static int __init pcc_cpufreq_init(void)
0580 {
0581     int ret;
0582 
0583     /* Skip initialization if another cpufreq driver is there. */
0584     if (cpufreq_get_current_driver())
0585         return -EEXIST;
0586 
0587     if (acpi_disabled)
0588         return -ENODEV;
0589 
0590     ret = pcc_cpufreq_probe();
0591     if (ret) {
0592         pr_debug("pcc_cpufreq_init: PCCH evaluation failed\n");
0593         return ret;
0594     }
0595 
0596     if (num_present_cpus() > 4) {
0597         pcc_cpufreq_driver.flags |= CPUFREQ_NO_AUTO_DYNAMIC_SWITCHING;
0598         pr_err("%s: Too many CPUs, dynamic performance scaling disabled\n",
0599                __func__);
0600         pr_err("%s: Try to enable another scaling driver through BIOS settings\n",
0601                __func__);
0602         pr_err("%s: and complain to the system vendor\n", __func__);
0603     }
0604 
0605     ret = cpufreq_register_driver(&pcc_cpufreq_driver);
0606 
0607     return ret;
0608 }
0609 
0610 static void __exit pcc_cpufreq_exit(void)
0611 {
0612     cpufreq_unregister_driver(&pcc_cpufreq_driver);
0613 
0614     pcc_clear_mapping();
0615 
0616     free_percpu(pcc_cpu_info);
0617 }
0618 
0619 static const struct acpi_device_id __maybe_unused processor_device_ids[] = {
0620     {ACPI_PROCESSOR_OBJECT_HID, },
0621     {ACPI_PROCESSOR_DEVICE_HID, },
0622     {},
0623 };
0624 MODULE_DEVICE_TABLE(acpi, processor_device_ids);
0625 
0626 MODULE_AUTHOR("Matthew Garrett, Naga Chumbalkar");
0627 MODULE_VERSION(PCC_VERSION);
0628 MODULE_DESCRIPTION("Processor Clocking Control interface driver");
0629 MODULE_LICENSE("GPL");
0630 
0631 late_initcall(pcc_cpufreq_init);
0632 module_exit(pcc_cpufreq_exit);