[7be6ad9] | 1 | /* |
---|
| 2 | * pci.c : this file contains basic PCI Io functions. |
---|
| 3 | * |
---|
| 4 | * CopyRight (C) 1999 valette@crf.canon.fr |
---|
| 5 | * |
---|
| 6 | * This code is heavilly inspired by the public specification of STREAM V2 |
---|
| 7 | * that can be found at : |
---|
| 8 | * |
---|
| 9 | * <http://www.chorus.com/Documentation/index.html> by following |
---|
| 10 | * the STREAM API Specification Document link. |
---|
| 11 | * |
---|
| 12 | * The license and distribution terms for this file may be |
---|
| 13 | * found in the file LICENSE in this distribution or at |
---|
[f8e0327] | 14 | * http://www.rtems.com/license/LICENSE. |
---|
[7be6ad9] | 15 | * |
---|
[f8e0327] | 16 | * $Id$ |
---|
[7be6ad9] | 17 | * |
---|
| 18 | * Copyright 2004, Brookhaven National Laboratory and |
---|
| 19 | * Shuchen K. Feng, <feng1@bnl.gov>, 2004 |
---|
| 20 | * - modified and added support for MVME5500 board |
---|
| 21 | * - added 2nd PCI support for the mvme5500/GT64260 PCI bridge |
---|
| 22 | * |
---|
| 23 | */ |
---|
| 24 | #define PCI_MAIN |
---|
| 25 | |
---|
| 26 | #include <libcpu/io.h> |
---|
| 27 | #include <rtems/bspIo.h> /* printk */ |
---|
| 28 | |
---|
| 29 | #include <bsp/pci.h> |
---|
| 30 | #include <bsp/gtreg.h> |
---|
| 31 | #include <bsp/gtpcireg.h> |
---|
| 32 | |
---|
| 33 | #include <stdio.h> |
---|
| 34 | #include <string.h> |
---|
| 35 | |
---|
| 36 | #define PCI_DEBUG 0 |
---|
| 37 | #define PCI_PRINT 1 |
---|
| 38 | |
---|
| 39 | #define PCI_INVALID_VENDORDEVICEID 0xffffffff |
---|
| 40 | #define PCI_MULTI_FUNCTION 0x80 |
---|
| 41 | #define HOSTBRIDGET_ERROR 0xf0000000 |
---|
| 42 | |
---|
| 43 | typedef unsigned char unchar; |
---|
| 44 | |
---|
| 45 | #define MAX_NUM_PCI_DEVICES 20 |
---|
| 46 | |
---|
| 47 | static int numPCIDevs=0; |
---|
| 48 | extern void PCI_interface(), pciAccessInit(); |
---|
| 49 | |
---|
| 50 | /* Pack RegNum,FuncNum,DevNum,BusNum,and ConfigEnable for |
---|
| 51 | * PCI Configuration Address Register |
---|
| 52 | */ |
---|
| 53 | #define pciConfigPack(bus,dev,func,offset)\ |
---|
| 54 | (((func&7)<<8)|((dev&0x1f )<<11)|(( bus&0xff)<<16)|(offset&0xfc))|0x80000000 |
---|
| 55 | |
---|
| 56 | /* |
---|
| 57 | * Bit encode for PCI_CONFIG_HEADER_TYPE register |
---|
| 58 | */ |
---|
| 59 | unchar ucMaxPCIBus=0; |
---|
| 60 | |
---|
| 61 | /* Please note that PCI0 and PCI1 does not correlate with the busNum 0 and 1. |
---|
| 62 | */ |
---|
| 63 | int PCIx_read_config_byte(int npci, unchar bus, unchar dev, |
---|
| 64 | unchar func, unchar offset, unchar *val) |
---|
| 65 | { |
---|
| 66 | *val = 0xff; |
---|
| 67 | if (offset & ~0xff) return PCIBIOS_BAD_REGISTER_NUMBER; |
---|
| 68 | outl(pciConfigPack(bus,dev,func,offset),BSP_pci_config[npci].pci_config_addr); |
---|
| 69 | *val = inb(BSP_pci_config[npci].pci_config_data + (offset&3)); |
---|
| 70 | return PCIBIOS_SUCCESSFUL; |
---|
| 71 | } |
---|
| 72 | |
---|
| 73 | int PCIx_read_config_word(int npci, unchar bus, unchar dev, |
---|
| 74 | unchar func, unchar offset, unsigned short *val) |
---|
| 75 | { |
---|
| 76 | *val = 0xffff; |
---|
| 77 | if ((offset&1)|| (offset & ~0xff)) return PCIBIOS_BAD_REGISTER_NUMBER; |
---|
| 78 | outl(pciConfigPack(bus,dev,func,offset),BSP_pci_config[npci].pci_config_addr); |
---|
| 79 | *val = inw(BSP_pci_config[npci].pci_config_data + (offset&2)); |
---|
| 80 | return PCIBIOS_SUCCESSFUL; |
---|
| 81 | } |
---|
| 82 | |
---|
| 83 | int PCIx_read_config_dword(int npci, unchar bus, unchar dev, |
---|
| 84 | unchar func, unchar offset, unsigned int *val) |
---|
| 85 | { |
---|
| 86 | *val = 0xffffffff; |
---|
| 87 | if ((offset&3)|| (offset & ~0xff)) return PCIBIOS_BAD_REGISTER_NUMBER; |
---|
| 88 | #if 0 |
---|
| 89 | printk("addr %x, data %x, pack %x \n", BSP_pci_config[npci].pci_config_addr, |
---|
| 90 | BSP_pci_config[npci].pci_config_data,pciConfigPack(bus,dev,func,offset)); |
---|
| 91 | #endif |
---|
| 92 | outl(pciConfigPack(bus,dev,func,offset),BSP_pci_config[npci].pci_config_addr); |
---|
| 93 | *val = inl(BSP_pci_config[npci].pci_config_data); |
---|
| 94 | return PCIBIOS_SUCCESSFUL; |
---|
| 95 | } |
---|
| 96 | |
---|
| 97 | int PCIx_write_config_byte(int npci, unchar bus, unchar dev, |
---|
| 98 | unchar func, unchar offset, unchar val) |
---|
| 99 | { |
---|
| 100 | if (offset & ~0xff) return PCIBIOS_BAD_REGISTER_NUMBER; |
---|
| 101 | |
---|
| 102 | outl(pciConfigPack(bus,dev,func,offset),BSP_pci_config[npci].pci_config_addr); |
---|
| 103 | outb(val, BSP_pci_config[npci].pci_config_data + (offset&3)); |
---|
| 104 | return PCIBIOS_SUCCESSFUL; |
---|
| 105 | } |
---|
| 106 | |
---|
| 107 | int PCIx_write_config_word(int npci, unchar bus, unchar dev, |
---|
| 108 | unchar func, unchar offset, unsigned short val) |
---|
| 109 | { |
---|
| 110 | if ((offset&1)|| (offset & ~0xff)) return PCIBIOS_BAD_REGISTER_NUMBER; |
---|
| 111 | outl(pciConfigPack(bus,dev,func,offset),BSP_pci_config[npci].pci_config_addr); |
---|
| 112 | outw(val, BSP_pci_config[npci].pci_config_data + (offset&3)); |
---|
| 113 | return PCIBIOS_SUCCESSFUL; |
---|
| 114 | } |
---|
| 115 | |
---|
| 116 | int PCIx_write_config_dword(int npci,unchar bus,unchar dev, |
---|
| 117 | unchar func, unchar offset, unsigned int val) |
---|
| 118 | { |
---|
| 119 | if ((offset&3)|| (offset & ~0xff)) return PCIBIOS_BAD_REGISTER_NUMBER; |
---|
| 120 | #if 0 |
---|
| 121 | printk("addr %x, data %x, pack %x \n", BSP_pci_config[npci].pci_config_addr, |
---|
| 122 | BSP_pci_config[npci].pci_config_data,pciConfigPack(bus,dev,func,offset)); |
---|
| 123 | #endif |
---|
| 124 | outl(pciConfigPack(bus,dev,func,offset),BSP_pci_config[npci].pci_config_addr); |
---|
| 125 | outl(val,BSP_pci_config[npci].pci_config_data); |
---|
| 126 | return PCIBIOS_SUCCESSFUL; |
---|
| 127 | } |
---|
| 128 | |
---|
| 129 | /* backwards compatible with other PPC board for the vmeUniverse.c */ |
---|
| 130 | int pci_read_config_byte(unchar bus, unchar dev,unchar func,unchar offset, |
---|
| 131 | unchar *val) |
---|
| 132 | { |
---|
| 133 | return(PCIx_read_config_byte(0, bus, dev, func, offset, val)); |
---|
| 134 | } |
---|
| 135 | |
---|
| 136 | int pci_read_config_word(unchar bus, unchar dev, |
---|
| 137 | unchar func, unchar offset, unsigned short *val) |
---|
| 138 | { |
---|
| 139 | return(PCIx_read_config_word(0, bus, dev, func, offset, val)); |
---|
| 140 | } |
---|
| 141 | |
---|
| 142 | int pci_read_config_dword(unchar bus, unchar dev, |
---|
| 143 | unchar func, unchar offset, unsigned int *val) |
---|
| 144 | { |
---|
| 145 | return(PCIx_read_config_dword(0, bus, dev, func, offset, val)); |
---|
| 146 | } |
---|
| 147 | |
---|
| 148 | int pci_write_config_byte(unchar bus, unchar dev, |
---|
| 149 | unchar func, unchar offset, unchar val) |
---|
| 150 | { |
---|
| 151 | return(PCIx_write_config_byte(0, bus, dev, func, offset, val)); |
---|
| 152 | } |
---|
| 153 | |
---|
| 154 | int pci_write_config_word(unchar bus, unchar dev, |
---|
| 155 | unchar func, unchar offset, unsigned short val) |
---|
| 156 | { |
---|
| 157 | return(PCIx_write_config_word(0, bus, dev, func, offset, val)); |
---|
| 158 | } |
---|
| 159 | |
---|
| 160 | int pci_write_config_dword(unchar bus,unchar dev, |
---|
| 161 | unchar func, unchar offset, unsigned int val) |
---|
| 162 | { |
---|
| 163 | return(PCIx_write_config_dword(0, bus, dev, func, offset, val)); |
---|
| 164 | } |
---|
| 165 | |
---|
| 166 | |
---|
| 167 | pci_config BSP_pci_config[2] = { |
---|
| 168 | {PCI0_CONFIG_ADDR,PCI0_CONFIG_DATA/*,&pci_functions*/}, |
---|
| 169 | {PCI1_CONFIG_ADDR,PCI1_CONFIG_DATA/*,&pci_functions*/} |
---|
| 170 | }; |
---|
| 171 | |
---|
| 172 | /* |
---|
| 173 | * This routine determines the maximum bus number in the system |
---|
| 174 | */ |
---|
[037864f5] | 175 | void pci_initialize() |
---|
[7be6ad9] | 176 | { |
---|
| 177 | int PciNumber; |
---|
| 178 | unchar ucBusNumber, ucSlotNumber, ucFnNumber, ucNumFuncs; |
---|
| 179 | unchar ucMaxSubordinate; |
---|
| 180 | unsigned long ulHeader; |
---|
| 181 | unsigned int data, datal, datah, pcidata, ulClass, ulDeviceID; |
---|
| 182 | unsigned short sdata; |
---|
| 183 | |
---|
| 184 | PCI_interface(); |
---|
| 185 | |
---|
| 186 | /* |
---|
| 187 | * Scan PCI0 and PCI1 bus0 |
---|
| 188 | */ |
---|
| 189 | for (PciNumber=0; PciNumber < 2; PciNumber++) { |
---|
| 190 | pciAccessInit(PciNumber); |
---|
| 191 | for (ucBusNumber=0; ucBusNumber< 2; ucBusNumber++) { |
---|
| 192 | for (ucSlotNumber=0;ucSlotNumber<PCI_MAX_DEVICES;ucSlotNumber++) { |
---|
| 193 | ucFnNumber = 0; |
---|
| 194 | PCIx_read_config_dword(PciNumber, ucBusNumber, |
---|
| 195 | ucSlotNumber, |
---|
| 196 | 0, |
---|
| 197 | PCI0_VENDOR_ID, |
---|
| 198 | &ulDeviceID); |
---|
| 199 | |
---|
| 200 | if( ulDeviceID==PCI_INVALID_VENDORDEVICEID) { |
---|
| 201 | /* This slot is empty */ |
---|
| 202 | continue; |
---|
| 203 | } |
---|
| 204 | |
---|
| 205 | if (++numPCIDevs > MAX_NUM_PCI_DEVICES) { |
---|
| 206 | BSP_panic("Too many PCI devices found; increase MAX_NUM_PCI_DEVICES in pcicache.c\n"); |
---|
| 207 | } |
---|
| 208 | |
---|
| 209 | switch(ulDeviceID) { |
---|
| 210 | case (PCI_VENDOR_ID_MARVELL+(PCI_DEVICE_ID_MARVELL_GT6426xAB<<16)): |
---|
| 211 | #if PCI_PRINT |
---|
| 212 | printk("Marvell GT6426xA/B hostbridge detected at PCI%d bus%d slot%d\n", |
---|
| 213 | PciNumber,ucBusNumber,ucSlotNumber); |
---|
| 214 | #endif |
---|
| 215 | ucMaxPCIBus ++; |
---|
| 216 | break; |
---|
| 217 | case (PCI_VENDOR_ID_PLX2+(PCI_DEVICE_ID_PLX2_PCI6154_HB2<<16)): |
---|
| 218 | #if PCI_PRINT |
---|
| 219 | printk("PLX PCI6154 PCI-PCI bridge detected at PCI%d bus%d slot%d\n", |
---|
| 220 | PciNumber,ucBusNumber,ucSlotNumber); |
---|
| 221 | #endif |
---|
| 222 | ucMaxPCIBus ++; |
---|
| 223 | break; |
---|
| 224 | case PCI_VENDOR_ID_TUNDRA: |
---|
| 225 | #if PCI_PRINT |
---|
| 226 | printk("TUNDRA PCI-VME bridge detected at PCI%d bus%d slot%d\n", |
---|
| 227 | PciNumber,ucBusNumber,ucSlotNumber); |
---|
| 228 | #endif |
---|
| 229 | ucMaxPCIBus ++; |
---|
| 230 | break; |
---|
| 231 | case (PCI_VENDOR_ID_INTEL+(PCI_DEVICE_INTEL_82544EI_COPPER<<16)): |
---|
| 232 | #if PCI_PRINT |
---|
| 233 | printk("INTEL 82544EI COPPER network controller detected at PCI%d bus%d slot%d\n", |
---|
| 234 | PciNumber,ucBusNumber,ucSlotNumber); |
---|
| 235 | #endif |
---|
| 236 | ucMaxPCIBus ++; |
---|
| 237 | break; |
---|
| 238 | default : |
---|
| 239 | #if PCI_PRINT |
---|
| 240 | printk("PCI%d Bus%d Slot%d DeviceID 0x%x \n", |
---|
| 241 | PciNumber,ucBusNumber,ucSlotNumber, ulDeviceID); |
---|
| 242 | #endif |
---|
| 243 | break; |
---|
| 244 | } |
---|
| 245 | #if PCI_DEBUG |
---|
| 246 | PCIx_read_config_dword(PciNumber, ucBusNumber, |
---|
| 247 | ucSlotNumber, |
---|
| 248 | 0, |
---|
| 249 | PCI0_BASE_ADDRESS_0, |
---|
| 250 | &data); |
---|
| 251 | printk("PCI%d_BASE_ADDRESS_0 0x%x \n",PciNumber, data); |
---|
| 252 | PCIx_read_config_dword(PciNumber, ucBusNumber, |
---|
| 253 | ucSlotNumber, |
---|
| 254 | 0, |
---|
| 255 | PCI0_BASE_ADDRESS_1, |
---|
| 256 | &data); |
---|
| 257 | printk("PCI%d_BASE_ADDRESS_1 0x%x \n",PciNumber, data); |
---|
| 258 | PCIx_read_config_dword(PciNumber, ucBusNumber, |
---|
| 259 | ucSlotNumber, |
---|
| 260 | 0, |
---|
| 261 | PCI0_BASE_ADDRESS_2, |
---|
| 262 | &data); |
---|
| 263 | printk("PCI%d_BASE_ADDRESS_2 0x%x \n",PciNumber, data); |
---|
| 264 | |
---|
| 265 | PCIx_read_config_dword(PciNumber, ucBusNumber, |
---|
| 266 | ucSlotNumber, |
---|
| 267 | 0, |
---|
| 268 | PCI0_BASE_ADDRESS_3, |
---|
| 269 | &data); |
---|
| 270 | printk("PCI%d_BASE_ADDRESS_3 0x%x \n",PciNumber, data); |
---|
| 271 | |
---|
| 272 | PCIx_read_config_word(PciNumber, ucBusNumber, |
---|
| 273 | ucSlotNumber, |
---|
| 274 | 0, |
---|
| 275 | PCI0_INTERRUPT_LINE, |
---|
| 276 | &sdata); |
---|
| 277 | printk("PCI%d_INTERRUPT_LINE 0x%x \n",PciNumber, sdata); |
---|
| 278 | |
---|
| 279 | /* We always enable internal memory. */ |
---|
| 280 | PCIx_read_config_dword(PciNumber, ucBusNumber, |
---|
| 281 | ucSlotNumber, |
---|
| 282 | 0, |
---|
| 283 | PCI0_MEM_BASE_ADDR, |
---|
| 284 | &pcidata); |
---|
| 285 | printk("PCI%d_MEM_BASE_ADDR 0x%x \n", PciNumber,pcidata); |
---|
| 286 | |
---|
| 287 | /* We always enable internal IO. */ |
---|
| 288 | PCIx_read_config_dword(PciNumber, ucBusNumber, |
---|
| 289 | ucSlotNumber, |
---|
| 290 | 0, |
---|
| 291 | PCI0_IO_BASE_ADDR, |
---|
| 292 | &pcidata); |
---|
| 293 | printk("PCI%d_IO_BASE_ADDR 0x%x \n", PciNumber,pcidata); |
---|
| 294 | #endif |
---|
| 295 | |
---|
| 296 | PCIx_read_config_dword(PciNumber, ucBusNumber, |
---|
| 297 | ucSlotNumber, |
---|
| 298 | 0, |
---|
| 299 | PCI0_CACHE_LINE_SIZE, |
---|
| 300 | &ulHeader); |
---|
| 301 | if ((ulHeader>>16)&PCI_MULTI_FUNCTION) |
---|
| 302 | ucNumFuncs=PCI_MAX_FUNCTIONS; |
---|
| 303 | else |
---|
| 304 | ucNumFuncs=1; |
---|
| 305 | |
---|
| 306 | #if PCI_DEBUG |
---|
| 307 | printk("PCI%d Slot 0x%x HEADER/LAT/CACHE 0x%x \n", |
---|
| 308 | PciNumber,ucSlotNumber, ulHeader); |
---|
| 309 | |
---|
| 310 | for (ucFnNumber=1;ucFnNumber<ucNumFuncs;ucFnNumber++) { |
---|
| 311 | PCIx_read_config_dword(PciNumber, ucBusNumber, |
---|
| 312 | ucSlotNumber, |
---|
| 313 | ucFnNumber, |
---|
| 314 | PCI0_VENDOR_ID, |
---|
| 315 | &ulDeviceID); |
---|
| 316 | if (ulDeviceID==PCI_INVALID_VENDORDEVICEID) { |
---|
| 317 | /* This slot/function is empty */ |
---|
| 318 | continue; |
---|
| 319 | } |
---|
| 320 | if (++numPCIDevs > MAX_NUM_PCI_DEVICES) { |
---|
| 321 | BSP_panic("Too many PCI devices found; increase MAX_NUM_PCI_DEVICES in pcicache.c\n"); |
---|
| 322 | } |
---|
| 323 | |
---|
| 324 | /* This slot/function has a device fitted.*/ |
---|
| 325 | PCIx_read_config_dword(PciNumber, ucBusNumber, |
---|
| 326 | ucSlotNumber, |
---|
| 327 | ucFnNumber, |
---|
| 328 | PCI0_CLASS_REVISION, |
---|
| 329 | &ulClass); |
---|
| 330 | printk("PCI%d Slot 0x%x Func %d classID 0x%x \n",PciNumber,ucSlotNumber, |
---|
| 331 | ucFnNumber, ulClass); |
---|
| 332 | |
---|
| 333 | ulClass >>= 16; |
---|
| 334 | if (ulClass == PCI_CLASS_GT6426xAB) |
---|
| 335 | printk("GT64260-PCI%d bridge found \n", PciNumber); |
---|
| 336 | } |
---|
| 337 | #endif |
---|
| 338 | PCIx_read_config_dword(PciNumber, ucBusNumber, |
---|
| 339 | ucSlotNumber, |
---|
| 340 | 0, |
---|
| 341 | PCI0_COMMAND, |
---|
| 342 | &pcidata); |
---|
| 343 | #if PCI_DEBUG |
---|
| 344 | printk("MOTLoad command staus 0x%x, ", pcidata); |
---|
| 345 | #endif |
---|
| 346 | /* Clear the error on the host bridge */ |
---|
| 347 | if ( (ucBusNumber==0) && (ucSlotNumber==0)) |
---|
| 348 | pcidata |= PCI_STATUS_CLRERR_MASK; |
---|
| 349 | /* Enable bus,I/O and memory master access. */ |
---|
| 350 | pcidata |= (PCI_COMMAND_MASTER|PCI_COMMAND_IO|PCI_COMMAND_MEMORY); |
---|
| 351 | PCIx_write_config_dword(PciNumber, ucBusNumber, |
---|
| 352 | ucSlotNumber, |
---|
| 353 | 0, |
---|
| 354 | PCI0_COMMAND, |
---|
| 355 | pcidata); |
---|
| 356 | |
---|
| 357 | PCIx_read_config_dword(PciNumber, ucBusNumber, |
---|
| 358 | ucSlotNumber, |
---|
| 359 | 0, |
---|
| 360 | PCI0_COMMAND, |
---|
| 361 | &pcidata); |
---|
| 362 | #if PCI_DEBUG |
---|
| 363 | printk("Now command/staus 0x%x\n", pcidata); |
---|
| 364 | #endif |
---|
| 365 | |
---|
| 366 | } |
---|
| 367 | } |
---|
| 368 | } /* PCI number */ |
---|
| 369 | } |
---|
| 370 | |
---|
| 371 | /* |
---|
| 372 | * Return the number of PCI buses in the system |
---|
| 373 | */ |
---|
| 374 | unsigned char BusCountPCI() |
---|
| 375 | { |
---|
| 376 | return(ucMaxPCIBus); |
---|
| 377 | } |
---|
| 378 | |
---|