1 /* $NetBSD: cy_pci.c,v 1.13 2001/11/13 07:48:41 lukem Exp $ */ 2 3 /* 4 * cy_pci.c 5 * 6 * Driver for Cyclades Cyclom-8/16/32 multiport serial cards 7 * (currently not tested with Cyclom-32 cards) 8 * 9 * Timo Rossi, 1996 10 */ 11 12 #include <sys/cdefs.h> 13 __KERNEL_RCSID(0, "$NetBSD: cy_pci.c,v 1.13 2001/11/13 07:48:41 lukem Exp $"); 14 15 #include <sys/param.h> 16 #include <sys/systm.h> 17 #include <sys/device.h> 18 19 #include <machine/bus.h> 20 #include <machine/intr.h> 21 22 #include <dev/pci/pcivar.h> 23 #include <dev/pci/pcireg.h> 24 #include <dev/pci/pcidevs.h> 25 26 #include <dev/ic/cd1400reg.h> 27 #include <dev/ic/cyreg.h> 28 #include <dev/ic/cyvar.h> 29 30 struct cy_pci_softc { 31 struct cy_softc sc_cy; /* real cy softc */ 32 33 bus_space_tag_t sc_iot; /* PLX runtime i/o tag */ 34 bus_space_handle_t sc_ioh; /* PLX runtime i/o handle */ 35 }; 36 37 int cy_pci_match(struct device *, struct cfdata *, void *); 38 void cy_pci_attach(struct device *, struct device *, void *); 39 40 struct cfattach cy_pci_ca = { 41 sizeof(struct cy_pci_softc), cy_pci_match, cy_pci_attach 42 }; 43 44 static const struct cy_pci_product { 45 pci_product_id_t cp_product; /* product ID */ 46 pcireg_t cp_memtype; /* memory type */ 47 } cy_pci_products[] = { 48 { PCI_PRODUCT_CYCLADES_CYCLOMY_1, 49 PCI_MAPREG_TYPE_MEM|PCI_MAPREG_MEM_TYPE_32BIT_1M }, 50 { PCI_PRODUCT_CYCLADES_CYCLOM4Y_1, 51 PCI_MAPREG_TYPE_MEM|PCI_MAPREG_MEM_TYPE_32BIT_1M }, 52 { PCI_PRODUCT_CYCLADES_CYCLOM8Y_1, 53 PCI_MAPREG_TYPE_MEM|PCI_MAPREG_MEM_TYPE_32BIT_1M }, 54 55 { PCI_PRODUCT_CYCLADES_CYCLOMY_2, 56 PCI_MAPREG_TYPE_MEM|PCI_MAPREG_MEM_TYPE_32BIT }, 57 { PCI_PRODUCT_CYCLADES_CYCLOM4Y_2, 58 PCI_MAPREG_TYPE_MEM|PCI_MAPREG_MEM_TYPE_32BIT }, 59 { PCI_PRODUCT_CYCLADES_CYCLOM8Y_2, 60 PCI_MAPREG_TYPE_MEM|PCI_MAPREG_MEM_TYPE_32BIT }, 61 62 { 0, 63 0 }, 64 }; 65 static const int cy_pci_nproducts = 66 sizeof(cy_pci_products) / sizeof(cy_pci_products[0]); 67 68 static const struct cy_pci_product * 69 cy_pci_lookup(const struct pci_attach_args *pa) 70 { 71 const struct cy_pci_product *cp; 72 int i; 73 74 if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_CYCLADES) 75 return (NULL); 76 77 for (i = 0; i < cy_pci_nproducts; i++) { 78 cp = &cy_pci_products[i]; 79 if (PCI_PRODUCT(pa->pa_id) == cp->cp_product) 80 return (cp); 81 } 82 return (NULL); 83 } 84 85 int 86 cy_pci_match(struct device *parent, struct cfdata *match, void *aux) 87 { 88 struct pci_attach_args *pa = aux; 89 90 return (cy_pci_lookup(pa) != NULL); 91 } 92 93 void 94 cy_pci_attach(struct device *parent, struct device *self, void *aux) 95 { 96 struct cy_pci_softc *psc = (void *) self; 97 struct cy_softc *sc = (void *) &psc->sc_cy; 98 struct pci_attach_args *pa = aux; 99 pci_intr_handle_t ih; 100 const struct cy_pci_product *cp; 101 const char *intrstr; 102 int plx_ver; 103 104 sc->sc_bustype = CY_BUSTYPE_PCI; 105 106 cp = cy_pci_lookup(pa); 107 if (cp == NULL) 108 panic("cy_pci_attach: impossible"); 109 110 printf(": Cyclades-Y multiport serial\n"); 111 112 if (pci_mapreg_map(pa, 0x14, PCI_MAPREG_TYPE_IO, 0, 113 &psc->sc_iot, &psc->sc_ioh, NULL, NULL) != 0) { 114 printf("%s: unable to map PLX registers\n", 115 sc->sc_dev.dv_xname); 116 return; 117 } 118 119 if (pci_mapreg_map(pa, 0x18, cp->cp_memtype, 0, 120 &sc->sc_memt, &sc->sc_bsh, NULL, NULL) != 0) { 121 printf("%s: unable to map device registers\n", 122 sc->sc_dev.dv_xname); 123 return; 124 } 125 126 if (cy_find(sc) == 0) { 127 printf("%s: unable to find CD1400s\n", sc->sc_dev.dv_xname); 128 return; 129 } 130 131 /* 132 * XXX Like the Cyclades-Z, we should really check the EEPROM to 133 * determine the "poll or interrupt" setting. For now, we always 134 * map the interrupt and enable it in the PLX. 135 */ 136 137 /* Map and establish the interrupt. */ 138 if (pci_intr_map(pa, &ih) != 0) { 139 printf(": unable to map interrupt\n"); 140 return; 141 } 142 intrstr = pci_intr_string(pa->pa_pc, ih); 143 sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_TTY, cy_intr, sc); 144 if (sc->sc_ih == NULL) { 145 printf(": unable to establish interrupt"); 146 if (intrstr != NULL) 147 printf(" at %s", intrstr); 148 printf("\n"); 149 return; 150 } 151 printf("%s: interrupting at %s\n", sc->sc_dev.dv_xname, intrstr); 152 153 cy_attach(sc); 154 155 plx_ver = bus_space_read_1(sc->sc_memt, sc->sc_bsh, CY_PLX_VER) & 0x0f; 156 157 /* Enable PCI card interrupts */ 158 switch (plx_ver) { 159 case CY_PLX_9050: 160 bus_space_write_2(psc->sc_iot, psc->sc_ioh, CY_PCI_INTENA_9050, 161 bus_space_read_2(psc->sc_iot, psc->sc_ioh, 162 CY_PCI_INTENA_9050) | 0x40); 163 break; 164 165 case CY_PLX_9060: 166 case CY_PLX_9080: 167 default: 168 bus_space_write_2(psc->sc_iot, psc->sc_ioh, CY_PCI_INTENA, 169 bus_space_read_2(psc->sc_iot, psc->sc_ioh, 170 CY_PCI_INTENA) | 0x900); 171 } 172 } 173