Statistics
| Branch: | Revision:

root / hw / char / etraxfs_ser.c @ cac3c384

History | View | Annotate | Download (6.4 kB)

1 83fa1010 ths
/*
2 83fa1010 ths
 * QEMU ETRAX System Emulator
3 83fa1010 ths
 *
4 83fa1010 ths
 * Copyright (c) 2007 Edgar E. Iglesias, Axis Communications AB.
5 83fa1010 ths
 *
6 83fa1010 ths
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 83fa1010 ths
 * of this software and associated documentation files (the "Software"), to deal
8 83fa1010 ths
 * in the Software without restriction, including without limitation the rights
9 83fa1010 ths
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 83fa1010 ths
 * copies of the Software, and to permit persons to whom the Software is
11 83fa1010 ths
 * furnished to do so, subject to the following conditions:
12 83fa1010 ths
 *
13 83fa1010 ths
 * The above copyright notice and this permission notice shall be included in
14 83fa1010 ths
 * all copies or substantial portions of the Software.
15 83fa1010 ths
 *
16 83fa1010 ths
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 83fa1010 ths
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 83fa1010 ths
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 83fa1010 ths
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 83fa1010 ths
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 83fa1010 ths
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 83fa1010 ths
 * THE SOFTWARE.
23 83fa1010 ths
 */
24 83fa1010 ths
25 83c9f4ca Paolo Bonzini
#include "hw/sysbus.h"
26 dccfcd0e Paolo Bonzini
#include "sysemu/char.h"
27 1de7afc9 Paolo Bonzini
#include "qemu/log.h"
28 83fa1010 ths
29 bbaf29c7 edgar_igl
#define D(x)
30 bbaf29c7 edgar_igl
31 72af9170 Edgar E. Iglesias
#define RW_TR_CTRL     (0x00 / 4)
32 72af9170 Edgar E. Iglesias
#define RW_TR_DMA_EN   (0x04 / 4)
33 72af9170 Edgar E. Iglesias
#define RW_REC_CTRL    (0x08 / 4)
34 72af9170 Edgar E. Iglesias
#define RW_DOUT        (0x1c / 4)
35 72af9170 Edgar E. Iglesias
#define RS_STAT_DIN    (0x20 / 4)
36 72af9170 Edgar E. Iglesias
#define R_STAT_DIN     (0x24 / 4)
37 72af9170 Edgar E. Iglesias
#define RW_INTR_MASK   (0x2c / 4)
38 72af9170 Edgar E. Iglesias
#define RW_ACK_INTR    (0x30 / 4)
39 72af9170 Edgar E. Iglesias
#define R_INTR         (0x34 / 4)
40 72af9170 Edgar E. Iglesias
#define R_MASKED_INTR  (0x38 / 4)
41 72af9170 Edgar E. Iglesias
#define R_MAX          (0x3c / 4)
42 83fa1010 ths
43 f062058f edgar_igl
#define STAT_DAV     16
44 f062058f edgar_igl
#define STAT_TR_IDLE 22
45 f062058f edgar_igl
#define STAT_TR_RDY  24
46 f062058f edgar_igl
47 f2964260 Edgar E. Iglesias
struct etrax_serial
48 83fa1010 ths
{
49 2a9859e7 Edgar E. Iglesias
    SysBusDevice busdev;
50 dbfb57f3 Edgar E. Iglesias
    MemoryRegion mmio;
51 2a9859e7 Edgar E. Iglesias
    CharDriverState *chr;
52 2a9859e7 Edgar E. Iglesias
    qemu_irq irq;
53 f062058f edgar_igl
54 2a9859e7 Edgar E. Iglesias
    int pending_tx;
55 f062058f edgar_igl
56 f2fcffbb Edgar E. Iglesias
    uint8_t rx_fifo[16];
57 f2fcffbb Edgar E. Iglesias
    unsigned int rx_fifo_pos;
58 f2fcffbb Edgar E. Iglesias
    unsigned int rx_fifo_len;
59 f2fcffbb Edgar E. Iglesias
60 2a9859e7 Edgar E. Iglesias
    /* Control registers.  */
61 2a9859e7 Edgar E. Iglesias
    uint32_t regs[R_MAX];
62 f062058f edgar_igl
};
63 f062058f edgar_igl
64 f2964260 Edgar E. Iglesias
static void ser_update_irq(struct etrax_serial *s)
65 f062058f edgar_igl
{
66 72af9170 Edgar E. Iglesias
67 f2fcffbb Edgar E. Iglesias
    if (s->rx_fifo_len) {
68 f2fcffbb Edgar E. Iglesias
        s->regs[R_INTR] |= 8;
69 f2fcffbb Edgar E. Iglesias
    } else {
70 f2fcffbb Edgar E. Iglesias
        s->regs[R_INTR] &= ~8;
71 f2fcffbb Edgar E. Iglesias
    }
72 f2fcffbb Edgar E. Iglesias
73 f2fcffbb Edgar E. Iglesias
    s->regs[R_MASKED_INTR] = s->regs[R_INTR] & s->regs[RW_INTR_MASK];
74 2a9859e7 Edgar E. Iglesias
    qemu_set_irq(s->irq, !!s->regs[R_MASKED_INTR]);
75 83fa1010 ths
}
76 f062058f edgar_igl
77 dbfb57f3 Edgar E. Iglesias
static uint64_t
78 a8170e5e Avi Kivity
ser_read(void *opaque, hwaddr addr, unsigned int size)
79 83fa1010 ths
{
80 2a9859e7 Edgar E. Iglesias
    struct etrax_serial *s = opaque;
81 2a9859e7 Edgar E. Iglesias
    uint32_t r = 0;
82 2a9859e7 Edgar E. Iglesias
83 2a9859e7 Edgar E. Iglesias
    addr >>= 2;
84 2a9859e7 Edgar E. Iglesias
    switch (addr)
85 2a9859e7 Edgar E. Iglesias
    {
86 2a9859e7 Edgar E. Iglesias
        case R_STAT_DIN:
87 f2fcffbb Edgar E. Iglesias
            r = s->rx_fifo[(s->rx_fifo_pos - s->rx_fifo_len) & 15];
88 f2fcffbb Edgar E. Iglesias
            if (s->rx_fifo_len) {
89 f2fcffbb Edgar E. Iglesias
                r |= 1 << STAT_DAV;
90 f2fcffbb Edgar E. Iglesias
            }
91 f2fcffbb Edgar E. Iglesias
            r |= 1 << STAT_TR_RDY;
92 f2fcffbb Edgar E. Iglesias
            r |= 1 << STAT_TR_IDLE;
93 2a9859e7 Edgar E. Iglesias
            break;
94 2a9859e7 Edgar E. Iglesias
        case RS_STAT_DIN:
95 f2fcffbb Edgar E. Iglesias
            r = s->rx_fifo[(s->rx_fifo_pos - s->rx_fifo_len) & 15];
96 f2fcffbb Edgar E. Iglesias
            if (s->rx_fifo_len) {
97 f2fcffbb Edgar E. Iglesias
                r |= 1 << STAT_DAV;
98 f2fcffbb Edgar E. Iglesias
                s->rx_fifo_len--;
99 f2fcffbb Edgar E. Iglesias
            }
100 f2fcffbb Edgar E. Iglesias
            r |= 1 << STAT_TR_RDY;
101 f2fcffbb Edgar E. Iglesias
            r |= 1 << STAT_TR_IDLE;
102 2a9859e7 Edgar E. Iglesias
            break;
103 2a9859e7 Edgar E. Iglesias
        default:
104 2a9859e7 Edgar E. Iglesias
            r = s->regs[addr];
105 8cc7c395 Edgar E. Iglesias
            D(qemu_log("%s " TARGET_FMT_plx "=%x\n", __func__, addr, r));
106 2a9859e7 Edgar E. Iglesias
            break;
107 2a9859e7 Edgar E. Iglesias
    }
108 2a9859e7 Edgar E. Iglesias
    return r;
109 83fa1010 ths
}
110 83fa1010 ths
111 83fa1010 ths
static void
112 a8170e5e Avi Kivity
ser_write(void *opaque, hwaddr addr,
113 dbfb57f3 Edgar E. Iglesias
          uint64_t val64, unsigned int size)
114 83fa1010 ths
{
115 2a9859e7 Edgar E. Iglesias
    struct etrax_serial *s = opaque;
116 dbfb57f3 Edgar E. Iglesias
    uint32_t value = val64;
117 dbfb57f3 Edgar E. Iglesias
    unsigned char ch = val64;
118 2a9859e7 Edgar E. Iglesias
119 8cc7c395 Edgar E. Iglesias
    D(qemu_log("%s " TARGET_FMT_plx "=%x\n",  __func__, addr, value));
120 2a9859e7 Edgar E. Iglesias
    addr >>= 2;
121 2a9859e7 Edgar E. Iglesias
    switch (addr)
122 2a9859e7 Edgar E. Iglesias
    {
123 2a9859e7 Edgar E. Iglesias
        case RW_DOUT:
124 2cc6e0a1 Anthony Liguori
            qemu_chr_fe_write(s->chr, &ch, 1);
125 f2fcffbb Edgar E. Iglesias
            s->regs[R_INTR] |= 3;
126 2a9859e7 Edgar E. Iglesias
            s->pending_tx = 1;
127 2a9859e7 Edgar E. Iglesias
            s->regs[addr] = value;
128 2a9859e7 Edgar E. Iglesias
            break;
129 2a9859e7 Edgar E. Iglesias
        case RW_ACK_INTR:
130 f2fcffbb Edgar E. Iglesias
            if (s->pending_tx) {
131 f2fcffbb Edgar E. Iglesias
                value &= ~1;
132 2a9859e7 Edgar E. Iglesias
                s->pending_tx = 0;
133 8cc7c395 Edgar E. Iglesias
                D(qemu_log("fixedup value=%x r_intr=%x\n",
134 8cc7c395 Edgar E. Iglesias
                           value, s->regs[R_INTR]));
135 2a9859e7 Edgar E. Iglesias
            }
136 f2fcffbb Edgar E. Iglesias
            s->regs[addr] = value;
137 f2fcffbb Edgar E. Iglesias
            s->regs[R_INTR] &= ~value;
138 f2fcffbb Edgar E. Iglesias
            D(printf("r_intr=%x\n", s->regs[R_INTR]));
139 2a9859e7 Edgar E. Iglesias
            break;
140 2a9859e7 Edgar E. Iglesias
        default:
141 2a9859e7 Edgar E. Iglesias
            s->regs[addr] = value;
142 2a9859e7 Edgar E. Iglesias
            break;
143 2a9859e7 Edgar E. Iglesias
    }
144 2a9859e7 Edgar E. Iglesias
    ser_update_irq(s);
145 83fa1010 ths
}
146 83fa1010 ths
147 dbfb57f3 Edgar E. Iglesias
static const MemoryRegionOps ser_ops = {
148 dbfb57f3 Edgar E. Iglesias
    .read = ser_read,
149 dbfb57f3 Edgar E. Iglesias
    .write = ser_write,
150 dbfb57f3 Edgar E. Iglesias
    .endianness = DEVICE_NATIVE_ENDIAN,
151 dbfb57f3 Edgar E. Iglesias
    .valid = {
152 dbfb57f3 Edgar E. Iglesias
        .min_access_size = 4,
153 dbfb57f3 Edgar E. Iglesias
        .max_access_size = 4
154 dbfb57f3 Edgar E. Iglesias
    }
155 83fa1010 ths
};
156 83fa1010 ths
157 f062058f edgar_igl
static void serial_receive(void *opaque, const uint8_t *buf, int size)
158 83fa1010 ths
{
159 2a9859e7 Edgar E. Iglesias
    struct etrax_serial *s = opaque;
160 f2fcffbb Edgar E. Iglesias
    int i;
161 f2fcffbb Edgar E. Iglesias
162 f2fcffbb Edgar E. Iglesias
    /* Got a byte.  */
163 f2fcffbb Edgar E. Iglesias
    if (s->rx_fifo_len >= 16) {
164 8cc7c395 Edgar E. Iglesias
        qemu_log("WARNING: UART dropped char.\n");
165 f2fcffbb Edgar E. Iglesias
        return;
166 f2fcffbb Edgar E. Iglesias
    }
167 f2fcffbb Edgar E. Iglesias
168 f2fcffbb Edgar E. Iglesias
    for (i = 0; i < size; i++) { 
169 f2fcffbb Edgar E. Iglesias
        s->rx_fifo[s->rx_fifo_pos] = buf[i];
170 f2fcffbb Edgar E. Iglesias
        s->rx_fifo_pos++;
171 f2fcffbb Edgar E. Iglesias
        s->rx_fifo_pos &= 15;
172 f2fcffbb Edgar E. Iglesias
        s->rx_fifo_len++;
173 f2fcffbb Edgar E. Iglesias
    }
174 f062058f edgar_igl
175 2a9859e7 Edgar E. Iglesias
    ser_update_irq(s);
176 f062058f edgar_igl
}
177 f062058f edgar_igl
178 f062058f edgar_igl
static int serial_can_receive(void *opaque)
179 f062058f edgar_igl
{
180 2a9859e7 Edgar E. Iglesias
    struct etrax_serial *s = opaque;
181 2a9859e7 Edgar E. Iglesias
    int r;
182 f062058f edgar_igl
183 2a9859e7 Edgar E. Iglesias
    /* Is the receiver enabled?  */
184 f2fcffbb Edgar E. Iglesias
    if (!(s->regs[RW_REC_CTRL] & (1 << 3))) {
185 f2fcffbb Edgar E. Iglesias
        return 0;
186 f2fcffbb Edgar E. Iglesias
    }
187 f062058f edgar_igl
188 f2fcffbb Edgar E. Iglesias
    r = sizeof(s->rx_fifo) - s->rx_fifo_len;
189 2a9859e7 Edgar E. Iglesias
    return r;
190 f062058f edgar_igl
}
191 f062058f edgar_igl
192 f062058f edgar_igl
static void serial_event(void *opaque, int event)
193 f062058f edgar_igl
{
194 f062058f edgar_igl
195 f062058f edgar_igl
}
196 f062058f edgar_igl
197 20be39de Edgar E. Iglesias
static void etraxfs_ser_reset(DeviceState *d)
198 f062058f edgar_igl
{
199 20be39de Edgar E. Iglesias
    struct etrax_serial *s = container_of(d, typeof(*s), busdev.qdev);
200 2a9859e7 Edgar E. Iglesias
201 2a9859e7 Edgar E. Iglesias
    /* transmitter begins ready and idle.  */
202 2a9859e7 Edgar E. Iglesias
    s->regs[RS_STAT_DIN] |= (1 << STAT_TR_RDY);
203 2a9859e7 Edgar E. Iglesias
    s->regs[RS_STAT_DIN] |= (1 << STAT_TR_IDLE);
204 2a9859e7 Edgar E. Iglesias
205 20be39de Edgar E. Iglesias
    s->regs[RW_REC_CTRL] = 0x10000;
206 20be39de Edgar E. Iglesias
207 20be39de Edgar E. Iglesias
}
208 20be39de Edgar E. Iglesias
209 20be39de Edgar E. Iglesias
static int etraxfs_ser_init(SysBusDevice *dev)
210 20be39de Edgar E. Iglesias
{
211 20be39de Edgar E. Iglesias
    struct etrax_serial *s = FROM_SYSBUS(typeof (*s), dev);
212 20be39de Edgar E. Iglesias
213 2a9859e7 Edgar E. Iglesias
    sysbus_init_irq(dev, &s->irq);
214 dbfb57f3 Edgar E. Iglesias
    memory_region_init_io(&s->mmio, &ser_ops, s, "etraxfs-serial", R_MAX * 4);
215 750ecd44 Avi Kivity
    sysbus_init_mmio(dev, &s->mmio);
216 dbfb57f3 Edgar E. Iglesias
217 0beb4942 Anthony Liguori
    s->chr = qemu_char_get_next_serial();
218 2a9859e7 Edgar E. Iglesias
    if (s->chr)
219 2a9859e7 Edgar E. Iglesias
        qemu_chr_add_handlers(s->chr,
220 2a9859e7 Edgar E. Iglesias
                      serial_can_receive, serial_receive,
221 2a9859e7 Edgar E. Iglesias
                      serial_event, s);
222 81a322d4 Gerd Hoffmann
    return 0;
223 83fa1010 ths
}
224 4b816985 Edgar E. Iglesias
225 999e12bb Anthony Liguori
static void etraxfs_ser_class_init(ObjectClass *klass, void *data)
226 999e12bb Anthony Liguori
{
227 39bffca2 Anthony Liguori
    DeviceClass *dc = DEVICE_CLASS(klass);
228 999e12bb Anthony Liguori
    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
229 999e12bb Anthony Liguori
230 999e12bb Anthony Liguori
    k->init = etraxfs_ser_init;
231 39bffca2 Anthony Liguori
    dc->reset = etraxfs_ser_reset;
232 999e12bb Anthony Liguori
}
233 999e12bb Anthony Liguori
234 8c43a6f0 Andreas Färber
static const TypeInfo etraxfs_ser_info = {
235 39bffca2 Anthony Liguori
    .name          = "etraxfs,serial",
236 39bffca2 Anthony Liguori
    .parent        = TYPE_SYS_BUS_DEVICE,
237 39bffca2 Anthony Liguori
    .instance_size = sizeof(struct etrax_serial),
238 39bffca2 Anthony Liguori
    .class_init    = etraxfs_ser_class_init,
239 20be39de Edgar E. Iglesias
};
240 20be39de Edgar E. Iglesias
241 83f7d43a Andreas Färber
static void etraxfs_serial_register_types(void)
242 4b816985 Edgar E. Iglesias
{
243 39bffca2 Anthony Liguori
    type_register_static(&etraxfs_ser_info);
244 4b816985 Edgar E. Iglesias
}
245 4b816985 Edgar E. Iglesias
246 83f7d43a Andreas Färber
type_init(etraxfs_serial_register_types)