1/* $NetBSD: acpipmtimer.c,v 1.7 2009/05/12 14:25:17 cegger Exp $ */ 2 3#include <sys/cdefs.h> 4__KERNEL_RCSID(0, "$NetBSD: acpipmtimer.c,v 1.7 2009/05/12 14:25:17 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 19struct hwtc { 20 struct timecounter tc; 21 bus_space_tag_t t; 22 bus_space_handle_t h; 23 bus_size_t off; 24}; 25 26static u_int acpihwtimer_read_safe(struct timecounter *); 27static u_int acpihwtimer_read_fast(struct timecounter *); 28 29acpipmtimer_t 30acpipmtimer_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 65int 66acpipmtimer_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 75static u_int 76acpihwtimer_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 91static u_int 92acpihwtimer_read_fast(struct timecounter *tc) 93{ 94 struct hwtc *h = tc->tc_priv; 95 96 return r(h); 97} 98