1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (C) 2019 Stephan Gerhold <stephan@gerhold.net>
4  *
5  * Based on arch/arm/cpu/armv7/u8500/timer.c:
6  * Copyright (C) 2010 Linaro Limited
7  * John Rigby <john.rigby@linaro.org>
8  *
9  * Based on Linux kernel source and internal ST-Ericsson U-Boot source:
10  * Copyright (C) 2009 Alessandro Rubini
11  * Copyright (C) 2010 ST-Ericsson
12  * Copyright (C) 2010 Linus Walleij for ST-Ericsson
13  */
14 
15 #include <dm.h>
16 #include <timer.h>
17 #include <asm/io.h>
18 #include <linux/bitops.h>
19 
20 #define MTU_NUM_TIMERS		4
21 
22 /* The timers */
23 struct nomadik_mtu_timer_regs {
24 	u32 lr;		/* Load register */
25 	u32 cv;		/* Current value */
26 	u32 cr;		/* Control register */
27 	u32 bglr;	/* Background load register */
28 };
29 
30 /* The MTU that contains the timers */
31 struct nomadik_mtu_regs {
32 	u32 imsc;	/* Interrupt mask set/clear */
33 	u32 ris;	/* Raw interrupt status */
34 	u32 mis;	/* Masked interrupt status */
35 	u32 icr;	/* Interrupt clear register */
36 
37 	struct nomadik_mtu_timer_regs timers[MTU_NUM_TIMERS];
38 };
39 
40 /* Bits for the control register */
41 #define MTU_CR_ONESHOT		BIT(0)	/* if 0 = wraps reloading from BGLR */
42 #define MTU_CR_32BITS		BIT(1)	/* if 0 = 16-bit counter */
43 
44 #define MTU_CR_PRESCALE_SHIFT	2
45 #define MTU_CR_PRESCALE_1	(0 << MTU_CR_PRESCALE_SHIFT)
46 #define MTU_CR_PRESCALE_16	(1 << MTU_CR_PRESCALE_SHIFT)
47 #define MTU_CR_PRESCALE_256	(2 << MTU_CR_PRESCALE_SHIFT)
48 
49 #define MTU_CR_PERIODIC		BIT(6)	/* if 0 = free-running */
50 #define MTU_CR_ENABLE		BIT(7)
51 
52 struct nomadik_mtu_priv {
53 	struct nomadik_mtu_timer_regs *timer;
54 };
55 
nomadik_mtu_get_count(struct udevice * dev)56 static u64 nomadik_mtu_get_count(struct udevice *dev)
57 {
58 	struct nomadik_mtu_priv *priv = dev_get_priv(dev);
59 
60 	/* Decrementing counter: invert the value */
61 	return timer_conv_64(~readl(&priv->timer->cv));
62 }
63 
nomadik_mtu_probe(struct udevice * dev)64 static int nomadik_mtu_probe(struct udevice *dev)
65 {
66 	struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
67 	struct nomadik_mtu_priv *priv = dev_get_priv(dev);
68 	struct nomadik_mtu_regs *mtu;
69 	u32 prescale;
70 
71 	mtu = dev_read_addr_ptr(dev);
72 	if (!mtu)
73 		return -EINVAL;
74 	priv->timer = mtu->timers; /* Use first timer */
75 
76 	if (!uc_priv->clock_rate)
77 		return -EINVAL;
78 
79 	/* Use divide-by-16 counter if tick rate is more than 32 MHz */
80 	if (uc_priv->clock_rate > 32000000) {
81 		uc_priv->clock_rate /= 16;
82 		prescale = MTU_CR_PRESCALE_16;
83 	} else {
84 		prescale = MTU_CR_PRESCALE_1;
85 	}
86 
87 	/* Configure a free-running, auto-wrap counter with selected prescale */
88 	writel(MTU_CR_ENABLE | prescale | MTU_CR_32BITS, &priv->timer->cr);
89 
90 	return 0;
91 }
92 
93 static const struct timer_ops nomadik_mtu_ops = {
94 	.get_count = nomadik_mtu_get_count,
95 };
96 
97 static const struct udevice_id nomadik_mtu_ids[] = {
98 	{ .compatible = "st,nomadik-mtu" },
99 	{}
100 };
101 
102 U_BOOT_DRIVER(nomadik_mtu) = {
103 	.name = "nomadik_mtu",
104 	.id = UCLASS_TIMER,
105 	.of_match = nomadik_mtu_ids,
106 	.priv_auto	= sizeof(struct nomadik_mtu_priv),
107 	.probe = nomadik_mtu_probe,
108 	.ops = &nomadik_mtu_ops,
109 };
110