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