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