1 /* 2 * SPDX-License-Identifier: GPL-2.0-or-later 3 * Copyright (C) 2024 IBM Corp. 4 * 5 * IBM Common FRU Access Macro 6 */ 7 8 #include "qemu/osdep.h" 9 #include "qemu/units.h" 10 11 #include "qapi/error.h" 12 #include "trace.h" 13 14 #include "hw/fsi/cfam.h" 15 #include "hw/fsi/fsi.h" 16 17 #include "hw/qdev-properties.h" 18 19 #define ENGINE_CONFIG_NEXT BIT(31) 20 #define ENGINE_CONFIG_TYPE_PEEK (0x02 << 4) 21 #define ENGINE_CONFIG_TYPE_FSI (0x03 << 4) 22 #define ENGINE_CONFIG_TYPE_SCRATCHPAD (0x06 << 4) 23 24 /* Valid, slots, version, type, crc */ 25 #define CFAM_CONFIG_REG(__VER, __TYPE, __CRC) \ 26 (ENGINE_CONFIG_NEXT | \ 27 0x00010000 | \ 28 (__VER) | \ 29 (__TYPE) | \ 30 (__CRC)) 31 32 #define TO_REG(x) ((x) >> 2) 33 34 #define CFAM_CONFIG_CHIP_ID TO_REG(0x00) 35 #define CFAM_CONFIG_PEEK_STATUS TO_REG(0x04) 36 #define CFAM_CONFIG_CHIP_ID_P9 0xc0022d15 37 #define CFAM_CONFIG_CHIP_ID_BREAK 0xc0de0000 38 39 static uint64_t fsi_cfam_config_read(void *opaque, hwaddr addr, unsigned size) 40 { 41 trace_fsi_cfam_config_read(addr, size); 42 43 switch (addr) { 44 case 0x00: 45 return CFAM_CONFIG_CHIP_ID_P9; 46 case 0x04: 47 return CFAM_CONFIG_REG(0x1000, ENGINE_CONFIG_TYPE_PEEK, 0xc); 48 case 0x08: 49 return CFAM_CONFIG_REG(0x5000, ENGINE_CONFIG_TYPE_FSI, 0xa); 50 case 0xc: 51 return CFAM_CONFIG_REG(0x1000, ENGINE_CONFIG_TYPE_SCRATCHPAD, 0x7); 52 default: 53 /* 54 * The config table contains different engines from 0xc onwards. 55 * The scratch pad is already added at address 0xc. We need to add 56 * future engines from address 0x10 onwards. Returning 0 as engine 57 * is not implemented. 58 */ 59 return 0; 60 } 61 } 62 63 static void fsi_cfam_config_write(void *opaque, hwaddr addr, uint64_t data, 64 unsigned size) 65 { 66 FSICFAMState *cfam = FSI_CFAM(opaque); 67 68 trace_fsi_cfam_config_write(addr, size, data); 69 70 switch (TO_REG(addr)) { 71 case CFAM_CONFIG_CHIP_ID: 72 case CFAM_CONFIG_PEEK_STATUS: 73 if (data == CFAM_CONFIG_CHIP_ID_BREAK) { 74 bus_cold_reset(BUS(&cfam->lbus)); 75 } 76 break; 77 default: 78 trace_fsi_cfam_config_write_noaddr(addr, size, data); 79 } 80 } 81 82 static const struct MemoryRegionOps cfam_config_ops = { 83 .read = fsi_cfam_config_read, 84 .write = fsi_cfam_config_write, 85 .valid.max_access_size = 4, 86 .valid.min_access_size = 4, 87 .impl.max_access_size = 4, 88 .impl.min_access_size = 4, 89 .endianness = DEVICE_BIG_ENDIAN, 90 }; 91 92 static uint64_t fsi_cfam_unimplemented_read(void *opaque, hwaddr addr, 93 unsigned size) 94 { 95 trace_fsi_cfam_unimplemented_read(addr, size); 96 97 return 0; 98 } 99 100 static void fsi_cfam_unimplemented_write(void *opaque, hwaddr addr, 101 uint64_t data, unsigned size) 102 { 103 trace_fsi_cfam_unimplemented_write(addr, size, data); 104 } 105 106 static const struct MemoryRegionOps fsi_cfam_unimplemented_ops = { 107 .read = fsi_cfam_unimplemented_read, 108 .write = fsi_cfam_unimplemented_write, 109 .endianness = DEVICE_BIG_ENDIAN, 110 }; 111 112 static void fsi_cfam_instance_init(Object *obj) 113 { 114 FSICFAMState *s = FSI_CFAM(obj); 115 116 object_initialize_child(obj, "scratchpad", &s->scratchpad, 117 TYPE_FSI_SCRATCHPAD); 118 } 119 120 static void fsi_cfam_realize(DeviceState *dev, Error **errp) 121 { 122 FSICFAMState *cfam = FSI_CFAM(dev); 123 FSISlaveState *slave = FSI_SLAVE(dev); 124 125 /* Each slave has a 2MiB address space */ 126 memory_region_init_io(&cfam->mr, OBJECT(cfam), &fsi_cfam_unimplemented_ops, 127 cfam, TYPE_FSI_CFAM, 2 * MiB); 128 129 qbus_init(&cfam->lbus, sizeof(cfam->lbus), TYPE_FSI_LBUS, DEVICE(cfam), 130 NULL); 131 132 memory_region_init_io(&cfam->config_iomem, OBJECT(cfam), &cfam_config_ops, 133 cfam, TYPE_FSI_CFAM ".config", 0x400); 134 135 memory_region_add_subregion(&cfam->mr, 0, &cfam->config_iomem); 136 memory_region_add_subregion(&cfam->mr, 0x800, &slave->iomem); 137 memory_region_add_subregion(&cfam->mr, 0xc00, &cfam->lbus.mr); 138 139 /* Add scratchpad engine */ 140 if (!qdev_realize(DEVICE(&cfam->scratchpad), BUS(&cfam->lbus), errp)) { 141 return; 142 } 143 144 FSILBusDevice *fsi_dev = FSI_LBUS_DEVICE(&cfam->scratchpad); 145 memory_region_add_subregion(&cfam->lbus.mr, 0, &fsi_dev->iomem); 146 } 147 148 static void fsi_cfam_class_init(ObjectClass *klass, void *data) 149 { 150 DeviceClass *dc = DEVICE_CLASS(klass); 151 dc->bus_type = TYPE_FSI_BUS; 152 dc->realize = fsi_cfam_realize; 153 } 154 155 static const TypeInfo fsi_cfam_info = { 156 .name = TYPE_FSI_CFAM, 157 .parent = TYPE_FSI_SLAVE, 158 .instance_init = fsi_cfam_instance_init, 159 .instance_size = sizeof(FSICFAMState), 160 .class_init = fsi_cfam_class_init, 161 }; 162 163 static void fsi_cfam_register_types(void) 164 { 165 type_register_static(&fsi_cfam_info); 166 } 167 168 type_init(fsi_cfam_register_types); 169