xref: /netbsd/sys/dev/ic/acpipmtimer.c (revision 6550d01e)
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