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