source: rtems/c/src/lib/libbsp/shared/vmeUniverse/vmeTsi148.c @ 6f10ffe

4.104.114.84.95
Last change on this file since 6f10ffe was 6f10ffe, checked in by Till Straumann <strauman@…>, on 01/27/06 at 00:35:27

2006-01-26 Till Straumann <strauman@…>

  • vmeUniverse/vmeTsi148.c, vmeUniverse/vmeUniverse.c, vmeUniverse/vmeUniverse.h, vmeUniverse/vme_amd_defs.h: Added 2F address modifier for VME64 CSR access.
  • Property mode set to 100644
File size: 39.2 KB
Line 
1/* $Id$ */
2
3/* Routines to configure the VME interface
4 * Author: Till Straumann <strauman@slac.stanford.edu>
5 *         Nov 2000, Oct 2001, Jan 2002
6 */
7
8#include <rtems.h>
9#include <stdio.h>
10#include <stdarg.h>
11#include <bsp/irq.h>
12#include <stdlib.h>
13#include <rtems/bspIo.h>        /* printk */
14#include <rtems/error.h>        /* printk */
15#include <bsp/pci.h>
16#include <bsp.h>
17#include <libcpu/byteorder.h>
18
19#include "vmeTsi148.h"
20
21#define STATIC static
22
23/* The tsi has 4 'local' wires that can be hooked to a PIC */
24
25#define TSI_NUM_WIRES                   4
26
27#define TSI148_NUM_OPORTS               8 /* number of outbound ports */
28#define TSI148_NUM_IPORTS               8 /* number of inbound  ports */
29
30#define NUM_TSI_DEVS                    2 /* number of instances supported */
31
32#define PCI_VENDOR_TUNDRA       0x10e3
33#define PCI_DEVICE_TSI148       0x0148
34
35#define TSI_OTSAU_SPACING       0x020
36
37#define TSI_OTSAU0_REG          0x100
38#define TSI_OTSAL0_REG          0x104
39#define TSI_OTEAU0_REG          0x108
40#define TSI_OTEAL0_REG          0x10c
41#define TSI_OTOFU0_REG          0x110
42#define TSI_OTOFL0_REG          0x114
43#define TSI_OTBS0_REG           0x118   /* 2eSST broadcast select */
44#define TSI_OTAT0_REG           0x11c
45#define TSI_OTSAU_REG(port)     (TSI_OTSAU0_REG + ((port)<<5))
46#define TSI_OTSAL_REG(port)     (TSI_OTSAL0_REG + ((port)<<5))
47#define TSI_OTEAU_REG(port)     (TSI_OTEAU0_REG + ((port)<<5))
48#define TSI_OTEAL_REG(port)     (TSI_OTEAL0_REG + ((port)<<5))
49#define TSI_OTOFU_REG(port)     (TSI_OTOFU0_REG + ((port)<<5))
50#define TSI_OTOFL_REG(port)     (TSI_OTOFL0_REG + ((port)<<5))
51#define TSI_OTBS_REG(port)      (TSI_OTBS0_REG + ((port)<<5))
52#define TSI_OTAT_REG(port)      (TSI_OTAT0_REG + ((port)<<5))
53#       define TSI_OTAT_EN                      (1<<31)
54#       define TSI_OTAT_MRPFD           (1<<18)
55#       define TSI_OTAT_PFS(x)          (((x)&3)<<16)
56#       define TSI_OTAT_2eSSTM(x)       (((x)&7)<<11)
57#       define TSI_OTAT_TM(x)           (((x)&7)<<8)
58#       define TSI_OTAT_DBW(x)          (((x)&3)<<6)
59#       define TSI_OTAT_SUP                     (1<<5)
60#       define TSI_OTAT_PGM                     (1<<4)
61#       define TSI_OTAT_ADMODE(x)       (((x)&0xf))
62#       define TSI_OTAT_ADMODE_A16      0
63#       define TSI_OTAT_ADMODE_A24      1
64#       define TSI_OTAT_ADMODE_A32      2
65#       define TSI_OTAT_ADMODE_A64      4
66#       define TSI_OTAT_ADMODE_CSR      5
67#       define TSI_OTAT_ADMODE_USR1     8
68#       define TSI_OTAT_ADMODE_USR2     9
69#       define TSI_OTAT_ADMODE_USR3     0xa
70#       define TSI_OTAT_ADMODE_USR4     0xb
71
72#define TSI_VIACK_1_REG         0x204
73
74#define TSI_VEAU_REG            0x260
75#define TSI_VEAL_REG            0x264
76#define TSI_VEAT_REG            0x268
77
78#define TSI_ITSAU_SPACING       0x020
79
80#define TSI_ITSAU0_REG          0x300
81#define TSI_ITSAL0_REG          0x304
82#define TSI_ITEAU0_REG          0x308
83#define TSI_ITEAL0_REG          0x30c
84#define TSI_ITOFU0_REG          0x310
85#define TSI_ITOFL0_REG          0x314
86#define TSI_ITAT0_REG           0x318
87#define TSI_ITSAU_REG(port)     (TSI_ITSAU0_REG + ((port)<<5))
88#define TSI_ITSAL_REG(port)     (TSI_ITSAL0_REG + ((port)<<5))
89#define TSI_ITEAU_REG(port)     (TSI_ITEAU0_REG + ((port)<<5))
90#define TSI_ITEAL_REG(port)     (TSI_ITEAL0_REG + ((port)<<5))
91#define TSI_ITOFU_REG(port)     (TSI_ITOFU0_REG + ((port)<<5))
92#define TSI_ITOFL_REG(port)     (TSI_ITOFL0_REG + ((port)<<5))
93#define TSI_ITAT_REG(port)      (TSI_ITAT0_REG + ((port)<<5))
94
95#       define TSI_ITAT_EN                      (1<<31)
96#       define TSI_ITAT_TH                      (1<<18)
97#       define TSI_ITAT_VFS(x)          (((x)&3)<<16)
98#       define TSI_ITAT_2eSSTM(x)       (((x)&7)<<12)
99#       define TSI_ITAT_2eSSTB          (1<<11)
100#       define TSI_ITAT_2eSST           (1<<10)
101#       define TSI_ITAT_2eVME           (1<<9)
102#       define TSI_ITAT_MBLT            (1<<8)
103#       define TSI_ITAT_BLT                     (1<<7)
104#       define TSI_ITAT_AS(x)           (((x)&7)<<4)
105#       define TSI_ITAT_ADMODE_A16      (0<<4)
106#       define TSI_ITAT_ADMODE_A24      (1<<4)
107#       define TSI_ITAT_ADMODE_A32      (2<<4)
108#       define TSI_ITAT_ADMODE_A64      (4<<4)
109#       define TSI_ITAT_SUP                     (1<<3)
110#       define TSI_ITAT_USR                     (1<<2)
111#       define TSI_ITAT_PGM                     (1<<1)
112#       define TSI_ITAT_DATA            (1<<0)
113
114#define TSI_VICR_REG            0x440
115#   define TSI_VICR_CNTS(v)             (((v)&3)<<30)
116#   define TSI_VICR_CNTS_DIS    (0<<30)
117#   define TSI_VICR_CNTS_IRQ1   (1<<30)
118#   define TSI_VICR_CNTS_IRQ2   (2<<30)
119#   define TSI_VICR_EDGIS(v)    (((v)&3)<<28)
120#   define TSI_VICR_EDGIS_DIS   (0<<28)
121#   define TSI_VICR_EDGIS_IRQ1  (1<<28)
122#   define TSI_VICR_EDGIS_IRQ2  (2<<28)
123#   define TSI_VICR_IRQ1F(v)    (((v)&3)<<26)
124#   define TSI_VICR_IRQ1F_NORML (0<<26)
125#   define TSI_VICR_IRQ1F_PULSE (1<<26)
126#   define TSI_VICR_IRQ1F_CLOCK (2<<26)
127#   define TSI_VICR_IRQ1F_1MHZ  (3<<26)
128#   define TSI_VICR_IRQ2F(v)    (((v)&3)<<24)
129#   define TSI_VICR_IRQ2F_NORML (0<<24)
130#   define TSI_VICR_IRQ2F_PULSE (1<<24)
131#   define TSI_VICR_IRQ2F_CLOCK (2<<24)
132#   define TSI_VICR_IRQ2F_1MHZ  (3<<24)
133#   define TSI_VICR_BIP                 (1<<23)
134#   define TSI_VICR_BIPS                (1<<22)
135#   define TSI_VICR_IRQC                (1<<15)
136#   define TSI_VICR_IRQLS(v)    (((v)&7)<<12)
137#   define TSI_VICR_IRQS                (1<<11)
138#   define TSI_VICR_IRQL(v)             (((v)&7)<<8)
139#   define TSI_VICR_STID(v)             ((v)&0xff)
140#define TSI_INTEN_REG           0x448
141#define TSI_INTEO_REG           0x44c
142#define TSI_INTS_REG            0x450
143#   define TSI_INTS_IRQ1S       (1<<1)
144#   define TSI_INTS_IRQ2S       (1<<2)
145#   define TSI_INTS_IRQ3S       (1<<3)
146#   define TSI_INTS_IRQ4S       (1<<4)
147#   define TSI_INTS_IRQ5S       (1<<5)
148#   define TSI_INTS_IRQ6S       (1<<6)
149#   define TSI_INTS_IRQ7S       (1<<7)
150#   define TSI_INTS_ACFLS       (1<<8)
151#   define TSI_INTS_SYSFLS      (1<<9)
152#   define TSI_INTS_IACKS       (1<<10)
153#   define TSI_INTS_VIES        (1<<11)
154#   define TSI_INTS_VERRS       (1<<12)
155#   define TSI_INTS_PERRS       (1<<13)
156#   define TSI_INTS_MB0S        (1<<16)
157#   define TSI_INTS_MB1S        (1<<17)
158#   define TSI_INTS_MB2S        (1<<18)
159#   define TSI_INTS_MB3S        (1<<19)
160#   define TSI_INTS_LM0S        (1<<20)
161#   define TSI_INTS_LM1S        (1<<21)
162#   define TSI_INTS_LM2S        (1<<22)
163#   define TSI_INTS_LM3S        (1<<23)
164#   define TSI_INTS_DMA0S       (1<<24)
165#   define TSI_INTS_DMA1S       (1<<25)
166#define TSI_INTC_REG            0x454
167#   define TSI_INTC_ACFLC       (1<<8)
168#   define TSI_INTC_SYSFLC      (1<<9)
169#   define TSI_INTC_IACKC       (1<<10)
170#   define TSI_INTC_VIEC        (1<<11)
171#   define TSI_INTC_VERRC       (1<<12)
172#   define TSI_INTC_PERRC       (1<<13)
173#   define TSI_INTC_MB0C        (1<<16)
174#   define TSI_INTC_MB1C        (1<<17)
175#   define TSI_INTC_MB2C        (1<<18)
176#   define TSI_INTC_MB3C        (1<<19)
177#   define TSI_INTC_LM0C        (1<<20)
178#   define TSI_INTC_LM1C        (1<<21)
179#   define TSI_INTC_LM2C        (1<<22)
180#   define TSI_INTC_LM3C        (1<<23)
181#   define TSI_INTC_DMA0C       (1<<24)
182#   define TSI_INTC_DMA1C       (1<<25)
183#define TSI_INTM1_REG           0x458
184#define TSI_INTM2_REG           0x45c
185
186
187#define TSI_RD(base, reg)                               in_be32(((base) + (reg)/sizeof(*base)))
188#define TSI_RD16(base, reg)                             in_be16((volatile unsigned short *)(base) + (reg)/sizeof(short))
189#define TSI_RD8(base, reg)                              *((volatile unsigned char *)(base) + (reg))
190#define TSI_WR(base, reg, val)                  out_be32(((base) + (reg)/sizeof(*base)), val)
191
192#define UNIV_SCTL_AM_MASK       (UNIV_CTL_VAS | UNIV_SCTL_PGM | UNIV_SCTL_DAT | UNIV_SCTL_USER | UNIV_SCTL_SUPER)
193
194
195/* allow the BSP to override the default routines */
196#ifndef BSP_PCI_FIND_DEVICE
197#define BSP_PCI_FIND_DEVICE             pci_find_device
198#endif
199#ifndef BSP_PCI_CONFIG_IN_LONG
200#define BSP_PCI_CONFIG_IN_LONG  pci_read_config_dword
201#endif
202#ifndef BSP_PCI_CONFIG_IN_SHORT
203#define BSP_PCI_CONFIG_IN_SHORT pci_read_config_word
204#endif
205#ifndef BSP_PCI_CONFIG_OUT_SHORT
206#define BSP_PCI_CONFIG_OUT_SHORT pci_write_config_word
207#endif
208#ifndef BSP_PCI_CONFIG_IN_BYTE
209#define BSP_PCI_CONFIG_IN_BYTE  pci_read_config_byte
210#endif
211
212typedef unsigned int pci_ulong;
213
214/* PCI_MEM_BASE is a possible offset between CPU- and PCI addresses.
215 * Should be defined by the BSP.
216 */
217#define PCI_TO_LOCAL_ADDR(memaddr) ((pci_ulong)(memaddr) + PCI_MEM_BASE)
218
219typedef struct {
220        BERegister *base;
221        int                     irqLine;
222        int                     pic_pin[TSI_NUM_WIRES];
223} Tsi148Dev;
224
225static Tsi148Dev devs[NUM_TSI_DEVS] = {{0}};
226
227/* registers should be mapped to guarded, non-cached memory; hence
228 * subsequent stores are ordered. eieio is only needed to enforce
229 * ordering of loads with respect to stores.
230 */
231
232/* private printing wrapper */
233static void
234uprintf(FILE *f, char *fmt, ...)
235{
236va_list ap;
237        va_start(ap, fmt);
238        if (!f || !_impure_ptr->__sdidinit) {
239                /* Might be called at an early stage when
240                 * to a buffer.
241                 */
242                vprintk(fmt,ap);
243        } else
244        {
245                vfprintf(f,fmt,ap);
246        }
247        va_end(ap);
248}
249
250#define CHECK_BASE(base,quiet,rval)     \
251        do {                                                    \
252                if ( !base ) {                          \
253                        if ( !quiet ) {                 \
254                                uprintf(stderr,"Tsi148: Driver not initialized\n");     \
255                        }                                               \
256                        return rval;                    \
257                }                                                       \
258        } while (0)
259
260int
261vmeTsi148FindPciBase(
262        int instance,
263        BERegister **pbase
264        )
265{
266int                                     bus,dev,fun;
267pci_ulong                       busaddr;
268unsigned char           irqline;
269unsigned short          wrd;
270
271        if (BSP_PCI_FIND_DEVICE(
272                        PCI_VENDOR_TUNDRA,
273                        PCI_DEVICE_TSI148,
274                        instance,
275                        &bus,
276                        &dev,
277                        &fun))
278                return -1;
279        if (BSP_PCI_CONFIG_IN_LONG(bus,dev,fun,PCI_BASE_ADDRESS_0,&busaddr))
280                return -1;
281        /* Assume upper BAR is zero */
282
283        *pbase=(BERegister*)(PCI_TO_LOCAL_ADDR(busaddr) & ~0xff);
284
285        if (BSP_PCI_CONFIG_IN_BYTE(bus,dev,fun,PCI_INTERRUPT_LINE,&irqline))
286                return -1;
287
288        /* Enable PCI master and memory access */
289        BSP_PCI_CONFIG_IN_SHORT(bus, dev, fun, PCI_COMMAND, &wrd);
290        BSP_PCI_CONFIG_OUT_SHORT(bus, dev, fun, PCI_COMMAND, wrd | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
291
292        return irqline;
293}
294
295int
296vmeTsi148InitInstance(unsigned instance)
297{
298int                                     irq;
299BERegister *base;
300
301        if ( instance >= NUM_TSI_DEVS )
302                return  -1;
303        if ( devs[instance].base )
304                return  -1;
305
306        if ((irq=vmeTsi148FindPciBase(instance,&base)) < 0) {
307                uprintf(stderr,"unable to find a Tsi148 in pci config space\n");
308        } else {
309                uprintf(stderr,"Tundra Tsi148 PCI-VME bridge detected at 0x%08x, IRQ %d\n",
310                                (unsigned int)base, irq);
311        }
312        devs[0].base    = base;
313        devs[0].irqLine = irq;
314
315        return irq < 0 ? -1 : 0;
316}
317
318int
319vmeTsi148Init(void)
320{
321        return vmeTsi148InitInstance(0);
322}
323
324
325void
326vmeTsi148ResetXX(BERegister *base)
327{
328int port;
329
330        CHECK_BASE(base,0, );
331
332        vmeTsi148DisableAllOutboundPortsXX(base);
333        for ( port=0; port < TSI148_NUM_OPORTS; port++ )
334                TSI_WR(base, TSI_OTBS_REG(port), 0);
335        TSI_WR(base, TSI_INTEO_REG, 0);
336        TSI_WR(base, TSI_INTEN_REG, 0);
337        TSI_WR(base, TSI_INTC_REG, 0xffffffff);
338        TSI_WR(base, TSI_INTM1_REG, 0);
339        TSI_WR(base, TSI_INTM2_REG, 0);
340        TSI_WR(base, TSI_VICR_REG, 0);
341        TSI_WR(base, TSI_VEAT_REG, TSI_VEAT_VESCL);
342}
343
344void
345vmeTsi148Reset()
346{
347        vmeTsi148ResetXX(devs[0].base);
348}
349
350/* convert an address space selector to a corresponding
351 * Tsi148 control mode word
352 */
353
354STATIC int
355am2omode(unsigned long address_space, unsigned long *pmode)
356{
357unsigned long mode=0;
358unsigned long tm, mask;
359
360        if ( ! (VME_MODE_DBW32_DISABLE  & address_space ) )
361                mode |= TSI_OTAT_DBW(1);
362        if ( ! (VME_MODE_PREFETCH_ENABLE & address_space) )
363                mode |= TSI_OTAT_MRPFD;
364        else {
365                mode |= TSI_OTAT_PFS(address_space>>12);
366        }
367        mode |= TSI_OTAT_2eSSTM(address_space>>16);
368
369        for ( tm = 1, mask = VME_MODE_BLT; ! (mask & address_space); tm++, mask<<=1 ) {
370                if ( VME_MODE_2eSST_BCST == mask ) {
371                        tm = 0; /* select default: BLT enabled */
372                        break;
373                }
374        }
375        mode |= TSI_OTAT_TM(tm);
376
377        switch (address_space & VME_AM_MASK) {
378                case VME_AM_STD_SUP_PGM:
379                case VME_AM_STD_USR_PGM:
380
381                        mode |= TSI_OTAT_PGM;
382
383                        /* fall thru */
384                case VME_AM_STD_SUP_DATA:
385                case VME_AM_STD_USR_DATA:
386
387                        mode |= TSI_OTAT_ADMODE_A24;
388                        break;
389
390                case VME_AM_EXT_SUP_PGM:
391                case VME_AM_EXT_USR_PGM:
392                        mode |= TSI_OTAT_PGM;
393
394                        /* fall thru */
395                case VME_AM_EXT_SUP_DATA:
396                case VME_AM_EXT_USR_DATA:
397                        mode |= TSI_OTAT_ADMODE_A32;
398                        break;
399
400                case VME_AM_SUP_SHORT_IO:
401                case VME_AM_USR_SHORT_IO:
402                        mode |= TSI_OTAT_ADMODE_A16;
403                        break;
404
405                case VME_AM_CSR:
406                        mode |= TSI_OTAT_ADMODE_CSR;
407                        break;
408
409                case 0: /* disable the port alltogether */
410                        break;
411
412                default:
413                        return -1;
414        }
415        if ( VME_AM_IS_SUP(address_space) )
416                mode |= TSI_OTAT_SUP;
417        *pmode = mode;
418        return 0;
419}
420
421STATIC int
422am2imode(unsigned long address_space, unsigned long *pmode)
423{
424unsigned long mode=0;
425unsigned long tm, mask;
426
427        mode |= TSI_ITAT_VFS(address_space>>12);
428        mode |= TSI_ITAT_2eSSTM(address_space>>16);
429
430        mode |= TSI_ITAT_BLT;
431
432        mask = VME_MODE_BLT;
433        tm = TSI_ITAT_BLT;
434        do {
435                mask<<=1; tm<<=1;
436                if ( address_space & mask )
437                        mode |= tm;
438        } while ( TSI_ITAT_2eSSTB != tm );
439
440        tm = 0;
441
442        switch (address_space & VME_AM_MASK) {
443                case VME_AM_STD_SUP_PGM:
444                case VME_AM_STD_USR_PGM:
445
446                        tm = 1;
447
448                        /* fall thru */
449                case VME_AM_STD_SUP_DATA:
450                case VME_AM_STD_USR_DATA:
451
452                        mode |= TSI_ITAT_ADMODE_A24;
453                        break;
454
455                case VME_AM_EXT_SUP_PGM:
456                case VME_AM_EXT_USR_PGM:
457                        tm = 1;
458
459                        /* fall thru */
460                case VME_AM_EXT_SUP_DATA:
461                case VME_AM_EXT_USR_DATA:
462                        mode |= TSI_ITAT_ADMODE_A32;
463                        break;
464
465                case VME_AM_SUP_SHORT_IO:
466                case VME_AM_USR_SHORT_IO:
467                        mode |= TSI_ITAT_ADMODE_A16;
468                        break;
469
470                case 0: /* disable the port alltogether */
471                        *pmode = 0;
472                        return 0;
473
474                default:
475                        return -1;
476        }
477
478        if ( VME_AM_IS_SUP(address_space) )
479                mode |= TSI_ITAT_SUP;
480        else
481                mode |= TSI_ITAT_USR;
482
483        if ( tm )
484                mode |= TSI_ITAT_PGM;
485        else
486                mode |= TSI_ITAT_DATA;
487
488        *pmode = mode;
489        return 0;
490}
491
492static void
493readTriple(
494        BERegister *base,
495        unsigned reg,
496        unsigned long long *ps,
497        unsigned long long *pl,
498        unsigned long long *po)
499{
500        *ps = TSI_RD(base, reg);
501        *ps = (*ps<<32) | (TSI_RD(base, (reg+4)) & 0xffff0000);
502        *pl = TSI_RD(base, (reg+8));
503        *pl = (*pl<<32) | (TSI_RD(base, (reg+0xc)) & 0xffff0000);
504        *po = TSI_RD(base, (reg+0x10));
505        *po = (*po<<32) | (TSI_RD(base, (reg+0x14)) & 0xffff0000);
506}
507
508
509static unsigned long
510inboundGranularity(unsigned long itat)
511{
512        switch ( itat & TSI_ITAT_AS(-1) ) {
513                case TSI_ITAT_ADMODE_A16:       return 0xf;
514                case TSI_ITAT_ADMODE_A24:       return 0xfff;
515                default:
516                break;
517        }
518        return 0xffff;
519}
520
521static int
522configTsiPort(
523        BERegister              *base,
524        int                             isout,
525        unsigned long   port,
526        unsigned long   address_space,
527        unsigned long   vme_address,
528        unsigned long   pci_address,
529        unsigned long   length)
530{
531unsigned long long      start, limit, offst;
532unsigned long           mode, mask, tat_reg, tsau_reg;
533char                            *name = (isout ? "Outbound" : "Inbound");
534
535        CHECK_BASE(base,0,-1);
536
537        mode = 0; /* silence warning */
538
539        if ( port >= (isout ? TSI148_NUM_OPORTS : TSI148_NUM_IPORTS) ) {
540                uprintf(stderr,"Tsi148 %s Port Cfg: invalid port\n", name);
541                return -1;
542        }
543
544        if ( length && (isout ? am2omode(address_space, &mode) : am2imode(address_space, &mode)) ) {
545                uprintf(stderr,"Tsi148 %s Port Cfg: invalid address space / mode flags\n",name);
546                return -1;
547        }
548
549
550        if ( isout ) {
551                start     = pci_address;
552                offst     = (unsigned long long)vme_address - start;
553                mask      = 0xffff;
554                tat_reg   = TSI_OTAT_REG(port);
555                tsau_reg  = TSI_OTSAU_REG(port);
556                mode     |= TSI_OTAT_EN;
557        } else {
558                start     = vme_address;
559                offst     = (unsigned long long)pci_address - start;
560                mask      = inboundGranularity(mode);
561                tat_reg   = TSI_ITAT_REG(port);
562                tsau_reg  = TSI_ITSAU_REG(port);
563                mode     |= TSI_ITAT_EN;
564        }
565
566        /* If they pass 'length==0' just disable */
567        if ( 0 == length ) {
568                TSI_WR(base, tat_reg, TSI_RD(base, tat_reg) & ~(isout ? TSI_OTAT_EN : TSI_ITAT_EN));
569                return 0;
570        }
571
572
573        if (   (vme_address & mask)
574            || (pci_address & mask)
575            || (length      & mask) ) {
576                uprintf(stderr,"Tsi148 %s Port Cfg: invalid address/length; must be multiple of 0x%x\n",
577                                name,
578                                mask+1);
579                return -1;
580        }
581
582        limit  = start + length - 1;
583
584        if ( limit >= (unsigned long long)1<<32 ) {
585                uprintf(stderr,"Tsi148 %s Port Cfg: invalid address/length; must be < 1<<32\n", name);
586                return -1;
587        }
588
589        /* Disable port */
590        TSI_WR(base, tat_reg, 0);
591
592        /* Force to 32-bits */
593        TSI_WR(base, tsau_reg       , 0);
594        TSI_WR(base, tsau_reg + 0x04, (uint32_t)start);
595        TSI_WR(base, tsau_reg + 0x08, 0);
596        TSI_WR(base, tsau_reg + 0x0c, (uint32_t)limit);
597        TSI_WR(base, tsau_reg + 0x10, (uint32_t)(offst>>32));
598        TSI_WR(base, tsau_reg + 0x14, (uint32_t)offst);
599
600        /* (outbound only:) leave 2eSST broadcast register alone for user to program */
601
602        /* Set mode and enable */
603        TSI_WR(base, tat_reg, mode);
604        return 0;
605}
606
607static int
608disableTsiPort(
609        BERegister              *base,
610        int                             isout,
611        unsigned long   port)
612{
613        return configTsiPort(base, isout, port, 0, 0, 0, 0);
614}
615
616int
617vmeTsi148InboundPortCfgXX(
618        BERegister              *base,
619        unsigned long   port,
620        unsigned long   address_space,
621        unsigned long   vme_address,
622        unsigned long   pci_address,
623        unsigned long   length)
624{
625        return configTsiPort(base, 0, port, address_space, vme_address, pci_address, length);
626}
627
628int
629vmeTsi148InboundPortCfg(
630        unsigned long   port,
631        unsigned long   address_space,
632        unsigned long   vme_address,
633        unsigned long   pci_address,
634        unsigned long   length)
635{
636        return configTsiPort(devs[0].base, 0, port, address_space, vme_address, pci_address, length);
637}
638
639
640int
641vmeTsi148OutboundPortCfgXX(
642        BERegister              *base,
643        unsigned long   port,
644        unsigned long   address_space,
645        unsigned long   vme_address,
646        unsigned long   pci_address,
647        unsigned long   length)
648{
649        return configTsiPort(base, 1, port, address_space, vme_address, pci_address, length);
650}
651
652int
653vmeTsi148OutboundPortCfg(
654        unsigned long   port,
655        unsigned long   address_space,
656        unsigned long   vme_address,
657        unsigned long   pci_address,
658        unsigned long   length)
659{
660        return configTsiPort(devs[0].base, 1, port, address_space, vme_address, pci_address, length);
661}
662
663
664int
665vmeTsi148XlateAddrXX(
666        BERegister *base,       /* TSI 148 base address */
667        int outbound,           /* look in the outbound windows */
668        int reverse,            /* reverse mapping; for outbound ports: map local to VME */
669        unsigned long as,       /* address space */
670        unsigned long aIn,      /* address to look up */
671        unsigned long *paOut/* where to put result */
672        )
673{
674unsigned long           mode, mode_msk;
675int                                     port;
676unsigned long long      start, limit, offst, a;
677unsigned long           tsau_reg, tat_reg, gran, skip;
678
679        CHECK_BASE(base,0,-1);
680
681        mode = 0; /* silence warning */
682
683        if ( VME_MODE_EXACT_MATCH & as ) {
684                mode_msk = ~0;
685        } else {
686                if ( outbound )
687                        mode_msk = TSI_OTAT_PGM | TSI_OTAT_SUP | TSI_OTAT_ADMODE(-1) | TSI_OTAT_EN;
688                else
689                        mode_msk = TSI_ITAT_PGM | TSI_ITAT_DATA | TSI_ITAT_SUP | TSI_ITAT_USR | TSI_ITAT_AS(-1) | TSI_ITAT_EN;
690        }
691
692        as &= ~VME_MODE_EXACT_MATCH;
693
694        if ( outbound ? am2omode(as,&mode) : am2imode(as,&mode) ) {
695                uprintf(stderr, "vmeTsi148XlateAddr: invalid address space/mode argument");
696                return -2;
697        }
698
699        if (outbound ) {
700                tsau_reg = TSI_OTSAU_REG(0);
701                tat_reg  = TSI_OTAT_REG(0);
702                skip     = TSI_OTSAU_SPACING;
703                mode    |= TSI_OTAT_EN;
704                gran     = 0x10000;
705        } else {
706                tsau_reg = TSI_ITSAU_REG(0);
707                tat_reg  = TSI_ITAT_REG(0);
708                skip     = TSI_ITSAU_SPACING;
709                mode    |= TSI_ITAT_EN;
710                gran     = inboundGranularity(mode) + 1;
711        }
712
713        for ( port = 0; port < TSI148_NUM_OPORTS; port++, tsau_reg += skip, tat_reg += skip ) {
714
715                if ( (mode & mode_msk) == (TSI_RD(base, tat_reg) & mode_msk) ) {
716
717                        /* found a window with of the right mode; now check the range */
718                        readTriple(base, tsau_reg, &start, &limit, &offst);
719                        limit += gran;
720
721                        if ( !reverse ) {
722                                start += offst;
723                                limit += offst;
724                                offst  = -offst;
725                        }
726                        a = aIn;
727                        if ( aIn >= start && aIn <= limit ) {
728                                /* found it */
729                                *paOut = (unsigned long)(a + offst);
730                                return 0;
731                        }
732                }
733        }
734
735        uprintf(stderr, "vmeTsi148XlateAddr: no matching mapping found\n");
736        return -1;
737}
738
739int
740vmeTsi148XlateAddr(
741        int outbound,           /* look in the outbound windows */
742        int reverse,            /* reverse mapping; for outbound ports: map local to VME */
743        unsigned long as,       /* address space */
744        unsigned long aIn,      /* address to look up */
745        unsigned long *paOut/* where to put result */
746        )
747{
748        return vmeTsi148XlateAddrXX(devs[0].base, outbound, reverse, as, aIn, paOut);
749}
750
751
752/* printk cannot format %llx */
753static void uprintfllx(FILE *f, unsigned long long v)
754{
755        if ( v >= ((unsigned long long)1)<<32 )
756                uprintf(f,"0x%lx%08lx ", (unsigned long)(v>>32), (unsigned long)(v & 0xffffffff));
757        else
758                uprintf(f,"0x%08lx ", (unsigned long)(v & 0xffffffff));
759}
760
761void
762vmeTsi148OutboundPortsShowXX(BERegister *base, FILE *f)
763{
764int                             port;
765unsigned long   mode;
766char                    tit = 0;
767
768unsigned long long      start, limit, offst;
769
770        CHECK_BASE(base,0, );
771
772        if (!f) f=stdout;
773        uprintf(f,"Tsi148 Outbound Ports:\n");
774
775        for ( port = 0; port < TSI148_NUM_OPORTS; port++ ) {
776                mode = TSI_RD(base, TSI_OTAT_REG(port));
777                if ( ! (TSI_OTAT_EN & mode) )
778                        continue; /* skip disabled ports */
779
780                readTriple(base, TSI_OTSAU_REG(port), &start, &limit, &offst);
781
782                /* convert limit to size */
783                limit = limit-start+0x10000;
784                if ( !tit ) {
785                        uprintf(f,"Port  VME-Addr   Size       PCI-Adrs   Mode:\n");
786                        tit = 1;
787                }
788                uprintf(f,"%d:    ", port);
789                uprintfllx(f,start+offst);
790                uprintfllx(f,limit);
791                uprintfllx(f,start);
792                switch( mode & TSI_OTAT_ADMODE(-1) ) {
793                        case TSI_OTAT_ADMODE_A16: uprintf(f,"A16"); break;
794                        case TSI_OTAT_ADMODE_A24: uprintf(f,"A24"); break;
795                        case TSI_OTAT_ADMODE_A32: uprintf(f,"A32"); break;
796                        case TSI_OTAT_ADMODE_A64: uprintf(f,"A64"); break;
797                        case TSI_OTAT_ADMODE_CSR: uprintf(f,"CSR"); break;
798                        default:                  uprintf(f,"A??"); break;
799                }
800
801                if ( mode & TSI_OTAT_PGM ) uprintf(f,", PGM");
802                if ( mode & TSI_OTAT_SUP ) uprintf(f,", SUP");
803                if ( ! (TSI_OTAT_MRPFD & mode) ) uprintf(f,", PREFETCH");
804
805                switch ( mode & TSI_OTAT_DBW(-1) ) {
806                        case TSI_OTAT_DBW(0):   uprintf(f,", D16"); break;
807                        case TSI_OTAT_DBW(1):   uprintf(f,", D32"); break;
808                        default:                                uprintf(f,", D??"); break;
809                }
810
811                switch( mode & TSI_OTAT_TM(-1) ) {
812                        case TSI_OTAT_TM(0):    uprintf(f,", SCT");             break;
813                        case TSI_OTAT_TM(1):    uprintf(f,", BLT");             break;
814                        case TSI_OTAT_TM(2):    uprintf(f,", MBLT");            break;
815                        case TSI_OTAT_TM(3):    uprintf(f,", 2eVME");           break;
816                        case TSI_OTAT_TM(4):    uprintf(f,", 2eSST");           break;
817                        case TSI_OTAT_TM(5):    uprintf(f,", 2eSST_BCST");      break;
818                        default:                                uprintf(f," TM??");             break;
819                }
820
821                uprintf(f,"\n");
822        }
823}
824
825void
826vmeTsi148OutboundPortsShow(FILE *f)
827{
828        vmeTsi148OutboundPortsShowXX(devs[0].base, f);
829}
830
831void
832vmeTsi148InboundPortsShowXX(BERegister *base, FILE *f)
833{
834int                             port;
835unsigned long   mode;
836char                    tit = 0;
837
838unsigned long long      start, limit, offst;
839
840        CHECK_BASE(base,0, );
841
842        if (!f) f=stdout;
843        uprintf(f,"Tsi148 Inbound Ports:\n");
844
845        for ( port = 0; port < TSI148_NUM_IPORTS; port++ ) {
846                mode = TSI_RD(base, TSI_ITAT_REG(port));
847                if ( ! (TSI_ITAT_EN & mode) )
848                        continue; /* skip disabled ports */
849
850                readTriple(base, TSI_ITSAU_REG(port), &start, &limit, &offst);
851
852                /* convert limit to size */
853                limit = limit - start + inboundGranularity(mode) + 1;
854                if ( !tit ) {
855                        uprintf(f,"Port  VME-Addr   Size       PCI-Adrs   Mode:\n");
856                        tit = 1;
857                }
858                uprintf(f,"%d:    ", port);
859                uprintfllx(f,start);
860                uprintfllx(f,limit);
861                uprintfllx(f,start+offst);
862                switch( mode & TSI_ITAT_AS(-1) ) {
863                        case TSI_ITAT_ADMODE_A16: uprintf(f,"A16"); break;
864                        case TSI_ITAT_ADMODE_A24: uprintf(f,"A24"); break;
865                        case TSI_ITAT_ADMODE_A32: uprintf(f,"A32"); break;
866                        case TSI_ITAT_ADMODE_A64: uprintf(f,"A64"); break;
867                        default:                  uprintf(f,"A??"); break;
868                }
869
870                if ( mode & TSI_ITAT_PGM )  uprintf(f,", PGM");
871                if ( mode & TSI_ITAT_DATA ) uprintf(f,", DAT");
872                if ( mode & TSI_ITAT_SUP )  uprintf(f,", SUP");
873                if ( mode & TSI_ITAT_USR )  uprintf(f,", USR");
874
875                if ( mode & TSI_ITAT_2eSSTB )  uprintf(f,", 2eSSTB");
876                if ( mode & TSI_ITAT_2eSST  )  uprintf(f,", 2eSST");
877                if ( mode & TSI_ITAT_2eVME  )  uprintf(f,", 2eVME");
878                if ( mode & TSI_ITAT_MBLT   )  uprintf(f,", MBLT");
879                if ( mode & TSI_ITAT_BLT    )  uprintf(f,", BLT");
880
881                uprintf(f,"\n");
882        }
883}
884
885void
886vmeTsi148InboundPortsShow(FILE *f)
887{
888        vmeTsi148InboundPortsShowXX(devs[0].base, f);
889}
890
891
892void
893vmeTsi148DisableAllInboundPortsXX(BERegister *base)
894{
895int port;
896
897        for ( port = 0; port < TSI148_NUM_IPORTS; port++ )
898                if ( disableTsiPort(base, 0, port) )
899                        break;
900}
901
902void
903vmeTsi148DisableAllInboundPorts(void)
904{
905        vmeTsi148DisableAllInboundPortsXX(devs[0].base);
906}
907
908void
909vmeTsi148DisableAllOutboundPortsXX(BERegister *base)
910{
911int port;
912
913        for ( port = 0; port < TSI148_NUM_IPORTS; port++ )
914                if ( disableTsiPort(base, 1, port) )
915                        break;
916}
917
918void
919vmeTsi148DisableAllOutboundPorts(void)
920{
921        vmeTsi148DisableAllOutboundPortsXX(devs[0].base);
922}
923
924
925/* Interrupt Subsystem */
926
927typedef struct
928IRQEntryRec_ {
929                VmeTsi148ISR    isr;
930                void                    *usrData;
931} IRQEntryRec, *IRQEntry;
932
933static IRQEntry irqHdlTbl[TSI_NUM_INT_VECS]={0};
934
935int        vmeTsi148IrqMgrInstalled=0;
936
937static volatile unsigned long   wire_mask[TSI_NUM_WIRES]     = {0};
938/* wires are offset by 1 so we can initialize the wire table to all zeros */
939static int                                              tsi_wire[TSI_NUM_WIRES] = {0};
940
941/* how should we iack a given level, 1,2,4 bytes? */
942static unsigned char tsi_iack_width[7] = {
943        1,1,1,1,1,1,1
944};
945
946/* map universe compatible vector # to Tsi slot (which maps to bit layout in stat/enable/... regs) */
947static int uni2tsi_vec_map[TSI_NUM_INT_VECS-256] = {
948        /* 256 no VOWN interrupt */                     -1,
949        /* TSI_DMA_INT_VEC                      257 */  256 + 24 - 8,
950        /* TSI_LERR_INT_VEC                     258 */  256 + 13 - 8,
951        /* TSI_VERR_INT_VEC                     259 */  256 + 12 - 8,
952        /* 260 is reserved       */                     -1,
953        /* TSI_VME_SW_IACK_INT_VEC      261 */  256 + 10 - 8,
954        /* 262 no PCI SW IRQ     */                     -1,
955        /* TSI_SYSFAIL_INT_VEC          263 */  256 +  9 - 8,
956        /* TSI_ACFAIL_INT_VEC           264 */  256 +  8 - 8,
957        /* TSI_MBOX0_INT_VEC            265 */  256 + 16 - 8,
958        /* TSI_MBOX1_INT_VEC            266 */  256 + 17 - 8,
959        /* TSI_MBOX2_INT_VEC            267 */  256 + 18 - 8,
960        /* TSI_MBOX3_INT_VEC            268 */  256 + 19 - 8,
961        /* TSI_LM0_INT_VEC                      269 */  256 + 20 - 8,
962        /* TSI_LM1_INT_VEC                      270 */  256 + 21 - 8,
963        /* TSI_LM2_INT_VEC                      271 */  256 + 22 - 8,
964        /* TSI_LM3_INT_VEC                      272 */  256 + 23 - 8,
965/* New vectors; only on TSI148 */
966        /* TSI_VIES_INT_VEC                     273 */  256 + 11 - 8,
967        /* TSI_DMA1_INT_VEC                     274 */  256 + 25 - 8,
968};
969
970/* and the reverse; map tsi bit number to universe compatible 'special' vector number */
971static int tsi2uni_vec_map[TSI_NUM_INT_VECS - 256] = {
972        TSI_ACFAIL_INT_VEC,
973        TSI_SYSFAIL_INT_VEC,
974        TSI_VME_SW_IACK_INT_VEC,
975        TSI_VIES_INT_VEC,
976        TSI_VERR_INT_VEC,
977        TSI_LERR_INT_VEC,
978        -1,
979        -1,
980        TSI_MBOX0_INT_VEC,
981        TSI_MBOX1_INT_VEC,
982        TSI_MBOX2_INT_VEC,
983        TSI_MBOX3_INT_VEC,
984        TSI_LM0_INT_VEC,
985        TSI_LM1_INT_VEC,
986        TSI_LM2_INT_VEC,
987        TSI_LM3_INT_VEC,
988        TSI_DMA_INT_VEC,
989        TSI_DMA1_INT_VEC,
990        -1,
991};
992
993static inline int
994uni2tsivec(int v)
995{
996        if ( v < 0 || v >= TSI_NUM_INT_VECS )
997                return -1;
998        return v < 256 ? v : uni2tsi_vec_map[v-256];
999}
1000
1001static int
1002lvl2bitno(unsigned int level)
1003{
1004        if ( level >= 256 )
1005                return uni2tsivec(level) + 8 - 256;
1006        else if ( level < 8 && level > 0 )
1007                return level;
1008        return -1;
1009}
1010
1011int
1012vmeTsi148IntRoute(unsigned int level, unsigned int pin)
1013{
1014int                             i;
1015unsigned long   mask, shift, mapreg, flags, wire;
1016
1017        if ( pin >= TSI_NUM_WIRES || ! tsi_wire[pin] || !vmeTsi148IrqMgrInstalled )
1018                return -1;
1019
1020        if ( level >= 256 ) {
1021                if ( (i = uni2tsivec(level)) < 0 )
1022                        return -1;
1023                shift = 8 + (i-256);
1024        } else if ( 1 <= level && level <=7 ) {
1025                shift = level;
1026        } else {
1027                return -1;      /* invalid level */
1028        }
1029
1030        mask = 1<<shift;
1031
1032        /* calculate the mapping register and contents */
1033        if ( shift < 16 ) {
1034                mapreg = TSI_INTM2_REG;
1035        } else if ( shift < 32 ) {
1036                shift -= 16;
1037                mapreg = TSI_INTM1_REG;
1038        } else {
1039                return -1;
1040        }
1041
1042        shift <<=1;
1043
1044        /* wires are offset by 1 so we can initialize the wire table to all zeros */
1045        wire = (tsi_wire[pin]-1) << shift;
1046
1047rtems_interrupt_disable(flags);
1048
1049        for ( i = 0; i<TSI_NUM_WIRES; i++ ) {
1050                wire_mask[i] &= ~mask;
1051        }
1052        wire_mask[pin] |= mask;
1053
1054        mask = TSI_RD(devs[0].base, mapreg) & ~ (0x3<<shift);
1055        mask |= wire;
1056        TSI_WR( devs[0].base, mapreg, mask );
1057
1058rtems_interrupt_enable(flags);
1059        return 0;
1060}
1061
1062VmeTsi148ISR
1063vmeTsi148ISRGet(unsigned long vector, void **parg)
1064{
1065VmeTsi148ISR      rval = 0;
1066unsigned long     flags;
1067volatile IRQEntry *p;
1068int               v = uni2tsivec(vector);
1069
1070
1071        if ( v < 0 )
1072                return rval;
1073
1074        p = irqHdlTbl + v;
1075
1076        rtems_interrupt_disable(flags);
1077                if ( *p ) {
1078                        if ( parg )
1079                                *parg = (*p)->usrData;
1080                        rval = (*p)->isr;
1081                }
1082        rtems_interrupt_enable(flags);
1083
1084        return rval;
1085}
1086
1087static void
1088tsiVMEISR(rtems_irq_hdl_param arg)
1089{
1090int                                     pin = (int)arg;
1091BERegister                      *b  = devs[0].base;
1092IRQEntry                        ip;
1093unsigned long           msk,lintstat,vector, vecarg;
1094int                                     lvl;
1095
1096        /* only handle interrupts routed to this pin */
1097        while ( (lintstat  = (TSI_RD(b, TSI_INTS_REG) & wire_mask[pin])) ) {
1098
1099                /* bit 0 is never set since it is never set in wire_mask */
1100
1101                do {
1102                        /* simplicity is king; just handle them in MSB to LSB order; reserved bits read as 0 */
1103#ifdef __PPC__
1104                        asm volatile("cntlzw %0, %1":"=r"(lvl):"r"(lintstat));
1105                        lvl = 31-lvl;
1106                        msk = 1<<lvl;
1107#else
1108                        { static unsigned long m[] = {
1109                                                                                         0xffff0000, 0xff00ff00, 0xf0f0f0f0, 0xcccccccc, 0xaaaaaaaa
1110                                                                                 };
1111                        int      i;
1112                        unsigned tmp;
1113
1114                        /* lintstat has already been checked...
1115                        if ( !lintstat ) {
1116                           lvl = -1; msk = 0;
1117                        } else
1118                         */
1119                        for ( i=0, lvl=0, msk = lintstat; i<5; i++ ) {
1120                                lvl <<= 1;
1121                                if ( (tmp = msk & m[i]) ) {
1122                                        lvl++;
1123                                        msk = tmp;
1124                                } else
1125                                        msk = msk & ~m[i];
1126                        }
1127                        }
1128#endif
1129
1130                        if ( lvl > 7 ) {
1131                                /* clear this interrupt level */
1132                                TSI_WR(b, TSI_INTC_REG, msk);
1133                                vector = 256 + lvl - 8;
1134                                vecarg = tsi2uni_vec_map[lvl-8];
1135                        } else {
1136                                /* need to do get the vector for this level */
1137                                switch ( tsi_iack_width[lvl-1] ) {
1138                                        default:
1139                                        case  1:
1140                                                vector = TSI_RD8(b, TSI_VIACK_1_REG - 4 + (lvl<<2) + 3);
1141                                                break;
1142
1143                                        case  2:
1144                                                vector = TSI_RD16(b, TSI_VIACK_1_REG - 4 + (lvl<<2) + 2);
1145                                                break;
1146
1147                                        case  4:
1148                                                vector = TSI_RD(b, TSI_VIACK_1_REG - 4 + (lvl<<2));
1149                                                break;
1150                                }
1151                                vecarg = vector;
1152                        }
1153
1154                        if ( !(ip=irqHdlTbl[vector])) {
1155                                /* TODO: log error message - RTEMS has no logger :-( */
1156                                vmeTsi148IntDisable(lvl);
1157                                printk("vmeTsi148 ISR: ERROR: no handler registered (level %i) IACK 0x%08x -- DISABING level %i\n",
1158                                                lvl, vector, lvl);
1159                        } else {
1160                                /* dispatch handler, it must clear the IRQ at the device */
1161                                ip->isr(ip->usrData, vecarg);
1162                        }
1163                } while ( (lintstat &= ~msk) );
1164                /* check if a new irq is pending already */
1165        }
1166}
1167
1168
1169static void
1170my_no_op(const rtems_irq_connect_data * arg)
1171{}
1172
1173static int
1174my_isOn(const rtems_irq_connect_data *arg)
1175{
1176                return (int)(TSI_RD(devs[0].base, TSI_INTEO_REG) & TSI_RD(devs[0].base, TSI_INTEN_REG));
1177}
1178
1179static void
1180connectIsr(int shared, rtems_irq_hdl isr, int pic_line, int slot)
1181{
1182rtems_irq_connect_data  xx;
1183        xx.on     = my_no_op; /* at _least_ they could check for a 0 pointer */
1184        xx.off    = my_no_op;
1185        xx.isOn   = my_isOn;
1186        xx.hdl    = isr;
1187        xx.handle = (rtems_irq_hdl_param)slot;
1188        xx.name   = pic_line;
1189
1190        if ( shared ) {
1191#if BSP_SHARED_HANDLER_SUPPORT > 0
1192                if (!BSP_install_rtems_shared_irq_handler(&xx))
1193                        BSP_panic("unable to install vmeTsi148 shared irq handler");
1194#else
1195        uprintf(stderr,"vmeTsi148: WARNING: your BSP doesn't support sharing interrupts\n");
1196                if (!BSP_install_rtems_irq_handler(&xx))
1197                        BSP_panic("unable to install vmeTsi148 irq handler");
1198#endif
1199        } else {
1200                if (!BSP_install_rtems_irq_handler(&xx))
1201                        BSP_panic("unable to install vmeTsi148 irq handler");
1202        }
1203}
1204
1205int
1206vmeTsi148InstallIrqMgrAlt(int shared, int tsi_pin0, int pic_pin0, ...)
1207{
1208int             rval;
1209va_list ap;
1210        va_start(ap, pic_pin0);
1211        rval = vmeTsi148InstallIrqMgrVa(shared, tsi_pin0, pic_pin0, ap);
1212        va_end(ap);
1213        return rval;
1214}
1215
1216int
1217vmeTsi148InstallIrqMgrVa(int shared, int tsi_pin0, int pic_pin0, va_list ap)
1218{
1219int     i,j, specialPin, tsi_pin[TSI_NUM_WIRES+1], pic_pin[TSI_NUM_WIRES];
1220
1221        if (vmeTsi148IrqMgrInstalled)                  return -4;
1222
1223        /* check parameters */
1224
1225        if ( tsi_pin0 < 0 || tsi_pin0 > 3 )            return -1;
1226
1227        tsi_pin[0] = tsi_pin0;
1228        pic_pin[0] = pic_pin0 < 0 ? devs[0].irqLine : pic_pin0;
1229        i = 1;
1230        while ( (tsi_pin[i] = va_arg(ap, int)) >= 0 ) {
1231               
1232                if ( i >= TSI_NUM_WIRES ) {
1233                                                               return -5;
1234                }
1235
1236                pic_pin[i] = va_arg(ap,int);
1237
1238                if ( tsi_pin[i] > 3 )                      return -2;
1239                if ( pic_pin[i] < 0 )                      return -3;
1240                i++;
1241        }
1242
1243        /* all routings must be different */
1244        for ( i=0; tsi_pin[i] >= 0; i++ ) {
1245                for ( j=i+1; tsi_pin[j] >= 0; j++ ) {
1246                        if ( tsi_pin[j] == tsi_pin[i] )        return -6;
1247                        if ( pic_pin[j] == pic_pin[i] )        return -7;
1248                }
1249        }
1250
1251        /* give them a chance to override buggy PCI info */
1252        if ( pic_pin[0] >= 0 && devs[0].irqLine != pic_pin[0] ) {
1253                uprintf(stderr,"Overriding main IRQ line PCI info with %d\n",
1254                                pic_pin[0]);
1255                devs[0].irqLine = pic_pin[0];
1256        }
1257
1258        for ( i = 0; tsi_pin[i] >= 0; i++ ) {
1259                /* offset wire # by one so we can initialize to 0 == invalid */
1260                tsi_wire[i] = tsi_pin[i] + 1;
1261                connectIsr(shared, tsiVMEISR, pic_pin[i], i);
1262        }
1263
1264        specialPin = tsi_pin[1] >= 0 ? 1 : 0;
1265
1266        /* setup routing */
1267       
1268        /* IntRoute checks for mgr being installed */
1269        vmeTsi148IrqMgrInstalled=1;
1270
1271        /* route 7 VME irqs to first / 'normal' pin */
1272        for ( i=1; i<8; i++ )
1273                vmeTsi148IntRoute( i, 0 );
1274        for ( i=TSI_DMA_INT_VEC; i<TSI_NUM_INT_VECS; i++ )
1275                vmeTsi148IntRoute( i, specialPin );
1276
1277        for ( i = 0; i<TSI_NUM_WIRES; i++ ) {
1278                /* remember (for unloading the driver) */
1279                devs[0].pic_pin[i] = ( ( tsi_pin[i] >=0 ) ? pic_pin[i] : -1 );
1280        }
1281
1282        return 0;
1283}
1284
1285int
1286vmeTsi148InstallISR(unsigned long vector, VmeTsi148ISR hdl, void *arg)
1287{
1288IRQEntry          ip;
1289int                               v;
1290unsigned long     flags;
1291volatile IRQEntry *p;
1292
1293                if ( !vmeTsi148IrqMgrInstalled || (v = uni2tsivec(vector)) < 0 )
1294                        return -1;
1295
1296                p = irqHdlTbl + v;
1297
1298                if (*p || !(ip=(IRQEntry)malloc(sizeof(IRQEntryRec))))
1299                                return -1;
1300
1301                ip->isr=hdl;
1302                ip->usrData=arg;
1303
1304                rtems_interrupt_disable(flags);
1305                if (*p) {
1306                        rtems_interrupt_enable(flags);
1307                        free(ip);
1308                        return -1;
1309                }
1310                *p = ip;
1311                rtems_interrupt_enable(flags);
1312                return 0;
1313}
1314
1315int
1316vmeTsi148RemoveISR(unsigned long vector, VmeTsi148ISR hdl, void *arg)
1317{
1318int               v;
1319IRQEntry          ip;
1320unsigned long     flags;
1321volatile IRQEntry *p;
1322
1323                if ( !vmeTsi148IrqMgrInstalled || (v = uni2tsivec(vector)) < 0 )
1324                        return -1;
1325
1326                p = irqHdlTbl + v;
1327
1328                rtems_interrupt_disable(flags);
1329                ip = *p;
1330                if ( !ip || ip->isr!=hdl || ip->usrData!=arg ) {
1331                                rtems_interrupt_enable(flags);
1332                                return -1;
1333                }
1334                *p = 0;
1335                rtems_interrupt_enable(flags);
1336
1337                free(ip);
1338                return 0;
1339}
1340
1341static int
1342intDoEnDis(unsigned int level, int dis)
1343{
1344BERegister              *b = devs[0].base;
1345unsigned long   flags, v;
1346int                             shift;
1347
1348        if (  ! vmeTsi148IrqMgrInstalled || (shift = lvl2bitno(level)) < 0 )
1349                return -1;
1350
1351        v = 1<<shift;
1352
1353        if ( !dis )
1354                return (int)(v & TSI_RD(b, TSI_INTEO_REG) & TSI_RD(b, TSI_INTEN_REG)) ? 1 : 0;
1355
1356        rtems_interrupt_disable(flags);
1357        if ( dis<0 ) {
1358                TSI_WR(b, TSI_INTEN_REG, TSI_RD(b, TSI_INTEN_REG) & ~v);
1359                TSI_WR(b, TSI_INTEO_REG, TSI_RD(b, TSI_INTEO_REG) & ~v);
1360        } else {
1361                TSI_WR(b, TSI_INTEN_REG, TSI_RD(b, TSI_INTEN_REG) |  v);
1362                TSI_WR(b, TSI_INTEO_REG, TSI_RD(b, TSI_INTEO_REG) |  v);
1363        }
1364        rtems_interrupt_enable(flags);
1365        return 0;
1366}
1367
1368int
1369vmeTsi148IntEnable(unsigned int level)
1370{
1371        return intDoEnDis(level, 1);
1372}
1373
1374int
1375vmeTsi148IntDisable(unsigned int level)
1376{
1377        return intDoEnDis(level, -1);
1378}
1379
1380int
1381vmeTsi148IntIsEnabled(unsigned int level)
1382{
1383        return intDoEnDis(level, 0);
1384}
1385
1386/* Set IACK width (1,2, or 4 bytes) for a given interrupt level.
1387 *
1388 * 'width' arg may be 0,1,2 or 4. If zero, the currently active
1389 * value is returned but not modified.
1390 *
1391 * RETURNS: old width or -1 if invalid argument.
1392 */
1393
1394int
1395vmeTsi148SetIackWidth(int level, int width)
1396{
1397int rval;
1398        if ( level < 1 || level > 7 || !vmeTsi148IrqMgrInstalled )
1399                return -1;
1400
1401        switch ( width ) {
1402                default: return -1;
1403                case 0:
1404                case 1:
1405                case 2:
1406                case 4:
1407                break;
1408        }
1409
1410        rval = tsi_iack_width[level-1];
1411        if ( width )
1412                tsi_iack_width[level-1] = width;
1413        return rval;
1414}
1415
1416int
1417vmeTsi148IntRaiseXX(BERegister *base, int level, unsigned vector)
1418{
1419unsigned long v;
1420
1421        CHECK_BASE(base,0,-1);
1422
1423        if ( level < 1 || level > 7 || vector > 255 )
1424                return -1;      /* invalid argument */
1425
1426        /* Check if already asserted */
1427        if ( (v = TSI_RD(base, TSI_VICR_REG)) & TSI_VICR_IRQS ) {
1428                return -2;  /* already asserted */
1429        }
1430
1431        v &= ~255;
1432
1433        v |= TSI_VICR_IRQL(level) | TSI_VICR_STID(vector);
1434
1435        /* Write Vector */
1436        TSI_WR(base, TSI_VICR_REG, v);
1437
1438        return 0;
1439       
1440}
1441
1442int
1443vmeTsi148IntRaise(int level, unsigned vector)
1444{
1445        return vmeTsi148IntRaiseXX(devs[0].base, level, vector);
1446}
1447
1448/* Loopback test of VME/Tsi148 internal interrupts */
1449
1450typedef struct {
1451        rtems_id        q;
1452        int                     l;
1453} LoopbackTstArgs;
1454
1455static void
1456loopbackTstIsr(void *arg, unsigned long vector)
1457{
1458LoopbackTstArgs *pa = arg;
1459        if ( RTEMS_SUCCESSFUL != rtems_message_queue_send(pa->q, (void*)&vector, sizeof(vector)) ) {
1460                /* Overrun ? */
1461                printk("vmeTsi148IntLoopbackTst: (ISR) message queue full / overrun ? disabling IRQ level %i\n", pa->l);
1462                vmeTsi148IntDisable(pa->l);
1463        }
1464}
1465
1466int
1467vmeTsi148IntLoopbackTst(int level, unsigned vector)
1468{
1469BERegister                      *b = devs[0].base;
1470rtems_status_code       sc;
1471rtems_id                        q = 0;
1472int                                     installed = 0;
1473int                                     i, err = 0;
1474int                                     doDisable = 0;
1475uint32_t                        size;
1476unsigned long           msg;
1477char *                          irqfmt  = "VME IRQ @vector %3i %s";
1478char *                          iackfmt = "VME IACK            %s";
1479LoopbackTstArgs         a;
1480
1481        CHECK_BASE(b,0,-1);
1482
1483        /* arg check */
1484        if ( level < 1 || level > 7 || vector > 255 )
1485                return -1;
1486
1487        /* Create message queue */
1488        if ( RTEMS_SUCCESSFUL != (sc=rtems_message_queue_create(
1489                                                                        rtems_build_name('t' ,'U','I','I'),
1490                                                                        4,
1491                                                                        sizeof(unsigned long),
1492                                                                        0,  /* default attributes: fifo, local */
1493                                                                        &q)) ) {
1494                rtems_error(sc, "vmeTsi148IntLoopbackTst: Unable to create message queue");
1495                goto bail;
1496        }
1497
1498        a.q = q;
1499        a.l = level;
1500
1501        /* Install handlers */
1502        if ( vmeTsi148InstallISR(vector, loopbackTstIsr, (void*)&a) ) {
1503                uprintf(stderr,"Unable to install VME ISR to vector %i\n",vector);
1504                goto bail;
1505        }
1506        installed++;
1507        if ( vmeTsi148InstallISR(TSI_VME_SW_IACK_INT_VEC, loopbackTstIsr, (void*)&a) ) {
1508                uprintf(stderr,"Unable to install VME ISR to IACK special vector %i\n",TSI_VME_SW_IACK_INT_VEC);
1509                goto bail;
1510        }
1511        installed++;
1512
1513        if ( !vmeTsi148IntIsEnabled(level) && 0==vmeTsi148IntEnable(level) )
1514                doDisable = 1;
1515       
1516        /* make sure there are no pending interrupts */
1517        TSI_WR(b, TSI_INTC_REG, TSI_INTC_IACKC);
1518
1519        if ( vmeTsi148IntEnable( TSI_VME_SW_IACK_INT_VEC ) ) {
1520                uprintf(stderr,"Unable to enable IACK interrupt\n");
1521                goto bail;
1522        }
1523
1524        printf("vmeTsi148 VME interrupt loopback test; STARTING...\n");
1525        printf(" --> asserting VME IRQ level %i\n", level);
1526        vmeTsi148IntRaise(level, vector);
1527
1528        for ( i = 0; i< 3; i++ ) {
1529        sc = rtems_message_queue_receive(
1530                            q,
1531                            &msg,
1532                            &size,
1533                            RTEMS_WAIT,
1534                            20);
1535                if ( sc ) {
1536                        if ( RTEMS_TIMEOUT == sc && i>1 ) {
1537                                /* OK; we dont' expect more to happen */
1538                                sc = 0;
1539                        } else {
1540                                rtems_error(sc,"Error waiting for interrupts");
1541                        }
1542                        break;
1543                }
1544                if ( msg == vector ) {
1545                        if ( !irqfmt ) {
1546                                printf("Excess VME IRQ received ?? -- BAD\n");
1547                                err = 1;
1548                        } else {
1549                                printf(irqfmt, vector, "received -- PASSED\n");
1550                                irqfmt = 0;
1551                        }
1552                } else if ( msg == TSI_VME_SW_IACK_INT_VEC ) {
1553                        if ( !iackfmt ) {
1554                                printf("Excess VME IACK received ?? -- BAD\n");
1555                                err = 1;
1556                        } else {
1557                                printf(iackfmt, "received -- PASSED\n");
1558                                iackfmt = 0;
1559                        }
1560                } else {
1561                        printf("Unknown IRQ (vector %lu) received -- BAD\n", msg);
1562                        err = 1;
1563                }
1564        }
1565
1566
1567        /* Missing anything ? */
1568        if ( irqfmt ) {
1569                printf(irqfmt,vector, "MISSED -- BAD\n");
1570                err = 1;
1571        }
1572        if ( iackfmt ) {
1573                printf(iackfmt, "MISSED -- BAD\n");
1574                err = 1;
1575        }
1576
1577        printf("FINISHED.\n");
1578
1579bail:
1580        if ( doDisable )
1581                vmeTsi148IntDisable(level);
1582        vmeTsi148IntDisable( TSI_VME_SW_IACK_INT_VEC );
1583        if ( installed > 0 )
1584                vmeTsi148RemoveISR(vector, loopbackTstIsr, (void*)&a);
1585        if ( installed > 1 )
1586                vmeTsi148RemoveISR(TSI_VME_SW_IACK_INT_VEC, loopbackTstIsr, (void*)&a);
1587        if ( q )
1588                rtems_message_queue_delete(q);
1589
1590        return sc ? sc : err;
1591}
1592
1593unsigned long
1594vmeTsi148ClearVMEBusErrorsXX(BERegister *base, unsigned long long *paddr)
1595{
1596unsigned long rval;
1597
1598        CHECK_BASE(base,1,-1);
1599
1600        rval = TSI_RD(base, TSI_VEAT_REG);
1601        if ( rval & TSI_VEAT_VES ) {
1602                if ( paddr ) {
1603                        *paddr  = ((unsigned long long)TSI_RD(base, TSI_VEAU_REG))<<32;
1604                        *paddr |= TSI_RD(base, TSI_VEAL_REG);
1605                }
1606                /* clear errors */
1607                TSI_WR(base, TSI_VEAT_REG, TSI_VEAT_VESCL);
1608        } else {
1609                rval = 0;
1610        }
1611        return rval;
1612}
1613
1614unsigned long
1615vmeTsi148ClearVMEBusErrors(unsigned long long *paddr)
1616{
1617        return vmeTsi148ClearVMEBusErrorsXX(devs[0].base, paddr);
1618}
1619
1620#ifdef DEBUG_MODULAR
1621void
1622_cexpModuleInitialize(void* unused)
1623{
1624        vmeTsi148Init();
1625        vmeTsi148Reset();
1626}
1627
1628int
1629_cexpModuleFinalize(void *unused)
1630{
1631int             i;
1632int             rval = 1;
1633void    (*isrs[TSI_NUM_WIRES])() = {
1634        isr_pin0,
1635        isr_pin1,
1636        isr_pin2,
1637        isr_pin3,
1638};
1639
1640rtems_irq_connect_data  xx;
1641        xx.on   = my_no_op; /* at _least_ they could check for a 0 pointer */
1642        xx.off  = my_no_op;
1643        xx.isOn = my_isOn;
1644
1645        TSI_WR(devs[0].base, TSI_INTEO_REG, 0);
1646
1647        for ( i=0; i<TSI_NUM_INT_VECS; i++) {
1648                /* Dont even bother to uninstall handlers */
1649        }
1650        if ( vmeTsi148IrqMgrInstalled ) {
1651                for ( i=0; i<TSI_NUM_WIRES; i++ ) {
1652                        if ( (int)(xx.name = devs[0].pic_pin[i]) >=0 ) {
1653                                xx.hdl  = isrs[i];
1654                                rval    = rval && BSP_remove_rtems_irq_handler(&xx);
1655                        }
1656                }
1657        }
1658        return !rval;
1659}
1660#endif
Note: See TracBrowser for help on using the repository browser.