2 * QEMU PowerPC PowerNV Emulation of a few OCC related registers
4 * Copyright (c) 2015-2017, IBM Corporation.
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.
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.
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/>.
19 #include "qemu/osdep.h"
21 #include "sysemu/sysemu.h"
22 #include "target/ppc/cpu.h"
23 #include "qapi/error.h"
25 #include "qemu/module.h"
27 #include "hw/ppc/pnv.h"
28 #include "hw/ppc/pnv_xscom.h"
29 #include "hw/ppc/pnv_occ.h"
31 #define OCB_OCI_OCCMISC 0x4020
32 #define OCB_OCI_OCCMISC_AND 0x4021
33 #define OCB_OCI_OCCMISC_OR 0x4022
35 static void pnv_occ_set_misc(PnvOCC
*occ
, uint64_t val
)
38 PnvOCCClass
*poc
= PNV_OCC_GET_CLASS(occ
);
40 val
&= 0xffff000000000000ull
;
43 irq_state
= !!(val
>> 63);
44 pnv_psi_irq_set(occ
->psi
, poc
->psi_irq
, irq_state
);
47 static uint64_t pnv_occ_power8_xscom_read(void *opaque
, hwaddr addr
,
50 PnvOCC
*occ
= PNV_OCC(opaque
);
51 uint32_t offset
= addr
>> 3;
59 qemu_log_mask(LOG_UNIMP
, "OCC Unimplemented register: Ox%"
60 HWADDR_PRIx
"\n", addr
>> 3);
65 static void pnv_occ_power8_xscom_write(void *opaque
, hwaddr addr
,
66 uint64_t val
, unsigned size
)
68 PnvOCC
*occ
= PNV_OCC(opaque
);
69 uint32_t offset
= addr
>> 3;
72 case OCB_OCI_OCCMISC_AND
:
73 pnv_occ_set_misc(occ
, occ
->occmisc
& val
);
75 case OCB_OCI_OCCMISC_OR
:
76 pnv_occ_set_misc(occ
, occ
->occmisc
| val
);
79 pnv_occ_set_misc(occ
, val
);
82 qemu_log_mask(LOG_UNIMP
, "OCC Unimplemented register: Ox%"
83 HWADDR_PRIx
"\n", addr
>> 3);
87 static const MemoryRegionOps pnv_occ_power8_xscom_ops
= {
88 .read
= pnv_occ_power8_xscom_read
,
89 .write
= pnv_occ_power8_xscom_write
,
90 .valid
.min_access_size
= 8,
91 .valid
.max_access_size
= 8,
92 .impl
.min_access_size
= 8,
93 .impl
.max_access_size
= 8,
94 .endianness
= DEVICE_BIG_ENDIAN
,
97 static void pnv_occ_power8_class_init(ObjectClass
*klass
, void *data
)
99 PnvOCCClass
*poc
= PNV_OCC_CLASS(klass
);
101 poc
->xscom_size
= PNV_XSCOM_OCC_SIZE
;
102 poc
->xscom_ops
= &pnv_occ_power8_xscom_ops
;
103 poc
->psi_irq
= PSIHB_IRQ_OCC
;
106 static const TypeInfo pnv_occ_power8_type_info
= {
107 .name
= TYPE_PNV8_OCC
,
108 .parent
= TYPE_PNV_OCC
,
109 .instance_size
= sizeof(PnvOCC
),
110 .class_init
= pnv_occ_power8_class_init
,
113 #define P9_OCB_OCI_OCCMISC 0x6080
114 #define P9_OCB_OCI_OCCMISC_CLEAR 0x6081
115 #define P9_OCB_OCI_OCCMISC_OR 0x6082
118 static uint64_t pnv_occ_power9_xscom_read(void *opaque
, hwaddr addr
,
121 PnvOCC
*occ
= PNV_OCC(opaque
);
122 uint32_t offset
= addr
>> 3;
126 case P9_OCB_OCI_OCCMISC
:
130 qemu_log_mask(LOG_UNIMP
, "OCC Unimplemented register: Ox%"
131 HWADDR_PRIx
"\n", addr
>> 3);
136 static void pnv_occ_power9_xscom_write(void *opaque
, hwaddr addr
,
137 uint64_t val
, unsigned size
)
139 PnvOCC
*occ
= PNV_OCC(opaque
);
140 uint32_t offset
= addr
>> 3;
143 case P9_OCB_OCI_OCCMISC_CLEAR
:
144 pnv_occ_set_misc(occ
, 0);
146 case P9_OCB_OCI_OCCMISC_OR
:
147 pnv_occ_set_misc(occ
, occ
->occmisc
| val
);
149 case P9_OCB_OCI_OCCMISC
:
150 pnv_occ_set_misc(occ
, val
);
153 qemu_log_mask(LOG_UNIMP
, "OCC Unimplemented register: Ox%"
154 HWADDR_PRIx
"\n", addr
>> 3);
158 static const MemoryRegionOps pnv_occ_power9_xscom_ops
= {
159 .read
= pnv_occ_power9_xscom_read
,
160 .write
= pnv_occ_power9_xscom_write
,
161 .valid
.min_access_size
= 8,
162 .valid
.max_access_size
= 8,
163 .impl
.min_access_size
= 8,
164 .impl
.max_access_size
= 8,
165 .endianness
= DEVICE_BIG_ENDIAN
,
168 static void pnv_occ_power9_class_init(ObjectClass
*klass
, void *data
)
170 PnvOCCClass
*poc
= PNV_OCC_CLASS(klass
);
172 poc
->xscom_size
= PNV9_XSCOM_OCC_SIZE
;
173 poc
->xscom_ops
= &pnv_occ_power9_xscom_ops
;
174 poc
->psi_irq
= PSIHB9_IRQ_OCC
;
177 static const TypeInfo pnv_occ_power9_type_info
= {
178 .name
= TYPE_PNV9_OCC
,
179 .parent
= TYPE_PNV_OCC
,
180 .instance_size
= sizeof(PnvOCC
),
181 .class_init
= pnv_occ_power9_class_init
,
184 static void pnv_occ_realize(DeviceState
*dev
, Error
**errp
)
186 PnvOCC
*occ
= PNV_OCC(dev
);
187 PnvOCCClass
*poc
= PNV_OCC_GET_CLASS(occ
);
189 Error
*local_err
= NULL
;
193 obj
= object_property_get_link(OBJECT(dev
), "psi", &local_err
);
195 error_propagate(errp
, local_err
);
196 error_prepend(errp
, "required link 'psi' not found: ");
199 occ
->psi
= PNV_PSI(obj
);
201 /* XScom region for OCC registers */
202 pnv_xscom_region_init(&occ
->xscom_regs
, OBJECT(dev
), poc
->xscom_ops
,
203 occ
, "xscom-occ", poc
->xscom_size
);
206 static void pnv_occ_class_init(ObjectClass
*klass
, void *data
)
208 DeviceClass
*dc
= DEVICE_CLASS(klass
);
210 dc
->realize
= pnv_occ_realize
;
211 dc
->desc
= "PowerNV OCC Controller";
214 static const TypeInfo pnv_occ_type_info
= {
215 .name
= TYPE_PNV_OCC
,
216 .parent
= TYPE_DEVICE
,
217 .instance_size
= sizeof(PnvOCC
),
218 .class_init
= pnv_occ_class_init
,
219 .class_size
= sizeof(PnvOCCClass
),
223 static void pnv_occ_register_types(void)
225 type_register_static(&pnv_occ_type_info
);
226 type_register_static(&pnv_occ_power8_type_info
);
227 type_register_static(&pnv_occ_power9_type_info
);
230 type_init(pnv_occ_register_types
);