if_ntwoc_pci.c revision 1.2 1 /* $NetBSD: if_ntwoc_pci.c,v 1.2 1999/02/15 04:54:35 hubertf Exp $ */
2
3 /*
4 * Copyright (c) 1998 Vixie Enterprises
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of Vixie Enterprises nor the names
17 * of its contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY VIXIE ENTERPRISES AND
21 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
22 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 * DISCLAIMED. IN NO EVENT SHALL VIXIE ENTERPRISES OR
25 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
28 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
29 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
34 * This software has been written for Vixie Enterprises by Michael Graff
35 * <explorer (at) flame.org>. To learn more about Vixie Enterprises, see
36 * ``http://www.vix.com''.
37 */
38
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/device.h>
42 #include <sys/mbuf.h>
43 #include <sys/socket.h>
44
45 #include <net/if.h>
46
47 #include <machine/cpu.h>
48 #include <machine/bus.h>
49 #include <machine/intr.h>
50
51 #include <dev/pci/pcivar.h>
52 #include <dev/pci/pcireg.h>
53 #include <dev/pci/pcidevs.h>
54
55 #include <dev/ic/hd64570reg.h>
56 #include <dev/ic/hd64570var.h>
57
58 #include <dev/pci/if_ntwoc_pcireg.h>
59
60 #if 0
61 #define NTWO_DEBUG
62 #endif
63
64 #ifdef NTWO_DEBUG
65 #define NTWO_DPRINTF(x) printf x
66 #else
67 #define NTWO_DPRINTF(x)
68 #endif
69
70 /*
71 * Card specific config register location
72 */
73 #define PCI_CBMA_ASIC 0x10 /* Configuration Base Memory Address */
74 #define PCI_CBMA_SCA 0x18
75
76 struct ntwoc_pci_softc {
77 /* Generic device stuff */
78 struct device sc_dev; /* Common to all devices */
79
80 /* PCI chipset glue */
81 pci_intr_handle_t *sc_ih; /* Interrupt handler */
82 pci_chipset_tag_t sc_sr; /* PCI chipset handle */
83
84 bus_space_tag_t sc_asic_iot; /* space cookie (for ASIC) */
85 bus_space_handle_t sc_asic_ioh; /* bus space handle (for ASIC) */
86
87 struct sca_softc sc_sca; /* the SCA itself */
88 };
89
90 static int ntwoc_pci_match __P((struct device *, struct cfdata *, void *));
91 static void ntwoc_pci_attach __P((struct device *, struct device *, void *));
92
93 static int ntwoc_intr __P((void *));
94 static void ntwoc_shutdown __P((void *sc));
95 static void ntwoc_dtr_callback __P((void *, int, int));
96
97 struct cfattach ntwoc_pci_ca = {
98 sizeof(struct ntwoc_pci_softc), ntwoc_pci_match, ntwoc_pci_attach,
99 };
100
101 /*
102 * Names for daughter card types. These match the NTWOC_DB_* defines.
103 */
104 char *ntwoc_db_names[] = {
105 "V.35", "Unknown 0x01", "Test", "Unknown 0x03",
106 "RS232", "Unknown 0x05", "RS422", "None"
107 };
108
109 static int
110 ntwoc_pci_match(struct device *parent, struct cfdata *match, void *aux)
111 {
112 struct pci_attach_args *pa = (struct pci_attach_args *)aux;
113
114 if ((PCI_VENDOR(pa->pa_id) == PCI_VENDOR_RISCOM)
115 && (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_RISCOM_N2))
116 return 1;
117
118 return 0;
119 }
120
121 static void
122 ntwoc_pci_attach(struct device *parent, struct device *self, void *aux)
123 {
124 struct ntwoc_pci_softc *sc = (void *)self;
125 struct pci_attach_args *pa = aux;
126 struct sca_softc *sca = &sc->sc_sca;
127 pci_intr_handle_t ih;
128 const char *intrstr;
129 pcireg_t csr;
130 u_int16_t frontend_cr;
131 u_int16_t db0, db1;
132 u_int numports;
133
134 printf(": N2 Serial Interface\n");
135
136 /*
137 * Map in the ASIC configuration space
138 */
139 if (pci_mapreg_map(pa, PCI_CBMA_ASIC, PCI_MAPREG_TYPE_MEM, 0,
140 &sc->sc_asic_iot, &sc->sc_asic_ioh, NULL, NULL)) {
141 printf("%s: Can't map register space (ASIC)\n",
142 sc->sc_dev.dv_xname);
143 return;
144 }
145 /*
146 * Map in the serial controller configuration space
147 */
148 if (pci_mapreg_map(pa, PCI_CBMA_SCA, PCI_MAPREG_TYPE_MEM, 0,
149 &sca->sc_iot, &sca->sc_ioh, NULL, NULL)) {
150 printf("%s: Can't map register space (SCA)\n",
151 sc->sc_dev.dv_xname);
152 return;
153 }
154
155 /*
156 * Enable the card
157 */
158 csr = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
159 pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, csr);
160
161 /*
162 * Map and establish the interrupt
163 */
164 if (pci_intr_map(pa->pa_pc, pa->pa_intrtag, pa->pa_intrpin,
165 pa->pa_intrline, &ih)) {
166 printf("%s: couldn't map interrupt\n", sc->sc_dev.dv_xname);
167 return;
168 }
169 intrstr = pci_intr_string(pa->pa_pc, ih);
170 sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_NET, ntwoc_intr, sc);
171 if (sc->sc_ih == NULL) {
172 printf("%s: couldn't establish interrupt",
173 sc->sc_dev.dv_xname);
174 if (intrstr != NULL)
175 printf(" at %s", intrstr);
176 printf("\n");
177 return;
178 }
179 printf("%s: interrupting at %s\n", sc->sc_dev.dv_xname, intrstr);
180
181 /*
182 * Perform total black magic. This is not only extremely
183 * disgusting, but it should be explained a lot more in the
184 * card's documentation.
185 *
186 * From what I gather, this does nothing more than configure the
187 * PCI to ISA translator ASIC the N2pci card uses.
188 *
189 * From the FreeBSD driver:
190 * offset
191 * 0x00 - Map Range - Mem-mapped to locate anywhere
192 * 0x04 - Re-Map - PCI address decode enable
193 * 0x18 - Bus Region - 32-bit bus, ready enable
194 * 0x1c - Master Range - include all 16 MB
195 * 0x20 - Master RAM - Map SCA Base at 0
196 * 0x28 - Master Remap - direct master memory enable
197 * 0x68 - Interrupt - Enable interrupt (0 to disable)
198 */
199 bus_space_write_4(sc->sc_asic_iot, sc->sc_asic_ioh,
200 0x00, 0xfffff000);
201 bus_space_write_4(sc->sc_asic_iot, sc->sc_asic_ioh,
202 0x04, 1);
203 bus_space_write_4(sc->sc_asic_iot, sc->sc_asic_ioh,
204 0x18, 0x40030043);
205 bus_space_write_4(sc->sc_asic_iot, sc->sc_asic_ioh,
206 0x1c, 0xff000000);
207 bus_space_write_4(sc->sc_asic_iot, sc->sc_asic_ioh,
208 0x20, 0);
209 bus_space_write_4(sc->sc_asic_iot, sc->sc_asic_ioh,
210 0x28, 0xe9);
211 bus_space_write_4(sc->sc_asic_iot, sc->sc_asic_ioh,
212 0x68, 0x10900);
213
214 /*
215 * pass the dma tag to the SCA
216 */
217 sca->sc_dmat = pa->pa_dmat;
218
219 /*
220 * Read the configuration information off the daughter card.
221 */
222 frontend_cr = bus_space_read_2(sca->sc_iot, sca->sc_ioh, NTWOC_FECR);
223 NTWO_DPRINTF(("%s: frontend_cr = 0x%04x\n",
224 sc->sc_dev.dv_xname, frontend_cr));
225
226 db0 = (frontend_cr & NTWOC_FECR_ID0) >> NTWOC_FECR_ID0_SHIFT;
227 db1 = (frontend_cr & NTWOC_FECR_ID1) >> NTWOC_FECR_ID1_SHIFT;
228
229 /*
230 * Port 1 HAS to be present. If it isn't, don't attach anything.
231 */
232 if (db0 == NTWOC_FE_ID_NONE) {
233 printf("%s: no ports available\n", sc->sc_dev.dv_xname);
234 return;
235 }
236
237 /*
238 * Port 1 is present. Now, check to see if port 2 is also
239 * present.
240 */
241 numports = 1;
242 if (db1 != NTWOC_FE_ID_NONE)
243 numports++;
244
245 printf("%s: %d port%s\n", sc->sc_dev.dv_xname, numports,
246 (numports > 1 ? "s" : ""));
247 printf("%s: port 0 interface card: %s\n", sc->sc_dev.dv_xname,
248 ntwoc_db_names[db0]);
249 if (numports > 1)
250 printf("%s: port 1 interface card: %s\n", sc->sc_dev.dv_xname,
251 ntwoc_db_names[db1]);
252
253 /*
254 * enable the RS422 tristate transmit
255 * diable clock output (use receiver clock for both)
256 */
257 frontend_cr |= (NTWOC_FECR_TE0 | NTWOC_FECR_TE1);
258 frontend_cr &= ~(NTWOC_FECR_ETC0 | NTWOC_FECR_ETC1);
259 bus_space_write_2(sc->sc_sca.sc_iot, sc->sc_sca.sc_ioh,
260 NTWOC_FECR, frontend_cr);
261
262 /*
263 * initialize the SCA. This will allocate DMAable memory based
264 * on the number of ports we passed in, the size of each
265 * buffer, and the number of buffers per port.
266 */
267 sca->parent = &sc->sc_dev;
268 sca->dtr_callback = ntwoc_dtr_callback;
269 sca->dtr_aux = sc;
270 sca_init(sca, numports);
271
272 /*
273 * always initialize port 0, since we have to have found it to
274 * get this far. If we have two ports, attach the second
275 * as well.
276 */
277 sca_port_attach(sca, 0);
278 if (numports == 2)
279 sca_port_attach(sca, 1);
280
281 /*
282 * Add shutdown hook so that DMA is disabled prior to reboot. Not
283 * doing do could allow DMA to corrupt kernel memory during the
284 * reboot before the driver initializes.
285 */
286 shutdownhook_establish(ntwoc_shutdown, sc);
287 }
288
289 static int
290 ntwoc_intr(void *arg)
291 {
292 struct ntwoc_pci_softc *sc = (struct ntwoc_pci_softc *)arg;
293
294 return sca_hardintr(&sc->sc_sca);
295 }
296
297 /*
298 * shut down interrupts and DMA, so we don't trash the kernel on warm
299 * boot. Also, lower DTR on each port and disable card interrupts.
300 */
301 static void
302 ntwoc_shutdown(void *aux)
303 {
304 struct ntwoc_pci_softc *sc = aux;
305 u_int16_t fecr;
306
307 /*
308 * shut down the SCA ports
309 */
310 sca_shutdown(&sc->sc_sca);
311
312 /*
313 * disable interupts for the whole card. Black magic, see comment
314 * above.
315 */
316 bus_space_write_4(sc->sc_asic_iot, sc->sc_asic_ioh,
317 0x68, 0x10900);
318
319 /*
320 * lower DTR on both ports
321 */
322 fecr = bus_space_read_2(sc->sc_sca.sc_iot,
323 sc->sc_sca.sc_ioh, NTWOC_FECR);
324 fecr |= (NTWOC_FECR_DTR0 | NTWOC_FECR_DTR1);
325 bus_space_write_2(sc->sc_sca.sc_iot, sc->sc_sca.sc_ioh,
326 NTWOC_FECR, fecr);
327 }
328
329 static void
330 ntwoc_dtr_callback(void *aux, int port, int state)
331 {
332 struct ntwoc_pci_softc *sc = aux;
333 u_int16_t fecr;
334
335 fecr = bus_space_read_2(sc->sc_sca.sc_iot,
336 sc->sc_sca.sc_ioh, NTWOC_FECR);
337
338 NTWO_DPRINTF(("port == %d, state == %d, old fecr: 0x%04x\n",
339 port, state, fecr));
340
341 if (port == 0) {
342 if (state == 0)
343 fecr |= NTWOC_FECR_DTR0;
344 else
345 fecr &= ~NTWOC_FECR_DTR0;
346 } else {
347 if (state == 0)
348 fecr |= NTWOC_FECR_DTR1;
349 else
350 fecr &= ~NTWOC_FECR_DTR1;
351 }
352
353 NTWO_DPRINTF(("new fecr: 0x%04x\n", fecr));
354
355 bus_space_write_2(sc->sc_sca.sc_iot, sc->sc_sca.sc_ioh,
356 NTWOC_FECR, fecr);
357 }
358