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