1*4887a701Sart /* $OpenBSD: sio.c,v 1.18 2001/02/05 17:14:40 art Exp $ */ 23a630e3fSniklas /* $NetBSD: sio.c,v 1.15 1996/12/05 01:39:36 cgd Exp $ */ 3df930be7Sderaadt 4df930be7Sderaadt /* 5417eba8cSderaadt * Copyright (c) 1995, 1996 Carnegie-Mellon University. 6df930be7Sderaadt * All rights reserved. 7df930be7Sderaadt * 8df930be7Sderaadt * Author: Chris G. Demetriou 9df930be7Sderaadt * 10df930be7Sderaadt * Permission to use, copy, modify and distribute this software and 11df930be7Sderaadt * its documentation is hereby granted, provided that both the copyright 12df930be7Sderaadt * notice and this permission notice appear in all copies of the 13df930be7Sderaadt * software, derivative works or modified versions, and any portions 14df930be7Sderaadt * thereof, and that both notices appear in supporting documentation. 15df930be7Sderaadt * 16df930be7Sderaadt * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 17df930be7Sderaadt * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 18df930be7Sderaadt * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 19df930be7Sderaadt * 20df930be7Sderaadt * Carnegie Mellon requests users of this software to return to 21df930be7Sderaadt * 22df930be7Sderaadt * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 23df930be7Sderaadt * School of Computer Science 24df930be7Sderaadt * Carnegie Mellon University 25df930be7Sderaadt * Pittsburgh PA 15213-3890 26df930be7Sderaadt * 27df930be7Sderaadt * any improvements or extensions that they make and grant Carnegie the 28df930be7Sderaadt * rights to redistribute these changes. 29df930be7Sderaadt */ 30df930be7Sderaadt 31df930be7Sderaadt #include <sys/param.h> 32df930be7Sderaadt #include <sys/systm.h> 33df930be7Sderaadt #include <sys/kernel.h> 34df930be7Sderaadt #include <sys/device.h> 35df930be7Sderaadt 36417eba8cSderaadt #include <machine/intr.h> 37e464495eSniklas #include <machine/bus.h> 38417eba8cSderaadt 3934fbf6deSderaadt #include <dev/isa/isavar.h> 4034fbf6deSderaadt #include <dev/eisa/eisavar.h> 4134fbf6deSderaadt 42df930be7Sderaadt #include <dev/pci/pcireg.h> 43df930be7Sderaadt #include <dev/pci/pcivar.h> 44df930be7Sderaadt #include <dev/pci/pcidevs.h> 45df930be7Sderaadt 4634fbf6deSderaadt #include <alpha/pci/siovar.h> 47df930be7Sderaadt 483a630e3fSniklas struct sio_softc { 493a630e3fSniklas struct device sc_dv; 503a630e3fSniklas 513a630e3fSniklas bus_space_tag_t sc_iot, sc_memt; 523a630e3fSniklas int sc_haseisa; 533a630e3fSniklas }; 543a630e3fSniklas 553a630e3fSniklas #ifdef __BROKEN_INDIRECT_CONFIG 56df930be7Sderaadt int siomatch __P((struct device *, void *, void *)); 573a630e3fSniklas #else 583a630e3fSniklas int siomatch __P((struct device *, struct cfdata *, void *)); 593a630e3fSniklas #endif 60df930be7Sderaadt void sioattach __P((struct device *, struct device *, void *)); 61df930be7Sderaadt 62417eba8cSderaadt struct cfattach sio_ca = { 633a630e3fSniklas sizeof(struct sio_softc), siomatch, sioattach, 64417eba8cSderaadt }; 65417eba8cSderaadt 66417eba8cSderaadt struct cfdriver sio_cd = { 67417eba8cSderaadt NULL, "sio", DV_DULL, 68df930be7Sderaadt }; 69df930be7Sderaadt 703a630e3fSniklas #ifdef __BROKEN_INDIRECT_CONFIG 7134fbf6deSderaadt int pcebmatch __P((struct device *, void *, void *)); 723a630e3fSniklas #else 733a630e3fSniklas int pcebmatch __P((struct device *, struct cfdata *, void *)); 743a630e3fSniklas #endif 7534fbf6deSderaadt 76417eba8cSderaadt struct cfattach pceb_ca = { 77835a491cSart sizeof(struct sio_softc), pcebmatch, sioattach, 7834fbf6deSderaadt }; 7934fbf6deSderaadt 80417eba8cSderaadt struct cfdriver pceb_cd = { 81417eba8cSderaadt NULL, "pceb", DV_DULL, 82417eba8cSderaadt }; 83417eba8cSderaadt 84417eba8cSderaadt union sio_attach_args { 85417eba8cSderaadt const char *sa_name; /* XXX should be common */ 86417eba8cSderaadt struct isabus_attach_args sa_iba; 87417eba8cSderaadt struct eisabus_attach_args sa_eba; 88417eba8cSderaadt }; 89417eba8cSderaadt 90833613b2Skstailey int sioprint __P((void *, const char *pnp)); 91417eba8cSderaadt void sio_isa_attach_hook __P((struct device *, struct device *, 92417eba8cSderaadt struct isabus_attach_args *)); 93417eba8cSderaadt void sio_eisa_attach_hook __P((struct device *, struct device *, 94417eba8cSderaadt struct eisabus_attach_args *)); 95417eba8cSderaadt int sio_eisa_maxslots __P((void *)); 96417eba8cSderaadt int sio_eisa_intr_map __P((void *, u_int, eisa_intr_handle_t *)); 9780b183b6Sderaadt void siocfiddle __P((struct isabus_attach_args *iba)); 98df930be7Sderaadt 993a630e3fSniklas void sio_bridge_callback __P((void *)); 1003a630e3fSniklas 101df930be7Sderaadt int 102df930be7Sderaadt siomatch(parent, match, aux) 103df930be7Sderaadt struct device *parent; 1043a630e3fSniklas #ifdef __BROKEN_INDIRECT_CONFIG 1053a630e3fSniklas void *match; 1063a630e3fSniklas #else 1073a630e3fSniklas struct cfdata *match; 1083a630e3fSniklas #endif 1093a630e3fSniklas void *aux; 110df930be7Sderaadt { 111417eba8cSderaadt struct pci_attach_args *pa = aux; 112df930be7Sderaadt 1136a30a1c1Smillert if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_CONTAQ && 114e6dd45c8Smillert PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_CONTAQ_82C693 && 1156a30a1c1Smillert pa->pa_function == 0) 11634fbf6deSderaadt return (1); 1176a30a1c1Smillert 1186a30a1c1Smillert if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_INTEL && 1196a30a1c1Smillert PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_INTEL_SIO) 1206a30a1c1Smillert return (1); 1216a30a1c1Smillert 1226a30a1c1Smillert return (0); 12334fbf6deSderaadt } 12434fbf6deSderaadt 12534fbf6deSderaadt int 12634fbf6deSderaadt pcebmatch(parent, match, aux) 12734fbf6deSderaadt struct device *parent; 1283a630e3fSniklas #ifdef __BROKEN_INDIRECT_CONFIG 1293a630e3fSniklas void *match; 1303a630e3fSniklas #else 1313a630e3fSniklas struct cfdata *match; 1323a630e3fSniklas #endif 1333a630e3fSniklas void *aux; 13434fbf6deSderaadt { 135417eba8cSderaadt struct pci_attach_args *pa = aux; 13634fbf6deSderaadt 137*4887a701Sart if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_INTEL && 138*4887a701Sart PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_INTEL_PCEB) 139df930be7Sderaadt return (1); 140*4887a701Sart 141*4887a701Sart return (0); 142df930be7Sderaadt } 143df930be7Sderaadt 144df930be7Sderaadt void 145df930be7Sderaadt sioattach(parent, self, aux) 146df930be7Sderaadt struct device *parent, *self; 147df930be7Sderaadt void *aux; 148df930be7Sderaadt { 1493a630e3fSniklas struct sio_softc *sc = (struct sio_softc *)self; 150417eba8cSderaadt struct pci_attach_args *pa = aux; 151df930be7Sderaadt 15250c9667dSderaadt printf("\n"); 15334fbf6deSderaadt 1543a630e3fSniklas sc->sc_iot = pa->pa_iot; 1553a630e3fSniklas sc->sc_memt = pa->pa_memt; 1563a630e3fSniklas sc->sc_haseisa = (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_INTEL_PCEB); 157df930be7Sderaadt 15834fbf6deSderaadt #ifdef EVCNT_COUNTERS 1593a630e3fSniklas evcnt_attach(&sc->sc_dv, "intr", &sio_intr_evcnt); 16034fbf6deSderaadt #endif 16134fbf6deSderaadt 1623a630e3fSniklas set_pci_isa_bridge_callback(sio_bridge_callback, sc); 1633a630e3fSniklas } 1643a630e3fSniklas 1653a630e3fSniklas void 1663a630e3fSniklas sio_bridge_callback(v) 1673a630e3fSniklas void *v; 1683a630e3fSniklas { 1693a630e3fSniklas struct sio_softc *sc = v; 1703a630e3fSniklas struct alpha_eisa_chipset ec; 1713a630e3fSniklas struct alpha_isa_chipset ic; 1723a630e3fSniklas union sio_attach_args sa; 1733a630e3fSniklas 1743a630e3fSniklas if (sc->sc_haseisa) { 175417eba8cSderaadt ec.ec_v = NULL; 176417eba8cSderaadt ec.ec_attach_hook = sio_eisa_attach_hook; 177417eba8cSderaadt ec.ec_maxslots = sio_eisa_maxslots; 178417eba8cSderaadt ec.ec_intr_map = sio_eisa_intr_map; 179417eba8cSderaadt ec.ec_intr_string = sio_intr_string; 180417eba8cSderaadt ec.ec_intr_establish = sio_intr_establish; 181417eba8cSderaadt ec.ec_intr_disestablish = sio_intr_disestablish; 182417eba8cSderaadt 183417eba8cSderaadt sa.sa_eba.eba_busname = "eisa"; 1843a630e3fSniklas sa.sa_eba.eba_iot = sc->sc_iot; 1853a630e3fSniklas sa.sa_eba.eba_memt = sc->sc_memt; 186417eba8cSderaadt sa.sa_eba.eba_ec = &ec; 1873a630e3fSniklas config_found(&sc->sc_dv, &sa.sa_eba, sioprint); 188df930be7Sderaadt } 189df930be7Sderaadt 190417eba8cSderaadt ic.ic_v = NULL; 191417eba8cSderaadt ic.ic_attach_hook = sio_isa_attach_hook; 192417eba8cSderaadt ic.ic_intr_establish = sio_intr_establish; 193417eba8cSderaadt ic.ic_intr_disestablish = sio_intr_disestablish; 194417eba8cSderaadt 195417eba8cSderaadt sa.sa_iba.iba_busname = "isa"; 1963a630e3fSniklas sa.sa_iba.iba_iot = sc->sc_iot; 1973a630e3fSniklas sa.sa_iba.iba_memt = sc->sc_memt; 198417eba8cSderaadt sa.sa_iba.iba_ic = ⁣ 1993a630e3fSniklas config_found(&sc->sc_dv, &sa.sa_iba, sioprint); 200417eba8cSderaadt } 201417eba8cSderaadt 202417eba8cSderaadt int 203df930be7Sderaadt sioprint(aux, pnp) 204df930be7Sderaadt void *aux; 205833613b2Skstailey const char *pnp; 206df930be7Sderaadt { 207417eba8cSderaadt register union sio_attach_args *sa = aux; 208df930be7Sderaadt 209df930be7Sderaadt if (pnp) 210417eba8cSderaadt printf("%s at %s", sa->sa_name, pnp); 211df930be7Sderaadt return (UNCONF); 212df930be7Sderaadt } 213417eba8cSderaadt 214417eba8cSderaadt void 215417eba8cSderaadt sio_isa_attach_hook(parent, self, iba) 216417eba8cSderaadt struct device *parent, *self; 217417eba8cSderaadt struct isabus_attach_args *iba; 218417eba8cSderaadt { 21980b183b6Sderaadt siocfiddle(iba); 220417eba8cSderaadt } 221417eba8cSderaadt 222417eba8cSderaadt void 223417eba8cSderaadt sio_eisa_attach_hook(parent, self, eba) 224417eba8cSderaadt struct device *parent, *self; 225417eba8cSderaadt struct eisabus_attach_args *eba; 226417eba8cSderaadt { 227417eba8cSderaadt 228417eba8cSderaadt /* Nothing to do. */ 229417eba8cSderaadt } 230417eba8cSderaadt 231417eba8cSderaadt int 232417eba8cSderaadt sio_eisa_maxslots(v) 233417eba8cSderaadt void *v; 234417eba8cSderaadt { 235417eba8cSderaadt 236417eba8cSderaadt return 16; /* as good a number as any. only 8, maybe? */ 237417eba8cSderaadt } 238417eba8cSderaadt 239417eba8cSderaadt int 240417eba8cSderaadt sio_eisa_intr_map(v, irq, ihp) 241417eba8cSderaadt void *v; 242417eba8cSderaadt u_int irq; 243417eba8cSderaadt eisa_intr_handle_t *ihp; 244417eba8cSderaadt { 245417eba8cSderaadt 246417eba8cSderaadt #define ICU_LEN 16 /* number of ISA IRQs (XXX) */ 247417eba8cSderaadt 248417eba8cSderaadt if (irq >= ICU_LEN) { 249417eba8cSderaadt printf("sio_eisa_intr_map: bad IRQ %d\n", irq); 250417eba8cSderaadt *ihp = -1; 251417eba8cSderaadt return 1; 252417eba8cSderaadt } 253417eba8cSderaadt if (irq == 2) { 254417eba8cSderaadt printf("sio_eisa_intr_map: changed IRQ 2 to IRQ 9\n"); 255417eba8cSderaadt irq = 9; 256417eba8cSderaadt } 257417eba8cSderaadt 258417eba8cSderaadt *ihp = irq; 259417eba8cSderaadt return 0; 260417eba8cSderaadt } 26180b183b6Sderaadt 26280b183b6Sderaadt 26380b183b6Sderaadt /* 26480b183b6Sderaadt * Look for and gently fondle the 87312 Super I/O chip. 26580b183b6Sderaadt */ 26680b183b6Sderaadt 26780b183b6Sderaadt #define SIOC_IDE_ENABLE 0x40 26880b183b6Sderaadt #define SIOC_NPORTS 2 26980b183b6Sderaadt void 27080b183b6Sderaadt siocfiddle(iba) 27180b183b6Sderaadt struct isabus_attach_args *iba; 27280b183b6Sderaadt { 27380b183b6Sderaadt bus_space_tag_t iot = iba->iba_iot; 27480b183b6Sderaadt bus_space_handle_t ioh; 27580b183b6Sderaadt extern int cputype; 27680b183b6Sderaadt int addr; 27780b183b6Sderaadt u_int8_t reg0; 27880b183b6Sderaadt 27980b183b6Sderaadt /* Decide based on machine type */ 28080b183b6Sderaadt switch (cputype) { 28180b183b6Sderaadt case 11: /* DEC AXPpci */ 28280b183b6Sderaadt case 12: /* DEC 2100 A50 */ 28380b183b6Sderaadt addr = 0x26e; 28480b183b6Sderaadt break; 28580b183b6Sderaadt case 26: /* DEC EB164 */ 28680b183b6Sderaadt addr = 0x398; 28780b183b6Sderaadt break; 28880b183b6Sderaadt default: 28980b183b6Sderaadt return; 29080b183b6Sderaadt } 29180b183b6Sderaadt 29280b183b6Sderaadt if (bus_space_map(iot, addr, SIOC_NPORTS, 0, &ioh)) 29380b183b6Sderaadt return; 29480b183b6Sderaadt 29580b183b6Sderaadt /* select and read register 0 */ 29680b183b6Sderaadt bus_space_write_1(iot, ioh, 0, 0); 29780b183b6Sderaadt reg0 = bus_space_read_1(iot, ioh, 1); 29880b183b6Sderaadt 29980b183b6Sderaadt /* write back with IDE enabled flag set, and do it twice! */ 30080b183b6Sderaadt bus_space_write_1(iot, ioh, 0, 0); 30180b183b6Sderaadt bus_space_write_1(iot, ioh, 1, reg0 | SIOC_IDE_ENABLE); 30280b183b6Sderaadt bus_space_write_1(iot, ioh, 1, reg0 | SIOC_IDE_ENABLE); 30380b183b6Sderaadt 30480b183b6Sderaadt bus_space_unmap(iot, ioh, SIOC_NPORTS); 30580b183b6Sderaadt } 306