From patchwork Mon Oct 24 11:27:04 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Mark Norman X-Patchwork-Id: 121328 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id AD9EE1007D1 for ; Mon, 24 Oct 2011 22:27:13 +1100 (EST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 435C0284E6; Mon, 24 Oct 2011 13:27:11 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 9u9MM+Tfiei8; Mon, 24 Oct 2011 13:27:11 +0200 (CEST) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 293B928552; Mon, 24 Oct 2011 13:27:10 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 22A6D28552 for ; Mon, 24 Oct 2011 13:27:07 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id dIV-SypxXwx7 for ; Mon, 24 Oct 2011 13:27:06 +0200 (CEST) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from mail-ww0-f52.google.com (mail-ww0-f52.google.com [74.125.82.52]) by theia.denx.de (Postfix) with ESMTPS id 12844284E6 for ; Mon, 24 Oct 2011 13:27:04 +0200 (CEST) Received: by wwf25 with SMTP id 25so10207792wwf.9 for ; Mon, 24 Oct 2011 04:27:04 -0700 (PDT) MIME-Version: 1.0 Received: by 10.216.9.146 with SMTP id 18mr3190962wet.54.1319455624172; Mon, 24 Oct 2011 04:27:04 -0700 (PDT) Received: by 10.216.50.135 with HTTP; Mon, 24 Oct 2011 04:27:04 -0700 (PDT) In-Reply-To: <20111023172248.4AB611408771@gemini.denx.de> References: <20111023172248.4AB611408771@gemini.denx.de> Date: Mon, 24 Oct 2011 21:57:04 +1030 Message-ID: From: Mark Norman To: Wolfgang Denk Cc: u-boot@lists.denx.de Subject: Re: [U-Boot] [PATCH] Update s3c24x0 timer implementation X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.9 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: u-boot-bounces@lists.denx.de Errors-To: u-boot-bounces@lists.denx.de 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. 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 --- 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 #include -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); + + /* Calculate timer freq, approx 100kHz @ PCLK=50MHz. */ + gd->timer_rate_hz = get_PCLK() / (2 * prescaler); + + /* 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; 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); } /* - * 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 unsigned long relocaddr; /* Start address of U-Boot in RAM */ phys_size_t ram_size; /* RAM size */ unsigned long mon_len; /* monitor len */