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