Statistics
| Branch: | Revision:

root / hw / apb_pci.c @ 18e08a55

History | View | Annotate | Download (7.9 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
PCIBus *pci_apb_init(target_phys_addr_t special_base,
186
                     target_phys_addr_t mem_base,
187
                     qemu_irq *pic, PCIBus **bus2, PCIBus **bus3)
188
{
189
    DeviceState *dev;
190
    SysBusDevice *s;
191
    APBState *d;
192

    
193
    /* Ultrasparc PBM main bus */
194
    dev = qdev_create(NULL, "pbm");
195
    qdev_init_nofail(dev);
196
    s = sysbus_from_qdev(dev);
197
    /* apb_config */
198
    sysbus_mmio_map(s, 0, special_base + 0x2000ULL);
199
    /* pci_ioport */
200
    sysbus_mmio_map(s, 1, special_base + 0x2000000ULL);
201
    /* mem_config: XXX size should be 4G-prom */
202
    sysbus_mmio_map(s, 2, special_base + 0x1000000ULL);
203
    /* mem_data */
204
    sysbus_mmio_map(s, 3, mem_base);
205
    d = FROM_SYSBUS(APBState, s);
206
    d->host_state.bus = pci_register_bus(&d->busdev.qdev, "pci",
207
                                         pci_apb_set_irq, pci_pbm_map_irq, pic,
208
                                         0, 32);
209
    pci_create_simple(d->host_state.bus, 0, "pbm");
210
    /* APB secondary busses */
211
    *bus2 = pci_bridge_init(d->host_state.bus, PCI_DEVFN(1, 0),
212
                            PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_SIMBA,
213
                            pci_apb_map_irq,
214
                            "Advanced PCI Bus secondary bridge 1");
215
    *bus3 = pci_bridge_init(d->host_state.bus, PCI_DEVFN(1, 1),
216
                            PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_SIMBA,
217
                            pci_apb_map_irq,
218
                            "Advanced PCI Bus secondary bridge 2");
219

    
220
    return d->host_state.bus;
221
}
222

    
223
static int pci_pbm_init_device(SysBusDevice *dev)
224
{
225

    
226
    APBState *s;
227
    int pci_mem_config, pci_mem_data, apb_config, pci_ioport;
228

    
229
    s = FROM_SYSBUS(APBState, dev);
230
    /* apb_config */
231
    apb_config = cpu_register_io_memory(apb_config_read,
232
                                        apb_config_write, s);
233
    sysbus_init_mmio(dev, 0x40ULL, apb_config);
234
    /* pci_ioport */
235
    pci_ioport = cpu_register_io_memory(pci_apb_ioread,
236
                                          pci_apb_iowrite, s);
237
    sysbus_init_mmio(dev, 0x10000ULL, pci_ioport);
238
    /* mem_config  */
239
    pci_mem_config = pci_host_config_register_io_memory(&s->host_state);
240
    sysbus_init_mmio(dev, 0x10ULL, pci_mem_config);
241
    /* mem_data */
242
    pci_mem_data = pci_host_data_register_io_memory(&s->host_state);
243
    sysbus_init_mmio(dev, 0x10000000ULL, pci_mem_data);
244
    return 0;
245
}
246

    
247
static int pbm_pci_host_init(PCIDevice *d)
248
{
249
    pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_SUN);
250
    pci_config_set_device_id(d->config, PCI_DEVICE_ID_SUN_SABRE);
251
    d->config[0x04] = 0x06; // command = bus master, pci mem
252
    d->config[0x05] = 0x00;
253
    d->config[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error
254
    d->config[0x07] = 0x03; // status = medium devsel
255
    d->config[0x08] = 0x00; // revision
256
    d->config[0x09] = 0x00; // programming i/f
257
    pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST);
258
    d->config[0x0D] = 0x10; // latency_timer
259
    d->config[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; // header_type
260
    return 0;
261
}
262

    
263
static PCIDeviceInfo pbm_pci_host_info = {
264
    .qdev.name = "pbm",
265
    .qdev.size = sizeof(PCIDevice),
266
    .init      = pbm_pci_host_init,
267
};
268

    
269
static void pbm_register_devices(void)
270
{
271
    sysbus_register_dev("pbm", sizeof(APBState), pci_pbm_init_device);
272
    pci_qdev_register(&pbm_pci_host_info);
273
}
274

    
275
device_init(pbm_register_devices)