Statistics
| Branch: | Revision:

root / hw / apb_pci.c @ d537cf6c

History | View | Annotate | Download (7.4 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 "vl.h"
30
typedef target_phys_addr_t pci_addr_t;
31
#include "pci_host.h"
32

    
33
typedef PCIHostState APBState;
34

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
253
    /* APB secondary busses */
254
    secondary = pci_bridge_init(s->bus, 8, 0x108e5000, pci_apb_map_irq, "Advanced PCI Bus secondary bridge 1");
255
    pci_bridge_init(s->bus, 9, 0x108e5000, pci_apb_map_irq, "Advanced PCI Bus secondary bridge 2");
256
    return secondary;
257
}
258

    
259