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