sd: Use ERRP_GUARD()
[qemu.git] / hw / char / mcf_uart.c
1 /*
2 * ColdFire UART emulation.
3 *
4 * Copyright (c) 2007 CodeSourcery.
5 *
6 * This code is licensed under the GPL
7 */
8
9 #include "qemu/osdep.h"
10 #include "hw/irq.h"
11 #include "hw/sysbus.h"
12 #include "qemu/module.h"
13 #include "qapi/error.h"
14 #include "hw/m68k/mcf.h"
15 #include "hw/qdev-properties.h"
16 #include "chardev/char-fe.h"
17
18 typedef struct {
19 SysBusDevice parent_obj;
20
21 MemoryRegion iomem;
22 uint8_t mr[2];
23 uint8_t sr;
24 uint8_t isr;
25 uint8_t imr;
26 uint8_t bg1;
27 uint8_t bg2;
28 uint8_t fifo[4];
29 uint8_t tb;
30 int current_mr;
31 int fifo_len;
32 int tx_enabled;
33 int rx_enabled;
34 qemu_irq irq;
35 CharBackend chr;
36 } mcf_uart_state;
37
38 #define TYPE_MCF_UART "mcf-uart"
39 #define MCF_UART(obj) OBJECT_CHECK(mcf_uart_state, (obj), TYPE_MCF_UART)
40
41 /* UART Status Register bits. */
42 #define MCF_UART_RxRDY 0x01
43 #define MCF_UART_FFULL 0x02
44 #define MCF_UART_TxRDY 0x04
45 #define MCF_UART_TxEMP 0x08
46 #define MCF_UART_OE 0x10
47 #define MCF_UART_PE 0x20
48 #define MCF_UART_FE 0x40
49 #define MCF_UART_RB 0x80
50
51 /* Interrupt flags. */
52 #define MCF_UART_TxINT 0x01
53 #define MCF_UART_RxINT 0x02
54 #define MCF_UART_DBINT 0x04
55 #define MCF_UART_COSINT 0x80
56
57 /* UMR1 flags. */
58 #define MCF_UART_BC0 0x01
59 #define MCF_UART_BC1 0x02
60 #define MCF_UART_PT 0x04
61 #define MCF_UART_PM0 0x08
62 #define MCF_UART_PM1 0x10
63 #define MCF_UART_ERR 0x20
64 #define MCF_UART_RxIRQ 0x40
65 #define MCF_UART_RxRTS 0x80
66
67 static void mcf_uart_update(mcf_uart_state *s)
68 {
69 s->isr &= ~(MCF_UART_TxINT | MCF_UART_RxINT);
70 if (s->sr & MCF_UART_TxRDY)
71 s->isr |= MCF_UART_TxINT;
72 if ((s->sr & ((s->mr[0] & MCF_UART_RxIRQ)
73 ? MCF_UART_FFULL : MCF_UART_RxRDY)) != 0)
74 s->isr |= MCF_UART_RxINT;
75
76 qemu_set_irq(s->irq, (s->isr & s->imr) != 0);
77 }
78
79 uint64_t mcf_uart_read(void *opaque, hwaddr addr,
80 unsigned size)
81 {
82 mcf_uart_state *s = (mcf_uart_state *)opaque;
83 switch (addr & 0x3f) {
84 case 0x00:
85 return s->mr[s->current_mr];
86 case 0x04:
87 return s->sr;
88 case 0x0c:
89 {
90 uint8_t val;
91 int i;
92
93 if (s->fifo_len == 0)
94 return 0;
95
96 val = s->fifo[0];
97 s->fifo_len--;
98 for (i = 0; i < s->fifo_len; i++)
99 s->fifo[i] = s->fifo[i + 1];
100 s->sr &= ~MCF_UART_FFULL;
101 if (s->fifo_len == 0)
102 s->sr &= ~MCF_UART_RxRDY;
103 mcf_uart_update(s);
104 qemu_chr_fe_accept_input(&s->chr);
105 return val;
106 }
107 case 0x10:
108 /* TODO: Implement IPCR. */
109 return 0;
110 case 0x14:
111 return s->isr;
112 case 0x18:
113 return s->bg1;
114 case 0x1c:
115 return s->bg2;
116 default:
117 return 0;
118 }
119 }
120
121 /* Update TxRDY flag and set data if present and enabled. */
122 static void mcf_uart_do_tx(mcf_uart_state *s)
123 {
124 if (s->tx_enabled && (s->sr & MCF_UART_TxEMP) == 0) {
125 /* XXX this blocks entire thread. Rewrite to use
126 * qemu_chr_fe_write and background I/O callbacks */
127 qemu_chr_fe_write_all(&s->chr, (unsigned char *)&s->tb, 1);
128 s->sr |= MCF_UART_TxEMP;
129 }
130 if (s->tx_enabled) {
131 s->sr |= MCF_UART_TxRDY;
132 } else {
133 s->sr &= ~MCF_UART_TxRDY;
134 }
135 }
136
137 static void mcf_do_command(mcf_uart_state *s, uint8_t cmd)
138 {
139 /* Misc command. */
140 switch ((cmd >> 4) & 7) {
141 case 0: /* No-op. */
142 break;
143 case 1: /* Reset mode register pointer. */
144 s->current_mr = 0;
145 break;
146 case 2: /* Reset receiver. */
147 s->rx_enabled = 0;
148 s->fifo_len = 0;
149 s->sr &= ~(MCF_UART_RxRDY | MCF_UART_FFULL);
150 break;
151 case 3: /* Reset transmitter. */
152 s->tx_enabled = 0;
153 s->sr |= MCF_UART_TxEMP;
154 s->sr &= ~MCF_UART_TxRDY;
155 break;
156 case 4: /* Reset error status. */
157 break;
158 case 5: /* Reset break-change interrupt. */
159 s->isr &= ~MCF_UART_DBINT;
160 break;
161 case 6: /* Start break. */
162 case 7: /* Stop break. */
163 break;
164 }
165
166 /* Transmitter command. */
167 switch ((cmd >> 2) & 3) {
168 case 0: /* No-op. */
169 break;
170 case 1: /* Enable. */
171 s->tx_enabled = 1;
172 mcf_uart_do_tx(s);
173 break;
174 case 2: /* Disable. */
175 s->tx_enabled = 0;
176 mcf_uart_do_tx(s);
177 break;
178 case 3: /* Reserved. */
179 fprintf(stderr, "mcf_uart: Bad TX command\n");
180 break;
181 }
182
183 /* Receiver command. */
184 switch (cmd & 3) {
185 case 0: /* No-op. */
186 break;
187 case 1: /* Enable. */
188 s->rx_enabled = 1;
189 break;
190 case 2:
191 s->rx_enabled = 0;
192 break;
193 case 3: /* Reserved. */
194 fprintf(stderr, "mcf_uart: Bad RX command\n");
195 break;
196 }
197 }
198
199 void mcf_uart_write(void *opaque, hwaddr addr,
200 uint64_t val, unsigned size)
201 {
202 mcf_uart_state *s = (mcf_uart_state *)opaque;
203 switch (addr & 0x3f) {
204 case 0x00:
205 s->mr[s->current_mr] = val;
206 s->current_mr = 1;
207 break;
208 case 0x04:
209 /* CSR is ignored. */
210 break;
211 case 0x08: /* Command Register. */
212 mcf_do_command(s, val);
213 break;
214 case 0x0c: /* Transmit Buffer. */
215 s->sr &= ~MCF_UART_TxEMP;
216 s->tb = val;
217 mcf_uart_do_tx(s);
218 break;
219 case 0x10:
220 /* ACR is ignored. */
221 break;
222 case 0x14:
223 s->imr = val;
224 break;
225 default:
226 break;
227 }
228 mcf_uart_update(s);
229 }
230
231 static void mcf_uart_reset(DeviceState *dev)
232 {
233 mcf_uart_state *s = MCF_UART(dev);
234
235 s->fifo_len = 0;
236 s->mr[0] = 0;
237 s->mr[1] = 0;
238 s->sr = MCF_UART_TxEMP;
239 s->tx_enabled = 0;
240 s->rx_enabled = 0;
241 s->isr = 0;
242 s->imr = 0;
243 }
244
245 static void mcf_uart_push_byte(mcf_uart_state *s, uint8_t data)
246 {
247 /* Break events overwrite the last byte if the fifo is full. */
248 if (s->fifo_len == 4)
249 s->fifo_len--;
250
251 s->fifo[s->fifo_len] = data;
252 s->fifo_len++;
253 s->sr |= MCF_UART_RxRDY;
254 if (s->fifo_len == 4)
255 s->sr |= MCF_UART_FFULL;
256
257 mcf_uart_update(s);
258 }
259
260 static void mcf_uart_event(void *opaque, QEMUChrEvent event)
261 {
262 mcf_uart_state *s = (mcf_uart_state *)opaque;
263
264 switch (event) {
265 case CHR_EVENT_BREAK:
266 s->isr |= MCF_UART_DBINT;
267 mcf_uart_push_byte(s, 0);
268 break;
269 default:
270 break;
271 }
272 }
273
274 static int mcf_uart_can_receive(void *opaque)
275 {
276 mcf_uart_state *s = (mcf_uart_state *)opaque;
277
278 return s->rx_enabled && (s->sr & MCF_UART_FFULL) == 0;
279 }
280
281 static void mcf_uart_receive(void *opaque, const uint8_t *buf, int size)
282 {
283 mcf_uart_state *s = (mcf_uart_state *)opaque;
284
285 mcf_uart_push_byte(s, buf[0]);
286 }
287
288 static const MemoryRegionOps mcf_uart_ops = {
289 .read = mcf_uart_read,
290 .write = mcf_uart_write,
291 .endianness = DEVICE_NATIVE_ENDIAN,
292 };
293
294 static void mcf_uart_instance_init(Object *obj)
295 {
296 SysBusDevice *dev = SYS_BUS_DEVICE(obj);
297 mcf_uart_state *s = MCF_UART(dev);
298
299 memory_region_init_io(&s->iomem, obj, &mcf_uart_ops, s, "uart", 0x40);
300 sysbus_init_mmio(dev, &s->iomem);
301
302 sysbus_init_irq(dev, &s->irq);
303 }
304
305 static void mcf_uart_realize(DeviceState *dev, Error **errp)
306 {
307 mcf_uart_state *s = MCF_UART(dev);
308
309 qemu_chr_fe_set_handlers(&s->chr, mcf_uart_can_receive, mcf_uart_receive,
310 mcf_uart_event, NULL, s, NULL, true);
311 }
312
313 static Property mcf_uart_properties[] = {
314 DEFINE_PROP_CHR("chardev", mcf_uart_state, chr),
315 DEFINE_PROP_END_OF_LIST(),
316 };
317
318 static void mcf_uart_class_init(ObjectClass *oc, void *data)
319 {
320 DeviceClass *dc = DEVICE_CLASS(oc);
321
322 dc->realize = mcf_uart_realize;
323 dc->reset = mcf_uart_reset;
324 device_class_set_props(dc, mcf_uart_properties);
325 set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
326 }
327
328 static const TypeInfo mcf_uart_info = {
329 .name = TYPE_MCF_UART,
330 .parent = TYPE_SYS_BUS_DEVICE,
331 .instance_size = sizeof(mcf_uart_state),
332 .instance_init = mcf_uart_instance_init,
333 .class_init = mcf_uart_class_init,
334 };
335
336 static void mcf_uart_register(void)
337 {
338 type_register_static(&mcf_uart_info);
339 }
340
341 type_init(mcf_uart_register)
342
343 void *mcf_uart_init(qemu_irq irq, Chardev *chrdrv)
344 {
345 DeviceState *dev;
346
347 dev = qdev_new(TYPE_MCF_UART);
348 if (chrdrv) {
349 qdev_prop_set_chr(dev, "chardev", chrdrv);
350 }
351 sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
352
353 sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);
354
355 return dev;
356 }
357
358 void mcf_uart_mm_init(hwaddr base, qemu_irq irq, Chardev *chrdrv)
359 {
360 DeviceState *dev;
361
362 dev = mcf_uart_init(irq, chrdrv);
363 sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
364 }