1 /* $NetBSD: isic_pci_elsa_qs1p.c,v 1.11 2003/05/08 21:18:42 martin Exp $ */
2
3 /*
4 * Copyright (c) 1997, 1999 Hellmuth Michaelis. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *---------------------------------------------------------------------------
28 *
29 * isic - I4B Siemens ISDN Chipset Driver for ELSA Quickstep 1000pro PCI
30 * =====================================================================
31 *
32 *---------------------------------------------------------------------------*/
33
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: isic_pci_elsa_qs1p.c,v 1.11 2003/05/08 21:18:42 martin Exp $");
36
37 #include <sys/param.h>
38 #include <sys/kernel.h>
39 #include <sys/systm.h>
40 #include <sys/mbuf.h>
41 #include <sys/socket.h>
42 #include <net/if.h>
43 #include <sys/callout.h>
44
45 #include <machine/bus.h>
46 #include <sys/device.h>
47
48 #include <dev/pci/pcireg.h>
49 #include <dev/pci/pcivar.h>
50 #include <dev/pci/pcidevs.h>
51
52 #include <netisdn/i4b_debug.h>
53 #include <netisdn/i4b_ioctl.h>
54 #include <netisdn/i4b_global.h>
55 #include <netisdn/i4b_debug.h>
56 #include <netisdn/i4b_l2.h>
57 #include <netisdn/i4b_l1l2.h>
58 #include <netisdn/i4b_mbuf.h>
59
60 #include <dev/ic/isic_l1.h>
61 #include <dev/ic/isac.h>
62 #include <dev/ic/hscx.h>
63 #include <dev/ic/ipac.h>
64 #include <dev/pci/isic_pci.h>
65
66 /* masks for register encoded in base addr */
67
68 #define ELSA_BASE_MASK 0x0ffff
69 #define ELSA_OFF_MASK 0xf0000
70
71 /* register id's to be encoded in base addr */
72
73 #define ELSA_IDISAC 0x00000
74 #define ELSA_IDHSCXA 0x10000
75 #define ELSA_IDHSCXB 0x20000
76 #define ELSA_IDIPAC 0x40000
77
78 /* offsets from base address */
79
80 #define ELSA_OFF_ALE 0x00
81 #define ELSA_OFF_RW 0x01
82
83 /* LED values */
84 #define ELSA_NO_LED 0xff
85 #define ELSA_GREEN_LED 0x40
86 #define ELSA_YELLOW_LED 0x80
87
88 #define ELSA_PORT0_MEM_MAPOFF PCI_MAPREG_START
89 #define ELSA_PORT0_IO_MAPOFF PCI_MAPREG_START+4
90 #define ELSA_PORT1_MAPOFF PCI_MAPREG_START+12
91
92
93 static void elsa_cmd_req(struct isic_softc *sc, int cmd, void *data);
94 static void elsa_led_handler(void *token);
95
96 /*---------------------------------------------------------------------------*
97 * ELSA QuickStep 1000pro/PCI ISAC get fifo routine
98 *---------------------------------------------------------------------------*/
99
100 static void
101 eqs1pp_read_fifo(struct isic_softc *sc, int what, void *buf, size_t size)
102 {
103 bus_space_tag_t t = sc->sc_maps[1].t;
104 bus_space_handle_t h = sc->sc_maps[1].h;
105 switch (what) {
106 case ISIC_WHAT_ISAC:
107 bus_space_write_1(t, h, ELSA_OFF_ALE, IPAC_ISAC_OFF);
108 bus_space_read_multi_1(t, h, ELSA_OFF_RW, buf, size);
109 break;
110 case ISIC_WHAT_HSCXA:
111 bus_space_write_1(t, h, ELSA_OFF_ALE, IPAC_HSCXA_OFF);
112 bus_space_read_multi_1(t, h, ELSA_OFF_RW, buf, size);
113 break;
114 case ISIC_WHAT_HSCXB:
115 bus_space_write_1(t, h, ELSA_OFF_ALE, IPAC_HSCXB_OFF);
116 bus_space_read_multi_1(t, h, ELSA_OFF_RW, buf, size);
117 break;
118 }
119 }
120
121 /*---------------------------------------------------------------------------*
122 * ELSA QuickStep 1000pro/PCI ISAC put fifo routine
123 *---------------------------------------------------------------------------*/
124
125 static void
126 eqs1pp_write_fifo(struct isic_softc *sc, int what, const void *buf, size_t size)
127 {
128 bus_space_tag_t t = sc->sc_maps[1].t;
129 bus_space_handle_t h = sc->sc_maps[1].h;
130 switch (what) {
131 case ISIC_WHAT_ISAC:
132 bus_space_write_1(t, h, ELSA_OFF_ALE, IPAC_ISAC_OFF);
133 bus_space_write_multi_1(t, h, ELSA_OFF_RW, (u_int8_t*)buf, size);
134 break;
135 case ISIC_WHAT_HSCXA:
136 bus_space_write_1(t, h, ELSA_OFF_ALE, IPAC_HSCXA_OFF);
137 bus_space_write_multi_1(t, h, ELSA_OFF_RW, (u_int8_t*)buf, size);
138 break;
139 case ISIC_WHAT_HSCXB:
140 bus_space_write_1(t, h, ELSA_OFF_ALE, IPAC_HSCXB_OFF);
141 bus_space_write_multi_1(t, h, ELSA_OFF_RW, (u_int8_t*)buf, size);
142 break;
143 }
144 }
145
146 /*---------------------------------------------------------------------------*
147 * ELSA QuickStep 1000pro/PCI ISAC put register routine
148 *---------------------------------------------------------------------------*/
149
150 static void
151 eqs1pp_write_reg(struct isic_softc *sc, int what, bus_size_t offs, u_int8_t data)
152 {
153 bus_space_tag_t t = sc->sc_maps[1].t;
154 bus_space_handle_t h = sc->sc_maps[1].h;
155 switch (what) {
156 case ISIC_WHAT_ISAC:
157 bus_space_write_1(t, h, ELSA_OFF_ALE, IPAC_ISAC_OFF+offs);
158 bus_space_write_1(t, h, ELSA_OFF_RW, data);
159 break;
160 case ISIC_WHAT_HSCXA:
161 bus_space_write_1(t, h, ELSA_OFF_ALE, IPAC_HSCXA_OFF+offs);
162 bus_space_write_1(t, h, ELSA_OFF_RW, data);
163 break;
164 case ISIC_WHAT_HSCXB:
165 bus_space_write_1(t, h, ELSA_OFF_ALE, IPAC_HSCXB_OFF+offs);
166 bus_space_write_1(t, h, ELSA_OFF_RW, data);
167 break;
168 case ISIC_WHAT_IPAC:
169 bus_space_write_1(t, h, ELSA_OFF_ALE, IPAC_IPAC_OFF+offs);
170 bus_space_write_1(t, h, ELSA_OFF_RW, data);
171 break;
172 }
173 }
174
175 /*---------------------------------------------------------------------------*
176 * ELSA QuickStep 1000pro/PCI ISAC get register routine
177 *---------------------------------------------------------------------------*/
178
179 static u_int8_t
180 eqs1pp_read_reg(struct isic_softc *sc, int what, bus_size_t offs)
181 {
182 bus_space_tag_t t = sc->sc_maps[1].t;
183 bus_space_handle_t h = sc->sc_maps[1].h;
184 switch (what) {
185 case ISIC_WHAT_ISAC:
186 bus_space_write_1(t, h, ELSA_OFF_ALE, IPAC_ISAC_OFF+offs);
187 return bus_space_read_1(t, h, ELSA_OFF_RW);
188 case ISIC_WHAT_HSCXA:
189 bus_space_write_1(t, h, ELSA_OFF_ALE, IPAC_HSCXA_OFF+offs);
190 return bus_space_read_1(t, h, ELSA_OFF_RW);
191 case ISIC_WHAT_HSCXB:
192 bus_space_write_1(t, h, ELSA_OFF_ALE, IPAC_HSCXB_OFF+offs);
193 return bus_space_read_1(t, h, ELSA_OFF_RW);
194 case ISIC_WHAT_IPAC:
195 {
196 bus_space_write_1(t, h, ELSA_OFF_ALE, IPAC_IPAC_OFF+offs);
197 return bus_space_read_1(t, h, ELSA_OFF_RW);
198 }
199 }
200
201 return 0;
202 }
203
204 /*---------------------------------------------------------------------------*
205 * isic_attach_Eqs1pp - attach for ELSA QuickStep 1000pro/PCI
206 *---------------------------------------------------------------------------*/
207
208 void
209 isic_attach_Eqs1pp(psc, pa)
210 struct pci_isic_softc *psc;
211 struct pci_attach_args *pa;
212 {
213 struct isic_softc *sc = &psc->sc_isic;
214
215 /* setup io mappings */
216 sc->sc_num_mappings = 2;
217 MALLOC_MAPS(sc);
218 sc->sc_maps[0].size = 0;
219 if (pci_mapreg_map(pa, ELSA_PORT0_MEM_MAPOFF, PCI_MAPREG_TYPE_MEM, 0,
220 &sc->sc_maps[0].t, &sc->sc_maps[0].h, &psc->sc_base, &psc->sc_size) != 0
221 && pci_mapreg_map(pa, ELSA_PORT0_IO_MAPOFF, PCI_MAPREG_TYPE_IO, 0,
222 &sc->sc_maps[0].t, &sc->sc_maps[0].h, &psc->sc_base, &psc->sc_size) != 0) {
223 printf("%s: can't map card registers\n", sc->sc_dev.dv_xname);
224 return;
225 }
226
227 /* PLX9050 Errata #1 */
228 if (PCI_REVISION(pa->pa_class) == 1 && psc->sc_base & 0x00000080) {
229 #ifdef DEBUG
230 printf("%s: no LCR access\n", sc->sc_dev.dv_xname);
231 #endif
232 } else
233 psc->flags |= PCIISIC_LCROK;
234
235 sc->sc_maps[1].size = 0;
236 if (pci_mapreg_map(pa, ELSA_PORT1_MAPOFF, PCI_MAPREG_TYPE_IO, 0,
237 &sc->sc_maps[1].t, &sc->sc_maps[1].h, NULL, NULL)) {
238 printf("%s: can't map i/o space\n", sc->sc_dev.dv_xname);
239 return;
240 }
241
242 /* setup access routines */
243
244 sc->clearirq = NULL;
245 sc->readreg = eqs1pp_read_reg;
246 sc->writereg = eqs1pp_write_reg;
247
248 sc->readfifo = eqs1pp_read_fifo;
249 sc->writefifo = eqs1pp_write_fifo;
250
251 sc->drv_command = elsa_cmd_req;
252
253 /* setup card type */
254
255 sc->sc_cardtyp = CARD_TYPEP_ELSAQS1PCI;
256
257 /* setup IOM bus type */
258
259 sc->sc_bustyp = BUS_TYPE_IOM2;
260
261 /* setup chip type = IPAC ! */
262
263 sc->sc_ipac = 1;
264 sc->sc_bfifolen = IPAC_BFIFO_LEN;
265
266 IPAC_WRITE(IPAC_ACFG, 0); /* outputs are open drain */
267 IPAC_WRITE(IPAC_AOE, /* aux 5..2 are inputs, 7, 6 outputs */
268 (IPAC_AOE_OE5 | IPAC_AOE_OE4 | IPAC_AOE_OE3 | IPAC_AOE_OE2));
269 IPAC_WRITE(IPAC_ATX, ELSA_NO_LED); /* set all output lines high */
270 callout_init(&((struct pci_isic_softc *)sc)->ledcallout);
271
272 /* disable any interrupts */
273 IPAC_WRITE(IPAC_MASK, 0xff);
274 bus_space_write_1(sc->sc_maps[0].t, sc->sc_maps[0].h, 0x4c, 0x01);
275 }
276
277 int
278 isic_intr_qs1p(vsc)
279 void *vsc;
280 {
281 struct pci_isic_softc *psc = vsc;
282 struct isic_softc *sc = &psc->sc_isic;
283 u_int32_t intcsr;
284
285 /*
286 * if we are not hit by the PLX bug we can try a shortcut
287 * (should improve speed for shared IRQs)
288 */
289 if (psc->flags & PCIISIC_LCROK) {
290 intcsr = bus_space_read_4(sc->sc_maps[0].t, sc->sc_maps[0].h,
291 0x4c /* INTCSR */);
292 if (!(intcsr & 0x4 /* LINTi1STAT */))
293 return (0);
294 }
295
296 return (isicintr(sc));
297 }
298
299 static void
300 elsa_cmd_req(struct isic_softc *sc, int cmd, void *data)
301 {
302 intptr_t v;
303 int s;
304 struct pci_isic_softc *psc = (struct pci_isic_softc *)sc;
305
306 switch (cmd) {
307 case CMR_DOPEN:
308 s = splnet();
309 /* enable hscx/isac irq's */
310 IPAC_WRITE(IPAC_MASK, (IPAC_MASK_INT1 | IPAC_MASK_INT0));
311 /* enable card interrupt */
312 bus_space_write_1(sc->sc_maps[0].t, sc->sc_maps[0].h, 0x4c, 0x41);
313 splx(s);
314 break;
315 case CMR_DCLOSE:
316 s = splnet();
317 callout_stop(&psc->ledcallout);
318 IPAC_WRITE(IPAC_ATX, ELSA_NO_LED);
319 IPAC_WRITE(IPAC_MASK, 0xff);
320 bus_space_write_1(sc->sc_maps[0].t, sc->sc_maps[0].h, 0x4c, 0x01);
321 splx(s);
322 break;
323 case CMR_SETLEDS:
324 v = (intptr_t)data;
325 callout_stop(&psc->ledcallout);
326
327 /* the magic value and keep reset off */
328 psc->ledstat = ELSA_NO_LED;
329 psc->ledblinkmask = 0;
330 psc->ledblinkfreq = 0;
331
332 /* now see what LEDs we want to add */
333 if (v & CMRLEDS_TEI)
334 psc->ledstat &= ~ELSA_GREEN_LED;
335
336 if (v & (CMRLEDS_B0|CMRLEDS_B1)) {
337 psc->ledstat &= ~ELSA_YELLOW_LED;
338 psc->ledblinkmask |= ELSA_YELLOW_LED;
339 if ((v & (CMRLEDS_B0|CMRLEDS_B1))
340 == (CMRLEDS_B0|CMRLEDS_B1))
341 psc->ledblinkfreq = hz/4;
342 else
343 psc->ledblinkfreq = hz;
344 }
345
346 elsa_led_handler(psc);
347 break;
348 }
349 }
350
351 static void
352 elsa_led_handler(void *token)
353 {
354 struct pci_isic_softc *psc = token;
355 struct isic_softc *sc = token; /* XXX */
356 int s;
357
358 s = splnet();
359 IPAC_WRITE(IPAC_ATX, psc->ledstat);
360 splx(s);
361 if (psc->ledblinkfreq) {
362 psc->ledstat ^= psc->ledblinkmask;
363 callout_reset(&psc->ledcallout, psc->ledblinkfreq,
364 elsa_led_handler, psc);
365 }
366 }
Cache object: f1ff367a3b793d4486a95419b8d875ca
|