1 /* $NetBSD: cy_pci.c,v 1.17 2003/01/31 00:07:41 thorpej 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.17 2003/01/31 00:07:41 thorpej 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 CFATTACH_DECL(cy_pci, sizeof(struct cy_pci_softc), 41 cy_pci_match, cy_pci_attach, NULL, NULL); 42 43 static const struct cy_pci_product { 44 pci_product_id_t cp_product; /* product ID */ 45 pcireg_t cp_memtype; /* memory type */ 46 } cy_pci_products[] = { 47 { PCI_PRODUCT_CYCLADES_CYCLOMY_1, 48 PCI_MAPREG_TYPE_MEM|PCI_MAPREG_MEM_TYPE_32BIT_1M }, 49 { PCI_PRODUCT_CYCLADES_CYCLOM4Y_1, 50 PCI_MAPREG_TYPE_MEM|PCI_MAPREG_MEM_TYPE_32BIT_1M }, 51 { PCI_PRODUCT_CYCLADES_CYCLOM8Y_1, 52 PCI_MAPREG_TYPE_MEM|PCI_MAPREG_MEM_TYPE_32BIT_1M }, 53 54 { PCI_PRODUCT_CYCLADES_CYCLOMY_2, 55 PCI_MAPREG_TYPE_MEM|PCI_MAPREG_MEM_TYPE_32BIT }, 56 { PCI_PRODUCT_CYCLADES_CYCLOM4Y_2, 57 PCI_MAPREG_TYPE_MEM|PCI_MAPREG_MEM_TYPE_32BIT }, 58 { PCI_PRODUCT_CYCLADES_CYCLOM8Y_2, 59 PCI_MAPREG_TYPE_MEM|PCI_MAPREG_MEM_TYPE_32BIT }, 60 61 { 0, 62 0 }, 63 }; 64 static const int cy_pci_nproducts = 65 sizeof(cy_pci_products) / sizeof(cy_pci_products[0]); 66 67 static const struct cy_pci_product * 68 cy_pci_lookup(const struct pci_attach_args *pa) 69 { 70 const struct cy_pci_product *cp; 71 int i; 72 73 if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_CYCLADES) 74 return (NULL); 75 76 for (i = 0; i < cy_pci_nproducts; i++) { 77 cp = &cy_pci_products[i]; 78 if (PCI_PRODUCT(pa->pa_id) == cp->cp_product) 79 return (cp); 80 } 81 return (NULL); 82 } 83 84 int 85 cy_pci_match(struct device *parent, struct cfdata *match, void *aux) 86 { 87 struct pci_attach_args *pa = aux; 88 89 return (cy_pci_lookup(pa) != NULL); 90 } 91 92 void 93 cy_pci_attach(struct device *parent, struct device *self, void *aux) 94 { 95 struct cy_pci_softc *psc = (void *) self; 96 struct cy_softc *sc = (void *) &psc->sc_cy; 97 struct pci_attach_args *pa = aux; 98 pci_intr_handle_t ih; 99 const struct cy_pci_product *cp; 100 const char *intrstr; 101 int plx_ver; 102 103 aprint_naive(": Multi-port serial controller\n"); 104 105 sc->sc_bustype = CY_BUSTYPE_PCI; 106 107 cp = cy_pci_lookup(pa); 108 if (cp == NULL) 109 panic("cy_pci_attach: impossible"); 110 111 aprint_normal(": Cyclades-Y multiport serial\n"); 112 113 if (pci_mapreg_map(pa, 0x14, PCI_MAPREG_TYPE_IO, 0, 114 &psc->sc_iot, &psc->sc_ioh, NULL, NULL) != 0) { 115 aprint_error("%s: unable to map PLX registers\n", 116 sc->sc_dev.dv_xname); 117 return; 118 } 119 120 if (pci_mapreg_map(pa, 0x18, cp->cp_memtype, 0, 121 &sc->sc_memt, &sc->sc_bsh, NULL, NULL) != 0) { 122 aprint_error("%s: unable to map device registers\n", 123 sc->sc_dev.dv_xname); 124 return; 125 } 126 127 if (cy_find(sc) == 0) { 128 aprint_error("%s: unable to find CD1400s\n", 129 sc->sc_dev.dv_xname); 130 return; 131 } 132 133 /* 134 * XXX Like the Cyclades-Z, we should really check the EEPROM to 135 * determine the "poll or interrupt" setting. For now, we always 136 * map the interrupt and enable it in the PLX. 137 */ 138 139 /* Map and establish the interrupt. */ 140 if (pci_intr_map(pa, &ih) != 0) { 141 aprint_error(": unable to map interrupt\n"); 142 return; 143 } 144 intrstr = pci_intr_string(pa->pa_pc, ih); 145 sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_TTY, cy_intr, sc); 146 if (sc->sc_ih == NULL) { 147 aprint_error(": unable to establish interrupt"); 148 if (intrstr != NULL) 149 aprint_normal(" at %s", intrstr); 150 aprint_normal("\n"); 151 return; 152 } 153 aprint_normal("%s: interrupting at %s\n", sc->sc_dev.dv_xname, intrstr); 154 155 cy_attach(sc); 156 157 plx_ver = bus_space_read_1(sc->sc_memt, sc->sc_bsh, CY_PLX_VER) & 0x0f; 158 159 /* Enable PCI card interrupts */ 160 switch (plx_ver) { 161 case CY_PLX_9050: 162 bus_space_write_2(psc->sc_iot, psc->sc_ioh, CY_PCI_INTENA_9050, 163 bus_space_read_2(psc->sc_iot, psc->sc_ioh, 164 CY_PCI_INTENA_9050) | 0x40); 165 break; 166 167 case CY_PLX_9060: 168 case CY_PLX_9080: 169 default: 170 bus_space_write_2(psc->sc_iot, psc->sc_ioh, CY_PCI_INTENA, 171 bus_space_read_2(psc->sc_iot, psc->sc_ioh, 172 CY_PCI_INTENA) | 0x900); 173 } 174 } 175