From patchwork Tue Jan 9 09:09:10 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "\(Exiting\) Baolin Wang" X-Patchwork-Id: 123817 Delivered-To: patch@linaro.org Received: by 10.140.22.227 with SMTP id 90csp3782123qgn; Tue, 9 Jan 2018 01:10:14 -0800 (PST) X-Google-Smtp-Source: ACJfBov0uT3u3cuxMeuham4q+37Muk2neKYDnejFYCWVQa0GDuY2NZ7Twy03R6MtXor8KPgNWVkn X-Received: by 10.84.232.197 with SMTP id x5mr6572384plm.80.1515489014478; Tue, 09 Jan 2018 01:10:14 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1515489014; cv=none; d=google.com; s=arc-20160816; b=eZHkKs9je25wnJT/XWHMMDlY/jyf7yye7TvYTYY3UgiOKmR/5IvCfRm0ZuEVc6owov o8neGlO7/eBy3hsHkAfBxkcYrbjfyKhgkb0eMAxFkRI6DoZ1HZpwK/19fUt5DJBwVHag kuBLVGFMFgflV0uGf/vqKxttHiJwsn1xK5SiX70fHhWnYr1nEC656QrW0qS4/CjFpN6a qezQ4iuqN/o4nOPORc+nxFSCWfCkrd9kxXqaOor51oZYfWNuNiwpsa5At7a10cMpCYDL /5CWoyj16dn9XZrpuKyD8WMTJL7jpp78GaSEMdxC/fqv9gGHBIo6/yPrWJ3V/VHcs0Hh UG6Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:message-id:date:subject:cc:to:from :dkim-signature:arc-authentication-results; bh=d5kCr/gQvwVHBhhjK6xGcTauOTz01Kzmx3XvtLsT5rQ=; b=Y1JtEZhVkXd7svF7StMKFAngN5+/HtbE9D2Z9Dus3VR+vsl3S8YPvooW2QHSnMYKBl B4Og3uG+MYH4aNtZsZmWQFgIcvFEjxCcxigVES/v6f5e/5vwWWfvYRq9twdCDjQjmLl/ mAaKFhwWV12cvthezZ5q0mwqDFINetEdo89o04Z2vwPT3wXYZR4QJ+Q2+PkRpj3KCTR7 5hpWaOmXAk2Wlir44Xf6NJYuk+6qePbGKqpwSWjmAKs/QKn5uHyfZRswNtlIE23DzI3e n3d7rQx7Rksza3cU+zrwBV49+uvJTxN2QqmLAogYqp+Ez9Va7raYy5oU0UmR6Th8WoZq eHbg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=fSS0gZtj; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id l81si9807982pfb.91.2018.01.09.01.10.14; Tue, 09 Jan 2018 01:10:14 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=fSS0gZtj; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751369AbeAIJJt (ORCPT + 28 others); Tue, 9 Jan 2018 04:09:49 -0500 Received: from mail-pg0-f66.google.com ([74.125.83.66]:43525 "EHLO mail-pg0-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750915AbeAIJJn (ORCPT ); Tue, 9 Jan 2018 04:09:43 -0500 Received: by mail-pg0-f66.google.com with SMTP id f14so5005213pga.10 for ; Tue, 09 Jan 2018 01:09:43 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id; bh=d5kCr/gQvwVHBhhjK6xGcTauOTz01Kzmx3XvtLsT5rQ=; b=fSS0gZtjdKyDUChMMXE3KI3/GprZLAAD8y+H9gYY5fYGBS0m1WAJdKf5l7NkIPRLPI iv3QKENdaR9BAeQ+SzGlvJUUWn1pil+MQeZRLUoOoD1As3d129eVAXo7dul/j7IcBukb PSUGyjsPNcVLjE9PJ0COKRf+E2nLPvKbMHF6I= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=d5kCr/gQvwVHBhhjK6xGcTauOTz01Kzmx3XvtLsT5rQ=; b=PY4Z78PlXAD/ZUVg+Ls1YAxdUAItpMVg6gMgznmYj4yKfnUe4ypXUb+Ath/6Hf8E7d KUjY0qBq4DYyo6acg6VvD99rPrZKgOAk/AUaUcUDJEkM5w2Ka7SsiFWQXpLMzc+9yNHl EZ7rpO0eo0fPxm8djO6pbiPCAksxCbSp9KXjpwpmlCqsmKoJONpPkTax7JJ2ZcvW55cS Kd0ZN0DP6Oih+1ersokSQD3ywoprTTPKS9iXIaA84ReffAYObQ2pGudgQnH+IoQ6///F OeBZR7y06ceRxT+90pue477f4IyRLTBPGWxNHVFjjGbo/BZdQWySXDkK1dJV+Bn9FHNY jNrA== X-Gm-Message-State: AKGB3mKmN3InsSqO6TH+122yTpqyuoe9cdd37F64/v3HG7P/M1j5rjB6 EEAyTvuFNJRyjJjs8sZqY1bMiQ== X-Received: by 10.99.65.70 with SMTP id o67mr11948617pga.348.1515488981896; Tue, 09 Jan 2018 01:09:41 -0800 (PST) Received: from baolinwangubtpc.spreadtrum.com ([117.18.48.82]) by smtp.gmail.com with ESMTPSA id m69sm15472964pfc.36.2018.01.09.01.09.39 (version=TLS1 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 09 Jan 2018 01:09:41 -0800 (PST) From: Baolin Wang To: daniel.lezcano@linaro.org, tglx@linutronix.de Cc: broonie@kernel.org, arnd@arndb.de, baolin.wang@linaro.org, linux-kernel@vger.kernel.org Subject: [PATCH 1/2] clocksource: Add persistent timer support Date: Tue, 9 Jan 2018 17:09:10 +0800 Message-Id: X-Mailer: git-send-email 1.7.9.5 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On some platforms (such as Spreadtrum sc9860 platform), they need one persistent timer to calculate the suspended time and compensate it for the OS time. But now there are no method to register one persistent timer on some architectures (such as arm64), thus this patch adds one common framework for timer drivers to register one persistent timer and implements the read_persistent_clock64() to compensate the OS time. Signed-off-by: Baolin Wang --- drivers/clocksource/Kconfig | 3 + drivers/clocksource/Makefile | 1 + drivers/clocksource/persistent-timer.c | 142 ++++++++++++++++++++++++++++++++ drivers/clocksource/persistent-timer.h | 26 ++++++ 4 files changed, 172 insertions(+) create mode 100644 drivers/clocksource/persistent-timer.c create mode 100644 drivers/clocksource/persistent-timer.h -- 1.7.9.5 diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 9a6b087..9cf3d41 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -27,6 +27,9 @@ config CLKBLD_I8253 config CLKSRC_MMIO bool +config PERSISTENT_TIMER + bool + config BCM2835_TIMER bool "BCM2835 timer driver" if COMPILE_TEST select CLKSRC_MMIO diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index d6dec44..42556f4 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -76,3 +76,4 @@ obj-$(CONFIG_H8300_TMR16) += h8300_timer16.o obj-$(CONFIG_H8300_TPU) += h8300_tpu.o obj-$(CONFIG_CLKSRC_ST_LPC) += clksrc_st_lpc.o obj-$(CONFIG_X86_NUMACHIP) += numachip.o +obj-$(CONFIG_PERSISTENT_TIMER) += persistent-timer.o diff --git a/drivers/clocksource/persistent-timer.c b/drivers/clocksource/persistent-timer.c new file mode 100644 index 0000000..89a631d --- /dev/null +++ b/drivers/clocksource/persistent-timer.c @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2017 Linaro, Inc. + * + * Author: Baolin Wang + */ + +#include +#include +#include +#include + +#include "persistent-timer.h" + +static struct persistent_timer *ptimer; + +void read_persistent_clock64(struct timespec64 *ts) +{ + u64 cycles, delta, nsecs; + + if (!ptimer) { + ts->tv_sec = 0; + ts->tv_nsec = 0; + return; + } + + cycles = ptimer->read(ptimer); + delta = (cycles - ptimer->last_cycles) & ptimer->mask; + + nsecs = clocksource_cyc2ns(delta, ptimer->mult, ptimer->shift); + timespec64_add_ns(&ptimer->ts, nsecs); + *ts = ptimer->ts; + + ptimer->last_cycles = cycles; +} + +static __init void persistent_timer_freq_init(struct persistent_timer *p) +{ + u64 max_sec = p->mask; + + do_div(max_sec, p->freq); + + /* + * Some counter's mask can be larger than 32bit, so we need to limit + * the max suspend time to have a good conversion precision. 12 hours + * can be enough usually. + */ + if (max_sec > 43200) + max_sec = 43200; + + clocks_calc_mult_shift(&p->mult, &p->shift, p->freq, + NSEC_PER_SEC, (u32)max_sec); +} + +static __init int persistent_timer_clk_init(struct device_node *np, + struct persistent_timer *p) +{ + int ret; + + p->clk = of_clk_get(np, 0); + if (IS_ERR(p->clk)) { + pr_err("Can't get timer clock\n"); + return PTR_ERR(p->clk); + } + + ret = clk_prepare_enable(p->clk); + if (ret) { + pr_err("Failed to enable clock for %pOF\n", np); + clk_put(p->clk); + return ret; + } + + p->freq = clk_get_rate(p->clk); + if (!p->freq) { + pr_err("Failed to get clock rate for %pOF\n", np); + clk_disable_unprepare(p->clk); + clk_put(p->clk); + return -EINVAL; + } + + return 0; +} + +static __init int persistent_timer_base_init(struct device_node *np, + struct persistent_timer *p) +{ + p->base = of_io_request_and_map(np, 0, of_node_full_name(np)); + if (IS_ERR(p->base)) { + pr_err("Can't map timer registers\n"); + return PTR_ERR(p->base); + } + + return 0; +} + +int __init persistent_timer_init_and_register(struct device_node *np, + struct persistent_timer *p) +{ + int ret; + + if (!p->read || !p->mask) + return -EINVAL; + + if (p->flags & PERSISTENT_TIMER_BASE) { + ret = persistent_timer_base_init(np, p); + if (ret) + return ret; + } + + if (p->flags & PERSISTENT_TIMER_CLOCK) { + ret = persistent_timer_clk_init(np, p); + if (ret) + goto err_clk; + } + + if (p->flags & PERSISTENT_TIMER_MULT_SHIFT) + persistent_timer_freq_init(p); + + p->last_cycles = 0; + ptimer = p; + return 0; + +err_clk: + if (p->flags & PERSISTENT_TIMER_BASE) + iounmap(p->base); + + return ret; +} + +void __init persistent_timer_cleanup(struct persistent_timer *p) +{ + if (p->flags & PERSISTENT_TIMER_CLOCK) { + p->freq = 0; + clk_disable_unprepare(p->clk); + clk_put(p->clk); + } + + if (p->flags & PERSISTENT_TIMER_BASE) + iounmap(p->base); + + ptimer = NULL; +} diff --git a/drivers/clocksource/persistent-timer.h b/drivers/clocksource/persistent-timer.h new file mode 100644 index 0000000..7705027 --- /dev/null +++ b/drivers/clocksource/persistent-timer.h @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: GPL-2.0 +#ifndef __PERSISTENT_TIMER_H__ +#define __PERSISTENT_TIMER_H__ + +#define PERSISTENT_TIMER_BASE BIT(0) +#define PERSISTENT_TIMER_CLOCK BIT(1) +#define PERSISTENT_TIMER_MULT_SHIFT BIT(2) + +struct persistent_timer { + u64 (*read)(struct persistent_timer *p); + void __iomem *base; + u64 last_cycles; + u64 mask; + u32 mult; + u32 shift; + struct clk *clk; + unsigned long freq; + unsigned int flags; + struct timespec64 ts; +}; + +extern int __init persistent_timer_init_and_register(struct device_node *np, + struct persistent_timer *p); +extern void __init persistent_timer_cleanup(struct persistent_timer *p); + +#endif