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