2009-08-18 21:47:46 +04:00
|
|
|
/* $NetBSD: acpipmtimer.c,v 1.8 2009/08/18 17:47:46 dyoung Exp $ */
|
2007-08-27 10:18:55 +04:00
|
|
|
|
|
|
|
#include <sys/cdefs.h>
|
2009-08-18 21:47:46 +04:00
|
|
|
__KERNEL_RCSID(0, "$NetBSD: acpipmtimer.c,v 1.8 2009/08/18 17:47:46 dyoung Exp $");
|
2006-06-26 20:13:21 +04:00
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
|
|
|
#include <sys/systm.h>
|
|
|
|
#include <sys/device.h>
|
|
|
|
#include <sys/malloc.h>
|
2007-10-19 15:59:34 +04:00
|
|
|
#include <sys/bus.h>
|
2006-06-26 20:13:21 +04:00
|
|
|
#include <sys/time.h>
|
|
|
|
#include <sys/timetc.h>
|
|
|
|
|
|
|
|
#include <dev/ic/acpipmtimer.h>
|
|
|
|
|
|
|
|
#define ACPI_PM_TIMER_FREQUENCY 3579545
|
|
|
|
|
|
|
|
struct hwtc {
|
|
|
|
struct timecounter tc;
|
|
|
|
bus_space_tag_t t;
|
|
|
|
bus_space_handle_t h;
|
|
|
|
bus_size_t off;
|
|
|
|
};
|
|
|
|
|
|
|
|
static u_int acpihwtimer_read_safe(struct timecounter *);
|
|
|
|
static u_int acpihwtimer_read_fast(struct timecounter *);
|
|
|
|
|
2009-08-18 21:47:46 +04:00
|
|
|
acpipmtimer_t
|
2009-05-12 18:16:35 +04:00
|
|
|
acpipmtimer_attach(device_t dev,
|
2006-06-26 20:13:21 +04:00
|
|
|
bus_space_tag_t t, bus_space_handle_t h, bus_size_t off,
|
|
|
|
int flags)
|
|
|
|
{
|
|
|
|
struct hwtc *tc;
|
|
|
|
|
|
|
|
tc = malloc(sizeof(struct hwtc), M_DEVBUF, M_WAITOK|M_ZERO);
|
2009-08-18 21:47:46 +04:00
|
|
|
if (tc == NULL)
|
|
|
|
return NULL;
|
2006-06-26 20:13:21 +04:00
|
|
|
|
2008-04-08 16:07:25 +04:00
|
|
|
tc->tc.tc_name = device_xname(dev);
|
2006-06-26 20:13:21 +04:00
|
|
|
tc->tc.tc_frequency = ACPI_PM_TIMER_FREQUENCY;
|
|
|
|
if (flags & ACPIPMT_32BIT)
|
|
|
|
tc->tc.tc_counter_mask = 0xffffffff;
|
|
|
|
else
|
|
|
|
tc->tc.tc_counter_mask = 0x00ffffff;
|
|
|
|
if (flags & ACPIPMT_BADLATCH) {
|
|
|
|
tc->tc.tc_get_timecount = acpihwtimer_read_safe;
|
|
|
|
tc->tc.tc_quality = 900;
|
|
|
|
} else {
|
|
|
|
tc->tc.tc_get_timecount = acpihwtimer_read_fast;
|
|
|
|
tc->tc.tc_quality = 1000;
|
|
|
|
}
|
|
|
|
|
|
|
|
tc->t = t;
|
|
|
|
tc->h = h;
|
|
|
|
tc->off = off;
|
|
|
|
|
|
|
|
tc->tc.tc_priv = tc;
|
|
|
|
tc_init(&tc->tc);
|
2007-08-27 10:17:28 +04:00
|
|
|
aprint_normal("%s: %d-bit timer\n", tc->tc.tc_name,
|
2006-06-26 20:13:21 +04:00
|
|
|
(flags & ACPIPMT_32BIT ? 32 : 24));
|
2009-08-18 21:47:46 +04:00
|
|
|
return tc;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
acpipmtimer_detach(acpipmtimer_t timer, int flags)
|
|
|
|
{
|
|
|
|
struct hwtc *tc = timer;
|
|
|
|
|
|
|
|
return tc_detach(&tc->tc);
|
2006-06-26 20:13:21 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
#define r(h) bus_space_read_4(h->t, h->h, h->off)
|
|
|
|
|
|
|
|
static u_int
|
|
|
|
acpihwtimer_read_safe(struct timecounter *tc)
|
|
|
|
{
|
|
|
|
struct hwtc *h = tc->tc_priv;
|
|
|
|
uint32_t t1, t2, t3;
|
|
|
|
|
|
|
|
t2 = r(h);
|
|
|
|
t3 = r(h);
|
|
|
|
do {
|
|
|
|
t1 = t2;
|
|
|
|
t2 = t3;
|
|
|
|
t3 = r(h);
|
|
|
|
} while ((t1 > t2) || (t2 > t3));
|
|
|
|
return (t2);
|
|
|
|
}
|
|
|
|
|
|
|
|
static u_int
|
|
|
|
acpihwtimer_read_fast(struct timecounter *tc)
|
|
|
|
{
|
|
|
|
struct hwtc *h = tc->tc_priv;
|
|
|
|
|
|
|
|
return r(h);
|
|
|
|
}
|