From patchwork Tue Mar 11 22:40:42 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Lezcano X-Patchwork-Id: 26054 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-pd0-f200.google.com (mail-pd0-f200.google.com [209.85.192.200]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 2B39920068 for ; Tue, 11 Mar 2014 22:41:37 +0000 (UTC) Received: by mail-pd0-f200.google.com with SMTP id p10sf457069pdj.11 for ; Tue, 11 Mar 2014 15:41:36 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:delivered-to:from:to:cc:subject :date:message-id:in-reply-to:references:sender:precedence:list-id :x-original-sender:x-original-authentication-results:mailing-list :list-post:list-help:list-archive:list-unsubscribe; bh=HNujtfchBGrS0jXnFbDCPDlQnEdbVCq+SpqWN+f1wvM=; b=Y3kY770gBoFBGHdfw0zYkrnWiaH1Fj6E7/4lfXO+gMtWFM1//i4WzFFmnYqWP5RhF/ 6v2UhXiukbvPveTWDtBHpqtAAEIzWuH1Vy8vhrAPWSU42VQeuN58xfnggrt5E+yxq6LM nIIdzUnidi9yvVRu35sDBcCwUFC5i3codtNoHHkI7m31bPEbkRvo9nDoZFP0J+xxaB2e FL1FNPh4oiivWYskAMU01Zv7Ipvr/jPuLMlwrw0x/k4MA6+QQjMdh4LH+LY4QfB068bt NyELovbv8TkBabXdmDqLybjNY0qJ3OmRkO6bnFQa3dxC4H1ffUqgn0KexvpznDjPtI2A TcQg== X-Gm-Message-State: ALoCoQk41vQMBYjFIC3wLKmhCUq8cUel1kH1K3GNtK371uKie4QccbV0gCYDTKjkdGqcNsK6zOn4 X-Received: by 10.66.189.228 with SMTP id gl4mr337387pac.26.1394577696436; Tue, 11 Mar 2014 15:41:36 -0700 (PDT) MIME-Version: 1.0 X-BeenThere: patchwork-forward@linaro.org Received: by 10.140.87.33 with SMTP id q30ls1780514qgd.99.gmail; Tue, 11 Mar 2014 15:41:36 -0700 (PDT) X-Received: by 10.52.188.41 with SMTP id fx9mr28264584vdc.19.1394577696264; Tue, 11 Mar 2014 15:41:36 -0700 (PDT) Received: from mail-vc0-f171.google.com (mail-vc0-f171.google.com [209.85.220.171]) by mx.google.com with ESMTPS id sn5si2127203vdc.128.2014.03.11.15.41.36 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Tue, 11 Mar 2014 15:41:36 -0700 (PDT) Received-SPF: neutral (google.com: 209.85.220.171 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) client-ip=209.85.220.171; Received: by mail-vc0-f171.google.com with SMTP id lg15so2922668vcb.16 for ; Tue, 11 Mar 2014 15:41:36 -0700 (PDT) X-Received: by 10.220.250.203 with SMTP id mp11mr29164301vcb.2.1394577696147; Tue, 11 Mar 2014 15:41:36 -0700 (PDT) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patch@linaro.org Received: by 10.220.78.9 with SMTP id i9csp238819vck; Tue, 11 Mar 2014 15:41:35 -0700 (PDT) X-Received: by 10.68.101.101 with SMTP id ff5mr770761pbb.116.1394577695020; Tue, 11 Mar 2014 15:41:35 -0700 (PDT) Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id tm9si352472pab.76.2014.03.11.15.41.34; Tue, 11 Mar 2014 15:41:34 -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; Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756040AbaCKWlE (ORCPT + 26 others); Tue, 11 Mar 2014 18:41:04 -0400 Received: from mail-we0-f170.google.com ([74.125.82.170]:36852 "EHLO mail-we0-f170.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756003AbaCKWlB (ORCPT ); Tue, 11 Mar 2014 18:41:01 -0400 Received: by mail-we0-f170.google.com with SMTP id w61so10658820wes.29 for ; Tue, 11 Mar 2014 15:40:59 -0700 (PDT) X-Received: by 10.180.98.200 with SMTP id ek8mr5048520wib.4.1394577659770; Tue, 11 Mar 2014 15:40:59 -0700 (PDT) Received: from localhost.localdomain (AToulouse-654-1-526-136.w109-220.abo.wanadoo.fr. [109.220.245.136]) by mx.google.com with ESMTPSA id n3sm10411631wix.10.2014.03.11.15.40.58 for (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Tue, 11 Mar 2014 15:40:59 -0700 (PDT) From: Daniel Lezcano To: tglx@linutronix.de, mingo@kernel.org Cc: linux-kernel@vger.kernel.org, dan.carpenter@oracle.com, ezequiel.garcia@free-electrons.com, ivan.khoronzhuk@ti.com, linus.walleij@linaro.org, magnus.damm@gmail.com, matthias.bgg@gmail.com, soren.brinkmann@xilinx.com, sboyd@codeaurora.org Subject: [PATCH 06/17] clocksource: timer-keystone: introduce clocksource driver for Keystone Date: Tue, 11 Mar 2014 23:40:42 +0100 Message-Id: <1394577653-8615-6-git-send-email-daniel.lezcano@linaro.org> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1394577653-8615-1-git-send-email-daniel.lezcano@linaro.org> References: <531F8FAC.2040902@linaro.org> <1394577653-8615-1-git-send-email-daniel.lezcano@linaro.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: list List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: daniel.lezcano@linaro.org X-Original-Authentication-Results: mx.google.com; spf=neutral (google.com: 209.85.220.171 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org X-Google-Group-Id: 836684582541 List-Post: , List-Help: , List-Archive: List-Unsubscribe: , From: Ivan Khoronzhuk Add broadcast clock-event device for the Keystone arch. The timer can be configured as a general-purpose 64-bit timer, dual general-purpose 32-bit timers. When configured as dual 32-bit timers, each half can operate in conjunction (chain mode) or independently (unchained mode) of each other. Reviewed-by: Stephen Boyd Acked-by: Santosh shilimkar Signed-off-by: Ivan Khoronzhuk Signed-off-by: Daniel Lezcano --- drivers/clocksource/Makefile | 1 + drivers/clocksource/timer-keystone.c | 244 ++++++++++++++++++++++++++++++++++ 2 files changed, 245 insertions(+) create mode 100644 drivers/clocksource/timer-keystone.c diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 01e5435..aed3488 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -38,3 +38,4 @@ obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o obj-$(CONFIG_ARM_GLOBAL_TIMER) += arm_global_timer.o obj-$(CONFIG_CLKSRC_METAG_GENERIC) += metag_generic.o obj-$(CONFIG_ARCH_HAS_TICK_BROADCAST) += dummy_timer.o +obj-$(CONFIG_ARCH_KEYSTONE) += timer-keystone.o diff --git a/drivers/clocksource/timer-keystone.c b/drivers/clocksource/timer-keystone.c new file mode 100644 index 0000000..86b08cd --- /dev/null +++ b/drivers/clocksource/timer-keystone.c @@ -0,0 +1,244 @@ +/* + * Keystone broadcast clock-event + * + * Copyright 2013 Texas Instruments, Inc. + * + * Author: Ivan Khoronzhuk + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include + +#define TIMER_NAME "timer-keystone" + +/* Timer register offsets */ +#define TIM12 0x10 +#define TIM34 0x14 +#define PRD12 0x18 +#define PRD34 0x1c +#define TCR 0x20 +#define TGCR 0x24 +#define INTCTLSTAT 0x44 + +/* Timer register bitfields */ +#define TCR_ENAMODE_MASK 0xC0 +#define TCR_ENAMODE_ONESHOT_MASK 0x40 +#define TCR_ENAMODE_PERIODIC_MASK 0x80 + +#define TGCR_TIM_UNRESET_MASK 0x03 +#define INTCTLSTAT_ENINT_MASK 0x01 + +/** + * struct keystone_timer: holds timer's data + * @base: timer memory base address + * @hz_period: cycles per HZ period + * @event_dev: event device based on timer + */ +static struct keystone_timer { + void __iomem *base; + unsigned long hz_period; + struct clock_event_device event_dev; +} timer; + +static inline u32 keystone_timer_readl(unsigned long rg) +{ + return readl_relaxed(timer.base + rg); +} + +static inline void keystone_timer_writel(u32 val, unsigned long rg) +{ + writel_relaxed(val, timer.base + rg); +} + +/** + * keystone_timer_barrier: write memory barrier + * use explicit barrier to avoid using readl/writel non relaxed function + * variants, because in our case non relaxed variants hide the true places + * where barrier is needed. + */ +static inline void keystone_timer_barrier(void) +{ + __iowmb(); +} + +/** + * keystone_timer_config: configures timer to work in oneshot/periodic modes. + * @ mode: mode to configure + * @ period: cycles number to configure for + */ +static int keystone_timer_config(u64 period, enum clock_event_mode mode) +{ + u32 tcr; + u32 off; + + tcr = keystone_timer_readl(TCR); + off = tcr & ~(TCR_ENAMODE_MASK); + + /* set enable mode */ + switch (mode) { + case CLOCK_EVT_MODE_ONESHOT: + tcr |= TCR_ENAMODE_ONESHOT_MASK; + break; + case CLOCK_EVT_MODE_PERIODIC: + tcr |= TCR_ENAMODE_PERIODIC_MASK; + break; + default: + return -1; + } + + /* disable timer */ + keystone_timer_writel(off, TCR); + /* here we have to be sure the timer has been disabled */ + keystone_timer_barrier(); + + /* reset counter to zero, set new period */ + keystone_timer_writel(0, TIM12); + keystone_timer_writel(0, TIM34); + keystone_timer_writel(period & 0xffffffff, PRD12); + keystone_timer_writel(period >> 32, PRD34); + + /* + * enable timer + * here we have to be sure that CNTLO, CNTHI, PRDLO, PRDHI registers + * have been written. + */ + keystone_timer_barrier(); + keystone_timer_writel(tcr, TCR); + return 0; +} + +static void keystone_timer_disable(void) +{ + u32 tcr; + + tcr = keystone_timer_readl(TCR); + + /* disable timer */ + tcr &= ~(TCR_ENAMODE_MASK); + keystone_timer_writel(tcr, TCR); +} + +static irqreturn_t keystone_timer_interrupt(int irq, void *dev_id) +{ + struct clock_event_device *evt = dev_id; + + evt->event_handler(evt); + return IRQ_HANDLED; +} + +static int keystone_set_next_event(unsigned long cycles, + struct clock_event_device *evt) +{ + return keystone_timer_config(cycles, evt->mode); +} + +static void keystone_set_mode(enum clock_event_mode mode, + struct clock_event_device *evt) +{ + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + keystone_timer_config(timer.hz_period, CLOCK_EVT_MODE_PERIODIC); + break; + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_SHUTDOWN: + case CLOCK_EVT_MODE_ONESHOT: + keystone_timer_disable(); + break; + default: + break; + } +} + +static void __init keystone_timer_init(struct device_node *np) +{ + struct clock_event_device *event_dev = &timer.event_dev; + unsigned long rate; + struct clk *clk; + int irq, error; + u32 tgcr; + + irq = irq_of_parse_and_map(np, 0); + if (irq == NO_IRQ) { + pr_err("%s: failed to map interrupts\n", __func__); + return; + } + + timer.base = of_iomap(np, 0); + if (!timer.base) { + pr_err("%s: failed to map registers\n", __func__); + return; + } + + clk = of_clk_get(np, 0); + if (IS_ERR(clk)) { + pr_err("%s: failed to get clock\n", __func__); + iounmap(timer.base); + return; + } + + error = clk_prepare_enable(clk); + if (error) { + pr_err("%s: failed to enable clock\n", __func__); + goto err; + } + + rate = clk_get_rate(clk); + + /* disable, use internal clock source */ + keystone_timer_writel(0, TCR); + /* here we have to be sure the timer has been disabled */ + keystone_timer_barrier(); + + /* reset timer as 64-bit, no pre-scaler, plus features are disabled */ + tgcr = 0; + keystone_timer_writel(0, TGCR); + + /* unreset timer */ + tgcr |= TGCR_TIM_UNRESET_MASK; + keystone_timer_writel(tgcr, TGCR); + + /* init counter to zero */ + keystone_timer_writel(0, TIM12); + keystone_timer_writel(0, TIM34); + + timer.hz_period = DIV_ROUND_UP(rate, HZ); + + /* enable timer interrupts */ + keystone_timer_writel(INTCTLSTAT_ENINT_MASK, INTCTLSTAT); + + error = request_irq(irq, keystone_timer_interrupt, IRQF_TIMER, + TIMER_NAME, event_dev); + if (error) { + pr_err("%s: failed to setup irq\n", __func__); + goto err; + } + + /* setup clockevent */ + event_dev->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; + event_dev->set_next_event = keystone_set_next_event; + event_dev->set_mode = keystone_set_mode; + event_dev->cpumask = cpu_all_mask; + event_dev->owner = THIS_MODULE; + event_dev->name = TIMER_NAME; + event_dev->irq = irq; + + clockevents_config_and_register(event_dev, rate, 1, ULONG_MAX); + + pr_info("keystone timer clock @%lu Hz\n", rate); + return; +err: + clk_put(clk); + iounmap(timer.base); +} + +CLOCKSOURCE_OF_DECLARE(keystone_timer, "ti,keystone-timer", + keystone_timer_init);