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
28 #include "qemu/osdep.h"
29 #include "hw/sysbus.h"
30 #include "hw/irq.h"
31 #include "hw/qdev-core.h"
32 #include "hw/qdev-properties.h"
33 #include "hw/qdev-properties-system.h"
34 #include "hw/sh4/sh.h"
35 #include "chardev/char-fe.h"
36 #include "qapi/error.h"
37 #include "qemu/timer.h"
38 #include "qemu/log.h"
39 #include "trace.h"
40
41 #define SH_SERIAL_FLAG_TEND (1 << 0)
42 #define SH_SERIAL_FLAG_TDE (1 << 1)
43 #define SH_SERIAL_FLAG_RDF (1 << 2)
44 #define SH_SERIAL_FLAG_BRK (1 << 3)
45 #define SH_SERIAL_FLAG_DR (1 << 4)
46
47 #define SH_RX_FIFO_LENGTH (16)
48
49 OBJECT_DECLARE_SIMPLE_TYPE(SHSerialState, SH_SERIAL)
50
51 struct SHSerialState {
52 SysBusDevice parent;
53 uint8_t smr;
54 uint8_t brr;
55 uint8_t scr;
56 uint8_t dr; /* ftdr / tdr */
57 uint8_t sr; /* fsr / ssr */
58 uint16_t fcr;
59 uint8_t sptr;
60
61 uint8_t rx_fifo[SH_RX_FIFO_LENGTH]; /* frdr / rdr */
62 uint8_t rx_cnt;
63 uint8_t rx_tail;
64 uint8_t rx_head;
65
66 uint8_t feat;
67 int flags;
68 int rtrg;
69
70 CharBackend chr;
71 QEMUTimer fifo_timeout_timer;
72 uint64_t etu; /* Elementary Time Unit (ns) */
73
74 qemu_irq eri;
75 qemu_irq rxi;
76 qemu_irq txi;
77 qemu_irq tei;
78 qemu_irq bri;
79 };
80
sh_serial_clear_fifo(SHSerialState * s)81 static void sh_serial_clear_fifo(SHSerialState *s)
82 {
83 memset(s->rx_fifo, 0, SH_RX_FIFO_LENGTH);
84 s->rx_cnt = 0;
85 s->rx_head = 0;
86 s->rx_tail = 0;
87 }
88
sh_serial_write(void * opaque,hwaddr offs,uint64_t val,unsigned size)89 static void sh_serial_write(void *opaque, hwaddr offs,
90 uint64_t val, unsigned size)
91 {
92 SHSerialState *s = opaque;
93 DeviceState *d = DEVICE(s);
94 unsigned char ch;
95
96 trace_sh_serial_write(d->id, size, offs, val);
97 switch (offs) {
98 case 0x00: /* SMR */
99 s->smr = val & ((s->feat & SH_SERIAL_FEAT_SCIF) ? 0x7b : 0xff);
100 return;
101 case 0x04: /* BRR */
102 s->brr = val;
103 return;
104 case 0x08: /* SCR */
105 /* TODO : For SH7751, SCIF mask should be 0xfb. */
106 s->scr = val & ((s->feat & SH_SERIAL_FEAT_SCIF) ? 0xfa : 0xff);
107 if (!(val & (1 << 5))) {
108 s->flags |= SH_SERIAL_FLAG_TEND;
109 }
110 if ((s->feat & SH_SERIAL_FEAT_SCIF) && s->txi) {
111 qemu_set_irq(s->txi, val & (1 << 7));
112 }
113 if (!(val & (1 << 6))) {
114 qemu_set_irq(s->rxi, 0);
115 }
116 return;
117 case 0x0c: /* FTDR / TDR */
118 if (qemu_chr_fe_backend_connected(&s->chr)) {
119 ch = val;
120 /*
121 * XXX this blocks entire thread. Rewrite to use
122 * qemu_chr_fe_write and background I/O callbacks
123 */
124 qemu_chr_fe_write_all(&s->chr, &ch, 1);
125 }
126 s->dr = val;
127 s->flags &= ~SH_SERIAL_FLAG_TDE;
128 return;
129 #if 0
130 case 0x14: /* FRDR / RDR */
131 ret = 0;
132 break;
133 #endif
134 }
135 if (s->feat & SH_SERIAL_FEAT_SCIF) {
136 switch (offs) {
137 case 0x10: /* FSR */
138 if (!(val & (1 << 6))) {
139 s->flags &= ~SH_SERIAL_FLAG_TEND;
140 }
141 if (!(val & (1 << 5))) {
142 s->flags &= ~SH_SERIAL_FLAG_TDE;
143 }
144 if (!(val & (1 << 4))) {
145 s->flags &= ~SH_SERIAL_FLAG_BRK;
146 }
147 if (!(val & (1 << 1))) {
148 s->flags &= ~SH_SERIAL_FLAG_RDF;
149 }
150 if (!(val & (1 << 0))) {
151 s->flags &= ~SH_SERIAL_FLAG_DR;
152 }
153
154 if (!(val & (1 << 1)) || !(val & (1 << 0))) {
155 if (s->rxi) {
156 qemu_set_irq(s->rxi, 0);
157 }
158 }
159 return;
160 case 0x18: /* FCR */
161 s->fcr = val;
162 switch ((val >> 6) & 3) {
163 case 0:
164 s->rtrg = 1;
165 break;
166 case 1:
167 s->rtrg = 4;
168 break;
169 case 2:
170 s->rtrg = 8;
171 break;
172 case 3:
173 s->rtrg = 14;
174 break;
175 }
176 if (val & (1 << 1)) {
177 sh_serial_clear_fifo(s);
178 s->sr &= ~(1 << 1);
179 }
180
181 return;
182 case 0x20: /* SPTR */
183 s->sptr = val & 0xf3;
184 return;
185 case 0x24: /* LSR */
186 return;
187 }
188 } else {
189 switch (offs) {
190 #if 0
191 case 0x0c:
192 ret = s->dr;
193 break;
194 case 0x10:
195 ret = 0;
196 break;
197 #endif
198 case 0x1c:
199 s->sptr = val & 0x8f;
200 return;
201 }
202 }
203 qemu_log_mask(LOG_GUEST_ERROR,
204 "%s: unsupported write to 0x%02" HWADDR_PRIx "\n",
205 __func__, offs);
206 }
207
sh_serial_read(void * opaque,hwaddr offs,unsigned size)208 static uint64_t sh_serial_read(void *opaque, hwaddr offs,
209 unsigned size)
210 {
211 SHSerialState *s = opaque;
212 DeviceState *d = DEVICE(s);
213 uint32_t ret = UINT32_MAX;
214
215 #if 0
216 switch (offs) {
217 case 0x00:
218 ret = s->smr;
219 break;
220 case 0x04:
221 ret = s->brr;
222 break;
223 case 0x08:
224 ret = s->scr;
225 break;
226 case 0x14:
227 ret = 0;
228 break;
229 }
230 #endif
231 if (s->feat & SH_SERIAL_FEAT_SCIF) {
232 switch (offs) {
233 case 0x00: /* SMR */
234 ret = s->smr;
235 break;
236 case 0x08: /* SCR */
237 ret = s->scr;
238 break;
239 case 0x10: /* FSR */
240 ret = 0;
241 if (s->flags & SH_SERIAL_FLAG_TEND) {
242 ret |= (1 << 6);
243 }
244 if (s->flags & SH_SERIAL_FLAG_TDE) {
245 ret |= (1 << 5);
246 }
247 if (s->flags & SH_SERIAL_FLAG_BRK) {
248 ret |= (1 << 4);
249 }
250 if (s->flags & SH_SERIAL_FLAG_RDF) {
251 ret |= (1 << 1);
252 }
253 if (s->flags & SH_SERIAL_FLAG_DR) {
254 ret |= (1 << 0);
255 }
256
257 if (s->scr & (1 << 5)) {
258 s->flags |= SH_SERIAL_FLAG_TDE | SH_SERIAL_FLAG_TEND;
259 }
260
261 break;
262 case 0x14:
263 if (s->rx_cnt > 0) {
264 ret = s->rx_fifo[s->rx_tail++];
265 s->rx_cnt--;
266 if (s->rx_tail == SH_RX_FIFO_LENGTH) {
267 s->rx_tail = 0;
268 }
269 if (s->rx_cnt < s->rtrg) {
270 s->flags &= ~SH_SERIAL_FLAG_RDF;
271 }
272 }
273 break;
274 case 0x18:
275 ret = s->fcr;
276 break;
277 case 0x1c:
278 ret = s->rx_cnt;
279 break;
280 case 0x20:
281 ret = s->sptr;
282 break;
283 case 0x24:
284 ret = 0;
285 break;
286 }
287 } else {
288 switch (offs) {
289 #if 0
290 case 0x0c:
291 ret = s->dr;
292 break;
293 case 0x10:
294 ret = 0;
295 break;
296 case 0x14:
297 ret = s->rx_fifo[0];
298 break;
299 #endif
300 case 0x1c:
301 ret = s->sptr;
302 break;
303 }
304 }
305 trace_sh_serial_read(d->id, size, offs, ret);
306
307 if (ret > UINT16_MAX) {
308 qemu_log_mask(LOG_GUEST_ERROR,
309 "%s: unsupported read from 0x%02" HWADDR_PRIx "\n",
310 __func__, offs);
311 ret = 0;
312 }
313
314 return ret;
315 }
316
sh_serial_can_receive(SHSerialState * s)317 static int sh_serial_can_receive(SHSerialState *s)
318 {
319 return s->scr & (1 << 4) ? SH_RX_FIFO_LENGTH - s->rx_head : 0;
320 }
321
sh_serial_receive_break(SHSerialState * s)322 static void sh_serial_receive_break(SHSerialState *s)
323 {
324 if (s->feat & SH_SERIAL_FEAT_SCIF) {
325 s->sr |= (1 << 4);
326 }
327 }
328
sh_serial_can_receive1(void * opaque)329 static int sh_serial_can_receive1(void *opaque)
330 {
331 SHSerialState *s = opaque;
332 return sh_serial_can_receive(s);
333 }
334
sh_serial_timeout_int(void * opaque)335 static void sh_serial_timeout_int(void *opaque)
336 {
337 SHSerialState *s = opaque;
338
339 s->flags |= SH_SERIAL_FLAG_RDF;
340 if (s->scr & (1 << 6) && s->rxi) {
341 qemu_set_irq(s->rxi, 1);
342 }
343 }
344
sh_serial_receive1(void * opaque,const uint8_t * buf,int size)345 static void sh_serial_receive1(void *opaque, const uint8_t *buf, int size)
346 {
347 SHSerialState *s = opaque;
348
349 if (s->feat & SH_SERIAL_FEAT_SCIF) {
350 int i;
351 for (i = 0; i < size; i++) {
352 s->rx_fifo[s->rx_head++] = buf[i];
353 if (s->rx_head == SH_RX_FIFO_LENGTH) {
354 s->rx_head = 0;
355 }
356 s->rx_cnt++;
357 if (s->rx_cnt >= s->rtrg) {
358 s->flags |= SH_SERIAL_FLAG_RDF;
359 if (s->scr & (1 << 6) && s->rxi) {
360 timer_del(&s->fifo_timeout_timer);
361 qemu_set_irq(s->rxi, 1);
362 }
363 } else {
364 timer_mod(&s->fifo_timeout_timer,
365 qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 15 * s->etu);
366 }
367 }
368 } else {
369 s->rx_fifo[0] = buf[0];
370 }
371 }
372
sh_serial_event(void * opaque,QEMUChrEvent event)373 static void sh_serial_event(void *opaque, QEMUChrEvent event)
374 {
375 SHSerialState *s = opaque;
376 if (event == CHR_EVENT_BREAK) {
377 sh_serial_receive_break(s);
378 }
379 }
380
381 static const MemoryRegionOps sh_serial_ops = {
382 .read = sh_serial_read,
383 .write = sh_serial_write,
384 .endianness = DEVICE_NATIVE_ENDIAN,
385 };
386
sh_serial_reset(DeviceState * dev)387 static void sh_serial_reset(DeviceState *dev)
388 {
389 SHSerialState *s = SH_SERIAL(dev);
390
391 s->flags = SH_SERIAL_FLAG_TEND | SH_SERIAL_FLAG_TDE;
392 s->rtrg = 1;
393
394 s->smr = 0;
395 s->brr = 0xff;
396 s->scr = 1 << 5; /* pretend that TX is enabled so early printk works */
397 s->sptr = 0;
398
399 if (s->feat & SH_SERIAL_FEAT_SCIF) {
400 s->fcr = 0;
401 } else {
402 s->dr = 0xff;
403 }
404
405 sh_serial_clear_fifo(s);
406 }
407
sh_serial_realize(DeviceState * d,Error ** errp)408 static void sh_serial_realize(DeviceState *d, Error **errp)
409 {
410 SHSerialState *s = SH_SERIAL(d);
411 MemoryRegion *iomem = g_malloc(sizeof(*iomem));
412
413 assert(d->id);
414 memory_region_init_io(iomem, OBJECT(d), &sh_serial_ops, s, d->id, 0x28);
415 sysbus_init_mmio(SYS_BUS_DEVICE(d), iomem);
416 qdev_init_gpio_out_named(d, &s->eri, "eri", 1);
417 qdev_init_gpio_out_named(d, &s->rxi, "rxi", 1);
418 qdev_init_gpio_out_named(d, &s->txi, "txi", 1);
419 qdev_init_gpio_out_named(d, &s->tei, "tei", 1);
420 qdev_init_gpio_out_named(d, &s->bri, "bri", 1);
421
422 if (qemu_chr_fe_backend_connected(&s->chr)) {
423 qemu_chr_fe_set_handlers(&s->chr, sh_serial_can_receive1,
424 sh_serial_receive1,
425 sh_serial_event, NULL, s, NULL, true);
426 }
427
428 timer_init_ns(&s->fifo_timeout_timer, QEMU_CLOCK_VIRTUAL,
429 sh_serial_timeout_int, s);
430 s->etu = NANOSECONDS_PER_SECOND / 9600;
431 }
432
sh_serial_unrealize(DeviceState * dev)433 static void sh_serial_unrealize(DeviceState *dev)
434 {
435 SHSerialState *s = SH_SERIAL(dev);
436
437 timer_del(&s->fifo_timeout_timer);
438 }
439
440 static const Property sh_serial_properties[] = {
441 DEFINE_PROP_CHR("chardev", SHSerialState, chr),
442 DEFINE_PROP_UINT8("features", SHSerialState, feat, 0),
443 };
444
sh_serial_class_init(ObjectClass * oc,const void * data)445 static void sh_serial_class_init(ObjectClass *oc, const void *data)
446 {
447 DeviceClass *dc = DEVICE_CLASS(oc);
448
449 device_class_set_props(dc, sh_serial_properties);
450 dc->realize = sh_serial_realize;
451 dc->unrealize = sh_serial_unrealize;
452 device_class_set_legacy_reset(dc, sh_serial_reset);
453 /* Reason: part of SuperH CPU/SoC, needs to be wired up */
454 dc->user_creatable = false;
455 }
456
457 static const TypeInfo sh_serial_types[] = {
458 {
459 .name = TYPE_SH_SERIAL,
460 .parent = TYPE_SYS_BUS_DEVICE,
461 .instance_size = sizeof(SHSerialState),
462 .class_init = sh_serial_class_init,
463 },
464 };
465
466 DEFINE_TYPES(sh_serial_types)
467