1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c) 2022 Nuvoton Technology Corp.
4  */
5 
6 #include <common.h>
7 #include <clk.h>
8 #include <dm.h>
9 #include <timer.h>
10 #include <asm/io.h>
11 
12 #define NPCM_TIMER_CLOCK_RATE	1000000UL		/* 1MHz timer */
13 #define NPCM_TIMER_INPUT_RATE	25000000UL		/* Rate of input clock */
14 #define NPCM_TIMER_TDR_MASK	GENMASK(23, 0)
15 #define NPCM_TIMER_MAX_VAL	NPCM_TIMER_TDR_MASK	/* max counter value */
16 
17 /* Register offsets */
18 #define TCR0	0x0	/* Timer Control and Status Register */
19 #define TICR0	0x8	/* Timer Initial Count Register */
20 #define TDR0	0x10	/* Timer Data Register */
21 
22 /* TCR fields */
23 #define TCR_MODE_PERIODIC	BIT(27)
24 #define TCR_EN			BIT(30)
25 #define TCR_PRESCALE		(NPCM_TIMER_INPUT_RATE / NPCM_TIMER_CLOCK_RATE - 1)
26 
27 enum input_clock_type {
28 	INPUT_CLOCK_FIXED,	/* input clock rate is fixed */
29 	INPUT_CLOCK_NON_FIXED
30 };
31 
32 /**
33  * struct npcm_timer_priv - private data for npcm timer driver
34  * npcm timer is a 24-bits down-counting timer.
35  *
36  * @last_count: last hw counter value
37  * @counter: the value to be returned for get_count ops
38  */
39 struct npcm_timer_priv {
40 	void __iomem *base;
41 	u32 last_count;
42 	u64 counter;
43 };
44 
npcm_timer_get_count(struct udevice * dev)45 static u64 npcm_timer_get_count(struct udevice *dev)
46 {
47 	struct npcm_timer_priv *priv = dev_get_priv(dev);
48 	u32 val;
49 
50 	/* The timer is counting down */
51 	val = readl(priv->base + TDR0) & NPCM_TIMER_TDR_MASK;
52 	if (val <= priv->last_count)
53 		priv->counter += priv->last_count - val;
54 	else
55 		priv->counter += priv->last_count + (NPCM_TIMER_MAX_VAL + 1 - val);
56 	priv->last_count = val;
57 
58 	return priv->counter;
59 }
60 
npcm_timer_probe(struct udevice * dev)61 static int npcm_timer_probe(struct udevice *dev)
62 {
63 	struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
64 	struct npcm_timer_priv *priv = dev_get_priv(dev);
65 	enum input_clock_type type = dev_get_driver_data(dev);
66 	struct clk clk;
67 	int ret;
68 
69 	priv->base = dev_read_addr_ptr(dev);
70 	if (!priv->base)
71 		return -EINVAL;
72 	uc_priv->clock_rate = NPCM_TIMER_CLOCK_RATE;
73 
74 	if (type == INPUT_CLOCK_NON_FIXED) {
75 		ret = clk_get_by_index(dev, 0, &clk);
76 		if (ret < 0)
77 			return ret;
78 
79 		ret = clk_set_rate(&clk, NPCM_TIMER_INPUT_RATE);
80 		if (ret < 0)
81 			return ret;
82 	}
83 
84 	/*
85 	 * Configure timer and start
86 	 * periodic mode
87 	 * timer clock rate = input clock / prescale
88 	 */
89 	writel(0, priv->base + TCR0);
90 	writel(NPCM_TIMER_MAX_VAL, priv->base + TICR0);
91 	writel(TCR_EN | TCR_MODE_PERIODIC | TCR_PRESCALE,
92 	       priv->base + TCR0);
93 
94 	return 0;
95 }
96 
97 static const struct timer_ops npcm_timer_ops = {
98 	.get_count = npcm_timer_get_count,
99 };
100 
101 static const struct udevice_id npcm_timer_ids[] = {
102 	{ .compatible = "nuvoton,npcm845-timer", .data = INPUT_CLOCK_FIXED},
103 	{ .compatible = "nuvoton,npcm750-timer", .data = INPUT_CLOCK_NON_FIXED},
104 	{}
105 };
106 
107 U_BOOT_DRIVER(npcm_timer) = {
108 	.name	= "npcm_timer",
109 	.id	= UCLASS_TIMER,
110 	.of_match = npcm_timer_ids,
111 	.priv_auto = sizeof(struct npcm_timer_priv),
112 	.probe = npcm_timer_probe,
113 	.ops	= &npcm_timer_ops,
114 	.flags = DM_FLAG_PRE_RELOC,
115 };
116