com_cardbus.c revision 1.18.6.1 1 /* $NetBSD: com_cardbus.c,v 1.18.6.1 2006/10/22 06:05:35 yamt 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.18.6.1 2006/10/22 06:05:35 yamt 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 cardbusreg_t cc_base;
64 bus_size_t cc_size;
65 cardbusreg_t cc_csr;
66 int cc_cben;
67 cardbustag_t cc_tag;
68 cardbusreg_t cc_reg;
69 int cc_type;
70 };
71
72 #define DEVNAME(CSC) ((CSC)->cc_com.sc_dev.dv_xname)
73
74 static int com_cardbus_match (struct device*, struct cfdata*, void*);
75 static void com_cardbus_attach (struct device*, struct device*, void*);
76 static int com_cardbus_detach (struct device*, int);
77
78 static void com_cardbus_setup(struct com_cardbus_softc*);
79 static int com_cardbus_enable (struct com_softc*);
80 static void com_cardbus_disable(struct com_softc*);
81
82 CFATTACH_DECL(com_cardbus, sizeof(struct com_cardbus_softc),
83 com_cardbus_match, com_cardbus_attach, com_cardbus_detach, com_activate);
84
85 static struct csdev {
86 int vendor;
87 int product;
88 cardbusreg_t reg;
89 int type;
90 } csdevs[] = {
91 { PCI_VENDOR_XIRCOM, PCI_PRODUCT_XIRCOM_MODEM56,
92 CARDBUS_BASE0_REG, CARDBUS_MAPREG_TYPE_IO },
93 { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_MODEM56,
94 CARDBUS_BASE0_REG, CARDBUS_MAPREG_TYPE_IO },
95 { PCI_VENDOR_3COM, PCI_PRODUCT_3COM_3C656_M,
96 CARDBUS_BASE0_REG, CARDBUS_MAPREG_TYPE_IO },
97 { PCI_VENDOR_3COM, PCI_PRODUCT_3COM_3C656B_M,
98 CARDBUS_BASE0_REG, CARDBUS_MAPREG_TYPE_IO },
99 { PCI_VENDOR_3COM, PCI_PRODUCT_3COM_3C656C_M,
100 CARDBUS_BASE0_REG, CARDBUS_MAPREG_TYPE_IO },
101 };
102
103 static const int ncsdevs = sizeof(csdevs) / sizeof(csdevs[0]);
104
105 static struct csdev*
106 find_csdev(struct cardbus_attach_args *ca)
107 {
108 struct csdev *cp;
109
110 for(cp = csdevs; cp < csdevs + ncsdevs; cp++)
111 if(cp->vendor == CARDBUS_VENDOR(ca->ca_id) &&
112 cp->product == CARDBUS_PRODUCT(ca->ca_id))
113 return cp;
114 return NULL;
115 }
116
117 static int
118 com_cardbus_match(struct device *parent __unused, struct cfdata *match __unused,
119 void *aux)
120 {
121 struct cardbus_attach_args *ca = aux;
122
123 /* known devices are ok */
124 if(find_csdev(ca) != NULL)
125 return 10;
126
127 /* as are serial devices with a known UART */
128 if(ca->ca_cis.funcid == PCMCIA_FUNCTION_SERIAL &&
129 ca->ca_cis.funce.serial.uart_present != 0 &&
130 (ca->ca_cis.funce.serial.uart_type == 0 || /* 8250 */
131 ca->ca_cis.funce.serial.uart_type == 1 || /* 16450 */
132 ca->ca_cis.funce.serial.uart_type == 2)) /* 16550 */
133 return 1;
134
135 return 0;
136 }
137
138 static int
139 gofigure(struct cardbus_attach_args *ca, struct com_cardbus_softc *csc)
140 {
141 int i, index = -1;
142 cardbusreg_t cis_ptr;
143 struct csdev *cp;
144
145 /* If this device is listed above, use the known values, */
146 cp = find_csdev(ca);
147 if(cp != NULL) {
148 csc->cc_reg = cp->reg;
149 csc->cc_type = cp->type;
150 return 0;
151 }
152
153 cis_ptr = Cardbus_conf_read(csc->cc_ct, csc->cc_tag, CARDBUS_CIS_REG);
154
155 /* otherwise try to deduce which BAR and type to use from CIS. If
156 there is only one BAR, it must be the one we should use, if
157 there are more, we're out of luck. */
158 for(i = 0; i < 7; i++) {
159 /* ignore zero sized BARs */
160 if(ca->ca_cis.bar[i].size == 0)
161 continue;
162 /* ignore the CIS BAR */
163 if(CARDBUS_CIS_ASI_BAR(cis_ptr) ==
164 CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[i].flags))
165 continue;
166 if(index != -1)
167 goto multi_bar;
168 index = i;
169 }
170 if(index == -1) {
171 printf(": couldn't find any base address tuple\n");
172 return 1;
173 }
174 csc->cc_reg = CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[index].flags);
175 if ((ca->ca_cis.bar[index].flags & 0x10) == 0)
176 csc->cc_type = CARDBUS_MAPREG_TYPE_MEM;
177 else
178 csc->cc_type = CARDBUS_MAPREG_TYPE_IO;
179 return 0;
180
181 multi_bar:
182 printf(": there are more than one possible base\n");
183
184 printf("%s: address for this device, "
185 "please report the following information\n",
186 DEVNAME(csc));
187 printf("%s: vendor 0x%x product 0x%x\n", DEVNAME(csc),
188 CARDBUS_VENDOR(ca->ca_id), CARDBUS_PRODUCT(ca->ca_id));
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 printf("%s: base address %x type %s size %x\n",
198 DEVNAME(csc),
199 CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[i].flags),
200 (ca->ca_cis.bar[i].flags & 0x10) ? "i/o" : "mem",
201 ca->ca_cis.bar[i].size);
202 }
203 return 1;
204 }
205
206 static void
207 com_cardbus_attach (struct device *parent __unused, struct device *self,
208 void *aux)
209 {
210 struct com_softc *sc = device_private(self);
211 struct com_cardbus_softc *csc = device_private(self);
212 struct cardbus_attach_args *ca = aux;
213 bus_space_handle_t ioh;
214 bus_space_tag_t iot;
215
216 csc->cc_ct = ca->ca_ct;
217 csc->cc_tag = Cardbus_make_tag(csc->cc_ct);
218
219 if(gofigure(ca, csc) != 0)
220 return;
221
222 if(Cardbus_mapreg_map(ca->ca_ct,
223 csc->cc_reg,
224 csc->cc_type,
225 0,
226 &iot,
227 &ioh,
228 &csc->cc_addr,
229 &csc->cc_size) != 0) {
230 printf("failed to map memory");
231 return;
232 }
233
234 COM_INIT_REGS(sc->sc_regs, iot, ioh, csc->cc_addr);
235
236 csc->cc_base = csc->cc_addr;
237 csc->cc_csr = CARDBUS_COMMAND_MASTER_ENABLE;
238 if(csc->cc_type == CARDBUS_MAPREG_TYPE_IO) {
239 csc->cc_base |= CARDBUS_MAPREG_TYPE_IO;
240 csc->cc_csr |= CARDBUS_COMMAND_IO_ENABLE;
241 csc->cc_cben = CARDBUS_IO_ENABLE;
242 } else {
243 csc->cc_csr |= CARDBUS_COMMAND_MEM_ENABLE;
244 csc->cc_cben = CARDBUS_MEM_ENABLE;
245 }
246
247 sc->sc_frequency = COM_FREQ;
248
249 sc->enable = com_cardbus_enable;
250 sc->disable = com_cardbus_disable;
251 sc->enabled = 0;
252
253 if (ca->ca_cis.cis1_info[0] && ca->ca_cis.cis1_info[1]) {
254 printf(": %s %s\n", ca->ca_cis.cis1_info[0],
255 ca->ca_cis.cis1_info[1]);
256 printf("%s", DEVNAME(csc));
257 }
258
259 com_cardbus_setup(csc);
260
261 com_attach_subr(sc);
262
263 Cardbus_function_disable(csc->cc_ct);
264 }
265
266 static void
267 com_cardbus_setup(struct com_cardbus_softc *csc)
268 {
269 cardbus_devfunc_t ct = csc->cc_ct;
270 cardbus_chipset_tag_t cc = ct->ct_cc;
271 cardbus_function_tag_t cf = ct->ct_cf;
272 cardbusreg_t reg;
273
274 Cardbus_conf_write(ct, csc->cc_tag, csc->cc_reg, csc->cc_base);
275
276 /* enable accesses on cardbus bridge */
277 (*cf->cardbus_ctrl)(cc, csc->cc_cben);
278 (*cf->cardbus_ctrl)(cc, CARDBUS_BM_ENABLE);
279
280 /* and the card itself */
281 reg = Cardbus_conf_read(ct, csc->cc_tag, CARDBUS_COMMAND_STATUS_REG);
282 reg &= ~(CARDBUS_COMMAND_IO_ENABLE | CARDBUS_COMMAND_MEM_ENABLE);
283 reg |= csc->cc_csr;
284 Cardbus_conf_write(ct, csc->cc_tag, CARDBUS_COMMAND_STATUS_REG, reg);
285
286 /*
287 * Make sure the latency timer is set to some reasonable
288 * value.
289 */
290 reg = cardbus_conf_read(cc, cf, csc->cc_tag, CARDBUS_BHLC_REG);
291 if (CARDBUS_LATTIMER(reg) < 0x20) {
292 reg &= ~(CARDBUS_LATTIMER_MASK << CARDBUS_LATTIMER_SHIFT);
293 reg |= (0x20 << CARDBUS_LATTIMER_SHIFT);
294 cardbus_conf_write(cc, cf, csc->cc_tag, CARDBUS_BHLC_REG, reg);
295 }
296 }
297
298 static int
299 com_cardbus_enable(struct com_softc *sc)
300 {
301 struct com_cardbus_softc *csc = (struct com_cardbus_softc*)sc;
302 struct cardbus_softc *psc =
303 (struct cardbus_softc *)device_parent(&sc->sc_dev);
304 cardbus_chipset_tag_t cc = psc->sc_cc;
305 cardbus_function_tag_t cf = psc->sc_cf;
306
307 Cardbus_function_enable(csc->cc_ct);
308
309 com_cardbus_setup(csc);
310
311 /* establish the interrupt. */
312 csc->cc_ih = cardbus_intr_establish(cc, cf, psc->sc_intrline,
313 IPL_SERIAL, comintr, sc);
314 if (csc->cc_ih == NULL) {
315 printf("%s: couldn't establish interrupt\n",
316 DEVNAME(csc));
317 return 1;
318 }
319
320 printf("%s: interrupting at irq %d\n",
321 DEVNAME(csc), psc->sc_intrline);
322
323 return 0;
324 }
325
326 static void
327 com_cardbus_disable(struct com_softc *sc)
328 {
329 struct com_cardbus_softc *csc = (struct com_cardbus_softc*)sc;
330 struct cardbus_softc *psc =
331 (struct cardbus_softc *)device_parent(&sc->sc_dev);
332 cardbus_chipset_tag_t cc = psc->sc_cc;
333 cardbus_function_tag_t cf = psc->sc_cf;
334
335 cardbus_intr_disestablish(cc, cf, csc->cc_ih);
336 csc->cc_ih = NULL;
337
338 Cardbus_function_disable(csc->cc_ct);
339 }
340
341 static int
342 com_cardbus_detach(struct device *self, int flags)
343 {
344 struct com_cardbus_softc *csc = device_private(self);
345 struct com_softc *sc = device_private(self);
346 struct cardbus_softc *psc = device_private(device_parent(self));
347 int error;
348
349 if ((error = com_detach(self, flags)) != 0)
350 return error;
351
352 if (csc->cc_ih != NULL)
353 cardbus_intr_disestablish(psc->sc_cc, psc->sc_cf, csc->cc_ih);
354
355 Cardbus_mapreg_unmap(csc->cc_ct, csc->cc_reg, sc->sc_regs.cr_iot,
356 sc->sc_regs.cr_ioh, csc->cc_size);
357
358 return 0;
359 }
360