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

4.104.11
Last change on this file since 38386473 was 38386473, checked in by Ralf Corsepius <ralf.corsepius@…>, on Oct 1, 2009 at 12:24:10 PM

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