1 /*
2  * Copyright (c) 2020 Henrik Brix Andersen <henrik@brixandersen.dk>
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT xlnx_xps_timer_1_00_a
8 
9 #include <zephyr/arch/cpu.h>
10 #include <zephyr/device.h>
11 #include <zephyr/drivers/counter.h>
12 #include <zephyr/irq.h>
13 #include <zephyr/sys/sys_io.h>
14 #include <zephyr/logging/log.h>
15 LOG_MODULE_REGISTER(xlnx_axi_timer, CONFIG_COUNTER_LOG_LEVEL);
16 
17 /* AXI Timer v2.0 registers offsets (See Xilinx PG079 for details) */
18 #define TCSR0_OFFSET 0x00
19 #define TLR0_OFFSET  0x04
20 #define TCR0_OFFSET  0x08
21 #define TCSR1_OFFSET 0x10
22 #define TLR1_OFFSET  0x14
23 #define TCR1_OFFSET  0x18
24 
25 /* TCSRx bit definitions */
26 #define TCSR_MDT   BIT(0)
27 #define TCSR_UDT   BIT(1)
28 #define TCSR_GENT  BIT(2)
29 #define TCSR_CAPT  BIT(3)
30 #define TCSR_ARHT  BIT(4)
31 #define TCSR_LOAD  BIT(5)
32 #define TCSR_ENIT  BIT(6)
33 #define TCSR_ENT   BIT(7)
34 #define TCSR_TINT  BIT(8)
35 #define TCSR_PWMA  BIT(9)
36 #define TCSR_ENALL BIT(10)
37 #define TCSR_CASC  BIT(11)
38 
39 /* 1st timer used as main timer in auto-reload, count-down. generate mode */
40 #define TCSR0_DEFAULT (TCSR_ENIT | TCSR_ARHT | TCSR_GENT | TCSR_UDT)
41 
42 /* 2nd timer (if available) used as alarm timer in count-down, generate mode */
43 #define TCSR1_DEFAULT (TCSR_ENIT | TCSR_GENT | TCSR_UDT)
44 
45 struct xlnx_axi_timer_config {
46 	struct counter_config_info info;
47 	mm_reg_t base;
48 	void (*irq_config_func)(const struct device *dev);
49 };
50 
51 struct xlnx_axi_timer_data {
52 	counter_top_callback_t top_callback;
53 	void *top_user_data;
54 	counter_alarm_callback_t alarm_callback;
55 	void *alarm_user_data;
56 };
57 
xlnx_axi_timer_read32(const struct device * dev,mm_reg_t offset)58 static inline uint32_t xlnx_axi_timer_read32(const struct device *dev,
59 					     mm_reg_t offset)
60 {
61 	const struct xlnx_axi_timer_config *config = dev->config;
62 
63 	return sys_read32(config->base + offset);
64 }
65 
xlnx_axi_timer_write32(const struct device * dev,uint32_t value,mm_reg_t offset)66 static inline void xlnx_axi_timer_write32(const struct device *dev,
67 					  uint32_t value,
68 					  mm_reg_t offset)
69 {
70 	const struct xlnx_axi_timer_config *config = dev->config;
71 
72 	sys_write32(value, config->base + offset);
73 }
74 
xlnx_axi_timer_start(const struct device * dev)75 static int xlnx_axi_timer_start(const struct device *dev)
76 {
77 	const struct xlnx_axi_timer_data *data = dev->data;
78 	uint32_t tcsr = TCSR0_DEFAULT | TCSR_ENT;
79 
80 	LOG_DBG("starting timer");
81 
82 	if (data->alarm_callback) {
83 		/* Start both timers synchronously */
84 		tcsr |= TCSR_ENALL;
85 	}
86 
87 	xlnx_axi_timer_write32(dev, tcsr, TCSR0_OFFSET);
88 
89 	return 0;
90 }
91 
xlnx_axi_timer_stop(const struct device * dev)92 static int xlnx_axi_timer_stop(const struct device *dev)
93 {
94 	const struct xlnx_axi_timer_config *config = dev->config;
95 	unsigned int key;
96 
97 	LOG_DBG("stopping timer");
98 
99 	key = irq_lock();
100 
101 	/* The timers cannot be stopped synchronously */
102 	if (config->info.channels > 0) {
103 		xlnx_axi_timer_write32(dev, TCSR1_DEFAULT, TCSR1_OFFSET);
104 	}
105 	xlnx_axi_timer_write32(dev, TCSR0_DEFAULT, TCSR0_OFFSET);
106 
107 	irq_unlock(key);
108 
109 	return 0;
110 }
111 
xlnx_axi_timer_get_value(const struct device * dev,uint32_t * ticks)112 static int xlnx_axi_timer_get_value(const struct device *dev, uint32_t *ticks)
113 {
114 
115 	*ticks = xlnx_axi_timer_read32(dev, TCR0_OFFSET);
116 
117 	return 0;
118 }
119 
xlnx_axi_timer_set_alarm(const struct device * dev,uint8_t chan_id,const struct counter_alarm_cfg * cfg)120 static int xlnx_axi_timer_set_alarm(const struct device *dev, uint8_t chan_id,
121 				    const struct counter_alarm_cfg *cfg)
122 {
123 	struct xlnx_axi_timer_data *data = dev->data;
124 	unsigned int key;
125 	uint32_t tcsr;
126 
127 	ARG_UNUSED(chan_id);
128 
129 	if (cfg->callback == NULL) {
130 		return -EINVAL;
131 	}
132 
133 	if (data->alarm_callback != NULL) {
134 		return -EBUSY;
135 	}
136 
137 	if (cfg->ticks > xlnx_axi_timer_read32(dev, TLR0_OFFSET)) {
138 		return -EINVAL;
139 	}
140 
141 	if (cfg->flags & COUNTER_ALARM_CFG_ABSOLUTE) {
142 		/*
143 		 * Since two different timers (with the same clock signal) are
144 		 * used for main timer and alarm timer we cannot support
145 		 * absolute alarms in a reliable way.
146 		 */
147 		return -ENOTSUP;
148 	}
149 
150 	LOG_DBG("triggering alarm in 0x%08x ticks", cfg->ticks);
151 
152 	/* Load alarm timer */
153 	xlnx_axi_timer_write32(dev, cfg->ticks, TLR1_OFFSET);
154 	xlnx_axi_timer_write32(dev, TCSR1_DEFAULT | TCSR_LOAD, TCSR1_OFFSET);
155 
156 	key = irq_lock();
157 
158 	data->alarm_callback = cfg->callback;
159 	data->alarm_user_data = cfg->user_data;
160 
161 	/* Enable alarm timer only if main timer already enabled */
162 	tcsr = xlnx_axi_timer_read32(dev, TCSR0_OFFSET);
163 	tcsr &= TCSR_ENT;
164 	xlnx_axi_timer_write32(dev, TCSR1_DEFAULT | tcsr, TCSR1_OFFSET);
165 
166 	irq_unlock(key);
167 
168 	return 0;
169 }
170 
xlnx_axi_timer_cancel_alarm(const struct device * dev,uint8_t chan_id)171 static int xlnx_axi_timer_cancel_alarm(const struct device *dev,
172 				       uint8_t chan_id)
173 {
174 	struct xlnx_axi_timer_data *data = dev->data;
175 
176 	ARG_UNUSED(chan_id);
177 
178 	LOG_DBG("cancelling alarm");
179 
180 	xlnx_axi_timer_write32(dev, TCSR1_DEFAULT, TCSR1_OFFSET);
181 	data->alarm_callback = NULL;
182 	data->alarm_user_data = NULL;
183 
184 	return 0;
185 }
186 
xlnx_axi_timer_set_top_value(const struct device * dev,const struct counter_top_cfg * cfg)187 static int xlnx_axi_timer_set_top_value(const struct device *dev,
188 					const struct counter_top_cfg *cfg)
189 {
190 	struct xlnx_axi_timer_data *data = dev->data;
191 	bool reload = true;
192 	uint32_t tcsr;
193 	uint32_t now;
194 
195 	if (cfg->ticks == 0) {
196 		return -EINVAL;
197 	}
198 
199 	if (data->alarm_callback) {
200 		return -EBUSY;
201 	}
202 
203 	LOG_DBG("setting top value to 0x%08x", cfg->ticks);
204 
205 	data->top_callback = cfg->callback;
206 	data->top_user_data = cfg->user_data;
207 
208 	if (cfg->flags & COUNTER_TOP_CFG_DONT_RESET) {
209 		reload = false;
210 
211 		if (cfg->flags & COUNTER_TOP_CFG_RESET_WHEN_LATE) {
212 			now = xlnx_axi_timer_read32(dev, TCR0_OFFSET);
213 			reload = cfg->ticks < now;
214 		}
215 	}
216 
217 	tcsr = xlnx_axi_timer_read32(dev, TCSR0_OFFSET);
218 	if ((tcsr & TCSR_ENT) == 0U) {
219 		/* Timer not enabled, force reload of new top value */
220 		reload = true;
221 	}
222 
223 	xlnx_axi_timer_write32(dev, cfg->ticks, TLR0_OFFSET);
224 
225 	if (reload) {
226 		xlnx_axi_timer_write32(dev, tcsr | TCSR_LOAD, TCSR0_OFFSET);
227 		xlnx_axi_timer_write32(dev, tcsr, TCSR0_OFFSET);
228 	}
229 
230 	return 0;
231 }
232 
xlnx_axi_timer_get_pending_int(const struct device * dev)233 static uint32_t xlnx_axi_timer_get_pending_int(const struct device *dev)
234 {
235 	const struct xlnx_axi_timer_config *config = dev->config;
236 	uint32_t pending = 0;
237 	uint32_t tcsr;
238 
239 	tcsr = xlnx_axi_timer_read32(dev, TCSR0_OFFSET);
240 	if (tcsr & TCSR_TINT) {
241 		pending = 1;
242 	}
243 
244 	if (config->info.channels > 0) {
245 		tcsr = xlnx_axi_timer_read32(dev, TCSR1_OFFSET);
246 		if (tcsr & TCSR_TINT) {
247 			pending = 1;
248 		}
249 	}
250 
251 	LOG_DBG("%sinterrupt pending", pending ? "" : "no ");
252 
253 	return pending;
254 }
255 
xlnx_axi_timer_get_top_value(const struct device * dev)256 static uint32_t xlnx_axi_timer_get_top_value(const struct device *dev)
257 {
258 	return xlnx_axi_timer_read32(dev, TLR0_OFFSET);
259 }
260 
xlnx_axi_timer_isr(const struct device * dev)261 static void xlnx_axi_timer_isr(const struct device *dev)
262 {
263 	struct xlnx_axi_timer_data *data = dev->data;
264 	counter_alarm_callback_t alarm_cb;
265 	uint32_t tcsr;
266 	uint32_t now;
267 
268 	tcsr = xlnx_axi_timer_read32(dev, TCSR1_OFFSET);
269 	if (tcsr & TCSR_TINT) {
270 		xlnx_axi_timer_write32(dev, TCSR1_DEFAULT | TCSR_TINT,
271 				       TCSR1_OFFSET);
272 
273 		if (data->alarm_callback) {
274 			now = xlnx_axi_timer_read32(dev, TCR0_OFFSET);
275 			alarm_cb = data->alarm_callback;
276 			data->alarm_callback = NULL;
277 
278 			alarm_cb(dev, 0, now, data->alarm_user_data);
279 		}
280 	}
281 
282 	tcsr = xlnx_axi_timer_read32(dev, TCSR0_OFFSET);
283 	if (tcsr & TCSR_TINT) {
284 		xlnx_axi_timer_write32(dev, tcsr, TCSR0_OFFSET);
285 
286 		if (data->top_callback) {
287 			data->top_callback(dev, data->top_user_data);
288 		}
289 	}
290 }
291 
xlnx_axi_timer_init(const struct device * dev)292 static int xlnx_axi_timer_init(const struct device *dev)
293 {
294 	const struct xlnx_axi_timer_config *config = dev->config;
295 
296 	LOG_DBG("max top value = 0x%08x", config->info.max_top_value);
297 	LOG_DBG("frequency = %d", config->info.freq);
298 	LOG_DBG("channels = %d", config->info.channels);
299 
300 	xlnx_axi_timer_write32(dev, config->info.max_top_value, TLR0_OFFSET);
301 	xlnx_axi_timer_write32(dev, TCSR0_DEFAULT | TCSR_LOAD, TCSR0_OFFSET);
302 
303 	if (config->info.channels > 0) {
304 		xlnx_axi_timer_write32(dev, TCSR1_DEFAULT, TCSR1_OFFSET);
305 	}
306 
307 	config->irq_config_func(dev);
308 
309 	return 0;
310 }
311 
312 static DEVICE_API(counter, xlnx_axi_timer_driver_api) = {
313 	.start = xlnx_axi_timer_start,
314 	.stop = xlnx_axi_timer_stop,
315 	.get_value = xlnx_axi_timer_get_value,
316 	.set_alarm = xlnx_axi_timer_set_alarm,
317 	.cancel_alarm = xlnx_axi_timer_cancel_alarm,
318 	.set_top_value = xlnx_axi_timer_set_top_value,
319 	.get_pending_int = xlnx_axi_timer_get_pending_int,
320 	.get_top_value = xlnx_axi_timer_get_top_value,
321 };
322 
323 #define XLNX_AXI_TIMER_INIT(n)						\
324 	static void xlnx_axi_timer_config_func_##n(const struct device *dev); \
325 									\
326 	static struct xlnx_axi_timer_config xlnx_axi_timer_config_##n = { \
327 		.info = {						\
328 			.max_top_value =				\
329 			GENMASK(DT_INST_PROP(n, xlnx_count_width) - 1, 0), \
330 			.freq = DT_INST_PROP(n, clock_frequency),	\
331 			.flags = 0,					\
332 			.channels =					\
333 			COND_CODE_1(DT_INST_PROP(n, xlnx_one_timer_only), \
334 				    (0), (1)),				\
335 		},							\
336 		.base = DT_INST_REG_ADDR(n),				\
337 		.irq_config_func = xlnx_axi_timer_config_func_##n,	\
338 	};								\
339 									\
340 	static struct xlnx_axi_timer_data xlnx_axi_timer_data_##n;	\
341 									\
342 	DEVICE_DT_INST_DEFINE(n, &xlnx_axi_timer_init,			\
343 			NULL,						\
344 			&xlnx_axi_timer_data_##n,			\
345 			&xlnx_axi_timer_config_##n,			\
346 			POST_KERNEL,					\
347 			CONFIG_COUNTER_INIT_PRIORITY,			\
348 			&xlnx_axi_timer_driver_api);			\
349 									\
350 	static void xlnx_axi_timer_config_func_##n(const struct device *dev) \
351 	{								\
352 		IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority),	\
353 			    xlnx_axi_timer_isr,				\
354 			    DEVICE_DT_INST_GET(n), 0);			\
355 		irq_enable(DT_INST_IRQN(n));				\
356 	}
357 
358 DT_INST_FOREACH_STATUS_OKAY(XLNX_AXI_TIMER_INIT)
359