cy_pci.c revision 1.13
11.13Slukem/* $NetBSD: cy_pci.c,v 1.13 2001/11/13 07:48:41 lukem Exp $ */ 21.1Schristos 31.1Schristos/* 41.1Schristos * cy_pci.c 51.1Schristos * 61.1Schristos * Driver for Cyclades Cyclom-8/16/32 multiport serial cards 71.1Schristos * (currently not tested with Cyclom-32 cards) 81.1Schristos * 91.1Schristos * Timo Rossi, 1996 101.1Schristos */ 111.13Slukem 121.13Slukem#include <sys/cdefs.h> 131.13Slukem__KERNEL_RCSID(0, "$NetBSD: cy_pci.c,v 1.13 2001/11/13 07:48:41 lukem Exp $"); 141.11Sthorpej 151.1Schristos#include <sys/param.h> 161.1Schristos#include <sys/systm.h> 171.1Schristos#include <sys/device.h> 181.1Schristos 191.1Schristos#include <machine/bus.h> 201.1Schristos#include <machine/intr.h> 211.1Schristos 221.1Schristos#include <dev/pci/pcivar.h> 231.1Schristos#include <dev/pci/pcireg.h> 241.1Schristos#include <dev/pci/pcidevs.h> 251.1Schristos 261.1Schristos#include <dev/ic/cd1400reg.h> 271.1Schristos#include <dev/ic/cyreg.h> 281.1Schristos#include <dev/ic/cyvar.h> 291.1Schristos 301.11Sthorpejstruct cy_pci_softc { 311.11Sthorpej struct cy_softc sc_cy; /* real cy softc */ 321.11Sthorpej 331.11Sthorpej bus_space_tag_t sc_iot; /* PLX runtime i/o tag */ 341.11Sthorpej bus_space_handle_t sc_ioh; /* PLX runtime i/o handle */ 351.11Sthorpej}; 361.11Sthorpej 371.11Sthorpejint cy_pci_match(struct device *, struct cfdata *, void *); 381.11Sthorpejvoid cy_pci_attach(struct device *, struct device *, void *); 391.1Schristos 401.1Schristosstruct cfattach cy_pci_ca = { 411.11Sthorpej sizeof(struct cy_pci_softc), cy_pci_match, cy_pci_attach 421.1Schristos}; 431.1Schristos 441.11Sthorpejstatic const struct cy_pci_product { 451.11Sthorpej pci_product_id_t cp_product; /* product ID */ 461.11Sthorpej pcireg_t cp_memtype; /* memory type */ 471.11Sthorpej} cy_pci_products[] = { 481.11Sthorpej { PCI_PRODUCT_CYCLADES_CYCLOMY_1, 491.11Sthorpej PCI_MAPREG_TYPE_MEM|PCI_MAPREG_MEM_TYPE_32BIT_1M }, 501.11Sthorpej { PCI_PRODUCT_CYCLADES_CYCLOM4Y_1, 511.11Sthorpej PCI_MAPREG_TYPE_MEM|PCI_MAPREG_MEM_TYPE_32BIT_1M }, 521.11Sthorpej { PCI_PRODUCT_CYCLADES_CYCLOM8Y_1, 531.11Sthorpej PCI_MAPREG_TYPE_MEM|PCI_MAPREG_MEM_TYPE_32BIT_1M }, 541.11Sthorpej 551.11Sthorpej { PCI_PRODUCT_CYCLADES_CYCLOMY_2, 561.11Sthorpej PCI_MAPREG_TYPE_MEM|PCI_MAPREG_MEM_TYPE_32BIT }, 571.11Sthorpej { PCI_PRODUCT_CYCLADES_CYCLOM4Y_2, 581.11Sthorpej PCI_MAPREG_TYPE_MEM|PCI_MAPREG_MEM_TYPE_32BIT }, 591.11Sthorpej { PCI_PRODUCT_CYCLADES_CYCLOM8Y_2, 601.11Sthorpej PCI_MAPREG_TYPE_MEM|PCI_MAPREG_MEM_TYPE_32BIT }, 611.1Schristos 621.11Sthorpej { 0, 631.11Sthorpej 0 }, 641.11Sthorpej}; 651.11Sthorpejstatic const int cy_pci_nproducts = 661.11Sthorpej sizeof(cy_pci_products) / sizeof(cy_pci_products[0]); 671.5Scgd 681.11Sthorpejstatic const struct cy_pci_product * 691.11Sthorpejcy_pci_lookup(const struct pci_attach_args *pa) 701.11Sthorpej{ 711.11Sthorpej const struct cy_pci_product *cp; 721.11Sthorpej int i; 731.5Scgd 741.11Sthorpej if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_CYCLADES) 751.11Sthorpej return (NULL); 761.1Schristos 771.11Sthorpej for (i = 0; i < cy_pci_nproducts; i++) { 781.11Sthorpej cp = &cy_pci_products[i]; 791.11Sthorpej if (PCI_PRODUCT(pa->pa_id) == cp->cp_product) 801.11Sthorpej return (cp); 811.11Sthorpej } 821.11Sthorpej return (NULL); 831.1Schristos} 841.1Schristos 851.11Sthorpejint 861.11Sthorpejcy_pci_match(struct device *parent, struct cfdata *match, void *aux) 871.1Schristos{ 881.11Sthorpej struct pci_attach_args *pa = aux; 891.1Schristos 901.11Sthorpej return (cy_pci_lookup(pa) != NULL); 911.1Schristos} 921.1Schristos 931.11Sthorpejvoid 941.11Sthorpejcy_pci_attach(struct device *parent, struct device *self, void *aux) 951.1Schristos{ 961.11Sthorpej struct cy_pci_softc *psc = (void *) self; 971.11Sthorpej struct cy_softc *sc = (void *) &psc->sc_cy; 981.11Sthorpej struct pci_attach_args *pa = aux; 991.11Sthorpej pci_intr_handle_t ih; 1001.11Sthorpej const struct cy_pci_product *cp; 1011.5Scgd const char *intrstr; 1021.9Stsubai int plx_ver; 1031.1Schristos 1041.1Schristos sc->sc_bustype = CY_BUSTYPE_PCI; 1051.1Schristos 1061.11Sthorpej cp = cy_pci_lookup(pa); 1071.11Sthorpej if (cp == NULL) 1081.11Sthorpej panic("cy_pci_attach: impossible"); 1091.11Sthorpej 1101.11Sthorpej printf(": Cyclades-Y multiport serial\n"); 1111.11Sthorpej 1121.11Sthorpej if (pci_mapreg_map(pa, 0x14, PCI_MAPREG_TYPE_IO, 0, 1131.11Sthorpej &psc->sc_iot, &psc->sc_ioh, NULL, NULL) != 0) { 1141.11Sthorpej printf("%s: unable to map PLX registers\n", 1151.11Sthorpej sc->sc_dev.dv_xname); 1161.5Scgd return; 1171.5Scgd } 1181.1Schristos 1191.11Sthorpej if (pci_mapreg_map(pa, 0x18, cp->cp_memtype, 0, 1201.11Sthorpej &sc->sc_memt, &sc->sc_bsh, NULL, NULL) != 0) { 1211.11Sthorpej printf("%s: unable to map device registers\n", 1221.11Sthorpej sc->sc_dev.dv_xname); 1231.11Sthorpej return; 1241.11Sthorpej } 1251.1Schristos 1261.5Scgd if (cy_find(sc) == 0) { 1271.11Sthorpej printf("%s: unable to find CD1400s\n", sc->sc_dev.dv_xname); 1281.5Scgd return; 1291.5Scgd } 1301.5Scgd 1311.11Sthorpej /* 1321.11Sthorpej * XXX Like the Cyclades-Z, we should really check the EEPROM to 1331.11Sthorpej * determine the "poll or interrupt" setting. For now, we always 1341.11Sthorpej * map the interrupt and enable it in the PLX. 1351.11Sthorpej */ 1361.11Sthorpej 1371.11Sthorpej /* Map and establish the interrupt. */ 1381.11Sthorpej if (pci_intr_map(pa, &ih) != 0) { 1391.11Sthorpej printf(": unable to map interrupt\n"); 1401.5Scgd return; 1411.5Scgd } 1421.11Sthorpej intrstr = pci_intr_string(pa->pa_pc, ih); 1431.11Sthorpej sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_TTY, cy_intr, sc); 1441.5Scgd if (sc->sc_ih == NULL) { 1451.11Sthorpej printf(": unable to establish interrupt"); 1461.5Scgd if (intrstr != NULL) 1471.5Scgd printf(" at %s", intrstr); 1481.5Scgd printf("\n"); 1491.5Scgd return; 1501.5Scgd } 1511.11Sthorpej printf("%s: interrupting at %s\n", sc->sc_dev.dv_xname, intrstr); 1521.5Scgd 1531.12Sthorpej cy_attach(sc); 1541.1Schristos 1551.11Sthorpej plx_ver = bus_space_read_1(sc->sc_memt, sc->sc_bsh, CY_PLX_VER) & 0x0f; 1561.9Stsubai 1571.1Schristos /* Enable PCI card interrupts */ 1581.9Stsubai switch (plx_ver) { 1591.9Stsubai case CY_PLX_9050: 1601.11Sthorpej bus_space_write_2(psc->sc_iot, psc->sc_ioh, CY_PCI_INTENA_9050, 1611.11Sthorpej bus_space_read_2(psc->sc_iot, psc->sc_ioh, 1621.11Sthorpej CY_PCI_INTENA_9050) | 0x40); 1631.9Stsubai break; 1641.11Sthorpej 1651.9Stsubai case CY_PLX_9060: 1661.9Stsubai case CY_PLX_9080: 1671.9Stsubai default: 1681.11Sthorpej bus_space_write_2(psc->sc_iot, psc->sc_ioh, CY_PCI_INTENA, 1691.11Sthorpej bus_space_read_2(psc->sc_iot, psc->sc_ioh, 1701.11Sthorpej CY_PCI_INTENA) | 0x900); 1711.9Stsubai } 1721.1Schristos} 173