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