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