Statistics
| Branch: | Revision:

root / hw / omap_gptimer.c @ ff90d503

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