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 pnv_lpc_opb_read(adu->lpc, lpc_addr, (void *)&data, lpc_size); 120 121 /* 122 * ADU access is performed within 8-byte aligned sectors. Smaller 123 * access sizes don't get formatted to the least significant byte, 124 * but rather appear in the data reg at the same offset as the 125 * address in memory. This shifts them into that position. 126 */ 127 adu->lpc_data_reg = be64_to_cpu(data) >> ((lpc_addr & 7) * 8); 128 } 129 break; 130 131 case ADU_LPC_DATA_REG: 132 adu->lpc_data_reg = val; 133 if (lpc_cmd_write(adu)) { 134 uint32_t lpc_addr = lpc_cmd_addr(adu); 135 uint32_t lpc_size = lpc_cmd_size(adu); 136 uint64_t data; 137 138 data = cpu_to_be64(val) >> ((lpc_addr & 7) * 8); /* See above */ 139 pnv_lpc_opb_write(adu->lpc, lpc_addr, (void *)&data, lpc_size); 140 } 141 break; 142 143 case ADU_LPC_STATUS_REG: 144 qemu_log_mask(LOG_UNIMP, 145 "ADU: Changing LPC_STATUS_REG is not implemented\n"); 146 break; 147 148 default: 149 qemu_log_mask(LOG_UNIMP, "ADU Unimplemented write register: Ox%08x\n", 150 offset); 151 } 152 } 153 154 const MemoryRegionOps pnv_adu_xscom_ops = { 155 .read = pnv_adu_xscom_read, 156 .write = pnv_adu_xscom_write, 157 .valid.min_access_size = 8, 158 .valid.max_access_size = 8, 159 .impl.min_access_size = 8, 160 .impl.max_access_size = 8, 161 .endianness = DEVICE_BIG_ENDIAN, 162 }; 163 164 static void pnv_adu_realize(DeviceState *dev, Error **errp) 165 { 166 PnvADU *adu = PNV_ADU(dev); 167 168 assert(adu->lpc); 169 170 /* XScom regions for ADU registers */ 171 pnv_xscom_region_init(&adu->xscom_regs, OBJECT(dev), 172 &pnv_adu_xscom_ops, adu, "xscom-adu", 173 PNV9_XSCOM_ADU_SIZE); 174 } 175 176 static Property pnv_adu_properties[] = { 177 DEFINE_PROP_LINK("lpc", PnvADU, lpc, TYPE_PNV_LPC, PnvLpcController *), 178 DEFINE_PROP_END_OF_LIST(), 179 }; 180 181 static void pnv_adu_class_init(ObjectClass *klass, void *data) 182 { 183 DeviceClass *dc = DEVICE_CLASS(klass); 184 185 dc->realize = pnv_adu_realize; 186 dc->desc = "PowerNV ADU"; 187 device_class_set_props(dc, pnv_adu_properties); 188 dc->user_creatable = false; 189 } 190 191 static const TypeInfo pnv_adu_type_info = { 192 .name = TYPE_PNV_ADU, 193 .parent = TYPE_DEVICE, 194 .instance_size = sizeof(PnvADU), 195 .class_init = pnv_adu_class_init, 196 .interfaces = (InterfaceInfo[]) { 197 { TYPE_PNV_XSCOM_INTERFACE }, 198 { } }, 199 }; 200 201 static void pnv_adu_register_types(void) 202 { 203 type_register_static(&pnv_adu_type_info); 204 } 205 206 type_init(pnv_adu_register_types); 207