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