xref: /openbmc/qemu/hw/char/pl011.c (revision 988717b46b6424907618cb845ace9d69062703af)
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  /*
11   * QEMU interface:
12   *  + sysbus MMIO region 0: device registers
13   *  + sysbus IRQ 0: UARTINTR (combined interrupt line)
14   *  + sysbus IRQ 1: UARTRXINTR (receive FIFO interrupt line)
15   *  + sysbus IRQ 2: UARTTXINTR (transmit FIFO interrupt line)
16   *  + sysbus IRQ 3: UARTRTINTR (receive timeout interrupt line)
17   *  + sysbus IRQ 4: UARTMSINTR (momem status interrupt line)
18   *  + sysbus IRQ 5: UARTEINTR (error interrupt line)
19   */
20  
21  #include "qemu/osdep.h"
22  #include "hw/char/pl011.h"
23  #include "hw/irq.h"
24  #include "hw/sysbus.h"
25  #include "migration/vmstate.h"
26  #include "chardev/char-fe.h"
27  #include "qemu/log.h"
28  #include "qemu/module.h"
29  #include "trace.h"
30  
31  #define PL011_INT_TX 0x20
32  #define PL011_INT_RX 0x10
33  
34  #define PL011_FLAG_TXFE 0x80
35  #define PL011_FLAG_RXFF 0x40
36  #define PL011_FLAG_TXFF 0x20
37  #define PL011_FLAG_RXFE 0x10
38  
39  /* Interrupt status bits in UARTRIS, UARTMIS, UARTIMSC */
40  #define INT_OE (1 << 10)
41  #define INT_BE (1 << 9)
42  #define INT_PE (1 << 8)
43  #define INT_FE (1 << 7)
44  #define INT_RT (1 << 6)
45  #define INT_TX (1 << 5)
46  #define INT_RX (1 << 4)
47  #define INT_DSR (1 << 3)
48  #define INT_DCD (1 << 2)
49  #define INT_CTS (1 << 1)
50  #define INT_RI (1 << 0)
51  #define INT_E (INT_OE | INT_BE | INT_PE | INT_FE)
52  #define INT_MS (INT_RI | INT_DSR | INT_DCD | INT_CTS)
53  
54  static const unsigned char pl011_id_arm[8] =
55    { 0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
56  static const unsigned char pl011_id_luminary[8] =
57    { 0x11, 0x00, 0x18, 0x01, 0x0d, 0xf0, 0x05, 0xb1 };
58  
59  /* Which bits in the interrupt status matter for each outbound IRQ line ? */
60  static const uint32_t irqmask[] = {
61      INT_E | INT_MS | INT_RT | INT_TX | INT_RX, /* combined IRQ */
62      INT_RX,
63      INT_TX,
64      INT_RT,
65      INT_MS,
66      INT_E,
67  };
68  
69  static void pl011_update(PL011State *s)
70  {
71      uint32_t flags;
72      int i;
73  
74      flags = s->int_level & s->int_enabled;
75      trace_pl011_irq_state(flags != 0);
76      for (i = 0; i < ARRAY_SIZE(s->irq); i++) {
77          qemu_set_irq(s->irq[i], (flags & irqmask[i]) != 0);
78      }
79  }
80  
81  static uint64_t pl011_read(void *opaque, hwaddr offset,
82                             unsigned size)
83  {
84      PL011State *s = (PL011State *)opaque;
85      uint32_t c;
86      uint64_t r;
87  
88      switch (offset >> 2) {
89      case 0: /* UARTDR */
90          s->flags &= ~PL011_FLAG_RXFF;
91          c = s->read_fifo[s->read_pos];
92          if (s->read_count > 0) {
93              s->read_count--;
94              if (++s->read_pos == 16)
95                  s->read_pos = 0;
96          }
97          if (s->read_count == 0) {
98              s->flags |= PL011_FLAG_RXFE;
99          }
100          if (s->read_count == s->read_trigger - 1)
101              s->int_level &= ~ PL011_INT_RX;
102          trace_pl011_read_fifo(s->read_count);
103          s->rsr = c >> 8;
104          pl011_update(s);
105          qemu_chr_fe_accept_input(&s->chr);
106          r = c;
107          break;
108      case 1: /* UARTRSR */
109          r = s->rsr;
110          break;
111      case 6: /* UARTFR */
112          r = s->flags;
113          break;
114      case 8: /* UARTILPR */
115          r = s->ilpr;
116          break;
117      case 9: /* UARTIBRD */
118          r = s->ibrd;
119          break;
120      case 10: /* UARTFBRD */
121          r = s->fbrd;
122          break;
123      case 11: /* UARTLCR_H */
124          r = s->lcr;
125          break;
126      case 12: /* UARTCR */
127          r = s->cr;
128          break;
129      case 13: /* UARTIFLS */
130          r = s->ifl;
131          break;
132      case 14: /* UARTIMSC */
133          r = s->int_enabled;
134          break;
135      case 15: /* UARTRIS */
136          r = s->int_level;
137          break;
138      case 16: /* UARTMIS */
139          r = s->int_level & s->int_enabled;
140          break;
141      case 18: /* UARTDMACR */
142          r = s->dmacr;
143          break;
144      case 0x3f8 ... 0x400:
145          r = s->id[(offset - 0xfe0) >> 2];
146          break;
147      default:
148          qemu_log_mask(LOG_GUEST_ERROR,
149                        "pl011_read: Bad offset 0x%x\n", (int)offset);
150          r = 0;
151          break;
152      }
153  
154      trace_pl011_read(offset, r);
155      return r;
156  }
157  
158  static void pl011_set_read_trigger(PL011State *s)
159  {
160  #if 0
161      /* The docs say the RX interrupt is triggered when the FIFO exceeds
162         the threshold.  However linux only reads the FIFO in response to an
163         interrupt.  Triggering the interrupt when the FIFO is non-empty seems
164         to make things work.  */
165      if (s->lcr & 0x10)
166          s->read_trigger = (s->ifl >> 1) & 0x1c;
167      else
168  #endif
169          s->read_trigger = 1;
170  }
171  
172  static void pl011_write(void *opaque, hwaddr offset,
173                          uint64_t value, unsigned size)
174  {
175      PL011State *s = (PL011State *)opaque;
176      unsigned char ch;
177  
178      trace_pl011_write(offset, value);
179  
180      switch (offset >> 2) {
181      case 0: /* UARTDR */
182          /* ??? Check if transmitter is enabled.  */
183          ch = value;
184          /* XXX this blocks entire thread. Rewrite to use
185           * qemu_chr_fe_write and background I/O callbacks */
186          qemu_chr_fe_write_all(&s->chr, &ch, 1);
187          s->int_level |= PL011_INT_TX;
188          pl011_update(s);
189          break;
190      case 1: /* UARTRSR/UARTECR */
191          s->rsr = 0;
192          break;
193      case 6: /* UARTFR */
194          /* Writes to Flag register are ignored.  */
195          break;
196      case 8: /* UARTUARTILPR */
197          s->ilpr = value;
198          break;
199      case 9: /* UARTIBRD */
200          s->ibrd = value;
201          break;
202      case 10: /* UARTFBRD */
203          s->fbrd = value;
204          break;
205      case 11: /* UARTLCR_H */
206          /* Reset the FIFO state on FIFO enable or disable */
207          if ((s->lcr ^ value) & 0x10) {
208              s->read_count = 0;
209              s->read_pos = 0;
210          }
211          s->lcr = value;
212          pl011_set_read_trigger(s);
213          break;
214      case 12: /* UARTCR */
215          /* ??? Need to implement the enable and loopback bits.  */
216          s->cr = value;
217          break;
218      case 13: /* UARTIFS */
219          s->ifl = value;
220          pl011_set_read_trigger(s);
221          break;
222      case 14: /* UARTIMSC */
223          s->int_enabled = value;
224          pl011_update(s);
225          break;
226      case 17: /* UARTICR */
227          s->int_level &= ~value;
228          pl011_update(s);
229          break;
230      case 18: /* UARTDMACR */
231          s->dmacr = value;
232          if (value & 3) {
233              qemu_log_mask(LOG_UNIMP, "pl011: DMA not implemented\n");
234          }
235          break;
236      default:
237          qemu_log_mask(LOG_GUEST_ERROR,
238                        "pl011_write: Bad offset 0x%x\n", (int)offset);
239      }
240  }
241  
242  static int pl011_can_receive(void *opaque)
243  {
244      PL011State *s = (PL011State *)opaque;
245      int r;
246  
247      if (s->lcr & 0x10) {
248          r = s->read_count < 16;
249      } else {
250          r = s->read_count < 1;
251      }
252      trace_pl011_can_receive(s->lcr, s->read_count, r);
253      return r;
254  }
255  
256  static void pl011_put_fifo(void *opaque, uint32_t value)
257  {
258      PL011State *s = (PL011State *)opaque;
259      int slot;
260  
261      slot = s->read_pos + s->read_count;
262      if (slot >= 16)
263          slot -= 16;
264      s->read_fifo[slot] = value;
265      s->read_count++;
266      s->flags &= ~PL011_FLAG_RXFE;
267      trace_pl011_put_fifo(value, s->read_count);
268      if (!(s->lcr & 0x10) || s->read_count == 16) {
269          trace_pl011_put_fifo_full();
270          s->flags |= PL011_FLAG_RXFF;
271      }
272      if (s->read_count == s->read_trigger) {
273          s->int_level |= PL011_INT_RX;
274          pl011_update(s);
275      }
276  }
277  
278  static void pl011_receive(void *opaque, const uint8_t *buf, int size)
279  {
280      pl011_put_fifo(opaque, *buf);
281  }
282  
283  static void pl011_event(void *opaque, QEMUChrEvent event)
284  {
285      if (event == CHR_EVENT_BREAK)
286          pl011_put_fifo(opaque, 0x400);
287  }
288  
289  static const MemoryRegionOps pl011_ops = {
290      .read = pl011_read,
291      .write = pl011_write,
292      .endianness = DEVICE_NATIVE_ENDIAN,
293  };
294  
295  static const VMStateDescription vmstate_pl011 = {
296      .name = "pl011",
297      .version_id = 2,
298      .minimum_version_id = 2,
299      .fields = (VMStateField[]) {
300          VMSTATE_UINT32(readbuff, PL011State),
301          VMSTATE_UINT32(flags, PL011State),
302          VMSTATE_UINT32(lcr, PL011State),
303          VMSTATE_UINT32(rsr, PL011State),
304          VMSTATE_UINT32(cr, PL011State),
305          VMSTATE_UINT32(dmacr, PL011State),
306          VMSTATE_UINT32(int_enabled, PL011State),
307          VMSTATE_UINT32(int_level, PL011State),
308          VMSTATE_UINT32_ARRAY(read_fifo, PL011State, 16),
309          VMSTATE_UINT32(ilpr, PL011State),
310          VMSTATE_UINT32(ibrd, PL011State),
311          VMSTATE_UINT32(fbrd, PL011State),
312          VMSTATE_UINT32(ifl, PL011State),
313          VMSTATE_INT32(read_pos, PL011State),
314          VMSTATE_INT32(read_count, PL011State),
315          VMSTATE_INT32(read_trigger, PL011State),
316          VMSTATE_END_OF_LIST()
317      }
318  };
319  
320  static Property pl011_properties[] = {
321      DEFINE_PROP_CHR("chardev", PL011State, chr),
322      DEFINE_PROP_END_OF_LIST(),
323  };
324  
325  static void pl011_init(Object *obj)
326  {
327      SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
328      PL011State *s = PL011(obj);
329      int i;
330  
331      memory_region_init_io(&s->iomem, OBJECT(s), &pl011_ops, s, "pl011", 0x1000);
332      sysbus_init_mmio(sbd, &s->iomem);
333      for (i = 0; i < ARRAY_SIZE(s->irq); i++) {
334          sysbus_init_irq(sbd, &s->irq[i]);
335      }
336  
337      s->read_trigger = 1;
338      s->ifl = 0x12;
339      s->cr = 0x300;
340      s->flags = 0x90;
341  
342      s->id = pl011_id_arm;
343  }
344  
345  static void pl011_realize(DeviceState *dev, Error **errp)
346  {
347      PL011State *s = PL011(dev);
348  
349      qemu_chr_fe_set_handlers(&s->chr, pl011_can_receive, pl011_receive,
350                               pl011_event, NULL, s, NULL, true);
351  }
352  
353  static void pl011_class_init(ObjectClass *oc, void *data)
354  {
355      DeviceClass *dc = DEVICE_CLASS(oc);
356  
357      dc->realize = pl011_realize;
358      dc->vmsd = &vmstate_pl011;
359      device_class_set_props(dc, pl011_properties);
360  }
361  
362  static const TypeInfo pl011_arm_info = {
363      .name          = TYPE_PL011,
364      .parent        = TYPE_SYS_BUS_DEVICE,
365      .instance_size = sizeof(PL011State),
366      .instance_init = pl011_init,
367      .class_init    = pl011_class_init,
368  };
369  
370  static void pl011_luminary_init(Object *obj)
371  {
372      PL011State *s = PL011(obj);
373  
374      s->id = pl011_id_luminary;
375  }
376  
377  static const TypeInfo pl011_luminary_info = {
378      .name          = TYPE_PL011_LUMINARY,
379      .parent        = TYPE_PL011,
380      .instance_init = pl011_luminary_init,
381  };
382  
383  static void pl011_register_types(void)
384  {
385      type_register_static(&pl011_arm_info);
386      type_register_static(&pl011_luminary_info);
387  }
388  
389  type_init(pl011_register_types)
390