source: rtems/c/src/lib/libbsp/sparc/leon3/pci/pci.c @ ce40d30

4.104.114.84.95
Last change on this file since ce40d30 was ce40d30, checked in by Joel Sherrill <joel.sherrill@…>, on Sep 6, 2007 at 1:24:03 PM

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

  • pci/pci.c: New file missed on previous commit.
  • Property mode set to 100644
File size: 15.7 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 GRPCI
23 *  Copyright (C) 2006 Gaisler Research
24 *
25 */
26
27#include <pci.h>
28#include <rtems/bspIo.h>
29
30#define PCI_ADDR 0x80000400
31#define DMAPCI_ADDR 0x80000500
32#define PCI_CONF 0xfff50000
33#define PCI_MEM_START 0xe0000000
34#define PCI_MEM_END   0xf0000000
35#define PCI_MEM_SIZE  (PCI_MEM_START - PCI_MEM_END)
36
37/* If uncommented byte twisting is enabled */
38/*#define BT_ENABLED 1*/
39
40/* Define PCI_INFO to get a listing of configured devices at boot time */
41#define PCI_INFO 1
42
43#define DEBUG 1 
44
45#ifdef DEBUG
46#define DBG(x...) printk(x)
47#else
48#define DBG(x...)
49#endif
50
51/* allow for overriding these definitions */
52#ifndef PCI_CONFIG_ADDR
53#define PCI_CONFIG_ADDR                 0xcf8
54#endif
55#ifndef PCI_CONFIG_DATA
56#define PCI_CONFIG_DATA                 0xcfc
57#endif
58
59#define PCI_INVALID_VENDORDEVICEID      0xffffffff
60#define PCI_MULTI_FUNCTION              0x80
61
62/* define a shortcut */
63#define pci     BSP_pci_configuration
64
65/*
66 * Bit encode for PCI_CONFIG_HEADER_TYPE register
67 */
68unsigned char ucMaxPCIBus; 
69typedef struct {
70        volatile unsigned int cfg_stat;
71        volatile unsigned int bar0;
72        volatile unsigned int page0;
73        volatile unsigned int bar1;
74        volatile unsigned int page1;
75        volatile unsigned int iomap;
76        volatile unsigned int stat_cmd;
77} LEON3_GRPCI_Regs_Map;
78
79LEON3_GRPCI_Regs_Map *pcic = (LEON3_GRPCI_Regs_Map *) PCI_ADDR;
80unsigned int *pcidma = (unsigned int *)DMAPCI_ADDR;
81
82struct pci_res {
83    unsigned int size;
84    unsigned char bar;
85    unsigned char devfn;
86};
87
88static inline unsigned int flip_dword (unsigned int l)
89{
90        return ((l&0xff)<<24) | (((l>>8)&0xff)<<16) | (((l>>16)&0xff)<<8)| ((l>>24)&0xff);
91}
92
93
94/*  The configuration access functions uses the DMA functionality of the
95 *  AT697 pci controller to be able access all slots
96 */
97 
98
99int
100pci_read_config_dword(unsigned char bus, unsigned char slot, unsigned char function, unsigned char offset, unsigned int *val) {
101
102    volatile unsigned int *pci_conf;
103
104    if (offset & 3) return PCIBIOS_BAD_REGISTER_NUMBER;
105       
106    if (slot > 21) {
107        *val = 0xffffffff;
108        return PCIBIOS_SUCCESSFUL;
109    }
110
111    pci_conf = PCI_CONF + ((slot<<11) | (function<<8) | offset);
112
113#ifdef BT_ENABLED
114    *val =  flip_dword(*pci_conf);
115#else
116    *val = *pci_conf;
117#endif
118
119    if (pcic->cfg_stat & 0x100) {
120        *val = 0xffffffff;
121    }
122
123   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); 
124
125    return PCIBIOS_SUCCESSFUL;
126}
127
128
129int 
130pci_read_config_word(unsigned char bus, unsigned char slot, unsigned char function, unsigned char offset, unsigned short *val) {
131    unsigned int v;
132
133    if (offset & 1) return PCIBIOS_BAD_REGISTER_NUMBER;
134
135    pci_read_config_dword(bus, slot, function, offset&~3, &v);
136    *val = 0xffff & (v >> (8*(offset & 3)));
137
138    return PCIBIOS_SUCCESSFUL;
139}
140
141
142int 
143pci_read_config_byte(unsigned char bus, unsigned char slot, unsigned char function, unsigned char offset, unsigned char *val) {
144    unsigned int v;
145
146    pci_read_config_dword(bus, slot, function, offset&~3, &v);
147
148    *val = 0xff & (v >> (8*(offset & 3)));
149
150    return PCIBIOS_SUCCESSFUL;
151}
152
153
154int
155pci_write_config_dword(unsigned char bus, unsigned char slot, unsigned char function, unsigned char offset, unsigned int val) {
156
157    volatile unsigned int *pci_conf;
158    unsigned int value;
159
160    if (offset & 3 || bus != 0) return PCIBIOS_BAD_REGISTER_NUMBER;
161
162
163    pci_conf = PCI_CONF + ((slot<<11) | (function<<8) | (offset & ~3));
164
165#ifdef BT_ENABLED
166        value = flip_dword(val);
167#else
168        value = val;
169#endif
170
171    *pci_conf = value;
172
173    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), value); 
174
175    return PCIBIOS_SUCCESSFUL;
176}
177
178
179int 
180pci_write_config_word(unsigned char bus, unsigned char slot, unsigned char function, unsigned char offset, unsigned short val) {
181    unsigned int v;
182
183    if (offset & 1) return PCIBIOS_BAD_REGISTER_NUMBER;
184
185    pci_read_config_dword(bus, slot, function, offset&~3, &v);
186
187    v = (v & ~(0xffff << (8*(offset&3)))) | ((0xffff&val) << (8*(offset&3)));
188
189    return pci_write_config_dword(bus, slot, function, offset&~3, v);
190}
191
192
193int 
194pci_write_config_byte(unsigned char bus, unsigned char slot, unsigned char function, unsigned char offset, unsigned char val) {
195    unsigned int v;
196
197    pci_read_config_dword(bus, slot, function, offset&~3, &v);
198
199    v = (v & ~(0xff << (8*(offset&3)))) | ((0xff&val) << (8*(offset&3)));
200   
201    return pci_write_config_dword(bus, slot, function, offset&~3, v);
202}
203
204
205
206const pci_config_access_functions pci_access_functions = {
207    pci_read_config_byte,
208    pci_read_config_word,
209    pci_read_config_dword,
210    pci_write_config_byte,
211    pci_write_config_word,
212    pci_write_config_dword
213};
214
215pci_config BSP_pci_configuration = { (volatile unsigned char*)PCI_CONFIG_ADDR,
216                                     (volatile unsigned char*)PCI_CONFIG_DATA,
217                                     &pci_access_functions };
218
219
220
221
222int init_grpci(void) {
223
224    volatile unsigned int *page0 =  (unsigned volatile int *) PCI_MEM_START;
225    unsigned int data, addr;
226
227#ifndef BT_ENABLED
228    pci_write_config_dword(0,0,0,0x10, 0xffffffff);
229    pci_read_config_dword(0,0,0,0x10, &addr);
230    pci_write_config_dword(0,0,0,0x10, flip_dword(0x10000000));    /* Setup bar0 to nonzero value (grpci considers BAR==0 as invalid) */
231    addr = (~flip_dword(addr)+1)>>1;                               /* page0 is accessed through upper half of bar0 */
232    pcic->cfg_stat |= 0x10000000;                                  /* Setup mmap reg so we can reach bar0 */ 
233    page0[addr/4] = 0;                                             /* Disable bytetwisting ... */
234#endif
235 
236    /* set 1:1 mapping between AHB -> PCI memory */
237    pcic->cfg_stat = (pcic->cfg_stat & 0x0fffffff) | PCI_MEM_START;
238   
239    /* and map system RAM at pci address 0x40000000 */ 
240    pci_write_config_dword(0, 0, 0, 0x14, 0x40000000);
241    pcic->page1 = 0x40000000;
242   
243     /* set as bus master and enable pci memory responses */ 
244    pci_read_config_dword(0, 0, 0, 0x4, &data);
245    pci_write_config_dword(0, 0, 0, 0x4, data | 0x6); 
246
247    return 0;
248}
249
250/* DMA functions which uses GRPCIs optional DMA controller (len in words) */
251int dma_to_pci(unsigned int ahb_addr, unsigned int pci_addr, unsigned int len) {
252    int ret = 0;
253
254    pcidma[0] = 0x82;
255    pcidma[1] = ahb_addr;
256    pcidma[2] = pci_addr;
257    pcidma[3] = len;
258    pcidma[0] = 0x83;       
259
260    while ( (pcidma[0] & 0x4) == 0)
261        ;
262
263    if (pcidma[0] & 0x8) { /* error */ 
264        ret = -1;
265    }
266
267    pcidma[0] |= 0xC; 
268    return ret;
269
270}
271
272int dma_from_pci(unsigned int ahb_addr, unsigned int pci_addr, unsigned int len) {
273    int ret = 0;
274
275    pcidma[0] = 0x80;
276    pcidma[1] = ahb_addr;
277    pcidma[2] = pci_addr;
278    pcidma[3] = len;
279    pcidma[0] = 0x81;       
280
281    while ( (pcidma[0] & 0x4) == 0)
282        ;
283
284    if (pcidma[0] & 0x8) { /* error */ 
285        ret = -1;
286    }
287
288    pcidma[0] |= 0xC; 
289    return ret;
290
291} 
292
293
294void pci_mem_enable(unsigned char bus, unsigned char slot, unsigned char function) {
295    unsigned int data;
296
297    pci_read_config_dword(0, slot, function, PCI_COMMAND, &data);
298    pci_write_config_dword(0, slot, function, PCI_COMMAND, data | PCI_COMMAND_MEMORY); 
299
300}
301
302void pci_master_enable(unsigned char bus, unsigned char slot, unsigned char function) {
303    unsigned int data;
304
305    pci_read_config_dword(0, slot, function, PCI_COMMAND, &data);
306    pci_write_config_dword(0, slot, function, PCI_COMMAND, data | PCI_COMMAND_MASTER); 
307
308}
309
310static inline void swap_res(struct pci_res **p1, struct pci_res **p2) {
311
312    struct pci_res *tmp = *p1;
313    *p1 = *p2;
314    *p2 = tmp;
315
316}
317
318/* pci_allocate_resources
319 *
320 * This function scans the bus and assigns PCI addresses to all devices. It handles both
321 * single function and multi function devices. All allocated devices are enabled and
322 * latency timers are set to 40.
323 *
324 * NOTE that it only allocates PCI memory space devices (that are at least 1 KB).
325 * IO spaces are not enabled. Also, it does not handle pci-pci bridges. They are left disabled.
326 *
327 *
328*/
329void pci_allocate_resources(void) {
330
331    unsigned int slot, numfuncs, func, id, pos, size, tmp, i, swapped, addr, dev, fn;
332    unsigned char header;
333    struct pci_res **res;
334
335    res = (struct pci_res **) malloc(sizeof(struct pci_res *)*32*8*6);
336
337    for (i = 0; i < 32*8*6; i++) {
338        res[i] = (struct pci_res *) malloc(sizeof(struct pci_res));     
339        res[i]->size = 0;
340        res[i]->devfn = i;
341    }
342
343    for(slot = 1; slot < PCI_MAX_DEVICES; slot++) {
344
345        pci_read_config_dword(0, slot, 0, PCI_VENDOR_ID, &id);
346
347        if(id == PCI_INVALID_VENDORDEVICEID || id == 0) {
348            /*
349             * This slot is empty
350             */
351            continue;
352        }
353
354        pci_read_config_byte(0, slot, 0, PCI_HEADER_TYPE, &header);
355     
356        if(header & PCI_MULTI_FUNCTION) {
357            numfuncs = PCI_MAX_FUNCTIONS;
358        }
359        else {
360            numfuncs = 1;
361        }
362
363        for(func = 0; func < numfuncs; func++) {
364
365            pci_read_config_dword(0, slot, func, PCI_VENDOR_ID, &id);
366            if(id == PCI_INVALID_VENDORDEVICEID || id == 0) {
367                continue;
368            }
369
370            pci_read_config_dword(0, slot, func, PCI_CLASS_REVISION, &tmp);
371            tmp >>= 16;
372            if (tmp == PCI_CLASS_BRIDGE_PCI) {
373                continue;
374            }
375           
376            for (pos = 0; pos < 6; pos++) {
377                pci_write_config_dword(0, slot, func, PCI_BASE_ADDRESS_0 + (pos<<2), 0xffffffff);
378                pci_read_config_dword(0, slot, func, PCI_BASE_ADDRESS_0 + (pos<<2), &size);
379
380                if (size == 0 || size == 0xffffffff || (size & 0x3f1) != 0){
381                    pci_write_config_dword(0, slot, func, PCI_BASE_ADDRESS_0 + (pos<<2), 0);
382                    continue;
383
384                }else {
385                    size &= 0xfffffff0;
386                    res[slot*8*6+func*6+pos]->size  = ~size+1;
387                    res[slot*8*6+func*6+pos]->devfn = slot*8 + func;
388                    res[slot*8*6+func*6+pos]->bar   = pos;
389
390                    DBG("Slot: %d, function: %d, bar%d size: %x\n", slot, func, pos, ~size+1);
391                }
392            }
393        }
394    }
395
396
397    /* Sort the resources in descending order */ 
398    swapped = 1;
399    while (swapped == 1) {
400        swapped = 0;
401        for (i = 0; i < 32*8*6-1; i++) {
402            if (res[i]->size < res[i+1]->size) {
403                swap_res(&res[i], &res[i+1]);
404                swapped = 1;
405            }
406        }
407        i++;
408    }
409
410    /* Assign the BARs */
411    addr = PCI_MEM_START;
412    for (i = 0; i < 32*8*6; i++) {
413
414        if (res[i]->size == 0) {
415            goto done;
416        }
417        if ( (addr + res[i]->size) > PCI_MEM_END) {
418            printk("Out of PCI memory space, all devices not configured.\n");
419            goto done;
420        }
421   
422        dev = res[i]->devfn >> 3;
423        fn  = res[i]->devfn & 7;
424   
425        DBG("Assigning PCI addr %x to device %d, function %d, bar %d\n", addr, dev, fn, res[i]->bar);
426        pci_write_config_dword(0, dev, fn, PCI_BASE_ADDRESS_0+res[i]->bar*4, addr);
427        addr += res[i]->size;
428
429        /* Set latency timer to 64 */
430        pci_read_config_dword(0, dev, fn, 0xC, &tmp);   
431        pci_write_config_dword(0, dev, fn, 0xC, tmp|0x4000);
432
433        pci_mem_enable(0, dev, fn); 
434
435    } 
436
437
438   
439done:
440
441#ifdef PCI_INFO
442    printk("\nPCI devices found and configured:\n");
443    for (slot = 1; slot < PCI_MAX_DEVICES; slot++) {
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_COMMAND, &tmp);
457
458            if (tmp & PCI_COMMAND_MEMORY) { 
459               
460                pci_read_config_dword(0, slot, func, PCI_VENDOR_ID,  &id);
461
462                if (id == PCI_INVALID_VENDORDEVICEID || id == 0) continue;
463               
464                printk("\nSlot %d function: %d\nVendor id: 0x%x, device id: 0x%x\n", slot, func, id & 0xffff, id>>16);
465
466                for (pos = 0; pos < 6; pos++) {
467                    pci_read_config_dword(0, slot, func, PCI_BASE_ADDRESS_0 + pos*4, &tmp);
468
469                    if (tmp != 0 && tmp != 0xffffffff && (tmp & 0x3f1) == 0) {
470
471                        printk("\tBAR %d: %x\n", pos, tmp);
472                    }
473               
474                }
475                printk("\n");
476
477            } 
478
479        }
480     }
481    printk("\n");
482#endif
483   
484    for (i = 0; i < 1536; i++) {
485        free(res[i]);
486    }
487    free(res);
488}
489
490
491
492int init_pci()
493{
494    unsigned char ucSlotNumber, ucFnNumber, ucNumFuncs;
495    unsigned char ucHeader;
496    unsigned char ucMaxSubordinate;
497    unsigned int  ulClass, ulDeviceID; 
498
499    DBG("Initializing PCI\n");
500    if ( init_grpci() ) {
501      return -1;
502    }
503    pci_allocate_resources();
504    DBG("PCI resource allocation done\n");
505/*
506 * Scan PCI bus 0 looking for PCI-PCI bridges
507 */
508    for(ucSlotNumber=0;ucSlotNumber<PCI_MAX_DEVICES;ucSlotNumber++) {
509        (void)pci_read_config_dword(0,
510                                    ucSlotNumber,
511                                    0,
512                                    PCI_VENDOR_ID,
513                                    &ulDeviceID);
514        if(ulDeviceID==PCI_INVALID_VENDORDEVICEID) {
515/*
516 * This slot is empty
517 */
518            continue;
519        }
520        (void)pci_read_config_byte(0,
521                                   ucSlotNumber,
522                                   0,
523                                   PCI_HEADER_TYPE,
524                                   &ucHeader);
525        if(ucHeader&PCI_MULTI_FUNCTION) {
526            ucNumFuncs=PCI_MAX_FUNCTIONS;
527        }
528        else {
529            ucNumFuncs=1;
530        }
531        for(ucFnNumber=0;ucFnNumber<ucNumFuncs;ucFnNumber++) {
532            (void)pci_read_config_dword(0,
533                                        ucSlotNumber,
534                                        ucFnNumber,
535                                        PCI_VENDOR_ID,
536                                        &ulDeviceID);
537            if(ulDeviceID==PCI_INVALID_VENDORDEVICEID) {
538/*
539 * This slot/function is empty
540 */
541                continue;
542            }
543
544/*
545 * This slot/function has a device fitted.
546 */
547            (void)pci_read_config_dword(0,
548                                        ucSlotNumber,
549                                        ucFnNumber,
550                                        PCI_CLASS_REVISION,
551                                        &ulClass);
552            ulClass >>= 16;
553            if (ulClass == PCI_CLASS_BRIDGE_PCI) {
554/*
555 * We have found a PCI-PCI bridge
556 */
557                (void)pci_read_config_byte(0,
558                                           ucSlotNumber,
559                                           ucFnNumber,
560                                           PCI_SUBORDINATE_BUS,
561                                           &ucMaxSubordinate);
562                if(ucMaxSubordinate>ucMaxPCIBus) {
563                    ucMaxPCIBus=ucMaxSubordinate;
564                }
565            }
566        }
567    }
568    return 0;
569}
570
571/*
572 * Return the number of PCI busses in the system
573 */
574unsigned char BusCountPCI()
575{
576    return(ucMaxPCIBus+1);
577}
Note: See TracBrowser for help on using the repository browser.