1/* $NetBSD: isic_pci_elsa_qs1p.c,v 1.18 2008/04/10 19:13:37 cegger 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.18 2008/04/10 19:13:37 cegger 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 <sys/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 93static void elsa_cmd_req(struct isic_softc *sc, int cmd, void *data); 94static void elsa_led_handler(void *token); 95 96/*---------------------------------------------------------------------------* 97 * ELSA QuickStep 1000pro/PCI ISAC get fifo routine 98 *---------------------------------------------------------------------------*/ 99 100static void 101eqs1pp_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 125static void 126eqs1pp_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, 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, 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, buf, size); 142 break; 143 } 144} 145 146/*---------------------------------------------------------------------------* 147 * ELSA QuickStep 1000pro/PCI ISAC put register routine 148 *---------------------------------------------------------------------------*/ 149 150static void 151eqs1pp_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 179static u_int8_t 180eqs1pp_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 208int 209isic_attach_Eqs1pp(struct pci_isic_softc *psc, struct pci_attach_args *pa) 210{ 211 struct isic_softc *sc = &psc->sc_isic; 212 213 /* setup io mappings */ 214 sc->sc_num_mappings = 2; 215 MALLOC_MAPS(sc); 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"); 222 return (0); 223 } 224 225 /* PLX9050 Errata #1 */ 226 if (PCI_REVISION(pa->pa_class) == 1 && psc->sc_base & 0x00000080) { 227#ifdef DEBUG 228 printf("%s: no LCR access\n", device_xname(&sc->sc_dev)); 229#endif 230 } else 231 psc->flags |= PCIISIC_LCROK; 232 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"); 237 return (0); 238 } 239 240 /* setup access routines */ 241 242 sc->clearirq = NULL; 243 sc->readreg = eqs1pp_read_reg; 244 sc->writereg = eqs1pp_write_reg; 245 246 sc->readfifo = eqs1pp_read_fifo; 247 sc->writefifo = eqs1pp_write_fifo; 248 249 sc->drv_command = elsa_cmd_req; 250 251 /* setup card type */ 252 253 sc->sc_cardtyp = CARD_TYPEP_ELSAQS1PCI; 254 255 /* setup IOM bus type */ 256 257 sc->sc_bustyp = BUS_TYPE_IOM2; 258 259 /* setup chip type = IPAC ! */ 260 261 sc->sc_ipac = 1; 262 sc->sc_bfifolen = IPAC_BFIFO_LEN; 263 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); 269 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); 273 274 return (1); 275} 276 277int 278isic_intr_qs1p(void *vsc) 279{ 280 struct pci_isic_softc *psc = vsc; 281 struct isic_softc *sc = &psc->sc_isic; 282 u_int32_t intcsr; 283 284 /* 285 * if we are not hit by the PLX bug we can try a shortcut 286 * (should improve speed for shared IRQs) 287 */ 288 if (psc->flags & PCIISIC_LCROK) { 289 intcsr = bus_space_read_4(sc->sc_maps[0].t, sc->sc_maps[0].h, 290 0x4c /* INTCSR */); 291 if (!(intcsr & 0x4 /* LINTi1STAT */)) 292 return (0); 293 } 294 295 return (isicintr(sc)); 296} 297 298static void 299elsa_cmd_req(struct isic_softc *sc, int cmd, void *data) 300{ 301 intptr_t v; 302 int s; 303 struct pci_isic_softc *psc = (struct pci_isic_softc *)sc; 304 305 switch (cmd) { 306 case CMR_DOPEN: 307 s = splnet(); 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); 312 splx(s); 313 break; 314 case CMR_DCLOSE: 315 s = splnet(); 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); 320 splx(s); 321 break; 322 case CMR_SETLEDS: 323 v = (intptr_t)data; 324 callout_stop(&psc->ledcallout); 325 326 /* the magic value and keep reset off */ 327 psc->ledstat = ELSA_NO_LED; 328 psc->ledblinkmask = 0; 329 psc->ledblinkfreq = 0; 330 331 /* now see what LEDs we want to add */ 332 if (v & CMRLEDS_TEI) 333 psc->ledstat &= ~ELSA_GREEN_LED; 334 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; 341 else 342 psc->ledblinkfreq = hz; 343 } 344 345 elsa_led_handler(psc); 346 break; 347 } 348} 349 350static void 351elsa_led_handler(void *token) 352{ 353 struct pci_isic_softc *psc = token; 354 struct isic_softc *sc = token; /* XXX */ 355 int s; 356 357 s = splnet(); 358 IPAC_WRITE(IPAC_ATX, psc->ledstat); 359 splx(s); 360 if (psc->ledblinkfreq) { 361 psc->ledstat ^= psc->ledblinkmask; 362 callout_reset(&psc->ledcallout, psc->ledblinkfreq, 363 elsa_led_handler, psc); 364 } 365} 366