From patchwork Thu Sep 22 13:46:48 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Linus Walleij X-Patchwork-Id: 4266 Return-Path: X-Original-To: patchwork@peony.canonical.com Delivered-To: patchwork@peony.canonical.com Received: from fiordland.canonical.com (fiordland.canonical.com [91.189.94.145]) by peony.canonical.com (Postfix) with ESMTP id BE60023EFA for ; Thu, 22 Sep 2011 13:46:58 +0000 (UTC) Received: from mail-fx0-f52.google.com (mail-fx0-f52.google.com [209.85.161.52]) by fiordland.canonical.com (Postfix) with ESMTP id ACB98A18215 for ; Thu, 22 Sep 2011 13:46:58 +0000 (UTC) Received: by mail-fx0-f52.google.com with SMTP id 23so3864669fxe.11 for ; Thu, 22 Sep 2011 06:46:58 -0700 (PDT) Received: by 10.223.33.19 with SMTP id f19mr3008112fad.122.1316699218468; Thu, 22 Sep 2011 06:46:58 -0700 (PDT) X-Forwarded-To: linaro-patchwork@canonical.com X-Forwarded-For: patch@linaro.org linaro-patchwork@canonical.com Delivered-To: patches@linaro.org Received: by 10.152.18.198 with SMTP id y6cs169004lad; Thu, 22 Sep 2011 06:46:58 -0700 (PDT) Received: by 10.14.4.203 with SMTP id 51mr769481eej.225.1316699217949; Thu, 22 Sep 2011 06:46:57 -0700 (PDT) Received: from eu1sys200aog115.obsmtp.com (eu1sys200aog115.obsmtp.com. [207.126.144.139]) by mx.google.com with SMTP id x12si2549103eem.162.2011.09.22.06.46.53 (version=TLSv1/SSLv3 cipher=OTHER); Thu, 22 Sep 2011 06:46:57 -0700 (PDT) Received-SPF: neutral (google.com: 207.126.144.139 is neither permitted nor denied by best guess record for domain of linus.walleij@stericsson.com) client-ip=207.126.144.139; Authentication-Results: mx.google.com; spf=neutral (google.com: 207.126.144.139 is neither permitted nor denied by best guess record for domain of linus.walleij@stericsson.com) smtp.mail=linus.walleij@stericsson.com Received: from beta.dmz-us.st.com ([167.4.1.35]) (using TLSv1) by eu1sys200aob115.postini.com ([207.126.147.11]) with SMTP ID DSNKTns8Tbo+ZzRvwvG2ZxFc3EeBrzQgNz7a@postini.com; Thu, 22 Sep 2011 13:46:57 UTC Received: from zeta.dmz-us.st.com (ns4.st.com [167.4.16.71]) by beta.dmz-us.st.com (STMicroelectronics) with ESMTP id F0A6141; Thu, 22 Sep 2011 13:46:51 +0000 (GMT) Received: from relay1.stm.gmessaging.net (unknown [10.230.100.17]) by zeta.dmz-us.st.com (STMicroelectronics) with ESMTP id 5F7FE61; Thu, 22 Sep 2011 13:46:51 +0000 (GMT) Received: from exdcvycastm004.EQ1STM.local (alteon-source-exch [10.230.100.61]) (using TLSv1 with cipher RC4-MD5 (128/128 bits)) (Client CN "exdcvycastm004", Issuer "exdcvycastm004" (not verified)) by relay1.stm.gmessaging.net (Postfix) with ESMTPS id B501C24C2F3; Thu, 22 Sep 2011 15:46:43 +0200 (CEST) Received: from localhost.localdomain (10.230.100.153) by smtp.stericsson.com (10.230.100.2) with Microsoft SMTP Server (TLS) id 8.3.83.0; Thu, 22 Sep 2011 15:46:50 +0200 From: Linus Walleij To: Cc: Lee Jones , Jonas Aaberg , Thomas Gleixner , Linus Walleij Subject: [PATCH 5/7] ARM: plat-nomadik: timer: Add support for periodic timers Date: Thu, 22 Sep 2011 15:46:48 +0200 Message-ID: <1316699208-21392-1-git-send-email-linus.walleij@stericsson.com> X-Mailer: git-send-email 1.7.3.2 MIME-Version: 1.0 From: Jonas Aaberg This adds support for a periodic mode in the MTU (Nomadik) timer clockevent driver. It also include changes needed for deeper powerstates where MTU block gets powered off. Cc: Thomas Gleixner Signed-off-by: Jonas Aaberg Signed-off-by: Linus Walleij --- arch/arm/plat-nomadik/timer.c | 88 ++++++++++++++++++++++++++++------------- 1 files changed, 60 insertions(+), 28 deletions(-) diff --git a/arch/arm/plat-nomadik/timer.c b/arch/arm/plat-nomadik/timer.c index bd638c5..a04b521 100644 --- a/arch/arm/plat-nomadik/timer.c +++ b/arch/arm/plat-nomadik/timer.c @@ -23,7 +23,12 @@ #include +static bool clkevt_periodic; +static u32 clk_prescale; +static u32 nmdk_cycle; /* write-once */ + void __iomem *mtu_base; /* Assigned by machine code */ + #ifdef CONFIG_NOMADIK_MTU_SCHED_CLOCK /* * Override the global weak sched_clock symbol with this @@ -49,31 +54,55 @@ static void notrace nomadik_update_sched_clock(void) update_sched_clock(&cd, cyc, (u32)~0); } #endif + /* Clockevent device: use one-shot mode */ +static int nmdk_clkevt_next(unsigned long evt, struct clock_event_device *ev) +{ + writel(1 << 1, mtu_base + MTU_IMSC); + writel(evt, mtu_base + MTU_LR(1)); + /* Load highest value, enable device, enable interrupts */ + writel(MTU_CRn_ONESHOT | clk_prescale | + MTU_CRn_32BITS | MTU_CRn_ENA, + mtu_base + MTU_CR(1)); + + return 0; +} + +static void nmdk_clkevt_reset(void) +{ + if (clkevt_periodic) { + + /* Timer: configure load and background-load, and fire it up */ + writel(nmdk_cycle, mtu_base + MTU_LR(1)); + writel(nmdk_cycle, mtu_base + MTU_BGLR(1)); + + writel(MTU_CRn_PERIODIC | clk_prescale | + MTU_CRn_32BITS | MTU_CRn_ENA, + mtu_base + MTU_CR(1)); + writel(1 << 1, mtu_base + MTU_IMSC); + } else { + /* Generate an interrupt to start the clockevent again */ + (void) nmdk_clkevt_next(nmdk_cycle, NULL); + } +} + static void nmdk_clkevt_mode(enum clock_event_mode mode, struct clock_event_device *dev) { - u32 cr; switch (mode) { case CLOCK_EVT_MODE_PERIODIC: - pr_err("%s: periodic mode not supported\n", __func__); + clkevt_periodic = true; + nmdk_clkevt_reset(); break; case CLOCK_EVT_MODE_ONESHOT: - /* Load highest value, enable device, enable interrupts */ - cr = readl(mtu_base + MTU_CR(1)); - writel(0, mtu_base + MTU_LR(1)); - writel(cr | MTU_CRn_ENA, mtu_base + MTU_CR(1)); - writel(1 << 1, mtu_base + MTU_IMSC); + clkevt_periodic = false; break; case CLOCK_EVT_MODE_SHUTDOWN: case CLOCK_EVT_MODE_UNUSED: - /* disable irq */ writel(0, mtu_base + MTU_IMSC); /* disable timer */ - cr = readl(mtu_base + MTU_CR(1)); - cr &= ~MTU_CRn_ENA; - writel(cr, mtu_base + MTU_CR(1)); + writel(0, mtu_base + MTU_CR(1)); /* load some high default value */ writel(0xffffffff, mtu_base + MTU_LR(1)); break; @@ -82,16 +111,9 @@ static void nmdk_clkevt_mode(enum clock_event_mode mode, } } -static int nmdk_clkevt_next(unsigned long evt, struct clock_event_device *ev) -{ - /* writing the value has immediate effect */ - writel(evt, mtu_base + MTU_LR(1)); - return 0; -} - static struct clock_event_device nmdk_clkevt = { .name = "mtu_1", - .features = CLOCK_EVT_FEAT_ONESHOT, + .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC, .rating = 200, .set_mode = nmdk_clkevt_mode, .set_next_event = nmdk_clkevt_next, @@ -116,11 +138,23 @@ static struct irqaction nmdk_timer_irq = { .dev_id = &nmdk_clkevt, }; +static void nmdk_clksrc_reset(void) +{ + /* Disable */ + writel(0, mtu_base + MTU_CR(0)); + + /* ClockSource: configure load and background-load, and fire it up */ + writel(nmdk_cycle, mtu_base + MTU_LR(0)); + writel(nmdk_cycle, mtu_base + MTU_BGLR(0)); + + writel(clk_prescale | MTU_CRn_32BITS | MTU_CRn_ENA, + mtu_base + MTU_CR(0)); +} + void __init nmdk_timer_init(void) { unsigned long rate; struct clk *clk0; - u32 cr = MTU_CRn_32BITS; clk0 = clk_get_sys("mtu0", NULL); BUG_ON(IS_ERR(clk0)); @@ -138,16 +172,16 @@ void __init nmdk_timer_init(void) rate = clk_get_rate(clk0); if (rate > 32000000) { rate /= 16; - cr |= MTU_CRn_PRESCALE_16; + clk_prescale = MTU_CRn_PRESCALE_16; } else { - cr |= MTU_CRn_PRESCALE_1; + clk_prescale = MTU_CRn_PRESCALE_1; } + nmdk_cycle = (rate + HZ/2) / HZ; + + /* Timer 0 is the free running clocksource */ - writel(cr, mtu_base + MTU_CR(0)); - writel(0, mtu_base + MTU_LR(0)); - writel(0, mtu_base + MTU_BGLR(0)); - writel(cr | MTU_CRn_ENA, mtu_base + MTU_CR(0)); + nmdk_clksrc_reset(); if (clocksource_mmio_init(mtu_base + MTU_VAL(0), "mtu_0", rate, 200, 32, clocksource_mmio_readl_down)) @@ -160,8 +194,6 @@ void __init nmdk_timer_init(void) clockevents_calc_mult_shift(&nmdk_clkevt, rate, MTU_MIN_RANGE); - writel(cr | MTU_CRn_ONESHOT, mtu_base + MTU_CR(1)); /* off, currently */ - nmdk_clkevt.max_delta_ns = clockevent_delta2ns(0xffffffff, &nmdk_clkevt); nmdk_clkevt.min_delta_ns =