Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / net / i4b / layer1 / isic / i4b_diva.c
1 /*
2  *   Copyright (c) 2001 Hellmuth Michaelis. 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  *---------------------------------------------------------------------------
26  *
27  *      Eicon Diehl DIVA 2.0 or 2.02 (ISA PnP) support for isic driver
28  *      --------------------------------------------------------------
29  *
30  * $FreeBSD: src/sys/i4b/layer1/isic/i4b_diva.c,v 1.1.2.1 2001/08/10 14:08:38 obrien Exp $
31  *
32  *      last edit-date: [Fri Jan 26 13:57:10 2001]
33  *
34  *---------------------------------------------------------------------------*/
35
36 #include "isic.h"
37 #include "opt_i4b.h"
38
39 #if NISIC > 0 && defined EICON_DIVA
40
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/socket.h>
44
45 #include <net/if.h>
46
47 #include <machine/i4b_ioctl.h>
48
49 #include <i4b/layer1/isic/i4b_isic.h>
50 #include <i4b/layer1/isic/i4b_ipac.h>
51 #include <i4b/layer1/isic/i4b_isic.h>
52 #include <i4b/layer1/isic/i4b_hscx.h>
53
54 /* offsets from base address */
55
56 #define DIVA_IPAC_OFF_ALE       0x00
57 #define DIVA_IPAC_OFF_RW        0x01
58
59 #define DIVA_ISAC_OFF_RW        0x02
60 #define DIVA_ISAC_OFF_ALE       0x06
61
62 #define DIVA_HSCX_OFF_RW        0x00
63 #define DIVA_HSCX_OFF_ALE       0x04
64
65 #define DIVA_CTRL_OFF           0x07
66 #define         DIVA_CTRL_RDIST 0x01
67 #define         DIVA_CTRL_WRRST 0x08
68 #define         DIVA_CTRL_WRLDA 0x20
69 #define         DIVA_CTRL_WRLDB 0x40
70 #define         DIVA_CTRL_WRICL 0x80
71
72 /* HSCX channel base offsets */
73
74 #define DIVA_HSCXA              0x00
75 #define DIVA_HSCXB              0x40
76
77 /*---------------------------------------------------------------------------*
78  *      Eicon Diehl DIVA 2.02
79  *---------------------------------------------------------------------------*/
80 static void 
81 diva_ipac_read_fifo(struct l1_softc *sc,int what,void *buf,size_t size)
82 {
83         bus_space_tag_t    t = rman_get_bustag(sc->sc_resources.io_base[0]);
84         bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[0]);
85
86         switch ( what )
87         {
88                 case ISIC_WHAT_ISAC:
89                         bus_space_write_1(t,h,DIVA_IPAC_OFF_ALE,IPAC_ISAC_OFF);
90                         bus_space_read_multi_1(t,h,DIVA_IPAC_OFF_RW,buf,size);
91                         break;
92                 case ISIC_WHAT_HSCXA:
93                         bus_space_write_1(t,h,DIVA_IPAC_OFF_ALE,IPAC_HSCXA_OFF);
94                         bus_space_read_multi_1(t,h,DIVA_IPAC_OFF_RW,buf,size);
95                         break;
96                 case ISIC_WHAT_HSCXB:
97                         bus_space_write_1(t,h,DIVA_IPAC_OFF_ALE,IPAC_HSCXB_OFF);
98                         bus_space_read_multi_1(t,h,DIVA_IPAC_OFF_RW,buf,size);
99                         break;
100         }
101 }
102
103 /*---------------------------------------------------------------------------*
104  *      Eicon Diehl DIVA 2.02
105  *---------------------------------------------------------------------------*/
106 static void 
107 diva_ipac_write_fifo(struct l1_softc *sc,int what,void *buf,size_t size)
108 {
109         bus_space_tag_t    t = rman_get_bustag(sc->sc_resources.io_base[0]);
110         bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[0]);
111
112         switch ( what )
113         {
114                 case ISIC_WHAT_ISAC:
115                         bus_space_write_1(t,h,DIVA_IPAC_OFF_ALE,IPAC_ISAC_OFF);
116                         bus_space_write_multi_1(t,h,DIVA_IPAC_OFF_RW,buf,size);
117                         break;
118                 case ISIC_WHAT_HSCXA:
119                         bus_space_write_1(t,h,DIVA_IPAC_OFF_ALE,IPAC_HSCXA_OFF);
120                         bus_space_write_multi_1(t,h,DIVA_IPAC_OFF_RW,buf,size);
121                         break;
122                 case ISIC_WHAT_HSCXB:
123                         bus_space_write_1(t,h,DIVA_IPAC_OFF_ALE,IPAC_HSCXB_OFF);
124                         bus_space_write_multi_1(t,h,DIVA_IPAC_OFF_RW,buf,size);
125                         break;
126         }
127 }
128
129 /*---------------------------------------------------------------------------*
130  *      Eicon Diehl DIVA 2.02
131  *---------------------------------------------------------------------------*/
132 static void
133 diva_ipac_write_reg(struct l1_softc *sc,int what,bus_size_t reg,u_int8_t data)
134 {
135         bus_space_tag_t    t = rman_get_bustag(sc->sc_resources.io_base[0]);
136         bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[0]);
137
138         switch ( what )
139         {
140                 case ISIC_WHAT_ISAC:
141                         bus_space_write_1(t,h,DIVA_IPAC_OFF_ALE,reg+IPAC_ISAC_OFF);
142                         bus_space_write_1(t,h,DIVA_IPAC_OFF_RW,data);
143                         break;
144                 case ISIC_WHAT_HSCXA:
145                         bus_space_write_1(t,h,DIVA_IPAC_OFF_ALE,reg+IPAC_HSCXA_OFF);
146                         bus_space_write_1(t,h,DIVA_IPAC_OFF_RW,data);
147                         break;
148                 case ISIC_WHAT_HSCXB:
149                         bus_space_write_1(t,h,DIVA_IPAC_OFF_ALE,reg+IPAC_HSCXB_OFF);
150                         bus_space_write_1(t,h,DIVA_IPAC_OFF_RW,data);
151                         break;
152                 case ISIC_WHAT_IPAC:
153                         bus_space_write_1(t,h,DIVA_IPAC_OFF_ALE,reg+IPAC_IPAC_OFF);
154                         bus_space_write_1(t,h,DIVA_IPAC_OFF_RW,data);
155                         break;
156         }
157 }
158
159 /*---------------------------------------------------------------------------*
160  *      Eicon Diehl DIVA 2.02
161  *---------------------------------------------------------------------------*/
162 static u_int8_t
163 diva_ipac_read_reg(struct l1_softc *sc,int what,bus_size_t reg)
164 {
165         bus_space_tag_t    t = rman_get_bustag(sc->sc_resources.io_base[0]);
166         bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[0]);
167
168         switch ( what )
169         {
170                 case ISIC_WHAT_ISAC:
171                         bus_space_write_1(t,h,DIVA_IPAC_OFF_ALE,reg+IPAC_ISAC_OFF);
172                         return bus_space_read_1(t,h,DIVA_IPAC_OFF_RW);
173                 case ISIC_WHAT_HSCXA:
174                         bus_space_write_1(t,h,DIVA_IPAC_OFF_ALE,reg+IPAC_HSCXA_OFF);
175                         return bus_space_read_1(t,h,DIVA_IPAC_OFF_RW);
176                 case ISIC_WHAT_HSCXB:
177                         bus_space_write_1(t,h,DIVA_IPAC_OFF_ALE,reg+IPAC_HSCXB_OFF);
178                         return bus_space_read_1(t,h,DIVA_IPAC_OFF_RW);
179                 case ISIC_WHAT_IPAC:
180                         bus_space_write_1(t,h,DIVA_IPAC_OFF_ALE,reg+IPAC_IPAC_OFF);
181                         return bus_space_read_1(t,h,DIVA_IPAC_OFF_RW);
182                 default:
183                         return 0;
184         }
185 }
186
187 /*---------------------------------------------------------------------------*
188  *      Eicon Diehl DIVA 2.02
189  *---------------------------------------------------------------------------*/
190 int
191 isic_attach_diva_ipac(device_t dev)
192 {
193         int unit = device_get_unit(dev);
194         struct l1_softc *sc = &l1_sc[unit];     
195         
196         /* setup access routines */
197
198         sc->clearirq = NULL;
199         sc->readreg = diva_ipac_read_reg;
200         sc->writereg = diva_ipac_write_reg;
201
202         sc->readfifo = diva_ipac_read_fifo;
203         sc->writefifo = diva_ipac_write_fifo;
204
205         /* setup card type */
206         
207         sc->sc_cardtyp = CARD_TYPEP_DIVA_ISA;
208
209         /* setup IOM bus type */
210         
211         sc->sc_bustyp = BUS_TYPE_IOM2;
212
213         /* setup chip type = IPAC */
214         
215         sc->sc_ipac = 1;
216         sc->sc_bfifolen = IPAC_BFIFO_LEN;
217
218         /* enable hscx/isac irq's */
219
220         IPAC_WRITE(IPAC_MASK, (IPAC_MASK_INT1 | IPAC_MASK_INT0));
221
222         IPAC_WRITE(IPAC_ACFG, 0);       /* outputs are open drain */
223
224         IPAC_WRITE(IPAC_AOE,            /* aux 5..2 are inputs, 7, 6 outputs */
225                 (IPAC_AOE_OE5 | IPAC_AOE_OE4 | IPAC_AOE_OE3 | IPAC_AOE_OE2));
226
227         IPAC_WRITE(IPAC_ATX, 0xff);     /* set all output lines high */
228
229         return(0);
230 }
231
232 /*---------------------------------------------------------------------------*
233  *      Eicon Diehl DIVA 2.0
234  *---------------------------------------------------------------------------*/
235 static void 
236 diva_read_fifo(struct l1_softc *sc,int what,void *buf,size_t size)
237 {
238         bus_space_tag_t    t = rman_get_bustag(sc->sc_resources.io_base[0]);
239         bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[0]);
240
241         switch(what)
242         {
243                 case ISIC_WHAT_ISAC:
244                         bus_space_write_1(t,h,DIVA_ISAC_OFF_ALE,0);
245                         bus_space_read_multi_1(t,h,DIVA_ISAC_OFF_RW,buf,size);
246                         break;
247
248                 case ISIC_WHAT_HSCXA:
249                         bus_space_write_1(t,h,DIVA_HSCX_OFF_ALE,DIVA_HSCXA);
250                         bus_space_read_multi_1(t,h,DIVA_HSCX_OFF_RW,buf,size);
251                         break;
252
253                 case ISIC_WHAT_HSCXB:
254                         bus_space_write_1(t,h,DIVA_HSCX_OFF_ALE,DIVA_HSCXB);
255                         bus_space_read_multi_1(t,h,DIVA_HSCX_OFF_RW,buf,size);
256                         break;
257         }
258 }
259
260 /*---------------------------------------------------------------------------*
261  *      Eicon Diehl DIVA 2.0
262  *---------------------------------------------------------------------------*/
263 static void 
264 diva_write_fifo(struct l1_softc *sc,int what,void *buf,size_t size)
265 {
266         bus_space_tag_t    t = rman_get_bustag(sc->sc_resources.io_base[0]);
267         bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[0]);
268
269         switch(what)
270         {
271                 case ISIC_WHAT_ISAC:
272                         bus_space_write_1(t,h,DIVA_ISAC_OFF_ALE,0);
273                         bus_space_write_multi_1(t,h,DIVA_ISAC_OFF_RW,buf,size);
274                         break;
275
276                 case ISIC_WHAT_HSCXA:
277                         bus_space_write_1(t,h,DIVA_HSCX_OFF_ALE,DIVA_HSCXA);
278                         bus_space_write_multi_1(t,h,DIVA_HSCX_OFF_RW,buf,size);
279                         break;
280
281                 case ISIC_WHAT_HSCXB:
282                         bus_space_write_1(t,h,DIVA_HSCX_OFF_ALE,DIVA_HSCXB);
283                         bus_space_write_multi_1(t,h,DIVA_HSCX_OFF_RW,buf,size);
284                         break;
285         }
286 }
287
288 /*---------------------------------------------------------------------------*
289  *      Eicon Diehl DIVA 2.0
290  *---------------------------------------------------------------------------*/
291 static void
292 diva_write_reg(struct l1_softc *sc,int what,bus_size_t reg,u_int8_t data)
293 {
294         bus_space_tag_t    t = rman_get_bustag(sc->sc_resources.io_base[0]);
295         bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[0]);
296
297         switch(what)
298         {
299                 case ISIC_WHAT_ISAC:
300                         bus_space_write_1(t,h,DIVA_ISAC_OFF_ALE,reg);
301                         bus_space_write_1(t,h,DIVA_ISAC_OFF_RW,data);
302                         break;
303
304                 case ISIC_WHAT_HSCXA:
305                         bus_space_write_1(t,h,DIVA_HSCX_OFF_ALE,reg+DIVA_HSCXA);
306                         bus_space_write_1(t,h,DIVA_HSCX_OFF_RW,data);
307                         break;
308
309                 case ISIC_WHAT_HSCXB:
310                         bus_space_write_1(t,h,DIVA_HSCX_OFF_ALE,reg+DIVA_HSCXB);
311                         bus_space_write_1(t,h,DIVA_HSCX_OFF_RW,data);
312                         break;
313         }
314 }
315
316 /*---------------------------------------------------------------------------*
317  *      Eicon Diehl DIVA 2.0
318  *---------------------------------------------------------------------------*/
319 static u_int8_t
320 diva_read_reg(struct l1_softc *sc,int what,bus_size_t reg)
321 {
322         bus_space_tag_t    t = rman_get_bustag(sc->sc_resources.io_base[0]);
323         bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[0]);
324
325         switch(what)
326         {
327                 case ISIC_WHAT_ISAC:
328                         bus_space_write_1(t,h,DIVA_ISAC_OFF_ALE,reg);
329                         return bus_space_read_1(t,h,DIVA_ISAC_OFF_RW);
330
331                 case ISIC_WHAT_HSCXA:
332                         bus_space_write_1(t,h,DIVA_HSCX_OFF_ALE,reg+DIVA_HSCXA);
333                         return bus_space_read_1(t,h,DIVA_HSCX_OFF_RW);
334
335                 case ISIC_WHAT_HSCXB:
336                         bus_space_write_1(t,h,DIVA_HSCX_OFF_ALE,reg+DIVA_HSCXB);
337                         return bus_space_read_1(t,h,DIVA_HSCX_OFF_RW);
338
339                 default:
340                         return 0;
341         }
342 }
343
344 /*---------------------------------------------------------------------------*
345  *      Eicon Diehl DIVA 2.0
346  *---------------------------------------------------------------------------*/
347 int
348 isic_attach_diva(device_t dev)
349 {
350         int unit = device_get_unit(dev);
351         struct l1_softc *sc = &l1_sc[unit];     
352         bus_space_tag_t    t = rman_get_bustag(sc->sc_resources.io_base[0]);
353         bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[0]);
354         
355         /* setup access routines */
356
357         sc->clearirq = NULL;
358         sc->readreg = diva_read_reg;
359         sc->writereg = diva_write_reg;
360
361         sc->readfifo = diva_read_fifo;
362         sc->writefifo = diva_write_fifo;
363
364         /* setup card type */
365         
366         sc->sc_cardtyp = CARD_TYPEP_DIVA_ISA;
367
368         /* setup IOM bus type */
369         
370         sc->sc_bustyp = BUS_TYPE_IOM2;
371
372         /* setup chip type = ISAC/HSCX */
373
374         sc->sc_ipac = 0;
375         sc->sc_bfifolen = HSCX_FIFO_LEN;
376
377         /* Read HSCX A/B VSTR.  Expected value is 0x05 (V2.1). */
378
379         if( ((HSCX_READ(0, H_VSTR) & 0xf) != 0x5) || 
380             ((HSCX_READ(1, H_VSTR) & 0xf) != 0x5) )
381         {
382                 printf("isic%d: HSCX VSTR test failed for Eicon DIVA 2.0\n",
383                         sc->sc_unit);
384                 printf("isic%d: HSC0: VSTR: %#x\n",
385                         sc->sc_unit, HSCX_READ(0, H_VSTR));
386                 printf("isic%d: HSC1: VSTR: %#x\n",
387                         sc->sc_unit, HSCX_READ(1, H_VSTR));
388                 return ENXIO;
389         }
390         /* reset on */
391         bus_space_write_1(t,h,DIVA_CTRL_OFF,0);
392         DELAY(100);
393         /* reset off */
394         bus_space_write_1(t,h,DIVA_CTRL_OFF,DIVA_CTRL_WRRST);
395         return(0);
396 }
397
398 #endif /* NISIC > 0 && defined EICON_DIVA */