From: Mark Norman <mpnorman@gmail.com>
To: u-boot@lists.denx.de
Subject: [U-Boot] [PATCH] Update s3c24x0 timer implementation
Date: Mon, 31 Oct 2011 21:28:50 +1030 [thread overview]
Message-ID: <1320058730-25584-1-git-send-email-mpnorman@gmail.com> (raw)
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(-)
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
next reply other threads:[~2011-10-31 10:58 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-10-31 10:58 Mark Norman [this message]
-- strict thread matches above, loose matches on Subject: below --
2011-10-23 11:52 [U-Boot] [PATCH] Update s3c24x0 timer implementation Mark Norman
2011-10-23 17:22 ` Wolfgang Denk
2011-10-24 11:27 ` Mark Norman
2011-10-24 13:58 ` Marek Vasut
2011-10-31 11:27 ` Mark Norman
2011-10-24 19:34 ` Wolfgang Denk
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=1320058730-25584-1-git-send-email-mpnorman@gmail.com \
--to=mpnorman@gmail.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox