Statistics
| Branch: | Revision:

root / hw / pl011.c @ a1bc20df

History | View | Annotate | Download (8.4 kB)

1 5fafdf24 ths
/*
2 cdbdb648 pbrook
 * Arm PrimeCell PL011 UART
3 cdbdb648 pbrook
 *
4 cdbdb648 pbrook
 * Copyright (c) 2006 CodeSourcery.
5 cdbdb648 pbrook
 * Written by Paul Brook
6 cdbdb648 pbrook
 *
7 8e31bf38 Matthew Fernandez
 * This code is licensed under the GPL.
8 cdbdb648 pbrook
 */
9 cdbdb648 pbrook
10 a7d518a6 Paul Brook
#include "sysbus.h"
11 87ecb68b pbrook
#include "qemu-char.h"
12 cdbdb648 pbrook
13 cdbdb648 pbrook
typedef struct {
14 a7d518a6 Paul Brook
    SysBusDevice busdev;
15 48484757 Avi Kivity
    MemoryRegion iomem;
16 cdbdb648 pbrook
    uint32_t readbuff;
17 cdbdb648 pbrook
    uint32_t flags;
18 cdbdb648 pbrook
    uint32_t lcr;
19 cdbdb648 pbrook
    uint32_t cr;
20 cdbdb648 pbrook
    uint32_t dmacr;
21 cdbdb648 pbrook
    uint32_t int_enabled;
22 cdbdb648 pbrook
    uint32_t int_level;
23 cdbdb648 pbrook
    uint32_t read_fifo[16];
24 cdbdb648 pbrook
    uint32_t ilpr;
25 cdbdb648 pbrook
    uint32_t ibrd;
26 cdbdb648 pbrook
    uint32_t fbrd;
27 cdbdb648 pbrook
    uint32_t ifl;
28 cdbdb648 pbrook
    int read_pos;
29 cdbdb648 pbrook
    int read_count;
30 cdbdb648 pbrook
    int read_trigger;
31 cdbdb648 pbrook
    CharDriverState *chr;
32 d537cf6c pbrook
    qemu_irq irq;
33 a7d518a6 Paul Brook
    const unsigned char *id;
34 cdbdb648 pbrook
} pl011_state;
35 cdbdb648 pbrook
36 cdbdb648 pbrook
#define PL011_INT_TX 0x20
37 cdbdb648 pbrook
#define PL011_INT_RX 0x10
38 cdbdb648 pbrook
39 cdbdb648 pbrook
#define PL011_FLAG_TXFE 0x80
40 cdbdb648 pbrook
#define PL011_FLAG_RXFF 0x40
41 cdbdb648 pbrook
#define PL011_FLAG_TXFF 0x20
42 cdbdb648 pbrook
#define PL011_FLAG_RXFE 0x10
43 cdbdb648 pbrook
44 a7d518a6 Paul Brook
static const unsigned char pl011_id_arm[8] =
45 a7d518a6 Paul Brook
  { 0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
46 a7d518a6 Paul Brook
static const unsigned char pl011_id_luminary[8] =
47 a7d518a6 Paul Brook
  { 0x11, 0x00, 0x18, 0x01, 0x0d, 0xf0, 0x05, 0xb1 };
48 cdbdb648 pbrook
49 cdbdb648 pbrook
static void pl011_update(pl011_state *s)
50 cdbdb648 pbrook
{
51 cdbdb648 pbrook
    uint32_t flags;
52 3b46e624 ths
53 cdbdb648 pbrook
    flags = s->int_level & s->int_enabled;
54 d537cf6c pbrook
    qemu_set_irq(s->irq, flags != 0);
55 cdbdb648 pbrook
}
56 cdbdb648 pbrook
57 a8170e5e Avi Kivity
static uint64_t pl011_read(void *opaque, hwaddr offset,
58 48484757 Avi Kivity
                           unsigned size)
59 cdbdb648 pbrook
{
60 cdbdb648 pbrook
    pl011_state *s = (pl011_state *)opaque;
61 cdbdb648 pbrook
    uint32_t c;
62 cdbdb648 pbrook
63 cdbdb648 pbrook
    if (offset >= 0xfe0 && offset < 0x1000) {
64 a7d518a6 Paul Brook
        return s->id[(offset - 0xfe0) >> 2];
65 cdbdb648 pbrook
    }
66 cdbdb648 pbrook
    switch (offset >> 2) {
67 cdbdb648 pbrook
    case 0: /* UARTDR */
68 cdbdb648 pbrook
        s->flags &= ~PL011_FLAG_RXFF;
69 cdbdb648 pbrook
        c = s->read_fifo[s->read_pos];
70 cdbdb648 pbrook
        if (s->read_count > 0) {
71 cdbdb648 pbrook
            s->read_count--;
72 cdbdb648 pbrook
            if (++s->read_pos == 16)
73 cdbdb648 pbrook
                s->read_pos = 0;
74 cdbdb648 pbrook
        }
75 cdbdb648 pbrook
        if (s->read_count == 0) {
76 cdbdb648 pbrook
            s->flags |= PL011_FLAG_RXFE;
77 cdbdb648 pbrook
        }
78 cdbdb648 pbrook
        if (s->read_count == s->read_trigger - 1)
79 cdbdb648 pbrook
            s->int_level &= ~ PL011_INT_RX;
80 cdbdb648 pbrook
        pl011_update(s);
81 0d4abda8 Peter Maydell
        if (s->chr) {
82 0d4abda8 Peter Maydell
            qemu_chr_accept_input(s->chr);
83 0d4abda8 Peter Maydell
        }
84 cdbdb648 pbrook
        return c;
85 cdbdb648 pbrook
    case 1: /* UARTCR */
86 cdbdb648 pbrook
        return 0;
87 cdbdb648 pbrook
    case 6: /* UARTFR */
88 cdbdb648 pbrook
        return s->flags;
89 cdbdb648 pbrook
    case 8: /* UARTILPR */
90 cdbdb648 pbrook
        return s->ilpr;
91 cdbdb648 pbrook
    case 9: /* UARTIBRD */
92 cdbdb648 pbrook
        return s->ibrd;
93 cdbdb648 pbrook
    case 10: /* UARTFBRD */
94 cdbdb648 pbrook
        return s->fbrd;
95 cdbdb648 pbrook
    case 11: /* UARTLCR_H */
96 cdbdb648 pbrook
        return s->lcr;
97 cdbdb648 pbrook
    case 12: /* UARTCR */
98 cdbdb648 pbrook
        return s->cr;
99 cdbdb648 pbrook
    case 13: /* UARTIFLS */
100 cdbdb648 pbrook
        return s->ifl;
101 cdbdb648 pbrook
    case 14: /* UARTIMSC */
102 cdbdb648 pbrook
        return s->int_enabled;
103 cdbdb648 pbrook
    case 15: /* UARTRIS */
104 cdbdb648 pbrook
        return s->int_level;
105 cdbdb648 pbrook
    case 16: /* UARTMIS */
106 cdbdb648 pbrook
        return s->int_level & s->int_enabled;
107 cdbdb648 pbrook
    case 18: /* UARTDMACR */
108 cdbdb648 pbrook
        return s->dmacr;
109 cdbdb648 pbrook
    default:
110 6d5433e0 Peter Maydell
        qemu_log_mask(LOG_GUEST_ERROR,
111 6d5433e0 Peter Maydell
                      "pl011_read: Bad offset %x\n", (int)offset);
112 cdbdb648 pbrook
        return 0;
113 cdbdb648 pbrook
    }
114 cdbdb648 pbrook
}
115 cdbdb648 pbrook
116 cdbdb648 pbrook
static void pl011_set_read_trigger(pl011_state *s)
117 cdbdb648 pbrook
{
118 cdbdb648 pbrook
#if 0
119 cdbdb648 pbrook
    /* The docs say the RX interrupt is triggered when the FIFO exceeds
120 cdbdb648 pbrook
       the threshold.  However linux only reads the FIFO in response to an
121 cdbdb648 pbrook
       interrupt.  Triggering the interrupt when the FIFO is non-empty seems
122 cdbdb648 pbrook
       to make things work.  */
123 cdbdb648 pbrook
    if (s->lcr & 0x10)
124 cdbdb648 pbrook
        s->read_trigger = (s->ifl >> 1) & 0x1c;
125 cdbdb648 pbrook
    else
126 cdbdb648 pbrook
#endif
127 cdbdb648 pbrook
        s->read_trigger = 1;
128 cdbdb648 pbrook
}
129 cdbdb648 pbrook
130 a8170e5e Avi Kivity
static void pl011_write(void *opaque, hwaddr offset,
131 48484757 Avi Kivity
                        uint64_t value, unsigned size)
132 cdbdb648 pbrook
{
133 cdbdb648 pbrook
    pl011_state *s = (pl011_state *)opaque;
134 cdbdb648 pbrook
    unsigned char ch;
135 cdbdb648 pbrook
136 cdbdb648 pbrook
    switch (offset >> 2) {
137 cdbdb648 pbrook
    case 0: /* UARTDR */
138 cdbdb648 pbrook
        /* ??? Check if transmitter is enabled.  */
139 cdbdb648 pbrook
        ch = value;
140 cdbdb648 pbrook
        if (s->chr)
141 2cc6e0a1 Anthony Liguori
            qemu_chr_fe_write(s->chr, &ch, 1);
142 cdbdb648 pbrook
        s->int_level |= PL011_INT_TX;
143 cdbdb648 pbrook
        pl011_update(s);
144 cdbdb648 pbrook
        break;
145 cdbdb648 pbrook
    case 1: /* UARTCR */
146 cdbdb648 pbrook
        s->cr = value;
147 cdbdb648 pbrook
        break;
148 9ee6e8bb pbrook
    case 6: /* UARTFR */
149 9ee6e8bb pbrook
        /* Writes to Flag register are ignored.  */
150 9ee6e8bb pbrook
        break;
151 cdbdb648 pbrook
    case 8: /* UARTUARTILPR */
152 cdbdb648 pbrook
        s->ilpr = value;
153 cdbdb648 pbrook
        break;
154 cdbdb648 pbrook
    case 9: /* UARTIBRD */
155 cdbdb648 pbrook
        s->ibrd = value;
156 cdbdb648 pbrook
        break;
157 cdbdb648 pbrook
    case 10: /* UARTFBRD */
158 cdbdb648 pbrook
        s->fbrd = value;
159 cdbdb648 pbrook
        break;
160 cdbdb648 pbrook
    case 11: /* UARTLCR_H */
161 cdbdb648 pbrook
        s->lcr = value;
162 cdbdb648 pbrook
        pl011_set_read_trigger(s);
163 cdbdb648 pbrook
        break;
164 cdbdb648 pbrook
    case 12: /* UARTCR */
165 cdbdb648 pbrook
        /* ??? Need to implement the enable and loopback bits.  */
166 cdbdb648 pbrook
        s->cr = value;
167 cdbdb648 pbrook
        break;
168 cdbdb648 pbrook
    case 13: /* UARTIFS */
169 cdbdb648 pbrook
        s->ifl = value;
170 cdbdb648 pbrook
        pl011_set_read_trigger(s);
171 cdbdb648 pbrook
        break;
172 cdbdb648 pbrook
    case 14: /* UARTIMSC */
173 cdbdb648 pbrook
        s->int_enabled = value;
174 cdbdb648 pbrook
        pl011_update(s);
175 cdbdb648 pbrook
        break;
176 cdbdb648 pbrook
    case 17: /* UARTICR */
177 cdbdb648 pbrook
        s->int_level &= ~value;
178 cdbdb648 pbrook
        pl011_update(s);
179 cdbdb648 pbrook
        break;
180 cdbdb648 pbrook
    case 18: /* UARTDMACR */
181 cdbdb648 pbrook
        s->dmacr = value;
182 6d5433e0 Peter Maydell
        if (value & 3) {
183 6d5433e0 Peter Maydell
            qemu_log_mask(LOG_UNIMP, "pl011: DMA not implemented\n");
184 6d5433e0 Peter Maydell
        }
185 cdbdb648 pbrook
        break;
186 cdbdb648 pbrook
    default:
187 6d5433e0 Peter Maydell
        qemu_log_mask(LOG_GUEST_ERROR,
188 6d5433e0 Peter Maydell
                      "pl011_write: Bad offset %x\n", (int)offset);
189 cdbdb648 pbrook
    }
190 cdbdb648 pbrook
}
191 cdbdb648 pbrook
192 aa1f17c1 ths
static int pl011_can_receive(void *opaque)
193 cdbdb648 pbrook
{
194 cdbdb648 pbrook
    pl011_state *s = (pl011_state *)opaque;
195 cdbdb648 pbrook
196 cdbdb648 pbrook
    if (s->lcr & 0x10)
197 cdbdb648 pbrook
        return s->read_count < 16;
198 cdbdb648 pbrook
    else
199 cdbdb648 pbrook
        return s->read_count < 1;
200 cdbdb648 pbrook
}
201 cdbdb648 pbrook
202 cc9c9ffc aurel32
static void pl011_put_fifo(void *opaque, uint32_t value)
203 cdbdb648 pbrook
{
204 cdbdb648 pbrook
    pl011_state *s = (pl011_state *)opaque;
205 cdbdb648 pbrook
    int slot;
206 cdbdb648 pbrook
207 cdbdb648 pbrook
    slot = s->read_pos + s->read_count;
208 cdbdb648 pbrook
    if (slot >= 16)
209 cdbdb648 pbrook
        slot -= 16;
210 cc9c9ffc aurel32
    s->read_fifo[slot] = value;
211 cdbdb648 pbrook
    s->read_count++;
212 cdbdb648 pbrook
    s->flags &= ~PL011_FLAG_RXFE;
213 cdbdb648 pbrook
    if (s->cr & 0x10 || s->read_count == 16) {
214 cdbdb648 pbrook
        s->flags |= PL011_FLAG_RXFF;
215 cdbdb648 pbrook
    }
216 cdbdb648 pbrook
    if (s->read_count == s->read_trigger) {
217 cdbdb648 pbrook
        s->int_level |= PL011_INT_RX;
218 cdbdb648 pbrook
        pl011_update(s);
219 cdbdb648 pbrook
    }
220 cdbdb648 pbrook
}
221 cdbdb648 pbrook
222 cc9c9ffc aurel32
static void pl011_receive(void *opaque, const uint8_t *buf, int size)
223 cc9c9ffc aurel32
{
224 cc9c9ffc aurel32
    pl011_put_fifo(opaque, *buf);
225 cc9c9ffc aurel32
}
226 cc9c9ffc aurel32
227 cdbdb648 pbrook
static void pl011_event(void *opaque, int event)
228 cdbdb648 pbrook
{
229 cc9c9ffc aurel32
    if (event == CHR_EVENT_BREAK)
230 cc9c9ffc aurel32
        pl011_put_fifo(opaque, 0x400);
231 cdbdb648 pbrook
}
232 cdbdb648 pbrook
233 48484757 Avi Kivity
static const MemoryRegionOps pl011_ops = {
234 48484757 Avi Kivity
    .read = pl011_read,
235 48484757 Avi Kivity
    .write = pl011_write,
236 48484757 Avi Kivity
    .endianness = DEVICE_NATIVE_ENDIAN,
237 cdbdb648 pbrook
};
238 cdbdb648 pbrook
239 02b68757 Juan Quintela
static const VMStateDescription vmstate_pl011 = {
240 02b68757 Juan Quintela
    .name = "pl011",
241 02b68757 Juan Quintela
    .version_id = 1,
242 02b68757 Juan Quintela
    .minimum_version_id = 1,
243 02b68757 Juan Quintela
    .minimum_version_id_old = 1,
244 02b68757 Juan Quintela
    .fields      = (VMStateField[]) {
245 02b68757 Juan Quintela
        VMSTATE_UINT32(readbuff, pl011_state),
246 02b68757 Juan Quintela
        VMSTATE_UINT32(flags, pl011_state),
247 02b68757 Juan Quintela
        VMSTATE_UINT32(lcr, pl011_state),
248 02b68757 Juan Quintela
        VMSTATE_UINT32(cr, pl011_state),
249 02b68757 Juan Quintela
        VMSTATE_UINT32(dmacr, pl011_state),
250 02b68757 Juan Quintela
        VMSTATE_UINT32(int_enabled, pl011_state),
251 02b68757 Juan Quintela
        VMSTATE_UINT32(int_level, pl011_state),
252 02b68757 Juan Quintela
        VMSTATE_UINT32_ARRAY(read_fifo, pl011_state, 16),
253 02b68757 Juan Quintela
        VMSTATE_UINT32(ilpr, pl011_state),
254 02b68757 Juan Quintela
        VMSTATE_UINT32(ibrd, pl011_state),
255 02b68757 Juan Quintela
        VMSTATE_UINT32(fbrd, pl011_state),
256 02b68757 Juan Quintela
        VMSTATE_UINT32(ifl, pl011_state),
257 02b68757 Juan Quintela
        VMSTATE_INT32(read_pos, pl011_state),
258 02b68757 Juan Quintela
        VMSTATE_INT32(read_count, pl011_state),
259 02b68757 Juan Quintela
        VMSTATE_INT32(read_trigger, pl011_state),
260 02b68757 Juan Quintela
        VMSTATE_END_OF_LIST()
261 02b68757 Juan Quintela
    }
262 02b68757 Juan Quintela
};
263 23e39294 pbrook
264 81a322d4 Gerd Hoffmann
static int pl011_init(SysBusDevice *dev, const unsigned char *id)
265 cdbdb648 pbrook
{
266 a7d518a6 Paul Brook
    pl011_state *s = FROM_SYSBUS(pl011_state, dev);
267 cdbdb648 pbrook
268 48484757 Avi Kivity
    memory_region_init_io(&s->iomem, &pl011_ops, s, "pl011", 0x1000);
269 750ecd44 Avi Kivity
    sysbus_init_mmio(dev, &s->iomem);
270 a7d518a6 Paul Brook
    sysbus_init_irq(dev, &s->irq);
271 a7d518a6 Paul Brook
    s->id = id;
272 0beb4942 Anthony Liguori
    s->chr = qemu_char_get_next_serial();
273 a7d518a6 Paul Brook
274 cdbdb648 pbrook
    s->read_trigger = 1;
275 cdbdb648 pbrook
    s->ifl = 0x12;
276 cdbdb648 pbrook
    s->cr = 0x300;
277 cdbdb648 pbrook
    s->flags = 0x90;
278 a7d518a6 Paul Brook
    if (s->chr) {
279 a7d518a6 Paul Brook
        qemu_chr_add_handlers(s->chr, pl011_can_receive, pl011_receive,
280 e5b0bc44 pbrook
                              pl011_event, s);
281 cdbdb648 pbrook
    }
282 02b68757 Juan Quintela
    vmstate_register(&dev->qdev, -1, &vmstate_pl011, s);
283 81a322d4 Gerd Hoffmann
    return 0;
284 cdbdb648 pbrook
}
285 a7d518a6 Paul Brook
286 999e12bb Anthony Liguori
static int pl011_arm_init(SysBusDevice *dev)
287 a7d518a6 Paul Brook
{
288 81a322d4 Gerd Hoffmann
    return pl011_init(dev, pl011_id_arm);
289 a7d518a6 Paul Brook
}
290 a7d518a6 Paul Brook
291 999e12bb Anthony Liguori
static int pl011_luminary_init(SysBusDevice *dev)
292 a7d518a6 Paul Brook
{
293 81a322d4 Gerd Hoffmann
    return pl011_init(dev, pl011_id_luminary);
294 a7d518a6 Paul Brook
}
295 a7d518a6 Paul Brook
296 999e12bb Anthony Liguori
static void pl011_arm_class_init(ObjectClass *klass, void *data)
297 999e12bb Anthony Liguori
{
298 999e12bb Anthony Liguori
    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
299 999e12bb Anthony Liguori
300 999e12bb Anthony Liguori
    sdc->init = pl011_arm_init;
301 999e12bb Anthony Liguori
}
302 999e12bb Anthony Liguori
303 39bffca2 Anthony Liguori
static TypeInfo pl011_arm_info = {
304 39bffca2 Anthony Liguori
    .name          = "pl011",
305 39bffca2 Anthony Liguori
    .parent        = TYPE_SYS_BUS_DEVICE,
306 39bffca2 Anthony Liguori
    .instance_size = sizeof(pl011_state),
307 39bffca2 Anthony Liguori
    .class_init    = pl011_arm_class_init,
308 999e12bb Anthony Liguori
};
309 999e12bb Anthony Liguori
310 999e12bb Anthony Liguori
static void pl011_luminary_class_init(ObjectClass *klass, void *data)
311 999e12bb Anthony Liguori
{
312 999e12bb Anthony Liguori
    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
313 999e12bb Anthony Liguori
314 999e12bb Anthony Liguori
    sdc->init = pl011_luminary_init;
315 999e12bb Anthony Liguori
}
316 999e12bb Anthony Liguori
317 39bffca2 Anthony Liguori
static TypeInfo pl011_luminary_info = {
318 39bffca2 Anthony Liguori
    .name          = "pl011_luminary",
319 39bffca2 Anthony Liguori
    .parent        = TYPE_SYS_BUS_DEVICE,
320 39bffca2 Anthony Liguori
    .instance_size = sizeof(pl011_state),
321 39bffca2 Anthony Liguori
    .class_init    = pl011_luminary_class_init,
322 999e12bb Anthony Liguori
};
323 999e12bb Anthony Liguori
324 83f7d43a Andreas Färber
static void pl011_register_types(void)
325 a7d518a6 Paul Brook
{
326 39bffca2 Anthony Liguori
    type_register_static(&pl011_arm_info);
327 39bffca2 Anthony Liguori
    type_register_static(&pl011_luminary_info);
328 a7d518a6 Paul Brook
}
329 a7d518a6 Paul Brook
330 83f7d43a Andreas Färber
type_init(pl011_register_types)