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> 13e4752dbbSAndrew Bresticker #include <linux/notifier.h> 14e12aa828SAndrew Bresticker #include <linux/of_irq.h> 15a331ce63SAndrew Bresticker #include <linux/percpu.h> 16a331ce63SAndrew Bresticker #include <linux/smp.h> 17fa5635a2SAndrew Bresticker #include <linux/time.h> 18e07127a0SPaul Burton #include <asm/mips-cps.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 24e07127a0SPaul Burton static u64 notrace gic_read_count(void) 25e07127a0SPaul Burton { 26e07127a0SPaul Burton unsigned int hi, hi2, lo; 27e07127a0SPaul Burton 28e07127a0SPaul Burton if (mips_cm_is64) 29e07127a0SPaul Burton return read_gic_counter(); 30e07127a0SPaul Burton 31e07127a0SPaul Burton do { 32e07127a0SPaul Burton hi = read_gic_counter_32h(); 33e07127a0SPaul Burton lo = read_gic_counter_32l(); 34e07127a0SPaul Burton hi2 = read_gic_counter_32h(); 35e07127a0SPaul Burton } while (hi2 != hi); 36e07127a0SPaul Burton 37e07127a0SPaul Burton return (((u64) hi) << 32) + lo; 38e07127a0SPaul Burton } 39e07127a0SPaul Burton 40a331ce63SAndrew Bresticker static int gic_next_event(unsigned long delta, struct clock_event_device *evt) 41a331ce63SAndrew Bresticker { 42f16ff2bdSMatt Redfearn int cpu = cpumask_first(evt->cpumask); 43a331ce63SAndrew Bresticker u64 cnt; 44a331ce63SAndrew Bresticker int res; 45a331ce63SAndrew Bresticker 46a331ce63SAndrew Bresticker cnt = gic_read_count(); 47a331ce63SAndrew Bresticker cnt += (u64)delta; 48f16ff2bdSMatt Redfearn if (cpu == raw_smp_processor_id()) { 49f16ff2bdSMatt Redfearn write_gic_vl_compare(cnt); 50f16ff2bdSMatt Redfearn } else { 51f16ff2bdSMatt Redfearn write_gic_vl_other(mips_cm_vp_id(cpu)); 52e07127a0SPaul Burton write_gic_vo_compare(cnt); 53f16ff2bdSMatt Redfearn } 54a331ce63SAndrew Bresticker res = ((int)(gic_read_count() - cnt) >= 0) ? -ETIME : 0; 55a331ce63SAndrew Bresticker return res; 56a331ce63SAndrew Bresticker } 57a331ce63SAndrew Bresticker 585fee56e0SAndrew Bresticker static irqreturn_t gic_compare_interrupt(int irq, void *dev_id) 59a331ce63SAndrew Bresticker { 60f7ea3060SAndrew Bresticker struct clock_event_device *cd = dev_id; 61a331ce63SAndrew Bresticker 62e07127a0SPaul Burton write_gic_vl_compare(read_gic_vl_compare()); 63a331ce63SAndrew Bresticker cd->event_handler(cd); 64a331ce63SAndrew Bresticker return IRQ_HANDLED; 65a331ce63SAndrew Bresticker } 66a331ce63SAndrew Bresticker 67a331ce63SAndrew Bresticker struct irqaction gic_compare_irqaction = { 68a331ce63SAndrew Bresticker .handler = gic_compare_interrupt, 69f7ea3060SAndrew Bresticker .percpu_dev_id = &gic_clockevent_device, 70a331ce63SAndrew Bresticker .flags = IRQF_PERCPU | IRQF_TIMER, 71a331ce63SAndrew Bresticker .name = "timer", 72a331ce63SAndrew Bresticker }; 73a331ce63SAndrew Bresticker 742dab9093SRichard Cochran static void gic_clockevent_cpu_init(unsigned int cpu, 752dab9093SRichard Cochran struct clock_event_device *cd) 76a331ce63SAndrew Bresticker { 77a331ce63SAndrew Bresticker cd->name = "MIPS GIC"; 78a331ce63SAndrew Bresticker cd->features = CLOCK_EVT_FEAT_ONESHOT | 79a331ce63SAndrew Bresticker CLOCK_EVT_FEAT_C3STOP; 80a331ce63SAndrew Bresticker 81a45da565SAndrew Bresticker cd->rating = 350; 82e4752dbbSAndrew Bresticker cd->irq = gic_timer_irq; 83a331ce63SAndrew Bresticker cd->cpumask = cpumask_of(cpu); 84a331ce63SAndrew Bresticker cd->set_next_event = gic_next_event; 85a331ce63SAndrew Bresticker 86b695d8e6SAndrew Bresticker clockevents_config_and_register(cd, gic_frequency, 0x300, 0x7fffffff); 87a331ce63SAndrew Bresticker 88e4752dbbSAndrew Bresticker enable_percpu_irq(gic_timer_irq, IRQ_TYPE_NONE); 89a331ce63SAndrew Bresticker } 90a331ce63SAndrew Bresticker 91e4752dbbSAndrew Bresticker static void gic_clockevent_cpu_exit(struct clock_event_device *cd) 92e4752dbbSAndrew Bresticker { 93e4752dbbSAndrew Bresticker disable_percpu_irq(gic_timer_irq); 94e4752dbbSAndrew Bresticker } 95e4752dbbSAndrew Bresticker 96fc6a6772SEzequiel Garcia static void gic_update_frequency(void *data) 97fc6a6772SEzequiel Garcia { 98fc6a6772SEzequiel Garcia unsigned long rate = (unsigned long)data; 99fc6a6772SEzequiel Garcia 100fc6a6772SEzequiel Garcia clockevents_update_freq(this_cpu_ptr(&gic_clockevent_device), rate); 101fc6a6772SEzequiel Garcia } 102fc6a6772SEzequiel Garcia 1032dab9093SRichard Cochran static int gic_starting_cpu(unsigned int cpu) 104e4752dbbSAndrew Bresticker { 1052dab9093SRichard Cochran gic_clockevent_cpu_init(cpu, this_cpu_ptr(&gic_clockevent_device)); 1062dab9093SRichard Cochran return 0; 107e4752dbbSAndrew Bresticker } 108e4752dbbSAndrew Bresticker 109fc6a6772SEzequiel Garcia static int gic_clk_notifier(struct notifier_block *nb, unsigned long action, 110fc6a6772SEzequiel Garcia void *data) 111fc6a6772SEzequiel Garcia { 112fc6a6772SEzequiel Garcia struct clk_notifier_data *cnd = data; 113fc6a6772SEzequiel Garcia 114fc6a6772SEzequiel Garcia if (action == POST_RATE_CHANGE) 115fc6a6772SEzequiel Garcia on_each_cpu(gic_update_frequency, (void *)cnd->new_rate, 1); 116fc6a6772SEzequiel Garcia 117fc6a6772SEzequiel Garcia return NOTIFY_OK; 118fc6a6772SEzequiel Garcia } 119fc6a6772SEzequiel Garcia 1202dab9093SRichard Cochran static int gic_dying_cpu(unsigned int cpu) 1212dab9093SRichard Cochran { 1222dab9093SRichard Cochran gic_clockevent_cpu_exit(this_cpu_ptr(&gic_clockevent_device)); 1232dab9093SRichard Cochran return 0; 1242dab9093SRichard Cochran } 125e4752dbbSAndrew Bresticker 126fc6a6772SEzequiel Garcia static struct notifier_block gic_clk_nb = { 127fc6a6772SEzequiel Garcia .notifier_call = gic_clk_notifier, 128fc6a6772SEzequiel Garcia }; 129fc6a6772SEzequiel Garcia 130e4752dbbSAndrew Bresticker static int gic_clockevent_init(void) 131e4752dbbSAndrew Bresticker { 132f95ac855SEzequiel Garcia int ret; 133f95ac855SEzequiel Garcia 1346982530eSPaul Burton if (!gic_frequency) 135e4752dbbSAndrew Bresticker return -ENXIO; 136e4752dbbSAndrew Bresticker 137f95ac855SEzequiel Garcia ret = setup_percpu_irq(gic_timer_irq, &gic_compare_irqaction); 1382fd0c93cSPaul Burton if (ret < 0) { 1392fd0c93cSPaul Burton pr_err("GIC timer IRQ %d setup failed: %d\n", 1402fd0c93cSPaul Burton gic_timer_irq, ret); 141f95ac855SEzequiel Garcia return ret; 1422fd0c93cSPaul Burton } 143e4752dbbSAndrew Bresticker 1442dab9093SRichard Cochran cpuhp_setup_state(CPUHP_AP_MIPS_GIC_TIMER_STARTING, 14573c1b41eSThomas Gleixner "clockevents/mips/gic/timer:starting", 14673c1b41eSThomas Gleixner gic_starting_cpu, gic_dying_cpu); 147a331ce63SAndrew Bresticker return 0; 148a331ce63SAndrew Bresticker } 149a331ce63SAndrew Bresticker 150a5a1d1c2SThomas Gleixner static u64 gic_hpt_read(struct clocksource *cs) 151fa5635a2SAndrew Bresticker { 152fa5635a2SAndrew Bresticker return gic_read_count(); 153fa5635a2SAndrew Bresticker } 154fa5635a2SAndrew Bresticker 155fa5635a2SAndrew Bresticker static struct clocksource gic_clocksource = { 156fa5635a2SAndrew Bresticker .name = "GIC", 157fa5635a2SAndrew Bresticker .read = gic_hpt_read, 158fa5635a2SAndrew Bresticker .flags = CLOCK_SOURCE_IS_CONTINUOUS, 159a7f4df4eSAlex Smith .archdata = { .vdso_clock_mode = VDSO_CLOCK_GIC }, 160fa5635a2SAndrew Bresticker }; 161fa5635a2SAndrew Bresticker 162d8152bf8SDaniel Lezcano static int __init __gic_clocksource_init(void) 163fa5635a2SAndrew Bresticker { 164e07127a0SPaul Burton unsigned int count_width; 165f95ac855SEzequiel Garcia int ret; 166f95ac855SEzequiel Garcia 167fa5635a2SAndrew Bresticker /* Set clocksource mask. */ 168e07127a0SPaul Burton count_width = read_gic_config() & GIC_CONFIG_COUNTBITS; 169e07127a0SPaul Burton count_width >>= __fls(GIC_CONFIG_COUNTBITS); 170e07127a0SPaul Burton count_width *= 4; 171e07127a0SPaul Burton count_width += 32; 172e07127a0SPaul Burton gic_clocksource.mask = CLOCKSOURCE_MASK(count_width); 173fa5635a2SAndrew Bresticker 174fa5635a2SAndrew Bresticker /* Calculate a somewhat reasonable rating value. */ 175e12aa828SAndrew Bresticker gic_clocksource.rating = 200 + gic_frequency / 10000000; 176fa5635a2SAndrew Bresticker 177f95ac855SEzequiel Garcia ret = clocksource_register_hz(&gic_clocksource, gic_frequency); 178f95ac855SEzequiel Garcia if (ret < 0) 179f95ac855SEzequiel Garcia pr_warn("GIC: Unable to register clocksource\n"); 180d8152bf8SDaniel Lezcano 181d8152bf8SDaniel Lezcano return ret; 182fa5635a2SAndrew Bresticker } 183e12aa828SAndrew Bresticker 184be5769e2SPaul Gortmaker static int __init gic_clocksource_of_init(struct device_node *node) 185e12aa828SAndrew Bresticker { 1865b4e8453SAndrew Bresticker struct clk *clk; 187fc6a6772SEzequiel Garcia int ret; 1885b4e8453SAndrew Bresticker 189e07127a0SPaul Burton if (!mips_gic_present() || !node->parent || 190d8152bf8SDaniel Lezcano !of_device_is_compatible(node->parent, "mti,gic")) { 191ac9ce6d1SRafał Miłecki pr_warn("No DT definition for the mips gic driver\n"); 192d8152bf8SDaniel Lezcano return -ENXIO; 193d8152bf8SDaniel Lezcano } 194e12aa828SAndrew Bresticker 1955b4e8453SAndrew Bresticker clk = of_clk_get(node, 0); 1965b4e8453SAndrew Bresticker if (!IS_ERR(clk)) { 1978c3ecd60SChristophe Jaillet ret = clk_prepare_enable(clk); 1988c3ecd60SChristophe Jaillet if (ret < 0) { 199eb811c73SEzequiel Garcia pr_err("GIC failed to enable clock\n"); 2005b4e8453SAndrew Bresticker clk_put(clk); 2018c3ecd60SChristophe Jaillet return ret; 202eb811c73SEzequiel Garcia } 203eb811c73SEzequiel Garcia 204eb811c73SEzequiel Garcia gic_frequency = clk_get_rate(clk); 2055b4e8453SAndrew Bresticker } else if (of_property_read_u32(node, "clock-frequency", 2065b4e8453SAndrew Bresticker &gic_frequency)) { 207e12aa828SAndrew Bresticker pr_err("GIC frequency not specified.\n"); 208*ed7158baSIngo Molnar return -EINVAL; 209e12aa828SAndrew Bresticker } 210e12aa828SAndrew Bresticker gic_timer_irq = irq_of_parse_and_map(node, 0); 211e12aa828SAndrew Bresticker if (!gic_timer_irq) { 212e12aa828SAndrew Bresticker pr_err("GIC timer IRQ not specified.\n"); 213*ed7158baSIngo Molnar return -EINVAL; 214e12aa828SAndrew Bresticker } 215e12aa828SAndrew Bresticker 216d8152bf8SDaniel Lezcano ret = __gic_clocksource_init(); 217d8152bf8SDaniel Lezcano if (ret) 218d8152bf8SDaniel Lezcano return ret; 219fc6a6772SEzequiel Garcia 220fc6a6772SEzequiel Garcia ret = gic_clockevent_init(); 221fc6a6772SEzequiel Garcia if (!ret && !IS_ERR(clk)) { 222fc6a6772SEzequiel Garcia if (clk_notifier_register(clk, &gic_clk_nb) < 0) 223fc6a6772SEzequiel Garcia pr_warn("GIC: Unable to register clock notifier\n"); 224fc6a6772SEzequiel Garcia } 22567d4e669SEzequiel Garcia 22667d4e669SEzequiel Garcia /* And finally start the counter */ 227e07127a0SPaul Burton clear_gic_config(GIC_CONFIG_COUNTSTOP); 228d8152bf8SDaniel Lezcano 229d8152bf8SDaniel Lezcano return 0; 230e12aa828SAndrew Bresticker } 23117273395SDaniel Lezcano TIMER_OF_DECLARE(mips_gic_timer, "mti,gic-timer", 232e12aa828SAndrew Bresticker gic_clocksource_of_init); 233