]> git.proxmox.com Git - mirror_qemu.git/blob - hw/ppc/pnv_homer.c
hw/ppc/pnv_homer: add PowerNV homer device model
[mirror_qemu.git] / hw / ppc / pnv_homer.c
1 /*
2 * QEMU PowerPC PowerNV Emulation of a few HOMER related registers
3 *
4 * Copyright (c) 2019, 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 "qapi/error.h"
21 #include "exec/hwaddr.h"
22 #include "exec/memory.h"
23 #include "sysemu/cpus.h"
24 #include "hw/qdev-core.h"
25 #include "hw/ppc/pnv.h"
26 #include "hw/ppc/pnv_homer.h"
27
28
29 static bool core_max_array(PnvHomer *homer, hwaddr addr)
30 {
31 int i;
32 PnvHomerClass *hmrc = PNV_HOMER_GET_CLASS(homer);
33
34 for (i = 0; i <= homer->chip->nr_cores; i++) {
35 if (addr == (hmrc->core_max_base + i)) {
36 return true;
37 }
38 }
39 return false;
40 }
41
42 /* P8 Pstate table */
43
44 #define PNV8_OCC_PSTATE_VERSION 0x1f8001
45 #define PNV8_OCC_PSTATE_MIN 0x1f8003
46 #define PNV8_OCC_PSTATE_VALID 0x1f8000
47 #define PNV8_OCC_PSTATE_THROTTLE 0x1f8002
48 #define PNV8_OCC_PSTATE_NOM 0x1f8004
49 #define PNV8_OCC_PSTATE_TURBO 0x1f8005
50 #define PNV8_OCC_PSTATE_ULTRA_TURBO 0x1f8006
51 #define PNV8_OCC_PSTATE_DATA 0x1f8008
52 #define PNV8_OCC_PSTATE_ID_ZERO 0x1f8010
53 #define PNV8_OCC_PSTATE_ID_ONE 0x1f8018
54 #define PNV8_OCC_PSTATE_ID_TWO 0x1f8020
55 #define PNV8_OCC_VDD_VOLTAGE_IDENTIFIER 0x1f8012
56 #define PNV8_OCC_VCS_VOLTAGE_IDENTIFIER 0x1f8013
57 #define PNV8_OCC_PSTATE_ZERO_FREQUENCY 0x1f8014
58 #define PNV8_OCC_PSTATE_ONE_FREQUENCY 0x1f801c
59 #define PNV8_OCC_PSTATE_TWO_FREQUENCY 0x1f8024
60 #define PNV8_CORE_MAX_BASE 0x1f8810
61
62
63 static uint64_t pnv_power8_homer_read(void *opaque, hwaddr addr,
64 unsigned size)
65 {
66 PnvHomer *homer = PNV_HOMER(opaque);
67
68 switch (addr) {
69 case PNV8_OCC_PSTATE_VERSION:
70 case PNV8_OCC_PSTATE_MIN:
71 case PNV8_OCC_PSTATE_ID_ZERO:
72 return 0;
73 case PNV8_OCC_PSTATE_VALID:
74 case PNV8_OCC_PSTATE_THROTTLE:
75 case PNV8_OCC_PSTATE_NOM:
76 case PNV8_OCC_PSTATE_TURBO:
77 case PNV8_OCC_PSTATE_ID_ONE:
78 case PNV8_OCC_VDD_VOLTAGE_IDENTIFIER:
79 case PNV8_OCC_VCS_VOLTAGE_IDENTIFIER:
80 return 1;
81 case PNV8_OCC_PSTATE_ULTRA_TURBO:
82 case PNV8_OCC_PSTATE_ID_TWO:
83 return 2;
84 case PNV8_OCC_PSTATE_DATA:
85 return 0x1000000000000000;
86 /* P8 frequency for 0, 1, and 2 pstates */
87 case PNV8_OCC_PSTATE_ZERO_FREQUENCY:
88 case PNV8_OCC_PSTATE_ONE_FREQUENCY:
89 case PNV8_OCC_PSTATE_TWO_FREQUENCY:
90 return 3000;
91 }
92 /* pstate table core max array */
93 if (core_max_array(homer, addr)) {
94 return 1;
95 }
96 return 0;
97 }
98
99 static void pnv_power8_homer_write(void *opaque, hwaddr addr,
100 uint64_t val, unsigned size)
101 {
102 /* callback function defined to homer write */
103 return;
104 }
105
106 static const MemoryRegionOps pnv_power8_homer_ops = {
107 .read = pnv_power8_homer_read,
108 .write = pnv_power8_homer_write,
109 .valid.min_access_size = 1,
110 .valid.max_access_size = 8,
111 .impl.min_access_size = 1,
112 .impl.max_access_size = 8,
113 .endianness = DEVICE_BIG_ENDIAN,
114 };
115
116 static void pnv_homer_power8_class_init(ObjectClass *klass, void *data)
117 {
118 PnvHomerClass *homer = PNV_HOMER_CLASS(klass);
119
120 homer->homer_size = PNV_HOMER_SIZE;
121 homer->homer_ops = &pnv_power8_homer_ops;
122 homer->core_max_base = PNV8_CORE_MAX_BASE;
123 }
124
125 static const TypeInfo pnv_homer_power8_type_info = {
126 .name = TYPE_PNV8_HOMER,
127 .parent = TYPE_PNV_HOMER,
128 .instance_size = sizeof(PnvHomer),
129 .class_init = pnv_homer_power8_class_init,
130 };
131
132 /* P9 Pstate table */
133
134 #define PNV9_OCC_PSTATE_ID_ZERO 0xe2018
135 #define PNV9_OCC_PSTATE_ID_ONE 0xe2020
136 #define PNV9_OCC_PSTATE_ID_TWO 0xe2028
137 #define PNV9_OCC_PSTATE_DATA 0xe2000
138 #define PNV9_OCC_PSTATE_DATA_AREA 0xe2008
139 #define PNV9_OCC_PSTATE_MIN 0xe2003
140 #define PNV9_OCC_PSTATE_NOM 0xe2004
141 #define PNV9_OCC_PSTATE_TURBO 0xe2005
142 #define PNV9_OCC_PSTATE_ULTRA_TURBO 0xe2818
143 #define PNV9_OCC_MAX_PSTATE_ULTRA_TURBO 0xe2006
144 #define PNV9_OCC_PSTATE_MAJOR_VERSION 0xe2001
145 #define PNV9_OCC_OPAL_RUNTIME_DATA 0xe2b85
146 #define PNV9_CHIP_HOMER_IMAGE_POINTER 0x200008
147 #define PNV9_CHIP_HOMER_BASE 0x0
148 #define PNV9_OCC_PSTATE_ZERO_FREQUENCY 0xe201c
149 #define PNV9_OCC_PSTATE_ONE_FREQUENCY 0xe2024
150 #define PNV9_OCC_PSTATE_TWO_FREQUENCY 0xe202c
151 #define PNV9_OCC_ROLE_MASTER_OR_SLAVE 0xe2002
152 #define PNV9_CORE_MAX_BASE 0xe2819
153
154
155 static uint64_t pnv_power9_homer_read(void *opaque, hwaddr addr,
156 unsigned size)
157 {
158 PnvHomer *homer = PNV_HOMER(opaque);
159
160 switch (addr) {
161 case PNV9_OCC_MAX_PSTATE_ULTRA_TURBO:
162 case PNV9_OCC_PSTATE_ID_ZERO:
163 return 0;
164 case PNV9_OCC_PSTATE_DATA:
165 case PNV9_OCC_ROLE_MASTER_OR_SLAVE:
166 case PNV9_OCC_PSTATE_NOM:
167 case PNV9_OCC_PSTATE_TURBO:
168 case PNV9_OCC_PSTATE_ID_ONE:
169 case PNV9_OCC_PSTATE_ULTRA_TURBO:
170 case PNV9_OCC_OPAL_RUNTIME_DATA:
171 return 1;
172 case PNV9_OCC_PSTATE_MIN:
173 case PNV9_OCC_PSTATE_ID_TWO:
174 return 2;
175
176 /* 3000 khz frequency for 0, 1, and 2 pstates */
177 case PNV9_OCC_PSTATE_ZERO_FREQUENCY:
178 case PNV9_OCC_PSTATE_ONE_FREQUENCY:
179 case PNV9_OCC_PSTATE_TWO_FREQUENCY:
180 return 3000;
181 case PNV9_OCC_PSTATE_MAJOR_VERSION:
182 return 0x90;
183 case PNV9_CHIP_HOMER_BASE:
184 case PNV9_OCC_PSTATE_DATA_AREA:
185 case PNV9_CHIP_HOMER_IMAGE_POINTER:
186 return 0x1000000000000000;
187 }
188 /* pstate table core max array */
189 if (core_max_array(homer, addr)) {
190 return 1;
191 }
192 return 0;
193 }
194
195 static void pnv_power9_homer_write(void *opaque, hwaddr addr,
196 uint64_t val, unsigned size)
197 {
198 /* callback function defined to homer write */
199 return;
200 }
201
202 static const MemoryRegionOps pnv_power9_homer_ops = {
203 .read = pnv_power9_homer_read,
204 .write = pnv_power9_homer_write,
205 .valid.min_access_size = 1,
206 .valid.max_access_size = 8,
207 .impl.min_access_size = 1,
208 .impl.max_access_size = 8,
209 .endianness = DEVICE_BIG_ENDIAN,
210 };
211
212 static void pnv_homer_power9_class_init(ObjectClass *klass, void *data)
213 {
214 PnvHomerClass *homer = PNV_HOMER_CLASS(klass);
215
216 homer->homer_size = PNV9_HOMER_SIZE;
217 homer->homer_ops = &pnv_power9_homer_ops;
218 homer->core_max_base = PNV9_CORE_MAX_BASE;
219 }
220
221 static const TypeInfo pnv_homer_power9_type_info = {
222 .name = TYPE_PNV9_HOMER,
223 .parent = TYPE_PNV_HOMER,
224 .instance_size = sizeof(PnvHomer),
225 .class_init = pnv_homer_power9_class_init,
226 };
227
228 static void pnv_homer_realize(DeviceState *dev, Error **errp)
229 {
230 PnvHomer *homer = PNV_HOMER(dev);
231 PnvHomerClass *hmrc = PNV_HOMER_GET_CLASS(homer);
232 Object *obj;
233 Error *local_err = NULL;
234
235 obj = object_property_get_link(OBJECT(dev), "chip", &local_err);
236 if (!obj) {
237 error_propagate(errp, local_err);
238 error_prepend(errp, "required link 'chip' not found: ");
239 return;
240 }
241 homer->chip = PNV_CHIP(obj);
242 /* homer region */
243 memory_region_init_io(&homer->regs, OBJECT(dev),
244 hmrc->homer_ops, homer, "homer-main-memory",
245 hmrc->homer_size);
246 }
247
248 static void pnv_homer_class_init(ObjectClass *klass, void *data)
249 {
250 DeviceClass *dc = DEVICE_CLASS(klass);
251
252 dc->realize = pnv_homer_realize;
253 dc->desc = "PowerNV HOMER Memory";
254 }
255
256 static const TypeInfo pnv_homer_type_info = {
257 .name = TYPE_PNV_HOMER,
258 .parent = TYPE_DEVICE,
259 .instance_size = sizeof(PnvHomer),
260 .class_init = pnv_homer_class_init,
261 .class_size = sizeof(PnvHomerClass),
262 .abstract = true,
263 };
264
265 static void pnv_homer_register_types(void)
266 {
267 type_register_static(&pnv_homer_type_info);
268 type_register_static(&pnv_homer_power8_type_info);
269 type_register_static(&pnv_homer_power9_type_info);
270 }
271
272 type_init(pnv_homer_register_types);