Daniel J Blueman | ce2e572 | 2015-09-21 18:02:25 +0800 | [diff] [blame] | 1 | /* |
| 2 | * |
| 3 | * Copyright (C) 2015 Numascale AS. All rights reserved. |
| 4 | * |
| 5 | * This software is licensed under the terms of the GNU General Public |
| 6 | * License version 2, as published by the Free Software Foundation, and |
| 7 | * may be copied, distributed, and modified under those terms. |
| 8 | * |
| 9 | * This program is distributed in the hope that it will be useful, |
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 12 | * GNU General Public License for more details. |
| 13 | * |
| 14 | */ |
| 15 | |
| 16 | #include <linux/clockchips.h> |
| 17 | |
| 18 | #include <asm/irq.h> |
| 19 | #include <asm/numachip/numachip.h> |
| 20 | #include <asm/numachip/numachip_csr.h> |
| 21 | |
Daniel J Blueman | ef34cc3 | 2015-09-23 09:38:13 +0800 | [diff] [blame] | 22 | static DEFINE_PER_CPU(struct clock_event_device, numachip2_ced); |
Daniel J Blueman | ce2e572 | 2015-09-21 18:02:25 +0800 | [diff] [blame] | 23 | |
| 24 | static cycles_t numachip2_timer_read(struct clocksource *cs) |
| 25 | { |
| 26 | return numachip2_read64_lcsr(NUMACHIP2_TIMER_NOW); |
| 27 | } |
| 28 | |
| 29 | static struct clocksource numachip2_clocksource = { |
| 30 | .name = "numachip2", |
| 31 | .rating = 295, |
| 32 | .read = numachip2_timer_read, |
| 33 | .mask = CLOCKSOURCE_MASK(64), |
| 34 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, |
| 35 | .mult = 1, |
| 36 | .shift = 0, |
| 37 | }; |
| 38 | |
| 39 | static int numachip2_set_next_event(unsigned long delta, struct clock_event_device *ced) |
| 40 | { |
| 41 | numachip2_write64_lcsr(NUMACHIP2_TIMER_DEADLINE + numachip2_timer(), |
| 42 | delta); |
| 43 | return 0; |
| 44 | } |
| 45 | |
Bhumika Goyal | 1043036 | 2017-08-29 23:47:11 +0530 | [diff] [blame] | 46 | static const struct clock_event_device numachip2_clockevent __initconst = { |
Daniel J Blueman | ce2e572 | 2015-09-21 18:02:25 +0800 | [diff] [blame] | 47 | .name = "numachip2", |
| 48 | .rating = 400, |
| 49 | .set_next_event = numachip2_set_next_event, |
| 50 | .features = CLOCK_EVT_FEAT_ONESHOT, |
| 51 | .mult = 1, |
| 52 | .shift = 0, |
| 53 | .min_delta_ns = 1250, |
Nicolai Stange | 6cf57ae | 2017-03-30 22:08:49 +0200 | [diff] [blame] | 54 | .min_delta_ticks = 1250, |
Daniel J Blueman | ce2e572 | 2015-09-21 18:02:25 +0800 | [diff] [blame] | 55 | .max_delta_ns = LONG_MAX, |
Nicolai Stange | 6cf57ae | 2017-03-30 22:08:49 +0200 | [diff] [blame] | 56 | .max_delta_ticks = LONG_MAX, |
Daniel J Blueman | ce2e572 | 2015-09-21 18:02:25 +0800 | [diff] [blame] | 57 | }; |
| 58 | |
| 59 | static void numachip_timer_interrupt(void) |
| 60 | { |
Daniel J Blueman | ef34cc3 | 2015-09-23 09:38:13 +0800 | [diff] [blame] | 61 | struct clock_event_device *ced = this_cpu_ptr(&numachip2_ced); |
Daniel J Blueman | ce2e572 | 2015-09-21 18:02:25 +0800 | [diff] [blame] | 62 | |
| 63 | ced->event_handler(ced); |
| 64 | } |
| 65 | |
| 66 | static __init void numachip_timer_each(struct work_struct *work) |
| 67 | { |
| 68 | unsigned local_apicid = __this_cpu_read(x86_cpu_to_apicid) & 0xff; |
Daniel J Blueman | ef34cc3 | 2015-09-23 09:38:13 +0800 | [diff] [blame] | 69 | struct clock_event_device *ced = this_cpu_ptr(&numachip2_ced); |
Daniel J Blueman | ce2e572 | 2015-09-21 18:02:25 +0800 | [diff] [blame] | 70 | |
| 71 | /* Setup IPI vector to local core and relative timing mode */ |
| 72 | numachip2_write64_lcsr(NUMACHIP2_TIMER_INT + numachip2_timer(), |
| 73 | (3 << 22) | (X86_PLATFORM_IPI_VECTOR << 14) | |
| 74 | (local_apicid << 6)); |
| 75 | |
| 76 | *ced = numachip2_clockevent; |
| 77 | ced->cpumask = cpumask_of(smp_processor_id()); |
| 78 | clockevents_register_device(ced); |
| 79 | } |
| 80 | |
| 81 | static int __init numachip_timer_init(void) |
| 82 | { |
| 83 | if (numachip_system != 2) |
| 84 | return -ENODEV; |
| 85 | |
| 86 | /* Reset timer */ |
| 87 | numachip2_write64_lcsr(NUMACHIP2_TIMER_RESET, 0); |
| 88 | clocksource_register_hz(&numachip2_clocksource, NSEC_PER_SEC); |
| 89 | |
| 90 | /* Setup per-cpu clockevents */ |
| 91 | x86_platform_ipi_callback = numachip_timer_interrupt; |
| 92 | schedule_on_each_cpu(&numachip_timer_each); |
| 93 | |
| 94 | return 0; |
| 95 | } |
| 96 | |
| 97 | arch_initcall(numachip_timer_init); |