1*2ecf1726SCédric Le Goater /* 2*2ecf1726SCédric Le Goater * ASPEED LPC Controller 3*2ecf1726SCédric Le Goater * 4*2ecf1726SCédric Le Goater * Copyright (C) 2017-2018 IBM Corp. 5*2ecf1726SCédric Le Goater * 6*2ecf1726SCédric Le Goater * This code is licensed under the GPL version 2 or later. See 7*2ecf1726SCédric Le Goater * the COPYING file in the top-level directory. 8*2ecf1726SCédric Le Goater */ 9*2ecf1726SCédric Le Goater 10*2ecf1726SCédric Le Goater #include "qemu/osdep.h" 11*2ecf1726SCédric Le Goater #include "qemu/log.h" 12*2ecf1726SCédric Le Goater #include "qemu/error-report.h" 13*2ecf1726SCédric Le Goater #include "hw/misc/aspeed_lpc.h" 14*2ecf1726SCédric Le Goater #include "qapi/error.h" 15*2ecf1726SCédric Le Goater #include "hw/qdev-properties.h" 16*2ecf1726SCédric Le Goater #include "migration/vmstate.h" 17*2ecf1726SCédric Le Goater 18*2ecf1726SCédric Le Goater #define TO_REG(offset) ((offset) >> 2) 19*2ecf1726SCédric Le Goater 20*2ecf1726SCédric Le Goater #define HICR0 TO_REG(0x00) 21*2ecf1726SCédric Le Goater #define HICR1 TO_REG(0x04) 22*2ecf1726SCédric Le Goater #define HICR2 TO_REG(0x08) 23*2ecf1726SCédric Le Goater #define HICR3 TO_REG(0x0C) 24*2ecf1726SCédric Le Goater #define HICR4 TO_REG(0x10) 25*2ecf1726SCédric Le Goater #define HICR5 TO_REG(0x80) 26*2ecf1726SCédric Le Goater #define HICR6 TO_REG(0x84) 27*2ecf1726SCédric Le Goater #define HICR7 TO_REG(0x88) 28*2ecf1726SCédric Le Goater #define HICR8 TO_REG(0x8C) 29*2ecf1726SCédric Le Goater 30*2ecf1726SCédric Le Goater static uint64_t aspeed_lpc_read(void *opaque, hwaddr offset, unsigned size) 31*2ecf1726SCédric Le Goater { 32*2ecf1726SCédric Le Goater AspeedLPCState *s = ASPEED_LPC(opaque); 33*2ecf1726SCédric Le Goater int reg = TO_REG(offset); 34*2ecf1726SCédric Le Goater 35*2ecf1726SCédric Le Goater if (reg >= ARRAY_SIZE(s->regs)) { 36*2ecf1726SCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, 37*2ecf1726SCédric Le Goater "%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n", 38*2ecf1726SCédric Le Goater __func__, offset); 39*2ecf1726SCédric Le Goater return 0; 40*2ecf1726SCédric Le Goater } 41*2ecf1726SCédric Le Goater 42*2ecf1726SCédric Le Goater return s->regs[reg]; 43*2ecf1726SCédric Le Goater } 44*2ecf1726SCédric Le Goater 45*2ecf1726SCédric Le Goater static void aspeed_lpc_write(void *opaque, hwaddr offset, uint64_t data, 46*2ecf1726SCédric Le Goater unsigned int size) 47*2ecf1726SCédric Le Goater { 48*2ecf1726SCédric Le Goater AspeedLPCState *s = ASPEED_LPC(opaque); 49*2ecf1726SCédric Le Goater int reg = TO_REG(offset); 50*2ecf1726SCédric Le Goater 51*2ecf1726SCédric Le Goater if (reg >= ARRAY_SIZE(s->regs)) { 52*2ecf1726SCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, 53*2ecf1726SCédric Le Goater "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n", 54*2ecf1726SCédric Le Goater __func__, offset); 55*2ecf1726SCédric Le Goater return; 56*2ecf1726SCédric Le Goater } 57*2ecf1726SCédric Le Goater 58*2ecf1726SCédric Le Goater s->regs[reg] = data; 59*2ecf1726SCédric Le Goater } 60*2ecf1726SCédric Le Goater 61*2ecf1726SCédric Le Goater static const MemoryRegionOps aspeed_lpc_ops = { 62*2ecf1726SCédric Le Goater .read = aspeed_lpc_read, 63*2ecf1726SCédric Le Goater .write = aspeed_lpc_write, 64*2ecf1726SCédric Le Goater .endianness = DEVICE_LITTLE_ENDIAN, 65*2ecf1726SCédric Le Goater .valid = { 66*2ecf1726SCédric Le Goater .min_access_size = 1, 67*2ecf1726SCédric Le Goater .max_access_size = 4, 68*2ecf1726SCédric Le Goater }, 69*2ecf1726SCédric Le Goater }; 70*2ecf1726SCédric Le Goater 71*2ecf1726SCédric Le Goater static void aspeed_lpc_reset(DeviceState *dev) 72*2ecf1726SCédric Le Goater { 73*2ecf1726SCédric Le Goater struct AspeedLPCState *s = ASPEED_LPC(dev); 74*2ecf1726SCédric Le Goater 75*2ecf1726SCédric Le Goater memset(s->regs, 0, sizeof(s->regs)); 76*2ecf1726SCédric Le Goater 77*2ecf1726SCédric Le Goater s->regs[HICR7] = s->hicr7; 78*2ecf1726SCédric Le Goater } 79*2ecf1726SCédric Le Goater 80*2ecf1726SCédric Le Goater static void aspeed_lpc_realize(DeviceState *dev, Error **errp) 81*2ecf1726SCédric Le Goater { 82*2ecf1726SCédric Le Goater AspeedLPCState *s = ASPEED_LPC(dev); 83*2ecf1726SCédric Le Goater SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 84*2ecf1726SCédric Le Goater 85*2ecf1726SCédric Le Goater sysbus_init_irq(sbd, &s->irq); 86*2ecf1726SCédric Le Goater 87*2ecf1726SCédric Le Goater memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_lpc_ops, s, 88*2ecf1726SCédric Le Goater TYPE_ASPEED_LPC, 0x1000); 89*2ecf1726SCédric Le Goater 90*2ecf1726SCédric Le Goater sysbus_init_mmio(sbd, &s->iomem); 91*2ecf1726SCédric Le Goater } 92*2ecf1726SCédric Le Goater 93*2ecf1726SCédric Le Goater static const VMStateDescription vmstate_aspeed_lpc = { 94*2ecf1726SCédric Le Goater .name = TYPE_ASPEED_LPC, 95*2ecf1726SCédric Le Goater .version_id = 1, 96*2ecf1726SCédric Le Goater .minimum_version_id = 1, 97*2ecf1726SCédric Le Goater .fields = (VMStateField[]) { 98*2ecf1726SCédric Le Goater VMSTATE_UINT32_ARRAY(regs, AspeedLPCState, ASPEED_LPC_NR_REGS), 99*2ecf1726SCédric Le Goater VMSTATE_END_OF_LIST(), 100*2ecf1726SCédric Le Goater } 101*2ecf1726SCédric Le Goater }; 102*2ecf1726SCédric Le Goater 103*2ecf1726SCédric Le Goater static Property aspeed_lpc_properties[] = { 104*2ecf1726SCédric Le Goater DEFINE_PROP_UINT32("hicr7", AspeedLPCState, hicr7, 0), 105*2ecf1726SCédric Le Goater DEFINE_PROP_END_OF_LIST(), 106*2ecf1726SCédric Le Goater }; 107*2ecf1726SCédric Le Goater 108*2ecf1726SCédric Le Goater static void aspeed_lpc_class_init(ObjectClass *klass, void *data) 109*2ecf1726SCédric Le Goater { 110*2ecf1726SCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 111*2ecf1726SCédric Le Goater 112*2ecf1726SCédric Le Goater dc->realize = aspeed_lpc_realize; 113*2ecf1726SCédric Le Goater dc->reset = aspeed_lpc_reset; 114*2ecf1726SCédric Le Goater dc->desc = "Aspeed LPC Controller", 115*2ecf1726SCédric Le Goater dc->vmsd = &vmstate_aspeed_lpc; 116*2ecf1726SCédric Le Goater device_class_set_props(dc, aspeed_lpc_properties); 117*2ecf1726SCédric Le Goater } 118*2ecf1726SCédric Le Goater 119*2ecf1726SCédric Le Goater static const TypeInfo aspeed_lpc_info = { 120*2ecf1726SCédric Le Goater .name = TYPE_ASPEED_LPC, 121*2ecf1726SCédric Le Goater .parent = TYPE_SYS_BUS_DEVICE, 122*2ecf1726SCédric Le Goater .instance_size = sizeof(AspeedLPCState), 123*2ecf1726SCédric Le Goater .class_init = aspeed_lpc_class_init, 124*2ecf1726SCédric Le Goater }; 125*2ecf1726SCédric Le Goater 126*2ecf1726SCédric Le Goater static void aspeed_lpc_register_types(void) 127*2ecf1726SCédric Le Goater { 128*2ecf1726SCédric Le Goater type_register_static(&aspeed_lpc_info); 129*2ecf1726SCédric Le Goater } 130*2ecf1726SCédric Le Goater 131*2ecf1726SCédric Le Goater type_init(aspeed_lpc_register_types); 132