xref: /qemu/hw/ppc/pnv_nest_pervasive.c (revision 9ea920dc)
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 
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 
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 
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 
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 
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