From patchwork Sat May 28 09:33:53 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kefeng Wang X-Patchwork-Id: 68788 Delivered-To: patch@linaro.org Received: by 10.140.92.199 with SMTP id b65csp508590qge; Sat, 28 May 2016 02:36:05 -0700 (PDT) X-Received: by 10.98.79.199 with SMTP id f68mr29469387pfj.44.1464428165554; Sat, 28 May 2016 02:36:05 -0700 (PDT) Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id r82si20896001pfa.197.2016.05.28.02.36.05; Sat, 28 May 2016 02:36:05 -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; 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 Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753673AbcE1Jfo (ORCPT + 30 others); Sat, 28 May 2016 05:35:44 -0400 Received: from szxga03-in.huawei.com ([119.145.14.66]:37433 "EHLO szxga03-in.huawei.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751972AbcE1Jf3 (ORCPT ); Sat, 28 May 2016 05:35:29 -0400 Received: from 172.24.1.47 (EHLO SZXEML423-HUB.china.huawei.com) ([172.24.1.47]) by szxrg03-dlp.huawei.com (MOS 4.4.3-GA FastPath queued) with ESMTP id CCH96856; Sat, 28 May 2016 17:35:14 +0800 (CST) Received: from linux-ibm.site (10.175.102.37) by SZXEML423-HUB.china.huawei.com (10.82.67.154) with Microsoft SMTP Server id 14.3.235.1; Sat, 28 May 2016 17:35:02 +0800 From: Kefeng Wang To: Thomas Gleixner , Daniel Lezcano , Rob Herring CC: , , , , Sudeep Holla , Arnd Bergmann , Subject: [PATCH 4/4] clocksource: sp804: support 64bit mode for hisilicon timer64 Date: Sat, 28 May 2016 17:33:53 +0800 Message-ID: <1464428033-52106-5-git-send-email-wangkefeng.wang@huawei.com> X-Mailer: git-send-email 1.7.12.4 In-Reply-To: <1464428033-52106-1-git-send-email-wangkefeng.wang@huawei.com> References: <1464428033-52106-1-git-send-email-wangkefeng.wang@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.175.102.37] X-CFilter-Loop: Reflected X-Mirapoint-Virus-RAPID-Raw: score=unknown(0), refid=str=0001.0A020205.57496653.0041, ss=1, re=0.000, recu=0.000, reip=0.000, cl=1, cld=1, fgs=0, ip=0.0.0.0, so=2013-05-26 15:14:31, dmn=2013-03-21 17:37:32 X-Mirapoint-Loop-Id: b24d3d31d0774d77255560d14775fbe0 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org There is a kind of 64bit mode timer in hisilicon soc(like Hip05, Hip06 and some arm32 soc), it is very similar with ARM sp804 Dual Timers, but TimerX LOAD/Value/BGLoad are 64bit(two 32bit regs), and reg offset is different. Signed-off-by: Kefeng Wang --- .../devicetree/bindings/timer/arm,sp804.txt | 1 + drivers/clocksource/timer-sp.h | 1 + drivers/clocksource/timer-sp804.c | 76 ++++++++++++++++++---- 3 files changed, 66 insertions(+), 12 deletions(-) -- 1.7.12.4 diff --git a/Documentation/devicetree/bindings/timer/arm,sp804.txt b/Documentation/devicetree/bindings/timer/arm,sp804.txt index 5cd8eee7..d8e8f8f 100644 --- a/Documentation/devicetree/bindings/timer/arm,sp804.txt +++ b/Documentation/devicetree/bindings/timer/arm,sp804.txt @@ -17,6 +17,7 @@ Optional properties: - arm,sp804-has-irq = <#>: In the case of only 1 timer irq line connected, this specifies if the irq connection is for timer 1 or timer 2. A value of 1 or 2 should be used. +- hisilicon,timer64: Support hisilicon 64bit mode timer. Example: diff --git a/drivers/clocksource/timer-sp.h b/drivers/clocksource/timer-sp.h index 050d885..adf82f4 100644 --- a/drivers/clocksource/timer-sp.h +++ b/drivers/clocksource/timer-sp.h @@ -16,6 +16,7 @@ #define TIMER_VALUE 0x04 /* ACVR ro */ #define TIMER_CTRL 0x08 /* ACVR rw */ #define TIMER_CTRL_ONESHOT (1 << 0) /* CVR */ +/* Used in hisilicon timer64, it means enabling 64bit mode */ #define TIMER_CTRL_32BIT (1 << 1) /* CVR */ #define TIMER_CTRL_DIV1 (0 << 2) /* ACVR */ #define TIMER_CTRL_DIV16 (1 << 2) /* ACVR */ diff --git a/drivers/clocksource/timer-sp804.c b/drivers/clocksource/timer-sp804.c index 2ff8777..7f1d947 100644 --- a/drivers/clocksource/timer-sp804.c +++ b/drivers/clocksource/timer-sp804.c @@ -34,6 +34,16 @@ #include "timer-sp.h" +#define TIMER64_2_BASE 0x40 +#define TIMER64_LOAD_L 0x00 +#define TIMER64_LOAD_H 0x04 +#define TIMER64_VALUE_L 0x08 +#define TIMER64_VALUE_H 0x0C + +#define HISI_OFFSET 0x8 + +static int timer64_offset; + static long __init sp804_get_clock_rate(struct clk *clk, const char *name) { long rate; @@ -78,8 +88,8 @@ static inline void sp804_load_mode_set(void __iomem *base, unsigned long load, i unsigned long ctrl = TIMER_CTRL_32BIT | TIMER_CTRL_IE | mode | TIMER_CTRL_ENABLE; - writel(load, base + TIMER_LOAD); - writel(ctrl, base + TIMER_CTRL); + writel(load, base + TIMER_LOAD); /* equal TIMER64_LOAD_L when timer64*/ + writel(ctrl, base + TIMER_CTRL + timer64_offset); } static void __iomem *sched_clock_base; @@ -89,11 +99,37 @@ static u64 notrace sp804_read(void) return ~readl_relaxed(sched_clock_base + TIMER_VALUE); } +static u64 notrace hisi_timer64_read(void) +{ + u32 val_lo, val_hi, tmp_hi; + + do { + val_hi = readl_relaxed(sched_clock_base + TIMER64_VALUE_H); + val_lo = readl_relaxed(sched_clock_base + TIMER64_VALUE_L); + tmp_hi = readl_relaxed(sched_clock_base + TIMER64_VALUE_H); + } while (val_hi != tmp_hi); + + return ((u64) val_hi << 32) | val_lo; +} + void __init sp804_timer_disable(void __iomem *base) { - writel(0, base + TIMER_CTRL); + writel(0, base + TIMER_CTRL + timer64_offset); } +static cycle_t hisi_clocksource_read(struct clocksource *cs) +{ + return hisi_timer64_read(); +} + +static struct clocksource hisi_clocksource = { + .name = "hisilicon_timer64", + .rating = 200, + .read = hisi_clocksource_read, + .mask = CLOCKSOURCE_MASK(64), + .flags = CLOCK_SOURCE_IS_CONTINUOUS, +}; + void __init __sp804_clocksource_and_sched_clock_init(void __iomem *base, const char *name, struct clk *clk, @@ -106,15 +142,25 @@ void __init __sp804_clocksource_and_sched_clock_init(void __iomem *base, /* setup timer 0 as free-running clocksource */ sp804_timer_disable(base); - writel(0xffffffff, base + TIMER_VALUE); + writel(0xffffffff, base + TIMER_VALUE); /* equal TIMER64_LOAD_H when tiemr64*/ + if (timer64_offset) { + writel(0xffffffff, base + TIMER64_VALUE_L); + writel(0xffffffff, base + TIMER64_VALUE_H); + } sp804_load_mode_set(base, 0xffffffff, TIMER_CTRL_PERIODIC & ~TIMER_CTRL_IE); - clocksource_mmio_init(base + TIMER_VALUE, name, - rate, 200, 32, clocksource_mmio_readl_down); + if (timer64_offset) + clocksource_register_hz(&hisi_clocksource, rate); + else + clocksource_mmio_init(base + TIMER_VALUE, name, rate, 200, 32, + clocksource_mmio_readl_down); if (use_sched_clock) { sched_clock_base = base; - sched_clock_register(sp804_read, 32, rate); + if (timer64_offset) + sched_clock_register(hisi_timer64_read, 64, rate); + else + sched_clock_register(sp804_read, 32, rate); } } @@ -130,7 +176,7 @@ static irqreturn_t sp804_timer_interrupt(int irq, void *dev_id) struct clock_event_device *evt = dev_id; /* clear the interrupt */ - writel(1, clkevt_base + TIMER_INTCLR); + writel(1, clkevt_base + TIMER_INTCLR + timer64_offset); evt->event_handler(evt); @@ -139,7 +185,7 @@ static irqreturn_t sp804_timer_interrupt(int irq, void *dev_id) static inline void timer_shutdown(struct clock_event_device *evt) { - writel(0, clkevt_base + TIMER_CTRL); + writel(0, clkevt_base + TIMER_CTRL + timer64_offset); } static int sp804_shutdown(struct clock_event_device *evt) @@ -204,6 +250,7 @@ void __init __sp804_clockevents_init(void __iomem *base, unsigned int irq, struc static void __init sp804_of_init(struct device_node *np) { static bool initialized = false; + int timer_2_base = TIMER_2_BASE; void __iomem *base; int irq; u32 irq_num = 0; @@ -214,9 +261,14 @@ static void __init sp804_of_init(struct device_node *np) if (WARN_ON(!base)) return; + if (of_property_read_bool(np, "hisilicon,timer64")) { + timer64_offset = HISI_OFFSET; + timer_2_base = TIMER64_2_BASE; + } + /* Ensure timers are disabled */ sp804_timer_disable(base); - sp804_timer_disable(base + TIMER_2_BASE); + sp804_timer_disable(base + timer_2_base); if (initialized || !of_device_is_available(np)) goto err; @@ -242,11 +294,11 @@ static void __init sp804_of_init(struct device_node *np) of_property_read_u32(np, "arm,sp804-has-irq", &irq_num); if (irq_num == 2) { - __sp804_clockevents_init(base + TIMER_2_BASE, irq, clk2, name); + __sp804_clockevents_init(base + timer_2_base, irq, clk2, name); __sp804_clocksource_and_sched_clock_init(base, name, clk1, 1); } else { __sp804_clockevents_init(base, irq, clk1 , name); - __sp804_clocksource_and_sched_clock_init(base + TIMER_2_BASE, + __sp804_clocksource_and_sched_clock_init(base + timer_2_base, name, clk2, 1); } initialized = true;