chipidea.c 4.9 KB

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