From: "Clément Léger" <clement.leger@bootlin.com>
To: Eugen Hristev <eugen.hristev@microchip.com>,
Ludovic Desroches <ludovic.desroches@microchip.com>
Cc: u-boot@lists.denx.de,
"Nicolas Ferre" <nicolas.ferre@microchip.com>,
"Thomas Petazzoni" <thomas.petazzoni@bootlin.com>,
"Claudiu Beznea" <Claudiu.Beznea@microchip.com>,
"Clément Léger" <clement.leger@bootlin.com>,
"Claudiu Beznea" <claudiu.beznea@microchip.com>
Subject: [PATCH v7 1/4] timer: atmel_tcb_timer: add atmel_tcb driver
Date: Fri, 11 Mar 2022 10:35:36 +0100 [thread overview]
Message-ID: <20220311093539.72669-2-clement.leger@bootlin.com> (raw)
In-Reply-To: <20220311093539.72669-1-clement.leger@bootlin.com>
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.
Reviewed-by: Claudiu Beznea <claudiu.beznea@microchip.com>
Signed-off-by: Clément Léger <clement.leger@bootlin.com>
---
MAINTAINERS | 1 +
arch/arm/mach-at91/armv7/Makefile | 2 +
drivers/timer/Kconfig | 8 ++
drivers/timer/Makefile | 1 +
drivers/timer/atmel_tcb_timer.c | 154 ++++++++++++++++++++++++++++++
5 files changed, 166 insertions(+)
create mode 100644 drivers/timer/atmel_tcb_timer.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 0f39bc6bc9..e30389dc3e 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/arch/arm/mach-at91/armv7/Makefile b/arch/arm/mach-at91/armv7/Makefile
index 246050b67b..f395b55c3d 100644
--- a/arch/arm/mach-at91/armv7/Makefile
+++ b/arch/arm/mach-at91/armv7/Makefile
@@ -14,9 +14,11 @@ obj-y += cpu.o
ifndef CONFIG_$(SPL_TPL_)SYSRESET
obj-y += reset.o
endif
+ifneq ($(CONFIG_ATMEL_TCB_TIMER),y)
ifneq ($(CONFIG_ATMEL_PIT_TIMER),y)
ifneq ($(CONFIG_MCHP_PIT64B_TIMER),y)
# old non-DM timer driver
obj-y += timer.o
endif
endif
+endif
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..70f43d3f73
--- /dev/null
+++ b/drivers/timer/atmel_tcb_timer.c
@@ -0,0 +1,154 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2022 Microchip Corporation
+ *
+ * Author: Clément Léger <clement.leger@bootlin.com>
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <timer.h>
+#include <asm/io.h>
+#include <linux/bitops.h>
+
+#define TCB_CHAN(chan) ((chan) * 0x40)
+
+#define TCB_CCR(chan) (0x0 + TCB_CHAN(chan))
+#define TCB_CCR_CLKEN (1 << 0)
+
+#define TCB_CMR(chan) (0x4 + TCB_CHAN(chan))
+#define TCB_CMR_WAVE (1 << 15)
+#define TCB_CMR_TIMER_CLOCK1 0
+#define TCB_CMR_XC1 6
+#define TCB_CMR_ACPA_SET (1 << 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 (1 << 0)
+
+#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_CLOCK1 | 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
next prev parent reply other threads:[~2022-03-11 9:38 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-03-11 9:35 [PATCH v7 0/4] add TCB driver for sama5d2 Clément Léger
2022-03-11 9:35 ` Clément Léger [this message]
2022-03-11 9:35 ` [PATCH v7 2/4] ARM: dts: at91: sama5d2: add AIC node Clément Léger
2022-03-11 9:35 ` [PATCH v7 3/4] ARM: dts: at91: sama5d2: add TCB node Clément Léger
2022-03-11 9:35 ` [PATCH v7 4/4] configs: sama5d2: enable option CONFIG_ATMEL_TCB_TIMER Clément Léger
2022-03-22 11:18 ` Eugen.Hristev
2022-03-22 12:35 ` Clément Léger
2022-03-30 15:49 ` Clément Léger
2022-03-31 5:59 ` Eugen.Hristev
2022-03-31 7:40 ` Clément Léger
2022-03-31 7:53 ` Eugen.Hristev
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20220311093539.72669-2-clement.leger@bootlin.com \
--to=clement.leger@bootlin.com \
--cc=Claudiu.Beznea@microchip.com \
--cc=eugen.hristev@microchip.com \
--cc=ludovic.desroches@microchip.com \
--cc=nicolas.ferre@microchip.com \
--cc=thomas.petazzoni@bootlin.com \
--cc=u-boot@lists.denx.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.