xref: /openbsd/sys/dev/puc/com_puc.c (revision 610f49f8)
1 /*	$OpenBSD: com_puc.c,v 1.4 2002/01/30 20:45:34 nordin Exp $	*/
2 
3 /*
4  * Copyright (c) 1997 - 1999, Jason Downs.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. Neither the name(s) of the author(s) nor the name OpenBSD
15  *    may be used to endorse or promote products derived from this software
16  *    without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS
19  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT,
22  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30 
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/ioctl.h>
34 #include <sys/select.h>
35 #include <sys/tty.h>
36 #include <sys/proc.h>
37 #include <sys/user.h>
38 #include <sys/conf.h>
39 #include <sys/file.h>
40 #include <sys/uio.h>
41 #include <sys/kernel.h>
42 #include <sys/syslog.h>
43 #include <sys/types.h>
44 #include <sys/device.h>
45 
46 #include <machine/intr.h>
47 #include <machine/bus.h>
48 
49 #include <dev/pci/pcivar.h>
50 #include <dev/pci/pucvar.h>
51 
52 #include <dev/isa/isavar.h>	/* XXX */
53 
54 #include "com.h"
55 #ifdef i386
56 #include "pccom.h"
57 #endif
58 
59 #include <dev/ic/comreg.h>
60 #if NPCCOM > 0
61 #include <i386/isa/pccomvar.h>
62 #endif
63 #if NCOM > 0
64 #include <dev/ic/comvar.h>
65 #endif
66 #include <dev/ic/ns16550reg.h>
67 
68 #define	com_lcr		com_cfcr
69 
70 int com_puc_match __P((struct device *, void *, void *));
71 void com_puc_attach __P((struct device *, struct device *, void *));
72 
73 #if NCOM_PUC
74 struct cfattach com_puc_ca = {
75 	sizeof(struct com_softc), com_puc_match, com_puc_attach
76 };
77 #endif
78 
79 #if NPCCOM_PUC
80 struct cfattach pccom_puc_ca = {
81 	sizeof(struct com_softc), com_puc_match, com_puc_attach
82 };
83 #endif
84 
85 void com_puc_attach2 __P((struct com_softc *));
86 
87 int
88 com_puc_match(parent, match, aux)
89 	struct device *parent;
90 	void *match, *aux;
91 {
92 	struct puc_attach_args *pa = aux;
93 
94 	if (pa->type == PUC_PORT_TYPE_COM)
95 		return(1);
96 
97 	return(0);
98 }
99 
100 void
101 com_puc_attach(parent, self, aux)
102 	struct device *parent, *self;
103 	void *aux;
104 {
105 	struct com_softc *sc = (void *)self;
106 	struct puc_attach_args *pa = aux;
107 	const char *intrstr;
108 
109 	/* Grab a PCI interrupt. */
110 	intrstr = pci_intr_string(pa->pc, pa->intrhandle);
111 	sc->sc_ih = pci_intr_establish(pa->pc, pa->intrhandle,
112 			IPL_HIGH, comintr, sc,
113 			sc->sc_dev.dv_xname);
114 	if (sc->sc_ih == NULL) {
115 		printf(": couldn't establish interrupt");
116 		if (intrstr != NULL)
117 			printf(" at %s", intrstr);
118 		printf("\n");
119 		return;
120 	}
121 	printf(" %s", intrstr);
122 
123 	sc->sc_iot = pa->t;
124 	sc->sc_ioh = pa->h;
125 	sc->sc_iobase = pa->a;
126 	sc->sc_frequency = COM_FREQ;
127 
128 	if (pa->flags)
129 		sc->sc_frequency = pa->flags & PUC_COM_CLOCKMASK;
130 
131 	com_puc_attach2(sc);
132 }
133 
134 /*
135  * XXX This should be handled by a generic attach
136  */
137 void
138 com_puc_attach2(sc)
139 	struct com_softc *sc;
140 {
141 	bus_space_tag_t iot = sc->sc_iot;
142 	bus_space_handle_t ioh = sc->sc_ioh;
143 	u_int8_t lcr;
144 
145 	sc->sc_hwflags = 0;
146 	sc->sc_swflags = 0;
147 
148 	timeout_set(&sc->sc_dtr_tmo, com_raisedtr, sc);
149 	timeout_set(&sc->sc_diag_tmo, comdiag, sc);
150 
151 	/*
152 	 * Probe for all known forms of UART.
153 	 */
154 	lcr = bus_space_read_1(iot, ioh, com_lcr);
155 
156 	bus_space_write_1(iot, ioh, com_lcr, LCR_EFR);
157 	bus_space_write_1(iot, ioh, com_efr, 0);
158 	bus_space_write_1(iot, ioh, com_lcr, 0);
159 
160 	bus_space_write_1(iot, ioh, com_fifo, FIFO_ENABLE);
161 	delay(100);
162 
163 	switch(bus_space_read_1(iot, ioh, com_iir) >> 6) {
164 	case 0:
165 		sc->sc_uarttype = COM_UART_16450;
166 		break;
167 	case 2:
168 		sc->sc_uarttype = COM_UART_16550;
169 		break;
170 	case 3:
171 		sc->sc_uarttype = COM_UART_16550A;
172 		break;
173 	default:
174 		sc->sc_uarttype = COM_UART_UNKNOWN;
175 		break;
176 	}
177 
178 	if (sc->sc_uarttype == COM_UART_16550A) { /* Probe for ST16650s */
179 		bus_space_write_1(iot, ioh, com_lcr, lcr | LCR_DLAB);
180 		if (bus_space_read_1(iot, ioh, com_efr) == 0) {
181 			sc->sc_uarttype = COM_UART_ST16650;
182 		} else {
183 			bus_space_write_1(iot, ioh, com_lcr, LCR_EFR);
184 			if (bus_space_read_1(iot, ioh, com_efr) == 0)
185 				sc->sc_uarttype = COM_UART_ST16650V2;
186 		}
187 	}
188 
189 #if NPCCOM > 0
190 #ifdef i386
191 	if (sc->sc_uarttype == COM_UART_ST16650V2) {	/* Probe for XR16850s */
192 		u_int8_t dlbl, dlbh;
193 
194 		/* Enable latch access and get the current values. */
195 		bus_space_write_1(iot, ioh, com_lcr, lcr | LCR_DLAB);
196 		dlbl = bus_space_read_1(iot, ioh, com_dlbl);
197 		dlbh = bus_space_read_1(iot, ioh, com_dlbh);
198 
199 		/* Zero out the latch divisors */
200 		bus_space_write_1(iot, ioh, com_dlbl, 0);
201 		bus_space_write_1(iot, ioh, com_dlbh, 0);
202 
203 		if (bus_space_read_1(iot, ioh, com_dlbh) == 0x10) {
204 			sc->sc_uarttype = COM_UART_XR16850;
205 			sc->sc_uartrev = bus_space_read_1(iot, ioh, com_dlbl);
206 		}
207 
208 		/* Reset to original. */
209 		bus_space_write_1(iot, ioh, com_dlbl, dlbl);
210 		bus_space_write_1(iot, ioh, com_dlbh, dlbh);
211 	}
212 #endif
213 #endif
214 
215 	/* Reset the LCR (latch access is probably enabled). */
216 	bus_space_write_1(iot, ioh, com_lcr, lcr);
217 	if (sc->sc_uarttype == COM_UART_16450) { /* Probe for 8250 */
218 		u_int8_t scr0, scr1, scr2;
219 
220 		scr0 = bus_space_read_1(iot, ioh, com_scratch);
221 		bus_space_write_1(iot, ioh, com_scratch, 0xa5);
222 		scr1 = bus_space_read_1(iot, ioh, com_scratch);
223 		bus_space_write_1(iot, ioh, com_scratch, 0x5a);
224 		scr2 = bus_space_read_1(iot, ioh, com_scratch);
225 		bus_space_write_1(iot, ioh, com_scratch, scr0);
226 
227 		if ((scr1 != 0xa5) || (scr2 != 0x5a))
228 			sc->sc_uarttype = COM_UART_8250;
229 	}
230 
231 	/*
232 	 * Print UART type and initialize ourself.
233 	 */
234 	sc->sc_fifolen = 1;	/* default */
235 	switch (sc->sc_uarttype) {
236 	case COM_UART_UNKNOWN:
237 		printf(": unknown uart\n");
238 		break;
239 	case COM_UART_8250:
240 		printf(": ns8250, no fifo\n");
241 		break;
242 	case COM_UART_16450:
243 		printf(": ns16450, no fifo\n");
244 		break;
245 	case COM_UART_16550:
246 		printf(": ns16550, no working fifo\n");
247 		break;
248 	case COM_UART_16550A:
249 		printf(": ns16550a, 16 byte fifo\n");
250 		SET(sc->sc_hwflags, COM_HW_FIFO);
251 		sc->sc_fifolen = 16;
252 		break;
253 	case COM_UART_ST16650:
254 		printf(": st16650, no working fifo\n");
255 		break;
256 	case COM_UART_ST16650V2:
257 		printf(": st16650, 32 byte fifo\n");
258 		SET(sc->sc_hwflags, COM_HW_FIFO);
259 		sc->sc_fifolen = 32;
260 		break;
261 #if NPCCOM > 0
262 #ifdef i386
263 	case COM_UART_XR16850:
264 		printf(": xr16850 (rev %d), 128 byte fifo\n", sc->sc_uartrev);
265 		SET(sc->sc_hwflags, COM_HW_FIFO);
266 		sc->sc_fifolen = 128;
267 		break;
268 #endif
269 #endif
270 	default:
271 		panic("comattach: bad fifo type");
272 	}
273 
274 	/* clear and disable fifo */
275 	bus_space_write_1(iot, ioh, com_fifo, FIFO_RCV_RST | FIFO_XMT_RST);
276 	(void)bus_space_read_1(iot, ioh, com_data);
277 	bus_space_write_1(iot, ioh, com_fifo, 0);
278 }
279