master
c 132 lines 3.46 KB
Raw
1 /*
2 * QEMU PowerPC nest MMU model
3 *
4 * Copyright (c) 2025, IBM Corporation.
5 *
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 *
8 * This code is licensed under the GPL version 2 or later. See the
9 * COPYING file in the top-level directory.
10 */
11
12 #include "qemu/osdep.h"
13 #include "qemu/log.h"
14 #include "hw/core/qdev-properties.h"
15
16 #include "hw/ppc/pnv.h"
17 #include "hw/ppc/pnv_xscom.h"
18 #include "hw/ppc/pnv_nmmu.h"
19 #include "hw/ppc/fdt.h"
20
21 #include <libfdt.h>
22
23 #define NMMU_XLAT_CTL_PTCR 0xb
24
25 static uint64_t pnv_nmmu_xscom_read(void *opaque, hwaddr addr, unsigned size)
26 {
27 PnvNMMU *nmmu = PNV_NMMU(opaque);
28 int reg = addr >> 3;
29 uint64_t val;
30
31 if (reg == NMMU_XLAT_CTL_PTCR) {
32 val = nmmu->ptcr;
33 } else {
34 val = 0xffffffffffffffffull;
35 qemu_log_mask(LOG_UNIMP, "nMMU: xscom read at 0x%" PRIx32 "\n", reg);
36 }
37 return val;
38 }
39
40 static void pnv_nmmu_xscom_write(void *opaque, hwaddr addr,
41 uint64_t val, unsigned size)
42 {
43 PnvNMMU *nmmu = PNV_NMMU(opaque);
44 int reg = addr >> 3;
45
46 if (reg == NMMU_XLAT_CTL_PTCR) {
47 nmmu->ptcr = val;
48 } else {
49 qemu_log_mask(LOG_UNIMP, "nMMU: xscom write at 0x%" PRIx32 "\n", reg);
50 }
51 }
52
53 static const MemoryRegionOps pnv_nmmu_xscom_ops = {
54 .read = pnv_nmmu_xscom_read,
55 .write = pnv_nmmu_xscom_write,
56 .valid.min_access_size = 8,
57 .valid.max_access_size = 8,
58 .impl.min_access_size = 8,
59 .impl.max_access_size = 8,
60 .endianness = DEVICE_BIG_ENDIAN,
61 };
62
63 static void pnv_nmmu_realize(DeviceState *dev, Error **errp)
64 {
65 PnvNMMU *nmmu = PNV_NMMU(dev);
66
67 assert(nmmu->chip);
68
69 /* NMMU xscom region */
70 pnv_xscom_region_init(&nmmu->xscom_regs, OBJECT(nmmu),
71 &pnv_nmmu_xscom_ops, nmmu,
72 "xscom-nmmu",
73 PNV10_XSCOM_NMMU_SIZE);
74 }
75
76 static int pnv_nmmu_dt_xscom(PnvXScomInterface *dev, void *fdt,
77 int offset)
78 {
79 PnvNMMU *nmmu = PNV_NMMU(dev);
80 char *name;
81 int nmmu_offset;
82 const char compat[] = "ibm,power9-nest-mmu";
83 uint32_t nmmu_pcba = PNV10_XSCOM_NEST0_MMU_BASE + nmmu->nmmu_id * 0x1000000;
84 uint32_t reg[2] = {
85 cpu_to_be32(nmmu_pcba),
86 cpu_to_be32(PNV10_XSCOM_NMMU_SIZE)
87 };
88
89 name = g_strdup_printf("nmmu@%x", nmmu_pcba);
90 nmmu_offset = fdt_add_subnode(fdt, offset, name);
91 _FDT(nmmu_offset);
92 g_free(name);
93
94 _FDT(fdt_setprop(fdt, nmmu_offset, "reg", reg, sizeof(reg)));
95 _FDT(fdt_setprop(fdt, nmmu_offset, "compatible", compat, sizeof(compat)));
96 return 0;
97 }
98
99 static const Property pnv_nmmu_properties[] = {
100 DEFINE_PROP_UINT32("nmmu_id", PnvNMMU, nmmu_id, 0),
101 DEFINE_PROP_LINK("chip", PnvNMMU, chip, TYPE_PNV_CHIP, PnvChip *),
102 };
103
104 static void pnv_nmmu_class_init(ObjectClass *klass, const void *data)
105 {
106 DeviceClass *dc = DEVICE_CLASS(klass);
107 PnvXScomInterfaceClass *xscomc = PNV_XSCOM_INTERFACE_CLASS(klass);
108
109 xscomc->dt_xscom = pnv_nmmu_dt_xscom;
110
111 dc->desc = "PowerNV nest MMU";
112 dc->realize = pnv_nmmu_realize;
113 device_class_set_props(dc, pnv_nmmu_properties);
114 }
115
116 static const TypeInfo pnv_nmmu_info = {
117 .name = TYPE_PNV_NMMU,
118 .parent = TYPE_DEVICE,
119 .instance_size = sizeof(PnvNMMU),
120 .class_init = pnv_nmmu_class_init,
121 .interfaces = (InterfaceInfo[]) {
122 { TYPE_PNV_XSCOM_INTERFACE },
123 { }
124 }
125 };
126
127 static void pnv_nmmu_register_types(void)
128 {
129 type_register_static(&pnv_nmmu_info);
130 }
131
132 type_init(pnv_nmmu_register_types);