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/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#include "cbe_cpufreq.h"
  31
  32static DEFINE_MUTEX(cbe_switch_mutex);
  33
  34
  35/* the CBE supports an 8 step frequency scaling */
  36static struct cpufreq_frequency_table cbe_freqs[] = {
  37        {1,     0},
  38        {2,     0},
  39        {3,     0},
  40        {4,     0},
  41        {5,     0},
  42        {6,     0},
  43        {8,     0},
  44        {10,    0},
  45        {0,     CPUFREQ_TABLE_END},
  46};
  47
  48/*
  49 * hardware specific functions
  50 */
  51
  52static int set_pmode(unsigned int cpu, unsigned int slow_mode)
  53{
  54        int rc;
  55
  56        if (cbe_cpufreq_has_pmi)
  57                rc = cbe_cpufreq_set_pmode_pmi(cpu, slow_mode);
  58        else
  59                rc = cbe_cpufreq_set_pmode(cpu, slow_mode);
  60
  61        pr_debug("register contains slow mode %d\n", cbe_cpufreq_get_pmode(cpu));
  62
  63        return rc;
  64}
  65
  66/*
  67 * cpufreq functions
  68 */
  69
  70static int cbe_cpufreq_cpu_init(struct cpufreq_policy *policy)
  71{
  72        const u32 *max_freqp;
  73        u32 max_freq;
  74        int i, cur_pmode;
  75        struct device_node *cpu;
  76
  77        cpu = of_get_cpu_node(policy->cpu, NULL);
  78
  79        if (!cpu)
  80                return -ENODEV;
  81
  82        pr_debug("init cpufreq on CPU %d\n", policy->cpu);
  83
  84        /*
  85         * Let's check we can actually get to the CELL regs
  86         */
  87        if (!cbe_get_cpu_pmd_regs(policy->cpu) ||
  88            !cbe_get_cpu_mic_tm_regs(policy->cpu)) {
  89                pr_info("invalid CBE regs pointers for cpufreq\n");
  90                return -EINVAL;
  91        }
  92
  93        max_freqp = of_get_property(cpu, "clock-frequency", NULL);
  94
  95        of_node_put(cpu);
  96
  97        if (!max_freqp)
  98                return -EINVAL;
  99
 100        /* we need the freq in kHz */
 101        max_freq = *max_freqp / 1000;
 102
 103        pr_debug("max clock-frequency is at %u kHz\n", max_freq);
 104        pr_debug("initializing frequency table\n");
 105
 106        /* initialize frequency table */
 107        for (i=0; cbe_freqs[i].frequency!=CPUFREQ_TABLE_END; i++) {
 108                cbe_freqs[i].frequency = max_freq / cbe_freqs[i].index;
 109                pr_debug("%d: %d\n", i, cbe_freqs[i].frequency);
 110        }
 111
 112        /* if DEBUG is enabled set_pmode() measures the latency
 113         * of a transition */
 114        policy->cpuinfo.transition_latency = 25000;
 115
 116        cur_pmode = cbe_cpufreq_get_pmode(policy->cpu);
 117        pr_debug("current pmode is at %d\n",cur_pmode);
 118
 119        policy->cur = cbe_freqs[cur_pmode].frequency;
 120
 121#ifdef CONFIG_SMP
 122        cpumask_copy(policy->cpus, cpu_sibling_mask(policy->cpu));
 123#endif
 124
 125        cpufreq_frequency_table_get_attr(cbe_freqs, policy->cpu);
 126
 127        /* this ensures that policy->cpuinfo_min
 128         * and policy->cpuinfo_max are set correctly */
 129        return cpufreq_frequency_table_cpuinfo(policy, cbe_freqs);
 130}
 131
 132static int cbe_cpufreq_cpu_exit(struct cpufreq_policy *policy)
 133{
 134        cpufreq_frequency_table_put_attr(policy->cpu);
 135        return 0;
 136}
 137
 138static int cbe_cpufreq_verify(struct cpufreq_policy *policy)
 139{
 140        return cpufreq_frequency_table_verify(policy, cbe_freqs);
 141}
 142
 143static int cbe_cpufreq_target(struct cpufreq_policy *policy,
 144                              unsigned int target_freq,
 145                              unsigned int relation)
 146{
 147        int rc;
 148        struct cpufreq_freqs freqs;
 149        unsigned int cbe_pmode_new;
 150
 151        cpufreq_frequency_table_target(policy,
 152                                       cbe_freqs,
 153                                       target_freq,
 154                                       relation,
 155                                       &cbe_pmode_new);
 156
 157        freqs.old = policy->cur;
 158        freqs.new = cbe_freqs[cbe_pmode_new].frequency;
 159        freqs.cpu = policy->cpu;
 160
 161        mutex_lock(&cbe_switch_mutex);
 162        cpufreq_notify_transition(&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].index);
 169
 170        rc = set_pmode(policy->cpu, cbe_pmode_new);
 171
 172        cpufreq_notify_transition(&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