Statistics
| Branch: | Revision:

root / hw / mcf_uart.c @ 5fafdf24

History | View | Annotate | Download (6.9 kB)

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