Statistics
| Branch: | Revision:

root / hw / omap_gptimer.c @ a8170e5e

History | View | Annotate | Download (12.8 kB)

1 c58d37cf cmchao
/*
2 c58d37cf cmchao
 * TI OMAP2 general purpose timers emulation.
3 c58d37cf cmchao
 *
4 c58d37cf cmchao
 * Copyright (C) 2007-2008 Nokia Corporation
5 c58d37cf cmchao
 * Written by Andrzej Zaborowski <andrew@openedhand.com>
6 c58d37cf cmchao
 *
7 c58d37cf cmchao
 * This program is free software; you can redistribute it and/or
8 c58d37cf cmchao
 * modify it under the terms of the GNU General Public License as
9 c58d37cf cmchao
 * published by the Free Software Foundation; either version 2 or
10 c58d37cf cmchao
 * (at your option) any later version of the License.
11 c58d37cf cmchao
 *
12 c58d37cf cmchao
 * This program is distributed in the hope that it will be useful,
13 c58d37cf cmchao
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 c58d37cf cmchao
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 c58d37cf cmchao
 * GNU General Public License for more details.
16 c58d37cf cmchao
 *
17 c58d37cf cmchao
 * You should have received a copy of the GNU General Public License along
18 c58d37cf cmchao
 * with this program; if not, see <http://www.gnu.org/licenses/>.
19 c58d37cf cmchao
 */
20 c58d37cf cmchao
#include "hw.h"
21 c58d37cf cmchao
#include "qemu-timer.h"
22 c58d37cf cmchao
#include "omap.h"
23 c58d37cf cmchao
24 c58d37cf cmchao
/* GP timers */
25 c58d37cf cmchao
struct omap_gp_timer_s {
26 9832b74c Avi Kivity
    MemoryRegion iomem;
27 c58d37cf cmchao
    qemu_irq irq;
28 c58d37cf cmchao
    qemu_irq wkup;
29 c58d37cf cmchao
    qemu_irq in;
30 c58d37cf cmchao
    qemu_irq out;
31 c58d37cf cmchao
    omap_clk clk;
32 c58d37cf cmchao
    QEMUTimer *timer;
33 c58d37cf cmchao
    QEMUTimer *match;
34 c58d37cf cmchao
    struct omap_target_agent_s *ta;
35 c58d37cf cmchao
36 c58d37cf cmchao
    int in_val;
37 c58d37cf cmchao
    int out_val;
38 c58d37cf cmchao
    int64_t time;
39 c58d37cf cmchao
    int64_t rate;
40 c58d37cf cmchao
    int64_t ticks_per_sec;
41 c58d37cf cmchao
42 c58d37cf cmchao
    int16_t config;
43 c58d37cf cmchao
    int status;
44 c58d37cf cmchao
    int it_ena;
45 c58d37cf cmchao
    int wu_ena;
46 c58d37cf cmchao
    int enable;
47 c58d37cf cmchao
    int inout;
48 c58d37cf cmchao
    int capt2;
49 c58d37cf cmchao
    int pt;
50 c58d37cf cmchao
    enum {
51 c58d37cf cmchao
        gpt_trigger_none, gpt_trigger_overflow, gpt_trigger_both
52 c58d37cf cmchao
    } trigger;
53 c58d37cf cmchao
    enum {
54 c58d37cf cmchao
        gpt_capture_none, gpt_capture_rising,
55 c58d37cf cmchao
        gpt_capture_falling, gpt_capture_both
56 c58d37cf cmchao
    } capture;
57 c58d37cf cmchao
    int scpwm;
58 c58d37cf cmchao
    int ce;
59 c58d37cf cmchao
    int pre;
60 c58d37cf cmchao
    int ptv;
61 c58d37cf cmchao
    int ar;
62 c58d37cf cmchao
    int st;
63 c58d37cf cmchao
    int posted;
64 c58d37cf cmchao
    uint32_t val;
65 c58d37cf cmchao
    uint32_t load_val;
66 c58d37cf cmchao
    uint32_t capture_val[2];
67 c58d37cf cmchao
    uint32_t match_val;
68 c58d37cf cmchao
    int capt_num;
69 c58d37cf cmchao
70 c58d37cf cmchao
    uint16_t writeh;        /* LSB */
71 c58d37cf cmchao
    uint16_t readh;        /* MSB */
72 c58d37cf cmchao
};
73 c58d37cf cmchao
74 c58d37cf cmchao
#define GPT_TCAR_IT        (1 << 2)
75 c58d37cf cmchao
#define GPT_OVF_IT        (1 << 1)
76 c58d37cf cmchao
#define GPT_MAT_IT        (1 << 0)
77 c58d37cf cmchao
78 c58d37cf cmchao
static inline void omap_gp_timer_intr(struct omap_gp_timer_s *timer, int it)
79 c58d37cf cmchao
{
80 c58d37cf cmchao
    if (timer->it_ena & it) {
81 c58d37cf cmchao
        if (!timer->status)
82 c58d37cf cmchao
            qemu_irq_raise(timer->irq);
83 c58d37cf cmchao
84 c58d37cf cmchao
        timer->status |= it;
85 c58d37cf cmchao
        /* Or are the status bits set even when masked?
86 c58d37cf cmchao
         * i.e. is masking applied before or after the status register?  */
87 c58d37cf cmchao
    }
88 c58d37cf cmchao
89 c58d37cf cmchao
    if (timer->wu_ena & it)
90 c58d37cf cmchao
        qemu_irq_pulse(timer->wkup);
91 c58d37cf cmchao
}
92 c58d37cf cmchao
93 c58d37cf cmchao
static inline void omap_gp_timer_out(struct omap_gp_timer_s *timer, int level)
94 c58d37cf cmchao
{
95 c58d37cf cmchao
    if (!timer->inout && timer->out_val != level) {
96 c58d37cf cmchao
        timer->out_val = level;
97 c58d37cf cmchao
        qemu_set_irq(timer->out, level);
98 c58d37cf cmchao
    }
99 c58d37cf cmchao
}
100 c58d37cf cmchao
101 c58d37cf cmchao
static inline uint32_t omap_gp_timer_read(struct omap_gp_timer_s *timer)
102 c58d37cf cmchao
{
103 c58d37cf cmchao
    uint64_t distance;
104 c58d37cf cmchao
105 c58d37cf cmchao
    if (timer->st && timer->rate) {
106 74475455 Paolo Bonzini
        distance = qemu_get_clock_ns(vm_clock) - timer->time;
107 c58d37cf cmchao
        distance = muldiv64(distance, timer->rate, timer->ticks_per_sec);
108 c58d37cf cmchao
109 c58d37cf cmchao
        if (distance >= 0xffffffff - timer->val)
110 c58d37cf cmchao
            return 0xffffffff;
111 c58d37cf cmchao
        else
112 c58d37cf cmchao
            return timer->val + distance;
113 c58d37cf cmchao
    } else
114 c58d37cf cmchao
        return timer->val;
115 c58d37cf cmchao
}
116 c58d37cf cmchao
117 c58d37cf cmchao
static inline void omap_gp_timer_sync(struct omap_gp_timer_s *timer)
118 c58d37cf cmchao
{
119 c58d37cf cmchao
    if (timer->st) {
120 c58d37cf cmchao
        timer->val = omap_gp_timer_read(timer);
121 74475455 Paolo Bonzini
        timer->time = qemu_get_clock_ns(vm_clock);
122 c58d37cf cmchao
    }
123 c58d37cf cmchao
}
124 c58d37cf cmchao
125 c58d37cf cmchao
static inline void omap_gp_timer_update(struct omap_gp_timer_s *timer)
126 c58d37cf cmchao
{
127 c58d37cf cmchao
    int64_t expires, matches;
128 c58d37cf cmchao
129 c58d37cf cmchao
    if (timer->st && timer->rate) {
130 c58d37cf cmchao
        expires = muldiv64(0x100000000ll - timer->val,
131 c58d37cf cmchao
                        timer->ticks_per_sec, timer->rate);
132 c58d37cf cmchao
        qemu_mod_timer(timer->timer, timer->time + expires);
133 c58d37cf cmchao
134 c58d37cf cmchao
        if (timer->ce && timer->match_val >= timer->val) {
135 c58d37cf cmchao
            matches = muldiv64(timer->match_val - timer->val,
136 c58d37cf cmchao
                            timer->ticks_per_sec, timer->rate);
137 c58d37cf cmchao
            qemu_mod_timer(timer->match, timer->time + matches);
138 c58d37cf cmchao
        } else
139 c58d37cf cmchao
            qemu_del_timer(timer->match);
140 c58d37cf cmchao
    } else {
141 c58d37cf cmchao
        qemu_del_timer(timer->timer);
142 c58d37cf cmchao
        qemu_del_timer(timer->match);
143 c58d37cf cmchao
        omap_gp_timer_out(timer, timer->scpwm);
144 c58d37cf cmchao
    }
145 c58d37cf cmchao
}
146 c58d37cf cmchao
147 c58d37cf cmchao
static inline void omap_gp_timer_trigger(struct omap_gp_timer_s *timer)
148 c58d37cf cmchao
{
149 c58d37cf cmchao
    if (timer->pt)
150 c58d37cf cmchao
        /* TODO in overflow-and-match mode if the first event to
151 c58d37cf cmchao
         * occur is the match, don't toggle.  */
152 c58d37cf cmchao
        omap_gp_timer_out(timer, !timer->out_val);
153 c58d37cf cmchao
    else
154 c58d37cf cmchao
        /* TODO inverted pulse on timer->out_val == 1?  */
155 c58d37cf cmchao
        qemu_irq_pulse(timer->out);
156 c58d37cf cmchao
}
157 c58d37cf cmchao
158 c58d37cf cmchao
static void omap_gp_timer_tick(void *opaque)
159 c58d37cf cmchao
{
160 c58d37cf cmchao
    struct omap_gp_timer_s *timer = (struct omap_gp_timer_s *) opaque;
161 c58d37cf cmchao
162 c58d37cf cmchao
    if (!timer->ar) {
163 c58d37cf cmchao
        timer->st = 0;
164 c58d37cf cmchao
        timer->val = 0;
165 c58d37cf cmchao
    } else {
166 c58d37cf cmchao
        timer->val = timer->load_val;
167 74475455 Paolo Bonzini
        timer->time = qemu_get_clock_ns(vm_clock);
168 c58d37cf cmchao
    }
169 c58d37cf cmchao
170 c58d37cf cmchao
    if (timer->trigger == gpt_trigger_overflow ||
171 c58d37cf cmchao
                    timer->trigger == gpt_trigger_both)
172 c58d37cf cmchao
        omap_gp_timer_trigger(timer);
173 c58d37cf cmchao
174 c58d37cf cmchao
    omap_gp_timer_intr(timer, GPT_OVF_IT);
175 c58d37cf cmchao
    omap_gp_timer_update(timer);
176 c58d37cf cmchao
}
177 c58d37cf cmchao
178 c58d37cf cmchao
static void omap_gp_timer_match(void *opaque)
179 c58d37cf cmchao
{
180 c58d37cf cmchao
    struct omap_gp_timer_s *timer = (struct omap_gp_timer_s *) opaque;
181 c58d37cf cmchao
182 c58d37cf cmchao
    if (timer->trigger == gpt_trigger_both)
183 c58d37cf cmchao
        omap_gp_timer_trigger(timer);
184 c58d37cf cmchao
185 c58d37cf cmchao
    omap_gp_timer_intr(timer, GPT_MAT_IT);
186 c58d37cf cmchao
}
187 c58d37cf cmchao
188 c58d37cf cmchao
static void omap_gp_timer_input(void *opaque, int line, int on)
189 c58d37cf cmchao
{
190 c58d37cf cmchao
    struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
191 c58d37cf cmchao
    int trigger;
192 c58d37cf cmchao
193 c58d37cf cmchao
    switch (s->capture) {
194 c58d37cf cmchao
    default:
195 c58d37cf cmchao
    case gpt_capture_none:
196 c58d37cf cmchao
        trigger = 0;
197 c58d37cf cmchao
        break;
198 c58d37cf cmchao
    case gpt_capture_rising:
199 c58d37cf cmchao
        trigger = !s->in_val && on;
200 c58d37cf cmchao
        break;
201 c58d37cf cmchao
    case gpt_capture_falling:
202 c58d37cf cmchao
        trigger = s->in_val && !on;
203 c58d37cf cmchao
        break;
204 c58d37cf cmchao
    case gpt_capture_both:
205 c58d37cf cmchao
        trigger = (s->in_val == !on);
206 c58d37cf cmchao
        break;
207 c58d37cf cmchao
    }
208 c58d37cf cmchao
    s->in_val = on;
209 c58d37cf cmchao
210 c58d37cf cmchao
    if (s->inout && trigger && s->capt_num < 2) {
211 c58d37cf cmchao
        s->capture_val[s->capt_num] = omap_gp_timer_read(s);
212 c58d37cf cmchao
213 c58d37cf cmchao
        if (s->capt2 == s->capt_num ++)
214 c58d37cf cmchao
            omap_gp_timer_intr(s, GPT_TCAR_IT);
215 c58d37cf cmchao
    }
216 c58d37cf cmchao
}
217 c58d37cf cmchao
218 c58d37cf cmchao
static void omap_gp_timer_clk_update(void *opaque, int line, int on)
219 c58d37cf cmchao
{
220 c58d37cf cmchao
    struct omap_gp_timer_s *timer = (struct omap_gp_timer_s *) opaque;
221 c58d37cf cmchao
222 c58d37cf cmchao
    omap_gp_timer_sync(timer);
223 c58d37cf cmchao
    timer->rate = on ? omap_clk_getrate(timer->clk) : 0;
224 c58d37cf cmchao
    omap_gp_timer_update(timer);
225 c58d37cf cmchao
}
226 c58d37cf cmchao
227 c58d37cf cmchao
static void omap_gp_timer_clk_setup(struct omap_gp_timer_s *timer)
228 c58d37cf cmchao
{
229 c58d37cf cmchao
    omap_clk_adduser(timer->clk,
230 c58d37cf cmchao
                    qemu_allocate_irqs(omap_gp_timer_clk_update, timer, 1)[0]);
231 c58d37cf cmchao
    timer->rate = omap_clk_getrate(timer->clk);
232 c58d37cf cmchao
}
233 c58d37cf cmchao
234 c58d37cf cmchao
void omap_gp_timer_reset(struct omap_gp_timer_s *s)
235 c58d37cf cmchao
{
236 c58d37cf cmchao
    s->config = 0x000;
237 c58d37cf cmchao
    s->status = 0;
238 c58d37cf cmchao
    s->it_ena = 0;
239 c58d37cf cmchao
    s->wu_ena = 0;
240 c58d37cf cmchao
    s->inout = 0;
241 c58d37cf cmchao
    s->capt2 = 0;
242 c58d37cf cmchao
    s->capt_num = 0;
243 c58d37cf cmchao
    s->pt = 0;
244 c58d37cf cmchao
    s->trigger = gpt_trigger_none;
245 c58d37cf cmchao
    s->capture = gpt_capture_none;
246 c58d37cf cmchao
    s->scpwm = 0;
247 c58d37cf cmchao
    s->ce = 0;
248 c58d37cf cmchao
    s->pre = 0;
249 c58d37cf cmchao
    s->ptv = 0;
250 c58d37cf cmchao
    s->ar = 0;
251 c58d37cf cmchao
    s->st = 0;
252 c58d37cf cmchao
    s->posted = 1;
253 c58d37cf cmchao
    s->val = 0x00000000;
254 c58d37cf cmchao
    s->load_val = 0x00000000;
255 c58d37cf cmchao
    s->capture_val[0] = 0x00000000;
256 c58d37cf cmchao
    s->capture_val[1] = 0x00000000;
257 c58d37cf cmchao
    s->match_val = 0x00000000;
258 c58d37cf cmchao
    omap_gp_timer_update(s);
259 c58d37cf cmchao
}
260 c58d37cf cmchao
261 a8170e5e Avi Kivity
static uint32_t omap_gp_timer_readw(void *opaque, hwaddr addr)
262 c58d37cf cmchao
{
263 c58d37cf cmchao
    struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
264 c58d37cf cmchao
265 c58d37cf cmchao
    switch (addr) {
266 c58d37cf cmchao
    case 0x00:        /* TIDR */
267 c58d37cf cmchao
        return 0x21;
268 c58d37cf cmchao
269 c58d37cf cmchao
    case 0x10:        /* TIOCP_CFG */
270 c58d37cf cmchao
        return s->config;
271 c58d37cf cmchao
272 c58d37cf cmchao
    case 0x14:        /* TISTAT */
273 c58d37cf cmchao
        /* ??? When's this bit reset? */
274 c58d37cf cmchao
        return 1;                                                /* RESETDONE */
275 c58d37cf cmchao
276 c58d37cf cmchao
    case 0x18:        /* TISR */
277 c58d37cf cmchao
        return s->status;
278 c58d37cf cmchao
279 c58d37cf cmchao
    case 0x1c:        /* TIER */
280 c58d37cf cmchao
        return s->it_ena;
281 c58d37cf cmchao
282 c58d37cf cmchao
    case 0x20:        /* TWER */
283 c58d37cf cmchao
        return s->wu_ena;
284 c58d37cf cmchao
285 c58d37cf cmchao
    case 0x24:        /* TCLR */
286 c58d37cf cmchao
        return (s->inout << 14) |
287 c58d37cf cmchao
                (s->capt2 << 13) |
288 c58d37cf cmchao
                (s->pt << 12) |
289 c58d37cf cmchao
                (s->trigger << 10) |
290 c58d37cf cmchao
                (s->capture << 8) |
291 c58d37cf cmchao
                (s->scpwm << 7) |
292 c58d37cf cmchao
                (s->ce << 6) |
293 c58d37cf cmchao
                (s->pre << 5) |
294 c58d37cf cmchao
                (s->ptv << 2) |
295 c58d37cf cmchao
                (s->ar << 1) |
296 c58d37cf cmchao
                (s->st << 0);
297 c58d37cf cmchao
298 c58d37cf cmchao
    case 0x28:        /* TCRR */
299 c58d37cf cmchao
        return omap_gp_timer_read(s);
300 c58d37cf cmchao
301 c58d37cf cmchao
    case 0x2c:        /* TLDR */
302 c58d37cf cmchao
        return s->load_val;
303 c58d37cf cmchao
304 c58d37cf cmchao
    case 0x30:        /* TTGR */
305 c58d37cf cmchao
        return 0xffffffff;
306 c58d37cf cmchao
307 c58d37cf cmchao
    case 0x34:        /* TWPS */
308 c58d37cf cmchao
        return 0x00000000;        /* No posted writes pending.  */
309 c58d37cf cmchao
310 c58d37cf cmchao
    case 0x38:        /* TMAR */
311 c58d37cf cmchao
        return s->match_val;
312 c58d37cf cmchao
313 c58d37cf cmchao
    case 0x3c:        /* TCAR1 */
314 c58d37cf cmchao
        return s->capture_val[0];
315 c58d37cf cmchao
316 c58d37cf cmchao
    case 0x40:        /* TSICR */
317 c58d37cf cmchao
        return s->posted << 2;
318 c58d37cf cmchao
319 c58d37cf cmchao
    case 0x44:        /* TCAR2 */
320 c58d37cf cmchao
        return s->capture_val[1];
321 c58d37cf cmchao
    }
322 c58d37cf cmchao
323 c58d37cf cmchao
    OMAP_BAD_REG(addr);
324 c58d37cf cmchao
    return 0;
325 c58d37cf cmchao
}
326 c58d37cf cmchao
327 a8170e5e Avi Kivity
static uint32_t omap_gp_timer_readh(void *opaque, hwaddr addr)
328 c58d37cf cmchao
{
329 c58d37cf cmchao
    struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
330 c58d37cf cmchao
    uint32_t ret;
331 c58d37cf cmchao
332 c58d37cf cmchao
    if (addr & 2)
333 c58d37cf cmchao
        return s->readh;
334 c58d37cf cmchao
    else {
335 c58d37cf cmchao
        ret = omap_gp_timer_readw(opaque, addr);
336 c58d37cf cmchao
        s->readh = ret >> 16;
337 c58d37cf cmchao
        return ret & 0xffff;
338 c58d37cf cmchao
    }
339 c58d37cf cmchao
}
340 c58d37cf cmchao
341 a8170e5e Avi Kivity
static void omap_gp_timer_write(void *opaque, hwaddr addr,
342 c58d37cf cmchao
                uint32_t value)
343 c58d37cf cmchao
{
344 c58d37cf cmchao
    struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
345 c58d37cf cmchao
346 c58d37cf cmchao
    switch (addr) {
347 c58d37cf cmchao
    case 0x00:        /* TIDR */
348 c58d37cf cmchao
    case 0x14:        /* TISTAT */
349 c58d37cf cmchao
    case 0x34:        /* TWPS */
350 c58d37cf cmchao
    case 0x3c:        /* TCAR1 */
351 c58d37cf cmchao
    case 0x44:        /* TCAR2 */
352 c58d37cf cmchao
        OMAP_RO_REG(addr);
353 c58d37cf cmchao
        break;
354 c58d37cf cmchao
355 c58d37cf cmchao
    case 0x10:        /* TIOCP_CFG */
356 c58d37cf cmchao
        s->config = value & 0x33d;
357 c58d37cf cmchao
        if (((value >> 3) & 3) == 3)                                /* IDLEMODE */
358 c58d37cf cmchao
            fprintf(stderr, "%s: illegal IDLEMODE value in TIOCP_CFG\n",
359 c58d37cf cmchao
                            __FUNCTION__);
360 c58d37cf cmchao
        if (value & 2)                                                /* SOFTRESET */
361 c58d37cf cmchao
            omap_gp_timer_reset(s);
362 c58d37cf cmchao
        break;
363 c58d37cf cmchao
364 c58d37cf cmchao
    case 0x18:        /* TISR */
365 c58d37cf cmchao
        if (value & GPT_TCAR_IT)
366 c58d37cf cmchao
            s->capt_num = 0;
367 c58d37cf cmchao
        if (s->status && !(s->status &= ~value))
368 c58d37cf cmchao
            qemu_irq_lower(s->irq);
369 c58d37cf cmchao
        break;
370 c58d37cf cmchao
371 c58d37cf cmchao
    case 0x1c:        /* TIER */
372 c58d37cf cmchao
        s->it_ena = value & 7;
373 c58d37cf cmchao
        break;
374 c58d37cf cmchao
375 c58d37cf cmchao
    case 0x20:        /* TWER */
376 c58d37cf cmchao
        s->wu_ena = value & 7;
377 c58d37cf cmchao
        break;
378 c58d37cf cmchao
379 c58d37cf cmchao
    case 0x24:        /* TCLR */
380 c58d37cf cmchao
        omap_gp_timer_sync(s);
381 c58d37cf cmchao
        s->inout = (value >> 14) & 1;
382 c58d37cf cmchao
        s->capt2 = (value >> 13) & 1;
383 c58d37cf cmchao
        s->pt = (value >> 12) & 1;
384 c58d37cf cmchao
        s->trigger = (value >> 10) & 3;
385 c58d37cf cmchao
        if (s->capture == gpt_capture_none &&
386 c58d37cf cmchao
                        ((value >> 8) & 3) != gpt_capture_none)
387 c58d37cf cmchao
            s->capt_num = 0;
388 c58d37cf cmchao
        s->capture = (value >> 8) & 3;
389 c58d37cf cmchao
        s->scpwm = (value >> 7) & 1;
390 c58d37cf cmchao
        s->ce = (value >> 6) & 1;
391 c58d37cf cmchao
        s->pre = (value >> 5) & 1;
392 c58d37cf cmchao
        s->ptv = (value >> 2) & 7;
393 c58d37cf cmchao
        s->ar = (value >> 1) & 1;
394 c58d37cf cmchao
        s->st = (value >> 0) & 1;
395 c58d37cf cmchao
        if (s->inout && s->trigger != gpt_trigger_none)
396 c58d37cf cmchao
            fprintf(stderr, "%s: GP timer pin must be an output "
397 c58d37cf cmchao
                            "for this trigger mode\n", __FUNCTION__);
398 c58d37cf cmchao
        if (!s->inout && s->capture != gpt_capture_none)
399 c58d37cf cmchao
            fprintf(stderr, "%s: GP timer pin must be an input "
400 c58d37cf cmchao
                            "for this capture mode\n", __FUNCTION__);
401 c58d37cf cmchao
        if (s->trigger == gpt_trigger_none)
402 c58d37cf cmchao
            omap_gp_timer_out(s, s->scpwm);
403 c58d37cf cmchao
        /* TODO: make sure this doesn't overflow 32-bits */
404 c58d37cf cmchao
        s->ticks_per_sec = get_ticks_per_sec() << (s->pre ? s->ptv + 1 : 0);
405 c58d37cf cmchao
        omap_gp_timer_update(s);
406 c58d37cf cmchao
        break;
407 c58d37cf cmchao
408 c58d37cf cmchao
    case 0x28:        /* TCRR */
409 74475455 Paolo Bonzini
        s->time = qemu_get_clock_ns(vm_clock);
410 c58d37cf cmchao
        s->val = value;
411 c58d37cf cmchao
        omap_gp_timer_update(s);
412 c58d37cf cmchao
        break;
413 c58d37cf cmchao
414 c58d37cf cmchao
    case 0x2c:        /* TLDR */
415 c58d37cf cmchao
        s->load_val = value;
416 c58d37cf cmchao
        break;
417 c58d37cf cmchao
418 c58d37cf cmchao
    case 0x30:        /* TTGR */
419 74475455 Paolo Bonzini
        s->time = qemu_get_clock_ns(vm_clock);
420 c58d37cf cmchao
        s->val = s->load_val;
421 c58d37cf cmchao
        omap_gp_timer_update(s);
422 c58d37cf cmchao
        break;
423 c58d37cf cmchao
424 c58d37cf cmchao
    case 0x38:        /* TMAR */
425 c58d37cf cmchao
        omap_gp_timer_sync(s);
426 c58d37cf cmchao
        s->match_val = value;
427 c58d37cf cmchao
        omap_gp_timer_update(s);
428 c58d37cf cmchao
        break;
429 c58d37cf cmchao
430 c58d37cf cmchao
    case 0x40:        /* TSICR */
431 c58d37cf cmchao
        s->posted = (value >> 2) & 1;
432 c58d37cf cmchao
        if (value & 2)        /* How much exactly are we supposed to reset? */
433 c58d37cf cmchao
            omap_gp_timer_reset(s);
434 c58d37cf cmchao
        break;
435 c58d37cf cmchao
436 c58d37cf cmchao
    default:
437 c58d37cf cmchao
        OMAP_BAD_REG(addr);
438 c58d37cf cmchao
    }
439 c58d37cf cmchao
}
440 c58d37cf cmchao
441 a8170e5e Avi Kivity
static void omap_gp_timer_writeh(void *opaque, hwaddr addr,
442 c58d37cf cmchao
                uint32_t value)
443 c58d37cf cmchao
{
444 c58d37cf cmchao
    struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
445 c58d37cf cmchao
446 c58d37cf cmchao
    if (addr & 2)
447 c58d37cf cmchao
        return omap_gp_timer_write(opaque, addr, (value << 16) | s->writeh);
448 c58d37cf cmchao
    else
449 c58d37cf cmchao
        s->writeh = (uint16_t) value;
450 c58d37cf cmchao
}
451 c58d37cf cmchao
452 9832b74c Avi Kivity
static const MemoryRegionOps omap_gp_timer_ops = {
453 9832b74c Avi Kivity
    .old_mmio = {
454 9832b74c Avi Kivity
        .read = {
455 9832b74c Avi Kivity
            omap_badwidth_read32,
456 9832b74c Avi Kivity
            omap_gp_timer_readh,
457 9832b74c Avi Kivity
            omap_gp_timer_readw,
458 9832b74c Avi Kivity
        },
459 9832b74c Avi Kivity
        .write = {
460 9832b74c Avi Kivity
            omap_badwidth_write32,
461 9832b74c Avi Kivity
            omap_gp_timer_writeh,
462 9832b74c Avi Kivity
            omap_gp_timer_write,
463 9832b74c Avi Kivity
        },
464 9832b74c Avi Kivity
    },
465 9832b74c Avi Kivity
    .endianness = DEVICE_NATIVE_ENDIAN,
466 c58d37cf cmchao
};
467 c58d37cf cmchao
468 c58d37cf cmchao
struct omap_gp_timer_s *omap_gp_timer_init(struct omap_target_agent_s *ta,
469 c58d37cf cmchao
                qemu_irq irq, omap_clk fclk, omap_clk iclk)
470 c58d37cf cmchao
{
471 c58d37cf cmchao
    struct omap_gp_timer_s *s = (struct omap_gp_timer_s *)
472 7267c094 Anthony Liguori
            g_malloc0(sizeof(struct omap_gp_timer_s));
473 c58d37cf cmchao
474 c58d37cf cmchao
    s->ta = ta;
475 c58d37cf cmchao
    s->irq = irq;
476 c58d37cf cmchao
    s->clk = fclk;
477 74475455 Paolo Bonzini
    s->timer = qemu_new_timer_ns(vm_clock, omap_gp_timer_tick, s);
478 74475455 Paolo Bonzini
    s->match = qemu_new_timer_ns(vm_clock, omap_gp_timer_match, s);
479 c58d37cf cmchao
    s->in = qemu_allocate_irqs(omap_gp_timer_input, s, 1)[0];
480 c58d37cf cmchao
    omap_gp_timer_reset(s);
481 c58d37cf cmchao
    omap_gp_timer_clk_setup(s);
482 c58d37cf cmchao
483 9832b74c Avi Kivity
    memory_region_init_io(&s->iomem, &omap_gp_timer_ops, s, "omap.gptimer",
484 9832b74c Avi Kivity
                          omap_l4_region_size(ta, 0));
485 f44336c5 Avi Kivity
    omap_l4_attach(ta, 0, &s->iomem);
486 c58d37cf cmchao
487 c58d37cf cmchao
    return s;
488 c58d37cf cmchao
}