qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

imx7_ccm.c (8851B)


      1 /*
      2  * Copyright (c) 2018, Impinj, Inc.
      3  *
      4  * i.MX7 CCM, PMU and ANALOG IP blocks 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 "qemu/log.h"
     14 #include "qemu/module.h"
     15 
     16 #include "hw/misc/imx7_ccm.h"
     17 #include "migration/vmstate.h"
     18 
     19 static void imx7_analog_reset(DeviceState *dev)
     20 {
     21     IMX7AnalogState *s = IMX7_ANALOG(dev);
     22 
     23     memset(s->pmu, 0, sizeof(s->pmu));
     24     memset(s->analog, 0, sizeof(s->analog));
     25 
     26     s->analog[ANALOG_PLL_ARM]         = 0x00002042;
     27     s->analog[ANALOG_PLL_DDR]         = 0x0060302c;
     28     s->analog[ANALOG_PLL_DDR_SS]      = 0x00000000;
     29     s->analog[ANALOG_PLL_DDR_NUM]     = 0x06aaac4d;
     30     s->analog[ANALOG_PLL_DDR_DENOM]   = 0x100003ec;
     31     s->analog[ANALOG_PLL_480]         = 0x00002000;
     32     s->analog[ANALOG_PLL_480A]        = 0x52605a56;
     33     s->analog[ANALOG_PLL_480B]        = 0x52525216;
     34     s->analog[ANALOG_PLL_ENET]        = 0x00001fc0;
     35     s->analog[ANALOG_PLL_AUDIO]       = 0x0001301b;
     36     s->analog[ANALOG_PLL_AUDIO_SS]    = 0x00000000;
     37     s->analog[ANALOG_PLL_AUDIO_NUM]   = 0x05f5e100;
     38     s->analog[ANALOG_PLL_AUDIO_DENOM] = 0x2964619c;
     39     s->analog[ANALOG_PLL_VIDEO]       = 0x0008201b;
     40     s->analog[ANALOG_PLL_VIDEO_SS]    = 0x00000000;
     41     s->analog[ANALOG_PLL_VIDEO_NUM]   = 0x0000f699;
     42     s->analog[ANALOG_PLL_VIDEO_DENOM] = 0x000f4240;
     43     s->analog[ANALOG_PLL_MISC0]       = 0x00000000;
     44 
     45     /* all PLLs need to be locked */
     46     s->analog[ANALOG_PLL_ARM]   |= ANALOG_PLL_LOCK;
     47     s->analog[ANALOG_PLL_DDR]   |= ANALOG_PLL_LOCK;
     48     s->analog[ANALOG_PLL_480]   |= ANALOG_PLL_LOCK;
     49     s->analog[ANALOG_PLL_480A]  |= ANALOG_PLL_LOCK;
     50     s->analog[ANALOG_PLL_480B]  |= ANALOG_PLL_LOCK;
     51     s->analog[ANALOG_PLL_ENET]  |= ANALOG_PLL_LOCK;
     52     s->analog[ANALOG_PLL_AUDIO] |= ANALOG_PLL_LOCK;
     53     s->analog[ANALOG_PLL_VIDEO] |= ANALOG_PLL_LOCK;
     54     s->analog[ANALOG_PLL_MISC0] |= ANALOG_PLL_LOCK;
     55 
     56     /*
     57      * Since I couldn't find any info about this in the reference
     58      * manual the value of this register is based strictly on matching
     59      * what Linux kernel expects it to be.
     60      */
     61     s->analog[ANALOG_DIGPROG]  = 0x720000;
     62     /*
     63      * Set revision to be 1.0 (Arbitrary choice, no particular
     64      * reason).
     65      */
     66     s->analog[ANALOG_DIGPROG] |= 0x000010;
     67 }
     68 
     69 static void imx7_ccm_reset(DeviceState *dev)
     70 {
     71     IMX7CCMState *s = IMX7_CCM(dev);
     72 
     73     memset(s->ccm, 0, sizeof(s->ccm));
     74 }
     75 
     76 #define CCM_INDEX(offset)   (((offset) & ~(hwaddr)0xF) / sizeof(uint32_t))
     77 #define CCM_BITOP(offset)   ((offset) & (hwaddr)0xF)
     78 
     79 enum {
     80     CCM_BITOP_NONE = 0x00,
     81     CCM_BITOP_SET  = 0x04,
     82     CCM_BITOP_CLR  = 0x08,
     83     CCM_BITOP_TOG  = 0x0C,
     84 };
     85 
     86 static uint64_t imx7_set_clr_tog_read(void *opaque, hwaddr offset,
     87                                       unsigned size)
     88 {
     89     const uint32_t *mmio = opaque;
     90 
     91     return mmio[CCM_INDEX(offset)];
     92 }
     93 
     94 static void imx7_set_clr_tog_write(void *opaque, hwaddr offset,
     95                                    uint64_t value, unsigned size)
     96 {
     97     const uint8_t  bitop = CCM_BITOP(offset);
     98     const uint32_t index = CCM_INDEX(offset);
     99     uint32_t *mmio = opaque;
    100 
    101     switch (bitop) {
    102     case CCM_BITOP_NONE:
    103         mmio[index]  = value;
    104         break;
    105     case CCM_BITOP_SET:
    106         mmio[index] |= value;
    107         break;
    108     case CCM_BITOP_CLR:
    109         mmio[index] &= ~value;
    110         break;
    111     case CCM_BITOP_TOG:
    112         mmio[index] ^= value;
    113         break;
    114     };
    115 }
    116 
    117 static const struct MemoryRegionOps imx7_set_clr_tog_ops = {
    118     .read = imx7_set_clr_tog_read,
    119     .write = imx7_set_clr_tog_write,
    120     .endianness = DEVICE_NATIVE_ENDIAN,
    121     .impl = {
    122         /*
    123          * Our device would not work correctly if the guest was doing
    124          * unaligned access. This might not be a limitation on the real
    125          * device but in practice there is no reason for a guest to access
    126          * this device unaligned.
    127          */
    128         .min_access_size = 4,
    129         .max_access_size = 4,
    130         .unaligned = false,
    131     },
    132 };
    133 
    134 static void imx7_digprog_write(void *opaque, hwaddr addr,
    135                                         uint64_t data, unsigned size)
    136 {
    137     qemu_log_mask(LOG_GUEST_ERROR,
    138                   "Guest write to read-only ANALOG_DIGPROG register\n");
    139 }
    140 
    141 static const struct MemoryRegionOps imx7_digprog_ops = {
    142     .read = imx7_set_clr_tog_read,
    143     .write = imx7_digprog_write,
    144     .endianness = DEVICE_NATIVE_ENDIAN,
    145     .impl = {
    146         .min_access_size = 4,
    147         .max_access_size = 4,
    148         .unaligned = false,
    149     },
    150 };
    151 
    152 static void imx7_ccm_init(Object *obj)
    153 {
    154     SysBusDevice *sd = SYS_BUS_DEVICE(obj);
    155     IMX7CCMState *s = IMX7_CCM(obj);
    156 
    157     memory_region_init_io(&s->iomem,
    158                           obj,
    159                           &imx7_set_clr_tog_ops,
    160                           s->ccm,
    161                           TYPE_IMX7_CCM ".ccm",
    162                           sizeof(s->ccm));
    163 
    164     sysbus_init_mmio(sd, &s->iomem);
    165 }
    166 
    167 static void imx7_analog_init(Object *obj)
    168 {
    169     SysBusDevice *sd = SYS_BUS_DEVICE(obj);
    170     IMX7AnalogState *s = IMX7_ANALOG(obj);
    171 
    172     memory_region_init(&s->mmio.container, obj, TYPE_IMX7_ANALOG,
    173                        0x10000);
    174 
    175     memory_region_init_io(&s->mmio.analog,
    176                           obj,
    177                           &imx7_set_clr_tog_ops,
    178                           s->analog,
    179                           TYPE_IMX7_ANALOG,
    180                           sizeof(s->analog));
    181 
    182     memory_region_add_subregion(&s->mmio.container,
    183                                 0x60, &s->mmio.analog);
    184 
    185     memory_region_init_io(&s->mmio.pmu,
    186                           obj,
    187                           &imx7_set_clr_tog_ops,
    188                           s->pmu,
    189                           TYPE_IMX7_ANALOG ".pmu",
    190                           sizeof(s->pmu));
    191 
    192     memory_region_add_subregion(&s->mmio.container,
    193                                 0x200, &s->mmio.pmu);
    194 
    195     memory_region_init_io(&s->mmio.digprog,
    196                           obj,
    197                           &imx7_digprog_ops,
    198                           &s->analog[ANALOG_DIGPROG],
    199                           TYPE_IMX7_ANALOG ".digprog",
    200                           sizeof(uint32_t));
    201 
    202     memory_region_add_subregion_overlap(&s->mmio.container,
    203                                         0x800, &s->mmio.digprog, 10);
    204 
    205 
    206     sysbus_init_mmio(sd, &s->mmio.container);
    207 }
    208 
    209 static const VMStateDescription vmstate_imx7_ccm = {
    210     .name = TYPE_IMX7_CCM,
    211     .version_id = 1,
    212     .minimum_version_id = 1,
    213     .fields = (VMStateField[]) {
    214         VMSTATE_UINT32_ARRAY(ccm, IMX7CCMState, CCM_MAX),
    215         VMSTATE_END_OF_LIST()
    216     },
    217 };
    218 
    219 static uint32_t imx7_ccm_get_clock_frequency(IMXCCMState *dev, IMXClk clock)
    220 {
    221     /*
    222      * This function is "consumed" by GPT emulation code, however on
    223      * i.MX7 each GPT block can have their own clock root. This means
    224      * that this functions needs somehow to know requester's identity
    225      * and the way to pass it: be it via additional IMXClk constants
    226      * or by adding another argument to this method needs to be
    227      * figured out
    228      */
    229     qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Not implemented\n",
    230                   TYPE_IMX7_CCM, __func__);
    231     return 0;
    232 }
    233 
    234 static void imx7_ccm_class_init(ObjectClass *klass, void *data)
    235 {
    236     DeviceClass *dc = DEVICE_CLASS(klass);
    237     IMXCCMClass *ccm = IMX_CCM_CLASS(klass);
    238 
    239     dc->reset = imx7_ccm_reset;
    240     dc->vmsd  = &vmstate_imx7_ccm;
    241     dc->desc  = "i.MX7 Clock Control Module";
    242 
    243     ccm->get_clock_frequency = imx7_ccm_get_clock_frequency;
    244 }
    245 
    246 static const TypeInfo imx7_ccm_info = {
    247     .name          = TYPE_IMX7_CCM,
    248     .parent        = TYPE_IMX_CCM,
    249     .instance_size = sizeof(IMX7CCMState),
    250     .instance_init = imx7_ccm_init,
    251     .class_init    = imx7_ccm_class_init,
    252 };
    253 
    254 static const VMStateDescription vmstate_imx7_analog = {
    255     .name = TYPE_IMX7_ANALOG,
    256     .version_id = 1,
    257     .minimum_version_id = 1,
    258     .fields = (VMStateField[]) {
    259         VMSTATE_UINT32_ARRAY(analog, IMX7AnalogState, ANALOG_MAX),
    260         VMSTATE_UINT32_ARRAY(pmu,    IMX7AnalogState, PMU_MAX),
    261         VMSTATE_END_OF_LIST()
    262     },
    263 };
    264 
    265 static void imx7_analog_class_init(ObjectClass *klass, void *data)
    266 {
    267     DeviceClass *dc = DEVICE_CLASS(klass);
    268 
    269     dc->reset = imx7_analog_reset;
    270     dc->vmsd  = &vmstate_imx7_analog;
    271     dc->desc  = "i.MX7 Analog Module";
    272 }
    273 
    274 static const TypeInfo imx7_analog_info = {
    275     .name          = TYPE_IMX7_ANALOG,
    276     .parent        = TYPE_SYS_BUS_DEVICE,
    277     .instance_size = sizeof(IMX7AnalogState),
    278     .instance_init = imx7_analog_init,
    279     .class_init    = imx7_analog_class_init,
    280 };
    281 
    282 static void imx7_ccm_register_type(void)
    283 {
    284     type_register_static(&imx7_ccm_info);
    285     type_register_static(&imx7_analog_info);
    286 }
    287 type_init(imx7_ccm_register_type)