pci_bridge: simplify memory regions some more
[qemu.git] / hw / pl011.c
blob707a161046e8d6be22e37823d059a401e18576e1
1 /*
2 * Arm PrimeCell PL011 UART
4 * Copyright (c) 2006 CodeSourcery.
5 * Written by Paul Brook
7 * This code is licensed under the GPL.
8 */
10 #include "sysbus.h"
11 #include "qemu-char.h"
13 typedef struct {
14 SysBusDevice busdev;
15 uint32_t readbuff;
16 uint32_t flags;
17 uint32_t lcr;
18 uint32_t cr;
19 uint32_t dmacr;
20 uint32_t int_enabled;
21 uint32_t int_level;
22 uint32_t read_fifo[16];
23 uint32_t ilpr;
24 uint32_t ibrd;
25 uint32_t fbrd;
26 uint32_t ifl;
27 int read_pos;
28 int read_count;
29 int read_trigger;
30 CharDriverState *chr;
31 qemu_irq irq;
32 const unsigned char *id;
33 } pl011_state;
35 #define PL011_INT_TX 0x20
36 #define PL011_INT_RX 0x10
38 #define PL011_FLAG_TXFE 0x80
39 #define PL011_FLAG_RXFF 0x40
40 #define PL011_FLAG_TXFF 0x20
41 #define PL011_FLAG_RXFE 0x10
43 static const unsigned char pl011_id_arm[8] =
44 { 0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
45 static const unsigned char pl011_id_luminary[8] =
46 { 0x11, 0x00, 0x18, 0x01, 0x0d, 0xf0, 0x05, 0xb1 };
48 static void pl011_update(pl011_state *s)
50 uint32_t flags;
52 flags = s->int_level & s->int_enabled;
53 qemu_set_irq(s->irq, flags != 0);
56 static uint32_t pl011_read(void *opaque, target_phys_addr_t offset)
58 pl011_state *s = (pl011_state *)opaque;
59 uint32_t c;
61 if (offset >= 0xfe0 && offset < 0x1000) {
62 return s->id[(offset - 0xfe0) >> 2];
64 switch (offset >> 2) {
65 case 0: /* UARTDR */
66 s->flags &= ~PL011_FLAG_RXFF;
67 c = s->read_fifo[s->read_pos];
68 if (s->read_count > 0) {
69 s->read_count--;
70 if (++s->read_pos == 16)
71 s->read_pos = 0;
73 if (s->read_count == 0) {
74 s->flags |= PL011_FLAG_RXFE;
76 if (s->read_count == s->read_trigger - 1)
77 s->int_level &= ~ PL011_INT_RX;
78 pl011_update(s);
79 qemu_chr_accept_input(s->chr);
80 return c;
81 case 1: /* UARTCR */
82 return 0;
83 case 6: /* UARTFR */
84 return s->flags;
85 case 8: /* UARTILPR */
86 return s->ilpr;
87 case 9: /* UARTIBRD */
88 return s->ibrd;
89 case 10: /* UARTFBRD */
90 return s->fbrd;
91 case 11: /* UARTLCR_H */
92 return s->lcr;
93 case 12: /* UARTCR */
94 return s->cr;
95 case 13: /* UARTIFLS */
96 return s->ifl;
97 case 14: /* UARTIMSC */
98 return s->int_enabled;
99 case 15: /* UARTRIS */
100 return s->int_level;
101 case 16: /* UARTMIS */
102 return s->int_level & s->int_enabled;
103 case 18: /* UARTDMACR */
104 return s->dmacr;
105 default:
106 hw_error("pl011_read: Bad offset %x\n", (int)offset);
107 return 0;
111 static void pl011_set_read_trigger(pl011_state *s)
113 #if 0
114 /* The docs say the RX interrupt is triggered when the FIFO exceeds
115 the threshold. However linux only reads the FIFO in response to an
116 interrupt. Triggering the interrupt when the FIFO is non-empty seems
117 to make things work. */
118 if (s->lcr & 0x10)
119 s->read_trigger = (s->ifl >> 1) & 0x1c;
120 else
121 #endif
122 s->read_trigger = 1;
125 static void pl011_write(void *opaque, target_phys_addr_t offset,
126 uint32_t value)
128 pl011_state *s = (pl011_state *)opaque;
129 unsigned char ch;
131 switch (offset >> 2) {
132 case 0: /* UARTDR */
133 /* ??? Check if transmitter is enabled. */
134 ch = value;
135 if (s->chr)
136 qemu_chr_fe_write(s->chr, &ch, 1);
137 s->int_level |= PL011_INT_TX;
138 pl011_update(s);
139 break;
140 case 1: /* UARTCR */
141 s->cr = value;
142 break;
143 case 6: /* UARTFR */
144 /* Writes to Flag register are ignored. */
145 break;
146 case 8: /* UARTUARTILPR */
147 s->ilpr = value;
148 break;
149 case 9: /* UARTIBRD */
150 s->ibrd = value;
151 break;
152 case 10: /* UARTFBRD */
153 s->fbrd = value;
154 break;
155 case 11: /* UARTLCR_H */
156 s->lcr = value;
157 pl011_set_read_trigger(s);
158 break;
159 case 12: /* UARTCR */
160 /* ??? Need to implement the enable and loopback bits. */
161 s->cr = value;
162 break;
163 case 13: /* UARTIFS */
164 s->ifl = value;
165 pl011_set_read_trigger(s);
166 break;
167 case 14: /* UARTIMSC */
168 s->int_enabled = value;
169 pl011_update(s);
170 break;
171 case 17: /* UARTICR */
172 s->int_level &= ~value;
173 pl011_update(s);
174 break;
175 case 18: /* UARTDMACR */
176 s->dmacr = value;
177 if (value & 3)
178 hw_error("PL011: DMA not implemented\n");
179 break;
180 default:
181 hw_error("pl011_write: Bad offset %x\n", (int)offset);
185 static int pl011_can_receive(void *opaque)
187 pl011_state *s = (pl011_state *)opaque;
189 if (s->lcr & 0x10)
190 return s->read_count < 16;
191 else
192 return s->read_count < 1;
195 static void pl011_put_fifo(void *opaque, uint32_t value)
197 pl011_state *s = (pl011_state *)opaque;
198 int slot;
200 slot = s->read_pos + s->read_count;
201 if (slot >= 16)
202 slot -= 16;
203 s->read_fifo[slot] = value;
204 s->read_count++;
205 s->flags &= ~PL011_FLAG_RXFE;
206 if (s->cr & 0x10 || s->read_count == 16) {
207 s->flags |= PL011_FLAG_RXFF;
209 if (s->read_count == s->read_trigger) {
210 s->int_level |= PL011_INT_RX;
211 pl011_update(s);
215 static void pl011_receive(void *opaque, const uint8_t *buf, int size)
217 pl011_put_fifo(opaque, *buf);
220 static void pl011_event(void *opaque, int event)
222 if (event == CHR_EVENT_BREAK)
223 pl011_put_fifo(opaque, 0x400);
226 static CPUReadMemoryFunc * const pl011_readfn[] = {
227 pl011_read,
228 pl011_read,
229 pl011_read
232 static CPUWriteMemoryFunc * const pl011_writefn[] = {
233 pl011_write,
234 pl011_write,
235 pl011_write
238 static const VMStateDescription vmstate_pl011 = {
239 .name = "pl011",
240 .version_id = 1,
241 .minimum_version_id = 1,
242 .minimum_version_id_old = 1,
243 .fields = (VMStateField[]) {
244 VMSTATE_UINT32(readbuff, pl011_state),
245 VMSTATE_UINT32(flags, pl011_state),
246 VMSTATE_UINT32(lcr, pl011_state),
247 VMSTATE_UINT32(cr, pl011_state),
248 VMSTATE_UINT32(dmacr, pl011_state),
249 VMSTATE_UINT32(int_enabled, pl011_state),
250 VMSTATE_UINT32(int_level, pl011_state),
251 VMSTATE_UINT32_ARRAY(read_fifo, pl011_state, 16),
252 VMSTATE_UINT32(ilpr, pl011_state),
253 VMSTATE_UINT32(ibrd, pl011_state),
254 VMSTATE_UINT32(fbrd, pl011_state),
255 VMSTATE_UINT32(ifl, pl011_state),
256 VMSTATE_INT32(read_pos, pl011_state),
257 VMSTATE_INT32(read_count, pl011_state),
258 VMSTATE_INT32(read_trigger, pl011_state),
259 VMSTATE_END_OF_LIST()
263 static int pl011_init(SysBusDevice *dev, const unsigned char *id)
265 int iomemtype;
266 pl011_state *s = FROM_SYSBUS(pl011_state, dev);
268 iomemtype = cpu_register_io_memory(pl011_readfn,
269 pl011_writefn, s,
270 DEVICE_NATIVE_ENDIAN);
271 sysbus_init_mmio(dev, 0x1000,iomemtype);
272 sysbus_init_irq(dev, &s->irq);
273 s->id = id;
274 s->chr = qdev_init_chardev(&dev->qdev);
276 s->read_trigger = 1;
277 s->ifl = 0x12;
278 s->cr = 0x300;
279 s->flags = 0x90;
280 if (s->chr) {
281 qemu_chr_add_handlers(s->chr, pl011_can_receive, pl011_receive,
282 pl011_event, s);
284 vmstate_register(&dev->qdev, -1, &vmstate_pl011, s);
285 return 0;
288 static int pl011_init_arm(SysBusDevice *dev)
290 return pl011_init(dev, pl011_id_arm);
293 static int pl011_init_luminary(SysBusDevice *dev)
295 return pl011_init(dev, pl011_id_luminary);
298 static void pl011_register_devices(void)
300 sysbus_register_dev("pl011", sizeof(pl011_state),
301 pl011_init_arm);
302 sysbus_register_dev("pl011_luminary", sizeof(pl011_state),
303 pl011_init_luminary);
306 device_init(pl011_register_devices)