xref: /openbmc/qemu/hw/misc/aspeed_gfx.c (revision a726d631)
1 /*
2  * ASPEED GFX Controller
3  *
4  * Copyright (C) 2023 IBM Corp.
5  *
6  * This code is licensed under the GPL version 2 or later.  See
7  * the COPYING file in the top-level directory.
8  */
9 
10 #include "qemu/osdep.h"
11 #include "qemu/log.h"
12 #include "qemu/error-report.h"
13 #include "hw/misc/aspeed_gfx.h"
14 #include "qapi/error.h"
15 #include "migration/vmstate.h"
16 
17 #include "trace.h"
18 
aspeed_gfx_read(void * opaque,hwaddr addr,unsigned int size)19 static uint64_t aspeed_gfx_read(void *opaque, hwaddr addr,
20                                      unsigned int size)
21 {
22     AspeedGFXState *s = ASPEED_GFX(opaque);
23     uint64_t val = 0;
24 
25     addr >>= 2;
26 
27     if (addr >= ASPEED_GFX_NR_REGS) {
28         qemu_log_mask(LOG_GUEST_ERROR,
29                       "%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n",
30                       __func__, addr << 2);
31     } else {
32         val = s->regs[addr];
33     }
34 
35     trace_aspeed_gfx_read(addr << 2, val);
36 
37     return val;
38 }
39 
aspeed_gfx_write(void * opaque,hwaddr addr,uint64_t data,unsigned int size)40 static void aspeed_gfx_write(void *opaque, hwaddr addr, uint64_t data,
41                               unsigned int size)
42 {
43     AspeedGFXState *s = ASPEED_GFX(opaque);
44 
45     trace_aspeed_gfx_write(addr, data);
46 
47     addr >>= 2;
48 
49     if (addr >= ASPEED_GFX_NR_REGS) {
50         qemu_log_mask(LOG_GUEST_ERROR,
51                       "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n",
52                       __func__, addr << 2);
53         return;
54     }
55 
56     s->regs[addr] = data;
57 }
58 
59 static const MemoryRegionOps aspeed_gfx_ops = {
60     .read = aspeed_gfx_read,
61     .write = aspeed_gfx_write,
62     .endianness = DEVICE_LITTLE_ENDIAN,
63     .valid = {
64         .min_access_size = 1,
65         .max_access_size = 4,
66     },
67 };
68 
aspeed_gfx_reset(DeviceState * dev)69 static void aspeed_gfx_reset(DeviceState *dev)
70 {
71     struct AspeedGFXState *s = ASPEED_GFX(dev);
72 
73     memset(s->regs, 0, sizeof(s->regs));
74 }
75 
aspeed_gfx_realize(DeviceState * dev,Error ** errp)76 static void aspeed_gfx_realize(DeviceState *dev, Error **errp)
77 {
78     AspeedGFXState *s = ASPEED_GFX(dev);
79     SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
80 
81     sysbus_init_irq(sbd, &s->irq);
82 
83     memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_gfx_ops, s,
84             TYPE_ASPEED_GFX, 0x1000);
85 
86     sysbus_init_mmio(sbd, &s->iomem);
87 }
88 
89 static const VMStateDescription vmstate_aspeed_gfx = {
90     .name = TYPE_ASPEED_GFX,
91     .version_id = 1,
92     .minimum_version_id = 1,
93     .fields = (VMStateField[]) {
94         VMSTATE_UINT32_ARRAY(regs, AspeedGFXState, ASPEED_GFX_NR_REGS),
95         VMSTATE_END_OF_LIST(),
96     }
97 };
98 
aspeed_gfx_class_init(ObjectClass * klass,void * data)99 static void aspeed_gfx_class_init(ObjectClass *klass, void *data)
100 {
101     DeviceClass *dc = DEVICE_CLASS(klass);
102 
103     dc->realize = aspeed_gfx_realize;
104     device_class_set_legacy_reset(dc, aspeed_gfx_reset);
105     dc->desc = "Aspeed GFX Controller";
106     dc->vmsd = &vmstate_aspeed_gfx;
107 }
108 
109 static const TypeInfo aspeed_gfx_info = {
110     .name = TYPE_ASPEED_GFX,
111     .parent = TYPE_SYS_BUS_DEVICE,
112     .instance_size = sizeof(AspeedGFXState),
113     .class_init = aspeed_gfx_class_init,
114 };
115 
aspeed_gfx_register_types(void)116 static void aspeed_gfx_register_types(void)
117 {
118     type_register_static(&aspeed_gfx_info);
119 }
120 
121 type_init(aspeed_gfx_register_types);
122