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