Received: by 2002:ac0:a581:0:0:0:0:0 with SMTP id m1-v6csp3028319imm; Sun, 1 Jul 2018 10:36:27 -0700 (PDT) X-Google-Smtp-Source: ADUXVKLolEJgkg5K2BLkf37U7MI5zB8JiWYWCM61MopWJ7wqKY41FhFh9zwftkahw5kqa15NdPY5 X-Received: by 2002:a17:902:205:: with SMTP id 5-v6mr22535020plc.301.1530466587199; Sun, 01 Jul 2018 10:36:27 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1530466587; cv=none; d=google.com; s=arc-20160816; b=Ny8Wmo5FT6AMgcd3JH3PQCu96D1YeMnbuin2gV0YUl0Mibl0hcLjTCyDkSbClV8YGZ HGLYTJiXWVi0fmoNTLssMqo8XeiE/YQf0qx84rrRN+FigVzBuHzSSemCQt2FZDcRE9cd 16XB6XBzXw3lfvMm1mLyuV1631b8G/2ufoYK52zwqhjpXlH/78Di85/7Tp/ex98pM0gK lvDbpyKAP2gRjIMQu11ynE1rE6isU8SRHzprt7YM65XXIdH8uCpDe2QImUy+2PeaVmVE jN6r4gXjT4wEDsGOjeJ7n1p2UzQuvmrC06YwIWukvXMozMGn6n8t73g5OCI5iLOqL0um hBEQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:references :in-reply-to:message-id:date:subject:cc:to:from :arc-authentication-results; bh=t0oG/byzafX38Buiq722NMQx8/fyiRWxTgX6s/1ODg8=; b=Bt0kGF/hMFffosMjCFGWys4lmu/Hunty1Fgl5C6zsKb6fTUxZAsroxL5DdBSfp+qbo OEnqVv6TOTsFtsSIs1o4akY7Nsb0PTj4/fsh1kG2gqBEcAKGlU8kM309Oz9dbBzUXQP7 zq+Cst7rZ7zN0BGaWwlc5Qdm6MekNmzVVjTYpHY/YWDOd28ctMF/1yuQWYR4haN0pwnf frmOv+AGZfKKQeTtt7i57dTNk9m8d+n1z106nxZHB19mQgvidndm0aFadB6fGb7NEZ3o v1OINO6yx6ZXtqPsSp2Yna2qnwGwwyAKSZRjXzm+nip8pYajZOe198pwv2uQcheGIsSH jRvA== ARC-Authentication-Results: i=1; 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 Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id t1-v6si13647450plo.241.2018.07.01.10.36.12; Sun, 01 Jul 2018 10:36:27 -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 S934302AbeGARfC (ORCPT + 99 others); Sun, 1 Jul 2018 13:35:02 -0400 Received: from smtp2200-217.mail.aliyun.com ([121.197.200.217]:48468 "EHLO smtp2200-217.mail.aliyun.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S965963AbeGARbz (ORCPT ); Sun, 1 Jul 2018 13:31:55 -0400 X-Alimail-AntiSpam: AC=CONTINUE;BC=0.07441621|-1;CH=green;FP=0|0|0|0|0|-1|-1|-1;HT=e01e01534;MF=ren_guo@c-sky.com;NM=1;PH=DS;RN=12;RT=12;SR=0;TI=SMTPD_---.CKwmkwP_1530466300; Received: from localhost(mailfrom:ren_guo@c-sky.com fp:SMTPD_---.CKwmkwP_1530466300) by smtp.aliyun-inc.com(10.147.43.95); Mon, 02 Jul 2018 01:31:40 +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:30:21 +0800 Message-Id: X-Mailer: git-send-email 2.7.4 In-Reply-To: References: In-Reply-To: References: Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 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