xref: /openbsd-src/sys/dev/cardbus/com_cardbus.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1 /* $OpenBSD: com_cardbus.c,v 1.43 2015/11/14 14:47:56 miod Exp $ */
2 /* $NetBSD: com_cardbus.c,v 1.4 2000/04/17 09:21:59 joda Exp $ */
3 
4 /*
5  * Copyright (c) 2000 Johan Danielsson
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * 3. Neither the name of author nor the names of any contributors may
20  *    be used to endorse or promote products derived from this
21  *    software without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
26  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
27  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
29  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34  */
35 
36 /* This is a driver for CardBus based serial devices. It is less
37    generic than it could be, but it keeps the complexity down. So far
38    it assumes that anything that reports itself as a `serial' device
39    is infact a 16x50 or 8250, which is not necessarily true (in
40    practice this shouldn't be a problem). It also does not handle
41    devices in the `multiport serial' or `modem' sub-classes, I've
42    never seen any of these, so I don't know what they might look like.
43 
44    If the CardBus device only has one BAR (that is not also the CIS
45    BAR) listed in the CIS, it is assumed to be the one to use. For
46    devices with more than one BAR, the list of known devies has to be
47    updated below.  */
48 
49 #include <sys/param.h>
50 #include <sys/systm.h>
51 #include <sys/tty.h>
52 #include <sys/device.h>
53 
54 #include <dev/cardbus/cardbusvar.h>
55 #include <dev/pci/pcidevs.h>
56 
57 #include <dev/pcmcia/pcmciareg.h>
58 
59 #include "com.h"
60 
61 #include <dev/ic/comreg.h>
62 #include <dev/ic/comvar.h>
63 #include <dev/ic/ns16550reg.h>
64 
65 #define	com_lcr		com_cfcr
66 
67 struct com_cardbus_softc {
68 	struct com_softc	cc_com;
69 	void			*cc_ih;
70 	cardbus_devfunc_t	cc_ct;
71 	bus_addr_t		cc_addr;
72 	pcireg_t		cc_base;
73 	bus_size_t		cc_size;
74 	pcireg_t		cc_csr;
75 	int			cc_cben;
76 	pcitag_t		cc_tag;
77 	pcireg_t		cc_reg;
78 	int			cc_type;
79 	u_char			cc_bug;
80 	pci_chipset_tag_t	cc_pc;
81 };
82 
83 #define DEVNAME(CSC) ((CSC)->cc_com.sc_dev.dv_xname)
84 
85 int	com_cardbus_match(struct device *, void *, void *);
86 void	com_cardbus_attach(struct device *, struct device *, void *);
87 int	com_cardbus_detach(struct device *, int);
88 
89 void	com_cardbus_setup(struct com_cardbus_softc *);
90 int	com_cardbus_enable(struct com_softc *);
91 void	com_cardbus_disable(struct com_softc *);
92 struct csdev *com_cardbus_find_csdev(struct cardbus_attach_args *);
93 int	com_cardbus_gofigure(struct cardbus_attach_args *,
94     struct com_cardbus_softc *);
95 
96 struct cfattach com_cardbus_ca = {
97 	sizeof(struct com_cardbus_softc), com_cardbus_match,
98 	com_cardbus_attach, com_cardbus_detach, com_activate
99 };
100 
101 #define BUG_BROADCOM	0x01
102 
103 /* XXX Keep this list synchronized with the corresponding one in pucdata.c */
104 static struct csdev {
105 	u_short		vendor;
106 	u_short		product;
107 	pcireg_t	reg;
108 	u_char		type;
109 	u_char		bug;
110 } csdevs[] = {
111 	{ PCI_VENDOR_3COM, PCI_PRODUCT_3COM_GLOBALMODEM56,
112 	  CARDBUS_BASE0_REG, PCI_MAPREG_TYPE_IO },
113 	{ PCI_VENDOR_3COM, PCI_PRODUCT_3COM_MODEM56,
114 	  CARDBUS_BASE0_REG, PCI_MAPREG_TYPE_IO },
115 	{ PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_SERIAL,
116 	  CARDBUS_BASE0_REG, PCI_MAPREG_TYPE_IO, BUG_BROADCOM },
117 	{ PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_SERIAL_2,
118 	  CARDBUS_BASE0_REG, PCI_MAPREG_TYPE_IO, BUG_BROADCOM },
119 	{ PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_SERIAL_GC,
120 	  CARDBUS_BASE0_REG, PCI_MAPREG_TYPE_IO },
121 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_MODEM56,
122 	  CARDBUS_BASE0_REG, PCI_MAPREG_TYPE_IO },
123 	{ PCI_VENDOR_OXFORD2, PCI_PRODUCT_OXFORD2_OXCB950,
124 	  CARDBUS_BASE0_REG, PCI_MAPREG_TYPE_IO },
125 	{ PCI_VENDOR_XIRCOM, PCI_PRODUCT_XIRCOM_CBEM56G,
126 	  CARDBUS_BASE0_REG, PCI_MAPREG_TYPE_IO },
127 	{ PCI_VENDOR_XIRCOM, PCI_PRODUCT_XIRCOM_MODEM56,
128 	  CARDBUS_BASE0_REG, PCI_MAPREG_TYPE_IO },
129 	{ PCI_VENDOR_WCH, PCI_PRODUCT_WCH_CH352,
130 	  CARDBUS_BASE0_REG, PCI_MAPREG_TYPE_IO },
131 	{ PCI_VENDOR_NETMOS, PCI_PRODUCT_NETMOS_NM9820,
132 	  CARDBUS_BASE0_REG, PCI_MAPREG_TYPE_IO }
133 };
134 
135 static const int ncsdevs = sizeof(csdevs) / sizeof(csdevs[0]);
136 
137 struct csdev*
138 com_cardbus_find_csdev(struct cardbus_attach_args *ca)
139 {
140 	struct csdev *cp;
141 
142 	for (cp = csdevs; cp < csdevs + ncsdevs; cp++)
143 		if (cp->vendor == PCI_VENDOR(ca->ca_id) &&
144 		    cp->product == PCI_PRODUCT(ca->ca_id))
145 			return (cp);
146 	return (NULL);
147 }
148 
149 int
150 com_cardbus_match(struct device *parent, void *match, void *aux)
151 {
152 	struct cardbus_attach_args *ca = aux;
153 
154 	/* known devices are ok */
155 	if (com_cardbus_find_csdev(ca) != NULL)
156 	    return (10);
157 
158 	/* as are serial devices with a known UART */
159 	if (ca->ca_cis.funcid == PCMCIA_FUNCTION_SERIAL &&
160 	    ca->ca_cis.funce.serial.uart_present != 0 &&
161 	    (ca->ca_cis.funce.serial.uart_type == 0 ||	/* 8250 */
162 	    ca->ca_cis.funce.serial.uart_type == 1 ||	/* 16450 */
163 	    ca->ca_cis.funce.serial.uart_type == 2))	/* 16550 */
164 		return (1);
165 
166 	return (0);
167 }
168 
169 int
170 com_cardbus_gofigure(struct cardbus_attach_args *ca,
171     struct com_cardbus_softc *csc)
172 {
173 	int i, index = -1;
174 	pcireg_t cis_ptr;
175 	struct csdev *cp;
176 
177 	/* If this device is listed above, use the known values, */
178 	cp = com_cardbus_find_csdev(ca);
179 	if (cp != NULL) {
180 		csc->cc_reg = cp->reg;
181 		csc->cc_type = cp->type;
182 		csc->cc_bug = cp->bug;
183 		return (0);
184 	}
185 
186 	cis_ptr = pci_conf_read(ca->ca_pc, csc->cc_tag, CARDBUS_CIS_REG);
187 
188 	/* otherwise try to deduce which BAR and type to use from CIS.  If
189 	   there is only one BAR, it must be the one we should use, if
190 	   there are more, we're out of luck.  */
191 	for (i = 0; i < 7; i++) {
192 		/* ignore zero sized BARs */
193 		if (ca->ca_cis.bar[i].size == 0)
194 			continue;
195 		/* ignore the CIS BAR */
196 		if (CARDBUS_CIS_ASI_BAR(cis_ptr) ==
197 		    CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[i].flags))
198 			continue;
199 		if (index != -1)
200 			goto multi_bar;
201 		index = i;
202 	}
203 	if (index == -1) {
204 		printf(": couldn't find any base address tuple\n");
205 		return (1);
206 	}
207 	csc->cc_reg = CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[index].flags);
208 	if ((ca->ca_cis.bar[index].flags & 0x10) == 0)
209 		csc->cc_type = PCI_MAPREG_TYPE_MEM;
210 	else
211 		csc->cc_type = PCI_MAPREG_TYPE_IO;
212 	return (0);
213 
214   multi_bar:
215 	printf(": there are more than one possible base\n");
216 
217 	printf("%s: address for this device, "
218 	    "please report the following information\n",
219 	    DEVNAME(csc));
220 	printf("%s: vendor 0x%x product 0x%x\n", DEVNAME(csc),
221 	    PCI_VENDOR(ca->ca_id), PCI_PRODUCT(ca->ca_id));
222 	for (i = 0; i < 7; i++) {
223 		/* ignore zero sized BARs */
224 		if (ca->ca_cis.bar[i].size == 0)
225 			continue;
226 		/* ignore the CIS BAR */
227 		if (CARDBUS_CIS_ASI_BAR(cis_ptr) ==
228 		    CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[i].flags))
229 			continue;
230 		printf("%s: base address %x type %s size %x\n",
231 		    DEVNAME(csc), CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[i].flags),
232 		    (ca->ca_cis.bar[i].flags & 0x10) ? "i/o" : "mem",
233 		    ca->ca_cis.bar[i].size);
234 	}
235 	return (1);
236 }
237 
238 void
239 com_cardbus_attach(struct device *parent, struct device *self, void *aux)
240 {
241 	struct com_softc *sc = (struct com_softc*)self;
242 	struct com_cardbus_softc *csc = (struct com_cardbus_softc*)self;
243 	struct cardbus_attach_args *ca = aux;
244 	cardbus_devfunc_t ct;
245 
246 	csc->cc_ct = ct = ca->ca_ct;
247 	csc->cc_tag = pci_make_tag(ca->ca_pc, ct->ct_bus, ct->ct_dev, ct->ct_func);
248 	csc->cc_pc = ca->ca_pc;
249 
250 	if (com_cardbus_gofigure(ca, csc) != 0)
251 		return;
252 
253 	if (Cardbus_mapreg_map(ca->ca_ct, csc->cc_reg, csc->cc_type, 0,
254 	    &sc->sc_iot, &sc->sc_ioh, &csc->cc_addr, &csc->cc_size) != 0) {
255 		printf(": can't map memory\n");
256 		return;
257 	}
258 
259 	csc->cc_base = csc->cc_addr;
260 	csc->cc_csr = PCI_COMMAND_MASTER_ENABLE;
261 	if (csc->cc_type == PCI_MAPREG_TYPE_IO) {
262 		csc->cc_base |= PCI_MAPREG_TYPE_IO;
263 		csc->cc_csr |= PCI_COMMAND_IO_ENABLE;
264 		csc->cc_cben = CARDBUS_IO_ENABLE;
265 	} else {
266 		csc->cc_csr |= PCI_COMMAND_MEM_ENABLE;
267 		csc->cc_cben = CARDBUS_MEM_ENABLE;
268 	}
269 
270 	sc->sc_iobase = csc->cc_addr;
271 	sc->sc_frequency = COM_FREQ;
272 
273 	sc->enable = com_cardbus_enable;
274 	sc->disable = com_cardbus_disable;
275 	sc->enabled = 0;
276 
277 	if (com_cardbus_enable(sc))
278 		return;
279 	sc->enabled = 1;
280 
281 	sc->sc_hwflags = 0;
282 	sc->sc_swflags = 0;
283 
284 	if (csc->cc_bug & BUG_BROADCOM)
285 		sc->sc_fifolen = 15;
286 
287 	com_attach_subr(sc);
288 }
289 
290 void
291 com_cardbus_setup(struct com_cardbus_softc *csc)
292 {
293 	cardbus_devfunc_t ct = csc->cc_ct;
294 	cardbus_chipset_tag_t cc = ct->ct_cc;
295 	pci_chipset_tag_t pc = csc->cc_pc;
296 	cardbus_function_tag_t cf = ct->ct_cf;
297 	pcireg_t reg;
298 
299 	pci_conf_write(pc, csc->cc_tag, csc->cc_reg, csc->cc_base);
300 
301 	/* enable accesses on cardbus bridge */
302 	cf->cardbus_ctrl(cc, csc->cc_cben);
303 	cf->cardbus_ctrl(cc, CARDBUS_BM_ENABLE);
304 
305 	/* and the card itself */
306 	reg = pci_conf_read(pc, csc->cc_tag, PCI_COMMAND_STATUS_REG);
307 	reg &= ~(PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE);
308 	reg |= csc->cc_csr;
309 	pci_conf_write(pc, csc->cc_tag, PCI_COMMAND_STATUS_REG, reg);
310 
311 	/*
312 	 * Make sure the latency timer is set to some reasonable
313 	 * value.
314 	 */
315 	reg = pci_conf_read(pc, csc->cc_tag, PCI_BHLC_REG);
316 	if (PCI_LATTIMER(reg) < 0x20) {
317 			reg &= ~(PCI_LATTIMER_MASK << PCI_LATTIMER_SHIFT);
318 			reg |= (0x20 << PCI_LATTIMER_SHIFT);
319 			pci_conf_write(pc, csc->cc_tag, PCI_BHLC_REG, reg);
320 	}
321 }
322 
323 int
324 com_cardbus_enable(struct com_softc *sc)
325 {
326 	struct com_cardbus_softc *csc = (struct com_cardbus_softc*)sc;
327 	struct cardbus_softc *psc =
328 	    (struct cardbus_softc *)sc->sc_dev.dv_parent;
329 	cardbus_chipset_tag_t cc = psc->sc_cc;
330 	cardbus_function_tag_t cf = psc->sc_cf;
331 
332 	Cardbus_function_enable(csc->cc_ct);
333 
334 	com_cardbus_setup(csc);
335 
336 	/* establish the interrupt. */
337 	csc->cc_ih = cardbus_intr_establish(cc, cf, psc->sc_intrline,
338 	    IPL_TTY, comintr, sc, DEVNAME(csc));
339 	if (csc->cc_ih == NULL) {
340 		printf(": couldn't establish interrupt\n");
341 		return (1);
342 	}
343 
344 	printf(": irq %d", psc->sc_intrline);
345 
346 	return (0);
347 }
348 
349 void
350 com_cardbus_disable(struct com_softc *sc)
351 {
352 	struct com_cardbus_softc *csc = (struct com_cardbus_softc*)sc;
353 	struct cardbus_softc *psc =
354 	    (struct cardbus_softc *)sc->sc_dev.dv_parent;
355 	cardbus_chipset_tag_t cc = psc->sc_cc;
356 	cardbus_function_tag_t cf = psc->sc_cf;
357 
358 	cardbus_intr_disestablish(cc, cf, csc->cc_ih);
359 	Cardbus_function_disable(csc->cc_ct);
360 }
361 
362 int
363 com_cardbus_detach(struct device *self, int flags)
364 {
365 	struct com_cardbus_softc *csc = (struct com_cardbus_softc *) self;
366 	struct com_softc *sc = (struct com_softc *) self;
367 	struct cardbus_softc *psc = (struct cardbus_softc *)self->dv_parent;
368 	int error;
369 
370 	if ((error = com_detach(self, flags)) != 0)
371 		return (error);
372 
373 	cardbus_intr_disestablish(psc->sc_cc, psc->sc_cf, csc->cc_ih);
374 
375 	Cardbus_mapreg_unmap(csc->cc_ct, csc->cc_reg, sc->sc_iot, sc->sc_ioh,
376 	    csc->cc_size);
377 
378 	return (0);
379 }
380