xref: /qemu/hw/intc/imx_gpcv2.c (revision e3d0814368d00e7985c31edf5d0cfce45972d4be)
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 
1050999e87fSAndrey Smirnov static void imx_gpcv2_class_init(ObjectClass *klass, void *data)
1060999e87fSAndrey Smirnov {
1070999e87fSAndrey Smirnov     DeviceClass *dc = DEVICE_CLASS(klass);
1080999e87fSAndrey Smirnov 
109*e3d08143SPeter 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