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