mirror of
https://github.com/opnsense/src.git
synced 2026-06-13 18:50:31 -04:00
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.
This commit is contained in:
parent
e4b58dfe33
commit
38d3befe9c
1 changed files with 34 additions and 3 deletions
|
|
@ -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;
|
||||
|
|
@ -141,6 +142,28 @@ get_freq(void)
|
|||
return (get_el0(cntfrq));
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue