From patchwork Wed Sep 20 14:51:06 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Benjamin Gaignard X-Patchwork-Id: 113133 Delivered-To: patch@linaro.org Received: by 10.140.106.117 with SMTP id d108csp860449qgf; Wed, 20 Sep 2017 07:51:32 -0700 (PDT) X-Received: by 10.84.229.6 with SMTP id b6mr2330199plk.401.1505919092309; Wed, 20 Sep 2017 07:51:32 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1505919092; cv=none; d=google.com; s=arc-20160816; b=j0yfencYGLqHEzYQMAMS6tR9REv1l2qH4EoxP9eTY1MNnaNB8nZEkbVURAp8rIXgdL qWSHkFlsfW0BnAUaHmqI4NzRvQ2HNuoDRmPlGDqgJP0ttJnjGZDYtsc3OcCRthxXy6mb SrEH8ikLSGnNJ4f/bEsrak25O+Wq+JQ6t3cAHedFj18Q6+ic2w1SNkXqObbrRcmVQ541 +mnqqMaDRK6ehWF6TelMN/TtF5ffyhMrqIQcwSymTT+9gZbxBpilcy/RebricmKRDgCR w7vJ3+m3jFnff4NbUKVYkNV4C/vhgZCiHfVM6ZzIhBis6a75Z6zLcmsssd9s5jYrI5Zs SXSw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=iaOM2Ii5btU3GhAcD3iGn8yPm2ThPYlJwr/71wQCq3g=; b=n57bDwWqMkJwK3ZzWY2D3oEXtNtxLlOfcao8PrsM23WM5u7g3F7nxBi9DUyXy8Yhzf xTPal9vHamjKQBOpgF6kJQbHj6sDkqhxUb3yb7udD+/mVuWY9Etylt9WcKd0QXKLEhGN W0CIEzAuSPqCCfAwJXK6KOAdAmPunsP3odBt7Q09i/e3yrkKr/AxOTm/ebfvs0MQDKbK CjhJgLFg6ihlVlBo+zbdkdt2HAabuBvB9co77sXmMbOysUhkudBvCYCmQEPHbKRwyzld ahwmq6iCrGoe7CR0YTGEAZwYfr4XYz1KM9Df63/zMDoaSDzc5nNiid/Vg85OpAr/9HF7 baqA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=fWlz/vw8; 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 x191si3336105pgx.642.2017.09.20.07.51.32; Wed, 20 Sep 2017 07:51:32 -0700 (PDT) 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=fWlz/vw8; 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 S1751838AbdITOv1 (ORCPT + 26 others); Wed, 20 Sep 2017 10:51:27 -0400 Received: from mail-wr0-f182.google.com ([209.85.128.182]:50429 "EHLO mail-wr0-f182.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751797AbdITOvY (ORCPT ); Wed, 20 Sep 2017 10:51:24 -0400 Received: by mail-wr0-f182.google.com with SMTP id w12so2381640wrc.7 for ; Wed, 20 Sep 2017 07:51:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=iaOM2Ii5btU3GhAcD3iGn8yPm2ThPYlJwr/71wQCq3g=; b=fWlz/vw86UR81+b2XX66qP4LGALQ9/6hxIOvUVqCFSjF1sWsdA1Ed4Dea1hOpcD6SY Xl4TMJAR1fnn+WMwcqce0DyA9ZroytCTX6gjsbyLzYfPaOQwBLwijKBQ9izxm93xl1hO kp6kzsSKxqrUMEN60KtITRiZAqOTIL0syL6JM= 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:in-reply-to :references; bh=iaOM2Ii5btU3GhAcD3iGn8yPm2ThPYlJwr/71wQCq3g=; b=l2F9fFGlPST1bxp+jLDMWDd8dDiCyB2R7mfPo9RTEGETRcqimo8L/4TmGlRgR6kQZQ 2Kcpo5unjGyjtlfScpE2OSdxLZmA0rhP9fYh2sPYQnKpECYOyhHSooOovL+Fj1OG1KN6 sNEwrK4wbP09hCEIFO2jvclTMHon48LCXFQd742rO4RvHU0yusCrXsIGCiywklwSE8eZ dhPJTv3jcFT97F/QhUm7JHsg/Rr3O+8yhzU026q0LlPpcRot14zYwIpz9ykbGCRq0cHB Mvns5GoLLP3BZDnBKVKLda6rtdV9R3ujC2LwaYP3Gj8qN7xWnKg1uaf0mq2/PpRT9v6I v9uA== X-Gm-Message-State: AHPjjUhK2Mq9aNbwaAMV0g5y7JIL+qwn7DTVnwgF3MLWdJczmUNvkMJW glhJ9Pnz7j1+mijlkTkq2wp+hg== X-Google-Smtp-Source: AOwi7QBk6qXxksSv/aduqF+MvDO8qvne1Wnx6+aUEwfmJ4UOmmy02Z9udznRP7wEdVjH1E7XQyAZNw== X-Received: by 10.223.160.23 with SMTP id k23mr4945945wrk.212.1505919083119; Wed, 20 Sep 2017 07:51:23 -0700 (PDT) Received: from lmecxl0911.lme.st.com ([80.215.203.94]) by smtp.gmail.com with ESMTPSA id z108sm2088197wrc.49.2017.09.20.07.51.21 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 20 Sep 2017 07:51:22 -0700 (PDT) From: Benjamin Gaignard To: robh+dt@kernel.org, mark.rutland@arm.com, linux@armlinux.org.uk, mcoquelin.stm32@gmail.com, alexandre.torgue@st.com, daniel.lezcano@linaro.org, tglx@linutronix.de, ludovic.barre@st.com Cc: devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Benjamin Gaignard Subject: [PATCH v3 1/2] clocksource: stm32: add clocksource support Date: Wed, 20 Sep 2017 16:51:06 +0200 Message-Id: <1505919067-28041-2-git-send-email-benjamin.gaignard@linaro.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1505919067-28041-1-git-send-email-benjamin.gaignard@linaro.org> References: <1505919067-28041-1-git-send-email-benjamin.gaignard@linaro.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Rework driver code to be able to implement clocksource and clockevent on the same hardware block. Before this patch only the counter of the hardware block was used to generate clock events. Now counter will be used to provide a 32 bits clock source and a comparator will provide clock events. In addition of that this patch also forbid to use 16 bits timers because they are not enough accurate. Use timer_of helpers functions to remove code from probe function and avoid using proprietary structure. Signed-off-by: Benjamin Gaignard Signed-off-by: Ludovic Barre --- drivers/clocksource/Kconfig | 1 + drivers/clocksource/timer-stm32.c | 229 ++++++++++++++++++-------------------- 2 files changed, 112 insertions(+), 118 deletions(-) -- 2.7.4 diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 0a953fc..50d40cb 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -289,6 +289,7 @@ config CLKSRC_STM32 bool "Clocksource for STM32 SoCs" if !ARCH_STM32 depends on OF && ARM && (ARCH_STM32 || COMPILE_TEST) select CLKSRC_MMIO + select TIMER_OF config CLKSRC_MPS2 bool "Clocksource for MPS2 SoCs" if COMPILE_TEST diff --git a/drivers/clocksource/timer-stm32.c b/drivers/clocksource/timer-stm32.c index 8f24237..fb84252 100644 --- a/drivers/clocksource/timer-stm32.c +++ b/drivers/clocksource/timer-stm32.c @@ -16,175 +16,168 @@ #include #include #include +#include +#include + +#include "timer-of.h" #define TIM_CR1 0x00 #define TIM_DIER 0x0c #define TIM_SR 0x10 #define TIM_EGR 0x14 +#define TIM_CNT 0x24 #define TIM_PSC 0x28 #define TIM_ARR 0x2c +#define TIM_CCR1 0x34 #define TIM_CR1_CEN BIT(0) -#define TIM_CR1_OPM BIT(3) +#define TIM_CR1_UDIS BIT(1) #define TIM_CR1_ARPE BIT(7) -#define TIM_DIER_UIE BIT(0) - -#define TIM_SR_UIF BIT(0) +#define TIM_DIER_CC1IE BIT(1) #define TIM_EGR_UG BIT(0) -struct stm32_clock_event_ddata { - struct clock_event_device evtdev; - unsigned periodic_top; - void __iomem *base; -}; - -static int stm32_clock_event_shutdown(struct clock_event_device *evtdev) +static int stm32_clock_event_shutdown(struct clock_event_device *evt) { - struct stm32_clock_event_ddata *data = - container_of(evtdev, struct stm32_clock_event_ddata, evtdev); - void *base = data->base; + struct timer_of *to = to_timer_of(evt); + + writel_relaxed(0, timer_of_base(to) + TIM_DIER); - writel_relaxed(0, base + TIM_CR1); return 0; } -static int stm32_clock_event_set_periodic(struct clock_event_device *evtdev) +static int stm32_clock_event_set_next_event(unsigned long evt, + struct clock_event_device *clkevt) { - struct stm32_clock_event_ddata *data = - container_of(evtdev, struct stm32_clock_event_ddata, evtdev); - void *base = data->base; + struct timer_of *to = to_timer_of(clkevt); + unsigned long cnt; + + cnt = readl_relaxed(timer_of_base(to) + TIM_CNT); + writel_relaxed(cnt + evt, timer_of_base(to) + TIM_CCR1); + writel_relaxed(TIM_DIER_CC1IE, timer_of_base(to) + TIM_DIER); - writel_relaxed(data->periodic_top, base + TIM_ARR); - writel_relaxed(TIM_CR1_ARPE | TIM_CR1_CEN, base + TIM_CR1); return 0; } -static int stm32_clock_event_set_next_event(unsigned long evt, - struct clock_event_device *evtdev) +static int stm32_clock_event_set_periodic(struct clock_event_device *evt) { - struct stm32_clock_event_ddata *data = - container_of(evtdev, struct stm32_clock_event_ddata, evtdev); + struct timer_of *to = to_timer_of(evt); - writel_relaxed(evt, data->base + TIM_ARR); - writel_relaxed(TIM_CR1_ARPE | TIM_CR1_OPM | TIM_CR1_CEN, - data->base + TIM_CR1); + return stm32_clock_event_set_next_event(timer_of_period(to), evt); +} - return 0; +static int stm32_clock_event_set_oneshot(struct clock_event_device *evt) +{ + return stm32_clock_event_set_next_event(0, evt); } static irqreturn_t stm32_clock_event_handler(int irq, void *dev_id) { - struct stm32_clock_event_ddata *data = dev_id; + struct clock_event_device *evt = (struct clock_event_device *)dev_id; + struct timer_of *to = to_timer_of(evt); + + writel_relaxed(0, timer_of_base(to) + TIM_SR); - writel_relaxed(0, data->base + TIM_SR); + if (clockevent_state_periodic(evt)) + stm32_clock_event_set_periodic(evt); + else + stm32_clock_event_shutdown(evt); - data->evtdev.event_handler(&data->evtdev); + evt->event_handler(evt); return IRQ_HANDLED; } -static struct stm32_clock_event_ddata clock_event_ddata = { - .evtdev = { - .name = "stm32 clockevent", - .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC, - .set_state_shutdown = stm32_clock_event_shutdown, - .set_state_periodic = stm32_clock_event_set_periodic, - .set_state_oneshot = stm32_clock_event_shutdown, - .tick_resume = stm32_clock_event_shutdown, - .set_next_event = stm32_clock_event_set_next_event, - .rating = 200, - }, -}; - -static int __init stm32_clockevent_init(struct device_node *np) +static void __init stm32_clockevent_init(struct timer_of *to) { - struct stm32_clock_event_ddata *data = &clock_event_ddata; - struct clk *clk; - struct reset_control *rstc; - unsigned long rate, max_delta; - int irq, ret, bits, prescaler = 1; - - clk = of_clk_get(np, 0); - if (IS_ERR(clk)) { - ret = PTR_ERR(clk); - pr_err("failed to get clock for clockevent (%d)\n", ret); - goto err_clk_get; - } + writel_relaxed(0, timer_of_base(to) + TIM_DIER); + writel_relaxed(0, timer_of_base(to) + TIM_SR); - ret = clk_prepare_enable(clk); - if (ret) { - pr_err("failed to enable timer clock for clockevent (%d)\n", - ret); - goto err_clk_enable; - } + clockevents_config_and_register(&to->clkevt, + timer_of_rate(to), 0x60, ~0U); +} - rate = clk_get_rate(clk); +static void __iomem *stm32_timer_cnt __read_mostly; +static u64 notrace stm32_read_sched_clock(void) +{ + return readl_relaxed(stm32_timer_cnt); +} - rstc = of_reset_control_get(np, NULL); - if (!IS_ERR(rstc)) { - reset_control_assert(rstc); - reset_control_deassert(rstc); - } +static int __init stm32_clocksource_init(struct timer_of *to) +{ + writel_relaxed(~0U, timer_of_base(to) + TIM_ARR); + writel_relaxed(0, timer_of_base(to) + TIM_PSC); + writel_relaxed(0, timer_of_base(to) + TIM_SR); + writel_relaxed(0, timer_of_base(to) + TIM_DIER); + writel_relaxed(0, timer_of_base(to) + TIM_SR); + writel_relaxed(TIM_CR1_ARPE | TIM_CR1_UDIS, + timer_of_base(to) + TIM_CR1); + + /* Make sure that registers are updated */ + writel_relaxed(TIM_EGR_UG, timer_of_base(to) + TIM_EGR); + + /* Enable controller */ + writel_relaxed(TIM_CR1_ARPE | TIM_CR1_UDIS | TIM_CR1_CEN, + timer_of_base(to) + TIM_CR1); + + stm32_timer_cnt = timer_of_base(to) + TIM_CNT; + sched_clock_register(stm32_read_sched_clock, 32, timer_of_rate(to)); + + return clocksource_mmio_init(stm32_timer_cnt, "stm32_timer", + timer_of_rate(to), 250, 32, + clocksource_mmio_readl_up); +} - data->base = of_iomap(np, 0); - if (!data->base) { - ret = -ENXIO; - pr_err("failed to map registers for clockevent\n"); - goto err_iomap; - } +static int __init stm32_timer_init(struct device_node *node) +{ + struct reset_control *rstc; + unsigned long max_arr; + struct timer_of *to; + int ret; - irq = irq_of_parse_and_map(np, 0); - if (!irq) { - ret = -EINVAL; - pr_err("%pOF: failed to get irq.\n", np); - goto err_get_irq; - } + to = kzalloc(sizeof(*to), GFP_KERNEL); + if (!to) + return -ENOMEM; - /* Detect whether the timer is 16 or 32 bits */ - writel_relaxed(~0U, data->base + TIM_ARR); - max_delta = readl_relaxed(data->base + TIM_ARR); - if (max_delta == ~0U) { - prescaler = 1; - bits = 32; - } else { - prescaler = 1024; - bits = 16; - } - writel_relaxed(0, data->base + TIM_ARR); + to->flags = TIMER_OF_IRQ | TIMER_OF_CLOCK | TIMER_OF_BASE; - writel_relaxed(prescaler - 1, data->base + TIM_PSC); - writel_relaxed(TIM_EGR_UG, data->base + TIM_EGR); - writel_relaxed(TIM_DIER_UIE, data->base + TIM_DIER); - writel_relaxed(0, data->base + TIM_SR); + to->clkevt.name = "stm32_clockevent"; + to->clkevt.rating = 200; + to->clkevt.features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC; + to->clkevt.set_state_shutdown = stm32_clock_event_shutdown; + to->clkevt.set_state_periodic = stm32_clock_event_set_periodic; + to->clkevt.set_state_oneshot = stm32_clock_event_set_oneshot; + to->clkevt.tick_resume = stm32_clock_event_shutdown; + to->clkevt.set_next_event = stm32_clock_event_set_next_event; - data->periodic_top = DIV_ROUND_CLOSEST(rate, prescaler * HZ); + to->of_irq.handler = stm32_clock_event_handler; - clockevents_config_and_register(&data->evtdev, - DIV_ROUND_CLOSEST(rate, prescaler), - 0x1, max_delta); + ret = timer_of_init(node, to); + if (ret) + return ret; - ret = request_irq(irq, stm32_clock_event_handler, IRQF_TIMER, - "stm32 clockevent", data); - if (ret) { - pr_err("%pOF: failed to request irq.\n", np); - goto err_get_irq; + rstc = of_reset_control_get(node, NULL); + if (!IS_ERR(rstc)) { + reset_control_assert(rstc); + reset_control_deassert(rstc); } - pr_info("%pOF: STM32 clockevent driver initialized (%d bits)\n", - np, bits); + /* Detect whether the timer is 16 or 32 bits */ + writel_relaxed(~0U, timer_of_base(to) + TIM_ARR); + max_arr = readl_relaxed(timer_of_base(to) + TIM_ARR); + if (max_arr != ~0U) { + pr_err("32 bits timer is needed\n"); + return -EINVAL; + } - return ret; + ret = stm32_clocksource_init(to); + if (ret) + return ret; -err_get_irq: - iounmap(data->base); -err_iomap: - clk_disable_unprepare(clk); -err_clk_enable: - clk_put(clk); -err_clk_get: - return ret; + stm32_clockevent_init(to); + + return 0; } -TIMER_OF_DECLARE(stm32, "st,stm32-timer", stm32_clockevent_init); +TIMER_OF_DECLARE(stm32, "st,stm32-timer", stm32_timer_init);