xref: /openbmc/qemu/hw/ppc/pnv_occ.c (revision f3da6934cdbb1599918ae31c33f957c5cd9070dd)
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