|
|
1.1 root 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:
1.1.1.2 ! root 40: #define SH_RX_FIFO_LENGTH (16)
! 41:
1.1 root 42: typedef struct {
43: uint8_t smr;
44: uint8_t brr;
45: uint8_t scr;
46: uint8_t dr; /* ftdr / tdr */
47: uint8_t sr; /* fsr / ssr */
48: uint16_t fcr;
49: uint8_t sptr;
50:
1.1.1.2 ! root 51: uint8_t rx_fifo[SH_RX_FIFO_LENGTH]; /* frdr / rdr */
1.1 root 52: uint8_t rx_cnt;
1.1.1.2 ! root 53: uint8_t rx_tail;
! 54: uint8_t rx_head;
1.1 root 55:
56: int freq;
57: int feat;
58: int flags;
1.1.1.2 ! root 59: int rtrg;
1.1 root 60:
61: CharDriverState *chr;
1.1.1.2 ! root 62:
! 63: qemu_irq eri;
! 64: qemu_irq rxi;
! 65: qemu_irq txi;
! 66: qemu_irq tei;
! 67: qemu_irq bri;
1.1 root 68: } sh_serial_state;
69:
1.1.1.2 ! root 70: static void sh_serial_clear_fifo(sh_serial_state * s)
! 71: {
! 72: memset(s->rx_fifo, 0, SH_RX_FIFO_LENGTH);
! 73: s->rx_cnt = 0;
! 74: s->rx_head = 0;
! 75: s->rx_tail = 0;
! 76: }
! 77:
1.1 root 78: static void sh_serial_ioport_write(void *opaque, uint32_t offs, uint32_t val)
79: {
80: sh_serial_state *s = opaque;
81: unsigned char ch;
82:
83: #ifdef DEBUG_SERIAL
1.1.1.2 ! root 84: printf("sh_serial: write offs=0x%02x val=0x%02x\n",
! 85: offs, val);
1.1 root 86: #endif
87: switch(offs) {
88: case 0x00: /* SMR */
89: s->smr = val & ((s->feat & SH_SERIAL_FEAT_SCIF) ? 0x7b : 0xff);
90: return;
91: case 0x04: /* BRR */
92: s->brr = val;
93: return;
94: case 0x08: /* SCR */
1.1.1.2 ! root 95: /* TODO : For SH7751, SCIF mask should be 0xfb. */
! 96: s->scr = val & ((s->feat & SH_SERIAL_FEAT_SCIF) ? 0xfa : 0xff);
1.1 root 97: if (!(val & (1 << 5)))
98: s->flags |= SH_SERIAL_FLAG_TEND;
1.1.1.2 ! root 99: if ((s->feat & SH_SERIAL_FEAT_SCIF) && s->txi) {
! 100: qemu_set_irq(s->txi, val & (1 << 7));
! 101: }
! 102: if (!(val & (1 << 6))) {
! 103: qemu_set_irq(s->rxi, 0);
! 104: }
1.1 root 105: return;
106: case 0x0c: /* FTDR / TDR */
107: if (s->chr) {
108: ch = val;
109: qemu_chr_write(s->chr, &ch, 1);
110: }
111: s->dr = val;
112: s->flags &= ~SH_SERIAL_FLAG_TDE;
113: return;
114: #if 0
115: case 0x14: /* FRDR / RDR */
116: ret = 0;
117: break;
118: #endif
119: }
120: if (s->feat & SH_SERIAL_FEAT_SCIF) {
121: switch(offs) {
122: case 0x10: /* FSR */
123: if (!(val & (1 << 6)))
124: s->flags &= ~SH_SERIAL_FLAG_TEND;
125: if (!(val & (1 << 5)))
126: s->flags &= ~SH_SERIAL_FLAG_TDE;
127: if (!(val & (1 << 4)))
128: s->flags &= ~SH_SERIAL_FLAG_BRK;
129: if (!(val & (1 << 1)))
130: s->flags &= ~SH_SERIAL_FLAG_RDF;
131: if (!(val & (1 << 0)))
132: s->flags &= ~SH_SERIAL_FLAG_DR;
1.1.1.2 ! root 133:
! 134: if (!(val & (1 << 1)) || !(val & (1 << 0))) {
! 135: if (s->rxi) {
! 136: qemu_set_irq(s->rxi, 0);
! 137: }
! 138: }
1.1 root 139: return;
140: case 0x18: /* FCR */
141: s->fcr = val;
1.1.1.2 ! root 142: switch ((val >> 6) & 3) {
! 143: case 0:
! 144: s->rtrg = 1;
! 145: break;
! 146: case 1:
! 147: s->rtrg = 4;
! 148: break;
! 149: case 2:
! 150: s->rtrg = 8;
! 151: break;
! 152: case 3:
! 153: s->rtrg = 14;
! 154: break;
! 155: }
! 156: if (val & (1 << 1)) {
! 157: sh_serial_clear_fifo(s);
! 158: s->sr &= ~(1 << 1);
! 159: }
! 160:
1.1 root 161: return;
162: case 0x20: /* SPTR */
1.1.1.2 ! root 163: s->sptr = val & 0xf3;
1.1 root 164: return;
165: case 0x24: /* LSR */
166: return;
167: }
168: }
169: else {
170: switch(offs) {
1.1.1.2 ! root 171: #if 0
1.1 root 172: case 0x0c:
173: ret = s->dr;
174: break;
175: case 0x10:
176: ret = 0;
177: break;
1.1.1.2 ! root 178: #endif
1.1 root 179: case 0x1c:
1.1.1.2 ! root 180: s->sptr = val & 0x8f;
! 181: return;
1.1 root 182: }
183: }
184:
185: fprintf(stderr, "sh_serial: unsupported write to 0x%02x\n", offs);
186: assert(0);
187: }
188:
189: static uint32_t sh_serial_ioport_read(void *opaque, uint32_t offs)
190: {
191: sh_serial_state *s = opaque;
192: uint32_t ret = ~0;
193:
194: #if 0
195: switch(offs) {
196: case 0x00:
197: ret = s->smr;
198: break;
199: case 0x04:
200: ret = s->brr;
201: break;
202: case 0x08:
203: ret = s->scr;
204: break;
205: case 0x14:
206: ret = 0;
207: break;
208: }
209: #endif
210: if (s->feat & SH_SERIAL_FEAT_SCIF) {
211: switch(offs) {
1.1.1.2 ! root 212: case 0x00: /* SMR */
! 213: ret = s->smr;
! 214: break;
! 215: case 0x08: /* SCR */
! 216: ret = s->scr;
! 217: break;
1.1 root 218: case 0x10: /* FSR */
219: ret = 0;
220: if (s->flags & SH_SERIAL_FLAG_TEND)
221: ret |= (1 << 6);
222: if (s->flags & SH_SERIAL_FLAG_TDE)
223: ret |= (1 << 5);
224: if (s->flags & SH_SERIAL_FLAG_BRK)
225: ret |= (1 << 4);
226: if (s->flags & SH_SERIAL_FLAG_RDF)
227: ret |= (1 << 1);
228: if (s->flags & SH_SERIAL_FLAG_DR)
229: ret |= (1 << 0);
230:
1.1.1.2 ! root 231: if (s->scr & (1 << 5))
1.1 root 232: s->flags |= SH_SERIAL_FLAG_TDE | SH_SERIAL_FLAG_TEND;
233:
234: break;
1.1.1.2 ! root 235: case 0x14:
! 236: if (s->rx_cnt > 0) {
! 237: ret = s->rx_fifo[s->rx_tail++];
! 238: s->rx_cnt--;
! 239: if (s->rx_tail == SH_RX_FIFO_LENGTH)
! 240: s->rx_tail = 0;
! 241: if (s->rx_cnt < s->rtrg)
! 242: s->flags &= ~SH_SERIAL_FLAG_RDF;
! 243: }
! 244: break;
1.1 root 245: #if 0
246: case 0x18:
247: ret = s->fcr;
248: break;
249: #endif
250: case 0x1c:
251: ret = s->rx_cnt;
252: break;
253: case 0x20:
254: ret = s->sptr;
255: break;
256: case 0x24:
257: ret = 0;
258: break;
259: }
260: }
261: else {
262: switch(offs) {
1.1.1.2 ! root 263: #if 0
1.1 root 264: case 0x0c:
265: ret = s->dr;
266: break;
267: case 0x10:
268: ret = 0;
269: break;
1.1.1.2 ! root 270: case 0x14:
! 271: ret = s->rx_fifo[0];
! 272: break;
! 273: #endif
1.1 root 274: case 0x1c:
275: ret = s->sptr;
276: break;
277: }
278: }
279: #ifdef DEBUG_SERIAL
1.1.1.2 ! root 280: printf("sh_serial: read offs=0x%02x val=0x%x\n",
! 281: offs, ret);
1.1 root 282: #endif
283:
284: if (ret & ~((1 << 16) - 1)) {
285: fprintf(stderr, "sh_serial: unsupported read from 0x%02x\n", offs);
286: assert(0);
287: }
288:
289: return ret;
290: }
291:
292: static int sh_serial_can_receive(sh_serial_state *s)
293: {
1.1.1.2 ! root 294: return s->scr & (1 << 4);
1.1 root 295: }
296:
297: static void sh_serial_receive_byte(sh_serial_state *s, int ch)
298: {
1.1.1.2 ! root 299: if (s->feat & SH_SERIAL_FEAT_SCIF) {
! 300: if (s->rx_cnt < SH_RX_FIFO_LENGTH) {
! 301: s->rx_fifo[s->rx_head++] = ch;
! 302: if (s->rx_head == SH_RX_FIFO_LENGTH)
! 303: s->rx_head = 0;
! 304: s->rx_cnt++;
! 305: if (s->rx_cnt >= s->rtrg) {
! 306: s->flags |= SH_SERIAL_FLAG_RDF;
! 307: if (s->scr & (1 << 6) && s->rxi) {
! 308: qemu_set_irq(s->rxi, 1);
! 309: }
! 310: }
! 311: }
! 312: } else {
! 313: s->rx_fifo[0] = ch;
! 314: }
1.1 root 315: }
316:
317: static void sh_serial_receive_break(sh_serial_state *s)
318: {
1.1.1.2 ! root 319: if (s->feat & SH_SERIAL_FEAT_SCIF)
! 320: s->sr |= (1 << 4);
1.1 root 321: }
322:
323: static int sh_serial_can_receive1(void *opaque)
324: {
325: sh_serial_state *s = opaque;
326: return sh_serial_can_receive(s);
327: }
328:
329: static void sh_serial_receive1(void *opaque, const uint8_t *buf, int size)
330: {
331: sh_serial_state *s = opaque;
332: sh_serial_receive_byte(s, buf[0]);
333: }
334:
335: static void sh_serial_event(void *opaque, int event)
336: {
337: sh_serial_state *s = opaque;
338: if (event == CHR_EVENT_BREAK)
339: sh_serial_receive_break(s);
340: }
341:
342: static uint32_t sh_serial_read (void *opaque, target_phys_addr_t addr)
343: {
344: sh_serial_state *s = opaque;
1.1.1.2 ! root 345: return sh_serial_ioport_read(s, addr);
1.1 root 346: }
347:
348: static void sh_serial_write (void *opaque,
349: target_phys_addr_t addr, uint32_t value)
350: {
351: sh_serial_state *s = opaque;
1.1.1.2 ! root 352: sh_serial_ioport_write(s, addr, value);
1.1 root 353: }
354:
355: static CPUReadMemoryFunc *sh_serial_readfn[] = {
356: &sh_serial_read,
357: &sh_serial_read,
358: &sh_serial_read,
359: };
360:
361: static CPUWriteMemoryFunc *sh_serial_writefn[] = {
362: &sh_serial_write,
363: &sh_serial_write,
364: &sh_serial_write,
365: };
366:
367: void sh_serial_init (target_phys_addr_t base, int feat,
1.1.1.2 ! root 368: uint32_t freq, CharDriverState *chr,
! 369: qemu_irq eri_source,
! 370: qemu_irq rxi_source,
! 371: qemu_irq txi_source,
! 372: qemu_irq tei_source,
! 373: qemu_irq bri_source)
1.1 root 374: {
375: sh_serial_state *s;
376: int s_io_memory;
377:
378: s = qemu_mallocz(sizeof(sh_serial_state));
379:
380: s->feat = feat;
381: s->flags = SH_SERIAL_FLAG_TEND | SH_SERIAL_FLAG_TDE;
1.1.1.2 ! root 382: s->rtrg = 1;
1.1 root 383:
384: s->smr = 0;
385: s->brr = 0xff;
386: s->scr = 1 << 5; /* pretend that TX is enabled so early printk works */
387: s->sptr = 0;
388:
389: if (feat & SH_SERIAL_FEAT_SCIF) {
390: s->fcr = 0;
391: }
392: else {
393: s->dr = 0xff;
394: }
395:
1.1.1.2 ! root 396: sh_serial_clear_fifo(s);
1.1 root 397:
398: s_io_memory = cpu_register_io_memory(0, sh_serial_readfn,
399: sh_serial_writefn, s);
1.1.1.2 ! root 400: cpu_register_physical_memory(P4ADDR(base), 0x28, s_io_memory);
! 401: cpu_register_physical_memory(A7ADDR(base), 0x28, s_io_memory);
1.1 root 402:
403: s->chr = chr;
404:
405: if (chr)
406: qemu_chr_add_handlers(chr, sh_serial_can_receive1, sh_serial_receive1,
407: sh_serial_event, s);
1.1.1.2 ! root 408:
! 409: s->eri = eri_source;
! 410: s->rxi = rxi_source;
! 411: s->txi = txi_source;
! 412: s->tei = tei_source;
! 413: s->bri = bri_source;
1.1 root 414: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.