Statistics
| Branch: | Revision:

root / hw / sh_serial.c @ 87ecb68b

History | View | Annotate | Download (7.5 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
#include <assert.h>
31 2f062c72 ths
32 2f062c72 ths
//#define DEBUG_SERIAL
33 2f062c72 ths
34 2f062c72 ths
#define SH_SERIAL_FLAG_TEND (1 << 0)
35 2f062c72 ths
#define SH_SERIAL_FLAG_TDE  (1 << 1)
36 2f062c72 ths
#define SH_SERIAL_FLAG_RDF  (1 << 2)
37 2f062c72 ths
#define SH_SERIAL_FLAG_BRK  (1 << 3)
38 2f062c72 ths
#define SH_SERIAL_FLAG_DR   (1 << 4)
39 2f062c72 ths
40 2f062c72 ths
typedef struct {
41 2f062c72 ths
    uint8_t smr;
42 2f062c72 ths
    uint8_t brr;
43 2f062c72 ths
    uint8_t scr;
44 2f062c72 ths
    uint8_t dr; /* ftdr / tdr */
45 2f062c72 ths
    uint8_t sr; /* fsr / ssr */
46 2f062c72 ths
    uint16_t fcr;
47 2f062c72 ths
    uint8_t sptr;
48 2f062c72 ths
49 2f062c72 ths
    uint8_t rx_fifo[16]; /* frdr / rdr */
50 2f062c72 ths
    uint8_t rx_cnt;
51 2f062c72 ths
52 2f062c72 ths
    target_phys_addr_t base;
53 2f062c72 ths
    int freq;
54 2f062c72 ths
    int feat;
55 2f062c72 ths
    int flags;
56 2f062c72 ths
57 2f062c72 ths
    CharDriverState *chr;
58 2f062c72 ths
} sh_serial_state;
59 2f062c72 ths
60 2f062c72 ths
static void sh_serial_ioport_write(void *opaque, uint32_t offs, uint32_t val)
61 2f062c72 ths
{
62 2f062c72 ths
    sh_serial_state *s = opaque;
63 2f062c72 ths
    unsigned char ch;
64 2f062c72 ths
65 2f062c72 ths
#ifdef DEBUG_SERIAL
66 2f062c72 ths
    printf("sh_serial: write base=0x%08lx offs=0x%02x val=0x%02x\n",
67 2f062c72 ths
           (unsigned long) s->base, offs, val);
68 2f062c72 ths
#endif
69 2f062c72 ths
    switch(offs) {
70 2f062c72 ths
    case 0x00: /* SMR */
71 2f062c72 ths
        s->smr = val & ((s->feat & SH_SERIAL_FEAT_SCIF) ? 0x7b : 0xff);
72 2f062c72 ths
        return;
73 2f062c72 ths
    case 0x04: /* BRR */
74 2f062c72 ths
        s->brr = val;
75 2f062c72 ths
        return;
76 2f062c72 ths
    case 0x08: /* SCR */
77 2f062c72 ths
        s->scr = val & ((s->feat & SH_SERIAL_FEAT_SCIF) ? 0xfb : 0xff);
78 2f062c72 ths
        if (!(val & (1 << 5)))
79 2f062c72 ths
            s->flags |= SH_SERIAL_FLAG_TEND;
80 2f062c72 ths
        return;
81 2f062c72 ths
    case 0x0c: /* FTDR / TDR */
82 2f062c72 ths
        if (s->chr) {
83 2f062c72 ths
            ch = val;
84 2f062c72 ths
            qemu_chr_write(s->chr, &ch, 1);
85 2f062c72 ths
        }
86 2f062c72 ths
        s->dr = val;
87 2f062c72 ths
        s->flags &= ~SH_SERIAL_FLAG_TDE;
88 2f062c72 ths
        return;
89 2f062c72 ths
#if 0
90 2f062c72 ths
    case 0x14: /* FRDR / RDR */
91 2f062c72 ths
        ret = 0;
92 2f062c72 ths
        break;
93 2f062c72 ths
#endif
94 2f062c72 ths
    }
95 2f062c72 ths
    if (s->feat & SH_SERIAL_FEAT_SCIF) {
96 2f062c72 ths
        switch(offs) {
97 2f062c72 ths
        case 0x10: /* FSR */
98 2f062c72 ths
            if (!(val & (1 << 6)))
99 2f062c72 ths
                s->flags &= ~SH_SERIAL_FLAG_TEND;
100 2f062c72 ths
            if (!(val & (1 << 5)))
101 2f062c72 ths
                s->flags &= ~SH_SERIAL_FLAG_TDE;
102 2f062c72 ths
            if (!(val & (1 << 4)))
103 2f062c72 ths
                s->flags &= ~SH_SERIAL_FLAG_BRK;
104 2f062c72 ths
            if (!(val & (1 << 1)))
105 2f062c72 ths
                s->flags &= ~SH_SERIAL_FLAG_RDF;
106 2f062c72 ths
            if (!(val & (1 << 0)))
107 2f062c72 ths
                s->flags &= ~SH_SERIAL_FLAG_DR;
108 2f062c72 ths
            return;
109 2f062c72 ths
        case 0x18: /* FCR */
110 2f062c72 ths
            s->fcr = val;
111 2f062c72 ths
            return;
112 2f062c72 ths
        case 0x20: /* SPTR */
113 2f062c72 ths
            s->sptr = val;
114 2f062c72 ths
            return;
115 2f062c72 ths
        case 0x24: /* LSR */
116 2f062c72 ths
            return;
117 2f062c72 ths
        }
118 2f062c72 ths
    }
119 2f062c72 ths
    else {
120 2f062c72 ths
#if 0
121 2f062c72 ths
        switch(offs) {
122 2f062c72 ths
        case 0x0c:
123 2f062c72 ths
            ret = s->dr;
124 2f062c72 ths
            break;
125 2f062c72 ths
        case 0x10:
126 2f062c72 ths
            ret = 0;
127 2f062c72 ths
            break;
128 2f062c72 ths
        case 0x1c:
129 2f062c72 ths
            ret = s->sptr;
130 2f062c72 ths
            break;
131 2f062c72 ths
        }
132 2f062c72 ths
#endif
133 2f062c72 ths
    }
134 2f062c72 ths
135 2f062c72 ths
    fprintf(stderr, "sh_serial: unsupported write to 0x%02x\n", offs);
136 2f062c72 ths
    assert(0);
137 2f062c72 ths
}
138 2f062c72 ths
139 2f062c72 ths
static uint32_t sh_serial_ioport_read(void *opaque, uint32_t offs)
140 2f062c72 ths
{
141 2f062c72 ths
    sh_serial_state *s = opaque;
142 2f062c72 ths
    uint32_t ret = ~0;
143 2f062c72 ths
144 2f062c72 ths
#if 0
145 2f062c72 ths
    switch(offs) {
146 2f062c72 ths
    case 0x00:
147 2f062c72 ths
        ret = s->smr;
148 2f062c72 ths
        break;
149 2f062c72 ths
    case 0x04:
150 2f062c72 ths
        ret = s->brr;
151 2f062c72 ths
        break;
152 2f062c72 ths
    case 0x08:
153 2f062c72 ths
        ret = s->scr;
154 2f062c72 ths
        break;
155 2f062c72 ths
    case 0x14:
156 2f062c72 ths
        ret = 0;
157 2f062c72 ths
        break;
158 2f062c72 ths
    }
159 2f062c72 ths
#endif
160 2f062c72 ths
    if (s->feat & SH_SERIAL_FEAT_SCIF) {
161 2f062c72 ths
        switch(offs) {
162 2f062c72 ths
        case 0x10: /* FSR */
163 2f062c72 ths
            ret = 0;
164 2f062c72 ths
            if (s->flags & SH_SERIAL_FLAG_TEND)
165 2f062c72 ths
                ret |= (1 << 6);
166 2f062c72 ths
            if (s->flags & SH_SERIAL_FLAG_TDE)
167 2f062c72 ths
                ret |= (1 << 5);
168 2f062c72 ths
            if (s->flags & SH_SERIAL_FLAG_BRK)
169 2f062c72 ths
                ret |= (1 << 4);
170 2f062c72 ths
            if (s->flags & SH_SERIAL_FLAG_RDF)
171 2f062c72 ths
                ret |= (1 << 1);
172 2f062c72 ths
            if (s->flags & SH_SERIAL_FLAG_DR)
173 2f062c72 ths
                ret |= (1 << 0);
174 2f062c72 ths
175 2f062c72 ths
            if (s->scr & (1 << 5))
176 2f062c72 ths
                s->flags |= SH_SERIAL_FLAG_TDE | SH_SERIAL_FLAG_TEND;
177 2f062c72 ths
178 2f062c72 ths
            break;
179 2f062c72 ths
#if 0
180 2f062c72 ths
        case 0x18:
181 2f062c72 ths
            ret = s->fcr;
182 2f062c72 ths
            break;
183 2f062c72 ths
#endif
184 2f062c72 ths
        case 0x1c:
185 2f062c72 ths
            ret = s->rx_cnt;
186 2f062c72 ths
            break;
187 2f062c72 ths
        case 0x20:
188 2f062c72 ths
            ret = s->sptr;
189 2f062c72 ths
            break;
190 2f062c72 ths
        case 0x24:
191 2f062c72 ths
            ret = 0;
192 2f062c72 ths
            break;
193 2f062c72 ths
        }
194 2f062c72 ths
    }
195 2f062c72 ths
    else {
196 2f062c72 ths
#if 0
197 2f062c72 ths
        switch(offs) {
198 2f062c72 ths
        case 0x0c:
199 2f062c72 ths
            ret = s->dr;
200 2f062c72 ths
            break;
201 2f062c72 ths
        case 0x10:
202 2f062c72 ths
            ret = 0;
203 2f062c72 ths
            break;
204 2f062c72 ths
        case 0x1c:
205 2f062c72 ths
            ret = s->sptr;
206 2f062c72 ths
            break;
207 2f062c72 ths
        }
208 2f062c72 ths
#endif
209 2f062c72 ths
    }
210 2f062c72 ths
#ifdef DEBUG_SERIAL
211 2f062c72 ths
    printf("sh_serial: read base=0x%08lx offs=0x%02x val=0x%x\n",
212 2f062c72 ths
           (unsigned long) s->base, offs, ret);
213 2f062c72 ths
#endif
214 2f062c72 ths
215 2f062c72 ths
    if (ret & ~((1 << 16) - 1)) {
216 2f062c72 ths
        fprintf(stderr, "sh_serial: unsupported read from 0x%02x\n", offs);
217 2f062c72 ths
        assert(0);
218 2f062c72 ths
    }
219 2f062c72 ths
220 2f062c72 ths
    return ret;
221 2f062c72 ths
}
222 2f062c72 ths
223 2f062c72 ths
static int sh_serial_can_receive(sh_serial_state *s)
224 2f062c72 ths
{
225 2f062c72 ths
    return 0;
226 2f062c72 ths
}
227 2f062c72 ths
228 2f062c72 ths
static void sh_serial_receive_byte(sh_serial_state *s, int ch)
229 2f062c72 ths
{
230 2f062c72 ths
}
231 2f062c72 ths
232 2f062c72 ths
static void sh_serial_receive_break(sh_serial_state *s)
233 2f062c72 ths
{
234 2f062c72 ths
}
235 2f062c72 ths
236 2f062c72 ths
static int sh_serial_can_receive1(void *opaque)
237 2f062c72 ths
{
238 2f062c72 ths
    sh_serial_state *s = opaque;
239 2f062c72 ths
    return sh_serial_can_receive(s);
240 2f062c72 ths
}
241 2f062c72 ths
242 2f062c72 ths
static void sh_serial_receive1(void *opaque, const uint8_t *buf, int size)
243 2f062c72 ths
{
244 2f062c72 ths
    sh_serial_state *s = opaque;
245 2f062c72 ths
    sh_serial_receive_byte(s, buf[0]);
246 2f062c72 ths
}
247 2f062c72 ths
248 2f062c72 ths
static void sh_serial_event(void *opaque, int event)
249 2f062c72 ths
{
250 2f062c72 ths
    sh_serial_state *s = opaque;
251 2f062c72 ths
    if (event == CHR_EVENT_BREAK)
252 2f062c72 ths
        sh_serial_receive_break(s);
253 2f062c72 ths
}
254 2f062c72 ths
255 2f062c72 ths
uint32_t sh_serial_read (void *opaque, target_phys_addr_t addr)
256 2f062c72 ths
{
257 2f062c72 ths
    sh_serial_state *s = opaque;
258 2f062c72 ths
    return sh_serial_ioport_read(s, addr - s->base);
259 2f062c72 ths
}
260 2f062c72 ths
261 2f062c72 ths
void sh_serial_write (void *opaque,
262 2f062c72 ths
                      target_phys_addr_t addr, uint32_t value)
263 2f062c72 ths
{
264 2f062c72 ths
    sh_serial_state *s = opaque;
265 2f062c72 ths
    sh_serial_ioport_write(s, addr - s->base, value);
266 2f062c72 ths
}
267 2f062c72 ths
268 2f062c72 ths
static CPUReadMemoryFunc *sh_serial_readfn[] = {
269 2f062c72 ths
    &sh_serial_read,
270 2f062c72 ths
    &sh_serial_read,
271 2f062c72 ths
    &sh_serial_read,
272 2f062c72 ths
};
273 2f062c72 ths
274 2f062c72 ths
static CPUWriteMemoryFunc *sh_serial_writefn[] = {
275 2f062c72 ths
    &sh_serial_write,
276 2f062c72 ths
    &sh_serial_write,
277 2f062c72 ths
    &sh_serial_write,
278 2f062c72 ths
};
279 2f062c72 ths
280 2f062c72 ths
void sh_serial_init (target_phys_addr_t base, int feat,
281 2f062c72 ths
                     uint32_t freq, CharDriverState *chr)
282 2f062c72 ths
{
283 2f062c72 ths
    sh_serial_state *s;
284 2f062c72 ths
    int s_io_memory;
285 2f062c72 ths
286 2f062c72 ths
    s = qemu_mallocz(sizeof(sh_serial_state));
287 2f062c72 ths
    if (!s)
288 2f062c72 ths
        return;
289 2f062c72 ths
290 2f062c72 ths
    s->base = base;
291 2f062c72 ths
    s->feat = feat;
292 2f062c72 ths
    s->flags = SH_SERIAL_FLAG_TEND | SH_SERIAL_FLAG_TDE;
293 2f062c72 ths
294 2f062c72 ths
    s->smr = 0;
295 2f062c72 ths
    s->brr = 0xff;
296 2f062c72 ths
    s->scr = 0;
297 2f062c72 ths
    s->sptr = 0;
298 2f062c72 ths
299 2f062c72 ths
    if (feat & SH_SERIAL_FEAT_SCIF) {
300 2f062c72 ths
        s->fcr = 0;
301 2f062c72 ths
    }
302 2f062c72 ths
    else {
303 2f062c72 ths
        s->dr = 0xff;
304 2f062c72 ths
    }
305 2f062c72 ths
306 2f062c72 ths
    s->rx_cnt = 0;
307 2f062c72 ths
308 2f062c72 ths
    s_io_memory = cpu_register_io_memory(0, sh_serial_readfn,
309 2f062c72 ths
                                         sh_serial_writefn, s);
310 2f062c72 ths
    cpu_register_physical_memory(base, 0x28, s_io_memory);
311 2f062c72 ths
312 2f062c72 ths
    s->chr = chr;
313 2f062c72 ths
314 2f062c72 ths
    if (chr)
315 2f062c72 ths
        qemu_chr_add_handlers(chr, sh_serial_can_receive1, sh_serial_receive1,
316 2f062c72 ths
                              sh_serial_event, s);
317 2f062c72 ths
}