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