Statistics
| Branch: | Revision:

root / hw / timer / imx_epit.c @ 6a1751b7

History | View | Annotate | Download (10 kB)

1
/*
2
 * IMX EPIT Timer
3
 *
4
 * Copyright (c) 2008 OK Labs
5
 * Copyright (c) 2011 NICTA Pty Ltd
6
 * Originally written by Hans Jiang
7
 * Updated by Peter Chubb
8
 * Updated by Jean-Christophe Dubois
9
 *
10
 * This code is licensed under GPL version 2 or later.  See
11
 * the COPYING file in the top-level directory.
12
 *
13
 */
14

    
15
#include "hw/hw.h"
16
#include "qemu/bitops.h"
17
#include "qemu/timer.h"
18
#include "hw/ptimer.h"
19
#include "hw/sysbus.h"
20
#include "hw/arm/imx.h"
21
#include "qemu/main-loop.h"
22

    
23
#define TYPE_IMX_EPIT "imx.epit"
24

    
25
#define DEBUG_TIMER 0
26
#if DEBUG_TIMER
27

    
28
static char const *imx_epit_reg_name(uint32_t reg)
29
{
30
    switch (reg) {
31
    case 0:
32
        return "CR";
33
    case 1:
34
        return "SR";
35
    case 2:
36
        return "LR";
37
    case 3:
38
        return "CMP";
39
    case 4:
40
        return "CNT";
41
    default:
42
        return "[?]";
43
    }
44
}
45

    
46
#  define DPRINTF(fmt, args...) \
47
    do { fprintf(stderr, "%s: " fmt , __func__, ##args); } while (0)
48
#else
49
#  define DPRINTF(fmt, args...) do {} while (0)
50
#endif
51

    
52
/*
53
 * Define to 1 for messages about attempts to
54
 * access unimplemented registers or similar.
55
 */
56
#define DEBUG_IMPLEMENTATION 1
57
#if DEBUG_IMPLEMENTATION
58
#  define IPRINTF(fmt, args...) \
59
          do { fprintf(stderr, "%s: " fmt, __func__, ##args); } while (0)
60
#else
61
#  define IPRINTF(fmt, args...) do {} while (0)
62
#endif
63

    
64
#define IMX_EPIT(obj) \
65
        OBJECT_CHECK(IMXEPITState, (obj), TYPE_IMX_EPIT)
66

    
67
/*
68
 * EPIT: Enhanced periodic interrupt timer
69
 */
70

    
71
#define CR_EN       (1 << 0)
72
#define CR_ENMOD    (1 << 1)
73
#define CR_OCIEN    (1 << 2)
74
#define CR_RLD      (1 << 3)
75
#define CR_PRESCALE_SHIFT (4)
76
#define CR_PRESCALE_MASK  (0xfff)
77
#define CR_SWR      (1 << 16)
78
#define CR_IOVW     (1 << 17)
79
#define CR_DBGEN    (1 << 18)
80
#define CR_WAITEN   (1 << 19)
81
#define CR_DOZEN    (1 << 20)
82
#define CR_STOPEN   (1 << 21)
83
#define CR_CLKSRC_SHIFT (24)
84
#define CR_CLKSRC_MASK  (0x3 << CR_CLKSRC_SHIFT)
85

    
86
#define TIMER_MAX  0XFFFFFFFFUL
87

    
88
/*
89
 * Exact clock frequencies vary from board to board.
90
 * These are typical.
91
 */
92
static const IMXClk imx_epit_clocks[] =  {
93
    0,        /* 00 disabled */
94
    IPG,      /* 01 ipg_clk, ~532MHz */
95
    IPG,      /* 10 ipg_clk_highfreq */
96
    CLK_32k,  /* 11 ipg_clk_32k -- ~32kHz */
97
};
98

    
99
typedef struct {
100
    SysBusDevice busdev;
101
    ptimer_state *timer_reload;
102
    ptimer_state *timer_cmp;
103
    MemoryRegion iomem;
104
    DeviceState *ccm;
105

    
106
    uint32_t cr;
107
    uint32_t sr;
108
    uint32_t lr;
109
    uint32_t cmp;
110
    uint32_t cnt;
111

    
112
    uint32_t freq;
113
    qemu_irq irq;
114
} IMXEPITState;
115

    
116
/*
117
 * Update interrupt status
118
 */
119
static void imx_epit_update_int(IMXEPITState *s)
120
{
121
    if (s->sr && (s->cr & CR_OCIEN) && (s->cr & CR_EN)) {
122
        qemu_irq_raise(s->irq);
123
    } else {
124
        qemu_irq_lower(s->irq);
125
    }
126
}
127

    
128
static void imx_epit_set_freq(IMXEPITState *s)
129
{
130
    uint32_t clksrc;
131
    uint32_t prescaler;
132
    uint32_t freq;
133

    
134
    clksrc = extract32(s->cr, CR_CLKSRC_SHIFT, 2);
135
    prescaler = 1 + extract32(s->cr, CR_PRESCALE_SHIFT, 12);
136

    
137
    freq = imx_clock_frequency(s->ccm, imx_epit_clocks[clksrc]) / prescaler;
138

    
139
    s->freq = freq;
140

    
141
    DPRINTF("Setting ptimer frequency to %u\n", freq);
142

    
143
    if (freq) {
144
        ptimer_set_freq(s->timer_reload, freq);
145
        ptimer_set_freq(s->timer_cmp, freq);
146
    }
147
}
148

    
149
static void imx_epit_reset(DeviceState *dev)
150
{
151
    IMXEPITState *s = IMX_EPIT(dev);
152

    
153
    /*
154
     * Soft reset doesn't touch some bits; hard reset clears them
155
     */
156
    s->cr &= (CR_EN|CR_ENMOD|CR_STOPEN|CR_DOZEN|CR_WAITEN|CR_DBGEN);
157
    s->sr = 0;
158
    s->lr = TIMER_MAX;
159
    s->cmp = 0;
160
    s->cnt = 0;
161
    /* stop both timers */
162
    ptimer_stop(s->timer_cmp);
163
    ptimer_stop(s->timer_reload);
164
    /* compute new frequency */
165
    imx_epit_set_freq(s);
166
    /* init both timers to TIMER_MAX */
167
    ptimer_set_limit(s->timer_cmp, TIMER_MAX, 1);
168
    ptimer_set_limit(s->timer_reload, TIMER_MAX, 1);
169
    if (s->freq && (s->cr & CR_EN)) {
170
        /* if the timer is still enabled, restart it */
171
        ptimer_run(s->timer_reload, 0);
172
    }
173
}
174

    
175
static uint32_t imx_epit_update_count(IMXEPITState *s)
176
{
177
     s->cnt = ptimer_get_count(s->timer_reload);
178

    
179
     return s->cnt;
180
}
181

    
182
static uint64_t imx_epit_read(void *opaque, hwaddr offset, unsigned size)
183
{
184
    IMXEPITState *s = IMX_EPIT(opaque);
185
    uint32_t reg_value = 0;
186
    uint32_t reg = offset >> 2;
187

    
188
    switch (reg) {
189
    case 0: /* Control Register */
190
        reg_value = s->cr;
191
        break;
192

    
193
    case 1: /* Status Register */
194
        reg_value = s->sr;
195
        break;
196

    
197
    case 2: /* LR - ticks*/
198
        reg_value = s->lr;
199
        break;
200

    
201
    case 3: /* CMP */
202
        reg_value = s->cmp;
203
        break;
204

    
205
    case 4: /* CNT */
206
        imx_epit_update_count(s);
207
        reg_value = s->cnt;
208
        break;
209

    
210
    default:
211
        IPRINTF("Bad offset %x\n", reg);
212
        break;
213
    }
214

    
215
    DPRINTF("(%s) = 0x%08x\n", imx_epit_reg_name(reg), reg_value);
216

    
217
    return reg_value;
218
}
219

    
220
static void imx_epit_reload_compare_timer(IMXEPITState *s)
221
{
222
    if ((s->cr & (CR_EN | CR_OCIEN)) == (CR_EN | CR_OCIEN))  {
223
        /* if the compare feature is on and timers are running */
224
        uint32_t tmp = imx_epit_update_count(s);
225
        uint64_t next;
226
        if (tmp > s->cmp) {
227
            /* It'll fire in this round of the timer */
228
            next = tmp - s->cmp;
229
        } else { /* catch it next time around */
230
            next = tmp - s->cmp + ((s->cr & CR_RLD) ? TIMER_MAX : s->lr);
231
        }
232
        ptimer_set_count(s->timer_cmp, next);
233
    }
234
}
235

    
236
static void imx_epit_write(void *opaque, hwaddr offset, uint64_t value,
237
                           unsigned size)
238
{
239
    IMXEPITState *s = IMX_EPIT(opaque);
240
    uint32_t reg = offset >> 2;
241
    uint64_t oldcr;
242

    
243
    DPRINTF("(%s, value = 0x%08x)\n", imx_epit_reg_name(reg), (uint32_t)value);
244

    
245
    switch (reg) {
246
    case 0: /* CR */
247

    
248
        oldcr = s->cr;
249
        s->cr = value & 0x03ffffff;
250
        if (s->cr & CR_SWR) {
251
            /* handle the reset */
252
            imx_epit_reset(DEVICE(s));
253
        } else {
254
            imx_epit_set_freq(s);
255
        }
256

    
257
        if (s->freq && (s->cr & CR_EN) && !(oldcr & CR_EN)) {
258
            if (s->cr & CR_ENMOD) {
259
                if (s->cr & CR_RLD) {
260
                    ptimer_set_limit(s->timer_reload, s->lr, 1);
261
                    ptimer_set_limit(s->timer_cmp, s->lr, 1);
262
                } else {
263
                    ptimer_set_limit(s->timer_reload, TIMER_MAX, 1);
264
                    ptimer_set_limit(s->timer_cmp, TIMER_MAX, 1);
265
                }
266
            }
267

    
268
            imx_epit_reload_compare_timer(s);
269
            ptimer_run(s->timer_reload, 0);
270
            if (s->cr & CR_OCIEN) {
271
                ptimer_run(s->timer_cmp, 0);
272
            } else {
273
                ptimer_stop(s->timer_cmp);
274
            }
275
        } else if (!(s->cr & CR_EN)) {
276
            /* stop both timers */
277
            ptimer_stop(s->timer_reload);
278
            ptimer_stop(s->timer_cmp);
279
        } else  if (s->cr & CR_OCIEN) {
280
            if (!(oldcr & CR_OCIEN)) {
281
                imx_epit_reload_compare_timer(s);
282
                ptimer_run(s->timer_cmp, 0);
283
            }
284
        } else {
285
            ptimer_stop(s->timer_cmp);
286
        }
287
        break;
288

    
289
    case 1: /* SR - ACK*/
290
        /* writing 1 to OCIF clear the OCIF bit */
291
        if (value & 0x01) {
292
            s->sr = 0;
293
            imx_epit_update_int(s);
294
        }
295
        break;
296

    
297
    case 2: /* LR - set ticks */
298
        s->lr = value;
299

    
300
        if (s->cr & CR_RLD) {
301
            /* Also set the limit if the LRD bit is set */
302
            /* If IOVW bit is set then set the timer value */
303
            ptimer_set_limit(s->timer_reload, s->lr, s->cr & CR_IOVW);
304
            ptimer_set_limit(s->timer_cmp, s->lr, 0);
305
        } else if (s->cr & CR_IOVW) {
306
            /* If IOVW bit is set then set the timer value */
307
            ptimer_set_count(s->timer_reload, s->lr);
308
        }
309

    
310
        imx_epit_reload_compare_timer(s);
311
        break;
312

    
313
    case 3: /* CMP */
314
        s->cmp = value;
315

    
316
        imx_epit_reload_compare_timer(s);
317

    
318
        break;
319

    
320
    default:
321
        IPRINTF("Bad offset %x\n", reg);
322

    
323
        break;
324
    }
325
}
326
static void imx_epit_cmp(void *opaque)
327
{
328
    IMXEPITState *s = IMX_EPIT(opaque);
329

    
330
    DPRINTF("sr was %d\n", s->sr);
331

    
332
    s->sr = 1;
333
    imx_epit_update_int(s);
334
}
335

    
336
void imx_timerp_create(const hwaddr addr, qemu_irq irq, DeviceState *ccm)
337
{
338
    IMXEPITState *pp;
339
    DeviceState *dev;
340

    
341
    dev = sysbus_create_simple(TYPE_IMX_EPIT, addr, irq);
342
    pp = IMX_EPIT(dev);
343
    pp->ccm = ccm;
344
}
345

    
346
static const MemoryRegionOps imx_epit_ops = {
347
  .read = imx_epit_read,
348
  .write = imx_epit_write,
349
  .endianness = DEVICE_NATIVE_ENDIAN,
350
};
351

    
352
static const VMStateDescription vmstate_imx_timer_epit = {
353
    .name = "imx.epit",
354
    .version_id = 2,
355
    .minimum_version_id = 2,
356
    .minimum_version_id_old = 2,
357
    .fields      = (VMStateField[]) {
358
        VMSTATE_UINT32(cr, IMXEPITState),
359
        VMSTATE_UINT32(sr, IMXEPITState),
360
        VMSTATE_UINT32(lr, IMXEPITState),
361
        VMSTATE_UINT32(cmp, IMXEPITState),
362
        VMSTATE_UINT32(cnt, IMXEPITState),
363
        VMSTATE_UINT32(freq, IMXEPITState),
364
        VMSTATE_PTIMER(timer_reload, IMXEPITState),
365
        VMSTATE_PTIMER(timer_cmp, IMXEPITState),
366
        VMSTATE_END_OF_LIST()
367
    }
368
};
369

    
370
static void imx_epit_realize(DeviceState *dev, Error **errp)
371
{
372
    IMXEPITState *s = IMX_EPIT(dev);
373
    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
374
    QEMUBH *bh;
375

    
376
    DPRINTF("\n");
377

    
378
    sysbus_init_irq(sbd, &s->irq);
379
    memory_region_init_io(&s->iomem, OBJECT(s), &imx_epit_ops, s, TYPE_IMX_EPIT,
380
                          0x00001000);
381
    sysbus_init_mmio(sbd, &s->iomem);
382

    
383
    s->timer_reload = ptimer_init(NULL);
384

    
385
    bh = qemu_bh_new(imx_epit_cmp, s);
386
    s->timer_cmp = ptimer_init(bh);
387
}
388

    
389
static void imx_epit_class_init(ObjectClass *klass, void *data)
390
{
391
    DeviceClass *dc  = DEVICE_CLASS(klass);
392

    
393
    dc->realize = imx_epit_realize;
394
    dc->reset = imx_epit_reset;
395
    dc->vmsd = &vmstate_imx_timer_epit;
396
    dc->desc = "i.MX periodic timer";
397
}
398

    
399
static const TypeInfo imx_epit_info = {
400
    .name = TYPE_IMX_EPIT,
401
    .parent = TYPE_SYS_BUS_DEVICE,
402
    .instance_size = sizeof(IMXEPITState),
403
    .class_init = imx_epit_class_init,
404
};
405

    
406
static void imx_epit_register_types(void)
407
{
408
    type_register_static(&imx_epit_info);
409
}
410

    
411
type_init(imx_epit_register_types)