From patchwork Mon Jan 8 13:28:47 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Lezcano X-Patchwork-Id: 123723 Delivered-To: patch@linaro.org Received: by 10.140.22.227 with SMTP id 90csp2731232qgn; Mon, 8 Jan 2018 05:33:16 -0800 (PST) X-Google-Smtp-Source: ACJfBovKyf0yMOHEx3TfKfJQa2wOKJN0puenn9BoSJ0Vh40SSqm5q2iKSimUI/PslfoBFoZdQ1iX X-Received: by 10.98.15.203 with SMTP id 72mr10781437pfp.104.1515418395924; Mon, 08 Jan 2018 05:33:15 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1515418395; cv=none; d=google.com; s=arc-20160816; b=e/vACr4sVJBB6UWdsrA5GeIhpSR7RMDWvzm/INbEW8Cw6GZMHesnwOgwlwvpzrMJfl VnuMRk761EdoZiiQOPC8a/04ZA6yP493+y8QxFCK9yH9Jn0S6ASWbBcOGres+kF/lmD/ pOloBN6GkRoKkvaz87wvGuQWqfHxkrOSuRXqWkLzL3ehZ8b4ArBBhzwG1udMArvoyXj9 As1pRIJogPuMkZdkZ3bJuL0Ww36doAfurEoqer7XnfDP7QweEuG3L0BA3bc7lVt3toZ6 1jRHu71yIn0wgMVLNJe3hUVcl2/IMxWyn5khRthP5MCazIqiHmBRY9eMOQwa8gk1BsNa GOGA== 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:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=KtKnQtNbgW+IKfNTkd60KftUovM7POKqMLM8kupjL9k=; b=eKllmVlxcltzITMWU3vNQ3tBAxDR/5pvjahKh5nIsue4oD4giIqkFnkgTICJ+t/C6l q7NIy15U4MQD31KlkB4L6/+gMcusdG5uxEOZ7nDg81Z7vP2shoZuMLk9HW6P1U5mPx2f 1Nbw+0dJJy3+kt0oLf37jz6Q1ST6/tw+clMyeGkr0yjc8O+RfhlJFQUYoHZBExzf19vB Zyy8IxUPWDPW2Z6cyRVE4UlNPD93mblmBd+6msqCPn5pSgtVgXrJfUYuA4OMXny9iJ6s PLx+RzAS1tRsZ1+bAecnlSShYYzvsw58yE3lZlEJRbEUZMfFInDIfrmTFMrGp7pYkvxL LBFg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=YZ3TCxA5; 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; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id h14si8740755pln.774.2018.01.08.05.33.15; Mon, 08 Jan 2018 05:33:15 -0800 (PST) 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; dkim=pass header.i=@linaro.org header.s=google header.b=YZ3TCxA5; 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; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933505AbeAHNdN (ORCPT + 28 others); Mon, 8 Jan 2018 08:33:13 -0500 Received: from mail-wm0-f67.google.com ([74.125.82.67]:38101 "EHLO mail-wm0-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S933307AbeAHN3i (ORCPT ); Mon, 8 Jan 2018 08:29:38 -0500 Received: by mail-wm0-f67.google.com with SMTP id 64so14208313wme.3 for ; Mon, 08 Jan 2018 05:29:37 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=KtKnQtNbgW+IKfNTkd60KftUovM7POKqMLM8kupjL9k=; b=YZ3TCxA5AlVk3uQSXpGriAWKhX3Qi8h5+ieZDOZcpxEI0/jLoIOeCT2ZhV6zf3uU1Y b3zOUiBGI6+CuHVfiwXmFOGK6acvwk5ylDV5j5VI2mwVrlt0sMmwdAikcKvs1oEDa8g6 dM3Vuh37jKkKELeb4VzXZFp3JrkcUw+L1glXc= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=KtKnQtNbgW+IKfNTkd60KftUovM7POKqMLM8kupjL9k=; b=t8qe7H4ez5MMzWQvL6I3Ay0vytUrwG9/XQ13LUollFazIWiiQYA7B6EvvmQLKR2tM4 T3E2MoOtW5a1iuuUwVzUBPVbqAAn3DRvuTVSx7quw9sicK1mUNuR0JcJ1UEzmoMWLEdk wVkbBw4OTBZyTw9u1mADEMDsd5cU2WqfjWVrX/7SUyLpGWZSJq+WQRm+DCtLA9SZHtfU rw9ilLBJmM+xcZn2dHiGSDi0eoXUR3UOAvp73kbnE/nPYMCFFrcsx6EpQdZizbNKrI5u Bov4JD6vev+HsuS4X3LqgNtZ6Qsedv8CoKvwxYkPymEd68OvXJxyQJDingbU7AxPFxGY k/3Q== X-Gm-Message-State: AKGB3mI245kSZJNY9lInpJo4RM/+r33BwwuVd+gvh2jX9Q1k8OBu6Skz 2xNPuKRwNTrV7QLdhf6czzQyqg== X-Received: by 10.28.59.69 with SMTP id i66mr10368158wma.3.1515418176931; Mon, 08 Jan 2018 05:29:36 -0800 (PST) Received: from mai.lan ([2001:41d0:fe90:b800:312a:53a5:1bef:6622]) by smtp.gmail.com with ESMTPSA id q196sm14354222wmb.22.2018.01.08.05.29.35 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 08 Jan 2018 05:29:36 -0800 (PST) From: Daniel Lezcano To: tglx@linutronix.de Cc: linux-kernel@vger.kernel.org, Baolin Wang , Philippe Ombredanne Subject: [PATCH 08/20] clocksource/drivers/spreadtrum: Add timer driver for Spreadtrum SC9860 platform Date: Mon, 8 Jan 2018 14:28:47 +0100 Message-Id: <1515418139-23276-8-git-send-email-daniel.lezcano@linaro.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1515418139-23276-1-git-send-email-daniel.lezcano@linaro.org> References: <1bbaef2e-4080-3f54-7db3-a8989acfd691@free.fr> <1515418139-23276-1-git-send-email-daniel.lezcano@linaro.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Baolin Wang The Spreadtrum SC9860 platform will use the architected timers as local clock events, but we also need a broadcast timer device to wakeup the cpus when the cpus are in sleep mode. The Spreadtrum timer can support 32bit or 64bit counter, as well as supporting period mode or one-shot mode. Signed-off-by: Baolin Wang Acked-by: Philippe Ombredanne Signed-off-by: Daniel Lezcano --- drivers/clocksource/Kconfig | 7 ++ drivers/clocksource/Makefile | 1 + drivers/clocksource/timer-sprd.c | 159 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 167 insertions(+) create mode 100644 drivers/clocksource/timer-sprd.c -- 2.7.4 diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index c729a88..9a6b087 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -441,6 +441,13 @@ config MTK_TIMER help Support for Mediatek timer driver. +config SPRD_TIMER + bool "Spreadtrum timer driver" if COMPILE_TEST + depends on HAS_IOMEM + select TIMER_OF + help + Enables the support for the Spreadtrum timer driver. + config SYS_SUPPORTS_SH_MTU2 bool diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 72711f1..d6dec44 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -54,6 +54,7 @@ obj-$(CONFIG_CLKSRC_TI_32K) += timer-ti-32k.o obj-$(CONFIG_CLKSRC_NPS) += timer-nps.o obj-$(CONFIG_OXNAS_RPS_TIMER) += timer-oxnas-rps.o obj-$(CONFIG_OWL_TIMER) += owl-timer.o +obj-$(CONFIG_SPRD_TIMER) += timer-sprd.o obj-$(CONFIG_ARC_TIMERS) += arc_timer.o obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o diff --git a/drivers/clocksource/timer-sprd.c b/drivers/clocksource/timer-sprd.c new file mode 100644 index 0000000..ef9ebea --- /dev/null +++ b/drivers/clocksource/timer-sprd.c @@ -0,0 +1,159 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2017 Spreadtrum Communications Inc. + */ + +#include +#include + +#include "timer-of.h" + +#define TIMER_NAME "sprd_timer" + +#define TIMER_LOAD_LO 0x0 +#define TIMER_LOAD_HI 0x4 +#define TIMER_VALUE_LO 0x8 +#define TIMER_VALUE_HI 0xc + +#define TIMER_CTL 0x10 +#define TIMER_CTL_PERIOD_MODE BIT(0) +#define TIMER_CTL_ENABLE BIT(1) +#define TIMER_CTL_64BIT_WIDTH BIT(16) + +#define TIMER_INT 0x14 +#define TIMER_INT_EN BIT(0) +#define TIMER_INT_RAW_STS BIT(1) +#define TIMER_INT_MASK_STS BIT(2) +#define TIMER_INT_CLR BIT(3) + +#define TIMER_VALUE_SHDW_LO 0x18 +#define TIMER_VALUE_SHDW_HI 0x1c + +#define TIMER_VALUE_LO_MASK GENMASK(31, 0) + +static void sprd_timer_enable(void __iomem *base, u32 flag) +{ + u32 val = readl_relaxed(base + TIMER_CTL); + + val |= TIMER_CTL_ENABLE; + if (flag & TIMER_CTL_64BIT_WIDTH) + val |= TIMER_CTL_64BIT_WIDTH; + else + val &= ~TIMER_CTL_64BIT_WIDTH; + + if (flag & TIMER_CTL_PERIOD_MODE) + val |= TIMER_CTL_PERIOD_MODE; + else + val &= ~TIMER_CTL_PERIOD_MODE; + + writel_relaxed(val, base + TIMER_CTL); +} + +static void sprd_timer_disable(void __iomem *base) +{ + u32 val = readl_relaxed(base + TIMER_CTL); + + val &= ~TIMER_CTL_ENABLE; + writel_relaxed(val, base + TIMER_CTL); +} + +static void sprd_timer_update_counter(void __iomem *base, unsigned long cycles) +{ + writel_relaxed(cycles & TIMER_VALUE_LO_MASK, base + TIMER_LOAD_LO); + writel_relaxed(0, base + TIMER_LOAD_HI); +} + +static void sprd_timer_enable_interrupt(void __iomem *base) +{ + writel_relaxed(TIMER_INT_EN, base + TIMER_INT); +} + +static void sprd_timer_clear_interrupt(void __iomem *base) +{ + u32 val = readl_relaxed(base + TIMER_INT); + + val |= TIMER_INT_CLR; + writel_relaxed(val, base + TIMER_INT); +} + +static int sprd_timer_set_next_event(unsigned long cycles, + struct clock_event_device *ce) +{ + struct timer_of *to = to_timer_of(ce); + + sprd_timer_disable(timer_of_base(to)); + sprd_timer_update_counter(timer_of_base(to), cycles); + sprd_timer_enable(timer_of_base(to), 0); + + return 0; +} + +static int sprd_timer_set_periodic(struct clock_event_device *ce) +{ + struct timer_of *to = to_timer_of(ce); + + sprd_timer_disable(timer_of_base(to)); + sprd_timer_update_counter(timer_of_base(to), timer_of_period(to)); + sprd_timer_enable(timer_of_base(to), TIMER_CTL_PERIOD_MODE); + + return 0; +} + +static int sprd_timer_shutdown(struct clock_event_device *ce) +{ + struct timer_of *to = to_timer_of(ce); + + sprd_timer_disable(timer_of_base(to)); + return 0; +} + +static irqreturn_t sprd_timer_interrupt(int irq, void *dev_id) +{ + struct clock_event_device *ce = (struct clock_event_device *)dev_id; + struct timer_of *to = to_timer_of(ce); + + sprd_timer_clear_interrupt(timer_of_base(to)); + + if (clockevent_state_oneshot(ce)) + sprd_timer_disable(timer_of_base(to)); + + ce->event_handler(ce); + return IRQ_HANDLED; +} + +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 = sprd_timer_shutdown, + .set_state_periodic = sprd_timer_set_periodic, + .set_next_event = sprd_timer_set_next_event, + .cpumask = cpu_possible_mask, + }, + + .of_irq = { + .handler = sprd_timer_interrupt, + .flags = IRQF_TIMER | IRQF_IRQPOLL, + }, +}; + +static int __init sprd_timer_init(struct device_node *np) +{ + int ret; + + ret = timer_of_init(np, &to); + if (ret) + return ret; + + sprd_timer_enable_interrupt(timer_of_base(&to)); + clockevents_config_and_register(&to.clkevt, timer_of_rate(&to), + 1, UINT_MAX); + + return 0; +} + +TIMER_OF_DECLARE(sc9860_timer, "sprd,sc9860-timer", sprd_timer_init);