bcm2835_aux.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. /*
  2. * BCM2835 (Raspberry Pi / Pi 2) Aux block (mini UART and SPI).
  3. * Copyright (c) 2015, Microsoft
  4. * Written by Andrew Baumann
  5. * Based on pl011.c, copyright terms below:
  6. *
  7. * Arm PrimeCell PL011 UART
  8. *
  9. * Copyright (c) 2006 CodeSourcery.
  10. * Written by Paul Brook
  11. *
  12. * This code is licensed under the GPL.
  13. *
  14. * At present only the core UART functions (data path for tx/rx) are
  15. * implemented. The following features/registers are unimplemented:
  16. * - Line/modem control
  17. * - Scratch register
  18. * - Extra control
  19. * - Baudrate
  20. * - SPI interfaces
  21. */
  22. #include "qemu/osdep.h"
  23. #include "hw/char/bcm2835_aux.h"
  24. #include "hw/irq.h"
  25. #include "hw/qdev-properties.h"
  26. #include "hw/qdev-properties-system.h"
  27. #include "migration/vmstate.h"
  28. #include "qemu/log.h"
  29. #include "qemu/module.h"
  30. #define AUX_IRQ 0x0
  31. #define AUX_ENABLES 0x4
  32. #define AUX_MU_IO_REG 0x40
  33. #define AUX_MU_IER_REG 0x44
  34. #define AUX_MU_IIR_REG 0x48
  35. #define AUX_MU_LCR_REG 0x4c
  36. #define AUX_MU_MCR_REG 0x50
  37. #define AUX_MU_LSR_REG 0x54
  38. #define AUX_MU_MSR_REG 0x58
  39. #define AUX_MU_SCRATCH 0x5c
  40. #define AUX_MU_CNTL_REG 0x60
  41. #define AUX_MU_STAT_REG 0x64
  42. #define AUX_MU_BAUD_REG 0x68
  43. /* bits in IER/IIR registers */
  44. #define RX_INT 0x1
  45. #define TX_INT 0x2
  46. static void bcm2835_aux_update(BCM2835AuxState *s)
  47. {
  48. /* signal an interrupt if either:
  49. * 1. rx interrupt is enabled and we have a non-empty rx fifo, or
  50. * 2. the tx interrupt is enabled (since we instantly drain the tx fifo)
  51. */
  52. s->iir = 0;
  53. if ((s->ier & RX_INT) && s->read_count != 0) {
  54. s->iir |= RX_INT;
  55. }
  56. if (s->ier & TX_INT) {
  57. s->iir |= TX_INT;
  58. }
  59. qemu_set_irq(s->irq, s->iir != 0);
  60. }
  61. static uint64_t bcm2835_aux_read(void *opaque, hwaddr offset, unsigned size)
  62. {
  63. BCM2835AuxState *s = opaque;
  64. uint32_t c, res;
  65. switch (offset) {
  66. case AUX_IRQ:
  67. return s->iir != 0;
  68. case AUX_ENABLES:
  69. return 1; /* mini UART permanently enabled */
  70. case AUX_MU_IO_REG:
  71. /* "DLAB bit set means access baudrate register" is NYI */
  72. c = s->read_fifo[s->read_pos];
  73. if (s->read_count > 0) {
  74. s->read_count--;
  75. if (++s->read_pos == BCM2835_AUX_RX_FIFO_LEN) {
  76. s->read_pos = 0;
  77. }
  78. }
  79. qemu_chr_fe_accept_input(&s->chr);
  80. bcm2835_aux_update(s);
  81. return c;
  82. case AUX_MU_IER_REG:
  83. /* "DLAB bit set means access baudrate register" is NYI */
  84. return 0xc0 | s->ier; /* FIFO enables always read 1 */
  85. case AUX_MU_IIR_REG:
  86. res = 0xc0; /* FIFO enables */
  87. /* The spec is unclear on what happens when both tx and rx
  88. * interrupts are active, besides that this cannot occur. At
  89. * present, we choose to prioritise the rx interrupt, since
  90. * the tx fifo is always empty. */
  91. if ((s->iir & RX_INT) && s->read_count != 0) {
  92. res |= 0x4;
  93. } else {
  94. res |= 0x2;
  95. }
  96. if (s->iir == 0) {
  97. res |= 0x1;
  98. }
  99. return res;
  100. case AUX_MU_LCR_REG:
  101. qemu_log_mask(LOG_UNIMP, "%s: AUX_MU_LCR_REG unsupported\n", __func__);
  102. return 0;
  103. case AUX_MU_MCR_REG:
  104. qemu_log_mask(LOG_UNIMP, "%s: AUX_MU_MCR_REG unsupported\n", __func__);
  105. return 0;
  106. case AUX_MU_LSR_REG:
  107. res = 0x60; /* tx idle, empty */
  108. if (s->read_count != 0) {
  109. res |= 0x1;
  110. }
  111. return res;
  112. case AUX_MU_MSR_REG:
  113. qemu_log_mask(LOG_UNIMP, "%s: AUX_MU_MSR_REG unsupported\n", __func__);
  114. return 0;
  115. case AUX_MU_SCRATCH:
  116. qemu_log_mask(LOG_UNIMP, "%s: AUX_MU_SCRATCH unsupported\n", __func__);
  117. return 0;
  118. case AUX_MU_CNTL_REG:
  119. return 0x3; /* tx, rx enabled */
  120. case AUX_MU_STAT_REG:
  121. res = 0x30e; /* space in the output buffer, empty tx fifo, idle tx/rx */
  122. if (s->read_count > 0) {
  123. res |= 0x1; /* data in input buffer */
  124. assert(s->read_count <= BCM2835_AUX_RX_FIFO_LEN);
  125. res |= ((uint32_t)s->read_count) << 16; /* rx fifo fill level */
  126. }
  127. return res;
  128. case AUX_MU_BAUD_REG:
  129. qemu_log_mask(LOG_UNIMP, "%s: AUX_MU_BAUD_REG unsupported\n", __func__);
  130. return 0;
  131. default:
  132. qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
  133. __func__, offset);
  134. return 0;
  135. }
  136. }
  137. static void bcm2835_aux_write(void *opaque, hwaddr offset, uint64_t value,
  138. unsigned size)
  139. {
  140. BCM2835AuxState *s = opaque;
  141. unsigned char ch;
  142. switch (offset) {
  143. case AUX_ENABLES:
  144. if (value != 1) {
  145. qemu_log_mask(LOG_UNIMP, "%s: unsupported attempt to enable SPI"
  146. " or disable UART: 0x%"PRIx64"\n",
  147. __func__, value);
  148. }
  149. break;
  150. case AUX_MU_IO_REG:
  151. /* "DLAB bit set means access baudrate register" is NYI */
  152. ch = value;
  153. /* XXX this blocks entire thread. Rewrite to use
  154. * qemu_chr_fe_write and background I/O callbacks */
  155. qemu_chr_fe_write_all(&s->chr, &ch, 1);
  156. break;
  157. case AUX_MU_IER_REG:
  158. /* "DLAB bit set means access baudrate register" is NYI */
  159. s->ier = value & (TX_INT | RX_INT);
  160. bcm2835_aux_update(s);
  161. break;
  162. case AUX_MU_IIR_REG:
  163. if (value & 0x2) {
  164. s->read_count = 0;
  165. }
  166. break;
  167. case AUX_MU_LCR_REG:
  168. qemu_log_mask(LOG_UNIMP, "%s: AUX_MU_LCR_REG unsupported\n", __func__);
  169. break;
  170. case AUX_MU_MCR_REG:
  171. qemu_log_mask(LOG_UNIMP, "%s: AUX_MU_MCR_REG unsupported\n", __func__);
  172. break;
  173. case AUX_MU_SCRATCH:
  174. qemu_log_mask(LOG_UNIMP, "%s: AUX_MU_SCRATCH unsupported\n", __func__);
  175. break;
  176. case AUX_MU_CNTL_REG:
  177. qemu_log_mask(LOG_UNIMP, "%s: AUX_MU_CNTL_REG unsupported\n", __func__);
  178. break;
  179. case AUX_MU_BAUD_REG:
  180. qemu_log_mask(LOG_UNIMP, "%s: AUX_MU_BAUD_REG unsupported\n", __func__);
  181. break;
  182. default:
  183. qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
  184. __func__, offset);
  185. }
  186. bcm2835_aux_update(s);
  187. }
  188. static int bcm2835_aux_can_receive(void *opaque)
  189. {
  190. BCM2835AuxState *s = opaque;
  191. return BCM2835_AUX_RX_FIFO_LEN - s->read_count;
  192. }
  193. static void bcm2835_aux_put_fifo(void *opaque, uint8_t value)
  194. {
  195. BCM2835AuxState *s = opaque;
  196. int slot;
  197. slot = s->read_pos + s->read_count;
  198. if (slot >= BCM2835_AUX_RX_FIFO_LEN) {
  199. slot -= BCM2835_AUX_RX_FIFO_LEN;
  200. }
  201. s->read_fifo[slot] = value;
  202. s->read_count++;
  203. if (s->read_count == BCM2835_AUX_RX_FIFO_LEN) {
  204. /* buffer full */
  205. }
  206. bcm2835_aux_update(s);
  207. }
  208. static void bcm2835_aux_receive(void *opaque, const uint8_t *buf, int size)
  209. {
  210. for (int i = 0; i < size; i++) {
  211. bcm2835_aux_put_fifo(opaque, buf[i]);
  212. }
  213. }
  214. static const MemoryRegionOps bcm2835_aux_ops = {
  215. .read = bcm2835_aux_read,
  216. .write = bcm2835_aux_write,
  217. .endianness = DEVICE_NATIVE_ENDIAN,
  218. .impl.min_access_size = 4,
  219. .impl.max_access_size = 4,
  220. .valid.min_access_size = 1,
  221. .valid.max_access_size = 4,
  222. };
  223. static const VMStateDescription vmstate_bcm2835_aux = {
  224. .name = TYPE_BCM2835_AUX,
  225. .version_id = 1,
  226. .minimum_version_id = 1,
  227. .fields = (const VMStateField[]) {
  228. VMSTATE_UINT8_ARRAY(read_fifo, BCM2835AuxState,
  229. BCM2835_AUX_RX_FIFO_LEN),
  230. VMSTATE_UINT8(read_pos, BCM2835AuxState),
  231. VMSTATE_UINT8(read_count, BCM2835AuxState),
  232. VMSTATE_UINT8(ier, BCM2835AuxState),
  233. VMSTATE_UINT8(iir, BCM2835AuxState),
  234. VMSTATE_END_OF_LIST()
  235. }
  236. };
  237. static void bcm2835_aux_init(Object *obj)
  238. {
  239. SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
  240. BCM2835AuxState *s = BCM2835_AUX(obj);
  241. memory_region_init_io(&s->iomem, OBJECT(s), &bcm2835_aux_ops, s,
  242. TYPE_BCM2835_AUX, 0x100);
  243. sysbus_init_mmio(sbd, &s->iomem);
  244. sysbus_init_irq(sbd, &s->irq);
  245. }
  246. static void bcm2835_aux_realize(DeviceState *dev, Error **errp)
  247. {
  248. BCM2835AuxState *s = BCM2835_AUX(dev);
  249. qemu_chr_fe_set_handlers(&s->chr, bcm2835_aux_can_receive,
  250. bcm2835_aux_receive, NULL, NULL, s, NULL, true);
  251. }
  252. static const Property bcm2835_aux_props[] = {
  253. DEFINE_PROP_CHR("chardev", BCM2835AuxState, chr),
  254. };
  255. static void bcm2835_aux_class_init(ObjectClass *oc, void *data)
  256. {
  257. DeviceClass *dc = DEVICE_CLASS(oc);
  258. dc->realize = bcm2835_aux_realize;
  259. dc->vmsd = &vmstate_bcm2835_aux;
  260. set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
  261. device_class_set_props(dc, bcm2835_aux_props);
  262. }
  263. static const TypeInfo bcm2835_aux_info = {
  264. .name = TYPE_BCM2835_AUX,
  265. .parent = TYPE_SYS_BUS_DEVICE,
  266. .instance_size = sizeof(BCM2835AuxState),
  267. .instance_init = bcm2835_aux_init,
  268. .class_init = bcm2835_aux_class_init,
  269. };
  270. static void bcm2835_aux_register_types(void)
  271. {
  272. type_register_static(&bcm2835_aux_info);
  273. }
  274. type_init(bcm2835_aux_register_types)