root/drivers/cpufreq/sparc-us3-cpufreq.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. read_safari_cfg
  2. update_safari_cfg
  3. get_current_freq
  4. us3_freq_get
  5. us3_freq_target
  6. us3_freq_cpu_init
  7. us3_freq_cpu_exit
  8. us3_freq_init
  9. us3_freq_exit

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /* us3_cpufreq.c: UltraSPARC-III cpu frequency support
   3  *
   4  * Copyright (C) 2003 David S. Miller (davem@redhat.com)
   5  *
   6  * Many thanks to Dominik Brodowski for fixing up the cpufreq
   7  * infrastructure in order to make this driver easier to implement.
   8  */
   9 
  10 #include <linux/kernel.h>
  11 #include <linux/module.h>
  12 #include <linux/sched.h>
  13 #include <linux/smp.h>
  14 #include <linux/cpufreq.h>
  15 #include <linux/threads.h>
  16 #include <linux/slab.h>
  17 #include <linux/init.h>
  18 
  19 #include <asm/head.h>
  20 #include <asm/timer.h>
  21 
  22 static struct cpufreq_driver *cpufreq_us3_driver;
  23 
  24 struct us3_freq_percpu_info {
  25         struct cpufreq_frequency_table table[4];
  26 };
  27 
  28 /* Indexed by cpu number. */
  29 static struct us3_freq_percpu_info *us3_freq_table;
  30 
  31 /* UltraSPARC-III has three dividers: 1, 2, and 32.  These are controlled
  32  * in the Safari config register.
  33  */
  34 #define SAFARI_CFG_DIV_1        0x0000000000000000UL
  35 #define SAFARI_CFG_DIV_2        0x0000000040000000UL
  36 #define SAFARI_CFG_DIV_32       0x0000000080000000UL
  37 #define SAFARI_CFG_DIV_MASK     0x00000000C0000000UL
  38 
  39 static void read_safari_cfg(void *arg)
  40 {
  41         unsigned long ret, *val = arg;
  42 
  43         __asm__ __volatile__("ldxa      [%%g0] %1, %0"
  44                              : "=&r" (ret)
  45                              : "i" (ASI_SAFARI_CONFIG));
  46         *val = ret;
  47 }
  48 
  49 static void update_safari_cfg(void *arg)
  50 {
  51         unsigned long reg, *new_bits = arg;
  52 
  53         read_safari_cfg(&reg);
  54         reg &= ~SAFARI_CFG_DIV_MASK;
  55         reg |= *new_bits;
  56 
  57         __asm__ __volatile__("stxa      %0, [%%g0] %1\n\t"
  58                              "membar    #Sync"
  59                              : /* no outputs */
  60                              : "r" (reg), "i" (ASI_SAFARI_CONFIG)
  61                              : "memory");
  62 }
  63 
  64 static unsigned long get_current_freq(unsigned int cpu, unsigned long safari_cfg)
  65 {
  66         unsigned long clock_tick = sparc64_get_clock_tick(cpu) / 1000;
  67         unsigned long ret;
  68 
  69         switch (safari_cfg & SAFARI_CFG_DIV_MASK) {
  70         case SAFARI_CFG_DIV_1:
  71                 ret = clock_tick / 1;
  72                 break;
  73         case SAFARI_CFG_DIV_2:
  74                 ret = clock_tick / 2;
  75                 break;
  76         case SAFARI_CFG_DIV_32:
  77                 ret = clock_tick / 32;
  78                 break;
  79         default:
  80                 BUG();
  81         }
  82 
  83         return ret;
  84 }
  85 
  86 static unsigned int us3_freq_get(unsigned int cpu)
  87 {
  88         unsigned long reg;
  89 
  90         if (smp_call_function_single(cpu, read_safari_cfg, &reg, 1))
  91                 return 0;
  92         return get_current_freq(cpu, reg);
  93 }
  94 
  95 static int us3_freq_target(struct cpufreq_policy *policy, unsigned int index)
  96 {
  97         unsigned int cpu = policy->cpu;
  98         unsigned long new_bits, new_freq;
  99 
 100         new_freq = sparc64_get_clock_tick(cpu) / 1000;
 101         switch (index) {
 102         case 0:
 103                 new_bits = SAFARI_CFG_DIV_1;
 104                 new_freq /= 1;
 105                 break;
 106         case 1:
 107                 new_bits = SAFARI_CFG_DIV_2;
 108                 new_freq /= 2;
 109                 break;
 110         case 2:
 111                 new_bits = SAFARI_CFG_DIV_32;
 112                 new_freq /= 32;
 113                 break;
 114 
 115         default:
 116                 BUG();
 117         }
 118 
 119         return smp_call_function_single(cpu, update_safari_cfg, &new_bits, 1);
 120 }
 121 
 122 static int __init us3_freq_cpu_init(struct cpufreq_policy *policy)
 123 {
 124         unsigned int cpu = policy->cpu;
 125         unsigned long clock_tick = sparc64_get_clock_tick(cpu) / 1000;
 126         struct cpufreq_frequency_table *table =
 127                 &us3_freq_table[cpu].table[0];
 128 
 129         table[0].driver_data = 0;
 130         table[0].frequency = clock_tick / 1;
 131         table[1].driver_data = 1;
 132         table[1].frequency = clock_tick / 2;
 133         table[2].driver_data = 2;
 134         table[2].frequency = clock_tick / 32;
 135         table[3].driver_data = 0;
 136         table[3].frequency = CPUFREQ_TABLE_END;
 137 
 138         policy->cpuinfo.transition_latency = 0;
 139         policy->cur = clock_tick;
 140         policy->freq_table = table;
 141 
 142         return 0;
 143 }
 144 
 145 static int us3_freq_cpu_exit(struct cpufreq_policy *policy)
 146 {
 147         if (cpufreq_us3_driver)
 148                 us3_freq_target(policy, 0);
 149 
 150         return 0;
 151 }
 152 
 153 static int __init us3_freq_init(void)
 154 {
 155         unsigned long manuf, impl, ver;
 156         int ret;
 157 
 158         if (tlb_type != cheetah && tlb_type != cheetah_plus)
 159                 return -ENODEV;
 160 
 161         __asm__("rdpr %%ver, %0" : "=r" (ver));
 162         manuf = ((ver >> 48) & 0xffff);
 163         impl  = ((ver >> 32) & 0xffff);
 164 
 165         if (manuf == CHEETAH_MANUF &&
 166             (impl == CHEETAH_IMPL ||
 167              impl == CHEETAH_PLUS_IMPL ||
 168              impl == JAGUAR_IMPL ||
 169              impl == PANTHER_IMPL)) {
 170                 struct cpufreq_driver *driver;
 171 
 172                 ret = -ENOMEM;
 173                 driver = kzalloc(sizeof(*driver), GFP_KERNEL);
 174                 if (!driver)
 175                         goto err_out;
 176 
 177                 us3_freq_table = kzalloc((NR_CPUS * sizeof(*us3_freq_table)),
 178                         GFP_KERNEL);
 179                 if (!us3_freq_table)
 180                         goto err_out;
 181 
 182                 driver->init = us3_freq_cpu_init;
 183                 driver->verify = cpufreq_generic_frequency_table_verify;
 184                 driver->target_index = us3_freq_target;
 185                 driver->get = us3_freq_get;
 186                 driver->exit = us3_freq_cpu_exit;
 187                 strcpy(driver->name, "UltraSPARC-III");
 188 
 189                 cpufreq_us3_driver = driver;
 190                 ret = cpufreq_register_driver(driver);
 191                 if (ret)
 192                         goto err_out;
 193 
 194                 return 0;
 195 
 196 err_out:
 197                 if (driver) {
 198                         kfree(driver);
 199                         cpufreq_us3_driver = NULL;
 200                 }
 201                 kfree(us3_freq_table);
 202                 us3_freq_table = NULL;
 203                 return ret;
 204         }
 205 
 206         return -ENODEV;
 207 }
 208 
 209 static void __exit us3_freq_exit(void)
 210 {
 211         if (cpufreq_us3_driver) {
 212                 cpufreq_unregister_driver(cpufreq_us3_driver);
 213                 kfree(cpufreq_us3_driver);
 214                 cpufreq_us3_driver = NULL;
 215                 kfree(us3_freq_table);
 216                 us3_freq_table = NULL;
 217         }
 218 }
 219 
 220 MODULE_AUTHOR("David S. Miller <davem@redhat.com>");
 221 MODULE_DESCRIPTION("cpufreq driver for UltraSPARC-III");
 222 MODULE_LICENSE("GPL");
 223 
 224 module_init(us3_freq_init);
 225 module_exit(us3_freq_exit);

/* [<][>][^][v][top][bottom][index][help] */