1*f944890dSJamin Lin /*
2*f944890dSJamin Lin * ASPEED SLI Controller
3*f944890dSJamin Lin *
4*f944890dSJamin Lin * Copyright (C) 2024 ASPEED Technology Inc.
5*f944890dSJamin Lin *
6*f944890dSJamin Lin * SPDX-License-Identifier: GPL-2.0-or-later
7*f944890dSJamin Lin */
8*f944890dSJamin Lin
9*f944890dSJamin Lin #include "qemu/osdep.h"
10*f944890dSJamin Lin #include "qemu/log.h"
11*f944890dSJamin Lin #include "qemu/error-report.h"
12*f944890dSJamin Lin #include "hw/qdev-properties.h"
13*f944890dSJamin Lin #include "hw/misc/aspeed_sli.h"
14*f944890dSJamin Lin #include "qapi/error.h"
15*f944890dSJamin Lin #include "migration/vmstate.h"
16*f944890dSJamin Lin #include "trace.h"
17*f944890dSJamin Lin
18*f944890dSJamin Lin #define SLI_REGION_SIZE 0x500
19*f944890dSJamin Lin #define TO_REG(addr) ((addr) >> 2)
20*f944890dSJamin Lin
aspeed_sli_read(void * opaque,hwaddr addr,unsigned int size)21*f944890dSJamin Lin static uint64_t aspeed_sli_read(void *opaque, hwaddr addr, unsigned int size)
22*f944890dSJamin Lin {
23*f944890dSJamin Lin AspeedSLIState *s = ASPEED_SLI(opaque);
24*f944890dSJamin Lin int reg = TO_REG(addr);
25*f944890dSJamin Lin
26*f944890dSJamin Lin if (reg >= ARRAY_SIZE(s->regs)) {
27*f944890dSJamin Lin qemu_log_mask(LOG_GUEST_ERROR,
28*f944890dSJamin Lin "%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n",
29*f944890dSJamin Lin __func__, addr);
30*f944890dSJamin Lin return 0;
31*f944890dSJamin Lin }
32*f944890dSJamin Lin
33*f944890dSJamin Lin trace_aspeed_sli_read(addr, size, s->regs[reg]);
34*f944890dSJamin Lin return s->regs[reg];
35*f944890dSJamin Lin }
36*f944890dSJamin Lin
aspeed_sli_write(void * opaque,hwaddr addr,uint64_t data,unsigned int size)37*f944890dSJamin Lin static void aspeed_sli_write(void *opaque, hwaddr addr, uint64_t data,
38*f944890dSJamin Lin unsigned int size)
39*f944890dSJamin Lin {
40*f944890dSJamin Lin AspeedSLIState *s = ASPEED_SLI(opaque);
41*f944890dSJamin Lin int reg = TO_REG(addr);
42*f944890dSJamin Lin
43*f944890dSJamin Lin if (reg >= ARRAY_SIZE(s->regs)) {
44*f944890dSJamin Lin qemu_log_mask(LOG_GUEST_ERROR,
45*f944890dSJamin Lin "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n",
46*f944890dSJamin Lin __func__, addr);
47*f944890dSJamin Lin return;
48*f944890dSJamin Lin }
49*f944890dSJamin Lin
50*f944890dSJamin Lin trace_aspeed_sli_write(addr, size, data);
51*f944890dSJamin Lin s->regs[reg] = data;
52*f944890dSJamin Lin }
53*f944890dSJamin Lin
aspeed_sliio_read(void * opaque,hwaddr addr,unsigned int size)54*f944890dSJamin Lin static uint64_t aspeed_sliio_read(void *opaque, hwaddr addr, unsigned int size)
55*f944890dSJamin Lin {
56*f944890dSJamin Lin AspeedSLIState *s = ASPEED_SLI(opaque);
57*f944890dSJamin Lin int reg = TO_REG(addr);
58*f944890dSJamin Lin
59*f944890dSJamin Lin if (reg >= ARRAY_SIZE(s->regs)) {
60*f944890dSJamin Lin qemu_log_mask(LOG_GUEST_ERROR,
61*f944890dSJamin Lin "%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n",
62*f944890dSJamin Lin __func__, addr);
63*f944890dSJamin Lin return 0;
64*f944890dSJamin Lin }
65*f944890dSJamin Lin
66*f944890dSJamin Lin trace_aspeed_sliio_read(addr, size, s->regs[reg]);
67*f944890dSJamin Lin return s->regs[reg];
68*f944890dSJamin Lin }
69*f944890dSJamin Lin
aspeed_sliio_write(void * opaque,hwaddr addr,uint64_t data,unsigned int size)70*f944890dSJamin Lin static void aspeed_sliio_write(void *opaque, hwaddr addr, uint64_t data,
71*f944890dSJamin Lin unsigned int size)
72*f944890dSJamin Lin {
73*f944890dSJamin Lin AspeedSLIState *s = ASPEED_SLI(opaque);
74*f944890dSJamin Lin int reg = TO_REG(addr);
75*f944890dSJamin Lin
76*f944890dSJamin Lin if (reg >= ARRAY_SIZE(s->regs)) {
77*f944890dSJamin Lin qemu_log_mask(LOG_GUEST_ERROR,
78*f944890dSJamin Lin "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n",
79*f944890dSJamin Lin __func__, addr);
80*f944890dSJamin Lin return;
81*f944890dSJamin Lin }
82*f944890dSJamin Lin
83*f944890dSJamin Lin trace_aspeed_sliio_write(addr, size, data);
84*f944890dSJamin Lin s->regs[reg] = data;
85*f944890dSJamin Lin }
86*f944890dSJamin Lin
87*f944890dSJamin Lin static const MemoryRegionOps aspeed_sli_ops = {
88*f944890dSJamin Lin .read = aspeed_sli_read,
89*f944890dSJamin Lin .write = aspeed_sli_write,
90*f944890dSJamin Lin .endianness = DEVICE_LITTLE_ENDIAN,
91*f944890dSJamin Lin .valid = {
92*f944890dSJamin Lin .min_access_size = 1,
93*f944890dSJamin Lin .max_access_size = 4,
94*f944890dSJamin Lin },
95*f944890dSJamin Lin };
96*f944890dSJamin Lin
97*f944890dSJamin Lin static const MemoryRegionOps aspeed_sliio_ops = {
98*f944890dSJamin Lin .read = aspeed_sliio_read,
99*f944890dSJamin Lin .write = aspeed_sliio_write,
100*f944890dSJamin Lin .endianness = DEVICE_LITTLE_ENDIAN,
101*f944890dSJamin Lin .valid = {
102*f944890dSJamin Lin .min_access_size = 1,
103*f944890dSJamin Lin .max_access_size = 4,
104*f944890dSJamin Lin },
105*f944890dSJamin Lin };
106*f944890dSJamin Lin
aspeed_sli_realize(DeviceState * dev,Error ** errp)107*f944890dSJamin Lin static void aspeed_sli_realize(DeviceState *dev, Error **errp)
108*f944890dSJamin Lin {
109*f944890dSJamin Lin AspeedSLIState *s = ASPEED_SLI(dev);
110*f944890dSJamin Lin SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
111*f944890dSJamin Lin
112*f944890dSJamin Lin memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_sli_ops, s,
113*f944890dSJamin Lin TYPE_ASPEED_SLI, SLI_REGION_SIZE);
114*f944890dSJamin Lin sysbus_init_mmio(sbd, &s->iomem);
115*f944890dSJamin Lin }
116*f944890dSJamin Lin
aspeed_sliio_realize(DeviceState * dev,Error ** errp)117*f944890dSJamin Lin static void aspeed_sliio_realize(DeviceState *dev, Error **errp)
118*f944890dSJamin Lin {
119*f944890dSJamin Lin AspeedSLIState *s = ASPEED_SLI(dev);
120*f944890dSJamin Lin SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
121*f944890dSJamin Lin
122*f944890dSJamin Lin memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_sliio_ops, s,
123*f944890dSJamin Lin TYPE_ASPEED_SLI, SLI_REGION_SIZE);
124*f944890dSJamin Lin sysbus_init_mmio(sbd, &s->iomem);
125*f944890dSJamin Lin }
126*f944890dSJamin Lin
aspeed_sli_class_init(ObjectClass * klass,void * data)127*f944890dSJamin Lin static void aspeed_sli_class_init(ObjectClass *klass, void *data)
128*f944890dSJamin Lin {
129*f944890dSJamin Lin DeviceClass *dc = DEVICE_CLASS(klass);
130*f944890dSJamin Lin
131*f944890dSJamin Lin dc->desc = "Aspeed SLI Controller";
132*f944890dSJamin Lin dc->realize = aspeed_sli_realize;
133*f944890dSJamin Lin }
134*f944890dSJamin Lin
135*f944890dSJamin Lin static const TypeInfo aspeed_sli_info = {
136*f944890dSJamin Lin .name = TYPE_ASPEED_SLI,
137*f944890dSJamin Lin .parent = TYPE_SYS_BUS_DEVICE,
138*f944890dSJamin Lin .instance_size = sizeof(AspeedSLIState),
139*f944890dSJamin Lin .class_init = aspeed_sli_class_init,
140*f944890dSJamin Lin .abstract = true,
141*f944890dSJamin Lin };
142*f944890dSJamin Lin
aspeed_2700_sli_class_init(ObjectClass * klass,void * data)143*f944890dSJamin Lin static void aspeed_2700_sli_class_init(ObjectClass *klass, void *data)
144*f944890dSJamin Lin {
145*f944890dSJamin Lin DeviceClass *dc = DEVICE_CLASS(klass);
146*f944890dSJamin Lin
147*f944890dSJamin Lin dc->desc = "AST2700 SLI Controller";
148*f944890dSJamin Lin }
149*f944890dSJamin Lin
aspeed_2700_sliio_class_init(ObjectClass * klass,void * data)150*f944890dSJamin Lin static void aspeed_2700_sliio_class_init(ObjectClass *klass, void *data)
151*f944890dSJamin Lin {
152*f944890dSJamin Lin DeviceClass *dc = DEVICE_CLASS(klass);
153*f944890dSJamin Lin
154*f944890dSJamin Lin dc->desc = "AST2700 I/O SLI Controller";
155*f944890dSJamin Lin dc->realize = aspeed_sliio_realize;
156*f944890dSJamin Lin }
157*f944890dSJamin Lin
158*f944890dSJamin Lin static const TypeInfo aspeed_2700_sli_info = {
159*f944890dSJamin Lin .name = TYPE_ASPEED_2700_SLI,
160*f944890dSJamin Lin .parent = TYPE_ASPEED_SLI,
161*f944890dSJamin Lin .class_init = aspeed_2700_sli_class_init,
162*f944890dSJamin Lin };
163*f944890dSJamin Lin
164*f944890dSJamin Lin static const TypeInfo aspeed_2700_sliio_info = {
165*f944890dSJamin Lin .name = TYPE_ASPEED_2700_SLIIO,
166*f944890dSJamin Lin .parent = TYPE_ASPEED_SLI,
167*f944890dSJamin Lin .class_init = aspeed_2700_sliio_class_init,
168*f944890dSJamin Lin };
169*f944890dSJamin Lin
aspeed_sli_register_types(void)170*f944890dSJamin Lin static void aspeed_sli_register_types(void)
171*f944890dSJamin Lin {
172*f944890dSJamin Lin type_register_static(&aspeed_sli_info);
173*f944890dSJamin Lin type_register_static(&aspeed_2700_sli_info);
174*f944890dSJamin Lin type_register_static(&aspeed_2700_sliio_info);
175*f944890dSJamin Lin }
176*f944890dSJamin Lin
177*f944890dSJamin Lin type_init(aspeed_sli_register_types);
178