4 * Copyright (c) 2008 OK Labs
5 * Copyright (c) 2011 NICTA Pty Ltd
6 * Originally written by Hans Jiang
7 * Updated by Peter Chubb
9 * This code is licensed under GPL version 2 or later. See
10 * the COPYING file in the top-level directory.
15 #include "qemu/bitops.h"
16 #include "qemu/timer.h"
17 #include "hw/ptimer.h"
18 #include "hw/sysbus.h"
19 #include "hw/arm/imx.h"
21 //#define DEBUG_TIMER 1
23 # define DPRINTF(fmt, args...) \
24 do { printf("imx_timer: " fmt , ##args); } while (0)
26 # define DPRINTF(fmt, args...) do {} while (0)
30 * Define to 1 for messages about attempts to
31 * access unimplemented registers or similar.
33 #define DEBUG_IMPLEMENTATION 1
34 #if DEBUG_IMPLEMENTATION
35 # define IPRINTF(fmt, args...) \
36 do { fprintf(stderr, "imx_timer: " fmt, ##args); } while (0)
38 # define IPRINTF(fmt, args...) do {} while (0)
42 * EPIT: Enhanced periodic interrupt timer
45 #define CR_EN (1 << 0)
46 #define CR_ENMOD (1 << 1)
47 #define CR_OCIEN (1 << 2)
48 #define CR_RLD (1 << 3)
49 #define CR_PRESCALE_SHIFT (4)
50 #define CR_PRESCALE_MASK (0xfff)
51 #define CR_SWR (1 << 16)
52 #define CR_IOVW (1 << 17)
53 #define CR_DBGEN (1 << 18)
54 #define CR_WAITEN (1 << 19)
55 #define CR_DOZEN (1 << 20)
56 #define CR_STOPEN (1 << 21)
57 #define CR_CLKSRC_SHIFT (24)
58 #define CR_CLKSRC_MASK (0x3 << CR_CLKSRC_SHIFT)
60 #define TIMER_MAX 0XFFFFFFFFUL
63 * Exact clock frequencies vary from board to board.
66 static const IMXClk imx_timerp_clocks
[] = {
68 IPG
, /* 01 ipg_clk, ~532MHz */
69 IPG
, /* 10 ipg_clk_highfreq */
70 CLK_32k
, /* 11 ipg_clk_32k -- ~32kHz */
75 ptimer_state
*timer_reload
;
76 ptimer_state
*timer_cmp
;
91 * Update interrupt status
93 static void imx_timerp_update(IMXTimerPState
*s
)
95 if (s
->sr
&& (s
->cr
& CR_OCIEN
)) {
96 qemu_irq_raise(s
->irq
);
98 qemu_irq_lower(s
->irq
);
102 static void set_timerp_freq(IMXTimerPState
*s
)
108 clksrc
= extract32(s
->cr
, CR_CLKSRC_SHIFT
, 2);
109 prescaler
= 1 + extract32(s
->cr
, CR_PRESCALE_SHIFT
, 12);
111 freq
= imx_clock_frequency(s
->ccm
, imx_timerp_clocks
[clksrc
]) / prescaler
;
114 DPRINTF("Setting ptimer frequency to %u\n", freq
);
117 ptimer_set_freq(s
->timer_reload
, freq
);
118 ptimer_set_freq(s
->timer_cmp
, freq
);
122 static void imx_timerp_reset(DeviceState
*dev
)
124 IMXTimerPState
*s
= container_of(dev
, IMXTimerPState
, busdev
.qdev
);
127 * Soft reset doesn't touch some bits; hard reset clears them
129 s
->cr
&= ~(CR_EN
|CR_ENMOD
|CR_STOPEN
|CR_DOZEN
|CR_WAITEN
|CR_DBGEN
);
134 /* stop both timers */
135 ptimer_stop(s
->timer_cmp
);
136 ptimer_stop(s
->timer_reload
);
137 /* compute new frequency */
139 /* init both timers to TIMER_MAX */
140 ptimer_set_limit(s
->timer_cmp
, TIMER_MAX
, 1);
141 ptimer_set_limit(s
->timer_reload
, TIMER_MAX
, 1);
142 if (s
->freq
&& (s
->cr
& CR_EN
)) {
143 /* if the timer is still enabled, restart it */
144 ptimer_run(s
->timer_reload
, 1);
148 static uint32_t imx_timerp_update_counts(IMXTimerPState
*s
)
150 s
->cnt
= ptimer_get_count(s
->timer_reload
);
155 static uint64_t imx_timerp_read(void *opaque
, hwaddr offset
,
158 IMXTimerPState
*s
= (IMXTimerPState
*)opaque
;
160 DPRINTF("p-read(offset=%x)", (unsigned int)(offset
>> 2));
161 switch (offset
>> 2) {
162 case 0: /* Control Register */
163 DPRINTF("cr %x\n", s
->cr
);
166 case 1: /* Status Register */
167 DPRINTF("sr %x\n", s
->sr
);
170 case 2: /* LR - ticks*/
171 DPRINTF("lr %x\n", s
->lr
);
175 DPRINTF("cmp %x\n", s
->cmp
);
179 imx_timerp_update_counts(s
);
180 DPRINTF(" cnt = %x\n", s
->cnt
);
184 IPRINTF("imx_timerp_read: Bad offset %x\n",
189 static void imx_reload_compare_timer(IMXTimerPState
*s
)
191 if ((s
->cr
& CR_OCIEN
) && s
->cmp
) {
192 /* if the compare feature is on */
193 uint32_t tmp
= imx_timerp_update_counts(s
);
195 /* reinit the cmp timer if required */
196 ptimer_set_count(s
->timer_cmp
, tmp
- s
->cmp
);
197 if ((s
->cr
& CR_EN
)) {
198 /* Restart the cmp timer if required */
199 ptimer_run(s
->timer_cmp
, 0);
205 static void imx_timerp_write(void *opaque
, hwaddr offset
,
206 uint64_t value
, unsigned size
)
208 IMXTimerPState
*s
= (IMXTimerPState
*)opaque
;
209 DPRINTF("p-write(offset=%x, value = %x)\n", (unsigned int)offset
>> 2,
210 (unsigned int)value
);
212 switch (offset
>> 2) {
214 s
->cr
= value
& 0x03ffffff;
215 if (s
->cr
& CR_SWR
) {
216 /* handle the reset */
217 imx_timerp_reset(&s
->busdev
.qdev
);
222 if (s
->freq
&& (s
->cr
& CR_EN
)) {
223 if (s
->cr
& CR_ENMOD
) {
224 if (s
->cr
& CR_RLD
) {
225 ptimer_set_limit(s
->timer_reload
, s
->lr
, 1);
227 ptimer_set_limit(s
->timer_reload
, TIMER_MAX
, 1);
231 imx_reload_compare_timer(s
);
233 ptimer_run(s
->timer_reload
, 1);
235 /* stop both timers */
236 ptimer_stop(s
->timer_reload
);
237 ptimer_stop(s
->timer_cmp
);
241 case 1: /* SR - ACK*/
242 /* writing 1 to OCIF clear the OCIF bit */
245 imx_timerp_update(s
);
249 case 2: /* LR - set ticks */
252 if (s
->cr
& CR_RLD
) {
253 /* Also set the limit if the LRD bit is set */
254 /* If IOVW bit is set then set the timer value */
255 ptimer_set_limit(s
->timer_reload
, s
->lr
, s
->cr
& CR_IOVW
);
256 } else if (s
->cr
& CR_IOVW
) {
257 /* If IOVW bit is set then set the timer value */
258 ptimer_set_count(s
->timer_reload
, s
->lr
);
261 imx_reload_compare_timer(s
);
268 imx_reload_compare_timer(s
);
273 IPRINTF("imx_timerp_write: Bad offset %x\n",
278 static void imx_timerp_reload(void *opaque
)
280 IMXTimerPState
*s
= (IMXTimerPState
*)opaque
;
282 DPRINTF("imxp reload\n");
284 if (!(s
->cr
& CR_EN
)) {
288 if (s
->cr
& CR_RLD
) {
289 ptimer_set_limit(s
->timer_reload
, s
->lr
, 1);
291 ptimer_set_limit(s
->timer_reload
, TIMER_MAX
, 1);
294 if (s
->cr
& CR_OCIEN
) {
295 /* if compare register is 0 then we handle the interrupt here */
298 imx_timerp_update(s
);
299 } else if (s
->cmp
<= s
->lr
) {
300 /* We should launch the compare register */
301 ptimer_set_count(s
->timer_cmp
, s
->lr
- s
->cmp
);
302 ptimer_run(s
->timer_cmp
, 0);
304 IPRINTF("imxp reload: s->lr < s->cmp\n");
309 static void imx_timerp_cmp(void *opaque
)
311 IMXTimerPState
*s
= (IMXTimerPState
*)opaque
;
313 DPRINTF("imxp compare\n");
315 ptimer_stop(s
->timer_cmp
);
317 /* compare register is not 0 */
320 imx_timerp_update(s
);
324 void imx_timerp_create(const hwaddr addr
,
331 dev
= sysbus_create_simple("imx_timerp", addr
, irq
);
332 pp
= container_of(dev
, IMXTimerPState
, busdev
.qdev
);
336 static const MemoryRegionOps imx_timerp_ops
= {
337 .read
= imx_timerp_read
,
338 .write
= imx_timerp_write
,
339 .endianness
= DEVICE_NATIVE_ENDIAN
,
342 static const VMStateDescription vmstate_imx_timerp
= {
343 .name
= "imx-timerp",
345 .minimum_version_id
= 2,
346 .minimum_version_id_old
= 2,
347 .fields
= (VMStateField
[]) {
348 VMSTATE_UINT32(cr
, IMXTimerPState
),
349 VMSTATE_UINT32(sr
, IMXTimerPState
),
350 VMSTATE_UINT32(lr
, IMXTimerPState
),
351 VMSTATE_UINT32(cmp
, IMXTimerPState
),
352 VMSTATE_UINT32(cnt
, IMXTimerPState
),
353 VMSTATE_UINT32(freq
, IMXTimerPState
),
354 VMSTATE_PTIMER(timer_reload
, IMXTimerPState
),
355 VMSTATE_PTIMER(timer_cmp
, IMXTimerPState
),
356 VMSTATE_END_OF_LIST()
360 static int imx_timerp_init(SysBusDevice
*dev
)
362 IMXTimerPState
*s
= FROM_SYSBUS(IMXTimerPState
, dev
);
365 DPRINTF("imx_timerp_init\n");
366 sysbus_init_irq(dev
, &s
->irq
);
367 memory_region_init_io(&s
->iomem
, &imx_timerp_ops
,
370 sysbus_init_mmio(dev
, &s
->iomem
);
372 bh
= qemu_bh_new(imx_timerp_reload
, s
);
373 s
->timer_reload
= ptimer_init(bh
);
375 bh
= qemu_bh_new(imx_timerp_cmp
, s
);
376 s
->timer_cmp
= ptimer_init(bh
);
382 static void imx_timerp_class_init(ObjectClass
*klass
, void *data
)
384 DeviceClass
*dc
= DEVICE_CLASS(klass
);
385 SysBusDeviceClass
*k
= SYS_BUS_DEVICE_CLASS(klass
);
386 k
->init
= imx_timerp_init
;
387 dc
->vmsd
= &vmstate_imx_timerp
;
388 dc
->reset
= imx_timerp_reset
;
389 dc
->desc
= "i.MX periodic timer";
392 static const TypeInfo imx_timerp_info
= {
393 .name
= "imx_timerp",
394 .parent
= TYPE_SYS_BUS_DEVICE
,
395 .instance_size
= sizeof(IMXTimerPState
),
396 .class_init
= imx_timerp_class_init
,
399 static void imx_timer_register_types(void)
401 type_register_static(&imx_timerp_info
);
404 type_init(imx_timer_register_types
)