Statistics
| Branch: | Revision:

root / hw / apb_pci.c @ 409570a7

History | View | Annotate | Download (8.6 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 pci_apb_iowriteb (void *opaque, target_phys_addr_t addr,
108
                                  uint32_t val)
109
{
110
    cpu_outb(addr & IOPORTS_MASK, val);
111
}
112

    
113
static void pci_apb_iowritew (void *opaque, target_phys_addr_t addr,
114
                                  uint32_t val)
115
{
116
    cpu_outw(addr & IOPORTS_MASK, val);
117
}
118

    
119
static void pci_apb_iowritel (void *opaque, target_phys_addr_t addr,
120
                                uint32_t val)
121
{
122
    cpu_outl(addr & IOPORTS_MASK, val);
123
}
124

    
125
static uint32_t pci_apb_ioreadb (void *opaque, target_phys_addr_t addr)
126
{
127
    uint32_t val;
128

    
129
    val = cpu_inb(addr & IOPORTS_MASK);
130
    return val;
131
}
132

    
133
static uint32_t pci_apb_ioreadw (void *opaque, target_phys_addr_t addr)
134
{
135
    uint32_t val;
136

    
137
    val = cpu_inw(addr & IOPORTS_MASK);
138
    return val;
139
}
140

    
141
static uint32_t pci_apb_ioreadl (void *opaque, target_phys_addr_t addr)
142
{
143
    uint32_t val;
144

    
145
    val = cpu_inl(addr & IOPORTS_MASK);
146
    return val;
147
}
148

    
149
static CPUWriteMemoryFunc * const pci_apb_iowrite[] = {
150
    &pci_apb_iowriteb,
151
    &pci_apb_iowritew,
152
    &pci_apb_iowritel,
153
};
154

    
155
static CPUReadMemoryFunc * const pci_apb_ioread[] = {
156
    &pci_apb_ioreadb,
157
    &pci_apb_ioreadw,
158
    &pci_apb_ioreadl,
159
};
160

    
161
/* The APB host has an IRQ line for each IRQ line of each slot.  */
162
static int pci_apb_map_irq(PCIDevice *pci_dev, int irq_num)
163
{
164
    return ((pci_dev->devfn & 0x18) >> 1) + irq_num;
165
}
166

    
167
static int pci_pbm_map_irq(PCIDevice *pci_dev, int irq_num)
168
{
169
    int bus_offset;
170
    if (pci_dev->devfn & 1)
171
        bus_offset = 16;
172
    else
173
        bus_offset = 0;
174
    return bus_offset + irq_num;
175
}
176

    
177
static void pci_apb_set_irq(void *opaque, int irq_num, int level)
178
{
179
    qemu_irq *pic = opaque;
180

    
181
    /* PCI IRQ map onto the first 32 INO.  */
182
    qemu_set_irq(pic[irq_num], level);
183
}
184

    
185
static void apb_pci_bridge_init(PCIBus *b)
186
{
187
    PCIDevice *dev = pci_bridge_get_device(b);
188

    
189
    /*
190
     * command register:
191
     * According to PCI bridge spec, after reset
192
     *   bus master bit is off
193
     *   memory space enable bit is off
194
     * According to manual (805-1251.pdf).
195
     *   the reset value should be zero unless the boot pin is tied high
196
     *   (which is true) and thus it should be PCI_COMMAND_MEMORY.
197
     */
198
    pci_set_word(dev->config + PCI_COMMAND,
199
                 PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
200
    dev->config[PCI_LATENCY_TIMER] = 0x10;
201
    dev->config[PCI_HEADER_TYPE] |= PCI_HEADER_TYPE_MULTI_FUNCTION;
202
}
203

    
204
PCIBus *pci_apb_init(target_phys_addr_t special_base,
205
                     target_phys_addr_t mem_base,
206
                     qemu_irq *pic, PCIBus **bus2, PCIBus **bus3)
207
{
208
    DeviceState *dev;
209
    SysBusDevice *s;
210
    APBState *d;
211

    
212
    /* Ultrasparc PBM main bus */
213
    dev = qdev_create(NULL, "pbm");
214
    qdev_init_nofail(dev);
215
    s = sysbus_from_qdev(dev);
216
    /* apb_config */
217
    sysbus_mmio_map(s, 0, special_base + 0x2000ULL);
218
    /* pci_ioport */
219
    sysbus_mmio_map(s, 1, special_base + 0x2000000ULL);
220
    /* mem_config: XXX size should be 4G-prom */
221
    sysbus_mmio_map(s, 2, special_base + 0x1000000ULL);
222
    /* mem_data */
223
    sysbus_mmio_map(s, 3, mem_base);
224
    d = FROM_SYSBUS(APBState, s);
225
    d->host_state.bus = pci_register_bus(&d->busdev.qdev, "pci",
226
                                         pci_apb_set_irq, pci_pbm_map_irq, pic,
227
                                         0, 32);
228
    pci_create_simple(d->host_state.bus, 0, "pbm");
229
    /* APB secondary busses */
230
    *bus2 = pci_bridge_init(d->host_state.bus, PCI_DEVFN(1, 0),
231
                            PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_SIMBA,
232
                            pci_apb_map_irq,
233
                            "Advanced PCI Bus secondary bridge 1");
234
    apb_pci_bridge_init(*bus2);
235

    
236
    *bus3 = pci_bridge_init(d->host_state.bus, PCI_DEVFN(1, 1),
237
                            PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_SIMBA,
238
                            pci_apb_map_irq,
239
                            "Advanced PCI Bus secondary bridge 2");
240
    apb_pci_bridge_init(*bus3);
241

    
242
    return d->host_state.bus;
243
}
244

    
245
static int pci_pbm_init_device(SysBusDevice *dev)
246
{
247

    
248
    APBState *s;
249
    int pci_mem_config, pci_mem_data, apb_config, pci_ioport;
250

    
251
    s = FROM_SYSBUS(APBState, dev);
252
    /* apb_config */
253
    apb_config = cpu_register_io_memory(apb_config_read,
254
                                        apb_config_write, s);
255
    sysbus_init_mmio(dev, 0x40ULL, apb_config);
256
    /* pci_ioport */
257
    pci_ioport = cpu_register_io_memory(pci_apb_ioread,
258
                                          pci_apb_iowrite, s);
259
    sysbus_init_mmio(dev, 0x10000ULL, pci_ioport);
260
    /* mem_config  */
261
    pci_mem_config = pci_host_conf_register_mmio(&s->host_state);
262
    sysbus_init_mmio(dev, 0x10ULL, pci_mem_config);
263
    /* mem_data */
264
    pci_mem_data = pci_host_data_register_mmio(&s->host_state);
265
    sysbus_init_mmio(dev, 0x10000000ULL, pci_mem_data);
266
    return 0;
267
}
268

    
269
static int pbm_pci_host_init(PCIDevice *d)
270
{
271
    pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_SUN);
272
    pci_config_set_device_id(d->config, PCI_DEVICE_ID_SUN_SABRE);
273
    d->config[0x04] = 0x06; // command = bus master, pci mem
274
    d->config[0x05] = 0x00;
275
    d->config[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error
276
    d->config[0x07] = 0x03; // status = medium devsel
277
    d->config[0x08] = 0x00; // revision
278
    d->config[0x09] = 0x00; // programming i/f
279
    pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST);
280
    d->config[0x0D] = 0x10; // latency_timer
281
    d->config[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; // header_type
282
    return 0;
283
}
284

    
285
static PCIDeviceInfo pbm_pci_host_info = {
286
    .qdev.name = "pbm",
287
    .qdev.size = sizeof(PCIDevice),
288
    .init      = pbm_pci_host_init,
289
};
290

    
291
static void pbm_register_devices(void)
292
{
293
    sysbus_register_dev("pbm", sizeof(APBState), pci_pbm_init_device);
294
    pci_qdev_register(&pbm_pci_host_info);
295
}
296

    
297
device_init(pbm_register_devices)