root/drivers/cpufreq/pasemi-cpufreq.c

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

DEFINITIONS

This source file includes following definitions.
  1. get_astate_freq
  2. get_cur_astate
  3. get_gizmo_latency
  4. set_astate
  5. check_astate
  6. restore_astate
  7. pas_cpufreq_cpu_init
  8. pas_cpufreq_cpu_exit
  9. pas_cpufreq_target
  10. pas_cpufreq_init
  11. pas_cpufreq_exit

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * Copyright (C) 2007 PA Semi, Inc
   4  *
   5  * Authors: Egor Martovetsky <egor@pasemi.com>
   6  *          Olof Johansson <olof@lixom.net>
   7  *
   8  * Maintained by: Olof Johansson <olof@lixom.net>
   9  *
  10  * Based on arch/powerpc/platforms/cell/cbe_cpufreq.c:
  11  * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
  12  */
  13 
  14 #include <linux/cpufreq.h>
  15 #include <linux/timer.h>
  16 #include <linux/module.h>
  17 #include <linux/of_address.h>
  18 
  19 #include <asm/hw_irq.h>
  20 #include <asm/io.h>
  21 #include <asm/prom.h>
  22 #include <asm/time.h>
  23 #include <asm/smp.h>
  24 
  25 #define SDCASR_REG              0x0100
  26 #define SDCASR_REG_STRIDE       0x1000
  27 #define SDCPWR_CFGA0_REG        0x0100
  28 #define SDCPWR_PWST0_REG        0x0000
  29 #define SDCPWR_GIZTIME_REG      0x0440
  30 
  31 /* SDCPWR_GIZTIME_REG fields */
  32 #define SDCPWR_GIZTIME_GR       0x80000000
  33 #define SDCPWR_GIZTIME_LONGLOCK 0x000000ff
  34 
  35 /* Offset of ASR registers from SDC base */
  36 #define SDCASR_OFFSET           0x120000
  37 
  38 static void __iomem *sdcpwr_mapbase;
  39 static void __iomem *sdcasr_mapbase;
  40 
  41 /* Current astate, is used when waking up from power savings on
  42  * one core, in case the other core has switched states during
  43  * the idle time.
  44  */
  45 static int current_astate;
  46 
  47 /* We support 5(A0-A4) power states excluding turbo(A5-A6) modes */
  48 static struct cpufreq_frequency_table pas_freqs[] = {
  49         {0, 0,  0},
  50         {0, 1,  0},
  51         {0, 2,  0},
  52         {0, 3,  0},
  53         {0, 4,  0},
  54         {0, 0,  CPUFREQ_TABLE_END},
  55 };
  56 
  57 /*
  58  * hardware specific functions
  59  */
  60 
  61 static int get_astate_freq(int astate)
  62 {
  63         u32 ret;
  64         ret = in_le32(sdcpwr_mapbase + SDCPWR_CFGA0_REG + (astate * 0x10));
  65 
  66         return ret & 0x3f;
  67 }
  68 
  69 static int get_cur_astate(int cpu)
  70 {
  71         u32 ret;
  72 
  73         ret = in_le32(sdcpwr_mapbase + SDCPWR_PWST0_REG);
  74         ret = (ret >> (cpu * 4)) & 0x7;
  75 
  76         return ret;
  77 }
  78 
  79 static int get_gizmo_latency(void)
  80 {
  81         u32 giztime, ret;
  82 
  83         giztime = in_le32(sdcpwr_mapbase + SDCPWR_GIZTIME_REG);
  84 
  85         /* just provide the upper bound */
  86         if (giztime & SDCPWR_GIZTIME_GR)
  87                 ret = (giztime & SDCPWR_GIZTIME_LONGLOCK) * 128000;
  88         else
  89                 ret = (giztime & SDCPWR_GIZTIME_LONGLOCK) * 1000;
  90 
  91         return ret;
  92 }
  93 
  94 static void set_astate(int cpu, unsigned int astate)
  95 {
  96         unsigned long flags;
  97 
  98         /* Return if called before init has run */
  99         if (unlikely(!sdcasr_mapbase))
 100                 return;
 101 
 102         local_irq_save(flags);
 103 
 104         out_le32(sdcasr_mapbase + SDCASR_REG + SDCASR_REG_STRIDE*cpu, astate);
 105 
 106         local_irq_restore(flags);
 107 }
 108 
 109 int check_astate(void)
 110 {
 111         return get_cur_astate(hard_smp_processor_id());
 112 }
 113 
 114 void restore_astate(int cpu)
 115 {
 116         set_astate(cpu, current_astate);
 117 }
 118 
 119 /*
 120  * cpufreq functions
 121  */
 122 
 123 static int pas_cpufreq_cpu_init(struct cpufreq_policy *policy)
 124 {
 125         struct cpufreq_frequency_table *pos;
 126         const u32 *max_freqp;
 127         u32 max_freq;
 128         int cur_astate, idx;
 129         struct resource res;
 130         struct device_node *cpu, *dn;
 131         int err = -ENODEV;
 132 
 133         cpu = of_get_cpu_node(policy->cpu, NULL);
 134         if (!cpu)
 135                 goto out;
 136 
 137         max_freqp = of_get_property(cpu, "clock-frequency", NULL);
 138         of_node_put(cpu);
 139         if (!max_freqp) {
 140                 err = -EINVAL;
 141                 goto out;
 142         }
 143 
 144         /* we need the freq in kHz */
 145         max_freq = *max_freqp / 1000;
 146 
 147         dn = of_find_compatible_node(NULL, NULL, "1682m-sdc");
 148         if (!dn)
 149                 dn = of_find_compatible_node(NULL, NULL,
 150                                              "pasemi,pwrficient-sdc");
 151         if (!dn)
 152                 goto out;
 153         err = of_address_to_resource(dn, 0, &res);
 154         of_node_put(dn);
 155         if (err)
 156                 goto out;
 157         sdcasr_mapbase = ioremap(res.start + SDCASR_OFFSET, 0x2000);
 158         if (!sdcasr_mapbase) {
 159                 err = -EINVAL;
 160                 goto out;
 161         }
 162 
 163         dn = of_find_compatible_node(NULL, NULL, "1682m-gizmo");
 164         if (!dn)
 165                 dn = of_find_compatible_node(NULL, NULL,
 166                                              "pasemi,pwrficient-gizmo");
 167         if (!dn) {
 168                 err = -ENODEV;
 169                 goto out_unmap_sdcasr;
 170         }
 171         err = of_address_to_resource(dn, 0, &res);
 172         of_node_put(dn);
 173         if (err)
 174                 goto out_unmap_sdcasr;
 175         sdcpwr_mapbase = ioremap(res.start, 0x1000);
 176         if (!sdcpwr_mapbase) {
 177                 err = -EINVAL;
 178                 goto out_unmap_sdcasr;
 179         }
 180 
 181         pr_debug("init cpufreq on CPU %d\n", policy->cpu);
 182         pr_debug("max clock-frequency is at %u kHz\n", max_freq);
 183         pr_debug("initializing frequency table\n");
 184 
 185         /* initialize frequency table */
 186         cpufreq_for_each_entry_idx(pos, pas_freqs, idx) {
 187                 pos->frequency = get_astate_freq(pos->driver_data) * 100000;
 188                 pr_debug("%d: %d\n", idx, pos->frequency);
 189         }
 190 
 191         cur_astate = get_cur_astate(policy->cpu);
 192         pr_debug("current astate is at %d\n",cur_astate);
 193 
 194         policy->cur = pas_freqs[cur_astate].frequency;
 195         ppc_proc_freq = policy->cur * 1000ul;
 196 
 197         cpufreq_generic_init(policy, pas_freqs, get_gizmo_latency());
 198         return 0;
 199 
 200 out_unmap_sdcasr:
 201         iounmap(sdcasr_mapbase);
 202 out:
 203         return err;
 204 }
 205 
 206 static int pas_cpufreq_cpu_exit(struct cpufreq_policy *policy)
 207 {
 208         /*
 209          * We don't support CPU hotplug. Don't unmap after the system
 210          * has already made it to a running state.
 211          */
 212         if (system_state >= SYSTEM_RUNNING)
 213                 return 0;
 214 
 215         if (sdcasr_mapbase)
 216                 iounmap(sdcasr_mapbase);
 217         if (sdcpwr_mapbase)
 218                 iounmap(sdcpwr_mapbase);
 219 
 220         return 0;
 221 }
 222 
 223 static int pas_cpufreq_target(struct cpufreq_policy *policy,
 224                               unsigned int pas_astate_new)
 225 {
 226         int i;
 227 
 228         pr_debug("setting frequency for cpu %d to %d kHz, 1/%d of max frequency\n",
 229                  policy->cpu,
 230                  pas_freqs[pas_astate_new].frequency,
 231                  pas_freqs[pas_astate_new].driver_data);
 232 
 233         current_astate = pas_astate_new;
 234 
 235         for_each_online_cpu(i)
 236                 set_astate(i, pas_astate_new);
 237 
 238         ppc_proc_freq = pas_freqs[pas_astate_new].frequency * 1000ul;
 239         return 0;
 240 }
 241 
 242 static struct cpufreq_driver pas_cpufreq_driver = {
 243         .name           = "pas-cpufreq",
 244         .flags          = CPUFREQ_CONST_LOOPS,
 245         .init           = pas_cpufreq_cpu_init,
 246         .exit           = pas_cpufreq_cpu_exit,
 247         .verify         = cpufreq_generic_frequency_table_verify,
 248         .target_index   = pas_cpufreq_target,
 249         .attr           = cpufreq_generic_attr,
 250 };
 251 
 252 /*
 253  * module init and destoy
 254  */
 255 
 256 static int __init pas_cpufreq_init(void)
 257 {
 258         if (!of_machine_is_compatible("PA6T-1682M") &&
 259             !of_machine_is_compatible("pasemi,pwrficient"))
 260                 return -ENODEV;
 261 
 262         return cpufreq_register_driver(&pas_cpufreq_driver);
 263 }
 264 
 265 static void __exit pas_cpufreq_exit(void)
 266 {
 267         cpufreq_unregister_driver(&pas_cpufreq_driver);
 268 }
 269 
 270 module_init(pas_cpufreq_init);
 271 module_exit(pas_cpufreq_exit);
 272 
 273 MODULE_LICENSE("GPL");
 274 MODULE_AUTHOR("Egor Martovetsky <egor@pasemi.com>, Olof Johansson <olof@lixom.net>");

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