/*
 * Cluster Power Controller emulation
 *
 * Copyright (c) 2016 Imagination Technologies
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
 */

#include "qemu/osdep.h"
#include "qapi/error.h"
#include "cpu.h"
#include "qemu/log.h"
#include "hw/sysbus.h"

#include "hw/misc/mips_cpc.h"

static inline uint64_t cpc_vp_run_mask(MIPSCPCState *cpc)
{
    return (1ULL << cpc->num_vp) - 1;
}

static void cpc_run_vp(MIPSCPCState *cpc, uint64_t vp_run)
{
    CPUState *cs = first_cpu;

    CPU_FOREACH(cs) {
        uint64_t i = 1ULL << cs->cpu_index;
        if (i & vp_run & ~cpc->vp_running) {
            cpu_reset(cs);
            cpc->vp_running |= i;
        }
    }
}

static void cpc_stop_vp(MIPSCPCState *cpc, uint64_t vp_stop)
{
    CPUState *cs = first_cpu;

    CPU_FOREACH(cs) {
        uint64_t i = 1ULL << cs->cpu_index;
        if (i & vp_stop & cpc->vp_running) {
            cpu_interrupt(cs, CPU_INTERRUPT_HALT);
            cpc->vp_running &= ~i;
        }
    }
}

static void cpc_write(void *opaque, hwaddr offset, uint64_t data,
                      unsigned size)
{
    MIPSCPCState *s = opaque;

    switch (offset) {
    case CPC_CL_BASE_OFS + CPC_VP_RUN_OFS:
    case CPC_CO_BASE_OFS + CPC_VP_RUN_OFS:
        cpc_run_vp(s, data & cpc_vp_run_mask(s));
        break;
    case CPC_CL_BASE_OFS + CPC_VP_STOP_OFS:
    case CPC_CO_BASE_OFS + CPC_VP_STOP_OFS:
        cpc_stop_vp(s, data & cpc_vp_run_mask(s));
        break;
    default:
        qemu_log_mask(LOG_UNIMP,
                      "%s: Bad offset 0x%x\n",  __func__, (int)offset);
        break;
    }

    return;
}

static uint64_t cpc_read(void *opaque, hwaddr offset, unsigned size)
{
    MIPSCPCState *s = opaque;

    switch (offset) {
    case CPC_CL_BASE_OFS + CPC_VP_RUNNING_OFS:
    case CPC_CO_BASE_OFS + CPC_VP_RUNNING_OFS:
        return s->vp_running;
    default:
        qemu_log_mask(LOG_UNIMP,
                      "%s: Bad offset 0x%x\n",  __func__, (int)offset);
        return 0;
    }
}

static const MemoryRegionOps cpc_ops = {
    .read = cpc_read,
    .write = cpc_write,
    .endianness = DEVICE_NATIVE_ENDIAN,
    .impl = {
        .max_access_size = 8,
    },
};

static void mips_cpc_init(Object *obj)
{
    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
    MIPSCPCState *s = MIPS_CPC(obj);

    memory_region_init_io(&s->mr, OBJECT(s), &cpc_ops, s, "mips-cpc",
                          CPC_ADDRSPACE_SZ);
    sysbus_init_mmio(sbd, &s->mr);
}

static void mips_cpc_realize(DeviceState *dev, Error **errp)
{
    MIPSCPCState *s = MIPS_CPC(dev);

    if (s->vp_start_running > cpc_vp_run_mask(s)) {
        error_setg(errp,
                   "incorrect vp_start_running 0x%" PRIx64 " for num_vp = %d",
                   s->vp_running, s->num_vp);
        return;
    }
}

static void mips_cpc_reset(DeviceState *dev)
{
    MIPSCPCState *s = MIPS_CPC(dev);

    /* Reflect the fact that all VPs are halted on reset */
    s->vp_running = 0;

    /* Put selected VPs into run state */
    cpc_run_vp(s, s->vp_start_running);
}

static const VMStateDescription vmstate_mips_cpc = {
    .name = "mips-cpc",
    .version_id = 0,
    .minimum_version_id = 0,
    .fields = (VMStateField[]) {
        VMSTATE_UINT64(vp_running, MIPSCPCState),
        VMSTATE_END_OF_LIST()
    },
};

static Property mips_cpc_properties[] = {
    DEFINE_PROP_UINT32("num-vp", MIPSCPCState, num_vp, 0x1),
    DEFINE_PROP_UINT64("vp-start-running", MIPSCPCState, vp_start_running, 0x1),
    DEFINE_PROP_END_OF_LIST(),
};

static void mips_cpc_class_init(ObjectClass *klass, void *data)
{
    DeviceClass *dc = DEVICE_CLASS(klass);

    dc->realize = mips_cpc_realize;
    dc->reset = mips_cpc_reset;
    dc->vmsd = &vmstate_mips_cpc;
    dc->props = mips_cpc_properties;
}

static const TypeInfo mips_cpc_info = {
    .name          = TYPE_MIPS_CPC,
    .parent        = TYPE_SYS_BUS_DEVICE,
    .instance_size = sizeof(MIPSCPCState),
    .instance_init = mips_cpc_init,
    .class_init    = mips_cpc_class_init,
};

static void mips_cpc_register_types(void)
{
    type_register_static(&mips_cpc_info);
}

type_init(mips_cpc_register_types)
