1 /* $OpenBSD: com_cardbus.c,v 1.46 2024/09/04 07:54:52 mglocker 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 in fact 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 <dev/ic/comreg.h>
60 #include <dev/ic/comvar.h>
61 #include <dev/ic/ns16550reg.h>
62
63 #define com_lcr com_cfcr
64
65 struct com_cardbus_softc {
66 struct com_softc cc_com;
67 void *cc_ih;
68 cardbus_devfunc_t cc_ct;
69 bus_addr_t cc_addr;
70 pcireg_t cc_base;
71 bus_size_t cc_size;
72 pcireg_t cc_csr;
73 int cc_cben;
74 pcitag_t cc_tag;
75 pcireg_t cc_reg;
76 int cc_type;
77 u_char cc_bug;
78 pci_chipset_tag_t cc_pc;
79 };
80
81 #define DEVNAME(CSC) ((CSC)->cc_com.sc_dev.dv_xname)
82
83 int com_cardbus_match(struct device *, void *, void *);
84 void com_cardbus_attach(struct device *, struct device *, void *);
85 int com_cardbus_detach(struct device *, int);
86
87 void com_cardbus_setup(struct com_cardbus_softc *);
88 int com_cardbus_enable(struct com_softc *);
89 void com_cardbus_disable(struct com_softc *);
90 struct csdev *com_cardbus_find_csdev(struct cardbus_attach_args *);
91 int com_cardbus_gofigure(struct cardbus_attach_args *,
92 struct com_cardbus_softc *);
93
94 const struct cfattach com_cardbus_ca = {
95 sizeof(struct com_cardbus_softc), com_cardbus_match,
96 com_cardbus_attach, com_cardbus_detach, com_activate
97 };
98
99 #define BUG_BROADCOM 0x01
100
101 /* XXX Keep this list synchronized with the corresponding one in pucdata.c */
102 static struct csdev {
103 u_short vendor;
104 u_short product;
105 pcireg_t reg;
106 u_char type;
107 u_char bug;
108 } csdevs[] = {
109 { PCI_VENDOR_3COM, PCI_PRODUCT_3COM_GLOBALMODEM56,
110 CARDBUS_BASE0_REG, PCI_MAPREG_TYPE_IO },
111 { PCI_VENDOR_3COM, PCI_PRODUCT_3COM_MODEM56,
112 CARDBUS_BASE0_REG, PCI_MAPREG_TYPE_IO },
113 { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_SERIAL,
114 CARDBUS_BASE0_REG, PCI_MAPREG_TYPE_IO, BUG_BROADCOM },
115 { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_SERIAL_2,
116 CARDBUS_BASE0_REG, PCI_MAPREG_TYPE_IO, BUG_BROADCOM },
117 { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_SERIAL_GC,
118 CARDBUS_BASE0_REG, PCI_MAPREG_TYPE_IO },
119 { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_MODEM56,
120 CARDBUS_BASE0_REG, PCI_MAPREG_TYPE_IO },
121 { PCI_VENDOR_OXFORD2, PCI_PRODUCT_OXFORD2_OXCB950,
122 CARDBUS_BASE0_REG, PCI_MAPREG_TYPE_IO },
123 { PCI_VENDOR_XIRCOM, PCI_PRODUCT_XIRCOM_CBEM56G,
124 CARDBUS_BASE0_REG, PCI_MAPREG_TYPE_IO },
125 { PCI_VENDOR_XIRCOM, PCI_PRODUCT_XIRCOM_MODEM56,
126 CARDBUS_BASE0_REG, PCI_MAPREG_TYPE_IO },
127 { PCI_VENDOR_WCH, PCI_PRODUCT_WCH_CH352,
128 CARDBUS_BASE0_REG, PCI_MAPREG_TYPE_IO },
129 { PCI_VENDOR_NETMOS, PCI_PRODUCT_NETMOS_NM9820,
130 CARDBUS_BASE0_REG, PCI_MAPREG_TYPE_IO }
131 };
132
133 static const int ncsdevs = sizeof(csdevs) / sizeof(csdevs[0]);
134
135 struct csdev*
com_cardbus_find_csdev(struct cardbus_attach_args * ca)136 com_cardbus_find_csdev(struct cardbus_attach_args *ca)
137 {
138 struct csdev *cp;
139
140 for (cp = csdevs; cp < csdevs + ncsdevs; cp++)
141 if (cp->vendor == PCI_VENDOR(ca->ca_id) &&
142 cp->product == PCI_PRODUCT(ca->ca_id))
143 return (cp);
144 return (NULL);
145 }
146
147 int
com_cardbus_match(struct device * parent,void * match,void * aux)148 com_cardbus_match(struct device *parent, void *match, void *aux)
149 {
150 struct cardbus_attach_args *ca = aux;
151
152 /* known devices are ok */
153 if (com_cardbus_find_csdev(ca) != NULL)
154 return (10);
155
156 /* as are serial devices with a known UART */
157 if (ca->ca_cis.funcid == PCMCIA_FUNCTION_SERIAL &&
158 ca->ca_cis.funce.serial.uart_present != 0 &&
159 (ca->ca_cis.funce.serial.uart_type == 0 || /* 8250 */
160 ca->ca_cis.funce.serial.uart_type == 1 || /* 16450 */
161 ca->ca_cis.funce.serial.uart_type == 2)) /* 16550 */
162 return (1);
163
164 return (0);
165 }
166
167 int
com_cardbus_gofigure(struct cardbus_attach_args * ca,struct com_cardbus_softc * csc)168 com_cardbus_gofigure(struct cardbus_attach_args *ca,
169 struct com_cardbus_softc *csc)
170 {
171 int i, index = -1;
172 pcireg_t cis_ptr;
173 struct csdev *cp;
174
175 /* If this device is listed above, use the known values, */
176 cp = com_cardbus_find_csdev(ca);
177 if (cp != NULL) {
178 csc->cc_reg = cp->reg;
179 csc->cc_type = cp->type;
180 csc->cc_bug = cp->bug;
181 return (0);
182 }
183
184 cis_ptr = pci_conf_read(ca->ca_pc, csc->cc_tag, CARDBUS_CIS_REG);
185
186 /* otherwise try to deduce which BAR and type to use from CIS. If
187 there is only one BAR, it must be the one we should use, if
188 there are more, we're out of luck. */
189 for (i = 0; i < 7; i++) {
190 /* ignore zero sized BARs */
191 if (ca->ca_cis.bar[i].size == 0)
192 continue;
193 /* ignore the CIS BAR */
194 if (CARDBUS_CIS_ASI_BAR(cis_ptr) ==
195 CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[i].flags))
196 continue;
197 if (index != -1)
198 goto multi_bar;
199 index = i;
200 }
201 if (index == -1) {
202 printf(": couldn't find any base address tuple\n");
203 return (1);
204 }
205 csc->cc_reg = CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[index].flags);
206 if ((ca->ca_cis.bar[index].flags & 0x10) == 0)
207 csc->cc_type = PCI_MAPREG_TYPE_MEM;
208 else
209 csc->cc_type = PCI_MAPREG_TYPE_IO;
210 return (0);
211
212 multi_bar:
213 printf(": there are more than one possible base\n");
214
215 printf("%s: address for this device, "
216 "please report the following information\n",
217 DEVNAME(csc));
218 printf("%s: vendor 0x%x product 0x%x\n", DEVNAME(csc),
219 PCI_VENDOR(ca->ca_id), PCI_PRODUCT(ca->ca_id));
220 for (i = 0; i < 7; i++) {
221 /* ignore zero sized BARs */
222 if (ca->ca_cis.bar[i].size == 0)
223 continue;
224 /* ignore the CIS BAR */
225 if (CARDBUS_CIS_ASI_BAR(cis_ptr) ==
226 CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[i].flags))
227 continue;
228 printf("%s: base address %x type %s size %x\n",
229 DEVNAME(csc), CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[i].flags),
230 (ca->ca_cis.bar[i].flags & 0x10) ? "i/o" : "mem",
231 ca->ca_cis.bar[i].size);
232 }
233 return (1);
234 }
235
236 void
com_cardbus_attach(struct device * parent,struct device * self,void * aux)237 com_cardbus_attach(struct device *parent, struct device *self, void *aux)
238 {
239 struct com_softc *sc = (struct com_softc*)self;
240 struct com_cardbus_softc *csc = (struct com_cardbus_softc*)self;
241 struct cardbus_attach_args *ca = aux;
242 cardbus_devfunc_t ct;
243
244 csc->cc_ct = ct = ca->ca_ct;
245 csc->cc_tag = pci_make_tag(ca->ca_pc, ct->ct_bus, ct->ct_dev, ct->ct_func);
246 csc->cc_pc = ca->ca_pc;
247
248 if (com_cardbus_gofigure(ca, csc) != 0)
249 return;
250
251 if (Cardbus_mapreg_map(ca->ca_ct, csc->cc_reg, csc->cc_type, 0,
252 &sc->sc_iot, &sc->sc_ioh, &csc->cc_addr, &csc->cc_size) != 0) {
253 printf(": can't map memory\n");
254 return;
255 }
256
257 csc->cc_base = csc->cc_addr;
258 csc->cc_csr = PCI_COMMAND_MASTER_ENABLE;
259 if (csc->cc_type == PCI_MAPREG_TYPE_IO) {
260 csc->cc_base |= PCI_MAPREG_TYPE_IO;
261 csc->cc_csr |= PCI_COMMAND_IO_ENABLE;
262 csc->cc_cben = CARDBUS_IO_ENABLE;
263 } else {
264 csc->cc_csr |= PCI_COMMAND_MEM_ENABLE;
265 csc->cc_cben = CARDBUS_MEM_ENABLE;
266 }
267
268 sc->sc_iobase = csc->cc_addr;
269 sc->sc_frequency = COM_FREQ;
270
271 sc->enable = com_cardbus_enable;
272 sc->disable = com_cardbus_disable;
273 sc->enabled = 0;
274
275 if (com_cardbus_enable(sc))
276 return;
277 sc->enabled = 1;
278
279 sc->sc_hwflags = 0;
280 sc->sc_swflags = 0;
281
282 if (csc->cc_bug & BUG_BROADCOM)
283 sc->sc_fifolen = 15;
284
285 com_attach_subr(sc);
286 }
287
288 void
com_cardbus_setup(struct com_cardbus_softc * csc)289 com_cardbus_setup(struct com_cardbus_softc *csc)
290 {
291 cardbus_devfunc_t ct = csc->cc_ct;
292 cardbus_chipset_tag_t cc = ct->ct_cc;
293 pci_chipset_tag_t pc = csc->cc_pc;
294 cardbus_function_tag_t cf = ct->ct_cf;
295 pcireg_t reg;
296
297 pci_conf_write(pc, csc->cc_tag, csc->cc_reg, csc->cc_base);
298
299 /* enable accesses on cardbus bridge */
300 cf->cardbus_ctrl(cc, csc->cc_cben);
301 cf->cardbus_ctrl(cc, CARDBUS_BM_ENABLE);
302
303 /* and the card itself */
304 reg = pci_conf_read(pc, csc->cc_tag, PCI_COMMAND_STATUS_REG);
305 reg &= ~(PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE);
306 reg |= csc->cc_csr;
307 pci_conf_write(pc, csc->cc_tag, PCI_COMMAND_STATUS_REG, reg);
308
309 /*
310 * Make sure the latency timer is set to some reasonable
311 * value.
312 */
313 reg = pci_conf_read(pc, csc->cc_tag, PCI_BHLC_REG);
314 if (PCI_LATTIMER(reg) < 0x20) {
315 reg &= ~(PCI_LATTIMER_MASK << PCI_LATTIMER_SHIFT);
316 reg |= (0x20 << PCI_LATTIMER_SHIFT);
317 pci_conf_write(pc, csc->cc_tag, PCI_BHLC_REG, reg);
318 }
319 }
320
321 int
com_cardbus_enable(struct com_softc * sc)322 com_cardbus_enable(struct com_softc *sc)
323 {
324 struct com_cardbus_softc *csc = (struct com_cardbus_softc*)sc;
325 struct cardbus_softc *psc =
326 (struct cardbus_softc *)sc->sc_dev.dv_parent;
327 cardbus_chipset_tag_t cc = psc->sc_cc;
328 cardbus_function_tag_t cf = psc->sc_cf;
329
330 Cardbus_function_enable(csc->cc_ct);
331
332 com_cardbus_setup(csc);
333
334 /* establish the interrupt. */
335 csc->cc_ih = cardbus_intr_establish(cc, cf, psc->sc_intrline,
336 IPL_TTY, comintr, sc, DEVNAME(csc));
337 if (csc->cc_ih == NULL) {
338 printf(": couldn't establish interrupt\n");
339 return (1);
340 }
341
342 printf(": irq %d", psc->sc_intrline);
343
344 return (0);
345 }
346
347 void
com_cardbus_disable(struct com_softc * sc)348 com_cardbus_disable(struct com_softc *sc)
349 {
350 struct com_cardbus_softc *csc = (struct com_cardbus_softc*)sc;
351 struct cardbus_softc *psc =
352 (struct cardbus_softc *)sc->sc_dev.dv_parent;
353 cardbus_chipset_tag_t cc = psc->sc_cc;
354 cardbus_function_tag_t cf = psc->sc_cf;
355
356 cardbus_intr_disestablish(cc, cf, csc->cc_ih);
357 Cardbus_function_disable(csc->cc_ct);
358 }
359
360 int
com_cardbus_detach(struct device * self,int flags)361 com_cardbus_detach(struct device *self, int flags)
362 {
363 struct com_cardbus_softc *csc = (struct com_cardbus_softc *) self;
364 struct com_softc *sc = (struct com_softc *) self;
365 struct cardbus_softc *psc = (struct cardbus_softc *)self->dv_parent;
366 int error;
367
368 if ((error = com_detach(self, flags)) != 0)
369 return (error);
370
371 cardbus_intr_disestablish(psc->sc_cc, psc->sc_cf, csc->cc_ih);
372
373 Cardbus_mapreg_unmap(csc->cc_ct, csc->cc_reg, sc->sc_iot, sc->sc_ioh,
374 csc->cc_size);
375
376 return (0);
377 }
378