Statistics
| Branch: | Revision:

root / hw / char / mcf_uart.c @ dccfcd0e

History | View | Annotate | Download (7.1 kB)

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