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
  33static DEFINE_MUTEX(cbe_switch_mutex);
  34
  35
  36/* the CBE supports an 8 step frequency scaling */
  37static struct cpufreq_frequency_table cbe_freqs[] = {
  38        {1,     0},
  39        {2,     0},
  40        {3,     0},
  41        {4,     0},
  42        {5,     0},
  43        {6,     0},
  44        {8,     0},
  45        {10,    0},
  46        {0,     CPUFREQ_TABLE_END},
  47};
  48
  49/*
  50 * hardware specific functions
  51 */
  52
  53static int set_pmode(unsigned int cpu, unsigned int slow_mode)
  54{
  55        int rc;
  56
  57        if (cbe_cpufreq_has_pmi)
  58                rc = cbe_cpufreq_set_pmode_pmi(cpu, slow_mode);
  59        else
  60                rc = cbe_cpufreq_set_pmode(cpu, slow_mode);
  61
  62        pr_debug("register contains slow mode %d\n", cbe_cpufreq_get_pmode(cpu));
  63
  64        return rc;
  65}
  66
  67/*
  68 * cpufreq functions
  69 */
  70
  71static int cbe_cpufreq_cpu_init(struct cpufreq_policy *policy)
  72{
  73        const u32 *max_freqp;
  74        u32 max_freq;
  75        int i, cur_pmode;
  76        struct device_node *cpu;
  77
  78        cpu = of_get_cpu_node(policy->cpu, NULL);
  79
  80        if (!cpu)
  81                return -ENODEV;
  82
  83        pr_debug("init cpufreq on CPU %d\n", policy->cpu);
  84
  85        /*
  86         * Let's check we can actually get to the CELL regs
  87         */
  88        if (!cbe_get_cpu_pmd_regs(policy->cpu) ||
  89            !cbe_get_cpu_mic_tm_regs(policy->cpu)) {
  90                pr_info("invalid CBE regs pointers for cpufreq\n");
  91                return -EINVAL;
  92        }
  93
  94        max_freqp = of_get_property(cpu, "clock-frequency", NULL);
  95
  96        of_node_put(cpu);
  97
  98        if (!max_freqp)
  99                return -EINVAL;
 100
 101        /* we need the freq in kHz */
 102        max_freq = *max_freqp / 1000;
 103
 104        pr_debug("max clock-frequency is at %u kHz\n", max_freq);
 105        pr_debug("initializing frequency table\n");
 106
 107        /* initialize frequency table */
 108        for (i=0; cbe_freqs[i].frequency!=CPUFREQ_TABLE_END; i++) {
 109                cbe_freqs[i].frequency = max_freq / cbe_freqs[i].driver_data;
 110                pr_debug("%d: %d\n", i, cbe_freqs[i].frequency);
 111        }
 112
 113        /* if DEBUG is enabled set_pmode() measures the latency
 114         * of a transition */
 115        policy->cpuinfo.transition_latency = 25000;
 116
 117        cur_pmode = cbe_cpufreq_get_pmode(policy->cpu);
 118        pr_debug("current pmode is at %d\n",cur_pmode);
 119
 120        policy->cur = cbe_freqs[cur_pmode].frequency;
 121
 122#ifdef CONFIG_SMP
 123        cpumask_copy(policy->cpus, cpu_sibling_mask(policy->cpu));
 124#endif
 125
 126        cpufreq_frequency_table_get_attr(cbe_freqs, policy->cpu);
 127
 128        /* this ensures that policy->cpuinfo_min
 129         * and policy->cpuinfo_max are set correctly */
 130        return cpufreq_frequency_table_cpuinfo(policy, cbe_freqs);
 131}
 132
 133static int cbe_cpufreq_cpu_exit(struct cpufreq_policy *policy)
 134{
 135        cpufreq_frequency_table_put_attr(policy->cpu);
 136        return 0;
 137}
 138
 139static int cbe_cpufreq_verify(struct cpufreq_policy *policy)
 140{
 141        return cpufreq_frequency_table_verify(policy, cbe_freqs);
 142}
 143
 144static int cbe_cpufreq_target(struct cpufreq_policy *policy,
 145                              unsigned int target_freq,
 146                              unsigned int relation)
 147{
 148        int rc;
 149        struct cpufreq_freqs freqs;
 150        unsigned int cbe_pmode_new;
 151
 152        cpufreq_frequency_table_target(policy,
 153                                       cbe_freqs,
 154                                       target_freq,
 155                                       relation,
 156                                       &cbe_pmode_new);
 157
 158        freqs.old = policy->cur;
 159        freqs.new = cbe_freqs[cbe_pmode_new].frequency;
 160
 161        mutex_lock(&cbe_switch_mutex);
 162        cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
 163
 164        pr_debug("setting frequency for cpu %d to %d kHz, " \
 165                 "1/%d of max frequency\n",
 166                 policy->cpu,
 167                 cbe_freqs[cbe_pmode_new].frequency,
 168                 cbe_freqs[cbe_pmode_new].driver_data);
 169
 170        rc = set_pmode(policy->cpu, cbe_pmode_new);
 171
 172        cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
 173        mutex_unlock(&cbe_switch_mutex);
 174
 175        return rc;
 176}
 177
 178static struct cpufreq_driver cbe_cpufreq_driver = {
 179        .verify         = cbe_cpufreq_verify,
 180        .target         = cbe_cpufreq_target,
 181        .init           = cbe_cpufreq_cpu_init,
 182        .exit           = cbe_cpufreq_cpu_exit,
 183        .name           = "cbe-cpufreq",
 184        .owner          = THIS_MODULE,
 185        .flags          = CPUFREQ_CONST_LOOPS,
 186};
 187
 188/*
 189 * module init and destoy
 190 */
 191
 192static int __init cbe_cpufreq_init(void)
 193{
 194        if (!machine_is(cell))
 195                return -ENODEV;
 196
 197        return cpufreq_register_driver(&cbe_cpufreq_driver);
 198}
 199
 200static void __exit cbe_cpufreq_exit(void)
 201{
 202        cpufreq_unregister_driver(&cbe_cpufreq_driver);
 203}
 204
 205module_init(cbe_cpufreq_init);
 206module_exit(cbe_cpufreq_exit);
 207
 208MODULE_LICENSE("GPL");
 209MODULE_AUTHOR("Christian Krafft <krafft@de.ibm.com>");
 210