1 /*
2 * QEMU PowerPC PowerNV Emulation of a few OCC related registers
3 *
4 * Copyright (c) 2015-2017, IBM Corporation.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License, version 2, as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include "qemu/osdep.h"
20 #include "target/ppc/cpu.h"
21 #include "qapi/error.h"
22 #include "qemu/log.h"
23 #include "qemu/module.h"
24 #include "hw/irq.h"
25 #include "hw/qdev-properties.h"
26 #include "hw/ppc/pnv.h"
27 #include "hw/ppc/pnv_xscom.h"
28 #include "hw/ppc/pnv_occ.h"
29
30 #define OCB_OCI_OCCMISC 0x4020
31 #define OCB_OCI_OCCMISC_AND 0x4021
32 #define OCB_OCI_OCCMISC_OR 0x4022
33
34 /* OCC sensors */
35 #define OCC_SENSOR_DATA_BLOCK_OFFSET 0x0000
36 #define OCC_SENSOR_DATA_VALID 0x0001
37 #define OCC_SENSOR_DATA_VERSION 0x0002
38 #define OCC_SENSOR_DATA_READING_VERSION 0x0004
39 #define OCC_SENSOR_DATA_NR_SENSORS 0x0008
40 #define OCC_SENSOR_DATA_NAMES_OFFSET 0x0010
41 #define OCC_SENSOR_DATA_READING_PING_OFFSET 0x0014
42 #define OCC_SENSOR_DATA_READING_PONG_OFFSET 0x000c
43 #define OCC_SENSOR_DATA_NAME_LENGTH 0x000d
44 #define OCC_SENSOR_NAME_STRUCTURE_TYPE 0x0023
45 #define OCC_SENSOR_LOC_CORE 0x0022
46 #define OCC_SENSOR_LOC_GPU 0x0020
47 #define OCC_SENSOR_TYPE_POWER 0x0003
48 #define OCC_SENSOR_NAME 0x0005
49 #define HWMON_SENSORS_MASK 0x001e
50
pnv_occ_set_misc(PnvOCC * occ,uint64_t val)51 static void pnv_occ_set_misc(PnvOCC *occ, uint64_t val)
52 {
53 bool irq_state;
54
55 val &= 0xffff000000000000ull;
56
57 occ->occmisc = val;
58 irq_state = !!(val >> 63);
59 qemu_set_irq(occ->psi_irq, irq_state);
60 }
61
pnv_occ_power8_xscom_read(void * opaque,hwaddr addr,unsigned size)62 static uint64_t pnv_occ_power8_xscom_read(void *opaque, hwaddr addr,
63 unsigned size)
64 {
65 PnvOCC *occ = PNV_OCC(opaque);
66 uint32_t offset = addr >> 3;
67 uint64_t val = 0;
68
69 switch (offset) {
70 case OCB_OCI_OCCMISC:
71 val = occ->occmisc;
72 break;
73 default:
74 qemu_log_mask(LOG_UNIMP, "OCC Unimplemented register: Ox%"
75 HWADDR_PRIx "\n", addr >> 3);
76 }
77 return val;
78 }
79
pnv_occ_power8_xscom_write(void * opaque,hwaddr addr,uint64_t val,unsigned size)80 static void pnv_occ_power8_xscom_write(void *opaque, hwaddr addr,
81 uint64_t val, unsigned size)
82 {
83 PnvOCC *occ = PNV_OCC(opaque);
84 uint32_t offset = addr >> 3;
85
86 switch (offset) {
87 case OCB_OCI_OCCMISC_AND:
88 pnv_occ_set_misc(occ, occ->occmisc & val);
89 break;
90 case OCB_OCI_OCCMISC_OR:
91 pnv_occ_set_misc(occ, occ->occmisc | val);
92 break;
93 case OCB_OCI_OCCMISC:
94 pnv_occ_set_misc(occ, val);
95 break;
96 default:
97 qemu_log_mask(LOG_UNIMP, "OCC Unimplemented register: Ox%"
98 HWADDR_PRIx "\n", addr >> 3);
99 }
100 }
101
pnv_occ_common_area_read(void * opaque,hwaddr addr,unsigned width)102 static uint64_t pnv_occ_common_area_read(void *opaque, hwaddr addr,
103 unsigned width)
104 {
105 switch (addr) {
106 /*
107 * occ-sensor sanity check that asserts the sensor
108 * header block
109 */
110 case OCC_SENSOR_DATA_BLOCK_OFFSET:
111 case OCC_SENSOR_DATA_VALID:
112 case OCC_SENSOR_DATA_VERSION:
113 case OCC_SENSOR_DATA_READING_VERSION:
114 case OCC_SENSOR_DATA_NR_SENSORS:
115 case OCC_SENSOR_DATA_NAMES_OFFSET:
116 case OCC_SENSOR_DATA_READING_PING_OFFSET:
117 case OCC_SENSOR_DATA_READING_PONG_OFFSET:
118 case OCC_SENSOR_NAME_STRUCTURE_TYPE:
119 return 1;
120 case OCC_SENSOR_DATA_NAME_LENGTH:
121 return 0x30;
122 case OCC_SENSOR_LOC_CORE:
123 return 0x0040;
124 case OCC_SENSOR_TYPE_POWER:
125 return 0x0080;
126 case OCC_SENSOR_NAME:
127 return 0x1000;
128 case HWMON_SENSORS_MASK:
129 case OCC_SENSOR_LOC_GPU:
130 return 0x8e00;
131 }
132 return 0;
133 }
134
pnv_occ_common_area_write(void * opaque,hwaddr addr,uint64_t val,unsigned width)135 static void pnv_occ_common_area_write(void *opaque, hwaddr addr,
136 uint64_t val, unsigned width)
137 {
138 /* callback function defined to occ common area write */
139 return;
140 }
141
142 static const MemoryRegionOps pnv_occ_power8_xscom_ops = {
143 .read = pnv_occ_power8_xscom_read,
144 .write = pnv_occ_power8_xscom_write,
145 .valid.min_access_size = 8,
146 .valid.max_access_size = 8,
147 .impl.min_access_size = 8,
148 .impl.max_access_size = 8,
149 .endianness = DEVICE_BIG_ENDIAN,
150 };
151
152 const MemoryRegionOps pnv_occ_sram_ops = {
153 .read = pnv_occ_common_area_read,
154 .write = pnv_occ_common_area_write,
155 .valid.min_access_size = 1,
156 .valid.max_access_size = 8,
157 .impl.min_access_size = 1,
158 .impl.max_access_size = 8,
159 .endianness = DEVICE_BIG_ENDIAN,
160 };
161
pnv_occ_power8_class_init(ObjectClass * klass,void * data)162 static void pnv_occ_power8_class_init(ObjectClass *klass, void *data)
163 {
164 PnvOCCClass *poc = PNV_OCC_CLASS(klass);
165
166 poc->xscom_size = PNV_XSCOM_OCC_SIZE;
167 poc->xscom_ops = &pnv_occ_power8_xscom_ops;
168 }
169
170 static const TypeInfo pnv_occ_power8_type_info = {
171 .name = TYPE_PNV8_OCC,
172 .parent = TYPE_PNV_OCC,
173 .instance_size = sizeof(PnvOCC),
174 .class_init = pnv_occ_power8_class_init,
175 };
176
177 #define P9_OCB_OCI_OCCMISC 0x6080
178 #define P9_OCB_OCI_OCCMISC_CLEAR 0x6081
179 #define P9_OCB_OCI_OCCMISC_OR 0x6082
180
181
pnv_occ_power9_xscom_read(void * opaque,hwaddr addr,unsigned size)182 static uint64_t pnv_occ_power9_xscom_read(void *opaque, hwaddr addr,
183 unsigned size)
184 {
185 PnvOCC *occ = PNV_OCC(opaque);
186 uint32_t offset = addr >> 3;
187 uint64_t val = 0;
188
189 switch (offset) {
190 case P9_OCB_OCI_OCCMISC:
191 val = occ->occmisc;
192 break;
193 default:
194 qemu_log_mask(LOG_UNIMP, "OCC Unimplemented register: Ox%"
195 HWADDR_PRIx "\n", addr >> 3);
196 }
197 return val;
198 }
199
pnv_occ_power9_xscom_write(void * opaque,hwaddr addr,uint64_t val,unsigned size)200 static void pnv_occ_power9_xscom_write(void *opaque, hwaddr addr,
201 uint64_t val, unsigned size)
202 {
203 PnvOCC *occ = PNV_OCC(opaque);
204 uint32_t offset = addr >> 3;
205
206 switch (offset) {
207 case P9_OCB_OCI_OCCMISC_CLEAR:
208 pnv_occ_set_misc(occ, 0);
209 break;
210 case P9_OCB_OCI_OCCMISC_OR:
211 pnv_occ_set_misc(occ, occ->occmisc | val);
212 break;
213 case P9_OCB_OCI_OCCMISC:
214 pnv_occ_set_misc(occ, val);
215 break;
216 default:
217 qemu_log_mask(LOG_UNIMP, "OCC Unimplemented register: Ox%"
218 HWADDR_PRIx "\n", addr >> 3);
219 }
220 }
221
222 static const MemoryRegionOps pnv_occ_power9_xscom_ops = {
223 .read = pnv_occ_power9_xscom_read,
224 .write = pnv_occ_power9_xscom_write,
225 .valid.min_access_size = 8,
226 .valid.max_access_size = 8,
227 .impl.min_access_size = 8,
228 .impl.max_access_size = 8,
229 .endianness = DEVICE_BIG_ENDIAN,
230 };
231
pnv_occ_power9_class_init(ObjectClass * klass,void * data)232 static void pnv_occ_power9_class_init(ObjectClass *klass, void *data)
233 {
234 PnvOCCClass *poc = PNV_OCC_CLASS(klass);
235 DeviceClass *dc = DEVICE_CLASS(klass);
236
237 dc->desc = "PowerNV OCC Controller (POWER9)";
238 poc->xscom_size = PNV9_XSCOM_OCC_SIZE;
239 poc->xscom_ops = &pnv_occ_power9_xscom_ops;
240 }
241
242 static const TypeInfo pnv_occ_power9_type_info = {
243 .name = TYPE_PNV9_OCC,
244 .parent = TYPE_PNV_OCC,
245 .instance_size = sizeof(PnvOCC),
246 .class_init = pnv_occ_power9_class_init,
247 };
248
pnv_occ_power10_class_init(ObjectClass * klass,void * data)249 static void pnv_occ_power10_class_init(ObjectClass *klass, void *data)
250 {
251 DeviceClass *dc = DEVICE_CLASS(klass);
252
253 dc->desc = "PowerNV OCC Controller (POWER10)";
254 }
255
256 static const TypeInfo pnv_occ_power10_type_info = {
257 .name = TYPE_PNV10_OCC,
258 .parent = TYPE_PNV9_OCC,
259 .class_init = pnv_occ_power10_class_init,
260 };
261
pnv_occ_realize(DeviceState * dev,Error ** errp)262 static void pnv_occ_realize(DeviceState *dev, Error **errp)
263 {
264 PnvOCC *occ = PNV_OCC(dev);
265 PnvOCCClass *poc = PNV_OCC_GET_CLASS(occ);
266
267 occ->occmisc = 0;
268
269 /* XScom region for OCC registers */
270 pnv_xscom_region_init(&occ->xscom_regs, OBJECT(dev), poc->xscom_ops,
271 occ, "xscom-occ", poc->xscom_size);
272
273 /* OCC common area mmio region for OCC SRAM registers */
274 memory_region_init_io(&occ->sram_regs, OBJECT(dev), &pnv_occ_sram_ops,
275 occ, "occ-common-area",
276 PNV_OCC_SENSOR_DATA_BLOCK_SIZE);
277
278 qdev_init_gpio_out(dev, &occ->psi_irq, 1);
279 }
280
pnv_occ_class_init(ObjectClass * klass,void * data)281 static void pnv_occ_class_init(ObjectClass *klass, void *data)
282 {
283 DeviceClass *dc = DEVICE_CLASS(klass);
284
285 dc->realize = pnv_occ_realize;
286 dc->desc = "PowerNV OCC Controller";
287 dc->user_creatable = false;
288 }
289
290 static const TypeInfo pnv_occ_type_info = {
291 .name = TYPE_PNV_OCC,
292 .parent = TYPE_DEVICE,
293 .instance_size = sizeof(PnvOCC),
294 .class_init = pnv_occ_class_init,
295 .class_size = sizeof(PnvOCCClass),
296 .abstract = true,
297 };
298
pnv_occ_register_types(void)299 static void pnv_occ_register_types(void)
300 {
301 type_register_static(&pnv_occ_type_info);
302 type_register_static(&pnv_occ_power8_type_info);
303 type_register_static(&pnv_occ_power9_type_info);
304 type_register_static(&pnv_occ_power10_type_info);
305 }
306
307 type_init(pnv_occ_register_types);
308