Statistics
| Branch: | Revision:

root / hw / grlib_gptimer.c @ 5251d196

History | View | Annotate | Download (10.8 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, "scaler:", unit->scaler);
169
        return unit->scaler;
170

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

    
175
    case CONFIG_OFFSET:
176
        trace_grlib_gptimer_readl(-1, "config:", 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, "counter value:", value);
193
            return value;
194

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

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

    
205
        default:
206
            break;
207
        }
208

    
209
    }
210

    
211
    trace_grlib_gptimer_unknown_register("read", addr);
212
    return 0;
213
}
214

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

    
222
    addr &= 0xff;
223

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

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

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

    
244
    default:
245
        break;
246
    }
247

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

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

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

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

    
266
        case CONFIG_OFFSET:
267
            trace_grlib_gptimer_writel(id, "config:", value);
268

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

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

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

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

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

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

    
294
        default:
295
            break;
296
        }
297

    
298
    }
299

    
300
    trace_grlib_gptimer_unknown_register("write", addr);
301
}
302

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

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

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

    
316
    assert(unit != NULL);
317

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

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

    
327

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

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

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

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

    
349
    unit->timers = qemu_mallocz(sizeof unit->timers[0] * unit->nr_timers);
350

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

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

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

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

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

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

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

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

    
395
device_init(grlib_gptimer_register)