chipidea.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. /*
  2. * Copyright (c) 2018, Impinj, Inc.
  3. *
  4. * Chipidea USB block emulation code
  5. *
  6. * Author: Andrey Smirnov <andrew.smirnov@gmail.com>
  7. *
  8. * This work is licensed under the terms of the GNU GPL, version 2 or later.
  9. * See the COPYING file in the top-level directory.
  10. */
  11. #include "qemu/osdep.h"
  12. #include "hw/usb/hcd-ehci.h"
  13. #include "hw/usb/chipidea.h"
  14. #include "qemu/module.h"
  15. enum {
  16. CHIPIDEA_USBx_DCIVERSION = 0x000,
  17. CHIPIDEA_USBx_DCCPARAMS = 0x004,
  18. CHIPIDEA_USBx_DCCPARAMS_HC = BIT(8),
  19. };
  20. static uint64_t chipidea_read(void *opaque, hwaddr offset,
  21. unsigned size)
  22. {
  23. return 0;
  24. }
  25. static void chipidea_write(void *opaque, hwaddr offset,
  26. uint64_t value, unsigned size)
  27. {
  28. }
  29. static const struct MemoryRegionOps chipidea_ops = {
  30. .read = chipidea_read,
  31. .write = chipidea_write,
  32. .endianness = DEVICE_NATIVE_ENDIAN,
  33. .impl = {
  34. /*
  35. * Our device would not work correctly if the guest was doing
  36. * unaligned access. This might not be a limitation on the
  37. * real device but in practice there is no reason for a guest
  38. * to access this device unaligned.
  39. */
  40. .min_access_size = 4,
  41. .max_access_size = 4,
  42. .unaligned = false,
  43. },
  44. };
  45. static uint64_t chipidea_dc_read(void *opaque, hwaddr offset,
  46. unsigned size)
  47. {
  48. switch (offset) {
  49. case CHIPIDEA_USBx_DCIVERSION:
  50. return 0x1;
  51. case CHIPIDEA_USBx_DCCPARAMS:
  52. /*
  53. * Real hardware (at least i.MX7) will also report the
  54. * controller as "Device Capable" (and 8 supported endpoints),
  55. * but there doesn't seem to be much point in doing so, since
  56. * we don't emulate that part.
  57. */
  58. return CHIPIDEA_USBx_DCCPARAMS_HC;
  59. }
  60. return 0;
  61. }
  62. static void chipidea_dc_write(void *opaque, hwaddr offset,
  63. uint64_t value, unsigned size)
  64. {
  65. }
  66. static const struct MemoryRegionOps chipidea_dc_ops = {
  67. .read = chipidea_dc_read,
  68. .write = chipidea_dc_write,
  69. .endianness = DEVICE_NATIVE_ENDIAN,
  70. .impl = {
  71. /*
  72. * Our device would not work correctly if the guest was doing
  73. * unaligned access. This might not be a limitation on the real
  74. * device but in practice there is no reason for a guest to access
  75. * this device unaligned.
  76. */
  77. .min_access_size = 4,
  78. .max_access_size = 4,
  79. .unaligned = false,
  80. },
  81. };
  82. static void chipidea_init(Object *obj)
  83. {
  84. EHCIState *ehci = &SYS_BUS_EHCI(obj)->ehci;
  85. ChipideaState *ci = CHIPIDEA(obj);
  86. int i;
  87. for (i = 0; i < ARRAY_SIZE(ci->iomem); i++) {
  88. const struct {
  89. const char *name;
  90. hwaddr offset;
  91. uint64_t size;
  92. const struct MemoryRegionOps *ops;
  93. } regions[ARRAY_SIZE(ci->iomem)] = {
  94. /*
  95. * Registers located between offsets 0x000 and 0xFC
  96. */
  97. {
  98. .name = TYPE_CHIPIDEA ".misc",
  99. .offset = 0x000,
  100. .size = 0x100,
  101. .ops = &chipidea_ops,
  102. },
  103. /*
  104. * Registers located between offsets 0x1A4 and 0x1DC
  105. */
  106. {
  107. .name = TYPE_CHIPIDEA ".endpoints",
  108. .offset = 0x1A4,
  109. .size = 0x1DC - 0x1A4 + 4,
  110. .ops = &chipidea_ops,
  111. },
  112. /*
  113. * USB_x_DCIVERSION and USB_x_DCCPARAMS
  114. */
  115. {
  116. .name = TYPE_CHIPIDEA ".dc",
  117. .offset = 0x120,
  118. .size = 8,
  119. .ops = &chipidea_dc_ops,
  120. },
  121. };
  122. memory_region_init_io(&ci->iomem[i],
  123. obj,
  124. regions[i].ops,
  125. ci,
  126. regions[i].name,
  127. regions[i].size);
  128. memory_region_add_subregion(&ehci->mem,
  129. regions[i].offset,
  130. &ci->iomem[i]);
  131. }
  132. }
  133. static void chipidea_class_init(ObjectClass *klass, void *data)
  134. {
  135. DeviceClass *dc = DEVICE_CLASS(klass);
  136. SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(klass);
  137. /*
  138. * Offsets used were taken from i.MX7Dual Applications Processor
  139. * Reference Manual, Rev 0.1, p. 3177, Table 11-59
  140. */
  141. sec->capsbase = 0x100;
  142. sec->opregbase = 0x140;
  143. sec->portnr = 1;
  144. set_bit(DEVICE_CATEGORY_USB, dc->categories);
  145. dc->desc = "Chipidea USB Module";
  146. }
  147. static const TypeInfo chipidea_info = {
  148. .name = TYPE_CHIPIDEA,
  149. .parent = TYPE_SYS_BUS_EHCI,
  150. .instance_size = sizeof(ChipideaState),
  151. .instance_init = chipidea_init,
  152. .class_init = chipidea_class_init,
  153. };
  154. static void chipidea_register_type(void)
  155. {
  156. type_register_static(&chipidea_info);
  157. }
  158. type_init(chipidea_register_type)