Home | History | Annotate | Line # | Download | only in ic
      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