From patchwork Mon Nov 28 14:31:26 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Kochetkov X-Patchwork-Id: 9449659 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 6EBF3600CB for ; Mon, 28 Nov 2016 14:37:38 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 6554425D99 for ; Mon, 28 Nov 2016 14:37:38 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 5A1A227C0C; Mon, 28 Nov 2016 14:37:38 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.1 required=2.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED,FREEMAIL_FROM,RCVD_IN_DNSWL_MED,T_DKIM_INVALID autolearn=unavailable version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 807CF25D99 for ; Mon, 28 Nov 2016 14:37:36 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.85_2 #1 (Red Hat Linux)) id 1cBN2G-0002nC-JO; Mon, 28 Nov 2016 14:36:00 +0000 Received: from merlin.infradead.org ([2001:4978:20e::2]) by bombadil.infradead.org with esmtps (Exim 4.85_2 #1 (Red Hat Linux)) id 1cBMyX-0007lw-JL; Mon, 28 Nov 2016 14:32:09 +0000 Received: from mail-lf0-x243.google.com ([2a00:1450:4010:c07::243]) by merlin.infradead.org with esmtps (Exim 4.85_2 #1 (Red Hat Linux)) id 1cBMyV-0003ZQ-Rg; Mon, 28 Nov 2016 14:32:08 +0000 Received: by mail-lf0-x243.google.com with SMTP id o20so9656118lfg.3; Mon, 28 Nov 2016 06:31:46 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=a1y9fxoiaSZxj97kJKRn97i/z7edz63GvVDBXyETfEo=; b=PMwlBr1wrnjUQvnQCi9fN9sZLCX4WVDddeD8Jym4kTBURLxs7Yu/rvcgmwaPff2VqK w9Z1w0hTwPdjijFxfLX6MITiESfOLEMi/qOtRK34mMGRxUM9uHsBD+j7mmg5FwKiHmEV ukG5GitUusYe8yjfDRFMbK5mRDI2Wo4MCfhKpWqhUrm6U0jlCuHZ/6gJ56R6otNSjGKW 4tNUYjC1TmWVpfvHN8jp/I0JMmq4S/PidSGDhdowtBG/mt4CYVa0aqs0lsy9EAFzCOFP 8VA9oxJX/H2zldyZKwiN2wOjxY+zm6nGgdYKwvAuIRCpcnaV7TF5ZM4zR7KJXbCVpJPM JeCw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=a1y9fxoiaSZxj97kJKRn97i/z7edz63GvVDBXyETfEo=; b=meUj0dRVYc//zab9KNuADlfX78SyJaESgwqF9JqoNtzVSOBtL3Ou5/Yn8bu0rkLVxn +Q1tG2pFCFONiuEDPcr0crFd+CgYn71Qs9qqUAHyj0pShfDL10gFRI9frKEJJcTPiT/v /kE17cn7SesMM4o/Q9X4+GmrZpUdal38aPMVsUQ1wGfeS93RyB+Nru5Rd3kD8spZMSiN D6hMRy46qDa6n5DI/LIQFoXgPxlySgy3FPFbgIQfjJWvfKM+2tJrekl3BL3I8/FSncIt sqknRxi/loz4cSoDKrMNzfbeQR5gjXOYLrnNJObgf7e/QIb725JMa58P5vv9BRuNowdz E29g== X-Gm-Message-State: AKaTC01jgQ9qg0oInqFxXce6XwNsbtTVuByaODj35y8umXx9C4f1Zbk1KhOwDHrJcyVruA== X-Received: by 10.46.8.25 with SMTP id 25mr10870206lji.21.1480343504101; Mon, 28 Nov 2016 06:31:44 -0800 (PST) Received: from ubuntu.lintech.local ([185.35.119.87]) by smtp.gmail.com with ESMTPSA id h30sm12816162lji.28.2016.11.28.06.31.42 (version=TLS1_1 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 28 Nov 2016 06:31:43 -0800 (PST) From: Alexander Kochetkov To: linux-kernel@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-rockchip@lists.infradead.org Subject: [PATCHv2 11/11] clocksource/drivers/rockchip_timer: implement clocksource timer Date: Mon, 28 Nov 2016 17:31:26 +0300 Message-Id: <1480343486-25539-12-git-send-email-al.kochet@gmail.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1480343486-25539-1-git-send-email-al.kochet@gmail.com> References: <1480343486-25539-1-git-send-email-al.kochet@gmail.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20161128_093208_056889_E6A0CFEC X-CRM114-Status: GOOD ( 18.76 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Mark Rutland , Huang Tao , Heiko Stuebner , Alexander Kochetkov , Daniel Lezcano , Russell King , Rob Herring , Thomas Gleixner , Caesar Wang MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP The clock supplying the arm-global-timer on the rk3188 is coming from the the cpu clock itself and thus changes its rate everytime cpufreq adjusts the cpu frequency making this timer unsuitable as a stable clocksource. The rk3188, rk3288 and following socs share a separate timer block already handled by the rockchip-timer driver. Therefore adapt this driver to also be able to act as clocksource on rk3188. In order to test clocksource you can run following commands and check how much time it take in real. On rk3188 it take about ~45 seconds. Such error cannot be fixed using NTP. Haven't test clocksource on rk3288 and onwards. Guess they can also have unstable clocksource. cpufreq-set -f 1.6GHZ date; sleep 60; date In order to use the patch you need to declare two timers in the dts file. The first timer will be initialized as clockevent provider and the second one as clocksource. The clockevent must be from alive subsystem as it used as backup for the local timers at sleep time. In order to resolve ambiguity between timers in the device tree, it is possible to correctly number the timers using "aliases" node. The patch does not break compatibility with older device tree files. The older device tree files contain only one timer. The timer will be initialized as clockevent, as expected. Signed-off-by: Alexander Kochetkov --- drivers/clocksource/rockchip_timer.c | 101 ++++++++++++++++++++++++++++------ 1 file changed, 85 insertions(+), 16 deletions(-) diff --git a/drivers/clocksource/rockchip_timer.c b/drivers/clocksource/rockchip_timer.c index 6224aa9..430b182 100644 --- a/drivers/clocksource/rockchip_timer.c +++ b/drivers/clocksource/rockchip_timer.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -42,7 +43,19 @@ struct rk_clock_event_device { struct rk_timer timer; }; +struct rk_clocksource { + struct clocksource cs; + struct rk_timer timer; +}; + +enum { + ROCKCHIP_CLKSRC_CLOCKEVENT = 0, + ROCKCHIP_CLKSRC_CLOCKSOURCE = 1, +}; + static struct rk_clock_event_device bc_timer; +static struct rk_clocksource cs_timer; +static int rk_next_clksrc = ROCKCHIP_CLKSRC_CLOCKEVENT; static inline struct rk_clock_event_device* rk_clock_event_device(struct clock_event_device *ce) @@ -143,13 +156,46 @@ static irqreturn_t rk_timer_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } +static cycle_t rk_timer_clocksource_read(struct clocksource *cs) +{ + struct rk_clocksource *_cs = + container_of(cs, struct rk_clocksource, cs); + + return ~rk_timer_counter_read(&_cs->timer); +} + +static u64 notrace rk_timer_sched_clock_read(void) +{ + struct rk_clocksource *_cs = &cs_timer; + + return ~rk_timer_counter_read(&_cs->timer); +} + static int __init rk_timer_init(struct device_node *np, u32 ctrl_reg) { - struct clock_event_device *ce = &bc_timer.ce; - struct rk_timer *timer = &bc_timer.timer; + struct clock_event_device *ce = NULL; + struct clocksource *cs = NULL; + struct rk_timer *timer = NULL; struct clk *timer_clk; struct clk *pclk; int ret = -EINVAL, irq; + int clksrc; + + clksrc = rk_next_clksrc; + rk_next_clksrc++; + + switch (clksrc) { + case ROCKCHIP_CLKSRC_CLOCKEVENT: + ce = &bc_timer.ce; + timer = &bc_timer.timer; + break; + case ROCKCHIP_CLKSRC_CLOCKSOURCE: + cs = &cs_timer.cs; + timer = &cs_timer.timer; + break; + default: + return -ENODEV; + } timer->base = of_iomap(np, 0); if (!timer->base) { @@ -193,26 +239,49 @@ static int __init rk_timer_init(struct device_node *np, u32 ctrl_reg) goto out_irq; } - ce->name = TIMER_NAME; - ce->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT | - CLOCK_EVT_FEAT_DYNIRQ; - ce->set_next_event = rk_timer_set_next_event; - ce->set_state_shutdown = rk_timer_shutdown; - ce->set_state_periodic = rk_timer_set_periodic; - ce->irq = irq; - ce->cpumask = cpu_possible_mask; - ce->rating = 250; + if (ce) { + ce->name = TIMER_NAME; + ce->features = CLOCK_EVT_FEAT_PERIODIC | + CLOCK_EVT_FEAT_ONESHOT | + CLOCK_EVT_FEAT_DYNIRQ; + ce->set_next_event = rk_timer_set_next_event; + ce->set_state_shutdown = rk_timer_shutdown; + ce->set_state_periodic = rk_timer_set_periodic; + ce->irq = irq; + ce->cpumask = cpu_possible_mask; + ce->rating = 250; + } + + if (cs) { + cs->name = TIMER_NAME; + cs->flags = CLOCK_SOURCE_IS_CONTINUOUS; + cs->mask = CLOCKSOURCE_MASK(64); + cs->read = rk_timer_clocksource_read; + cs->rating = 350; + } rk_timer_interrupt_clear(timer); rk_timer_disable(timer); - ret = request_irq(irq, rk_timer_interrupt, IRQF_TIMER, TIMER_NAME, ce); - if (ret) { - pr_err("Failed to initialize '%s': %d\n", TIMER_NAME, ret); - goto out_irq; + if (ce) { + ret = request_irq(irq, rk_timer_interrupt, IRQF_TIMER, + TIMER_NAME, ce); + if (ret) { + pr_err("Failed to initialize '%s': %d\n", + TIMER_NAME, ret); + goto out_irq; + } + + clockevents_config_and_register(ce, timer->freq, 1, UINT_MAX); } - clockevents_config_and_register(ce, timer->freq, 1, UINT_MAX); + if (cs) { + rk_timer_update_counter(U64_MAX, timer); + rk_timer_enable(timer, 0); + clocksource_register_hz(cs, timer->freq); + sched_clock_register(rk_timer_sched_clock_read, 64, + timer->freq); + } return 0;