qemu

Форк
0
/
mcf_uart.c 
367 строк · 8.6 Кб
1
/*
2
 * ColdFire UART emulation.
3
 *
4
 * Copyright (c) 2007 CodeSourcery.
5
 *
6
 * This code is licensed under the GPL
7
 */
8

9
#include "qemu/osdep.h"
10
#include "hw/irq.h"
11
#include "hw/sysbus.h"
12
#include "qemu/module.h"
13
#include "qapi/error.h"
14
#include "hw/m68k/mcf.h"
15
#include "hw/qdev-properties.h"
16
#include "hw/qdev-properties-system.h"
17
#include "chardev/char-fe.h"
18
#include "qom/object.h"
19

20
struct mcf_uart_state {
21
    SysBusDevice parent_obj;
22

23
    MemoryRegion iomem;
24
    uint8_t mr[2];
25
    uint8_t sr;
26
    uint8_t isr;
27
    uint8_t imr;
28
    uint8_t bg1;
29
    uint8_t bg2;
30
    uint8_t fifo[4];
31
    uint8_t tb;
32
    int current_mr;
33
    int fifo_len;
34
    int tx_enabled;
35
    int rx_enabled;
36
    qemu_irq irq;
37
    CharBackend chr;
38
};
39

40
#define TYPE_MCF_UART "mcf-uart"
41
OBJECT_DECLARE_SIMPLE_TYPE(mcf_uart_state, MCF_UART)
42

43
/* UART Status Register bits.  */
44
#define MCF_UART_RxRDY  0x01
45
#define MCF_UART_FFULL  0x02
46
#define MCF_UART_TxRDY  0x04
47
#define MCF_UART_TxEMP  0x08
48
#define MCF_UART_OE     0x10
49
#define MCF_UART_PE     0x20
50
#define MCF_UART_FE     0x40
51
#define MCF_UART_RB     0x80
52

53
/* Interrupt flags.  */
54
#define MCF_UART_TxINT  0x01
55
#define MCF_UART_RxINT  0x02
56
#define MCF_UART_DBINT  0x04
57
#define MCF_UART_COSINT 0x80
58

59
/* UMR1 flags.  */
60
#define MCF_UART_BC0    0x01
61
#define MCF_UART_BC1    0x02
62
#define MCF_UART_PT     0x04
63
#define MCF_UART_PM0    0x08
64
#define MCF_UART_PM1    0x10
65
#define MCF_UART_ERR    0x20
66
#define MCF_UART_RxIRQ  0x40
67
#define MCF_UART_RxRTS  0x80
68

69
static void mcf_uart_update(mcf_uart_state *s)
70
{
71
    s->isr &= ~(MCF_UART_TxINT | MCF_UART_RxINT);
72
    if (s->sr & MCF_UART_TxRDY)
73
        s->isr |= MCF_UART_TxINT;
74
    if ((s->sr & ((s->mr[0] & MCF_UART_RxIRQ)
75
                  ? MCF_UART_FFULL : MCF_UART_RxRDY)) != 0)
76
        s->isr |= MCF_UART_RxINT;
77

78
    qemu_set_irq(s->irq, (s->isr & s->imr) != 0);
79
}
80

81
uint64_t mcf_uart_read(void *opaque, hwaddr addr,
82
                       unsigned size)
83
{
84
    mcf_uart_state *s = (mcf_uart_state *)opaque;
85
    switch (addr & 0x3f) {
86
    case 0x00:
87
        return s->mr[s->current_mr];
88
    case 0x04:
89
        return s->sr;
90
    case 0x0c:
91
        {
92
            uint8_t val;
93
            int i;
94

95
            if (s->fifo_len == 0)
96
                return 0;
97

98
            val = s->fifo[0];
99
            s->fifo_len--;
100
            for (i = 0; i < s->fifo_len; i++)
101
                s->fifo[i] = s->fifo[i + 1];
102
            s->sr &= ~MCF_UART_FFULL;
103
            if (s->fifo_len == 0)
104
                s->sr &= ~MCF_UART_RxRDY;
105
            mcf_uart_update(s);
106
            qemu_chr_fe_accept_input(&s->chr);
107
            return val;
108
        }
109
    case 0x10:
110
        /* TODO: Implement IPCR.  */
111
        return 0;
112
    case 0x14:
113
        return s->isr;
114
    case 0x18:
115
        return s->bg1;
116
    case 0x1c:
117
        return s->bg2;
118
    default:
119
        return 0;
120
    }
121
}
122

123
/* Update TxRDY flag and set data if present and enabled.  */
124
static void mcf_uart_do_tx(mcf_uart_state *s)
125
{
126
    if (s->tx_enabled && (s->sr & MCF_UART_TxEMP) == 0) {
127
        /* XXX this blocks entire thread. Rewrite to use
128
         * qemu_chr_fe_write and background I/O callbacks */
129
        qemu_chr_fe_write_all(&s->chr, (unsigned char *)&s->tb, 1);
130
        s->sr |= MCF_UART_TxEMP;
131
    }
132
    if (s->tx_enabled) {
133
        s->sr |= MCF_UART_TxRDY;
134
    } else {
135
        s->sr &= ~MCF_UART_TxRDY;
136
    }
137
}
138

139
static void mcf_do_command(mcf_uart_state *s, uint8_t cmd)
140
{
141
    /* Misc command.  */
142
    switch ((cmd >> 4) & 7) {
143
    case 0: /* No-op.  */
144
        break;
145
    case 1: /* Reset mode register pointer.  */
146
        s->current_mr = 0;
147
        break;
148
    case 2: /* Reset receiver.  */
149
        s->rx_enabled = 0;
150
        s->fifo_len = 0;
151
        s->sr &= ~(MCF_UART_RxRDY | MCF_UART_FFULL);
152
        break;
153
    case 3: /* Reset transmitter.  */
154
        s->tx_enabled = 0;
155
        s->sr |= MCF_UART_TxEMP;
156
        s->sr &= ~MCF_UART_TxRDY;
157
        break;
158
    case 4: /* Reset error status.  */
159
        break;
160
    case 5: /* Reset break-change interrupt.  */
161
        s->isr &= ~MCF_UART_DBINT;
162
        break;
163
    case 6: /* Start break.  */
164
    case 7: /* Stop break.  */
165
        break;
166
    }
167

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

185
    /* Receiver command.  */
186
    switch (cmd & 3) {
187
    case 0: /* No-op.  */
188
        break;
189
    case 1: /* Enable.  */
190
        s->rx_enabled = 1;
191
        break;
192
    case 2:
193
        s->rx_enabled = 0;
194
        break;
195
    case 3: /* Reserved.  */
196
        fprintf(stderr, "mcf_uart: Bad RX command\n");
197
        break;
198
    }
199
}
200

201
void mcf_uart_write(void *opaque, hwaddr addr,
202
                    uint64_t val, unsigned size)
203
{
204
    mcf_uart_state *s = (mcf_uart_state *)opaque;
205
    switch (addr & 0x3f) {
206
    case 0x00:
207
        s->mr[s->current_mr] = val;
208
        s->current_mr = 1;
209
        break;
210
    case 0x04:
211
        /* CSR is ignored.  */
212
        break;
213
    case 0x08: /* Command Register.  */
214
        mcf_do_command(s, val);
215
        break;
216
    case 0x0c: /* Transmit Buffer.  */
217
        s->sr &= ~MCF_UART_TxEMP;
218
        s->tb = val;
219
        mcf_uart_do_tx(s);
220
        break;
221
    case 0x10:
222
        /* ACR is ignored.  */
223
        break;
224
    case 0x14:
225
        s->imr = val;
226
        break;
227
    default:
228
        break;
229
    }
230
    mcf_uart_update(s);
231
}
232

233
static void mcf_uart_reset(DeviceState *dev)
234
{
235
    mcf_uart_state *s = MCF_UART(dev);
236

237
    s->fifo_len = 0;
238
    s->mr[0] = 0;
239
    s->mr[1] = 0;
240
    s->sr = MCF_UART_TxEMP;
241
    s->tx_enabled = 0;
242
    s->rx_enabled = 0;
243
    s->isr = 0;
244
    s->imr = 0;
245
}
246

247
static void mcf_uart_push_byte(mcf_uart_state *s, uint8_t data)
248
{
249
    /* Break events overwrite the last byte if the fifo is full.  */
250
    if (s->fifo_len == 4)
251
        s->fifo_len--;
252

253
    s->fifo[s->fifo_len] = data;
254
    s->fifo_len++;
255
    s->sr |= MCF_UART_RxRDY;
256
    if (s->fifo_len == 4)
257
        s->sr |= MCF_UART_FFULL;
258

259
    mcf_uart_update(s);
260
}
261

262
static void mcf_uart_event(void *opaque, QEMUChrEvent event)
263
{
264
    mcf_uart_state *s = (mcf_uart_state *)opaque;
265

266
    switch (event) {
267
    case CHR_EVENT_BREAK:
268
        s->isr |= MCF_UART_DBINT;
269
        mcf_uart_push_byte(s, 0);
270
        break;
271
    default:
272
        break;
273
    }
274
}
275

276
static int mcf_uart_can_receive(void *opaque)
277
{
278
    mcf_uart_state *s = (mcf_uart_state *)opaque;
279

280
    return s->rx_enabled && (s->sr & MCF_UART_FFULL) == 0;
281
}
282

283
static void mcf_uart_receive(void *opaque, const uint8_t *buf, int size)
284
{
285
    mcf_uart_state *s = (mcf_uart_state *)opaque;
286

287
    mcf_uart_push_byte(s, buf[0]);
288
}
289

290
static const MemoryRegionOps mcf_uart_ops = {
291
    .read = mcf_uart_read,
292
    .write = mcf_uart_write,
293
    .endianness = DEVICE_NATIVE_ENDIAN,
294
};
295

296
static void mcf_uart_instance_init(Object *obj)
297
{
298
    SysBusDevice *dev = SYS_BUS_DEVICE(obj);
299
    mcf_uart_state *s = MCF_UART(dev);
300

301
    memory_region_init_io(&s->iomem, obj, &mcf_uart_ops, s, "uart", 0x40);
302
    sysbus_init_mmio(dev, &s->iomem);
303

304
    sysbus_init_irq(dev, &s->irq);
305
}
306

307
static void mcf_uart_realize(DeviceState *dev, Error **errp)
308
{
309
    mcf_uart_state *s = MCF_UART(dev);
310

311
    qemu_chr_fe_set_handlers(&s->chr, mcf_uart_can_receive, mcf_uart_receive,
312
                             mcf_uart_event, NULL, s, NULL, true);
313
}
314

315
static Property mcf_uart_properties[] = {
316
    DEFINE_PROP_CHR("chardev", mcf_uart_state, chr),
317
    DEFINE_PROP_END_OF_LIST(),
318
};
319

320
static void mcf_uart_class_init(ObjectClass *oc, void *data)
321
{
322
    DeviceClass *dc = DEVICE_CLASS(oc);
323

324
    dc->realize = mcf_uart_realize;
325
    dc->reset = mcf_uart_reset;
326
    device_class_set_props(dc, mcf_uart_properties);
327
    set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
328
}
329

330
static const TypeInfo mcf_uart_info = {
331
    .name          = TYPE_MCF_UART,
332
    .parent        = TYPE_SYS_BUS_DEVICE,
333
    .instance_size = sizeof(mcf_uart_state),
334
    .instance_init = mcf_uart_instance_init,
335
    .class_init    = mcf_uart_class_init,
336
};
337

338
static void mcf_uart_register(void)
339
{
340
    type_register_static(&mcf_uart_info);
341
}
342

343
type_init(mcf_uart_register)
344

345
DeviceState *mcf_uart_create(qemu_irq irq, Chardev *chrdrv)
346
{
347
    DeviceState *dev;
348

349
    dev = qdev_new(TYPE_MCF_UART);
350
    if (chrdrv) {
351
        qdev_prop_set_chr(dev, "chardev", chrdrv);
352
    }
353
    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
354
    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);
355

356
    return dev;
357
}
358

359
DeviceState *mcf_uart_create_mmap(hwaddr base, qemu_irq irq, Chardev *chrdrv)
360
{
361
    DeviceState *dev;
362

363
    dev = mcf_uart_create(irq, chrdrv);
364
    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
365

366
    return dev;
367
}
368

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.