]> git.proxmox.com Git - qemu.git/blame - hw/apb_pci.c
pci: introduce constant PCI_NUM_PINS for the number of interrupt pins, 4.
[qemu.git] / hw / apb_pci.c
CommitLineData
502a5395
PB
1/*
2 * QEMU Ultrasparc APB PCI host
3 *
4 * Copyright (c) 2006 Fabrice Bellard
5fafdf24 5 *
502a5395
PB
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 */
80b3ada7 24
a94fd955 25/* XXX This file and most of its contents are somewhat misnamed. The
80b3ada7
PB
26 Ultrasparc PCI host is called the PCI Bus Module (PBM). The APB is
27 the secondary PCI bridge. */
28
72f44c8c 29#include "sysbus.h"
87ecb68b 30#include "pci.h"
a94fd955
BS
31
32/* debug APB */
33//#define DEBUG_APB
34
35#ifdef DEBUG_APB
001faf32
BS
36#define APB_DPRINTF(fmt, ...) \
37do { printf("APB: " fmt , ## __VA_ARGS__); } while (0)
a94fd955 38#else
001faf32 39#define APB_DPRINTF(fmt, ...)
a94fd955
BS
40#endif
41
930f3fe1
BS
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
c227f099 51typedef target_phys_addr_t pci_addr_t;
502a5395
PB
52#include "pci_host.h"
53
72f44c8c
BS
54typedef struct APBState {
55 SysBusDevice busdev;
56 PCIHostState host_state;
57} APBState;
502a5395 58
c227f099 59static void pci_apb_config_writel (void *opaque, target_phys_addr_t addr,
502a5395
PB
60 uint32_t val)
61{
62 APBState *s = opaque;
502a5395 63
a94fd955
BS
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);
72f44c8c 69 s->host_state.config_reg = val;
502a5395
PB
70}
71
72static uint32_t pci_apb_config_readl (void *opaque,
c227f099 73 target_phys_addr_t addr)
502a5395
PB
74{
75 APBState *s = opaque;
76 uint32_t val;
502a5395 77
72f44c8c 78 val = s->host_state.config_reg;
a94fd955
BS
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);
502a5395
PB
84 return val;
85}
86
d60efc6b 87static CPUWriteMemoryFunc * const pci_apb_config_write[] = {
502a5395
PB
88 &pci_apb_config_writel,
89 &pci_apb_config_writel,
90 &pci_apb_config_writel,
91};
92
d60efc6b 93static CPUReadMemoryFunc * const pci_apb_config_read[] = {
502a5395
PB
94 &pci_apb_config_readl,
95 &pci_apb_config_readl,
96 &pci_apb_config_readl,
97};
98
c227f099 99static void apb_config_writel (void *opaque, target_phys_addr_t addr,
f930d07e 100 uint32_t val)
502a5395
PB
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
f930d07e 110 // XXX
502a5395 111 default:
f930d07e 112 break;
502a5395
PB
113 }
114}
115
116static uint32_t apb_config_readl (void *opaque,
c227f099 117 target_phys_addr_t addr)
502a5395
PB
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
f930d07e 128 // XXX
502a5395 129 default:
f930d07e
BS
130 val = 0;
131 break;
502a5395
PB
132 }
133 return val;
134}
135
d60efc6b 136static CPUWriteMemoryFunc * const apb_config_write[] = {
502a5395
PB
137 &apb_config_writel,
138 &apb_config_writel,
139 &apb_config_writel,
140};
141
d60efc6b 142static CPUReadMemoryFunc * const apb_config_read[] = {
502a5395
PB
143 &apb_config_readl,
144 &apb_config_readl,
145 &apb_config_readl,
146};
147
d60efc6b 148static CPUWriteMemoryFunc * const pci_apb_write[] = {
502a5395
PB
149 &pci_host_data_writeb,
150 &pci_host_data_writew,
151 &pci_host_data_writel,
152};
153
d60efc6b 154static CPUReadMemoryFunc * const pci_apb_read[] = {
502a5395
PB
155 &pci_host_data_readb,
156 &pci_host_data_readw,
157 &pci_host_data_readl,
158};
159
c227f099 160static void pci_apb_iowriteb (void *opaque, target_phys_addr_t addr,
502a5395
PB
161 uint32_t val)
162{
afcea8cb 163 cpu_outb(addr & IOPORTS_MASK, val);
502a5395
PB
164}
165
c227f099 166static void pci_apb_iowritew (void *opaque, target_phys_addr_t addr,
502a5395
PB
167 uint32_t val)
168{
afcea8cb 169 cpu_outw(addr & IOPORTS_MASK, val);
502a5395
PB
170}
171
c227f099 172static void pci_apb_iowritel (void *opaque, target_phys_addr_t addr,
502a5395
PB
173 uint32_t val)
174{
afcea8cb 175 cpu_outl(addr & IOPORTS_MASK, val);
502a5395
PB
176}
177
c227f099 178static uint32_t pci_apb_ioreadb (void *opaque, target_phys_addr_t addr)
502a5395
PB
179{
180 uint32_t val;
181
afcea8cb 182 val = cpu_inb(addr & IOPORTS_MASK);
502a5395
PB
183 return val;
184}
185
c227f099 186static uint32_t pci_apb_ioreadw (void *opaque, target_phys_addr_t addr)
502a5395
PB
187{
188 uint32_t val;
189
afcea8cb 190 val = cpu_inw(addr & IOPORTS_MASK);
502a5395
PB
191 return val;
192}
193
c227f099 194static uint32_t pci_apb_ioreadl (void *opaque, target_phys_addr_t addr)
502a5395
PB
195{
196 uint32_t val;
197
afcea8cb 198 val = cpu_inl(addr & IOPORTS_MASK);
502a5395
PB
199 return val;
200}
201
d60efc6b 202static CPUWriteMemoryFunc * const pci_apb_iowrite[] = {
502a5395
PB
203 &pci_apb_iowriteb,
204 &pci_apb_iowritew,
205 &pci_apb_iowritel,
206};
207
d60efc6b 208static CPUReadMemoryFunc * const pci_apb_ioread[] = {
502a5395
PB
209 &pci_apb_ioreadb,
210 &pci_apb_ioreadw,
211 &pci_apb_ioreadl,
212};
213
80b3ada7 214/* The APB host has an IRQ line for each IRQ line of each slot. */
d2b59317 215static int pci_apb_map_irq(PCIDevice *pci_dev, int irq_num)
502a5395 216{
80b3ada7
PB
217 return ((pci_dev->devfn & 0x18) >> 1) + irq_num;
218}
219
220static 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;
d2b59317
PB
228}
229
5d4e84c8 230static void pci_apb_set_irq(void *opaque, int irq_num, int level)
d2b59317 231{
5d4e84c8
JQ
232 qemu_irq *pic = opaque;
233
80b3ada7 234 /* PCI IRQ map onto the first 32 INO. */
d537cf6c 235 qemu_set_irq(pic[irq_num], level);
502a5395
PB
236}
237
c227f099
AL
238PCIBus *pci_apb_init(target_phys_addr_t special_base,
239 target_phys_addr_t mem_base,
c190ea07 240 qemu_irq *pic, PCIBus **bus2, PCIBus **bus3)
502a5395 241{
72f44c8c
BS
242 DeviceState *dev;
243 SysBusDevice *s;
244 APBState *d;
502a5395 245
80b3ada7 246 /* Ultrasparc PBM main bus */
72f44c8c 247 dev = qdev_create(NULL, "pbm");
e23a1b33 248 qdev_init_nofail(dev);
72f44c8c
BS
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);
c5ff6d54 259 d->host_state.bus = pci_register_bus(&d->busdev.qdev, "pci",
72f44c8c
BS
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");
502a5395 270
72f44c8c
BS
271 return d->host_state.bus;
272}
273
81a322d4 274static int pci_pbm_init_device(SysBusDevice *dev)
72f44c8c
BS
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 */
1eed09cb 282 apb_config = cpu_register_io_memory(apb_config_read,
f930d07e 283 apb_config_write, s);
72f44c8c
BS
284 sysbus_init_mmio(dev, 0x40ULL, apb_config);
285 /* pci_ioport */
1eed09cb 286 pci_ioport = cpu_register_io_memory(pci_apb_ioread,
502a5395 287 pci_apb_iowrite, s);
72f44c8c
BS
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);
81a322d4 297 return 0;
72f44c8c 298}
502a5395 299
81a322d4 300static int pbm_pci_host_init(PCIDevice *d)
72f44c8c 301{
deb54399
AL
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);
502a5395
PB
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
173a543b 310 pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST);
502a5395 311 d->config[0x0D] = 0x10; // latency_timer
110c50fd 312 d->config[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; // header_type
81a322d4 313 return 0;
72f44c8c 314}
80b3ada7 315
72f44c8c
BS
316static PCIDeviceInfo pbm_pci_host_info = {
317 .qdev.name = "pbm",
318 .qdev.size = sizeof(PCIDevice),
319 .init = pbm_pci_host_init,
320};
321
322static 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);
502a5395 326}
72f44c8c
BS
327
328device_init(pbm_register_devices)