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

Last change on this file since bd91ff4e was bd91ff4e, checked in by Joel Sherrill <joel.sherrill@…>, on 11/10/04 at 22:15:01

2004-11-10 Richard Campbell <richard.campbell@…>

  • ChangeLog?, Makefile.am, bootloader/misc.c, bootloader/pci.c, bootloader/pci.h, console/console.c, console/inch.c, console/reboot.c, console/uart.c, console/uart.h, include/bsp.h, irq/irq.c, irq/irq.h, irq/irq_init.c, motorola/motorola.c, motorola/motorola.h, openpic/openpic.c, openpic/openpic.h, pci/detect_raven_bridge.c, pci/pci.c, pci/pci.h, start/start.S, startup/bspstart.c, vectors/vectors_init.c, vme/vmeconfig.c: Add MVME2100 BSP and MPC8240 support. There was also a significant amount of spelling and whitespace cleanup.
  • tod/.cvsignore, tod/Makefile.am, tod/todcfg.c: New files.
  • Property mode set to 100644
File size: 17.6 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 heavily 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.rtems.com/license/LICENSE.
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#include <rtems/bspIo.h>
25
26/* allow for overriding these definitions */
27#ifndef PCI_CONFIG_ADDR
28#define PCI_CONFIG_ADDR                 0xcf8
29#endif
30#ifndef PCI_CONFIG_DATA
31#define PCI_CONFIG_DATA                 0xcfc
32#endif
33
34#define PCI_INVALID_VENDORDEVICEID      0xffffffff
35#define PCI_MULTI_FUNCTION              0x80
36
37/* define a shortcut */
38#define pci     BSP_pci_configuration
39
40/*
41 * Bit encode for PCI_CONFIG_HEADER_TYPE register
42 */
43unsigned char ucMaxPCIBus;
44
45static int
46indirect_pci_read_config_byte(unsigned char bus, unsigned char slot,
47                              unsigned char function,
48                              unsigned char offset, unsigned char *val) {
49        out_be32((unsigned int*) pci.pci_config_addr,
50                 0x80|(bus<<8)|(PCI_DEVFN(slot,function)<<16)|((offset&~3)<<24));
51        *val = in_8(pci.pci_config_data + (offset&3));
52        return PCIBIOS_SUCCESSFUL;
53}
54
55static int
56indirect_pci_read_config_word(unsigned char bus, unsigned char slot,
57                              unsigned char function,
58                              unsigned char offset, unsigned short *val) {
59        *val = 0xffff;
60        if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER;
61        out_be32((unsigned int*) pci.pci_config_addr,
62                 0x80|(bus<<8)|(PCI_DEVFN(slot,function)<<16)|((offset&~3)<<24));
63        *val = in_le16((volatile unsigned short *)(pci.pci_config_data + (offset&3)));
64        return PCIBIOS_SUCCESSFUL;
65}
66
67static int
68indirect_pci_read_config_dword(unsigned char bus, unsigned char slot,
69                              unsigned char function,
70                              unsigned char offset, unsigned int *val) {
71        *val = 0xffffffff;
72        if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER;
73        out_be32((unsigned int*) pci.pci_config_addr,
74                 0x80|(bus<<8)|(PCI_DEVFN(slot,function)<<16)|(offset<<24));
75        *val = in_le32((volatile unsigned int *)pci.pci_config_data);
76        return PCIBIOS_SUCCESSFUL;
77}
78
79static int
80indirect_pci_write_config_byte(unsigned char bus, unsigned char slot,
81                               unsigned char function,
82                               unsigned char offset, unsigned char val) {
83        out_be32((unsigned int*) pci.pci_config_addr,
84                 0x80|(bus<<8)|(PCI_DEVFN(slot,function)<<16)|((offset&~3)<<24));
85        out_8(pci.pci_config_data + (offset&3), val);
86        return PCIBIOS_SUCCESSFUL;
87}
88
89static int
90indirect_pci_write_config_word(unsigned char bus, unsigned char slot,
91                               unsigned char function,
92                               unsigned char offset, unsigned short val) {
93        if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER;
94        out_be32((unsigned int*) pci.pci_config_addr,
95                 0x80|(bus<<8)|(PCI_DEVFN(slot,function)<<16)|((offset&~3)<<24));
96        out_le16((volatile unsigned short *)(pci.pci_config_data + (offset&3)), val);
97        return PCIBIOS_SUCCESSFUL;
98}
99
100static int
101indirect_pci_write_config_dword(unsigned char bus, unsigned char slot,
102                                unsigned char function,
103                                unsigned char offset, unsigned int val) {
104        if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER;
105        out_be32((unsigned int*) pci.pci_config_addr,
106                 0x80|(bus<<8)|(PCI_DEVFN(slot,function)<<16)|(offset<<24));
107        out_le32((volatile unsigned int *)pci.pci_config_data, val);
108        return PCIBIOS_SUCCESSFUL;
109}
110
111const pci_config_access_functions pci_indirect_functions = {
112        indirect_pci_read_config_byte,
113        indirect_pci_read_config_word,
114        indirect_pci_read_config_dword,
115        indirect_pci_write_config_byte,
116        indirect_pci_write_config_word,
117        indirect_pci_write_config_dword
118};
119
120pci_config BSP_pci_configuration = {(volatile unsigned char*)PCI_CONFIG_ADDR,
121                         (volatile unsigned char*)PCI_CONFIG_DATA,
122                         &pci_indirect_functions};
123
124static int
125direct_pci_read_config_byte(unsigned char bus, unsigned char slot,
126                            unsigned char function,
127                            unsigned char offset, unsigned char *val) {
128        if (bus != 0 || (1<<slot & 0xff8007fe)) {
129                *val=0xff;
130                return PCIBIOS_DEVICE_NOT_FOUND;
131        }
132        *val=in_8(pci.pci_config_data + ((1<<slot)&~1)
133                  + (function<<8) + offset);
134        return PCIBIOS_SUCCESSFUL;
135}
136
137static int
138direct_pci_read_config_word(unsigned char bus, unsigned char slot,
139                            unsigned char function,
140                            unsigned char offset, unsigned short *val) {
141        *val = 0xffff;
142        if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER;
143        if (bus != 0 || (1<<slot & 0xff8007fe)) {
144                return PCIBIOS_DEVICE_NOT_FOUND;
145        }
146        *val=in_le16((volatile unsigned short *)
147                     (pci.pci_config_data + ((1<<slot)&~1)
148                      + (function<<8) + offset));
149        return PCIBIOS_SUCCESSFUL;
150}
151
152static int
153direct_pci_read_config_dword(unsigned char bus, unsigned char slot,
154                             unsigned char function,
155                             unsigned char offset, unsigned int *val) {
156        *val = 0xffffffff;
157        if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER;
158        if (bus != 0 || (1<<slot & 0xff8007fe)) {
159                return PCIBIOS_DEVICE_NOT_FOUND;
160        }
161        *val=in_le32((volatile unsigned int *)
162                     (pci.pci_config_data + ((1<<slot)&~1)
163                      + (function<<8) + offset));
164        return PCIBIOS_SUCCESSFUL;
165}
166
167static int
168direct_pci_write_config_byte(unsigned char bus, unsigned char slot,
169                             unsigned char function,
170                             unsigned char offset, unsigned char val) {
171        if (bus != 0 || (1<<slot & 0xff8007fe)) {
172                return PCIBIOS_DEVICE_NOT_FOUND;
173        }
174        out_8(pci.pci_config_data + ((1<<slot)&~1)
175              + (function<<8) + offset,
176              val);
177        return PCIBIOS_SUCCESSFUL;
178}
179
180static int
181direct_pci_write_config_word(unsigned char bus, unsigned char slot,
182                             unsigned char function,
183                             unsigned char offset, unsigned short val) {
184        if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER;
185        if (bus != 0 || (1<<slot & 0xff8007fe)) {
186                return PCIBIOS_DEVICE_NOT_FOUND;
187        }
188        out_le16((volatile unsigned short *)
189                 (pci.pci_config_data + ((1<<slot)&~1)
190                  + (function<<8) + offset),
191                 val);
192        return PCIBIOS_SUCCESSFUL;
193}
194
195static int
196direct_pci_write_config_dword(unsigned char bus, unsigned char slot,
197                              unsigned char function,
198                              unsigned char offset, unsigned int val) {
199        if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER;
200        if (bus != 0 || (1<<slot & 0xff8007fe)) {
201                return PCIBIOS_DEVICE_NOT_FOUND;
202        }
203        out_le32((volatile unsigned int *)
204                 (pci.pci_config_data + ((1<<slot)&~1)
205                  + (function<<8) + offset),
206                 val);
207        return PCIBIOS_SUCCESSFUL;
208}
209
210const pci_config_access_functions pci_direct_functions = {
211        direct_pci_read_config_byte,
212        direct_pci_read_config_word,
213        direct_pci_read_config_dword,
214        direct_pci_write_config_byte,
215        direct_pci_write_config_word,
216        direct_pci_write_config_dword
217};
218
219
220#define PRINT_MSG() \
221             printk("pci : Device %d:%02x routed to interrupt_line %d\n", pbus, pslot, int_name )
222
223
224/*
225** Validate a test interrupt name and print a warning if its not one of
226** the names defined in the routing record.
227*/
228static int test_intname(
229  const struct _int_map *row,
230  int pbus,
231  int pslot,
232  int int_pin,
233  int int_name
234)
235{
236   int j, k;
237   int _nopin= -1, _noname= -1;
238
239   for(j=0; row->pin_route[j].pin > -1; j++)
240   {
241      if( row->pin_route[j].pin == int_pin )
242      {
243         _nopin = 0;
244         
245         for(k=0; k<4 && row->pin_route[j].int_name[k] > -1; k++ )
246         {
247            if( row->pin_route[j].int_name[k] == int_name ){ _noname=0; break; }
248         }
249         break;
250      }
251   }
252
253   if( _nopin  )
254   {
255      printk("pci : Device %d:%02x supplied a bogus interrupt_pin %d\n", pbus, pslot, int_pin );
256      return -1;
257   }
258   else
259   {
260      if( _noname )
261         printk("pci : Device %d:%02x supplied a suspicious interrupt_line %d, using it anyway\n", pbus, pslot, int_name );
262   }
263   return 0;
264}
265
266
267
268
269
270struct pcibridge
271{
272      int bus,slot;
273};
274
275
276static int FindPCIbridge( int mybus, struct pcibridge *pb )
277{
278   int          pbus, pslot;
279   unsigned8    bussec, buspri;
280   unsigned16   devid, vendorid, dclass;
281
282   for(pbus=0; pbus< BusCountPCI(); pbus++)
283   {
284      for(pslot=0; pslot< PCI_MAX_DEVICES; pslot++)
285      {
286         pci_read_config_word(pbus, pslot, 0, PCI_DEVICE_ID, &devid);
287         if( devid == 0xffff ) continue;
288
289         pci_read_config_word(pbus, pslot, 0, PCI_DEVICE_ID, &vendorid);
290         if( vendorid == 0xffff ) continue;
291
292         pci_read_config_word(pbus, pslot, 0, PCI_CLASS_DEVICE, &dclass);
293
294         if( dclass == PCI_CLASS_BRIDGE_PCI )
295         {
296            pci_read_config_byte(pbus, pslot, 0, PCI_PRIMARY_BUS,    &buspri);
297            pci_read_config_byte(pbus, pslot, 0, PCI_SECONDARY_BUS,  &bussec);
298
299#if 0
300            printk("pci : Found bridge at %d:%d, mybus %d, pribus %d, secbus %d  ", pbus, pslot, mybus, buspri, bussec );
301#endif
302            if( bussec == mybus )
303            {
304#if 0
305               printk("match\n");
306#endif
307               /* found our nearest bridge going towards the root */
308               pb->bus = pbus;
309               pb->slot = pslot;
310
311               return 0;
312            }
313#if 0
314            printk("no match\n");
315#endif
316         }
317
318
319      }
320   }
321   return -1;
322}
323
324
325
326
327
328
329
330
331void FixupPCI( const struct _int_map *bspmap, int (*swizzler)(int,int) )
332{
333   unsigned char        cvalue;
334   unsigned16           devid;
335   int                  ismatch, i, j, pbus, pslot, int_pin, int_name;
336
337   /*
338   ** If the device has a non-zero INTERRUPT_PIN, assign a bsp-specific
339   ** INTERRUPT_NAME if one isn't already in place.  Then, drivers can
340   ** trivially use INTERRUPT_NAME to hook up with devices.
341   */
342
343   for(pbus=0; pbus< BusCountPCI(); pbus++)
344   {
345      for(pslot=0; pslot< PCI_MAX_DEVICES; pslot++)
346      {
347         pci_read_config_word(pbus, pslot, 0, PCI_DEVICE_ID, &devid);
348         if( devid == 0xffff ) continue;
349
350         /* got a device */
351
352         pci_read_config_byte( pbus, pslot, 0, PCI_INTERRUPT_PIN, &cvalue);
353         int_pin = cvalue;
354
355         pci_read_config_byte( pbus, pslot, 0, PCI_INTERRUPT_LINE, &cvalue);
356         int_name = cvalue;
357
358/* printk("pci : device %d:%02x devid %04x, intpin %d, intline  %d\n", pbus, pslot, devid, int_pin, int_name ); */
359
360         if( int_pin > 0 )
361         {
362            ismatch = 0;
363
364            /*
365            ** first run thru the bspmap table and see if we have an explicit configuration
366            */
367            for(i=0; bspmap[i].bus > -1; i++)
368            {
369               if( bspmap[i].bus == pbus && bspmap[i].slot == pslot )
370               {
371                  ismatch = -1;
372                  /* we have a record in the table that gives specific
373                   * pins and interrupts for devices in this slot */
374                  if( int_name == 255 )
375                  {
376                     /* find the vector associated with whatever pin the device gives us */
377                     for( int_name=-1, j=0; bspmap[i].pin_route[j].pin > -1; j++ )
378                     {
379                        if( bspmap[i].pin_route[j].pin == int_pin )
380                        {
381                           int_name = bspmap[i].pin_route[j].int_name[0];
382                           break;
383                        }
384                     }
385                     if( int_name == -1 )
386                     {
387                        printk("pci : Unable to resolve device %d:%d w/ swizzled int pin %d to an interrupt_line.\n", pbus, pslot, int_pin );
388                     }
389                     else
390                     {
391                        PRINT_MSG();
392                        pci_write_config_byte(pbus,pslot,0,PCI_INTERRUPT_LINE,(cvalue= int_name, cvalue));
393                     }
394                  }
395                  else
396                  {
397                     test_intname( &bspmap[i],pbus,pslot,int_pin,int_name);
398                  }
399                  break;
400               }
401            }
402
403           
404            if( !ismatch )
405            {
406               /*
407               ** no match, which means we're on a bus someplace.  Work
408               ** backwards from it to one of our defined busses,
409               ** swizzling thru each bridge on the way.
410               */
411
412               /* keep pbus, pslot pointed to the device being
413               configured while we track down the bridges using
414               tbus,tslot.  We keep searching the routing table because
415               we may end up finding our bridge in it */
416
417               int tbus= pbus, tslot= pslot;
418
419               for(;;)
420               {
421
422                  for(i=0; bspmap[i].bus > -1; i++)
423                  {
424                     if( bspmap[i].bus == tbus && (bspmap[i].slot == tslot || bspmap[i].slot == -1) )
425                     {
426                        ismatch = -1;
427                        /* found a record for this bus, so swizzle the
428                         * int_pin which we then use to find the
429                         * interrupt_name.
430                         */
431
432                        if( int_name == 255 )
433                        {
434                           /*
435                           ** FIXME.  I can't believe this little hack
436                           ** is right.  It does not yield an error in
437                           ** convienently simple situations.
438                           */
439                           if( tbus ) int_pin = (*swizzler)(tslot,int_pin);
440
441
442                           /*
443                           ** int_pin points to the interrupt channel
444                           ** this card ends up delivering interrupts
445                           ** on.  Find the int_name servicing it.
446                           */
447                           for( int_name=-1, j=0; bspmap[i].pin_route[j].pin > -1; j++ )
448                           {
449                              if( bspmap[i].pin_route[j].pin == int_pin )
450                              {
451                                 int_name = bspmap[i].pin_route[j].int_name[0];
452                                 break;
453                              }
454                           }
455                           if( int_name == -1 )
456                           {
457                              printk("pci : Unable to resolve device %d:%d w/ swizzled int pin %d to an interrupt_line.\n", pbus, pslot, int_pin );
458                           }
459                           else
460                           {
461                              PRINT_MSG();
462                              pci_write_config_byte(pbus,pslot,0,PCI_INTERRUPT_LINE,(cvalue= int_name, cvalue));
463                           }
464                        }
465                        else
466                        {
467                           test_intname(&bspmap[i],pbus,pslot,int_pin,int_name);
468                        }
469                        goto donesearch;
470                     }
471                  }
472
473
474                  if( !ismatch )
475                  {
476                     struct pcibridge   pb;
477
478                     /*
479                     ** Haven't found our bus in the int map, so work
480                     ** upwards thru the bridges till we find it.
481                     */
482
483                     if( FindPCIbridge( tbus, &pb )== 0 )
484                     {
485                        int_pin = (*swizzler)(tslot,int_pin);
486
487                        /* our next bridge up is on pb.bus, pb.slot- now
488                        ** instead of pointing to the device we're
489                        ** trying to configure, we move from bridge to
490                        ** bridge.
491                        */
492
493                        tbus = pb.bus;
494                        tslot = pb.slot;
495                     }
496                     else
497                     {
498                        printk("pci : No bridge from bus %d towards root found\n", tbus );
499                        goto donesearch;
500                     }
501                     
502                  }
503
504               }
505            }
506           donesearch:
507
508
509            if( !ismatch && int_pin != 0 && int_name == 255 )
510            {
511               printk("pci : Unable to match device %d:%d with an int routing table entry\n", pbus, pslot  );
512            }
513
514
515         }
516      }
517   }
518}
519
520
521
522
523
524
525
526
527
528
529/*
530 * This routine determines the maximum bus number in the system
531 */
532void InitializePCI()
533{
534  extern void detect_host_bridge();
535  unsigned char ucSlotNumber, ucFnNumber, ucNumFuncs;
536  unsigned char ucHeader;
537  unsigned char ucMaxSubordinate;
538  unsigned int  ulClass, ulDeviceID;
539
540  detect_host_bridge();
541
542  /*
543   * Scan PCI bus 0 looking for PCI-PCI bridges
544   */
545  for(ucSlotNumber=0;ucSlotNumber<PCI_MAX_DEVICES;ucSlotNumber++) {
546    (void)pci_read_config_dword(0,
547                                ucSlotNumber,
548                                0,
549                                PCI_VENDOR_ID,
550                                &ulDeviceID);
551    if(ulDeviceID==PCI_INVALID_VENDORDEVICEID) {
552      /*
553       * This slot is empty
554       */
555      continue;
556    }
557    (void)pci_read_config_byte(0,
558                               ucSlotNumber,
559                               0,
560                               PCI_HEADER_TYPE,
561                               &ucHeader);
562    if(ucHeader&PCI_MULTI_FUNCTION)     {
563      ucNumFuncs=PCI_MAX_FUNCTIONS;
564    }
565    else {
566      ucNumFuncs=1;
567    }
568    for(ucFnNumber=0;ucFnNumber<ucNumFuncs;ucFnNumber++) {
569      (void)pci_read_config_dword(0,
570                                  ucSlotNumber,
571                                  ucFnNumber,
572                                  PCI_VENDOR_ID,
573                                  &ulDeviceID);
574      if(ulDeviceID==PCI_INVALID_VENDORDEVICEID) {
575                                /*
576                                 * This slot/function is empty
577                                 */
578        continue;
579      }
580
581      /*
582       * This slot/function has a device fitted.
583       */
584      (void)pci_read_config_dword(0,
585                                  ucSlotNumber,
586                                  ucFnNumber,
587                                  PCI_CLASS_REVISION,
588                                  &ulClass);
589      ulClass >>= 16;
590      if (ulClass == PCI_CLASS_BRIDGE_PCI) {
591                                /*
592                                 * We have found a PCI-PCI bridge
593                                 */
594        (void)pci_read_config_byte(0,
595                                   ucSlotNumber,
596                                   ucFnNumber,
597                                   PCI_SUBORDINATE_BUS,
598                                   &ucMaxSubordinate);
599        if(ucMaxSubordinate>ucMaxPCIBus) {
600          ucMaxPCIBus=ucMaxSubordinate;
601        }
602      }
603    }
604  }
605}
606
607/*
608 * Return the number of PCI busses in the system
609 */
610unsigned char BusCountPCI()
611{
612  return(ucMaxPCIBus+1);
613}
Note: See TracBrowser for help on using the repository browser.