Statistics
| Branch: | Revision:

root / hw / misc / macio / macio.c @ 2c9b15ca

History | View | Annotate | Download (10.1 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
/*
73
 * The mac-io has two interfaces to the ESCC. One is called "escc-legacy",
74
 * while the other one is the normal, current ESCC interface.
75
 *
76
 * The magic below creates memory aliases to spawn the escc-legacy device
77
 * purely by rerouting the respective registers to our escc region. This
78
 * works because the only difference between the two memory regions is the
79
 * register layout, not their semantics.
80
 *
81
 * Reference: ftp://ftp.software.ibm.com/rs6000/technology/spec/chrp/inwork/CHRP_IORef_1.0.pdf
82
 */
83
static void macio_escc_legacy_setup(MacIOState *macio_state)
84
{
85
    MemoryRegion *escc_legacy = g_new(MemoryRegion, 1);
86
    MemoryRegion *bar = &macio_state->bar;
87
    int i;
88
    static const int maps[] = {
89
        0x00, 0x00,
90
        0x02, 0x20,
91
        0x04, 0x10,
92
        0x06, 0x30,
93
        0x08, 0x40,
94
        0x0A, 0x50,
95
        0x60, 0x60,
96
        0x70, 0x70,
97
        0x80, 0x70,
98
        0x90, 0x80,
99
        0xA0, 0x90,
100
        0xB0, 0xA0,
101
        0xC0, 0xB0,
102
        0xD0, 0xC0,
103
        0xE0, 0xD0,
104
        0xF0, 0xE0,
105
    };
106

    
107
    memory_region_init(escc_legacy, NULL, "escc-legacy", 256);
108
    for (i = 0; i < ARRAY_SIZE(maps); i += 2) {
109
        MemoryRegion *port = g_new(MemoryRegion, 1);
110
        memory_region_init_alias(port, NULL, "escc-legacy-port",
111
                                 macio_state->escc_mem, maps[i+1], 0x2);
112
        memory_region_add_subregion(escc_legacy, maps[i], port);
113
    }
114

    
115
    memory_region_add_subregion(bar, 0x12000, escc_legacy);
116
}
117

    
118
static void macio_bar_setup(MacIOState *macio_state)
119
{
120
    MemoryRegion *bar = &macio_state->bar;
121

    
122
    if (macio_state->escc_mem) {
123
        memory_region_add_subregion(bar, 0x13000, macio_state->escc_mem);
124
        macio_escc_legacy_setup(macio_state);
125
    }
126
}
127

    
128
static int macio_common_initfn(PCIDevice *d)
129
{
130
    MacIOState *s = MACIO(d);
131
    SysBusDevice *sysbus_dev;
132
    int ret;
133

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

    
136
    ret = qdev_init(DEVICE(&s->cuda));
137
    if (ret < 0) {
138
        return ret;
139
    }
140
    sysbus_dev = SYS_BUS_DEVICE(&s->cuda);
141
    memory_region_add_subregion(&s->bar, 0x16000,
142
                                sysbus_mmio_get_region(sysbus_dev, 0));
143

    
144
    macio_bar_setup(s);
145
    pci_register_bar(d, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar);
146

    
147
    return 0;
148
}
149

    
150
static int macio_oldworld_initfn(PCIDevice *d)
151
{
152
    MacIOState *s = MACIO(d);
153
    OldWorldMacIOState *os = OLDWORLD_MACIO(d);
154
    SysBusDevice *sysbus_dev;
155
    int ret = macio_common_initfn(d);
156
    if (ret < 0) {
157
        return ret;
158
    }
159

    
160
    sysbus_dev = SYS_BUS_DEVICE(&s->cuda);
161
    sysbus_connect_irq(sysbus_dev, 0, os->irqs[0]);
162

    
163
    ret = qdev_init(DEVICE(&os->nvram));
164
    if (ret < 0) {
165
        return ret;
166
    }
167
    sysbus_dev = SYS_BUS_DEVICE(&os->nvram);
168
    memory_region_add_subregion(&s->bar, 0x60000,
169
                                sysbus_mmio_get_region(sysbus_dev, 0));
170
    pmac_format_nvram_partition(&os->nvram, os->nvram.size);
171

    
172
    if (s->pic_mem) {
173
        /* Heathrow PIC */
174
        memory_region_add_subregion(&s->bar, 0x00000, s->pic_mem);
175
    }
176

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

    
186
    return 0;
187
}
188

    
189
static void macio_oldworld_init(Object *obj)
190
{
191
    MacIOState *s = MACIO(obj);
192
    OldWorldMacIOState *os = OLDWORLD_MACIO(obj);
193
    DeviceState *dev;
194

    
195
    qdev_init_gpio_out(DEVICE(obj), os->irqs, ARRAY_SIZE(os->irqs));
196

    
197
    object_initialize(&os->nvram, TYPE_MACIO_NVRAM);
198
    dev = DEVICE(&os->nvram);
199
    qdev_prop_set_uint32(dev, "size", 0x2000);
200
    qdev_prop_set_uint32(dev, "it_shift", 4);
201

    
202
    object_initialize(&os->ide, TYPE_MACIO_IDE);
203
    qdev_set_parent_bus(DEVICE(&os->ide), sysbus_get_default());
204
    memory_region_add_subregion(&s->bar, 0x1f000 + (1 * 0x1000), &os->ide.mem);
205
    object_property_add_child(obj, "ide", OBJECT(&os->ide), NULL);
206
}
207

    
208
static int macio_newworld_initfn(PCIDevice *d)
209
{
210
    MacIOState *s = MACIO(d);
211
    NewWorldMacIOState *ns = NEWWORLD_MACIO(d);
212
    SysBusDevice *sysbus_dev;
213
    int ret = macio_common_initfn(d);
214
    if (ret < 0) {
215
        return ret;
216
    }
217

    
218
    sysbus_dev = SYS_BUS_DEVICE(&s->cuda);
219
    sysbus_connect_irq(sysbus_dev, 0, ns->irqs[0]);
220

    
221
    if (s->pic_mem) {
222
        /* OpenPIC */
223
        memory_region_add_subregion(&s->bar, 0x40000, s->pic_mem);
224
    }
225

    
226
    sysbus_dev = SYS_BUS_DEVICE(&ns->ide[0]);
227
    sysbus_connect_irq(sysbus_dev, 0, ns->irqs[1]);
228
    sysbus_connect_irq(sysbus_dev, 1, ns->irqs[2]);
229
    macio_ide_register_dma(&ns->ide[0], s->dbdma, 0x16);
230
    ret = qdev_init(DEVICE(&ns->ide[0]));
231
    if (ret < 0) {
232
        return ret;
233
    }
234

    
235
    sysbus_dev = SYS_BUS_DEVICE(&ns->ide[1]);
236
    sysbus_connect_irq(sysbus_dev, 0, ns->irqs[3]);
237
    sysbus_connect_irq(sysbus_dev, 1, ns->irqs[4]);
238
    macio_ide_register_dma(&ns->ide[1], s->dbdma, 0x1a);
239
    ret = qdev_init(DEVICE(&ns->ide[1]));
240
    if (ret < 0) {
241
        return ret;
242
    }
243

    
244
    return 0;
245
}
246

    
247
static void macio_newworld_init(Object *obj)
248
{
249
    MacIOState *s = MACIO(obj);
250
    NewWorldMacIOState *ns = NEWWORLD_MACIO(obj);
251
    int i;
252
    gchar *name;
253

    
254
    qdev_init_gpio_out(DEVICE(obj), ns->irqs, ARRAY_SIZE(ns->irqs));
255

    
256
    for (i = 0; i < 2; i++) {
257
        object_initialize(&ns->ide[i], TYPE_MACIO_IDE);
258
        qdev_set_parent_bus(DEVICE(&ns->ide[i]), sysbus_get_default());
259
        memory_region_add_subregion(&s->bar, 0x1f000 + ((i + 1) * 0x1000),
260
                                    &ns->ide[i].mem);
261
        name = g_strdup_printf("ide[%i]", i);
262
        object_property_add_child(obj, name, OBJECT(&ns->ide[i]), NULL);
263
        g_free(name);
264
    }
265
}
266

    
267
static void macio_instance_init(Object *obj)
268
{
269
    MacIOState *s = MACIO(obj);
270
    MemoryRegion *dbdma_mem;
271

    
272
    memory_region_init(&s->bar, NULL, "macio", 0x80000);
273

    
274
    object_initialize(&s->cuda, TYPE_CUDA);
275
    qdev_set_parent_bus(DEVICE(&s->cuda), sysbus_get_default());
276
    object_property_add_child(obj, "cuda", OBJECT(&s->cuda), NULL);
277

    
278
    s->dbdma = DBDMA_init(&dbdma_mem);
279
    memory_region_add_subregion(&s->bar, 0x08000, dbdma_mem);
280
}
281

    
282
static void macio_oldworld_class_init(ObjectClass *oc, void *data)
283
{
284
    PCIDeviceClass *pdc = PCI_DEVICE_CLASS(oc);
285

    
286
    pdc->init = macio_oldworld_initfn;
287
    pdc->device_id = PCI_DEVICE_ID_APPLE_343S1201;
288
}
289

    
290
static void macio_newworld_class_init(ObjectClass *oc, void *data)
291
{
292
    PCIDeviceClass *pdc = PCI_DEVICE_CLASS(oc);
293

    
294
    pdc->init = macio_newworld_initfn;
295
    pdc->device_id = PCI_DEVICE_ID_APPLE_UNI_N_KEYL;
296
}
297

    
298
static void macio_class_init(ObjectClass *klass, void *data)
299
{
300
    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
301

    
302
    k->vendor_id = PCI_VENDOR_ID_APPLE;
303
    k->class_id = PCI_CLASS_OTHERS << 8;
304
}
305

    
306
static const TypeInfo macio_oldworld_type_info = {
307
    .name          = TYPE_OLDWORLD_MACIO,
308
    .parent        = TYPE_MACIO,
309
    .instance_size = sizeof(OldWorldMacIOState),
310
    .instance_init = macio_oldworld_init,
311
    .class_init    = macio_oldworld_class_init,
312
};
313

    
314
static const TypeInfo macio_newworld_type_info = {
315
    .name          = TYPE_NEWWORLD_MACIO,
316
    .parent        = TYPE_MACIO,
317
    .instance_size = sizeof(NewWorldMacIOState),
318
    .instance_init = macio_newworld_init,
319
    .class_init    = macio_newworld_class_init,
320
};
321

    
322
static const TypeInfo macio_type_info = {
323
    .name          = TYPE_MACIO,
324
    .parent        = TYPE_PCI_DEVICE,
325
    .instance_size = sizeof(MacIOState),
326
    .instance_init = macio_instance_init,
327
    .abstract      = true,
328
    .class_init    = macio_class_init,
329
};
330

    
331
static void macio_register_types(void)
332
{
333
    type_register_static(&macio_type_info);
334
    type_register_static(&macio_oldworld_type_info);
335
    type_register_static(&macio_newworld_type_info);
336
}
337

    
338
type_init(macio_register_types)
339

    
340
void macio_init(PCIDevice *d,
341
                MemoryRegion *pic_mem,
342
                MemoryRegion *escc_mem)
343
{
344
    MacIOState *macio_state = MACIO(d);
345

    
346
    macio_state->pic_mem = pic_mem;
347
    macio_state->escc_mem = escc_mem;
348
    /* Note: this code is strongly inspirated from the corresponding code
349
       in PearPC */
350

    
351
    qdev_init_nofail(DEVICE(d));
352
}