adir_pci.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. /*
  2. * arch/ppc/platforms/adir_pci.c
  3. *
  4. * PCI support for SBS Adirondack
  5. *
  6. * By Michael Sokolov <msokolov@ivan.Harhan.ORG>
  7. * based on the K2 version by Matt Porter <mporter@mvista.com>
  8. */
  9. #include <linux/kernel.h>
  10. #include <linux/init.h>
  11. #include <linux/pci.h>
  12. #include <linux/slab.h>
  13. #include <asm/byteorder.h>
  14. #include <asm/io.h>
  15. #include <asm/uaccess.h>
  16. #include <asm/machdep.h>
  17. #include <asm/pci-bridge.h>
  18. #include <syslib/cpc710.h>
  19. #include "adir.h"
  20. #undef DEBUG
  21. #ifdef DEBUG
  22. #define DBG(x...) printk(x)
  23. #else
  24. #define DBG(x...)
  25. #endif /* DEBUG */
  26. static inline int __init
  27. adir_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
  28. {
  29. #define PCIIRQ(a,b,c,d) {ADIR_IRQ_##a,ADIR_IRQ_##b,ADIR_IRQ_##c,ADIR_IRQ_##d},
  30. struct pci_controller *hose = pci_bus_to_hose(dev->bus->number);
  31. /*
  32. * The three PCI devices on the motherboard have dedicated lines to the
  33. * CPLD interrupt controller, bypassing the standard PCI INTA-D and the
  34. * PC interrupt controller. All other PCI devices (slots) have usual
  35. * staggered INTA-D lines, resulting in 8 lines total (PCI0 INTA-D and
  36. * PCI1 INTA-D). All 8 go to the CPLD interrupt controller. PCI0 INTA-D
  37. * also go to the south bridge, so we have the option of taking them
  38. * via the CPLD interrupt controller or via the south bridge 8259
  39. * 8258 thingy. PCI1 INTA-D can only be taken via the CPLD interrupt
  40. * controller. We take all PCI interrupts via the CPLD interrupt
  41. * controller as recommended by SBS.
  42. *
  43. * We also have some monkey business with the PCI devices within the
  44. * VT82C686B south bridge itself. This chip actually has 7 functions on
  45. * its IDSEL. Function 0 is the actual south bridge, function 1 is IDE,
  46. * and function 4 is some special stuff. The other 4 functions are just
  47. * regular PCI devices bundled in the chip. 2 and 3 are USB UHCIs and 5
  48. * and 6 are audio (not supported on the Adirondack).
  49. *
  50. * This is where the monkey business begins. PCI devices are supposed
  51. * to signal normal PCI interrupts. But the 4 functions in question are
  52. * located in the south bridge chip, which is designed with the
  53. * assumption that it will be fielding PCI INTA-D interrupts rather
  54. * than generating them. Here's what it does. Each of the functions in
  55. * question routes its interrupt to one of the IRQs on the 8259 thingy.
  56. * Which one? It looks at the Interrupt Line register in the PCI config
  57. * space, even though the PCI spec says it's for BIOS/OS interaction
  58. * only.
  59. *
  60. * How do we deal with this? We take these interrupts via 8259 IRQs as
  61. * we have to. We return the desired IRQ numbers from this routine when
  62. * called for the functions in question. The PCI scan code will then
  63. * stick our return value into the Interrupt Line register in the PCI
  64. * config space, and the interrupt will actually go there. We identify
  65. * these functions within the south bridge IDSEL by their interrupt pin
  66. * numbers, as the VT82C686B has 04 in the Interrupt Pin register for
  67. * USB and 03 for audio.
  68. */
  69. if (!hose->index) {
  70. static char pci_irq_table[][4] =
  71. /*
  72. * PCI IDSEL/INTPIN->INTLINE
  73. * A B C D
  74. */
  75. {
  76. /* south bridge */ PCIIRQ(IDE0, NONE, VIA_AUDIO, VIA_USB)
  77. /* Ethernet 0 */ PCIIRQ(MBETH0, MBETH0, MBETH0, MBETH0)
  78. /* PCI0 slot 1 */ PCIIRQ(PCI0_INTB, PCI0_INTC, PCI0_INTD, PCI0_INTA)
  79. /* PCI0 slot 2 */ PCIIRQ(PCI0_INTC, PCI0_INTD, PCI0_INTA, PCI0_INTB)
  80. /* PCI0 slot 3 */ PCIIRQ(PCI0_INTD, PCI0_INTA, PCI0_INTB, PCI0_INTC)
  81. };
  82. const long min_idsel = 3, max_idsel = 7, irqs_per_slot = 4;
  83. return PCI_IRQ_TABLE_LOOKUP;
  84. } else {
  85. static char pci_irq_table[][4] =
  86. /*
  87. * PCI IDSEL/INTPIN->INTLINE
  88. * A B C D
  89. */
  90. {
  91. /* Ethernet 1 */ PCIIRQ(MBETH1, MBETH1, MBETH1, MBETH1)
  92. /* SCSI */ PCIIRQ(MBSCSI, MBSCSI, MBSCSI, MBSCSI)
  93. /* PCI1 slot 1 */ PCIIRQ(PCI1_INTB, PCI1_INTC, PCI1_INTD, PCI1_INTA)
  94. /* PCI1 slot 2 */ PCIIRQ(PCI1_INTC, PCI1_INTD, PCI1_INTA, PCI1_INTB)
  95. /* PCI1 slot 3 */ PCIIRQ(PCI1_INTD, PCI1_INTA, PCI1_INTB, PCI1_INTC)
  96. };
  97. const long min_idsel = 3, max_idsel = 7, irqs_per_slot = 4;
  98. return PCI_IRQ_TABLE_LOOKUP;
  99. }
  100. #undef PCIIRQ
  101. }
  102. static void
  103. adir_pcibios_fixup_resources(struct pci_dev *dev)
  104. {
  105. int i;
  106. if ((dev->vendor == PCI_VENDOR_ID_IBM) &&
  107. (dev->device == PCI_DEVICE_ID_IBM_CPC710_PCI64))
  108. {
  109. DBG("Fixup CPC710 resources\n");
  110. for (i=0; i<DEVICE_COUNT_RESOURCE; i++)
  111. {
  112. dev->resource[i].start = 0;
  113. dev->resource[i].end = 0;
  114. }
  115. }
  116. }
  117. /*
  118. * CPC710 DD3 has an errata causing it to hang the system if a type 0 config
  119. * cycle is attempted on its PCI32 interface with a device number > 21.
  120. * CPC710's PCI bridges map device numbers 1 through 21 to AD11 through AD31.
  121. * Per the PCI spec it MUST accept all other device numbers and do nothing, and
  122. * software MUST scan all device numbers without assuming how IDSELs are
  123. * mapped. However, as the CPC710 DD3's errata causes such correct scanning
  124. * procedure to hang the system, we have no choice but to introduce this hack
  125. * of knowingly avoiding device numbers > 21 on PCI0,
  126. */
  127. static int
  128. adir_exclude_device(u_char bus, u_char devfn)
  129. {
  130. if ((bus == 0) && (PCI_SLOT(devfn) > 21))
  131. return PCIBIOS_DEVICE_NOT_FOUND;
  132. else
  133. return PCIBIOS_SUCCESSFUL;
  134. }
  135. void adir_find_bridges(void)
  136. {
  137. struct pci_controller *hose_a, *hose_b;
  138. /* Setup PCI32 hose */
  139. hose_a = pcibios_alloc_controller();
  140. if (!hose_a)
  141. return;
  142. hose_a->first_busno = 0;
  143. hose_a->last_busno = 0xff;
  144. hose_a->pci_mem_offset = ADIR_PCI32_MEM_BASE;
  145. hose_a->io_space.start = 0;
  146. hose_a->io_space.end = ADIR_PCI32_VIRT_IO_SIZE - 1;
  147. hose_a->mem_space.start = 0;
  148. hose_a->mem_space.end = ADIR_PCI32_MEM_SIZE - 1;
  149. hose_a->io_resource.start = 0;
  150. hose_a->io_resource.end = ADIR_PCI32_VIRT_IO_SIZE - 1;
  151. hose_a->io_resource.flags = IORESOURCE_IO;
  152. hose_a->mem_resources[0].start = ADIR_PCI32_MEM_BASE;
  153. hose_a->mem_resources[0].end = ADIR_PCI32_MEM_BASE +
  154. ADIR_PCI32_MEM_SIZE - 1;
  155. hose_a->mem_resources[0].flags = IORESOURCE_MEM;
  156. hose_a->io_base_phys = ADIR_PCI32_IO_BASE;
  157. hose_a->io_base_virt = (void *) ADIR_PCI32_VIRT_IO_BASE;
  158. ppc_md.pci_exclude_device = adir_exclude_device;
  159. setup_indirect_pci(hose_a, ADIR_PCI32_CONFIG_ADDR,
  160. ADIR_PCI32_CONFIG_DATA);
  161. /* Initialize PCI32 bus registers */
  162. early_write_config_byte(hose_a,
  163. hose_a->first_busno,
  164. PCI_DEVFN(0, 0),
  165. CPC710_BUS_NUMBER,
  166. hose_a->first_busno);
  167. early_write_config_byte(hose_a,
  168. hose_a->first_busno,
  169. PCI_DEVFN(0, 0),
  170. CPC710_SUB_BUS_NUMBER,
  171. hose_a->last_busno);
  172. hose_a->last_busno = pciauto_bus_scan(hose_a, hose_a->first_busno);
  173. /* Write out correct max subordinate bus number for hose A */
  174. early_write_config_byte(hose_a,
  175. hose_a->first_busno,
  176. PCI_DEVFN(0, 0),
  177. CPC710_SUB_BUS_NUMBER,
  178. hose_a->last_busno);
  179. /* Setup PCI64 hose */
  180. hose_b = pcibios_alloc_controller();
  181. if (!hose_b)
  182. return;
  183. hose_b->first_busno = hose_a->last_busno + 1;
  184. hose_b->last_busno = 0xff;
  185. hose_b->pci_mem_offset = ADIR_PCI64_MEM_BASE;
  186. hose_b->io_space.start = 0;
  187. hose_b->io_space.end = ADIR_PCI64_VIRT_IO_SIZE - 1;
  188. hose_b->mem_space.start = 0;
  189. hose_b->mem_space.end = ADIR_PCI64_MEM_SIZE - 1;
  190. hose_b->io_resource.start = 0;
  191. hose_b->io_resource.end = ADIR_PCI64_VIRT_IO_SIZE - 1;
  192. hose_b->io_resource.flags = IORESOURCE_IO;
  193. hose_b->mem_resources[0].start = ADIR_PCI64_MEM_BASE;
  194. hose_b->mem_resources[0].end = ADIR_PCI64_MEM_BASE +
  195. ADIR_PCI64_MEM_SIZE - 1;
  196. hose_b->mem_resources[0].flags = IORESOURCE_MEM;
  197. hose_b->io_base_phys = ADIR_PCI64_IO_BASE;
  198. hose_b->io_base_virt = (void *) ADIR_PCI64_VIRT_IO_BASE;
  199. setup_indirect_pci(hose_b, ADIR_PCI64_CONFIG_ADDR,
  200. ADIR_PCI64_CONFIG_DATA);
  201. /* Initialize PCI64 bus registers */
  202. early_write_config_byte(hose_b,
  203. 0,
  204. PCI_DEVFN(0, 0),
  205. CPC710_SUB_BUS_NUMBER,
  206. 0xff);
  207. early_write_config_byte(hose_b,
  208. 0,
  209. PCI_DEVFN(0, 0),
  210. CPC710_BUS_NUMBER,
  211. hose_b->first_busno);
  212. hose_b->last_busno = pciauto_bus_scan(hose_b,
  213. hose_b->first_busno);
  214. /* Write out correct max subordinate bus number for hose B */
  215. early_write_config_byte(hose_b,
  216. hose_b->first_busno,
  217. PCI_DEVFN(0, 0),
  218. CPC710_SUB_BUS_NUMBER,
  219. hose_b->last_busno);
  220. ppc_md.pcibios_fixup = NULL;
  221. ppc_md.pcibios_fixup_resources = adir_pcibios_fixup_resources;
  222. ppc_md.pci_swizzle = common_swizzle;
  223. ppc_md.pci_map_irq = adir_map_irq;
  224. }