xref: /openbmc/qemu/hw/misc/aspeed_lpc.c (revision 2ecf1726)
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