Statistics
| Branch: | Revision:

root / hw / grlib_gptimer.c @ ad3376cc

History | View | Annotate | Download (10.7 kB)

1 0f3a4a01 Fabien Chouteau
/*
2 0f3a4a01 Fabien Chouteau
 * QEMU GRLIB GPTimer Emulator
3 0f3a4a01 Fabien Chouteau
 *
4 0f3a4a01 Fabien Chouteau
 * Copyright (c) 2010-2011 AdaCore
5 0f3a4a01 Fabien Chouteau
 *
6 0f3a4a01 Fabien Chouteau
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 0f3a4a01 Fabien Chouteau
 * of this software and associated documentation files (the "Software"), to deal
8 0f3a4a01 Fabien Chouteau
 * in the Software without restriction, including without limitation the rights
9 0f3a4a01 Fabien Chouteau
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 0f3a4a01 Fabien Chouteau
 * copies of the Software, and to permit persons to whom the Software is
11 0f3a4a01 Fabien Chouteau
 * furnished to do so, subject to the following conditions:
12 0f3a4a01 Fabien Chouteau
 *
13 0f3a4a01 Fabien Chouteau
 * The above copyright notice and this permission notice shall be included in
14 0f3a4a01 Fabien Chouteau
 * all copies or substantial portions of the Software.
15 0f3a4a01 Fabien Chouteau
 *
16 0f3a4a01 Fabien Chouteau
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 0f3a4a01 Fabien Chouteau
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 0f3a4a01 Fabien Chouteau
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 0f3a4a01 Fabien Chouteau
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 0f3a4a01 Fabien Chouteau
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 0f3a4a01 Fabien Chouteau
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 0f3a4a01 Fabien Chouteau
 * THE SOFTWARE.
23 0f3a4a01 Fabien Chouteau
 */
24 0f3a4a01 Fabien Chouteau
25 0f3a4a01 Fabien Chouteau
#include "sysbus.h"
26 0f3a4a01 Fabien Chouteau
#include "qemu-timer.h"
27 0f3a4a01 Fabien Chouteau
28 0f3a4a01 Fabien Chouteau
#include "trace.h"
29 0f3a4a01 Fabien Chouteau
30 0f3a4a01 Fabien Chouteau
#define UNIT_REG_SIZE    16     /* Size of memory mapped regs for the unit */
31 0f3a4a01 Fabien Chouteau
#define GPTIMER_REG_SIZE 16     /* Size of memory mapped regs for a GPTimer */
32 0f3a4a01 Fabien Chouteau
33 0f3a4a01 Fabien Chouteau
#define GPTIMER_MAX_TIMERS 8
34 0f3a4a01 Fabien Chouteau
35 0f3a4a01 Fabien Chouteau
/* GPTimer Config register fields */
36 0f3a4a01 Fabien Chouteau
#define GPTIMER_ENABLE      (1 << 0)
37 0f3a4a01 Fabien Chouteau
#define GPTIMER_RESTART     (1 << 1)
38 0f3a4a01 Fabien Chouteau
#define GPTIMER_LOAD        (1 << 2)
39 0f3a4a01 Fabien Chouteau
#define GPTIMER_INT_ENABLE  (1 << 3)
40 0f3a4a01 Fabien Chouteau
#define GPTIMER_INT_PENDING (1 << 4)
41 0f3a4a01 Fabien Chouteau
#define GPTIMER_CHAIN       (1 << 5) /* Not supported */
42 0f3a4a01 Fabien Chouteau
#define GPTIMER_DEBUG_HALT  (1 << 6) /* Not supported */
43 0f3a4a01 Fabien Chouteau
44 0f3a4a01 Fabien Chouteau
/* Memory mapped register offsets */
45 0f3a4a01 Fabien Chouteau
#define SCALER_OFFSET         0x00
46 0f3a4a01 Fabien Chouteau
#define SCALER_RELOAD_OFFSET  0x04
47 0f3a4a01 Fabien Chouteau
#define CONFIG_OFFSET         0x08
48 0f3a4a01 Fabien Chouteau
#define COUNTER_OFFSET        0x00
49 0f3a4a01 Fabien Chouteau
#define COUNTER_RELOAD_OFFSET 0x04
50 0f3a4a01 Fabien Chouteau
#define TIMER_BASE            0x10
51 0f3a4a01 Fabien Chouteau
52 0f3a4a01 Fabien Chouteau
typedef struct GPTimer     GPTimer;
53 0f3a4a01 Fabien Chouteau
typedef struct GPTimerUnit GPTimerUnit;
54 0f3a4a01 Fabien Chouteau
55 0f3a4a01 Fabien Chouteau
struct GPTimer {
56 0f3a4a01 Fabien Chouteau
    QEMUBH *bh;
57 0f3a4a01 Fabien Chouteau
    struct ptimer_state *ptimer;
58 0f3a4a01 Fabien Chouteau
59 0f3a4a01 Fabien Chouteau
    qemu_irq     irq;
60 0f3a4a01 Fabien Chouteau
    int          id;
61 0f3a4a01 Fabien Chouteau
    GPTimerUnit *unit;
62 0f3a4a01 Fabien Chouteau
63 0f3a4a01 Fabien Chouteau
    /* registers */
64 0f3a4a01 Fabien Chouteau
    uint32_t counter;
65 0f3a4a01 Fabien Chouteau
    uint32_t reload;
66 0f3a4a01 Fabien Chouteau
    uint32_t config;
67 0f3a4a01 Fabien Chouteau
};
68 0f3a4a01 Fabien Chouteau
69 0f3a4a01 Fabien Chouteau
struct GPTimerUnit {
70 0f3a4a01 Fabien Chouteau
    SysBusDevice  busdev;
71 0f3a4a01 Fabien Chouteau
72 0f3a4a01 Fabien Chouteau
    uint32_t nr_timers;         /* Number of timers available */
73 0f3a4a01 Fabien Chouteau
    uint32_t freq_hz;           /* System frequency */
74 0f3a4a01 Fabien Chouteau
    uint32_t irq_line;          /* Base irq line */
75 0f3a4a01 Fabien Chouteau
76 0f3a4a01 Fabien Chouteau
    GPTimer *timers;
77 0f3a4a01 Fabien Chouteau
78 0f3a4a01 Fabien Chouteau
    /* registers */
79 0f3a4a01 Fabien Chouteau
    uint32_t scaler;
80 0f3a4a01 Fabien Chouteau
    uint32_t reload;
81 0f3a4a01 Fabien Chouteau
    uint32_t config;
82 0f3a4a01 Fabien Chouteau
};
83 0f3a4a01 Fabien Chouteau
84 0f3a4a01 Fabien Chouteau
static void grlib_gptimer_enable(GPTimer *timer)
85 0f3a4a01 Fabien Chouteau
{
86 0f3a4a01 Fabien Chouteau
    assert(timer != NULL);
87 0f3a4a01 Fabien Chouteau
88 0f3a4a01 Fabien Chouteau
89 0f3a4a01 Fabien Chouteau
    ptimer_stop(timer->ptimer);
90 0f3a4a01 Fabien Chouteau
91 0f3a4a01 Fabien Chouteau
    if (!(timer->config & GPTIMER_ENABLE)) {
92 0f3a4a01 Fabien Chouteau
        /* Timer disabled */
93 0f3a4a01 Fabien Chouteau
        trace_grlib_gptimer_disabled(timer->id, timer->config);
94 0f3a4a01 Fabien Chouteau
        return;
95 0f3a4a01 Fabien Chouteau
    }
96 0f3a4a01 Fabien Chouteau
97 0f3a4a01 Fabien Chouteau
    /* ptimer is triggered when the counter reach 0 but GPTimer is triggered at
98 0f3a4a01 Fabien Chouteau
       underflow. Set count + 1 to simulate the GPTimer behavior. */
99 0f3a4a01 Fabien Chouteau
100 0f3a4a01 Fabien Chouteau
    trace_grlib_gptimer_enable(timer->id, timer->counter + 1);
101 0f3a4a01 Fabien Chouteau
102 0f3a4a01 Fabien Chouteau
    ptimer_set_count(timer->ptimer, timer->counter + 1);
103 0f3a4a01 Fabien Chouteau
    ptimer_run(timer->ptimer, 1);
104 0f3a4a01 Fabien Chouteau
}
105 0f3a4a01 Fabien Chouteau
106 0f3a4a01 Fabien Chouteau
static void grlib_gptimer_restart(GPTimer *timer)
107 0f3a4a01 Fabien Chouteau
{
108 0f3a4a01 Fabien Chouteau
    assert(timer != NULL);
109 0f3a4a01 Fabien Chouteau
110 0f3a4a01 Fabien Chouteau
    trace_grlib_gptimer_restart(timer->id, timer->reload);
111 0f3a4a01 Fabien Chouteau
112 0f3a4a01 Fabien Chouteau
    timer->counter = timer->reload;
113 0f3a4a01 Fabien Chouteau
    grlib_gptimer_enable(timer);
114 0f3a4a01 Fabien Chouteau
}
115 0f3a4a01 Fabien Chouteau
116 0f3a4a01 Fabien Chouteau
static void grlib_gptimer_set_scaler(GPTimerUnit *unit, uint32_t scaler)
117 0f3a4a01 Fabien Chouteau
{
118 0f3a4a01 Fabien Chouteau
    int i = 0;
119 0f3a4a01 Fabien Chouteau
    uint32_t value = 0;
120 0f3a4a01 Fabien Chouteau
121 0f3a4a01 Fabien Chouteau
    assert(unit != NULL);
122 0f3a4a01 Fabien Chouteau
123 0f3a4a01 Fabien Chouteau
    if (scaler > 0) {
124 0f3a4a01 Fabien Chouteau
        value = unit->freq_hz / (scaler + 1);
125 0f3a4a01 Fabien Chouteau
    } else {
126 0f3a4a01 Fabien Chouteau
        value = unit->freq_hz;
127 0f3a4a01 Fabien Chouteau
    }
128 0f3a4a01 Fabien Chouteau
129 0f3a4a01 Fabien Chouteau
    trace_grlib_gptimer_set_scaler(scaler, value);
130 0f3a4a01 Fabien Chouteau
131 0f3a4a01 Fabien Chouteau
    for (i = 0; i < unit->nr_timers; i++) {
132 0f3a4a01 Fabien Chouteau
        ptimer_set_freq(unit->timers[i].ptimer, value);
133 0f3a4a01 Fabien Chouteau
    }
134 0f3a4a01 Fabien Chouteau
}
135 0f3a4a01 Fabien Chouteau
136 0f3a4a01 Fabien Chouteau
static void grlib_gptimer_hit(void *opaque)
137 0f3a4a01 Fabien Chouteau
{
138 0f3a4a01 Fabien Chouteau
    GPTimer *timer = opaque;
139 0f3a4a01 Fabien Chouteau
    assert(timer != NULL);
140 0f3a4a01 Fabien Chouteau
141 0f3a4a01 Fabien Chouteau
    trace_grlib_gptimer_hit(timer->id);
142 0f3a4a01 Fabien Chouteau
143 0f3a4a01 Fabien Chouteau
    /* Timer expired */
144 0f3a4a01 Fabien Chouteau
145 0f3a4a01 Fabien Chouteau
    if (timer->config & GPTIMER_INT_ENABLE) {
146 0f3a4a01 Fabien Chouteau
        /* Set the pending bit (only unset by write in the config register) */
147 0f3a4a01 Fabien Chouteau
        timer->config |= GPTIMER_INT_PENDING;
148 0f3a4a01 Fabien Chouteau
        qemu_irq_pulse(timer->irq);
149 0f3a4a01 Fabien Chouteau
    }
150 0f3a4a01 Fabien Chouteau
151 0f3a4a01 Fabien Chouteau
    if (timer->config & GPTIMER_RESTART) {
152 0f3a4a01 Fabien Chouteau
        grlib_gptimer_restart(timer);
153 0f3a4a01 Fabien Chouteau
    }
154 0f3a4a01 Fabien Chouteau
}
155 0f3a4a01 Fabien Chouteau
156 0f3a4a01 Fabien Chouteau
static uint32_t grlib_gptimer_readl(void *opaque, target_phys_addr_t addr)
157 0f3a4a01 Fabien Chouteau
{
158 0f3a4a01 Fabien Chouteau
    GPTimerUnit        *unit  = opaque;
159 0f3a4a01 Fabien Chouteau
    target_phys_addr_t  timer_addr;
160 0f3a4a01 Fabien Chouteau
    int                 id;
161 0f3a4a01 Fabien Chouteau
    uint32_t            value = 0;
162 0f3a4a01 Fabien Chouteau
163 0f3a4a01 Fabien Chouteau
    addr &= 0xff;
164 0f3a4a01 Fabien Chouteau
165 0f3a4a01 Fabien Chouteau
    /* Unit registers */
166 0f3a4a01 Fabien Chouteau
    switch (addr) {
167 0f3a4a01 Fabien Chouteau
    case SCALER_OFFSET:
168 b4548fcc Stefan Hajnoczi
        trace_grlib_gptimer_readl(-1, addr, unit->scaler);
169 0f3a4a01 Fabien Chouteau
        return unit->scaler;
170 0f3a4a01 Fabien Chouteau
171 0f3a4a01 Fabien Chouteau
    case SCALER_RELOAD_OFFSET:
172 b4548fcc Stefan Hajnoczi
        trace_grlib_gptimer_readl(-1, addr, unit->reload);
173 0f3a4a01 Fabien Chouteau
        return unit->reload;
174 0f3a4a01 Fabien Chouteau
175 0f3a4a01 Fabien Chouteau
    case CONFIG_OFFSET:
176 b4548fcc Stefan Hajnoczi
        trace_grlib_gptimer_readl(-1, addr, unit->config);
177 0f3a4a01 Fabien Chouteau
        return unit->config;
178 0f3a4a01 Fabien Chouteau
179 0f3a4a01 Fabien Chouteau
    default:
180 0f3a4a01 Fabien Chouteau
        break;
181 0f3a4a01 Fabien Chouteau
    }
182 0f3a4a01 Fabien Chouteau
183 0f3a4a01 Fabien Chouteau
    timer_addr = (addr % TIMER_BASE);
184 0f3a4a01 Fabien Chouteau
    id         = (addr - TIMER_BASE) / TIMER_BASE;
185 0f3a4a01 Fabien Chouteau
186 0f3a4a01 Fabien Chouteau
    if (id >= 0 && id < unit->nr_timers) {
187 0f3a4a01 Fabien Chouteau
188 0f3a4a01 Fabien Chouteau
        /* GPTimer registers */
189 0f3a4a01 Fabien Chouteau
        switch (timer_addr) {
190 0f3a4a01 Fabien Chouteau
        case COUNTER_OFFSET:
191 0f3a4a01 Fabien Chouteau
            value = ptimer_get_count(unit->timers[id].ptimer);
192 b4548fcc Stefan Hajnoczi
            trace_grlib_gptimer_readl(id, addr, value);
193 0f3a4a01 Fabien Chouteau
            return value;
194 0f3a4a01 Fabien Chouteau
195 0f3a4a01 Fabien Chouteau
        case COUNTER_RELOAD_OFFSET:
196 0f3a4a01 Fabien Chouteau
            value = unit->timers[id].reload;
197 b4548fcc Stefan Hajnoczi
            trace_grlib_gptimer_readl(id, addr, value);
198 0f3a4a01 Fabien Chouteau
            return value;
199 0f3a4a01 Fabien Chouteau
200 0f3a4a01 Fabien Chouteau
        case CONFIG_OFFSET:
201 b4548fcc Stefan Hajnoczi
            trace_grlib_gptimer_readl(id, addr, unit->timers[id].config);
202 0f3a4a01 Fabien Chouteau
            return unit->timers[id].config;
203 0f3a4a01 Fabien Chouteau
204 0f3a4a01 Fabien Chouteau
        default:
205 0f3a4a01 Fabien Chouteau
            break;
206 0f3a4a01 Fabien Chouteau
        }
207 0f3a4a01 Fabien Chouteau
208 0f3a4a01 Fabien Chouteau
    }
209 0f3a4a01 Fabien Chouteau
210 b4548fcc Stefan Hajnoczi
    trace_grlib_gptimer_readl(-1, addr, 0);
211 0f3a4a01 Fabien Chouteau
    return 0;
212 0f3a4a01 Fabien Chouteau
}
213 0f3a4a01 Fabien Chouteau
214 0f3a4a01 Fabien Chouteau
static void
215 0f3a4a01 Fabien Chouteau
grlib_gptimer_writel(void *opaque, target_phys_addr_t addr, uint32_t value)
216 0f3a4a01 Fabien Chouteau
{
217 0f3a4a01 Fabien Chouteau
    GPTimerUnit        *unit = opaque;
218 0f3a4a01 Fabien Chouteau
    target_phys_addr_t  timer_addr;
219 0f3a4a01 Fabien Chouteau
    int                 id;
220 0f3a4a01 Fabien Chouteau
221 0f3a4a01 Fabien Chouteau
    addr &= 0xff;
222 0f3a4a01 Fabien Chouteau
223 0f3a4a01 Fabien Chouteau
    /* Unit registers */
224 0f3a4a01 Fabien Chouteau
    switch (addr) {
225 0f3a4a01 Fabien Chouteau
    case SCALER_OFFSET:
226 0f3a4a01 Fabien Chouteau
        value &= 0xFFFF; /* clean up the value */
227 0f3a4a01 Fabien Chouteau
        unit->scaler = value;
228 b4548fcc Stefan Hajnoczi
        trace_grlib_gptimer_writel(-1, addr, unit->scaler);
229 0f3a4a01 Fabien Chouteau
        return;
230 0f3a4a01 Fabien Chouteau
231 0f3a4a01 Fabien Chouteau
    case SCALER_RELOAD_OFFSET:
232 0f3a4a01 Fabien Chouteau
        value &= 0xFFFF; /* clean up the value */
233 0f3a4a01 Fabien Chouteau
        unit->reload = value;
234 b4548fcc Stefan Hajnoczi
        trace_grlib_gptimer_writel(-1, addr, unit->reload);
235 0f3a4a01 Fabien Chouteau
        grlib_gptimer_set_scaler(unit, value);
236 0f3a4a01 Fabien Chouteau
        return;
237 0f3a4a01 Fabien Chouteau
238 0f3a4a01 Fabien Chouteau
    case CONFIG_OFFSET:
239 0f3a4a01 Fabien Chouteau
        /* Read Only (disable timer freeze not supported) */
240 b4548fcc Stefan Hajnoczi
        trace_grlib_gptimer_writel(-1, addr, 0);
241 0f3a4a01 Fabien Chouteau
        return;
242 0f3a4a01 Fabien Chouteau
243 0f3a4a01 Fabien Chouteau
    default:
244 0f3a4a01 Fabien Chouteau
        break;
245 0f3a4a01 Fabien Chouteau
    }
246 0f3a4a01 Fabien Chouteau
247 0f3a4a01 Fabien Chouteau
    timer_addr = (addr % TIMER_BASE);
248 0f3a4a01 Fabien Chouteau
    id         = (addr - TIMER_BASE) / TIMER_BASE;
249 0f3a4a01 Fabien Chouteau
250 0f3a4a01 Fabien Chouteau
    if (id >= 0 && id < unit->nr_timers) {
251 0f3a4a01 Fabien Chouteau
252 0f3a4a01 Fabien Chouteau
        /* GPTimer registers */
253 0f3a4a01 Fabien Chouteau
        switch (timer_addr) {
254 0f3a4a01 Fabien Chouteau
        case COUNTER_OFFSET:
255 b4548fcc Stefan Hajnoczi
            trace_grlib_gptimer_writel(id, addr, value);
256 0f3a4a01 Fabien Chouteau
            unit->timers[id].counter = value;
257 0f3a4a01 Fabien Chouteau
            grlib_gptimer_enable(&unit->timers[id]);
258 0f3a4a01 Fabien Chouteau
            return;
259 0f3a4a01 Fabien Chouteau
260 0f3a4a01 Fabien Chouteau
        case COUNTER_RELOAD_OFFSET:
261 b4548fcc Stefan Hajnoczi
            trace_grlib_gptimer_writel(id, addr, value);
262 0f3a4a01 Fabien Chouteau
            unit->timers[id].reload = value;
263 0f3a4a01 Fabien Chouteau
            return;
264 0f3a4a01 Fabien Chouteau
265 0f3a4a01 Fabien Chouteau
        case CONFIG_OFFSET:
266 b4548fcc Stefan Hajnoczi
            trace_grlib_gptimer_writel(id, addr, value);
267 0f3a4a01 Fabien Chouteau
268 0f3a4a01 Fabien Chouteau
            if (value & GPTIMER_INT_PENDING) {
269 0f3a4a01 Fabien Chouteau
                /* clear pending bit */
270 0f3a4a01 Fabien Chouteau
                value &= ~GPTIMER_INT_PENDING;
271 0f3a4a01 Fabien Chouteau
            } else {
272 0f3a4a01 Fabien Chouteau
                /* keep pending bit */
273 0f3a4a01 Fabien Chouteau
                value |= unit->timers[id].config & GPTIMER_INT_PENDING;
274 0f3a4a01 Fabien Chouteau
            }
275 0f3a4a01 Fabien Chouteau
276 0f3a4a01 Fabien Chouteau
            unit->timers[id].config = value;
277 0f3a4a01 Fabien Chouteau
278 0f3a4a01 Fabien Chouteau
            /* gptimer_restart calls gptimer_enable, so if "enable" and "load"
279 0f3a4a01 Fabien Chouteau
               bits are present, we just have to call restart. */
280 0f3a4a01 Fabien Chouteau
281 0f3a4a01 Fabien Chouteau
            if (value & GPTIMER_LOAD) {
282 0f3a4a01 Fabien Chouteau
                grlib_gptimer_restart(&unit->timers[id]);
283 0f3a4a01 Fabien Chouteau
            } else if (value & GPTIMER_ENABLE) {
284 0f3a4a01 Fabien Chouteau
                grlib_gptimer_enable(&unit->timers[id]);
285 0f3a4a01 Fabien Chouteau
            }
286 0f3a4a01 Fabien Chouteau
287 0f3a4a01 Fabien Chouteau
            /* These fields must always be read as 0 */
288 0f3a4a01 Fabien Chouteau
            value &= ~(GPTIMER_LOAD & GPTIMER_DEBUG_HALT);
289 0f3a4a01 Fabien Chouteau
290 0f3a4a01 Fabien Chouteau
            unit->timers[id].config = value;
291 0f3a4a01 Fabien Chouteau
            return;
292 0f3a4a01 Fabien Chouteau
293 0f3a4a01 Fabien Chouteau
        default:
294 0f3a4a01 Fabien Chouteau
            break;
295 0f3a4a01 Fabien Chouteau
        }
296 0f3a4a01 Fabien Chouteau
297 0f3a4a01 Fabien Chouteau
    }
298 0f3a4a01 Fabien Chouteau
299 b4548fcc Stefan Hajnoczi
    trace_grlib_gptimer_writel(-1, addr, value);
300 0f3a4a01 Fabien Chouteau
}
301 0f3a4a01 Fabien Chouteau
302 0f3a4a01 Fabien Chouteau
static CPUReadMemoryFunc * const grlib_gptimer_read[] = {
303 0f3a4a01 Fabien Chouteau
    NULL, NULL, grlib_gptimer_readl,
304 0f3a4a01 Fabien Chouteau
};
305 0f3a4a01 Fabien Chouteau
306 0f3a4a01 Fabien Chouteau
static CPUWriteMemoryFunc * const grlib_gptimer_write[] = {
307 0f3a4a01 Fabien Chouteau
    NULL, NULL, grlib_gptimer_writel,
308 0f3a4a01 Fabien Chouteau
};
309 0f3a4a01 Fabien Chouteau
310 0f3a4a01 Fabien Chouteau
static void grlib_gptimer_reset(DeviceState *d)
311 0f3a4a01 Fabien Chouteau
{
312 0f3a4a01 Fabien Chouteau
    GPTimerUnit *unit = container_of(d, GPTimerUnit, busdev.qdev);
313 0f3a4a01 Fabien Chouteau
    int          i    = 0;
314 0f3a4a01 Fabien Chouteau
315 0f3a4a01 Fabien Chouteau
    assert(unit != NULL);
316 0f3a4a01 Fabien Chouteau
317 0f3a4a01 Fabien Chouteau
    unit->scaler = 0;
318 0f3a4a01 Fabien Chouteau
    unit->reload = 0;
319 0f3a4a01 Fabien Chouteau
    unit->config = 0;
320 0f3a4a01 Fabien Chouteau
321 0f3a4a01 Fabien Chouteau
    unit->config  = unit->nr_timers;
322 0f3a4a01 Fabien Chouteau
    unit->config |= unit->irq_line << 3;
323 0f3a4a01 Fabien Chouteau
    unit->config |= 1 << 8;     /* separate interrupt */
324 0f3a4a01 Fabien Chouteau
    unit->config |= 1 << 9;     /* Disable timer freeze */
325 0f3a4a01 Fabien Chouteau
326 0f3a4a01 Fabien Chouteau
327 0f3a4a01 Fabien Chouteau
    for (i = 0; i < unit->nr_timers; i++) {
328 0f3a4a01 Fabien Chouteau
        GPTimer *timer = &unit->timers[i];
329 0f3a4a01 Fabien Chouteau
330 0f3a4a01 Fabien Chouteau
        timer->counter = 0;
331 0f3a4a01 Fabien Chouteau
        timer->reload = 0;
332 0f3a4a01 Fabien Chouteau
        timer->config = 0;
333 0f3a4a01 Fabien Chouteau
        ptimer_stop(timer->ptimer);
334 0f3a4a01 Fabien Chouteau
        ptimer_set_count(timer->ptimer, 0);
335 0f3a4a01 Fabien Chouteau
        ptimer_set_freq(timer->ptimer, unit->freq_hz);
336 0f3a4a01 Fabien Chouteau
    }
337 0f3a4a01 Fabien Chouteau
}
338 0f3a4a01 Fabien Chouteau
339 0f3a4a01 Fabien Chouteau
static int grlib_gptimer_init(SysBusDevice *dev)
340 0f3a4a01 Fabien Chouteau
{
341 0f3a4a01 Fabien Chouteau
    GPTimerUnit  *unit = FROM_SYSBUS(typeof(*unit), dev);
342 0f3a4a01 Fabien Chouteau
    unsigned int  i;
343 0f3a4a01 Fabien Chouteau
    int           timer_regs;
344 0f3a4a01 Fabien Chouteau
345 0f3a4a01 Fabien Chouteau
    assert(unit->nr_timers > 0);
346 0f3a4a01 Fabien Chouteau
    assert(unit->nr_timers <= GPTIMER_MAX_TIMERS);
347 0f3a4a01 Fabien Chouteau
348 0f3a4a01 Fabien Chouteau
    unit->timers = qemu_mallocz(sizeof unit->timers[0] * unit->nr_timers);
349 0f3a4a01 Fabien Chouteau
350 0f3a4a01 Fabien Chouteau
    for (i = 0; i < unit->nr_timers; i++) {
351 0f3a4a01 Fabien Chouteau
        GPTimer *timer = &unit->timers[i];
352 0f3a4a01 Fabien Chouteau
353 0f3a4a01 Fabien Chouteau
        timer->unit   = unit;
354 0f3a4a01 Fabien Chouteau
        timer->bh     = qemu_bh_new(grlib_gptimer_hit, timer);
355 0f3a4a01 Fabien Chouteau
        timer->ptimer = ptimer_init(timer->bh);
356 0f3a4a01 Fabien Chouteau
        timer->id     = i;
357 0f3a4a01 Fabien Chouteau
358 0f3a4a01 Fabien Chouteau
        /* One IRQ line for each timer */
359 0f3a4a01 Fabien Chouteau
        sysbus_init_irq(dev, &timer->irq);
360 0f3a4a01 Fabien Chouteau
361 0f3a4a01 Fabien Chouteau
        ptimer_set_freq(timer->ptimer, unit->freq_hz);
362 0f3a4a01 Fabien Chouteau
    }
363 0f3a4a01 Fabien Chouteau
364 0f3a4a01 Fabien Chouteau
    timer_regs = cpu_register_io_memory(grlib_gptimer_read,
365 0f3a4a01 Fabien Chouteau
                                        grlib_gptimer_write,
366 0f3a4a01 Fabien Chouteau
                                        unit, DEVICE_NATIVE_ENDIAN);
367 0f3a4a01 Fabien Chouteau
    if (timer_regs < 0) {
368 0f3a4a01 Fabien Chouteau
        return -1;
369 0f3a4a01 Fabien Chouteau
    }
370 0f3a4a01 Fabien Chouteau
371 0f3a4a01 Fabien Chouteau
    sysbus_init_mmio(dev, UNIT_REG_SIZE + GPTIMER_REG_SIZE * unit->nr_timers,
372 0f3a4a01 Fabien Chouteau
                     timer_regs);
373 0f3a4a01 Fabien Chouteau
    return 0;
374 0f3a4a01 Fabien Chouteau
}
375 0f3a4a01 Fabien Chouteau
376 0f3a4a01 Fabien Chouteau
static SysBusDeviceInfo grlib_gptimer_info = {
377 0f3a4a01 Fabien Chouteau
    .init       = grlib_gptimer_init,
378 0f3a4a01 Fabien Chouteau
    .qdev.name  = "grlib,gptimer",
379 0f3a4a01 Fabien Chouteau
    .qdev.reset = grlib_gptimer_reset,
380 0f3a4a01 Fabien Chouteau
    .qdev.size  = sizeof(GPTimerUnit),
381 0f3a4a01 Fabien Chouteau
    .qdev.props = (Property[]) {
382 0f3a4a01 Fabien Chouteau
        DEFINE_PROP_UINT32("frequency", GPTimerUnit, freq_hz,   40000000),
383 0f3a4a01 Fabien Chouteau
        DEFINE_PROP_UINT32("irq-line",  GPTimerUnit, irq_line,  8),
384 0f3a4a01 Fabien Chouteau
        DEFINE_PROP_UINT32("nr-timers", GPTimerUnit, nr_timers, 2),
385 0f3a4a01 Fabien Chouteau
        DEFINE_PROP_END_OF_LIST()
386 0f3a4a01 Fabien Chouteau
    }
387 0f3a4a01 Fabien Chouteau
};
388 0f3a4a01 Fabien Chouteau
389 0f3a4a01 Fabien Chouteau
static void grlib_gptimer_register(void)
390 0f3a4a01 Fabien Chouteau
{
391 0f3a4a01 Fabien Chouteau
    sysbus_register_withprop(&grlib_gptimer_info);
392 0f3a4a01 Fabien Chouteau
}
393 0f3a4a01 Fabien Chouteau
394 0f3a4a01 Fabien Chouteau
device_init(grlib_gptimer_register)