1 /*
2 * QEMU PowerPC nest pervasive common chiplet model
3 *
4 * Copyright (c) 2023, IBM Corporation.
5 *
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
8
9 #include "qemu/osdep.h"
10 #include "qemu/log.h"
11 #include "hw/qdev-properties.h"
12 #include "hw/ppc/pnv.h"
13 #include "hw/ppc/pnv_xscom.h"
14 #include "hw/ppc/pnv_nest_pervasive.h"
15
16 /*
17 * Status, configuration, and control units in POWER chips is provided
18 * by the pervasive subsystem, which connects registers to the SCOM bus,
19 * which can be programmed by processor cores, other units on the chip,
20 * BMCs, or other POWER chips.
21 *
22 * A POWER10 chip is divided into logical units called chiplets. Chiplets
23 * are broadly divided into "core chiplets" (with the processor cores) and
24 * "nest chiplets" (with everything else). Each chiplet has an attachment
25 * to the pervasive bus (PIB) and with chiplet-specific registers.
26 * All nest chiplets have a common basic set of registers.
27 *
28 * This model will provide the registers functionality for common registers of
29 * nest unit (PB Chiplet, PCI Chiplets, MC Chiplet, PAU Chiplets)
30 *
31 * Currently this model provide the read/write functionality of chiplet control
32 * scom registers.
33 */
34
35 #define CPLT_CONF0 0x08
36 #define CPLT_CONF0_OR 0x18
37 #define CPLT_CONF0_CLEAR 0x28
38 #define CPLT_CONF1 0x09
39 #define CPLT_CONF1_OR 0x19
40 #define CPLT_CONF1_CLEAR 0x29
41 #define CPLT_STAT0 0x100
42 #define CPLT_MASK0 0x101
43 #define CPLT_PROTECT_MODE 0x3FE
44 #define CPLT_ATOMIC_CLOCK 0x3FF
45
pnv_chiplet_ctrl_read(void * opaque,hwaddr addr,unsigned size)46 static uint64_t pnv_chiplet_ctrl_read(void *opaque, hwaddr addr, unsigned size)
47 {
48 PnvNestChipletPervasive *nest_pervasive = PNV_NEST_CHIPLET_PERVASIVE(
49 opaque);
50 uint32_t reg = addr >> 3;
51 uint64_t val = ~0ull;
52
53 /* CPLT_CTRL0 to CPLT_CTRL5 */
54 for (int i = 0; i < PNV_CPLT_CTRL_SIZE; i++) {
55 if (reg == i) {
56 return nest_pervasive->control_regs.cplt_ctrl[i];
57 } else if ((reg == (i + 0x10)) || (reg == (i + 0x20))) {
58 qemu_log_mask(LOG_GUEST_ERROR, "%s: Write only register, ignoring "
59 "xscom read at 0x%" PRIx32 "\n",
60 __func__, reg);
61 return val;
62 }
63 }
64
65 switch (reg) {
66 case CPLT_CONF0:
67 val = nest_pervasive->control_regs.cplt_cfg0;
68 break;
69 case CPLT_CONF0_OR:
70 case CPLT_CONF0_CLEAR:
71 qemu_log_mask(LOG_GUEST_ERROR, "%s: Write only register, ignoring "
72 "xscom read at 0x%" PRIx32 "\n",
73 __func__, reg);
74 break;
75 case CPLT_CONF1:
76 val = nest_pervasive->control_regs.cplt_cfg1;
77 break;
78 case CPLT_CONF1_OR:
79 case CPLT_CONF1_CLEAR:
80 qemu_log_mask(LOG_GUEST_ERROR, "%s: Write only register, ignoring "
81 "xscom read at 0x%" PRIx32 "\n",
82 __func__, reg);
83 break;
84 case CPLT_STAT0:
85 val = nest_pervasive->control_regs.cplt_stat0;
86 break;
87 case CPLT_MASK0:
88 val = nest_pervasive->control_regs.cplt_mask0;
89 break;
90 case CPLT_PROTECT_MODE:
91 val = nest_pervasive->control_regs.ctrl_protect_mode;
92 break;
93 case CPLT_ATOMIC_CLOCK:
94 val = nest_pervasive->control_regs.ctrl_atomic_lock;
95 break;
96 default:
97 qemu_log_mask(LOG_UNIMP, "%s: Chiplet_control_regs: Invalid xscom "
98 "read at 0x%" PRIx32 "\n", __func__, reg);
99 }
100 return val;
101 }
102
pnv_chiplet_ctrl_write(void * opaque,hwaddr addr,uint64_t val,unsigned size)103 static void pnv_chiplet_ctrl_write(void *opaque, hwaddr addr,
104 uint64_t val, unsigned size)
105 {
106 PnvNestChipletPervasive *nest_pervasive = PNV_NEST_CHIPLET_PERVASIVE(
107 opaque);
108 uint32_t reg = addr >> 3;
109
110 /* CPLT_CTRL0 to CPLT_CTRL5 */
111 for (int i = 0; i < PNV_CPLT_CTRL_SIZE; i++) {
112 if (reg == i) {
113 nest_pervasive->control_regs.cplt_ctrl[i] = val;
114 return;
115 } else if (reg == (i + 0x10)) {
116 nest_pervasive->control_regs.cplt_ctrl[i] |= val;
117 return;
118 } else if (reg == (i + 0x20)) {
119 nest_pervasive->control_regs.cplt_ctrl[i] &= ~val;
120 return;
121 }
122 }
123
124 switch (reg) {
125 case CPLT_CONF0:
126 nest_pervasive->control_regs.cplt_cfg0 = val;
127 break;
128 case CPLT_CONF0_OR:
129 nest_pervasive->control_regs.cplt_cfg0 |= val;
130 break;
131 case CPLT_CONF0_CLEAR:
132 nest_pervasive->control_regs.cplt_cfg0 &= ~val;
133 break;
134 case CPLT_CONF1:
135 nest_pervasive->control_regs.cplt_cfg1 = val;
136 break;
137 case CPLT_CONF1_OR:
138 nest_pervasive->control_regs.cplt_cfg1 |= val;
139 break;
140 case CPLT_CONF1_CLEAR:
141 nest_pervasive->control_regs.cplt_cfg1 &= ~val;
142 break;
143 case CPLT_STAT0:
144 nest_pervasive->control_regs.cplt_stat0 = val;
145 break;
146 case CPLT_MASK0:
147 nest_pervasive->control_regs.cplt_mask0 = val;
148 break;
149 case CPLT_PROTECT_MODE:
150 nest_pervasive->control_regs.ctrl_protect_mode = val;
151 break;
152 case CPLT_ATOMIC_CLOCK:
153 nest_pervasive->control_regs.ctrl_atomic_lock = val;
154 break;
155 default:
156 qemu_log_mask(LOG_UNIMP, "%s: Chiplet_control_regs: Invalid xscom "
157 "write at 0x%" PRIx32 "\n",
158 __func__, reg);
159 }
160 }
161
162 static const MemoryRegionOps pnv_nest_pervasive_control_xscom_ops = {
163 .read = pnv_chiplet_ctrl_read,
164 .write = pnv_chiplet_ctrl_write,
165 .valid.min_access_size = 8,
166 .valid.max_access_size = 8,
167 .impl.min_access_size = 8,
168 .impl.max_access_size = 8,
169 .endianness = DEVICE_BIG_ENDIAN,
170 };
171
pnv_nest_pervasive_realize(DeviceState * dev,Error ** errp)172 static void pnv_nest_pervasive_realize(DeviceState *dev, Error **errp)
173 {
174 PnvNestChipletPervasive *nest_pervasive = PNV_NEST_CHIPLET_PERVASIVE(dev);
175
176 /* Chiplet control scoms */
177 pnv_xscom_region_init(&nest_pervasive->xscom_ctrl_regs_mr,
178 OBJECT(nest_pervasive),
179 &pnv_nest_pervasive_control_xscom_ops,
180 nest_pervasive, "pervasive-control",
181 PNV10_XSCOM_CHIPLET_CTRL_REGS_SIZE);
182 }
183
pnv_nest_pervasive_class_init(ObjectClass * klass,void * data)184 static void pnv_nest_pervasive_class_init(ObjectClass *klass, void *data)
185 {
186 DeviceClass *dc = DEVICE_CLASS(klass);
187
188 dc->desc = "PowerNV nest pervasive chiplet";
189 dc->realize = pnv_nest_pervasive_realize;
190 }
191
192 static const TypeInfo pnv_nest_pervasive_info = {
193 .name = TYPE_PNV_NEST_CHIPLET_PERVASIVE,
194 .parent = TYPE_DEVICE,
195 .instance_size = sizeof(PnvNestChipletPervasive),
196 .class_init = pnv_nest_pervasive_class_init,
197 .interfaces = (InterfaceInfo[]) {
198 { TYPE_PNV_XSCOM_INTERFACE },
199 { }
200 }
201 };
202
pnv_nest_pervasive_register_types(void)203 static void pnv_nest_pervasive_register_types(void)
204 {
205 type_register_static(&pnv_nest_pervasive_info);
206 }
207
208 type_init(pnv_nest_pervasive_register_types);
209