source: rtems/c/src/lib/libbsp/sparc/leon2/pci/pci.c @ 38386473

4.104.115
Last change on this file since 38386473 was 38386473, checked in by Ralf Corsepius <ralf.corsepius@…>, on 10/01/09 at 12:24:10

2009-10-01 Ralf Corsépius <ralf.corsepius@…>

PR 1445/BSPs

  • pci/pci.c: Rename pci_[read|write]_config* functions into BSP_pci_[read|write]_config* and make them static.
  • Property mode set to 100644
File size: 19.5 KB
RevLine 
[931e9cc0]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 *
[243596d]16 *  $Id$
[931e9cc0]17 *
18 *  Till Straumann, <strauman@slac.stanford.edu>, 1/2002
19 *   - separated bridge detection code out of this file
20 *
21 *  Adapted to LEON2 AT697 PCI
22 *  Copyright (C) 2006 Gaisler Research
23 *
24 */
25
26#include <pci.h>
27#include <rtems/bspIo.h>
28#include <stdlib.h>
29
30/* Define PCI_INFO to get a listing of configured devices at boot time */
31#define PCI_INFO 1
32
33/* #define DEBUG 1 */
34
35#ifdef DEBUG
36#define DBG(x...) printk(x)
37#else
38#define DBG(x...)
39#endif
40
41/* allow for overriding these definitions */
42#ifndef PCI_CONFIG_ADDR
43#define PCI_CONFIG_ADDR                 0xcf8
44#endif
45#ifndef PCI_CONFIG_DATA
46#define PCI_CONFIG_DATA                 0xcfc
47#endif
48
49#define PCI_INVALID_VENDORDEVICEID      0xffffffff
50#define PCI_MULTI_FUNCTION              0x80
51
52/* define a shortcut */
53#define pci     BSP_pci_configuration
54
55/*
56 * Bit encode for PCI_CONFIG_HEADER_TYPE register
57 */
58unsigned char ucMaxPCIBus; 
59
60typedef struct {
61    volatile unsigned int pciid1;        /* 0x80000100 - PCI Device identification register 1         */
62    volatile unsigned int pcisc;         /* 0x80000104 - PCI Status & Command                         */
63    volatile unsigned int pciid2;        /* 0x80000108 - PCI Device identification register 2         */
64    volatile unsigned int pcibhlc;       /* 0x8000010c - BIST, Header type, Cache line size register  */
65    volatile unsigned int mbar1;         /* 0x80000110 - Memory Base Address Register 1               */
66    volatile unsigned int mbar2;         /* 0x80000114 - Memory Base Address Register 2               */
67    volatile unsigned int iobar3;        /* 0x80000118 - IO Base Address Register 3                   */
68    volatile unsigned int dummy1[4];     /* 0x8000011c - 0x80000128                                   */
69    volatile unsigned int pcisid;        /* 0x8000012c - Subsystem identification register            */
70    volatile unsigned int dummy2;        /* 0x80000130                                                */
71    volatile unsigned int pcicp;         /* 0x80000134 - PCI capabilities pointer register            */
72    volatile unsigned int dummy3;        /* 0x80000138                                                */
73    volatile unsigned int pcili;         /* 0x8000013c - PCI latency interrupt register               */
74    volatile unsigned int pcirt;         /* 0x80000140 - PCI retry, trdy config                       */
75    volatile unsigned int pcicw;         /* 0x80000144 - PCI configuration write register             */
76    volatile unsigned int pcisa;         /* 0x80000148 - PCI Initiator Start Address                  */
77    volatile unsigned int pciiw;         /* 0x8000014c - PCI Initiator Write Register                 */
78    volatile unsigned int pcidma;        /* 0x80000150 - PCI DMA configuration register               */
79    volatile unsigned int pciis;         /* 0x80000154 - PCI Initiator Status Register                */
80    volatile unsigned int pciic;         /* 0x80000158 - PCI Initiator Configuration                  */
81    volatile unsigned int pcitpa;        /* 0x8000015c - PCI Target Page Address Register             */   
82    volatile unsigned int pcitsc;        /* 0x80000160 - PCI Target Status-Command Register           */
83    volatile unsigned int pciite;        /* 0x80000164 - PCI Interrupt Enable Register                */
84    volatile unsigned int pciitp;        /* 0x80000168 - PCI Interrupt Pending Register               */
85    volatile unsigned int pciitf;        /* 0x8000016c - PCI Interrupt Force Register                 */
86    volatile unsigned int pcid;          /* 0x80000170 - PCI Data Register                            */   
87    volatile unsigned int pcibe;         /* 0x80000174 - PCI Burst End Register                       */
88    volatile unsigned int pcidmaa;       /* 0x80000178 - PCI DMA Address Register                     */
89} AT697_PCI_Map;
90
91AT697_PCI_Map *pcic = (AT697_PCI_Map *) 0x80000100;
92
93#define PCI_MEM_START 0xa0000000
94#define PCI_MEM_END   0xf0000000
95#define PCI_MEM_SIZE  (PCI_MEM_START - PCI_MEM_END)
96
97
98struct pci_res {
99    unsigned int size;
100    unsigned char bar;
101    unsigned char devfn;
102};
103
104/*  The configuration access functions uses the DMA functionality of the
105 *  AT697 pci controller to be able access all slots
106 */
107 
[38386473]108static int
109BSP_pci_read_config_dword(unsigned char bus, unsigned char slot, unsigned char function, unsigned char offset, unsigned int *val) {
[931e9cc0]110
111    volatile unsigned int data;
112
113    if (offset & 3) return PCIBIOS_BAD_REGISTER_NUMBER;
114
115    pcic->pciitp = 0xff; /* clear interrupts */
116
117    pcic->pcisa = (  1<<(11+slot) ) | ((function & 7)<<8) |  (offset&0x3f);
118    pcic->pcidma = 0xa01;
119    pcic->pcidmaa = (unsigned int) &data;
120
121    while (pcic->pciitp == 0)
122        ;
123   
124    pcic->pciitp = 0xff; /* clear interrupts */
125
126    if (pcic->pcisc & 0x20000000)  { /* Master Abort */
127        pcic->pcisc |= 0x20000000;
128        *val = 0xffffffff;
129    }
130    else
131        *val = data;
132
133    DBG("pci_read - bus: %d, dev: %d, fn: %d, off: %d => addr: %x, val: %x\n", bus, slot, function, offset,  (1<<(11+slot) ) | ((function & 7)<<8) |  (offset&0x3f), *val);
134
135    return PCIBIOS_SUCCESSFUL;
136}
137
138
[38386473]139static int
140BSP_pci_read_config_word(unsigned char bus, unsigned char slot, unsigned char function, unsigned char offset, unsigned short *val) {
[931e9cc0]141    unsigned int v;
142
143    if (offset & 1) return PCIBIOS_BAD_REGISTER_NUMBER;
144
145    pci_read_config_dword(bus, slot, function, offset&~3, &v);
146    *val = 0xffff & (v >> (8*(offset & 3)));
147
148    return PCIBIOS_SUCCESSFUL;
149}
150
151
[38386473]152static int
153BSP_pci_read_config_byte(unsigned char bus, unsigned char slot, unsigned char function, unsigned char offset, unsigned char *val) {
[931e9cc0]154    unsigned int v;
155
156    pci_read_config_dword(bus, slot, function, offset&~3, &v);
157
158    *val = 0xff & (v >> (8*(offset & 3)));
159
160    return PCIBIOS_SUCCESSFUL;
161}
162
163
[38386473]164static int
165BSP_pci_write_config_dword(unsigned char bus, unsigned char slot, unsigned char function, unsigned char offset, unsigned int val) {
[931e9cc0]166
167    if (offset & 3) return PCIBIOS_BAD_REGISTER_NUMBER;
168
169    pcic->pciitp = 0xff; /* clear interrupts */
170 
171    pcic->pcisa = (  1<<(11+slot) ) | ((function & 7)<<8) |  (offset&0x3f);
172    pcic->pcidma = 0xb01;
173    pcic->pcidmaa = (unsigned int) &val;
174
175    while (pcic->pciitp == 0)
176        ;
177
178    if (pcic->pcisc & 0x20000000)  { /* Master Abort */
179        pcic->pcisc |= 0x20000000;
180    }
181
182    pcic->pciitp = 0xff; /* clear interrupts */
183
184/*    DBG("pci write - bus: %d, dev: %d, fn: %d, off: %d => addr: %x, val: %x\n", bus, slot, function, offset, (1<<(11+slot) ) | ((function & 7)<<8) |  (offset&0x3f), val); */
185
186    return PCIBIOS_SUCCESSFUL;
187}
188
189
[38386473]190static int
191BSP_pci_write_config_word(unsigned char bus, unsigned char slot, unsigned char function, unsigned char offset, unsigned short val) {
[931e9cc0]192    unsigned int v;
193
194    if (offset & 1) return PCIBIOS_BAD_REGISTER_NUMBER;
195
196    pci_read_config_dword(bus, slot, function, offset&~3, &v);
197
198    v = (v & ~(0xffff << (8*(offset&3)))) | ((0xffff&val) << (8*(offset&3)));
199
200    return pci_write_config_dword(bus, slot, function, offset&~3, v);
201}
202
203
[38386473]204static int
205BSP_pci_write_config_byte(unsigned char bus, unsigned char slot, unsigned char function, unsigned char offset, unsigned char val) {
[931e9cc0]206    unsigned int v;
207
208    pci_read_config_dword(bus, slot, function, offset&~3, &v);
209
210    v = (v & ~(0xff << (8*(offset&3)))) | ((0xff&val) << (8*(offset&3)));
211   
212    return pci_write_config_dword(bus, slot, function, offset&~3, v);
213}
214
215
216
217const pci_config_access_functions pci_access_functions = {
[38386473]218    BSP_pci_read_config_byte,
219    BSP_pci_read_config_word,
220    BSP_pci_read_config_dword,
221    BSP_pci_write_config_byte,
222    BSP_pci_write_config_word,
223    BSP_pci_write_config_dword
[931e9cc0]224};
225
226pci_config BSP_pci_configuration = { (volatile unsigned char*)PCI_CONFIG_ADDR,
227                                     (volatile unsigned char*)PCI_CONFIG_DATA,
228                                     &pci_access_functions };
229
230
231
232
233void init_at697_pci(void) {
234
235    /* Reset */
236    pcic->pciic = 0xffffffff;
237
238    /* Map system RAM at pci address 0x40000000 and system SDRAM to pci address 0x60000000  */
239    pcic->mbar1  = 0x40000000;
240    pcic->mbar2  = 0x60000000;
241    pcic->pcitpa = 0x40006000;
242
243    /* Enable PCI master and target memory command response  */
244    pcic->pcisc |= 0x40 | 0x6;
245
246    /* Set latency timer to 64 */
247    pcic->pcibhlc = 0x00004000;
248
249    /* Set Inititator configuration so that AHB slave accesses generate memory read/write commands */
250    pcic->pciic = 0x41;
251
252    pcic->pciite = 0xff;
253
254}
255
256/* May not pass a 1k boundary */
257int dma_from_pci_1k(unsigned int addr, unsigned int paddr, unsigned char len) {
258
259    int retval = 0;
260
261    if (addr & 3) {
262        return -1;
263    }
264
265    pcic->pciitp = 0xff; /* clear interrupts */
266
267    pcic->pcisa = paddr;
268    pcic->pcidma = 0xc00 | len;
269    pcic->pcidmaa = addr;
270
271    while (pcic->pciitp == 0)
272        ;
273
274    if (pcic->pciitp & 0x7F) {
275        retval = -1;
276    }
277
278    pcic->pciitp = 0xff; /* clear interrupts */
279
280    if (pcic->pcisc & 0x20000000)  { /* Master Abort */
281        pcic->pcisc |= 0x20000000;
282        retval = -1;
283    }
284   
285    return retval;
286}
287
288/* May not pass a 1k boundary */
289int dma_to_pci_1k(unsigned int addr, unsigned int paddr, unsigned char len) {
290
291    int retval = 0;
292
293    if (addr & 3) return -1;
294
295    pcic->pciitp = 0xff; /* clear interrupts */
296
297    pcic->pcisa = paddr;
298    pcic->pcidma = 0x700 | len;
299    pcic->pcidmaa = addr;
300
301    while (pcic->pciitp == 0)
302        ;
303   
304    if (pcic->pciitp & 0x7F) retval = -1;
305
306    pcic->pciitp = 0xff; /* clear interrupts */
307
308    if (pcic->pcisc & 0x20000000)  { /* Master Abort */
309        pcic->pcisc |= 0x20000000;
310        retval =  -1;
311    }
312
313    return retval;
314}
315
316/* Transfer len number of words from addr to paddr */
317int dma_to_pci(unsigned int addr, unsigned int paddr, unsigned int len) {
318   
319    int tmp_len;
320
321    /* Align to 1k boundary */
322    tmp_len = ((addr + 1024)  & 0xfffffc00) - addr;
323
324    tmp_len = (tmp_len/4 < len) ? tmp_len : (len*4);
325
326    if (dma_to_pci_1k(addr, paddr, tmp_len/4) < 0)
327        return -1;
328
329    addr += tmp_len;
330    paddr += tmp_len;
331    len -= tmp_len/4;
332   
333    /* Transfer all 1k blocks */
334    while (len >= 128) {
335
336        if (dma_to_pci_1k(addr, paddr, 128) < 0)
337            return -1;
338
339        addr += 512;
340        paddr += 512;
341        len -= 128;
342
343    }
344
345    /* Transfer last words */
346    if (len) return dma_to_pci_1k(addr, paddr, len);
347
348    return 0;
349}
350
351/* Transfer len number of words from paddr to addr */
352int dma_from_pci(unsigned int addr, unsigned int paddr, unsigned int len) {
353
354    int tmp_len;
355
356    /* Align to 1k boundary */
357    tmp_len = ((addr + 1024)  & 0xfffffc00) - addr;
358
359    tmp_len = (tmp_len/4 < len) ? tmp_len : (len*4);
360
361    if (dma_from_pci_1k(addr, paddr, tmp_len/4) < 0)
362        return -1;
363
364    addr += tmp_len;
365    paddr += tmp_len;
366    len -= tmp_len/4;
367   
368    /* Transfer all 1k blocks */
369    while (len >= 128) {
370
371        if (dma_from_pci_1k(addr, paddr, 128) < 0)
372            return -1;
373        addr += 512;
374        paddr += 512;
375        len -= 128;
376
377    }
378
379    /* Transfer last words */
380    if (len) return dma_from_pci_1k(addr, paddr, len);
381
382    return 0;
383}
384
385void pci_mem_enable(unsigned char bus, unsigned char slot, unsigned char function) {
386    unsigned int data;
387
388    pci_read_config_dword(0, slot, function, PCI_COMMAND, &data);
389    pci_write_config_dword(0, slot, function, PCI_COMMAND, data | PCI_COMMAND_MEMORY); 
390
391}
392
393void pci_master_enable(unsigned char bus, unsigned char slot, unsigned char function) {
394    unsigned int data;
395
396    pci_read_config_dword(0, slot, function, PCI_COMMAND, &data);
397    pci_write_config_dword(0, slot, function, PCI_COMMAND, data | PCI_COMMAND_MASTER); 
398
399}
400
401static inline void swap_res(struct pci_res **p1, struct pci_res **p2) {
402
403    struct pci_res *tmp = *p1;
404    *p1 = *p2;
405    *p2 = tmp;
406
407}
408
409/* pci_allocate_resources
410 *
411 * This function scans the bus and assigns PCI addresses to all devices. It handles both
412 * single function and multi function devices. All allocated devices are enabled and
413 * latency timers are set to 40.
414 *
415 * NOTE that it only allocates PCI memory space devices. IO spaces are not enabled.
416 * Also, it does not handle pci-pci bridges. They are left disabled.
417 *
418 *
419*/
420void pci_allocate_resources(void) {
421
422    unsigned int slot, numfuncs, func, id, pos, size, tmp, i, swapped, addr, dev, fn;
423    unsigned char header;
424    struct pci_res **res;
425
426    res = (struct pci_res **) malloc(sizeof(struct pci_res *)*32*8*6);
427
428    for (i = 0; i < 32*8*6; i++) {
429        res[i] = (struct pci_res *) malloc(sizeof(struct pci_res));     
430        res[i]->size = 0;
431        res[i]->devfn = i;
432    }
433
434    for(slot = 0; slot< PCI_MAX_DEVICES; slot++) {
435
436        pci_read_config_dword(0, slot, 0, PCI_VENDOR_ID, &id);
437
438        if(id == PCI_INVALID_VENDORDEVICEID || id == 0) {
439            /*
440             * This slot is empty
441             */
442            continue;
443        }
444
445        pci_read_config_byte(0, slot, 0, PCI_HEADER_TYPE, &header);
446     
447        if(header & PCI_MULTI_FUNCTION) {
448            numfuncs = PCI_MAX_FUNCTIONS;
449        }
450        else {
451            numfuncs = 1;
452        }
453
454        for(func = 0; func < numfuncs; func++) {
455
456            pci_read_config_dword(0, slot, func, PCI_VENDOR_ID, &id);
457            if(id == PCI_INVALID_VENDORDEVICEID || id == 0) {
458                continue;
459            }
460
461            pci_read_config_dword(0, slot, func, PCI_CLASS_REVISION, &tmp);
462            tmp >>= 16;
463            if (tmp == PCI_CLASS_BRIDGE_PCI) {
464                continue;
465            }
466           
467            for (pos = 0; pos < 6; pos++) {
468                pci_write_config_dword(0, slot, func, PCI_BASE_ADDRESS_0 + (pos<<2), 0xffffffff);
469                pci_read_config_dword(0, slot, func, PCI_BASE_ADDRESS_0 + (pos<<2), &size);
470
471                if (size == 0 || size == 0xffffffff || (size & 0xff) != 0) {
472                    pci_write_config_dword(0, slot, func, PCI_BASE_ADDRESS_0 + (pos<<2), 0);
473                    continue;
474                }
475
476                else {
477                    res[slot*8*6+func*6+pos]->size  = ~size+1;
478                    res[slot*8*6+func*6+pos]->devfn = slot*8 + func;
479                    res[slot*8*6+func*6+pos]->bar   = pos;
480
481                    DBG("Slot: %d, function: %d, bar%d size: %x\n", slot, func, pos, ~size+1);
482                }
483            }
484        }
485    }
486
487
488    /* Sort the resources in descending order */
489
490    swapped = 1;
491    while (swapped == 1) {
492        swapped = 0;
493        for (i = 0; i < 32*8*6-1; i++) {
494            if (res[i]->size < res[i+1]->size) {
495                swap_res(&res[i], &res[i+1]);
496                swapped = 1;
497            }
498        }
499        i++;
500    }
501
502    /* Assign the BARs */
503
504    addr = PCI_MEM_START;
505    for (i = 0; i < 32*8*6; i++) {
506
507        if (res[i]->size == 0) {
508            goto done;
509        }
510        if ( (addr + res[i]->size) > PCI_MEM_END) {
511            printk("Out of PCI memory space, all devices not configured.\n");
512            goto done;
513        }
514   
515        dev = res[i]->devfn >> 3;
516        fn  = res[i]->devfn & 7;
517   
518        DBG("Assigning PCI addr %x to device %d, function %d, bar %d\n", addr, dev, fn, res[i]->bar);
519        pci_write_config_dword(0, dev, fn, PCI_BASE_ADDRESS_0+res[i]->bar*4, addr);
520        addr += res[i]->size;
521
522        /* Set latency timer to 64 */
523        pci_read_config_dword(0, dev, fn, 0xC, &tmp);   
524        pci_write_config_dword(0, dev, fn, 0xC, tmp|0x4000);
525
526        pci_mem_enable(0, dev, fn); 
527
528    }
529
530
531   
532done:
533
534#ifdef PCI_INFO
535    printk("\nPCI devices found and configured:\n");
536    for (slot = 0; slot < PCI_MAX_DEVICES; slot++) {
537       
538        pci_read_config_byte(0, slot, 0, PCI_HEADER_TYPE, &header);
539       
540        if(header & PCI_MULTI_FUNCTION) {
541            numfuncs = PCI_MAX_FUNCTIONS;
542        }
543        else {
544            numfuncs = 1;
545        }
546
547        for (func = 0; func < numfuncs; func++) {
548           
549            pci_read_config_dword(0, slot, func, PCI_COMMAND, &tmp);
550
551            if (tmp & PCI_COMMAND_MEMORY) {
552               
553                pci_read_config_dword(0, slot, func, PCI_VENDOR_ID,  &id);
554
555                if (id == PCI_INVALID_VENDORDEVICEID || id == 0) continue;
556               
557                printk("\nSlot %d function: %d\nVendor id: 0x%x, device id: 0x%x\n", slot, func, id & 0xffff, id>>16);
558
559                for (pos = 0; pos < 6; pos++) {
560                    pci_read_config_dword(0, slot, func, PCI_BASE_ADDRESS_0 + pos*4, &tmp);
561
562                    if (tmp != 0 && tmp != 0xffffffff && (tmp & 0xff) == 0) {
563
564                        printk("\tBAR %d: %x\n", pos, tmp);
565                    }
566               
567                }
568                printk("\n");
569
570            }
571
572        }
573     }
574    printk("\n");
575#endif
576   
577    for (i = 0; i < 1536; i++) {
578        free(res[i]);
579    }
580    free(res);
581}
582
583
584
585
586
587
588
589/*
590 * This routine determines the maximum bus number in the system
591 */
[49c8f45]592int init_pci(void)
[931e9cc0]593{
594    unsigned char ucSlotNumber, ucFnNumber, ucNumFuncs;
595    unsigned char ucHeader;
596    unsigned char ucMaxSubordinate;
597    unsigned int  ulClass, ulDeviceID;
598
599    init_at697_pci();
600    pci_allocate_resources();
601
602/*
603 * Scan PCI bus 0 looking for PCI-PCI bridges
604 */
605    for(ucSlotNumber=0;ucSlotNumber<PCI_MAX_DEVICES;ucSlotNumber++) {
606        (void)pci_read_config_dword(0,
607                                    ucSlotNumber,
608                                    0,
609                                    PCI_VENDOR_ID,
610                                    &ulDeviceID);
611        if(ulDeviceID==PCI_INVALID_VENDORDEVICEID) {
612/*
613 * This slot is empty
614 */
615            continue;
616        }
617        (void)pci_read_config_byte(0,
618                                   ucSlotNumber,
619                                   0,
620                                   PCI_HEADER_TYPE,
621                                   &ucHeader);
622        if(ucHeader&PCI_MULTI_FUNCTION) {
623            ucNumFuncs=PCI_MAX_FUNCTIONS;
624        }
625        else {
626            ucNumFuncs=1;
627        }
628        for(ucFnNumber=0;ucFnNumber<ucNumFuncs;ucFnNumber++) {
629            (void)pci_read_config_dword(0,
630                                        ucSlotNumber,
631                                        ucFnNumber,
632                                        PCI_VENDOR_ID,
633                                        &ulDeviceID);
634            if(ulDeviceID==PCI_INVALID_VENDORDEVICEID) {
635/*
636 * This slot/function is empty
637 */
638                continue;
639            }
640
641/*
642 * This slot/function has a device fitted.
643 */
644            (void)pci_read_config_dword(0,
645                                        ucSlotNumber,
646                                        ucFnNumber,
647                                        PCI_CLASS_REVISION,
648                                        &ulClass);
649            ulClass >>= 16;
650            if (ulClass == PCI_CLASS_BRIDGE_PCI) {
651/*
652 * We have found a PCI-PCI bridge
653 */
654                (void)pci_read_config_byte(0,
655                                           ucSlotNumber,
656                                           ucFnNumber,
657                                           PCI_SUBORDINATE_BUS,
658                                           &ucMaxSubordinate);
659                if(ucMaxSubordinate>ucMaxPCIBus) {
660                    ucMaxPCIBus=ucMaxSubordinate;
661                }
662            }
663        }
664    }
665    return 0;
666}
667
668/*
669 * Return the number of PCI busses in the system
670 */
[49c8f45]671unsigned char BusCountPCI(void)
[931e9cc0]672{
673    return(ucMaxPCIBus+1);
674}
Note: See TracBrowser for help on using the repository browser.