source: rtems/c/src/lib/libbsp/sparc/shared/pci/pcif.c @ 3c236cc

4.115
Last change on this file since 3c236cc was 3c236cc, checked in by Daniel Hellstrom <daniel@…>, on 02/05/14 at 16:17:53

LEON PCI: fix for PCI host bridge driver CFG space access

  • Property mode set to 100644
File size: 14.1 KB
Line 
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
16 *  http://www.rtems.com/license/LICENSE.
17 */
18
19#include <stdio.h>
20#include <stdlib.h>
21#include <string.h>
22#include <libcpu/byteorder.h>
23#include <libcpu/access.h>
24#include <pci.h>
25#include <pci/cfg.h>
26
27#include <drvmgr/drvmgr.h>
28#include <drvmgr/ambapp_bus.h>
29#include <ambapp.h>
30#include <drvmgr/pci_bus.h>
31
32#include <pci.h>
33#include <rtems/bspIo.h>
34#include <string.h>
35
36/* Configuration options */
37#define SYSTEM_MAINMEM_START 0x40000000
38
39/* Interrupt assignment. Set to other value than 0xff in order to
40 * override defaults and plug&play information
41 */
42#ifndef PCIF_INTA_SYSIRQ
43 #define PCIF_INTA_SYSIRQ 0xff
44#endif
45#ifndef PCIF_INTB_SYSIRQ
46 #define PCIF_INTB_SYSIRQ 0xff
47#endif
48#ifndef PCIF_INTC_SYSIRQ
49 #define PCIF_INTC_SYSIRQ 0xff
50#endif
51#ifndef PCIF_INTD_SYSIRQ
52 #define PCIF_INTD_SYSIRQ 0xff
53#endif
54
55/*#define DEBUG 1  */
56
57#ifdef DEBUG
58#define DBG(x...) printk(x)
59#else
60#define DBG(x...)
61#endif
62
63/*
64 * Bit encode for PCI_CONFIG_HEADER_TYPE register
65 */
66struct pcif_regs {
67        volatile unsigned int bars[4];  /* 0x00-0x10 */
68        volatile unsigned int bus;      /* 0x10 */
69        volatile unsigned int map_io;   /* 0x14 */
70        volatile unsigned int status;   /* 0x18 */
71        volatile unsigned int intr;     /* 0x1c */
72        int unused[(0x40-0x20)/4];      /* 0x20-0x40 */
73        volatile unsigned int maps[(0x80-0x40)/4];   /* 0x40-0x80*/
74};
75
76/* Used internally for accessing the PCI bridge's configuration space itself */
77#define HOST_TGT PCI_DEV(0xff, 0, 0)
78
79struct pcif_priv *pcifpriv = NULL;
80static int pcif_minor = 0;
81
82/* PCI Interrupt assignment. Connects an PCI interrupt pin (INTA#..INTD#)
83 * to a system interrupt number.
84 */
85unsigned char pcif_pci_irq_table[4] =
86{
87        /* INTA# */     PCIF_INTA_SYSIRQ,
88        /* INTB# */     PCIF_INTB_SYSIRQ,
89        /* INTC# */     PCIF_INTC_SYSIRQ,
90        /* INTD# */     PCIF_INTD_SYSIRQ
91};
92
93/* Driver private data struture */
94struct pcif_priv {
95        struct drvmgr_dev       *dev;
96        struct pcif_regs                *regs;
97        int                             irq;
98        int                             minor;
99        int                             irq_mask;
100
101        unsigned int                    pci_area;
102        unsigned int                    pci_area_end;
103        unsigned int                    pci_io;   
104        unsigned int                    pci_conf;
105        unsigned int                    pci_conf_end;
106
107        uint32_t                        devVend; /* Host PCI Vendor/Device ID */
108        uint32_t                        bar1_size;
109
110        struct drvmgr_map_entry         maps_up[2];
111        struct drvmgr_map_entry         maps_down[2];
112        struct pcibus_config            config;
113};
114
115int pcif_init1(struct drvmgr_dev *dev);
116int pcif_init3(struct drvmgr_dev *dev);
117
118/* PCIF DRIVER */
119
120struct drvmgr_drv_ops pcif_ops =
121{
122        .init = {pcif_init1, NULL, pcif_init3, NULL},
123        .remove = NULL,
124        .info = NULL
125};
126
127struct amba_dev_id pcif_ids[] =
128{
129        {VENDOR_GAISLER, GAISLER_PCIF},
130        {0, 0}          /* Mark end of table */
131};
132
133struct amba_drv_info pcif_info =
134{
135        {
136                DRVMGR_OBJ_DRV,                 /* Driver */
137                NULL,                           /* Next driver */
138                NULL,                           /* Device list */
139                DRIVER_AMBAPP_GAISLER_PCIF_ID,  /* Driver ID */
140                "PCIF_DRV",                     /* Driver Name */
141                DRVMGR_BUS_TYPE_AMBAPP,         /* Bus Type */
142                &pcif_ops,
143                NULL,                           /* Funcs */
144                0,                              /* No devices yet */
145                sizeof(struct pcif_priv),       /* Let drvmgr alloc private */
146        },
147        &pcif_ids[0]
148};
149
150void pcif_register_drv(void)
151{
152        DBG("Registering PCIF driver\n");
153        drvmgr_drv_register(&pcif_info.general);
154}
155
156int pcif_cfg_r32(pci_dev_t dev, int ofs, uint32_t *val)
157{
158        struct pcif_priv *priv = pcifpriv;
159        volatile uint32_t *pci_conf;
160        uint32_t devfn;
161        int retval;
162        int bus = PCI_DEV_BUS(dev);
163
164        if (ofs & 3)
165                return PCISTS_EINVAL;
166
167        if (PCI_DEV_SLOT(dev) > 15) {
168                *val = 0xffffffff;
169                return PCISTS_OK;
170        }
171
172        /* PCIF can access "non-standard" devices on bus0 (on AD11.AD16),
173         * but we skip them.
174         */
175        if (dev == HOST_TGT)
176                bus = devfn = 0;
177        else if (bus == 0)
178                devfn = PCI_DEV_DEVFUNC(dev) + PCI_DEV(0, 6, 0);
179        else
180                devfn = PCI_DEV_DEVFUNC(dev);
181
182        /* Select bus */
183        priv->regs->bus = bus << 16;
184
185        pci_conf = (volatile uint32_t *)(priv->pci_conf | (devfn << 8) | ofs);
186
187        *val = *pci_conf;
188
189        if (priv->regs->status & 0x30000000) {
190                *val = 0xffffffff;
191                retval = PCISTS_MSTABRT;
192        } else
193                retval = PCISTS_OK;
194
195        DBG("pci_read: [%x:%x:%x] reg: 0x%x => addr: 0x%x, val: 0x%x\n",
196                PCI_DEV_EXPAND(dev), ofs, pci_conf, *val);
197
198        return retval;
199}
200int pcif_cfg_r16(pci_dev_t dev, int ofs, uint16_t *val)
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
214int pcif_cfg_r8(pci_dev_t dev, int ofs, uint8_t *val)
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
226int pcif_cfg_w32(pci_dev_t dev, int ofs, uint32_t val)
227{
228        struct pcif_priv *priv = pcifpriv;
229        volatile uint32_t *pci_conf;
230        uint32_t devfn;
231        int bus = PCI_DEV_BUS(dev);
232
233        if (ofs & ~0xfc)
234                return PCISTS_EINVAL;
235
236        if (PCI_DEV_SLOT(dev) > 15)
237                return PCISTS_MSTABRT;
238
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;
244        else if (bus == 0)
245                devfn = PCI_DEV_DEVFUNC(dev) + PCI_DEV(0, 6, 0);
246        else
247                devfn = PCI_DEV_DEVFUNC(dev);
248
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
262int pcif_cfg_w16(pci_dev_t dev, int ofs, uint16_t val)
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
279int pcif_cfg_w8(pci_dev_t dev, int ofs, uint8_t val)
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 */
303uint8_t pcif_bus0_irq_map(pci_dev_t dev, int irq_pin)
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
318int pcif_translate(uint32_t *address, int type, int dir)
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 */
353int pcif_hw_init(struct pcif_priv *priv)
354{
355        struct pcif_regs *regs;
356        uint32_t data, size;
357        int mst;
358        pci_dev_t host = HOST_TGT;
359
360        regs = priv->regs;
361
362        /* Mask PCI interrupts */
363        regs->intr = 0;
364
365        /* Get the PCIF Host PCI ID */
366        pcif_cfg_r32(host, PCI_VENDOR_ID, &priv->devVend);
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 */
386        pcif_cfg_w32(host, PCI_BASE_ADDRESS_1, 0xffffffff);
387        pcif_cfg_r32(host, PCI_BASE_ADDRESS_1, &size);
388        priv->bar1_size = (~(size & ~0xf)) + 1;
389
390        pcif_cfg_w32(host, PCI_BASE_ADDRESS_0, 0);
391        pcif_cfg_w32(host, PCI_BASE_ADDRESS_1, SYSTEM_MAINMEM_START);
392        pcif_cfg_w32(host, PCI_BASE_ADDRESS_2, 0);
393        pcif_cfg_w32(host, PCI_BASE_ADDRESS_3, 0);
394        pcif_cfg_w32(host, PCI_BASE_ADDRESS_4, 0);
395        pcif_cfg_w32(host, PCI_BASE_ADDRESS_5, 0);
396
397        /* set as bus master and enable pci memory responses */ 
398        pcif_cfg_r32(host, PCI_COMMAND, &data);
399        data |= (PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
400        pcif_cfg_w32(host, PCI_COMMAND, data);
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 */
415int pcif_init(struct pcif_priv *priv)
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.