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

4.104.114.84.9
Last change on this file since adac8ab was adac8ab, checked in by Till Straumann <strauman@…>, on Jan 17, 2007 at 6:33:29 AM

2007-01-16 Till Straumann <strauman@…>

  • vmeUniverse/vmeTsi148.c, vmeUniverse/vmeTsi148.h,
  • vmeUniverse/vmeUniverse.c, vmeUniverse/vmeUniverse.h,
  • vmeUniverse/vme_am_defs.h: Added SLAC/Stanford Authorship Note / Copyright + Liability Disclaimer.
  • Property mode set to 100644
File size: 51.5 KB
Line 
1/* $Id$ */
2
3/* Driver for the Tundra Tsi148 pci-vme bridge */
4
5/*
6 * Authorship
7 * ----------
8 * This software was created by
9 *     Till Straumann <strauman@slac.stanford.edu>, 2005-2007,
10 *         Stanford Linear Accelerator Center, Stanford University.
11 *
12 * Acknowledgement of sponsorship
13 * ------------------------------
14 * This software was produced by
15 *     the Stanford Linear Accelerator Center, Stanford University,
16 *         under Contract DE-AC03-76SFO0515 with the Department of Energy.
17 *
18 * Government disclaimer of liability
19 * ----------------------------------
20 * Neither the United States nor the United States Department of Energy,
21 * nor any of their employees, makes any warranty, express or implied, or
22 * assumes any legal liability or responsibility for the accuracy,
23 * completeness, or usefulness of any data, apparatus, product, or process
24 * disclosed, or represents that its use would not infringe privately owned
25 * rights.
26 *
27 * Stanford disclaimer of liability
28 * --------------------------------
29 * Stanford University makes no representations or warranties, express or
30 * implied, nor assumes any liability for the use of this software.
31 *
32 * Stanford disclaimer of copyright
33 * --------------------------------
34 * Stanford University, owner of the copyright, hereby disclaims its
35 * copyright and all other rights in this software.  Hence, anyone may
36 * freely use it for any purpose without restriction. 
37 *
38 * Maintenance of notices
39 * ----------------------
40 * In the interest of clarity regarding the origin and status of this
41 * SLAC software, this and all the preceding Stanford University notices
42 * are to remain affixed to any copy or derivative of this software made
43 * or distributed by the recipient and are to be affixed to any copy of
44 * software made or distributed by the recipient that contains a copy or
45 * derivative of this software.
46 *
47 * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03
48 */ 
49
50#include <rtems.h>
51#include <stdio.h>
52#include <stdarg.h>
53#include <bsp/irq.h>
54#include <stdlib.h>
55#include <rtems/bspIo.h>        /* printk */
56#include <rtems/error.h>        /* printk */
57#include <bsp/pci.h>
58#include <bsp.h>
59#include <libcpu/byteorder.h>
60
61#define __INSIDE_RTEMS_BSP__
62
63#include "vmeTsi148.h"
64
65#define STATIC static
66
67/* The tsi has 4 'local' wires that can be hooked to a PIC */
68
69#define TSI_NUM_WIRES                   4
70
71#define TSI148_NUM_OPORTS               8 /* number of outbound ports */
72#define TSI148_NUM_IPORTS               8 /* number of inbound  ports */
73
74#define NUM_TSI_DEVS                    2 /* number of instances supported */
75
76#define PCI_VENDOR_TUNDRA       0x10e3
77#define PCI_DEVICE_TSI148       0x0148
78
79#define TSI_OTSAU_SPACING       0x020
80
81#define TSI_OTSAU0_REG          0x100
82#define TSI_OTSAL0_REG          0x104
83#define TSI_OTEAU0_REG          0x108
84#define TSI_OTEAL0_REG          0x10c
85#define TSI_OTOFU0_REG          0x110
86#define TSI_OTOFL0_REG          0x114
87#define TSI_OTBS0_REG           0x118   /* 2eSST broadcast select */
88#define TSI_OTAT0_REG           0x11c
89#define TSI_OTSAU_REG(port)     (TSI_OTSAU0_REG + ((port)<<5))
90#define TSI_OTSAL_REG(port)     (TSI_OTSAL0_REG + ((port)<<5))
91#define TSI_OTEAU_REG(port)     (TSI_OTEAU0_REG + ((port)<<5))
92#define TSI_OTEAL_REG(port)     (TSI_OTEAL0_REG + ((port)<<5))
93#define TSI_OTOFU_REG(port)     (TSI_OTOFU0_REG + ((port)<<5))
94#define TSI_OTOFL_REG(port)     (TSI_OTOFL0_REG + ((port)<<5))
95#define TSI_OTBS_REG(port)      (TSI_OTBS0_REG + ((port)<<5))
96#define TSI_OTAT_REG(port)      (TSI_OTAT0_REG + ((port)<<5))
97#       define TSI_OTAT_EN                      (1<<31)
98#       define TSI_OTAT_MRPFD           (1<<18)
99#       define TSI_OTAT_PFS(x)          (((x)&3)<<16)
100#       define TSI_OTAT_2eSSTM(x)       (((x)&7)<<11)
101#       define TSI_OTAT_2eSSTM_160      TSI_OTAT_2eSSTM(0)
102#       define TSI_OTAT_2eSSTM_267      TSI_OTAT_2eSSTM(1)
103#       define TSI_OTAT_2eSSTM_320      TSI_OTAT_2eSSTM(2)
104#       define TSI_OTAT_TM(x)           (((x)&7)<<8)
105#               define TSI_TM_SCT_IDX           0
106#               define TSI_TM_BLT_IDX           1
107#               define TSI_TM_MBLT_IDX          2
108#               define TSI_TM_2eVME_IDX         3
109#               define TSI_TM_2eSST_IDX         4
110#               define TSI_TM_2eSSTB_IDX        5
111#       define TSI_OTAT_DBW(x)          (((x)&3)<<6)
112#       define TSI_OTAT_SUP                     (1<<5)
113#       define TSI_OTAT_PGM                     (1<<4)
114#       define TSI_OTAT_ADMODE(x)       (((x)&0xf))
115#       define TSI_OTAT_ADMODE_A16      0
116#       define TSI_OTAT_ADMODE_A24      1
117#       define TSI_OTAT_ADMODE_A32      2
118#       define TSI_OTAT_ADMODE_A64      4
119#       define TSI_OTAT_ADMODE_CSR      5
120#       define TSI_OTAT_ADMODE_USR1     8
121#       define TSI_OTAT_ADMODE_USR2     9
122#       define TSI_OTAT_ADMODE_USR3     0xa
123#       define TSI_OTAT_ADMODE_USR4     0xb
124
125#define TSI_VIACK_1_REG         0x204
126
127#define TSI_VSTAT_REG           0x23c
128#       define TSI_VSTAT_CPURST         (1<<15) /* clear power-up reset bit */
129#       define TSI_VSTAT_BDFAIL         (1<<14)
130#       define TSI_VSTAT_PURSTS         (1<<12)
131#       define TSI_VSTAT_BDFAILS        (1<<11)
132#       define TSI_VSTAT_SYSFLS         (1<<10)
133#       define TSI_VSTAT_ACFAILS        (1<< 9)
134#       define TSI_VSTAT_SCONS          (1<< 8)
135#       define TSI_VSTAT_GAP            (1<< 5)
136#       define TSI_VSTAT_GA_MSK         (0x1f)
137
138#define TSI_VEAU_REG            0x260
139#define TSI_VEAL_REG            0x264
140#define TSI_VEAT_REG            0x268
141
142#define TSI_ITSAU_SPACING       0x020
143
144#define TSI_ITSAU0_REG          0x300
145#define TSI_ITSAL0_REG          0x304
146#define TSI_ITEAU0_REG          0x308
147#define TSI_ITEAL0_REG          0x30c
148#define TSI_ITOFU0_REG          0x310
149#define TSI_ITOFL0_REG          0x314
150#define TSI_ITAT0_REG           0x318
151#define TSI_ITSAU_REG(port)     (TSI_ITSAU0_REG + ((port)<<5))
152#define TSI_ITSAL_REG(port)     (TSI_ITSAL0_REG + ((port)<<5))
153#define TSI_ITEAU_REG(port)     (TSI_ITEAU0_REG + ((port)<<5))
154#define TSI_ITEAL_REG(port)     (TSI_ITEAL0_REG + ((port)<<5))
155#define TSI_ITOFU_REG(port)     (TSI_ITOFU0_REG + ((port)<<5))
156#define TSI_ITOFL_REG(port)     (TSI_ITOFL0_REG + ((port)<<5))
157#define TSI_ITAT_REG(port)      (TSI_ITAT0_REG + ((port)<<5))
158
159#       define TSI_ITAT_EN                      (1<<31)
160#       define TSI_ITAT_TH                      (1<<18)
161#       define TSI_ITAT_VFS(x)          (((x)&3)<<16)
162#       define TSI_ITAT_2eSSTM(x)       (((x)&7)<<12)
163#       define TSI_ITAT_2eSSTM_160      TSI_ITAT_2eSSTM(0)
164#       define TSI_ITAT_2eSSTM_267      TSI_ITAT_2eSSTM(1)
165#       define TSI_ITAT_2eSSTM_320      TSI_ITAT_2eSSTM(2)
166#       define TSI_ITAT_2eSSTB          (1<<11)
167#       define TSI_ITAT_2eSST           (1<<10)
168#       define TSI_ITAT_2eVME           (1<<9)
169#       define TSI_ITAT_MBLT            (1<<8)
170#       define TSI_ITAT_BLT                     (1<<7)
171#       define TSI_ITAT_AS(x)           (((x)&7)<<4)
172#       define TSI_ITAT_ADMODE_A16      (0<<4)
173#       define TSI_ITAT_ADMODE_A24      (1<<4)
174#       define TSI_ITAT_ADMODE_A32      (2<<4)
175#       define TSI_ITAT_ADMODE_A64      (4<<4)
176#       define TSI_ITAT_SUP                     (1<<3)
177#       define TSI_ITAT_USR                     (1<<2)
178#       define TSI_ITAT_PGM                     (1<<1)
179#       define TSI_ITAT_DATA            (1<<0)
180
181#define TSI_CBAU_REG            0x40c
182#define TSI_CBAL_REG            0x410
183#define TSI_CRGAT_REG           0x414
184#   define TSI_CRGAT_EN         (1<<7)
185#       define TSI_CRGAT_AS_MSK (7<<4)
186#       define TSI_CRGAT_A16    (0<<4)
187#       define TSI_CRGAT_A24    (1<<4)
188#       define TSI_CRGAT_A32    (2<<4)
189#       define TSI_CRGAT_A64    (4<<4)
190#   define TSI_CRGAT_SUP        (1<<3)
191#   define TSI_CRGAT_USR        (1<<2)
192#   define TSI_CRGAT_PGM        (1<<1)
193#   define TSI_CRGAT_DATA       (1<<0)
194
195#define TSI_VICR_REG            0x440
196#   define TSI_VICR_CNTS(v)             (((v)&3)<<30)
197#   define TSI_VICR_CNTS_DIS    (0<<30)
198#   define TSI_VICR_CNTS_IRQ1   (1<<30)
199#   define TSI_VICR_CNTS_IRQ2   (2<<30)
200#   define TSI_VICR_EDGIS(v)    (((v)&3)<<28)
201#   define TSI_VICR_EDGIS_DIS   (0<<28)
202#   define TSI_VICR_EDGIS_IRQ1  (1<<28)
203#   define TSI_VICR_EDGIS_IRQ2  (2<<28)
204#   define TSI_VICR_IRQ1F(v)    (((v)&3)<<26)
205#   define TSI_VICR_IRQ1F_NORML (0<<26)
206#   define TSI_VICR_IRQ1F_PULSE (1<<26)
207#   define TSI_VICR_IRQ1F_CLOCK (2<<26)
208#   define TSI_VICR_IRQ1F_1MHZ  (3<<26)
209#   define TSI_VICR_IRQ2F(v)    (((v)&3)<<24)
210#   define TSI_VICR_IRQ2F_NORML (0<<24)
211#   define TSI_VICR_IRQ2F_PULSE (1<<24)
212#   define TSI_VICR_IRQ2F_CLOCK (2<<24)
213#   define TSI_VICR_IRQ2F_1MHZ  (3<<24)
214#   define TSI_VICR_BIP                 (1<<23)
215#   define TSI_VICR_BIPS                (1<<22)
216#   define TSI_VICR_IRQC                (1<<15)
217#   define TSI_VICR_IRQLS(v)    (((v)&7)<<12)
218#   define TSI_VICR_IRQS                (1<<11)
219#   define TSI_VICR_IRQL(v)             (((v)&7)<<8)
220#   define TSI_VICR_STID(v)             ((v)&0xff)
221#define TSI_INTEN_REG           0x448
222#define TSI_INTEO_REG           0x44c
223#define TSI_INTS_REG            0x450
224#   define TSI_INTS_IRQ1S       (1<<1)
225#   define TSI_INTS_IRQ2S       (1<<2)
226#   define TSI_INTS_IRQ3S       (1<<3)
227#   define TSI_INTS_IRQ4S       (1<<4)
228#   define TSI_INTS_IRQ5S       (1<<5)
229#   define TSI_INTS_IRQ6S       (1<<6)
230#   define TSI_INTS_IRQ7S       (1<<7)
231#   define TSI_INTS_ACFLS       (1<<8)
232#   define TSI_INTS_SYSFLS      (1<<9)
233#   define TSI_INTS_IACKS       (1<<10)
234#   define TSI_INTS_VIES        (1<<11)
235#   define TSI_INTS_VERRS       (1<<12)
236#   define TSI_INTS_PERRS       (1<<13)
237#   define TSI_INTS_MB0S        (1<<16)
238#   define TSI_INTS_MB1S        (1<<17)
239#   define TSI_INTS_MB2S        (1<<18)
240#   define TSI_INTS_MB3S        (1<<19)
241#   define TSI_INTS_LM0S        (1<<20)
242#   define TSI_INTS_LM1S        (1<<21)
243#   define TSI_INTS_LM2S        (1<<22)
244#   define TSI_INTS_LM3S        (1<<23)
245#   define TSI_INTS_DMA0S       (1<<24)
246#   define TSI_INTS_DMA1S       (1<<25)
247#define TSI_INTC_REG            0x454
248#   define TSI_INTC_ACFLC       (1<<8)
249#   define TSI_INTC_SYSFLC      (1<<9)
250#   define TSI_INTC_IACKC       (1<<10)
251#   define TSI_INTC_VIEC        (1<<11)
252#   define TSI_INTC_VERRC       (1<<12)
253#   define TSI_INTC_PERRC       (1<<13)
254#   define TSI_INTC_MB0C        (1<<16)
255#   define TSI_INTC_MB1C        (1<<17)
256#   define TSI_INTC_MB2C        (1<<18)
257#   define TSI_INTC_MB3C        (1<<19)
258#   define TSI_INTC_LM0C        (1<<20)
259#   define TSI_INTC_LM1C        (1<<21)
260#   define TSI_INTC_LM2C        (1<<22)
261#   define TSI_INTC_LM3C        (1<<23)
262#   define TSI_INTC_DMA0C       (1<<24)
263#   define TSI_INTC_DMA1C       (1<<25)
264#define TSI_INTM1_REG           0x458
265#define TSI_INTM2_REG           0x45c
266
267#define TSI_CBAR_REG            0xffc
268
269#define TSI_CSR_OFFSET          0x7f000
270
271#define TSI_CRG_SIZE            (1<<12)         /* 4k */
272
273
274#define TSI_RD(base, reg)                               in_be32((volatile unsigned *)((base) + (reg)/sizeof(*base)))
275#define TSI_RD16(base, reg)                             in_be16((volatile unsigned short *)(base) + (reg)/sizeof(short))
276#define TSI_LE_RD16(base, reg)                  in_le16((volatile unsigned short *)(base) + (reg)/sizeof(short))
277#define TSI_LE_RD32(base, reg)                  in_le32((volatile unsigned *)(base) + (reg)/sizeof(*base))
278#define TSI_RD8(base, reg)                              in_8((volatile unsigned char *)(base) + (reg))
279#define TSI_WR(base, reg, val)                  out_be32((volatile unsigned *)((base) + (reg)/sizeof(*base)), val)
280
281#define UNIV_SCTL_AM_MASK       (UNIV_CTL_VAS | UNIV_SCTL_PGM | UNIV_SCTL_DAT | UNIV_SCTL_USER | UNIV_SCTL_SUPER)
282
283
284/* allow the BSP to override the default routines */
285#ifndef BSP_PCI_FIND_DEVICE
286#define BSP_PCI_FIND_DEVICE             pci_find_device
287#endif
288#ifndef BSP_PCI_CONFIG_IN_LONG
289#define BSP_PCI_CONFIG_IN_LONG  pci_read_config_dword
290#endif
291#ifndef BSP_PCI_CONFIG_IN_SHORT
292#define BSP_PCI_CONFIG_IN_SHORT pci_read_config_word
293#endif
294#ifndef BSP_PCI_CONFIG_OUT_SHORT
295#define BSP_PCI_CONFIG_OUT_SHORT pci_write_config_word
296#endif
297#ifndef BSP_PCI_CONFIG_IN_BYTE
298#define BSP_PCI_CONFIG_IN_BYTE  pci_read_config_byte
299#endif
300
301typedef unsigned int pci_ulong;
302
303/* PCI_MEM_BASE is a possible offset between CPU- and PCI addresses.
304 * Should be defined by the BSP.
305 */
306#ifndef BSP_PCI2LOCAL_ADDR
307#ifndef PCI_MEM_BASE
308#define PCI_MEM_BASE 0
309#endif
310#define BSP_PCI2LOCAL_ADDR(memaddr) ((unsigned long)(memaddr) + PCI_MEM_BASE)
311#endif
312
313typedef struct {
314        BERegister *base;
315        int                     irqLine;
316        int                     pic_pin[TSI_NUM_WIRES];
317} Tsi148Dev;
318
319static Tsi148Dev devs[NUM_TSI_DEVS] = {{0}};
320
321/* forward decl */
322extern int vmeTsi148RegPort;
323extern int vmeTsi148RegCSR;
324
325/* registers should be mapped to guarded, non-cached memory; hence
326 * subsequent stores are ordered. eieio is only needed to enforce
327 * ordering of loads with respect to stores.
328 */
329
330/* private printing wrapper */
331static void
332uprintf(FILE *f, char *fmt, ...)
333{
334va_list ap;
335        va_start(ap, fmt);
336        if (!f || !_impure_ptr->__sdidinit) {
337                /* Might be called at an early stage when
338                 * to a buffer.
339                 */
340                vprintk(fmt,ap);
341        } else 
342        {
343                vfprintf(f,fmt,ap);
344        }
345        va_end(ap);
346}
347
348#define CHECK_BASE(base,quiet,rval)     \
349        do {                                                    \
350                if ( !base ) {                          \
351                        if ( !quiet ) {                 \
352                                uprintf(stderr,"Tsi148: Driver not initialized\n");     \
353                        }                                               \
354                        return rval;                    \
355                }                                                       \
356        } while (0)
357
358int
359vmeTsi148FindPciBase(
360        int instance,
361        BERegister **pbase
362        )
363{
364int                                     bus,dev,fun;
365pci_ulong                       busaddr;
366unsigned char           irqline;
367unsigned short          wrd;
368
369        if (BSP_PCI_FIND_DEVICE(
370                        PCI_VENDOR_TUNDRA,
371                        PCI_DEVICE_TSI148,
372                        instance,
373                        &bus,
374                        &dev,
375                        &fun))
376                return -1;
377        if (BSP_PCI_CONFIG_IN_LONG(bus,dev,fun,PCI_BASE_ADDRESS_0,&busaddr))
378                return -1;
379        /* Assume upper BAR is zero */
380
381        *pbase=(BERegister*)(((pci_ulong)BSP_PCI2LOCAL_ADDR(busaddr)) & ~0xff);
382
383        if (BSP_PCI_CONFIG_IN_BYTE(bus,dev,fun,PCI_INTERRUPT_LINE,&irqline))
384                return -1;
385
386        /* Enable PCI master and memory access */
387        BSP_PCI_CONFIG_IN_SHORT(bus, dev, fun, PCI_COMMAND, &wrd);
388        BSP_PCI_CONFIG_OUT_SHORT(bus, dev, fun, PCI_COMMAND, wrd | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
389
390        return irqline;
391}
392
393int
394vmeTsi148InitInstance(unsigned instance)
395{
396int                                     irq;
397BERegister *base;
398
399        if ( instance >= NUM_TSI_DEVS )
400                return  -1;
401        if ( devs[instance].base )
402                return  -1;
403
404        if ((irq=vmeTsi148FindPciBase(instance,&base)) < 0) {
405                uprintf(stderr,"unable to find a Tsi148 in pci config space\n");
406        } else {
407                uprintf(stderr,"Tundra Tsi148 PCI-VME bridge detected at 0x%08x, IRQ %d\n",
408                                (unsigned int)base, irq);
409        }
410        devs[0].base    = base;
411        devs[0].irqLine = irq;
412
413        return irq < 0 ? -1 : 0;
414}
415
416int
417vmeTsi148Init(void)
418{
419        return vmeTsi148InitInstance(0);
420}
421
422
423void
424vmeTsi148ResetXX(BERegister *base)
425{
426int port;
427
428        CHECK_BASE(base,0, );
429
430        vmeTsi148DisableAllOutboundPortsXX(base);
431        for ( port=0; port < TSI148_NUM_OPORTS; port++ )
432                TSI_WR(base, TSI_OTBS_REG(port), 0);
433        TSI_WR(base, TSI_INTEO_REG, 0);
434        TSI_WR(base, TSI_INTEN_REG, 0);
435        TSI_WR(base, TSI_INTC_REG, 0xffffffff);
436        TSI_WR(base, TSI_INTM1_REG, 0);
437        TSI_WR(base, TSI_INTM2_REG, 0);
438        TSI_WR(base, TSI_VICR_REG, 0);
439        TSI_WR(base, TSI_VEAT_REG, TSI_VEAT_VESCL);
440        /* Clear BDFAIL / (--> SYSFAIL) */
441#       define TSI_VSTAT_BDFAIL         (1<<14)
442        TSI_WR(base, TSI_VSTAT_REG, TSI_RD(base, TSI_VSTAT_REG) & ~TSI_VSTAT_BDFAIL);
443}
444
445void
446vmeTsi148Reset()
447{
448        vmeTsi148ResetXX(devs[0].base);
449}
450
451/* convert an address space selector to a corresponding
452 * Tsi148 control mode word
453 */
454
455static unsigned long ck2esst(unsigned long am)
456{
457        if ( VME_AM_IS_2eSST(am) ) {
458                /* make sure 2eVME is selected */
459                am &= ~VME_AM_MASK;
460                am |= VME_AM_2eVME_6U;
461        }
462        return am;
463}
464
465STATIC int
466am2omode(unsigned long address_space, unsigned long *pmode)
467{
468unsigned long mode = 0;
469unsigned long tm   = TSI_TM_SCT_IDX;
470
471        if ( ! (VME_MODE_DBW16  & address_space ) )
472                mode |= TSI_OTAT_DBW(1);
473        if ( ! (VME_MODE_PREFETCH_ENABLE & address_space) )
474                mode |= TSI_OTAT_MRPFD;
475        else {
476                mode |= TSI_OTAT_PFS(address_space>>_LD_VME_MODE_PREFETCHSZ);
477        }
478
479        address_space = ck2esst(address_space);
480
481        switch (address_space & VME_AM_MASK) {
482                case VME_AM_STD_SUP_PGM:
483                case VME_AM_STD_USR_PGM:
484
485                        mode |= TSI_OTAT_PGM;
486
487                        /* fall thru */
488                case VME_AM_STD_SUP_BLT:
489                case VME_AM_STD_SUP_MBLT:
490
491                case VME_AM_STD_USR_BLT:
492                case VME_AM_STD_USR_MBLT:
493                        switch ( address_space & 3 ) {
494                                case 0: tm = TSI_TM_MBLT_IDX; break;
495                                case 3: tm = TSI_TM_BLT_IDX; break;
496                                default: break;
497                        }
498
499                case VME_AM_STD_SUP_DATA:
500                case VME_AM_STD_USR_DATA:
501
502                        mode |= TSI_OTAT_ADMODE_A24;
503                        break;
504
505                case VME_AM_EXT_SUP_PGM:
506                case VME_AM_EXT_USR_PGM:
507                        mode |= TSI_OTAT_PGM;
508
509                        /* fall thru */
510                case VME_AM_EXT_SUP_BLT:
511                case VME_AM_EXT_SUP_MBLT:
512
513                case VME_AM_EXT_USR_BLT:
514                case VME_AM_EXT_USR_MBLT:
515                        switch ( address_space & 3 ) {
516                                case 0: tm = TSI_TM_MBLT_IDX; break;
517                                case 3: tm = TSI_TM_BLT_IDX; break;
518                                default: break;
519                        }
520
521                case VME_AM_EXT_SUP_DATA:
522                case VME_AM_EXT_USR_DATA:
523
524                        mode |= TSI_OTAT_ADMODE_A32;
525                        break;
526
527                case VME_AM_SUP_SHORT_IO:
528                case VME_AM_USR_SHORT_IO:
529                        mode |= TSI_OTAT_ADMODE_A16;
530                        break;
531
532                case VME_AM_CSR:
533                        mode |= TSI_OTAT_ADMODE_CSR;
534                        break;
535
536                case VME_AM_2eVME_6U:
537                case VME_AM_2eVME_3U:
538                        mode |= TSI_OTAT_ADMODE_A32;
539                        if ( VME_AM_IS_2eSST(address_space) ) {
540                                tm = ( VME_AM_2eSST_BCST & address_space ) ?
541                                                TSI_TM_2eSSTB_IDX : TSI_TM_2eSST_IDX;
542                                switch ( VME_AM_IS_2eSST(address_space) ) {
543                                        default:
544                                        case VME_AM_2eSST_LO:  mode |= TSI_OTAT_2eSSTM_160; break;
545                                        case VME_AM_2eSST_MID: mode |= TSI_OTAT_2eSSTM_267; break;
546                                        case VME_AM_2eSST_HI:  mode |= TSI_OTAT_2eSSTM_320; break;
547                                }
548                        } else {
549                                tm    = TSI_TM_2eVME_IDX;
550                        }
551                break;
552
553                case 0: /* disable the port alltogether */
554                        break;
555
556                default:
557                        return -1;
558        }
559
560        mode |= TSI_OTAT_TM(tm);
561
562        if ( VME_AM_IS_SUP(address_space) )
563                mode |= TSI_OTAT_SUP;
564        *pmode = mode;
565        return 0;
566}
567
568STATIC int
569am2imode(unsigned long address_space, unsigned long *pmode)
570{
571unsigned long mode=0;
572unsigned long pgm = 0;
573
574        mode |= TSI_ITAT_VFS(address_space>>_LD_VME_MODE_PREFETCHSZ);
575
576        if ( VME_AM_IS_2eSST(address_space) ) {
577                        mode |= TSI_ITAT_2eSST;
578                if ( VME_AM_2eSST_BCST & address_space )
579                        mode |= TSI_ITAT_2eSSTB;
580                switch ( VME_AM_IS_2eSST(address_space) ) {
581                        default:
582                        case VME_AM_2eSST_LO:  mode |= TSI_ITAT_2eSSTM_160; break;
583                        case VME_AM_2eSST_MID: mode |= TSI_ITAT_2eSSTM_267; break;
584                        case VME_AM_2eSST_HI:  mode |= TSI_ITAT_2eSSTM_320; break;
585                }
586                address_space = ck2esst(address_space);
587        }
588
589        mode |= TSI_ITAT_BLT;
590        mode |= TSI_ITAT_MBLT;
591
592        mode |= TSI_ITAT_PGM; /* always allow PGM access */
593        mode |= TSI_ITAT_USR; /* always allow USR access */
594
595        switch (address_space & VME_AM_MASK) {
596                case VME_AM_STD_SUP_PGM:
597                case VME_AM_STD_USR_PGM:
598
599                        pgm = 1;
600
601                        /* fall thru */
602                case VME_AM_STD_SUP_BLT:
603                case VME_AM_STD_SUP_MBLT:
604                case VME_AM_STD_USR_BLT:
605                case VME_AM_STD_USR_MBLT:
606                case VME_AM_STD_SUP_DATA:
607                case VME_AM_STD_USR_DATA:
608
609                        mode |= TSI_ITAT_ADMODE_A24;
610                        break;
611
612                case VME_AM_EXT_SUP_PGM:
613                case VME_AM_EXT_USR_PGM:
614                        pgm = 1;
615
616                        /* fall thru */
617                case VME_AM_2eVME_6U:
618                case VME_AM_2eVME_3U:
619                case VME_AM_EXT_SUP_BLT:
620                case VME_AM_EXT_SUP_MBLT:
621                case VME_AM_EXT_USR_BLT:
622                case VME_AM_EXT_USR_MBLT:
623                case VME_AM_EXT_SUP_DATA:
624                case VME_AM_EXT_USR_DATA:
625                        mode |= TSI_ITAT_ADMODE_A32;
626                        break;
627
628                case VME_AM_SUP_SHORT_IO:
629                case VME_AM_USR_SHORT_IO:
630                        mode |= TSI_ITAT_ADMODE_A16;
631                        break;
632
633                case 0: /* disable the port alltogether */
634                        *pmode = 0;
635                        return 0;
636
637                default:
638                        return -1;
639        }
640
641        if ( VME_AM_IS_SUP(address_space) )
642                mode |= TSI_ITAT_SUP;
643
644        if ( !pgm )
645                mode |= TSI_ITAT_DATA;
646
647        *pmode = mode;
648        return 0;
649}
650
651static void
652readTriple(
653        BERegister *base,
654        unsigned reg,
655        unsigned long long *ps,
656        unsigned long long *pl,
657        unsigned long long *po)
658{
659        *ps = TSI_RD(base, reg);
660        *ps = (*ps<<32) | (TSI_RD(base, (reg+4)) & 0xffff0000);
661        *pl = TSI_RD(base, (reg+8));
662        *pl = (*pl<<32) | (TSI_RD(base, (reg+0xc)) & 0xffff0000);
663        *po = TSI_RD(base, (reg+0x10));
664        *po = (*po<<32) | (TSI_RD(base, (reg+0x14)) & 0xffff0000);
665}
666
667
668static unsigned long
669inboundGranularity(unsigned long itat)
670{
671        switch ( itat & TSI_ITAT_AS(-1) ) {
672                case TSI_ITAT_ADMODE_A16:       return 0xf;
673                case TSI_ITAT_ADMODE_A24:       return 0xfff;
674                default:
675                break;
676        }
677        return 0xffff;
678}
679
680static int
681configTsiPort(
682        BERegister              *base,
683        int                             isout,
684        unsigned long   port,
685        unsigned long   address_space,
686        unsigned long   vme_address,
687        unsigned long   pci_address,
688        unsigned long   length)
689{
690unsigned long long      start, limit, offst;
691unsigned long           mode, mask, tat_reg, tsau_reg;
692char                            *name = (isout ? "Outbound" : "Inbound");
693int                                     i,s,l;
694
695        CHECK_BASE(base,0,-1);
696
697        mode = 0; /* silence warning */
698
699        if ( port >= (isout ? TSI148_NUM_OPORTS : TSI148_NUM_IPORTS) ) {
700                uprintf(stderr,"Tsi148 %s Port Cfg: invalid port\n", name);
701                return -1;
702        }
703
704        if ( base == devs[0].base && isout && vmeTsi148RegPort == port ) {
705                uprintf(stderr,"Tsi148 %s Port Cfg: invalid port; reserved by the interrupt manager for CRG\n", name);
706                return -1;
707        }
708
709        if ( length && (isout ? am2omode(address_space, &mode) : am2imode(address_space, &mode)) ) {
710                uprintf(stderr,"Tsi148 %s Port Cfg: invalid address space / mode flags\n",name);
711                return -1;
712        }
713
714
715        if ( isout ) {
716                start     = pci_address;
717                offst     = (unsigned long long)vme_address - start;
718                mask      = 0xffff;
719                tat_reg   = TSI_OTAT_REG(port);
720                tsau_reg  = TSI_OTSAU_REG(port);
721                mode     |= TSI_OTAT_EN;
722
723                /* check for overlap */
724                for ( i = 0; i < TSI148_NUM_OPORTS; i++ ) {
725                        /* ignore 'this' port */
726                        if ( i == port || ! (TSI_OTAT_EN & TSI_RD(base, TSI_OTAT_REG(i))) )
727                                continue;
728
729                        /* check requested PCI range against current port 'i' config */
730                        s = TSI_RD(base, TSI_OTSAU_REG(i) + 0x04); /* start */
731                        l = TSI_RD(base, TSI_OTSAU_REG(i) + 0x0c); /* limit */
732                        if ( ! ( start + length <= s || start > s + l ) ) {
733                                uprintf(stderr,"Tsi148 Outbound Port Cfg: PCI address range overlaps with port %i (0x%08x..0x%08x)\n", i, s, l);
734                                return -1;
735                        }
736                }
737        } else {
738                start     = vme_address;
739                offst     = (unsigned long long)pci_address - start;
740                mask      = inboundGranularity(mode);
741                tat_reg   = TSI_ITAT_REG(port);
742                tsau_reg  = TSI_ITSAU_REG(port);
743                mode     |= TSI_ITAT_EN;
744
745                /* check for overlap */
746                for ( i = 0; i < TSI148_NUM_IPORTS; i++ ) {
747                        /* ignore 'this' port */
748                        if ( i == port || ! (TSI_ITAT_EN & (s=TSI_RD(base, TSI_ITAT_REG(i)))) )
749                                continue;
750
751                        if ( (TSI_ITAT_AS(-1) & s) != (TSI_ITAT_AS(-1) & mode) ) {
752                                /* different address space */
753                                continue;
754                        }
755
756                        if ( ! (mode & s & (TSI_ITAT_SUP | TSI_ITAT_USR | TSI_ITAT_PGM | TSI_ITAT_DATA)) ) {
757                                /* orthogonal privileges */
758                                continue;
759                        }
760
761                        /* check requested VME range against current port 'i' config */
762                        s = TSI_RD(base, TSI_ITSAU_REG(i) + 0x04); /* start */
763                        l = TSI_RD(base, TSI_ITSAU_REG(i) + 0x0c); /* limit */
764                        if ( ! ( start + length <= s || start > s + l ) ) {
765                                uprintf(stderr,"Tsi148 Inbound Port Cfg: VME address range overlaps with port %i (0x%08x..0x%08x)\n", i, s, l);
766                                return -1;
767                        }
768                }
769        }
770
771        /* If they pass 'length==0' just disable */
772        if ( 0 == length ) {
773                TSI_WR(base, tat_reg, TSI_RD(base, tat_reg) & ~(isout ? TSI_OTAT_EN : TSI_ITAT_EN));
774                return 0;
775        }
776
777
778        if (   (vme_address & mask)
779            || (pci_address & mask)
780            || (length      & mask) ) {
781                uprintf(stderr,"Tsi148 %s Port Cfg: invalid address/length; must be multiple of 0x%x\n",
782                                name,
783                                mask+1);
784                return -1;
785        }
786
787        limit  = start + length - 1;
788
789        if ( limit >= (unsigned long long)1<<32 ) {
790                uprintf(stderr,"Tsi148 %s Port Cfg: invalid address/length; must be < 1<<32\n", name);
791                return -1;
792        }
793
794        /* Disable port */
795        TSI_WR(base, tat_reg, 0);
796
797        /* Force to 32-bits */
798        TSI_WR(base, tsau_reg       , 0);
799        TSI_WR(base, tsau_reg + 0x04, (uint32_t)start);
800        TSI_WR(base, tsau_reg + 0x08, 0);
801        TSI_WR(base, tsau_reg + 0x0c, (uint32_t)limit);
802        TSI_WR(base, tsau_reg + 0x10, (uint32_t)(offst>>32));
803        TSI_WR(base, tsau_reg + 0x14, (uint32_t)offst);
804
805        /* (outbound only:) leave 2eSST broadcast register alone for user to program */
806
807        /* Set mode and enable */
808        TSI_WR(base, tat_reg, mode);
809        return 0;
810}
811
812static int
813disableTsiPort(
814        BERegister              *base,
815        int                             isout,
816        unsigned long   port)
817{
818        return configTsiPort(base, isout, port, 0, 0, 0, 0);
819}
820
821int
822vmeTsi148InboundPortCfgXX(
823        BERegister              *base,
824        unsigned long   port,
825        unsigned long   address_space,
826        unsigned long   vme_address,
827        unsigned long   pci_address,
828        unsigned long   length)
829{
830        return configTsiPort(base, 0, port, address_space, vme_address, pci_address, length);
831}
832
833int
834vmeTsi148InboundPortCfg(
835        unsigned long   port,
836        unsigned long   address_space,
837        unsigned long   vme_address,
838        unsigned long   pci_address,
839        unsigned long   length)
840{
841        return configTsiPort(devs[0].base, 0, port, address_space, vme_address, pci_address, length);
842}
843
844
845int
846vmeTsi148OutboundPortCfgXX(
847        BERegister              *base,
848        unsigned long   port,
849        unsigned long   address_space,
850        unsigned long   vme_address,
851        unsigned long   pci_address,
852        unsigned long   length)
853{
854        return configTsiPort(base, 1, port, address_space, vme_address, pci_address, length);
855}
856
857int
858vmeTsi148OutboundPortCfg(
859        unsigned long   port,
860        unsigned long   address_space,
861        unsigned long   vme_address,
862        unsigned long   pci_address,
863        unsigned long   length)
864{
865        return configTsiPort(devs[0].base, 1, port, address_space, vme_address, pci_address, length);
866}
867
868
869static int
870xlateFindPort(
871        BERegister *base,       /* TSI 148 base address */
872        int outbound,           /* look in the outbound windows */
873        int reverse,            /* reverse mapping; for outbound ports: map local to VME */
874        unsigned long as,       /* address space */
875        unsigned long aIn,      /* address to look up */
876        unsigned long *paOut/* where to put result */
877        )
878{
879unsigned long           mode, mode_msk;
880int                                     port;
881unsigned long long      start, limit, offst, a;
882unsigned long           tsau_reg, tat_reg, gran, skip;
883
884        CHECK_BASE(base,0,-1);
885
886        mode = 0; /* silence warning */
887
888        switch ( as & VME_MODE_MATCH_MASK ) {
889                case VME_MODE_EXACT_MATCH:
890                        mode_msk = ~0;
891                break;
892
893                case VME_MODE_AS_MATCH:
894                        if ( outbound ) 
895                                mode_msk = TSI_OTAT_ADMODE(-1) | TSI_OTAT_EN;
896                        else
897                                mode_msk = TSI_ITAT_AS(-1) | TSI_ITAT_EN;
898                break;
899
900                default:
901                        if ( outbound ) 
902                                mode_msk = TSI_OTAT_PGM | TSI_OTAT_SUP | TSI_OTAT_ADMODE(-1) | TSI_OTAT_EN;
903                        else
904                                mode_msk = TSI_ITAT_PGM | TSI_ITAT_DATA | TSI_ITAT_SUP | TSI_ITAT_USR | TSI_ITAT_AS(-1) | TSI_ITAT_EN;
905                break;
906        }
907
908        as &= ~VME_MODE_MATCH_MASK;
909
910        if ( outbound ? am2omode(as,&mode) : am2imode(as,&mode) ) {
911                uprintf(stderr, "vmeTsi148XlateAddr: invalid address space/mode argument");
912                return -2;
913        }
914
915        if (outbound ) {
916                tsau_reg = TSI_OTSAU_REG(0);
917                tat_reg  = TSI_OTAT_REG(0);
918                skip     = TSI_OTSAU_SPACING;
919                mode    |= TSI_OTAT_EN;
920                gran     = 0x10000;
921        } else {
922                tsau_reg = TSI_ITSAU_REG(0);
923                tat_reg  = TSI_ITAT_REG(0);
924                skip     = TSI_ITSAU_SPACING;
925                mode    |= TSI_ITAT_EN;
926                gran     = inboundGranularity(mode) + 1;
927        }
928
929        for ( port = 0; port < TSI148_NUM_OPORTS; port++, tsau_reg += skip, tat_reg += skip ) {
930
931                if ( (mode & mode_msk) == (TSI_RD(base, tat_reg) & mode_msk) ) {
932
933                        /* found a window with of the right mode; now check the range */
934                        readTriple(base, tsau_reg, &start, &limit, &offst);
935                        limit += gran;
936
937                        if ( !reverse ) {
938                                start += offst; 
939                                limit += offst;
940                                offst  = -offst;
941                        }
942                        a = aIn;
943                        if ( aIn >= start && aIn <= limit ) {
944                                /* found it */
945                                *paOut = (unsigned long)(a + offst);
946                                return port;
947                        }
948                }
949        }
950
951        uprintf(stderr, "vmeTsi148XlateAddr: no matching mapping found\n");
952        return -1;
953}
954
955int
956vmeTsi148XlateAddrXX(
957        BERegister *base,       /* TSI 148 base address */
958        int outbound,           /* look in the outbound windows */
959        int reverse,            /* reverse mapping; for outbound ports: map local to VME */
960        unsigned long as,       /* address space */
961        unsigned long aIn,      /* address to look up */
962        unsigned long *paOut/* where to put result */
963        )
964{
965int port = xlateFindPort( base, outbound, reverse, as, aIn, paOut );
966        return port < 0 ? -1 : 0;
967}
968
969int
970vmeTsi148XlateAddr(
971        int outbound,           /* look in the outbound windows */
972        int reverse,            /* reverse mapping; for outbound ports: map local to VME */
973        unsigned long as,       /* address space */
974        unsigned long aIn,      /* address to look up */
975        unsigned long *paOut/* where to put result */
976        )
977{
978        return vmeTsi148XlateAddrXX(devs[0].base, outbound, reverse, as, aIn, paOut);
979}
980
981
982/* printk cannot format %llx */
983static void uprintfllx(FILE *f, unsigned long long v)
984{
985        if ( v >= ((unsigned long long)1)<<32 )
986                uprintf(f,"0x%lx%08lx ", (unsigned long)(v>>32), (unsigned long)(v & 0xffffffff));
987        else
988                uprintf(f,"0x%08lx ", (unsigned long)(v & 0xffffffff));
989}
990
991void
992vmeTsi148OutboundPortsShowXX(BERegister *base, FILE *f)
993{
994int                             port;
995unsigned long   mode;
996char                    tit = 0;
997
998unsigned long long      start, limit, offst;
999
1000        CHECK_BASE(base,0, );
1001
1002        if (!f) f=stdout;
1003        uprintf(f,"Tsi148 Outbound Ports:\n");
1004
1005        for ( port = 0; port < TSI148_NUM_OPORTS; port++ ) {
1006                mode = TSI_RD(base, TSI_OTAT_REG(port));
1007                if ( ! (TSI_OTAT_EN & mode) )
1008                        continue; /* skip disabled ports */
1009
1010                readTriple(base, TSI_OTSAU_REG(port), &start, &limit, &offst);
1011
1012                /* convert limit to size */
1013                limit = limit-start+0x10000;
1014                if ( !tit ) {
1015                        uprintf(f,"Port  VME-Addr   Size       PCI-Adrs   Mode:\n");
1016                        tit = 1;
1017                }
1018                uprintf(f,"%d:    ", port);
1019                uprintfllx(f,start+offst);
1020                uprintfllx(f,limit);
1021                uprintfllx(f,start);
1022                switch( mode & TSI_OTAT_ADMODE(-1) ) {
1023                        case TSI_OTAT_ADMODE_A16: uprintf(f,"A16"); break;
1024                        case TSI_OTAT_ADMODE_A24: uprintf(f,"A24"); break;
1025                        case TSI_OTAT_ADMODE_A32: uprintf(f,"A32"); break;
1026                        case TSI_OTAT_ADMODE_A64: uprintf(f,"A64"); break;
1027                        case TSI_OTAT_ADMODE_CSR: uprintf(f,"CSR"); break;
1028                        default:                  uprintf(f,"A??"); break;
1029                }
1030
1031                if ( mode & TSI_OTAT_PGM ) uprintf(f,", PGM");
1032                if ( mode & TSI_OTAT_SUP ) uprintf(f,", SUP");
1033                if ( ! (TSI_OTAT_MRPFD & mode) ) uprintf(f,", PREFETCH");
1034
1035                switch ( mode & TSI_OTAT_DBW(-1) ) {
1036                        case TSI_OTAT_DBW(0):   uprintf(f,", D16"); break;
1037                        case TSI_OTAT_DBW(1):   uprintf(f,", D32"); break;
1038                        default:                                uprintf(f,", D??"); break;
1039                }
1040
1041                switch( mode & TSI_OTAT_TM(-1) ) {
1042                        case TSI_OTAT_TM(0):    uprintf(f,", SCT");             break;
1043                        case TSI_OTAT_TM(1):    uprintf(f,", BLT");             break;
1044                        case TSI_OTAT_TM(2):    uprintf(f,", MBLT");            break;
1045                        case TSI_OTAT_TM(3):    uprintf(f,", 2eVME");           break;
1046                        case TSI_OTAT_TM(4):    uprintf(f,", 2eSST");           break;
1047                        case TSI_OTAT_TM(5):    uprintf(f,", 2eSST_BCST");      break;
1048                        default:                                uprintf(f," TM??");             break;
1049                }
1050
1051                uprintf(f,"\n");
1052        }
1053}
1054
1055void
1056vmeTsi148OutboundPortsShow(FILE *f)
1057{
1058        vmeTsi148OutboundPortsShowXX(devs[0].base, f);
1059}
1060
1061void
1062vmeTsi148InboundPortsShowXX(BERegister *base, FILE *f)
1063{
1064int                             port;
1065unsigned long   mode;
1066char                    tit = 0;
1067
1068unsigned long long      start, limit, offst;
1069
1070        CHECK_BASE(base,0, );
1071
1072        if (!f) f=stdout;
1073        uprintf(f,"Tsi148 Inbound Ports:\n");
1074
1075        for ( port = 0; port < TSI148_NUM_IPORTS; port++ ) {
1076                mode = TSI_RD(base, TSI_ITAT_REG(port));
1077                if ( ! (TSI_ITAT_EN & mode) )
1078                        continue; /* skip disabled ports */
1079
1080                readTriple(base, TSI_ITSAU_REG(port), &start, &limit, &offst);
1081
1082                /* convert limit to size */
1083                limit = limit - start + inboundGranularity(mode) + 1;
1084                if ( !tit ) {
1085                        uprintf(f,"Port  VME-Addr   Size       PCI-Adrs   Mode:\n");
1086                        tit = 1;
1087                }
1088                uprintf(f,"%d:    ", port);
1089                uprintfllx(f,start);
1090                uprintfllx(f,limit);
1091                uprintfllx(f,start+offst);
1092                switch( mode & TSI_ITAT_AS(-1) ) {
1093                        case TSI_ITAT_ADMODE_A16: uprintf(f,"A16"); break;
1094                        case TSI_ITAT_ADMODE_A24: uprintf(f,"A24"); break;
1095                        case TSI_ITAT_ADMODE_A32: uprintf(f,"A32"); break;
1096                        case TSI_ITAT_ADMODE_A64: uprintf(f,"A64"); break;
1097                        default:                  uprintf(f,"A??"); break;
1098                }
1099
1100                if ( mode & TSI_ITAT_PGM )  uprintf(f,", PGM");
1101                if ( mode & TSI_ITAT_DATA ) uprintf(f,", DAT");
1102                if ( mode & TSI_ITAT_SUP )  uprintf(f,", SUP");
1103                if ( mode & TSI_ITAT_USR )  uprintf(f,", USR");
1104
1105                if ( mode & TSI_ITAT_2eSSTB )  uprintf(f,", 2eSSTB");
1106                if ( mode & TSI_ITAT_2eSST  )  uprintf(f,", 2eSST");
1107                if ( mode & TSI_ITAT_2eVME  )  uprintf(f,", 2eVME");
1108                if ( mode & TSI_ITAT_MBLT   )  uprintf(f,", MBLT");
1109                if ( mode & TSI_ITAT_BLT    )  uprintf(f,", BLT");
1110
1111                uprintf(f,"\n");
1112        }
1113}
1114
1115void
1116vmeTsi148InboundPortsShow(FILE *f)
1117{
1118        vmeTsi148InboundPortsShowXX(devs[0].base, f);
1119}
1120
1121
1122void
1123vmeTsi148DisableAllInboundPortsXX(BERegister *base)
1124{
1125int port;
1126
1127        for ( port = 0; port < TSI148_NUM_IPORTS; port++ )
1128                if ( disableTsiPort(base, 0, port) )
1129                        break;
1130}
1131
1132void
1133vmeTsi148DisableAllInboundPorts(void)
1134{
1135        vmeTsi148DisableAllInboundPortsXX(devs[0].base);
1136}
1137
1138void
1139vmeTsi148DisableAllOutboundPortsXX(BERegister *base)
1140{
1141int port;
1142
1143        for ( port = 0; port < TSI148_NUM_IPORTS; port++ )
1144                if ( disableTsiPort(base, 1, port) )
1145                        break;
1146}
1147
1148void
1149vmeTsi148DisableAllOutboundPorts(void)
1150{
1151        vmeTsi148DisableAllOutboundPortsXX(devs[0].base);
1152}
1153
1154
1155/* Map internal register block to VME */
1156
1157int
1158vmeTsi148MapCRGXX(BERegister *b, uint32_t vme_base, uint32_t as )
1159{
1160uint32_t mode;
1161
1162        CHECK_BASE( b, 0, -1 );
1163
1164        if ( vmeTsi148RegPort > -1 && ! vmeTsi148RegCSR ) {
1165        uprintf(stderr,"vmeTsi148: CRG already mapped and in use by interrupt manager\n");
1166                return -1;
1167        }
1168
1169        /* enable all, SUP/USR/PGM/DATA accesses */
1170        mode = TSI_CRGAT_EN | TSI_CRGAT_SUP | TSI_CRGAT_USR | TSI_CRGAT_PGM |  TSI_CRGAT_DATA;
1171
1172        if ( VME_AM_IS_SHORT(as) ) {
1173                mode |= TSI_CRGAT_A16;
1174        } else 
1175        if ( VME_AM_IS_STD(as) ) {
1176                mode |= TSI_CRGAT_A24;
1177        } else 
1178        if ( VME_AM_IS_EXT(as) ) {
1179                mode |= TSI_CRGAT_A32;
1180        } else {
1181                return -2;
1182        }
1183
1184        /* map CRG to VME bus */
1185        TSI_WR( b, TSI_CBAL_REG, (vme_base & ~(TSI_CRG_SIZE-1)));
1186        TSI_WR( b, TSI_CRGAT_REG, mode );
1187
1188        return 0;
1189}
1190
1191int
1192vmeTsi148MapCRG(uint32_t vme_base, uint32_t as )
1193{
1194        return vmeTsi148MapCRGXX( devs[0].base, vme_base, as );
1195}
1196
1197/* Interrupt Subsystem */
1198
1199typedef struct
1200IRQEntryRec_ {
1201                VmeTsi148ISR    isr;
1202                void                    *usrData;
1203} IRQEntryRec, *IRQEntry;
1204
1205static IRQEntry irqHdlTbl[TSI_NUM_INT_VECS]={0};
1206
1207int        vmeTsi148IrqMgrInstalled = 0;
1208int        vmeTsi148RegPort         = -1;
1209int        vmeTsi148RegCSR                      = 0;
1210BERegister *vmeTsi148RegBase        = 0;
1211
1212static volatile unsigned long   wire_mask[TSI_NUM_WIRES]     = {0};
1213/* wires are offset by 1 so we can initialize the wire table to all zeros */
1214static int                                              tsi_wire[TSI_NUM_WIRES] = {0};
1215
1216/* how should we iack a given level, 1,2,4 bytes? */
1217static unsigned char tsi_iack_width[7] = {
1218        1,1,1,1,1,1,1
1219};
1220
1221/* map universe compatible vector # to Tsi slot (which maps to bit layout in stat/enable/... regs) */
1222static int uni2tsi_vec_map[TSI_NUM_INT_VECS-256] = {
1223        /* 256 no VOWN interrupt */                     -1,
1224        /* TSI_DMA_INT_VEC                      257 */  256 + 24 - 8,
1225        /* TSI_LERR_INT_VEC                     258 */  256 + 13 - 8,
1226        /* TSI_VERR_INT_VEC                     259 */  256 + 12 - 8,
1227        /* 260 is reserved       */                     -1,
1228        /* TSI_VME_SW_IACK_INT_VEC      261 */  256 + 10 - 8,
1229        /* 262 no PCI SW IRQ     */                     -1,
1230        /* TSI_SYSFAIL_INT_VEC          263 */  256 +  9 - 8,
1231        /* TSI_ACFAIL_INT_VEC           264 */  256 +  8 - 8,
1232        /* TSI_MBOX0_INT_VEC            265 */  256 + 16 - 8,
1233        /* TSI_MBOX1_INT_VEC            266 */  256 + 17 - 8,
1234        /* TSI_MBOX2_INT_VEC            267 */  256 + 18 - 8,
1235        /* TSI_MBOX3_INT_VEC            268 */  256 + 19 - 8,
1236        /* TSI_LM0_INT_VEC                      269 */  256 + 20 - 8,
1237        /* TSI_LM1_INT_VEC                      270 */  256 + 21 - 8,
1238        /* TSI_LM2_INT_VEC                      271 */  256 + 22 - 8,
1239        /* TSI_LM3_INT_VEC                      272 */  256 + 23 - 8,
1240/* New vectors; only on TSI148 */
1241        /* TSI_VIES_INT_VEC                     273 */  256 + 11 - 8,
1242        /* TSI_DMA1_INT_VEC                     274 */  256 + 25 - 8,
1243};
1244
1245/* and the reverse; map tsi bit number to universe compatible 'special' vector number */
1246static int tsi2uni_vec_map[TSI_NUM_INT_VECS - 256] = {
1247        TSI_ACFAIL_INT_VEC,
1248        TSI_SYSFAIL_INT_VEC,
1249        TSI_VME_SW_IACK_INT_VEC,
1250        TSI_VIES_INT_VEC,
1251        TSI_VERR_INT_VEC,
1252        TSI_LERR_INT_VEC,
1253        -1,
1254        -1,
1255        TSI_MBOX0_INT_VEC,
1256        TSI_MBOX1_INT_VEC,
1257        TSI_MBOX2_INT_VEC,
1258        TSI_MBOX3_INT_VEC,
1259        TSI_LM0_INT_VEC,
1260        TSI_LM1_INT_VEC,
1261        TSI_LM2_INT_VEC,
1262        TSI_LM3_INT_VEC,
1263        TSI_DMA_INT_VEC,
1264        TSI_DMA1_INT_VEC,
1265        -1,
1266};
1267
1268static inline int
1269uni2tsivec(int v)
1270{
1271        if ( v < 0 || v >= TSI_NUM_INT_VECS )
1272                return -1;
1273        return v < 256 ? v : uni2tsi_vec_map[v-256];
1274}
1275
1276static int
1277lvl2bitno(unsigned int level)
1278{
1279        if ( level >= 256 )
1280                return uni2tsivec(level) + 8 - 256;
1281        else if ( level < 8 && level > 0 )
1282                return level;
1283        return -1;
1284}
1285
1286int
1287vmeTsi148IntRoute(unsigned int level, unsigned int pin)
1288{
1289int                             i;
1290unsigned long   mask, shift, mapreg, flags, wire;
1291
1292        if ( pin >= TSI_NUM_WIRES || ! tsi_wire[pin] || !vmeTsi148IrqMgrInstalled )
1293                return -1;
1294
1295        if ( level >= 256 ) {
1296                if ( (i = uni2tsivec(level)) < 0 )
1297                        return -1;
1298                shift = 8 + (i-256);
1299        } else if ( 1 <= level && level <=7 ) {
1300                shift = level;
1301        } else {
1302                return -1;      /* invalid level */
1303        }
1304
1305        mask = 1<<shift;
1306
1307        /* calculate the mapping register and contents */
1308        if ( shift < 16 ) {
1309                mapreg = TSI_INTM2_REG;
1310        } else if ( shift < 32 ) {
1311                shift -= 16;
1312                mapreg = TSI_INTM1_REG;
1313        } else {
1314                return -1;
1315        }
1316
1317        shift <<=1;
1318
1319        /* wires are offset by 1 so we can initialize the wire table to all zeros */
1320        wire = (tsi_wire[pin]-1) << shift;
1321
1322rtems_interrupt_disable(flags);
1323
1324        for ( i = 0; i<TSI_NUM_WIRES; i++ ) {
1325                wire_mask[i] &= ~mask;
1326        }
1327        wire_mask[pin] |= mask;
1328
1329        mask = TSI_RD(devs[0].base, mapreg) & ~ (0x3<<shift);
1330        mask |= wire;
1331        TSI_WR( devs[0].base, mapreg, mask );
1332
1333rtems_interrupt_enable(flags);
1334        return 0;
1335}
1336
1337VmeTsi148ISR
1338vmeTsi148ISRGet(unsigned long vector, void **parg)
1339{
1340VmeTsi148ISR      rval = 0;
1341unsigned long     flags;
1342volatile IRQEntry *p;
1343int               v = uni2tsivec(vector);
1344
1345
1346        if ( v < 0 )
1347                return rval;
1348
1349        p = irqHdlTbl + v;
1350
1351        rtems_interrupt_disable(flags);
1352                if ( *p ) {
1353                        if ( parg )
1354                                *parg = (*p)->usrData;
1355                        rval = (*p)->isr;
1356                }
1357        rtems_interrupt_enable(flags);
1358
1359        return rval;
1360}
1361
1362static void
1363tsiVMEISR(rtems_irq_hdl_param arg)
1364{
1365int                                     pin = (int)arg;
1366BERegister                      *= devs[0].base;
1367IRQEntry                        ip;
1368unsigned long           msk,lintstat,vector, vecarg;
1369int                                     lvl;
1370
1371        /* only handle interrupts routed to this pin */
1372
1373        /* NOTE: we read the status register over VME, thus flushing the FIFO
1374         *       where the user ISR possibly left write commands to clear
1375         *       the interrupt condition at the device.
1376         *       This is very important - otherwise, the IRQ level may still be
1377         *       asserted and we would detect an interrupt here but the subsequent
1378         *       IACK would fail since the write operation was flushed to the
1379         *       device in the mean time.
1380         */
1381        while ( (lintstat  = (TSI_RD(vmeTsi148RegBase, TSI_INTS_REG) & wire_mask[pin])) ) {
1382
1383                /* bit 0 is never set since it is never set in wire_mask */
1384
1385                do {
1386                        /* simplicity is king; just handle them in MSB to LSB order; reserved bits read as 0 */
1387#ifdef __PPC__
1388                        asm volatile("cntlzw %0, %1":"=r"(lvl):"r"(lintstat));
1389                        lvl = 31-lvl;
1390                        msk = 1<<lvl;
1391#else
1392                        { static unsigned long m[] = {
1393                                                                                         0xffff0000, 0xff00ff00, 0xf0f0f0f0, 0xcccccccc, 0xaaaaaaaa
1394                                                                                 };
1395                        int      i;
1396                        unsigned tmp;
1397
1398                        /* lintstat has already been checked...
1399                        if ( !lintstat ) {
1400                           lvl = -1; msk = 0;
1401                        } else
1402                         */
1403                        for ( i=0, lvl=0, msk = lintstat; i<5; i++ ) {
1404                                lvl <<= 1;
1405                                if ( (tmp = msk & m[i]) ) {
1406                                        lvl++;
1407                                        msk = tmp;
1408                                } else
1409                                        msk = msk & ~m[i];
1410                        }
1411                        }
1412#endif
1413
1414                        if ( lvl > 7 ) {
1415                                /* clear this interrupt level */
1416                                TSI_WR(b, TSI_INTC_REG, msk);
1417                                vector = 256 + lvl - 8;
1418                                vecarg = tsi2uni_vec_map[lvl-8];
1419                        } else {
1420                                /* need to do get the vector for this level */
1421                                switch ( tsi_iack_width[lvl-1] ) {
1422                                        default:
1423                                        case  1:
1424                                                vector = TSI_RD8(b, TSI_VIACK_1_REG - 4 + (lvl<<2) + 3);
1425                                                break;
1426
1427                                        case  2:
1428                                                vector = TSI_RD16(b, TSI_VIACK_1_REG - 4 + (lvl<<2) + 2);
1429                                                break;
1430
1431                                        case  4:
1432                                                vector = TSI_RD(b, TSI_VIACK_1_REG - 4 + (lvl<<2));
1433                                                break;
1434                                }
1435                                vecarg = vector;
1436                        }
1437
1438                        if ( !(ip=irqHdlTbl[vector])) {
1439                                /* TODO: log error message - RTEMS has no logger :-( */
1440                                vmeTsi148IntDisable(lvl);
1441                                printk("vmeTsi148 ISR: ERROR: no handler registered (level %i) IACK 0x%08x -- DISABLING level %i\n",
1442                                                lvl, vector, lvl);
1443                        } else {
1444                                /* dispatch handler, it must clear the IRQ at the device */
1445                                ip->isr(ip->usrData, vecarg);
1446                                /* convenience for disobedient users who don't use in_xxx/out_xxx; make
1447                                 * sure we order the subsequent read from the status register after
1448                                 * their business.
1449                                 */
1450                                iobarrier_rw();
1451                        }
1452                } while ( (lintstat &= ~msk) );
1453                /* check if a new irq is pending already */
1454        }
1455}
1456
1457
1458static void
1459my_no_op(const rtems_irq_connect_data * arg)
1460{}
1461
1462static int
1463my_isOn(const rtems_irq_connect_data *arg)
1464{
1465                return (int)(TSI_RD(devs[0].base, TSI_INTEO_REG) & TSI_RD(devs[0].base, TSI_INTEN_REG));
1466}
1467
1468static void
1469connectIsr(int shared, rtems_irq_hdl isr, int pic_line, int slot)
1470{
1471rtems_irq_connect_data  xx;
1472        xx.on     = my_no_op; /* at _least_ they could check for a 0 pointer */
1473        xx.off    = my_no_op;
1474        xx.isOn   = my_isOn;
1475        xx.hdl    = isr;
1476        xx.handle = (rtems_irq_hdl_param)slot; 
1477        xx.name   = pic_line;
1478
1479        if ( shared ) {
1480#if BSP_SHARED_HANDLER_SUPPORT > 0
1481                if (!BSP_install_rtems_shared_irq_handler(&xx))
1482                        BSP_panic("unable to install vmeTsi148 shared irq handler");
1483#else
1484        uprintf(stderr,"vmeTsi148: WARNING: your BSP doesn't support sharing interrupts\n");
1485                if (!BSP_install_rtems_irq_handler(&xx))
1486                        BSP_panic("unable to install vmeTsi148 irq handler");
1487#endif
1488        } else {
1489                if (!BSP_install_rtems_irq_handler(&xx))
1490                        BSP_panic("unable to install vmeTsi148 irq handler");
1491        }
1492}
1493
1494int
1495vmeTsi148InstallIrqMgrAlt(int shared, int tsi_pin0, int pic_pin0, ...)
1496{
1497int             rval;
1498va_list ap;
1499        va_start(ap, pic_pin0);
1500        rval = vmeTsi148InstallIrqMgrVa(shared, tsi_pin0, pic_pin0, ap);
1501        va_end(ap);
1502        return rval;
1503}
1504
1505#ifndef BSP_EARLY_PROBE_VME
1506#define BSP_EARLY_PROBE_VME(addr)       \
1507        (                                                                                                                                                                                                       \
1508                vmeTsi148ClearVMEBusErrorsXX( devs[0].base, 0 ),                                                                                                \
1509                ( ((PCI_DEVICE_TSI148 << 16) | PCI_VENDOR_TUNDRA ) == TSI_LE_RD32( ((BERegister*)(addr)), 0 )   \
1510                 && 0 == vmeTsi148ClearVMEBusErrorsXX( devs[0].base, 0 ) )                                                                              \
1511        )
1512#endif
1513
1514/* Check if there is a vme address/as is mapped in any of the outbound windows
1515 * and look for the PCI vendordevice ID there.
1516 * RETURNS: -1 on error (no mapping or probe failure), outbound window # (0..7)
1517 *          on success. Address translated into CPU address is returned in *pcpu_addr.
1518 */
1519static int
1520mappedAndProbed(unsigned long vme_addr, unsigned as, unsigned long *pcpu_addr)
1521{
1522int j;
1523char *regtype = (as & VME_AM_MASK) == VME_AM_CSR ? "CSR" : "CRG";
1524
1525        /* try to find mapping */
1526        if ( 0 > (j = xlateFindPort(
1527                                devs[0].base,
1528                                1, 0,
1529                                as | VME_MODE_AS_MATCH,
1530                                vme_addr,
1531                                pcpu_addr ) ) ) {
1532                        uprintf(stderr,"vmeTsi148 - Unable to find mapping for %s VME base (0x%08x)\n", regtype, vme_addr);
1533                        uprintf(stderr,"            in outbound windows.\n");
1534        }
1535        else {
1536                        /* found a slot number; probe it */
1537                        *pcpu_addr = BSP_PCI2LOCAL_ADDR( *pcpu_addr );
1538                        if ( BSP_EARLY_PROBE_VME(*pcpu_addr) ) {
1539                                uprintf(stderr,"vmeTsi148 - IRQ manager using VME %s to flush FIFO\n", regtype);
1540                                return j;
1541                        } else {
1542                                uprintf(stderr,"vmeTsi148 - Found slot info but detection of tsi148 in VME %s space failed\n", regtype);
1543                        }
1544        }
1545        return -1;
1546}
1547
1548int
1549vmeTsi148InstallIrqMgrVa(int shared, int tsi_pin0, int pic_pin0, va_list ap)
1550{
1551int     i,j, specialPin, tsi_pin[TSI_NUM_WIRES+1], pic_pin[TSI_NUM_WIRES];
1552unsigned long cpu_base, vme_reg_base;
1553
1554        if (vmeTsi148IrqMgrInstalled)                  return -4;
1555
1556        /* check parameters */
1557
1558        if ( tsi_pin0 < 0 || tsi_pin0 > 3 )            return -1;
1559
1560        tsi_pin[0] = tsi_pin0;
1561        pic_pin[0] = pic_pin0 < 0 ? devs[0].irqLine : pic_pin0;
1562        i = 1;
1563        while ( (tsi_pin[i] = va_arg(ap, int)) >= 0 ) {
1564               
1565                if ( i >= TSI_NUM_WIRES ) {
1566                                                               return -5;
1567                }
1568
1569                pic_pin[i] = va_arg(ap,int);
1570
1571                if ( tsi_pin[i] > 3 )                      return -2;
1572                if ( pic_pin[i] < 0 )                      return -3;
1573                i++;
1574        }
1575
1576        /* all routings must be different */
1577        for ( i=0; tsi_pin[i] >= 0; i++ ) {
1578                for ( j=i+1; tsi_pin[j] >= 0; j++ ) {
1579                        if ( tsi_pin[j] == tsi_pin[i] )        return -6;
1580                        if ( pic_pin[j] == pic_pin[i] )        return -7;
1581                }
1582        }
1583
1584        i        = -1;
1585
1586        /* first try VME CSR space; do we have a base address set ? */
1587
1588        uprintf(stderr,"vmeTsi148 IRQ manager: looking for registers on VME...\n");
1589
1590        if ( ( i = ((TSI_RD( devs[0].base, TSI_CBAR_REG ) & 0xff) >> 3) ) > 0 ) {
1591                uprintf(stderr,"Trying to find CSR on VME...\n");
1592                vme_reg_base = i*0x80000 + TSI_CSR_OFFSET;
1593                i = mappedAndProbed( vme_reg_base, VME_AM_CSR , &cpu_base);
1594                if ( i >= 0 )
1595                        vmeTsi148RegCSR = 1;
1596        } else {
1597                i = -1;
1598        }
1599
1600        if ( -1 == i ) {
1601
1602                uprintf(stderr,"Trying to find CRG on VME...\n");
1603
1604                /* Next we see if the CRG block is mapped to VME */
1605
1606                if ( (TSI_CRGAT_EN & (j = TSI_RD( devs[0].base, TSI_CRGAT_REG ))) ) {
1607                        switch ( j & TSI_CRGAT_AS_MSK ) {
1608                                case TSI_CRGAT_A16 : i = VME_AM_SUP_SHORT_IO; break;
1609                                case TSI_CRGAT_A24 : i = VME_AM_STD_SUP_DATA; break;
1610                                case TSI_CRGAT_A32 : i = VME_AM_EXT_SUP_DATA; break;
1611                                default:
1612                                break;
1613                        }
1614                        vme_reg_base = TSI_RD( devs[0].base, TSI_CBAL_REG ) & ~ (TSI_CRG_SIZE - 1);
1615                }
1616
1617                if ( -1 == i ) {
1618                } else {
1619                        i = mappedAndProbed( vme_reg_base, (i & VME_AM_MASK), &cpu_base );
1620                }
1621        }
1622
1623        if ( i < 0 ) {
1624                        uprintf(stderr,"vmeTsi148 IRQ manager - BSP configuration error: registers not found on VME\n");
1625                        uprintf(stderr,"(should open outbound window to CSR space or map CRG [vmeTsi148MapCRG()])\n");
1626                        uprintf(stderr,"Falling back to PCI but you might experience spurious VME interrupts; read a register\n");
1627                        uprintf(stderr,"back from user ISR to flush posted-write FIFO as a work-around\n");
1628                        cpu_base = (unsigned long)devs[0].base;
1629                        i        = -1;
1630        }
1631
1632        vmeTsi148RegBase = (BERegister*)cpu_base;
1633        vmeTsi148RegPort = i;
1634
1635        /* give them a chance to override buggy PCI info */
1636        if ( pic_pin[0] >= 0 && devs[0].irqLine != pic_pin[0] ) {
1637                uprintf(stderr,"Overriding main IRQ line PCI info with %d\n",
1638                                pic_pin[0]);
1639                devs[0].irqLine = pic_pin[0];
1640        }
1641
1642        for ( i = 0; tsi_pin[i] >= 0; i++ ) {
1643                /* offset wire # by one so we can initialize to 0 == invalid */
1644                tsi_wire[i] = tsi_pin[i] + 1;
1645                connectIsr(shared, tsiVMEISR, pic_pin[i], i);
1646        }
1647
1648        specialPin = tsi_pin[1] >= 0 ? 1 : 0;
1649
1650        /* setup routing */
1651       
1652        /* IntRoute checks for mgr being installed */
1653        vmeTsi148IrqMgrInstalled=1;
1654
1655        /* route 7 VME irqs to first / 'normal' pin */
1656        for ( i=1; i<8; i++ )
1657                vmeTsi148IntRoute( i, 0 );
1658        for ( i=TSI_DMA_INT_VEC; i<TSI_NUM_INT_VECS; i++ )
1659                vmeTsi148IntRoute( i, specialPin );
1660
1661        for ( i = 0; i<TSI_NUM_WIRES; i++ ) {
1662                /* remember (for unloading the driver) */
1663                devs[0].pic_pin[i] = ( ( tsi_pin[i] >=0 ) ? pic_pin[i] : -1 );
1664        }
1665
1666        return 0;
1667}
1668
1669int
1670vmeTsi148InstallISR(unsigned long vector, VmeTsi148ISR hdl, void *arg)
1671{
1672IRQEntry          ip;
1673int                               v;
1674unsigned long     flags;
1675volatile IRQEntry *p;
1676
1677                if ( !vmeTsi148IrqMgrInstalled || (v = uni2tsivec(vector)) < 0 )
1678                        return -1;
1679
1680                p = irqHdlTbl + v;
1681
1682                if (*p || !(ip=(IRQEntry)malloc(sizeof(IRQEntryRec))))
1683                                return -1;
1684
1685                ip->isr=hdl;
1686                ip->usrData=arg;
1687
1688                rtems_interrupt_disable(flags);
1689                if (*p) {
1690                        rtems_interrupt_enable(flags);
1691                        free(ip);
1692                        return -1;
1693                }
1694                *p = ip;
1695                rtems_interrupt_enable(flags);
1696                return 0;
1697}
1698
1699int
1700vmeTsi148RemoveISR(unsigned long vector, VmeTsi148ISR hdl, void *arg)
1701{
1702int               v;
1703IRQEntry          ip;
1704unsigned long     flags;
1705volatile IRQEntry *p;
1706
1707                if ( !vmeTsi148IrqMgrInstalled || (v = uni2tsivec(vector)) < 0 )
1708                        return -1;
1709
1710                p = irqHdlTbl + v;
1711
1712                rtems_interrupt_disable(flags);
1713                ip = *p;
1714                if ( !ip || ip->isr!=hdl || ip->usrData!=arg ) {
1715                                rtems_interrupt_enable(flags);
1716                                return -1;
1717                }
1718                *p = 0;
1719                rtems_interrupt_enable(flags);
1720
1721                free(ip);
1722                return 0;
1723}
1724
1725static int
1726intDoEnDis(unsigned int level, int dis)
1727{
1728BERegister              *b = devs[0].base;
1729unsigned long   flags, v;
1730int                             shift;
1731
1732        if (  ! vmeTsi148IrqMgrInstalled || (shift = lvl2bitno(level)) < 0 )
1733                return -1;
1734
1735        v = 1<<shift;
1736
1737        if ( !dis )
1738                return (int)(v & TSI_RD(b, TSI_INTEO_REG) & TSI_RD(b, TSI_INTEN_REG)) ? 1 : 0;
1739
1740        rtems_interrupt_disable(flags);
1741        if ( dis<0 ) {
1742                TSI_WR(b, TSI_INTEN_REG, TSI_RD(b, TSI_INTEN_REG) & ~v);
1743                TSI_WR(b, TSI_INTEO_REG, TSI_RD(b, TSI_INTEO_REG) & ~v);
1744        } else {
1745                TSI_WR(b, TSI_INTEN_REG, TSI_RD(b, TSI_INTEN_REG) |  v);
1746                TSI_WR(b, TSI_INTEO_REG, TSI_RD(b, TSI_INTEO_REG) |  v);
1747        }
1748        rtems_interrupt_enable(flags);
1749        return 0;
1750}
1751
1752int
1753vmeTsi148IntEnable(unsigned int level)
1754{
1755        return intDoEnDis(level, 1);
1756}
1757
1758int
1759vmeTsi148IntDisable(unsigned int level)
1760{
1761        return intDoEnDis(level, -1);
1762}
1763
1764int
1765vmeTsi148IntIsEnabled(unsigned int level)
1766{
1767        return intDoEnDis(level, 0);
1768}
1769
1770/* Set IACK width (1,2, or 4 bytes) for a given interrupt level.
1771 *
1772 * 'width' arg may be 0,1,2 or 4. If zero, the currently active
1773 * value is returned but not modified.
1774 *
1775 * RETURNS: old width or -1 if invalid argument.
1776 */
1777
1778int
1779vmeTsi148SetIackWidth(int level, int width)
1780{
1781int rval;
1782        if ( level < 1 || level > 7 || !vmeTsi148IrqMgrInstalled )
1783                return -1;
1784
1785        switch ( width ) {
1786                default: return -1;
1787                case 0:
1788                case 1:
1789                case 2:
1790                case 4:
1791                break;
1792        }
1793
1794        rval = tsi_iack_width[level-1];
1795        if ( width )
1796                tsi_iack_width[level-1] = width;
1797        return rval;
1798}
1799
1800int
1801vmeTsi148IntRaiseXX(BERegister *base, int level, unsigned vector)
1802{
1803unsigned long v;
1804
1805        CHECK_BASE(base,0,-1);
1806
1807        if ( level < 1 || level > 7 || vector > 255 )
1808                return -1;      /* invalid argument */
1809
1810        /* Check if already asserted */
1811        if ( (v = TSI_RD(base, TSI_VICR_REG)) & TSI_VICR_IRQS ) {
1812                return -2;  /* already asserted */
1813        }
1814
1815        v &= ~255;
1816
1817        v |= TSI_VICR_IRQL(level) | TSI_VICR_STID(vector);
1818
1819        /* Write Vector */
1820        TSI_WR(base, TSI_VICR_REG, v);
1821
1822        return 0;
1823       
1824}
1825
1826int
1827vmeTsi148IntRaise(int level, unsigned vector)
1828{
1829        return vmeTsi148IntRaiseXX(devs[0].base, level, vector);
1830}
1831
1832/* Loopback test of VME/Tsi148 internal interrupts */
1833
1834typedef struct {
1835        rtems_id        q;
1836        int                     l;
1837} LoopbackTstArgs;
1838
1839static void
1840loopbackTstIsr(void *arg, unsigned long vector)
1841{
1842LoopbackTstArgs *pa = arg;
1843        if ( RTEMS_SUCCESSFUL != rtems_message_queue_send(pa->q, (void*)&vector, sizeof(vector)) ) {
1844                /* Overrun ? */
1845                printk("vmeTsi148IntLoopbackTst: (ISR) message queue full / overrun ? disabling IRQ level %i\n", pa->l);
1846                vmeTsi148IntDisable(pa->l);
1847        }
1848}
1849
1850int
1851vmeTsi148IntLoopbackTst(int level, unsigned vector)
1852{
1853BERegister                      *b = devs[0].base;
1854rtems_status_code       sc;
1855rtems_id                        q = 0;
1856int                                     installed = 0;
1857int                                     i, err = 0;
1858int                                     doDisable = 0;
1859uint32_t                        size;
1860unsigned long           msg;
1861char *                          irqfmt  = "VME IRQ @vector %3i %s";
1862char *                          iackfmt = "VME IACK            %s";
1863LoopbackTstArgs         a;
1864
1865        CHECK_BASE(b,0,-1);
1866
1867        /* arg check */
1868        if ( level < 1 || level > 7 || vector > 255 )
1869                return -1;
1870
1871        /* Create message queue */
1872        if ( RTEMS_SUCCESSFUL != (sc=rtems_message_queue_create(
1873                                                                        rtems_build_name('t' ,'U','I','I'),
1874                                                                        4,
1875                                                                        sizeof(unsigned long),
1876                                                                        0,  /* default attributes: fifo, local */
1877                                                                        &q)) ) {
1878                rtems_error(sc, "vmeTsi148IntLoopbackTst: Unable to create message queue");
1879                goto bail;
1880        }
1881
1882        a.q = q;
1883        a.l = level;
1884
1885        /* Install handlers */
1886        if ( vmeTsi148InstallISR(vector, loopbackTstIsr, (void*)&a) ) {
1887                uprintf(stderr,"Unable to install VME ISR to vector %i\n",vector);
1888                goto bail;
1889        }
1890        installed++;
1891        if ( vmeTsi148InstallISR(TSI_VME_SW_IACK_INT_VEC, loopbackTstIsr, (void*)&a) ) {
1892                uprintf(stderr,"Unable to install VME ISR to IACK special vector %i\n",TSI_VME_SW_IACK_INT_VEC);
1893                goto bail;
1894        }
1895        installed++;
1896
1897        if ( !vmeTsi148IntIsEnabled(level) && 0==vmeTsi148IntEnable(level) )
1898                doDisable = 1;
1899       
1900        /* make sure there are no pending interrupts */
1901        TSI_WR(b, TSI_INTC_REG, TSI_INTC_IACKC);
1902
1903        if ( vmeTsi148IntEnable( TSI_VME_SW_IACK_INT_VEC ) ) {
1904                uprintf(stderr,"Unable to enable IACK interrupt\n");
1905                goto bail;
1906        }
1907
1908        printf("vmeTsi148 VME interrupt loopback test; STARTING...\n");
1909        printf(" --> asserting VME IRQ level %i\n", level);
1910        vmeTsi148IntRaise(level, vector);
1911
1912        for ( i = 0; i< 3; i++ ) {
1913        sc = rtems_message_queue_receive(
1914                            q,
1915                            &msg,
1916                            &size,
1917                            RTEMS_WAIT,
1918                            20);
1919                if ( sc ) {
1920                        if ( RTEMS_TIMEOUT == sc && i>1 ) {
1921                                /* OK; we dont' expect more to happen */
1922                                sc = 0;
1923                        } else {
1924                                rtems_error(sc,"Error waiting for interrupts");
1925                        }
1926                        break;
1927                }
1928                if ( msg == vector ) {
1929                        if ( !irqfmt ) {
1930                                printf("Excess VME IRQ received ?? -- BAD\n");
1931                                err = 1;
1932                        } else {
1933                                printf(irqfmt, vector, "received -- PASSED\n");
1934                                irqfmt = 0;
1935                        }
1936                } else if ( msg == TSI_VME_SW_IACK_INT_VEC ) {
1937                        if ( !iackfmt ) {
1938                                printf("Excess VME IACK received ?? -- BAD\n");
1939                                err = 1;
1940                        } else {
1941                                printf(iackfmt, "received -- PASSED\n");
1942                                iackfmt = 0;
1943                        }
1944                } else {
1945                        printf("Unknown IRQ (vector %lu) received -- BAD\n", msg);
1946                        err = 1;
1947                }
1948        }
1949
1950
1951        /* Missing anything ? */
1952        if ( irqfmt ) {
1953                printf(irqfmt,vector, "MISSED -- BAD\n");
1954                err = 1;
1955        }
1956        if ( iackfmt ) {
1957                printf(iackfmt, "MISSED -- BAD\n");
1958                err = 1;
1959        }
1960
1961        printf("FINISHED.\n");
1962
1963bail:
1964        if ( doDisable )
1965                vmeTsi148IntDisable(level);
1966        vmeTsi148IntDisable( TSI_VME_SW_IACK_INT_VEC );
1967        if ( installed > 0 )
1968                vmeTsi148RemoveISR(vector, loopbackTstIsr, (void*)&a);
1969        if ( installed > 1 )
1970                vmeTsi148RemoveISR(TSI_VME_SW_IACK_INT_VEC, loopbackTstIsr, (void*)&a);
1971        if ( q )
1972                rtems_message_queue_delete(q);
1973
1974        return sc ? sc : err;
1975}
1976
1977unsigned long
1978vmeTsi148ClearVMEBusErrorsXX(BERegister *base, uint32_t *paddr)
1979{
1980unsigned long rval;
1981
1982        CHECK_BASE(base,1,-1);
1983
1984        rval = TSI_RD(base, TSI_VEAT_REG);
1985        if ( rval & TSI_VEAT_VES ) {
1986                if ( paddr ) {
1987#if 0 /* no 64-bit support yet */
1988                        *paddr  = ((unsigned long long)TSI_RD(base, TSI_VEAU_REG))<<32;
1989                        *paddr |= TSI_RD(base, TSI_VEAL_REG);
1990#else
1991                        *paddr = TSI_RD(base, TSI_VEAL_REG);
1992#endif
1993                }
1994                /* clear errors */
1995                TSI_WR(base, TSI_VEAT_REG, TSI_VEAT_VESCL);
1996        } else {
1997                rval = 0;
1998        }
1999        return rval;
2000}
2001
2002unsigned long
2003vmeTsi148ClearVMEBusErrors(uint32_t *paddr)
2004{
2005        return vmeTsi148ClearVMEBusErrorsXX(devs[0].base, paddr);
2006}
2007
2008#ifdef DEBUG_MODULAR
2009void
2010_cexpModuleInitialize(void* unused)
2011{
2012        vmeTsi148Init();
2013        vmeTsi148Reset();
2014}
2015
2016int
2017_cexpModuleFinalize(void *unused)
2018{
2019int             i;
2020int             rval = 1;
2021void    (*isrs[TSI_NUM_WIRES])() = {
2022        isr_pin0,
2023        isr_pin1,
2024        isr_pin2,
2025        isr_pin3,
2026};
2027
2028rtems_irq_connect_data  xx;
2029        xx.on   = my_no_op; /* at _least_ they could check for a 0 pointer */
2030        xx.off  = my_no_op;
2031        xx.isOn = my_isOn;
2032
2033        TSI_WR(devs[0].base, TSI_INTEO_REG, 0);
2034
2035        for ( i=0; i<TSI_NUM_INT_VECS; i++) {
2036                /* Dont even bother to uninstall handlers */
2037        }
2038        if ( vmeTsi148IrqMgrInstalled ) {
2039                for ( i=0; i<TSI_NUM_WIRES; i++ ) {
2040                        if ( (int)(xx.name = devs[0].pic_pin[i]) >=0 ) {
2041                                xx.hdl  = isrs[i];
2042                                rval    = rval && BSP_remove_rtems_irq_handler(&xx);
2043                        }
2044                }
2045        }
2046        return !rval;
2047}
2048#endif
Note: See TracBrowser for help on using the repository browser.