1 /* $NetBSD: acpipmtimer.c,v 1.6 2008/04/08 12:07:25 cegger Exp $ */ 2 3 #include <sys/cdefs.h> 4 __KERNEL_RCSID(0, "$NetBSD: acpipmtimer.c,v 1.6 2008/04/08 12:07:25 cegger 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 int 30 acpipmtimer_attach(struct device *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) 38 return (-1); 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 (0); 63 } 64 65 #define r(h) bus_space_read_4(h->t, h->h, h->off) 66 67 static u_int 68 acpihwtimer_read_safe(struct timecounter *tc) 69 { 70 struct hwtc *h = tc->tc_priv; 71 uint32_t t1, t2, t3; 72 73 t2 = r(h); 74 t3 = r(h); 75 do { 76 t1 = t2; 77 t2 = t3; 78 t3 = r(h); 79 } while ((t1 > t2) || (t2 > t3)); 80 return (t2); 81 } 82 83 static u_int 84 acpihwtimer_read_fast(struct timecounter *tc) 85 { 86 struct hwtc *h = tc->tc_priv; 87 88 return r(h); 89 } 90