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