pcie_aer: support configurable AER capa version
[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 #include "qemu/osdep.h"
9 #include "hw/hw.h"
10 #include "hw/m68k/mcf.h"
11 #include "sysemu/char.h"
12 #include "exec/address-spaces.h"
13 #include "qapi/error.h"
14
15 typedef struct {
16 MemoryRegion iomem;
17 uint8_t mr[2];
18 uint8_t sr;
19 uint8_t isr;
20 uint8_t imr;
21 uint8_t bg1;
22 uint8_t bg2;
23 uint8_t fifo[4];
24 uint8_t tb;
25 int current_mr;
26 int fifo_len;
27 int tx_enabled;
28 int rx_enabled;
29 qemu_irq irq;
30 CharBackend chr;
31 } mcf_uart_state;
32
33 /* UART Status Register bits. */
34 #define MCF_UART_RxRDY 0x01
35 #define MCF_UART_FFULL 0x02
36 #define MCF_UART_TxRDY 0x04
37 #define MCF_UART_TxEMP 0x08
38 #define MCF_UART_OE 0x10
39 #define MCF_UART_PE 0x20
40 #define MCF_UART_FE 0x40
41 #define MCF_UART_RB 0x80
42
43 /* Interrupt flags. */
44 #define MCF_UART_TxINT 0x01
45 #define MCF_UART_RxINT 0x02
46 #define MCF_UART_DBINT 0x04
47 #define MCF_UART_COSINT 0x80
48
49 /* UMR1 flags. */
50 #define MCF_UART_BC0 0x01
51 #define MCF_UART_BC1 0x02
52 #define MCF_UART_PT 0x04
53 #define MCF_UART_PM0 0x08
54 #define MCF_UART_PM1 0x10
55 #define MCF_UART_ERR 0x20
56 #define MCF_UART_RxIRQ 0x40
57 #define MCF_UART_RxRTS 0x80
58
59 static void mcf_uart_update(mcf_uart_state *s)
60 {
61 s->isr &= ~(MCF_UART_TxINT | MCF_UART_RxINT);
62 if (s->sr & MCF_UART_TxRDY)
63 s->isr |= MCF_UART_TxINT;
64 if ((s->sr & ((s->mr[0] & MCF_UART_RxIRQ)
65 ? MCF_UART_FFULL : MCF_UART_RxRDY)) != 0)
66 s->isr |= MCF_UART_RxINT;
67
68 qemu_set_irq(s->irq, (s->isr & s->imr) != 0);
69 }
70
71 uint64_t mcf_uart_read(void *opaque, hwaddr addr,
72 unsigned size)
73 {
74 mcf_uart_state *s = (mcf_uart_state *)opaque;
75 switch (addr & 0x3f) {
76 case 0x00:
77 return s->mr[s->current_mr];
78 case 0x04:
79 return s->sr;
80 case 0x0c:
81 {
82 uint8_t val;
83 int i;
84
85 if (s->fifo_len == 0)
86 return 0;
87
88 val = s->fifo[0];
89 s->fifo_len--;
90 for (i = 0; i < s->fifo_len; i++)
91 s->fifo[i] = s->fifo[i + 1];
92 s->sr &= ~MCF_UART_FFULL;
93 if (s->fifo_len == 0)
94 s->sr &= ~MCF_UART_RxRDY;
95 mcf_uart_update(s);
96 qemu_chr_fe_accept_input(&s->chr);
97 return val;
98 }
99 case 0x10:
100 /* TODO: Implement IPCR. */
101 return 0;
102 case 0x14:
103 return s->isr;
104 case 0x18:
105 return s->bg1;
106 case 0x1c:
107 return s->bg2;
108 default:
109 return 0;
110 }
111 }
112
113 /* Update TxRDY flag and set data if present and enabled. */
114 static void mcf_uart_do_tx(mcf_uart_state *s)
115 {
116 if (s->tx_enabled && (s->sr & MCF_UART_TxEMP) == 0) {
117 /* XXX this blocks entire thread. Rewrite to use
118 * qemu_chr_fe_write and background I/O callbacks */
119 qemu_chr_fe_write_all(&s->chr, (unsigned char *)&s->tb, 1);
120 s->sr |= MCF_UART_TxEMP;
121 }
122 if (s->tx_enabled) {
123 s->sr |= MCF_UART_TxRDY;
124 } else {
125 s->sr &= ~MCF_UART_TxRDY;
126 }
127 }
128
129 static void mcf_do_command(mcf_uart_state *s, uint8_t cmd)
130 {
131 /* Misc command. */
132 switch ((cmd >> 4) & 7) {
133 case 0: /* No-op. */
134 break;
135 case 1: /* Reset mode register pointer. */
136 s->current_mr = 0;
137 break;
138 case 2: /* Reset receiver. */
139 s->rx_enabled = 0;
140 s->fifo_len = 0;
141 s->sr &= ~(MCF_UART_RxRDY | MCF_UART_FFULL);
142 break;
143 case 3: /* Reset transmitter. */
144 s->tx_enabled = 0;
145 s->sr |= MCF_UART_TxEMP;
146 s->sr &= ~MCF_UART_TxRDY;
147 break;
148 case 4: /* Reset error status. */
149 break;
150 case 5: /* Reset break-change interrupt. */
151 s->isr &= ~MCF_UART_DBINT;
152 break;
153 case 6: /* Start break. */
154 case 7: /* Stop break. */
155 break;
156 }
157
158 /* Transmitter command. */
159 switch ((cmd >> 2) & 3) {
160 case 0: /* No-op. */
161 break;
162 case 1: /* Enable. */
163 s->tx_enabled = 1;
164 mcf_uart_do_tx(s);
165 break;
166 case 2: /* Disable. */
167 s->tx_enabled = 0;
168 mcf_uart_do_tx(s);
169 break;
170 case 3: /* Reserved. */
171 fprintf(stderr, "mcf_uart: Bad TX command\n");
172 break;
173 }
174
175 /* Receiver command. */
176 switch (cmd & 3) {
177 case 0: /* No-op. */
178 break;
179 case 1: /* Enable. */
180 s->rx_enabled = 1;
181 break;
182 case 2:
183 s->rx_enabled = 0;
184 break;
185 case 3: /* Reserved. */
186 fprintf(stderr, "mcf_uart: Bad RX command\n");
187 break;
188 }
189 }
190
191 void mcf_uart_write(void *opaque, hwaddr addr,
192 uint64_t val, unsigned size)
193 {
194 mcf_uart_state *s = (mcf_uart_state *)opaque;
195 switch (addr & 0x3f) {
196 case 0x00:
197 s->mr[s->current_mr] = val;
198 s->current_mr = 1;
199 break;
200 case 0x04:
201 /* CSR is ignored. */
202 break;
203 case 0x08: /* Command Register. */
204 mcf_do_command(s, val);
205 break;
206 case 0x0c: /* Transmit Buffer. */
207 s->sr &= ~MCF_UART_TxEMP;
208 s->tb = val;
209 mcf_uart_do_tx(s);
210 break;
211 case 0x10:
212 /* ACR is ignored. */
213 break;
214 case 0x14:
215 s->imr = val;
216 break;
217 default:
218 break;
219 }
220 mcf_uart_update(s);
221 }
222
223 static void mcf_uart_reset(mcf_uart_state *s)
224 {
225 s->fifo_len = 0;
226 s->mr[0] = 0;
227 s->mr[1] = 0;
228 s->sr = MCF_UART_TxEMP;
229 s->tx_enabled = 0;
230 s->rx_enabled = 0;
231 s->isr = 0;
232 s->imr = 0;
233 }
234
235 static void mcf_uart_push_byte(mcf_uart_state *s, uint8_t data)
236 {
237 /* Break events overwrite the last byte if the fifo is full. */
238 if (s->fifo_len == 4)
239 s->fifo_len--;
240
241 s->fifo[s->fifo_len] = data;
242 s->fifo_len++;
243 s->sr |= MCF_UART_RxRDY;
244 if (s->fifo_len == 4)
245 s->sr |= MCF_UART_FFULL;
246
247 mcf_uart_update(s);
248 }
249
250 static void mcf_uart_event(void *opaque, int event)
251 {
252 mcf_uart_state *s = (mcf_uart_state *)opaque;
253
254 switch (event) {
255 case CHR_EVENT_BREAK:
256 s->isr |= MCF_UART_DBINT;
257 mcf_uart_push_byte(s, 0);
258 break;
259 default:
260 break;
261 }
262 }
263
264 static int mcf_uart_can_receive(void *opaque)
265 {
266 mcf_uart_state *s = (mcf_uart_state *)opaque;
267
268 return s->rx_enabled && (s->sr & MCF_UART_FFULL) == 0;
269 }
270
271 static void mcf_uart_receive(void *opaque, const uint8_t *buf, int size)
272 {
273 mcf_uart_state *s = (mcf_uart_state *)opaque;
274
275 mcf_uart_push_byte(s, buf[0]);
276 }
277
278 void *mcf_uart_init(qemu_irq irq, CharDriverState *chr)
279 {
280 mcf_uart_state *s;
281
282 s = g_malloc0(sizeof(mcf_uart_state));
283 s->irq = irq;
284 if (chr) {
285 qemu_chr_fe_init(&s->chr, chr, &error_abort);
286 qemu_chr_fe_set_handlers(&s->chr, mcf_uart_can_receive,
287 mcf_uart_receive, mcf_uart_event,
288 s, NULL, true);
289 }
290 mcf_uart_reset(s);
291 return s;
292 }
293
294 static const MemoryRegionOps mcf_uart_ops = {
295 .read = mcf_uart_read,
296 .write = mcf_uart_write,
297 .endianness = DEVICE_NATIVE_ENDIAN,
298 };
299
300 void mcf_uart_mm_init(MemoryRegion *sysmem,
301 hwaddr base,
302 qemu_irq irq,
303 CharDriverState *chr)
304 {
305 mcf_uart_state *s;
306
307 s = mcf_uart_init(irq, chr);
308 memory_region_init_io(&s->iomem, NULL, &mcf_uart_ops, s, "uart", 0x40);
309 memory_region_add_subregion(sysmem, base, &s->iomem);
310 }