cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

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
     19static 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
     69static 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
     79enum {
     80    CCM_BITOP_NONE = 0x00,
     81    CCM_BITOP_SET  = 0x04,
     82    CCM_BITOP_CLR  = 0x08,
     83    CCM_BITOP_TOG  = 0x0C,
     84};
     85
     86static 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
     94static 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
    117static 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
    134static 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
    141static 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
    152static 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
    167static 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
    209static 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
    219static 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
    234static 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
    246static 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
    254static 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
    265static 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
    274static 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
    282static void imx7_ccm_register_type(void)
    283{
    284    type_register_static(&imx7_ccm_info);
    285    type_register_static(&imx7_analog_info);
    286}
    287type_init(imx7_ccm_register_type)