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