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
imx_gpcv2_reset(DeviceState * dev)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
imx_gpcv2_read(void * opaque,hwaddr offset,unsigned size)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
imx_gpcv2_write(void * opaque,hwaddr offset,uint64_t value,unsigned size)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
imx_gpcv2_init(Object * obj)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
imx_gpcv2_class_init(ObjectClass * klass,const void * data)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
imx_gpcv2_register_type(void)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