From patchwork Fri Apr 17 10:50:19 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Griffin X-Patchwork-Id: 6230201 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 6F9FC9F1AC for ; Fri, 17 Apr 2015 10:53:58 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 5BA952037D for ; Fri, 17 Apr 2015 10:53:57 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 5B00D2037F for ; Fri, 17 Apr 2015 10:53:56 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1Yj3rb-0003sz-3n; Fri, 17 Apr 2015 10:51:11 +0000 Received: from mail-wi0-f175.google.com ([209.85.212.175]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1Yj3rN-0003kK-60 for linux-arm-kernel@lists.infradead.org; Fri, 17 Apr 2015 10:50:58 +0000 Received: by widjs5 with SMTP id js5so31129064wid.1 for ; Fri, 17 Apr 2015 03:50:35 -0700 (PDT) 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=6tEmkSrlbSKXVbXkGrvN149yInDs7Zbo0DyBGl29b/E=; b=AH5NWPl0vNgbfqa04xnSSANkJFwUX5oCV3HZeliIVm/KpNQUa1EkRxKnDHlwzQJ+pz DJ05H6sRhR2GTqi2hQy6u/WbptCOzRT4CARBot6Rl+oZ4LnzPLwvi2WSDwPmf4NWVaWS KZ7Yjn5K2f8GsGV2gPlzsEA7qpHfrGUHGLkPOltb7Cb77jFJ9XWUrv4Mr6AHB03kJz4U 3tY+Z9OtyZbIUjD6ManJZMol8Dq23ZVtqdlE1xAjIxJF0BvmJspHwD+wbA11ziKGHHsI 50I8wI/lb6TuCJnvlqteaCo8qtf4dS0Cq9ngW09OIk4dhK6ZIG7R0y9IBiulzKrpQm3x uoIA== X-Gm-Message-State: ALoCoQkwOjh7u79va7YBFodVj/pUH1KcPp63jFei40JlVMaUf+ugmnu+ZkkYkL3jkY08dGkwLOvw X-Received: by 10.194.142.168 with SMTP id rx8mr4655729wjb.43.1429267834917; Fri, 17 Apr 2015 03:50:34 -0700 (PDT) Received: from localhost.localdomain ([213.205.252.24]) by mx.google.com with ESMTPSA id mv11sm2092668wic.23.2015.04.17.03.50.32 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Fri, 17 Apr 2015 03:50:34 -0700 (PDT) From: Peter Griffin To: linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, srinivas.kandagatla@gmail.com, maxime.coquelin@st.com, patrice.chotard@st.com, daniel.lezcano@linaro.org, tglx@linutronix.de Subject: [PATCH 1/5] clocksource: st_lpc: Add LPC timer as a clocksource. Date: Fri, 17 Apr 2015 11:50:19 +0100 Message-Id: <1429267823-8879-2-git-send-email-peter.griffin@linaro.org> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1429267823-8879-1-git-send-email-peter.griffin@linaro.org> References: <1429267823-8879-1-git-send-email-peter.griffin@linaro.org> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20150417_035057_547038_2DAFEC76 X-CRM114-Status: GOOD ( 18.08 ) X-Spam-Score: -0.7 (/) Cc: peter.griffin@linaro.org, devicetree@vger.kernel.org, Ajit Pal Singh , lee.jones@linaro.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-4.2 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This patch adds support for the LPC timer as a clocksource which is found on stih407 family SoCs. We wish to use the LPC timer as a clocksource instead of arm_global_timer, as the latter is tied to CPU frequency, and that driver currently makes no account for frequency scaling. Once this driver is merged cpufreq can be enabled for stih407 family SoCs without also effecting sched_clock. Signed-off-by: Ajit Pal Singh Signed-off-by: Peter Griffin --- drivers/clocksource/Kconfig | 16 +++++ drivers/clocksource/Makefile | 1 + drivers/clocksource/st_lpc.c | 154 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 171 insertions(+) create mode 100644 drivers/clocksource/st_lpc.c diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index a0b036c..29cd67d 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -253,4 +253,20 @@ config CLKSRC_PXA help This enables OST0 support available on PXA and SA-11x0 platforms. + +config CLKSRC_ST_LPC_CLOCK + bool + depends on ARCH_STI + select CLKSRC_OF if OF + help + Enable this option to use the Low Power controller timer + as clock source. + +config CLKSRC_ST_LPC_TIMER_SCHED_CLOCK + bool + depends on ST_LPC_CLOCK + default y + help + Use Low Power controller timer clock source as sched_clock + endmenu diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 752d5c7..356d331 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -51,3 +51,4 @@ obj-$(CONFIG_ARCH_INTEGRATOR_AP) += timer-integrator-ap.o obj-$(CONFIG_CLKSRC_VERSATILE) += versatile.o obj-$(CONFIG_CLKSRC_MIPS_GIC) += mips-gic-timer.o obj-$(CONFIG_ASM9260_TIMER) += asm9260_timer.o +obj-$(CONFIG_CLKSRC_ST_LPC_CLOCK) += st_lpc.o diff --git a/drivers/clocksource/st_lpc.c b/drivers/clocksource/st_lpc.c new file mode 100644 index 0000000..f9abded --- /dev/null +++ b/drivers/clocksource/st_lpc.c @@ -0,0 +1,154 @@ +/* + * This driver implements a Clocksource using the Low Power Timer in + * the Low Power Controller (LPC) in some STMicroelectronics + * STi series SoCs + * + * Copyright (C) 2015 STMicroelectronics Limited + * Author: Francesco Virlinzi + * Author: Ajit Pal Singh + * + * May be copied or modified under the terms of the GNU General Public + * License. See linux/COPYING for more information. + */ + +#include +#include +#include +#include +#include +#include + +/* Low Power Timer */ +#define LPC_LPT_LSB_OFF 0x400 +#define LPC_LPT_MSB_OFF 0x404 +#define LPC_LPT_START_OFF 0x408 + +struct st_lpc { + struct clk *clk; + void __iomem *iomem_cs; +}; + +static struct st_lpc *st_lpc; + +static u64 notrace st_lpc_counter_read(void) +{ + u64 counter; + u32 lower; + u32 upper, old_upper; + + upper = readl_relaxed(st_lpc->iomem_cs + LPC_LPT_MSB_OFF); + do { + old_upper = upper; + lower = readl_relaxed(st_lpc->iomem_cs + LPC_LPT_LSB_OFF); + upper = readl_relaxed(st_lpc->iomem_cs + LPC_LPT_MSB_OFF); + } while (upper != old_upper); + + counter = upper; + counter <<= 32; + counter |= lower; + return counter; +} + +static cycle_t st_lpc_clocksource_read(struct clocksource *cs) +{ + return st_lpc_counter_read(); +} + +static void st_lpc_clocksource_reset(struct clocksource *cs) +{ + writel_relaxed(0, st_lpc->iomem_cs + LPC_LPT_START_OFF); + writel_relaxed(0, st_lpc->iomem_cs + LPC_LPT_MSB_OFF); + writel_relaxed(0, st_lpc->iomem_cs + LPC_LPT_LSB_OFF); + writel_relaxed(1, st_lpc->iomem_cs + LPC_LPT_START_OFF); +} + +static struct clocksource st_lpc_clocksource = { + .name = "st-lpc clocksource", + .rating = 301, + .read = st_lpc_clocksource_read, + .mask = CLOCKSOURCE_MASK(64), + .flags = CLOCK_SOURCE_IS_CONTINUOUS, +}; + +#ifdef CONFIG_CLKSRC_LPC_TIMER_SCHED_CLOCK +static u64 notrace st_lpc_sched_clock_read(void) +{ + return st_lpc_counter_read(); +} +#endif + +static void __init st_lpc_clocksource_init(void) +{ + unsigned long rate; + + st_lpc_clocksource_reset(&st_lpc_clocksource); + + rate = clk_get_rate(st_lpc->clk); +#ifdef CONFIG_CLKSRC_LPC_TIMER_SCHED_CLOCK + sched_clock_register(st_lpc_sched_clock_read, 64, rate); +#endif + clocksource_register_hz(&st_lpc_clocksource, rate); + +} + +static int st_lpc_setup_clk(struct device_node *np) +{ + char *clk_name = "lpc_clk"; + struct clk *clk; + int ret; + + clk = of_clk_get_by_name(np, clk_name); + if (IS_ERR(clk)) { + pr_err("st-lpc: unable to get lpc clock\n"); + ret = PTR_ERR(clk); + return ret; + } + + if (clk_prepare_enable(clk)) { + pr_err("st-lpc: %s could not be enabled\n", clk_name); + return -EINVAL; + } + + if (!clk_get_rate(clk)) { + pr_err("st-lpc: Unable to get clock rate\n"); + clk_disable_unprepare(clk); + return -EINVAL; + } + + pr_info("st-lpc: %s running @ %lu Hz\n", + clk_name, clk_get_rate(clk)); + + st_lpc->clk = clk; + + return 0; +} + +static void __init st_lpc_of_register(struct device_node *np) +{ + st_lpc = kzalloc(sizeof(*st_lpc), GFP_KERNEL); + if (!st_lpc) { + pr_err("st-lpc: No memory available\n"); + return; + } + + st_lpc->iomem_cs = of_iomap(np, 0); + if (!st_lpc->iomem_cs) { + pr_err("st-lpc: Unable to map iomem\n"); + goto err_kfree; + } + + if (st_lpc_setup_clk(np)) + goto err_iounmap; + + st_lpc_clocksource_init(); + + pr_info("st-lpc: clocksource initialised: iomem: %p\n", + st_lpc->iomem_cs); + return; +err_iounmap: + iounmap(st_lpc->iomem_cs); +err_kfree: + kfree(st_lpc); +} + +CLOCKSOURCE_OF_DECLARE(st_lpc, "st,st_lpc_timer", st_lpc_of_register);