Initial import of binutils 2.22 on the new vendor branch
[dragonfly.git] / sys / net / i4b / capi / iavc / iavc_card.c
1 /*
2  * Copyright (c) 2001 Cubical Solutions Ltd. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  *
25  * capi/iavc/iavc_card.c
26  *              The AVM ISDN controllers' card specific support routines.
27  *
28  * $FreeBSD: src/sys/i4b/capi/iavc/iavc_card.c,v 1.1.2.1 2001/08/10 14:08:34 obrien Exp $
29  * $DragonFly: src/sys/net/i4b/capi/iavc/iavc_card.c,v 1.8 2006/10/25 20:56:03 dillon Exp $
30  */
31
32 #include <sys/param.h>
33 #include <sys/kernel.h>
34 #include <sys/systm.h>
35 #include <sys/mbuf.h>
36 #include <sys/socket.h>
37 #include <sys/bus.h>
38 #include <sys/rman.h>
39 #include <sys/thread2.h>
40
41 #include <machine/clock.h>
42
43 #include <net/if.h>
44
45 #include <net/i4b/include/machine/i4b_debug.h>
46 #include <net/i4b/include/machine/i4b_ioctl.h>
47 #include <net/i4b/include/machine/i4b_trace.h>
48
49 #include "../../include/i4b_global.h"
50 #include "../../include/i4b_l3l4.h"
51 #include "../../include/i4b_mbuf.h"
52 #include "../capi.h"
53
54 #include "iavc.h"
55
56 /*
57 //  AVM B1 (active BRI, PIO mode)
58 */
59
60 int
61 b1_detect(iavc_softc_t *sc)
62 {
63     if ((iavc_read_port(sc, B1_INSTAT) & 0xfc) ||
64         (iavc_read_port(sc, B1_OUTSTAT) & 0xfc))
65         return (1);
66
67     b1io_outp(sc, B1_INSTAT, 0x02);
68     b1io_outp(sc, B1_OUTSTAT, 0x02);
69     if ((iavc_read_port(sc, B1_INSTAT) & 0xfe) != 2 ||
70         (iavc_read_port(sc, B1_OUTSTAT) & 0xfe) != 2)
71         return (2);
72
73     b1io_outp(sc, B1_INSTAT, 0x00);
74     b1io_outp(sc, B1_OUTSTAT, 0x00);
75     if ((iavc_read_port(sc, B1_INSTAT) & 0xfe) ||
76         (iavc_read_port(sc, B1_OUTSTAT) & 0xfe))
77         return (3);
78
79     return (0); /* found */
80 }
81
82 void
83 b1_disable_irq(iavc_softc_t *sc)
84 {
85     b1io_outp(sc, B1_INSTAT, 0x00);
86 }
87
88 void
89 b1_reset(iavc_softc_t *sc)
90 {
91     b1io_outp(sc, B1_RESET, 0);
92     DELAY(55*2*1000);
93
94     b1io_outp(sc, B1_RESET, 1);
95     DELAY(55*2*1000);
96
97     b1io_outp(sc, B1_RESET, 0);
98     DELAY(55*2*1000);
99 }
100
101 /*
102 //  Newer PCI-based B1's, and T1's, supports DMA
103 */
104
105 int
106 b1dma_detect(iavc_softc_t *sc)
107 {
108     AMCC_WRITE(sc, AMCC_MCSR, 0);
109     DELAY(10*1000);
110     AMCC_WRITE(sc, AMCC_MCSR, 0x0f000000);
111     DELAY(10*1000);
112     AMCC_WRITE(sc, AMCC_MCSR, 0);
113     DELAY(42*1000);
114
115     AMCC_WRITE(sc, AMCC_RXLEN, 0);
116     AMCC_WRITE(sc, AMCC_TXLEN, 0);
117     sc->sc_csr = 0;
118     AMCC_WRITE(sc, AMCC_INTCSR, sc->sc_csr);
119
120     if (AMCC_READ(sc, AMCC_INTCSR) != 0)
121         return 1;
122
123     AMCC_WRITE(sc, AMCC_RXPTR, 0xffffffff);
124     AMCC_WRITE(sc, AMCC_TXPTR, 0xffffffff);
125     if ((AMCC_READ(sc, AMCC_RXPTR) != 0xfffffffc) ||
126         (AMCC_READ(sc, AMCC_TXPTR) != 0xfffffffc))
127         return 2;
128
129     AMCC_WRITE(sc, AMCC_RXPTR, 0);
130     AMCC_WRITE(sc, AMCC_TXPTR, 0);
131     if ((AMCC_READ(sc, AMCC_RXPTR) != 0) ||
132         (AMCC_READ(sc, AMCC_TXPTR) != 0))
133         return 3;
134
135     iavc_write_port(sc, 0x10, 0x00);
136     iavc_write_port(sc, 0x07, 0x00);
137
138     iavc_write_port(sc, 0x02, 0x02);
139     iavc_write_port(sc, 0x03, 0x02);
140
141     if (((iavc_read_port(sc, 0x02) & 0xfe) != 0x02) ||
142         (iavc_read_port(sc, 0x03) != 0x03))
143         return 4;
144
145     iavc_write_port(sc, 0x02, 0x00);
146     iavc_write_port(sc, 0x03, 0x00);
147
148     if (((iavc_read_port(sc, 0x02) & 0xfe) != 0x00) ||
149         (iavc_read_port(sc, 0x03) != 0x01))
150         return 5;
151
152     return (0); /* found */
153 }
154
155 void
156 b1dma_reset(iavc_softc_t *sc)
157 {
158     crit_enter();
159     sc->sc_csr = 0;
160     AMCC_WRITE(sc, AMCC_INTCSR, sc->sc_csr);
161     AMCC_WRITE(sc, AMCC_MCSR, 0);
162     AMCC_WRITE(sc, AMCC_RXLEN, 0);
163     AMCC_WRITE(sc, AMCC_TXLEN, 0);
164
165     iavc_write_port(sc, 0x10, 0x00); /* XXX magic numbers from */
166     iavc_write_port(sc, 0x07, 0x00); /* XXX the linux driver */
167
168     crit_exit();
169
170     AMCC_WRITE(sc, AMCC_MCSR, 0);
171     DELAY(10 * 1000);
172     AMCC_WRITE(sc, AMCC_MCSR, 0x0f000000);
173     DELAY(10 * 1000);
174     AMCC_WRITE(sc, AMCC_MCSR, 0);
175     DELAY(42 * 1000);
176 }
177
178 /*
179 //  AVM T1 (active PRI)
180 */
181
182 /* XXX how do these differ from b1io_{read,write}_reg()? XXX */
183
184 static int
185 b1dma_tx_empty(int iobase)
186 {
187         return inb(iobase + 3) & 1;
188 }
189
190 static int
191 b1dma_rx_full(int iobase)
192 {
193         return inb(iobase + 2) & 1;
194 }
195
196 static int
197 b1dma_tolink(iavc_softc_t *sc, void *buf, int len)
198 {
199     volatile int spin;
200     char *s = (char*) buf;
201     while (len--) {
202         spin = 0;
203         while (!b1dma_tx_empty(sc->sc_iobase) && spin < 100000)
204             spin++;
205         if (!b1dma_tx_empty(sc->sc_iobase))
206             return -1;
207         t1io_outp(sc, 1, *s++);
208     }
209     return 0;
210 }
211
212 static int
213 b1dma_fromlink(iavc_softc_t *sc, void *buf, int len)
214 {
215     volatile int spin;
216     char *s = (char*) buf;
217     while (len--) {
218         spin = 0;
219         while (!b1dma_rx_full(sc->sc_iobase) && spin < 100000)
220             spin++;
221         if (!b1dma_rx_full(sc->sc_iobase))
222             return -1;
223         *s++ = t1io_inp(sc, 0);
224     }
225     return 0;
226 }
227
228 static int
229 WriteReg(iavc_softc_t *sc, u_int32_t reg, u_int8_t val)
230 {
231     u_int8_t cmd = 0;
232     if (b1dma_tolink(sc, &cmd, 1) == 0 &&
233         b1dma_tolink(sc, &reg, 4) == 0) {
234         u_int32_t tmp = val;
235         return b1dma_tolink(sc, &tmp, 4);
236     }
237     return -1;
238 }
239
240 static u_int8_t
241 ReadReg(iavc_softc_t *sc, u_int32_t reg)
242 {
243     u_int8_t cmd = 1;
244     if (b1dma_tolink(sc, &cmd, 1) == 0 &&
245         b1dma_tolink(sc, &reg, 4) == 0) {
246         u_int32_t tmp;
247         if (b1dma_fromlink(sc, &tmp, 4) == 0)
248             return (u_int8_t) tmp;
249     }
250     return 0xff;
251 }
252
253 int
254 t1_detect(iavc_softc_t *sc)
255 {
256     int ret = b1dma_detect(sc);
257     if (ret) return ret;
258
259     if ((WriteReg(sc, 0x80001000, 0x11) != 0) ||
260         (WriteReg(sc, 0x80101000, 0x22) != 0) ||
261         (WriteReg(sc, 0x80201000, 0x33) != 0) ||
262         (WriteReg(sc, 0x80301000, 0x44) != 0))
263         return 6;
264
265     if ((ReadReg(sc, 0x80001000) != 0x11) ||
266         (ReadReg(sc, 0x80101000) != 0x22) ||
267         (ReadReg(sc, 0x80201000) != 0x33) ||
268         (ReadReg(sc, 0x80301000) != 0x44))
269         return 7;
270
271     if ((WriteReg(sc, 0x80001000, 0x55) != 0) ||
272         (WriteReg(sc, 0x80101000, 0x66) != 0) ||
273         (WriteReg(sc, 0x80201000, 0x77) != 0) ||
274         (WriteReg(sc, 0x80301000, 0x88) != 0))
275         return 8;
276
277     if ((ReadReg(sc, 0x80001000) != 0x55) ||
278         (ReadReg(sc, 0x80101000) != 0x66) ||
279         (ReadReg(sc, 0x80201000) != 0x77) ||
280         (ReadReg(sc, 0x80301000) != 0x88))
281         return 9;
282
283     return 0; /* found */
284 }
285
286 void
287 t1_disable_irq(iavc_softc_t *sc)
288 {
289     iavc_write_port(sc, T1_IRQMASTER, 0x00);
290 }
291
292 void
293 t1_reset(iavc_softc_t *sc)
294 {
295     b1_reset(sc);
296     iavc_write_port(sc, B1_INSTAT, 0x00);
297     iavc_write_port(sc, B1_OUTSTAT, 0x00);
298     iavc_write_port(sc, T1_IRQMASTER, 0x00);
299     iavc_write_port(sc, T1_RESETBOARD, 0x0f);
300 }