xref: /openbmc/qemu/hw/pci-host/aspeed_pcie.c (revision 4aee1ac7f365390a5ee8108520f66c8718cc2b4b)
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