2
0

sifive_uart.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  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. #include "qemu/osdep.h"
  19. #include "qapi/error.h"
  20. #include "qemu/log.h"
  21. #include "hw/sysbus.h"
  22. #include "chardev/char.h"
  23. #include "chardev/char-fe.h"
  24. #include "hw/hw.h"
  25. #include "hw/irq.h"
  26. #include "hw/riscv/sifive_uart.h"
  27. /*
  28. * Not yet implemented:
  29. *
  30. * Transmit FIFO using "qemu/fifo8.h"
  31. */
  32. /* Returns the state of the IP (interrupt pending) register */
  33. static uint64_t uart_ip(SiFiveUARTState *s)
  34. {
  35. uint64_t ret = 0;
  36. uint64_t txcnt = SIFIVE_UART_GET_TXCNT(s->txctrl);
  37. uint64_t rxcnt = SIFIVE_UART_GET_RXCNT(s->rxctrl);
  38. if (txcnt != 0) {
  39. ret |= SIFIVE_UART_IP_TXWM;
  40. }
  41. if (s->rx_fifo_len > rxcnt) {
  42. ret |= SIFIVE_UART_IP_RXWM;
  43. }
  44. return ret;
  45. }
  46. static void update_irq(SiFiveUARTState *s)
  47. {
  48. int cond = 0;
  49. if ((s->ie & SIFIVE_UART_IE_TXWM) ||
  50. ((s->ie & SIFIVE_UART_IE_RXWM) && s->rx_fifo_len)) {
  51. cond = 1;
  52. }
  53. if (cond) {
  54. qemu_irq_raise(s->irq);
  55. } else {
  56. qemu_irq_lower(s->irq);
  57. }
  58. }
  59. static uint64_t
  60. uart_read(void *opaque, hwaddr addr, unsigned int size)
  61. {
  62. SiFiveUARTState *s = opaque;
  63. unsigned char r;
  64. switch (addr) {
  65. case SIFIVE_UART_RXFIFO:
  66. if (s->rx_fifo_len) {
  67. r = s->rx_fifo[0];
  68. memmove(s->rx_fifo, s->rx_fifo + 1, s->rx_fifo_len - 1);
  69. s->rx_fifo_len--;
  70. qemu_chr_fe_accept_input(&s->chr);
  71. update_irq(s);
  72. return r;
  73. }
  74. return 0x80000000;
  75. case SIFIVE_UART_TXFIFO:
  76. return 0; /* Should check tx fifo */
  77. case SIFIVE_UART_IE:
  78. return s->ie;
  79. case SIFIVE_UART_IP:
  80. return uart_ip(s);
  81. case SIFIVE_UART_TXCTRL:
  82. return s->txctrl;
  83. case SIFIVE_UART_RXCTRL:
  84. return s->rxctrl;
  85. case SIFIVE_UART_DIV:
  86. return s->div;
  87. }
  88. qemu_log_mask(LOG_GUEST_ERROR, "%s: bad read: addr=0x%x\n",
  89. __func__, (int)addr);
  90. return 0;
  91. }
  92. static void
  93. uart_write(void *opaque, hwaddr addr,
  94. uint64_t val64, unsigned int size)
  95. {
  96. SiFiveUARTState *s = opaque;
  97. uint32_t value = val64;
  98. unsigned char ch = value;
  99. switch (addr) {
  100. case SIFIVE_UART_TXFIFO:
  101. qemu_chr_fe_write(&s->chr, &ch, 1);
  102. update_irq(s);
  103. return;
  104. case SIFIVE_UART_IE:
  105. s->ie = val64;
  106. update_irq(s);
  107. return;
  108. case SIFIVE_UART_TXCTRL:
  109. s->txctrl = val64;
  110. return;
  111. case SIFIVE_UART_RXCTRL:
  112. s->rxctrl = val64;
  113. return;
  114. case SIFIVE_UART_DIV:
  115. s->div = val64;
  116. return;
  117. }
  118. qemu_log_mask(LOG_GUEST_ERROR, "%s: bad write: addr=0x%x v=0x%x\n",
  119. __func__, (int)addr, (int)value);
  120. }
  121. static const MemoryRegionOps uart_ops = {
  122. .read = uart_read,
  123. .write = uart_write,
  124. .endianness = DEVICE_NATIVE_ENDIAN,
  125. .valid = {
  126. .min_access_size = 4,
  127. .max_access_size = 4
  128. }
  129. };
  130. static void uart_rx(void *opaque, const uint8_t *buf, int size)
  131. {
  132. SiFiveUARTState *s = opaque;
  133. /* Got a byte. */
  134. if (s->rx_fifo_len >= sizeof(s->rx_fifo)) {
  135. printf("WARNING: UART dropped char.\n");
  136. return;
  137. }
  138. s->rx_fifo[s->rx_fifo_len++] = *buf;
  139. update_irq(s);
  140. }
  141. static int uart_can_rx(void *opaque)
  142. {
  143. SiFiveUARTState *s = opaque;
  144. return s->rx_fifo_len < sizeof(s->rx_fifo);
  145. }
  146. static void uart_event(void *opaque, int event)
  147. {
  148. }
  149. static int uart_be_change(void *opaque)
  150. {
  151. SiFiveUARTState *s = opaque;
  152. qemu_chr_fe_set_handlers(&s->chr, uart_can_rx, uart_rx, uart_event,
  153. uart_be_change, s, NULL, true);
  154. return 0;
  155. }
  156. /*
  157. * Create UART device.
  158. */
  159. SiFiveUARTState *sifive_uart_create(MemoryRegion *address_space, hwaddr base,
  160. Chardev *chr, qemu_irq irq)
  161. {
  162. SiFiveUARTState *s = g_malloc0(sizeof(SiFiveUARTState));
  163. s->irq = irq;
  164. qemu_chr_fe_init(&s->chr, chr, &error_abort);
  165. qemu_chr_fe_set_handlers(&s->chr, uart_can_rx, uart_rx, uart_event,
  166. uart_be_change, s, NULL, true);
  167. memory_region_init_io(&s->mmio, NULL, &uart_ops, s,
  168. TYPE_SIFIVE_UART, SIFIVE_UART_MAX);
  169. memory_region_add_subregion(address_space, base, &s->mmio);
  170. return s;
  171. }