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