1 /* 2 * This file is subject to the terms and conditions of the GNU General Public 3 * License. See the file "COPYING" in the main directory of this archive 4 * for more details. 5 * 6 * SNI specific PCI support for RM200/RM300. 7 * 8 * Copyright (C) 1997 - 2000, 2003 Ralf Baechle <ralf@linux-mips.org> 9 */ 10 #include <linux/kernel.h> 11 #include <linux/pci.h> 12 #include <linux/types.h> 13 #include <asm/sni.h> 14 15 /* 16 * It seems that on the RM200 only lower 3 bits of the 5 bit PCI device 17 * address are decoded. We therefore manually have to reject attempts at 18 * reading outside this range. Being on the paranoid side we only do this 19 * test for bus 0 and hope forwarding and decoding work properly for any 20 * subordinated busses. 21 * 22 * ASIC PCI only supports type 1 config cycles. 23 */ 24 static int set_config_address(unsigned int busno, unsigned int devfn, int reg) 25 { 26 if ((devfn > 255) || (reg > 255)) 27 return PCIBIOS_BAD_REGISTER_NUMBER; 28 29 if (busno == 0 && devfn >= PCI_DEVFN(8, 0)) 30 return PCIBIOS_DEVICE_NOT_FOUND; 31 32 *(volatile u32 *)PCIMT_CONFIG_ADDRESS = 33 ((busno & 0xff) << 16) | 34 ((devfn & 0xff) << 8) | 35 (reg & 0xfc); 36 37 return PCIBIOS_SUCCESSFUL; 38 } 39 40 static int pcimt_read(struct pci_bus *bus, unsigned int devfn, int reg, 41 int size, u32 * val) 42 { 43 int res; 44 45 if ((res = set_config_address(bus->number, devfn, reg))) 46 return res; 47 48 switch (size) { 49 case 1: 50 *val = inb(PCIMT_CONFIG_DATA + (reg & 3)); 51 break; 52 case 2: 53 *val = inw(PCIMT_CONFIG_DATA + (reg & 2)); 54 break; 55 case 4: 56 *val = inl(PCIMT_CONFIG_DATA); 57 break; 58 } 59 60 return 0; 61 } 62 63 static int pcimt_write(struct pci_bus *bus, unsigned int devfn, int reg, 64 int size, u32 val) 65 { 66 int res; 67 68 if ((res = set_config_address(bus->number, devfn, reg))) 69 return res; 70 71 switch (size) { 72 case 1: 73 outb(val, PCIMT_CONFIG_DATA + (reg & 3)); 74 break; 75 case 2: 76 outw(val, PCIMT_CONFIG_DATA + (reg & 2)); 77 break; 78 case 4: 79 outl(val, PCIMT_CONFIG_DATA); 80 break; 81 } 82 83 return 0; 84 } 85 86 struct pci_ops sni_pcimt_ops = { 87 .read = pcimt_read, 88 .write = pcimt_write, 89 }; 90 91 static int pcit_set_config_address(unsigned int busno, unsigned int devfn, int reg) 92 { 93 if ((devfn > 255) || (reg > 255) || (busno > 255)) 94 return PCIBIOS_BAD_REGISTER_NUMBER; 95 96 outl((1 << 31) | ((busno & 0xff) << 16) | ((devfn & 0xff) << 8) | (reg & 0xfc), 0xcf8); 97 return PCIBIOS_SUCCESSFUL; 98 } 99 100 static int pcit_read(struct pci_bus *bus, unsigned int devfn, int reg, 101 int size, u32 * val) 102 { 103 int res; 104 105 /* 106 * on bus 0 we need to check, whether there is a device answering 107 * for the devfn by doing a config write and checking the result. If 108 * we don't do it, we will get a data bus error 109 */ 110 if (bus->number == 0) { 111 pcit_set_config_address(0, 0, 0x68); 112 outl(inl(0xcfc) | 0xc0000000, 0xcfc); 113 if ((res = pcit_set_config_address(0, devfn, 0))) 114 return res; 115 outl(0xffffffff, 0xcfc); 116 pcit_set_config_address(0, 0, 0x68); 117 if (inl(0xcfc) & 0x100000) 118 return PCIBIOS_DEVICE_NOT_FOUND; 119 } 120 if ((res = pcit_set_config_address(bus->number, devfn, reg))) 121 return res; 122 123 switch (size) { 124 case 1: 125 *val = inb(PCIMT_CONFIG_DATA + (reg & 3)); 126 break; 127 case 2: 128 *val = inw(PCIMT_CONFIG_DATA + (reg & 2)); 129 break; 130 case 4: 131 *val = inl(PCIMT_CONFIG_DATA); 132 break; 133 } 134 return 0; 135 } 136 137 static int pcit_write(struct pci_bus *bus, unsigned int devfn, int reg, 138 int size, u32 val) 139 { 140 int res; 141 142 if ((res = pcit_set_config_address(bus->number, devfn, reg))) 143 return res; 144 145 switch (size) { 146 case 1: 147 outb(val, PCIMT_CONFIG_DATA + (reg & 3)); 148 break; 149 case 2: 150 outw(val, PCIMT_CONFIG_DATA + (reg & 2)); 151 break; 152 case 4: 153 outl(val, PCIMT_CONFIG_DATA); 154 break; 155 } 156 157 return 0; 158 } 159 160 161 struct pci_ops sni_pcit_ops = { 162 .read = pcit_read, 163 .write = pcit_write, 164 }; 165
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.