1 | /* $NetBSD: acpipmtimer.c,v 1.8 2009/08/18 17:47:46 dyoung Exp $ */ |
2 | |
3 | #include <sys/cdefs.h> |
4 | __KERNEL_RCSID(0, "$NetBSD: acpipmtimer.c,v 1.8 2009/08/18 17:47:46 dyoung Exp $" ); |
5 | |
6 | #include <sys/types.h> |
7 | |
8 | #include <sys/systm.h> |
9 | #include <sys/device.h> |
10 | #include <sys/malloc.h> |
11 | #include <sys/bus.h> |
12 | #include <sys/time.h> |
13 | #include <sys/timetc.h> |
14 | |
15 | #include <dev/ic/acpipmtimer.h> |
16 | |
17 | #define ACPI_PM_TIMER_FREQUENCY 3579545 |
18 | |
19 | struct hwtc { |
20 | struct timecounter tc; |
21 | bus_space_tag_t t; |
22 | bus_space_handle_t h; |
23 | bus_size_t off; |
24 | }; |
25 | |
26 | static u_int acpihwtimer_read_safe(struct timecounter *); |
27 | static u_int acpihwtimer_read_fast(struct timecounter *); |
28 | |
29 | acpipmtimer_t |
30 | acpipmtimer_attach(device_t dev, |
31 | bus_space_tag_t t, bus_space_handle_t h, bus_size_t off, |
32 | int flags) |
33 | { |
34 | struct hwtc *tc; |
35 | |
36 | tc = malloc(sizeof(struct hwtc), M_DEVBUF, M_WAITOK|M_ZERO); |
37 | if (tc == NULL) |
38 | return NULL; |
39 | |
40 | tc->tc.tc_name = device_xname(dev); |
41 | tc->tc.tc_frequency = ACPI_PM_TIMER_FREQUENCY; |
42 | if (flags & ACPIPMT_32BIT) |
43 | tc->tc.tc_counter_mask = 0xffffffff; |
44 | else |
45 | tc->tc.tc_counter_mask = 0x00ffffff; |
46 | if (flags & ACPIPMT_BADLATCH) { |
47 | tc->tc.tc_get_timecount = acpihwtimer_read_safe; |
48 | tc->tc.tc_quality = 900; |
49 | } else { |
50 | tc->tc.tc_get_timecount = acpihwtimer_read_fast; |
51 | tc->tc.tc_quality = 1000; |
52 | } |
53 | |
54 | tc->t = t; |
55 | tc->h = h; |
56 | tc->off = off; |
57 | |
58 | tc->tc.tc_priv = tc; |
59 | tc_init(&tc->tc); |
60 | aprint_normal("%s: %d-bit timer\n" , tc->tc.tc_name, |
61 | (flags & ACPIPMT_32BIT ? 32 : 24)); |
62 | return tc; |
63 | } |
64 | |
65 | int |
66 | acpipmtimer_detach(acpipmtimer_t timer, int flags) |
67 | { |
68 | struct hwtc *tc = timer; |
69 | |
70 | return tc_detach(&tc->tc); |
71 | } |
72 | |
73 | #define r(h) bus_space_read_4(h->t, h->h, h->off) |
74 | |
75 | static u_int |
76 | acpihwtimer_read_safe(struct timecounter *tc) |
77 | { |
78 | struct hwtc *h = tc->tc_priv; |
79 | uint32_t t1, t2, t3; |
80 | |
81 | t2 = r(h); |
82 | t3 = r(h); |
83 | do { |
84 | t1 = t2; |
85 | t2 = t3; |
86 | t3 = r(h); |
87 | } while ((t1 > t2) || (t2 > t3)); |
88 | return (t2); |
89 | } |
90 | |
91 | static u_int |
92 | acpihwtimer_read_fast(struct timecounter *tc) |
93 | { |
94 | struct hwtc *h = tc->tc_priv; |
95 | |
96 | return r(h); |
97 | } |
98 | |