xref: /qemu/hw/ppc/pnv_occ.c (revision 13f934e7)
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 
240     poc->xscom_size = PNV9_XSCOM_OCC_SIZE;
241     poc->xscom_ops = &pnv_occ_power9_xscom_ops;
242     poc->psi_irq = PSIHB9_IRQ_OCC;
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_realize(DeviceState *dev, Error **errp)
253 {
254     PnvOCC *occ = PNV_OCC(dev);
255     PnvOCCClass *poc = PNV_OCC_GET_CLASS(occ);
256 
257     assert(occ->psi);
258 
259     occ->occmisc = 0;
260 
261     /* XScom region for OCC registers */
262     pnv_xscom_region_init(&occ->xscom_regs, OBJECT(dev), poc->xscom_ops,
263                           occ, "xscom-occ", poc->xscom_size);
264 
265     /* OCC common area mmio region for OCC SRAM registers */
266     memory_region_init_io(&occ->sram_regs, OBJECT(dev), &pnv_occ_sram_ops,
267                           occ, "occ-common-area",
268                           PNV_OCC_SENSOR_DATA_BLOCK_SIZE);
269 }
270 
271 static Property pnv_occ_properties[] = {
272     DEFINE_PROP_LINK("psi", PnvOCC, psi, TYPE_PNV_PSI, PnvPsi *),
273     DEFINE_PROP_END_OF_LIST(),
274 };
275 
276 static void pnv_occ_class_init(ObjectClass *klass, void *data)
277 {
278     DeviceClass *dc = DEVICE_CLASS(klass);
279 
280     dc->realize = pnv_occ_realize;
281     dc->desc = "PowerNV OCC Controller";
282     device_class_set_props(dc, pnv_occ_properties);
283     dc->user_creatable = false;
284 }
285 
286 static const TypeInfo pnv_occ_type_info = {
287     .name          = TYPE_PNV_OCC,
288     .parent        = TYPE_DEVICE,
289     .instance_size = sizeof(PnvOCC),
290     .class_init    = pnv_occ_class_init,
291     .class_size    = sizeof(PnvOCCClass),
292     .abstract      = true,
293 };
294 
295 static void pnv_occ_register_types(void)
296 {
297     type_register_static(&pnv_occ_type_info);
298     type_register_static(&pnv_occ_power8_type_info);
299     type_register_static(&pnv_occ_power9_type_info);
300 }
301 
302 type_init(pnv_occ_register_types);
303