1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * |
4 | * Copyright (C) 2015 Numascale AS. All rights reserved. |
5 | */ |
6 | |
7 | #include <linux/clockchips.h> |
8 | |
9 | #include <asm/irq.h> |
10 | #include <asm/numachip/numachip.h> |
11 | #include <asm/numachip/numachip_csr.h> |
12 | |
13 | static DEFINE_PER_CPU(struct clock_event_device, numachip2_ced); |
14 | |
15 | static cycles_t numachip2_timer_read(struct clocksource *cs) |
16 | { |
17 | return numachip2_read64_lcsr(NUMACHIP2_TIMER_NOW); |
18 | } |
19 | |
20 | static struct clocksource numachip2_clocksource = { |
21 | .name = "numachip2" , |
22 | .rating = 295, |
23 | .read = numachip2_timer_read, |
24 | .mask = CLOCKSOURCE_MASK(64), |
25 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, |
26 | .mult = 1, |
27 | .shift = 0, |
28 | }; |
29 | |
30 | static int numachip2_set_next_event(unsigned long delta, struct clock_event_device *ced) |
31 | { |
32 | numachip2_write64_lcsr(NUMACHIP2_TIMER_DEADLINE + numachip2_timer(), |
33 | val: delta); |
34 | return 0; |
35 | } |
36 | |
37 | static const struct clock_event_device numachip2_clockevent __initconst = { |
38 | .name = "numachip2" , |
39 | .rating = 400, |
40 | .set_next_event = numachip2_set_next_event, |
41 | .features = CLOCK_EVT_FEAT_ONESHOT, |
42 | .mult = 1, |
43 | .shift = 0, |
44 | .min_delta_ns = 1250, |
45 | .min_delta_ticks = 1250, |
46 | .max_delta_ns = LONG_MAX, |
47 | .max_delta_ticks = LONG_MAX, |
48 | }; |
49 | |
50 | static void numachip_timer_interrupt(void) |
51 | { |
52 | struct clock_event_device *ced = this_cpu_ptr(&numachip2_ced); |
53 | |
54 | ced->event_handler(ced); |
55 | } |
56 | |
57 | static __init void numachip_timer_each(struct work_struct *work) |
58 | { |
59 | unsigned local_apicid = __this_cpu_read(x86_cpu_to_apicid) & 0xff; |
60 | struct clock_event_device *ced = this_cpu_ptr(&numachip2_ced); |
61 | |
62 | /* Setup IPI vector to local core and relative timing mode */ |
63 | numachip2_write64_lcsr(NUMACHIP2_TIMER_INT + numachip2_timer(), |
64 | val: (3 << 22) | (X86_PLATFORM_IPI_VECTOR << 14) | |
65 | (local_apicid << 6)); |
66 | |
67 | *ced = numachip2_clockevent; |
68 | ced->cpumask = cpumask_of(smp_processor_id()); |
69 | clockevents_register_device(dev: ced); |
70 | } |
71 | |
72 | static int __init numachip_timer_init(void) |
73 | { |
74 | if (numachip_system != 2) |
75 | return -ENODEV; |
76 | |
77 | /* Reset timer */ |
78 | numachip2_write64_lcsr(NUMACHIP2_TIMER_RESET, val: 0); |
79 | clocksource_register_hz(cs: &numachip2_clocksource, NSEC_PER_SEC); |
80 | |
81 | /* Setup per-cpu clockevents */ |
82 | x86_platform_ipi_callback = numachip_timer_interrupt; |
83 | schedule_on_each_cpu(func: &numachip_timer_each); |
84 | |
85 | return 0; |
86 | } |
87 | |
88 | arch_initcall(numachip_timer_init); |
89 | |