linux/arch/arm/mach-integrator/cpu.c
<<
>>
Prefs
   1/*
   2 *  linux/arch/arm/mach-integrator/cpu.c
   3 *
   4 *  Copyright (C) 2001-2002 Deep Blue Solutions Ltd.
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License version 2 as
   8 * published by the Free Software Foundation.
   9 *
  10 * CPU support functions
  11 */
  12#include <linux/module.h>
  13#include <linux/types.h>
  14#include <linux/kernel.h>
  15#include <linux/cpufreq.h>
  16#include <linux/slab.h>
  17#include <linux/sched.h>
  18#include <linux/smp.h>
  19#include <linux/init.h>
  20#include <linux/io.h>
  21
  22#include <mach/hardware.h>
  23#include <asm/mach-types.h>
  24#include <asm/hardware/icst525.h>
  25
  26static struct cpufreq_driver integrator_driver;
  27
  28#define CM_ID   (IO_ADDRESS(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_ID_OFFSET)
  29#define CM_OSC  (IO_ADDRESS(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_OSC_OFFSET)
  30#define CM_STAT (IO_ADDRESS(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_STAT_OFFSET)
  31#define CM_LOCK (IO_ADDRESS(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_LOCK_OFFSET)
  32
  33static const struct icst525_params lclk_params = {
  34        .ref            = 24000,
  35        .vco_max        = 320000,
  36        .vd_min         = 8,
  37        .vd_max         = 132,
  38        .rd_min         = 24,
  39        .rd_max         = 24,
  40};
  41
  42static const struct icst525_params cclk_params = {
  43        .ref            = 24000,
  44        .vco_max        = 320000,
  45        .vd_min         = 12,
  46        .vd_max         = 160,
  47        .rd_min         = 24,
  48        .rd_max         = 24,
  49};
  50
  51/*
  52 * Validate the speed policy.
  53 */
  54static int integrator_verify_policy(struct cpufreq_policy *policy)
  55{
  56        struct icst525_vco vco;
  57
  58        cpufreq_verify_within_limits(policy, 
  59                                     policy->cpuinfo.min_freq, 
  60                                     policy->cpuinfo.max_freq);
  61
  62        vco = icst525_khz_to_vco(&cclk_params, policy->max);
  63        policy->max = icst525_khz(&cclk_params, vco);
  64
  65        vco = icst525_khz_to_vco(&cclk_params, policy->min);
  66        policy->min = icst525_khz(&cclk_params, vco);
  67
  68        cpufreq_verify_within_limits(policy, 
  69                                     policy->cpuinfo.min_freq, 
  70                                     policy->cpuinfo.max_freq);
  71
  72        return 0;
  73}
  74
  75
  76static int integrator_set_target(struct cpufreq_policy *policy,
  77                                 unsigned int target_freq,
  78                                 unsigned int relation)
  79{
  80        cpumask_t cpus_allowed;
  81        int cpu = policy->cpu;
  82        struct icst525_vco vco;
  83        struct cpufreq_freqs freqs;
  84        u_int cm_osc;
  85
  86        /*
  87         * Save this threads cpus_allowed mask.
  88         */
  89        cpus_allowed = current->cpus_allowed;
  90
  91        /*
  92         * Bind to the specified CPU.  When this call returns,
  93         * we should be running on the right CPU.
  94         */
  95        set_cpus_allowed(current, cpumask_of_cpu(cpu));
  96        BUG_ON(cpu != smp_processor_id());
  97
  98        /* get current setting */
  99        cm_osc = __raw_readl(CM_OSC);
 100
 101        if (machine_is_integrator()) {
 102                vco.s = (cm_osc >> 8) & 7;
 103        } else if (machine_is_cintegrator()) {
 104                vco.s = 1;
 105        }
 106        vco.v = cm_osc & 255;
 107        vco.r = 22;
 108        freqs.old = icst525_khz(&cclk_params, vco);
 109
 110        /* icst525_khz_to_vco rounds down -- so we need the next
 111         * larger freq in case of CPUFREQ_RELATION_L.
 112         */
 113        if (relation == CPUFREQ_RELATION_L)
 114                target_freq += 999;
 115        if (target_freq > policy->max)
 116                target_freq = policy->max;
 117        vco = icst525_khz_to_vco(&cclk_params, target_freq);
 118        freqs.new = icst525_khz(&cclk_params, vco);
 119
 120        freqs.cpu = policy->cpu;
 121
 122        if (freqs.old == freqs.new) {
 123                set_cpus_allowed(current, cpus_allowed);
 124                return 0;
 125        }
 126
 127        cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
 128
 129        cm_osc = __raw_readl(CM_OSC);
 130
 131        if (machine_is_integrator()) {
 132                cm_osc &= 0xfffff800;
 133                cm_osc |= vco.s << 8;
 134        } else if (machine_is_cintegrator()) {
 135                cm_osc &= 0xffffff00;
 136        }
 137        cm_osc |= vco.v;
 138
 139        __raw_writel(0xa05f, CM_LOCK);
 140        __raw_writel(cm_osc, CM_OSC);
 141        __raw_writel(0, CM_LOCK);
 142
 143        /*
 144         * Restore the CPUs allowed mask.
 145         */
 146        set_cpus_allowed(current, cpus_allowed);
 147
 148        cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
 149
 150        return 0;
 151}
 152
 153static unsigned int integrator_get(unsigned int cpu)
 154{
 155        cpumask_t cpus_allowed;
 156        unsigned int current_freq;
 157        u_int cm_osc;
 158        struct icst525_vco vco;
 159
 160        cpus_allowed = current->cpus_allowed;
 161
 162        set_cpus_allowed(current, cpumask_of_cpu(cpu));
 163        BUG_ON(cpu != smp_processor_id());
 164
 165        /* detect memory etc. */
 166        cm_osc = __raw_readl(CM_OSC);
 167
 168        if (machine_is_integrator()) {
 169                vco.s = (cm_osc >> 8) & 7;
 170        } else if (machine_is_cintegrator()) {
 171                vco.s = 1;
 172        }
 173        vco.v = cm_osc & 255;
 174        vco.r = 22;
 175
 176        current_freq = icst525_khz(&cclk_params, vco); /* current freq */
 177
 178        set_cpus_allowed(current, cpus_allowed);
 179
 180        return current_freq;
 181}
 182
 183static int integrator_cpufreq_init(struct cpufreq_policy *policy)
 184{
 185
 186        /* set default policy and cpuinfo */
 187        policy->cpuinfo.max_freq = 160000;
 188        policy->cpuinfo.min_freq = 12000;
 189        policy->cpuinfo.transition_latency = 1000000; /* 1 ms, assumed */
 190        policy->cur = policy->min = policy->max = integrator_get(policy->cpu);
 191
 192        return 0;
 193}
 194
 195static struct cpufreq_driver integrator_driver = {
 196        .verify         = integrator_verify_policy,
 197        .target         = integrator_set_target,
 198        .get            = integrator_get,
 199        .init           = integrator_cpufreq_init,
 200        .name           = "integrator",
 201};
 202
 203static int __init integrator_cpu_init(void)
 204{
 205        return cpufreq_register_driver(&integrator_driver);
 206}
 207
 208static void __exit integrator_cpu_exit(void)
 209{
 210        cpufreq_unregister_driver(&integrator_driver);
 211}
 212
 213MODULE_AUTHOR ("Russell M. King");
 214MODULE_DESCRIPTION ("cpufreq driver for ARM Integrator CPUs");
 215MODULE_LICENSE ("GPL");
 216
 217module_init(integrator_cpu_init);
 218module_exit(integrator_cpu_exit);
 219
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.