From patchwork Tue Nov 29 13:45:17 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Kochetkov X-Patchwork-Id: 9452189 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 EAEEF6071C for ; Tue, 29 Nov 2016 14:22:01 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id DD9812830A for ; Tue, 29 Nov 2016 14:22:01 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id D1E2E28339; Tue, 29 Nov 2016 14:22:01 +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 58A082830A for ; Tue, 29 Nov 2016 14:22:01 +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 1cBjFw-0008BM-Ba; Tue, 29 Nov 2016 14:19:36 +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 1cBjFu-00089g-4T; Tue, 29 Nov 2016 14:19:34 +0000 Received: from mail-lf0-x244.google.com ([2a00:1450:4010:c07::244]) by merlin.infradead.org with esmtps (Exim 4.85_2 #1 (Red Hat Linux)) id 1cBijP-0002Lr-SK; Tue, 29 Nov 2016 13:46:00 +0000 Received: by mail-lf0-x244.google.com with SMTP id p100so12711987lfg.2; Tue, 29 Nov 2016 05:45:39 -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=EnG2h0Z6EyT971kSaqeiSPdaYsTDLATU7lSyKLEnoaw=; b=TlLs90J2Z2pOSohkWq0upLraNo+Hnw2q+2dnATh6tX1r7a5mcd196p8gtpFJtbuPwz dXO37/4QQIGVGqjkyRIu7Sg2RZ2VgZNjskMNyo9EnJhJkpeZ9ohpFd6HApV+VllWF+SA oBbIs5fjEmwgyVooHzeqcxaTvBVOGCcjrPuIlnRrzx8hTQQ47M3/X7ymFs7AeBzXa8B+ n5M8XiHVxNlwbhCb8htTyRjLLCjnqeppKHlWDcXjoYfMk44AKgrCwpOQ3JcpN99zn6i8 mlTBV+Qx5MVhr2pHwOU8K9Wi69nU3d4graPpqtc9R0A8t0Zzt5WlAvrWKDg3u0CXnkib Q/CA== 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=EnG2h0Z6EyT971kSaqeiSPdaYsTDLATU7lSyKLEnoaw=; b=Pb+UGkxHZoUwm9D7o6/CCA56AtIQpGPhpYlv74WKPhfD3u2CGmsAtjvnfsuGfOaRSs YihFimAXnuwg6aCRiDGs77mRrOQ4dYA8NsPeNiSJBHqovdHjMm7jpV80kDzvIRZVj33x bXerTg1a390JuYyOqFiRk3CmIVQKEhS+QIv6e3RO10kaP3OkFQchlkv2mAD2c9Eu1fPw fMF5rOmYPcRKEPUWQjNX6+FRdKOwpK1XdM61GzS1HnCbK3irLHGoV1IdWgJ32XKasK1R 9j+ffTb23x7hxbyX6lm3OCDyQjtZFeQcG+i3TnPQqEuwGZLwe2wTqeQs86gCnZxMaeWt GumA== X-Gm-Message-State: AKaTC03nFmdUVonGfyJQpbQuhx+Fb+79Vp1jO3i1HCqTUSyzCyNVG1QDXEzUzwzCu2Zo4w== X-Received: by 10.46.0.218 with SMTP id e87mr12166051lji.54.1480427137438; Tue, 29 Nov 2016 05:45:37 -0800 (PST) Received: from ubuntu.lintech.local ([185.35.119.87]) by smtp.gmail.com with ESMTPSA id y3sm250543lfj.42.2016.11.29.05.45.36 (version=TLS1_1 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 29 Nov 2016 05:45:36 -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: [PATCH v3 12/13] clocksource/drivers/rockchip_timer: implement clocksource timer Date: Tue, 29 Nov 2016 16:45:17 +0300 Message-Id: <1480427118-5126-13-git-send-email-al.kochet@gmail.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1480427118-5126-1-git-send-email-al.kochet@gmail.com> References: <1480343486-25539-1-git-send-email-al.kochet@gmail.com> <1480427118-5126-1-git-send-email-al.kochet@gmail.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20161129_084600_088530_524F0F5D X-CRM114-Status: GOOD ( 18.98 ) 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..1af80a0 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 = 250; + } 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;