1 /* $NetBSD: cy_pci.c,v 1.16 2002/10/02 16:51:08 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.16 2002/10/02 16:51:08 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 sc->sc_bustype = CY_BUSTYPE_PCI; 104 105 cp = cy_pci_lookup(pa); 106 if (cp == NULL) 107 panic("cy_pci_attach: impossible"); 108 109 printf(": Cyclades-Y multiport serial\n"); 110 111 if (pci_mapreg_map(pa, 0x14, PCI_MAPREG_TYPE_IO, 0, 112 &psc->sc_iot, &psc->sc_ioh, NULL, NULL) != 0) { 113 printf("%s: unable to map PLX registers\n", 114 sc->sc_dev.dv_xname); 115 return; 116 } 117 118 if (pci_mapreg_map(pa, 0x18, cp->cp_memtype, 0, 119 &sc->sc_memt, &sc->sc_bsh, NULL, NULL) != 0) { 120 printf("%s: unable to map device registers\n", 121 sc->sc_dev.dv_xname); 122 return; 123 } 124 125 if (cy_find(sc) == 0) { 126 printf("%s: unable to find CD1400s\n", sc->sc_dev.dv_xname); 127 return; 128 } 129 130 /* 131 * XXX Like the Cyclades-Z, we should really check the EEPROM to 132 * determine the "poll or interrupt" setting. For now, we always 133 * map the interrupt and enable it in the PLX. 134 */ 135 136 /* Map and establish the interrupt. */ 137 if (pci_intr_map(pa, &ih) != 0) { 138 printf(": unable to map interrupt\n"); 139 return; 140 } 141 intrstr = pci_intr_string(pa->pa_pc, ih); 142 sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_TTY, cy_intr, sc); 143 if (sc->sc_ih == NULL) { 144 printf(": unable to establish interrupt"); 145 if (intrstr != NULL) 146 printf(" at %s", intrstr); 147 printf("\n"); 148 return; 149 } 150 printf("%s: interrupting at %s\n", sc->sc_dev.dv_xname, intrstr); 151 152 cy_attach(sc); 153 154 plx_ver = bus_space_read_1(sc->sc_memt, sc->sc_bsh, CY_PLX_VER) & 0x0f; 155 156 /* Enable PCI card interrupts */ 157 switch (plx_ver) { 158 case CY_PLX_9050: 159 bus_space_write_2(psc->sc_iot, psc->sc_ioh, CY_PCI_INTENA_9050, 160 bus_space_read_2(psc->sc_iot, psc->sc_ioh, 161 CY_PCI_INTENA_9050) | 0x40); 162 break; 163 164 case CY_PLX_9060: 165 case CY_PLX_9080: 166 default: 167 bus_space_write_2(psc->sc_iot, psc->sc_ioh, CY_PCI_INTENA, 168 bus_space_read_2(psc->sc_iot, psc->sc_ioh, 169 CY_PCI_INTENA) | 0x900); 170 } 171 } 172