1 /* 2 * QEMU PowerPC PowerNV ADU unit 3 * 4 * The ADU unit actually implements XSCOM, which is the bridge between MMIO 5 * and PIB. However it also includes control and status registers and other 6 * functions that are exposed as PIB (xscom) registers. 7 * 8 * To keep things simple, pnv_xscom.c remains the XSCOM bridge 9 * implementation, and pnv_adu.c implements the ADU registers and other 10 * functions. 11 * 12 * Copyright (c) 2024, IBM Corporation. 13 * 14 * SPDX-License-Identifier: GPL-2.0-or-later 15 */ 16 17 #include "qemu/osdep.h" 18 #include "qemu/log.h" 19 20 #include "hw/qdev-properties.h" 21 #include "hw/ppc/pnv.h" 22 #include "hw/ppc/pnv_adu.h" 23 #include "hw/ppc/pnv_chip.h" 24 #include "hw/ppc/pnv_lpc.h" 25 #include "hw/ppc/pnv_xscom.h" 26 #include "trace.h" 27 28 #define ADU_LPC_BASE_REG 0x40 29 #define ADU_LPC_CMD_REG 0x41 30 #define ADU_LPC_DATA_REG 0x42 31 #define ADU_LPC_STATUS_REG 0x43 32 33 static uint64_t pnv_adu_xscom_read(void *opaque, hwaddr addr, unsigned width) 34 { 35 PnvADU *adu = PNV_ADU(opaque); 36 uint32_t offset = addr >> 3; 37 uint64_t val = 0; 38 39 switch (offset) { 40 case 0x18: /* Receive status reg */ 41 case 0x12: /* log register */ 42 case 0x13: /* error register */ 43 break; 44 case ADU_LPC_BASE_REG: 45 /* 46 * LPC Address Map in Pervasive ADU Workbook 47 * 48 * return PNV10_LPCM_BASE(chip) & PPC_BITMASK(8, 31); 49 * XXX: implement as class property, or get from LPC? 50 */ 51 qemu_log_mask(LOG_UNIMP, "ADU: LPC_BASE_REG is not implemented\n"); 52 break; 53 case ADU_LPC_CMD_REG: 54 val = adu->lpc_cmd_reg; 55 break; 56 case ADU_LPC_DATA_REG: 57 val = adu->lpc_data_reg; 58 break; 59 case ADU_LPC_STATUS_REG: 60 val = PPC_BIT(0); /* ack / done */ 61 break; 62 63 default: 64 qemu_log_mask(LOG_UNIMP, "ADU Unimplemented read register: Ox%08x\n", 65 offset); 66 } 67 68 trace_pnv_adu_xscom_read(addr, val); 69 70 return val; 71 } 72 73 static bool lpc_cmd_read(PnvADU *adu) 74 { 75 return !!(adu->lpc_cmd_reg & PPC_BIT(0)); 76 } 77 78 static bool lpc_cmd_write(PnvADU *adu) 79 { 80 return !lpc_cmd_read(adu); 81 } 82 83 static uint32_t lpc_cmd_addr(PnvADU *adu) 84 { 85 return (adu->lpc_cmd_reg & PPC_BITMASK(32, 63)) >> PPC_BIT_NR(63); 86 } 87 88 static uint32_t lpc_cmd_size(PnvADU *adu) 89 { 90 return (adu->lpc_cmd_reg & PPC_BITMASK(5, 11)) >> PPC_BIT_NR(11); 91 } 92 93 static void pnv_adu_xscom_write(void *opaque, hwaddr addr, uint64_t val, 94 unsigned width) 95 { 96 PnvADU *adu = PNV_ADU(opaque); 97 uint32_t offset = addr >> 3; 98 99 trace_pnv_adu_xscom_write(addr, val); 100 101 switch (offset) { 102 case 0x18: /* Receive status reg */ 103 case 0x12: /* log register */ 104 case 0x13: /* error register */ 105 break; 106 107 case ADU_LPC_BASE_REG: 108 qemu_log_mask(LOG_UNIMP, 109 "ADU: Changing LPC_BASE_REG is not implemented\n"); 110 break; 111 112 case ADU_LPC_CMD_REG: 113 adu->lpc_cmd_reg = val; 114 if (lpc_cmd_read(adu)) { 115 uint32_t lpc_addr = lpc_cmd_addr(adu); 116 uint32_t lpc_size = lpc_cmd_size(adu); 117 uint64_t data = 0; 118 119 if (!is_power_of_2(lpc_size) || lpc_size > sizeof(data)) { 120 qemu_log_mask(LOG_GUEST_ERROR, "ADU: Unsupported LPC access " 121 "size:%" PRId32 "\n", lpc_size); 122 break; 123 } 124 125 pnv_lpc_opb_read(adu->lpc, lpc_addr, (void *)&data, lpc_size); 126 127 /* 128 * ADU access is performed within 8-byte aligned sectors. Smaller 129 * access sizes don't get formatted to the least significant byte, 130 * but rather appear in the data reg at the same offset as the 131 * address in memory. This shifts them into that position. 132 */ 133 adu->lpc_data_reg = be64_to_cpu(data) >> ((lpc_addr & 7) * 8); 134 } 135 break; 136 137 case ADU_LPC_DATA_REG: 138 adu->lpc_data_reg = val; 139 if (lpc_cmd_write(adu)) { 140 uint32_t lpc_addr = lpc_cmd_addr(adu); 141 uint32_t lpc_size = lpc_cmd_size(adu); 142 uint64_t data; 143 144 if (!is_power_of_2(lpc_size) || lpc_size > sizeof(data)) { 145 qemu_log_mask(LOG_GUEST_ERROR, "ADU: Unsupported LPC access " 146 "size:%" PRId32 "\n", lpc_size); 147 break; 148 } 149 150 data = cpu_to_be64(val) >> ((lpc_addr & 7) * 8); /* See above */ 151 pnv_lpc_opb_write(adu->lpc, lpc_addr, (void *)&data, lpc_size); 152 } 153 break; 154 155 case ADU_LPC_STATUS_REG: 156 qemu_log_mask(LOG_UNIMP, 157 "ADU: Changing LPC_STATUS_REG is not implemented\n"); 158 break; 159 160 default: 161 qemu_log_mask(LOG_UNIMP, "ADU Unimplemented write register: Ox%08x\n", 162 offset); 163 } 164 } 165 166 const MemoryRegionOps pnv_adu_xscom_ops = { 167 .read = pnv_adu_xscom_read, 168 .write = pnv_adu_xscom_write, 169 .valid.min_access_size = 8, 170 .valid.max_access_size = 8, 171 .impl.min_access_size = 8, 172 .impl.max_access_size = 8, 173 .endianness = DEVICE_BIG_ENDIAN, 174 }; 175 176 static void pnv_adu_realize(DeviceState *dev, Error **errp) 177 { 178 PnvADU *adu = PNV_ADU(dev); 179 180 assert(adu->lpc); 181 182 /* XScom regions for ADU registers */ 183 pnv_xscom_region_init(&adu->xscom_regs, OBJECT(dev), 184 &pnv_adu_xscom_ops, adu, "xscom-adu", 185 PNV9_XSCOM_ADU_SIZE); 186 } 187 188 static Property pnv_adu_properties[] = { 189 DEFINE_PROP_LINK("lpc", PnvADU, lpc, TYPE_PNV_LPC, PnvLpcController *), 190 DEFINE_PROP_END_OF_LIST(), 191 }; 192 193 static void pnv_adu_class_init(ObjectClass *klass, void *data) 194 { 195 DeviceClass *dc = DEVICE_CLASS(klass); 196 197 dc->realize = pnv_adu_realize; 198 dc->desc = "PowerNV ADU"; 199 device_class_set_props(dc, pnv_adu_properties); 200 dc->user_creatable = false; 201 } 202 203 static const TypeInfo pnv_adu_type_info = { 204 .name = TYPE_PNV_ADU, 205 .parent = TYPE_DEVICE, 206 .instance_size = sizeof(PnvADU), 207 .class_init = pnv_adu_class_init, 208 .interfaces = (InterfaceInfo[]) { 209 { TYPE_PNV_XSCOM_INTERFACE }, 210 { } }, 211 }; 212 213 static void pnv_adu_register_types(void) 214 { 215 type_register_static(&pnv_adu_type_info); 216 } 217 218 type_init(pnv_adu_register_types); 219