]>
Commit | Line | Data |
---|---|---|
0722d05a BH |
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 "hw/hw.h" | |
21 | #include "sysemu/sysemu.h" | |
22 | #include "target/ppc/cpu.h" | |
23 | #include "qapi/error.h" | |
24 | #include "qemu/log.h" | |
25 | ||
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 | static void pnv_occ_set_misc(PnvOCC *occ, uint64_t val) | |
35 | { | |
36 | bool irq_state; | |
37 | ||
38 | val &= 0xffff000000000000ull; | |
39 | ||
40 | occ->occmisc = val; | |
41 | irq_state = !!(val >> 63); | |
42 | pnv_psi_irq_set(occ->psi, PSIHB_IRQ_OCC, irq_state); | |
43 | } | |
44 | ||
45 | static uint64_t pnv_occ_xscom_read(void *opaque, hwaddr addr, unsigned size) | |
46 | { | |
47 | PnvOCC *occ = PNV_OCC(opaque); | |
48 | uint32_t offset = addr >> 3; | |
49 | uint64_t val = 0; | |
50 | ||
51 | switch (offset) { | |
52 | case OCB_OCI_OCCMISC: | |
53 | val = occ->occmisc; | |
54 | break; | |
55 | default: | |
56 | qemu_log_mask(LOG_UNIMP, "OCC Unimplemented register: Ox%" | |
57 | HWADDR_PRIx "\n", addr); | |
58 | } | |
59 | return val; | |
60 | } | |
61 | ||
62 | static void pnv_occ_xscom_write(void *opaque, hwaddr addr, | |
63 | uint64_t val, unsigned size) | |
64 | { | |
65 | PnvOCC *occ = PNV_OCC(opaque); | |
66 | uint32_t offset = addr >> 3; | |
67 | ||
68 | switch (offset) { | |
69 | case OCB_OCI_OCCMISC_AND: | |
70 | pnv_occ_set_misc(occ, occ->occmisc & val); | |
71 | break; | |
72 | case OCB_OCI_OCCMISC_OR: | |
73 | pnv_occ_set_misc(occ, occ->occmisc | val); | |
74 | break; | |
75 | case OCB_OCI_OCCMISC: | |
76 | pnv_occ_set_misc(occ, val); | |
77 | break; | |
78 | default: | |
79 | qemu_log_mask(LOG_UNIMP, "OCC Unimplemented register: Ox%" | |
80 | HWADDR_PRIx "\n", addr); | |
81 | } | |
82 | } | |
83 | ||
84 | static const MemoryRegionOps pnv_occ_xscom_ops = { | |
85 | .read = pnv_occ_xscom_read, | |
86 | .write = pnv_occ_xscom_write, | |
87 | .valid.min_access_size = 8, | |
88 | .valid.max_access_size = 8, | |
89 | .impl.min_access_size = 8, | |
90 | .impl.max_access_size = 8, | |
91 | .endianness = DEVICE_BIG_ENDIAN, | |
92 | }; | |
93 | ||
94 | ||
95 | static void pnv_occ_realize(DeviceState *dev, Error **errp) | |
96 | { | |
97 | PnvOCC *occ = PNV_OCC(dev); | |
98 | Object *obj; | |
99 | Error *error = NULL; | |
100 | ||
101 | occ->occmisc = 0; | |
102 | ||
103 | /* get PSI object from chip */ | |
104 | obj = object_property_get_link(OBJECT(dev), "psi", &error); | |
105 | if (!obj) { | |
106 | error_setg(errp, "%s: required link 'psi' not found: %s", | |
107 | __func__, error_get_pretty(error)); | |
108 | return; | |
109 | } | |
110 | occ->psi = PNV_PSI(obj); | |
111 | ||
112 | /* XScom region for OCC registers */ | |
113 | pnv_xscom_region_init(&occ->xscom_regs, OBJECT(dev), &pnv_occ_xscom_ops, | |
114 | occ, "xscom-occ", PNV_XSCOM_OCC_SIZE); | |
115 | } | |
116 | ||
117 | static void pnv_occ_class_init(ObjectClass *klass, void *data) | |
118 | { | |
119 | DeviceClass *dc = DEVICE_CLASS(klass); | |
120 | ||
121 | dc->realize = pnv_occ_realize; | |
122 | } | |
123 | ||
124 | static const TypeInfo pnv_occ_type_info = { | |
125 | .name = TYPE_PNV_OCC, | |
126 | .parent = TYPE_DEVICE, | |
127 | .instance_size = sizeof(PnvOCC), | |
128 | .class_init = pnv_occ_class_init, | |
129 | }; | |
130 | ||
131 | static void pnv_occ_register_types(void) | |
132 | { | |
133 | type_register_static(&pnv_occ_type_info); | |
134 | } | |
135 | ||
136 | type_init(pnv_occ_register_types) |