Patchwork [U-Boot] Update s3c24x0 timer implementation

login
register
mail settings
Submitter Mark Norman
Date Oct. 31, 2011, 10:58 a.m.
Message ID <1320058730-25584-1-git-send-email-mpnorman@gmail.com>
Download mbox | patch
Permalink /patch/122783/
State Not Applicable
Delegated to: Minkyu Kang
Headers show

Comments

Mark Norman - Oct. 31, 2011, 10:58 a.m.
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@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(-)

Patch

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 */;