Received: by 2002:a05:7412:31a9:b0:e2:908c:2ebd with SMTP id et41csp4418512rdb; Fri, 15 Sep 2023 01:13:52 -0700 (PDT) X-Google-Smtp-Source: AGHT+IEgqBcd/HWGz7x9DHHXdsM1gZC8RUQj+1jZOt1MetGiiGezLeJtZbmFMKghi9AOTkomkTYM X-Received: by 2002:a17:90b:1196:b0:269:4645:80b9 with SMTP id gk22-20020a17090b119600b00269464580b9mr742931pjb.2.1694765632085; Fri, 15 Sep 2023 01:13:52 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1694765632; cv=none; d=google.com; s=arc-20160816; b=sYNnwpJbIeZ0HTGIYeNQSPJMresOvoN7FQvBb/HvbqII2dadsfkiLVfPam4oS/8Lg4 VbYkFlqXQV3ViWLX1L4/uT0o1DT5MO/eY7C43pK6zG7JxH2DiYUCwaFRad7YGIywIVbD wQgOd/D1+8shnHQdsl/m/A5MQbJA0Bicqx8scRfK8gF1QnkiO2em6LSKpEbVkdd7izZ+ AYqgRxQeMi4lwuLiqUFPYv9Ermd7BxCTbHK3HXeJ2RkL8qVM44prFegcGSfpgZVz//Ah pNmCxvlYqfEkzXJkxw/NKxuw/MIdZmVzyNZZQkH1z5/WCPljvP35wllwx24tMhkI42V2 GJwQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:reply-to:cc:to:in-reply-to:references:message-id :content-transfer-encoding:mime-version:subject:date:from :dkim-signature; bh=F7C5CdkwhH5J/nmB6RN+fLPSioVzjH6MzYeDMNsOzgc=; fh=AysWwR5WX/emMTOwOYsXqPNbbESmhJOu4Yb0/COXpZ8=; b=fS0e04IiQZrRaWAbf20wFL0tNtI8JDqTg+K4OqHCrkcJonyob0Ack7Aa7uy3LV7phA uWbgheGKmEI/1XqhaA85w5b6zZQDRcSPdBW9BIXjhr1irCiisIwbZRqAm1NcxCbKWXN+ fzU0UK3MofYG3YioQthMnirvVS2N/5TZVxYkhXOn3WC/RuaavpkHyBUH9onq4937sI0W R5Qpm/3g1BWbRVHzPN5cjLw2k15Ps76rMl6xoK/Pez83jT70tel/PnaaLQPqek3q2bnL Kdt8dREZlGzerv/WHk7BfPJ52FJghh73bLF9OGRdd5aVZOjOd31z31IKvJjlWCGUtkfO ISRQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=k20201202 header.b=WhF9JtSP; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::3:2 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Return-Path: Received: from agentk.vger.email (agentk.vger.email. [2620:137:e000::3:2]) by mx.google.com with ESMTPS id b6-20020a17090a12c600b0025de453ee4csi3020926pjg.168.2023.09.15.01.13.51 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 15 Sep 2023 01:13:52 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::3:2 as permitted sender) client-ip=2620:137:e000::3:2; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=k20201202 header.b=WhF9JtSP; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::3:2 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Received: from out1.vger.email (depot.vger.email [IPv6:2620:137:e000::3:0]) by agentk.vger.email (Postfix) with ESMTP id B66AC8222295; Fri, 15 Sep 2023 01:12:58 -0700 (PDT) X-Virus-Status: Clean X-Virus-Scanned: clamav-milter 0.103.10 at agentk.vger.email Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233027AbjIOIMq (ORCPT + 99 others); Fri, 15 Sep 2023 04:12:46 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34092 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232893AbjIOIMS (ORCPT ); Fri, 15 Sep 2023 04:12:18 -0400 Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E79C42722 for ; Fri, 15 Sep 2023 01:12:10 -0700 (PDT) Received: by smtp.kernel.org (Postfix) with ESMTPS id CB7ECC433CC; Fri, 15 Sep 2023 08:12:08 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1694765528; bh=9XN2hAnsjMncIYnm1bQ8cbwe7mkvYM4tX+INvhk45BM=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=WhF9JtSPUk7uvD80kqNZ0E622R9fqIpsx7qyApbNpbxhfrdtVMTSBT/Rn7/capybI M2tu8DwymSPN0QBcEGmfVAeqnNoy2xGXcZeT4baa247/UtNWl3bFK/z60MShbhDbIn B8bED/LX6Oky0dcc8+l+38ufS1bfu7ga+Uas9Kjhp7QOT/Xv50lgpPTMm/Otq72l/1 saGQkJdY6hPR4wu5uXaPfMVcbgRfQDIpeirKxwkELkzmgosn5zUT0jMl1FnFYWzCM3 tqADH0nhVzT+OWSpoqfhBVLj9hUHoXdkLOSiQEpFsIjdFz7njyv97z/CtthHtSbUsr Hc5TI9k9hT0ew== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id B96AFEE643C; Fri, 15 Sep 2023 08:12:08 +0000 (UTC) From: Nikita Shubin via B4 Relay Date: Fri, 15 Sep 2023 11:10:54 +0300 Subject: [PATCH v4 12/42] clocksource: ep93xx: Add driver for Cirrus Logic EP93xx MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Message-Id: <20230915-ep93xx-v4-12-a1d779dcec10@maquefel.me> References: <20230915-ep93xx-v4-0-a1d779dcec10@maquefel.me> In-Reply-To: <20230915-ep93xx-v4-0-a1d779dcec10@maquefel.me> To: Daniel Lezcano , Thomas Gleixner Cc: linux-kernel@vger.kernel.org, Arnd Bergmann , Alexander Sverdlin X-Mailer: b4 0.13-dev-e3e53 X-Developer-Signature: v=1; a=ed25519-sha256; t=1694765525; l=7739; i=nikita.shubin@maquefel.me; s=20230718; h=from:subject:message-id; bh=lUOF5SVzhbiow4dRhadRUEJmNA99wtTxdMoHv87TsaA=; =?utf-8?q?b=3Da53bx6eIi5tw?= =?utf-8?q?y0PulluwI7uPi7YVdIn3lS7DWfNXu5XCJq4SXQGKPkBJBp2vFrZr6NjzLGjawFvU?= k4Jhl25EByFWko24uWAe1BgcAAxZjXr73geHtbW7XYcUyq9cBr2a X-Developer-Key: i=nikita.shubin@maquefel.me; a=ed25519; pk=vqf5YIUJ7BJv3EJFaNNxWZgGuMgDH6rwufTLflwU9ac= X-Endpoint-Received: by B4 Relay for nikita.shubin@maquefel.me/20230718 with auth_id=65 X-Original-From: Nikita Shubin Reply-To: X-Spam-Status: No, score=-1.2 required=5.0 tests=DKIMWL_WL_HIGH,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,MAILING_LIST_MULTI, SPF_HELO_NONE,SPF_PASS autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on agentk.vger.email Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-Greylist: Sender passed SPF test, not delayed by milter-greylist-4.6.4 (agentk.vger.email [0.0.0.0]); Fri, 15 Sep 2023 01:13:11 -0700 (PDT) From: Nikita Shubin Rewrite EP93xx timer driver located in arch/arm/mach-ep93xx/timer-ep93xx.c trying to do everything the device tree way: - Make every IO-access relative to a base address and dynamic so we can do a dynamic ioremap and get going. - Find register range and interrupt from the device tree. Reviewed-by: Linus Walleij Tested-by: Alexander Sverdlin Signed-off-by: Nikita Shubin --- drivers/clocksource/Kconfig | 11 +++ drivers/clocksource/Makefile | 1 + drivers/clocksource/timer-ep93xx.c | 190 +++++++++++++++++++++++++++++++++++++ 3 files changed, 202 insertions(+) diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index c4d671a5a13d..f1b84b05b281 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -739,4 +739,15 @@ config GOLDFISH_TIMER help Support for the timer/counter of goldfish-rtc +config EP93XX_TIMER + bool "Cirrus Logic ep93xx timer driver" if COMPILE_TEST + depends on ARCH_EP93XX + depends on GENERIC_CLOCKEVENTS + depends on HAS_IOMEM + select CLKSRC_MMIO + select TIMER_OF + help + Enables support for the Cirrus Logic timer block + EP93XX. + endmenu diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 5d93c9e3fc55..b6a3cf1f5b9d 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -90,3 +90,4 @@ obj-$(CONFIG_MSC313E_TIMER) += timer-msc313e.o obj-$(CONFIG_GOLDFISH_TIMER) += timer-goldfish.o obj-$(CONFIG_GXP_TIMER) += timer-gxp.o obj-$(CONFIG_CLKSRC_LOONGSON1_PWM) += timer-loongson1-pwm.o +obj-$(CONFIG_EP93XX_TIMER) += timer-ep93xx.o diff --git a/drivers/clocksource/timer-ep93xx.c b/drivers/clocksource/timer-ep93xx.c new file mode 100644 index 000000000000..bc0ca6e12334 --- /dev/null +++ b/drivers/clocksource/timer-ep93xx.c @@ -0,0 +1,190 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Cirrus Logic EP93xx timer driver. + * Copyright (C) 2021 Nikita Shubin + * + * Based on a rewrite of arch/arm/mach-ep93xx/timer.c: + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/************************************************************************* + * Timer handling for EP93xx + ************************************************************************* + * The ep93xx has four internal timers. Timers 1, 2 (both 16 bit) and + * 3 (32 bit) count down at 508 kHz, are self-reloading, and can generate + * an interrupt on underflow. Timer 4 (40 bit) counts down at 983.04 kHz, + * is free-running, and can't generate interrupts. + * + * The 508 kHz timers are ideal for use for the timer interrupt, as the + * most common values of HZ divide 508 kHz nicely. We pick the 32 bit + * timer (timer 3) to get as long sleep intervals as possible when using + * CONFIG_NO_HZ. + * + * The higher clock rate of timer 4 makes it a better choice than the + * other timers for use as clock source and for sched_clock(), providing + * a stable 40 bit time base. + ************************************************************************* + */ + +#define EP93XX_TIMER1_LOAD 0x00 +#define EP93XX_TIMER1_VALUE 0x04 +#define EP93XX_TIMER1_CONTROL 0x08 +#define EP93XX_TIMER123_CONTROL_ENABLE BIT(7) +#define EP93XX_TIMER123_CONTROL_MODE BIT(6) +#define EP93XX_TIMER123_CONTROL_CLKSEL BIT(3) +#define EP93XX_TIMER1_CLEAR 0x0c +#define EP93XX_TIMER2_LOAD 0x20 +#define EP93XX_TIMER2_VALUE 0x24 +#define EP93XX_TIMER2_CONTROL 0x28 +#define EP93XX_TIMER2_CLEAR 0x2c +/* + * This read-only register contains the low word of the time stamp debug timer + * ( Timer4). When this register is read, the high byte of the Timer4 counter is + * saved in the Timer4ValueHigh register. + */ +#define EP93XX_TIMER4_VALUE_LOW 0x60 +#define EP93XX_TIMER4_VALUE_HIGH 0x64 +#define EP93XX_TIMER4_VALUE_HIGH_ENABLE BIT(8) +#define EP93XX_TIMER3_LOAD 0x80 +#define EP93XX_TIMER3_VALUE 0x84 +#define EP93XX_TIMER3_CONTROL 0x88 +#define EP93XX_TIMER3_CLEAR 0x8c + +#define EP93XX_TIMER123_RATE 508469 +#define EP93XX_TIMER4_RATE 983040 + +struct ep93xx_tcu { + void __iomem *base; +}; + +static struct ep93xx_tcu *ep93xx_tcu; + +static u64 ep93xx_clocksource_read(struct clocksource *c) +{ + struct ep93xx_tcu *tcu = ep93xx_tcu; + + return lo_hi_readq(tcu->base + EP93XX_TIMER4_VALUE_LOW) & GENMASK_ULL(39, 0); +} + +static u64 notrace ep93xx_read_sched_clock(void) +{ + return ep93xx_clocksource_read(NULL); +} + +static int ep93xx_clkevt_set_next_event(unsigned long next, + struct clock_event_device *evt) +{ + struct ep93xx_tcu *tcu = ep93xx_tcu; + /* Default mode: periodic, off, 508 kHz */ + u32 tmode = EP93XX_TIMER123_CONTROL_MODE | + EP93XX_TIMER123_CONTROL_CLKSEL; + + /* Clear timer */ + writel(tmode, tcu->base + EP93XX_TIMER3_CONTROL); + + /* Set next event */ + writel(next, tcu->base + EP93XX_TIMER3_LOAD); + writel(tmode | EP93XX_TIMER123_CONTROL_ENABLE, + tcu->base + EP93XX_TIMER3_CONTROL); + return 0; +} + +static int ep93xx_clkevt_shutdown(struct clock_event_device *evt) +{ + struct ep93xx_tcu *tcu = ep93xx_tcu; + /* Disable timer */ + writel(0, tcu->base + EP93XX_TIMER3_CONTROL); + + return 0; +} + +static struct clock_event_device ep93xx_clockevent = { + .name = "timer1", + .features = CLOCK_EVT_FEAT_ONESHOT, + .set_state_shutdown = ep93xx_clkevt_shutdown, + .set_state_oneshot = ep93xx_clkevt_shutdown, + .tick_resume = ep93xx_clkevt_shutdown, + .set_next_event = ep93xx_clkevt_set_next_event, + .rating = 300, +}; + +static irqreturn_t ep93xx_timer_interrupt(int irq, void *dev_id) +{ + struct ep93xx_tcu *tcu = ep93xx_tcu; + struct clock_event_device *evt = dev_id; + + /* Writing any value clears the timer interrupt */ + writel(1, tcu->base + EP93XX_TIMER3_CLEAR); + + evt->event_handler(evt); + + return IRQ_HANDLED; +} + +static int __init ep93xx_timer_of_init(struct device_node *np) +{ + int irq; + unsigned long flags = IRQF_TIMER | IRQF_IRQPOLL; + struct ep93xx_tcu *tcu; + int ret; + + tcu = kzalloc(sizeof(*tcu), GFP_KERNEL); + if (!tcu) + return -ENOMEM; + + tcu->base = of_iomap(np, 0); + if (!tcu->base) { + pr_err("Can't remap registers\n"); + ret = -ENXIO; + goto out_free; + } + + ep93xx_tcu = tcu; + + irq = irq_of_parse_and_map(np, 0); + if (irq == 0) + irq = -EINVAL; + if (irq < 0) { + pr_err("EP93XX Timer Can't parse IRQ %d", irq); + goto out_free; + } + + /* Enable and register clocksource and sched_clock on timer 4 */ + writel(EP93XX_TIMER4_VALUE_HIGH_ENABLE, + tcu->base + EP93XX_TIMER4_VALUE_HIGH); + clocksource_mmio_init(NULL, "timer4", + EP93XX_TIMER4_RATE, 200, 40, + ep93xx_clocksource_read); + sched_clock_register(ep93xx_read_sched_clock, 40, + EP93XX_TIMER4_RATE); + + /* Set up clockevent on timer 3 */ + if (request_irq(irq, ep93xx_timer_interrupt, flags, "ep93xx timer", + &ep93xx_clockevent)) + pr_err("Failed to request irq %d (ep93xx timer)\n", irq); + + clockevents_config_and_register(&ep93xx_clockevent, + EP93XX_TIMER123_RATE, + 1, + UINT_MAX); + + return 0; + +out_free: + kfree(tcu); + return ret; +} +TIMER_OF_DECLARE(ep93xx_timer, "cirrus,ep9301-timer", ep93xx_timer_of_init); -- 2.39.2