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