qemu/hw/ppc/pnv_homer.c
<<
>>
Prefs
   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 "exec/memory.h"
  24#include "sysemu/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_homer.h"
  29#include "hw/ppc/pnv_xscom.h"
  30
  31
  32static bool core_max_array(PnvHomer *homer, hwaddr addr)
  33{
  34    int i;
  35    PnvHomerClass *hmrc = PNV_HOMER_GET_CLASS(homer);
  36
  37    for (i = 0; i <= homer->chip->nr_cores; i++) {
  38        if (addr == (hmrc->core_max_base + i)) {
  39            return true;
  40       }
  41    }
  42    return false;
  43}
  44
  45/* P8 Pstate table */
  46
  47#define PNV8_OCC_PSTATE_VERSION          0x1f8001
  48#define PNV8_OCC_PSTATE_MIN              0x1f8003
  49#define PNV8_OCC_PSTATE_VALID            0x1f8000
  50#define PNV8_OCC_PSTATE_THROTTLE         0x1f8002
  51#define PNV8_OCC_PSTATE_NOM              0x1f8004
  52#define PNV8_OCC_PSTATE_TURBO            0x1f8005
  53#define PNV8_OCC_PSTATE_ULTRA_TURBO      0x1f8006
  54#define PNV8_OCC_PSTATE_DATA             0x1f8008
  55#define PNV8_OCC_PSTATE_ID_ZERO          0x1f8010
  56#define PNV8_OCC_PSTATE_ID_ONE           0x1f8018
  57#define PNV8_OCC_PSTATE_ID_TWO           0x1f8020
  58#define PNV8_OCC_VDD_VOLTAGE_IDENTIFIER  0x1f8012
  59#define PNV8_OCC_VCS_VOLTAGE_IDENTIFIER  0x1f8013
  60#define PNV8_OCC_PSTATE_ZERO_FREQUENCY   0x1f8014
  61#define PNV8_OCC_PSTATE_ONE_FREQUENCY    0x1f801c
  62#define PNV8_OCC_PSTATE_TWO_FREQUENCY    0x1f8024
  63#define PNV8_CORE_MAX_BASE               0x1f8810
  64
  65
  66static uint64_t pnv_power8_homer_read(void *opaque, hwaddr addr,
  67                                      unsigned size)
  68{
  69    PnvHomer *homer = PNV_HOMER(opaque);
  70
  71    switch (addr) {
  72    case PNV8_OCC_PSTATE_VERSION:
  73    case PNV8_OCC_PSTATE_MIN:
  74    case PNV8_OCC_PSTATE_ID_ZERO:
  75        return 0;
  76    case PNV8_OCC_PSTATE_VALID:
  77    case PNV8_OCC_PSTATE_THROTTLE:
  78    case PNV8_OCC_PSTATE_NOM:
  79    case PNV8_OCC_PSTATE_TURBO:
  80    case PNV8_OCC_PSTATE_ID_ONE:
  81    case PNV8_OCC_VDD_VOLTAGE_IDENTIFIER:
  82    case PNV8_OCC_VCS_VOLTAGE_IDENTIFIER:
  83        return 1;
  84    case PNV8_OCC_PSTATE_ULTRA_TURBO:
  85    case PNV8_OCC_PSTATE_ID_TWO:
  86        return 2;
  87    case PNV8_OCC_PSTATE_DATA:
  88        return 0x1000000000000000;
  89    /* P8 frequency for 0, 1, and 2 pstates */
  90    case PNV8_OCC_PSTATE_ZERO_FREQUENCY:
  91    case PNV8_OCC_PSTATE_ONE_FREQUENCY:
  92    case PNV8_OCC_PSTATE_TWO_FREQUENCY:
  93        return 3000;
  94    }
  95    /* pstate table core max array */
  96    if (core_max_array(homer, addr)) {
  97        return 1;
  98    }
  99    return 0;
 100}
 101
 102static void pnv_power8_homer_write(void *opaque, hwaddr addr,
 103                                   uint64_t val, unsigned size)
 104{
 105    /* callback function defined to homer write */
 106    return;
 107}
 108
 109static const MemoryRegionOps pnv_power8_homer_ops = {
 110    .read = pnv_power8_homer_read,
 111    .write = pnv_power8_homer_write,
 112    .valid.min_access_size = 1,
 113    .valid.max_access_size = 8,
 114    .impl.min_access_size = 1,
 115    .impl.max_access_size = 8,
 116    .endianness = DEVICE_BIG_ENDIAN,
 117};
 118
 119/* P8 PBA BARs */
 120#define PBA_BAR0                     0x00
 121#define PBA_BAR1                     0x01
 122#define PBA_BAR2                     0x02
 123#define PBA_BAR3                     0x03
 124#define PBA_BARMASK0                 0x04
 125#define PBA_BARMASK1                 0x05
 126#define PBA_BARMASK2                 0x06
 127#define PBA_BARMASK3                 0x07
 128
 129static uint64_t pnv_homer_power8_pba_read(void *opaque, hwaddr addr,
 130                                          unsigned size)
 131{
 132    PnvHomer *homer = PNV_HOMER(opaque);
 133    PnvChip *chip = homer->chip;
 134    uint32_t reg = addr >> 3;
 135    uint64_t val = 0;
 136
 137    switch (reg) {
 138    case PBA_BAR0:
 139        val = PNV_HOMER_BASE(chip);
 140        break;
 141    case PBA_BARMASK0: /* P8 homer region mask */
 142        val = (PNV_HOMER_SIZE - 1) & 0x300000;
 143        break;
 144    case PBA_BAR3: /* P8 occ common area */
 145        val = PNV_OCC_COMMON_AREA_BASE;
 146        break;
 147    case PBA_BARMASK3: /* P8 occ common area mask */
 148        val = (PNV_OCC_COMMON_AREA_SIZE - 1) & 0x700000;
 149        break;
 150    default:
 151        qemu_log_mask(LOG_UNIMP, "PBA: read to unimplemented register: Ox%"
 152                      HWADDR_PRIx "\n", addr >> 3);
 153    }
 154    return val;
 155}
 156
 157static void pnv_homer_power8_pba_write(void *opaque, hwaddr addr,
 158                                         uint64_t val, unsigned size)
 159{
 160    qemu_log_mask(LOG_UNIMP, "PBA: write to unimplemented register: Ox%"
 161                  HWADDR_PRIx "\n", addr >> 3);
 162}
 163
 164static const MemoryRegionOps pnv_homer_power8_pba_ops = {
 165    .read = pnv_homer_power8_pba_read,
 166    .write = pnv_homer_power8_pba_write,
 167    .valid.min_access_size = 8,
 168    .valid.max_access_size = 8,
 169    .impl.min_access_size = 8,
 170    .impl.max_access_size = 8,
 171    .endianness = DEVICE_BIG_ENDIAN,
 172};
 173
 174static void pnv_homer_power8_class_init(ObjectClass *klass, void *data)
 175{
 176    PnvHomerClass *homer = PNV_HOMER_CLASS(klass);
 177
 178    homer->pba_size = PNV_XSCOM_PBA_SIZE;
 179    homer->pba_ops = &pnv_homer_power8_pba_ops;
 180    homer->homer_size = PNV_HOMER_SIZE;
 181    homer->homer_ops = &pnv_power8_homer_ops;
 182    homer->core_max_base = PNV8_CORE_MAX_BASE;
 183}
 184
 185static const TypeInfo pnv_homer_power8_type_info = {
 186    .name          = TYPE_PNV8_HOMER,
 187    .parent        = TYPE_PNV_HOMER,
 188    .instance_size = sizeof(PnvHomer),
 189    .class_init    = pnv_homer_power8_class_init,
 190};
 191
 192/* P9 Pstate table */
 193
 194#define PNV9_OCC_PSTATE_ID_ZERO          0xe2018
 195#define PNV9_OCC_PSTATE_ID_ONE           0xe2020
 196#define PNV9_OCC_PSTATE_ID_TWO           0xe2028
 197#define PNV9_OCC_PSTATE_DATA             0xe2000
 198#define PNV9_OCC_PSTATE_DATA_AREA        0xe2008
 199#define PNV9_OCC_PSTATE_MIN              0xe2003
 200#define PNV9_OCC_PSTATE_NOM              0xe2004
 201#define PNV9_OCC_PSTATE_TURBO            0xe2005
 202#define PNV9_OCC_PSTATE_ULTRA_TURBO      0xe2818
 203#define PNV9_OCC_MAX_PSTATE_ULTRA_TURBO  0xe2006
 204#define PNV9_OCC_PSTATE_MAJOR_VERSION    0xe2001
 205#define PNV9_OCC_OPAL_RUNTIME_DATA       0xe2b85
 206#define PNV9_CHIP_HOMER_IMAGE_POINTER    0x200008
 207#define PNV9_CHIP_HOMER_BASE             0x0
 208#define PNV9_OCC_PSTATE_ZERO_FREQUENCY   0xe201c
 209#define PNV9_OCC_PSTATE_ONE_FREQUENCY    0xe2024
 210#define PNV9_OCC_PSTATE_TWO_FREQUENCY    0xe202c
 211#define PNV9_OCC_ROLE_MASTER_OR_SLAVE    0xe2002
 212#define PNV9_CORE_MAX_BASE               0xe2819
 213
 214
 215static uint64_t pnv_power9_homer_read(void *opaque, hwaddr addr,
 216                                      unsigned size)
 217{
 218    PnvHomer *homer = PNV_HOMER(opaque);
 219
 220    switch (addr) {
 221    case PNV9_OCC_MAX_PSTATE_ULTRA_TURBO:
 222    case PNV9_OCC_PSTATE_ID_ZERO:
 223        return 0;
 224    case PNV9_OCC_PSTATE_DATA:
 225    case PNV9_OCC_ROLE_MASTER_OR_SLAVE:
 226    case PNV9_OCC_PSTATE_NOM:
 227    case PNV9_OCC_PSTATE_TURBO:
 228    case PNV9_OCC_PSTATE_ID_ONE:
 229    case PNV9_OCC_PSTATE_ULTRA_TURBO:
 230    case PNV9_OCC_OPAL_RUNTIME_DATA:
 231        return 1;
 232    case PNV9_OCC_PSTATE_MIN:
 233    case PNV9_OCC_PSTATE_ID_TWO:
 234        return 2;
 235
 236    /* 3000 khz frequency for 0, 1, and 2 pstates */
 237    case PNV9_OCC_PSTATE_ZERO_FREQUENCY:
 238    case PNV9_OCC_PSTATE_ONE_FREQUENCY:
 239    case PNV9_OCC_PSTATE_TWO_FREQUENCY:
 240        return 3000;
 241    case PNV9_OCC_PSTATE_MAJOR_VERSION:
 242        return 0x90;
 243    case PNV9_CHIP_HOMER_BASE:
 244    case PNV9_OCC_PSTATE_DATA_AREA:
 245    case PNV9_CHIP_HOMER_IMAGE_POINTER:
 246        return 0x1000000000000000;
 247    }
 248    /* pstate table core max array */
 249    if (core_max_array(homer, addr)) {
 250        return 1;
 251    }
 252    return 0;
 253}
 254
 255static void pnv_power9_homer_write(void *opaque, hwaddr addr,
 256                                   uint64_t val, unsigned size)
 257{
 258    /* callback function defined to homer write */
 259    return;
 260}
 261
 262static const MemoryRegionOps pnv_power9_homer_ops = {
 263    .read = pnv_power9_homer_read,
 264    .write = pnv_power9_homer_write,
 265    .valid.min_access_size = 1,
 266    .valid.max_access_size = 8,
 267    .impl.min_access_size = 1,
 268    .impl.max_access_size = 8,
 269    .endianness = DEVICE_BIG_ENDIAN,
 270};
 271
 272static uint64_t pnv_homer_power9_pba_read(void *opaque, hwaddr addr,
 273                                          unsigned size)
 274{
 275    PnvHomer *homer = PNV_HOMER(opaque);
 276    PnvChip *chip = homer->chip;
 277    uint32_t reg = addr >> 3;
 278    uint64_t val = 0;
 279
 280    switch (reg) {
 281    case PBA_BAR0:
 282        val = PNV9_HOMER_BASE(chip);
 283        break;
 284    case PBA_BARMASK0: /* P9 homer region mask */
 285        val = (PNV9_HOMER_SIZE - 1) & 0x300000;
 286        break;
 287    case PBA_BAR2: /* P9 occ common area */
 288        val = PNV9_OCC_COMMON_AREA_BASE;
 289        break;
 290    case PBA_BARMASK2: /* P9 occ common area size */
 291        val = (PNV9_OCC_COMMON_AREA_SIZE - 1) & 0x700000;
 292        break;
 293    default:
 294        qemu_log_mask(LOG_UNIMP, "PBA: read to unimplemented register: Ox%"
 295                      HWADDR_PRIx "\n", addr >> 3);
 296    }
 297    return val;
 298}
 299
 300static void pnv_homer_power9_pba_write(void *opaque, hwaddr addr,
 301                                         uint64_t val, unsigned size)
 302{
 303    qemu_log_mask(LOG_UNIMP, "PBA: write to unimplemented register: Ox%"
 304                  HWADDR_PRIx "\n", addr >> 3);
 305}
 306
 307static const MemoryRegionOps pnv_homer_power9_pba_ops = {
 308    .read = pnv_homer_power9_pba_read,
 309    .write = pnv_homer_power9_pba_write,
 310    .valid.min_access_size = 8,
 311    .valid.max_access_size = 8,
 312    .impl.min_access_size = 8,
 313    .impl.max_access_size = 8,
 314    .endianness = DEVICE_BIG_ENDIAN,
 315};
 316
 317static void pnv_homer_power9_class_init(ObjectClass *klass, void *data)
 318{
 319    PnvHomerClass *homer = PNV_HOMER_CLASS(klass);
 320
 321    homer->pba_size = PNV9_XSCOM_PBA_SIZE;
 322    homer->pba_ops = &pnv_homer_power9_pba_ops;
 323    homer->homer_size = PNV9_HOMER_SIZE;
 324    homer->homer_ops = &pnv_power9_homer_ops;
 325    homer->core_max_base = PNV9_CORE_MAX_BASE;
 326}
 327
 328static const TypeInfo pnv_homer_power9_type_info = {
 329    .name          = TYPE_PNV9_HOMER,
 330    .parent        = TYPE_PNV_HOMER,
 331    .instance_size = sizeof(PnvHomer),
 332    .class_init    = pnv_homer_power9_class_init,
 333};
 334
 335static void pnv_homer_realize(DeviceState *dev, Error **errp)
 336{
 337    PnvHomer *homer = PNV_HOMER(dev);
 338    PnvHomerClass *hmrc = PNV_HOMER_GET_CLASS(homer);
 339
 340    assert(homer->chip);
 341
 342    pnv_xscom_region_init(&homer->pba_regs, OBJECT(dev), hmrc->pba_ops,
 343                          homer, "xscom-pba", hmrc->pba_size);
 344
 345    /* homer region */
 346    memory_region_init_io(&homer->regs, OBJECT(dev),
 347                          hmrc->homer_ops, homer, "homer-main-memory",
 348                          hmrc->homer_size);
 349}
 350
 351static Property pnv_homer_properties[] = {
 352    DEFINE_PROP_LINK("chip", PnvHomer, chip, TYPE_PNV_CHIP, PnvChip *),
 353    DEFINE_PROP_END_OF_LIST(),
 354};
 355
 356static void pnv_homer_class_init(ObjectClass *klass, void *data)
 357{
 358    DeviceClass *dc = DEVICE_CLASS(klass);
 359
 360    dc->realize = pnv_homer_realize;
 361    dc->desc = "PowerNV HOMER Memory";
 362    device_class_set_props(dc, pnv_homer_properties);
 363    dc->user_creatable = false;
 364}
 365
 366static const TypeInfo pnv_homer_type_info = {
 367    .name          = TYPE_PNV_HOMER,
 368    .parent        = TYPE_DEVICE,
 369    .instance_size = sizeof(PnvHomer),
 370    .class_init    = pnv_homer_class_init,
 371    .class_size    = sizeof(PnvHomerClass),
 372    .abstract      = true,
 373};
 374
 375static void pnv_homer_register_types(void)
 376{
 377    type_register_static(&pnv_homer_type_info);
 378    type_register_static(&pnv_homer_power8_type_info);
 379    type_register_static(&pnv_homer_power9_type_info);
 380}
 381
 382type_init(pnv_homer_register_types);
 383