From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.8 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, MAILING_LIST_MULTI,SPF_PASS,UNPARSEABLE_RELAY,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 7C055C6778C for ; Sun, 1 Jul 2018 17:35:20 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 3929D2548A for ; Sun, 1 Jul 2018 17:35:20 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 3929D2548A Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=c-sky.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1030965AbeGARfS (ORCPT ); Sun, 1 Jul 2018 13:35:18 -0400 Received: from smtp2200-217.mail.aliyun.com ([121.197.200.217]:57104 "EHLO smtp2200-217.mail.aliyun.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S965318AbeGARfM (ORCPT ); Sun, 1 Jul 2018 13:35:12 -0400 X-Alimail-AntiSpam: AC=CONTINUE;BC=0.07441621|-1;CH=green;FP=12445046842757616890|1|1|9|0|-1|-1|-1;HT=e01e04486;MF=ren_guo@c-sky.com;NM=1;PH=DS;RN=12;RT=12;SR=0;TI=SMTPD_---.CKwoIY6_1530466501; Received: from localhost(mailfrom:ren_guo@c-sky.com fp:SMTPD_---.CKwoIY6_1530466501) by smtp.aliyun-inc.com(10.147.41.231); Mon, 02 Jul 2018 01:35:01 +0800 From: Guo Ren To: linux-arch@vger.kernel.org, linux-kernel@vger.kernel.org, tglx@linutronix.de, daniel.lezcano@linaro.org, jason@lakedaemon.net, arnd@arndb.de Cc: c-sky_gcc_upstream@c-sky.com, gnu-csky@mentor.com, thomas.petazzoni@bootlin.com, wbx@uclibc-ng.org, ren_guo@c-sky.com, green.hu@gmail.com Subject: [PATCH V2 18/19] clocksource: add C-SKY clocksource drivers Date: Mon, 2 Jul 2018 01:34:58 +0800 Message-Id: X-Mailer: git-send-email 2.7.4 In-Reply-To: References: Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Message-ID: <20180701173458.wpm9hQCWnHtMwvAvMxhOwyfNEuMdYxbm_7nQEoidKRY@z> Signed-off-by: Guo Ren --- drivers/clocksource/Makefile | 1 + drivers/clocksource/timer-csky-v1.c | 169 +++++++++++++++++++++++++++++++ drivers/clocksource/timer-nationalchip.c | 165 ++++++++++++++++++++++++++++++ 3 files changed, 335 insertions(+) create mode 100644 drivers/clocksource/timer-csky-v1.c create mode 100644 drivers/clocksource/timer-nationalchip.c diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index d6dec44..bbc567b 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -76,3 +76,4 @@ obj-$(CONFIG_H8300_TMR16) += h8300_timer16.o obj-$(CONFIG_H8300_TPU) += h8300_tpu.o obj-$(CONFIG_CLKSRC_ST_LPC) += clksrc_st_lpc.o obj-$(CONFIG_X86_NUMACHIP) += numachip.o +obj-$(CONFIG_CSKY) += timer-csky-v1.o timer-nationalchip.o diff --git a/drivers/clocksource/timer-csky-v1.c b/drivers/clocksource/timer-csky-v1.c new file mode 100644 index 0000000..f3a822a --- /dev/null +++ b/drivers/clocksource/timer-csky-v1.c @@ -0,0 +1,169 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2018 Hangzhou NationalChip Science & Technology Co.,Ltd. +#include +#include +#include +#include +#include + +#include "timer-of.h" + +#define PTIM_CTLR "cr<0, 14>" +#define PTIM_TSR "cr<1, 14>" +#define PTIM_CCVR_HI "cr<2, 14>" +#define PTIM_CCVR_LO "cr<3, 14>" +#define PTIM_LVR "cr<6, 14>" + +#define BITS_CSKY_TIMER 56 + +DECLARE_PER_CPU(struct timer_of, csky_to); + +static int csky_timer_irq; +static int csky_timer_rate; + +static inline u64 get_ccvr(void) +{ + u32 lo, hi, t; + + do { + hi = mfcr(PTIM_CCVR_HI); + lo = mfcr(PTIM_CCVR_LO); + t = mfcr(PTIM_CCVR_HI); + } while(t != hi); + + return ((u64)hi << 32) | lo; +} + +static irqreturn_t timer_interrupt(int irq, void *dev) +{ + struct timer_of *to = this_cpu_ptr(&csky_to); + + mtcr(PTIM_TSR, 0); + + to->clkevt.event_handler(&to->clkevt); + + return IRQ_HANDLED; +} + +static int csky_timer_set_next_event(unsigned long delta, struct clock_event_device *ce) +{ + mtcr(PTIM_LVR, delta); + + return 0; +} + +static int csky_timer_shutdown(struct clock_event_device *ce) +{ + mtcr(PTIM_CTLR, 0); + + return 0; +} + +static int csky_timer_oneshot(struct clock_event_device *ce) +{ + mtcr(PTIM_CTLR, 1); + + return 0; +} + +static int csky_timer_oneshot_stopped(struct clock_event_device *ce) +{ + mtcr(PTIM_CTLR, 0); + + return 0; +} + +DEFINE_PER_CPU(struct timer_of, csky_to) = { + .flags = TIMER_OF_CLOCK | TIMER_OF_IRQ, + + .clkevt = { + .name = "C-SKY SMP Timer V1", + .rating = 300, + .features = CLOCK_EVT_FEAT_PERCPU | CLOCK_EVT_FEAT_ONESHOT, + .set_state_shutdown = csky_timer_shutdown, + .set_state_oneshot = csky_timer_oneshot, + .set_state_oneshot_stopped = csky_timer_oneshot_stopped, + .set_next_event = csky_timer_set_next_event, + }, + + .of_irq = { + .handler = timer_interrupt, + .flags = IRQF_TIMER, + .percpu = 1, + }, +}; + +/*** clock event for percpu ***/ +static int csky_timer_starting_cpu(unsigned int cpu) +{ + struct timer_of *to = this_cpu_ptr(&csky_to); + + to->clkevt.cpumask = cpumask_of(smp_processor_id()); + + clockevents_config_and_register(&to->clkevt, csky_timer_rate, 0, ULONG_MAX); + + enable_percpu_irq(csky_timer_irq, 0); + + return 0; +} + +static int csky_timer_dying_cpu(unsigned int cpu) +{ + disable_percpu_irq(csky_timer_irq); + + return 0; +} + +/*** clock source ***/ +static u64 sched_clock_read(void) +{ + return get_ccvr(); +} + +static u64 clksrc_read(struct clocksource *c) +{ + return get_ccvr(); +} + +struct clocksource csky_clocksource = { + .name = "csky_timer_v1_clksrc", + .rating = 400, + .mask = CLOCKSOURCE_MASK(BITS_CSKY_TIMER), + .flags = CLOCK_SOURCE_IS_CONTINUOUS, + .read = clksrc_read, +}; + +static void csky_clksrc_init(void) +{ + clocksource_register_hz(&csky_clocksource, csky_timer_rate); + + sched_clock_register(sched_clock_read, BITS_CSKY_TIMER, csky_timer_rate); +} + +static int __init csky_timer_v1_init(struct device_node *np) +{ + int ret; + struct timer_of *to = this_cpu_ptr(&csky_to); + + ret = timer_of_init(np, to); + if (ret) + return ret; + + csky_timer_irq = to->of_irq.irq; + csky_timer_rate = timer_of_rate(to); + + ret = cpuhp_setup_state(CPUHP_AP_DUMMY_TIMER_STARTING, + "clockevents/csky/timer:starting", + csky_timer_starting_cpu, + csky_timer_dying_cpu); + if (ret) { + pr_err("%s: Failed to cpuhp_setup_state.\n", __func__); + return ret; + } + + csky_clksrc_init(); + + return ret; +} +TIMER_OF_DECLARE(csky_timer_v1, "csky,timer-v1", csky_timer_v1_init); + diff --git a/drivers/clocksource/timer-nationalchip.c b/drivers/clocksource/timer-nationalchip.c new file mode 100644 index 0000000..8f4e1e5 --- /dev/null +++ b/drivers/clocksource/timer-nationalchip.c @@ -0,0 +1,165 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2018 Hangzhou NationalChip Science & Technology Co.,Ltd. +#include +#include +#include + +#include "timer-of.h" + +#define TIMER_NAME "nc_timer" +#define TIMER_FREQ 1000000 +#define CLKSRC_OFFSET 0x40 + +#define TIMER_STATUS 0x00 +#define TIMER_VALUE 0x04 +#define TIMER_CONTRL 0x10 +#define TIMER_CONFIG 0x20 +#define TIMER_DIV 0x24 +#define TIMER_INI 0x28 + +#define STATUS_clr BIT(0) + +#define CONTRL_rst BIT(0) +#define CONTRL_start BIT(1) + +#define CONFIG_en BIT(0) +#define CONFIG_irq_en BIT(1) + +static irqreturn_t timer_interrupt(int irq, void *dev) +{ + struct clock_event_device *ce = (struct clock_event_device *) dev; + void __iomem *base = timer_of_base(to_timer_of(ce)); + + writel_relaxed(STATUS_clr, base + TIMER_STATUS); + + ce->event_handler(ce); + + return IRQ_HANDLED; +} + +static int nc_timer_set_periodic(struct clock_event_device *ce) +{ + void __iomem *base = timer_of_base(to_timer_of(ce)); + + /* reset */ + writel_relaxed(CONTRL_rst, base + TIMER_CONTRL); + + /* config the timeout value */ + writel_relaxed(ULONG_MAX - timer_of_period(to_timer_of(ce)), + base + TIMER_INI); + + /* enable with irq and start */ + writel_relaxed(CONFIG_en|CONFIG_irq_en, base + TIMER_CONFIG); + writel_relaxed(CONTRL_start, base + TIMER_CONTRL); + + return 0; +} + +static int nc_timer_set_next_event(unsigned long delta, struct clock_event_device *ce) +{ + void __iomem *base = timer_of_base(to_timer_of(ce)); + + /* use reset to pause timer */ + writel_relaxed(CONTRL_rst, base + TIMER_CONTRL); + + /* config next timeout value */ + writel_relaxed(ULONG_MAX - delta, base + TIMER_INI); + writel_relaxed(CONTRL_start, base + TIMER_CONTRL); + + return 0; +} + +static int nc_timer_shutdown(struct clock_event_device *ce) +{ + void __iomem *base = timer_of_base(to_timer_of(ce)); + + writel_relaxed(0, base + TIMER_CONTRL); + writel_relaxed(0, base + TIMER_CONFIG); + + return 0; +} + +static struct timer_of to = { + .flags = TIMER_OF_IRQ | TIMER_OF_BASE | TIMER_OF_CLOCK, + + .clkevt = { + .name = TIMER_NAME, + .rating = 300, + .features = CLOCK_EVT_FEAT_DYNIRQ | CLOCK_EVT_FEAT_PERIODIC | + CLOCK_EVT_FEAT_ONESHOT, + .set_state_shutdown = nc_timer_shutdown, + .set_state_periodic = nc_timer_set_periodic, + .set_next_event = nc_timer_set_next_event, + .cpumask = cpu_possible_mask, + }, + + .of_irq = { + .handler = timer_interrupt, + .flags = IRQF_TIMER | IRQF_IRQPOLL, + }, +}; + +static u64 notrace nc_sched_clock_read(void) +{ + void __iomem *base; + + base = timer_of_base(&to) + CLKSRC_OFFSET; + + return (u64) readl_relaxed(base + TIMER_VALUE); +} + +static void nc_timer_set_div(void __iomem *base) +{ + unsigned int div; + + div = timer_of_rate(&to)/TIMER_FREQ - 1; + + writel_relaxed(div, base + TIMER_DIV); +} + +static void nc_clkevt_init(void __iomem *base) +{ + /* reset */ + writel_relaxed(CONTRL_rst, base + TIMER_CONTRL); + + /* reset config */ + writel_relaxed(0, base + TIMER_CONFIG); + + nc_timer_set_div(base); + + clockevents_config_and_register(&to.clkevt, TIMER_FREQ, 1, ULONG_MAX); +} + +static void nc_clksrc_init(void __iomem *base) +{ + writel_relaxed(CONTRL_rst, base + TIMER_CONTRL); + + writel_relaxed(CONFIG_en, base + TIMER_CONFIG); + + nc_timer_set_div(base); + + writel_relaxed(0, base + TIMER_INI); + writel_relaxed(CONTRL_start, base + TIMER_CONTRL); + + clocksource_mmio_init(base + TIMER_VALUE, "nationalchip", TIMER_FREQ, 200, 32, + clocksource_mmio_readl_up); + + sched_clock_register(nc_sched_clock_read, 32, TIMER_FREQ); +} + +static int __init nc_timer_init(struct device_node *np) +{ + int ret; + + ret = timer_of_init(np, &to); + if (ret) + return ret; + + nc_clkevt_init(timer_of_base(&to)); + + nc_clksrc_init(timer_of_base(&to) + CLKSRC_OFFSET); + + return 0; +} +TIMER_OF_DECLARE(nc_timer, "nationalchip,timer-v1", nc_timer_init); + -- 2.7.4