Statistics
| Branch: | Revision:

root / hw / apb_pci.c @ 1eed09cb

History | View | Annotate | Download (8 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 "hw.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
typedef target_phys_addr_t pci_addr_t;
43
#include "pci_host.h"
44

    
45
typedef PCIHostState APBState;
46

    
47
static void pci_apb_config_writel (void *opaque, target_phys_addr_t addr,
48
                                         uint32_t val)
49
{
50
    APBState *s = opaque;
51

    
52
#ifdef TARGET_WORDS_BIGENDIAN
53
    val = bswap32(val);
54
#endif
55
    APB_DPRINTF("config_writel addr " TARGET_FMT_plx " val %x\n", addr,
56
                val);
57
    s->config_reg = val;
58
}
59

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

    
66
    val = s->config_reg;
67
#ifdef TARGET_WORDS_BIGENDIAN
68
    val = bswap32(val);
69
#endif
70
    APB_DPRINTF("config_readl addr " TARGET_FMT_plx " val %x\n", addr,
71
                val);
72
    return val;
73
}
74

    
75
static CPUWriteMemoryFunc *pci_apb_config_write[] = {
76
    &pci_apb_config_writel,
77
    &pci_apb_config_writel,
78
    &pci_apb_config_writel,
79
};
80

    
81
static CPUReadMemoryFunc *pci_apb_config_read[] = {
82
    &pci_apb_config_readl,
83
    &pci_apb_config_readl,
84
    &pci_apb_config_readl,
85
};
86

    
87
static void apb_config_writel (void *opaque, target_phys_addr_t addr,
88
                               uint32_t val)
89
{
90
    //PCIBus *s = opaque;
91

    
92
    switch (addr & 0x3f) {
93
    case 0x00: // Control/Status
94
    case 0x10: // AFSR
95
    case 0x18: // AFAR
96
    case 0x20: // Diagnostic
97
    case 0x28: // Target address space
98
        // XXX
99
    default:
100
        break;
101
    }
102
}
103

    
104
static uint32_t apb_config_readl (void *opaque,
105
                                  target_phys_addr_t addr)
106
{
107
    //PCIBus *s = opaque;
108
    uint32_t val;
109

    
110
    switch (addr & 0x3f) {
111
    case 0x00: // Control/Status
112
    case 0x10: // AFSR
113
    case 0x18: // AFAR
114
    case 0x20: // Diagnostic
115
    case 0x28: // Target address space
116
        // XXX
117
    default:
118
        val = 0;
119
        break;
120
    }
121
    return val;
122
}
123

    
124
static CPUWriteMemoryFunc *apb_config_write[] = {
125
    &apb_config_writel,
126
    &apb_config_writel,
127
    &apb_config_writel,
128
};
129

    
130
static CPUReadMemoryFunc *apb_config_read[] = {
131
    &apb_config_readl,
132
    &apb_config_readl,
133
    &apb_config_readl,
134
};
135

    
136
static CPUWriteMemoryFunc *pci_apb_write[] = {
137
    &pci_host_data_writeb,
138
    &pci_host_data_writew,
139
    &pci_host_data_writel,
140
};
141

    
142
static CPUReadMemoryFunc *pci_apb_read[] = {
143
    &pci_host_data_readb,
144
    &pci_host_data_readw,
145
    &pci_host_data_readl,
146
};
147

    
148
static void pci_apb_iowriteb (void *opaque, target_phys_addr_t addr,
149
                                  uint32_t val)
150
{
151
    cpu_outb(NULL, addr & 0xffff, val);
152
}
153

    
154
static void pci_apb_iowritew (void *opaque, target_phys_addr_t addr,
155
                                  uint32_t val)
156
{
157
    cpu_outw(NULL, addr & 0xffff, val);
158
}
159

    
160
static void pci_apb_iowritel (void *opaque, target_phys_addr_t addr,
161
                                uint32_t val)
162
{
163
    cpu_outl(NULL, addr & 0xffff, val);
164
}
165

    
166
static uint32_t pci_apb_ioreadb (void *opaque, target_phys_addr_t addr)
167
{
168
    uint32_t val;
169

    
170
    val = cpu_inb(NULL, addr & 0xffff);
171
    return val;
172
}
173

    
174
static uint32_t pci_apb_ioreadw (void *opaque, target_phys_addr_t addr)
175
{
176
    uint32_t val;
177

    
178
    val = cpu_inw(NULL, addr & 0xffff);
179
    return val;
180
}
181

    
182
static uint32_t pci_apb_ioreadl (void *opaque, target_phys_addr_t addr)
183
{
184
    uint32_t val;
185

    
186
    val = cpu_inl(NULL, addr & 0xffff);
187
    return val;
188
}
189

    
190
static CPUWriteMemoryFunc *pci_apb_iowrite[] = {
191
    &pci_apb_iowriteb,
192
    &pci_apb_iowritew,
193
    &pci_apb_iowritel,
194
};
195

    
196
static CPUReadMemoryFunc *pci_apb_ioread[] = {
197
    &pci_apb_ioreadb,
198
    &pci_apb_ioreadw,
199
    &pci_apb_ioreadl,
200
};
201

    
202
/* The APB host has an IRQ line for each IRQ line of each slot.  */
203
static int pci_apb_map_irq(PCIDevice *pci_dev, int irq_num)
204
{
205
    return ((pci_dev->devfn & 0x18) >> 1) + irq_num;
206
}
207

    
208
static int pci_pbm_map_irq(PCIDevice *pci_dev, int irq_num)
209
{
210
    int bus_offset;
211
    if (pci_dev->devfn & 1)
212
        bus_offset = 16;
213
    else
214
        bus_offset = 0;
215
    return bus_offset + irq_num;
216
}
217

    
218
static void pci_apb_set_irq(qemu_irq *pic, int irq_num, int level)
219
{
220
    /* PCI IRQ map onto the first 32 INO.  */
221
    qemu_set_irq(pic[irq_num], level);
222
}
223

    
224
PCIBus *pci_apb_init(target_phys_addr_t special_base,
225
                     target_phys_addr_t mem_base,
226
                     qemu_irq *pic, PCIBus **bus2, PCIBus **bus3)
227
{
228
    APBState *s;
229
    PCIDevice *d;
230
    int pci_mem_config, pci_mem_data, apb_config, pci_ioport;
231

    
232
    s = qemu_mallocz(sizeof(APBState));
233
    /* Ultrasparc PBM main bus */
234
    s->bus = pci_register_bus(NULL, "pci",
235
                              pci_apb_set_irq, pci_pbm_map_irq, pic, 0, 32);
236

    
237
    pci_mem_config = cpu_register_io_memory(pci_apb_config_read,
238
                                            pci_apb_config_write, s);
239
    apb_config = cpu_register_io_memory(apb_config_read,
240
                                        apb_config_write, s);
241
    pci_mem_data = cpu_register_io_memory(pci_apb_read,
242
                                          pci_apb_write, s);
243
    pci_ioport = cpu_register_io_memory(pci_apb_ioread,
244
                                          pci_apb_iowrite, s);
245

    
246
    cpu_register_physical_memory(special_base + 0x2000ULL, 0x40, apb_config);
247
    cpu_register_physical_memory(special_base + 0x1000000ULL, 0x10,
248
                                 pci_mem_config);
249
    cpu_register_physical_memory(special_base + 0x2000000ULL, 0x10000,
250
                                 pci_ioport);
251
    cpu_register_physical_memory(mem_base, 0x10000000,
252
                                 pci_mem_data); // XXX size should be 4G-prom
253

    
254
    d = pci_register_device(s->bus, "Advanced PCI Bus", sizeof(PCIDevice),
255
                            0, NULL, NULL);
256
    pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_SUN);
257
    pci_config_set_device_id(d->config, PCI_DEVICE_ID_SUN_SABRE);
258
    d->config[0x04] = 0x06; // command = bus master, pci mem
259
    d->config[0x05] = 0x00;
260
    d->config[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error
261
    d->config[0x07] = 0x03; // status = medium devsel
262
    d->config[0x08] = 0x00; // revision
263
    d->config[0x09] = 0x00; // programming i/f
264
    pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST);
265
    d->config[0x0D] = 0x10; // latency_timer
266
    d->config[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; // header_type
267

    
268
    /* APB secondary busses */
269
    *bus2 = pci_bridge_init(s->bus, 8, PCI_VENDOR_ID_SUN,
270
                            PCI_DEVICE_ID_SUN_SIMBA, pci_apb_map_irq,
271
                            "Advanced PCI Bus secondary bridge 1");
272
    *bus3 = pci_bridge_init(s->bus, 9, PCI_VENDOR_ID_SUN,
273
                            PCI_DEVICE_ID_SUN_SIMBA, pci_apb_map_irq,
274
                            "Advanced PCI Bus secondary bridge 2");
275
    return s->bus;
276
}