1 /* 2 * ASPEED PCIe Host Controller 3 * 4 * Copyright (C) 2025 ASPEED Technology Inc. 5 * Copyright (c) 2022 Cédric Le Goater <clg@kaod.org> 6 * 7 * Jamin Lin <jamin_lin@aspeedtech.com> 8 * 9 * SPDX-License-Identifier: GPL-2.0-or-later 10 * 11 * This file is based on Cédric Le Goater's patch: 12 * "pci: Add Aspeed host bridge (WIP)" 13 * https://github.com/legoater/qemu/commit/d1b97b0c7844219d847122410dc189854f9d26df 14 * 15 * Modifications have been made to support the Aspeed AST2600 and AST2700 16 * platforms. 17 */ 18 19 #include "qemu/osdep.h" 20 #include "qemu/log.h" 21 #include "qapi/error.h" 22 #include "hw/qdev-properties.h" 23 #include "hw/registerfields.h" 24 #include "hw/irq.h" 25 #include "hw/pci/pci_host.h" 26 #include "hw/pci-host/aspeed_pcie.h" 27 #include "hw/pci/msi.h" 28 #include "trace.h" 29 30 /* 31 * PCIe Root 32 */ 33 34 static void aspeed_pcie_root_class_init(ObjectClass *klass, const void *data) 35 { 36 PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); 37 DeviceClass *dc = DEVICE_CLASS(klass); 38 39 set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); 40 dc->desc = "ASPEED PCIe Host Bridge"; 41 k->vendor_id = PCI_VENDOR_ID_ASPEED; 42 k->device_id = 0x1150; 43 k->class_id = PCI_CLASS_BRIDGE_HOST; 44 k->revision = 0; 45 46 /* 47 * PCI-facing part of the host bridge, 48 * not usable without the host-facing part 49 */ 50 dc->user_creatable = false; 51 } 52 53 static const TypeInfo aspeed_pcie_root_info = { 54 .name = TYPE_ASPEED_PCIE_ROOT, 55 .parent = TYPE_PCI_DEVICE, 56 .instance_size = sizeof(AspeedPCIERootState), 57 .class_init = aspeed_pcie_root_class_init, 58 .interfaces = (const InterfaceInfo[]) { 59 { INTERFACE_CONVENTIONAL_PCI_DEVICE }, 60 { }, 61 }, 62 }; 63 64 /* 65 * PCIe Root Complex (RC) 66 */ 67 68 static void aspeed_pcie_rc_set_irq(void *opaque, int irq, int level) 69 { 70 AspeedPCIERcState *rc = (AspeedPCIERcState *) opaque; 71 AspeedPCIECfgState *cfg = 72 container_of(rc, AspeedPCIECfgState, rc); 73 AspeedPCIECfgClass *apc = ASPEED_PCIE_CFG_GET_CLASS(cfg); 74 const AspeedPCIERcRegs *rc_regs; 75 bool intx; 76 77 assert(irq < PCI_NUM_PINS); 78 79 rc_regs = &apc->reg_map->rc; 80 81 if (level) { 82 cfg->regs[rc_regs->int_sts_reg] |= BIT(irq); 83 } else { 84 cfg->regs[rc_regs->int_sts_reg] &= ~BIT(irq); 85 } 86 87 intx = !!(cfg->regs[rc_regs->int_sts_reg] & cfg->regs[rc_regs->int_en_reg]); 88 trace_aspeed_pcie_rc_intx_set_irq(cfg->id, irq, intx); 89 qemu_set_irq(rc->irq, intx); 90 } 91 92 static int aspeed_pcie_rc_map_irq(PCIDevice *pci_dev, int irq_num) 93 { 94 return irq_num % PCI_NUM_PINS; 95 } 96 97 static void aspeed_pcie_rc_realize(DeviceState *dev, Error **errp) 98 { 99 PCIExpressHost *pex = PCIE_HOST_BRIDGE(dev); 100 AspeedPCIERcState *rc = ASPEED_PCIE_RC(dev); 101 AspeedPCIECfgState *cfg = 102 container_of(rc, AspeedPCIECfgState, rc); 103 PCIHostState *pci = PCI_HOST_BRIDGE(dev); 104 SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 105 g_autofree char *name; 106 107 /* PCI configuration space */ 108 pcie_host_mmcfg_init(pex, PCIE_MMCFG_SIZE_MAX); 109 sysbus_init_mmio(sbd, &pex->mmio); 110 111 /* MMIO and IO region */ 112 memory_region_init(&rc->mmio, OBJECT(rc), "mmio", UINT64_MAX); 113 memory_region_init(&rc->io, OBJECT(rc), "io", 0x10000); 114 115 name = g_strdup_printf("pcie.%d.mmio_window", cfg->id); 116 memory_region_init_io(&rc->mmio_window, OBJECT(rc), &unassigned_io_ops, 117 OBJECT(rc), name, UINT64_MAX); 118 name = g_strdup_printf("pcie.%d.ioport_window", cfg->id); 119 memory_region_init_io(&rc->io_window, OBJECT(rc), &unassigned_io_ops, 120 OBJECT(rc), name, 0x10000); 121 122 memory_region_add_subregion(&rc->mmio_window, 0, &rc->mmio); 123 memory_region_add_subregion(&rc->io_window, 0, &rc->io); 124 sysbus_init_mmio(sbd, &rc->mmio_window); 125 sysbus_init_mmio(sbd, &rc->io_window); 126 127 sysbus_init_irq(sbd, &rc->irq); 128 pci->bus = pci_register_root_bus(dev, NULL, aspeed_pcie_rc_set_irq, 129 aspeed_pcie_rc_map_irq, rc, &rc->mmio, 130 &rc->io, 0, 4, TYPE_PCIE_BUS); 131 pci->bus->flags |= PCI_BUS_EXTENDED_CONFIG_SPACE; 132 133 qdev_realize(DEVICE(&rc->root), BUS(pci->bus), &error_fatal); 134 } 135 136 static const char *aspeed_pcie_rc_root_bus_path(PCIHostState *host_bridge, 137 PCIBus *rootbus) 138 { 139 AspeedPCIERcState *s = ASPEED_PCIE_RC(host_bridge); 140 141 snprintf(s->name, sizeof(s->name), "0000:%02x", s->bus_nr); 142 143 return s->name; 144 } 145 146 static void aspeed_pcie_rc_instance_init(Object *obj) 147 { 148 AspeedPCIERcState *s = ASPEED_PCIE_RC(obj); 149 AspeedPCIERootState *root = &s->root; 150 151 object_initialize_child(obj, "root", root, TYPE_ASPEED_PCIE_ROOT); 152 qdev_prop_set_int32(DEVICE(root), "addr", PCI_DEVFN(0, 0)); 153 qdev_prop_set_bit(DEVICE(root), "multifunction", false); 154 } 155 156 static const Property aspeed_pcie_rc_props[] = { 157 DEFINE_PROP_UINT32("bus-nr", AspeedPCIERcState, bus_nr, 0), 158 }; 159 160 static void aspeed_pcie_rc_class_init(ObjectClass *klass, const void *data) 161 { 162 PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(klass); 163 DeviceClass *dc = DEVICE_CLASS(klass); 164 165 dc->desc = "ASPEED PCIe RC"; 166 dc->realize = aspeed_pcie_rc_realize; 167 dc->fw_name = "pci"; 168 set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); 169 170 hc->root_bus_path = aspeed_pcie_rc_root_bus_path; 171 device_class_set_props(dc, aspeed_pcie_rc_props); 172 173 msi_nonbroken = true; 174 } 175 176 static const TypeInfo aspeed_pcie_rc_info = { 177 .name = TYPE_ASPEED_PCIE_RC, 178 .parent = TYPE_PCIE_HOST_BRIDGE, 179 .instance_size = sizeof(AspeedPCIERcState), 180 .instance_init = aspeed_pcie_rc_instance_init, 181 .class_init = aspeed_pcie_rc_class_init, 182 }; 183 184 /* 185 * PCIe Config 186 * 187 * AHB to PCIe Bus Bridge (H2X) 188 * 189 * On the AST2600: 190 * NOTE: rc_l is not supported by this model. 191 * - Registers 0x00 - 0x7F are shared by both PCIe0 (rc_l) and PCIe1 (rc_h). 192 * - Registers 0x80 - 0xBF are specific to PCIe0. 193 * - Registers 0xC0 - 0xFF are specific to PCIe1. 194 */ 195 196 /* AST2600 */ 197 REG32(H2X_CTRL, 0x00) 198 FIELD(H2X_CTRL, CLEAR_RX, 4, 1) 199 REG32(H2X_TX_CLEAR, 0x08) 200 FIELD(H2X_TX_CLEAR, IDLE, 0, 1) 201 REG32(H2X_RDATA, 0x0C) 202 REG32(H2X_TX_DESC0, 0x10) 203 REG32(H2X_TX_DESC1, 0x14) 204 REG32(H2X_TX_DESC2, 0x18) 205 REG32(H2X_TX_DESC3, 0x1C) 206 REG32(H2X_TX_DATA, 0x20) 207 REG32(H2X_TX_STS, 0x24) 208 FIELD(H2X_TX_STS, IDLE, 31, 1) 209 FIELD(H2X_TX_STS, RC_L_TX_COMP, 24, 1) 210 FIELD(H2X_TX_STS, RC_H_TX_COMP, 25, 1) 211 FIELD(H2X_TX_STS, TRIG, 0, 1) 212 REG32(H2X_RC_H_CTRL, 0xC0) 213 REG32(H2X_RC_H_INT_EN, 0xC4) 214 REG32(H2X_RC_H_INT_STS, 0xC8) 215 SHARED_FIELD(H2X_RC_INT_INTDONE, 4, 1) 216 SHARED_FIELD(H2X_RC_INT_INTX, 0, 4) 217 REG32(H2X_RC_H_RDATA, 0xCC) 218 219 #define TLP_FMTTYPE_CFGRD0 0x04 /* Configuration Read Type 0 */ 220 #define TLP_FMTTYPE_CFGWR0 0x44 /* Configuration Write Type 0 */ 221 #define TLP_FMTTYPE_CFGRD1 0x05 /* Configuration Read Type 1 */ 222 #define TLP_FMTTYPE_CFGWR1 0x45 /* Configuration Write Type 1 */ 223 224 #define PCIE_CFG_FMTTYPE_MASK(x) (((x) >> 24) & 0xff) 225 #define PCIE_CFG_BYTE_EN(x) ((x) & 0xf) 226 227 static const AspeedPCIERegMap aspeed_regmap = { 228 .rc = { 229 .int_en_reg = R_H2X_RC_H_INT_EN, 230 .int_sts_reg = R_H2X_RC_H_INT_STS, 231 }, 232 }; 233 234 static uint64_t aspeed_pcie_cfg_read(void *opaque, hwaddr addr, 235 unsigned int size) 236 { 237 AspeedPCIECfgState *s = ASPEED_PCIE_CFG(opaque); 238 uint32_t reg = addr >> 2; 239 uint32_t value = 0; 240 241 value = s->regs[reg]; 242 243 trace_aspeed_pcie_cfg_read(s->id, addr, value); 244 245 return value; 246 } 247 248 static void aspeed_pcie_cfg_translate_write(uint8_t byte_en, uint32_t *addr, 249 uint64_t *val, int *len) 250 { 251 uint64_t packed_val = 0; 252 int first_bit = -1; 253 int index = 0; 254 int i; 255 256 *len = ctpop8(byte_en); 257 258 if (*len == 0 || *len > 4) { 259 goto err; 260 } 261 262 /* Special case: full 4-byte write must be 4-byte aligned */ 263 if (byte_en == 0x0f) { 264 if (*addr % 4 != 0) { 265 goto err; 266 } 267 *val = *val & 0xffffffff; 268 return; 269 } 270 271 for (i = 0; i < 4; i++) { 272 if (byte_en & (1 << i)) { 273 if (first_bit < 0) { 274 first_bit = i; 275 } 276 packed_val |= ((*val >> (i * 8)) & 0xff) << (index * 8); 277 index++; 278 } 279 } 280 281 *addr += first_bit; 282 *val = packed_val; 283 284 return; 285 286 err: 287 qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid byte enable: 0x%x\n", 288 __func__, byte_en); 289 } 290 291 static void aspeed_pcie_cfg_readwrite(AspeedPCIECfgState *s, 292 const AspeedPCIECfgTxDesc *desc) 293 { 294 AspeedPCIERcState *rc = &s->rc; 295 PCIHostState *pci; 296 uint32_t cfg_addr; 297 PCIDevice *pdev; 298 uint32_t offset; 299 uint8_t byte_en; 300 bool is_write; 301 uint8_t devfn; 302 uint64_t val; 303 uint8_t bus; 304 int len; 305 306 val = ~0; 307 is_write = !!(desc->desc0 & BIT(30)); 308 cfg_addr = desc->desc2; 309 310 bus = (cfg_addr >> 24) & 0xff; 311 devfn = (cfg_addr >> 16) & 0xff; 312 offset = cfg_addr & 0xffc; 313 314 pci = PCI_HOST_BRIDGE(rc); 315 316 /* 317 * On the AST2600, the RC_H bus number ranges from 0x80 to 0xFF, and its 318 * root port uses bus number 0x80 instead of the standard 0x00. To locate 319 * the device at root port 0, remap bus number 0x80 to 0x00 so that the 320 * PCI subsystem can correctly discover the devices. 321 */ 322 if (bus == rc->bus_nr) { 323 bus = 0; 324 } 325 326 pdev = pci_find_device(pci->bus, bus, devfn); 327 if (!pdev) { 328 s->regs[desc->rdata_reg] = ~0; 329 goto out; 330 } 331 332 switch (PCIE_CFG_FMTTYPE_MASK(desc->desc0)) { 333 case TLP_FMTTYPE_CFGWR0: 334 case TLP_FMTTYPE_CFGWR1: 335 byte_en = PCIE_CFG_BYTE_EN(desc->desc1); 336 val = desc->wdata; 337 aspeed_pcie_cfg_translate_write(byte_en, &offset, &val, &len); 338 pci_host_config_write_common(pdev, offset, pci_config_size(pdev), 339 val, len); 340 break; 341 case TLP_FMTTYPE_CFGRD0: 342 case TLP_FMTTYPE_CFGRD1: 343 val = pci_host_config_read_common(pdev, offset, 344 pci_config_size(pdev), 4); 345 s->regs[desc->rdata_reg] = val; 346 break; 347 default: 348 qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid CFG type. DESC0=0x%x\n", 349 __func__, desc->desc0); 350 } 351 352 out: 353 trace_aspeed_pcie_cfg_rw(s->id, is_write ? "write" : "read", bus, devfn, 354 cfg_addr, val); 355 } 356 357 static void aspeed_pcie_cfg_write(void *opaque, hwaddr addr, uint64_t data, 358 unsigned int size) 359 { 360 AspeedPCIECfgState *s = ASPEED_PCIE_CFG(opaque); 361 AspeedPCIECfgClass *apc = ASPEED_PCIE_CFG_GET_CLASS(s); 362 AspeedPCIECfgTxDesc desc; 363 uint32_t reg = addr >> 2; 364 uint32_t rc_reg; 365 366 trace_aspeed_pcie_cfg_write(s->id, addr, data); 367 368 switch (reg) { 369 case R_H2X_CTRL: 370 if (data & R_H2X_CTRL_CLEAR_RX_MASK) { 371 s->regs[R_H2X_RDATA] = ~0; 372 } 373 break; 374 case R_H2X_TX_CLEAR: 375 if (data & R_H2X_TX_CLEAR_IDLE_MASK) { 376 s->regs[R_H2X_TX_STS] &= ~R_H2X_TX_STS_IDLE_MASK; 377 } 378 break; 379 case R_H2X_TX_STS: 380 if (data & R_H2X_TX_STS_TRIG_MASK) { 381 desc.desc0 = s->regs[R_H2X_TX_DESC0]; 382 desc.desc1 = s->regs[R_H2X_TX_DESC1]; 383 desc.desc2 = s->regs[R_H2X_TX_DESC2]; 384 desc.desc3 = s->regs[R_H2X_TX_DESC3]; 385 desc.wdata = s->regs[R_H2X_TX_DATA]; 386 desc.rdata_reg = R_H2X_RC_H_RDATA; 387 aspeed_pcie_cfg_readwrite(s, &desc); 388 rc_reg = apc->reg_map->rc.int_sts_reg; 389 s->regs[rc_reg] |= H2X_RC_INT_INTDONE_MASK; 390 s->regs[R_H2X_TX_STS] |= 391 BIT(R_H2X_TX_STS_RC_H_TX_COMP_SHIFT); 392 s->regs[R_H2X_TX_STS] |= R_H2X_TX_STS_IDLE_MASK; 393 } 394 break; 395 /* preserve INTx status */ 396 case R_H2X_RC_H_INT_STS: 397 if (data & H2X_RC_INT_INTDONE_MASK) { 398 s->regs[R_H2X_TX_STS] &= ~R_H2X_TX_STS_RC_H_TX_COMP_MASK; 399 } 400 s->regs[reg] &= ~data | H2X_RC_INT_INTX_MASK; 401 break; 402 default: 403 s->regs[reg] = data; 404 break; 405 } 406 } 407 408 static const MemoryRegionOps aspeed_pcie_cfg_ops = { 409 .read = aspeed_pcie_cfg_read, 410 .write = aspeed_pcie_cfg_write, 411 .endianness = DEVICE_LITTLE_ENDIAN, 412 .valid = { 413 .min_access_size = 1, 414 .max_access_size = 4, 415 }, 416 }; 417 418 static void aspeed_pcie_cfg_instance_init(Object *obj) 419 { 420 AspeedPCIECfgState *s = ASPEED_PCIE_CFG(obj); 421 422 object_initialize_child(obj, "rc", &s->rc, TYPE_ASPEED_PCIE_RC); 423 424 return; 425 } 426 427 static void aspeed_pcie_cfg_reset(DeviceState *dev) 428 { 429 AspeedPCIECfgState *s = ASPEED_PCIE_CFG(dev); 430 AspeedPCIECfgClass *apc = ASPEED_PCIE_CFG_GET_CLASS(s); 431 432 memset(s->regs, 0, apc->nr_regs << 2); 433 } 434 435 static void aspeed_pcie_cfg_realize(DeviceState *dev, Error **errp) 436 { 437 SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 438 AspeedPCIECfgState *s = ASPEED_PCIE_CFG(dev); 439 AspeedPCIECfgClass *apc = ASPEED_PCIE_CFG_GET_CLASS(s); 440 g_autofree char *name; 441 442 s->regs = g_new(uint32_t, apc->nr_regs); 443 name = g_strdup_printf(TYPE_ASPEED_PCIE_CFG ".regs.%d", s->id); 444 memory_region_init_io(&s->mmio, OBJECT(s), apc->reg_ops, s, name, 445 apc->nr_regs << 2); 446 sysbus_init_mmio(sbd, &s->mmio); 447 448 object_property_set_int(OBJECT(&s->rc), "bus-nr", 449 apc->rc_bus_nr, 450 &error_abort); 451 if (!sysbus_realize(SYS_BUS_DEVICE(&s->rc), errp)) { 452 return; 453 } 454 } 455 456 static void aspeed_pcie_cfg_unrealize(DeviceState *dev) 457 { 458 AspeedPCIECfgState *s = ASPEED_PCIE_CFG(dev); 459 460 g_free(s->regs); 461 s->regs = NULL; 462 } 463 464 static const Property aspeed_pcie_cfg_props[] = { 465 DEFINE_PROP_UINT32("id", AspeedPCIECfgState, id, 0), 466 }; 467 468 static void aspeed_pcie_cfg_class_init(ObjectClass *klass, const void *data) 469 { 470 DeviceClass *dc = DEVICE_CLASS(klass); 471 AspeedPCIECfgClass *apc = ASPEED_PCIE_CFG_CLASS(klass); 472 473 dc->desc = "ASPEED PCIe Config"; 474 dc->realize = aspeed_pcie_cfg_realize; 475 dc->unrealize = aspeed_pcie_cfg_unrealize; 476 device_class_set_legacy_reset(dc, aspeed_pcie_cfg_reset); 477 device_class_set_props(dc, aspeed_pcie_cfg_props); 478 479 apc->reg_ops = &aspeed_pcie_cfg_ops; 480 apc->reg_map = &aspeed_regmap; 481 apc->nr_regs = 0x100 >> 2; 482 apc->rc_bus_nr = 0x80; 483 } 484 485 static const TypeInfo aspeed_pcie_cfg_info = { 486 .name = TYPE_ASPEED_PCIE_CFG, 487 .parent = TYPE_SYS_BUS_DEVICE, 488 .instance_init = aspeed_pcie_cfg_instance_init, 489 .instance_size = sizeof(AspeedPCIECfgState), 490 .class_init = aspeed_pcie_cfg_class_init, 491 .class_size = sizeof(AspeedPCIECfgClass), 492 }; 493 494 /* 495 * PCIe PHY 496 * 497 * PCIe Host Controller (PCIEH) 498 */ 499 500 /* AST2600 */ 501 REG32(PEHR_ID, 0x00) 502 FIELD(PEHR_ID, DEV, 16, 16) 503 REG32(PEHR_CLASS_CODE, 0x04) 504 REG32(PEHR_DATALINK, 0x10) 505 REG32(PEHR_PROTECT, 0x7C) 506 FIELD(PEHR_PROTECT, LOCK, 0, 8) 507 REG32(PEHR_LINK, 0xC0) 508 FIELD(PEHR_LINK, STS, 5, 1) 509 510 #define ASPEED_PCIE_PHY_UNLOCK 0xA8 511 512 static uint64_t aspeed_pcie_phy_read(void *opaque, hwaddr addr, 513 unsigned int size) 514 { 515 AspeedPCIEPhyState *s = ASPEED_PCIE_PHY(opaque); 516 uint32_t reg = addr >> 2; 517 uint32_t value = 0; 518 519 value = s->regs[reg]; 520 521 trace_aspeed_pcie_phy_read(s->id, addr, value); 522 523 return value; 524 } 525 526 static void aspeed_pcie_phy_write(void *opaque, hwaddr addr, uint64_t data, 527 unsigned int size) 528 { 529 AspeedPCIEPhyState *s = ASPEED_PCIE_PHY(opaque); 530 uint32_t reg = addr >> 2; 531 532 trace_aspeed_pcie_phy_write(s->id, addr, data); 533 534 switch (reg) { 535 case R_PEHR_PROTECT: 536 data &= R_PEHR_PROTECT_LOCK_MASK; 537 s->regs[reg] = !!(data == ASPEED_PCIE_PHY_UNLOCK); 538 break; 539 default: 540 s->regs[reg] = data; 541 break; 542 } 543 } 544 545 static const MemoryRegionOps aspeed_pcie_phy_ops = { 546 .read = aspeed_pcie_phy_read, 547 .write = aspeed_pcie_phy_write, 548 .endianness = DEVICE_LITTLE_ENDIAN, 549 .valid = { 550 .min_access_size = 1, 551 .max_access_size = 4, 552 }, 553 }; 554 555 static void aspeed_pcie_phy_reset(DeviceState *dev) 556 { 557 AspeedPCIEPhyState *s = ASPEED_PCIE_PHY(dev); 558 AspeedPCIEPhyClass *apc = ASPEED_PCIE_PHY_GET_CLASS(s); 559 560 memset(s->regs, 0, apc->nr_regs << 2); 561 562 s->regs[R_PEHR_ID] = 563 (0x1150 << R_PEHR_ID_DEV_SHIFT) | PCI_VENDOR_ID_ASPEED; 564 s->regs[R_PEHR_CLASS_CODE] = 0x06040006; 565 s->regs[R_PEHR_DATALINK] = 0xD7040022; 566 s->regs[R_PEHR_LINK] = R_PEHR_LINK_STS_MASK; 567 } 568 569 static void aspeed_pcie_phy_realize(DeviceState *dev, Error **errp) 570 { 571 AspeedPCIEPhyState *s = ASPEED_PCIE_PHY(dev); 572 AspeedPCIEPhyClass *apc = ASPEED_PCIE_PHY_GET_CLASS(s); 573 SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 574 g_autofree char *name; 575 576 s->regs = g_new(uint32_t, apc->nr_regs); 577 name = g_strdup_printf(TYPE_ASPEED_PCIE_PHY ".regs.%d", s->id); 578 memory_region_init_io(&s->mmio, OBJECT(s), &aspeed_pcie_phy_ops, s, name, 579 apc->nr_regs << 2); 580 sysbus_init_mmio(sbd, &s->mmio); 581 } 582 583 static void aspeed_pcie_phy_unrealize(DeviceState *dev) 584 { 585 AspeedPCIEPhyState *s = ASPEED_PCIE_PHY(dev); 586 587 g_free(s->regs); 588 s->regs = NULL; 589 } 590 591 static const Property aspeed_pcie_phy_props[] = { 592 DEFINE_PROP_UINT32("id", AspeedPCIEPhyState, id, 0), 593 }; 594 595 static void aspeed_pcie_phy_class_init(ObjectClass *klass, const void *data) 596 { 597 DeviceClass *dc = DEVICE_CLASS(klass); 598 AspeedPCIEPhyClass *apc = ASPEED_PCIE_PHY_CLASS(klass); 599 600 dc->desc = "ASPEED PCIe Phy"; 601 dc->realize = aspeed_pcie_phy_realize; 602 dc->unrealize = aspeed_pcie_phy_unrealize; 603 device_class_set_legacy_reset(dc, aspeed_pcie_phy_reset); 604 device_class_set_props(dc, aspeed_pcie_phy_props); 605 606 apc->nr_regs = 0x100 >> 2; 607 } 608 609 static const TypeInfo aspeed_pcie_phy_info = { 610 .name = TYPE_ASPEED_PCIE_PHY, 611 .parent = TYPE_SYS_BUS_DEVICE, 612 .instance_size = sizeof(AspeedPCIEPhyState), 613 .class_init = aspeed_pcie_phy_class_init, 614 .class_size = sizeof(AspeedPCIEPhyClass), 615 }; 616 617 static void aspeed_pcie_register_types(void) 618 { 619 type_register_static(&aspeed_pcie_root_info); 620 type_register_static(&aspeed_pcie_rc_info); 621 type_register_static(&aspeed_pcie_cfg_info); 622 type_register_static(&aspeed_pcie_phy_info); 623 } 624 625 type_init(aspeed_pcie_register_types); 626 627