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 <mpnor...@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 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot