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 PHY 32 * 33 * PCIe Host Controller (PCIEH) 34 */ 35 36 /* AST2600 */ 37 REG32(PEHR_ID, 0x00) 38 FIELD(PEHR_ID, DEV, 16, 16) 39 REG32(PEHR_CLASS_CODE, 0x04) 40 REG32(PEHR_DATALINK, 0x10) 41 REG32(PEHR_PROTECT, 0x7C) 42 FIELD(PEHR_PROTECT, LOCK, 0, 8) 43 REG32(PEHR_LINK, 0xC0) 44 FIELD(PEHR_LINK, STS, 5, 1) 45 46 #define ASPEED_PCIE_PHY_UNLOCK 0xA8 47 48 static uint64_t aspeed_pcie_phy_read(void *opaque, hwaddr addr, 49 unsigned int size) 50 { 51 AspeedPCIEPhyState *s = ASPEED_PCIE_PHY(opaque); 52 uint32_t reg = addr >> 2; 53 uint32_t value = 0; 54 55 value = s->regs[reg]; 56 57 trace_aspeed_pcie_phy_read(s->id, addr, value); 58 59 return value; 60 } 61 62 static void aspeed_pcie_phy_write(void *opaque, hwaddr addr, uint64_t data, 63 unsigned int size) 64 { 65 AspeedPCIEPhyState *s = ASPEED_PCIE_PHY(opaque); 66 uint32_t reg = addr >> 2; 67 68 trace_aspeed_pcie_phy_write(s->id, addr, data); 69 70 switch (reg) { 71 case R_PEHR_PROTECT: 72 data &= R_PEHR_PROTECT_LOCK_MASK; 73 s->regs[reg] = !!(data == ASPEED_PCIE_PHY_UNLOCK); 74 break; 75 default: 76 s->regs[reg] = data; 77 break; 78 } 79 } 80 81 static const MemoryRegionOps aspeed_pcie_phy_ops = { 82 .read = aspeed_pcie_phy_read, 83 .write = aspeed_pcie_phy_write, 84 .endianness = DEVICE_LITTLE_ENDIAN, 85 .valid = { 86 .min_access_size = 1, 87 .max_access_size = 4, 88 }, 89 }; 90 91 static void aspeed_pcie_phy_reset(DeviceState *dev) 92 { 93 AspeedPCIEPhyState *s = ASPEED_PCIE_PHY(dev); 94 AspeedPCIEPhyClass *apc = ASPEED_PCIE_PHY_GET_CLASS(s); 95 96 memset(s->regs, 0, apc->nr_regs << 2); 97 98 s->regs[R_PEHR_ID] = 99 (0x1150 << R_PEHR_ID_DEV_SHIFT) | PCI_VENDOR_ID_ASPEED; 100 s->regs[R_PEHR_CLASS_CODE] = 0x06040006; 101 s->regs[R_PEHR_DATALINK] = 0xD7040022; 102 s->regs[R_PEHR_LINK] = R_PEHR_LINK_STS_MASK; 103 } 104 105 static void aspeed_pcie_phy_realize(DeviceState *dev, Error **errp) 106 { 107 AspeedPCIEPhyState *s = ASPEED_PCIE_PHY(dev); 108 AspeedPCIEPhyClass *apc = ASPEED_PCIE_PHY_GET_CLASS(s); 109 SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 110 g_autofree char *name; 111 112 s->regs = g_new(uint32_t, apc->nr_regs); 113 name = g_strdup_printf(TYPE_ASPEED_PCIE_PHY ".regs.%d", s->id); 114 memory_region_init_io(&s->mmio, OBJECT(s), &aspeed_pcie_phy_ops, s, name, 115 apc->nr_regs << 2); 116 sysbus_init_mmio(sbd, &s->mmio); 117 } 118 119 static void aspeed_pcie_phy_unrealize(DeviceState *dev) 120 { 121 AspeedPCIEPhyState *s = ASPEED_PCIE_PHY(dev); 122 123 g_free(s->regs); 124 s->regs = NULL; 125 } 126 127 static const Property aspeed_pcie_phy_props[] = { 128 DEFINE_PROP_UINT32("id", AspeedPCIEPhyState, id, 0), 129 }; 130 131 static void aspeed_pcie_phy_class_init(ObjectClass *klass, const void *data) 132 { 133 DeviceClass *dc = DEVICE_CLASS(klass); 134 AspeedPCIEPhyClass *apc = ASPEED_PCIE_PHY_CLASS(klass); 135 136 dc->desc = "ASPEED PCIe Phy"; 137 dc->realize = aspeed_pcie_phy_realize; 138 dc->unrealize = aspeed_pcie_phy_unrealize; 139 device_class_set_legacy_reset(dc, aspeed_pcie_phy_reset); 140 device_class_set_props(dc, aspeed_pcie_phy_props); 141 142 apc->nr_regs = 0x100 >> 2; 143 } 144 145 static const TypeInfo aspeed_pcie_phy_info = { 146 .name = TYPE_ASPEED_PCIE_PHY, 147 .parent = TYPE_SYS_BUS_DEVICE, 148 .instance_size = sizeof(AspeedPCIEPhyState), 149 .class_init = aspeed_pcie_phy_class_init, 150 .class_size = sizeof(AspeedPCIEPhyClass), 151 }; 152 153 static void aspeed_pcie_register_types(void) 154 { 155 type_register_static(&aspeed_pcie_phy_info); 156 } 157 158 type_init(aspeed_pcie_register_types); 159 160