1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * apb_timer.c: Driver for Langwell APB timers
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * (C) Copyright 2009 Intel Corporation
6*4882a593Smuzhiyun * Author: Jacob Pan (jacob.jun.pan@intel.com)
7*4882a593Smuzhiyun *
8*4882a593Smuzhiyun * Note:
9*4882a593Smuzhiyun * Langwell is the south complex of Intel Moorestown MID platform. There are
10*4882a593Smuzhiyun * eight external timers in total that can be used by the operating system.
11*4882a593Smuzhiyun * The timer information, such as frequency and addresses, is provided to the
12*4882a593Smuzhiyun * OS via SFI tables.
13*4882a593Smuzhiyun * Timer interrupts are routed via FW/HW emulated IOAPIC independently via
14*4882a593Smuzhiyun * individual redirection table entries (RTE).
15*4882a593Smuzhiyun * Unlike HPET, there is no master counter, therefore one of the timers are
16*4882a593Smuzhiyun * used as clocksource. The overall allocation looks like:
17*4882a593Smuzhiyun * - timer 0 - NR_CPUs for per cpu timer
18*4882a593Smuzhiyun * - one timer for clocksource
19*4882a593Smuzhiyun * - one timer for watchdog driver.
20*4882a593Smuzhiyun * It is also worth notice that APB timer does not support true one-shot mode,
21*4882a593Smuzhiyun * free-running mode will be used here to emulate one-shot mode.
22*4882a593Smuzhiyun * APB timer can also be used as broadcast timer along with per cpu local APIC
23*4882a593Smuzhiyun * timer, but by default APB timer has higher rating than local APIC timers.
24*4882a593Smuzhiyun */
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun #include <linux/delay.h>
27*4882a593Smuzhiyun #include <linux/dw_apb_timer.h>
28*4882a593Smuzhiyun #include <linux/errno.h>
29*4882a593Smuzhiyun #include <linux/init.h>
30*4882a593Smuzhiyun #include <linux/slab.h>
31*4882a593Smuzhiyun #include <linux/pm.h>
32*4882a593Smuzhiyun #include <linux/sfi.h>
33*4882a593Smuzhiyun #include <linux/interrupt.h>
34*4882a593Smuzhiyun #include <linux/cpu.h>
35*4882a593Smuzhiyun #include <linux/irq.h>
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun #include <asm/fixmap.h>
38*4882a593Smuzhiyun #include <asm/apb_timer.h>
39*4882a593Smuzhiyun #include <asm/intel-mid.h>
40*4882a593Smuzhiyun #include <asm/time.h>
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun #define APBT_CLOCKEVENT_RATING 110
43*4882a593Smuzhiyun #define APBT_CLOCKSOURCE_RATING 250
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun #define APBT_CLOCKEVENT0_NUM (0)
46*4882a593Smuzhiyun #define APBT_CLOCKSOURCE_NUM (2)
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun static phys_addr_t apbt_address;
49*4882a593Smuzhiyun static int apb_timer_block_enabled;
50*4882a593Smuzhiyun static void __iomem *apbt_virt_address;
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun /*
53*4882a593Smuzhiyun * Common DW APB timer info
54*4882a593Smuzhiyun */
55*4882a593Smuzhiyun static unsigned long apbt_freq;
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun struct apbt_dev {
58*4882a593Smuzhiyun struct dw_apb_clock_event_device *timer;
59*4882a593Smuzhiyun unsigned int num;
60*4882a593Smuzhiyun int cpu;
61*4882a593Smuzhiyun unsigned int irq;
62*4882a593Smuzhiyun char name[10];
63*4882a593Smuzhiyun };
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun static struct dw_apb_clocksource *clocksource_apbt;
66*4882a593Smuzhiyun
adev_virt_addr(struct apbt_dev * adev)67*4882a593Smuzhiyun static inline void __iomem *adev_virt_addr(struct apbt_dev *adev)
68*4882a593Smuzhiyun {
69*4882a593Smuzhiyun return apbt_virt_address + adev->num * APBTMRS_REG_SIZE;
70*4882a593Smuzhiyun }
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun static DEFINE_PER_CPU(struct apbt_dev, cpu_apbt_dev);
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun #ifdef CONFIG_SMP
75*4882a593Smuzhiyun static unsigned int apbt_num_timers_used;
76*4882a593Smuzhiyun #endif
77*4882a593Smuzhiyun
apbt_set_mapping(void)78*4882a593Smuzhiyun static inline void apbt_set_mapping(void)
79*4882a593Smuzhiyun {
80*4882a593Smuzhiyun struct sfi_timer_table_entry *mtmr;
81*4882a593Smuzhiyun int phy_cs_timer_id = 0;
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun if (apbt_virt_address) {
84*4882a593Smuzhiyun pr_debug("APBT base already mapped\n");
85*4882a593Smuzhiyun return;
86*4882a593Smuzhiyun }
87*4882a593Smuzhiyun mtmr = sfi_get_mtmr(APBT_CLOCKEVENT0_NUM);
88*4882a593Smuzhiyun if (mtmr == NULL) {
89*4882a593Smuzhiyun printk(KERN_ERR "Failed to get MTMR %d from SFI\n",
90*4882a593Smuzhiyun APBT_CLOCKEVENT0_NUM);
91*4882a593Smuzhiyun return;
92*4882a593Smuzhiyun }
93*4882a593Smuzhiyun apbt_address = (phys_addr_t)mtmr->phys_addr;
94*4882a593Smuzhiyun if (!apbt_address) {
95*4882a593Smuzhiyun printk(KERN_WARNING "No timer base from SFI, use default\n");
96*4882a593Smuzhiyun apbt_address = APBT_DEFAULT_BASE;
97*4882a593Smuzhiyun }
98*4882a593Smuzhiyun apbt_virt_address = ioremap(apbt_address, APBT_MMAP_SIZE);
99*4882a593Smuzhiyun if (!apbt_virt_address) {
100*4882a593Smuzhiyun pr_debug("Failed mapping APBT phy address at %lu\n",\
101*4882a593Smuzhiyun (unsigned long)apbt_address);
102*4882a593Smuzhiyun goto panic_noapbt;
103*4882a593Smuzhiyun }
104*4882a593Smuzhiyun apbt_freq = mtmr->freq_hz;
105*4882a593Smuzhiyun sfi_free_mtmr(mtmr);
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun /* Now figure out the physical timer id for clocksource device */
108*4882a593Smuzhiyun mtmr = sfi_get_mtmr(APBT_CLOCKSOURCE_NUM);
109*4882a593Smuzhiyun if (mtmr == NULL)
110*4882a593Smuzhiyun goto panic_noapbt;
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun /* Now figure out the physical timer id */
113*4882a593Smuzhiyun pr_debug("Use timer %d for clocksource\n",
114*4882a593Smuzhiyun (int)(mtmr->phys_addr & 0xff) / APBTMRS_REG_SIZE);
115*4882a593Smuzhiyun phy_cs_timer_id = (unsigned int)(mtmr->phys_addr & 0xff) /
116*4882a593Smuzhiyun APBTMRS_REG_SIZE;
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun clocksource_apbt = dw_apb_clocksource_init(APBT_CLOCKSOURCE_RATING,
119*4882a593Smuzhiyun "apbt0", apbt_virt_address + phy_cs_timer_id *
120*4882a593Smuzhiyun APBTMRS_REG_SIZE, apbt_freq);
121*4882a593Smuzhiyun return;
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun panic_noapbt:
124*4882a593Smuzhiyun panic("Failed to setup APB system timer\n");
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun }
127*4882a593Smuzhiyun
apbt_clear_mapping(void)128*4882a593Smuzhiyun static inline void apbt_clear_mapping(void)
129*4882a593Smuzhiyun {
130*4882a593Smuzhiyun iounmap(apbt_virt_address);
131*4882a593Smuzhiyun apbt_virt_address = NULL;
132*4882a593Smuzhiyun }
133*4882a593Smuzhiyun
apbt_clockevent_register(void)134*4882a593Smuzhiyun static int __init apbt_clockevent_register(void)
135*4882a593Smuzhiyun {
136*4882a593Smuzhiyun struct sfi_timer_table_entry *mtmr;
137*4882a593Smuzhiyun struct apbt_dev *adev = this_cpu_ptr(&cpu_apbt_dev);
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun mtmr = sfi_get_mtmr(APBT_CLOCKEVENT0_NUM);
140*4882a593Smuzhiyun if (mtmr == NULL) {
141*4882a593Smuzhiyun printk(KERN_ERR "Failed to get MTMR %d from SFI\n",
142*4882a593Smuzhiyun APBT_CLOCKEVENT0_NUM);
143*4882a593Smuzhiyun return -ENODEV;
144*4882a593Smuzhiyun }
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun adev->num = smp_processor_id();
147*4882a593Smuzhiyun adev->timer = dw_apb_clockevent_init(smp_processor_id(), "apbt0",
148*4882a593Smuzhiyun intel_mid_timer_options == INTEL_MID_TIMER_LAPIC_APBT ?
149*4882a593Smuzhiyun APBT_CLOCKEVENT_RATING - 100 : APBT_CLOCKEVENT_RATING,
150*4882a593Smuzhiyun adev_virt_addr(adev), 0, apbt_freq);
151*4882a593Smuzhiyun /* Firmware does EOI handling for us. */
152*4882a593Smuzhiyun adev->timer->eoi = NULL;
153*4882a593Smuzhiyun
154*4882a593Smuzhiyun if (intel_mid_timer_options == INTEL_MID_TIMER_LAPIC_APBT) {
155*4882a593Smuzhiyun global_clock_event = &adev->timer->ced;
156*4882a593Smuzhiyun printk(KERN_DEBUG "%s clockevent registered as global\n",
157*4882a593Smuzhiyun global_clock_event->name);
158*4882a593Smuzhiyun }
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun dw_apb_clockevent_register(adev->timer);
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun sfi_free_mtmr(mtmr);
163*4882a593Smuzhiyun return 0;
164*4882a593Smuzhiyun }
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun #ifdef CONFIG_SMP
167*4882a593Smuzhiyun
apbt_setup_irq(struct apbt_dev * adev)168*4882a593Smuzhiyun static void apbt_setup_irq(struct apbt_dev *adev)
169*4882a593Smuzhiyun {
170*4882a593Smuzhiyun irq_modify_status(adev->irq, 0, IRQ_MOVE_PCNTXT);
171*4882a593Smuzhiyun irq_set_affinity(adev->irq, cpumask_of(adev->cpu));
172*4882a593Smuzhiyun }
173*4882a593Smuzhiyun
174*4882a593Smuzhiyun /* Should be called with per cpu */
apbt_setup_secondary_clock(void)175*4882a593Smuzhiyun void apbt_setup_secondary_clock(void)
176*4882a593Smuzhiyun {
177*4882a593Smuzhiyun struct apbt_dev *adev;
178*4882a593Smuzhiyun int cpu;
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun /* Don't register boot CPU clockevent */
181*4882a593Smuzhiyun cpu = smp_processor_id();
182*4882a593Smuzhiyun if (!cpu)
183*4882a593Smuzhiyun return;
184*4882a593Smuzhiyun
185*4882a593Smuzhiyun adev = this_cpu_ptr(&cpu_apbt_dev);
186*4882a593Smuzhiyun if (!adev->timer) {
187*4882a593Smuzhiyun adev->timer = dw_apb_clockevent_init(cpu, adev->name,
188*4882a593Smuzhiyun APBT_CLOCKEVENT_RATING, adev_virt_addr(adev),
189*4882a593Smuzhiyun adev->irq, apbt_freq);
190*4882a593Smuzhiyun adev->timer->eoi = NULL;
191*4882a593Smuzhiyun } else {
192*4882a593Smuzhiyun dw_apb_clockevent_resume(adev->timer);
193*4882a593Smuzhiyun }
194*4882a593Smuzhiyun
195*4882a593Smuzhiyun printk(KERN_INFO "Registering CPU %d clockevent device %s, cpu %08x\n",
196*4882a593Smuzhiyun cpu, adev->name, adev->cpu);
197*4882a593Smuzhiyun
198*4882a593Smuzhiyun apbt_setup_irq(adev);
199*4882a593Smuzhiyun dw_apb_clockevent_register(adev->timer);
200*4882a593Smuzhiyun
201*4882a593Smuzhiyun return;
202*4882a593Smuzhiyun }
203*4882a593Smuzhiyun
204*4882a593Smuzhiyun /*
205*4882a593Smuzhiyun * this notify handler process CPU hotplug events. in case of S0i3, nonboot
206*4882a593Smuzhiyun * cpus are disabled/enabled frequently, for performance reasons, we keep the
207*4882a593Smuzhiyun * per cpu timer irq registered so that we do need to do free_irq/request_irq.
208*4882a593Smuzhiyun *
209*4882a593Smuzhiyun * TODO: it might be more reliable to directly disable percpu clockevent device
210*4882a593Smuzhiyun * without the notifier chain. currently, cpu 0 may get interrupts from other
211*4882a593Smuzhiyun * cpu timers during the offline process due to the ordering of notification.
212*4882a593Smuzhiyun * the extra interrupt is harmless.
213*4882a593Smuzhiyun */
apbt_cpu_dead(unsigned int cpu)214*4882a593Smuzhiyun static int apbt_cpu_dead(unsigned int cpu)
215*4882a593Smuzhiyun {
216*4882a593Smuzhiyun struct apbt_dev *adev = &per_cpu(cpu_apbt_dev, cpu);
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun dw_apb_clockevent_pause(adev->timer);
219*4882a593Smuzhiyun if (system_state == SYSTEM_RUNNING) {
220*4882a593Smuzhiyun pr_debug("skipping APBT CPU %u offline\n", cpu);
221*4882a593Smuzhiyun } else {
222*4882a593Smuzhiyun pr_debug("APBT clockevent for cpu %u offline\n", cpu);
223*4882a593Smuzhiyun dw_apb_clockevent_stop(adev->timer);
224*4882a593Smuzhiyun }
225*4882a593Smuzhiyun return 0;
226*4882a593Smuzhiyun }
227*4882a593Smuzhiyun
apbt_late_init(void)228*4882a593Smuzhiyun static __init int apbt_late_init(void)
229*4882a593Smuzhiyun {
230*4882a593Smuzhiyun if (intel_mid_timer_options == INTEL_MID_TIMER_LAPIC_APBT ||
231*4882a593Smuzhiyun !apb_timer_block_enabled)
232*4882a593Smuzhiyun return 0;
233*4882a593Smuzhiyun return cpuhp_setup_state(CPUHP_X86_APB_DEAD, "x86/apb:dead", NULL,
234*4882a593Smuzhiyun apbt_cpu_dead);
235*4882a593Smuzhiyun }
236*4882a593Smuzhiyun fs_initcall(apbt_late_init);
237*4882a593Smuzhiyun #else
238*4882a593Smuzhiyun
apbt_setup_secondary_clock(void)239*4882a593Smuzhiyun void apbt_setup_secondary_clock(void) {}
240*4882a593Smuzhiyun
241*4882a593Smuzhiyun #endif /* CONFIG_SMP */
242*4882a593Smuzhiyun
apbt_clocksource_register(void)243*4882a593Smuzhiyun static int apbt_clocksource_register(void)
244*4882a593Smuzhiyun {
245*4882a593Smuzhiyun u64 start, now;
246*4882a593Smuzhiyun u64 t1;
247*4882a593Smuzhiyun
248*4882a593Smuzhiyun /* Start the counter, use timer 2 as source, timer 0/1 for event */
249*4882a593Smuzhiyun dw_apb_clocksource_start(clocksource_apbt);
250*4882a593Smuzhiyun
251*4882a593Smuzhiyun /* Verify whether apbt counter works */
252*4882a593Smuzhiyun t1 = dw_apb_clocksource_read(clocksource_apbt);
253*4882a593Smuzhiyun start = rdtsc();
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun /*
256*4882a593Smuzhiyun * We don't know the TSC frequency yet, but waiting for
257*4882a593Smuzhiyun * 200000 TSC cycles is safe:
258*4882a593Smuzhiyun * 4 GHz == 50us
259*4882a593Smuzhiyun * 1 GHz == 200us
260*4882a593Smuzhiyun */
261*4882a593Smuzhiyun do {
262*4882a593Smuzhiyun rep_nop();
263*4882a593Smuzhiyun now = rdtsc();
264*4882a593Smuzhiyun } while ((now - start) < 200000UL);
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun /* APBT is the only always on clocksource, it has to work! */
267*4882a593Smuzhiyun if (t1 == dw_apb_clocksource_read(clocksource_apbt))
268*4882a593Smuzhiyun panic("APBT counter not counting. APBT disabled\n");
269*4882a593Smuzhiyun
270*4882a593Smuzhiyun dw_apb_clocksource_register(clocksource_apbt);
271*4882a593Smuzhiyun
272*4882a593Smuzhiyun return 0;
273*4882a593Smuzhiyun }
274*4882a593Smuzhiyun
275*4882a593Smuzhiyun /*
276*4882a593Smuzhiyun * Early setup the APBT timer, only use timer 0 for booting then switch to
277*4882a593Smuzhiyun * per CPU timer if possible.
278*4882a593Smuzhiyun * returns 1 if per cpu apbt is setup
279*4882a593Smuzhiyun * returns 0 if no per cpu apbt is chosen
280*4882a593Smuzhiyun * panic if set up failed, this is the only platform timer on Moorestown.
281*4882a593Smuzhiyun */
apbt_time_init(void)282*4882a593Smuzhiyun void __init apbt_time_init(void)
283*4882a593Smuzhiyun {
284*4882a593Smuzhiyun #ifdef CONFIG_SMP
285*4882a593Smuzhiyun int i;
286*4882a593Smuzhiyun struct sfi_timer_table_entry *p_mtmr;
287*4882a593Smuzhiyun struct apbt_dev *adev;
288*4882a593Smuzhiyun #endif
289*4882a593Smuzhiyun
290*4882a593Smuzhiyun if (apb_timer_block_enabled)
291*4882a593Smuzhiyun return;
292*4882a593Smuzhiyun apbt_set_mapping();
293*4882a593Smuzhiyun if (!apbt_virt_address)
294*4882a593Smuzhiyun goto out_noapbt;
295*4882a593Smuzhiyun /*
296*4882a593Smuzhiyun * Read the frequency and check for a sane value, for ESL model
297*4882a593Smuzhiyun * we extend the possible clock range to allow time scaling.
298*4882a593Smuzhiyun */
299*4882a593Smuzhiyun
300*4882a593Smuzhiyun if (apbt_freq < APBT_MIN_FREQ || apbt_freq > APBT_MAX_FREQ) {
301*4882a593Smuzhiyun pr_debug("APBT has invalid freq 0x%lx\n", apbt_freq);
302*4882a593Smuzhiyun goto out_noapbt;
303*4882a593Smuzhiyun }
304*4882a593Smuzhiyun if (apbt_clocksource_register()) {
305*4882a593Smuzhiyun pr_debug("APBT has failed to register clocksource\n");
306*4882a593Smuzhiyun goto out_noapbt;
307*4882a593Smuzhiyun }
308*4882a593Smuzhiyun if (!apbt_clockevent_register())
309*4882a593Smuzhiyun apb_timer_block_enabled = 1;
310*4882a593Smuzhiyun else {
311*4882a593Smuzhiyun pr_debug("APBT has failed to register clockevent\n");
312*4882a593Smuzhiyun goto out_noapbt;
313*4882a593Smuzhiyun }
314*4882a593Smuzhiyun #ifdef CONFIG_SMP
315*4882a593Smuzhiyun /* kernel cmdline disable apb timer, so we will use lapic timers */
316*4882a593Smuzhiyun if (intel_mid_timer_options == INTEL_MID_TIMER_LAPIC_APBT) {
317*4882a593Smuzhiyun printk(KERN_INFO "apbt: disabled per cpu timer\n");
318*4882a593Smuzhiyun return;
319*4882a593Smuzhiyun }
320*4882a593Smuzhiyun pr_debug("%s: %d CPUs online\n", __func__, num_online_cpus());
321*4882a593Smuzhiyun if (num_possible_cpus() <= sfi_mtimer_num)
322*4882a593Smuzhiyun apbt_num_timers_used = num_possible_cpus();
323*4882a593Smuzhiyun else
324*4882a593Smuzhiyun apbt_num_timers_used = 1;
325*4882a593Smuzhiyun pr_debug("%s: %d APB timers used\n", __func__, apbt_num_timers_used);
326*4882a593Smuzhiyun
327*4882a593Smuzhiyun /* here we set up per CPU timer data structure */
328*4882a593Smuzhiyun for (i = 0; i < apbt_num_timers_used; i++) {
329*4882a593Smuzhiyun adev = &per_cpu(cpu_apbt_dev, i);
330*4882a593Smuzhiyun adev->num = i;
331*4882a593Smuzhiyun adev->cpu = i;
332*4882a593Smuzhiyun p_mtmr = sfi_get_mtmr(i);
333*4882a593Smuzhiyun if (p_mtmr)
334*4882a593Smuzhiyun adev->irq = p_mtmr->irq;
335*4882a593Smuzhiyun else
336*4882a593Smuzhiyun printk(KERN_ERR "Failed to get timer for cpu %d\n", i);
337*4882a593Smuzhiyun snprintf(adev->name, sizeof(adev->name) - 1, "apbt%d", i);
338*4882a593Smuzhiyun }
339*4882a593Smuzhiyun #endif
340*4882a593Smuzhiyun
341*4882a593Smuzhiyun return;
342*4882a593Smuzhiyun
343*4882a593Smuzhiyun out_noapbt:
344*4882a593Smuzhiyun apbt_clear_mapping();
345*4882a593Smuzhiyun apb_timer_block_enabled = 0;
346*4882a593Smuzhiyun panic("failed to enable APB timer\n");
347*4882a593Smuzhiyun }
348