From patchwork Mon Jun 10 09:35:55 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sebastian Hesselbarth X-Patchwork-Id: 2696531 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from casper.infradead.org (casper.infradead.org [85.118.1.10]) by patchwork1.kernel.org (Postfix) with ESMTP id 686B63FD4F for ; Mon, 10 Jun 2013 09:37:20 +0000 (UTC) Received: from merlin.infradead.org ([2001:4978:20e::2]) by casper.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1UlyWw-0000lR-Tv; Mon, 10 Jun 2013 09:36:52 +0000 Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1UlyWf-0005pT-GC; Mon, 10 Jun 2013 09:36:33 +0000 Received: from mail-bk0-x231.google.com ([2a00:1450:4008:c01::231]) by merlin.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1UlyWc-0005oc-C8 for linux-arm-kernel@lists.infradead.org; Mon, 10 Jun 2013 09:36:31 +0000 Received: by mail-bk0-f49.google.com with SMTP id mz10so1039278bkb.8 for ; Mon, 10 Jun 2013 02:36:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references; bh=D/5nczOm76DTP8FcodowyS2sCN9EjiTpEZUOUoAU330=; b=OoqA7claXTHAnAuSephnzgnPlKmrGWaQwvDSs1w0O7ukpWOe4gX3yaLQgt45YNxQD4 oDnXqOXzYzyYEXklImY65h2VULq6yYpodcbQ7REM/LV/PUjmuBaP57ilRXBF6EzPfEJv djSnP2pHXgWrwa/POnKqrUCAlFjMDelcSdET9sdFBWNmOt7+MFRTiVm9Cv0VhXV0D1Nq BQ/QGdJ62ZYtczg5EwuKGpaXCz09A6O2Kq5pRHPVXBMtSgw/CvDjTgr/7nRNDoftAe1d ibTcVAK1nRIqqqgVSVwWziet2keXtWzDmRNUViH2ozKysccElWtULkrKjrClZfWY5Qmf 7DIQ== X-Received: by 10.204.224.15 with SMTP id im15mr1371733bkb.120.1370856968153; Mon, 10 Jun 2013 02:36:08 -0700 (PDT) Received: from topkick.lan (dslc-082-083-251-181.pools.arcor-ip.net. [82.83.251.181]) by mx.google.com with ESMTPSA id jm15sm3291088bkb.13.2013.06.10.02.36.06 for (version=TLSv1.2 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Mon, 10 Jun 2013 02:36:07 -0700 (PDT) Received: from picnic.unix.mst.uni-hannover.de (firewall.mst.uni-hannover.de [130.75.30.51]) by topkick.lan (Postfix) with ESMTPSA id 1FEB75F918; Mon, 10 Jun 2013 11:34:55 +0200 (CEST) From: Sebastian Hesselbarth To: Sebastian Hesselbarth Subject: [PATCH v4 2/6] clocksource: add Marvell Orion SoC timer Date: Mon, 10 Jun 2013 11:35:55 +0200 Message-Id: <1370856955-10514-1-git-send-email-sebastian.hesselbarth@gmail.com> X-Mailer: git-send-email 1.7.2.5 In-Reply-To: <1370536034-23956-1-git-send-email-sebastian.hesselbarth@gmail.com> References: <1370536034-23956-1-git-send-email-sebastian.hesselbarth@gmail.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20130610_053630_715161_0533CB6B X-CRM114-Status: GOOD ( 26.65 ) X-Spam-Score: -2.0 (--) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-2.0 points) pts rule name description ---- ---------------------- -------------------------------------------------- 0.0 FREEMAIL_FROM Sender email is commonly abused enduser mail provider (sebastian.hesselbarth[at]gmail.com) -0.0 SPF_PASS SPF: sender matches SPF record -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature Cc: Thomas Petazzoni , Andrew Lunn , Russell King , Jason Cooper , linux-doc@vger.kernel.org, devicetree-discuss@lists.ozlabs.org, Daniel Lezcano , linux-kernel@vger.kernel.org, Rob Herring , Gregory Clement , John Stultz , Rob Landley , Grant Likely , Thomas Gleixner , linux-arm-kernel@lists.infradead.org, Sebastian Hesselbarth X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.15 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 This patch add a DT enabled driver for timers found on Marvell Orion SoCs (Kirkwood, Dove, Orion5x, and Discovery Innovation). It installs a free- running clocksource on timer0 and a clockevent source on timer1. Corresponding device tree documentation is also added. Signed-off-by: Sebastian Hesselbarth Tested-by: Andrew Lunn --- Changelog: v3->v4: - export thread-safe access to TIMER_CTRL register to use with watchdog - remove IRQF_DISABLED and add .irq to clock event (Suggested by Daniel Lezcano) Notes: - This is only an update to clocksource driver, the remaining patches are not resent as they have not been changed. - I will not rework orion watchdog driver for this patch set. It is written Kirkwood/Orion5x specific although it will also work on Dove and it is messing with shared registers. It has done it before, so I consider it broken anyway. I (or somebody else) will take care of proper watchdog later. - An updated branch can be found on git://github.com/shesselba/linux-dove.git orion-irqchip-for-v3.11_v4 Cc: Grant Likely Cc: Rob Herring Cc: Rob Landley Cc: Thomas Gleixner Cc: John Stultz Cc: Russell King Cc: Jason Cooper Cc: Andrew Lunn Cc: Thomas Petazzoni Cc: Gregory Clement Cc: Daniel Lezcano Cc: devicetree-discuss@lists.ozlabs.org Cc: linux-doc@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org Cc: linux-kernel@vger.kernel.org --- .../bindings/timer/marvell,orion-timer.txt | 17 +++ drivers/clocksource/Kconfig | 5 + drivers/clocksource/Makefile | 1 + drivers/clocksource/time-orion.c | 150 ++++++++++++++++++++ 4 files changed, 173 insertions(+), 0 deletions(-) create mode 100644 Documentation/devicetree/bindings/timer/marvell,orion-timer.txt create mode 100644 drivers/clocksource/time-orion.c diff --git a/Documentation/devicetree/bindings/timer/marvell,orion-timer.txt b/Documentation/devicetree/bindings/timer/marvell,orion-timer.txt new file mode 100644 index 0000000..62bb826 --- /dev/null +++ b/Documentation/devicetree/bindings/timer/marvell,orion-timer.txt @@ -0,0 +1,17 @@ +Marvell Orion SoC timer + +Required properties: +- compatible: shall be "marvell,orion-timer" +- reg: base address of the timer register starting with TIMERS CONTROL register +- interrupt-parent: phandle of the bridge interrupt controller +- interrupts: should contain the interrupts for Timer0 and Timer1 +- clocks: phandle of timer reference clock (tclk) + +Example: + timer: timer { + compatible = "marvell,orion-timer"; + reg = <0x20300 0x20>; + interrupt-parent = <&bridge_intc>; + interrupts = <1>, <2>; + clocks = <&core_clk 0>; + }; diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index f151c6c..2404869 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -25,6 +25,11 @@ config DW_APB_TIMER_OF config ARMADA_370_XP_TIMER bool +config ORION_TIMER + select CLKSRC_OF + select CLKSRC_MMIO + bool + config SUN4I_TIMER bool diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 8d979c7..d1e8d68 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_DW_APB_TIMER_OF) += dw_apb_timer_of.o obj-$(CONFIG_CLKSRC_NOMADIK_MTU) += nomadik-mtu.o obj-$(CONFIG_CLKSRC_DBX500_PRCMU) += clksrc-dbx500-prcmu.o obj-$(CONFIG_ARMADA_370_XP_TIMER) += time-armada-370-xp.o +obj-$(CONFIG_ORION_TIMER) += time-orion.o obj-$(CONFIG_ARCH_BCM2835) += bcm2835_timer.o obj-$(CONFIG_ARCH_MARCO) += timer-marco.o obj-$(CONFIG_ARCH_MXS) += mxs_timer.o diff --git a/drivers/clocksource/time-orion.c b/drivers/clocksource/time-orion.c new file mode 100644 index 0000000..ad7df17 --- /dev/null +++ b/drivers/clocksource/time-orion.c @@ -0,0 +1,150 @@ +/* + * Marvell Orion SoC timer handling. + * + * Sebastian Hesselbarth + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + * + * Timer 0 is used as free-running clocksource, while timer 1 is + * used as clock_event_device. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TIMER_CTRL 0x00 +#define TIMER0_EN BIT(0) +#define TIMER0_RELOAD_EN BIT(1) +#define TIMER1_EN BIT(2) +#define TIMER1_RELOAD_EN BIT(3) +#define TIMER0_RELOAD 0x10 +#define TIMER0_VAL 0x14 +#define TIMER1_RELOAD 0x18 +#define TIMER1_VAL 0x1c + +#define ORION_ONESHOT_MIN 1 +#define ORION_ONESHOT_MAX 0xfffffffe + +static void __iomem *timer_base; +static DEFINE_SPINLOCK(timer_ctrl_lock); + +/* + * Thread-safe access to TIMER_CTRL register + * (shared with watchdog timer) + */ +void orion_timer_ctrl_clrset(u32 clr, u32 set) +{ + spin_lock(&timer_ctrl_lock); + writel((readl(timer_base + TIMER_CTRL) & ~clr) | set, + timer_base + TIMER_CTRL); + spin_unlock(&timer_ctrl_lock); +} +EXPORT_SYMBOL(orion_timer_ctrl_clrset); + +/* + * Free-running clocksource handling. + */ +static u32 notrace orion_read_sched_clock(void) +{ + return ~readl(timer_base + TIMER0_VAL); +} + +/* + * Clockevent handling. + */ +static u32 ticks_per_jiffy; + +static int orion_clkevt_next_event(unsigned long delta, + struct clock_event_device *dev) +{ + /* setup and enable one-shot timer */ + writel(delta, timer_base + TIMER1_VAL); + orion_timer_ctrl_clrset(TIMER1_RELOAD_EN, TIMER1_EN); + + return 0; +} + +static void orion_clkevt_mode(enum clock_event_mode mode, + struct clock_event_device *dev) +{ + if (mode == CLOCK_EVT_MODE_PERIODIC) { + /* setup and enable periodic timer at 1/HZ intervals */ + writel(ticks_per_jiffy - 1, timer_base + TIMER1_RELOAD); + writel(ticks_per_jiffy - 1, timer_base + TIMER1_VAL); + orion_timer_ctrl_clrset(0, TIMER1_RELOAD_EN | TIMER1_EN); + } else { + /* disable timer */ + orion_timer_ctrl_clrset(TIMER1_RELOAD_EN | TIMER1_EN, 0); + } +} + +static struct clock_event_device orion_clkevt = { + .name = "orion_event", + .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC, + .shift = 32, + .rating = 300, + .set_next_event = orion_clkevt_next_event, + .set_mode = orion_clkevt_mode, +}; + +static irqreturn_t orion_clkevt_irq_handler(int irq, void *dev_id) +{ + orion_clkevt.event_handler(&orion_clkevt); + return IRQ_HANDLED; +} + +static struct irqaction orion_clkevt_irq = { + .name = "orion_event", + .flags = IRQF_TIMER, + .handler = orion_clkevt_irq_handler, +}; + +static void __init orion_timer_init(struct device_node *np) +{ + struct clk *clk; + int irq; + + /* timer registers are shared with watchdog timer */ + timer_base = of_iomap(np, 0); + if (!timer_base) + panic("%s: unable to map resource\n", np->name); + + clk = of_clk_get(np, 0); + if (IS_ERR(clk)) + panic("%s: unable to get clk\n", np->name); + clk_prepare_enable(clk); + + /* we are only interested in timer1 irq */ + irq = irq_of_parse_and_map(np, 1); + if (irq <= 0) + panic("%s: unable to parse timer1 irq\n", np->name); + + /* setup timer0 as free-running clocksource */ + writel(~0, timer_base + TIMER0_VAL); + writel(~0, timer_base + TIMER0_RELOAD); + orion_timer_ctrl_clrset(0, TIMER0_RELOAD_EN | TIMER0_EN); + clocksource_mmio_init(timer_base + TIMER0_VAL, "orion_clocksource", + clk_get_rate(clk), 300, 32, + clocksource_mmio_readl_down); + setup_sched_clock(orion_read_sched_clock, 32, clk_get_rate(clk)); + + /* setup timer1 as clockevent timer */ + if (setup_irq(irq, &orion_clkevt_irq)) + panic("%s: unable to setup irq\n", np->name); + + ticks_per_jiffy = (clk_get_rate(clk) + HZ/2) / HZ; + orion_clkevt.cpumask = cpumask_of(0); + orion_clkevt.irq = irq; + clockevents_config_and_register(&orion_clkevt, clk_get_rate(clk), + ORION_ONESHOT_MIN, ORION_ONESHOT_MAX); +} +CLOCKSOURCE_OF_DECLARE(orion_timer, "marvell,orion-timer", orion_timer_init);