~ubuntu-branches/ubuntu/wily/qemu-kvm-spice/wily

« back to all changes in this revision

Viewing changes to hw/grlib_gptimer.c

  • Committer: Bazaar Package Importer
  • Author(s): Serge Hallyn
  • Date: 2011-10-19 10:44:56 UTC
  • Revision ID: james.westby@ubuntu.com-20111019104456-xgvskumk3sxi97f4
Tags: upstream-0.15.0+noroms
ImportĀ upstreamĀ versionĀ 0.15.0+noroms

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 = qemu_mallocz(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)