Statistics
| Branch: | Revision:

root / hw / apb_pci.c @ 77f193da

History | View | Annotate | Download (7.7 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 contests 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
typedef target_phys_addr_t pci_addr_t;
32
#include "pci_host.h"
33

    
34
typedef PCIHostState APBState;
35

    
36
static void pci_apb_config_writel (void *opaque, target_phys_addr_t addr,
37
                                         uint32_t val)
38
{
39
    APBState *s = opaque;
40
    int i;
41

    
42
    for (i = 11; i < 32; i++) {
43
        if ((val & (1 << i)) != 0)
44
            break;
45
    }
46
    s->config_reg = (1 << 16) | (val & 0x7FC) | (i << 11);
47
}
48

    
49
static uint32_t pci_apb_config_readl (void *opaque,
50
                                            target_phys_addr_t addr)
51
{
52
    APBState *s = opaque;
53
    uint32_t val;
54
    int devfn;
55

    
56
    devfn = (s->config_reg >> 8) & 0xFF;
57
    val = (1 << (devfn >> 3)) | ((devfn & 0x07) << 8) | (s->config_reg & 0xFC);
58
    return val;
59
}
60

    
61
static CPUWriteMemoryFunc *pci_apb_config_write[] = {
62
    &pci_apb_config_writel,
63
    &pci_apb_config_writel,
64
    &pci_apb_config_writel,
65
};
66

    
67
static CPUReadMemoryFunc *pci_apb_config_read[] = {
68
    &pci_apb_config_readl,
69
    &pci_apb_config_readl,
70
    &pci_apb_config_readl,
71
};
72

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

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

    
90
static uint32_t apb_config_readl (void *opaque,
91
                                  target_phys_addr_t addr)
92
{
93
    //PCIBus *s = opaque;
94
    uint32_t val;
95

    
96
    switch (addr & 0x3f) {
97
    case 0x00: // Control/Status
98
    case 0x10: // AFSR
99
    case 0x18: // AFAR
100
    case 0x20: // Diagnostic
101
    case 0x28: // Target address space
102
        // XXX
103
    default:
104
        val = 0;
105
        break;
106
    }
107
    return val;
108
}
109

    
110
static CPUWriteMemoryFunc *apb_config_write[] = {
111
    &apb_config_writel,
112
    &apb_config_writel,
113
    &apb_config_writel,
114
};
115

    
116
static CPUReadMemoryFunc *apb_config_read[] = {
117
    &apb_config_readl,
118
    &apb_config_readl,
119
    &apb_config_readl,
120
};
121

    
122
static CPUWriteMemoryFunc *pci_apb_write[] = {
123
    &pci_host_data_writeb,
124
    &pci_host_data_writew,
125
    &pci_host_data_writel,
126
};
127

    
128
static CPUReadMemoryFunc *pci_apb_read[] = {
129
    &pci_host_data_readb,
130
    &pci_host_data_readw,
131
    &pci_host_data_readl,
132
};
133

    
134
static void pci_apb_iowriteb (void *opaque, target_phys_addr_t addr,
135
                                  uint32_t val)
136
{
137
    cpu_outb(NULL, addr & 0xffff, val);
138
}
139

    
140
static void pci_apb_iowritew (void *opaque, target_phys_addr_t addr,
141
                                  uint32_t val)
142
{
143
    cpu_outw(NULL, addr & 0xffff, val);
144
}
145

    
146
static void pci_apb_iowritel (void *opaque, target_phys_addr_t addr,
147
                                uint32_t val)
148
{
149
    cpu_outl(NULL, addr & 0xffff, val);
150
}
151

    
152
static uint32_t pci_apb_ioreadb (void *opaque, target_phys_addr_t addr)
153
{
154
    uint32_t val;
155

    
156
    val = cpu_inb(NULL, addr & 0xffff);
157
    return val;
158
}
159

    
160
static uint32_t pci_apb_ioreadw (void *opaque, target_phys_addr_t addr)
161
{
162
    uint32_t val;
163

    
164
    val = cpu_inw(NULL, addr & 0xffff);
165
    return val;
166
}
167

    
168
static uint32_t pci_apb_ioreadl (void *opaque, target_phys_addr_t addr)
169
{
170
    uint32_t val;
171

    
172
    val = cpu_inl(NULL, addr & 0xffff);
173
    return val;
174
}
175

    
176
static CPUWriteMemoryFunc *pci_apb_iowrite[] = {
177
    &pci_apb_iowriteb,
178
    &pci_apb_iowritew,
179
    &pci_apb_iowritel,
180
};
181

    
182
static CPUReadMemoryFunc *pci_apb_ioread[] = {
183
    &pci_apb_ioreadb,
184
    &pci_apb_ioreadw,
185
    &pci_apb_ioreadl,
186
};
187

    
188
/* The APB host has an IRQ line for each IRQ line of each slot.  */
189
static int pci_apb_map_irq(PCIDevice *pci_dev, int irq_num)
190
{
191
    return ((pci_dev->devfn & 0x18) >> 1) + irq_num;
192
}
193

    
194
static int pci_pbm_map_irq(PCIDevice *pci_dev, int irq_num)
195
{
196
    int bus_offset;
197
    if (pci_dev->devfn & 1)
198
        bus_offset = 16;
199
    else
200
        bus_offset = 0;
201
    return bus_offset + irq_num;
202
}
203

    
204
static void pci_apb_set_irq(qemu_irq *pic, int irq_num, int level)
205
{
206
    /* PCI IRQ map onto the first 32 INO.  */
207
    qemu_set_irq(pic[irq_num], level);
208
}
209

    
210
PCIBus *pci_apb_init(target_phys_addr_t special_base,
211
                     target_phys_addr_t mem_base,
212
                     qemu_irq *pic)
213
{
214
    APBState *s;
215
    PCIDevice *d;
216
    int pci_mem_config, pci_mem_data, apb_config, pci_ioport;
217
    PCIBus *secondary;
218

    
219
    s = qemu_mallocz(sizeof(APBState));
220
    /* Ultrasparc PBM main bus */
221
    s->bus = pci_register_bus(pci_apb_set_irq, pci_pbm_map_irq, pic, 0, 32);
222

    
223
    pci_mem_config = cpu_register_io_memory(0, pci_apb_config_read,
224
                                            pci_apb_config_write, s);
225
    apb_config = cpu_register_io_memory(0, apb_config_read,
226
                                        apb_config_write, s);
227
    pci_mem_data = cpu_register_io_memory(0, pci_apb_read,
228
                                          pci_apb_write, s);
229
    pci_ioport = cpu_register_io_memory(0, pci_apb_ioread,
230
                                          pci_apb_iowrite, s);
231

    
232
    cpu_register_physical_memory(special_base + 0x2000ULL, 0x40, apb_config);
233
    cpu_register_physical_memory(special_base + 0x1000000ULL, 0x10,
234
                                 pci_mem_config);
235
    cpu_register_physical_memory(special_base + 0x2000000ULL, 0x10000,
236
                                 pci_ioport);
237
    cpu_register_physical_memory(mem_base, 0x10000000,
238
                                 pci_mem_data); // XXX size should be 4G-prom
239

    
240
    d = pci_register_device(s->bus, "Advanced PCI Bus", sizeof(PCIDevice),
241
                            0, NULL, NULL);
242
    d->config[0x00] = 0x8e; // vendor_id : Sun
243
    d->config[0x01] = 0x10;
244
    d->config[0x02] = 0x00; // device_id
245
    d->config[0x03] = 0xa0;
246
    d->config[0x04] = 0x06; // command = bus master, pci mem
247
    d->config[0x05] = 0x00;
248
    d->config[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error
249
    d->config[0x07] = 0x03; // status = medium devsel
250
    d->config[0x08] = 0x00; // revision
251
    d->config[0x09] = 0x00; // programming i/f
252
    d->config[0x0A] = 0x00; // class_sub = pci host
253
    d->config[0x0B] = 0x06; // class_base = PCI_bridge
254
    d->config[0x0D] = 0x10; // latency_timer
255
    d->config[0x0E] = 0x00; // header_type
256

    
257
    /* APB secondary busses */
258
    secondary = pci_bridge_init(s->bus, 8, 0x108e5000, pci_apb_map_irq,
259
                                "Advanced PCI Bus secondary bridge 1");
260
    pci_bridge_init(s->bus, 9, 0x108e5000, pci_apb_map_irq,
261
                    "Advanced PCI Bus secondary bridge 2");
262
    return secondary;
263
}
264

    
265