Statistics
| Branch: | Revision:

root / hw / grlib_gptimer.c @ 7267c094

History | View | Annotate | Download (10.7 kB)

1
/*
2
 * QEMU GRLIB GPTimer Emulator
3
 *
4
 * Copyright (c) 2010-2011 AdaCore
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7
 * of this software and associated documentation files (the "Software"), to deal
8
 * in the Software without restriction, including without limitation the rights
9
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
 * copies of the Software, and to permit persons to whom the Software is
11
 * furnished to do so, subject to the following conditions:
12
 *
13
 * The above copyright notice and this permission notice shall be included in
14
 * all copies or substantial portions of the Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
 * THE SOFTWARE.
23
 */
24

    
25
#include "sysbus.h"
26
#include "qemu-timer.h"
27

    
28
#include "trace.h"
29

    
30
#define UNIT_REG_SIZE    16     /* Size of memory mapped regs for the unit */
31
#define GPTIMER_REG_SIZE 16     /* Size of memory mapped regs for a GPTimer */
32

    
33
#define GPTIMER_MAX_TIMERS 8
34

    
35
/* GPTimer Config register fields */
36
#define GPTIMER_ENABLE      (1 << 0)
37
#define GPTIMER_RESTART     (1 << 1)
38
#define GPTIMER_LOAD        (1 << 2)
39
#define GPTIMER_INT_ENABLE  (1 << 3)
40
#define GPTIMER_INT_PENDING (1 << 4)
41
#define GPTIMER_CHAIN       (1 << 5) /* Not supported */
42
#define GPTIMER_DEBUG_HALT  (1 << 6) /* Not supported */
43

    
44
/* Memory mapped register offsets */
45
#define SCALER_OFFSET         0x00
46
#define SCALER_RELOAD_OFFSET  0x04
47
#define CONFIG_OFFSET         0x08
48
#define COUNTER_OFFSET        0x00
49
#define COUNTER_RELOAD_OFFSET 0x04
50
#define TIMER_BASE            0x10
51

    
52
typedef struct GPTimer     GPTimer;
53
typedef struct GPTimerUnit GPTimerUnit;
54

    
55
struct GPTimer {
56
    QEMUBH *bh;
57
    struct ptimer_state *ptimer;
58

    
59
    qemu_irq     irq;
60
    int          id;
61
    GPTimerUnit *unit;
62

    
63
    /* registers */
64
    uint32_t counter;
65
    uint32_t reload;
66
    uint32_t config;
67
};
68

    
69
struct GPTimerUnit {
70
    SysBusDevice  busdev;
71

    
72
    uint32_t nr_timers;         /* Number of timers available */
73
    uint32_t freq_hz;           /* System frequency */
74
    uint32_t irq_line;          /* Base irq line */
75

    
76
    GPTimer *timers;
77

    
78
    /* registers */
79
    uint32_t scaler;
80
    uint32_t reload;
81
    uint32_t config;
82
};
83

    
84
static void grlib_gptimer_enable(GPTimer *timer)
85
{
86
    assert(timer != NULL);
87

    
88

    
89
    ptimer_stop(timer->ptimer);
90

    
91
    if (!(timer->config & GPTIMER_ENABLE)) {
92
        /* Timer disabled */
93
        trace_grlib_gptimer_disabled(timer->id, timer->config);
94
        return;
95
    }
96

    
97
    /* ptimer is triggered when the counter reach 0 but GPTimer is triggered at
98
       underflow. Set count + 1 to simulate the GPTimer behavior. */
99

    
100
    trace_grlib_gptimer_enable(timer->id, timer->counter + 1);
101

    
102
    ptimer_set_count(timer->ptimer, timer->counter + 1);
103
    ptimer_run(timer->ptimer, 1);
104
}
105

    
106
static void grlib_gptimer_restart(GPTimer *timer)
107
{
108
    assert(timer != NULL);
109

    
110
    trace_grlib_gptimer_restart(timer->id, timer->reload);
111

    
112
    timer->counter = timer->reload;
113
    grlib_gptimer_enable(timer);
114
}
115

    
116
static void grlib_gptimer_set_scaler(GPTimerUnit *unit, uint32_t scaler)
117
{
118
    int i = 0;
119
    uint32_t value = 0;
120

    
121
    assert(unit != NULL);
122

    
123
    if (scaler > 0) {
124
        value = unit->freq_hz / (scaler + 1);
125
    } else {
126
        value = unit->freq_hz;
127
    }
128

    
129
    trace_grlib_gptimer_set_scaler(scaler, value);
130

    
131
    for (i = 0; i < unit->nr_timers; i++) {
132
        ptimer_set_freq(unit->timers[i].ptimer, value);
133
    }
134
}
135

    
136
static void grlib_gptimer_hit(void *opaque)
137
{
138
    GPTimer *timer = opaque;
139
    assert(timer != NULL);
140

    
141
    trace_grlib_gptimer_hit(timer->id);
142

    
143
    /* Timer expired */
144

    
145
    if (timer->config & GPTIMER_INT_ENABLE) {
146
        /* Set the pending bit (only unset by write in the config register) */
147
        timer->config |= GPTIMER_INT_PENDING;
148
        qemu_irq_pulse(timer->irq);
149
    }
150

    
151
    if (timer->config & GPTIMER_RESTART) {
152
        grlib_gptimer_restart(timer);
153
    }
154
}
155

    
156
static uint32_t grlib_gptimer_readl(void *opaque, target_phys_addr_t addr)
157
{
158
    GPTimerUnit        *unit  = opaque;
159
    target_phys_addr_t  timer_addr;
160
    int                 id;
161
    uint32_t            value = 0;
162

    
163
    addr &= 0xff;
164

    
165
    /* Unit registers */
166
    switch (addr) {
167
    case SCALER_OFFSET:
168
        trace_grlib_gptimer_readl(-1, addr, unit->scaler);
169
        return unit->scaler;
170

    
171
    case SCALER_RELOAD_OFFSET:
172
        trace_grlib_gptimer_readl(-1, addr, unit->reload);
173
        return unit->reload;
174

    
175
    case CONFIG_OFFSET:
176
        trace_grlib_gptimer_readl(-1, addr, unit->config);
177
        return unit->config;
178

    
179
    default:
180
        break;
181
    }
182

    
183
    timer_addr = (addr % TIMER_BASE);
184
    id         = (addr - TIMER_BASE) / TIMER_BASE;
185

    
186
    if (id >= 0 && id < unit->nr_timers) {
187

    
188
        /* GPTimer registers */
189
        switch (timer_addr) {
190
        case COUNTER_OFFSET:
191
            value = ptimer_get_count(unit->timers[id].ptimer);
192
            trace_grlib_gptimer_readl(id, addr, value);
193
            return value;
194

    
195
        case COUNTER_RELOAD_OFFSET:
196
            value = unit->timers[id].reload;
197
            trace_grlib_gptimer_readl(id, addr, value);
198
            return value;
199

    
200
        case CONFIG_OFFSET:
201
            trace_grlib_gptimer_readl(id, addr, unit->timers[id].config);
202
            return unit->timers[id].config;
203

    
204
        default:
205
            break;
206
        }
207

    
208
    }
209

    
210
    trace_grlib_gptimer_readl(-1, addr, 0);
211
    return 0;
212
}
213

    
214
static void
215
grlib_gptimer_writel(void *opaque, target_phys_addr_t addr, uint32_t value)
216
{
217
    GPTimerUnit        *unit = opaque;
218
    target_phys_addr_t  timer_addr;
219
    int                 id;
220

    
221
    addr &= 0xff;
222

    
223
    /* Unit registers */
224
    switch (addr) {
225
    case SCALER_OFFSET:
226
        value &= 0xFFFF; /* clean up the value */
227
        unit->scaler = value;
228
        trace_grlib_gptimer_writel(-1, addr, unit->scaler);
229
        return;
230

    
231
    case SCALER_RELOAD_OFFSET:
232
        value &= 0xFFFF; /* clean up the value */
233
        unit->reload = value;
234
        trace_grlib_gptimer_writel(-1, addr, unit->reload);
235
        grlib_gptimer_set_scaler(unit, value);
236
        return;
237

    
238
    case CONFIG_OFFSET:
239
        /* Read Only (disable timer freeze not supported) */
240
        trace_grlib_gptimer_writel(-1, addr, 0);
241
        return;
242

    
243
    default:
244
        break;
245
    }
246

    
247
    timer_addr = (addr % TIMER_BASE);
248
    id         = (addr - TIMER_BASE) / TIMER_BASE;
249

    
250
    if (id >= 0 && id < unit->nr_timers) {
251

    
252
        /* GPTimer registers */
253
        switch (timer_addr) {
254
        case COUNTER_OFFSET:
255
            trace_grlib_gptimer_writel(id, addr, value);
256
            unit->timers[id].counter = value;
257
            grlib_gptimer_enable(&unit->timers[id]);
258
            return;
259

    
260
        case COUNTER_RELOAD_OFFSET:
261
            trace_grlib_gptimer_writel(id, addr, value);
262
            unit->timers[id].reload = value;
263
            return;
264

    
265
        case CONFIG_OFFSET:
266
            trace_grlib_gptimer_writel(id, addr, value);
267

    
268
            if (value & GPTIMER_INT_PENDING) {
269
                /* clear pending bit */
270
                value &= ~GPTIMER_INT_PENDING;
271
            } else {
272
                /* keep pending bit */
273
                value |= unit->timers[id].config & GPTIMER_INT_PENDING;
274
            }
275

    
276
            unit->timers[id].config = value;
277

    
278
            /* gptimer_restart calls gptimer_enable, so if "enable" and "load"
279
               bits are present, we just have to call restart. */
280

    
281
            if (value & GPTIMER_LOAD) {
282
                grlib_gptimer_restart(&unit->timers[id]);
283
            } else if (value & GPTIMER_ENABLE) {
284
                grlib_gptimer_enable(&unit->timers[id]);
285
            }
286

    
287
            /* These fields must always be read as 0 */
288
            value &= ~(GPTIMER_LOAD & GPTIMER_DEBUG_HALT);
289

    
290
            unit->timers[id].config = value;
291
            return;
292

    
293
        default:
294
            break;
295
        }
296

    
297
    }
298

    
299
    trace_grlib_gptimer_writel(-1, addr, value);
300
}
301

    
302
static CPUReadMemoryFunc * const grlib_gptimer_read[] = {
303
    NULL, NULL, grlib_gptimer_readl,
304
};
305

    
306
static CPUWriteMemoryFunc * const grlib_gptimer_write[] = {
307
    NULL, NULL, grlib_gptimer_writel,
308
};
309

    
310
static void grlib_gptimer_reset(DeviceState *d)
311
{
312
    GPTimerUnit *unit = container_of(d, GPTimerUnit, busdev.qdev);
313
    int          i    = 0;
314

    
315
    assert(unit != NULL);
316

    
317
    unit->scaler = 0;
318
    unit->reload = 0;
319
    unit->config = 0;
320

    
321
    unit->config  = unit->nr_timers;
322
    unit->config |= unit->irq_line << 3;
323
    unit->config |= 1 << 8;     /* separate interrupt */
324
    unit->config |= 1 << 9;     /* Disable timer freeze */
325

    
326

    
327
    for (i = 0; i < unit->nr_timers; i++) {
328
        GPTimer *timer = &unit->timers[i];
329

    
330
        timer->counter = 0;
331
        timer->reload = 0;
332
        timer->config = 0;
333
        ptimer_stop(timer->ptimer);
334
        ptimer_set_count(timer->ptimer, 0);
335
        ptimer_set_freq(timer->ptimer, unit->freq_hz);
336
    }
337
}
338

    
339
static int grlib_gptimer_init(SysBusDevice *dev)
340
{
341
    GPTimerUnit  *unit = FROM_SYSBUS(typeof(*unit), dev);
342
    unsigned int  i;
343
    int           timer_regs;
344

    
345
    assert(unit->nr_timers > 0);
346
    assert(unit->nr_timers <= GPTIMER_MAX_TIMERS);
347

    
348
    unit->timers = g_malloc0(sizeof unit->timers[0] * unit->nr_timers);
349

    
350
    for (i = 0; i < unit->nr_timers; i++) {
351
        GPTimer *timer = &unit->timers[i];
352

    
353
        timer->unit   = unit;
354
        timer->bh     = qemu_bh_new(grlib_gptimer_hit, timer);
355
        timer->ptimer = ptimer_init(timer->bh);
356
        timer->id     = i;
357

    
358
        /* One IRQ line for each timer */
359
        sysbus_init_irq(dev, &timer->irq);
360

    
361
        ptimer_set_freq(timer->ptimer, unit->freq_hz);
362
    }
363

    
364
    timer_regs = cpu_register_io_memory(grlib_gptimer_read,
365
                                        grlib_gptimer_write,
366
                                        unit, DEVICE_NATIVE_ENDIAN);
367
    if (timer_regs < 0) {
368
        return -1;
369
    }
370

    
371
    sysbus_init_mmio(dev, UNIT_REG_SIZE + GPTIMER_REG_SIZE * unit->nr_timers,
372
                     timer_regs);
373
    return 0;
374
}
375

    
376
static SysBusDeviceInfo grlib_gptimer_info = {
377
    .init       = grlib_gptimer_init,
378
    .qdev.name  = "grlib,gptimer",
379
    .qdev.reset = grlib_gptimer_reset,
380
    .qdev.size  = sizeof(GPTimerUnit),
381
    .qdev.props = (Property[]) {
382
        DEFINE_PROP_UINT32("frequency", GPTimerUnit, freq_hz,   40000000),
383
        DEFINE_PROP_UINT32("irq-line",  GPTimerUnit, irq_line,  8),
384
        DEFINE_PROP_UINT32("nr-timers", GPTimerUnit, nr_timers, 2),
385
        DEFINE_PROP_END_OF_LIST()
386
    }
387
};
388

    
389
static void grlib_gptimer_register(void)
390
{
391
    sysbus_register_withprop(&grlib_gptimer_info);
392
}
393

    
394
device_init(grlib_gptimer_register)