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