Statistics
| Branch: | Revision:

root / hw / char / etraxfs_ser.c @ f53f81e0

History | View | Annotate | Download (6.5 kB)

1
/*
2
 * QEMU ETRAX System Emulator
3
 *
4
 * Copyright (c) 2007 Edgar E. Iglesias, Axis Communications AB.
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7
 * of this software and associated documentation files (the "Software"), to deal
8
 * in the Software without restriction, including without limitation the rights
9
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
 * copies of the Software, and to permit persons to whom the Software is
11
 * furnished to do so, subject to the following conditions:
12
 *
13
 * The above copyright notice and this permission notice shall be included in
14
 * all copies or substantial portions of the Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
 * THE SOFTWARE.
23
 */
24

    
25
#include "hw/sysbus.h"
26
#include "sysemu/char.h"
27
#include "qemu/log.h"
28

    
29
#define D(x)
30

    
31
#define RW_TR_CTRL     (0x00 / 4)
32
#define RW_TR_DMA_EN   (0x04 / 4)
33
#define RW_REC_CTRL    (0x08 / 4)
34
#define RW_DOUT        (0x1c / 4)
35
#define RS_STAT_DIN    (0x20 / 4)
36
#define R_STAT_DIN     (0x24 / 4)
37
#define RW_INTR_MASK   (0x2c / 4)
38
#define RW_ACK_INTR    (0x30 / 4)
39
#define R_INTR         (0x34 / 4)
40
#define R_MASKED_INTR  (0x38 / 4)
41
#define R_MAX          (0x3c / 4)
42

    
43
#define STAT_DAV     16
44
#define STAT_TR_IDLE 22
45
#define STAT_TR_RDY  24
46

    
47
#define TYPE_ETRAX_FS_SERIAL "etraxfs,serial"
48
#define ETRAX_SERIAL(obj) \
49
    OBJECT_CHECK(ETRAXSerial, (obj), TYPE_ETRAX_FS_SERIAL)
50

    
51
typedef struct ETRAXSerial {
52
    SysBusDevice parent_obj;
53

    
54
    MemoryRegion mmio;
55
    CharDriverState *chr;
56
    qemu_irq irq;
57

    
58
    int pending_tx;
59

    
60
    uint8_t rx_fifo[16];
61
    unsigned int rx_fifo_pos;
62
    unsigned int rx_fifo_len;
63

    
64
    /* Control registers.  */
65
    uint32_t regs[R_MAX];
66
} ETRAXSerial;
67

    
68
static void ser_update_irq(ETRAXSerial *s)
69
{
70

    
71
    if (s->rx_fifo_len) {
72
        s->regs[R_INTR] |= 8;
73
    } else {
74
        s->regs[R_INTR] &= ~8;
75
    }
76

    
77
    s->regs[R_MASKED_INTR] = s->regs[R_INTR] & s->regs[RW_INTR_MASK];
78
    qemu_set_irq(s->irq, !!s->regs[R_MASKED_INTR]);
79
}
80

    
81
static uint64_t
82
ser_read(void *opaque, hwaddr addr, unsigned int size)
83
{
84
    ETRAXSerial *s = opaque;
85
    uint32_t r = 0;
86

    
87
    addr >>= 2;
88
    switch (addr)
89
    {
90
        case R_STAT_DIN:
91
            r = s->rx_fifo[(s->rx_fifo_pos - s->rx_fifo_len) & 15];
92
            if (s->rx_fifo_len) {
93
                r |= 1 << STAT_DAV;
94
            }
95
            r |= 1 << STAT_TR_RDY;
96
            r |= 1 << STAT_TR_IDLE;
97
            break;
98
        case RS_STAT_DIN:
99
            r = s->rx_fifo[(s->rx_fifo_pos - s->rx_fifo_len) & 15];
100
            if (s->rx_fifo_len) {
101
                r |= 1 << STAT_DAV;
102
                s->rx_fifo_len--;
103
            }
104
            r |= 1 << STAT_TR_RDY;
105
            r |= 1 << STAT_TR_IDLE;
106
            break;
107
        default:
108
            r = s->regs[addr];
109
            D(qemu_log("%s " TARGET_FMT_plx "=%x\n", __func__, addr, r));
110
            break;
111
    }
112
    return r;
113
}
114

    
115
static void
116
ser_write(void *opaque, hwaddr addr,
117
          uint64_t val64, unsigned int size)
118
{
119
    ETRAXSerial *s = opaque;
120
    uint32_t value = val64;
121
    unsigned char ch = val64;
122

    
123
    D(qemu_log("%s " TARGET_FMT_plx "=%x\n",  __func__, addr, value));
124
    addr >>= 2;
125
    switch (addr)
126
    {
127
        case RW_DOUT:
128
            qemu_chr_fe_write(s->chr, &ch, 1);
129
            s->regs[R_INTR] |= 3;
130
            s->pending_tx = 1;
131
            s->regs[addr] = value;
132
            break;
133
        case RW_ACK_INTR:
134
            if (s->pending_tx) {
135
                value &= ~1;
136
                s->pending_tx = 0;
137
                D(qemu_log("fixedup value=%x r_intr=%x\n",
138
                           value, s->regs[R_INTR]));
139
            }
140
            s->regs[addr] = value;
141
            s->regs[R_INTR] &= ~value;
142
            D(printf("r_intr=%x\n", s->regs[R_INTR]));
143
            break;
144
        default:
145
            s->regs[addr] = value;
146
            break;
147
    }
148
    ser_update_irq(s);
149
}
150

    
151
static const MemoryRegionOps ser_ops = {
152
    .read = ser_read,
153
    .write = ser_write,
154
    .endianness = DEVICE_NATIVE_ENDIAN,
155
    .valid = {
156
        .min_access_size = 4,
157
        .max_access_size = 4
158
    }
159
};
160

    
161
static void serial_receive(void *opaque, const uint8_t *buf, int size)
162
{
163
    ETRAXSerial *s = opaque;
164
    int i;
165

    
166
    /* Got a byte.  */
167
    if (s->rx_fifo_len >= 16) {
168
        qemu_log("WARNING: UART dropped char.\n");
169
        return;
170
    }
171

    
172
    for (i = 0; i < size; i++) { 
173
        s->rx_fifo[s->rx_fifo_pos] = buf[i];
174
        s->rx_fifo_pos++;
175
        s->rx_fifo_pos &= 15;
176
        s->rx_fifo_len++;
177
    }
178

    
179
    ser_update_irq(s);
180
}
181

    
182
static int serial_can_receive(void *opaque)
183
{
184
    ETRAXSerial *s = opaque;
185
    int r;
186

    
187
    /* Is the receiver enabled?  */
188
    if (!(s->regs[RW_REC_CTRL] & (1 << 3))) {
189
        return 0;
190
    }
191

    
192
    r = sizeof(s->rx_fifo) - s->rx_fifo_len;
193
    return r;
194
}
195

    
196
static void serial_event(void *opaque, int event)
197
{
198

    
199
}
200

    
201
static void etraxfs_ser_reset(DeviceState *d)
202
{
203
    ETRAXSerial *s = ETRAX_SERIAL(d);
204

    
205
    /* transmitter begins ready and idle.  */
206
    s->regs[RS_STAT_DIN] |= (1 << STAT_TR_RDY);
207
    s->regs[RS_STAT_DIN] |= (1 << STAT_TR_IDLE);
208

    
209
    s->regs[RW_REC_CTRL] = 0x10000;
210

    
211
}
212

    
213
static int etraxfs_ser_init(SysBusDevice *dev)
214
{
215
    ETRAXSerial *s = ETRAX_SERIAL(dev);
216

    
217
    sysbus_init_irq(dev, &s->irq);
218
    memory_region_init_io(&s->mmio, OBJECT(s), &ser_ops, s,
219
                          "etraxfs-serial", R_MAX * 4);
220
    sysbus_init_mmio(dev, &s->mmio);
221

    
222
    s->chr = qemu_char_get_next_serial();
223
    if (s->chr) {
224
        qemu_chr_add_handlers(s->chr,
225
                              serial_can_receive, serial_receive,
226
                              serial_event, s);
227
    }
228
    return 0;
229
}
230

    
231
static void etraxfs_ser_class_init(ObjectClass *klass, void *data)
232
{
233
    DeviceClass *dc = DEVICE_CLASS(klass);
234
    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
235

    
236
    k->init = etraxfs_ser_init;
237
    dc->reset = etraxfs_ser_reset;
238
}
239

    
240
static const TypeInfo etraxfs_ser_info = {
241
    .name          = TYPE_ETRAX_FS_SERIAL,
242
    .parent        = TYPE_SYS_BUS_DEVICE,
243
    .instance_size = sizeof(ETRAXSerial),
244
    .class_init    = etraxfs_ser_class_init,
245
};
246

    
247
static void etraxfs_serial_register_types(void)
248
{
249
    type_register_static(&etraxfs_ser_info);
250
}
251

    
252
type_init(etraxfs_serial_register_types)