]>
Commit | Line | Data |
---|---|---|
69b91039 FB |
1 | /* |
2 | * QEMU PCI bus manager | |
3 | * | |
4 | * Copyright (c) 2004 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 | #include "vl.h" | |
25 | ||
26 | //#define DEBUG_PCI | |
27 | ||
0ac32c83 FB |
28 | #define PCI_VENDOR_ID 0x00 /* 16 bits */ |
29 | #define PCI_DEVICE_ID 0x02 /* 16 bits */ | |
30 | #define PCI_COMMAND 0x04 /* 16 bits */ | |
31 | #define PCI_COMMAND_IO 0x1 /* Enable response in I/O space */ | |
32 | #define PCI_COMMAND_MEMORY 0x2 /* Enable response in Memory space */ | |
33 | #define PCI_CLASS_DEVICE 0x0a /* Device class */ | |
34 | #define PCI_INTERRUPT_LINE 0x3c /* 8 bits */ | |
35 | #define PCI_INTERRUPT_PIN 0x3d /* 8 bits */ | |
36 | #define PCI_MIN_GNT 0x3e /* 8 bits */ | |
37 | #define PCI_MAX_LAT 0x3f /* 8 bits */ | |
38 | ||
39 | /* just used for simpler irq handling. */ | |
40 | #define PCI_DEVICES_MAX 64 | |
41 | #define PCI_IRQ_WORDS ((PCI_DEVICES_MAX + 31) / 32) | |
42 | ||
30468f78 FB |
43 | struct PCIBus { |
44 | int bus_num; | |
45 | int devfn_min; | |
46 | void (*set_irq)(PCIDevice *pci_dev, int irq_num, int level); | |
47 | uint32_t config_reg; /* XXX: suppress */ | |
384d8876 FB |
48 | /* low level pic */ |
49 | SetIRQFunc *low_set_irq; | |
50 | void *irq_opaque; | |
30468f78 FB |
51 | PCIDevice *devices[256]; |
52 | }; | |
69b91039 | 53 | |
69b91039 | 54 | target_phys_addr_t pci_mem_base; |
0ac32c83 FB |
55 | static int pci_irq_index; |
56 | static uint32_t pci_irq_levels[4][PCI_IRQ_WORDS]; | |
30468f78 FB |
57 | static PCIBus *first_bus; |
58 | ||
59 | static PCIBus *pci_register_bus(void) | |
60 | { | |
61 | PCIBus *bus; | |
62 | bus = qemu_mallocz(sizeof(PCIBus)); | |
63 | first_bus = bus; | |
64 | return bus; | |
65 | } | |
69b91039 | 66 | |
30ca2aab FB |
67 | void generic_pci_save(QEMUFile* f, void *opaque) |
68 | { | |
69 | PCIDevice* s=(PCIDevice*)opaque; | |
70 | ||
71 | qemu_put_buffer(f, s->config, 256); | |
72 | } | |
73 | ||
74 | int generic_pci_load(QEMUFile* f, void *opaque, int version_id) | |
75 | { | |
76 | PCIDevice* s=(PCIDevice*)opaque; | |
77 | ||
78 | if (version_id != 1) | |
79 | return -EINVAL; | |
80 | ||
81 | qemu_get_buffer(f, s->config, 256); | |
82 | return 0; | |
83 | } | |
84 | ||
69b91039 | 85 | /* -1 for devfn means auto assign */ |
30468f78 FB |
86 | PCIDevice *pci_register_device(PCIBus *bus, const char *name, |
87 | int instance_size, int devfn, | |
69b91039 FB |
88 | PCIConfigReadFunc *config_read, |
89 | PCIConfigWriteFunc *config_write) | |
90 | { | |
30468f78 | 91 | PCIDevice *pci_dev; |
69b91039 | 92 | |
0ac32c83 FB |
93 | if (pci_irq_index >= PCI_DEVICES_MAX) |
94 | return NULL; | |
95 | ||
69b91039 | 96 | if (devfn < 0) { |
30468f78 FB |
97 | for(devfn = bus->devfn_min ; devfn < 256; devfn += 8) { |
98 | if (!bus->devices[devfn]) | |
69b91039 FB |
99 | goto found; |
100 | } | |
101 | return NULL; | |
102 | found: ; | |
103 | } | |
104 | pci_dev = qemu_mallocz(instance_size); | |
105 | if (!pci_dev) | |
106 | return NULL; | |
30468f78 | 107 | pci_dev->bus = bus; |
69b91039 FB |
108 | pci_dev->devfn = devfn; |
109 | pstrcpy(pci_dev->name, sizeof(pci_dev->name), name); | |
0ac32c83 FB |
110 | |
111 | if (!config_read) | |
112 | config_read = pci_default_read_config; | |
113 | if (!config_write) | |
114 | config_write = pci_default_write_config; | |
69b91039 FB |
115 | pci_dev->config_read = config_read; |
116 | pci_dev->config_write = config_write; | |
0ac32c83 | 117 | pci_dev->irq_index = pci_irq_index++; |
30468f78 | 118 | bus->devices[devfn] = pci_dev; |
69b91039 FB |
119 | return pci_dev; |
120 | } | |
121 | ||
122 | void pci_register_io_region(PCIDevice *pci_dev, int region_num, | |
123 | uint32_t size, int type, | |
124 | PCIMapIORegionFunc *map_func) | |
125 | { | |
126 | PCIIORegion *r; | |
d7ce493a | 127 | uint32_t addr; |
69b91039 | 128 | |
8a8696a3 | 129 | if ((unsigned int)region_num >= PCI_NUM_REGIONS) |
69b91039 FB |
130 | return; |
131 | r = &pci_dev->io_regions[region_num]; | |
132 | r->addr = -1; | |
133 | r->size = size; | |
134 | r->type = type; | |
135 | r->map_func = map_func; | |
d7ce493a PB |
136 | if (region_num == PCI_ROM_SLOT) { |
137 | addr = 0x30; | |
138 | } else { | |
139 | addr = 0x10 + region_num * 4; | |
140 | } | |
141 | *(uint32_t *)(pci_dev->config + addr) = cpu_to_le32(type); | |
69b91039 FB |
142 | } |
143 | ||
0ac32c83 | 144 | static void pci_addr_writel(void* opaque, uint32_t addr, uint32_t val) |
69b91039 | 145 | { |
30468f78 | 146 | PCIBus *s = opaque; |
69b91039 FB |
147 | s->config_reg = val; |
148 | } | |
149 | ||
0ac32c83 | 150 | static uint32_t pci_addr_readl(void* opaque, uint32_t addr) |
69b91039 | 151 | { |
30468f78 | 152 | PCIBus *s = opaque; |
69b91039 FB |
153 | return s->config_reg; |
154 | } | |
155 | ||
0ac32c83 FB |
156 | static void pci_update_mappings(PCIDevice *d) |
157 | { | |
158 | PCIIORegion *r; | |
159 | int cmd, i; | |
8a8696a3 | 160 | uint32_t last_addr, new_addr, config_ofs; |
0ac32c83 FB |
161 | |
162 | cmd = le16_to_cpu(*(uint16_t *)(d->config + PCI_COMMAND)); | |
8a8696a3 | 163 | for(i = 0; i < PCI_NUM_REGIONS; i++) { |
0ac32c83 | 164 | r = &d->io_regions[i]; |
8a8696a3 FB |
165 | if (i == PCI_ROM_SLOT) { |
166 | config_ofs = 0x30; | |
167 | } else { | |
168 | config_ofs = 0x10 + i * 4; | |
169 | } | |
0ac32c83 FB |
170 | if (r->size != 0) { |
171 | if (r->type & PCI_ADDRESS_SPACE_IO) { | |
172 | if (cmd & PCI_COMMAND_IO) { | |
173 | new_addr = le32_to_cpu(*(uint32_t *)(d->config + | |
8a8696a3 | 174 | config_ofs)); |
0ac32c83 FB |
175 | new_addr = new_addr & ~(r->size - 1); |
176 | last_addr = new_addr + r->size - 1; | |
177 | /* NOTE: we have only 64K ioports on PC */ | |
178 | if (last_addr <= new_addr || new_addr == 0 || | |
179 | last_addr >= 0x10000) { | |
180 | new_addr = -1; | |
181 | } | |
182 | } else { | |
183 | new_addr = -1; | |
184 | } | |
185 | } else { | |
186 | if (cmd & PCI_COMMAND_MEMORY) { | |
187 | new_addr = le32_to_cpu(*(uint32_t *)(d->config + | |
8a8696a3 FB |
188 | config_ofs)); |
189 | /* the ROM slot has a specific enable bit */ | |
190 | if (i == PCI_ROM_SLOT && !(new_addr & 1)) | |
191 | goto no_mem_map; | |
0ac32c83 FB |
192 | new_addr = new_addr & ~(r->size - 1); |
193 | last_addr = new_addr + r->size - 1; | |
194 | /* NOTE: we do not support wrapping */ | |
195 | /* XXX: as we cannot support really dynamic | |
196 | mappings, we handle specific values as invalid | |
197 | mappings. */ | |
198 | if (last_addr <= new_addr || new_addr == 0 || | |
199 | last_addr == -1) { | |
200 | new_addr = -1; | |
201 | } | |
202 | } else { | |
8a8696a3 | 203 | no_mem_map: |
0ac32c83 FB |
204 | new_addr = -1; |
205 | } | |
206 | } | |
207 | /* now do the real mapping */ | |
208 | if (new_addr != r->addr) { | |
209 | if (r->addr != -1) { | |
210 | if (r->type & PCI_ADDRESS_SPACE_IO) { | |
211 | int class; | |
212 | /* NOTE: specific hack for IDE in PC case: | |
213 | only one byte must be mapped. */ | |
214 | class = d->config[0x0a] | (d->config[0x0b] << 8); | |
215 | if (class == 0x0101 && r->size == 4) { | |
216 | isa_unassign_ioport(r->addr + 2, 1); | |
217 | } else { | |
218 | isa_unassign_ioport(r->addr, r->size); | |
219 | } | |
220 | } else { | |
221 | cpu_register_physical_memory(r->addr + pci_mem_base, | |
222 | r->size, | |
223 | IO_MEM_UNASSIGNED); | |
224 | } | |
225 | } | |
226 | r->addr = new_addr; | |
227 | if (r->addr != -1) { | |
228 | r->map_func(d, i, r->addr, r->size, r->type); | |
229 | } | |
230 | } | |
231 | } | |
232 | } | |
233 | } | |
234 | ||
235 | uint32_t pci_default_read_config(PCIDevice *d, | |
236 | uint32_t address, int len) | |
69b91039 | 237 | { |
0ac32c83 FB |
238 | uint32_t val; |
239 | switch(len) { | |
240 | case 1: | |
241 | val = d->config[address]; | |
242 | break; | |
243 | case 2: | |
244 | val = le16_to_cpu(*(uint16_t *)(d->config + address)); | |
245 | break; | |
246 | default: | |
247 | case 4: | |
248 | val = le32_to_cpu(*(uint32_t *)(d->config + address)); | |
249 | break; | |
250 | } | |
251 | return val; | |
252 | } | |
253 | ||
254 | void pci_default_write_config(PCIDevice *d, | |
255 | uint32_t address, uint32_t val, int len) | |
256 | { | |
257 | int can_write, i; | |
7bf5be70 | 258 | uint32_t end, addr; |
0ac32c83 | 259 | |
8a8696a3 FB |
260 | if (len == 4 && ((address >= 0x10 && address < 0x10 + 4 * 6) || |
261 | (address >= 0x30 && address < 0x34))) { | |
0ac32c83 FB |
262 | PCIIORegion *r; |
263 | int reg; | |
264 | ||
8a8696a3 FB |
265 | if ( address >= 0x30 ) { |
266 | reg = PCI_ROM_SLOT; | |
267 | }else{ | |
268 | reg = (address - 0x10) >> 2; | |
269 | } | |
0ac32c83 FB |
270 | r = &d->io_regions[reg]; |
271 | if (r->size == 0) | |
272 | goto default_config; | |
273 | /* compute the stored value */ | |
8a8696a3 FB |
274 | if (reg == PCI_ROM_SLOT) { |
275 | /* keep ROM enable bit */ | |
276 | val &= (~(r->size - 1)) | 1; | |
277 | } else { | |
278 | val &= ~(r->size - 1); | |
279 | val |= r->type; | |
280 | } | |
281 | *(uint32_t *)(d->config + address) = cpu_to_le32(val); | |
0ac32c83 | 282 | pci_update_mappings(d); |
69b91039 | 283 | return; |
0ac32c83 FB |
284 | } |
285 | default_config: | |
286 | /* not efficient, but simple */ | |
7bf5be70 | 287 | addr = address; |
0ac32c83 FB |
288 | for(i = 0; i < len; i++) { |
289 | /* default read/write accesses */ | |
1f62d938 | 290 | switch(d->config[0x0e]) { |
0ac32c83 | 291 | case 0x00: |
1f62d938 FB |
292 | case 0x80: |
293 | switch(addr) { | |
294 | case 0x00: | |
295 | case 0x01: | |
296 | case 0x02: | |
297 | case 0x03: | |
298 | case 0x08: | |
299 | case 0x09: | |
300 | case 0x0a: | |
301 | case 0x0b: | |
302 | case 0x0e: | |
303 | case 0x10 ... 0x27: /* base */ | |
304 | case 0x30 ... 0x33: /* rom */ | |
305 | case 0x3d: | |
306 | can_write = 0; | |
307 | break; | |
308 | default: | |
309 | can_write = 1; | |
310 | break; | |
311 | } | |
0ac32c83 FB |
312 | break; |
313 | default: | |
1f62d938 FB |
314 | case 0x01: |
315 | switch(addr) { | |
316 | case 0x00: | |
317 | case 0x01: | |
318 | case 0x02: | |
319 | case 0x03: | |
320 | case 0x08: | |
321 | case 0x09: | |
322 | case 0x0a: | |
323 | case 0x0b: | |
324 | case 0x0e: | |
325 | case 0x38 ... 0x3b: /* rom */ | |
326 | case 0x3d: | |
327 | can_write = 0; | |
328 | break; | |
329 | default: | |
330 | can_write = 1; | |
331 | break; | |
332 | } | |
0ac32c83 FB |
333 | break; |
334 | } | |
335 | if (can_write) { | |
7bf5be70 | 336 | d->config[addr] = val; |
0ac32c83 | 337 | } |
7bf5be70 | 338 | addr++; |
0ac32c83 FB |
339 | val >>= 8; |
340 | } | |
341 | ||
342 | end = address + len; | |
343 | if (end > PCI_COMMAND && address < (PCI_COMMAND + 2)) { | |
344 | /* if the command register is modified, we must modify the mappings */ | |
345 | pci_update_mappings(d); | |
69b91039 FB |
346 | } |
347 | } | |
348 | ||
349 | static void pci_data_write(void *opaque, uint32_t addr, | |
350 | uint32_t val, int len) | |
351 | { | |
30468f78 FB |
352 | PCIBus *s = opaque; |
353 | PCIDevice *pci_dev; | |
354 | int config_addr, bus_num; | |
69b91039 FB |
355 | |
356 | #if defined(DEBUG_PCI) && 0 | |
357 | printf("pci_data_write: addr=%08x val=%08x len=%d\n", | |
358 | s->config_reg, val, len); | |
359 | #endif | |
360 | if (!(s->config_reg & (1 << 31))) { | |
361 | return; | |
362 | } | |
30468f78 FB |
363 | bus_num = (s->config_reg >> 16) & 0xff; |
364 | if (bus_num != 0) | |
69b91039 | 365 | return; |
30468f78 | 366 | pci_dev = s->devices[(s->config_reg >> 8) & 0xff]; |
69b91039 FB |
367 | if (!pci_dev) |
368 | return; | |
369 | config_addr = (s->config_reg & 0xfc) | (addr & 3); | |
69b91039 FB |
370 | #if defined(DEBUG_PCI) |
371 | printf("pci_config_write: %s: addr=%02x val=%08x len=%d\n", | |
372 | pci_dev->name, config_addr, val, len); | |
373 | #endif | |
0ac32c83 | 374 | pci_dev->config_write(pci_dev, config_addr, val, len); |
69b91039 FB |
375 | } |
376 | ||
377 | static uint32_t pci_data_read(void *opaque, uint32_t addr, | |
378 | int len) | |
379 | { | |
30468f78 FB |
380 | PCIBus *s = opaque; |
381 | PCIDevice *pci_dev; | |
382 | int config_addr, bus_num; | |
69b91039 FB |
383 | uint32_t val; |
384 | ||
385 | if (!(s->config_reg & (1 << 31))) | |
386 | goto fail; | |
30468f78 FB |
387 | bus_num = (s->config_reg >> 16) & 0xff; |
388 | if (bus_num != 0) | |
69b91039 | 389 | goto fail; |
30468f78 | 390 | pci_dev = s->devices[(s->config_reg >> 8) & 0xff]; |
69b91039 FB |
391 | if (!pci_dev) { |
392 | fail: | |
63ce9e0a FB |
393 | switch(len) { |
394 | case 1: | |
395 | val = 0xff; | |
396 | break; | |
397 | case 2: | |
398 | val = 0xffff; | |
399 | break; | |
400 | default: | |
401 | case 4: | |
402 | val = 0xffffffff; | |
403 | break; | |
404 | } | |
69b91039 FB |
405 | goto the_end; |
406 | } | |
407 | config_addr = (s->config_reg & 0xfc) | (addr & 3); | |
408 | val = pci_dev->config_read(pci_dev, config_addr, len); | |
409 | #if defined(DEBUG_PCI) | |
410 | printf("pci_config_read: %s: addr=%02x val=%08x len=%d\n", | |
411 | pci_dev->name, config_addr, val, len); | |
412 | #endif | |
413 | the_end: | |
414 | #if defined(DEBUG_PCI) && 0 | |
415 | printf("pci_data_read: addr=%08x val=%08x len=%d\n", | |
416 | s->config_reg, val, len); | |
417 | #endif | |
418 | return val; | |
419 | } | |
420 | ||
421 | static void pci_data_writeb(void* opaque, uint32_t addr, uint32_t val) | |
422 | { | |
423 | pci_data_write(opaque, addr, val, 1); | |
424 | } | |
425 | ||
426 | static void pci_data_writew(void* opaque, uint32_t addr, uint32_t val) | |
427 | { | |
428 | pci_data_write(opaque, addr, val, 2); | |
429 | } | |
430 | ||
431 | static void pci_data_writel(void* opaque, uint32_t addr, uint32_t val) | |
432 | { | |
433 | pci_data_write(opaque, addr, val, 4); | |
434 | } | |
435 | ||
436 | static uint32_t pci_data_readb(void* opaque, uint32_t addr) | |
437 | { | |
438 | return pci_data_read(opaque, addr, 1); | |
439 | } | |
440 | ||
441 | static uint32_t pci_data_readw(void* opaque, uint32_t addr) | |
442 | { | |
443 | return pci_data_read(opaque, addr, 2); | |
444 | } | |
445 | ||
446 | static uint32_t pci_data_readl(void* opaque, uint32_t addr) | |
447 | { | |
448 | return pci_data_read(opaque, addr, 4); | |
449 | } | |
450 | ||
451 | /* i440FX PCI bridge */ | |
452 | ||
30468f78 FB |
453 | static void piix3_set_irq(PCIDevice *pci_dev, int irq_num, int level); |
454 | ||
455 | PCIBus *i440fx_init(void) | |
69b91039 | 456 | { |
30468f78 | 457 | PCIBus *s; |
69b91039 FB |
458 | PCIDevice *d; |
459 | ||
30468f78 FB |
460 | s = pci_register_bus(); |
461 | s->set_irq = piix3_set_irq; | |
462 | ||
0ac32c83 FB |
463 | register_ioport_write(0xcf8, 4, 4, pci_addr_writel, s); |
464 | register_ioport_read(0xcf8, 4, 4, pci_addr_readl, s); | |
69b91039 FB |
465 | |
466 | register_ioport_write(0xcfc, 4, 1, pci_data_writeb, s); | |
467 | register_ioport_write(0xcfc, 4, 2, pci_data_writew, s); | |
468 | register_ioport_write(0xcfc, 4, 4, pci_data_writel, s); | |
469 | register_ioport_read(0xcfc, 4, 1, pci_data_readb, s); | |
470 | register_ioport_read(0xcfc, 4, 2, pci_data_readw, s); | |
471 | register_ioport_read(0xcfc, 4, 4, pci_data_readl, s); | |
472 | ||
30468f78 | 473 | d = pci_register_device(s, "i440FX", sizeof(PCIDevice), 0, |
0ac32c83 | 474 | NULL, NULL); |
69b91039 FB |
475 | |
476 | d->config[0x00] = 0x86; // vendor_id | |
477 | d->config[0x01] = 0x80; | |
478 | d->config[0x02] = 0x37; // device_id | |
479 | d->config[0x03] = 0x12; | |
480 | d->config[0x08] = 0x02; // revision | |
358c6407 | 481 | d->config[0x0a] = 0x00; // class_sub = host2pci |
69b91039 | 482 | d->config[0x0b] = 0x06; // class_base = PCI_bridge |
358c6407 | 483 | d->config[0x0e] = 0x00; // header_type |
30468f78 | 484 | return s; |
69b91039 FB |
485 | } |
486 | ||
0ac32c83 FB |
487 | /* PIIX3 PCI to ISA bridge */ |
488 | ||
489 | typedef struct PIIX3State { | |
490 | PCIDevice dev; | |
491 | } PIIX3State; | |
492 | ||
493 | PIIX3State *piix3_state; | |
494 | ||
30468f78 FB |
495 | /* return the global irq number corresponding to a given device irq |
496 | pin. We could also use the bus number to have a more precise | |
497 | mapping. */ | |
498 | static inline int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num) | |
499 | { | |
500 | int slot_addend; | |
39d22439 | 501 | slot_addend = (pci_dev->devfn >> 3) - 1; |
30468f78 FB |
502 | return (irq_num + slot_addend) & 3; |
503 | } | |
504 | ||
72cc6cfe FB |
505 | static inline int get_pci_irq_level(int irq_num) |
506 | { | |
507 | int pic_level; | |
508 | #if (PCI_IRQ_WORDS == 2) | |
509 | pic_level = ((pci_irq_levels[irq_num][0] | | |
510 | pci_irq_levels[irq_num][1]) != 0); | |
511 | #else | |
512 | { | |
513 | int i; | |
514 | pic_level = 0; | |
515 | for(i = 0; i < PCI_IRQ_WORDS; i++) { | |
516 | if (pci_irq_levels[irq_num][i]) { | |
517 | pic_level = 1; | |
518 | break; | |
519 | } | |
520 | } | |
521 | } | |
522 | #endif | |
523 | return pic_level; | |
524 | } | |
525 | ||
30468f78 FB |
526 | static void piix3_set_irq(PCIDevice *pci_dev, int irq_num, int level) |
527 | { | |
528 | int irq_index, shift, pic_irq, pic_level; | |
529 | uint32_t *p; | |
530 | ||
531 | irq_num = pci_slot_get_pirq(pci_dev, irq_num); | |
532 | irq_index = pci_dev->irq_index; | |
533 | p = &pci_irq_levels[irq_num][irq_index >> 5]; | |
534 | shift = (irq_index & 0x1f); | |
535 | *p = (*p & ~(1 << shift)) | (level << shift); | |
536 | ||
537 | /* now we change the pic irq level according to the piix irq mappings */ | |
72cc6cfe | 538 | /* XXX: optimize */ |
30468f78 FB |
539 | pic_irq = piix3_state->dev.config[0x60 + irq_num]; |
540 | if (pic_irq < 16) { | |
541 | /* the pic level is the logical OR of all the PCI irqs mapped | |
542 | to it */ | |
543 | pic_level = 0; | |
72cc6cfe FB |
544 | if (pic_irq == piix3_state->dev.config[0x60]) |
545 | pic_level |= get_pci_irq_level(0); | |
546 | if (pic_irq == piix3_state->dev.config[0x61]) | |
547 | pic_level |= get_pci_irq_level(1); | |
548 | if (pic_irq == piix3_state->dev.config[0x62]) | |
549 | pic_level |= get_pci_irq_level(2); | |
550 | if (pic_irq == piix3_state->dev.config[0x63]) | |
551 | pic_level |= get_pci_irq_level(3); | |
30468f78 FB |
552 | pic_set_irq(pic_irq, pic_level); |
553 | } | |
554 | } | |
555 | ||
0ac32c83 FB |
556 | static void piix3_reset(PIIX3State *d) |
557 | { | |
558 | uint8_t *pci_conf = d->dev.config; | |
559 | ||
560 | pci_conf[0x04] = 0x07; // master, memory and I/O | |
561 | pci_conf[0x05] = 0x00; | |
562 | pci_conf[0x06] = 0x00; | |
563 | pci_conf[0x07] = 0x02; // PCI_status_devsel_medium | |
564 | pci_conf[0x4c] = 0x4d; | |
565 | pci_conf[0x4e] = 0x03; | |
566 | pci_conf[0x4f] = 0x00; | |
567 | pci_conf[0x60] = 0x80; | |
568 | pci_conf[0x69] = 0x02; | |
569 | pci_conf[0x70] = 0x80; | |
570 | pci_conf[0x76] = 0x0c; | |
571 | pci_conf[0x77] = 0x0c; | |
572 | pci_conf[0x78] = 0x02; | |
573 | pci_conf[0x79] = 0x00; | |
574 | pci_conf[0x80] = 0x00; | |
575 | pci_conf[0x82] = 0x00; | |
576 | pci_conf[0xa0] = 0x08; | |
577 | pci_conf[0xa0] = 0x08; | |
578 | pci_conf[0xa2] = 0x00; | |
579 | pci_conf[0xa3] = 0x00; | |
580 | pci_conf[0xa4] = 0x00; | |
581 | pci_conf[0xa5] = 0x00; | |
582 | pci_conf[0xa6] = 0x00; | |
583 | pci_conf[0xa7] = 0x00; | |
584 | pci_conf[0xa8] = 0x0f; | |
585 | pci_conf[0xaa] = 0x00; | |
586 | pci_conf[0xab] = 0x00; | |
587 | pci_conf[0xac] = 0x00; | |
588 | pci_conf[0xae] = 0x00; | |
589 | } | |
590 | ||
30468f78 | 591 | void piix3_init(PCIBus *bus) |
0ac32c83 FB |
592 | { |
593 | PIIX3State *d; | |
594 | uint8_t *pci_conf; | |
595 | ||
30468f78 FB |
596 | d = (PIIX3State *)pci_register_device(bus, "PIIX3", sizeof(PIIX3State), |
597 | -1, NULL, NULL); | |
30ca2aab FB |
598 | register_savevm("PIIX3", 0, 1, generic_pci_save, generic_pci_load, d); |
599 | ||
0ac32c83 FB |
600 | piix3_state = d; |
601 | pci_conf = d->dev.config; | |
602 | ||
603 | pci_conf[0x00] = 0x86; // Intel | |
604 | pci_conf[0x01] = 0x80; | |
605 | pci_conf[0x02] = 0x00; // 82371SB PIIX3 PCI-to-ISA bridge (Step A1) | |
606 | pci_conf[0x03] = 0x70; | |
607 | pci_conf[0x0a] = 0x01; // class_sub = PCI_ISA | |
608 | pci_conf[0x0b] = 0x06; // class_base = PCI_bridge | |
609 | pci_conf[0x0e] = 0x80; // header_type = PCI_multifunction, generic | |
610 | ||
611 | piix3_reset(d); | |
612 | } | |
613 | ||
77d4bc34 FB |
614 | /* PREP pci init */ |
615 | ||
30468f78 | 616 | static inline void set_config(PCIBus *s, target_phys_addr_t addr) |
77d4bc34 FB |
617 | { |
618 | int devfn, i; | |
619 | ||
620 | for(i = 0; i < 11; i++) { | |
621 | if ((addr & (1 << (11 + i))) != 0) | |
622 | break; | |
623 | } | |
624 | devfn = ((addr >> 8) & 7) | (i << 3); | |
625 | s->config_reg = 0x80000000 | (addr & 0xfc) | (devfn << 8); | |
626 | } | |
627 | ||
8a8696a3 | 628 | static void PPC_PCIIO_writeb (void *opaque, target_phys_addr_t addr, uint32_t val) |
77d4bc34 | 629 | { |
30468f78 | 630 | PCIBus *s = opaque; |
77d4bc34 FB |
631 | set_config(s, addr); |
632 | pci_data_write(s, addr, val, 1); | |
633 | } | |
634 | ||
8a8696a3 | 635 | static void PPC_PCIIO_writew (void *opaque, target_phys_addr_t addr, uint32_t val) |
77d4bc34 | 636 | { |
30468f78 | 637 | PCIBus *s = opaque; |
77d4bc34 FB |
638 | set_config(s, addr); |
639 | #ifdef TARGET_WORDS_BIGENDIAN | |
640 | val = bswap16(val); | |
641 | #endif | |
642 | pci_data_write(s, addr, val, 2); | |
643 | } | |
644 | ||
8a8696a3 | 645 | static void PPC_PCIIO_writel (void *opaque, target_phys_addr_t addr, uint32_t val) |
77d4bc34 | 646 | { |
30468f78 | 647 | PCIBus *s = opaque; |
77d4bc34 FB |
648 | set_config(s, addr); |
649 | #ifdef TARGET_WORDS_BIGENDIAN | |
650 | val = bswap32(val); | |
651 | #endif | |
652 | pci_data_write(s, addr, val, 4); | |
653 | } | |
654 | ||
8a8696a3 | 655 | static uint32_t PPC_PCIIO_readb (void *opaque, target_phys_addr_t addr) |
77d4bc34 | 656 | { |
30468f78 | 657 | PCIBus *s = opaque; |
77d4bc34 FB |
658 | uint32_t val; |
659 | set_config(s, addr); | |
660 | val = pci_data_read(s, addr, 1); | |
661 | return val; | |
662 | } | |
663 | ||
8a8696a3 | 664 | static uint32_t PPC_PCIIO_readw (void *opaque, target_phys_addr_t addr) |
77d4bc34 | 665 | { |
30468f78 | 666 | PCIBus *s = opaque; |
77d4bc34 FB |
667 | uint32_t val; |
668 | set_config(s, addr); | |
669 | val = pci_data_read(s, addr, 2); | |
670 | #ifdef TARGET_WORDS_BIGENDIAN | |
671 | val = bswap16(val); | |
672 | #endif | |
673 | return val; | |
674 | } | |
675 | ||
8a8696a3 | 676 | static uint32_t PPC_PCIIO_readl (void *opaque, target_phys_addr_t addr) |
77d4bc34 | 677 | { |
30468f78 | 678 | PCIBus *s = opaque; |
77d4bc34 FB |
679 | uint32_t val; |
680 | set_config(s, addr); | |
681 | val = pci_data_read(s, addr, 4); | |
682 | #ifdef TARGET_WORDS_BIGENDIAN | |
683 | val = bswap32(val); | |
684 | #endif | |
685 | return val; | |
686 | } | |
687 | ||
688 | static CPUWriteMemoryFunc *PPC_PCIIO_write[] = { | |
689 | &PPC_PCIIO_writeb, | |
690 | &PPC_PCIIO_writew, | |
691 | &PPC_PCIIO_writel, | |
692 | }; | |
693 | ||
694 | static CPUReadMemoryFunc *PPC_PCIIO_read[] = { | |
695 | &PPC_PCIIO_readb, | |
696 | &PPC_PCIIO_readw, | |
697 | &PPC_PCIIO_readl, | |
698 | }; | |
699 | ||
30468f78 FB |
700 | static void prep_set_irq(PCIDevice *d, int irq_num, int level) |
701 | { | |
702 | /* XXX: we do not simulate the hardware - we rely on the BIOS to | |
703 | set correctly for irq line field */ | |
704 | pic_set_irq(d->config[PCI_INTERRUPT_LINE], level); | |
705 | } | |
706 | ||
707 | PCIBus *pci_prep_init(void) | |
77d4bc34 | 708 | { |
30468f78 | 709 | PCIBus *s; |
77d4bc34 FB |
710 | PCIDevice *d; |
711 | int PPC_io_memory; | |
712 | ||
30468f78 FB |
713 | s = pci_register_bus(); |
714 | s->set_irq = prep_set_irq; | |
715 | ||
da9b266b FB |
716 | register_ioport_write(0xcf8, 4, 4, pci_addr_writel, s); |
717 | register_ioport_read(0xcf8, 4, 4, pci_addr_readl, s); | |
718 | ||
719 | register_ioport_write(0xcfc, 4, 1, pci_data_writeb, s); | |
720 | register_ioport_write(0xcfc, 4, 2, pci_data_writew, s); | |
721 | register_ioport_write(0xcfc, 4, 4, pci_data_writel, s); | |
722 | register_ioport_read(0xcfc, 4, 1, pci_data_readb, s); | |
723 | register_ioport_read(0xcfc, 4, 2, pci_data_readw, s); | |
724 | register_ioport_read(0xcfc, 4, 4, pci_data_readl, s); | |
725 | ||
8a8696a3 FB |
726 | PPC_io_memory = cpu_register_io_memory(0, PPC_PCIIO_read, |
727 | PPC_PCIIO_write, s); | |
77d4bc34 FB |
728 | cpu_register_physical_memory(0x80800000, 0x00400000, PPC_io_memory); |
729 | ||
384d8876 FB |
730 | /* PCI host bridge */ |
731 | d = pci_register_device(s, "PREP Host Bridge - Motorola Raven", | |
732 | sizeof(PCIDevice), 0, NULL, NULL); | |
733 | d->config[0x00] = 0x57; // vendor_id : Motorola | |
77d4bc34 | 734 | d->config[0x01] = 0x10; |
384d8876 FB |
735 | d->config[0x02] = 0x01; // device_id : Raven |
736 | d->config[0x03] = 0x48; | |
737 | d->config[0x08] = 0x00; // revision | |
738 | d->config[0x0A] = 0x00; // class_sub = pci host | |
739 | d->config[0x0B] = 0x06; // class_base = PCI_bridge | |
740 | d->config[0x0C] = 0x08; // cache_line_size | |
741 | d->config[0x0D] = 0x10; // latency_timer | |
742 | d->config[0x0E] = 0x00; // header_type | |
743 | d->config[0x34] = 0x00; // capabilities_pointer | |
744 | ||
30468f78 | 745 | return s; |
77d4bc34 FB |
746 | } |
747 | ||
748 | ||
f2aa58c6 FB |
749 | /* Grackle PCI host */ |
750 | static void pci_grackle_config_writel (void *opaque, target_phys_addr_t addr, | |
751 | uint32_t val) | |
77d4bc34 | 752 | { |
30468f78 | 753 | PCIBus *s = opaque; |
77d4bc34 FB |
754 | #ifdef TARGET_WORDS_BIGENDIAN |
755 | val = bswap32(val); | |
756 | #endif | |
757 | s->config_reg = val; | |
758 | } | |
759 | ||
f2aa58c6 | 760 | static uint32_t pci_grackle_config_readl (void *opaque, target_phys_addr_t addr) |
77d4bc34 | 761 | { |
30468f78 | 762 | PCIBus *s = opaque; |
77d4bc34 FB |
763 | uint32_t val; |
764 | ||
765 | val = s->config_reg; | |
766 | #ifdef TARGET_WORDS_BIGENDIAN | |
767 | val = bswap32(val); | |
768 | #endif | |
769 | return val; | |
770 | } | |
771 | ||
f2aa58c6 FB |
772 | static CPUWriteMemoryFunc *pci_grackle_config_write[] = { |
773 | &pci_grackle_config_writel, | |
774 | &pci_grackle_config_writel, | |
775 | &pci_grackle_config_writel, | |
77d4bc34 FB |
776 | }; |
777 | ||
f2aa58c6 FB |
778 | static CPUReadMemoryFunc *pci_grackle_config_read[] = { |
779 | &pci_grackle_config_readl, | |
780 | &pci_grackle_config_readl, | |
781 | &pci_grackle_config_readl, | |
77d4bc34 FB |
782 | }; |
783 | ||
f2aa58c6 FB |
784 | static void pci_grackle_writeb (void *opaque, target_phys_addr_t addr, |
785 | uint32_t val) | |
77d4bc34 | 786 | { |
30468f78 | 787 | PCIBus *s = opaque; |
77d4bc34 FB |
788 | pci_data_write(s, addr, val, 1); |
789 | } | |
790 | ||
f2aa58c6 FB |
791 | static void pci_grackle_writew (void *opaque, target_phys_addr_t addr, |
792 | uint32_t val) | |
77d4bc34 | 793 | { |
30468f78 | 794 | PCIBus *s = opaque; |
77d4bc34 FB |
795 | #ifdef TARGET_WORDS_BIGENDIAN |
796 | val = bswap16(val); | |
797 | #endif | |
798 | pci_data_write(s, addr, val, 2); | |
799 | } | |
800 | ||
f2aa58c6 FB |
801 | static void pci_grackle_writel (void *opaque, target_phys_addr_t addr, |
802 | uint32_t val) | |
77d4bc34 | 803 | { |
30468f78 | 804 | PCIBus *s = opaque; |
77d4bc34 FB |
805 | #ifdef TARGET_WORDS_BIGENDIAN |
806 | val = bswap32(val); | |
807 | #endif | |
808 | pci_data_write(s, addr, val, 4); | |
809 | } | |
810 | ||
f2aa58c6 | 811 | static uint32_t pci_grackle_readb (void *opaque, target_phys_addr_t addr) |
77d4bc34 | 812 | { |
30468f78 | 813 | PCIBus *s = opaque; |
77d4bc34 FB |
814 | uint32_t val; |
815 | val = pci_data_read(s, addr, 1); | |
816 | return val; | |
817 | } | |
818 | ||
f2aa58c6 | 819 | static uint32_t pci_grackle_readw (void *opaque, target_phys_addr_t addr) |
77d4bc34 | 820 | { |
30468f78 | 821 | PCIBus *s = opaque; |
77d4bc34 FB |
822 | uint32_t val; |
823 | val = pci_data_read(s, addr, 2); | |
824 | #ifdef TARGET_WORDS_BIGENDIAN | |
825 | val = bswap16(val); | |
826 | #endif | |
827 | return val; | |
828 | } | |
829 | ||
f2aa58c6 FB |
830 | static uint32_t pci_grackle_readl (void *opaque, target_phys_addr_t addr) |
831 | { | |
30468f78 | 832 | PCIBus *s = opaque; |
f2aa58c6 FB |
833 | uint32_t val; |
834 | ||
835 | val = pci_data_read(s, addr, 4); | |
836 | #ifdef TARGET_WORDS_BIGENDIAN | |
837 | val = bswap32(val); | |
838 | #endif | |
839 | return val; | |
840 | } | |
841 | ||
842 | static CPUWriteMemoryFunc *pci_grackle_write[] = { | |
843 | &pci_grackle_writeb, | |
844 | &pci_grackle_writew, | |
845 | &pci_grackle_writel, | |
846 | }; | |
847 | ||
848 | static CPUReadMemoryFunc *pci_grackle_read[] = { | |
849 | &pci_grackle_readb, | |
850 | &pci_grackle_readw, | |
851 | &pci_grackle_readl, | |
852 | }; | |
384d8876 FB |
853 | |
854 | void pci_set_pic(PCIBus *bus, SetIRQFunc *set_irq, void *irq_opaque) | |
855 | { | |
856 | bus->low_set_irq = set_irq; | |
857 | bus->irq_opaque = irq_opaque; | |
858 | } | |
859 | ||
860 | /* XXX: we do not simulate the hardware - we rely on the BIOS to | |
861 | set correctly for irq line field */ | |
862 | static void pci_set_irq_simple(PCIDevice *d, int irq_num, int level) | |
863 | { | |
864 | PCIBus *s = d->bus; | |
865 | s->low_set_irq(s->irq_opaque, d->config[PCI_INTERRUPT_LINE], level); | |
866 | } | |
867 | ||
868 | PCIBus *pci_grackle_init(uint32_t base) | |
869 | { | |
870 | PCIBus *s; | |
871 | PCIDevice *d; | |
872 | int pci_mem_config, pci_mem_data; | |
873 | ||
874 | s = pci_register_bus(); | |
875 | s->set_irq = pci_set_irq_simple; | |
876 | ||
877 | pci_mem_config = cpu_register_io_memory(0, pci_grackle_config_read, | |
878 | pci_grackle_config_write, s); | |
879 | pci_mem_data = cpu_register_io_memory(0, pci_grackle_read, | |
880 | pci_grackle_write, s); | |
881 | cpu_register_physical_memory(base, 0x1000, pci_mem_config); | |
882 | cpu_register_physical_memory(base + 0x00200000, 0x1000, pci_mem_data); | |
883 | d = pci_register_device(s, "Grackle host bridge", sizeof(PCIDevice), | |
884 | 0, NULL, NULL); | |
885 | d->config[0x00] = 0x57; // vendor_id | |
886 | d->config[0x01] = 0x10; | |
887 | d->config[0x02] = 0x02; // device_id | |
888 | d->config[0x03] = 0x00; | |
889 | d->config[0x08] = 0x00; // revision | |
890 | d->config[0x09] = 0x01; | |
891 | d->config[0x0a] = 0x00; // class_sub = host | |
892 | d->config[0x0b] = 0x06; // class_base = PCI_bridge | |
893 | d->config[0x0e] = 0x00; // header_type | |
894 | ||
895 | d->config[0x18] = 0x00; // primary_bus | |
896 | d->config[0x19] = 0x01; // secondary_bus | |
897 | d->config[0x1a] = 0x00; // subordinate_bus | |
898 | d->config[0x1c] = 0x00; | |
899 | d->config[0x1d] = 0x00; | |
900 | ||
901 | d->config[0x20] = 0x00; // memory_base | |
902 | d->config[0x21] = 0x00; | |
903 | d->config[0x22] = 0x01; // memory_limit | |
904 | d->config[0x23] = 0x00; | |
905 | ||
906 | d->config[0x24] = 0x00; // prefetchable_memory_base | |
907 | d->config[0x25] = 0x00; | |
908 | d->config[0x26] = 0x00; // prefetchable_memory_limit | |
909 | d->config[0x27] = 0x00; | |
910 | ||
911 | #if 0 | |
912 | /* PCI2PCI bridge same values as PearPC - check this */ | |
913 | d->config[0x00] = 0x11; // vendor_id | |
914 | d->config[0x01] = 0x10; | |
915 | d->config[0x02] = 0x26; // device_id | |
916 | d->config[0x03] = 0x00; | |
917 | d->config[0x08] = 0x02; // revision | |
918 | d->config[0x0a] = 0x04; // class_sub = pci2pci | |
919 | d->config[0x0b] = 0x06; // class_base = PCI_bridge | |
920 | d->config[0x0e] = 0x01; // header_type | |
921 | ||
922 | d->config[0x18] = 0x0; // primary_bus | |
923 | d->config[0x19] = 0x1; // secondary_bus | |
924 | d->config[0x1a] = 0x1; // subordinate_bus | |
925 | d->config[0x1c] = 0x10; // io_base | |
926 | d->config[0x1d] = 0x20; // io_limit | |
927 | ||
928 | d->config[0x20] = 0x80; // memory_base | |
929 | d->config[0x21] = 0x80; | |
930 | d->config[0x22] = 0x90; // memory_limit | |
931 | d->config[0x23] = 0x80; | |
932 | ||
933 | d->config[0x24] = 0x00; // prefetchable_memory_base | |
934 | d->config[0x25] = 0x84; | |
935 | d->config[0x26] = 0x00; // prefetchable_memory_limit | |
936 | d->config[0x27] = 0x85; | |
30468f78 | 937 | #endif |
384d8876 FB |
938 | return s; |
939 | } | |
f2aa58c6 FB |
940 | |
941 | /* Uninorth PCI host (for all Mac99 and newer machines */ | |
942 | static void pci_unin_main_config_writel (void *opaque, target_phys_addr_t addr, | |
943 | uint32_t val) | |
944 | { | |
30468f78 | 945 | PCIBus *s = opaque; |
f2aa58c6 FB |
946 | int i; |
947 | ||
948 | #ifdef TARGET_WORDS_BIGENDIAN | |
949 | val = bswap32(val); | |
950 | #endif | |
951 | ||
952 | for (i = 11; i < 32; i++) { | |
953 | if ((val & (1 << i)) != 0) | |
954 | break; | |
955 | } | |
956 | #if 0 | |
957 | s->config_reg = 0x80000000 | (1 << 16) | (val & 0x7FC) | (i << 11); | |
958 | #else | |
959 | s->config_reg = 0x80000000 | (0 << 16) | (val & 0x7FC) | (i << 11); | |
960 | #endif | |
961 | } | |
962 | ||
963 | static uint32_t pci_unin_main_config_readl (void *opaque, | |
964 | target_phys_addr_t addr) | |
965 | { | |
30468f78 | 966 | PCIBus *s = opaque; |
f2aa58c6 FB |
967 | uint32_t val; |
968 | int devfn; | |
969 | ||
970 | devfn = (s->config_reg >> 8) & 0xFF; | |
971 | val = (1 << (devfn >> 3)) | ((devfn & 0x07) << 8) | (s->config_reg & 0xFC); | |
972 | #ifdef TARGET_WORDS_BIGENDIAN | |
973 | val = bswap32(val); | |
974 | #endif | |
975 | ||
976 | return val; | |
977 | } | |
978 | ||
979 | static CPUWriteMemoryFunc *pci_unin_main_config_write[] = { | |
980 | &pci_unin_main_config_writel, | |
981 | &pci_unin_main_config_writel, | |
982 | &pci_unin_main_config_writel, | |
983 | }; | |
984 | ||
985 | static CPUReadMemoryFunc *pci_unin_main_config_read[] = { | |
986 | &pci_unin_main_config_readl, | |
987 | &pci_unin_main_config_readl, | |
988 | &pci_unin_main_config_readl, | |
989 | }; | |
990 | ||
991 | static void pci_unin_main_writeb (void *opaque, target_phys_addr_t addr, | |
992 | uint32_t val) | |
993 | { | |
30468f78 | 994 | PCIBus *s = opaque; |
f2aa58c6 FB |
995 | pci_data_write(s, addr & 7, val, 1); |
996 | } | |
997 | ||
998 | static void pci_unin_main_writew (void *opaque, target_phys_addr_t addr, | |
999 | uint32_t val) | |
1000 | { | |
30468f78 | 1001 | PCIBus *s = opaque; |
f2aa58c6 FB |
1002 | #ifdef TARGET_WORDS_BIGENDIAN |
1003 | val = bswap16(val); | |
1004 | #endif | |
1005 | pci_data_write(s, addr & 7, val, 2); | |
1006 | } | |
1007 | ||
1008 | static void pci_unin_main_writel (void *opaque, target_phys_addr_t addr, | |
1009 | uint32_t val) | |
1010 | { | |
30468f78 | 1011 | PCIBus *s = opaque; |
f2aa58c6 FB |
1012 | #ifdef TARGET_WORDS_BIGENDIAN |
1013 | val = bswap32(val); | |
1014 | #endif | |
1015 | pci_data_write(s, addr & 7, val, 4); | |
1016 | } | |
1017 | ||
1018 | static uint32_t pci_unin_main_readb (void *opaque, target_phys_addr_t addr) | |
1019 | { | |
30468f78 | 1020 | PCIBus *s = opaque; |
f2aa58c6 FB |
1021 | uint32_t val; |
1022 | ||
1023 | val = pci_data_read(s, addr & 7, 1); | |
1024 | ||
1025 | return val; | |
1026 | } | |
1027 | ||
1028 | static uint32_t pci_unin_main_readw (void *opaque, target_phys_addr_t addr) | |
1029 | { | |
30468f78 | 1030 | PCIBus *s = opaque; |
f2aa58c6 FB |
1031 | uint32_t val; |
1032 | ||
1033 | val = pci_data_read(s, addr & 7, 2); | |
1034 | #ifdef TARGET_WORDS_BIGENDIAN | |
1035 | val = bswap16(val); | |
1036 | #endif | |
1037 | ||
1038 | return val; | |
1039 | } | |
1040 | ||
1041 | static uint32_t pci_unin_main_readl (void *opaque, target_phys_addr_t addr) | |
77d4bc34 | 1042 | { |
30468f78 | 1043 | PCIBus *s = opaque; |
77d4bc34 FB |
1044 | uint32_t val; |
1045 | ||
1046 | val = pci_data_read(s, addr, 4); | |
1047 | #ifdef TARGET_WORDS_BIGENDIAN | |
1048 | val = bswap32(val); | |
1049 | #endif | |
f2aa58c6 FB |
1050 | |
1051 | return val; | |
1052 | } | |
1053 | ||
1054 | static CPUWriteMemoryFunc *pci_unin_main_write[] = { | |
1055 | &pci_unin_main_writeb, | |
1056 | &pci_unin_main_writew, | |
1057 | &pci_unin_main_writel, | |
1058 | }; | |
1059 | ||
1060 | static CPUReadMemoryFunc *pci_unin_main_read[] = { | |
1061 | &pci_unin_main_readb, | |
1062 | &pci_unin_main_readw, | |
1063 | &pci_unin_main_readl, | |
1064 | }; | |
1065 | ||
30468f78 FB |
1066 | #if 0 |
1067 | ||
f2aa58c6 FB |
1068 | static void pci_unin_config_writel (void *opaque, target_phys_addr_t addr, |
1069 | uint32_t val) | |
1070 | { | |
30468f78 | 1071 | PCIBus *s = opaque; |
f2aa58c6 FB |
1072 | |
1073 | #ifdef TARGET_WORDS_BIGENDIAN | |
1074 | val = bswap32(val); | |
1075 | #endif | |
1076 | s->config_reg = 0x80000000 | (val & ~0x00000001); | |
1077 | } | |
1078 | ||
1079 | static uint32_t pci_unin_config_readl (void *opaque, | |
1080 | target_phys_addr_t addr) | |
1081 | { | |
30468f78 | 1082 | PCIBus *s = opaque; |
f2aa58c6 FB |
1083 | uint32_t val; |
1084 | ||
1085 | val = (s->config_reg | 0x00000001) & ~0x80000000; | |
1086 | #ifdef TARGET_WORDS_BIGENDIAN | |
1087 | val = bswap32(val); | |
1088 | #endif | |
1089 | ||
1090 | return val; | |
1091 | } | |
1092 | ||
1093 | static CPUWriteMemoryFunc *pci_unin_config_write[] = { | |
1094 | &pci_unin_config_writel, | |
1095 | &pci_unin_config_writel, | |
1096 | &pci_unin_config_writel, | |
1097 | }; | |
1098 | ||
1099 | static CPUReadMemoryFunc *pci_unin_config_read[] = { | |
1100 | &pci_unin_config_readl, | |
1101 | &pci_unin_config_readl, | |
1102 | &pci_unin_config_readl, | |
1103 | }; | |
1104 | ||
1105 | static void pci_unin_writeb (void *opaque, target_phys_addr_t addr, | |
1106 | uint32_t val) | |
1107 | { | |
30468f78 | 1108 | PCIBus *s = opaque; |
f2aa58c6 FB |
1109 | pci_data_write(s, addr & 3, val, 1); |
1110 | } | |
1111 | ||
1112 | static void pci_unin_writew (void *opaque, target_phys_addr_t addr, | |
1113 | uint32_t val) | |
1114 | { | |
30468f78 | 1115 | PCIBus *s = opaque; |
f2aa58c6 FB |
1116 | #ifdef TARGET_WORDS_BIGENDIAN |
1117 | val = bswap16(val); | |
1118 | #endif | |
1119 | pci_data_write(s, addr & 3, val, 2); | |
1120 | } | |
1121 | ||
1122 | static void pci_unin_writel (void *opaque, target_phys_addr_t addr, | |
1123 | uint32_t val) | |
1124 | { | |
30468f78 | 1125 | PCIBus *s = opaque; |
f2aa58c6 FB |
1126 | #ifdef TARGET_WORDS_BIGENDIAN |
1127 | val = bswap32(val); | |
1128 | #endif | |
1129 | pci_data_write(s, addr & 3, val, 4); | |
1130 | } | |
1131 | ||
1132 | static uint32_t pci_unin_readb (void *opaque, target_phys_addr_t addr) | |
1133 | { | |
30468f78 | 1134 | PCIBus *s = opaque; |
f2aa58c6 FB |
1135 | uint32_t val; |
1136 | ||
1137 | val = pci_data_read(s, addr & 3, 1); | |
1138 | ||
1139 | return val; | |
1140 | } | |
1141 | ||
1142 | static uint32_t pci_unin_readw (void *opaque, target_phys_addr_t addr) | |
1143 | { | |
30468f78 | 1144 | PCIBus *s = opaque; |
f2aa58c6 FB |
1145 | uint32_t val; |
1146 | ||
1147 | val = pci_data_read(s, addr & 3, 2); | |
1148 | #ifdef TARGET_WORDS_BIGENDIAN | |
1149 | val = bswap16(val); | |
1150 | #endif | |
1151 | ||
1152 | return val; | |
1153 | } | |
1154 | ||
1155 | static uint32_t pci_unin_readl (void *opaque, target_phys_addr_t addr) | |
1156 | { | |
30468f78 | 1157 | PCIBus *s = opaque; |
f2aa58c6 FB |
1158 | uint32_t val; |
1159 | ||
1160 | val = pci_data_read(s, addr & 3, 4); | |
1161 | #ifdef TARGET_WORDS_BIGENDIAN | |
1162 | val = bswap32(val); | |
1163 | #endif | |
1164 | ||
77d4bc34 FB |
1165 | return val; |
1166 | } | |
1167 | ||
f2aa58c6 FB |
1168 | static CPUWriteMemoryFunc *pci_unin_write[] = { |
1169 | &pci_unin_writeb, | |
1170 | &pci_unin_writew, | |
1171 | &pci_unin_writel, | |
77d4bc34 FB |
1172 | }; |
1173 | ||
f2aa58c6 FB |
1174 | static CPUReadMemoryFunc *pci_unin_read[] = { |
1175 | &pci_unin_readb, | |
1176 | &pci_unin_readw, | |
1177 | &pci_unin_readl, | |
77d4bc34 | 1178 | }; |
30468f78 FB |
1179 | #endif |
1180 | ||
30468f78 | 1181 | PCIBus *pci_pmac_init(void) |
77d4bc34 | 1182 | { |
30468f78 | 1183 | PCIBus *s; |
77d4bc34 FB |
1184 | PCIDevice *d; |
1185 | int pci_mem_config, pci_mem_data; | |
1186 | ||
f2aa58c6 FB |
1187 | /* Use values found on a real PowerMac */ |
1188 | /* Uninorth main bus */ | |
30468f78 | 1189 | s = pci_register_bus(); |
384d8876 | 1190 | s->set_irq = pci_set_irq_simple; |
30468f78 | 1191 | |
f2aa58c6 FB |
1192 | pci_mem_config = cpu_register_io_memory(0, pci_unin_main_config_read, |
1193 | pci_unin_main_config_write, s); | |
1194 | pci_mem_data = cpu_register_io_memory(0, pci_unin_main_read, | |
1195 | pci_unin_main_write, s); | |
1196 | cpu_register_physical_memory(0xf2800000, 0x1000, pci_mem_config); | |
1197 | cpu_register_physical_memory(0xf2c00000, 0x1000, pci_mem_data); | |
30468f78 FB |
1198 | s->devfn_min = 11 << 3; |
1199 | d = pci_register_device(s, "Uni-north main", sizeof(PCIDevice), | |
1200 | 11 << 3, NULL, NULL); | |
f2aa58c6 FB |
1201 | d->config[0x00] = 0x6b; // vendor_id : Apple |
1202 | d->config[0x01] = 0x10; | |
1203 | d->config[0x02] = 0x1F; // device_id | |
1204 | d->config[0x03] = 0x00; | |
1205 | d->config[0x08] = 0x00; // revision | |
1206 | d->config[0x0A] = 0x00; // class_sub = pci host | |
1207 | d->config[0x0B] = 0x06; // class_base = PCI_bridge | |
1208 | d->config[0x0C] = 0x08; // cache_line_size | |
1209 | d->config[0x0D] = 0x10; // latency_timer | |
1210 | d->config[0x0E] = 0x00; // header_type | |
1211 | d->config[0x34] = 0x00; // capabilities_pointer | |
1212 | ||
1213 | #if 0 // XXX: not activated as PPC BIOS doesn't handle mutiple buses properly | |
1214 | /* pci-to-pci bridge */ | |
1215 | d = pci_register_device("Uni-north bridge", sizeof(PCIDevice), 0, 13 << 3, | |
1216 | NULL, NULL); | |
1217 | d->config[0x00] = 0x11; // vendor_id : TI | |
1218 | d->config[0x01] = 0x10; | |
1219 | d->config[0x02] = 0x26; // device_id | |
1220 | d->config[0x03] = 0x00; | |
1221 | d->config[0x08] = 0x05; // revision | |
1222 | d->config[0x0A] = 0x04; // class_sub = pci2pci | |
1223 | d->config[0x0B] = 0x06; // class_base = PCI_bridge | |
1224 | d->config[0x0C] = 0x08; // cache_line_size | |
1225 | d->config[0x0D] = 0x20; // latency_timer | |
1226 | d->config[0x0E] = 0x01; // header_type | |
1227 | ||
1228 | d->config[0x18] = 0x01; // primary_bus | |
1229 | d->config[0x19] = 0x02; // secondary_bus | |
1230 | d->config[0x1A] = 0x02; // subordinate_bus | |
1231 | d->config[0x1B] = 0x20; // secondary_latency_timer | |
1232 | d->config[0x1C] = 0x11; // io_base | |
1233 | d->config[0x1D] = 0x01; // io_limit | |
1234 | d->config[0x20] = 0x00; // memory_base | |
1235 | d->config[0x21] = 0x80; | |
1236 | d->config[0x22] = 0x00; // memory_limit | |
1237 | d->config[0x23] = 0x80; | |
1238 | d->config[0x24] = 0x01; // prefetchable_memory_base | |
1239 | d->config[0x25] = 0x80; | |
1240 | d->config[0x26] = 0xF1; // prefectchable_memory_limit | |
1241 | d->config[0x27] = 0x7F; | |
1242 | // d->config[0x34] = 0xdc // capabilities_pointer | |
1243 | #endif | |
1244 | #if 0 // XXX: not needed for now | |
1245 | /* Uninorth AGP bus */ | |
1246 | s = &pci_bridge[1]; | |
1247 | pci_mem_config = cpu_register_io_memory(0, pci_unin_config_read, | |
1248 | pci_unin_config_write, s); | |
1249 | pci_mem_data = cpu_register_io_memory(0, pci_unin_read, | |
1250 | pci_unin_write, s); | |
1251 | cpu_register_physical_memory(0xf0800000, 0x1000, pci_mem_config); | |
1252 | cpu_register_physical_memory(0xf0c00000, 0x1000, pci_mem_data); | |
1253 | ||
1254 | d = pci_register_device("Uni-north AGP", sizeof(PCIDevice), 0, 11 << 3, | |
1255 | NULL, NULL); | |
1256 | d->config[0x00] = 0x6b; // vendor_id : Apple | |
1257 | d->config[0x01] = 0x10; | |
1258 | d->config[0x02] = 0x20; // device_id | |
1259 | d->config[0x03] = 0x00; | |
1260 | d->config[0x08] = 0x00; // revision | |
1261 | d->config[0x0A] = 0x00; // class_sub = pci host | |
1262 | d->config[0x0B] = 0x06; // class_base = PCI_bridge | |
1263 | d->config[0x0C] = 0x08; // cache_line_size | |
1264 | d->config[0x0D] = 0x10; // latency_timer | |
1265 | d->config[0x0E] = 0x00; // header_type | |
1266 | // d->config[0x34] = 0x80; // capabilities_pointer | |
1267 | #endif | |
77d4bc34 | 1268 | |
f2aa58c6 FB |
1269 | #if 0 // XXX: not needed for now |
1270 | /* Uninorth internal bus */ | |
1271 | s = &pci_bridge[2]; | |
1272 | pci_mem_config = cpu_register_io_memory(0, pci_unin_config_read, | |
1273 | pci_unin_config_write, s); | |
1274 | pci_mem_data = cpu_register_io_memory(0, pci_unin_read, | |
1275 | pci_unin_write, s); | |
1276 | cpu_register_physical_memory(0xf4800000, 0x1000, pci_mem_config); | |
1277 | cpu_register_physical_memory(0xf4c00000, 0x1000, pci_mem_data); | |
1278 | ||
1279 | d = pci_register_device("Uni-north internal", sizeof(PCIDevice), | |
1280 | 3, 11 << 3, NULL, NULL); | |
1281 | d->config[0x00] = 0x6b; // vendor_id : Apple | |
1282 | d->config[0x01] = 0x10; | |
1283 | d->config[0x02] = 0x1E; // device_id | |
1284 | d->config[0x03] = 0x00; | |
1285 | d->config[0x08] = 0x00; // revision | |
1286 | d->config[0x0A] = 0x00; // class_sub = pci host | |
1287 | d->config[0x0B] = 0x06; // class_base = PCI_bridge | |
1288 | d->config[0x0C] = 0x08; // cache_line_size | |
1289 | d->config[0x0D] = 0x10; // latency_timer | |
1290 | d->config[0x0E] = 0x00; // header_type | |
1291 | d->config[0x34] = 0x00; // capabilities_pointer | |
1292 | #endif | |
30468f78 | 1293 | return s; |
77d4bc34 FB |
1294 | } |
1295 | ||
83469015 FB |
1296 | /* Ultrasparc APB PCI host */ |
1297 | static void pci_apb_config_writel (void *opaque, target_phys_addr_t addr, | |
1298 | uint32_t val) | |
1299 | { | |
1300 | PCIBus *s = opaque; | |
1301 | int i; | |
1302 | ||
1303 | for (i = 11; i < 32; i++) { | |
1304 | if ((val & (1 << i)) != 0) | |
1305 | break; | |
1306 | } | |
1307 | s->config_reg = 0x80000000 | (1 << 16) | (val & 0x7FC) | (i << 11); | |
1308 | } | |
1309 | ||
1310 | static uint32_t pci_apb_config_readl (void *opaque, | |
1311 | target_phys_addr_t addr) | |
1312 | { | |
1313 | PCIBus *s = opaque; | |
1314 | uint32_t val; | |
1315 | int devfn; | |
1316 | ||
1317 | devfn = (s->config_reg >> 8) & 0xFF; | |
1318 | val = (1 << (devfn >> 3)) | ((devfn & 0x07) << 8) | (s->config_reg & 0xFC); | |
1319 | return val; | |
1320 | } | |
1321 | ||
1322 | static CPUWriteMemoryFunc *pci_apb_config_write[] = { | |
1323 | &pci_apb_config_writel, | |
1324 | &pci_apb_config_writel, | |
1325 | &pci_apb_config_writel, | |
1326 | }; | |
1327 | ||
1328 | static CPUReadMemoryFunc *pci_apb_config_read[] = { | |
1329 | &pci_apb_config_readl, | |
1330 | &pci_apb_config_readl, | |
1331 | &pci_apb_config_readl, | |
1332 | }; | |
1333 | ||
1334 | static void apb_config_writel (void *opaque, target_phys_addr_t addr, | |
1335 | uint32_t val) | |
1336 | { | |
1337 | //PCIBus *s = opaque; | |
1338 | ||
1339 | switch (addr & 0x3f) { | |
1340 | case 0x00: // Control/Status | |
1341 | case 0x10: // AFSR | |
1342 | case 0x18: // AFAR | |
1343 | case 0x20: // Diagnostic | |
1344 | case 0x28: // Target address space | |
1345 | // XXX | |
1346 | default: | |
1347 | break; | |
1348 | } | |
1349 | } | |
1350 | ||
1351 | static uint32_t apb_config_readl (void *opaque, | |
1352 | target_phys_addr_t addr) | |
1353 | { | |
1354 | //PCIBus *s = opaque; | |
1355 | uint32_t val; | |
1356 | ||
1357 | switch (addr & 0x3f) { | |
1358 | case 0x00: // Control/Status | |
1359 | case 0x10: // AFSR | |
1360 | case 0x18: // AFAR | |
1361 | case 0x20: // Diagnostic | |
1362 | case 0x28: // Target address space | |
1363 | // XXX | |
1364 | default: | |
1365 | val = 0; | |
1366 | break; | |
1367 | } | |
1368 | return val; | |
1369 | } | |
1370 | ||
1371 | static CPUWriteMemoryFunc *apb_config_write[] = { | |
1372 | &apb_config_writel, | |
1373 | &apb_config_writel, | |
1374 | &apb_config_writel, | |
1375 | }; | |
1376 | ||
1377 | static CPUReadMemoryFunc *apb_config_read[] = { | |
1378 | &apb_config_readl, | |
1379 | &apb_config_readl, | |
1380 | &apb_config_readl, | |
1381 | }; | |
1382 | ||
1383 | static void pci_apb_writeb (void *opaque, target_phys_addr_t addr, | |
1384 | uint32_t val) | |
1385 | { | |
1386 | PCIBus *s = opaque; | |
1387 | ||
1388 | pci_data_write(s, addr & 7, val, 1); | |
1389 | } | |
1390 | ||
1391 | static void pci_apb_writew (void *opaque, target_phys_addr_t addr, | |
1392 | uint32_t val) | |
1393 | { | |
1394 | PCIBus *s = opaque; | |
1395 | ||
1396 | pci_data_write(s, addr & 7, val, 2); | |
1397 | } | |
1398 | ||
1399 | static void pci_apb_writel (void *opaque, target_phys_addr_t addr, | |
1400 | uint32_t val) | |
1401 | { | |
1402 | PCIBus *s = opaque; | |
1403 | ||
1404 | pci_data_write(s, addr & 7, val, 4); | |
1405 | } | |
1406 | ||
1407 | static uint32_t pci_apb_readb (void *opaque, target_phys_addr_t addr) | |
1408 | { | |
1409 | PCIBus *s = opaque; | |
1410 | uint32_t val; | |
1411 | ||
1412 | val = pci_data_read(s, addr & 7, 1); | |
1413 | return val; | |
1414 | } | |
1415 | ||
1416 | static uint32_t pci_apb_readw (void *opaque, target_phys_addr_t addr) | |
1417 | { | |
1418 | PCIBus *s = opaque; | |
1419 | uint32_t val; | |
1420 | ||
1421 | val = pci_data_read(s, addr & 7, 2); | |
1422 | return val; | |
1423 | } | |
1424 | ||
1425 | static uint32_t pci_apb_readl (void *opaque, target_phys_addr_t addr) | |
1426 | { | |
1427 | PCIBus *s = opaque; | |
1428 | uint32_t val; | |
1429 | ||
1430 | val = pci_data_read(s, addr, 4); | |
1431 | return val; | |
1432 | } | |
1433 | ||
1434 | static CPUWriteMemoryFunc *pci_apb_write[] = { | |
1435 | &pci_apb_writeb, | |
1436 | &pci_apb_writew, | |
1437 | &pci_apb_writel, | |
1438 | }; | |
1439 | ||
1440 | static CPUReadMemoryFunc *pci_apb_read[] = { | |
1441 | &pci_apb_readb, | |
1442 | &pci_apb_readw, | |
1443 | &pci_apb_readl, | |
1444 | }; | |
1445 | ||
1446 | static void pci_apb_iowriteb (void *opaque, target_phys_addr_t addr, | |
1447 | uint32_t val) | |
1448 | { | |
1449 | cpu_outb(NULL, addr & 0xffff, val); | |
1450 | } | |
1451 | ||
1452 | static void pci_apb_iowritew (void *opaque, target_phys_addr_t addr, | |
1453 | uint32_t val) | |
1454 | { | |
1455 | cpu_outw(NULL, addr & 0xffff, val); | |
1456 | } | |
1457 | ||
1458 | static void pci_apb_iowritel (void *opaque, target_phys_addr_t addr, | |
1459 | uint32_t val) | |
1460 | { | |
1461 | cpu_outl(NULL, addr & 0xffff, val); | |
1462 | } | |
1463 | ||
1464 | static uint32_t pci_apb_ioreadb (void *opaque, target_phys_addr_t addr) | |
1465 | { | |
1466 | uint32_t val; | |
1467 | ||
1468 | val = cpu_inb(NULL, addr & 0xffff); | |
1469 | return val; | |
1470 | } | |
1471 | ||
1472 | static uint32_t pci_apb_ioreadw (void *opaque, target_phys_addr_t addr) | |
1473 | { | |
1474 | uint32_t val; | |
1475 | ||
1476 | val = cpu_inw(NULL, addr & 0xffff); | |
1477 | return val; | |
1478 | } | |
1479 | ||
1480 | static uint32_t pci_apb_ioreadl (void *opaque, target_phys_addr_t addr) | |
1481 | { | |
1482 | uint32_t val; | |
1483 | ||
1484 | val = cpu_inl(NULL, addr & 0xffff); | |
1485 | return val; | |
1486 | } | |
1487 | ||
1488 | static CPUWriteMemoryFunc *pci_apb_iowrite[] = { | |
1489 | &pci_apb_iowriteb, | |
1490 | &pci_apb_iowritew, | |
1491 | &pci_apb_iowritel, | |
1492 | }; | |
1493 | ||
1494 | static CPUReadMemoryFunc *pci_apb_ioread[] = { | |
1495 | &pci_apb_ioreadb, | |
1496 | &pci_apb_ioreadw, | |
1497 | &pci_apb_ioreadl, | |
1498 | }; | |
1499 | ||
1500 | PCIBus *pci_apb_init(target_ulong special_base, target_ulong mem_base) | |
1501 | { | |
1502 | PCIBus *s; | |
1503 | PCIDevice *d; | |
1504 | int pci_mem_config, pci_mem_data, apb_config, pci_ioport; | |
1505 | ||
1506 | /* Ultrasparc APB main bus */ | |
1507 | s = pci_register_bus(); | |
1508 | s->set_irq = pci_set_irq_simple; | |
1509 | ||
1510 | pci_mem_config = cpu_register_io_memory(0, pci_apb_config_read, | |
1511 | pci_apb_config_write, s); | |
1512 | apb_config = cpu_register_io_memory(0, apb_config_read, | |
1513 | apb_config_write, s); | |
1514 | pci_mem_data = cpu_register_io_memory(0, pci_apb_read, | |
1515 | pci_apb_write, s); | |
1516 | pci_ioport = cpu_register_io_memory(0, pci_apb_ioread, | |
1517 | pci_apb_iowrite, s); | |
1518 | ||
1519 | cpu_register_physical_memory(special_base + 0x2000ULL, 0x40, apb_config); | |
1520 | cpu_register_physical_memory(special_base + 0x1000000ULL, 0x10, pci_mem_config); | |
1521 | cpu_register_physical_memory(special_base + 0x2000000ULL, 0x10000, pci_ioport); | |
1522 | cpu_register_physical_memory(mem_base, 0x10000000, pci_mem_data); // XXX size should be 4G-prom | |
1523 | ||
1524 | d = pci_register_device(s, "Advanced PCI Bus", sizeof(PCIDevice), | |
1525 | -1, NULL, NULL); | |
1526 | d->config[0x00] = 0x8e; // vendor_id : Sun | |
1527 | d->config[0x01] = 0x10; | |
1528 | d->config[0x02] = 0x00; // device_id | |
1529 | d->config[0x03] = 0xa0; | |
1530 | d->config[0x04] = 0x06; // command = bus master, pci mem | |
1531 | d->config[0x05] = 0x00; | |
1532 | d->config[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error | |
1533 | d->config[0x07] = 0x03; // status = medium devsel | |
1534 | d->config[0x08] = 0x00; // revision | |
1535 | d->config[0x09] = 0x00; // programming i/f | |
1536 | d->config[0x0A] = 0x00; // class_sub = pci host | |
1537 | d->config[0x0B] = 0x06; // class_base = PCI_bridge | |
1538 | d->config[0x0D] = 0x10; // latency_timer | |
1539 | d->config[0x0E] = 0x00; // header_type | |
1540 | return s; | |
1541 | } | |
1542 | ||
0ac32c83 FB |
1543 | /***********************************************************/ |
1544 | /* generic PCI irq support */ | |
1545 | ||
0ac32c83 | 1546 | /* 0 <= irq_num <= 3. level must be 0 or 1 */ |
77d4bc34 FB |
1547 | void pci_set_irq(PCIDevice *pci_dev, int irq_num, int level) |
1548 | { | |
30468f78 FB |
1549 | PCIBus *bus = pci_dev->bus; |
1550 | bus->set_irq(pci_dev, irq_num, level); | |
77d4bc34 | 1551 | } |
0ac32c83 FB |
1552 | |
1553 | /***********************************************************/ | |
1554 | /* monitor info on PCI */ | |
1555 | ||
1556 | static void pci_info_device(PCIDevice *d) | |
1557 | { | |
1558 | int i, class; | |
1559 | PCIIORegion *r; | |
1560 | ||
8e3a9fd2 | 1561 | term_printf(" Bus %2d, device %3d, function %d:\n", |
30468f78 | 1562 | d->bus->bus_num, d->devfn >> 3, d->devfn & 7); |
0ac32c83 | 1563 | class = le16_to_cpu(*((uint16_t *)(d->config + PCI_CLASS_DEVICE))); |
8e3a9fd2 | 1564 | term_printf(" "); |
0ac32c83 FB |
1565 | switch(class) { |
1566 | case 0x0101: | |
8e3a9fd2 | 1567 | term_printf("IDE controller"); |
0ac32c83 FB |
1568 | break; |
1569 | case 0x0200: | |
8e3a9fd2 | 1570 | term_printf("Ethernet controller"); |
0ac32c83 FB |
1571 | break; |
1572 | case 0x0300: | |
8e3a9fd2 | 1573 | term_printf("VGA controller"); |
0ac32c83 FB |
1574 | break; |
1575 | default: | |
8e3a9fd2 | 1576 | term_printf("Class %04x", class); |
0ac32c83 FB |
1577 | break; |
1578 | } | |
8e3a9fd2 | 1579 | term_printf(": PCI device %04x:%04x\n", |
0ac32c83 FB |
1580 | le16_to_cpu(*((uint16_t *)(d->config + PCI_VENDOR_ID))), |
1581 | le16_to_cpu(*((uint16_t *)(d->config + PCI_DEVICE_ID)))); | |
1582 | ||
1583 | if (d->config[PCI_INTERRUPT_PIN] != 0) { | |
8e3a9fd2 | 1584 | term_printf(" IRQ %d.\n", d->config[PCI_INTERRUPT_LINE]); |
0ac32c83 | 1585 | } |
8a8696a3 | 1586 | for(i = 0;i < PCI_NUM_REGIONS; i++) { |
0ac32c83 FB |
1587 | r = &d->io_regions[i]; |
1588 | if (r->size != 0) { | |
8e3a9fd2 | 1589 | term_printf(" BAR%d: ", i); |
0ac32c83 | 1590 | if (r->type & PCI_ADDRESS_SPACE_IO) { |
8e3a9fd2 | 1591 | term_printf("I/O at 0x%04x [0x%04x].\n", |
0ac32c83 FB |
1592 | r->addr, r->addr + r->size - 1); |
1593 | } else { | |
8e3a9fd2 | 1594 | term_printf("32 bit memory at 0x%08x [0x%08x].\n", |
0ac32c83 FB |
1595 | r->addr, r->addr + r->size - 1); |
1596 | } | |
1597 | } | |
1598 | } | |
1599 | } | |
1600 | ||
1601 | void pci_info(void) | |
1602 | { | |
30468f78 FB |
1603 | PCIBus *bus = first_bus; |
1604 | PCIDevice *d; | |
1605 | int devfn; | |
0ac32c83 | 1606 | |
30468f78 FB |
1607 | if (bus) { |
1608 | for(devfn = 0; devfn < 256; devfn++) { | |
1609 | d = bus->devices[devfn]; | |
1610 | if (d) | |
1611 | pci_info_device(d); | |
0ac32c83 FB |
1612 | } |
1613 | } | |
1614 | } | |
1615 | ||
1616 | /***********************************************************/ | |
1617 | /* XXX: the following should be moved to the PC BIOS */ | |
1618 | ||
30468f78 | 1619 | static __attribute__((unused)) uint32_t isa_inb(uint32_t addr) |
0ac32c83 | 1620 | { |
c68ea704 | 1621 | return cpu_inb(NULL, addr); |
0ac32c83 FB |
1622 | } |
1623 | ||
1624 | static void isa_outb(uint32_t val, uint32_t addr) | |
1625 | { | |
c68ea704 | 1626 | cpu_outb(NULL, addr, val); |
0ac32c83 FB |
1627 | } |
1628 | ||
30468f78 | 1629 | static __attribute__((unused)) uint32_t isa_inw(uint32_t addr) |
0ac32c83 | 1630 | { |
c68ea704 | 1631 | return cpu_inw(NULL, addr); |
0ac32c83 FB |
1632 | } |
1633 | ||
30468f78 | 1634 | static __attribute__((unused)) void isa_outw(uint32_t val, uint32_t addr) |
0ac32c83 | 1635 | { |
c68ea704 | 1636 | cpu_outw(NULL, addr, val); |
0ac32c83 FB |
1637 | } |
1638 | ||
30468f78 | 1639 | static __attribute__((unused)) uint32_t isa_inl(uint32_t addr) |
0ac32c83 | 1640 | { |
c68ea704 | 1641 | return cpu_inl(NULL, addr); |
0ac32c83 FB |
1642 | } |
1643 | ||
30468f78 | 1644 | static __attribute__((unused)) void isa_outl(uint32_t val, uint32_t addr) |
0ac32c83 | 1645 | { |
c68ea704 | 1646 | cpu_outl(NULL, addr, val); |
0ac32c83 FB |
1647 | } |
1648 | ||
1649 | static void pci_config_writel(PCIDevice *d, uint32_t addr, uint32_t val) | |
1650 | { | |
30468f78 FB |
1651 | PCIBus *s = d->bus; |
1652 | s->config_reg = 0x80000000 | (s->bus_num << 16) | | |
0ac32c83 FB |
1653 | (d->devfn << 8) | addr; |
1654 | pci_data_write(s, 0, val, 4); | |
1655 | } | |
1656 | ||
1657 | static void pci_config_writew(PCIDevice *d, uint32_t addr, uint32_t val) | |
1658 | { | |
30468f78 FB |
1659 | PCIBus *s = d->bus; |
1660 | s->config_reg = 0x80000000 | (s->bus_num << 16) | | |
0ac32c83 FB |
1661 | (d->devfn << 8) | (addr & ~3); |
1662 | pci_data_write(s, addr & 3, val, 2); | |
1663 | } | |
1664 | ||
1665 | static void pci_config_writeb(PCIDevice *d, uint32_t addr, uint32_t val) | |
1666 | { | |
30468f78 FB |
1667 | PCIBus *s = d->bus; |
1668 | s->config_reg = 0x80000000 | (s->bus_num << 16) | | |
0ac32c83 FB |
1669 | (d->devfn << 8) | (addr & ~3); |
1670 | pci_data_write(s, addr & 3, val, 1); | |
1671 | } | |
1672 | ||
30468f78 | 1673 | static __attribute__((unused)) uint32_t pci_config_readl(PCIDevice *d, uint32_t addr) |
0ac32c83 | 1674 | { |
30468f78 FB |
1675 | PCIBus *s = d->bus; |
1676 | s->config_reg = 0x80000000 | (s->bus_num << 16) | | |
0ac32c83 FB |
1677 | (d->devfn << 8) | addr; |
1678 | return pci_data_read(s, 0, 4); | |
1679 | } | |
1680 | ||
1681 | static uint32_t pci_config_readw(PCIDevice *d, uint32_t addr) | |
1682 | { | |
30468f78 FB |
1683 | PCIBus *s = d->bus; |
1684 | s->config_reg = 0x80000000 | (s->bus_num << 16) | | |
0ac32c83 FB |
1685 | (d->devfn << 8) | (addr & ~3); |
1686 | return pci_data_read(s, addr & 3, 2); | |
1687 | } | |
1688 | ||
1689 | static uint32_t pci_config_readb(PCIDevice *d, uint32_t addr) | |
1690 | { | |
30468f78 FB |
1691 | PCIBus *s = d->bus; |
1692 | s->config_reg = 0x80000000 | (s->bus_num << 16) | | |
0ac32c83 FB |
1693 | (d->devfn << 8) | (addr & ~3); |
1694 | return pci_data_read(s, addr & 3, 1); | |
1695 | } | |
69b91039 FB |
1696 | |
1697 | static uint32_t pci_bios_io_addr; | |
1698 | static uint32_t pci_bios_mem_addr; | |
0ac32c83 FB |
1699 | /* host irqs corresponding to PCI irqs A-D */ |
1700 | static uint8_t pci_irqs[4] = { 11, 9, 11, 9 }; | |
69b91039 FB |
1701 | |
1702 | static void pci_set_io_region_addr(PCIDevice *d, int region_num, uint32_t addr) | |
1703 | { | |
69b91039 | 1704 | PCIIORegion *r; |
0ac32c83 | 1705 | uint16_t cmd; |
8a8696a3 FB |
1706 | uint32_t ofs; |
1707 | ||
1708 | if ( region_num == PCI_ROM_SLOT ) { | |
1709 | ofs = 0x30; | |
1710 | }else{ | |
1711 | ofs = 0x10 + region_num * 4; | |
1712 | } | |
69b91039 | 1713 | |
8a8696a3 | 1714 | pci_config_writel(d, ofs, addr); |
69b91039 FB |
1715 | r = &d->io_regions[region_num]; |
1716 | ||
1717 | /* enable memory mappings */ | |
0ac32c83 | 1718 | cmd = pci_config_readw(d, PCI_COMMAND); |
8a8696a3 FB |
1719 | if ( region_num == PCI_ROM_SLOT ) |
1720 | cmd |= 2; | |
1721 | else if (r->type & PCI_ADDRESS_SPACE_IO) | |
0ac32c83 | 1722 | cmd |= 1; |
69b91039 | 1723 | else |
0ac32c83 FB |
1724 | cmd |= 2; |
1725 | pci_config_writew(d, PCI_COMMAND, cmd); | |
69b91039 FB |
1726 | } |
1727 | ||
69b91039 FB |
1728 | static void pci_bios_init_device(PCIDevice *d) |
1729 | { | |
1730 | int class; | |
1731 | PCIIORegion *r; | |
1732 | uint32_t *paddr; | |
63ce9e0a | 1733 | int i, pin, pic_irq, vendor_id, device_id; |
69b91039 | 1734 | |
63ce9e0a | 1735 | class = pci_config_readw(d, PCI_CLASS_DEVICE); |
1f62d938 FB |
1736 | vendor_id = pci_config_readw(d, PCI_VENDOR_ID); |
1737 | device_id = pci_config_readw(d, PCI_DEVICE_ID); | |
69b91039 FB |
1738 | switch(class) { |
1739 | case 0x0101: | |
63ce9e0a FB |
1740 | if (vendor_id == 0x8086 && device_id == 0x7010) { |
1741 | /* PIIX3 IDE */ | |
63ce9e0a | 1742 | pci_config_writew(d, 0x40, 0x8000); // enable IDE0 |
7f647cf6 | 1743 | pci_config_writew(d, 0x42, 0x8000); // enable IDE1 |
d187d4b2 | 1744 | goto default_map; |
63ce9e0a FB |
1745 | } else { |
1746 | /* IDE: we map it as in ISA mode */ | |
1747 | pci_set_io_region_addr(d, 0, 0x1f0); | |
1748 | pci_set_io_region_addr(d, 1, 0x3f4); | |
1749 | pci_set_io_region_addr(d, 2, 0x170); | |
1750 | pci_set_io_region_addr(d, 3, 0x374); | |
1751 | } | |
69b91039 | 1752 | break; |
0ac32c83 | 1753 | case 0x0300: |
4c7634bc FB |
1754 | if (vendor_id != 0x1234) |
1755 | goto default_map; | |
0ac32c83 FB |
1756 | /* VGA: map frame buffer to default Bochs VBE address */ |
1757 | pci_set_io_region_addr(d, 0, 0xE0000000); | |
1758 | break; | |
f2aa58c6 FB |
1759 | case 0x0800: |
1760 | /* PIC */ | |
1761 | vendor_id = pci_config_readw(d, PCI_VENDOR_ID); | |
1762 | device_id = pci_config_readw(d, PCI_DEVICE_ID); | |
1763 | if (vendor_id == 0x1014) { | |
1764 | /* IBM */ | |
1765 | if (device_id == 0x0046 || device_id == 0xFFFF) { | |
1766 | /* MPIC & MPIC2 */ | |
1767 | pci_set_io_region_addr(d, 0, 0x80800000 + 0x00040000); | |
1768 | } | |
1769 | } | |
1770 | break; | |
1f62d938 | 1771 | case 0xff00: |
f2aa58c6 FB |
1772 | if (vendor_id == 0x0106b && |
1773 | (device_id == 0x0017 || device_id == 0x0022)) { | |
1f62d938 FB |
1774 | /* macio bridge */ |
1775 | pci_set_io_region_addr(d, 0, 0x80800000); | |
1776 | } | |
1777 | break; | |
69b91039 | 1778 | default: |
4c7634bc | 1779 | default_map: |
69b91039 | 1780 | /* default memory mappings */ |
8a8696a3 | 1781 | for(i = 0; i < PCI_NUM_REGIONS; i++) { |
69b91039 FB |
1782 | r = &d->io_regions[i]; |
1783 | if (r->size) { | |
1784 | if (r->type & PCI_ADDRESS_SPACE_IO) | |
1785 | paddr = &pci_bios_io_addr; | |
1786 | else | |
1787 | paddr = &pci_bios_mem_addr; | |
1788 | *paddr = (*paddr + r->size - 1) & ~(r->size - 1); | |
1789 | pci_set_io_region_addr(d, i, *paddr); | |
1790 | *paddr += r->size; | |
1791 | } | |
1792 | } | |
1793 | break; | |
1794 | } | |
0ac32c83 FB |
1795 | |
1796 | /* map the interrupt */ | |
1797 | pin = pci_config_readb(d, PCI_INTERRUPT_PIN); | |
1798 | if (pin != 0) { | |
1799 | pin = pci_slot_get_pirq(d, pin - 1); | |
1800 | pic_irq = pci_irqs[pin]; | |
1801 | pci_config_writeb(d, PCI_INTERRUPT_LINE, pic_irq); | |
1802 | } | |
69b91039 FB |
1803 | } |
1804 | ||
1805 | /* | |
1806 | * This function initializes the PCI devices as a normal PCI BIOS | |
1807 | * would do. It is provided just in case the BIOS has no support for | |
1808 | * PCI. | |
1809 | */ | |
1810 | void pci_bios_init(void) | |
1811 | { | |
30468f78 FB |
1812 | PCIBus *bus; |
1813 | PCIDevice *d; | |
1814 | int devfn, i, irq; | |
0ac32c83 | 1815 | uint8_t elcr[2]; |
69b91039 FB |
1816 | |
1817 | pci_bios_io_addr = 0xc000; | |
1818 | pci_bios_mem_addr = 0xf0000000; | |
1819 | ||
0ac32c83 FB |
1820 | /* activate IRQ mappings */ |
1821 | elcr[0] = 0x00; | |
1822 | elcr[1] = 0x00; | |
1823 | for(i = 0; i < 4; i++) { | |
1824 | irq = pci_irqs[i]; | |
1825 | /* set to trigger level */ | |
1826 | elcr[irq >> 3] |= (1 << (irq & 7)); | |
1827 | /* activate irq remapping in PIIX */ | |
1828 | pci_config_writeb((PCIDevice *)piix3_state, 0x60 + i, irq); | |
1829 | } | |
1830 | isa_outb(elcr[0], 0x4d0); | |
1831 | isa_outb(elcr[1], 0x4d1); | |
1832 | ||
30468f78 FB |
1833 | bus = first_bus; |
1834 | if (bus) { | |
1835 | for(devfn = 0; devfn < 256; devfn++) { | |
1836 | d = bus->devices[devfn]; | |
1837 | if (d) | |
1838 | pci_bios_init_device(d); | |
77d4bc34 FB |
1839 | } |
1840 | } | |
1841 | } | |
a41b2ff2 PB |
1842 | |
1843 | /* Initialize a PCI NIC. */ | |
1844 | void pci_nic_init(PCIBus *bus, NICInfo *nd) | |
1845 | { | |
1846 | if (strcmp(nd->model, "ne2k_pci") == 0) { | |
1847 | pci_ne2000_init(bus, nd); | |
1848 | } else if (strcmp(nd->model, "rtl8139") == 0) { | |
1849 | pci_rtl8139_init(bus, nd); | |
1850 | } else { | |
1851 | fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd->model); | |
1852 | exit (1); | |
1853 | } | |
1854 | } | |
1855 |