summaryrefslogtreecommitdiff
path: root/cpu
diff options
context:
space:
mode:
authorScott McNutt <smcnutt@psyent.com>2010-04-01 00:00:56 -0400
committerScott McNutt <smcnutt@psyent.com>2010-04-02 12:28:41 -0400
commitd8bc0a2889700ba063598de6d4e7d135360b537e (patch)
tree78412b80d2152b3690723179897fc5113c108b8e /cpu
parented2941578480d30b413e081b6f1a5675d4afd9e2 (diff)
nios2: Reload timer count in reset_timer()
When the timestamp is incremented via interrupt and the interrupt period is greater than 1 msec, successive calls to get_timer() can produce inaccurate timing since the interrupts are asynchronous to the timing loop. For example, with an interrupt period of 10 msec two successive calls to get_timer() could indicate an elapsed time of 10 msec after only several hundred usecs -- depending on when the next interrupt actually occurs. This behavior can cause reliability issues with components such as CFI and NAND. This can be remedied by calling reset_timer() prior to establishing the base timestamp with get_timer(0), provided reset_timer() resets the hardware timer (rather than simply resetting only the timestamp). This has the effect of synchronizing the interrupts (and the advance of the timestamp) with the timing loop. Signed-off-by: Scott McNutt <smcnutt@psyent.com>
Diffstat (limited to 'cpu')
-rw-r--r--cpu/nios2/interrupts.c33
1 files changed, 33 insertions, 0 deletions
diff --git a/cpu/nios2/interrupts.c b/cpu/nios2/interrupts.c
index 5c3b5e6146a..b552db4eba3 100644
--- a/cpu/nios2/interrupts.c
+++ b/cpu/nios2/interrupts.c
@@ -56,7 +56,40 @@ volatile ulong timestamp = 0;
void reset_timer (void)
{
+ nios_timer_t *tmr =(nios_timer_t *)CONFIG_SYS_NIOS_TMRBASE;
+
+ /* From Embedded Peripherals Handbook:
+ *
+ * "When the hardware is configured with Writeable period
+ * disabled, writing to one of the period_n registers causes
+ * the counter to reset to the fixed Timeout Period specified
+ * at system generation time."
+ *
+ * Here we force a reload to prevent early timeouts from
+ * get_timer() when the interrupt period is greater than
+ * than 1 msec.
+ *
+ * Simply write to periodl with its own value to force an
+ * internal counter reload, THEN reset the timestamp.
+ */
+ writel (readl (&tmr->periodl), &tmr->periodl);
timestamp = 0;
+
+ /* From Embedded Peripherals Handbook:
+ *
+ * "Writing to one of the period_n registers stops the internal
+ * counter, except when the hardware is configured with Start/Stop
+ * control bits off. If Start/Stop control bits is off, writing
+ * either register does not stop the counter."
+ *
+ * In order to accomodate either configuration, the control
+ * register is re-written. If the counter is stopped, it will
+ * be restarted. If it is running, the write is essentially
+ * a nop.
+ */
+ writel (NIOS_TIMER_ITO | NIOS_TIMER_CONT | NIOS_TIMER_START,
+ &tmr->control);
+
}
ulong get_timer (ulong base)