Statistics
| Branch: | Revision:

root / hw / syborg_timer.c @ 0f921197

History | View | Annotate | Download (6.6 kB)

1 4af39611 Paul Brook
/*
2 4af39611 Paul Brook
 * Syborg Interval Timer.
3 4af39611 Paul Brook
 *
4 4af39611 Paul Brook
 * Copyright (c) 2008 CodeSourcery
5 4af39611 Paul Brook
 *
6 4af39611 Paul Brook
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 4af39611 Paul Brook
 * of this software and associated documentation files (the "Software"), to deal
8 4af39611 Paul Brook
 * in the Software without restriction, including without limitation the rights
9 4af39611 Paul Brook
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 4af39611 Paul Brook
 * copies of the Software, and to permit persons to whom the Software is
11 4af39611 Paul Brook
 * furnished to do so, subject to the following conditions:
12 4af39611 Paul Brook
 *
13 4af39611 Paul Brook
 * The above copyright notice and this permission notice shall be included in
14 4af39611 Paul Brook
 * all copies or substantial portions of the Software.
15 4af39611 Paul Brook
 *
16 4af39611 Paul Brook
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 4af39611 Paul Brook
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 4af39611 Paul Brook
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 4af39611 Paul Brook
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 4af39611 Paul Brook
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 4af39611 Paul Brook
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 4af39611 Paul Brook
 * THE SOFTWARE.
23 4af39611 Paul Brook
 */
24 4af39611 Paul Brook
25 4af39611 Paul Brook
#include "sysbus.h"
26 4af39611 Paul Brook
#include "qemu-timer.h"
27 4af39611 Paul Brook
#include "syborg.h"
28 4af39611 Paul Brook
29 4af39611 Paul Brook
//#define DEBUG_SYBORG_TIMER
30 4af39611 Paul Brook
31 4af39611 Paul Brook
#ifdef DEBUG_SYBORG_TIMER
32 4af39611 Paul Brook
#define DPRINTF(fmt, ...) \
33 4af39611 Paul Brook
do { printf("syborg_timer: " fmt , ##args); } while (0)
34 4af39611 Paul Brook
#define BADF(fmt, ...) \
35 4af39611 Paul Brook
do { fprintf(stderr, "syborg_timer: error: " fmt , ## __VA_ARGS__); \
36 4af39611 Paul Brook
    exit(1);} while (0)
37 4af39611 Paul Brook
#else
38 4af39611 Paul Brook
#define DPRINTF(fmt, ...) do {} while(0)
39 4af39611 Paul Brook
#define BADF(fmt, ...) \
40 4af39611 Paul Brook
do { fprintf(stderr, "syborg_timer: error: " fmt , ## __VA_ARGS__);} while (0)
41 4af39611 Paul Brook
#endif
42 4af39611 Paul Brook
43 4af39611 Paul Brook
enum {
44 4af39611 Paul Brook
    TIMER_ID          = 0,
45 4af39611 Paul Brook
    TIMER_RUNNING     = 1,
46 4af39611 Paul Brook
    TIMER_ONESHOT     = 2,
47 4af39611 Paul Brook
    TIMER_LIMIT       = 3,
48 4af39611 Paul Brook
    TIMER_VALUE       = 4,
49 4af39611 Paul Brook
    TIMER_INT_ENABLE  = 5,
50 4af39611 Paul Brook
    TIMER_INT_STATUS  = 6,
51 4af39611 Paul Brook
    TIMER_FREQ        = 7
52 4af39611 Paul Brook
};
53 4af39611 Paul Brook
54 4af39611 Paul Brook
typedef struct {
55 4af39611 Paul Brook
    SysBusDevice busdev;
56 4af39611 Paul Brook
    ptimer_state *timer;
57 4af39611 Paul Brook
    int running;
58 4af39611 Paul Brook
    int oneshot;
59 4af39611 Paul Brook
    uint32_t limit;
60 4af39611 Paul Brook
    uint32_t freq;
61 4af39611 Paul Brook
    uint32_t int_level;
62 4af39611 Paul Brook
    uint32_t int_enabled;
63 4af39611 Paul Brook
    qemu_irq irq;
64 4af39611 Paul Brook
} SyborgTimerState;
65 4af39611 Paul Brook
66 4af39611 Paul Brook
static void syborg_timer_update(SyborgTimerState *s)
67 4af39611 Paul Brook
{
68 4af39611 Paul Brook
    /* Update interrupt.  */
69 4af39611 Paul Brook
    if (s->int_level && s->int_enabled) {
70 4af39611 Paul Brook
        qemu_irq_raise(s->irq);
71 4af39611 Paul Brook
    } else {
72 4af39611 Paul Brook
        qemu_irq_lower(s->irq);
73 4af39611 Paul Brook
    }
74 4af39611 Paul Brook
}
75 4af39611 Paul Brook
76 4af39611 Paul Brook
static void syborg_timer_tick(void *opaque)
77 4af39611 Paul Brook
{
78 4af39611 Paul Brook
    SyborgTimerState *s = (SyborgTimerState *)opaque;
79 4af39611 Paul Brook
    //DPRINTF("Timer Tick\n");
80 4af39611 Paul Brook
    s->int_level = 1;
81 4af39611 Paul Brook
    if (s->oneshot)
82 4af39611 Paul Brook
        s->running = 0;
83 4af39611 Paul Brook
    syborg_timer_update(s);
84 4af39611 Paul Brook
}
85 4af39611 Paul Brook
86 c227f099 Anthony Liguori
static uint32_t syborg_timer_read(void *opaque, target_phys_addr_t offset)
87 4af39611 Paul Brook
{
88 4af39611 Paul Brook
    SyborgTimerState *s = (SyborgTimerState *)opaque;
89 4af39611 Paul Brook
90 4af39611 Paul Brook
    DPRINTF("Reg read %d\n", (int)offset);
91 4af39611 Paul Brook
    offset &= 0xfff;
92 4af39611 Paul Brook
    switch (offset >> 2) {
93 4af39611 Paul Brook
    case TIMER_ID:
94 4af39611 Paul Brook
        return SYBORG_ID_TIMER;
95 4af39611 Paul Brook
    case TIMER_RUNNING:
96 4af39611 Paul Brook
        return s->running;
97 4af39611 Paul Brook
    case TIMER_ONESHOT:
98 4af39611 Paul Brook
        return s->oneshot;
99 4af39611 Paul Brook
    case TIMER_LIMIT:
100 4af39611 Paul Brook
        return s->limit;
101 4af39611 Paul Brook
    case TIMER_VALUE:
102 4af39611 Paul Brook
        return ptimer_get_count(s->timer);
103 4af39611 Paul Brook
    case TIMER_INT_ENABLE:
104 4af39611 Paul Brook
        return s->int_enabled;
105 4af39611 Paul Brook
    case TIMER_INT_STATUS:
106 4af39611 Paul Brook
        return s->int_level;
107 4af39611 Paul Brook
    case TIMER_FREQ:
108 4af39611 Paul Brook
        return s->freq;
109 4af39611 Paul Brook
    default:
110 4af39611 Paul Brook
        cpu_abort(cpu_single_env, "syborg_timer_read: Bad offset %x\n",
111 4af39611 Paul Brook
                  (int)offset);
112 4af39611 Paul Brook
        return 0;
113 4af39611 Paul Brook
    }
114 4af39611 Paul Brook
}
115 4af39611 Paul Brook
116 c227f099 Anthony Liguori
static void syborg_timer_write(void *opaque, target_phys_addr_t offset,
117 4af39611 Paul Brook
                               uint32_t value)
118 4af39611 Paul Brook
{
119 4af39611 Paul Brook
    SyborgTimerState *s = (SyborgTimerState *)opaque;
120 4af39611 Paul Brook
121 4af39611 Paul Brook
    DPRINTF("Reg write %d\n", (int)offset);
122 4af39611 Paul Brook
    offset &= 0xfff;
123 4af39611 Paul Brook
    switch (offset >> 2) {
124 4af39611 Paul Brook
    case TIMER_RUNNING:
125 4af39611 Paul Brook
        if (value == s->running)
126 4af39611 Paul Brook
            break;
127 4af39611 Paul Brook
        s->running = value;
128 4af39611 Paul Brook
        if (value) {
129 4af39611 Paul Brook
            ptimer_run(s->timer, s->oneshot);
130 4af39611 Paul Brook
        } else {
131 4af39611 Paul Brook
            ptimer_stop(s->timer);
132 4af39611 Paul Brook
        }
133 4af39611 Paul Brook
        break;
134 4af39611 Paul Brook
    case TIMER_ONESHOT:
135 4af39611 Paul Brook
        if (s->running) {
136 4af39611 Paul Brook
            ptimer_stop(s->timer);
137 4af39611 Paul Brook
        }
138 4af39611 Paul Brook
        s->oneshot = value;
139 4af39611 Paul Brook
        if (s->running) {
140 4af39611 Paul Brook
            ptimer_run(s->timer, s->oneshot);
141 4af39611 Paul Brook
        }
142 4af39611 Paul Brook
        break;
143 4af39611 Paul Brook
    case TIMER_LIMIT:
144 4af39611 Paul Brook
        s->limit = value;
145 4af39611 Paul Brook
        ptimer_set_limit(s->timer, value, 1);
146 4af39611 Paul Brook
        break;
147 4af39611 Paul Brook
    case TIMER_VALUE:
148 4af39611 Paul Brook
        ptimer_set_count(s->timer, value);
149 4af39611 Paul Brook
        break;
150 4af39611 Paul Brook
    case TIMER_INT_ENABLE:
151 4af39611 Paul Brook
        s->int_enabled = value;
152 4af39611 Paul Brook
        syborg_timer_update(s);
153 4af39611 Paul Brook
        break;
154 4af39611 Paul Brook
    case TIMER_INT_STATUS:
155 4af39611 Paul Brook
        s->int_level &= ~value;
156 4af39611 Paul Brook
        syborg_timer_update(s);
157 4af39611 Paul Brook
        break;
158 4af39611 Paul Brook
    default:
159 4af39611 Paul Brook
        cpu_abort(cpu_single_env, "syborg_timer_write: Bad offset %x\n",
160 4af39611 Paul Brook
                  (int)offset);
161 4af39611 Paul Brook
        break;
162 4af39611 Paul Brook
    }
163 4af39611 Paul Brook
}
164 4af39611 Paul Brook
165 d60efc6b Blue Swirl
static CPUReadMemoryFunc * const syborg_timer_readfn[] = {
166 4af39611 Paul Brook
    syborg_timer_read,
167 4af39611 Paul Brook
    syborg_timer_read,
168 4af39611 Paul Brook
    syborg_timer_read
169 4af39611 Paul Brook
};
170 4af39611 Paul Brook
171 d60efc6b Blue Swirl
static CPUWriteMemoryFunc * const syborg_timer_writefn[] = {
172 4af39611 Paul Brook
    syborg_timer_write,
173 4af39611 Paul Brook
    syborg_timer_write,
174 4af39611 Paul Brook
    syborg_timer_write
175 4af39611 Paul Brook
};
176 4af39611 Paul Brook
177 4af39611 Paul Brook
static void syborg_timer_save(QEMUFile *f, void *opaque)
178 4af39611 Paul Brook
{
179 4af39611 Paul Brook
    SyborgTimerState *s = opaque;
180 4af39611 Paul Brook
181 4af39611 Paul Brook
    qemu_put_be32(f, s->running);
182 4af39611 Paul Brook
    qemu_put_be32(f, s->oneshot);
183 4af39611 Paul Brook
    qemu_put_be32(f, s->limit);
184 4af39611 Paul Brook
    qemu_put_be32(f, s->int_level);
185 4af39611 Paul Brook
    qemu_put_be32(f, s->int_enabled);
186 4af39611 Paul Brook
    qemu_put_ptimer(f, s->timer);
187 4af39611 Paul Brook
}
188 4af39611 Paul Brook
189 4af39611 Paul Brook
static int syborg_timer_load(QEMUFile *f, void *opaque, int version_id)
190 4af39611 Paul Brook
{
191 4af39611 Paul Brook
    SyborgTimerState *s = opaque;
192 4af39611 Paul Brook
193 4af39611 Paul Brook
    if (version_id != 1)
194 4af39611 Paul Brook
        return -EINVAL;
195 4af39611 Paul Brook
196 4af39611 Paul Brook
    s->running = qemu_get_be32(f);
197 4af39611 Paul Brook
    s->oneshot = qemu_get_be32(f);
198 4af39611 Paul Brook
    s->limit = qemu_get_be32(f);
199 4af39611 Paul Brook
    s->int_level = qemu_get_be32(f);
200 4af39611 Paul Brook
    s->int_enabled = qemu_get_be32(f);
201 4af39611 Paul Brook
    qemu_get_ptimer(f, s->timer);
202 4af39611 Paul Brook
203 4af39611 Paul Brook
    return 0;
204 4af39611 Paul Brook
}
205 4af39611 Paul Brook
206 81a322d4 Gerd Hoffmann
static int syborg_timer_init(SysBusDevice *dev)
207 4af39611 Paul Brook
{
208 4af39611 Paul Brook
    SyborgTimerState *s = FROM_SYSBUS(SyborgTimerState, dev);
209 4af39611 Paul Brook
    QEMUBH *bh;
210 4af39611 Paul Brook
    int iomemtype;
211 4af39611 Paul Brook
212 4af39611 Paul Brook
    if (s->freq == 0) {
213 4af39611 Paul Brook
        fprintf(stderr, "syborg_timer: Zero/unset frequency\n");
214 4af39611 Paul Brook
        exit(1);
215 4af39611 Paul Brook
    }
216 4af39611 Paul Brook
    sysbus_init_irq(dev, &s->irq);
217 1eed09cb Avi Kivity
    iomemtype = cpu_register_io_memory(syborg_timer_readfn,
218 4af39611 Paul Brook
                                       syborg_timer_writefn, s);
219 4af39611 Paul Brook
    sysbus_init_mmio(dev, 0x1000, iomemtype);
220 4af39611 Paul Brook
221 4af39611 Paul Brook
    bh = qemu_bh_new(syborg_timer_tick, s);
222 4af39611 Paul Brook
    s->timer = ptimer_init(bh);
223 4af39611 Paul Brook
    ptimer_set_freq(s->timer, s->freq);
224 4af39611 Paul Brook
    register_savevm("syborg_timer", -1, 1,
225 4af39611 Paul Brook
                    syborg_timer_save, syborg_timer_load, s);
226 81a322d4 Gerd Hoffmann
    return 0;
227 4af39611 Paul Brook
}
228 4af39611 Paul Brook
229 1431b6a1 Paul Brook
static SysBusDeviceInfo syborg_timer_info = {
230 1431b6a1 Paul Brook
    .init = syborg_timer_init,
231 074f2fff Gerd Hoffmann
    .qdev.name  = "syborg,timer",
232 074f2fff Gerd Hoffmann
    .qdev.size  = sizeof(SyborgTimerState),
233 ee6847d1 Gerd Hoffmann
    .qdev.props = (Property[]) {
234 083301fc Gerd Hoffmann
        DEFINE_PROP_UINT32("frequency",SyborgTimerState, freq, 0),
235 083301fc Gerd Hoffmann
        DEFINE_PROP_END_OF_LIST(),
236 1431b6a1 Paul Brook
    }
237 1431b6a1 Paul Brook
};
238 1431b6a1 Paul Brook
239 4af39611 Paul Brook
static void syborg_timer_register_devices(void)
240 4af39611 Paul Brook
{
241 074f2fff Gerd Hoffmann
    sysbus_register_withprop(&syborg_timer_info);
242 4af39611 Paul Brook
}
243 4af39611 Paul Brook
244 4af39611 Paul Brook
device_init(syborg_timer_register_devices)