xref: /openbmc/qemu/hw/ppc/pnv_occ.c (revision c85cad81)
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          0x580000
36 #define OCC_SENSOR_DATA_VALID                 0x580001
37 #define OCC_SENSOR_DATA_VERSION               0x580002
38 #define OCC_SENSOR_DATA_READING_VERSION       0x580004
39 #define OCC_SENSOR_DATA_NR_SENSORS            0x580008
40 #define OCC_SENSOR_DATA_NAMES_OFFSET          0x580010
41 #define OCC_SENSOR_DATA_READING_PING_OFFSET   0x580014
42 #define OCC_SENSOR_DATA_READING_PONG_OFFSET   0x58000c
43 #define OCC_SENSOR_DATA_NAME_LENGTH           0x58000d
44 #define OCC_SENSOR_NAME_STRUCTURE_TYPE        0x580023
45 #define OCC_SENSOR_LOC_CORE                   0x580022
46 #define OCC_SENSOR_LOC_GPU                    0x580020
47 #define OCC_SENSOR_TYPE_POWER                 0x580003
48 #define OCC_SENSOR_NAME                       0x580005
49 #define HWMON_SENSORS_MASK                    0x58001e
50 #define SLW_IMAGE_BASE                        0x0
51 
52 static void pnv_occ_set_misc(PnvOCC *occ, uint64_t val)
53 {
54     bool irq_state;
55 
56     val &= 0xffff000000000000ull;
57 
58     occ->occmisc = val;
59     irq_state = !!(val >> 63);
60     qemu_set_irq(occ->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 }
172 
173 static const TypeInfo pnv_occ_power8_type_info = {
174     .name          = TYPE_PNV8_OCC,
175     .parent        = TYPE_PNV_OCC,
176     .instance_size = sizeof(PnvOCC),
177     .class_init    = pnv_occ_power8_class_init,
178 };
179 
180 #define P9_OCB_OCI_OCCMISC              0x6080
181 #define P9_OCB_OCI_OCCMISC_CLEAR        0x6081
182 #define P9_OCB_OCI_OCCMISC_OR           0x6082
183 
184 
185 static uint64_t pnv_occ_power9_xscom_read(void *opaque, hwaddr addr,
186                                           unsigned size)
187 {
188     PnvOCC *occ = PNV_OCC(opaque);
189     uint32_t offset = addr >> 3;
190     uint64_t val = 0;
191 
192     switch (offset) {
193     case P9_OCB_OCI_OCCMISC:
194         val = occ->occmisc;
195         break;
196     default:
197         qemu_log_mask(LOG_UNIMP, "OCC Unimplemented register: Ox%"
198                       HWADDR_PRIx "\n", addr >> 3);
199     }
200     return val;
201 }
202 
203 static void pnv_occ_power9_xscom_write(void *opaque, hwaddr addr,
204                                        uint64_t val, unsigned size)
205 {
206     PnvOCC *occ = PNV_OCC(opaque);
207     uint32_t offset = addr >> 3;
208 
209     switch (offset) {
210     case P9_OCB_OCI_OCCMISC_CLEAR:
211         pnv_occ_set_misc(occ, 0);
212         break;
213     case P9_OCB_OCI_OCCMISC_OR:
214         pnv_occ_set_misc(occ, occ->occmisc | val);
215         break;
216     case P9_OCB_OCI_OCCMISC:
217         pnv_occ_set_misc(occ, val);
218        break;
219     default:
220         qemu_log_mask(LOG_UNIMP, "OCC Unimplemented register: Ox%"
221                       HWADDR_PRIx "\n", addr >> 3);
222     }
223 }
224 
225 static const MemoryRegionOps pnv_occ_power9_xscom_ops = {
226     .read = pnv_occ_power9_xscom_read,
227     .write = pnv_occ_power9_xscom_write,
228     .valid.min_access_size = 8,
229     .valid.max_access_size = 8,
230     .impl.min_access_size = 8,
231     .impl.max_access_size = 8,
232     .endianness = DEVICE_BIG_ENDIAN,
233 };
234 
235 static void pnv_occ_power9_class_init(ObjectClass *klass, void *data)
236 {
237     PnvOCCClass *poc = PNV_OCC_CLASS(klass);
238     DeviceClass *dc = DEVICE_CLASS(klass);
239 
240     dc->desc = "PowerNV OCC Controller (POWER9)";
241     poc->xscom_size = PNV9_XSCOM_OCC_SIZE;
242     poc->xscom_ops = &pnv_occ_power9_xscom_ops;
243 }
244 
245 static const TypeInfo pnv_occ_power9_type_info = {
246     .name          = TYPE_PNV9_OCC,
247     .parent        = TYPE_PNV_OCC,
248     .instance_size = sizeof(PnvOCC),
249     .class_init    = pnv_occ_power9_class_init,
250 };
251 
252 static void pnv_occ_power10_class_init(ObjectClass *klass, void *data)
253 {
254     DeviceClass *dc = DEVICE_CLASS(klass);
255 
256     dc->desc = "PowerNV OCC Controller (POWER10)";
257 }
258 
259 static const TypeInfo pnv_occ_power10_type_info = {
260     .name          = TYPE_PNV10_OCC,
261     .parent        = TYPE_PNV9_OCC,
262     .class_init    = pnv_occ_power10_class_init,
263 };
264 
265 static void pnv_occ_realize(DeviceState *dev, Error **errp)
266 {
267     PnvOCC *occ = PNV_OCC(dev);
268     PnvOCCClass *poc = PNV_OCC_GET_CLASS(occ);
269 
270     occ->occmisc = 0;
271 
272     /* XScom region for OCC registers */
273     pnv_xscom_region_init(&occ->xscom_regs, OBJECT(dev), poc->xscom_ops,
274                           occ, "xscom-occ", poc->xscom_size);
275 
276     /* OCC common area mmio region for OCC SRAM registers */
277     memory_region_init_io(&occ->sram_regs, OBJECT(dev), &pnv_occ_sram_ops,
278                           occ, "occ-common-area",
279                           PNV_OCC_SENSOR_DATA_BLOCK_SIZE);
280 
281     qdev_init_gpio_out(dev, &occ->psi_irq, 1);
282 }
283 
284 static void pnv_occ_class_init(ObjectClass *klass, void *data)
285 {
286     DeviceClass *dc = DEVICE_CLASS(klass);
287 
288     dc->realize = pnv_occ_realize;
289     dc->desc = "PowerNV OCC Controller";
290     dc->user_creatable = false;
291 }
292 
293 static const TypeInfo pnv_occ_type_info = {
294     .name          = TYPE_PNV_OCC,
295     .parent        = TYPE_DEVICE,
296     .instance_size = sizeof(PnvOCC),
297     .class_init    = pnv_occ_class_init,
298     .class_size    = sizeof(PnvOCCClass),
299     .abstract      = true,
300 };
301 
302 static void pnv_occ_register_types(void)
303 {
304     type_register_static(&pnv_occ_type_info);
305     type_register_static(&pnv_occ_power8_type_info);
306     type_register_static(&pnv_occ_power9_type_info);
307     type_register_static(&pnv_occ_power10_type_info);
308 }
309 
310 type_init(pnv_occ_register_types);
311