summaryrefslogtreecommitdiff
path: root/sys/arch/armv7
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2016-07-18 19:22:46 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2016-07-18 19:22:46 +0000
commitad32aa7c281ff2706d1d0c5e0aa1d9cb1dd6c775 (patch)
tree7de02bd0971fe07d86376439468ac29c3b6a412b /sys/arch/armv7
parent2b8bdfa8472fc8f72e3dc32e3aa059a742e86e80 (diff)
Apparently we need to explicitly stop the timers before reloading them. At
least this is what Linux does and it fixes a hang on the Olimex A10s boards. While there, also preserve the clock selection when reloading the timer. ok patrick@, jsg@, tom@
Diffstat (limited to 'sys/arch/armv7')
-rw-r--r--sys/arch/armv7/sunxi/sxitimer.c38
1 files changed, 35 insertions, 3 deletions
diff --git a/sys/arch/armv7/sunxi/sxitimer.c b/sys/arch/armv7/sunxi/sxitimer.c
index 4062b87ffe4..e882a4eada4 100644
--- a/sys/arch/armv7/sunxi/sxitimer.c
+++ b/sys/arch/armv7/sunxi/sxitimer.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sxitimer.c,v 1.5 2016/02/01 23:31:34 jsg Exp $ */
+/* $OpenBSD: sxitimer.c,v 1.6 2016/07/18 19:22:45 kettenis Exp $ */
/*
* Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org>
* Copyright (c) 2013 Raphael Graf <r@undefined.ch>
@@ -76,6 +76,8 @@
#define STATTIMER 1
#define CNTRTIMER 2
+#define TIMER_SYNC 3
+
void sxitimer_attach(struct device *, struct device *, void *);
int sxitimer_tickintr(void *);
int sxitimer_statintr(void *);
@@ -83,6 +85,7 @@ void sxitimer_cpu_initclocks(void);
void sxitimer_setstatclockrate(int);
uint64_t sxitimer_readcnt64(void);
uint32_t sxitimer_readcnt32(void);
+void sxitimer_sync(void);
void sxitimer_delay(u_int);
u_int sxitimer_get_timecount(struct timecounter *);
@@ -267,6 +270,7 @@ int
sxitimer_tickintr(void *frame)
{
uint32_t now, nextevent;
+ uint32_t val;
int rc = 0;
splassert(IPL_CLOCK);
@@ -304,12 +308,21 @@ sxitimer_tickintr(void *frame)
sxitimer_tick_nextevt = now;
}
+ val = bus_space_read_4(sxitimer_iot, sxitimer_ioh,
+ TIMER_CTRL(TICKTIMER));
+ bus_space_write_4(sxitimer_iot, sxitimer_ioh,
+ TIMER_CTRL(TICKTIMER), val & ~TIMER_ENABLE);
+
+ sxitimer_sync();
+
bus_space_write_4(sxitimer_iot, sxitimer_ioh,
TIMER_INTV(TICKTIMER), nextevent);
+ val = bus_space_read_4(sxitimer_iot, sxitimer_ioh,
+ TIMER_CTRL(TICKTIMER));
bus_space_write_4(sxitimer_iot, sxitimer_ioh,
TIMER_CTRL(TICKTIMER),
- TIMER_ENABLE | TIMER_RELOAD | TIMER_SINGLESHOT);
+ val | TIMER_ENABLE | TIMER_RELOAD | TIMER_SINGLESHOT);
return rc;
}
@@ -318,6 +331,7 @@ int
sxitimer_statintr(void *frame)
{
uint32_t now, nextevent, r;
+ uint32_t val;
int rc = 0;
splassert(IPL_STATCLOCK);
@@ -352,12 +366,21 @@ sxitimer_statintr(void *frame)
sxitimer_stat_nextevt = now;
}
+ val = bus_space_read_4(sxitimer_iot, sxitimer_ioh,
+ TIMER_CTRL(STATTIMER));
+ bus_space_write_4(sxitimer_iot, sxitimer_ioh,
+ TIMER_CTRL(STATTIMER), val & ~TIMER_ENABLE);
+
+ sxitimer_sync();
+
bus_space_write_4(sxitimer_iot, sxitimer_ioh,
TIMER_INTV(STATTIMER), nextevent);
+ val = bus_space_read_4(sxitimer_iot, sxitimer_ioh,
+ TIMER_CTRL(STATTIMER));
bus_space_write_4(sxitimer_iot, sxitimer_ioh,
TIMER_CTRL(STATTIMER),
- TIMER_ENABLE | TIMER_RELOAD | TIMER_SINGLESHOT);
+ val | TIMER_ENABLE | TIMER_RELOAD | TIMER_SINGLESHOT);
return rc;
}
@@ -391,6 +414,15 @@ sxitimer_readcnt32(void)
}
void
+sxitimer_sync(void)
+{
+ uint32_t now = sxitimer_readcnt32();
+
+ while ((now - sxitimer_readcnt32()) < TIMER_SYNC)
+ CPU_BUSY_CYCLE();
+}
+
+void
sxitimer_delay(u_int usecs)
{
uint64_t oclock, timeout;