Statistics
| Branch: | Revision:

root / hw / apb_pci.c @ 930f3fe1

History | View | Annotate | Download (9.2 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

    
32
/* debug APB */
33
//#define DEBUG_APB
34

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

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

    
51
typedef target_phys_addr_t pci_addr_t;
52
#include "pci_host.h"
53

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

    
59
static void pci_apb_config_writel (void *opaque, target_phys_addr_t addr,
60
                                         uint32_t val)
61
{
62
    APBState *s = opaque;
63

    
64
#ifdef TARGET_WORDS_BIGENDIAN
65
    val = bswap32(val);
66
#endif
67
    APB_DPRINTF("config_writel addr " TARGET_FMT_plx " val %x\n", addr,
68
                val);
69
    s->host_state.config_reg = val;
70
}
71

    
72
static uint32_t pci_apb_config_readl (void *opaque,
73
                                            target_phys_addr_t addr)
74
{
75
    APBState *s = opaque;
76
    uint32_t val;
77

    
78
    val = s->host_state.config_reg;
79
#ifdef TARGET_WORDS_BIGENDIAN
80
    val = bswap32(val);
81
#endif
82
    APB_DPRINTF("config_readl addr " TARGET_FMT_plx " val %x\n", addr,
83
                val);
84
    return val;
85
}
86

    
87
static CPUWriteMemoryFunc * const pci_apb_config_write[] = {
88
    &pci_apb_config_writel,
89
    &pci_apb_config_writel,
90
    &pci_apb_config_writel,
91
};
92

    
93
static CPUReadMemoryFunc * const pci_apb_config_read[] = {
94
    &pci_apb_config_readl,
95
    &pci_apb_config_readl,
96
    &pci_apb_config_readl,
97
};
98

    
99
static void apb_config_writel (void *opaque, target_phys_addr_t addr,
100
                               uint32_t val)
101
{
102
    //PCIBus *s = opaque;
103

    
104
    switch (addr & 0x3f) {
105
    case 0x00: // Control/Status
106
    case 0x10: // AFSR
107
    case 0x18: // AFAR
108
    case 0x20: // Diagnostic
109
    case 0x28: // Target address space
110
        // XXX
111
    default:
112
        break;
113
    }
114
}
115

    
116
static uint32_t apb_config_readl (void *opaque,
117
                                  target_phys_addr_t addr)
118
{
119
    //PCIBus *s = opaque;
120
    uint32_t val;
121

    
122
    switch (addr & 0x3f) {
123
    case 0x00: // Control/Status
124
    case 0x10: // AFSR
125
    case 0x18: // AFAR
126
    case 0x20: // Diagnostic
127
    case 0x28: // Target address space
128
        // XXX
129
    default:
130
        val = 0;
131
        break;
132
    }
133
    return val;
134
}
135

    
136
static CPUWriteMemoryFunc * const apb_config_write[] = {
137
    &apb_config_writel,
138
    &apb_config_writel,
139
    &apb_config_writel,
140
};
141

    
142
static CPUReadMemoryFunc * const apb_config_read[] = {
143
    &apb_config_readl,
144
    &apb_config_readl,
145
    &apb_config_readl,
146
};
147

    
148
static CPUWriteMemoryFunc * const pci_apb_write[] = {
149
    &pci_host_data_writeb,
150
    &pci_host_data_writew,
151
    &pci_host_data_writel,
152
};
153

    
154
static CPUReadMemoryFunc * const pci_apb_read[] = {
155
    &pci_host_data_readb,
156
    &pci_host_data_readw,
157
    &pci_host_data_readl,
158
};
159

    
160
static void pci_apb_iowriteb (void *opaque, target_phys_addr_t addr,
161
                                  uint32_t val)
162
{
163
    cpu_outb(addr & IOPORTS_MASK, val);
164
}
165

    
166
static void pci_apb_iowritew (void *opaque, target_phys_addr_t addr,
167
                                  uint32_t val)
168
{
169
    cpu_outw(addr & IOPORTS_MASK, val);
170
}
171

    
172
static void pci_apb_iowritel (void *opaque, target_phys_addr_t addr,
173
                                uint32_t val)
174
{
175
    cpu_outl(addr & IOPORTS_MASK, val);
176
}
177

    
178
static uint32_t pci_apb_ioreadb (void *opaque, target_phys_addr_t addr)
179
{
180
    uint32_t val;
181

    
182
    val = cpu_inb(addr & IOPORTS_MASK);
183
    return val;
184
}
185

    
186
static uint32_t pci_apb_ioreadw (void *opaque, target_phys_addr_t addr)
187
{
188
    uint32_t val;
189

    
190
    val = cpu_inw(addr & IOPORTS_MASK);
191
    return val;
192
}
193

    
194
static uint32_t pci_apb_ioreadl (void *opaque, target_phys_addr_t addr)
195
{
196
    uint32_t val;
197

    
198
    val = cpu_inl(addr & IOPORTS_MASK);
199
    return val;
200
}
201

    
202
static CPUWriteMemoryFunc * const pci_apb_iowrite[] = {
203
    &pci_apb_iowriteb,
204
    &pci_apb_iowritew,
205
    &pci_apb_iowritel,
206
};
207

    
208
static CPUReadMemoryFunc * const pci_apb_ioread[] = {
209
    &pci_apb_ioreadb,
210
    &pci_apb_ioreadw,
211
    &pci_apb_ioreadl,
212
};
213

    
214
/* The APB host has an IRQ line for each IRQ line of each slot.  */
215
static int pci_apb_map_irq(PCIDevice *pci_dev, int irq_num)
216
{
217
    return ((pci_dev->devfn & 0x18) >> 1) + irq_num;
218
}
219

    
220
static int pci_pbm_map_irq(PCIDevice *pci_dev, int irq_num)
221
{
222
    int bus_offset;
223
    if (pci_dev->devfn & 1)
224
        bus_offset = 16;
225
    else
226
        bus_offset = 0;
227
    return bus_offset + irq_num;
228
}
229

    
230
static void pci_apb_set_irq(void *opaque, int irq_num, int level)
231
{
232
    qemu_irq *pic = opaque;
233

    
234
    /* PCI IRQ map onto the first 32 INO.  */
235
    qemu_set_irq(pic[irq_num], level);
236
}
237

    
238
PCIBus *pci_apb_init(target_phys_addr_t special_base,
239
                     target_phys_addr_t mem_base,
240
                     qemu_irq *pic, PCIBus **bus2, PCIBus **bus3)
241
{
242
    DeviceState *dev;
243
    SysBusDevice *s;
244
    APBState *d;
245

    
246
    /* Ultrasparc PBM main bus */
247
    dev = qdev_create(NULL, "pbm");
248
    qdev_init_nofail(dev);
249
    s = sysbus_from_qdev(dev);
250
    /* apb_config */
251
    sysbus_mmio_map(s, 0, special_base + 0x2000ULL);
252
    /* pci_ioport */
253
    sysbus_mmio_map(s, 1, special_base + 0x2000000ULL);
254
    /* mem_config: XXX size should be 4G-prom */
255
    sysbus_mmio_map(s, 2, special_base + 0x1000000ULL);
256
    /* mem_data */
257
    sysbus_mmio_map(s, 3, mem_base);
258
    d = FROM_SYSBUS(APBState, s);
259
    d->host_state.bus = pci_register_bus(&d->busdev.qdev, "pci",
260
                                         pci_apb_set_irq, pci_pbm_map_irq, pic,
261
                                         0, 32);
262
    pci_create_simple(d->host_state.bus, 0, "pbm");
263
    /* APB secondary busses */
264
    *bus2 = pci_bridge_init(d->host_state.bus, 8, PCI_VENDOR_ID_SUN,
265
                            PCI_DEVICE_ID_SUN_SIMBA, pci_apb_map_irq,
266
                            "Advanced PCI Bus secondary bridge 1");
267
    *bus3 = pci_bridge_init(d->host_state.bus, 9, PCI_VENDOR_ID_SUN,
268
                            PCI_DEVICE_ID_SUN_SIMBA, pci_apb_map_irq,
269
                            "Advanced PCI Bus secondary bridge 2");
270

    
271
    return d->host_state.bus;
272
}
273

    
274
static int pci_pbm_init_device(SysBusDevice *dev)
275
{
276

    
277
    APBState *s;
278
    int pci_mem_config, pci_mem_data, apb_config, pci_ioport;
279

    
280
    s = FROM_SYSBUS(APBState, dev);
281
    /* apb_config */
282
    apb_config = cpu_register_io_memory(apb_config_read,
283
                                        apb_config_write, s);
284
    sysbus_init_mmio(dev, 0x40ULL, apb_config);
285
    /* pci_ioport */
286
    pci_ioport = cpu_register_io_memory(pci_apb_ioread,
287
                                          pci_apb_iowrite, s);
288
    sysbus_init_mmio(dev, 0x10000ULL, pci_ioport);
289
    /* mem_config  */
290
    pci_mem_config = cpu_register_io_memory(pci_apb_config_read,
291
                                            pci_apb_config_write, s);
292
    sysbus_init_mmio(dev, 0x10ULL, pci_mem_config);
293
    /* mem_data */
294
    pci_mem_data = cpu_register_io_memory(pci_apb_read,
295
                                          pci_apb_write, &s->host_state);
296
    sysbus_init_mmio(dev, 0x10000000ULL, pci_mem_data);
297
    return 0;
298
}
299

    
300
static int pbm_pci_host_init(PCIDevice *d)
301
{
302
    pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_SUN);
303
    pci_config_set_device_id(d->config, PCI_DEVICE_ID_SUN_SABRE);
304
    d->config[0x04] = 0x06; // command = bus master, pci mem
305
    d->config[0x05] = 0x00;
306
    d->config[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error
307
    d->config[0x07] = 0x03; // status = medium devsel
308
    d->config[0x08] = 0x00; // revision
309
    d->config[0x09] = 0x00; // programming i/f
310
    pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST);
311
    d->config[0x0D] = 0x10; // latency_timer
312
    d->config[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; // header_type
313
    return 0;
314
}
315

    
316
static PCIDeviceInfo pbm_pci_host_info = {
317
    .qdev.name = "pbm",
318
    .qdev.size = sizeof(PCIDevice),
319
    .init      = pbm_pci_host_init,
320
};
321

    
322
static void pbm_register_devices(void)
323
{
324
    sysbus_register_dev("pbm", sizeof(APBState), pci_pbm_init_device);
325
    pci_qdev_register(&pbm_pci_host_info);
326
}
327

    
328
device_init(pbm_register_devices)