1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * Copyright (c) 2022 Nuvoton Technology Corp.
4 */
5
6 #include <dm.h>
7 #include <timer.h>
8 #include <asm/io.h>
9
10 #define NPCM_TIMER_CLOCK_RATE 25000000UL /* 25MHz */
11
12 /* Register offsets */
13 #define SECCNT 0x0 /* Seconds Counter Register */
14 #define CNTR25M 0x4 /* 25MHz Counter Register */
15
16 struct npcm_timer_priv {
17 void __iomem *base;
18 };
19
npcm_timer_get_count(struct udevice * dev)20 static u64 npcm_timer_get_count(struct udevice *dev)
21 {
22 struct npcm_timer_priv *priv = dev_get_priv(dev);
23 u64 reg_sec, reg_25m;
24 u64 counter;
25
26 reg_sec = readl(priv->base + SECCNT);
27 reg_25m = readl(priv->base + CNTR25M);
28 /*
29 * When CNTR25M reaches 25M, it goes to 0 and SECCNT is increased by 1.
30 * When CNTR25M is zero, wait for CNTR25M to become non-zero in case
31 * SECCNT is not updated yet.
32 */
33 if (reg_25m == 0) {
34 while (reg_25m == 0)
35 reg_25m = readl(priv->base + CNTR25M);
36 reg_sec = readl(priv->base + SECCNT);
37 }
38 counter = reg_sec * NPCM_TIMER_CLOCK_RATE + reg_25m;
39
40 return counter;
41 }
42
npcm_timer_probe(struct udevice * dev)43 static int npcm_timer_probe(struct udevice *dev)
44 {
45 struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
46 struct npcm_timer_priv *priv = dev_get_priv(dev);
47
48 priv->base = dev_read_addr_ptr(dev);
49 if (!priv->base)
50 return -EINVAL;
51 uc_priv->clock_rate = NPCM_TIMER_CLOCK_RATE;
52
53 return 0;
54 }
55
56 static const struct timer_ops npcm_timer_ops = {
57 .get_count = npcm_timer_get_count,
58 };
59
60 static const struct udevice_id npcm_timer_ids[] = {
61 { .compatible = "nuvoton,npcm845-timer"},
62 { .compatible = "nuvoton,npcm750-timer"},
63 {}
64 };
65
66 U_BOOT_DRIVER(npcm_timer) = {
67 .name = "npcm_timer",
68 .id = UCLASS_TIMER,
69 .of_match = npcm_timer_ids,
70 .priv_auto = sizeof(struct npcm_timer_priv),
71 .probe = npcm_timer_probe,
72 .ops = &npcm_timer_ops,
73 .flags = DM_FLAG_PRE_RELOC,
74 };
75