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