pnv_occ.c (9121B)
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 "target/ppc/cpu.h" 21#include "qapi/error.h" 22#include "qemu/log.h" 23#include "qemu/module.h" 24#include "hw/qdev-properties.h" 25#include "hw/ppc/pnv.h" 26#include "hw/ppc/pnv_xscom.h" 27#include "hw/ppc/pnv_occ.h" 28 29#define OCB_OCI_OCCMISC 0x4020 30#define OCB_OCI_OCCMISC_AND 0x4021 31#define OCB_OCI_OCCMISC_OR 0x4022 32 33/* OCC sensors */ 34#define OCC_SENSOR_DATA_BLOCK_OFFSET 0x580000 35#define OCC_SENSOR_DATA_VALID 0x580001 36#define OCC_SENSOR_DATA_VERSION 0x580002 37#define OCC_SENSOR_DATA_READING_VERSION 0x580004 38#define OCC_SENSOR_DATA_NR_SENSORS 0x580008 39#define OCC_SENSOR_DATA_NAMES_OFFSET 0x580010 40#define OCC_SENSOR_DATA_READING_PING_OFFSET 0x580014 41#define OCC_SENSOR_DATA_READING_PONG_OFFSET 0x58000c 42#define OCC_SENSOR_DATA_NAME_LENGTH 0x58000d 43#define OCC_SENSOR_NAME_STRUCTURE_TYPE 0x580023 44#define OCC_SENSOR_LOC_CORE 0x580022 45#define OCC_SENSOR_LOC_GPU 0x580020 46#define OCC_SENSOR_TYPE_POWER 0x580003 47#define OCC_SENSOR_NAME 0x580005 48#define HWMON_SENSORS_MASK 0x58001e 49#define SLW_IMAGE_BASE 0x0 50 51static void pnv_occ_set_misc(PnvOCC *occ, uint64_t val) 52{ 53 bool irq_state; 54 PnvOCCClass *poc = PNV_OCC_GET_CLASS(occ); 55 56 val &= 0xffff000000000000ull; 57 58 occ->occmisc = val; 59 irq_state = !!(val >> 63); 60 pnv_psi_irq_set(occ->psi, poc->psi_irq, irq_state); 61} 62 63static uint64_t pnv_occ_power8_xscom_read(void *opaque, hwaddr addr, 64 unsigned size) 65{ 66 PnvOCC *occ = PNV_OCC(opaque); 67 uint32_t offset = addr >> 3; 68 uint64_t val = 0; 69 70 switch (offset) { 71 case OCB_OCI_OCCMISC: 72 val = occ->occmisc; 73 break; 74 default: 75 qemu_log_mask(LOG_UNIMP, "OCC Unimplemented register: Ox%" 76 HWADDR_PRIx "\n", addr >> 3); 77 } 78 return val; 79} 80 81static void pnv_occ_power8_xscom_write(void *opaque, hwaddr addr, 82 uint64_t val, unsigned size) 83{ 84 PnvOCC *occ = PNV_OCC(opaque); 85 uint32_t offset = addr >> 3; 86 87 switch (offset) { 88 case OCB_OCI_OCCMISC_AND: 89 pnv_occ_set_misc(occ, occ->occmisc & val); 90 break; 91 case OCB_OCI_OCCMISC_OR: 92 pnv_occ_set_misc(occ, occ->occmisc | val); 93 break; 94 case OCB_OCI_OCCMISC: 95 pnv_occ_set_misc(occ, val); 96 break; 97 default: 98 qemu_log_mask(LOG_UNIMP, "OCC Unimplemented register: Ox%" 99 HWADDR_PRIx "\n", addr >> 3); 100 } 101} 102 103static uint64_t pnv_occ_common_area_read(void *opaque, hwaddr addr, 104 unsigned width) 105{ 106 switch (addr) { 107 /* 108 * occ-sensor sanity check that asserts the sensor 109 * header block 110 */ 111 case OCC_SENSOR_DATA_BLOCK_OFFSET: 112 case OCC_SENSOR_DATA_VALID: 113 case OCC_SENSOR_DATA_VERSION: 114 case OCC_SENSOR_DATA_READING_VERSION: 115 case OCC_SENSOR_DATA_NR_SENSORS: 116 case OCC_SENSOR_DATA_NAMES_OFFSET: 117 case OCC_SENSOR_DATA_READING_PING_OFFSET: 118 case OCC_SENSOR_DATA_READING_PONG_OFFSET: 119 case OCC_SENSOR_NAME_STRUCTURE_TYPE: 120 return 1; 121 case OCC_SENSOR_DATA_NAME_LENGTH: 122 return 0x30; 123 case OCC_SENSOR_LOC_CORE: 124 return 0x0040; 125 case OCC_SENSOR_TYPE_POWER: 126 return 0x0080; 127 case OCC_SENSOR_NAME: 128 return 0x1000; 129 case HWMON_SENSORS_MASK: 130 case OCC_SENSOR_LOC_GPU: 131 return 0x8e00; 132 case SLW_IMAGE_BASE: 133 return 0x1000000000000000; 134 } 135 return 0; 136} 137 138static void pnv_occ_common_area_write(void *opaque, hwaddr addr, 139 uint64_t val, unsigned width) 140{ 141 /* callback function defined to occ common area write */ 142 return; 143} 144 145static const MemoryRegionOps pnv_occ_power8_xscom_ops = { 146 .read = pnv_occ_power8_xscom_read, 147 .write = pnv_occ_power8_xscom_write, 148 .valid.min_access_size = 8, 149 .valid.max_access_size = 8, 150 .impl.min_access_size = 8, 151 .impl.max_access_size = 8, 152 .endianness = DEVICE_BIG_ENDIAN, 153}; 154 155const MemoryRegionOps pnv_occ_sram_ops = { 156 .read = pnv_occ_common_area_read, 157 .write = pnv_occ_common_area_write, 158 .valid.min_access_size = 1, 159 .valid.max_access_size = 8, 160 .impl.min_access_size = 1, 161 .impl.max_access_size = 8, 162 .endianness = DEVICE_BIG_ENDIAN, 163}; 164 165static void pnv_occ_power8_class_init(ObjectClass *klass, void *data) 166{ 167 PnvOCCClass *poc = PNV_OCC_CLASS(klass); 168 169 poc->xscom_size = PNV_XSCOM_OCC_SIZE; 170 poc->xscom_ops = &pnv_occ_power8_xscom_ops; 171 poc->psi_irq = PSIHB_IRQ_OCC; 172} 173 174static const TypeInfo pnv_occ_power8_type_info = { 175 .name = TYPE_PNV8_OCC, 176 .parent = TYPE_PNV_OCC, 177 .instance_size = sizeof(PnvOCC), 178 .class_init = pnv_occ_power8_class_init, 179}; 180 181#define P9_OCB_OCI_OCCMISC 0x6080 182#define P9_OCB_OCI_OCCMISC_CLEAR 0x6081 183#define P9_OCB_OCI_OCCMISC_OR 0x6082 184 185 186static uint64_t pnv_occ_power9_xscom_read(void *opaque, hwaddr addr, 187 unsigned size) 188{ 189 PnvOCC *occ = PNV_OCC(opaque); 190 uint32_t offset = addr >> 3; 191 uint64_t val = 0; 192 193 switch (offset) { 194 case P9_OCB_OCI_OCCMISC: 195 val = occ->occmisc; 196 break; 197 default: 198 qemu_log_mask(LOG_UNIMP, "OCC Unimplemented register: Ox%" 199 HWADDR_PRIx "\n", addr >> 3); 200 } 201 return val; 202} 203 204static void pnv_occ_power9_xscom_write(void *opaque, hwaddr addr, 205 uint64_t val, unsigned size) 206{ 207 PnvOCC *occ = PNV_OCC(opaque); 208 uint32_t offset = addr >> 3; 209 210 switch (offset) { 211 case P9_OCB_OCI_OCCMISC_CLEAR: 212 pnv_occ_set_misc(occ, 0); 213 break; 214 case P9_OCB_OCI_OCCMISC_OR: 215 pnv_occ_set_misc(occ, occ->occmisc | val); 216 break; 217 case P9_OCB_OCI_OCCMISC: 218 pnv_occ_set_misc(occ, val); 219 break; 220 default: 221 qemu_log_mask(LOG_UNIMP, "OCC Unimplemented register: Ox%" 222 HWADDR_PRIx "\n", addr >> 3); 223 } 224} 225 226static const MemoryRegionOps pnv_occ_power9_xscom_ops = { 227 .read = pnv_occ_power9_xscom_read, 228 .write = pnv_occ_power9_xscom_write, 229 .valid.min_access_size = 8, 230 .valid.max_access_size = 8, 231 .impl.min_access_size = 8, 232 .impl.max_access_size = 8, 233 .endianness = DEVICE_BIG_ENDIAN, 234}; 235 236static void pnv_occ_power9_class_init(ObjectClass *klass, void *data) 237{ 238 PnvOCCClass *poc = PNV_OCC_CLASS(klass); 239 240 poc->xscom_size = PNV9_XSCOM_OCC_SIZE; 241 poc->xscom_ops = &pnv_occ_power9_xscom_ops; 242 poc->psi_irq = PSIHB9_IRQ_OCC; 243} 244 245static const TypeInfo pnv_occ_power9_type_info = { 246 .name = TYPE_PNV9_OCC, 247 .parent = TYPE_PNV_OCC, 248 .instance_size = sizeof(PnvOCC), 249 .class_init = pnv_occ_power9_class_init, 250}; 251 252static void pnv_occ_realize(DeviceState *dev, Error **errp) 253{ 254 PnvOCC *occ = PNV_OCC(dev); 255 PnvOCCClass *poc = PNV_OCC_GET_CLASS(occ); 256 257 assert(occ->psi); 258 259 occ->occmisc = 0; 260 261 /* XScom region for OCC registers */ 262 pnv_xscom_region_init(&occ->xscom_regs, OBJECT(dev), poc->xscom_ops, 263 occ, "xscom-occ", poc->xscom_size); 264 265 /* OCC common area mmio region for OCC SRAM registers */ 266 memory_region_init_io(&occ->sram_regs, OBJECT(dev), &pnv_occ_sram_ops, 267 occ, "occ-common-area", 268 PNV_OCC_SENSOR_DATA_BLOCK_SIZE); 269} 270 271static Property pnv_occ_properties[] = { 272 DEFINE_PROP_LINK("psi", PnvOCC, psi, TYPE_PNV_PSI, PnvPsi *), 273 DEFINE_PROP_END_OF_LIST(), 274}; 275 276static void pnv_occ_class_init(ObjectClass *klass, void *data) 277{ 278 DeviceClass *dc = DEVICE_CLASS(klass); 279 280 dc->realize = pnv_occ_realize; 281 dc->desc = "PowerNV OCC Controller"; 282 device_class_set_props(dc, pnv_occ_properties); 283 dc->user_creatable = false; 284} 285 286static const TypeInfo pnv_occ_type_info = { 287 .name = TYPE_PNV_OCC, 288 .parent = TYPE_DEVICE, 289 .instance_size = sizeof(PnvOCC), 290 .class_init = pnv_occ_class_init, 291 .class_size = sizeof(PnvOCCClass), 292 .abstract = true, 293}; 294 295static void pnv_occ_register_types(void) 296{ 297 type_register_static(&pnv_occ_type_info); 298 type_register_static(&pnv_occ_power8_type_info); 299 type_register_static(&pnv_occ_power9_type_info); 300} 301 302type_init(pnv_occ_register_types);