xref: /netbsd/sys/dev/pci/cy_pci.c (revision bf9ec67e)
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