10722d05aSBenjamin Herrenschmidt /*
20722d05aSBenjamin Herrenschmidt * QEMU PowerPC PowerNV Emulation of a few OCC related registers
30722d05aSBenjamin Herrenschmidt *
40722d05aSBenjamin Herrenschmidt * Copyright (c) 2015-2017, IBM Corporation.
50722d05aSBenjamin Herrenschmidt *
60722d05aSBenjamin Herrenschmidt * This program is free software; you can redistribute it and/or modify
70722d05aSBenjamin Herrenschmidt * it under the terms of the GNU General Public License, version 2, as
80722d05aSBenjamin Herrenschmidt * published by the Free Software Foundation.
90722d05aSBenjamin Herrenschmidt *
100722d05aSBenjamin Herrenschmidt * This program is distributed in the hope that it will be useful,
110722d05aSBenjamin Herrenschmidt * but WITHOUT ANY WARRANTY; without even the implied warranty of
120722d05aSBenjamin Herrenschmidt * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
130722d05aSBenjamin Herrenschmidt * GNU General Public License for more details.
140722d05aSBenjamin Herrenschmidt *
150722d05aSBenjamin Herrenschmidt * You should have received a copy of the GNU General Public License
160722d05aSBenjamin Herrenschmidt * along with this program; if not, see <http://www.gnu.org/licenses/>.
170722d05aSBenjamin Herrenschmidt */
180722d05aSBenjamin Herrenschmidt
190722d05aSBenjamin Herrenschmidt #include "qemu/osdep.h"
200722d05aSBenjamin Herrenschmidt #include "target/ppc/cpu.h"
210722d05aSBenjamin Herrenschmidt #include "qapi/error.h"
220722d05aSBenjamin Herrenschmidt #include "qemu/log.h"
230b8fa32fSMarkus Armbruster #include "qemu/module.h"
24b0ae5c69SCédric Le Goater #include "hw/irq.h"
25ee3d2713SGreg Kurz #include "hw/qdev-properties.h"
260722d05aSBenjamin Herrenschmidt #include "hw/ppc/pnv.h"
270722d05aSBenjamin Herrenschmidt #include "hw/ppc/pnv_xscom.h"
280722d05aSBenjamin Herrenschmidt #include "hw/ppc/pnv_occ.h"
290722d05aSBenjamin Herrenschmidt
300722d05aSBenjamin Herrenschmidt #define OCB_OCI_OCCMISC 0x4020
310722d05aSBenjamin Herrenschmidt #define OCB_OCI_OCCMISC_AND 0x4021
320722d05aSBenjamin Herrenschmidt #define OCB_OCI_OCCMISC_OR 0x4022
330722d05aSBenjamin Herrenschmidt
34f3db8266SBalamuruhan S /* OCC sensors */
35f3db8266SBalamuruhan S #define OCC_SENSOR_DATA_BLOCK_OFFSET 0x580000
36f3db8266SBalamuruhan S #define OCC_SENSOR_DATA_VALID 0x580001
37f3db8266SBalamuruhan S #define OCC_SENSOR_DATA_VERSION 0x580002
38f3db8266SBalamuruhan S #define OCC_SENSOR_DATA_READING_VERSION 0x580004
39f3db8266SBalamuruhan S #define OCC_SENSOR_DATA_NR_SENSORS 0x580008
40f3db8266SBalamuruhan S #define OCC_SENSOR_DATA_NAMES_OFFSET 0x580010
41f3db8266SBalamuruhan S #define OCC_SENSOR_DATA_READING_PING_OFFSET 0x580014
42f3db8266SBalamuruhan S #define OCC_SENSOR_DATA_READING_PONG_OFFSET 0x58000c
43f3db8266SBalamuruhan S #define OCC_SENSOR_DATA_NAME_LENGTH 0x58000d
44f3db8266SBalamuruhan S #define OCC_SENSOR_NAME_STRUCTURE_TYPE 0x580023
45f3db8266SBalamuruhan S #define OCC_SENSOR_LOC_CORE 0x580022
46f3db8266SBalamuruhan S #define OCC_SENSOR_LOC_GPU 0x580020
47f3db8266SBalamuruhan S #define OCC_SENSOR_TYPE_POWER 0x580003
48f3db8266SBalamuruhan S #define OCC_SENSOR_NAME 0x580005
49f3db8266SBalamuruhan S #define HWMON_SENSORS_MASK 0x58001e
50f3db8266SBalamuruhan S #define SLW_IMAGE_BASE 0x0
51f3db8266SBalamuruhan S
pnv_occ_set_misc(PnvOCC * occ,uint64_t val)520722d05aSBenjamin Herrenschmidt static void pnv_occ_set_misc(PnvOCC *occ, uint64_t val)
530722d05aSBenjamin Herrenschmidt {
540722d05aSBenjamin Herrenschmidt bool irq_state;
550722d05aSBenjamin Herrenschmidt
560722d05aSBenjamin Herrenschmidt val &= 0xffff000000000000ull;
570722d05aSBenjamin Herrenschmidt
580722d05aSBenjamin Herrenschmidt occ->occmisc = val;
590722d05aSBenjamin Herrenschmidt irq_state = !!(val >> 63);
60b0ae5c69SCédric Le Goater qemu_set_irq(occ->psi_irq, irq_state);
610722d05aSBenjamin Herrenschmidt }
620722d05aSBenjamin Herrenschmidt
pnv_occ_power8_xscom_read(void * opaque,hwaddr addr,unsigned size)633233838cSCédric Le Goater static uint64_t pnv_occ_power8_xscom_read(void *opaque, hwaddr addr,
643233838cSCédric Le Goater unsigned size)
650722d05aSBenjamin Herrenschmidt {
660722d05aSBenjamin Herrenschmidt PnvOCC *occ = PNV_OCC(opaque);
670722d05aSBenjamin Herrenschmidt uint32_t offset = addr >> 3;
680722d05aSBenjamin Herrenschmidt uint64_t val = 0;
690722d05aSBenjamin Herrenschmidt
700722d05aSBenjamin Herrenschmidt switch (offset) {
710722d05aSBenjamin Herrenschmidt case OCB_OCI_OCCMISC:
720722d05aSBenjamin Herrenschmidt val = occ->occmisc;
730722d05aSBenjamin Herrenschmidt break;
740722d05aSBenjamin Herrenschmidt default:
750722d05aSBenjamin Herrenschmidt qemu_log_mask(LOG_UNIMP, "OCC Unimplemented register: Ox%"
763233838cSCédric Le Goater HWADDR_PRIx "\n", addr >> 3);
770722d05aSBenjamin Herrenschmidt }
780722d05aSBenjamin Herrenschmidt return val;
790722d05aSBenjamin Herrenschmidt }
800722d05aSBenjamin Herrenschmidt
pnv_occ_power8_xscom_write(void * opaque,hwaddr addr,uint64_t val,unsigned size)813233838cSCédric Le Goater static void pnv_occ_power8_xscom_write(void *opaque, hwaddr addr,
820722d05aSBenjamin Herrenschmidt uint64_t val, unsigned size)
830722d05aSBenjamin Herrenschmidt {
840722d05aSBenjamin Herrenschmidt PnvOCC *occ = PNV_OCC(opaque);
850722d05aSBenjamin Herrenschmidt uint32_t offset = addr >> 3;
860722d05aSBenjamin Herrenschmidt
870722d05aSBenjamin Herrenschmidt switch (offset) {
880722d05aSBenjamin Herrenschmidt case OCB_OCI_OCCMISC_AND:
890722d05aSBenjamin Herrenschmidt pnv_occ_set_misc(occ, occ->occmisc & val);
900722d05aSBenjamin Herrenschmidt break;
910722d05aSBenjamin Herrenschmidt case OCB_OCI_OCCMISC_OR:
920722d05aSBenjamin Herrenschmidt pnv_occ_set_misc(occ, occ->occmisc | val);
930722d05aSBenjamin Herrenschmidt break;
940722d05aSBenjamin Herrenschmidt case OCB_OCI_OCCMISC:
950722d05aSBenjamin Herrenschmidt pnv_occ_set_misc(occ, val);
960722d05aSBenjamin Herrenschmidt break;
970722d05aSBenjamin Herrenschmidt default:
980722d05aSBenjamin Herrenschmidt qemu_log_mask(LOG_UNIMP, "OCC Unimplemented register: Ox%"
993233838cSCédric Le Goater HWADDR_PRIx "\n", addr >> 3);
1000722d05aSBenjamin Herrenschmidt }
1010722d05aSBenjamin Herrenschmidt }
1020722d05aSBenjamin Herrenschmidt
pnv_occ_common_area_read(void * opaque,hwaddr addr,unsigned width)103f3db8266SBalamuruhan S static uint64_t pnv_occ_common_area_read(void *opaque, hwaddr addr,
104f3db8266SBalamuruhan S unsigned width)
105f3db8266SBalamuruhan S {
106f3db8266SBalamuruhan S switch (addr) {
107f3db8266SBalamuruhan S /*
108f3db8266SBalamuruhan S * occ-sensor sanity check that asserts the sensor
109f3db8266SBalamuruhan S * header block
110f3db8266SBalamuruhan S */
111f3db8266SBalamuruhan S case OCC_SENSOR_DATA_BLOCK_OFFSET:
112f3db8266SBalamuruhan S case OCC_SENSOR_DATA_VALID:
113f3db8266SBalamuruhan S case OCC_SENSOR_DATA_VERSION:
114f3db8266SBalamuruhan S case OCC_SENSOR_DATA_READING_VERSION:
115f3db8266SBalamuruhan S case OCC_SENSOR_DATA_NR_SENSORS:
116f3db8266SBalamuruhan S case OCC_SENSOR_DATA_NAMES_OFFSET:
117f3db8266SBalamuruhan S case OCC_SENSOR_DATA_READING_PING_OFFSET:
118f3db8266SBalamuruhan S case OCC_SENSOR_DATA_READING_PONG_OFFSET:
119f3db8266SBalamuruhan S case OCC_SENSOR_NAME_STRUCTURE_TYPE:
120f3db8266SBalamuruhan S return 1;
121f3db8266SBalamuruhan S case OCC_SENSOR_DATA_NAME_LENGTH:
122f3db8266SBalamuruhan S return 0x30;
123f3db8266SBalamuruhan S case OCC_SENSOR_LOC_CORE:
124f3db8266SBalamuruhan S return 0x0040;
125f3db8266SBalamuruhan S case OCC_SENSOR_TYPE_POWER:
126f3db8266SBalamuruhan S return 0x0080;
127f3db8266SBalamuruhan S case OCC_SENSOR_NAME:
128f3db8266SBalamuruhan S return 0x1000;
129f3db8266SBalamuruhan S case HWMON_SENSORS_MASK:
130f3db8266SBalamuruhan S case OCC_SENSOR_LOC_GPU:
131f3db8266SBalamuruhan S return 0x8e00;
132f3db8266SBalamuruhan S case SLW_IMAGE_BASE:
133f3db8266SBalamuruhan S return 0x1000000000000000;
134f3db8266SBalamuruhan S }
135f3db8266SBalamuruhan S return 0;
136f3db8266SBalamuruhan S }
137f3db8266SBalamuruhan S
pnv_occ_common_area_write(void * opaque,hwaddr addr,uint64_t val,unsigned width)138f3db8266SBalamuruhan S static void pnv_occ_common_area_write(void *opaque, hwaddr addr,
139f3db8266SBalamuruhan S uint64_t val, unsigned width)
140f3db8266SBalamuruhan S {
141f3db8266SBalamuruhan S /* callback function defined to occ common area write */
142f3db8266SBalamuruhan S return;
143f3db8266SBalamuruhan S }
144f3db8266SBalamuruhan S
1453233838cSCédric Le Goater static const MemoryRegionOps pnv_occ_power8_xscom_ops = {
1463233838cSCédric Le Goater .read = pnv_occ_power8_xscom_read,
1473233838cSCédric Le Goater .write = pnv_occ_power8_xscom_write,
1480722d05aSBenjamin Herrenschmidt .valid.min_access_size = 8,
1490722d05aSBenjamin Herrenschmidt .valid.max_access_size = 8,
1500722d05aSBenjamin Herrenschmidt .impl.min_access_size = 8,
1510722d05aSBenjamin Herrenschmidt .impl.max_access_size = 8,
1520722d05aSBenjamin Herrenschmidt .endianness = DEVICE_BIG_ENDIAN,
1530722d05aSBenjamin Herrenschmidt };
1540722d05aSBenjamin Herrenschmidt
155f3db8266SBalamuruhan S const MemoryRegionOps pnv_occ_sram_ops = {
156f3db8266SBalamuruhan S .read = pnv_occ_common_area_read,
157f3db8266SBalamuruhan S .write = pnv_occ_common_area_write,
158f3db8266SBalamuruhan S .valid.min_access_size = 1,
159f3db8266SBalamuruhan S .valid.max_access_size = 8,
160f3db8266SBalamuruhan S .impl.min_access_size = 1,
161f3db8266SBalamuruhan S .impl.max_access_size = 8,
162f3db8266SBalamuruhan S .endianness = DEVICE_BIG_ENDIAN,
163f3db8266SBalamuruhan S };
164f3db8266SBalamuruhan S
pnv_occ_power8_class_init(ObjectClass * klass,void * data)1653233838cSCédric Le Goater static void pnv_occ_power8_class_init(ObjectClass *klass, void *data)
1663233838cSCédric Le Goater {
1673233838cSCédric Le Goater PnvOCCClass *poc = PNV_OCC_CLASS(klass);
1683233838cSCédric Le Goater
1693233838cSCédric Le Goater poc->xscom_size = PNV_XSCOM_OCC_SIZE;
1703233838cSCédric Le Goater poc->xscom_ops = &pnv_occ_power8_xscom_ops;
1713233838cSCédric Le Goater }
1723233838cSCédric Le Goater
1733233838cSCédric Le Goater static const TypeInfo pnv_occ_power8_type_info = {
1743233838cSCédric Le Goater .name = TYPE_PNV8_OCC,
1753233838cSCédric Le Goater .parent = TYPE_PNV_OCC,
1763233838cSCédric Le Goater .instance_size = sizeof(PnvOCC),
1773233838cSCédric Le Goater .class_init = pnv_occ_power8_class_init,
1783233838cSCédric Le Goater };
1790722d05aSBenjamin Herrenschmidt
1806598a70dSCédric Le Goater #define P9_OCB_OCI_OCCMISC 0x6080
1816598a70dSCédric Le Goater #define P9_OCB_OCI_OCCMISC_CLEAR 0x6081
1826598a70dSCédric Le Goater #define P9_OCB_OCI_OCCMISC_OR 0x6082
1836598a70dSCédric Le Goater
1846598a70dSCédric Le Goater
pnv_occ_power9_xscom_read(void * opaque,hwaddr addr,unsigned size)1856598a70dSCédric Le Goater static uint64_t pnv_occ_power9_xscom_read(void *opaque, hwaddr addr,
1866598a70dSCédric Le Goater unsigned size)
1876598a70dSCédric Le Goater {
1886598a70dSCédric Le Goater PnvOCC *occ = PNV_OCC(opaque);
1896598a70dSCédric Le Goater uint32_t offset = addr >> 3;
1906598a70dSCédric Le Goater uint64_t val = 0;
1916598a70dSCédric Le Goater
1926598a70dSCédric Le Goater switch (offset) {
1936598a70dSCédric Le Goater case P9_OCB_OCI_OCCMISC:
1946598a70dSCédric Le Goater val = occ->occmisc;
1956598a70dSCédric Le Goater break;
1966598a70dSCédric Le Goater default:
1976598a70dSCédric Le Goater qemu_log_mask(LOG_UNIMP, "OCC Unimplemented register: Ox%"
1986598a70dSCédric Le Goater HWADDR_PRIx "\n", addr >> 3);
1996598a70dSCédric Le Goater }
2006598a70dSCédric Le Goater return val;
2016598a70dSCédric Le Goater }
2026598a70dSCédric Le Goater
pnv_occ_power9_xscom_write(void * opaque,hwaddr addr,uint64_t val,unsigned size)2036598a70dSCédric Le Goater static void pnv_occ_power9_xscom_write(void *opaque, hwaddr addr,
2046598a70dSCédric Le Goater uint64_t val, unsigned size)
2056598a70dSCédric Le Goater {
2066598a70dSCédric Le Goater PnvOCC *occ = PNV_OCC(opaque);
2076598a70dSCédric Le Goater uint32_t offset = addr >> 3;
2086598a70dSCédric Le Goater
2096598a70dSCédric Le Goater switch (offset) {
2106598a70dSCédric Le Goater case P9_OCB_OCI_OCCMISC_CLEAR:
2116598a70dSCédric Le Goater pnv_occ_set_misc(occ, 0);
2126598a70dSCédric Le Goater break;
2136598a70dSCédric Le Goater case P9_OCB_OCI_OCCMISC_OR:
2146598a70dSCédric Le Goater pnv_occ_set_misc(occ, occ->occmisc | val);
2156598a70dSCédric Le Goater break;
2166598a70dSCédric Le Goater case P9_OCB_OCI_OCCMISC:
2176598a70dSCédric Le Goater pnv_occ_set_misc(occ, val);
2186598a70dSCédric Le Goater break;
2196598a70dSCédric Le Goater default:
2206598a70dSCédric Le Goater qemu_log_mask(LOG_UNIMP, "OCC Unimplemented register: Ox%"
2216598a70dSCédric Le Goater HWADDR_PRIx "\n", addr >> 3);
2226598a70dSCédric Le Goater }
2236598a70dSCédric Le Goater }
2246598a70dSCédric Le Goater
2256598a70dSCédric Le Goater static const MemoryRegionOps pnv_occ_power9_xscom_ops = {
2266598a70dSCédric Le Goater .read = pnv_occ_power9_xscom_read,
2276598a70dSCédric Le Goater .write = pnv_occ_power9_xscom_write,
2286598a70dSCédric Le Goater .valid.min_access_size = 8,
2296598a70dSCédric Le Goater .valid.max_access_size = 8,
2306598a70dSCédric Le Goater .impl.min_access_size = 8,
2316598a70dSCédric Le Goater .impl.max_access_size = 8,
2326598a70dSCédric Le Goater .endianness = DEVICE_BIG_ENDIAN,
2336598a70dSCédric Le Goater };
2346598a70dSCédric Le Goater
pnv_occ_power9_class_init(ObjectClass * klass,void * data)2356598a70dSCédric Le Goater static void pnv_occ_power9_class_init(ObjectClass *klass, void *data)
2366598a70dSCédric Le Goater {
2376598a70dSCédric Le Goater PnvOCCClass *poc = PNV_OCC_CLASS(klass);
2388bf682a3SCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass);
2396598a70dSCédric Le Goater
2408bf682a3SCédric Le Goater dc->desc = "PowerNV OCC Controller (POWER9)";
2416598a70dSCédric Le Goater poc->xscom_size = PNV9_XSCOM_OCC_SIZE;
2426598a70dSCédric Le Goater poc->xscom_ops = &pnv_occ_power9_xscom_ops;
2436598a70dSCédric Le Goater }
2446598a70dSCédric Le Goater
2456598a70dSCédric Le Goater static const TypeInfo pnv_occ_power9_type_info = {
2466598a70dSCédric Le Goater .name = TYPE_PNV9_OCC,
2476598a70dSCédric Le Goater .parent = TYPE_PNV_OCC,
2486598a70dSCédric Le Goater .instance_size = sizeof(PnvOCC),
2496598a70dSCédric Le Goater .class_init = pnv_occ_power9_class_init,
2506598a70dSCédric Le Goater };
2516598a70dSCédric Le Goater
pnv_occ_power10_class_init(ObjectClass * klass,void * data)2528bf682a3SCédric Le Goater static void pnv_occ_power10_class_init(ObjectClass *klass, void *data)
2538bf682a3SCédric Le Goater {
2548bf682a3SCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass);
2558bf682a3SCédric Le Goater
2568bf682a3SCédric Le Goater dc->desc = "PowerNV OCC Controller (POWER10)";
2578bf682a3SCédric Le Goater }
2588bf682a3SCédric Le Goater
2598bf682a3SCédric Le Goater static const TypeInfo pnv_occ_power10_type_info = {
2608bf682a3SCédric Le Goater .name = TYPE_PNV10_OCC,
2618bf682a3SCédric Le Goater .parent = TYPE_PNV9_OCC,
2628bf682a3SCédric Le Goater .class_init = pnv_occ_power10_class_init,
2638bf682a3SCédric Le Goater };
2648bf682a3SCédric Le Goater
pnv_occ_realize(DeviceState * dev,Error ** errp)2650722d05aSBenjamin Herrenschmidt static void pnv_occ_realize(DeviceState *dev, Error **errp)
2660722d05aSBenjamin Herrenschmidt {
2670722d05aSBenjamin Herrenschmidt PnvOCC *occ = PNV_OCC(dev);
2683233838cSCédric Le Goater PnvOCCClass *poc = PNV_OCC_GET_CLASS(occ);
269ee3d2713SGreg Kurz
2700722d05aSBenjamin Herrenschmidt occ->occmisc = 0;
2710722d05aSBenjamin Herrenschmidt
2720722d05aSBenjamin Herrenschmidt /* XScom region for OCC registers */
2733233838cSCédric Le Goater pnv_xscom_region_init(&occ->xscom_regs, OBJECT(dev), poc->xscom_ops,
2743233838cSCédric Le Goater occ, "xscom-occ", poc->xscom_size);
275f3db8266SBalamuruhan S
2763a1b70b6SCédric Le Goater /* OCC common area mmio region for OCC SRAM registers */
2773a1b70b6SCédric Le Goater memory_region_init_io(&occ->sram_regs, OBJECT(dev), &pnv_occ_sram_ops,
2783a1b70b6SCédric Le Goater occ, "occ-common-area",
2793a1b70b6SCédric Le Goater PNV_OCC_SENSOR_DATA_BLOCK_SIZE);
2800722d05aSBenjamin Herrenschmidt
281*7d5b0d68SPhilippe Mathieu-Daudé qdev_init_gpio_out(dev, &occ->psi_irq, 1);
282b0ae5c69SCédric Le Goater }
283ee3d2713SGreg Kurz
pnv_occ_class_init(ObjectClass * klass,void * data)2840722d05aSBenjamin Herrenschmidt static void pnv_occ_class_init(ObjectClass *klass, void *data)
2850722d05aSBenjamin Herrenschmidt {
2860722d05aSBenjamin Herrenschmidt DeviceClass *dc = DEVICE_CLASS(klass);
2870722d05aSBenjamin Herrenschmidt
2880722d05aSBenjamin Herrenschmidt dc->realize = pnv_occ_realize;
2893233838cSCédric Le Goater dc->desc = "PowerNV OCC Controller";
29023a782ebSCédric Le Goater dc->user_creatable = false;
2910722d05aSBenjamin Herrenschmidt }
2920722d05aSBenjamin Herrenschmidt
2930722d05aSBenjamin Herrenschmidt static const TypeInfo pnv_occ_type_info = {
2940722d05aSBenjamin Herrenschmidt .name = TYPE_PNV_OCC,
2950722d05aSBenjamin Herrenschmidt .parent = TYPE_DEVICE,
2960722d05aSBenjamin Herrenschmidt .instance_size = sizeof(PnvOCC),
2970722d05aSBenjamin Herrenschmidt .class_init = pnv_occ_class_init,
2983233838cSCédric Le Goater .class_size = sizeof(PnvOCCClass),
2993233838cSCédric Le Goater .abstract = true,
3000722d05aSBenjamin Herrenschmidt };
3010722d05aSBenjamin Herrenschmidt
pnv_occ_register_types(void)3020722d05aSBenjamin Herrenschmidt static void pnv_occ_register_types(void)
3030722d05aSBenjamin Herrenschmidt {
3040722d05aSBenjamin Herrenschmidt type_register_static(&pnv_occ_type_info);
3053233838cSCédric Le Goater type_register_static(&pnv_occ_power8_type_info);
3066598a70dSCédric Le Goater type_register_static(&pnv_occ_power9_type_info);
3078bf682a3SCédric Le Goater type_register_static(&pnv_occ_power10_type_info);
3080722d05aSBenjamin Herrenschmidt }
3090722d05aSBenjamin Herrenschmidt
3103233838cSCédric Le Goater type_init(pnv_occ_register_types);
311