blob: 086908a846e1f9a9333bd4ec2910bde0a821dbf0 [file] [log] [blame]
pbrook502a5392006-05-13 16:11:23 +00001/*
2 * QEMU Ultrasparc APB PCI host
3 *
4 * Copyright (c) 2006 Fabrice Bellard
ths5fafdf22007-09-16 21:08:06 +00005 *
pbrook502a5392006-05-13 16:11:23 +00006 * 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 */
pbrook80b3ada2006-09-24 17:01:44 +000024
blueswir1a94fd952009-01-09 20:53:30 +000025/* XXX This file and most of its contents are somewhat misnamed. The
pbrook80b3ada2006-09-24 17:01:44 +000026 Ultrasparc PCI host is called the PCI Bus Module (PBM). The APB is
27 the secondary PCI bridge. */
28
pbrook87ecb682007-11-17 17:14:51 +000029#include "hw.h"
30#include "pci.h"
blueswir1a94fd952009-01-09 20:53:30 +000031
32/* debug APB */
33//#define DEBUG_APB
34
35#ifdef DEBUG_APB
36#define APB_DPRINTF(fmt, args...) \
37do { printf("APB: " fmt , ##args); } while (0)
38#else
39#define APB_DPRINTF(fmt, args...)
40#endif
41
pbrook502a5392006-05-13 16:11:23 +000042typedef target_phys_addr_t pci_addr_t;
43#include "pci_host.h"
44
45typedef PCIHostState APBState;
46
47static void pci_apb_config_writel (void *opaque, target_phys_addr_t addr,
48 uint32_t val)
49{
50 APBState *s = opaque;
pbrook502a5392006-05-13 16:11:23 +000051
blueswir1a94fd952009-01-09 20:53:30 +000052#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;
pbrook502a5392006-05-13 16:11:23 +000058}
59
60static uint32_t pci_apb_config_readl (void *opaque,
61 target_phys_addr_t addr)
62{
63 APBState *s = opaque;
64 uint32_t val;
pbrook502a5392006-05-13 16:11:23 +000065
blueswir1a94fd952009-01-09 20:53:30 +000066 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);
pbrook502a5392006-05-13 16:11:23 +000072 return val;
73}
74
75static CPUWriteMemoryFunc *pci_apb_config_write[] = {
76 &pci_apb_config_writel,
77 &pci_apb_config_writel,
78 &pci_apb_config_writel,
79};
80
81static CPUReadMemoryFunc *pci_apb_config_read[] = {
82 &pci_apb_config_readl,
83 &pci_apb_config_readl,
84 &pci_apb_config_readl,
85};
86
87static void apb_config_writel (void *opaque, target_phys_addr_t addr,
blueswir1f930d072007-10-06 11:28:21 +000088 uint32_t val)
pbrook502a5392006-05-13 16:11:23 +000089{
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
blueswir1f930d072007-10-06 11:28:21 +000098 // XXX
pbrook502a5392006-05-13 16:11:23 +000099 default:
blueswir1f930d072007-10-06 11:28:21 +0000100 break;
pbrook502a5392006-05-13 16:11:23 +0000101 }
102}
103
104static uint32_t apb_config_readl (void *opaque,
blueswir1f930d072007-10-06 11:28:21 +0000105 target_phys_addr_t addr)
pbrook502a5392006-05-13 16:11:23 +0000106{
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
blueswir1f930d072007-10-06 11:28:21 +0000116 // XXX
pbrook502a5392006-05-13 16:11:23 +0000117 default:
blueswir1f930d072007-10-06 11:28:21 +0000118 val = 0;
119 break;
pbrook502a5392006-05-13 16:11:23 +0000120 }
121 return val;
122}
123
124static CPUWriteMemoryFunc *apb_config_write[] = {
125 &apb_config_writel,
126 &apb_config_writel,
127 &apb_config_writel,
128};
129
130static CPUReadMemoryFunc *apb_config_read[] = {
131 &apb_config_readl,
132 &apb_config_readl,
133 &apb_config_readl,
134};
135
136static CPUWriteMemoryFunc *pci_apb_write[] = {
137 &pci_host_data_writeb,
138 &pci_host_data_writew,
139 &pci_host_data_writel,
140};
141
142static CPUReadMemoryFunc *pci_apb_read[] = {
143 &pci_host_data_readb,
144 &pci_host_data_readw,
145 &pci_host_data_readl,
146};
147
148static 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
154static 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
160static 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
166static 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
174static 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
182static 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
190static CPUWriteMemoryFunc *pci_apb_iowrite[] = {
191 &pci_apb_iowriteb,
192 &pci_apb_iowritew,
193 &pci_apb_iowritel,
194};
195
196static CPUReadMemoryFunc *pci_apb_ioread[] = {
197 &pci_apb_ioreadb,
198 &pci_apb_ioreadw,
199 &pci_apb_ioreadl,
200};
201
pbrook80b3ada2006-09-24 17:01:44 +0000202/* The APB host has an IRQ line for each IRQ line of each slot. */
pbrookd2b59312006-09-24 00:16:34 +0000203static int pci_apb_map_irq(PCIDevice *pci_dev, int irq_num)
pbrook502a5392006-05-13 16:11:23 +0000204{
pbrook80b3ada2006-09-24 17:01:44 +0000205 return ((pci_dev->devfn & 0x18) >> 1) + irq_num;
206}
207
208static 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;
pbrookd2b59312006-09-24 00:16:34 +0000216}
217
pbrookd537cf62007-04-07 18:14:41 +0000218static void pci_apb_set_irq(qemu_irq *pic, int irq_num, int level)
pbrookd2b59312006-09-24 00:16:34 +0000219{
pbrook80b3ada2006-09-24 17:01:44 +0000220 /* PCI IRQ map onto the first 32 INO. */
pbrookd537cf62007-04-07 18:14:41 +0000221 qemu_set_irq(pic[irq_num], level);
pbrook502a5392006-05-13 16:11:23 +0000222}
223
blueswir1fdf41d22007-05-30 18:54:40 +0000224PCIBus *pci_apb_init(target_phys_addr_t special_base,
225 target_phys_addr_t mem_base,
pbrookd537cf62007-04-07 18:14:41 +0000226 qemu_irq *pic)
pbrook502a5392006-05-13 16:11:23 +0000227{
228 APBState *s;
229 PCIDevice *d;
230 int pci_mem_config, pci_mem_data, apb_config, pci_ioport;
pbrook80b3ada2006-09-24 17:01:44 +0000231 PCIBus *secondary;
pbrook502a5392006-05-13 16:11:23 +0000232
233 s = qemu_mallocz(sizeof(APBState));
pbrook80b3ada2006-09-24 17:01:44 +0000234 /* Ultrasparc PBM main bus */
235 s->bus = pci_register_bus(pci_apb_set_irq, pci_pbm_map_irq, pic, 0, 32);
pbrook502a5392006-05-13 16:11:23 +0000236
237 pci_mem_config = cpu_register_io_memory(0, pci_apb_config_read,
238 pci_apb_config_write, s);
239 apb_config = cpu_register_io_memory(0, apb_config_read,
blueswir1f930d072007-10-06 11:28:21 +0000240 apb_config_write, s);
pbrook502a5392006-05-13 16:11:23 +0000241 pci_mem_data = cpu_register_io_memory(0, pci_apb_read,
242 pci_apb_write, s);
243 pci_ioport = cpu_register_io_memory(0, pci_apb_ioread,
244 pci_apb_iowrite, s);
245
246 cpu_register_physical_memory(special_base + 0x2000ULL, 0x40, apb_config);
blueswir177f193d2008-05-12 16:13:33 +0000247 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
pbrook502a5392006-05-13 16:11:23 +0000253
ths5fafdf22007-09-16 21:08:06 +0000254 d = pci_register_device(s->bus, "Advanced PCI Bus", sizeof(PCIDevice),
pbrook80b3ada2006-09-24 17:01:44 +0000255 0, NULL, NULL);
pbrook502a5392006-05-13 16:11:23 +0000256 d->config[0x00] = 0x8e; // vendor_id : Sun
257 d->config[0x01] = 0x10;
258 d->config[0x02] = 0x00; // device_id
259 d->config[0x03] = 0xa0;
260 d->config[0x04] = 0x06; // command = bus master, pci mem
261 d->config[0x05] = 0x00;
262 d->config[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error
263 d->config[0x07] = 0x03; // status = medium devsel
264 d->config[0x08] = 0x00; // revision
265 d->config[0x09] = 0x00; // programming i/f
266 d->config[0x0A] = 0x00; // class_sub = pci host
267 d->config[0x0B] = 0x06; // class_base = PCI_bridge
268 d->config[0x0D] = 0x10; // latency_timer
269 d->config[0x0E] = 0x00; // header_type
pbrook80b3ada2006-09-24 17:01:44 +0000270
271 /* APB secondary busses */
blueswir177f193d2008-05-12 16:13:33 +0000272 secondary = pci_bridge_init(s->bus, 8, 0x108e5000, pci_apb_map_irq,
273 "Advanced PCI Bus secondary bridge 1");
274 pci_bridge_init(s->bus, 9, 0x108e5000, pci_apb_map_irq,
275 "Advanced PCI Bus secondary bridge 2");
blueswir1a94fd952009-01-09 20:53:30 +0000276 return s->bus;
pbrook502a5392006-05-13 16:11:23 +0000277}