xref: /qemu/hw/ppc/pnv_occ.c (revision 336d354b)
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/qdev-properties.h"
25 #include "hw/ppc/pnv.h"
26 #include "hw/ppc/pnv_xscom.h"
27 #include "hw/ppc/pnv_occ.h"
28 
29 #define OCB_OCI_OCCMISC         0x4020
30 #define OCB_OCI_OCCMISC_AND     0x4021
31 #define OCB_OCI_OCCMISC_OR      0x4022
32 
33 /* OCC sensors */
34 #define OCC_SENSOR_DATA_BLOCK_OFFSET          0x580000
35 #define OCC_SENSOR_DATA_VALID                 0x580001
36 #define OCC_SENSOR_DATA_VERSION               0x580002
37 #define OCC_SENSOR_DATA_READING_VERSION       0x580004
38 #define OCC_SENSOR_DATA_NR_SENSORS            0x580008
39 #define OCC_SENSOR_DATA_NAMES_OFFSET          0x580010
40 #define OCC_SENSOR_DATA_READING_PING_OFFSET   0x580014
41 #define OCC_SENSOR_DATA_READING_PONG_OFFSET   0x58000c
42 #define OCC_SENSOR_DATA_NAME_LENGTH           0x58000d
43 #define OCC_SENSOR_NAME_STRUCTURE_TYPE        0x580023
44 #define OCC_SENSOR_LOC_CORE                   0x580022
45 #define OCC_SENSOR_LOC_GPU                    0x580020
46 #define OCC_SENSOR_TYPE_POWER                 0x580003
47 #define OCC_SENSOR_NAME                       0x580005
48 #define HWMON_SENSORS_MASK                    0x58001e
49 #define SLW_IMAGE_BASE                        0x0
50 
51 static void pnv_occ_set_misc(PnvOCC *occ, uint64_t val)
52 {
53     bool irq_state;
54     PnvOCCClass *poc = PNV_OCC_GET_CLASS(occ);
55 
56     val &= 0xffff000000000000ull;
57 
58     occ->occmisc = val;
59     irq_state = !!(val >> 63);
60     pnv_psi_irq_set(occ->psi, poc->psi_irq, irq_state);
61 }
62 
63 static uint64_t pnv_occ_power8_xscom_read(void *opaque, hwaddr addr,
64                                           unsigned size)
65 {
66     PnvOCC *occ = PNV_OCC(opaque);
67     uint32_t offset = addr >> 3;
68     uint64_t val = 0;
69 
70     switch (offset) {
71     case OCB_OCI_OCCMISC:
72         val = occ->occmisc;
73         break;
74     default:
75         qemu_log_mask(LOG_UNIMP, "OCC Unimplemented register: Ox%"
76                       HWADDR_PRIx "\n", addr >> 3);
77     }
78     return val;
79 }
80 
81 static void pnv_occ_power8_xscom_write(void *opaque, hwaddr addr,
82                                        uint64_t val, unsigned size)
83 {
84     PnvOCC *occ = PNV_OCC(opaque);
85     uint32_t offset = addr >> 3;
86 
87     switch (offset) {
88     case OCB_OCI_OCCMISC_AND:
89         pnv_occ_set_misc(occ, occ->occmisc & val);
90         break;
91     case OCB_OCI_OCCMISC_OR:
92         pnv_occ_set_misc(occ, occ->occmisc | val);
93         break;
94     case OCB_OCI_OCCMISC:
95         pnv_occ_set_misc(occ, val);
96         break;
97     default:
98         qemu_log_mask(LOG_UNIMP, "OCC Unimplemented register: Ox%"
99                       HWADDR_PRIx "\n", addr >> 3);
100     }
101 }
102 
103 static uint64_t pnv_occ_common_area_read(void *opaque, hwaddr addr,
104                                          unsigned width)
105 {
106     switch (addr) {
107     /*
108      * occ-sensor sanity check that asserts the sensor
109      * header block
110      */
111     case OCC_SENSOR_DATA_BLOCK_OFFSET:
112     case OCC_SENSOR_DATA_VALID:
113     case OCC_SENSOR_DATA_VERSION:
114     case OCC_SENSOR_DATA_READING_VERSION:
115     case OCC_SENSOR_DATA_NR_SENSORS:
116     case OCC_SENSOR_DATA_NAMES_OFFSET:
117     case OCC_SENSOR_DATA_READING_PING_OFFSET:
118     case OCC_SENSOR_DATA_READING_PONG_OFFSET:
119     case OCC_SENSOR_NAME_STRUCTURE_TYPE:
120         return 1;
121     case OCC_SENSOR_DATA_NAME_LENGTH:
122         return 0x30;
123     case OCC_SENSOR_LOC_CORE:
124         return 0x0040;
125     case OCC_SENSOR_TYPE_POWER:
126         return 0x0080;
127     case OCC_SENSOR_NAME:
128         return 0x1000;
129     case HWMON_SENSORS_MASK:
130     case OCC_SENSOR_LOC_GPU:
131         return 0x8e00;
132     case SLW_IMAGE_BASE:
133         return 0x1000000000000000;
134     }
135     return 0;
136 }
137 
138 static void pnv_occ_common_area_write(void *opaque, hwaddr addr,
139                                              uint64_t val, unsigned width)
140 {
141     /* callback function defined to occ common area write */
142     return;
143 }
144 
145 static const MemoryRegionOps pnv_occ_power8_xscom_ops = {
146     .read = pnv_occ_power8_xscom_read,
147     .write = pnv_occ_power8_xscom_write,
148     .valid.min_access_size = 8,
149     .valid.max_access_size = 8,
150     .impl.min_access_size = 8,
151     .impl.max_access_size = 8,
152     .endianness = DEVICE_BIG_ENDIAN,
153 };
154 
155 const MemoryRegionOps pnv_occ_sram_ops = {
156     .read = pnv_occ_common_area_read,
157     .write = pnv_occ_common_area_write,
158     .valid.min_access_size = 1,
159     .valid.max_access_size = 8,
160     .impl.min_access_size = 1,
161     .impl.max_access_size = 8,
162     .endianness = DEVICE_BIG_ENDIAN,
163 };
164 
165 static void pnv_occ_power8_class_init(ObjectClass *klass, void *data)
166 {
167     PnvOCCClass *poc = PNV_OCC_CLASS(klass);
168 
169     poc->xscom_size = PNV_XSCOM_OCC_SIZE;
170     poc->xscom_ops = &pnv_occ_power8_xscom_ops;
171     poc->psi_irq = PSIHB_IRQ_OCC;
172 }
173 
174 static const TypeInfo pnv_occ_power8_type_info = {
175     .name          = TYPE_PNV8_OCC,
176     .parent        = TYPE_PNV_OCC,
177     .instance_size = sizeof(PnvOCC),
178     .class_init    = pnv_occ_power8_class_init,
179 };
180 
181 #define P9_OCB_OCI_OCCMISC              0x6080
182 #define P9_OCB_OCI_OCCMISC_CLEAR        0x6081
183 #define P9_OCB_OCI_OCCMISC_OR           0x6082
184 
185 
186 static uint64_t pnv_occ_power9_xscom_read(void *opaque, hwaddr addr,
187                                           unsigned size)
188 {
189     PnvOCC *occ = PNV_OCC(opaque);
190     uint32_t offset = addr >> 3;
191     uint64_t val = 0;
192 
193     switch (offset) {
194     case P9_OCB_OCI_OCCMISC:
195         val = occ->occmisc;
196         break;
197     default:
198         qemu_log_mask(LOG_UNIMP, "OCC Unimplemented register: Ox%"
199                       HWADDR_PRIx "\n", addr >> 3);
200     }
201     return val;
202 }
203 
204 static void pnv_occ_power9_xscom_write(void *opaque, hwaddr addr,
205                                        uint64_t val, unsigned size)
206 {
207     PnvOCC *occ = PNV_OCC(opaque);
208     uint32_t offset = addr >> 3;
209 
210     switch (offset) {
211     case P9_OCB_OCI_OCCMISC_CLEAR:
212         pnv_occ_set_misc(occ, 0);
213         break;
214     case P9_OCB_OCI_OCCMISC_OR:
215         pnv_occ_set_misc(occ, occ->occmisc | val);
216         break;
217     case P9_OCB_OCI_OCCMISC:
218         pnv_occ_set_misc(occ, val);
219        break;
220     default:
221         qemu_log_mask(LOG_UNIMP, "OCC Unimplemented register: Ox%"
222                       HWADDR_PRIx "\n", addr >> 3);
223     }
224 }
225 
226 static const MemoryRegionOps pnv_occ_power9_xscom_ops = {
227     .read = pnv_occ_power9_xscom_read,
228     .write = pnv_occ_power9_xscom_write,
229     .valid.min_access_size = 8,
230     .valid.max_access_size = 8,
231     .impl.min_access_size = 8,
232     .impl.max_access_size = 8,
233     .endianness = DEVICE_BIG_ENDIAN,
234 };
235 
236 static void pnv_occ_power9_class_init(ObjectClass *klass, void *data)
237 {
238     PnvOCCClass *poc = PNV_OCC_CLASS(klass);
239     DeviceClass *dc = DEVICE_CLASS(klass);
240 
241     dc->desc = "PowerNV OCC Controller (POWER9)";
242     poc->xscom_size = PNV9_XSCOM_OCC_SIZE;
243     poc->xscom_ops = &pnv_occ_power9_xscom_ops;
244     poc->psi_irq = PSIHB9_IRQ_OCC;
245 }
246 
247 static const TypeInfo pnv_occ_power9_type_info = {
248     .name          = TYPE_PNV9_OCC,
249     .parent        = TYPE_PNV_OCC,
250     .instance_size = sizeof(PnvOCC),
251     .class_init    = pnv_occ_power9_class_init,
252 };
253 
254 static void pnv_occ_power10_class_init(ObjectClass *klass, void *data)
255 {
256     DeviceClass *dc = DEVICE_CLASS(klass);
257 
258     dc->desc = "PowerNV OCC Controller (POWER10)";
259 }
260 
261 static const TypeInfo pnv_occ_power10_type_info = {
262     .name          = TYPE_PNV10_OCC,
263     .parent        = TYPE_PNV9_OCC,
264     .class_init    = pnv_occ_power10_class_init,
265 };
266 
267 static void pnv_occ_realize(DeviceState *dev, Error **errp)
268 {
269     PnvOCC *occ = PNV_OCC(dev);
270     PnvOCCClass *poc = PNV_OCC_GET_CLASS(occ);
271 
272     assert(occ->psi);
273 
274     occ->occmisc = 0;
275 
276     /* XScom region for OCC registers */
277     pnv_xscom_region_init(&occ->xscom_regs, OBJECT(dev), poc->xscom_ops,
278                           occ, "xscom-occ", poc->xscom_size);
279 
280     /* OCC common area mmio region for OCC SRAM registers */
281     memory_region_init_io(&occ->sram_regs, OBJECT(dev), &pnv_occ_sram_ops,
282                           occ, "occ-common-area",
283                           PNV_OCC_SENSOR_DATA_BLOCK_SIZE);
284 }
285 
286 static Property pnv_occ_properties[] = {
287     DEFINE_PROP_LINK("psi", PnvOCC, psi, TYPE_PNV_PSI, PnvPsi *),
288     DEFINE_PROP_END_OF_LIST(),
289 };
290 
291 static void pnv_occ_class_init(ObjectClass *klass, void *data)
292 {
293     DeviceClass *dc = DEVICE_CLASS(klass);
294 
295     dc->realize = pnv_occ_realize;
296     dc->desc = "PowerNV OCC Controller";
297     device_class_set_props(dc, pnv_occ_properties);
298     dc->user_creatable = false;
299 }
300 
301 static const TypeInfo pnv_occ_type_info = {
302     .name          = TYPE_PNV_OCC,
303     .parent        = TYPE_DEVICE,
304     .instance_size = sizeof(PnvOCC),
305     .class_init    = pnv_occ_class_init,
306     .class_size    = sizeof(PnvOCCClass),
307     .abstract      = true,
308 };
309 
310 static void pnv_occ_register_types(void)
311 {
312     type_register_static(&pnv_occ_type_info);
313     type_register_static(&pnv_occ_power8_type_info);
314     type_register_static(&pnv_occ_power9_type_info);
315     type_register_static(&pnv_occ_power10_type_info);
316 }
317 
318 type_init(pnv_occ_register_types);
319