hw/misc/a9scu: Do not allow invalid CPU count
[qemu/ar7.git] / hw / char / mcf_uart.c
blobf6baa3ce770796dfb246ec2c1046af7b35f1b8d7
1 /*
2 * ColdFire UART emulation.
4 * Copyright (c) 2007 CodeSourcery.
6 * This code is licensed under the GPL
7 */
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 #include "qom/object.h"
19 struct mcf_uart_state {
20 SysBusDevice parent_obj;
22 MemoryRegion iomem;
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;
36 CharBackend chr;
38 typedef struct mcf_uart_state mcf_uart_state;
40 #define TYPE_MCF_UART "mcf-uart"
41 DECLARE_INSTANCE_CHECKER(mcf_uart_state, MCF_UART,
42 TYPE_MCF_UART)
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
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
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
70 static void mcf_uart_update(mcf_uart_state *s)
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;
79 qemu_set_irq(s->irq, (s->isr & s->imr) != 0);
82 uint64_t mcf_uart_read(void *opaque, hwaddr addr,
83 unsigned size)
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:
93 uint8_t val;
94 int i;
96 if (s->fifo_len == 0)
97 return 0;
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);
107 qemu_chr_fe_accept_input(&s->chr);
108 return val;
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;
124 /* Update TxRDY flag and set data if present and enabled. */
125 static void mcf_uart_do_tx(mcf_uart_state *s)
127 if (s->tx_enabled && (s->sr & MCF_UART_TxEMP) == 0) {
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);
131 s->sr |= MCF_UART_TxEMP;
133 if (s->tx_enabled) {
134 s->sr |= MCF_UART_TxRDY;
135 } else {
136 s->sr &= ~MCF_UART_TxRDY;
140 static void mcf_do_command(mcf_uart_state *s, uint8_t cmd)
142 /* Misc command. */
143 switch ((cmd >> 4) & 7) {
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;
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;
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;
202 void mcf_uart_write(void *opaque, hwaddr addr,
203 uint64_t val, unsigned size)
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;
231 mcf_uart_update(s);
234 static void mcf_uart_reset(DeviceState *dev)
236 mcf_uart_state *s = MCF_UART(dev);
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;
248 static void mcf_uart_push_byte(mcf_uart_state *s, uint8_t data)
250 /* Break events overwrite the last byte if the fifo is full. */
251 if (s->fifo_len == 4)
252 s->fifo_len--;
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;
260 mcf_uart_update(s);
263 static void mcf_uart_event(void *opaque, QEMUChrEvent event)
265 mcf_uart_state *s = (mcf_uart_state *)opaque;
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;
277 static int mcf_uart_can_receive(void *opaque)
279 mcf_uart_state *s = (mcf_uart_state *)opaque;
281 return s->rx_enabled && (s->sr & MCF_UART_FFULL) == 0;
284 static void mcf_uart_receive(void *opaque, const uint8_t *buf, int size)
286 mcf_uart_state *s = (mcf_uart_state *)opaque;
288 mcf_uart_push_byte(s, buf[0]);
291 static const MemoryRegionOps mcf_uart_ops = {
292 .read = mcf_uart_read,
293 .write = mcf_uart_write,
294 .endianness = DEVICE_NATIVE_ENDIAN,
297 static void mcf_uart_instance_init(Object *obj)
299 SysBusDevice *dev = SYS_BUS_DEVICE(obj);
300 mcf_uart_state *s = MCF_UART(dev);
302 memory_region_init_io(&s->iomem, obj, &mcf_uart_ops, s, "uart", 0x40);
303 sysbus_init_mmio(dev, &s->iomem);
305 sysbus_init_irq(dev, &s->irq);
308 static void mcf_uart_realize(DeviceState *dev, Error **errp)
310 mcf_uart_state *s = MCF_UART(dev);
312 qemu_chr_fe_set_handlers(&s->chr, mcf_uart_can_receive, mcf_uart_receive,
313 mcf_uart_event, NULL, s, NULL, true);
316 static Property mcf_uart_properties[] = {
317 DEFINE_PROP_CHR("chardev", mcf_uart_state, chr),
318 DEFINE_PROP_END_OF_LIST(),
321 static void mcf_uart_class_init(ObjectClass *oc, void *data)
323 DeviceClass *dc = DEVICE_CLASS(oc);
325 dc->realize = mcf_uart_realize;
326 dc->reset = mcf_uart_reset;
327 device_class_set_props(dc, mcf_uart_properties);
328 set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
331 static 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,
339 static void mcf_uart_register(void)
341 type_register_static(&mcf_uart_info);
344 type_init(mcf_uart_register)
346 void *mcf_uart_init(qemu_irq irq, Chardev *chrdrv)
348 DeviceState *dev;
350 dev = qdev_new(TYPE_MCF_UART);
351 if (chrdrv) {
352 qdev_prop_set_chr(dev, "chardev", chrdrv);
354 sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
356 sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);
358 return dev;
361 void mcf_uart_mm_init(hwaddr base, qemu_irq irq, Chardev *chrdrv)
363 DeviceState *dev;
365 dev = mcf_uart_init(irq, chrdrv);
366 sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);