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 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 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 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 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 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 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 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 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 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 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