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

4.104.114.84.95
Last change on this file since 9c6019ed was 9c6019ed, checked in by Till Straumann <strauman@…>, on 07/16/07 at 06:01:14
  • vmeUniverse/vmeTsi148.c: Use size_t for sizes.
  • Property mode set to 100644
File size: 67.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#include <bsp/VMEDMA.h>
65#include "vmeTsi148DMA.h"
66#include "bspVmeDmaListP.h"
67
68
69#define DEBUG
70
71#ifdef DEBUG
72#define STATIC
73#else
74#define STATIC static
75#endif
76
77/* The tsi has 4 'local' wires that can be hooked to a PIC */
78
79#define TSI_NUM_WIRES                   4
80
81#define TSI148_NUM_OPORTS               8 /* number of outbound ports */
82#define TSI148_NUM_IPORTS               8 /* number of inbound  ports */
83
84#define NUM_TSI_DEVS                    2 /* number of instances supported */
85
86#define PCI_VENDOR_TUNDRA       0x10e3
87#define PCI_DEVICE_TSI148       0x0148
88
89#define TSI_OTSAU_SPACING       0x020
90
91#define TSI_OTSAU0_REG          0x100
92#define TSI_OTSAL0_REG          0x104
93#define TSI_OTEAU0_REG          0x108
94#define TSI_OTEAL0_REG          0x10c
95#define TSI_OTOFU0_REG          0x110
96#define TSI_OTOFL0_REG          0x114
97#define TSI_OTBS0_REG           0x118   /* 2eSST broadcast select */
98#define TSI_OTAT0_REG           0x11c
99#define TSI_OTSAU_REG(port)     (TSI_OTSAU0_REG + ((port)<<5))
100#define TSI_OTSAL_REG(port)     (TSI_OTSAL0_REG + ((port)<<5))
101#define TSI_OTEAU_REG(port)     (TSI_OTEAU0_REG + ((port)<<5))
102#define TSI_OTEAL_REG(port)     (TSI_OTEAL0_REG + ((port)<<5))
103#define TSI_OTOFU_REG(port)     (TSI_OTOFU0_REG + ((port)<<5))
104#define TSI_OTOFL_REG(port)     (TSI_OTOFL0_REG + ((port)<<5))
105#define TSI_OTBS_REG(port)      (TSI_OTBS0_REG + ((port)<<5))
106#define TSI_OTAT_REG(port)      (TSI_OTAT0_REG + ((port)<<5))
107#       define TSI_OTAT_EN                      (1<<31)
108#       define TSI_OTAT_MRPFD           (1<<18)
109#       define TSI_OTAT_PFS(x)          (((x)&3)<<16)
110#       define TSI_OTAT_2eSSTM(x)       (((x)&7)<<11)
111#       define TSI_OTAT_2eSSTM_160      TSI_OTAT_2eSSTM(0)
112#       define TSI_OTAT_2eSSTM_267      TSI_OTAT_2eSSTM(1)
113#       define TSI_OTAT_2eSSTM_320      TSI_OTAT_2eSSTM(2)
114#       define TSI_OTAT_TM(x)           (((x)&7)<<8)
115#               define TSI_TM_SCT_IDX           0
116#               define TSI_TM_BLT_IDX           1
117#               define TSI_TM_MBLT_IDX          2
118#               define TSI_TM_2eVME_IDX         3
119#               define TSI_TM_2eSST_IDX         4
120#               define TSI_TM_2eSSTB_IDX        5
121#       define TSI_OTAT_DBW(x)          (((x)&3)<<6)
122#       define TSI_OTAT_SUP                     (1<<5)
123#       define TSI_OTAT_PGM                     (1<<4)
124#       define TSI_OTAT_ADMODE(x)       (((x)&0xf))
125#       define TSI_OTAT_ADMODE_A16      0
126#       define TSI_OTAT_ADMODE_A24      1
127#       define TSI_OTAT_ADMODE_A32      2
128#       define TSI_OTAT_ADMODE_A64      4
129#       define TSI_OTAT_ADMODE_CSR      5
130#       define TSI_OTAT_ADMODE_USR1     8
131#       define TSI_OTAT_ADMODE_USR2     9
132#       define TSI_OTAT_ADMODE_USR3     0xa
133#       define TSI_OTAT_ADMODE_USR4     0xb
134
135#define TSI_VIACK_1_REG         0x204
136
137#define TSI_VSTAT_REG           0x23c
138#       define TSI_VSTAT_CPURST         (1<<15) /* clear power-up reset bit */
139#       define TSI_VSTAT_BDFAIL         (1<<14)
140#       define TSI_VSTAT_PURSTS         (1<<12)
141#       define TSI_VSTAT_BDFAILS        (1<<11)
142#       define TSI_VSTAT_SYSFLS         (1<<10)
143#       define TSI_VSTAT_ACFAILS        (1<< 9)
144#       define TSI_VSTAT_SCONS          (1<< 8)
145#       define TSI_VSTAT_GAP            (1<< 5)
146#       define TSI_VSTAT_GA_MSK         (0x1f)
147
148#define TSI_VEAU_REG            0x260
149#define TSI_VEAL_REG            0x264
150#define TSI_VEAT_REG            0x268
151
152#define TSI_ITSAU_SPACING       0x020
153
154#define TSI_ITSAU0_REG          0x300
155#define TSI_ITSAL0_REG          0x304
156#define TSI_ITEAU0_REG          0x308
157#define TSI_ITEAL0_REG          0x30c
158#define TSI_ITOFU0_REG          0x310
159#define TSI_ITOFL0_REG          0x314
160#define TSI_ITAT0_REG           0x318
161#define TSI_ITSAU_REG(port)     (TSI_ITSAU0_REG + ((port)<<5))
162#define TSI_ITSAL_REG(port)     (TSI_ITSAL0_REG + ((port)<<5))
163#define TSI_ITEAU_REG(port)     (TSI_ITEAU0_REG + ((port)<<5))
164#define TSI_ITEAL_REG(port)     (TSI_ITEAL0_REG + ((port)<<5))
165#define TSI_ITOFU_REG(port)     (TSI_ITOFU0_REG + ((port)<<5))
166#define TSI_ITOFL_REG(port)     (TSI_ITOFL0_REG + ((port)<<5))
167#define TSI_ITAT_REG(port)      (TSI_ITAT0_REG + ((port)<<5))
168
169#       define TSI_ITAT_EN                      (1<<31)
170#       define TSI_ITAT_TH                      (1<<18)
171#       define TSI_ITAT_VFS(x)          (((x)&3)<<16)
172#       define TSI_ITAT_2eSSTM(x)       (((x)&7)<<12)
173#       define TSI_ITAT_2eSSTM_160      TSI_ITAT_2eSSTM(0)
174#       define TSI_ITAT_2eSSTM_267      TSI_ITAT_2eSSTM(1)
175#       define TSI_ITAT_2eSSTM_320      TSI_ITAT_2eSSTM(2)
176#       define TSI_ITAT_2eSSTB          (1<<11)
177#       define TSI_ITAT_2eSST           (1<<10)
178#       define TSI_ITAT_2eVME           (1<<9)
179#       define TSI_ITAT_MBLT            (1<<8)
180#       define TSI_ITAT_BLT                     (1<<7)
181#       define TSI_ITAT_AS(x)           (((x)&7)<<4)
182#       define TSI_ITAT_ADMODE_A16      (0<<4)
183#       define TSI_ITAT_ADMODE_A24      (1<<4)
184#       define TSI_ITAT_ADMODE_A32      (2<<4)
185#       define TSI_ITAT_ADMODE_A64      (4<<4)
186#       define TSI_ITAT_SUP                     (1<<3)
187#       define TSI_ITAT_USR                     (1<<2)
188#       define TSI_ITAT_PGM                     (1<<1)
189#       define TSI_ITAT_DATA            (1<<0)
190
191#define TSI_CBAU_REG            0x40c
192#define TSI_CBAL_REG            0x410
193#define TSI_CRGAT_REG           0x414
194#   define TSI_CRGAT_EN         (1<<7)
195#       define TSI_CRGAT_AS_MSK (7<<4)
196#       define TSI_CRGAT_A16    (0<<4)
197#       define TSI_CRGAT_A24    (1<<4)
198#       define TSI_CRGAT_A32    (2<<4)
199#       define TSI_CRGAT_A64    (4<<4)
200#   define TSI_CRGAT_SUP        (1<<3)
201#   define TSI_CRGAT_USR        (1<<2)
202#   define TSI_CRGAT_PGM        (1<<1)
203#   define TSI_CRGAT_DATA       (1<<0)
204
205#define TSI_VICR_REG            0x440
206#   define TSI_VICR_CNTS(v)             (((v)&3)<<30)
207#   define TSI_VICR_CNTS_DIS    (0<<30)
208#   define TSI_VICR_CNTS_IRQ1   (1<<30)
209#   define TSI_VICR_CNTS_IRQ2   (2<<30)
210#   define TSI_VICR_EDGIS(v)    (((v)&3)<<28)
211#   define TSI_VICR_EDGIS_DIS   (0<<28)
212#   define TSI_VICR_EDGIS_IRQ1  (1<<28)
213#   define TSI_VICR_EDGIS_IRQ2  (2<<28)
214#   define TSI_VICR_IRQ1F(v)    (((v)&3)<<26)
215#   define TSI_VICR_IRQ1F_NORML (0<<26)
216#   define TSI_VICR_IRQ1F_PULSE (1<<26)
217#   define TSI_VICR_IRQ1F_CLOCK (2<<26)
218#   define TSI_VICR_IRQ1F_1MHZ  (3<<26)
219#   define TSI_VICR_IRQ2F(v)    (((v)&3)<<24)
220#   define TSI_VICR_IRQ2F_NORML (0<<24)
221#   define TSI_VICR_IRQ2F_PULSE (1<<24)
222#   define TSI_VICR_IRQ2F_CLOCK (2<<24)
223#   define TSI_VICR_IRQ2F_1MHZ  (3<<24)
224#   define TSI_VICR_BIP                 (1<<23)
225#   define TSI_VICR_BIPS                (1<<22)
226#   define TSI_VICR_IRQC                (1<<15)
227#   define TSI_VICR_IRQLS(v)    (((v)&7)<<12)
228#   define TSI_VICR_IRQS                (1<<11)
229#   define TSI_VICR_IRQL(v)             (((v)&7)<<8)
230#   define TSI_VICR_STID(v)             ((v)&0xff)
231#define TSI_INTEN_REG           0x448
232#define TSI_INTEO_REG           0x44c
233#define TSI_INTS_REG            0x450
234#   define TSI_INTS_IRQ1S       (1<<1)
235#   define TSI_INTS_IRQ2S       (1<<2)
236#   define TSI_INTS_IRQ3S       (1<<3)
237#   define TSI_INTS_IRQ4S       (1<<4)
238#   define TSI_INTS_IRQ5S       (1<<5)
239#   define TSI_INTS_IRQ6S       (1<<6)
240#   define TSI_INTS_IRQ7S       (1<<7)
241#   define TSI_INTS_ACFLS       (1<<8)
242#   define TSI_INTS_SYSFLS      (1<<9)
243#   define TSI_INTS_IACKS       (1<<10)
244#   define TSI_INTS_VIES        (1<<11)
245#   define TSI_INTS_VERRS       (1<<12)
246#   define TSI_INTS_PERRS       (1<<13)
247#   define TSI_INTS_MB0S        (1<<16)
248#   define TSI_INTS_MB1S        (1<<17)
249#   define TSI_INTS_MB2S        (1<<18)
250#   define TSI_INTS_MB3S        (1<<19)
251#   define TSI_INTS_LM0S        (1<<20)
252#   define TSI_INTS_LM1S        (1<<21)
253#   define TSI_INTS_LM2S        (1<<22)
254#   define TSI_INTS_LM3S        (1<<23)
255#   define TSI_INTS_DMA0S       (1<<24)
256#   define TSI_INTS_DMA1S       (1<<25)
257#define TSI_INTC_REG            0x454
258#   define TSI_INTC_ACFLC       (1<<8)
259#   define TSI_INTC_SYSFLC      (1<<9)
260#   define TSI_INTC_IACKC       (1<<10)
261#   define TSI_INTC_VIEC        (1<<11)
262#   define TSI_INTC_VERRC       (1<<12)
263#   define TSI_INTC_PERRC       (1<<13)
264#   define TSI_INTC_MB0C        (1<<16)
265#   define TSI_INTC_MB1C        (1<<17)
266#   define TSI_INTC_MB2C        (1<<18)
267#   define TSI_INTC_MB3C        (1<<19)
268#   define TSI_INTC_LM0C        (1<<20)
269#   define TSI_INTC_LM1C        (1<<21)
270#   define TSI_INTC_LM2C        (1<<22)
271#   define TSI_INTC_LM3C        (1<<23)
272#   define TSI_INTC_DMA0C       (1<<24)
273#   define TSI_INTC_DMA1C       (1<<25)
274#define TSI_INTM1_REG           0x458
275#define TSI_INTM2_REG           0x45c
276
277#define TSI_CBAR_REG            0xffc
278
279#define TSI_CSR_OFFSET          0x7f000
280
281#define TSI_CRG_SIZE            (1<<12)         /* 4k */
282
283
284#define TSI_RD(base, reg)                               in_be32((volatile unsigned *)((base) + (reg)/sizeof(*base)))
285#define TSI_RD16(base, reg)                             in_be16((volatile unsigned short *)(base) + (reg)/sizeof(short))
286#define TSI_LE_RD16(base, reg)                  in_le16((volatile unsigned short *)(base) + (reg)/sizeof(short))
287#define TSI_LE_RD32(base, reg)                  in_le32((volatile unsigned *)(base) + (reg)/sizeof(*base))
288#define TSI_RD8(base, reg)                              in_8((volatile unsigned char *)(base) + (reg))
289#define TSI_WR(base, reg, val)                  out_be32((volatile unsigned *)((base) + (reg)/sizeof(*base)), val)
290
291#define UNIV_SCTL_AM_MASK       (UNIV_CTL_VAS | UNIV_SCTL_PGM | UNIV_SCTL_DAT | UNIV_SCTL_USER | UNIV_SCTL_SUPER)
292
293
294/* allow the BSP to override the default routines */
295#ifndef BSP_PCI_FIND_DEVICE
296#define BSP_PCI_FIND_DEVICE             pci_find_device
297#endif
298#ifndef BSP_PCI_CONFIG_IN_LONG
299#define BSP_PCI_CONFIG_IN_LONG  pci_read_config_dword
300#endif
301#ifndef BSP_PCI_CONFIG_IN_SHORT
302#define BSP_PCI_CONFIG_IN_SHORT pci_read_config_word
303#endif
304#ifndef BSP_PCI_CONFIG_OUT_SHORT
305#define BSP_PCI_CONFIG_OUT_SHORT pci_write_config_word
306#endif
307#ifndef BSP_PCI_CONFIG_IN_BYTE
308#define BSP_PCI_CONFIG_IN_BYTE  pci_read_config_byte
309#endif
310
311typedef unsigned int pci_ulong;
312
313#ifdef __BIG_ENDIAN__
314        static inline void st_be32( uint32_t *a, uint32_t v)
315        {
316                *a = v;
317        }
318        static inline uint32_t ld_be32( uint32_t *a )
319        {
320                return *a;
321        }
322#elif defined(__LITTLE_ENDIAN__)
323#error "You need to implement st_be32/ld_be32"
324#else
325#error "Undefined endianness??"
326#endif
327
328#ifndef BSP_LOCAL2PCI_ADDR
329/* try legacy PCI_DRAM_OFFSET */
330#ifndef PCI_DRAM_OFFSET
331#define PCI_DRAM_OFFSET 0
332#endif
333#define BSP_LOCAL2PCI_ADDR(l)   (((uint32_t)l)+PCI_DRAM_OFFSET)
334#endif
335
336/* PCI_MEM_BASE is a possible offset between CPU- and PCI addresses.
337 * Should be defined by the BSP.
338 */
339#ifndef BSP_PCI2LOCAL_ADDR
340#ifndef PCI_MEM_BASE
341#define PCI_MEM_BASE 0
342#endif
343#define BSP_PCI2LOCAL_ADDR(memaddr) ((unsigned long)(memaddr) + PCI_MEM_BASE)
344#endif
345
346typedef uint32_t BEValue;
347
348typedef struct {
349        BERegister *base;
350        int                     irqLine;
351        int                     pic_pin[TSI_NUM_WIRES];
352} Tsi148Dev;
353
354static Tsi148Dev devs[NUM_TSI_DEVS] = {{0}};
355
356#define THEBASE (devs[0].base)
357
358/* forward decl */
359extern int vmeTsi148RegPort;
360extern int vmeTsi148RegCSR;
361
362/* registers should be mapped to guarded, non-cached memory; hence
363 * subsequent stores are ordered. eieio is only needed to enforce
364 * ordering of loads with respect to stores.
365 */
366
367/* private printing wrapper */
368static void
369uprintf(FILE *f, char *fmt, ...)
370{
371va_list ap;
372        va_start(ap, fmt);
373        if (!f || !_impure_ptr->__sdidinit) {
374                /* Might be called at an early stage when
375                 * to a buffer.
376                 */
377                vprintk(fmt,ap);
378        } else
379        {
380                vfprintf(f,fmt,ap);
381        }
382        va_end(ap);
383}
384
385#define CHECK_BASE(base,quiet,rval)     \
386        do {                                                    \
387                if ( !base ) {                          \
388                        if ( !quiet ) {                 \
389                                uprintf(stderr,"Tsi148: Driver not initialized\n");     \
390                        }                                               \
391                        return rval;                    \
392                }                                                       \
393        } while (0)
394
395int
396vmeTsi148FindPciBase(
397        int instance,
398        BERegister **pbase
399        )
400{
401int                                     bus,dev,fun;
402pci_ulong                       busaddr;
403unsigned char           irqline;
404unsigned short          wrd;
405
406        if (BSP_PCI_FIND_DEVICE(
407                        PCI_VENDOR_TUNDRA,
408                        PCI_DEVICE_TSI148,
409                        instance,
410                        &bus,
411                        &dev,
412                        &fun))
413                return -1;
414        if (BSP_PCI_CONFIG_IN_LONG(bus,dev,fun,PCI_BASE_ADDRESS_0,&busaddr))
415                return -1;
416        /* Assume upper BAR is zero */
417
418        *pbase=(BERegister*)(((pci_ulong)BSP_PCI2LOCAL_ADDR(busaddr)) & ~0xff);
419
420        if (BSP_PCI_CONFIG_IN_BYTE(bus,dev,fun,PCI_INTERRUPT_LINE,&irqline))
421                return -1;
422
423        /* Enable PCI master and memory access */
424        BSP_PCI_CONFIG_IN_SHORT(bus, dev, fun, PCI_COMMAND, &wrd);
425        BSP_PCI_CONFIG_OUT_SHORT(bus, dev, fun, PCI_COMMAND, wrd | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
426
427        return irqline;
428}
429
430int
431vmeTsi148InitInstance(unsigned instance)
432{
433int                                     irq;
434BERegister *base;
435
436        if ( instance >= NUM_TSI_DEVS )
437                return  -1;
438        if ( devs[instance].base )
439                return  -1;
440
441        if ((irq=vmeTsi148FindPciBase(instance,&base)) < 0) {
442                uprintf(stderr,"unable to find a Tsi148 in pci config space\n");
443        } else {
444                uprintf(stderr,"Tundra Tsi148 PCI-VME bridge detected at 0x%08x, IRQ %d\n",
445                                (unsigned int)base, irq);
446        }
447        devs[0].base    = base;
448        devs[0].irqLine = irq;
449
450        return irq < 0 ? -1 : 0;
451}
452
453int
454vmeTsi148Init(void)
455{
456        return vmeTsi148InitInstance(0);
457}
458
459
460void
461vmeTsi148ResetXX(BERegister *base)
462{
463int port;
464
465        CHECK_BASE(base,0, );
466
467        vmeTsi148DisableAllOutboundPortsXX(base);
468        for ( port=0; port < TSI148_NUM_OPORTS; port++ )
469                TSI_WR(base, TSI_OTBS_REG(port), 0);
470        TSI_WR(base, TSI_INTEO_REG, 0);
471        TSI_WR(base, TSI_INTEN_REG, 0);
472        TSI_WR(base, TSI_INTC_REG, 0xffffffff);
473        TSI_WR(base, TSI_INTM1_REG, 0);
474        TSI_WR(base, TSI_INTM2_REG, 0);
475        TSI_WR(base, TSI_VICR_REG, 0);
476        TSI_WR(base, TSI_VEAT_REG, TSI_VEAT_VESCL);
477        /* Clear BDFAIL / (--> SYSFAIL) */
478#       define TSI_VSTAT_BDFAIL         (1<<14)
479        TSI_WR(base, TSI_VSTAT_REG, TSI_RD(base, TSI_VSTAT_REG) & ~TSI_VSTAT_BDFAIL);
480}
481
482void
483vmeTsi148Reset()
484{
485        vmeTsi148ResetXX(THEBASE);
486}
487
488/* convert an address space selector to a corresponding
489 * Tsi148 control mode word
490 */
491
492static unsigned long ck2esst(unsigned long am)
493{
494        if ( VME_AM_IS_2eSST(am) ) {
495                /* make sure 2eVME is selected */
496                am &= ~VME_AM_MASK;
497                am |= VME_AM_2eVME_6U;
498        }
499        return am;
500}
501
502STATIC int
503am2omode(unsigned long address_space, unsigned long *pmode)
504{
505unsigned long mode = 0;
506unsigned long tm   = TSI_TM_SCT_IDX;
507
508        switch ( VME_MODE_DBW_MSK & address_space ) {
509                case VME_MODE_DBW8:
510                        return -1;      /* unsupported */
511
512                case VME_MODE_DBW16:
513                        break;
514
515                default:
516                case VME_MODE_DBW32:
517                        mode |= TSI_OTAT_DBW(1);
518                        break;
519        }
520
521        if ( ! (VME_MODE_PREFETCH_ENABLE & address_space) )
522                mode |= TSI_OTAT_MRPFD;
523        else {
524                mode |= TSI_OTAT_PFS(address_space>>_LD_VME_MODE_PREFETCHSZ);
525        }
526
527        address_space = ck2esst(address_space);
528
529        switch (address_space & VME_AM_MASK) {
530                case VME_AM_STD_SUP_PGM:
531                case VME_AM_STD_USR_PGM:
532
533                        mode |= TSI_OTAT_PGM;
534
535                        /* fall thru */
536                case VME_AM_STD_SUP_BLT:
537                case VME_AM_STD_SUP_MBLT:
538
539                case VME_AM_STD_USR_BLT:
540                case VME_AM_STD_USR_MBLT:
541                        switch ( address_space & 3 ) {
542                                case 0: tm = TSI_TM_MBLT_IDX; break;
543                                case 3: tm = TSI_TM_BLT_IDX; break;
544                                default: break;
545                        }
546
547                case VME_AM_STD_SUP_DATA:
548                case VME_AM_STD_USR_DATA:
549
550                        mode |= TSI_OTAT_ADMODE_A24;
551                        break;
552
553                case VME_AM_EXT_SUP_PGM:
554                case VME_AM_EXT_USR_PGM:
555                        mode |= TSI_OTAT_PGM;
556
557                        /* fall thru */
558                case VME_AM_EXT_SUP_BLT:
559                case VME_AM_EXT_SUP_MBLT:
560
561                case VME_AM_EXT_USR_BLT:
562                case VME_AM_EXT_USR_MBLT:
563                        switch ( address_space & 3 ) {
564                                case 0: tm = TSI_TM_MBLT_IDX; break;
565                                case 3: tm = TSI_TM_BLT_IDX; break;
566                                default: break;
567                        }
568
569                case VME_AM_EXT_SUP_DATA:
570                case VME_AM_EXT_USR_DATA:
571
572                        mode |= TSI_OTAT_ADMODE_A32;
573                        break;
574
575                case VME_AM_SUP_SHORT_IO:
576                case VME_AM_USR_SHORT_IO:
577                        mode |= TSI_OTAT_ADMODE_A16;
578                        break;
579
580                case VME_AM_CSR:
581                        mode |= TSI_OTAT_ADMODE_CSR;
582                        break;
583
584                case VME_AM_2eVME_6U:
585                case VME_AM_2eVME_3U:
586                        mode |= TSI_OTAT_ADMODE_A32;
587                        if ( VME_AM_IS_2eSST(address_space) ) {
588                                tm = ( VME_AM_2eSST_BCST & address_space ) ?
589                                                TSI_TM_2eSSTB_IDX : TSI_TM_2eSST_IDX;
590                                switch ( VME_AM_IS_2eSST(address_space) ) {
591                                        default:
592                                        case VME_AM_2eSST_LO:  mode |= TSI_OTAT_2eSSTM_160; break;
593                                        case VME_AM_2eSST_MID: mode |= TSI_OTAT_2eSSTM_267; break;
594                                        case VME_AM_2eSST_HI:  mode |= TSI_OTAT_2eSSTM_320; break;
595                                }
596                        } else {
597                                tm    = TSI_TM_2eVME_IDX;
598                        }
599                break;
600
601                case 0: /* disable the port alltogether */
602                        break;
603
604                default:
605                        return -1;
606        }
607
608        mode |= TSI_OTAT_TM(tm);
609
610        if ( VME_AM_IS_SUP(address_space) )
611                mode |= TSI_OTAT_SUP;
612        *pmode = mode;
613        return 0;
614}
615
616STATIC int
617am2imode(unsigned long address_space, unsigned long *pmode)
618{
619unsigned long mode=0;
620unsigned long pgm = 0;
621
622        mode |= TSI_ITAT_VFS(address_space>>_LD_VME_MODE_PREFETCHSZ);
623
624        if ( VME_AM_IS_2eSST(address_space) ) {
625                        mode |= TSI_ITAT_2eSST;
626                if ( VME_AM_2eSST_BCST & address_space )
627                        mode |= TSI_ITAT_2eSSTB;
628                switch ( VME_AM_IS_2eSST(address_space) ) {
629                        default:
630                        case VME_AM_2eSST_LO:  mode |= TSI_ITAT_2eSSTM_160; break;
631                        case VME_AM_2eSST_MID: mode |= TSI_ITAT_2eSSTM_267; break;
632                        case VME_AM_2eSST_HI:  mode |= TSI_ITAT_2eSSTM_320; break;
633                }
634                address_space = ck2esst(address_space);
635        }
636
637        mode |= TSI_ITAT_BLT;
638        mode |= TSI_ITAT_MBLT;
639
640        mode |= TSI_ITAT_PGM; /* always allow PGM access */
641        mode |= TSI_ITAT_USR; /* always allow USR access */
642
643        switch (address_space & VME_AM_MASK) {
644                case VME_AM_STD_SUP_PGM:
645                case VME_AM_STD_USR_PGM:
646
647                        pgm = 1;
648
649                        /* fall thru */
650                case VME_AM_STD_SUP_BLT:
651                case VME_AM_STD_SUP_MBLT:
652                case VME_AM_STD_USR_BLT:
653                case VME_AM_STD_USR_MBLT:
654                case VME_AM_STD_SUP_DATA:
655                case VME_AM_STD_USR_DATA:
656
657                        mode |= TSI_ITAT_ADMODE_A24;
658                        break;
659
660                case VME_AM_EXT_SUP_PGM:
661                case VME_AM_EXT_USR_PGM:
662                        pgm = 1;
663
664                        /* fall thru */
665                case VME_AM_2eVME_6U:
666                case VME_AM_2eVME_3U:
667                case VME_AM_EXT_SUP_BLT:
668                case VME_AM_EXT_SUP_MBLT:
669                case VME_AM_EXT_USR_BLT:
670                case VME_AM_EXT_USR_MBLT:
671                case VME_AM_EXT_SUP_DATA:
672                case VME_AM_EXT_USR_DATA:
673                        mode |= TSI_ITAT_ADMODE_A32;
674                        break;
675
676                case VME_AM_SUP_SHORT_IO:
677                case VME_AM_USR_SHORT_IO:
678                        mode |= TSI_ITAT_ADMODE_A16;
679                        break;
680
681                case 0: /* disable the port alltogether */
682                        *pmode = 0;
683                        return 0;
684
685                default:
686                        return -1;
687        }
688
689        if ( VME_AM_IS_SUP(address_space) )
690                mode |= TSI_ITAT_SUP;
691
692        if ( !pgm )
693                mode |= TSI_ITAT_DATA;
694
695        *pmode = mode;
696        return 0;
697}
698
699static void
700readTriple(
701        BERegister *base,
702        unsigned reg,
703        unsigned long long *ps,
704        unsigned long long *pl,
705        unsigned long long *po)
706{
707        *ps = TSI_RD(base, reg);
708        *ps = (*ps<<32) | (TSI_RD(base, (reg+4)) & 0xffff0000);
709        *pl = TSI_RD(base, (reg+8));
710        *pl = (*pl<<32) | (TSI_RD(base, (reg+0xc)) & 0xffff0000);
711        *po = TSI_RD(base, (reg+0x10));
712        *po = (*po<<32) | (TSI_RD(base, (reg+0x14)) & 0xffff0000);
713}
714
715
716static unsigned long
717inboundGranularity(unsigned long itat)
718{
719        switch ( itat & TSI_ITAT_AS(-1) ) {
720                case TSI_ITAT_ADMODE_A16:       return 0xf;
721                case TSI_ITAT_ADMODE_A24:       return 0xfff;
722                default:
723                break;
724        }
725        return 0xffff;
726}
727
728static int
729configTsiPort(
730        BERegister              *base,
731        int                             isout,
732        unsigned long   port,
733        unsigned long   address_space,
734        unsigned long   vme_address,
735        unsigned long   pci_address,
736        unsigned long   length)
737{
738unsigned long long      start, limit, offst;
739unsigned long           mode, mask, tat_reg, tsau_reg;
740char                            *name = (isout ? "Outbound" : "Inbound");
741int                                     i,s,l;
742
743        CHECK_BASE(base,0,-1);
744
745        mode = 0; /* silence warning */
746
747        if ( port >= (isout ? TSI148_NUM_OPORTS : TSI148_NUM_IPORTS) ) {
748                uprintf(stderr,"Tsi148 %s Port Cfg: invalid port\n", name);
749                return -1;
750        }
751
752        if ( base == THEBASE && isout && vmeTsi148RegPort == port ) {
753                uprintf(stderr,"Tsi148 %s Port Cfg: invalid port; reserved by the interrupt manager for CRG\n", name);
754                return -1;
755        }
756
757        if ( length && (isout ? am2omode(address_space, &mode) : am2imode(address_space, &mode)) ) {
758                uprintf(stderr,"Tsi148 %s Port Cfg: invalid address space / mode flags\n",name);
759                return -1;
760        }
761
762
763        if ( isout ) {
764                start     = pci_address;
765                offst     = (unsigned long long)vme_address - start;
766                mask      = 0xffff;
767                tat_reg   = TSI_OTAT_REG(port);
768                tsau_reg  = TSI_OTSAU_REG(port);
769                mode     |= TSI_OTAT_EN;
770
771                /* check for overlap */
772                for ( i = 0; i < TSI148_NUM_OPORTS; i++ ) {
773                        /* ignore 'this' port */
774                        if ( i == port || ! (TSI_OTAT_EN & TSI_RD(base, TSI_OTAT_REG(i))) )
775                                continue;
776
777                        /* check requested PCI range against current port 'i' config */
778                        s = TSI_RD(base, TSI_OTSAU_REG(i) + 0x04); /* start */
779                        l = TSI_RD(base, TSI_OTSAU_REG(i) + 0x0c); /* limit */
780                        if ( ! ( start + length <= s || start > s + l ) ) {
781                                uprintf(stderr,"Tsi148 Outbound Port Cfg: PCI address range overlaps with port %i (0x%08x..0x%08x)\n", i, s, l);
782                                return -1;
783                        }
784                }
785        } else {
786                start     = vme_address;
787                offst     = (unsigned long long)pci_address - start;
788                mask      = inboundGranularity(mode);
789                tat_reg   = TSI_ITAT_REG(port);
790                tsau_reg  = TSI_ITSAU_REG(port);
791                mode     |= TSI_ITAT_EN;
792
793                /* check for overlap */
794                for ( i = 0; i < TSI148_NUM_IPORTS; i++ ) {
795                        /* ignore 'this' port */
796                        if ( i == port || ! (TSI_ITAT_EN & (s=TSI_RD(base, TSI_ITAT_REG(i)))) )
797                                continue;
798
799                        if ( (TSI_ITAT_AS(-1) & s) != (TSI_ITAT_AS(-1) & mode) ) {
800                                /* different address space */
801                                continue;
802                        }
803
804                        if ( ! (mode & s & (TSI_ITAT_SUP | TSI_ITAT_USR | TSI_ITAT_PGM | TSI_ITAT_DATA)) ) {
805                                /* orthogonal privileges */
806                                continue;
807                        }
808
809                        /* check requested VME range against current port 'i' config */
810                        s = TSI_RD(base, TSI_ITSAU_REG(i) + 0x04); /* start */
811                        l = TSI_RD(base, TSI_ITSAU_REG(i) + 0x0c); /* limit */
812                        if ( ! ( start + length <= s || start > s + l ) ) {
813                                uprintf(stderr,"Tsi148 Inbound Port Cfg: VME address range overlaps with port %i (0x%08x..0x%08x)\n", i, s, l);
814                                return -1;
815                        }
816                }
817        }
818
819        /* If they pass 'length==0' just disable */
820        if ( 0 == length ) {
821                TSI_WR(base, tat_reg, TSI_RD(base, tat_reg) & ~(isout ? TSI_OTAT_EN : TSI_ITAT_EN));
822                return 0;
823        }
824
825
826        if (   (vme_address & mask)
827            || (pci_address & mask)
828            || (length      & mask) ) {
829                uprintf(stderr,"Tsi148 %s Port Cfg: invalid address/length; must be multiple of 0x%x\n",
830                                name,
831                                mask+1);
832                return -1;
833        }
834
835        limit  = start + length - 1;
836
837        if ( limit >= (unsigned long long)1<<32 ) {
838                uprintf(stderr,"Tsi148 %s Port Cfg: invalid address/length; must be < 1<<32\n", name);
839                return -1;
840        }
841
842        /* Disable port */
843        TSI_WR(base, tat_reg, 0);
844
845        /* Force to 32-bits */
846        TSI_WR(base, tsau_reg       , 0);
847        TSI_WR(base, tsau_reg + 0x04, (uint32_t)start);
848        TSI_WR(base, tsau_reg + 0x08, 0);
849        TSI_WR(base, tsau_reg + 0x0c, (uint32_t)limit);
850        TSI_WR(base, tsau_reg + 0x10, (uint32_t)(offst>>32));
851        TSI_WR(base, tsau_reg + 0x14, (uint32_t)offst);
852
853        /* (outbound only:) leave 2eSST broadcast register alone for user to program */
854
855        /* Set mode and enable */
856        TSI_WR(base, tat_reg, mode);
857        return 0;
858}
859
860static int
861disableTsiPort(
862        BERegister              *base,
863        int                             isout,
864        unsigned long   port)
865{
866        return configTsiPort(base, isout, port, 0, 0, 0, 0);
867}
868
869int
870vmeTsi148InboundPortCfgXX(
871        BERegister              *base,
872        unsigned long   port,
873        unsigned long   address_space,
874        unsigned long   vme_address,
875        unsigned long   pci_address,
876        unsigned long   length)
877{
878        return configTsiPort(base, 0, port, address_space, vme_address, pci_address, length);
879}
880
881int
882vmeTsi148InboundPortCfg(
883        unsigned long   port,
884        unsigned long   address_space,
885        unsigned long   vme_address,
886        unsigned long   pci_address,
887        unsigned long   length)
888{
889        return configTsiPort(THEBASE, 0, port, address_space, vme_address, pci_address, length);
890}
891
892
893int
894vmeTsi148OutboundPortCfgXX(
895        BERegister              *base,
896        unsigned long   port,
897        unsigned long   address_space,
898        unsigned long   vme_address,
899        unsigned long   pci_address,
900        unsigned long   length)
901{
902        return configTsiPort(base, 1, port, address_space, vme_address, pci_address, length);
903}
904
905int
906vmeTsi148OutboundPortCfg(
907        unsigned long   port,
908        unsigned long   address_space,
909        unsigned long   vme_address,
910        unsigned long   pci_address,
911        unsigned long   length)
912{
913        return configTsiPort(THEBASE, 1, port, address_space, vme_address, pci_address, length);
914}
915
916
917static int
918xlateFindPort(
919        BERegister *base,       /* TSI 148 base address */
920        int outbound,           /* look in the outbound windows */
921        int reverse,            /* reverse mapping; for outbound ports: map local to VME */
922        unsigned long as,       /* address space */
923        unsigned long aIn,      /* address to look up */
924        unsigned long *paOut/* where to put result */
925        )
926{
927unsigned long           mode, mode_msk;
928int                                     port;
929unsigned long long      start, limit, offst, a;
930unsigned long           tsau_reg, tat_reg, gran, skip;
931
932        CHECK_BASE(base,0,-1);
933
934        mode = 0; /* silence warning */
935
936        switch ( as & VME_MODE_MATCH_MASK ) {
937                case VME_MODE_EXACT_MATCH:
938                        mode_msk = ~0;
939                break;
940
941                case VME_MODE_AS_MATCH:
942                        if ( outbound )
943                                mode_msk = TSI_OTAT_ADMODE(-1) | TSI_OTAT_EN;
944                        else
945                                mode_msk = TSI_ITAT_AS(-1) | TSI_ITAT_EN;
946                break;
947
948                default:
949                        if ( outbound )
950                                mode_msk = TSI_OTAT_PGM | TSI_OTAT_SUP | TSI_OTAT_ADMODE(-1) | TSI_OTAT_EN;
951                        else
952                                mode_msk = TSI_ITAT_PGM | TSI_ITAT_DATA | TSI_ITAT_SUP | TSI_ITAT_USR | TSI_ITAT_AS(-1) | TSI_ITAT_EN;
953                break;
954        }
955
956        as &= ~VME_MODE_MATCH_MASK;
957
958        if ( outbound ? am2omode(as,&mode) : am2imode(as,&mode) ) {
959                uprintf(stderr, "vmeTsi148XlateAddr: invalid address space/mode argument");
960                return -2;
961        }
962
963        if (outbound ) {
964                tsau_reg = TSI_OTSAU_REG(0);
965                tat_reg  = TSI_OTAT_REG(0);
966                skip     = TSI_OTSAU_SPACING;
967                mode    |= TSI_OTAT_EN;
968                gran     = 0x10000;
969        } else {
970                tsau_reg = TSI_ITSAU_REG(0);
971                tat_reg  = TSI_ITAT_REG(0);
972                skip     = TSI_ITSAU_SPACING;
973                mode    |= TSI_ITAT_EN;
974                gran     = inboundGranularity(mode) + 1;
975        }
976
977        for ( port = 0; port < TSI148_NUM_OPORTS; port++, tsau_reg += skip, tat_reg += skip ) {
978
979                if ( (mode & mode_msk) == (TSI_RD(base, tat_reg) & mode_msk) ) {
980
981                        /* found a window with of the right mode; now check the range */
982                        readTriple(base, tsau_reg, &start, &limit, &offst);
983                        limit += gran;
984
985                        if ( !reverse ) {
986                                start += offst;
987                                limit += offst;
988                                offst  = -offst;
989                        }
990                        a = aIn;
991                        if ( aIn >= start && aIn <= limit ) {
992                                /* found it */
993                                *paOut = (unsigned long)(a + offst);
994                                return port;
995                        }
996                }
997        }
998
999        uprintf(stderr, "vmeTsi148XlateAddr: no matching mapping found\n");
1000        return -1;
1001}
1002
1003int
1004vmeTsi148XlateAddrXX(
1005        BERegister *base,       /* TSI 148 base address */
1006        int outbound,           /* look in the outbound windows */
1007        int reverse,            /* reverse mapping; for outbound ports: map local to VME */
1008        unsigned long as,       /* address space */
1009        unsigned long aIn,      /* address to look up */
1010        unsigned long *paOut/* where to put result */
1011        )
1012{
1013int port = xlateFindPort( base, outbound, reverse, as, aIn, paOut );
1014        return port < 0 ? -1 : 0;
1015}
1016
1017int
1018vmeTsi148XlateAddr(
1019        int outbound,           /* look in the outbound windows */
1020        int reverse,            /* reverse mapping; for outbound ports: map local to VME */
1021        unsigned long as,       /* address space */
1022        unsigned long aIn,      /* address to look up */
1023        unsigned long *paOut/* where to put result */
1024        )
1025{
1026        return vmeTsi148XlateAddrXX(THEBASE, outbound, reverse, as, aIn, paOut);
1027}
1028
1029
1030/* printk cannot format %llx */
1031static void uprintfllx(FILE *f, unsigned long long v)
1032{
1033        if ( v >= ((unsigned long long)1)<<32 )
1034                uprintf(f,"0x%lx%08lx ", (unsigned long)(v>>32), (unsigned long)(v & 0xffffffff));
1035        else
1036                uprintf(f,"0x%08lx ", (unsigned long)(v & 0xffffffff));
1037}
1038
1039void
1040vmeTsi148OutboundPortsShowXX(BERegister *base, FILE *f)
1041{
1042int                             port;
1043unsigned long   mode;
1044char                    tit = 0;
1045
1046unsigned long long      start, limit, offst;
1047
1048        CHECK_BASE(base,0, );
1049
1050        if (!f) f=stdout;
1051        uprintf(f,"Tsi148 Outbound Ports:\n");
1052
1053        for ( port = 0; port < TSI148_NUM_OPORTS; port++ ) {
1054                mode = TSI_RD(base, TSI_OTAT_REG(port));
1055                if ( ! (TSI_OTAT_EN & mode) )
1056                        continue; /* skip disabled ports */
1057
1058                readTriple(base, TSI_OTSAU_REG(port), &start, &limit, &offst);
1059
1060                /* convert limit to size */
1061                limit = limit-start+0x10000;
1062                if ( !tit ) {
1063                        uprintf(f,"Port  VME-Addr   Size       PCI-Adrs   Mode:\n");
1064                        tit = 1;
1065                }
1066                uprintf(f,"%d:    ", port);
1067                uprintfllx(f,start+offst);
1068                uprintfllx(f,limit);
1069                uprintfllx(f,start);
1070                switch( mode & TSI_OTAT_ADMODE(-1) ) {
1071                        case TSI_OTAT_ADMODE_A16: uprintf(f,"A16"); break;
1072                        case TSI_OTAT_ADMODE_A24: uprintf(f,"A24"); break;
1073                        case TSI_OTAT_ADMODE_A32: uprintf(f,"A32"); break;
1074                        case TSI_OTAT_ADMODE_A64: uprintf(f,"A64"); break;
1075                        case TSI_OTAT_ADMODE_CSR: uprintf(f,"CSR"); break;
1076                        default:                  uprintf(f,"A??"); break;
1077                }
1078
1079                if ( mode & TSI_OTAT_PGM ) uprintf(f,", PGM");
1080                if ( mode & TSI_OTAT_SUP ) uprintf(f,", SUP");
1081                if ( ! (TSI_OTAT_MRPFD & mode) ) uprintf(f,", PREFETCH");
1082
1083                switch ( mode & TSI_OTAT_DBW(-1) ) {
1084                        case TSI_OTAT_DBW(0):   uprintf(f,", D16"); break;
1085                        case TSI_OTAT_DBW(1):   uprintf(f,", D32"); break;
1086                        default:                                uprintf(f,", D??"); break;
1087                }
1088
1089                switch( mode & TSI_OTAT_TM(-1) ) {
1090                        case TSI_OTAT_TM(0):    uprintf(f,", SCT");             break;
1091                        case TSI_OTAT_TM(1):    uprintf(f,", BLT");             break;
1092                        case TSI_OTAT_TM(2):    uprintf(f,", MBLT");            break;
1093                        case TSI_OTAT_TM(3):    uprintf(f,", 2eVME");           break;
1094                        case TSI_OTAT_TM(4):    uprintf(f,", 2eSST");           break;
1095                        case TSI_OTAT_TM(5):    uprintf(f,", 2eSST_BCST");      break;
1096                        default:                                uprintf(f," TM??");             break;
1097                }
1098
1099                uprintf(f,"\n");
1100        }
1101}
1102
1103void
1104vmeTsi148OutboundPortsShow(FILE *f)
1105{
1106        vmeTsi148OutboundPortsShowXX(THEBASE, f);
1107}
1108
1109void
1110vmeTsi148InboundPortsShowXX(BERegister *base, FILE *f)
1111{
1112int                             port;
1113unsigned long   mode;
1114char                    tit = 0;
1115
1116unsigned long long      start, limit, offst;
1117
1118        CHECK_BASE(base,0, );
1119
1120        if (!f) f=stdout;
1121        uprintf(f,"Tsi148 Inbound Ports:\n");
1122
1123        for ( port = 0; port < TSI148_NUM_IPORTS; port++ ) {
1124                mode = TSI_RD(base, TSI_ITAT_REG(port));
1125                if ( ! (TSI_ITAT_EN & mode) )
1126                        continue; /* skip disabled ports */
1127
1128                readTriple(base, TSI_ITSAU_REG(port), &start, &limit, &offst);
1129
1130                /* convert limit to size */
1131                limit = limit - start + inboundGranularity(mode) + 1;
1132                if ( !tit ) {
1133                        uprintf(f,"Port  VME-Addr   Size       PCI-Adrs   Mode:\n");
1134                        tit = 1;
1135                }
1136                uprintf(f,"%d:    ", port);
1137                uprintfllx(f,start);
1138                uprintfllx(f,limit);
1139                uprintfllx(f,start+offst);
1140                switch( mode & TSI_ITAT_AS(-1) ) {
1141                        case TSI_ITAT_ADMODE_A16: uprintf(f,"A16"); break;
1142                        case TSI_ITAT_ADMODE_A24: uprintf(f,"A24"); break;
1143                        case TSI_ITAT_ADMODE_A32: uprintf(f,"A32"); break;
1144                        case TSI_ITAT_ADMODE_A64: uprintf(f,"A64"); break;
1145                        default:                  uprintf(f,"A??"); break;
1146                }
1147
1148                if ( mode & TSI_ITAT_PGM )  uprintf(f,", PGM");
1149                if ( mode & TSI_ITAT_DATA ) uprintf(f,", DAT");
1150                if ( mode & TSI_ITAT_SUP )  uprintf(f,", SUP");
1151                if ( mode & TSI_ITAT_USR )  uprintf(f,", USR");
1152
1153                if ( mode & TSI_ITAT_2eSSTB )  uprintf(f,", 2eSSTB");
1154                if ( mode & TSI_ITAT_2eSST  )  uprintf(f,", 2eSST");
1155                if ( mode & TSI_ITAT_2eVME  )  uprintf(f,", 2eVME");
1156                if ( mode & TSI_ITAT_MBLT   )  uprintf(f,", MBLT");
1157                if ( mode & TSI_ITAT_BLT    )  uprintf(f,", BLT");
1158
1159                uprintf(f,"\n");
1160        }
1161}
1162
1163void
1164vmeTsi148InboundPortsShow(FILE *f)
1165{
1166        vmeTsi148InboundPortsShowXX(THEBASE, f);
1167}
1168
1169
1170void
1171vmeTsi148DisableAllInboundPortsXX(BERegister *base)
1172{
1173int port;
1174
1175        for ( port = 0; port < TSI148_NUM_IPORTS; port++ )
1176                if ( disableTsiPort(base, 0, port) )
1177                        break;
1178}
1179
1180void
1181vmeTsi148DisableAllInboundPorts(void)
1182{
1183        vmeTsi148DisableAllInboundPortsXX(THEBASE);
1184}
1185
1186void
1187vmeTsi148DisableAllOutboundPortsXX(BERegister *base)
1188{
1189int port;
1190
1191        for ( port = 0; port < TSI148_NUM_IPORTS; port++ )
1192                if ( disableTsiPort(base, 1, port) )
1193                        break;
1194}
1195
1196void
1197vmeTsi148DisableAllOutboundPorts(void)
1198{
1199        vmeTsi148DisableAllOutboundPortsXX(THEBASE);
1200}
1201
1202
1203/* Map internal register block to VME */
1204
1205int
1206vmeTsi148MapCRGXX(BERegister *b, uint32_t vme_base, uint32_t as )
1207{
1208uint32_t mode;
1209
1210        CHECK_BASE( b, 0, -1 );
1211
1212        if ( vmeTsi148RegPort > -1 && ! vmeTsi148RegCSR ) {
1213        uprintf(stderr,"vmeTsi148: CRG already mapped and in use by interrupt manager\n");
1214                return -1;
1215        }
1216
1217        /* enable all, SUP/USR/PGM/DATA accesses */
1218        mode = TSI_CRGAT_EN | TSI_CRGAT_SUP | TSI_CRGAT_USR | TSI_CRGAT_PGM |  TSI_CRGAT_DATA;
1219
1220        if ( VME_AM_IS_SHORT(as) ) {
1221                mode |= TSI_CRGAT_A16;
1222        } else
1223        if ( VME_AM_IS_STD(as) ) {
1224                mode |= TSI_CRGAT_A24;
1225        } else
1226        if ( VME_AM_IS_EXT(as) ) {
1227                mode |= TSI_CRGAT_A32;
1228        } else {
1229                return -2;
1230        }
1231
1232        /* map CRG to VME bus */
1233        TSI_WR( b, TSI_CBAL_REG, (vme_base & ~(TSI_CRG_SIZE-1)));
1234        TSI_WR( b, TSI_CRGAT_REG, mode );
1235
1236        return 0;
1237}
1238
1239int
1240vmeTsi148MapCRG(uint32_t vme_base, uint32_t as )
1241{
1242        return vmeTsi148MapCRGXX( THEBASE, vme_base, as );
1243}
1244
1245/* Interrupt Subsystem */
1246
1247typedef struct
1248IRQEntryRec_ {
1249                VmeTsi148ISR    isr;
1250                void                    *usrData;
1251} IRQEntryRec, *IRQEntry;
1252
1253static IRQEntry irqHdlTbl[TSI_NUM_INT_VECS]={0};
1254
1255int        vmeTsi148IrqMgrInstalled = 0;
1256int        vmeTsi148RegPort         = -1;
1257int        vmeTsi148RegCSR                      = 0;
1258BERegister *vmeTsi148RegBase        = 0;
1259
1260static volatile unsigned long   wire_mask[TSI_NUM_WIRES]     = {0};
1261/* wires are offset by 1 so we can initialize the wire table to all zeros */
1262static int                                              tsi_wire[TSI_NUM_WIRES] = {0};
1263
1264/* how should we iack a given level, 1,2,4 bytes? */
1265static unsigned char tsi_iack_width[7] = {
1266        1,1,1,1,1,1,1
1267};
1268
1269/* map universe compatible vector # to Tsi slot (which maps to bit layout in stat/enable/... regs) */
1270static int uni2tsi_vec_map[TSI_NUM_INT_VECS-256] = {
1271        /* 256 no VOWN interrupt */                     -1,
1272        /* TSI_DMA_INT_VEC                      257 */  256 + 24 - 8,
1273        /* TSI_LERR_INT_VEC                     258 */  256 + 13 - 8,
1274        /* TSI_VERR_INT_VEC                     259 */  256 + 12 - 8,
1275        /* 260 is reserved       */                     -1,
1276        /* TSI_VME_SW_IACK_INT_VEC      261 */  256 + 10 - 8,
1277        /* 262 no PCI SW IRQ     */                     -1,
1278        /* TSI_SYSFAIL_INT_VEC          263 */  256 +  9 - 8,
1279        /* TSI_ACFAIL_INT_VEC           264 */  256 +  8 - 8,
1280        /* TSI_MBOX0_INT_VEC            265 */  256 + 16 - 8,
1281        /* TSI_MBOX1_INT_VEC            266 */  256 + 17 - 8,
1282        /* TSI_MBOX2_INT_VEC            267 */  256 + 18 - 8,
1283        /* TSI_MBOX3_INT_VEC            268 */  256 + 19 - 8,
1284        /* TSI_LM0_INT_VEC                      269 */  256 + 20 - 8,
1285        /* TSI_LM1_INT_VEC                      270 */  256 + 21 - 8,
1286        /* TSI_LM2_INT_VEC                      271 */  256 + 22 - 8,
1287        /* TSI_LM3_INT_VEC                      272 */  256 + 23 - 8,
1288/* New vectors; only on TSI148 */
1289        /* TSI_VIES_INT_VEC                     273 */  256 + 11 - 8,
1290        /* TSI_DMA1_INT_VEC                     274 */  256 + 25 - 8,
1291};
1292
1293/* and the reverse; map tsi bit number to universe compatible 'special' vector number */
1294static int tsi2uni_vec_map[TSI_NUM_INT_VECS - 256] = {
1295        TSI_ACFAIL_INT_VEC,
1296        TSI_SYSFAIL_INT_VEC,
1297        TSI_VME_SW_IACK_INT_VEC,
1298        TSI_VIES_INT_VEC,
1299        TSI_VERR_INT_VEC,
1300        TSI_LERR_INT_VEC,
1301        -1,
1302        -1,
1303        TSI_MBOX0_INT_VEC,
1304        TSI_MBOX1_INT_VEC,
1305        TSI_MBOX2_INT_VEC,
1306        TSI_MBOX3_INT_VEC,
1307        TSI_LM0_INT_VEC,
1308        TSI_LM1_INT_VEC,
1309        TSI_LM2_INT_VEC,
1310        TSI_LM3_INT_VEC,
1311        TSI_DMA_INT_VEC,
1312        TSI_DMA1_INT_VEC,
1313        -1,
1314};
1315
1316static inline int
1317uni2tsivec(int v)
1318{
1319        if ( v < 0 || v >= TSI_NUM_INT_VECS )
1320                return -1;
1321        return v < 256 ? v : uni2tsi_vec_map[v-256];
1322}
1323
1324static int
1325lvl2bitno(unsigned int level)
1326{
1327        if ( level >= 256 )
1328                return uni2tsivec(level) + 8 - 256;
1329        else if ( level < 8 && level > 0 )
1330                return level;
1331        return -1;
1332}
1333
1334int
1335vmeTsi148IntRoute(unsigned int level, unsigned int pin)
1336{
1337int                             i;
1338unsigned long   mask, shift, mapreg, flags, wire;
1339
1340        if ( pin >= TSI_NUM_WIRES || ! tsi_wire[pin] || !vmeTsi148IrqMgrInstalled )
1341                return -1;
1342
1343        if ( level >= 256 ) {
1344                if ( (i = uni2tsivec(level)) < 0 )
1345                        return -1;
1346                shift = 8 + (i-256);
1347        } else if ( 1 <= level && level <=7 ) {
1348                shift = level;
1349        } else {
1350                return -1;      /* invalid level */
1351        }
1352
1353        mask = 1<<shift;
1354
1355        /* calculate the mapping register and contents */
1356        if ( shift < 16 ) {
1357                mapreg = TSI_INTM2_REG;
1358        } else if ( shift < 32 ) {
1359                shift -= 16;
1360                mapreg = TSI_INTM1_REG;
1361        } else {
1362                return -1;
1363        }
1364
1365        shift <<=1;
1366
1367        /* wires are offset by 1 so we can initialize the wire table to all zeros */
1368        wire = (tsi_wire[pin]-1) << shift;
1369
1370rtems_interrupt_disable(flags);
1371
1372        for ( i = 0; i<TSI_NUM_WIRES; i++ ) {
1373                wire_mask[i] &= ~mask;
1374        }
1375        wire_mask[pin] |= mask;
1376
1377        mask = TSI_RD(THEBASE, mapreg) & ~ (0x3<<shift);
1378        mask |= wire;
1379        TSI_WR( THEBASE, mapreg, mask );
1380
1381rtems_interrupt_enable(flags);
1382        return 0;
1383}
1384
1385VmeTsi148ISR
1386vmeTsi148ISRGet(unsigned long vector, void **parg)
1387{
1388VmeTsi148ISR      rval = 0;
1389unsigned long     flags;
1390volatile IRQEntry *p;
1391int               v = uni2tsivec(vector);
1392
1393
1394        if ( v < 0 )
1395                return rval;
1396
1397        p = irqHdlTbl + v;
1398
1399        rtems_interrupt_disable(flags);
1400                if ( *p ) {
1401                        if ( parg )
1402                                *parg = (*p)->usrData;
1403                        rval = (*p)->isr;
1404                }
1405        rtems_interrupt_enable(flags);
1406
1407        return rval;
1408}
1409
1410static void
1411tsiVMEISR(rtems_irq_hdl_param arg)
1412{
1413int                                     pin = (int)arg;
1414BERegister                      *b  = THEBASE;
1415IRQEntry                        ip;
1416unsigned long           msk,lintstat,vector, vecarg;
1417int                                     lvl;
1418
1419        /* only handle interrupts routed to this pin */
1420
1421        /* NOTE: we read the status register over VME, thus flushing the FIFO
1422         *       where the user ISR possibly left write commands to clear
1423         *       the interrupt condition at the device.
1424         *       This is very important - otherwise, the IRQ level may still be
1425         *       asserted and we would detect an interrupt here but the subsequent
1426         *       IACK would fail since the write operation was flushed to the
1427         *       device in the mean time.
1428         */
1429        while ( (lintstat  = (TSI_RD(vmeTsi148RegBase, TSI_INTS_REG) & wire_mask[pin])) ) {
1430
1431                /* bit 0 is never set since it is never set in wire_mask */
1432
1433                do {
1434                        /* simplicity is king; just handle them in MSB to LSB order; reserved bits read as 0 */
1435#ifdef __PPC__
1436                        asm volatile("cntlzw %0, %1":"=r"(lvl):"r"(lintstat));
1437                        lvl = 31-lvl;
1438                        msk = 1<<lvl;
1439#else
1440                        { static unsigned long m[] = {
1441                                                                                         0xffff0000, 0xff00ff00, 0xf0f0f0f0, 0xcccccccc, 0xaaaaaaaa
1442                                                                                 };
1443                        int      i;
1444                        unsigned tmp;
1445
1446                        /* lintstat has already been checked...
1447                        if ( !lintstat ) {
1448                           lvl = -1; msk = 0;
1449                        } else
1450                         */
1451                        for ( i=0, lvl=0, msk = lintstat; i<5; i++ ) {
1452                                lvl <<= 1;
1453                                if ( (tmp = msk & m[i]) ) {
1454                                        lvl++;
1455                                        msk = tmp;
1456                                } else
1457                                        msk = msk & ~m[i];
1458                        }
1459                        }
1460#endif
1461
1462                        if ( lvl > 7 ) {
1463                                /* clear this interrupt level */
1464                                TSI_WR(b, TSI_INTC_REG, msk);
1465                                vector = 256 + lvl - 8;
1466                                vecarg = tsi2uni_vec_map[lvl-8];
1467                        } else {
1468                                /* need to do get the vector for this level */
1469                                switch ( tsi_iack_width[lvl-1] ) {
1470                                        default:
1471                                        case  1:
1472                                                vector = TSI_RD8(b, TSI_VIACK_1_REG - 4 + (lvl<<2) + 3);
1473                                                break;
1474
1475                                        case  2:
1476                                                vector = TSI_RD16(b, TSI_VIACK_1_REG - 4 + (lvl<<2) + 2);
1477                                                break;
1478
1479                                        case  4:
1480                                                vector = TSI_RD(b, TSI_VIACK_1_REG - 4 + (lvl<<2));
1481                                                break;
1482                                }
1483                                vecarg = vector;
1484                        }
1485
1486                        if ( !(ip=irqHdlTbl[vector])) {
1487                                /* TODO: log error message - RTEMS has no logger :-( */
1488                                vmeTsi148IntDisable(lvl);
1489                                printk("vmeTsi148 ISR: ERROR: no handler registered (level %i) IACK 0x%08x -- DISABLING level %i\n",
1490                                                lvl, vector, lvl);
1491                        } else {
1492                                /* dispatch handler, it must clear the IRQ at the device */
1493                                ip->isr(ip->usrData, vecarg);
1494                                /* convenience for disobedient users who don't use in_xxx/out_xxx; make
1495                                 * sure we order the subsequent read from the status register after
1496                                 * their business.
1497                                 */
1498                                iobarrier_rw();
1499                        }
1500                } while ( (lintstat &= ~msk) );
1501                /* check if a new irq is pending already */
1502        }
1503}
1504
1505
1506static void
1507my_no_op(const rtems_irq_connect_data * arg)
1508{}
1509
1510static int
1511my_isOn(const rtems_irq_connect_data *arg)
1512{
1513                return (int)(TSI_RD(THEBASE, TSI_INTEO_REG) & TSI_RD(THEBASE, TSI_INTEN_REG));
1514}
1515
1516static void
1517connectIsr(int shared, rtems_irq_hdl isr, int pic_line, int slot)
1518{
1519rtems_irq_connect_data  xx;
1520        xx.on     = my_no_op; /* at _least_ they could check for a 0 pointer */
1521        xx.off    = my_no_op;
1522        xx.isOn   = my_isOn;
1523        xx.hdl    = isr;
1524        xx.handle = (rtems_irq_hdl_param)slot;
1525        xx.name   = pic_line;
1526
1527        if ( shared ) {
1528#if BSP_SHARED_HANDLER_SUPPORT > 0
1529                if (!BSP_install_rtems_shared_irq_handler(&xx))
1530                        BSP_panic("unable to install vmeTsi148 shared irq handler");
1531#else
1532        uprintf(stderr,"vmeTsi148: WARNING: your BSP doesn't support sharing interrupts\n");
1533                if (!BSP_install_rtems_irq_handler(&xx))
1534                        BSP_panic("unable to install vmeTsi148 irq handler");
1535#endif
1536        } else {
1537                if (!BSP_install_rtems_irq_handler(&xx))
1538                        BSP_panic("unable to install vmeTsi148 irq handler");
1539        }
1540}
1541
1542int
1543vmeTsi148InstallIrqMgrAlt(int shared, int tsi_pin0, int pic_pin0, ...)
1544{
1545int             rval;
1546va_list ap;
1547        va_start(ap, pic_pin0);
1548        rval = vmeTsi148InstallIrqMgrVa(shared, tsi_pin0, pic_pin0, ap);
1549        va_end(ap);
1550        return rval;
1551}
1552
1553#ifndef BSP_EARLY_PROBE_VME
1554#define BSP_EARLY_PROBE_VME(addr)       \
1555        (                                                                                                                                                                                                       \
1556                vmeTsi148ClearVMEBusErrorsXX( THEBASE, 0 ),                                                                                             \
1557                ( ((PCI_DEVICE_TSI148 << 16) | PCI_VENDOR_TUNDRA ) == TSI_LE_RD32( ((BERegister*)(addr)), 0 )   \
1558                 && 0 == vmeTsi148ClearVMEBusErrorsXX( THEBASE, 0 ) )                                                                           \
1559        )
1560#endif
1561
1562/* Check if there is a vme address/as is mapped in any of the outbound windows
1563 * and look for the PCI vendordevice ID there.
1564 * RETURNS: -1 on error (no mapping or probe failure), outbound window # (0..7)
1565 *          on success. Address translated into CPU address is returned in *pcpu_addr.
1566 */
1567static int
1568mappedAndProbed(unsigned long vme_addr, unsigned as, unsigned long *pcpu_addr)
1569{
1570int j;
1571char *regtype = (as & VME_AM_MASK) == VME_AM_CSR ? "CSR" : "CRG";
1572
1573        /* try to find mapping */
1574        if ( 0 > (j = xlateFindPort(
1575                                THEBASE,
1576                                1, 0,
1577                                as | VME_MODE_AS_MATCH,
1578                                vme_addr,
1579                                pcpu_addr ) ) ) {
1580                        uprintf(stderr,"vmeTsi148 - Unable to find mapping for %s VME base (0x%08x)\n", regtype, vme_addr);
1581                        uprintf(stderr,"            in outbound windows.\n");
1582        }
1583        else {
1584                        /* found a slot number; probe it */
1585                        *pcpu_addr = BSP_PCI2LOCAL_ADDR( *pcpu_addr );
1586                        if ( BSP_EARLY_PROBE_VME(*pcpu_addr) ) {
1587                                uprintf(stderr,"vmeTsi148 - IRQ manager using VME %s to flush FIFO\n", regtype);
1588                                return j;
1589                        } else {
1590                                uprintf(stderr,"vmeTsi148 - Found slot info but detection of tsi148 in VME %s space failed\n", regtype);
1591                        }
1592        }
1593        return -1;
1594}
1595
1596int
1597vmeTsi148InstallIrqMgrVa(int shared, int tsi_pin0, int pic_pin0, va_list ap)
1598{
1599int     i,j, specialPin, tsi_pin[TSI_NUM_WIRES+1], pic_pin[TSI_NUM_WIRES];
1600unsigned long cpu_base, vme_reg_base;
1601
1602        if (vmeTsi148IrqMgrInstalled)                  return -4;
1603
1604        /* check parameters */
1605
1606        if ( tsi_pin0 < 0 || tsi_pin0 > 3 )            return -1;
1607
1608        tsi_pin[0] = tsi_pin0;
1609        pic_pin[0] = pic_pin0 < 0 ? devs[0].irqLine : pic_pin0;
1610        i = 1;
1611        while ( (tsi_pin[i] = va_arg(ap, int)) >= 0 ) {
1612               
1613                if ( i >= TSI_NUM_WIRES ) {
1614                                                               return -5;
1615                }
1616
1617                pic_pin[i] = va_arg(ap,int);
1618
1619                if ( tsi_pin[i] > 3 )                      return -2;
1620                if ( pic_pin[i] < 0 )                      return -3;
1621                i++;
1622        }
1623
1624        /* all routings must be different */
1625        for ( i=0; tsi_pin[i] >= 0; i++ ) {
1626                for ( j=i+1; tsi_pin[j] >= 0; j++ ) {
1627                        if ( tsi_pin[j] == tsi_pin[i] )        return -6;
1628                        if ( pic_pin[j] == pic_pin[i] )        return -7;
1629                }
1630        }
1631
1632        i        = -1;
1633
1634        /* first try VME CSR space; do we have a base address set ? */
1635
1636        uprintf(stderr,"vmeTsi148 IRQ manager: looking for registers on VME...\n");
1637
1638        if ( ( i = ((TSI_RD( THEBASE, TSI_CBAR_REG ) & 0xff) >> 3) ) > 0 ) {
1639                uprintf(stderr,"Trying to find CSR on VME...\n");
1640                vme_reg_base = i*0x80000 + TSI_CSR_OFFSET;
1641                i = mappedAndProbed( vme_reg_base, VME_AM_CSR , &cpu_base);
1642                if ( i >= 0 )
1643                        vmeTsi148RegCSR = 1;
1644        } else {
1645                i = -1;
1646        }
1647
1648        if ( -1 == i ) {
1649
1650                uprintf(stderr,"Trying to find CRG on VME...\n");
1651
1652                /* Next we see if the CRG block is mapped to VME */
1653
1654                if ( (TSI_CRGAT_EN & (j = TSI_RD( THEBASE, TSI_CRGAT_REG ))) ) {
1655                        switch ( j & TSI_CRGAT_AS_MSK ) {
1656                                case TSI_CRGAT_A16 : i = VME_AM_SUP_SHORT_IO; break;
1657                                case TSI_CRGAT_A24 : i = VME_AM_STD_SUP_DATA; break;
1658                                case TSI_CRGAT_A32 : i = VME_AM_EXT_SUP_DATA; break;
1659                                default:
1660                                break;
1661                        }
1662                        vme_reg_base = TSI_RD( THEBASE, TSI_CBAL_REG ) & ~ (TSI_CRG_SIZE - 1);
1663                }
1664
1665                if ( -1 == i ) {
1666                } else {
1667                        i = mappedAndProbed( vme_reg_base, (i & VME_AM_MASK), &cpu_base );
1668                }
1669        }
1670
1671        if ( i < 0 ) {
1672                        uprintf(stderr,"vmeTsi148 IRQ manager - BSP configuration error: registers not found on VME\n");
1673                        uprintf(stderr,"(should open outbound window to CSR space or map CRG [vmeTsi148MapCRG()])\n");
1674                        uprintf(stderr,"Falling back to PCI but you might experience spurious VME interrupts; read a register\n");
1675                        uprintf(stderr,"back from user ISR to flush posted-write FIFO as a work-around\n");
1676                        cpu_base = (unsigned long)THEBASE;
1677                        i        = -1;
1678        }
1679
1680        vmeTsi148RegBase = (BERegister*)cpu_base;
1681        vmeTsi148RegPort = i;
1682
1683        /* give them a chance to override buggy PCI info */
1684        if ( pic_pin[0] >= 0 && devs[0].irqLine != pic_pin[0] ) {
1685                uprintf(stderr,"Overriding main IRQ line PCI info with %d\n",
1686                                pic_pin[0]);
1687                devs[0].irqLine = pic_pin[0];
1688        }
1689
1690        for ( i = 0; tsi_pin[i] >= 0; i++ ) {
1691                /* offset wire # by one so we can initialize to 0 == invalid */
1692                tsi_wire[i] = tsi_pin[i] + 1;
1693                connectIsr(shared, tsiVMEISR, pic_pin[i], i);
1694        }
1695
1696        specialPin = tsi_pin[1] >= 0 ? 1 : 0;
1697
1698        /* setup routing */
1699       
1700        /* IntRoute checks for mgr being installed */
1701        vmeTsi148IrqMgrInstalled=1;
1702
1703        /* route 7 VME irqs to first / 'normal' pin */
1704        for ( i=1; i<8; i++ )
1705                vmeTsi148IntRoute( i, 0 );
1706        for ( i=TSI_DMA_INT_VEC; i<TSI_NUM_INT_VECS; i++ )
1707                vmeTsi148IntRoute( i, specialPin );
1708
1709        for ( i = 0; i<TSI_NUM_WIRES; i++ ) {
1710                /* remember (for unloading the driver) */
1711                devs[0].pic_pin[i] = ( ( tsi_pin[i] >=0 ) ? pic_pin[i] : -1 );
1712        }
1713
1714        return 0;
1715}
1716
1717int
1718vmeTsi148InstallISR(unsigned long vector, VmeTsi148ISR hdl, void *arg)
1719{
1720IRQEntry          ip;
1721int                               v;
1722unsigned long     flags;
1723volatile IRQEntry *p;
1724
1725                if ( !vmeTsi148IrqMgrInstalled || (v = uni2tsivec(vector)) < 0 )
1726                        return -1;
1727
1728                p = irqHdlTbl + v;
1729
1730                if (*p || !(ip=(IRQEntry)malloc(sizeof(IRQEntryRec))))
1731                                return -1;
1732
1733                ip->isr=hdl;
1734                ip->usrData=arg;
1735
1736                rtems_interrupt_disable(flags);
1737                if (*p) {
1738                        rtems_interrupt_enable(flags);
1739                        free(ip);
1740                        return -1;
1741                }
1742                *p = ip;
1743                rtems_interrupt_enable(flags);
1744                return 0;
1745}
1746
1747int
1748vmeTsi148RemoveISR(unsigned long vector, VmeTsi148ISR hdl, void *arg)
1749{
1750int               v;
1751IRQEntry          ip;
1752unsigned long     flags;
1753volatile IRQEntry *p;
1754
1755                if ( !vmeTsi148IrqMgrInstalled || (v = uni2tsivec(vector)) < 0 )
1756                        return -1;
1757
1758                p = irqHdlTbl + v;
1759
1760                rtems_interrupt_disable(flags);
1761                ip = *p;
1762                if ( !ip || ip->isr!=hdl || ip->usrData!=arg ) {
1763                                rtems_interrupt_enable(flags);
1764                                return -1;
1765                }
1766                *p = 0;
1767                rtems_interrupt_enable(flags);
1768
1769                free(ip);
1770                return 0;
1771}
1772
1773static int
1774intDoEnDis(unsigned int level, int dis)
1775{
1776BERegister              *b = THEBASE;
1777unsigned long   flags, v;
1778int                             shift;
1779
1780        if (  ! vmeTsi148IrqMgrInstalled || (shift = lvl2bitno(level)) < 0 )
1781                return -1;
1782
1783        v = 1<<shift;
1784
1785        if ( !dis )
1786                return (int)(v & TSI_RD(b, TSI_INTEO_REG) & TSI_RD(b, TSI_INTEN_REG)) ? 1 : 0;
1787
1788        rtems_interrupt_disable(flags);
1789        if ( dis<0 ) {
1790                TSI_WR(b, TSI_INTEN_REG, TSI_RD(b, TSI_INTEN_REG) & ~v);
1791                TSI_WR(b, TSI_INTEO_REG, TSI_RD(b, TSI_INTEO_REG) & ~v);
1792        } else {
1793                TSI_WR(b, TSI_INTEN_REG, TSI_RD(b, TSI_INTEN_REG) |  v);
1794                TSI_WR(b, TSI_INTEO_REG, TSI_RD(b, TSI_INTEO_REG) |  v);
1795        }
1796        rtems_interrupt_enable(flags);
1797        return 0;
1798}
1799
1800int
1801vmeTsi148IntEnable(unsigned int level)
1802{
1803        return intDoEnDis(level, 1);
1804}
1805
1806int
1807vmeTsi148IntDisable(unsigned int level)
1808{
1809        return intDoEnDis(level, -1);
1810}
1811
1812int
1813vmeTsi148IntIsEnabled(unsigned int level)
1814{
1815        return intDoEnDis(level, 0);
1816}
1817
1818/* Set IACK width (1,2, or 4 bytes) for a given interrupt level.
1819 *
1820 * 'width' arg may be 0,1,2 or 4. If zero, the currently active
1821 * value is returned but not modified.
1822 *
1823 * RETURNS: old width or -1 if invalid argument.
1824 */
1825
1826int
1827vmeTsi148SetIackWidth(int level, int width)
1828{
1829int rval;
1830        if ( level < 1 || level > 7 || !vmeTsi148IrqMgrInstalled )
1831                return -1;
1832
1833        switch ( width ) {
1834                default: return -1;
1835                case 0:
1836                case 1:
1837                case 2:
1838                case 4:
1839                break;
1840        }
1841
1842        rval = tsi_iack_width[level-1];
1843        if ( width )
1844                tsi_iack_width[level-1] = width;
1845        return rval;
1846}
1847
1848int
1849vmeTsi148IntRaiseXX(BERegister *base, int level, unsigned vector)
1850{
1851unsigned long v;
1852
1853        CHECK_BASE(base,0,-1);
1854
1855        if ( level < 1 || level > 7 || vector > 255 )
1856                return -1;      /* invalid argument */
1857
1858        /* Check if already asserted */
1859        if ( (v = TSI_RD(base, TSI_VICR_REG)) & TSI_VICR_IRQS ) {
1860                return -2;  /* already asserted */
1861        }
1862
1863        v &= ~255;
1864
1865        v |= TSI_VICR_IRQL(level) | TSI_VICR_STID(vector);
1866
1867        /* Write Vector */
1868        TSI_WR(base, TSI_VICR_REG, v);
1869
1870        return 0;
1871       
1872}
1873
1874int
1875vmeTsi148IntRaise(int level, unsigned vector)
1876{
1877        return vmeTsi148IntRaiseXX(THEBASE, level, vector);
1878}
1879
1880/* Loopback test of VME/Tsi148 internal interrupts */
1881
1882typedef struct {
1883        rtems_id        q;
1884        int                     l;
1885} LoopbackTstArgs;
1886
1887static void
1888loopbackTstIsr(void *arg, unsigned long vector)
1889{
1890LoopbackTstArgs *pa = arg;
1891        if ( RTEMS_SUCCESSFUL != rtems_message_queue_send(pa->q, (void*)&vector, sizeof(vector)) ) {
1892                /* Overrun ? */
1893                printk("vmeTsi148IntLoopbackTst: (ISR) message queue full / overrun ? disabling IRQ level %i\n", pa->l);
1894                vmeTsi148IntDisable(pa->l);
1895        }
1896}
1897
1898int
1899vmeTsi148IntLoopbackTst(int level, unsigned vector)
1900{
1901BERegister                      *b = THEBASE;
1902rtems_status_code       sc;
1903rtems_id                        q = 0;
1904int                                     installed = 0;
1905int                                     i, err = 0;
1906int                                     doDisable = 0;
1907size_t                          size;
1908unsigned long           msg;
1909char *                          irqfmt  = "VME IRQ @vector %3i %s";
1910char *                          iackfmt = "VME IACK            %s";
1911LoopbackTstArgs         a;
1912
1913        CHECK_BASE(b,0,-1);
1914
1915        /* arg check */
1916        if ( level < 1 || level > 7 || vector > 255 )
1917                return -1;
1918
1919        /* Create message queue */
1920        if ( RTEMS_SUCCESSFUL != (sc=rtems_message_queue_create(
1921                                                                        rtems_build_name('t' ,'U','I','I'),
1922                                                                        4,
1923                                                                        sizeof(unsigned long),
1924                                                                        0,  /* default attributes: fifo, local */
1925                                                                        &q)) ) {
1926                rtems_error(sc, "vmeTsi148IntLoopbackTst: Unable to create message queue");
1927                goto bail;
1928        }
1929
1930        a.q = q;
1931        a.l = level;
1932
1933        /* Install handlers */
1934        if ( vmeTsi148InstallISR(vector, loopbackTstIsr, (void*)&a) ) {
1935                uprintf(stderr,"Unable to install VME ISR to vector %i\n",vector);
1936                goto bail;
1937        }
1938        installed++;
1939        if ( vmeTsi148InstallISR(TSI_VME_SW_IACK_INT_VEC, loopbackTstIsr, (void*)&a) ) {
1940                uprintf(stderr,"Unable to install VME ISR to IACK special vector %i\n",TSI_VME_SW_IACK_INT_VEC);
1941                goto bail;
1942        }
1943        installed++;
1944
1945        if ( !vmeTsi148IntIsEnabled(level) && 0==vmeTsi148IntEnable(level) )
1946                doDisable = 1;
1947       
1948        /* make sure there are no pending interrupts */
1949        TSI_WR(b, TSI_INTC_REG, TSI_INTC_IACKC);
1950
1951        if ( vmeTsi148IntEnable( TSI_VME_SW_IACK_INT_VEC ) ) {
1952                uprintf(stderr,"Unable to enable IACK interrupt\n");
1953                goto bail;
1954        }
1955
1956        printf("vmeTsi148 VME interrupt loopback test; STARTING...\n");
1957        printf(" --> asserting VME IRQ level %i\n", level);
1958        vmeTsi148IntRaise(level, vector);
1959
1960        for ( i = 0; i< 3; i++ ) {
1961        sc = rtems_message_queue_receive(
1962                            q,
1963                            &msg,
1964                            &size,
1965                            RTEMS_WAIT,
1966                            20);
1967                if ( sc ) {
1968                        if ( RTEMS_TIMEOUT == sc && i>1 ) {
1969                                /* OK; we dont' expect more to happen */
1970                                sc = 0;
1971                        } else {
1972                                rtems_error(sc,"Error waiting for interrupts");
1973                        }
1974                        break;
1975                }
1976                if ( msg == vector ) {
1977                        if ( !irqfmt ) {
1978                                printf("Excess VME IRQ received ?? -- BAD\n");
1979                                err = 1;
1980                        } else {
1981                                printf(irqfmt, vector, "received -- PASSED\n");
1982                                irqfmt = 0;
1983                        }
1984                } else if ( msg == TSI_VME_SW_IACK_INT_VEC ) {
1985                        if ( !iackfmt ) {
1986                                printf("Excess VME IACK received ?? -- BAD\n");
1987                                err = 1;
1988                        } else {
1989                                printf(iackfmt, "received -- PASSED\n");
1990                                iackfmt = 0;
1991                        }
1992                } else {
1993                        printf("Unknown IRQ (vector %lu) received -- BAD\n", msg);
1994                        err = 1;
1995                }
1996        }
1997
1998
1999        /* Missing anything ? */
2000        if ( irqfmt ) {
2001                printf(irqfmt,vector, "MISSED -- BAD\n");
2002                err = 1;
2003        }
2004        if ( iackfmt ) {
2005                printf(iackfmt, "MISSED -- BAD\n");
2006                err = 1;
2007        }
2008
2009        printf("FINISHED.\n");
2010
2011bail:
2012        if ( doDisable )
2013                vmeTsi148IntDisable(level);
2014        vmeTsi148IntDisable( TSI_VME_SW_IACK_INT_VEC );
2015        if ( installed > 0 )
2016                vmeTsi148RemoveISR(vector, loopbackTstIsr, (void*)&a);
2017        if ( installed > 1 )
2018                vmeTsi148RemoveISR(TSI_VME_SW_IACK_INT_VEC, loopbackTstIsr, (void*)&a);
2019        if ( q )
2020                rtems_message_queue_delete(q);
2021
2022        return sc ? sc : err;
2023}
2024
2025unsigned long
2026vmeTsi148ClearVMEBusErrorsXX(BERegister *base, uint32_t *paddr)
2027{
2028unsigned long rval;
2029
2030        CHECK_BASE(base,1,-1);
2031
2032        rval = TSI_RD(base, TSI_VEAT_REG);
2033        if ( rval & TSI_VEAT_VES ) {
2034                if ( paddr ) {
2035#if 0 /* no 64-bit support yet */
2036                        *paddr  = ((unsigned long long)TSI_RD(base, TSI_VEAU_REG))<<32;
2037                        *paddr |= TSI_RD(base, TSI_VEAL_REG);
2038#else
2039                        *paddr = TSI_RD(base, TSI_VEAL_REG);
2040#endif
2041                }
2042                /* clear errors */
2043                TSI_WR(base, TSI_VEAT_REG, TSI_VEAT_VESCL);
2044        } else {
2045                rval = 0;
2046        }
2047        return rval;
2048}
2049
2050unsigned long
2051vmeTsi148ClearVMEBusErrors(uint32_t *paddr)
2052{
2053        return vmeTsi148ClearVMEBusErrorsXX(THEBASE, paddr);
2054}
2055
2056/** DMA Support **/
2057
2058/* descriptor must be 8-byte aligned */
2059typedef struct VmeTsi148DmaListDescriptorRec_ {
2060        BEValue                                         dsau,  dsal;   
2061        BEValue                                         ddau,  ddal;   
2062        BEValue                                         dsat,  ddat;   
2063        BEValue                                         dnlau, dnlal;
2064        BEValue                                         dcnt,  ddbs;
2065} VmeTsi148DmaListDescriptorRec;
2066
2067static void     tsi_desc_init  (DmaDescriptor);
2068static int      tsi_desc_setup (DmaDescriptor, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t);
2069static void     tsi_desc_setnxt(DmaDescriptor, DmaDescriptor);
2070static void     tsi_desc_dump  (DmaDescriptor);
2071static int      tsi_desc_start (volatile void *controller_addr, int channel, DmaDescriptor p);
2072
2073VMEDmaListClassRec      vmeTsi148DmaListClass = {
2074        desc_size:  sizeof(VmeTsi148DmaListDescriptorRec),
2075        desc_align: 8,
2076        freeList:   0,
2077        desc_alloc: 0,
2078        desc_free:  0,
2079        desc_init:  tsi_desc_init,
2080        desc_setnxt:tsi_desc_setnxt,
2081        desc_setup: tsi_desc_setup,
2082        desc_start: tsi_desc_start,
2083        desc_refr:  0,
2084        desc_dump:      tsi_desc_dump,
2085};
2086
2087/* DMA Control */
2088#define TSI_DMA_REG(off,i)      ((off)+(((i)&1)<<7))   
2089
2090#define TSI_DCTL_REG(i)         TSI_DMA_REG(0x500,i)
2091#define TSI_DCTL0_REG           0x500
2092#define TSI_DCTL1_REG           0x580
2093#   define TSI_DCTL_ABT         (1<<27) /* abort */
2094#   define TSI_DCTL_PAU         (1<<26) /* pause */
2095#   define TSI_DCTL_DGO         (1<<25) /* GO    */
2096#   define TSI_DCTL_MOD         (1<<23) /* linked list: 0, direct: 1 */
2097#   define TSI_DCTL_VFAR        (1<<17) /* flush FIFO on VME error: 1 (discard: 0) */
2098#   define TSI_DCTL_PFAR        (1<<16) /* flush FIFO on PCI error: 1 (discard: 0) */
2099
2100#   define TSI_DCTL_VBKS(i)     (((i)&7)<<12) /* VME block size */
2101#   define TSI_DCTL_VBKS_32     TSI_DCTL_VBKS(0)
2102#   define TSI_DCTL_VBKS_64     TSI_DCTL_VBKS(1)
2103#   define TSI_DCTL_VBKS_128    TSI_DCTL_VBKS(2)
2104#   define TSI_DCTL_VBKS_256    TSI_DCTL_VBKS(3)
2105#   define TSI_DCTL_VBKS_512    TSI_DCTL_VBKS(4)
2106#   define TSI_DCTL_VBKS_1024   TSI_DCTL_VBKS(5)
2107#   define TSI_DCTL_VBKS_2048   TSI_DCTL_VBKS(6)
2108#   define TSI_DCTL_VBKS_4096   TSI_DCTL_VBKS(7)
2109
2110#   define TSI_DCTL_VBOT(i)     (((i)&7)<< 8) /* VME back-off time */
2111#   define TSI_DCTL_VBOT_0us    TSI_DCTL_VBOT(0)
2112#   define TSI_DCTL_VBOT_1us    TSI_DCTL_VBOT(1)
2113#   define TSI_DCTL_VBOT_2us    TSI_DCTL_VBOT(2)
2114#   define TSI_DCTL_VBOT_4us    TSI_DCTL_VBOT(3)
2115#   define TSI_DCTL_VBOT_8us    TSI_DCTL_VBOT(4)
2116#   define TSI_DCTL_VBOT_16us   TSI_DCTL_VBOT(5)
2117#   define TSI_DCTL_VBOT_32us   TSI_DCTL_VBOT(6)
2118#   define TSI_DCTL_VBOT_64us   TSI_DCTL_VBOT(7)
2119
2120#   define TSI_DCTL_PBKS(i)     (((i)&7)<< 4) /* PCI block size */
2121#   define TSI_DCTL_PBKS_32     TSI_DCTL_PBKS(0)
2122#   define TSI_DCTL_PBKS_64     TSI_DCTL_PBKS(1)
2123#   define TSI_DCTL_PBKS_128    TSI_DCTL_PBKS(2)
2124#   define TSI_DCTL_PBKS_256    TSI_DCTL_PBKS(3)
2125#   define TSI_DCTL_PBKS_512    TSI_DCTL_PBKS(4)
2126#   define TSI_DCTL_PBKS_1024   TSI_DCTL_PBKS(5)
2127#   define TSI_DCTL_PBKS_2048   TSI_DCTL_PBKS(6)
2128#   define TSI_DCTL_PBKS_4096   TSI_DCTL_PBKS(7)
2129
2130#   define TSI_DCTL_PBOT(i)     (((i)&7)<< 0) /* PCI back-off time */
2131#   define TSI_DCTL_PBOT_0us    TSI_DCTL_PBOT(0)
2132#   define TSI_DCTL_PBOT_1us    TSI_DCTL_PBOT(1)
2133#   define TSI_DCTL_PBOT_2us    TSI_DCTL_PBOT(2)
2134#   define TSI_DCTL_PBOT_4us    TSI_DCTL_PBOT(3)
2135#   define TSI_DCTL_PBOT_8us    TSI_DCTL_PBOT(4)
2136#   define TSI_DCTL_PBOT_16us   TSI_DCTL_PBOT(5)
2137#   define TSI_DCTL_PBOT_32us   TSI_DCTL_PBOT(6)
2138#   define TSI_DCTL_PBOT_64us   TSI_DCTL_PBOT(7)
2139
2140/* DMA Status */
2141#define TSI_DSTA_REG(i)         TSI_DMA_REG(0x504,i)
2142#define TSI_DSTA0_REG           0x504
2143#define TSI_DSTA1_REG           0x584
2144#   define TSI_DSTA_ERR         (1<<28)
2145#   define TSI_DSTA_ABT         (1<<27)
2146#   define TSI_DSTA_PAU         (1<<26)
2147#   define TSI_DSTA_DON         (1<<25)
2148#   define TSI_DSTA_BSY         (1<<24)
2149#   define TSI_DSTA_ERRS        (1<<20) /* Error source; PCI:1, VME:0 */
2150#   define TSI_DSTA_ERT_MSK     (3<<16) /* Error type                 */
2151#   define TSI_DSTA_ERT_BERR_E  (0<<16) /* 2eVME even or other bus error */
2152#   define TSI_DSTA_ERT_BERR_O  (1<<16) /* 2eVME odd bus error        */
2153#   define TSI_DSTA_ERT_SLVE_E  (2<<16) /* 2eVME even or other slave termination */
2154#   define TSI_DSTA_ERT_SLVE_O  (3<<16) /* 2eVME odd slave termination; 2eSST read last word invalid */
2155
2156/* DMA Current source address upper */
2157#define TSI_DCSAU_REG(i)        TSI_DMA_REG(0x508,i)
2158#define TSI_DCSAU0_REG          0x508
2159#define TSI_DCSAU1_REG          0x588
2160
2161/* DMA Current source address lower */
2162#define TSI_DCSAL_REG(i)        TSI_DMA_REG(0x50c,i)
2163#define TSI_DCSAL0_REG          0x50c
2164#define TSI_DCSAL1_REG          0x58c
2165
2166/* DMA Current destination address upper */
2167#define TSI_DCDAU_REG(i)        TSI_DMA_REG(0x510,i)
2168#define TSI_DCDAU0_REG          0x510
2169#define TSI_DCDAU1_REG          0x590
2170
2171/* DMA Current destination address lower */
2172#define TSI_DCDAL_REG(i)        TSI_DMA_REG(0x514,i)
2173#define TSI_DCDAL0_REG          0x514
2174#define TSI_DCDAL1_REG          0x594
2175
2176/* DMA Current link address upper */
2177#define TSI_DCLAU_REG(i)        TSI_DMA_REG(0x518,i)
2178#define TSI_DCLAU0_REG          0x518
2179#define TSI_DCLAU1_REG          0x598
2180
2181/* DMA Current link address lower */
2182#define TSI_DCLAL_REG(i)        TSI_DMA_REG(0x51c,i)
2183#define TSI_DCLAL0_REG          0x51c
2184#define TSI_DCLAL1_REG          0x59c
2185
2186/* DMA Source address upper */
2187#define TSI_DSAU_REG(i)         TSI_DMA_REG(0x520,i)
2188#define TSI_DSAU0_REG           0x520
2189#define TSI_DSAU1_REG           0x5a0
2190
2191/* DMA Source address lower */
2192#define TSI_DSAL_REG(i)         TSI_DMA_REG(0x524,i)
2193#define TSI_DSAL0_REG           0x524
2194#define TSI_DSAL1_REG           0x5a4
2195
2196/* DMA Destination address upper */
2197#define TSI_DDAU_REG(i)         TSI_DMA_REG(0x528,i)
2198#define TSI_DDAU0_REG           0x528
2199#define TSI_DDAU1_REG           0x5a8
2200
2201/* DMA Destination address lower */
2202#define TSI_DDAL_REG(i)         TSI_DMA_REG(0x52c,i)
2203#define TSI_DDAL0_REG           0x52c
2204#define TSI_DDAL1_REG           0x5ac
2205
2206/* DMA Source Attribute */
2207#define TSI_DSAT_REG(i)         TSI_DMA_REG(0x530,i)
2208#define TSI_DSAT0_REG           0x530
2209#define TSI_DSAT1_REG           0x5b0
2210
2211/* DMA Destination Attribute */
2212#define TSI_DDAT_REG(i)         TSI_DMA_REG(0x534,i)
2213#define TSI_DDAT0_REG           0x534
2214#define TSI_DDAT1_REG           0x5b4
2215
2216#   define TSI_DXAT_TYP(i)      (((i)&3)<<28)   /* Xfer type */
2217#   define TSI_DXAT_TYP_PCI     TSI_DXAT_TYP(0)
2218#   define TSI_DXAT_TYP_VME     TSI_DXAT_TYP(1)
2219#   define TSI_DSAT_TYP_PAT     TSI_DXAT_TYP(2) /* pattern */
2220
2221#   define TSI_DSAT_PSZ         (1<<25) /* pattern size 32-bit: 0, 8-bit: 1 */
2222#   define TSI_DSAT_NIN         (1<<24) /* no-increment */
2223
2224#       define TSI_DXAT_OTAT_MSK        ((1<<13)-1)     /* get bits compatible with OTAT */
2225
2226#   define TSI_DXAT_SSTM(i)     (((i)&3)<<11)   /* 2eSST Xfer rate (MB/s) */
2227#   define TSI_DXAT_SSTM_116    TSI_DXAT_SSTM(0)
2228#   define TSI_DXAT_SSTM_267    TSI_DXAT_SSTM(1)
2229#   define TSI_DXAT_SSTM_320    TSI_DXAT_SSTM(2)
2230
2231#   define TSI_DXAT_TM(i)       (((i)&7)<< 8) /* VME Xfer mode */
2232#   define TSI_DXAT_TM_SCT      TSI_DXAT_TM(0)
2233#   define TSI_DXAT_TM_BLT      TSI_DXAT_TM(1)
2234#   define TSI_DXAT_TM_MBLT     TSI_DXAT_TM(2)
2235#   define TSI_DXAT_TM_2eVME    TSI_DXAT_TM(3)
2236#   define TSI_DXAT_TM_2eSST    TSI_DXAT_TM(4)
2237#   define TSI_DSAT_TM_2eSST_B  TSI_DXAT_TM(5)  /* 2eSST broadcast */
2238
2239#   define TSI_DXAT_DBW(i)      (((i)&3)<< 6)   /* VME Data width */
2240#   define TSI_DXAT_DBW_16      TSI_DXAT_DBW(0)
2241#   define TSI_DXAT_DBW_32      TSI_DXAT_DBW(1)
2242
2243#   define TSI_DXAT_SUP         (1<<5)  /* supervisor access */
2244#   define TSI_DXAT_PGM         (1<<4)  /* program access    */
2245
2246#   define TSI_DXAT_AM(i)       (((i)&15)<<0)   /* VME Address mode */
2247#   define TSI_DXAT_AM_A16      TSI_DXAT_AM(0)
2248#   define TSI_DXAT_AM_A24      TSI_DXAT_AM(1)
2249#   define TSI_DXAT_AM_A32      TSI_DXAT_AM(2)
2250#   define TSI_DXAT_AM_A64      TSI_DXAT_AM(4)
2251#   define TSI_DXAT_AM_CSR      TSI_DXAT_AM(5)
2252
2253/* DMA Next link address upper */
2254#define TSI_DNLAU_REG(i)        TSI_DMA_REG(0x538,i)
2255#define TSI_DNLAU0_REG          0x538
2256#define TSI_DNLAU1_REG          0x5b8
2257
2258/* DMA Next link address lower */
2259#define TSI_DNLAL_REG(i)        TSI_DMA_REG(0x53c,i)
2260#define TSI_DNLAL0_REG          0x53c
2261#define TSI_DNLAL1_REG          0x5bc
2262
2263#       define TSI_DNLAL_LLA    1       /* last element in chain */
2264
2265/* DMA Byte Count */
2266#define TSI_DCNT_REG(i)         TSI_DMA_REG(0x540,i)
2267#define TSI_DCNT0_REG           0x540
2268#define TSI_DCNT1_REG           0x54c
2269
2270/* DMA 2eSST destination broadcast select */
2271#define TSI_DDBS_REG(i)         TSI_DMA_REG(0x544,i)
2272#define TSI_DDBS0_REG           0x544
2273#define TSI_DDBS1_REG           0x5c4
2274
2275/* Convert canonical xfer_mode into Tsi148 bits; return -1 if invalid */
2276static uint32_t
2277vme_attr(uint32_t xfer_mode)
2278{
2279uint32_t vme_mode;
2280        if ( am2omode(xfer_mode, &vme_mode) )
2281                return BSP_VMEDMA_STATUS_UNSUP;
2282
2283        /* am2omode may set prefetch and other bits */
2284        vme_mode &= TSI_DXAT_OTAT_MSK;
2285        vme_mode |= TSI_DXAT_TYP_VME;
2286
2287        if ( BSP_VMEDMA_MODE_NOINC_VME & xfer_mode )  {
2288                /* no-incr. only supported on source address */
2289                if ( (BSP_VMEDMA_MODE_PCI2VME & xfer_mode) )
2290                        return BSP_VMEDMA_STATUS_UNSUP;
2291                vme_mode |= TSI_DSAT_NIN;
2292        }
2293
2294        return vme_mode;
2295}
2296
2297static uint32_t
2298pci_attr(uint32_t xfer_mode)
2299{
2300uint32_t pci_mode = 0;
2301        if ( BSP_VMEDMA_MODE_NOINC_PCI & xfer_mode )  {
2302                /* no-incr. only supported on source address */
2303                if ( ! (BSP_VMEDMA_MODE_PCI2VME & xfer_mode) )
2304                        return BSP_VMEDMA_STATUS_UNSUP;
2305                pci_mode |= TSI_DSAT_NIN;
2306        }
2307        return pci_mode;
2308}
2309
2310static void tsi_desc_init(DmaDescriptor p)
2311{
2312VmeTsi148DmaListDescriptor d = p;
2313        st_be32( &d->dnlau, 0 );
2314        st_be32( &d->dnlal, TSI_DNLAL_LLA );
2315        st_be32( &d->ddbs, (1<<22)-1 ); /* SSTB broadcast not yet fully supported */
2316}
2317
2318static void
2319tsi_desc_setnxt(DmaDescriptor p, DmaDescriptor n)
2320{
2321VmeTsi148DmaListDescriptor d = p;
2322        if ( 0 == n ) {
2323                st_be32( &d->dnlal, TSI_DNLAL_LLA );
2324        } else {
2325                st_be32( &d->dnlal, BSP_LOCAL2PCI_ADDR((uint32_t)n) );
2326        }
2327}
2328
2329static void
2330tsi_desc_dump(DmaDescriptor p)
2331{
2332VmeTsi148DmaListDescriptor d = p;
2333                printf("   DSA: 0x%08lx%08lx\n", ld_be32(&d->dsau),  ld_be32(&d->dsal));
2334                printf("   DDA: 0x%08lx%08lx\n", ld_be32(&d->ddau),  ld_be32(&d->ddal));
2335                printf("   NLA: 0x%08lx%08lx\n", ld_be32(&d->dnlau), ld_be32(&d->dnlal));
2336                printf("   SAT: 0x%08lx              DAT: 0x%08lx\n", ld_be32(&d->dsat), ld_be32(&d->ddat));
2337                printf("   CNT: 0x%08lx\n",      ld_be32(&d->dcnt));
2338}
2339
2340
2341int
2342vmeTsi148DmaSetupXX(BERegister *base, int channel, uint32_t mode, uint32_t xfer_mode, void *custom)
2343{
2344uint32_t ctl = 0;
2345uint32_t vmeatt, pciatt, sat, dat;
2346
2347        if ( channel < 0 || channel > 1 )
2348                return BSP_VMEDMA_STATUS_UNSUP;
2349
2350        /* Check bus mode */
2351        if ( (uint32_t)BSP_VMEDMA_STATUS_UNSUP == (vmeatt = vme_attr(xfer_mode)) )
2352                return -2;
2353
2354        /* Check PCI bus mode */
2355        if ( (uint32_t)BSP_VMEDMA_STATUS_UNSUP == (pciatt = pci_attr(xfer_mode)) )
2356                return -3;
2357
2358        /* Compute control word; bottleneck is VME; */
2359        ctl |= TSI_DCTL_PBKS_32;
2360        ctl |= (BSP_VMEDMA_OPT_THROUGHPUT == mode ? TSI_DCTL_PBOT_0us : TSI_DCTL_PBOT_1us);
2361
2362        switch ( mode ) {
2363                case BSP_VMEDMA_OPT_THROUGHPUT:
2364                        ctl |= TSI_DCTL_VBKS_1024;             
2365                        ctl |= TSI_DCTL_VBOT_0us;
2366                break;
2367               
2368                case BSP_VMEDMA_OPT_LOWLATENCY:
2369                        ctl |= TSI_DCTL_VBKS_32;
2370                        ctl |= TSI_DCTL_VBOT_0us;
2371                break;
2372
2373                case BSP_VMEDMA_OPT_SHAREDBUS:
2374                        ctl |= TSI_DCTL_VBKS_128;
2375                        ctl |= TSI_DCTL_VBOT_64us;
2376                break;
2377
2378                case BSP_VMEDMA_OPT_CUSTOM:
2379                        ctl = *(uint32_t*)custom;
2380                break;
2381
2382                default:
2383                case BSP_VMEDMA_OPT_DEFAULT:
2384                        ctl = 0;
2385                break;
2386        }
2387        TSI_WR(base, TSI_DCTL_REG(channel), ctl);
2388        if ( BSP_VMEDMA_MODE_PCI2VME & xfer_mode ) {
2389                dat = vmeatt; sat = pciatt;
2390        } else {
2391                sat = vmeatt; dat = pciatt;
2392        }
2393        TSI_WR(base, TSI_DSAT_REG(channel), sat);
2394        TSI_WR(base, TSI_DDAT_REG(channel), dat);
2395        return 0;
2396}
2397
2398int
2399vmeTsi148DmaSetup(int channel, uint32_t mode, uint32_t xfer_mode, void *custom)
2400{
2401BERegister *base = THEBASE;
2402        return vmeTsi148DmaSetupXX(base, channel, mode, xfer_mode, custom);
2403}
2404
2405
2406int
2407vmeTsi148DmaListStartXX(BERegister *base, int channel, VmeTsi148DmaListDescriptor d)
2408{
2409uint32_t ctl;
2410
2411        if ( d ) {
2412                /* Set list pointer and start */
2413                if ( channel < 0 || channel > 1 )
2414                        return BSP_VMEDMA_STATUS_UNSUP;
2415
2416                if ( TSI_DSTA_BSY & TSI_RD(base, TSI_DSTA_REG(channel)) )
2417                        return BSP_VMEDMA_STATUS_BUSY;  /* channel busy */
2418
2419                TSI_WR(base, TSI_DNLAL_REG(channel), (uint32_t)BSP_LOCAL2PCI_ADDR(d));
2420
2421                asm volatile("":::"memory");
2422
2423                /* Start transfer */
2424                ctl  = TSI_RD(base, TSI_DCTL_REG(channel)) | TSI_DCTL_DGO;
2425                ctl &= ~TSI_DCTL_MOD;
2426                TSI_WR(base, TSI_DCTL_REG(channel), ctl);
2427        }
2428        /* else: list vs. direct mode is set by the respective start commands */
2429        return 0;
2430}
2431
2432int
2433vmeTsi148DmaListStart(int channel, VmeTsi148DmaListDescriptor d)
2434{
2435BERegister *base = THEBASE;
2436        return vmeTsi148DmaListStartXX(base, channel, d);
2437}
2438
2439int
2440vmeTsi148DmaStartXX(BERegister *base, int channel, uint32_t pci_addr, uint32_t vme_addr, uint32_t n_bytes)
2441{
2442uint32_t src, dst, ctl;
2443
2444        if ( channel < 0 || channel > 1 )
2445                return BSP_VMEDMA_STATUS_UNSUP;
2446
2447        if ( TSI_DSTA_BSY & TSI_RD(base, TSI_DSTA_REG(channel)) )
2448                return BSP_VMEDMA_STATUS_BUSY;  /* channel busy */
2449
2450        /* retrieve direction from dst attribute */
2451        if ( TSI_DXAT_TYP_VME & TSI_RD(base, TSI_DDAT_REG(channel)) ) {
2452                dst = vme_addr;
2453                src = pci_addr;
2454        } else {
2455                src = vme_addr;
2456                dst = pci_addr;
2457        }
2458        /* FIXME: we leave the 'upper' registers (topmost 32bits) alone.
2459         *        Probably, we should reset them at init...
2460         */
2461        TSI_WR(base, TSI_DSAL_REG(channel), src);
2462        TSI_WR(base, TSI_DDAL_REG(channel), dst);
2463        TSI_WR(base, TSI_DCNT_REG(channel), n_bytes);
2464
2465        asm volatile("":::"memory");
2466
2467        /* Start transfer */
2468        ctl  = TSI_RD(base, TSI_DCTL_REG(channel)) | TSI_DCTL_DGO | TSI_DCTL_MOD;               
2469        TSI_WR(base, TSI_DCTL_REG(channel), ctl);
2470
2471        return 0;
2472}
2473
2474int
2475vmeTsi148DmaStart(int channel, uint32_t pci_addr, uint32_t vme_addr, uint32_t n_bytes)
2476{
2477BERegister *base = THEBASE;
2478        return vmeTsi148DmaStartXX(base, channel, pci_addr, vme_addr, n_bytes);
2479}
2480
2481uint32_t
2482vmeTsi148DmaStatusXX(BERegister *base, int channel)
2483{
2484uint32_t        st = TSI_RD(base, TSI_DSTA_REG(channel));
2485
2486        if ( channel < 0 || channel > 1 )
2487                return BSP_VMEDMA_STATUS_UNSUP;
2488
2489        st = TSI_RD(base, TSI_DSTA_REG(channel));
2490
2491        /* Status can be zero if an empty list (all counts == 0) is executed */
2492        if ( (TSI_DSTA_DON & st) || 0 == st )
2493                return BSP_VMEDMA_STATUS_OK;
2494
2495        if ( TSI_DSTA_BSY & st )
2496                return BSP_VMEDMA_STATUS_BUSY;  /* channel busy */
2497
2498        if ( TSI_DSTA_ERR & st ) {
2499                if ( TSI_DSTA_ERRS & st )
2500                        return BSP_VMEDMA_STATUS_BERR_PCI;
2501                if ( ! (TSI_DSTA_ERT_SLVE_E     & st) )
2502                        return BSP_VMEDMA_STATUS_BERR_VME;
2503        }
2504
2505        return BSP_VMEDMA_STATUS_OERR;
2506}
2507
2508uint32_t
2509vmeTsi148DmaStatus(int channel)
2510{
2511BERegister *base = THEBASE;
2512        return vmeTsi148DmaStatusXX(base, channel);
2513}
2514
2515#define ALL_BITS_NEEDED (BSP_VMEDMA_MSK_ATTR | BSP_VMEDMA_MSK_PCIA | BSP_VMEDMA_MSK_VMEA)
2516
2517static int
2518tsi_desc_setup (
2519                DmaDescriptor p,
2520                uint32_t        attr_mask,
2521                uint32_t        xfer_mode,
2522                uint32_t        pci_addr,
2523                uint32_t        vme_addr,
2524                uint32_t        n_bytes)
2525{
2526VmeTsi148DmaListDescriptor      d = p;
2527uint32_t        vmeatt = 0, pciatt = 0, tmp, src, dst, dat, sat;
2528
2529        /* argument check */
2530
2531        /* since we must vme/pci into src/dst we need the direction
2532         * bit. Reject requests that have only part of the mask
2533         * bits set. It would be possible to be more sophisticated
2534         * by caching more information but we try to be simple here...
2535         */
2536        tmp = attr_mask & ALL_BITS_NEEDED;
2537        if ( tmp != 0 && tmp != ALL_BITS_NEEDED )
2538                return -1;
2539
2540        if ( BSP_VMEDMA_MSK_ATTR & attr_mask ) {
2541                /* Check VME bus mode */
2542                vmeatt = vme_attr(xfer_mode);
2543                if ( (uint32_t)BSP_VMEDMA_STATUS_UNSUP == vmeatt  )
2544                        return -1;
2545
2546                /* Check PCI bus mode */
2547                pciatt = pci_attr(xfer_mode);
2548                if ( (uint32_t)BSP_VMEDMA_STATUS_UNSUP == pciatt  )
2549                        return -1;
2550        }
2551
2552        if ( BSP_VMEDMA_MSK_ATTR & attr_mask ) {
2553                if ( BSP_VMEDMA_MODE_PCI2VME & xfer_mode ) {
2554                        dat = vmeatt;   sat = pciatt;
2555                        dst = vme_addr; src = pci_addr;
2556                } else {
2557                        sat = vmeatt;   dat = pciatt;
2558                        src = vme_addr; dst = pci_addr;
2559                }
2560                st_be32( &d->dsau, 0 );   st_be32( &d->dsal, src );
2561                st_be32( &d->ddau, 0 );   st_be32( &d->ddal, dst );
2562                st_be32( &d->dsat, sat ); st_be32( &d->ddat, dat );
2563        }
2564
2565        if ( BSP_VMEDMA_MSK_BCNT & attr_mask )
2566                st_be32( &d->dcnt, n_bytes);
2567
2568        return 0;
2569}
2570
2571static int
2572tsi_desc_start (volatile void *controller_addr, int channel, DmaDescriptor p)
2573{
2574VmeTsi148DmaListDescriptor d = p;
2575        if ( !controller_addr )
2576                controller_addr = THEBASE;
2577        return vmeTsi148DmaListStartXX((BERegister*)controller_addr, channel, d);
2578}
2579
2580#ifdef DEBUG_MODULAR
2581void
2582_cexpModuleInitialize(void* unused)
2583{
2584        vmeTsi148Init();
2585        vmeTsi148Reset();
2586}
2587
2588int
2589_cexpModuleFinalize(void *unused)
2590{
2591int             i;
2592int             rval = 1;
2593void    (*isrs[TSI_NUM_WIRES])() = {
2594        isr_pin0,
2595        isr_pin1,
2596        isr_pin2,
2597        isr_pin3,
2598};
2599
2600rtems_irq_connect_data  xx;
2601        xx.on   = my_no_op; /* at _least_ they could check for a 0 pointer */
2602        xx.off  = my_no_op;
2603        xx.isOn = my_isOn;
2604
2605        TSI_WR(THEBASE, TSI_INTEO_REG, 0);
2606
2607        for ( i=0; i<TSI_NUM_INT_VECS; i++) {
2608                /* Dont even bother to uninstall handlers */
2609        }
2610        if ( vmeTsi148IrqMgrInstalled ) {
2611                for ( i=0; i<TSI_NUM_WIRES; i++ ) {
2612                        if ( (int)(xx.name = devs[0].pic_pin[i]) >=0 ) {
2613                                xx.hdl  = isrs[i];
2614                                rval    = rval && BSP_remove_rtems_irq_handler(&xx);
2615                        }
2616                }
2617        }
2618        return !rval;
2619}
2620#endif
Note: See TracBrowser for help on using the repository browser.