ppc.c revision 40565
1311116Sdim/*-
2311116Sdim * Copyright (c) 1997, 1998 Nicolas Souchu
3311116Sdim * All rights reserved.
4311116Sdim *
5311116Sdim * Redistribution and use in source and binary forms, with or without
6311116Sdim * modification, are permitted provided that the following conditions
7311116Sdim * are met:
8311116Sdim * 1. Redistributions of source code must retain the above copyright
9311116Sdim *    notice, this list of conditions and the following disclaimer.
10311116Sdim * 2. Redistributions in binary form must reproduce the above copyright
11341825Sdim *    notice, this list of conditions and the following disclaimer in the
12311116Sdim *    documentation and/or other materials provided with the distribution.
13311116Sdim *
14311116Sdim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15311116Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16311116Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17311116Sdim * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18311116Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19311116Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20311116Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21311116Sdim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22311116Sdim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23311116Sdim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24311116Sdim * SUCH DAMAGE.
25321369Sdim *
26311116Sdim *	$Id: ppc.c,v 1.9 1998/09/20 14:47:01 nsouch Exp $
27311116Sdim *
28311116Sdim */
29311116Sdim#include "ppc.h"
30327952Sdim
31311116Sdim#if NPPC > 0
32311116Sdim
33311116Sdim#include <sys/param.h>
34311116Sdim#include <sys/systm.h>
35311116Sdim#include <sys/conf.h>
36311116Sdim#include <sys/malloc.h>
37311116Sdim#include <sys/kernel.h>
38311116Sdim
39311116Sdim#include <machine/clock.h>
40311116Sdim
41311116Sdim#include <vm/vm.h>
42311116Sdim#include <vm/vm_param.h>
43311116Sdim#include <vm/pmap.h>
44311116Sdim
45311116Sdim#include <i386/isa/isa_device.h>
46311116Sdim
47311116Sdim#include <dev/ppbus/ppbconf.h>
48311116Sdim#include <dev/ppbus/ppb_msq.h>
49311116Sdim
50311116Sdim#include <i386/isa/ppcreg.h>
51311116Sdim
52311116Sdimstatic int	ppcprobe(struct isa_device *);
53311116Sdimstatic int	ppcattach(struct isa_device *);
54311116Sdim
55311116Sdimstruct isa_driver ppcdriver = {
56311116Sdim	ppcprobe, ppcattach, "ppc"
57341825Sdim};
58341825Sdim
59341825Sdimstatic struct ppc_data *ppcdata[NPPC];
60311116Sdimstatic int nppc = 0;
61311116Sdim
62311116Sdimstatic char *ppc_types[] = {
63311116Sdim	"SMC-like", "SMC FDC37C665GT", "SMC FDC37C666GT", "PC87332", "PC87306",
64311116Sdim	"82091AA", "Generic", "W83877F", "W83877AF", "Winbond", 0
65311116Sdim};
66311116Sdim
67344779Sdim/* list of available modes */
68344779Sdimstatic char *ppc_avms[] = {
69344779Sdim	"COMPATIBLE", "NIBBLE-only", "PS2-only", "PS2/NIBBLE", "EPP-only",
70344779Sdim	"EPP/NIBBLE", "EPP/PS2", "EPP/PS2/NIBBLE", "ECP-only",
71344779Sdim	"ECP/NIBBLE", "ECP/PS2", "ECP/PS2/NIBBLE", "ECP/EPP",
72344779Sdim	"ECP/EPP/NIBBLE", "ECP/EPP/PS2", "ECP/EPP/PS2/NIBBLE", 0
73344779Sdim};
74344779Sdim
75344779Sdim/* list of current executing modes
76344779Sdim * Note that few modes do not actually exist.
77344779Sdim */
78344779Sdimstatic char *ppc_modes[] = {
79344779Sdim	"COMPATIBLE", "NIBBLE", "PS/2", "PS/2", "EPP",
80344779Sdim	"EPP", "EPP", "EPP", "ECP",
81344779Sdim	"ECP", "ECP+PS2", "ECP+PS2", "ECP+EPP",
82344779Sdim	"ECP+EPP", "ECP+EPP", "ECP+EPP", 0
83344779Sdim};
84344779Sdim
85344779Sdimstatic char *ppc_epp_protocol[] = { " (EPP 1.9)", " (EPP 1.7)", 0 };
86344779Sdim
87344779Sdim/*
88344779Sdim * BIOS printer list - used by BIOS probe.
89344779Sdim */
90344779Sdim#define	BIOS_PPC_PORTS	0x408
91311116Sdim#define	BIOS_PORTS	(short *)(KERNBASE+BIOS_PPC_PORTS)
92311116Sdim#define	BIOS_MAX_PPC	4
93311116Sdim
94311116Sdim/*
95311116Sdim * All these functions are default actions for IN/OUT operations.
96311116Sdim * They may be redefined if needed.
97311116Sdim */
98311116Sdimstatic void ppc_outsb_epp(int unit, char *addr, int cnt) {
99311116Sdim	outsb(ppcdata[unit]->ppc_base + PPC_EPP_DATA, addr, cnt); }
100341825Sdimstatic void ppc_outsw_epp(int unit, char *addr, int cnt) {
101344779Sdim	outsw(ppcdata[unit]->ppc_base + PPC_EPP_DATA, addr, cnt); }
102311116Sdimstatic void ppc_outsl_epp(int unit, char *addr, int cnt) {
103311116Sdim	outsl(ppcdata[unit]->ppc_base + PPC_EPP_DATA, addr, cnt); }
104311116Sdimstatic void ppc_insb_epp(int unit, char *addr, int cnt) {
105311116Sdim	insb(ppcdata[unit]->ppc_base + PPC_EPP_DATA, addr, cnt); }
106311116Sdimstatic void ppc_insw_epp(int unit, char *addr, int cnt) {
107311116Sdim	insw(ppcdata[unit]->ppc_base + PPC_EPP_DATA, addr, cnt); }
108311116Sdimstatic void ppc_insl_epp(int unit, char *addr, int cnt) {
109311116Sdim	insl(ppcdata[unit]->ppc_base + PPC_EPP_DATA, addr, cnt); }
110341825Sdim
111311116Sdimstatic char ppc_rdtr(int unit) { return r_dtr(ppcdata[unit]); }
112311116Sdimstatic char ppc_rstr(int unit) { return r_str(ppcdata[unit]); }
113311116Sdimstatic char ppc_rctr(int unit) { return r_ctr(ppcdata[unit]); }
114311116Sdimstatic char ppc_repp(int unit) { return r_epp(ppcdata[unit]); }
115311116Sdimstatic char ppc_recr(int unit) { return r_ecr(ppcdata[unit]); }
116311116Sdimstatic char ppc_rfifo(int unit) { return r_fifo(ppcdata[unit]); }
117321369Sdim
118311116Sdimstatic void ppc_wdtr(int unit, char byte) { w_dtr(ppcdata[unit], byte); }
119321369Sdimstatic void ppc_wstr(int unit, char byte) { w_str(ppcdata[unit], byte); }
120321369Sdimstatic void ppc_wctr(int unit, char byte) { w_ctr(ppcdata[unit], byte); }
121321369Sdimstatic void ppc_wepp(int unit, char byte) { w_epp(ppcdata[unit], byte); }
122311116Sdimstatic void ppc_wecr(int unit, char byte) { w_ecr(ppcdata[unit], byte); }
123311116Sdimstatic void ppc_wfifo(int unit, char byte) { w_fifo(ppcdata[unit], byte); }
124321369Sdim
125311116Sdimstatic void ppc_reset_epp_timeout(int);
126321369Sdimstatic void ppc_ecp_sync(int);
127344779Sdimstatic ointhand2_t ppcintr;
128344779Sdim
129321369Sdimstatic int ppc_exec_microseq(int, struct ppb_microseq **);
130321369Sdimstatic int ppc_generic_setmode(int, int);
131311116Sdimstatic int ppc_smclike_setmode(int, int);
132321369Sdim
133321369Sdimstatic struct ppb_adapter ppc_smclike_adapter = {
134321369Sdim
135321369Sdim	0,	/* no intr handler, filled by chipset dependent code */
136321369Sdim
137321369Sdim	ppc_reset_epp_timeout, ppc_ecp_sync,
138341825Sdim
139311116Sdim	ppc_exec_microseq,
140311116Sdim
141311116Sdim	ppc_smclike_setmode,
142311116Sdim
143311116Sdim	ppc_outsb_epp, ppc_outsw_epp, ppc_outsl_epp,
144341825Sdim	ppc_insb_epp, ppc_insw_epp, ppc_insl_epp,
145311116Sdim
146311116Sdim	ppc_rdtr, ppc_rstr, ppc_rctr, ppc_repp, ppc_recr, ppc_rfifo,
147311116Sdim	ppc_wdtr, ppc_wstr, ppc_wctr, ppc_wepp, ppc_wecr, ppc_wfifo
148};
149
150static struct ppb_adapter ppc_generic_adapter = {
151
152	0,	/* no intr handler, filled by chipset dependent code */
153
154	ppc_reset_epp_timeout, ppc_ecp_sync,
155
156	ppc_exec_microseq,
157
158	ppc_generic_setmode,
159
160	ppc_outsb_epp, ppc_outsw_epp, ppc_outsl_epp,
161	ppc_insb_epp, ppc_insw_epp, ppc_insl_epp,
162
163	ppc_rdtr, ppc_rstr, ppc_rctr, ppc_repp, ppc_recr, ppc_rfifo,
164	ppc_wdtr, ppc_wstr, ppc_wctr, ppc_wepp, ppc_wecr, ppc_wfifo
165};
166
167/*
168 * ppc_ecp_sync()		XXX
169 */
170static void
171ppc_ecp_sync(int unit) {
172
173	struct ppc_data *ppc = ppcdata[unit];
174	int i, r;
175
176	r = r_ecr(ppc);
177	if ((r & 0xe0) != 0x80)
178		return;
179
180	for (i = 0; i < 100; i++) {
181		r = r_ecr(ppc);
182		if (r & 0x1)
183			return;
184		DELAY(100);
185	}
186
187	printf("ppc%d: ECP sync failed as data still " \
188		"present in FIFO.\n", unit);
189
190	return;
191}
192
193static void
194ppcintr(int unit)
195{
196	/* call directly upper code */
197	ppb_intr(&ppcdata[unit]->ppc_link);
198
199	return;
200}
201
202static int
203ppc_detect_port(struct ppc_data *ppc)
204{
205
206	w_ctr(ppc, 0x0c);	/* To avoid missing PS2 ports */
207	w_dtr(ppc, 0xaa);
208	if (r_dtr(ppc) != (char) 0xaa)
209		return (0);
210
211	return (1);
212}
213
214/*
215 * ppc_pc873xx_detect
216 *
217 * Probe for a Natsemi PC873xx-family part.
218 *
219 * References in this function are to the National Semiconductor
220 * PC87332 datasheet TL/C/11930, May 1995 revision.
221 */
222static int pc873xx_basetab[] = {0x0398, 0x026e, 0x015c, 0x002e, 0};
223static int pc873xx_porttab[] = {0x0378, 0x03bc, 0x0278, 0};
224
225static int
226ppc_pc873xx_detect(struct ppc_data *ppc, int chipset_mode)	/* XXX mode never forced */
227{
228    static int	index = 0;
229    int		base, idport;
230    int		val;
231
232    while ((idport = pc873xx_basetab[index++])) {
233
234	/* XXX should check first to see if this location is already claimed */
235
236	/*
237	 * Pull the 873xx through the power-on ID cycle (2.2,1.).  We can't use this
238	 * to locate the chip as it may already have been used by the BIOS.
239	 */
240	(void)inb(idport); (void)inb(idport); (void)inb(idport); (void)inb(idport);
241
242	/*
243	 * Read the SID byte.  Possible values are :
244	 *
245	 * 0001xxxx	PC87332
246	 * 01110xxx	PC87306
247	 */
248	outb(idport, PC873_SID);
249	val = inb(idport + 1);
250	if ((val & 0xf0) == 0x10) {
251	    ppc->ppc_type = NS_PC87332;
252	} else if ((val & 0xf8) == 0x70) {
253	    ppc->ppc_type = NS_PC87306;
254	} else {
255	    if (bootverbose && (val != 0xff))
256		printf("PC873xx probe at 0x%x got unknown ID 0x%x\n", idport, val);
257	    continue ;		/* not recognised */
258	}
259
260	/*
261	 * We think we have one.  Is it enabled and where we want it to be?
262	 */
263	outb(idport, PC873_FER);
264	val = inb(idport + 1);
265	if (!(val & PC873_PPENABLE)) {
266	    if (bootverbose)
267		printf("PC873xx parallel port disabled\n");
268	    continue;
269	}
270	outb(idport, PC873_FAR);
271	val = inb(idport + 1) & 0x3;
272	/* XXX we should create a driver instance for every port found */
273	if (pc873xx_porttab[val] != ppc->ppc_base) {
274	    if (bootverbose)
275		printf("PC873xx at 0x%x not for driver at port 0x%x\n",
276		       pc873xx_porttab[val], ppc->ppc_base);
277	    continue;
278	}
279
280	/*
281	 * This is the port we want.  Can we dink with it to improve
282	 * our chances?
283	 */
284	outb(idport, PC873_PTR);
285	val = inb(idport + 1);
286	if (val & PC873_CFGLOCK) {
287	    if (bootverbose)
288		printf("PC873xx locked\n");
289
290	    /* work out what mode we're in */
291	    ppc->ppc_avm |= PPB_NIBBLE;		/* worst case */
292
293	    outb(idport, PC873_PCR);
294	    val = inb(idport + 1);
295	    if ((val & PC873_EPPEN) && (val & PC873_EPP19)) {
296		outb(idport, PC873_PTR);
297		val = inb(idport + 1);
298		if (!(val & PC873_EPPRDIR)) {
299		    ppc->ppc_avm |= PPB_EPP;	/* As we would have done it anwyay */
300		}
301	    } else if ((val & PC873_ECPEN) && (val & PC873_ECPCLK)) {
302		ppc->ppc_avm |= PPB_PS2;	/* tolerable alternative */
303	    }
304	} else {
305	    if (bootverbose)
306		printf("PC873xx unlocked, ");
307
308#if 0	/* broken */
309	    /*
310	     * Frob the zero-wait-state option if possible; it causes
311	     * unreliable operation.
312	     */
313	    outb(idport, PC873_FCR);
314	    val = inb(idport + 1);
315	    if ((ppc->ppc_type == NS_PC87306) ||	/* we are a '306 */
316		!(val & PC873_ZWSPWDN)) {		/* or pin _is_ ZWS */
317		val &= ~PC873_ZWS;
318		outb(idport + 1, val);			/* must disable ZWS */
319		outb(idport + 1, val);
320
321		if (bootverbose)
322		    printf("ZWS %s, ", (val & PC873_ZWS) ? "enabled" : "disabled");
323	    }
324
325#endif
326	    if (bootverbose)
327		printf("reconfiguring for ");
328
329	    /*
330	     * if the chip is at 0x3bc, we can't use EPP as there's no room
331	     * for the extra registers.
332	     *
333	     * XXX should we use ECP mode always and use the EPP submode?
334	     */
335	    if (ppc->ppc_base != 0x3bc) {
336		if (bootverbose)
337		    printf("EPP 1.9\n");
338
339		/* configure for EPP 1.9 operation XXX should be configurable */
340		outb(idport, PC873_PCR);
341		val = inb(idport + 1);
342		val &= ~(PC873_ECPEN | PC873_ECPCLK);	/* disable ECP */
343		val |= (PC873_EPPEN | PC873_EPP19);	/* enable EPP */
344		outb(idport + 1, val);
345		outb(idport + 1, val);
346
347		/* enable automatic direction turnover */
348		outb(idport, PC873_PTR);
349		val = inb(idport + 1);
350		val &= ~PC873_EPPRDIR;			/* disable "regular" direction change */
351		outb(idport + 1, val);
352		outb(idport + 1, val);
353
354		/* we are an EPP-32 port */
355		ppc->ppc_avm |= PPB_EPP;
356	    } else {
357		if (bootverbose)
358		    printf("ECP\n");
359
360		/* configure as an ECP port to get bidirectional operation for now */
361		outb(idport, PC873_PCR);
362		outb(idport + 1, inb(idport + 1) | PC873_ECPEN | PC873_ECPCLK);
363
364		/* we look like a PS/2 port */
365		ppc->ppc_avm |= PPB_PS2;
366	    }
367	}
368
369	return(chipset_mode);
370    }
371    return(-1);
372}
373
374static int
375ppc_check_epp_timeout(struct ppc_data *ppc)
376{
377	ppc_reset_epp_timeout(ppc->ppc_unit);
378
379	return (!(r_str(ppc) & TIMEOUT));
380}
381
382/*
383 * ppc_smc37c66xgt_detect
384 *
385 * SMC FDC37C66xGT configuration.
386 */
387static int
388ppc_smc37c66xgt_detect(struct ppc_data *ppc, int chipset_mode)
389{
390	int s, i;
391	char r;
392	int type = -1;
393	int csr = SMC66x_CSR;	/* initial value is 0x3F0 */
394
395	int port_address[] = { -1 /* disabled */ , 0x3bc, 0x378, 0x278 };
396
397
398#define cio csr+1	/* config IO port is either 0x3F1 or 0x371 */
399
400	/*
401	 * Detection: enter configuration mode and read CRD register.
402	 */
403
404	s = splhigh();
405	outb(csr, SMC665_iCODE);
406	outb(csr, SMC665_iCODE);
407	splx(s);
408
409	outb(csr, 0xd);
410	if (inb(cio) == 0x65) {
411		type = SMC_37C665GT;
412		goto config;
413	}
414
415	for (i = 0; i < 2; i++) {
416		s = splhigh();
417		outb(csr, SMC666_iCODE);
418		outb(csr, SMC666_iCODE);
419		splx(s);
420
421		outb(csr, 0xd);
422		if (inb(cio) == 0x66) {
423			type = SMC_37C666GT;
424			break;
425		}
426
427		/* Another chance, CSR may be hard-configured to be at 0x370 */
428		csr = SMC666_CSR;
429	}
430
431config:
432	/*
433	 * If chipset not found, do not continue.
434	 */
435	if (type == -1)
436		return (-1);
437
438	/* select CR1 */
439	outb(csr, 0x1);
440
441	/* read the port's address: bits 0 and 1 of CR1 */
442	r = inb(cio) & SMC_CR1_ADDR;
443	if (port_address[r] != ppc->ppc_base)
444		return (-1);
445
446	ppc->ppc_type = type;
447
448	/*
449	 * CR1 and CR4 registers bits 3 and 0/1 for mode configuration
450	 * If SPP mode is detected, try to set ECP+EPP mode
451	 */
452
453	if (bootverbose) {
454		outb(csr, 0x1);
455		printf("ppc%d: SMC registers CR1=0x%x", ppc->ppc_unit,
456			inb(cio) & 0xff);
457
458		outb(csr, 0x4);
459		printf(" CR4=0x%x", inb(cio) & 0xff);
460	}
461
462	/* select CR1 */
463	outb(csr, 0x1);
464
465	if (!chipset_mode) {
466		/* autodetect mode */
467
468		/* 666GT is ~certainly~ hardwired to an extended ECP+EPP mode */
469		if (type == SMC_37C666GT) {
470			ppc->ppc_avm |= PPB_ECP | PPB_EPP | PPB_SPP;
471			if (bootverbose)
472				printf(" configuration hardwired, supposing " \
473					"ECP+EPP SPP");
474
475		} else
476		   if ((inb(cio) & SMC_CR1_MODE) == 0) {
477			/* already in extended parallel port mode, read CR4 */
478			outb(csr, 0x4);
479			r = (inb(cio) & SMC_CR4_EMODE);
480
481			switch (r) {
482			case SMC_SPP:
483				ppc->ppc_avm |= PPB_SPP;
484				if (bootverbose)
485					printf(" SPP");
486				break;
487
488			case SMC_EPPSPP:
489				ppc->ppc_avm |= PPB_EPP | PPB_SPP;
490				if (bootverbose)
491					printf(" EPP SPP");
492				break;
493
494			case SMC_ECP:
495				ppc->ppc_avm |= PPB_ECP | PPB_SPP;
496				if (bootverbose)
497					printf(" ECP SPP");
498				break;
499
500			case SMC_ECPEPP:
501				ppc->ppc_avm |= PPB_ECP | PPB_EPP | PPB_SPP;
502				if (bootverbose)
503					printf(" ECP+EPP SPP");
504				break;
505			}
506		   } else {
507			/* not an extended port mode */
508			ppc->ppc_avm |= PPB_SPP;
509			if (bootverbose)
510				printf(" SPP");
511		   }
512
513	} else {
514		/* mode forced */
515		ppc->ppc_avm = chipset_mode;
516
517		/* 666GT is ~certainly~ hardwired to an extended ECP+EPP mode */
518		if (type == SMC_37C666GT)
519			goto end_detect;
520
521		r = inb(cio);
522		if ((chipset_mode & (PPB_ECP | PPB_EPP)) == 0) {
523			/* do not use ECP when the mode is not forced to */
524			outb(cio, r | SMC_CR1_MODE);
525			if (bootverbose)
526				printf(" SPP");
527		} else {
528			/* an extended mode is selected */
529			outb(cio, r & ~SMC_CR1_MODE);
530
531			/* read CR4 register and reset mode field */
532			outb(csr, 0x4);
533			r = inb(cio) & ~SMC_CR4_EMODE;
534
535			if (chipset_mode & PPB_ECP) {
536				if (chipset_mode & PPB_EPP) {
537					outb(cio, r | SMC_ECPEPP);
538					if (bootverbose)
539						printf(" ECP+EPP");
540				} else {
541					outb(cio, r | SMC_ECP);
542					if (bootverbose)
543						printf(" ECP");
544				}
545			} else {
546				/* PPB_EPP is set */
547				outb(cio, r | SMC_EPPSPP);
548				if (bootverbose)
549					printf(" EPP SPP");
550			}
551		}
552		ppc->ppc_avm = chipset_mode;
553	}
554
555end_detect:
556
557	if (bootverbose)
558		printf ("\n");
559
560	if (ppc->ppc_avm & PPB_EPP) {
561		/* select CR4 */
562		outb(csr, 0x4);
563		r = inb(cio);
564
565		/*
566		 * Set the EPP protocol...
567		 * Low=EPP 1.9 (1284 standard) and High=EPP 1.7
568		 */
569		if (ppc->ppc_epp == EPP_1_9)
570			outb(cio, (r & ~SMC_CR4_EPPTYPE));
571		else
572			outb(cio, (r | SMC_CR4_EPPTYPE));
573	}
574
575	/* end config mode */
576	outb(csr, 0xaa);
577
578	ppc->ppc_link.adapter = &ppc_smclike_adapter;
579	ppc_smclike_setmode(ppc->ppc_unit, chipset_mode);
580
581	return (chipset_mode);
582}
583
584/*
585 * Winbond W83877F stuff
586 *
587 * EFER: extended function enable register
588 * EFIR: extended function index register
589 * EFDR: extended function data register
590 */
591#define efir ((efer == 0x250) ? 0x251 : 0x3f0)
592#define efdr ((efer == 0x250) ? 0x252 : 0x3f1)
593
594static int w83877f_efers[] = { 0x250, 0x3f0, 0x3f0, 0x250 };
595static int w83877f_keys[] = { 0x89, 0x86, 0x87, 0x88 };
596static int w83877f_keyiter[] = { 1, 2, 2, 1 };
597static int w83877f_hefs[] = { WINB_HEFERE, WINB_HEFRAS, WINB_HEFERE | WINB_HEFRAS, 0 };
598
599static int
600ppc_w83877f_detect(struct ppc_data *ppc, int chipset_mode)
601{
602	int i, j, efer, base;
603	unsigned char r, hefere, hefras;
604
605	for (i = 0; i < 4; i ++) {
606		/* first try to enable configuration registers */
607		efer = w83877f_efers[i];
608
609		/* write the key to the EFER */
610		for (j = 0; j < w83877f_keyiter[i]; j ++)
611			outb (efer, w83877f_keys[i]);
612
613		/* then check HEFERE and HEFRAS bits */
614		outb (efir, 0x0c);
615		hefere = inb(efdr) & WINB_HEFERE;
616
617		outb (efir, 0x16);
618		hefras = inb(efdr) & WINB_HEFRAS;
619
620		/*
621		 * HEFRAS	HEFERE
622		 *   0		   1	write 89h to 250h (power-on default)
623		 *   1		   0	write 86h twice to 3f0h
624		 *   1		   1	write 87h twice to 3f0h
625		 *   0		   0	write 88h to 250h
626		 */
627		if ((hefere | hefras) == w83877f_hefs[i])
628			goto found;
629	}
630
631	return (-1);	/* failed */
632
633found:
634	/* check base port address - read from CR23 */
635	outb(efir, 0x23);
636	if (ppc->ppc_base != inb(efdr) * 4)		/* 4 bytes boundaries */
637		return (-1);
638
639	/* read CHIP ID from CR9/bits0-3 */
640	outb(efir, 0x9);
641
642	switch (inb(efdr) & WINB_CHIPID) {
643		case WINB_W83877F_ID:
644			ppc->ppc_type = WINB_W83877F;
645			break;
646
647		case WINB_W83877AF_ID:
648			ppc->ppc_type = WINB_W83877AF;
649			break;
650
651		default:
652			ppc->ppc_type = WINB_UNKNOWN;
653	}
654
655	if (bootverbose) {
656		/* dump of registers */
657		printf("ppc%d: 0x%x - ", ppc->ppc_unit, w83877f_keys[i]);
658		for (i = 0; i <= 0xd; i ++) {
659			outb(efir, i);
660			printf("0x%x ", inb(efdr));
661		}
662		for (i = 0x10; i <= 0x17; i ++) {
663			outb(efir, i);
664			printf("0x%x ", inb(efdr));
665		}
666		outb(efir, 0x1e);
667		printf("0x%x ", inb(efdr));
668		for (i = 0x20; i <= 0x29; i ++) {
669			outb(efir, i);
670			printf("0x%x ", inb(efdr));
671		}
672		printf("\n");
673		printf("ppc%d:", ppc->ppc_unit);
674	}
675
676	ppc->ppc_link.adapter = &ppc_generic_adapter;
677
678	if (!chipset_mode) {
679		/* autodetect mode */
680
681		/* select CR0 */
682		outb(efir, 0x0);
683		r = inb(efdr) & (WINB_PRTMODS0 | WINB_PRTMODS1);
684
685		/* select CR9 */
686		outb(efir, 0x9);
687		r |= (inb(efdr) & WINB_PRTMODS2);
688
689		switch (r) {
690		case WINB_W83757:
691			if (bootverbose)
692				printf("ppc%d: W83757 compatible mode\n",
693					ppc->ppc_unit);
694			return (-1);	/* generic or SMC-like */
695
696		case WINB_EXTFDC:
697		case WINB_EXTADP:
698		case WINB_EXT2FDD:
699		case WINB_JOYSTICK:
700			if (bootverbose)
701				printf(" not in parallel port mode\n");
702			return (-1);
703
704		case (WINB_PARALLEL | WINB_EPP_SPP):
705			ppc->ppc_avm |= PPB_EPP | PPB_SPP;
706			if (bootverbose)
707				printf(" EPP SPP");
708			break;
709
710		case (WINB_PARALLEL | WINB_ECP):
711			ppc->ppc_avm |= PPB_ECP | PPB_SPP;
712			if (bootverbose)
713				printf(" ECP SPP");
714			break;
715
716		case (WINB_PARALLEL | WINB_ECP_EPP):
717			ppc->ppc_avm |= PPB_ECP | PPB_EPP | PPB_SPP;
718			ppc->ppc_link.adapter = &ppc_smclike_adapter;
719
720			if (bootverbose)
721				printf(" ECP+EPP SPP");
722			break;
723		default:
724			printf("%s: unknown case (0x%x)!\n", __FUNCTION__, r);
725		}
726
727	} else {
728		/* mode forced */
729
730		/* select CR9 and set PRTMODS2 bit */
731		outb(efir, 0x9);
732		outb(efdr, inb(efdr) & ~WINB_PRTMODS2);
733
734		/* select CR0 and reset PRTMODSx bits */
735		outb(efir, 0x0);
736		outb(efdr, inb(efdr) & ~(WINB_PRTMODS0 | WINB_PRTMODS1));
737
738		if (chipset_mode & PPB_ECP) {
739			if (chipset_mode & PPB_EPP) {
740				outb(efdr, inb(efdr) | WINB_ECP_EPP);
741				if (bootverbose)
742					printf(" ECP+EPP");
743
744				ppc->ppc_link.adapter = &ppc_smclike_adapter;
745
746			} else {
747				outb(efdr, inb(efdr) | WINB_ECP);
748				if (bootverbose)
749					printf(" ECP");
750			}
751		} else {
752			/* select EPP_SPP otherwise */
753			outb(efdr, inb(efdr) | WINB_EPP_SPP);
754			if (bootverbose)
755				printf(" EPP SPP");
756		}
757		ppc->ppc_avm = chipset_mode;
758	}
759
760	if (bootverbose)
761		printf("\n");
762
763	/* exit configuration mode */
764	outb(efer, 0xaa);
765
766	ppc->ppc_link.adapter->setmode(ppc->ppc_unit, chipset_mode);
767
768	return (chipset_mode);
769}
770
771/*
772 * ppc_generic_detect
773 */
774static int
775ppc_generic_detect(struct ppc_data *ppc, int chipset_mode)
776{
777	char save_control;
778
779	/* default to generic */
780	ppc->ppc_link.adapter = &ppc_generic_adapter;
781
782	if (bootverbose)
783		printf("ppc%d:", ppc->ppc_unit);
784
785	if (!chipset_mode) {
786		/* first, check for ECP */
787		w_ecr(ppc, 0x20);
788		if ((r_ecr(ppc) & 0xe0) == 0x20) {
789			ppc->ppc_avm |= PPB_ECP | PPB_SPP;
790			if (bootverbose)
791				printf(" ECP SPP");
792
793			/* search for SMC style ECP+EPP mode */
794			w_ecr(ppc, 0x80);
795		}
796
797		/* try to reset EPP timeout bit */
798		if (ppc_check_epp_timeout(ppc)) {
799			ppc->ppc_avm |= PPB_EPP;
800
801			if (ppc->ppc_avm & PPB_ECP) {
802				/* SMC like chipset found */
803				ppc->ppc_type = SMC_LIKE;
804				ppc->ppc_link.adapter = &ppc_smclike_adapter;
805
806				if (bootverbose)
807					printf(" ECP+EPP");
808			} else {
809				if (bootverbose)
810					printf(" EPP");
811			}
812		} else {
813			/* restore to standard mode */
814			w_ecr(ppc, 0x0);
815		}
816
817		/* XXX try to detect NIBBLE and PS2 modes */
818		ppc->ppc_avm |= PPB_NIBBLE;
819
820		if (bootverbose)
821			printf(" SPP");
822
823	} else {
824		ppc->ppc_avm = chipset_mode;
825	}
826
827	if (bootverbose)
828		printf("\n");
829
830	ppc->ppc_link.adapter->setmode(ppc->ppc_unit, chipset_mode);
831
832	return (chipset_mode);
833}
834
835/*
836 * ppc_detect()
837 *
838 * mode is the mode suggested at boot
839 */
840static int
841ppc_detect(struct ppc_data *ppc, int chipset_mode) {
842
843	int i, mode;
844
845	/* list of supported chipsets */
846	int (*chipset_detect[])(struct ppc_data *, int) = {
847		ppc_pc873xx_detect,
848		ppc_smc37c66xgt_detect,
849		ppc_w83877f_detect,
850		ppc_generic_detect,
851		NULL
852	};
853
854	/* if can't find the port and mode not forced return error */
855	if (!ppc_detect_port(ppc) && chipset_mode == 0)
856		return (EIO);			/* failed, port not present */
857
858	/* assume centronics compatible mode is supported */
859	ppc->ppc_avm = PPB_COMPATIBLE;
860
861	/* we have to differenciate available chipset modes,
862	 * chipset running modes and IEEE-1284 operating modes
863	 *
864	 * after detection, the port must support running in compatible mode
865	 */
866	for (i=0; chipset_detect[i] != NULL; i++) {
867		if ((mode = chipset_detect[i](ppc, chipset_mode)) != -1) {
868			ppc->ppc_mode = mode;
869			break;
870		}
871	}
872
873	return (0);
874}
875
876/*
877 * ppc_exec_microseq()
878 *
879 * Execute a microsequence.
880 * Microsequence mechanism is supposed to handle fast I/O operations.
881 */
882static int
883ppc_exec_microseq(int unit, struct ppb_microseq **p_msq)
884{
885	struct ppc_data	*ppc = ppcdata[unit];
886	struct ppb_microseq *mi;
887	char cc, *p;
888	int i, iter, len;
889	int error;
890
891	register int reg;
892	register char mask;
893	register int accum = 0;
894	register char *ptr = 0;
895
896	struct ppb_microseq *stack = 0;
897
898/* microsequence registers are equivalent to PC-like port registers */
899#define r_reg(register,ppc) ((char)inb((ppc)->ppc_base + register))
900#define w_reg(register,ppc,byte) outb((ppc)->ppc_base + register, byte)
901
902#define INCR_PC (mi ++)		/* increment program counter */
903
904	mi = *p_msq;
905	for (;;) {
906		switch (mi->opcode) {
907		case MS_OP_RSET:
908			cc = r_reg(mi->arg[0].i, ppc);
909			cc &= (char)mi->arg[2].i;	/* clear mask */
910			cc |= (char)mi->arg[1].i;	/* assert mask */
911                        w_reg(mi->arg[0].i, ppc, cc);
912			INCR_PC;
913                        break;
914
915		case MS_OP_RASSERT_P:
916			reg = mi->arg[1].i;
917			ptr = ppc->ppc_ptr;
918
919			if ((len = mi->arg[0].i) == MS_ACCUM) {
920				accum = ppc->ppc_accum;
921				for (; accum; accum--)
922					w_reg(reg, ppc, *ptr++);
923				ppc->ppc_accum = accum;
924			} else
925				for (i=0; i<len; i++)
926					w_reg(reg, ppc, *ptr++);
927			ppc->ppc_ptr = ptr;
928
929			INCR_PC;
930			break;
931
932                case MS_OP_RFETCH_P:
933			reg = mi->arg[1].i;
934			mask = (char)mi->arg[2].i;
935			ptr = ppc->ppc_ptr;
936
937			if ((len = mi->arg[0].i) == MS_ACCUM) {
938				accum = ppc->ppc_accum;
939				for (; accum; accum--)
940					*ptr++ = r_reg(reg, ppc) & mask;
941				ppc->ppc_accum = accum;
942			} else
943				for (i=0; i<len; i++)
944					*ptr++ = r_reg(reg, ppc) & mask;
945			ppc->ppc_ptr = ptr;
946
947			INCR_PC;
948                        break;
949
950                case MS_OP_RFETCH:
951			*((char *) mi->arg[2].p) = r_reg(mi->arg[0].i, ppc) &
952							(char)mi->arg[1].i;
953			INCR_PC;
954                        break;
955
956		case MS_OP_RASSERT:
957                case MS_OP_DELAY:
958
959		/* let's suppose the next instr. is the same */
960		prefetch:
961			for (;mi->opcode == MS_OP_RASSERT; INCR_PC)
962				w_reg(mi->arg[0].i, ppc, (char)mi->arg[1].i);
963
964			if (mi->opcode == MS_OP_DELAY) {
965				DELAY(mi->arg[0].i);
966				INCR_PC;
967				goto prefetch;
968			}
969			break;
970
971		case MS_OP_ADELAY:
972			if (mi->arg[0].i)
973				tsleep(NULL, PPBPRI, "ppbdelay",
974						mi->arg[0].i * (hz/1000));
975			INCR_PC;
976			break;
977
978		case MS_OP_TRIG:
979			reg = mi->arg[0].i;
980			iter = mi->arg[1].i;
981			p = (char *)mi->arg[2].p;
982
983			/* XXX delay limited to 255 us */
984			for (i=0; i<iter; i++) {
985				w_reg(reg, ppc, *p++);
986				DELAY((unsigned char)*p++);
987			}
988			INCR_PC;
989			break;
990
991                case MS_OP_SET:
992                        ppc->ppc_accum = mi->arg[0].i;
993			INCR_PC;
994                        break;
995
996                case MS_OP_DBRA:
997                        if (--ppc->ppc_accum > 0)
998                                mi += mi->arg[0].i;
999			else
1000				INCR_PC;
1001                        break;
1002
1003                case MS_OP_BRSET:
1004                        cc = r_str(ppc);
1005                        if ((cc & (char)mi->arg[0].i) == (char)mi->arg[0].i)
1006                                mi += mi->arg[1].i;
1007			else
1008				INCR_PC;
1009                        break;
1010
1011                case MS_OP_BRCLEAR:
1012                        cc = r_str(ppc);
1013                        if ((cc & (char)mi->arg[0].i) == 0)
1014                                mi += mi->arg[1].i;
1015			else
1016				INCR_PC;
1017                        break;
1018
1019		case MS_OP_BRSTAT:
1020			cc = r_str(ppc);
1021			if ((cc & ((char)mi->arg[0].i | (char)mi->arg[1].i)) ==
1022							(char)mi->arg[0].i)
1023				mi += mi->arg[2].i;
1024			else
1025				INCR_PC;
1026			break;
1027
1028		case MS_OP_C_CALL:
1029			/*
1030			 * If the C call returns !0 then end the microseq.
1031			 * The current state of ptr is passed to the C function
1032			 */
1033			if ((error = mi->arg[0].f(mi->arg[1].p, ppc->ppc_ptr)))
1034				return (error);
1035
1036			INCR_PC;
1037			break;
1038
1039		case MS_OP_PTR:
1040			ppc->ppc_ptr = (char *)mi->arg[0].p;
1041			INCR_PC;
1042			break;
1043
1044		case MS_OP_CALL:
1045			if (stack)
1046				panic("%s: too much calls", __FUNCTION__);
1047
1048			if (mi->arg[0].p) {
1049				/* store the state of the actual
1050				 * microsequence
1051				 */
1052				stack = mi;
1053
1054				/* jump to the new microsequence */
1055				mi = (struct ppb_microseq *)mi->arg[0].p;
1056			} else
1057				INCR_PC;
1058
1059			break;
1060
1061		case MS_OP_SUBRET:
1062			/* retrieve microseq and pc state before the call */
1063			mi = stack;
1064
1065			/* reset the stack */
1066			stack = 0;
1067
1068			/* XXX return code */
1069
1070			INCR_PC;
1071			break;
1072
1073                case MS_OP_PUT:
1074                case MS_OP_GET:
1075                case MS_OP_RET:
1076			/* can't return to ppb level during the execution
1077			 * of a submicrosequence */
1078			if (stack)
1079				panic("%s: can't return to ppb level",
1080								__FUNCTION__);
1081
1082			/* update pc for ppb level of execution */
1083			*p_msq = mi;
1084
1085			/* return to ppb level of execution */
1086			return (0);
1087
1088                default:
1089                        panic("%s: unknown microsequence opcode 0x%x",
1090                                __FUNCTION__, mi->opcode);
1091                }
1092	}
1093
1094	/* unreached */
1095}
1096
1097/*
1098 * Configure current operating mode
1099 */
1100static int
1101ppc_generic_setmode(int unit, int mode)
1102{
1103	struct ppc_data *ppc = ppcdata[unit];
1104
1105	/* back to compatible mode, XXX don't know yet what to do here */
1106	if (mode == 0) {
1107		ppc->ppc_mode = PPB_COMPATIBLE;
1108		return (0);
1109	}
1110
1111	/* check if mode is available */
1112	if (!(ppc->ppc_avm & mode))
1113		return (EOPNOTSUPP);
1114
1115	/* if ECP mode, configure ecr register */
1116	if (ppc->ppc_avm & PPB_ECP) {
1117
1118		/* XXX disable DMA, enable interrupts */
1119		if (mode & PPB_EPP)
1120			return (EOPNOTSUPP);
1121		else if (mode & PPB_PS2)
1122			/* select PS2 mode with ECP */
1123			w_ecr(ppc, 0x20);
1124		else if (mode & PPB_ECP)
1125			/* select ECP mode */
1126			w_ecr(ppc, 0x60);
1127		else
1128			/* select standard parallel port mode */
1129			w_ecr(ppc, 0x00);
1130	}
1131
1132	ppc->ppc_mode = mode;
1133
1134	return (0);
1135}
1136
1137int
1138ppc_smclike_setmode(int unit, int mode)
1139{
1140	struct ppc_data *ppc = ppcdata[unit];
1141
1142	/* back to compatible mode, XXX don't know yet what to do here */
1143	if (mode == 0) {
1144		ppc->ppc_mode = PPB_COMPATIBLE;
1145		return (0);
1146	}
1147
1148	/* check if mode is available */
1149	if (!(ppc->ppc_avm & mode))
1150		return (EOPNOTSUPP);
1151
1152	/* if ECP mode, configure ecr register */
1153	if (ppc->ppc_avm & PPB_ECP) {
1154
1155		/* XXX disable DMA, enable interrupts */
1156		if (mode & PPB_EPP)
1157			/* select EPP mode */
1158			w_ecr(ppc, 0x80);
1159		else if (mode & PPB_PS2)
1160			/* select PS2 mode with ECP */
1161			w_ecr(ppc, 0x20);
1162		else if (mode & PPB_ECP)
1163			/* select ECP mode */
1164			w_ecr(ppc, 0x60);
1165		else
1166			/* select standard parallel port mode */
1167			w_ecr(ppc, 0x00);
1168	}
1169
1170	ppc->ppc_mode = mode;
1171
1172
1173	return (0);
1174}
1175
1176/*
1177 * EPP timeout, according to the PC87332 manual
1178 * Semantics of clearing EPP timeout bit.
1179 * PC87332	- reading SPP_STR does it...
1180 * SMC		- write 1 to EPP timeout bit			XXX
1181 * Others	- (???) write 0 to EPP timeout bit
1182 */
1183static void
1184ppc_reset_epp_timeout(int unit)
1185{
1186	struct ppc_data *ppc = ppcdata[unit];
1187	register char r;
1188
1189	r = r_str(ppc);
1190	w_str(ppc, r | 0x1);
1191	w_str(ppc, r & 0xfe);
1192
1193	return;
1194}
1195
1196static int
1197ppcprobe(struct isa_device *dvp)
1198{
1199	static short next_bios_ppc = 0;
1200	struct ppc_data *ppc;
1201	int error;
1202
1203	/*
1204	 * If port not specified, use bios list.
1205	 */
1206	if(dvp->id_iobase < 0) {
1207		if((next_bios_ppc < BIOS_MAX_PPC) &&
1208				(*(BIOS_PORTS+next_bios_ppc) != 0) ) {
1209			dvp->id_iobase = *(BIOS_PORTS+next_bios_ppc++);
1210			printf("ppc: parallel port found at 0x%x\n",
1211							dvp->id_iobase);
1212		} else
1213			return (0);
1214	}
1215
1216	/*
1217	 * Port was explicitly specified.
1218	 * This allows probing of ports unknown to the BIOS.
1219	 */
1220
1221	/*
1222	 * Allocate the ppc_data structure.
1223	 */
1224	ppc = malloc(sizeof(struct ppc_data), M_DEVBUF, M_NOWAIT);
1225	if (!ppc) {
1226		printf("ppc: cannot malloc!\n");
1227		goto error;
1228	}
1229	bzero(ppc, sizeof(struct ppc_data));
1230
1231	ppc->ppc_base = dvp->id_iobase;
1232	ppc->ppc_unit = dvp->id_unit;
1233	ppc->ppc_type = GENERIC;
1234
1235	ppc->ppc_mode = PPB_COMPATIBLE;
1236	ppc->ppc_epp = (dvp->id_flags & 0x10) >> 4;
1237
1238	/*
1239	 * XXX Try and detect if interrupts are working
1240	 */
1241	if (!(dvp->id_flags & 0x20))
1242		ppc->ppc_irq = (dvp->id_irq);
1243
1244	ppcdata[ppc->ppc_unit] = ppc;
1245	nppc ++;
1246
1247	/*
1248	 * Link the Parallel Port Chipset (adapter) to
1249	 * the future ppbus. Default to a generic chipset
1250	 */
1251	ppc->ppc_link.adapter_unit = ppc->ppc_unit;
1252	ppc->ppc_link.adapter = &ppc_generic_adapter;
1253
1254	/*
1255	 * Try to detect the chipset and its mode.
1256	 */
1257	if (ppc_detect(ppc, dvp->id_flags & 0xf))
1258		goto error;
1259
1260end_probe:
1261
1262	return (1);
1263
1264error:
1265	return (0);
1266}
1267
1268static int
1269ppcattach(struct isa_device *isdp)
1270{
1271	struct ppc_data *ppc = ppcdata[isdp->id_unit];
1272	struct ppb_data *ppbus;
1273	char * mode;
1274
1275	printf("ppc%d: %s chipset (%s) in %s mode%s\n", ppc->ppc_unit,
1276		ppc_types[ppc->ppc_type], ppc_avms[ppc->ppc_avm],
1277		ppc_modes[ppc->ppc_mode], (PPB_IS_EPP(ppc->ppc_mode)) ?
1278			ppc_epp_protocol[ppc->ppc_epp] : "");
1279
1280	isdp->id_ointr = ppcintr;
1281
1282	/*
1283	 * Prepare ppbus data area for upper level code.
1284	 */
1285	ppbus = ppb_alloc_bus();
1286
1287	if (!ppbus)
1288		return (0);
1289
1290	ppc->ppc_link.ppbus = ppbus;
1291	ppbus->ppb_link = &ppc->ppc_link;
1292
1293	/*
1294	 * Probe the ppbus and attach devices found.
1295	 */
1296	ppb_attachdevs(ppbus);
1297
1298	return (1);
1299}
1300#endif
1301