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