xref: /openbmc/qemu/hw/ppc/pnv_occ.c (revision ab9056ff)
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 
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->sram_size = PNV_OCC_COMMON_AREA_SIZE;
171     poc->xscom_ops = &pnv_occ_power8_xscom_ops;
172     poc->sram_ops = &pnv_occ_sram_ops;
173     poc->psi_irq = PSIHB_IRQ_OCC;
174 }
175 
176 static const TypeInfo pnv_occ_power8_type_info = {
177     .name          = TYPE_PNV8_OCC,
178     .parent        = TYPE_PNV_OCC,
179     .instance_size = sizeof(PnvOCC),
180     .class_init    = pnv_occ_power8_class_init,
181 };
182 
183 #define P9_OCB_OCI_OCCMISC              0x6080
184 #define P9_OCB_OCI_OCCMISC_CLEAR        0x6081
185 #define P9_OCB_OCI_OCCMISC_OR           0x6082
186 
187 
188 static uint64_t pnv_occ_power9_xscom_read(void *opaque, hwaddr addr,
189                                           unsigned size)
190 {
191     PnvOCC *occ = PNV_OCC(opaque);
192     uint32_t offset = addr >> 3;
193     uint64_t val = 0;
194 
195     switch (offset) {
196     case P9_OCB_OCI_OCCMISC:
197         val = occ->occmisc;
198         break;
199     default:
200         qemu_log_mask(LOG_UNIMP, "OCC Unimplemented register: Ox%"
201                       HWADDR_PRIx "\n", addr >> 3);
202     }
203     return val;
204 }
205 
206 static void pnv_occ_power9_xscom_write(void *opaque, hwaddr addr,
207                                        uint64_t val, unsigned size)
208 {
209     PnvOCC *occ = PNV_OCC(opaque);
210     uint32_t offset = addr >> 3;
211 
212     switch (offset) {
213     case P9_OCB_OCI_OCCMISC_CLEAR:
214         pnv_occ_set_misc(occ, 0);
215         break;
216     case P9_OCB_OCI_OCCMISC_OR:
217         pnv_occ_set_misc(occ, occ->occmisc | val);
218         break;
219     case P9_OCB_OCI_OCCMISC:
220         pnv_occ_set_misc(occ, val);
221        break;
222     default:
223         qemu_log_mask(LOG_UNIMP, "OCC Unimplemented register: Ox%"
224                       HWADDR_PRIx "\n", addr >> 3);
225     }
226 }
227 
228 static const MemoryRegionOps pnv_occ_power9_xscom_ops = {
229     .read = pnv_occ_power9_xscom_read,
230     .write = pnv_occ_power9_xscom_write,
231     .valid.min_access_size = 8,
232     .valid.max_access_size = 8,
233     .impl.min_access_size = 8,
234     .impl.max_access_size = 8,
235     .endianness = DEVICE_BIG_ENDIAN,
236 };
237 
238 static void pnv_occ_power9_class_init(ObjectClass *klass, void *data)
239 {
240     PnvOCCClass *poc = PNV_OCC_CLASS(klass);
241 
242     poc->xscom_size = PNV9_XSCOM_OCC_SIZE;
243     poc->sram_size = PNV9_OCC_COMMON_AREA_SIZE;
244     poc->xscom_ops = &pnv_occ_power9_xscom_ops;
245     poc->sram_ops = &pnv_occ_sram_ops;
246     poc->psi_irq = PSIHB9_IRQ_OCC;
247 }
248 
249 static const TypeInfo pnv_occ_power9_type_info = {
250     .name          = TYPE_PNV9_OCC,
251     .parent        = TYPE_PNV_OCC,
252     .instance_size = sizeof(PnvOCC),
253     .class_init    = pnv_occ_power9_class_init,
254 };
255 
256 static void pnv_occ_realize(DeviceState *dev, Error **errp)
257 {
258     PnvOCC *occ = PNV_OCC(dev);
259     PnvOCCClass *poc = PNV_OCC_GET_CLASS(occ);
260     Object *obj;
261     Error *local_err = NULL;
262 
263     occ->occmisc = 0;
264 
265     obj = object_property_get_link(OBJECT(dev), "psi", &local_err);
266     if (!obj) {
267         error_propagate(errp, local_err);
268         error_prepend(errp, "required link 'psi' not found: ");
269         return;
270     }
271     occ->psi = PNV_PSI(obj);
272 
273     /* XScom region for OCC registers */
274     pnv_xscom_region_init(&occ->xscom_regs, OBJECT(dev), poc->xscom_ops,
275                           occ, "xscom-occ", poc->xscom_size);
276 
277     /* XScom region for OCC SRAM registers */
278     pnv_xscom_region_init(&occ->sram_regs, OBJECT(dev), poc->sram_ops,
279                           occ, "occ-common-area", poc->sram_size);
280 }
281 
282 static void pnv_occ_class_init(ObjectClass *klass, void *data)
283 {
284     DeviceClass *dc = DEVICE_CLASS(klass);
285 
286     dc->realize = pnv_occ_realize;
287     dc->desc = "PowerNV OCC Controller";
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 
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 }
305 
306 type_init(pnv_occ_register_types);
307