All of lore.kernel.org
 help / color / mirror / Atom feed
From: Alessandro Rubini <rubini-list@gnudd.com>
To: u-boot@lists.denx.de
Subject: [U-Boot] [PATCH v3] arm nomadik: use 1000 as HZ value and rewrite timer code
Date: Mon, 29 Jun 2009 12:52:37 +0200	[thread overview]
Message-ID: <20090629105237.GA11969@mail.gnudd.com> (raw)
In-Reply-To: <20090627220232.GR8587@game.jcrosoft.org>

From: Alessandro Rubini <rubini@unipv.it>

This sets CONFIG_SYS_HZ to 1000 as required, and completely rewrites
timer code, which is now both correct and much smaller.  Unused
functions like udelay_masked() have been removed as no driver uses
them, even the ones that are not currently active for this board.
mtu.h is copied literally from the kernel sources.

Signed-off-by: Alessandro Rubini <rubini@unipv.it>
Acked-by: Andrea Gallo <andrea.gallo@stericsson.com>
---

I've used mtu.h from kernel sources and done the other changes as requested
(the extra variable just to return it was a mishap from an earlier printf
I needed to find a misconfig).

> for the record what is its precision now?

it counts at 2.4MHz, so the 1000HZ tick has no approximation and udelay
is correct with sub-microsecond error. I'll use in soft_i2c, needed to
turn on the LCD light.

 cpu/arm926ejs/nomadik/mtu.h   |   45 +++++++++++
 cpu/arm926ejs/nomadik/timer.c |  166 +++++++----------------------------------
 include/configs/nhk8815.h     |    2 +-
 3 files changed, 73 insertions(+), 140 deletions(-)
 create mode 100644 cpu/arm926ejs/nomadik/mtu.h

diff --git a/cpu/arm926ejs/nomadik/mtu.h b/cpu/arm926ejs/nomadik/mtu.h
new file mode 100644
index 0000000..21b4a7a
--- /dev/null
+++ b/cpu/arm926ejs/nomadik/mtu.h
@@ -0,0 +1,45 @@
+
+#ifndef __ASM_ARCH_MTU_H
+#define __ASM_ARCH_MTU_H
+
+/*
+ * The MTU device hosts four different counters, with 4 set of
+ * registers. These are register names.
+ */
+
+#define MTU_IMSC	0x00	/* Interrupt mask set/clear */
+#define MTU_RIS		0x04	/* Raw interrupt status */
+#define MTU_MIS		0x08	/* Masked interrupt status */
+#define MTU_ICR		0x0C	/* Interrupt clear register */
+
+/* per-timer registers take 0..3 as argument */
+#define MTU_LR(x)	(0x10 + 0x10 * (x) + 0x00)	/* Load value */
+#define MTU_VAL(x)	(0x10 + 0x10 * (x) + 0x04)	/* Current value */
+#define MTU_CR(x)	(0x10 + 0x10 * (x) + 0x08)	/* Control reg */
+#define MTU_BGLR(x)	(0x10 + 0x10 * (x) + 0x0c)	/* At next overflow */
+
+/* bits for the control register */
+#define MTU_CRn_ENA		0x80
+#define MTU_CRn_PERIODIC	0x40	/* if 0 = free-running */
+#define MTU_CRn_PRESCALE_MASK	0x0c
+#define MTU_CRn_PRESCALE_1		0x00
+#define MTU_CRn_PRESCALE_16		0x04
+#define MTU_CRn_PRESCALE_256		0x08
+#define MTU_CRn_32BITS		0x02
+#define MTU_CRn_ONESHOT		0x01	/* if 0 = wraps reloading from BGLR*/
+
+/* Other registers are usual amba/primecell registers, currently not used */
+#define MTU_ITCR	0xff0
+#define MTU_ITOP	0xff4
+
+#define MTU_PERIPH_ID0	0xfe0
+#define MTU_PERIPH_ID1	0xfe4
+#define MTU_PERIPH_ID2	0xfe8
+#define MTU_PERIPH_ID3	0xfeC
+
+#define MTU_PCELL0	0xff0
+#define MTU_PCELL1	0xff4
+#define MTU_PCELL2	0xff8
+#define MTU_PCELL3	0xffC
+
+#endif /* __ASM_ARCH_MTU_H */
diff --git a/cpu/arm926ejs/nomadik/timer.c b/cpu/arm926ejs/nomadik/timer.c
index 2870d24..d0946ec 100644
--- a/cpu/arm926ejs/nomadik/timer.c
+++ b/cpu/arm926ejs/nomadik/timer.c
@@ -1,20 +1,5 @@
 /*
- * (C) Copyright 2003
- * Texas Instruments <www.ti.com>
- *
- * (C) Copyright 2002
- * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
- * Marius Groeger <mgroeger@sysgo.de>
- *
- * (C) Copyright 2002
- * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
- * Alex Zuepke <azu@sysgo.de>
- *
- * (C) Copyright 2002-2004
- * Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
- *
- * (C) Copyright 2004
- * Philippe Robin, ARM Ltd. <philippe.robin@arm.com>
+ * (C) Copyright 2009 Alessandro Rubini
  *
  * See file CREDITS for list of people who contributed to this
  * project.
@@ -37,146 +22,49 @@
 
 #include <common.h>
 #include <asm/io.h>
+#include "mtu.h"
 
-#define TIMER_LOAD_VAL 0xffffffff
-
-/* macro to read the 32 bit timer */
-#define READ_TIMER readl(CONFIG_SYS_TIMERBASE + 20)
+/*
+ * The timer is a decrementer, we'll left it free running at 2.4MHz.
+ * We have 2.4 ticks per microsecond and an overflow in almost 30min
+ */
+#define TIMER_CLOCK		(24 * 100 * 1000)
+#define COUNT_TO_USEC(x)	((x) * 5 / 12)	/* overflows at 6min */
+#define USEC_TO_COUNT(x)	((x) * 12 / 5)	/* overflows at 6min */
+#define TICKS_PER_HZ		(TIMER_CLOCK / CONFIG_SYS_HZ)
+#define TICKS_TO_HZ(x)		((x) / TICKS_PER_HZ)
 
-static ulong timestamp;
-static ulong lastdec;
+/* macro to read the 32 bit timer: since it decrements, we invert read value */
+#define READ_TIMER() (~readl(CONFIG_SYS_TIMERBASE + MTU_VAL(0)))
 
-/* nothing really to do with interrupts, just starts up a counter. */
+/* Configure a free-running, auto-wrap counter with no prescaler */
 int timer_init(void)
 {
-	/* Load timer with initial value */
-	writel(TIMER_LOAD_VAL, CONFIG_SYS_TIMERBASE + 16);
-
-	/*
-	 * Set timer to be enabled, free-running, no interrupts, 256 divider,
-	 * 32-bit, wrap-mode
-	 */
-	writel(0x8a, CONFIG_SYS_TIMERBASE + 24);
-
-	/* init the timestamp and lastdec value */
-	reset_timer_masked();
-
+	writel(MTU_CRn_ENA | MTU_CRn_PRESCALE_1 | MTU_CRn_32BITS,
+	       CONFIG_SYS_TIMERBASE + MTU_CR(0));
+	reset_timer();
 	return 0;
 }
 
-/*
- * timer without interrupts
- */
+/* Restart counting from 0 */
 void reset_timer(void)
 {
-	reset_timer_masked();
+	writel(0, CONFIG_SYS_TIMERBASE + MTU_LR(0)); /* Immediate effect */
 }
 
+/* Return how many HZ passed since "base" */
 ulong get_timer(ulong base)
 {
-	return get_timer_masked() - base;
+	return  TICKS_TO_HZ(READ_TIMER()) - base;
 }
 
-void set_timer(ulong t)
-{
-	timestamp = t;
-}
-
-/* delay x useconds AND perserve advance timstamp value */
+/* Delay x useconds */
 void udelay(unsigned long usec)
 {
-	ulong tmo, tmp;
-
-	if (usec >= 1000) {
-		/* if "big" number, spread normalization to seconds */
-		tmo = usec / 1000;	/* start to normalize */
-		tmo *= CONFIG_SYS_HZ;	/* find number of "ticks" */
-		tmo /= 1000;		/* finish normalize. */
-	} else {
-		/* small number, don't kill it prior to HZ multiply */
-		tmo = usec * CONFIG_SYS_HZ;
-		tmo /= (1000 * 1000);
-	}
-
-	tmp = get_timer(0);		/* get current timestamp */
-	if ((tmo + tmp + 1) < tmp)	/* will roll time stamp? */
-		reset_timer_masked();	/* reset to 0, set lastdec value */
-	else
-		tmo += tmp;
-
-	while (get_timer_masked() < tmo)
-		/* nothing */ ;
-}
-
-void reset_timer_masked(void)
-{
-	/* reset time */
-	lastdec = READ_TIMER;	/* capure current decrementer value time */
-	timestamp = 0;		/* start "advancing" time stamp from 0 */
-}
-
-ulong get_timer_masked(void)
-{
-	ulong now = READ_TIMER;		/* current tick value */
-
-	if (lastdec >= now) {		/* normal mode (non roll) */
-		/* move stamp fordward */
-		timestamp += lastdec - now;
-	} else {
-		/*
-		 * An overflow is expected.
-		 * nts = ts + ld + (TLV - now)
-		 * ts=old stamp, ld=time that passed before passing through -1
-		 * (TLV-now) amount of time after passing though -1
-		 * nts = new "advancing time stamp"...it could also roll
-		 */
-		timestamp += lastdec + TIMER_LOAD_VAL - now;
-	}
-	lastdec = now;
-
-	return timestamp;
-}
-
-/* waits specified delay value and resets timestamp */
-void udelay_masked(unsigned long usec)
-{
-	ulong tmo;
-
-	if (usec >= 1000) {
-		/* if "big" number, spread normalization to seconds */
-		tmo = usec / 1000;	/* start to normalize */
-		tmo *= CONFIG_SYS_HZ;	/* find number of "ticks" */
-		tmo /= 1000;		/* finish normalize. */
-	} else {
-		/* else small number, don't kill it prior to HZ multiply */
-		tmo = usec * CONFIG_SYS_HZ;
-		tmo /= (1000*1000);
-	}
-
-	reset_timer_masked();
-	/* set "advancing" timestamp to 0, set lastdec vaule */
-
-	while (get_timer_masked() < tmo)
-		/* nothing */ ;
-}
-
-/*
- * This function is derived from PowerPC code (read timebase as long long).
- * On ARM it just returns the timer value.
- */
-unsigned long long get_ticks(void)
-{
-	return get_timer(0);
-}
-
-/*
- * This function is derived from PowerPC code (timebase clock frequency).
- * On ARM it returns the number of timer ticks per second.
- */
-ulong get_tbclk(void)
-{
-	ulong tbclk;
+	ulong ini, end;
 
-	tbclk = CONFIG_SYS_HZ;
-	return tbclk;
+	ini = READ_TIMER();
+	end = ini + USEC_TO_COUNT(usec);
+	while ((signed)(end - READ_TIMER()) > 0)
+		;
 }
diff --git a/include/configs/nhk8815.h b/include/configs/nhk8815.h
index bf1a915..3e2e09f 100644
--- a/include/configs/nhk8815.h
+++ b/include/configs/nhk8815.h
@@ -96,7 +96,7 @@
 #define CONFIG_MISC_INIT_R	/* call misc_init_r during start up */
 
 /* timing informazion */
-#define CONFIG_SYS_HZ		(2400000 / 256)	/* Timer0: 2.4Mhz + divider */
+#define CONFIG_SYS_HZ		1000 /* Mandatory... */
 #define CONFIG_SYS_TIMERBASE	0x101E2000
 
 /* serial port (PL011) configuration */
-- 
1.5.6.5

  reply	other threads:[~2009-06-29 10:52 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-06-22  9:18 [U-Boot] [PATCH 0/4 v2] Clean up the Nomadik board and add OneNand Alessandro Rubini
2009-06-22  9:18 ` [U-Boot] [PATCH 1/4 v2] arm nomadik: rename board to nhk8815 Alessandro Rubini
2009-06-22  9:18 ` [U-Boot] [PATCH 2/4 v2] arm nomadik: cleanup reset Alessandro Rubini
2009-06-22  9:18 ` [U-Boot] [PATCH 3/4 v2] arm nomadik: allow Nand and OneNand to coexists Alessandro Rubini
2009-06-22  9:19 ` [U-Boot] [PATCH 4/4 v2] arm nomadik: use 1000 as HZ value and rewrite timer code Alessandro Rubini
2009-06-25 21:46 ` [U-Boot] [PATCH 0/4 v2] Clean up the Nomadik board and add OneNand Jean-Christophe PLAGNIOL-VILLARD
     [not found] ` <6a60aa4cc4e40f72a235dd845d4d4a3f06f373b7.1245661681.git.rubini@unipv.it>
2009-06-27 22:02   ` [U-Boot] [PATCH 4/4 v2] arm nomadik: use 1000 as HZ value and rewrite timer code Jean-Christophe PLAGNIOL-VILLARD
2009-06-29 10:52     ` Alessandro Rubini [this message]
2009-06-29 20:25       ` [U-Boot] [PATCH v3] " Jean-Christophe PLAGNIOL-VILLARD
2009-07-02 21:16 ` [U-Boot] [PATCH 0/4 v2] Clean up the Nomadik board and add OneNand Jean-Christophe PLAGNIOL-VILLARD

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20090629105237.GA11969@mail.gnudd.com \
    --to=rubini-list@gnudd.com \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.