xref: /openbmc/qemu/hw/ppc/pnv_homer.c (revision ab9056ff)
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 "qapi/error.h"
21 #include "exec/hwaddr.h"
22 #include "exec/memory.h"
23 #include "sysemu/cpus.h"
24 #include "hw/qdev-core.h"
25 #include "hw/ppc/pnv.h"
26 #include "hw/ppc/pnv_homer.h"
27 
28 
29 static bool core_max_array(PnvHomer *homer, hwaddr addr)
30 {
31     int i;
32     PnvHomerClass *hmrc = PNV_HOMER_GET_CLASS(homer);
33 
34     for (i = 0; i <= homer->chip->nr_cores; i++) {
35         if (addr == (hmrc->core_max_base + i)) {
36             return true;
37        }
38     }
39     return false;
40 }
41 
42 /* P8 Pstate table */
43 
44 #define PNV8_OCC_PSTATE_VERSION          0x1f8001
45 #define PNV8_OCC_PSTATE_MIN              0x1f8003
46 #define PNV8_OCC_PSTATE_VALID            0x1f8000
47 #define PNV8_OCC_PSTATE_THROTTLE         0x1f8002
48 #define PNV8_OCC_PSTATE_NOM              0x1f8004
49 #define PNV8_OCC_PSTATE_TURBO            0x1f8005
50 #define PNV8_OCC_PSTATE_ULTRA_TURBO      0x1f8006
51 #define PNV8_OCC_PSTATE_DATA             0x1f8008
52 #define PNV8_OCC_PSTATE_ID_ZERO          0x1f8010
53 #define PNV8_OCC_PSTATE_ID_ONE           0x1f8018
54 #define PNV8_OCC_PSTATE_ID_TWO           0x1f8020
55 #define PNV8_OCC_VDD_VOLTAGE_IDENTIFIER  0x1f8012
56 #define PNV8_OCC_VCS_VOLTAGE_IDENTIFIER  0x1f8013
57 #define PNV8_OCC_PSTATE_ZERO_FREQUENCY   0x1f8014
58 #define PNV8_OCC_PSTATE_ONE_FREQUENCY    0x1f801c
59 #define PNV8_OCC_PSTATE_TWO_FREQUENCY    0x1f8024
60 #define PNV8_CORE_MAX_BASE               0x1f8810
61 
62 
63 static uint64_t pnv_power8_homer_read(void *opaque, hwaddr addr,
64                                       unsigned size)
65 {
66     PnvHomer *homer = PNV_HOMER(opaque);
67 
68     switch (addr) {
69     case PNV8_OCC_PSTATE_VERSION:
70     case PNV8_OCC_PSTATE_MIN:
71     case PNV8_OCC_PSTATE_ID_ZERO:
72         return 0;
73     case PNV8_OCC_PSTATE_VALID:
74     case PNV8_OCC_PSTATE_THROTTLE:
75     case PNV8_OCC_PSTATE_NOM:
76     case PNV8_OCC_PSTATE_TURBO:
77     case PNV8_OCC_PSTATE_ID_ONE:
78     case PNV8_OCC_VDD_VOLTAGE_IDENTIFIER:
79     case PNV8_OCC_VCS_VOLTAGE_IDENTIFIER:
80         return 1;
81     case PNV8_OCC_PSTATE_ULTRA_TURBO:
82     case PNV8_OCC_PSTATE_ID_TWO:
83         return 2;
84     case PNV8_OCC_PSTATE_DATA:
85         return 0x1000000000000000;
86     /* P8 frequency for 0, 1, and 2 pstates */
87     case PNV8_OCC_PSTATE_ZERO_FREQUENCY:
88     case PNV8_OCC_PSTATE_ONE_FREQUENCY:
89     case PNV8_OCC_PSTATE_TWO_FREQUENCY:
90         return 3000;
91     }
92     /* pstate table core max array */
93     if (core_max_array(homer, addr)) {
94         return 1;
95     }
96     return 0;
97 }
98 
99 static void pnv_power8_homer_write(void *opaque, hwaddr addr,
100                                    uint64_t val, unsigned size)
101 {
102     /* callback function defined to homer write */
103     return;
104 }
105 
106 static const MemoryRegionOps pnv_power8_homer_ops = {
107     .read = pnv_power8_homer_read,
108     .write = pnv_power8_homer_write,
109     .valid.min_access_size = 1,
110     .valid.max_access_size = 8,
111     .impl.min_access_size = 1,
112     .impl.max_access_size = 8,
113     .endianness = DEVICE_BIG_ENDIAN,
114 };
115 
116 static void pnv_homer_power8_class_init(ObjectClass *klass, void *data)
117 {
118     PnvHomerClass *homer = PNV_HOMER_CLASS(klass);
119 
120     homer->homer_size = PNV_HOMER_SIZE;
121     homer->homer_ops = &pnv_power8_homer_ops;
122     homer->core_max_base = PNV8_CORE_MAX_BASE;
123 }
124 
125 static const TypeInfo pnv_homer_power8_type_info = {
126     .name          = TYPE_PNV8_HOMER,
127     .parent        = TYPE_PNV_HOMER,
128     .instance_size = sizeof(PnvHomer),
129     .class_init    = pnv_homer_power8_class_init,
130 };
131 
132 /* P9 Pstate table */
133 
134 #define PNV9_OCC_PSTATE_ID_ZERO          0xe2018
135 #define PNV9_OCC_PSTATE_ID_ONE           0xe2020
136 #define PNV9_OCC_PSTATE_ID_TWO           0xe2028
137 #define PNV9_OCC_PSTATE_DATA             0xe2000
138 #define PNV9_OCC_PSTATE_DATA_AREA        0xe2008
139 #define PNV9_OCC_PSTATE_MIN              0xe2003
140 #define PNV9_OCC_PSTATE_NOM              0xe2004
141 #define PNV9_OCC_PSTATE_TURBO            0xe2005
142 #define PNV9_OCC_PSTATE_ULTRA_TURBO      0xe2818
143 #define PNV9_OCC_MAX_PSTATE_ULTRA_TURBO  0xe2006
144 #define PNV9_OCC_PSTATE_MAJOR_VERSION    0xe2001
145 #define PNV9_OCC_OPAL_RUNTIME_DATA       0xe2b85
146 #define PNV9_CHIP_HOMER_IMAGE_POINTER    0x200008
147 #define PNV9_CHIP_HOMER_BASE             0x0
148 #define PNV9_OCC_PSTATE_ZERO_FREQUENCY   0xe201c
149 #define PNV9_OCC_PSTATE_ONE_FREQUENCY    0xe2024
150 #define PNV9_OCC_PSTATE_TWO_FREQUENCY    0xe202c
151 #define PNV9_OCC_ROLE_MASTER_OR_SLAVE    0xe2002
152 #define PNV9_CORE_MAX_BASE               0xe2819
153 
154 
155 static uint64_t pnv_power9_homer_read(void *opaque, hwaddr addr,
156                                       unsigned size)
157 {
158     PnvHomer *homer = PNV_HOMER(opaque);
159 
160     switch (addr) {
161     case PNV9_OCC_MAX_PSTATE_ULTRA_TURBO:
162     case PNV9_OCC_PSTATE_ID_ZERO:
163         return 0;
164     case PNV9_OCC_PSTATE_DATA:
165     case PNV9_OCC_ROLE_MASTER_OR_SLAVE:
166     case PNV9_OCC_PSTATE_NOM:
167     case PNV9_OCC_PSTATE_TURBO:
168     case PNV9_OCC_PSTATE_ID_ONE:
169     case PNV9_OCC_PSTATE_ULTRA_TURBO:
170     case PNV9_OCC_OPAL_RUNTIME_DATA:
171         return 1;
172     case PNV9_OCC_PSTATE_MIN:
173     case PNV9_OCC_PSTATE_ID_TWO:
174         return 2;
175 
176     /* 3000 khz frequency for 0, 1, and 2 pstates */
177     case PNV9_OCC_PSTATE_ZERO_FREQUENCY:
178     case PNV9_OCC_PSTATE_ONE_FREQUENCY:
179     case PNV9_OCC_PSTATE_TWO_FREQUENCY:
180         return 3000;
181     case PNV9_OCC_PSTATE_MAJOR_VERSION:
182         return 0x90;
183     case PNV9_CHIP_HOMER_BASE:
184     case PNV9_OCC_PSTATE_DATA_AREA:
185     case PNV9_CHIP_HOMER_IMAGE_POINTER:
186         return 0x1000000000000000;
187     }
188     /* pstate table core max array */
189     if (core_max_array(homer, addr)) {
190         return 1;
191     }
192     return 0;
193 }
194 
195 static void pnv_power9_homer_write(void *opaque, hwaddr addr,
196                                    uint64_t val, unsigned size)
197 {
198     /* callback function defined to homer write */
199     return;
200 }
201 
202 static const MemoryRegionOps pnv_power9_homer_ops = {
203     .read = pnv_power9_homer_read,
204     .write = pnv_power9_homer_write,
205     .valid.min_access_size = 1,
206     .valid.max_access_size = 8,
207     .impl.min_access_size = 1,
208     .impl.max_access_size = 8,
209     .endianness = DEVICE_BIG_ENDIAN,
210 };
211 
212 static void pnv_homer_power9_class_init(ObjectClass *klass, void *data)
213 {
214     PnvHomerClass *homer = PNV_HOMER_CLASS(klass);
215 
216     homer->homer_size = PNV9_HOMER_SIZE;
217     homer->homer_ops = &pnv_power9_homer_ops;
218     homer->core_max_base = PNV9_CORE_MAX_BASE;
219 }
220 
221 static const TypeInfo pnv_homer_power9_type_info = {
222     .name          = TYPE_PNV9_HOMER,
223     .parent        = TYPE_PNV_HOMER,
224     .instance_size = sizeof(PnvHomer),
225     .class_init    = pnv_homer_power9_class_init,
226 };
227 
228 static void pnv_homer_realize(DeviceState *dev, Error **errp)
229 {
230     PnvHomer *homer = PNV_HOMER(dev);
231     PnvHomerClass *hmrc = PNV_HOMER_GET_CLASS(homer);
232     Object *obj;
233     Error *local_err = NULL;
234 
235     obj = object_property_get_link(OBJECT(dev), "chip", &local_err);
236     if (!obj) {
237         error_propagate(errp, local_err);
238         error_prepend(errp, "required link 'chip' not found: ");
239         return;
240     }
241     homer->chip = PNV_CHIP(obj);
242     /* homer region */
243     memory_region_init_io(&homer->regs, OBJECT(dev),
244                           hmrc->homer_ops, homer, "homer-main-memory",
245                           hmrc->homer_size);
246 }
247 
248 static void pnv_homer_class_init(ObjectClass *klass, void *data)
249 {
250     DeviceClass *dc = DEVICE_CLASS(klass);
251 
252     dc->realize = pnv_homer_realize;
253     dc->desc = "PowerNV HOMER Memory";
254 }
255 
256 static const TypeInfo pnv_homer_type_info = {
257     .name          = TYPE_PNV_HOMER,
258     .parent        = TYPE_DEVICE,
259     .instance_size = sizeof(PnvHomer),
260     .class_init    = pnv_homer_class_init,
261     .class_size    = sizeof(PnvHomerClass),
262     .abstract      = true,
263 };
264 
265 static void pnv_homer_register_types(void)
266 {
267     type_register_static(&pnv_homer_type_info);
268     type_register_static(&pnv_homer_power8_type_info);
269     type_register_static(&pnv_homer_power9_type_info);
270 }
271 
272 type_init(pnv_homer_register_types);
273