Statistics
| Branch: | Revision:

root / hw / etraxfs_timer.c @ 0200db65

History | View | Annotate | Download (8.4 kB)

1
/*
2
 * QEMU ETRAX Timers
3
 *
4
 * Copyright (c) 2007 Edgar E. Iglesias, Axis Communications AB.
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 "sysbus.h"
25
#include "sysemu.h"
26
#include "qemu-timer.h"
27

    
28
#define D(x)
29

    
30
#define RW_TMR0_DIV   0x00
31
#define R_TMR0_DATA   0x04
32
#define RW_TMR0_CTRL  0x08
33
#define RW_TMR1_DIV   0x10
34
#define R_TMR1_DATA   0x14
35
#define RW_TMR1_CTRL  0x18
36
#define R_TIME        0x38
37
#define RW_WD_CTRL    0x40
38
#define R_WD_STAT     0x44
39
#define RW_INTR_MASK  0x48
40
#define RW_ACK_INTR   0x4c
41
#define R_INTR        0x50
42
#define R_MASKED_INTR 0x54
43

    
44
struct etrax_timer {
45
    SysBusDevice busdev;
46
    MemoryRegion mmio;
47
    qemu_irq irq;
48
    qemu_irq nmi;
49

    
50
    QEMUBH *bh_t0;
51
    QEMUBH *bh_t1;
52
    QEMUBH *bh_wd;
53
    ptimer_state *ptimer_t0;
54
    ptimer_state *ptimer_t1;
55
    ptimer_state *ptimer_wd;
56

    
57
    int wd_hits;
58

    
59
    /* Control registers.  */
60
    uint32_t rw_tmr0_div;
61
    uint32_t r_tmr0_data;
62
    uint32_t rw_tmr0_ctrl;
63

    
64
    uint32_t rw_tmr1_div;
65
    uint32_t r_tmr1_data;
66
    uint32_t rw_tmr1_ctrl;
67

    
68
    uint32_t rw_wd_ctrl;
69

    
70
    uint32_t rw_intr_mask;
71
    uint32_t rw_ack_intr;
72
    uint32_t r_intr;
73
    uint32_t r_masked_intr;
74
};
75

    
76
static uint64_t
77
timer_read(void *opaque, target_phys_addr_t addr, unsigned int size)
78
{
79
    struct etrax_timer *t = opaque;
80
    uint32_t r = 0;
81

    
82
    switch (addr) {
83
    case R_TMR0_DATA:
84
        r = ptimer_get_count(t->ptimer_t0);
85
        break;
86
    case R_TMR1_DATA:
87
        r = ptimer_get_count(t->ptimer_t1);
88
        break;
89
    case R_TIME:
90
        r = qemu_get_clock_ns(vm_clock) / 10;
91
        break;
92
    case RW_INTR_MASK:
93
        r = t->rw_intr_mask;
94
        break;
95
    case R_MASKED_INTR:
96
        r = t->r_intr & t->rw_intr_mask;
97
        break;
98
    default:
99
        D(printf ("%s %x\n", __func__, addr));
100
        break;
101
    }
102
    return r;
103
}
104

    
105
static void update_ctrl(struct etrax_timer *t, int tnum)
106
{
107
    unsigned int op;
108
    unsigned int freq;
109
    unsigned int freq_hz;
110
    unsigned int div;
111
    uint32_t ctrl;
112

    
113
    ptimer_state *timer;
114

    
115
    if (tnum == 0) {
116
        ctrl = t->rw_tmr0_ctrl;
117
        div = t->rw_tmr0_div;
118
        timer = t->ptimer_t0;
119
    } else {
120
        ctrl = t->rw_tmr1_ctrl;
121
        div = t->rw_tmr1_div;
122
        timer = t->ptimer_t1;
123
    }
124

    
125

    
126
    op = ctrl & 3;
127
    freq = ctrl >> 2;
128
    freq_hz = 32000000;
129

    
130
    switch (freq)
131
    {
132
    case 0:
133
    case 1:
134
        D(printf ("extern or disabled timer clock?\n"));
135
        break;
136
    case 4: freq_hz =  29493000; break;
137
    case 5: freq_hz =  32000000; break;
138
    case 6: freq_hz =  32768000; break;
139
    case 7: freq_hz = 100000000; break;
140
    default:
141
        abort();
142
        break;
143
    }
144

    
145
    D(printf ("freq_hz=%d div=%d\n", freq_hz, div));
146
    ptimer_set_freq(timer, freq_hz);
147
    ptimer_set_limit(timer, div, 0);
148

    
149
    switch (op)
150
    {
151
        case 0:
152
            /* Load.  */
153
            ptimer_set_limit(timer, div, 1);
154
            break;
155
        case 1:
156
            /* Hold.  */
157
            ptimer_stop(timer);
158
            break;
159
        case 2:
160
            /* Run.  */
161
            ptimer_run(timer, 0);
162
            break;
163
        default:
164
            abort();
165
            break;
166
    }
167
}
168

    
169
static void timer_update_irq(struct etrax_timer *t)
170
{
171
    t->r_intr &= ~(t->rw_ack_intr);
172
    t->r_masked_intr = t->r_intr & t->rw_intr_mask;
173

    
174
    D(printf("%s: masked_intr=%x\n", __func__, t->r_masked_intr));
175
    qemu_set_irq(t->irq, !!t->r_masked_intr);
176
}
177

    
178
static void timer0_hit(void *opaque)
179
{
180
    struct etrax_timer *t = opaque;
181
    t->r_intr |= 1;
182
    timer_update_irq(t);
183
}
184

    
185
static void timer1_hit(void *opaque)
186
{
187
    struct etrax_timer *t = opaque;
188
    t->r_intr |= 2;
189
    timer_update_irq(t);
190
}
191

    
192
static void watchdog_hit(void *opaque)
193
{
194
    struct etrax_timer *t = opaque;
195
    if (t->wd_hits == 0) {
196
        /* real hw gives a single tick before reseting but we are
197
           a bit friendlier to compensate for our slower execution.  */
198
        ptimer_set_count(t->ptimer_wd, 10);
199
        ptimer_run(t->ptimer_wd, 1);
200
        qemu_irq_raise(t->nmi);
201
    }
202
    else
203
        qemu_system_reset_request();
204

    
205
    t->wd_hits++;
206
}
207

    
208
static inline void timer_watchdog_update(struct etrax_timer *t, uint32_t value)
209
{
210
    unsigned int wd_en = t->rw_wd_ctrl & (1 << 8);
211
    unsigned int wd_key = t->rw_wd_ctrl >> 9;
212
    unsigned int wd_cnt = t->rw_wd_ctrl & 511;
213
    unsigned int new_key = value >> 9 & ((1 << 7) - 1);
214
    unsigned int new_cmd = (value >> 8) & 1;
215

    
216
    /* If the watchdog is enabled, they written key must match the
217
       complement of the previous.  */
218
    wd_key = ~wd_key & ((1 << 7) - 1);
219

    
220
    if (wd_en && wd_key != new_key)
221
        return;
222

    
223
    D(printf("en=%d new_key=%x oldkey=%x cmd=%d cnt=%d\n", 
224
         wd_en, new_key, wd_key, new_cmd, wd_cnt));
225

    
226
    if (t->wd_hits)
227
        qemu_irq_lower(t->nmi);
228

    
229
    t->wd_hits = 0;
230

    
231
    ptimer_set_freq(t->ptimer_wd, 760);
232
    if (wd_cnt == 0)
233
        wd_cnt = 256;
234
    ptimer_set_count(t->ptimer_wd, wd_cnt);
235
    if (new_cmd)
236
        ptimer_run(t->ptimer_wd, 1);
237
    else
238
        ptimer_stop(t->ptimer_wd);
239

    
240
    t->rw_wd_ctrl = value;
241
}
242

    
243
static void
244
timer_write(void *opaque, target_phys_addr_t addr,
245
            uint64_t val64, unsigned int size)
246
{
247
    struct etrax_timer *t = opaque;
248
    uint32_t value = val64;
249

    
250
    switch (addr)
251
    {
252
        case RW_TMR0_DIV:
253
            t->rw_tmr0_div = value;
254
            break;
255
        case RW_TMR0_CTRL:
256
            D(printf ("RW_TMR0_CTRL=%x\n", value));
257
            t->rw_tmr0_ctrl = value;
258
            update_ctrl(t, 0);
259
            break;
260
        case RW_TMR1_DIV:
261
            t->rw_tmr1_div = value;
262
            break;
263
        case RW_TMR1_CTRL:
264
            D(printf ("RW_TMR1_CTRL=%x\n", value));
265
            t->rw_tmr1_ctrl = value;
266
            update_ctrl(t, 1);
267
            break;
268
        case RW_INTR_MASK:
269
            D(printf ("RW_INTR_MASK=%x\n", value));
270
            t->rw_intr_mask = value;
271
            timer_update_irq(t);
272
            break;
273
        case RW_WD_CTRL:
274
            timer_watchdog_update(t, value);
275
            break;
276
        case RW_ACK_INTR:
277
            t->rw_ack_intr = value;
278
            timer_update_irq(t);
279
            t->rw_ack_intr = 0;
280
            break;
281
        default:
282
            printf ("%s " TARGET_FMT_plx " %x\n",
283
                __func__, addr, value);
284
            break;
285
    }
286
}
287

    
288
static const MemoryRegionOps timer_ops = {
289
    .read = timer_read,
290
    .write = timer_write,
291
    .endianness = DEVICE_LITTLE_ENDIAN,
292
    .valid = {
293
        .min_access_size = 4,
294
        .max_access_size = 4
295
    }
296
};
297

    
298
static void etraxfs_timer_reset(void *opaque)
299
{
300
    struct etrax_timer *t = opaque;
301

    
302
    ptimer_stop(t->ptimer_t0);
303
    ptimer_stop(t->ptimer_t1);
304
    ptimer_stop(t->ptimer_wd);
305
    t->rw_wd_ctrl = 0;
306
    t->r_intr = 0;
307
    t->rw_intr_mask = 0;
308
    qemu_irq_lower(t->irq);
309
}
310

    
311
static int etraxfs_timer_init(SysBusDevice *dev)
312
{
313
    struct etrax_timer *t = FROM_SYSBUS(typeof (*t), dev);
314

    
315
    t->bh_t0 = qemu_bh_new(timer0_hit, t);
316
    t->bh_t1 = qemu_bh_new(timer1_hit, t);
317
    t->bh_wd = qemu_bh_new(watchdog_hit, t);
318
    t->ptimer_t0 = ptimer_init(t->bh_t0);
319
    t->ptimer_t1 = ptimer_init(t->bh_t1);
320
    t->ptimer_wd = ptimer_init(t->bh_wd);
321

    
322
    sysbus_init_irq(dev, &t->irq);
323
    sysbus_init_irq(dev, &t->nmi);
324

    
325
    memory_region_init_io(&t->mmio, &timer_ops, t, "etraxfs-timer", 0x5c);
326
    sysbus_init_mmio_region(dev, &t->mmio);
327
    qemu_register_reset(etraxfs_timer_reset, t);
328
    return 0;
329
}
330

    
331
static void etraxfs_timer_register(void)
332
{
333
    sysbus_register_dev("etraxfs,timer", sizeof (struct etrax_timer),
334
                        etraxfs_timer_init);
335
}
336

    
337
device_init(etraxfs_timer_register)