]> Git Repo - qemu.git/blob - hw/omap_gptimer.c
block: drive_init(): Improve CHS setting error message
[qemu.git] / hw / omap_gptimer.c
1 /*
2  * TI OMAP2 general purpose timers emulation.
3  *
4  * Copyright (C) 2007-2008 Nokia Corporation
5  * Written by Andrzej Zaborowski <[email protected]>
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.h"
21 #include "qemu-timer.h"
22 #include "omap.h"
23
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;
34
35     int in_val;
36     int out_val;
37     int64_t time;
38     int64_t rate;
39     int64_t ticks_per_sec;
40
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;
68
69     uint16_t writeh;    /* LSB */
70     uint16_t readh;     /* MSB */
71 };
72
73 #define GPT_TCAR_IT     (1 << 2)
74 #define GPT_OVF_IT      (1 << 1)
75 #define GPT_MAT_IT      (1 << 0)
76
77 static inline void omap_gp_timer_intr(struct omap_gp_timer_s *timer, int it)
78 {
79     if (timer->it_ena & it) {
80         if (!timer->status)
81             qemu_irq_raise(timer->irq);
82
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?  */
86     }
87
88     if (timer->wu_ena & it)
89         qemu_irq_pulse(timer->wkup);
90 }
91
92 static inline void omap_gp_timer_out(struct omap_gp_timer_s *timer, int level)
93 {
94     if (!timer->inout && timer->out_val != level) {
95         timer->out_val = level;
96         qemu_set_irq(timer->out, level);
97     }
98 }
99
100 static inline uint32_t omap_gp_timer_read(struct omap_gp_timer_s *timer)
101 {
102     uint64_t distance;
103
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);
107
108         if (distance >= 0xffffffff - timer->val)
109             return 0xffffffff;
110         else
111             return timer->val + distance;
112     } else
113         return timer->val;
114 }
115
116 static inline void omap_gp_timer_sync(struct omap_gp_timer_s *timer)
117 {
118     if (timer->st) {
119         timer->val = omap_gp_timer_read(timer);
120         timer->time = qemu_get_clock_ns(vm_clock);
121     }
122 }
123
124 static inline void omap_gp_timer_update(struct omap_gp_timer_s *timer)
125 {
126     int64_t expires, matches;
127
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);
132
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);
143     }
144 }
145
146 static inline void omap_gp_timer_trigger(struct omap_gp_timer_s *timer)
147 {
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);
155 }
156
157 static void omap_gp_timer_tick(void *opaque)
158 {
159     struct omap_gp_timer_s *timer = (struct omap_gp_timer_s *) opaque;
160
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);
167     }
168
169     if (timer->trigger == gpt_trigger_overflow ||
170                     timer->trigger == gpt_trigger_both)
171         omap_gp_timer_trigger(timer);
172
173     omap_gp_timer_intr(timer, GPT_OVF_IT);
174     omap_gp_timer_update(timer);
175 }
176
177 static void omap_gp_timer_match(void *opaque)
178 {
179     struct omap_gp_timer_s *timer = (struct omap_gp_timer_s *) opaque;
180
181     if (timer->trigger == gpt_trigger_both)
182         omap_gp_timer_trigger(timer);
183
184     omap_gp_timer_intr(timer, GPT_MAT_IT);
185 }
186
187 static void omap_gp_timer_input(void *opaque, int line, int on)
188 {
189     struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
190     int trigger;
191
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;
206     }
207     s->in_val = on;
208
209     if (s->inout && trigger && s->capt_num < 2) {
210         s->capture_val[s->capt_num] = omap_gp_timer_read(s);
211
212         if (s->capt2 == s->capt_num ++)
213             omap_gp_timer_intr(s, GPT_TCAR_IT);
214     }
215 }
216
217 static void omap_gp_timer_clk_update(void *opaque, int line, int on)
218 {
219     struct omap_gp_timer_s *timer = (struct omap_gp_timer_s *) opaque;
220
221     omap_gp_timer_sync(timer);
222     timer->rate = on ? omap_clk_getrate(timer->clk) : 0;
223     omap_gp_timer_update(timer);
224 }
225
226 static void omap_gp_timer_clk_setup(struct omap_gp_timer_s *timer)
227 {
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);
231 }
232
233 void omap_gp_timer_reset(struct omap_gp_timer_s *s)
234 {
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);
258 }
259
260 static uint32_t omap_gp_timer_readw(void *opaque, target_phys_addr_t addr)
261 {
262     struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
263
264     switch (addr) {
265     case 0x00:  /* TIDR */
266         return 0x21;
267
268     case 0x10:  /* TIOCP_CFG */
269         return s->config;
270
271     case 0x14:  /* TISTAT */
272         /* ??? When's this bit reset? */
273         return 1;                                               /* RESETDONE */
274
275     case 0x18:  /* TISR */
276         return s->status;
277
278     case 0x1c:  /* TIER */
279         return s->it_ena;
280
281     case 0x20:  /* TWER */
282         return s->wu_ena;
283
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);
296
297     case 0x28:  /* TCRR */
298         return omap_gp_timer_read(s);
299
300     case 0x2c:  /* TLDR */
301         return s->load_val;
302
303     case 0x30:  /* TTGR */
304         return 0xffffffff;
305
306     case 0x34:  /* TWPS */
307         return 0x00000000;      /* No posted writes pending.  */
308
309     case 0x38:  /* TMAR */
310         return s->match_val;
311
312     case 0x3c:  /* TCAR1 */
313         return s->capture_val[0];
314
315     case 0x40:  /* TSICR */
316         return s->posted << 2;
317
318     case 0x44:  /* TCAR2 */
319         return s->capture_val[1];
320     }
321
322     OMAP_BAD_REG(addr);
323     return 0;
324 }
325
326 static uint32_t omap_gp_timer_readh(void *opaque, target_phys_addr_t addr)
327 {
328     struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
329     uint32_t ret;
330
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;
337     }
338 }
339
340 static CPUReadMemoryFunc * const omap_gp_timer_readfn[] = {
341     omap_badwidth_read32,
342     omap_gp_timer_readh,
343     omap_gp_timer_readw,
344 };
345
346 static void omap_gp_timer_write(void *opaque, target_phys_addr_t addr,
347                 uint32_t value)
348 {
349     struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
350
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;
359
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;
368
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;
375
376     case 0x1c:  /* TIER */
377         s->it_ena = value & 7;
378         break;
379
380     case 0x20:  /* TWER */
381         s->wu_ena = value & 7;
382         break;
383
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;
412
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;
418
419     case 0x2c:  /* TLDR */
420         s->load_val = value;
421         break;
422
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;
428
429     case 0x38:  /* TMAR */
430         omap_gp_timer_sync(s);
431         s->match_val = value;
432         omap_gp_timer_update(s);
433         break;
434
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;
440
441     default:
442         OMAP_BAD_REG(addr);
443     }
444 }
445
446 static void omap_gp_timer_writeh(void *opaque, target_phys_addr_t addr,
447                 uint32_t value)
448 {
449     struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
450
451     if (addr & 2)
452         return omap_gp_timer_write(opaque, addr, (value << 16) | s->writeh);
453     else
454         s->writeh = (uint16_t) value;
455 }
456
457 static CPUWriteMemoryFunc * const omap_gp_timer_writefn[] = {
458     omap_badwidth_write32,
459     omap_gp_timer_writeh,
460     omap_gp_timer_write,
461 };
462
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)
465 {
466     int iomemtype;
467     struct omap_gp_timer_s *s = (struct omap_gp_timer_s *)
468             qemu_mallocz(sizeof(struct omap_gp_timer_s));
469
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);
478
479     iomemtype = l4_register_io_memory(omap_gp_timer_readfn,
480                     omap_gp_timer_writefn, s);
481     omap_l4_attach(ta, 0, iomemtype);
482
483     return s;
484 }
This page took 0.081518 seconds and 4 git commands to generate.