Statistics
| Branch: | Revision:

root / hw / slavio_timer.c @ 85e3023e

History | View | Annotate | Download (12 kB)

1
/*
2
 * QEMU Sparc SLAVIO timer controller emulation
3
 *
4
 * Copyright (c) 2003-2005 Fabrice Bellard
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
#include "hw.h"
25
#include "sun4m.h"
26
#include "qemu-timer.h"
27

    
28
//#define DEBUG_TIMER
29

    
30
#ifdef DEBUG_TIMER
31
#define DPRINTF(fmt, args...) \
32
do { printf("TIMER: " fmt , ##args); } while (0)
33
#else
34
#define DPRINTF(fmt, args...)
35
#endif
36

    
37
/*
38
 * Registers of hardware timer in sun4m.
39
 *
40
 * This is the timer/counter part of chip STP2001 (Slave I/O), also
41
 * produced as NCR89C105. See
42
 * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
43
 *
44
 * The 31-bit counter is incremented every 500ns by bit 9. Bits 8..0
45
 * are zero. Bit 31 is 1 when count has been reached.
46
 *
47
 * Per-CPU timers interrupt local CPU, system timer uses normal
48
 * interrupt routing.
49
 *
50
 */
51

    
52
#define MAX_CPUS 16
53

    
54
typedef struct SLAVIO_TIMERState {
55
    qemu_irq irq;
56
    ptimer_state *timer;
57
    uint32_t count, counthigh, reached;
58
    uint64_t limit;
59
    // processor only
60
    int running;
61
    struct SLAVIO_TIMERState *master;
62
    int slave_index;
63
    // system only
64
    unsigned int num_slaves;
65
    struct SLAVIO_TIMERState *slave[MAX_CPUS];
66
    uint32_t slave_mode;
67
} SLAVIO_TIMERState;
68

    
69
#define TIMER_MAXADDR 0x1f
70
#define SYS_TIMER_SIZE 0x14
71
#define CPU_TIMER_SIZE 0x10
72

    
73
#define SYS_TIMER_OFFSET      0x10000ULL
74
#define CPU_TIMER_OFFSET(cpu) (0x1000ULL * cpu)
75

    
76
#define TIMER_LIMIT         0
77
#define TIMER_COUNTER       1
78
#define TIMER_COUNTER_NORST 2
79
#define TIMER_STATUS        3
80
#define TIMER_MODE          4
81

    
82
#define TIMER_COUNT_MASK32 0xfffffe00
83
#define TIMER_LIMIT_MASK32 0x7fffffff
84
#define TIMER_MAX_COUNT64  0x7ffffffffffffe00ULL
85
#define TIMER_MAX_COUNT32  0x7ffffe00ULL
86
#define TIMER_REACHED      0x80000000
87
#define TIMER_PERIOD       500ULL // 500ns
88
#define LIMIT_TO_PERIODS(l) ((l) >> 9)
89
#define PERIODS_TO_LIMIT(l) ((l) << 9)
90

    
91
static int slavio_timer_is_user(SLAVIO_TIMERState *s)
92
{
93
    return s->master && (s->master->slave_mode & (1 << s->slave_index));
94
}
95

    
96
// Update count, set irq, update expire_time
97
// Convert from ptimer countdown units
98
static void slavio_timer_get_out(SLAVIO_TIMERState *s)
99
{
100
    uint64_t count, limit;
101

    
102
    if (s->limit == 0) /* free-run processor or system counter */
103
        limit = TIMER_MAX_COUNT32;
104
    else
105
        limit = s->limit;
106

    
107
    if (s->timer)
108
        count = limit - PERIODS_TO_LIMIT(ptimer_get_count(s->timer));
109
    else
110
        count = 0;
111

    
112
    DPRINTF("get_out: limit %" PRIx64 " count %x%08x\n", s->limit,
113
            s->counthigh, s->count);
114
    s->count = count & TIMER_COUNT_MASK32;
115
    s->counthigh = count >> 32;
116
}
117

    
118
// timer callback
119
static void slavio_timer_irq(void *opaque)
120
{
121
    SLAVIO_TIMERState *s = opaque;
122

    
123
    slavio_timer_get_out(s);
124
    DPRINTF("callback: count %x%08x\n", s->counthigh, s->count);
125
    if (!slavio_timer_is_user(s)) {
126
        s->reached = TIMER_REACHED;
127
        qemu_irq_raise(s->irq);
128
    }
129
}
130

    
131
static uint32_t slavio_timer_mem_readl(void *opaque, target_phys_addr_t addr)
132
{
133
    SLAVIO_TIMERState *s = opaque;
134
    uint32_t saddr, ret;
135

    
136
    saddr = (addr & TIMER_MAXADDR) >> 2;
137
    switch (saddr) {
138
    case TIMER_LIMIT:
139
        // read limit (system counter mode) or read most signifying
140
        // part of counter (user mode)
141
        if (slavio_timer_is_user(s)) {
142
            // read user timer MSW
143
            slavio_timer_get_out(s);
144
            ret = s->counthigh;
145
        } else {
146
            // read limit
147
            // clear irq
148
            qemu_irq_lower(s->irq);
149
            s->reached = 0;
150
            ret = s->limit & TIMER_LIMIT_MASK32;
151
        }
152
        break;
153
    case TIMER_COUNTER:
154
        // read counter and reached bit (system mode) or read lsbits
155
        // of counter (user mode)
156
        slavio_timer_get_out(s);
157
        if (slavio_timer_is_user(s)) // read user timer LSW
158
            ret = s->count & TIMER_COUNT_MASK32;
159
        else // read limit
160
            ret = (s->count & TIMER_MAX_COUNT32) | s->reached;
161
        break;
162
    case TIMER_STATUS:
163
        // only available in processor counter/timer
164
        // read start/stop status
165
        ret = s->running;
166
        break;
167
    case TIMER_MODE:
168
        // only available in system counter
169
        // read user/system mode
170
        ret = s->slave_mode;
171
        break;
172
    default:
173
        DPRINTF("invalid read address " TARGET_FMT_plx "\n", addr);
174
        ret = 0;
175
        break;
176
    }
177
    DPRINTF("read " TARGET_FMT_plx " = %08x\n", addr, ret);
178

    
179
    return ret;
180
}
181

    
182
static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr,
183
                                    uint32_t val)
184
{
185
    SLAVIO_TIMERState *s = opaque;
186
    uint32_t saddr;
187

    
188
    DPRINTF("write " TARGET_FMT_plx " %08x\n", addr, val);
189
    saddr = (addr & TIMER_MAXADDR) >> 2;
190
    switch (saddr) {
191
    case TIMER_LIMIT:
192
        if (slavio_timer_is_user(s)) {
193
            // set user counter MSW, reset counter
194
            qemu_irq_lower(s->irq);
195
            s->limit = TIMER_MAX_COUNT64;
196
            DPRINTF("processor %d user timer reset\n", s->slave_index);
197
            if (s->timer)
198
                ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(s->limit), 1);
199
        } else {
200
            // set limit, reset counter
201
            qemu_irq_lower(s->irq);
202
            s->limit = val & TIMER_MAX_COUNT32;
203
            if (s->timer) {
204
                if (s->limit == 0) /* free-run */
205
                    ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1);
206
                else
207
                    ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(s->limit), 1);
208
            }
209
        }
210
        break;
211
    case TIMER_COUNTER:
212
        if (slavio_timer_is_user(s)) {
213
            // set user counter LSW, reset counter
214
            qemu_irq_lower(s->irq);
215
            s->limit = TIMER_MAX_COUNT64;
216
            DPRINTF("processor %d user timer reset\n", s->slave_index);
217
            if (s->timer)
218
                ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(s->limit), 1);
219
        } else
220
            DPRINTF("not user timer\n");
221
        break;
222
    case TIMER_COUNTER_NORST:
223
        // set limit without resetting counter
224
        s->limit = val & TIMER_MAX_COUNT32;
225
        if (s->timer) {
226
            if (s->limit == 0)        /* free-run */
227
                ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 0);
228
            else
229
                ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(s->limit), 0);
230
        }
231
        break;
232
    case TIMER_STATUS:
233
        if (slavio_timer_is_user(s)) {
234
            // start/stop user counter
235
            if ((val & 1) && !s->running) {
236
                DPRINTF("processor %d user timer started\n", s->slave_index);
237
                if (s->timer)
238
                    ptimer_run(s->timer, 0);
239
                s->running = 1;
240
            } else if (!(val & 1) && s->running) {
241
                DPRINTF("processor %d user timer stopped\n", s->slave_index);
242
                if (s->timer)
243
                    ptimer_stop(s->timer);
244
                s->running = 0;
245
            }
246
        }
247
        break;
248
    case TIMER_MODE:
249
        if (s->master == NULL) {
250
            unsigned int i;
251

    
252
            for (i = 0; i < s->num_slaves; i++) {
253
                if (val & (1 << i)) {
254
                    qemu_irq_lower(s->slave[i]->irq);
255
                    s->slave[i]->limit = -1ULL;
256
                }
257
                if ((val & (1 << i)) != (s->slave_mode & (1 << i))) {
258
                    ptimer_stop(s->slave[i]->timer);
259
                    ptimer_set_limit(s->slave[i]->timer,
260
                                     LIMIT_TO_PERIODS(s->slave[i]->limit), 1);
261
                    DPRINTF("processor %d timer changed\n",
262
                            s->slave[i]->slave_index);
263
                    ptimer_run(s->slave[i]->timer, 0);
264
                }
265
            }
266
            s->slave_mode = val & ((1 << s->num_slaves) - 1);
267
        } else
268
            DPRINTF("not system timer\n");
269
        break;
270
    default:
271
        DPRINTF("invalid write address " TARGET_FMT_plx "\n", addr);
272
        break;
273
    }
274
}
275

    
276
static CPUReadMemoryFunc *slavio_timer_mem_read[3] = {
277
    slavio_timer_mem_readl,
278
    slavio_timer_mem_readl,
279
    slavio_timer_mem_readl,
280
};
281

    
282
static CPUWriteMemoryFunc *slavio_timer_mem_write[3] = {
283
    slavio_timer_mem_writel,
284
    slavio_timer_mem_writel,
285
    slavio_timer_mem_writel,
286
};
287

    
288
static void slavio_timer_save(QEMUFile *f, void *opaque)
289
{
290
    SLAVIO_TIMERState *s = opaque;
291

    
292
    qemu_put_be64s(f, &s->limit);
293
    qemu_put_be32s(f, &s->count);
294
    qemu_put_be32s(f, &s->counthigh);
295
    qemu_put_be32s(f, &s->reached);
296
    qemu_put_be32s(f, &s->running);
297
    if (s->timer)
298
        qemu_put_ptimer(f, s->timer);
299
}
300

    
301
static int slavio_timer_load(QEMUFile *f, void *opaque, int version_id)
302
{
303
    SLAVIO_TIMERState *s = opaque;
304

    
305
    if (version_id != 3)
306
        return -EINVAL;
307

    
308
    qemu_get_be64s(f, &s->limit);
309
    qemu_get_be32s(f, &s->count);
310
    qemu_get_be32s(f, &s->counthigh);
311
    qemu_get_be32s(f, &s->reached);
312
    qemu_get_be32s(f, &s->running);
313
    if (s->timer)
314
        qemu_get_ptimer(f, s->timer);
315

    
316
    return 0;
317
}
318

    
319
static void slavio_timer_reset(void *opaque)
320
{
321
    SLAVIO_TIMERState *s = opaque;
322

    
323
    s->limit = 0;
324
    s->count = 0;
325
    s->reached = 0;
326
    s->slave_mode = 0;
327
    if (!s->master || s->slave_index < s->master->num_slaves) {
328
        ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1);
329
        ptimer_run(s->timer, 0);
330
    }
331
    s->running = 1;
332
    qemu_irq_lower(s->irq);
333
}
334

    
335
static SLAVIO_TIMERState *slavio_timer_init(target_phys_addr_t addr,
336
                                            qemu_irq irq,
337
                                            SLAVIO_TIMERState *master,
338
                                            int slave_index)
339
{
340
    int slavio_timer_io_memory;
341
    SLAVIO_TIMERState *s;
342
    QEMUBH *bh;
343

    
344
    s = qemu_mallocz(sizeof(SLAVIO_TIMERState));
345
    if (!s)
346
        return s;
347
    s->irq = irq;
348
    s->master = master;
349
    s->slave_index = slave_index;
350
    if (!master || slave_index < master->num_slaves) {
351
        bh = qemu_bh_new(slavio_timer_irq, s);
352
        s->timer = ptimer_init(bh);
353
        ptimer_set_period(s->timer, TIMER_PERIOD);
354
    }
355

    
356
    slavio_timer_io_memory = cpu_register_io_memory(0, slavio_timer_mem_read,
357
                                                    slavio_timer_mem_write, s);
358
    if (master)
359
        cpu_register_physical_memory(addr, CPU_TIMER_SIZE,
360
                                     slavio_timer_io_memory);
361
    else
362
        cpu_register_physical_memory(addr, SYS_TIMER_SIZE,
363
                                     slavio_timer_io_memory);
364
    register_savevm("slavio_timer", addr, 3, slavio_timer_save,
365
                    slavio_timer_load, s);
366
    qemu_register_reset(slavio_timer_reset, s);
367
    slavio_timer_reset(s);
368

    
369
    return s;
370
}
371

    
372
void slavio_timer_init_all(target_phys_addr_t base, qemu_irq master_irq,
373
                           qemu_irq *cpu_irqs, unsigned int num_cpus)
374
{
375
    SLAVIO_TIMERState *master;
376
    unsigned int i;
377

    
378
    master = slavio_timer_init(base + SYS_TIMER_OFFSET, master_irq, NULL, 0);
379

    
380
    master->num_slaves = num_cpus;
381

    
382
    for (i = 0; i < MAX_CPUS; i++) {
383
        master->slave[i] = slavio_timer_init(base + (target_phys_addr_t)
384
                                             CPU_TIMER_OFFSET(i),
385
                                             cpu_irqs[i], master, i);
386
    }
387
}