[U-Boot] [PATCH] Update s3c24x0 timer implementation

Mark Norman mpnorman at gmail.com
Mon Oct 31 11:58:50 CET 2011


The s3c24x0 timer has been updated to avoid using static variables prior
to BSS being made available.
Restructured code based on other timer.c files.
Updated comments and several parameters.

Signed-off-by: Mark Norman <mpnorman at gmail.com>
---
Changes for v2:
   - Fixed multi-line comment format
   - Formatting updates to separate declarations from code
   - Removed unrelated changes accidentally included in original patch
Changes for v3:
   - Added bitfield declarations to avoid using magic numbers.
   - Change to use existing global_data variables instead of creating new
     ones.

 arch/arm/cpu/arm920t/s3c24x0/timer.c |  180 ++++++++++++++++------------------
 1 files changed, 85 insertions(+), 95 deletions(-)

diff --git a/arch/arm/cpu/arm920t/s3c24x0/timer.c b/arch/arm/cpu/arm920t/s3c24x0/timer.c
index 9571870..8e1b935 100644
--- a/arch/arm/cpu/arm920t/s3c24x0/timer.c
+++ b/arch/arm/cpu/arm920t/s3c24x0/timer.c
@@ -35,116 +35,93 @@
 #include <asm/io.h>
 #include <asm/arch/s3c24x0_cpu.h>
 
-int timer_load_val = 0;
-static ulong timer_clk;
+/* Timer Control Register (TCON) bitfields */
+#define TCON_TMR4_AUTO_RELOAD (1<<22)
+#define TCON_TMR4_MAN_UPDATE  (1<<21)
+#define TCON_TMR4_START       (1<<20)
+#define TCON_TMR4_MASK        (TCON_TMR4_AUTO_RELOAD | TCON_TMR4_MAN_UPDATE | \
+				TCON_TMR4_START)
 
-/* macro to read the 16 bit timer */
-static inline ulong READ_TIMER(void)
+/* Timer Configuration Register 0 (TCFG0) bitfields */
+#define TCFG0_PRESCALER1(x)   (((x) & 0xff) << 8)
+
+/* Watchdog Timer Control Register (WTCON) bitfields */
+#define WTCON_TIMER_EN        (1<<5)
+#define WTCON_RESET_EN        (1<<0)
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define timestamp          (gd->tbl)
+#define lastdec            (gd->lastinc)
+#define timer_rate_hz      (gd->timer_rate_hz)
+#define timer_reset_value  (gd->timer_reset_value)
+
+/* Read the 16 bit timer */
+static inline ulong read_timer(void)
 {
 	struct s3c24x0_timers *timers = s3c24x0_get_base_timers();
 
 	return readl(&timers->tcnto4) & 0xffff;
 }
 
-static ulong timestamp;
-static ulong lastdec;
-
 int timer_init(void)
 {
+	/*
+	 * PWM Timer 4 is used because it has no output.
+	 * Prescaler is hard fixed at 250, divider at 2.
+	 * This generates a Timer clock frequency of 100kHz (@PCLK=50MHz) and
+	 * therefore 10us timer ticks.
+	 */
+	const ulong prescaler = 250;
+	const ulong divider = 2;
 	struct s3c24x0_timers *timers = s3c24x0_get_base_timers();
 	ulong tmr;
 
-	/* use PWM Timer 4 because it has no output */
-	/* prescaler for Timer 4 is 16 */
-	writel(0x0f00, &timers->tcfg0);
-	if (timer_load_val == 0) {
-		/*
-		 * for 10 ms clock period @ PCLK with 4 bit divider = 1/2
-		 * (default) and prescaler = 16. Should be 10390
-		 * @33.25MHz and 15625 @ 50 MHz
-		 */
-		timer_load_val = get_PCLK() / (2 * 16 * 100);
-		timer_clk = get_PCLK() / (2 * 16);
-	}
-	/* load value for 10 ms timeout */
-	lastdec = timer_load_val;
-	writel(timer_load_val, &timers->tcntb4);
-	/* auto load, manual update of timer 4 */
-	tmr = (readl(&timers->tcon) & ~0x0700000) | 0x0600000;
-	writel(tmr, &timers->tcon);
-	/* auto load, start timer 4 */
-	tmr = (tmr & ~0x0700000) | 0x0500000;
-	writel(tmr, &timers->tcon);
-	timestamp = 0;
-
-	return (0);
-}
-
-/*
- * timer without interrupts
- */
-ulong get_timer(ulong base)
-{
-	return get_timer_masked() - base;
-}
-
-void __udelay (unsigned long usec)
-{
-	ulong tmo;
-	ulong start = get_ticks();
+	/* Set prescaler for Timer 4 */
+	writel(TCFG0_PRESCALER1(prescaler-1), &timers->tcfg0);
 
-	tmo = usec / 1000;
-	tmo *= (timer_load_val * 100);
-	tmo /= 1000;
+	/* Calculate timer freq, approx 100kHz @ PCLK=50MHz. */
+	timer_rate_hz = get_PCLK() / (divider * prescaler);
 
-	while ((ulong) (get_ticks() - start) < tmo)
-		/*NOP*/;
-}
-
-ulong get_timer_masked(void)
-{
-	ulong tmr = get_ticks();
+	/* Set timer for 0.5s timeout (50000 ticks @ 10us ticks). */
+	timer_reset_value = 50000;
+	writel(timer_reset_value, &timers->tcntb4);
+	lastdec = timer_reset_value;
 
-	return tmr / (timer_clk / CONFIG_SYS_HZ);
-}
+	/* Load the initial timer 4 count value using the manual update bit. */
+	tmr = readl(&timers->tcon);
+	tmr &= ~TCON_TMR4_MASK;
+	tmr |= (TCON_TMR4_AUTO_RELOAD | TCON_TMR4_MAN_UPDATE);
+	writel(tmr, &timers->tcon);
 
-void udelay_masked(unsigned long usec)
-{
-	ulong tmo;
-	ulong endtime;
-	signed long diff;
-
-	if (usec >= 1000) {
-		tmo = usec / 1000;
-		tmo *= (timer_load_val * 100);
-		tmo /= 1000;
-	} else {
-		tmo = usec * (timer_load_val * 100);
-		tmo /= (1000 * 1000);
-	}
+	/* Configure timer 4 for auto reload and start it. */
+	tmr &= ~TCON_TMR4_MASK;
+	tmr |= (TCON_TMR4_AUTO_RELOAD | TCON_TMR4_START);
+	writel(tmr, &timers->tcon);
 
-	endtime = get_ticks() + tmo;
+	timestamp = 0;
 
-	do {
-		ulong now = get_ticks();
-		diff = endtime - now;
-	} while (diff >= 0);
+	return 0;
 }
 
 /*
- * This function is derived from PowerPC code (read timebase as long long).
- * On ARM it just returns the timer value.
+ * Get the number of ticks (in CONFIG_SYS_HZ resolution)
  */
 unsigned long long get_ticks(void)
 {
-	ulong now = READ_TIMER();
+	return get_timer(0);
+}
+
+unsigned long get_timer_raw(void)
+{
+	ulong now = read_timer();
 
 	if (lastdec >= now) {
 		/* normal mode */
 		timestamp += lastdec - now;
 	} else {
 		/* we have an overflow ... */
-		timestamp += lastdec + timer_load_val - now;
+		timestamp += lastdec + timer_reset_value - now;
 	}
 	lastdec = now;
 
@@ -157,20 +134,33 @@ unsigned long long get_ticks(void)
  */
 ulong get_tbclk(void)
 {
-	ulong tbclk;
-
-#if defined(CONFIG_SMDK2400)
-	tbclk = timer_load_val * 100;
-#elif defined(CONFIG_SBC2410X) || \
-      defined(CONFIG_SMDK2410) || \
-	defined(CONFIG_S3C2440) || \
-      defined(CONFIG_VCMA9)
-	tbclk = CONFIG_SYS_HZ;
-#else
-#	error "tbclk not configured"
-#endif
-
-	return tbclk;
+	return CONFIG_SYS_HZ;
+}
+
+ulong get_timer_masked(void)
+{
+	unsigned long tmr = get_timer_raw();
+
+	return (tmr * CONFIG_SYS_HZ) / timer_rate_hz;
+}
+
+ulong get_timer(ulong base)
+{
+	return get_timer_masked() - base;
+}
+
+void __udelay(unsigned long usec)
+{
+	unsigned long tmp;
+	unsigned long tmo;
+
+	/* convert usec to ticks. */
+	tmo = ((timer_rate_hz / 1000) * usec) / 1000;
+
+	tmp = get_timer_raw() + tmo;	/* get current timestamp */
+
+	while (get_timer_raw() < tmp)   /* loop till event */
+		/*NOP*/;
 }
 
 /*
@@ -189,7 +179,7 @@ void reset_cpu(ulong ignored)
 	writel(0x0001, &watchdog->wtcnt);
 
 	/* Enable watchdog timer; assert reset at timer timeout */
-	writel(0x0021, &watchdog->wtcon);
+	writel(WTCON_TIMER_EN | WTCON_RESET_EN, &watchdog->wtcon);
 
 	while (1)
 		/* loop forever and wait for reset to happen */;
-- 
1.7.1



More information about the U-Boot mailing list