Statistics
| Branch: | Revision:

root / hw / mcf_uart.c @ 8af7a3ab

History | View | Annotate | Download (7 kB)

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

    
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;
28

    
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
38

    
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
44

    
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
54

    
55
static void mcf_uart_update(mcf_uart_state *s)
56
{
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;
63

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

    
67
uint32_t mcf_uart_read(void *opaque, target_phys_addr_t addr)
68
{
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:
76
        {
77
            uint8_t val;
78
            int i;
79

    
80
            if (s->fifo_len == 0)
81
                return 0;
82

    
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
            qemu_chr_accept_input(s->chr);
92
            return val;
93
        }
94
    case 0x10:
95
        /* TODO: Implement IPCR.  */
96
        return 0;
97
    case 0x14:
98
        return s->isr;
99
    case 0x18:
100
        return s->bg1;
101
    case 0x1c:
102
        return s->bg2;
103
    default:
104
        return 0;
105
    }
106
}
107

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

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

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

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

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

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

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

    
234
    s->fifo[s->fifo_len] = data;
235
    s->fifo_len++;
236
    s->sr |= MCF_UART_RxRDY;
237
    if (s->fifo_len == 4)
238
        s->sr |= MCF_UART_FFULL;
239

    
240
    mcf_uart_update(s);
241
}
242

    
243
static void mcf_uart_event(void *opaque, int event)
244
{
245
    mcf_uart_state *s = (mcf_uart_state *)opaque;
246

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

    
257
static int mcf_uart_can_receive(void *opaque)
258
{
259
    mcf_uart_state *s = (mcf_uart_state *)opaque;
260

    
261
    return s->rx_enabled && (s->sr & MCF_UART_FFULL) == 0;
262
}
263

    
264
static void mcf_uart_receive(void *opaque, const uint8_t *buf, int size)
265
{
266
    mcf_uart_state *s = (mcf_uart_state *)opaque;
267

    
268
    mcf_uart_push_byte(s, buf[0]);
269
}
270

    
271
void *mcf_uart_init(qemu_irq irq, CharDriverState *chr)
272
{
273
    mcf_uart_state *s;
274

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

    
286

    
287
static CPUReadMemoryFunc * const mcf_uart_readfn[] = {
288
   mcf_uart_read,
289
   mcf_uart_read,
290
   mcf_uart_read
291
};
292

    
293
static CPUWriteMemoryFunc * const mcf_uart_writefn[] = {
294
   mcf_uart_write,
295
   mcf_uart_write,
296
   mcf_uart_write
297
};
298

    
299
void mcf_uart_mm_init(target_phys_addr_t base, qemu_irq irq,
300
                      CharDriverState *chr)
301
{
302
    mcf_uart_state *s;
303
    int iomemtype;
304

    
305
    s = mcf_uart_init(irq, chr);
306
    iomemtype = cpu_register_io_memory(mcf_uart_readfn,
307
                                       mcf_uart_writefn, s);
308
    cpu_register_physical_memory(base, 0x40, iomemtype);
309
}