Commit 057b613990d1665d1d2936655a1aca1962126800
Committed by
Tom Rini
1 parent
c82216803d
Exists in
smarc_8mq_lf_v2020.04
and in
9 other branches
timer: Add driver for Nomadik Multi Timer Unit (MTU)
The Nomadik Multi Timer Unit (MTU) provides 4 decrementing free-running timers. It is used in ST-Ericsson Ux500 SoCs. The driver uses the first timer to implement UCLASS_TIMER. Signed-off-by: Stephan Gerhold <stephan@gerhold.net> Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Showing 3 changed files with 124 additions and 0 deletions Side-by-side Diff
drivers/timer/Kconfig
... | ... | @@ -127,6 +127,15 @@ |
127 | 127 | hardware ways, nor got from device tree at the time when device |
128 | 128 | tree is not available yet. |
129 | 129 | |
130 | +config NOMADIK_MTU_TIMER | |
131 | + bool "Nomadik MTU Timer" | |
132 | + depends on TIMER | |
133 | + help | |
134 | + Enables support for the Nomadik Multi Timer Unit (MTU), | |
135 | + used in ST-Ericsson Ux500 SoCs. | |
136 | + The MTU provides 4 decrementing free-running timers. | |
137 | + At the moment, only the first timer is used by the driver. | |
138 | + | |
130 | 139 | config OMAP_TIMER |
131 | 140 | bool "Omap timer support" |
132 | 141 | depends on TIMER |
drivers/timer/Makefile
... | ... | @@ -12,6 +12,7 @@ |
12 | 12 | obj-$(CONFIG_CADENCE_TTC_TIMER) += cadence-ttc.o |
13 | 13 | obj-$(CONFIG_DESIGNWARE_APB_TIMER) += dw-apb-timer.o |
14 | 14 | obj-$(CONFIG_MPC83XX_TIMER) += mpc83xx_timer.o |
15 | +obj-$(CONFIG_NOMADIK_MTU_TIMER) += nomadik-mtu-timer.o | |
15 | 16 | obj-$(CONFIG_OMAP_TIMER) += omap-timer.o |
16 | 17 | obj-$(CONFIG_RENESAS_OSTM_TIMER) += ostm_timer.o |
17 | 18 | obj-$(CONFIG_RISCV_TIMER) += riscv_timer.o |
drivers/timer/nomadik-mtu-timer.c
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 <common.h> | |
16 | +#include <dm.h> | |
17 | +#include <timer.h> | |
18 | +#include <asm/io.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 | + | |
56 | +static int nomadik_mtu_get_count(struct udevice *dev, u64 *count) | |
57 | +{ | |
58 | + struct nomadik_mtu_priv *priv = dev_get_priv(dev); | |
59 | + | |
60 | + /* Decrementing counter: invert the value */ | |
61 | + *count = timer_conv_64(~readl(&priv->timer->cv)); | |
62 | + | |
63 | + return 0; | |
64 | +} | |
65 | + | |
66 | +static int nomadik_mtu_probe(struct udevice *dev) | |
67 | +{ | |
68 | + struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev); | |
69 | + struct nomadik_mtu_priv *priv = dev_get_priv(dev); | |
70 | + struct nomadik_mtu_regs *mtu; | |
71 | + fdt_addr_t addr; | |
72 | + u32 prescale; | |
73 | + | |
74 | + addr = dev_read_addr(dev); | |
75 | + if (addr == FDT_ADDR_T_NONE) | |
76 | + return -EINVAL; | |
77 | + | |
78 | + mtu = (struct nomadik_mtu_regs *)addr; | |
79 | + priv->timer = mtu->timers; /* Use first timer */ | |
80 | + | |
81 | + if (!uc_priv->clock_rate) | |
82 | + return -EINVAL; | |
83 | + | |
84 | + /* Use divide-by-16 counter if tick rate is more than 32 MHz */ | |
85 | + if (uc_priv->clock_rate > 32000000) { | |
86 | + uc_priv->clock_rate /= 16; | |
87 | + prescale = MTU_CR_PRESCALE_16; | |
88 | + } else { | |
89 | + prescale = MTU_CR_PRESCALE_1; | |
90 | + } | |
91 | + | |
92 | + /* Configure a free-running, auto-wrap counter with selected prescale */ | |
93 | + writel(MTU_CR_ENABLE | prescale | MTU_CR_32BITS, &priv->timer->cr); | |
94 | + | |
95 | + return 0; | |
96 | +} | |
97 | + | |
98 | +static const struct timer_ops nomadik_mtu_ops = { | |
99 | + .get_count = nomadik_mtu_get_count, | |
100 | +}; | |
101 | + | |
102 | +static const struct udevice_id nomadik_mtu_ids[] = { | |
103 | + { .compatible = "st,nomadik-mtu" }, | |
104 | + {} | |
105 | +}; | |
106 | + | |
107 | +U_BOOT_DRIVER(nomadik_mtu) = { | |
108 | + .name = "nomadik_mtu", | |
109 | + .id = UCLASS_TIMER, | |
110 | + .of_match = nomadik_mtu_ids, | |
111 | + .priv_auto_alloc_size = sizeof(struct nomadik_mtu_priv), | |
112 | + .probe = nomadik_mtu_probe, | |
113 | + .ops = &nomadik_mtu_ops, | |
114 | +}; |