Statistics
| Branch: | Revision:

root / hw / sh_serial.c @ 7aff0f21

History | View | Annotate | Download (9.9 kB)

1 2f062c72 ths
/*
2 2f062c72 ths
 * QEMU SCI/SCIF serial port emulation
3 2f062c72 ths
 *
4 2f062c72 ths
 * Copyright (c) 2007 Magnus Damm
5 2f062c72 ths
 *
6 2f062c72 ths
 * Based on serial.c - QEMU 16450 UART emulation
7 2f062c72 ths
 * Copyright (c) 2003-2004 Fabrice Bellard
8 2f062c72 ths
 *
9 2f062c72 ths
 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 2f062c72 ths
 * of this software and associated documentation files (the "Software"), to deal
11 2f062c72 ths
 * in the Software without restriction, including without limitation the rights
12 2f062c72 ths
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 2f062c72 ths
 * copies of the Software, and to permit persons to whom the Software is
14 2f062c72 ths
 * furnished to do so, subject to the following conditions:
15 2f062c72 ths
 *
16 2f062c72 ths
 * The above copyright notice and this permission notice shall be included in
17 2f062c72 ths
 * all copies or substantial portions of the Software.
18 2f062c72 ths
 *
19 2f062c72 ths
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 2f062c72 ths
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 2f062c72 ths
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 2f062c72 ths
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 2f062c72 ths
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 2f062c72 ths
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 2f062c72 ths
 * THE SOFTWARE.
26 2f062c72 ths
 */
27 87ecb68b pbrook
#include "hw.h"
28 87ecb68b pbrook
#include "sh.h"
29 87ecb68b pbrook
#include "qemu-char.h"
30 2f062c72 ths
31 2f062c72 ths
//#define DEBUG_SERIAL
32 2f062c72 ths
33 2f062c72 ths
#define SH_SERIAL_FLAG_TEND (1 << 0)
34 2f062c72 ths
#define SH_SERIAL_FLAG_TDE  (1 << 1)
35 2f062c72 ths
#define SH_SERIAL_FLAG_RDF  (1 << 2)
36 2f062c72 ths
#define SH_SERIAL_FLAG_BRK  (1 << 3)
37 2f062c72 ths
#define SH_SERIAL_FLAG_DR   (1 << 4)
38 2f062c72 ths
39 63242a00 aurel32
#define SH_RX_FIFO_LENGTH (16)
40 63242a00 aurel32
41 2f062c72 ths
typedef struct {
42 2f062c72 ths
    uint8_t smr;
43 2f062c72 ths
    uint8_t brr;
44 2f062c72 ths
    uint8_t scr;
45 2f062c72 ths
    uint8_t dr; /* ftdr / tdr */
46 2f062c72 ths
    uint8_t sr; /* fsr / ssr */
47 2f062c72 ths
    uint16_t fcr;
48 2f062c72 ths
    uint8_t sptr;
49 2f062c72 ths
50 63242a00 aurel32
    uint8_t rx_fifo[SH_RX_FIFO_LENGTH]; /* frdr / rdr */
51 2f062c72 ths
    uint8_t rx_cnt;
52 63242a00 aurel32
    uint8_t rx_tail;
53 63242a00 aurel32
    uint8_t rx_head;
54 2f062c72 ths
55 2f062c72 ths
    int freq;
56 2f062c72 ths
    int feat;
57 2f062c72 ths
    int flags;
58 63242a00 aurel32
    int rtrg;
59 2f062c72 ths
60 2f062c72 ths
    CharDriverState *chr;
61 bf5b7423 aurel32
62 4e7ed2d1 aurel32
    qemu_irq eri;
63 4e7ed2d1 aurel32
    qemu_irq rxi;
64 4e7ed2d1 aurel32
    qemu_irq txi;
65 4e7ed2d1 aurel32
    qemu_irq tei;
66 4e7ed2d1 aurel32
    qemu_irq bri;
67 2f062c72 ths
} sh_serial_state;
68 2f062c72 ths
69 63242a00 aurel32
static void sh_serial_clear_fifo(sh_serial_state * s)
70 63242a00 aurel32
{
71 63242a00 aurel32
    memset(s->rx_fifo, 0, SH_RX_FIFO_LENGTH);
72 63242a00 aurel32
    s->rx_cnt = 0;
73 63242a00 aurel32
    s->rx_head = 0;
74 63242a00 aurel32
    s->rx_tail = 0;
75 63242a00 aurel32
}
76 63242a00 aurel32
77 b7277ac2 Aurelien Jarno
static void sh_serial_write(void *opaque, uint32_t offs, uint32_t val)
78 2f062c72 ths
{
79 2f062c72 ths
    sh_serial_state *s = opaque;
80 2f062c72 ths
    unsigned char ch;
81 2f062c72 ths
82 2f062c72 ths
#ifdef DEBUG_SERIAL
83 8da3ff18 pbrook
    printf("sh_serial: write offs=0x%02x val=0x%02x\n",
84 8da3ff18 pbrook
           offs, val);
85 2f062c72 ths
#endif
86 2f062c72 ths
    switch(offs) {
87 2f062c72 ths
    case 0x00: /* SMR */
88 2f062c72 ths
        s->smr = val & ((s->feat & SH_SERIAL_FEAT_SCIF) ? 0x7b : 0xff);
89 2f062c72 ths
        return;
90 2f062c72 ths
    case 0x04: /* BRR */
91 2f062c72 ths
        s->brr = val;
92 2f062c72 ths
        return;
93 2f062c72 ths
    case 0x08: /* SCR */
94 63242a00 aurel32
        /* TODO : For SH7751, SCIF mask should be 0xfb. */
95 bf5b7423 aurel32
        s->scr = val & ((s->feat & SH_SERIAL_FEAT_SCIF) ? 0xfa : 0xff);
96 2f062c72 ths
        if (!(val & (1 << 5)))
97 2f062c72 ths
            s->flags |= SH_SERIAL_FLAG_TEND;
98 bf5b7423 aurel32
        if ((s->feat & SH_SERIAL_FEAT_SCIF) && s->txi) {
99 4e7ed2d1 aurel32
            qemu_set_irq(s->txi, val & (1 << 7));
100 bf5b7423 aurel32
        }
101 4e7ed2d1 aurel32
        if (!(val & (1 << 6))) {
102 4e7ed2d1 aurel32
            qemu_set_irq(s->rxi, 0);
103 63242a00 aurel32
        }
104 2f062c72 ths
        return;
105 2f062c72 ths
    case 0x0c: /* FTDR / TDR */
106 2f062c72 ths
        if (s->chr) {
107 2f062c72 ths
            ch = val;
108 2f062c72 ths
            qemu_chr_write(s->chr, &ch, 1);
109 2f062c72 ths
        }
110 2f062c72 ths
        s->dr = val;
111 2f062c72 ths
        s->flags &= ~SH_SERIAL_FLAG_TDE;
112 2f062c72 ths
        return;
113 2f062c72 ths
#if 0
114 2f062c72 ths
    case 0x14: /* FRDR / RDR */
115 2f062c72 ths
        ret = 0;
116 2f062c72 ths
        break;
117 2f062c72 ths
#endif
118 2f062c72 ths
    }
119 2f062c72 ths
    if (s->feat & SH_SERIAL_FEAT_SCIF) {
120 2f062c72 ths
        switch(offs) {
121 2f062c72 ths
        case 0x10: /* FSR */
122 2f062c72 ths
            if (!(val & (1 << 6)))
123 2f062c72 ths
                s->flags &= ~SH_SERIAL_FLAG_TEND;
124 2f062c72 ths
            if (!(val & (1 << 5)))
125 2f062c72 ths
                s->flags &= ~SH_SERIAL_FLAG_TDE;
126 2f062c72 ths
            if (!(val & (1 << 4)))
127 2f062c72 ths
                s->flags &= ~SH_SERIAL_FLAG_BRK;
128 2f062c72 ths
            if (!(val & (1 << 1)))
129 2f062c72 ths
                s->flags &= ~SH_SERIAL_FLAG_RDF;
130 2f062c72 ths
            if (!(val & (1 << 0)))
131 2f062c72 ths
                s->flags &= ~SH_SERIAL_FLAG_DR;
132 63242a00 aurel32
133 63242a00 aurel32
            if (!(val & (1 << 1)) || !(val & (1 << 0))) {
134 4e7ed2d1 aurel32
                if (s->rxi) {
135 4e7ed2d1 aurel32
                    qemu_set_irq(s->rxi, 0);
136 63242a00 aurel32
                }
137 63242a00 aurel32
            }
138 2f062c72 ths
            return;
139 2f062c72 ths
        case 0x18: /* FCR */
140 2f062c72 ths
            s->fcr = val;
141 63242a00 aurel32
            switch ((val >> 6) & 3) {
142 63242a00 aurel32
            case 0:
143 63242a00 aurel32
                s->rtrg = 1;
144 63242a00 aurel32
                break;
145 63242a00 aurel32
            case 1:
146 63242a00 aurel32
                s->rtrg = 4;
147 63242a00 aurel32
                break;
148 63242a00 aurel32
            case 2:
149 63242a00 aurel32
                s->rtrg = 8;
150 63242a00 aurel32
                break;
151 63242a00 aurel32
            case 3:
152 63242a00 aurel32
                s->rtrg = 14;
153 63242a00 aurel32
                break;
154 63242a00 aurel32
            }
155 63242a00 aurel32
            if (val & (1 << 1)) {
156 63242a00 aurel32
                sh_serial_clear_fifo(s);
157 63242a00 aurel32
                s->sr &= ~(1 << 1);
158 63242a00 aurel32
            }
159 63242a00 aurel32
160 2f062c72 ths
            return;
161 2f062c72 ths
        case 0x20: /* SPTR */
162 63242a00 aurel32
            s->sptr = val & 0xf3;
163 2f062c72 ths
            return;
164 2f062c72 ths
        case 0x24: /* LSR */
165 2f062c72 ths
            return;
166 2f062c72 ths
        }
167 2f062c72 ths
    }
168 2f062c72 ths
    else {
169 2f062c72 ths
        switch(offs) {
170 d1f193b0 aurel32
#if 0
171 2f062c72 ths
        case 0x0c:
172 2f062c72 ths
            ret = s->dr;
173 2f062c72 ths
            break;
174 2f062c72 ths
        case 0x10:
175 2f062c72 ths
            ret = 0;
176 2f062c72 ths
            break;
177 d1f193b0 aurel32
#endif
178 2f062c72 ths
        case 0x1c:
179 d1f193b0 aurel32
            s->sptr = val & 0x8f;
180 d1f193b0 aurel32
            return;
181 2f062c72 ths
        }
182 2f062c72 ths
    }
183 2f062c72 ths
184 2f062c72 ths
    fprintf(stderr, "sh_serial: unsupported write to 0x%02x\n", offs);
185 43dc2a64 Blue Swirl
    abort();
186 2f062c72 ths
}
187 2f062c72 ths
188 b7277ac2 Aurelien Jarno
static uint32_t sh_serial_read(void *opaque, uint32_t offs)
189 2f062c72 ths
{
190 2f062c72 ths
    sh_serial_state *s = opaque;
191 2f062c72 ths
    uint32_t ret = ~0;
192 2f062c72 ths
193 2f062c72 ths
#if 0
194 2f062c72 ths
    switch(offs) {
195 2f062c72 ths
    case 0x00:
196 2f062c72 ths
        ret = s->smr;
197 2f062c72 ths
        break;
198 2f062c72 ths
    case 0x04:
199 2f062c72 ths
        ret = s->brr;
200 2f062c72 ths
        break;
201 2f062c72 ths
    case 0x08:
202 2f062c72 ths
        ret = s->scr;
203 2f062c72 ths
        break;
204 2f062c72 ths
    case 0x14:
205 2f062c72 ths
        ret = 0;
206 2f062c72 ths
        break;
207 2f062c72 ths
    }
208 2f062c72 ths
#endif
209 2f062c72 ths
    if (s->feat & SH_SERIAL_FEAT_SCIF) {
210 2f062c72 ths
        switch(offs) {
211 bf5b7423 aurel32
        case 0x00: /* SMR */
212 bf5b7423 aurel32
            ret = s->smr;
213 bf5b7423 aurel32
            break;
214 bf5b7423 aurel32
        case 0x08: /* SCR */
215 bf5b7423 aurel32
            ret = s->scr;
216 bf5b7423 aurel32
            break;
217 2f062c72 ths
        case 0x10: /* FSR */
218 2f062c72 ths
            ret = 0;
219 2f062c72 ths
            if (s->flags & SH_SERIAL_FLAG_TEND)
220 2f062c72 ths
                ret |= (1 << 6);
221 2f062c72 ths
            if (s->flags & SH_SERIAL_FLAG_TDE)
222 2f062c72 ths
                ret |= (1 << 5);
223 2f062c72 ths
            if (s->flags & SH_SERIAL_FLAG_BRK)
224 2f062c72 ths
                ret |= (1 << 4);
225 2f062c72 ths
            if (s->flags & SH_SERIAL_FLAG_RDF)
226 2f062c72 ths
                ret |= (1 << 1);
227 2f062c72 ths
            if (s->flags & SH_SERIAL_FLAG_DR)
228 2f062c72 ths
                ret |= (1 << 0);
229 2f062c72 ths
230 63242a00 aurel32
            if (s->scr & (1 << 5))
231 2f062c72 ths
                s->flags |= SH_SERIAL_FLAG_TDE | SH_SERIAL_FLAG_TEND;
232 2f062c72 ths
233 2f062c72 ths
            break;
234 63242a00 aurel32
        case 0x14:
235 63242a00 aurel32
            if (s->rx_cnt > 0) {
236 63242a00 aurel32
                ret = s->rx_fifo[s->rx_tail++];
237 63242a00 aurel32
                s->rx_cnt--;
238 63242a00 aurel32
                if (s->rx_tail == SH_RX_FIFO_LENGTH)
239 63242a00 aurel32
                    s->rx_tail = 0;
240 63242a00 aurel32
                if (s->rx_cnt < s->rtrg)
241 63242a00 aurel32
                    s->flags &= ~SH_SERIAL_FLAG_RDF;
242 63242a00 aurel32
            }
243 63242a00 aurel32
            break;
244 2f062c72 ths
#if 0
245 2f062c72 ths
        case 0x18:
246 2f062c72 ths
            ret = s->fcr;
247 2f062c72 ths
            break;
248 2f062c72 ths
#endif
249 2f062c72 ths
        case 0x1c:
250 2f062c72 ths
            ret = s->rx_cnt;
251 2f062c72 ths
            break;
252 2f062c72 ths
        case 0x20:
253 2f062c72 ths
            ret = s->sptr;
254 2f062c72 ths
            break;
255 2f062c72 ths
        case 0x24:
256 2f062c72 ths
            ret = 0;
257 2f062c72 ths
            break;
258 2f062c72 ths
        }
259 2f062c72 ths
    }
260 2f062c72 ths
    else {
261 2f062c72 ths
        switch(offs) {
262 d1f193b0 aurel32
#if 0
263 2f062c72 ths
        case 0x0c:
264 2f062c72 ths
            ret = s->dr;
265 2f062c72 ths
            break;
266 2f062c72 ths
        case 0x10:
267 2f062c72 ths
            ret = 0;
268 2f062c72 ths
            break;
269 63242a00 aurel32
        case 0x14:
270 63242a00 aurel32
            ret = s->rx_fifo[0];
271 63242a00 aurel32
            break;
272 d1f193b0 aurel32
#endif
273 2f062c72 ths
        case 0x1c:
274 2f062c72 ths
            ret = s->sptr;
275 2f062c72 ths
            break;
276 2f062c72 ths
        }
277 2f062c72 ths
    }
278 2f062c72 ths
#ifdef DEBUG_SERIAL
279 8da3ff18 pbrook
    printf("sh_serial: read offs=0x%02x val=0x%x\n",
280 8da3ff18 pbrook
           offs, ret);
281 2f062c72 ths
#endif
282 2f062c72 ths
283 2f062c72 ths
    if (ret & ~((1 << 16) - 1)) {
284 2f062c72 ths
        fprintf(stderr, "sh_serial: unsupported read from 0x%02x\n", offs);
285 43dc2a64 Blue Swirl
        abort();
286 2f062c72 ths
    }
287 2f062c72 ths
288 2f062c72 ths
    return ret;
289 2f062c72 ths
}
290 2f062c72 ths
291 2f062c72 ths
static int sh_serial_can_receive(sh_serial_state *s)
292 2f062c72 ths
{
293 63242a00 aurel32
    return s->scr & (1 << 4);
294 2f062c72 ths
}
295 2f062c72 ths
296 2f062c72 ths
static void sh_serial_receive_break(sh_serial_state *s)
297 2f062c72 ths
{
298 63242a00 aurel32
    if (s->feat & SH_SERIAL_FEAT_SCIF)
299 63242a00 aurel32
        s->sr |= (1 << 4);
300 2f062c72 ths
}
301 2f062c72 ths
302 2f062c72 ths
static int sh_serial_can_receive1(void *opaque)
303 2f062c72 ths
{
304 2f062c72 ths
    sh_serial_state *s = opaque;
305 2f062c72 ths
    return sh_serial_can_receive(s);
306 2f062c72 ths
}
307 2f062c72 ths
308 2f062c72 ths
static void sh_serial_receive1(void *opaque, const uint8_t *buf, int size)
309 2f062c72 ths
{
310 2f062c72 ths
    sh_serial_state *s = opaque;
311 b7d2b020 Aurelien Jarno
312 b7d2b020 Aurelien Jarno
    if (s->feat & SH_SERIAL_FEAT_SCIF) {
313 b7d2b020 Aurelien Jarno
        int i;
314 b7d2b020 Aurelien Jarno
        for (i = 0; i < size; i++) {
315 b7d2b020 Aurelien Jarno
            if (s->rx_cnt < SH_RX_FIFO_LENGTH) {
316 b7d2b020 Aurelien Jarno
                s->rx_fifo[s->rx_head++] = buf[i];
317 b7d2b020 Aurelien Jarno
                if (s->rx_head == SH_RX_FIFO_LENGTH) {
318 b7d2b020 Aurelien Jarno
                    s->rx_head = 0;
319 b7d2b020 Aurelien Jarno
                }
320 b7d2b020 Aurelien Jarno
                s->rx_cnt++;
321 b7d2b020 Aurelien Jarno
                if (s->rx_cnt >= s->rtrg) {
322 b7d2b020 Aurelien Jarno
                    s->flags |= SH_SERIAL_FLAG_RDF;
323 b7d2b020 Aurelien Jarno
                    if (s->scr & (1 << 6) && s->rxi) {
324 b7d2b020 Aurelien Jarno
                        qemu_set_irq(s->rxi, 1);
325 b7d2b020 Aurelien Jarno
                    }
326 b7d2b020 Aurelien Jarno
                }
327 b7d2b020 Aurelien Jarno
            }
328 b7d2b020 Aurelien Jarno
        }
329 b7d2b020 Aurelien Jarno
    } else {
330 b7d2b020 Aurelien Jarno
        s->rx_fifo[0] = buf[0];
331 b7d2b020 Aurelien Jarno
    }
332 2f062c72 ths
}
333 2f062c72 ths
334 2f062c72 ths
static void sh_serial_event(void *opaque, int event)
335 2f062c72 ths
{
336 2f062c72 ths
    sh_serial_state *s = opaque;
337 2f062c72 ths
    if (event == CHR_EVENT_BREAK)
338 2f062c72 ths
        sh_serial_receive_break(s);
339 2f062c72 ths
}
340 2f062c72 ths
341 d60efc6b Blue Swirl
static CPUReadMemoryFunc * const sh_serial_readfn[] = {
342 2f062c72 ths
    &sh_serial_read,
343 2f062c72 ths
    &sh_serial_read,
344 2f062c72 ths
    &sh_serial_read,
345 2f062c72 ths
};
346 2f062c72 ths
347 d60efc6b Blue Swirl
static CPUWriteMemoryFunc * const sh_serial_writefn[] = {
348 2f062c72 ths
    &sh_serial_write,
349 2f062c72 ths
    &sh_serial_write,
350 2f062c72 ths
    &sh_serial_write,
351 2f062c72 ths
};
352 2f062c72 ths
353 c227f099 Anthony Liguori
void sh_serial_init (target_phys_addr_t base, int feat,
354 bf5b7423 aurel32
                     uint32_t freq, CharDriverState *chr,
355 4e7ed2d1 aurel32
                     qemu_irq eri_source,
356 4e7ed2d1 aurel32
                     qemu_irq rxi_source,
357 4e7ed2d1 aurel32
                     qemu_irq txi_source,
358 4e7ed2d1 aurel32
                     qemu_irq tei_source,
359 4e7ed2d1 aurel32
                     qemu_irq bri_source)
360 2f062c72 ths
{
361 2f062c72 ths
    sh_serial_state *s;
362 2f062c72 ths
    int s_io_memory;
363 2f062c72 ths
364 2f062c72 ths
    s = qemu_mallocz(sizeof(sh_serial_state));
365 2f062c72 ths
366 2f062c72 ths
    s->feat = feat;
367 2f062c72 ths
    s->flags = SH_SERIAL_FLAG_TEND | SH_SERIAL_FLAG_TDE;
368 63242a00 aurel32
    s->rtrg = 1;
369 2f062c72 ths
370 2f062c72 ths
    s->smr = 0;
371 2f062c72 ths
    s->brr = 0xff;
372 b7d35e65 balrog
    s->scr = 1 << 5; /* pretend that TX is enabled so early printk works */
373 2f062c72 ths
    s->sptr = 0;
374 2f062c72 ths
375 2f062c72 ths
    if (feat & SH_SERIAL_FEAT_SCIF) {
376 2f062c72 ths
        s->fcr = 0;
377 2f062c72 ths
    }
378 2f062c72 ths
    else {
379 2f062c72 ths
        s->dr = 0xff;
380 2f062c72 ths
    }
381 2f062c72 ths
382 63242a00 aurel32
    sh_serial_clear_fifo(s);
383 2f062c72 ths
384 1eed09cb Avi Kivity
    s_io_memory = cpu_register_io_memory(sh_serial_readfn,
385 2507c12a Alexander Graf
                                         sh_serial_writefn, s,
386 2507c12a Alexander Graf
                                         DEVICE_NATIVE_ENDIAN);
387 5c16736a balrog
    cpu_register_physical_memory(P4ADDR(base), 0x28, s_io_memory);
388 5c16736a balrog
    cpu_register_physical_memory(A7ADDR(base), 0x28, s_io_memory);
389 2f062c72 ths
390 2f062c72 ths
    s->chr = chr;
391 2f062c72 ths
392 2f062c72 ths
    if (chr)
393 2f062c72 ths
        qemu_chr_add_handlers(chr, sh_serial_can_receive1, sh_serial_receive1,
394 2f062c72 ths
                              sh_serial_event, s);
395 bf5b7423 aurel32
396 bf5b7423 aurel32
    s->eri = eri_source;
397 bf5b7423 aurel32
    s->rxi = rxi_source;
398 bf5b7423 aurel32
    s->txi = txi_source;
399 bf5b7423 aurel32
    s->tei = tei_source;
400 bf5b7423 aurel32
    s->bri = bri_source;
401 2f062c72 ths
}