Commit | Line | Data |
---|---|---|
ce2e572c DB |
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 | ||
ef34cc34 | 22 | static DEFINE_PER_CPU(struct clock_event_device, numachip2_ced); |
ce2e572c DB |
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 | ||
46 | static struct clock_event_device numachip2_clockevent = { | |
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, | |
54 | .max_delta_ns = LONG_MAX, | |
55 | }; | |
56 | ||
57 | static void numachip_timer_interrupt(void) | |
58 | { | |
ef34cc34 | 59 | struct clock_event_device *ced = this_cpu_ptr(&numachip2_ced); |
ce2e572c DB |
60 | |
61 | ced->event_handler(ced); | |
62 | } | |
63 | ||
64 | static __init void numachip_timer_each(struct work_struct *work) | |
65 | { | |
66 | unsigned local_apicid = __this_cpu_read(x86_cpu_to_apicid) & 0xff; | |
ef34cc34 | 67 | struct clock_event_device *ced = this_cpu_ptr(&numachip2_ced); |
ce2e572c DB |
68 | |
69 | /* Setup IPI vector to local core and relative timing mode */ | |
70 | numachip2_write64_lcsr(NUMACHIP2_TIMER_INT + numachip2_timer(), | |
71 | (3 << 22) | (X86_PLATFORM_IPI_VECTOR << 14) | | |
72 | (local_apicid << 6)); | |
73 | ||
74 | *ced = numachip2_clockevent; | |
75 | ced->cpumask = cpumask_of(smp_processor_id()); | |
76 | clockevents_register_device(ced); | |
77 | } | |
78 | ||
79 | static int __init numachip_timer_init(void) | |
80 | { | |
81 | if (numachip_system != 2) | |
82 | return -ENODEV; | |
83 | ||
84 | /* Reset timer */ | |
85 | numachip2_write64_lcsr(NUMACHIP2_TIMER_RESET, 0); | |
86 | clocksource_register_hz(&numachip2_clocksource, NSEC_PER_SEC); | |
87 | ||
88 | /* Setup per-cpu clockevents */ | |
89 | x86_platform_ipi_callback = numachip_timer_interrupt; | |
90 | schedule_on_each_cpu(&numachip_timer_each); | |
91 | ||
92 | return 0; | |
93 | } | |
94 | ||
95 | arch_initcall(numachip_timer_init); |