From patchwork Fri Jul 13 16:11:43 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: seedshope X-Patchwork-Id: 170917 X-Patchwork-Delegate: promsoft@gmail.com 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 88C822C02E8 for ; Sat, 14 Jul 2012 02:13:21 +1000 (EST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id B06E128131; Fri, 13 Jul 2012 18:13:03 +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 tjTPTkVG4xMk; Fri, 13 Jul 2012 18:13:02 +0200 (CEST) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 4FA85280E8; Fri, 13 Jul 2012 18:12:48 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 42E30280A6 for ; Fri, 13 Jul 2012 18:12:45 +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 2AMtnmRN8BSp for ; Fri, 13 Jul 2012 18:12:44 +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 EA7B9280F4 for ; Fri, 13 Jul 2012 18:12:32 +0200 (CEST) Received: by mail-pb0-f44.google.com with SMTP id wy7so5538073pbc.3 for ; Fri, 13 Jul 2012 09:12:32 -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=E3Bj7gcwv6Rr0umaKR2kistq8/tNAmDpownFmkhyX1o=; b=nulr/Yc16E5o+6iUGUeBD9ooACBAyeBWiHmhyuyoVu3fJN3YSaAP+lvo3d5iuygRnt YoT6NdIOmwvmFFjcsS/ocSIQF0J+is81kDlwo9Efsi0Mua/iT/meR0uNv33vd/b9XS1g s26W7xIK2Sfn1HBCpG6GoqRqA/ZGhNsT039grNtxhzHNmOdhfxAfUYfh97ZCUzD6L9La z9F4/ONM/8fwVxAuNz41JfBjLdaqzNVbCTxQRf7KE/zlRl/HITyDY2TgPKnRfn9MByH0 wgc1y+I5xKVkAJmmwbeKoww06PIa+wdBX7Gn0V37TI0TUknLley/6U8hYzqa7OQz/YL4 Lc1w== Received: by 10.68.200.162 with SMTP id jt2mr4618352pbc.54.1342195952575; Fri, 13 Jul 2012 09:12:32 -0700 (PDT) Received: from localhost.localdomain ([221.221.22.146]) by mx.google.com with ESMTPS id he9sm6266691pbc.68.2012.07.13.09.12.28 (version=TLSv1/SSLv3 cipher=OTHER); Fri, 13 Jul 2012 09:12:31 -0700 (PDT) From: Zhong Hongbo To: u-boot@lists.denx.de Date: Sat, 14 Jul 2012 00:11:43 +0800 Message-Id: <1342195913-25161-6-git-send-email-bocui107@gmail.com> X-Mailer: git-send-email 1.7.5.4 In-Reply-To: <1342195913-25161-1-git-send-email-bocui107@gmail.com> References: <1342195913-25161-1-git-send-email-bocui107@gmail.com> Cc: Scott Wood Subject: [U-Boot] [V2 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 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; }