1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
|
/*
* Copyright (c) 2006-2024, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2024/08/08 ShichengChu first version
*/
#include <rtthread.h>
#include <rtdevice.h>
#include "drv_timer.h"
#define DBG_LEVEL DBG_LOG
#include <rtdbg.h>
#define LOG_TAG "DRV.TIMER"
#include "pinctrl.h"
#include "mmio.h"
#include "drv_ioremap.h"
#define DW_NR_TIMERS 8
#define TIMER_FREQ 25000000
#define DW_TIMER_GET_RELOAD_VAL(_tim_, _frq_) ((_tim_ < 25000U) ? ((_frq_ * _tim_) / 1000U) : (_frq_ * (_tim_ / 1000U)))
#define DW_TIMER0_BASE 0x030A0000UL
#define DW_TIMER0_SIZE 0x14U
#define DW_TIMER1_BASE (DW_TIMER0_BASE+DW_TIMER0_SIZE)
#define DW_TIMER1_SIZE DW_TIMER0_SIZE
#define DW_TIMER2_BASE (DW_TIMER1_BASE+DW_TIMER1_SIZE)
#define DW_TIMER2_SIZE DW_TIMER1_SIZE
#define DW_TIMER3_BASE (DW_TIMER2_BASE+DW_TIMER2_SIZE)
#define DW_TIMER3_SIZE DW_TIMER2_SIZE
#define DW_TIMER4_BASE (DW_TIMER3_BASE+DW_TIMER3_SIZE)
#define DW_TIMER4_SIZE DW_TIMER3_SIZE
#define DW_TIMER5_BASE (DW_TIMER4_BASE+DW_TIMER4_SIZE)
#define DW_TIMER5_SIZE DW_TIMER4_SIZE
#define DW_TIMER6_BASE (DW_TIMER5_BASE+DW_TIMER5_SIZE)
#define DW_TIMER6_SIZE DW_TIMER5_SIZE
#define DW_TIMER7_BASE (DW_TIMER6_BASE+DW_TIMER6_SIZE)
#define DW_TIMER7_SIZE DW_TIMER6_SIZE
#if defined(BSP_USING_CV18XX) || defined(SOC_CV18XX_AARCH64)
#define TIMER_INTR_0 BSP_TIMER_IRQ_BASE + 0
#define TIMER_INTR_1 BSP_TIMER_IRQ_BASE + 1
#define TIMER_INTR_2 BSP_TIMER_IRQ_BASE + 2
#define TIMER_INTR_3 BSP_TIMER_IRQ_BASE + 3
#define TIMER_INTR_4 BSP_TIMER_IRQ_BASE + 4
#define TIMER_INTR_5 BSP_TIMER_IRQ_BASE + 5
#define TIMER_INTR_6 BSP_TIMER_IRQ_BASE + 6
#define TIMER_INTR_7 BSP_TIMER_IRQ_BASE + 7
#elif defined(BSP_USING_C906_LITTLE)
#define TIMER_INTR_4 BSP_TIMER_IRQ_BASE + 0
#define TIMER_INTR_5 BSP_TIMER_IRQ_BASE + 1
#define TIMER_INTR_6 BSP_TIMER_IRQ_BASE + 2
#define TIMER_INTR_7 BSP_TIMER_IRQ_BASE + 3
#else
#error "Unsupported CPU type!"
#endif
/*! Timer1 Control Reg, offset: 0x08 */
#define DW_TIMER_CTL_ENABLE_SEL_Pos (0U)
#define DW_TIMER_CTL_ENABLE_SEL_Msk (0x1U << DW_TIMER_CTL_ENABLE_SEL_Pos)
#define DW_TIMER_CTL_ENABLE_SEL_EN DW_TIMER_CTL_ENABLE_SEL_Msk
#define DW_TIMER_CTL_MODE_SEL_Pos (1U)
#define DW_TIMER_CTL_MODE_SEL_Msk (0x1U << DW_TIMER_CTL_MODE_SEL_Pos)
#define DW_TIMER_CTL_MODE_SEL_EN DW_TIMER_CTL_MODE_SEL_Msk
#define DW_TIMER_CTL_INT_MASK_Pos (2U)
#define DW_TIMER_CTL_INT_MASK_Msk (0x1U << DW_TIMER_CTL_INT_MASK_Pos)
#define DW_TIMER_CTL_INT_MAKS_EN DW_TIMER_CTL_INT_MASK_Msk
#define DW_TIMER_CTL_HARD_TRIG_Pos (4U)
#define DW_TIMER_CTL_HARD_TRIG_Msk (0x1U << DW_TIMER_CTL_HARD_TRIG_Pos)
#define DW_TIMER_CTL_HARD_TRIG_EN DW_TIMER_CTL_HARD_TRIG_Msk
/*! Timer EOI, offset: 0x0c */
#define DW_TIMER_EOI_REG_Pos (0U)
#define DW_TIMER_EOI_REG_Msk (0x1U << DW_TIMER_EOI_REG_Pos)
#define DW_TIMER_EOI_REG_EN DW_TIMER_EOI_REG_Msk
/*! Timer Int Status, offset: 0x10 */
#define DW_TIMER_INT_STATUS_Pos (0U)
#define DW_TIMER_INT_STATUS_Msk (0x1U << DW_TIMER_INT_STATUS_Pos)
#define DW_TIMER_INT_STATUS_EN DW_TIMER_INT_STATUS_Msk
/*! Timers Int Status, offset: 0xa0 */
#define DW_TIMERS_INT_STATUS_Pos (0U)
#define DW_TIMERS_INT_STATUS_Msk (0x2U << DW_TIMERS_INT_STATUS_Pos)
#define DW_TIMERS_INT_STATUS_EN DW_TIMERS_INT_STATUS_Msk
/*! Timers EOI, offset: 0xa4 */
#define DW_TIMERS_EOI_REG_Pos (0U)
#define DW_TIMERS_EOI_REG_Msk (0x2U << DW_TIMERS_EOI_REG_Pos)
#define DW_TIMERS_EOI_REG_EN DW_TIMERS_EOI_REG_Msk
/*! Timers Raw Int Status,offset: 0xa8 */
#define DW_TIMERS_RAW_INT_STA_Pos (0U)
#define DW_TIMERS_RAW_INT_STA_Msk (0x2U << DW_TIMERS_RAW_INT_STA_Pos)
#define DW_TIMERS_RAW_INT_STA_EN DW_TIMERS_RAW_INT_STA_Msk
typedef struct {
volatile uint32_t TLC; /* Offset: 0x000 (R/W) TimerLoadCount */
volatile const uint32_t TCV; /* Offset: 0x004 (R/ ) TimerCurrentValue */
volatile uint32_t TCR; /* Offset: 0x008 (R/W) TimerControlReg */
volatile const uint32_t TEOI; /* Offset: 0x00c (R/ ) TimerEOI */
volatile const uint32_t TIS; /* Offset: 0x010 (R/ ) TimerIntStatus */
} dw_timer_regs_t;
typedef struct {
dw_timer_regs_t timer[DW_NR_TIMERS];
volatile const uint32_t TSIS; /* Offset: 0x0a0 (R/ ) TimersIntStatus */
volatile const uint32_t TSEOI; /* Offset: 0x0a4 (R/ ) TimersEOI */
volatile const uint32_t TSRIS; /* Offset: 0x0a8 (R/ ) TimersRawIntStatus */
} dw_timer_general_regs_t;
typedef struct _timer
{
char *name;
dw_timer_regs_t *base;
rt_uint32_t irqno;
rt_hwtimer_t timer;
}_timer_t;
static void _timer_init(rt_hwtimer_t *timer, rt_uint32_t state);
static rt_err_t _timer_start(rt_hwtimer_t *timer, rt_uint32_t cnt, rt_hwtimer_mode_t mode);
static void _timer_stop(rt_hwtimer_t *timer);
static rt_uint32_t _timer_count_get(rt_hwtimer_t *timer);
static rt_err_t _timer_control(rt_hwtimer_t *timer, rt_uint32_t cmd, void *args);
static const struct rt_hwtimer_ops _timer_ops = {
.init = _timer_init,
.start = _timer_start,
.stop = _timer_stop,
.count_get = _timer_count_get,
.control = _timer_control
};
static const struct rt_hwtimer_info _timer_info = {
.maxfreq = 25000000UL,
.minfreq = 25000000UL,
.maxcnt = 0xFFFFFFFF,
.cntmode = HWTIMER_MODE_PERIOD
};
static _timer_t _timer_obj[] =
{
#ifdef BSP_USING_TIMER0
{
.name = "timer0",
.base = (dw_timer_regs_t *)DW_TIMER0_BASE,
.irqno = TIMER_INTR_0
},
#endif /* BSP_USING_TIMER0 */
#ifdef BSP_USING_TIMER1
{
.name = "timer1",
.base = (dw_timer_regs_t *)DW_TIMER1_BASE,
.irqno = TIMER_INTR_1
},
#endif /* BSP_USING_TIMER1 */
#ifdef BSP_USING_TIMER2
{
.name = "timer2",
.base = (dw_timer_regs_t *)DW_TIMER2_BASE,
.irqno = TIMER_INTR_2
},
#endif /* BSP_USING_TIMER2 */
#ifdef BSP_USING_TIMER3
{
.name = "timer3",
.base = (dw_timer_regs_t *)DW_TIMER3_BASE,
.irqno = TIMER_INTR_3
},
#endif /* BSP_USING_TIMER3 */
#ifdef BSP_USING_TIMER4
{
.name = "timer4",
.base = (dw_timer_regs_t *)DW_TIMER4_BASE,
.irqno = TIMER_INTR_4
},
#endif /* BSP_USING_TIMER4 */
#ifdef BSP_USING_TIMER5
{
.name = "timer5",
.base = (dw_timer_regs_t *)DW_TIMER5_BASE,
.irqno = TIMER_INTR_5
},
#endif /* BSP_USING_TIMER5 */
#ifdef BSP_USING_TIMER6
{
.name = "timer6",
.base = (dw_timer_regs_t *)DW_TIMER6_BASE,
.irqno = TIMER_INTR_6
},
#endif /* BSP_USING_TIMER6 */
#ifdef BSP_USING_TIMER7
{
.name = "timer7",
.base = (dw_timer_regs_t *)DW_TIMER7_BASE,
.irqno = TIMER_INTR_7
},
#endif /* BSP_USING_TIMER7 */
};
uint32_t hal_timer_read_load(dw_timer_regs_t *timer_base)
{
return (timer_base->TLC);
}
void hal_timer_write_load(dw_timer_regs_t *timer_base, uint32_t value)
{
timer_base->TLC = value;
}
uint32_t hal_timer_get_current(dw_timer_regs_t *timer_base)
{
return (timer_base->TCV);
}
void hal_timer_set_enable(dw_timer_regs_t *timer_base)
{
timer_base->TCR |= (DW_TIMER_CTL_ENABLE_SEL_EN);
}
void hal_timer_set_disable(dw_timer_regs_t *timer_base)
{
timer_base->TCR &= ~(DW_TIMER_CTL_ENABLE_SEL_EN);
}
uint32_t hal_timer_get_enable(dw_timer_regs_t *timer_base)
{
if ((timer_base->TCR) & DW_TIMER_CTL_ENABLE_SEL_EN)
return 1;
return 0;
}
void hal_timer_set_mode_free(dw_timer_regs_t *timer_base)
{
timer_base->TCR &= ~(DW_TIMER_CTL_MODE_SEL_EN);
}
void hal_timer_set_mode_load(dw_timer_regs_t *timer_base)
{
timer_base->TCR |= (DW_TIMER_CTL_MODE_SEL_EN);
}
uint32_t hal_timer_get_model(dw_timer_regs_t *timer_base)
{
if ((timer_base->TCR) & DW_TIMER_CTL_MODE_SEL_EN)
return 1;
return 0;
}
void hal_timer_set_mask(dw_timer_regs_t *timer_base)
{
timer_base->TCR |= (DW_TIMER_CTL_INT_MAKS_EN);
}
void hal_timer_set_unmask(dw_timer_regs_t *timer_base)
{
timer_base->TCR &= ~(DW_TIMER_CTL_INT_MAKS_EN);
}
uint32_t hal_timer_get_mask(dw_timer_regs_t *timer_base)
{
if ((timer_base->TCR) & DW_TIMER_CTL_INT_MAKS_EN)
return 1;
return 0;
}
void hal_timer_set_hardtrigger_en(dw_timer_regs_t *timer_base)
{
timer_base->TCR |= (DW_TIMER_CTL_HARD_TRIG_EN);
}
void hal_timer_set_hardtrigger_dis(dw_timer_regs_t *timer_base)
{
timer_base->TCR &= ~(DW_TIMER_CTL_HARD_TRIG_EN);
}
uint32_t hal_timer_get_hardtrigger(dw_timer_regs_t *timer_base)
{
if ((timer_base->TCR) & DW_TIMER_CTL_HARD_TRIG_EN)
return 1;
return 0;
}
uint32_t hal_timer_clear_irq(dw_timer_regs_t *timer_base)
{
if ((timer_base->TEOI) & DW_TIMER_EOI_REG_EN)
return 1;
return 0;
}
uint32_t hal_timer_get_int_status(dw_timer_regs_t *timer_base)
{
if ((timer_base->TIS) & DW_TIMER_INT_STATUS_EN)
return 1;
return 0;
}
void hal_timer_reset_register(dw_timer_regs_t *timer_base)
{
timer_base->TCR = 0U;
timer_base->TLC = 0U;
}
uint32_t hal_timer_general_active_after_mask(dw_timer_general_regs_t *timer_base)
{
return ((timer_base->TSIS) & DW_TIMERS_INT_STATUS_EN);
}
uint32_t hal_timer_general_clear_irq(dw_timer_general_regs_t *timer_base)
{
return ((timer_base->TSEOI) & DW_TIMERS_EOI_REG_EN);
}
uint32_t hal_timer_general_active_prior_mask(dw_timer_general_regs_t *timer_base)
{
return ((timer_base->TSRIS) & DW_TIMERS_RAW_INT_STA_EN);
}
static void rt_hw_hwtmr_isr(int irqno, void *param)
{
_timer_t *_tmr = param;
dw_timer_regs_t *timer_base = _tmr->base;
if (hal_timer_get_int_status(timer_base))
{
hal_timer_clear_irq(timer_base);
hal_timer_set_disable(timer_base);
rt_device_hwtimer_isr(&_tmr->timer);
if(_tmr->timer.mode == HWTIMER_MODE_PERIOD)
{
hal_timer_set_enable(timer_base);
hal_timer_set_unmask(timer_base);
}
}
}
static void _timer_init(rt_hwtimer_t *timer, rt_uint32_t state)
{
_timer_t *_tmr = rt_container_of(timer, _timer_t, timer);
RT_ASSERT(_tmr!=NULL)
if(state)
{
hal_timer_reset_register(_tmr->base);
}
}
static rt_err_t _timer_start(rt_hwtimer_t *timer, rt_uint32_t cnt, rt_hwtimer_mode_t mode)
{
_timer_t *_tmr = rt_container_of(timer, _timer_t, timer);
uint32_t tmp_load = cnt;
hal_timer_set_mode_load(_tmr->base);
/*FIXME: no less than 10*/
if (tmp_load < 10)
{
tmp_load = 10;
}
hal_timer_set_disable(_tmr->base);
hal_timer_write_load(_tmr->base, tmp_load);
hal_timer_set_enable(_tmr->base);
hal_timer_set_unmask(_tmr->base);
return RT_EOK;
}
static void _timer_stop(rt_hwtimer_t *timer)
{
_timer_t *_tmr = rt_container_of(timer, _timer_t, timer);
hal_timer_set_mask(_tmr->base);
hal_timer_set_disable(_tmr->base);
}
static rt_uint32_t _timer_count_get(rt_hwtimer_t *timer)
{
_timer_t *_tmr = rt_container_of(timer, _timer_t, timer);
rt_uint32_t cnt = hal_timer_get_current(_tmr->base);
return cnt;
}
static rt_err_t _timer_control(rt_hwtimer_t *timer, rt_uint32_t cmd, void *args)
{
rt_err_t err = RT_EOK;
_timer_t *_tmr = rt_container_of(timer, _timer_t, timer);
switch (cmd)
{
case HWTIMER_CTRL_FREQ_SET:
err = -RT_ERROR;
break;
case HWTIMER_CTRL_INFO_GET:
*(rt_hwtimer_t*)args = _tmr->timer;
break;
case HWTIMER_CTRL_MODE_SET:
_tmr->timer.mode = *(rt_uint32_t*)args;
break;
case HWTIMER_CTRL_STOP:
_timer_stop(timer);
break;
default:
err = -RT_EINVAL;
break;
}
return err;
}
int rt_hw_timer_init(void)
{
int ret = RT_EOK;
for (uint32_t i = 0; i < sizeof(_timer_obj) / sizeof(_timer_obj[0]); i++)
{
_timer_obj[i].base = (dw_timer_regs_t *)DRV_IOREMAP((void*)_timer_obj[i].base, 0x10000);
_timer_obj[i].timer.info = &_timer_info;
_timer_obj[i].timer.ops = &_timer_ops;
ret = rt_device_hwtimer_register(&_timer_obj[i].timer, _timer_obj[i].name, &_timer_obj[i]);
if (ret != RT_EOK)
{
LOG_E("%s register failed", _timer_obj[i].name);
}
rt_hw_interrupt_install(_timer_obj[i].irqno, rt_hw_hwtmr_isr, &_timer_obj[i], _timer_obj[i].name);
rt_hw_interrupt_umask(_timer_obj[i].irqno);
}
return ret;
}
INIT_DEVICE_EXPORT(rt_hw_timer_init);
|