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"
20 #include "target/ppc/cpu.h"
21 #include "qapi/error.h"
23 #include "qemu/module.h"
25 #include "hw/ppc/pnv.h"
26 #include "hw/ppc/pnv_xscom.h"
27 #include "hw/ppc/pnv_occ.h"
29 #define OCB_OCI_OCCMISC 0x4020
30 #define OCB_OCI_OCCMISC_AND 0x4021
31 #define OCB_OCI_OCCMISC_OR 0x4022
33 static void pnv_occ_set_misc(PnvOCC
*occ
, uint64_t val
)
36 PnvOCCClass
*poc
= PNV_OCC_GET_CLASS(occ
);
38 val
&= 0xffff000000000000ull
;
41 irq_state
= !!(val
>> 63);
42 pnv_psi_irq_set(occ
->psi
, poc
->psi_irq
, irq_state
);
45 static uint64_t pnv_occ_power8_xscom_read(void *opaque
, hwaddr addr
,
48 PnvOCC
*occ
= PNV_OCC(opaque
);
49 uint32_t offset
= addr
>> 3;
57 qemu_log_mask(LOG_UNIMP
, "OCC Unimplemented register: Ox%"
58 HWADDR_PRIx
"\n", addr
>> 3);
63 static void pnv_occ_power8_xscom_write(void *opaque
, hwaddr addr
,
64 uint64_t val
, unsigned size
)
66 PnvOCC
*occ
= PNV_OCC(opaque
);
67 uint32_t offset
= addr
>> 3;
70 case OCB_OCI_OCCMISC_AND
:
71 pnv_occ_set_misc(occ
, occ
->occmisc
& val
);
73 case OCB_OCI_OCCMISC_OR
:
74 pnv_occ_set_misc(occ
, occ
->occmisc
| val
);
77 pnv_occ_set_misc(occ
, val
);
80 qemu_log_mask(LOG_UNIMP
, "OCC Unimplemented register: Ox%"
81 HWADDR_PRIx
"\n", addr
>> 3);
85 static const MemoryRegionOps pnv_occ_power8_xscom_ops
= {
86 .read
= pnv_occ_power8_xscom_read
,
87 .write
= pnv_occ_power8_xscom_write
,
88 .valid
.min_access_size
= 8,
89 .valid
.max_access_size
= 8,
90 .impl
.min_access_size
= 8,
91 .impl
.max_access_size
= 8,
92 .endianness
= DEVICE_BIG_ENDIAN
,
95 static void pnv_occ_power8_class_init(ObjectClass
*klass
, void *data
)
97 PnvOCCClass
*poc
= PNV_OCC_CLASS(klass
);
99 poc
->xscom_size
= PNV_XSCOM_OCC_SIZE
;
100 poc
->xscom_ops
= &pnv_occ_power8_xscom_ops
;
101 poc
->psi_irq
= PSIHB_IRQ_OCC
;
104 static const TypeInfo pnv_occ_power8_type_info
= {
105 .name
= TYPE_PNV8_OCC
,
106 .parent
= TYPE_PNV_OCC
,
107 .instance_size
= sizeof(PnvOCC
),
108 .class_init
= pnv_occ_power8_class_init
,
111 #define P9_OCB_OCI_OCCMISC 0x6080
112 #define P9_OCB_OCI_OCCMISC_CLEAR 0x6081
113 #define P9_OCB_OCI_OCCMISC_OR 0x6082
116 static uint64_t pnv_occ_power9_xscom_read(void *opaque
, hwaddr addr
,
119 PnvOCC
*occ
= PNV_OCC(opaque
);
120 uint32_t offset
= addr
>> 3;
124 case P9_OCB_OCI_OCCMISC
:
128 qemu_log_mask(LOG_UNIMP
, "OCC Unimplemented register: Ox%"
129 HWADDR_PRIx
"\n", addr
>> 3);
134 static void pnv_occ_power9_xscom_write(void *opaque
, hwaddr addr
,
135 uint64_t val
, unsigned size
)
137 PnvOCC
*occ
= PNV_OCC(opaque
);
138 uint32_t offset
= addr
>> 3;
141 case P9_OCB_OCI_OCCMISC_CLEAR
:
142 pnv_occ_set_misc(occ
, 0);
144 case P9_OCB_OCI_OCCMISC_OR
:
145 pnv_occ_set_misc(occ
, occ
->occmisc
| val
);
147 case P9_OCB_OCI_OCCMISC
:
148 pnv_occ_set_misc(occ
, val
);
151 qemu_log_mask(LOG_UNIMP
, "OCC Unimplemented register: Ox%"
152 HWADDR_PRIx
"\n", addr
>> 3);
156 static const MemoryRegionOps pnv_occ_power9_xscom_ops
= {
157 .read
= pnv_occ_power9_xscom_read
,
158 .write
= pnv_occ_power9_xscom_write
,
159 .valid
.min_access_size
= 8,
160 .valid
.max_access_size
= 8,
161 .impl
.min_access_size
= 8,
162 .impl
.max_access_size
= 8,
163 .endianness
= DEVICE_BIG_ENDIAN
,
166 static void pnv_occ_power9_class_init(ObjectClass
*klass
, void *data
)
168 PnvOCCClass
*poc
= PNV_OCC_CLASS(klass
);
170 poc
->xscom_size
= PNV9_XSCOM_OCC_SIZE
;
171 poc
->xscom_ops
= &pnv_occ_power9_xscom_ops
;
172 poc
->psi_irq
= PSIHB9_IRQ_OCC
;
175 static const TypeInfo pnv_occ_power9_type_info
= {
176 .name
= TYPE_PNV9_OCC
,
177 .parent
= TYPE_PNV_OCC
,
178 .instance_size
= sizeof(PnvOCC
),
179 .class_init
= pnv_occ_power9_class_init
,
182 static void pnv_occ_realize(DeviceState
*dev
, Error
**errp
)
184 PnvOCC
*occ
= PNV_OCC(dev
);
185 PnvOCCClass
*poc
= PNV_OCC_GET_CLASS(occ
);
187 Error
*local_err
= NULL
;
191 obj
= object_property_get_link(OBJECT(dev
), "psi", &local_err
);
193 error_propagate(errp
, local_err
);
194 error_prepend(errp
, "required link 'psi' not found: ");
197 occ
->psi
= PNV_PSI(obj
);
199 /* XScom region for OCC registers */
200 pnv_xscom_region_init(&occ
->xscom_regs
, OBJECT(dev
), poc
->xscom_ops
,
201 occ
, "xscom-occ", poc
->xscom_size
);
204 static void pnv_occ_class_init(ObjectClass
*klass
, void *data
)
206 DeviceClass
*dc
= DEVICE_CLASS(klass
);
208 dc
->realize
= pnv_occ_realize
;
209 dc
->desc
= "PowerNV OCC Controller";
212 static const TypeInfo pnv_occ_type_info
= {
213 .name
= TYPE_PNV_OCC
,
214 .parent
= TYPE_DEVICE
,
215 .instance_size
= sizeof(PnvOCC
),
216 .class_init
= pnv_occ_class_init
,
217 .class_size
= sizeof(PnvOCCClass
),
221 static void pnv_occ_register_types(void)
223 type_register_static(&pnv_occ_type_info
);
224 type_register_static(&pnv_occ_power8_type_info
);
225 type_register_static(&pnv_occ_power9_type_info
);
228 type_init(pnv_occ_register_types
);