Statistics
| Branch: | Revision:

root / hw / grlib_gptimer.c @ be62a2eb

History | View | Annotate | Download (10.6 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
    MemoryRegion iomem;
72

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

    
77
    GPTimer *timers;
78

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

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

    
89

    
90
    ptimer_stop(timer->ptimer);
91

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

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

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

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

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

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

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

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

    
122
    assert(unit != NULL);
123

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

    
130
    trace_grlib_gptimer_set_scaler(scaler, value);
131

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

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

    
142
    trace_grlib_gptimer_hit(timer->id);
143

    
144
    /* Timer expired */
145

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

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

    
157
static uint64_t grlib_gptimer_read(void *opaque, target_phys_addr_t addr,
158
                                   unsigned size)
159
{
160
    GPTimerUnit        *unit  = opaque;
161
    target_phys_addr_t  timer_addr;
162
    int                 id;
163
    uint32_t            value = 0;
164

    
165
    addr &= 0xff;
166

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

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

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

    
181
    default:
182
        break;
183
    }
184

    
185
    timer_addr = (addr % TIMER_BASE);
186
    id         = (addr - TIMER_BASE) / TIMER_BASE;
187

    
188
    if (id >= 0 && id < unit->nr_timers) {
189

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

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

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

    
206
        default:
207
            break;
208
        }
209

    
210
    }
211

    
212
    trace_grlib_gptimer_readl(-1, addr, 0);
213
    return 0;
214
}
215

    
216
static void grlib_gptimer_write(void *opaque, target_phys_addr_t addr,
217
                                uint64_t value, unsigned size)
218
{
219
    GPTimerUnit        *unit = opaque;
220
    target_phys_addr_t  timer_addr;
221
    int                 id;
222

    
223
    addr &= 0xff;
224

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

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

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

    
245
    default:
246
        break;
247
    }
248

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

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

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

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

    
267
        case CONFIG_OFFSET:
268
            trace_grlib_gptimer_writel(id, addr, value);
269

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

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

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

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

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

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

    
295
        default:
296
            break;
297
        }
298

    
299
    }
300

    
301
    trace_grlib_gptimer_writel(-1, addr, value);
302
}
303

    
304
static const MemoryRegionOps grlib_gptimer_ops = {
305
    .read = grlib_gptimer_read,
306
    .write = grlib_gptimer_write,
307
    .endianness = DEVICE_NATIVE_ENDIAN,
308
    .valid = {
309
        .min_access_size = 4,
310
        .max_access_size = 4,
311
    },
312
};
313

    
314
static void grlib_gptimer_reset(DeviceState *d)
315
{
316
    GPTimerUnit *unit = container_of(d, GPTimerUnit, busdev.qdev);
317
    int          i    = 0;
318

    
319
    assert(unit != NULL);
320

    
321
    unit->scaler = 0;
322
    unit->reload = 0;
323
    unit->config = 0;
324

    
325
    unit->config  = unit->nr_timers;
326
    unit->config |= unit->irq_line << 3;
327
    unit->config |= 1 << 8;     /* separate interrupt */
328
    unit->config |= 1 << 9;     /* Disable timer freeze */
329

    
330

    
331
    for (i = 0; i < unit->nr_timers; i++) {
332
        GPTimer *timer = &unit->timers[i];
333

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

    
343
static int grlib_gptimer_init(SysBusDevice *dev)
344
{
345
    GPTimerUnit  *unit = FROM_SYSBUS(typeof(*unit), dev);
346
    unsigned int  i;
347

    
348
    assert(unit->nr_timers > 0);
349
    assert(unit->nr_timers <= GPTIMER_MAX_TIMERS);
350

    
351
    unit->timers = g_malloc0(sizeof unit->timers[0] * unit->nr_timers);
352

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

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

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

    
364
        ptimer_set_freq(timer->ptimer, unit->freq_hz);
365
    }
366

    
367
    memory_region_init_io(&unit->iomem, &grlib_gptimer_ops, unit, "gptimer",
368
                          UNIT_REG_SIZE + GPTIMER_REG_SIZE * unit->nr_timers);
369

    
370
    sysbus_init_mmio(dev, &unit->iomem);
371
    return 0;
372
}
373

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

    
387
static void grlib_gptimer_register(void)
388
{
389
    sysbus_register_withprop(&grlib_gptimer_info);
390
}
391

    
392
device_init(grlib_gptimer_register)