source: rtems/c/src/lib/libbsp/sparc/shared/pci/pcif.c @ 4a7d1026

4.115
Last change on this file since 4a7d1026 was 4a7d1026, checked in by Daniel Hellstrom <daniel@…>, on 04/13/15 at 08:25:52

sparc bsps: updated license to rtems.org

  • Property mode set to 100644
File size: 14.0 KB
RevLine 
[46e41c98]1/*  GRLIB PCIF PCI HOST driver.
2 *
3 *  COPYRIGHT (c) 2008.
4 *  Cobham Gaisler AB.
5 *
6 *  Configures the PCIF core and initialize,
7 *   - the PCI Library (pci.c)
8 *   - the general part of the PCI Bus driver (pci_bus.c)
9 * 
10 *  System interrupt assigned to PCI interrupt (INTA#..INTD#) is by
11 *  default taken from Plug and Play, but may be overridden by the
12 *  driver resources INTA#..INTD#.
13 *
14 *  The license and distribution terms for this file may be
15 *  found in found in the file LICENSE in this distribution or at
[4a7d1026]16 *  http://www.rtems.org/license/LICENSE.
[46e41c98]17 */
18
19#include <stdio.h>
20#include <stdlib.h>
21#include <string.h>
22#include <libcpu/byteorder.h>
23#include <libcpu/access.h>
[28950f0b]24#include <rtems/bspIo.h>
[46e41c98]25#include <pci.h>
26#include <pci/cfg.h>
27
28#include <drvmgr/drvmgr.h>
29#include <drvmgr/ambapp_bus.h>
30#include <ambapp.h>
31#include <drvmgr/pci_bus.h>
[5823bae8]32#include <bsp/pcif.h>
[46e41c98]33
34
35/* Configuration options */
36#define SYSTEM_MAINMEM_START 0x40000000
37
38/* Interrupt assignment. Set to other value than 0xff in order to
39 * override defaults and plug&play information
40 */
41#ifndef PCIF_INTA_SYSIRQ
42 #define PCIF_INTA_SYSIRQ 0xff
43#endif
44#ifndef PCIF_INTB_SYSIRQ
45 #define PCIF_INTB_SYSIRQ 0xff
46#endif
47#ifndef PCIF_INTC_SYSIRQ
48 #define PCIF_INTC_SYSIRQ 0xff
49#endif
50#ifndef PCIF_INTD_SYSIRQ
51 #define PCIF_INTD_SYSIRQ 0xff
52#endif
53
54/*#define DEBUG 1  */
55
56#ifdef DEBUG
57#define DBG(x...) printk(x)
58#else
59#define DBG(x...)
60#endif
61
62/*
63 * Bit encode for PCI_CONFIG_HEADER_TYPE register
64 */
65struct pcif_regs {
66        volatile unsigned int bars[4];  /* 0x00-0x10 */
67        volatile unsigned int bus;      /* 0x10 */
68        volatile unsigned int map_io;   /* 0x14 */
69        volatile unsigned int status;   /* 0x18 */
70        volatile unsigned int intr;     /* 0x1c */
71        int unused[(0x40-0x20)/4];      /* 0x20-0x40 */
72        volatile unsigned int maps[(0x80-0x40)/4];   /* 0x40-0x80*/
73};
74
[51347053]75/* Used internally for accessing the PCI bridge's configuration space itself */
76#define HOST_TGT PCI_DEV(0xff, 0, 0)
77
[46e41c98]78struct pcif_priv *pcifpriv = NULL;
79static int pcif_minor = 0;
80
81/* PCI Interrupt assignment. Connects an PCI interrupt pin (INTA#..INTD#)
82 * to a system interrupt number.
83 */
84unsigned char pcif_pci_irq_table[4] =
85{
86        /* INTA# */     PCIF_INTA_SYSIRQ,
87        /* INTB# */     PCIF_INTB_SYSIRQ,
88        /* INTC# */     PCIF_INTC_SYSIRQ,
89        /* INTD# */     PCIF_INTD_SYSIRQ
90};
91
92/* Driver private data struture */
93struct pcif_priv {
94        struct drvmgr_dev       *dev;
95        struct pcif_regs                *regs;
96        int                             irq;
97        int                             minor;
98        int                             irq_mask;
99
100        unsigned int                    pci_area;
101        unsigned int                    pci_area_end;
102        unsigned int                    pci_io;   
103        unsigned int                    pci_conf;
104        unsigned int                    pci_conf_end;
105
106        uint32_t                        devVend; /* Host PCI Vendor/Device ID */
107        uint32_t                        bar1_size;
108
109        struct drvmgr_map_entry         maps_up[2];
110        struct drvmgr_map_entry         maps_down[2];
111        struct pcibus_config            config;
112};
113
114int pcif_init1(struct drvmgr_dev *dev);
115int pcif_init3(struct drvmgr_dev *dev);
116
117/* PCIF DRIVER */
118
119struct drvmgr_drv_ops pcif_ops =
120{
121        .init = {pcif_init1, NULL, pcif_init3, NULL},
122        .remove = NULL,
123        .info = NULL
124};
125
126struct amba_dev_id pcif_ids[] =
127{
128        {VENDOR_GAISLER, GAISLER_PCIF},
129        {0, 0}          /* Mark end of table */
130};
131
132struct amba_drv_info pcif_info =
133{
134        {
135                DRVMGR_OBJ_DRV,                 /* Driver */
136                NULL,                           /* Next driver */
137                NULL,                           /* Device list */
138                DRIVER_AMBAPP_GAISLER_PCIF_ID,  /* Driver ID */
139                "PCIF_DRV",                     /* Driver Name */
140                DRVMGR_BUS_TYPE_AMBAPP,         /* Bus Type */
141                &pcif_ops,
142                NULL,                           /* Funcs */
143                0,                              /* No devices yet */
144                sizeof(struct pcif_priv),       /* Let drvmgr alloc private */
145        },
146        &pcif_ids[0]
147};
148
149void pcif_register_drv(void)
150{
151        DBG("Registering PCIF driver\n");
152        drvmgr_drv_register(&pcif_info.general);
153}
154
[28950f0b]155static int pcif_cfg_r32(pci_dev_t dev, int ofs, uint32_t *val)
[46e41c98]156{
157        struct pcif_priv *priv = pcifpriv;
158        volatile uint32_t *pci_conf;
[51347053]159        uint32_t devfn;
[46e41c98]160        int retval;
161        int bus = PCI_DEV_BUS(dev);
162
163        if (ofs & 3)
164                return PCISTS_EINVAL;
165
[51347053]166        if (PCI_DEV_SLOT(dev) > 15) {
[46e41c98]167                *val = 0xffffffff;
168                return PCISTS_OK;
169        }
170
[51347053]171        /* PCIF can access "non-standard" devices on bus0 (on AD11.AD16),
172         * but we skip them.
173         */
174        if (dev == HOST_TGT)
175                bus = devfn = 0;
[3c236cc]176        else if (bus == 0)
[51347053]177                devfn = PCI_DEV_DEVFUNC(dev) + PCI_DEV(0, 6, 0);
178        else
179                devfn = PCI_DEV_DEVFUNC(dev);
180
[46e41c98]181        /* Select bus */
182        priv->regs->bus = bus << 16;
183
184        pci_conf = (volatile uint32_t *)(priv->pci_conf | (devfn << 8) | ofs);
185
186        *val = *pci_conf;
187
188        if (priv->regs->status & 0x30000000) {
189                *val = 0xffffffff;
190                retval = PCISTS_MSTABRT;
191        } else
192                retval = PCISTS_OK;
193
194        DBG("pci_read: [%x:%x:%x] reg: 0x%x => addr: 0x%x, val: 0x%x\n",
195                PCI_DEV_EXPAND(dev), ofs, pci_conf, *val);
196
197        return retval;
198}
[28950f0b]199
200static int pcif_cfg_r16(pci_dev_t dev, int ofs, uint16_t *val)
[46e41c98]201{
202        uint32_t v;
203        int retval;
204
205        if (ofs & 1)
206                return PCISTS_EINVAL;
207
208        retval = pcif_cfg_r32(dev, ofs & ~0x3, &v);
209        *val = 0xffff & (v >> (8*(ofs & 0x3)));
210
211        return retval;
212}
213
[28950f0b]214static int pcif_cfg_r8(pci_dev_t dev, int ofs, uint8_t *val)
[46e41c98]215{
216        uint32_t v;
217        int retval;
218
219        retval = pcif_cfg_r32(dev, ofs & ~0x3, &v);
220
221        *val = 0xff & (v >> (8*(ofs & 3)));
222
223        return retval;
224}
225
[28950f0b]226static int pcif_cfg_w32(pci_dev_t dev, int ofs, uint32_t val)
[46e41c98]227{
228        struct pcif_priv *priv = pcifpriv;
229        volatile uint32_t *pci_conf;
[51347053]230        uint32_t devfn;
[46e41c98]231        int bus = PCI_DEV_BUS(dev);
232
233        if (ofs & ~0xfc)
234                return PCISTS_EINVAL;
235
[51347053]236        if (PCI_DEV_SLOT(dev) > 15)
[46e41c98]237                return PCISTS_MSTABRT;
238
[51347053]239        /* PCIF can access "non-standard" devices on bus0 (on AD11.AD16),
240         * but we skip them.
241         */
242        if (dev == HOST_TGT)
243                bus = devfn = 0;
[3c236cc]244        else if (bus == 0)
[51347053]245                devfn = PCI_DEV_DEVFUNC(dev) + PCI_DEV(0, 6, 0);
246        else
247                devfn = PCI_DEV_DEVFUNC(dev);
248
[46e41c98]249        /* Select bus */
250        priv->regs->bus = bus << 16;
251
252        pci_conf = (volatile uint32_t *)(priv->pci_conf | (devfn << 8) | ofs);
253
254        *pci_conf = val;
255
256        DBG("pci_write - [%x:%x:%x] reg: 0x%x => addr: 0x%x, val: 0x%x\n",
257                PCI_DEV_EXPAND(dev), ofs, pci_conf, value);
258
259        return PCISTS_OK;
260}
261
[28950f0b]262static int pcif_cfg_w16(pci_dev_t dev, int ofs, uint16_t val)
[46e41c98]263{
264        uint32_t v;
265        int retval;
266
267        if (ofs & 1)
268                return PCISTS_EINVAL;
269
270        retval = pcif_cfg_r32(dev, ofs & ~0x3, &v);
271        if (retval != PCISTS_OK)
272                return retval;
273
274        v = (v & ~(0xffff << (8*(ofs&3)))) | ((0xffff&val) << (8*(ofs&3)));
275
276        return pcif_cfg_w32(dev, ofs & ~0x3, v);
277}
278
[28950f0b]279static int pcif_cfg_w8(pci_dev_t dev, int ofs, uint8_t val)
[46e41c98]280{
281        uint32_t v;
282        int retval;
283
284        retval = pcif_cfg_r32(dev, ofs & ~0x3, &v);
285        if (retval != PCISTS_OK)
286                return retval;
287
288        v = (v & ~(0xff << (8*(ofs&3)))) | ((0xff&val) << (8*(ofs&3)));
289
290        return pcif_cfg_w32(dev, ofs & ~0x3, v);
291}
292
293
294/* Return the assigned system IRQ number that corresponds to the PCI
295 * "Interrupt Pin" information from configuration space.
296 *
297 * The IRQ information is stored in the pcif_pci_irq_table configurable
298 * by the user.
299 *
300 * Returns the "system IRQ" for the PCI INTA#..INTD# pin in irq_pin. Returns
301 * 0xff if not assigned.
302 */
[28950f0b]303static uint8_t pcif_bus0_irq_map(pci_dev_t dev, int irq_pin)
[46e41c98]304{
305        uint8_t sysIrqNr = 0; /* not assigned */
306        int irq_group;
307
308        if ( (irq_pin >= 1) && (irq_pin <= 4) ) {
309                /* Use default IRQ decoding on PCI BUS0 according slot numbering */
310                irq_group = PCI_DEV_SLOT(dev) & 0x3;
311                irq_pin = ((irq_pin - 1) + irq_group) & 0x3;
312                /* Valid PCI "Interrupt Pin" number */
313                sysIrqNr = pcif_pci_irq_table[irq_pin];
314        }
315        return sysIrqNr;
316}
317
[28950f0b]318static int pcif_translate(uint32_t *address, int type, int dir)
[46e41c98]319{
320        /* No address translation implmented at this point */
321        return 0;
322}
323
324extern struct pci_memreg_ops pci_memreg_sparc_be_ops;
325
326/* PCIF Big-Endian PCI access routines */
327struct pci_access_drv pcif_access_drv = {
328        .cfg =
329        {
330                pcif_cfg_r8,
331                pcif_cfg_r16,
332                pcif_cfg_r32,
333                pcif_cfg_w8,
334                pcif_cfg_w16,
335                pcif_cfg_w32,
336        },
337        .io =   /* PCIF only supports Big-endian */
338        {
339                _ld8,
340                _ld_be16,
341                _ld_be32,
342                _st8,
343                _st_be16,
344                _st_be32,
345        },
346        .memreg = &pci_memreg_sparc_be_ops,
347        .translate = pcif_translate,
348};
349
350/* Initializes the PCIF core hardware
351 *
352 */
[28950f0b]353static int pcif_hw_init(struct pcif_priv *priv)
[46e41c98]354{
355        struct pcif_regs *regs;
356        uint32_t data, size;
357        int mst;
[51347053]358        pci_dev_t host = HOST_TGT;
[46e41c98]359
360        regs = priv->regs;
361
362        /* Mask PCI interrupts */
363        regs->intr = 0;
364
365        /* Get the PCIF Host PCI ID */
[d5ca821]366        pcif_cfg_r32(host, PCIR_VENDOR, &priv->devVend);
[46e41c98]367
368        /* set 1:1 mapping between AHB -> PCI memory space, for all Master cores */
369        for ( mst=0; mst<16; mst++) {
370                regs->maps[mst] = priv->pci_area;
371
372                /* Check if this register is implemented */
373                if ( regs->maps[mst] != priv->pci_area )
374                        break;
375        }
376
377        /* and map system RAM at pci address SYSTEM_MAINMEM_START. This way
378         * PCI targets can do DMA directly into CPU main memory.
379         */
380        regs->bars[0] = SYSTEM_MAINMEM_START;
381        regs->bars[1] = 0;
382        regs->bars[2] = 0;
383        regs->bars[3] = 0;
384
385        /* determine size of target BAR1 */
[d5ca821]386        pcif_cfg_w32(host, PCIR_BAR(1), 0xffffffff);
387        pcif_cfg_r32(host, PCIR_BAR(1), &size);
[46e41c98]388        priv->bar1_size = (~(size & ~0xf)) + 1;
389
[d5ca821]390        pcif_cfg_w32(host, PCIR_BAR(0), 0);
391        pcif_cfg_w32(host, PCIR_BAR(1), SYSTEM_MAINMEM_START);
392        pcif_cfg_w32(host, PCIR_BAR(2), 0);
393        pcif_cfg_w32(host, PCIR_BAR(3), 0);
394        pcif_cfg_w32(host, PCIR_BAR(4), 0);
395        pcif_cfg_w32(host, PCIR_BAR(5), 0);
[46e41c98]396
397        /* set as bus master and enable pci memory responses */ 
[d5ca821]398        pcif_cfg_r32(host, PCIR_COMMAND, &data);
399        data |= (PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN);
400        pcif_cfg_w32(host, PCIR_COMMAND, data);
[46e41c98]401
402        /* Successful */
403        return 0;
404}
405
406/* Initializes the PCIF core and driver, must be called before calling init_pci()
407 *
408 * Return values
409 *  0             Successful initalization
410 *  -1            Error during initialization, for example "PCI core not found".
411 *  -2            Error PCI controller not HOST (targets not supported)
412 *  -3            Error due to PCIF hardware initialization
413 *  -4            Error registering driver to PCI layer
414 */
[28950f0b]415static int pcif_init(struct pcif_priv *priv)
[46e41c98]416{
417        struct ambapp_apb_info *apb;
418        struct ambapp_ahb_info *ahb;
419        int pin;
420        union drvmgr_key_value *value;
421        char keyname[6];
422        struct amba_dev_info *ainfo = priv->dev->businfo;
423
424        /* Find PCI core from Plug&Play information */
425        apb = ainfo->info.apb_slv;
426        ahb = ainfo->info.ahb_slv;
427
428        /* Found PCI core, init private structure */
429        priv->irq = apb->irq;
430        priv->regs = (struct pcif_regs *)apb->start;
431
432        /* Calculate the PCI windows
433         *  AMBA->PCI Window:                       AHB SLAVE AREA0
434         *  AMBA->PCI I/O cycles Window:            AHB SLAVE AREA1 Lower half
435         *  AMBA->PCI Configuration cycles Window:  AHB SLAVE AREA1 Upper half
436         */
437        priv->pci_area     = ahb->start[0];
438        priv->pci_area_end = ahb->start[0] + ahb->mask[0];
439        priv->pci_io       = ahb->start[1];
440        priv->pci_conf     = ahb->start[1] + (ahb->mask[1] >> 1);
441        priv->pci_conf_end = ahb->start[1] + ahb->mask[1];
442
443        /* On systems where PCI I/O area and configuration area is apart of the "PCI Window"
444         * the PCI Window stops at the start of the PCI I/O area
445         */
446        if ( (priv->pci_io > priv->pci_area) && (priv->pci_io < (priv->pci_area_end-1)) ) {
447                priv->pci_area_end = priv->pci_io;
448        }
449
450        /* Init PCI interrupt assignment table to all use the interrupt routed through
451         * the PCIF core.
452         */
453        strcpy(keyname, "INTX#");
454        for (pin=1; pin<5; pin++) {
455                if ( pcif_pci_irq_table[pin-1] == 0xff ) {
456                        pcif_pci_irq_table[pin-1] = priv->irq;
457
458                        /* User may override Plug & Play IRQ */
459                        keyname[3] = 'A' + (pin-1);
460                        value = drvmgr_dev_key_get(priv->dev, keyname, KEY_TYPE_INT);
461                        if ( value )
462                                pcif_pci_irq_table[pin-1] = value->i;
463                }
464        }
465
466        priv->irq_mask = 0xf;
467        value = drvmgr_dev_key_get(priv->dev, "", KEY_TYPE_INT);
468        if ( value )
469                priv->irq_mask = value->i & 0xf;
470
471        /* This driver only support HOST systems, we check for HOST */
472        if ( priv->regs->status & 0x00000001 ) {
473                /* Target not supported */
474                return -2;
475        }
476
477        /* Init the PCI Core */
478        if ( pcif_hw_init(priv) ) {
479                return -3;
480        }
481
482        /* Down streams translation table */
483        priv->maps_down[0].name = "AMBA -> PCI MEM Window";
484        priv->maps_down[0].size = priv->pci_area_end - priv->pci_area;
485        priv->maps_down[0].from_adr = (void *)priv->pci_area;
486        priv->maps_down[0].to_adr = (void *)priv->pci_area;
487        /* End table */
488        priv->maps_down[1].size = 0;
489
490        /* Up streams translation table */
491        priv->maps_up[0].name = "Target BAR1 -> AMBA";
492        priv->maps_up[0].size = priv->bar1_size;
493        priv->maps_up[0].from_adr = (void *)SYSTEM_MAINMEM_START;
494        priv->maps_up[0].to_adr = (void *)SYSTEM_MAINMEM_START;
495        /* End table */
496        priv->maps_up[1].size = 0;
497
498        return 0;
499}
500
501/* Called when a core is found with the AMBA device and vendor ID
502 * given in pcif_ids[].
503 */
504int pcif_init1(struct drvmgr_dev *dev)
505{
506        struct pcif_priv *priv;
507        struct pci_auto_setup pcif_auto_cfg;
508
509        DBG("PCIF[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
510
511        if ( pcif_minor != 0 ) {
512                printf("Driver only supports one PCI core\n");
513                return DRVMGR_FAIL;
514        }
515
516        priv = dev->priv;
517        if ( !priv )
518                return DRVMGR_NOMEM;
519
520        dev->priv = priv;
521        priv->dev = dev;
522        priv->minor = pcif_minor++;
523
524        pcifpriv = priv;
525        if ( pcif_init(priv) ) {
526                printf("Failed to initialize PCIF driver\n");
527                free(priv);
528                dev->priv = NULL;
529                return DRVMGR_FAIL;
530        }
531
532        /* Host is always Big-Endian */
533        pci_endian = PCI_BIG_ENDIAN;
534
535        /* Register the PCI core at the PCI layer */
536
537        if (pci_access_drv_register(&pcif_access_drv)) {
538                /* Access routines registration failed */
539                return DRVMGR_FAIL;
540        }
541
542        /* Prepare memory MAP */
543        pcif_auto_cfg.options = 0;
544        pcif_auto_cfg.mem_start = 0;
545        pcif_auto_cfg.mem_size = 0;
546        pcif_auto_cfg.memio_start = priv->pci_area;
547        pcif_auto_cfg.memio_size = priv->pci_area_end - priv->pci_area;
548        pcif_auto_cfg.io_start = priv->pci_io;
549        pcif_auto_cfg.io_size = priv->pci_conf - priv->pci_io;
550        pcif_auto_cfg.irq_map = pcif_bus0_irq_map;
551        pcif_auto_cfg.irq_route = NULL; /* use standard routing */
552        pci_config_register(&pcif_auto_cfg);
553
554        if (pci_config_init()) {
555                /* PCI configuration failed */
556                return DRVMGR_FAIL;
557        }
558
559        priv->config.maps_down = &priv->maps_down[0];
560        priv->config.maps_up = &priv->maps_up[0];
561        return pcibus_register(dev, &priv->config);
562}
563
564int pcif_init3(struct drvmgr_dev *dev)
565{
566        struct pcif_priv *priv = dev->priv;
567
568        /* Unmask all interrupts, on some sytems this
569         * might be problematic because all PCI IRQs are
570         * not connected on the PCB or used for something
571         * else. The irqMask driver resource can be used to
572         * control which PCI IRQs are used to generate the
573         * PCI system IRQ, example:
574         *
575         * 0xf - enable all  (DEFAULT)
576         * 0x8 - enable one PCI irq
577         *
578         * Before unmasking PCI IRQ, all PCI boards must
579         * have been initialized and IRQ turned off to avoid
580         * system hang.
581         */
582
583        priv->regs->intr = priv->irq_mask;
584
585        return DRVMGR_OK;
586}
Note: See TracBrowser for help on using the repository browser.