Statistics
| Branch: | Revision:

root / hw / sh_serial.c @ c1ded3dc

History | View | Annotate | Download (10.2 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 2f062c72 ths
static void sh_serial_ioport_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 2f062c72 ths
static uint32_t sh_serial_ioport_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_byte(sh_serial_state *s, int ch)
297 2f062c72 ths
{
298 63242a00 aurel32
    if (s->feat & SH_SERIAL_FEAT_SCIF) {
299 63242a00 aurel32
        if (s->rx_cnt < SH_RX_FIFO_LENGTH) {
300 63242a00 aurel32
            s->rx_fifo[s->rx_head++] = ch;
301 63242a00 aurel32
            if (s->rx_head == SH_RX_FIFO_LENGTH)
302 63242a00 aurel32
                s->rx_head = 0;
303 63242a00 aurel32
            s->rx_cnt++;
304 63242a00 aurel32
            if (s->rx_cnt >= s->rtrg) {
305 63242a00 aurel32
                s->flags |= SH_SERIAL_FLAG_RDF;
306 63242a00 aurel32
                if (s->scr & (1 << 6) && s->rxi) {
307 4e7ed2d1 aurel32
                    qemu_set_irq(s->rxi, 1);
308 63242a00 aurel32
                }
309 63242a00 aurel32
            }
310 63242a00 aurel32
        }
311 63242a00 aurel32
    } else {
312 63242a00 aurel32
        s->rx_fifo[0] = ch;
313 63242a00 aurel32
    }
314 2f062c72 ths
}
315 2f062c72 ths
316 2f062c72 ths
static void sh_serial_receive_break(sh_serial_state *s)
317 2f062c72 ths
{
318 63242a00 aurel32
    if (s->feat & SH_SERIAL_FEAT_SCIF)
319 63242a00 aurel32
        s->sr |= (1 << 4);
320 2f062c72 ths
}
321 2f062c72 ths
322 2f062c72 ths
static int sh_serial_can_receive1(void *opaque)
323 2f062c72 ths
{
324 2f062c72 ths
    sh_serial_state *s = opaque;
325 2f062c72 ths
    return sh_serial_can_receive(s);
326 2f062c72 ths
}
327 2f062c72 ths
328 2f062c72 ths
static void sh_serial_receive1(void *opaque, const uint8_t *buf, int size)
329 2f062c72 ths
{
330 2f062c72 ths
    sh_serial_state *s = opaque;
331 2f062c72 ths
    sh_serial_receive_byte(s, buf[0]);
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 c227f099 Anthony Liguori
static uint32_t sh_serial_read (void *opaque, target_phys_addr_t addr)
342 2f062c72 ths
{
343 2f062c72 ths
    sh_serial_state *s = opaque;
344 8da3ff18 pbrook
    return sh_serial_ioport_read(s, addr);
345 2f062c72 ths
}
346 2f062c72 ths
347 9596ebb7 pbrook
static void sh_serial_write (void *opaque,
348 c227f099 Anthony Liguori
                             target_phys_addr_t addr, uint32_t value)
349 2f062c72 ths
{
350 2f062c72 ths
    sh_serial_state *s = opaque;
351 8da3ff18 pbrook
    sh_serial_ioport_write(s, addr, value);
352 2f062c72 ths
}
353 2f062c72 ths
354 d60efc6b Blue Swirl
static CPUReadMemoryFunc * const sh_serial_readfn[] = {
355 2f062c72 ths
    &sh_serial_read,
356 2f062c72 ths
    &sh_serial_read,
357 2f062c72 ths
    &sh_serial_read,
358 2f062c72 ths
};
359 2f062c72 ths
360 d60efc6b Blue Swirl
static CPUWriteMemoryFunc * const sh_serial_writefn[] = {
361 2f062c72 ths
    &sh_serial_write,
362 2f062c72 ths
    &sh_serial_write,
363 2f062c72 ths
    &sh_serial_write,
364 2f062c72 ths
};
365 2f062c72 ths
366 c227f099 Anthony Liguori
void sh_serial_init (target_phys_addr_t base, int feat,
367 bf5b7423 aurel32
                     uint32_t freq, CharDriverState *chr,
368 4e7ed2d1 aurel32
                     qemu_irq eri_source,
369 4e7ed2d1 aurel32
                     qemu_irq rxi_source,
370 4e7ed2d1 aurel32
                     qemu_irq txi_source,
371 4e7ed2d1 aurel32
                     qemu_irq tei_source,
372 4e7ed2d1 aurel32
                     qemu_irq bri_source)
373 2f062c72 ths
{
374 2f062c72 ths
    sh_serial_state *s;
375 2f062c72 ths
    int s_io_memory;
376 2f062c72 ths
377 2f062c72 ths
    s = qemu_mallocz(sizeof(sh_serial_state));
378 2f062c72 ths
379 2f062c72 ths
    s->feat = feat;
380 2f062c72 ths
    s->flags = SH_SERIAL_FLAG_TEND | SH_SERIAL_FLAG_TDE;
381 63242a00 aurel32
    s->rtrg = 1;
382 2f062c72 ths
383 2f062c72 ths
    s->smr = 0;
384 2f062c72 ths
    s->brr = 0xff;
385 b7d35e65 balrog
    s->scr = 1 << 5; /* pretend that TX is enabled so early printk works */
386 2f062c72 ths
    s->sptr = 0;
387 2f062c72 ths
388 2f062c72 ths
    if (feat & SH_SERIAL_FEAT_SCIF) {
389 2f062c72 ths
        s->fcr = 0;
390 2f062c72 ths
    }
391 2f062c72 ths
    else {
392 2f062c72 ths
        s->dr = 0xff;
393 2f062c72 ths
    }
394 2f062c72 ths
395 63242a00 aurel32
    sh_serial_clear_fifo(s);
396 2f062c72 ths
397 1eed09cb Avi Kivity
    s_io_memory = cpu_register_io_memory(sh_serial_readfn,
398 2f062c72 ths
                                         sh_serial_writefn, s);
399 5c16736a balrog
    cpu_register_physical_memory(P4ADDR(base), 0x28, s_io_memory);
400 5c16736a balrog
    cpu_register_physical_memory(A7ADDR(base), 0x28, s_io_memory);
401 2f062c72 ths
402 2f062c72 ths
    s->chr = chr;
403 2f062c72 ths
404 2f062c72 ths
    if (chr)
405 2f062c72 ths
        qemu_chr_add_handlers(chr, sh_serial_can_receive1, sh_serial_receive1,
406 2f062c72 ths
                              sh_serial_event, s);
407 bf5b7423 aurel32
408 bf5b7423 aurel32
    s->eri = eri_source;
409 bf5b7423 aurel32
    s->rxi = rxi_source;
410 bf5b7423 aurel32
    s->txi = txi_source;
411 bf5b7423 aurel32
    s->tei = tei_source;
412 bf5b7423 aurel32
    s->bri = bri_source;
413 2f062c72 ths
}