Break up vl.h.
[qemu] / hw / sh_serial.c
1 /*
2  * QEMU SCI/SCIF serial port emulation
3  *
4  * Copyright (c) 2007 Magnus Damm
5  *
6  * Based on serial.c - QEMU 16450 UART emulation
7  * Copyright (c) 2003-2004 Fabrice Bellard
8  *
9  * Permission is hereby granted, free of charge, to any person obtaining a copy
10  * of this software and associated documentation files (the "Software"), to deal
11  * in the Software without restriction, including without limitation the rights
12  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13  * copies of the Software, and to permit persons to whom the Software is
14  * furnished to do so, subject to the following conditions:
15  *
16  * The above copyright notice and this permission notice shall be included in
17  * all copies or substantial portions of the Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25  * THE SOFTWARE.
26  */
27 #include "hw.h"
28 #include "sh.h"
29 #include "qemu-char.h"
30 #include <assert.h>
31
32 //#define DEBUG_SERIAL
33
34 #define SH_SERIAL_FLAG_TEND (1 << 0)
35 #define SH_SERIAL_FLAG_TDE  (1 << 1)
36 #define SH_SERIAL_FLAG_RDF  (1 << 2)
37 #define SH_SERIAL_FLAG_BRK  (1 << 3)
38 #define SH_SERIAL_FLAG_DR   (1 << 4)
39
40 typedef struct {
41     uint8_t smr;
42     uint8_t brr;
43     uint8_t scr;
44     uint8_t dr; /* ftdr / tdr */
45     uint8_t sr; /* fsr / ssr */
46     uint16_t fcr;
47     uint8_t sptr;
48
49     uint8_t rx_fifo[16]; /* frdr / rdr */
50     uint8_t rx_cnt;
51
52     target_phys_addr_t base;
53     int freq;
54     int feat;
55     int flags;
56
57     CharDriverState *chr;
58 } sh_serial_state;
59
60 static void sh_serial_ioport_write(void *opaque, uint32_t offs, uint32_t val)
61 {
62     sh_serial_state *s = opaque;
63     unsigned char ch;
64
65 #ifdef DEBUG_SERIAL
66     printf("sh_serial: write base=0x%08lx offs=0x%02x val=0x%02x\n",
67            (unsigned long) s->base, offs, val);
68 #endif
69     switch(offs) {
70     case 0x00: /* SMR */
71         s->smr = val & ((s->feat & SH_SERIAL_FEAT_SCIF) ? 0x7b : 0xff);
72         return;
73     case 0x04: /* BRR */
74         s->brr = val;
75         return;
76     case 0x08: /* SCR */
77         s->scr = val & ((s->feat & SH_SERIAL_FEAT_SCIF) ? 0xfb : 0xff);
78         if (!(val & (1 << 5)))
79             s->flags |= SH_SERIAL_FLAG_TEND;
80         return;
81     case 0x0c: /* FTDR / TDR */
82         if (s->chr) {
83             ch = val;
84             qemu_chr_write(s->chr, &ch, 1);
85         }
86         s->dr = val;
87         s->flags &= ~SH_SERIAL_FLAG_TDE;
88         return;
89 #if 0
90     case 0x14: /* FRDR / RDR */
91         ret = 0;
92         break;
93 #endif
94     }
95     if (s->feat & SH_SERIAL_FEAT_SCIF) {
96         switch(offs) {
97         case 0x10: /* FSR */
98             if (!(val & (1 << 6)))
99                 s->flags &= ~SH_SERIAL_FLAG_TEND;
100             if (!(val & (1 << 5)))
101                 s->flags &= ~SH_SERIAL_FLAG_TDE;
102             if (!(val & (1 << 4)))
103                 s->flags &= ~SH_SERIAL_FLAG_BRK;
104             if (!(val & (1 << 1)))
105                 s->flags &= ~SH_SERIAL_FLAG_RDF;
106             if (!(val & (1 << 0)))
107                 s->flags &= ~SH_SERIAL_FLAG_DR;
108             return;
109         case 0x18: /* FCR */
110             s->fcr = val;
111             return;
112         case 0x20: /* SPTR */
113             s->sptr = val;
114             return;
115         case 0x24: /* LSR */
116             return;
117         }
118     }
119     else {
120 #if 0
121         switch(offs) {
122         case 0x0c:
123             ret = s->dr;
124             break;
125         case 0x10:
126             ret = 0;
127             break;
128         case 0x1c:
129             ret = s->sptr;
130             break;
131         }
132 #endif
133     }
134
135     fprintf(stderr, "sh_serial: unsupported write to 0x%02x\n", offs);
136     assert(0);
137 }
138
139 static uint32_t sh_serial_ioport_read(void *opaque, uint32_t offs)
140 {
141     sh_serial_state *s = opaque;
142     uint32_t ret = ~0;
143
144 #if 0
145     switch(offs) {
146     case 0x00:
147         ret = s->smr;
148         break;
149     case 0x04:
150         ret = s->brr;
151         break;
152     case 0x08:
153         ret = s->scr;
154         break;
155     case 0x14:
156         ret = 0;
157         break;
158     }
159 #endif
160     if (s->feat & SH_SERIAL_FEAT_SCIF) {
161         switch(offs) {
162         case 0x10: /* FSR */
163             ret = 0;
164             if (s->flags & SH_SERIAL_FLAG_TEND)
165                 ret |= (1 << 6);
166             if (s->flags & SH_SERIAL_FLAG_TDE)
167                 ret |= (1 << 5);
168             if (s->flags & SH_SERIAL_FLAG_BRK)
169                 ret |= (1 << 4);
170             if (s->flags & SH_SERIAL_FLAG_RDF)
171                 ret |= (1 << 1);
172             if (s->flags & SH_SERIAL_FLAG_DR)
173                 ret |= (1 << 0);
174
175             if (s->scr & (1 << 5))
176                 s->flags |= SH_SERIAL_FLAG_TDE | SH_SERIAL_FLAG_TEND;
177
178             break;
179 #if 0
180         case 0x18:
181             ret = s->fcr;
182             break;
183 #endif
184         case 0x1c:
185             ret = s->rx_cnt;
186             break;
187         case 0x20:
188             ret = s->sptr;
189             break;
190         case 0x24:
191             ret = 0;
192             break;
193         }
194     }
195     else {
196 #if 0
197         switch(offs) {
198         case 0x0c:
199             ret = s->dr;
200             break;
201         case 0x10:
202             ret = 0;
203             break;
204         case 0x1c:
205             ret = s->sptr;
206             break;
207         }
208 #endif
209     }
210 #ifdef DEBUG_SERIAL
211     printf("sh_serial: read base=0x%08lx offs=0x%02x val=0x%x\n",
212            (unsigned long) s->base, offs, ret);
213 #endif
214
215     if (ret & ~((1 << 16) - 1)) {
216         fprintf(stderr, "sh_serial: unsupported read from 0x%02x\n", offs);
217         assert(0);
218     }
219
220     return ret;
221 }
222
223 static int sh_serial_can_receive(sh_serial_state *s)
224 {
225     return 0;
226 }
227
228 static void sh_serial_receive_byte(sh_serial_state *s, int ch)
229 {
230 }
231
232 static void sh_serial_receive_break(sh_serial_state *s)
233 {
234 }
235
236 static int sh_serial_can_receive1(void *opaque)
237 {
238     sh_serial_state *s = opaque;
239     return sh_serial_can_receive(s);
240 }
241
242 static void sh_serial_receive1(void *opaque, const uint8_t *buf, int size)
243 {
244     sh_serial_state *s = opaque;
245     sh_serial_receive_byte(s, buf[0]);
246 }
247
248 static void sh_serial_event(void *opaque, int event)
249 {
250     sh_serial_state *s = opaque;
251     if (event == CHR_EVENT_BREAK)
252         sh_serial_receive_break(s);
253 }
254
255 uint32_t sh_serial_read (void *opaque, target_phys_addr_t addr)
256 {
257     sh_serial_state *s = opaque;
258     return sh_serial_ioport_read(s, addr - s->base);
259 }
260
261 void sh_serial_write (void *opaque,
262                       target_phys_addr_t addr, uint32_t value)
263 {
264     sh_serial_state *s = opaque;
265     sh_serial_ioport_write(s, addr - s->base, value);
266 }
267
268 static CPUReadMemoryFunc *sh_serial_readfn[] = {
269     &sh_serial_read,
270     &sh_serial_read,
271     &sh_serial_read,
272 };
273
274 static CPUWriteMemoryFunc *sh_serial_writefn[] = {
275     &sh_serial_write,
276     &sh_serial_write,
277     &sh_serial_write,
278 };
279
280 void sh_serial_init (target_phys_addr_t base, int feat,
281                      uint32_t freq, CharDriverState *chr)
282 {
283     sh_serial_state *s;
284     int s_io_memory;
285
286     s = qemu_mallocz(sizeof(sh_serial_state));
287     if (!s)
288         return;
289
290     s->base = base;
291     s->feat = feat;
292     s->flags = SH_SERIAL_FLAG_TEND | SH_SERIAL_FLAG_TDE;
293
294     s->smr = 0;
295     s->brr = 0xff;
296     s->scr = 0;
297     s->sptr = 0;
298
299     if (feat & SH_SERIAL_FEAT_SCIF) {
300         s->fcr = 0;
301     }
302     else {
303         s->dr = 0xff;
304     }
305
306     s->rx_cnt = 0;
307
308     s_io_memory = cpu_register_io_memory(0, sh_serial_readfn,
309                                          sh_serial_writefn, s);
310     cpu_register_physical_memory(base, 0x28, s_io_memory);
311
312     s->chr = chr;
313
314     if (chr)
315         qemu_chr_add_handlers(chr, sh_serial_can_receive1, sh_serial_receive1,
316                               sh_serial_event, s);
317 }