xref: /linux/drivers/clocksource/timer-pistachio.c (revision c532de5a67a70f8533d495f8f2aaa9a0491c3ad0)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Pistachio clocksource based on general-purpose timers
4  *
5  * Copyright (C) 2015 Imagination Technologies
6  */
7 
8 #define pr_fmt(fmt) "%s: " fmt, __func__
9 
10 #include <linux/clk.h>
11 #include <linux/clocksource.h>
12 #include <linux/clockchips.h>
13 #include <linux/delay.h>
14 #include <linux/err.h>
15 #include <linux/init.h>
16 #include <linux/spinlock.h>
17 #include <linux/mfd/syscon.h>
18 #include <linux/of.h>
19 #include <linux/of_address.h>
20 #include <linux/platform_device.h>
21 #include <linux/regmap.h>
22 #include <linux/sched_clock.h>
23 #include <linux/time.h>
24 
25 /* Top level reg */
26 #define CR_TIMER_CTRL_CFG		0x00
27 #define TIMER_ME_GLOBAL			BIT(0)
28 #define CR_TIMER_REV			0x10
29 
30 /* Timer specific registers */
31 #define TIMER_CFG			0x20
32 #define TIMER_ME_LOCAL			BIT(0)
33 #define TIMER_RELOAD_VALUE		0x24
34 #define TIMER_CURRENT_VALUE		0x28
35 #define TIMER_CURRENT_OVERFLOW_VALUE	0x2C
36 #define TIMER_IRQ_STATUS		0x30
37 #define TIMER_IRQ_CLEAR			0x34
38 #define TIMER_IRQ_MASK			0x38
39 
40 #define PERIP_TIMER_CONTROL		0x90
41 
42 /* Timer specific configuration Values */
43 #define RELOAD_VALUE			0xffffffff
44 
45 struct pistachio_clocksource {
46 	void __iomem *base;
47 	raw_spinlock_t lock;
48 	struct clocksource cs;
49 };
50 
51 static struct pistachio_clocksource pcs_gpt;
52 
53 #define to_pistachio_clocksource(cs)	\
54 	container_of(cs, struct pistachio_clocksource, cs)
55 
56 static inline u32 gpt_readl(void __iomem *base, u32 offset, u32 gpt_id)
57 {
58 	return readl(base + 0x20 * gpt_id + offset);
59 }
60 
61 static inline void gpt_writel(void __iomem *base, u32 value, u32 offset,
62 		u32 gpt_id)
63 {
64 	writel(value, base + 0x20 * gpt_id + offset);
65 }
66 
67 static u64 notrace
68 pistachio_clocksource_read_cycles(struct clocksource *cs)
69 {
70 	struct pistachio_clocksource *pcs = to_pistachio_clocksource(cs);
71 	__maybe_unused u32 overflow;
72 	u32 counter;
73 	unsigned long flags;
74 
75 	/*
76 	 * The counter value is only refreshed after the overflow value is read.
77 	 * And they must be read in strict order, hence raw spin lock added.
78 	 */
79 
80 	raw_spin_lock_irqsave(&pcs->lock, flags);
81 	overflow = gpt_readl(pcs->base, TIMER_CURRENT_OVERFLOW_VALUE, 0);
82 	counter = gpt_readl(pcs->base, TIMER_CURRENT_VALUE, 0);
83 	raw_spin_unlock_irqrestore(&pcs->lock, flags);
84 
85 	return (u64)~counter;
86 }
87 
88 static u64 notrace pistachio_read_sched_clock(void)
89 {
90 	return pistachio_clocksource_read_cycles(&pcs_gpt.cs);
91 }
92 
93 static void pistachio_clksrc_set_mode(struct clocksource *cs, int timeridx,
94 			int enable)
95 {
96 	struct pistachio_clocksource *pcs = to_pistachio_clocksource(cs);
97 	u32 val;
98 
99 	val = gpt_readl(pcs->base, TIMER_CFG, timeridx);
100 	if (enable)
101 		val |= TIMER_ME_LOCAL;
102 	else
103 		val &= ~TIMER_ME_LOCAL;
104 
105 	gpt_writel(pcs->base, val, TIMER_CFG, timeridx);
106 }
107 
108 static void pistachio_clksrc_enable(struct clocksource *cs, int timeridx)
109 {
110 	struct pistachio_clocksource *pcs = to_pistachio_clocksource(cs);
111 
112 	/* Disable GPT local before loading reload value */
113 	pistachio_clksrc_set_mode(cs, timeridx, false);
114 	gpt_writel(pcs->base, RELOAD_VALUE, TIMER_RELOAD_VALUE, timeridx);
115 	pistachio_clksrc_set_mode(cs, timeridx, true);
116 }
117 
118 static void pistachio_clksrc_disable(struct clocksource *cs, int timeridx)
119 {
120 	/* Disable GPT local */
121 	pistachio_clksrc_set_mode(cs, timeridx, false);
122 }
123 
124 static int pistachio_clocksource_enable(struct clocksource *cs)
125 {
126 	pistachio_clksrc_enable(cs, 0);
127 	return 0;
128 }
129 
130 static void pistachio_clocksource_disable(struct clocksource *cs)
131 {
132 	pistachio_clksrc_disable(cs, 0);
133 }
134 
135 /* Desirable clock source for pistachio platform */
136 static struct pistachio_clocksource pcs_gpt = {
137 	.cs =	{
138 		.name		= "gptimer",
139 		.rating		= 300,
140 		.enable		= pistachio_clocksource_enable,
141 		.disable	= pistachio_clocksource_disable,
142 		.read		= pistachio_clocksource_read_cycles,
143 		.mask		= CLOCKSOURCE_MASK(32),
144 		.flags		= CLOCK_SOURCE_IS_CONTINUOUS |
145 				  CLOCK_SOURCE_SUSPEND_NONSTOP,
146 		},
147 };
148 
149 static int __init pistachio_clksrc_of_init(struct device_node *node)
150 {
151 	struct clk *sys_clk, *fast_clk;
152 	struct regmap *periph_regs;
153 	unsigned long rate;
154 	int ret;
155 
156 	pcs_gpt.base = of_iomap(node, 0);
157 	if (!pcs_gpt.base) {
158 		pr_err("cannot iomap\n");
159 		return -ENXIO;
160 	}
161 
162 	periph_regs = syscon_regmap_lookup_by_phandle(node, "img,cr-periph");
163 	if (IS_ERR(periph_regs)) {
164 		pr_err("cannot get peripheral regmap (%ld)\n",
165 		       PTR_ERR(periph_regs));
166 		return PTR_ERR(periph_regs);
167 	}
168 
169 	/* Switch to using the fast counter clock */
170 	ret = regmap_update_bits(periph_regs, PERIP_TIMER_CONTROL,
171 				 0xf, 0x0);
172 	if (ret)
173 		return ret;
174 
175 	sys_clk = of_clk_get_by_name(node, "sys");
176 	if (IS_ERR(sys_clk)) {
177 		pr_err("clock get failed (%ld)\n", PTR_ERR(sys_clk));
178 		return PTR_ERR(sys_clk);
179 	}
180 
181 	fast_clk = of_clk_get_by_name(node, "fast");
182 	if (IS_ERR(fast_clk)) {
183 		pr_err("clock get failed (%lu)\n", PTR_ERR(fast_clk));
184 		return PTR_ERR(fast_clk);
185 	}
186 
187 	ret = clk_prepare_enable(sys_clk);
188 	if (ret < 0) {
189 		pr_err("failed to enable clock (%d)\n", ret);
190 		return ret;
191 	}
192 
193 	ret = clk_prepare_enable(fast_clk);
194 	if (ret < 0) {
195 		pr_err("failed to enable clock (%d)\n", ret);
196 		clk_disable_unprepare(sys_clk);
197 		return ret;
198 	}
199 
200 	rate = clk_get_rate(fast_clk);
201 
202 	/* Disable irq's for clocksource usage */
203 	gpt_writel(pcs_gpt.base, 0, TIMER_IRQ_MASK, 0);
204 	gpt_writel(pcs_gpt.base, 0, TIMER_IRQ_MASK, 1);
205 	gpt_writel(pcs_gpt.base, 0, TIMER_IRQ_MASK, 2);
206 	gpt_writel(pcs_gpt.base, 0, TIMER_IRQ_MASK, 3);
207 
208 	/* Enable timer block */
209 	writel(TIMER_ME_GLOBAL, pcs_gpt.base);
210 
211 	raw_spin_lock_init(&pcs_gpt.lock);
212 	sched_clock_register(pistachio_read_sched_clock, 32, rate);
213 	return clocksource_register_hz(&pcs_gpt.cs, rate);
214 }
215 TIMER_OF_DECLARE(pistachio_gptimer, "img,pistachio-gptimer",
216 		       pistachio_clksrc_of_init);
217