xemu/hw/misc/aspeed_lpc.c

132 lines
3.4 KiB
C
Raw Normal View History

/*
* ASPEED LPC Controller
*
* Copyright (C) 2017-2018 IBM Corp.
*
* This code is licensed under the GPL version 2 or later. See
* the COPYING file in the top-level directory.
*/
#include "qemu/osdep.h"
#include "qemu/log.h"
#include "qemu/error-report.h"
#include "hw/misc/aspeed_lpc.h"
#include "qapi/error.h"
#include "hw/qdev-properties.h"
#include "migration/vmstate.h"
#define TO_REG(offset) ((offset) >> 2)
#define HICR0 TO_REG(0x00)
#define HICR1 TO_REG(0x04)
#define HICR2 TO_REG(0x08)
#define HICR3 TO_REG(0x0C)
#define HICR4 TO_REG(0x10)
#define HICR5 TO_REG(0x80)
#define HICR6 TO_REG(0x84)
#define HICR7 TO_REG(0x88)
#define HICR8 TO_REG(0x8C)
static uint64_t aspeed_lpc_read(void *opaque, hwaddr offset, unsigned size)
{
AspeedLPCState *s = ASPEED_LPC(opaque);
int reg = TO_REG(offset);
if (reg >= ARRAY_SIZE(s->regs)) {
qemu_log_mask(LOG_GUEST_ERROR,
"%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n",
__func__, offset);
return 0;
}
return s->regs[reg];
}
static void aspeed_lpc_write(void *opaque, hwaddr offset, uint64_t data,
unsigned int size)
{
AspeedLPCState *s = ASPEED_LPC(opaque);
int reg = TO_REG(offset);
if (reg >= ARRAY_SIZE(s->regs)) {
qemu_log_mask(LOG_GUEST_ERROR,
"%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n",
__func__, offset);
return;
}
s->regs[reg] = data;
}
static const MemoryRegionOps aspeed_lpc_ops = {
.read = aspeed_lpc_read,
.write = aspeed_lpc_write,
.endianness = DEVICE_LITTLE_ENDIAN,
.valid = {
.min_access_size = 1,
.max_access_size = 4,
},
};
static void aspeed_lpc_reset(DeviceState *dev)
{
struct AspeedLPCState *s = ASPEED_LPC(dev);
memset(s->regs, 0, sizeof(s->regs));
s->regs[HICR7] = s->hicr7;
}
static void aspeed_lpc_realize(DeviceState *dev, Error **errp)
{
AspeedLPCState *s = ASPEED_LPC(dev);
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
sysbus_init_irq(sbd, &s->irq);
memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_lpc_ops, s,
TYPE_ASPEED_LPC, 0x1000);
sysbus_init_mmio(sbd, &s->iomem);
}
static const VMStateDescription vmstate_aspeed_lpc = {
.name = TYPE_ASPEED_LPC,
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_UINT32_ARRAY(regs, AspeedLPCState, ASPEED_LPC_NR_REGS),
VMSTATE_END_OF_LIST(),
}
};
static Property aspeed_lpc_properties[] = {
DEFINE_PROP_UINT32("hicr7", AspeedLPCState, hicr7, 0),
DEFINE_PROP_END_OF_LIST(),
};
static void aspeed_lpc_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = aspeed_lpc_realize;
dc->reset = aspeed_lpc_reset;
dc->desc = "Aspeed LPC Controller",
dc->vmsd = &vmstate_aspeed_lpc;
device_class_set_props(dc, aspeed_lpc_properties);
}
static const TypeInfo aspeed_lpc_info = {
.name = TYPE_ASPEED_LPC,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(AspeedLPCState),
.class_init = aspeed_lpc_class_init,
};
static void aspeed_lpc_register_types(void)
{
type_register_static(&aspeed_lpc_info);
}
type_init(aspeed_lpc_register_types);