xref: /openbmc/qemu/hw/pci-host/pnv_phb3_pbcq.c (revision b91a0fa7)
1 /*
2  * QEMU PowerPC PowerNV (POWER8) PHB3 model
3  *
4  * Copyright (c) 2014-2020, IBM Corporation.
5  *
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-common.h"
12 #include "qemu/log.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"
21 
22 #include <libfdt.h>
23 
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__)
27 
28 static uint64_t pnv_pbcq_nest_xscom_read(void *opaque, hwaddr addr,
29                                          unsigned size)
30 {
31     PnvPBCQState *pbcq = PNV_PBCQ(opaque);
32     uint32_t offset = addr >> 3;
33 
34     return pbcq->nest_regs[offset];
35 }
36 
37 static uint64_t pnv_pbcq_pci_xscom_read(void *opaque, hwaddr addr,
38                                         unsigned size)
39 {
40     PnvPBCQState *pbcq = PNV_PBCQ(opaque);
41     uint32_t offset = addr >> 3;
42 
43     return pbcq->pci_regs[offset];
44 }
45 
46 static uint64_t pnv_pbcq_spci_xscom_read(void *opaque, hwaddr addr,
47                                          unsigned size)
48 {
49     PnvPBCQState *pbcq = PNV_PBCQ(opaque);
50     uint32_t offset = addr >> 3;
51 
52     if (offset == PBCQ_SPCI_ASB_DATA) {
53         return pnv_phb3_reg_read(pbcq->phb,
54                                  pbcq->spci_regs[PBCQ_SPCI_ASB_ADDR], 8);
55     }
56     return pbcq->spci_regs[offset];
57 }
58 
59 static void pnv_pbcq_update_map(PnvPBCQState *pbcq)
60 {
61     uint64_t bar_en = pbcq->nest_regs[PBCQ_NEST_BAR_EN];
62     uint64_t bar, mask, size;
63 
64     /*
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
70      */
71 
72     /* Handle unmaps */
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);
76     }
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);
80     }
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);
84     }
85 
86     /* Update PHB */
87     pnv_phb3_update_regions(pbcq->phb);
88 
89     /* Handle maps */
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;
99     }
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;
109     }
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;
113         size = 0x1000;
114         memory_region_init(&pbcq->phbbar, OBJECT(pbcq), "pbcq-phb", size);
115         memory_region_add_subregion(get_system_memory(), bar, &pbcq->phbbar);
116     }
117 
118     /* Update PHB */
119     pnv_phb3_update_regions(pbcq->phb);
120 }
121 
122 static void pnv_pbcq_nest_xscom_write(void *opaque, hwaddr addr,
123                                 uint64_t val, unsigned size)
124 {
125     PnvPBCQState *pbcq = PNV_PBCQ(opaque);
126     uint32_t reg = addr >> 3;
127 
128     switch (reg) {
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");
137         }
138         pbcq->nest_regs[reg] = val & 0xffffffffc0000000ull;
139         break;
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");
143         }
144         pbcq->nest_regs[reg] = val & 0xfffffffffc000000ull;
145         break;
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);
150         break;
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);
155         break;
156     case PBCQ_NEST_LSI_SRC_ID:
157         pbcq->nest_regs[reg] = val & PBCQ_NEST_LSI_SRC;
158         pnv_phb3_remap_irqs(pbcq->phb);
159         break;
160     default:
161         phb3_pbcq_error(pbcq, "%s @0x%"HWADDR_PRIx"=%"PRIx64, __func__,
162                         addr, val);
163     }
164 }
165 
166 static void pnv_pbcq_pci_xscom_write(void *opaque, hwaddr addr,
167                                      uint64_t val, unsigned size)
168 {
169     PnvPBCQState *pbcq = PNV_PBCQ(opaque);
170     uint32_t reg = addr >> 3;
171 
172     switch (reg) {
173     case PBCQ_PCI_BAR2:
174         pbcq->pci_regs[reg] = val & 0xfffffffffc000000ull;
175         pnv_pbcq_update_map(pbcq);
176         break;
177     default:
178         phb3_pbcq_error(pbcq, "%s @0x%"HWADDR_PRIx"=%"PRIx64, __func__,
179                         addr, val);
180     }
181 }
182 
183 static void pnv_pbcq_spci_xscom_write(void *opaque, hwaddr addr,
184                                 uint64_t val, unsigned size)
185 {
186     PnvPBCQState *pbcq = PNV_PBCQ(opaque);
187     uint32_t reg = addr >> 3;
188 
189     switch (reg) {
190     case PBCQ_SPCI_ASB_ADDR:
191         pbcq->spci_regs[reg] = val & 0xfff;
192         break;
193     case PBCQ_SPCI_ASB_STATUS:
194         pbcq->spci_regs[reg] &= ~val;
195         break;
196     case PBCQ_SPCI_ASB_DATA:
197         pnv_phb3_reg_write(pbcq->phb, pbcq->spci_regs[PBCQ_SPCI_ASB_ADDR],
198                            val, 8);
199         break;
200     case PBCQ_SPCI_AIB_CAPP_EN:
201     case PBCQ_SPCI_CAPP_SEC_TMR:
202         break;
203     default:
204         phb3_pbcq_error(pbcq, "%s @0x%"HWADDR_PRIx"=%"PRIx64, __func__,
205                         addr, val);
206     }
207 }
208 
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,
217 };
218 
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,
227 };
228 
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,
237 };
238 
239 static void pnv_pbcq_default_bars(PnvPBCQState *pbcq)
240 {
241     uint64_t mm0, mm1, reg;
242     PnvPHB3 *phb = pbcq->phb;
243 
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;
250 
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;
257 }
258 
259 static void pnv_pbcq_realize(DeviceState *dev, Error **errp)
260 {
261     PnvPBCQState *pbcq = PNV_PBCQ(dev);
262     PnvPHB3 *phb;
263     char name[32];
264 
265     assert(pbcq->phb);
266     phb = pbcq->phb;
267 
268     /* TODO: Fix OPAL to do that: establish default BAR values */
269     pnv_pbcq_default_bars(pbcq);
270 
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);
287 
288     /* Populate the XSCOM address space. */
289     pnv_xscom_add_subregion(phb->chip,
290                             PNV_XSCOM_PBCQ_NEST_BASE + 0x400 * phb->phb_id,
291                             &pbcq->xscom_nest_regs);
292     pnv_xscom_add_subregion(phb->chip,
293                             PNV_XSCOM_PBCQ_PCI_BASE + 0x400 * phb->phb_id,
294                             &pbcq->xscom_pci_regs);
295     pnv_xscom_add_subregion(phb->chip,
296                             PNV_XSCOM_PBCQ_SPCI_BASE + 0x040 * phb->phb_id,
297                             &pbcq->xscom_spci_regs);
298 }
299 
300 static int pnv_pbcq_dt_xscom(PnvXScomInterface *dev, void *fdt,
301                              int xscom_offset)
302 {
303     const char compat[] = "ibm,power8-pbcq";
304     PnvPHB3 *phb = PNV_PBCQ(dev)->phb;
305     char *name;
306     int offset;
307     uint32_t lpc_pcba = PNV_XSCOM_PBCQ_NEST_BASE + 0x400 * phb->phb_id;
308     uint32_t reg[] = {
309         cpu_to_be32(lpc_pcba),
310         cpu_to_be32(PNV_XSCOM_PBCQ_NEST_SIZE),
311         cpu_to_be32(PNV_XSCOM_PBCQ_PCI_BASE + 0x400 * phb->phb_id),
312         cpu_to_be32(PNV_XSCOM_PBCQ_PCI_SIZE),
313         cpu_to_be32(PNV_XSCOM_PBCQ_SPCI_BASE + 0x040 * phb->phb_id),
314         cpu_to_be32(PNV_XSCOM_PBCQ_SPCI_SIZE)
315     };
316 
317     name = g_strdup_printf("pbcq@%x", lpc_pcba);
318     offset = fdt_add_subnode(fdt, xscom_offset, name);
319     _FDT(offset);
320     g_free(name);
321 
322     _FDT((fdt_setprop(fdt, offset, "reg", reg, sizeof(reg))));
323 
324     _FDT((fdt_setprop_cell(fdt, offset, "ibm,phb-index", phb->phb_id)));
325     _FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id", phb->chip_id)));
326     _FDT((fdt_setprop(fdt, offset, "compatible", compat,
327                       sizeof(compat))));
328     return 0;
329 }
330 
331 static void phb3_pbcq_instance_init(Object *obj)
332 {
333     PnvPBCQState *pbcq = PNV_PBCQ(obj);
334 
335     object_property_add_link(obj, "phb", TYPE_PNV_PHB3,
336                              (Object **)&pbcq->phb,
337                              object_property_allow_set_link,
338                              OBJ_PROP_LINK_STRONG);
339 }
340 
341 static void pnv_pbcq_class_init(ObjectClass *klass, void *data)
342 {
343     DeviceClass *dc = DEVICE_CLASS(klass);
344     PnvXScomInterfaceClass *xdc = PNV_XSCOM_INTERFACE_CLASS(klass);
345 
346     xdc->dt_xscom = pnv_pbcq_dt_xscom;
347 
348     dc->realize = pnv_pbcq_realize;
349     dc->user_creatable = false;
350 }
351 
352 static const TypeInfo pnv_pbcq_type_info = {
353     .name          = TYPE_PNV_PBCQ,
354     .parent        = TYPE_DEVICE,
355     .instance_size = sizeof(PnvPBCQState),
356     .instance_init = phb3_pbcq_instance_init,
357     .class_init    = pnv_pbcq_class_init,
358     .interfaces    = (InterfaceInfo[]) {
359         { TYPE_PNV_XSCOM_INTERFACE },
360         { }
361     }
362 };
363 
364 static void pnv_pbcq_register_types(void)
365 {
366     type_register_static(&pnv_pbcq_type_info);
367 }
368 
369 type_init(pnv_pbcq_register_types)
370