Statistics
| Branch: | Revision:

root / hw / mcf_uart.c @ 20dcee94

History | View | Annotate | Download (6.9 kB)

1
/* 
2
 * ColdFire UART emulation.
3
 *
4
 * Copyright (c) 2007 CodeSourcery.
5
 *
6
 * This code is licenced under the GPL
7
 */
8
#include "vl.h"
9

    
10
typedef struct {
11
    uint8_t mr[2];
12
    uint8_t sr;
13
    uint8_t isr;
14
    uint8_t imr;
15
    uint8_t bg1;
16
    uint8_t bg2;
17
    uint8_t fifo[4];
18
    uint8_t tb;
19
    int current_mr;
20
    int fifo_len;
21
    int tx_enabled;
22
    int rx_enabled;
23
    qemu_irq irq;
24
    CharDriverState *chr;
25
} mcf_uart_state;
26

    
27
/* UART Status Register bits.  */
28
#define MCF_UART_RxRDY  0x01
29
#define MCF_UART_FFULL  0x02
30
#define MCF_UART_TxRDY  0x04
31
#define MCF_UART_TxEMP  0x08
32
#define MCF_UART_OE     0x10
33
#define MCF_UART_PE     0x20
34
#define MCF_UART_FE     0x40
35
#define MCF_UART_RB     0x80
36

    
37
/* Interrupt flags.  */
38
#define MCF_UART_TxINT  0x01
39
#define MCF_UART_RxINT  0x02
40
#define MCF_UART_DBINT  0x04
41
#define MCF_UART_COSINT 0x80
42

    
43
/* UMR1 flags.  */
44
#define MCF_UART_BC0    0x01
45
#define MCF_UART_BC1    0x02
46
#define MCF_UART_PT     0x04
47
#define MCF_UART_PM0    0x08
48
#define MCF_UART_PM1    0x10
49
#define MCF_UART_ERR    0x20
50
#define MCF_UART_RxIRQ  0x40
51
#define MCF_UART_RxRTS  0x80
52

    
53
static void mcf_uart_update(mcf_uart_state *s)
54
{
55
    s->isr &= ~(MCF_UART_TxINT | MCF_UART_RxINT);
56
    if (s->sr & MCF_UART_TxRDY)
57
        s->isr |= MCF_UART_TxINT;
58
    if ((s->sr & ((s->mr[0] & MCF_UART_RxIRQ)
59
                  ? MCF_UART_FFULL : MCF_UART_RxRDY)) != 0)
60
        s->isr |= MCF_UART_RxINT;
61

    
62
    qemu_set_irq(s->irq, (s->isr & s->imr) != 0);
63
}
64

    
65
uint32_t mcf_uart_read(void *opaque, target_phys_addr_t addr)
66
{
67
    mcf_uart_state *s = (mcf_uart_state *)opaque;
68
    switch (addr & 0x3f) {
69
    case 0x00:
70
        return s->mr[s->current_mr];
71
    case 0x04:
72
        return s->sr;
73
    case 0x0c:
74
        {
75
            uint8_t val;
76
            int i;
77

    
78
            if (s->fifo_len == 0)
79
                return 0;
80

    
81
            val = s->fifo[0];
82
            s->fifo_len--;
83
            for (i = 0; i < s->fifo_len; i++)
84
                s->fifo[i] = s->fifo[i + 1];
85
            s->sr &= ~MCF_UART_FFULL;
86
            if (s->fifo_len == 0)
87
                s->sr &= ~MCF_UART_RxRDY;
88
            mcf_uart_update(s);
89
            return val;
90
        }
91
    case 0x10:
92
        /* TODO: Implement IPCR.  */
93
        return 0;
94
    case 0x14:
95
        return s->isr;
96
    case 0x18:
97
        return s->bg1;
98
    case 0x1c:
99
        return s->bg2;
100
    default:
101
        return 0;
102
    }
103
}
104

    
105
/* Update TxRDY flag and set data if present and enabled.  */
106
static void mcf_uart_do_tx(mcf_uart_state *s)
107
{
108
    if (s->tx_enabled && (s->sr & MCF_UART_TxEMP) == 0) {
109
        if (s->chr)
110
            qemu_chr_write(s->chr, (unsigned char *)&s->tb, 1);
111
        s->sr |= MCF_UART_TxEMP;
112
    }
113
    if (s->tx_enabled) {
114
        s->sr |= MCF_UART_TxRDY;
115
    } else {
116
        s->sr &= ~MCF_UART_TxRDY;
117
    }
118
}
119

    
120
static void mcf_do_command(mcf_uart_state *s, uint8_t cmd)
121
{
122
    /* Misc command.  */
123
    switch ((cmd >> 4) & 3) {
124
    case 0: /* No-op.  */
125
        break;
126
    case 1: /* Reset mode register pointer.  */
127
        s->current_mr = 0;
128
        break;
129
    case 2: /* Reset receiver.  */
130
        s->rx_enabled = 0;
131
        s->fifo_len = 0;
132
        s->sr &= ~(MCF_UART_RxRDY | MCF_UART_FFULL);
133
        break;
134
    case 3: /* Reset transmitter.  */
135
        s->tx_enabled = 0;
136
        s->sr |= MCF_UART_TxEMP;
137
        s->sr &= ~MCF_UART_TxRDY;
138
        break;
139
    case 4: /* Reset error status.  */
140
        break;
141
    case 5: /* Reset break-change interrupt.  */
142
        s->isr &= ~MCF_UART_DBINT;
143
        break;
144
    case 6: /* Start break.  */
145
    case 7: /* Stop break.  */
146
        break;
147
    }
148

    
149
    /* Transmitter command.  */
150
    switch ((cmd >> 2) & 3) {
151
    case 0: /* No-op.  */
152
        break;
153
    case 1: /* Enable.  */
154
        s->tx_enabled = 1;
155
        mcf_uart_do_tx(s);
156
        break;
157
    case 2: /* Disable.  */
158
        s->tx_enabled = 0;
159
        mcf_uart_do_tx(s);
160
        break;
161
    case 3: /* Reserved.  */
162
        fprintf(stderr, "mcf_uart: Bad TX command\n");
163
        break;
164
    }
165

    
166
    /* Receiver command.  */
167
    switch (cmd & 3) {
168
    case 0: /* No-op.  */
169
        break;
170
    case 1: /* Enable.  */
171
        s->rx_enabled = 1;
172
        break;
173
    case 2:
174
        s->rx_enabled = 0;
175
        break;
176
    case 3: /* Reserved.  */
177
        fprintf(stderr, "mcf_uart: Bad RX command\n");
178
        break;
179
    }
180
}
181

    
182
void mcf_uart_write(void *opaque, target_phys_addr_t addr, uint32_t val)
183
{
184
    mcf_uart_state *s = (mcf_uart_state *)opaque;
185
    switch (addr & 0x3f) {
186
    case 0x00:
187
        s->mr[s->current_mr] = val;
188
        s->current_mr = 1;
189
        break;
190
    case 0x04:
191
        /* CSR is ignored.  */
192
        break;
193
    case 0x08: /* Command Register.  */
194
        mcf_do_command(s, val);
195
        break;
196
    case 0x0c: /* Transmit Buffer.  */
197
        s->sr &= ~MCF_UART_TxEMP;
198
        s->tb = val;
199
        mcf_uart_do_tx(s);
200
        break;
201
    case 0x10:
202
        /* ACR is ignored.  */
203
        break;
204
    case 0x14:
205
        s->imr = val;
206
        break;
207
    default:
208
        break;
209
    }
210
    mcf_uart_update(s);
211
}
212

    
213
static void mcf_uart_reset(mcf_uart_state *s)
214
{
215
    s->fifo_len = 0;
216
    s->mr[0] = 0;
217
    s->mr[1] = 0;
218
    s->sr = MCF_UART_TxEMP;
219
    s->tx_enabled = 0;
220
    s->rx_enabled = 0;
221
    s->isr = 0;
222
    s->imr = 0;
223
}
224

    
225
static void mcf_uart_push_byte(mcf_uart_state *s, uint8_t data)
226
{
227
    /* Break events overwrite the last byte if the fifo is full.  */
228
    if (s->fifo_len == 4)
229
        s->fifo_len--;
230

    
231
    s->fifo[s->fifo_len] = data;
232
    s->fifo_len++;
233
    s->sr |= MCF_UART_RxRDY;
234
    if (s->fifo_len == 4)
235
        s->sr |= MCF_UART_FFULL;
236

    
237
    mcf_uart_update(s);
238
}
239

    
240
static void mcf_uart_event(void *opaque, int event)
241
{
242
    mcf_uart_state *s = (mcf_uart_state *)opaque;
243

    
244
    switch (event) {
245
    case CHR_EVENT_BREAK:
246
        s->isr |= MCF_UART_DBINT;
247
        mcf_uart_push_byte(s, 0);
248
        break;
249
    default:
250
        break;
251
    }
252
}
253

    
254
static int mcf_uart_can_receive(void *opaque)
255
{
256
    mcf_uart_state *s = (mcf_uart_state *)opaque;
257

    
258
    return s->rx_enabled && (s->sr & MCF_UART_FFULL) == 0;
259
}
260

    
261
static void mcf_uart_receive(void *opaque, const uint8_t *buf, int size)
262
{
263
    mcf_uart_state *s = (mcf_uart_state *)opaque;
264

    
265
    mcf_uart_push_byte(s, buf[0]);
266
}
267

    
268
void *mcf_uart_init(qemu_irq irq, CharDriverState *chr)
269
{
270
    mcf_uart_state *s;
271

    
272
    s = qemu_mallocz(sizeof(mcf_uart_state));
273
    s->chr = chr;
274
    s->irq = irq;
275
    if (chr) {
276
        qemu_chr_add_handlers(chr, mcf_uart_can_receive, mcf_uart_receive,
277
                              mcf_uart_event, s);
278
    }
279
    mcf_uart_reset(s);
280
    return s;
281
}
282

    
283

    
284
static CPUReadMemoryFunc *mcf_uart_readfn[] = {
285
   mcf_uart_read,
286
   mcf_uart_read,
287
   mcf_uart_read
288
};
289

    
290
static CPUWriteMemoryFunc *mcf_uart_writefn[] = {
291
   mcf_uart_write,
292
   mcf_uart_write,
293
   mcf_uart_write
294
};
295

    
296
void mcf_uart_mm_init(target_phys_addr_t base, qemu_irq irq,
297
                      CharDriverState *chr)
298
{
299
    mcf_uart_state *s;
300
    int iomemtype;
301

    
302
    s = mcf_uart_init(irq, chr);
303
    iomemtype = cpu_register_io_memory(0, mcf_uart_readfn,
304
                                       mcf_uart_writefn, s);
305
    cpu_register_physical_memory(base, 0x40, iomemtype);
306
}