1 /*
2  * Copyright (c) 2023 Intel Corporation.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT snps_dw_timers
8 
9 #include <zephyr/device.h>
10 #include <zephyr/drivers/counter.h>
11 #include <zephyr/spinlock.h>
12 #include <zephyr/logging/log.h>
13 #include <zephyr/drivers/reset.h>
14 #include <zephyr/drivers/clock_control.h>
15 
16 LOG_MODULE_REGISTER(dw_timer, CONFIG_COUNTER_LOG_LEVEL);
17 
18 static int counter_dw_timer_get_value(const struct device *timer_dev, uint32_t *ticks);
19 
20 /* DW APB timer register offsets */
21 #define LOADCOUNT_OFST           0x0
22 #define CURRENTVAL_OFST          0x4
23 #define CONTROLREG_OFST          0x8
24 #define EOI_OFST                 0xc
25 #define INTSTAT_OFST             0x10
26 
27 /* free running mode value */
28 #define FREE_RUNNING_MODE_VAL 0xFFFFFFFFUL
29 
30 /* DW APB timer control flags */
31 #define TIMER_CONTROL_ENABLE_BIT    0
32 #define TIMER_MODE_BIT              1
33 #define TIMER_INTR_MASK_BIT         2
34 
35 /* DW APB timer modes */
36 #define USER_DEFINED_MODE       1
37 #define FREE_RUNNING_MODE       0
38 
39 #define DEV_CFG(_dev) ((const struct counter_dw_timer_config *)(_dev)->config)
40 #define DEV_DATA(_dev) ((struct counter_dw_timer_drv_data *const)(_dev)->data)
41 
42 /* Device Configuration */
43 struct counter_dw_timer_config {
44 	struct counter_config_info info;
45 
46 	DEVICE_MMIO_NAMED_ROM(timer_mmio);
47 
48 	/* clock frequency of timer */
49 	uint32_t freq;
50 #if DT_ANY_INST_HAS_PROP_STATUS_OKAY(clocks)
51 	/* clock controller dev instance */
52 	const struct device *clk_dev;
53 	/* identifier for timer to get clock freq from clk manager */
54 	clock_control_subsys_t clkid;
55 #endif
56 
57 #if DT_ANY_INST_HAS_PROP_STATUS_OKAY(resets)
58 	/* reset controller device configuration*/
59 	const struct reset_dt_spec reset;
60 #endif
61 
62 	/* interrupt config function ptr */
63 	void (*irq_config)(void);
64 };
65 
66 /* Driver data */
67 struct counter_dw_timer_drv_data {
68 	/* mmio address mapping info */
69 	DEVICE_MMIO_NAMED_RAM(timer_mmio);
70 #if DT_ANY_INST_HAS_PROP_STATUS_OKAY(clocks)
71 	/* clock frequency of timer */
72 	uint32_t freq;
73 #endif
74 	/* spin lock to protect user data */
75 	struct k_spinlock lock;
76 	/* top callback function */
77 	counter_top_callback_t top_cb;
78 	/* alarm callback function */
79 	counter_alarm_callback_t alarm_cb;
80 	/* private user data */
81 	void *prv_data;
82 };
83 
counter_dw_timer_irq_handler(const struct device * timer_dev)84 static void counter_dw_timer_irq_handler(const struct device *timer_dev)
85 {
86 	uint32_t ticks = 0;
87 	uintptr_t reg_base = DEVICE_MMIO_NAMED_GET(timer_dev, timer_mmio);
88 	struct counter_dw_timer_drv_data *const data = DEV_DATA(timer_dev);
89 	k_spinlock_key_t key;
90 	counter_alarm_callback_t alarm_cb = data->alarm_cb;
91 
92 	/* read EOI register to clear interrupt flag */
93 	sys_read32(reg_base + EOI_OFST);
94 
95 	counter_dw_timer_get_value(timer_dev, &ticks);
96 
97 	key = k_spin_lock(&data->lock);
98 
99 	/* In case of alarm, mask interrupt and disable the callback. User
100 	 * can configure the alarm in same context within callback function.
101 	 */
102 	if (data->alarm_cb) {
103 		sys_set_bit(reg_base + CONTROLREG_OFST, TIMER_INTR_MASK_BIT);
104 
105 		data->alarm_cb = NULL;
106 		alarm_cb(timer_dev, 0, ticks, data->prv_data);
107 
108 	} else if (data->top_cb) {
109 		data->top_cb(timer_dev, data->prv_data);
110 	}
111 
112 	k_spin_unlock(&data->lock, key);
113 }
114 
counter_dw_timer_start(const struct device * dev)115 static int counter_dw_timer_start(const struct device *dev)
116 {
117 	uintptr_t reg_base = DEVICE_MMIO_NAMED_GET(dev, timer_mmio);
118 
119 	/* disable timer before starting in free-running mode */
120 	sys_clear_bit(reg_base + CONTROLREG_OFST, TIMER_CONTROL_ENABLE_BIT);
121 
122 	/* starting timer in free running mode */
123 	sys_clear_bit(reg_base + CONTROLREG_OFST, TIMER_MODE_BIT);
124 	sys_set_bit(reg_base + CONTROLREG_OFST, TIMER_INTR_MASK_BIT);
125 	sys_write32(FREE_RUNNING_MODE_VAL, reg_base + LOADCOUNT_OFST);
126 
127 	/* enable timer */
128 	sys_set_bit(reg_base + CONTROLREG_OFST, TIMER_CONTROL_ENABLE_BIT);
129 	return 0;
130 }
131 
counter_dw_timer_disable(const struct device * dev)132 int counter_dw_timer_disable(const struct device *dev)
133 {
134 	uintptr_t reg_base = DEVICE_MMIO_NAMED_GET(dev, timer_mmio);
135 
136 	/* stop timer */
137 	sys_clear_bit(reg_base + CONTROLREG_OFST, TIMER_CONTROL_ENABLE_BIT);
138 	return 0;
139 }
140 
counter_dw_timer_get_top_value(const struct device * timer_dev)141 static uint32_t counter_dw_timer_get_top_value(const struct device *timer_dev)
142 {
143 	uint32_t top_val = 0;
144 	uintptr_t reg_base = DEVICE_MMIO_NAMED_GET(timer_dev, timer_mmio);
145 
146 	/* get the current top value from load count register */
147 	top_val = sys_read32(reg_base + LOADCOUNT_OFST);
148 
149 	return top_val;
150 }
151 
counter_dw_timer_get_value(const struct device * timer_dev,uint32_t * ticks)152 static int counter_dw_timer_get_value(const struct device *timer_dev, uint32_t *ticks)
153 {
154 	uintptr_t reg_base = DEVICE_MMIO_NAMED_GET(timer_dev, timer_mmio);
155 
156 	/* current value of the current value register */
157 	*ticks = sys_read32(reg_base + CURRENTVAL_OFST);
158 
159 	return 0;
160 }
161 
counter_dw_timer_set_top_value(const struct device * timer_dev,const struct counter_top_cfg * top_cfg)162 static int counter_dw_timer_set_top_value(const struct device *timer_dev,
163 					const struct counter_top_cfg *top_cfg)
164 {
165 	uintptr_t reg_base = DEVICE_MMIO_NAMED_GET(timer_dev, timer_mmio);
166 	struct counter_dw_timer_drv_data *const data = DEV_DATA(timer_dev);
167 	k_spinlock_key_t key;
168 
169 	if (top_cfg == NULL) {
170 		LOG_ERR("Invalid top value configuration");
171 		return -EINVAL;
172 	}
173 
174 	/* top value cannot be updated without reset */
175 	if (top_cfg->flags & COUNTER_TOP_CFG_DONT_RESET) {
176 		LOG_ERR("Updating top value without reset is not supported");
177 		return -ENOTSUP;
178 	}
179 
180 	key = k_spin_lock(&data->lock);
181 
182 	/* top value cannot be updated if the alarm is active */
183 	if (data->alarm_cb) {
184 		k_spin_unlock(&data->lock, key);
185 		LOG_ERR("Top value cannot be updated, alarm is active!");
186 		return -EBUSY;
187 	}
188 
189 	if (!top_cfg->callback) {
190 		/* mask an interrupt if callback is not passed */
191 		sys_set_bit(reg_base + CONTROLREG_OFST, TIMER_INTR_MASK_BIT);
192 	} else {
193 		/* unmask interrupt if callback is passed */
194 		sys_clear_bit(reg_base + CONTROLREG_OFST, TIMER_INTR_MASK_BIT);
195 	}
196 
197 	data->top_cb = top_cfg->callback;
198 	data->prv_data = top_cfg->user_data;
199 
200 	/* top value can be loaded only when timer is stopped and re-enabled */
201 	sys_clear_bit(reg_base + CONTROLREG_OFST, TIMER_CONTROL_ENABLE_BIT);
202 
203 	/* configuring timer in user-defined mode */
204 	sys_set_bit(reg_base + CONTROLREG_OFST, TIMER_MODE_BIT);
205 
206 	/* set new top value */
207 	sys_write32(top_cfg->ticks, reg_base + LOADCOUNT_OFST);
208 	sys_set_bit(reg_base + CONTROLREG_OFST, TIMER_CONTROL_ENABLE_BIT);
209 
210 	k_spin_unlock(&data->lock, key);
211 
212 	return 0;
213 }
214 
counter_dw_timer_set_alarm(const struct device * timer_dev,uint8_t chan_id,const struct counter_alarm_cfg * alarm_cfg)215 static int counter_dw_timer_set_alarm(const struct device *timer_dev, uint8_t chan_id,
216 				 const struct counter_alarm_cfg *alarm_cfg)
217 {
218 	ARG_UNUSED(chan_id);
219 	uintptr_t reg_base = DEVICE_MMIO_NAMED_GET(timer_dev, timer_mmio);
220 	struct counter_dw_timer_drv_data *const data = DEV_DATA(timer_dev);
221 	k_spinlock_key_t key;
222 
223 	if (alarm_cfg == NULL) {
224 		LOG_ERR("Invalid alarm configuration");
225 		return -EINVAL;
226 	}
227 
228 	/* Alarm callback is mandatory */
229 	if (!alarm_cfg->callback) {
230 		LOG_ERR("Alarm callback function cannot be null");
231 		return -EINVAL;
232 	}
233 
234 	/* absolute alarm is not supported as interrupts are triggered
235 	 * only when the counter reaches 0(downcounter)
236 	 */
237 	if (alarm_cfg->flags & COUNTER_ALARM_CFG_ABSOLUTE) {
238 		LOG_ERR("Absolute alarm is not supported");
239 		return -ENOTSUP;
240 	}
241 
242 	key = k_spin_lock(&data->lock);
243 
244 	/* check if alarm is already active */
245 	if (data->alarm_cb != NULL) {
246 		LOG_ERR("Alarm is already active\n");
247 		k_spin_unlock(&data->lock, key);
248 		return -EBUSY;
249 	}
250 
251 	data->alarm_cb = alarm_cfg->callback;
252 	data->prv_data = alarm_cfg->user_data;
253 
254 	sys_clear_bit(reg_base + CONTROLREG_OFST, TIMER_CONTROL_ENABLE_BIT);
255 
256 	/* start timer in user-defined mode */
257 	sys_set_bit(reg_base + CONTROLREG_OFST, TIMER_MODE_BIT);
258 	sys_clear_bit(reg_base + CONTROLREG_OFST, TIMER_INTR_MASK_BIT);
259 
260 	sys_write32(alarm_cfg->ticks, reg_base + LOADCOUNT_OFST);
261 	sys_set_bit(reg_base + CONTROLREG_OFST, TIMER_CONTROL_ENABLE_BIT);
262 
263 	k_spin_unlock(&data->lock, key);
264 
265 	return 0;
266 }
267 
counter_dw_timer_cancel_alarm(const struct device * timer_dev,uint8_t chan_id)268 static int counter_dw_timer_cancel_alarm(const struct device *timer_dev, uint8_t chan_id)
269 {
270 	ARG_UNUSED(chan_id);
271 	uintptr_t reg_base = DEVICE_MMIO_NAMED_GET(timer_dev, timer_mmio);
272 	struct counter_dw_timer_drv_data *const data = DEV_DATA(timer_dev);
273 	k_spinlock_key_t key;
274 
275 	key = k_spin_lock(&data->lock);
276 
277 	sys_write32(0, reg_base + CONTROLREG_OFST);
278 
279 	data->alarm_cb = NULL;
280 	data->prv_data = NULL;
281 
282 	k_spin_unlock(&data->lock, key);
283 
284 	return 0;
285 }
286 
counter_dw_timer_get_freq(const struct device * timer_dev)287 uint32_t counter_dw_timer_get_freq(const struct device *timer_dev)
288 {
289 #if DT_ANY_INST_HAS_PROP_STATUS_OKAY(clocks)
290 	struct counter_dw_timer_drv_data *const data = DEV_DATA(timer_dev);
291 
292 	return data->freq;
293 #else
294 	const struct counter_dw_timer_config *config = DEV_CFG(timer_dev);
295 
296 	return config->freq;
297 #endif
298 }
299 
300 static DEVICE_API(counter, dw_timer_driver_api) = {
301 	.start = counter_dw_timer_start,
302 	.stop = counter_dw_timer_disable,
303 	.get_value = counter_dw_timer_get_value,
304 	.set_top_value = counter_dw_timer_set_top_value,
305 	.get_top_value = counter_dw_timer_get_top_value,
306 	.set_alarm = counter_dw_timer_set_alarm,
307 	.cancel_alarm = counter_dw_timer_cancel_alarm,
308 	.get_freq = counter_dw_timer_get_freq,
309 };
310 
counter_dw_timer_init(const struct device * timer_dev)311 static int counter_dw_timer_init(const struct device *timer_dev)
312 {
313 	DEVICE_MMIO_NAMED_MAP(timer_dev, timer_mmio, K_MEM_CACHE_NONE);
314 	const struct counter_dw_timer_config *timer_config = DEV_CFG(timer_dev);
315 #if DT_ANY_INST_HAS_PROP_STATUS_OKAY(clocks) || DT_ANY_INST_HAS_PROP_STATUS_OKAY(resets)
316 	int ret;
317 #endif
318 
319 	/*
320 	 * get clock rate from clock_frequency property if valid,
321 	 * otherwise, get clock rate from clock manager
322 	 */
323 #if DT_ANY_INST_HAS_PROP_STATUS_OKAY(clocks)
324 	struct counter_dw_timer_drv_data *const data = DEV_DATA(timer_dev);
325 
326 	if (!device_is_ready(timer_config->clk_dev)) {
327 		LOG_ERR("clock controller device not ready");
328 		return -ENODEV;
329 	}
330 	ret = clock_control_get_rate(timer_config->clk_dev,
331 					timer_config->clkid, &data->freq);
332 	if (ret != 0) {
333 		LOG_ERR("Unable to get clock rate: err:%d", ret);
334 		return ret;
335 	}
336 #endif
337 
338 	/* Reset timer only if reset controller driver is supported */
339 #if DT_ANY_INST_HAS_PROP_STATUS_OKAY(resets)
340 	if (timer_config->reset.dev != NULL) {
341 		if (!device_is_ready(timer_config->reset.dev)) {
342 			LOG_ERR("Reset controller device not ready");
343 			return -ENODEV;
344 		}
345 
346 		ret = reset_line_toggle(timer_config->reset.dev, timer_config->reset.id);
347 		if (ret != 0) {
348 			LOG_ERR("Timer reset failed");
349 			return ret;
350 		}
351 	}
352 #endif
353 
354 	timer_config->irq_config();
355 
356 	return 0;
357 }
358 
359 #define DW_SNPS_TIMER_CLOCK_RATE_INIT(inst)							\
360 	COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, clock_frequency),				\
361 		(										\
362 			.freq = DT_INST_PROP(inst, clock_frequency),				\
363 		),										\
364 		(										\
365 			.freq = 0,								\
366 			.clk_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(inst)),			\
367 			.clkid = (clock_control_subsys_t)DT_INST_CLOCKS_CELL(inst, clkid),	\
368 		)										\
369 	)
370 
371 #define DW_SNPS_TIMER_SNPS_RESET_SPEC_INIT(inst)				\
372 	.reset = RESET_DT_SPEC_INST_GET(inst),					\
373 
374 #define CREATE_DW_TIMER_DEV(inst)						\
375 	static void counter_dw_timer_irq_config_##inst(void); \
376 	static struct counter_dw_timer_drv_data timer_data_##inst;		\
377 	static const struct counter_dw_timer_config timer_config_##inst = {	\
378 		DEVICE_MMIO_NAMED_ROM_INIT(timer_mmio, DT_DRV_INST(inst)),	\
379 		DW_SNPS_TIMER_CLOCK_RATE_INIT(inst)				\
380 		.info = {							\
381 					.max_top_value = UINT32_MAX,		\
382 					.channels = 1,				\
383 		},								\
384 		IF_ENABLED(DT_INST_NODE_HAS_PROP(inst, resets),			\
385 			(DW_SNPS_TIMER_SNPS_RESET_SPEC_INIT(inst)))		\
386 		.irq_config = counter_dw_timer_irq_config_##inst,		\
387 	};									\
388 	DEVICE_DT_INST_DEFINE(inst,						\
389 			counter_dw_timer_init,					\
390 			NULL, &timer_data_##inst,				\
391 			&timer_config_##inst, POST_KERNEL,			\
392 			CONFIG_COUNTER_INIT_PRIORITY,				\
393 			&dw_timer_driver_api);					\
394 	static void counter_dw_timer_irq_config_##inst(void)			\
395 	{									\
396 		IRQ_CONNECT(DT_INST_IRQN(inst),					\
397 				DT_INST_IRQ(inst, priority),			\
398 				counter_dw_timer_irq_handler,			\
399 				DEVICE_DT_INST_GET(inst), 0);			\
400 		irq_enable(DT_INST_IRQN(inst));					\
401 	}
402 
403 DT_INST_FOREACH_STATUS_OKAY(CREATE_DW_TIMER_DEV);
404