Statistics
| Branch: | Revision:

root / hw / pl011.c @ 0dad6c35

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