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 Received: from phobos.denx.de (phobos.denx.de [85.214.62.61]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 4055EC433EF for ; Fri, 4 Mar 2022 09:47:05 +0000 (UTC) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id E275683BB0; Fri, 4 Mar 2022 10:46:56 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=reject dis=none) header.from=bootlin.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (2048-bit key; unprotected) header.d=bootlin.com header.i=@bootlin.com header.b="OVilM+a+"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 9102083531; Fri, 4 Mar 2022 10:46:52 +0100 (CET) Received: from relay9-d.mail.gandi.net (relay9-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::229]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 8130183B6D for ; Fri, 4 Mar 2022 10:46:48 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=reject dis=none) header.from=bootlin.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=clement.leger@bootlin.com Received: (Authenticated sender: clement.leger@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 9A333FF809; Fri, 4 Mar 2022 09:46:47 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1646387208; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=+FgCq6Aubs6ZoFQd3EtHs30DFT7x7VkTo737y0VTGFA=; b=OVilM+a+YxpZH7NS0WkUMrLzHAxUB4LQCySEuTMqKM11HzD76EqQoPm9phxRj9UQUYuTlE /nS8EjncLW40o7vNfCStW/vJQdFFagUVGeWccg7BNU3Mro5ExPqyyuguktD6l/k31jO6yl t+8HYJnNKExBwbOOR6m7jjZmm66Lv80TDjU3PpiY9NOHpnTu/L+gknqIFVNfG9X7bthX4D im64si3FbZGpbrAf9BKdWrsfQ3S/JDqSi9S/SidIlNwzb4Ztwskp/pgRYzkvZAbz4iA8w2 OYsAFHCbZ+v+Gy0HLei1fzlVC141QXT4Pmnh3aM2Ia4zMUVnVKsBxSJ0AKAdsA== From: =?UTF-8?q?Cl=C3=A9ment=20L=C3=A9ger?= To: Eugen Hristev , Ludovic Desroches Cc: u-boot@lists.denx.de, Nicolas Ferre , Thomas Petazzoni , Claudiu Beznea , =?UTF-8?q?Cl=C3=A9ment=20L=C3=A9ger?= Subject: [PATCH v4 1/3] timer: atmel_tcb_timer: add atmel_tcb driver Date: Fri, 4 Mar 2022 10:45:20 +0100 Message-Id: <20220304094522.47714-2-clement.leger@bootlin.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220304094522.47714-1-clement.leger@bootlin.com> References: <20220304094522.47714-1-clement.leger@bootlin.com> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.39 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.5 at phobos.denx.de X-Virus-Status: Clean Add a driver for the timer counter block that can be found on sama5d2. This driver will be used when booting under OP-TEE since the pit timer which is part of the SYSC is secured. Channel 1 & 2 are configured to be chained together which allows to have a 64bits counter. Signed-off-by: Clément Léger --- MAINTAINERS | 1 + drivers/timer/Kconfig | 8 ++ drivers/timer/Makefile | 1 + drivers/timer/atmel_tcb_timer.c | 155 ++++++++++++++++++++++++++++++++ 4 files changed, 165 insertions(+) create mode 100644 drivers/timer/atmel_tcb_timer.c diff --git a/MAINTAINERS b/MAINTAINERS index fb171e0c68..73b46c4631 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -352,6 +352,7 @@ F: arch/arm/mach-at91/ F: board/atmel/ F: drivers/cpu/at91_cpu.c F: drivers/misc/microchip_flexcom.c +F: drivers/timer/atmel_tcb_timer.c F: include/dt-bindings/mfd/atmel-flexcom.h F: drivers/timer/mchp-pit64b-timer.c diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig index 8913142654..8fad59b81a 100644 --- a/drivers/timer/Kconfig +++ b/drivers/timer/Kconfig @@ -96,6 +96,14 @@ config ATMEL_PIT_TIMER it is designed to offer maximum accuracy and efficient management, even for systems with long response time. +config ATMEL_TCB_TIMER + bool "Atmel timer counter support" + depends on TIMER + depends on ARCH_AT91 + help + Select this to enable the use of the timer counter as a monotonic + counter. + config CADENCE_TTC_TIMER bool "Cadence TTC (Triple Timer Counter)" depends on TIMER diff --git a/drivers/timer/Makefile b/drivers/timer/Makefile index e2bd530eb0..58da6c1e84 100644 --- a/drivers/timer/Makefile +++ b/drivers/timer/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_ARC_TIMER) += arc_timer.o obj-$(CONFIG_AST_TIMER) += ast_timer.o obj-$(CONFIG_ATCPIT100_TIMER) += atcpit100_timer.o obj-$(CONFIG_ATMEL_PIT_TIMER) += atmel_pit_timer.o +obj-$(CONFIG_ATMEL_TCB_TIMER) += atmel_tcb_timer.o obj-$(CONFIG_CADENCE_TTC_TIMER) += cadence-ttc.o obj-$(CONFIG_DESIGNWARE_APB_TIMER) += dw-apb-timer.o obj-$(CONFIG_MPC83XX_TIMER) += mpc83xx_timer.o diff --git a/drivers/timer/atmel_tcb_timer.c b/drivers/timer/atmel_tcb_timer.c new file mode 100644 index 0000000000..b73b367227 --- /dev/null +++ b/drivers/timer/atmel_tcb_timer.c @@ -0,0 +1,155 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2022 Microchip Corporation + * + * Author: Clément Léger + */ + +#include +#include +#include +#include +#include +#include + +#define TCB_CHAN(chan) ((chan) * 0x40) + +#define TCB_CCR(chan) (0x0 + TCB_CHAN(chan)) +#define TCB_CCR_SWTRG 0x4 +#define TCB_CCR_CLKEN 0x1 + +#define TCB_CMR(chan) (0x4 + TCB_CHAN(chan)) +#define TCB_CMR_WAVE BIT(15) +#define TCB_CMR_TIMER_CLOCK0 0 +#define TCB_CMR_XC1 6 +#define TCB_CMR_ACPA_SET BIT(16) +#define TCB_CMR_ACPC_CLEAR (2 << 18) + +#define TCB_CV(chan) (0x10 + TCB_CHAN(chan)) + +#define TCB_RA(chan) (0x14 + TCB_CHAN(chan)) +#define TCB_RC(chan) (0x1c + TCB_CHAN(chan)) + +#define TCB_IDR(chan) (0x28 + TCB_CHAN(chan)) + +#define TCB_BCR 0xc0 +#define TCB_BCR_SYNC 0x1 + +#define TCB_BMR 0xc4 +#define TCB_BMR_TC1XC1S_TIOA0 (2 << 2) + +#define TCB_WPMR 0xe4 +#define TCB_WPMR_WAKEY 0x54494d + +struct atmel_tcb_plat { + void __iomem *base; +}; + +static u64 atmel_tcb_get_count(struct udevice *dev) +{ + struct atmel_tcb_plat *plat = dev_get_plat(dev); + u64 cv0 = 0; + u64 cv1 = 0; + + do { + cv1 = readl(plat->base + TCB_CV(1)); + cv0 = readl(plat->base + TCB_CV(0)); + } while (readl(plat->base + TCB_CV(1)) != cv1); + + cv0 |= cv1 << 32; + + return cv0; +} + +static void atmel_tcb_configure(void __iomem *base) +{ + /* Disable write protection */ + writel(TCB_WPMR_WAKEY, base + TCB_WPMR); + + /* Disable all irqs for both channel 0 & 1 */ + writel(0xff, base + TCB_IDR(0)); + writel(0xff, base + TCB_IDR(1)); + + /* + * In order to avoid wrapping, use a 64 bit counter by chaining + * two channels. + * Channel 0 is configured to generate a clock on TIOA0 which is cleared + * when reaching 0x80000000 and set when reaching 0. + */ + writel(TCB_CMR_TIMER_CLOCK0 | TCB_CMR_WAVE | TCB_CMR_ACPA_SET + | TCB_CMR_ACPC_CLEAR, base + TCB_CMR(0)); + writel(0x80000000, base + TCB_RC(0)); + writel(0x1, base + TCB_RA(0)); + writel(TCB_CCR_CLKEN, base + TCB_CCR(0)); + + /* Channel 1 is configured to use TIOA0 as input */ + writel(TCB_CMR_XC1 | TCB_CMR_WAVE, base + TCB_CMR(1)); + writel(TCB_CCR_CLKEN, base + TCB_CCR(1)); + + /* Set XC1 input to be TIOA0 (ie output of Channel 0) */ + writel(TCB_BMR_TC1XC1S_TIOA0, base + TCB_BMR); + + /* Sync & start all timers */ + writel(TCB_BCR_SYNC, base + TCB_BCR); +} + +static int atmel_tcb_probe(struct udevice *dev) +{ + struct atmel_tcb_plat *plat = dev_get_plat(dev); + struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev); + struct clk clk; + ulong clk_rate; + int ret; + + if (!device_is_compatible(dev->parent, "atmel,sama5d2-tcb")) + return -EINVAL; + + /* Currently, we only support channel 0 and 1 to be chained */ + if (dev_read_addr_index(dev, 0) != 0 && + dev_read_addr_index(dev, 1) != 1) { + printf("Error: only chained timers 0 and 1 are supported\n"); + return -EINVAL; + } + + ret = clk_get_by_name(dev->parent, "gclk", &clk); + if (ret) + return -EINVAL; + + clk_rate = clk_get_rate(&clk); + if (!clk_rate) + return -EINVAL; + + uc_priv->clock_rate = clk_rate; + + atmel_tcb_configure(plat->base); + + return 0; +} + +static int atmel_tcb_of_to_plat(struct udevice *dev) +{ + struct atmel_tcb_plat *plat = dev_get_plat(dev); + + plat->base = dev_read_addr_ptr(dev->parent); + + return 0; +} + +static const struct timer_ops atmel_tcb_ops = { + .get_count = atmel_tcb_get_count, +}; + +static const struct udevice_id atmel_tcb_ids[] = { + { .compatible = "atmel,tcb-timer" }, + { } +}; + +U_BOOT_DRIVER(atmel_tcb) = { + .name = "atmel_tcb", + .id = UCLASS_TIMER, + .of_match = atmel_tcb_ids, + .of_to_plat = atmel_tcb_of_to_plat, + .plat_auto = sizeof(struct atmel_tcb_plat), + .probe = atmel_tcb_probe, + .ops = &atmel_tcb_ops, +}; -- 2.34.1