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 "qemu/log.h"
21 #include "qapi/error.h"
22 #include "exec/hwaddr.h"
23 #include "system/memory.h"
24 #include "system/cpus.h"
25 #include "hw/qdev-core.h"
26 #include "hw/qdev-properties.h"
27 #include "hw/ppc/pnv.h"
28 #include "hw/ppc/pnv_chip.h"
29 #include "hw/ppc/pnv_homer.h"
30 #include "hw/ppc/pnv_xscom.h"
31
32 /* P8 PBA BARs */
33 #define PBA_BAR0 0x00
34 #define PBA_BAR1 0x01
35 #define PBA_BAR2 0x02
36 #define PBA_BAR3 0x03
37 #define PBA_BARMASK0 0x04
38 #define PBA_BARMASK1 0x05
39 #define PBA_BARMASK2 0x06
40 #define PBA_BARMASK3 0x07
41
pnv_homer_power8_pba_read(void * opaque,hwaddr addr,unsigned size)42 static uint64_t pnv_homer_power8_pba_read(void *opaque, hwaddr addr,
43 unsigned size)
44 {
45 PnvHomer *homer = PNV_HOMER(opaque);
46 PnvHomerClass *hmrc = PNV_HOMER_GET_CLASS(homer);
47 uint32_t reg = addr >> 3;
48 uint64_t val = 0;
49
50 switch (reg) {
51 case PBA_BAR0:
52 val = homer->base;
53 break;
54 case PBA_BARMASK0: /* P8 homer region mask */
55 val = (hmrc->size - 1) & 0x300000;
56 break;
57 case PBA_BAR3: /* P8 occ common area */
58 val = PNV_OCC_COMMON_AREA_BASE;
59 break;
60 case PBA_BARMASK3: /* P8 occ common area mask */
61 val = (PNV_OCC_COMMON_AREA_SIZE - 1) & 0x700000;
62 break;
63 default:
64 qemu_log_mask(LOG_UNIMP, "PBA: read to unimplemented register: Ox%"
65 HWADDR_PRIx "\n", addr >> 3);
66 }
67 return val;
68 }
69
pnv_homer_power8_pba_write(void * opaque,hwaddr addr,uint64_t val,unsigned size)70 static void pnv_homer_power8_pba_write(void *opaque, hwaddr addr,
71 uint64_t val, unsigned size)
72 {
73 qemu_log_mask(LOG_UNIMP, "PBA: write to unimplemented register: Ox%"
74 HWADDR_PRIx "\n", addr >> 3);
75 }
76
77 static const MemoryRegionOps pnv_homer_power8_pba_ops = {
78 .read = pnv_homer_power8_pba_read,
79 .write = pnv_homer_power8_pba_write,
80 .valid.min_access_size = 8,
81 .valid.max_access_size = 8,
82 .impl.min_access_size = 8,
83 .impl.max_access_size = 8,
84 .endianness = DEVICE_BIG_ENDIAN,
85 };
86
pnv_homer_power8_get_base(PnvChip * chip)87 static hwaddr pnv_homer_power8_get_base(PnvChip *chip)
88 {
89 return PNV_HOMER_BASE(chip);
90 }
91
pnv_homer_power8_class_init(ObjectClass * klass,const void * data)92 static void pnv_homer_power8_class_init(ObjectClass *klass, const void *data)
93 {
94 PnvHomerClass *homer = PNV_HOMER_CLASS(klass);
95
96 homer->get_base = pnv_homer_power8_get_base;
97 homer->size = PNV_HOMER_SIZE;
98 homer->pba_size = PNV_XSCOM_PBA_SIZE;
99 homer->pba_ops = &pnv_homer_power8_pba_ops;
100 }
101
102 static const TypeInfo pnv_homer_power8_type_info = {
103 .name = TYPE_PNV8_HOMER,
104 .parent = TYPE_PNV_HOMER,
105 .instance_size = sizeof(PnvHomer),
106 .class_init = pnv_homer_power8_class_init,
107 };
108
pnv_homer_power9_pba_read(void * opaque,hwaddr addr,unsigned size)109 static uint64_t pnv_homer_power9_pba_read(void *opaque, hwaddr addr,
110 unsigned size)
111 {
112 PnvHomer *homer = PNV_HOMER(opaque);
113 PnvHomerClass *hmrc = PNV_HOMER_GET_CLASS(homer);
114 uint32_t reg = addr >> 3;
115 uint64_t val = 0;
116
117 switch (reg) {
118 case PBA_BAR0:
119 val = homer->base;
120 break;
121 case PBA_BARMASK0: /* P9 homer region mask */
122 val = (hmrc->size - 1) & 0x300000;
123 break;
124 case PBA_BAR2: /* P9 occ common area */
125 val = PNV9_OCC_COMMON_AREA_BASE;
126 break;
127 case PBA_BARMASK2: /* P9 occ common area size */
128 val = (PNV9_OCC_COMMON_AREA_SIZE - 1) & 0x700000;
129 break;
130 default:
131 qemu_log_mask(LOG_UNIMP, "PBA: read to unimplemented register: Ox%"
132 HWADDR_PRIx "\n", addr >> 3);
133 }
134 return val;
135 }
136
pnv_homer_power9_pba_write(void * opaque,hwaddr addr,uint64_t val,unsigned size)137 static void pnv_homer_power9_pba_write(void *opaque, hwaddr addr,
138 uint64_t val, unsigned size)
139 {
140 qemu_log_mask(LOG_UNIMP, "PBA: write to unimplemented register: Ox%"
141 HWADDR_PRIx "\n", addr >> 3);
142 }
143
144 static const MemoryRegionOps pnv_homer_power9_pba_ops = {
145 .read = pnv_homer_power9_pba_read,
146 .write = pnv_homer_power9_pba_write,
147 .valid.min_access_size = 8,
148 .valid.max_access_size = 8,
149 .impl.min_access_size = 8,
150 .impl.max_access_size = 8,
151 .endianness = DEVICE_BIG_ENDIAN,
152 };
153
pnv_homer_power9_get_base(PnvChip * chip)154 static hwaddr pnv_homer_power9_get_base(PnvChip *chip)
155 {
156 return PNV9_HOMER_BASE(chip);
157 }
158
pnv_homer_power9_class_init(ObjectClass * klass,const void * data)159 static void pnv_homer_power9_class_init(ObjectClass *klass, const void *data)
160 {
161 PnvHomerClass *homer = PNV_HOMER_CLASS(klass);
162
163 homer->get_base = pnv_homer_power9_get_base;
164 homer->size = PNV_HOMER_SIZE;
165 homer->pba_size = PNV9_XSCOM_PBA_SIZE;
166 homer->pba_ops = &pnv_homer_power9_pba_ops;
167 }
168
169 static const TypeInfo pnv_homer_power9_type_info = {
170 .name = TYPE_PNV9_HOMER,
171 .parent = TYPE_PNV_HOMER,
172 .instance_size = sizeof(PnvHomer),
173 .class_init = pnv_homer_power9_class_init,
174 };
175
pnv_homer_power10_pba_read(void * opaque,hwaddr addr,unsigned size)176 static uint64_t pnv_homer_power10_pba_read(void *opaque, hwaddr addr,
177 unsigned size)
178 {
179 PnvHomer *homer = PNV_HOMER(opaque);
180 PnvHomerClass *hmrc = PNV_HOMER_GET_CLASS(homer);
181 uint32_t reg = addr >> 3;
182 uint64_t val = 0;
183
184 switch (reg) {
185 case PBA_BAR0:
186 val = homer->base;
187 break;
188 case PBA_BARMASK0: /* P10 homer region mask */
189 val = (hmrc->size - 1) & 0x300000;
190 break;
191 case PBA_BAR2: /* P10 occ common area */
192 val = PNV10_OCC_COMMON_AREA_BASE;
193 break;
194 case PBA_BARMASK2: /* P10 occ common area size */
195 val = (PNV10_OCC_COMMON_AREA_SIZE - 1) & 0x700000;
196 break;
197 default:
198 qemu_log_mask(LOG_UNIMP, "PBA: read to unimplemented register: Ox%"
199 HWADDR_PRIx "\n", addr >> 3);
200 }
201 return val;
202 }
203
pnv_homer_power10_pba_write(void * opaque,hwaddr addr,uint64_t val,unsigned size)204 static void pnv_homer_power10_pba_write(void *opaque, hwaddr addr,
205 uint64_t val, unsigned size)
206 {
207 qemu_log_mask(LOG_UNIMP, "PBA: write to unimplemented register: Ox%"
208 HWADDR_PRIx "\n", addr >> 3);
209 }
210
211 static const MemoryRegionOps pnv_homer_power10_pba_ops = {
212 .read = pnv_homer_power10_pba_read,
213 .write = pnv_homer_power10_pba_write,
214 .valid.min_access_size = 8,
215 .valid.max_access_size = 8,
216 .impl.min_access_size = 8,
217 .impl.max_access_size = 8,
218 .endianness = DEVICE_BIG_ENDIAN,
219 };
220
pnv_homer_power10_get_base(PnvChip * chip)221 static hwaddr pnv_homer_power10_get_base(PnvChip *chip)
222 {
223 return PNV10_HOMER_BASE(chip);
224 }
225
pnv_homer_power10_class_init(ObjectClass * klass,const void * data)226 static void pnv_homer_power10_class_init(ObjectClass *klass, const void *data)
227 {
228 PnvHomerClass *homer = PNV_HOMER_CLASS(klass);
229
230 homer->get_base = pnv_homer_power10_get_base;
231 homer->size = PNV_HOMER_SIZE;
232 homer->pba_size = PNV10_XSCOM_PBA_SIZE;
233 homer->pba_ops = &pnv_homer_power10_pba_ops;
234 }
235
236 static const TypeInfo pnv_homer_power10_type_info = {
237 .name = TYPE_PNV10_HOMER,
238 .parent = TYPE_PNV_HOMER,
239 .instance_size = sizeof(PnvHomer),
240 .class_init = pnv_homer_power10_class_init,
241 };
242
pnv_homer_realize(DeviceState * dev,Error ** errp)243 static void pnv_homer_realize(DeviceState *dev, Error **errp)
244 {
245 PnvHomer *homer = PNV_HOMER(dev);
246 PnvHomerClass *hmrc = PNV_HOMER_GET_CLASS(homer);
247 char homer_str[32];
248
249 assert(homer->chip);
250
251 pnv_xscom_region_init(&homer->pba_regs, OBJECT(dev), hmrc->pba_ops,
252 homer, "xscom-pba", hmrc->pba_size);
253
254 /* Homer RAM region */
255 homer->base = hmrc->get_base(homer->chip);
256
257 snprintf(homer_str, sizeof(homer_str), "homer-chip%d-memory",
258 homer->chip->chip_id);
259 if (!memory_region_init_ram(&homer->mem, OBJECT(homer),
260 homer_str, hmrc->size, errp)) {
261 return;
262 }
263 }
264
265 static const Property pnv_homer_properties[] = {
266 DEFINE_PROP_LINK("chip", PnvHomer, chip, TYPE_PNV_CHIP, PnvChip *),
267 };
268
pnv_homer_class_init(ObjectClass * klass,const void * data)269 static void pnv_homer_class_init(ObjectClass *klass, const void *data)
270 {
271 DeviceClass *dc = DEVICE_CLASS(klass);
272
273 dc->realize = pnv_homer_realize;
274 dc->desc = "PowerNV HOMER Memory";
275 device_class_set_props(dc, pnv_homer_properties);
276 dc->user_creatable = false;
277 }
278
279 static const TypeInfo pnv_homer_type_info = {
280 .name = TYPE_PNV_HOMER,
281 .parent = TYPE_DEVICE,
282 .instance_size = sizeof(PnvHomer),
283 .class_init = pnv_homer_class_init,
284 .class_size = sizeof(PnvHomerClass),
285 .abstract = true,
286 };
287
pnv_homer_register_types(void)288 static void pnv_homer_register_types(void)
289 {
290 type_register_static(&pnv_homer_type_info);
291 type_register_static(&pnv_homer_power8_type_info);
292 type_register_static(&pnv_homer_power9_type_info);
293 type_register_static(&pnv_homer_power10_type_info);
294 }
295
296 type_init(pnv_homer_register_types);
297