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