[U-Boot] [PATCH] Update s3c24x0 timer implementation
Marek Vasut
marek.vasut at gmail.com
Mon Oct 24 15:58:36 CEST 2011
> Dear Wolfgang Denk,
>
> Thank you for your response.
>
> >> Since the .rel.text section is required by the relocation code, I
> >> assume that .bss global variables cannot be used until after
> >> relocation?
> >
> > Why do you have to make such assumptions? That's documented
> > behaviour. Didn't you RTFM?
>
> I thought I had done a thorough search previously but after receiving
> your response I managed to find some of the details outlined in the
> README file.
>
> I have attached an updated patch below which hopefully addresses the
> other issues you highlighted.
Hehe, you should RTFM ;-) http://www.denx.de/wiki/U-Boot/Patches
Generally, use git send-email to send the patch.
>
> Kind Regards,
>
> Mark Norman
>
>
>
> The s3c24x0 timer has been updated to use the global_data struct.
> Restructured code based on other timer.c files.
> Updated comments and several parameters.
>
> Signed-off-by: Mark Norman <mpnorman at gmail.com>
> ---
> arch/arm/cpu/arm920t/s3c24x0/timer.c | 155
> +++++++++++++-------------------- arch/arm/include/asm/global_data.h |
> 4 +
> 2 files changed, 65 insertions(+), 94 deletions(-)
>
> diff --git a/arch/arm/cpu/arm920t/s3c24x0/timer.c
> b/arch/arm/cpu/arm920t/s3c24x0/timer.c
> index 9571870..5695c62 100644
> --- a/arch/arm/cpu/arm920t/s3c24x0/timer.c
> +++ b/arch/arm/cpu/arm920t/s3c24x0/timer.c
> @@ -35,142 +35,109 @@
> #include <asm/io.h>
> #include <asm/arch/s3c24x0_cpu.h>
>
> -int timer_load_val = 0;
> -static ulong timer_clk;
> +DECLARE_GLOBAL_DATA_PTR;
>
> -/* macro to read the 16 bit timer */
> -static inline ulong READ_TIMER(void)
> +/* 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;
> 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 */
> + /* Set prescaler for Timer 4 */
> + writel((prescaler-1) << 8, &timers->tcfg0);
Can we get rid of the magic numbers please?
> +
> + /* Calculate timer freq, approx 100kHz @ PCLK=50MHz. */
> + gd->timer_rate_hz = get_PCLK() / (2 * prescaler);
Can get_PCLK() be renamed to be lower-case only?
> +
> + /* Set timer for 0.5s timeout (50000 ticks @ 10us ticks). */
> + gd->timer_reset_value = 50000;
> + writel(gd->timer_reset_value, &timers->tcntb4);
> + gd->lastdec = gd->timer_reset_value;
> +
> + /* Load the initial timer 4 count value using the manual update bit. */
> tmr = (readl(&timers->tcon) & ~0x0700000) | 0x0600000;
Magic values :-(
> writel(tmr, &timers->tcon);
> - /* auto load, start timer 4 */
> +
> + /* Configure timer 4 for auto reload and start it. */
> tmr = (tmr & ~0x0700000) | 0x0500000;
> writel(tmr, &timers->tcon);
> - timestamp = 0;
> +
> + gd->timestamp = 0;
>
> return (0);
return 0;
if you're cleaning this crap up, do it all at once ;-)
> }
>
> /*
> - * timer without interrupts
> + * Get the number of ticks (in CONFIG_SYS_HZ resolution)
> */
> -ulong get_timer(ulong base)
> +unsigned long long get_ticks(void)
> {
> - return get_timer_masked() - base;
> + return get_timer(0);
> }
>
> -void __udelay (unsigned long usec)
> +unsigned long get_timer_raw(void)
> {
> - ulong tmo;
> - ulong start = get_ticks();
> + ulong now = read_timer();
>
> - tmo = usec / 1000;
> - tmo *= (timer_load_val * 100);
> - tmo /= 1000;
> + if (gd->lastdec >= now) {
> + /* normal mode */
> + gd->timestamp += gd->lastdec - now;
> + } else {
> + /* we have an overflow ... */
> + gd->timestamp += gd->lastdec + gd->timer_reset_value - now;
> + }
> + gd->lastdec = now;
>
> - while ((ulong) (get_ticks() - start) < tmo)
> - /*NOP*/;
> + return gd->timestamp;
> }
>
> -ulong get_timer_masked(void)
> +/*
> + * 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 tmr = get_ticks();
> -
> - return tmr / (timer_clk / CONFIG_SYS_HZ);
> + return CONFIG_SYS_HZ;
> }
>
> -void udelay_masked(unsigned long usec)
> +ulong get_timer_masked(void)
> {
> - 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);
> - }
> + unsigned long tmr = get_timer_raw();
>
> - endtime = get_ticks() + tmo;
> + return (tmr * CONFIG_SYS_HZ) / gd->timer_rate_hz;
> +}
>
> - do {
> - ulong now = get_ticks();
> - diff = endtime - now;
> - } while (diff >= 0);
> +ulong get_timer(ulong base)
> +{
> + return get_timer_masked() - base;
> }
>
> -/*
> - * 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)
> +void __udelay(unsigned long usec)
> {
> - ulong now = READ_TIMER();
> + unsigned long tmp;
> + unsigned long tmo;
>
> - if (lastdec >= now) {
> - /* normal mode */
> - timestamp += lastdec - now;
> - } else {
> - /* we have an overflow ... */
> - timestamp += lastdec + timer_load_val - now;
> - }
> - lastdec = now;
> + /* convert usec to ticks. */
> + tmo = ((gd->timer_rate_hz / 1000) * usec) / 1000;
>
> - return timestamp;
> -}
> + tmp = get_timer_raw() + tmo; /* get current timestamp */
>
> -/*
> - * 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;
> -
> -#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;
> + while (get_timer_raw() < tmp) /* loop till event */
> + /*NOP*/;
> }
>
> /*
> diff --git a/arch/arm/include/asm/global_data.h
> b/arch/arm/include/asm/global_data.h
> index fac98d5..b836915 100644
> --- a/arch/arm/include/asm/global_data.h
> +++ b/arch/arm/include/asm/global_data.h
> @@ -67,6 +67,10 @@ typedef struct global_data {
> #ifdef CONFIG_IXP425
> unsigned long timestamp;
> #endif
> +#ifdef CONFIG_S3C24X0
> + unsigned long lastdec;
> + unsigned long timestamp;
> +#endif
I wonder about this change ...
> unsigned long relocaddr; /* Start address of U-Boot in RAM */
> phys_size_t ram_size; /* RAM size */
> unsigned long mon_len; /* monitor len */
Cheers
More information about the U-Boot
mailing list