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