linux/drivers/cpufreq/ppc_cbe_cpufreq.c
<<
>>
Prefs
   1/*
   2 * cpufreq driver for the cell processor
   3 *
   4 * (C) Copyright IBM Deutschland Entwicklung GmbH 2005-2007
   5 *
   6 * Author: Christian Krafft <krafft@de.ibm.com>
   7 *
   8 * This program is free software; you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License as published by
  10 * the Free Software Foundation; either version 2, or (at your option)
  11 * any later version.
  12 *
  13 * This program is distributed in the hope that it will be useful,
  14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16 * GNU General Public License for more details.
  17 *
  18 * You should have received a copy of the GNU General Public License
  19 * along with this program; if not, write to the Free Software
  20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21 */
  22
  23#include <linux/cpufreq.h>
  24#include <linux/module.h>
  25#include <linux/of_platform.h>
  26
  27#include <asm/machdep.h>
  28#include <asm/prom.h>
  29#include <asm/cell-regs.h>
  30
  31#include "ppc_cbe_cpufreq.h"
  32
  33/* the CBE supports an 8 step frequency scaling */
  34static struct cpufreq_frequency_table cbe_freqs[] = {
  35        {0, 1,  0},
  36        {0, 2,  0},
  37        {0, 3,  0},
  38        {0, 4,  0},
  39        {0, 5,  0},
  40        {0, 6,  0},
  41        {0, 8,  0},
  42        {0, 10, 0},
  43        {0, 0,  CPUFREQ_TABLE_END},
  44};
  45
  46/*
  47 * hardware specific functions
  48 */
  49
  50static int set_pmode(unsigned int cpu, unsigned int slow_mode)
  51{
  52        int rc;
  53
  54        if (cbe_cpufreq_has_pmi)
  55                rc = cbe_cpufreq_set_pmode_pmi(cpu, slow_mode);
  56        else
  57                rc = cbe_cpufreq_set_pmode(cpu, slow_mode);
  58
  59        pr_debug("register contains slow mode %d\n", cbe_cpufreq_get_pmode(cpu));
  60
  61        return rc;
  62}
  63
  64/*
  65 * cpufreq functions
  66 */
  67
  68static int cbe_cpufreq_cpu_init(struct cpufreq_policy *policy)
  69{
  70        struct cpufreq_frequency_table *pos;
  71        const u32 *max_freqp;
  72        u32 max_freq;
  73        int cur_pmode;
  74        struct device_node *cpu;
  75
  76        cpu = of_get_cpu_node(policy->cpu, NULL);
  77
  78        if (!cpu)
  79                return -ENODEV;
  80
  81        pr_debug("init cpufreq on CPU %d\n", policy->cpu);
  82
  83        /*
  84         * Let's check we can actually get to the CELL regs
  85         */
  86        if (!cbe_get_cpu_pmd_regs(policy->cpu) ||
  87            !cbe_get_cpu_mic_tm_regs(policy->cpu)) {
  88                pr_info("invalid CBE regs pointers for cpufreq\n");
  89                return -EINVAL;
  90        }
  91
  92        max_freqp = of_get_property(cpu, "clock-frequency", NULL);
  93
  94        of_node_put(cpu);
  95
  96        if (!max_freqp)
  97                return -EINVAL;
  98
  99        /* we need the freq in kHz */
 100        max_freq = *max_freqp / 1000;
 101
 102        pr_debug("max clock-frequency is at %u kHz\n", max_freq);
 103        pr_debug("initializing frequency table\n");
 104
 105        /* initialize frequency table */
 106        cpufreq_for_each_entry(pos, cbe_freqs) {
 107                pos->frequency = max_freq / pos->driver_data;
 108                pr_debug("%d: %d\n", (int)(pos - cbe_freqs), pos->frequency);
 109        }
 110
 111        /* if DEBUG is enabled set_pmode() measures the latency
 112         * of a transition */
 113        policy->cpuinfo.transition_latency = 25000;
 114
 115        cur_pmode = cbe_cpufreq_get_pmode(policy->cpu);
 116        pr_debug("current pmode is at %d\n",cur_pmode);
 117
 118        policy->cur = cbe_freqs[cur_pmode].frequency;
 119
 120#ifdef CONFIG_SMP
 121        cpumask_copy(policy->cpus, cpu_sibling_mask(policy->cpu));
 122#endif
 123
 124        /* this ensures that policy->cpuinfo_min
 125         * and policy->cpuinfo_max are set correctly */
 126        return cpufreq_table_validate_and_show(policy, cbe_freqs);
 127}
 128
 129static int cbe_cpufreq_target(struct cpufreq_policy *policy,
 130                              unsigned int cbe_pmode_new)
 131{
 132        pr_debug("setting frequency for cpu %d to %d kHz, " \
 133                 "1/%d of max frequency\n",
 134                 policy->cpu,
 135                 cbe_freqs[cbe_pmode_new].frequency,
 136                 cbe_freqs[cbe_pmode_new].driver_data);
 137
 138        return set_pmode(policy->cpu, cbe_pmode_new);
 139}
 140
 141static struct cpufreq_driver cbe_cpufreq_driver = {
 142        .verify         = cpufreq_generic_frequency_table_verify,
 143        .target_index   = cbe_cpufreq_target,
 144        .init           = cbe_cpufreq_cpu_init,
 145        .name           = "cbe-cpufreq",
 146        .flags          = CPUFREQ_CONST_LOOPS,
 147};
 148
 149/*
 150 * module init and destoy
 151 */
 152
 153static int __init cbe_cpufreq_init(void)
 154{
 155        if (!machine_is(cell))
 156                return -ENODEV;
 157
 158        return cpufreq_register_driver(&cbe_cpufreq_driver);
 159}
 160
 161static void __exit cbe_cpufreq_exit(void)
 162{
 163        cpufreq_unregister_driver(&cbe_cpufreq_driver);
 164}
 165
 166module_init(cbe_cpufreq_init);
 167module_exit(cbe_cpufreq_exit);
 168
 169MODULE_LICENSE("GPL");
 170MODULE_AUTHOR("Christian Krafft <krafft@de.ibm.com>");
 171