]>
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 | ||
69b91039 FB |
43 | typedef struct PCIBridge { |
44 | uint32_t config_reg; | |
45 | PCIDevice **pci_bus[256]; | |
46 | } PCIBridge; | |
47 | ||
f2aa58c6 | 48 | static PCIBridge pci_bridge[3]; |
69b91039 | 49 | target_phys_addr_t pci_mem_base; |
0ac32c83 FB |
50 | static int pci_irq_index; |
51 | static uint32_t pci_irq_levels[4][PCI_IRQ_WORDS]; | |
69b91039 FB |
52 | |
53 | /* -1 for devfn means auto assign */ | |
54 | PCIDevice *pci_register_device(const char *name, int instance_size, | |
55 | int bus_num, int devfn, | |
56 | PCIConfigReadFunc *config_read, | |
57 | PCIConfigWriteFunc *config_write) | |
58 | { | |
f2aa58c6 | 59 | PCIBridge *s = &pci_bridge[0]; |
69b91039 FB |
60 | PCIDevice *pci_dev, **bus; |
61 | ||
0ac32c83 FB |
62 | if (pci_irq_index >= PCI_DEVICES_MAX) |
63 | return NULL; | |
64 | ||
69b91039 FB |
65 | if (!s->pci_bus[bus_num]) { |
66 | s->pci_bus[bus_num] = qemu_mallocz(256 * sizeof(PCIDevice *)); | |
67 | if (!s->pci_bus[bus_num]) | |
68 | return NULL; | |
69 | } | |
70 | bus = s->pci_bus[bus_num]; | |
71 | if (devfn < 0) { | |
72 | for(devfn = 0 ; devfn < 256; devfn += 8) { | |
f2aa58c6 FB |
73 | #ifdef TARGET_PPC |
74 | if ((devfn >> 3) < 11) | |
75 | continue; | |
76 | #endif | |
69b91039 FB |
77 | if (!bus[devfn]) |
78 | goto found; | |
79 | } | |
80 | return NULL; | |
81 | found: ; | |
82 | } | |
83 | pci_dev = qemu_mallocz(instance_size); | |
84 | if (!pci_dev) | |
85 | return NULL; | |
86 | pci_dev->bus_num = bus_num; | |
87 | pci_dev->devfn = devfn; | |
88 | pstrcpy(pci_dev->name, sizeof(pci_dev->name), name); | |
0ac32c83 FB |
89 | |
90 | if (!config_read) | |
91 | config_read = pci_default_read_config; | |
92 | if (!config_write) | |
93 | config_write = pci_default_write_config; | |
69b91039 FB |
94 | pci_dev->config_read = config_read; |
95 | pci_dev->config_write = config_write; | |
0ac32c83 | 96 | pci_dev->irq_index = pci_irq_index++; |
69b91039 FB |
97 | bus[devfn] = pci_dev; |
98 | return pci_dev; | |
99 | } | |
100 | ||
101 | void pci_register_io_region(PCIDevice *pci_dev, int region_num, | |
102 | uint32_t size, int type, | |
103 | PCIMapIORegionFunc *map_func) | |
104 | { | |
105 | PCIIORegion *r; | |
106 | ||
8a8696a3 | 107 | if ((unsigned int)region_num >= PCI_NUM_REGIONS) |
69b91039 FB |
108 | return; |
109 | r = &pci_dev->io_regions[region_num]; | |
110 | r->addr = -1; | |
111 | r->size = size; | |
112 | r->type = type; | |
113 | r->map_func = map_func; | |
114 | } | |
115 | ||
0ac32c83 | 116 | static void pci_addr_writel(void* opaque, uint32_t addr, uint32_t val) |
69b91039 FB |
117 | { |
118 | PCIBridge *s = opaque; | |
119 | s->config_reg = val; | |
120 | } | |
121 | ||
0ac32c83 | 122 | static uint32_t pci_addr_readl(void* opaque, uint32_t addr) |
69b91039 FB |
123 | { |
124 | PCIBridge *s = opaque; | |
125 | return s->config_reg; | |
126 | } | |
127 | ||
0ac32c83 FB |
128 | static void pci_update_mappings(PCIDevice *d) |
129 | { | |
130 | PCIIORegion *r; | |
131 | int cmd, i; | |
8a8696a3 | 132 | uint32_t last_addr, new_addr, config_ofs; |
0ac32c83 FB |
133 | |
134 | cmd = le16_to_cpu(*(uint16_t *)(d->config + PCI_COMMAND)); | |
8a8696a3 | 135 | for(i = 0; i < PCI_NUM_REGIONS; i++) { |
0ac32c83 | 136 | r = &d->io_regions[i]; |
8a8696a3 FB |
137 | if (i == PCI_ROM_SLOT) { |
138 | config_ofs = 0x30; | |
139 | } else { | |
140 | config_ofs = 0x10 + i * 4; | |
141 | } | |
0ac32c83 FB |
142 | if (r->size != 0) { |
143 | if (r->type & PCI_ADDRESS_SPACE_IO) { | |
144 | if (cmd & PCI_COMMAND_IO) { | |
145 | new_addr = le32_to_cpu(*(uint32_t *)(d->config + | |
8a8696a3 | 146 | config_ofs)); |
0ac32c83 FB |
147 | new_addr = new_addr & ~(r->size - 1); |
148 | last_addr = new_addr + r->size - 1; | |
149 | /* NOTE: we have only 64K ioports on PC */ | |
150 | if (last_addr <= new_addr || new_addr == 0 || | |
151 | last_addr >= 0x10000) { | |
152 | new_addr = -1; | |
153 | } | |
154 | } else { | |
155 | new_addr = -1; | |
156 | } | |
157 | } else { | |
158 | if (cmd & PCI_COMMAND_MEMORY) { | |
159 | new_addr = le32_to_cpu(*(uint32_t *)(d->config + | |
8a8696a3 FB |
160 | config_ofs)); |
161 | /* the ROM slot has a specific enable bit */ | |
162 | if (i == PCI_ROM_SLOT && !(new_addr & 1)) | |
163 | goto no_mem_map; | |
0ac32c83 FB |
164 | new_addr = new_addr & ~(r->size - 1); |
165 | last_addr = new_addr + r->size - 1; | |
166 | /* NOTE: we do not support wrapping */ | |
167 | /* XXX: as we cannot support really dynamic | |
168 | mappings, we handle specific values as invalid | |
169 | mappings. */ | |
170 | if (last_addr <= new_addr || new_addr == 0 || | |
171 | last_addr == -1) { | |
172 | new_addr = -1; | |
173 | } | |
174 | } else { | |
8a8696a3 | 175 | no_mem_map: |
0ac32c83 FB |
176 | new_addr = -1; |
177 | } | |
178 | } | |
179 | /* now do the real mapping */ | |
180 | if (new_addr != r->addr) { | |
181 | if (r->addr != -1) { | |
182 | if (r->type & PCI_ADDRESS_SPACE_IO) { | |
183 | int class; | |
184 | /* NOTE: specific hack for IDE in PC case: | |
185 | only one byte must be mapped. */ | |
186 | class = d->config[0x0a] | (d->config[0x0b] << 8); | |
187 | if (class == 0x0101 && r->size == 4) { | |
188 | isa_unassign_ioport(r->addr + 2, 1); | |
189 | } else { | |
190 | isa_unassign_ioport(r->addr, r->size); | |
191 | } | |
192 | } else { | |
193 | cpu_register_physical_memory(r->addr + pci_mem_base, | |
194 | r->size, | |
195 | IO_MEM_UNASSIGNED); | |
196 | } | |
197 | } | |
198 | r->addr = new_addr; | |
199 | if (r->addr != -1) { | |
200 | r->map_func(d, i, r->addr, r->size, r->type); | |
201 | } | |
202 | } | |
203 | } | |
204 | } | |
205 | } | |
206 | ||
207 | uint32_t pci_default_read_config(PCIDevice *d, | |
208 | uint32_t address, int len) | |
69b91039 | 209 | { |
0ac32c83 FB |
210 | uint32_t val; |
211 | switch(len) { | |
212 | case 1: | |
213 | val = d->config[address]; | |
214 | break; | |
215 | case 2: | |
216 | val = le16_to_cpu(*(uint16_t *)(d->config + address)); | |
217 | break; | |
218 | default: | |
219 | case 4: | |
220 | val = le32_to_cpu(*(uint32_t *)(d->config + address)); | |
221 | break; | |
222 | } | |
223 | return val; | |
224 | } | |
225 | ||
226 | void pci_default_write_config(PCIDevice *d, | |
227 | uint32_t address, uint32_t val, int len) | |
228 | { | |
229 | int can_write, i; | |
7bf5be70 | 230 | uint32_t end, addr; |
0ac32c83 | 231 | |
8a8696a3 FB |
232 | if (len == 4 && ((address >= 0x10 && address < 0x10 + 4 * 6) || |
233 | (address >= 0x30 && address < 0x34))) { | |
0ac32c83 FB |
234 | PCIIORegion *r; |
235 | int reg; | |
236 | ||
8a8696a3 FB |
237 | if ( address >= 0x30 ) { |
238 | reg = PCI_ROM_SLOT; | |
239 | }else{ | |
240 | reg = (address - 0x10) >> 2; | |
241 | } | |
0ac32c83 FB |
242 | r = &d->io_regions[reg]; |
243 | if (r->size == 0) | |
244 | goto default_config; | |
245 | /* compute the stored value */ | |
8a8696a3 FB |
246 | if (reg == PCI_ROM_SLOT) { |
247 | /* keep ROM enable bit */ | |
248 | val &= (~(r->size - 1)) | 1; | |
249 | } else { | |
250 | val &= ~(r->size - 1); | |
251 | val |= r->type; | |
252 | } | |
253 | *(uint32_t *)(d->config + address) = cpu_to_le32(val); | |
0ac32c83 | 254 | pci_update_mappings(d); |
69b91039 | 255 | return; |
0ac32c83 FB |
256 | } |
257 | default_config: | |
258 | /* not efficient, but simple */ | |
7bf5be70 | 259 | addr = address; |
0ac32c83 FB |
260 | for(i = 0; i < len; i++) { |
261 | /* default read/write accesses */ | |
1f62d938 | 262 | switch(d->config[0x0e]) { |
0ac32c83 | 263 | case 0x00: |
1f62d938 FB |
264 | case 0x80: |
265 | switch(addr) { | |
266 | case 0x00: | |
267 | case 0x01: | |
268 | case 0x02: | |
269 | case 0x03: | |
270 | case 0x08: | |
271 | case 0x09: | |
272 | case 0x0a: | |
273 | case 0x0b: | |
274 | case 0x0e: | |
275 | case 0x10 ... 0x27: /* base */ | |
276 | case 0x30 ... 0x33: /* rom */ | |
277 | case 0x3d: | |
278 | can_write = 0; | |
279 | break; | |
280 | default: | |
281 | can_write = 1; | |
282 | break; | |
283 | } | |
0ac32c83 FB |
284 | break; |
285 | default: | |
1f62d938 FB |
286 | case 0x01: |
287 | switch(addr) { | |
288 | case 0x00: | |
289 | case 0x01: | |
290 | case 0x02: | |
291 | case 0x03: | |
292 | case 0x08: | |
293 | case 0x09: | |
294 | case 0x0a: | |
295 | case 0x0b: | |
296 | case 0x0e: | |
297 | case 0x38 ... 0x3b: /* rom */ | |
298 | case 0x3d: | |
299 | can_write = 0; | |
300 | break; | |
301 | default: | |
302 | can_write = 1; | |
303 | break; | |
304 | } | |
0ac32c83 FB |
305 | break; |
306 | } | |
307 | if (can_write) { | |
7bf5be70 | 308 | d->config[addr] = val; |
0ac32c83 | 309 | } |
7bf5be70 | 310 | addr++; |
0ac32c83 FB |
311 | val >>= 8; |
312 | } | |
313 | ||
314 | end = address + len; | |
315 | if (end > PCI_COMMAND && address < (PCI_COMMAND + 2)) { | |
316 | /* if the command register is modified, we must modify the mappings */ | |
317 | pci_update_mappings(d); | |
69b91039 FB |
318 | } |
319 | } | |
320 | ||
321 | static void pci_data_write(void *opaque, uint32_t addr, | |
322 | uint32_t val, int len) | |
323 | { | |
324 | PCIBridge *s = opaque; | |
325 | PCIDevice **bus, *pci_dev; | |
0ac32c83 | 326 | int config_addr; |
69b91039 FB |
327 | |
328 | #if defined(DEBUG_PCI) && 0 | |
329 | printf("pci_data_write: addr=%08x val=%08x len=%d\n", | |
330 | s->config_reg, val, len); | |
331 | #endif | |
332 | if (!(s->config_reg & (1 << 31))) { | |
333 | return; | |
334 | } | |
335 | if ((s->config_reg & 0x3) != 0) { | |
336 | return; | |
337 | } | |
338 | bus = s->pci_bus[(s->config_reg >> 16) & 0xff]; | |
339 | if (!bus) | |
340 | return; | |
341 | pci_dev = bus[(s->config_reg >> 8) & 0xff]; | |
342 | if (!pci_dev) | |
343 | return; | |
344 | config_addr = (s->config_reg & 0xfc) | (addr & 3); | |
69b91039 FB |
345 | #if defined(DEBUG_PCI) |
346 | printf("pci_config_write: %s: addr=%02x val=%08x len=%d\n", | |
347 | pci_dev->name, config_addr, val, len); | |
348 | #endif | |
0ac32c83 | 349 | pci_dev->config_write(pci_dev, config_addr, val, len); |
69b91039 FB |
350 | } |
351 | ||
352 | static uint32_t pci_data_read(void *opaque, uint32_t addr, | |
353 | int len) | |
354 | { | |
355 | PCIBridge *s = opaque; | |
356 | PCIDevice **bus, *pci_dev; | |
357 | int config_addr; | |
358 | uint32_t val; | |
359 | ||
360 | if (!(s->config_reg & (1 << 31))) | |
361 | goto fail; | |
362 | if ((s->config_reg & 0x3) != 0) | |
363 | goto fail; | |
364 | bus = s->pci_bus[(s->config_reg >> 16) & 0xff]; | |
365 | if (!bus) | |
366 | goto fail; | |
367 | pci_dev = bus[(s->config_reg >> 8) & 0xff]; | |
368 | if (!pci_dev) { | |
369 | fail: | |
63ce9e0a FB |
370 | switch(len) { |
371 | case 1: | |
372 | val = 0xff; | |
373 | break; | |
374 | case 2: | |
375 | val = 0xffff; | |
376 | break; | |
377 | default: | |
378 | case 4: | |
379 | val = 0xffffffff; | |
380 | break; | |
381 | } | |
69b91039 FB |
382 | goto the_end; |
383 | } | |
384 | config_addr = (s->config_reg & 0xfc) | (addr & 3); | |
385 | val = pci_dev->config_read(pci_dev, config_addr, len); | |
386 | #if defined(DEBUG_PCI) | |
387 | printf("pci_config_read: %s: addr=%02x val=%08x len=%d\n", | |
388 | pci_dev->name, config_addr, val, len); | |
389 | #endif | |
390 | the_end: | |
391 | #if defined(DEBUG_PCI) && 0 | |
392 | printf("pci_data_read: addr=%08x val=%08x len=%d\n", | |
393 | s->config_reg, val, len); | |
394 | #endif | |
395 | return val; | |
396 | } | |
397 | ||
398 | static void pci_data_writeb(void* opaque, uint32_t addr, uint32_t val) | |
399 | { | |
400 | pci_data_write(opaque, addr, val, 1); | |
401 | } | |
402 | ||
403 | static void pci_data_writew(void* opaque, uint32_t addr, uint32_t val) | |
404 | { | |
405 | pci_data_write(opaque, addr, val, 2); | |
406 | } | |
407 | ||
408 | static void pci_data_writel(void* opaque, uint32_t addr, uint32_t val) | |
409 | { | |
410 | pci_data_write(opaque, addr, val, 4); | |
411 | } | |
412 | ||
413 | static uint32_t pci_data_readb(void* opaque, uint32_t addr) | |
414 | { | |
415 | return pci_data_read(opaque, addr, 1); | |
416 | } | |
417 | ||
418 | static uint32_t pci_data_readw(void* opaque, uint32_t addr) | |
419 | { | |
420 | return pci_data_read(opaque, addr, 2); | |
421 | } | |
422 | ||
423 | static uint32_t pci_data_readl(void* opaque, uint32_t addr) | |
424 | { | |
425 | return pci_data_read(opaque, addr, 4); | |
426 | } | |
427 | ||
428 | /* i440FX PCI bridge */ | |
429 | ||
69b91039 FB |
430 | void i440fx_init(void) |
431 | { | |
f2aa58c6 | 432 | PCIBridge *s = &pci_bridge[0]; |
69b91039 FB |
433 | PCIDevice *d; |
434 | ||
0ac32c83 FB |
435 | register_ioport_write(0xcf8, 4, 4, pci_addr_writel, s); |
436 | register_ioport_read(0xcf8, 4, 4, pci_addr_readl, s); | |
69b91039 FB |
437 | |
438 | register_ioport_write(0xcfc, 4, 1, pci_data_writeb, s); | |
439 | register_ioport_write(0xcfc, 4, 2, pci_data_writew, s); | |
440 | register_ioport_write(0xcfc, 4, 4, pci_data_writel, s); | |
441 | register_ioport_read(0xcfc, 4, 1, pci_data_readb, s); | |
442 | register_ioport_read(0xcfc, 4, 2, pci_data_readw, s); | |
443 | register_ioport_read(0xcfc, 4, 4, pci_data_readl, s); | |
444 | ||
445 | d = pci_register_device("i440FX", sizeof(PCIDevice), 0, 0, | |
0ac32c83 | 446 | NULL, NULL); |
69b91039 FB |
447 | |
448 | d->config[0x00] = 0x86; // vendor_id | |
449 | d->config[0x01] = 0x80; | |
450 | d->config[0x02] = 0x37; // device_id | |
451 | d->config[0x03] = 0x12; | |
452 | d->config[0x08] = 0x02; // revision | |
358c6407 | 453 | d->config[0x0a] = 0x00; // class_sub = host2pci |
69b91039 | 454 | d->config[0x0b] = 0x06; // class_base = PCI_bridge |
358c6407 | 455 | d->config[0x0e] = 0x00; // header_type |
69b91039 FB |
456 | } |
457 | ||
0ac32c83 FB |
458 | /* PIIX3 PCI to ISA bridge */ |
459 | ||
460 | typedef struct PIIX3State { | |
461 | PCIDevice dev; | |
462 | } PIIX3State; | |
463 | ||
464 | PIIX3State *piix3_state; | |
465 | ||
466 | static void piix3_reset(PIIX3State *d) | |
467 | { | |
468 | uint8_t *pci_conf = d->dev.config; | |
469 | ||
470 | pci_conf[0x04] = 0x07; // master, memory and I/O | |
471 | pci_conf[0x05] = 0x00; | |
472 | pci_conf[0x06] = 0x00; | |
473 | pci_conf[0x07] = 0x02; // PCI_status_devsel_medium | |
474 | pci_conf[0x4c] = 0x4d; | |
475 | pci_conf[0x4e] = 0x03; | |
476 | pci_conf[0x4f] = 0x00; | |
477 | pci_conf[0x60] = 0x80; | |
478 | pci_conf[0x69] = 0x02; | |
479 | pci_conf[0x70] = 0x80; | |
480 | pci_conf[0x76] = 0x0c; | |
481 | pci_conf[0x77] = 0x0c; | |
482 | pci_conf[0x78] = 0x02; | |
483 | pci_conf[0x79] = 0x00; | |
484 | pci_conf[0x80] = 0x00; | |
485 | pci_conf[0x82] = 0x00; | |
486 | pci_conf[0xa0] = 0x08; | |
487 | pci_conf[0xa0] = 0x08; | |
488 | pci_conf[0xa2] = 0x00; | |
489 | pci_conf[0xa3] = 0x00; | |
490 | pci_conf[0xa4] = 0x00; | |
491 | pci_conf[0xa5] = 0x00; | |
492 | pci_conf[0xa6] = 0x00; | |
493 | pci_conf[0xa7] = 0x00; | |
494 | pci_conf[0xa8] = 0x0f; | |
495 | pci_conf[0xaa] = 0x00; | |
496 | pci_conf[0xab] = 0x00; | |
497 | pci_conf[0xac] = 0x00; | |
498 | pci_conf[0xae] = 0x00; | |
499 | } | |
500 | ||
501 | void piix3_init(void) | |
502 | { | |
503 | PIIX3State *d; | |
504 | uint8_t *pci_conf; | |
505 | ||
506 | d = (PIIX3State *)pci_register_device("PIIX3", sizeof(PIIX3State), | |
507 | 0, -1, | |
508 | NULL, NULL); | |
509 | piix3_state = d; | |
510 | pci_conf = d->dev.config; | |
511 | ||
512 | pci_conf[0x00] = 0x86; // Intel | |
513 | pci_conf[0x01] = 0x80; | |
514 | pci_conf[0x02] = 0x00; // 82371SB PIIX3 PCI-to-ISA bridge (Step A1) | |
515 | pci_conf[0x03] = 0x70; | |
516 | pci_conf[0x0a] = 0x01; // class_sub = PCI_ISA | |
517 | pci_conf[0x0b] = 0x06; // class_base = PCI_bridge | |
518 | pci_conf[0x0e] = 0x80; // header_type = PCI_multifunction, generic | |
519 | ||
520 | piix3_reset(d); | |
521 | } | |
522 | ||
77d4bc34 FB |
523 | /* PREP pci init */ |
524 | ||
525 | static inline void set_config(PCIBridge *s, target_phys_addr_t addr) | |
526 | { | |
527 | int devfn, i; | |
528 | ||
529 | for(i = 0; i < 11; i++) { | |
530 | if ((addr & (1 << (11 + i))) != 0) | |
531 | break; | |
532 | } | |
533 | devfn = ((addr >> 8) & 7) | (i << 3); | |
534 | s->config_reg = 0x80000000 | (addr & 0xfc) | (devfn << 8); | |
535 | } | |
536 | ||
8a8696a3 | 537 | static void PPC_PCIIO_writeb (void *opaque, target_phys_addr_t addr, uint32_t val) |
77d4bc34 | 538 | { |
8a8696a3 | 539 | PCIBridge *s = opaque; |
77d4bc34 FB |
540 | set_config(s, addr); |
541 | pci_data_write(s, addr, val, 1); | |
542 | } | |
543 | ||
8a8696a3 | 544 | static void PPC_PCIIO_writew (void *opaque, target_phys_addr_t addr, uint32_t val) |
77d4bc34 | 545 | { |
8a8696a3 | 546 | PCIBridge *s = opaque; |
77d4bc34 FB |
547 | set_config(s, addr); |
548 | #ifdef TARGET_WORDS_BIGENDIAN | |
549 | val = bswap16(val); | |
550 | #endif | |
551 | pci_data_write(s, addr, val, 2); | |
552 | } | |
553 | ||
8a8696a3 | 554 | static void PPC_PCIIO_writel (void *opaque, target_phys_addr_t addr, uint32_t val) |
77d4bc34 | 555 | { |
8a8696a3 | 556 | PCIBridge *s = opaque; |
77d4bc34 FB |
557 | set_config(s, addr); |
558 | #ifdef TARGET_WORDS_BIGENDIAN | |
559 | val = bswap32(val); | |
560 | #endif | |
561 | pci_data_write(s, addr, val, 4); | |
562 | } | |
563 | ||
8a8696a3 | 564 | static uint32_t PPC_PCIIO_readb (void *opaque, target_phys_addr_t addr) |
77d4bc34 | 565 | { |
8a8696a3 | 566 | PCIBridge *s = opaque; |
77d4bc34 FB |
567 | uint32_t val; |
568 | set_config(s, addr); | |
569 | val = pci_data_read(s, addr, 1); | |
570 | return val; | |
571 | } | |
572 | ||
8a8696a3 | 573 | static uint32_t PPC_PCIIO_readw (void *opaque, target_phys_addr_t addr) |
77d4bc34 | 574 | { |
8a8696a3 | 575 | PCIBridge *s = opaque; |
77d4bc34 FB |
576 | uint32_t val; |
577 | set_config(s, addr); | |
578 | val = pci_data_read(s, addr, 2); | |
579 | #ifdef TARGET_WORDS_BIGENDIAN | |
580 | val = bswap16(val); | |
581 | #endif | |
582 | return val; | |
583 | } | |
584 | ||
8a8696a3 | 585 | static uint32_t PPC_PCIIO_readl (void *opaque, target_phys_addr_t addr) |
77d4bc34 | 586 | { |
8a8696a3 | 587 | PCIBridge *s = opaque; |
77d4bc34 FB |
588 | uint32_t val; |
589 | set_config(s, addr); | |
590 | val = pci_data_read(s, addr, 4); | |
591 | #ifdef TARGET_WORDS_BIGENDIAN | |
592 | val = bswap32(val); | |
593 | #endif | |
594 | return val; | |
595 | } | |
596 | ||
597 | static CPUWriteMemoryFunc *PPC_PCIIO_write[] = { | |
598 | &PPC_PCIIO_writeb, | |
599 | &PPC_PCIIO_writew, | |
600 | &PPC_PCIIO_writel, | |
601 | }; | |
602 | ||
603 | static CPUReadMemoryFunc *PPC_PCIIO_read[] = { | |
604 | &PPC_PCIIO_readb, | |
605 | &PPC_PCIIO_readw, | |
606 | &PPC_PCIIO_readl, | |
607 | }; | |
608 | ||
609 | void pci_prep_init(void) | |
610 | { | |
f2aa58c6 | 611 | PCIBridge *s = &pci_bridge[0]; |
77d4bc34 FB |
612 | PCIDevice *d; |
613 | int PPC_io_memory; | |
614 | ||
8a8696a3 FB |
615 | PPC_io_memory = cpu_register_io_memory(0, PPC_PCIIO_read, |
616 | PPC_PCIIO_write, s); | |
77d4bc34 FB |
617 | cpu_register_physical_memory(0x80800000, 0x00400000, PPC_io_memory); |
618 | ||
619 | d = pci_register_device("PREP PCI Bridge", sizeof(PCIDevice), 0, 0, | |
620 | NULL, NULL); | |
621 | ||
622 | /* XXX: put correct IDs */ | |
623 | d->config[0x00] = 0x11; // vendor_id | |
624 | d->config[0x01] = 0x10; | |
625 | d->config[0x02] = 0x26; // device_id | |
626 | d->config[0x03] = 0x00; | |
627 | d->config[0x08] = 0x02; // revision | |
628 | d->config[0x0a] = 0x04; // class_sub = pci2pci | |
629 | d->config[0x0b] = 0x06; // class_base = PCI_bridge | |
630 | d->config[0x0e] = 0x01; // header_type | |
631 | } | |
632 | ||
633 | ||
634 | /* pmac pci init */ | |
635 | ||
f2aa58c6 FB |
636 | /* Grackle PCI host */ |
637 | static void pci_grackle_config_writel (void *opaque, target_phys_addr_t addr, | |
638 | uint32_t val) | |
77d4bc34 | 639 | { |
8a8696a3 | 640 | PCIBridge *s = opaque; |
77d4bc34 FB |
641 | #ifdef TARGET_WORDS_BIGENDIAN |
642 | val = bswap32(val); | |
643 | #endif | |
644 | s->config_reg = val; | |
645 | } | |
646 | ||
f2aa58c6 | 647 | static uint32_t pci_grackle_config_readl (void *opaque, target_phys_addr_t addr) |
77d4bc34 | 648 | { |
8a8696a3 | 649 | PCIBridge *s = opaque; |
77d4bc34 FB |
650 | uint32_t val; |
651 | ||
652 | val = s->config_reg; | |
653 | #ifdef TARGET_WORDS_BIGENDIAN | |
654 | val = bswap32(val); | |
655 | #endif | |
656 | return val; | |
657 | } | |
658 | ||
f2aa58c6 FB |
659 | static CPUWriteMemoryFunc *pci_grackle_config_write[] = { |
660 | &pci_grackle_config_writel, | |
661 | &pci_grackle_config_writel, | |
662 | &pci_grackle_config_writel, | |
77d4bc34 FB |
663 | }; |
664 | ||
f2aa58c6 FB |
665 | static CPUReadMemoryFunc *pci_grackle_config_read[] = { |
666 | &pci_grackle_config_readl, | |
667 | &pci_grackle_config_readl, | |
668 | &pci_grackle_config_readl, | |
77d4bc34 FB |
669 | }; |
670 | ||
f2aa58c6 FB |
671 | static void pci_grackle_writeb (void *opaque, target_phys_addr_t addr, |
672 | uint32_t val) | |
77d4bc34 | 673 | { |
8a8696a3 | 674 | PCIBridge *s = opaque; |
77d4bc34 FB |
675 | pci_data_write(s, addr, val, 1); |
676 | } | |
677 | ||
f2aa58c6 FB |
678 | static void pci_grackle_writew (void *opaque, target_phys_addr_t addr, |
679 | uint32_t val) | |
77d4bc34 | 680 | { |
8a8696a3 | 681 | PCIBridge *s = opaque; |
77d4bc34 FB |
682 | #ifdef TARGET_WORDS_BIGENDIAN |
683 | val = bswap16(val); | |
684 | #endif | |
685 | pci_data_write(s, addr, val, 2); | |
686 | } | |
687 | ||
f2aa58c6 FB |
688 | static void pci_grackle_writel (void *opaque, target_phys_addr_t addr, |
689 | uint32_t val) | |
77d4bc34 | 690 | { |
8a8696a3 | 691 | PCIBridge *s = opaque; |
77d4bc34 FB |
692 | #ifdef TARGET_WORDS_BIGENDIAN |
693 | val = bswap32(val); | |
694 | #endif | |
695 | pci_data_write(s, addr, val, 4); | |
696 | } | |
697 | ||
f2aa58c6 | 698 | static uint32_t pci_grackle_readb (void *opaque, target_phys_addr_t addr) |
77d4bc34 | 699 | { |
8a8696a3 | 700 | PCIBridge *s = opaque; |
77d4bc34 FB |
701 | uint32_t val; |
702 | val = pci_data_read(s, addr, 1); | |
703 | return val; | |
704 | } | |
705 | ||
f2aa58c6 | 706 | static uint32_t pci_grackle_readw (void *opaque, target_phys_addr_t addr) |
77d4bc34 | 707 | { |
8a8696a3 | 708 | PCIBridge *s = opaque; |
77d4bc34 FB |
709 | uint32_t val; |
710 | val = pci_data_read(s, addr, 2); | |
711 | #ifdef TARGET_WORDS_BIGENDIAN | |
712 | val = bswap16(val); | |
713 | #endif | |
714 | return val; | |
715 | } | |
716 | ||
f2aa58c6 FB |
717 | static uint32_t pci_grackle_readl (void *opaque, target_phys_addr_t addr) |
718 | { | |
719 | PCIBridge *s = opaque; | |
720 | uint32_t val; | |
721 | ||
722 | val = pci_data_read(s, addr, 4); | |
723 | #ifdef TARGET_WORDS_BIGENDIAN | |
724 | val = bswap32(val); | |
725 | #endif | |
726 | return val; | |
727 | } | |
728 | ||
729 | static CPUWriteMemoryFunc *pci_grackle_write[] = { | |
730 | &pci_grackle_writeb, | |
731 | &pci_grackle_writew, | |
732 | &pci_grackle_writel, | |
733 | }; | |
734 | ||
735 | static CPUReadMemoryFunc *pci_grackle_read[] = { | |
736 | &pci_grackle_readb, | |
737 | &pci_grackle_readw, | |
738 | &pci_grackle_readl, | |
739 | }; | |
740 | ||
741 | /* Uninorth PCI host (for all Mac99 and newer machines */ | |
742 | static void pci_unin_main_config_writel (void *opaque, target_phys_addr_t addr, | |
743 | uint32_t val) | |
744 | { | |
745 | PCIBridge *s = opaque; | |
746 | int i; | |
747 | ||
748 | #ifdef TARGET_WORDS_BIGENDIAN | |
749 | val = bswap32(val); | |
750 | #endif | |
751 | ||
752 | for (i = 11; i < 32; i++) { | |
753 | if ((val & (1 << i)) != 0) | |
754 | break; | |
755 | } | |
756 | #if 0 | |
757 | s->config_reg = 0x80000000 | (1 << 16) | (val & 0x7FC) | (i << 11); | |
758 | #else | |
759 | s->config_reg = 0x80000000 | (0 << 16) | (val & 0x7FC) | (i << 11); | |
760 | #endif | |
761 | } | |
762 | ||
763 | static uint32_t pci_unin_main_config_readl (void *opaque, | |
764 | target_phys_addr_t addr) | |
765 | { | |
766 | PCIBridge *s = opaque; | |
767 | uint32_t val; | |
768 | int devfn; | |
769 | ||
770 | devfn = (s->config_reg >> 8) & 0xFF; | |
771 | val = (1 << (devfn >> 3)) | ((devfn & 0x07) << 8) | (s->config_reg & 0xFC); | |
772 | #ifdef TARGET_WORDS_BIGENDIAN | |
773 | val = bswap32(val); | |
774 | #endif | |
775 | ||
776 | return val; | |
777 | } | |
778 | ||
779 | static CPUWriteMemoryFunc *pci_unin_main_config_write[] = { | |
780 | &pci_unin_main_config_writel, | |
781 | &pci_unin_main_config_writel, | |
782 | &pci_unin_main_config_writel, | |
783 | }; | |
784 | ||
785 | static CPUReadMemoryFunc *pci_unin_main_config_read[] = { | |
786 | &pci_unin_main_config_readl, | |
787 | &pci_unin_main_config_readl, | |
788 | &pci_unin_main_config_readl, | |
789 | }; | |
790 | ||
791 | static void pci_unin_main_writeb (void *opaque, target_phys_addr_t addr, | |
792 | uint32_t val) | |
793 | { | |
794 | PCIBridge *s = opaque; | |
795 | pci_data_write(s, addr & 7, val, 1); | |
796 | } | |
797 | ||
798 | static void pci_unin_main_writew (void *opaque, target_phys_addr_t addr, | |
799 | uint32_t val) | |
800 | { | |
801 | PCIBridge *s = opaque; | |
802 | #ifdef TARGET_WORDS_BIGENDIAN | |
803 | val = bswap16(val); | |
804 | #endif | |
805 | pci_data_write(s, addr & 7, val, 2); | |
806 | } | |
807 | ||
808 | static void pci_unin_main_writel (void *opaque, target_phys_addr_t addr, | |
809 | uint32_t val) | |
810 | { | |
811 | PCIBridge *s = opaque; | |
812 | #ifdef TARGET_WORDS_BIGENDIAN | |
813 | val = bswap32(val); | |
814 | #endif | |
815 | pci_data_write(s, addr & 7, val, 4); | |
816 | } | |
817 | ||
818 | static uint32_t pci_unin_main_readb (void *opaque, target_phys_addr_t addr) | |
819 | { | |
820 | PCIBridge *s = opaque; | |
821 | uint32_t val; | |
822 | ||
823 | val = pci_data_read(s, addr & 7, 1); | |
824 | ||
825 | return val; | |
826 | } | |
827 | ||
828 | static uint32_t pci_unin_main_readw (void *opaque, target_phys_addr_t addr) | |
829 | { | |
830 | PCIBridge *s = opaque; | |
831 | uint32_t val; | |
832 | ||
833 | val = pci_data_read(s, addr & 7, 2); | |
834 | #ifdef TARGET_WORDS_BIGENDIAN | |
835 | val = bswap16(val); | |
836 | #endif | |
837 | ||
838 | return val; | |
839 | } | |
840 | ||
841 | static uint32_t pci_unin_main_readl (void *opaque, target_phys_addr_t addr) | |
77d4bc34 | 842 | { |
8a8696a3 | 843 | PCIBridge *s = opaque; |
77d4bc34 FB |
844 | uint32_t val; |
845 | ||
846 | val = pci_data_read(s, addr, 4); | |
847 | #ifdef TARGET_WORDS_BIGENDIAN | |
848 | val = bswap32(val); | |
849 | #endif | |
f2aa58c6 FB |
850 | |
851 | return val; | |
852 | } | |
853 | ||
854 | static CPUWriteMemoryFunc *pci_unin_main_write[] = { | |
855 | &pci_unin_main_writeb, | |
856 | &pci_unin_main_writew, | |
857 | &pci_unin_main_writel, | |
858 | }; | |
859 | ||
860 | static CPUReadMemoryFunc *pci_unin_main_read[] = { | |
861 | &pci_unin_main_readb, | |
862 | &pci_unin_main_readw, | |
863 | &pci_unin_main_readl, | |
864 | }; | |
865 | ||
866 | static void pci_unin_config_writel (void *opaque, target_phys_addr_t addr, | |
867 | uint32_t val) | |
868 | { | |
869 | PCIBridge *s = opaque; | |
870 | ||
871 | #ifdef TARGET_WORDS_BIGENDIAN | |
872 | val = bswap32(val); | |
873 | #endif | |
874 | s->config_reg = 0x80000000 | (val & ~0x00000001); | |
875 | } | |
876 | ||
877 | static uint32_t pci_unin_config_readl (void *opaque, | |
878 | target_phys_addr_t addr) | |
879 | { | |
880 | PCIBridge *s = opaque; | |
881 | uint32_t val; | |
882 | ||
883 | val = (s->config_reg | 0x00000001) & ~0x80000000; | |
884 | #ifdef TARGET_WORDS_BIGENDIAN | |
885 | val = bswap32(val); | |
886 | #endif | |
887 | ||
888 | return val; | |
889 | } | |
890 | ||
891 | static CPUWriteMemoryFunc *pci_unin_config_write[] = { | |
892 | &pci_unin_config_writel, | |
893 | &pci_unin_config_writel, | |
894 | &pci_unin_config_writel, | |
895 | }; | |
896 | ||
897 | static CPUReadMemoryFunc *pci_unin_config_read[] = { | |
898 | &pci_unin_config_readl, | |
899 | &pci_unin_config_readl, | |
900 | &pci_unin_config_readl, | |
901 | }; | |
902 | ||
903 | static void pci_unin_writeb (void *opaque, target_phys_addr_t addr, | |
904 | uint32_t val) | |
905 | { | |
906 | PCIBridge *s = opaque; | |
907 | pci_data_write(s, addr & 3, val, 1); | |
908 | } | |
909 | ||
910 | static void pci_unin_writew (void *opaque, target_phys_addr_t addr, | |
911 | uint32_t val) | |
912 | { | |
913 | PCIBridge *s = opaque; | |
914 | #ifdef TARGET_WORDS_BIGENDIAN | |
915 | val = bswap16(val); | |
916 | #endif | |
917 | pci_data_write(s, addr & 3, val, 2); | |
918 | } | |
919 | ||
920 | static void pci_unin_writel (void *opaque, target_phys_addr_t addr, | |
921 | uint32_t val) | |
922 | { | |
923 | PCIBridge *s = opaque; | |
924 | #ifdef TARGET_WORDS_BIGENDIAN | |
925 | val = bswap32(val); | |
926 | #endif | |
927 | pci_data_write(s, addr & 3, val, 4); | |
928 | } | |
929 | ||
930 | static uint32_t pci_unin_readb (void *opaque, target_phys_addr_t addr) | |
931 | { | |
932 | PCIBridge *s = opaque; | |
933 | uint32_t val; | |
934 | ||
935 | val = pci_data_read(s, addr & 3, 1); | |
936 | ||
937 | return val; | |
938 | } | |
939 | ||
940 | static uint32_t pci_unin_readw (void *opaque, target_phys_addr_t addr) | |
941 | { | |
942 | PCIBridge *s = opaque; | |
943 | uint32_t val; | |
944 | ||
945 | val = pci_data_read(s, addr & 3, 2); | |
946 | #ifdef TARGET_WORDS_BIGENDIAN | |
947 | val = bswap16(val); | |
948 | #endif | |
949 | ||
950 | return val; | |
951 | } | |
952 | ||
953 | static uint32_t pci_unin_readl (void *opaque, target_phys_addr_t addr) | |
954 | { | |
955 | PCIBridge *s = opaque; | |
956 | uint32_t val; | |
957 | ||
958 | val = pci_data_read(s, addr & 3, 4); | |
959 | #ifdef TARGET_WORDS_BIGENDIAN | |
960 | val = bswap32(val); | |
961 | #endif | |
962 | ||
77d4bc34 FB |
963 | return val; |
964 | } | |
965 | ||
f2aa58c6 FB |
966 | static CPUWriteMemoryFunc *pci_unin_write[] = { |
967 | &pci_unin_writeb, | |
968 | &pci_unin_writew, | |
969 | &pci_unin_writel, | |
77d4bc34 FB |
970 | }; |
971 | ||
f2aa58c6 FB |
972 | static CPUReadMemoryFunc *pci_unin_read[] = { |
973 | &pci_unin_readb, | |
974 | &pci_unin_readw, | |
975 | &pci_unin_readl, | |
77d4bc34 FB |
976 | }; |
977 | ||
978 | void pci_pmac_init(void) | |
979 | { | |
f2aa58c6 | 980 | PCIBridge *s; |
77d4bc34 FB |
981 | PCIDevice *d; |
982 | int pci_mem_config, pci_mem_data; | |
983 | ||
f2aa58c6 FB |
984 | /* Use values found on a real PowerMac */ |
985 | /* Uninorth main bus */ | |
986 | s = &pci_bridge[0]; | |
987 | pci_mem_config = cpu_register_io_memory(0, pci_unin_main_config_read, | |
988 | pci_unin_main_config_write, s); | |
989 | pci_mem_data = cpu_register_io_memory(0, pci_unin_main_read, | |
990 | pci_unin_main_write, s); | |
991 | cpu_register_physical_memory(0xf2800000, 0x1000, pci_mem_config); | |
992 | cpu_register_physical_memory(0xf2c00000, 0x1000, pci_mem_data); | |
993 | ||
994 | d = pci_register_device("Uni-north main", sizeof(PCIDevice), 0, 11 << 3, | |
77d4bc34 | 995 | NULL, NULL); |
f2aa58c6 FB |
996 | d->config[0x00] = 0x6b; // vendor_id : Apple |
997 | d->config[0x01] = 0x10; | |
998 | d->config[0x02] = 0x1F; // device_id | |
999 | d->config[0x03] = 0x00; | |
1000 | d->config[0x08] = 0x00; // revision | |
1001 | d->config[0x0A] = 0x00; // class_sub = pci host | |
1002 | d->config[0x0B] = 0x06; // class_base = PCI_bridge | |
1003 | d->config[0x0C] = 0x08; // cache_line_size | |
1004 | d->config[0x0D] = 0x10; // latency_timer | |
1005 | d->config[0x0E] = 0x00; // header_type | |
1006 | d->config[0x34] = 0x00; // capabilities_pointer | |
1007 | ||
1008 | #if 0 // XXX: not activated as PPC BIOS doesn't handle mutiple buses properly | |
1009 | /* pci-to-pci bridge */ | |
1010 | d = pci_register_device("Uni-north bridge", sizeof(PCIDevice), 0, 13 << 3, | |
1011 | NULL, NULL); | |
1012 | d->config[0x00] = 0x11; // vendor_id : TI | |
1013 | d->config[0x01] = 0x10; | |
1014 | d->config[0x02] = 0x26; // device_id | |
1015 | d->config[0x03] = 0x00; | |
1016 | d->config[0x08] = 0x05; // revision | |
1017 | d->config[0x0A] = 0x04; // class_sub = pci2pci | |
1018 | d->config[0x0B] = 0x06; // class_base = PCI_bridge | |
1019 | d->config[0x0C] = 0x08; // cache_line_size | |
1020 | d->config[0x0D] = 0x20; // latency_timer | |
1021 | d->config[0x0E] = 0x01; // header_type | |
1022 | ||
1023 | d->config[0x18] = 0x01; // primary_bus | |
1024 | d->config[0x19] = 0x02; // secondary_bus | |
1025 | d->config[0x1A] = 0x02; // subordinate_bus | |
1026 | d->config[0x1B] = 0x20; // secondary_latency_timer | |
1027 | d->config[0x1C] = 0x11; // io_base | |
1028 | d->config[0x1D] = 0x01; // io_limit | |
1029 | d->config[0x20] = 0x00; // memory_base | |
1030 | d->config[0x21] = 0x80; | |
1031 | d->config[0x22] = 0x00; // memory_limit | |
1032 | d->config[0x23] = 0x80; | |
1033 | d->config[0x24] = 0x01; // prefetchable_memory_base | |
1034 | d->config[0x25] = 0x80; | |
1035 | d->config[0x26] = 0xF1; // prefectchable_memory_limit | |
1036 | d->config[0x27] = 0x7F; | |
1037 | // d->config[0x34] = 0xdc // capabilities_pointer | |
1038 | #endif | |
1039 | #if 0 // XXX: not needed for now | |
1040 | /* Uninorth AGP bus */ | |
1041 | s = &pci_bridge[1]; | |
1042 | pci_mem_config = cpu_register_io_memory(0, pci_unin_config_read, | |
1043 | pci_unin_config_write, s); | |
1044 | pci_mem_data = cpu_register_io_memory(0, pci_unin_read, | |
1045 | pci_unin_write, s); | |
1046 | cpu_register_physical_memory(0xf0800000, 0x1000, pci_mem_config); | |
1047 | cpu_register_physical_memory(0xf0c00000, 0x1000, pci_mem_data); | |
1048 | ||
1049 | d = pci_register_device("Uni-north AGP", sizeof(PCIDevice), 0, 11 << 3, | |
1050 | NULL, NULL); | |
1051 | d->config[0x00] = 0x6b; // vendor_id : Apple | |
1052 | d->config[0x01] = 0x10; | |
1053 | d->config[0x02] = 0x20; // device_id | |
1054 | d->config[0x03] = 0x00; | |
1055 | d->config[0x08] = 0x00; // revision | |
1056 | d->config[0x0A] = 0x00; // class_sub = pci host | |
1057 | d->config[0x0B] = 0x06; // class_base = PCI_bridge | |
1058 | d->config[0x0C] = 0x08; // cache_line_size | |
1059 | d->config[0x0D] = 0x10; // latency_timer | |
1060 | d->config[0x0E] = 0x00; // header_type | |
1061 | // d->config[0x34] = 0x80; // capabilities_pointer | |
1062 | #endif | |
77d4bc34 | 1063 | |
f2aa58c6 FB |
1064 | #if 0 // XXX: not needed for now |
1065 | /* Uninorth internal bus */ | |
1066 | s = &pci_bridge[2]; | |
1067 | pci_mem_config = cpu_register_io_memory(0, pci_unin_config_read, | |
1068 | pci_unin_config_write, s); | |
1069 | pci_mem_data = cpu_register_io_memory(0, pci_unin_read, | |
1070 | pci_unin_write, s); | |
1071 | cpu_register_physical_memory(0xf4800000, 0x1000, pci_mem_config); | |
1072 | cpu_register_physical_memory(0xf4c00000, 0x1000, pci_mem_data); | |
1073 | ||
1074 | d = pci_register_device("Uni-north internal", sizeof(PCIDevice), | |
1075 | 3, 11 << 3, NULL, NULL); | |
1076 | d->config[0x00] = 0x6b; // vendor_id : Apple | |
1077 | d->config[0x01] = 0x10; | |
1078 | d->config[0x02] = 0x1E; // device_id | |
1079 | d->config[0x03] = 0x00; | |
1080 | d->config[0x08] = 0x00; // revision | |
1081 | d->config[0x0A] = 0x00; // class_sub = pci host | |
1082 | d->config[0x0B] = 0x06; // class_base = PCI_bridge | |
1083 | d->config[0x0C] = 0x08; // cache_line_size | |
1084 | d->config[0x0D] = 0x10; // latency_timer | |
1085 | d->config[0x0E] = 0x00; // header_type | |
1086 | d->config[0x34] = 0x00; // capabilities_pointer | |
1087 | #endif | |
1088 | ||
1089 | #if 0 // Grackle ? | |
77d4bc34 FB |
1090 | /* same values as PearPC - check this */ |
1091 | d->config[0x00] = 0x11; // vendor_id | |
1092 | d->config[0x01] = 0x10; | |
1093 | d->config[0x02] = 0x26; // device_id | |
1094 | d->config[0x03] = 0x00; | |
1095 | d->config[0x08] = 0x02; // revision | |
1096 | d->config[0x0a] = 0x04; // class_sub = pci2pci | |
1097 | d->config[0x0b] = 0x06; // class_base = PCI_bridge | |
1098 | d->config[0x0e] = 0x01; // header_type | |
1099 | ||
1100 | d->config[0x18] = 0x0; // primary_bus | |
1101 | d->config[0x19] = 0x1; // secondary_bus | |
1102 | d->config[0x1a] = 0x1; // subordinate_bus | |
1103 | d->config[0x1c] = 0x10; // io_base | |
1104 | d->config[0x1d] = 0x20; // io_limit | |
1105 | ||
1106 | d->config[0x20] = 0x80; // memory_base | |
1107 | d->config[0x21] = 0x80; | |
1108 | d->config[0x22] = 0x90; // memory_limit | |
1109 | d->config[0x23] = 0x80; | |
1110 | ||
1111 | d->config[0x24] = 0x00; // prefetchable_memory_base | |
1112 | d->config[0x25] = 0x84; | |
1113 | d->config[0x26] = 0x00; // prefetchable_memory_limit | |
1114 | d->config[0x27] = 0x85; | |
f2aa58c6 | 1115 | #endif |
77d4bc34 FB |
1116 | } |
1117 | ||
0ac32c83 FB |
1118 | /***********************************************************/ |
1119 | /* generic PCI irq support */ | |
1120 | ||
1121 | /* return the global irq number corresponding to a given device irq | |
1122 | pin. We could also use the bus number to have a more precise | |
1123 | mapping. */ | |
1124 | static inline int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num) | |
1125 | { | |
1126 | int slot_addend; | |
1127 | slot_addend = (pci_dev->devfn >> 3); | |
1128 | return (irq_num + slot_addend) & 3; | |
1129 | } | |
1130 | ||
1131 | /* 0 <= irq_num <= 3. level must be 0 or 1 */ | |
77d4bc34 FB |
1132 | #ifdef TARGET_PPC |
1133 | void pci_set_irq(PCIDevice *pci_dev, int irq_num, int level) | |
1134 | { | |
1135 | } | |
1136 | #else | |
0ac32c83 FB |
1137 | void pci_set_irq(PCIDevice *pci_dev, int irq_num, int level) |
1138 | { | |
1139 | int irq_index, shift, pic_irq, pic_level; | |
1140 | uint32_t *p; | |
1141 | ||
1142 | irq_num = pci_slot_get_pirq(pci_dev, irq_num); | |
1143 | irq_index = pci_dev->irq_index; | |
1144 | p = &pci_irq_levels[irq_num][irq_index >> 5]; | |
1145 | shift = (irq_index & 0x1f); | |
1146 | *p = (*p & ~(1 << shift)) | (level << shift); | |
1147 | ||
1148 | /* now we change the pic irq level according to the piix irq mappings */ | |
1149 | pic_irq = piix3_state->dev.config[0x60 + irq_num]; | |
1150 | if (pic_irq < 16) { | |
1151 | /* the pic level is the logical OR of all the PCI irqs mapped | |
1152 | to it */ | |
1153 | pic_level = 0; | |
1154 | #if (PCI_IRQ_WORDS == 2) | |
1155 | pic_level = ((pci_irq_levels[irq_num][0] | | |
1156 | pci_irq_levels[irq_num][1]) != 0); | |
1157 | #else | |
1158 | { | |
1159 | int i; | |
1160 | pic_level = 0; | |
1161 | for(i = 0; i < PCI_IRQ_WORDS; i++) { | |
1162 | if (pci_irq_levels[irq_num][i]) { | |
1163 | pic_level = 1; | |
1164 | break; | |
1165 | } | |
1166 | } | |
1167 | } | |
1168 | #endif | |
1169 | pic_set_irq(pic_irq, pic_level); | |
1170 | } | |
1171 | } | |
77d4bc34 | 1172 | #endif |
0ac32c83 FB |
1173 | |
1174 | /***********************************************************/ | |
1175 | /* monitor info on PCI */ | |
1176 | ||
1177 | static void pci_info_device(PCIDevice *d) | |
1178 | { | |
1179 | int i, class; | |
1180 | PCIIORegion *r; | |
1181 | ||
1182 | printf(" Bus %2d, device %3d, function %d:\n", | |
1183 | d->bus_num, d->devfn >> 3, d->devfn & 7); | |
1184 | class = le16_to_cpu(*((uint16_t *)(d->config + PCI_CLASS_DEVICE))); | |
1185 | printf(" "); | |
1186 | switch(class) { | |
1187 | case 0x0101: | |
1188 | printf("IDE controller"); | |
1189 | break; | |
1190 | case 0x0200: | |
1191 | printf("Ethernet controller"); | |
1192 | break; | |
1193 | case 0x0300: | |
1194 | printf("VGA controller"); | |
1195 | break; | |
1196 | default: | |
1197 | printf("Class %04x", class); | |
1198 | break; | |
1199 | } | |
1200 | printf(": PCI device %04x:%04x\n", | |
1201 | le16_to_cpu(*((uint16_t *)(d->config + PCI_VENDOR_ID))), | |
1202 | le16_to_cpu(*((uint16_t *)(d->config + PCI_DEVICE_ID)))); | |
1203 | ||
1204 | if (d->config[PCI_INTERRUPT_PIN] != 0) { | |
1205 | printf(" IRQ %d.\n", d->config[PCI_INTERRUPT_LINE]); | |
1206 | } | |
8a8696a3 | 1207 | for(i = 0;i < PCI_NUM_REGIONS; i++) { |
0ac32c83 FB |
1208 | r = &d->io_regions[i]; |
1209 | if (r->size != 0) { | |
1210 | printf(" BAR%d: ", i); | |
1211 | if (r->type & PCI_ADDRESS_SPACE_IO) { | |
1212 | printf("I/O at 0x%04x [0x%04x].\n", | |
1213 | r->addr, r->addr + r->size - 1); | |
1214 | } else { | |
1215 | printf("32 bit memory at 0x%08x [0x%08x].\n", | |
1216 | r->addr, r->addr + r->size - 1); | |
1217 | } | |
1218 | } | |
1219 | } | |
1220 | } | |
1221 | ||
1222 | void pci_info(void) | |
1223 | { | |
f2aa58c6 | 1224 | PCIBridge *s = &pci_bridge[0]; |
0ac32c83 FB |
1225 | PCIDevice **bus; |
1226 | int bus_num, devfn; | |
1227 | ||
1228 | for(bus_num = 0; bus_num < 256; bus_num++) { | |
1229 | bus = s->pci_bus[bus_num]; | |
1230 | if (bus) { | |
1231 | for(devfn = 0; devfn < 256; devfn++) { | |
1232 | if (bus[devfn]) | |
1233 | pci_info_device(bus[devfn]); | |
1234 | } | |
1235 | } | |
1236 | } | |
1237 | } | |
1238 | ||
1239 | /***********************************************************/ | |
1240 | /* XXX: the following should be moved to the PC BIOS */ | |
1241 | ||
1242 | static uint32_t isa_inb(uint32_t addr) | |
1243 | { | |
1244 | return cpu_inb(cpu_single_env, addr); | |
1245 | } | |
1246 | ||
1247 | static void isa_outb(uint32_t val, uint32_t addr) | |
1248 | { | |
1249 | cpu_outb(cpu_single_env, addr, val); | |
1250 | } | |
1251 | ||
1252 | static uint32_t isa_inw(uint32_t addr) | |
1253 | { | |
1254 | return cpu_inw(cpu_single_env, addr); | |
1255 | } | |
1256 | ||
1257 | static void isa_outw(uint32_t val, uint32_t addr) | |
1258 | { | |
1259 | cpu_outw(cpu_single_env, addr, val); | |
1260 | } | |
1261 | ||
1262 | static uint32_t isa_inl(uint32_t addr) | |
1263 | { | |
1264 | return cpu_inl(cpu_single_env, addr); | |
1265 | } | |
1266 | ||
1267 | static void isa_outl(uint32_t val, uint32_t addr) | |
1268 | { | |
1269 | cpu_outl(cpu_single_env, addr, val); | |
1270 | } | |
1271 | ||
1272 | static void pci_config_writel(PCIDevice *d, uint32_t addr, uint32_t val) | |
1273 | { | |
f2aa58c6 | 1274 | PCIBridge *s = &pci_bridge[0]; |
0ac32c83 FB |
1275 | s->config_reg = 0x80000000 | (d->bus_num << 16) | |
1276 | (d->devfn << 8) | addr; | |
1277 | pci_data_write(s, 0, val, 4); | |
1278 | } | |
1279 | ||
1280 | static void pci_config_writew(PCIDevice *d, uint32_t addr, uint32_t val) | |
1281 | { | |
f2aa58c6 | 1282 | PCIBridge *s = &pci_bridge[0]; |
0ac32c83 FB |
1283 | s->config_reg = 0x80000000 | (d->bus_num << 16) | |
1284 | (d->devfn << 8) | (addr & ~3); | |
1285 | pci_data_write(s, addr & 3, val, 2); | |
1286 | } | |
1287 | ||
1288 | static void pci_config_writeb(PCIDevice *d, uint32_t addr, uint32_t val) | |
1289 | { | |
f2aa58c6 | 1290 | PCIBridge *s = &pci_bridge[0]; |
0ac32c83 FB |
1291 | s->config_reg = 0x80000000 | (d->bus_num << 16) | |
1292 | (d->devfn << 8) | (addr & ~3); | |
1293 | pci_data_write(s, addr & 3, val, 1); | |
1294 | } | |
1295 | ||
1296 | static uint32_t pci_config_readl(PCIDevice *d, uint32_t addr) | |
1297 | { | |
f2aa58c6 | 1298 | PCIBridge *s = &pci_bridge[0]; |
0ac32c83 FB |
1299 | s->config_reg = 0x80000000 | (d->bus_num << 16) | |
1300 | (d->devfn << 8) | addr; | |
1301 | return pci_data_read(s, 0, 4); | |
1302 | } | |
1303 | ||
1304 | static uint32_t pci_config_readw(PCIDevice *d, uint32_t addr) | |
1305 | { | |
f2aa58c6 | 1306 | PCIBridge *s = &pci_bridge[0]; |
0ac32c83 FB |
1307 | s->config_reg = 0x80000000 | (d->bus_num << 16) | |
1308 | (d->devfn << 8) | (addr & ~3); | |
1309 | return pci_data_read(s, addr & 3, 2); | |
1310 | } | |
1311 | ||
1312 | static uint32_t pci_config_readb(PCIDevice *d, uint32_t addr) | |
1313 | { | |
f2aa58c6 | 1314 | PCIBridge *s = &pci_bridge[0]; |
0ac32c83 FB |
1315 | s->config_reg = 0x80000000 | (d->bus_num << 16) | |
1316 | (d->devfn << 8) | (addr & ~3); | |
1317 | return pci_data_read(s, addr & 3, 1); | |
1318 | } | |
69b91039 FB |
1319 | |
1320 | static uint32_t pci_bios_io_addr; | |
1321 | static uint32_t pci_bios_mem_addr; | |
0ac32c83 FB |
1322 | /* host irqs corresponding to PCI irqs A-D */ |
1323 | static uint8_t pci_irqs[4] = { 11, 9, 11, 9 }; | |
69b91039 FB |
1324 | |
1325 | static void pci_set_io_region_addr(PCIDevice *d, int region_num, uint32_t addr) | |
1326 | { | |
69b91039 | 1327 | PCIIORegion *r; |
0ac32c83 | 1328 | uint16_t cmd; |
8a8696a3 FB |
1329 | uint32_t ofs; |
1330 | ||
1331 | if ( region_num == PCI_ROM_SLOT ) { | |
1332 | ofs = 0x30; | |
1333 | }else{ | |
1334 | ofs = 0x10 + region_num * 4; | |
1335 | } | |
69b91039 | 1336 | |
8a8696a3 | 1337 | pci_config_writel(d, ofs, addr); |
69b91039 FB |
1338 | r = &d->io_regions[region_num]; |
1339 | ||
1340 | /* enable memory mappings */ | |
0ac32c83 | 1341 | cmd = pci_config_readw(d, PCI_COMMAND); |
8a8696a3 FB |
1342 | if ( region_num == PCI_ROM_SLOT ) |
1343 | cmd |= 2; | |
1344 | else if (r->type & PCI_ADDRESS_SPACE_IO) | |
0ac32c83 | 1345 | cmd |= 1; |
69b91039 | 1346 | else |
0ac32c83 FB |
1347 | cmd |= 2; |
1348 | pci_config_writew(d, PCI_COMMAND, cmd); | |
69b91039 FB |
1349 | } |
1350 | ||
69b91039 FB |
1351 | static void pci_bios_init_device(PCIDevice *d) |
1352 | { | |
1353 | int class; | |
1354 | PCIIORegion *r; | |
1355 | uint32_t *paddr; | |
63ce9e0a | 1356 | int i, pin, pic_irq, vendor_id, device_id; |
69b91039 | 1357 | |
63ce9e0a | 1358 | class = pci_config_readw(d, PCI_CLASS_DEVICE); |
1f62d938 FB |
1359 | vendor_id = pci_config_readw(d, PCI_VENDOR_ID); |
1360 | device_id = pci_config_readw(d, PCI_DEVICE_ID); | |
69b91039 FB |
1361 | switch(class) { |
1362 | case 0x0101: | |
63ce9e0a FB |
1363 | if (vendor_id == 0x8086 && device_id == 0x7010) { |
1364 | /* PIIX3 IDE */ | |
1365 | pci_config_writew(d, PCI_COMMAND, PCI_COMMAND_IO); | |
1366 | pci_config_writew(d, 0x40, 0x8000); // enable IDE0 | |
7f647cf6 | 1367 | pci_config_writew(d, 0x42, 0x8000); // enable IDE1 |
63ce9e0a FB |
1368 | } else { |
1369 | /* IDE: we map it as in ISA mode */ | |
1370 | pci_set_io_region_addr(d, 0, 0x1f0); | |
1371 | pci_set_io_region_addr(d, 1, 0x3f4); | |
1372 | pci_set_io_region_addr(d, 2, 0x170); | |
1373 | pci_set_io_region_addr(d, 3, 0x374); | |
1374 | } | |
69b91039 | 1375 | break; |
0ac32c83 | 1376 | case 0x0300: |
4c7634bc FB |
1377 | if (vendor_id != 0x1234) |
1378 | goto default_map; | |
0ac32c83 FB |
1379 | /* VGA: map frame buffer to default Bochs VBE address */ |
1380 | pci_set_io_region_addr(d, 0, 0xE0000000); | |
1381 | break; | |
f2aa58c6 FB |
1382 | case 0x0800: |
1383 | /* PIC */ | |
1384 | vendor_id = pci_config_readw(d, PCI_VENDOR_ID); | |
1385 | device_id = pci_config_readw(d, PCI_DEVICE_ID); | |
1386 | if (vendor_id == 0x1014) { | |
1387 | /* IBM */ | |
1388 | if (device_id == 0x0046 || device_id == 0xFFFF) { | |
1389 | /* MPIC & MPIC2 */ | |
1390 | pci_set_io_region_addr(d, 0, 0x80800000 + 0x00040000); | |
1391 | } | |
1392 | } | |
1393 | break; | |
1f62d938 | 1394 | case 0xff00: |
f2aa58c6 FB |
1395 | if (vendor_id == 0x0106b && |
1396 | (device_id == 0x0017 || device_id == 0x0022)) { | |
1f62d938 FB |
1397 | /* macio bridge */ |
1398 | pci_set_io_region_addr(d, 0, 0x80800000); | |
1399 | } | |
1400 | break; | |
69b91039 | 1401 | default: |
4c7634bc | 1402 | default_map: |
69b91039 | 1403 | /* default memory mappings */ |
8a8696a3 | 1404 | for(i = 0; i < PCI_NUM_REGIONS; i++) { |
69b91039 FB |
1405 | r = &d->io_regions[i]; |
1406 | if (r->size) { | |
1407 | if (r->type & PCI_ADDRESS_SPACE_IO) | |
1408 | paddr = &pci_bios_io_addr; | |
1409 | else | |
1410 | paddr = &pci_bios_mem_addr; | |
1411 | *paddr = (*paddr + r->size - 1) & ~(r->size - 1); | |
1412 | pci_set_io_region_addr(d, i, *paddr); | |
1413 | *paddr += r->size; | |
1414 | } | |
1415 | } | |
1416 | break; | |
1417 | } | |
0ac32c83 FB |
1418 | |
1419 | /* map the interrupt */ | |
1420 | pin = pci_config_readb(d, PCI_INTERRUPT_PIN); | |
1421 | if (pin != 0) { | |
1422 | pin = pci_slot_get_pirq(d, pin - 1); | |
1423 | pic_irq = pci_irqs[pin]; | |
1424 | pci_config_writeb(d, PCI_INTERRUPT_LINE, pic_irq); | |
1425 | } | |
69b91039 FB |
1426 | } |
1427 | ||
1428 | /* | |
1429 | * This function initializes the PCI devices as a normal PCI BIOS | |
1430 | * would do. It is provided just in case the BIOS has no support for | |
1431 | * PCI. | |
1432 | */ | |
1433 | void pci_bios_init(void) | |
1434 | { | |
f2aa58c6 | 1435 | PCIBridge *s = &pci_bridge[0]; |
69b91039 | 1436 | PCIDevice **bus; |
0ac32c83 FB |
1437 | int bus_num, devfn, i, irq; |
1438 | uint8_t elcr[2]; | |
69b91039 FB |
1439 | |
1440 | pci_bios_io_addr = 0xc000; | |
1441 | pci_bios_mem_addr = 0xf0000000; | |
1442 | ||
0ac32c83 FB |
1443 | /* activate IRQ mappings */ |
1444 | elcr[0] = 0x00; | |
1445 | elcr[1] = 0x00; | |
1446 | for(i = 0; i < 4; i++) { | |
1447 | irq = pci_irqs[i]; | |
1448 | /* set to trigger level */ | |
1449 | elcr[irq >> 3] |= (1 << (irq & 7)); | |
1450 | /* activate irq remapping in PIIX */ | |
1451 | pci_config_writeb((PCIDevice *)piix3_state, 0x60 + i, irq); | |
1452 | } | |
1453 | isa_outb(elcr[0], 0x4d0); | |
1454 | isa_outb(elcr[1], 0x4d1); | |
1455 | ||
69b91039 FB |
1456 | for(bus_num = 0; bus_num < 256; bus_num++) { |
1457 | bus = s->pci_bus[bus_num]; | |
1458 | if (bus) { | |
1459 | for(devfn = 0; devfn < 256; devfn++) { | |
1460 | if (bus[devfn]) | |
1461 | pci_bios_init_device(bus[devfn]); | |
1462 | } | |
1463 | } | |
1464 | } | |
1465 | } | |
77d4bc34 FB |
1466 | |
1467 | /* | |
1468 | * This function initializes the PCI devices as a normal PCI BIOS | |
1469 | * would do. It is provided just in case the BIOS has no support for | |
1470 | * PCI. | |
1471 | */ | |
1472 | void pci_ppc_bios_init(void) | |
1473 | { | |
f2aa58c6 | 1474 | PCIBridge *s = &pci_bridge[0]; |
77d4bc34 | 1475 | PCIDevice **bus; |
f2aa58c6 FB |
1476 | int bus_num, devfn; |
1477 | #if 0 | |
1478 | int i, irq; | |
77d4bc34 | 1479 | uint8_t elcr[2]; |
f2aa58c6 | 1480 | #endif |
77d4bc34 FB |
1481 | |
1482 | pci_bios_io_addr = 0xc000; | |
1483 | pci_bios_mem_addr = 0xc0000000; | |
1484 | ||
1485 | #if 0 | |
1486 | /* activate IRQ mappings */ | |
1487 | elcr[0] = 0x00; | |
1488 | elcr[1] = 0x00; | |
1489 | for(i = 0; i < 4; i++) { | |
1490 | irq = pci_irqs[i]; | |
1491 | /* set to trigger level */ | |
1492 | elcr[irq >> 3] |= (1 << (irq & 7)); | |
1493 | /* activate irq remapping in PIIX */ | |
1494 | pci_config_writeb((PCIDevice *)piix3_state, 0x60 + i, irq); | |
1495 | } | |
1496 | isa_outb(elcr[0], 0x4d0); | |
1497 | isa_outb(elcr[1], 0x4d1); | |
1498 | #endif | |
1499 | ||
1500 | for(bus_num = 0; bus_num < 256; bus_num++) { | |
1501 | bus = s->pci_bus[bus_num]; | |
1502 | if (bus) { | |
1503 | for(devfn = 0; devfn < 256; devfn++) { | |
1504 | if (bus[devfn]) | |
1505 | pci_bios_init_device(bus[devfn]); | |
1506 | } | |
1507 | } | |
1508 | } | |
1509 | } |