]> Git Repo - qemu.git/blob - hw/etraxfs_timer.c
MIPS Magnum R4000 machine
[qemu.git] / hw / etraxfs_timer.c
1 /*
2  * QEMU ETRAX Timers
3  *
4  * Copyright (c) 2007 Edgar E. Iglesias, Axis Communications AB.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  */
24 #include <stdio.h>
25 #include <sys/time.h>
26 #include "hw.h"
27 #include "qemu-timer.h"
28
29 #define D(x)
30
31 #define RW_TMR0_DIV   0x00
32 #define R_TMR0_DATA   0x04
33 #define RW_TMR0_CTRL  0x08
34 #define RW_TMR1_DIV   0x10
35 #define R_TMR1_DATA   0x14
36 #define RW_TMR1_CTRL  0x18
37 #define R_TIME        0x38
38 #define RW_WD_CTRL    0x40
39 #define RW_INTR_MASK  0x48
40 #define RW_ACK_INTR   0x4c
41 #define R_INTR        0x50
42 #define R_MASKED_INTR 0x54
43
44 struct fs_timer_t {
45         CPUState *env;
46         qemu_irq *irq;
47         target_phys_addr_t base;
48
49         QEMUBH *bh;
50         ptimer_state *ptimer;
51         unsigned int limit;
52         int scale;
53         uint32_t mask;
54         struct timeval last;
55
56         uint32_t rw_intr_mask;
57         uint32_t rw_ack_intr;
58         uint32_t r_intr;
59 };
60
61 /* diff two timevals.  Return a single int in us. */
62 int diff_timeval_us(struct timeval *a, struct timeval *b)
63 {
64         int diff;
65
66         /* assume these values are signed.  */
67         diff = (a->tv_sec - b->tv_sec) * 1000 * 1000;
68         diff += (a->tv_usec - b->tv_usec);
69         return diff;
70 }
71
72 static uint32_t timer_rinvalid (void *opaque, target_phys_addr_t addr)
73 {
74         struct fs_timer_t *t = opaque;
75         CPUState *env = t->env;
76         cpu_abort(env, "Unsupported short access. reg=%x pc=%x.\n", 
77                   addr, env->pc);
78         return 0;
79 }
80
81 static uint32_t timer_readl (void *opaque, target_phys_addr_t addr)
82 {
83         struct fs_timer_t *t = opaque;
84         D(CPUState *env = t->env);
85         uint32_t r = 0;
86
87         /* Make addr relative to this instances base.  */
88         addr -= t->base;
89         switch (addr) {
90         case R_TMR0_DATA:
91                 break;
92         case R_TMR1_DATA:
93                 D(printf ("R_TMR1_DATA\n"));
94                 break;
95         case R_TIME:
96         {
97                 struct timeval now;
98                 gettimeofday(&now, NULL);
99                 if (!(t->last.tv_sec == 0 
100                       && t->last.tv_usec == 0)) {
101                         r = diff_timeval_us(&now, &t->last);
102                         r *= 1000; /* convert to ns.  */
103                         r++; /* make sure we increase for each call.  */
104                 }
105                 t->last = now;
106                 break;
107         }
108
109         case RW_INTR_MASK:
110                 r = t->rw_intr_mask;
111                 break;
112         case R_MASKED_INTR:
113                 r = t->r_intr & t->rw_intr_mask;
114                 break;
115         default:
116                 D(printf ("%s %x p=%x\n", __func__, addr, env->pc));
117                 break;
118         }
119         return r;
120 }
121
122 static void
123 timer_winvalid (void *opaque, target_phys_addr_t addr, uint32_t value)
124 {
125         struct fs_timer_t *t = opaque;
126         CPUState *env = t->env;
127         cpu_abort(env, "Unsupported short access. reg=%x pc=%x.\n", 
128                   addr, env->pc);
129 }
130
131 static void write_ctrl(struct fs_timer_t *t, uint32_t v)
132 {
133         int op;
134         int freq;
135         int freq_hz;
136
137         op = v & 3;
138         freq = v >> 2;
139         freq_hz = 32000000;
140
141         switch (freq)
142         {
143         case 0:
144         case 1:
145                 D(printf ("extern or disabled timer clock?\n"));
146                 break;
147         case 4: freq_hz =  29493000; break;
148         case 5: freq_hz =  32000000; break;
149         case 6: freq_hz =  32768000; break;
150         case 7: freq_hz = 100000000; break;
151         default:
152                 abort();
153                 break;
154         }
155
156         D(printf ("freq_hz=%d limit=%d\n", freq_hz, t->limit));
157         t->scale = 0;
158         if (t->limit > 2048)
159         {
160                 t->scale = 2048;
161                 ptimer_set_period(t->ptimer, freq_hz / t->scale);
162         }
163
164         switch (op)
165         {
166                 case 0:
167                         D(printf ("limit=%d %d\n", 
168                                   t->limit, t->limit/t->scale));
169                         ptimer_set_limit(t->ptimer, t->limit / t->scale, 1);
170                         break;
171                 case 1:
172                         ptimer_stop(t->ptimer);
173                         break;
174                 case 2:
175                         ptimer_run(t->ptimer, 0);
176                         break;
177                 default:
178                         abort();
179                         break;
180         }
181 }
182
183 static void timer_ack_irq(struct fs_timer_t *t)
184 {
185         if (!(t->r_intr & t->mask & t->rw_intr_mask))
186                 qemu_irq_lower(t->irq[0]);
187 }
188
189 static void
190 timer_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
191 {
192         struct fs_timer_t *t = opaque;
193         CPUState *env = t->env;
194
195         D(printf ("%s %x %x pc=%x\n",
196                 __func__, addr, value, env->pc));
197         /* Make addr relative to this instances base.  */
198         addr -= t->base;
199         switch (addr)
200         {
201                 case RW_TMR0_DIV:
202                         D(printf ("RW_TMR0_DIV=%x\n", value));
203                         t->limit = value;
204                         break;
205                 case RW_TMR0_CTRL:
206                         D(printf ("RW_TMR0_CTRL=%x\n", value));
207                         write_ctrl(t, value);
208                         break;
209                 case RW_TMR1_DIV:
210                         D(printf ("RW_TMR1_DIV=%x\n", value));
211                         break;
212                 case RW_TMR1_CTRL:
213                         D(printf ("RW_TMR1_CTRL=%x\n", value));
214                         break;
215                 case RW_INTR_MASK:
216                         D(printf ("RW_INTR_MASK=%x\n", value));
217                         t->rw_intr_mask = value;
218                         break;
219                 case RW_WD_CTRL:
220                         D(printf ("RW_WD_CTRL=%x\n", value));
221                         break;
222                 case RW_ACK_INTR:
223                         t->r_intr &= ~value;
224                         timer_ack_irq(t);
225                         break;
226                 default:
227                         printf ("%s %x %x pc=%x\n",
228                                 __func__, addr, value, env->pc);
229                         break;
230         }
231 }
232
233 static CPUReadMemoryFunc *timer_read[] = {
234     &timer_rinvalid,
235     &timer_rinvalid,
236     &timer_readl,
237 };
238
239 static CPUWriteMemoryFunc *timer_write[] = {
240     &timer_winvalid,
241     &timer_winvalid,
242     &timer_writel,
243 };
244
245 static void timer_irq(void *opaque)
246 {
247         struct fs_timer_t *t = opaque;
248         t->r_intr |= t->mask;
249         if (t->mask & t->rw_intr_mask) {
250                 D(printf("%s raise\n", __func__));
251                 qemu_irq_raise(t->irq[0]);
252         }
253 }
254
255 void etraxfs_timer_init(CPUState *env, qemu_irq *irqs, 
256                         target_phys_addr_t base)
257 {
258         static struct fs_timer_t *t;
259         int timer_regs;
260
261         t = qemu_mallocz(sizeof *t);
262         if (!t)
263                 return;
264
265         t->bh = qemu_bh_new(timer_irq, t);
266         t->ptimer = ptimer_init(t->bh);
267         t->irq = irqs + 26;
268         t->mask = 1;
269         t->env = env;
270         t->base = base;
271
272         timer_regs = cpu_register_io_memory(0, timer_read, timer_write, t);
273         cpu_register_physical_memory (base, 0x5c, timer_regs);
274 }
This page took 0.04407 seconds and 4 git commands to generate.