|
|
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.1.6 root 77: static void sh_serial_write(void *opaque, uint32_t offs, uint32_t val)
1.1 root 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;
1.1.1.7 ! root 108: qemu_chr_fe_write(s->chr, &ch, 1);
1.1 root 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:
1.1.1.6 root 188: static uint32_t sh_serial_read(void *opaque, uint32_t offs)
1.1 root 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_break(sh_serial_state *s)
297: {
1.1.1.2 root 298: if (s->feat & SH_SERIAL_FEAT_SCIF)
299: s->sr |= (1 << 4);
1.1 root 300: }
301:
302: static int sh_serial_can_receive1(void *opaque)
303: {
304: sh_serial_state *s = opaque;
305: return sh_serial_can_receive(s);
306: }
307:
308: static void sh_serial_receive1(void *opaque, const uint8_t *buf, int size)
309: {
310: sh_serial_state *s = opaque;
1.1.1.6 root 311:
312: if (s->feat & SH_SERIAL_FEAT_SCIF) {
313: int i;
314: for (i = 0; i < size; i++) {
315: if (s->rx_cnt < SH_RX_FIFO_LENGTH) {
316: s->rx_fifo[s->rx_head++] = buf[i];
317: if (s->rx_head == SH_RX_FIFO_LENGTH) {
318: s->rx_head = 0;
319: }
320: s->rx_cnt++;
321: if (s->rx_cnt >= s->rtrg) {
322: s->flags |= SH_SERIAL_FLAG_RDF;
323: if (s->scr & (1 << 6) && s->rxi) {
324: qemu_set_irq(s->rxi, 1);
325: }
326: }
327: }
328: }
329: } else {
330: s->rx_fifo[0] = buf[0];
331: }
1.1 root 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:
1.1.1.4 root 341: static CPUReadMemoryFunc * const sh_serial_readfn[] = {
1.1 root 342: &sh_serial_read,
343: &sh_serial_read,
344: &sh_serial_read,
345: };
346:
1.1.1.4 root 347: static CPUWriteMemoryFunc * const sh_serial_writefn[] = {
1.1 root 348: &sh_serial_write,
349: &sh_serial_write,
350: &sh_serial_write,
351: };
352:
353: void sh_serial_init (target_phys_addr_t base, int feat,
1.1.1.2 root 354: uint32_t freq, CharDriverState *chr,
355: qemu_irq eri_source,
356: qemu_irq rxi_source,
357: qemu_irq txi_source,
358: qemu_irq tei_source,
359: qemu_irq bri_source)
1.1 root 360: {
361: sh_serial_state *s;
362: int s_io_memory;
363:
1.1.1.7 ! root 364: s = g_malloc0(sizeof(sh_serial_state));
1.1 root 365:
366: s->feat = feat;
367: s->flags = SH_SERIAL_FLAG_TEND | SH_SERIAL_FLAG_TDE;
1.1.1.2 root 368: s->rtrg = 1;
1.1 root 369:
370: s->smr = 0;
371: s->brr = 0xff;
372: s->scr = 1 << 5; /* pretend that TX is enabled so early printk works */
373: s->sptr = 0;
374:
375: if (feat & SH_SERIAL_FEAT_SCIF) {
376: s->fcr = 0;
377: }
378: else {
379: s->dr = 0xff;
380: }
381:
1.1.1.2 root 382: sh_serial_clear_fifo(s);
1.1 root 383:
1.1.1.3 root 384: s_io_memory = cpu_register_io_memory(sh_serial_readfn,
1.1.1.6 root 385: sh_serial_writefn, s,
386: DEVICE_NATIVE_ENDIAN);
1.1.1.2 root 387: cpu_register_physical_memory(P4ADDR(base), 0x28, s_io_memory);
388: cpu_register_physical_memory(A7ADDR(base), 0x28, s_io_memory);
1.1 root 389:
390: s->chr = chr;
391:
392: if (chr)
393: qemu_chr_add_handlers(chr, sh_serial_can_receive1, sh_serial_receive1,
394: sh_serial_event, s);
1.1.1.2 root 395:
396: s->eri = eri_source;
397: s->rxi = rxi_source;
398: s->txi = txi_source;
399: s->tei = tei_source;
400: s->bri = bri_source;
1.1 root 401: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.