]> git.proxmox.com Git - mirror_qemu.git/blame - hw/misc/macio/macio.c
target-arm: Correct check for non-EL3
[mirror_qemu.git] / hw / misc / macio / macio.c
CommitLineData
3cbee15b
JM
1/*
2 * PowerMac MacIO device emulation
3 *
4 * Copyright (c) 2005-2007 Fabrice Bellard
5 * Copyright (c) 2007 Jocelyn Mayer
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE.
24 */
83c9f4ca
PB
25#include "hw/hw.h"
26#include "hw/ppc/mac.h"
27#include "hw/pci/pci.h"
0d09e41a
PB
28#include "hw/ppc/mac_dbdma.h"
29#include "hw/char/escc.h"
3cbee15b 30
fcf1bbab
AF
31#define TYPE_MACIO "macio"
32#define MACIO(obj) OBJECT_CHECK(MacIOState, (obj), TYPE_MACIO)
33
d8c51b05
AL
34typedef struct MacIOState
35{
fcf1bbab 36 /*< private >*/
d8c51b05 37 PCIDevice parent;
fcf1bbab
AF
38 /*< public >*/
39
23c5e4ca 40 MemoryRegion bar;
45fa67fb 41 CUDAState cuda;
07a7484e 42 void *dbdma;
23c5e4ca 43 MemoryRegion *pic_mem;
23c5e4ca 44 MemoryRegion *escc_mem;
b981289c 45 uint64_t frequency;
d8c51b05 46} MacIOState;
3cbee15b 47
95ed3b7c
AF
48#define OLDWORLD_MACIO(obj) \
49 OBJECT_CHECK(OldWorldMacIOState, (obj), TYPE_OLDWORLD_MACIO)
50
51typedef struct OldWorldMacIOState {
52 /*< private >*/
53 MacIOState parent_obj;
54 /*< public >*/
55
14eefd0e 56 qemu_irq irqs[5];
07a7484e 57
95ed3b7c 58 MacIONVRAMState nvram;
14eefd0e 59 MACIOIDEState ide[2];
95ed3b7c
AF
60} OldWorldMacIOState;
61
07a7484e
AF
62#define NEWWORLD_MACIO(obj) \
63 OBJECT_CHECK(NewWorldMacIOState, (obj), TYPE_NEWWORLD_MACIO)
64
65typedef struct NewWorldMacIOState {
66 /*< private >*/
67 MacIOState parent_obj;
68 /*< public >*/
45fa67fb 69 qemu_irq irqs[5];
07a7484e
AF
70 MACIOIDEState ide[2];
71} NewWorldMacIOState;
72
0d54a502
AG
73/*
74 * The mac-io has two interfaces to the ESCC. One is called "escc-legacy",
75 * while the other one is the normal, current ESCC interface.
76 *
77 * The magic below creates memory aliases to spawn the escc-legacy device
78 * purely by rerouting the respective registers to our escc region. This
79 * works because the only difference between the two memory regions is the
80 * register layout, not their semantics.
81 *
82 * Reference: ftp://ftp.software.ibm.com/rs6000/technology/spec/chrp/inwork/CHRP_IORef_1.0.pdf
83 */
84static void macio_escc_legacy_setup(MacIOState *macio_state)
85{
86 MemoryRegion *escc_legacy = g_new(MemoryRegion, 1);
87 MemoryRegion *bar = &macio_state->bar;
88 int i;
89 static const int maps[] = {
90 0x00, 0x00,
91 0x02, 0x20,
92 0x04, 0x10,
93 0x06, 0x30,
94 0x08, 0x40,
95 0x0A, 0x50,
96 0x60, 0x60,
97 0x70, 0x70,
98 0x80, 0x70,
99 0x90, 0x80,
100 0xA0, 0x90,
101 0xB0, 0xA0,
102 0xC0, 0xB0,
103 0xD0, 0xC0,
104 0xE0, 0xD0,
105 0xF0, 0xE0,
106 };
107
2c9b15ca 108 memory_region_init(escc_legacy, NULL, "escc-legacy", 256);
0d54a502
AG
109 for (i = 0; i < ARRAY_SIZE(maps); i += 2) {
110 MemoryRegion *port = g_new(MemoryRegion, 1);
2c9b15ca
PB
111 memory_region_init_alias(port, NULL, "escc-legacy-port",
112 macio_state->escc_mem, maps[i+1], 0x2);
0d54a502
AG
113 memory_region_add_subregion(escc_legacy, maps[i], port);
114 }
115
116 memory_region_add_subregion(bar, 0x12000, escc_legacy);
117}
118
d8c51b05 119static void macio_bar_setup(MacIOState *macio_state)
3cbee15b 120{
23c5e4ca 121 MemoryRegion *bar = &macio_state->bar;
3cbee15b 122
23c5e4ca
AK
123 if (macio_state->escc_mem) {
124 memory_region_add_subregion(bar, 0x13000, macio_state->escc_mem);
0d54a502 125 macio_escc_legacy_setup(macio_state);
7fa9ae1a 126 }
3cbee15b
JM
127}
128
d037834a 129static int macio_common_initfn(PCIDevice *d)
d8c51b05 130{
7b925079 131 MacIOState *s = MACIO(d);
45fa67fb
AF
132 SysBusDevice *sysbus_dev;
133 int ret;
7b925079 134
d8c51b05 135 d->config[0x3d] = 0x01; // interrupt on pin 1
7b925079 136
45fa67fb
AF
137 ret = qdev_init(DEVICE(&s->cuda));
138 if (ret < 0) {
139 return ret;
140 }
141 sysbus_dev = SYS_BUS_DEVICE(&s->cuda);
142 memory_region_add_subregion(&s->bar, 0x16000,
143 sysbus_mmio_get_region(sysbus_dev, 0));
144
7b925079
AF
145 macio_bar_setup(s);
146 pci_register_bar(d, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar);
147
d8c51b05
AL
148 return 0;
149}
150
14eefd0e
AG
151static int macio_initfn_ide(MacIOState *s, MACIOIDEState *ide, qemu_irq irq0,
152 qemu_irq irq1, int dmaid)
153{
154 SysBusDevice *sysbus_dev;
155
156 sysbus_dev = SYS_BUS_DEVICE(ide);
157 sysbus_connect_irq(sysbus_dev, 0, irq0);
158 sysbus_connect_irq(sysbus_dev, 1, irq1);
159 macio_ide_register_dma(ide, s->dbdma, dmaid);
160 return qdev_init(DEVICE(ide));
161}
162
d037834a
AF
163static int macio_oldworld_initfn(PCIDevice *d)
164{
165 MacIOState *s = MACIO(d);
95ed3b7c
AF
166 OldWorldMacIOState *os = OLDWORLD_MACIO(d);
167 SysBusDevice *sysbus_dev;
14eefd0e
AG
168 int i;
169 int cur_irq = 0;
d037834a
AF
170 int ret = macio_common_initfn(d);
171 if (ret < 0) {
172 return ret;
173 }
174
45fa67fb 175 sysbus_dev = SYS_BUS_DEVICE(&s->cuda);
14eefd0e 176 sysbus_connect_irq(sysbus_dev, 0, os->irqs[cur_irq++]);
45fa67fb 177
95ed3b7c
AF
178 ret = qdev_init(DEVICE(&os->nvram));
179 if (ret < 0) {
180 return ret;
181 }
182 sysbus_dev = SYS_BUS_DEVICE(&os->nvram);
183 memory_region_add_subregion(&s->bar, 0x60000,
184 sysbus_mmio_get_region(sysbus_dev, 0));
185 pmac_format_nvram_partition(&os->nvram, os->nvram.size);
186
d037834a
AF
187 if (s->pic_mem) {
188 /* Heathrow PIC */
189 memory_region_add_subregion(&s->bar, 0x00000, s->pic_mem);
190 }
191
14eefd0e
AG
192 /* IDE buses */
193 for (i = 0; i < ARRAY_SIZE(os->ide); i++) {
194 qemu_irq irq0 = os->irqs[cur_irq++];
195 qemu_irq irq1 = os->irqs[cur_irq++];
196
197 ret = macio_initfn_ide(s, &os->ide[i], irq0, irq1, 0x16 + (i * 4));
198 if (ret < 0) {
199 return ret;
200 }
07a7484e
AF
201 }
202
d037834a
AF
203 return 0;
204}
205
213f0c4f
AF
206static void macio_init_ide(MacIOState *s, MACIOIDEState *ide, size_t ide_size,
207 int index)
14eefd0e
AG
208{
209 gchar *name;
210
213f0c4f 211 object_initialize(ide, ide_size, TYPE_MACIO_IDE);
14eefd0e
AG
212 qdev_set_parent_bus(DEVICE(ide), sysbus_get_default());
213 memory_region_add_subregion(&s->bar, 0x1f000 + ((index + 1) * 0x1000),
214 &ide->mem);
215 name = g_strdup_printf("ide[%i]", index);
216 object_property_add_child(OBJECT(s), name, OBJECT(ide), NULL);
217 g_free(name);
218}
219
95ed3b7c
AF
220static void macio_oldworld_init(Object *obj)
221{
07a7484e 222 MacIOState *s = MACIO(obj);
95ed3b7c
AF
223 OldWorldMacIOState *os = OLDWORLD_MACIO(obj);
224 DeviceState *dev;
14eefd0e 225 int i;
95ed3b7c 226
07a7484e
AF
227 qdev_init_gpio_out(DEVICE(obj), os->irqs, ARRAY_SIZE(os->irqs));
228
213f0c4f 229 object_initialize(&os->nvram, sizeof(os->nvram), TYPE_MACIO_NVRAM);
95ed3b7c
AF
230 dev = DEVICE(&os->nvram);
231 qdev_prop_set_uint32(dev, "size", 0x2000);
232 qdev_prop_set_uint32(dev, "it_shift", 4);
07a7484e 233
14eefd0e 234 for (i = 0; i < 2; i++) {
213f0c4f 235 macio_init_ide(s, &os->ide[i], sizeof(os->ide[i]), i);
14eefd0e 236 }
95ed3b7c
AF
237}
238
a0f9fdfd
AG
239static void timer_write(void *opaque, hwaddr addr, uint64_t value,
240 unsigned size)
241{
242}
243
244static uint64_t timer_read(void *opaque, hwaddr addr, unsigned size)
245{
246 uint32_t value = 0;
d696760b
AG
247 uint64_t systime = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
248 uint64_t kltime;
249
250 kltime = muldiv64(systime, 4194300, get_ticks_per_sec() * 4);
251 kltime = muldiv64(kltime, 18432000, 1048575);
a0f9fdfd
AG
252
253 switch (addr) {
254 case 0x38:
d696760b 255 value = kltime;
a0f9fdfd
AG
256 break;
257 case 0x3c:
d696760b 258 value = kltime >> 32;
a0f9fdfd
AG
259 break;
260 }
261
262 return value;
263}
264
265static const MemoryRegionOps timer_ops = {
266 .read = timer_read,
267 .write = timer_write,
9397a7c8 268 .endianness = DEVICE_LITTLE_ENDIAN,
a0f9fdfd
AG
269};
270
d037834a
AF
271static int macio_newworld_initfn(PCIDevice *d)
272{
273 MacIOState *s = MACIO(d);
07a7484e
AF
274 NewWorldMacIOState *ns = NEWWORLD_MACIO(d);
275 SysBusDevice *sysbus_dev;
6c5819c4 276 MemoryRegion *timer_memory = NULL;
14eefd0e
AG
277 int i;
278 int cur_irq = 0;
d037834a
AF
279 int ret = macio_common_initfn(d);
280 if (ret < 0) {
281 return ret;
282 }
283
45fa67fb 284 sysbus_dev = SYS_BUS_DEVICE(&s->cuda);
14eefd0e 285 sysbus_connect_irq(sysbus_dev, 0, ns->irqs[cur_irq++]);
45fa67fb 286
d037834a
AF
287 if (s->pic_mem) {
288 /* OpenPIC */
289 memory_region_add_subregion(&s->bar, 0x40000, s->pic_mem);
290 }
291
14eefd0e
AG
292 /* IDE buses */
293 for (i = 0; i < ARRAY_SIZE(ns->ide); i++) {
294 qemu_irq irq0 = ns->irqs[cur_irq++];
295 qemu_irq irq1 = ns->irqs[cur_irq++];
07a7484e 296
14eefd0e
AG
297 ret = macio_initfn_ide(s, &ns->ide[i], irq0, irq1, 0x16 + (i * 4));
298 if (ret < 0) {
299 return ret;
300 }
07a7484e
AF
301 }
302
a0f9fdfd 303 /* Timer */
6c5819c4 304 timer_memory = g_new(MemoryRegion, 1);
a0f9fdfd
AG
305 memory_region_init_io(timer_memory, OBJECT(s), &timer_ops, NULL, "timer",
306 0x1000);
307 memory_region_add_subregion(&s->bar, 0x15000, timer_memory);
308
d037834a
AF
309 return 0;
310}
311
07a7484e
AF
312static void macio_newworld_init(Object *obj)
313{
314 MacIOState *s = MACIO(obj);
315 NewWorldMacIOState *ns = NEWWORLD_MACIO(obj);
316 int i;
07a7484e
AF
317
318 qdev_init_gpio_out(DEVICE(obj), ns->irqs, ARRAY_SIZE(ns->irqs));
319
320 for (i = 0; i < 2; i++) {
213f0c4f 321 macio_init_ide(s, &ns->ide[i], sizeof(ns->ide[i]), i);
07a7484e
AF
322 }
323}
324
fcf1bbab
AF
325static void macio_instance_init(Object *obj)
326{
327 MacIOState *s = MACIO(obj);
07a7484e 328 MemoryRegion *dbdma_mem;
fcf1bbab 329
2c9b15ca 330 memory_region_init(&s->bar, NULL, "macio", 0x80000);
07a7484e 331
213f0c4f 332 object_initialize(&s->cuda, sizeof(s->cuda), TYPE_CUDA);
45fa67fb
AF
333 qdev_set_parent_bus(DEVICE(&s->cuda), sysbus_get_default());
334 object_property_add_child(obj, "cuda", OBJECT(&s->cuda), NULL);
335
07a7484e
AF
336 s->dbdma = DBDMA_init(&dbdma_mem);
337 memory_region_add_subregion(&s->bar, 0x08000, dbdma_mem);
fcf1bbab
AF
338}
339
02635923
MCA
340static const VMStateDescription vmstate_macio_oldworld = {
341 .name = "macio-oldworld",
342 .version_id = 0,
343 .minimum_version_id = 0,
344 .fields = (VMStateField[]) {
345 VMSTATE_PCI_DEVICE(parent_obj.parent, OldWorldMacIOState),
346 VMSTATE_END_OF_LIST()
347 }
348};
349
d037834a
AF
350static void macio_oldworld_class_init(ObjectClass *oc, void *data)
351{
352 PCIDeviceClass *pdc = PCI_DEVICE_CLASS(oc);
02635923 353 DeviceClass *dc = DEVICE_CLASS(oc);
d037834a
AF
354
355 pdc->init = macio_oldworld_initfn;
356 pdc->device_id = PCI_DEVICE_ID_APPLE_343S1201;
02635923 357 dc->vmsd = &vmstate_macio_oldworld;
d037834a
AF
358}
359
02635923
MCA
360static const VMStateDescription vmstate_macio_newworld = {
361 .name = "macio-newworld",
362 .version_id = 0,
363 .minimum_version_id = 0,
364 .fields = (VMStateField[]) {
365 VMSTATE_PCI_DEVICE(parent_obj.parent, NewWorldMacIOState),
366 VMSTATE_END_OF_LIST()
367 }
368};
369
d037834a
AF
370static void macio_newworld_class_init(ObjectClass *oc, void *data)
371{
372 PCIDeviceClass *pdc = PCI_DEVICE_CLASS(oc);
02635923 373 DeviceClass *dc = DEVICE_CLASS(oc);
d037834a
AF
374
375 pdc->init = macio_newworld_initfn;
376 pdc->device_id = PCI_DEVICE_ID_APPLE_UNI_N_KEYL;
02635923 377 dc->vmsd = &vmstate_macio_newworld;
d037834a
AF
378}
379
b981289c
AG
380static Property macio_properties[] = {
381 DEFINE_PROP_UINT64("frequency", MacIOState, frequency, 0),
382 DEFINE_PROP_END_OF_LIST()
383};
384
40021f08
AL
385static void macio_class_init(ObjectClass *klass, void *data)
386{
387 PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
b981289c 388 DeviceClass *dc = DEVICE_CLASS(klass);
40021f08 389
40021f08
AL
390 k->vendor_id = PCI_VENDOR_ID_APPLE;
391 k->class_id = PCI_CLASS_OTHERS << 8;
b981289c 392 dc->props = macio_properties;
40021f08
AL
393}
394
d037834a
AF
395static const TypeInfo macio_oldworld_type_info = {
396 .name = TYPE_OLDWORLD_MACIO,
397 .parent = TYPE_MACIO,
95ed3b7c
AF
398 .instance_size = sizeof(OldWorldMacIOState),
399 .instance_init = macio_oldworld_init,
d037834a
AF
400 .class_init = macio_oldworld_class_init,
401};
402
403static const TypeInfo macio_newworld_type_info = {
404 .name = TYPE_NEWWORLD_MACIO,
405 .parent = TYPE_MACIO,
07a7484e
AF
406 .instance_size = sizeof(NewWorldMacIOState),
407 .instance_init = macio_newworld_init,
d037834a
AF
408 .class_init = macio_newworld_class_init,
409};
410
fcf1bbab
AF
411static const TypeInfo macio_type_info = {
412 .name = TYPE_MACIO,
39bffca2
AL
413 .parent = TYPE_PCI_DEVICE,
414 .instance_size = sizeof(MacIOState),
fcf1bbab 415 .instance_init = macio_instance_init,
d037834a 416 .abstract = true,
39bffca2 417 .class_init = macio_class_init,
d8c51b05
AL
418};
419
83f7d43a 420static void macio_register_types(void)
d8c51b05 421{
fcf1bbab 422 type_register_static(&macio_type_info);
d037834a
AF
423 type_register_static(&macio_oldworld_type_info);
424 type_register_static(&macio_newworld_type_info);
d8c51b05
AL
425}
426
83f7d43a 427type_init(macio_register_types)
d8c51b05 428
d037834a 429void macio_init(PCIDevice *d,
07a7484e 430 MemoryRegion *pic_mem,
d037834a 431 MemoryRegion *escc_mem)
3cbee15b 432{
d037834a 433 MacIOState *macio_state = MACIO(d);
3cbee15b 434
23c5e4ca 435 macio_state->pic_mem = pic_mem;
23c5e4ca 436 macio_state->escc_mem = escc_mem;
3cbee15b
JM
437 /* Note: this code is strongly inspirated from the corresponding code
438 in PearPC */
b981289c
AG
439 qdev_prop_set_uint64(DEVICE(&macio_state->cuda), "frequency",
440 macio_state->frequency);
deb54399 441
7b925079 442 qdev_init_nofail(DEVICE(d));
3cbee15b 443}