11.26Sjdolecek/* $NetBSD: cy_pci.c,v 1.26 2018/12/09 11:14:02 jdolecek 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.26Sjdolecek__KERNEL_RCSID(0, "$NetBSD: cy_pci.c,v 1.26 2018/12/09 11:14:02 jdolecek Exp $"); 141.11Sthorpej 151.1Schristos#include <sys/param.h> 161.1Schristos#include <sys/systm.h> 171.1Schristos#include <sys/device.h> 181.1Schristos 191.22Sad#include <sys/bus.h> 201.22Sad#include <sys/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.11Sthorpejstatic const struct cy_pci_product { 381.11Sthorpej pci_product_id_t cp_product; /* product ID */ 391.11Sthorpej pcireg_t cp_memtype; /* memory type */ 401.11Sthorpej} cy_pci_products[] = { 411.11Sthorpej { PCI_PRODUCT_CYCLADES_CYCLOMY_1, 421.11Sthorpej PCI_MAPREG_TYPE_MEM|PCI_MAPREG_MEM_TYPE_32BIT_1M }, 431.11Sthorpej { PCI_PRODUCT_CYCLADES_CYCLOM4Y_1, 441.11Sthorpej PCI_MAPREG_TYPE_MEM|PCI_MAPREG_MEM_TYPE_32BIT_1M }, 451.11Sthorpej { PCI_PRODUCT_CYCLADES_CYCLOM8Y_1, 461.11Sthorpej PCI_MAPREG_TYPE_MEM|PCI_MAPREG_MEM_TYPE_32BIT_1M }, 471.11Sthorpej 481.11Sthorpej { PCI_PRODUCT_CYCLADES_CYCLOMY_2, 491.11Sthorpej PCI_MAPREG_TYPE_MEM|PCI_MAPREG_MEM_TYPE_32BIT }, 501.11Sthorpej { PCI_PRODUCT_CYCLADES_CYCLOM4Y_2, 511.11Sthorpej PCI_MAPREG_TYPE_MEM|PCI_MAPREG_MEM_TYPE_32BIT }, 521.11Sthorpej { PCI_PRODUCT_CYCLADES_CYCLOM8Y_2, 531.11Sthorpej PCI_MAPREG_TYPE_MEM|PCI_MAPREG_MEM_TYPE_32BIT }, 541.1Schristos 551.11Sthorpej { 0, 561.11Sthorpej 0 }, 571.11Sthorpej}; 581.11Sthorpejstatic const int cy_pci_nproducts = 591.11Sthorpej sizeof(cy_pci_products) / sizeof(cy_pci_products[0]); 601.5Scgd 611.11Sthorpejstatic const struct cy_pci_product * 621.11Sthorpejcy_pci_lookup(const struct pci_attach_args *pa) 631.11Sthorpej{ 641.11Sthorpej const struct cy_pci_product *cp; 651.11Sthorpej int i; 661.5Scgd 671.11Sthorpej if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_CYCLADES) 681.11Sthorpej return (NULL); 691.1Schristos 701.11Sthorpej for (i = 0; i < cy_pci_nproducts; i++) { 711.11Sthorpej cp = &cy_pci_products[i]; 721.11Sthorpej if (PCI_PRODUCT(pa->pa_id) == cp->cp_product) 731.11Sthorpej return (cp); 741.11Sthorpej } 751.11Sthorpej return (NULL); 761.1Schristos} 771.1Schristos 781.18Sthorpejstatic int 791.23Smattcy_pci_match(device_t parent, cfdata_t match, void *aux) 801.1Schristos{ 811.11Sthorpej struct pci_attach_args *pa = aux; 821.1Schristos 831.11Sthorpej return (cy_pci_lookup(pa) != NULL); 841.1Schristos} 851.1Schristos 861.18Sthorpejstatic void 871.23Smattcy_pci_attach(device_t parent, device_t self, void *aux) 881.1Schristos{ 891.23Smatt struct cy_pci_softc *psc = device_private(self); 901.23Smatt struct cy_softc *sc = &psc->sc_cy; 911.11Sthorpej struct pci_attach_args *pa = aux; 921.11Sthorpej pci_intr_handle_t ih; 931.11Sthorpej const struct cy_pci_product *cp; 941.5Scgd const char *intrstr; 951.9Stsubai int plx_ver; 961.24Schristos char intrbuf[PCI_INTRSTR_LEN]; 971.1Schristos 981.23Smatt sc->sc_dev = self; 991.23Smatt 1001.17Sthorpej aprint_naive(": Multi-port serial controller\n"); 1011.17Sthorpej 1021.1Schristos sc->sc_bustype = CY_BUSTYPE_PCI; 1031.1Schristos 1041.11Sthorpej cp = cy_pci_lookup(pa); 1051.11Sthorpej if (cp == NULL) 1061.11Sthorpej panic("cy_pci_attach: impossible"); 1071.11Sthorpej 1081.17Sthorpej aprint_normal(": Cyclades-Y multiport serial\n"); 1091.11Sthorpej 1101.11Sthorpej if (pci_mapreg_map(pa, 0x14, PCI_MAPREG_TYPE_IO, 0, 1111.11Sthorpej &psc->sc_iot, &psc->sc_ioh, NULL, NULL) != 0) { 1121.23Smatt aprint_error_dev(sc->sc_dev, "unable to map PLX registers\n"); 1131.5Scgd return; 1141.5Scgd } 1151.1Schristos 1161.11Sthorpej if (pci_mapreg_map(pa, 0x18, cp->cp_memtype, 0, 1171.11Sthorpej &sc->sc_memt, &sc->sc_bsh, NULL, NULL) != 0) { 1181.25Smsaitoh aprint_error_dev(sc->sc_dev, 1191.25Smsaitoh "unable to map device registers\n"); 1201.11Sthorpej return; 1211.11Sthorpej } 1221.1Schristos 1231.5Scgd if (cy_find(sc) == 0) { 1241.23Smatt aprint_error_dev(sc->sc_dev, "unable to find CD1400s\n"); 1251.5Scgd return; 1261.5Scgd } 1271.5Scgd 1281.11Sthorpej /* 1291.11Sthorpej * XXX Like the Cyclades-Z, we should really check the EEPROM to 1301.11Sthorpej * determine the "poll or interrupt" setting. For now, we always 1311.11Sthorpej * map the interrupt and enable it in the PLX. 1321.11Sthorpej */ 1331.11Sthorpej 1341.11Sthorpej /* Map and establish the interrupt. */ 1351.11Sthorpej if (pci_intr_map(pa, &ih) != 0) { 1361.23Smatt aprint_error_dev(sc->sc_dev, "unable to map interrupt\n"); 1371.5Scgd return; 1381.5Scgd } 1391.24Schristos intrstr = pci_intr_string(pa->pa_pc, ih, intrbuf, sizeof(intrbuf)); 1401.26Sjdolecek sc->sc_ih = pci_intr_establish_xname(pa->pa_pc, ih, IPL_TTY, cy_intr, 1411.26Sjdolecek sc, device_xname(self)); 1421.5Scgd if (sc->sc_ih == NULL) { 1431.23Smatt aprint_error_dev(sc->sc_dev, "unable to establish interrupt"); 1441.5Scgd if (intrstr != NULL) 1451.23Smatt aprint_error(" at %s", intrstr); 1461.23Smatt aprint_error("\n"); 1471.5Scgd return; 1481.5Scgd } 1491.23Smatt aprint_normal_dev(sc->sc_dev, "interrupting at %s\n", intrstr); 1501.5Scgd 1511.12Sthorpej cy_attach(sc); 1521.1Schristos 1531.11Sthorpej plx_ver = bus_space_read_1(sc->sc_memt, sc->sc_bsh, CY_PLX_VER) & 0x0f; 1541.9Stsubai 1551.1Schristos /* Enable PCI card interrupts */ 1561.9Stsubai switch (plx_ver) { 1571.9Stsubai case CY_PLX_9050: 1581.11Sthorpej bus_space_write_2(psc->sc_iot, psc->sc_ioh, CY_PCI_INTENA_9050, 1591.11Sthorpej bus_space_read_2(psc->sc_iot, psc->sc_ioh, 1601.11Sthorpej CY_PCI_INTENA_9050) | 0x40); 1611.9Stsubai break; 1621.11Sthorpej 1631.9Stsubai case CY_PLX_9060: 1641.9Stsubai case CY_PLX_9080: 1651.9Stsubai default: 1661.11Sthorpej bus_space_write_2(psc->sc_iot, psc->sc_ioh, CY_PCI_INTENA, 1671.11Sthorpej bus_space_read_2(psc->sc_iot, psc->sc_ioh, 1681.11Sthorpej CY_PCI_INTENA) | 0x900); 1691.9Stsubai } 1701.1Schristos} 1711.18Sthorpej 1721.23SmattCFATTACH_DECL_NEW(cy_pci, sizeof(struct cy_pci_softc), 1731.18Sthorpej cy_pci_match, cy_pci_attach, NULL, NULL); 174