Statistics
| Branch: | Revision:

root / hw / pl011.c @ 2cae4119

History | View | Annotate | Download (8.3 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 48484757 Avi Kivity
static uint64_t pl011_read(void *opaque, target_phys_addr_t 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 2ac71179 Paul Brook
        hw_error("pl011_read: Bad offset %x\n", (int)offset);
111 cdbdb648 pbrook
        return 0;
112 cdbdb648 pbrook
    }
113 cdbdb648 pbrook
}
114 cdbdb648 pbrook
115 cdbdb648 pbrook
static void pl011_set_read_trigger(pl011_state *s)
116 cdbdb648 pbrook
{
117 cdbdb648 pbrook
#if 0
118 cdbdb648 pbrook
    /* The docs say the RX interrupt is triggered when the FIFO exceeds
119 cdbdb648 pbrook
       the threshold.  However linux only reads the FIFO in response to an
120 cdbdb648 pbrook
       interrupt.  Triggering the interrupt when the FIFO is non-empty seems
121 cdbdb648 pbrook
       to make things work.  */
122 cdbdb648 pbrook
    if (s->lcr & 0x10)
123 cdbdb648 pbrook
        s->read_trigger = (s->ifl >> 1) & 0x1c;
124 cdbdb648 pbrook
    else
125 cdbdb648 pbrook
#endif
126 cdbdb648 pbrook
        s->read_trigger = 1;
127 cdbdb648 pbrook
}
128 cdbdb648 pbrook
129 c227f099 Anthony Liguori
static void pl011_write(void *opaque, target_phys_addr_t offset,
130 48484757 Avi Kivity
                        uint64_t value, unsigned size)
131 cdbdb648 pbrook
{
132 cdbdb648 pbrook
    pl011_state *s = (pl011_state *)opaque;
133 cdbdb648 pbrook
    unsigned char ch;
134 cdbdb648 pbrook
135 cdbdb648 pbrook
    switch (offset >> 2) {
136 cdbdb648 pbrook
    case 0: /* UARTDR */
137 cdbdb648 pbrook
        /* ??? Check if transmitter is enabled.  */
138 cdbdb648 pbrook
        ch = value;
139 cdbdb648 pbrook
        if (s->chr)
140 2cc6e0a1 Anthony Liguori
            qemu_chr_fe_write(s->chr, &ch, 1);
141 cdbdb648 pbrook
        s->int_level |= PL011_INT_TX;
142 cdbdb648 pbrook
        pl011_update(s);
143 cdbdb648 pbrook
        break;
144 cdbdb648 pbrook
    case 1: /* UARTCR */
145 cdbdb648 pbrook
        s->cr = value;
146 cdbdb648 pbrook
        break;
147 9ee6e8bb pbrook
    case 6: /* UARTFR */
148 9ee6e8bb pbrook
        /* Writes to Flag register are ignored.  */
149 9ee6e8bb pbrook
        break;
150 cdbdb648 pbrook
    case 8: /* UARTUARTILPR */
151 cdbdb648 pbrook
        s->ilpr = value;
152 cdbdb648 pbrook
        break;
153 cdbdb648 pbrook
    case 9: /* UARTIBRD */
154 cdbdb648 pbrook
        s->ibrd = value;
155 cdbdb648 pbrook
        break;
156 cdbdb648 pbrook
    case 10: /* UARTFBRD */
157 cdbdb648 pbrook
        s->fbrd = value;
158 cdbdb648 pbrook
        break;
159 cdbdb648 pbrook
    case 11: /* UARTLCR_H */
160 cdbdb648 pbrook
        s->lcr = value;
161 cdbdb648 pbrook
        pl011_set_read_trigger(s);
162 cdbdb648 pbrook
        break;
163 cdbdb648 pbrook
    case 12: /* UARTCR */
164 cdbdb648 pbrook
        /* ??? Need to implement the enable and loopback bits.  */
165 cdbdb648 pbrook
        s->cr = value;
166 cdbdb648 pbrook
        break;
167 cdbdb648 pbrook
    case 13: /* UARTIFS */
168 cdbdb648 pbrook
        s->ifl = value;
169 cdbdb648 pbrook
        pl011_set_read_trigger(s);
170 cdbdb648 pbrook
        break;
171 cdbdb648 pbrook
    case 14: /* UARTIMSC */
172 cdbdb648 pbrook
        s->int_enabled = value;
173 cdbdb648 pbrook
        pl011_update(s);
174 cdbdb648 pbrook
        break;
175 cdbdb648 pbrook
    case 17: /* UARTICR */
176 cdbdb648 pbrook
        s->int_level &= ~value;
177 cdbdb648 pbrook
        pl011_update(s);
178 cdbdb648 pbrook
        break;
179 cdbdb648 pbrook
    case 18: /* UARTDMACR */
180 cdbdb648 pbrook
        s->dmacr = value;
181 cdbdb648 pbrook
        if (value & 3)
182 2ac71179 Paul Brook
            hw_error("PL011: DMA not implemented\n");
183 cdbdb648 pbrook
        break;
184 cdbdb648 pbrook
    default:
185 2ac71179 Paul Brook
        hw_error("pl011_write: Bad offset %x\n", (int)offset);
186 cdbdb648 pbrook
    }
187 cdbdb648 pbrook
}
188 cdbdb648 pbrook
189 aa1f17c1 ths
static int pl011_can_receive(void *opaque)
190 cdbdb648 pbrook
{
191 cdbdb648 pbrook
    pl011_state *s = (pl011_state *)opaque;
192 cdbdb648 pbrook
193 cdbdb648 pbrook
    if (s->lcr & 0x10)
194 cdbdb648 pbrook
        return s->read_count < 16;
195 cdbdb648 pbrook
    else
196 cdbdb648 pbrook
        return s->read_count < 1;
197 cdbdb648 pbrook
}
198 cdbdb648 pbrook
199 cc9c9ffc aurel32
static void pl011_put_fifo(void *opaque, uint32_t value)
200 cdbdb648 pbrook
{
201 cdbdb648 pbrook
    pl011_state *s = (pl011_state *)opaque;
202 cdbdb648 pbrook
    int slot;
203 cdbdb648 pbrook
204 cdbdb648 pbrook
    slot = s->read_pos + s->read_count;
205 cdbdb648 pbrook
    if (slot >= 16)
206 cdbdb648 pbrook
        slot -= 16;
207 cc9c9ffc aurel32
    s->read_fifo[slot] = value;
208 cdbdb648 pbrook
    s->read_count++;
209 cdbdb648 pbrook
    s->flags &= ~PL011_FLAG_RXFE;
210 cdbdb648 pbrook
    if (s->cr & 0x10 || s->read_count == 16) {
211 cdbdb648 pbrook
        s->flags |= PL011_FLAG_RXFF;
212 cdbdb648 pbrook
    }
213 cdbdb648 pbrook
    if (s->read_count == s->read_trigger) {
214 cdbdb648 pbrook
        s->int_level |= PL011_INT_RX;
215 cdbdb648 pbrook
        pl011_update(s);
216 cdbdb648 pbrook
    }
217 cdbdb648 pbrook
}
218 cdbdb648 pbrook
219 cc9c9ffc aurel32
static void pl011_receive(void *opaque, const uint8_t *buf, int size)
220 cc9c9ffc aurel32
{
221 cc9c9ffc aurel32
    pl011_put_fifo(opaque, *buf);
222 cc9c9ffc aurel32
}
223 cc9c9ffc aurel32
224 cdbdb648 pbrook
static void pl011_event(void *opaque, int event)
225 cdbdb648 pbrook
{
226 cc9c9ffc aurel32
    if (event == CHR_EVENT_BREAK)
227 cc9c9ffc aurel32
        pl011_put_fifo(opaque, 0x400);
228 cdbdb648 pbrook
}
229 cdbdb648 pbrook
230 48484757 Avi Kivity
static const MemoryRegionOps pl011_ops = {
231 48484757 Avi Kivity
    .read = pl011_read,
232 48484757 Avi Kivity
    .write = pl011_write,
233 48484757 Avi Kivity
    .endianness = DEVICE_NATIVE_ENDIAN,
234 cdbdb648 pbrook
};
235 cdbdb648 pbrook
236 02b68757 Juan Quintela
static const VMStateDescription vmstate_pl011 = {
237 02b68757 Juan Quintela
    .name = "pl011",
238 02b68757 Juan Quintela
    .version_id = 1,
239 02b68757 Juan Quintela
    .minimum_version_id = 1,
240 02b68757 Juan Quintela
    .minimum_version_id_old = 1,
241 02b68757 Juan Quintela
    .fields      = (VMStateField[]) {
242 02b68757 Juan Quintela
        VMSTATE_UINT32(readbuff, pl011_state),
243 02b68757 Juan Quintela
        VMSTATE_UINT32(flags, pl011_state),
244 02b68757 Juan Quintela
        VMSTATE_UINT32(lcr, pl011_state),
245 02b68757 Juan Quintela
        VMSTATE_UINT32(cr, pl011_state),
246 02b68757 Juan Quintela
        VMSTATE_UINT32(dmacr, pl011_state),
247 02b68757 Juan Quintela
        VMSTATE_UINT32(int_enabled, pl011_state),
248 02b68757 Juan Quintela
        VMSTATE_UINT32(int_level, pl011_state),
249 02b68757 Juan Quintela
        VMSTATE_UINT32_ARRAY(read_fifo, pl011_state, 16),
250 02b68757 Juan Quintela
        VMSTATE_UINT32(ilpr, pl011_state),
251 02b68757 Juan Quintela
        VMSTATE_UINT32(ibrd, pl011_state),
252 02b68757 Juan Quintela
        VMSTATE_UINT32(fbrd, pl011_state),
253 02b68757 Juan Quintela
        VMSTATE_UINT32(ifl, pl011_state),
254 02b68757 Juan Quintela
        VMSTATE_INT32(read_pos, pl011_state),
255 02b68757 Juan Quintela
        VMSTATE_INT32(read_count, pl011_state),
256 02b68757 Juan Quintela
        VMSTATE_INT32(read_trigger, pl011_state),
257 02b68757 Juan Quintela
        VMSTATE_END_OF_LIST()
258 02b68757 Juan Quintela
    }
259 02b68757 Juan Quintela
};
260 23e39294 pbrook
261 81a322d4 Gerd Hoffmann
static int pl011_init(SysBusDevice *dev, const unsigned char *id)
262 cdbdb648 pbrook
{
263 a7d518a6 Paul Brook
    pl011_state *s = FROM_SYSBUS(pl011_state, dev);
264 cdbdb648 pbrook
265 48484757 Avi Kivity
    memory_region_init_io(&s->iomem, &pl011_ops, s, "pl011", 0x1000);
266 750ecd44 Avi Kivity
    sysbus_init_mmio(dev, &s->iomem);
267 a7d518a6 Paul Brook
    sysbus_init_irq(dev, &s->irq);
268 a7d518a6 Paul Brook
    s->id = id;
269 0beb4942 Anthony Liguori
    s->chr = qemu_char_get_next_serial();
270 a7d518a6 Paul Brook
271 cdbdb648 pbrook
    s->read_trigger = 1;
272 cdbdb648 pbrook
    s->ifl = 0x12;
273 cdbdb648 pbrook
    s->cr = 0x300;
274 cdbdb648 pbrook
    s->flags = 0x90;
275 a7d518a6 Paul Brook
    if (s->chr) {
276 a7d518a6 Paul Brook
        qemu_chr_add_handlers(s->chr, pl011_can_receive, pl011_receive,
277 e5b0bc44 pbrook
                              pl011_event, s);
278 cdbdb648 pbrook
    }
279 02b68757 Juan Quintela
    vmstate_register(&dev->qdev, -1, &vmstate_pl011, s);
280 81a322d4 Gerd Hoffmann
    return 0;
281 cdbdb648 pbrook
}
282 a7d518a6 Paul Brook
283 999e12bb Anthony Liguori
static int pl011_arm_init(SysBusDevice *dev)
284 a7d518a6 Paul Brook
{
285 81a322d4 Gerd Hoffmann
    return pl011_init(dev, pl011_id_arm);
286 a7d518a6 Paul Brook
}
287 a7d518a6 Paul Brook
288 999e12bb Anthony Liguori
static int pl011_luminary_init(SysBusDevice *dev)
289 a7d518a6 Paul Brook
{
290 81a322d4 Gerd Hoffmann
    return pl011_init(dev, pl011_id_luminary);
291 a7d518a6 Paul Brook
}
292 a7d518a6 Paul Brook
293 999e12bb Anthony Liguori
static void pl011_arm_class_init(ObjectClass *klass, void *data)
294 999e12bb Anthony Liguori
{
295 999e12bb Anthony Liguori
    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
296 999e12bb Anthony Liguori
297 999e12bb Anthony Liguori
    sdc->init = pl011_arm_init;
298 999e12bb Anthony Liguori
}
299 999e12bb Anthony Liguori
300 39bffca2 Anthony Liguori
static TypeInfo pl011_arm_info = {
301 39bffca2 Anthony Liguori
    .name          = "pl011",
302 39bffca2 Anthony Liguori
    .parent        = TYPE_SYS_BUS_DEVICE,
303 39bffca2 Anthony Liguori
    .instance_size = sizeof(pl011_state),
304 39bffca2 Anthony Liguori
    .class_init    = pl011_arm_class_init,
305 999e12bb Anthony Liguori
};
306 999e12bb Anthony Liguori
307 999e12bb Anthony Liguori
static void pl011_luminary_class_init(ObjectClass *klass, void *data)
308 999e12bb Anthony Liguori
{
309 999e12bb Anthony Liguori
    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
310 999e12bb Anthony Liguori
311 999e12bb Anthony Liguori
    sdc->init = pl011_luminary_init;
312 999e12bb Anthony Liguori
}
313 999e12bb Anthony Liguori
314 39bffca2 Anthony Liguori
static TypeInfo pl011_luminary_info = {
315 39bffca2 Anthony Liguori
    .name          = "pl011_luminary",
316 39bffca2 Anthony Liguori
    .parent        = TYPE_SYS_BUS_DEVICE,
317 39bffca2 Anthony Liguori
    .instance_size = sizeof(pl011_state),
318 39bffca2 Anthony Liguori
    .class_init    = pl011_luminary_class_init,
319 999e12bb Anthony Liguori
};
320 999e12bb Anthony Liguori
321 83f7d43a Andreas Färber
static void pl011_register_types(void)
322 a7d518a6 Paul Brook
{
323 39bffca2 Anthony Liguori
    type_register_static(&pl011_arm_info);
324 39bffca2 Anthony Liguori
    type_register_static(&pl011_luminary_info);
325 a7d518a6 Paul Brook
}
326 a7d518a6 Paul Brook
327 83f7d43a Andreas Färber
type_init(pl011_register_types)