1 /* 2 * Copyright (C) 2001 Dave Engebretsen, IBM Corporation 3 * Copyright (C) 2003 Anton Blanchard <anton@au.ibm.com>, IBM 4 * 5 * pSeries specific routines for PCI. 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2 of the License, or 10 * (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 */ 21 22 #include <linux/init.h> 23 #include <linux/ioport.h> 24 #include <linux/kernel.h> 25 #include <linux/pci.h> 26 #include <linux/string.h> 27 28 #include <asm/pci-bridge.h> 29 #include <asm/prom.h> 30 #include <asm/ppc-pci.h> 31 32 static int __devinitdata s7a_workaround = -1; 33 34 #if 0 35 void pcibios_name_device(struct pci_dev *dev) 36 { 37 struct device_node *dn; 38 39 /* 40 * Add IBM loc code (slot) as a prefix to the device names for service 41 */ 42 dn = pci_device_to_OF_node(dev); 43 if (dn) { 44 char *loc_code = get_property(dn, "ibm,loc-code", 0); 45 if (loc_code) { 46 int loc_len = strlen(loc_code); 47 if (loc_len < sizeof(dev->dev.name)) { 48 memmove(dev->dev.name+loc_len+1, dev->dev.name, 49 sizeof(dev->dev.name)-loc_len-1); 50 memcpy(dev->dev.name, loc_code, loc_len); 51 dev->dev.name[loc_len] = ' '; 52 dev->dev.name[sizeof(dev->dev.name)-1] = '\0'; 53 } 54 } 55 } 56 } 57 DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pcibios_name_device); 58 #endif 59 60 static void __devinit check_s7a(void) 61 { 62 struct device_node *root; 63 char *model; 64 65 s7a_workaround = 0; 66 root = of_find_node_by_path("/"); 67 if (root) { 68 model = get_property(root, "model", NULL); 69 if (model && !strcmp(model, "IBM,7013-S7A")) 70 s7a_workaround = 1; 71 of_node_put(root); 72 } 73 } 74 75 void __devinit pSeries_irq_bus_setup(struct pci_bus *bus) 76 { 77 struct pci_dev *dev; 78 79 if (s7a_workaround < 0) 80 check_s7a(); 81 list_for_each_entry(dev, &bus->devices, bus_list) { 82 pci_read_irq_line(dev); 83 if (s7a_workaround) { 84 if (dev->irq > 16) { 85 dev->irq -= 3; 86 pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 87 dev->irq); 88 } 89 } 90 } 91 } 92 93 static void __init pSeries_request_regions(void) 94 { 95 if (!isa_io_base) 96 return; 97 98 request_region(0x20,0x20,"pic1"); 99 request_region(0xa0,0x20,"pic2"); 100 request_region(0x00,0x20,"dma1"); 101 request_region(0x40,0x20,"timer"); 102 request_region(0x80,0x10,"dma page reg"); 103 request_region(0xc0,0x20,"dma2"); 104 } 105 106 void __init pSeries_final_fixup(void) 107 { 108 pSeries_request_regions(); 109 110 pci_addr_cache_build(); 111 } 112 113 /* 114 * Assume the winbond 82c105 is the IDE controller on a 115 * p610. We should probably be more careful in case 116 * someone tries to plug in a similar adapter. 117 */ 118 static void fixup_winbond_82c105(struct pci_dev* dev) 119 { 120 int i; 121 unsigned int reg; 122 123 if (!machine_is(pseries)) 124 return; 125 126 printk("Using INTC for W82c105 IDE controller.\n"); 127 pci_read_config_dword(dev, 0x40, ®); 128 /* Enable LEGIRQ to use INTC instead of ISA interrupts */ 129 pci_write_config_dword(dev, 0x40, reg | (1<<11)); 130 131 for (i = 0; i < DEVICE_COUNT_RESOURCE; ++i) { 132 /* zap the 2nd function of the winbond chip */ 133 if (dev->resource[i].flags & IORESOURCE_IO 134 && dev->bus->number == 0 && dev->devfn == 0x81) 135 dev->resource[i].flags &= ~IORESOURCE_IO; 136 } 137 } 138 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105, 139 fixup_winbond_82c105); 140