1 /* $NetBSD: isic_pci_elsa_qs1p.c,v 1.18 2008/04/10 19:13:37 cegger Exp $ */
4 * Copyright (c) 1997, 1999 Hellmuth Michaelis. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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
27 *---------------------------------------------------------------------------
29 * isic - I4B Siemens ISDN Chipset Driver for ELSA Quickstep 1000pro PCI
30 * =====================================================================
32 *---------------------------------------------------------------------------*/
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: isic_pci_elsa_qs1p.c,v 1.18 2008/04/10 19:13:37 cegger Exp $");
37 #include <sys/param.h>
38 #include <sys/kernel.h>
39 #include <sys/systm.h>
41 #include <sys/socket.h>
43 #include <sys/callout.h>
46 #include <sys/device.h>
48 #include <dev/pci/pcireg.h>
49 #include <dev/pci/pcivar.h>
50 #include <dev/pci/pcidevs.h>
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>
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>
66 /* masks for register encoded in base addr */
68 #define ELSA_BASE_MASK 0x0ffff
69 #define ELSA_OFF_MASK 0xf0000
71 /* register id's to be encoded in base addr */
73 #define ELSA_IDISAC 0x00000
74 #define ELSA_IDHSCXA 0x10000
75 #define ELSA_IDHSCXB 0x20000
76 #define ELSA_IDIPAC 0x40000
78 /* offsets from base address */
80 #define ELSA_OFF_ALE 0x00
81 #define ELSA_OFF_RW 0x01
84 #define ELSA_NO_LED 0xff
85 #define ELSA_GREEN_LED 0x40
86 #define ELSA_YELLOW_LED 0x80
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
93 static void elsa_cmd_req(struct isic_softc
*sc
, int cmd
, void *data
);
94 static void elsa_led_handler(void *token
);
96 /*---------------------------------------------------------------------------*
97 * ELSA QuickStep 1000pro/PCI ISAC get fifo routine
98 *---------------------------------------------------------------------------*/
101 eqs1pp_read_fifo(struct isic_softc
*sc
, int what
, void *buf
, size_t size
)
103 bus_space_tag_t t
= sc
->sc_maps
[1].t
;
104 bus_space_handle_t h
= sc
->sc_maps
[1].h
;
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
);
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
);
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
);
121 /*---------------------------------------------------------------------------*
122 * ELSA QuickStep 1000pro/PCI ISAC put fifo routine
123 *---------------------------------------------------------------------------*/
126 eqs1pp_write_fifo(struct isic_softc
*sc
, int what
, const void *buf
, size_t size
)
128 bus_space_tag_t t
= sc
->sc_maps
[1].t
;
129 bus_space_handle_t h
= sc
->sc_maps
[1].h
;
132 bus_space_write_1(t
, h
, ELSA_OFF_ALE
, IPAC_ISAC_OFF
);
133 bus_space_write_multi_1(t
, h
, ELSA_OFF_RW
, buf
, size
);
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
, buf
, size
);
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
, buf
, size
);
146 /*---------------------------------------------------------------------------*
147 * ELSA QuickStep 1000pro/PCI ISAC put register routine
148 *---------------------------------------------------------------------------*/
151 eqs1pp_write_reg(struct isic_softc
*sc
, int what
, bus_size_t offs
, u_int8_t data
)
153 bus_space_tag_t t
= sc
->sc_maps
[1].t
;
154 bus_space_handle_t h
= sc
->sc_maps
[1].h
;
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
);
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
);
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
);
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
);
175 /*---------------------------------------------------------------------------*
176 * ELSA QuickStep 1000pro/PCI ISAC get register routine
177 *---------------------------------------------------------------------------*/
180 eqs1pp_read_reg(struct isic_softc
*sc
, int what
, bus_size_t offs
)
182 bus_space_tag_t t
= sc
->sc_maps
[1].t
;
183 bus_space_handle_t h
= sc
->sc_maps
[1].h
;
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
);
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
);
204 /*---------------------------------------------------------------------------*
205 * isic_attach_Eqs1pp - attach for ELSA QuickStep 1000pro/PCI
206 *---------------------------------------------------------------------------*/
209 isic_attach_Eqs1pp(struct pci_isic_softc
*psc
, struct pci_attach_args
*pa
)
211 struct isic_softc
*sc
= &psc
->sc_isic
;
213 /* setup io mappings */
214 sc
->sc_num_mappings
= 2;
216 sc
->sc_maps
[0].size
= 0;
217 if (pci_mapreg_map(pa
, ELSA_PORT0_MEM_MAPOFF
, PCI_MAPREG_TYPE_MEM
, 0,
218 &sc
->sc_maps
[0].t
, &sc
->sc_maps
[0].h
, &psc
->sc_base
, &psc
->sc_size
) != 0
219 && pci_mapreg_map(pa
, ELSA_PORT0_IO_MAPOFF
, PCI_MAPREG_TYPE_IO
, 0,
220 &sc
->sc_maps
[0].t
, &sc
->sc_maps
[0].h
, &psc
->sc_base
, &psc
->sc_size
) != 0) {
221 aprint_error_dev(&sc
->sc_dev
, "can't map card registers\n");
225 /* PLX9050 Errata #1 */
226 if (PCI_REVISION(pa
->pa_class
) == 1 && psc
->sc_base
& 0x00000080) {
228 printf("%s: no LCR access\n", device_xname(&sc
->sc_dev
));
231 psc
->flags
|= PCIISIC_LCROK
;
233 sc
->sc_maps
[1].size
= 0;
234 if (pci_mapreg_map(pa
, ELSA_PORT1_MAPOFF
, PCI_MAPREG_TYPE_IO
, 0,
235 &sc
->sc_maps
[1].t
, &sc
->sc_maps
[1].h
, NULL
, NULL
)) {
236 aprint_error_dev(&sc
->sc_dev
, "can't map i/o space\n");
240 /* setup access routines */
243 sc
->readreg
= eqs1pp_read_reg
;
244 sc
->writereg
= eqs1pp_write_reg
;
246 sc
->readfifo
= eqs1pp_read_fifo
;
247 sc
->writefifo
= eqs1pp_write_fifo
;
249 sc
->drv_command
= elsa_cmd_req
;
251 /* setup card type */
253 sc
->sc_cardtyp
= CARD_TYPEP_ELSAQS1PCI
;
255 /* setup IOM bus type */
257 sc
->sc_bustyp
= BUS_TYPE_IOM2
;
259 /* setup chip type = IPAC ! */
262 sc
->sc_bfifolen
= IPAC_BFIFO_LEN
;
264 IPAC_WRITE(IPAC_ACFG
, 0); /* outputs are open drain */
265 IPAC_WRITE(IPAC_AOE
, /* aux 5..2 are inputs, 7, 6 outputs */
266 (IPAC_AOE_OE5
| IPAC_AOE_OE4
| IPAC_AOE_OE3
| IPAC_AOE_OE2
));
267 IPAC_WRITE(IPAC_ATX
, ELSA_NO_LED
); /* set all output lines high */
268 callout_init(&((struct pci_isic_softc
*)sc
)->ledcallout
, 0);
270 /* disable any interrupts */
271 IPAC_WRITE(IPAC_MASK
, 0xff);
272 bus_space_write_1(sc
->sc_maps
[0].t
, sc
->sc_maps
[0].h
, 0x4c, 0x01);
278 isic_intr_qs1p(void *vsc
)
280 struct pci_isic_softc
*psc
= vsc
;
281 struct isic_softc
*sc
= &psc
->sc_isic
;
285 * if we are not hit by the PLX bug we can try a shortcut
286 * (should improve speed for shared IRQs)
288 if (psc
->flags
& PCIISIC_LCROK
) {
289 intcsr
= bus_space_read_4(sc
->sc_maps
[0].t
, sc
->sc_maps
[0].h
,
291 if (!(intcsr
& 0x4 /* LINTi1STAT */))
295 return (isicintr(sc
));
299 elsa_cmd_req(struct isic_softc
*sc
, int cmd
, void *data
)
303 struct pci_isic_softc
*psc
= (struct pci_isic_softc
*)sc
;
308 /* enable hscx/isac irq's */
309 IPAC_WRITE(IPAC_MASK
, (IPAC_MASK_INT1
| IPAC_MASK_INT0
));
310 /* enable card interrupt */
311 bus_space_write_1(sc
->sc_maps
[0].t
, sc
->sc_maps
[0].h
, 0x4c, 0x41);
316 callout_stop(&psc
->ledcallout
);
317 IPAC_WRITE(IPAC_ATX
, ELSA_NO_LED
);
318 IPAC_WRITE(IPAC_MASK
, 0xff);
319 bus_space_write_1(sc
->sc_maps
[0].t
, sc
->sc_maps
[0].h
, 0x4c, 0x01);
324 callout_stop(&psc
->ledcallout
);
326 /* the magic value and keep reset off */
327 psc
->ledstat
= ELSA_NO_LED
;
328 psc
->ledblinkmask
= 0;
329 psc
->ledblinkfreq
= 0;
331 /* now see what LEDs we want to add */
333 psc
->ledstat
&= ~ELSA_GREEN_LED
;
335 if (v
& (CMRLEDS_B0
|CMRLEDS_B1
)) {
336 psc
->ledstat
&= ~ELSA_YELLOW_LED
;
337 psc
->ledblinkmask
|= ELSA_YELLOW_LED
;
338 if ((v
& (CMRLEDS_B0
|CMRLEDS_B1
))
339 == (CMRLEDS_B0
|CMRLEDS_B1
))
340 psc
->ledblinkfreq
= hz
/4;
342 psc
->ledblinkfreq
= hz
;
345 elsa_led_handler(psc
);
351 elsa_led_handler(void *token
)
353 struct pci_isic_softc
*psc
= token
;
354 struct isic_softc
*sc
= token
; /* XXX */
358 IPAC_WRITE(IPAC_ATX
, psc
->ledstat
);
360 if (psc
->ledblinkfreq
) {
361 psc
->ledstat
^= psc
->ledblinkmask
;
362 callout_reset(&psc
->ledcallout
, psc
->ledblinkfreq
,
363 elsa_led_handler
, psc
);