Statistics
| Branch: | Revision:

root / hw / misc / macio / macio.c @ 49ab747f

History | View | Annotate | Download (8.7 kB)

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
 */
25
#include "hw/hw.h"
26
#include "hw/ppc/mac.h"
27
#include "hw/pci/pci.h"
28
#include "hw/ppc/mac_dbdma.h"
29
#include "hw/char/escc.h"
30

    
31
#define TYPE_MACIO "macio"
32
#define MACIO(obj) OBJECT_CHECK(MacIOState, (obj), TYPE_MACIO)
33

    
34
typedef struct MacIOState
35
{
36
    /*< private >*/
37
    PCIDevice parent;
38
    /*< public >*/
39

    
40
    MemoryRegion bar;
41
    CUDAState cuda;
42
    void *dbdma;
43
    MemoryRegion *pic_mem;
44
    MemoryRegion *escc_mem;
45
} MacIOState;
46

    
47
#define OLDWORLD_MACIO(obj) \
48
    OBJECT_CHECK(OldWorldMacIOState, (obj), TYPE_OLDWORLD_MACIO)
49

    
50
typedef struct OldWorldMacIOState {
51
    /*< private >*/
52
    MacIOState parent_obj;
53
    /*< public >*/
54

    
55
    qemu_irq irqs[3];
56

    
57
    MacIONVRAMState nvram;
58
    MACIOIDEState ide;
59
} OldWorldMacIOState;
60

    
61
#define NEWWORLD_MACIO(obj) \
62
    OBJECT_CHECK(NewWorldMacIOState, (obj), TYPE_NEWWORLD_MACIO)
63

    
64
typedef struct NewWorldMacIOState {
65
    /*< private >*/
66
    MacIOState parent_obj;
67
    /*< public >*/
68
    qemu_irq irqs[5];
69
    MACIOIDEState ide[2];
70
} NewWorldMacIOState;
71

    
72
static void macio_bar_setup(MacIOState *macio_state)
73
{
74
    MemoryRegion *bar = &macio_state->bar;
75

    
76
    if (macio_state->escc_mem) {
77
        memory_region_add_subregion(bar, 0x13000, macio_state->escc_mem);
78
    }
79
}
80

    
81
static int macio_common_initfn(PCIDevice *d)
82
{
83
    MacIOState *s = MACIO(d);
84
    SysBusDevice *sysbus_dev;
85
    int ret;
86

    
87
    d->config[0x3d] = 0x01; // interrupt on pin 1
88

    
89
    ret = qdev_init(DEVICE(&s->cuda));
90
    if (ret < 0) {
91
        return ret;
92
    }
93
    sysbus_dev = SYS_BUS_DEVICE(&s->cuda);
94
    memory_region_add_subregion(&s->bar, 0x16000,
95
                                sysbus_mmio_get_region(sysbus_dev, 0));
96

    
97
    macio_bar_setup(s);
98
    pci_register_bar(d, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar);
99

    
100
    return 0;
101
}
102

    
103
static int macio_oldworld_initfn(PCIDevice *d)
104
{
105
    MacIOState *s = MACIO(d);
106
    OldWorldMacIOState *os = OLDWORLD_MACIO(d);
107
    SysBusDevice *sysbus_dev;
108
    int ret = macio_common_initfn(d);
109
    if (ret < 0) {
110
        return ret;
111
    }
112

    
113
    sysbus_dev = SYS_BUS_DEVICE(&s->cuda);
114
    sysbus_connect_irq(sysbus_dev, 0, os->irqs[0]);
115

    
116
    ret = qdev_init(DEVICE(&os->nvram));
117
    if (ret < 0) {
118
        return ret;
119
    }
120
    sysbus_dev = SYS_BUS_DEVICE(&os->nvram);
121
    memory_region_add_subregion(&s->bar, 0x60000,
122
                                sysbus_mmio_get_region(sysbus_dev, 0));
123
    pmac_format_nvram_partition(&os->nvram, os->nvram.size);
124

    
125
    if (s->pic_mem) {
126
        /* Heathrow PIC */
127
        memory_region_add_subregion(&s->bar, 0x00000, s->pic_mem);
128
    }
129

    
130
    sysbus_dev = SYS_BUS_DEVICE(&os->ide);
131
    sysbus_connect_irq(sysbus_dev, 0, os->irqs[1]);
132
    sysbus_connect_irq(sysbus_dev, 1, os->irqs[2]);
133
    macio_ide_register_dma(&os->ide, s->dbdma, 0x16);
134
    ret = qdev_init(DEVICE(&os->ide));
135
    if (ret < 0) {
136
        return ret;
137
    }
138

    
139
    return 0;
140
}
141

    
142
static void macio_oldworld_init(Object *obj)
143
{
144
    MacIOState *s = MACIO(obj);
145
    OldWorldMacIOState *os = OLDWORLD_MACIO(obj);
146
    DeviceState *dev;
147

    
148
    qdev_init_gpio_out(DEVICE(obj), os->irqs, ARRAY_SIZE(os->irqs));
149

    
150
    object_initialize(&os->nvram, TYPE_MACIO_NVRAM);
151
    dev = DEVICE(&os->nvram);
152
    qdev_prop_set_uint32(dev, "size", 0x2000);
153
    qdev_prop_set_uint32(dev, "it_shift", 4);
154

    
155
    object_initialize(&os->ide, TYPE_MACIO_IDE);
156
    qdev_set_parent_bus(DEVICE(&os->ide), sysbus_get_default());
157
    memory_region_add_subregion(&s->bar, 0x1f000 + (1 * 0x1000), &os->ide.mem);
158
    object_property_add_child(obj, "ide", OBJECT(&os->ide), NULL);
159
}
160

    
161
static int macio_newworld_initfn(PCIDevice *d)
162
{
163
    MacIOState *s = MACIO(d);
164
    NewWorldMacIOState *ns = NEWWORLD_MACIO(d);
165
    SysBusDevice *sysbus_dev;
166
    int ret = macio_common_initfn(d);
167
    if (ret < 0) {
168
        return ret;
169
    }
170

    
171
    sysbus_dev = SYS_BUS_DEVICE(&s->cuda);
172
    sysbus_connect_irq(sysbus_dev, 0, ns->irqs[0]);
173

    
174
    if (s->pic_mem) {
175
        /* OpenPIC */
176
        memory_region_add_subregion(&s->bar, 0x40000, s->pic_mem);
177
    }
178

    
179
    sysbus_dev = SYS_BUS_DEVICE(&ns->ide[0]);
180
    sysbus_connect_irq(sysbus_dev, 0, ns->irqs[1]);
181
    sysbus_connect_irq(sysbus_dev, 1, ns->irqs[2]);
182
    macio_ide_register_dma(&ns->ide[0], s->dbdma, 0x16);
183
    ret = qdev_init(DEVICE(&ns->ide[0]));
184
    if (ret < 0) {
185
        return ret;
186
    }
187

    
188
    sysbus_dev = SYS_BUS_DEVICE(&ns->ide[1]);
189
    sysbus_connect_irq(sysbus_dev, 0, ns->irqs[3]);
190
    sysbus_connect_irq(sysbus_dev, 1, ns->irqs[4]);
191
    macio_ide_register_dma(&ns->ide[1], s->dbdma, 0x1a);
192
    ret = qdev_init(DEVICE(&ns->ide[1]));
193
    if (ret < 0) {
194
        return ret;
195
    }
196

    
197
    return 0;
198
}
199

    
200
static void macio_newworld_init(Object *obj)
201
{
202
    MacIOState *s = MACIO(obj);
203
    NewWorldMacIOState *ns = NEWWORLD_MACIO(obj);
204
    int i;
205
    gchar *name;
206

    
207
    qdev_init_gpio_out(DEVICE(obj), ns->irqs, ARRAY_SIZE(ns->irqs));
208

    
209
    for (i = 0; i < 2; i++) {
210
        object_initialize(&ns->ide[i], TYPE_MACIO_IDE);
211
        qdev_set_parent_bus(DEVICE(&ns->ide[i]), sysbus_get_default());
212
        memory_region_add_subregion(&s->bar, 0x1f000 + ((i + 1) * 0x1000),
213
                                    &ns->ide[i].mem);
214
        name = g_strdup_printf("ide[%i]", i);
215
        object_property_add_child(obj, name, OBJECT(&ns->ide[i]), NULL);
216
        g_free(name);
217
    }
218
}
219

    
220
static void macio_instance_init(Object *obj)
221
{
222
    MacIOState *s = MACIO(obj);
223
    MemoryRegion *dbdma_mem;
224

    
225
    memory_region_init(&s->bar, "macio", 0x80000);
226

    
227
    object_initialize(&s->cuda, TYPE_CUDA);
228
    qdev_set_parent_bus(DEVICE(&s->cuda), sysbus_get_default());
229
    object_property_add_child(obj, "cuda", OBJECT(&s->cuda), NULL);
230

    
231
    s->dbdma = DBDMA_init(&dbdma_mem);
232
    memory_region_add_subregion(&s->bar, 0x08000, dbdma_mem);
233
}
234

    
235
static void macio_oldworld_class_init(ObjectClass *oc, void *data)
236
{
237
    PCIDeviceClass *pdc = PCI_DEVICE_CLASS(oc);
238

    
239
    pdc->init = macio_oldworld_initfn;
240
    pdc->device_id = PCI_DEVICE_ID_APPLE_343S1201;
241
}
242

    
243
static void macio_newworld_class_init(ObjectClass *oc, void *data)
244
{
245
    PCIDeviceClass *pdc = PCI_DEVICE_CLASS(oc);
246

    
247
    pdc->init = macio_newworld_initfn;
248
    pdc->device_id = PCI_DEVICE_ID_APPLE_UNI_N_KEYL;
249
}
250

    
251
static void macio_class_init(ObjectClass *klass, void *data)
252
{
253
    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
254

    
255
    k->vendor_id = PCI_VENDOR_ID_APPLE;
256
    k->class_id = PCI_CLASS_OTHERS << 8;
257
}
258

    
259
static const TypeInfo macio_oldworld_type_info = {
260
    .name          = TYPE_OLDWORLD_MACIO,
261
    .parent        = TYPE_MACIO,
262
    .instance_size = sizeof(OldWorldMacIOState),
263
    .instance_init = macio_oldworld_init,
264
    .class_init    = macio_oldworld_class_init,
265
};
266

    
267
static const TypeInfo macio_newworld_type_info = {
268
    .name          = TYPE_NEWWORLD_MACIO,
269
    .parent        = TYPE_MACIO,
270
    .instance_size = sizeof(NewWorldMacIOState),
271
    .instance_init = macio_newworld_init,
272
    .class_init    = macio_newworld_class_init,
273
};
274

    
275
static const TypeInfo macio_type_info = {
276
    .name          = TYPE_MACIO,
277
    .parent        = TYPE_PCI_DEVICE,
278
    .instance_size = sizeof(MacIOState),
279
    .instance_init = macio_instance_init,
280
    .abstract      = true,
281
    .class_init    = macio_class_init,
282
};
283

    
284
static void macio_register_types(void)
285
{
286
    type_register_static(&macio_type_info);
287
    type_register_static(&macio_oldworld_type_info);
288
    type_register_static(&macio_newworld_type_info);
289
}
290

    
291
type_init(macio_register_types)
292

    
293
void macio_init(PCIDevice *d,
294
                MemoryRegion *pic_mem,
295
                MemoryRegion *escc_mem)
296
{
297
    MacIOState *macio_state = MACIO(d);
298

    
299
    macio_state->pic_mem = pic_mem;
300
    macio_state->escc_mem = escc_mem;
301
    /* Note: this code is strongly inspirated from the corresponding code
302
       in PearPC */
303

    
304
    qdev_init_nofail(DEVICE(d));
305
}