xref: /openbmc/qemu/hw/ppc/pnv_core.c (revision dfad8421af474a38e272cdb19ae3c8e778acf820)
1  /*
2   * QEMU PowerPC PowerNV CPU Core model
3   *
4   * Copyright (c) 2016, IBM Corporation.
5   *
6   * This library is free software; you can redistribute it and/or
7   * modify it under the terms of the GNU Lesser General Public License
8   * as published by the Free Software Foundation; either version 2.1 of
9   * the License, or (at your option) any later version.
10   *
11   * This library is distributed in the hope that it will be useful, but
12   * WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14   * Lesser General Public License for more details.
15   *
16   * You should have received a copy of the GNU Lesser General Public
17   * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18   */
19  
20  #include "qemu/osdep.h"
21  #include "sysemu/reset.h"
22  #include "qapi/error.h"
23  #include "qemu/log.h"
24  #include "qemu/module.h"
25  #include "target/ppc/cpu.h"
26  #include "hw/ppc/ppc.h"
27  #include "hw/ppc/pnv.h"
28  #include "hw/ppc/pnv_chip.h"
29  #include "hw/ppc/pnv_core.h"
30  #include "hw/ppc/pnv_xscom.h"
31  #include "hw/ppc/xics.h"
32  #include "hw/qdev-properties.h"
33  #include "helper_regs.h"
34  
35  static const char *pnv_core_cpu_typename(PnvCore *pc)
36  {
37      const char *core_type = object_class_get_name(object_get_class(OBJECT(pc)));
38      int len = strlen(core_type) - strlen(PNV_CORE_TYPE_SUFFIX);
39      char *s = g_strdup_printf(POWERPC_CPU_TYPE_NAME("%.*s"), len, core_type);
40      const char *cpu_type = object_class_get_name(object_class_by_name(s));
41      g_free(s);
42      return cpu_type;
43  }
44  
45  static void pnv_core_cpu_reset(PnvCore *pc, PowerPCCPU *cpu)
46  {
47      CPUState *cs = CPU(cpu);
48      CPUPPCState *env = &cpu->env;
49      PnvChipClass *pcc = PNV_CHIP_GET_CLASS(pc->chip);
50  
51      cpu_reset(cs);
52  
53      /*
54       * the skiboot firmware elects a primary thread to initialize the
55       * system and it can be any.
56       */
57      env->gpr[3] = PNV_FDT_ADDR;
58      env->nip = 0x10;
59      env->msr |= MSR_HVB; /* Hypervisor mode */
60      env->spr[SPR_HRMOR] = pc->hrmor;
61      if (pc->big_core) {
62          /* Clear "small core" bit on Power9/10 (this is set in default PVR) */
63          env->spr[SPR_PVR] &= ~PPC_BIT(51);
64      }
65      hreg_compute_hflags(env);
66      ppc_maybe_interrupt(env);
67  
68      cpu_ppc_tb_reset(env);
69  
70      pcc->intc_reset(pc->chip, cpu);
71  }
72  
73  /*
74   * These values are read by the PowerNV HW monitors under Linux
75   */
76  #define PNV_XSCOM_EX_DTS_RESULT0     0x50000
77  #define PNV_XSCOM_EX_DTS_RESULT1     0x50001
78  
79  static uint64_t pnv_core_power8_xscom_read(void *opaque, hwaddr addr,
80                                             unsigned int width)
81  {
82      uint32_t offset = addr >> 3;
83      uint64_t val = 0;
84  
85      /* The result should be 38 C */
86      switch (offset) {
87      case PNV_XSCOM_EX_DTS_RESULT0:
88          val = 0x26f024f023f0000ull;
89          break;
90      case PNV_XSCOM_EX_DTS_RESULT1:
91          val = 0x24f000000000000ull;
92          break;
93      default:
94          qemu_log_mask(LOG_UNIMP, "%s: unimp read 0x%08x\n", __func__,
95                        offset);
96      }
97  
98      return val;
99  }
100  
101  static void pnv_core_power8_xscom_write(void *opaque, hwaddr addr, uint64_t val,
102                                          unsigned int width)
103  {
104      uint32_t offset = addr >> 3;
105  
106      qemu_log_mask(LOG_UNIMP, "%s: unimp write 0x%08x\n", __func__,
107                    offset);
108  }
109  
110  static const MemoryRegionOps pnv_core_power8_xscom_ops = {
111      .read = pnv_core_power8_xscom_read,
112      .write = pnv_core_power8_xscom_write,
113      .valid.min_access_size = 8,
114      .valid.max_access_size = 8,
115      .impl.min_access_size = 8,
116      .impl.max_access_size = 8,
117      .endianness = DEVICE_BIG_ENDIAN,
118  };
119  
120  
121  /*
122   * POWER9 core controls
123   */
124  #define PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_HYP 0xf010d
125  #define PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_OTR 0xf010a
126  
127  #define PNV9_XSCOM_EC_CORE_THREAD_STATE    0x10ab3
128  
129  static uint64_t pnv_core_power9_xscom_read(void *opaque, hwaddr addr,
130                                             unsigned int width)
131  {
132      uint32_t offset = addr >> 3;
133      uint64_t val = 0;
134  
135      /* The result should be 38 C */
136      switch (offset) {
137      case PNV_XSCOM_EX_DTS_RESULT0:
138          val = 0x26f024f023f0000ull;
139          break;
140      case PNV_XSCOM_EX_DTS_RESULT1:
141          val = 0x24f000000000000ull;
142          break;
143      case PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_HYP:
144      case PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_OTR:
145          val = 0x0;
146          break;
147      case PNV9_XSCOM_EC_CORE_THREAD_STATE:
148          val = 0;
149          break;
150      default:
151          qemu_log_mask(LOG_UNIMP, "%s: unimp read 0x%08x\n", __func__,
152                        offset);
153      }
154  
155      return val;
156  }
157  
158  static void pnv_core_power9_xscom_write(void *opaque, hwaddr addr, uint64_t val,
159                                          unsigned int width)
160  {
161      uint32_t offset = addr >> 3;
162  
163      switch (offset) {
164      case PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_HYP:
165      case PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_OTR:
166          break;
167      default:
168          qemu_log_mask(LOG_UNIMP, "%s: unimp write 0x%08x\n", __func__,
169                        offset);
170      }
171  }
172  
173  static const MemoryRegionOps pnv_core_power9_xscom_ops = {
174      .read = pnv_core_power9_xscom_read,
175      .write = pnv_core_power9_xscom_write,
176      .valid.min_access_size = 8,
177      .valid.max_access_size = 8,
178      .impl.min_access_size = 8,
179      .impl.max_access_size = 8,
180      .endianness = DEVICE_BIG_ENDIAN,
181  };
182  
183  /*
184   * POWER10 core controls
185   */
186  
187  #define PNV10_XSCOM_EC_CORE_THREAD_STATE    0x412
188  #define PNV10_XSCOM_EC_CORE_THREAD_INFO     0x413
189  #define PNV10_XSCOM_EC_CORE_DIRECT_CONTROLS 0x449
190  #define PNV10_XSCOM_EC_CORE_RAS_STATUS      0x454
191  
192  static uint64_t pnv_core_power10_xscom_read(void *opaque, hwaddr addr,
193                                             unsigned int width)
194  {
195      PnvCore *pc = PNV_CORE(opaque);
196      int nr_threads = CPU_CORE(pc)->nr_threads;
197      int i;
198      uint32_t offset = addr >> 3;
199      uint64_t val = 0;
200  
201      switch (offset) {
202      case PNV10_XSCOM_EC_CORE_THREAD_STATE:
203          for (i = 0; i < nr_threads; i++) {
204              PowerPCCPU *cpu = pc->threads[i];
205              CPUState *cs = CPU(cpu);
206  
207              if (cs->halted) {
208                  val |= PPC_BIT(56 + i);
209              }
210          }
211          if (pc->lpar_per_core) {
212              val |= PPC_BIT(62);
213          }
214          break;
215      case PNV10_XSCOM_EC_CORE_THREAD_INFO:
216          break;
217      case PNV10_XSCOM_EC_CORE_RAS_STATUS:
218          for (i = 0; i < nr_threads; i++) {
219              PowerPCCPU *cpu = pc->threads[i];
220              CPUState *cs = CPU(cpu);
221              if (cs->stopped) {
222                  val |= PPC_BIT(0 + 8 * i) | PPC_BIT(1 + 8 * i);
223              }
224          }
225          break;
226      default:
227          qemu_log_mask(LOG_UNIMP, "%s: unimp read 0x%08x\n", __func__,
228                        offset);
229      }
230  
231      return val;
232  }
233  
234  static void pnv_core_power10_xscom_write(void *opaque, hwaddr addr,
235                                           uint64_t val, unsigned int width)
236  {
237      PnvCore *pc = PNV_CORE(opaque);
238      int nr_threads = CPU_CORE(pc)->nr_threads;
239      int i;
240      uint32_t offset = addr >> 3;
241  
242      switch (offset) {
243      case PNV10_XSCOM_EC_CORE_DIRECT_CONTROLS:
244          for (i = 0; i < nr_threads; i++) {
245              PowerPCCPU *cpu = pc->threads[i];
246              CPUState *cs = CPU(cpu);
247  
248              if (val & PPC_BIT(7 + 8 * i)) { /* stop */
249                  val &= ~PPC_BIT(7 + 8 * i);
250                  cpu_pause(cs);
251              }
252              if (val & PPC_BIT(6 + 8 * i)) { /* start */
253                  val &= ~PPC_BIT(6 + 8 * i);
254                  cpu_resume(cs);
255              }
256              if (val & PPC_BIT(4 + 8 * i)) { /* sreset */
257                  val &= ~PPC_BIT(4 + 8 * i);
258                  pnv_cpu_do_nmi_resume(cs);
259              }
260              if (val & PPC_BIT(3 + 8 * i)) { /* clear maint */
261                  /*
262                   * Hardware has very particular cases for where clear maint
263                   * must be used and where start must be used to resume a
264                   * thread. These are not modelled exactly, just treat
265                   * this and start the same.
266                   */
267                  val &= ~PPC_BIT(3 + 8 * i);
268                  cpu_resume(cs);
269              }
270          }
271          if (val) {
272              qemu_log_mask(LOG_UNIMP, "%s: unimp bits in DIRECT_CONTROLS "
273                                       "0x%016" PRIx64 "\n", __func__, val);
274          }
275          break;
276  
277      default:
278          qemu_log_mask(LOG_UNIMP, "%s: unimp write 0x%08x\n", __func__,
279                        offset);
280      }
281  }
282  
283  static const MemoryRegionOps pnv_core_power10_xscom_ops = {
284      .read = pnv_core_power10_xscom_read,
285      .write = pnv_core_power10_xscom_write,
286      .valid.min_access_size = 8,
287      .valid.max_access_size = 8,
288      .impl.min_access_size = 8,
289      .impl.max_access_size = 8,
290      .endianness = DEVICE_BIG_ENDIAN,
291  };
292  
293  static void pnv_core_cpu_realize(PnvCore *pc, PowerPCCPU *cpu, Error **errp,
294                                   int thread_index)
295  {
296      CPUPPCState *env = &cpu->env;
297      int core_hwid;
298      ppc_spr_t *pir_spr = &env->spr_cb[SPR_PIR];
299      ppc_spr_t *tir_spr = &env->spr_cb[SPR_TIR];
300      uint32_t pir, tir;
301      Error *local_err = NULL;
302      PnvChipClass *pcc = PNV_CHIP_GET_CLASS(pc->chip);
303  
304      if (!qdev_realize(DEVICE(cpu), NULL, errp)) {
305          return;
306      }
307  
308      pcc->intc_create(pc->chip, cpu, &local_err);
309      if (local_err) {
310          error_propagate(errp, local_err);
311          return;
312      }
313  
314      core_hwid = object_property_get_uint(OBJECT(pc), "hwid", &error_abort);
315  
316      pcc->get_pir_tir(pc->chip, core_hwid, thread_index, &pir, &tir);
317      pir_spr->default_value = pir;
318      tir_spr->default_value = tir;
319  
320      if (pc->big_core) {
321          /* 2 "small cores" get the same core index for SMT operations */
322          env->core_index = core_hwid >> 1;
323      } else {
324          env->core_index = core_hwid;
325      }
326  
327      if (pc->lpar_per_core) {
328          cpu_ppc_set_1lpar(cpu);
329      }
330  
331      /* Set time-base frequency to 512 MHz */
332      cpu_ppc_tb_init(env, PNV_TIMEBASE_FREQ);
333  }
334  
335  static void pnv_core_reset(void *dev)
336  {
337      CPUCore *cc = CPU_CORE(dev);
338      PnvCore *pc = PNV_CORE(dev);
339      int i;
340  
341      for (i = 0; i < cc->nr_threads; i++) {
342          pnv_core_cpu_reset(pc, pc->threads[i]);
343      }
344  }
345  
346  static void pnv_core_realize(DeviceState *dev, Error **errp)
347  {
348      PnvCore *pc = PNV_CORE(OBJECT(dev));
349      PnvCoreClass *pcc = PNV_CORE_GET_CLASS(pc);
350      CPUCore *cc = CPU_CORE(OBJECT(dev));
351      const char *typename = pnv_core_cpu_typename(pc);
352      Error *local_err = NULL;
353      void *obj;
354      int i, j;
355      char name[32];
356  
357      assert(pc->chip);
358  
359      pc->threads = g_new(PowerPCCPU *, cc->nr_threads);
360      for (i = 0; i < cc->nr_threads; i++) {
361          PowerPCCPU *cpu;
362          PnvCPUState *pnv_cpu;
363  
364          obj = object_new(typename);
365          cpu = POWERPC_CPU(obj);
366  
367          pc->threads[i] = POWERPC_CPU(obj);
368          if (cc->nr_threads > 1) {
369              cpu->env.has_smt_siblings = true;
370          }
371  
372          snprintf(name, sizeof(name), "thread[%d]", i);
373          object_property_add_child(OBJECT(pc), name, obj);
374  
375          cpu->machine_data = g_new0(PnvCPUState, 1);
376          pnv_cpu = pnv_cpu_state(cpu);
377          pnv_cpu->pnv_core = pc;
378  
379          object_unref(obj);
380      }
381  
382      for (j = 0; j < cc->nr_threads; j++) {
383          pnv_core_cpu_realize(pc, pc->threads[j], &local_err, j);
384          if (local_err) {
385              goto err;
386          }
387      }
388  
389      snprintf(name, sizeof(name), "xscom-core.%d", cc->core_id);
390      pnv_xscom_region_init(&pc->xscom_regs, OBJECT(dev), pcc->xscom_ops,
391                            pc, name, pcc->xscom_size);
392  
393      qemu_register_reset(pnv_core_reset, pc);
394      return;
395  
396  err:
397      while (--i >= 0) {
398          obj = OBJECT(pc->threads[i]);
399          object_unparent(obj);
400      }
401      g_free(pc->threads);
402      error_propagate(errp, local_err);
403  }
404  
405  static void pnv_core_cpu_unrealize(PnvCore *pc, PowerPCCPU *cpu)
406  {
407      PnvCPUState *pnv_cpu = pnv_cpu_state(cpu);
408      PnvChipClass *pcc = PNV_CHIP_GET_CLASS(pc->chip);
409  
410      pcc->intc_destroy(pc->chip, cpu);
411      cpu_remove_sync(CPU(cpu));
412      cpu->machine_data = NULL;
413      g_free(pnv_cpu);
414      object_unparent(OBJECT(cpu));
415  }
416  
417  static void pnv_core_unrealize(DeviceState *dev)
418  {
419      PnvCore *pc = PNV_CORE(dev);
420      CPUCore *cc = CPU_CORE(dev);
421      int i;
422  
423      qemu_unregister_reset(pnv_core_reset, pc);
424  
425      for (i = 0; i < cc->nr_threads; i++) {
426          pnv_core_cpu_unrealize(pc, pc->threads[i]);
427      }
428      g_free(pc->threads);
429  }
430  
431  static Property pnv_core_properties[] = {
432      DEFINE_PROP_UINT32("hwid", PnvCore, hwid, 0),
433      DEFINE_PROP_UINT64("hrmor", PnvCore, hrmor, 0),
434      DEFINE_PROP_BOOL("big-core", PnvCore, big_core, false),
435      DEFINE_PROP_BOOL("quirk-tb-big-core", PnvCore, tod_state.big_core_quirk,
436                       false),
437      DEFINE_PROP_BOOL("lpar-per-core", PnvCore, lpar_per_core, false),
438      DEFINE_PROP_LINK("chip", PnvCore, chip, TYPE_PNV_CHIP, PnvChip *),
439      DEFINE_PROP_END_OF_LIST(),
440  };
441  
442  static void pnv_core_power8_class_init(ObjectClass *oc, void *data)
443  {
444      PnvCoreClass *pcc = PNV_CORE_CLASS(oc);
445  
446      pcc->xscom_ops = &pnv_core_power8_xscom_ops;
447      pcc->xscom_size = PNV_XSCOM_EX_SIZE;
448  }
449  
450  static void pnv_core_power9_class_init(ObjectClass *oc, void *data)
451  {
452      PnvCoreClass *pcc = PNV_CORE_CLASS(oc);
453  
454      pcc->xscom_ops = &pnv_core_power9_xscom_ops;
455      pcc->xscom_size = PNV_XSCOM_EX_SIZE;
456  }
457  
458  static void pnv_core_power10_class_init(ObjectClass *oc, void *data)
459  {
460      PnvCoreClass *pcc = PNV_CORE_CLASS(oc);
461  
462      pcc->xscom_ops = &pnv_core_power10_xscom_ops;
463      pcc->xscom_size = PNV10_XSCOM_EC_SIZE;
464  }
465  
466  static void pnv_core_class_init(ObjectClass *oc, void *data)
467  {
468      DeviceClass *dc = DEVICE_CLASS(oc);
469  
470      dc->realize = pnv_core_realize;
471      dc->unrealize = pnv_core_unrealize;
472      device_class_set_props(dc, pnv_core_properties);
473      dc->user_creatable = false;
474  }
475  
476  #define DEFINE_PNV_CORE_TYPE(family, cpu_model) \
477      {                                           \
478          .parent = TYPE_PNV_CORE,                \
479          .name = PNV_CORE_TYPE_NAME(cpu_model),  \
480          .class_init = pnv_core_##family##_class_init, \
481      }
482  
483  static const TypeInfo pnv_core_infos[] = {
484      {
485          .name           = TYPE_PNV_CORE,
486          .parent         = TYPE_CPU_CORE,
487          .instance_size  = sizeof(PnvCore),
488          .class_size     = sizeof(PnvCoreClass),
489          .class_init = pnv_core_class_init,
490          .abstract       = true,
491      },
492      DEFINE_PNV_CORE_TYPE(power8, "power8e_v2.1"),
493      DEFINE_PNV_CORE_TYPE(power8, "power8_v2.0"),
494      DEFINE_PNV_CORE_TYPE(power8, "power8nvl_v1.0"),
495      DEFINE_PNV_CORE_TYPE(power9, "power9_v2.2"),
496      DEFINE_PNV_CORE_TYPE(power10, "power10_v2.0"),
497  };
498  
499  DEFINE_TYPES(pnv_core_infos)
500  
501  /*
502   * POWER9 Quads
503   */
504  
505  #define P9X_EX_NCU_SPEC_BAR                     0x11010
506  
507  static uint64_t pnv_quad_power9_xscom_read(void *opaque, hwaddr addr,
508                                             unsigned int width)
509  {
510      uint32_t offset = addr >> 3;
511      uint64_t val = -1;
512  
513      switch (offset) {
514      case P9X_EX_NCU_SPEC_BAR:
515      case P9X_EX_NCU_SPEC_BAR + 0x400: /* Second EX */
516          val = 0;
517          break;
518      default:
519          qemu_log_mask(LOG_UNIMP, "%s: unimp read 0x%08x\n", __func__,
520                        offset);
521      }
522  
523      return val;
524  }
525  
526  static void pnv_quad_power9_xscom_write(void *opaque, hwaddr addr, uint64_t val,
527                                          unsigned int width)
528  {
529      uint32_t offset = addr >> 3;
530  
531      switch (offset) {
532      case P9X_EX_NCU_SPEC_BAR:
533      case P9X_EX_NCU_SPEC_BAR + 0x400: /* Second EX */
534          break;
535      default:
536          qemu_log_mask(LOG_UNIMP, "%s: unimp write 0x%08x\n", __func__,
537                    offset);
538      }
539  }
540  
541  static const MemoryRegionOps pnv_quad_power9_xscom_ops = {
542      .read = pnv_quad_power9_xscom_read,
543      .write = pnv_quad_power9_xscom_write,
544      .valid.min_access_size = 8,
545      .valid.max_access_size = 8,
546      .impl.min_access_size = 8,
547      .impl.max_access_size = 8,
548      .endianness = DEVICE_BIG_ENDIAN,
549  };
550  
551  /*
552   * POWER10 Quads
553   */
554  
555  static uint64_t pnv_quad_power10_xscom_read(void *opaque, hwaddr addr,
556                                              unsigned int width)
557  {
558      uint32_t offset = addr >> 3;
559      uint64_t val = -1;
560  
561      switch (offset) {
562      default:
563          qemu_log_mask(LOG_UNIMP, "%s: unimp read 0x%08x\n", __func__,
564                        offset);
565      }
566  
567      return val;
568  }
569  
570  static void pnv_quad_power10_xscom_write(void *opaque, hwaddr addr,
571                                           uint64_t val, unsigned int width)
572  {
573      uint32_t offset = addr >> 3;
574  
575      switch (offset) {
576      default:
577          qemu_log_mask(LOG_UNIMP, "%s: unimp write 0x%08x\n", __func__,
578                        offset);
579      }
580  }
581  
582  static const MemoryRegionOps pnv_quad_power10_xscom_ops = {
583      .read = pnv_quad_power10_xscom_read,
584      .write = pnv_quad_power10_xscom_write,
585      .valid.min_access_size = 8,
586      .valid.max_access_size = 8,
587      .impl.min_access_size = 8,
588      .impl.max_access_size = 8,
589      .endianness = DEVICE_BIG_ENDIAN,
590  };
591  
592  #define P10_QME_SPWU_HYP 0x83c
593  #define P10_QME_SSH_HYP  0x82c
594  
595  static uint64_t pnv_qme_power10_xscom_read(void *opaque, hwaddr addr,
596                                              unsigned int width)
597  {
598      PnvQuad *eq = PNV_QUAD(opaque);
599      uint32_t offset = addr >> 3;
600      uint64_t val = -1;
601  
602      /*
603       * Forth nibble selects the core within a quad, mask it to process read
604       * for any core.
605       */
606      switch (offset & ~PPC_BITMASK32(16, 19)) {
607      case P10_QME_SSH_HYP:
608          val = 0;
609          if (eq->special_wakeup_done) {
610              val |= PPC_BIT(1); /* SPWU DONE */
611              val |= PPC_BIT(4); /* SSH SPWU DONE */
612          }
613          break;
614      default:
615          qemu_log_mask(LOG_UNIMP, "%s: unimp read 0x%08x\n", __func__,
616                        offset);
617      }
618  
619      return val;
620  }
621  
622  static void pnv_qme_power10_xscom_write(void *opaque, hwaddr addr,
623                                           uint64_t val, unsigned int width)
624  {
625      PnvQuad *eq = PNV_QUAD(opaque);
626      uint32_t offset = addr >> 3;
627      bool set;
628      int i;
629  
630      switch (offset & ~PPC_BITMASK32(16, 19)) {
631      case P10_QME_SPWU_HYP:
632          set = !!(val & PPC_BIT(0));
633          eq->special_wakeup_done = set;
634          for (i = 0; i < 4; i++) {
635              /* These bits select cores in the quad */
636              if (offset & PPC_BIT32(16 + i)) {
637                  eq->special_wakeup[i] = set;
638              }
639          }
640          break;
641      default:
642          qemu_log_mask(LOG_UNIMP, "%s: unimp write 0x%08x\n", __func__,
643                        offset);
644      }
645  }
646  
647  static const MemoryRegionOps pnv_qme_power10_xscom_ops = {
648      .read = pnv_qme_power10_xscom_read,
649      .write = pnv_qme_power10_xscom_write,
650      .valid.min_access_size = 8,
651      .valid.max_access_size = 8,
652      .impl.min_access_size = 8,
653      .impl.max_access_size = 8,
654      .endianness = DEVICE_BIG_ENDIAN,
655  };
656  
657  static void pnv_quad_power9_realize(DeviceState *dev, Error **errp)
658  {
659      PnvQuad *eq = PNV_QUAD(dev);
660      PnvQuadClass *pqc = PNV_QUAD_GET_CLASS(eq);
661      char name[32];
662  
663      snprintf(name, sizeof(name), "xscom-quad.%d", eq->quad_id);
664      pnv_xscom_region_init(&eq->xscom_regs, OBJECT(dev),
665                            pqc->xscom_ops,
666                            eq, name,
667                            pqc->xscom_size);
668  }
669  
670  static void pnv_quad_power10_realize(DeviceState *dev, Error **errp)
671  {
672      PnvQuad *eq = PNV_QUAD(dev);
673      PnvQuadClass *pqc = PNV_QUAD_GET_CLASS(eq);
674      char name[32];
675  
676      snprintf(name, sizeof(name), "xscom-quad.%d", eq->quad_id);
677      pnv_xscom_region_init(&eq->xscom_regs, OBJECT(dev),
678                            pqc->xscom_ops,
679                            eq, name,
680                            pqc->xscom_size);
681  
682      snprintf(name, sizeof(name), "xscom-qme.%d", eq->quad_id);
683      pnv_xscom_region_init(&eq->xscom_qme_regs, OBJECT(dev),
684                            pqc->xscom_qme_ops,
685                            eq, name,
686                            pqc->xscom_qme_size);
687  }
688  
689  static Property pnv_quad_properties[] = {
690      DEFINE_PROP_UINT32("quad-id", PnvQuad, quad_id, 0),
691      DEFINE_PROP_END_OF_LIST(),
692  };
693  
694  static void pnv_quad_power9_class_init(ObjectClass *oc, void *data)
695  {
696      PnvQuadClass *pqc = PNV_QUAD_CLASS(oc);
697      DeviceClass *dc = DEVICE_CLASS(oc);
698  
699      dc->realize = pnv_quad_power9_realize;
700  
701      pqc->xscom_ops = &pnv_quad_power9_xscom_ops;
702      pqc->xscom_size = PNV9_XSCOM_EQ_SIZE;
703  }
704  
705  static void pnv_quad_power10_class_init(ObjectClass *oc, void *data)
706  {
707      PnvQuadClass *pqc = PNV_QUAD_CLASS(oc);
708      DeviceClass *dc = DEVICE_CLASS(oc);
709  
710      dc->realize = pnv_quad_power10_realize;
711  
712      pqc->xscom_ops = &pnv_quad_power10_xscom_ops;
713      pqc->xscom_size = PNV10_XSCOM_EQ_SIZE;
714  
715      pqc->xscom_qme_ops = &pnv_qme_power10_xscom_ops;
716      pqc->xscom_qme_size = PNV10_XSCOM_QME_SIZE;
717  }
718  
719  static void pnv_quad_class_init(ObjectClass *oc, void *data)
720  {
721      DeviceClass *dc = DEVICE_CLASS(oc);
722  
723      device_class_set_props(dc, pnv_quad_properties);
724      dc->user_creatable = false;
725  }
726  
727  static const TypeInfo pnv_quad_infos[] = {
728      {
729          .name          = TYPE_PNV_QUAD,
730          .parent        = TYPE_DEVICE,
731          .instance_size = sizeof(PnvQuad),
732          .class_size    = sizeof(PnvQuadClass),
733          .class_init    = pnv_quad_class_init,
734          .abstract      = true,
735      },
736      {
737          .parent = TYPE_PNV_QUAD,
738          .name = PNV_QUAD_TYPE_NAME("power9"),
739          .class_init = pnv_quad_power9_class_init,
740      },
741      {
742          .parent = TYPE_PNV_QUAD,
743          .name = PNV_QUAD_TYPE_NAME("power10"),
744          .class_init = pnv_quad_power10_class_init,
745      },
746  };
747  
748  DEFINE_TYPES(pnv_quad_infos);
749