qemu/hw/misc/imx6_src.c
<<
>>
Prefs
   1/*
   2 * IMX6 System Reset Controller
   3 *
   4 * Copyright (c) 2015 Jean-Christophe Dubois <jcd@tribudubois.net>
   5 *
   6 * This work is licensed under the terms of the GNU GPL, version 2 or later.
   7 * See the COPYING file in the top-level directory.
   8 *
   9 */
  10
  11#include "qemu/osdep.h"
  12#include "hw/misc/imx6_src.h"
  13#include "sysemu/sysemu.h"
  14#include "qemu/bitops.h"
  15#include "qemu/log.h"
  16#include "arm-powerctl.h"
  17
  18#ifndef DEBUG_IMX6_SRC
  19#define DEBUG_IMX6_SRC 0
  20#endif
  21
  22#define DPRINTF(fmt, args...) \
  23    do { \
  24        if (DEBUG_IMX6_SRC) { \
  25            fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX6_SRC, \
  26                                             __func__, ##args); \
  27        } \
  28    } while (0)
  29
  30static char const *imx6_src_reg_name(uint32_t reg)
  31{
  32    static char unknown[20];
  33
  34    switch (reg) {
  35    case SRC_SCR:
  36        return "SRC_SCR";
  37    case SRC_SBMR1:
  38        return "SRC_SBMR1";
  39    case SRC_SRSR:
  40        return "SRC_SRSR";
  41    case SRC_SISR:
  42        return "SRC_SISR";
  43    case SRC_SIMR:
  44        return "SRC_SIMR";
  45    case SRC_SBMR2:
  46        return "SRC_SBMR2";
  47    case SRC_GPR1:
  48        return "SRC_GPR1";
  49    case SRC_GPR2:
  50        return "SRC_GPR2";
  51    case SRC_GPR3:
  52        return "SRC_GPR3";
  53    case SRC_GPR4:
  54        return "SRC_GPR4";
  55    case SRC_GPR5:
  56        return "SRC_GPR5";
  57    case SRC_GPR6:
  58        return "SRC_GPR6";
  59    case SRC_GPR7:
  60        return "SRC_GPR7";
  61    case SRC_GPR8:
  62        return "SRC_GPR8";
  63    case SRC_GPR9:
  64        return "SRC_GPR9";
  65    case SRC_GPR10:
  66        return "SRC_GPR10";
  67    default:
  68        sprintf(unknown, "%d ?", reg);
  69        return unknown;
  70    }
  71}
  72
  73static const VMStateDescription vmstate_imx6_src = {
  74    .name = TYPE_IMX6_SRC,
  75    .version_id = 1,
  76    .minimum_version_id = 1,
  77    .fields = (VMStateField[]) {
  78        VMSTATE_UINT32_ARRAY(regs, IMX6SRCState, SRC_MAX),
  79        VMSTATE_END_OF_LIST()
  80    },
  81};
  82
  83static void imx6_src_reset(DeviceState *dev)
  84{
  85    IMX6SRCState *s = IMX6_SRC(dev);
  86
  87    DPRINTF("\n");
  88
  89    memset(s->regs, 0, sizeof(s->regs));
  90
  91    /* Set reset values */
  92    s->regs[SRC_SCR] = 0x521;
  93    s->regs[SRC_SRSR] = 0x1;
  94    s->regs[SRC_SIMR] = 0x1F;
  95}
  96
  97static uint64_t imx6_src_read(void *opaque, hwaddr offset, unsigned size)
  98{
  99    uint32_t value = 0;
 100    IMX6SRCState *s = (IMX6SRCState *)opaque;
 101    uint32_t index = offset >> 2;
 102
 103    if (index < SRC_MAX) {
 104        value = s->regs[index];
 105    } else {
 106        qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
 107                      HWADDR_PRIx "\n", TYPE_IMX6_SRC, __func__, offset);
 108
 109    }
 110
 111    DPRINTF("reg[%s] => 0x%" PRIx32 "\n", imx6_src_reg_name(index), value);
 112
 113    return value;
 114}
 115
 116static void imx6_src_write(void *opaque, hwaddr offset, uint64_t value,
 117                           unsigned size)
 118{
 119    IMX6SRCState *s = (IMX6SRCState *)opaque;
 120    uint32_t index = offset >> 2;
 121    unsigned long change_mask;
 122    unsigned long current_value = value;
 123
 124    if (index >=  SRC_MAX) {
 125        qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
 126                      HWADDR_PRIx "\n", TYPE_IMX6_SRC, __func__, offset);
 127        return;
 128    }
 129
 130    DPRINTF("reg[%s] <= 0x%" PRIx32 "\n", imx6_src_reg_name(index),
 131            (uint32_t)current_value);
 132
 133    change_mask = s->regs[index] ^ (uint32_t)current_value;
 134
 135    switch (index) {
 136    case SRC_SCR:
 137        /*
 138         * On real hardware when the system reset controller starts a
 139         * secondary CPU it runs through some boot ROM code which reads
 140         * the SRC_GPRX registers controlling the start address and branches
 141         * to it.
 142         * Here we are taking a short cut and branching directly to the
 143         * requested address (we don't want to run the boot ROM code inside
 144         * QEMU)
 145         */
 146        if (EXTRACT(change_mask, CORE3_ENABLE)) {
 147            if (EXTRACT(current_value, CORE3_ENABLE)) {
 148                /* CORE 3 is brought up */
 149                arm_set_cpu_on(3, s->regs[SRC_GPR7], s->regs[SRC_GPR8],
 150                               3, false);
 151            } else {
 152                /* CORE 3 is shut down */
 153                arm_set_cpu_off(3);
 154            }
 155            /* We clear the reset bits as the processor changed state */
 156            clear_bit(CORE3_RST_SHIFT, &current_value);
 157            clear_bit(CORE3_RST_SHIFT, &change_mask);
 158        }
 159        if (EXTRACT(change_mask, CORE2_ENABLE)) {
 160            if (EXTRACT(current_value, CORE2_ENABLE)) {
 161                /* CORE 2 is brought up */
 162                arm_set_cpu_on(2, s->regs[SRC_GPR5], s->regs[SRC_GPR6],
 163                               3, false);
 164            } else {
 165                /* CORE 3 is shut down */
 166                arm_set_cpu_off(2);
 167            }
 168            /* We clear the reset bits as the processor changed state */
 169            clear_bit(CORE2_RST_SHIFT, &current_value);
 170            clear_bit(CORE2_RST_SHIFT, &change_mask);
 171        }
 172        if (EXTRACT(change_mask, CORE1_ENABLE)) {
 173            if (EXTRACT(current_value, CORE1_ENABLE)) {
 174                /* CORE 1 is brought up */
 175                arm_set_cpu_on(1, s->regs[SRC_GPR3], s->regs[SRC_GPR4],
 176                               3, false);
 177            } else {
 178                /* CORE 3 is shut down */
 179                arm_set_cpu_off(1);
 180            }
 181            /* We clear the reset bits as the processor changed state */
 182            clear_bit(CORE1_RST_SHIFT, &current_value);
 183            clear_bit(CORE1_RST_SHIFT, &change_mask);
 184        }
 185        if (EXTRACT(change_mask, CORE0_RST)) {
 186            arm_reset_cpu(0);
 187            clear_bit(CORE0_RST_SHIFT, &current_value);
 188        }
 189        if (EXTRACT(change_mask, CORE1_RST)) {
 190            arm_reset_cpu(1);
 191            clear_bit(CORE1_RST_SHIFT, &current_value);
 192        }
 193        if (EXTRACT(change_mask, CORE2_RST)) {
 194            arm_reset_cpu(2);
 195            clear_bit(CORE2_RST_SHIFT, &current_value);
 196        }
 197        if (EXTRACT(change_mask, CORE3_RST)) {
 198            arm_reset_cpu(3);
 199            clear_bit(CORE3_RST_SHIFT, &current_value);
 200        }
 201        if (EXTRACT(change_mask, SW_IPU2_RST)) {
 202            /* We pretend the IPU2 is reset */
 203            clear_bit(SW_IPU2_RST_SHIFT, &current_value);
 204        }
 205        if (EXTRACT(change_mask, SW_IPU1_RST)) {
 206            /* We pretend the IPU1 is reset */
 207            clear_bit(SW_IPU1_RST_SHIFT, &current_value);
 208        }
 209        s->regs[index] = current_value;
 210        break;
 211    default:
 212        s->regs[index] = current_value;
 213        break;
 214    }
 215}
 216
 217static const struct MemoryRegionOps imx6_src_ops = {
 218    .read = imx6_src_read,
 219    .write = imx6_src_write,
 220    .endianness = DEVICE_NATIVE_ENDIAN,
 221    .valid = {
 222        /*
 223         * Our device would not work correctly if the guest was doing
 224         * unaligned access. This might not be a limitation on the real
 225         * device but in practice there is no reason for a guest to access
 226         * this device unaligned.
 227         */
 228        .min_access_size = 4,
 229        .max_access_size = 4,
 230        .unaligned = false,
 231    },
 232};
 233
 234static void imx6_src_realize(DeviceState *dev, Error **errp)
 235{
 236    IMX6SRCState *s = IMX6_SRC(dev);
 237
 238    memory_region_init_io(&s->iomem, OBJECT(dev), &imx6_src_ops, s,
 239                          TYPE_IMX6_SRC, 0x1000);
 240    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
 241}
 242
 243static void imx6_src_class_init(ObjectClass *klass, void *data)
 244{
 245    DeviceClass *dc = DEVICE_CLASS(klass);
 246
 247    dc->realize = imx6_src_realize;
 248    dc->reset = imx6_src_reset;
 249    dc->vmsd = &vmstate_imx6_src;
 250    dc->desc = "i.MX6 System Reset Controller";
 251}
 252
 253static const TypeInfo imx6_src_info = {
 254    .name          = TYPE_IMX6_SRC,
 255    .parent        = TYPE_SYS_BUS_DEVICE,
 256    .instance_size = sizeof(IMX6SRCState),
 257    .class_init    = imx6_src_class_init,
 258};
 259
 260static void imx6_src_register_types(void)
 261{
 262    type_register_static(&imx6_src_info);
 263}
 264
 265type_init(imx6_src_register_types)
 266