1 /**	$MirOS: src/sys/dev/pcmcia/esp_pcmcia.c,v 1.3 2005/07/04 01:15:48 tg Exp $ */
2 /*	$OpenBSD: esp_pcmcia.c,v 1.5 2005/01/27 17:04:55 millert Exp $	*/
3 /*	$NetBSD: esp_pcmcia.c,v 1.8 2000/06/05 15:36:45 tsutsui Exp $	*/
4 
5 /*-
6  * Copyright (c) 2000 The NetBSD Foundation, Inc.
7  * All rights reserved.
8  *
9  * This code is derived from software contributed to The NetBSD Foundation
10  * by Charles M. Hannum.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  * 3. All advertising materials mentioning features or use of this software
21  *    must display the following acknowledgement:
22  *        This product includes software developed by the NetBSD
23  *        Foundation, Inc. and its contributors.
24  * 4. Neither the name of The NetBSD Foundation nor the names of its
25  *    contributors may be used to endorse or promote products derived
26  *    from this software without specific prior written permission.
27  *
28  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
29  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
30  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
32  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38  * POSSIBILITY OF SUCH DAMAGE.
39  */
40 
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/device.h>
44 #include <sys/buf.h>
45 
46 #include <machine/bus.h>
47 #include <machine/intr.h>
48 
49 #include <scsi/scsi_all.h>
50 #include <scsi/scsiconf.h>
51 
52 #include <dev/pcmcia/pcmciareg.h>
53 #include <dev/pcmcia/pcmciavar.h>
54 #include <dev/pcmcia/pcmciadevs.h>
55 
56 #include <dev/ic/ncr53c9xreg.h>
57 #include <dev/ic/ncr53c9xvar.h>
58 
59 struct esp_pcmcia_softc {
60 	struct ncr53c9x_softc	sc_ncr53c9x;	/* glue to MI code */
61 
62 	int		sc_active;		/* Pseudo-DMA state vars */
63 	int		sc_tc;
64 	int		sc_datain;
65 	size_t		sc_dmasize;
66 	size_t		sc_dmatrans;
67 	char		**sc_dmaaddr;
68 	size_t		*sc_pdmalen;
69 
70 	/* PCMCIA-specific goo. */
71 	struct pcmcia_io_handle sc_pcioh;	/* PCMCIA i/o space info */
72 	int sc_io_window;			/* our i/o window */
73 	struct pcmcia_function *sc_pf;		/* our PCMCIA function */
74 	void *sc_ih;				/* interrupt handler */
75 #ifdef ESP_PCMCIA_POLL
76 	struct callout sc_poll_ch;
77 #endif
78 	int sc_flags;
79 #define	ESP_PCMCIA_ATTACHED	1		/* attach completed */
80 #define ESP_PCMCIA_ATTACHING	2		/* attach in progress */
81 };
82 
83 int	esp_pcmcia_match(struct device *, void *, void *);
84 void	esp_pcmcia_attach(struct device *, struct device *, void *);
85 void	esp_pcmcia_init(struct esp_pcmcia_softc *);
86 int	esp_pcmcia_detach(struct device *, int);
87 int	esp_pcmcia_enable(void *, int);
88 
89 struct scsi_adapter esp_pcmcia_adapter = {
90 	ncr53c9x_scsi_cmd,	/* cmd */
91 	minphys,		/* minphys */
92 	0,			/* open */
93 	0,			/* close */
94 };
95 
96 struct cfattach esp_pcmcia_ca = {
97 	sizeof(struct esp_pcmcia_softc), esp_pcmcia_match, esp_pcmcia_attach
98 };
99 
100 /*
101  * Functions and the switch for the MI code.
102  */
103 #ifdef ESP_PCMCIA_POLL
104 void	esp_pcmcia_poll(void *);
105 #endif
106 u_char	esp_pcmcia_read_reg(struct ncr53c9x_softc *, int);
107 void	esp_pcmcia_write_reg(struct ncr53c9x_softc *, int, u_char);
108 int	esp_pcmcia_dma_isintr(struct ncr53c9x_softc *);
109 void	esp_pcmcia_dma_reset(struct ncr53c9x_softc *);
110 int	esp_pcmcia_dma_intr(struct ncr53c9x_softc *);
111 int	esp_pcmcia_dma_setup(struct ncr53c9x_softc *, caddr_t *,
112 	    size_t *, int, size_t *);
113 void	esp_pcmcia_dma_go(struct ncr53c9x_softc *);
114 void	esp_pcmcia_dma_stop(struct ncr53c9x_softc *);
115 int	esp_pcmcia_dma_isactive(struct ncr53c9x_softc *);
116 
117 struct ncr53c9x_glue esp_pcmcia_glue = {
118 	esp_pcmcia_read_reg,
119 	esp_pcmcia_write_reg,
120 	esp_pcmcia_dma_isintr,
121 	esp_pcmcia_dma_reset,
122 	esp_pcmcia_dma_intr,
123 	esp_pcmcia_dma_setup,
124 	esp_pcmcia_dma_go,
125 	esp_pcmcia_dma_stop,
126 	esp_pcmcia_dma_isactive,
127 	NULL,			/* gl_clear_latched_intr */
128 };
129 
130 struct esp_pcmcia_product {
131 	u_int16_t	app_vendor;		/* PCMCIA vendor ID */
132 	u_int16_t	app_product;		/* PCMCIA product ID */
133 	int		app_expfunc;		/* expected function number */
134 } esp_pcmcia_prod[] = {
135 	{ PCMCIA_VENDOR_PANASONIC, PCMCIA_PRODUCT_PANASONIC_KXLC002, 0 },
136 	{ PCMCIA_VENDOR_PANASONIC, PCMCIA_PRODUCT_PANASONIC_KME, 0 },
137 	{ PCMCIA_VENDOR_NEWMEDIA2, PCMCIA_PRODUCT_NEWMEDIA2_BUSTOASTER, 0 }
138 };
139 
140 int
esp_pcmcia_match(parent,match,aux)141 esp_pcmcia_match(parent, match, aux)
142 	struct device *parent;
143 	void *match, *aux;
144 {
145 	struct pcmcia_attach_args *pa = aux;
146 	int i;
147 
148 	for (i = 0; i < sizeof(esp_pcmcia_prod)/sizeof(esp_pcmcia_prod[0]); i++)
149 		if (pa->manufacturer == esp_pcmcia_prod[i].app_vendor &&
150 		    pa->product == esp_pcmcia_prod[i].app_product &&
151 		    pa->pf->number == esp_pcmcia_prod[i].app_expfunc)
152 			return (1);
153 	return (0);
154 }
155 
156 void
esp_pcmcia_attach(parent,self,aux)157 esp_pcmcia_attach(parent, self, aux)
158 	struct device *parent, *self;
159 	void *aux;
160 {
161 	struct esp_pcmcia_softc *esc = (void *)self;
162 	struct ncr53c9x_softc *sc = &esc->sc_ncr53c9x;
163 	struct pcmcia_attach_args *pa = aux;
164 	struct pcmcia_config_entry *cfe;
165 	struct pcmcia_function *pf = pa->pf;
166 	const char *intrstr;
167 
168 	esc->sc_pf = pf;
169 
170 	for (cfe = SIMPLEQ_FIRST(&pf->cfe_head); cfe != NULL;
171 	    cfe = SIMPLEQ_NEXT(cfe, cfe_list)) {
172 		if (cfe->num_memspace != 0 ||
173 		    cfe->num_iospace != 1)
174 			continue;
175 
176 		if (pcmcia_io_alloc(pa->pf, cfe->iospace[0].start,
177 		    cfe->iospace[0].length, 0, &esc->sc_pcioh) == 0)
178 			break;
179 	}
180 
181 	if (cfe == 0) {
182 		printf(": can't alloc i/o space\n");
183 		goto no_config_entry;
184 	}
185 
186 	/* Enable the card. */
187 	pcmcia_function_init(pf, cfe);
188 	if (pcmcia_function_enable(pf)) {
189 		printf(": function enable failed\n");
190 		goto enable_failed;
191 	}
192 
193 	/* Map in the I/O space */
194 	if (pcmcia_io_map(pa->pf, PCMCIA_WIDTH_AUTO, 0, esc->sc_pcioh.size,
195 	    &esc->sc_pcioh, &esc->sc_io_window)) {
196 		printf(": can't map i/o space\n");
197 		goto iomap_failed;
198 	}
199 
200 	printf(" port 0x%lx/%d", esc->sc_pcioh.addr, (int)(esc->sc_pcioh.size));
201 
202 	esp_pcmcia_init(esc);
203 
204 	esc->sc_ih = pcmcia_intr_establish(esc->sc_pf, IPL_BIO,
205 	    ncr53c9x_intr, &esc->sc_ncr53c9x, esc->sc_dev.dv_xname);
206 	intrstr = pcmcia_intr_string(psc->sc_pf, esc->sc_ih);
207 	if (esc->sc_ih == NULL) {
208 		printf(", %s\n", intrstr);
209 		goto iomap_failed;
210 	}
211 	if (*intrstr)
212 		printf(", %s", intrstr);
213 
214 	/*
215 	 *  Initialize nca board itself.
216 	 */
217 	esc->sc_flags |= ESP_PCMCIA_ATTACHING;
218 	ncr53c9x_attach(sc, &esp_pcmcia_adapter, NULL);
219 	esc->sc_flags &= ~ESP_PCMCIA_ATTACHING;
220 	esc->sc_flags |= ESP_PCMCIA_ATTACHED;
221 	return;
222 
223 iomap_failed:
224 	/* Disable the device. */
225 	pcmcia_function_disable(esc->sc_pf);
226 
227 enable_failed:
228 	/* Unmap our I/O space. */
229 	pcmcia_io_free(esc->sc_pf, &esc->sc_pcioh);
230 
231 no_config_entry:
232 	return;
233 }
234 
235 void
esp_pcmcia_init(esc)236 esp_pcmcia_init(esc)
237 	struct esp_pcmcia_softc *esc;
238 {
239 	struct ncr53c9x_softc *sc = &esc->sc_ncr53c9x;
240 	bus_space_tag_t iot = esc->sc_pcioh.iot;
241 	bus_space_handle_t ioh = esc->sc_pcioh.ioh;
242 
243 	/* id 7, clock 40M, parity ON, sync OFF, fast ON, slow ON */
244 
245 	sc->sc_glue = &esp_pcmcia_glue;
246 
247 #ifdef ESP_PCMCIA_POLL
248 	callout_init(&esc->sc_poll_ch);
249 #endif
250 
251 	sc->sc_rev = NCR_VARIANT_ESP406;
252 	sc->sc_id = 7;
253 	sc->sc_freq = 40;
254 	/* try -PARENB -SLOW */
255 	sc->sc_cfg1 = sc->sc_id | NCRCFG1_PARENB | NCRCFG1_SLOW;
256 	/* try +FE */
257 	sc->sc_cfg2 = NCRCFG2_SCSI2;
258 	/* try -IDM -FSCSI -FCLK */
259 	sc->sc_cfg3 = NCRESPCFG3_CDB | NCRESPCFG3_FCLK | NCRESPCFG3_IDM |
260 	    NCRESPCFG3_FSCSI;
261 	sc->sc_cfg4 = NCRCFG4_ACTNEG;
262 	/* try +INTP */
263 	sc->sc_cfg5 = NCRCFG5_CRS1 | NCRCFG5_AADDR | NCRCFG5_PTRINC;
264 	sc->sc_minsync = 0;
265 	sc->sc_maxxfer = 64 * 1024;
266 
267 	bus_space_write_1(iot, ioh, NCR_CFG5, sc->sc_cfg5);
268 
269 	bus_space_write_1(iot, ioh, NCR_PIOI, 0);
270 	bus_space_write_1(iot, ioh, NCR_PSTAT, 0);
271 	bus_space_write_1(iot, ioh, 0x09, 0x24);
272 
273 	bus_space_write_1(iot, ioh, NCR_CFG4, sc->sc_cfg4);
274 }
275 
276 #ifdef notyet
277 int
esp_pcmcia_detach(self,flags)278 esp_pcmcia_detach(self, flags)
279 	struct device *self;
280 	int flags;
281 {
282 	struct esp_pcmcia_softc *esc = (void *)self;
283 	int error;
284 
285 	if ((esc->sc_flags & ESP_PCMCIA_ATTACHED) == 0) {
286 		/* Nothing to detach. */
287 		return (0);
288 	}
289 
290 	error = ncr53c9x_detach(&esc->sc_ncr53c9x, flags);
291 	if (error)
292 		return (error);
293 
294 	/* Unmap our i/o window and i/o space. */
295 	pcmcia_io_unmap(esc->sc_pf, esc->sc_io_window);
296 	pcmcia_io_free(esc->sc_pf, &esc->sc_pcioh);
297 
298 	return (0);
299 }
300 #endif
301 
302 int
esp_pcmcia_enable(arg,onoff)303 esp_pcmcia_enable(arg, onoff)
304 	void *arg;
305 	int onoff;
306 {
307 	struct esp_pcmcia_softc *esc = arg;
308 
309 	if (onoff) {
310 #ifdef ESP_PCMCIA_POLL
311 		callout_reset(&esc->sc_poll_ch, 1, esp_pcmcia_poll, esc);
312 #else
313 		/* Establish the interrupt handler. */
314 		esc->sc_ih = pcmcia_intr_establish(esc->sc_pf, IPL_BIO,
315 		    ncr53c9x_intr, &esc->sc_ncr53c9x,
316 		    esc->sc_ncr53c9x.sc_dev.dv_xname);
317 		if (esc->sc_ih == NULL) {
318 			printf("%s: couldn't establish interrupt handler\n",
319 			    esc->sc_ncr53c9x.sc_dev.dv_xname);
320 			return (EIO);
321 		}
322 #endif
323 
324 		/*
325 		 * If attach is in progress, we know that card power is
326 		 * enabled and chip will be initialized later.
327 		 * Otherwise, enable and reset now.
328 		 */
329 		if ((esc->sc_flags & ESP_PCMCIA_ATTACHING) == 0) {
330 			if (pcmcia_function_enable(esc->sc_pf)) {
331 				printf("%s: couldn't enable PCMCIA function\n",
332 				    esc->sc_ncr53c9x.sc_dev.dv_xname);
333 				pcmcia_intr_disestablish(esc->sc_pf,
334 				    esc->sc_ih);
335 				return (EIO);
336 			}
337 
338 			/* Initialize only chip.  */
339 			ncr53c9x_init(&esc->sc_ncr53c9x, 0);
340 		}
341 	} else {
342 		pcmcia_function_disable(esc->sc_pf);
343 #ifdef ESP_PCMCIA_POLL
344 		callout_stop(&esc->sc_poll_ch);
345 #else
346 		pcmcia_intr_disestablish(esc->sc_pf, esc->sc_ih);
347 #endif
348 	}
349 
350 	return (0);
351 }
352 
353 #ifdef ESP_PCMCIA_POLL
354 void
esp_pcmcia_poll(arg)355 esp_pcmcia_poll(arg)
356 	void *arg;
357 {
358 	struct esp_pcmcia_softc *esc = arg;
359 
360 	(void) ncr53c9x_intr(&esc->sc_ncr53c9x);
361 	callout_reset(&esc->sc_poll_ch, 1, esp_pcmcia_poll, esc);
362 }
363 #endif
364 
365 /*
366  * Glue functions.
367  */
368 u_char
esp_pcmcia_read_reg(sc,reg)369 esp_pcmcia_read_reg(sc, reg)
370 	struct ncr53c9x_softc *sc;
371 	int reg;
372 {
373 	struct esp_pcmcia_softc *esc = (struct esp_pcmcia_softc *)sc;
374 	u_char v;
375 
376 	v = bus_space_read_1(esc->sc_pcioh.iot, esc->sc_pcioh.ioh, reg);
377 	return v;
378 }
379 
380 void
esp_pcmcia_write_reg(sc,reg,val)381 esp_pcmcia_write_reg(sc, reg, val)
382 	struct ncr53c9x_softc *sc;
383 	int reg;
384 	u_char val;
385 {
386 	struct esp_pcmcia_softc *esc = (struct esp_pcmcia_softc *)sc;
387 	u_char v = val;
388 
389 	if (reg == NCR_CMD && v == (NCRCMD_TRANS|NCRCMD_DMA))
390 		v = NCRCMD_TRANS;
391 	bus_space_write_1(esc->sc_pcioh.iot, esc->sc_pcioh.ioh, reg, v);
392 }
393 
394 int
esp_pcmcia_dma_isintr(sc)395 esp_pcmcia_dma_isintr(sc)
396 	struct ncr53c9x_softc *sc;
397 {
398 
399 	return NCR_READ_REG(sc, NCR_STAT) & NCRSTAT_INT;
400 }
401 
402 void
esp_pcmcia_dma_reset(sc)403 esp_pcmcia_dma_reset(sc)
404 	struct ncr53c9x_softc *sc;
405 {
406 	struct esp_pcmcia_softc *esc = (struct esp_pcmcia_softc *)sc;
407 
408 	esc->sc_active = 0;
409 	esc->sc_tc = 0;
410 }
411 
412 int
esp_pcmcia_dma_intr(sc)413 esp_pcmcia_dma_intr(sc)
414 	struct ncr53c9x_softc *sc;
415 {
416 	struct esp_pcmcia_softc *esc = (struct esp_pcmcia_softc *)sc;
417 	u_char	*p;
418 	u_int	espphase, espstat, espintr;
419 	int	cnt;
420 
421 	if (esc->sc_active == 0) {
422 		printf("%s: dma_intr--inactive DMA\n", sc->sc_dev.dv_xname);
423 		return -1;
424 	}
425 
426 	if ((sc->sc_espintr & NCRINTR_BS) == 0) {
427 		esc->sc_active = 0;
428 		return 0;
429 	}
430 
431 	cnt = *esc->sc_pdmalen;
432 	if (*esc->sc_pdmalen == 0) {
433 		printf("%s: data interrupt, but no count left\n",
434 		    sc->sc_dev.dv_xname);
435 	}
436 
437 	p = *esc->sc_dmaaddr;
438 	espphase = sc->sc_phase;
439 	espstat = (u_int) sc->sc_espstat;
440 	espintr = (u_int) sc->sc_espintr;
441 	do {
442 		if (esc->sc_datain) {
443 			*p++ = NCR_READ_REG(sc, NCR_FIFO);
444 			cnt--;
445 			if (espphase == DATA_IN_PHASE)
446 				NCR_WRITE_REG(sc, NCR_CMD, NCRCMD_TRANS);
447 			else
448 				esc->sc_active = 0;
449 	 	} else {
450 			if (espphase == DATA_OUT_PHASE ||
451 			    espphase == MESSAGE_OUT_PHASE) {
452 				NCR_WRITE_REG(sc, NCR_FIFO, *p++);
453 				cnt--;
454 				NCR_WRITE_REG(sc, NCR_CMD, NCRCMD_TRANS);
455 			} else
456 				esc->sc_active = 0;
457 		}
458 
459 		if (esc->sc_active) {
460 			while (!(NCR_READ_REG(sc, NCR_STAT) & NCRSTAT_INT));
461 			espstat = NCR_READ_REG(sc, NCR_STAT);
462 			espintr = NCR_READ_REG(sc, NCR_INTR);
463 			espphase = (espintr & NCRINTR_DIS)
464 				    ? /* Disconnected */ BUSFREE_PHASE
465 				    : espstat & PHASE_MASK;
466 		}
467 	} while (esc->sc_active && espintr);
468 	sc->sc_phase = espphase;
469 	sc->sc_espstat = (u_char) espstat;
470 	sc->sc_espintr = (u_char) espintr;
471 	*esc->sc_dmaaddr = p;
472 	*esc->sc_pdmalen = cnt;
473 
474 	if (*esc->sc_pdmalen == 0)
475 		esc->sc_tc = NCRSTAT_TC;
476 	sc->sc_espstat |= esc->sc_tc;
477 	return 0;
478 }
479 
480 int
esp_pcmcia_dma_setup(sc,addr,len,datain,dmasize)481 esp_pcmcia_dma_setup(sc, addr, len, datain, dmasize)
482 	struct ncr53c9x_softc *sc;
483 	caddr_t *addr;
484 	size_t *len;
485 	int datain;
486 	size_t *dmasize;
487 {
488 	struct esp_pcmcia_softc *esc = (struct esp_pcmcia_softc *)sc;
489 
490 	esc->sc_dmaaddr = addr;
491 	esc->sc_pdmalen = len;
492 	esc->sc_datain = datain;
493 	esc->sc_dmasize = *dmasize;
494 	esc->sc_tc = 0;
495 
496 	return 0;
497 }
498 
499 void
esp_pcmcia_dma_go(sc)500 esp_pcmcia_dma_go(sc)
501 	struct ncr53c9x_softc *sc;
502 {
503 	struct esp_pcmcia_softc *esc = (struct esp_pcmcia_softc *)sc;
504 
505 	esc->sc_active = 1;
506 }
507 
508 void
esp_pcmcia_dma_stop(sc)509 esp_pcmcia_dma_stop(sc)
510 	struct ncr53c9x_softc *sc;
511 {
512 }
513 
514 int
esp_pcmcia_dma_isactive(sc)515 esp_pcmcia_dma_isactive(sc)
516 	struct ncr53c9x_softc *sc;
517 {
518 	struct esp_pcmcia_softc *esc = (struct esp_pcmcia_softc *)sc;
519 
520 	return (esc->sc_active);
521 }
522