]>
Commit | Line | Data |
---|---|---|
312df5f1 AK |
1 | /* Ported over from i386 by AK, original copyright was: |
2 | * | |
3 | * (C) Dominik Brodowski <linux@brodo.de> 2003 | |
4 | * | |
5 | * Driver to use the Power Management Timer (PMTMR) available in some | |
6 | * southbridges as primary timing source for the Linux kernel. | |
7 | * | |
8 | * Based on parts of linux/drivers/acpi/hardware/hwtimer.c, timer_pit.c, | |
9 | * timer_hpet.c, and on Arjan van de Ven's implementation for 2.4. | |
10 | * | |
11 | * This file is licensed under the GPL v2. | |
12 | * | |
13 | * Dropped all the hardware bug workarounds for now. Hopefully they | |
14 | * are not needed on 64bit chipsets. | |
15 | */ | |
16 | ||
17 | #include <linux/jiffies.h> | |
18 | #include <linux/kernel.h> | |
19 | #include <linux/time.h> | |
20 | #include <linux/init.h> | |
21 | #include <linux/cpumask.h> | |
70a20025 TG |
22 | #include <linux/acpi_pmtmr.h> |
23 | ||
312df5f1 AK |
24 | #include <asm/io.h> |
25 | #include <asm/proto.h> | |
26 | #include <asm/msr.h> | |
27 | #include <asm/vsyscall.h> | |
28 | ||
312df5f1 AK |
29 | static inline u32 cyc2us(u32 cycles) |
30 | { | |
31 | /* The Power Management Timer ticks at 3.579545 ticks per microsecond. | |
32 | * 1 / PM_TIMER_FREQUENCY == 0.27936511 =~ 286/1024 [error: 0.024%] | |
33 | * | |
34 | * Even with HZ = 100, delta is at maximum 35796 ticks, so it can | |
35 | * easily be multiplied with 286 (=0x11E) without having to fear | |
36 | * u32 overflows. | |
37 | */ | |
38 | cycles *= 286; | |
39 | return (cycles >> 10); | |
40 | } | |
41 | ||
0c3749c4 AK |
42 | static unsigned pmtimer_wait_tick(void) |
43 | { | |
44 | u32 a, b; | |
45 | for (a = b = inl(pmtmr_ioport) & ACPI_PM_MASK; | |
46 | a == b; | |
47 | b = inl(pmtmr_ioport) & ACPI_PM_MASK) | |
c36cd16f | 48 | cpu_relax(); |
0c3749c4 AK |
49 | return b; |
50 | } | |
51 | ||
52 | /* note: wait time is rounded up to one tick */ | |
53 | void pmtimer_wait(unsigned us) | |
54 | { | |
55 | u32 a, b; | |
56 | a = pmtimer_wait_tick(); | |
57 | do { | |
58 | b = inl(pmtmr_ioport); | |
c36cd16f | 59 | cpu_relax(); |
0c3749c4 AK |
60 | } while (cyc2us(b - a) < us); |
61 | } | |
62 | ||
312df5f1 AK |
63 | static int __init nopmtimer_setup(char *s) |
64 | { | |
65 | pmtmr_ioport = 0; | |
9b41046c | 66 | return 1; |
312df5f1 AK |
67 | } |
68 | ||
69 | __setup("nopmtimer", nopmtimer_setup); |