Remove most uses of phys_ram_base (initial patch by Ian Jackson)
[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
59     struct intc_source *eri;
60     struct intc_source *rxi;
61     struct intc_source *txi;
62     struct intc_source *tei;
63     struct intc_source *bri;
64 } sh_serial_state;
65
66 static void sh_serial_ioport_write(void *opaque, uint32_t offs, uint32_t val)
67 {
68     sh_serial_state *s = opaque;
69     unsigned char ch;
70
71 #ifdef DEBUG_SERIAL
72     printf("sh_serial: write base=0x%08lx offs=0x%02x val=0x%02x\n",
73            (unsigned long) s->base, offs, val);
74 #endif
75     switch(offs) {
76     case 0x00: /* SMR */
77         s->smr = val & ((s->feat & SH_SERIAL_FEAT_SCIF) ? 0x7b : 0xff);
78         return;
79     case 0x04: /* BRR */
80         s->brr = val;
81         return;
82     case 0x08: /* SCR */
83         s->scr = val & ((s->feat & SH_SERIAL_FEAT_SCIF) ? 0xfa : 0xff);
84         if (!(val & (1 << 5)))
85             s->flags |= SH_SERIAL_FLAG_TEND;
86         if ((s->feat & SH_SERIAL_FEAT_SCIF) && s->txi) {
87             if ((val & (1 << 7)) && !(s->txi->asserted))
88                 sh_intc_toggle_source(s->txi, 0, 1);
89             else if (!(val & (1 << 7)) && s->txi->asserted)
90                 sh_intc_toggle_source(s->txi, 0, -1);
91         }
92         return;
93     case 0x0c: /* FTDR / TDR */
94         if (s->chr) {
95             ch = val;
96             qemu_chr_write(s->chr, &ch, 1);
97         }
98         s->dr = val;
99         s->flags &= ~SH_SERIAL_FLAG_TDE;
100         return;
101 #if 0
102     case 0x14: /* FRDR / RDR */
103         ret = 0;
104         break;
105 #endif
106     }
107     if (s->feat & SH_SERIAL_FEAT_SCIF) {
108         switch(offs) {
109         case 0x10: /* FSR */
110             if (!(val & (1 << 6)))
111                 s->flags &= ~SH_SERIAL_FLAG_TEND;
112             if (!(val & (1 << 5)))
113                 s->flags &= ~SH_SERIAL_FLAG_TDE;
114             if (!(val & (1 << 4)))
115                 s->flags &= ~SH_SERIAL_FLAG_BRK;
116             if (!(val & (1 << 1)))
117                 s->flags &= ~SH_SERIAL_FLAG_RDF;
118             if (!(val & (1 << 0)))
119                 s->flags &= ~SH_SERIAL_FLAG_DR;
120             return;
121         case 0x18: /* FCR */
122             s->fcr = val;
123             return;
124         case 0x20: /* SPTR */
125             s->sptr = val;
126             return;
127         case 0x24: /* LSR */
128             return;
129         }
130     }
131     else {
132 #if 0
133         switch(offs) {
134         case 0x0c:
135             ret = s->dr;
136             break;
137         case 0x10:
138             ret = 0;
139             break;
140         case 0x1c:
141             ret = s->sptr;
142             break;
143         }
144 #endif
145     }
146
147     fprintf(stderr, "sh_serial: unsupported write to 0x%02x\n", offs);
148     assert(0);
149 }
150
151 static uint32_t sh_serial_ioport_read(void *opaque, uint32_t offs)
152 {
153     sh_serial_state *s = opaque;
154     uint32_t ret = ~0;
155
156 #if 0
157     switch(offs) {
158     case 0x00:
159         ret = s->smr;
160         break;
161     case 0x04:
162         ret = s->brr;
163         break;
164     case 0x08:
165         ret = s->scr;
166         break;
167     case 0x14:
168         ret = 0;
169         break;
170     }
171 #endif
172     if (s->feat & SH_SERIAL_FEAT_SCIF) {
173         switch(offs) {
174         case 0x00: /* SMR */
175             ret = s->smr;
176             break;
177         case 0x08: /* SCR */
178             ret = s->scr;
179             break;
180         case 0x10: /* FSR */
181             ret = 0;
182             if (s->flags & SH_SERIAL_FLAG_TEND)
183                 ret |= (1 << 6);
184             if (s->flags & SH_SERIAL_FLAG_TDE)
185                 ret |= (1 << 5);
186             if (s->flags & SH_SERIAL_FLAG_BRK)
187                 ret |= (1 << 4);
188             if (s->flags & SH_SERIAL_FLAG_RDF)
189                 ret |= (1 << 1);
190             if (s->flags & SH_SERIAL_FLAG_DR)
191                 ret |= (1 << 0);
192
193             if (s->scr & (1 << 5))
194                 s->flags |= SH_SERIAL_FLAG_TDE | SH_SERIAL_FLAG_TEND;
195
196             break;
197 #if 0
198         case 0x18:
199             ret = s->fcr;
200             break;
201 #endif
202         case 0x1c:
203             ret = s->rx_cnt;
204             break;
205         case 0x20:
206             ret = s->sptr;
207             break;
208         case 0x24:
209             ret = 0;
210             break;
211         }
212     }
213     else {
214 #if 0
215         switch(offs) {
216         case 0x0c:
217             ret = s->dr;
218             break;
219         case 0x10:
220             ret = 0;
221             break;
222         case 0x1c:
223             ret = s->sptr;
224             break;
225         }
226 #endif
227     }
228 #ifdef DEBUG_SERIAL
229     printf("sh_serial: read base=0x%08lx offs=0x%02x val=0x%x\n",
230            (unsigned long) s->base, offs, ret);
231 #endif
232
233     if (ret & ~((1 << 16) - 1)) {
234         fprintf(stderr, "sh_serial: unsupported read from 0x%02x\n", offs);
235         assert(0);
236     }
237
238     return ret;
239 }
240
241 static int sh_serial_can_receive(sh_serial_state *s)
242 {
243     return 0;
244 }
245
246 static void sh_serial_receive_byte(sh_serial_state *s, int ch)
247 {
248 }
249
250 static void sh_serial_receive_break(sh_serial_state *s)
251 {
252 }
253
254 static int sh_serial_can_receive1(void *opaque)
255 {
256     sh_serial_state *s = opaque;
257     return sh_serial_can_receive(s);
258 }
259
260 static void sh_serial_receive1(void *opaque, const uint8_t *buf, int size)
261 {
262     sh_serial_state *s = opaque;
263     sh_serial_receive_byte(s, buf[0]);
264 }
265
266 static void sh_serial_event(void *opaque, int event)
267 {
268     sh_serial_state *s = opaque;
269     if (event == CHR_EVENT_BREAK)
270         sh_serial_receive_break(s);
271 }
272
273 static uint32_t sh_serial_read (void *opaque, target_phys_addr_t addr)
274 {
275     sh_serial_state *s = opaque;
276     return sh_serial_ioport_read(s, addr - s->base);
277 }
278
279 static void sh_serial_write (void *opaque,
280                              target_phys_addr_t addr, uint32_t value)
281 {
282     sh_serial_state *s = opaque;
283     sh_serial_ioport_write(s, addr - s->base, value);
284 }
285
286 static CPUReadMemoryFunc *sh_serial_readfn[] = {
287     &sh_serial_read,
288     &sh_serial_read,
289     &sh_serial_read,
290 };
291
292 static CPUWriteMemoryFunc *sh_serial_writefn[] = {
293     &sh_serial_write,
294     &sh_serial_write,
295     &sh_serial_write,
296 };
297
298 void sh_serial_init (target_phys_addr_t base, int feat,
299                      uint32_t freq, CharDriverState *chr,
300                      struct intc_source *eri_source,
301                      struct intc_source *rxi_source,
302                      struct intc_source *txi_source,
303                      struct intc_source *tei_source,
304                      struct intc_source *bri_source)
305 {
306     sh_serial_state *s;
307     int s_io_memory;
308
309     s = qemu_mallocz(sizeof(sh_serial_state));
310     if (!s)
311         return;
312
313     s->base = base;
314     s->feat = feat;
315     s->flags = SH_SERIAL_FLAG_TEND | SH_SERIAL_FLAG_TDE;
316
317     s->smr = 0;
318     s->brr = 0xff;
319     s->scr = 1 << 5; /* pretend that TX is enabled so early printk works */
320     s->sptr = 0;
321
322     if (feat & SH_SERIAL_FEAT_SCIF) {
323         s->fcr = 0;
324     }
325     else {
326         s->dr = 0xff;
327     }
328
329     s->rx_cnt = 0;
330
331     s_io_memory = cpu_register_io_memory(0, sh_serial_readfn,
332                                          sh_serial_writefn, s);
333     cpu_register_physical_memory(base, 0x28, s_io_memory);
334
335     s->chr = chr;
336
337     if (chr)
338         qemu_chr_add_handlers(chr, sh_serial_can_receive1, sh_serial_receive1,
339                               sh_serial_event, s);
340
341     s->eri = eri_source;
342     s->rxi = rxi_source;
343     s->txi = txi_source;
344     s->tei = tei_source;
345     s->bri = bri_source;
346 }