timer: orion-timer: Add support for other Armada SoC's
[platform/kernel/u-boot.git] / drivers / timer / orion-timer.c
1 // SPDX-License-Identifier: GPL-2.0+
2 #include <asm/io.h>
3 #include <common.h>
4 #include <dm/device.h>
5 #include <dm/fdtaddr.h>
6 #include <timer.h>
7
8 #define TIMER_CTRL              0x00
9 #define TIMER0_EN               BIT(0)
10 #define TIMER0_RELOAD_EN        BIT(1)
11 #define TIMER0_RELOAD           0x10
12 #define TIMER0_VAL              0x14
13
14 enum input_clock_type {
15         INPUT_CLOCK_NON_FIXED,
16         INPUT_CLOCK_25MHZ,      /* input clock rate is fixed to 25MHz */
17 };
18
19 struct orion_timer_priv {
20         void *base;
21 };
22
23 #define MVEBU_TIMER_FIXED_RATE_25MHZ    25000000
24
25 /**
26  * timer_early_get_rate() - Get the timer rate before driver model
27  */
28 unsigned long notrace timer_early_get_rate(void)
29 {
30         return MVEBU_TIMER_FIXED_RATE_25MHZ;
31 }
32
33 /**
34  * timer_early_get_count() - Get the timer count before driver model
35  *
36  */
37 u64 notrace timer_early_get_count(void)
38 {
39         return timer_conv_64(~readl(MVEBU_TIMER_BASE + TIMER0_VAL));
40 }
41
42 static uint64_t orion_timer_get_count(struct udevice *dev)
43 {
44         struct orion_timer_priv *priv = dev_get_priv(dev);
45
46         return timer_conv_64(~readl(priv->base + TIMER0_VAL));
47 }
48
49 static int orion_timer_probe(struct udevice *dev)
50 {
51         struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
52         enum input_clock_type type = dev_get_driver_data(dev);
53         struct orion_timer_priv *priv = dev_get_priv(dev);
54
55         priv->base = devfdt_remap_addr_index(dev, 0);
56         if (!priv->base) {
57                 debug("unable to map registers\n");
58                 return -ENOMEM;
59         }
60
61         writel(~0, priv->base + TIMER0_VAL);
62         writel(~0, priv->base + TIMER0_RELOAD);
63
64         if (type == INPUT_CLOCK_25MHZ) {
65                 /*
66                  * On Armada XP / 38x ..., the 25MHz clock source needs to
67                  * be enabled
68                  */
69                 setbits_le32(priv->base + TIMER_CTRL, BIT(11));
70                 uc_priv->clock_rate = MVEBU_TIMER_FIXED_RATE_25MHZ;
71         } else {
72                 uc_priv->clock_rate = CONFIG_SYS_TCLK;
73         }
74
75         /* enable timer */
76         setbits_le32(priv->base + TIMER_CTRL, TIMER0_EN | TIMER0_RELOAD_EN);
77
78         return 0;
79 }
80
81 static const struct timer_ops orion_timer_ops = {
82         .get_count = orion_timer_get_count,
83 };
84
85 static const struct udevice_id orion_timer_ids[] = {
86         { .compatible = "marvell,orion-timer", .data = INPUT_CLOCK_NON_FIXED },
87         { .compatible = "marvell,armada-370-timer", .data = INPUT_CLOCK_25MHZ },
88         { .compatible = "marvell,armada-xp-timer", .data = INPUT_CLOCK_25MHZ },
89         {}
90 };
91
92 U_BOOT_DRIVER(orion_timer) = {
93         .name   = "orion_timer",
94         .id     = UCLASS_TIMER,
95         .of_match = orion_timer_ids,
96         .probe = orion_timer_probe,
97         .ops    = &orion_timer_ops,
98         .priv_auto      = sizeof(struct orion_timer_priv),
99 };