10999e87fSAndrey Smirnov /* 20999e87fSAndrey Smirnov * Copyright (c) 2018, Impinj, Inc. 30999e87fSAndrey Smirnov * 40999e87fSAndrey Smirnov * i.MX7 GPCv2 block emulation code 50999e87fSAndrey Smirnov * 60999e87fSAndrey Smirnov * Author: Andrey Smirnov <andrew.smirnov@gmail.com> 70999e87fSAndrey Smirnov * 80999e87fSAndrey Smirnov * This work is licensed under the terms of the GNU GPL, version 2 or later. 90999e87fSAndrey Smirnov * See the COPYING file in the top-level directory. 100999e87fSAndrey Smirnov */ 110999e87fSAndrey Smirnov 120999e87fSAndrey Smirnov #include "qemu/osdep.h" 130999e87fSAndrey Smirnov #include "hw/intc/imx_gpcv2.h" 14d6454270SMarkus Armbruster #include "migration/vmstate.h" 150b8fa32fSMarkus Armbruster #include "qemu/module.h" 160999e87fSAndrey Smirnov 170999e87fSAndrey Smirnov #define GPC_PU_PGC_SW_PUP_REQ 0x0f8 180999e87fSAndrey Smirnov #define GPC_PU_PGC_SW_PDN_REQ 0x104 190999e87fSAndrey Smirnov 200999e87fSAndrey Smirnov #define USB_HSIC_PHY_SW_Pxx_REQ BIT(4) 210999e87fSAndrey Smirnov #define USB_OTG2_PHY_SW_Pxx_REQ BIT(3) 220999e87fSAndrey Smirnov #define USB_OTG1_PHY_SW_Pxx_REQ BIT(2) 230999e87fSAndrey Smirnov #define PCIE_PHY_SW_Pxx_REQ BIT(1) 240999e87fSAndrey Smirnov #define MIPI_PHY_SW_Pxx_REQ BIT(0) 250999e87fSAndrey Smirnov 260999e87fSAndrey Smirnov 270999e87fSAndrey Smirnov static void imx_gpcv2_reset(DeviceState *dev) 280999e87fSAndrey Smirnov { 290999e87fSAndrey Smirnov IMXGPCv2State *s = IMX_GPCV2(dev); 300999e87fSAndrey Smirnov 310999e87fSAndrey Smirnov memset(s->regs, 0, sizeof(s->regs)); 320999e87fSAndrey Smirnov } 330999e87fSAndrey Smirnov 340999e87fSAndrey Smirnov static uint64_t imx_gpcv2_read(void *opaque, hwaddr offset, 350999e87fSAndrey Smirnov unsigned size) 360999e87fSAndrey Smirnov { 370999e87fSAndrey Smirnov IMXGPCv2State *s = opaque; 380999e87fSAndrey Smirnov 390999e87fSAndrey Smirnov return s->regs[offset / sizeof(uint32_t)]; 400999e87fSAndrey Smirnov } 410999e87fSAndrey Smirnov 420999e87fSAndrey Smirnov static void imx_gpcv2_write(void *opaque, hwaddr offset, 430999e87fSAndrey Smirnov uint64_t value, unsigned size) 440999e87fSAndrey Smirnov { 450999e87fSAndrey Smirnov IMXGPCv2State *s = opaque; 460999e87fSAndrey Smirnov const size_t idx = offset / sizeof(uint32_t); 470999e87fSAndrey Smirnov 480999e87fSAndrey Smirnov s->regs[idx] = value; 490999e87fSAndrey Smirnov 500999e87fSAndrey Smirnov /* 510999e87fSAndrey Smirnov * Real HW will clear those bits once as a way to indicate that 520999e87fSAndrey Smirnov * power up request is complete 530999e87fSAndrey Smirnov */ 540999e87fSAndrey Smirnov if (offset == GPC_PU_PGC_SW_PUP_REQ || 550999e87fSAndrey Smirnov offset == GPC_PU_PGC_SW_PDN_REQ) { 560999e87fSAndrey Smirnov s->regs[idx] &= ~(USB_HSIC_PHY_SW_Pxx_REQ | 570999e87fSAndrey Smirnov USB_OTG2_PHY_SW_Pxx_REQ | 580999e87fSAndrey Smirnov USB_OTG1_PHY_SW_Pxx_REQ | 590999e87fSAndrey Smirnov PCIE_PHY_SW_Pxx_REQ | 600999e87fSAndrey Smirnov MIPI_PHY_SW_Pxx_REQ); 610999e87fSAndrey Smirnov } 620999e87fSAndrey Smirnov } 630999e87fSAndrey Smirnov 640999e87fSAndrey Smirnov static const struct MemoryRegionOps imx_gpcv2_ops = { 650999e87fSAndrey Smirnov .read = imx_gpcv2_read, 660999e87fSAndrey Smirnov .write = imx_gpcv2_write, 670999e87fSAndrey Smirnov .endianness = DEVICE_NATIVE_ENDIAN, 680999e87fSAndrey Smirnov .impl = { 690999e87fSAndrey Smirnov /* 700999e87fSAndrey Smirnov * Our device would not work correctly if the guest was doing 710999e87fSAndrey Smirnov * unaligned access. This might not be a limitation on the real 720999e87fSAndrey Smirnov * device but in practice there is no reason for a guest to access 730999e87fSAndrey Smirnov * this device unaligned. 740999e87fSAndrey Smirnov */ 750999e87fSAndrey Smirnov .min_access_size = 4, 760999e87fSAndrey Smirnov .max_access_size = 4, 770999e87fSAndrey Smirnov .unaligned = false, 780999e87fSAndrey Smirnov }, 790999e87fSAndrey Smirnov }; 800999e87fSAndrey Smirnov 810999e87fSAndrey Smirnov static void imx_gpcv2_init(Object *obj) 820999e87fSAndrey Smirnov { 830999e87fSAndrey Smirnov SysBusDevice *sd = SYS_BUS_DEVICE(obj); 840999e87fSAndrey Smirnov IMXGPCv2State *s = IMX_GPCV2(obj); 850999e87fSAndrey Smirnov 860999e87fSAndrey Smirnov memory_region_init_io(&s->iomem, 870999e87fSAndrey Smirnov obj, 880999e87fSAndrey Smirnov &imx_gpcv2_ops, 890999e87fSAndrey Smirnov s, 900999e87fSAndrey Smirnov TYPE_IMX_GPCV2 ".iomem", 910999e87fSAndrey Smirnov sizeof(s->regs)); 920999e87fSAndrey Smirnov sysbus_init_mmio(sd, &s->iomem); 930999e87fSAndrey Smirnov } 940999e87fSAndrey Smirnov 950999e87fSAndrey Smirnov static const VMStateDescription vmstate_imx_gpcv2 = { 960999e87fSAndrey Smirnov .name = TYPE_IMX_GPCV2, 970999e87fSAndrey Smirnov .version_id = 1, 980999e87fSAndrey Smirnov .minimum_version_id = 1, 9945b1f81dSRichard Henderson .fields = (const VMStateField[]) { 1000999e87fSAndrey Smirnov VMSTATE_UINT32_ARRAY(regs, IMXGPCv2State, GPC_NUM), 1010999e87fSAndrey Smirnov VMSTATE_END_OF_LIST() 1020999e87fSAndrey Smirnov }, 1030999e87fSAndrey Smirnov }; 1040999e87fSAndrey Smirnov 105*12d1a768SPhilippe Mathieu-Daudé static void imx_gpcv2_class_init(ObjectClass *klass, const void *data) 1060999e87fSAndrey Smirnov { 1070999e87fSAndrey Smirnov DeviceClass *dc = DEVICE_CLASS(klass); 1080999e87fSAndrey Smirnov 109e3d08143SPeter Maydell device_class_set_legacy_reset(dc, imx_gpcv2_reset); 1100999e87fSAndrey Smirnov dc->vmsd = &vmstate_imx_gpcv2; 1110999e87fSAndrey Smirnov dc->desc = "i.MX GPCv2 Module"; 1120999e87fSAndrey Smirnov } 1130999e87fSAndrey Smirnov 1140999e87fSAndrey Smirnov static const TypeInfo imx_gpcv2_info = { 1150999e87fSAndrey Smirnov .name = TYPE_IMX_GPCV2, 1160999e87fSAndrey Smirnov .parent = TYPE_SYS_BUS_DEVICE, 1170999e87fSAndrey Smirnov .instance_size = sizeof(IMXGPCv2State), 1180999e87fSAndrey Smirnov .instance_init = imx_gpcv2_init, 1190999e87fSAndrey Smirnov .class_init = imx_gpcv2_class_init, 1200999e87fSAndrey Smirnov }; 1210999e87fSAndrey Smirnov 1220999e87fSAndrey Smirnov static void imx_gpcv2_register_type(void) 1230999e87fSAndrey Smirnov { 1240999e87fSAndrey Smirnov type_register_static(&imx_gpcv2_info); 1250999e87fSAndrey Smirnov } 1260999e87fSAndrey Smirnov type_init(imx_gpcv2_register_type) 127