2 * QEMU PowerPC PowerNV (POWER8) PHB3 model
4 * Copyright (c) 2014-2020, IBM Corporation.
6 * This code is licensed under the GPL version 2 or later. See the
7 * COPYING file in the top-level directory.
9 #include "qemu/osdep.h"
10 #include "qapi/error.h"
11 #include "qemu-common.h"
13 #include "target/ppc/cpu.h"
14 #include "hw/ppc/fdt.h"
15 #include "hw/pci-host/pnv_phb3_regs.h"
16 #include "hw/pci-host/pnv_phb3.h"
17 #include "hw/ppc/pnv.h"
18 #include "hw/ppc/pnv_xscom.h"
19 #include "hw/pci/pci_bridge.h"
20 #include "hw/pci/pci_bus.h"
24 #define phb3_pbcq_error(pbcq, fmt, ...) \
25 qemu_log_mask(LOG_GUEST_ERROR, "phb3_pbcq[%d:%d]: " fmt "\n", \
26 (pbcq)->phb->chip_id, (pbcq)->phb->phb_id, ## __VA_ARGS__)
28 static uint64_t pnv_pbcq_nest_xscom_read(void *opaque
, hwaddr addr
,
31 PnvPBCQState
*pbcq
= PNV_PBCQ(opaque
);
32 uint32_t offset
= addr
>> 3;
34 return pbcq
->nest_regs
[offset
];
37 static uint64_t pnv_pbcq_pci_xscom_read(void *opaque
, hwaddr addr
,
40 PnvPBCQState
*pbcq
= PNV_PBCQ(opaque
);
41 uint32_t offset
= addr
>> 3;
43 return pbcq
->pci_regs
[offset
];
46 static uint64_t pnv_pbcq_spci_xscom_read(void *opaque
, hwaddr addr
,
49 PnvPBCQState
*pbcq
= PNV_PBCQ(opaque
);
50 uint32_t offset
= addr
>> 3;
52 if (offset
== PBCQ_SPCI_ASB_DATA
) {
53 return pnv_phb3_reg_read(pbcq
->phb
,
54 pbcq
->spci_regs
[PBCQ_SPCI_ASB_ADDR
], 8);
56 return pbcq
->spci_regs
[offset
];
59 static void pnv_pbcq_update_map(PnvPBCQState
*pbcq
)
61 uint64_t bar_en
= pbcq
->nest_regs
[PBCQ_NEST_BAR_EN
];
62 uint64_t bar
, mask
, size
;
65 * NOTE: This will really not work well if those are remapped
66 * after the PHB has created its sub regions. We could do better
67 * if we had a way to resize regions but we don't really care
68 * that much in practice as the stuff below really only happens
69 * once early during boot
73 if (memory_region_is_mapped(&pbcq
->mmbar0
) &&
74 !(bar_en
& PBCQ_NEST_BAR_EN_MMIO0
)) {
75 memory_region_del_subregion(get_system_memory(), &pbcq
->mmbar0
);
77 if (memory_region_is_mapped(&pbcq
->mmbar1
) &&
78 !(bar_en
& PBCQ_NEST_BAR_EN_MMIO1
)) {
79 memory_region_del_subregion(get_system_memory(), &pbcq
->mmbar1
);
81 if (memory_region_is_mapped(&pbcq
->phbbar
) &&
82 !(bar_en
& PBCQ_NEST_BAR_EN_PHB
)) {
83 memory_region_del_subregion(get_system_memory(), &pbcq
->phbbar
);
87 pnv_phb3_update_regions(pbcq
->phb
);
90 if (!memory_region_is_mapped(&pbcq
->mmbar0
) &&
91 (bar_en
& PBCQ_NEST_BAR_EN_MMIO0
)) {
92 bar
= pbcq
->nest_regs
[PBCQ_NEST_MMIO_BAR0
] >> 14;
93 mask
= pbcq
->nest_regs
[PBCQ_NEST_MMIO_MASK0
];
94 size
= ((~mask
) >> 14) + 1;
95 memory_region_init(&pbcq
->mmbar0
, OBJECT(pbcq
), "pbcq-mmio0", size
);
96 memory_region_add_subregion(get_system_memory(), bar
, &pbcq
->mmbar0
);
97 pbcq
->mmio0_base
= bar
;
98 pbcq
->mmio0_size
= size
;
100 if (!memory_region_is_mapped(&pbcq
->mmbar1
) &&
101 (bar_en
& PBCQ_NEST_BAR_EN_MMIO1
)) {
102 bar
= pbcq
->nest_regs
[PBCQ_NEST_MMIO_BAR1
] >> 14;
103 mask
= pbcq
->nest_regs
[PBCQ_NEST_MMIO_MASK1
];
104 size
= ((~mask
) >> 14) + 1;
105 memory_region_init(&pbcq
->mmbar1
, OBJECT(pbcq
), "pbcq-mmio1", size
);
106 memory_region_add_subregion(get_system_memory(), bar
, &pbcq
->mmbar1
);
107 pbcq
->mmio1_base
= bar
;
108 pbcq
->mmio1_size
= size
;
110 if (!memory_region_is_mapped(&pbcq
->phbbar
)
111 && (bar_en
& PBCQ_NEST_BAR_EN_PHB
)) {
112 bar
= pbcq
->nest_regs
[PBCQ_NEST_PHB_BAR
] >> 14;
114 memory_region_init(&pbcq
->phbbar
, OBJECT(pbcq
), "pbcq-phb", size
);
115 memory_region_add_subregion(get_system_memory(), bar
, &pbcq
->phbbar
);
119 pnv_phb3_update_regions(pbcq
->phb
);
122 static void pnv_pbcq_nest_xscom_write(void *opaque
, hwaddr addr
,
123 uint64_t val
, unsigned size
)
125 PnvPBCQState
*pbcq
= PNV_PBCQ(opaque
);
126 uint32_t reg
= addr
>> 3;
129 case PBCQ_NEST_MMIO_BAR0
:
130 case PBCQ_NEST_MMIO_BAR1
:
131 case PBCQ_NEST_MMIO_MASK0
:
132 case PBCQ_NEST_MMIO_MASK1
:
133 if (pbcq
->nest_regs
[PBCQ_NEST_BAR_EN
] &
134 (PBCQ_NEST_BAR_EN_MMIO0
|
135 PBCQ_NEST_BAR_EN_MMIO1
)) {
136 phb3_pbcq_error(pbcq
, "Changing enabled BAR unsupported");
138 pbcq
->nest_regs
[reg
] = val
& 0xffffffffc0000000ull
;
140 case PBCQ_NEST_PHB_BAR
:
141 if (pbcq
->nest_regs
[PBCQ_NEST_BAR_EN
] & PBCQ_NEST_BAR_EN_PHB
) {
142 phb3_pbcq_error(pbcq
, "Changing enabled BAR unsupported");
144 pbcq
->nest_regs
[reg
] = val
& 0xfffffffffc000000ull
;
146 case PBCQ_NEST_BAR_EN
:
147 pbcq
->nest_regs
[reg
] = val
& 0xf800000000000000ull
;
148 pnv_pbcq_update_map(pbcq
);
149 pnv_phb3_remap_irqs(pbcq
->phb
);
151 case PBCQ_NEST_IRSN_COMPARE
:
152 case PBCQ_NEST_IRSN_MASK
:
153 pbcq
->nest_regs
[reg
] = val
& PBCQ_NEST_IRSN_COMP
;
154 pnv_phb3_remap_irqs(pbcq
->phb
);
156 case PBCQ_NEST_LSI_SRC_ID
:
157 pbcq
->nest_regs
[reg
] = val
& PBCQ_NEST_LSI_SRC
;
158 pnv_phb3_remap_irqs(pbcq
->phb
);
161 phb3_pbcq_error(pbcq
, "%s @0x%"HWADDR_PRIx
"=%"PRIx64
, __func__
,
166 static void pnv_pbcq_pci_xscom_write(void *opaque
, hwaddr addr
,
167 uint64_t val
, unsigned size
)
169 PnvPBCQState
*pbcq
= PNV_PBCQ(opaque
);
170 uint32_t reg
= addr
>> 3;
174 pbcq
->pci_regs
[reg
] = val
& 0xfffffffffc000000ull
;
175 pnv_pbcq_update_map(pbcq
);
178 phb3_pbcq_error(pbcq
, "%s @0x%"HWADDR_PRIx
"=%"PRIx64
, __func__
,
183 static void pnv_pbcq_spci_xscom_write(void *opaque
, hwaddr addr
,
184 uint64_t val
, unsigned size
)
186 PnvPBCQState
*pbcq
= PNV_PBCQ(opaque
);
187 uint32_t reg
= addr
>> 3;
190 case PBCQ_SPCI_ASB_ADDR
:
191 pbcq
->spci_regs
[reg
] = val
& 0xfff;
193 case PBCQ_SPCI_ASB_STATUS
:
194 pbcq
->spci_regs
[reg
] &= ~val
;
196 case PBCQ_SPCI_ASB_DATA
:
197 pnv_phb3_reg_write(pbcq
->phb
, pbcq
->spci_regs
[PBCQ_SPCI_ASB_ADDR
],
200 case PBCQ_SPCI_AIB_CAPP_EN
:
201 case PBCQ_SPCI_CAPP_SEC_TMR
:
204 phb3_pbcq_error(pbcq
, "%s @0x%"HWADDR_PRIx
"=%"PRIx64
, __func__
,
209 static const MemoryRegionOps pnv_pbcq_nest_xscom_ops
= {
210 .read
= pnv_pbcq_nest_xscom_read
,
211 .write
= pnv_pbcq_nest_xscom_write
,
212 .valid
.min_access_size
= 8,
213 .valid
.max_access_size
= 8,
214 .impl
.min_access_size
= 8,
215 .impl
.max_access_size
= 8,
216 .endianness
= DEVICE_BIG_ENDIAN
,
219 static const MemoryRegionOps pnv_pbcq_pci_xscom_ops
= {
220 .read
= pnv_pbcq_pci_xscom_read
,
221 .write
= pnv_pbcq_pci_xscom_write
,
222 .valid
.min_access_size
= 8,
223 .valid
.max_access_size
= 8,
224 .impl
.min_access_size
= 8,
225 .impl
.max_access_size
= 8,
226 .endianness
= DEVICE_BIG_ENDIAN
,
229 static const MemoryRegionOps pnv_pbcq_spci_xscom_ops
= {
230 .read
= pnv_pbcq_spci_xscom_read
,
231 .write
= pnv_pbcq_spci_xscom_write
,
232 .valid
.min_access_size
= 8,
233 .valid
.max_access_size
= 8,
234 .impl
.min_access_size
= 8,
235 .impl
.max_access_size
= 8,
236 .endianness
= DEVICE_BIG_ENDIAN
,
239 static void pnv_pbcq_default_bars(PnvPBCQState
*pbcq
)
241 uint64_t mm0
, mm1
, reg
;
242 PnvPHB3
*phb
= pbcq
->phb
;
244 mm0
= 0x3d00000000000ull
+ 0x4000000000ull
* phb
->chip_id
+
245 0x1000000000ull
* phb
->phb_id
;
246 mm1
= 0x3ff8000000000ull
+ 0x0200000000ull
* phb
->chip_id
+
247 0x0080000000ull
* phb
->phb_id
;
248 reg
= 0x3fffe40000000ull
+ 0x0000400000ull
* phb
->chip_id
+
249 0x0000100000ull
* phb
->phb_id
;
251 pbcq
->nest_regs
[PBCQ_NEST_MMIO_BAR0
] = mm0
<< 14;
252 pbcq
->nest_regs
[PBCQ_NEST_MMIO_BAR1
] = mm1
<< 14;
253 pbcq
->nest_regs
[PBCQ_NEST_PHB_BAR
] = reg
<< 14;
254 pbcq
->nest_regs
[PBCQ_NEST_MMIO_MASK0
] = 0x3fff000000000ull
<< 14;
255 pbcq
->nest_regs
[PBCQ_NEST_MMIO_MASK1
] = 0x3ffff80000000ull
<< 14;
256 pbcq
->pci_regs
[PBCQ_PCI_BAR2
] = reg
<< 14;
259 static void pnv_pbcq_realize(DeviceState
*dev
, Error
**errp
)
261 PnvPBCQState
*pbcq
= PNV_PBCQ(dev
);
268 /* TODO: Fix OPAL to do that: establish default BAR values */
269 pnv_pbcq_default_bars(pbcq
);
271 /* Initialize the XSCOM region for the PBCQ registers */
272 snprintf(name
, sizeof(name
), "xscom-pbcq-nest-%d.%d",
273 phb
->chip_id
, phb
->phb_id
);
274 pnv_xscom_region_init(&pbcq
->xscom_nest_regs
, OBJECT(dev
),
275 &pnv_pbcq_nest_xscom_ops
, pbcq
, name
,
276 PNV_XSCOM_PBCQ_NEST_SIZE
);
277 snprintf(name
, sizeof(name
), "xscom-pbcq-pci-%d.%d",
278 phb
->chip_id
, phb
->phb_id
);
279 pnv_xscom_region_init(&pbcq
->xscom_pci_regs
, OBJECT(dev
),
280 &pnv_pbcq_pci_xscom_ops
, pbcq
, name
,
281 PNV_XSCOM_PBCQ_PCI_SIZE
);
282 snprintf(name
, sizeof(name
), "xscom-pbcq-spci-%d.%d",
283 phb
->chip_id
, phb
->phb_id
);
284 pnv_xscom_region_init(&pbcq
->xscom_spci_regs
, OBJECT(dev
),
285 &pnv_pbcq_spci_xscom_ops
, pbcq
, name
,
286 PNV_XSCOM_PBCQ_SPCI_SIZE
);
289 static int pnv_pbcq_dt_xscom(PnvXScomInterface
*dev
, void *fdt
,
292 const char compat
[] = "ibm,power8-pbcq";
293 PnvPHB3
*phb
= PNV_PBCQ(dev
)->phb
;
296 uint32_t lpc_pcba
= PNV_XSCOM_PBCQ_NEST_BASE
+ 0x400 * phb
->phb_id
;
298 cpu_to_be32(lpc_pcba
),
299 cpu_to_be32(PNV_XSCOM_PBCQ_NEST_SIZE
),
300 cpu_to_be32(PNV_XSCOM_PBCQ_PCI_BASE
+ 0x400 * phb
->phb_id
),
301 cpu_to_be32(PNV_XSCOM_PBCQ_PCI_SIZE
),
302 cpu_to_be32(PNV_XSCOM_PBCQ_SPCI_BASE
+ 0x040 * phb
->phb_id
),
303 cpu_to_be32(PNV_XSCOM_PBCQ_SPCI_SIZE
)
306 name
= g_strdup_printf("pbcq@%x", lpc_pcba
);
307 offset
= fdt_add_subnode(fdt
, xscom_offset
, name
);
311 _FDT((fdt_setprop(fdt
, offset
, "reg", reg
, sizeof(reg
))));
313 _FDT((fdt_setprop_cell(fdt
, offset
, "ibm,phb-index", phb
->phb_id
)));
314 _FDT((fdt_setprop_cell(fdt
, offset
, "ibm,chip-id", phb
->chip_id
)));
315 _FDT((fdt_setprop(fdt
, offset
, "compatible", compat
,
320 static void phb3_pbcq_instance_init(Object
*obj
)
322 PnvPBCQState
*pbcq
= PNV_PBCQ(obj
);
324 object_property_add_link(obj
, "phb", TYPE_PNV_PHB3
,
325 (Object
**)&pbcq
->phb
,
326 object_property_allow_set_link
,
327 OBJ_PROP_LINK_STRONG
);
330 static void pnv_pbcq_class_init(ObjectClass
*klass
, void *data
)
332 DeviceClass
*dc
= DEVICE_CLASS(klass
);
333 PnvXScomInterfaceClass
*xdc
= PNV_XSCOM_INTERFACE_CLASS(klass
);
335 xdc
->dt_xscom
= pnv_pbcq_dt_xscom
;
337 dc
->realize
= pnv_pbcq_realize
;
338 dc
->user_creatable
= false;
341 static const TypeInfo pnv_pbcq_type_info
= {
342 .name
= TYPE_PNV_PBCQ
,
343 .parent
= TYPE_DEVICE
,
344 .instance_size
= sizeof(PnvPBCQState
),
345 .instance_init
= phb3_pbcq_instance_init
,
346 .class_init
= pnv_pbcq_class_init
,
347 .interfaces
= (InterfaceInfo
[]) {
348 { TYPE_PNV_XSCOM_INTERFACE
},
353 static void pnv_pbcq_register_types(void)
355 type_register_static(&pnv_pbcq_type_info
);
358 type_init(pnv_pbcq_register_types
)