source: rtems/c/src/lib/libbsp/powerpc/shared/pci/pci.c @ 69ed59f

4.104.114.84.95
Last change on this file since 69ed59f was 69ed59f, checked in by Joel Sherrill <joel.sherrill@…>, on May 14, 2002 at 5:10:17 PM

2001-05-14 Till Straumann <strauman@…>

  • bootloader/misc.c, console/Makefile.am, console/console.c, console/consoleIo.h, console/inch.c, console/polled_io.c, console/uart.c, console/uart.h, include/bsp.h, irq/Makefile.am, irq/irq.c, irq/irq.h, irq/irq_init.c, openpic/openpic.c, openpic/openpic.h, pci/Makefile.am, pci/pci.c, pci/pci.h, residual/Makefile.am, start/start.S, startup/bspstart.c, vectors/vectors.S, vectors/vectors.h, vectors/vectors_init.c: Per PR216, "libbsp/powerpc/shared" BSP has been modified considerably with the goal to make it more flexible and reusable by other BSPs. The main strategies were:
    • eliminate hardcoded base addresses; devices use offsets and a BSP defined base address.
    • separate functionality into different files (e.g. reboot from inch.c to reboot.c) which can be overridden by a 'derived' BSP.
    • separate initialization code into separate files (e.g. PCI bridge detection/initialization was separated from the more generic PCI access routines), also to make it easier for 'derived' BSPs to substitute their own initialization code.

There are also a couple of enhancements and fixes:

  • IRQ handling code now has a hook for attaching a VME bridge.
  • OpenPIC is now explicitely initialized (polarities, senses). Eliminated the implicit assumption on the presence of an ISA PIC.
  • UART and console driver now supports more than 1 port. The current maximum of 2 can easily be extended by enlarging a table (it would even be easier if the ISR API was not broken by design).
  • fixed polled_io.c so it correctly supports console on COM2
  • fixed TLB invalidation code (start.S).
  • exception handler prints a stack backtrace.
  • added BSP_pciFindDevice() to scan the pci bus for a particular vendor/device/instance.
  • Property mode set to 100644
File size: 8.4 KB
Line 
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 found in the file LICENSE in this distribution or at
14 *  http://www.OARcorp.com/rtems/license.html.
15 *
16 *  $Id$
17 *
18 *  Till Straumann, <strauman@slac.stanford.edu>, 1/2002
19 *   - separated bridge detection code out of this file
20 */
21
22#include <libcpu/io.h>
23#include <bsp/pci.h>
24
25/* allow for overriding these definitions */
26#ifndef PCI_CONFIG_ADDR
27#define PCI_CONFIG_ADDR                 0xcf8
28#endif
29#ifndef PCI_CONFIG_DATA
30#define PCI_CONFIG_DATA                 0xcfc
31#endif
32
33#define PCI_INVALID_VENDORDEVICEID      0xffffffff
34#define PCI_MULTI_FUNCTION              0x80
35
36/* define a shortcut */
37#define pci     BSP_pci_configuration
38
39/*
40 * Bit encode for PCI_CONFIG_HEADER_TYPE register
41 */
42unsigned char ucMaxPCIBus;
43
44static int
45indirect_pci_read_config_byte(unsigned char bus, unsigned char slot,
46                              unsigned char function, 
47                              unsigned char offset, unsigned char *val) {
48        out_be32((unsigned int*) pci.pci_config_addr, 
49                 0x80|(bus<<8)|(PCI_DEVFN(slot,function)<<16)|((offset&~3)<<24));
50        *val = in_8(pci.pci_config_data + (offset&3));
51        return PCIBIOS_SUCCESSFUL;
52}
53
54static int
55indirect_pci_read_config_word(unsigned char bus, unsigned char slot,
56                              unsigned char function, 
57                              unsigned char offset, unsigned short *val) {
58        *val = 0xffff; 
59        if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER;
60        out_be32((unsigned int*) pci.pci_config_addr, 
61                 0x80|(bus<<8)|(PCI_DEVFN(slot,function)<<16)|((offset&~3)<<24));
62        *val = in_le16((volatile unsigned short *)(pci.pci_config_data + (offset&3)));
63        return PCIBIOS_SUCCESSFUL;
64}
65
66static int
67indirect_pci_read_config_dword(unsigned char bus, unsigned char slot,
68                              unsigned char function, 
69                              unsigned char offset, unsigned int *val) {
70        *val = 0xffffffff; 
71        if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER;
72        out_be32((unsigned int*) pci.pci_config_addr, 
73                 0x80|(bus<<8)|(PCI_DEVFN(slot,function)<<16)|(offset<<24));
74        *val = in_le32((volatile unsigned int *)pci.pci_config_data);
75        return PCIBIOS_SUCCESSFUL;
76}
77
78static int
79indirect_pci_write_config_byte(unsigned char bus, unsigned char slot,
80                               unsigned char function, 
81                               unsigned char offset, unsigned char val) {
82        out_be32((unsigned int*) pci.pci_config_addr, 
83                 0x80|(bus<<8)|(PCI_DEVFN(slot,function)<<16)|((offset&~3)<<24));
84        out_8(pci.pci_config_data + (offset&3), val);
85        return PCIBIOS_SUCCESSFUL;
86}
87
88static int
89indirect_pci_write_config_word(unsigned char bus, unsigned char slot,
90                               unsigned char function, 
91                               unsigned char offset, unsigned short val) {
92        if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER;
93        out_be32((unsigned int*) pci.pci_config_addr, 
94                 0x80|(bus<<8)|(PCI_DEVFN(slot,function)<<16)|((offset&~3)<<24));
95        out_le16((volatile unsigned short *)(pci.pci_config_data + (offset&3)), val);
96        return PCIBIOS_SUCCESSFUL;
97}
98
99static int
100indirect_pci_write_config_dword(unsigned char bus, unsigned char slot,
101                                unsigned char function, 
102                                unsigned char offset, unsigned int val) {
103        if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER;
104        out_be32((unsigned int*) pci.pci_config_addr, 
105                 0x80|(bus<<8)|(PCI_DEVFN(slot,function)<<16)|(offset<<24));
106        out_le32((volatile unsigned int *)pci.pci_config_data, val);
107        return PCIBIOS_SUCCESSFUL;
108}
109
110const pci_config_access_functions pci_indirect_functions = {
111        indirect_pci_read_config_byte,
112        indirect_pci_read_config_word,
113        indirect_pci_read_config_dword,
114        indirect_pci_write_config_byte,
115        indirect_pci_write_config_word,
116        indirect_pci_write_config_dword
117};
118
119pci_config BSP_pci_configuration = {(volatile unsigned char*)PCI_CONFIG_ADDR,
120                         (volatile unsigned char*)PCI_CONFIG_DATA,
121                         &pci_indirect_functions};
122
123static int
124direct_pci_read_config_byte(unsigned char bus, unsigned char slot,
125                            unsigned char function, 
126                            unsigned char offset, unsigned char *val) {
127        if (bus != 0 || (1<<slot & 0xff8007fe)) {
128                *val=0xff;
129                return PCIBIOS_DEVICE_NOT_FOUND;
130        }
131        *val=in_8(pci.pci_config_data + ((1<<slot)&~1) 
132                  + (function<<8) + offset);
133        return PCIBIOS_SUCCESSFUL;
134}
135
136static int
137direct_pci_read_config_word(unsigned char bus, unsigned char slot,
138                            unsigned char function, 
139                            unsigned char offset, unsigned short *val) {
140        *val = 0xffff; 
141        if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER;
142        if (bus != 0 || (1<<slot & 0xff8007fe)) {
143                return PCIBIOS_DEVICE_NOT_FOUND;
144        }
145        *val=in_le16((volatile unsigned short *)
146                     (pci.pci_config_data + ((1<<slot)&~1)
147                      + (function<<8) + offset));
148        return PCIBIOS_SUCCESSFUL;
149}
150
151static int
152direct_pci_read_config_dword(unsigned char bus, unsigned char slot,
153                             unsigned char function, 
154                             unsigned char offset, unsigned int *val) {
155        *val = 0xffffffff; 
156        if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER;
157        if (bus != 0 || (1<<slot & 0xff8007fe)) {
158                return PCIBIOS_DEVICE_NOT_FOUND;
159        }
160        *val=in_le32((volatile unsigned int *)
161                     (pci.pci_config_data + ((1<<slot)&~1)
162                      + (function<<8) + offset));
163        return PCIBIOS_SUCCESSFUL;
164}
165
166static int
167direct_pci_write_config_byte(unsigned char bus, unsigned char slot,
168                             unsigned char function, 
169                             unsigned char offset, unsigned char val) {
170        if (bus != 0 || (1<<slot & 0xff8007fe)) {
171                return PCIBIOS_DEVICE_NOT_FOUND;
172        }
173        out_8(pci.pci_config_data + ((1<<slot)&~1) 
174              + (function<<8) + offset, 
175              val);
176        return PCIBIOS_SUCCESSFUL;
177}
178
179static int
180direct_pci_write_config_word(unsigned char bus, unsigned char slot,
181                             unsigned char function, 
182                             unsigned char offset, unsigned short val) {
183        if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER;
184        if (bus != 0 || (1<<slot & 0xff8007fe)) {
185                return PCIBIOS_DEVICE_NOT_FOUND;
186        }
187        out_le16((volatile unsigned short *)
188                 (pci.pci_config_data + ((1<<slot)&~1)
189                  + (function<<8) + offset),
190                 val);
191        return PCIBIOS_SUCCESSFUL;
192}
193
194static int
195direct_pci_write_config_dword(unsigned char bus, unsigned char slot,
196                              unsigned char function, 
197                              unsigned char offset, unsigned int val) {
198        if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER;
199        if (bus != 0 || (1<<slot & 0xff8007fe)) {
200                return PCIBIOS_DEVICE_NOT_FOUND;
201        }
202        out_le32((volatile unsigned int *)
203                 (pci.pci_config_data + ((1<<slot)&~1)
204                  + (function<<8) + offset),
205                 val);
206        return PCIBIOS_SUCCESSFUL;
207}
208
209const pci_config_access_functions pci_direct_functions = {
210        direct_pci_read_config_byte,
211        direct_pci_read_config_word,
212        direct_pci_read_config_dword,
213        direct_pci_write_config_byte,
214        direct_pci_write_config_word,
215        direct_pci_write_config_dword
216};
217
218
219/*
220 * This routine determines the maximum bus number in the system
221 */
222void InitializePCI()
223{
224  extern void detect_host_bridge();
225  unsigned char ucSlotNumber, ucFnNumber, ucNumFuncs;
226  unsigned char ucHeader;
227  unsigned char ucMaxSubordinate;
228  unsigned int  ulClass, ulDeviceID;
229
230  detect_host_bridge();
231  /*
232   * Scan PCI bus 0 looking for PCI-PCI bridges
233   */
234  for(ucSlotNumber=0;ucSlotNumber<PCI_MAX_DEVICES;ucSlotNumber++) {
235    (void)pci_read_config_dword(0,
236                                ucSlotNumber,
237                                0,
238                                PCI_VENDOR_ID,
239                                &ulDeviceID);
240    if(ulDeviceID==PCI_INVALID_VENDORDEVICEID) {
241      /*
242       * This slot is empty
243       */
244      continue;
245    }
246    (void)pci_read_config_byte(0,
247                               ucSlotNumber,
248                               0,
249                               PCI_HEADER_TYPE,
250                               &ucHeader);
251    if(ucHeader&PCI_MULTI_FUNCTION)     {
252      ucNumFuncs=PCI_MAX_FUNCTIONS;
253    }
254    else {
255      ucNumFuncs=1;
256    }
257    for(ucFnNumber=0;ucFnNumber<ucNumFuncs;ucFnNumber++) {
258      (void)pci_read_config_dword(0,
259                                  ucSlotNumber,
260                                  ucFnNumber,
261                                  PCI_VENDOR_ID,
262                                  &ulDeviceID);
263      if(ulDeviceID==PCI_INVALID_VENDORDEVICEID) {
264                                /*
265                                 * This slot/function is empty
266                                 */
267        continue;
268      }
269
270      /*
271       * This slot/function has a device fitted.
272       */
273      (void)pci_read_config_dword(0,
274                                  ucSlotNumber,
275                                  ucFnNumber,
276                                  PCI_CLASS_REVISION,
277                                  &ulClass);
278      ulClass >>= 16;
279      if (ulClass == PCI_CLASS_BRIDGE_PCI) {
280                                /*
281                                 * We have found a PCI-PCI bridge
282                                 */
283        (void)pci_read_config_byte(0,
284                                   ucSlotNumber,
285                                   ucFnNumber,
286                                   PCI_SUBORDINATE_BUS,
287                                   &ucMaxSubordinate);
288        if(ucMaxSubordinate>ucMaxPCIBus) {
289          ucMaxPCIBus=ucMaxSubordinate;
290        }
291      }
292    }
293  }
294}
295
296/*
297 * Return the number of PCI busses in the system
298 */
299unsigned char BusCountPCI()
300{
301  return(ucMaxPCIBus+1);
302}
Note: See TracBrowser for help on using the repository browser.