Statistics
| Branch: | Revision:

root / hw / etraxfs_timer.c @ 9a393c6c

History | View | Annotate | Download (6.1 kB)

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