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