Break up vl.h.
[qemu/mini2440.git] / hw / mcf_uart.c
blob01973a02fd58023d3af5aad9f05d456f4c4b2a0f
1 /*
2 * ColdFire UART emulation.
4 * Copyright (c) 2007 CodeSourcery.
6 * This code is licenced under the GPL
7 */
8 #include "hw.h"
9 #include "mcf.h"
10 #include "qemu-char.h"
12 typedef struct {
13 uint8_t mr[2];
14 uint8_t sr;
15 uint8_t isr;
16 uint8_t imr;
17 uint8_t bg1;
18 uint8_t bg2;
19 uint8_t fifo[4];
20 uint8_t tb;
21 int current_mr;
22 int fifo_len;
23 int tx_enabled;
24 int rx_enabled;
25 qemu_irq irq;
26 CharDriverState *chr;
27 } mcf_uart_state;
29 /* UART Status Register bits. */
30 #define MCF_UART_RxRDY 0x01
31 #define MCF_UART_FFULL 0x02
32 #define MCF_UART_TxRDY 0x04
33 #define MCF_UART_TxEMP 0x08
34 #define MCF_UART_OE 0x10
35 #define MCF_UART_PE 0x20
36 #define MCF_UART_FE 0x40
37 #define MCF_UART_RB 0x80
39 /* Interrupt flags. */
40 #define MCF_UART_TxINT 0x01
41 #define MCF_UART_RxINT 0x02
42 #define MCF_UART_DBINT 0x04
43 #define MCF_UART_COSINT 0x80
45 /* UMR1 flags. */
46 #define MCF_UART_BC0 0x01
47 #define MCF_UART_BC1 0x02
48 #define MCF_UART_PT 0x04
49 #define MCF_UART_PM0 0x08
50 #define MCF_UART_PM1 0x10
51 #define MCF_UART_ERR 0x20
52 #define MCF_UART_RxIRQ 0x40
53 #define MCF_UART_RxRTS 0x80
55 static void mcf_uart_update(mcf_uart_state *s)
57 s->isr &= ~(MCF_UART_TxINT | MCF_UART_RxINT);
58 if (s->sr & MCF_UART_TxRDY)
59 s->isr |= MCF_UART_TxINT;
60 if ((s->sr & ((s->mr[0] & MCF_UART_RxIRQ)
61 ? MCF_UART_FFULL : MCF_UART_RxRDY)) != 0)
62 s->isr |= MCF_UART_RxINT;
64 qemu_set_irq(s->irq, (s->isr & s->imr) != 0);
67 uint32_t mcf_uart_read(void *opaque, target_phys_addr_t addr)
69 mcf_uart_state *s = (mcf_uart_state *)opaque;
70 switch (addr & 0x3f) {
71 case 0x00:
72 return s->mr[s->current_mr];
73 case 0x04:
74 return s->sr;
75 case 0x0c:
77 uint8_t val;
78 int i;
80 if (s->fifo_len == 0)
81 return 0;
83 val = s->fifo[0];
84 s->fifo_len--;
85 for (i = 0; i < s->fifo_len; i++)
86 s->fifo[i] = s->fifo[i + 1];
87 s->sr &= ~MCF_UART_FFULL;
88 if (s->fifo_len == 0)
89 s->sr &= ~MCF_UART_RxRDY;
90 mcf_uart_update(s);
91 return val;
93 case 0x10:
94 /* TODO: Implement IPCR. */
95 return 0;
96 case 0x14:
97 return s->isr;
98 case 0x18:
99 return s->bg1;
100 case 0x1c:
101 return s->bg2;
102 default:
103 return 0;
107 /* Update TxRDY flag and set data if present and enabled. */
108 static void mcf_uart_do_tx(mcf_uart_state *s)
110 if (s->tx_enabled && (s->sr & MCF_UART_TxEMP) == 0) {
111 if (s->chr)
112 qemu_chr_write(s->chr, (unsigned char *)&s->tb, 1);
113 s->sr |= MCF_UART_TxEMP;
115 if (s->tx_enabled) {
116 s->sr |= MCF_UART_TxRDY;
117 } else {
118 s->sr &= ~MCF_UART_TxRDY;
122 static void mcf_do_command(mcf_uart_state *s, uint8_t cmd)
124 /* Misc command. */
125 switch ((cmd >> 4) & 3) {
126 case 0: /* No-op. */
127 break;
128 case 1: /* Reset mode register pointer. */
129 s->current_mr = 0;
130 break;
131 case 2: /* Reset receiver. */
132 s->rx_enabled = 0;
133 s->fifo_len = 0;
134 s->sr &= ~(MCF_UART_RxRDY | MCF_UART_FFULL);
135 break;
136 case 3: /* Reset transmitter. */
137 s->tx_enabled = 0;
138 s->sr |= MCF_UART_TxEMP;
139 s->sr &= ~MCF_UART_TxRDY;
140 break;
141 case 4: /* Reset error status. */
142 break;
143 case 5: /* Reset break-change interrupt. */
144 s->isr &= ~MCF_UART_DBINT;
145 break;
146 case 6: /* Start break. */
147 case 7: /* Stop break. */
148 break;
151 /* Transmitter command. */
152 switch ((cmd >> 2) & 3) {
153 case 0: /* No-op. */
154 break;
155 case 1: /* Enable. */
156 s->tx_enabled = 1;
157 mcf_uart_do_tx(s);
158 break;
159 case 2: /* Disable. */
160 s->tx_enabled = 0;
161 mcf_uart_do_tx(s);
162 break;
163 case 3: /* Reserved. */
164 fprintf(stderr, "mcf_uart: Bad TX command\n");
165 break;
168 /* Receiver command. */
169 switch (cmd & 3) {
170 case 0: /* No-op. */
171 break;
172 case 1: /* Enable. */
173 s->rx_enabled = 1;
174 break;
175 case 2:
176 s->rx_enabled = 0;
177 break;
178 case 3: /* Reserved. */
179 fprintf(stderr, "mcf_uart: Bad RX command\n");
180 break;
184 void mcf_uart_write(void *opaque, target_phys_addr_t addr, uint32_t val)
186 mcf_uart_state *s = (mcf_uart_state *)opaque;
187 switch (addr & 0x3f) {
188 case 0x00:
189 s->mr[s->current_mr] = val;
190 s->current_mr = 1;
191 break;
192 case 0x04:
193 /* CSR is ignored. */
194 break;
195 case 0x08: /* Command Register. */
196 mcf_do_command(s, val);
197 break;
198 case 0x0c: /* Transmit Buffer. */
199 s->sr &= ~MCF_UART_TxEMP;
200 s->tb = val;
201 mcf_uart_do_tx(s);
202 break;
203 case 0x10:
204 /* ACR is ignored. */
205 break;
206 case 0x14:
207 s->imr = val;
208 break;
209 default:
210 break;
212 mcf_uart_update(s);
215 static void mcf_uart_reset(mcf_uart_state *s)
217 s->fifo_len = 0;
218 s->mr[0] = 0;
219 s->mr[1] = 0;
220 s->sr = MCF_UART_TxEMP;
221 s->tx_enabled = 0;
222 s->rx_enabled = 0;
223 s->isr = 0;
224 s->imr = 0;
227 static void mcf_uart_push_byte(mcf_uart_state *s, uint8_t data)
229 /* Break events overwrite the last byte if the fifo is full. */
230 if (s->fifo_len == 4)
231 s->fifo_len--;
233 s->fifo[s->fifo_len] = data;
234 s->fifo_len++;
235 s->sr |= MCF_UART_RxRDY;
236 if (s->fifo_len == 4)
237 s->sr |= MCF_UART_FFULL;
239 mcf_uart_update(s);
242 static void mcf_uart_event(void *opaque, int event)
244 mcf_uart_state *s = (mcf_uart_state *)opaque;
246 switch (event) {
247 case CHR_EVENT_BREAK:
248 s->isr |= MCF_UART_DBINT;
249 mcf_uart_push_byte(s, 0);
250 break;
251 default:
252 break;
256 static int mcf_uart_can_receive(void *opaque)
258 mcf_uart_state *s = (mcf_uart_state *)opaque;
260 return s->rx_enabled && (s->sr & MCF_UART_FFULL) == 0;
263 static void mcf_uart_receive(void *opaque, const uint8_t *buf, int size)
265 mcf_uart_state *s = (mcf_uart_state *)opaque;
267 mcf_uart_push_byte(s, buf[0]);
270 void *mcf_uart_init(qemu_irq irq, CharDriverState *chr)
272 mcf_uart_state *s;
274 s = qemu_mallocz(sizeof(mcf_uart_state));
275 s->chr = chr;
276 s->irq = irq;
277 if (chr) {
278 qemu_chr_add_handlers(chr, mcf_uart_can_receive, mcf_uart_receive,
279 mcf_uart_event, s);
281 mcf_uart_reset(s);
282 return s;
286 static CPUReadMemoryFunc *mcf_uart_readfn[] = {
287 mcf_uart_read,
288 mcf_uart_read,
289 mcf_uart_read
292 static CPUWriteMemoryFunc *mcf_uart_writefn[] = {
293 mcf_uart_write,
294 mcf_uart_write,
295 mcf_uart_write
298 void mcf_uart_mm_init(target_phys_addr_t base, qemu_irq irq,
299 CharDriverState *chr)
301 mcf_uart_state *s;
302 int iomemtype;
304 s = mcf_uart_init(irq, chr);
305 iomemtype = cpu_register_io_memory(0, mcf_uart_readfn,
306 mcf_uart_writefn, s);
307 cpu_register_physical_memory(base, 0x40, iomemtype);