contrib/elf2dmp: Use GPtrArray
[qemu/armbru.git] / hw / pci-host / pnv_phb3_pbcq.c
blob82f70efa4311af7229473dea9354f2d034579b3c
1 /*
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.
8 */
9 #include "qemu/osdep.h"
10 #include "qapi/error.h"
11 #include "qemu/log.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"
21 #include <libfdt.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,
28 unsigned size)
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,
37 unsigned size)
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,
46 unsigned size)
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
71 /* Handle unmaps */
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);
85 /* Update PHB */
86 pnv_phb3_update_regions(pbcq->phb);
88 /* Handle maps */
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;
112 size = 0x1000;
113 memory_region_init(&pbcq->phbbar, OBJECT(pbcq), "pbcq-phb", size);
114 memory_region_add_subregion(get_system_memory(), bar, &pbcq->phbbar);
117 /* Update PHB */
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;
127 switch (reg) {
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;
138 break;
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;
144 break;
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);
149 break;
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);
154 break;
155 case PBCQ_NEST_LSI_SRC_ID:
156 pbcq->nest_regs[reg] = val & PBCQ_NEST_LSI_SRC;
157 pnv_phb3_remap_irqs(pbcq->phb);
158 break;
159 default:
160 phb3_pbcq_error(pbcq, "%s @0x%"HWADDR_PRIx"=%"PRIx64, __func__,
161 addr, val);
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;
171 switch (reg) {
172 case PBCQ_PCI_BAR2:
173 pbcq->pci_regs[reg] = val & 0xfffffffffc000000ull;
174 pnv_pbcq_update_map(pbcq);
175 break;
176 default:
177 phb3_pbcq_error(pbcq, "%s @0x%"HWADDR_PRIx"=%"PRIx64, __func__,
178 addr, val);
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;
188 switch (reg) {
189 case PBCQ_SPCI_ASB_ADDR:
190 pbcq->spci_regs[reg] = val & 0xfff;
191 break;
192 case PBCQ_SPCI_ASB_STATUS:
193 pbcq->spci_regs[reg] &= ~val;
194 break;
195 case PBCQ_SPCI_ASB_DATA:
196 pnv_phb3_reg_write(pbcq->phb, pbcq->spci_regs[PBCQ_SPCI_ASB_ADDR],
197 val, 8);
198 break;
199 case PBCQ_SPCI_AIB_CAPP_EN:
200 case PBCQ_SPCI_CAPP_SEC_TMR:
201 break;
202 default:
203 phb3_pbcq_error(pbcq, "%s @0x%"HWADDR_PRIx"=%"PRIx64, __func__,
204 addr, val);
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);
261 PnvPHB3 *phb;
262 char name[32];
264 assert(pbcq->phb);
265 phb = pbcq->phb;
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,
300 int xscom_offset)
302 const char compat[] = "ibm,power8-pbcq";
303 PnvPHB3 *phb = PNV_PBCQ(dev)->phb;
304 char *name;
305 int offset;
306 uint32_t lpc_pcba = PNV_XSCOM_PBCQ_NEST_BASE + 0x400 * phb->phb_id;
307 uint32_t reg[] = {
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);
318 _FDT(offset);
319 g_free(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,
326 sizeof(compat))));
327 return 0;
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)