xref: /qemu/hw/char/sifive_uart.c (revision ccf86c392c5b8949bafd363e44d3abb112578044)
1  /*
2   * QEMU model of the UART on the SiFive E300 and U500 series SOCs.
3   *
4   * Copyright (c) 2016 Stefan O'Rear
5   *
6   * This program is free software; you can redistribute it and/or modify it
7   * under the terms and conditions of the GNU General Public License,
8   * version 2 or later, as published by the Free Software Foundation.
9   *
10   * This program is distributed in the hope it will be useful, but WITHOUT
11   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13   * more details.
14   *
15   * You should have received a copy of the GNU General Public License along with
16   * this program.  If not, see <http://www.gnu.org/licenses/>.
17   */
18  
19  #include "qemu/osdep.h"
20  #include "qapi/error.h"
21  #include "qemu/log.h"
22  #include "migration/vmstate.h"
23  #include "chardev/char.h"
24  #include "chardev/char-fe.h"
25  #include "hw/irq.h"
26  #include "hw/char/sifive_uart.h"
27  #include "hw/qdev-properties-system.h"
28  
29  #define TX_INTERRUPT_TRIGGER_DELAY_NS 100
30  
31  /*
32   * Not yet implemented:
33   *
34   * Transmit FIFO using "qemu/fifo8.h"
35   */
36  
37  /* Returns the state of the IP (interrupt pending) register */
38  static uint64_t sifive_uart_ip(SiFiveUARTState *s)
39  {
40      uint64_t ret = 0;
41  
42      uint64_t txcnt = SIFIVE_UART_GET_TXCNT(s->txctrl);
43      uint64_t rxcnt = SIFIVE_UART_GET_RXCNT(s->rxctrl);
44  
45      if (txcnt != 0) {
46          ret |= SIFIVE_UART_IP_TXWM;
47      }
48      if (s->rx_fifo_len > rxcnt) {
49          ret |= SIFIVE_UART_IP_RXWM;
50      }
51  
52      return ret;
53  }
54  
55  static void sifive_uart_update_irq(SiFiveUARTState *s)
56  {
57      int cond = 0;
58      if ((s->ie & SIFIVE_UART_IE_TXWM) ||
59          ((s->ie & SIFIVE_UART_IE_RXWM) && s->rx_fifo_len)) {
60          cond = 1;
61      }
62      if (cond) {
63          qemu_irq_raise(s->irq);
64      } else {
65          qemu_irq_lower(s->irq);
66      }
67  }
68  
69  static gboolean sifive_uart_xmit(void *do_not_use, GIOCondition cond,
70                                   void *opaque)
71  {
72      SiFiveUARTState *s = opaque;
73      int ret;
74      const uint8_t *characters;
75      uint32_t numptr = 0;
76  
77      /* instant drain the fifo when there's no back-end */
78      if (!qemu_chr_fe_backend_connected(&s->chr)) {
79          fifo8_reset(&s->tx_fifo);
80          return G_SOURCE_REMOVE;
81      }
82  
83      if (fifo8_is_empty(&s->tx_fifo)) {
84          return G_SOURCE_REMOVE;
85      }
86  
87      /* Don't pop the FIFO in case the write fails */
88      characters = fifo8_peek_bufptr(&s->tx_fifo,
89                                     fifo8_num_used(&s->tx_fifo), &numptr);
90      ret = qemu_chr_fe_write(&s->chr, characters, numptr);
91  
92      if (ret >= 0) {
93          /* We wrote the data, actually pop the fifo */
94          fifo8_pop_bufptr(&s->tx_fifo, ret, NULL);
95      }
96  
97      if (!fifo8_is_empty(&s->tx_fifo)) {
98          guint r = qemu_chr_fe_add_watch(&s->chr, G_IO_OUT | G_IO_HUP,
99                                          sifive_uart_xmit, s);
100          if (!r) {
101              fifo8_reset(&s->tx_fifo);
102              return G_SOURCE_REMOVE;
103          }
104      }
105  
106      /* Clear the TX Full bit */
107      if (!fifo8_is_full(&s->tx_fifo)) {
108          s->txfifo &= ~SIFIVE_UART_TXFIFO_FULL;
109      }
110  
111      sifive_uart_update_irq(s);
112      return G_SOURCE_REMOVE;
113  }
114  
115  static void sifive_uart_write_tx_fifo(SiFiveUARTState *s, const uint8_t *buf,
116                                        int size)
117  {
118      uint64_t current_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
119  
120      if (size > fifo8_num_free(&s->tx_fifo)) {
121          size = fifo8_num_free(&s->tx_fifo);
122          qemu_log_mask(LOG_GUEST_ERROR, "sifive_uart: TX FIFO overflow");
123      }
124  
125      fifo8_push_all(&s->tx_fifo, buf, size);
126  
127      if (fifo8_is_full(&s->tx_fifo)) {
128          s->txfifo |= SIFIVE_UART_TXFIFO_FULL;
129      }
130  
131      timer_mod(s->fifo_trigger_handle, current_time +
132                    TX_INTERRUPT_TRIGGER_DELAY_NS);
133  }
134  
135  static uint64_t
136  sifive_uart_read(void *opaque, hwaddr addr, unsigned int size)
137  {
138      SiFiveUARTState *s = opaque;
139      unsigned char r;
140      switch (addr) {
141      case SIFIVE_UART_RXFIFO:
142          if (s->rx_fifo_len) {
143              r = s->rx_fifo[0];
144              memmove(s->rx_fifo, s->rx_fifo + 1, s->rx_fifo_len - 1);
145              s->rx_fifo_len--;
146              qemu_chr_fe_accept_input(&s->chr);
147              sifive_uart_update_irq(s);
148              return r;
149          }
150          return 0x80000000;
151  
152      case SIFIVE_UART_TXFIFO:
153          return s->txfifo;
154      case SIFIVE_UART_IE:
155          return s->ie;
156      case SIFIVE_UART_IP:
157          return sifive_uart_ip(s);
158      case SIFIVE_UART_TXCTRL:
159          return s->txctrl;
160      case SIFIVE_UART_RXCTRL:
161          return s->rxctrl;
162      case SIFIVE_UART_DIV:
163          return s->div;
164      }
165  
166      qemu_log_mask(LOG_GUEST_ERROR, "%s: bad read: addr=0x%x\n",
167                    __func__, (int)addr);
168      return 0;
169  }
170  
171  static void
172  sifive_uart_write(void *opaque, hwaddr addr,
173                    uint64_t val64, unsigned int size)
174  {
175      SiFiveUARTState *s = opaque;
176      uint32_t value = val64;
177      uint8_t ch = value;
178  
179      switch (addr) {
180      case SIFIVE_UART_TXFIFO:
181          sifive_uart_write_tx_fifo(s, &ch, 1);
182          return;
183      case SIFIVE_UART_IE:
184          s->ie = val64;
185          sifive_uart_update_irq(s);
186          return;
187      case SIFIVE_UART_TXCTRL:
188          s->txctrl = val64;
189          return;
190      case SIFIVE_UART_RXCTRL:
191          s->rxctrl = val64;
192          return;
193      case SIFIVE_UART_DIV:
194          s->div = val64;
195          return;
196      }
197      qemu_log_mask(LOG_GUEST_ERROR, "%s: bad write: addr=0x%x v=0x%x\n",
198                    __func__, (int)addr, (int)value);
199  }
200  
201  static void fifo_trigger_update(void *opaque)
202  {
203      SiFiveUARTState *s = opaque;
204  
205      sifive_uart_xmit(NULL, G_IO_OUT, s);
206  }
207  
208  static const MemoryRegionOps sifive_uart_ops = {
209      .read = sifive_uart_read,
210      .write = sifive_uart_write,
211      .endianness = DEVICE_NATIVE_ENDIAN,
212      .valid = {
213          .min_access_size = 4,
214          .max_access_size = 4
215      }
216  };
217  
218  static void sifive_uart_rx(void *opaque, const uint8_t *buf, int size)
219  {
220      SiFiveUARTState *s = opaque;
221  
222      /* Got a byte.  */
223      if (s->rx_fifo_len >= sizeof(s->rx_fifo)) {
224          printf("WARNING: UART dropped char.\n");
225          return;
226      }
227      s->rx_fifo[s->rx_fifo_len++] = *buf;
228  
229      sifive_uart_update_irq(s);
230  }
231  
232  static int sifive_uart_can_rx(void *opaque)
233  {
234      SiFiveUARTState *s = opaque;
235  
236      return s->rx_fifo_len < sizeof(s->rx_fifo);
237  }
238  
239  static void sifive_uart_event(void *opaque, QEMUChrEvent event)
240  {
241  }
242  
243  static int sifive_uart_be_change(void *opaque)
244  {
245      SiFiveUARTState *s = opaque;
246  
247      qemu_chr_fe_set_handlers(&s->chr, sifive_uart_can_rx, sifive_uart_rx,
248                               sifive_uart_event, sifive_uart_be_change, s,
249                               NULL, true);
250  
251      return 0;
252  }
253  
254  static const Property sifive_uart_properties[] = {
255      DEFINE_PROP_CHR("chardev", SiFiveUARTState, chr),
256  };
257  
258  static void sifive_uart_init(Object *obj)
259  {
260      SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
261      SiFiveUARTState *s = SIFIVE_UART(obj);
262  
263      memory_region_init_io(&s->mmio, OBJECT(s), &sifive_uart_ops, s,
264                            TYPE_SIFIVE_UART, SIFIVE_UART_MAX);
265      sysbus_init_mmio(sbd, &s->mmio);
266      sysbus_init_irq(sbd, &s->irq);
267  }
268  
269  static void sifive_uart_realize(DeviceState *dev, Error **errp)
270  {
271      SiFiveUARTState *s = SIFIVE_UART(dev);
272  
273      s->fifo_trigger_handle = timer_new_ns(QEMU_CLOCK_VIRTUAL,
274                                            fifo_trigger_update, s);
275  
276      qemu_chr_fe_set_handlers(&s->chr, sifive_uart_can_rx, sifive_uart_rx,
277                               sifive_uart_event, sifive_uart_be_change, s,
278                               NULL, true);
279  
280  }
281  
282  static void sifive_uart_reset_enter(Object *obj, ResetType type)
283  {
284      SiFiveUARTState *s = SIFIVE_UART(obj);
285  
286      s->txfifo = 0;
287      s->ie = 0;
288      s->ip = 0;
289      s->txctrl = 0;
290      s->rxctrl = 0;
291      s->div = 0;
292  
293      s->rx_fifo_len = 0;
294  
295      memset(s->rx_fifo, 0, SIFIVE_UART_RX_FIFO_SIZE);
296      fifo8_create(&s->tx_fifo, SIFIVE_UART_TX_FIFO_SIZE);
297  }
298  
299  static void sifive_uart_reset_hold(Object *obj, ResetType type)
300  {
301      SiFiveUARTState *s = SIFIVE_UART(obj);
302      qemu_irq_lower(s->irq);
303  }
304  
305  static const VMStateDescription vmstate_sifive_uart = {
306      .name = TYPE_SIFIVE_UART,
307      .version_id = 2,
308      .minimum_version_id = 2,
309      .fields = (const VMStateField[]) {
310          VMSTATE_UINT8_ARRAY(rx_fifo, SiFiveUARTState,
311                              SIFIVE_UART_RX_FIFO_SIZE),
312          VMSTATE_UINT8(rx_fifo_len, SiFiveUARTState),
313          VMSTATE_UINT32(ie, SiFiveUARTState),
314          VMSTATE_UINT32(ip, SiFiveUARTState),
315          VMSTATE_UINT32(txctrl, SiFiveUARTState),
316          VMSTATE_UINT32(rxctrl, SiFiveUARTState),
317          VMSTATE_UINT32(div, SiFiveUARTState),
318          VMSTATE_UINT32(txfifo, SiFiveUARTState),
319          VMSTATE_FIFO8(tx_fifo, SiFiveUARTState),
320          VMSTATE_TIMER_PTR(fifo_trigger_handle, SiFiveUARTState),
321          VMSTATE_END_OF_LIST()
322      },
323  };
324  
325  
326  static void sifive_uart_class_init(ObjectClass *oc, void *data)
327  {
328      DeviceClass *dc = DEVICE_CLASS(oc);
329      ResettableClass *rc = RESETTABLE_CLASS(oc);
330  
331      dc->realize = sifive_uart_realize;
332      dc->vmsd = &vmstate_sifive_uart;
333      rc->phases.enter = sifive_uart_reset_enter;
334      rc->phases.hold  = sifive_uart_reset_hold;
335      device_class_set_props(dc, sifive_uart_properties);
336      set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
337  }
338  
339  static const TypeInfo sifive_uart_info = {
340      .name          = TYPE_SIFIVE_UART,
341      .parent        = TYPE_SYS_BUS_DEVICE,
342      .instance_size = sizeof(SiFiveUARTState),
343      .instance_init = sifive_uart_init,
344      .class_init    = sifive_uart_class_init,
345  };
346  
347  static void sifive_uart_register_types(void)
348  {
349      type_register_static(&sifive_uart_info);
350  }
351  
352  type_init(sifive_uart_register_types)
353  
354  /*
355   * Create UART device.
356   */
357  SiFiveUARTState *sifive_uart_create(MemoryRegion *address_space, hwaddr base,
358      Chardev *chr, qemu_irq irq)
359  {
360      DeviceState *dev;
361      SysBusDevice *s;
362  
363      dev = qdev_new("riscv.sifive.uart");
364      s = SYS_BUS_DEVICE(dev);
365      qdev_prop_set_chr(dev, "chardev", chr);
366      sysbus_realize_and_unref(s, &error_fatal);
367      memory_region_add_subregion(address_space, base,
368                                  sysbus_mmio_get_region(s, 0));
369      sysbus_connect_irq(s, 0, irq);
370  
371      return SIFIVE_UART(dev);
372  }
373