1*ca033107SNinad Palsule /* 2*ca033107SNinad Palsule * SPDX-License-Identifier: GPL-2.0-or-later 3*ca033107SNinad Palsule * Copyright (C) 2024 IBM Corp. 4*ca033107SNinad Palsule * 5*ca033107SNinad Palsule * IBM Flexible Service Interface master 6*ca033107SNinad Palsule */ 7*ca033107SNinad Palsule 8*ca033107SNinad Palsule #include "qemu/osdep.h" 9*ca033107SNinad Palsule #include "qapi/error.h" 10*ca033107SNinad Palsule #include "qemu/log.h" 11*ca033107SNinad Palsule #include "trace.h" 12*ca033107SNinad Palsule 13*ca033107SNinad Palsule #include "hw/fsi/fsi-master.h" 14*ca033107SNinad Palsule 15*ca033107SNinad Palsule #define TYPE_OP_BUS "opb" 16*ca033107SNinad Palsule 17*ca033107SNinad Palsule #define TO_REG(x) ((x) >> 2) 18*ca033107SNinad Palsule 19*ca033107SNinad Palsule #define FSI_MENP0 TO_REG(0x010) 20*ca033107SNinad Palsule #define FSI_MENP32 TO_REG(0x014) 21*ca033107SNinad Palsule #define FSI_MSENP0 TO_REG(0x018) 22*ca033107SNinad Palsule #define FSI_MLEVP0 TO_REG(0x018) 23*ca033107SNinad Palsule #define FSI_MSENP32 TO_REG(0x01c) 24*ca033107SNinad Palsule #define FSI_MLEVP32 TO_REG(0x01c) 25*ca033107SNinad Palsule #define FSI_MCENP0 TO_REG(0x020) 26*ca033107SNinad Palsule #define FSI_MREFP0 TO_REG(0x020) 27*ca033107SNinad Palsule #define FSI_MCENP32 TO_REG(0x024) 28*ca033107SNinad Palsule #define FSI_MREFP32 TO_REG(0x024) 29*ca033107SNinad Palsule 30*ca033107SNinad Palsule #define FSI_MVER TO_REG(0x074) 31*ca033107SNinad Palsule #define FSI_MRESP0 TO_REG(0x0d0) 32*ca033107SNinad Palsule 33*ca033107SNinad Palsule #define FSI_MRESB0 TO_REG(0x1d0) 34*ca033107SNinad Palsule #define FSI_MRESB0_RESET_GENERAL BIT(31) 35*ca033107SNinad Palsule #define FSI_MRESB0_RESET_ERROR BIT(30) 36*ca033107SNinad Palsule 37*ca033107SNinad Palsule static uint64_t fsi_master_read(void *opaque, hwaddr addr, unsigned size) 38*ca033107SNinad Palsule { 39*ca033107SNinad Palsule FSIMasterState *s = FSI_MASTER(opaque); 40*ca033107SNinad Palsule int reg = TO_REG(addr); 41*ca033107SNinad Palsule 42*ca033107SNinad Palsule trace_fsi_master_read(addr, size); 43*ca033107SNinad Palsule 44*ca033107SNinad Palsule if (reg >= FSI_MASTER_NR_REGS) { 45*ca033107SNinad Palsule qemu_log_mask(LOG_GUEST_ERROR, 46*ca033107SNinad Palsule "%s: Out of bounds read: 0x%"HWADDR_PRIx" for %u\n", 47*ca033107SNinad Palsule __func__, addr, size); 48*ca033107SNinad Palsule return 0; 49*ca033107SNinad Palsule } 50*ca033107SNinad Palsule 51*ca033107SNinad Palsule return s->regs[reg]; 52*ca033107SNinad Palsule } 53*ca033107SNinad Palsule 54*ca033107SNinad Palsule static void fsi_master_write(void *opaque, hwaddr addr, uint64_t data, 55*ca033107SNinad Palsule unsigned size) 56*ca033107SNinad Palsule { 57*ca033107SNinad Palsule FSIMasterState *s = FSI_MASTER(opaque); 58*ca033107SNinad Palsule int reg = TO_REG(addr); 59*ca033107SNinad Palsule 60*ca033107SNinad Palsule trace_fsi_master_write(addr, size, data); 61*ca033107SNinad Palsule 62*ca033107SNinad Palsule if (reg >= FSI_MASTER_NR_REGS) { 63*ca033107SNinad Palsule qemu_log_mask(LOG_GUEST_ERROR, 64*ca033107SNinad Palsule "%s: Out of bounds write: %"HWADDR_PRIx" for %u\n", 65*ca033107SNinad Palsule __func__, addr, size); 66*ca033107SNinad Palsule return; 67*ca033107SNinad Palsule } 68*ca033107SNinad Palsule 69*ca033107SNinad Palsule switch (reg) { 70*ca033107SNinad Palsule case FSI_MENP0: 71*ca033107SNinad Palsule s->regs[FSI_MENP0] = data; 72*ca033107SNinad Palsule break; 73*ca033107SNinad Palsule case FSI_MENP32: 74*ca033107SNinad Palsule s->regs[FSI_MENP32] = data; 75*ca033107SNinad Palsule break; 76*ca033107SNinad Palsule case FSI_MSENP0: 77*ca033107SNinad Palsule s->regs[FSI_MENP0] |= data; 78*ca033107SNinad Palsule break; 79*ca033107SNinad Palsule case FSI_MSENP32: 80*ca033107SNinad Palsule s->regs[FSI_MENP32] |= data; 81*ca033107SNinad Palsule break; 82*ca033107SNinad Palsule case FSI_MCENP0: 83*ca033107SNinad Palsule s->regs[FSI_MENP0] &= ~data; 84*ca033107SNinad Palsule break; 85*ca033107SNinad Palsule case FSI_MCENP32: 86*ca033107SNinad Palsule s->regs[FSI_MENP32] &= ~data; 87*ca033107SNinad Palsule break; 88*ca033107SNinad Palsule case FSI_MRESP0: 89*ca033107SNinad Palsule /* Perform necessary resets leave register 0 to indicate no errors */ 90*ca033107SNinad Palsule break; 91*ca033107SNinad Palsule case FSI_MRESB0: 92*ca033107SNinad Palsule if (data & FSI_MRESB0_RESET_GENERAL) { 93*ca033107SNinad Palsule device_cold_reset(DEVICE(opaque)); 94*ca033107SNinad Palsule } 95*ca033107SNinad Palsule if (data & FSI_MRESB0_RESET_ERROR) { 96*ca033107SNinad Palsule /* FIXME: this seems dubious */ 97*ca033107SNinad Palsule device_cold_reset(DEVICE(opaque)); 98*ca033107SNinad Palsule } 99*ca033107SNinad Palsule break; 100*ca033107SNinad Palsule default: 101*ca033107SNinad Palsule s->regs[reg] = data; 102*ca033107SNinad Palsule } 103*ca033107SNinad Palsule } 104*ca033107SNinad Palsule 105*ca033107SNinad Palsule static const struct MemoryRegionOps fsi_master_ops = { 106*ca033107SNinad Palsule .read = fsi_master_read, 107*ca033107SNinad Palsule .write = fsi_master_write, 108*ca033107SNinad Palsule .endianness = DEVICE_BIG_ENDIAN, 109*ca033107SNinad Palsule }; 110*ca033107SNinad Palsule 111*ca033107SNinad Palsule static void fsi_master_init(Object *o) 112*ca033107SNinad Palsule { 113*ca033107SNinad Palsule FSIMasterState *s = FSI_MASTER(o); 114*ca033107SNinad Palsule 115*ca033107SNinad Palsule object_initialize_child(o, "cfam", &s->cfam, TYPE_FSI_CFAM); 116*ca033107SNinad Palsule 117*ca033107SNinad Palsule qbus_init(&s->bus, sizeof(s->bus), TYPE_FSI_BUS, DEVICE(s), NULL); 118*ca033107SNinad Palsule 119*ca033107SNinad Palsule memory_region_init_io(&s->iomem, OBJECT(s), &fsi_master_ops, s, 120*ca033107SNinad Palsule TYPE_FSI_MASTER, 0x10000000); 121*ca033107SNinad Palsule memory_region_init(&s->opb2fsi, OBJECT(s), "fsi.opb2fsi", 0x10000000); 122*ca033107SNinad Palsule } 123*ca033107SNinad Palsule 124*ca033107SNinad Palsule static void fsi_master_realize(DeviceState *dev, Error **errp) 125*ca033107SNinad Palsule { 126*ca033107SNinad Palsule FSIMasterState *s = FSI_MASTER(dev); 127*ca033107SNinad Palsule 128*ca033107SNinad Palsule if (!qdev_realize(DEVICE(&s->cfam), BUS(&s->bus), errp)) { 129*ca033107SNinad Palsule return; 130*ca033107SNinad Palsule } 131*ca033107SNinad Palsule 132*ca033107SNinad Palsule /* address ? */ 133*ca033107SNinad Palsule memory_region_add_subregion(&s->opb2fsi, 0, &s->cfam.mr); 134*ca033107SNinad Palsule } 135*ca033107SNinad Palsule 136*ca033107SNinad Palsule static void fsi_master_reset(DeviceState *dev) 137*ca033107SNinad Palsule { 138*ca033107SNinad Palsule FSIMasterState *s = FSI_MASTER(dev); 139*ca033107SNinad Palsule 140*ca033107SNinad Palsule /* Initialize registers */ 141*ca033107SNinad Palsule memset(s->regs, 0, sizeof(s->regs)); 142*ca033107SNinad Palsule 143*ca033107SNinad Palsule /* ASPEED default */ 144*ca033107SNinad Palsule s->regs[FSI_MVER] = 0xe0050101; 145*ca033107SNinad Palsule } 146*ca033107SNinad Palsule 147*ca033107SNinad Palsule static void fsi_master_class_init(ObjectClass *klass, void *data) 148*ca033107SNinad Palsule { 149*ca033107SNinad Palsule DeviceClass *dc = DEVICE_CLASS(klass); 150*ca033107SNinad Palsule 151*ca033107SNinad Palsule dc->bus_type = TYPE_OP_BUS; 152*ca033107SNinad Palsule dc->desc = "FSI Master"; 153*ca033107SNinad Palsule dc->realize = fsi_master_realize; 154*ca033107SNinad Palsule dc->reset = fsi_master_reset; 155*ca033107SNinad Palsule } 156*ca033107SNinad Palsule 157*ca033107SNinad Palsule static const TypeInfo fsi_master_info = { 158*ca033107SNinad Palsule .name = TYPE_FSI_MASTER, 159*ca033107SNinad Palsule .parent = TYPE_DEVICE, 160*ca033107SNinad Palsule .instance_init = fsi_master_init, 161*ca033107SNinad Palsule .instance_size = sizeof(FSIMasterState), 162*ca033107SNinad Palsule .class_init = fsi_master_class_init, 163*ca033107SNinad Palsule }; 164*ca033107SNinad Palsule 165*ca033107SNinad Palsule static void fsi_register_types(void) 166*ca033107SNinad Palsule { 167*ca033107SNinad Palsule type_register_static(&fsi_master_info); 168*ca033107SNinad Palsule } 169*ca033107SNinad Palsule 170*ca033107SNinad Palsule type_init(fsi_register_types); 171