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