1*1f93a6e4SLeon Alrae /* 2*1f93a6e4SLeon Alrae * Cluster Power Controller emulation 3*1f93a6e4SLeon Alrae * 4*1f93a6e4SLeon Alrae * Copyright (c) 2016 Imagination Technologies 5*1f93a6e4SLeon Alrae * 6*1f93a6e4SLeon Alrae * This library is free software; you can redistribute it and/or 7*1f93a6e4SLeon Alrae * modify it under the terms of the GNU Lesser General Public 8*1f93a6e4SLeon Alrae * License as published by the Free Software Foundation; either 9*1f93a6e4SLeon Alrae * version 2 of the License, or (at your option) any later version. 10*1f93a6e4SLeon Alrae * 11*1f93a6e4SLeon Alrae * This library is distributed in the hope that it will be useful, 12*1f93a6e4SLeon Alrae * but WITHOUT ANY WARRANTY; without even the implied warranty of 13*1f93a6e4SLeon Alrae * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14*1f93a6e4SLeon Alrae * Lesser General Public License for more details. 15*1f93a6e4SLeon Alrae * 16*1f93a6e4SLeon Alrae * You should have received a copy of the GNU Lesser General Public 17*1f93a6e4SLeon Alrae * License along with this library; if not, see <http://www.gnu.org/licenses/>. 18*1f93a6e4SLeon Alrae */ 19*1f93a6e4SLeon Alrae 20*1f93a6e4SLeon Alrae #include "qemu/osdep.h" 21*1f93a6e4SLeon Alrae #include "qapi/error.h" 22*1f93a6e4SLeon Alrae #include "hw/sysbus.h" 23*1f93a6e4SLeon Alrae 24*1f93a6e4SLeon Alrae #include "hw/misc/mips_cpc.h" 25*1f93a6e4SLeon Alrae 26*1f93a6e4SLeon Alrae static inline uint64_t cpc_vp_run_mask(MIPSCPCState *cpc) 27*1f93a6e4SLeon Alrae { 28*1f93a6e4SLeon Alrae return (1ULL << cpc->num_vp) - 1; 29*1f93a6e4SLeon Alrae } 30*1f93a6e4SLeon Alrae 31*1f93a6e4SLeon Alrae static void cpc_run_vp(MIPSCPCState *cpc, uint64_t vp_run) 32*1f93a6e4SLeon Alrae { 33*1f93a6e4SLeon Alrae CPUState *cs = first_cpu; 34*1f93a6e4SLeon Alrae 35*1f93a6e4SLeon Alrae CPU_FOREACH(cs) { 36*1f93a6e4SLeon Alrae uint64_t i = 1ULL << cs->cpu_index; 37*1f93a6e4SLeon Alrae if (i & vp_run & ~cpc->vp_running) { 38*1f93a6e4SLeon Alrae cpu_interrupt(cs, CPU_INTERRUPT_WAKE); 39*1f93a6e4SLeon Alrae cpc->vp_running |= i; 40*1f93a6e4SLeon Alrae } 41*1f93a6e4SLeon Alrae } 42*1f93a6e4SLeon Alrae } 43*1f93a6e4SLeon Alrae 44*1f93a6e4SLeon Alrae static void cpc_stop_vp(MIPSCPCState *cpc, uint64_t vp_stop) 45*1f93a6e4SLeon Alrae { 46*1f93a6e4SLeon Alrae CPUState *cs = first_cpu; 47*1f93a6e4SLeon Alrae 48*1f93a6e4SLeon Alrae CPU_FOREACH(cs) { 49*1f93a6e4SLeon Alrae uint64_t i = 1ULL << cs->cpu_index; 50*1f93a6e4SLeon Alrae if (i & vp_stop & cpc->vp_running) { 51*1f93a6e4SLeon Alrae cs->halted = 1; 52*1f93a6e4SLeon Alrae cpu_reset_interrupt(cs, CPU_INTERRUPT_WAKE); 53*1f93a6e4SLeon Alrae cpc->vp_running &= ~i; 54*1f93a6e4SLeon Alrae } 55*1f93a6e4SLeon Alrae } 56*1f93a6e4SLeon Alrae } 57*1f93a6e4SLeon Alrae 58*1f93a6e4SLeon Alrae static void cpc_write(void *opaque, hwaddr offset, uint64_t data, 59*1f93a6e4SLeon Alrae unsigned size) 60*1f93a6e4SLeon Alrae { 61*1f93a6e4SLeon Alrae MIPSCPCState *s = opaque; 62*1f93a6e4SLeon Alrae 63*1f93a6e4SLeon Alrae switch (offset) { 64*1f93a6e4SLeon Alrae case CPC_CL_BASE_OFS + CPC_VP_RUN_OFS: 65*1f93a6e4SLeon Alrae case CPC_CO_BASE_OFS + CPC_VP_RUN_OFS: 66*1f93a6e4SLeon Alrae cpc_run_vp(s, data & cpc_vp_run_mask(s)); 67*1f93a6e4SLeon Alrae break; 68*1f93a6e4SLeon Alrae case CPC_CL_BASE_OFS + CPC_VP_STOP_OFS: 69*1f93a6e4SLeon Alrae case CPC_CO_BASE_OFS + CPC_VP_STOP_OFS: 70*1f93a6e4SLeon Alrae cpc_stop_vp(s, data & cpc_vp_run_mask(s)); 71*1f93a6e4SLeon Alrae break; 72*1f93a6e4SLeon Alrae default: 73*1f93a6e4SLeon Alrae qemu_log_mask(LOG_UNIMP, 74*1f93a6e4SLeon Alrae "%s: Bad offset 0x%x\n", __func__, (int)offset); 75*1f93a6e4SLeon Alrae break; 76*1f93a6e4SLeon Alrae } 77*1f93a6e4SLeon Alrae 78*1f93a6e4SLeon Alrae return; 79*1f93a6e4SLeon Alrae } 80*1f93a6e4SLeon Alrae 81*1f93a6e4SLeon Alrae static uint64_t cpc_read(void *opaque, hwaddr offset, unsigned size) 82*1f93a6e4SLeon Alrae { 83*1f93a6e4SLeon Alrae MIPSCPCState *s = opaque; 84*1f93a6e4SLeon Alrae 85*1f93a6e4SLeon Alrae switch (offset) { 86*1f93a6e4SLeon Alrae case CPC_CL_BASE_OFS + CPC_VP_RUNNING_OFS: 87*1f93a6e4SLeon Alrae case CPC_CO_BASE_OFS + CPC_VP_RUNNING_OFS: 88*1f93a6e4SLeon Alrae return s->vp_running; 89*1f93a6e4SLeon Alrae default: 90*1f93a6e4SLeon Alrae qemu_log_mask(LOG_UNIMP, 91*1f93a6e4SLeon Alrae "%s: Bad offset 0x%x\n", __func__, (int)offset); 92*1f93a6e4SLeon Alrae return 0; 93*1f93a6e4SLeon Alrae } 94*1f93a6e4SLeon Alrae } 95*1f93a6e4SLeon Alrae 96*1f93a6e4SLeon Alrae static const MemoryRegionOps cpc_ops = { 97*1f93a6e4SLeon Alrae .read = cpc_read, 98*1f93a6e4SLeon Alrae .write = cpc_write, 99*1f93a6e4SLeon Alrae .endianness = DEVICE_NATIVE_ENDIAN, 100*1f93a6e4SLeon Alrae .impl = { 101*1f93a6e4SLeon Alrae .max_access_size = 8, 102*1f93a6e4SLeon Alrae }, 103*1f93a6e4SLeon Alrae }; 104*1f93a6e4SLeon Alrae 105*1f93a6e4SLeon Alrae static void mips_cpc_init(Object *obj) 106*1f93a6e4SLeon Alrae { 107*1f93a6e4SLeon Alrae SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 108*1f93a6e4SLeon Alrae MIPSCPCState *s = MIPS_CPC(obj); 109*1f93a6e4SLeon Alrae 110*1f93a6e4SLeon Alrae memory_region_init_io(&s->mr, OBJECT(s), &cpc_ops, s, "mips-cpc", 111*1f93a6e4SLeon Alrae CPC_ADDRSPACE_SZ); 112*1f93a6e4SLeon Alrae sysbus_init_mmio(sbd, &s->mr); 113*1f93a6e4SLeon Alrae } 114*1f93a6e4SLeon Alrae 115*1f93a6e4SLeon Alrae static void mips_cpc_realize(DeviceState *dev, Error **errp) 116*1f93a6e4SLeon Alrae { 117*1f93a6e4SLeon Alrae MIPSCPCState *s = MIPS_CPC(dev); 118*1f93a6e4SLeon Alrae 119*1f93a6e4SLeon Alrae if (s->vp_start_running > cpc_vp_run_mask(s)) { 120*1f93a6e4SLeon Alrae error_setg(errp, 121*1f93a6e4SLeon Alrae "incorrect vp_start_running 0x%" PRIx64 " for num_vp = %d", 122*1f93a6e4SLeon Alrae s->vp_running, s->num_vp); 123*1f93a6e4SLeon Alrae return; 124*1f93a6e4SLeon Alrae } 125*1f93a6e4SLeon Alrae } 126*1f93a6e4SLeon Alrae 127*1f93a6e4SLeon Alrae static void mips_cpc_reset(DeviceState *dev) 128*1f93a6e4SLeon Alrae { 129*1f93a6e4SLeon Alrae MIPSCPCState *s = MIPS_CPC(dev); 130*1f93a6e4SLeon Alrae 131*1f93a6e4SLeon Alrae /* Reflect the fact that all VPs are halted on reset */ 132*1f93a6e4SLeon Alrae s->vp_running = 0; 133*1f93a6e4SLeon Alrae 134*1f93a6e4SLeon Alrae /* Put selected VPs into run state */ 135*1f93a6e4SLeon Alrae cpc_run_vp(s, s->vp_start_running); 136*1f93a6e4SLeon Alrae } 137*1f93a6e4SLeon Alrae 138*1f93a6e4SLeon Alrae static const VMStateDescription vmstate_mips_cpc = { 139*1f93a6e4SLeon Alrae .name = "mips-cpc", 140*1f93a6e4SLeon Alrae .version_id = 0, 141*1f93a6e4SLeon Alrae .minimum_version_id = 0, 142*1f93a6e4SLeon Alrae .fields = (VMStateField[]) { 143*1f93a6e4SLeon Alrae VMSTATE_UINT64(vp_running, MIPSCPCState), 144*1f93a6e4SLeon Alrae VMSTATE_END_OF_LIST() 145*1f93a6e4SLeon Alrae }, 146*1f93a6e4SLeon Alrae }; 147*1f93a6e4SLeon Alrae 148*1f93a6e4SLeon Alrae static Property mips_cpc_properties[] = { 149*1f93a6e4SLeon Alrae DEFINE_PROP_UINT32("num-vp", MIPSCPCState, num_vp, 0x1), 150*1f93a6e4SLeon Alrae DEFINE_PROP_UINT64("vp-start-running", MIPSCPCState, vp_start_running, 0x1), 151*1f93a6e4SLeon Alrae DEFINE_PROP_END_OF_LIST(), 152*1f93a6e4SLeon Alrae }; 153*1f93a6e4SLeon Alrae 154*1f93a6e4SLeon Alrae static void mips_cpc_class_init(ObjectClass *klass, void *data) 155*1f93a6e4SLeon Alrae { 156*1f93a6e4SLeon Alrae DeviceClass *dc = DEVICE_CLASS(klass); 157*1f93a6e4SLeon Alrae 158*1f93a6e4SLeon Alrae dc->realize = mips_cpc_realize; 159*1f93a6e4SLeon Alrae dc->reset = mips_cpc_reset; 160*1f93a6e4SLeon Alrae dc->vmsd = &vmstate_mips_cpc; 161*1f93a6e4SLeon Alrae dc->props = mips_cpc_properties; 162*1f93a6e4SLeon Alrae } 163*1f93a6e4SLeon Alrae 164*1f93a6e4SLeon Alrae static const TypeInfo mips_cpc_info = { 165*1f93a6e4SLeon Alrae .name = TYPE_MIPS_CPC, 166*1f93a6e4SLeon Alrae .parent = TYPE_SYS_BUS_DEVICE, 167*1f93a6e4SLeon Alrae .instance_size = sizeof(MIPSCPCState), 168*1f93a6e4SLeon Alrae .instance_init = mips_cpc_init, 169*1f93a6e4SLeon Alrae .class_init = mips_cpc_class_init, 170*1f93a6e4SLeon Alrae }; 171*1f93a6e4SLeon Alrae 172*1f93a6e4SLeon Alrae static void mips_cpc_register_types(void) 173*1f93a6e4SLeon Alrae { 174*1f93a6e4SLeon Alrae type_register_static(&mips_cpc_info); 175*1f93a6e4SLeon Alrae } 176*1f93a6e4SLeon Alrae 177*1f93a6e4SLeon Alrae type_init(mips_cpc_register_types) 178