summaryrefslogtreecommitdiff
path: root/sys/arch/arm/cortex/agtimer.c
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2016-08-10 06:51:58 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2016-08-10 06:51:58 +0000
commit97360e4f7fb79c7ed9e72ac047993fd9d925f0e2 (patch)
tree091f29080ee707d30ddf3a27b993b97be74ac2d9 /sys/arch/arm/cortex/agtimer.c
parent8327ec8e10ed3b4aa49efdee4df51ed8b2b4deb7 (diff)
Dynamically attach agtimer(4). Since agtimer(4) also provides the delay()
function for platforms that have it, rework the code a bit such that it can be used before agtimer(4) attaches. Introduce a new agtimer_init() function that checks whether the CPU implements the Generic Timer feature and switches to agtimer_delay() if that feature is present. Call this function from the generic platform initialization code. ok jsg@
Diffstat (limited to 'sys/arch/arm/cortex/agtimer.c')
-rw-r--r--sys/arch/arm/cortex/agtimer.c92
1 files changed, 51 insertions, 41 deletions
diff --git a/sys/arch/arm/cortex/agtimer.c b/sys/arch/arm/cortex/agtimer.c
index 38c8edaaefa..c2692c14481 100644
--- a/sys/arch/arm/cortex/agtimer.c
+++ b/sys/arch/arm/cortex/agtimer.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: agtimer.c,v 1.6 2016/08/05 13:31:29 kettenis Exp $ */
+/* $OpenBSD: agtimer.c,v 1.7 2016/08/10 06:51:57 kettenis Exp $ */
/*
* Copyright (c) 2011 Dale Rahn <drahn@openbsd.org>
* Copyright (c) 2013 Patrick Wildt <patrick@blueri.se>
@@ -25,11 +25,16 @@
#include <sys/timetc.h>
#include <sys/evcount.h>
-#include <arm/cpufunc.h>
-#include <machine/bus.h>
#include <machine/intr.h>
+#include <machine/bus.h>
+#include <machine/fdt.h>
+
+#include <arm/cpufunc.h>
#include <arm/cortex/cortex.h>
+#include <dev/ofw/fdt.h>
+#include <dev/ofw/openfirm.h>
+
/* registers */
#define GTIMER_CNTP_CTL_ENABLE (1 << 0)
#define GTIMER_CNTP_CTL_IMASK (1 << 1)
@@ -54,6 +59,7 @@ struct agtimer_pcpu_softc {
struct agtimer_softc {
struct device sc_dev;
+ int sc_node;
struct agtimer_pcpu_softc sc_pstat[MAX_ARM_CPUS];
@@ -71,7 +77,7 @@ struct agtimer_softc {
int agtimer_match(struct device *, void *, void *);
void agtimer_attach(struct device *, struct device *, void *);
-uint64_t agtimer_readcnt64(struct agtimer_softc *sc);
+uint64_t agtimer_readcnt64(void);
int agtimer_intr(void *);
void agtimer_cpu_initclocks(void);
void agtimer_delay(u_int);
@@ -79,15 +85,6 @@ void agtimer_setstatclockrate(int stathz);
void agtimer_set_clockrate(int32_t new_frequency);
void agtimer_startclock(void);
-/* hack - XXXX
- * agtimer connects directly to ampintc, not thru the generic
- * interface because it uses an 'internal' interrupt
- * not a peripheral interrupt.
- */
-void *ampintc_intr_establish(int, int, int (*)(void *), void *, char *);
-
-
-
struct cfattach agtimer_ca = {
sizeof (struct agtimer_softc), agtimer_match, agtimer_attach
};
@@ -97,7 +94,7 @@ struct cfdriver agtimer_cd = {
};
uint64_t
-agtimer_readcnt64(struct agtimer_softc *sc)
+agtimer_readcnt64(void)
{
uint64_t val;
@@ -152,20 +149,23 @@ agtimer_set_tval(uint32_t val)
int
agtimer_match(struct device *parent, void *cfdata, void *aux)
{
- if ((cpufunc_id() & CPU_ID_CORTEX_A7_MASK) == CPU_ID_CORTEX_A7 ||
- (cpufunc_id() & CPU_ID_CORTEX_A15_MASK) == CPU_ID_CORTEX_A15 ||
- (cpufunc_id() & CPU_ID_CORTEX_A17_MASK) == CPU_ID_CORTEX_A17)
- return (1);
+ struct fdt_attach_args *faa = (struct fdt_attach_args *)aux;
- return 0;
+ return OF_is_compatible(faa->fa_node, "arm,armv7-timer");
}
void
-agtimer_attach(struct device *parent, struct device *self, void *args)
+agtimer_attach(struct device *parent, struct device *self, void *aux)
{
struct agtimer_softc *sc = (struct agtimer_softc *)self;
+ struct fdt_attach_args *faa = aux;
+
+ sc->sc_node = faa->fa_node;
+ agtimer_frequency =
+ OF_getpropint(sc->sc_node, "clock-frequency", agtimer_frequency);
sc->sc_ticks_per_second = agtimer_frequency;
+
printf(": tick rate %d KHz\n", sc->sc_ticks_per_second /1000);
/* XXX: disable user access */
@@ -192,8 +192,7 @@ agtimer_attach(struct device *parent, struct device *self, void *args)
u_int
agtimer_get_timecount(struct timecounter *tc)
{
- struct agtimer_softc *sc = agtimer_timecounter.tc_priv;
- return agtimer_readcnt64(sc);
+ return agtimer_readcnt64();
}
int
@@ -218,7 +217,7 @@ agtimer_intr(void *frame)
* do the right thing
*/
- now = agtimer_readcnt64(sc);
+ now = agtimer_readcnt64();
while (pc->pc_nexttickevent <= now) {
pc->pc_nexttickevent += sc->sc_ticks_per_intr;
@@ -301,17 +300,13 @@ agtimer_cpu_initclocks()
sc->sc_ticks_err_cnt = sc->sc_ticks_per_second % hz;
pc->pc_ticks_err_sum = 0;
- /* establish interrupts */
- /* XXX - irq */
-
- /* secure physical timer */
- ampintc_intr_establish(29, IPL_CLOCK, agtimer_intr,
- NULL, "tick");
- /* non-secure physical timer */
- ampintc_intr_establish(30, IPL_CLOCK, agtimer_intr,
- NULL, "tick");
+ /* Setup secure and non-secure timer IRQs. */
+ arm_intr_establish_fdt_idx(sc->sc_node, 0, IPL_CLOCK,
+ agtimer_intr, NULL, "tick");
+ arm_intr_establish_fdt_idx(sc->sc_node, 1, IPL_CLOCK,
+ agtimer_intr, NULL, "tick");
- next = agtimer_readcnt64(sc) + sc->sc_ticks_per_intr;
+ next = agtimer_readcnt64() + sc->sc_ticks_per_intr;
pc->pc_nexttickevent = pc->pc_nextstatevent = next;
reg = agtimer_get_ctrl();
@@ -324,29 +319,28 @@ agtimer_cpu_initclocks()
void
agtimer_delay(u_int usecs)
{
- struct agtimer_softc *sc = agtimer_cd.cd_devs[0];
u_int32_t clock, oclock, delta, delaycnt;
volatile int j;
int csec, usec;
- if (usecs > (0x80000000 / (sc->sc_ticks_per_second))) {
+ if (usecs > (0x80000000 / agtimer_frequency)) {
csec = usecs / 10000;
usec = usecs % 10000;
- delaycnt = (sc->sc_ticks_per_second / 100) * csec +
- (sc->sc_ticks_per_second / 100) * usec / 10000;
+ delaycnt = (agtimer_frequency / 100) * csec +
+ (agtimer_frequency / 100) * usec / 10000;
} else {
- delaycnt = sc->sc_ticks_per_second * usecs / 1000000;
+ delaycnt = agtimer_frequency * usecs / 1000000;
}
if (delaycnt <= 1)
for (j = 100; j > 0; j--)
;
- oclock = agtimer_readcnt64(sc);
+ oclock = agtimer_readcnt64();
while (1) {
for (j = 100; j > 0; j--)
;
- clock = agtimer_readcnt64(sc);
+ clock = agtimer_readcnt64();
delta = clock - oclock;
if (delta > delaycnt)
break;
@@ -387,7 +381,7 @@ agtimer_startclock(void)
uint64_t nextevent;
uint32_t reg;
- nextevent = agtimer_readcnt64(sc) + sc->sc_ticks_per_intr;
+ nextevent = agtimer_readcnt64() + sc->sc_ticks_per_intr;
pc->pc_nexttickevent = pc->pc_nextstatevent = nextevent;
reg = agtimer_get_ctrl();
@@ -396,3 +390,19 @@ agtimer_startclock(void)
agtimer_set_tval(sc->sc_ticks_per_second);
agtimer_set_ctrl(reg);
}
+
+void
+agtimer_init(void)
+{
+ uint32_t id_pfr1, cntfrq = 0;
+
+ /* Check for Generic Timer support. */
+ __asm volatile("mrc p15, 0, %0, c0, c1, 1" : "=r"(id_pfr1));
+ if ((id_pfr1 & 0x000f0000) == 0x00010000)
+ __asm volatile("mrc p15, 0, %0, c14, c0, 0" : "=r" (cntfrq));
+
+ if (cntfrq != 0) {
+ agtimer_frequency = cntfrq;
+ arm_clock_register(NULL, agtimer_delay, NULL, NULL);
+ }
+}