Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * cpufreq driver for the cell processor
0004  *
0005  * (C) Copyright IBM Deutschland Entwicklung GmbH 2005-2007
0006  *
0007  * Author: Christian Krafft <krafft@de.ibm.com>
0008  */
0009 
0010 #include <linux/cpufreq.h>
0011 #include <linux/module.h>
0012 #include <linux/of_platform.h>
0013 
0014 #include <asm/machdep.h>
0015 #include <asm/cell-regs.h>
0016 
0017 #include "ppc_cbe_cpufreq.h"
0018 
0019 /* the CBE supports an 8 step frequency scaling */
0020 static struct cpufreq_frequency_table cbe_freqs[] = {
0021     {0, 1,  0},
0022     {0, 2,  0},
0023     {0, 3,  0},
0024     {0, 4,  0},
0025     {0, 5,  0},
0026     {0, 6,  0},
0027     {0, 8,  0},
0028     {0, 10, 0},
0029     {0, 0,  CPUFREQ_TABLE_END},
0030 };
0031 
0032 /*
0033  * hardware specific functions
0034  */
0035 
0036 static int set_pmode(unsigned int cpu, unsigned int slow_mode)
0037 {
0038     int rc;
0039 
0040     if (cbe_cpufreq_has_pmi)
0041         rc = cbe_cpufreq_set_pmode_pmi(cpu, slow_mode);
0042     else
0043         rc = cbe_cpufreq_set_pmode(cpu, slow_mode);
0044 
0045     pr_debug("register contains slow mode %d\n", cbe_cpufreq_get_pmode(cpu));
0046 
0047     return rc;
0048 }
0049 
0050 /*
0051  * cpufreq functions
0052  */
0053 
0054 static int cbe_cpufreq_cpu_init(struct cpufreq_policy *policy)
0055 {
0056     struct cpufreq_frequency_table *pos;
0057     const u32 *max_freqp;
0058     u32 max_freq;
0059     int cur_pmode;
0060     struct device_node *cpu;
0061 
0062     cpu = of_get_cpu_node(policy->cpu, NULL);
0063 
0064     if (!cpu)
0065         return -ENODEV;
0066 
0067     pr_debug("init cpufreq on CPU %d\n", policy->cpu);
0068 
0069     /*
0070      * Let's check we can actually get to the CELL regs
0071      */
0072     if (!cbe_get_cpu_pmd_regs(policy->cpu) ||
0073         !cbe_get_cpu_mic_tm_regs(policy->cpu)) {
0074         pr_info("invalid CBE regs pointers for cpufreq\n");
0075         of_node_put(cpu);
0076         return -EINVAL;
0077     }
0078 
0079     max_freqp = of_get_property(cpu, "clock-frequency", NULL);
0080 
0081     of_node_put(cpu);
0082 
0083     if (!max_freqp)
0084         return -EINVAL;
0085 
0086     /* we need the freq in kHz */
0087     max_freq = *max_freqp / 1000;
0088 
0089     pr_debug("max clock-frequency is at %u kHz\n", max_freq);
0090     pr_debug("initializing frequency table\n");
0091 
0092     /* initialize frequency table */
0093     cpufreq_for_each_entry(pos, cbe_freqs) {
0094         pos->frequency = max_freq / pos->driver_data;
0095         pr_debug("%d: %d\n", (int)(pos - cbe_freqs), pos->frequency);
0096     }
0097 
0098     /* if DEBUG is enabled set_pmode() measures the latency
0099      * of a transition */
0100     policy->cpuinfo.transition_latency = 25000;
0101 
0102     cur_pmode = cbe_cpufreq_get_pmode(policy->cpu);
0103     pr_debug("current pmode is at %d\n",cur_pmode);
0104 
0105     policy->cur = cbe_freqs[cur_pmode].frequency;
0106 
0107 #ifdef CONFIG_SMP
0108     cpumask_copy(policy->cpus, cpu_sibling_mask(policy->cpu));
0109 #endif
0110 
0111     policy->freq_table = cbe_freqs;
0112     cbe_cpufreq_pmi_policy_init(policy);
0113     return 0;
0114 }
0115 
0116 static int cbe_cpufreq_cpu_exit(struct cpufreq_policy *policy)
0117 {
0118     cbe_cpufreq_pmi_policy_exit(policy);
0119     return 0;
0120 }
0121 
0122 static int cbe_cpufreq_target(struct cpufreq_policy *policy,
0123                   unsigned int cbe_pmode_new)
0124 {
0125     pr_debug("setting frequency for cpu %d to %d kHz, " \
0126          "1/%d of max frequency\n",
0127          policy->cpu,
0128          cbe_freqs[cbe_pmode_new].frequency,
0129          cbe_freqs[cbe_pmode_new].driver_data);
0130 
0131     return set_pmode(policy->cpu, cbe_pmode_new);
0132 }
0133 
0134 static struct cpufreq_driver cbe_cpufreq_driver = {
0135     .verify     = cpufreq_generic_frequency_table_verify,
0136     .target_index   = cbe_cpufreq_target,
0137     .init       = cbe_cpufreq_cpu_init,
0138     .exit       = cbe_cpufreq_cpu_exit,
0139     .name       = "cbe-cpufreq",
0140     .flags      = CPUFREQ_CONST_LOOPS,
0141 };
0142 
0143 /*
0144  * module init and destoy
0145  */
0146 
0147 static int __init cbe_cpufreq_init(void)
0148 {
0149     int ret;
0150 
0151     if (!machine_is(cell))
0152         return -ENODEV;
0153 
0154     cbe_cpufreq_pmi_init();
0155 
0156     ret = cpufreq_register_driver(&cbe_cpufreq_driver);
0157     if (ret)
0158         cbe_cpufreq_pmi_exit();
0159 
0160     return ret;
0161 }
0162 
0163 static void __exit cbe_cpufreq_exit(void)
0164 {
0165     cpufreq_unregister_driver(&cbe_cpufreq_driver);
0166     cbe_cpufreq_pmi_exit();
0167 }
0168 
0169 module_init(cbe_cpufreq_init);
0170 module_exit(cbe_cpufreq_exit);
0171 
0172 MODULE_LICENSE("GPL");
0173 MODULE_AUTHOR("Christian Krafft <krafft@de.ibm.com>");