linux/arch/powerpc/platforms/cell/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/of_platform.h>
  25
  26#include <asm/machdep.h>
  27#include <asm/prom.h>
  28#include <asm/cell-regs.h>
  29#include "cbe_cpufreq.h"
  30
  31static DEFINE_MUTEX(cbe_switch_mutex);
  32
  33
  34/* the CBE supports an 8 step frequency scaling */
  35static struct cpufreq_frequency_table cbe_freqs[] = {
  36        {1,     0},
  37        {2,     0},
  38        {3,     0},
  39        {4,     0},
  40        {5,     0},
  41        {6,     0},
  42        {8,     0},
  43        {10,    0},
  44        {0,     CPUFREQ_TABLE_END},
  45};
  46
  47/*
  48 * hardware specific functions
  49 */
  50
  51static int set_pmode(unsigned int cpu, unsigned int slow_mode)
  52{
  53        int rc;
  54
  55        if (cbe_cpufreq_has_pmi)
  56                rc = cbe_cpufreq_set_pmode_pmi(cpu, slow_mode);
  57        else
  58                rc = cbe_cpufreq_set_pmode(cpu, slow_mode);
  59
  60        pr_debug("register contains slow mode %d\n", cbe_cpufreq_get_pmode(cpu));
  61
  62        return rc;
  63}
  64
  65/*
  66 * cpufreq functions
  67 */
  68
  69static int cbe_cpufreq_cpu_init(struct cpufreq_policy *policy)
  70{
  71        const u32 *max_freqp;
  72        u32 max_freq;
  73        int i, 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        for (i=0; cbe_freqs[i].frequency!=CPUFREQ_TABLE_END; i++) {
 107                cbe_freqs[i].frequency = max_freq / cbe_freqs[i].index;
 108                pr_debug("%d: %d\n", i, cbe_freqs[i].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        cpufreq_frequency_table_get_attr(cbe_freqs, policy->cpu);
 125
 126        /* this ensures that policy->cpuinfo_min
 127         * and policy->cpuinfo_max are set correctly */
 128        return cpufreq_frequency_table_cpuinfo(policy, cbe_freqs);
 129}
 130
 131static int cbe_cpufreq_cpu_exit(struct cpufreq_policy *policy)
 132{
 133        cpufreq_frequency_table_put_attr(policy->cpu);
 134        return 0;
 135}
 136
 137static int cbe_cpufreq_verify(struct cpufreq_policy *policy)
 138{
 139        return cpufreq_frequency_table_verify(policy, cbe_freqs);
 140}
 141
 142static int cbe_cpufreq_target(struct cpufreq_policy *policy,
 143                              unsigned int target_freq,
 144                              unsigned int relation)
 145{
 146        int rc;
 147        struct cpufreq_freqs freqs;
 148        unsigned int cbe_pmode_new;
 149
 150        cpufreq_frequency_table_target(policy,
 151                                       cbe_freqs,
 152                                       target_freq,
 153                                       relation,
 154                                       &cbe_pmode_new);
 155
 156        freqs.old = policy->cur;
 157        freqs.new = cbe_freqs[cbe_pmode_new].frequency;
 158        freqs.cpu = policy->cpu;
 159
 160        mutex_lock(&cbe_switch_mutex);
 161        cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
 162
 163        pr_debug("setting frequency for cpu %d to %d kHz, " \
 164                 "1/%d of max frequency\n",
 165                 policy->cpu,
 166                 cbe_freqs[cbe_pmode_new].frequency,
 167                 cbe_freqs[cbe_pmode_new].index);
 168
 169        rc = set_pmode(policy->cpu, cbe_pmode_new);
 170
 171        cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
 172        mutex_unlock(&cbe_switch_mutex);
 173
 174        return rc;
 175}
 176
 177static struct cpufreq_driver cbe_cpufreq_driver = {
 178        .verify         = cbe_cpufreq_verify,
 179        .target         = cbe_cpufreq_target,
 180        .init           = cbe_cpufreq_cpu_init,
 181        .exit           = cbe_cpufreq_cpu_exit,
 182        .name           = "cbe-cpufreq",
 183        .owner          = THIS_MODULE,
 184        .flags          = CPUFREQ_CONST_LOOPS,
 185};
 186
 187/*
 188 * module init and destoy
 189 */
 190
 191static int __init cbe_cpufreq_init(void)
 192{
 193        if (!machine_is(cell))
 194                return -ENODEV;
 195
 196        return cpufreq_register_driver(&cbe_cpufreq_driver);
 197}
 198
 199static void __exit cbe_cpufreq_exit(void)
 200{
 201        cpufreq_unregister_driver(&cbe_cpufreq_driver);
 202}
 203
 204module_init(cbe_cpufreq_init);
 205module_exit(cbe_cpufreq_exit);
 206
 207MODULE_LICENSE("GPL");
 208MODULE_AUTHOR("Christian Krafft <krafft@de.ibm.com>");
 209