xref: /qemu/hw/ppc/pnv_homer.c (revision 06b40d250ecfa1633209c2e431a7a38acfd03a98)
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 "system/memory.h"
24 #include "system/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_chip.h"
29 #include "hw/ppc/pnv_homer.h"
30 #include "hw/ppc/pnv_xscom.h"
31 
32 /* P8 PBA BARs */
33 #define PBA_BAR0                     0x00
34 #define PBA_BAR1                     0x01
35 #define PBA_BAR2                     0x02
36 #define PBA_BAR3                     0x03
37 #define PBA_BARMASK0                 0x04
38 #define PBA_BARMASK1                 0x05
39 #define PBA_BARMASK2                 0x06
40 #define PBA_BARMASK3                 0x07
41 
pnv_homer_power8_pba_read(void * opaque,hwaddr addr,unsigned size)42 static uint64_t pnv_homer_power8_pba_read(void *opaque, hwaddr addr,
43                                           unsigned size)
44 {
45     PnvHomer *homer = PNV_HOMER(opaque);
46     PnvHomerClass *hmrc = PNV_HOMER_GET_CLASS(homer);
47     uint32_t reg = addr >> 3;
48     uint64_t val = 0;
49 
50     switch (reg) {
51     case PBA_BAR0:
52         val = homer->base;
53         break;
54     case PBA_BARMASK0: /* P8 homer region mask */
55         val = (hmrc->size - 1) & 0x300000;
56         break;
57     case PBA_BAR3: /* P8 occ common area */
58         val = PNV_OCC_COMMON_AREA_BASE;
59         break;
60     case PBA_BARMASK3: /* P8 occ common area mask */
61         val = (PNV_OCC_COMMON_AREA_SIZE - 1) & 0x700000;
62         break;
63     default:
64         qemu_log_mask(LOG_UNIMP, "PBA: read to unimplemented register: Ox%"
65                       HWADDR_PRIx "\n", addr >> 3);
66     }
67     return val;
68 }
69 
pnv_homer_power8_pba_write(void * opaque,hwaddr addr,uint64_t val,unsigned size)70 static void pnv_homer_power8_pba_write(void *opaque, hwaddr addr,
71                                          uint64_t val, unsigned size)
72 {
73     qemu_log_mask(LOG_UNIMP, "PBA: write to unimplemented register: Ox%"
74                   HWADDR_PRIx "\n", addr >> 3);
75 }
76 
77 static const MemoryRegionOps pnv_homer_power8_pba_ops = {
78     .read = pnv_homer_power8_pba_read,
79     .write = pnv_homer_power8_pba_write,
80     .valid.min_access_size = 8,
81     .valid.max_access_size = 8,
82     .impl.min_access_size = 8,
83     .impl.max_access_size = 8,
84     .endianness = DEVICE_BIG_ENDIAN,
85 };
86 
pnv_homer_power8_get_base(PnvChip * chip)87 static hwaddr pnv_homer_power8_get_base(PnvChip *chip)
88 {
89     return PNV_HOMER_BASE(chip);
90 }
91 
pnv_homer_power8_class_init(ObjectClass * klass,const void * data)92 static void pnv_homer_power8_class_init(ObjectClass *klass, const void *data)
93 {
94     PnvHomerClass *homer = PNV_HOMER_CLASS(klass);
95 
96     homer->get_base = pnv_homer_power8_get_base;
97     homer->size = PNV_HOMER_SIZE;
98     homer->pba_size = PNV_XSCOM_PBA_SIZE;
99     homer->pba_ops = &pnv_homer_power8_pba_ops;
100 }
101 
102 static const TypeInfo pnv_homer_power8_type_info = {
103     .name          = TYPE_PNV8_HOMER,
104     .parent        = TYPE_PNV_HOMER,
105     .instance_size = sizeof(PnvHomer),
106     .class_init    = pnv_homer_power8_class_init,
107 };
108 
pnv_homer_power9_pba_read(void * opaque,hwaddr addr,unsigned size)109 static uint64_t pnv_homer_power9_pba_read(void *opaque, hwaddr addr,
110                                           unsigned size)
111 {
112     PnvHomer *homer = PNV_HOMER(opaque);
113     PnvHomerClass *hmrc = PNV_HOMER_GET_CLASS(homer);
114     uint32_t reg = addr >> 3;
115     uint64_t val = 0;
116 
117     switch (reg) {
118     case PBA_BAR0:
119         val = homer->base;
120         break;
121     case PBA_BARMASK0: /* P9 homer region mask */
122         val = (hmrc->size - 1) & 0x300000;
123         break;
124     case PBA_BAR2: /* P9 occ common area */
125         val = PNV9_OCC_COMMON_AREA_BASE;
126         break;
127     case PBA_BARMASK2: /* P9 occ common area size */
128         val = (PNV9_OCC_COMMON_AREA_SIZE - 1) & 0x700000;
129         break;
130     default:
131         qemu_log_mask(LOG_UNIMP, "PBA: read to unimplemented register: Ox%"
132                       HWADDR_PRIx "\n", addr >> 3);
133     }
134     return val;
135 }
136 
pnv_homer_power9_pba_write(void * opaque,hwaddr addr,uint64_t val,unsigned size)137 static void pnv_homer_power9_pba_write(void *opaque, hwaddr addr,
138                                          uint64_t val, unsigned size)
139 {
140     qemu_log_mask(LOG_UNIMP, "PBA: write to unimplemented register: Ox%"
141                   HWADDR_PRIx "\n", addr >> 3);
142 }
143 
144 static const MemoryRegionOps pnv_homer_power9_pba_ops = {
145     .read = pnv_homer_power9_pba_read,
146     .write = pnv_homer_power9_pba_write,
147     .valid.min_access_size = 8,
148     .valid.max_access_size = 8,
149     .impl.min_access_size = 8,
150     .impl.max_access_size = 8,
151     .endianness = DEVICE_BIG_ENDIAN,
152 };
153 
pnv_homer_power9_get_base(PnvChip * chip)154 static hwaddr pnv_homer_power9_get_base(PnvChip *chip)
155 {
156     return PNV9_HOMER_BASE(chip);
157 }
158 
pnv_homer_power9_class_init(ObjectClass * klass,const void * data)159 static void pnv_homer_power9_class_init(ObjectClass *klass, const void *data)
160 {
161     PnvHomerClass *homer = PNV_HOMER_CLASS(klass);
162 
163     homer->get_base = pnv_homer_power9_get_base;
164     homer->size = PNV_HOMER_SIZE;
165     homer->pba_size = PNV9_XSCOM_PBA_SIZE;
166     homer->pba_ops = &pnv_homer_power9_pba_ops;
167 }
168 
169 static const TypeInfo pnv_homer_power9_type_info = {
170     .name          = TYPE_PNV9_HOMER,
171     .parent        = TYPE_PNV_HOMER,
172     .instance_size = sizeof(PnvHomer),
173     .class_init    = pnv_homer_power9_class_init,
174 };
175 
pnv_homer_power10_pba_read(void * opaque,hwaddr addr,unsigned size)176 static uint64_t pnv_homer_power10_pba_read(void *opaque, hwaddr addr,
177                                           unsigned size)
178 {
179     PnvHomer *homer = PNV_HOMER(opaque);
180     PnvHomerClass *hmrc = PNV_HOMER_GET_CLASS(homer);
181     uint32_t reg = addr >> 3;
182     uint64_t val = 0;
183 
184     switch (reg) {
185     case PBA_BAR0:
186         val = homer->base;
187         break;
188     case PBA_BARMASK0: /* P10 homer region mask */
189         val = (hmrc->size - 1) & 0x300000;
190         break;
191     case PBA_BAR2: /* P10 occ common area */
192         val = PNV10_OCC_COMMON_AREA_BASE;
193         break;
194     case PBA_BARMASK2: /* P10 occ common area size */
195         val = (PNV10_OCC_COMMON_AREA_SIZE - 1) & 0x700000;
196         break;
197     default:
198         qemu_log_mask(LOG_UNIMP, "PBA: read to unimplemented register: Ox%"
199                       HWADDR_PRIx "\n", addr >> 3);
200     }
201     return val;
202 }
203 
pnv_homer_power10_pba_write(void * opaque,hwaddr addr,uint64_t val,unsigned size)204 static void pnv_homer_power10_pba_write(void *opaque, hwaddr addr,
205                                          uint64_t val, unsigned size)
206 {
207     qemu_log_mask(LOG_UNIMP, "PBA: write to unimplemented register: Ox%"
208                   HWADDR_PRIx "\n", addr >> 3);
209 }
210 
211 static const MemoryRegionOps pnv_homer_power10_pba_ops = {
212     .read = pnv_homer_power10_pba_read,
213     .write = pnv_homer_power10_pba_write,
214     .valid.min_access_size = 8,
215     .valid.max_access_size = 8,
216     .impl.min_access_size = 8,
217     .impl.max_access_size = 8,
218     .endianness = DEVICE_BIG_ENDIAN,
219 };
220 
pnv_homer_power10_get_base(PnvChip * chip)221 static hwaddr pnv_homer_power10_get_base(PnvChip *chip)
222 {
223     return PNV10_HOMER_BASE(chip);
224 }
225 
pnv_homer_power10_class_init(ObjectClass * klass,const void * data)226 static void pnv_homer_power10_class_init(ObjectClass *klass, const void *data)
227 {
228     PnvHomerClass *homer = PNV_HOMER_CLASS(klass);
229 
230     homer->get_base = pnv_homer_power10_get_base;
231     homer->size = PNV_HOMER_SIZE;
232     homer->pba_size = PNV10_XSCOM_PBA_SIZE;
233     homer->pba_ops = &pnv_homer_power10_pba_ops;
234 }
235 
236 static const TypeInfo pnv_homer_power10_type_info = {
237     .name          = TYPE_PNV10_HOMER,
238     .parent        = TYPE_PNV_HOMER,
239     .instance_size = sizeof(PnvHomer),
240     .class_init    = pnv_homer_power10_class_init,
241 };
242 
pnv_homer_realize(DeviceState * dev,Error ** errp)243 static void pnv_homer_realize(DeviceState *dev, Error **errp)
244 {
245     PnvHomer *homer = PNV_HOMER(dev);
246     PnvHomerClass *hmrc = PNV_HOMER_GET_CLASS(homer);
247     char homer_str[32];
248 
249     assert(homer->chip);
250 
251     pnv_xscom_region_init(&homer->pba_regs, OBJECT(dev), hmrc->pba_ops,
252                           homer, "xscom-pba", hmrc->pba_size);
253 
254     /* Homer RAM region */
255     homer->base = hmrc->get_base(homer->chip);
256 
257     snprintf(homer_str, sizeof(homer_str), "homer-chip%d-memory",
258              homer->chip->chip_id);
259     if (!memory_region_init_ram(&homer->mem, OBJECT(homer),
260                                 homer_str, hmrc->size, errp)) {
261         return;
262     }
263 }
264 
265 static const Property pnv_homer_properties[] = {
266     DEFINE_PROP_LINK("chip", PnvHomer, chip, TYPE_PNV_CHIP, PnvChip *),
267 };
268 
pnv_homer_class_init(ObjectClass * klass,const void * data)269 static void pnv_homer_class_init(ObjectClass *klass, const void *data)
270 {
271     DeviceClass *dc = DEVICE_CLASS(klass);
272 
273     dc->realize = pnv_homer_realize;
274     dc->desc = "PowerNV HOMER Memory";
275     device_class_set_props(dc, pnv_homer_properties);
276     dc->user_creatable = false;
277 }
278 
279 static const TypeInfo pnv_homer_type_info = {
280     .name          = TYPE_PNV_HOMER,
281     .parent        = TYPE_DEVICE,
282     .instance_size = sizeof(PnvHomer),
283     .class_init    = pnv_homer_class_init,
284     .class_size    = sizeof(PnvHomerClass),
285     .abstract      = true,
286 };
287 
pnv_homer_register_types(void)288 static void pnv_homer_register_types(void)
289 {
290     type_register_static(&pnv_homer_type_info);
291     type_register_static(&pnv_homer_power8_type_info);
292     type_register_static(&pnv_homer_power9_type_info);
293     type_register_static(&pnv_homer_power10_type_info);
294 }
295 
296 type_init(pnv_homer_register_types);
297