1 /* $NetBSD: com_cardbus.c,v 1.31 2018/12/08 17:46:13 thorpej Exp $ */
2
3 /*
4 * Copyright (c) 2000 Johan Danielsson
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 *
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * 3. Neither the name of author nor the names of any contributors may
19 * be used to endorse or promote products derived from this
20 * software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
26 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
29 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
30 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 */
34
35 /* A driver for CardBus based serial devices.
36
37 If the CardBus device only has one BAR (that is not also the CIS
38 BAR) listed in the CIS, it is assumed to be the one to use. For
39 devices with more than one BAR, the list of known devices has to be
40 updated below. */
41
42 #include <sys/cdefs.h>
43 __KERNEL_RCSID(0, "$NetBSD: com_cardbus.c,v 1.31 2018/12/08 17:46:13 thorpej Exp $");
44
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/tty.h>
48 #include <sys/device.h>
49
50 #include <dev/cardbus/cardbusvar.h>
51 #include <dev/pci/pcidevs.h>
52
53 #include <dev/pcmcia/pcmciareg.h>
54
55 #include <dev/ic/comreg.h>
56 #include <dev/ic/comvar.h>
57
58 struct com_cardbus_softc {
59 struct com_softc cc_com;
60 void *cc_ih;
61 cardbus_devfunc_t cc_ct;
62 bus_addr_t cc_addr;
63 pcireg_t cc_base;
64 bus_size_t cc_size;
65 pcireg_t cc_csr;
66 pcitag_t cc_tag;
67 pcireg_t cc_reg;
68 int cc_type;
69 };
70
71 #define DEVICET(CSC) ((CSC)->cc_com.sc_dev)
72
73 static int com_cardbus_match (device_t, cfdata_t, void*);
74 static void com_cardbus_attach (device_t, device_t, void*);
75 static int com_cardbus_detach (device_t, int);
76
77 static void com_cardbus_setup(struct com_cardbus_softc*);
78 static int com_cardbus_enable (struct com_softc*);
79 static void com_cardbus_disable(struct com_softc*);
80
81 CFATTACH_DECL_NEW(com_cardbus, sizeof(struct com_cardbus_softc),
82 com_cardbus_match, com_cardbus_attach, com_cardbus_detach, NULL);
83
84 static struct csdev {
85 int vendor;
86 int product;
87 pcireg_t reg;
88 int type;
89 } csdevs[] = {
90 { PCI_VENDOR_XIRCOM, PCI_PRODUCT_XIRCOM_MODEM56,
91 PCI_BAR0, PCI_MAPREG_TYPE_IO },
92 { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_MODEM56,
93 PCI_BAR0, PCI_MAPREG_TYPE_IO },
94 { PCI_VENDOR_3COM, PCI_PRODUCT_3COM_3C656_M,
95 PCI_BAR0, PCI_MAPREG_TYPE_IO },
96 { PCI_VENDOR_3COM, PCI_PRODUCT_3COM_3C656B_M,
97 PCI_BAR0, PCI_MAPREG_TYPE_IO },
98 { PCI_VENDOR_3COM, PCI_PRODUCT_3COM_3C656C_M,
99 PCI_BAR0, PCI_MAPREG_TYPE_IO },
100 };
101
102 static const int ncsdevs = sizeof(csdevs) / sizeof(csdevs[0]);
103
104 static struct csdev*
find_csdev(struct cardbus_attach_args * ca)105 find_csdev(struct cardbus_attach_args *ca)
106 {
107 struct csdev *cp;
108
109 for(cp = csdevs; cp < csdevs + ncsdevs; cp++)
110 if(cp->vendor == PCI_VENDOR(ca->ca_id) &&
111 cp->product == PCI_PRODUCT(ca->ca_id))
112 return cp;
113 return NULL;
114 }
115
116 static int
com_cardbus_match(device_t parent,cfdata_t match,void * aux)117 com_cardbus_match(device_t parent, cfdata_t match, void *aux)
118 {
119 struct cardbus_attach_args *ca = aux;
120
121 /* known devices are ok */
122 if(find_csdev(ca) != NULL)
123 return 10;
124
125 /* as are serial devices with a known UART */
126 if(ca->ca_cis.funcid == PCMCIA_FUNCTION_SERIAL &&
127 ca->ca_cis.funce.serial.uart_present != 0 &&
128 (ca->ca_cis.funce.serial.uart_type == 0 || /* 8250 */
129 ca->ca_cis.funce.serial.uart_type == 1 || /* 16450 */
130 ca->ca_cis.funce.serial.uart_type == 2)) /* 16550 */
131 return 1;
132
133 return 0;
134 }
135
136 static int
gofigure(struct cardbus_attach_args * ca,struct com_cardbus_softc * csc)137 gofigure(struct cardbus_attach_args *ca, struct com_cardbus_softc *csc)
138 {
139 int i, index = -1;
140 pcireg_t cis_ptr;
141 struct csdev *cp;
142
143 /* If this device is listed above, use the known values, */
144 cp = find_csdev(ca);
145 if(cp != NULL) {
146 csc->cc_reg = cp->reg;
147 csc->cc_type = cp->type;
148 return 0;
149 }
150
151 cis_ptr = Cardbus_conf_read(csc->cc_ct, csc->cc_tag, CARDBUS_CIS_REG);
152
153 /* otherwise try to deduce which BAR and type to use from CIS. If
154 there is only one BAR, it must be the one we should use, if
155 there are more, we're out of luck. */
156 for(i = 0; i < 7; i++) {
157 /* ignore zero sized BARs */
158 if(ca->ca_cis.bar[i].size == 0)
159 continue;
160 /* ignore the CIS BAR */
161 if(CARDBUS_CIS_ASI_BAR(cis_ptr) ==
162 CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[i].flags))
163 continue;
164 if(index != -1)
165 goto multi_bar;
166 index = i;
167 }
168 if(index == -1) {
169 aprint_error(": couldn't find any base address tuple\n");
170 return 1;
171 }
172 csc->cc_reg = CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[index].flags);
173 if ((ca->ca_cis.bar[index].flags & 0x10) == 0)
174 csc->cc_type = PCI_MAPREG_TYPE_MEM;
175 else
176 csc->cc_type = PCI_MAPREG_TYPE_IO;
177 return 0;
178
179 multi_bar:
180 aprint_error(": there are more than one possible base\n");
181
182 aprint_error_dev(DEVICET(csc), "address for this device, "
183 "please report the following information\n");
184 aprint_error_dev(DEVICET(csc), "vendor 0x%x product 0x%x\n",
185 PCI_VENDOR(ca->ca_id), PCI_PRODUCT(ca->ca_id));
186 for(i = 0; i < 7; i++) {
187 /* ignore zero sized BARs */
188 if(ca->ca_cis.bar[i].size == 0)
189 continue;
190 /* ignore the CIS BAR */
191 if(CARDBUS_CIS_ASI_BAR(cis_ptr) ==
192 CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[i].flags))
193 continue;
194 aprint_error_dev(DEVICET(csc),
195 "base address %x type %s size %x\n",
196 CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[i].flags),
197 (ca->ca_cis.bar[i].flags & 0x10) ? "i/o" : "mem",
198 ca->ca_cis.bar[i].size);
199 }
200 return 1;
201 }
202
203 static void
com_cardbus_attach(device_t parent,device_t self,void * aux)204 com_cardbus_attach (device_t parent, device_t self, void *aux)
205 {
206 struct com_softc *sc = device_private(self);
207 struct com_cardbus_softc *csc = device_private(self);
208 struct cardbus_attach_args *ca = aux;
209 bus_space_handle_t ioh;
210 bus_space_tag_t iot;
211
212 sc->sc_dev = self;
213 csc->cc_ct = ca->ca_ct;
214 csc->cc_tag = ca->ca_tag;
215
216 if(gofigure(ca, csc) != 0)
217 return;
218
219 if(Cardbus_mapreg_map(ca->ca_ct,
220 csc->cc_reg,
221 csc->cc_type,
222 0,
223 &iot,
224 &ioh,
225 &csc->cc_addr,
226 &csc->cc_size) != 0) {
227 aprint_error("failed to map memory");
228 return;
229 }
230
231 com_init_regs(&sc->sc_regs, iot, ioh, csc->cc_addr);
232
233 csc->cc_base = csc->cc_addr;
234 csc->cc_csr = PCI_COMMAND_MASTER_ENABLE;
235 if(csc->cc_type == PCI_MAPREG_TYPE_IO) {
236 csc->cc_base |= PCI_MAPREG_TYPE_IO;
237 csc->cc_csr |= PCI_COMMAND_IO_ENABLE;
238 } else {
239 csc->cc_csr |= PCI_COMMAND_MEM_ENABLE;
240 }
241
242 sc->sc_frequency = COM_FREQ;
243
244 sc->enable = com_cardbus_enable;
245 sc->disable = com_cardbus_disable;
246 sc->enabled = 0;
247
248 if (ca->ca_cis.cis1_info[0] && ca->ca_cis.cis1_info[1]) {
249 aprint_normal(": %s %s\n", ca->ca_cis.cis1_info[0],
250 ca->ca_cis.cis1_info[1]);
251 aprint_normal("%s", device_xname(DEVICET(csc)));
252 }
253
254 com_cardbus_setup(csc);
255
256 com_attach_subr(sc);
257
258 Cardbus_function_disable(csc->cc_ct);
259 }
260
261 static void
com_cardbus_setup(struct com_cardbus_softc * csc)262 com_cardbus_setup(struct com_cardbus_softc *csc)
263 {
264 cardbus_devfunc_t ct = csc->cc_ct;
265 pcireg_t reg;
266
267 Cardbus_conf_write(ct, csc->cc_tag, csc->cc_reg, csc->cc_base);
268
269 /* and the card itself */
270 reg = Cardbus_conf_read(ct, csc->cc_tag, PCI_COMMAND_STATUS_REG);
271 reg &= ~(PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE);
272 reg |= csc->cc_csr;
273 Cardbus_conf_write(ct, csc->cc_tag, PCI_COMMAND_STATUS_REG, reg);
274
275 /*
276 * Make sure the latency timer is set to some reasonable
277 * value.
278 */
279 reg = Cardbus_conf_read(ct, csc->cc_tag, PCI_BHLC_REG);
280 if (PCI_LATTIMER(reg) < 0x20) {
281 reg &= ~(PCI_LATTIMER_MASK << PCI_LATTIMER_SHIFT);
282 reg |= (0x20 << PCI_LATTIMER_SHIFT);
283 Cardbus_conf_write(ct, csc->cc_tag, PCI_BHLC_REG, reg);
284 }
285 }
286
287 static int
com_cardbus_enable(struct com_softc * sc)288 com_cardbus_enable(struct com_softc *sc)
289 {
290 struct com_cardbus_softc *csc = (struct com_cardbus_softc*)sc;
291 cardbus_devfunc_t ct = csc->cc_ct;
292
293 Cardbus_function_enable(ct);
294
295 com_cardbus_setup(csc);
296
297 /* establish the interrupt. */
298 csc->cc_ih = Cardbus_intr_establish(ct, IPL_SERIAL, comintr, sc);
299 if (csc->cc_ih == NULL) {
300 aprint_error_dev(DEVICET(csc),
301 "couldn't establish interrupt\n");
302 return 1;
303 }
304
305 return 0;
306 }
307
308 static void
com_cardbus_disable(struct com_softc * sc)309 com_cardbus_disable(struct com_softc *sc)
310 {
311 struct com_cardbus_softc *csc = (struct com_cardbus_softc*)sc;
312 cardbus_devfunc_t ct = csc->cc_ct;
313
314 Cardbus_intr_disestablish(ct, csc->cc_ih);
315 csc->cc_ih = NULL;
316
317 Cardbus_function_disable(ct);
318 }
319
320 static int
com_cardbus_detach(device_t self,int flags)321 com_cardbus_detach(device_t self, int flags)
322 {
323 struct com_cardbus_softc *csc = device_private(self);
324 struct com_softc *sc = device_private(self);
325 cardbus_devfunc_t ct = csc->cc_ct;
326 int error;
327
328 if ((error = com_detach(self, flags)) != 0)
329 return error;
330
331 if (csc->cc_ih != NULL)
332 Cardbus_intr_disestablish(ct, csc->cc_ih);
333
334 Cardbus_mapreg_unmap(csc->cc_ct, csc->cc_reg, sc->sc_regs.cr_iot,
335 sc->sc_regs.cr_ioh, csc->cc_size);
336
337 return 0;
338 }
339