1fa5635a2SAndrew Bresticker /* 2fa5635a2SAndrew Bresticker * This file is subject to the terms and conditions of the GNU General Public 3fa5635a2SAndrew Bresticker * License. See the file "COPYING" in the main directory of this archive 4fa5635a2SAndrew Bresticker * for more details. 5fa5635a2SAndrew Bresticker * 6fa5635a2SAndrew Bresticker * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved. 7fa5635a2SAndrew Bresticker */ 85b4e8453SAndrew Bresticker #include <linux/clk.h> 9a331ce63SAndrew Bresticker #include <linux/clockchips.h> 10e4752dbbSAndrew Bresticker #include <linux/cpu.h> 11fa5635a2SAndrew Bresticker #include <linux/init.h> 12a331ce63SAndrew Bresticker #include <linux/interrupt.h> 13fa5635a2SAndrew Bresticker #include <linux/irqchip/mips-gic.h> 14e4752dbbSAndrew Bresticker #include <linux/notifier.h> 15e12aa828SAndrew Bresticker #include <linux/of_irq.h> 16a331ce63SAndrew Bresticker #include <linux/percpu.h> 17a331ce63SAndrew Bresticker #include <linux/smp.h> 18fa5635a2SAndrew Bresticker #include <linux/time.h> 19fa5635a2SAndrew Bresticker 205fee56e0SAndrew Bresticker static DEFINE_PER_CPU(struct clock_event_device, gic_clockevent_device); 21e4752dbbSAndrew Bresticker static int gic_timer_irq; 22b0854514SAndrew Bresticker static unsigned int gic_frequency; 23a331ce63SAndrew Bresticker 24a331ce63SAndrew Bresticker static int gic_next_event(unsigned long delta, struct clock_event_device *evt) 25a331ce63SAndrew Bresticker { 26a331ce63SAndrew Bresticker u64 cnt; 27a331ce63SAndrew Bresticker int res; 28a331ce63SAndrew Bresticker 29a331ce63SAndrew Bresticker cnt = gic_read_count(); 30a331ce63SAndrew Bresticker cnt += (u64)delta; 31a331ce63SAndrew Bresticker gic_write_cpu_compare(cnt, cpumask_first(evt->cpumask)); 32a331ce63SAndrew Bresticker res = ((int)(gic_read_count() - cnt) >= 0) ? -ETIME : 0; 33a331ce63SAndrew Bresticker return res; 34a331ce63SAndrew Bresticker } 35a331ce63SAndrew Bresticker 365fee56e0SAndrew Bresticker static irqreturn_t gic_compare_interrupt(int irq, void *dev_id) 37a331ce63SAndrew Bresticker { 38f7ea3060SAndrew Bresticker struct clock_event_device *cd = dev_id; 39a331ce63SAndrew Bresticker 40a331ce63SAndrew Bresticker gic_write_compare(gic_read_compare()); 41a331ce63SAndrew Bresticker cd->event_handler(cd); 42a331ce63SAndrew Bresticker return IRQ_HANDLED; 43a331ce63SAndrew Bresticker } 44a331ce63SAndrew Bresticker 45a331ce63SAndrew Bresticker struct irqaction gic_compare_irqaction = { 46a331ce63SAndrew Bresticker .handler = gic_compare_interrupt, 47f7ea3060SAndrew Bresticker .percpu_dev_id = &gic_clockevent_device, 48a331ce63SAndrew Bresticker .flags = IRQF_PERCPU | IRQF_TIMER, 49a331ce63SAndrew Bresticker .name = "timer", 50a331ce63SAndrew Bresticker }; 51a331ce63SAndrew Bresticker 522dab9093SRichard Cochran static void gic_clockevent_cpu_init(unsigned int cpu, 532dab9093SRichard Cochran struct clock_event_device *cd) 54a331ce63SAndrew Bresticker { 55a331ce63SAndrew Bresticker cd->name = "MIPS GIC"; 56a331ce63SAndrew Bresticker cd->features = CLOCK_EVT_FEAT_ONESHOT | 57a331ce63SAndrew Bresticker CLOCK_EVT_FEAT_C3STOP; 58a331ce63SAndrew Bresticker 59a45da565SAndrew Bresticker cd->rating = 350; 60e4752dbbSAndrew Bresticker cd->irq = gic_timer_irq; 61a331ce63SAndrew Bresticker cd->cpumask = cpumask_of(cpu); 62a331ce63SAndrew Bresticker cd->set_next_event = gic_next_event; 63a331ce63SAndrew Bresticker 64b695d8e6SAndrew Bresticker clockevents_config_and_register(cd, gic_frequency, 0x300, 0x7fffffff); 65a331ce63SAndrew Bresticker 66e4752dbbSAndrew Bresticker enable_percpu_irq(gic_timer_irq, IRQ_TYPE_NONE); 67a331ce63SAndrew Bresticker } 68a331ce63SAndrew Bresticker 69e4752dbbSAndrew Bresticker static void gic_clockevent_cpu_exit(struct clock_event_device *cd) 70e4752dbbSAndrew Bresticker { 71e4752dbbSAndrew Bresticker disable_percpu_irq(gic_timer_irq); 72e4752dbbSAndrew Bresticker } 73e4752dbbSAndrew Bresticker 74fc6a6772SEzequiel Garcia static void gic_update_frequency(void *data) 75fc6a6772SEzequiel Garcia { 76fc6a6772SEzequiel Garcia unsigned long rate = (unsigned long)data; 77fc6a6772SEzequiel Garcia 78fc6a6772SEzequiel Garcia clockevents_update_freq(this_cpu_ptr(&gic_clockevent_device), rate); 79fc6a6772SEzequiel Garcia } 80fc6a6772SEzequiel Garcia 812dab9093SRichard Cochran static int gic_starting_cpu(unsigned int cpu) 82e4752dbbSAndrew Bresticker { 832dab9093SRichard Cochran gic_clockevent_cpu_init(cpu, this_cpu_ptr(&gic_clockevent_device)); 842dab9093SRichard Cochran return 0; 85e4752dbbSAndrew Bresticker } 86e4752dbbSAndrew Bresticker 87fc6a6772SEzequiel Garcia static int gic_clk_notifier(struct notifier_block *nb, unsigned long action, 88fc6a6772SEzequiel Garcia void *data) 89fc6a6772SEzequiel Garcia { 90fc6a6772SEzequiel Garcia struct clk_notifier_data *cnd = data; 91fc6a6772SEzequiel Garcia 92fc6a6772SEzequiel Garcia if (action == POST_RATE_CHANGE) 93fc6a6772SEzequiel Garcia on_each_cpu(gic_update_frequency, (void *)cnd->new_rate, 1); 94fc6a6772SEzequiel Garcia 95fc6a6772SEzequiel Garcia return NOTIFY_OK; 96fc6a6772SEzequiel Garcia } 97fc6a6772SEzequiel Garcia 982dab9093SRichard Cochran static int gic_dying_cpu(unsigned int cpu) 992dab9093SRichard Cochran { 1002dab9093SRichard Cochran gic_clockevent_cpu_exit(this_cpu_ptr(&gic_clockevent_device)); 1012dab9093SRichard Cochran return 0; 1022dab9093SRichard Cochran } 103e4752dbbSAndrew Bresticker 104fc6a6772SEzequiel Garcia static struct notifier_block gic_clk_nb = { 105fc6a6772SEzequiel Garcia .notifier_call = gic_clk_notifier, 106fc6a6772SEzequiel Garcia }; 107fc6a6772SEzequiel Garcia 108e4752dbbSAndrew Bresticker static int gic_clockevent_init(void) 109e4752dbbSAndrew Bresticker { 110f95ac855SEzequiel Garcia int ret; 111f95ac855SEzequiel Garcia 1126982530eSPaul Burton if (!gic_frequency) 113e4752dbbSAndrew Bresticker return -ENXIO; 114e4752dbbSAndrew Bresticker 115f95ac855SEzequiel Garcia ret = setup_percpu_irq(gic_timer_irq, &gic_compare_irqaction); 1162fd0c93cSPaul Burton if (ret < 0) { 1172fd0c93cSPaul Burton pr_err("GIC timer IRQ %d setup failed: %d\n", 1182fd0c93cSPaul Burton gic_timer_irq, ret); 119f95ac855SEzequiel Garcia return ret; 1202fd0c93cSPaul Burton } 121e4752dbbSAndrew Bresticker 1222dab9093SRichard Cochran cpuhp_setup_state(CPUHP_AP_MIPS_GIC_TIMER_STARTING, 123*73c1b41eSThomas Gleixner "clockevents/mips/gic/timer:starting", 124*73c1b41eSThomas Gleixner gic_starting_cpu, gic_dying_cpu); 125a331ce63SAndrew Bresticker return 0; 126a331ce63SAndrew Bresticker } 127a331ce63SAndrew Bresticker 128fa5635a2SAndrew Bresticker static cycle_t gic_hpt_read(struct clocksource *cs) 129fa5635a2SAndrew Bresticker { 130fa5635a2SAndrew Bresticker return gic_read_count(); 131fa5635a2SAndrew Bresticker } 132fa5635a2SAndrew Bresticker 133fa5635a2SAndrew Bresticker static struct clocksource gic_clocksource = { 134fa5635a2SAndrew Bresticker .name = "GIC", 135fa5635a2SAndrew Bresticker .read = gic_hpt_read, 136fa5635a2SAndrew Bresticker .flags = CLOCK_SOURCE_IS_CONTINUOUS, 137a7f4df4eSAlex Smith .archdata = { .vdso_clock_mode = VDSO_CLOCK_GIC }, 138fa5635a2SAndrew Bresticker }; 139fa5635a2SAndrew Bresticker 140d8152bf8SDaniel Lezcano static int __init __gic_clocksource_init(void) 141fa5635a2SAndrew Bresticker { 142f95ac855SEzequiel Garcia int ret; 143f95ac855SEzequiel Garcia 144fa5635a2SAndrew Bresticker /* Set clocksource mask. */ 145fa5635a2SAndrew Bresticker gic_clocksource.mask = CLOCKSOURCE_MASK(gic_get_count_width()); 146fa5635a2SAndrew Bresticker 147fa5635a2SAndrew Bresticker /* Calculate a somewhat reasonable rating value. */ 148e12aa828SAndrew Bresticker gic_clocksource.rating = 200 + gic_frequency / 10000000; 149fa5635a2SAndrew Bresticker 150f95ac855SEzequiel Garcia ret = clocksource_register_hz(&gic_clocksource, gic_frequency); 151f95ac855SEzequiel Garcia if (ret < 0) 152f95ac855SEzequiel Garcia pr_warn("GIC: Unable to register clocksource\n"); 153d8152bf8SDaniel Lezcano 154d8152bf8SDaniel Lezcano return ret; 155fa5635a2SAndrew Bresticker } 156e12aa828SAndrew Bresticker 157e12aa828SAndrew Bresticker void __init gic_clocksource_init(unsigned int frequency) 158e12aa828SAndrew Bresticker { 159e12aa828SAndrew Bresticker gic_frequency = frequency; 160e12aa828SAndrew Bresticker gic_timer_irq = MIPS_GIC_IRQ_BASE + 161e12aa828SAndrew Bresticker GIC_LOCAL_TO_HWIRQ(GIC_LOCAL_INT_COMPARE); 162e12aa828SAndrew Bresticker 163e12aa828SAndrew Bresticker __gic_clocksource_init(); 16467d4e669SEzequiel Garcia gic_clockevent_init(); 16567d4e669SEzequiel Garcia 16667d4e669SEzequiel Garcia /* And finally start the counter */ 16767d4e669SEzequiel Garcia gic_start_count(); 168e12aa828SAndrew Bresticker } 169e12aa828SAndrew Bresticker 170be5769e2SPaul Gortmaker static int __init gic_clocksource_of_init(struct device_node *node) 171e12aa828SAndrew Bresticker { 1725b4e8453SAndrew Bresticker struct clk *clk; 173fc6a6772SEzequiel Garcia int ret; 1745b4e8453SAndrew Bresticker 175d8152bf8SDaniel Lezcano if (!gic_present || !node->parent || 176d8152bf8SDaniel Lezcano !of_device_is_compatible(node->parent, "mti,gic")) { 177d8152bf8SDaniel Lezcano pr_warn("No DT definition for the mips gic driver"); 178d8152bf8SDaniel Lezcano return -ENXIO; 179d8152bf8SDaniel Lezcano } 180e12aa828SAndrew Bresticker 1815b4e8453SAndrew Bresticker clk = of_clk_get(node, 0); 1825b4e8453SAndrew Bresticker if (!IS_ERR(clk)) { 183eb811c73SEzequiel Garcia if (clk_prepare_enable(clk) < 0) { 184eb811c73SEzequiel Garcia pr_err("GIC failed to enable clock\n"); 1855b4e8453SAndrew Bresticker clk_put(clk); 186d8152bf8SDaniel Lezcano return PTR_ERR(clk); 187eb811c73SEzequiel Garcia } 188eb811c73SEzequiel Garcia 189eb811c73SEzequiel Garcia gic_frequency = clk_get_rate(clk); 1905b4e8453SAndrew Bresticker } else if (of_property_read_u32(node, "clock-frequency", 1915b4e8453SAndrew Bresticker &gic_frequency)) { 192e12aa828SAndrew Bresticker pr_err("GIC frequency not specified.\n"); 193d8152bf8SDaniel Lezcano return -EINVAL;; 194e12aa828SAndrew Bresticker } 195e12aa828SAndrew Bresticker gic_timer_irq = irq_of_parse_and_map(node, 0); 196e12aa828SAndrew Bresticker if (!gic_timer_irq) { 197e12aa828SAndrew Bresticker pr_err("GIC timer IRQ not specified.\n"); 198d8152bf8SDaniel Lezcano return -EINVAL;; 199e12aa828SAndrew Bresticker } 200e12aa828SAndrew Bresticker 201d8152bf8SDaniel Lezcano ret = __gic_clocksource_init(); 202d8152bf8SDaniel Lezcano if (ret) 203d8152bf8SDaniel Lezcano return ret; 204fc6a6772SEzequiel Garcia 205fc6a6772SEzequiel Garcia ret = gic_clockevent_init(); 206fc6a6772SEzequiel Garcia if (!ret && !IS_ERR(clk)) { 207fc6a6772SEzequiel Garcia if (clk_notifier_register(clk, &gic_clk_nb) < 0) 208fc6a6772SEzequiel Garcia pr_warn("GIC: Unable to register clock notifier\n"); 209fc6a6772SEzequiel Garcia } 21067d4e669SEzequiel Garcia 21167d4e669SEzequiel Garcia /* And finally start the counter */ 21267d4e669SEzequiel Garcia gic_start_count(); 213d8152bf8SDaniel Lezcano 214d8152bf8SDaniel Lezcano return 0; 215e12aa828SAndrew Bresticker } 216177cf6e5SDaniel Lezcano CLOCKSOURCE_OF_DECLARE(mips_gic_timer, "mti,gic-timer", 217e12aa828SAndrew Bresticker gic_clocksource_of_init); 218