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