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

4.104.114.84.95
Last change on this file since a7ff7e7 was 931e9cc0, checked in by Joel Sherrill <joel.sherrill@…>, on 09/06/07 at 16:33:26

2007-09-06 Daniel Hellstrom <daniel@…>

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