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"
12 #include "target/ppc/cpu.h"
13 #include "hw/ppc/fdt.h"
14 #include "hw/pci-host/pnv_phb3_regs.h"
15 #include "hw/pci-host/pnv_phb3.h"
16 #include "hw/ppc/pnv.h"
17 #include "hw/ppc/pnv_xscom.h"
18 #include "hw/pci/pci_bridge.h"
19 #include "hw/pci/pci_bus.h"
23 #define phb3_pbcq_error(pbcq, fmt, ...) \
24 qemu_log_mask(LOG_GUEST_ERROR, "phb3_pbcq[%d:%d]: " fmt "\n", \
25 (pbcq)->phb->chip_id, (pbcq)->phb->phb_id, ## __VA_ARGS__)
27 static uint64_t pnv_pbcq_nest_xscom_read(void *opaque
, hwaddr addr
,
30 PnvPBCQState
*pbcq
= PNV_PBCQ(opaque
);
31 uint32_t offset
= addr
>> 3;
33 return pbcq
->nest_regs
[offset
];
36 static uint64_t pnv_pbcq_pci_xscom_read(void *opaque
, hwaddr addr
,
39 PnvPBCQState
*pbcq
= PNV_PBCQ(opaque
);
40 uint32_t offset
= addr
>> 3;
42 return pbcq
->pci_regs
[offset
];
45 static uint64_t pnv_pbcq_spci_xscom_read(void *opaque
, hwaddr addr
,
48 PnvPBCQState
*pbcq
= PNV_PBCQ(opaque
);
49 uint32_t offset
= addr
>> 3;
51 if (offset
== PBCQ_SPCI_ASB_DATA
) {
52 return pnv_phb3_reg_read(pbcq
->phb
,
53 pbcq
->spci_regs
[PBCQ_SPCI_ASB_ADDR
], 8);
55 return pbcq
->spci_regs
[offset
];
58 static void pnv_pbcq_update_map(PnvPBCQState
*pbcq
)
60 uint64_t bar_en
= pbcq
->nest_regs
[PBCQ_NEST_BAR_EN
];
61 uint64_t bar
, mask
, size
;
64 * NOTE: This will really not work well if those are remapped
65 * after the PHB has created its sub regions. We could do better
66 * if we had a way to resize regions but we don't really care
67 * that much in practice as the stuff below really only happens
68 * once early during boot
72 if (memory_region_is_mapped(&pbcq
->mmbar0
) &&
73 !(bar_en
& PBCQ_NEST_BAR_EN_MMIO0
)) {
74 memory_region_del_subregion(get_system_memory(), &pbcq
->mmbar0
);
76 if (memory_region_is_mapped(&pbcq
->mmbar1
) &&
77 !(bar_en
& PBCQ_NEST_BAR_EN_MMIO1
)) {
78 memory_region_del_subregion(get_system_memory(), &pbcq
->mmbar1
);
80 if (memory_region_is_mapped(&pbcq
->phbbar
) &&
81 !(bar_en
& PBCQ_NEST_BAR_EN_PHB
)) {
82 memory_region_del_subregion(get_system_memory(), &pbcq
->phbbar
);
86 pnv_phb3_update_regions(pbcq
->phb
);
89 if (!memory_region_is_mapped(&pbcq
->mmbar0
) &&
90 (bar_en
& PBCQ_NEST_BAR_EN_MMIO0
)) {
91 bar
= pbcq
->nest_regs
[PBCQ_NEST_MMIO_BAR0
] >> 14;
92 mask
= pbcq
->nest_regs
[PBCQ_NEST_MMIO_MASK0
];
93 size
= ((~mask
) >> 14) + 1;
94 memory_region_init(&pbcq
->mmbar0
, OBJECT(pbcq
), "pbcq-mmio0", size
);
95 memory_region_add_subregion(get_system_memory(), bar
, &pbcq
->mmbar0
);
96 pbcq
->mmio0_base
= bar
;
97 pbcq
->mmio0_size
= size
;
99 if (!memory_region_is_mapped(&pbcq
->mmbar1
) &&
100 (bar_en
& PBCQ_NEST_BAR_EN_MMIO1
)) {
101 bar
= pbcq
->nest_regs
[PBCQ_NEST_MMIO_BAR1
] >> 14;
102 mask
= pbcq
->nest_regs
[PBCQ_NEST_MMIO_MASK1
];
103 size
= ((~mask
) >> 14) + 1;
104 memory_region_init(&pbcq
->mmbar1
, OBJECT(pbcq
), "pbcq-mmio1", size
);
105 memory_region_add_subregion(get_system_memory(), bar
, &pbcq
->mmbar1
);
106 pbcq
->mmio1_base
= bar
;
107 pbcq
->mmio1_size
= size
;
109 if (!memory_region_is_mapped(&pbcq
->phbbar
)
110 && (bar_en
& PBCQ_NEST_BAR_EN_PHB
)) {
111 bar
= pbcq
->nest_regs
[PBCQ_NEST_PHB_BAR
] >> 14;
113 memory_region_init(&pbcq
->phbbar
, OBJECT(pbcq
), "pbcq-phb", size
);
114 memory_region_add_subregion(get_system_memory(), bar
, &pbcq
->phbbar
);
118 pnv_phb3_update_regions(pbcq
->phb
);
121 static void pnv_pbcq_nest_xscom_write(void *opaque
, hwaddr addr
,
122 uint64_t val
, unsigned size
)
124 PnvPBCQState
*pbcq
= PNV_PBCQ(opaque
);
125 uint32_t reg
= addr
>> 3;
128 case PBCQ_NEST_MMIO_BAR0
:
129 case PBCQ_NEST_MMIO_BAR1
:
130 case PBCQ_NEST_MMIO_MASK0
:
131 case PBCQ_NEST_MMIO_MASK1
:
132 if (pbcq
->nest_regs
[PBCQ_NEST_BAR_EN
] &
133 (PBCQ_NEST_BAR_EN_MMIO0
|
134 PBCQ_NEST_BAR_EN_MMIO1
)) {
135 phb3_pbcq_error(pbcq
, "Changing enabled BAR unsupported");
137 pbcq
->nest_regs
[reg
] = val
& 0xffffffffc0000000ull
;
139 case PBCQ_NEST_PHB_BAR
:
140 if (pbcq
->nest_regs
[PBCQ_NEST_BAR_EN
] & PBCQ_NEST_BAR_EN_PHB
) {
141 phb3_pbcq_error(pbcq
, "Changing enabled BAR unsupported");
143 pbcq
->nest_regs
[reg
] = val
& 0xfffffffffc000000ull
;
145 case PBCQ_NEST_BAR_EN
:
146 pbcq
->nest_regs
[reg
] = val
& 0xf800000000000000ull
;
147 pnv_pbcq_update_map(pbcq
);
148 pnv_phb3_remap_irqs(pbcq
->phb
);
150 case PBCQ_NEST_IRSN_COMPARE
:
151 case PBCQ_NEST_IRSN_MASK
:
152 pbcq
->nest_regs
[reg
] = val
& PBCQ_NEST_IRSN_COMP
;
153 pnv_phb3_remap_irqs(pbcq
->phb
);
155 case PBCQ_NEST_LSI_SRC_ID
:
156 pbcq
->nest_regs
[reg
] = val
& PBCQ_NEST_LSI_SRC
;
157 pnv_phb3_remap_irqs(pbcq
->phb
);
160 phb3_pbcq_error(pbcq
, "%s @0x%"HWADDR_PRIx
"=%"PRIx64
, __func__
,
165 static void pnv_pbcq_pci_xscom_write(void *opaque
, hwaddr addr
,
166 uint64_t val
, unsigned size
)
168 PnvPBCQState
*pbcq
= PNV_PBCQ(opaque
);
169 uint32_t reg
= addr
>> 3;
173 pbcq
->pci_regs
[reg
] = val
& 0xfffffffffc000000ull
;
174 pnv_pbcq_update_map(pbcq
);
177 phb3_pbcq_error(pbcq
, "%s @0x%"HWADDR_PRIx
"=%"PRIx64
, __func__
,
182 static void pnv_pbcq_spci_xscom_write(void *opaque
, hwaddr addr
,
183 uint64_t val
, unsigned size
)
185 PnvPBCQState
*pbcq
= PNV_PBCQ(opaque
);
186 uint32_t reg
= addr
>> 3;
189 case PBCQ_SPCI_ASB_ADDR
:
190 pbcq
->spci_regs
[reg
] = val
& 0xfff;
192 case PBCQ_SPCI_ASB_STATUS
:
193 pbcq
->spci_regs
[reg
] &= ~val
;
195 case PBCQ_SPCI_ASB_DATA
:
196 pnv_phb3_reg_write(pbcq
->phb
, pbcq
->spci_regs
[PBCQ_SPCI_ASB_ADDR
],
199 case PBCQ_SPCI_AIB_CAPP_EN
:
200 case PBCQ_SPCI_CAPP_SEC_TMR
:
203 phb3_pbcq_error(pbcq
, "%s @0x%"HWADDR_PRIx
"=%"PRIx64
, __func__
,
208 static const MemoryRegionOps pnv_pbcq_nest_xscom_ops
= {
209 .read
= pnv_pbcq_nest_xscom_read
,
210 .write
= pnv_pbcq_nest_xscom_write
,
211 .valid
.min_access_size
= 8,
212 .valid
.max_access_size
= 8,
213 .impl
.min_access_size
= 8,
214 .impl
.max_access_size
= 8,
215 .endianness
= DEVICE_BIG_ENDIAN
,
218 static const MemoryRegionOps pnv_pbcq_pci_xscom_ops
= {
219 .read
= pnv_pbcq_pci_xscom_read
,
220 .write
= pnv_pbcq_pci_xscom_write
,
221 .valid
.min_access_size
= 8,
222 .valid
.max_access_size
= 8,
223 .impl
.min_access_size
= 8,
224 .impl
.max_access_size
= 8,
225 .endianness
= DEVICE_BIG_ENDIAN
,
228 static const MemoryRegionOps pnv_pbcq_spci_xscom_ops
= {
229 .read
= pnv_pbcq_spci_xscom_read
,
230 .write
= pnv_pbcq_spci_xscom_write
,
231 .valid
.min_access_size
= 8,
232 .valid
.max_access_size
= 8,
233 .impl
.min_access_size
= 8,
234 .impl
.max_access_size
= 8,
235 .endianness
= DEVICE_BIG_ENDIAN
,
238 static void pnv_pbcq_default_bars(PnvPBCQState
*pbcq
)
240 uint64_t mm0
, mm1
, reg
;
241 PnvPHB3
*phb
= pbcq
->phb
;
243 mm0
= 0x3d00000000000ull
+ 0x4000000000ull
* phb
->chip_id
+
244 0x1000000000ull
* phb
->phb_id
;
245 mm1
= 0x3ff8000000000ull
+ 0x0200000000ull
* phb
->chip_id
+
246 0x0080000000ull
* phb
->phb_id
;
247 reg
= 0x3fffe40000000ull
+ 0x0000400000ull
* phb
->chip_id
+
248 0x0000100000ull
* phb
->phb_id
;
250 pbcq
->nest_regs
[PBCQ_NEST_MMIO_BAR0
] = mm0
<< 14;
251 pbcq
->nest_regs
[PBCQ_NEST_MMIO_BAR1
] = mm1
<< 14;
252 pbcq
->nest_regs
[PBCQ_NEST_PHB_BAR
] = reg
<< 14;
253 pbcq
->nest_regs
[PBCQ_NEST_MMIO_MASK0
] = 0x3fff000000000ull
<< 14;
254 pbcq
->nest_regs
[PBCQ_NEST_MMIO_MASK1
] = 0x3ffff80000000ull
<< 14;
255 pbcq
->pci_regs
[PBCQ_PCI_BAR2
] = reg
<< 14;
258 static void pnv_pbcq_realize(DeviceState
*dev
, Error
**errp
)
260 PnvPBCQState
*pbcq
= PNV_PBCQ(dev
);
267 /* TODO: Fix OPAL to do that: establish default BAR values */
268 pnv_pbcq_default_bars(pbcq
);
270 /* Initialize the XSCOM region for the PBCQ registers */
271 snprintf(name
, sizeof(name
), "xscom-pbcq-nest-%d.%d",
272 phb
->chip_id
, phb
->phb_id
);
273 pnv_xscom_region_init(&pbcq
->xscom_nest_regs
, OBJECT(dev
),
274 &pnv_pbcq_nest_xscom_ops
, pbcq
, name
,
275 PNV_XSCOM_PBCQ_NEST_SIZE
);
276 snprintf(name
, sizeof(name
), "xscom-pbcq-pci-%d.%d",
277 phb
->chip_id
, phb
->phb_id
);
278 pnv_xscom_region_init(&pbcq
->xscom_pci_regs
, OBJECT(dev
),
279 &pnv_pbcq_pci_xscom_ops
, pbcq
, name
,
280 PNV_XSCOM_PBCQ_PCI_SIZE
);
281 snprintf(name
, sizeof(name
), "xscom-pbcq-spci-%d.%d",
282 phb
->chip_id
, phb
->phb_id
);
283 pnv_xscom_region_init(&pbcq
->xscom_spci_regs
, OBJECT(dev
),
284 &pnv_pbcq_spci_xscom_ops
, pbcq
, name
,
285 PNV_XSCOM_PBCQ_SPCI_SIZE
);
287 /* Populate the XSCOM address space. */
288 pnv_xscom_add_subregion(phb
->chip
,
289 PNV_XSCOM_PBCQ_NEST_BASE
+ 0x400 * phb
->phb_id
,
290 &pbcq
->xscom_nest_regs
);
291 pnv_xscom_add_subregion(phb
->chip
,
292 PNV_XSCOM_PBCQ_PCI_BASE
+ 0x400 * phb
->phb_id
,
293 &pbcq
->xscom_pci_regs
);
294 pnv_xscom_add_subregion(phb
->chip
,
295 PNV_XSCOM_PBCQ_SPCI_BASE
+ 0x040 * phb
->phb_id
,
296 &pbcq
->xscom_spci_regs
);
299 static int pnv_pbcq_dt_xscom(PnvXScomInterface
*dev
, void *fdt
,
302 const char compat
[] = "ibm,power8-pbcq";
303 PnvPHB3
*phb
= PNV_PBCQ(dev
)->phb
;
306 uint32_t lpc_pcba
= PNV_XSCOM_PBCQ_NEST_BASE
+ 0x400 * phb
->phb_id
;
308 cpu_to_be32(lpc_pcba
),
309 cpu_to_be32(PNV_XSCOM_PBCQ_NEST_SIZE
),
310 cpu_to_be32(PNV_XSCOM_PBCQ_PCI_BASE
+ 0x400 * phb
->phb_id
),
311 cpu_to_be32(PNV_XSCOM_PBCQ_PCI_SIZE
),
312 cpu_to_be32(PNV_XSCOM_PBCQ_SPCI_BASE
+ 0x040 * phb
->phb_id
),
313 cpu_to_be32(PNV_XSCOM_PBCQ_SPCI_SIZE
)
316 name
= g_strdup_printf("pbcq@%x", lpc_pcba
);
317 offset
= fdt_add_subnode(fdt
, xscom_offset
, name
);
321 _FDT((fdt_setprop(fdt
, offset
, "reg", reg
, sizeof(reg
))));
323 _FDT((fdt_setprop_cell(fdt
, offset
, "ibm,phb-index", phb
->phb_id
)));
324 _FDT((fdt_setprop_cell(fdt
, offset
, "ibm,chip-id", phb
->chip_id
)));
325 _FDT((fdt_setprop(fdt
, offset
, "compatible", compat
,
330 static void phb3_pbcq_instance_init(Object
*obj
)
332 PnvPBCQState
*pbcq
= PNV_PBCQ(obj
);
334 object_property_add_link(obj
, "phb", TYPE_PNV_PHB3
,
335 (Object
**)&pbcq
->phb
,
336 object_property_allow_set_link
,
337 OBJ_PROP_LINK_STRONG
);
340 static void pnv_pbcq_class_init(ObjectClass
*klass
, void *data
)
342 DeviceClass
*dc
= DEVICE_CLASS(klass
);
343 PnvXScomInterfaceClass
*xdc
= PNV_XSCOM_INTERFACE_CLASS(klass
);
345 xdc
->dt_xscom
= pnv_pbcq_dt_xscom
;
347 dc
->realize
= pnv_pbcq_realize
;
348 dc
->user_creatable
= false;
351 static const TypeInfo pnv_pbcq_type_info
= {
352 .name
= TYPE_PNV_PBCQ
,
353 .parent
= TYPE_DEVICE
,
354 .instance_size
= sizeof(PnvPBCQState
),
355 .instance_init
= phb3_pbcq_instance_init
,
356 .class_init
= pnv_pbcq_class_init
,
357 .interfaces
= (InterfaceInfo
[]) {
358 { TYPE_PNV_XSCOM_INTERFACE
},
363 static void pnv_pbcq_register_types(void)
365 type_register_static(&pnv_pbcq_type_info
);
368 type_init(pnv_pbcq_register_types
)