Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 14 Jun 2018 17:18:15 +0000 (UTC)
From:      Emmanuel Vadot <manu@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r335156 - head/sys/arm/arm
Message-ID:  <201806141718.w5EHIFnE093607@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: manu
Date: Thu Jun 14 17:18:15 2018
New Revision: 335156
URL: https://svnweb.freebsd.org/changeset/base/335156

Log:
  arm timer: Add workaround for Allwinner A64 timer
  
  The timer present in allwinner A64 SoC is unstable, value can jump backward
  or forward.
  It was found that when bit 11 and upper roll over the low bits can sometimes
  being read as all as 1 or all as 0.
  Simply ignore the values for those cases.

Modified:
  head/sys/arm/arm/generic_timer.c

Modified: head/sys/arm/arm/generic_timer.c
==============================================================================
--- head/sys/arm/arm/generic_timer.c	Thu Jun 14 17:09:33 2018	(r335155)
+++ head/sys/arm/arm/generic_timer.c	Thu Jun 14 17:18:15 2018	(r335156)
@@ -92,6 +92,7 @@ __FBSDID("$FreeBSD$");
 struct arm_tmr_softc {
 	struct resource		*res[4];
 	void			*ihl[4];
+	uint64_t		(*get_cntxct)(bool);
 	uint32_t		clkfreq;
 	struct eventtimer	et;
 	bool			physical;
@@ -142,6 +143,28 @@ get_freq(void)
 }
 
 static uint64_t
+get_cntxct_a64_unstable(bool physical)
+{
+	uint64_t val
+;
+	isb();
+	if (physical) {
+		do {
+			val = get_el0(cntpct);
+		}
+		while (((val + 1) & 0x7FF) <= 1);
+	}
+	else {
+		do {
+			val = get_el0(cntvct);
+		}
+		while (((val + 1) & 0x7FF) <= 1);
+	}
+
+	return (val);
+}
+
+static uint64_t
 get_cntxct(bool physical)
 {
 	uint64_t val;
@@ -226,7 +249,7 @@ static unsigned
 arm_tmr_get_timecount(struct timecounter *tc)
 {
 
-	return (get_cntxct(arm_tmr_sc->physical));
+	return (arm_tmr_sc->get_cntxct(arm_tmr_sc->physical));
 }
 
 static int
@@ -379,6 +402,7 @@ arm_tmr_attach(device_t dev)
 	if (arm_tmr_sc)
 		return (ENXIO);
 
+	sc->get_cntxct = &get_cntxct_a64_unstable;
 #ifdef FDT
 	/* Get the base clock frequency */
 	node = ofw_bus_get_node(dev);
@@ -387,6 +411,13 @@ arm_tmr_attach(device_t dev)
 		    sizeof(clock));
 		if (error > 0)
 			sc->clkfreq = clock;
+
+		if (OF_hasprop(node, "allwinner,sun50i-a64-unstable-timer")) {
+			sc->get_cntxct = &get_cntxct_a64_unstable;
+			if (bootverbose)
+				device_printf(dev,
+				    "Enabling allwinner unstable timer workaround\n");
+		}
 	}
 #endif
 
@@ -518,10 +549,10 @@ arm_tmr_do_delay(int usec, void *arg)
 	else
 		counts = usec * counts_per_usec;
 
-	first = get_cntxct(sc->physical);
+	first = sc->get_cntxct(sc->physical);
 
 	while (counts > 0) {
-		last = get_cntxct(sc->physical);
+		last = sc->get_cntxct(sc->physical);
 		counts -= (int32_t)(last - first);
 		first = last;
 	}



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201806141718.w5EHIFnE093607>