imx_gpcv2.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. /*
  2. * Copyright (c) 2018, Impinj, Inc.
  3. *
  4. * i.MX7 GPCv2 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/intc/imx_gpcv2.h"
  13. #include "migration/vmstate.h"
  14. #include "qemu/module.h"
  15. #define GPC_PU_PGC_SW_PUP_REQ 0x0f8
  16. #define GPC_PU_PGC_SW_PDN_REQ 0x104
  17. #define USB_HSIC_PHY_SW_Pxx_REQ BIT(4)
  18. #define USB_OTG2_PHY_SW_Pxx_REQ BIT(3)
  19. #define USB_OTG1_PHY_SW_Pxx_REQ BIT(2)
  20. #define PCIE_PHY_SW_Pxx_REQ BIT(1)
  21. #define MIPI_PHY_SW_Pxx_REQ BIT(0)
  22. static void imx_gpcv2_reset(DeviceState *dev)
  23. {
  24. IMXGPCv2State *s = IMX_GPCV2(dev);
  25. memset(s->regs, 0, sizeof(s->regs));
  26. }
  27. static uint64_t imx_gpcv2_read(void *opaque, hwaddr offset,
  28. unsigned size)
  29. {
  30. IMXGPCv2State *s = opaque;
  31. return s->regs[offset / sizeof(uint32_t)];
  32. }
  33. static void imx_gpcv2_write(void *opaque, hwaddr offset,
  34. uint64_t value, unsigned size)
  35. {
  36. IMXGPCv2State *s = opaque;
  37. const size_t idx = offset / sizeof(uint32_t);
  38. s->regs[idx] = value;
  39. /*
  40. * Real HW will clear those bits once as a way to indicate that
  41. * power up request is complete
  42. */
  43. if (offset == GPC_PU_PGC_SW_PUP_REQ ||
  44. offset == GPC_PU_PGC_SW_PDN_REQ) {
  45. s->regs[idx] &= ~(USB_HSIC_PHY_SW_Pxx_REQ |
  46. USB_OTG2_PHY_SW_Pxx_REQ |
  47. USB_OTG1_PHY_SW_Pxx_REQ |
  48. PCIE_PHY_SW_Pxx_REQ |
  49. MIPI_PHY_SW_Pxx_REQ);
  50. }
  51. }
  52. static const struct MemoryRegionOps imx_gpcv2_ops = {
  53. .read = imx_gpcv2_read,
  54. .write = imx_gpcv2_write,
  55. .endianness = DEVICE_NATIVE_ENDIAN,
  56. .impl = {
  57. /*
  58. * Our device would not work correctly if the guest was doing
  59. * unaligned access. This might not be a limitation on the real
  60. * device but in practice there is no reason for a guest to access
  61. * this device unaligned.
  62. */
  63. .min_access_size = 4,
  64. .max_access_size = 4,
  65. .unaligned = false,
  66. },
  67. };
  68. static void imx_gpcv2_init(Object *obj)
  69. {
  70. SysBusDevice *sd = SYS_BUS_DEVICE(obj);
  71. IMXGPCv2State *s = IMX_GPCV2(obj);
  72. memory_region_init_io(&s->iomem,
  73. obj,
  74. &imx_gpcv2_ops,
  75. s,
  76. TYPE_IMX_GPCV2 ".iomem",
  77. sizeof(s->regs));
  78. sysbus_init_mmio(sd, &s->iomem);
  79. }
  80. static const VMStateDescription vmstate_imx_gpcv2 = {
  81. .name = TYPE_IMX_GPCV2,
  82. .version_id = 1,
  83. .minimum_version_id = 1,
  84. .fields = (const VMStateField[]) {
  85. VMSTATE_UINT32_ARRAY(regs, IMXGPCv2State, GPC_NUM),
  86. VMSTATE_END_OF_LIST()
  87. },
  88. };
  89. static void imx_gpcv2_class_init(ObjectClass *klass, void *data)
  90. {
  91. DeviceClass *dc = DEVICE_CLASS(klass);
  92. dc->reset = imx_gpcv2_reset;
  93. dc->vmsd = &vmstate_imx_gpcv2;
  94. dc->desc = "i.MX GPCv2 Module";
  95. }
  96. static const TypeInfo imx_gpcv2_info = {
  97. .name = TYPE_IMX_GPCV2,
  98. .parent = TYPE_SYS_BUS_DEVICE,
  99. .instance_size = sizeof(IMXGPCv2State),
  100. .instance_init = imx_gpcv2_init,
  101. .class_init = imx_gpcv2_class_init,
  102. };
  103. static void imx_gpcv2_register_type(void)
  104. {
  105. type_register_static(&imx_gpcv2_info);
  106. }
  107. type_init(imx_gpcv2_register_type)