Statistics
| Branch: | Revision:

root / hw / mcf_uart.c @ 8af7a3ab

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