Statistics
| Branch: | Revision:

root / hw / apb_pci.c @ a455783b

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

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

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

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

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

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

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

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

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

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

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

    
106
static void pci_apb_iowriteb (void *opaque, target_phys_addr_t addr,
107
                                  uint32_t val)
108
{
109
    cpu_outb(addr & IOPORTS_MASK, val);
110
}
111

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
184
PCIBus *pci_apb_init(target_phys_addr_t special_base,
185
                     target_phys_addr_t mem_base,
186
                     qemu_irq *pic, PCIBus **bus2, PCIBus **bus3)
187
{
188
    DeviceState *dev;
189
    SysBusDevice *s;
190
    APBState *d;
191

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

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

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

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

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

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

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

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

    
274
device_init(pbm_register_devices)