From patchwork Sat Jul 28 09:35:38 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: seedshope X-Patchwork-Id: 173850 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 94BF32C0098 for ; Sat, 28 Jul 2012 19:39:17 +1000 (EST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 3FE662809D; Sat, 28 Jul 2012 11:39:04 +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 NLtrkF2FzvVM; Sat, 28 Jul 2012 11:39:04 +0200 (CEST) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id C5B5E28089; Sat, 28 Jul 2012 11:38:52 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 22A6F2808A for ; Sat, 28 Jul 2012 11:38:50 +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 brZh3w5rwVEa for ; Sat, 28 Jul 2012 11:38:49 +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-pb0-f44.google.com (mail-pb0-f44.google.com [209.85.160.44]) by theia.denx.de (Postfix) with ESMTPS id 100BF2808B for ; Sat, 28 Jul 2012 11:38:40 +0200 (CEST) Received: by mail-pb0-f44.google.com with SMTP id wy7so6498823pbc.3 for ; Sat, 28 Jul 2012 02:38:40 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references; bh=p4e0nZA5hHQv2EvNL9ohOJYZwcyYDhSGV1Pvic/h3+s=; b=BpVBWTZgpIoYKUY2bmQ91WFccd83GgGbmdbwIf9sXvMUaZLB4LLXihqFG/HuTqXdke 6s0oONw9hOWG6AWJ8xtG2lmPpeqrQQIUKVv46xPqb0J9ULh/ymTnbkYC5eq5dZdFwPlA o9b4yKcEdSHUS1t2oveqyJ3xDgtJc99cPQhMujOL7PXAPo+J+59OK1rvuu/SgkLrnvDD QOgd9tHSI0XS5ZCih5knmLCZq8ULybkxsQnPO2h/eFk9DJXRxMPLvugucfK6jcOm/9fb JERVr8XqCRhqSf5v2e1E33bbHJiF3q7/TcjbRdA2h5gjbp2AKkuPIUT1Ut/9kV3CvZTs 1Uvg== Received: by 10.68.130.9 with SMTP id oa9mr20095051pbb.95.1343468320059; Sat, 28 Jul 2012 02:38:40 -0700 (PDT) Received: from localhost.localdomain ([221.221.21.198]) by mx.google.com with ESMTPS id hf4sm3687803pbc.4.2012.07.28.02.38.35 (version=TLSv1/SSLv3 cipher=OTHER); Sat, 28 Jul 2012 02:38:39 -0700 (PDT) From: Zhong Hongbo To: Minkyu Kang Date: Sat, 28 Jul 2012 17:35:38 +0800 Message-Id: <1343468148-26595-6-git-send-email-bocui107@gmail.com> X-Mailer: git-send-email 1.7.5.4 In-Reply-To: <1343468148-26595-1-git-send-email-bocui107@gmail.com> References: <1343468148-26595-1-git-send-email-bocui107@gmail.com> Cc: u-boot@lists.denx.de, Zhong Hongbo Subject: [U-Boot] [V3 05/15] S3C64XX: reference s5p cpu time system for s3c64xx timer X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.11 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: u-boot-bounces@lists.denx.de Errors-To: u-boot-bounces@lists.denx.de From: Zhong Hongbo The old s3c64xx timer is not work normal, Adopt s5p time design, It work perfect. Signed-off-by: Zhong Hongbo --- Change for V3: - None. Change for V2: - Delete const key word for the variable of struct s3c_timer --- arch/arm/cpu/arm1176/s3c64xx/timer.c | 193 ++++++++++++++++------------------ 1 files changed, 93 insertions(+), 100 deletions(-) diff --git a/arch/arm/cpu/arm1176/s3c64xx/timer.c b/arch/arm/cpu/arm1176/s3c64xx/timer.c index f16a37b..47d7731 100644 --- a/arch/arm/cpu/arm1176/s3c64xx/timer.c +++ b/arch/arm/cpu/arm1176/s3c64xx/timer.c @@ -1,23 +1,8 @@ /* - * (C) Copyright 2003 - * Texas Instruments + * Copyright (C) 2012 + * Zhong Hongbo * - * (C) Copyright 2002 - * Sysgo Real-Time Solutions, GmbH - * Marius Groeger - * - * (C) Copyright 2002 - * Sysgo Real-Time Solutions, GmbH - * Alex Zuepke - * - * (C) Copyright 2002-2004 - * Gary Jennejohn, DENX Software Engineering, - * - * (C) Copyright 2004 - * Philippe Robin, ARM Ltd. - * - * (C) Copyright 2008 - * Guennadi Liakhovetki, DENX Software Engineering, + * based on arch/arm/cpu/armv7/s5p-common/timer.c * * See file CREDITS for list of people who contributed to this * project. @@ -39,64 +24,29 @@ */ #include -#include +#include #include -#include - -static ulong timer_load_val; +#include +#include -#define PRESCALER 167 +DECLARE_GLOBAL_DATA_PTR; -static s3c64xx_timers *s3c64xx_get_base_timers(void) -{ - return (s3c64xx_timers *)ELFIN_TIMER_BASE; -} +static unsigned long get_current_tick(void); /* macro to read the 16 bit timer */ -static inline ulong read_timer(void) +static inline struct s3c_timer *s3c_get_base_timer(void) { - s3c64xx_timers *const timers = s3c64xx_get_base_timers(); - - return timers->TCNTO4; + return (struct s3c_timer *)s3c64xx_get_base_timer(); } -/* Internal tick units */ -/* Last decremneter snapshot */ -static unsigned long lastdec; -/* Monotonic incrementing timer */ -static unsigned long long timestamp; - int timer_init(void) { - s3c64xx_timers *const timers = s3c64xx_get_base_timers(); - - /* use PWM Timer 4 because it has no output */ - /* - * We use the following scheme for the timer: - * Prescaler is hard fixed at 167, divider at 1/4. - * This gives at PCLK frequency 66MHz approx. 10us ticks - * The timer is set to wrap after 100s, at 66MHz this obviously - * happens after 10,000,000 ticks. A long variable can thus - * keep values up to 40,000s, i.e., 11 hours. This should be - * enough for most uses:-) Possible optimizations: select a - * binary-friendly frequency, e.g., 1ms / 128. Also calculate - * the prescaler automatically for other PCLK frequencies. - */ - timers->TCFG0 = PRESCALER << 8; - if (timer_load_val == 0) { - timer_load_val = get_PCLK() / PRESCALER * (100 / 4); /* 100s */ - timers->TCFG1 = (timers->TCFG1 & ~0xf0000) | 0x20000; - } - - /* load value for 10 ms timeout */ - lastdec = timers->TCNTB4 = timer_load_val; - /* auto load, manual update of Timer 4 */ - timers->TCON = (timers->TCON & ~0x00700000) | TCON_4_AUTO | - TCON_4_UPDATE; + /* PWM Timer 4 */ + pwm_init(4, MUX_DIV_2, 0); + pwm_config(4, 0, 0); + pwm_enable(4); - /* auto load, start Timer 4 */ - timers->TCON = (timers->TCON & ~0x00700000) | TCON_4_AUTO | COUNT_4_ON; - timestamp = 0; + reset_timer_masked(); return 0; } @@ -104,57 +54,100 @@ int timer_init(void) /* * timer without interrupts */ - -/* - * 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) +unsigned long get_timer(unsigned long base) { - ulong now = read_timer(); + return get_timer_masked() - base; +} - if (lastdec >= now) { - /* normal mode */ - timestamp += lastdec - now; +/* delay x useconds */ +void __udelay(unsigned long usec) +{ + struct s3c_timer *timer = s3c_get_base_timer(); + unsigned long tmo, tmp, count_value; + + count_value = readl(&timer->tcntb4); + + if (usec >= 1000) { + /* + * if "big" number, spread normalization + * to seconds + * 1. start to normalize for usec to ticks per sec + * 2. find number of "ticks" to wait to achieve target + * 3. finish normalize. + */ + tmo = usec / 1000; + tmo *= (CONFIG_SYS_HZ * count_value); + tmo /= 1000; } else { - /* we have an overflow ... */ - timestamp += lastdec + timer_load_val - now; + /* else small number, don't kill it prior to HZ multiply */ + tmo = usec * CONFIG_SYS_HZ * count_value; + tmo /= (1000 * 1000); } - lastdec = now; - return timestamp; + /* get current timestamp */ + tmp = get_current_tick(); + + /* if setting this fordward will roll time stamp */ + /* reset "advancing" timestamp to 0, set lastinc value */ + /* else, set advancing stamp wake up time */ + if ((tmo + tmp + 1) < tmp) + reset_timer_masked(); + else + tmo += tmp; + + /* loop till event */ + while (get_current_tick() < tmo) + + ; /* nop */ } -/* - * 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) +void reset_timer_masked(void) { - /* We overrun in 100s */ - return (ulong)(timer_load_val / 100); + struct s3c_timer *timer = s3c_get_base_timer(); + + /* reset time */ + gd->lastinc = readl(&timer->tcnto4); + gd->tbl = 0; } -ulong get_timer_masked(void) +unsigned long get_timer_masked(void) { - unsigned long long res = get_ticks(); - do_div (res, (timer_load_val / (100 * CONFIG_SYS_HZ))); - return res; + struct s3c_timer *timer = s3c_get_base_timer(); + unsigned long count_value = readl(&timer->tcntb4); + + return get_current_tick() / count_value; } -ulong get_timer(ulong base) +static unsigned long get_current_tick(void) { - return get_timer_masked() - base; + struct s3c_timer *timer = s3c_get_base_timer(); + unsigned long now = readl(&timer->tcnto4); + unsigned long count_value = readl(&timer->tcntb4); + + if (gd->lastinc >= now) + gd->tbl += gd->lastinc - now; + else + gd->tbl += gd->lastinc + count_value - now; + + gd->lastinc = now; + + return gd->tbl; } -void __udelay(unsigned long usec) +/* + * 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) { - unsigned long long tmp; - ulong tmo; - - tmo = (usec + 9) / 10; - tmp = get_ticks() + tmo; /* get current timestamp */ + return get_timer(0); +} - while (get_ticks() < tmp)/* loop till event */ - /*NOP*/; +/* + * This function is derived from PowerPC code (timebase clock frequency). + * On ARM it returns the number of timer ticks per second. + */ +unsigned long get_tbclk(void) +{ + return CONFIG_SYS_HZ; }