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