root/drivers/clocksource/mips-gic-timer.c

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

DEFINITIONS

This source file includes following definitions.
  1. gic_read_count
  2. gic_next_event
  3. gic_compare_interrupt
  4. gic_clockevent_cpu_init
  5. gic_clockevent_cpu_exit
  6. gic_update_frequency
  7. gic_starting_cpu
  8. gic_clk_notifier
  9. gic_dying_cpu
  10. gic_clockevent_init
  11. gic_hpt_read
  12. __gic_clocksource_init
  13. gic_clocksource_of_init

   1 /*
   2  * This file is subject to the terms and conditions of the GNU General Public
   3  * License.  See the file "COPYING" in the main directory of this archive
   4  * for more details.
   5  *
   6  * Copyright (C) 2012 MIPS Technologies, Inc.  All rights reserved.
   7  */
   8 
   9 #define pr_fmt(fmt) "mips-gic-timer: " fmt
  10 
  11 #include <linux/clk.h>
  12 #include <linux/clockchips.h>
  13 #include <linux/cpu.h>
  14 #include <linux/init.h>
  15 #include <linux/interrupt.h>
  16 #include <linux/notifier.h>
  17 #include <linux/of_irq.h>
  18 #include <linux/percpu.h>
  19 #include <linux/smp.h>
  20 #include <linux/time.h>
  21 #include <asm/mips-cps.h>
  22 
  23 static DEFINE_PER_CPU(struct clock_event_device, gic_clockevent_device);
  24 static int gic_timer_irq;
  25 static unsigned int gic_frequency;
  26 
  27 static u64 notrace gic_read_count(void)
  28 {
  29         unsigned int hi, hi2, lo;
  30 
  31         if (mips_cm_is64)
  32                 return read_gic_counter();
  33 
  34         do {
  35                 hi = read_gic_counter_32h();
  36                 lo = read_gic_counter_32l();
  37                 hi2 = read_gic_counter_32h();
  38         } while (hi2 != hi);
  39 
  40         return (((u64) hi) << 32) + lo;
  41 }
  42 
  43 static int gic_next_event(unsigned long delta, struct clock_event_device *evt)
  44 {
  45         int cpu = cpumask_first(evt->cpumask);
  46         u64 cnt;
  47         int res;
  48 
  49         cnt = gic_read_count();
  50         cnt += (u64)delta;
  51         if (cpu == raw_smp_processor_id()) {
  52                 write_gic_vl_compare(cnt);
  53         } else {
  54                 write_gic_vl_other(mips_cm_vp_id(cpu));
  55                 write_gic_vo_compare(cnt);
  56         }
  57         res = ((int)(gic_read_count() - cnt) >= 0) ? -ETIME : 0;
  58         return res;
  59 }
  60 
  61 static irqreturn_t gic_compare_interrupt(int irq, void *dev_id)
  62 {
  63         struct clock_event_device *cd = dev_id;
  64 
  65         write_gic_vl_compare(read_gic_vl_compare());
  66         cd->event_handler(cd);
  67         return IRQ_HANDLED;
  68 }
  69 
  70 static struct irqaction gic_compare_irqaction = {
  71         .handler = gic_compare_interrupt,
  72         .percpu_dev_id = &gic_clockevent_device,
  73         .flags = IRQF_PERCPU | IRQF_TIMER,
  74         .name = "timer",
  75 };
  76 
  77 static void gic_clockevent_cpu_init(unsigned int cpu,
  78                                     struct clock_event_device *cd)
  79 {
  80         cd->name                = "MIPS GIC";
  81         cd->features            = CLOCK_EVT_FEAT_ONESHOT |
  82                                   CLOCK_EVT_FEAT_C3STOP;
  83 
  84         cd->rating              = 350;
  85         cd->irq                 = gic_timer_irq;
  86         cd->cpumask             = cpumask_of(cpu);
  87         cd->set_next_event      = gic_next_event;
  88 
  89         clockevents_config_and_register(cd, gic_frequency, 0x300, 0x7fffffff);
  90 
  91         enable_percpu_irq(gic_timer_irq, IRQ_TYPE_NONE);
  92 }
  93 
  94 static void gic_clockevent_cpu_exit(struct clock_event_device *cd)
  95 {
  96         disable_percpu_irq(gic_timer_irq);
  97 }
  98 
  99 static void gic_update_frequency(void *data)
 100 {
 101         unsigned long rate = (unsigned long)data;
 102 
 103         clockevents_update_freq(this_cpu_ptr(&gic_clockevent_device), rate);
 104 }
 105 
 106 static int gic_starting_cpu(unsigned int cpu)
 107 {
 108         gic_clockevent_cpu_init(cpu, this_cpu_ptr(&gic_clockevent_device));
 109         return 0;
 110 }
 111 
 112 static int gic_clk_notifier(struct notifier_block *nb, unsigned long action,
 113                             void *data)
 114 {
 115         struct clk_notifier_data *cnd = data;
 116 
 117         if (action == POST_RATE_CHANGE)
 118                 on_each_cpu(gic_update_frequency, (void *)cnd->new_rate, 1);
 119 
 120         return NOTIFY_OK;
 121 }
 122 
 123 static int gic_dying_cpu(unsigned int cpu)
 124 {
 125         gic_clockevent_cpu_exit(this_cpu_ptr(&gic_clockevent_device));
 126         return 0;
 127 }
 128 
 129 static struct notifier_block gic_clk_nb = {
 130         .notifier_call = gic_clk_notifier,
 131 };
 132 
 133 static int gic_clockevent_init(void)
 134 {
 135         int ret;
 136 
 137         if (!gic_frequency)
 138                 return -ENXIO;
 139 
 140         ret = setup_percpu_irq(gic_timer_irq, &gic_compare_irqaction);
 141         if (ret < 0) {
 142                 pr_err("IRQ %d setup failed (%d)\n", gic_timer_irq, ret);
 143                 return ret;
 144         }
 145 
 146         cpuhp_setup_state(CPUHP_AP_MIPS_GIC_TIMER_STARTING,
 147                           "clockevents/mips/gic/timer:starting",
 148                           gic_starting_cpu, gic_dying_cpu);
 149         return 0;
 150 }
 151 
 152 static u64 gic_hpt_read(struct clocksource *cs)
 153 {
 154         return gic_read_count();
 155 }
 156 
 157 static struct clocksource gic_clocksource = {
 158         .name           = "GIC",
 159         .read           = gic_hpt_read,
 160         .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 161         .archdata       = { .vdso_clock_mode = VDSO_CLOCK_GIC },
 162 };
 163 
 164 static int __init __gic_clocksource_init(void)
 165 {
 166         unsigned int count_width;
 167         int ret;
 168 
 169         /* Set clocksource mask. */
 170         count_width = read_gic_config() & GIC_CONFIG_COUNTBITS;
 171         count_width >>= __ffs(GIC_CONFIG_COUNTBITS);
 172         count_width *= 4;
 173         count_width += 32;
 174         gic_clocksource.mask = CLOCKSOURCE_MASK(count_width);
 175 
 176         /* Calculate a somewhat reasonable rating value. */
 177         gic_clocksource.rating = 200 + gic_frequency / 10000000;
 178 
 179         ret = clocksource_register_hz(&gic_clocksource, gic_frequency);
 180         if (ret < 0)
 181                 pr_warn("Unable to register clocksource\n");
 182 
 183         return ret;
 184 }
 185 
 186 static int __init gic_clocksource_of_init(struct device_node *node)
 187 {
 188         struct clk *clk;
 189         int ret;
 190 
 191         if (!mips_gic_present() || !node->parent ||
 192             !of_device_is_compatible(node->parent, "mti,gic")) {
 193                 pr_warn("No DT definition\n");
 194                 return -ENXIO;
 195         }
 196 
 197         clk = of_clk_get(node, 0);
 198         if (!IS_ERR(clk)) {
 199                 ret = clk_prepare_enable(clk);
 200                 if (ret < 0) {
 201                         pr_err("Failed to enable clock\n");
 202                         clk_put(clk);
 203                         return ret;
 204                 }
 205 
 206                 gic_frequency = clk_get_rate(clk);
 207         } else if (of_property_read_u32(node, "clock-frequency",
 208                                         &gic_frequency)) {
 209                 pr_err("Frequency not specified\n");
 210                 return -EINVAL;
 211         }
 212         gic_timer_irq = irq_of_parse_and_map(node, 0);
 213         if (!gic_timer_irq) {
 214                 pr_err("IRQ not specified\n");
 215                 return -EINVAL;
 216         }
 217 
 218         ret = __gic_clocksource_init();
 219         if (ret)
 220                 return ret;
 221 
 222         ret = gic_clockevent_init();
 223         if (!ret && !IS_ERR(clk)) {
 224                 if (clk_notifier_register(clk, &gic_clk_nb) < 0)
 225                         pr_warn("Unable to register clock notifier\n");
 226         }
 227 
 228         /* And finally start the counter */
 229         clear_gic_config(GIC_CONFIG_COUNTSTOP);
 230 
 231         return 0;
 232 }
 233 TIMER_OF_DECLARE(mips_gic_timer, "mti,gic-timer",
 234                        gic_clocksource_of_init);

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