Statistics
| Branch: | Revision:

root / hw / apb_pci.c @ 776e1bbb

History | View | Annotate | Download (10.7 kB)

1
/*
2
 * QEMU Ultrasparc APB PCI host
3
 *
4
 * Copyright (c) 2006 Fabrice Bellard
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7
 * of this software and associated documentation files (the "Software"), to deal
8
 * in the Software without restriction, including without limitation the rights
9
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
 * copies of the Software, and to permit persons to whom the Software is
11
 * furnished to do so, subject to the following conditions:
12
 *
13
 * The above copyright notice and this permission notice shall be included in
14
 * all copies or substantial portions of the Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
 * THE SOFTWARE.
23
 */
24

    
25
/* XXX This file and most of its contents are somewhat misnamed.  The
26
   Ultrasparc PCI host is called the PCI Bus Module (PBM).  The APB is
27
   the secondary PCI bridge.  */
28

    
29
#include "sysbus.h"
30
#include "pci.h"
31
#include "pci_host.h"
32
#include "apb_pci.h"
33

    
34
/* debug APB */
35
//#define DEBUG_APB
36

    
37
#ifdef DEBUG_APB
38
#define APB_DPRINTF(fmt, ...) \
39
do { printf("APB: " fmt , ## __VA_ARGS__); } while (0)
40
#else
41
#define APB_DPRINTF(fmt, ...)
42
#endif
43

    
44
/*
45
 * Chipset docs:
46
 * PBM: "UltraSPARC IIi User's Manual",
47
 * http://www.sun.com/processors/manuals/805-0087.pdf
48
 *
49
 * APB: "Advanced PCI Bridge (APB) User's Manual",
50
 * http://www.sun.com/processors/manuals/805-1251.pdf
51
 */
52

    
53
typedef struct APBState {
54
    SysBusDevice busdev;
55
    PCIHostState host_state;
56
} APBState;
57

    
58
static void apb_config_writel (void *opaque, target_phys_addr_t addr,
59
                               uint32_t val)
60
{
61
    //PCIBus *s = opaque;
62

    
63
    switch (addr & 0x3f) {
64
    case 0x00: // Control/Status
65
    case 0x10: // AFSR
66
    case 0x18: // AFAR
67
    case 0x20: // Diagnostic
68
    case 0x28: // Target address space
69
        // XXX
70
    default:
71
        break;
72
    }
73
}
74

    
75
static uint32_t apb_config_readl (void *opaque,
76
                                  target_phys_addr_t addr)
77
{
78
    //PCIBus *s = opaque;
79
    uint32_t val;
80

    
81
    switch (addr & 0x3f) {
82
    case 0x00: // Control/Status
83
    case 0x10: // AFSR
84
    case 0x18: // AFAR
85
    case 0x20: // Diagnostic
86
    case 0x28: // Target address space
87
        // XXX
88
    default:
89
        val = 0;
90
        break;
91
    }
92
    return val;
93
}
94

    
95
static CPUWriteMemoryFunc * const apb_config_write[] = {
96
    &apb_config_writel,
97
    &apb_config_writel,
98
    &apb_config_writel,
99
};
100

    
101
static CPUReadMemoryFunc * const apb_config_read[] = {
102
    &apb_config_readl,
103
    &apb_config_readl,
104
    &apb_config_readl,
105
};
106

    
107
static void apb_pci_config_write(APBState *s, target_phys_addr_t addr,
108
                                 uint32_t val, int size)
109
{
110
    APB_DPRINTF("%s: addr " TARGET_FMT_lx " val %x\n", __func__, addr, val);
111
    pci_data_write(s->host_state.bus, (addr & 0x00ffffff) | (1u << 31), val,
112
                   size);
113
}
114

    
115
static uint32_t apb_pci_config_read(APBState *s, target_phys_addr_t addr,
116
                                    int size)
117
{
118
    uint32_t ret;
119

    
120
    ret = pci_data_read(s->host_state.bus, (addr & 0x00ffffff) | (1u << 31),
121
                        size);
122
    APB_DPRINTF("%s: addr " TARGET_FMT_lx " -> %x\n", __func__, addr, ret);
123
    return ret;
124
}
125

    
126
static void apb_pci_config_writel(void *opaque, target_phys_addr_t addr,
127
                                  uint32_t val)
128
{
129
    APBState *s = opaque;
130

    
131
    apb_pci_config_write(s, addr, bswap32(val), 4);
132
}
133

    
134
static void apb_pci_config_writew(void *opaque, target_phys_addr_t addr,
135
                                  uint32_t val)
136
{
137
    APBState *s = opaque;
138

    
139
    apb_pci_config_write(s, addr, bswap16(val), 2);
140
}
141

    
142
static void apb_pci_config_writeb(void *opaque, target_phys_addr_t addr,
143
                                  uint32_t val)
144
{
145
    APBState *s = opaque;
146

    
147
    apb_pci_config_write(s, addr, val, 1);
148
}
149

    
150
static uint32_t apb_pci_config_readl(void *opaque, target_phys_addr_t addr)
151
{
152
    APBState *s = opaque;
153

    
154
    return bswap32(apb_pci_config_read(s, addr, 4));
155
}
156

    
157
static uint32_t apb_pci_config_readw(void *opaque, target_phys_addr_t addr)
158
{
159
    APBState *s = opaque;
160

    
161
    return bswap16(apb_pci_config_read(s, addr, 2));
162
}
163

    
164
static uint32_t apb_pci_config_readb(void *opaque, target_phys_addr_t addr)
165
{
166
    APBState *s = opaque;
167

    
168
    return apb_pci_config_read(s, addr, 1);
169
}
170

    
171
static CPUWriteMemoryFunc * const apb_pci_config_writes[] = {
172
    &apb_pci_config_writeb,
173
    &apb_pci_config_writew,
174
    &apb_pci_config_writel,
175
};
176

    
177
static CPUReadMemoryFunc * const apb_pci_config_reads[] = {
178
    &apb_pci_config_readb,
179
    &apb_pci_config_readw,
180
    &apb_pci_config_readl,
181
};
182

    
183
static void pci_apb_iowriteb (void *opaque, target_phys_addr_t addr,
184
                                  uint32_t val)
185
{
186
    cpu_outb(addr & IOPORTS_MASK, val);
187
}
188

    
189
static void pci_apb_iowritew (void *opaque, target_phys_addr_t addr,
190
                                  uint32_t val)
191
{
192
    cpu_outw(addr & IOPORTS_MASK, val);
193
}
194

    
195
static void pci_apb_iowritel (void *opaque, target_phys_addr_t addr,
196
                                uint32_t val)
197
{
198
    cpu_outl(addr & IOPORTS_MASK, val);
199
}
200

    
201
static uint32_t pci_apb_ioreadb (void *opaque, target_phys_addr_t addr)
202
{
203
    uint32_t val;
204

    
205
    val = cpu_inb(addr & IOPORTS_MASK);
206
    return val;
207
}
208

    
209
static uint32_t pci_apb_ioreadw (void *opaque, target_phys_addr_t addr)
210
{
211
    uint32_t val;
212

    
213
    val = cpu_inw(addr & IOPORTS_MASK);
214
    return val;
215
}
216

    
217
static uint32_t pci_apb_ioreadl (void *opaque, target_phys_addr_t addr)
218
{
219
    uint32_t val;
220

    
221
    val = cpu_inl(addr & IOPORTS_MASK);
222
    return val;
223
}
224

    
225
static CPUWriteMemoryFunc * const pci_apb_iowrite[] = {
226
    &pci_apb_iowriteb,
227
    &pci_apb_iowritew,
228
    &pci_apb_iowritel,
229
};
230

    
231
static CPUReadMemoryFunc * const pci_apb_ioread[] = {
232
    &pci_apb_ioreadb,
233
    &pci_apb_ioreadw,
234
    &pci_apb_ioreadl,
235
};
236

    
237
/* The APB host has an IRQ line for each IRQ line of each slot.  */
238
static int pci_apb_map_irq(PCIDevice *pci_dev, int irq_num)
239
{
240
    return ((pci_dev->devfn & 0x18) >> 1) + irq_num;
241
}
242

    
243
static int pci_pbm_map_irq(PCIDevice *pci_dev, int irq_num)
244
{
245
    int bus_offset;
246
    if (pci_dev->devfn & 1)
247
        bus_offset = 16;
248
    else
249
        bus_offset = 0;
250
    return bus_offset + irq_num;
251
}
252

    
253
static void pci_apb_set_irq(void *opaque, int irq_num, int level)
254
{
255
    qemu_irq *pic = opaque;
256

    
257
    /* PCI IRQ map onto the first 32 INO.  */
258
    qemu_set_irq(pic[irq_num], level);
259
}
260

    
261
static void apb_pci_bridge_init(PCIBus *b)
262
{
263
    PCIDevice *dev = pci_bridge_get_device(b);
264

    
265
    /*
266
     * command register:
267
     * According to PCI bridge spec, after reset
268
     *   bus master bit is off
269
     *   memory space enable bit is off
270
     * According to manual (805-1251.pdf).
271
     *   the reset value should be zero unless the boot pin is tied high
272
     *   (which is true) and thus it should be PCI_COMMAND_MEMORY.
273
     */
274
    pci_set_word(dev->config + PCI_COMMAND,
275
                 PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
276
    dev->config[PCI_LATENCY_TIMER] = 0x10;
277
    dev->config[PCI_HEADER_TYPE] |= PCI_HEADER_TYPE_MULTI_FUNCTION;
278
}
279

    
280
PCIBus *pci_apb_init(target_phys_addr_t special_base,
281
                     target_phys_addr_t mem_base,
282
                     qemu_irq *pic, PCIBus **bus2, PCIBus **bus3)
283
{
284
    DeviceState *dev;
285
    SysBusDevice *s;
286
    APBState *d;
287

    
288
    /* Ultrasparc PBM main bus */
289
    dev = qdev_create(NULL, "pbm");
290
    qdev_init_nofail(dev);
291
    s = sysbus_from_qdev(dev);
292
    /* apb_config */
293
    sysbus_mmio_map(s, 0, special_base);
294
    /* pci_ioport */
295
    sysbus_mmio_map(s, 1, special_base + 0x2000000ULL);
296
    /* pci_config */
297
    sysbus_mmio_map(s, 2, special_base + 0x1000000ULL);
298
    /* mem_data */
299
    sysbus_mmio_map(s, 3, mem_base);
300
    d = FROM_SYSBUS(APBState, s);
301
    d->host_state.bus = pci_register_bus(&d->busdev.qdev, "pci",
302
                                         pci_apb_set_irq, pci_pbm_map_irq, pic,
303
                                         0, 32);
304
    pci_bus_set_mem_base(d->host_state.bus, mem_base);
305

    
306
    pci_create_simple(d->host_state.bus, 0, "pbm");
307
    /* APB secondary busses */
308
    *bus2 = pci_bridge_init(d->host_state.bus, PCI_DEVFN(1, 0),
309
                            PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_SIMBA,
310
                            pci_apb_map_irq,
311
                            "Advanced PCI Bus secondary bridge 1");
312
    apb_pci_bridge_init(*bus2);
313

    
314
    *bus3 = pci_bridge_init(d->host_state.bus, PCI_DEVFN(1, 1),
315
                            PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_SIMBA,
316
                            pci_apb_map_irq,
317
                            "Advanced PCI Bus secondary bridge 2");
318
    apb_pci_bridge_init(*bus3);
319

    
320
    return d->host_state.bus;
321
}
322

    
323
static int pci_pbm_init_device(SysBusDevice *dev)
324
{
325

    
326
    APBState *s;
327
    int pci_mem_data, apb_config, pci_ioport, pci_config;
328

    
329
    s = FROM_SYSBUS(APBState, dev);
330
    /* apb_config */
331
    apb_config = cpu_register_io_memory(apb_config_read,
332
                                        apb_config_write, s);
333
    sysbus_init_mmio(dev, 0x10000ULL, apb_config);
334
    /* pci_ioport */
335
    pci_ioport = cpu_register_io_memory(pci_apb_ioread,
336
                                          pci_apb_iowrite, s);
337
    sysbus_init_mmio(dev, 0x10000ULL, pci_ioport);
338
    /* pci_config */
339
    pci_config = cpu_register_io_memory(apb_pci_config_reads,
340
                                        apb_pci_config_writes, s);
341
    sysbus_init_mmio(dev, 0x1000000ULL, pci_config);
342
    /* mem_data */
343
    pci_mem_data = pci_host_data_register_mmio(&s->host_state);
344
    sysbus_init_mmio(dev, 0x10000000ULL, pci_mem_data);
345
    return 0;
346
}
347

    
348
static int pbm_pci_host_init(PCIDevice *d)
349
{
350
    pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_SUN);
351
    pci_config_set_device_id(d->config, PCI_DEVICE_ID_SUN_SABRE);
352
    d->config[0x04] = 0x06; // command = bus master, pci mem
353
    d->config[0x05] = 0x00;
354
    d->config[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error
355
    d->config[0x07] = 0x03; // status = medium devsel
356
    d->config[0x08] = 0x00; // revision
357
    d->config[0x09] = 0x00; // programming i/f
358
    pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST);
359
    d->config[0x0D] = 0x10; // latency_timer
360
    d->config[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; // header_type
361
    return 0;
362
}
363

    
364
static PCIDeviceInfo pbm_pci_host_info = {
365
    .qdev.name = "pbm",
366
    .qdev.size = sizeof(PCIDevice),
367
    .init      = pbm_pci_host_init,
368
    .header_type  = PCI_HEADER_TYPE_BRIDGE,
369
};
370

    
371
static void pbm_register_devices(void)
372
{
373
    sysbus_register_dev("pbm", sizeof(APBState), pci_pbm_init_device);
374
    pci_qdev_register(&pbm_pci_host_info);
375
}
376

    
377
device_init(pbm_register_devices)